AmrSystem Class Reference

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

Single block carried on an AMR hierarchy, composed at runtime. More...

#include <amr_system.hpp>

+ Collaboration diagram for pops::AmrSystem:

Classes

struct  SourceNewtonReport
 Report of the implicit (IMEX) source Newton of a block, AGGREGATED over the levels and substeps of the block's LAST advance. More...
 

Public Member Functions

 AmrSystem (const AmrSystemConfig &cfg)
 
 ~AmrSystem ()
 
 AmrSystem (const AmrSystem &)=delete
 
AmrSystemoperator= (const AmrSystem &)=delete
 
 AmrSystem (AmrSystem &&) noexcept
 
AmrSystemoperator= (AmrSystem &&) noexcept
 
void add_dt_bound (const std::string &label, std::function< double()> fn)
 GLOBAL time-step bound (AMR counterpart of System::add_dt_bound): fn() evaluated ONCE per step_cfl (host), all_reduce_min (identical dt on all ranks), <= 0 / non-finite = inert this step.
 
std::string last_dt_bound () const
 ACTIVE bound of the last step_cfl: "transport:<block>" | "source_frequency:<block>" | "stability_dt:<block>" | "global:<label>" | "degenerate" | "" (no CFL step yet).
 
void add_block (const std::string &name, const ModelSpec &model, const std::string &limiter="minmod", const std::string &riemann="rusanov", const std::string &recon="conservative", const std::string &time="explicit", int substeps=1, int stride=1, const std::vector< std::string > &implicit_vars={}, const std::vector< std::string > &implicit_roles={}, const NewtonOptions &newton={}, bool newton_diagnostics=false, double positivity_floor=0.0)
 Adds a block carried on the AMR.
 
SourceNewtonReport newton_report (const std::string &name)
 
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).
 
void add_native_block (const std::string &name, const std::string &so_path, 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, double positivity_floor=0.0)
 Wires a NATIVE AMR block from a .so loader generated by the DSL (backend "production", target "amr_system": dsl.compile_native(target="amr_system") / compile(backend="production", target="amr_system")).
 
void set_refinement (double threshold, const std::string &variable=std::string(), const std::string &role=std::string())
 Refines the cells where the SELECTED conserved variable exceeds threshold.
 
void set_phi_refinement (double grad_threshold)
 Adds to the regrid criterion the PHI tag on |grad phi| (D4 of the design docs/AMR_REGRID_UNION_TAGS_DESIGN.md): also refines the cells where the norm of the gradient of the electrostatic potential |grad phi| (components 1,2 of the shared aux) exceeds grad_threshold.
 
void set_poisson (const std::string &rhs="charge_density", const std::string &solver="geometric_mg", const std::string &bc="auto", const std::string &wall="none", double wall_radius=0.0)
 Configures the coarse Poisson (cf.
 
void set_density (const std::string &name, const std::vector< double > &rho)
 Sets the initial density on the coarse level (component 0), n*n row-major.
 
void set_conservative_state (const std::string &name, const std::vector< double > &U)
 Sets the FULL INITIAL CONSERVATIVE STATE (all components) on the coarse level, then prolongs it to the fine levels at build (constant injection, like the density).
 
void set_magnetic_field (const std::vector< double > &bz)
 Sets the magnetic field B_z(x, y) of the coarse level (n*n row-major), required by the Schur-condensed source stage (Lorentz term Omega = B_z).
 
void set_aux_field_component (int comp, const std::vector< double > &field)
 Sets a model-NAMED aux field (ADC-291) at shared-channel component comp (>= kAuxNamedBase) from a coarse base-level field field (n*n row-major).
 
void set_aux_field_halo_component (int comp, int bc_type, double value)
 Declares a per-field aux HALO policy (ADC-369) for the NAMED component comp (>= kAuxNamedBase): bc_type is pops::BCType (Foextrap=1 / Dirichlet=2), value the Dirichlet boundary value.
 
void set_source_stage (const std::string &name, const std::string &kind, double theta, double alpha, const SourceStageOptions &opts={})
 Enables the Schur-CONDENSED SOURCE STAGE (amr-schur path) on block name.
 
void set_time_scheme (const std::string &scheme)
 Chooses the time-splitting policy of the condensed source stage: "lie" (default, H(dt) S(dt)) or "strang" (H(dt/2) S(dt) H(dt/2), 2nd order).
 
void add_coupled_source (const CoupledSourceProgram &prog, double frequency=0.0, const std::string &label="coupled_source")
 Registers an inter-species COUPLED SOURCE (compiled pops.dsl.CoupledSource, flat bytecode ABI P5), refined counterpart of System::add_coupled_source but on the SHARED AMR hierarchy.
 
void step (double dt)
 one AMR macro-step (periodic regrid included)
 
void advance (double dt, int nsteps)
 
double step_cfl (double cfl)
 Advances at dt = cfl * coarse_dx / max wave speed.
 
int nx () const
 
double time () const
 
int macro_step () const
 MACRO-STEP counter (0-indexed; incremented by step / advance / step_cfl), parity with System::macro_step.
 
void set_clock (double t, int macro_step)
 RESTORES the AMR clock (t, macro_step) – parity with System::set_clock.
 
int n_blocks () const
 number of blocks (1 = mono-block AmrCouplerMP; >= 2 = AmrRuntime)
 
std::vector< std::string > block_names () const
 Names of the blocks in add order (parity with System::block_names): the IO facade iterates over them to write EACH block by its name (an empty name -> block 0, historical mono-block compat).
 
int n_patches ()
 number of current fine patches (of the shared hierarchy)
 
std::vector< PatchBoxpatch_boxes ()
 Index-space signatures of the current fine patches: one PatchBox (level, ilo, jlo, ihi, jhi) per fine box, for ALL fine levels (level >= 1).
 
int coarse_local_boxes ()
 COARSE-level (base) box counts, MPI ownership diagnostic (ADC-319).
 
int coarse_total_boxes ()
 
int n_levels ()
 AMR CHECKPOINT / RESTART (ADC-65 single-block single-rank; ADC-509 multi-block + np>1): per-level STATE accessors + hierarchy imposition for a BIT-IDENTICAL resumption (cf.
 
int n_vars ()
 number of conserved components (MONO-BLOCK; multi-block: block_n_vars)
 
std::vector< double > level_state (int k)
 FULL conservative state of level k, flat component-major c*nf*nf + j*nf + i (nf = n << k; zeros outside the patches at the fine level – only the patch interior is defined).
 
std::vector< double > level_state_global (int k)
 MONO-BLOCK, np>1 gather (all ranks call)
 
void set_level_state (int k, const std::vector< double > &s)
 restores the state of level k (as is)
 
std::vector< double > level_potential (int k)
 Potential phi of level k, flat nf*nf row-major.
 
std::vector< double > level_potential_global (int k)
 np>1 gather (all ranks call)
 
void set_level_potential (int k, const std::vector< double > &p)
 restores phi of level k
 
void set_hierarchy (const std::vector< PatchBox > &boxes)
 Imposes the SAVED fine hierarchy (at restart) instead of Berger-Rigoutsos clustering: boxes are the patch_boxes() signatures of the checkpoint (filtered to level 1 in mono-block).
 
int block_n_vars (const std::string &name)
 MULTI-BLOCK per-BLOCK per-level checkpoint accessors (ADC-509).
 
std::vector< double > block_level_state (const std::string &name, int k)
 
std::vector< double > block_level_state_global (const std::string &name, int k)
 np>1 gather (all ranks call)
 
void set_block_level_state (const std::string &name, int k, const std::vector< double > &s)
 
double mass ()
 mass of the 1st block on the coarse (conserved at reflux)
 
double mass (const std::string &name)
 mass of the named block on the coarse (conserved PER BLOCK)
 
std::vector< double > density ()
 coarse density of the 1st block (component 0), n*n row-major
 
std::vector< double > density (const std::string &name)
 coarse density of the named block, n*n
 
std::vector< double > potential ()
 Electrostatic potential phi of the COARSE LEVEL (base), n*n row-major.
 
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 System::register_elliptic_field / set_block_elliptic_field. The named field owns its RHS (a per-block brick), a DEDICATED coarse GeometricMG, and its OWN aux output components; AmrRuntime solves it each solve_fields and injects it to the fine levels, so a bare run() leaves it SOLVED. The default Poisson path is untouched / bit-identical. Registering a named field forces the MULTI-BLOCK runtime engine (AmrRuntime) even for a single block (the named-field solve lives there, not on the single-block AmrCouplerMP coupler). POPS_EXPORT: resolved by the generated AMR .so / native loader across the dlopen boundary, like set_compiled_block.

Registers named field's aux output components (where its solved phi / centered grad land). Called by the native AMR loader for each m.elliptic_field. gx_comp / gy_comp < 0 => only phi is written (the field declared fewer than 3 aux slots).

Exceptions
ifthe system is already built.
POPS_EXPORT void register_elliptic_field (const std::string &field, int phi_comp, int gx_comp, int gy_comp)
 
POPS_EXPORT void set_block_elliptic_field (const std::string &block_name, const std::string &field, std::function< void(const MultiFab &, MultiFab &)> rhs)
 Attaches named field's RHS closure (rhs += elliptic_field_rhs(U)) to block block_name.
 
std::vector< double > named_field_values (const std::string &field)
 Solved potential of named field on the COARSE level, n*n row-major (read-back).
 
AMR / MPI profiling (Spec 5 sec.12.5, ADC-479 criterion 43)

Per-phase wall-clock timing of the AMR runtime: the engine times its non-numeric phases – "regrid" (rebuild the patch hierarchy), "fill_boundary" (the cross-rank ghost halo exchange), "average_down" (restrict fine onto coarse) – plus integer counters ("regrid" / "fill_boundary" per-run counts, and under MPI np>1 "mpi_reductions" / "mpi_messages").

Disabled by default (no hot-path cost when off, parity with System). enable_profiling() then step()/step_cfl() over a run where a regrid fires (regrid_every set) then profile_report() returns the table; the typed PerformanceSummary.by_amr_mpi() view surfaces it. Per-rank (no cross-rank reduction of the report). Multi-block engine only (the runtime owns the union regrid + shared-aux halo).

void enable_profiling ()
 
void disable_profiling ()
 
bool is_profiling () const
 
void reset_profiling ()
 
std::string profile_report () const
 

Detailed Description

Single block carried on an AMR hierarchy, composed at runtime.

pops::AmrSystemConfig cfg; // base level: n x n on [0, L]^2
cfg.n = 64;
pops::AmrSystem amr(cfg);
ne.transport = "exb"; ne.source = "none"; ne.elliptic = "charge";
amr.add_block("ne", ne, "minmod", "rusanov", "conservative", "explicit");
amr.set_poisson("charge_density", "geometric_mg");
amr.set_refinement(0.1); // refine where any block's field exceeds the threshold
amr.set_density("ne", rho0); // rho0: initial density on the base level
amr.step_cfl(0.4); // conservative refluxed step + composite FAC Poisson
Single block carried on an AMR hierarchy, composed at runtime.
Definition amr_system.hpp:245
AMR mesh and cadence (per-block physical parameters live in the ModelSpec).
Definition amr_system.hpp:61
int n
coarse-level cells per direction
Definition amr_system.hpp:62
Brick composition of a block plus parameters.
Definition model_spec.hpp:27
std::string source
"none" (default, neutral: no force) | "potential" | "gravity"
Definition model_spec.hpp:29
std::string elliptic
REQUIRED (unset): "charge" | "background" | "gravity".
Definition model_spec.hpp:31
std::string transport
REQUIRED (unset): "exb" | "compressible" | "isothermal".
Definition model_spec.hpp:28

Constructor & Destructor Documentation

◆ AmrSystem() [1/3]

pops::AmrSystem::AmrSystem ( const AmrSystemConfig cfg)
explicit

◆ ~AmrSystem()

pops::AmrSystem::~AmrSystem ( )

◆ AmrSystem() [2/3]

pops::AmrSystem::AmrSystem ( const AmrSystem )
delete

◆ AmrSystem() [3/3]

pops::AmrSystem::AmrSystem ( AmrSystem &&  )
noexcept

Member Function Documentation

◆ add_block()

void pops::AmrSystem::add_block ( const std::string &  name,
const ModelSpec model,
const std::string &  limiter = "minmod",
const std::string &  riemann = "rusanov",
const std::string &  recon = "conservative",
const std::string &  time = "explicit",
int  substeps = 1,
int  stride = 1,
const std::vector< std::string > &  implicit_vars = {},
const std::vector< std::string > &  implicit_roles = {},
const NewtonOptions newton = {},
bool  newton_diagnostics = false,
double  positivity_floor = 0.0 
)

Adds a block carried on the AMR.

Same spatial-scheme parameters as System (limiter x riemann x recon), applied to each level/patch of the hierarchy. The FIRST add_block defines the block; a 2nd (or more) switches to the multi-block engine (shared hierarchy, co-located sum Poisson). Blocks can have DIFFERENT SPATIAL SCHEMES.

Parameters
nameblock name: INDEXES the block (set_density(name), mass(name), density(name)). In multi-block the name must be unique; mono-block an empty name targets the single block.
modelcomposition of bricks (transport/source/elliptic + parameters)
limiter"none" | "minmod" | "vanleer" | "weno5" (weno5 = WENO5-Z, 3 ghosts; rusanov)
riemann"rusanov" | "hll" (generic signed-wave, requires model.wave_speeds) | "hllc" | "roe" (generic when the model supplies the Riemann capability HasHLLCStructure / HasRoeDissipation; else the canonical Euler 2D layout, 4 variables + pressure)
time"explicit" (SSPRK2, forward-Euler source carried by the AMR step) | "ssprk3" (SSPRK3, order 3, reflux per stage; explicit transport, EXCLUSIVE of imex) | "imex" (stiff source handled IMPLICITLY by backward_euler_source; the transport stays explicit, carried by the conservative reflux; cf. capstone vii). Any other treatment is refused.
substepsexplicit substeps of the block (>= 1): the effective step is split into substeps equal pieces (MULTI-BLOCK only; in mono-block, carried by AmrCouplerMP).
strideHOLD-THEN-CATCH-UP cadence of the block (>= 1; default 1 = each macro-step). stride=M holds the block M-1 macro-steps then catches it up by an effective step M*dt (multirate). MULTI-BLOCK only (a single block always advances every step). step_cfl honors the cadence: dt = cfl*h*min_b(substeps_b/(stride_b*w_b)), mirror of System::step_cfl.
implicit_vars/ implicit_roles partial IMEX mask CARRIED BY THE BLOCK (cf. System::add_block): conserved components handled IMPLICITLY, by NAME (implicit_vars) or by physical ROLE (implicit_roles). EMPTY (default) -> full backward-Euler (all components implicit). Only meaningful with time="imex": requesting them in explicit is an ERROR (no silent ignore). MULTI-BLOCK only (the mono-block AmrCouplerMP carries its IMEX without a mask; a mask there is therefore refused).
Exceptions
std::runtime_errorif a block is already defined, if substeps < 1, if stride < 1, if time is not in {explicit, ssprk3, imex}, if recon is not in {conservative, primitive}, or if an implicit mask is requested outside IMEX / with a name-role absent from the block.
Parameters
newtonoptions of the IMEX source Newton grouped in a POD (ADC-214; cf. NewtonOptions; parity with System::add_block): max_iters / rel_tol / abs_tol / fd_eps / damping / fail_policy. Default {} = historical constants, bit-identical. SUPPORT (wave 3, settled): these OPTIONS are wired in MONO-BLOCK (coupler AmrCouplerMP) AND in MULTI-BLOCK (AmrRuntime engine); the .so loaders reject them (flat ABI). fail_policy warn/throw works everywhere.
newton_diagnosticsaggregated Newton report (newton_report): wired in NATIVE MULTI-BLOCK only (the mono-block rejects it at build, the .so loaders at the facade). Stays flat (a separate bool, outside the homogeneous family of convergence options).
positivity_floorZhang-Shu positivity floor (ADC-259): if > 0, the AMR transport floors the Density-role face states (reconstruct_pp / zhang_shu_scale) AND the C/F fine ghost means to >= floor. Default 0 = inactive, bit-identical. Guarantee = face / ghost-state Density positivity only (order-1 fallback), NOT updated-mean nor pressure positivity (parity with System::add_block). A model without a Density role rejects floor > 0. The COMPILED .so path carries it too (ADC-322): a loader regenerated against this header marshals the floor (pops_install_native_amr).

◆ add_coupled_source()

void pops::AmrSystem::add_coupled_source ( const CoupledSourceProgram prog,
double  frequency = 0.0,
const std::string &  label = "coupled_source" 
)

Registers an inter-species COUPLED SOURCE (compiled pops.dsl.CoupledSource, flat bytecode ABI P5), refined counterpart of System::add_coupled_source but on the SHARED AMR hierarchy.

The source is applied at EACH macro-step AFTER the transport, by forward-Euler splitting, level by level, followed by a fine -> coarse cascade (consistency of the covered coarse cells, #169). The coupling is baked into a device-clean stack machine (CoupledSourceKernel): NO per-cell Python callback in the hot path. MULTI-BLOCK only (>= 2 add_block: the coupling reads/writes SEVERAL named blocks). Must be called BEFORE the first step (the runtime engine is built at lazy build; the source is injected into it).

CONSERVATION: an add_pair construction (a term +expr on a block, -expr exactly on the other, SAME cell) makes the sum of the two blocks conserved PER CELL (and globally) to machine precision. The engine does NOT IMPOSE it (an ionization creating an e/i pair is legal): it is a property of the constructed coupling (verify_conservation on the DSL side checks it symbolically).

Exceptions
std::runtime_errorif called in mono-block, if the system is already built, or if the shape of the bytecode / a role / a block is invalid (same guards as System).
Parameters
progbytecode description of the coupling grouped in a POD (ADC-214; cf. CoupledSourceProgram; parity with System::add_coupled_source): in_blocks / in_roles / consts / out_blocks / out_roles + prog_ops / prog_args / prog_lens (stack machine) + freq_prog_ops / freq_prog_args (PER-CELL frequency mu(U) optional; EMPTY = constant frequency only, bit-identical; non-empty: evaluated on the COARSE LEVEL of the input blocks at each step_cfl, MAX + all_reduce_max, bound dt <= cfl / max(mu) on the coarse, not the patches).
frequencyCONSTANT declared frequency mu [1/s] of the coupling (wave 3): bound dt <= cfl/mu on the macro-step of step_cfl; <= 0 (default) = no bound.
labelname of the coupling (reason "coupled_source:<label>" of last_dt_bound).

◆ add_dt_bound()

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

GLOBAL time-step bound (AMR counterpart of System::add_dt_bound): fn() evaluated ONCE per step_cfl (host), all_reduce_min (identical dt on all ranks), <= 0 / non-finite = inert this step.

Hook for non-local constraints (coupling, scheduler, user ramp).

◆ add_native_block()

void pops::AmrSystem::add_native_block ( const std::string &  name,
const std::string &  so_path,
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,
double  positivity_floor = 0.0 
)

Wires a NATIVE AMR block from a .so loader generated by the DSL (backend "production", target "amr_system": dsl.compile_native(target="amr_system") / compile(backend="production", target="amr_system")).

AMR counterpart of System::add_native_block: the .so inlines the header template add_compiled_model(AmrSystem&, ...), which materializes a concrete AmrCouplerMP<Model> at lazy build and installs its hooks via set_compiled_block – NATIVE path, SAME AMR hierarchy as add_block (conservative reflux, regrid), no flat-array marshaling.

The _pops module is PROMOTED to global scope (RTLD_NOLOAD) then the loader is dlopen-ed in RTLD_GLOBAL to resolve set_compiled_block; the ABI key baked in the loader (pops_native_abi_key) is compared to the module's (abi_key()) – mismatch => clear error (no silent UB at the C++ boundary). Same scheme guard-rails as System (upstream validation).

MULTI-BLOCK (capstone v): add_native_block CAN now be called several times (or mixed with native add_block) -> the compiled blocks co-exist on the shared hierarchy via AmrRuntime (the loader recompiled against this header provides the runtime builder; cf. set_compiled_block). The name then INDEXES the block (set_density/mass/density), like add_block. time is wired to {explicit, imex} (imex = stiff implicit source via backward_euler_source; any other treatment is rejected by add_compiled_model). The multirate (stride) and the partial IMEX mask do NOT transit through the flat ABI of the loader (ABI unchanged): this .so path now REJECTS them at the Python facade level (AmrSystem.add_equation raises ValueError on stride>1 or a non-empty IMEX mask, rather than ignoring them silently). For these parameters, use native add_block (ModelSpec) or add_compiled_model(AmrSystem&) DIRECTLY (header), which expose stride and the mask. recon "primitive" and flux "roe"/"hllc" are WIRED at parity (#113: dispatch_amr_compiled accepts them; the Python facade applies a pressure guard for hllc/roe). limiter "weno5" (WENO5-Z, 3 ghosts) is WIRED on rusanov (#105: the coupler levels are allocated to Limiter::n_ghost and the regrid inherits n_grow(): no out-of-bounds read).

Exceptions
std::runtime_errorif the ABI diverges, if a symbol is missing, or substeps < 1.
Parameters
nameblock name: cosmetic in mono-block, INDEXES the block in multi-block (set_density/ mass/density; must be unique and non-empty from the 2nd block on, like add_block).
positivity_floorZhang-Shu positivity floor of the block (ADC-322): the .so flat ABI now carries it (pops_install_native_amr -> add_compiled_model -> set_compiled_block), so a loader regenerated against this header floors the Density-role face states like a native add_block. 0 (default) = inactive, bit-identical.

◆ advance()

void pops::AmrSystem::advance ( double  dt,
int  nsteps 
)

◆ block_level_state()

std::vector< double > pops::AmrSystem::block_level_state ( const std::string &  name,
int  k 
)

◆ block_level_state_global()

std::vector< double > pops::AmrSystem::block_level_state_global ( const std::string &  name,
int  k 
)

np>1 gather (all ranks call)

◆ block_n_vars()

int pops::AmrSystem::block_n_vars ( const std::string &  name)

MULTI-BLOCK per-BLOCK per-level checkpoint accessors (ADC-509).

The AmrRuntime engine shares the layout AND the aux across blocks, so the per-level STATE is read/restored PER BLOCK (by NAME) while phi stays shared (level_potential above). name indexes the block (block_names()); k: level. The _global variant all_reduce_sum the per-rank fabs (np>1 gather, all ranks call); the shared hierarchy is the deterministic frozen central patch (regrid_every==0), reproduced at restart by replaying the same composition -> no set_hierarchy needed.

Exceptions
inMONO-BLOCK (use the level_state path) or if name / k is out of bounds. conserved components of the named block

◆ block_names()

std::vector< std::string > pops::AmrSystem::block_names ( ) const

Names of the blocks in add order (parity with System::block_names): the IO facade iterates over them to write EACH block by its name (an empty name -> block 0, historical mono-block compat).

◆ coarse_local_boxes()

int pops::AmrSystem::coarse_local_boxes ( )

COARSE-level (base) box counts, MPI ownership diagnostic (ADC-319).

coarse_local_boxes() = number of base boxes OWNED by this rank (level-0 MultiFab local_size()); coarse_total_boxes() = total base boxes across all ranks (BoxArray size, identical on every rank). With distribute_coarse=true the base is split into several boxes spread round-robin, so local < total per rank and the coarse transport distributes (MPI strong-scaling); a single-box or replicated base gives local == total on every rank. coarse_local_boxes() is rank-dependent, coarse_total_boxes() is rank-independent. Forces the lazy build (ensure_built) like n_patches()/mass()/density().

◆ coarse_total_boxes()

int pops::AmrSystem::coarse_total_boxes ( )

◆ density() [1/2]

std::vector< double > pops::AmrSystem::density ( )

coarse density of the 1st block (component 0), n*n row-major

◆ density() [2/2]

std::vector< double > pops::AmrSystem::density ( const std::string &  name)

coarse density of the named block, n*n

◆ disable_profiling()

void pops::AmrSystem::disable_profiling ( )

◆ enable_profiling()

void pops::AmrSystem::enable_profiling ( )

◆ is_profiling()

bool pops::AmrSystem::is_profiling ( ) const

◆ last_dt_bound()

std::string pops::AmrSystem::last_dt_bound ( ) const

ACTIVE bound of the last step_cfl: "transport:<block>" | "source_frequency:<block>" | "stability_dt:<block>" | "global:<label>" | "degenerate" | "" (no CFL step yet).

◆ level_potential()

std::vector< double > pops::AmrSystem::level_potential ( int  k)

Potential phi of level k, flat nf*nf row-major.

Level 0 = warm-start of the multigrid (bit-identical resumption); level >= 1 = aux comp 0 (recomputed at update). SHARED -> works in MONO-BLOCK as well as MULTI-BLOCK (single aux). The _global variant gathers under np>1.

◆ level_potential_global()

std::vector< double > pops::AmrSystem::level_potential_global ( int  k)

np>1 gather (all ranks call)

◆ level_state()

std::vector< double > pops::AmrSystem::level_state ( int  k)

FULL conservative state of level k, flat component-major c*nf*nf + j*nf + i (nf = n << k; zeros outside the patches at the fine level – only the patch interior is defined).

MONO-BLOCK.

◆ level_state_global()

std::vector< double > pops::AmrSystem::level_state_global ( int  k)

MONO-BLOCK, np>1 gather (all ranks call)

◆ macro_step()

int pops::AmrSystem::macro_step ( ) const

MACRO-STEP counter (0-indexed; incremented by step / advance / step_cfl), parity with System::macro_step.

Required for checkpoint/restart (the stride / regrid cadence depends on macro_step % stride|regrid_every, not only on t). Prerequisite IO PR-IO-3 (audit 2026-06).

◆ mass() [1/2]

double pops::AmrSystem::mass ( )

mass of the 1st block on the coarse (conserved at reflux)

◆ mass() [2/2]

double pops::AmrSystem::mass ( const std::string &  name)

mass of the named block on the coarse (conserved PER BLOCK)

◆ n_blocks()

int pops::AmrSystem::n_blocks ( ) const

number of blocks (1 = mono-block AmrCouplerMP; >= 2 = AmrRuntime)

◆ n_levels()

int pops::AmrSystem::n_levels ( )

AMR CHECKPOINT / RESTART (ADC-65 single-block single-rank; ADC-509 multi-block + np>1): per-level STATE accessors + hierarchy imposition for a BIT-IDENTICAL resumption (cf.

AmrSystem.checkpoint/restart on the Python side). MONO-BLOCK uses these (level_state / level_potential / set_hierarchy on the AmrCouplerMP coupler); MULTI-BLOCK (AmrRuntime engine, SHARED layout + aux) uses the per-BLOCK variants below (block_level_state ...), plus the SHARED level_potential / n_levels (no set_hierarchy: the shared hierarchy is the deterministic frozen central patch, reproduced by replaying the same composition). The _global variants all_reduce_sum the per-rank fabs so a np>1 checkpoint gathers onto rank 0 (mono-rank: identity, bit-identical). Force the lazy build (ensure_built) like patch_boxes()/mass(). k: level (0 = coarse, >= 1 = fine). number of levels of the hierarchy (>= 1; mono OR multi-block)

◆ n_patches()

int pops::AmrSystem::n_patches ( )

number of current fine patches (of the shared hierarchy)

◆ n_vars()

int pops::AmrSystem::n_vars ( )

number of conserved components (MONO-BLOCK; multi-block: block_n_vars)

◆ named_field_values()

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

Solved potential of named field on the COARSE level, n*n row-major (read-back).

Solves the hierarchy fields if needed (so it is current even before any step), then reads the field's phi component. AMR counterpart of System::aux_field_component for a named elliptic field.

Exceptions
ifthe field is unregistered (or in the single-block AmrCouplerMP path, which carries no named field).

◆ newton_report()

SourceNewtonReport pops::AmrSystem::newton_report ( const std::string &  name)
Exceptions
std::runtime_errorif the block is unknown, in mono-block, on a .so loader, or if the block did not enable newton_diagnostics. Forces the lazy build (ensure_built).

◆ nx()

int pops::AmrSystem::nx ( ) const

◆ operator=() [1/2]

AmrSystem & pops::AmrSystem::operator= ( AmrSystem &&  )
noexcept

◆ operator=() [2/2]

AmrSystem & pops::AmrSystem::operator= ( const AmrSystem )
delete

◆ patch_boxes()

std::vector< PatchBox > pops::AmrSystem::patch_boxes ( )

Index-space signatures of the current fine patches: one PatchBox (level, ilo, jlo, ihi, jhi) per fine box, for ALL fine levels (level >= 1).

INCLUSIVE corners in the index space of the level (n << level cells/direction, ratio 2). SAME source as n_patches() (the GLOBAL fine BoxArray, all boxes/all ranks -> rank-independent, MPI-safe, zero communication). It is a QUERY (between steps): read-only of the already-stored boxes, NO hot-path cost. The conversion to [0, L]^2 is done on the Python side (which knows n via nx() and L). Forces the lazy build (ensure_built) like n_patches()/mass()/density().

◆ potential()

std::vector< double > pops::AmrSystem::potential ( )

Electrostatic potential phi of the COARSE LEVEL (base), n*n row-major.

Level 0 covers the whole domain: enough to sample a median circle (azimuthal FFT), SAME observable as System::potential() on a single-level mesh. Solves the coarse Poisson if needed (cf. System::potential / ensure_elliptic), so current value even before any step. MULTI-BLOCK: phi results from the SYSTEM Poisson (Sum_b q_b n_b co-located); shared by all the blocks (single aux). The block name therefore does not intervene.

◆ profile_report()

std::string pops::AmrSystem::profile_report ( ) const

◆ register_elliptic_field()

POPS_EXPORT void pops::AmrSystem::register_elliptic_field ( const std::string &  field,
int  phi_comp,
int  gx_comp,
int  gy_comp 
)

◆ reset_profiling()

void pops::AmrSystem::reset_profiling ( )

◆ set_aux_field_component()

void pops::AmrSystem::set_aux_field_component ( int  comp,
const std::vector< double > &  field 
)

Sets a model-NAMED aux field (ADC-291) at shared-channel component comp (>= kAuxNamedBase) from a coarse base-level field field (n*n row-major).

AMR counterpart of System::set_aux_field_component: the field is STATIC (re-applied by the engine each update, so it survives a regrid) and reaches every level via the coarse->fine aux injection. Works on the single-block (AmrCouplerMP) AND multi-block (AmrRuntime) paths. The Python facade resolves the name to comp and reshapes the array. Mono-rank facade (same as set_density).

Exceptions
ifthe system is already built, if comp is reserved (< kAuxNamedBase), or if field is not of size n*n.

◆ set_aux_field_halo_component()

void pops::AmrSystem::set_aux_field_halo_component ( int  comp,
int  bc_type,
double  value 
)

Declares a per-field aux HALO policy (ADC-369) for the NAMED component comp (>= kAuxNamedBase): bc_type is pops::BCType (Foextrap=1 / Dirichlet=2), value the Dirichlet boundary value.

Seeded onto the engine at build and applied after the shared coarse aux fill (overriding only that component's physical-face ghosts; periodic faces keep their wrap). AMR counterpart of System::set_aux_field_halo_component.

Exceptions
ona reserved component or an unsupported type.

◆ set_block_elliptic_field()

POPS_EXPORT void pops::AmrSystem::set_block_elliptic_field ( const std::string &  block_name,
const std::string &  field,
std::function< void(const MultiFab &, MultiFab &)>  rhs 
)

Attaches named field's RHS closure (rhs += elliptic_field_rhs(U)) to block block_name.

Called by the native AMR loader (make_poisson_rhs of the per-field brick).

Exceptions
ifthe system is already built or the block is unknown.

◆ set_block_level_state()

void pops::AmrSystem::set_block_level_state ( const std::string &  name,
int  k,
const std::vector< double > &  s 
)

◆ set_clock()

void pops::AmrSystem::set_clock ( double  t,
int  macro_step 
)

RESTORES the AMR clock (t, macro_step) – parity with System::set_clock.

Sets the time AND the macro-step counter (propagated to the regrid/stride cadence of the engine, mono-block as well as multi-block). Useful alone (stride cadence + clock resumption).

Exceptions
ifmacro_step < 0.

◆ set_compiled_block()

POPS_EXPORT void pops::AmrSystem::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).

TWO type-erased builders are frozen here, for the TWO routings of the facade:

  • mono_builder: given the AmrBuildParams frozen at lazy build, returns the AmrCompiledHooks of a concrete AmrCouplerMP<Model>. Used IN MONO-BLOCK (1 single compiled block) -> historical AmrCouplerMP path, UNTOUCHED, bit-identical.
  • multi_builder: given the SHARED layout materialized at lazy build (common to all blocks), returns the type-erased AmrRuntimeBlock of the block. Used IN MULTI-BLOCK (>= 2 blocks, compiled and/or native mixed) -> AmrRuntime runtime engine, exactly like add_block. recon_prim / imex / stride / implicit_vars / implicit_roles: metadata of the block (temporal scheme, multirate, partial IMEX mask) frozen at add time, consumed by the multi-block routing (the mono-block already carries them in the AmrBuildParams via mono_builder). DO NOT call directly: go through the free function add_compiled_model(AmrSystem&, ...).
    Exceptions
    std::runtime_errorif the system is already built. DEFAULT VISIBILITY (POPS_EXPORT): the ONLY method called by the header template add_compiled_model(AmrSystem&) (cf. amr_dsl_block.hpp). A generated .so loader (DSL "production" path on the AMR side, emit_cpp_native_loader(target="amr_system") / add_native_block) inlines this template and must resolve this symbol from the already-loaded _pops module; compiled with -fvisibility=hidden (pybind11), the module would not export it without this annotation and the dlopen of the loader would fail. Symmetric with the POPS_EXPORT methods of System (grid_context/install_block).

◆ set_conservative_state()

void pops::AmrSystem::set_conservative_state ( const std::string &  name,
const std::vector< double > &  U 
)

Sets the FULL INITIAL CONSERVATIVE STATE (all components) on the coarse level, then prolongs it to the fine levels at build (constant injection, like the density).

U is flat component-major (c*n*n + j*n + i) of size ncomp*n*n; ncomp == n_vars of the model (checked at build, where only Model::n_vars is known). Takes priority over set_density: allows starting the AMR from a full drift state (rho, rho*u, rho*v) instead of m=0. The conversion primitive -> conservative (rho_u = rho*u) is done on the Python side (the caller already supplies the conservative). Wired on the NATIVE blocks (mono-block as well as multi-block: threaded to the native builder, seed the coarse then inject to the fine); in multi-block name indexes the target block. A COMPILED (.so) block carrying a state raises at build in multi-block (the .so loader does not transport the state): use a native block pops.Model(...) or set_density.

Exceptions
std::runtime_errorif the system is already built, if U is empty, or if its size is not a multiple of n*n.

◆ set_density()

void pops::AmrSystem::set_density ( const std::string &  name,
const std::vector< double > &  rho 
)

Sets the initial density on the coarse level (component 0), n*n row-major.

Parameters
namecosmetic label (mono-block AMR: the density targets the single block).

◆ set_hierarchy()

void pops::AmrSystem::set_hierarchy ( const std::vector< PatchBox > &  boxes)

Imposes the SAVED fine hierarchy (at restart) instead of Berger-Rigoutsos clustering: boxes are the patch_boxes() signatures of the checkpoint (filtered to level 1 in mono-block).

MONO-BLOCK.

◆ set_level_potential()

void pops::AmrSystem::set_level_potential ( int  k,
const std::vector< double > &  p 
)

restores phi of level k

◆ set_level_state()

void pops::AmrSystem::set_level_state ( int  k,
const std::vector< double > &  s 
)

restores the state of level k (as is)

◆ set_magnetic_field()

void pops::AmrSystem::set_magnetic_field ( const std::vector< double > &  bz)

Sets the magnetic field B_z(x, y) of the coarse level (n*n row-major), required by the Schur-condensed source stage (Lorentz term Omega = B_z).

AMR counterpart of System::set_magnetic_field. MONO-BLOCK only (the condensed AMR stage is wired on the mono-block coupler AmrCouplerMP).

Exceptions
std::runtime_errorif the system is already built or if bz is not of size n*n.

◆ set_phi_refinement()

void pops::AmrSystem::set_phi_refinement ( double  grad_threshold)

Adds to the regrid criterion the PHI tag on |grad phi| (D4 of the design docs/AMR_REGRID_UNION_TAGS_DESIGN.md): also refines the cells where the norm of the gradient of the electrostatic potential |grad phi| (components 1,2 of the shared aux) exceeds grad_threshold.

MULTI-BLOCK only (the AmrRuntime runtime engine carries the union-of-tags regrid; the mono-block path AmrCouplerMP has no separate phi predicate). The phi tag is ADDED to the union of the density tags per block (set_refinement): the mesh refines where ANY block exceeds its density threshold OR |grad phi| exceeds grad_threshold. PHYSICAL criterion: a sharp ring/edge feature follows the gradient of the potential, not the density alone.

Parameters
grad_thresholdthreshold of |grad phi|. <= 0 (DEFAULT) -> the phi tag is DISABLED (phi does not contribute to the union; bit-identical to before this call). Without regrid_every > 0, no effect (the regrid is never called). To be called BEFORE the first step.

◆ set_poisson()

void pops::AmrSystem::set_poisson ( const std::string &  rhs = "charge_density",
const std::string &  solver = "geometric_mg",
const std::string &  bc = "auto",
const std::string &  wall = "none",
double  wall_radius = 0.0 
)

Configures the coarse Poisson (cf.

System::set_poisson). On AMR the elliptic solver is ALWAYS GeometricMG and the right-hand side ALWAYS f = sum of the block's elliptic bricks.

Parameters
rhs"charge_density" | "composite" (same composed right-hand side as System)
solver"geometric_mg" only (the only one wired on the hierarchy; no FFT)
bc"auto" | "periodic" | "dirichlet" | "neumann"
wall"none" | "circle" (circular conductive wall, requires wall_radius > 0)
Exceptions
std::runtime_errorif rhs, solver, bc or wall is outside the supported domain.

◆ set_refinement()

void pops::AmrSystem::set_refinement ( double  threshold,
const std::string &  variable = std::string(),
const std::string &  role = std::string() 
)

Refines the cells where the SELECTED conserved variable exceeds threshold.

By default the variable is component 0 (historically the density), preserving the bit-identical 1e30 no-op. Optionally the variable is selected PER BLOCK by NAME (variable, e.g. "E") or by physical ROLE (role, e.g. "energy"): each block resolves it against its OWN conservative VariableSet, so a model whose refinement variable is NOT at component 0 refines correctly (ADC-296). Resolution is STRICT – a block lacking the requested name/role raises an explicit error at build, never a silent fallback to component 0 (mirror of add_coupled_source). At most one of variable / role may be set. MULTI-BLOCK only for a non-default selector (the AmrRuntime union-of-tags regrid carries the per-block predicates); the mono-block AmrCouplerMP path and the compiled .so loader refine on component 0 only and reject a non-empty selector, mirroring how set_phi_refinement is multi-block only.

Parameters
thresholdrefinement threshold (1e30 default elsewhere => no refinement, frozen).
variableconserved-variable NAME to threshold; empty (default) => component 0.
roleconserved-variable physical ROLE to threshold; empty (default) => component 0.

◆ set_source_stage()

void pops::AmrSystem::set_source_stage ( const std::string &  name,
const std::string &  kind,
double  theta,
double  alpha,
const SourceStageOptions opts = {} 
)

Enables the Schur-CONDENSED SOURCE STAGE (amr-schur path) on block name.

AMR counterpart of System::set_source_stage: assembles and solves the GLOBAL electrostatic/Lorentz condensed operator (on the coarse, by composing the uniform stage #126), instead of the LOCAL cell-by-cell IMEX source. This is the OPT-IN of the amr-schur path, the refined equivalent of the uniform time=Strang(Explicit(ssprk3), CondensedSchur(theta, alpha)). The block transport must be SOURCE-FREE (model with NoSource source brick): the source is played separately by the stage.

Parameters
kindonly "electrostatic_lorentz" wired (cf. CondensedSchurSourceStepper).
thetatheta-scheme in (0, 1] (0.5 = Crank-Nicolson).
alphaelectrostatic coupling constant.
Exceptions
std::runtime_errorif the system is already built, in MULTI-BLOCK, if kind/theta are out of domain, or (at build) if the block does not expose Density/MomentumX/MomentumY or if set_magnetic_field was not called.
Parameters
optssettings grouped in a POD (ADC-214; cf. SourceStageOptions; parity with System::set_source_stage): krylov_tol / krylov_max_iters (COARSE Krylov solve; <= 0 = historical defaults 1e-10 / 400; the FAC composite solve keeps its own tolerances, Phase 4) and descriptors density / momentum_x / momentum_y / energy ("" = canonical role, bit-identical; otherwise stable role name or block variable name, resolved at build). The POD's bz_aux_component field is IGNORED here (the mono-block AMR stage reads the canonical B_z channel). Default {} = historical behavior.

◆ set_time_scheme()

void pops::AmrSystem::set_time_scheme ( const std::string &  scheme)

Chooses the time-splitting policy of the condensed source stage: "lie" (default, H(dt) S(dt)) or "strang" (H(dt/2) S(dt) H(dt/2), 2nd order).

AMR counterpart of System::set_time_scheme. Without a condensed source stage (set_source_stage not called), no effect.

Exceptions
ifscheme unknown / already built.

◆ step()

void pops::AmrSystem::step ( double  dt)

one AMR macro-step (periodic regrid included)

◆ step_cfl()

double pops::AmrSystem::step_cfl ( double  cfl)

Advances at dt = cfl * coarse_dx / max wave speed.

Returns
the dt used.

◆ time()

double pops::AmrSystem::time ( ) const

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