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

adc_cpp: include/pops/numerics/spatial/operators/masked_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
masked_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
23
24namespace pops {
25
26// ============================================================================
27// DOMAIN MASK (T2 effort, conservative, OPT-IN -- default path untouched)
28// ============================================================================
29// The mask makes the FV transport aware of an ACTIVE sub-domain (e.g. a bounded disk-shaped region).
30// Convention: mask(i, j) >= 0.5 -> ACTIVE cell, otherwise INACTIVE. A face is OPEN (normal flux
31// computed) if BOTH adjacent cells are active; it is CLOSED (normal flux set to ZERO) if at least
32// one is inactive. Zeroing the normal flux at active/inactive faces makes the step CONSERVATIVE
33// over the active sub-domain: no mass crosses the boundary, so the total mass over the active cells
34// is conserved to machine precision (telescoping internal fluxes, zero boundary fluxes). This is the
35// FV counterpart of the conducting wall (which only acts on the elliptic part).
36//
37// The residual is written ONLY on the active cells; an inactive cell keeps its residual at 0
38// (the caller does not advance it). This header does NOT wire this path into System::step: it
39// provides the mask-aware brick, exercised directly by the tests and, eventually, behind the
40// active-sub-domain opt-in.
41
42namespace detail {
44POPS_HD inline bool mask_active(const ConstArray4& mask, int i, int j) {
45 return mask(i, j, 0) >= Real(0.5);
46}
47
58template <class Limiter, class NumericalFlux, class Model>
60 Model model;
64 Limiter lim;
65 NumericalFlux nflux;
68 int pos_comp = 0;
69 POPS_HD void operator()(int i, int j) const {
70 if (!mask_active(mask, i,
71 j)) { // cell outside the active sub-domain: zero residual, not advanced
72 for (int c = 0; c < Model::n_vars; ++c)
73 r(i, j, c) = Real(0);
74 return;
75 }
76 const Aux Ac = load_aux<aux_comps<Model>()>(ax, i, j);
77 const Aux Axm = load_aux<aux_comps<Model>()>(ax, i - 1, j);
78 const Aux Axp = load_aux<aux_comps<Model>()>(ax, i + 1, j);
79 const Aux Aym = load_aux<aux_comps<Model>()>(ax, i, j - 1);
80 const Aux Ayp = load_aux<aux_comps<Model>()>(ax, i, j + 1);
81
82 // x faces: reconstruction on either side, numerical flux, THEN mask gate (closed face
83 // -> zero normal flux) -- an inactive neighbor cell closes the face between it and (i, j).
84 const auto Lxm =
85 reconstruct_pp<Model>(model, u, i - 1, j, 0, +1, lim, recon_prim, pos_floor, pos_comp);
86 const auto Rxm =
87 reconstruct_pp<Model>(model, u, i, j, 0, -1, lim, recon_prim, pos_floor, pos_comp);
88 const auto Lxp =
89 reconstruct_pp<Model>(model, u, i, j, 0, +1, lim, recon_prim, pos_floor, pos_comp);
90 const auto Rxp =
91 reconstruct_pp<Model>(model, u, i + 1, j, 0, -1, lim, recon_prim, pos_floor, pos_comp);
92 auto Fxm = nflux(model, Lxm, Axm, Rxm, Ac, 0);
93 auto Fxp = nflux(model, Lxp, Ac, Rxp, Axp, 0);
94 if (!mask_active(mask, i - 1, j))
95 Fxm = typename Model::State{};
96 if (!mask_active(mask, i + 1, j))
97 Fxp = typename Model::State{};
98
99 // y faces
100 const auto Lym =
101 reconstruct_pp<Model>(model, u, i, j - 1, 1, +1, lim, recon_prim, pos_floor, pos_comp);
102 const auto Rym =
103 reconstruct_pp<Model>(model, u, i, j, 1, -1, lim, recon_prim, pos_floor, pos_comp);
104 const auto Lyp =
105 reconstruct_pp<Model>(model, u, i, j, 1, +1, lim, recon_prim, pos_floor, pos_comp);
106 const auto Ryp =
107 reconstruct_pp<Model>(model, u, i, j + 1, 1, -1, lim, recon_prim, pos_floor, pos_comp);
108 auto Fym = nflux(model, Lym, Aym, Rym, Ac, 1);
109 auto Fyp = nflux(model, Lyp, Ac, Ryp, Ayp, 1);
110 if (!mask_active(mask, i, j - 1))
111 Fym = typename Model::State{};
112 if (!mask_active(mask, i, j + 1))
113 Fyp = typename Model::State{};
114
115 const auto S = model.source(load_state<Model>(u, i, j), Ac);
116 for (int c = 0; c < Model::n_vars; ++c)
117 r(i, j, c) = S[c] - (Fxp[c] - Fxm[c]) / dx - (Fyp[c] - Fym[c]) / dy;
118 }
119};
120} // namespace detail
121
132template <class Limiter = NoSlope, class NumericalFlux = RusanovFlux, class Model>
133void assemble_rhs_masked(const Model& model, const MultiFab& U, const MultiFab& aux,
134 const MultiFab& mask, const Geometry& geom, MultiFab& R,
135 bool recon_prim = false, Real pos_floor = Real(0)) {
136 detail::require_reconstruction_ghosts<Limiter>(U); // state ghosts >= stencil (otherwise OOB)
137 const Real dx = geom.dx(), dy = geom.dy();
138 const Limiter lim{};
139 const NumericalFlux nflux{};
140 const int pos_comp = detail::positivity_comp<Model>(pos_floor);
141 for (int li = 0; li < U.local_size(); ++li) {
142 const ConstArray4 u = U.fab(li).const_array();
143 const ConstArray4 ax = aux.fab(li).const_array();
144 const ConstArray4 mk = mask.fab(li).const_array();
145 Array4 r = R.fab(li).array();
146 const Box2D v = R.box(li);
148 model, u, ax, mk, r, dx, dy, lim, nflux, recon_prim, pos_floor, pos_comp});
149 }
150}
151
152} // 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
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).
POPS_HD bool mask_active(const ConstArray4 &mask, int i, int j)
Activity indicator of a cell from a 0/1 cell-centered mask (>= 0.5 -> active).
Definition masked_operator.hpp:44
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 assemble_rhs_masked(const Model &model, const MultiFab &U, const MultiFab &aux, const MultiFab &mask, const Geometry &geom, MultiFab &R, bool recon_prim=false, Real pos_floor=Real(0))
assemble_rhs_masked<Limiter,NumericalFlux>: residual R = -div Fhat + S RESTRICTED to a 0/1 cell-cente...
Definition masked_operator.hpp:133
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
AssembleRhsMaskedKernel: variant of AssembleRhsKernel AWARE of a domain mask.
Definition masked_operator.hpp:59
NumericalFlux nflux
Definition masked_operator.hpp:65
bool recon_prim
Definition masked_operator.hpp:66
POPS_HD void operator()(int i, int j) const
Definition masked_operator.hpp:69
ConstArray4 u
Definition masked_operator.hpp:61
Real pos_floor
Zhang-Shu positivity limiter (<= 0: inactive, bit-identical)
Definition masked_operator.hpp:67
Array4 r
Definition masked_operator.hpp:62
int pos_comp
component of the Density role (resolved by the host caller)
Definition masked_operator.hpp:68
ConstArray4 ax
Definition masked_operator.hpp:61
Model model
Definition masked_operator.hpp:60
Real dx
Definition masked_operator.hpp:63
ConstArray4 mask
Definition masked_operator.hpp:61
Limiter lim
Definition masked_operator.hpp:64
Real dy
Definition masked_operator.hpp:63
#define POPS_HD
Definition types.hpp:25