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.
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:
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.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.
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.
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).
| 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 |
| 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 |
|
| integer, | public, | parameter | :: | CAVITY_SIGN_DEPTH | = | 0 |
The file variable IS the ice-base DEPTH, positive down and |
| integer, | public, | parameter | :: | CAVITY_SIGN_ELEVATION | = | 1 |
The file variable is the ice-base ELEVATION |
| 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
|
| 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; |
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.
| Type | Intent | Optional | 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 |
Configure-time guard: every draft entry is finite and >= 0.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | z_draft(nx,ny) | |||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny |
&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.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| character(len=*), | intent(in) | :: | name |
&ocean_cavity_dyn_nml draft_sign -> CAVITY_SIGN_*.
Returns CAVITY_SIGN_INVALID on an unrecognised spelling — the
caller fails loud.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| character(len=*), | intent(in) | :: | name |
&ocean_cavity_dyn_nml draft_source -> CAVITY_SOURCE_*.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| character(len=*), | intent(in) | :: | name |
.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.
| Type | Intent | Optional | 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 |
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.
| Type | Intent | Optional | 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). |
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.
| Type | Intent | Optional | 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 |
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).
| Type | Intent | Optional | 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 |
|
||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny |
Normalise a freshly loaded draft field onto Roundabout’s
convention (DEPTH, positive down, >= 0).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | z_draft(nx,ny) | |||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | sign_code |
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.
| Type | Intent | Optional | 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 |
p_ice_ref = (rho_ref*GRAVITY) * z_draft (Pa).
| Type | Intent | Optional | 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 |
|
||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | 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).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(out) | :: | eta_trim(nx,ny) |
Initial free-surface anomaly (m, positive UP); |
||
| 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 |
||
| real(kind=wp), | intent(in) | :: | h_min_cavity |
Grounding cutoff (m), |
||
| real(kind=wp), | intent(in) | :: | rho_ref |
The load’s reference density (kg/m^3), |
||
| real(kind=wp), | intent(in) | :: | rho_surf |
Initial in-situ density at |
||
| real(kind=wp), | intent(in) | :: | drho_dz |
d(rho)/dz of the initial profile (kg/m^4, |
||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | 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.
| Type | Intent | Optional | 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 |
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.
| Type | Intent | Optional | 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
|
||
| real(kind=wp), | intent(in) | :: | x1 |
Shelf box in GRID coordinate units; a bound at or beyond
|
||
| real(kind=wp), | intent(in) | :: | y0 |
Shelf box in GRID coordinate units; a bound at or beyond
|
||
| real(kind=wp), | intent(in) | :: | y1 |
Shelf box in GRID coordinate units; a bound at or beyond
|
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.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | z_draft(:,:) | |||
| type(hgrid_t), | intent(in) | :: | grid | |||
| real(kind=wp), | intent(in) | :: | draft0 |
Draft at |
||
| 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 |