diff --git a/compass/landice/tests/ismip7_forcing/fracture/process_excess_melt.py b/compass/landice/tests/ismip7_forcing/fracture/process_excess_melt.py
index bc55cebc99..0f291792f0 100644
--- a/compass/landice/tests/ismip7_forcing/fracture/process_excess_melt.py
+++ b/compass/landice/tests/ismip7_forcing/fracture/process_excess_melt.py
@@ -145,8 +145,8 @@ def run(self):
os.remove(f)
# Place output in the appropriate directory
- output_path = os.path.join(output_base_path, "excess_melt",
- f"{model}_{scenario}")
+ output_path = os.path.join(output_base_path, f"{model}_{scenario}",
+ "excess_melt")
if not os.path.exists(output_path):
os.makedirs(output_path)
diff --git a/compass/landice/tests/ismip7_forcing/fracture/process_lake_properties.py b/compass/landice/tests/ismip7_forcing/fracture/process_lake_properties.py
index d9b3838a14..2b5d5ac1d5 100644
--- a/compass/landice/tests/ismip7_forcing/fracture/process_lake_properties.py
+++ b/compass/landice/tests/ismip7_forcing/fracture/process_lake_properties.py
@@ -147,8 +147,8 @@ def run(self):
os.remove(f)
# Place output in the appropriate directory
- output_path = os.path.join(output_base_path, "lake_properties",
- f"{model}_{scenario}")
+ output_path = os.path.join(output_base_path, f"{model}_{scenario}",
+ "lake_properties")
if not os.path.exists(output_path):
os.makedirs(output_path)
diff --git a/compass/landice/tests/ismip7_forcing/fracture/process_shelf_collapse.py b/compass/landice/tests/ismip7_forcing/fracture/process_shelf_collapse.py
index 6bf71fd40c..bf6537438e 100644
--- a/compass/landice/tests/ismip7_forcing/fracture/process_shelf_collapse.py
+++ b/compass/landice/tests/ismip7_forcing/fracture/process_shelf_collapse.py
@@ -125,8 +125,8 @@ def run(self):
os.remove(remapped_file)
# Place output in the appropriate directory
- output_path = os.path.join(output_base_path, "shelf_collapse",
- f"{model}_{scenario}")
+ output_path = os.path.join(output_base_path, f"{model}_{scenario}",
+ "shelf_collapse")
if not os.path.exists(output_path):
os.makedirs(output_path)
diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/__init__.py b/compass/landice/tests/ismip7_run/ismip7_ais/__init__.py
index c6e3a41c94..7e234b6a5c 100644
--- a/compass/landice/tests/ismip7_run/ismip7_ais/__init__.py
+++ b/compass/landice/tests/ismip7_run/ismip7_ais/__init__.py
@@ -12,12 +12,12 @@
EXPERIMENTS = {
'historical_CESM2-WACCM': {
'scenario': 'historical', 'model': 'CESM2-WACCM',
- 'start_time': '2000-01-01_00:00:00',
+ 'start_time': '2008-01-01_00:00:00',
'stop_time': '2015-01-01_00:00:00',
'is_historical': True},
'historical_MRI-ESM2-0': {
'scenario': 'historical', 'model': 'MRI-ESM2-0',
- 'start_time': '2000-01-01_00:00:00',
+ 'start_time': '2008-01-01_00:00:00',
'stop_time': '2015-01-01_00:00:00',
'is_historical': True},
'ssp370_CESM2-WACCM': {
@@ -62,7 +62,7 @@
'is_historical': False},
'ocx': {
'scenario': 'ocx', 'model': None,
- 'start_time': '1990-01-01_00:00:00',
+ 'start_time': '2008-01-01_00:00:00',
'stop_time': '2026-01-01_00:00:00',
'is_historical': True},
}
diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais.cfg b/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais.cfg
index 745e4c89f7..bfada238b8 100644
--- a/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais.cfg
+++ b/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais.cfg
@@ -59,6 +59,18 @@ calving_method = restore
# Only required if calving_method is set to 'von_mises'.
von_mises_parameter_path = NotAvailable
+# Whether to apply the ISMIP7 Path C ice shelf collapse mask (from
+# ismip7_forcing fracture) as hydrofracture-gated mask calving. Expected
+# layout: {forcing_basepath}/{model}_{scenario}/shelf_collapse/*.nc
+# Not used for historical, ctrl, or ocx experiments. If true and the mask
+# file is missing for an experiment that should have one, setup fails.
+use_hydrofracture_forcing = true
+
+# Ice fracture toughness (K_IC, Pa m^0.5) used in the hydrofracture
+# vulnerability criterion gating mask calving. Only used when
+# use_hydrofracture_forcing is true.
+calving_fracture_toughness = 2.0e5
+
# True if running coupled MALI-sea level model simulation
sea_level_model = false
diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice b/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice
index 165f9611f6..f505ef541f 100644
--- a/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice
+++ b/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice
@@ -1,4 +1,5 @@
config_velocity_solver = 'FO'
+ config_fem_extension_method = 'ismip7-era'
config_do_velocity_reconstruction_for_external_dycore = .false.
config_unrealistic_velocity = 00.00159
config_nonconvergence_error = .false.
diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/set_up_experiment.py b/compass/landice/tests/ismip7_run/ismip7_ais/set_up_experiment.py
index 98d59d4c40..7545ba7448 100644
--- a/compass/landice/tests/ismip7_run/ismip7_ais/set_up_experiment.py
+++ b/compass/landice/tests/ismip7_run/ismip7_ais/set_up_experiment.py
@@ -63,6 +63,10 @@ def setup(self): # noqa: C901
reference_surface_path = section.get('reference_surface_path')
reference_surface_fname = os.path.split(reference_surface_path)[-1]
calving_method = section.get('calving_method')
+ use_hydrofracture_forcing = section.getboolean(
+ 'use_hydrofracture_forcing')
+ calving_fracture_toughness = section.get(
+ 'calving_fracture_toughness')
sea_level_model = section.getboolean('sea_level_model')
exp_info = self.exp_info
@@ -229,6 +233,27 @@ def setup(self): # noqa: C901
sys.exit(f"ERROR: Expected 1 TF file at {tf_search}, "
f"found {len(tf_list)}: {tf_list}")
+ # --- Find shelf collapse (calving) mask from ismip7_forcing
+ # fracture Path C, if requested ---
+ # historical, ctrl, and ocx experiments never use hydrofracture
+ # forcing, regardless of use_hydrofracture_forcing.
+ useCalvingMask = False
+ if (use_hydrofracture_forcing and
+ scenario not in ('historical', 'ctrl', 'ocx')):
+ mask_search = os.path.join(forcing_dir, 'shelf_collapse',
+ '*ice_shelf_collapse_mask_*.nc')
+ mask_list = glob.glob(mask_search)
+ if len(mask_list) == 1:
+ mask_fname = os.path.split(mask_list[0])[-1]
+ os.symlink(mask_list[0],
+ os.path.join(self.work_dir, mask_fname))
+ useCalvingMask = True
+ else:
+ sys.exit(
+ f"ERROR: use_hydrofracture_forcing is True but did not "
+ f"find exactly 1 shelf collapse mask file at "
+ f"{mask_search}: {mask_list}")
+
# --- Set up streams ---
# Determine forcing interval
if scenario == 'ctrl':
@@ -266,6 +291,14 @@ def setup(self): # noqa: C901
out_name='streams.landice',
template_replacements=stream_replacements)
+ if useCalvingMask:
+ mask_stream_replacements = {
+ 'input_file_calving_mask_forcing_name': mask_fname}
+ self.add_streams_file(
+ resource_location, 'streams.mask_calving',
+ out_name='streams.landice',
+ template_replacements=mask_stream_replacements)
+
# --- Set up namelist ---
self.add_namelist_file(
resource_location, 'namelist.landice',
@@ -307,6 +340,19 @@ def setup(self): # noqa: C901
out_name='streams.landice',
template_replacements=vM_stream_replacements)
+ # Mask calving options (ismip7_forcing fracture Path C), gated by
+ # hydrofracture vulnerability (MALI PR #187)
+ if useCalvingMask:
+ options = {
+ 'config_apply_calving_mask': ".true.",
+ 'config_restore_calving_front': ".false.",
+ 'config_require_extensional_stresses_for_mask_calving':
+ ".true.",
+ 'config_calving_fracture_toughness':
+ f'{calving_fracture_toughness}'}
+ self.add_namelist_options(options=options,
+ out_name='namelist.landice')
+
# Sea-level model options
if sea_level_model:
slm_input_ice = section.get('slm_input_ice')
diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template b/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template
index 5465926fb8..03de43b3db 100644
--- a/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template
+++ b/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template
@@ -108,7 +108,7 @@
filename_template="output/output_2d_$Y.nc"
type="output">
-
+
@@ -128,6 +128,8 @@
+
+
diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/streams.mask_calving b/compass/landice/tests/ismip7_run/ismip7_ais/streams.mask_calving
new file mode 100644
index 0000000000..c885b4da76
--- /dev/null
+++ b/compass/landice/tests/ismip7_run/ismip7_ais/streams.mask_calving
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py b/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py
index ab883d15e2..44af20c9df 100644
--- a/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py
+++ b/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py
@@ -59,7 +59,7 @@
'is_historical': False},
'ocx': {
'scenario': 'ocx', 'model': None,
- 'start_time': '1990-01-01_00:00:00',
+ 'start_time': '2007-01-01_00:00:00',
'stop_time': '2026-01-01_00:00:00',
'is_historical': True},
}
diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice b/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice
index d29250f7b6..c00c9a5d18 100644
--- a/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice
+++ b/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice
@@ -1,4 +1,5 @@
config_velocity_solver = 'FO'
+ config_fem_extension_method = 'ismip7-era'
config_do_velocity_reconstruction_for_external_dycore = .false.
config_unrealistic_velocity = 00.00159
config_nonconvergence_error = .false.
diff --git a/docs/developers_guide/landice/test_groups/ismip7_run.rst b/docs/developers_guide/landice/test_groups/ismip7_run.rst
index 46b1c81541..edbab77740 100644
--- a/docs/developers_guide/landice/test_groups/ismip7_run.rst
+++ b/docs/developers_guide/landice/test_groups/ismip7_run.rst
@@ -75,16 +75,27 @@ The ``setup`` method sets up the experiment directory by:
and restart frequency.
5. Adding calving-specific streams (face melting, von Mises params) if
configured.
-6. Creating a restart symlink for projection experiments pointing to
+6. If ``use_hydrofracture_forcing`` is true and the experiment's scenario
+ is not ``historical``, ``ctrl``, or ``ocx``, looking for a single Path C
+ ``ice_shelf_collapse_mask_*.nc`` file under
+ ``{forcing_basepath}/{model}_{scenario}/shelf_collapse/`` (from
+ :ref:`landice_ismip7_forcing_fracture`). If found, it is symlinked in,
+ the ``streams.mask_calving`` stream is added, and
+ ``config_apply_calving_mask``, ``config_restore_calving_front``,
+ ``config_require_extensional_stresses_for_mask_calving``, and
+ ``config_calving_fracture_toughness`` are set accordingly. If not
+ found, setup fails with an error, since the mask is required whenever
+ ``use_hydrofracture_forcing`` is true for that scenario.
+7. Creating a restart symlink for projection experiments pointing to
the corresponding ESM's historical restart
(``../historical_{model}/rst.2015-01-01.nc``).
-7. Setting up CTRL2015 experiments with constant-climate forcing
+8. Setting up CTRL2015 experiments with constant-climate forcing
(``initial_only`` intervals).
-8. Setting up the OCX experiment with reanalysis-based forcing.
-9. If SLM coupling is enabled, adding a ``CreateSlmMappingFiles`` step
- and writing the SLM namelist from the Jinja2 template.
-10. Generating a ``graph.info`` file and a SLURM job script.
-11. Symlinking the compass load script into the run directory.
+9. Setting up the OCX experiment with reanalysis-based forcing.
+10. If SLM coupling is enabled, adding a ``CreateSlmMappingFiles`` step
+ and writing the SLM namelist from the Jinja2 template.
+11. Generating a ``graph.info`` file and a SLURM job script.
+12. Symlinking the compass load script into the run directory.
The ``run`` method executes MALI for the given experiment.
diff --git a/docs/users_guide/landice/test_groups/ismip7_forcing.rst b/docs/users_guide/landice/test_groups/ismip7_forcing.rst
index 417e3552c0..4a5ca9ea82 100644
--- a/docs/users_guide/landice/test_groups/ismip7_forcing.rst
+++ b/docs/users_guide/landice/test_groups/ismip7_forcing.rst
@@ -91,6 +91,9 @@ Processed forcing is written under ``output_base_path`` in a layout that the
{output_base_path}/{group}/atmosphere/{mesh}_temperature_{source}_{scenario}_{years}.nc
{output_base_path}/{group}/atmosphere/{mesh}_runoff_... (and the two gradients)
{output_base_path}/{group}/ocean_thermal_forcing/{mesh}_thermal_forcing_{source}_{scenario}_{years}.nc
+ {output_base_path}/{group}/shelf_collapse/{mesh}_ice_shelf_collapse_mask_*.nc
+ {output_base_path}/{group}/excess_melt/{mesh}_excess_melt_*.nc
+ {output_base_path}/{group}/lake_properties/{mesh}_lake_properties_*.nc
The ``group`` directory is ``{model}_{scenario}`` for ESM scenarios and ``OCX``
for GrIS OCX. AIS OCX writes one group per selected ocean product,
@@ -365,7 +368,7 @@ is useful when only some of the pathway source files are available.
(melt + rain after firn air content depletion), matching
``excess_melt_*.nc``. The output variable is ``ismip7ExcessMelt``
(converted from mm w.e. yr-1 to SI units of kg m-2 s-1) and is written to
- ``{output_base_path}/excess_melt/{model}_{scenario}/``. Conservative
+ ``{output_base_path}/{model}_{scenario}/excess_melt/``. Conservative
remapping is used by default since this is a flux. This source file has no
``x``/``y`` coordinate variables and its array is flipped along the y axis
relative to the other fracture files, so the step reconstructs the source
@@ -376,7 +379,7 @@ is useful when only some of the pathway source files are available.
depth and area fraction from the Grau et al. (2025) parameterization,
matching ``lake_properties_*.nc``. The output variables are
``ismip7LakeDepth`` (m) and ``ismip7LakeAreaFraction`` (unitless), written
- to ``{output_base_path}/lake_properties/{model}_{scenario}/``. Bilinear
+ to ``{output_base_path}/{model}_{scenario}/lake_properties/``. Bilinear
remapping is used by default.
* **process_shelf_collapse** (Path C): Remaps the annual ice shelf collapse
@@ -389,7 +392,7 @@ is useful when only some of the pathway source files are available.
that the 0/1 mask values are preserved, and the remapped mask is rounded to
0/1. The output variable is ``calvingMask`` with an accompanying ``xtime``
variable, and the result is written to
- ``{output_base_path}/shelf_collapse/{model}_{scenario}/``.
+ ``{output_base_path}/{model}_{scenario}/shelf_collapse/``.
All three pathways produce continuous fields (Paths A and B) or a discrete
mask (Path C) with an accompanying ``xtime`` variable. The output variable
diff --git a/docs/users_guide/landice/test_groups/ismip7_run.rst b/docs/users_guide/landice/test_groups/ismip7_run.rst
index 1d418eb849..97501104d7 100644
--- a/docs/users_guide/landice/test_groups/ismip7_run.rst
+++ b/docs/users_guide/landice/test_groups/ismip7_run.rst
@@ -113,13 +113,21 @@ Usage
├── CESM2-WACCM_historical/
│ ├── atmosphere/
│ │ └── {mesh}_smb_CESM2-WACCM_historical_*.nc
- │ └── ocean_thermal_forcing/
- │ └── {mesh}_thermal_forcing_CESM2-WACCM_historical_*.nc
+ │ ├── ocean_thermal_forcing/
+ │ │ └── {mesh}_thermal_forcing_CESM2-WACCM_historical_*.nc
+ │ └── shelf_collapse/
+ │ └── {mesh}_ice_shelf_collapse_mask_*.nc
├── CESM2-WACCM_ssp585/
│ ├── atmosphere/
- │ └── ocean_thermal_forcing/
+ │ ├── ocean_thermal_forcing/
+ │ └── shelf_collapse/
└── ...
+ The ``shelf_collapse`` subdirectory (ISMIP7 Path C ice shelf collapse
+ mask, produced by :ref:`landice_ismip7_forcing_fracture`) is required
+ for ``ssp*`` experiments unless ``use_hydrofracture_forcing`` is set to
+ ``false``; see :ref:`landice_ismip7_run_mask_calving` below.
+
3. Create a user config file overriding the ``NotAvailable`` paths.
4. Set up and run::
@@ -168,6 +176,17 @@ All config options should be reviewed and altered as needed.
calving_method = restore
von_mises_parameter_path = NotAvailable
+ # Whether to apply the ISMIP7 Path C ice shelf collapse mask as
+ # hydrofracture-gated mask calving (not used for historical, ctrl, or
+ # ocx experiments). If true, setup fails when the mask file is missing
+ # for an experiment that should have one.
+ use_hydrofracture_forcing = true
+
+ # Ice fracture toughness (Pa m^0.5) for the hydrofracture vulnerability
+ # criterion gating mask calving, used only when use_hydrofracture_forcing
+ # is true.
+ calving_fracture_toughness = 2.0e5
+
# Face melting
use_face_melting = false
@@ -211,6 +230,37 @@ ISMIP7 uses more forcing fields than ISMIP6, at mixed temporal resolutions:
For CTRL2015 experiments, all forcing intervals are set to
``initial_only`` (constant climate).
+.. _landice_ismip7_run_mask_calving:
+
+Mask Calving (Path C)
+----------------------
+
+``ismip7_ais`` can optionally apply the ISMIP7 Path C ice shelf collapse
+mask produced by :ref:`landice_ismip7_forcing_fracture`. The mask is looked
+up under the same ``forcing_basepath`` used for the atmosphere/ocean
+forcing, at
+``{forcing_basepath}/{model}_{scenario}/shelf_collapse/*ice_shelf_collapse_mask_*.nc``.
+``historical``, ``ctrl``, and ``ocx`` experiments never use this pathway,
+regardless of ``use_hydrofracture_forcing``.
+
+When ``use_hydrofracture_forcing`` is ``true`` (the default) for any other
+experiment (e.g. ``ssp126``, ``ssp370``, ``ssp585``), a matching mask file
+is required: if it is missing, ``compass setup`` fails with an error rather
+than silently skipping mask calving. When found, the mask is symlinked into
+the run directory and used to force calving:
+
+* ``config_apply_calving_mask`` is set to ``.true.``
+* ``config_restore_calving_front`` is set to ``.false.``
+* ``config_require_extensional_stresses_for_mask_calving`` is set to
+ ``.true.``, so the mask only removes floating ice that is also vulnerable
+ to hydrofracture per the fracture-toughness criterion of Lai et al.
+ (2020) / Reynolds and Nowicki (2026). The threshold depends on
+ ``config_calving_fracture_toughness``.
+
+Set ``use_hydrofracture_forcing = false`` to disable mask calving and the
+hydrofracture gating entirely; experiments then use their normal
+``calving_method`` configuration instead.
+
.. _landice_ismip7_run_ais:
ismip7_ais