@@ -14,8 +14,7 @@ template<typename T> class Finufft_FFT_plan {
1414 Finufft_FFT_plan (const Finufft_FFT_plan &) = delete ;
1515 Finufft_FFT_plan &operator =(const Finufft_FFT_plan &) = delete ;
1616 [[maybe_unused]] void plan (const std::vector<int > & /* dims*/ , size_t /* batchSize*/ ,
17- std::complex <T> * /* ptr*/ , int /* sign*/ , int /* options*/ ,
18- int /* nthreads*/ ) {}
17+ int /* sign*/ , int /* options*/ , int /* nthreads*/ ) {}
1918
2019 [[maybe_unused]] static void forget_wisdom () {}
2120 [[maybe_unused]] static void cleanup () {}
@@ -28,6 +27,7 @@ template<typename T> class Finufft_FFT_plan {
2827#include < complex>
2928#include < fftw3.h> // (after complex) needed so can typedef FFTW_CPX
3029// clang-format on
30+ #include < array>
3131#include < mutex>
3232
3333template <typename T> class Finufft_FFT_plan {};
@@ -73,11 +73,17 @@ template<> struct Finufft_FFT_plan<float> {
7373 }
7474 Finufft_FFT_plan &operator =(const Finufft_FFT_plan &) = delete ;
7575
76- void plan
77- [[maybe_unused]] (const std::vector<int > &dims, size_t batchSize,
78- std::complex <float > *ptr, int sign, int options, int nthreads) {
76+ void plan [[maybe_unused]] (const std::vector<int > &dims, size_t batchSize, int sign,
77+ int options, int nthreads) {
7978 uint64_t nf = 1 ;
8079 for (auto i : dims) nf *= i;
80+ // FFTW_ESTIMATE never touches the buffer; FFTW_MEASURE etc. run trial FFTs.
81+ // Use a 1-element dummy for ESTIMATE, full aligned buffer otherwise.
82+ using cpxf = std::complex <float >;
83+ std::array<cpxf, 1 > dummy{};
84+ std::vector<cpxf> buf (options & FFTW_ESTIMATE ? 0 : nf * batchSize);
85+ auto *ptr =
86+ reinterpret_cast <fftwf_complex *>(buf.empty () ? dummy.data () : buf.data ());
8187 lock ();
8288 // Destroy existing plans before creating new ones (handles re-planning)
8389 if (plan_) {
@@ -91,14 +97,12 @@ template<> struct Finufft_FFT_plan<float> {
9197#ifdef _OPENMP
9298 fftwf_plan_with_nthreads (nthreads);
9399#endif
94- plan_ = fftwf_plan_many_dft (int (dims.size ()), dims.data (), int (batchSize),
95- reinterpret_cast <fftwf_complex *>(ptr), nullptr , 1 ,
96- int (nf), reinterpret_cast <fftwf_complex *>(ptr), nullptr ,
97- 1 , int (nf), sign, unsigned (options));
98- plan_adj_ = fftwf_plan_many_dft (int (dims.size ()), dims.data (), int (batchSize),
99- reinterpret_cast <fftwf_complex *>(ptr), nullptr , 1 ,
100- int (nf), reinterpret_cast <fftwf_complex *>(ptr),
101- nullptr , 1 , int (nf), -sign, unsigned (options));
100+ plan_ = fftwf_plan_many_dft (int (dims.size ()), dims.data (), int (batchSize), ptr,
101+ nullptr , 1 , int (nf), ptr, nullptr , 1 , int (nf), sign,
102+ unsigned (options));
103+ plan_adj_ = fftwf_plan_many_dft (int (dims.size ()), dims.data (), int (batchSize), ptr,
104+ nullptr , 1 , int (nf), ptr, nullptr , 1 , int (nf), -sign,
105+ unsigned (options));
102106 unlock ();
103107 }
104108 void execute [[maybe_unused]] (std::complex <float > *data) const {
@@ -158,11 +162,16 @@ template<> struct Finufft_FFT_plan<double> {
158162 }
159163 Finufft_FFT_plan &operator =(const Finufft_FFT_plan &) = delete ;
160164
161- void plan
162- [[maybe_unused]] (const std::vector<int > &dims, size_t batchSize,
163- std::complex <double > *ptr, int sign, int options, int nthreads) {
165+ void plan [[maybe_unused]] (const std::vector<int > &dims, size_t batchSize, int sign,
166+ int options, int nthreads) {
164167 uint64_t nf = 1 ;
165168 for (auto i : dims) nf *= i;
169+ // FFTW_ESTIMATE never touches the buffer; FFTW_MEASURE etc. run trial FFTs.
170+ // Use a 1-element dummy for ESTIMATE, full aligned buffer otherwise.
171+ using cpxd = std::complex <double >;
172+ std::array<cpxd, 1 > dummy{};
173+ std::vector<cpxd> buf (options & FFTW_ESTIMATE ? 0 : nf * batchSize);
174+ auto *ptr = reinterpret_cast <fftw_complex *>(buf.empty () ? dummy.data () : buf.data ());
166175 lock ();
167176 // Destroy existing plans before creating new ones (handles re-planning)
168177 if (plan_) {
@@ -176,14 +185,12 @@ template<> struct Finufft_FFT_plan<double> {
176185#ifdef _OPENMP
177186 fftw_plan_with_nthreads (nthreads);
178187#endif
179- plan_ = fftw_plan_many_dft (int (dims.size ()), dims.data (), int (batchSize),
180- reinterpret_cast <fftw_complex *>(ptr), nullptr , 1 , int (nf),
181- reinterpret_cast <fftw_complex *>(ptr), nullptr , 1 , int (nf),
182- sign, unsigned (options));
183- plan_adj_ = fftw_plan_many_dft (int (dims.size ()), dims.data (), int (batchSize),
184- reinterpret_cast <fftw_complex *>(ptr), nullptr , 1 ,
185- int (nf), reinterpret_cast <fftw_complex *>(ptr),
186- nullptr , 1 , int (nf), -sign, unsigned (options));
188+ plan_ =
189+ fftw_plan_many_dft (int (dims.size ()), dims.data (), int (batchSize), ptr, nullptr , 1 ,
190+ int (nf), ptr, nullptr , 1 , int (nf), sign, unsigned (options));
191+ plan_adj_ =
192+ fftw_plan_many_dft (int (dims.size ()), dims.data (), int (batchSize), ptr, nullptr , 1 ,
193+ int (nf), ptr, nullptr , 1 , int (nf), -sign, unsigned (options));
187194 unlock ();
188195 }
189196 void execute [[maybe_unused]] (std::complex <double > *data) const {
0 commit comments