Gated ocean_sea_ice_t slot for the SIS2-derived sea-ice model
(PLAN_SEA_ICE.md). PR 0 was plumbing only; PR 1 added the first
prognostic array — the ocean-side frazil supercooling accumulator
frazil_heat (filled by rdb_ice_frazil) plus its heat-budget
contributor array. PR 2 added the enthalpy library
(rdb_ice_enthalpy). PR 3a lands the Winton column prognostics:
part_size, m_ice, m_snow, enth_ice, enth_snow, sal_ice
— driven only by the new rdb_ice_column test suite (nothing in
the driver calls the column kernels yet). A run with
&ocean_ice_nml enable = .false. (the default) never calls into
this module beyond the parent gates, so existing configurations
stay byte-identical.
PR 3b lands the ocean<->ice coupling seam: rdb_ice_frazil_uptake
spends the frazil bank as new category-1 ice (m_frozen_diag) and
rdb_ice_ocean_coupler refreshes the surface Q_salt field from
the resulting brine-rejection rate (salt_flux_diag) — both new
fields below.
PR 3c lands the coupleable atmospheric-forcing seam
(atm_sf0/atm_dsfdt/atm_sw_dn, filled by rdb_ice_atm_forcing),
the ocean->ice basal-flux field (fb, filled by
rdb_ice_basal_flux, which also samples the sst_seam/ssurf_seam/
tfw_seam scratch reused by rdb_ice_thermo_driver), the column’s
per-category scratch outputs (tsurf_out/h2o_ocn_to_ice/
h2o_ice_to_ocn/heat_to_ocn/sw_thru), and the melt-side
ocean-coupling diags heat_flux_diag/m_melt_diag (parallel to
salt_flux_diag/m_frozen_diag) that rdb_ice_ocean_coupler’s
ice_ocean_heat_flux and the driver’s resume fold consume.
PR 4a lands the multi-category ITD: h_lim/mh_lim (SIS2 category
thickness/mass bounds, ice_itd_category_bounds, THIS module) and the
fb_part_sum scratch (the rdb_ice_thermo_driver fb-cover snapshot).
Mirrors ocean_meke_t (the default-off, gated- allocation,
restart-persistent precedent). PR-58 adds an optional hlim_cfg
override of the bin edges (ice_itd_category_bounds’s hlim_vals
dummy) — see hlim_cfg below.
PR 4b lands horizontal category transport (rdb_ice_transport):
u_ice/v_ice (C-grid face velocities, persistent, allocated
whenever the ice slot is live — PR 5’s EVP dynamics will fill them
instead of the v1 ocean-surface-velocity sampler) and the
transport-only scratch workspace (mca_ice/mca_snow,
uh_ice/vh_ice/uh_snow/vh_snow, htot_work/hl_x_work/
hr_x_work/hl_y_work/hr_y_work/uhtot_work/vhtot_work)
allocated ONLY when
&ocean_ice_nml transport = .true. (the this%transport flag,
set from config before init, mirrors enable/ncat). Later
rungs: PR 5 C-grid EVP dynamics (replaces the u_ice/v_ice filler).
PR 5 lands C-grid EVP rheology (rdb_ice_evp): dynamics (master
flag, set from config before init like transport) gates the
driver’s ice_evp_step call (which now WRITES u_ice/v_ice
instead of the transport sampler) and turns on the stress fields
str_d/str_t (T-cells) + str_s (corners) — the H&D (1997)
divergence/tension/shear stress tensor components, persistent +
restart-carried. tau_a_x/tau_a_y are a configure-time snapshot
of the wind stress felt by the ice (no ice-specific bulk drag law,
D7); fxoc/fyoc are the subcycle-averaged ice->ocean stress that
ice_ocean_stress_flux (rdb_ice_ocean_coupler) blends into
ocean_surface_stress_t%tau_x/tau_y by concentration. All seven
fields are allocated UNCONDITIONALLY whenever the ice slot is live
(same contract as u_ice/v_ice — cheap 2-D arrays), zero-init.
PR 63 closes the resume hole PR 5 documented (F4): fxoc/fyoc
restart-carry the subcycle-averaged drag, but ice_ocean_stress_flux
blends it against the PRE-thermo ci of that same step, and the
checkpoint only ever sees the POST-thermo ci — so reconstructing
the blend at resume from the checkpointed masses gives a different
answer whenever thermo/transport changed ci after the blend.
tau_ocn_x/tau_ocn_y mirror the exact blended value
ice_ocean_stress_flux last wrote into
ocean_surface_stress_t%tau_x/tau_y — restart-carried, so the
resume path COPIES it instead of recomputing it (formula-agnostic:
the carry stays exact under any future change to the blend
formula). tau_ocn_valid is the host-only “was a blend ever
written” flag (0.0 fresh run / pre-PR-63 checkpoint, 1.0 otherwise)
— SIS2’s query_initialized('stress_mag') fallback idiom
(ice_type.F90:264, ice_model.F90:2410), needed because an
unconditional copy on a fresh run would hand the ocean a zeroed
wind stress on step 1. See ice_ocean_stress_resume_apply
(rdb_ice_ocean_coupler).
Two-mode convention (part_size/m_ice/m_snow), load-bearing.
ncat == 1 is the LEGACY LUMPED mode landed by PR 3b/3c:
part_size is never maintained (part_size(:,:,0)=1 forever,
category 1 unused), and m_ice/m_snow/enth_ice/enth_snow/
sal_ice are per unit CELL area. All existing code paths
(ice_frazil_uptake_impl, the ncat=1 ice_thermo_driver_reduce_impl)
run byte-for-byte unchanged under this mode — bit-identity with PR 3c
is guaranteed BY CONSTRUCTION (dispatch happens only at the three
shim points in rdb_ice_frazil_uptake/rdb_ice_thermo_driver/
rdb_ice_itd, never inside a kernel). ncat > 1 is the SIS2 ITD
mode (PR 4a): part_size is LIVE (Σ_cat part_size = 1, category 0 =
open water), and m_ice/m_snow become per unit ICE-COVERED-area
intensive quantities (SIS2 mH_ice/mH_snow) — the frazil uptake
annexes open water into an occupied/thinnest category
(ice_frazil_uptake_multicat_impl), the thermo-driver reduce
part-weights the per-cell diags, and ice_adjust_categories
(rdb_ice_itd) restores the ITD (whole-category “move all of it”
shift, SIS_transport.F90:611-891) once per thermo window.
enth_ice/enth_snow/sal_ice stay per-MASS intensive in BOTH
modes (unchanged meaning). Restart files written by PR-3c at
ncat>1 carry the OLD lumped meaning — the feature branch is
unreleased, so this break is accepted (not carried forward).
PR 26 lands the snowfall source term: has_snowfall (host-side
dispatch gate, latched from &ocean_ice_nml snowfall /= 0 before
init, mirrors transport/dynamics), the fourth atmospheric-seam
field atm_fprec (kg/m^2/s, filled by rdb_ice_atm_forcing
alongside atm_sw_dn, consumed by rdb_ice_column’s
ice_snow_accumulate), and the ocean-delivery pair
snow_part_ocn/fprec_ocn_diag (the PRE-column ice-free-cover
snapshot and the resulting ocean-bound frozen-precipitation share,
filled by rdb_ice_thermo_driver/rdb_ice_snow — same
PRE-column-snapshot contract as fb_part_sum). All three arrays
are allocated UNCONDITIONALLY whenever the ice slot is live (cheap
2-D arrays, same contract as the rest of the atm_* seam);
has_snowfall is what makes snowfall=0 byte-identical by
construction. fprec_ocn_diag is the binding seam PR-16 consumes
as a net_massin source (see rdb_ice_snow’s module docstring).
PR 27 lands the Archimedes freeboard snow-ice flood: snow_ice
(host-side gate, latched from &ocean_ice_nml snow_ice BEFORE
init, same convention as has_snowfall/transport/dynamics)
and snow_to_ice (per-category kg/m² output, SIS2 SN2IC,
allocated UNCONDITIONALLY whenever the ice slot is live, same
contract as sw_thru — filled by ice_thermo_columns, zeroed
unconditionally every thermo step, copyin/delete mapped, NOT
restart-carried, no downstream consumer yet). snow_ice=.false.
(default) is what makes the flood byte-identical by construction.
Persistent EVP-rheology scratch (SIS2 C-grid dynamics), hung off
ocean_sea_ice_t as the evp_ws slot — eagerly allocated in the
ice state’s init and GPU-mapped via enter_data, so it matches
the rest of src/core/ocean/ (which carries ZERO module-level
save allocatables — every kernel puts its scratch on a state
DT). Replaces the retired rdb_ice_evp module-level save
workspace + its lazy evp_workspace_ensure/ice_evp_cleanup
lifecycle. Allocated / mapped ONLY when ocean_sea_ice_t%dynamics
is on (the workspace is EVP-dynamics-only).
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| real(kind=wp), | public, | allocatable | :: | a_u_w(:,:) |
PR 62: face ice concentration, |
||
| real(kind=wp), | public, | allocatable | :: | a_v_w(:,:) |
PR 62: face ice concentration, |
||
| real(kind=wp), | public, | allocatable | :: | ci_in_w(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | ci_w(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | del_sh_min_pr_w(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | del_sh_w(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | mask_q_w(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | mask_t_w(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | mask_u_w(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | mask_v_w(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | mi_ratio_a_q_w(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | mi_u_w(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | mi_v_w(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | mice_in_w(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | mice_w(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | mis_in_w(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | mis_w(:,:) | |||
| integer, | public | :: | nx | = | 0 |
Cached T-cell x extent (nx_total). |
|
| integer, | public | :: | ny | = | 0 |
Cached T-cell y extent (ny_total). |
|
| real(kind=wp), | public, | allocatable | :: | pres_mice_w(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | q_w(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | sh_dd_w(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | sh_ds_w(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | sh_dt_w(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | u_tmp_w(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | zeta_w(:,:) |
| procedure, public, non_overridable :: bytes => evp_workspace_bytes | |
| procedure, public, non_overridable :: destroy => evp_workspace_destroy | |
| procedure, public, non_overridable :: enter_data => evp_workspace_enter_data | |
| procedure, public, non_overridable :: exit_data => evp_workspace_exit_data | |
| procedure, public, non_overridable :: init => evp_workspace_init |
Sea-ice state slot. All fields default to the inert
(enable=.false.) configuration so an ocean run that never sets
&ocean_ice_nml is byte-identical to a build without this slot.
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| real(kind=wp), | public, | allocatable | :: | atm_dsfdt(:,:) |
SEB slope dSF/dT (W/m^2/K) — |
||
| real(kind=wp), | public, | allocatable | :: | atm_fprec(:,:) |
PR 26: frozen-precipitation rate onto the ice top (kg/m^2/s), |
||
| real(kind=wp), | public, | allocatable | :: | atm_sf0(:,:) |
Net upward surface flux at T_surf=0 (W/m^2), the SEB intercept
|
||
| real(kind=wp), | public, | allocatable | :: | atm_sw_dn(:,:) |
Downwelling shortwave into the ice top (W/m^2) — |
||
| logical, | public | :: | dynamics | = | .false. |
EVP rheology master switch ( |
|
| logical, | public | :: | enable | = | .false. |
Master switch ( |
|
| real(kind=wp), | public, | allocatable | :: | enth_ice(:,:,:,:) |
Ice specific enthalpy (J/kg), shape (nx_total, ny_total,
ncat, nk_ice). BOTTOM-UP: k=1 = ice BOTTOM (ocean side),
k=nk_ice = ice TOP (atm/snow side) — the opposite of the
SIS2/ |
||
| real(kind=wp), | public, | allocatable | :: | enth_snow(:,:,:,:) |
Snow specific enthalpy (J/kg), shape (nx_total, ny_total, ncat, 1). |
||
| type(evp_workspace_t), | public | :: | evp_ws |
Persistent EVP-dynamics scratch ( |
|||
| real(kind=wp), | public, | allocatable | :: | fb(:,:) |
Ocean -> ice-base heat flux (W/m^2), filled by
|
||
| real(kind=wp), | public, | allocatable | :: | fb_part_sum(:,:) |
Pre-column fb-charged ice-cover fraction snapshot (shape
(nx_total, ny_total)) — |
||
| real(kind=wp), | public, | allocatable | :: | fprec_ocn_diag(:,:) |
PR 26: frozen precipitation delivered directly to the ocean
(kg/m^2/s, per unit CELL area, >= 0) — the share of
|
||
| real(kind=wp), | public, | allocatable | :: | frazil_heat(:,:) |
Ocean-side frazil supercooling BANK (J/m², T-cells, shape
(nx_total, ny_total)). |
||
| real(kind=wp), | public, | allocatable | :: | fxoc(:,:) |
Subcycle-averaged ice->ocean stress [Pa], u-faces, shape
(nx_total+1, ny_total). SIS2 |
||
| real(kind=wp), | public, | allocatable | :: | fyoc(:,:) |
Ditto, v-faces, shape (nx_total, ny_total+1). SIS2 |
||
| real(kind=wp), | public, | allocatable | :: | h2o_ice_to_ocn(:,:,:) |
Meltwater mass to the ocean (kg/m²), shape (nx_total, ny_total, ncat), >= 0. SCRATCH. |
||
| real(kind=wp), | public, | allocatable | :: | h2o_ocn_to_ice(:,:,:) |
Mass FROZEN from the ocean onto the ice base (kg/m²), shape (nx_total, ny_total, ncat), >= 0. SCRATCH. |
||
| real(kind=wp), | public, | allocatable | :: | h_lim(:) |
Category lower thickness limits (m), shape (1:ncat+1) — SIS2
|
||
| logical, | public | :: | has_snowfall | = | .false. |
Host-side dispatch gate for the PR 26 snowfall source term,
latched from |
|
| real(kind=wp), | public, | allocatable | :: | heat_budget_frazil(:,:,:) |
hTr (K·m) change per cell per outer step attributed to the
frazil clamp — the |
||
| real(kind=wp), | public, | allocatable | :: | heat_flux_diag(:,:) |
Ice -> ocean net surface heat flux from the last thermo window
(W/m^2, POSITIVE DOWN into the ocean — the Q_heat convention),
shape (nx_total, ny_total). Q_heat = heat_to_ocn/dt_therm - fb
(see |
||
| real(kind=wp), | public, | allocatable | :: | heat_to_ocn(:,:,:) |
Leftover melt energy drained back to the ocean (J/m²), shape (nx_total, ny_total, ncat), >= 0. SCRATCH. |
||
| real(kind=wp), | public, | allocatable | :: | hl_x_work(:,:) |
PPM face-edge reconstruction of the category-SUMMED zonal mass,
FACE-shaped |
||
| real(kind=wp), | public, | allocatable | :: | hl_y_work(:,:) |
North-face PPM edge, |
||
| real(kind=wp), | public, | allocatable | :: | hlim_cfg(:) |
hlim |
||
| real(kind=wp), | public, | allocatable | :: | hr_x_work(:,:) |
Right-cell zonal face-edge companion to |
||
| real(kind=wp), | public, | allocatable | :: | hr_y_work(:,:) |
North-face right-cell PPM edge, |
||
| real(kind=wp), | public, | allocatable | :: | htot_work(:,:) |
Category-SUMMED mass, 2-D scratch (kg/m² of CELL area), shape
(nx_total, ny_total). Reused for the ice solve then the snow
solve, per direction (SIS2 |
||
| logical, | public | :: | is_init | = | .false. |
True between |
|
| real(kind=wp), | public, | allocatable | :: | m_frozen_diag(:,:) |
New frazil-ice mass formed in the LAST thermo window (kg per
m² of CELL area — v1 category convention, see
|
||
| real(kind=wp), | public, | allocatable | :: | m_ice(:,:,:) |
Total ice mass per category (kg/m²), shape (nx_total,
ny_total, ncat). TWO-MODE CONVENTION: |
||
| real(kind=wp), | public, | allocatable | :: | m_melt_diag(:,:) |
Net meltwater mass to the ocean in the last window (kg/m^2 of cell, = h2o_ice_to_ocn - h2o_ocn_to_ice summed over cats; POSITIVE = net melt). OVERWRITTEN each window. Restart-carried for post-resume diagnostic continuity (like m_frozen_diag). |
||
| real(kind=wp), | public, | allocatable | :: | m_snow(:,:,:) |
Snow mass per category (kg/m²), shape (nx_total, ny_total,
ncat). Same two-mode area convention as |
||
| real(kind=wp), | public, | allocatable | :: | mca_ice(:,:,:) |
Cell-averaged ice mass per category (CAS space, kg/m² of CELL
area — SIS2 |
||
| real(kind=wp), | public, | allocatable | :: | mca_snow(:,:,:) |
Cell-averaged snow mass per category (CAS space, kg/m² of CELL
area), shape (nx_total, ny_total, ncat). Same lifecycle as
|
||
| real(kind=wp), | public, | allocatable | :: | mh_lim(:) |
Category lower MASS limits (kg/m²), shape (1:ncat+1),
|
||
| integer, | public | :: | ncat | = | 5 |
Number of ice thickness categories ( |
|
| integer, | public | :: | nk_ice | = | 2 |
Vertical ice layers per category ( |
|
| integer, | public | :: | nx_total | = | 0 | ||
| integer, | public | :: | ny_total | = | 0 | ||
| real(kind=wp), | public, | allocatable | :: | part_size(:,:,:) |
Fractional ice-category area, shape (nx_total, ny_total,
0:ncat). Category 0 = OPEN WATER; Σ_cat part_size = 1.
TWO-MODE CONVENTION (module docstring): |
||
| real(kind=wp), | public, | allocatable | :: | sal_ice(:,:,:,:) |
Ice bulk salinity (PSU), shape (nx_total, ny_total, ncat,
nk_ice), same BOTTOM-UP k convention as |
||
| real(kind=wp), | public, | allocatable | :: | salt_flux_diag(:,:) |
Ice -> ocean virtual salt flux from the last uptake
(PSU·kg/m²/s, POSITIVE SALINIFIES — the surface-flux Q_salt
convention), shape (nx_total, ny_total). PERSISTENT +
restart-carried: |
||
| logical, | public | :: | snow_ice | = | .false. |
Archimedes freeboard snow-ice flood master switch
( |
|
| real(kind=wp), | public, | allocatable | :: | snow_part_ocn(:,:) |
PR 26: pre-column ice-free-cover fraction snapshot (shape
(nx_total, ny_total)), |
||
| real(kind=wp), | public, | allocatable | :: | snow_to_ice(:,:,:) |
PR 27: Archimedes freeboard snow-ice conversion this thermo
window (kg/m² per category), shape (nx_total, ny_total,
ncat), >= 0 — SIS2 |
||
| real(kind=wp), | public, | allocatable | :: | sst_seam(:,:) |
Sampled sea-surface temperature (degC) at the one-step-lagged
surface, filled by |
||
| real(kind=wp), | public, | allocatable | :: | ssurf_seam(:,:) |
Sampled sea-surface salinity (PSU), same sharing contract as
|
||
| real(kind=wp), | public, | allocatable | :: | str_d(:,:) |
Divergence stress tensor component [Pa*m], T-cells, shape
(nx_total, ny_total). SIS2 |
||
| real(kind=wp), | public, | allocatable | :: | str_s(:,:) |
Shearing stress tensor component (cross term) [Pa*m],
corners, shape (nx_total+1, ny_total+1). SIS2 |
||
| real(kind=wp), | public, | allocatable | :: | str_t(:,:) |
Tension stress tensor component [Pa*m], T-cells, shape
(nx_total, ny_total). SIS2 |
||
| real(kind=wp), | public, | allocatable | :: | sw_thru(:,:,:) |
Shortwave transmitted through the ice to the ocean (W/m²),
shape (nx_total, ny_total, ncat), >= 0. Per-category column
output; PR 31 reduces it to the per-cell |
||
| real(kind=wp), | public, | allocatable | :: | sw_thru_diag(:,:) |
PR 31: ice -> ocean shortwave transmitted through the ice to
the water below, reduced to per unit CELL area from the
per-category |
||
| real(kind=wp), | public, | allocatable | :: | tau_a_x(:,:) |
Atmospheric (wind) stress felt by the ice, snapshotted onto u-faces [Pa], shape (nx_total+1, ny_total). Configure-time copy of the ocean’s wind-stress field (D7: one atmospheric stress field, no ice-specific bulk drag law) — NOT restart- carried (rebuilt at configure from the wind-stress config on every run, resumed or fresh). |
||
| real(kind=wp), | public, | allocatable | :: | tau_a_y(:,:) |
Ditto, v-faces, shape (nx_total, ny_total+1). |
||
| real(kind=wp), | public | :: | tau_ocn_valid | = | 0.0_wp |
HOST-ONLY (PR 63). Exactly 0.0 or 1.0. |
|
| real(kind=wp), | public, | allocatable | :: | tau_ocn_x(:,:) |
PR 63. Mirror of the exact value |
||
| real(kind=wp), | public, | allocatable | :: | tau_ocn_y(:,:) |
Ditto, v-faces, shape (nx_total, ny_total+1). SIS2
|
||
| real(kind=wp), | public, | allocatable | :: | tfw_seam(:,:) |
Sampled seawater freezing temperature at the surface (degC),
same sharing contract as |
||
| real(kind=wp), | public, | allocatable | :: | tr_flux_x_work(:,:,:) |
Per-category zonal DONOR-VALUE buffer ( |
||
| real(kind=wp), | public, | allocatable | :: | tr_flux_y_work(:,:,:) |
Meridional twin of |
||
| logical, | public | :: | transport | = | .false. |
Horizontal category transport switch ( |
|
| real(kind=wp), | public, | allocatable | :: | tsurf_out(:,:,:) |
Column skin temperature (degC), shape (nx_total, ny_total, ncat) — diagnostic, recomputed every thermo step. SCRATCH. |
||
| real(kind=wp), | public, | allocatable | :: | u_ice(:,:) |
Ice velocity at C-grid u-faces (m/s), shape (nx_total+1,
ny_total). v1 INTERIM: sampled from the ocean surface layer
every transport call ( |
||
| real(kind=wp), | public, | allocatable | :: | uh_ice(:,:,:) |
Per-category zonal ice-mass face transport (kg/s), shape (nx_total+1, ny_total, ncat). SCRATCH, recomputed every pass. |
||
| real(kind=wp), | public, | allocatable | :: | uh_snow(:,:,:) |
Per-category zonal snow-mass face transport (kg/s), shape (nx_total+1, ny_total, ncat). SCRATCH. |
||
| real(kind=wp), | public, | allocatable | :: | uhtot_work(:,:) |
Category-SUMMED zonal face transport (kg/s), shape (nx_total+1, ny_total). SCRATCH, reused per medium. |
||
| real(kind=wp), | public, | allocatable | :: | v_ice(:,:) |
Ice velocity at C-grid v-faces (m/s), shape (nx_total,
ny_total+1). Same interim/persistent contract as |
||
| real(kind=wp), | public, | allocatable | :: | vh_ice(:,:,:) |
Per-category meridional ice-mass face transport (kg/s), shape (nx_total, ny_total+1, ncat). SCRATCH. |
||
| real(kind=wp), | public, | allocatable | :: | vh_snow(:,:,:) |
Per-category meridional snow-mass face transport (kg/s), shape (nx_total, ny_total+1, ncat). SCRATCH. |
||
| real(kind=wp), | public, | allocatable | :: | vhtot_work(:,:) |
Category-SUMMED meridional face transport (kg/s), shape (nx_total, ny_total+1). SCRATCH, reused per medium. |
| procedure, public, non_overridable :: bytes => ocean_sea_ice_bytes | |
| procedure, public, non_overridable :: destroy => ocean_sea_ice_destroy | |
| procedure, public, non_overridable :: enter_data => ocean_sea_ice_enter_data | |
| procedure, public, non_overridable :: exit_data => ocean_sea_ice_exit_data | |
| procedure, public, non_overridable :: init => ocean_sea_ice_init |
Counted allocatable footprint of the EVP scratch (0 when
unallocated, i.e. whenever &ocean_ice_nml dynamics is off).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(evp_workspace_t), | intent(in) | :: | this |
Counted allocatable footprint of the sea-ice slot (one
arr_bytes term per array, mirroring ocean_meke_bytes).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_sea_ice_t), | intent(in) | :: | this |
Two-mode per-cell concentration/mass gather (module docstring
convention), shared by rdb_ice_evp (ice_evp_step) and
rdb_ice_ocean_coupler (ice_ocean_stress_flux) so neither
module depends on the other.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | wet_T(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | part_size(nx,ny,0:ncat) | |||
| real(kind=wp), | intent(in) | :: | m_ice(nx,ny,ncat) | |||
| real(kind=wp), | intent(in) | :: | m_snow(nx,ny,ncat) | |||
| real(kind=wp), | intent(out) | :: | mis(nx,ny) | |||
| real(kind=wp), | intent(out) | :: | mice(nx,ny) | |||
| real(kind=wp), | intent(out) | :: | ci(nx,ny) | |||
| integer, | intent(in) | :: | ncat | |||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny |
SIS2 initialize_ice_categories
(SIS_state_initialization.F90:45-78): absent hlim_vals fills
the first min(ncat+1, 8) entries from the default
lower-thickness-limit table HLIM_DFLT_TABLE; a supplied
hlim_vals fills the first min(ncat+1, size(hlim_vals))
entries from IT instead (PR-58 — the SIS2 hLim_vals optional
dummy Roundabout’s port originally declined to carry). Either way,
the remainder extrapolates by constant width,
h_lim(k) = 2*h_lim(k-1) - h_lim(k-2), resuming at ONE PAST
however many entries were actually supplied — not at a fixed
index 9. mh_lim = ICE_RHO_ICE*h_lim (SIS2 mH_cat_bound,
SIS_state_initialization.F90:75-77). h_lim(c)/mh_lim(c) is
the LOWER bound of category c (1-based); index ncat+1 is the
lower bound that WOULD start category ncat+1 — stored (SIS2
keeps it) but never used as an upper cap on category ncat
(ice_adjust_categories’s upward pass stops at c = ncat-1).
No fixed-size local arrays — ncat is unbounded here (unlike
the per-column ICE_NK_MAX-capped layer arrays).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | ncat |
Number of ice thickness categories (declared first — decl-order). |
||
| real(kind=wp), | intent(out) | :: | h_lim(ncat+1) |
Category lower thickness limits (m), |
||
| real(kind=wp), | intent(out) | :: | mh_lim(ncat+1) |
Category lower mass limits (kg/m²), |
||
| real(kind=wp), | intent(in), | optional | :: | hlim_vals(:) |
entries, strictly increasing, |
Reverse of init (host deallocation). Idempotent — safe on an
already-clean workspace. Device unmapping is exit_data’s job
(call it first).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(evp_workspace_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(evp_workspace_t), | intent(inout) | :: | this |
Attach the scratch to the device with create — every array is
pure scratch, fully (re)written before it is read on every
ice_evp_dynamics call (masks rebuilt, cell fields filled, the
subcycle kernels overwrite the rest), so create (not copyin)
is correct. One-level components of the type(...) dummy — same
shape as ocean_sea_ice_enter_data_impl, no associate-leaf needed.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(evp_workspace_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(evp_workspace_t), | intent(inout) | :: | this |
Reverse of enter_data_impl — pure scratch, delete throughout.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(evp_workspace_t), | intent(inout) | :: | this |
Allocate the EVP scratch for an (nx,ny) T-cell domain, zero-init.
Called ONCE per workspace lifetime — from ocean_sea_ice_init
(gated on dynamics) and from the EVP test harness. nx/ny
declared before the arrays that use them is unnecessary here (all
allocatables), but the extents are cached for destroy.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(evp_workspace_t), | intent(inout) | :: | this | |||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny |
Reverse of init. Clears is_init first (use-after-destroy
guard), then releases allocations.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_sea_ice_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_sea_ice_t), | intent(inout) | :: | this |
Attach the slot’s allocatables to the device. copyin (not
create) throughout: every array is host-initialised (0, or
part_size/sal_ice’s non-zero defaults) at init, and a
restart read seeds the persistent ones host-side before the
mapping. PR 3c’s seam + scratch fields are also copyin: they
are host-zeroed at init and (re)filled device-side every thermo
step, so a plain copyin is correct (and cheap — one-time).
PR 4b: u_ice/v_ice are copyin (host-zeroed at init, and the
v1 sampler / PR-5 EVP both WRITE them device-side every call —
copyin establishes presence, same contract as the atm_* seam).
PR 5: str_d/str_t/str_s are copyin (host-zeroed at init or
restart-seeded; ice_evp_dynamics reads them before the first
write on every call — limit_stresses runs first). tau_a_x/
tau_a_y are copyin (host-snapshotted at configure, then read
device-side every substep — never written on-device). fxoc/
fyoc are copyin (host-zeroed at init or restart-seeded; the
EVP core zeros them itself at call entry before accumulating).
PR 63: tau_ocn_x/tau_ocn_y are copyin (host-zeroed at init
or restart-seeded; ice_tau_mirror_impl WRITES them device-side
every call to ice_ocean_stress_flux — same reasoning as
fxoc/fyoc). tau_ocn_valid is NEVER mapped — it is host-only
scalar state, set on the host by ice_ocean_stress_flux and read
on the host by ice_ocean_stress_resume_apply; register_scalar
forces device_mapped=.false. on the restart side for the same
reason.
The transport workspace is create (pure scratch, recomputed
from scratch every pass — never read before written), mapped
only if (this%transport) (memory Rule 2, same gate as the
host-side allocation).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_sea_ice_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_sea_ice_t), | intent(inout) | :: | this |
Reverse of enter_data_impl — all six PR-3a fields are
prognostic state (post-run host inspection + restart write),
same as the persistent frazil bank; the drain-and-zero budget
scratch is dropped. PR 3b’s m_frozen_diag/salt_flux_diag
are both PERSISTENT (restart-carried) — copyout, not delete.
PR 3c: heat_flux_diag/m_melt_diag are likewise PERSISTENT
(copyout); PR 31’s sw_thru_diag is PERSISTENT too (copyout,
restart-carried — NOT its per-category parent sw_thru, which
stays delete); the atm_* seam, fb/sst_seam/ssurf_seam/
tfw_seam, and the per-category column scratch
(tsurf_out/h2o_ocn_to_ice/h2o_ice_to_ocn/heat_to_ocn/
sw_thru) are all recomputed every thermo step — delete. PR 4a:
h_lim/mh_lim are delete (recomputed from ncat at init,
never mutated after); fb_part_sum is delete (recomputed every
thermo step, same lifecycle as the other scratch seams). PR 4b:
u_ice/v_ice are copyout (post-run host inspection, same
contract as the melt/frazil diags); the transport workspace is
delete (pure scratch), gated the same if (this%transport) as
the enter_data map. PR 5: str_d/str_t/str_s/fxoc/fyoc
are copyout (PERSISTENT, restart-carried); tau_a_x/tau_a_y
are delete (configure-time snapshot, not restart-carried —
rebuilt fresh on every run). PR 26: atm_fprec is delete
(same lifecycle as the rest of the atm_* seam); fprec_ocn_diag/
snow_part_ocn are delete (SCRATCH, recomputed every thermo
step, same lifecycle as fb_part_sum). PR 63: tau_ocn_x/tau_ocn_y
are copyout — PERSISTENT, restart-carried, and the restart write
reads the host copy (opposite lifecycle to tau_a_x/tau_a_y,
do not copy that pattern). tau_ocn_valid is never mapped, so
there is nothing to unmap.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_sea_ice_t), | intent(inout) | :: | this |
Cache the grid extents, allocate the frazil (PR 1) + Winton
column (PR 3a) prognostics, and mark the slot live. Allocation
is gated on enable at the parent call site (memory Rule 2),
so an ice-off run never carries these arrays.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_sea_ice_t), | intent(inout) | :: | this | |||
| type(hgrid_t), | intent(in) | :: | grid |