@@ -33,14 +33,23 @@ public:
3333 * \param domain the forward domain (i.e., the domain of the real data)
3434 * \param info optional information
3535 */
36- explicit LocalR2C (IntVectND<M> const & fft_size, bool cache_plan = true );
36+ explicit LocalR2C (IntVectND<M> const & fft_size,
37+ #ifdef AMREX_USE_GPU
38+ bool cache_plan = true );
39+ #else
40+ bool cache_plan = false );
41+ // Caching does not work with FFTW, because the plan is associated with
42+ // data pointers.
43+ #endif
3744
3845 ~LocalR2C ();
3946
47+ LocalR2C () = default;
48+ LocalR2C (LocalR2C &&);
49+ LocalR2C& operator = (LocalR2C &&);
50+
4051 LocalR2C (LocalR2C const &) = delete ;
41- LocalR2C (LocalR2C &&) = delete ;
4252 LocalR2C& operator = (LocalR2C const &) = delete ;
43- LocalR2C& operator = (LocalR2C &&) = delete ;
4453
4554 /* *
4655 * \brief Forward transform
@@ -56,6 +65,8 @@ public:
5665 DIR == Direction::both, int > = 0 >
5766 void forward (T const * indata, GpuComplex<T>* outdata);
5867
68+ void clear ();
69+
5970 /* *
6071 * \brief Backward transform
6172 *
@@ -88,21 +99,29 @@ private:
8899 void * m_buffer = nullptr ; // for fftw
89100
90101#if defined(AMREX_USE_SYCL)
91- gpuStream_t m_gpu_stream;
102+ gpuStream_t m_gpu_stream{} ;
92103#endif
93104
94105 IntVectND<M> m_real_size;
95106 IntVectND<M> m_spectral_size;
96107
97- bool m_cache_plan;
108+ bool m_cache_plan = false ;
98109};
99110
100111template <typename T, FFT::Direction D, int M>
101112LocalR2C<T,D,M>::LocalR2C (IntVectND<M> const & fft_size, bool cache_plan)
102113 : m_real_size(fft_size),
103114 m_spectral_size (fft_size),
115+ #if defined(AMREX_USE_GPU)
104116 m_cache_plan (cache_plan)
117+ #else
118+ m_cache_plan (false )
119+ #endif
105120{
121+ #if !defined(AMREX_USE_GPU)
122+ amrex::ignore_unused (cache_plan);
123+ #endif
124+
106125 BL_PROFILE (" FFT::LocalR2C" );
107126 m_spectral_size[0 ] = m_real_size[0 ]/2 + 1 ;
108127
@@ -123,14 +142,14 @@ LocalR2C<T,D,M>::LocalR2C (IntVectND<M> const& fft_size, bool cache_plan)
123142#endif
124143
125144#ifdef AMREX_USE_SYCL
126- m_fft_fwd.template init_r2c <Direction::forward,M>(m_real_size, m_buffer, cache_plan );
145+ m_fft_fwd.template init_r2c <Direction::forward,M>(m_real_size, m_buffer, m_cache_plan );
127146 m_fft_bwd = m_fft_fwd;
128147#else
129148 if constexpr (D == Direction::both || D == Direction::forward) {
130- m_fft_fwd.template init_r2c <Direction::forward,M>(m_real_size, m_buffer, cache_plan );
149+ m_fft_fwd.template init_r2c <Direction::forward,M>(m_real_size, m_buffer, m_cache_plan );
131150 }
132151 if constexpr (D == Direction::both || D == Direction::backward) {
133- m_fft_bwd.template init_r2c <Direction::backward,M>(m_real_size, m_buffer, cache_plan );
152+ m_fft_bwd.template init_r2c <Direction::backward,M>(m_real_size, m_buffer, m_cache_plan );
134153 }
135154#endif
136155
@@ -140,18 +159,68 @@ LocalR2C<T,D,M>::LocalR2C (IntVectND<M> const& fft_size, bool cache_plan)
140159}
141160
142161template <typename T, FFT::Direction D, int M>
143- LocalR2C<T,D,M>::~LocalR2C ()
162+ void LocalR2C<T,D,M>::clear ()
144163{
145- static_assert (M >= 1 && M <= 3 );
146-
147- if (m_buffer) { The_Arena ()->free (m_buffer); }
164+ if (m_buffer) {
165+ The_Arena ()->free (m_buffer);
166+ m_buffer = nullptr ;
167+ }
148168
149169 if (!m_cache_plan) {
150170 if (m_fft_bwd.plan != m_fft_fwd.plan ) {
151171 m_fft_bwd.destroy ();
152172 }
153173 m_fft_fwd.destroy ();
154174 }
175+
176+ m_fft_fwd = Plan<T>{};
177+ m_fft_bwd = Plan<T>{};
178+ }
179+
180+ template <typename T, FFT::Direction D, int M>
181+ LocalR2C<T,D,M>::~LocalR2C ()
182+ {
183+ static_assert (M >= 1 && M <= 3 );
184+ clear ();
185+ }
186+
187+ template <typename T, FFT::Direction D, int M>
188+ LocalR2C<T,D,M>::LocalR2C (LocalR2C && rhs)
189+ : m_fft_fwd(rhs.m_fft_fwd),
190+ m_fft_bwd (rhs.m_fft_bwd),
191+ m_buffer(rhs.m_buffer),
192+ #if defined(AMREX_USE_SYCL)
193+ m_gpu_stream (rhs.m_gpu_stream),
194+ #endif
195+ m_real_size (rhs.m_real_size),
196+ m_spectral_size(rhs.m_spectral_size),
197+ m_cache_plan(rhs.m_cache_plan)
198+ {
199+ rhs.m_buffer = nullptr ;
200+ rhs.m_cache_plan = true ; // So that plans in rhs are not destroyed.
201+ }
202+
203+ template <typename T, FFT::Direction D, int M>
204+ LocalR2C<T,D,M>& LocalR2C<T,D,M>::operator = (LocalR2C && rhs)
205+ {
206+ if (this == &rhs) { return *this ; }
207+
208+ this ->clear ();
209+
210+ m_fft_fwd = rhs.m_fft_fwd ;
211+ m_fft_bwd = rhs.m_fft_bwd ;
212+ m_buffer = rhs.m_buffer ;
213+ #if defined(AMREX_USE_SYCL)
214+ m_gpu_stream = rhs.m_gpu_stream ;
215+ #endif
216+ m_real_size = rhs.m_real_size ;
217+ m_spectral_size = rhs.m_spectral_size ;
218+ m_cache_plan = rhs.m_cache_plan ;
219+
220+ rhs.m_buffer = nullptr ;
221+ rhs.m_cache_plan = true ; // So that plans in rhs are not destroyed.
222+
223+ return *this ;
155224}
156225
157226template <typename T, FFT::Direction D, int M>
0 commit comments