Globally-integrated conservation scalars (total mass, KE, salt,
heat) plus a per-kernel contributor registry, used to check a
kernel’s per-cell budget accumulator against the actual state
change (LHS = current_total − values_init vs RHS =
Σ contributors%total_integrated). No production caller by
design (PR-8): this module has no ocean_state_t slot — a
consumer constructs a local type(ocean_budgets_t) (seven of
Roundabout’s ocean conservation tests already do this; see
tests/test_ocean_surface_flux.F90 for the idiom). It is
single-rank with no MPI reduction; a production run’s global
conservation report is rdb_ocean_console_stats.F90:
ocean_console_stats_report, which does allreduce correctly.
init_snapshot(state) captures values_init;
evaluate(state) recomputes values.
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | public, | parameter | :: | BUDGET_HEAT_TOTAL | = | 4 | |
| integer, | public, | parameter | :: | BUDGET_KE | = | 2 |
kinetic energy |
| integer, | public, | parameter | :: | BUDGET_MASS | = | 1 | |
| integer, | public, | parameter | :: | BUDGET_N_DEFAULT | = | 4 | |
| integer, | public, | parameter | :: | BUDGET_SALT_TOTAL | = | 3 | |
| character(len=12), | private, | parameter | :: | BUDGET_NAMES(BUDGET_N_DEFAULT) | = | ["mass ", "KE ", "salt_total ", "heat_total "] | |
| integer, | private, | parameter | :: | INITIAL_CONTRIBUTOR_CAPACITY | = | 16 |
One source/sink of a conserved quantity, populated by a physics
kernel each step (adds dt·delta into per_cell) and drained at
eval cadence (drain_contributors integrates per_cell·mask·dA
over k into total_integrated, then zeroes per_cell).
total_integrated is the cumulative RHS checked against
LHS = current_total − values_init.
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| logical, | public | :: | device_resident | = | .false. |
True when |
|
| logical, | public | :: | is_active | = | .false. | ||
| character(len=64), | public | :: | name | = | "" |
Identifier — “continuity”, “vert_diff_heat”, “surface_heat_flux”, … |
|
| real(kind=wp), | public, | pointer | :: | per_cell(:,:,:) | => | null() |
Kernel-owned per-step accumulator; manager holds a non-owning pointer (kernel guarantees the array outlives registration). |
| integer, | public | :: | quantity | = | 0 |
Tag from BUDGET_* (MASS / SALT_TOTAL / HEAT_TOTAL / …). |
|
| real(kind=wp), | public | :: | total_integrated | = | 0.0_wp |
Cumulative spatial integral of contributions drained so far this run. Sign convention: positive = source. |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| real(kind=wp), | public, | allocatable | :: | areaT(:,:) |
Per-cell T-area (m²) copied from the metrics slot via |
||
| type(budget_contributor_t), | public, | allocatable | :: | contributors(:) | |||
| type(hgrid_t), | public | :: | grid | ||||
| logical, | public | :: | has_snapshot | = | .false. |
True once |
|
| logical, | public | :: | is_init | = | .false. | ||
| type(diag_mask_t), | public, | allocatable | :: | mask |
Optional region mask. Default = whole interior (built lazily);
reset via |
||
| integer, | public | :: | n_contributors | = | 0 | ||
| integer, | public | :: | n_contributors_max | = | 0 | ||
| integer, | public | :: | nbudgets | = | BUDGET_N_DEFAULT | ||
| real(kind=wp), | public | :: | values(BUDGET_N_DEFAULT) | = | 0.0_wp | ||
| real(kind=wp), | public | :: | values_init(BUDGET_N_DEFAULT) | = | 0.0_wp |
| procedure, public, non_overridable :: bytes => ocean_budgets_bytes | |
| procedure, public, non_overridable :: destroy => ocean_budgets_destroy | |
| procedure, public, non_overridable :: drain_contributors => ocean_budgets_drain_contributors | |
| procedure, public, non_overridable :: evaluate => ocean_budgets_evaluate | |
| procedure, public, non_overridable :: init => ocean_budgets_init | |
| procedure, public, non_overridable :: init_snapshot => ocean_budgets_init_snapshot | |
| procedure, public, non_overridable :: register_contributor => ocean_budgets_register_contributor | |
| procedure, public, non_overridable :: set_area => ocean_budgets_set_area | |
| procedure, public, non_overridable :: set_mask => ocean_budgets_set_mask |
Total KE: Σ over masked interior of 0.5·h·(u²+v²)·areaT·weight,
u/v averaged from C-grid faces to centres. Public only for tests.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(multilayer_state_t), | intent(in) | :: | ms | |||
| type(diag_mask_t), | intent(in) | :: | mask | |||
| real(kind=wp), | intent(in) | :: | areaT(:,:) |
Total mass: Σ over masked interior of h_layer·areaT·weight over k.
Units: m³. Public only for the unit-test suite.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(multilayer_state_t), | intent(in) | :: | ms | |||
| type(diag_mask_t), | intent(in) | :: | mask | |||
| real(kind=wp), | intent(in) | :: | areaT(:,:) |
Total tracer content: Σ over masked interior of hTr·areaT·weight
over k. hTr is thickness-weighted, so this is ∫(tracer·volume),
the conserved quantity. Public only for the unit-test suite.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(multilayer_state_t), | intent(in) | :: | ms | |||
| integer, | intent(in) | :: | it | |||
| type(diag_mask_t), | intent(in) | :: | mask | |||
| real(kind=wp), | intent(in) | :: | areaT(:,:) |
Counted allocatable footprint of the conservation budgets (own accumulator; registry contributors are counted by their owning slot) slot (0 when unallocated).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_budgets_t), | intent(in) | :: | this |
Per-cell T-area (m²) for physical integrals: cached metrics areaT
once set_area has run, else uniform grid%dx·grid%dy.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_budgets_t), | intent(in) | :: | this | |||
| real(kind=wp), | intent(out), | allocatable | :: | areaT(:,:) |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_budgets_t), | intent(inout) | :: | this |
For each contributor: integrate per_cell·mask·areaT (over k) into
total_integrated, then zero per_cell for the next window.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_budgets_t), | intent(inout) | :: | this |
Recompute this%values(:) from the current multilayer state.
Honours this%mask — sums are weighted by mask%weight · areaT.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_budgets_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(in) | :: | ms |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_budgets_t), | intent(inout) | :: | this | |||
| type(hgrid_t), | intent(in) | :: | grid |
Snapshot values_init from the current state. Call once
after the IC is set + the EOS has run, before stepping.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_budgets_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(in) | :: | ms |
Register a per-kernel contributor: store a non-owning pointer to
the kernel-owned per_cell + metadata. Set device_resident
when per_cell is GPU-mapped (drain syncs it). Idempotent on
name (re-registering updates the pointer, resets the integral).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_budgets_t), | intent(inout) | :: | this | |||
| character(len=*), | intent(in) | :: | name | |||
| integer, | intent(in) | :: | quantity | |||
| real(kind=wp), | intent(in), | target | :: | per_cell(:,:,:) | ||
| logical, | intent(in), | optional | :: | device_resident |
Cache the per-cell T-area (m²) from the metrics slot. After this,
physical integrals weight by mask%weight·areaT; before it they
fall back to grid%dx·grid%dy (= areaT on uniform Cartesian).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_budgets_t), | intent(inout) | :: | this | |||
| real(kind=wp), | intent(in) | :: | areaT(:,:) |
Override the default global mask. Useful for regional conservation diagnostics — “mass north of 30°S stays at FP.”
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_budgets_t), | intent(inout) | :: | this | |||
| type(diag_mask_t), | intent(in) | :: | mask |