run_stage Subroutine

private subroutine run_stage(grid, metrics, dyn, eos, cor, ct, pgf, hv, bd, ss, va, hd, vd, vmix, ms, dt, stage, sf, geo, lateral_mix, epbl, kshear, slopes, vmix_tidal, td, cav)

One FE stage of the multilayer step. Order of operations:

  1. EOS: rho_layer <- linear(T, S)
  2. Velocity-tendency computes — Coriolis, PGF, hvisc, bottom drag, surface stress. All read h_old, u, v and write to their own tendency buffers; none touch h yet.
  3. continuity_tracer_step_split — interleaved Lie-split horizontal step: zonal flux + tracer zonal + apply zonal + meridional flux + tracer meridional + apply meridional. Updates h AND hTr together; the CWC discrete theorem holds (uniform T stays uniform).
  4. tracer_hdiff — Laplacian diffusion on hTr.
  5. compute_w_from_continuity — diagnose w from the total horizontal divergence stored in flux_h_layer.
  6. tracer_advect_vertical — upwind-in-z + h update that cancels the horizontal h change (Eulerian-z mode).
  7. Velocity-tendency applies (Coriolis, PGF, hvisc, drag, surface stress) — all additive.
  8. Surface tracer fluxes (heat, salt).
  9. Vertical mixing closure + vdiff.

Arguments

Type IntentOptional Attributes Name
type(hgrid_t), intent(in) :: grid
type(ocean_metrics_t), intent(in) :: metrics

Curvilinear horizontal metrics — forwarded to the PGF.

type(ocean_dyn_t), intent(in) :: dyn
type(eos_t), intent(in) :: eos
type(coriolis_adv_t), intent(inout) :: cor
type(continuity_t), intent(inout) :: ct
type(ocean_pressure_force_t), intent(inout) :: pgf
type(ocean_horizontal_viscosity_t), intent(inout) :: hv
type(ocean_bottom_drag_t), intent(inout) :: bd
type(ocean_surface_stress_t), intent(inout) :: ss
type(ocean_vertical_advection_t), intent(inout) :: va
type(ocean_hdiff_tracer_t), intent(inout) :: hd
type(ocean_vdiff_t), intent(inout) :: vd
type(ocean_vmix_t), intent(inout) :: vmix
type(multilayer_state_t), intent(inout) :: ms
real(kind=wp), intent(in) :: dt
integer, intent(in) :: stage

RK2 stage (1 or 2); see vmix_apply_in_stage.

type(ocean_surface_flux_t), intent(in), optional :: sf
type(ocean_geothermal_t), intent(in), optional :: geo

Geothermal bottom-heat-flux slot. See ocean_dyn_step.

type(ocean_lateral_mix_t), intent(inout), optional :: lateral_mix
type(ocean_epbl_t), intent(inout), optional :: epbl
type(ocean_kappa_shear_t), intent(inout), optional :: kshear
type(ocean_slopes_t), intent(inout), optional :: slopes
type(ocean_tidal_mixing_t), intent(inout), optional :: vmix_tidal
type(ocean_top_drag_t), intent(inout), optional :: td

Ice-shelf TOP-drag slot (&ocean_tdrag_nml). OPTIONAL so the many direct ocean_dyn_step* / run_stage* call sites in the test suite need no churn; the production driver always passes it. Absent, or present and disabled, => no kernel launch and a bit-identical step.

type(ocean_cavity_flux_t), intent(inout), optional :: cav

Ice-shelf basal-melt slot (&ocean_cavity_melt_nml). OPTIONAL for the same reason td is: the direct ocean_dyn_step* / run_stage* call sites in the test suite need no churn, and the production driver always passes it. Absent, disabled, or freshwater="virtual" => no kernel launch and a bit-identical step. It is threaded down here rather than acted on in engine_step_finalize because the real-freshwater volume must be spent in the SAME stage, at the SAME stage weight and from the SAME melt value as the salt and heat halves the surface-flux apply spends – see ocean_cavity_mass_step’s docstring.


Calls

proc~~run_stage~~CallsGraph proc~run_stage run_stage proc~apply_sw_and_restore apply_sw_and_restore proc~run_stage->proc~apply_sw_and_restore proc~compute_w_from_continuity compute_w_from_continuity proc~run_stage->proc~compute_w_from_continuity proc~continuity_tracer_step_split continuity_tracer_step_split proc~run_stage->proc~continuity_tracer_step_split proc~coriolis_adv_apply_tendencies coriolis_adv_apply_tendencies proc~run_stage->proc~coriolis_adv_apply_tendencies proc~coriolis_adv_compute_tendencies coriolis_adv_compute_tendencies proc~run_stage->proc~coriolis_adv_compute_tendencies proc~ocean_accumulate_mass_out ocean_accumulate_mass_out proc~run_stage->proc~ocean_accumulate_mass_out proc~ocean_bottom_drag_apply_tendencies ocean_bottom_drag_apply_tendencies proc~run_stage->proc~ocean_bottom_drag_apply_tendencies proc~ocean_bottom_drag_compute_tendencies ocean_bottom_drag_compute_tendencies proc~run_stage->proc~ocean_bottom_drag_compute_tendencies proc~ocean_cavity_mass_step ocean_cavity_mass_step proc~run_stage->proc~ocean_cavity_mass_step proc~ocean_channel_drag_apply_tendencies ocean_channel_drag_apply_tendencies proc~run_stage->proc~ocean_channel_drag_apply_tendencies proc~ocean_channel_drag_compute_tendencies ocean_channel_drag_compute_tendencies proc~run_stage->proc~ocean_channel_drag_compute_tendencies proc~ocean_dyn_is_thermo_step ocean_dyn_t%ocean_dyn_is_thermo_step proc~run_stage->proc~ocean_dyn_is_thermo_step proc~ocean_dyn_therm_dt ocean_dyn_t%ocean_dyn_therm_dt proc~run_stage->proc~ocean_dyn_therm_dt proc~ocean_eos_compute ocean_eos_compute proc~run_stage->proc~ocean_eos_compute proc~ocean_geothermal_apply_tracers ocean_geothermal_apply_tracers proc~run_stage->proc~ocean_geothermal_apply_tracers proc~ocean_horizontal_viscosity_apply_tendencies ocean_horizontal_viscosity_apply_tendencies proc~run_stage->proc~ocean_horizontal_viscosity_apply_tendencies proc~ocean_horizontal_viscosity_compute_ke_diss ocean_horizontal_viscosity_compute_ke_diss proc~run_stage->proc~ocean_horizontal_viscosity_compute_ke_diss proc~ocean_horizontal_viscosity_compute_tendencies ocean_horizontal_viscosity_compute_tendencies proc~run_stage->proc~ocean_horizontal_viscosity_compute_tendencies proc~ocean_ideal_age_apply ocean_ideal_age_apply proc~run_stage->proc~ocean_ideal_age_apply proc~ocean_lateral_mix_compute ocean_lateral_mix_compute proc~run_stage->proc~ocean_lateral_mix_compute proc~ocean_pressure_force_apply ocean_pressure_force_apply proc~run_stage->proc~ocean_pressure_force_apply proc~ocean_pressure_force_compute ocean_pressure_force_compute proc~run_stage->proc~ocean_pressure_force_compute proc~ocean_slopes_compute ocean_slopes_compute proc~run_stage->proc~ocean_slopes_compute proc~ocean_surface_flux_apply_tracers ocean_surface_flux_apply_tracers proc~run_stage->proc~ocean_surface_flux_apply_tracers proc~ocean_surface_stress_apply_tendencies ocean_surface_stress_apply_tendencies proc~run_stage->proc~ocean_surface_stress_apply_tendencies proc~ocean_surface_stress_compute_tendencies ocean_surface_stress_compute_tendencies proc~run_stage->proc~ocean_surface_stress_compute_tendencies proc~ocean_top_drag_apply_tendencies ocean_top_drag_apply_tendencies proc~run_stage->proc~ocean_top_drag_apply_tendencies proc~ocean_top_drag_compute_tendencies ocean_top_drag_compute_tendencies proc~run_stage->proc~ocean_top_drag_compute_tendencies proc~tracer_advect_vertical tracer_advect_vertical proc~run_stage->proc~tracer_advect_vertical proc~tracer_hdiff tracer_hdiff proc~run_stage->proc~tracer_hdiff proc~vmix_apply_in_stage vmix_apply_in_stage proc~run_stage->proc~vmix_apply_in_stage proc~ocean_surface_flux_apply_sw_penetration ocean_surface_flux_apply_sw_penetration proc~apply_sw_and_restore->proc~ocean_surface_flux_apply_sw_penetration proc~ocean_surface_restore_apply_tracers ocean_surface_restore_apply_tracers proc~apply_sw_and_restore->proc~ocean_surface_restore_apply_tracers interface~ocean_fold_north_v_face ocean_fold_north_v_face proc~continuity_tracer_step_split->interface~ocean_fold_north_v_face interface~ocean_halo_centre ocean_halo_centre proc~continuity_tracer_step_split->interface~ocean_halo_centre proc~accumulate_flux_x accumulate_flux_x proc~continuity_tracer_step_split->proc~accumulate_flux_x proc~accumulate_flux_y accumulate_flux_y proc~continuity_tracer_step_split->proc~accumulate_flux_y proc~continuity_apply_meridional continuity_apply_meridional proc~continuity_tracer_step_split->proc~continuity_apply_meridional proc~continuity_apply_zonal continuity_apply_zonal proc~continuity_tracer_step_split->proc~continuity_apply_zonal proc~continuity_meridional_flux continuity_meridional_flux proc~continuity_tracer_step_split->proc~continuity_meridional_flux proc~continuity_zonal_flux continuity_zonal_flux proc~continuity_tracer_step_split->proc~continuity_zonal_flux proc~drain_copy_3d drain_copy_3d proc~continuity_tracer_step_split->proc~drain_copy_3d proc~drain_rescale_htr drain_rescale_hTr proc~continuity_tracer_step_split->proc~drain_rescale_htr proc~drain_rescale_htr_budget drain_rescale_hTr_budget proc~continuity_tracer_step_split->proc~drain_rescale_htr_budget proc~mle_fold_x mle_fold_x proc~continuity_tracer_step_split->proc~mle_fold_x proc~mle_fold_y mle_fold_y proc~continuity_tracer_step_split->proc~mle_fold_y proc~ocean_bc_outer_face_tag ocean_bc_outer_face_tag proc~continuity_tracer_step_split->proc~ocean_bc_outer_face_tag proc~ocean_fold_wrap_centre_3d_state ocean_fold_wrap_centre_3d_state proc~continuity_tracer_step_split->proc~ocean_fold_wrap_centre_3d_state proc~ocean_halo_is_decomposed_x ocean_halo_is_decomposed_x proc~continuity_tracer_step_split->proc~ocean_halo_is_decomposed_x proc~ocean_halo_is_decomposed_y ocean_halo_is_decomposed_y proc~continuity_tracer_step_split->proc~ocean_halo_is_decomposed_y proc~ocean_periodic_wrap_centre_3d ocean_periodic_wrap_centre_3d proc~continuity_tracer_step_split->proc~ocean_periodic_wrap_centre_3d proc~pd_limit_meridional_impl pd_limit_meridional_impl proc~continuity_tracer_step_split->proc~pd_limit_meridional_impl proc~pd_limit_zonal_impl pd_limit_zonal_impl proc~continuity_tracer_step_split->proc~pd_limit_zonal_impl proc~profiler_start profiler_start proc~continuity_tracer_step_split->proc~profiler_start proc~profiler_stop profiler_stop proc~continuity_tracer_step_split->proc~profiler_stop proc~tracer_advect_meridional tracer_advect_meridional proc~continuity_tracer_step_split->proc~tracer_advect_meridional proc~tracer_advect_zonal tracer_advect_zonal proc~continuity_tracer_step_split->proc~tracer_advect_zonal proc~coriolis_adv_compute_tendencies_hk coriolis_adv_compute_tendencies_hk proc~coriolis_adv_compute_tendencies->proc~coriolis_adv_compute_tendencies_hk proc~coriolis_adv_compute_tendencies_sadourny coriolis_adv_compute_tendencies_sadourny proc~coriolis_adv_compute_tendencies->proc~coriolis_adv_compute_tendencies_sadourny proc~coriolis_adv_compute_tendencies_sadourny_energy coriolis_adv_compute_tendencies_sadourny_energy proc~coriolis_adv_compute_tendencies->proc~coriolis_adv_compute_tendencies_sadourny_energy proc~efp_carry efp_carry proc~ocean_accumulate_mass_out->proc~efp_carry proc~efp_decompose_impl efp_decompose_impl proc~ocean_accumulate_mass_out->proc~efp_decompose_impl local local proc~ocean_bottom_drag_compute_tendencies->local proc~compute_distributed_drag compute_distributed_drag proc~ocean_bottom_drag_compute_tendencies->proc~compute_distributed_drag error error proc~ocean_cavity_mass_step->error proc~cavity_comp_apply_impl cavity_comp_apply_impl proc~ocean_cavity_mass_step->proc~cavity_comp_apply_impl proc~cavity_comp_scale_tracer_impl cavity_comp_scale_tracer_impl proc~ocean_cavity_mass_step->proc~cavity_comp_scale_tracer_impl proc~cavity_comp_withdrawal cavity_comp_withdrawal proc~ocean_cavity_mass_step->proc~cavity_comp_withdrawal proc~cavity_mass_apply_impl cavity_mass_apply_impl proc~ocean_cavity_mass_step->proc~cavity_mass_apply_impl proc~cavity_mass_salt_mirror_impl cavity_mass_salt_mirror_impl proc~ocean_cavity_mass_step->proc~cavity_mass_salt_mirror_impl proc~cavity_mass_thin_is_fatal cavity_mass_thin_is_fatal proc~ocean_cavity_mass_step->proc~cavity_mass_thin_is_fatal proc~cavity_mass_totals_impl cavity_mass_totals_impl proc~ocean_cavity_mass_step->proc~cavity_mass_totals_impl proc~fail fail proc~ocean_cavity_mass_step->proc~fail proc~halo_allreduce_sum halo_allreduce_sum proc~ocean_cavity_mass_step->proc~halo_allreduce_sum to_string to_string proc~ocean_cavity_mass_step->to_string proc~compute_channel_drag_rates compute_channel_drag_rates proc~ocean_channel_drag_compute_tendencies->proc~compute_channel_drag_rates proc~eos_compute_arrays eos_compute_arrays proc~ocean_eos_compute->proc~eos_compute_arrays proc~apply_geothermal_src_impl apply_geothermal_src_impl proc~ocean_geothermal_apply_tracers->proc~apply_geothermal_src_impl proc~hvisc_apply_impl hvisc_apply_impl proc~ocean_horizontal_viscosity_apply_tendencies->proc~hvisc_apply_impl proc~hvisc_ke_diss_impl hvisc_ke_diss_impl proc~ocean_horizontal_viscosity_compute_ke_diss->proc~hvisc_ke_diss_impl proc~ocean_horizontal_viscosity_compute_tendencies_on ocean_horizontal_viscosity_compute_tendencies_on proc~ocean_horizontal_viscosity_compute_tendencies->proc~ocean_horizontal_viscosity_compute_tendencies_on proc~ocean_ideal_age_age_step ocean_ideal_age_age_step proc~ocean_ideal_age_apply->proc~ocean_ideal_age_age_step proc~ocean_lateral_mix_compute_leith ocean_lateral_mix_compute_leith proc~ocean_lateral_mix_compute->proc~ocean_lateral_mix_compute_leith proc~ocean_lateral_mix_compute_leith_biharm ocean_lateral_mix_compute_leith_biharm proc~ocean_lateral_mix_compute->proc~ocean_lateral_mix_compute_leith_biharm proc~ocean_lateral_mix_compute_smag ocean_lateral_mix_compute_smag proc~ocean_lateral_mix_compute->proc~ocean_lateral_mix_compute_smag proc~ocean_lateral_mix_compute_smag_ah ocean_lateral_mix_compute_smag_ah proc~ocean_lateral_mix_compute->proc~ocean_lateral_mix_compute_smag_ah proc~ocean_lateral_mix_compute_vel_scale ocean_lateral_mix_compute_vel_scale proc~ocean_lateral_mix_compute->proc~ocean_lateral_mix_compute_vel_scale proc~ocean_pressure_force_compute->local proc~compute_fv_mom6_impl compute_fv_mom6_impl proc~ocean_pressure_force_compute->proc~compute_fv_mom6_impl proc~compute_fv_mom6_insitu_pcm_impl compute_fv_mom6_insitu_pcm_impl proc~ocean_pressure_force_compute->proc~compute_fv_mom6_insitu_pcm_impl proc~compute_fv_mom6_reconstruct_impl compute_fv_mom6_reconstruct_impl proc~ocean_pressure_force_compute->proc~compute_fv_mom6_reconstruct_impl proc~compute_gprime_impl compute_gprime_impl proc~ocean_pressure_force_compute->proc~compute_gprime_impl proc~eos_wright_pgf_column_sweep_impl eos_wright_pgf_column_sweep_impl proc~ocean_pressure_force_compute->proc~eos_wright_pgf_column_sweep_impl proc~use_insitu_pcm use_insitu_pcm proc~ocean_pressure_force_compute->proc~use_insitu_pcm proc~ocean_slopes_compute_impl ocean_slopes_compute_impl proc~ocean_slopes_compute->proc~ocean_slopes_compute_impl proc~apply_surface_src_2d_dyn_impl apply_surface_src_2d_dyn_impl proc~ocean_surface_flux_apply_tracers->proc~apply_surface_src_2d_dyn_impl proc~apply_surface_src_2d_dyn_nobudget_impl apply_surface_src_2d_dyn_nobudget_impl proc~ocean_surface_flux_apply_tracers->proc~apply_surface_src_2d_dyn_nobudget_impl proc~apply_surface_src_2d_impl apply_surface_src_2d_impl proc~ocean_surface_flux_apply_tracers->proc~apply_surface_src_2d_impl proc~apply_surface_src_2d_nobudget_impl apply_surface_src_2d_nobudget_impl proc~ocean_surface_flux_apply_tracers->proc~apply_surface_src_2d_nobudget_impl proc~surfstress_apply_impl surfstress_apply_impl proc~ocean_surface_stress_apply_tendencies->proc~surfstress_apply_impl proc~surfstress_compute_impl surfstress_compute_impl proc~ocean_surface_stress_compute_tendencies->proc~surfstress_compute_impl proc~surfstress_distributed_impl surfstress_distributed_impl proc~ocean_surface_stress_compute_tendencies->proc~surfstress_distributed_impl proc~top_drag_stress_mag_impl top_drag_stress_mag_impl proc~ocean_top_drag_compute_tendencies->proc~top_drag_stress_mag_impl proc~top_drag_tendencies_impl top_drag_tendencies_impl proc~ocean_top_drag_compute_tendencies->proc~top_drag_tendencies_impl proc~apply_w_to_h_layer apply_w_to_h_layer proc~tracer_advect_vertical->proc~apply_w_to_h_layer proc~tracer_advect_vertical_one_impl tracer_advect_vertical_one_impl proc~tracer_advect_vertical->proc~tracer_advect_vertical_one_impl proc~tracer_hdiff->proc~ocean_bc_outer_face_tag proc~tracer_hdiff_one_impl tracer_hdiff_one_impl proc~tracer_hdiff->proc~tracer_hdiff_one_impl proc~vmix_apply_in_stage->proc~ocean_dyn_is_thermo_step proc~vmix_apply_in_stage->proc~ocean_dyn_therm_dt proc~vmix_apply_in_stage->error proc~epbl_compute epbl_compute proc~vmix_apply_in_stage->proc~epbl_compute proc~epbl_merge_into_kv_kt epbl_merge_into_kv_kt proc~vmix_apply_in_stage->proc~epbl_merge_into_kv_kt proc~kappa_shear_compute kappa_shear_compute proc~vmix_apply_in_stage->proc~kappa_shear_compute proc~kappa_shear_merge_into_kv_kt kappa_shear_merge_into_kv_kt proc~vmix_apply_in_stage->proc~kappa_shear_merge_into_kv_kt proc~vmix_apply_in_stage->proc~profiler_start proc~vmix_apply_in_stage->proc~profiler_stop proc~tidal_mixing_compute tidal_mixing_compute proc~vmix_apply_in_stage->proc~tidal_mixing_compute proc~tidal_mixing_merge_into_kt tidal_mixing_merge_into_kt proc~vmix_apply_in_stage->proc~tidal_mixing_merge_into_kt proc~vdiff_apply_momentum vdiff_apply_momentum proc~vmix_apply_in_stage->proc~vdiff_apply_momentum proc~vdiff_apply_tracers vdiff_apply_tracers proc~vmix_apply_in_stage->proc~vdiff_apply_tracers proc~visc_rem_halo_refresh visc_rem_halo_refresh proc~vmix_apply_in_stage->proc~visc_rem_halo_refresh proc~visc_rem_precompute visc_rem_precompute proc~vmix_apply_in_stage->proc~visc_rem_precompute proc~vmix_add_kv_ml_invz2 vmix_add_kv_ml_invz2 proc~vmix_apply_in_stage->proc~vmix_add_kv_ml_invz2 proc~vmix_apply_convection vmix_apply_convection proc~vmix_apply_in_stage->proc~vmix_apply_convection proc~vmix_apply_kpp_overlay vmix_apply_kpp_overlay proc~vmix_apply_in_stage->proc~vmix_apply_kpp_overlay proc~vmix_apply_nonlocal_tendencies vmix_apply_nonlocal_tendencies proc~vmix_apply_in_stage->proc~vmix_apply_nonlocal_tendencies proc~vmix_assemble vmix_assemble proc~vmix_apply_in_stage->proc~vmix_assemble proc~vmix_compute_pp81 vmix_compute_pp81 proc~vmix_apply_in_stage->proc~vmix_compute_pp81 proc~vmix_split_kd_heat_salt vmix_split_kd_heat_salt proc~vmix_apply_in_stage->proc~vmix_split_kd_heat_salt proc~fold_v_2d fold_v_2d interface~ocean_fold_north_v_face->proc~fold_v_2d proc~fold_v_3d fold_v_3d interface~ocean_fold_north_v_face->proc~fold_v_3d proc~ocean_halo_centre_2d ocean_halo_centre_2d interface~ocean_halo_centre->proc~ocean_halo_centre_2d proc~ocean_halo_centre_3d ocean_halo_centre_3d interface~ocean_halo_centre->proc~ocean_halo_centre_3d proc~apply_geothermal_src_impl->local proc~apply_surface_src_2d_dyn_impl->local proc~apply_surface_src_2d_dyn_nobudget_impl->local proc~apply_surface_src_2d_impl->local proc~apply_surface_src_2d_nobudget_impl->local proc~cavity_comp_apply_impl->local reduce reduce proc~cavity_comp_apply_impl->reduce proc~cavity_mass_apply_impl->local proc~cavity_mass_apply_impl->reduce proc~cavity_mass_salt_mirror_impl->local proc~cavity_mass_totals_impl->reduce proc~compute_channel_drag_rates->local proc~compute_distributed_drag->local proc~compute_fv_mom6_impl->local proc~compute_fv_mom6_insitu_pcm_impl->local proc~fv_mom6_mass_weights fv_mom6_mass_weights proc~compute_fv_mom6_insitu_pcm_impl->proc~fv_mom6_mass_weights proc~recon_rho_surf recon_rho_surf proc~compute_fv_mom6_insitu_pcm_impl->proc~recon_rho_surf proc~roquet_pcm_dpa_face roquet_pcm_dpa_face proc~compute_fv_mom6_insitu_pcm_impl->proc~roquet_pcm_dpa_face proc~roquet_pcm_dpa_intz roquet_pcm_dpa_intz proc~compute_fv_mom6_insitu_pcm_impl->proc~roquet_pcm_dpa_intz proc~wright_pcm_dpa_face wright_pcm_dpa_face proc~compute_fv_mom6_insitu_pcm_impl->proc~wright_pcm_dpa_face proc~wright_pcm_dpa_intz wright_pcm_dpa_intz proc~compute_fv_mom6_insitu_pcm_impl->proc~wright_pcm_dpa_intz rdb_vl_conc rdb_vl_conc proc~compute_fv_mom6_insitu_pcm_impl->rdb_vl_conc rdb_vl_is_live rdb_vl_is_live proc~compute_fv_mom6_insitu_pcm_impl->rdb_vl_is_live proc~compute_fv_mom6_reconstruct_impl->local proc~boole_dpa_face boole_dpa_face proc~compute_fv_mom6_reconstruct_impl->proc~boole_dpa_face proc~boole_dpa_face_wright boole_dpa_face_wright proc~compute_fv_mom6_reconstruct_impl->proc~boole_dpa_face_wright proc~boole_dpa_intz_layer boole_dpa_intz_layer proc~compute_fv_mom6_reconstruct_impl->proc~boole_dpa_intz_layer proc~boole_dpa_intz_layer_wright boole_dpa_intz_layer_wright proc~compute_fv_mom6_reconstruct_impl->proc~boole_dpa_intz_layer_wright proc~plm_edges_layer plm_edges_layer proc~compute_fv_mom6_reconstruct_impl->proc~plm_edges_layer proc~ppm_edges_layer ppm_edges_layer proc~compute_fv_mom6_reconstruct_impl->proc~ppm_edges_layer proc~compute_fv_mom6_reconstruct_impl->proc~recon_rho_surf proc~roquet_recon_dpa_face roquet_recon_dpa_face proc~compute_fv_mom6_reconstruct_impl->proc~roquet_recon_dpa_face proc~roquet_recon_dpa_intz roquet_recon_dpa_intz proc~compute_fv_mom6_reconstruct_impl->proc~roquet_recon_dpa_intz proc~compute_fv_mom6_reconstruct_impl->rdb_vl_conc proc~compute_fv_mom6_reconstruct_impl->rdb_vl_is_live proc~compute_gprime_impl->local proc~continuity_meridional_flux->local proc~continuity_meridional_flux->proc~ocean_bc_outer_face_tag proc~ppm_cell_limiter ppm_cell_limiter proc~continuity_meridional_flux->proc~ppm_cell_limiter proc~ppm_limit_pos ppm_limit_pos proc~continuity_meridional_flux->proc~ppm_limit_pos proc~ppm_limited_slope ppm_limited_slope proc~continuity_meridional_flux->proc~ppm_limited_slope proc~ppm_mirror_h ppm_mirror_h proc~continuity_meridional_flux->proc~ppm_mirror_h proc~renormalise_meridional_flux_to_vhbt renormalise_meridional_flux_to_vhbt proc~continuity_meridional_flux->proc~renormalise_meridional_flux_to_vhbt proc~volcfl_face volcfl_face proc~continuity_meridional_flux->proc~volcfl_face proc~continuity_zonal_flux->local proc~continuity_zonal_flux->proc~ocean_bc_outer_face_tag proc~continuity_zonal_flux->proc~ppm_cell_limiter proc~continuity_zonal_flux->proc~ppm_limit_pos proc~continuity_zonal_flux->proc~ppm_limited_slope proc~continuity_zonal_flux->proc~ppm_mirror_h proc~renormalise_zonal_flux_to_uhbt renormalise_zonal_flux_to_uhbt proc~continuity_zonal_flux->proc~renormalise_zonal_flux_to_uhbt proc~continuity_zonal_flux->proc~volcfl_face proc~coriolis_adv_compute_tendencies_hk->local proc~hk_corner_h hk_corner_h proc~coriolis_adv_compute_tendencies_hk->proc~hk_corner_h proc~hk_pair_coef hk_pair_coef proc~coriolis_adv_compute_tendencies_hk->proc~hk_pair_coef proc~porous_narrow_3d porous_narrow_3d proc~coriolis_adv_compute_tendencies_hk->proc~porous_narrow_3d proc~coriolis_adv_compute_tendencies_sadourny->local proc~weno3_recon weno3_recon proc~coriolis_adv_compute_tendencies_sadourny->proc~weno3_recon proc~weno5_recon weno5_recon proc~coriolis_adv_compute_tendencies_sadourny->proc~weno5_recon proc~weno7_recon weno7_recon proc~coriolis_adv_compute_tendencies_sadourny->proc~weno7_recon proc~coriolis_adv_compute_tendencies_sadourny_energy->local proc~corner_abs_vort corner_abs_vort proc~coriolis_adv_compute_tendencies_sadourny_energy->proc~corner_abs_vort proc~coriolis_adv_compute_tendencies_sadourny_energy->proc~porous_narrow_3d proc~drain_rescale_htr_budget->local proc~eos_linear_impl eos_linear_impl proc~eos_compute_arrays->proc~eos_linear_impl proc~eos_roquet_spv_impl eos_roquet_spv_impl proc~eos_compute_arrays->proc~eos_roquet_spv_impl proc~eos_wright_impl eos_wright_impl proc~eos_compute_arrays->proc~eos_wright_impl proc~eos_wright_pgf_column_sweep_impl->local proc~epbl_column_kernel epbl_column_kernel proc~epbl_compute->proc~epbl_column_kernel proc~fail->error proc~error_ring_push error_ring_push proc~fail->proc~error_ring_push allreduce allreduce proc~halo_allreduce_sum->allreduce proc~comm_env_compute_comm comm_env_compute_comm proc~halo_allreduce_sum->proc~comm_env_compute_comm proc~hvisc_ke_diss_impl->local proc~kappa_shear_column_kernel kappa_shear_column_kernel proc~kappa_shear_compute->proc~kappa_shear_column_kernel proc~kappa_shear_vertex_kernel kappa_shear_vertex_kernel proc~kappa_shear_compute->proc~kappa_shear_vertex_kernel proc~kappa_shear_vertex_scatter kappa_shear_vertex_scatter proc~kappa_shear_compute->proc~kappa_shear_vertex_scatter interface~fold_north_centre fold_north_centre proc~ocean_fold_wrap_centre_3d_state->interface~fold_north_centre interface~ocean_fold_pack ocean_fold_pack proc~ocean_fold_wrap_centre_3d_state->interface~ocean_fold_pack interface~ocean_fold_unpack ocean_fold_unpack proc~ocean_fold_wrap_centre_3d_state->interface~ocean_fold_unpack proc~n_tracers n_tracers proc~ocean_fold_wrap_centre_3d_state->proc~n_tracers proc~ocean_fold_begin ocean_fold_begin proc~ocean_fold_wrap_centre_3d_state->proc~ocean_fold_begin proc~ocean_fold_end ocean_fold_end proc~ocean_fold_wrap_centre_3d_state->proc~ocean_fold_end proc~ocean_fold_exchange ocean_fold_exchange proc~ocean_fold_wrap_centre_3d_state->proc~ocean_fold_exchange proc~ocean_fold_is_distributed ocean_fold_is_distributed proc~ocean_fold_wrap_centre_3d_state->proc~ocean_fold_is_distributed proc~hvisc_add_aniso_coef hvisc_add_aniso_coef proc~ocean_horizontal_viscosity_compute_tendencies_on->proc~hvisc_add_aniso_coef proc~hvisc_avg_a_face hvisc_avg_A_face proc~ocean_horizontal_viscosity_compute_tendencies_on->proc~hvisc_avg_a_face proc~hvisc_clamp_a hvisc_clamp_A proc~ocean_horizontal_viscosity_compute_tendencies_on->proc~hvisc_clamp_a proc~hvisc_compute_biharmonic_face_impl hvisc_compute_biharmonic_face_impl proc~ocean_horizontal_viscosity_compute_tendencies_on->proc~hvisc_compute_biharmonic_face_impl proc~hvisc_compute_biharmonic_impl hvisc_compute_biharmonic_impl proc~ocean_horizontal_viscosity_compute_tendencies_on->proc~hvisc_compute_biharmonic_impl proc~hvisc_compute_face_impl hvisc_compute_face_impl proc~ocean_horizontal_viscosity_compute_tendencies_on->proc~hvisc_compute_face_impl proc~hvisc_compute_scalar_impl hvisc_compute_scalar_impl proc~ocean_horizontal_viscosity_compute_tendencies_on->proc~hvisc_compute_scalar_impl proc~hvisc_compute_stress hvisc_compute_stress proc~ocean_horizontal_viscosity_compute_tendencies_on->proc~hvisc_compute_stress proc~hvisc_fill_a_scalar hvisc_fill_A_scalar proc~ocean_horizontal_viscosity_compute_tendencies_on->proc~hvisc_fill_a_scalar proc~ocean_lateral_mix_compute_leith->local proc~ocean_lateral_mix_compute_leith_biharm->local proc~ocean_lateral_mix_compute_smag->local proc~ocean_lateral_mix_compute_smag_ah->local proc~ocean_lateral_mix_compute_vel_scale->local proc~ocean_slopes_build_e ocean_slopes_build_e proc~ocean_slopes_compute_impl->proc~ocean_slopes_build_e proc~ocean_slopes_mask_open_column ocean_slopes_mask_open_column proc~ocean_slopes_compute_impl->proc~ocean_slopes_mask_open_column proc~ocean_slopes_pass_x ocean_slopes_pass_x proc~ocean_slopes_compute_impl->proc~ocean_slopes_pass_x proc~ocean_slopes_pass_y ocean_slopes_pass_y proc~ocean_slopes_compute_impl->proc~ocean_slopes_pass_y proc~ocean_slopes_vert_fill_ts ocean_slopes_vert_fill_ts proc~ocean_slopes_compute_impl->proc~ocean_slopes_vert_fill_ts proc~apply_sw_penetration_cover_impl apply_sw_penetration_cover_impl proc~ocean_surface_flux_apply_sw_penetration->proc~apply_sw_penetration_cover_impl proc~apply_sw_penetration_impl apply_sw_penetration_impl proc~ocean_surface_flux_apply_sw_penetration->proc~apply_sw_penetration_impl proc~apply_surface_restore_2d_cover_impl apply_surface_restore_2d_cover_impl proc~ocean_surface_restore_apply_tracers->proc~apply_surface_restore_2d_cover_impl proc~apply_surface_restore_2d_impl apply_surface_restore_2d_impl proc~ocean_surface_restore_apply_tracers->proc~apply_surface_restore_2d_impl proc~pd_limit_meridional_impl->local proc~pd_limit_meridional_impl->reduce proc~pd_limit_zonal_impl->local proc~pd_limit_zonal_impl->reduce proc~find_or_create_region find_or_create_region proc~profiler_start->proc~find_or_create_region proc~get_wall_time get_wall_time proc~profiler_start->proc~get_wall_time proc~nvtx_range_push nvtx_range_push proc~profiler_start->proc~nvtx_range_push proc~profiler_stop->proc~get_wall_time proc~nvtx_range_pop nvtx_range_pop proc~profiler_stop->proc~nvtx_range_pop proc~surfstress_compute_impl->local proc~surfstress_distributed_impl->local proc~tidal_mixing_column_kernel tidal_mixing_column_kernel proc~tidal_mixing_compute->proc~tidal_mixing_column_kernel proc~top_drag_stress_mag_impl->local proc~top_drag_tendencies_impl->local proc~tracer_advect_meridional_one_impl tracer_advect_meridional_one_impl proc~tracer_advect_meridional->proc~tracer_advect_meridional_one_impl proc~tracer_advect_vertical_one_impl->local proc~tracer_advect_zonal_one_impl tracer_advect_zonal_one_impl proc~tracer_advect_zonal->proc~tracer_advect_zonal_one_impl proc~tracer_hdiff_one_impl->local proc~diffuse_velocity_columns_impl diffuse_velocity_columns_impl proc~vdiff_apply_momentum->proc~diffuse_velocity_columns_impl proc~fill_bbl_constants fill_bbl_constants proc~vdiff_apply_momentum->proc~fill_bbl_constants proc~fill_kv_scalar_buf fill_kv_scalar_buf proc~vdiff_apply_momentum->proc~fill_kv_scalar_buf proc~vdiff_apply_tracers->error proc~apply_factored_tracer apply_factored_tracer proc~vdiff_apply_tracers->proc~apply_factored_tracer proc~build_factorize_tracer_matrix build_factorize_tracer_matrix proc~vdiff_apply_tracers->proc~build_factorize_tracer_matrix proc~vdiff_apply_tracers->proc~fill_kv_scalar_buf proc~visc_rem_halo_refresh->proc~ocean_halo_is_decomposed_x proc~visc_rem_halo_refresh->proc~ocean_halo_is_decomposed_y interface~ocean_halo_face_x ocean_halo_face_x proc~visc_rem_halo_refresh->interface~ocean_halo_face_x interface~ocean_halo_face_y ocean_halo_face_y proc~visc_rem_halo_refresh->interface~ocean_halo_face_y proc~ocean_fold_wrap_visc_rem ocean_fold_wrap_visc_rem proc~visc_rem_halo_refresh->proc~ocean_fold_wrap_visc_rem proc~ocean_periodic_wrap_face_x_3d ocean_periodic_wrap_face_x_3d proc~visc_rem_halo_refresh->proc~ocean_periodic_wrap_face_x_3d proc~ocean_periodic_wrap_face_y_3d ocean_periodic_wrap_face_y_3d proc~visc_rem_halo_refresh->proc~ocean_periodic_wrap_face_y_3d proc~visc_rem_precompute->proc~vdiff_apply_momentum proc~visc_rem_precompute->proc~visc_rem_halo_refresh proc~vmix_add_kv_ml_invz2->local proc~vmix_convection_impl vmix_convection_impl proc~vmix_apply_convection->proc~vmix_convection_impl proc~vmix_kpp_overlay_impl vmix_kpp_overlay_impl proc~vmix_apply_kpp_overlay->proc~vmix_kpp_overlay_impl proc~vmix_assemble_clip_henyey_impl vmix_assemble_clip_henyey_impl proc~vmix_assemble->proc~vmix_assemble_clip_henyey_impl proc~vmix_assemble_clip_impl vmix_assemble_clip_impl proc~vmix_assemble->proc~vmix_assemble_clip_impl proc~vmix_assemble_clip_profile_impl vmix_assemble_clip_profile_impl proc~vmix_assemble->proc~vmix_assemble_clip_profile_impl proc~vmix_bkgnd_fill_impl vmix_bkgnd_fill_impl proc~vmix_assemble->proc~vmix_bkgnd_fill_impl proc~vmix_guard_impl vmix_guard_impl proc~vmix_assemble->proc~vmix_guard_impl proc~vmix_resolve_kd_min vmix_resolve_kd_min proc~vmix_assemble->proc~vmix_resolve_kd_min proc~vmix_smooth_121_impl vmix_smooth_121_impl proc~vmix_assemble->proc~vmix_smooth_121_impl proc~vmix_compute_pp81->local proc~vmix_split_ddiff_eos_impl vmix_split_ddiff_eos_impl proc~vmix_split_kd_heat_salt->proc~vmix_split_ddiff_eos_impl proc~vmix_split_ddiff_impl vmix_split_ddiff_impl proc~vmix_split_kd_heat_salt->proc~vmix_split_ddiff_impl proc~vmix_split_kd_heat_salt_impl vmix_split_kd_heat_salt_impl proc~vmix_split_kd_heat_salt->proc~vmix_split_kd_heat_salt_impl

Called by

proc~~run_stage~~CalledByGraph proc~run_stage run_stage proc~ocean_dyn_step ocean_dyn_step proc~ocean_dyn_step->proc~run_stage proc~engine_step engine_step proc~engine_step->proc~ocean_dyn_step proc~driver_run_ocean driver_run_ocean proc~driver_run_ocean->proc~engine_step proc~rdb_ocean_step rdb_ocean_step proc~rdb_ocean_step->proc~engine_step proc~driver_run driver_run proc~driver_run->proc~driver_run_ocean

Variables

Type Visibility Attributes Name Initial
logical, private :: fold_top

.true. when the ice-shelf top drag is folded into the vdiff k = nz diagonal — see the gate note at the vmix_apply_in_stage call below for why the test is implicit_fold, not present(td).

integer, private :: i_ss

Loop/extent locals for the inline stress_shelf publish.

integer, private :: j_ss

Loop/extent locals for the inline stress_shelf publish.

integer, private :: nx_ss

Loop/extent locals for the inline stress_shelf publish.

integer, private :: ny_ss

Loop/extent locals for the inline stress_shelf publish.

logical, private :: publish_shelf

.true. when the ice-shelf top-drag slot is live and its stress_top is therefore full-sized and freshly written.

logical, private :: therm_active
real(kind=wp), private :: therm_dt

Source Code

   subroutine run_stage(grid, metrics, dyn, eos, cor, ct, pgf, hv, bd, ss, va, hd, vd, vmix, ms, dt, stage, sf, geo, lateral_mix, epbl, kshear, slopes, vmix_tidal, td, cav)
      !! One FE stage of the multilayer step.  Order of operations:
      !!
      !!   1. EOS: rho_layer <- linear(T, S)
      !!   2. Velocity-tendency computes — Coriolis, PGF, hvisc,
      !!      bottom drag, surface stress.  All read h_old, u, v
      !!      and write to their own tendency buffers; none touch
      !!      h yet.
      !!   3. continuity_tracer_step_split — interleaved
      !!      Lie-split horizontal step: zonal flux + tracer zonal +
      !!      apply zonal + meridional flux + tracer meridional +
      !!      apply meridional.  Updates h AND hTr together; the
      !!      CWC discrete theorem holds (uniform T stays uniform).
      !!   4. tracer_hdiff — Laplacian diffusion on hTr.
      !!   5. compute_w_from_continuity — diagnose w from the total
      !!      horizontal divergence stored in `flux_h_layer`.
      !!   6. tracer_advect_vertical — upwind-in-z + h update that
      !!      cancels the horizontal h change (Eulerian-z mode).
      !!   7. Velocity-tendency applies (Coriolis, PGF, hvisc, drag,
      !!      surface stress) — all additive.
      !!   8. Surface tracer fluxes (heat, salt).
      !!   9. Vertical mixing closure + vdiff.
      type(hgrid_t), intent(in) :: grid
      type(ocean_metrics_t), intent(in) :: metrics
         !! Curvilinear horizontal metrics — forwarded to the PGF.
      type(ocean_dyn_t), intent(in) :: dyn
      type(eos_t), intent(in) :: eos
      type(coriolis_adv_t), intent(inout) :: cor
      type(continuity_t), intent(inout) :: ct
      type(ocean_pressure_force_t), intent(inout) :: pgf
      type(ocean_horizontal_viscosity_t), intent(inout) :: hv
      type(ocean_bottom_drag_t), intent(inout) :: bd
      type(ocean_top_drag_t), intent(inout), optional :: td
         !! Ice-shelf TOP-drag slot (`&ocean_tdrag_nml`).  OPTIONAL so the
         !! many direct `ocean_dyn_step*` / `run_stage*` call sites in the
         !! test suite need no churn; the production driver always passes
         !! it.  Absent, or present and disabled, => no kernel launch and
         !! a bit-identical step.
      type(ocean_cavity_flux_t), intent(inout), optional :: cav
         !! Ice-shelf basal-melt slot (`&ocean_cavity_melt_nml`).
         !! OPTIONAL for the same reason `td` is: the direct
         !! `ocean_dyn_step*` / `run_stage*` call sites in the test suite
         !! need no churn, and the production driver always passes it.
         !! Absent, disabled, or `freshwater="virtual"` => no kernel
         !! launch and a bit-identical step.  It is threaded down here
         !! rather than acted on in `engine_step_finalize` because the
         !! real-freshwater volume must be spent in the SAME stage, at
         !! the SAME stage weight and from the SAME `melt` value as the
         !! salt and heat halves the surface-flux apply spends -- see
         !! `ocean_cavity_mass_step`'s docstring.
      type(ocean_surface_stress_t), intent(inout) :: ss
      type(ocean_vertical_advection_t), intent(inout) :: va
      type(ocean_hdiff_tracer_t), intent(inout) :: hd
      type(ocean_vdiff_t), intent(inout) :: vd
      type(ocean_vmix_t), intent(inout) :: vmix
      type(multilayer_state_t), intent(inout) :: ms
      real(wp), intent(in) :: dt
      integer, intent(in) :: stage
         !! RK2 stage (1 or 2); see vmix_apply_in_stage.
      type(ocean_surface_flux_t), intent(in), optional :: sf
      type(ocean_geothermal_t), intent(in), optional :: geo
         !! Geothermal bottom-heat-flux slot.  See `ocean_dyn_step`.
      type(ocean_lateral_mix_t), intent(inout), optional :: lateral_mix
      type(ocean_epbl_t), intent(inout), optional :: epbl
      type(ocean_kappa_shear_t), intent(inout), optional :: kshear
      type(ocean_slopes_t), intent(inout), optional :: slopes
      type(ocean_tidal_mixing_t), intent(inout), optional :: vmix_tidal

      logical :: therm_active
      logical :: fold_top
         !! `.true.` when the ice-shelf top drag is folded into the vdiff
         !! `k = nz` diagonal — see the gate note at the `vmix_apply_in_stage`
         !! call below for why the test is `implicit_fold`, not `present(td)`.
      logical :: publish_shelf
         !! `.true.` when the ice-shelf top-drag slot is live and its
         !! `stress_top` is therefore full-sized and freshly written.
      integer :: i_ss, j_ss, nx_ss, ny_ss
         !! Loop/extent locals for the inline `stress_shelf` publish.
      real(wp) :: therm_dt

      therm_active = dyn%enable_thermodynamics .and. dyn%is_thermo_step()
      therm_dt = dyn%therm_dt(dt)

      ! EOS is DYNAMICS, not thermodynamics: rho_layer feeds the baroclinic
      ! PGF every step. Gating it on `is_thermo_step()` zero-order-holds the
      ! restoring force of the internal-gravity-wave oscillator for
      ! tau = (dt_therm_ratio-1)*dt, which is a delayed-restoring-force
      ! instability: sigma ~ omega^2*tau/2, unstable for ANY tau > 0, maximal
      ! at the grid scale. Measured on eady: sigma ∝ alpha_T ∝ N^2, sigma ∝ k^2,
      ! the mode is the diagonal 2-delta checkerboard, and the rate recovers
      ! the mode-2 internal wave speed. Survival was only ever by viscosity
      ! margin (nu*k^2 > sigma) — eady at nu_h=100 is marginal and blows up;
      ! double_gyre at nu_h=10000 merely looks fine.
      !
      ! So recompute rho EVERY dynamics step whenever thermodynamics is on.
      ! The EXPENSIVE thermo (mixing, ALE remap, tracer advection/hdiff,
      ! surface fluxes) stays on the slow `therm_active` cadence below, which
      ! is where the cost actually is. Bit-identical at dt_therm_ratio = 1,
      ! where is_thermo_step() is always true.
      call ocean_eos_compute(eos, ms, active=dyn%enable_thermodynamics)
      call coriolis_adv_compute_tendencies(grid, metrics, cor, ms)
      call ocean_pressure_force_compute(grid, metrics, pgf, ms, eos=eos)
      call ocean_lateral_mix_compute(grid, metrics, lateral_mix, ms)
      call ocean_horizontal_viscosity_compute_tendencies(grid, metrics, hv, ms, &
                                                         lateral_mix=lateral_mix, dt=dt)
      ! KE dissipation rate for the MEKE frictional source — captured here
      ! (du_visc fresh, u_face still pre-viscous) before the apply below.
      ! No-op unless MEKE's frictional source is enabled.
      call ocean_horizontal_viscosity_compute_ke_diss(hv, ms)
      call ocean_bottom_drag_compute_tendencies(grid, bd, ms, dt)
      call ocean_channel_drag_compute_tendencies(grid, metrics, bd, ms)
      ! Ice-shelf top drag (`&ocean_tdrag_nml`).  Sits with the other slow
      ! velocity-tendency computes; the kernel returns immediately when the
      ! slot is disabled, so an ordinary run pays one host branch.
      if (present(td)) call ocean_top_drag_compute_tendencies(td, ms, dt)
      ! Phase 4b: publish the ice-shelf base stress that BOTH boundary-
      ! layer schemes take `u_*` from.  Under a shelf the wind has been
      ! masked out of `tau` (so `stress_mag` is exactly 0 there) and the
      ! turbulent boundary layer is driven by the ice-ocean stress
      ! instead — `u_*^2 = |tau_top|/rho_0`.
      !
      ! Written INLINE as a `do concurrent`, not as a call handing
      ! `ss%stress_shelf` to an external subroutine: a host-gated call
      ! with a state array as an actual makes nvfortran treat the array
      ! as escaping and pessimises every `do concurrent` in this routine
      ! (CLAUDE.md, measured at +4.8%% on an inert porous pass).
      !
      ! Gated on `td%enable`, not `present(td)`: a DISABLED slot carries
      ! a `(1,1)` placeholder `stress_top`.
      !
      ! Placed here — after the top-drag compute, before
      ! `vmix_apply_in_stage` below — so KPP/EPBL read THIS stage's
      ! stress.  No lag.
      publish_shelf = .false.
      if (present(td)) publish_shelf = td%enable
      if (publish_shelf) then
         nx_ss = size(ss%stress_shelf, 1)
         ny_ss = size(ss%stress_shelf, 2)
         do concurrent(j_ss=1:ny_ss, i_ss=1:nx_ss)
            ss%stress_shelf(i_ss, j_ss) = td%stress_top(i_ss, j_ss)
         end do
      end if
      call ocean_surface_stress_compute_tendencies(grid, ss, ms)

      ! Horizontal step + tracer chain.  Continuity-tracer is
      ! unconditional (the h advection lives here regardless of
      ! thermodynamics); the tracer-only kernels self-gate on
      ! `therm_active`.
      !
      ! Phase 2 (6b) horizontal-tracer-advect cadence dispatch
      ! (`dt_tracer_advect_ratio`):
      !   ratio == 1 (default) → the existing every-step fused
      !     continuity+tracer kernel runs verbatim ⇒ bit-identical.
      !   ratio  > 1 → TR_MODE_ACCUMULATE: advance h + accumulate
      !     0.5·mass_flux·dt into ct%uhtr/vhtr per RK2 stage (hTr frozen);
      !     the boundary drain in `ocean_dyn_step` spends them.
      if (dyn%dt_tracer_advect_ratio <= 1) then
         call continuity_tracer_step_split(grid, metrics, ct, ms, dt)
      else
         call continuity_tracer_step_split(grid, metrics, ct, ms, dt, &
                                           tracer_mode=TR_MODE_ACCUMULATE)
      end if
      call tracer_hdiff(grid, metrics, hd, ms, therm_dt, active=therm_active)
      ! Mass budget: flux_h_layer now holds the total horizontal divergence
      ! (the same field compute_w_from_continuity reads).  Accumulate the
      ! boundary mass outflux for this RK2 stage (weight 0.5, since rk2_average
      ! halves each stage's contribution); vertical advection + ALE remap only
      ! redistribute within a column, so they don't affect the column-mass
      ! budget.  Closes the ocean mass Error to round-off with open BCs.
      call ocean_accumulate_mass_out(ms, ms%flux_h_layer, metrics%areaT, &
                                     grid%nghost, dt, 0.5_wp)
      call compute_w_from_continuity(grid, va, ms)
      call tracer_advect_vertical(grid, va, ms, therm_dt, active=therm_active)

      ! Velocity-side applies (no thermodynamics gate).  Async-chained on
      ! OpenACC queue 1 (additive accumulations onto u_face/v_face, FIFO-
      ! ordered).  The interleaved tracer applies below run on the default
      ! queue but touch disjoint arrays (hTr), so there is no cross-queue
      ! race.  ONE `!$acc wait(1)` before vmix — the first device consumer
      ! that reads the applied u_face/v_face (shear).
      call coriolis_adv_apply_tendencies(cor, ms, dt, no_wait=.true.)
      call ocean_pressure_force_apply(pgf, ms, dt, no_wait=.true.)
      call ocean_horizontal_viscosity_apply_tendencies(hv, ms, dt, no_wait=.true.)
      ! Double-count guard: when the bottom drag / wind stress are folded
      ! into the implicit vdiff tridiagonal (`&ocean_vdiff_nml implicit_*`),
      ! their explicit pre-solve applies are SKIPPED here so the forcing is
      ! not applied twice.  Channel (side-wall) drag is a distinct lateral
      ! term and always applies.  Defaults (both off) ⇒ both applies run ⇒
      ! bit-identical to the prior path.  The MOM6 BBL glue (`bbl_glue`)
      ! is the same kind of fold: its piston IS the bed drag, so the
      ! explicit (or `&ocean_bdrag_nml implicit` split-apply) one is skipped.
      if (.not. (vd%implicit_drag .or. vd%bbl_glue)) then
         call ocean_bottom_drag_apply_tendencies(bd, ms, dt, no_wait=.true.)
      end if
      call ocean_channel_drag_apply_tendencies(bd, ms, dt, no_wait=.true.)
      ! Top drag: same double-count guard as the bed.  `implicit_fold`
      ! (`&ocean_vdiff_nml implicit_top_drag`) folds the rate into the
      ! vdiff `k = nz` diagonal instead, so the explicit apply is skipped
      ! there.
      if (present(td)) then
         if (.not. td%implicit_fold) then
            call ocean_top_drag_apply_tendencies(td, ms, dt, no_wait=.true.)
         end if
      end if
      if (.not. vd%implicit_stress) then
         call ocean_surface_stress_apply_tendencies(ss, ms, dt, no_wait=.true.)
      end if

      ! Surface tracer fluxes, geothermal bottom flux, ideal-age, vmix.
      call ocean_surface_flux_apply_tracers(grid, sf, ms, therm_dt, active=therm_active)
      ! Ice-shelf real freshwater MASS (&ocean_cavity_melt_nml
      ! freshwater='mass').  Immediately after the surface-flux apply,
      ! because it REPLACES that apply's virtual cavity salt increment
      ! with the real advective one and adds the meltwater volume + its
      ! enthalpy in the same stage, at the same weight, from the same
      ! `melt`.  Absent / disabled / 'virtual' => immediate return.
      ! Weight 0.5 per SSP-RK2 stage, matching ocean_accumulate_mass_out.
      if (present(cav)) then
         call ocean_cavity_mass_step(grid, metrics, cav, ms, therm_dt, 0.5_wp, &
                                     active=therm_active)
      end if
      call apply_sw_and_restore(grid, metrics, sf, ms, therm_dt, therm_active)
      call ocean_geothermal_apply_tracers(grid, geo, ms, therm_dt, active=therm_active)
      ! Ideal-age interior aging only (PR-7): thermo-cadence gated, mirrors
      ! its tracer-kernel neighbours above.  The surface Dirichlet reset is
      ! NOT here — it runs once per outer step, after rk2_average, in
      ! `ocean_dyn_step` (a per-stage reset is halved by the RK2 average).
      call ocean_ideal_age_apply(grid, ms, therm_dt, active=dyn%is_thermo_step())

      ! Isopycnal-slope diagnostics — purely diagnostic, refreshed at
      ! thermo cadence (same gate as the lateral closures it feeds).
      ! No-op when absent / disabled (bit-identical).
      if (present(slopes) .and. therm_active) then
         if (slopes%enable) then
            call ocean_slopes_compute(grid, metrics, eos, slopes, ms, therm_dt)
         end if
      end if

      !$acc wait(1)
      ! No `bt_work` here: the unsplit path has no BT correction at all,
      ! so there is no consumer for visc_rem — do_remnant stays .false.
      ! The top-drag fold arrays are handed over as ARRAYS, not as the
      ! slot: `td` is optional here, and dereferencing an absent
      ! derived-type dummy is not allowed, whereas forwarding an absent
      ! optional ARRAY dummy on to another optional dummy is.
      !
      ! GATED ON `implicit_fold`, NOT on `present(td)`.  A DISABLED
      ! top-drag slot carries PLACEHOLDER-sized arrays, and the
      ! explicit-shape `(nu, nv)` dummy down in
      ! `diffuse_velocity_columns_impl` is mapped by nvfortran
      ! UNCONDITIONALLY — the `if (do_top)` guard inside the kernel is a
      ! runtime branch the compiler cannot see.  Handing over a `(2,1)`
      ! placeholder therefore aborts the GPU build with "variable in data
      ! clause is partially present", which is exactly what it did before
      ! this gate.  The fold requires `&ocean_tdrag_nml enable`
      ! (validate_config), so when it is on the arrays are full size.
      fold_top = .false.
      if (present(td)) fold_top = td%implicit_fold
      if (fold_top) then
         call vmix_apply_in_stage(grid, dyn, vmix, vd, ss, bd, ms, dt, stage, sf, epbl=epbl, kshear=kshear, &
                                  vmix_tidal=vmix_tidal, metrics=metrics, &
                                  lambda_top_u=td%lambda_top_u, lambda_top_v=td%lambda_top_v, &
                                  cover_u=td%cover_u, cover_v=td%cover_v)
      else
         call vmix_apply_in_stage(grid, dyn, vmix, vd, ss, bd, ms, dt, stage, sf, epbl=epbl, kshear=kshear, &
                                  vmix_tidal=vmix_tidal, metrics=metrics)
      end if
   end subroutine run_stage