Bottom-drag variant + coefficients, the continuity PPM positivity guard, and the BT-budget diagnostic probe — plus their rank-0 log lines. All knobs default off/zero (bit-identical to pre-knob nmls).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(config_t), | intent(in) | :: | cfg | |||
| type(ocean_state_t), | intent(inout) | :: | ocean_state | |||
| integer, | intent(in) | :: | compute_rank | |||
| integer, | intent(out), | optional | :: | ierr |
Non-zero on an isopycnal-floor configuration conflict when
present; absent behaves as today ( |
subroutine configure_ocean_drag(cfg, ocean_state, compute_rank, ierr) !! Bottom-drag variant + coefficients, the continuity PPM positivity !! guard, and the BT-budget diagnostic probe — plus their rank-0 log !! lines. All knobs default off/zero (bit-identical to pre-knob nmls). type(config_t), intent(in) :: cfg type(ocean_state_t), intent(inout) :: ocean_state integer, intent(in) :: compute_rank integer, intent(out), optional :: ierr !! Non-zero on an isopycnal-floor configuration conflict when !! present; absent behaves as today (`error stop`). ! EOS variant FIRST: this is the earliest configure_ocean_* call, so ! `ocean_state%eos%variant` is set before the EOS-handle is copied into ! the vmix / EPBL / kappa-shear slots (in configure_ocean_lateral / ! _epbl / _kappa_shear). The device-callable gate + the FV_WRIGHT ! cross-check run later, in configure_ocean_pgf (post pgf-variant parse). ocean_state%eos%variant = parse_eos_variant(cfg%ocean%eos%eos) ! Potential-density reference pressure. Assigned HERE, in the ! earliest configure_ocean_* call, so the value is already on the ! handle when it is copied into the vmix / EPBL / kappa-shear slots ! further down — and before `enter_data`, so the mapped copies carry ! it. `eos_t` is a flat POD read by value into the `_impl` calls, so ! this host assignment owes no `!$acc update device` under ! mem:separate (same contract as `rho0`/`rho_ref` on the PGF slot). ! Horizontally uniform by design — see the knob's FORD docstring. ocean_state%eos%p_ref = cfg%ocean%eos%p_ref ! Freezing-point (liquidus) coefficient set — same site, same ! reasons, and one more: the ICE slot reads the god-state handle ! directly (`engine%state%eos` is what `ice_frazil_accumulate`, ! `ice_frazil_uptake` and `ice_compute_basal_flux` are handed), so ! landing the set here puts it on the ONE handle every liquidus ! consumer sees, before any copy is taken and before `enter_data`. ! An unrecognised string is already fatal in `validate_config`; ! `eos_apply_tfreeze_set` leaves the handle untouched for it. call eos_apply_tfreeze_set(ocean_state%eos, & parse_tfreeze_set(cfg%ocean%eos%tfreeze_set)) if (compute_rank == 0) then call logger%info("EOS variant: "//trim(cfg%ocean%eos%eos)) if (parse_tfreeze_set(cfg%ocean%eos%tfreeze_set) /= TFREEZE_SET_SEAICE) then call logger%info("Liquidus set: "//trim(cfg%ocean%eos%tfreeze_set)// & " (ISOMIP+ / Asay-Davis et al. 2016 Table 4; the "// & "default 'seaice' SIS2 set is ~0.03 degC warmer at S=34.5)") end if end if ocean_state%bdrag%variant = parse_bdrag_variant(cfg%ocean%bdrag%form) ocean_state%bdrag%c_drag = cfg%ocean%bdrag%cd ocean_state%bdrag%r_linear = cfg%ocean%bdrag%r ocean_state%bdrag%hbbl = cfg%ocean%bdrag%hbbl ocean_state%bdrag%drag_bg_vel = cfg%ocean%bdrag%bg_vel ocean_state%bdrag%bbl_thick_min = cfg%ocean%bdrag%bbl_thick_min ocean_state%bdrag%bed_factor = cfg%ocean%bdrag%bed_factor ocean_state%bdrag%channel_drag = cfg%ocean%bdrag%channel_drag ocean_state%bdrag%cdrag_side = cfg%ocean%bdrag%cdrag_side ocean_state%bdrag%implicit = cfg%ocean%bdrag%implicit ! Continuity PPM positivity guard (MOM6 PPM_limit_pos analogue). ocean_state%continuity%use_ppm_limit_pos = cfg%ocean%continuity%ppm_limit_pos ocean_state%continuity%renorm_consistent_flux = cfg%ocean%continuity%renorm_consistent_flux ! Wet/dry composition: the Newton uhbt renormalisation's donor ! re-pick + CFL bracket destabilise the drying front (h_layer goes ! negative, test_ocean_wetdry_driver) — wet/dry keeps the legacy ! single-step form it was validated on. ocean_state%continuity%renorm_legacy_single_step = cfg%ocean%wetdry%enable ocean_state%continuity%h_min = cfg%ocean%continuity%h_min ocean_state%continuity%vol_cfl = cfg%ocean%continuity%vol_cfl if (compute_rank == 0 .and. cfg%ocean%continuity%ppm_limit_pos) then call logger%info("Continuity PPM: positivity guard ON (MOM6 PPM_limit_pos), "// & "h_min = "//to_string(cfg%ocean%continuity%h_min)//" m") end if ! Positive-definite split continuity (MOM6-prevention + Roundabout-conservation). ! h_lim = angstrom_h on VCOORD_LAGRANGIAN, else 0 (⇒ P1 floor inert on ! non-Lagrangian coords). Default off ⇒ bit-identical. ocean_state%continuity%positive_definite = cfg%ocean%continuity%positive_definite if (parse_ocean_vcoord_type(cfg%vcoord_type) == VCOORD_LAGRANGIAN) then ocean_state%continuity%h_lim = cfg%ocean%isopycnal%angstrom_h else ocean_state%continuity%h_lim = 0.0_wp end if if (compute_rank == 0 .and. cfg%ocean%continuity%positive_definite) then call logger%info("Continuity PD: positive_definite ON (h>=h_lim, zero mass "// & "created), h_lim = "//to_string(ocean_state%continuity%h_lim)//" m") end if ! Phase-1 Lagrangian minimum-thickness floor (MOM6 Angstrom_H analogue). ! Only passed to the h-update kernels when the active vcoord is ! VCOORD_LAGRANGIAN (gated in rdb_ocean_dyn at the call site). 0 = off. ocean_state%continuity%angstrom_h = cfg%ocean%isopycnal%angstrom_h if (compute_rank == 0 .and. cfg%ocean%isopycnal%angstrom_h > 0.0_wp) then call logger%info("Isopycnal floor: angstrom_h = "// & to_string(cfg%ocean%isopycnal%angstrom_h)//" m (Lagrangian only)") end if ! Conservative minimum-thickness mode: replaces the injecting floor with a ! per-column borrow (rdb_ocean_min_thickness), invoked from the dyn ! continuity site. Fail-loud: needs angstrom_h > 0 AND VCOORD_LAGRANGIAN. ocean_state%continuity%conservative_floor = cfg%ocean%isopycnal%conservative_floor if (cfg%ocean%isopycnal%conservative_floor) then if (cfg%ocean%isopycnal%angstrom_h <= 0.0_wp) then call fail("ocean_isopycnal_nml: conservative_floor=.true. requires "// & "angstrom_h > 0 (nothing to floor to).", ierr, OCEAN_STATUS_ERR_SETUP) return end if if (parse_ocean_vcoord_type(cfg%vcoord_type) /= VCOORD_LAGRANGIAN) then call fail("ocean_isopycnal_nml: conservative_floor=.true. is only "// & "valid with vcoord_type='lagrangian' (isopycnal path).", ierr, OCEAN_STATUS_ERR_SETUP) return end if if (compute_rank == 0) then call logger%info("Isopycnal floor: conservative_floor = ON "// & "(per-column borrow, mass/momentum/tracer conserving)") end if end if ! Phase-2/3 Lagrangian grounding-stability knobs on ocean_dyn_t. ! Gates tested at the dyn call sites; bit-identical when off. ocean_state%dyn%angstrom_h = cfg%ocean%isopycnal%angstrom_h ocean_state%dyn%reset_vanished_u = cfg%ocean%isopycnal%reset_vanished_u ocean_state%dyn%cfl_ignore_vanished = cfg%ocean%isopycnal%cfl_ignore_vanished ocean_state%dyn%check_h_positive = cfg%ocean%isopycnal%check_h_positive if (compute_rank == 0) then if (cfg%ocean%isopycnal%reset_vanished_u) then call logger%info("Isopycnal reset: reset_vanished_u = ON (Lagrangian only)") end if if (cfg%ocean%isopycnal%cfl_ignore_vanished) then call logger%info("Isopycnal CFL: cfl_ignore_vanished = ON (Lagrangian only)") end if end if if (compute_rank == 0 .and. cfg%ocean%continuity%vol_cfl) then call logger%info("Continuity PPM: swept-volume face thickness ON (MOM6 vol_CFL)") end if ! Ghost-band poison debug knob. ocean_state%dyn%poison_ghosts = cfg%ocean%mpi%poison_ghosts ! BT-budget diagnostic probe — heavy when on (D->H + 16 prints/step). ocean_state%dyn%debug_bt_budget = cfg%ocean%debug%budget if (compute_rank == 0 .and. cfg%ocean%debug%budget) then call logger%info("BT-budget probe: ENABLED (per-step per-region "// & "power decomposition)") end if ! KE attribution meter — heavy when on (serialises the apply chain). ocean_state%dyn%ke_probe%enable = cfg%ocean%debug%ke_attr ocean_state%dyn%ke_probe%start_step = cfg%ocean%debug%ke_attr_start_step ocean_state%dyn%ke_probe%end_step = cfg%ocean%debug%ke_attr_end_step ocean_state%dyn%chksum_probe%enable = cfg%ocean%debug%chksum ocean_state%dyn%chksum_probe%start_step = cfg%ocean%debug%chksum_start_step ocean_state%dyn%chksum_probe%end_step = cfg%ocean%debug%chksum_end_step ocean_state%dyn%chksum_probe%interior = cfg%ocean%debug%chksum_interior if (compute_rank == 0 .and. cfg%ocean%debug%ke_attr) then call logger%info("KE-attr meter: ENABLED (per-segment layer-KE "// & "rows, steps "//to_string(cfg%ocean%debug%ke_attr_start_step)// & " to "//to_string(cfg%ocean%debug%ke_attr_end_step)//")") end if if (compute_rank == 0) then call logger%info("Bottom drag: "//trim(cfg%ocean%bdrag%form)// & " C_d="//to_string(cfg%ocean%bdrag%cd)// & " r="//to_string(cfg%ocean%bdrag%r)//" 1/s") if (cfg%ocean%bdrag%hbbl > 0.0_wp) then call logger%info("Bottom drag BBL: HBBL="//to_string(cfg%ocean%bdrag%hbbl)// & " m bg_vel="//to_string(cfg%ocean%bdrag%bg_vel)// & " m/s thick_min="//to_string(cfg%ocean%bdrag%bbl_thick_min)//" m") else call logger%info("Bottom drag BBL: bed-layer only (HBBL=0)") ! Bed-only mode drags the face's first LIVE layer `k_bot_u/v`. ! Under z_fixed that index is filled at configure ! (`configure_ocean_k_bot`) and skips the static bed fillers, so ! the bed-only mode reaches water there. `k_bot ≡ 1` under ! zstar_full (its bed-side layers vanish DYNAMICALLY, no static ! pattern) and, until `configure_ocean_k_bot` learns it, under ! zstar (static z_fixed fillers): k = 1 is an inert filler in ! every column shallower than the deepest nominal interface and ! almost the whole domain runs with NO bottom drag. HBBL mode ! accumulates thickness from the bed up, skips those fillers and ! reaches the live bottom layer. if ((cfg%ocean%bdrag%cd > 0.0_wp .or. cfg%ocean%bdrag%r > 0.0_wp) .and. & (parse_ocean_vcoord_type(cfg%vcoord_type) == VCOORD_ZSTAR .or. & parse_ocean_vcoord_type(cfg%vcoord_type) == VCOORD_ZSTAR_FULL)) then call logger%warning("&ocean_bdrag_nml hbbl = 0 (bed-layer-only drag) under "// & "vcoord_type = '"//trim(cfg%vcoord_type)//"': the drag "// & "acts on layer k = 1, an inert filler in every column "// & "shallower than the deepest nominal layer, so those "// & "columns get NO bottom drag. Set hbbl > 0 (MOM6 "// & "OM4/OM_1deg: HBBL = 10 m, bg_vel = 0.1 m/s).") end if end if if (cfg%ocean%bdrag%channel_drag) then call logger%info("Channel drag: ON cdrag_side="// & to_string(cfg%ocean%bdrag%cdrag_side)) end if end if if (present(ierr)) ierr = OCEAN_STATUS_OK end subroutine configure_ocean_drag