rdb_ocean_cavity Module

Static ice-shelf cavity GEOMETRY: the prescribed ice draft z_draft(i,j) and the arithmetic that turns it into a water column, a grounding decision and an isostatic load.

The datum (the whole design in three lines)

With b the bed depth (m, positive down) and z_draft >= 0 the ice-base depth (m, positive down):

(D)  datum :  bt_H_ref = b - z_draft            (was: bt_H_ref = b)
              ... and exactly 0 on a GROUNDED column, which has no
              water column at all -- see `cavity_datum_impl`
(P)  load  :  p_ice_ref = rho_ref*GRAVITY*z_draft
(I)  invariant :  rho_ref*g*z_draft + (bt_H_ref - b)*rho_ref*g == 0
              on every WET column (a grounded one carries no
              barotropic momentum equation, so no load to count)

(I) says the load is counted exactly ONCE: whatever the datum absorbs must not also be handed to the eta_forcing seam. The two halves of “once” are:

  • BAROTROPIC — the datum (D), and nothing else on the seam. The datum puts the free surface the PGF sees at eta_geo = -z_draft and p_ice_ref in the pa(nz+1) BC cancels exactly that, so under the MOM6 split (&ocean_bt_nml bc_pgf_forcing, where the depth-mean layer PGF forces the barotropic mode) the static load is balanced, and under the legacy split it was discarded with the depth mean. Either way p_ice_ref never joins sf%p_surf, out of which eta_ib — and hence eta_forcing — is built.
  • PRESSURE — p_ice_ref (P), assembled into multilayer_state_t%p_top = p_ice_ref + sf%p_surf and read by the FV_MOM6 pa(nz+1) top BC and the in-situ EOS. Only the load ANOMALY (total minus what the datum carries, i.e. exactly sf%p_surf under the Boussinesq-isostatic convention) reaches the seam, so an inverse-barometer run with no cavity is bit-identical and a cavity with no p_surf sends the seam nothing at all.

The consequence of (D) is that the free-surface anomaly bt_eta = sum(h_layer) - bt_H_ref is ZERO under the shelf at rest, so every consumer of the water-column thickness D = bt_H_ref + bt_eta — the barotropic continuity face thickness, the Chapman phase speed, the ALE remap_h_ref, the wet/dry depth — is already correct with no cavity branch of its own. That is Losch (2008) §2.1’s own convention (“the ‘sea-surface height’ eta is the deviation from the ‘reference’ ice-shelf draft h”), and it is why the draft is NOT carried in eta.

The geopotential interface stack is a DIFFERENT datum and stays absolute: the FV PGF builds e_face(1) = -b from the true bed and stacks upward, so the column top lands at -z_draft + eta on its own. Two datums, kept apart on purpose.

Grounding

A column whose water thickness b - z_draft falls below h_min_cavity is LAND — it goes through the same seed_wet_mask_impl the bathymetry uses, so the static metric-zeroing land mask and the finite land-state seeding follow for free. There is deliberately NO thin film of water under grounded ice.

Units

Every knob in &ocean_cavity_dyn_nml is in METRES; the setters below work in GRID coordinate units (metres on a Cartesian grid, DEGREES on spherical/curvilinear). cavity_fill_draft converts at the dispatch with topo_length_to_grid_units, exactly as &ocean_topo_nml slope_scale is converted for the formula bathymetry — without it a metres position against a degrees grid puts the shelf outside the domain.

Host-only by construction: every routine here runs at SETUP, before ocean_state_enter_data, on plain do loops (a do concurrent here would make -stdpar=gpu round-trip unmapped arrays through the device once per loop — the documented ic-seed trap).


Uses

  • module~~rdb_ocean_cavity~~UsesGraph module~rdb_ocean_cavity rdb_ocean_cavity module~rdb_constants rdb_constants module~rdb_ocean_cavity->module~rdb_constants module~rdb_grid rdb_grid module~rdb_ocean_cavity->module~rdb_grid pic_types pic_types module~rdb_constants->pic_types module~rdb_grid->module~rdb_constants

Used by

  • module~~rdb_ocean_cavity~~UsedByGraph module~rdb_ocean_cavity rdb_ocean_cavity module~rdb_ocean_setup rdb_ocean_setup module~rdb_ocean_setup->module~rdb_ocean_cavity module~rdb_ocean_state rdb_ocean_state module~rdb_ocean_setup->module~rdb_ocean_state module~rdb_ocean_state->module~rdb_ocean_cavity proc~validate_config validate_config proc~validate_config->module~rdb_ocean_cavity module~rdb_driver rdb_driver 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_diag_derived rdb_ocean_diag_derived module~rdb_ocean_diag_derived->module~rdb_ocean_state module~rdb_ocean_diag_fills rdb_ocean_diag_fills 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_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 module~rdb_ocean_api rdb_ocean_api module~rdb_ocean_api->module~rdb_handle module~rdb_ocean_api->module~rdb_ocean_diag_derived module~rdb_ocean_api->module~rdb_ocean_diag_fills module~rdb_ocean_api->module~rdb_ocean_engine

Variables

Type Visibility Attributes Name Initial
real(kind=wp), public, parameter :: CAVITY_BOUND_INF = 1.0e29_wp

“No limit on this side” sentinel for the shelf-box corners. A bound whose magnitude is at or above this is IGNORED, which is what the &ocean_cavity_dyn_nml draft_x0/x1/y0/y1 defaults of +/-1e30 mean. It is a sentinel rather than a sign convention because a NEGATIVE position is legitimate: the ghost band sits at negative global x/y, and a shelf that reaches the west wall must cover those ghost columns too — a box that stops at x = 0 would put a phantom calving front one cell outside the wall, which is the formula-bathymetry ghost trap in its cavity form.

integer, public, parameter :: CAVITY_DRAFT_FILE = 3

Static 2-D NetCDF draft — deferred (fails loud at configure).

integer, public, parameter :: CAVITY_DRAFT_FLAT = 1

Uniform draft inside the shelf box.

integer, public, parameter :: CAVITY_DRAFT_INVALID = -1

Unrecognised spelling.

integer, public, parameter :: CAVITY_DRAFT_LINEAR = 2

Linear-in-x draft inside the shelf box.

integer, public, parameter :: CAVITY_DRAFT_NONE = 0

z_draft = 0 everywhere (the identity, even when enabled).

integer, public, parameter :: CAVITY_SIGN_DEPTH = 0

The file variable IS the ice-base DEPTH, positive down and >= 0 — Roundabout’s own z_draft convention, so the values pass through unchanged.

integer, public, parameter :: CAVITY_SIGN_ELEVATION = 1

The file variable is the ice-base ELEVATION z_d, positive UP and therefore <= 0 under a floating shelf — the convention the ISOMIP+ geometry file uses (“iceDraft … the elevation of the ice-ocean interface (z_d)”, Asay-Davis et al. 2016 Sect. 3.3). Values are NEGATED on load.

integer, public, parameter :: CAVITY_SIGN_INVALID = -1

Unrecognised spelling. There is deliberately NO default that guesses from the data: a draft file whose sign is inferred from minval < 0 would silently flip an all-zero (open-ocean) or partially-calved field, and the two conventions differ by the entire ice load.

integer, public, parameter :: CAVITY_SOURCE_DRAFT = 0

The formula gives the ice-base DEPTH directly.

integer, public, parameter :: CAVITY_SOURCE_INVALID = -1
integer, public, parameter :: CAVITY_SOURCE_IN_SITU = 2

True isostasy against the in-situ column — deferred.

integer, public, parameter :: CAVITY_SOURCE_THICKNESS = 1

The formula gives an ice THICKNESS; z_draft = rho_ice*h/rho_0.


Functions

public pure function cavity_datum_residual(bt_H_ref, b, z_draft, h_min, nx, ny) result(resid)

Max violation of the counted-once invariant (I) in METRES of reference depth, over the WET columns: max |bt_H_ref - (b - z_draft)| where b - z_draft >= h_min.

Read more…

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: bt_H_ref(nx,ny)
real(kind=wp), intent(in) :: b(nx,ny)
real(kind=wp), intent(in) :: z_draft(nx,ny)
real(kind=wp), intent(in) :: h_min
integer, intent(in) :: nx
integer, intent(in) :: ny

Return Value real(kind=wp)

public pure function cavity_draft_is_finite_nonneg(z_draft, nx, ny) result(ok)

Configure-time guard: every draft entry is finite and >= 0.

Read more…

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: z_draft(nx,ny)
integer, intent(in) :: nx
integer, intent(in) :: ny

Return Value logical

public pure function parse_cavity_draft_config(name) result(code)

&ocean_cavity_dyn_nml draft_config -> CAVITY_DRAFT_*. Returns CAVITY_DRAFT_INVALID on an unrecognised spelling — the caller fails loud; there is no silent default.

Arguments

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

Return Value integer

public pure function parse_cavity_draft_sign(name) result(code)

&ocean_cavity_dyn_nml draft_sign -> CAVITY_SIGN_*. Returns CAVITY_SIGN_INVALID on an unrecognised spelling — the caller fails loud.

Arguments

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

Return Value integer

public pure function parse_cavity_draft_source(name) result(code)

&ocean_cavity_dyn_nml draft_source -> CAVITY_SOURCE_*.

Arguments

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

Return Value integer

private pure function in_shelf_box(x, y, x0, x1, y0, y1) result(inside)

.true. inside the shelf box. Each of the four bounds is applied only when it is FINITE in the CAVITY_BOUND_INF sense, so the namelist defaults (+/-1e30) describe an unbounded shelf and a user who only wants a calving front in x need not describe y at all.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: x
real(kind=wp), intent(in) :: y
real(kind=wp), intent(in) :: x0
real(kind=wp), intent(in) :: x1
real(kind=wp), intent(in) :: y0
real(kind=wp), intent(in) :: y1

Return Value logical


Subroutines

public pure subroutine cavity_apply_land_exclusion(z_draft, b, nx, ny, n_over_land)

NO ICE OVER LAND (design rule R2): force z_draft = 0 on every column the bathymetry already calls land (b < LAND_DEPTH_THRESHOLD), and report how many were touched so the caller can log it.

Read more…

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: z_draft(nx,ny)
real(kind=wp), intent(in) :: b(nx,ny)
integer, intent(in) :: nx
integer, intent(in) :: ny
integer, intent(out) :: n_over_land

Count of columns whose draft was zeroed (ghosts included).

public pure subroutine cavity_count_grounded(b, z_draft, h_min, ng, nx_phys, ny_phys, nx, ny, n_grounded, n_interior)

Count the INTERIOR columns the cavity grounds: wet bed (b >= LAND_DEPTH_THRESHOLD) but water thickness b - z_draft < h_min. Interior-only, because the ghost band carries extrapolated bathymetry and would bias the fraction the grounded_max_frac sanity bound is taken against.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: b(nx,ny)
real(kind=wp), intent(in) :: z_draft(nx,ny)
real(kind=wp), intent(in) :: h_min
integer, intent(in) :: ng
integer, intent(in) :: nx_phys
integer, intent(in) :: ny_phys
integer, intent(in) :: nx
integer, intent(in) :: ny
integer, intent(out) :: n_grounded
integer, intent(out) :: n_interior

public pure subroutine cavity_datum_impl(H_ref, b, z_draft, h_min, nx, ny)

The BAROTROPIC DATUM: bt_H_ref = b - z_draft on a column that has water under the ice, and exactly 0 on one that is GROUNDED (b - z_draft < h_min, i.e. land by the very rule seed_wet_mask_impl applies).

Read more…

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(out) :: H_ref(nx,ny)
real(kind=wp), intent(in) :: b(nx,ny)
real(kind=wp), intent(in) :: z_draft(nx,ny)
real(kind=wp), intent(in) :: h_min

&ocean_cavity_dyn_nml h_min_cavity (m, validated > 0) — the SAME grounding cutoff the wet-mask seed applies, passed rather than re-spelled so the two decisions cannot drift.

integer, intent(in) :: nx
integer, intent(in) :: ny

public pure subroutine cavity_draft_apply_sign(z_draft, nx, ny, sign_code)

Normalise a freshly loaded draft field onto Roundabout’s convention (DEPTH, positive down, >= 0).

Read more…

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: z_draft(nx,ny)
integer, intent(in) :: nx
integer, intent(in) :: ny
integer, intent(in) :: sign_code

public pure subroutine cavity_fill_cover_frac(cover_frac, z_draft, nx, ny)

v1 ice-cover fraction: BINARY, 1 wherever there is any draft. An area-blended calving front (a partially covered cell) is a melt-physics decision, not a geometry one, so it is deliberately left for the slice that needs it — the field exists now only so that slice does not have to re-open the metrics lifecycle.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(out) :: cover_frac(nx,ny)
real(kind=wp), intent(in) :: z_draft(nx,ny)
integer, intent(in) :: nx
integer, intent(in) :: ny

public pure subroutine cavity_fill_p_ice_ref(p_ice_ref, z_draft, rho_g, nx, ny)

p_ice_ref = (rho_ref*GRAVITY) * z_draft (Pa).

Read more…

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(out) :: p_ice_ref(nx,ny)
real(kind=wp), intent(in) :: z_draft(nx,ny)
real(kind=wp), intent(in) :: rho_g

rho_ref*GRAVITY (kg m^-2 s^-2), pre-multiplied by the caller.

integer, intent(in) :: nx
integer, intent(in) :: ny

public pure subroutine cavity_trim_eta_linear_impl(eta_trim, ok, z_draft, water, h_min_cavity, rho_ref, rho_surf, drho_dz, nx, ny)

The TRIMMED initial surface (MOM6 TRIM_IC_FOR_P_SURF, trim_for_ice): the free-surface anomaly eta_trim that puts a loaded column top exactly where the displaced water’s own weight equals the load, so the initial state is at rest under the MOM6 barotropic split (&ocean_bt_nml bc_pgf_forcing).

Read more…

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(out) :: eta_trim(nx,ny)

Initial free-surface anomaly (m, positive UP); <= 0 wherever the displaced water is lighter than rho_ref.

logical, intent(out) :: ok
real(kind=wp), intent(in) :: z_draft(nx,ny)

Ice-base depth (m, positive down), ghosts included.

real(kind=wp), intent(in) :: water(nx,ny)

Reference water column b - z_draft (m) — the grounding test.

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

Grounding cutoff (m), &ocean_cavity_dyn_nml h_min_cavity.

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

The load’s reference density (kg/m^3), eos%rho0.

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

Initial in-situ density at z = 0 (kg/m^3).

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

d(rho)/dz of the initial profile (kg/m^4, z positive UP; < 0 for a stable column).

integer, intent(in) :: nx
integer, intent(in) :: ny

public pure subroutine cavity_water_column_impl(water, b, z_draft, nx, ny)

water = b - z_draft — the reference water-column thickness the datum, the layer split and the wet-mask seed all work on. Kept as one named routine so the three call sites cannot drift.

Read more…

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(out) :: water(nx,ny)
real(kind=wp), intent(in) :: b(nx,ny)
real(kind=wp), intent(in) :: z_draft(nx,ny)
integer, intent(in) :: nx
integer, intent(in) :: ny

public pure subroutine set_draft_flat(z_draft, grid, draft, x0, x1, y0, y1)

Uniform draft draft inside the shelf box [x0,x1] x [y0,y1], zero outside it (open ocean, including everything beyond the calving front at x1). Any bound at or beyond CAVITY_BOUND_INF is ignored — the shelf is then open on that side, which is what the namelist defaults ask for.

Read more…

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: z_draft(:,:)
type(hgrid_t), intent(in) :: grid
real(kind=wp), intent(in) :: draft

Draft depth (m, positive down) inside the box.

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

Shelf box in GRID coordinate units; a bound at or beyond CAVITY_BOUND_INF is ignored (open on that side).

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

Shelf box in GRID coordinate units; a bound at or beyond CAVITY_BOUND_INF is ignored (open on that side).

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

Shelf box in GRID coordinate units; a bound at or beyond CAVITY_BOUND_INF is ignored (open on that side).

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

Shelf box in GRID coordinate units; a bound at or beyond CAVITY_BOUND_INF is ignored (open on that side).

public pure subroutine set_draft_linear(z_draft, grid, draft0, slope, x0, x1, y0, y1)

Linear-in-x draft z_draft = draft0 + slope*(x - x0) inside the shelf box, clipped at 0 from below (a formula that would lift the ice base above the sea surface is open water, not negative ice), and zero outside the box.

Read more…

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: z_draft(:,:)
type(hgrid_t), intent(in) :: grid
real(kind=wp), intent(in) :: draft0

Draft at x = x0 (m, positive down).

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

d(draft)/dx in draft-metres per grid unit.

real(kind=wp), intent(in) :: x0
real(kind=wp), intent(in) :: x1
real(kind=wp), intent(in) :: y0
real(kind=wp), intent(in) :: y1