include/pops/runtime/builders/compiled/amr_dsl_block.hpp Source File

adc_cpp: include/pops/runtime/builders/compiled/amr_dsl_block.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
amr_dsl_block.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <pops/coupling/schur/amr/amr_condensed_schur_source_stepper.hpp> // GLOBAL condensed source stage (amr-schur)
4#include <pops/coupling/amr/amr_coupler_mp.hpp> // AmrCouplerMP, AmrLevelMP
8#include <pops/mesh/execution/for_each.hpp> // device_fence
11#include <pops/mesh/layout/refinement.hpp> // coarsen_index
14#include <pops/numerics/spatial_operator.hpp> // SourceFreeModel (explicit IMEX half-step, transport only)
15#include <pops/numerics/time/integrators/implicit_stepper.hpp> // backward_euler_source + ImplicitMask (stiff IMEX source)
16#include <pops/parallel/comm.hpp> // n_ranks
17#include <pops/runtime/amr/amr_runtime.hpp> // AmrRuntimeBlock (type-erased multi-block registry)
19#include <pops/runtime/builders/block/block_builder.hpp> // detail::make_poisson_rhs (rhs += elliptic_rhs(U))
20#include <pops/runtime/config/dispatch_tags.hpp> // UNIQUE tag registry (validate_limiter/riemann)
21
22#include <algorithm> // std::find, std::sort (resolving the partial IMEX mask of a compiled block)
23#include <functional>
24#include <memory>
25#include <stdexcept>
26#include <string>
27#include <utility>
28#include <vector>
29
46
47namespace pops {
48
51template <class L, class F>
52struct AmrDiscLF {
53 using Limiter = L;
54 using NumericalFlux = F;
55};
56
57namespace detail {
58
59// Projection ponctuelle post-pas appliquee PAR NIVEAU (ADC-177) : miroir de PointwiseProject
60// (block_builder.hpp) mais sur la pile de niveaux AMR ; aux = lev.aux (cable par AmrRuntime).
61// Defini en tete du namespace : utilise par build_amr_compiled (mono-bloc) ET build_amr_block
62// (multi-bloc natif), tous deux situes plus bas (la recherche qualifiee detail:: exige la
63// declaration AVANT le point d'usage). No-op (else) si le modele ne declare pas m.project.
64template <class Model>
65void apply_pointwise_project_amr(const Model& m, std::vector<AmrLevelMP>& levels) {
66 if constexpr (HasPointwiseProjection<Model>) {
67 for (auto& lev : levels) {
68 MultiFab& U = lev.U;
69 const MultiFab& a = *lev.aux;
70 for (int li = 0; li < U.local_size(); ++li)
71 for_each_cell(U.box(li),
73 a.fab(li).const_array()});
74 }
75 } else {
76 (void)m;
77 (void)levels;
78 }
79}
80
84inline void amr_write_coarse_bz(MultiFab& bz, const std::vector<double>& field, int n) {
85 if (static_cast<int>(field.size()) != n * n)
86 throw std::runtime_error(
87 "AMR amr-schur: B_z field of size != n*n (call set_magnetic_field before the first step)");
89 for (int li = 0; li < bz.local_size(); ++li) {
90 Array4 b = bz.fab(li).array();
91 const Box2D v = bz.box(li);
92 for (int j = v.lo[1]; j <= v.hi[1]; ++j)
93 for (int i = v.lo[0]; i <= v.hi[0]; ++i)
94 b(i, j, 0) = field[static_cast<std::size_t>(j) * n + i];
95 }
96}
97
103template <class Coupler>
105 MultiFab& phi_coarse, double theta, double dt) {
106 device_fence();
107 for (int li = 0; li < phi_coarse.local_size(); ++li)
108 for_each_cell(phi_coarse.box(li),
109 CopyComp0Kernel{phi_coarse.fab(li).array(), cpl.aux0().fab(li).const_array()});
110 schur.step(cpl.levels(), phi_coarse, bz_coarse, /*c_bz=*/0, static_cast<Real>(theta),
111 static_cast<Real>(dt));
112}
113
119template <class Model, class Limiter, class Flux>
120AmrCompiledHooks build_amr_compiled(const Model& model, const AmrBuildParams& bp) {
122 const int nc = Model::n_vars;
123 const Geometry g{Box2D::from_extents(bp.n, bp.n), 0.0, bp.L, 0.0, bp.L};
124 const double dxc = bp.L / bp.n, dxf = dxc / 2;
125 // Level 0 (coarse): layout decided by the ownership policy (replicated mono-box by default,
126 // distributed multi-box if bp.distribute_coarse). When replicated, dmap = my_rank() everywhere (the box
127 // lives on each rank; a round-robin would place it on rank 0 only -> out-of-bounds fab elsewhere,
128 // segfault under np>1). The fine seed (allocated below ONLY when refinement is configured) starts on the
129 // SAME dmap as the coarse; the initial regrid REBUILDS it then REDISTRIBUTES round-robin
130 // (DistributionMapping(nfine, n_ranks())) -> multi-GPU distribution of the fine patches. When distributed,
131 // the coarse is distributed TOO (AMR strong-scaling).
132 const auto [bac, dm] = coupler_make_coarse_layout(bp.n, bp.distribute_coarse, bp.coarse_max_grid);
133 const int ng = Limiter::n_ghost; // limiter stencil (1 NoSlope, 2 MUSCL): scheme parity
134 MultiFab Uc(bac, dm, nc, ng);
135 Uc.set_val(Real(0));
136 std::vector<AmrLevelMP> levels;
137 levels.push_back({std::move(Uc), nullptr, dxc, dxc});
138 // Level 1 (central seed fine patch, reshaped by the regrid): allocated ONLY on the explicit/imex path
139 // AND when refinement is actually configured (set_refinement was called -> refine_threshold below its
140 // 1e30 "no refinement" sentinel). Two reasons to gate it:
141 // - amr-schur (Step 2/3) runs MONO-LEVEL: the condensed source stage does not yet carry the multi-level
142 // case (cf. AmrCondensedSchurSourceStepper, guard on the number of fine patches), so a seed would trip
143 // that guard at the first step. Multi-level amr-schur (fine reconstruction + cascade + composite
144 // Schur/Poisson) is Step 4.
145 // - NO refinement (ADC-324): with the 1e30 sentinel the build-time regrid below (cpl->regrid(crit)) tags
146 // nothing and amr_regrid_finest is a deliberate no-op on zero tags, so the seed would NEVER be reshaped
147 // or removed -- it would persist as a SINGLE un-chopped fine box on the coarse dmap (box 0 -> rank 0),
148 // dead weight that starves MPI strong-scaling (rank 0 carries its coarse boxes PLUS the whole fine
149 // patch). Gating on refine_threshold keeps the no-refinement hierarchy MONO-LEVEL (n_patches()==0, like
150 // the amr-schur path), so the coarse distributes cleanly. When refinement IS configured the seed is
151 // allocated and the first build regrid chops + distributes it round-robin exactly as before (UNCHANGED).
152 if (!bp.schur && bp.refine_threshold < 1e30) {
153 const int I0 = bp.n / 4, I1 = 3 * bp.n / 4 - 1, J0 = bp.n / 4, J1 = 3 * bp.n / 4 - 1;
154 Box2D fb{{2 * I0, 2 * J0}, {2 * I1 + 1, 2 * J1 + 1}};
155 BoxArray baf(std::vector<Box2D>{fb});
156 MultiFab Uf(baf, dm, nc, ng);
157 Uf.set_val(Real(0));
158 levels.push_back({std::move(Uf), nullptr, dxf, dxf});
159 }
160
161 auto cpl = std::make_shared<Coupler>(model, g, bac, bp.poisson_bc, std::move(levels), bp.wall,
163 // Coarse seed: COMPLETE conservative state (preferred, set_conservative_state) otherwise density
164 // only (historical). coupler_inject_coarse_to_fine_mb prolongs ALL components (loop k<nc), so the
165 // momentum of the seed propagates freely to the fine levels -- no change of prolongation.
166 // has_state==false -> bit-identical density path (NO-DEFAULT-CHANGE).
167 if (bp.has_state)
168 coupler_write_coarse_state(cpl->coarse(), bp.state, bp.n, nc);
169 else if (bp.has_density)
170 coupler_write_coarse(cpl->coarse(), bp.density, bp.n, nc, bp.gamma);
171 auto& Lv = cpl->levels();
172 for (std::size_t k = 1; k < Lv.size(); ++k)
173 coupler_inject_coarse_to_fine_mb(cpl->coarse(), Lv[k].U, !bp.distribute_coarse);
174
175 const double thr = bp.refine_threshold;
176 auto crit = [thr](const ConstArray4& a, int i, int j) { return a(i, j, 0) > thr; };
177 if (cpl->levels().size() > 1)
178 cpl->regrid(crit); // no regrid on a mono-level hierarchy (amr-schur)
179 // model-NAMED aux (ADC-291): seed the static named fields onto the coupler's shared aux BEFORE the
180 // first update/step (like density/B_z seeding). The coupler re-applies them in compute_aux each
181 // update, so they persist across regrid and reach every level via the aux injection. Empty -> no-op.
182 for (const auto& kv : bp.named_aux)
183 cpl->set_named_aux(kv.first, std::vector<Real>(kv.second.begin(), kv.second.end()));
184 // ADC-369: per-field aux halo policies (compute_aux applies them after the shared fill).
185 for (const auto& kv : bp.named_aux_bc)
186 cpl->set_named_aux_bc(kv.first, kv.second);
187 cpl->update();
188
190 h.coupler_holder = cpl; // lifetime: the closures capture cpl (shared_ptr)
191 const int sub = bp.substeps;
192 const bool rprim = bp.recon_prim;
193 const bool imex = bp.imex; // implicit stiff source (backward_euler) rather than forward Euler
194 const int regrid_every = bp.regrid_every;
195 // NEWTON OPTIONS of the mono-block IMEX source (wave 3): threaded to cpl->step -> advance_amr ->
196 // backward_euler_source. DEFAULT {} (newton_options not set) = historical constants (2 iters) ->
197 // bit-identical path (2a). Captured BY VALUE (POD) in the h.step closure.
198 const NewtonOptions nopts = bp.newton_options;
199 // TIME METHOD mono-block: integer of the flat ABI (bp.time_method) -> AmrTimeMethod, threaded to
200 // cpl->step -> advance_amr. 0 (default / older .so loader) = historical kEuler, bit-identical.
201 const AmrTimeMethod tmethod =
203 // Zhang-Shu positivity floor (ADC-259): threaded to cpl->step / advance_transport -> advance_amr ->
204 // compute_face_fluxes + C/F ghost clamp. bp.pos_floor == 0 (default / older flat-ABI .so loader that
205 // never sets this append-only field) -> inactive, bit-identical historical path.
206 const Real pf = static_cast<Real>(bp.pos_floor);
207 auto step_state = std::make_shared<int>(0); // step counter shared by the closure
208 if (bp.schur) {
209 // amr-schur PATH: GLOBAL condensed source stage (electrostatic/Lorentz) instead of the LOCAL
210 // explicit/imex source. The stage is built on the COARSE grid by COMPOSING the uniform stage #126
211 // (Density/MomentumX/MomentumY roles of the Model -> clear error HERE if missing). Coarse B_z required
212 // (set_magnetic_field). The model must be SOURCE-FREE (NoSource source brick): advance_transport
213 // then runs NO source (the source is the condensed stage alone), mirror of the uniform path where the
214 // block is added with its transport only (time.hyperbolic) + the separate condensed source stage.
215 //
216 // WARNING: OPTION A = INTERMEDIATE. The condensed stage solves the elliptic on the COARSE grid (like the
217 // AMR Poisson compute_aux/solve_fields), then grad phi is injected (piecewise constant) to the fines: the
218 // fine patches refine the TRANSPORT but NOT the elliptic coupling. For a FAITHFUL paper/AMR reproduction
219 // a multi-level COMPOSITE Schur/Poisson will be needed (condensed elliptic solved at the patch
220 // resolution, composite MG crossing the levels) -- infrastructure absent today (GeometricMG
221 // coarsens ONE grid, != AMR hierarchy). This is the fidelity lock, to do AFTER the mono-level parity.
222 // RESOLUTION of the field descriptors (wave 3 audit, parity with System::set_source_stage):
223 // "" = canonical role (historical, bit-identical); otherwise stable ROLE name then block VARIABLE name.
224 // Failure = explicit error at build (never a silent ignore).
225 const VariableSet schur_vs = Model::conservative_vars();
226 auto resolve_schur = [&schur_vs](const std::string& spec, VariableRole canonical,
227 const char* label) -> int {
228 if (spec.empty()) {
229 const int idx = schur_vs.index_of(canonical);
230 if (idx < 0)
231 throw std::runtime_error(
232 std::string("AmrSystem::set_source_stage: the block does not expose "
233 "the role ") +
234 label + " (declare the roles, or pass an explicit descriptor)");
235 return idx;
236 }
237 const VariableRole r = role_from_name(spec);
238 if (r != VariableRole::Custom) {
239 const int idx = schur_vs.index_of(r);
240 if (idx < 0)
241 throw std::runtime_error("AmrSystem::set_source_stage: role '" + spec + "' missing (" +
242 label + ")");
243 return idx;
244 }
245 for (std::size_t i = 0; i < schur_vs.names.size(); ++i)
246 if (schur_vs.names[i] == spec)
247 return static_cast<int>(i);
248 throw std::runtime_error("AmrSystem::set_source_stage: '" + spec +
249 "' is neither a stable role nor a block variable (" + label + ")");
250 };
251 const int sc_rho = resolve_schur(bp.schur_density, VariableRole::Density, "Density");
252 const int sc_mx = resolve_schur(bp.schur_momentum_x, VariableRole::MomentumX, "MomentumX");
253 const int sc_my = resolve_schur(bp.schur_momentum_y, VariableRole::MomentumY, "MomentumY");
254 const int sc_E = (bp.schur_energy == "none")
255 ? -1
256 : (bp.schur_energy.empty()
258 : resolve_schur(bp.schur_energy, VariableRole::Energy, "Energy"));
259 auto schur = std::make_shared<AmrCondensedSchurSourceStepper>(
260 schur_vs, sc_rho, sc_mx, sc_my, sc_E, g, bac, bp.poisson_bc,
261 static_cast<Real>(bp.schur_alpha));
262 if (bp.schur_krylov_tol > 0.0 || bp.schur_krylov_max_iters > 0)
263 schur->set_krylov(
264 bp.schur_krylov_tol > 0.0 ? static_cast<Real>(bp.schur_krylov_tol) : Real(1e-10),
266 auto bz_coarse = std::make_shared<MultiFab>(bac, dm, 1, 1);
267 amr_write_coarse_bz(*bz_coarse, bp.bz_field, bp.n);
268 auto phi_coarse = std::make_shared<MultiFab>(bac, dm, 1, 1);
269 phi_coarse->set_val(Real(0));
270 const double theta = bp.schur_theta;
271 const bool strang = bp.schur_strang;
272 h.step = [cpl, crit, sub, rprim, regrid_every, step_state, schur, bz_coarse, phi_coarse, theta,
273 strang, model, pf](double dt) {
274 // amr-schur Step 2/3: MONO-LEVEL hierarchy (the condensed stage does not carry the multi-level case).
275 // So we do NOT regrid (a regrid would create a fine patch -> multi-level guard of the stage). The
276 // amr-schur regrid will come with the composite Schur/Poisson (Step 4). cf. levels().size() > 1.
277 if (regrid_every > 0 && *step_state > 0 && *step_state % regrid_every == 0 &&
278 cpl->levels().size() > 1)
279 cpl->regrid(crit);
280 const double h2 = dt / sub;
281 for (int s = 0; s < sub; ++s) {
282 if (strang) {
283 // STRANG (2nd order): H(dt/2); S(dt); H(dt/2), with update() (= sync_down + coarse Poisson
284 // + grad inject, the AMR counterpart of solve_fields) RE-SOLVED BEFORE each stage that
285 // consumes phi -- exactly SystemStepper::step_strang (3 solves: head, pre-source, post-source).
286 cpl->update();
287 cpl->template advance_transport<AmrDiscLF<Limiter, Flux>>(Real(0.5) * h2, rprim, pf);
288 cpl->update();
289 amr_schur_source(*cpl, *schur, *bz_coarse, *phi_coarse, theta, h2);
290 cpl->update();
291 cpl->template advance_transport<AmrDiscLF<Limiter, Flux>>(Real(0.5) * h2, rprim, pf);
292 } else {
293 // LIE (Godunov, 1st order): H(dt); S(dt). A single update() at the head (the source stage reads
294 // the head phi), mirror of SystemStepper::step Lie (a single solve_fields, transport, source).
295 cpl->update();
296 cpl->template advance_transport<AmrDiscLF<Limiter, Flux>>(h2, rprim, pf);
297 amr_schur_source(*cpl, *schur, *bz_coarse, *phi_coarse, theta, h2);
298 }
299 }
300 // PROJECTION PONCTUELLE post-pas (ADC-177) PAR NIVEAU, APRES transport + source condensee de
301 // tous les substeps. No-op si le modele ne declare pas m.project (HasPointwiseProjection false).
302 detail::apply_pointwise_project_amr(model, cpl->levels());
303 ++*step_state;
304 };
305 } else {
306 h.step = [cpl, crit, sub, rprim, imex, regrid_every, step_state, nopts, tmethod, model,
307 pf](double dt) {
308 if (regrid_every > 0 && *step_state > 0 && *step_state % regrid_every == 0)
309 cpl->regrid(crit);
310 const double h2 = dt / sub;
311 // NEWTON OPTIONS threaded to the coupler (mono-block): nopts={} by default => iters=2 historical,
312 // bit-identical; non-default nopts (set_density + pops.IMEX(newton_*)) drives the local Newton.
313 // tmethod (kEuler default) selects SSPRK3 if requested (time='ssprk3'); kEuler bit-identical.
314 for (int s = 0; s < sub; ++s)
315 cpl->template step<AmrDiscLF<Limiter, Flux>>(h2, rprim, imex, nopts, tmethod, pf);
316 // PROJECTION PONCTUELLE post-pas (ADC-177) PAR NIVEAU, APRES transport + source de tous les
317 // substeps. No-op si le modele ne declare pas m.project (HasPointwiseProjection false).
318 detail::apply_pointwise_project_amr(model, cpl->levels());
319 ++*step_state;
320 };
321 }
322 // RESTORATION of the CADENCE PHASE (IO v1, parity with System::set_clock): AmrSystem::set_clock sets
323 // the macro-step counter of the mono-block (the regrid cadence reads *step_state) on restart. Shares the
324 // SAME step_state as the step closure above -> the regrid phase resumes exactly. Without the call,
325 // *step_state stays at 0 (default, bit-identical).
326 h.set_macro_step = [step_state](int s) { *step_state = s; };
327 // CFL SPEED: lambda* (HasStabilitySpeed trait) if declared, otherwise max_wave_speed of the coupler
328 // (historical fallback, bit-identical) -- SAME policy as System/make_max_speed, evaluated on the
329 // COARSE grid (the AMR mono-block CFL lives at the coarse step).
330 if constexpr (HasStabilitySpeed<Model>) {
331 h.max_speed = [cpl, model] {
332 return static_cast<double>(max_stability_speed_mf(model, cpl->coarse(), cpl->aux0()));
333 };
334 } else {
335 h.max_speed = [cpl] { return static_cast<double>(cpl->max_wave_speed()); };
336 }
337 // OPTIONAL STEP BOUNDS (AMR mono-block StabilityPolicy): same reductions as System,
338 // hooks left EMPTY without the trait (AmrSystem::step_cfl then keeps the historical formula).
339 if constexpr (HasSourceFrequency<Model>) {
340 h.source_frequency = [cpl, model] {
341 return static_cast<double>(max_source_frequency_mf(model, cpl->coarse(), cpl->aux0()));
342 };
343 }
344 if constexpr (HasStabilityDt<Model>) {
345 h.stability_dt = [cpl, model] {
346 return static_cast<double>(min_stability_dt_mf(model, cpl->coarse(), cpl->aux0()));
347 };
348 }
349 h.mass = [cpl] { return static_cast<double>(cpl->mass()); };
350 h.n_patches = [cpl] {
351 auto& L = cpl->levels();
352 return L.size() >= 2 ? static_cast<int>(L[1].U.box_array().size()) : 0;
353 };
354 // Index-space signatures of the fine patches (mono-block counterpart of AmrRuntime::patch_boxes).
355 // Captures the SAME cpl as the other hooks (no new lifetime concern), reads the already materialized
356 // BoxArray -> query between steps, zero cost on the hot path (h.step untouched).
357 h.patch_boxes = [cpl] {
358 auto& L = cpl->levels();
359 std::vector<pops::PatchBox> out;
360 for (std::size_t k = 1; k < L.size(); ++k) {
361 const auto& bxs = L[k].U.box_array().boxes();
362 for (const pops::Box2D& b : bxs)
363 out.push_back(pops::PatchBox{static_cast<int>(k), b.lo[0], b.lo[1], b.hi[0], b.hi[1]});
364 }
365 return out;
366 };
367 // Coarse-level (base) box counts (ADC-319, MPI ownership diagnostic): per-rank OWNED fabs of level 0
368 // (local_size()) and the GLOBAL base box count (box_array().size()). Same cpl capture as the other
369 // hooks (no new lifetime concern); a query between steps, zero cost on the hot path. distribute_coarse
370 // -> local < total per rank (distributed coarse transport); replicated/single-box -> local == total.
371 h.coarse_local_boxes = [cpl] { return cpl->coarse().local_size(); };
372 h.coarse_total_boxes = [cpl] { return cpl->coarse().box_array().size(); };
373 // AMR CHECKPOINT / RESTART single-rank (ADC-65): COMPLETE conservative state per level + phi
374 // (warm-start) + imposing the saved fine hierarchy. Capture the SAME cpl (shared_ptr) as the
375 // other hooks (no new lifetime concern). Single-rank: the coupler accessors loop over local_size()
376 // (no gather) -- the facade rejects np>1 / multi-block upstream. These hooks are QUERIES/SETTERS
377 // between steps: zero cost on the hot path (h.step untouched).
378 h.n_levels = [cpl] { return cpl->nlev(); };
379 h.n_vars = [] { return Model::n_vars; };
380 h.level_state = [cpl](int k) { return cpl->level_state(k); };
381 h.set_level_state = [cpl](int k, const std::vector<double>& s) { cpl->set_level_state(k, s); };
382 h.level_potential = [cpl](int k) { return cpl->level_potential(k); };
383 h.set_level_potential = [cpl](int k, const std::vector<double>& p) {
384 cpl->set_level_potential(k, p);
385 };
386 // GLOBAL (np>1 gather) counterparts (ADC-509): the facade routes to these under MPI np>1 so a
387 // bit-identical checkpoint gathers the distributed per-level fabs onto rank 0 (COLLECTIVE, all ranks
388 // call). Mono-rank they return the same array as the non-global hooks above (reduce = identity).
389 h.level_state_global = [cpl](int k) { return cpl->level_state_global(k); };
390 h.level_potential_global = [cpl](int k) { return cpl->level_potential_global(k); };
391 h.set_hierarchy = [cpl](const std::vector<pops::PatchBox>& boxes) {
392 // Mono-block: all patches live at level 1 -> we filter level == 1 and convert to Box2D
393 // (INCLUSIVE corners, fine-level index space), then impose this BoxArray on the coupler.
394 std::vector<pops::Box2D> fb;
395 for (const pops::PatchBox& b : boxes)
396 if (b.level == 1)
397 fb.push_back(pops::Box2D{{b.ilo, b.jlo}, {b.ihi, b.jhi}});
398 cpl->set_hierarchy(fb);
399 };
400 const int nn = bp.n;
401 const bool repl = !bp.distribute_coarse;
402 h.density = [cpl, nn, repl] { return coupler_read_coarse(cpl->coarse(), nn, repl); };
403 // Coarse phi: we refresh (update() = sync_down + compute_aux, hence coarse Poisson solve)
404 // then read aux0 component 0. Counterpart of System::potential() which calls ensure_elliptic: the
405 // value is current even if no step has run yet. update() is already called at each step,
406 // so the overhead exists only on a call outside the loop (diagnostic).
407 h.potential = [cpl, nn, repl] {
408 cpl->update();
409 return coupler_read_coarse_phi(cpl->aux0(), nn, repl);
410 };
411 return h;
412}
413
421 Geometry geom; // geometry of the coarse level (Poisson)
422 BoxArray ba_coarse; // BoxArray of the coarse grid
423 DistributionMapping dm_coarse; // DistributionMapping of the coarse grid
424 std::vector<BoxArray> ba; // [level] shared BoxArray (coarse + fines)
425 std::vector<DistributionMapping> dm; // [level] shared DistributionMapping
426 std::vector<Real> dx, dy; // [level] mesh spacing
427 bool replicated_coarse = true; // ownership of level 0
428 BCRec poisson_bc; // BC of the coarse Poisson
429 std::function<bool(Real, Real)> wall; // conducting-wall predicate (empty = none)
430 int n = 128; // coarse cells per direction
431 Periodicity base_per{true, true}; // periodicity of the base domain
432
433 int nlev() const { return static_cast<int>(ba.size()); }
434};
435
442 S.geom = Geometry{Box2D::from_extents(bp.n, bp.n), 0.0, bp.L, 0.0, bp.L};
443 S.n = bp.n;
445 S.poisson_bc = bp.poisson_bc;
446 S.wall = bp.wall;
447 const double dxc = bp.L / bp.n, dxf = dxc / 2;
448 const auto [bac, dmc] =
449 detail::coupler_make_coarse_layout(bp.n, bp.distribute_coarse, bp.coarse_max_grid);
450 S.ba_coarse = bac;
451 S.dm_coarse = dmc;
452 // Central FIXED fine patch: same signatures as build_amr_compiled (coarse cells
453 // [n/4 .. 3n/4-1]^2, refined x2). DISTRIBUTED round-robin DistributionMapping(nfine, n_ranks()),
454 // EXACTLY like the regrid of the mono-block path (amr_regrid_finest): the fine patches are
455 // distributed over the ranks (one per GPU). This is ESSENTIAL under MPI: on the REPLICATED coarse,
456 // if the fine were placed on the same replicated dmap ({my_rank()}), EACH rank would hold a copy
457 // of the fine box and the reflux (all_reduce_sum_inplace of the flux registers) would sum the SAME
458 // contribution n_ranks() times -> mass over-counted (grows with np). In serial (np=1) the round-robin
459 // dmap places the box on rank 0, identical to {my_rank()}: bit-identical.
460 const int I0 = bp.n / 4, I1 = 3 * bp.n / 4 - 1, J0 = bp.n / 4, J1 = 3 * bp.n / 4 - 1;
461 const Box2D fb{{2 * I0, 2 * J0}, {2 * I1 + 1, 2 * J1 + 1}};
462 BoxArray baf(std::vector<Box2D>{fb});
463 DistributionMapping dmf(baf.size(),
464 n_ranks()); // fine distributed round-robin (one patch per rank)
465 S.ba = {bac, baf};
466 S.dm = {dmc, dmf};
467 S.dx = {dxc, dxf};
468 S.dy = {dxc, dxf};
469 return S;
470}
471
496template <class Model, class Limiter, class Flux>
498 const Model& model, const SharedAmrLayout& S, const std::string& name,
499 const std::vector<double>& density, bool has_density, double gamma, int substeps,
500 bool recon_prim, bool imex, int stride = 1, const std::vector<int>& implicit_components = {},
501 const NewtonOptions& nopts = {}, const std::vector<double>* state = nullptr,
502 bool newton_diagnostics = false, AmrTimeMethod time_method = AmrTimeMethod::kEuler,
503 double pos_floor = 0.0) {
504 const int nc = Model::n_vars;
505 const int ng = Limiter::n_ghost; // limiter stencil (scheme parity, like build_amr_compiled)
506 const int nlev = S.nlev();
507 auto levels = std::make_shared<std::vector<AmrLevelMP>>();
508 levels->reserve(nlev);
509 for (int k = 0; k < nlev; ++k) {
510 MultiFab U(S.ba[k], S.dm[k], nc, ng);
511 U.set_val(Real(0));
512 levels->push_back(AmrLevelMP{std::move(U), nullptr, S.dx[k], S.dy[k]});
513 }
514 // Coarse seed + piecewise-constant injection to the fines, exactly like
515 // build_amr_compiled: COMPLETE CONSERVATIVE STATE (set_conservative_state, wave 3: now
516 // wired in multi-block, preferred) otherwise density (component 0, rest at rest) otherwise zero.
517 if (state && !state->empty())
518 detail::coupler_write_coarse_state((*levels)[0].U, *state, S.n, nc);
519 else if (has_density)
520 detail::coupler_write_coarse((*levels)[0].U, density, S.n, nc, gamma);
521 for (int k = 1; k < nlev; ++k)
522 detail::coupler_inject_coarse_to_fine_mb((*levels)[0].U, (*levels)[k].U, S.replicated_coarse);
523
524 AmrRuntimeBlock b;
525 b.name = name;
526 b.ncomp = nc;
527 b.gamma = gamma;
528 b.substeps = substeps;
529 b.stride = stride;
530 b.imex = imex; // time treatment of the block: selects advance vs imex_advance in step()
531 b.aux_ncomp = aux_comps<Model>(); // aux width READ by the model (B_z/T_e -> > kAuxBaseComps)
532 b.cons_vars =
533 Model::conservative_vars(); // names + ROLES: role resolution -> component of coupled sources
534 b.levels = levels;
535
536 const bool rprim = recon_prim;
537 // advance: ONE AMR transport sub-step of the block (conservative Berger-Oliger + reflux + average_down)
538 // of size dt, with ITS scheme (Limiter, Flux) on ITS level stack, source in
539 // FORWARD EULER (imex=false always here: the IMEX path lives in imex_advance, selected by
540 // step()). The sub-step loop (substeps) and the stride cadence are CARRIED by AmrRuntime::step,
541 // not by this closure: thus the multirate semantics are in ONE place in the engine (mirror
542 // of AmrSystemCoupler::step) and stay disableable / testable there. Implicit FUNCTOR:
543 // advance_amr<Limiter, Flux> is a named template function (no cross-TU extended lambda);
544 // we capture it in a std::function from THIS TU (device-clean recipe #64/#97).
545 // tmethod (kEuler default) selects SSPRK3 (time='ssprk3') for the explicit transport of the block;
546 // kEuler -> historical forward Euler, bit-identical. The explicit source stays carried by advance_amr.
547 b.advance = [model, rprim, time_method, pos_floor](std::vector<AmrLevelMP>& L, const Box2D& dom,
548 Real dt, Periodicity per, bool repl) {
549 advance_amr<Limiter, Flux>(model, L, dom, dt, per, repl, rprim, /*imex=*/false, NewtonOptions{},
550 time_method, static_cast<Real>(pos_floor));
551 };
552 // imex_advance (capstone vii): ONE Lie step [source-free transport; implicit source] whose
553 // SEMANTICS mirror the IMEX branch of AmrSystemCoupler::step (SourceFreeModel + AmrImplicitSourceStepper),
554 // populated ONLY if imex. (1) EXPLICIT transport on the SOURCE-FREE model (SourceFreeModel<Model>:
555 // flux/CFL of the model, null source) by the SAME AMR engine (conservative reflux); (2) stiff source
556 // IMPLICIT backward_euler_source AT EACH LEVEL (local Newton), with the mask @p implicit_components
557 // carried by the BLOCK (partial IMEX); (3) cascade fine -> coarse (mf_average_down_mb) for the coherence
558 // of the covered coarse cells. AmrRuntime::step calls this closure substeps times: at
559 // substeps=1 this is exactly the compile-time IMEX branch, for substeps>1 the runtime SUB-CYCLES the
560 // splitting (assumed decision, cf. IMEX SEMANTICS UNDER substeps in amr_runtime.hpp).
561 // We CAPTURE the mask in an ImplicitMask<Model::n_vars> (device-clean POD) once here (the
562 // width n_vars is known only at build, the mask is inactive if implicit_components is empty ->
563 // full backward-Euler, bit-identical to IMEX without a mask). SourceFreeModel<Model> is a concrete
564 // type instantiated IN this TU: its advance_amr<Limiter, Flux> stays compiled (no cross-TU extended
565 // lambda), captured in the std::function of identical signature to advance. The reconstruction
566 // of the source-free half-step stays CONSERVATIVE (recon_prim=false): SAME choice as AmrSystemCoupler::step
567 // (which calls advance_amr on SourceFreeModel with the default), and SourceFreeModel does not expose
568 // the primitive variables anyway (cf. its header). The EXPLICIT block, for its part, keeps recon_prim=rprim.
569 if (imex) {
570 ImplicitMask<Model::n_vars> mask;
571 for (int c : implicit_components)
572 if (c >= 0 && c < Model::n_vars) {
573 mask.active = true;
574 mask.flag[c] = true;
575 }
576 // NEWTON DIAGNOSTICS (OPT-IN, wave 3): we allocate the AGGREGATE report of the block in a shared_ptr
577 // (STABLE address even after moving the AmrRuntimeBlock into the engine registry) and we
578 // capture its raw pointer in the imex_advance closure. newton_diagnostics==false (default) ->
579 // nreport=nullptr -> backward_euler_source FAST path, bit-identical. The RESET of the report is the
580 // responsibility of AmrRuntime::step (head of the block advance), like System::AdvanceImex.
581 std::shared_ptr<NewtonReport> nrep;
582 if (newton_diagnostics) {
583 nrep = std::make_shared<NewtonReport>();
584 b.newton_diagnostics = true;
585 b.newton_report = nrep;
586 }
587 NewtonReport* nreport = nrep.get(); // null without diagnostics; stable address otherwise
588 b.imex_advance = [model, mask, nopts, nreport, pos_floor](std::vector<AmrLevelMP>& L,
589 const Box2D& dom, Real dt,
590 Periodicity per, bool repl) {
591 // (1) explicit source-free transport (-div F only), reflux carries the hyperbolic conservation.
592 // The Zhang-Shu floor (ADC-259) applies to the source-free TRANSPORT (the half-step that
593 // reconstructs faces); the stiff implicit source backward_euler_source below stays unfloored
594 // (cell-local, parity with the uniform System IMEX). SourceFreeModel<Model> forwards
595 // conservative_vars(), so positivity_comp resolves the SAME Density-role component.
596 advance_amr<Limiter, Flux>(SourceFreeModel<Model>{model}, L, dom, dt, per, repl,
597 /*recon_prim=*/false, /*imex=*/false, NewtonOptions{},
598 AmrTimeMethod::kEuler, static_cast<Real>(pos_floor));
599 // (2) stiff implicit source backward-Euler PER LEVEL (local Newton, block mask). The report
600 // nreport (null without diagnostics) AGGREGATES over the levels: backward_euler_source does its own
601 // max/sum + MPI all_reduce into *nreport (no reset here -> it also accumulates over the sub-steps,
602 // step() having reset at the head of the advance). nreport==nullptr -> fast bit-identical path.
603 const int nlev_l = static_cast<int>(L.size());
604 for (int k = 0; k < nlev_l; ++k)
605 backward_euler_source<Model>(model, *L[k].aux, L[k].U, dt, nopts, mask, nreport);
606 // (3) COVERAGE INVARIANT (cf. AmrImplicitSourceStepper): the implicit source was solved
607 // level by level, so a COVERED coarse cell would carry a phantom coarse source
608 // instead of the 2x2 average of its children. Cascade fine -> coarse for the coherence (the mass,
609 // sum of the coarse grid alone, then does not count the patch source twice). Mono-level: empty loop
610 // -> bit-identical. The source remaining CELL-LOCAL (not a face flux), it does NOT enter
611 // the reflux registers: conservation at the coarse-fine interfaces stays intact.
612 for (int k = nlev_l - 1; k >= 1; --k)
613 mf_average_down_mb(L[k].U, L[k - 1].U);
614 };
615 }
616 // PROJECTION PONCTUELLE post-pas (ADC-177) : cablee SEULEMENT si le modele declare m.project
617 // (HasPointwiseProjection). AmrRuntime::step l'applique PAR NIVEAU a la FIN de l'avance du bloc
618 // (substeps + reflux/cascade faits). Vide sinon -> trajectoire bit-identique. Capture le `model`
619 // concret comme advance / imex_advance (foncteur device-clean, pas de lambda etendue cross-TU).
620 if constexpr (HasPointwiseProjection<Model>)
621 b.project_per_level = [model](std::vector<AmrLevelMP>& L) {
622 detail::apply_pointwise_project_amr(model, L);
623 };
624 // Contribution of the block to the SUMMED Poisson RHS: rhs += elliptic_rhs(U) on the coarse grid (pure
625 // host loop). SAME functor as the flat System (make_poisson_rhs -> detail::PoissonRhs) -> each
626 // block accumulates (+=) into the SAME cells of the shared coarse grid (per-cell co-location).
627 b.add_elliptic_rhs = make_poisson_rhs(model);
628 // CFL SPEED of the block: SAME policy as System (make_max_speed) -- stability lambda*
629 // (HasStabilitySpeed trait) if the model declares it, otherwise max_wave_speed (historical fallback,
630 // bit-identical). The Riemann solvers always read max_wave_speed.
631 if constexpr (HasStabilitySpeed<Model>) {
632 b.max_speed = [model](const MultiFab& U, const MultiFab& aux) {
633 return max_stability_speed_mf(model, U, aux);
634 };
635 } else {
636 b.max_speed = [model](const MultiFab& U, const MultiFab& aux) {
637 return max_wave_speed_mf(model, U, aux);
638 };
639 }
640 // OPTIONAL STEP BOUNDS (AMR StabilityPolicy): same reductions as System
641 // (max_source_frequency_mf / min_stability_dt_mf), evaluated by AmrRuntime::step_cfl on the
642 // COARSE grid. Closures left EMPTY when the model does not declare the trait (bit-identical).
643 if constexpr (HasSourceFrequency<Model>) {
644 b.source_frequency = [model](const MultiFab& U, const MultiFab& aux) {
645 return max_source_frequency_mf(model, U, aux);
646 };
647 }
648 if constexpr (HasStabilityDt<Model>) {
649 b.stability_dt = [model](const MultiFab& U, const MultiFab& aux) {
650 return min_stability_dt_mf(model, U, aux);
651 };
652 }
653 const Geometry g = S.geom;
654 const bool repl = S.replicated_coarse;
655 b.mass = [levels, g, repl] {
656 const MultiFab& U = (*levels)[0].U;
657 const Real dV = g.dx() * g.dy();
658 Real M = 0;
659 for (int li = 0; li < U.local_size(); ++li) {
660 const ConstArray4 u = U.fab(li).const_array();
661 M += for_each_cell_reduce_sum(U.box(li),
662 [u, dV] POPS_HD(int i, int j) { return u(i, j, 0) * dV; });
663 }
664 return repl ? M : all_reduce_sum(M);
665 };
666 const int nn = S.n;
667 b.density = [levels, nn, repl] { return detail::coupler_read_coarse((*levels)[0].U, nn, repl); };
668 b.potential = [nn, repl](const MultiFab& aux0) {
669 return detail::coupler_read_coarse_phi(aux0, nn, repl);
670 };
671 return b;
672}
673
674// ADC-359 per-flux branches of dispatch_amr_block, factored so the compressible AMR seam compiles ONE
675// flux per TU (build_amr_block_for_flux -> these). Each body is the corresponding `if (riem == "<flux>")`
676// branch of dispatch_amr_block VERBATIM (same leaves, same hllc/roe `if constexpr` capability guards, same
677// messages); validate_riemann/limiter run in the caller (dispatch_amr_block, or the compressible thin
678// dispatcher python/amr_block_compressible.cpp). dispatch_amr_block (below, unchanged) still serves the
679// exb/isothermal seam, where the if constexpr guards prune hllc/roe.
680template <class Model>
682 const Model& m, const std::string& lim, const SharedAmrLayout& S, const std::string& name,
683 const std::vector<double>& density, bool has_density, double gamma, int substeps,
684 bool recon_prim, bool imex, int stride, const std::vector<int>& implicit_components,
685 const NewtonOptions& nopts, const std::vector<double>* state, bool newton_diagnostics,
686 AmrTimeMethod time_method, double pos_floor) {
687 if (lim == "none")
688 return build_amr_block<Model, NoSlope, RusanovFlux>(
689 m, S, name, density, has_density, gamma, substeps, recon_prim, imex, stride,
690 implicit_components, nopts, state, newton_diagnostics, time_method, pos_floor);
691 if (lim == "minmod")
692 return build_amr_block<Model, Minmod, RusanovFlux>(
693 m, S, name, density, has_density, gamma, substeps, recon_prim, imex, stride,
694 implicit_components, nopts, state, newton_diagnostics, time_method, pos_floor);
695 if (lim == "vanleer")
696 return build_amr_block<Model, VanLeer, RusanovFlux>(
697 m, S, name, density, has_density, gamma, substeps, recon_prim, imex, stride,
698 implicit_components, nopts, state, newton_diagnostics, time_method, pos_floor);
699 if (lim == "weno5")
700 return build_amr_block<Model, Weno5, RusanovFlux>(
701 m, S, name, density, has_density, gamma, substeps, recon_prim, imex, stride,
702 implicit_components, nopts, state, newton_diagnostics, time_method, pos_floor);
703 throw_registry_dispatch_mismatch("add_block(AmrSystem, multi-block)", "limiteur", lim);
704}
705
706template <class Model>
707AmrRuntimeBlock dispatch_amr_block_hll(const Model& m, const std::string& lim,
708 const SharedAmrLayout& S, const std::string& name,
709 const std::vector<double>& density, bool has_density,
710 double gamma, int substeps, bool recon_prim, bool imex,
711 int stride, const std::vector<int>& implicit_components,
712 const NewtonOptions& nopts, const std::vector<double>* state,
713 bool newton_diagnostics, AmrTimeMethod time_method,
714 double pos_floor) {
715 if constexpr (requires(const Model mm, typename Model::State s, Aux a, Real r) {
716 mm.wave_speeds(s, a, 0, r, r);
717 }) {
718 if (lim == "none")
719 return build_amr_block<Model, NoSlope, HLLFlux>(
720 m, S, name, density, has_density, gamma, substeps, recon_prim, imex, stride,
721 implicit_components, nopts, state, newton_diagnostics, time_method, pos_floor);
722 if (lim == "minmod")
723 return build_amr_block<Model, Minmod, HLLFlux>(
724 m, S, name, density, has_density, gamma, substeps, recon_prim, imex, stride,
725 implicit_components, nopts, state, newton_diagnostics, time_method, pos_floor);
726 if (lim == "vanleer")
727 return build_amr_block<Model, VanLeer, HLLFlux>(
728 m, S, name, density, has_density, gamma, substeps, recon_prim, imex, stride,
729 implicit_components, nopts, state, newton_diagnostics, time_method, pos_floor);
730 if (lim == "weno5")
731 return build_amr_block<Model, Weno5, HLLFlux>(
732 m, S, name, density, has_density, gamma, substeps, recon_prim, imex, stride,
733 implicit_components, nopts, state, newton_diagnostics, time_method, pos_floor);
734 throw_registry_dispatch_mismatch("add_block(AmrSystem, multi-block)", "limiteur", lim);
735 } else {
736 throw std::runtime_error(
737 "add_block(AmrSystem, multi-block): flux 'hll' requires signed wave "
738 "speeds (model.wave_speeds); this transport -> 'rusanov'");
739 }
740}
741
742template <class Model>
743AmrRuntimeBlock dispatch_amr_block_hllc(const Model& m, const std::string& lim,
744 const SharedAmrLayout& S, const std::string& name,
745 const std::vector<double>& density, bool has_density,
746 double gamma, int substeps, bool recon_prim, bool imex,
747 int stride, const std::vector<int>& implicit_components,
748 const NewtonOptions& nopts,
749 const std::vector<double>* state, bool newton_diagnostics,
750 AmrTimeMethod time_method, double pos_floor) {
751 if constexpr (HasHLLCStructure<Model> ||
752 (Model::n_vars == 4 &&
753 requires(const Model mm, typename Model::State s) { mm.pressure(s); })) {
754 if (lim == "none")
755 return build_amr_block<Model, NoSlope, HLLCFlux>(
756 m, S, name, density, has_density, gamma, substeps, recon_prim, imex, stride,
757 implicit_components, nopts, state, newton_diagnostics, time_method, pos_floor);
758 if (lim == "minmod")
759 return build_amr_block<Model, Minmod, HLLCFlux>(
760 m, S, name, density, has_density, gamma, substeps, recon_prim, imex, stride,
761 implicit_components, nopts, state, newton_diagnostics, time_method, pos_floor);
762 if (lim == "vanleer")
763 return build_amr_block<Model, VanLeer, HLLCFlux>(
764 m, S, name, density, has_density, gamma, substeps, recon_prim, imex, stride,
765 implicit_components, nopts, state, newton_diagnostics, time_method, pos_floor);
766 if (lim == "weno5")
767 return build_amr_block<Model, Weno5, HLLCFlux>(
768 m, S, name, density, has_density, gamma, substeps, recon_prim, imex, stride,
769 implicit_components, nopts, state, newton_diagnostics, time_method, pos_floor);
770 throw_registry_dispatch_mismatch("add_block(AmrSystem, multi-block)", "limiteur", lim);
771 } else {
772 throw std::runtime_error(
773 "add_block(AmrSystem, multi-block): flux 'hllc' requires a "
774 "compressible Euler 2D transport (4 variables + pressure) OR the "
775 "model's HLLC capability (pressure + wave_speeds + contact_speed + "
776 "hllc_star_state, cf. HasHLLCStructure); this transport -> "
777 "'hll'/'rusanov'");
778 }
779}
780
781template <class Model>
782AmrRuntimeBlock dispatch_amr_block_roe(const Model& m, const std::string& lim,
783 const SharedAmrLayout& S, const std::string& name,
784 const std::vector<double>& density, bool has_density,
785 double gamma, int substeps, bool recon_prim, bool imex,
786 int stride, const std::vector<int>& implicit_components,
787 const NewtonOptions& nopts, const std::vector<double>* state,
788 bool newton_diagnostics, AmrTimeMethod time_method,
789 double pos_floor) {
790 if constexpr (HasRoeDissipation<Model> ||
791 (Model::n_vars == 4 &&
792 requires(const Model mm, typename Model::State s) { mm.pressure(s); })) {
793 if (lim == "none")
794 return build_amr_block<Model, NoSlope, RoeFlux>(
795 m, S, name, density, has_density, gamma, substeps, recon_prim, imex, stride,
796 implicit_components, nopts, state, newton_diagnostics, time_method, pos_floor);
797 if (lim == "minmod")
798 return build_amr_block<Model, Minmod, RoeFlux>(
799 m, S, name, density, has_density, gamma, substeps, recon_prim, imex, stride,
800 implicit_components, nopts, state, newton_diagnostics, time_method, pos_floor);
801 if (lim == "vanleer")
802 return build_amr_block<Model, VanLeer, RoeFlux>(
803 m, S, name, density, has_density, gamma, substeps, recon_prim, imex, stride,
804 implicit_components, nopts, state, newton_diagnostics, time_method, pos_floor);
805 if (lim == "weno5")
806 return build_amr_block<Model, Weno5, RoeFlux>(
807 m, S, name, density, has_density, gamma, substeps, recon_prim, imex, stride,
808 implicit_components, nopts, state, newton_diagnostics, time_method, pos_floor);
809 throw_registry_dispatch_mismatch("add_block(AmrSystem, multi-block)", "limiteur", lim);
810 } else {
811 throw std::runtime_error(
812 "add_block(AmrSystem, multi-block): flux 'roe' requires a "
813 "compressible Euler 2D transport (4 variables + pressure) OR the "
814 "model's Roe capability (roe_dissipation, cf. HasRoeDissipation); "
815 "this transport -> 'hll'/'rusanov'");
816 }
817}
818
824template <class Model>
826 const Model& m, const std::string& lim, const std::string& riem, const SharedAmrLayout& S,
827 const std::string& name, const std::vector<double>& density, bool has_density, double gamma,
828 int substeps, bool recon_prim, bool imex, int stride = 1,
829 const std::vector<int>& implicit_components = {}, const NewtonOptions& nopts = {},
830 const std::vector<double>* state = nullptr, bool newton_diagnostics = false,
831 AmrTimeMethod time_method = AmrTimeMethod::kEuler, double pos_floor = 0.0) {
832 // CENTRALIZED VALIDATION (dispatch_tags.hpp registry) BEFORE the dispatch: same tags accepted /
833 // rejected as before, identical messages. The template if/else dispatch that follows is UNCHANGED; the
834 // capability guards (hllc/roe: 2D Euler or capability) stay `if constexpr` PER MODEL.
835 validate_riemann(riem, /*polar=*/false, "add_block(AmrSystem, multi-block)");
836 validate_limiter(lim, "add_block(AmrSystem, multi-block)");
837 // ADC-359: delegate to the flux-pinned dispatch_amr_block_<flux> helpers above (factored so the
838 // compressible seam compiles one flux per TU). Behavior is unchanged: same leaves, same hllc/roe
839 // capability guards, same throws. exb/isothermal route here as before (their guards prune hllc/roe).
840 if (riem == "rusanov")
841 return dispatch_amr_block_rusanov(m, lim, S, name, density, has_density, gamma, substeps,
842 recon_prim, imex, stride, implicit_components, nopts, state,
843 newton_diagnostics, time_method, pos_floor);
844 if (riem == "hll")
845 return dispatch_amr_block_hll(m, lim, S, name, density, has_density, gamma, substeps,
846 recon_prim, imex, stride, implicit_components, nopts, state,
847 newton_diagnostics, time_method, pos_floor);
848 if (riem == "hllc")
849 return dispatch_amr_block_hllc(m, lim, S, name, density, has_density, gamma, substeps,
850 recon_prim, imex, stride, implicit_components, nopts, state,
851 newton_diagnostics, time_method, pos_floor);
852 if (riem == "roe")
853 return dispatch_amr_block_roe(m, lim, S, name, density, has_density, gamma, substeps,
854 recon_prim, imex, stride, implicit_components, nopts, state,
855 newton_diagnostics, time_method, pos_floor);
856 throw_registry_dispatch_mismatch("add_block(AmrSystem, multi-block)", "flux", riem);
857}
858
859// ADC-359 per-flux branches of dispatch_amr_compiled, factored so the compressible compiled AMR seam
860// compiles ONE flux per TU (build_amr_compiled_for_flux -> these). Each body is the corresponding
861// `if (riem == "<flux>")` branch of dispatch_amr_compiled VERBATIM (same leaves, guards, messages);
862// validate_* run in the caller. dispatch_amr_compiled (below, unchanged) still serves exb/isothermal.
863template <class Model>
864AmrCompiledHooks dispatch_amr_compiled_rusanov(const Model& m, const std::string& lim,
865 const AmrBuildParams& bp) {
866 if (lim == "none")
867 return build_amr_compiled<Model, NoSlope, RusanovFlux>(m, bp);
868 if (lim == "minmod")
869 return build_amr_compiled<Model, Minmod, RusanovFlux>(m, bp);
870 if (lim == "vanleer")
871 return build_amr_compiled<Model, VanLeer, RusanovFlux>(m, bp);
872 if (lim == "weno5")
873 return build_amr_compiled<Model, Weno5, RusanovFlux>(m, bp);
874 throw_registry_dispatch_mismatch("add_compiled_model(AmrSystem)", "limiteur", lim);
875}
876
877template <class Model>
878AmrCompiledHooks dispatch_amr_compiled_hll(const Model& m, const std::string& lim,
879 const AmrBuildParams& bp) {
880 if constexpr (requires(const Model mm, typename Model::State s, Aux a, Real r) {
881 mm.wave_speeds(s, a, 0, r, r);
882 }) {
883 if (lim == "none")
884 return build_amr_compiled<Model, NoSlope, HLLFlux>(m, bp);
885 if (lim == "minmod")
886 return build_amr_compiled<Model, Minmod, HLLFlux>(m, bp);
887 if (lim == "vanleer")
888 return build_amr_compiled<Model, VanLeer, HLLFlux>(m, bp);
889 if (lim == "weno5")
890 return build_amr_compiled<Model, Weno5, HLLFlux>(m, bp);
891 throw_registry_dispatch_mismatch("add_compiled_model(AmrSystem)", "limiteur", lim);
892 } else {
893 throw std::runtime_error(
894 "add_compiled_model(AmrSystem): flux 'hll' requires signed wave "
895 "speeds (model.wave_speeds: declare a primitive 'p'); "
896 "this transport -> 'rusanov'");
897 }
898}
899
900template <class Model>
901AmrCompiledHooks dispatch_amr_compiled_hllc(const Model& m, const std::string& lim,
902 const AmrBuildParams& bp) {
903 if constexpr (HasHLLCStructure<Model> ||
904 (Model::n_vars == 4 &&
905 requires(const Model mm, typename Model::State s) { mm.pressure(s); })) {
906 if (lim == "none")
907 return build_amr_compiled<Model, NoSlope, HLLCFlux>(m, bp);
908 if (lim == "minmod")
909 return build_amr_compiled<Model, Minmod, HLLCFlux>(m, bp);
910 if (lim == "vanleer")
911 return build_amr_compiled<Model, VanLeer, HLLCFlux>(m, bp);
912 if (lim == "weno5")
913 return build_amr_compiled<Model, Weno5, HLLCFlux>(m, bp);
914 throw_registry_dispatch_mismatch("add_compiled_model(AmrSystem)", "limiteur", lim);
915 } else {
916 throw std::runtime_error(
917 "add_compiled_model(AmrSystem): flux 'hllc' requires a "
918 "compressible Euler 2D transport (4 variables + pressure) OR the "
919 "model's HLLC capability (pressure + wave_speeds + contact_speed + "
920 "hllc_star_state, cf. HasHLLCStructure); this transport -> "
921 "'hll'/'rusanov'");
922 }
923}
924
925template <class Model>
926AmrCompiledHooks dispatch_amr_compiled_roe(const Model& m, const std::string& lim,
927 const AmrBuildParams& bp) {
928 if constexpr (HasRoeDissipation<Model> ||
929 (Model::n_vars == 4 &&
930 requires(const Model mm, typename Model::State s) { mm.pressure(s); })) {
931 if (lim == "none")
932 return build_amr_compiled<Model, NoSlope, RoeFlux>(m, bp);
933 if (lim == "minmod")
934 return build_amr_compiled<Model, Minmod, RoeFlux>(m, bp);
935 if (lim == "vanleer")
936 return build_amr_compiled<Model, VanLeer, RoeFlux>(m, bp);
937 if (lim == "weno5")
938 return build_amr_compiled<Model, Weno5, RoeFlux>(m, bp);
939 throw_registry_dispatch_mismatch("add_compiled_model(AmrSystem)", "limiteur", lim);
940 } else {
941 throw std::runtime_error(
942 "add_compiled_model(AmrSystem): flux 'roe' requires a "
943 "compressible Euler 2D transport (4 variables + pressure) OR the "
944 "model's Roe capability (roe_dissipation, cf. HasRoeDissipation); "
945 "this transport -> 'hll'/'rusanov'");
946 }
947}
948
952template <class Model>
953AmrCompiledHooks dispatch_amr_compiled(const Model& m, const std::string& lim,
954 const std::string& riem, const AmrBuildParams& bp) {
955 // CENTRALIZED VALIDATION (dispatch_tags.hpp registry) BEFORE the dispatch: same tags accepted /
956 // rejected as before. Template if/else dispatch UNCHANGED; per-model hllc/roe capability guards.
957 validate_riemann(riem, /*polar=*/false, "add_compiled_model(AmrSystem)");
958 validate_limiter(lim, "add_compiled_model(AmrSystem)");
959 // ADC-359: delegate to the flux-pinned dispatch_amr_compiled_<flux> helpers above. Behavior unchanged
960 // (same leaves, guards, throws); exb/isothermal route here as before (their guards prune hllc/roe).
961 if (riem == "rusanov")
962 return dispatch_amr_compiled_rusanov(m, lim, bp);
963 if (riem == "hll")
964 return dispatch_amr_compiled_hll(m, lim, bp);
965 if (riem == "hllc")
966 return dispatch_amr_compiled_hllc(m, lim, bp);
967 if (riem == "roe")
968 return dispatch_amr_compiled_roe(m, lim, bp);
969 throw_registry_dispatch_mismatch("add_compiled_model(AmrSystem)", "flux", riem);
970}
971
972} // namespace detail
973
980 const std::string& block, const VariableSet& cons, const std::vector<std::string>& names,
981 const std::vector<std::string>& roles) {
982 std::vector<int> out;
983 auto push_unique = [&out](int c) {
984 if (std::find(out.begin(), out.end(), c) == out.end())
985 out.push_back(c);
986 };
987 for (const std::string& nm : names) {
988 int idx = -1;
989 for (int i = 0; i < static_cast<int>(cons.names.size()); ++i)
990 if (cons.names[i] == nm) {
991 idx = i;
992 break;
993 }
994 if (idx < 0)
995 throw std::runtime_error("add_compiled_model(AmrSystem): implicit_vars: variable '" + nm +
996 "' missing from block '" + block + "'");
997 push_unique(idx);
998 }
999 for (const std::string& rn : roles) {
1000 const VariableRole role = role_from_name(rn);
1001 const int idx = cons.index_of(role);
1002 if (role == VariableRole::Custom || idx < 0)
1003 throw std::runtime_error("add_compiled_model(AmrSystem): implicit_roles: role '" + rn +
1004 "' missing from block '" + block + "'");
1005 push_unique(idx);
1006 }
1007 std::sort(out.begin(), out.end());
1008 return out;
1009}
1010
1027template <class Model>
1028void add_compiled_model(AmrSystem& sys, const std::string& name, Model model,
1029 const std::string& limiter = "minmod",
1030 const std::string& riemann = "rusanov",
1031 const std::string& recon = "conservative",
1032 const std::string& time = "explicit", double gamma = 1.4, int substeps = 1,
1033 int stride = 1, const std::vector<std::string>& implicit_vars = {},
1034 const std::vector<std::string>& implicit_roles = {},
1035 double pos_floor = 0.0) {
1036 if (substeps < 1)
1037 throw std::runtime_error("add_compiled_model(AmrSystem): substeps >= 1");
1038 // PROJECTION PONCTUELLE post-pas (ADC-177) : DESORMAIS CABLEE sur AmrSystem. Appliquee PAR NIVEAU
1039 // a la fin de l'avance du pas (apres le reflux), aussi bien sur le coupleur mono-bloc
1040 // (build_amr_compiled -> cpl->levels()) que sur le multi-bloc natif (build_amr_block ->
1041 // AmrRuntime::step -> project_per_level). Cell-local + idempotente : conservation preservee (les
1042 // flux-registres sont deja regles). No-op si le modele ne declare pas m.project.
1043 // SSPRK3 IS NOT carried by the COMPILED path: neither the mono_builder nor the multi_builder
1044 // freezes AmrBuildParams::time_method / passes AmrTimeMethod to dispatch_amr_block (the flat ABI of the
1045 // .so loader does not marshal the method). EXPLICIT rejection rather than a silent kEuler fallback; an
1046 // SSPRK3 block must be NATIVE (AmrSystem::add_block / dispatch_amr_block, which threads it).
1047 if (time == "ssprk3")
1048 throw std::runtime_error(
1049 "add_compiled_model(AmrSystem): time='ssprk3' not carried by the "
1050 "compiled path (.so); use a native block pops.Model(...).");
1051 if (time != "explicit" && time != "imex")
1052 throw std::runtime_error("add_compiled_model(AmrSystem): time '" + time +
1053 "' unknown (explicit|imex)");
1054 if (recon != "conservative" && recon != "primitive")
1055 throw std::runtime_error("add_compiled_model(AmrSystem): recon unknown '" + recon +
1056 "' (conservative|primitive)");
1057 const bool recon_prim = (recon == "primitive");
1058 const bool imex = (time == "imex");
1059 // (1) MONO-BLOCK builder: captures the concrete Model + the scheme, materializes the AmrCouplerMP at the
1060 // lazy build (refine/poisson/density parameters frozen at that point). Historical path, untouched.
1061 auto mono_builder = [model, limiter, riemann, recon_prim, imex](const AmrBuildParams& bp) {
1062 AmrBuildParams p = bp;
1063 p.recon_prim = recon_prim;
1064 p.imex = imex;
1065 return detail::dispatch_amr_compiled(model, limiter, riemann, p);
1066 };
1067 // (2) MULTI-BLOCK builder: captures the SAME concrete Model/scheme, materializes the AmrRuntimeBlock of the
1068 // block on the SHARED layout (common to all blocks, created once at ensure_built). Resolves ITSELF
1069 // the partial IMEX mask against cons_vars of the concrete Model (known here), then calls dispatch_amr_block
1070 // -- EXACTLY the native path of add_block, only the point of type resolution differs (here at
1071 // the add, there from a ModelSpec at build). FUNCTOR without a cross-TU extended lambda in the kernel:
1072 // dispatch_amr_block captures advance_amr<Limiter, Flux> (named template function), device-clean
1073 // recipe #64/#97; the outer lambda only orchestrates (no device kernel in its body).
1074 auto multi_builder = [model, limiter, riemann](
1075 const detail::SharedAmrLayout& S, const std::string& bname,
1076 const std::vector<double>& density, bool has_density, double bgamma,
1077 int bsub, bool brecon_prim, bool bimex, int bstride,
1078 const std::vector<std::string>& ivars,
1079 const std::vector<std::string>& iroles, double bpos_floor) {
1080 const std::vector<int> impl_components =
1081 bimex
1082 ? resolve_implicit_components_compiled(bname, Model::conservative_vars(), ivars, iroles)
1083 : std::vector<int>{};
1084 // pos_floor (ADC-322): the .so flat ABI now carries the Zhang-Shu floor; forward it to the SAME
1085 // dispatch_amr_block -> build_amr_block leaf as a native multi-block. The compiled path transports
1086 // NEITHER Newton options/state/diagnostics NOR SSPRK3 (rejected at the facade / add_compiled_model),
1087 // so those intermediate arguments stay at their historical defaults (kEuler, no Newton, no state).
1088 return detail::dispatch_amr_block(
1089 model, limiter, riemann, S, bname, density, has_density, bgamma, bsub, brecon_prim, bimex,
1090 bstride, impl_components, NewtonOptions{},
1091 /*state=*/nullptr, /*newton_diagnostics=*/false, AmrTimeMethod::kEuler, bpos_floor);
1092 };
1093 sys.set_compiled_block(Model::n_vars, gamma, substeps, std::move(mono_builder),
1094 std::move(multi_builder), name, recon_prim, imex, stride, implicit_vars,
1095 implicit_roles, pos_floor);
1096}
1097
1098} // namespace pops
AmrCondensedSchurSourceStepper: AMR counterpart of the Schur-condensed SOURCE stage (CondensedSchurSo...
AmrCouplerMP: MULTI-PATCH E x B AMR coupler (coarse Poisson -> aux = grad phi -> fine injection -> co...
AMR multi-block engine at RUNTIME (type-erased registry keyed by name).
Multi-species composition on AMR at runtime: the refined counterpart of System.
Builds the closures of a block (time advance + residual + Poisson contribution) from a COMPILED model...
Box2D: the integer index space of a 2D cell-centered Cartesian grid.
BoxArray: the set of boxes tiling a level (disjoint, covering).
Schur-condensed SOURCE stage over an AMR hierarchy.
Definition amr_condensed_schur_source_stepper.hpp:54
void step(std::vector< AmrLevelMP > &levels, MultiFab &coarse_phi, const MultiFab &coarse_bz, int c_bz, Real theta, Real dt)
Condensed SOURCE stage, IN-PLACE on the hierarchy levels and the coarse potential coarse_phi.
Definition amr_condensed_schur_source_stepper.hpp:105
Multi-patch E x B AMR coupler.
Definition amr_coupler_mp.hpp:276
Single block carried on an AMR hierarchy, composed at runtime.
Definition amr_system.hpp:245
POPS_EXPORT void set_compiled_block(int ncomp, double gamma, int substeps, std::function< AmrCompiledHooks(const AmrBuildParams &)> mono_builder, AmrCompiledBlockBuilder multi_builder={}, const std::string &name=std::string(), bool recon_prim=false, bool imex=false, int stride=1, const std::vector< std::string > &implicit_vars={}, const std::vector< std::string > &implicit_roles={}, double pos_floor=0.0)
Registers a COMPILED block (add_compiled_model path, header amr_dsl_block.hpp).
Ordered list of boxes tiling a level.
Definition box_array.hpp:22
Single-block hyperbolic-elliptic coupler.
Definition coupler.hpp:74
Owning MPI rank of each box, indexed by GLOBAL box index (parallel to a BoxArray).
Definition distribution_mapping.hpp:19
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
void set_val(Real v)
Fills all cells (valid + ghosts) of every local fab with v.
Definition multifab.hpp:85
int local_size() const
Number of fabs OWNED by this rank (bound on local indices).
Definition multifab.hpp:65
Parallel seam: minimal MPI abstraction (rank/size + collectives) with serial fallback.
HLLC capability: the model provides the CONTACT wave speed and the STAR STATE on side k.
Definition numerical_flux.hpp:142
Trait OPTIONNEL : PROJECTION PONCTUELLE post-pas U -> project(U, aux) (ADC-177).
Definition physical_model.hpp:154
Roe capability: the model provides its FULL Roe dissipation d = |A_roe(UL, UR)| (UR - UL) – Roe avera...
Definition numerical_flux.hpp:156
OPTIONAL trait: local source frequency mu [1/s] (bound dt <= cfl / max mu, without h).
Definition physical_model.hpp:137
OPTIONAL trait: direct admissible step per cell (bound dt <= min stability_dt, without cfl).
Definition physical_model.hpp:143
OPTIONAL trait: stability speed lambda* replacing max_wave_speed in the block CFL.
Definition physical_model.hpp:131
SINGLE registry of spatial scheme tags (limiters + Riemann fluxes): shared source of truth for ALL di...
DistributionMapping: maps each box (by global index) to its owning MPI rank.
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...
Implicit / IMEX block step as a named CONTRACT.
MultiFab: a field DISTRIBUTED over a level (equivalent of AMReX's MultiFab).
AmrRuntimeBlock dispatch_amr_block_hll(const Model &m, const std::string &lim, const SharedAmrLayout &S, const std::string &name, const std::vector< double > &density, bool has_density, double gamma, int substeps, bool recon_prim, bool imex, int stride, const std::vector< int > &implicit_components, const NewtonOptions &nopts, const std::vector< double > *state, bool newton_diagnostics, AmrTimeMethod time_method, double pos_floor)
Definition amr_dsl_block.hpp:707
std::vector< double > coupler_read_coarse(const MultiFab &U, int n, bool replicated)
Definition amr_coupler_mp.hpp:169
AmrCompiledHooks dispatch_amr_compiled_rusanov(const Model &m, const std::string &lim, const AmrBuildParams &bp)
Definition amr_dsl_block.hpp:864
std::pair< BoxArray, DistributionMapping > coupler_make_coarse_layout(int n, bool distribute, int max_grid)
Definition amr_coupler_mp.hpp:257
AmrCompiledHooks dispatch_amr_compiled(const Model &m, const std::string &lim, const std::string &riem, const AmrBuildParams &bp)
Dispatch of the spatial scheme (limiter x Riemann flux) -> build_amr_compiled.
Definition amr_dsl_block.hpp:953
AmrRuntimeBlock dispatch_amr_block_rusanov(const Model &m, const std::string &lim, const SharedAmrLayout &S, const std::string &name, const std::vector< double > &density, bool has_density, double gamma, int substeps, bool recon_prim, bool imex, int stride, const std::vector< int > &implicit_components, const NewtonOptions &nopts, const std::vector< double > *state, bool newton_diagnostics, AmrTimeMethod time_method, double pos_floor)
Definition amr_dsl_block.hpp:681
AmrRuntimeBlock dispatch_amr_block_hllc(const Model &m, const std::string &lim, const SharedAmrLayout &S, const std::string &name, const std::vector< double > &density, bool has_density, double gamma, int substeps, bool recon_prim, bool imex, int stride, const std::vector< int > &implicit_components, const NewtonOptions &nopts, const std::vector< double > *state, bool newton_diagnostics, AmrTimeMethod time_method, double pos_floor)
Definition amr_dsl_block.hpp:743
std::vector< double > coupler_read_coarse_phi(const MultiFab &aux0, int n, bool replicated)
Definition amr_coupler_mp.hpp:191
void coupler_write_coarse(MultiFab &U, const std::vector< double > &rho, int n, int ncomp, double gamma)
Definition amr_coupler_mp.hpp:112
void amr_schur_source(Coupler &cpl, AmrCondensedSchurSourceStepper &schur, MultiFab &bz_coarse, MultiFab &phi_coarse, double theta, double dt)
A GLOBAL condensed source STAGE on the mono-block coupler hierarchy.
Definition amr_dsl_block.hpp:104
AmrRuntimeBlock dispatch_amr_block(const Model &m, const std::string &lim, const std::string &riem, const SharedAmrLayout &S, const std::string &name, const std::vector< double > &density, bool has_density, double gamma, int substeps, bool recon_prim, bool imex, int stride=1, const std::vector< int > &implicit_components={}, const NewtonOptions &nopts={}, const std::vector< double > *state=nullptr, bool newton_diagnostics=false, AmrTimeMethod time_method=AmrTimeMethod::kEuler, double pos_floor=0.0)
Dispatch of the spatial scheme (limiter x Riemann flux) -> build_amr_block.
Definition amr_dsl_block.hpp:825
void coupler_inject_coarse_to_fine_mb(const MultiFab &Uc, MultiFab &Uf, bool replicated)
Definition amr_coupler_mp.hpp:212
AmrRuntimeBlock dispatch_amr_block_roe(const Model &m, const std::string &lim, const SharedAmrLayout &S, const std::string &name, const std::vector< double > &density, bool has_density, double gamma, int substeps, bool recon_prim, bool imex, int stride, const std::vector< int > &implicit_components, const NewtonOptions &nopts, const std::vector< double > *state, bool newton_diagnostics, AmrTimeMethod time_method, double pos_floor)
Definition amr_dsl_block.hpp:782
SharedAmrLayout make_shared_amr_layout(const AmrBuildParams &bp)
Builds the SHARED layout (PR1): coarse (per the ownership policy) + ONE central FIXED fine patch (the...
Definition amr_dsl_block.hpp:440
AmrCompiledHooks dispatch_amr_compiled_hll(const Model &m, const std::string &lim, const AmrBuildParams &bp)
Definition amr_dsl_block.hpp:878
AmrCompiledHooks dispatch_amr_compiled_hllc(const Model &m, const std::string &lim, const AmrBuildParams &bp)
Definition amr_dsl_block.hpp:901
void apply_pointwise_project_amr(const Model &m, std::vector< AmrLevelMP > &levels)
Definition amr_dsl_block.hpp:65
AmrCompiledHooks dispatch_amr_compiled_roe(const Model &m, const std::string &lim, const AmrBuildParams &bp)
Definition amr_dsl_block.hpp:926
AmrRuntimeBlock build_amr_block(const Model &model, const SharedAmrLayout &S, const std::string &name, const std::vector< double > &density, bool has_density, double gamma, int substeps, bool recon_prim, bool imex, int stride=1, const std::vector< int > &implicit_components={}, const NewtonOptions &nopts={}, const std::vector< double > *state=nullptr, bool newton_diagnostics=false, AmrTimeMethod time_method=AmrTimeMethod::kEuler, double pos_floor=0.0)
Builds ONE type-erased AMR block (AmrRuntimeBlock) on the SHARED layout S, for a composite Model + co...
Definition amr_dsl_block.hpp:497
void amr_write_coarse_bz(MultiFab &bz, const std::vector< double > &field, int n)
Fills the COARSE B_z field (component 0, n*n row-major in GLOBAL indices) from field.
Definition amr_dsl_block.hpp:84
AmrCompiledHooks build_amr_compiled(const Model &model, const AmrBuildParams &bp)
Builds the AMR coupler for a composite Model + concrete (Limiter, Flux) and fills the type-erased hoo...
Definition amr_dsl_block.hpp:120
void coupler_write_coarse_state(MultiFab &U, const std::vector< double > &state, int n, int ncomp)
Definition amr_coupler_mp.hpp:143
Definition amr_hierarchy.hpp:29
Real for_each_cell_reduce_sum(const Box2D &b, F f)
SUM reduction of f(i, j) over box b.
Definition for_each.hpp:199
void throw_registry_dispatch_mismatch(const char *ctx, const char *kind, const std::string &tag)
DEFENSE-IN-DEPTH guard: reached only if a VALID tag (already accepted by validate_*) is routed by NO ...
Definition dispatch_tags.hpp:138
void validate_riemann(const std::string &riem, bool polar=false, const char *ctx="System")
Validates a Riemann FLUX tag against kRiemanns.
Definition dispatch_tags.hpp:111
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 mf_average_down_mb(const MultiFab &Uf, MultiFab &Uc)
Definition amr_subcycling.hpp:305
int n_ranks()
Definition comm.hpp:139
void validate_limiter(const std::string &lim, const char *ctx="System")
Validates a LIMITER tag against kLimiters.
Definition dispatch_tags.hpp:99
double all_reduce_sum(double x)
Definition comm.hpp:143
void add_compiled_model(AmrSystem &sys, const std::string &name, Model model, const std::string &limiter="minmod", const std::string &riemann="rusanov", const std::string &recon="conservative", const std::string &time="explicit", double gamma=1.4, int substeps=1, int stride=1, const std::vector< std::string > &implicit_vars={}, const std::vector< std::string > &implicit_roles={}, double pos_floor=0.0)
Wires model (concrete CompositeModel) as an AMR block of sys, with the requested scheme.
Definition amr_dsl_block.hpp:1028
Real min_stability_dt_mf(const Model &model, const MultiFab &U, const MultiFab &aux)
Global min of the declared admissible step (HasStabilityDt trait), via max(1/dt) (cf.
Definition wave_speed.hpp:222
std::vector< int > resolve_implicit_components_compiled(const std::string &block, const VariableSet &cons, const std::vector< std::string > &names, const std::vector< std::string > &roles)
Resolves the partial IMEX MASK (implicit_vars / implicit_roles) of a COMPILED block into indices of c...
Definition amr_dsl_block.hpp:979
void device_fence()
Device barrier: waits for in-flight kernels to finish before a HOST access to unified memory.
Definition kokkos_env.hpp:43
Real max_source_frequency_mf(const Model &model, const MultiFab &U, const MultiFab &aux)
Global max of the source frequency (HasSourceFrequency trait). 0 if the source does not constrain.
Definition wave_speed.hpp:209
AmrTimeMethod
Definition amr_flux_helpers.hpp:46
VariableRole
PHYSICAL role of a component.
Definition variables.hpp:27
std::function< void(const MultiFab &, MultiFab &)> make_poisson_rhs(const Model &m)
Block contribution to the Poisson right-hand side: rhs += elliptic_rhs(U) (host loop).
Definition block_builder.hpp:861
VariableRole role_from_name(const std::string &s)
Forward declaration: VariableSet::index_of(const std::string&) resolves a canonical role NAME via rol...
Definition variables.hpp:130
Real max_stability_speed_mf(const Model &model, const MultiFab &U, const MultiFab &aux)
Global max of the STABILITY speed (HasStabilitySpeed trait) – counterpart of max_wave_speed_mf.
Definition wave_speed.hpp:197
Real max_wave_speed_mf(const Model &model, const MultiFab &U, const MultiFab &aux)
max_wave_speed_mf: global max of the wave speed over the whole MultiFab (CFL).
Definition wave_speed.hpp:66
Single-interface numerical flux policies: Rusanov, HLL, HLLC, Roe.
Interface reconstruction policies: MUSCL limiters and WENO5-Z.
AMR inter-level transfer operators (integer ratio r) + parallel_copy.
Cartesian spatial operator: assembles R(U, aux) = -div F + S over the cells of a level.
Frozen parameters passed to the deferred build of the compiled path (add_compiled_model).
Definition amr_system.hpp:84
double L
Definition amr_system.hpp:86
double schur_theta
theta-scheme of the condensed stage (0.5 = Crank-Nicolson)
Definition amr_system.hpp:110
std::string schur_energy
Definition amr_system.hpp:129
double refine_threshold
1e30 => no refinement
Definition amr_system.hpp:92
bool has_state
Definition amr_system.hpp:103
std::function< bool(Real, Real)> wall
conductive wall predicate (empty = none)
Definition amr_system.hpp:94
int n
Definition amr_system.hpp:85
int coarse_max_grid
tile size of the distributed coarse (0 => n/2)
Definition amr_system.hpp:98
int schur_krylov_max_iters
iteration budget (<= 0 = default 400)
Definition amr_system.hpp:126
int regrid_every
Definition amr_system.hpp:87
BCRec poisson_bc
coarse Poisson BC (resolved by set_poisson)
Definition amr_system.hpp:93
std::vector< double > state
ncomp*n*n, component-major c*n*n + j*n + i; ncomp == Model::n_vars
Definition amr_system.hpp:105
bool imex
time == "imex": stiff implicit source (backward_euler)
Definition amr_system.hpp:91
std::map< int, std::vector< double > > named_aux
Model-NAMED aux fields (ADC-291): component (>= kAuxNamedBase) -> coarse base-level field (n*n row-ma...
Definition amr_system.hpp:119
bool distribute_coarse
distributed multi-box coarse (AMR strong-scaling)
Definition amr_system.hpp:97
bool schur
true: GLOBAL condensed source stage (instead of local explicit/imex)
Definition amr_system.hpp:109
double pos_floor
Definition amr_system.hpp:148
double schur_alpha
electrostatic coupling constant of the condensed stage
Definition amr_system.hpp:111
std::vector< double > density
initial coarse density (component 0), n*n
Definition amr_system.hpp:96
std::string schur_momentum_x
Definition amr_system.hpp:129
NewtonOptions newton_options
Definition amr_system.hpp:135
std::map< int, AuxHaloPolicy > named_aux_bc
Per-field aux HALO policies (ADC-369): component -> uniform boundary policy, seeded onto the engine a...
Definition amr_system.hpp:123
double schur_krylov_tol
tolerance of the coarse Krylov solve (<= 0 = default 1e-10)
Definition amr_system.hpp:125
bool has_density
Definition amr_system.hpp:95
std::string schur_momentum_y
Definition amr_system.hpp:129
std::vector< double > bz_field
coarse B_z(x,y) field, n*n row-major (required by the condensed stage)
Definition amr_system.hpp:115
double gamma
Definition amr_system.hpp:88
bool recon_prim
recon == "primitive" (frozen by add_compiled_model)
Definition amr_system.hpp:90
std::string schur_density
Definition amr_system.hpp:129
int substeps
Definition amr_system.hpp:89
bool schur_strang
true: Strang splitting H(dt/2) S(dt) H(dt/2); false: Lie H(dt) S(dt)
Definition amr_system.hpp:112
int time_method
Definition amr_system.hpp:140
Type-erased closures of a compiled AMR block, produced by amr_dsl_block::build_amr_compiled and insta...
Definition amr_system.hpp:153
std::function< double()> mass
coarse mass
Definition amr_system.hpp:157
std::function< void(double)> step
one macro-step (periodic regrid included)
Definition amr_system.hpp:155
std::function< std::vector< PatchBox >()> patch_boxes
index-space signatures of the fine patches
Definition amr_system.hpp:166
std::function< double()> max_speed
max wave speed (CFL step)
Definition amr_system.hpp:156
std::function< double()> stability_dt
coarse min of the admissible step (0 = does not constrain)
Definition amr_system.hpp:173
std::function< int()> n_patches
number of fine patches
Definition amr_system.hpp:158
std::function< void(int)> set_macro_step
restores the cadence (regrid) phase of the mono-block
Definition amr_system.hpp:179
std::shared_ptr< void > coupler_holder
keeps the AmrCouplerMP<Model> alive
Definition amr_system.hpp:154
std::function< double()> source_frequency
coarse max of mu [1/s] (0 = does not constrain)
Definition amr_system.hpp:171
Bundle (limiter, Riemann flux) expected by AmrCouplerMP::step<Disc>.
Definition amr_dsl_block.hpp:52
F NumericalFlux
Definition amr_dsl_block.hpp:54
L Limiter
Definition amr_dsl_block.hpp:53
Type-erased closures of ONE AMR block, placed on the shared hierarchy.
Definition amr_runtime.hpp:98
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
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
static Box2D from_extents(int nx, int ny)
Box [0, nx-1] x [0, ny-1] covering nx*ny cells from the index origin.
Definition box2d.hpp:42
int hi[2]
Definition box2d.hpp:39
int lo[2]
Definition box2d.hpp:38
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
Options of the local Newton of the implicit source (backward-Euler).
Definition implicit_stepper.hpp:114
INDEX-SPACE footprint of an AMR fine patch, exposed to Python by AmrSystem::patch_boxes().
Definition patch_box.hpp:30
Per-direction periodicity: halo wrapping in x and/or y during the exchange (false = open edge,...
Definition fill_boundary.hpp:37
A model's variable set: kind (cons/prim), names, size, canonical roles (optional, parallel to names; ...
Definition variables.hpp:58
std::vector< std::string > names
Definition variables.hpp:60
int index_of(VariableRole role) const
Index of the component carrying role (first occurrence), -1 if absent.
Definition variables.hpp:67
Definition geometric_mg.hpp:66
Kernel device de la PROJECTION PONCTUELLE post-pas (ADC-177) : U(i, j) <- m.project(U(i,...
Definition block_builder.hpp:225
SHARED layout of a multi-block AMR hierarchy (PR1 capstone), frozen at construction.
Definition amr_dsl_block.hpp:420
DistributionMapping dm_coarse
Definition amr_dsl_block.hpp:423
int n
Definition amr_dsl_block.hpp:430
int nlev() const
Definition amr_dsl_block.hpp:433
std::vector< BoxArray > ba
Definition amr_dsl_block.hpp:424
std::function< bool(Real, Real)> wall
Definition amr_dsl_block.hpp:429
BoxArray ba_coarse
Definition amr_dsl_block.hpp:422
BCRec poisson_bc
Definition amr_dsl_block.hpp:428
Geometry geom
Definition amr_dsl_block.hpp:421
std::vector< Real > dy
Definition amr_dsl_block.hpp:426
bool replicated_coarse
Definition amr_dsl_block.hpp:427
std::vector< DistributionMapping > dm
Definition amr_dsl_block.hpp:425
std::vector< Real > dx
Definition amr_dsl_block.hpp:426
#define POPS_HD
Definition types.hpp:25