Equilibrium (astronomical) body-force tidal forcing state for the
ocean dyn-core (capability C1). Fills a GPU-resident equilibrium
tide elevation eta_eq(x,y) from a small set of harmonic
constituents; the barotropic momentum solve then drives
-g grad(eta - eta_forcing) (pure surface body force), where
eta_forcing = eta_eq + eta_sal folds in the scalar self-attraction
& loading (C2) surface elevation eta_sal = beta_sal*eta (Ray 1998;
Accad & Pekeris 1978). With eta_sal = beta*eta the surface term
becomes the effective-gravity -g(1-beta) grad(eta); beta is lagged
one outer step (uses the stage-start barotropic eta). SAL is
opt-in (use_sal, default off) — off ⇒ eta_forcing == eta_eq,
bit-identical to C1.
MOM6 divergence (intentional): MOM6 scalar SAL scales the whole
(eta - eta_eq) by (1-beta) (its dgeo_de), damping the body tide by
beta too; we apply the Accad-Pekeris load eta_sal = beta*eta to the
ocean surface only (body tide at full strength). Both are valid scalar
approximations; they differ by g*beta*grad(eta_eq) (~9% of the tidal
forcing at beta=0.09). Internal-tide drag (C4) and OBC-tide
reconciliation (C3) remain out of scope; the dead use_itd/
itd_coeff/itd_global_scale scaffolding for C4 was removed (PR-8)
— PR-29 (barotropic linear wave drag) lands its own
lwd_drag_u/v map on a different type instead.
Per-outer-step update decomposes the sum-over-constituents into a
host-side scalar update (amp_cos, amp_sin; nconst cos/sin
calls) times a precomputed device-resident spatial structure
(cos_struct, sin_struct, built once at init from lat/lon), so
the device kernel does NO per-cell trigonometry and NO reduction —
2 mul + 1 add per constituent per cell.
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | public, | parameter | :: | TIDES_NCONST_DEFAULT | = | 8 |
Standard constituents: M2 S2 N2 K2 K1 O1 P1 Q1. |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| real(kind=wp), | public, | allocatable | :: | amp_c(:) |
(nconst) equilibrium amplitudes A (m). |
||
| real(kind=wp), | public, | allocatable | :: | amp_cos(:) |
(nconst) per-step scratch Alovefcos(omeganow+V+u). |
||
| real(kind=wp), | public, | allocatable | :: | amp_sin(:) |
(nconst) per-step scratch Alovef*sin(…). |
||
| real(kind=wp), | public | :: | beta_sal | = | 0.0_wp |
Scalar SAL factor beta (~0.085-0.12; C2). |
|
| real(kind=wp), | public, | allocatable | :: | cos_struct(:,:,:) |
(nx,ny,3) cos-part spatial structure per species slice. |
||
| logical, | public | :: | enable | = | .false. |
Master switch (default off => bit-identical). |
|
| real(kind=wp), | public, | allocatable | :: | eta_eq(:,:) |
(nx,ny) equilibrium tide elevation (m) at cell centres. |
||
| real(kind=wp), | public, | allocatable | :: | eta_forcing(:,:) |
(nx,ny) combined seam field |
||
| real(kind=wp), | public, | allocatable | :: | eta_sal(:,:) |
(nx,ny) scalar-SAL elevation (m); |
||
| real(kind=wp), | public, | allocatable | :: | f_nodal(:) |
(nconst) nodal amplitude factor (fixed at nodal_ref_date). |
||
| logical, | public | :: | is_init | = | .false. |
True between |
|
| real(kind=wp), | public, | allocatable | :: | love_c(:) |
(nconst) Love-number factors. |
||
| integer, | public | :: | nconst | = | 0 |
Number of active harmonic constituents. |
|
| real(kind=wp), | public, | allocatable | :: | omega_c(:) |
(nconst) angular frequencies (rad/s). |
||
| real(kind=wp), | public, | allocatable | :: | phase0(:) |
(nconst) equilibrium argument V_c at ref_date (rad). |
||
| real(kind=wp), | public, | allocatable | :: | sin_struct(:,:,:) |
(nx,ny,3) sin-part spatial structure per species slice. |
||
| integer, | public, | allocatable | :: | species_c(:) |
(nconst) structure-slice index 1/2/3 (diurnal/semidi/long-per). |
||
| real(kind=wp), | public | :: | t_epoch | = | 0.0_wp |
Seconds from ref_date to the model’s t=0 (v1: 0). |
|
| real(kind=wp), | public, | allocatable | :: | u_nodal(:) |
(nconst) nodal phase (rad). |
||
| logical, | public | :: | use_sal | = | .false. |
Apply scalar self-attraction & loading (C2). |
| procedure, public, non_overridable :: bytes => ocean_tides_bytes | |
| procedure, public, non_overridable :: destroy => ocean_tides_destroy | |
| procedure, public, non_overridable :: enter_data => ocean_tides_enter_data | |
| procedure, public, non_overridable :: exit_data => ocean_tides_exit_data | |
| procedure, public, non_overridable :: init => ocean_tides_init |
Counted allocatable footprint of the tides 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_tides_t), | intent(in) | :: | this |
Build the (nx,ny,3) cos/sin spatial-structure arrays from cell- centre latitude/longitude (degrees), via the angle-sum fold cos(theta + nlambda) = cos(theta)cos(nlambda) - sin(theta)sin(n*lambda). Plain host loop over all cells incl. ghosts (before enter_data). slice 1 diurnal (n=1): G1 = sin(2 phi) slice 2 semidiurnal(n=2): G2 = cos^2 phi slice 3 long-period(n=0): G0 = 1/2 - 3/2 sin^2 phi
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_tides_t), | intent(inout) | :: | this | |||
| real(kind=wp), | intent(in) | :: | geolat(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | geolon(nx,ny) | |||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny |
Allocate the active-constituent arrays + 2D fields and fill the
catalog copies + astronomy (phase0, nodal f/u) at the reference
and nodal reference day numbers. Host-side setup (before
enter_data). cat_idx(1:nconst) are catalog indices
(1..TIDES_CATALOG_SIZE).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_tides_t), | intent(inout) | :: | this | |||
| integer, | intent(in) | :: | cat_idx(nconst) | |||
| integer, | intent(in) | :: | nconst | |||
| real(kind=wp), | intent(in) | :: | dref | |||
| real(kind=wp), | intent(in) | :: | dnodal | |||
| logical, | intent(in) | :: | add_nodal | |||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny |
Refresh eta_eq(x,y) for the current outer-step time t (s).
Host recomputes the nconst amplitude scalars, pushes them to
the device, then a do concurrent fills eta_eq with no
per-cell trig and no reduction. Held static across the inner
barotropic substep loop.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_tides_t), | intent(inout) | :: | this | |||
| real(kind=wp), | intent(in) | :: | t |
Refresh the combined seam field eta_forcing for the current
outer step. Scalar self-attraction & loading (C2): when
use_sal, eta_sal = beta_sal*eta_current and
eta_forcing = eta_eq + eta_sal; otherwise eta_forcing = eta_eq
(bit-identical to C1). eta_current is the lagged (stage-start,
previous outer step) barotropic surface elevation. Host does no
work; the fill is a single explicit-shape do concurrent. Must
be called AFTER tides_update_eta_eq (reads the fresh eta_eq).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_tides_t), | intent(inout) | :: | this | |||
| real(kind=wp), | intent(in) | :: | eta_current(:,:) |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_tides_t), | intent(inout) | :: | this |
Attach the device-resident tide arrays. Only when enabled.
select-type -> non-poly _impl (AMD libomptarget class-box rule).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_tides_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_tides_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_tides_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_tides_t), | intent(inout) | :: | this |
Minimal init — the real allocation + astronomy fill happens in
tides_configure_astronomy / tides_build_struct once the
namelist + metrics are available (host, before enter_data).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_tides_t), | intent(inout) | :: | this | |||
| type(hgrid_t), | intent(in) | :: | grid |
Flat-impl device fill (explicit-shape dummies — no descriptor walk). eta_eq(i,j) = sum_c amp_cos(c)cos_struct(i,j,m) + amp_sin(c)sin_struct(i,j,m), m = species_c(c). Contiguous index (i) innermost.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nconst | |||
| integer, | intent(in) | :: | species_c(nconst) | |||
| real(kind=wp), | intent(in) | :: | amp_cos(nconst) | |||
| real(kind=wp), | intent(in) | :: | amp_sin(nconst) | |||
| real(kind=wp), | intent(in) | :: | cos_struct(nx,ny,3) | |||
| real(kind=wp), | intent(in) | :: | sin_struct(nx,ny,3) | |||
| real(kind=wp), | intent(out) | :: | eta_eq(nx,ny) |
Flat-impl device fill (explicit-shape dummies). Loop-invariant
use_sal branch kept INSIDE the single do concurrent (one
launch, uniform branch is ~free). Off ⇒ pure copy of eta_eq
into eta_forcing ⇒ bit-identical. Contiguous index (i) innermost.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| logical, | intent(in) | :: | use_sal | |||
| real(kind=wp), | intent(in) | :: | beta_sal | |||
| real(kind=wp), | intent(in) | :: | eta_current(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | eta_eq(nx,ny) | |||
| real(kind=wp), | intent(inout) | :: | eta_sal(nx,ny) | |||
| real(kind=wp), | intent(out) | :: | eta_forcing(nx,ny) |