include/pops/numerics/elliptic/poisson/poisson_operator.hpp Source FileΒΆ

adc_cpp: include/pops/numerics/elliptic/poisson/poisson_operator.hpp Source File
adc_cpp 0.3.0
Model-free C++23 core for coupled hyperbolic-elliptic systems on adaptive (AMR) meshes, with MPI and GPU (Kokkos) backends
poisson_operator.hpp
Go to the documentation of this file.
1#pragma once
2
28
35
36namespace pops {
37
38// Harmonic mean of two center permittivities -> face permittivity.
39// Guard against division by 0 if both centers are zero (inactive cell).
41 const Real s = ec + ev;
42 return s > Real(0) ? Real(2) * ec * ev / s : Real(0);
43}
44
45namespace detail {
46// Weights of the FOUR faces (xm, xp, ym, yp) at (i,j) for the FACE permittivity path (he), with or
47// without cut-cell. Each face = HARMONIC mean of the two adjacent centers (eps_x for x faces,
48// eps_y for y faces); in cut-cell (hc) the face Shortley-Weller weight is multiplied by its
49// permittivity, otherwise 1/h^2 (idx2 / idy2) is applied. Free POPS_HD functor (device-clean) shared
50// by the three he kernels (apply / residual / smoother); body STRICTLY identical to the three
51// original copies -> bit-identical output. Output by reference (wxm/wxp/wym/wyp).
52POPS_HD inline void face_weights(const ConstArray4& ep, const ConstArray4& ey, int i, int j,
53 Real idx2, Real idy2, bool hc, const ConstArray4& cf, Real& wxm,
54 Real& wxp, Real& wym, Real& wyp) {
55 const Real ec = ep(i, j); // eps_x at center (x faces)
56 const Real ecy = ey(i, j); // eps_y at center (y faces); == ec when isotropic
57 const Real exm = eps_harmonic(ec, ep(i - 1, j));
58 const Real exp = eps_harmonic(ec, ep(i + 1, j));
59 const Real eym = eps_harmonic(ecy, ey(i, j - 1));
60 const Real eyp = eps_harmonic(ecy, ey(i, j + 1));
61 if (hc) { // cut-cell: eps_face multiplies each Shortley-Weller weight
62 wxm = cf(i, j, 0) * exm;
63 wxp = cf(i, j, 1) * exp;
64 wym = cf(i, j, 2) * eym;
65 wyp = cf(i, j, 3) * eyp;
66 } else { // 5-point stencil with variable face coefficient
67 wxm = exm * idx2;
68 wxp = exp * idx2;
69 wym = eym * idy2;
70 wyp = eyp * idy2;
71 }
72}
73
74// Divergence of the CROSS FLUXES of the full tensor at (i,j): d_x(Axy d_y phi) + d_y(Ayx d_x phi),
75// discretized by finite volumes (9-point stencil) as described in the header. Returns the
76// contribution to be ADDED to div(A grad phi). Free POPS_HD functor (device-clean) shared by
77// apply_laplacian and poisson_residual; face coefficient = ARITHMETIC mean. hxy/hyx
78// guard each half-term: an ABSENT coefficient (field not provided) contributes 0 without deref.
79POPS_HD inline Real cross_div(const ConstArray4& p, bool hxy, const ConstArray4& axy, bool hyx,
80 const ConstArray4& ayx, int i, int j, Real idx, Real idy) {
81 Real out = Real(0);
82 if (hxy) { // x faces: cross flux = Axy_face * (d_y phi)_face, tangential averaged over 4 corners.
83 const Real axy_xp = Real(0.5) * (axy(i, j) + axy(i + 1, j));
84 const Real axy_xm = Real(0.5) * (axy(i, j) + axy(i - 1, j));
85 const Real dyf_xp =
86 (p(i, j + 1) + p(i + 1, j + 1) - p(i, j - 1) - p(i + 1, j - 1)) * (Real(0.25) * idy);
87 const Real dyf_xm =
88 (p(i - 1, j + 1) + p(i, j + 1) - p(i - 1, j - 1) - p(i, j - 1)) * (Real(0.25) * idy);
89 out += (axy_xp * dyf_xp - axy_xm * dyf_xm) * idx;
90 }
91 if (hyx) { // y faces: cross flux = Ayx_face * (d_x phi)_face.
92 const Real ayx_yp = Real(0.5) * (ayx(i, j) + ayx(i, j + 1));
93 const Real ayx_ym = Real(0.5) * (ayx(i, j) + ayx(i, j - 1));
94 const Real dxf_yp =
95 (p(i + 1, j) + p(i + 1, j + 1) - p(i - 1, j) - p(i - 1, j + 1)) * (Real(0.25) * idx);
96 const Real dxf_ym =
97 (p(i + 1, j - 1) + p(i + 1, j) - p(i - 1, j - 1) - p(i - 1, j)) * (Real(0.25) * idx);
98 out += (ayx_yp * dxf_yp - ayx_ym * dxf_ym) * idy;
99 }
100 return out;
101}
102
103// NAMED FUNCTORS (and not POPS_HD lambdas) for the Poisson operator and Gauss-Seidel smoother kernels.
104// Same reasons as the rest of the elliptic path (#93, recipe #64): these kernels are
105// first-instantiated from the MG V-cycle pulled from an external TU (harness / native loader); an extended
106// lambda there breaks the device kernel emission under nvcc (null kernel-stub -> Cuda segfault in
107// Release -O without -g). Body STRICTLY identical to the former lambdas (same he/hc/hk branches,
108// same stencil) -> bit-identical residual and potential on CPU and device.
109
110// L = div(A grad phi) - kappa phi (apply_laplacian). cf/ep/ey/ka unused if the flag is false.
111// hxy/hyx => FULL tensor: we ADD the cross fluxes d_x(Axy d_y phi) + d_y(Ayx d_x phi) (idx/idy
112// = 1/dx, 1/dy; axy/ayx = off-diagonal coefficients at center). hxy=hyx=false => bit-identical.
117 bool hc;
119 bool he;
121 bool hk;
123 bool hxy, hyx;
125 int c; // component the matvec acts on; 0 for the scalar Poisson path (bit-identical 2-arg access)
126 POPS_HD void operator()(int i, int j) const {
127 if (he) { // face permittivity (harmonic), with or without cut-cell (coefficient path: comp 0 only)
128 Real wxm, wxp, wym, wyp;
129 face_weights(ep, ey, i, j, idx2, idy2, hc, cf, wxm, wxp, wym, wyp);
130 L(i, j) = wxp * p(i + 1, j) + wxm * p(i - 1, j) + wyp * p(i, j + 1) + wym * p(i, j - 1) -
131 (wxm + wxp + wym + wyp) * p(i, j);
132 } else if (hc) // cut-cell coefficient path (comp 0 only)
133 L(i, j) = cf(i, j, 1) * p(i + 1, j) + cf(i, j, 0) * p(i - 1, j) + cf(i, j, 3) * p(i, j + 1) +
134 cf(i, j, 2) * p(i, j - 1) - cf(i, j, 4) * p(i, j);
135 else // bare 5-point stencil, applied PER COMPONENT (c); c==0 => the scalar path, bit-identical.
136 L(i, j, c) = (p(i + 1, j, c) - 2 * p(i, j, c) + p(i - 1, j, c)) * idx2 +
137 (p(i, j + 1, c) - 2 * p(i, j, c) + p(i, j - 1, c)) * idy2;
138 // FULL block: ADDITIVE cross fluxes (after the diagonal stencil). hxy=hyx=false => +0, bit-identical.
139 if (hxy || hyx)
140 L(i, j) += cross_div(p, hxy, axy, hyx, ayx, i, j, idx, idy);
141 // Helmholtz / screened operator: L phi = div(A grad phi) - kappa phi.
142 if (hk)
143 L(i, j) -= ka(i, j) * p(i, j);
144 }
145};
146
147// res = f - L phi on active cells, 0 on conductor cells (poisson_residual).
148// hx => FULL tensor: ADDITIVE cross fluxes (cf. ApplyLaplacianKernel). hx=false => bit-identical.
153 bool hm;
155 bool hc;
157 bool he;
159 bool hk;
161 bool hxy, hyx;
163 POPS_HD void operator()(int i, int j) const {
164 if (hm && mk(i, j) == Real(0)) {
165 r(i, j) = 0;
166 return;
167 }
168 Real lap;
169 if (he) { // face permittivity (harmonic), with or without cut-cell
170 Real wxm, wxp, wym, wyp;
171 face_weights(ep, ey, i, j, idx2, idy2, hc, cf, wxm, wxp, wym, wyp);
172 lap = wxp * p(i + 1, j) + wxm * p(i - 1, j) + wyp * p(i, j + 1) + wym * p(i, j - 1) -
173 (wxm + wxp + wym + wyp) * p(i, j);
174 } else if (hc)
175 lap = cf(i, j, 1) * p(i + 1, j) + cf(i, j, 0) * p(i - 1, j) + cf(i, j, 3) * p(i, j + 1) +
176 cf(i, j, 2) * p(i, j - 1) - cf(i, j, 4) * p(i, j);
177 else
178 lap = (p(i + 1, j) - 2 * p(i, j) + p(i - 1, j)) * idx2 +
179 (p(i, j + 1) - 2 * p(i, j) + p(i, j - 1)) * idy2;
180 // FULL block: ADDITIVE cross fluxes (after the diagonal stencil). hxy=hyx=false => +0, bit-identical.
181 if (hxy || hyx)
182 lap += cross_div(p, hxy, axy, hyx, ayx, i, j, idx, idy);
183 // res = f - L phi, L phi = div(A grad phi) - kappa phi = lap - kappa phi.
184 r(i, j) = ff(i, j) - lap + (hk ? ka(i, j) * p(i, j) : Real(0));
185 }
186};
187} // namespace detail
188
189// a_xy/a_yx: off-diagonal coefficients (FULL tensor). nullptr => cross term absent
190// (bit-identical diagonal/Poisson operator). Ghosts (1 layer) assumed filled by the caller.
191inline void apply_laplacian(const MultiFab& phi, const Geometry& geom, MultiFab& lap,
192 const MultiFab* coef = nullptr, const MultiFab* eps = nullptr,
193 const MultiFab* kappa = nullptr, const MultiFab* eps_y = nullptr,
194 const MultiFab* a_xy = nullptr, const MultiFab* a_yx = nullptr) {
195 const Real idx2 = Real(1) / (geom.dx() * geom.dx());
196 const Real idy2 = Real(1) / (geom.dy() * geom.dy());
197 const Real idx = Real(1) / geom.dx();
198 const Real idy = Real(1) / geom.dy();
199 for (int li = 0; li < phi.local_size(); ++li) {
200 const ConstArray4 p = phi.fab(li).const_array();
201 Array4 L = lap.fab(li).array();
202 const Box2D v = lap.box(li);
203 const bool hc = coef != nullptr;
204 const ConstArray4 cf = hc ? coef->fab(li).const_array() : ConstArray4{};
205 const bool he = eps != nullptr;
206 const ConstArray4 ep = he ? eps->fab(li).const_array() : ConstArray4{};
207 // eps_y==nullptr => isotropic: y faces read the same field as the x faces (eps_x).
208 const ConstArray4 ey = (he && eps_y) ? eps_y->fab(li).const_array() : ep;
209 const bool hk = kappa != nullptr; // reaction term -kappa phi
210 const ConstArray4 ka = hk ? kappa->fab(li).const_array() : ConstArray4{};
211 const bool hxy = a_xy != nullptr; // Axy cross half-term (x faces)
212 const bool hyx = a_yx != nullptr; // Ayx cross half-term (y faces)
213 const ConstArray4 axy = hxy ? a_xy->fab(li).const_array() : ConstArray4{};
214 const ConstArray4 ayx = hyx ? a_yx->fab(li).const_array() : ConstArray4{};
215 // Bare 5-point matvec acts on EVERY component (a vector / state matrix-free operator: the
216 // condensed-Schur block unknown). The coefficient / cross / Helmholtz branches are single-component
217 // (the scalar Poisson operator), so they run for component 0 only; nc==1 reproduces the old
218 // single-pass, bit-identical scalar path.
219 const int nc = (he || hc || hk || hxy || hyx) ? 1 : lap.ncomp();
220 for (int c = 0; c < nc; ++c)
221 for_each_cell(v, detail::ApplyLaplacianKernel{p, L, idx2, idy2, idx, idy, hc, cf, he, ep, ey,
222 hk, ka, hxy, hyx, axy, ayx, c});
223 }
224}
225
226namespace detail {
227// Centered finite-volume divergence of a cell-centered vector flux: the x-flux is read from
228// component @c cx of fx and the y-flux from component @c cy of fy:
229// div(i,j) = (fx(i+1,j,cx) - fx(i-1,j,cx)) / (2 dx) + (fy(i,j+1,cy) - fy(i,j-1,cy)) / (2 dy),
230// second order, the exact inverse of the centered gradient (field_postprocess). Named functor
231// (and not an POPS_HD lambda) for the same reason as the other elliptic kernels (#93): it is
232// first-instantiated from an external TU (the compiled time-program .so) and an extended lambda
233// breaks the device kernel emission under nvcc. half_idx/half_idy = 1/(2 dx), 1/(2 dy).
238 int cx, cy;
239 POPS_HD void operator()(int i, int j) const {
240 div(i, j) = (fx(i + 1, j, cx) - fx(i - 1, j, cx)) * half_idx +
241 (fy(i, j + 1, cy) - fy(i, j - 1, cy)) * half_idy;
242 }
243};
244} // namespace detail
245
246// Centered FV divergence of a cell-centered vector flux into div_out (component 0):
247// div = d fx/dx + d fy/dy, centered (the matching inverse of the centered gradient). The x-flux is
248// read from component @p cx of @p fx and the y-flux from component @p cy of @p fy, so the 2-component
249// output of the centered gradient (field_postprocess: d/dx in component 0, d/dy in component 1) can be
250// fed back as a SINGLE field passed for both arguments (apply_divergence(g, g, geom, out, 0, 1)) to
251// recover the 5-point Laplacian, or two distinct single-component fluxes with cx = cy = 0. Ghosts (1
252// layer) assumed filled by the caller. Mirrors apply_laplacian's structure (one local-fab loop, named
253// functor). The Schur condensation builder uses the same stencil inline (coupling/schur/core/
254// schur_condensation.hpp SchurRhsAssembleKernel, which fuses it with -Lap phi^n -- not refactored to
255// call this so the native source path stays bit-identical).
256inline void apply_divergence(const MultiFab& fx, const MultiFab& fy, const Geometry& geom,
257 MultiFab& div_out, int cx = 0, int cy = 0) {
258 const Real half_idx = Real(1) / (Real(2) * geom.dx());
259 const Real half_idy = Real(1) / (Real(2) * geom.dy());
260 for (int li = 0; li < div_out.local_size(); ++li) {
261 const ConstArray4 fxv = fx.fab(li).const_array();
262 const ConstArray4 fyv = fy.fab(li).const_array();
263 Array4 d = div_out.fab(li).array();
264 for_each_cell(div_out.box(li),
265 detail::DivergenceKernel{fxv, fyv, d, half_idx, half_idy, cx, cy});
266 }
267}
268
269// res = f - div(A grad phi) on active cells, 0 on conductor cells.
270// a_xy/a_yx: off-diagonal coefficients (cf. apply_laplacian). nullptr => bit-identical.
271inline void poisson_residual(MultiFab& phi, const MultiFab& f, const Geometry& geom,
272 const BCRec& bc, MultiFab& res, const MultiFab* mask = nullptr,
273 const MultiFab* coef = nullptr, const MultiFab* eps = nullptr,
274 const MultiFab* kappa = nullptr, const MultiFab* eps_y = nullptr,
275 const MultiFab* a_xy = nullptr, const MultiFab* a_yx = nullptr) {
276 device_fence(); // GPU: phi may have been written by a kernel (smoother); we
277 // wait before the host read in fill_ghosts.
278 fill_ghosts(phi, geom.domain, bc);
279 const Real idx2 = Real(1) / (geom.dx() * geom.dx());
280 const Real idy2 = Real(1) / (geom.dy() * geom.dy());
281 const Real idx = Real(1) / geom.dx();
282 const Real idy = Real(1) / geom.dy();
283 for (int li = 0; li < phi.local_size(); ++li) {
284 const ConstArray4 p = phi.fab(li).const_array();
285 const ConstArray4 ff = f.fab(li).const_array();
286 Array4 r = res.fab(li).array();
287 const Box2D v = res.box(li);
288 const bool hm = mask != nullptr;
289 const ConstArray4 mk = hm ? mask->fab(li).const_array() : ConstArray4{};
290 const bool hc = coef != nullptr;
291 const ConstArray4 cf = hc ? coef->fab(li).const_array() : ConstArray4{};
292 const bool he = eps != nullptr;
293 const ConstArray4 ep = he ? eps->fab(li).const_array() : ConstArray4{};
294 // eps_y==nullptr => isotropic: y faces read the same field as the x faces (eps_x).
295 const ConstArray4 ey = (he && eps_y) ? eps_y->fab(li).const_array() : ep;
296 const bool hk = kappa != nullptr; // reaction term -kappa phi
297 const ConstArray4 ka = hk ? kappa->fab(li).const_array() : ConstArray4{};
298 const bool hxy = a_xy != nullptr; // Axy cross half-term (x faces)
299 const bool hyx = a_yx != nullptr; // Ayx cross half-term (y faces)
300 const ConstArray4 axy = hxy ? a_xy->fab(li).const_array() : ConstArray4{};
301 const ConstArray4 ayx = hyx ? a_yx->fab(li).const_array() : ConstArray4{};
303 detail::PoissonResidualKernel{p, ff, r, idx2, idy2, idx, idy, hm, mk, hc,
304 cf, he, ep, ey, hk, ka, hxy, hyx, axy, ayx});
305 }
306}
307
308namespace detail {
309// Red-black Gauss-Seidel smoother on one color (gs_color). p is WRITTEN in place. Body identical to
310// the former lambda -> bit-identical. See the comment of the other kernels (#93) for the motivation
311// of the named functor.
316 int color;
317 bool hm;
319 bool hc;
321 bool he;
323 bool hk;
325 POPS_HD void operator()(int i, int j) const {
326 if (((i + j) & 1) != color)
327 return;
328 if (hm && mk(i, j) == Real(0))
329 return; // conductor: pins phi=0
330 Real off, diag;
331 if (he) { // face permittivity (harmonic), with or without cut-cell
332 Real wxm, wxp, wym, wyp;
333 face_weights(ep, ey, i, j, idx2, idy2, hc, cf, wxm, wxp, wym, wyp);
334 off = wxp * p(i + 1, j) + wxm * p(i - 1, j) + wyp * p(i, j + 1) + wym * p(i, j - 1);
335 diag = wxm + wxp + wym + wyp;
336 } else if (
337 hc) { // cut-cell stencil (Shortley-Weller); conductor neighbor = phi=0 on the circle
338 off = cf(i, j, 1) * p(i + 1, j) + cf(i, j, 0) * p(i - 1, j) + cf(i, j, 3) * p(i, j + 1) +
339 cf(i, j, 2) * p(i, j - 1);
340 diag = cf(i, j, 4);
341 } else {
342 off = (p(i + 1, j) + p(i - 1, j)) * idx2 + (p(i, j + 1) + p(i, j - 1)) * idy2;
343 diag = diag0;
344 }
345 // Reaction term: the operator becomes div(eps grad phi) - kappa phi, so the
346 // diagonal gains +kappa (kappa >= 0 => more diagonally dominant, MG converges better).
347 p(i, j) = (off - ff(i, j)) / (diag + (hk ? ka(i, j) : Real(0)));
348 }
349};
350
351inline void gs_color(MultiFab& phi, const MultiFab& f, const Geometry& geom, int color,
352 const MultiFab* mask, const MultiFab* coef, const MultiFab* eps,
353 const MultiFab* kappa = nullptr, const MultiFab* eps_y = nullptr) {
354 const Real idx2 = Real(1) / (geom.dx() * geom.dx());
355 const Real idy2 = Real(1) / (geom.dy() * geom.dy());
356 const Real diag0 = 2 * idx2 + 2 * idy2;
357 for (int li = 0; li < phi.local_size(); ++li) {
358 Array4 p = phi.fab(li).array();
359 const ConstArray4 ff = f.fab(li).const_array();
360 const Box2D v = phi.box(li);
361 const bool hm = mask != nullptr;
362 const ConstArray4 mk = hm ? mask->fab(li).const_array() : ConstArray4{};
363 const bool hc = coef != nullptr;
364 const ConstArray4 cf = hc ? coef->fab(li).const_array() : ConstArray4{};
365 const bool he = eps != nullptr;
366 const ConstArray4 ep = he ? eps->fab(li).const_array() : ConstArray4{};
367 // eps_y==nullptr => isotropic: y faces read the same field as the x faces (eps_x).
368 const ConstArray4 ey = (he && eps_y) ? eps_y->fab(li).const_array() : ep;
369 const bool hk = kappa != nullptr; // reaction term -kappa phi (Helmholtz / screened)
370 const ConstArray4 ka = hk ? kappa->fab(li).const_array() : ConstArray4{};
372 v, GsColorKernel{p, ff, idx2, idy2, diag0, color, hm, mk, hc, cf, he, ep, ey, hk, ka});
373 }
374}
375} // namespace detail
376
377inline void gs_rb_sweep(MultiFab& phi, const MultiFab& f, const Geometry& geom, const BCRec& bc,
378 const MultiFab* mask = nullptr, const MultiFab* coef = nullptr,
379 const MultiFab* eps = nullptr, const MultiFab* kappa = nullptr,
380 const MultiFab* eps_y = nullptr) {
381 device_fence(); // wait for the previous kernel before the host read of the halos
382 fill_ghosts(phi, geom.domain, bc);
383 detail::gs_color(phi, f, geom, 0, mask, coef, eps, kappa, eps_y); // red (GPU kernel)
384 device_fence(); // the black sweep reads the red values via host fill_ghosts
385 fill_ghosts(phi, geom.domain, bc);
386 detail::gs_color(phi, f, geom, 1, mask, coef, eps, kappa, eps_y); // black
387}
388
389inline void gs_smooth(MultiFab& phi, const MultiFab& f, const Geometry& geom, const BCRec& bc,
390 int nsweeps, const MultiFab* mask = nullptr, const MultiFab* coef = nullptr,
391 const MultiFab* eps = nullptr, const MultiFab* kappa = nullptr,
392 const MultiFab* eps_y = nullptr) {
393 for (int s = 0; s < nsweeps; ++s)
394 gs_rb_sweep(phi, f, geom, bc, mask, coef, eps, kappa, eps_y);
395}
396
397namespace detail {
398// Pins phi=0 in the conductor cells (mask==0). Named functor (#93); body identical.
402 POPS_HD void operator()(int i, int j) const {
403 if (mk(i, j) == Real(0))
404 p(i, j) = 0;
405 }
406};
407} // namespace detail
408
409// Forces phi=0 in the conductor cells (mask==0).
410inline void zero_conductor(MultiFab& phi, const MultiFab& mask) {
411 for (int li = 0; li < phi.local_size(); ++li) {
412 Array4 p = phi.fab(li).array();
413 const ConstArray4 mk = mask.fab(li).const_array();
414 const Box2D v = phi.box(li);
416 }
417}
418
419} // namespace pops
ConstArray4 const_array() const
READ handle (POD device-copyable) over this Fab. Valid as long as the Fab lives.
Definition fab2d.hpp:96
Array4 array()
WRITE handle (POD device-copyable) over this Fab. Valid as long as the Fab lives.
Definition fab2d.hpp:91
Field distributed over a level: decomposition (BoxArray) + distribution (DistributionMapping) + ncomp...
Definition multifab.hpp:33
Fab2D & fab(int li)
Local fab at index li (0 <= li < local_size()), for writing.
Definition multifab.hpp:67
int ncomp() const
Number of components.
Definition multifab.hpp:60
const Box2D & box(int li) const
VALID box of local fab li.
Definition multifab.hpp:71
int local_size() const
Number of fabs OWNED by this rank (bound on local indices).
Definition multifab.hpp:65
Fab2D: single-grid data on a Box2D (in-house equivalent of AMReX's FArrayBox); Array4 / ConstArray4: ...
for_each_cell and reductions: the parallelism SEAM over the cells of a Box2D; sync_host / sync_device...
Geometry: index-space (Box2D) <-> Cartesian physical-space mapping; PolarGeometry: SIBLING for a glob...
MultiFab: a field DISTRIBUTED over a level (equivalent of AMReX's MultiFab).
void gs_color(MultiFab &phi, const MultiFab &f, const Geometry &geom, int color, const MultiFab *mask, const MultiFab *coef, const MultiFab *eps, const MultiFab *kappa=nullptr, const MultiFab *eps_y=nullptr)
Definition poisson_operator.hpp:351
POPS_HD void face_weights(const ConstArray4 &ep, const ConstArray4 &ey, int i, int j, Real idx2, Real idy2, bool hc, const ConstArray4 &cf, Real &wxm, Real &wxp, Real &wym, Real &wyp)
Definition poisson_operator.hpp:52
POPS_HD Real cross_div(const ConstArray4 &p, bool hxy, const ConstArray4 &axy, bool hyx, const ConstArray4 &ayx, int i, int j, Real idx, Real idy)
Definition poisson_operator.hpp:79
Definition amr_hierarchy.hpp:29
void for_each_cell(const Box2D &b, F f)
Applies f to EACH cell (i, j) of box b (bounds inclusive), via Kokkos::parallel_for (Serial / OpenMP ...
Definition for_each.hpp:138
double Real
Definition types.hpp:30
void zero_conductor(MultiFab &phi, const MultiFab &mask)
Definition poisson_operator.hpp:410
void apply_laplacian(const MultiFab &phi, const Geometry &geom, MultiFab &lap, const MultiFab *coef=nullptr, const MultiFab *eps=nullptr, const MultiFab *kappa=nullptr, const MultiFab *eps_y=nullptr, const MultiFab *a_xy=nullptr, const MultiFab *a_yx=nullptr)
Definition poisson_operator.hpp:191
void device_fence()
Device barrier: waits for in-flight kernels to finish before a HOST access to unified memory.
Definition kokkos_env.hpp:43
void gs_smooth(MultiFab &phi, const MultiFab &f, const Geometry &geom, const BCRec &bc, int nsweeps, const MultiFab *mask=nullptr, const MultiFab *coef=nullptr, const MultiFab *eps=nullptr, const MultiFab *kappa=nullptr, const MultiFab *eps_y=nullptr)
Definition poisson_operator.hpp:389
void gs_rb_sweep(MultiFab &phi, const MultiFab &f, const Geometry &geom, const BCRec &bc, const MultiFab *mask=nullptr, const MultiFab *coef=nullptr, const MultiFab *eps=nullptr, const MultiFab *kappa=nullptr, const MultiFab *eps_y=nullptr)
Definition poisson_operator.hpp:377
void poisson_residual(MultiFab &phi, const MultiFab &f, const Geometry &geom, const BCRec &bc, MultiFab &res, const MultiFab *mask=nullptr, const MultiFab *coef=nullptr, const MultiFab *eps=nullptr, const MultiFab *kappa=nullptr, const MultiFab *eps_y=nullptr, const MultiFab *a_xy=nullptr, const MultiFab *a_yx=nullptr)
Definition poisson_operator.hpp:271
POPS_HD Real eps_harmonic(Real ec, Real ev)
Definition poisson_operator.hpp:40
void apply_divergence(const MultiFab &fx, const MultiFab &fy, const Geometry &geom, MultiFab &div_out, int cx=0, int cy=0)
Definition poisson_operator.hpp:256
void fill_ghosts(MultiFab &mf, const Box2D &domain, const BCRec &bc)
COMPLETE ghost filling: fill_boundary (interior + periodic, periodicity deduced from bc) THEN fill_ph...
Definition physical_bc.hpp:227
PHYSICAL boundary conditions at the domain edge (BCType, BCRec, fill_physical_bc, fill_ghosts).
WRITE POD handle (raw pointer + strides) over a Fab2D buffer, indexed by (i, j, c) IN GLOBAL INDICES ...
Definition fab2d.hpp:29
Boundary conditions for the FOUR faces of the domain (type + associated Dirichlet value).
Definition physical_bc.hpp:29
2D integer index space, cell-centered.
Definition box2d.hpp:37
READ-only handle (const counterpart of Array4): same layout and same contract (POD device-copyable,...
Definition fab2d.hpp:44
Cartesian geometry of a level: index domain + physical bounds [xlo, xhi] x [ylo, yhi].
Definition geometry.hpp:20
POPS_HD Real dy() const
Grid spacing in y (= (yhi - ylo) / domain.ny()). POPS_HD.
Definition geometry.hpp:33
POPS_HD Real dx() const
Grid spacing in x (= (xhi - xlo) / domain.nx()). POPS_HD.
Definition geometry.hpp:31
Box2D domain
Definition geometry.hpp:21
Definition poisson_operator.hpp:113
ConstArray4 cf
Definition poisson_operator.hpp:118
ConstArray4 ep
Definition poisson_operator.hpp:120
ConstArray4 axy
Definition poisson_operator.hpp:124
bool he
Definition poisson_operator.hpp:119
bool hyx
Definition poisson_operator.hpp:123
Real idy2
Definition poisson_operator.hpp:116
bool hk
Definition poisson_operator.hpp:121
Real idx
Definition poisson_operator.hpp:116
Real idx2
Definition poisson_operator.hpp:116
Array4 L
Definition poisson_operator.hpp:115
Real idy
Definition poisson_operator.hpp:116
bool hc
Definition poisson_operator.hpp:117
ConstArray4 ayx
Definition poisson_operator.hpp:124
int c
Definition poisson_operator.hpp:125
ConstArray4 ey
Definition poisson_operator.hpp:120
ConstArray4 p
Definition poisson_operator.hpp:114
bool hxy
Definition poisson_operator.hpp:123
ConstArray4 ka
Definition poisson_operator.hpp:122
POPS_HD void operator()(int i, int j) const
Definition poisson_operator.hpp:126
Definition poisson_operator.hpp:234
int cx
Definition poisson_operator.hpp:238
ConstArray4 fy
Definition poisson_operator.hpp:235
ConstArray4 fx
Definition poisson_operator.hpp:235
POPS_HD void operator()(int i, int j) const
Definition poisson_operator.hpp:239
int cy
Definition poisson_operator.hpp:238
Array4 div
Definition poisson_operator.hpp:236
Real half_idy
Definition poisson_operator.hpp:237
Real half_idx
Definition poisson_operator.hpp:237
Definition poisson_operator.hpp:312
Array4 p
Definition poisson_operator.hpp:313
ConstArray4 cf
Definition poisson_operator.hpp:320
bool hm
Definition poisson_operator.hpp:317
Real idy2
Definition poisson_operator.hpp:315
ConstArray4 ey
Definition poisson_operator.hpp:322
Real idx2
Definition poisson_operator.hpp:315
ConstArray4 mk
Definition poisson_operator.hpp:318
bool hk
Definition poisson_operator.hpp:323
bool hc
Definition poisson_operator.hpp:319
ConstArray4 ep
Definition poisson_operator.hpp:322
POPS_HD void operator()(int i, int j) const
Definition poisson_operator.hpp:325
Real diag0
Definition poisson_operator.hpp:315
ConstArray4 ka
Definition poisson_operator.hpp:324
int color
Definition poisson_operator.hpp:316
bool he
Definition poisson_operator.hpp:321
ConstArray4 ff
Definition poisson_operator.hpp:314
Definition poisson_operator.hpp:149
Real idx2
Definition poisson_operator.hpp:152
Real idy2
Definition poisson_operator.hpp:152
ConstArray4 ep
Definition poisson_operator.hpp:158
Array4 r
Definition poisson_operator.hpp:151
ConstArray4 ka
Definition poisson_operator.hpp:160
POPS_HD void operator()(int i, int j) const
Definition poisson_operator.hpp:163
ConstArray4 ey
Definition poisson_operator.hpp:158
ConstArray4 cf
Definition poisson_operator.hpp:156
Real idx
Definition poisson_operator.hpp:152
ConstArray4 mk
Definition poisson_operator.hpp:154
ConstArray4 ff
Definition poisson_operator.hpp:150
ConstArray4 axy
Definition poisson_operator.hpp:162
Real idy
Definition poisson_operator.hpp:152
bool hk
Definition poisson_operator.hpp:159
ConstArray4 p
Definition poisson_operator.hpp:150
bool hc
Definition poisson_operator.hpp:155
bool hyx
Definition poisson_operator.hpp:161
ConstArray4 ayx
Definition poisson_operator.hpp:162
bool he
Definition poisson_operator.hpp:157
bool hxy
Definition poisson_operator.hpp:161
bool hm
Definition poisson_operator.hpp:153
Definition poisson_operator.hpp:399
POPS_HD void operator()(int i, int j) const
Definition poisson_operator.hpp:402
Array4 p
Definition poisson_operator.hpp:400
ConstArray4 mk
Definition poisson_operator.hpp:401
Base scalar types and the POPS_HD macro (host+device portability).
#define POPS_HD
Definition types.hpp:25