| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| logical, | public | :: | direct_stress | = | .false. |
MOM6 DIRECT_STRESS analogue. When |
|
| type(scratch_3d_buffer_t), | public | :: | du_stress |
Surface stress tendency at east faces, shape (nx+1, ny, nz). Only k=nz carries a non-zero value; k |
|||
| type(scratch_3d_buffer_t), | public | :: | dv_stress |
Surface stress tendency at north faces, shape (nx, ny+1, nz). |
|||
| real(kind=wp), | public | :: | h_min | = | 1.0e-3_wp |
Floor on the surface-layer thickness in the |
|
| logical, | public | :: | has_stress_mag | = | .false. |
True once |
|
| real(kind=wp), | public | :: | hmix_stress | = | 0.0_wp |
Thickness (m) of the surface slab over which the stress
is spread when |
|
| logical, | public | :: | is_init | = | .false. |
True between |
|
| real(kind=wp), | public | :: | rho0 | = | 1035.0_wp |
Boussinesq reference density (kg/m^3) used in the
|
|
| real(kind=wp), | public, | allocatable | :: | stress_mag(:,:) |
Cell-centred wind-stress magnitude |
||
| real(kind=wp), | public, | allocatable | :: | stress_shelf(:,:) |
Cell-centred magnitude of the stress an ICE-SHELF BASE
exerts on the ocean (N/m^2, |
||
| real(kind=wp), | public, | allocatable | :: | tau_x(:,:) |
Zonal wind stress (N/m^2) on east faces, shape |
||
| real(kind=wp), | public, | allocatable | :: | tau_y(:,:) |
Meridional wind stress (N/m^2) on north faces, shape
|
| procedure, public, non_overridable :: bytes => ocean_surface_stress_bytes | |
| procedure, public, non_overridable :: destroy => ocean_surfstress_destroy | |
| procedure, public, non_overridable :: enter_data => ocean_surfstress_enter_data | |
| procedure, public, non_overridable :: exit_data => ocean_surfstress_exit_data | |
| procedure, public, non_overridable :: init => ocean_surfstress_init | |
| procedure, public, non_overridable :: set_wind_stress_2gyre => ocean_surfstress_set_2gyre | |
| procedure, public, non_overridable :: set_wind_stress_const => ocean_surfstress_set_const | |
| procedure, public, non_overridable :: set_wind_stress_neverworld2 => ocean_surfstress_set_neverworld2 |
Counted allocatable footprint of the surface stress 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_surface_stress_t), | intent(in) | :: | this |
Zero the wind-stress pair on every C-grid face that touches an
ice-covered cell, then refresh stress_mag from the masked
pair. The two halves are ONE call on purpose: a masked tau
with a stale stress_mag would leave KPP/EPBL mixing on a wind
that no longer reaches the water.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_surface_stress_t), | intent(inout) | :: | ss | |||
| real(kind=wp), | intent(in) | :: | cover_frac(:,:) |
Ice-cover fraction at cell centres ( |
Outer-shim — flattens the derived-type derefs before the
do concurrent body sees them. Explicit-shape dimensions
derived from ms and passed to the impl as scalar args.
no_wait (optional, default .false.): forwarded to the impl —
when .true. the apply DC loops run on OpenACC queue 1 without a
trailing sync, so the batched velocity-apply chain in
run_stage_split !$acc wait(1)s ONCE. Default ⇒ blocking.
Not pure because of the async/wait directives.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_surface_stress_t), | intent(in) | :: | this | |||
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| logical, | intent(in), | optional | :: | no_wait |
Fill du_stress / dv_stress with the surface stress
acceleration tau / (rho_0 * h_top) at k = nz. Outer-shim:
hoist the derived-type derefs (this%tau_x, this%du_stress%data,
ms%h_layer, ms%wet_mask) to the host, dispatch to flat-impl.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_surface_stress_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(in) | :: | ms |
Recompute stress_mag from the CURRENT tau_x/tau_y, shape
taken from the already-allocated arrays (no grid needed — this
is the grid-free twin of ocean_surface_stress_set_derived, for
callers that hold the slot but not the grid).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_surface_stress_t), | intent(inout) | :: | ss |
Fill stress_mag from the current tau_x/tau_y — the MOM6
set_derived_forcing_fields analogue (PR-12), and the public
entry point configure_ocean_forcing calls after the
wind_config dispatch. Host-side (the wind field is
configure-static in v1, so one fill at configure suffices — a
future time-varying wind reader re-calls this after each read).
Not pure: writes into ss. Call BEFORE enter_data, or
follow with !$acc update device(ss%stress_mag) if already
mapped. In practice this is a defensive re-fill only: every
set_wind_stress_* setter already refreshes stress_mag in
step (ocean_surfstress_refresh_stress_mag) so stress_mag is
never stale relative to tau_x/tau_y regardless of call site
(production driver OR a unit test that never reaches
configure_ocean_forcing).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid |
Kept in the public signature (PR-12 plan §5.2) though shape
is now taken from |
||
| type(ocean_surface_stress_t), | intent(inout) | :: | ss | |||
| real(kind=wp), | intent(in), | optional | :: | cover_frac(:,:) |
Ice-shelf cover fraction at cell centres
( |
Publish the ice-base stress from a FRICTION VELOCITY:
stress_shelf = rho_0 * u_*^2.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | stress_shelf(nx,ny) |
|
||
| real(kind=wp), | intent(in) | :: | ustar(nx,ny) |
|
||
| real(kind=wp), | intent(in) | :: | rho0 |
Reference density (kg/m^3) – the single rho0 of record, by
value from |
||
| integer, | intent(in) | :: | nx |
Extents of BOTH arrays. The caller gates on the melt slot’s
|
||
| integer, | intent(in) | :: | ny |
Extents of BOTH arrays. The caller gates on the melt slot’s
|
Flat do concurrent kernel behind ocean_surface_stress_apply_cover
— explicit-shape dummies, integer dims first (decl-order, ifx
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | tau_x(nx+1,ny) | |||
| real(kind=wp), | intent(inout) | :: | tau_y(nx,ny+1) | |||
| real(kind=wp), | intent(in) | :: | cover_frac(nx,ny) | |||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny |
stress_mag(i,j) = |tau| at cell centres — literal copy of the
three lines this dedups from rdb_ocean_vmix.F90 (KPP,
:575-577/:641-643, pre-PR-12) and rdb_ocean_epbl.F90
(:974-976, pre-PR-12): SAME face-average op order, so the
substitution at each call site is bit-identical (PR-12 §7.5).
Explicit-shape dummies, integer dims first (decl-order).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | tau_x(nx+1,ny) | |||
| real(kind=wp), | intent(in) | :: | tau_y(nx,ny+1) | |||
| real(kind=wp), | intent(inout) | :: | stress_mag(nx,ny) | |||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_surface_stress_t), | intent(inout) | :: | this |
Type-bound wrapper — delegates to the non-polymorphic impl so the device-attach map base is the heap object, not a polymorphic stack box (AMD libomptarget cross-slot-overlap fix). Slot-header presence comes from the orchestrator’s root copyin(state); only the leaf arrays + scratch are attached here.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_surface_stress_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_surface_stress_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_surface_stress_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_surface_stress_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_surface_stress_t), | intent(inout) | :: | this | |||
| type(hgrid_t), | intent(in) | :: | grid | |||
| integer, | intent(in), | optional | :: | nz_ml |
Type-bound-facing shim behind every set_wind_stress_* setter:
strips the polymorphic box (same reason as enter_data) and
delegates to ocean_surface_stress_refresh_mag. Keeping this
call inside each setter — rather than requiring a separate
explicit call — is what keeps stress_mag correct for every
existing caller, including unit tests that build
ocean_surface_stress_t directly and never reach
configure_ocean_forcing.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_surface_stress_t), | intent(inout) | :: | this |
Fill tau_x with the MOM6 2gyre profile,
tau_x(i,j) = taux_mag · (1 − cos(2π · (y − y_south) / y_len)),
and zero tau_y. In Cartesian terms (y − y_south) / y_len
is the normalised position from the south wall of the physical
domain (0 at south, 1 at north), so the formula reduces to
taux_mag · (1 − cos(2π · ((j_phys − 0.5) / ny_phys))) with
j_phys = j − nghost. Physical-interior rows only; ghost rows
stay at zero so wall faces see no spurious stress. Host only —
call enter_data afterwards (or !$acc update device if
already mapped).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_surface_stress_t), | intent(inout) | :: | this | |||
| type(hgrid_t), | intent(in) | :: | grid | |||
| real(kind=wp), | intent(in) | :: | taux_mag | |||
| integer, | intent(in), | optional | :: | j_offset | ||
| integer, | intent(in), | optional | :: | ny_global |
Fill tau_x / tau_y uniformly with the given scalar
values. Convenience helper for the spatially-constant
wind case (the Tier-1 default and most unit tests). Host
only — call enter_data afterwards (or !$acc update
device if already mapped) to sync to GPU. Refreshes
stress_mag in step (PR-12) so every existing caller —
production and unit test alike — gets a consistent
stress_mag with no separate call required.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_surface_stress_t), | intent(inout) | :: | this | |||
| real(kind=wp), | intent(in) | :: | tau_x_val | |||
| real(kind=wp), | intent(in) | :: | tau_y_val |
Fill tau_x with the Neverworld2 zonal wind-stress profile
(Marques et al. 2022, GMD; MOM6-inspired) and zero tau_y. τ_x is a
3-band piecewise function of the normalized meridional position
y = (j_phys − 0.5)/ny_phys ∈ [0,1] (which equals MOM6’s
(lat − south)/len_lat on a uniform grid), scaled by the peak stress
taux_mag (Pa), with off = 0.02:
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_surface_stress_t), | intent(inout) | :: | this | |||
| type(hgrid_t), | intent(in) | :: | grid | |||
| real(kind=wp), | intent(in) | :: | taux_mag | |||
| integer, | intent(in), | optional | :: | j_offset | ||
| integer, | intent(in), | optional | :: | ny_global |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | u_face(nx+1,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | v_face(nx,ny+1,nz) | |||
| real(kind=wp), | intent(in) | :: | du_stress(nx+1,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | dv_stress(nx,ny+1,nz) | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| logical, | intent(in) | :: | lwait |
.false. ⇒ leave the apply on queue 1 without syncing (batched). |
Flat-array surface-stress kernel. Explicit-shape dummies so NVHPC stdpar can compile the device kernel against static bounds.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | h_layer(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | wet_mask(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | tau_x(nx+1,ny) | |||
| real(kind=wp), | intent(in) | :: | tau_y(nx,ny+1) | |||
| real(kind=wp), | intent(inout) | :: | du_stress(nx+1,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | dv_stress(nx,ny+1,nz) | |||
| real(kind=wp), | intent(in) | :: | rho0 | |||
| real(kind=wp), | intent(in) | :: | h_min | |||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz |
DIRECT_STRESS branch — distribute the wind stress across
the top hmix_stress metres of the column. For each face,
walk layers from k = nz (surface) down to k = 1, accumulating
thickness; the surface boundary layer (SBL) is the set of
layers whose top sits within hmix_stress of the free
surface. The acceleration per layer is:
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | h_layer(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | wet_mask(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | tau_x(nx+1,ny) | |||
| real(kind=wp), | intent(in) | :: | tau_y(nx,ny+1) | |||
| real(kind=wp), | intent(inout) | :: | du_stress(nx+1,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | dv_stress(nx,ny+1,nz) | |||
| real(kind=wp), | intent(in) | :: | rho0 | |||
| real(kind=wp), | intent(in) | :: | h_min | |||
| real(kind=wp), | intent(in) | :: | hmix_stress | |||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz |