code: def _Xfftn(
      a,
      s,
      axes,
      overwrite_input,
      planner_effort,
      threads,
      auto_align_input,
      auto_contiguous,
      avoid_copy,
      inverse,
      real,
      normalise_idft=True,
      ortho=False,
      real_direction_flag=None,
  ):
      """Generic transform interface for all the transforms. No
      defaults exist. The transform must be specified exactly.
  
      The argument ``real_direction_flag`` is a slight exception to this
      rule: for backwards compatibility this function defaults to standard
      Fourier transforms (and not the specialized real to real variants).
      If this flag is set to one of the standard real transform types
      (e.g., 'FFTW_RODFT00') then the arguments ``inverse`` and ``real``
      are ignored.
      """
      a_orig = a
      invreal = inverse and real
  
      if real_direction_flag is not None:
          direction = real_direction_flag
          real_to_real = True
      elif inverse:
          direction = "FFTW_BACKWARD"
          real_to_real = False
      else:
          direction = "FFTW_FORWARD"
          real_to_real = False
  
      if planner_effort not in _valid_efforts:
          raise ValueError("Invalid planner effort: ", planner_effort)
  
      s, axes = _cook_nd_args(a, s, axes, invreal)
  
      input_shape, output_shape = _compute_array_shapes(
          a, s, axes, inverse, real
      )
  
      a_is_complex = numpy.iscomplexobj(a)
  
      # Make the input dtype correct by transforming to an available type
      if real_to_real:
          if a.dtype not in _real_to_real_dtypes:
              a = numpy.asarray(a, dtype=_default_dtype)
      else:
          if a.dtype.char not in _rc_dtype_pairs:
              dtype = _default_dtype
              if (
                  a.dtype == numpy.dtype("float16")
                  and "32" in pyfftw._supported_types
              ):
                  # convert half-precision to single precision, if available
                  dtype = numpy.dtype("float32")
  
              # warn when losing precision but not when using a higher precision
              if dtype.itemsize < a.dtype.itemsize:
                  warnings.warn(
                      "Narrowing conversion from %s to %s precision"
                      % (a.dtype, dtype)
                  )
  
              if not real or inverse:
                  # It's going to be complex
                  dtype = numpy.dtype(_rc_dtype_pairs[dtype.char])
  
              # finally convert the input array
              a = numpy.asarray(a, dtype=dtype)
          elif not (real and not inverse) and not a_is_complex:
              # We need to make it a complex dtype
              a = numpy.asarray(a, dtype=_rc_dtype_pairs[a.dtype.char])
  
          elif (real and not inverse) and a_is_complex:
              # It should be real
              a = numpy.asarray(a, dtype=_rc_dtype_pairs[a.dtype.char])
  
      # Make the output dtype correct
      if (
          not real
      ):  # 'real' implies c2r or r2c; hence 'not real' means r2r or c2c.
          output_dtype = a.dtype
  
      else:
          output_dtype = _rc_dtype_pairs[a.dtype.char]
  
      if not avoid_copy:
          a_copy = a.copy()
  
      output_array = pyfftw.empty_aligned(output_shape, output_dtype)
  
      flags = [planner_effort]
  
      if not auto_align_input:
          flags.append("FFTW_UNALIGNED")
  
      if overwrite_input:
          flags.append("FFTW_DESTROY_INPUT")
  
      if not a.shape == input_shape:
          if avoid_copy:
              raise ValueError(
                  "Cannot avoid copy: "
                  "The transform shape is not the same as the array size. "
                  "(from avoid_copy flag)"
              )
  
          # This means we need to use an _FFTWWrapper object
          # and so need to create slicers.
          (
              update_input_array_slicer,
              FFTW_array_slicer,
          ) = _setup_input_slicers(a.shape, input_shape)
  
          # Also, the input array will be a different shape to the shape of
          # `a`, so we need to create a new array.
          input_array = pyfftw.empty_aligned(input_shape, a.dtype)
  
          FFTW_object = _FFTWWrapper(
              input_array,
              output_array,
              axes,
              direction,
              flags,
              threads,
              input_array_slicer=update_input_array_slicer,
              FFTW_array_slicer=FFTW_array_slicer,
              normalise_idft=normalise_idft,
              ortho=ortho,
          )
  
          # We copy the data back into the internal FFTW object array
          internal_array = FFTW_object.input_array
          internal_array[:] = 0
          internal_array[FFTW_array_slicer] = a_copy[
              update_input_array_slicer
          ]
  
      else:
          # Otherwise we can use `a` as-is
  
          input_array = a
  
          if auto_contiguous:
              # We only need to create a new array if it's not already
              # contiguous
              if not (
                  a.flags["C_CONTIGUOUS"] or a.flags["F_CONTIGUOUS"]
              ):
                  if avoid_copy:
                      raise ValueError(
                          "Cannot avoid copy: "
                          "The input array is not contiguous and "
                          "auto_contiguous is set. (from avoid_copy flag)"
                      )
  
                  input_array = pyfftw.empty_aligned(a.shape, a.dtype)
  
          if auto_align_input and not pyfftw.is_byte_aligned(
              input_array
          ):
              if avoid_copy:
                  raise ValueError(
                      "Cannot avoid copy: "
                      "The input array is not aligned and "
                      "auto_align is set. (from avoid_copy flag)"
                  )
  
              input_array = pyfftw.byte_align(input_array)
  
          FFTW_object = pyfftw.FFTW(
              input_array,
              output_array,
              axes,
              direction,
              flags,
              threads,
              normalise_idft=normalise_idft,
              ortho=ortho,
          )
  
          if not avoid_copy:
              # Copy the data back into the (likely) destroyed array
              FFTW_object.input_array[:] = a_copy
  
      return FFTW_object
  
file_path: py-fftw/pyfftw/builders/_utils.py
imports: import multiprocessing
  import pyfftw
  import numpy
  import warnings
  from ..None import _threading_type
  from ..None import config
label_desc: Use image node_id 4 for calling a global function with example usage: _Xfftn(a, s, axes, overwrite_input, planner_effort, threads, auto_align_input, auto_contiguous, avoid_copy, inverse, real, normalise_idft, ortho, real_direction_flag) and returns: FFTW_object