| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | public, | parameter | :: | BBL_FORM_LINEAR | = | 1 |
|
| integer, | public, | parameter | :: | BBL_FORM_QUADRATIC | = | 2 |
|
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| real(kind=wp), | public | :: | K_v_momentum | = | 0.0_wp |
Constant momentum vertical viscosity (m^2/s). Zero is a no-op. |
|
| real(kind=wp), | public | :: | K_v_tracer | = | 0.0_wp |
Constant tracer vertical diffusivity (m^2/s). Zero is a no-op. |
|
| type(scratch_3d_buffer_t), | public | :: | a_diag_t |
Sub-diagonal for the tracer solve. Shape (nx, ny, nz). |
|||
| type(scratch_3d_buffer_t), | public | :: | a_diag_u |
East-face (u) tridiagonal scratch. |
|||
| type(scratch_3d_buffer_t), | public | :: | a_diag_v |
North-face (v) tridiagonal scratch. |
|||
| type(scratch_3d_buffer_t), | public | :: | b_diag_t |
Main diagonal. |
|||
| type(scratch_3d_buffer_t), | public | :: | b_diag_u |
East-face (u) tridiagonal scratch. |
|||
| type(scratch_3d_buffer_t), | public | :: | b_diag_v |
North-face (v) tridiagonal scratch. |
|||
| real(kind=wp), | public | :: | bbl_bg_vel | = | 0.0_wp |
MOM6 |
|
| real(kind=wp), | public | :: | bbl_cd | = | 0.0_wp |
MOM6 |
|
| real(kind=wp), | public, | allocatable | :: | bbl_conc_s(:,:,:) |
Cell salinity concentration, as |
||
| real(kind=wp), | public, | allocatable | :: | bbl_conc_t(:,:,:) |
Cell temperature CONCENTRATION |
||
| integer, | public | :: | bbl_form | = | BBL_FORM_QUADRATIC |
Drag law of the BBL ( |
|
| logical, | public | :: | bbl_glue | = | .false. |
MOM6 |
|
| real(kind=wp), | public | :: | bbl_hbbl | = | 0.0_wp |
MOM6 |
|
| logical, | public | :: | bbl_per_face | = | .false. |
The MOM6 bottom boundary layer ( |
|
| real(kind=wp), | public | :: | bbl_piston | = | 3.0e-4_wp |
BBL drag piston velocity u* (m/s) for |
|
| real(kind=wp), | public | :: | bbl_rho0 | = | 1035.0_wp |
Boussinesq reference density of the BBL stratification measure. |
|
| logical, | public | :: | bbl_rino_cap | = | .false. |
MOM6 |
|
| real(kind=wp), | public | :: | bbl_thick_min | = | 0.0_wp |
MOM6 |
|
| real(kind=wp), | public, | allocatable | :: | bbl_thick_u(:,:) |
BBL thickness (m) at u-faces, |
||
| real(kind=wp), | public, | allocatable | :: | bbl_thick_v(:,:) |
BBL thickness (m) at v-faces, |
||
| type(scratch_3d_buffer_t), | public | :: | c_diag_t |
Super-diagonal (overwritten by |
|||
| type(scratch_3d_buffer_t), | public | :: | c_diag_u |
East-face (u) tridiagonal scratch. |
|||
| type(scratch_3d_buffer_t), | public | :: | c_diag_v |
North-face (v) tridiagonal scratch. |
|||
| real(kind=wp), | public | :: | hbbl_visc | = | 10.0_wp |
Bottom-boundary-layer scale for the |
|
| logical, | public | :: | hvel_harmonic | = | .false. |
Which MOM6 face-thickness branch |
|
| logical, | public | :: | hvel_mom6 | = | .false. |
MOM6 |
|
| logical, | public | :: | hvel_upwind | = | .true. |
Near-bed upwind (arithmetic-donor) blend inside the
|
|
| logical, | public | :: | implicit_drag | = | .false. |
Fold the quadratic / linear bottom drag into the backward-Euler
vertical-friction tridiagonal as a stress bottom-BC diagonal
coupling ( |
|
| logical, | public | :: | implicit_stress | = | .false. |
Fold the surface wind stress into the backward-Euler vertical-
friction tridiagonal as a Neumann top-BC right-hand-side term
( |
|
| logical, | public | :: | implicit_top_drag | = | .false. |
Fold the ICE-SHELF TOP drag into the |
|
| logical, | public | :: | is_init | = | .false. |
True between |
|
| real(kind=wp), | public | :: | kv_bbl_bg | = | 1.0e-4_wp |
MOM6 |
|
| real(kind=wp), | public, | allocatable | :: | kv_bbl_u(:,:) |
BBL viscosity |
||
| real(kind=wp), | public, | allocatable | :: | kv_bbl_v(:,:) |
BBL viscosity at v-faces, |
||
| type(scratch_3d_buffer_t), | public | :: | kv_scalar_buf |
Diffusivity workspace used when no 3D source is provided. |
|||
| type(scratch_3d_buffer_t), | public | :: | rhs_t |
Right-hand side / solution. |
|||
| type(scratch_3d_buffer_t), | public | :: | rhs_u |
East-face (u) tridiagonal scratch. |
|||
| type(scratch_3d_buffer_t), | public | :: | rhs_v |
North-face (v) tridiagonal scratch. |
|||
| logical, | public | :: | use_harmonic | = | .false. |
MOM6 HARMONIC_VISC analogue. When |
|
| logical, | public | :: | zlevel_faces | = | .false. |
|
| procedure, public, non_overridable :: bytes => ocean_vdiff_bytes | |
| procedure, public, non_overridable :: destroy => ocean_vdiff_destroy | |
| procedure, public, non_overridable :: enter_data => ocean_vdiff_enter_data | |
| procedure, public, non_overridable :: exit_data => ocean_vdiff_exit_data | |
| procedure, public, non_overridable :: init => ocean_vdiff_init |
Public only for the unit-test suite (no production module imports it); ignore when developing production code in other modules. Face-thickness for the vdiff implicit operator.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | h_a | |||
| real(kind=wp), | intent(in) | :: | h_b | |||
| logical, | intent(in) | :: | use_harmonic |
Counted allocatable footprint of the implicit vertical diffusion slot (0 when unallocated).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_vdiff_t), | intent(in) | :: | this |
Backward-Euler vertical viscosity applied to
ms%u_face_x_layer and ms%v_face_y_layer. Per-face
h_face averaged from the two abutting cell columns.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_vdiff_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| real(kind=wp), | intent(in), | optional | :: | kv_source(grid%nx_total,grid%ny_total,ms%nz_ml+1) | ||
| real(kind=wp), | intent(in), | optional | :: | tau_u(grid%nx_total+1,grid%ny_total) | ||
| real(kind=wp), | intent(in), | optional | :: | tau_v(grid%nx_total,grid%ny_total+1) | ||
| real(kind=wp), | intent(in), | optional | :: | lambda_bot_u(grid%nx_total+1,grid%ny_total) | ||
| real(kind=wp), | intent(in), | optional | :: | lambda_bot_v(grid%nx_total,grid%ny_total+1) | ||
| real(kind=wp), | intent(in), | optional | :: | rho0 |
Boussinesq reference density for the implicit surface-stress
fold, |
|
| real(kind=wp), | intent(inout), | optional | :: | visc_rem_u(grid%nx_total+1,grid%ny_total,ms%nz_ml) | ||
| real(kind=wp), | intent(inout), | optional | :: | visc_rem_v(grid%nx_total,grid%ny_total+1,ms%nz_ml) |
Explicit-shape for the reason spelled out on the argument list above. |
|
| logical, | intent(in), | optional | :: | remnant_only |
|
|
| real(kind=wp), | intent(in), | optional | :: | kv_corner_source(grid%nx_total+1,grid%ny_total+1,ms%nz_ml+1) |
Corner-staggered interface viscosity source, |
|
| real(kind=wp), | intent(in), | optional | :: | kv_corner_prandtl |
Scale applied to |
|
| real(kind=wp), | intent(in), | optional | :: | lambda_top_u(grid%nx_total+1,grid%ny_total) | ||
| real(kind=wp), | intent(in), | optional | :: | lambda_top_v(grid%nx_total,grid%ny_total+1) | ||
| real(kind=wp), | intent(in), | optional | :: | cover_u(grid%nx_total+1,grid%ny_total) | ||
| real(kind=wp), | intent(in), | optional | :: | cover_v(grid%nx_total,grid%ny_total+1) |
Backward-Euler vertical diffusivity on every registered
tracer. Each tracer is converted to T = hTr/h, the
tridiagonal solve runs, then hTr = T*h is reconstituted.
h_layer is untouched. Per-tracer
do_vertical_diffusion flag gates participation.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_vdiff_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| real(kind=wp), | intent(in), | optional | :: | kt_source(:,:,:) |
Temperature diffusivity, (nx, ny, nz+1), interface-located. |
|
| real(kind=wp), | intent(in), | optional | :: | ks_source(:,:,:) |
Salinity + passive-tracer diffusivity, same shape. MUST
be accompanied by |
Latch the MOM6 per-face bottom boundary layer (bbl_per_face) from
the bottom-drag configuration and size its workspace. Called once
at configure, BEFORE enter_data, by rdb_ocean_setup when
bbl_glue is on. MOM6 set_visc_init is the parameter map:
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_vdiff_t), | intent(inout) | :: | this | |||
| integer, | intent(in) | :: | nx |
Cell-centred extents (ghosts included) of the workspace. |
||
| integer, | intent(in) | :: | ny |
Cell-centred extents (ghosts included) of the workspace. |
||
| integer, | intent(in) | :: | nz |
Cell-centred extents (ghosts included) of the workspace. |
||
| integer, | intent(in) | :: | form |
|
||
| real(kind=wp), | intent(in) | :: | cd |
Quadratic drag coefficient (dimensionless). |
||
| real(kind=wp), | intent(in) | :: | r_linear |
Linear drag rate (1/s) of the HBBL-distributed linear drag. |
||
| real(kind=wp), | intent(in) | :: | hbbl |
MOM6 |
||
| real(kind=wp), | intent(in) | :: | bg_vel |
MOM6 |
||
| real(kind=wp), | intent(in) | :: | thick_min |
MOM6 |
||
| logical, | intent(in) | :: | rino_cap |
MOM6 |
||
| real(kind=wp), | intent(in) | :: | rho0 |
Boussinesq reference density (kg/m^3). |
||
| real(kind=wp), | intent(in) | :: | kv_bg |
MOM6 |
MOM6 set_viscous_BBL (the
BOTTOMDRAGLAW branch): the per-face bottom-boundary-layer
viscosity kv_bbl_u/v and thickness bbl_thick_u/v that the
vertical-friction glue reads. Called ONCE per outer step, before
the stage loop, from the state at the start of the step — MOM6
calls it once per step, from step_MOM_dynamics, before the
predictor. No-op unless bbl_glue .and. bbl_per_face.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_vdiff_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(in) | :: | ms | |||
| type(eos_t), | intent(in) | :: | eos |
The run’s equation of state, for |
||
| real(kind=wp), | intent(in) | :: | f_corner(grid%nx_total+1,grid%ny_total+1) |
Coriolis parameter at cell SW corners (1/s), |
Apply the pre-factored tridiagonal (from
build_factorize_tracer_matrix) to one tracer: form T = hTr/h,
run the Thomas RHS sweep + back-substitution against the stored
pivots, and reconstitute hTr = T_new * h_layer. Operates on
concentration so it conserves cell-centred T; h_layer and the
factored a/b/c are read-only (shared across every tracer).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | h_layer(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | hTr(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | a_diag(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | b_diag(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | c_diag(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | rhs(nx,ny,nz) | |||
| real(kind=wp), | intent(inout), | optional | :: | budget(nx,ny,nz) |
Cell concentrations of one tracer through THE vanished-layer column
rule (rdb_vl_column_conc): hTr/h on a live layer, the donor’s
concentration on a filler, never a quotient by a near-zero or
negative thickness.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | h(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | htr(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | conc(nx,ny,nz) |
Per-face body of vdiff_set_viscous_bbl (see there). x_face
selects the u-faces (nx+1, ny) (cells i-1, i) or the v-faces
(nx, ny+1) (cells j-1, j).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nu | |||
| integer, | intent(in) | :: | nv | |||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| logical, | intent(in) | :: | x_face | |||
| real(kind=wp), | intent(in) | :: | u_x(nx+1,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | v_y(nx,ny+1,nz) | |||
| real(kind=wp), | intent(in) | :: | h(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | wet(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | conc_t(ncx,ncy,ncz) | |||
| real(kind=wp), | intent(in) | :: | conc_s(ncx,ncy,ncz) |
Cell T/S concentrations; read only when |
||
| integer, | intent(in) | :: | ncx | |||
| integer, | intent(in) | :: | ncy | |||
| integer, | intent(in) | :: | ncz | |||
| real(kind=wp), | intent(in) | :: | f_corner(nx+1,ny+1) | |||
| logical, | intent(in) | :: | use_eos | |||
| type(eos_t), | intent(in) | :: | eos | |||
| integer, | intent(in) | :: | form | |||
| real(kind=wp), | intent(in) | :: | cd | |||
| real(kind=wp), | intent(in) | :: | hbbl | |||
| real(kind=wp), | intent(in) | :: | bg_vel | |||
| real(kind=wp), | intent(in) | :: | thick_min | |||
| logical, | intent(in) | :: | rino_cap | |||
| real(kind=wp), | intent(in) | :: | rho0 | |||
| real(kind=wp), | intent(inout) | :: | kv_bbl(nu,nv) | |||
| real(kind=wp), | intent(inout) | :: | bbl_thick(nu,nv) |
Build the backward-Euler tridiagonal per cell column and run the
Thomas forward factorization — the tracer-INDEPENDENT half of the
vertical-diffusion solve (depends only on kv/h/dt). Run once per
stage; every registered tracer then reuses the factored
coefficients via apply_factored_tracer.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| logical, | intent(in) | :: | use_harmonic | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| real(kind=wp), | intent(in) | :: | kv_centre(nx,ny,nz+1) | |||
| real(kind=wp), | intent(in) | :: | h_layer(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | a_diag(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | b_diag(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | c_diag(nx,ny,nz) |
Build + solve the tridiagonal system per face column.
u_face is either u_face_x_layer (x_face = .true.,
shape (nx+1, ny)) or v_face_y_layer (x_face = .false.,
shape (nx, ny+1)). h_layer is cell-centred (nx, ny, nz)
and we average across the face direction to get the face
thickness. kv_centre is the same cell-centred diffusivity
field used by the tracer kernel — we average it across the
face to get a face-located value at each interface.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nu | |||
| integer, | intent(in) | :: | nv | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| real(kind=wp), | intent(inout) | :: | u_face(nu,nv,nz) | |||
| real(kind=wp), | intent(in) | :: | h_layer(nx_cells,ny_cells,nz) | |||
| real(kind=wp), | intent(in) | :: | kv_centre(nx_cells,ny_cells,nz+1) | |||
| real(kind=wp), | intent(in) | :: | wet_cell(nx_cells,ny_cells) |
Cell-centred wet/dry land mask (1 wet, 0 land). The wind-stress
fold multiplies |
||
| logical, | intent(in) | :: | x_face | |||
| integer, | intent(in) | :: | nx_cells | |||
| integer, | intent(in) | :: | ny_cells | |||
| logical, | intent(in) | :: | use_harmonic | |||
| real(kind=wp), | intent(inout) | :: | a_diag(nu,nv,nz) | |||
| real(kind=wp), | intent(inout) | :: | b_diag(nu,nv,nz) | |||
| real(kind=wp), | intent(inout) | :: | c_diag(nu,nv,nz) | |||
| real(kind=wp), | intent(inout) | :: | rhs(nu,nv,nz) | |||
| logical, | intent(in) | :: | do_stress |
Fold the surface wind stress into the |
||
| logical, | intent(in) | :: | do_drag |
Fold the bottom drag into the |
||
| real(kind=wp), | intent(in) | :: | rho0 |
Boussinesq reference density for the |
||
| real(kind=wp), | intent(in), | optional | :: | tau_face(nu,nv) |
Wind stress (N/m²) on this face. Present iff |
|
| real(kind=wp), | intent(in), | optional | :: | lambda_bot(nu,nv) |
Bottom-drag Rayleigh rate λ (1/s) on this face. Present iff
|
|
| logical, | intent(in) | :: | do_top |
Fold the ice-shelf top drag into the |
||
| real(kind=wp), | intent(in), | optional | :: | lambda_top(nu,nv) |
Top-drag Rayleigh rate λ (1/s) on this face. Present iff
|
|
| real(kind=wp), | intent(in), | optional | :: | cover_face(nu,nv) |
Face ice-cover mask (0 open, 1 under ice), the OR of the two
abutting cells ( |
|
| logical, | intent(in) | :: | solve_momentum |
|
||
| logical, | intent(in) | :: | do_remnant |
Fill |
||
| real(kind=wp), | intent(inout), | optional | :: | visc_rem_out(nu,nv,nz) |
Output γ_k, bottom-up ( |
|
| logical, | intent(in) | :: | hvel_mom6 |
MOM6 HARMONIC_VISC parity for |
||
| real(kind=wp), | intent(in) | :: | hbbl_visc |
Bottom-layer scale for the |
||
| logical, | intent(in) | :: | bbl_glue |
MOM6 |
||
| logical, | intent(in) | :: | hvel_upwind |
|
||
| logical, | intent(in) | :: | hvel_harmonic |
MOM6 |
||
| real(kind=wp), | intent(in) | :: | kv_bbl_face(nu,nv) |
BBL viscosity |
||
| real(kind=wp), | intent(in) | :: | bbl_thick_face(nu,nv) |
BBL thickness (m) of this face (MOM6 |
||
| real(kind=wp), | intent(in) | :: | kv_bbl_bg |
MOM6 |
||
| logical, | intent(in) | :: | do_corner |
Add the corner-staggered viscosity to every face interface.
Gated INSIDE the single DC (no split loop — NVHPC penalty);
|
||
| real(kind=wp), | intent(in) | :: | kv_prandtl |
Scale on |
||
| real(kind=wp), | intent(in), | optional | :: | kv_corner(nx_cells+1,ny_cells+1,nz+1) |
Corner-staggered interface viscosity (SW-corner convention:
corner (i,j) is the SW corner of cell (i,j)). A face reads
the 2-point average of its two END corners: u-face (i,j) →
corners (i,j)/(i,j+1); v-face (i,j) → corners (i,j)/(i+1,j)
— the direct corner→face route, never via a tracer point.
Present iff |
|
| logical, | intent(in) | :: | zlevel_faces |
|
||
| integer, | intent(in) | :: | k_top_face(nu,nv) |
|
||
| integer, | intent(in) | :: | k_bot_face(nu,nv) |
|
The historical constant-piston glue (bbl_per_face = .false.).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | kv_bbl(nu,nv) | |||
| real(kind=wp), | intent(inout) | :: | bbl_thick(nu,nv) | |||
| real(kind=wp), | intent(in) | :: | kv_val | |||
| real(kind=wp), | intent(in) | :: | thick_val | |||
| integer, | intent(in) | :: | nu | |||
| integer, | intent(in) | :: | nv |
Broadcast the scalar viscosity kappa into the
interface-located workspace. Boundary interfaces (bed at
k=1, surface at k=nz+1) are forced to zero to match the
closed BCs the column solve assumes; the original scalar
kernel hard-coded those BCs via α_1 = 0 and β_nz = 0.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(out) | :: | kv_buf(nx,ny,nz+1) | |||
| real(kind=wp), | intent(in) | :: | kappa | |||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_vdiff_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_vdiff_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_vdiff_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_vdiff_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_vdiff_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_vdiff_t), | intent(inout) | :: | this | |||
| type(hgrid_t), | intent(in) | :: | grid | |||
| integer, | intent(in), | optional | :: | nz_ml |