Copy the &ocean_epbl_nml knobs onto the EPBL slot — every
field, end to end (don’t repeat the KPP ri_crit/c_vt2
dead-config gap). Also fills f_centre from the same
beta-plane parameters the Coriolis slot uses, copies the EOS
hookup, validates the configuration, and resolves the
EPBL-vs-KPP mutual exclusion.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(config_t), | intent(in) | :: | cfg | |||
| type(ocean_state_t), | intent(inout) | :: | ocean_state | |||
| type(hgrid_t), | intent(in) | :: | grid | |||
| integer, | intent(in) | :: | compute_rank | |||
| integer, | intent(out), | optional | :: | ierr |
Non-zero on an EPBL configuration conflict when present; absent
behaves as today ( |
subroutine configure_ocean_epbl(cfg, ocean_state, grid, compute_rank, ierr) !! Copy the `&ocean_epbl_nml` knobs onto the EPBL slot — every !! field, end to end (don't repeat the KPP ri_crit/c_vt2 !! dead-config gap). Also fills `f_centre` from the same !! beta-plane parameters the Coriolis slot uses, copies the EOS !! hookup, validates the configuration, and resolves the !! EPBL-vs-KPP mutual exclusion. type(config_t), intent(in) :: cfg type(ocean_state_t), intent(inout) :: ocean_state type(hgrid_t), intent(in) :: grid integer, intent(in) :: compute_rank integer, intent(out), optional :: ierr !! Non-zero on an EPBL configuration conflict when present; absent !! behaves as today (`error stop`). associate (epbl => ocean_state%epbl, ecfg => cfg%ocean%epbl) ! `enable` is flipped LAST, only once every validation below has ! passed (P0.1 review F9 — `configure_ocean_porous` is the ! pattern): setting it up front left a half-configured slot ! flagged enabled on any of this routine's many failure returns. if (.not. ecfg%enable) then epbl%enable = .false. if (present(ierr)) ierr = OCEAN_STATUS_OK return end if epbl%mstar_scheme = parse_epbl_mstar_scheme(ecfg%mstar_scheme) if (epbl%mstar_scheme < 0) then call fail("ocean_epbl_nml: unknown mstar_scheme '"// & trim(ecfg%mstar_scheme)//"' (constant/om4/rh18)", ierr, OCEAN_STATUS_ERR_SETUP) return end if epbl%vstar_scheme = parse_epbl_vstar_scheme(ecfg%vel_scale_scheme) if (epbl%vstar_scheme < 0) then call fail("ocean_epbl_nml: unknown vel_scale_scheme '"// & trim(ecfg%vel_scale_scheme)//"' (cube_root/rh18)", ierr, OCEAN_STATUS_ERR_SETUP) return end if epbl%combine_mode = parse_epbl_combine(ecfg%combine) if (epbl%combine_mode < 0) then call fail("ocean_epbl_nml: unknown combine '"// & trim(ecfg%combine)//"' (add/max)", ierr, OCEAN_STATUS_ERR_SETUP) return end if epbl%mstar_const = ecfg%mstar epbl%mstar_cap = ecfg%mstar_cap epbl%mstar_coef1 = ecfg%mstar_coef1 epbl%c_ek = ecfg%c_ek epbl%mstar_conv_adj = ecfg%mstar_conv_adj epbl%rh18_cn1 = ecfg%rh18_cn1 epbl%rh18_cn2 = ecfg%rh18_cn2 epbl%rh18_cn3 = ecfg%rh18_cn3 epbl%rh18_cs1 = ecfg%rh18_cs1 epbl%rh18_cs2 = ecfg%rh18_cs2 epbl%nstar = ecfg%nstar epbl%tke_decay = ecfg%tke_decay epbl%wstar_ustar_coef = ecfg%wstar_ustar_coef epbl%vstar_scale_fac = ecfg%vstar_scale_fac epbl%vstar_surf_fac = ecfg%vstar_surf_fac epbl%von_karman = ecfg%von_karman epbl%ekman_scale_coef = ecfg%ekman_scale_coef epbl%min_mix_len = ecfg%min_mix_len epbl%mixlen_exponent = ecfg%mixlen_exponent epbl%translay_scale = ecfg%translay_scale epbl%mld_iteration = ecfg%mld_iteration epbl%mld_tol = ecfg%mld_tol epbl%mld_max_its = ecfg%mld_max_its epbl%mld_bisection = ecfg%mld_bisection epbl%mld_use_prev_guess = ecfg%mld_use_prev_guess epbl%omega = ecfg%omega epbl%omega_frac = ecfg%omega_frac epbl%prandtl = ecfg%prandtl epbl%tke_diags = ecfg%tke_diags ! (PR-21) Penetrating-SW TKE ledger switch lives on ! &ocean_thermo_nml (shared with KPP), not &ocean_epbl_nml. epbl%epbl_sw_ctke = cfg%ocean%thermo%epbl_sw_ctke ! Langmuir (LF17 wind-only path). epbl%use_lt = ecfg%use_lt if (ecfg%use_lt) then epbl%lt_scheme = parse_epbl_lt_scheme(ecfg%lt_scheme) if (epbl%lt_scheme < 0) then call fail("ocean_epbl_nml: unknown lt_scheme '"// & trim(ecfg%lt_scheme)//"' (rescale/additive)", ierr, OCEAN_STATUS_ERR_SETUP) return end if epbl%lt_enhance_coef = ecfg%lt_enhance_coef epbl%lt_enhance_exp = ecfg%lt_enhance_exp epbl%lt_max_enhance = ecfg%lt_max_enhance epbl%la_frac_hbl = ecfg%la_frac_hbl epbl%lt_lac1 = ecfg%lt_lac1 epbl%lt_lac2 = ecfg%lt_lac2 epbl%lt_lac3 = ecfg%lt_lac3 epbl%lt_lac4 = ecfg%lt_lac4 epbl%lt_lac5 = ecfg%lt_lac5 if (compute_rank == 0) then call logger%info("EPBL Langmuir: LF17 wind-only, scheme="// & trim(ecfg%lt_scheme)//" coef="// & to_string(ecfg%lt_enhance_coef)//" exp="// & to_string(ecfg%lt_enhance_exp)) end if end if ! EOS hookup: the EPBL energy weights use the SAME EOS handle ! the dyn-core runs (shared flat-POD copy — one source of ! truth, no scalar copies that can drift). epbl%eos = ocean_state%eos epbl%rho0 = ocean_state%eos%rho0 ! (E3) Top-of-column pressure in the IN-SITU EOS arguments AND ! in the PE weight. `&ocean_psurf_nml in_eos` is the single ! gate for the whole `ms%p_top` seam; assigned HERE, at ! configure, so it is latched before `ocean_state_enter_data` ! and the kernel reads it by value (host scalar -- no ! `!$acc update device` owed). Off (default) ⇒ the stack ! starts at 0 Pa, bit-identically. NOTE this is NOT redundant ! with `p_top` being zero: a cavity fills `p_top` with the ice ! load whether or not `in_eos` is set. epbl%in_eos = cfg%ocean%psurf%in_eos ! |f| at cell centres, same scheme the Coriolis slot uses (D7). call fill_coriolis_centre(cfg, ocean_state%metrics, grid, epbl%f_centre) ! Validation. if (.not. cfg%ocean%vmix%use_closure) then call fail("ocean_epbl_nml: enable=.true. requires "// & "ocean_vmix_nml use_closure=.true. (EPBL folds "// & "into the interior closure's kv/kt)", ierr, OCEAN_STATUS_ERR_SETUP) return end if if (.not. cfg%ocean%thermo%enable_thermodynamics) then call fail("ocean_epbl_nml: enable=.true. requires "// & "active thermodynamics (EPBL reads T, S)", ierr, OCEAN_STATUS_ERR_SETUP) return end if if (epbl%mld_iteration .and. & (epbl%translay_scale < 0.0_wp .or. epbl%translay_scale >= 1.0_wp)) then call fail("ocean_epbl_nml: translay_scale must be in "// & "[0,1) when mld_iteration is on", ierr, OCEAN_STATUS_ERR_SETUP) return end if ! KPP mutual exclusion: EPBL replaces the overlay. use_kpp ! defaults on, so override with a log line rather than abort. if (ocean_state%vmix%use_kpp) then ocean_state%vmix%use_kpp = .false. if (compute_rank == 0) then call logger%info("EPBL enabled: KPP overlay disabled "// & "(mutually exclusive surface schemes)") end if end if if (compute_rank == 0) then call logger%info("EPBL: mstar="//trim(ecfg%mstar_scheme)// & " nstar="//to_string(ecfg%nstar)// & " tke_decay="//to_string(ecfg%tke_decay)// & " vstar="//trim(ecfg%vel_scale_scheme)// & " combine="//trim(ecfg%combine)) end if epbl%enable = .true. end associate if (present(ierr)) ierr = OCEAN_STATUS_OK end subroutine configure_ocean_epbl