OpenPFC  0.1.4
Phase Field Crystal simulation framework
Loading...
Searching...
No Matches
fft.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2025 VTT Technical Research Centre of Finland Ltd
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
43#pragma once
44
46#include "openpfc/backends/heffte_adapter.hpp" // Ensure this is included for the conversion operator
51
52#include <heffte.h>
53#include <iostream>
54#include <memory>
55#include <mpi.h>
56
57namespace pfc {
58namespace fft {
59
60namespace layout {
61
62using box3di = heffte::box3d<int>;
63using Decomposition = pfc::decomposition::Decomposition;
65
72struct FFTLayout {
74 const int m_r2c_direction = 0;
75 const std::vector<heffte::box3d<int>> m_real_boxes;
76 const std::vector<heffte::box3d<int>> m_complex_boxes;
77};
78
88const FFTLayout create(const Decomposition &decomposition, int r2c_direction);
89
90inline const auto &get_real_box(const FFTLayout &layout, int i) {
91 return layout.m_real_boxes.at(i);
92}
93
94inline const auto &get_complex_box(const FFTLayout &layout, int i) {
95 return layout.m_complex_boxes.at(i);
96}
97
98inline auto get_r2c_direction(const FFTLayout &layout) {
99 return layout.m_r2c_direction;
100}
101
102} // namespace layout
103
104using pfc::types::Int3;
105using pfc::types::Real3;
106
107using Decomposition = pfc::decomposition::Decomposition;
108using RealVector = std::vector<double>;
109using ComplexVector = std::vector<std::complex<double>>;
111
112// Backend-aware DataBuffer type aliases
115#if defined(OpenPFC_ENABLE_CUDA)
119#endif
120
128enum class Backend {
129 FFTW,
130 CUDA
131};
132
133// Type aliases for different FFT backends
135#if defined(OpenPFC_ENABLE_CUDA)
136using fft_r2c_cuda =
138#endif
139
140struct IFFT {
141 virtual ~IFFT() = default;
142
149 virtual void forward(const RealVector &in, ComplexVector &out) = 0;
150
157 virtual void backward(const ComplexVector &in, RealVector &out) = 0;
158
159 virtual void reset_fft_time() = 0;
160 virtual double get_fft_time() const = 0;
161
162 virtual size_t size_inbox() const = 0;
163 virtual size_t size_outbox() const = 0;
164 virtual size_t size_workspace() const = 0;
165
173 virtual size_t get_allocated_memory_bytes() const = 0;
174};
175
248template <typename BackendTag = heffte::backend::fftw> struct FFT_Impl : IFFT {
249
250 // const Decomposition m_decomposition; /**< The Decomposition object. */
251 // const box3di m_inbox, m_outbox; /**< Local inbox and outbox boxes. */
252
253 using fft_type = heffte::fft3d_r2c<BackendTag>;
254 const fft_type m_fft;
255 double m_fft_time = 0.0;
257 // Backend-aware workspace - precision determined by data types in forward/backward
258 // calls Default to double precision workspace (can be overridden per call)
259 using workspace_type = typename heffte::fft3d_r2c<
261 workspace_type
269 FFT_Impl(fft_type fft) : m_fft(std::move(fft)), m_wrk(m_fft.size_workspace()) {}
270
306 // Forward method using DataBuffer (backend-aware, precision-aware via template)
307 template <typename RealBackendTag, typename ComplexBackendTag, typename RealType>
309 core::DataBuffer<ComplexBackendTag, std::complex<RealType>> &out) {
310 static_assert(std::is_same_v<RealBackendTag, ComplexBackendTag>,
311 "Input and output must use the same backend");
313 // HeFFTe's forward method is templated on input/output types and handles
314 // precision automatically Create workspace with matching precision
316 std::complex<RealType>>(m_fft.size_workspace());
317 m_fft.forward(in.data(), out.data(), wrk.data());
319 }
320
321 // Forward method using std::vector (implements IFFT interface)
322 // For CPU backend: works directly with std::vector
323 // For GPU backend: throws error (must use DataBuffer overload)
324 void forward(const RealVector &in, ComplexVector &out) override {
325 if constexpr (std::is_same_v<BackendTag, heffte::backend::fftw>) {
326 // CPU backend: call HeFFTe directly (no conversion needed)
328 m_fft.forward(in.data(), out.data(), m_wrk.data());
330 } else {
331 // GPU backend: must use DataBuffer
332 throw std::runtime_error(
333 "GPU FFT requires DataBuffer, not std::vector. Use forward(DataBuffer, "
334 "DataBuffer) instead.");
335 }
336 }
337
380 // Backward method using DataBuffer (backend-aware, precision-aware via template)
381 template <typename ComplexBackendTag, typename RealBackendTag, typename RealType>
382 void
383 backward(const core::DataBuffer<ComplexBackendTag, std::complex<RealType>> &in,
385 static_assert(std::is_same_v<ComplexBackendTag, RealBackendTag>,
386 "Input and output must use the same backend");
388 // HeFFTe's backward method is templated on input/output types and handles
389 // precision automatically Create workspace with matching precision
391 std::complex<RealType>>(m_fft.size_workspace());
392 m_fft.backward(in.data(), out.data(), wrk.data(), heffte::scale::full);
394 }
395
396 // Backward method using std::vector (implements IFFT interface)
397 // For CPU backend: works directly with std::vector
398 // For GPU backend: throws error (must use DataBuffer overload)
399 void backward(const ComplexVector &in, RealVector &out) override {
400 if constexpr (std::is_same_v<BackendTag, heffte::backend::fftw>) {
401 // CPU backend: call HeFFTe directly (no conversion needed)
403 m_fft.backward(in.data(), out.data(), m_wrk.data(), heffte::scale::full);
405 } else {
406 // GPU backend: must use DataBuffer
407 throw std::runtime_error(
408 "GPU FFT requires DataBuffer, not std::vector. Use backward(DataBuffer, "
409 "DataBuffer) instead.");
410 }
411 }
412
416 void reset_fft_time() override { m_fft_time = 0.0; }
417
423 double get_fft_time() const override { return m_fft_time; }
424
430 // const Decomposition &get_decomposition() { return m_decomposition; }
431
437 size_t size_inbox() const override { return m_fft.size_inbox(); }
438
444 size_t size_outbox() const override { return m_fft.size_outbox(); }
445
451 size_t size_workspace() const override { return m_fft.size_workspace(); }
452
460 size_t get_allocated_memory_bytes() const override {
461 return m_wrk.size() * sizeof(typename workspace_type::value_type);
462 }
463};
464
465// Type aliases for backward compatibility (defaults to FFTW backend)
466// Precision is handled by data types, not template parameters
468
469// Helper functions
470template <typename BackendTag>
471inline const auto &get_fft_object(const FFT_Impl<BackendTag> &fft) noexcept {
472 return fft.m_fft;
473}
474
475template <typename BackendTag>
476inline auto get_inbox(const FFT_Impl<BackendTag> &fft) noexcept {
477 return get_fft_object(fft).inbox();
478}
479
480template <typename BackendTag>
481inline auto get_outbox(const FFT_Impl<BackendTag> &fft) noexcept {
482 return get_fft_object(fft).outbox();
483}
484
485using heffte::plan_options;
486using layout::FFTLayout;
487
499FFT create(const FFTLayout &fft_layout, int rank_id, plan_options options);
500
512FFT create(const Decomposition &decomposition, int rank_id);
513
525FFT create(const Decomposition &decomposition);
526
540std::unique_ptr<IFFT> create_with_backend(const FFTLayout &fft_layout, int rank_id,
541 plan_options options, Backend backend);
542
552std::unique_ptr<IFFT> create_with_backend(const Decomposition &decomposition,
553 int rank_id, Backend backend);
554
555} // namespace fft
556
557using FFT = fft::FFT;
559
560} // namespace pfc
Backend tags for compile-time backend selection.
std::array< int, 3 > Int3
Type aliases for clarity.
Definition types.hpp:45
Backend-agnostic memory buffer with tag-based dispatch.
Domain decomposition for parallel MPI simulations.
std::unique_ptr< IFFT > create_with_backend(const FFTLayout &fft_layout, int rank_id, plan_options options, Backend backend)
Creates an FFT object with runtime backend selection.
heffte::box3d< int > box3di
Type alias for 3D integer box.
Definition fft.hpp:110
Backend
FFT backend selection.
Definition fft.hpp:128
@ FFTW
CPU-based FFT using FFTW (default)
@ CUDA
GPU-based FFT using cuFFT (requires CUDA support)
heffte::fft3d_r2c< heffte::backend::fftw > fft_r2c
FFTW backend (CPU)
Definition fft.hpp:134
Adapter functions for HeFFTe library integration.
K-space (Fourier space) helper functions for spectral methods.
Backend-agnostic memory buffer.
Definition databuffer.hpp:68
Describes a static, pure partitioning of the global simulation domain into local subdomains.
Definition decomposition.hpp:182
FFT class for distributed-memory parallel Fourier transforms.
Definition fft.hpp:248
void reset_fft_time() override
Resets the recorded FFT computation time to zero.
Definition fft.hpp:416
size_t size_inbox() const override
Returns the associated Decomposition object.
Definition fft.hpp:437
void forward(const RealVector &in, ComplexVector &out) override
Performs the forward FFT transformation.
Definition fft.hpp:324
size_t size_outbox() const override
Returns the size of the outbox used for FFT computations.
Definition fft.hpp:444
double m_fft_time
Definition fft.hpp:255
size_t size_workspace() const override
Returns the size of the workspace used for FFT computations.
Definition fft.hpp:451
const fft_type m_fft
Definition fft.hpp:254
void backward(const ComplexVector &in, RealVector &out) override
Performs the backward (inverse) FFT transformation.
Definition fft.hpp:399
FFT_Impl(fft_type fft)
Constructs an FFT object with the given HeFFTe FFT object.
Definition fft.hpp:269
double get_fft_time() const override
Returns the recorded FFT computation time.
Definition fft.hpp:423
workspace_type m_wrk
Definition fft.hpp:262
size_t get_allocated_memory_bytes() const override
Returns the total memory allocated by HeFFTe in bytes.
Definition fft.hpp:460
Definition fft.hpp:140
virtual void backward(const ComplexVector &in, RealVector &out)=0
Performs the backward (inverse) FFT transformation.
virtual void forward(const RealVector &in, ComplexVector &out)=0
Performs the forward FFT transformation.
virtual size_t get_allocated_memory_bytes() const =0
Returns the total memory allocated by HeFFTe in bytes.
Structure to hold the layout of FFT data.
Definition fft.hpp:72
const Decomposition m_decomposition
The Decomposition object.
Definition fft.hpp:73
const std::vector< heffte::box3d< int > > m_complex_boxes
Complex boxes for FFT.
Definition fft.hpp:76
const int m_r2c_direction
Real-to-complex symmetry direction.
Definition fft.hpp:74
const std::vector< heffte::box3d< int > > m_real_boxes
Real boxes for FFT.
Definition fft.hpp:75
Represents the global simulation domain (the "world").
Definition world.hpp:91
World(const Int3 &lower, const Int3 &upper, const CoordinateSystem< T > &cs)
Constructs a World object.
World class definition and unified interface.