ocean_budget_is_active Function

public 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.

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: tracer_idx
logical, intent(in) :: horiz_adv_budget_valid

Return Value logical


Called by

proc~~ocean_budget_is_active~~CalledByGraph proc~ocean_budget_is_active ocean_budget_is_active proc~ocean_console_stats_report ocean_console_stats_report proc~ocean_console_stats_report->proc~ocean_budget_is_active proc~driver_run_ocean driver_run_ocean proc~driver_run_ocean->proc~ocean_console_stats_report proc~driver_run driver_run proc~driver_run->proc~driver_run_ocean

Source Code

   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