Seed the cfg-derived scalars the slot inits read up front (layer count, ideal-age toggle), allocate via init(grid), then override the linear-EOS params (after eos%init has set its defaults). Carries the ocean branch that state_init_from_config held before the coastal / ocean state split — the order (nz_ml + ideal_age before init, eos after) is load-bearing and matches the pre-split behaviour.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_state_t), | intent(inout) | :: | this | |||
| type(config_t), | intent(in) | :: | cfg | |||
| type(hgrid_t), | intent(in) | :: | grid |
subroutine ocean_state_init_from_config(this, cfg, grid) !! Seed the cfg-derived scalars the slot inits read up front (layer !! count, ideal-age toggle), allocate via init(grid), then override the !! linear-EOS params (after eos%init has set its defaults). Carries the !! ocean branch that state_init_from_config held before the coastal / !! ocean state split — the order (nz_ml + ideal_age before init, eos !! after) is load-bearing and matches the pre-split behaviour. class(ocean_state_t), intent(inout) :: this type(config_t), intent(in) :: cfg type(hgrid_t), intent(in) :: grid this%multilayer%nz_ml = cfg%nz_layers this%enable_ideal_age = cfg%ocean%tracers%enable_ideal_age this%enable_pseudo_salt = cfg%ocean%tracers%enable_pseudo_salt ! Enable flags govern CONDITIONAL ALLOCATION (ocean_state_init gates ! each default-off closure's array allocation on its `enable`), so ! they must be latched BEFORE init(grid). The full per-closure knob ! copy still runs after init (below) and re-sets these idempotently; ! MEKE and Fox-Kemper/MLE otherwise get their enable only in the ! later configure_ocean_* pass, so they are seeded from cfg here too. ! Windowed tracer advection (Phase 2/6b): its 13-array workspace ! (~3.7 GiB at 600²x100) is only consumed at ratio > 1, so the ! allocation gate latches here like the closures below. this%continuity%windowed_advection = cfg%ocean%vmix%dt_tracer_advect_ratio > 1 ! Pressure-force scratch: 11 of the 16 buffers are FV_MOM6- or ! in-layer-reconstruction-only (~3.5 GB at 1000x800x50) and are ! unreachable on the shipped gprime / montgomery / fv_lite envelope. ! `variant` + `reconstruct_for_pressure` therefore latch HERE, ahead ! of init(grid), and `scratch_gated` turns the per-variant gate on; ! `configure_ocean_pgf` re-sets both idempotently later. Direct ! `pgf%init(...)` call sites leave `scratch_gated = .false.` and keep ! the allocate-everything behaviour. this%pressure_force%variant = parse_opgf_variant(cfg%ocean%pgf%form) this%pressure_force%reconstruct_for_pressure = cfg%ocean%pgf%reconstruct_for_pressure ! Grounded-layer PGF gate: for FV_MOM6 the `z_centre` buffer exists only ! to feed this gate, so the flag has to be known BEFORE the allocation ! gate runs. It is a pure config-time decision, so latch it here next to ! `variant`; `configure_ocean_pgf` recomputes it (and error-stops if the ! latch drifted) for the FV_LITE / FV_WRIGHT paths too. this%pressure_force%skip_nonoverlap = & pgf_nonoverlap_gate_on(cfg, this%pressure_force%variant) this%pressure_force%scratch_gated = .true. ! Ice-shelf cavity geometry: `use_cavity` gates the allocation of ! the three static metrics fields (`z_draft`, `cover_frac`, ! `p_ice_ref`), so it latches HERE — and it has to be earlier than ! most: the draft is filled inside `ocean_state_seed_from_cfg`, ! which is the first thing the engine does after this, long before ! any `configure_ocean_*` pass. Off ⇒ three `(1,1)` placeholders. this%metrics%use_cavity = cfg%ocean%cavity_dyn%enable ! Ice-shelf basal melt: the melt slot's own gate, latched here for ! the same reason (its `init` sizes eleven 2-D arrays off it). this%cavity_flux%enable = cfg%ocean%cavity_melt%enable ! Ice-shelf top drag: same gate discipline — its `init` sizes the ! two face scratch buffers and five 2-D fields off `enable`. this%tdrag%enable = cfg%ocean%tdrag%enable this%epbl%enable = cfg%ocean%epbl%enable this%kshear%enable = cfg%ocean%kshear%enable this%vmix_tidal%enable = cfg%ocean%tidal_mixing%enable this%slopes%enable = cfg%ocean%slopes%enable this%gm%enable = cfg%ocean%gm%enable this%redi%enable = cfg%ocean%redi%enable this%varmix%enable = cfg%ocean%varmix%enable this%meke%enable = cfg%ocean%meke%enable this%mle%enable = cfg%ocean%foxkemper%enable ! Sea ice (PR 0 scaffold): enable gates the slot's init + ! enter_data/exit_data; ncat/nk_ice size the per-category arrays ! once PR 3+ allocates them, so all three latch before init like ! the closures above. this%ice%enable = cfg%ocean%ice%enable this%ice%ncat = cfg%ocean%ice%ncat this%ice%nk_ice = cfg%ocean%ice%nk_ice ! PR 4b: transport latches before init too (gates the workspace ! allocation, memory Rule 2 — see rdb_ice_state%init). this%ice%transport = cfg%ocean%ice%transport ! PR 5: EVP dynamics master flag (gates the driver's ice_evp_step ! call + the transport sampler skip; no per-slot allocation gate — ! str_d/str_t/str_s/tau_a_*/fxoc/fyoc are unconditional whenever the ! ice slot is live, same contract as u_ice/v_ice). this%ice%dynamics = cfg%ocean%ice%dynamics ! PR-23: enable gates the sponge's (potentially large, 4-D ! nx*ny*nz*n_tracers) reference-state allocation, so it latches ! before init like the closures above (`ocean_sponge_init` is only ! called when `this%sponge%enable`, see below). this%sponge%enable = cfg%ocean%sponge%enable ! PR-58: hlim latches before init (ice_itd_category_bounds runs ! inside ice%init). Unallocated => the hardcoded SIS2 default table. block integer :: n_hlim n_hlim = ice_hlim_count(cfg%ocean%ice%hlim) if (n_hlim > 0) this%ice%hlim_cfg = cfg%ocean%ice%hlim(1:n_hlim) ! allocate-on-assign end block ! PR 26: snowfall's host-side dispatch gate — latches before init ! like transport/dynamics above (no per-slot allocation gate; ! atm_fprec/snow_part_ocn/fprec_ocn_diag are unconditional whenever ! the ice slot is live, same contract as u_ice/v_ice). This is what ! makes `snowfall=0` byte-identical BY CONSTRUCTION. this%ice%has_snowfall = (cfg%ocean%ice%snowfall /= 0.0_wp) ! PR 27: Archimedes snow-ice flood master flag — latches before ! init like has_snowfall/transport/dynamics above (no per-slot ! allocation gate; snow_to_ice is unconditional whenever the ice ! slot is live, same contract as sw_thru). This is what makes ! `snow_ice=.false.` byte-identical BY CONSTRUCTION. this%ice%snow_ice = cfg%ocean%ice%snow_ice call this%init(grid) #ifndef RDB_NO_NETCDF ! `this%init(grid)` above already built a default-sized (16 slot, ! quiet) reader — safe to re-run with the real config now, since ! nothing can have been registered between the two calls (grid ! init happens before any consumer registration, and registration ! itself only happens after this returns — see the seam contract ! in rdb_ocean_data_input's module docstring). call this%data_input%init(cfg%ocean%data) #endif ! Linear-EOS reference state, all five members off `&ocean_ic_nml`. ! This runs before `ocean_state_enter_data` AND before the ! `configure_ocean_*` pass that copies the whole flat-POD handle ! onto the closure slots that carry their own copy ! (`vmix%eos`, `epbl%eos`, `kshear%eos`, `tidal_mixing%eos` — ! `rdb_ocean_setup.F90`), so every rider and every device kernel ! that takes `eos_t` by value sees the configured values. Defaults ! equal the `eos_t` component defaults ⇒ bit-identical. this%eos%alpha_T = cfg%ocean%ic%alpha_T this%eos%beta_S = cfg%ocean%ic%beta_S this%eos%T_ref = cfg%ocean%ic%T_ref this%eos%S_ref = cfg%ocean%ic%S_ref this%eos%rho0 = cfg%ocean%ic%rho_0 ! EPBL master switch is read here (before the configure_ocean_* ! pass) because diag registration — which gates the MLD_EPBL / ! Kd_EPBL variables on it — runs before configure in the driver. this%epbl%enable = cfg%ocean%epbl%enable this%wavespeed%enable = cfg%ocean%wavespeed%enable this%kshear%enable = cfg%ocean%kshear%enable this%slopes%enable = cfg%ocean%slopes%enable this%slopes%kd_smooth = cfg%ocean%slopes%kd_smooth this%slopes%min_dz_for_n2 = cfg%ocean%slopes%min_dz_for_n2 this%slopes%rho0 = cfg%ocean%ic%rho_0 this%gm%enable = cfg%ocean%gm%enable this%gm%khth = cfg%ocean%gm%khth this%gm%khth_max_cfl = cfg%ocean%gm%khth_max_cfl this%gm%khth_slope_max = cfg%ocean%gm%khth_slope_max this%gm%rho0 = cfg%ocean%ic%rho_0 this%redi%enable = cfg%ocean%redi%enable this%redi%continuous = cfg%ocean%redi%continuous this%redi%khtr = cfg%ocean%redi%khtr this%varmix%enable = cfg%ocean%varmix%enable this%varmix%use_visbeck = cfg%ocean%varmix%use_visbeck this%varmix%resoln_scaled_khth = cfg%ocean%varmix%resoln_scaled_khth this%varmix%resoln_scaled_khtr = cfg%ocean%varmix%resoln_scaled_khtr this%varmix%gill_equatorial_ld = cfg%ocean%varmix%gill_equatorial_ld this%varmix%interpolate_res_fn = cfg%ocean%varmix%interpolate_res_fn this%varmix%kh_res_fn_power = cfg%ocean%varmix%kh_res_fn_power this%varmix%kh_res_scale_coef = cfg%ocean%varmix%kh_res_scale_coef this%varmix%khth = cfg%ocean%varmix%khth this%varmix%khtr = cfg%ocean%varmix%khtr this%varmix%khth_slope_cff = cfg%ocean%varmix%khth_slope_cff this%varmix%khtr_slope_cff = cfg%ocean%varmix%khtr_slope_cff this%varmix%khth_min = cfg%ocean%varmix%khth_min this%varmix%khth_max = cfg%ocean%varmix%khth_max this%varmix%khtr_min = cfg%ocean%varmix%khtr_min this%varmix%khtr_max = cfg%ocean%varmix%khtr_max this%varmix%visbeck_l_scale = cfg%ocean%varmix%visbeck_l_scale this%varmix%visbeck_max_slope = cfg%ocean%varmix%visbeck_max_slope ! ---- MEKE (capability [5]) ---- this%meke%enable = cfg%ocean%meke%enable this%meke%gmcoeff = cfg%ocean%meke%gmcoeff this%meke%frcoeff = cfg%ocean%meke%frcoeff ! Turn the hvisc KE-dissipation diagnostic on ONLY when MEKE's ! frictional source is active; otherwise the viscous apply skips it ! (zero extra work, bit-identical). this%hvisc%compute_ke_diss = cfg%ocean%meke%enable .and. & (cfg%ocean%meke%frcoeff >= 0.0_wp) this%meke%bgsrc = cfg%ocean%meke%bgsrc this%meke%damping = cfg%ocean%meke%damping this%meke%kh = cfg%ocean%meke%kh this%meke%k4 = cfg%ocean%meke%k4 this%meke%khcoeff = cfg%ocean%meke%khcoeff this%meke%cd_scale = cfg%ocean%meke%cd_scale this%meke%cb = cfg%ocean%meke%cb this%meke%ct = cfg%ocean%meke%ct this%meke%min_gamma2 = cfg%ocean%meke%min_gamma2 this%meke%uscale = cfg%ocean%meke%uscale this%meke%use_bbl_drag = cfg%ocean%meke%use_bbl_drag this%meke%dtscale = cfg%ocean%meke%dtscale this%meke%khth_fac = cfg%ocean%meke%khth_fac this%meke%khtr_fac = cfg%ocean%meke%khtr_fac this%meke%backscatter = cfg%ocean%meke%backscatter this%meke%visc_coeff_ku = cfg%ocean%meke%backscatter_visc_coeff_ku this%meke%khmeke_fac = cfg%ocean%meke%khmeke_fac this%meke%advection_factor = cfg%ocean%meke%advection_factor this%meke%alpha_deform = cfg%ocean%meke%alpha_deform this%meke%alpha_rhines = cfg%ocean%meke%alpha_rhines this%meke%alpha_eady = cfg%ocean%meke%alpha_eady this%meke%alpha_frict = cfg%ocean%meke%alpha_frict this%meke%alpha_grid = cfg%ocean%meke%alpha_grid ! cdrag: prefer the side-drag coefficient if set (> 0), else the ! MEKE-specific knob default. if (cfg%ocean%bdrag%cdrag_side > 0.0_wp) then this%meke%cdrag = cfg%ocean%bdrag%cdrag_side else this%meke%cdrag = cfg%ocean%meke%cdrag end if this%vmix_tidal%enable = cfg%ocean%tidal_mixing%enable this%tides%enable = cfg%ocean%tides%enable this%p_surf%enable = cfg%ocean%psurf%enable this%p_surf%in_eos = cfg%ocean%psurf%in_eos end subroutine ocean_state_init_from_config