configure_ocean_kappa_shear Subroutine

private subroutine configure_ocean_kappa_shear(cfg, ocean_state, grid, compute_rank, ierr)

Copy the &ocean_kappa_shear_nml knobs onto the kappa-shear slot — every field, end to end (don’t repeat the KPP dead-config gap). Fills f_centre from the same beta-plane parameters the Coriolis slot uses, copies the EOS hookup, and validates. No mutual exclusion: kappa-shear is an interior closure that coexists with KPP / EPBL and PP81/background.

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
integer, intent(out), optional :: ierr

Non-zero on a kappa-shear configuration conflict when present; absent behaves as today (error stop).


Calls

proc~~configure_ocean_kappa_shear~~CallsGraph proc~configure_ocean_kappa_shear configure_ocean_kappa_shear info info proc~configure_ocean_kappa_shear->info proc~fail fail proc~configure_ocean_kappa_shear->proc~fail proc~fill_coriolis_centre fill_coriolis_centre proc~configure_ocean_kappa_shear->proc~fill_coriolis_centre proc~fill_coriolis_corner fill_coriolis_corner proc~configure_ocean_kappa_shear->proc~fill_coriolis_corner proc~ocean_kappa_shear_init_vertex ocean_kappa_shear_t%ocean_kappa_shear_init_vertex proc~configure_ocean_kappa_shear->proc~ocean_kappa_shear_init_vertex to_string to_string proc~configure_ocean_kappa_shear->to_string warning warning proc~configure_ocean_kappa_shear->warning error error proc~fail->error proc~error_ring_push error_ring_push proc~fail->proc~error_ring_push proc~metrics_fill_coriolis metrics_fill_coriolis proc~fill_coriolis_centre->proc~metrics_fill_coriolis proc~parse_coriolis_scheme parse_coriolis_scheme proc~fill_coriolis_centre->proc~parse_coriolis_scheme proc~fill_coriolis_corner->proc~metrics_fill_coriolis proc~fill_coriolis_corner->proc~parse_coriolis_scheme

Called by

proc~~configure_ocean_kappa_shear~~CalledByGraph proc~configure_ocean_kappa_shear configure_ocean_kappa_shear proc~configure_ocean_lateral configure_ocean_lateral proc~configure_ocean_lateral->proc~configure_ocean_kappa_shear proc~engine_setup engine_setup proc~engine_setup->proc~configure_ocean_lateral 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_kappa_shear(cfg, ocean_state, grid, compute_rank, ierr)
      !! Copy the `&ocean_kappa_shear_nml` knobs onto the kappa-shear slot
      !! — every field, end to end (don't repeat the KPP dead-config
      !! gap).  Fills `f_centre` from the same beta-plane parameters the
      !! Coriolis slot uses, copies the EOS hookup, and validates.  No
      !! mutual exclusion: kappa-shear is an interior closure that
      !! coexists with KPP / EPBL and PP81/background.
      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 a kappa-shear configuration conflict when present;
         !! absent behaves as today (`error stop`).

      associate (ks => ocean_state%kshear, kcfg => cfg%ocean%kshear)
         ! `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. kcfg%enable) then
            ks%enable = .false.
            if (present(ierr)) ierr = OCEAN_STATUS_OK
            return
         end if

         ! Fail loud at configure (wavespeed precedent): both kappa-shear
         ! kernels gather into fixed-size NZ_STACK_MAX column arrays, so
         ! nz > NZ_STACK_MAX would silently overrun per-thread stack.
         if (ocean_state%multilayer%nz_ml > NZ_STACK_MAX) then
            call fail("ocean_kappa_shear_nml: nz_layers exceeds "// &
                      "NZ_STACK_MAX (raise NZ_STACK_MAX in rdb_constants)", ierr, OCEAN_STATUS_ERR_SETUP)
            return
         end if

         ! Every JHL08 knob (no dead-config gaps).
         ks%ri_crit = kcfg%ri_crit
         ks%shearmix_rate = kcfg%shearmix_rate
         ks%fri_curvature = kcfg%fri_curvature
         ks%c_n = kcfg%c_n
         ks%c_s = kcfg%c_s
         ks%lambda = kcfg%lambda
         ks%lz_rescale = kcfg%lz_rescale
         ks%kappa_0 = kcfg%kappa_0
         ks%kappa_seed = kcfg%kappa_seed
         ks%kappa_trunc = kcfg%kappa_trunc
         ks%tke_bg = kcfg%tke_bg
         ks%tol_err = kcfg%tol_err
         ks%max_inner_it = kcfg%max_inner_it
         ks%max_substep_it = kcfg%max_substep_it
         ks%src_max_chg = kcfg%src_max_chg
         ks%prandtl_turb = kcfg%prandtl_turb
         ks%vel_underflow = kcfg%vel_underflow
         ks%massless_merge = kcfg%massless_merge
         ks%vertex_geometric_mean = kcfg%vertex_geometric_mean
         ks%vertex_geomean_kdmin = kcfg%vertex_geomean_kdmin

         ! EOS hookup: the buoyancy derivatives use the SAME EOS handle
         ! the dyn-core runs (shared flat-POD copy — one source of
         ! truth, no scalar copies that can drift).
         ks%eos = ocean_state%eos
         ks%rho0 = ocean_state%eos%rho0

         ! |f| at cell centres, same scheme the Coriolis slot uses (D7).
         call fill_coriolis_centre(cfg, ocean_state%metrics, grid, ks%f_centre)

         ! Vertex form (MOM6 VERTEX_SHEAR): allocate the corner fields
         ! (deliberately not in `init` — the corner carrier is nz+1 full
         ! planes, paid only when selected) and fill the SIGNED corner
         ! f via the same generator-driven scheme (the kernel squares
         ! it).  Runs before `ocean_state_enter_data`, so the new
         ! allocatables map with the slot.
         if (kcfg%at_vertex) then
            ! nghost >= 2 fail-loud (pv_adv_required_nghost precedent):
            ! corners are solved on [2,nx]x[2,ny] only, so the outermost
            ! array ring averages with never-solved zero ring corners.
            ! With nghost >= 2 that ring is entirely ghost cells and the
            ! owned-cell answer is exact; with nghost < 2 the depressed
            ! first-ring kt could leak into owned cells via smoothing.
            if (grid%nghost < 2) then
               call fail("ocean_kappa_shear_nml: at_vertex requires "// &
                         "nghost >= 2 (corner solve covers interior "// &
                         "corners only; got nghost="//to_string(grid%nghost)//")", ierr, OCEAN_STATUS_ERR_SETUP)
               return
            end if
            call ks%init_vertex(grid, ocean_state%multilayer%nz_ml)
            call fill_coriolis_corner(cfg, ocean_state%metrics, grid, ks%f_corner)
         end if

         ! Validation.
         if (.not. cfg%ocean%vmix%use_closure) then
            call fail("ocean_kappa_shear_nml: enable=.true. requires "// &
                      "ocean_vmix_nml use_closure=.true. (kappa-shear "// &
                      "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_kappa_shear_nml: enable=.true. requires "// &
                      "active thermodynamics (kappa-shear reads T, S)", ierr, OCEAN_STATUS_ERR_SETUP)
            return
         end if
         if (ks%ri_crit <= 0.0_wp) then
            call fail("ocean_kappa_shear_nml: ri_crit must be > 0", ierr, OCEAN_STATUS_ERR_SETUP)
            return
         end if
         if (ks%max_inner_it < 1) then
            call fail("ocean_kappa_shear_nml: max_inner_it must be >= 1", ierr, OCEAN_STATUS_ERR_SETUP)
            return
         end if
         if (ks%max_substep_it < 1) then
            call fail("ocean_kappa_shear_nml: max_substep_it must be >= 1", ierr, OCEAN_STATUS_ERR_SETUP)
            return
         end if
         if (ks%kappa_0 <= 0.0_wp) then
            call fail("ocean_kappa_shear_nml: kappa_0 must be > 0", ierr, OCEAN_STATUS_ERR_SETUP)
            return
         end if
         if (ks%tol_err <= 0.0_wp) then
            call fail("ocean_kappa_shear_nml: tol_err must be > 0", ierr, OCEAN_STATUS_ERR_SETUP)
            return
         end if
         if (ks%prandtl_turb <= 0.0_wp) then
            call fail("ocean_kappa_shear_nml: prandtl_turb must be > 0", ierr, OCEAN_STATUS_ERR_SETUP)
            return
         end if
         if (ks%vertex_geomean_kdmin < 0.0_wp) then
            call fail("ocean_kappa_shear_nml: vertex_geomean_kdmin must be >= 0", ierr, OCEAN_STATUS_ERR_SETUP)
            return
         end if
         if (compute_rank == 0) then
            ! Advisory warnings (MOM6-parity semantics, not errors).
            if (kcfg%vertex_geomean_kdmin > 0.0_wp .and. &
                .not. kcfg%vertex_geometric_mean) then
               call logger%warning("ocean_kappa_shear_nml: vertex_geomean_kdmin "// &
                                   "is inert without vertex_geometric_mean")
            end if
            if (kcfg%at_vertex .and. kcfg%vertex_geometric_mean .and. &
                kcfg%vertex_geomean_kdmin == 0.0_wp) then
               call logger%warning("ocean_kappa_shear_nml: geometric mean with "// &
                                   "kdmin=0 hard-zeros Kd wherever ANY corner is 0 "// &
                                   "(every shear-zone edge); production configs "// &
                                   "use vertex_geomean_kdmin=1e-9")
            end if
         end if

         if (compute_rank == 0) then
            call logger%info("Kappa-shear:      interior closure enabled "// &
                             "(ri_crit="//to_string(kcfg%ri_crit)// &
                             "  prandtl_turb="//to_string(kcfg%prandtl_turb)// &
                             trim(merge("  at_vertex", "           ", kcfg%at_vertex))//")")
         end if
         ks%enable = .true.
      end associate
      if (present(ierr)) ierr = OCEAN_STATUS_OK
   end subroutine configure_ocean_kappa_shear