The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.
MODULE = PDL::FFTW3 PACKAGE = PDL::FFTW3

void *
compute_plan( dims_ref, do_double_precision, is_real_fft, do_inverse_fft, in, out )
  SV*  dims_ref
  bool do_double_precision
  bool is_real_fft
  bool do_inverse_fft
  pdl* in
  pdl* out
CODE:
{
  // Given input and output matrices, this function computes the FFTW plan

  // PDL stores its data in the opposite dimension order from what FFTW wants. I
  // handle this by passing in the dimension counts backwards.
  AV* dims_av = (AV*)SvRV(dims_ref);
  int rank = av_len(dims_av) + 1;

  int dims_row_first[rank];
  for( int i=0; i<rank; i++)
    dims_row_first[i] = SvIV( *av_fetch( dims_av, rank-i-1, 0) );

  // if out is null, I do a dummy alloc of memory so I can pass the pointer to
  // the planner
  void* out_data = out->data;
  if(out->state & PDL_NOMYDIMS)
    out_data = do_double_precision ?
      (void*) fftw_alloc_complex(16) :
      (void*)fftwf_alloc_complex(16);

  void* plan;
  if( !is_real_fft )
  {
    int direction = do_inverse_fft ? FFTW_BACKWARD : FFTW_FORWARD;

    // complex-complex FFT. Input/output have identical dimensions
    if( !do_double_precision )
      plan =
        fftwf_plan_dft( rank, dims_row_first,
                        (fftwf_complex*)in->data, (fftwf_complex*)out_data,
                        direction, FFTW_ESTIMATE);
    else
      plan =
        fftw_plan_dft( rank, dims_row_first,
                       (fftw_complex*)in->data, (fftw_complex*)out_data,
                       direction, FFTW_ESTIMATE);
  }
  else
  {
    // real-complex FFT. Input/output have different dimensions
    if( !do_double_precision)
    {
      if( !do_inverse_fft )
        plan =
          fftwf_plan_dft_r2c( rank, dims_row_first,
                              (float*)in->data, (fftwf_complex*)out_data,
                              FFTW_ESTIMATE );
      else
        plan =
          fftwf_plan_dft_c2r( rank, dims_row_first,
                              (fftwf_complex*)in->data, (float*)out_data,
                              FFTW_ESTIMATE );
    }
    else
    {
      if( !do_inverse_fft )
        plan =
          fftw_plan_dft_r2c( rank, dims_row_first,
                             (double*)in->data, (fftw_complex*)out_data,
                             FFTW_ESTIMATE );
      else
        plan =
          fftw_plan_dft_c2r( rank, dims_row_first,
                             (fftw_complex*)in->data, (double*)out_data,
                             FFTW_ESTIMATE );
    }
  }

  // out was null; free the dummy pointer
  if(out->state & PDL_NOMYDIMS)
  {
    if(do_double_precision) fftw_free (out_data);
    else                    fftwf_free(out_data);
  }


  if( plan == NULL )
    XSRETURN_UNDEF;
  else
    RETVAL = (void*)PTR2IV(plan);
}
OUTPUT:
 RETVAL



bool
is_same_data( in, out )
  pdl* in
  pdl* out
CODE:
{
  RETVAL = in->data == out->data;
}
OUTPUT:
 RETVAL