configure_ocean_bt Subroutine

public subroutine configure_ocean_bt(cfg, ocean_state, grid, compute_rank)

Barotropic-substep correction knobs (MOM6 frhatu h-weighting, bc-PGF retro-correction, bt_rem_u drag damping, visc_rem joint weight), the BT_cont_type / upstream-PPM h_face workspace allocations, and the rank-0 PGF/BT configuration log lines.

Arguments

Type IntentOptional 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

Calls

proc~~configure_ocean_bt~~CallsGraph proc~configure_ocean_bt configure_ocean_bt info info proc~configure_ocean_bt->info proc~ocean_bt_forcing_visc_rem_on ocean_bt_forcing_visc_rem_on proc~configure_ocean_bt->proc~ocean_bt_forcing_visc_rem_on proc~ocean_bt_rem_from_visc_rem_on ocean_bt_rem_from_visc_rem_on proc~configure_ocean_bt->proc~ocean_bt_rem_from_visc_rem_on proc~ocean_bt_renorm_visc_rem_on ocean_bt_renorm_visc_rem_on proc~configure_ocean_bt->proc~ocean_bt_renorm_visc_rem_on proc~ocean_bt_visc_rem_producer_on ocean_bt_visc_rem_producer_on proc~configure_ocean_bt->proc~ocean_bt_visc_rem_producer_on proc~parse_frhat_scheme parse_frhat_scheme proc~configure_ocean_bt->proc~parse_frhat_scheme to_string to_string proc~configure_ocean_bt->to_string warning warning proc~configure_ocean_bt->warning proc~ocean_bt_visc_rem_producer_on->proc~ocean_bt_forcing_visc_rem_on proc~ocean_bt_visc_rem_producer_on->proc~ocean_bt_rem_from_visc_rem_on proc~ocean_bt_visc_rem_producer_on->proc~ocean_bt_renorm_visc_rem_on

Called by

proc~~configure_ocean_bt~~CalledByGraph proc~configure_ocean_bt configure_ocean_bt proc~engine_setup engine_setup proc~engine_setup->proc~configure_ocean_bt proc~complete_ocean_create complete_ocean_create proc~complete_ocean_create->proc~engine_setup proc~driver_run_ocean driver_run_ocean proc~driver_run_ocean->proc~engine_setup proc~driver_validate driver_validate proc~driver_validate->proc~engine_setup proc~driver_run driver_run proc~driver_run->proc~driver_run_ocean proc~rdb_ocean_create_finalize rdb_ocean_create_finalize proc~rdb_ocean_create_finalize->proc~complete_ocean_create proc~rdb_ocean_create_from_string rdb_ocean_create_from_string proc~rdb_ocean_create_from_string->proc~complete_ocean_create

Source Code

   subroutine configure_ocean_bt(cfg, ocean_state, grid, compute_rank)
      !! Barotropic-substep correction knobs (MOM6 frhatu h-weighting, bc-PGF
      !! retro-correction, bt_rem_u drag damping, visc_rem joint weight), the
      !! BT_cont_type / upstream-PPM h_face workspace allocations, and the
      !! rank-0 PGF/BT configuration log lines.
      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

      ! MOM6 BT_force / eta_PF split: the depth-mean baroclinic PGF forces
      ! the barotropic substep (default on).
      ocean_state%dyn%bt_work%bt_bc_pgf_forcing = cfg%ocean%bt%bc_pgf_forcing
      if (compute_rank == 0 .and. .not. cfg%ocean%bt%bc_pgf_forcing) then
         call logger%warning("&ocean_bt_nml bc_pgf_forcing = .false.: LEGACY split — the "// &
                             "barotropic mode does not feel the depth-mean baroclinic "// &
                             "pressure gradient (no JEBAR / bottom-pressure torque)")
      end if

      ! MOM6 btstep_layer_accel — per-layer bc-PGF retro-correction (needs FV_MOM6).
      ocean_state%dyn%bt_work%bt_correction_bc_pgf = cfg%ocean%bt%correction_bc_pgf
      if (compute_rank == 0 .and. cfg%ocean%bt%correction_bc_pgf) then
         call logger%info("BT correction:    bc-PGF retro-correction ON "// &
                          "(MOM6 btstep_layer_accel; requires fv_mom6 PGF)")
      end if

      ! MOM6 bt_rem_u — multiplicative drag damping inside the BT substep.
      ocean_state%dyn%bt_work%bt_substep_drag = cfg%ocean%bt%substep_drag
      if (compute_rank == 0 .and. cfg%ocean%bt%substep_drag) then
         call logger%info("BT substep:       drag damping ON "// &
                          "(MOM6 bt_rem_u: r·HBBL/(Htot+r·HBBL·dt_bt))")
      end if

      ! PR-2 (bt-rem-from-av-rem): bt_rem_u/v from the SAME viscous
      ! remnant the layered momentum solve uses (MOM6's barotropic
      ! solver). Mutually exclusive with substep_drag and bt_halo > 0
      ! (validated at configure).
      ocean_state%dyn%bt_work%bt_rem_from_visc_rem = ocean_bt_rem_from_visc_rem_on(cfg)
      ocean_state%dyn%bt_work%bt_strong_drag = cfg%ocean%bt%strong_drag
      ocean_state%dyn%bt_work%bt_rescale_strong_drag = cfg%ocean%bt%rescale_strong_drag

      ! frhat port (&ocean_bt_nml frhat_scheme): the per-layer face-thickness
      ! closure every barotropic depth mean reads (MOM6 btcalc HYBRID vs the
      ! plain two-abutting-cell arithmetic mean). Default "arithmetic" ==
      ! bit-identical to the pre-port tree.
      ocean_state%dyn%bt_work%frhat_scheme = parse_frhat_scheme(cfg%ocean%bt%frhat_scheme, &
                                                                FRHAT_ARITHMETIC)
      if (compute_rank == 0 .and. ocean_state%dyn%bt_work%frhat_scheme == FRHAT_HYBRID) then
         call logger%info("BT frhat:         hybrid ON "// &
                          "(MOM6 btcalc HVEL_SCHEME=HYBRID face-thickness closure)")
      end if
      if (compute_rank == 0 .and. ocean_bt_rem_from_visc_rem_on(cfg)) then
         block
            character(len=:), allocatable :: bt_rem_msg
            bt_rem_msg = "BT substep:       bt_rem = av_rem**(1/n_inner) ON "// &
                         "(MOM6 av_rem/bt_rem from visc_rem"
            if (cfg%ocean%bt%strong_drag) bt_rem_msg = bt_rem_msg//", strong_drag"
            if (cfg%ocean%bt%rescale_strong_drag) bt_rem_msg = bt_rem_msg//", rescale_strong_drag"
            bt_rem_msg = bt_rem_msg//")"
            call logger%info(bt_rem_msg)
         end block
      end if

      ! MOM6 planetary-only fast loop — drop live ζ_bt/∇KE from the substeps
      ! (they stay frozen inside F_bt_*_fast); Cor_ref reduces to f·v̄.
      ocean_state%dyn%bt_work%substep_zeta_ke = cfg%ocean%bt%substep_zeta_ke
      if (compute_rank == 0 .and. .not. cfg%ocean%bt%substep_zeta_ke) then
         call logger%info("BT substep:       planetary Coriolis only "// &
                          "(substep_zeta_ke=.false.; MOM6 q=f/D parity — "// &
                          "live ζ_bt/∇KE off, frozen copies stay in F_bt)")
      end if

      ! RETIRED visc_rem-weighted BT-corrector fold (wt = visc_rem/<visc_rem>_h):
      ! `correction_visc_rem` is now fail-loud at configure (D1 follow-up —
      ! MOM6's accel_layer_u never weights this fold), so this field is
      ! wired straight from the RAW (deprecated) knob, never from
      ! `visc_rem_chain` — a test that constructs `cfg` directly and sets
      ! the raw field (bypassing the nml refusal) still gets the weighted
      ! dispatch the kernel itself supports; everyone else reads 1.
      ocean_state%dyn%bt_work%bt_correction_visc_rem = cfg%ocean%bt%correction_visc_rem
      if (compute_rank == 0 .and. cfg%ocean%bt%correction_visc_rem) then
         call logger%info("BT correction:    visc_rem/<visc_rem>_h weight ON "// &
                          "(visc_rem produced by vdiff)")
      end if
      ! D1 follow-up: the visc_rem PRODUCER is decoupled from the retired
      ! weighted fold above — it runs whenever ANY real consumer needs
      ! visc_rem_u/v fresh (forcing/renorm/bt_rem_from, or visc_rem_chain,
      ! which implies all three).
      ocean_state%dyn%bt_work%bt_visc_rem_producer = ocean_bt_visc_rem_producer_on(cfg)
      ! MOM6 wt_u parity for the BT FORCING assembly (PGF_BUG.md §9):
      ! friction-damped layers stop forcing the fast loop.  Self-sufficient
      ! (see `bt_visc_rem_producer` above).
      ocean_state%dyn%bt_work%bt_forcing_visc_rem = ocean_bt_forcing_visc_rem_on(cfg)
      if (compute_rank == 0 .and. ocean_bt_forcing_visc_rem_on(cfg)) then
         call logger%info("BT forcing:       h·visc_rem weight ON (MOM6 wt_u)")
      end if
      ! MOM6 dt·visc_rem·accel parity: the per-layer slow applies are
      ! attenuated by the viscous remnant (requires correction_visc_rem,
      ! validated at configure).
      ocean_state%dyn%accel_visc_rem = cfg%ocean%vdiff%accel_visc_rem
      if (compute_rank == 0 .and. cfg%ocean%vdiff%accel_visc_rem) then
         call logger%info("Velocity applies: visc_rem-attenuated ON "// &
                          "(MOM6 u = u0 + dt*visc_rem*accel)")
      end if
      ! Eagerly allocate the accel_visc_rem stage-entry velocity snapshots
      ! here (ocean-state convention: slots allocated at setup, mapped once
      ! at enter_data — no mid-run lazy alloc), but ONLY when the knob is on
      ! — on a large grid these two face arrays are ~GB, so the default-off
      ! path must not pay for them.  Runs BEFORE ocean_state_enter_data, so
      ! ocean_dyn_enter_data_impl copyin sees them allocated (host source=0).
      if (ocean_state%dyn%accel_visc_rem) then
         allocate (ocean_state%dyn%avr_u0(grid%nx_total + 1, grid%ny_total, &
                                          ocean_state%multilayer%nz_ml), source=0.0_wp)
         allocate (ocean_state%dyn%avr_v0(grid%nx_total, grid%ny_total + 1, &
                                          ocean_state%multilayer%nz_ml), source=0.0_wp)
      end if
      ! SPEC S3: outer split-explicit time-scheme selector.  The enum
      ! registration constrains the string (and rejects both retired
      ! spellings of this scheme, "mom6_pc" and "split_rk2", by name);
      ! the default is the MOM6 predictor-corrector, `pred_corr`.
      if (trim(cfg%ocean%bt%split_scheme) == "pred_corr") then
         ocean_state%dyn%split_scheme = SPLIT_SCHEME_PRED_CORR
      else
         ocean_state%dyn%split_scheme = SPLIT_SCHEME_SSP_RK2
      end if
      ocean_state%dyn%pc_be = cfg%ocean%bt%pc_be
      ! Print the RESOLVED scheme for BOTH branches, not just the non-default
      ! one.  A banner that only speaks up for one value cannot answer "which
      ! scheme did this namelist actually run", which is the only reliable way
      ! to enumerate what a default flip touches -- grepping the namelists
      ! cannot (a key may be absent, commented out, or set in an included
      ! group).
      if (compute_rank == 0) then
         if (ocean_state%dyn%split_scheme == SPLIT_SCHEME_PRED_CORR) then
            call logger%info("Split scheme:     pred_corr (MOM6 predictor-corrector; "// &
                             "tendencies on u_av/h_av; BE = "// &
                             to_string(cfg%ocean%bt%pc_be)//")")
         else
            call logger%info("Split scheme:     ssp_rk2 (EXPERIMENTAL; two "// &
                             "identical stages, SSP average -- grows internal "// &
                             "gravity waves from a stratified rest state)")
         end if
      end if
      ! SPEC S2b: γ-weighted continuity transport-matching inversion.
      ocean_state%dyn%bt_work%bt_renorm_visc_rem = ocean_bt_renorm_visc_rem_on(cfg)
      if (compute_rank == 0 .and. ocean_bt_renorm_visc_rem_on(cfg)) then
         call logger%info("BT renormaliser:  gamma-weighted du + u_cor (MOM6 "// &
                          "continuity inversion parity)")
      end if
      ! PR-8 / D1 follow-up: every `*_visc_rem` consumer couples against
      ! `visc_rem_u/v`, which are only ever filled away from their
      ! `source=1.0` default by the implicit bottom-drag diagonal fold
      ! (`&ocean_vdiff_nml implicit_drag`) or `bbl_glue` breaking vdiff's
      ! per-row unit-sum normalisation — without either the chain is
      ! exactly gamma==1 (a x1.0). Warn rather than abort (tidal_mixing
      ! e_uniform=0 precedent): PR-19 (visc_rem) is the named owner that
      ! fills the arrays for other configurations.  (`validate_config` also
      ! carries this check at configure; repeated here for the rank-0 log.)
      if (compute_rank == 0 .and. ocean_bt_visc_rem_producer_on(cfg) .and. &
          .not. (cfg%ocean%vdiff%implicit_drag .or. ocean_state%vdiff%bbl_glue)) then
         call logger%warning("&ocean_bt_nml forcing_visc_rem/renorm_visc_rem/"// &
                             "bt_rem_from_visc_rem/visc_rem_chain has no effect without "// &
                             "&ocean_vdiff_nml implicit_drag=.true. or bbl_glue=.true. "// &
                             "(visc_rem_u/v stay at their source=1.0 default; PR-19 owns filling them)")
      end if

      ! BT_cont_type flux-bounded continuity: allocate the per-face coefficient
      ! packs so enter_data attaches them; default off leaves them unallocated.
      ocean_state%dyn%bt_work%use_bt_cont_type = cfg%ocean%bt%use_cont_type
      if (cfg%ocean%bt%use_cont_type) then
         block
            integer :: nx_w, ny_w
            nx_w = grid%nx_total
            ny_w = grid%ny_total
            allocate (ocean_state%dyn%bt_work%BTCL_u(nx_w + 1, ny_w))
            allocate (ocean_state%dyn%bt_work%BTCL_v(nx_w, ny_w + 1))
         end block
      end if
      ! Upstream-PPM h_face for the BT chain — allocate the per-face slots.
      ocean_state%dyn%bt_work%use_upstream_h_face = cfg%ocean%bt%upstream_h_face
      if (cfg%ocean%bt%upstream_h_face) then
         block
            integer :: nx_w, ny_w
            nx_w = grid%nx_total
            ny_w = grid%ny_total
            allocate (ocean_state%dyn%bt_work%h_face_up_x(nx_w + 1, ny_w), source=0.0_wp)
            allocate (ocean_state%dyn%bt_work%h_face_up_y(nx_w, ny_w + 1), source=0.0_wp)
         end block
      end if
      if (compute_rank == 0) then
         if (ocean_state%pressure_force%variant == OPGF_VARIANT_GPRIME) then
            call logger%info("PGF form:         gprime  gfs="// &
                             to_string(cfg%ocean%pgf%gprime_gfs)//" m/s²  gint="// &
                             to_string(cfg%ocean%pgf%gprime_gint)//" m/s²")
         else
            call logger%info("PGF form:         "//trim(cfg%ocean%pgf%form))
         end if
         if (cfg%ocean%bt%bebt > 0.0_wp) then
            call logger%info("BEBT projection:  bebt="// &
                             to_string(cfg%ocean%bt%bebt)// &
                             " (BT η flux uses (1+bebt)·u^n − bebt·u^{n-1})")
         end if
         if (cfg%ocean%bt%use_cont_type) then
            call logger%info("BT_cont_type:     ON  (flux-bounded BT continuity)")
            if (cfg%ocean%bt%cont_corr_bounds) then
               call logger%info("                  BT_CONT_CORR_BOUNDS=.true. (η-corr bound from BT_cont)")
            end if
         end if
         if (cfg%ocean%bt%upstream_h_face) then
            call logger%info("BT upstream-h:    ON  (BT chain uses upstream-PPM h_face)")
         end if
      end if
   end subroutine configure_ocean_bt