ocean_budget_stage_weight Function

public pure function ocean_budget_stage_weight(is_pc) result(w)

The per-outer-step weight that turns the salt/heat budget ACCUMULATORS into the state change they must account for.

ssp_rk2 (is_pc = .false.) -> 0.5 (= RK2_STAGE_WEIGHT) pred_corr (is_pc = .true. ) -> 1.0

ms%{salt,heat}_budget_* are += accumulators filled by the tracer chain, zeroed once per OUTER step. Under split_scheme="ssp_rk2" the chain runs on BOTH identical stages, so the accumulator holds twice the step’s contribution and 0.5 converts it. Under split_scheme="pred_corr" there is ONE prognostic tracer update — the corrector; the predictor runs TR_MODE_NONE and contributes nothing — so the accumulator already equals the step’s contribution 1:1 and halving it reports exactly half the true source/transport.

This is the same distinction ocean_frazil_heat_src documents for the frazil accumulator (filled once per outer step ⇒ full weight).

MEASURED, 2026-09-13: with the 0.5 weight applied to a pred_corr run the console src came out exactly half its ssp_rk2 value on every surface-flux case (acc_channel -1.057E+15 -> -5.285E+14; epbl_basin -4.720E+16 -> -2.360E+16) while the Heat TOTAL matched to every printed digit, and the closed-budget residual went from ~1e-13 to ~5e-4. Ten shipped namelists failed the stability suite’s conservation gate on that alone. Sole home of the mapping.

Arguments

Type IntentOptional Attributes Name
logical, intent(in) :: is_pc

Return Value real(kind=wp)


Called by

proc~~ocean_budget_stage_weight~~CalledByGraph proc~ocean_budget_stage_weight ocean_budget_stage_weight proc~driver_run_ocean driver_run_ocean proc~driver_run_ocean->proc~ocean_budget_stage_weight proc~engine_step engine_step proc~driver_run_ocean->proc~engine_step proc~run_gm_step run_gm_step proc~run_gm_step->proc~ocean_budget_stage_weight proc~driver_run driver_run proc~driver_run->proc~driver_run_ocean proc~ocean_dyn_step_split ocean_dyn_step_split proc~ocean_dyn_step_split->proc~run_gm_step proc~engine_step->proc~ocean_dyn_step_split proc~rdb_ocean_step rdb_ocean_step proc~rdb_ocean_step->proc~engine_step

Source Code

   pure function ocean_budget_stage_weight(is_pc) result(w)
      !! The per-outer-step weight that turns the salt/heat budget
      !! ACCUMULATORS into the state change they must account for.
      !!
      !!   ssp_rk2  (is_pc = .false.)  ->  0.5   (= `RK2_STAGE_WEIGHT`)
      !!   pred_corr  (is_pc = .true. )  ->  1.0
      !!
      !! `ms%{salt,heat}_budget_*` are `+=` accumulators filled by the tracer
      !! chain, zeroed once per OUTER step.  Under `split_scheme="ssp_rk2"`
      !! the chain runs on BOTH identical stages, so the accumulator holds
      !! twice the step's contribution and 0.5 converts it.  Under
      !! `split_scheme="pred_corr"` there is ONE prognostic tracer update — the
      !! corrector; the predictor runs `TR_MODE_NONE` and contributes
      !! nothing — so the accumulator already equals the step's contribution
      !! 1:1 and halving it reports exactly half the true source/transport.
      !!
      !! This is the same distinction `ocean_frazil_heat_src` documents for
      !! the frazil accumulator (filled once per outer step ⇒ full weight).
      !!
      !! MEASURED, 2026-09-13: with the 0.5 weight applied to a pred_corr run
      !! the console `src` came out exactly half its ssp_rk2 value on every
      !! surface-flux case (`acc_channel` -1.057E+15 -> -5.285E+14;
      !! `epbl_basin` -4.720E+16 -> -2.360E+16) while the Heat TOTAL matched
      !! to every printed digit, and the closed-budget residual went from
      !! ~1e-13 to ~5e-4. Ten shipped namelists failed the stability suite's
      !! conservation gate on that alone. Sole home of the mapping.
      logical, intent(in) :: is_pc
      real(wp) :: w
      if (is_pc) then
         w = 1.0_wp
      else
         w = RK2_STAGE_WEIGHT
      end if
   end function ocean_budget_stage_weight