Whether a tracer’s closed budget (out/src residual) should be
reported. .true. iff the tracer is registered (tracer_idx > 0)
AND the horizontal-advection accumulator is complete AND no
un-instrumented interior source is active.
horiz_adv_budget_valid = .false. declares that some horizontal
tracer transport moved hTr without being recorded in
*_budget_horiz_adv, so a “closed” residual read off that
accumulator would be WRONG.
The windowed tracer-advection path (dt_tracer_advect_ratio > 1)
USED to be such a producer — the fused tracer_advect_* kernels are
skipped in TR_MODE_ACCUMULATE, so nothing filled the accumulator.
That fall-back silently reported a live SURFACE HEAT FLUX as a 5e-5
“leak” (the raw-drift column cannot subtract a source), which is what
the four acc_channel windowed namelists were failing on. The
windowed path is now fully instrumented — continuity_tracer_drain’s
sub-cycle and BOTH halves of the concentration hold accumulate into
the same arrays (see DRAIN_BUDGET_POST_AVERAGE_WEIGHT in
rdb_continuity) — so that producer is gone and the driver no longer
passes this argument. The dummy is kept for the next
un-instrumented transport path (and for the fall-back unit test).
Redi + an OPEN boundary USED to be another fall-back
(redi_with_open_edge): the neutral flux through the open face was
not in the out accumulator, so the console printed raw drift — the
advective boundary exchange itself, ~4e-5 in 24 steps — as the
“residual”. redi_apply_flux now books its realised increment into
*_budget_hdiff, so the gate is gone and the budget closes.
PR-23 (real sponge) note: this gate used to carry a
sponge_relax_tracers fall-back — the legacy band sponge’s tracer
sink was an un-instrumented interior source. Both sponge paths are
now instrumented (the legacy band’s hTr sink was folded into the
same accumulators the map-driven path uses — see
ms%salt_budget_sponge / heat_budget_sponge and
ocean_heat_src_sum / ocean_salt_src_sum), so the gate is dead
and has been removed; the closed budget stays active with the
sponge on.
In the remaining fall-back case the console reverts to raw drift —
(Q_total − Q0)/Q0 — which is byte-identical to the pre-budget
behaviour (active = .false.). Sole home of the gate logic — the
reporter and the fallback unit test both call it.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | tracer_idx | |||
| logical, | intent(in) | :: | horiz_adv_budget_valid |
pure function ocean_budget_is_active(tracer_idx, horiz_adv_budget_valid) result(active) !! Whether a tracer's closed budget (`out`/`src` residual) should be !! reported. `.true.` iff the tracer is registered (`tracer_idx > 0`) !! AND the horizontal-advection accumulator is complete AND no !! un-instrumented interior source is active. !! !! `horiz_adv_budget_valid = .false.` declares that some horizontal !! tracer transport moved `hTr` without being recorded in !! `*_budget_horiz_adv`, so a "closed" residual read off that !! accumulator would be WRONG. !! !! The windowed tracer-advection path (`dt_tracer_advect_ratio > 1`) !! USED to be such a producer — the fused `tracer_advect_*` kernels are !! skipped in `TR_MODE_ACCUMULATE`, so nothing filled the accumulator. !! That fall-back silently reported a live SURFACE HEAT FLUX as a 5e-5 !! "leak" (the raw-drift column cannot subtract a source), which is what !! the four `acc_channel` windowed namelists were failing on. The !! windowed path is now fully instrumented — `continuity_tracer_drain`'s !! sub-cycle and BOTH halves of the concentration hold accumulate into !! the same arrays (see `DRAIN_BUDGET_POST_AVERAGE_WEIGHT` in !! `rdb_continuity`) — so that producer is gone and the driver no longer !! passes this argument. The dummy is kept for the next !! un-instrumented transport path (and for the fall-back unit test). !! !! Redi + an OPEN boundary USED to be another fall-back !! (`redi_with_open_edge`): the neutral flux through the open face was !! not in the `out` accumulator, so the console printed raw drift — the !! advective boundary exchange itself, ~4e-5 in 24 steps — as the !! "residual". `redi_apply_flux` now books its realised increment into !! `*_budget_hdiff`, so the gate is gone and the budget closes. !! !! PR-23 (real sponge) note: this gate used to carry a !! `sponge_relax_tracers` fall-back — the legacy band sponge's tracer !! sink was an un-instrumented interior source. Both sponge paths are !! now instrumented (the legacy band's `hTr` sink was folded into the !! same accumulators the map-driven path uses — see !! `ms%salt_budget_sponge` / `heat_budget_sponge` and !! `ocean_heat_src_sum` / `ocean_salt_src_sum`), so the gate is dead !! and has been removed; the closed budget stays active with the !! sponge on. !! !! In the remaining fall-back case the console reverts to raw drift — !! `(Q_total − Q0)/Q0` — which is byte-identical to the pre-budget !! behaviour (`active = .false.`). Sole home of the gate logic — the !! reporter and the fallback unit test both call it. integer, intent(in) :: tracer_idx logical, intent(in) :: horiz_adv_budget_valid logical :: active active = (tracer_idx > 0) .and. horiz_adv_budget_valid end function ocean_budget_is_active