ocean_cavity_flux_t Derived Type

type, public :: ocean_cavity_flux_t

Ice-shelf basal-melt slot: the 2-D interface state plus the parameter bundles the kernel is called with.

Every array is (nx_total, ny_total) when enable, (1,1) otherwise — the z_draft gating convention, latched in ocean_state_init_from_config BEFORE init so the allocation gate can read it.


Inherits

type~~ocean_cavity_flux_t~~InheritsGraph type~ocean_cavity_flux_t ocean_cavity_flux_t type~ocean_cavity_const_t ocean_cavity_const_t type~ocean_cavity_flux_t->type~ocean_cavity_const_t const type~ocean_cavity_exchange_t ocean_cavity_exchange_t type~ocean_cavity_flux_t->type~ocean_cavity_exchange_t par type~ocean_cavity_ice_t ocean_cavity_ice_t type~ocean_cavity_flux_t->type~ocean_cavity_ice_t ice

Inherited by

type~~ocean_cavity_flux_t~~InheritedByGraph type~ocean_cavity_flux_t ocean_cavity_flux_t type~ocean_state_t ocean_state_t type~ocean_state_t->type~ocean_cavity_flux_t cavity_flux 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, allocatable :: active(:,:)

Composed solve mask (0/1): cover_frac AND wet AND “the far-field sample found mass”. This is what the kernel’s cover argument is given.

real(kind=wp), public :: cdrag_top = 2.5e-3_wp

Top drag coefficient for the MELT friction velocity only.

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

Per-cell top-layer thickness RATIO h_new/h_old left behind by the volume_compensation sink, exactly 1 everywhere the sink did not act. Every PASSIVE tracer’s top-layer load is multiplied by it (cavity_comp_scale_tracer_impl) so the removed parcel carries that cell’s own concentration and changes none of them. Allocated with the rest of the slot (full size iff enable); left at 1 when volume_comp = CAVITY_VC_NONE.

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

Thickness (m) the compensation sink removed from each open -ocean column this thermo step; zero when compensation is off.

type(ocean_cavity_const_t), public :: const

Thermodynamic + turbulence constants. Flat POD, left at the ISOMIP+ protocol values (Asay-Davis et al. (2016) Table 4): rho_w, c_w, alpha_T, beta_S here are the MELT LAW’s own calibrated constants, NOT copies of the model’s Boussinesq rho_0 — the same “out of scope on purpose” category as RHO_WATER and &ocean_ice_nml rho_ocean in src/core/ocean/README.md’s reference-density table. Overriding them would break ISOMIP+ comparability, which is the reason this path exists.

logical, public :: enable = .false.

&ocean_cavity_melt_nml enable, latched before init.

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

Cell-centred Coriolis parameter (1/s), from the same fill_coriolis_centre every other slot uses. Read by hj99 only, as |f|; the law does not exist at f = 0.

real(kind=wp), public :: far_field_depth = 10.0_wp

Thickness (m) below the ice base the far field is averaged over. See the module docstring: metres, not layers.

integer, public :: freshwater = CAVITY_FW_VIRTUAL

&ocean_cavity_melt_nml freshwater, parsed. CAVITY_FW_VIRTUAL (default) ⇒ ocean_cavity_mass_step is an immediate return and the path is byte-identical.

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

Haline exchange velocity (m/s), same convention.

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

Thermal exchange velocity (m/s) the column’s solve converged on — NOT par%gamma_t_coeff, which is the dimensionless coefficient. Under hj99 / yung25 it is an implicit function of the converged interface state, so it is stored rather than re-derived: a diagnostic that rebuilt it from u* alone would report the NEUTRAL value instead of the stratification-suppressed one. Zero where inactive.

type(ocean_cavity_ice_t), public :: ice

Ice-conduction selector + T_ice. Flat POD.

logical, public :: is_init = .false.

Set by init after every allocation succeeds; cleared by destroy first. Always test this, never allocated(...).

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

Canonical melt mass flux (kg/m^2/s), > 0 melting.

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

Domain-integrated meltwater VOLUME (m^3) added this thermo step over the INTERIOR (ghosts excluded, globally combined). Diagnostic + the input the compensation sink spends.

integer, public :: n_no_root_step = 0

Active columns returning NO_PHYSICAL_ROOT this step.

integer(kind=int64), public :: n_no_root_total = 0_int64

Running total of NO_PHYSICAL_ROOT.

integer, public :: n_nonfinite_step = 0

Active columns returning NONFINITE_INPUT/NONFINITE_STATE this step. FATAL — the driver fails loud.

integer, public :: n_not_converged_step = 0

Active columns returning NOT_CONVERGED this step (zero melt applied there — the kernel’s documented safe state).

integer(kind=int64), public :: n_not_converged_total = 0_int64

Running total, drained to the console like continuity_t%n_limited_total. int64 because a long run with one stubborn column can exceed 2e9.

integer, public :: n_other_step = 0

Active columns returning any other non-OK status (BAD_INPUT, NO_CORIOLIS, LAW_DOMAIN, …).

integer(kind=int64), public :: n_other_total = 0_int64

Running total of every other non-OK, non-fatal status.

integer, public :: n_thin_step = 0

Columns this thermo step whose top layer could NOT give up the thickness the real-mass path asked of it without falling through H_CAVITY_FLOOR — a FREEZING column (m < 0) whose top layer is thinner than |m|*dt/rho_0, or a compensation sink deeper than the open-ocean top layer. The withdrawal is CLAMPED to what is there ABOVE the floor (so h stays strictly above the vanish marker, never on or below it) and the count is FATAL: a clamped withdrawal is a withdrawal the tracked mass source no longer matches, so continuing would print a budget that silently stopped closing. Same stance as the non-finite melt column.

integer(kind=int64), public :: n_thin_total = 0_int64

Running total of n_thin_step, for the record.

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

Interior wet area (m^2) the ice does NOT cover, globally combined — the denominator of the uniform sink.

type(ocean_cavity_exchange_t), public :: par

Exchange-law selector + coefficients. Flat POD; its f_cor member is unused here (the driver substitutes the per-column f_cor array).

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

Turbulent heat flux ocean → interface (W/m^2), > 0 cools the ocean.

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

Boussinesq reference density (kg/m^3) — THE density that converts the melt MASS flux into a thickness tendency, and the same one ocean_surface_flux_t%rho0 divides the surface tracer sources by. Assigned at configure from the single rho_0 of record; the literal is only the pre-configure type default. The two MUST agree or the salt undo is not the exact negation of what the apply kernel stamped, which is asserted at configure.

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

Interface salinity (g/kg).

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

Far-field salinity (g/kg), same average.

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

Ice salinity (g/kg).

integer, public, allocatable :: status(:,:)

CAVITY_MELT_* per column; CAVITY_MELT_OK where inactive.

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

Interface temperature (degC), on the liquidus.

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

Far-field temperature (degC), thickness-weighted over far_field_depth.

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

Far-field x velocity at the cell CENTRE (m/s), same average.

real(kind=wp), public :: u_tide = 1.0e-2_wp

RMS tidal velocity (m/s) in the melt u*.

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

Melt friction velocity (m/s).

real(kind=wp), public :: ustar_min = 1.0e-4_wp

Friction-velocity floor (m/s).

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

Far-field y velocity at the cell CENTRE (m/s), same average.

integer, public :: volume_comp = CAVITY_VC_NONE

&ocean_cavity_melt_nml volume_compensation, parsed. Requires freshwater = CAVITY_FW_MASS (validate_config).


Type-Bound Procedures

procedure, public, non_overridable :: bytes => ocean_cavity_flux_bytes

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

    Counted allocatable footprint (0 when unallocated). One arr_bytes term per array — add one here when an array joins the type.

    Arguments

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

    Return Value integer(kind=int64)

procedure, public, non_overridable :: destroy => ocean_cavity_flux_destroy

procedure, public, non_overridable :: enter_data => ocean_cavity_flux_enter_data

  • private subroutine ocean_cavity_flux_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 stack box.

    Arguments

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

procedure, public, non_overridable :: exit_data => ocean_cavity_flux_exit_data

procedure, public, non_overridable :: init => ocean_cavity_flux_init

  • private subroutine ocean_cavity_flux_init(this, grid)

    Allocate the slot. Gated on enable (latched by ocean_state_init_from_config before this runs), so a run without a cavity pays fourteen (1,1) placeholders.

    Arguments

    Type IntentOptional Attributes Name
    class(ocean_cavity_flux_t), intent(inout) :: this
    type(hgrid_t), intent(in) :: grid

Source Code

   type :: ocean_cavity_flux_t
      !! Ice-shelf basal-melt slot: the 2-D interface state plus the
      !! parameter bundles the kernel is called with.
      !!
      !! Every array is `(nx_total, ny_total)` when `enable`, `(1,1)`
      !! otherwise — the `z_draft` gating convention, latched in
      !! `ocean_state_init_from_config` BEFORE `init` so the allocation
      !! gate can read it.
      logical :: is_init = .false.
         !! Set by `init` after every allocation succeeds; cleared by
         !! `destroy` first.  Always test this, never `allocated(...)`.
      logical :: enable = .false.
         !! `&ocean_cavity_melt_nml enable`, latched before `init`.

      ! ---- Knobs the kernel is called with (host scalars) ----
      real(wp) :: far_field_depth = 10.0_wp
         !! Thickness (m) below the ice base the far field is averaged
         !! over.  See the module docstring: metres, not layers.
      real(wp) :: cdrag_top = 2.5e-3_wp
         !! Top drag coefficient for the MELT friction velocity only.
      real(wp) :: u_tide = 1.0e-2_wp
         !! RMS tidal velocity (m/s) in the melt `u*`.
      real(wp) :: ustar_min = 1.0e-4_wp
         !! Friction-velocity floor (m/s).
      real(wp) :: s_ice = 0.0_wp
         !! Ice salinity (g/kg).
      integer :: freshwater = CAVITY_FW_VIRTUAL
         !! `&ocean_cavity_melt_nml freshwater`, parsed.
         !! `CAVITY_FW_VIRTUAL` (default) ⇒ `ocean_cavity_mass_step` is
         !! an immediate return and the path is byte-identical.
      integer :: volume_comp = CAVITY_VC_NONE
         !! `&ocean_cavity_melt_nml volume_compensation`, parsed.
         !! Requires `freshwater = CAVITY_FW_MASS` (validate_config).
      real(wp) :: rho0 = 1035.0_wp
         !! Boussinesq reference density (kg/m^3) — THE density that
         !! converts the melt MASS flux into a thickness tendency, and
         !! the same one `ocean_surface_flux_t%rho0` divides the surface
         !! tracer sources by.  Assigned at configure from the single
         !! `rho_0` of record; the literal is only the pre-configure type
         !! default.  The two MUST agree or the salt undo is not the
         !! exact negation of what the apply kernel stamped, which is
         !! asserted at configure.
      type(ocean_cavity_exchange_t) :: par
         !! Exchange-law selector + coefficients.  Flat POD; its
         !! `f_cor` member is unused here (the driver substitutes the
         !! per-column `f_cor` array).
      type(ocean_cavity_ice_t) :: ice
         !! Ice-conduction selector + `T_ice`.  Flat POD.
      type(ocean_cavity_const_t) :: const
         !! Thermodynamic + turbulence constants.  Flat POD, left at the
         !! ISOMIP+ protocol values (Asay-Davis et al. (2016) Table 4):
         !! `rho_w`, `c_w`, `alpha_T`, `beta_S` here are the MELT LAW's
         !! own calibrated constants, NOT copies of the model's
         !! Boussinesq `rho_0` — the same "out of scope on purpose"
         !! category as `RHO_WATER` and `&ocean_ice_nml rho_ocean` in
         !! `src/core/ocean/README.md`'s reference-density table.
         !! Overriding them would break ISOMIP+ comparability, which is
         !! the reason this path exists.

      ! ---- Static, filled once at configure ----
      real(wp), allocatable :: f_cor(:, :)
         !! Cell-centred Coriolis parameter (1/s), from the same
         !! `fill_coriolis_centre` every other slot uses.  Read by
         !! `hj99` only, as `|f|`; the law does not exist at `f = 0`.

      ! ---- Per-step interface state (all device-resident) ----
      real(wp), allocatable :: active(:, :)
         !! Composed solve mask (0/1): `cover_frac` AND wet AND "the
         !! far-field sample found mass".  This is what the kernel's
         !! `cover` argument is given.
      real(wp), allocatable :: t_far(:, :)
         !! Far-field temperature (degC), thickness-weighted over
         !! `far_field_depth`.
      real(wp), allocatable :: s_far(:, :)
         !! Far-field salinity (g/kg), same average.
      real(wp), allocatable :: u_far(:, :)
         !! Far-field x velocity at the cell CENTRE (m/s), same average.
      real(wp), allocatable :: v_far(:, :)
         !! Far-field y velocity at the cell CENTRE (m/s), same average.
      real(wp), allocatable :: ustar(:, :)
         !! Melt friction velocity (m/s).
      real(wp), allocatable :: t_b(:, :)
         !! Interface temperature (degC), on the liquidus.
      real(wp), allocatable :: s_b(:, :)
         !! Interface salinity (g/kg).
      real(wp), allocatable :: melt(:, :)
         !! **Canonical** melt mass flux (kg/m^2/s), > 0 melting.
      real(wp), allocatable :: q_ocean(:, :)
         !! Turbulent heat flux ocean → interface (W/m^2), > 0 cools the
         !! ocean.
      real(wp), allocatable :: gamma_t(:, :)
         !! Thermal exchange velocity (m/s) the column's solve converged
         !! on — NOT `par%gamma_t_coeff`, which is the dimensionless
         !! coefficient.  Under `hj99` / `yung25` it is an implicit
         !! function of the converged interface state, so it is stored
         !! rather than re-derived: a diagnostic that rebuilt it from
         !! `u*` alone would report the NEUTRAL value instead of the
         !! stratification-suppressed one.  Zero where inactive.
      real(wp), allocatable :: gamma_s(:, :)
         !! Haline exchange velocity (m/s), same convention.
      integer, allocatable :: status(:, :)
         !! `CAVITY_MELT_*` per column; `CAVITY_MELT_OK` where inactive.
      real(wp), allocatable :: comp_scale(:, :)
         !! Per-cell top-layer thickness RATIO `h_new/h_old` left behind
         !! by the `volume_compensation` sink, exactly `1` everywhere the
         !! sink did not act.  Every PASSIVE tracer's top-layer load is
         !! multiplied by it (`cavity_comp_scale_tracer_impl`) so the
         !! removed parcel carries that cell's own concentration and
         !! changes none of them.  Allocated with the rest of the slot
         !! (full size iff `enable`); left at `1` when
         !! `volume_comp = CAVITY_VC_NONE`.

      ! ---- Status counters (host scalars, reduced off the device) ----
      integer :: n_nonfinite_step = 0
         !! Active columns returning `NONFINITE_INPUT`/`NONFINITE_STATE`
         !! this step.  **FATAL** — the driver fails loud.
      integer :: n_not_converged_step = 0
         !! Active columns returning `NOT_CONVERGED` this step (zero melt
         !! applied there — the kernel's documented safe state).
      integer :: n_no_root_step = 0
         !! Active columns returning `NO_PHYSICAL_ROOT` this step.
      integer :: n_other_step = 0
         !! Active columns returning any other non-OK status
         !! (`BAD_INPUT`, `NO_CORIOLIS`, `LAW_DOMAIN`, ...).
      integer(int64) :: n_not_converged_total = 0_int64
         !! Running total, drained to the console like
         !! `continuity_t%n_limited_total`.  int64 because a
         !! long run with one stubborn column can exceed 2e9.
      integer(int64) :: n_no_root_total = 0_int64
         !! Running total of `NO_PHYSICAL_ROOT`.
      integer(int64) :: n_other_total = 0_int64
         !! Running total of every other non-OK, non-fatal status.
      integer :: n_thin_step = 0
         !! Columns this thermo step whose top layer could NOT give up
         !! the thickness the real-mass path asked of it without falling
         !! through `H_CAVITY_FLOOR` — a FREEZING column (`m < 0`) whose
         !! top layer is thinner than `|m|*dt/rho_0`, or a compensation
         !! sink deeper than the open-ocean top layer.  The withdrawal is
         !! CLAMPED to what is there ABOVE the floor (so `h` stays
         !! strictly above the vanish marker, never on or below it) and
         !! the count is FATAL: a clamped withdrawal is a
         !! withdrawal the tracked mass source no longer matches, so
         !! continuing would print a budget that silently stopped
         !! closing.  Same stance as the non-finite melt column.
      integer(int64) :: n_thin_total = 0_int64
         !! Running total of `n_thin_step`, for the record.
      real(wp) :: melt_volume_step = 0.0_wp
         !! Domain-integrated meltwater VOLUME (m^3) added this thermo
         !! step over the INTERIOR (ghosts excluded, globally combined).
         !! Diagnostic + the input the compensation sink spends.
      real(wp) :: open_area = 0.0_wp
         !! Interior wet area (m^2) the ice does NOT cover, globally
         !! combined — the denominator of the uniform sink.
      real(wp) :: comp_withdrawal_step = 0.0_wp
         !! Thickness (m) the compensation sink removed from each open
         !! -ocean column this thermo step; zero when compensation is off.
   contains
      procedure, non_overridable :: init => ocean_cavity_flux_init
      procedure, non_overridable :: destroy => ocean_cavity_flux_destroy
      procedure, non_overridable :: enter_data => ocean_cavity_flux_enter_data
      procedure, non_overridable :: exit_data => ocean_cavity_flux_exit_data
      procedure, non_overridable :: bytes => ocean_cavity_flux_bytes
   end type ocean_cavity_flux_t