1#ifndef AMREX_FFT_OPENBC_SOLVER_H_
2#define AMREX_FFT_OPENBC_SOLVER_H_
24template <
typename T = Real>
61 [[nodiscard]]
Box const&
Domain ()
const {
return m_domain; }
71 static IntVect make_padded_length (
Box const& domain,
Info const& info);
72 static Box make_grown_domain (
Box const& domain,
IntVect const& padded_len,
80 std::unique_ptr<R2C<T>> m_r2c_green;
87 int ndims = AMREX_SPACEDIM;
88#if (AMREX_SPACEDIM == 3)
89 if (info.twod_mode) { ndims = 2; }
93 if (info.openbc_padding) {
94 for (
int idim = 0; idim < ndims; ++idim) {
102Box OpenBCSolver<T>::make_grown_domain (
Box const& domain,
IntVect const& padded_len,
106 int ndims = AMREX_SPACEDIM;
107#if (AMREX_SPACEDIM == 3)
108 if (info.twod_mode) { ndims = 2; }
112 for (
int idim = 0; idim < ndims; ++idim) {
114 len[idim] <= std::numeric_limits<int>::max()/2,
115 "FFT::OpenBCSolver: padded domain length exceeds int range");
118 return Box(domain.smallEnd(), domain.smallEnd()+len-
IntVect(1), domain.ixType());
125 m_padded_length(
OpenBCSolver<T>::make_padded_length(domain, info)),
126 m_r2c(
OpenBCSolver<T>::make_grown_domain(domain, m_padded_length, info),
130 "FFT::OpenBCSolver does not support FFT::Info::batch_size > 1");
132#if (AMREX_SPACEDIM == 3)
134 auto gdom = make_grown_domain(domain, m_padded_length, m_info);
135 gdom.enclosedCells(2);
140 gdom.setBig(2, nprocs-1);
141 m_r2c_green = std::make_unique<R2C<T>>(gdom,m_info);
142 auto [sd, ord] = m_r2c_green->getSpectralData();
148 auto [sd, ord] = m_r2c.getSpectralData();
150 m_G_fft.define(sd->boxArray(), sd->DistributionMap(), 1, 0);
158 BL_PROFILE(
"OpenBCSolver::setGreensFunction");
160 auto* infab = m_info.twod_mode ? detail::get_fab(m_r2c_green->m_rx)
161 : detail::get_fab(m_r2c.m_rx);
162 auto const& lo = m_domain.smallEnd();
163 auto const& lo3 = lo.dim3();
164 auto const len3d = m_padded_length.dim3();
167 auto const& a = infab->array();
168 auto box = infab->box();
170 int ndims = m_info.twod_mode ? AMREX_SPACEDIM-1 : AMREX_SPACEDIM;
171 for (
int idim = 0; idim < ndims; ++idim) {
172 if (box.smallEnd(idim) == lo[idim] && box.length(idim) == 2*len[idim]) {
173 box.growHi(idim, -len[idim]+1);
182 if (i == len[0] || j == len[1] || k == len[2]) {
186 auto jj = (j > len[1]) ? 2*len[1]-j : j;
187 auto kk = (k > len[2]) ? 2*len[2]-k : k;
188 G = greens_function(ii+lo3.x,jj+lo3.y,kk+lo3.z);
190 for (
int koff = 0; koff < nimages[2]; ++koff) {
191 int k2 = (koff == 0) ? k : 2*len[2]-k;
192 if ((k2 == 2*len[2]) || (koff == 1 && k == len[2])) {
195 for (
int joff = 0; joff < nimages[1]; ++joff) {
196 int j2 = (joff == 0) ? j : 2*len[1]-j;
197 if ((j2 == 2*len[1]) || (joff == 1 && j == len[1])) {
200 for (
int ioff = 0; ioff < nimages[0]; ++ioff) {
201 int i2 = (ioff == 0) ? i : 2*len[0]-i;
202 if ((i2 == 2*len[0]) || (ioff == 1 && i == len[0])) {
205 a(i2+lo3.x,j2+lo3.y,k2+lo3.z) = G;
212 if (m_info.twod_mode) {
213 m_r2c_green->forward(m_r2c_green->m_rx);
215 m_r2c.forward(m_r2c.m_rx);
218 if (!m_info.twod_mode) {
219 auto [sd, ord] = m_r2c.getSpectralData();
221 auto const* srcfab = detail::get_fab(*sd);
223 auto* dstfab = detail::get_fab(m_G_fft);
231 m_r2c.prepare_openbc();
240 auto& inmf = m_r2c.m_rx;
242 inmf.ParallelCopy(rho, 0, 0, 1);
244 m_r2c.m_openbc_half = !m_info.twod_mode;
246 m_r2c.m_openbc_half =
false;
248 auto scaling_factor = m_r2c.scalingFactor();
250 auto const* gfab = detail::get_fab(m_G_fft);
252 auto [sd, ord] = m_r2c.getSpectralData();
254 auto* rhofab = detail::get_fab(*sd);
256 auto*
pdst = rhofab->dataPtr();
257 auto const* psrc = gfab->dataPtr();
258 Box const& rhobox = rhofab->box();
259#if (AMREX_SPACEDIM == 3)
261 if (m_info.twod_mode) {
270#if (AMREX_SPACEDIM == 3)
271 Long isrc = i % leng;
275 pdst[i] *= psrc[isrc] * scaling_factor;
278 amrex::Abort(
"FFT::OpenBCSolver::solve: how did this happen?");
282 m_r2c.m_openbc_half = !m_info.twod_mode;
283 m_r2c.backward_doit(phi, phi.nGrowVect());
284 m_r2c.m_openbc_half =
false;
#define BL_PROFILE(a)
Definition AMReX_BLProfiler.H:551
#define AMREX_ALWAYS_ASSERT_WITH_MESSAGE(EX, MSG)
Definition AMReX_BLassert.H:49
#define AMREX_ASSERT(EX)
Definition AMReX_BLassert.H:38
#define AMREX_GPU_DEVICE
Definition AMReX_GpuQualifiers.H:18
Real * pdst
Definition AMReX_HypreMLABecLap.cpp:1140
__host__ __device__ Long numPts() const noexcept
Return the number of points contained in the BoxND.
Definition AMReX_Box.H:364
__host__ __device__ IntVectND< dim > length() const noexcept
Return the length of the BoxND.
Definition AMReX_Box.H:155
Convolution-based solver for open boundary conditions using Green's functions.
Definition AMReX_FFT_OpenBCSolver.H:26
Box const & Domain() const
Access the physical domain this solver was built for.
Definition AMReX_FFT_OpenBCSolver.H:61
typename R2C< T >::MF MF
Definition AMReX_FFT_OpenBCSolver.H:28
void solve(MF &phi, MF const &rho)
Solve for phi given right-hand side rho.
Definition AMReX_FFT_OpenBCSolver.H:236
void setGreensFunction(F const &greens_function)
Populate the spectral Green's function used by subsequent solves.
Definition AMReX_FFT_OpenBCSolver.H:156
IntVect const & PaddedLength() const
Access the one-sided padded length used to build the internal FFT domain.
Definition AMReX_FFT_OpenBCSolver.H:68
typename R2C< T >::cMF cMF
Definition AMReX_FFT_OpenBCSolver.H:29
OpenBCSolver(Box const &domain, Info const &info=Info{})
Build a solver over domain using the FFT Info settings in info.
Definition AMReX_FFT_OpenBCSolver.H:122
Parallel Discrete Fourier Transform.
Definition AMReX_FFT_R2C.H:48
std::conditional_t< C, cMF, std::conditional_t< std::is_same_v< T, Real >, MultiFab, FabArray< BaseFab< T > > > > MF
Definition AMReX_FFT_R2C.H:53
Open Boundary Poisson Solver.
Definition AMReX_OpenBC.H:70
OpenBCSolver()=default
Construct an empty solver; call define() before solving.
amrex_long Long
Definition AMReX_INT.H:30
void ParallelForOMP(T n, L const &f) noexcept
Performance-portable kernel launch function with optional OpenMP threading.
Definition AMReX_GpuLaunch.H:328
Definition AMReX_FFT_Helper.H:53
int nextFastLen(int target, int nfactors=FastNumPrimeFactors())
Return the smallest fast FFT length greater than or equal to target.
Definition AMReX_FFT_Helper.H:286
DomainStrategy
Definition AMReX_FFT_Helper.H:57
void dtod_memcpy_async(void *p_d_dst, const void *p_d_src, const std::size_t sz) noexcept
Definition AMReX_GpuDevice.H:449
int NProcsSub() noexcept
number of ranks in current frame
Definition AMReX_ParallelContext.H:74
@ make_alias
Definition AMReX_MakeType.H:7
__host__ __device__ void ignore_unused(const Ts &...)
This shuts up the compiler about unused variables.
Definition AMReX.H:139
BoxND< 3 > Box
Box is an alias for amrex::BoxND instantiated with AMREX_SPACEDIM.
Definition AMReX_BaseFwd.H:30
IntVectND< 3 > IntVect
IntVect is an alias for amrex::IntVectND instantiated with AMREX_SPACEDIM.
Definition AMReX_BaseFwd.H:33
void Abort(const std::string &msg)
Print out message to cerr and exit via abort().
Definition AMReX.cpp:241
Definition AMReX_FFT_Helper.H:83
bool twod_mode
Definition AMReX_FFT_Helper.H:94
int batch_size
Batched FFT size. Only support in R2C, not R2X.
Definition AMReX_FFT_Helper.H:106
int nprocs
Max number of processes to use.
Definition AMReX_FFT_Helper.H:109
Fixed-size array that can be used on GPU.
Definition AMReX_Array.H:43