rdb_ocean_top_drag Module


Uses

  • module~~rdb_ocean_top_drag~~UsesGraph module~rdb_ocean_top_drag rdb_ocean_top_drag iso_fortran_env iso_fortran_env module~rdb_ocean_top_drag->iso_fortran_env module~rdb_constants rdb_constants module~rdb_ocean_top_drag->module~rdb_constants module~rdb_grid rdb_grid module~rdb_ocean_top_drag->module~rdb_grid module~rdb_mem_report rdb_mem_report module~rdb_ocean_top_drag->module~rdb_mem_report module~rdb_multilayer_state rdb_multilayer_state module~rdb_ocean_top_drag->module~rdb_multilayer_state module~rdb_scratch_3d rdb_scratch_3d module~rdb_ocean_top_drag->module~rdb_scratch_3d pic_types pic_types module~rdb_constants->pic_types module~rdb_grid->module~rdb_constants module~rdb_mem_report->iso_fortran_env module~rdb_mem_report->module~rdb_constants pic_logger pic_logger module~rdb_mem_report->pic_logger pic_strings pic_strings module~rdb_mem_report->pic_strings module~rdb_multilayer_state->iso_fortran_env module~rdb_multilayer_state->module~rdb_constants module~rdb_multilayer_state->module~rdb_grid module~rdb_multilayer_state->module~rdb_mem_report module~rdb_efp rdb_efp module~rdb_multilayer_state->module~rdb_efp module~rdb_error_ring rdb_error_ring module~rdb_multilayer_state->module~rdb_error_ring module~rdb_tracer rdb_tracer module~rdb_multilayer_state->module~rdb_tracer module~rdb_multilayer_state->pic_logger module~rdb_scratch_3d->iso_fortran_env module~rdb_scratch_3d->module~rdb_constants module~rdb_scratch_3d->module~rdb_mem_report module~rdb_efp->iso_fortran_env ieee_arithmetic ieee_arithmetic module~rdb_efp->ieee_arithmetic module~rdb_error_ring->pic_logger module~rdb_tracer->iso_fortran_env module~rdb_tracer->module~rdb_constants module~rdb_tracer->module~rdb_grid module~rdb_tracer->module~rdb_mem_report

Used by

  • module~~rdb_ocean_top_drag~~UsedByGraph module~rdb_ocean_top_drag rdb_ocean_top_drag module~rdb_barotropic_coupling rdb_barotropic_coupling module~rdb_barotropic_coupling->module~rdb_ocean_top_drag module~rdb_ocean_dyn rdb_ocean_dyn module~rdb_ocean_dyn->module~rdb_ocean_top_drag module~rdb_ocean_dyn->module~rdb_barotropic_coupling module~rdb_ocean_setup rdb_ocean_setup module~rdb_ocean_setup->module~rdb_ocean_top_drag module~rdb_ocean_setup->module~rdb_ocean_dyn module~rdb_ocean_state rdb_ocean_state module~rdb_ocean_setup->module~rdb_ocean_state module~rdb_ocean_state->module~rdb_ocean_top_drag module~rdb_ocean_state->module~rdb_ocean_dyn proc~validate_config validate_config proc~validate_config->module~rdb_ocean_top_drag module~rdb_driver rdb_driver module~rdb_driver->module~rdb_ocean_dyn module~rdb_driver->module~rdb_ocean_state module~rdb_ocean_engine rdb_ocean_engine module~rdb_driver->module~rdb_ocean_engine module~rdb_handle rdb_handle module~rdb_handle->module~rdb_ocean_state module~rdb_handle->module~rdb_ocean_engine module~rdb_ocean_api rdb_ocean_api module~rdb_ocean_api->module~rdb_ocean_dyn module~rdb_ocean_api->module~rdb_handle module~rdb_ocean_diag_derived rdb_ocean_diag_derived module~rdb_ocean_api->module~rdb_ocean_diag_derived module~rdb_ocean_diag_fills rdb_ocean_diag_fills module~rdb_ocean_api->module~rdb_ocean_diag_fills module~rdb_ocean_api->module~rdb_ocean_engine module~rdb_ocean_diag_derived->module~rdb_ocean_state module~rdb_ocean_diag_derived->module~rdb_ocean_diag_fills module~rdb_ocean_diag_fills->module~rdb_ocean_state module~rdb_ocean_engine->module~rdb_ocean_dyn module~rdb_ocean_engine->module~rdb_ocean_setup module~rdb_ocean_engine->module~rdb_ocean_state module~rdb_ocean_engine->module~rdb_ocean_diag_derived module~rdb_ocean_engine->module~rdb_ocean_diag_fills

Variables

Type Visibility Attributes Name Initial
integer, public, parameter :: TDRAG_INVALID = -1

Sentinel for an unrecognised form string. Linear and quadratic carry different coefficient DIMENSIONS and different decay laws, so a typo must abort rather than silently pick one.

integer, public, parameter :: TDRAG_LINEAR = 1

Linear Rayleigh top drag, du/dt = -r*u. The form with a closed-form spin-down; used by the analytic decay gate.

integer, public, parameter :: TDRAG_QUADRATIC = 2

Quadratic (log-layer) top drag, du/dt = -C_d*|U|*u/h. Production default when the group is enabled.


Derived Types

type, public ::  ocean_top_drag_t

Ice-shelf top-drag slot. Every array is full size when enable, a (1,1) / (1,1,1) placeholder otherwise — the ocean_cavity_flux_t gating convention, latched in ocean_state_init_from_config BEFORE init so the allocation gate can read it.

Components

Type Visibility Attributes Name Initial
real(kind=wp), public :: c_drag = 0.0_wp

Quadratic drag coefficient (dimensionless). ISOMIP+ 2.5e-3. Zero disables the quadratic branch.

real(kind=wp), public, allocatable :: cover_t(:,:)

CELL-CENTRED ice-cover mask, shape (nx, ny) — a configure-time copy of metrics%cover_frac. Held on the slot (rather than reaching into metrics per step) so the kernel signature carries exactly the fields it reads. Used only by the stress_top diagnostic, which is cell-centred.

real(kind=wp), public, allocatable :: cover_u(:,:)

Face ice-cover mask at east faces, shape (nx+1, ny): the OR of the two abutting cells’ cover_frac (see the module docstring). STATIC — filled once at configure.

real(kind=wp), public, allocatable :: cover_v(:,:)

Face ice-cover mask at north faces, shape (nx, ny+1).

real(kind=wp), public :: drag_bg_vel = 0.0_wp

Background velocity floor (m/s) in the quadratic speed, |U_eff| = max(drag_bg_vel, |U_tbl|) (the mirror of MOM6 DRAG_BG_VEL). UNLIKE the bottom-drag slot, this is honoured in BOTH the layer-only and distributed modes — the two kernels are one code path here. Zero (default) ⇒ no floor ⇒ the layer-only quadratic branch is the exact algebraic mirror of ocean_bottom_drag_compute_tendencies.

type(scratch_3d_buffer_t), public :: du_drag

Top-drag tendency at east faces, shape (nx+1, ny, nz). Only layers inside the top boundary layer carry a non-zero value.

type(scratch_3d_buffer_t), public :: dv_drag

Top-drag tendency at north faces, shape (nx, ny+1, nz).

logical, public :: enable = .false.

&ocean_tdrag_nml enable, latched before init. Off ⇒ placeholders, no kernel launch, byte-identical.

real(kind=wp), public :: h_min = 1.0e-3_wp

Floor on the top-layer face thickness inside the u/h_top division — keeps the kernel finite when the top layer pinches out. Matches the bottom-drag h_min.

real(kind=wp), public :: htbl = 0.0_wp

Top-boundary-layer thickness (m) the stress is distributed over (the mirror of hbbl). Zero (default) = layer-nz-only mode.

logical, public :: implicit = .false.

Backward-Euler top drag in this kernel: the tendency is formed as -lambda*u/(1 + dt*lambda) so the standalone apply gives u^{n+1} = u/(1 + dt*lambda). Unconditionally stable for any layer thickness. Default .false. = explicit forward Euler.

logical, public :: implicit_fold = .false.

&ocean_vdiff_nml implicit_top_drag: fill lambda_top_u/v so the vdiff solver can fold the drag into its k = nz diagonal, and let the driver SKIP the explicit apply. Default .false. ⇒ the rate fields stay zero.

logical, public :: is_init = .false.

True between init and destroy. Always test this, never allocated(...).

real(kind=wp), public, allocatable :: lambda_top_u(:,:)

Top-layer (k=nz) Rayleigh RATE lambda (1/s) at east faces, shape (nx+1, ny): C_d*|U|/h_nz (quadratic, |U| frozen at u^n) or r (linear), already cover- and wet-masked. Consumed by vdiff_apply_momentum as the +dt*lambda add on the k = nz diagonal. Zero unless implicit_fold.

real(kind=wp), public, allocatable :: lambda_top_v(:,:)

Top-layer Rayleigh rate at north faces, shape (nx, ny+1).

real(kind=wp), public :: r_linear = 0.0_wp

Linear Rayleigh coefficient (1/s). Zero disables the linear branch even when the variant tag selects it.

real(kind=wp), public :: rho0 = 0.0_wp

Boussinesq reference density (kg/m^3) — eos%rho0 via configure_ocean_reference_density. Used ONLY to turn the kinematic drag into the stress_top diagnostic; no dynamics reads it.

real(kind=wp), public, allocatable :: stress_top(:,:)

Cell-centred magnitude of the top stress (N/m^2), rho_0 * |a_drag| * h_tbl — see the module docstring. Write only here; the KPP/EPBL ustar_shelf consumer is a later PR.

real(kind=wp), public :: tbl_thick_min = 0.0_wp

Minimum effective TBL thickness (m) in the stress / h_tbl denominator (mirror of BBL_THICK_MIN). Zero (default) falls back to h_min.

integer, public :: variant = TDRAG_QUADRATIC

Active drag variant (TDRAG_*).

Type-Bound Procedures

procedure, public, non_overridable :: bytes => ocean_top_drag_bytes
procedure, public, non_overridable :: destroy => ocean_top_drag_destroy
procedure, public, non_overridable :: enter_data => ocean_top_drag_enter_data
procedure, public, non_overridable :: exit_data => ocean_top_drag_exit_data
procedure, public, non_overridable :: init => ocean_top_drag_init

Functions

public pure function parse_tdrag_variant(name) result(code)

Translate a namelist string into a TDRAG_* code. An unrecognised string returns TDRAG_INVALID — a typo must abort rather than silently select one of two laws with different coefficient dimensions. Accepts the same spellings as parse_bdrag_variant, deliberately: the two groups mirror.

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: name

Return Value integer

public pure function tdrag_variant_is_implemented(code) result(ok)

.true. only for a top-drag variant with a real kernel. The single gate validate_config consumes.

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: code

Return Value logical

private pure function ocean_top_drag_bytes(this) result(nbytes)

Counted allocatable footprint of the top-drag slot (0 when unallocated). One arr_bytes term per array — add a term here when a new allocatable joins the type.

Arguments

Type IntentOptional Attributes Name
class(ocean_top_drag_t), intent(in) :: this

Return Value integer(kind=int64)


Subroutines

public subroutine ocean_top_drag_apply_tendencies(this, ms, dt, no_wait)

u += dt*du_drag, v += dt*dv_drag over the whole face array — layers outside the top boundary layer carry an exact zero.

Read more…

Arguments

Type IntentOptional Attributes Name
type(ocean_top_drag_t), intent(in) :: this
type(multilayer_state_t), intent(inout) :: ms
real(kind=wp), intent(in) :: dt
logical, intent(in), optional :: no_wait

public pure subroutine ocean_top_drag_compute_tendencies(this, ms, dt)

Fill du_drag / dv_drag with the top-boundary drag acceleration, stress_top with the cell-centred stress magnitude, and (when implicit_fold) lambda_top_u/v with the k = k_top Rayleigh rate the vdiff diagonal consumes (the rate-capture row and the sink row MUST be the same row).

Read more…

Arguments

Type IntentOptional Attributes Name
type(ocean_top_drag_t), intent(inout) :: this
type(multilayer_state_t), intent(in) :: ms
real(kind=wp), intent(in) :: dt

Outer-step length (s); only read when this%implicit.

public pure subroutine top_drag_fill_face_cover_impl(cover_u, cover_v, cover_frac, nx, ny)

Project the cell-centred cover_frac onto velocity faces with the OR rule (see the module docstring for why OR and not AND at a calving front). Host-side, once, at configure.

Read more…

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(out) :: cover_u(nx+1,ny)
real(kind=wp), intent(out) :: cover_v(nx,ny+1)
real(kind=wp), intent(in) :: cover_frac(nx,ny)
integer, intent(in) :: nx
integer, intent(in) :: ny

public pure subroutine top_drag_stress_mag_impl(stress_top, u_face, v_face, h_layer, wet_mask, cover_frac, k_top, h_vanished, variant, r, c_d, h_floor, htbl, bg_vel, tbl_min, rho0, nx_u, ny_u, nx_v, ny_v, nx, ny, nz)

Cell-centred magnitude of the top stress (N/m^2), for the later ustar_shelf consumer:

Read more…

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(out) :: stress_top(nx,ny)
real(kind=wp), intent(in) :: u_face(nx_u,ny_u,nz)
real(kind=wp), intent(in) :: v_face(nx_v,ny_v,nz)
real(kind=wp), intent(in) :: h_layer(nx,ny,nz)
real(kind=wp), intent(in) :: wet_mask(nx,ny)
real(kind=wp), intent(in) :: cover_frac(nx,ny)
integer, intent(in) :: k_top(nx,ny)

ms%k_top – the first LIVE layer, nz off a rigid top. stress_top is the one number the boundary-layer schemes turn into u_* under the shelf (through ocean_surface_stress_t%stress_shelf), so a band mean built from a filler is a wrong u_* in BOTH KPP and EPBL.

real(kind=wp), intent(in) :: h_vanished

H_VANISHED; see top_drag_tendencies_impl.

integer, intent(in) :: variant
real(kind=wp), intent(in) :: r
real(kind=wp), intent(in) :: c_d
real(kind=wp), intent(in) :: h_floor
real(kind=wp), intent(in) :: htbl
real(kind=wp), intent(in) :: bg_vel
real(kind=wp), intent(in) :: tbl_min
real(kind=wp), intent(in) :: rho0
integer, intent(in) :: nx_u
integer, intent(in) :: ny_u
integer, intent(in) :: nx_v
integer, intent(in) :: ny_v
integer, intent(in) :: nx
integer, intent(in) :: ny
integer, intent(in) :: nz

public pure subroutine top_drag_tendencies_impl(du_drag, dv_drag, lambda_u, lambda_v, u_face, v_face, h_layer, wet_mask, cover_u, cover_v, k_top_u, k_top_v, h_vanished, variant, r, c_d, h_floor, htbl, bg_vel, tbl_min, dt_imp, fold, nx_u, ny_u, nx_v, ny_v, nx, ny, nz)

Flat device kernel: explicit-shape dummies, no derived-type dereference inside the do concurrent.

Read more…

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(out) :: du_drag(nx_u,ny_u,nz)
real(kind=wp), intent(out) :: dv_drag(nx_v,ny_v,nz)
real(kind=wp), intent(out) :: lambda_u(nx+1,ny)
real(kind=wp), intent(out) :: lambda_v(nx,ny+1)
real(kind=wp), intent(in) :: u_face(nx_u,ny_u,nz)
real(kind=wp), intent(in) :: v_face(nx_v,ny_v,nz)
real(kind=wp), intent(in) :: h_layer(nx,ny,nz)
real(kind=wp), intent(in) :: wet_mask(nx,ny)
real(kind=wp), intent(in) :: cover_u(nx+1,ny)
real(kind=wp), intent(in) :: cover_v(nx,ny+1)
integer, intent(in) :: k_top_u(nx+1,ny)

ms%k_top_u / k_top_v – the first layer LIVE on BOTH sides of the face (min of the two columns’ own k_top), nz wherever nothing vanishes against the top, so the walks below start exactly where they do today on every coordinate but z_fixed under a rigid top.

integer, intent(in) :: k_top_v(nx,ny+1)

ms%k_top_u / k_top_v – the first layer LIVE on BOTH sides of the face (min of the two columns’ own k_top), nz wherever nothing vanishes against the top, so the walks below start exactly where they do today on every coordinate but z_fixed under a rigid top.

real(kind=wp), intent(in) :: h_vanished

H_VANISHED. The band walks exit on a face thickness at or below this instead of at or below ZERO: a filler has h = zstar_h_min > 0, so the old <= 0 gate let it into the band with h_in/h_face = 1 – FULL drag rate on a massless layer – while contributing nothing to cumul_h.

integer, intent(in) :: variant
real(kind=wp), intent(in) :: r
real(kind=wp), intent(in) :: c_d
real(kind=wp), intent(in) :: h_floor
real(kind=wp), intent(in) :: htbl
real(kind=wp), intent(in) :: bg_vel
real(kind=wp), intent(in) :: tbl_min
real(kind=wp), intent(in) :: dt_imp
logical, intent(in) :: fold
integer, intent(in) :: nx_u
integer, intent(in) :: ny_u
integer, intent(in) :: nx_v
integer, intent(in) :: ny_v
integer, intent(in) :: nx
integer, intent(in) :: ny
integer, intent(in) :: nz

private subroutine ocean_top_drag_destroy(this)

Release the slot. is_init is cleared FIRST.

Arguments

Type IntentOptional Attributes Name
class(ocean_top_drag_t), intent(inout) :: this

private subroutine ocean_top_drag_enter_data(this)

Type-bound wrapper — delegates to the non-polymorphic impl so the device-attach map base is the heap object, not a polymorphic box.

Arguments

Type IntentOptional Attributes Name
class(ocean_top_drag_t), intent(inout) :: this

private subroutine ocean_top_drag_enter_data_impl(this)

copyin (not create) for the four host-filled 2-D fields — cover_u/cover_v are STATIC configure-time geometry and would otherwise reach the device as allocator leftovers (mem:separate).

Arguments

Type IntentOptional Attributes Name
type(ocean_top_drag_t), intent(inout) :: this

private subroutine ocean_top_drag_exit_data(this)

Arguments

Type IntentOptional Attributes Name
class(ocean_top_drag_t), intent(inout) :: this

private subroutine ocean_top_drag_exit_data_impl(this)

Arguments

Type IntentOptional Attributes Name
type(ocean_top_drag_t), intent(inout) :: this

private subroutine ocean_top_drag_init(this, grid, nz_ml)

Allocate the slot. Gated on enable (latched before this runs), so a run without an ice shelf pays five (1,1) placeholders and two (1,1,1) scratch buffers.

Arguments

Type IntentOptional Attributes Name
class(ocean_top_drag_t), intent(inout) :: this
type(hgrid_t), intent(in) :: grid
integer, intent(in), optional :: nz_ml