| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| logical, | public | :: | at_vertex | = | .false. |
Solve the JHL08 columns at C-grid CORNERS (vorticity points)
instead of tracer points, then average the corner Kd back to
tracer points (MOM6 |
|
| real(kind=wp), | public | :: | c_n | = | 0.24_wp |
TKE decay vs N (TKE_N_DECAY_CONST). |
|
| real(kind=wp), | public | :: | c_s | = | 0.14_wp |
TKE decay vs shear (TKE_SHEAR_DECAY_CONST). |
|
| logical, | public | :: | enable | = | .false. |
Master switch. Default off — existing namelists and tests
stay bit-identical. Requires |
|
| type(eos_t), | public | :: | eos | ||||
| real(kind=wp), | public, | allocatable | :: | f_centre(:,:) |
|f| at cell centres (1/s); filled by |
||
| real(kind=wp), | public, | allocatable | :: | f_corner(:,:) |
SIGNED Coriolis f at C-grid corners (1/s), |
||
| real(kind=wp), | public | :: | fri_curvature | = | -0.97_wp |
Ri-function curvature (FRI_CURVATURE). |
|
| logical, | public | :: | is_init | = | .false. |
True between |
|
| real(kind=wp), | public | :: | kappa_0 | = | 1.0e-7_wp |
Background diffusivity (m^2/s); also the pre-step kappa. |
|
| real(kind=wp), | public | :: | kappa_seed | = | 1.0_wp |
Iteration seed diffusivity (m^2/s). |
|
| real(kind=wp), | public | :: | kappa_trunc | = | 1.0e-9_wp |
Diffusivity below this -> 0 (m^2/s). |
|
| real(kind=wp), | public, | allocatable | :: | kd_corner(:,:,:) |
Corner diffusivity at interfaces (m^2/s), |
||
| real(kind=wp), | public, | allocatable | :: | kd_int(:,:,:) |
Kappa-shear diffusivity at interfaces (m^2/s), (nx,ny,nz+1), global bottom-up: zero at bed (K=1) and surface (K=nz+1). |
||
| real(kind=wp), | public | :: | lambda | = | 0.82_wp |
Buoyancy length-scale coefficient (KAPPA_BUOY_SCALE_COEF). |
|
| real(kind=wp), | public | :: | lz_rescale | = | 1.0_wp |
Boundary-distance length-scale rescale (LZ_RESCALE). |
|
| logical, | public | :: | massless_merge | = | .false. |
is merged onto its massive sub-grid (rdb_massless), solved on
|
|
| integer, | public | :: | max_inner_it | = | 50 |
Inner Picard iteration cap (MAX_RINO_IT). |
|
| integer, | public | :: | max_substep_it | = | 13 |
Outer adaptive substep cap (MAX_KAPPA_SHEAR_IT). |
|
| real(kind=wp), | public | :: | prandtl_turb | = | 1.0_wp |
Kv = prandtl_turb * Kd into the momentum solve. |
|
| real(kind=wp), | public | :: | rho0 | = | 1035.0_wp |
Boussinesq reference density (kg/m^3). |
|
| real(kind=wp), | public | :: | ri_crit | = | 0.25_wp |
Critical Richardson number (MOM6 RINO_CRIT). |
|
| real(kind=wp), | public | :: | shearmix_rate | = | 0.089_wp |
Source-rate coefficient (SHEARMIX_RATE). |
|
| real(kind=wp), | public | :: | src_max_chg | = | 10.0_wp |
Adaptive-dt source-change tolerance band. |
|
| real(kind=wp), | public | :: | tke_bg | = | 0.0_wp |
Background TKE (m^2/s^2); Q is a denominator, floored. |
|
| real(kind=wp), | public, | allocatable | :: | tke_int(:,:,:) |
Time-mean TKE at interfaces (m^2/s^2), same shape/convention — diagnostic (currently filled to 0; reserved for the TKE budget diag). Vertex mode zeroes it (corner TKE not carried). |
||
| real(kind=wp), | public | :: | tol_err | = | 0.1_wp |
Picard convergence tolerance (KAPPA_SHEAR_TOL_ERR). |
|
| real(kind=wp), | public | :: | vel_underflow | = | 0.0_wp |
Velocity snap-to-zero magnitude (m/s) in the projection. |
|
| real(kind=wp), | public | :: | vertex_geomean_kdmin | = | 0.0_wp |
Floor (m^2/s) applied to each corner Kd BEFORE the geometric
mean (MOM6 |
|
| logical, | public | :: | vertex_geometric_mean | = | .false. |
Corner->centre averaging: geometric mean of the 4 corner Kd
(MOM6 |
Counted allocatable footprint of the kappa-shear slot (0 when unallocated). One arr_bytes term per array — add a term here when a new allocatable joins the type.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_kappa_shear_t), | intent(in) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_kappa_shear_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_kappa_shear_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_kappa_shear_t), | intent(inout) | :: | this |
Allocate the persistent fields. Always allocates (configure
runs after init, so enable is not known yet); the off-cost
is the f_centre + two interface fields.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_kappa_shear_t), | intent(inout) | :: | this | |||
| type(hgrid_t), | intent(in) | :: | grid | |||
| integer, | intent(in), | optional | :: | nz_ml |
Allocate the vertex-mode corner fields and set at_vertex.
Called at CONFIGURE time (after init, before enter_data) —
deliberately NOT from init, so the (nx+1,ny+1,nz+1) corner
carrier is only ever allocated when the vertex form is actually
selected (~327 MB at 1000x800x50).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_kappa_shear_t), | intent(inout) | :: | this | |||
| type(hgrid_t), | intent(in) | :: | grid | |||
| integer, | intent(in) | :: | nz_ml |
Fill f_centre with the beta-plane Coriolis magnitude at cell
centres: |f_0 + beta*(y - y_ref)|. Mirrors EPBL’s
set_f_centre. Call after init, before enter_data.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_kappa_shear_t), | intent(inout) | :: | this | |||
| type(hgrid_t), | intent(in) | :: | grid | |||
| real(kind=wp), | intent(in) | :: | f_0 | |||
| real(kind=wp), | intent(in) | :: | beta | |||
| real(kind=wp), | intent(in) | :: | y_ref |
Fill f_corner with the SIGNED beta-plane Coriolis at C-grid
corners: f_0 + beta(y - y_ref), corner row j at
y = (j-1-nghost)dy (half a cell below centre row j — corner
(i,j) is the SW corner of cell (i,j)). Bit-identical to
metrics_fill_coriolis’s beta-plane corner fill. Call after
init_vertex, before enter_data.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_kappa_shear_t), | intent(inout) | :: | this | |||
| type(hgrid_t), | intent(in) | :: | grid | |||
| real(kind=wp), | intent(in) | :: | f_0 | |||
| real(kind=wp), | intent(in) | :: | beta | |||
| real(kind=wp), | intent(in) | :: | y_ref |
type :: ocean_kappa_shear_t logical :: is_init = .false. !! True between `init` and `destroy`. ! ---- Scheme selection + master switch ---- logical :: enable = .false. !! Master switch. Default off — existing namelists and tests !! stay bit-identical. Requires `vmix%use_closure` + !! thermodynamics (validated at configure). ! ---- JHL08 knobs (defaults = paper / OM4 production) ---- real(wp) :: ri_crit = 0.25_wp !! Critical Richardson number (MOM6 RINO_CRIT). real(wp) :: shearmix_rate = 0.089_wp !! Source-rate coefficient (SHEARMIX_RATE). real(wp) :: fri_curvature = -0.97_wp !! Ri-function curvature (FRI_CURVATURE). real(wp) :: c_n = 0.24_wp !! TKE decay vs N (TKE_N_DECAY_CONST). real(wp) :: c_s = 0.14_wp !! TKE decay vs shear (TKE_SHEAR_DECAY_CONST). real(wp) :: lambda = 0.82_wp !! Buoyancy length-scale coefficient (KAPPA_BUOY_SCALE_COEF). real(wp) :: lz_rescale = 1.0_wp !! Boundary-distance length-scale rescale (LZ_RESCALE). real(wp) :: kappa_0 = 1.0e-7_wp !! Background diffusivity (m^2/s); also the pre-step kappa. real(wp) :: kappa_seed = 1.0_wp !! Iteration seed diffusivity (m^2/s). real(wp) :: kappa_trunc = 1.0e-9_wp !! Diffusivity below this -> 0 (m^2/s). real(wp) :: tke_bg = 0.0_wp !! Background TKE (m^2/s^2); Q is a denominator, floored. real(wp) :: tol_err = 0.1_wp !! Picard convergence tolerance (KAPPA_SHEAR_TOL_ERR). integer :: max_inner_it = 50 !! Inner Picard iteration cap (MAX_RINO_IT). integer :: max_substep_it = 13 !! Outer adaptive substep cap (MAX_KAPPA_SHEAR_IT). real(wp) :: src_max_chg = 10.0_wp !! Adaptive-dt source-change tolerance band. real(wp) :: prandtl_turb = 1.0_wp !! Kv = prandtl_turb * Kd into the momentum solve. real(wp) :: vel_underflow = 0.0_wp !! Velocity snap-to-zero magnitude (m/s) in the projection. logical :: massless_merge = .false. !! D4: when on, a column carrying vanished (< H_VANISHED) layers !! is merged onto its massive sub-grid (rdb_massless), solved on !! `nzc <= nz` layers, and the kappa/TKE interface fields are !! interpolated back — replacing the blunt `max(h, H_VANISHED)` !! gather floor. Default off (bit-identical). A per-column !! `any(h < H_VANISHED)` precheck makes healthy columns bypass !! the merge machinery entirely, so knob-on stays bit-identical !! on healthy envelopes (invariant I1). ! ---- Vertex (corner) form — MOM6 VERTEX_SHEAR ---- logical :: at_vertex = .false. !! Solve the JHL08 columns at C-grid CORNERS (vorticity points) !! instead of tracer points, then average the corner Kd back to !! tracer points (MOM6 `VERTEX_SHEAR`; the OM5-class production !! setting). The corner column sees the native face velocities !! without the u_h/v_h centre average, so resolved shear is not !! damped before the solve. Default off — bit-identical. !! Kd: corner solve -> Pass-C average -> `kd_int` at tracer !! points. Kv: routed corner->face (MOM6 `Kv_shear_Bu` !! consumed in vertvisc) — `kd_corner` feeds !! `vdiff_apply_momentum`'s `kv_corner_source` seam scaled by !! `prandtl_turb`, and the cell-centred kv merge is suppressed !! (no corner->centre->face smoothing, no double-count). !! Corner TKE is not carried (`tke_int` is zeroed in vertex !! mode). logical :: vertex_geometric_mean = .false. !! Corner->centre averaging: geometric mean of the 4 corner Kd !! (MOM6 `VERTEX_SHEAR_GEOMETRIC_MEAN`) instead of the plain !! arithmetic mean. A geometric mean is 0 if ANY corner is 0 — !! pair with `vertex_geomean_kdmin` (see below). real(wp) :: vertex_geomean_kdmin = 0.0_wp !! Floor (m^2/s) applied to each corner Kd BEFORE the geometric !! mean (MOM6 `VERTEX_SHEAR_GEOMETRIC_MEAN_KDMIN`; inert unless !! `vertex_geometric_mean`). With 0 the geometric mean hard- !! zeros Kd at every shear-zone edge; OM5 configs use 1e-9. ! ---- EOS hookup (shared handle from the eos slot) ---- ! Value copy of the flat-POD `eos_t` set at configure ! from `ocean_state%eos` — the buoyancy derivatives use the ! SAME EOS the dyn-core runs. Maps onto the device with the ! parent for free; one source of truth (no drifting copies). type(eos_t) :: eos real(wp) :: rho0 = 1035.0_wp !! Boussinesq reference density (kg/m^3). ! ---- Persistent fields ---- real(wp), allocatable :: f_centre(:, :) !! |f| at cell centres (1/s); filled by `set_f_centre`. real(wp), allocatable :: kd_int(:, :, :) !! Kappa-shear diffusivity at interfaces (m^2/s), (nx,ny,nz+1), !! global bottom-up: zero at bed (K=1) and surface (K=nz+1). real(wp), allocatable :: tke_int(:, :, :) !! Time-mean TKE at interfaces (m^2/s^2), same shape/convention !! — diagnostic (currently filled to 0; reserved for the TKE !! budget diag). Vertex mode zeroes it (corner TKE not carried). ! ---- Vertex-mode persistent fields (allocated by `init_vertex`, ! only when `at_vertex` — the corner carrier is nz+1 full planes) ---- real(wp), allocatable :: f_corner(:, :) !! SIGNED Coriolis f at C-grid corners (1/s), `(nx+1,ny+1)`; !! corner (i,j) is the SW corner of cell (i,j). The kernel !! squares it (MOM6 vertex form takes f^2 straight at the !! corner, no 4-point average). Filled by `set_f_corner` !! (beta-plane) or `fill_coriolis_corner` at configure. real(wp), allocatable :: kd_corner(:, :, :) !! Corner diffusivity at interfaces (m^2/s), `(nx+1,ny+1,nz+1)`, !! global bottom-up. The Pass-B -> Pass-C carrier (MOM6 !! `kappa_vertex`): the corner solve writes it, the scatter !! kernel averages it to tracer points, and the momentum vdiff !! reads it as the corner Kv source (`kv_corner_source`, !! scaled by `prandtl_turb` — the corner->face viscosity seam, !! MOM6 `Kv_shear_Bu`). A REQUIRED snapshot — !! fusing solve+scatter would be a read-neighbour/write-own !! `do concurrent` race. Ring corners (ic=1, ic=nx+1, jc=1, !! jc=ny+1) are never solved and stay exactly 0. contains procedure, non_overridable :: init => ocean_kappa_shear_init procedure, non_overridable :: init_vertex => ocean_kappa_shear_init_vertex procedure, non_overridable :: destroy => ocean_kappa_shear_destroy procedure, non_overridable :: enter_data => ocean_kappa_shear_enter_data procedure, non_overridable :: exit_data => ocean_kappa_shear_exit_data procedure, non_overridable :: set_f_centre => ocean_kappa_shear_set_f_centre procedure, non_overridable :: set_f_corner => ocean_kappa_shear_set_f_corner procedure, non_overridable :: bytes => ocean_kappa_shear_bytes end type ocean_kappa_shear_t