include/pops/numerics/spatial/operators/cartesian_operator.hpp Source FileΒΆ

adc_cpp: include/pops/numerics/spatial/operators/cartesian_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
cartesian_operator.hpp
Go to the documentation of this file.
1
12
13#pragma once
14
20#include <pops/numerics/spatial/primitives/face_flux.hpp> // reconstruct_pp, require_reconstruction_ghosts
21#include <pops/numerics/spatial/primitives/positivity.hpp> // detail::positivity_comp
22#include <pops/numerics/spatial/primitives/state_access.hpp> // load_state, load_aux, DiffusiveModel
23#include <pops/numerics/spatial/primitives/wave_speed.hpp> // fill_wave_speed_cache
24
25namespace pops {
26
27namespace detail {
34//
35// nvcc does not reliably emit the device kernel of a Model-template extended lambda first
36// instantiated from an EXTERNAL TU through the std::function / host-lambda nesting of block_builder:
37// the test passes on Serial and under compute-sanitizer but segfaults at runtime on Cuda (Heisenbug).
38// A device-callable class does not have these instantiation-context restrictions. Body IDENTICAL to
39// the former lambda -> residual BIT-IDENTICAL to add_block on CPU (and, targeted, on device).
40template <class Limiter, class NumericalFlux, class Model>
42 Model model;
46 Limiter lim;
47 NumericalFlux nflux;
50 int pos_comp = 0;
51 POPS_HD void operator()(int i, int j) const {
52 const Aux Ac = load_aux<aux_comps<Model>()>(ax, i, j);
53 const Aux Axm = load_aux<aux_comps<Model>()>(ax, i - 1, j);
54 const Aux Axp = load_aux<aux_comps<Model>()>(ax, i + 1, j);
55 const Aux Aym = load_aux<aux_comps<Model>()>(ax, i, j - 1);
56 const Aux Ayp = load_aux<aux_comps<Model>()>(ax, i, j + 1);
57
58 // x faces: reconstruction of the states on either side of each face
59 const auto Lxm =
60 reconstruct_pp<Model>(model, u, i - 1, j, 0, +1, lim, recon_prim, pos_floor, pos_comp);
61 const auto Rxm =
62 reconstruct_pp<Model>(model, u, i, j, 0, -1, lim, recon_prim, pos_floor, pos_comp);
63 const auto Lxp =
64 reconstruct_pp<Model>(model, u, i, j, 0, +1, lim, recon_prim, pos_floor, pos_comp);
65 const auto Rxp =
66 reconstruct_pp<Model>(model, u, i + 1, j, 0, -1, lim, recon_prim, pos_floor, pos_comp);
67 const auto Fxm = nflux(model, Lxm, Axm, Rxm, Ac, 0);
68 const auto Fxp = nflux(model, Lxp, Ac, Rxp, Axp, 0);
69
70 // y faces
71 const auto Lym =
72 reconstruct_pp<Model>(model, u, i, j - 1, 1, +1, lim, recon_prim, pos_floor, pos_comp);
73 const auto Rym =
74 reconstruct_pp<Model>(model, u, i, j, 1, -1, lim, recon_prim, pos_floor, pos_comp);
75 const auto Lyp =
76 reconstruct_pp<Model>(model, u, i, j, 1, +1, lim, recon_prim, pos_floor, pos_comp);
77 const auto Ryp =
78 reconstruct_pp<Model>(model, u, i, j + 1, 1, -1, lim, recon_prim, pos_floor, pos_comp);
79 const auto Fym = nflux(model, Lym, Aym, Rym, Ac, 1);
80 const auto Fyp = nflux(model, Lyp, Ac, Ryp, Ayp, 1);
81
82 const auto S = model.source(load_state<Model>(u, i, j), Ac);
83 for (int c = 0; c < Model::n_vars; ++c)
84 r(i, j, c) = S[c] - (Fxp[c] - Fxm[c]) / dx - (Fyp[c] - Fym[c]) / dy;
85
86 // Parabolic (Fickian) term: +nu Lap(U), 5-point centered differences.
87 // Guarded by DiffusiveModel: no effect (nor codegen) for a non-diffusive model.
88 if constexpr (DiffusiveModel<Model>) {
89 const Real nu = model.diffusivity();
90 const Real idx2 = Real(1) / (dx * dx), idy2 = Real(1) / (dy * dy);
91 for (int c = 0; c < Model::n_vars; ++c)
92 r(i, j, c) += nu * ((u(i + 1, j, c) - 2 * u(i, j, c) + u(i - 1, j, c)) * idx2 +
93 (u(i, j + 1, c) - 2 * u(i, j, c) + u(i, j - 1, c)) * idy2);
94 }
95 }
96};
97} // namespace detail
98
106template <class Limiter = NoSlope, class NumericalFlux = RusanovFlux, class Model>
107void assemble_rhs(const Model& model, const MultiFab& U, const MultiFab& aux, const Geometry& geom,
108 MultiFab& R, bool recon_prim = false, Real pos_floor = Real(0)) {
109 detail::require_reconstruction_ghosts<Limiter>(U); // state ghosts >= stencil (otherwise OOB)
110 const Real dx = geom.dx(), dy = geom.dy();
111 const Limiter lim{};
112 const NumericalFlux nflux{};
113 const int pos_comp = detail::positivity_comp<Model>(pos_floor);
114 for (int li = 0; li < U.local_size(); ++li) {
115 const ConstArray4 u = U.fab(li).const_array();
116 const ConstArray4 ax = aux.fab(li).const_array();
117 Array4 r = R.fab(li).array();
118 const Box2D v = R.box(li);
120 model, u, ax, r, dx, dy, lim, nflux, recon_prim, pos_floor, pos_comp});
121 }
122}
123
124namespace detail {
131template <class Limiter, class Model>
133 Model model;
137 Limiter lim;
140 int pos_comp = 0;
141 POPS_HD void operator()(int i, int j) const {
142 const Aux Ac = load_aux<aux_comps<Model>()>(ax, i, j);
143 const Aux Axm = load_aux<aux_comps<Model>()>(ax, i - 1, j);
144 const Aux Axp = load_aux<aux_comps<Model>()>(ax, i + 1, j);
145 const Aux Aym = load_aux<aux_comps<Model>()>(ax, i, j - 1);
146 const Aux Ayp = load_aux<aux_comps<Model>()>(ax, i, j + 1);
147
148 // x faces: reconstruction of the states on both sides of each face
149 const auto Lxm =
150 reconstruct_pp<Model>(model, u, i - 1, j, 0, +1, lim, recon_prim, pos_floor, pos_comp);
151 const auto Rxm =
152 reconstruct_pp<Model>(model, u, i, j, 0, -1, lim, recon_prim, pos_floor, pos_comp);
153 const auto Lxp =
154 reconstruct_pp<Model>(model, u, i, j, 0, +1, lim, recon_prim, pos_floor, pos_comp);
155 const auto Rxp =
156 reconstruct_pp<Model>(model, u, i + 1, j, 0, -1, lim, recon_prim, pos_floor, pos_comp);
157 // face signal speeds = union (min of the lo, max of the hi) of the two adjacent cells: the LEFT
158 // cell is always the lower-index neighbor (same operands/order as hll_speeds).
159 const Real sLxm = ws(i - 1, j, 0) < ws(i, j, 0) ? ws(i - 1, j, 0) : ws(i, j, 0);
160 const Real sRxm = ws(i - 1, j, 1) > ws(i, j, 1) ? ws(i - 1, j, 1) : ws(i, j, 1);
161 const Real sLxp = ws(i, j, 0) < ws(i + 1, j, 0) ? ws(i, j, 0) : ws(i + 1, j, 0);
162 const Real sRxp = ws(i, j, 1) > ws(i + 1, j, 1) ? ws(i, j, 1) : ws(i + 1, j, 1);
163 const auto Fxm = hll_flux_with_speeds(model, Lxm, Axm, Rxm, Ac, 0, sLxm, sRxm);
164 const auto Fxp = hll_flux_with_speeds(model, Lxp, Ac, Rxp, Axp, 0, sLxp, sRxp);
165
166 // y faces (components 2 = lo_y, 3 = hi_y of the scratch)
167 const auto Lym =
168 reconstruct_pp<Model>(model, u, i, j - 1, 1, +1, lim, recon_prim, pos_floor, pos_comp);
169 const auto Rym =
170 reconstruct_pp<Model>(model, u, i, j, 1, -1, lim, recon_prim, pos_floor, pos_comp);
171 const auto Lyp =
172 reconstruct_pp<Model>(model, u, i, j, 1, +1, lim, recon_prim, pos_floor, pos_comp);
173 const auto Ryp =
174 reconstruct_pp<Model>(model, u, i, j + 1, 1, -1, lim, recon_prim, pos_floor, pos_comp);
175 const Real sLym = ws(i, j - 1, 2) < ws(i, j, 2) ? ws(i, j - 1, 2) : ws(i, j, 2);
176 const Real sRym = ws(i, j - 1, 3) > ws(i, j, 3) ? ws(i, j - 1, 3) : ws(i, j, 3);
177 const Real sLyp = ws(i, j, 2) < ws(i, j + 1, 2) ? ws(i, j, 2) : ws(i, j + 1, 2);
178 const Real sRyp = ws(i, j, 3) > ws(i, j + 1, 3) ? ws(i, j, 3) : ws(i, j + 1, 3);
179 const auto Fym = hll_flux_with_speeds(model, Lym, Aym, Rym, Ac, 1, sLym, sRym);
180 const auto Fyp = hll_flux_with_speeds(model, Lyp, Ac, Ryp, Ayp, 1, sLyp, sRyp);
181
182 const auto S = model.source(load_state<Model>(u, i, j), Ac);
183 for (int c = 0; c < Model::n_vars; ++c)
184 r(i, j, c) = S[c] - (Fxp[c] - Fxm[c]) / dx - (Fyp[c] - Fym[c]) / dy;
185
186 // Parabolic (Fickian) term: identical to AssembleRhsKernel, guarded by DiffusiveModel.
187 if constexpr (DiffusiveModel<Model>) {
188 const Real nu = model.diffusivity();
189 const Real idx2 = Real(1) / (dx * dx), idy2 = Real(1) / (dy * dy);
190 for (int c = 0; c < Model::n_vars; ++c)
191 r(i, j, c) += nu * ((u(i + 1, j, c) - 2 * u(i, j, c) + u(i - 1, j, c)) * idx2 +
192 (u(i, j + 1, c) - 2 * u(i, j, c) + u(i, j - 1, c)) * idy2);
193 }
194 }
195};
196} // namespace detail
197
204template <class Limiter = NoSlope, class Model>
205void assemble_rhs_hll_cached(const Model& model, const MultiFab& U, const MultiFab& aux,
206 const Geometry& geom, MultiFab& R, MultiFab& cache,
207 bool recon_prim = false, Real pos_floor = Real(0)) {
208 const Real dx = geom.dx(), dy = geom.dy();
209 const Limiter lim{};
210 const int pos_comp = detail::positivity_comp<Model>(pos_floor);
211 fill_wave_speed_cache(model, U, aux, cache);
212 for (int li = 0; li < U.local_size(); ++li) {
213 const ConstArray4 u = U.fab(li).const_array();
214 const ConstArray4 ax = aux.fab(li).const_array();
215 const ConstArray4 ws = cache.fab(li).const_array();
216 Array4 r = R.fab(li).array();
217 const Box2D v = R.box(li);
219 model, u, ax, ws, r, dx, dy, lim, recon_prim, pos_floor, pos_comp});
220 }
221}
222
223} // 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
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
DiffusiveModel: optional concept for models with isotropic scalar diffusion.
Definition state_access.hpp:38
Fab2D: single-grid data on a Box2D (in-house equivalent of AMReX's FArrayBox); Array4 / ConstArray4: ...
Face-state reconstruction and face fluxes of the Cartesian spatial operator.
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).
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
void assemble_rhs(const Model &model, const MultiFab &U, const MultiFab &aux, const Geometry &geom, MultiFab &R, bool recon_prim=false, Real pos_floor=Real(0))
assemble_rhs<Limiter,NumericalFlux>: residual R = -div Fhat + S over all boxes.
Definition cartesian_operator.hpp:107
double Real
Definition types.hpp:30
void assemble_rhs_hll_cached(const Model &model, const MultiFab &U, const MultiFab &aux, const Geometry &geom, MultiFab &R, MultiFab &cache, bool recon_prim=false, Real pos_floor=Real(0))
assemble_rhs_hll_cached<Limiter>: residual R = -div Fhat + S at the HLL flux, wave speeds PRE-COMPUTE...
Definition cartesian_operator.hpp:205
void fill_wave_speed_cache(const Model &model, const MultiFab &U, const MultiFab &aux, MultiFab &cache)
fill_wave_speed_cache: fills the per-cell wave speed scratch (lo_x, hi_x, lo_y, hi_y).
Definition wave_speed.hpp:277
POPS_HD Model::State hll_flux_with_speeds(const Model &m, const typename Model::State &UL, const Aux &AL, const typename Model::State &UR, const Aux &AR, int dir, Real sL, Real sR)
hll_flux_with_speeds: HLL flux from ALREADY estimated signal speeds (sL, sR).
Definition numerical_flux.hpp:96
Single-interface numerical flux policies: Rusanov, HLL, HLLC, Roe.
Zhang-Shu positivity limiter and Density-role resolution.
Model/state/aux access layer of the Cartesian spatial operator.
WRITE POD handle (raw pointer + strides) over a Fab2D buffer, indexed by (i, j, c) IN GLOBAL INDICES ...
Definition fab2d.hpp:29
POINTWISE auxiliary fields shared with the physics: single coupling channel.
Definition state.hpp:123
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
AssembleRhsHllCachedKernel: kernel of the residual R = -div Fhat + S for the HLL flux with wave speed...
Definition cartesian_operator.hpp:132
ConstArray4 ax
Definition cartesian_operator.hpp:134
Limiter lim
Definition cartesian_operator.hpp:137
bool recon_prim
Definition cartesian_operator.hpp:138
ConstArray4 u
Definition cartesian_operator.hpp:134
POPS_HD void operator()(int i, int j) const
Definition cartesian_operator.hpp:141
ConstArray4 ws
Definition cartesian_operator.hpp:134
Model model
Definition cartesian_operator.hpp:133
Real dx
Definition cartesian_operator.hpp:136
Real dy
Definition cartesian_operator.hpp:136
Real pos_floor
Zhang-Shu positivity limiter (<= 0: inactive, bit-identical)
Definition cartesian_operator.hpp:139
Array4 r
Definition cartesian_operator.hpp:135
int pos_comp
Density role component (resolved by the host caller)
Definition cartesian_operator.hpp:140
AssembleRhsKernel<Limiter,NumericalFlux,Model>: device kernel of the central residual of assemble_rhs...
Definition cartesian_operator.hpp:41
Real pos_floor
Zhang-Shu positivity limiter (<= 0: inactive, bit-identical)
Definition cartesian_operator.hpp:49
Real dx
Definition cartesian_operator.hpp:45
ConstArray4 ax
Definition cartesian_operator.hpp:43
NumericalFlux nflux
Definition cartesian_operator.hpp:47
POPS_HD void operator()(int i, int j) const
Definition cartesian_operator.hpp:51
Model model
Definition cartesian_operator.hpp:42
bool recon_prim
Definition cartesian_operator.hpp:48
int pos_comp
component of the Density role (resolved by the host caller)
Definition cartesian_operator.hpp:50
ConstArray4 u
Definition cartesian_operator.hpp:43
Array4 r
Definition cartesian_operator.hpp:44
Limiter lim
Definition cartesian_operator.hpp:46
Real dy
Definition cartesian_operator.hpp:45
#define POPS_HD
Definition types.hpp:25
Global wave-speed / step-bound reductions and the HLL wave-speed cache.