coriolis_adv_t Derived Type

type, public :: coriolis_adv_t


Inherits

type~~coriolis_adv_t~~InheritsGraph type~coriolis_adv_t coriolis_adv_t type~scratch_3d_buffer_t scratch_3d_buffer_t type~coriolis_adv_t->type~scratch_3d_buffer_t q_corner, ke_centre, pv_flux_x, pv_flux_y, mass_flux_u, mass_flux_v

Inherited by

type~~coriolis_adv_t~~InheritedByGraph type~coriolis_adv_t coriolis_adv_t type~ocean_state_t ocean_state_t type~ocean_state_t->type~coriolis_adv_t coriolis_adv type~ocean_engine_t ocean_engine_t type~ocean_engine_t->type~ocean_state_t state type~ocean_handle_t ocean_handle_t type~ocean_handle_t->type~ocean_state_t state type~ocean_handle_t->type~ocean_engine_t engine

Components

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

Meridional gradient df/dy (1/(s·m)). Diagnostic / convenience storage — the field-of-record is f_corner.

logical, public :: bound_coriolis = .false.

MOM6 BOUND_CORIOLIS. When .true. (energy scheme only — &ocean_coriolis_nml bound_coriolis, config fail-loud on any other form) the energy-scheme PV flux is clamped into the range of the four neighbouring (f+ζ)·v velocity-form estimates BEFORE the KE-gradient subtraction, capping the thin-layer q·vh blow-up. Read host-side into a local flag in the kernel; default .false. ⇒ untaken branch ⇒ bit-identical.

integer, public :: corner_h_variant = CORNER_H_CELL_MEAN

PV corner-thickness construction (energy scheme). CORNER_H_CELL_MEAN (default, bit-identical) — wet-area 4-cell mean, CORIOLIS_H_MIN_PV-capped. CORNER_H_MOM6_AREA — MOM6’s q = abs_vort·Area_q/(hArea_q + PV_VOL_NEGLECT). The two are algebraically identical above the floor; they differ only in the vanishing-thickness guard. Set from &ocean_coriolis_nml corner_h at setup (config fail-loud on non-energy forms); read host-side into a local flag in the kernel.

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

f-plane baseline. init fills f_corner = f_0; later re-population (set_beta_plane) overrides on a per- corner basis.

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

Coriolis parameter (1/s) at C-grid corners, shape (nx+1, ny+1).

logical, public :: hk_pair_floor = .false.

Run the sadourny_hk PAIR-FLOORED passes (hk_pair_coef) even with &vcoord_nml zfixed_closed_faces off. Latched at setup for the coordinates that lay STATIC bed fillers (z_fixed, zstar, zstar_full): over a stepped bed an OPEN face then pairs a live cell with a zstar_h_min filler, so an HK “cross” pair meets a corner of fillers (h_corner ~ 1e-4 m) against a transport through a live face — the same unbounded h_face/h_corner the floor exists for, four decades larger than on the closed-face partial cells it was written against. The floor is inactive wherever no cell outweighs the other three of its corner, so a flat bed stays bit-identical. Off (default) for every other coordinate ⇒ bit-identical there.

logical, public :: is_init = .false.

True between init and destroy. Prefer this to allocated(...) — tracks GPU device attachment too.

type(scratch_3d_buffer_t), public :: ke_centre

Kinetic energy at cell centres for the gradient(KE) form.

type(scratch_3d_buffer_t), public :: mass_flux_u

HK path: u_face_x * h_at_u_face (mass flux per face) at east faces. Same shape as pv_flux_x — (nx+1, ny, nz). Unused by the Sadourny path; allocated regardless so the lifecycle is uniform.

type(scratch_3d_buffer_t), public :: mass_flux_v

HK path: v_face_y * h_at_v_face at north faces. Shape (nx, ny+1, nz). Same usage caveat as mass_flux_u.

logical, public :: no_slip = .false.

Lateral boundary condition at coasts (spec §14 C1). .false. (default) = FREE-SLIP: the corner relative vorticity is multiplied by wet_q so a land corner contributes zero rel-vort (tangential velocity free at the wall, MOM6’s free-slip closure). .true. = NO-SLIP: the factor becomes 2 - wet_q (image vorticity, MOM6’s no-slip). Set from &ocean_hvisc_nml no_slip (shared with the lateral strain). All-wet ⇒ wet_q≡1 ⇒ factor ≡1 ⇒ bit-identical.

integer, public :: pv_adv_scheme = PV_ADV_CENTERED

PV face-interpolation scheme (orthogonal to pv_variant): PV_ADV_CENTERED (default, 2-pt corner average -> bit-identical) or PV_ADV_WENO{3,5,7} (upwind-biased WENO-Z reconstruction of the corner absolute vorticity onto the faces in the Sadourny path). Driven from &ocean_coriolis_nml pv_adv_scheme via parse_pv_adv_scheme; weno5/weno7 require nghost>=4/5 (pv_adv_required_nghost).

type(scratch_3d_buffer_t), public :: pv_flux_x

du/dt at east faces.

type(scratch_3d_buffer_t), public :: pv_flux_y

dv/dt at north faces.

integer, public :: pv_variant = PV_VARIANT_SADOURNY

Active PV/Coriolis scheme variant. Defaults to Sadourny; set to PV_VARIANT_SADOURNY_HK to engage the Arakawa-Hsu correction. Driven from &ocean_setup_nml ocean_coriolis_form via parse_pv_variant.

type(scratch_3d_buffer_t), public :: q_corner

Sadourny path: relative vorticity ζ at corners. HK path: per-mass PV q = (f + ζ) / h_at_corner at corners. Both kernels write-then-read this in a single call so the repurposing is safe — they never coexist within one stage.

logical, public :: state_fluxes = .false.

&ocean_coriolis_nml use_state_fluxes — mass-consistent CorAdCalc. Config guarantees form="sadourny_energy" + split_scheme="pred_corr"; the dyn driver forwards it to coriolis_adv_compute_tendencies(use_state_fluxes=) in the CORRECTOR stage only (the predictor keeps the recompute — its continuity has not run yet this step).

logical, public :: use_hk_correction = .false.

Convenience flag mirroring pv_variant == SADOURNY_HK. Diagnostic only — the dispatch in ocean_dyn reads pv_variant directly.

logical, public :: weno_velocity_smooth = .false.

&ocean_coriolis_nml weno_velocity_smooth (MOM6 WENO_VELOCITY_SMOOTH, default off): when on, the WENO smoothness indicators are computed from the tangential velocity rather than the vorticity. Off = vorticity-based (MOM6 default).


Type-Bound Procedures

procedure, public, non_overridable :: bytes => coriolis_adv_bytes

  • private pure function coriolis_adv_bytes(this) result(nbytes)

    Counted allocatable footprint of the Coriolis-advection 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(coriolis_adv_t), intent(in) :: this

    Return Value integer(kind=int64)

procedure, public, non_overridable :: destroy => coriolis_adv_destroy

procedure, public, non_overridable :: enter_data => coriolis_adv_enter_data

procedure, public, non_overridable :: exit_data => coriolis_adv_exit_data

procedure, public, non_overridable :: init => coriolis_adv_init

  • private subroutine coriolis_adv_init(this, grid, nz_ml)

    Allocate the 4 scratch buffers sized at (nx_face / ny_face / corner, nz). Default nz=1 covers the barotropic kernel; passing nz_ml sizes them for the multilayer kernel. Same backward-compatible pattern as continuity_init.

    Arguments

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

procedure, public, non_overridable :: set_beta_plane => coriolis_adv_set_beta_plane

  • private subroutine coriolis_adv_set_beta_plane(this, grid, f_0, beta, y_ref)

    Populate f_corner with a beta-plane profile f(y) = f_0 + beta * (y - y_ref)

    Read more…

    Arguments

    Type IntentOptional Attributes Name
    class(coriolis_adv_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

Source Code

   type :: coriolis_adv_t
      logical :: is_init = .false.
         !! True between `init` and `destroy`.  Prefer this to
         !! `allocated(...)` — tracks GPU device attachment too.
      integer :: pv_variant = PV_VARIANT_SADOURNY
         !! Active PV/Coriolis scheme variant.  Defaults to Sadourny;
         !! set to `PV_VARIANT_SADOURNY_HK` to engage the Arakawa-Hsu
         !! correction.  Driven from `&ocean_setup_nml
         !! ocean_coriolis_form` via `parse_pv_variant`.
      logical :: use_hk_correction = .false.
         !! Convenience flag mirroring `pv_variant == SADOURNY_HK`.
         !! Diagnostic only — the dispatch in `ocean_dyn` reads
         !! `pv_variant` directly.
      integer :: pv_adv_scheme = PV_ADV_CENTERED
         !! PV face-interpolation scheme (orthogonal to `pv_variant`):
         !! `PV_ADV_CENTERED` (default, 2-pt corner average -> bit-identical)
         !! or `PV_ADV_WENO{3,5,7}` (upwind-biased WENO-Z reconstruction of the
         !! corner absolute vorticity onto the faces in the Sadourny path).
         !! Driven from `&ocean_coriolis_nml pv_adv_scheme` via
         !! `parse_pv_adv_scheme`; weno5/weno7 require nghost>=4/5
         !! (`pv_adv_required_nghost`).
      logical :: weno_velocity_smooth = .false.
         !! `&ocean_coriolis_nml weno_velocity_smooth` (MOM6
         !! `WENO_VELOCITY_SMOOTH`, default off): when on, the WENO
         !! smoothness indicators are computed from the tangential velocity
         !! rather than the vorticity.  Off = vorticity-based (MOM6 default).
      logical :: state_fluxes = .false.
         !! `&ocean_coriolis_nml use_state_fluxes` — mass-consistent
         !! CorAdCalc.  Config guarantees `form="sadourny_energy"` +
         !! `split_scheme="pred_corr"`; the dyn driver forwards it to
         !! `coriolis_adv_compute_tendencies(use_state_fluxes=)` in the
         !! CORRECTOR stage only (the predictor keeps the recompute —
         !! its continuity has not run yet this step).
      logical :: no_slip = .false.
         !! Lateral boundary condition at coasts (spec §14 C1).
         !! `.false.` (default) = FREE-SLIP: the corner relative
         !! vorticity is multiplied by `wet_q` so a land corner
         !! contributes zero rel-vort (tangential velocity free at the
         !! wall, MOM6's free-slip closure).  `.true.` = NO-SLIP:
         !! the factor becomes `2 - wet_q` (image vorticity, MOM6's no-slip).
         !! Set from `&ocean_hvisc_nml no_slip` (shared with the lateral
         !! strain).  All-wet ⇒ `wet_q≡1` ⇒ factor `≡1` ⇒ bit-identical.
      logical :: hk_pair_floor = .false.
         !! Run the `sadourny_hk` PAIR-FLOORED passes (`hk_pair_coef`) even
         !! with `&vcoord_nml zfixed_closed_faces` off.  Latched at setup
         !! for the coordinates that lay STATIC bed fillers (`z_fixed`,
         !! `zstar`, `zstar_full`): over a stepped bed an OPEN face then
         !! pairs a live cell with a `zstar_h_min` filler, so an HK "cross"
         !! pair meets a corner of fillers (`h_corner ~ 1e-4 m`) against a
         !! transport through a live face — the same unbounded
         !! `h_face/h_corner` the floor exists for, four decades larger than
         !! on the closed-face partial cells it was written against.  The
         !! floor is inactive wherever no cell outweighs the other three of
         !! its corner, so a flat bed stays bit-identical.  Off (default)
         !! for every other coordinate ⇒ bit-identical there.
      integer :: corner_h_variant = CORNER_H_CELL_MEAN
         !! PV corner-thickness construction (energy scheme).
         !! `CORNER_H_CELL_MEAN` (default, bit-identical) — wet-area 4-cell
         !! mean, `CORIOLIS_H_MIN_PV`-capped.  `CORNER_H_MOM6_AREA` — MOM6's
         !! `q = abs_vort·Area_q/(hArea_q + PV_VOL_NEGLECT)`.  The two are
         !! algebraically identical above the floor; they differ only in the
         !! vanishing-thickness guard.  Set from `&ocean_coriolis_nml corner_h`
         !! at setup (config fail-loud on non-energy forms); read host-side
         !! into a local flag in the kernel.
      logical :: bound_coriolis = .false.
         !! MOM6 `BOUND_CORIOLIS`.  When
         !! `.true.` (energy scheme only — `&ocean_coriolis_nml bound_coriolis`,
         !! config fail-loud on any other form) the energy-scheme PV flux is
         !! clamped into the range of the four neighbouring `(f+ζ)·v`
         !! velocity-form estimates BEFORE the KE-gradient subtraction, capping
         !! the thin-layer `q·vh` blow-up.  Read host-side into a local flag in
         !! the kernel; default `.false.` ⇒ untaken branch ⇒ bit-identical.

      ! ---- Coriolis parameter field ----
      ! `f_corner` holds f at C-grid corners (SW corner of cell
      ! (i, j) sits at position (i-1/2, j-1/2)).  Both kernels read
      ! it here and average to the relevant face.  Shape (nx+1, ny+1).
      !
      ! Initialised to `f_0` everywhere by `init`; switch to a
      ! `f = f_0 + beta * (y - y_ref)` profile via
      ! `coriolis_adv_set_beta_plane`.  For an f-plane just leave
      ! `f_0` at the desired value and skip the beta call.
      real(wp), allocatable :: f_corner(:, :)
         !! Coriolis parameter (1/s) at C-grid corners, shape
         !! (nx+1, ny+1).
      real(wp) :: f_0 = 0.0_wp
         !! f-plane baseline.  `init` fills `f_corner = f_0`; later
         !! re-population (`set_beta_plane`) overrides on a per-
         !! corner basis.
      real(wp) :: beta = 0.0_wp
         !! Meridional gradient `df/dy` (1/(s·m)).  Diagnostic /
         !! convenience storage — the field-of-record is `f_corner`.

      ! ---- Per-step scratch ----
      type(scratch_3d_buffer_t) :: q_corner
         !! Sadourny path: relative vorticity ζ at corners.
         !! HK path: per-mass PV q = (f + ζ) / h_at_corner at corners.
         !! Both kernels write-then-read this in a single call so the
         !! repurposing is safe — they never coexist within one stage.
      type(scratch_3d_buffer_t) :: ke_centre
         !! Kinetic energy at cell centres for the gradient(KE) form.
      type(scratch_3d_buffer_t) :: pv_flux_x
         !! du/dt at east faces.
      type(scratch_3d_buffer_t) :: pv_flux_y
         !! dv/dt at north faces.
      type(scratch_3d_buffer_t) :: mass_flux_u
         !! HK path: u_face_x * h_at_u_face (mass flux per face) at
         !! east faces.  Same shape as `pv_flux_x` — (nx+1, ny, nz).
         !! Unused by the Sadourny path; allocated regardless so the
         !! lifecycle is uniform.
      type(scratch_3d_buffer_t) :: mass_flux_v
         !! HK path: v_face_y * h_at_v_face at north faces.  Shape
         !! (nx, ny+1, nz).  Same usage caveat as `mass_flux_u`.
   contains
      procedure, non_overridable :: init => coriolis_adv_init
      procedure, non_overridable :: destroy => coriolis_adv_destroy
      procedure, non_overridable :: enter_data => coriolis_adv_enter_data
      procedure, non_overridable :: exit_data => coriolis_adv_exit_data
      procedure, non_overridable :: set_beta_plane => coriolis_adv_set_beta_plane
      procedure, non_overridable :: bytes => coriolis_adv_bytes
   end type coriolis_adv_t