31
31
32
32
pp_addhdr( '
33
33
#include <fftw3.h>
34
+
35
+ /* the Linux kernel does something similar to assert at compile time */
36
+ #define static_assert_fftw(x) (void)( sizeof( int[ 1 - 2* !(x) ]) )
34
37
' );
35
38
36
39
37
40
# I want to be able to say $X = fft1($x); rank is required. 'fft()' is ambiguous
38
41
# about whether threading is desired or if a large fft is desired. Old PDL::FFTW
39
42
# did one thing, matlab does another, so I do not include this function at all
40
43
44
+ my $TEMPLATE_REAL = <<'EOF';
45
+ // This is the template used by PP to generate the FFTW routines.
46
+
47
+ // This is passed into pp_def() in the 'Code' key. Before this file is passed to
48
+ // pp_def, the following strings are replaced:
49
+ //
50
+ // INVERSE If this is a c2r transform rather than r2c
51
+ // RANK The rank of this transform
52
+
53
+ {
54
+ // make sure the PDL data type I'm using matches the FFTW data type
55
+ static_assert_fftw( sizeof($GENERIC())*2 == sizeof($TFD(fftwf_,fftw_)complex) );
56
+
57
+ $TFD(fftwf_,fftw_)plan plan = INT2PTR( $TFD(fftwf_,fftw_)plan, $COMP(plan));
41
58
59
+ if( !INVERSE )
60
+ $TFD(fftwf_,fftw_)execute_dft_r2c( plan,
61
+ ($TFD(float,double)*)$P(real),
62
+ ($TFD(fftwf_,fftw_)complex*)$P(complexv) );
63
+ else
64
+ {
65
+ // FFTW inverse real transforms clobber their input. I thus make a new
66
+ // buffer and transform from there
67
+ unsigned long nelem = 1;
68
+ for( int i=0; i<=RANK; i++ )
69
+ nelem *= $PDL(complexv)->dims[i];
70
+ unsigned long elem_scale = sizeof($GENERIC()) / sizeof( $TFD(float,double) ); /* native complex */
71
+ /* explicit C types here means when changed to $TGC will still be right */
72
+ $TFD(float,double)* input_copy = $TFD(fftwf_,fftw_)alloc_real( nelem * elem_scale );
73
+ memcpy( input_copy, $P(complexv), sizeof($GENERIC()) * nelem );
74
+
75
+ $TFD(fftwf_,fftw_)execute_dft_c2r( plan,
76
+ ($TFD(fftwf_,fftw_)complex*)input_copy,
77
+ ($TFD(float,double)*)$P(real) );
78
+
79
+ $TFD(fftwf_,fftw_)free( input_copy );
80
+ }
81
+ }
82
+ EOF
83
+ my $TEMPLATE_COMPLEX = <<'EOF';
84
+ // This is the template used by PP to generate the FFTW routines.
85
+ {
86
+ // make sure the PDL data type I'm using matches the FFTW data type
87
+ static_assert_fftw( sizeof($GENERIC())*2 == sizeof($TFD(fftwf_,fftw_)complex) );
42
88
89
+ $TFD(fftwf_,fftw_)plan plan = INT2PTR( $TFD(fftwf_,fftw_)plan, $COMP(plan));
90
+ $TFD(fftwf_,fftw_)execute_dft( plan,
91
+ ($TFD(fftwf_,fftw_)complex*)$P(in),
92
+ ($TFD(fftwf_,fftw_)complex*)$P(out) );
93
+ }
94
+ EOF
43
95
44
96
# I define up to rank-10 FFTs. This is annoyingly arbitrary, but hopefully
45
97
# should be sufficient
@@ -653,7 +705,6 @@ pp_add_exported( map "${_}fftn", '','i','r','ir' );
653
705
654
706
pp_done();
655
707
656
-
657
708
sub generateDefinitions
658
709
{
659
710
my $rank = shift;
@@ -676,7 +727,7 @@ sub generateDefinitions
676
727
unshift @dims, 'n0=2';
677
728
my $dims_string = join(',', @dims);
678
729
$pp_def{Pars} = "in($dims_string); [o]out($dims_string);";
679
- $pp_def{Code} = slurp('template_complex.c') ;
730
+ $pp_def{Code} = $TEMPLATE_COMPLEX ;
680
731
pp_def( "__fft$rank", %pp_def );
681
732
682
733
##################################################################################
@@ -687,7 +738,7 @@ sub generateDefinitions
687
738
$dims_complex[1] = 'nhalf'; # first complex dim is real->dim(0)/2+1
688
739
my $dims_real_string = join(',', @dims_real);
689
740
my $dims_complex_string = join(',', @dims_complex);
690
- my $code_real = slurp('template_real.c') ;
741
+ my $code_real = $TEMPLATE_REAL ;
691
742
$code_real =~ s/RANK/$rank/ge;
692
743
my $code_real_forward = $code_real;
693
744
my $code_real_backward = $code_real;
730
781
$dims_string = join(',', @dims);
731
782
delete $pp_def{RedoDimsCode};
732
783
$pp_def{Pars} = "in($dims_string); [o]out($dims_string);";
733
- $pp_def{Code} = slurp('template_complex.c') ;
784
+ $pp_def{Code} = $TEMPLATE_COMPLEX ;
734
785
$pp_def{Code} =~ s/TFD/TGC/g;
735
786
$pp_def{Code} =~ s/\*2//g; # the sizeof-doubling
736
787
$pp_def{GenericTypes} = [qw(G C)];
743
794
$dims_complex[0] = 'nhalf'; # first complex dim is real->dim(0)/2+1
744
795
$dims_real_string = join(',', @dims_real);
745
796
$dims_complex_string = join(',', @dims_complex);
746
- $code_real = slurp('template_real.c') ;
797
+ $code_real = $TEMPLATE_REAL ;
747
798
$code_real =~ s/RANK/$rank-1/ge;
748
799
$code_real_forward = $code_real;
749
800
$code_real_backward = $code_real;
773
824
pp_def( "__irNfft$rank", %pp_def );
774
825
}
775
826
776
- sub slurp
777
- {
827
+ sub slurp {
778
828
my $filename = shift;
779
- open FD, '<', $filename or die "Couldn't open '$filename' for rading";
780
-
829
+ open my $fh, '<', $filename or die "open '$filename' for reading: $!";
781
830
local $/ = undef;
782
- my $contents = <FD>;
783
- close FD;
784
- return qq{\n#line 0 "$filename"\n\n} . $contents;
831
+ return qq{\n#line 0 "$filename"\n\n} . <$fh>;
785
832
}
0 commit comments