subroutine ocean_state_init(this, grid)
!! Construct the ocean god state. Each slot's `init` allocates its
!! own arrays; the DEFAULT-OFF closures (EPBL, kappa-shear, tidal
!! mixing, GM, Redi, MLE/Fox-Kemper, VarMix, MEKE, isopycnal slopes)
!! are gated on their `enable` flag so a plain run does not pay their
!! multi-GB footprint. This requires the enable flags to be set
!! BEFORE `init` — `ocean_state_init_from_config` hoists them above
!! its `call this%init(grid)` for exactly this reason. The gated
!! closures' runtime kernels already early-return on `.not. enable`
!! (and `enter_data`/`exit_data` are gated in the parent walk), so a
!! gated-off slot is never touched with unallocated arrays.
class(ocean_state_t), intent(inout) :: this
type(hgrid_t), intent(in) :: grid
logical :: need_slopes
! Isopycnal slopes feed GM (and the standalone slope diffusivity);
! Redi and MLE compute their own coefficients and do NOT read slopes.
need_slopes = this%slopes%enable .or. this%gm%enable
call this%barotropic%init(grid)
call this%metrics%init(grid)
if (this%use_multilayer) then
call this%multilayer%init(grid, with_ideal_age=this%enable_ideal_age)
! Pseudo-salt registration MUST happen here — after multilayer%init
! (so the registry exists), before enter_data (registry_locked
! guard) and, critically, before ocean_bc_state_init below sizes
! bc%n_tracers (§2.5 of the plan: registering after that call
! silently skips the new tracer at OBC-clamped edges).
if (this%enable_pseudo_salt) call ocean_pseudo_salt_register(this%multilayer, grid)
call this%dyn%init(grid, nz_ml=this%multilayer%nz_ml)
else
call this%dyn%init(grid)
end if
! the ocean is always multilayer
if (this%use_multilayer) then
call this%continuity%init(grid, nz_ml=this%multilayer%nz_ml)
call this%coriolis_adv%init(grid, nz_ml=this%multilayer%nz_ml)
call this%pressure_force%init(grid, nz_ml=this%multilayer%nz_ml)
call this%hvisc%init(grid, nz_ml=this%multilayer%nz_ml)
call this%bdrag%init(grid, nz_ml=this%multilayer%nz_ml)
call this%tdrag%init(grid, nz_ml=this%multilayer%nz_ml)
call this%surface_stress%init(grid, nz_ml=this%multilayer%nz_ml)
call this%surface_flux%init(grid)
call this%cavity_flux%init(grid)
call this%vert_advect%init(grid, nz_ml=this%multilayer%nz_ml)
call this%hdiff_tracer%init(grid, nz_ml=this%multilayer%nz_ml)
call this%vdiff%init(grid, nz_ml=this%multilayer%nz_ml)
else
call this%continuity%init(grid)
call this%coriolis_adv%init(grid)
call this%pressure_force%init(grid)
call this%hvisc%init(grid)
call this%bdrag%init(grid)
call this%tdrag%init(grid)
call this%surface_stress%init(grid)
call this%surface_flux%init(grid)
call this%cavity_flux%init(grid)
call this%vert_advect%init(grid)
call this%hdiff_tracer%init(grid)
call this%vdiff%init(grid)
end if
! Always-on vertical mixing (PP81/KPP base) + horizontal viscosity
! (harmonic/biharmonic) back the production envelope, so they are
! unconditional. The eddy/alternative closures below are gated.
if (this%use_multilayer) then
call this%vmix%init(grid, nz_ml=this%multilayer%nz_ml)
call this%lateral_mix%init(grid, nz_ml=this%multilayer%nz_ml)
if (this%epbl%enable) call this%epbl%init(grid, nz_ml=this%multilayer%nz_ml)
if (this%kshear%enable) call this%kshear%init(grid, nz_ml=this%multilayer%nz_ml)
if (this%vmix_tidal%enable) call this%vmix_tidal%init(grid, nz_ml=this%multilayer%nz_ml)
if (need_slopes) call this%slopes%init(grid, nz_ml=this%multilayer%nz_ml)
if (this%mle%enable) call this%mle%init(grid, nz_ml=this%multilayer%nz_ml)
if (this%gm%enable) call this%gm%init(grid, nz_ml=this%multilayer%nz_ml)
if (this%redi%enable) call this%redi%init(grid, nz_ml=this%multilayer%nz_ml)
if (this%varmix%enable) call this%varmix%init(grid, nz_ml=this%multilayer%nz_ml)
if (this%meke%enable) call this%meke%init(grid, nz_ml=this%multilayer%nz_ml)
else
call this%vmix%init(grid)
call this%lateral_mix%init(grid)
if (this%epbl%enable) call this%epbl%init(grid)
if (this%kshear%enable) call this%kshear%init(grid)
if (this%vmix_tidal%enable) call this%vmix_tidal%init(grid)
if (need_slopes) call this%slopes%init(grid)
if (this%mle%enable) call this%mle%init(grid)
if (this%gm%enable) call this%gm%init(grid)
if (this%redi%enable) call this%redi%init(grid)
if (this%varmix%enable) call this%varmix%init(grid)
if (this%meke%enable) call this%meke%init(grid)
end if
call this%wavespeed%init(grid)
call this%eos%init(grid)
if (this%use_multilayer) then
call this%vcoord%init(grid, nz_ml=this%multilayer%nz_ml)
else
call this%vcoord%init(grid)
end if
call this%tides%init(grid)
call this%p_surf%init(grid)
if (this%ice%enable) call this%ice%init(grid)
call this%obc%init(grid)
if (this%use_multilayer) then
call ocean_bc_state_init(this%bc, grid, nz_ml=this%multilayer%nz_ml, &
n_tracers=size(this%multilayer%tracers))
! PR-23: gated call (mirrors epbl/kshear/...) — `ocean_sponge_init`
! only allocates the (potentially large) idamp/ref_tracer arrays
! when `enable`, so a disabled sponge (default) never allocates.
if (this%sponge%enable) then
call this%sponge%init(grid, nz_ml=this%multilayer%nz_ml, &
n_tracers=size(this%multilayer%tracers))
end if
else
call ocean_bc_state_init(this%bc, grid, nz_ml=1)
end if
call this%diag%init(grid)
#ifndef RDB_NO_NETCDF
call this%data_input%init()
#endif
call this%restart%init()
this%is_init = .true.
end subroutine ocean_state_init