AmrRuntime Class Reference

adc_cpp: pops::AmrRuntime Class Reference
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
pops::AmrRuntime Class Reference

AMR multi-block engine at runtime. More...

#include <amr_runtime.hpp>

+ Collaboration diagram for pops::AmrRuntime:

Public Types

using TagPredicate = std::function< bool(const ConstArray4 &, int, int)>
 Tag predicate of the union regrid: (ConstArray4 of the read field, i, j) -> should we refine ? HOST type (evaluated in the host loop of tag_cells, never on device): a std::function capturing a concrete functor is licit (nvcc-safe – the predicate does not enter a kernel).
 

Public Member Functions

 AmrRuntime (const Geometry &geom, const BoxArray &ba_coarse, const BCRec &bcPhi, std::vector< AmrRuntimeBlock > blocks, Periodicity base_per=Periodicity{true, true}, bool replicated_coarse=true, std::function< bool(Real, Real)> active={})
 
int nlev () const
 
std::size_t n_blocks () const
 
const VariableSetblock_cons_vars (std::size_t b) const
 Conservative VariableSet (names + physical roles, Model::conservative_vars()) of block b.
 
std::size_t n_coupled_sources () const
 
MultiFabphi ()
 
MultiFabpoisson_rhs ()
 
const MultiFabaux (int k) const
 
std::vector< AmrLevelMP > & levels (std::size_t b)
 
Real mass (std::size_t b) const
 
std::vector< double > density (std::size_t b) const
 
int solve_count () const
 
int regrid_count () const
 
void set_regrid (int every, int grow=2, int margin=2)
 Activates the UNION-TAGS REGRID at the cadence every (in macro-steps): every every macro-steps, BEFORE the macro-step's step(dt) (D2, consistent with the single-block amr_dsl_block.hpp:104), the shared hierarchy is re-gridded from the UNION of the tags of all blocks + phi.
 
void set_block_tag_predicate (std::size_t b, TagPredicate crit)
 Registers the TAG PREDICATE of block b (D1: PER-BLOCK union criterion).
 
void set_phi_tag_predicate (TagPredicate crit)
 Registers the PHI TAG PREDICATE (D4: SEPARATE phi criterion, on |grad phi|).
 
void set_named_aux (int comp, std::vector< Real > field)
 Registers a model-NAMED aux field (ADC-291) at shared-channel component comp (= kAuxNamedBase.
 
void set_named_aux_bc (int comp, AuxHaloPolicy policy)
 Registers a per-field aux HALO policy (ADC-369) for the named component comp: solve_fields applies it onto the COARSE aux AFTER the shared fill_ghosts, overriding only that component's physical-face ghosts (periodic faces stay periodic).
 
void add_coupled_source (const std::vector< std::string > &in_blocks, const std::vector< std::string > &in_roles, const std::vector< double > &consts, const std::vector< std::string > &out_blocks, const std::vector< std::string > &out_roles, const std::vector< int > &prog_ops, const std::vector< int > &prog_args, const std::vector< int > &prog_lens)
 Registers an inter-species COUPLED SOURCE (DSL CoupledSource, P5 bytecode) on the runtime facade, counterpart of System::add_coupled_source.
 
void coupled_source_step (Real dt)
 Applies ALL the registered coupled sources of a step dt, by forward-Euler splitting.
 
void solve_fields ()
 sync_down (per block) + system coarse Poisson (CO-LOCATED SUMMED RHS) + coarse aux + fine injection.
 
void solve_named_fields ()
 Solves every registered NAMED elliptic field (ADC-428) on the coarse, writes phi (+ centered grad) into the field's own aux components, ghost-fills them and injects coarse->fine.
 
void regrid ()
 UNION-TAGS REGRID (capstone Phase 2, C.6; docs/AMR_REGRID_UNION_TAGS_DESIGN.md, steps R0-R8).
 
void step (Real dt)
 Advances the system by one macro-step dt.
 
Real step_cfl (Real cfl, Real h)
 substeps/stride-aware CFL step (runtime counterpart of System::step_cfl, EXACT mirror of its formula).
 
int macro_step () const
 MACRO-STEP counter of the engine (regrid + hold-then-catch-up stride cadence: regrid when macro_step_ % regrid_every == 0, stride catch-up when (macro_step_+1) % stride == 0).
 
void set_macro_step (int s)
 RESTORES the macro-step counter (IO v1, reserved for restart via AmrSystem::set_clock): without it the regrid/stride cadence would restart from phase 0 after a resume.
 
void set_profiler (runtime::program::Profiler *prof)
 AMR / MPI PROFILING SEAM (Spec 5 sec.12.5, ADC-479 criterion 43).
 
void add_dt_bound (const std::string &label, std::function< double()> fn)
 GLOBAL step bound (AMR counterpart of System::add_dt_bound): fn() evaluated once per step_cfl, all_reduce_min, <= 0/non-finite = inert.
 
void add_coupled_frequency (const std::string &label, Real mu)
 DECLARED frequency of a coupled source (CoupledSource.frequency, wave-3 audit): step bound dt <= cfl / mu on the MACRO-step (the couplings apply once per macro-step).
 
void add_coupled_frequency_expr (const std::string &label, const std::vector< std::string > &in_blocks, const std::vector< std::string > &in_roles, const std::vector< double > &consts, const std::vector< int > &freq_prog_ops, const std::vector< int > &freq_prog_args)
 PER-CELL COUPLED frequency (CoupledSource.frequency with an Expr, refinement of the CONSTANT frequency above): a bytecode program mu(U) on the SAME register table as the source (inputs in_blocks/in_roles then constants consts).
 
const std::string & last_dt_bound () const
 ACTIVE bound of the last step_cfl ("transport:<block>" / "source_frequency:<block>" / "stability_dt:<block>" / "global:<label>" / "degenerate" / "" before the first step).
 
const NewtonReportnewton_report (const std::string &name) const
 NEWTON REPORT (OPT-IN IMEX diagnostics) of block name, AGGREGATED over the levels and substeps of its LAST advance (cf.
 
std::vector< double > potential ()
 Coarse potential (component 0 of the shared aux) as an n*n row-major field.
 
Real max_speed ()
 Max SYSTEM wave speed (max over the blocks) on the current coarse. Requires the aux up to date.
 
int n_patches () const
 
std::vector< PatchBoxpatch_boxes () const
 
int coarse_local_boxes () const
 
int coarse_total_boxes () const
 
int block_n_vars (std::size_t b) const
 
std::vector< double > block_level_state (std::size_t b, int k) const
 
std::vector< double > block_level_state_global (std::size_t b, int k) const
 
void set_block_level_state (std::size_t b, int k, const std::vector< double > &s)
 
std::vector< double > level_potential (int k)
 
std::vector< double > level_potential_global (int k)
 
void set_level_potential (int k, const std::vector< double > &p)
 
Named multi-elliptic fields (ADC-428)

A SECOND elliptic solve (beyond the default coarse Poisson) for a user-named field (m.elliptic_field("psi", rhs=..., aux=[...])) on the AMR hierarchy.

AMR counterpart of SystemFieldSolver::register_named_field / solve_named_field_from_state. Each named field owns a DEDICATED coarse GeometricMG solver (built lazily, REUSING the native solver – the operator is never reimplemented), its RHS = sum over blocks of named_elliptic_rhs[field], and its own aux output components (the model's named aux slots, >= kAuxNamedBase). solve_fields() solves every registered named field right after the default Poisson and injects its aux to the fine levels, so a bare run() leaves the field SOLVED (readable via named_field_values). The default Poisson path (mg_) is untouched / bit-identical. Empty default -> the named-field loop is a no-op.

Registers named field's aux output components: phi_comp where the solved potential lands, gx_comp / gy_comp where its centered gradient lands. gx_comp / gy_comp < 0 => only phi is written (the field declared fewer than 3 aux slots). Idempotent (re-register overwrites the components and drops the lazily-built solver so the next solve rebuilds it). The dedicated solver is built on the first solve, never here.

void register_named_field (const std::string &field, int phi_comp, int gx_comp, int gy_comp)
 
void set_block_named_elliptic_rhs (std::size_t b, const std::string &field, std::function< void(const MultiFab &, MultiFab &)> rhs)
 Attaches named field's RHS contribution closure (rhs += elliptic_field_rhs(U_b)) to block b.
 
std::size_t n_named_fields () const
 Number of registered named elliptic fields (diagnostic / test).
 
bool has_named_field (const std::string &field) const
 True if field is a registered named elliptic field.
 
std::vector< double > named_field_values (const std::string &field)
 Solved potential of named field as a COARSE n*n row-major field (diagnostic / read-back).
 

Detailed Description

AMR multi-block engine at runtime.

Owns the SHARED aux per level, the coarse Poisson (GeometricMG), the geometry + BC, and the type-erased block REGISTRY. Reproduces the AmrSystemCoupler algorithm (solve_fields + step) over closures rather than a CoupledSystem.

Member Typedef Documentation

◆ TagPredicate

using pops::AmrRuntime::TagPredicate = std::function<bool(const ConstArray4&, int, int)>

Tag predicate of the union regrid: (ConstArray4 of the read field, i, j) -> should we refine ? HOST type (evaluated in the host loop of tag_cells, never on device): a std::function capturing a concrete functor is licit (nvcc-safe – the predicate does not enter a kernel).

We use it for the PER-BLOCK criterion (read on the block density/U, component 0) and for the phi criterion (read on the shared aux). docs/AMR_REGRID_UNION_TAGS_DESIGN.md (D1, D4).

Constructor & Destructor Documentation

◆ AmrRuntime()

pops::AmrRuntime::AmrRuntime ( const Geometry geom,
const BoxArray ba_coarse,
const BCRec bcPhi,
std::vector< AmrRuntimeBlock blocks,
Periodicity  base_per = Periodicity{true, true},
bool  replicated_coarse = true,
std::function< bool(Real, Real)>  active = {} 
)
inline
Parameters
geomgeometry of the coarse level (domain + physical extents).
ba_coarseBoxArray of the coarse (the coarse Poisson lives on it).
bcPhiBC of the coarse Poisson.
blocksblock registry (>= 1), all on the SAME layout (guarded at the ctor).
base_perperiodicity of the base domain (transport).
replicated_coarseownership of level 0 (replicated single-box, or distributed multi-box).
activeconductive-wall predicate (passed to MG; empty = none).

Member Function Documentation

◆ add_coupled_frequency()

void pops::AmrRuntime::add_coupled_frequency ( const std::string &  label,
Real  mu 
)
inline

DECLARED frequency of a coupled source (CoupledSource.frequency, wave-3 audit): step bound dt <= cfl / mu on the MACRO-step (the couplings apply once per macro-step).

mu <= 0 = inert (no bound).

◆ add_coupled_frequency_expr()

void pops::AmrRuntime::add_coupled_frequency_expr ( const std::string &  label,
const std::vector< std::string > &  in_blocks,
const std::vector< std::string > &  in_roles,
const std::vector< double > &  consts,
const std::vector< int > &  freq_prog_ops,
const std::vector< int > &  freq_prog_args 
)
inline

PER-CELL COUPLED frequency (CoupledSource.frequency with an Expr, refinement of the CONSTANT frequency above): a bytecode program mu(U) on the SAME register table as the source (inputs in_blocks/in_roles then constants consts).

Evaluated at each step_cfl on the COARSE level of the input blocks (where the AMR CFL lives: h = dx_coarse), MAX reduction + global all_reduce_max, bound dt <= cfl / max(mu) on the macro-step. The bound is thus evaluated on the COARSE (not on the fine patches): consistent with the AMR transport CFL, but a local under-estimate of mu under a fine patch is not seen (assumed choice, documented). Empty program -> ignored (no bound). Form validation (opcodes / register bounds) and STRICT role resolution, like add_coupled_source.

+ Here is the call graph for this function:

◆ add_coupled_source()

void pops::AmrRuntime::add_coupled_source ( const std::vector< std::string > &  in_blocks,
const std::vector< std::string > &  in_roles,
const std::vector< double > &  consts,
const std::vector< std::string > &  out_blocks,
const std::vector< std::string > &  out_roles,
const std::vector< int > &  prog_ops,
const std::vector< int > &  prog_args,
const std::vector< int > &  prog_lens 
)
inline

Registers an inter-species COUPLED SOURCE (DSL CoupledSource, P5 bytecode) on the runtime facade, counterpart of System::add_coupled_source.

The ABI is FLAT (postfix bytecode): we resolve each (block, role) into (block index, component) then store a closure that, at each macro-step AFTER the transport, applies the source by additive forward-Euler splitting via coupled_source_step. The coupling is ENTIRELY baked into a stack machine (device-clean functor CoupledSourceKernel): NO per-cell Python callback in the hot path.

CONSERVATION (conservative exchange): with an add_pair construction (one +expr term on one block, -expr exactly on the other, SAME cell), the two per-cell contributions are opposite up to sign, so n_a + n_b is conserved PER CELL (and globally) to machine precision, independent of dt and of the state. The engine does not enforce it (an ionization creating a pair is licit): conservation is a property of the constructed coupling, checked test-side.

Parameters
in_blocks/in_rolesREAD fields (one register per (block, role)), in register order.
constsconstants (parameters), loaded into the registers after the inputs.
out_blocks/out_rolestarget (block, role) of each source term.
prog_ops/prog_argsCONCATENATED postfix bytecode of all the terms (split by prog_lens).
prog_lensprogram length of each term (size == out_blocks).
Exceptions
std::runtime_erroron an inconsistent form, an unknown role, an unknown block, an opcode or register out of bounds, or a program too long (same guards as System).
+ Here is the call graph for this function:

◆ add_dt_bound()

void pops::AmrRuntime::add_dt_bound ( const std::string &  label,
std::function< double()>  fn 
)
inline

GLOBAL step bound (AMR counterpart of System::add_dt_bound): fn() evaluated once per step_cfl, all_reduce_min, <= 0/non-finite = inert.

For user coupling/scheduler/policies.

◆ aux()

const MultiFab & pops::AmrRuntime::aux ( int  k) const
inline

◆ block_cons_vars()

const VariableSet & pops::AmrRuntime::block_cons_vars ( std::size_t  b) const
inline

Conservative VariableSet (names + physical roles, Model::conservative_vars()) of block b.

The SAME cons_vars that add_coupled_source resolves (block, role) against; exposed read-only so the facade can resolve a name/role-selected regrid variable into a component per block (ADC-296).

Exceptions
ifb is out of bounds.

◆ block_level_state()

std::vector< double > pops::AmrRuntime::block_level_state ( std::size_t  b,
int  k 
) const
inline
+ Here is the call graph for this function:

◆ block_level_state_global()

std::vector< double > pops::AmrRuntime::block_level_state_global ( std::size_t  b,
int  k 
) const
inline
+ Here is the call graph for this function:

◆ block_n_vars()

int pops::AmrRuntime::block_n_vars ( std::size_t  b) const
inline

◆ coarse_local_boxes()

int pops::AmrRuntime::coarse_local_boxes ( ) const
inline

◆ coarse_total_boxes()

int pops::AmrRuntime::coarse_total_boxes ( ) const
inline

◆ coupled_source_step()

void pops::AmrRuntime::coupled_source_step ( Real  dt)
inline

Applies ALL the registered coupled sources of a step dt, by forward-Euler splitting.

Runtime counterpart of AmrSystemCoupler::coupled_source_step: we refresh the fields (aux per level) then, source by source, we apply the bytecode INDEPENDENTLY AT EACH LEVEL of the shared hierarchy (the blocks live on ALL levels), followed by a fine -> coarse cascade.

COVERAGE INVARIANT (#169): the source was applied independently on EACH level, so a coarse cell COVERED by a fine patch would otherwise carry its own coarse source, unrelated to the source seen by its fine children. A covered coarse cell MUST be the 2x2 average of its children (it does not represent matter on its own). We restore this consistency by the SAME fine -> coarse cascade (mf_average_down_mb) as solve_fields and the compile-time engine: without it, the mass diagnostic (sum of the coarse only) would count a phantom coarse source under the patch. Single-level hierarchy: no covered cell, the cascade loops do not run -> bit-identical to the no-patch case.

PER-CELL CONSERVATION: at a given level, each term writes out(i,j,comp) += dt * S(reg(i,j)) on the SAME cell (i,j) read by the inputs; an add_pair exchange lays +S on one block and -S on the other AT THE SAME (i,j), so the sum of the two blocks is unchanged cell by cell. Without a registered source (coupled_sources_ empty): total no-op -> bit-identical trajectory to the historical one.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ density()

std::vector< double > pops::AmrRuntime::density ( std::size_t  b) const
inline

◆ has_named_field()

bool pops::AmrRuntime::has_named_field ( const std::string &  field) const
inline

True if field is a registered named elliptic field.

◆ last_dt_bound()

const std::string & pops::AmrRuntime::last_dt_bound ( ) const
inline

ACTIVE bound of the last step_cfl ("transport:<block>" / "source_frequency:<block>" / "stability_dt:<block>" / "global:<label>" / "degenerate" / "" before the first step).

◆ level_potential()

std::vector< double > pops::AmrRuntime::level_potential ( int  k)
inline
+ Here is the call graph for this function:

◆ level_potential_global()

std::vector< double > pops::AmrRuntime::level_potential_global ( int  k)
inline
+ Here is the call graph for this function:

◆ levels()

std::vector< AmrLevelMP > & pops::AmrRuntime::levels ( std::size_t  b)
inline
+ Here is the caller graph for this function:

◆ macro_step()

int pops::AmrRuntime::macro_step ( ) const
inline

MACRO-STEP counter of the engine (regrid + hold-then-catch-up stride cadence: regrid when macro_step_ % regrid_every == 0, stride catch-up when (macro_step_+1) % stride == 0).

◆ mass()

Real pops::AmrRuntime::mass ( std::size_t  b) const
inline

◆ max_speed()

Real pops::AmrRuntime::max_speed ( )
inline

Max SYSTEM wave speed (max over the blocks) on the current coarse. Requires the aux up to date.

+ Here is the call graph for this function:

◆ n_blocks()

std::size_t pops::AmrRuntime::n_blocks ( ) const
inline

◆ n_coupled_sources()

std::size_t pops::AmrRuntime::n_coupled_sources ( ) const
inline

◆ n_named_fields()

std::size_t pops::AmrRuntime::n_named_fields ( ) const
inline

Number of registered named elliptic fields (diagnostic / test).

◆ n_patches()

int pops::AmrRuntime::n_patches ( ) const
inline

◆ named_field_values()

std::vector< double > pops::AmrRuntime::named_field_values ( const std::string &  field)
inline

Solved potential of named field as a COARSE n*n row-major field (diagnostic / read-back).

Solves the fields if needed (counterpart of potential() for the default phi), then reads the field's phi_comp on the coarse aux.

Exceptions
iffield is unregistered. AMR counterpart of System::aux_field_component for a named elliptic field.
+ Here is the call graph for this function:

◆ newton_report()

const NewtonReport & pops::AmrRuntime::newton_report ( const std::string &  name) const
inline

NEWTON REPORT (OPT-IN IMEX diagnostics) of block name, AGGREGATED over the levels and substeps of its LAST advance (cf.

AmrRuntimeBlock::newton_report). AMR counterpart of System::newton_report.

Exceptions
std::runtime_errorif the block is unknown, or if it was not added with newton_diagnostics=true (no silently empty report).

◆ nlev()

int pops::AmrRuntime::nlev ( ) const
inline

◆ patch_boxes()

std::vector< PatchBox > pops::AmrRuntime::patch_boxes ( ) const
inline

◆ phi()

MultiFab & pops::AmrRuntime::phi ( )
inline
+ Here is the call graph for this function:

◆ poisson_rhs()

MultiFab & pops::AmrRuntime::poisson_rhs ( )
inline
+ Here is the call graph for this function:

◆ potential()

std::vector< double > pops::AmrRuntime::potential ( )
inline

Coarse potential (component 0 of the shared aux) as an n*n row-major field.

Solves the fields if needed (counterpart of AmrSystem::potential), then reads aux(0). Identical for all blocks.

+ Here is the call graph for this function:

◆ register_named_field()

void pops::AmrRuntime::register_named_field ( const std::string &  field,
int  phi_comp,
int  gx_comp,
int  gy_comp 
)
inline

◆ regrid()

void pops::AmrRuntime::regrid ( )
inline

UNION-TAGS REGRID (capstone Phase 2, C.6; docs/AMR_REGRID_UNION_TAGS_DESIGN.md, steps R0-R8).

Re-grids the SHARED hierarchy from the UNION (cell-by-cell OR) of the tags of ALL blocks (per-block predicate, D1) + the phi tags (on |grad phi|, D4), followed by ONE SINGLE Berger-Rigoutsos clustering -> ONE SINGLE new fine layout applied to ALL blocks (including those held by their stride, D3) AND to the shared aux. Maintains the shared-layout PRECONDITION (same_layout_or_throw) after the regrid. v1 with 2 LEVELS (coarse + 1 fine, D5): no-op if nlev < 2. No-op (grid unchanged) if the union of the tags is empty (nothing to refine).

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ regrid_count()

int pops::AmrRuntime::regrid_count ( ) const
inline

◆ set_block_level_state()

void pops::AmrRuntime::set_block_level_state ( std::size_t  b,
int  k,
const std::vector< double > &  s 
)
inline
+ Here is the call graph for this function:

◆ set_block_named_elliptic_rhs()

void pops::AmrRuntime::set_block_named_elliptic_rhs ( std::size_t  b,
const std::string &  field,
std::function< void(const MultiFab &, MultiFab &)>  rhs 
)
inline

Attaches named field's RHS contribution closure (rhs += elliptic_field_rhs(U_b)) to block b.

Called per declared field once the runtime owns the blocks.

Exceptions
ifb is out of bounds.

◆ set_block_tag_predicate()

void pops::AmrRuntime::set_block_tag_predicate ( std::size_t  b,
TagPredicate  crit 
)
inline

Registers the TAG PREDICATE of block b (D1: PER-BLOCK union criterion).

The predicate is evaluated on the block U (component 0 = density, or a discrete gradient at the caller's charge) at the PARENT level during the regrid; the UNION (OR) of the predicates of all blocks + the phi criterion drives the clustering. A block WITHOUT a registered predicate tags nothing on ITS side (it stays re-gridded as background, present everywhere, by the union of the other criteria).

Exceptions
ifb is out of bounds.

◆ set_level_potential()

void pops::AmrRuntime::set_level_potential ( int  k,
const std::vector< double > &  p 
)
inline
+ Here is the call graph for this function:

◆ set_macro_step()

void pops::AmrRuntime::set_macro_step ( int  s)
inline

RESTORES the macro-step counter (IO v1, reserved for restart via AmrSystem::set_clock): without it the regrid/stride cadence would restart from phase 0 after a resume.

No effect on the level state; only sets the cadence phase.

◆ set_named_aux()

void pops::AmrRuntime::set_named_aux ( int  comp,
std::vector< Real field 
)
inline

Registers a model-NAMED aux field (ADC-291) at shared-channel component comp (= kAuxNamedBase.

  • k for the k-th named field of a block), as a coarse base-level field field (n*n row-major, global cell index j*nx+i). The field is STATIC (external to the elliptic): solve_fields re-applies it onto the coarse aux every macro-step AFTER field_postprocess (which only writes phi/grad, comps 0..2) and BEFORE the coarse->fine injection, so it reaches every level and SURVIVES a regrid (regrid re-solves). AMR counterpart of System::set_aux_field_component. No-op default: without a named field the map is empty and the path is bit-identical. comp must be >= kAuxNamedBase and within the channel (the facade validates and resolves the name).

◆ set_named_aux_bc()

void pops::AmrRuntime::set_named_aux_bc ( int  comp,
AuxHaloPolicy  policy 
)
inline

Registers a per-field aux HALO policy (ADC-369) for the named component comp: solve_fields applies it onto the COARSE aux AFTER the shared fill_ghosts, overriding only that component's physical-face ghosts (periodic faces stay periodic).

Coarse-level scope (fine patches touching the domain boundary inherit the shared BC). No-op default. AMR counterpart of System::set_aux_field_halo_component.

◆ set_phi_tag_predicate()

void pops::AmrRuntime::set_phi_tag_predicate ( TagPredicate  crit)
inline

Registers the PHI TAG PREDICATE (D4: SEPARATE phi criterion, on |grad phi|).

The predicate is evaluated on the shared aux of the parent level (components 1,2 = grad phi in x,y) during the regrid; it adds to the union of the blocks' tags. Not registered -> phi does not contribute to the union.

◆ set_profiler()

void pops::AmrRuntime::set_profiler ( runtime::program::Profiler prof)
inline

AMR / MPI PROFILING SEAM (Spec 5 sec.12.5, ADC-479 criterion 43).

The AmrSystem owns the runtime::program::Profiler (parity with System::profiler_) and wires it in here AFTER build, so the engine times its non-numeric AMR phases – regrid, fill_boundary (the cross-rank ghost exchange), average_down (fine -> coarse restriction) – into the SAME table profile_report() renders, alongside the coarse step / field_solve phases. The pointer is null by default (the engine never touches it), and every scope/count is guarded by profiler_->enabled(), so a run WITHOUT profiling pays ZERO cost (no scope object, no clock read) – the granularity is per-regrid / per-solve, NOT per-cell. Passing nullptr detaches the profiler (no-op timing).

◆ set_regrid()

void pops::AmrRuntime::set_regrid ( int  every,
int  grow = 2,
int  margin = 2 
)
inline

Activates the UNION-TAGS REGRID at the cadence every (in macro-steps): every every macro-steps, BEFORE the macro-step's step(dt) (D2, consistent with the single-block amr_dsl_block.hpp:104), the shared hierarchy is re-gridded from the UNION of the tags of all blocks + phi.

every == 0 (DEFAULT) -> FROZEN hierarchy, regrid never called -> BIT-IDENTICAL trajectory to the historical one (the feature is opt-in). grow: tag dilation (nesting + anticipation); margin: nesting (clamp the patches to the boundaries). Must be called BEFORE the first step.

◆ solve_count()

int pops::AmrRuntime::solve_count ( ) const
inline

◆ solve_fields()

void pops::AmrRuntime::solve_fields ( )
inline

sync_down (per block) + system coarse Poisson (CO-LOCATED SUMMED RHS) + coarse aux + fine injection.

Reproduces AmrSystemCoupler::solve_fields identically, but the system RHS is assembled by the blocks' add_elliptic_rhs closures (Sum_b elliptic_rhs_b(U_b)) instead of a compile-time RhsAssembler.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ solve_named_fields()

void pops::AmrRuntime::solve_named_fields ( )
inline

Solves every registered NAMED elliptic field (ADC-428) on the coarse, writes phi (+ centered grad) into the field's own aux components, ghost-fills them and injects coarse->fine.

Mirror of the default Poisson block above (steps 2-4) but per named field, reusing a DEDICATED GeometricMG. The default phi/grad (comps 0..2) are never touched. No-op (early return) without a named field, so the default-only path stays bit-identical.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ step()

void pops::AmrRuntime::step ( Real  dt)
inline

Advances the system by one macro-step dt.

We first solve the fields (co-located summed Poisson, ONCE per macro-step: OncePerStep cadence), then each block advances over ITS level stack with ITS scheme, honoring its stride cadence and its substeps, and ITS temporal treatment. Runtime counterpart of AmrSystemCoupler::step (OncePerStep): the compile-time version carries substeps/stride in block_substeps_v / block_stride_v and chooses the treatment by the constexpr block_time_treatment_v; here the engine carries the substep loop, the stride filter AND the IMEX-vs-explicit selection.

TREATMENT SELECTION (capstone vii):

  • EXPLICIT block (b.imex == false): the advance closure does ONE advance_amr (transport + forward-Euler source), called substeps times;
  • IMEX block (b.imex == true): the imex_advance closure does ONE SOURCE-FREE advance_amr then the IMPLICIT stiff source backward_euler_source per level + cascade (cf. AmrRuntimeBlock::imex_advance), called substeps times. Unconditionally stable on a stiff relaxation (where the explicit, of factor |1 - dt/eps|, DIVERGES as soon as dt > 2 eps). The substep loop is COMMON to both treatments (substeps applications of h = bdt/substeps), so the runtime also SUB-CYCLES the IMEX splitting. At substeps=1 this sub-cycling is a no-op and the IMEX path coincides with the IMEX branch of the compile-time engine AmrSystemCoupler::step; for substeps>1 it DIVERGES deliberately from that engine (which itself ignores substeps on its IMEX branch): see IMEX SEMANTICS UNDER substeps in the header (CFL-safe on the transport, backward-Euler stable at any step, stiff relaxation more accurate). imex == false everywhere -> advance path only -> bit-identical trajectory to the historical one (the IMEX is opt-in).
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ step_cfl()

Real pops::AmrRuntime::step_cfl ( Real  cfl,
Real  h 
)
inline

substeps/stride-aware CFL step (runtime counterpart of System::step_cfl, EXACT mirror of its formula).

A block of stride cadence advances by an effective step stride*dt in substeps substeps, so each substep is worth stride*dt/substeps; the per-substep stability condition stride*dt/substeps <= cfl*h/w_b gives dt <= cfl*h*substeps_b/(stride_b*w_b). The GLOBAL dt is the min over the blocks (the most constraining). We first solve the fields (per-block max_speed requires the aux up to date), compute dt, then advance by one step(dt). h = coarse mesh spacing (dx_coarse). Returns the dt used. Single-block (a single block, stride=1): if w_b is the only constraining one, dt = cfl*h*substeps/w (identical to System::step_cfl single-block).

+ Here is the call graph for this function:

The documentation for this class was generated from the following file: