Alamo
FFT.H
Go to the documentation of this file.
1#ifndef OPERATOR_SPECTRAL_FFT_H_
2#define OPERATOR_SPECTRAL_FFT_H_
3
4#include <AMReX_BoxArray.H>
5#include <AMReX_BoxList.H>
6#include <AMReX_DistributionMapping.H>
7#include <AMReX_Interpolater.H>
8#include <AMReX_MultiFab.H>
9#include <AMReX_MultiFabUtil.H>
10#include <AMReX_Vector.H>
11
12#include <algorithm>
13#include <memory>
14
15#include "BC/Nothing.H"
16#include "Set/Set.H"
17#include "Util/Util.H"
18
19#ifdef ALAMO_FFT
20#include <AMReX_FFT.H>
21#endif
22
23namespace Operator
24{
25namespace Spectral
26{
27
28#ifdef ALAMO_FFT
29class FFT
30{
31public:
32 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
33 static Set::Scalar K (int dir, int mode, const int* length, const Set::Scalar* kscale)
34 {
35 if (dir == 0) return mode * kscale[0];
36 return (mode < length[dir] / 2 ? mode : mode - length[dir]) * kscale[dir];
37 }
38
39 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
40 static Set::Scalar Omega2 (int m, int n, int p, const int* length, const Set::Scalar* kscale)
41 {
42#if AMREX_SPACEDIM < 3
43 amrex::ignore_unused(p);
44#endif
45 return AMREX_D_TERM(K(0,m,length,kscale) * K(0,m,length,kscale),
46 + K(1,n,length,kscale) * K(1,n,length,kscale),
47 + K(2,p,length,kscale) * K(2,p,length,kscale));
48 }
49
50 FFT (const amrex::Geometry& a_geom)
51 : m_geom(a_geom),
52 m_fft(a_geom.Domain())
53 {
54 auto const& layout = m_fft.getSpectralDataLayout();
55 m_cba = layout.first;
56 m_cdm = layout.second;
57
58 m_domain = a_geom.Domain();
59 m_scaling = 1.0 / a_geom.Domain().d_numPts();
60 for (int dir = 0; dir < AMREX_SPACEDIM; ++dir)
61 {
62 m_length[dir] = a_geom.Domain().length(dir);
63 m_kscale[dir] = 2.0 * Set::Constant::Pi / (m_length[dir] * a_geom.CellSize(dir));
64 }
65 }
66
67 FFT (
68 const amrex::Vector<amrex::Geometry>& a_geom,
69 const amrex::Vector<amrex::IntVect>& a_ref_ratio,
70 int a_finest_level)
71 : FFT(a_geom[a_finest_level])
72 {
73 Util::Assert(INFO, TEST(a_finest_level >= 0));
74 Util::Assert(INFO, TEST(static_cast<int>(a_geom.size()) > a_finest_level));
75 Util::Assert(INFO, TEST(a_finest_level == 0 || static_cast<int>(a_ref_ratio.size()) >= a_finest_level));
76 m_geom_hierarchy = a_geom;
77 m_ref_ratio = a_ref_ratio;
78 }
79
80 FFT (const FFT&) = delete;
81 FFT (FFT&&) = delete;
82 FFT& operator= (const FFT&) = delete;
83 FFT& operator= (FFT&&) = delete;
84
85 const amrex::Geometry& Geom () const { return m_geom; }
86 const amrex::Box& Domain () const { return m_domain; }
87 const amrex::BoxArray& SpectralBoxArray () const { return m_cba; }
88 const amrex::DistributionMapping& SpectralDistributionMap () const { return m_cdm; }
89 int Length (int dir) const { return m_length[dir]; }
90 Set::Scalar KScale (int dir) const { return m_kscale[dir]; }
91 Set::Scalar K (int dir, int mode) const
92 {
93 return K(dir, mode, m_length, m_kscale);
94 }
95
96 Set::Scalar Omega2 (int m, int n, int p) const
97 {
98 return Omega2(m, n, p, m_length, m_kscale);
99 }
100
101 amrex::FabArray<amrex::BaseFab<Set::Complex> > MakeSpectralFab (int ncomp = 1, int ngrow = 0) const
102 {
103 return amrex::FabArray<amrex::BaseFab<Set::Complex> >(m_cba, m_cdm, ncomp, ngrow);
104 }
105
106 template <class F>
107 void ParallelFor (const amrex::Box& bx, F&& f) const
108 {
109 int length[AMREX_SPACEDIM];
110 Set::Scalar kscale[AMREX_SPACEDIM];
111 for (int dir = 0; dir < AMREX_SPACEDIM; ++dir)
112 {
113 length[dir] = m_length[dir];
114 kscale[dir] = m_kscale[dir];
115 }
116
117 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int m, int n, int p) {
118 f(m, n, p, Omega2(m, n, p, length, kscale));
119 });
120 }
121
122 void Forward (const amrex::MultiFab& in, amrex::FabArray<amrex::BaseFab<Set::Complex> >& out, int scomp = 0, int dcomp = 0)
123 {
124 m_fft.forward(in, out, scomp, dcomp);
125 }
126
127 void Backward (const amrex::FabArray<amrex::BaseFab<Set::Complex> >& in, amrex::MultiFab& out, int scomp = 0, int dcomp = 0)
128 {
129 m_fft.backward(in, out, scomp, dcomp);
130 out.mult(m_scaling, dcomp, 1, 0);
131 }
132
133 bool IsFullDomain (const amrex::MultiFab& mf) const
134 {
135 return mf.boxArray().complementIn(m_domain).isEmpty();
136 }
137
138 void Forward (
139 const amrex::Vector<std::unique_ptr<amrex::MultiFab> >& hierarchy,
140 int lev,
141 amrex::FabArray<amrex::BaseFab<Set::Complex> >& out,
142 int scomp = 0,
143 int dcomp = 0,
144 amrex::Real time = 0.0)
145 {
146 Util::Assert(INFO, TEST(lev >= 0));
147 Util::Assert(INFO, TEST(static_cast<int>(hierarchy.size()) > lev));
148 if (IsFullDomain(*hierarchy[lev]))
149 {
150 Forward(*hierarchy[lev], out, scomp, dcomp);
151 return;
152 }
153
154 auto full = CompositeToUniform(hierarchy, lev, time, hierarchy[lev]->nComp(), hierarchy[lev]->nGrow());
155 Forward(*full, out, scomp, dcomp);
156 }
157
158 void Backward (
159 const amrex::FabArray<amrex::BaseFab<Set::Complex> >& in,
160 amrex::Vector<std::unique_ptr<amrex::MultiFab> >& hierarchy,
161 int lev,
162 int scomp = 0,
163 int dcomp = 0)
164 {
165 Util::Assert(INFO, TEST(lev >= 0));
166 Util::Assert(INFO, TEST(static_cast<int>(hierarchy.size()) > lev));
167 if (IsFullDomain(*hierarchy[lev]))
168 {
169 Backward(in, *hierarchy[lev], scomp, dcomp);
170 return;
171 }
172
173 EnsureRealTemporary(hierarchy[lev]->nComp(), hierarchy[lev]->nGrow());
174 Backward(in, *m_real_tmp, scomp, dcomp);
175 CopyFromFull(*m_real_tmp, *hierarchy[lev], m_geom, dcomp, dcomp, 1);
176 }
177
178 static amrex::BoxArray FullBoxArray (const amrex::Geometry& geom, int max_grid_size = 0)
179 {
180 amrex::BoxArray ba(geom.Domain());
181 if (max_grid_size > 0) ba.maxSize(max_grid_size);
182 return ba;
183 }
184
185 static std::unique_ptr<amrex::MultiFab> MakeFullMultiFab (
186 const amrex::Geometry& geom,
187 int ncomp,
188 int ngrow = 0,
189 int max_grid_size = 0)
190 {
191 amrex::BoxArray ba = FullBoxArray(geom, max_grid_size);
192 amrex::DistributionMapping dm(ba);
193 return std::make_unique<amrex::MultiFab>(ba, dm, ncomp, ngrow);
194 }
195
196 static void CopyToFull (
197 amrex::MultiFab& full,
198 const amrex::MultiFab& src,
199 const amrex::Geometry& geom,
200 int scomp = 0,
201 int dcomp = 0,
202 int ncomp = -1)
203 {
204 if (ncomp < 0) ncomp = std::min(src.nComp() - scomp, full.nComp() - dcomp);
205 full.ParallelCopy(src, scomp, dcomp, ncomp, 0, 0, geom.periodicity());
206 }
207
208 static void CopyFromFull (
209 const amrex::MultiFab& full,
210 amrex::MultiFab& dst,
211 const amrex::Geometry& geom,
212 int scomp = 0,
213 int dcomp = 0,
214 int ncomp = -1)
215 {
216 if (ncomp < 0) ncomp = std::min(full.nComp() - scomp, dst.nComp() - dcomp);
217 dst.ParallelCopy(full, scomp, dcomp, ncomp, 0, 0, geom.periodicity());
218 }
219
220 template <class PhysBC>
221 static void ProlongateFromCoarse (
222 amrex::MultiFab& fine,
223 amrex::Real time,
224 const amrex::MultiFab& coarse,
225 const amrex::Geometry& crse_geom,
226 const amrex::Geometry& fine_geom,
227 const amrex::IntVect& ref_ratio,
228 PhysBC& physbc,
229 int scomp = 0,
230 int dcomp = 0,
231 int ncomp = -1)
232 {
233 if (ncomp < 0) ncomp = std::min(coarse.nComp() - scomp, fine.nComp() - dcomp);
234
235 amrex::Interpolater* mapper = &amrex::cell_cons_interp;
236 if (fine.boxArray().ixType() == amrex::IndexType::TheNodeType())
237 mapper = &amrex::node_bilinear_interp;
238
239 physbc.define(fine_geom);
240 amrex::Vector<amrex::BCRec> bcs(ncomp, physbc.GetBCRec());
241 amrex::InterpFromCoarseLevel(
242 fine, time, coarse, scomp, dcomp, ncomp,
243 crse_geom, fine_geom,
244 physbc, 0,
245 physbc, 0,
246 ref_ratio,
247 mapper, bcs, 0);
248 }
249
250 template <class PhysBC>
251 static std::unique_ptr<amrex::MultiFab> CompositeToUniform (
252 const amrex::Vector<amrex::MultiFab*>& hierarchy,
253 const amrex::Vector<amrex::Geometry>& geom,
254 const amrex::Vector<amrex::IntVect>& ref_ratio,
255 int finest_level,
256 amrex::Real time,
257 PhysBC& physbc,
258 int ncomp,
259 int ngrow = 0,
260 int max_grid_size = 0)
261 {
262 Util::Assert(INFO, TEST(finest_level >= 0));
263 Util::Assert(INFO, TEST(static_cast<int>(hierarchy.size()) > finest_level));
264 Util::Assert(INFO, TEST(static_cast<int>(geom.size()) > finest_level));
265
266 amrex::Vector<std::unique_ptr<amrex::MultiFab> > full(finest_level + 1);
267 for (int lev = 0; lev <= finest_level; ++lev)
268 {
269 full[lev] = MakeFullMultiFab(geom[lev], ncomp, ngrow, max_grid_size);
270 full[lev]->setVal(0.0);
271
272 if (lev > 0)
273 {
274 Util::Assert(INFO, TEST(static_cast<int>(ref_ratio.size()) >= lev));
275 ProlongateFromCoarse(*full[lev], time, *full[lev - 1], geom[lev - 1], geom[lev],
276 ref_ratio[lev - 1], physbc, 0, 0, ncomp);
277 }
278
279 CopyToFull(*full[lev], *hierarchy[lev], geom[lev], 0, 0, ncomp);
280 }
281
282 return std::move(full[finest_level]);
283 }
284
285 static void UniformToComposite (
286 const amrex::MultiFab& full_fine,
287 amrex::Vector<amrex::MultiFab*>& hierarchy,
288 const amrex::Vector<amrex::Geometry>& geom,
289 const amrex::Vector<amrex::IntVect>& ref_ratio,
290 int finest_level,
291 int ncomp,
292 int max_grid_size = 0)
293 {
294 Util::Assert(INFO, TEST(finest_level >= 0));
295 Util::Assert(INFO, TEST(static_cast<int>(hierarchy.size()) > finest_level));
296 Util::Assert(INFO, TEST(static_cast<int>(geom.size()) > finest_level));
297
298 amrex::Vector<std::unique_ptr<amrex::MultiFab> > full(finest_level + 1);
299 full[finest_level] = MakeFullMultiFab(geom[finest_level], ncomp, 0, max_grid_size);
300 CopyToFull(*full[finest_level], full_fine, geom[finest_level], 0, 0, ncomp);
301
302 for (int lev = finest_level - 1; lev >= 0; --lev)
303 {
304 Util::Assert(INFO, TEST(static_cast<int>(ref_ratio.size()) > lev));
305 full[lev] = MakeFullMultiFab(geom[lev], ncomp, 0, max_grid_size);
306 amrex::average_down(*full[lev + 1], *full[lev], 0, ncomp, ref_ratio[lev]);
307 }
308
309 for (int lev = 0; lev <= finest_level; ++lev)
310 CopyFromFull(*full[lev], *hierarchy[lev], geom[lev], 0, 0, ncomp);
311 }
312
313private:
314 void EnsureRealTemporary (int ncomp, int ngrow)
315 {
316 if (!m_real_tmp || m_real_tmp->nComp() != ncomp || m_real_tmp->nGrow() != ngrow)
317 m_real_tmp = MakeFullMultiFab(m_geom, ncomp, ngrow);
318 }
319
320 std::unique_ptr<amrex::MultiFab> CompositeToUniform (
321 const amrex::Vector<std::unique_ptr<amrex::MultiFab> >& hierarchy,
322 int finest_lev,
323 amrex::Real time,
324 int ncomp,
325 int ngrow)
326 {
327 Util::Assert(INFO, TEST(finest_lev >= 0));
328 Util::Assert(INFO, TEST(static_cast<int>(hierarchy.size()) > finest_lev));
329 Util::Assert(INFO, TEST(static_cast<int>(m_geom_hierarchy.size()) > finest_lev),
330 "Patchy spectral FFT requires hierarchy geometry context");
331 Util::Assert(INFO, TEST(finest_lev == 0 || static_cast<int>(m_ref_ratio.size()) >= finest_lev));
332
333 amrex::Vector<std::unique_ptr<amrex::MultiFab> > full(finest_lev + 1);
334 for (int ilev = 0; ilev <= finest_lev; ++ilev)
335 {
336 const amrex::Geometry& level_geom = m_geom_hierarchy[ilev];
337 full[ilev] = MakeFullMultiFab(level_geom, ncomp, ngrow);
338 full[ilev]->setVal(0.0);
339
340 if (ilev > 0)
341 {
342 BC::Nothing physbc;
343 ProlongateFromCoarse(*full[ilev], time, *full[ilev - 1],
344 m_geom_hierarchy[ilev - 1], level_geom, m_ref_ratio[ilev - 1], physbc, 0, 0, ncomp);
345 }
346
347 CopyToFull(*full[ilev], *hierarchy[ilev], level_geom, 0, 0, ncomp);
348 }
349
350 return std::move(full[finest_lev]);
351 }
352
353 amrex::Geometry m_geom;
354 amrex::FFT::R2C<Set::Scalar> m_fft;
355 amrex::BoxArray m_cba;
356 amrex::DistributionMapping m_cdm;
357 std::unique_ptr<amrex::MultiFab> m_real_tmp;
358 amrex::Vector<amrex::Geometry> m_geom_hierarchy;
359 amrex::Vector<amrex::IntVect> m_ref_ratio;
360 amrex::Box m_domain;
361 int m_length[AMREX_SPACEDIM];
362 Set::Scalar m_kscale[AMREX_SPACEDIM];
363 Set::Scalar m_scaling;
364};
365#else
366class FFT
367{
368public:
369 FFT (const amrex::Geometry&) { Util::Abort(INFO,"Alamo must be compiled with fft"); }
370};
371#endif
372
373}
374}
375
376#endif
#define TEST(x)
Definition Util.H:25
#define INFO
Definition Util.H:24
FFT(const amrex::Geometry &)
Definition FFT.H:369
Documentation for operator namespace.
Definition Diagonal.cpp:14
const Set::Scalar Pi
Definition Set.cpp:13
amrex::Real Scalar
Definition Base.H:19
void Abort(const char *msg)
Definition Util.cpp:268
AMREX_FORCE_INLINE void Assert(std::string file, std::string func, int line, std::string smt, bool pass, Args const &... args)
Definition Util.H:58