57 fftw_destroy_plan(plan_forward_);
59 fftw_destroy_plan(plan_inverse_);
60 for (TransformSlot& slot : additional_slots_) {
61 if (slot.plan_forward)
62 fftw_destroy_plan(slot.plan_forward);
63 if (slot.plan_inverse)
64 fftw_destroy_plan(slot.plan_inverse);
77 bool use_measured_planning =
false)
override {
78 grid_dimension_1_ = dimension_1;
79 grid_dimension_2_ = dimension_2;
80 grid_dimension_3_ = dimension_3;
81 int total_points = dimension_1 * dimension_2 * dimension_3;
82 work_.resize(total_points);
113 constexpr std::size_t maximum_additional_scratch_bytes = 1024ull * 1024ull * 1024ull;
114 std::size_t bytes_per_slot = 2 *
static_cast<std::size_t
>(total_points) *
sizeof(
Complex);
115 int affordable_slots =
116 1 +
static_cast<int>(maximum_additional_scratch_bytes /
117 std::max<std::size_t>(bytes_per_slot, std::size_t{1}));
118 requested_slots = std::min(requested_slots, affordable_slots);
120#ifdef Q3_USE_FFTW_THREADS
121 static bool fftw_threads_initialized =
false;
122 int number_of_fft_threads = 1;
123 const char* omp_threads_env = std::getenv(
"OMP_NUM_THREADS");
124 if (omp_threads_env !=
nullptr) {
125 number_of_fft_threads = std::atoi(omp_threads_env);
126 if (number_of_fft_threads < 1) {
127 number_of_fft_threads = 1;
138 if (requested_slots > 1) {
139 number_of_fft_threads = 1;
141 if (number_of_fft_threads > 1) {
142 if (!fftw_threads_initialized) {
144 fftw_threads_initialized =
true;
146 fftw_plan_with_nthreads(number_of_fft_threads);
150 unsigned int planning_flags = use_measured_planning ? FFTW_MEASURE : FFTW_ESTIMATE;
151 output_buffer_.resize(total_points);
157 plan_forward_ = fftw_plan_dft_3d(dimension_1,
160 reinterpret_cast<fftw_complex*
>(work_.data()),
161 reinterpret_cast<fftw_complex*
>(output_buffer_.data()),
165 plan_inverse_ = fftw_plan_dft_3d(dimension_1,
168 reinterpret_cast<fftw_complex*
>(work_.data()),
169 reinterpret_cast<fftw_complex*
>(output_buffer_.data()),
181 additional_slots_.resize(
static_cast<std::size_t
>(std::max(requested_slots - 1, 0)));
182 for (TransformSlot& slot : additional_slots_) {
183 slot.input.resize(total_points);
184 slot.output.resize(total_points);
186 fftw_plan_dft_3d(dimension_1,
189 reinterpret_cast<fftw_complex*
>(slot.input.data()),
190 reinterpret_cast<fftw_complex*
>(slot.output.data()),
194 fftw_plan_dft_3d(dimension_1,
197 reinterpret_cast<fftw_complex*
>(slot.input.data()),
198 reinterpret_cast<fftw_complex*
>(slot.output.data()),
228 int total_points = grid_dimension_1_ * grid_dimension_2_ * grid_dimension_3_;
229 std::memcpy(work_.data(), data, total_points *
sizeof(
Complex));
230 fftw_execute(plan_inverse_);
231 Real inverse_total_points = 1.0 / total_points;
232 for (
int point_index = 0; point_index < total_points; point_index++) {
233 data[point_index] = output_buffer_[point_index] * inverse_total_points;