Appearance
adam_forest_object
ADAM, forest class definition — orchestrator of a forest of realms.
The forest tends an array of realms (realm_object extensions, e.g. prism_cpu_object, prism_fnl_object). It is a behavior-only class: it owns no derived-type state. Each realm lives in the program driver as a concrete monomorphic array (type(prism_cpu_object) :: realm(N)); the forest receives the array as class(realm_object), intent(inout) :: realm(:) and orchestrates inter-realm operations:
- sequence per-realm initialize / finalize calls
- reduce per-realm dt to a global dt (min reduction)
- iterate per-realm timestep advance
- iterate per-realm post-step diagnostics / IO
- reduce per-realm termination predicate to a global done (AND reduction)
The forest NEVER reaches inside a realm's private state; it only invokes the realm-side TBPs that carry the _forest suffix. Together these TBPs form the orchestrator contract (see adam_realm_object).
Class-with-TBPs (not module-of-routines) so future forest-level configuration (MPI sub-communicator topology, inter-realm connectivity descriptor) can be added as intrinsic-typed state without a module API break.
See docs/guide/forest.md for the conceptual overview of the multi-realm machinery (manifest schema, α/β cadence trade-offs, phase cycle) and src/lib/common/README.md → "Forest orchestration" for the library-developer contract surface.
Source: src/lib/common/adam_forest_object.F90
Dependencies
Contents
- forest_object
- seam_rows_t
- initialize
- initialize_from_manifest
- finalize
- compute_global_dt
- evolve_one_step
- is_done
- post_step
- regrid
- simulate
- simulate_from_manifest
- start_timing
- report_timing
- check_runtime_amr
- check_beta_admissibility
- populate_inter_realm_topology
- check_couplings
- seam_sides
- check_nested
- build_seam_rows
- enumerate_seam_side
- store_seam_rows
- group_rows
- realm_face_leaves
- push_row
- leaf_metrics
- ghost_slab_extents
- wrap_periodic_tangential
- register_intra_realm_amr_seams
- apply_reflux_corrections
- share_flux_register
- seam_cell_size
- size_pairs
- leaf_on_realm_face
- inside_domain
- ghost_label
Derived Types
forest_object
Behavior-only orchestrator of an array of realms.
Components
| Name | Type | Attributes | Description |
|---|---|---|---|
n | integer(kind=I4P) | Number of realms in the forest (set by initialize from size(realm)). | |
flux_register | type(flux_register_object) | Coarse-fine interface reflux machinery. | |
timing | logical | ||
wtime | real(kind=R8P) |
Type-Bound Procedures
| Name | Attributes | Description |
|---|---|---|
initialize | pass(self) | Sequence each realm's initialize_forest at startup (single shared INI). |
initialize_from_manifest | pass(self) | Like initialize, but each realm reads its own INI from a forest manifest. |
finalize | pass(self) | Sequence each realm's finalize_forest at shutdown. |
compute_global_dt | pass(self) | Min-reduce each realm's compute_local_dt_forest across the forest. |
evolve_one_step | pass(self) | Iterate realm(😃%advance_one_step_forest(dt) for one global timestep. |
is_done | pass(self) | AND-reduce each realm's is_done_forest across the forest. |
post_step | pass(self) | Iterate realm(😃%post_step_forest for the per-step diagnostics/IO block. |
regrid | pass(self) | Iterate realm(😃%regrid_forest, rebuild the register on a change (#74). |
simulate | pass(self) | Main entry point (single shared INI): drive the full simulation. |
simulate_from_manifest | pass(self) | Main entry point (per-realm INIs via forest manifest). |
populate_inter_realm_topology | pass(self) | Translate manifest face-pairs into maps of neighbors. |
register_intra_realm_amr_seams | pass(self) | Register intra-realm AMR coarse-fine faces in the flux |
apply_reflux_corrections | pass(self) | Apply Berger-Colella reflux to coarse-side. |
share_flux_register | pass(self) | Copy the register into every realm (#68 A2). |
start_timing | pass(self) | Arm the timing report (issue #53). |
report_timing | pass(self) | Print the timing report (issue #53). |
seam_rows_t
Growable list of integer rows, used while the seam rows are enumerated.
Components
| Name | Type | Attributes | Description |
|---|---|---|---|
row | integer(kind=I4P) | allocatable | Rows (n, columns). |
n | integer(kind=I4P) | Rows in use. |
Subroutines
initialize
Initialize the forest and every realm it tends.
fortran
subroutine initialize(self, realm, filename)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
self | class(forest_object) | inout | The forest. | |
realm | class(realm_object) | inout | The realms to initialize. | |
filename | character(len=*) | in | Input parameters file name (shared across realms for v1). |
Call graph
initialize_from_manifest
Initialize the forest and every realm using per-realm INIs from a manifest.
Like initialize but each realm receives its OWN INI path (manifest%realm_ini(is)) instead of a shared filename. After all realms are initialized, translates the manifest's face-pair list into per-realm maps%inter_realm_neighbors entries.
The driver MUST allocate realm(size = manifest%realms_number) with the concrete app type before calling this — the forest does not !< allocate the realm array (it cannot, since realm_object is abstract and each app has its own extension).
fortran
subroutine initialize_from_manifest(self, realm, manifest)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
self | class(forest_object) | inout | The forest. | |
realm | class(realm_object) | inout | The realms to initialize. | |
manifest | type(forest_manifest_t) | in | Parsed manifest (per-realm INI paths + topology). |
Call graph
finalize
Shut down the forest and every realm it tends.
Iterates realm(is)%finalize_forest in increasing index order; each realm closes its IO files, releases its resources, and finalizes its MPI handler.
fortran
subroutine finalize(self, realm)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
self | class(forest_object) | in | The forest. | |
realm | class(realm_object) | inout | The realms to shut down. |
Call graph
compute_global_dt
Compute the forest-global stability-limited dt.
Each realm reports its local dt via compute_local_dt_forest; the forest takes the min across all realms (intra-process) and then across all MPI ranks (MPI_ALLREDUCE on MPI_COMM_WORLD). Returns the bit-identical global min every rank should advance by.
fortran
subroutine compute_global_dt(self, realm, dt)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
self | class(forest_object) | in | The forest. | |
realm | class(realm_object) | inout | The realms to query. | |
dt | real(kind=R8P) | out | Global stability-limited dt. |
Call graph
evolve_one_step
Advance every realm by one global timestep — α end-of-step barrier semantics.
N=1 fast path: realm owns the whole step (advance_one_step_forest). No seam machinery is exercised (there are no peer seams to refresh).
N>1 multi-realm path: per-seam coupling cadence (α / β).
The forest drives an integrator-agnostic K-stage clock with K_realm(is) = realm(is)%stages_per_step_forest() and K_max = max(K_realm). Asymmetric per-realm K is a first-class operating mode under α; the per-stage TBPs (begin/end_stage_forest) are gated behind k <= K_realm(is) so a realm with K < K_max no-ops the trailing stages.
Each inter-realm seam carries a coupling_cadence from the manifest (cached on the realm as seam_local_cadence(p)):
α (CADENCE_END_OF_STEP, default; AMReX-aligned coarse-fine convention) Mid-step peer ghosts are INTENTIONALLY STALE-BY-ONE-STEP. During stages 1..K, each realm reads the peer ghosts established by the previous end-of-step exchange (or by the initial-condition seam fill at populate_inter_realm_topology time, for the first step). This is structurally identical to AMReX's FillCoarsePatch reading coarse t^n data during fine sub-steps (Berger-Oliger 1984; AMReX_Amr.cpp::timeStep). Phase 5 (below) is the α seam coherence boundary: once per step, after close_step_forest, every realm's stage_active == 0 and the receiver reads peer's committed q. α admits asymmetric per-realm K (the K-equality guard is removed). Cost: first-order seam coupling in time.
β (CADENCE_STAGE_COINCIDENT, opt-in) Peer ghosts are refreshed once per RK substage, inside the K loop (Phase 2 below), before end_stage_forest reads them. Admissible only when both endpoint realms agree on (scheme_time, rk_scheme, nv, K) — enforced at forest init by check_beta_admissibility. Recovers bit-equivalence to a monolithic single-realm run on the union grid when admissible. Seam coupling order matches the per-realm interior order. Spatial operator MAY differ per realm.
Per-seam selection: the same forest may carry α seams and β seams simultaneously. Phase 2 iterates seams and fires only for β; Phase 5 iterates seams and fires only for α. A seam is filled exactly once per step under either cadence (Phase 2 may fire K times for β, but at successive substages, never duplicating the same substage).
Reflux cadence (α.r1):
The flux register's third axis is collapsed to 1. PRISM realms gate apply_reflux_to_stage_forest and accumulate_seam_fluxes_fv on the realm's own final RK substage (stage == rk%nrk). Earlier substages no-op. The mid-step apply_reflux_corrections call below therefore fires for every k, but only the k == K_realm(is) invocation does real work on realm is. Independent of α/β: β does not restore Wang 2018 per-stage RK-weighted reflux (deferred).
Phase outline:
Phase 0 — open_step_forest (per-realm prologue) For k = 1..K_max: Phase 1 — begin_stage_forest (per-realm, gated by k <= K_realm(is)) Phase 2 — fill_seam_from_peer_forest (per-seam, β-gated) Phase 3 — end_stage_forest (per-realm, gated by k <= K_realm(is)) + reduce_fine_sums + apply_reflux_corrections (reflux body is α.r1 end-of-step gated inside the realm) Phase 4 — close_step_forest (per-realm epilogue) Phase 5 — fill_seam_from_peer_forest (per-seam, α-gated)
LOAD-BEARING INVARIANT (β): Phase 2 must complete on ALL realms before Phase 3 starts on ANY realm. The orchestrator's serial inner loops within a rank give this for free under the Phase-A replicated-forest layout. If a future refactor interleaves Phase 2 and Phase 3, the read-after-overwrite race returns.
Future per-realm-dt subcycling (Berger-Colella "case 4") and γ (dense-output peer reads) are deferred. β with asymmetric K would require γ-class interpolation; not in scope.
fortran
subroutine evolve_one_step(self, realm)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
self | class(forest_object) | inout | The forest. | |
realm | class(realm_object) | inout | target | The realms to advance. |
Call graph
is_done
Decide whether the whole forest has finished evolving.
Each realm reports its local predicate via is_done_forest; the forest AND-reduces across all realms (intra-process) and then across all MPI ranks (MPI_ALLREDUCE on MPI_COMM_WORLD). AND-reduction means the forest keeps evolving as long as ANY realm wants to — matching the legacy single-realm semantics for v1 (with one realm the global predicate equals that realm's local one).
fortran
subroutine is_done(self, realm, done)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
self | class(forest_object) | in | The forest. | |
realm | class(realm_object) | inout | The realms to query. | |
done | logical | out | Forest-global termination predicate. |
Call graph
post_step
Run every realm's post-step diagnostics / IO / AMR block.
fortran
subroutine post_step(self, realm)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
self | class(forest_object) | in | The forest. | |
realm | class(realm_object) | inout | The realms to query. |
Call graph
regrid
Let every realm regrid if its cadence asks for it now, then rebuild what the forest owns (issue #74, M5).
Runs after the step closes and before post_step, on committed q (no stage active): the fields, histories and restart files post_step saves then describe the grid the next step runs on, so a run restarted at a regrid step continues exactly as the uninterrupted one (saved before the regrid, the restart held the old grid and the restarted run diverged from the regrid step on). A realm that regrids changes its tree, so the intra-realm 2:1 faces of the flux register (and the per-block register index the positivity seam sync and the div(B) seam band read) describe the old grid: the register is rebuilt from the new trees. Runtime regridding is single-realm (refused on a multi-realm forest at initialisation, check_runtime_amr), so no inter-realm seam row or register face needs rebuilding. The fused fast path is chosen per step from flux_register%nfaces, so a run that gains or loses 2:1 faces switches path with the rebuilt register.
fortran
subroutine regrid(self, realm)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
self | class(forest_object) | inout | The forest. | |
realm | class(realm_object) | inout | The realms. |
Call graph
simulate
Drive the full simulation: initialize, time-loop, finalize.
Top-level entry point the program driver calls. The time loop is: initialize → loop {evolve_one_step → post_step → is_done} → finalize. Each step invokes the orchestrator-contract TBPs on every realm; the per-realm body decides what app-specific work to do internally.
fortran
subroutine simulate(self, realm, filename)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
self | class(forest_object) | inout | The forest. | |
realm | class(realm_object) | inout | The realms to evolve. | |
filename | character(len=*) | in | Input parameters file name. |
Call graph
simulate_from_manifest
Drive the full simulation using per-realm INIs from a manifest.
Like simulate but uses initialize_from_manifest to populate each realm from its own INI file, and (via that initialize) wires the inter-realm topology from the manifest. The time-loop body is identical to simulate.
fortran
subroutine simulate_from_manifest(self, realm, manifest)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
self | class(forest_object) | inout | The forest. | |
realm | class(realm_object) | inout | The realms to evolve. | |
manifest | type(forest_manifest_t) | in | Parsed manifest. |
Call graph
start_timing
Arm the timing report when the environment sets ADAM_SEAM_TIMING=1 (issue #53): the forest times its loop, steps and reflux, every realm the phases of the seam fills of its ghosts. Off by default, the output unchanged.
fortran
subroutine start_timing(self, realm)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
self | class(forest_object) | inout | The forest. | |
realm | class(realm_object) | inout | The realms. |
Call graph
report_timing
Print the timing report (issue #53): the maximum over the ranks of the forest timers and, per realm, of the seam fill phases (local copy, buffers, pack, MPI, unpack) and of their sum; fills and rows summed over the ranks.
fortran
subroutine report_timing(self, realm)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
self | class(forest_object) | in | The forest. | |
realm | class(realm_object) | in | The realms. |
Call graph
check_runtime_amr
Refuse runtime regridding on a multi-realm forest (issue #74, D-M5-4).
The inter-realm topology (seam rows, BC_SEAM crown overrides, inter-realm register faces) is built once, at initialisation; a realm that regrids would leave it describing the old grid, silently. Until it is rebuilt per regrid, a realm that regrids must be the only one.
fortran
subroutine check_runtime_amr(realm)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
realm | class(realm_object) | in | Initialized realms. |
Call graph
check_beta_admissibility
Enforce β admissibility contract on every stage_coincident seam.
For each manifest face-pair with coupling_cadence == CADENCE_STAGE_COINCIDENT, query both endpoint realms' coupling_descriptor_forest and verify they agree on (scheme_time, rk_scheme, nv). On any mismatch error_stop with a precise diagnostic naming the offending pair and the specific descriptor field that disagrees. Per-realm K participation (stages_per_step_forest()) is verified too: under β both endpoints must report the same K (asymmetric-K is α's domain, not β's).
Runs once at initialize_from_manifest time, after every realm's initialize_forest has populated numerics, rk, physics.
fortran
subroutine check_beta_admissibility(realm, manifest)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
realm | class(realm_object) | inout | The initialized realms. | |
manifest | type(forest_manifest_t) | in | Parsed manifest. |
Call graph
populate_inter_realm_topology
Translate manifest face-pairs into per-realm maps%inter_realm_neighbors.
Each manifest face-pair becomes TWO entries — one in realm_a's adam%maps%inter_realm_neighbors (looking outward toward realm_b) and one in realm_b's (looking back). Both entries carry the SAME coupling kind. Block indices are NOT resolved at this stage; the manifest declares realm-level coupling (which realm-face touches which realm-face), and the realm-side override of exchange_inter_realm_halos_forest is responsible for enumerating per-block face cells at exchange time. This keeps the manifest small and avoids encoding block layouts that depend on AMR / decomposition state not known at INI parse time.
fortran
subroutine populate_inter_realm_topology(self, realm, manifest)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
self | class(forest_object) | inout | The forest. | |
realm | class(realm_object) | inout | Initialized realms whose adam%maps gets populated. | |
manifest | type(forest_manifest_t) | in | Parsed manifest. |
Call graph
check_couplings
Validate the coupling of every manifest face pair against the realm geometry (issue #52); error_stop otherwise.
Walks the seam leaves of both sides on the replicated trees (the same result on every rank):
mirror: one cell size on each side's seam face, equal across the seam;refined: one cell size per side with ratio exactly 2 (either side may be the coarse one), equal block cell counts along the seam, the same[amr] seam_ghost_fill, and nested blocks: every fine seam leaf covers one 2:1 quadrant of the face of one coarse seam leaf, and even block cell counts in the fine realm;periodic,interpolate: schema-reserved, refused (before issue #52 they were accepted and run asmirror).
fortran
subroutine check_couplings(realm, manifest)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
realm | class(realm_object) | inout | Forest realms. | |
manifest | type(forest_manifest_t) | in | Parsed manifest. |
Call graph
seam_sides
The coarse and fine sides of a face pair: for a refined seam the realm with the larger seam cells is the coarse side (issue #52), for a mirror seam realm_a by convention.
fortran
subroutine seam_sides(realm, pair, rc, fc, rf, ff, refined)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
realm | class(realm_object) | in | Forest realms. | |
pair | type(forest_face_pair_t) | in | Face pair. | |
rc | integer(kind=I4P) | out | Coarse-side realm and face. | |
fc | integer(kind=I4P) | out | Coarse-side realm and face. | |
rf | integer(kind=I4P) | out | Fine-side realm and face. | |
ff | integer(kind=I4P) | out | Fine-side realm and face. | |
refined | logical | out | 2:1 seam. |
Call graph
check_nested
Every fine seam leaf must cover one 2:1 quadrant of the seam face of one coarse leaf: half its tangential extent, starting at its origin or at its midpoint along each tangential axis.
fortran
subroutine check_nested(coarse, fine, face_f, pfx)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
coarse | class(realm_object) | inout | Coarse realm. | |
fine | class(realm_object) | inout | Fine realm. | |
face_f | integer(kind=I4P) | in | Fine seam face. | |
pfx | character(len=*) | in | Error message prefix. |
Call graph
build_seam_rows
Build the seam ghost rows of every realm from the replicated trees (issue #40).
Every rank walks, for every face pair (side A then side B), every leaf of the realm owning the ghosts that lies on the seam face, owned or not, and every ghost of its slab (tangential edge and corner ghosts included), in the tree's own order: the same sequence on every rank. The peer cell is the interior cell of the leaf of the peer realm containing the ghost centre (get_closest_block on the peer's replicated tree); ghosts outside the peer domain are corners where the seam meets a physical boundary and are left to the physical BC. Each rank keeps the rows it takes part in:
- local (ghost and cell here):
[peer, b_cell, b_ghost, i_cell, j_cell, k_cell, i_ghost, j_ghost, k_ghost]; - receive (ghost here, cell on rank r):
[r, b_ghost, i_ghost, j_ghost, k_ghost]on the ghost realm; - send (cell here, ghost on rank r):
[r, b_cell, i_cell, j_cell, k_cell]on the cell realm.
Since the order is shared, the rows rank A sends to rank B for a seam are, in order, the rows B receives from A. The peer cell centre must coincide with the ghost centre: mirror seams join cells of the same size.
fortran
subroutine build_seam_rows(realm, manifest)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
realm | class(realm_object) | inout | Forest realms. | |
manifest | type(forest_manifest_t) | in | Parsed manifest. |
Call graph
enumerate_seam_side
Enumerate the seam ghosts of realm is on face, whose peer is realm ip; append this rank's rows.
fortran
subroutine enumerate_seam_side(realm, is, ip, face, local, recv, send)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
realm | class(realm_object) | inout | Forest realms. | |
is | integer(kind=I4P) | in | Realm owning the ghosts. | |
ip | integer(kind=I4P) | in | Realm owning the cells. | |
face | integer(kind=I4P) | in | Seam face of realm is (FACE_* code). | |
local | type(seam_rows_t) | inout | Local rows of realm is. | |
recv | type(seam_rows_t) | inout | Receive rows of realm is. | |
send | type(seam_rows_t) | inout | Send rows of realm ip. |
Call graph
store_seam_rows
Store the enumerated seam rows of realm is into its maps, grouped by peer slot (and by rank inside a slot).
fortran
subroutine store_seam_rows(realm, is, manifest, local, recv, send)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
realm | class(realm_object) | inout | Realm is. | |
is | integer(kind=I4P) | in | Realm index. | |
manifest | type(forest_manifest_t) | in | Parsed manifest. | |
local | type(seam_rows_t) | in | Local rows (col 1 = peer realm). | |
recv | type(seam_rows_t) | in | Receive rows (col 1 = peer realm). | |
send | type(seam_rows_t) | in | Send rows (col 1 = ghost realm). |
Call graph
group_rows
Group cross-rank rows [peer, rank, b, i, j, k, ...] by peer slot and, inside a slot, by ascending rank, keeping the enumeration order within a rank; store them without the peer column ([rank, b, i, j, k], plus kind, meta for send rows).
fortran
subroutine group_rows(rows, peers, cell, row_start, row_count)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
rows | type(seam_rows_t) | in | Enumerated rows. | |
peers | integer(kind=I4P) | in | Peer realm of each slot. | |
cell | integer(kind=I4P) | out | allocatable | Grouped rows. |
row_start | integer(kind=I4P) | out | allocatable | First row of each slot. |
row_count | integer(kind=I4P) | out | allocatable | Rows of each slot. |
Call graph
realm_face_leaves
Morton codes of the leaves of a realm that lie on one face of its domain, in tree order (issue #51).
fortran
subroutine realm_face_leaves(this_realm, face, codes)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
this_realm | class(realm_object) | in | Realm. | |
face | integer(kind=I4P) | in | Face code (FACE_X_MIN..FACE_Z_MAX). | |
codes | integer(kind=I8P) | out | allocatable | Leaves on the face. |
Call graph
push_row
Append a row to a growable row list (the capacity doubles when full).
fortran
subroutine push_row(list, row)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
list | type(seam_rows_t) | inout | Row list. | |
row | integer(kind=I4P) | in | Row to append. |
Call graph
leaf_metrics
Origin, cell size and (optionally) upper corner of the leaf code of a realm, from its tree and grid (valid on every rank, whichever rank owns the leaf).
fortran
subroutine leaf_metrics(this_realm, code, emin, dxyz, emax)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
this_realm | class(realm_object) | in | Realm. | |
code | integer(kind=I8P) | in | Leaf Morton code. | |
emin | real(kind=R8P) | out | Leaf origin. | |
dxyz | real(kind=R8P) | out | Cell size. | |
emax | real(kind=R8P) | out | optional | Leaf upper corner. |
Call graph
ghost_slab_extents
The (i, j, k) bounds of a block's ghost slab on one face: ngc cells deep on the (axis, sgn) face, the two tangential axes over the full ghost-extended range [1-ngc, n+ngc] (edge and corner ghosts included).
Attributes: pure
fortran
subroutine ghost_slab_extents(this_realm, axis, sgn, imin_g, imax_g, jmin_g, jmax_g, kmin_g, kmax_g)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
this_realm | class(realm_object) | in | Realm. | |
axis | integer(kind=I4P) | in | Face axis and side. | |
sgn | integer(kind=I4P) | in | Face axis and side. | |
imin_g | integer(kind=I4P) | out | Slab bounds. | |
imax_g | integer(kind=I4P) | out | Slab bounds. | |
jmin_g | integer(kind=I4P) | out | Slab bounds. | |
jmax_g | integer(kind=I4P) | out | Slab bounds. | |
kmin_g | integer(kind=I4P) | out | Slab bounds. | |
kmax_g | integer(kind=I4P) | out | Slab bounds. |
Call graph
wrap_periodic_tangential
Wrap a seam ghost centre into the peer domain along every tangential axis periodic on both realms (issue #65 P4).
The edge and corner ghosts of a seam slab past a tangential boundary of the ghost realm lie outside the peer domain too. At a physical boundary they are the BC's; at a periodic one no BC fills them (the realm's own maps have no neighbour across the seam), and they kept their initial values, read by every stencil with tangential reach (the dissipative fluxes: NaN at the first step of a mirror split periodic in y). Their peer is the cell one period away, which the wrap makes get_closest_block find. Both realms span the same tangential extent at a mirror or refined seam (the faces cover each other), so the period is the peer's domain length.
Attributes: pure
fortran
subroutine wrap_periodic_tangential(realm_g, realm_c, axis, xg)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
realm_g | class(realm_object) | in | Realm owning the ghost. | |
realm_c | class(realm_object) | in | Realm owning the cells. | |
axis | integer(kind=I4P) | in | Seam normal axis. | |
xg | real(kind=R8P) | inout | Ghost centre. |
Call graph
register_intra_realm_amr_seams
Register every intra-realm AMR coarse-fine face in the forest flux register.
Walks each realm's tree node neighborhood (already built by make_neighborhood at realm init) and, for every block whose face neighbor is MORE refined (NODE_MORE_REFINED — this block is the COARSE side of a 2:1 jump), adds one register entry. The fine-side blocks (the ratio/2 finer neighbors covering that coarse face) are recorded in fine_block(:).
Only the 6 faces (fec = 1..6) are registered — reflux is a face-flux correction; edge/corner adjacencies (fec = 7..26) carry no conserved face flux and are skipped.
Two-pass, mirroring register_inter_realm_seams:
- Pass 1 counts coarse-side faces across all realms → register size.
- Pass 2 calls
register_face(seam_kind = SEAM_KIND_INTRA_REALM_AMR, ...)and fills the signedinter_realm_face_register_indexlookup:+cursoron the coarse (block, bc_fec),-cursoron each fine neighbor block's opposite face. For intra-realm jumps coarse and fine are the SAME realm, socoarse_realm = fine_realm = is.
Register ownership. This routine is the sole initializer of the flux register: it calls flux_register%initialize with the intra-realm face count (possibly 0, which still flips the register's is_initialized_ so the per-step reset/reflux hooks are safe no-ops) plus extra_faces.
Composition with inter-realm seams (issue #37). The manifest path calls it first with extra_faces = the inter-realm seam face count, then register_inter_realm_seams appends those faces after the nfaces_intra intra-realm ones. Both lists are walked on the replicated trees (issue #40), so every rank holds the same faces under the same cursors, which is what the register's cross-rank reduction of the fine sums relies on.
fortran
subroutine register_intra_realm_amr_seams(self, realm, extra_faces, nfaces_intra)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
self | class(forest_object) | inout | The forest. | |
realm | class(realm_object) | inout | Initialized realms whose trees are walked. | |
extra_faces | integer(kind=I4P) | in | optional | Register slots reserved for inter-realm faces. |
nfaces_intra | integer(kind=I4P) | out | optional | Intra-realm AMR faces registered (cursors 1..n). |
Call graph
apply_reflux_corrections
Dispatch the Berger-Colella reflux correction to every realm.
Called once per step AFTER close_step_forest's update_q. The forest's role is purely orchestration: it iterates the realm array and invokes each realm's apply_reflux_to_stage_forest TBP, passing that realm's OWN final stage (stages_per_step_forest()) so the realm-side end-of-step gate (stage == self%rk%nrk) fires for every realm, asymmetric-K included. The realm-side body filters flux_register%face(:) by face%coarse_realm == self%realm_index and adds the per-cell end-of-step correction directly into its committed self%q (full dt/dx weight, no stage RK coefficient — AMReX Berger-Colella cadence).
The forest never reaches realm%rk/realm%q directly: the per-cell write lives realm-side. This is the integrator-agnostic split — see realm_object%apply_reflux_to_stage_forest for the contract, and prism_cpu_object for the RK-specific override.
Empty register fast path: when the register has no faces the per-realm calls each short-circuit on flux_register%nfaces == 0.
fortran
subroutine apply_reflux_corrections(self, realm, dt)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
self | class(forest_object) | in | The forest (holds the flux register). | |
realm | class(realm_object) | inout | Realms; each realm's reflux TBP fires once. | |
dt | real(kind=R8P) | in | Time step. |
Call graph
share_flux_register
Copy the flux register into every realm (realm_object%flux_register_copy), after each build (init, regrid, manifest): the faces, their ownership and their accumulators (zeroed), so that a realm can accumulate one residual evaluation's seam fluxes for a diagnostic without touching the forest's step accumulators (issue #68 A2). The register is replicated (the same faces on every rank, issue #40), and so is the copy.
fortran
subroutine share_flux_register(self, realm)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
self | class(forest_object) | inout | The forest. | |
realm | class(realm_object) | inout | Realms. |
Call graph
Functions
seam_cell_size
The cell size of the leaves of a realm on its seam face: one size for all of them, error_stop otherwise.
Returns: real(kind=R8P)
fortran
function seam_cell_size(this_realm, face, pfx) result(dxyz)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
this_realm | class(realm_object) | in | Realm. | |
face | integer(kind=I4P) | in | Seam face (FACE_* code). | |
pfx | character(len=*) | in | Error message prefix. |
Call graph
size_pairs
Number of face pairs of a manifest.
Attributes: pure
Returns: integer(kind=I4P)
fortran
function size_pairs(manifest) result(n)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
manifest | type(forest_manifest_t) | in | Parsed manifest. |
leaf_on_realm_face
Return .true. iff the leaf code of a realm has its (axis, sgn) face on the realm boundary (any owner rank).
Returns: logical
fortran
function leaf_on_realm_face(this_realm, code, axis, sgn) result(yes)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
this_realm | class(realm_object) | in | Realm. | |
code | integer(kind=I8P) | in | Leaf Morton code. | |
axis | integer(kind=I4P) | in | Face axis (1..3) and side (+1 max, -1 min). | |
sgn | integer(kind=I4P) | in | Face axis (1..3) and side (+1 max, -1 min). |
Call graph
inside_domain
Return .true. iff xc lies inside the domain of this_realm, at least tol away from its boundary.
Attributes: pure
Returns: logical
fortran
function inside_domain(this_realm, xc, tol) result(yes)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
this_realm | class(realm_object) | in | Realm to query. | |
xc | real(kind=R8P) | in | Point. | |
tol | real(kind=R8P) | in | Per-axis margin. |
Call graph
ghost_label
Name a seam ghost cell in an error message.
Returns: character(len=:)
fortran
function ghost_label(is, b, i, j, k) result(label)Arguments
| Name | Type | Intent | Attributes | Description |
|---|---|---|---|---|
is | integer(kind=I4P) | in | Realm index. | |
b | integer(kind=I4P) | in | Owner-local block and ghost cell indices. | |
i | integer(kind=I4P) | in | Owner-local block and ghost cell indices. | |
j | integer(kind=I4P) | in | Owner-local block and ghost cell indices. | |
k | integer(kind=I4P) | in | Owner-local block and ghost cell indices. |
Call graph