From 90ecb5928e51b477ec81d66a72220d5d3c149d6e Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Tue, 9 Jun 2026 12:18:25 -0700 Subject: [PATCH 01/24] Create ismip7_run test group Create test group to control both AIS and GIS simulations for ISMIP7. --- compass/landice/__init__.py | 2 + compass/landice/tests/ismip7_run/__init__.py | 19 + .../tests/ismip7_run/ismip7_ais/__init__.py | 157 +++++++ .../ismip7_run/ismip7_ais/albany_input.yaml | 239 +++++++++++ .../ismip7_ais/create_slm_mapping_files.py | 100 +++++ .../ismip7_run/ismip7_ais/ismip7_ais.cfg | 79 ++++ .../ismip7_run/ismip7_ais/namelist.landice | 82 ++++ .../ismip7_ais/namelist.sealevel.template | 68 +++ .../ismip7_ais/set_up_experiment.py | 389 ++++++++++++++++++ .../ismip7_run/ismip7_ais/streams.faceMelting | 34 ++ .../ismip7_ais/streams.landice.template | 198 +++++++++ .../ismip7_run/ismip7_ais/streams.vM_params | 13 + .../tests/ismip7_run/ismip7_gris/__init__.py | 134 ++++++ .../ismip7_run/ismip7_gris/albany_input.yaml | 239 +++++++++++ .../ismip7_run/ismip7_gris/ismip7_gris.cfg | 46 +++ .../ismip7_run/ismip7_gris/namelist.landice | 79 ++++ .../ismip7_gris/set_up_experiment.py | 304 ++++++++++++++ .../ismip7_gris/streams.landice.template | 197 +++++++++ .../ismip7_run/ismip7_gris/streams.vM_params | 13 + .../landice/test_groups/index.rst | 1 + .../landice/test_groups/ismip7_run.rst | 116 ++++++ .../users_guide/landice/test_groups/index.rst | 1 + .../landice/test_groups/ismip7_run.rst | 228 ++++++++++ 23 files changed, 2738 insertions(+) create mode 100644 compass/landice/tests/ismip7_run/__init__.py create mode 100644 compass/landice/tests/ismip7_run/ismip7_ais/__init__.py create mode 100644 compass/landice/tests/ismip7_run/ismip7_ais/albany_input.yaml create mode 100644 compass/landice/tests/ismip7_run/ismip7_ais/create_slm_mapping_files.py create mode 100644 compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais.cfg create mode 100644 compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice create mode 100644 compass/landice/tests/ismip7_run/ismip7_ais/namelist.sealevel.template create mode 100644 compass/landice/tests/ismip7_run/ismip7_ais/set_up_experiment.py create mode 100644 compass/landice/tests/ismip7_run/ismip7_ais/streams.faceMelting create mode 100644 compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template create mode 100644 compass/landice/tests/ismip7_run/ismip7_ais/streams.vM_params create mode 100644 compass/landice/tests/ismip7_run/ismip7_gris/__init__.py create mode 100644 compass/landice/tests/ismip7_run/ismip7_gris/albany_input.yaml create mode 100644 compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris.cfg create mode 100644 compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice create mode 100644 compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py create mode 100644 compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template create mode 100644 compass/landice/tests/ismip7_run/ismip7_gris/streams.vM_params create mode 100644 docs/developers_guide/landice/test_groups/ismip7_run.rst create mode 100644 docs/users_guide/landice/test_groups/ismip7_run.rst diff --git a/compass/landice/__init__.py b/compass/landice/__init__.py index 6fec487fd7..aafe35fdd6 100644 --- a/compass/landice/__init__.py +++ b/compass/landice/__init__.py @@ -12,6 +12,7 @@ from compass.landice.tests.ismip6_forcing import Ismip6Forcing from compass.landice.tests.ismip6_run import Ismip6Run from compass.landice.tests.ismip7_forcing import Ismip7Forcing +from compass.landice.tests.ismip7_run import Ismip7Run from compass.landice.tests.isunnguata_sermia import IsunnguataSermia from compass.landice.tests.kangerlussuaq import Kangerlussuaq from compass.landice.tests.koge_bugt_s import KogeBugtS @@ -48,6 +49,7 @@ def __init__(self): self.add_test_group(Ismip6Forcing(mpas_core=self)) self.add_test_group(Ismip6Run(mpas_core=self)) self.add_test_group(Ismip7Forcing(mpas_core=self)) + self.add_test_group(Ismip7Run(mpas_core=self)) self.add_test_group(IsunnguataSermia(mpas_core=self)) self.add_test_group(Kangerlussuaq(mpas_core=self)) self.add_test_group(KogeBugtS(mpas_core=self)) diff --git a/compass/landice/tests/ismip7_run/__init__.py b/compass/landice/tests/ismip7_run/__init__.py new file mode 100644 index 0000000000..64eb375d00 --- /dev/null +++ b/compass/landice/tests/ismip7_run/__init__.py @@ -0,0 +1,19 @@ +from compass.landice.tests.ismip7_run.ismip7_ais import Ismip7Ais +from compass.landice.tests.ismip7_run.ismip7_gris import Ismip7Gris +from compass.testgroup import TestGroup + + +class Ismip7Run(TestGroup): + """ + A test group for automated setup of a suite of standardized + ISMIP7 simulations for both AIS and GrIS. + """ + def __init__(self, mpas_core): + """ + mpas_core : compass.landice.Landice + the MPAS core that this test group belongs to + """ + super().__init__(mpas_core=mpas_core, name='ismip7_run') + + self.add_test_case(Ismip7Ais(test_group=self)) + self.add_test_case(Ismip7Gris(test_group=self)) diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/__init__.py b/compass/landice/tests/ismip7_run/ismip7_ais/__init__.py new file mode 100644 index 0000000000..ba229244fe --- /dev/null +++ b/compass/landice/tests/ismip7_run/ismip7_ais/__init__.py @@ -0,0 +1,157 @@ +import os + +from compass.landice.tests.ismip7_run.ismip7_ais.create_slm_mapping_files import ( # noqa + CreateSlmMappingFiles, +) +from compass.landice.tests.ismip7_run.ismip7_ais.set_up_experiment import ( + SetUpExperiment, +) +from compass.testcase import TestCase + +# Define the full experiment matrix per the ISMIP7 protocol +EXPERIMENTS = { + 'historical_CESM2-WACCM': { + 'scenario': 'historical', 'model': 'CESM2-WACCM', + 'start_time': '1850-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': '1850-01-01_00:00:00', + 'stop_time': '2015-01-01_00:00:00', + 'is_historical': True}, + 'ssp370_CESM2-WACCM': { + 'scenario': 'ssp370', 'model': 'CESM2-WACCM', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2101-01-01_00:00:00', + 'is_historical': False}, + 'ssp370_MRI-ESM2-0': { + 'scenario': 'ssp370', 'model': 'MRI-ESM2-0', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2101-01-01_00:00:00', + 'is_historical': False}, + 'ssp126_CESM2-WACCM': { + 'scenario': 'ssp126', 'model': 'CESM2-WACCM', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', + 'is_historical': False}, + 'ssp126_MRI-ESM2-0': { + 'scenario': 'ssp126', 'model': 'MRI-ESM2-0', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', + 'is_historical': False}, + 'ssp585_CESM2-WACCM': { + 'scenario': 'ssp585', 'model': 'CESM2-WACCM', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', + 'is_historical': False}, + 'ssp585_MRI-ESM2-0': { + 'scenario': 'ssp585', 'model': 'MRI-ESM2-0', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', + 'is_historical': False}, + 'ctrl_CESM2-WACCM': { + 'scenario': 'ctrl', 'model': 'CESM2-WACCM', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', + 'is_historical': False}, + 'ctrl_MRI-ESM2-0': { + 'scenario': 'ctrl', 'model': 'MRI-ESM2-0', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', + 'is_historical': False}, + 'ocx': { + 'scenario': 'ocx', 'model': None, + 'start_time': '1990-01-01_00:00:00', + 'stop_time': '2026-01-01_00:00:00', + 'is_historical': True}, +} + + +class Ismip7Ais(TestCase): + """ + A test case for automated setup of a suite of standardized + ISMIP7 simulations for the Antarctic Ice Sheet. + """ + + def __init__(self, test_group): + """ + Create the test case + + Parameters + ---------- + test_group : compass.landice.tests.ismip7_run.Ismip7Run + The test group that this test case belongs to + """ + name = 'ismip7_ais' + super().__init__(test_group=test_group, name=name, subdir=name) + + def configure(self): + """ + Set up the desired ISMIP7 AIS experiments. + + Read the experiment list from config and add a SetUpExperiment + step for each. + """ + config = self.config + exp_list_str = config.get('ismip7_run_ais', 'exp_list') + + if exp_list_str == 'all': + exp_list = list(EXPERIMENTS.keys()) + elif exp_list_str == 'historical': + exp_list = [k for k, v in EXPERIMENTS.items() + if v['is_historical']] + elif exp_list_str == 'projections': + exp_list = [k for k, v in EXPERIMENTS.items() + if not v['is_historical'] and + v['scenario'] != 'ctrl'] + elif exp_list_str == 'ctrl': + exp_list = [k for k, v in EXPERIMENTS.items() + if v['scenario'] == 'ctrl'] + else: + exp_list = [s.strip() for s in exp_list_str.split(',')] + + for exp in exp_list: + if exp not in EXPERIMENTS: + raise ValueError( + f"Unknown experiment '{exp}'. Valid experiments: " + f"{list(EXPERIMENTS.keys())}") + if os.path.exists(os.path.join(self.work_dir, exp)): + print(f"WARNING: {exp} path already exists; skipping. " + "Remove the directory " + f"{os.path.join(self.work_dir, exp)} and run " + "'compass setup' again to recreate.") + else: + self.add_step( + SetUpExperiment(test_case=self, name=exp, + subdir=exp, exp=exp, + exp_info=EXPERIMENTS[exp])) + + # Do not add experiments to steps_to_run; + # each experiment (step) should be submitted manually + self.steps_to_run = [] + + # Optionally set up sea-level model mapping files + sea_level_model = config.getboolean('ismip7_run_ais', + 'sea_level_model') + if sea_level_model: + subdir = 'mapping_files' + if os.path.exists(os.path.join(self.work_dir, subdir)): + print(f"WARNING: {subdir} path already exists; skipping.") + else: + self.add_step( + CreateSlmMappingFiles(test_case=self, + name='mapping_files', + subdir=subdir)) + self.steps_to_run.append('mapping_files') + + def run(self): + """ + A dummy run method + """ + raise ValueError( + "ERROR: 'compass run' has no functionality at the test case " + "level for this test. Please submit the job script in each " + "experiment's subdirectory manually instead. " + "To create Sea-Level Model mapping files, submit job script " + "or execute 'compass run' from the 'mapping_files' subdirectory.") diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/albany_input.yaml b/compass/landice/tests/ismip7_run/ismip7_ais/albany_input.yaml new file mode 100644 index 0000000000..e1a4dcd7c4 --- /dev/null +++ b/compass/landice/tests/ismip7_run/ismip7_ais/albany_input.yaml @@ -0,0 +1,239 @@ +%YAML 1.1 +--- +ANONYMOUS: + Problem: + LandIce Field Norm: + sliding_velocity_basalside: + Regularization Type: Given Value + Regularization Value: 1.0e-4 + LandIce BCs: + BC 0: + Basal Friction Coefficient: + Type: Power Law + Power Exponent: 0.2 + Mu Type: Field + Effective Pressure Type: Constant + Effective Pressure: 1.0 + # Zero Effective Pressure On Floating Ice At Nodes: true + Zero Beta On Floating Ice: true + + Cubature Degree: 8 + +# Discretization Description + Discretization: + #Exodus Output File Name: albany_output.exo + + Piro: +# Nonlinear Solver Information + NOX: + Nonlinear Solver: Line Search Based + Line Search: + Full Step: + Full Step: 1.0e+00 + Method: Backtrack + Solver Options: + Status Test Check Type: Minimal + Status Tests: + Test Type: Combo + Combo Type: OR + Number of Tests: 2 + Test 0: + Test Type: NormF + Norm Type: Two Norm + Scale Type: Scaled + Tolerance: 1.0e-05 + Test 1: + Test Type: MaxIters + Maximum Iterations: 50 + Printing: + Output Precision: 3 + Output Processor: 0 + Output Information: + Error: true + Warning: true + Outer Iteration: true + Parameters: false + Details: false + Linear Solver Details: false + Stepper Iteration: true + Stepper Details: true + Stepper Parameters: true + + Direction: + Method: Newton + Newton: + Forcing Term Method: Constant + Rescue Bad Newton Solve: true + Linear Solver: + Write Linear System: false + Tolerance: 1.0e-8 + + Stratimikos Linear Solver: + Stratimikos: + +# Linear Solver Information + Linear Solver Type: Belos + Linear Solver Types: + Belos: + Solver Type: Block GMRES + Solver Types: + Block GMRES: + Output Frequency: 20 + Output Style: 1 + Verbosity: 33 + Maximum Iterations: 200 + Block Size: 1 + Num Blocks: 200 + Flexible Gmres: false + VerboseObject: + Output File: none + Verbosity Level: low + +# Preconditioner Information + Preconditioner Type: MueLu + Preconditioner Types: + + Ifpack2: + Overlap: 1 + Prec Type: ILUT + + MueLu: + Matrix: + PDE equations: 2 + Factories: + myLineDetectionFact: + factory: LineDetectionFactory + 'linedetection: orientation': coordinates + mySemiCoarsenPFact1: + factory: SemiCoarsenPFactory + 'semicoarsen: coarsen rate': 14 + UncoupledAggregationFact2: + factory: UncoupledAggregationFactory + 'aggregation: ordering': graph + 'aggregation: max selected neighbors': 0 + 'aggregation: min agg size': 3 + 'aggregation: phase3 avoid singletons': true + MyCoarseMap2: + factory: CoarseMapFactory + Aggregates: UncoupledAggregationFact2 + myTentativePFact2: + 'tentative: calculate qr': true + factory: TentativePFactory + Aggregates: UncoupledAggregationFact2 + CoarseMap: MyCoarseMap2 + mySaPFact2: + 'sa: eigenvalue estimate num iterations': 10 + 'sa: damping factor': 1.33333e+00 + factory: SaPFactory + P: myTentativePFact2 + myTransferCoordinatesFact: + factory: CoordinatesTransferFactory + CoarseMap: MyCoarseMap2 + Aggregates: UncoupledAggregationFact2 + myTogglePFact: + factory: TogglePFactory + 'semicoarsen: number of levels': 2 + TransferFactories: + P1: mySemiCoarsenPFact1 + P2: mySaPFact2 + Ptent1: mySemiCoarsenPFact1 + Ptent2: myTentativePFact2 + Nullspace1: mySemiCoarsenPFact1 + Nullspace2: myTentativePFact2 + myRestrictorFact: + factory: TransPFactory + P: myTogglePFact + myToggleTransferCoordinatesFact: + factory: ToggleCoordinatesTransferFactory + Chosen P: myTogglePFact + TransferFactories: + Coordinates1: mySemiCoarsenPFact1 + Coordinates2: myTransferCoordinatesFact + myRAPFact: + factory: RAPFactory + P: myTogglePFact + R: myRestrictorFact + TransferFactories: + For Coordinates: myToggleTransferCoordinatesFact + myRepartitionHeuristicFact: + factory: RepartitionHeuristicFactory + A: myRAPFact + 'repartition: min rows per proc': 3000 + 'repartition: max imbalance': 1.327e+00 + 'repartition: start level': 1 + myZoltanInterface: + factory: ZoltanInterface + A: myRAPFact + Coordinates: myToggleTransferCoordinatesFact + number of partitions: myRepartitionHeuristicFact + myRepartitionFact: + factory: RepartitionFactory + A: myRAPFact + Partition: myZoltanInterface + 'repartition: remap parts': true + number of partitions: myRepartitionHeuristicFact + myRebalanceProlongatorFact: + factory: RebalanceTransferFactory + type: Interpolation + P: myTogglePFact + Coordinates: myToggleTransferCoordinatesFact + Nullspace: myTogglePFact + myRebalanceRestrictionFact: + factory: RebalanceTransferFactory + type: Restriction + R: myRestrictorFact + myRebalanceAFact: + factory: RebalanceAcFactory + A: myRAPFact + TransferFactories: { } + mySmoother1: + factory: TrilinosSmoother + type: LINESMOOTHING_BANDEDRELAXATION + 'smoother: pre or post': both + ParameterList: + 'relaxation: type': Gauss-Seidel + 'relaxation: sweeps': 1 + 'relaxation: damping factor': 1.0 + mySmoother3: + factory: TrilinosSmoother + type: RELAXATION + 'smoother: pre or post': both + ParameterList: + 'relaxation: type': Gauss-Seidel + 'relaxation: sweeps': 1 + 'relaxation: damping factor': 1.0 + mySmoother4: + factory: TrilinosSmoother + type: RELAXATION + 'smoother: pre or post': pre + ParameterList: + 'relaxation: type': Gauss-Seidel + 'relaxation: sweeps': 4 + 'relaxation: damping factor': 1.0 + Hierarchy: + max levels: 7 + 'coarse: max size': 2000 + verbosity: None + Finest: + Smoother: mySmoother1 + CoarseSolver: mySmoother4 + P: myRebalanceProlongatorFact + Nullspace: myRebalanceProlongatorFact + CoarseNumZLayers: myLineDetectionFact + LineDetection_Layers: myLineDetectionFact + LineDetection_VertLineIds: myLineDetectionFact + A: myRebalanceAFact + Coordinates: myRebalanceProlongatorFact + Importer: myRepartitionFact + All: + startLevel: 1 + Smoother: mySmoother4 + CoarseSolver: mySmoother4 + P: myRebalanceProlongatorFact + Nullspace: myRebalanceProlongatorFact + CoarseNumZLayers: myLineDetectionFact + LineDetection_Layers: myLineDetectionFact + LineDetection_VertLineIds: myLineDetectionFact + A: myRebalanceAFact + Coordinates: myRebalanceProlongatorFact + Importer: myRepartitionFact diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/create_slm_mapping_files.py b/compass/landice/tests/ismip7_run/ismip7_ais/create_slm_mapping_files.py new file mode 100644 index 0000000000..108ee7544c --- /dev/null +++ b/compass/landice/tests/ismip7_run/ismip7_ais/create_slm_mapping_files.py @@ -0,0 +1,100 @@ +import shutil + +from mpas_tools.logging import check_call +from mpas_tools.scrip.from_mpas import scrip_from_mpas + +from compass.step import Step + + +class CreateSlmMappingFiles(Step): + """ + A step for creating mapping files for the Sea Level Model + """ + + def __init__(self, test_case, name, subdir): + """ + Initialize step + """ + super().__init__(test_case=test_case, name=name, subdir=subdir) + + def setup(self): + print(" Setting up mapping_file subdirectory") + + def run(self): + """ + Run this step of the test case + """ + config = self.config + logger = self.logger + section = config['ismip7_run_ais'] + sea_level_model = section.getboolean('sea_level_model') + if sea_level_model: + self._build_mapping_files(config, logger) + + def _build_mapping_files(self, config, logger): + """ + Build mapping files between the MALI mesh and the SLM grid. + """ + section = config['ismip7_run_ais'] + init_cond_path = section.get('init_cond_path') + nglv = section.getint('nglv') + section = config['parallel'] + ntasks = section.getint('cores_per_node') + + mali_scripfile = 'mali_scripfile.nc' + slm_scripfile = f'slm_nglv{nglv}scripfile.nc' + mali_meshfile = 'mali_meshfile_sphereLatLon.nc' + + # SLM scripfile + logger.info(f'creating scripfile for the SLM grid with ' + f'{nglv} Gauss-Legendre points in latitude') + + args = ['ncremap', + '-g', slm_scripfile, + '-G', + f'latlon={nglv},{2 * int(nglv)}#lat_typ=gss#lat_drc=n2s'] + + check_call(args, logger=logger) + + # MALI scripfile + shutil.copy(init_cond_path, mali_meshfile) + args = ['set_lat_lon_fields_in_planar_grid', + '--file', mali_meshfile, + '--proj', 'ais-bedmap2-sphere'] + + check_call(args, logger=logger) + + logger.info('creating scrip file for the mali mesh') + scrip_from_mpas(mali_meshfile, mali_scripfile) + + # MALI -> SLM mapping file + logger.info('creating MALI -> SLM grid mapfile with conserve method') + + parallel_executable = config.get("parallel", "parallel_executable") + args = parallel_executable.split(' ') + args.extend(['-n', f'{ntasks}', + 'ESMF_RegridWeightGen', + '-s', mali_scripfile, + '-d', slm_scripfile, + '-w', 'mapfile_mali_to_slm.nc', + '-m', 'conserve', + '-i', '-64bit_offset', '--netcdf4', + '--src_regional']) + + check_call(args, logger) + + # SLM -> MALI mapping file + logger.info('creating SLM -> MALI mesh mapfile with bilinear method') + args = parallel_executable.split(' ') + args.extend(['-n', f'{ntasks}', + 'ESMF_RegridWeightGen', + '-s', slm_scripfile, + '-d', mali_scripfile, + '-w', 'mapfile_slm_to_mali.nc', + '-m', 'bilinear', + '-i', '-64bit_offset', '--netcdf4', + '--dst_regional']) + + check_call(args, logger) + + logger.info('mapping file creation complete') diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais.cfg b/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais.cfg new file mode 100644 index 0000000000..ab88bd0b80 --- /dev/null +++ b/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais.cfg @@ -0,0 +1,79 @@ +[ismip7_run_ais] + +# List of experiments to set up. +# Can be "all", "historical", "projections", "ctrl", or a +# comma-delimited list of experiment names. +# Valid experiment names: +# historical_CESM2-WACCM, historical_MRI-ESM2-0, +# ssp126_CESM2-WACCM, ssp126_MRI-ESM2-0, +# ssp370_CESM2-WACCM, ssp370_MRI-ESM2-0, +# ssp585_CESM2-WACCM, ssp585_MRI-ESM2-0, +# ctrl_CESM2-WACCM, ctrl_MRI-ESM2-0, +# ocx +exp_list = all + +# Number of tasks to use for each run +ntasks = 128 + +# Value to use for config_pio_stride. +# Should be divisible into ntasks +pio_stride = 128 + +# Base path to the pre-processed ISMIP7 forcing files. +# Expected layout: +# {forcing_basepath}/{model}_{scenario}/atmosphere/ +# {forcing_basepath}/{model}_{scenario}/ocean_thermal_forcing/ +# User has to supply. +forcing_basepath = NotAvailable + +# Path to the initial condition file. User has to supply. +init_cond_path = NotAvailable + +# Path to the file for the basal melt parametrization coefficients. +melt_params_path = NotAvailable + +# Path to the region mask file +region_mask_path = NotAvailable + +# Path to the ocean thermal forcing climatology file for CTRL2015 runs. +# This is the constant-climate 30-year mean (2000-2029) thermal forcing. +# User has to supply if running ctrl experiments. +ctrl_tf_climatology_path = NotAvailable + +# Path to the atmosphere climatology files for CTRL2015 runs. +# Directory containing constant-climate SMB, temperature, etc. +# User has to supply if running ctrl experiments. +ctrl_atm_climatology_path = NotAvailable + +# Path to OCX (observationally constrained experiment) forcing. +# User has to supply if running the ocx experiment. +ocx_forcing_path = NotAvailable + +# Calving method to use. Options: restore, von_mises +calving_method = restore + +# Path to the file containing the von Mises parameter fields. +# Only required if calving_method is set to 'von_mises'. +von_mises_parameter_path = NotAvailable + +# Whether face melting should be included in the runs +use_face_melting = false + +# True if running coupled MALI-sea level model simulation +sea_level_model = false + +# Path to the directory containing globally defined ice thickness +# field for the sea-level model +slm_input_ice = NotAvailable + +# Path to the directory containing earth model for the sea-level model +slm_input_earth = NotAvailable + +# Earth structure profile filename +slm_earth_structure = prem_512.l60K2C.sum18p6.dum19p2.tz19p4.lm22 + +# Path to the directory containing other SLM input files +slm_input_others = NotAvailable + +# Number of gauss-legendre nodes in latitude (typically multiple of 512) +nglv = 2048 diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice b/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice new file mode 100644 index 0000000000..ceaf39f281 --- /dev/null +++ b/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice @@ -0,0 +1,82 @@ + config_velocity_solver = 'FO' + config_do_velocity_reconstruction_for_external_dycore = .false. + config_unrealistic_velocity = 00.00159 + config_nonconvergence_error = .false. + + config_thickness_advection = 'fo' + config_tracer_advection = 'fo' + config_zero_sfcMassBalApplied_over_bare_land = .true. + + config_uplift_method = 'none' + config_slm_coupling_interval = 5 + config_MALI_to_SLM_weights_file = 'mapfile_mali_to_slm.nc' + config_SLM_to_MALI_weights_file = 'mapfile_slm_to_mali.nc' + + config_calving = 'none' + config_apply_calving_mask = .false. + config_restore_calving_front_prevent_retreat = .false. + config_calculate_damage = .true. + config_damage_calving_threshold = 0.95 + config_damage_calving_method = 'none' + config_calving_speed_limit = 0.00063492063 + config_restore_calving_front = .true. + config_remove_icebergs = .true. + config_remove_small_islands = .true. + config_distribute_unablatedVolumeDynCell = .true. + config_calving_error_threshold = 100000.0 + + config_thermal_solver = 'temperature' + config_thermal_calculate_bmb = .true. + config_temperature_init = 'file' + config_thermal_thickness = 0.0 + config_surface_air_temperature_source = 'file' + config_basal_heat_flux_source = 'file' + + config_basal_mass_bal_float = 'ismip6' + config_front_mass_bal_grounded = 'none' + config_add_ocean_thermal_forcing = 0.0 + + config_ice_density = 910.0 + config_ocean_density = 1028.0 + config_sea_level = 0.0 + config_flowLawExponent = 3.0 + config_dynamic_thickness = 10.0 + + config_dt = '0000-01-00_00:00:00' + config_time_integration = 'forward_euler' + config_adaptive_timestep = .true. + config_adaptive_timestep_calvingCFL_fraction = 0.8 + config_adaptive_timestep_include_calving = .true. + config_min_adaptive_timestep = 60 + config_max_adaptive_timestep = 3.154e7 + config_adaptive_timestep_CFL_fraction = 0.8 + config_adaptive_timestep_include_DCFL = .false. + config_adaptive_timestep_force_interval = '0001-00-00_00:00:00' + + config_do_restart = .true. + config_restart_timestamp_name = 'restart_timestamp' + config_start_time = 'file' + config_stop_time = '2301-01-01_00:00:00' + config_calendar_type = 'noleap' + + config_stats_interval = 0 + config_write_stats_on_startup = .false. + config_stats_cell_ID = 1 + config_write_output_on_startup = .true. + + config_always_compute_fem_grid = .true. + + config_ocean_connection_N = .false. + config_SGH = .false. + + config_AM_globalStats_enable = .true. + config_AM_globalStats_compute_interval = 'output_interval' + config_AM_globalStats_stream_name = 'globalStatsOutput' + config_AM_globalStats_compute_on_startup = .true. + config_AM_globalStats_write_on_startup = .true. + + config_AM_regionalStats_enable = .true. + config_AM_regionalStats_compute_interval = 'output_interval' + config_AM_regionalStats_stream_name = 'regionalStatsOutput' + config_AM_regionalStats_compute_on_startup = .true. + config_AM_regionalStats_write_on_startup = .true. diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/namelist.sealevel.template b/compass/landice/tests/ismip7_run/ismip7_ais/namelist.sealevel.template new file mode 100644 index 0000000000..e92a72ecab --- /dev/null +++ b/compass/landice/tests/ismip7_run/ismip7_ais/namelist.sealevel.template @@ -0,0 +1,68 @@ +&time_config + itersl = 1 + starttime = 2000 + dt1 = 5 + +/ +&model_resolution + norder = 512 + nglv = {{ nglv }} + +/ +&io_directory + inputfolder_ice = '{{ slm_input_ice }}' + inputfolder = '{{ slm_input_others }}' + planetfolder = '{{ slm_input_earth }}' + gridfolder = '{{ slm_input_others }}' + outputfolder = 'OUTPUT_SLM/' + outputfolder_ice = 'ICELOAD_SLM/' + folder_coupled = '' + +/ +&file_format + ext ='' + fType_in = 'text' + fType_out = 'both' + +/ +&file_name + planetmodel = '{{ slm_earth_structure }}' + icemodel = 'iceGlobalDomain_zeroField_GL{{ nglv }}_' + icemodel_out = 'iceload_out_' + timearray = 'times' + topomodel = 'etopo2_nglv{{ nglv }}_outside_AIS' + topo_initial = 'etopo2_nglv{{ nglv }}_outside_AIS' + grid_lat = 'GLlat_{{ nglv }}.txt' + grid_lon = 'GLlon_{{ nglv }}.txt' + +/ +&model_config + checkmarine = .false. + tpw = .true. + calcRG = .true. + input_times = .false. + initial_topo = .true. + iceVolume = .true. + coupling = .true. + patch_ice = .true. + +/ +&timewindow_config + L_sim = 300 + dt1 = 5 + dt2 = 10 + dt3 = 10 + dt4 = 10 + Ldt1 = 300 + Ldt2 = 0 + Ldt3 = 0 + Ldt4 = 0 + +/ +&others + whichplanet = 'earth' + + +/ + +! end of the namelist file 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 new file mode 100644 index 0000000000..c9251e03f3 --- /dev/null +++ b/compass/landice/tests/ismip7_run/ismip7_ais/set_up_experiment.py @@ -0,0 +1,389 @@ +import glob +import os +import shutil +import sys +from importlib import resources + +from jinja2 import Template + +from compass.job import write_job_script +from compass.load_script import symlink_load_script +from compass.model import make_graph_file, run_model +from compass.step import Step + + +class SetUpExperiment(Step): + """ + A step for setting up an ISMIP7 AIS experiment + """ + + def __init__(self, test_case, name, subdir, exp, exp_info): + """ + Set up a new experiment + + Parameters + ---------- + test_case : compass.testcase.TestCase + The test case this step belongs to + + name : str + The name of this step (same as the experiment name) + + subdir : str + Subdirectory for this step + + exp : str + Experiment identifier (e.g., 'ssp585_CESM2-WACCM') + + exp_info : dict + Dictionary with experiment metadata: + scenario, model, start_time, stop_time, is_historical + """ + self.exp = exp + self.exp_info = exp_info + + super().__init__(test_case=test_case, name=name, subdir=subdir) + + def setup(self): # noqa: C901 + """ + Set up the experiment directory with all needed files. + """ + print(f" Setting up experiment {self.exp}") + + config = self.config + section = config['ismip7_run_ais'] + self.ntasks = section.getint('ntasks') + self.min_tasks = self.ntasks + forcing_basepath = section.get('forcing_basepath') + init_cond_path = section.get('init_cond_path') + init_cond_fname = os.path.split(init_cond_path)[-1] + melt_params_path = section.get('melt_params_path') + melt_params_fname = os.path.split(melt_params_path)[-1] + region_mask_path = section.get('region_mask_path') + region_mask_fname = os.path.split(region_mask_path)[-1] + calving_method = section.get('calving_method') + use_face_melting = section.getboolean('use_face_melting') + sea_level_model = section.getboolean('sea_level_model') + + exp_info = self.exp_info + scenario = exp_info['scenario'] + model = exp_info['model'] + is_historical = exp_info['is_historical'] + start_time = exp_info['start_time'] + stop_time = exp_info['stop_time'] + + # Define where to get templates (in current package) + resource_location = 'compass.landice.tests.ismip7_run.ismip7_ais' + + # Define calving method + use_vM_calving = (calving_method == 'von_mises') + + # --- Determine forcing file paths --- + if scenario == 'ocx': + ocx_forcing_path = section.get('ocx_forcing_path') + forcing_dir = ocx_forcing_path + elif scenario == 'ctrl': + # Control run uses climatology forcing + forcing_dir = None # handled separately below + else: + # Standard ESM-driven experiment + forcing_dir = os.path.join(forcing_basepath, + f"{model}_{scenario}") + + # --- Copy input files --- + if is_historical: + shutil.copy(init_cond_path, self.work_dir) + shutil.copy(melt_params_path, self.work_dir) + shutil.copy(region_mask_path, self.work_dir) + + # --- Find and copy forcing files --- + if scenario == 'ctrl': + # Control run: use climatology files + ctrl_tf_path = section.get('ctrl_tf_climatology_path') + ctrl_atm_path = section.get('ctrl_atm_climatology_path') + tf_fname = os.path.split(ctrl_tf_path)[-1] + shutil.copy(ctrl_tf_path, self.work_dir) + + # Find atmosphere climatology files + smb_files = glob.glob(os.path.join(ctrl_atm_path, '*smb*.nc')) + if len(smb_files) == 1: + smb_fname = os.path.split(smb_files[0])[-1] + shutil.copy(smb_files[0], self.work_dir) + else: + sys.exit(f"ERROR: Expected 1 SMB climatology file in " + f"{ctrl_atm_path}, found {len(smb_files)}") + + temp_files = glob.glob( + os.path.join(ctrl_atm_path, '*temperature*.nc')) + if len(temp_files) == 1: + temp_fname = os.path.split(temp_files[0])[-1] + shutil.copy(temp_files[0], self.work_dir) + else: + sys.exit(f"ERROR: Expected 1 temperature climatology file in " + f"{ctrl_atm_path}, found {len(temp_files)}") + + runoff_files = glob.glob( + os.path.join(ctrl_atm_path, '*runoff*.nc')) + if len(runoff_files) == 1: + runoff_fname = os.path.split(runoff_files[0])[-1] + shutil.copy(runoff_files[0], self.work_dir) + else: + runoff_fname = '' # runoff may not exist for ctrl + + smb_grad_files = glob.glob( + os.path.join(ctrl_atm_path, '*smb_gradient*.nc')) + smb_grad_fname = '' + if len(smb_grad_files) == 1: + smb_grad_fname = os.path.split(smb_grad_files[0])[-1] + shutil.copy(smb_grad_files[0], self.work_dir) + + temp_grad_files = glob.glob( + os.path.join(ctrl_atm_path, '*temperature_gradient*.nc')) + temp_grad_fname = '' + if len(temp_grad_files) == 1: + temp_grad_fname = os.path.split(temp_grad_files[0])[-1] + shutil.copy(temp_grad_files[0], self.work_dir) + + else: + # Standard or OCX experiment: find forcing in forcing_dir + atm_dir = os.path.join(forcing_dir, 'atmosphere') + ocean_dir = os.path.join(forcing_dir, 'ocean_thermal_forcing') + + # SMB forcing + smb_search = os.path.join(atm_dir, '*smb_*.nc') + smb_list = glob.glob(smb_search) + if len(smb_list) == 1: + smb_fname = os.path.split(smb_list[0])[-1] + shutil.copy(smb_list[0], self.work_dir) + else: + sys.exit(f"ERROR: Expected 1 SMB file at {smb_search}, " + f"found {len(smb_list)}: {smb_list}") + + # Temperature forcing + temp_search = os.path.join(atm_dir, '*temperature_*.nc') + temp_list = glob.glob(temp_search) + if len(temp_list) == 1: + temp_fname = os.path.split(temp_list[0])[-1] + shutil.copy(temp_list[0], self.work_dir) + else: + sys.exit(f"ERROR: Expected 1 temperature file at " + f"{temp_search}, found {len(temp_list)}") + + # Runoff forcing (optional — may not exist for all experiments) + runoff_search = os.path.join(atm_dir, '*runoff_*.nc') + runoff_list = glob.glob(runoff_search) + runoff_fname = '' + if len(runoff_list) == 1: + runoff_fname = os.path.split(runoff_list[0])[-1] + shutil.copy(runoff_list[0], self.work_dir) + + # SMB gradient (lapse rate) + smb_grad_search = os.path.join(atm_dir, '*smb_gradient_*.nc') + smb_grad_list = glob.glob(smb_grad_search) + smb_grad_fname = '' + if len(smb_grad_list) == 1: + smb_grad_fname = os.path.split(smb_grad_list[0])[-1] + shutil.copy(smb_grad_list[0], self.work_dir) + + # Temperature gradient (lapse rate) + temp_grad_search = os.path.join(atm_dir, + '*temperature_gradient_*.nc') + temp_grad_list = glob.glob(temp_grad_search) + temp_grad_fname = '' + if len(temp_grad_list) == 1: + temp_grad_fname = os.path.split(temp_grad_list[0])[-1] + shutil.copy(temp_grad_list[0], self.work_dir) + + # Thermal forcing + tf_search = os.path.join(ocean_dir, '*thermal_forcing_*.nc') + tf_list = glob.glob(tf_search) + if len(tf_list) == 1: + tf_fname = os.path.split(tf_list[0])[-1] + shutil.copy(tf_list[0], self.work_dir) + else: + sys.exit(f"ERROR: Expected 1 TF file at {tf_search}, " + f"found {len(tf_list)}: {tf_list}") + + # --- Set up streams --- + # Determine forcing interval + if scenario == 'ctrl': + forcing_interval_monthly = 'initial_only' + forcing_interval_annual = 'initial_only' + elif is_historical: + # Historical: read forcing at each interval + forcing_interval_monthly = '0000-01-00_00:00:00' + forcing_interval_annual = '0001-00-00_00:00:00' + else: + # Projections + forcing_interval_monthly = '0000-01-00_00:00:00' + forcing_interval_annual = '0001-00-00_00:00:00' + + stream_replacements = { + 'input_file_init_cond': init_cond_fname if is_historical + else 'USE_RESTART_FILE_INSTEAD', + 'input_file_region_mask': region_mask_fname if is_historical + else 'USE_RESTART_FILE_INSTEAD', + 'input_file_melt_params': melt_params_fname, + 'input_file_SMB_forcing': smb_fname, + 'input_file_temperature_forcing': temp_fname, + 'input_file_TF_forcing': tf_fname, + 'input_file_runoff_forcing': runoff_fname, + 'input_file_smb_gradient_forcing': smb_grad_fname, + 'input_file_temperature_gradient_forcing': temp_grad_fname, + 'forcing_interval_monthly': forcing_interval_monthly, + 'forcing_interval_annual': forcing_interval_annual, + } + + self.add_streams_file( + resource_location, + 'streams.landice.template', + out_name='streams.landice', + template_replacements=stream_replacements) + + if use_face_melting: + self.add_streams_file( + resource_location, 'streams.faceMelting', + out_name='streams.landice') + + # --- Set up namelist --- + self.add_namelist_file( + resource_location, 'namelist.landice', + out_name='namelist.landice') + + # PIO options + pio_stride = section.getint('pio_stride') + io_tasks = self.ntasks // pio_stride + options = {'config_pio_stride': f'{pio_stride}', + 'config_pio_num_iotasks': f'{io_tasks}'} + self.add_namelist_options(options=options, + out_name='namelist.landice') + + # Historical-specific options + if is_historical: + options = {'config_do_restart': ".false.", + 'config_start_time': f"'{start_time}'", + 'config_stop_time': f"'{stop_time}'"} + self.add_namelist_options(options=options, + out_name='namelist.landice') + else: + options = {'config_stop_time': f"'{stop_time}'"} + self.add_namelist_options(options=options, + out_name='namelist.landice') + + # Calving options + if use_vM_calving: + vM_path = section.get('von_mises_parameter_path') + options = { + 'config_calving': "'von_Mises_stress'", + 'config_restore_calving_front': ".false.", + 'config_floating_von_Mises_threshold_stress_source': "'data'", + 'config_grounded_von_Mises_threshold_stress_source': "'data'"} + self.add_namelist_options(options=options, + out_name='namelist.landice') + vM_stream_replacements = {'input_file_VM_params': vM_path} + self.add_streams_file( + resource_location, 'streams.vM_params', + out_name='streams.landice', + template_replacements=vM_stream_replacements) + + # Face melting options + if use_face_melting: + options = { + 'config_front_mass_bal_grounded': "'ismip6'", + 'config_use_3d_thermal_forcing_for_face_melt': '.true.'} + 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') + slm_input_earth = section.get('slm_input_earth') + slm_earth_structure = section.get('slm_earth_structure') + slm_input_others = section.get('slm_input_others') + nglv = section.getint('nglv') + + slm_input_ice = os.path.join(slm_input_ice, + f'GL{nglv}/ice_noGrIS_GL{nglv}/') + slm_input_others = os.path.join(slm_input_others, + f'GL{nglv}/') + + options = {'config_uplift_method': "'sealevelmodel'"} + self.add_namelist_options(options=options, + out_name='namelist.landice') + + template = Template(resources.read_text( + resource_location, 'namelist.sealevel.template')) + text = template.render( + nglv=int(nglv), slm_input_ice=slm_input_ice, + slm_input_earth=slm_input_earth, + slm_earth_structure=slm_earth_structure, + slm_input_others=slm_input_others) + + file_slm_nl = os.path.join(self.work_dir, 'namelist.sealevel') + with open(file_slm_nl, 'w') as handle: + handle.write(text) + + os.makedirs(os.path.join(self.work_dir, 'OUTPUT_SLM/'), + exist_ok=True) + os.makedirs(os.path.join(self.work_dir, 'ICELOAD_SLM/'), + exist_ok=True) + + map_dir = os.path.join('..', 'mapping_files') + for map_file in ('mapfile_mali_to_slm.nc', + 'mapfile_slm_to_mali.nc'): + os.symlink(os.path.join(map_dir, map_file), + os.path.join(self.work_dir, map_file)) + + # --- Symlink restart for projections/ctrl --- + if not is_historical: + hist_exp = f"historical_{model}" + os.symlink(f"../{hist_exp}/rst.2015-01-01.nc", + os.path.join(self.work_dir, 'rst.2015-01-01.nc')) + with open(os.path.join(self.work_dir, "restart_timestamp"), + "w") as text_file: + text_file.write("2015-01-01_00:00:00") + + # --- Add albany yaml, graph file, load script, job script --- + self.add_input_file( + filename='albany_input.yaml', + package=resource_location, + copy=True) + + make_graph_file(mesh_filename=init_cond_path, + graph_filename=os.path.join(self.work_dir, + 'graph.info')) + + symlink_load_script(self.work_dir) + + self.config.set('job', 'job_name', self.exp) + machine = self.config.get('deploy', 'machine') + pre_run_cmd = ('LOGDIR=previous_logs_`date +"%Y-%m-%d_%H-%M-%S"`;' + 'mkdir $LOGDIR; cp log* $LOGDIR; date') + post_run_cmd = "date" + write_job_script(self.config, machine, + target_cores=self.ntasks, min_cores=self.min_tasks, + work_dir=self.work_dir, + pre_run_commands=pre_run_cmd, + post_run_commands=post_run_cmd) + + self.add_model_as_input() + + def run(self): + """ + Run this step of the test case + """ + config = self.config + section = config['ismip7_run_ais'] + sea_level_model = section.getboolean('sea_level_model') + if sea_level_model: + map_dir = os.path.join('..', 'mapping_files') + for map_file in ('mapfile_mali_to_slm.nc', + 'mapfile_slm_to_mali.nc'): + if not os.path.isfile(os.path.join(map_dir, map_file)): + sys.exit(f"ERROR: 'mapping_files/{map_file}' " + "does not exist in workdir. " + "Please run the 'mapping_files' step " + "before proceeding.") + + run_model(step=self, namelist='namelist.landice', + streams='streams.landice') diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/streams.faceMelting b/compass/landice/tests/ismip7_run/ismip7_ais/streams.faceMelting new file mode 100644 index 0000000000..8d387bc063 --- /dev/null +++ b/compass/landice/tests/ismip7_run/ismip7_ais/streams.faceMelting @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template b/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template new file mode 100644 index 0000000000..5c1a14e2a9 --- /dev/null +++ b/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/streams.vM_params b/compass/landice/tests/ismip7_run/ismip7_ais/streams.vM_params new file mode 100644 index 0000000000..f7ce35a840 --- /dev/null +++ b/compass/landice/tests/ismip7_run/ismip7_ais/streams.vM_params @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py b/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py new file mode 100644 index 0000000000..7874b7c25c --- /dev/null +++ b/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py @@ -0,0 +1,134 @@ +import os + +from compass.landice.tests.ismip7_run.ismip7_gris.set_up_experiment import ( + SetUpExperiment, +) +from compass.testcase import TestCase + +# Define the full experiment matrix for GrIS +EXPERIMENTS = { + 'historical_CESM2-WACCM': { + 'scenario': 'historical', 'model': 'CESM2-WACCM', + 'start_time': '1850-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': '1850-01-01_00:00:00', + 'stop_time': '2015-01-01_00:00:00', + 'is_historical': True}, + 'ssp370_CESM2-WACCM': { + 'scenario': 'ssp370', 'model': 'CESM2-WACCM', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2101-01-01_00:00:00', + 'is_historical': False}, + 'ssp370_MRI-ESM2-0': { + 'scenario': 'ssp370', 'model': 'MRI-ESM2-0', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2101-01-01_00:00:00', + 'is_historical': False}, + 'ssp126_CESM2-WACCM': { + 'scenario': 'ssp126', 'model': 'CESM2-WACCM', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', + 'is_historical': False}, + 'ssp126_MRI-ESM2-0': { + 'scenario': 'ssp126', 'model': 'MRI-ESM2-0', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', + 'is_historical': False}, + 'ssp585_CESM2-WACCM': { + 'scenario': 'ssp585', 'model': 'CESM2-WACCM', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', + 'is_historical': False}, + 'ssp585_MRI-ESM2-0': { + 'scenario': 'ssp585', 'model': 'MRI-ESM2-0', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', + 'is_historical': False}, + 'ctrl_CESM2-WACCM': { + 'scenario': 'ctrl', 'model': 'CESM2-WACCM', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', + 'is_historical': False}, + 'ctrl_MRI-ESM2-0': { + 'scenario': 'ctrl', 'model': 'MRI-ESM2-0', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', + 'is_historical': False}, + 'ocx': { + 'scenario': 'ocx', 'model': None, + 'start_time': '1990-01-01_00:00:00', + 'stop_time': '2026-01-01_00:00:00', + 'is_historical': True}, +} + + +class Ismip7Gris(TestCase): + """ + A test case for automated setup of a suite of standardized + ISMIP7 simulations for the Greenland Ice Sheet. + """ + + def __init__(self, test_group): + """ + Create the test case + + Parameters + ---------- + test_group : compass.landice.tests.ismip7_run.Ismip7Run + The test group that this test case belongs to + """ + name = 'ismip7_gris' + super().__init__(test_group=test_group, name=name, subdir=name) + + def configure(self): + """ + Set up the desired ISMIP7 GrIS experiments. + """ + config = self.config + exp_list_str = config.get('ismip7_run_gris', 'exp_list') + + if exp_list_str == 'all': + exp_list = list(EXPERIMENTS.keys()) + elif exp_list_str == 'historical': + exp_list = [k for k, v in EXPERIMENTS.items() + if v['is_historical']] + elif exp_list_str == 'projections': + exp_list = [k for k, v in EXPERIMENTS.items() + if not v['is_historical'] and + v['scenario'] != 'ctrl'] + elif exp_list_str == 'ctrl': + exp_list = [k for k, v in EXPERIMENTS.items() + if v['scenario'] == 'ctrl'] + else: + exp_list = [s.strip() for s in exp_list_str.split(',')] + + for exp in exp_list: + if exp not in EXPERIMENTS: + raise ValueError( + f"Unknown experiment '{exp}'. Valid experiments: " + f"{list(EXPERIMENTS.keys())}") + if os.path.exists(os.path.join(self.work_dir, exp)): + print(f"WARNING: {exp} path already exists; skipping. " + "Remove the directory " + f"{os.path.join(self.work_dir, exp)} and run " + "'compass setup' again to recreate.") + else: + self.add_step( + SetUpExperiment(test_case=self, name=exp, + subdir=exp, exp=exp, + exp_info=EXPERIMENTS[exp])) + + # Do not add experiments to steps_to_run + self.steps_to_run = [] + + def run(self): + """ + A dummy run method + """ + raise ValueError( + "ERROR: 'compass run' has no functionality at the test case " + "level for this test. Please submit the job script in each " + "experiment's subdirectory manually instead.") diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/albany_input.yaml b/compass/landice/tests/ismip7_run/ismip7_gris/albany_input.yaml new file mode 100644 index 0000000000..e1a4dcd7c4 --- /dev/null +++ b/compass/landice/tests/ismip7_run/ismip7_gris/albany_input.yaml @@ -0,0 +1,239 @@ +%YAML 1.1 +--- +ANONYMOUS: + Problem: + LandIce Field Norm: + sliding_velocity_basalside: + Regularization Type: Given Value + Regularization Value: 1.0e-4 + LandIce BCs: + BC 0: + Basal Friction Coefficient: + Type: Power Law + Power Exponent: 0.2 + Mu Type: Field + Effective Pressure Type: Constant + Effective Pressure: 1.0 + # Zero Effective Pressure On Floating Ice At Nodes: true + Zero Beta On Floating Ice: true + + Cubature Degree: 8 + +# Discretization Description + Discretization: + #Exodus Output File Name: albany_output.exo + + Piro: +# Nonlinear Solver Information + NOX: + Nonlinear Solver: Line Search Based + Line Search: + Full Step: + Full Step: 1.0e+00 + Method: Backtrack + Solver Options: + Status Test Check Type: Minimal + Status Tests: + Test Type: Combo + Combo Type: OR + Number of Tests: 2 + Test 0: + Test Type: NormF + Norm Type: Two Norm + Scale Type: Scaled + Tolerance: 1.0e-05 + Test 1: + Test Type: MaxIters + Maximum Iterations: 50 + Printing: + Output Precision: 3 + Output Processor: 0 + Output Information: + Error: true + Warning: true + Outer Iteration: true + Parameters: false + Details: false + Linear Solver Details: false + Stepper Iteration: true + Stepper Details: true + Stepper Parameters: true + + Direction: + Method: Newton + Newton: + Forcing Term Method: Constant + Rescue Bad Newton Solve: true + Linear Solver: + Write Linear System: false + Tolerance: 1.0e-8 + + Stratimikos Linear Solver: + Stratimikos: + +# Linear Solver Information + Linear Solver Type: Belos + Linear Solver Types: + Belos: + Solver Type: Block GMRES + Solver Types: + Block GMRES: + Output Frequency: 20 + Output Style: 1 + Verbosity: 33 + Maximum Iterations: 200 + Block Size: 1 + Num Blocks: 200 + Flexible Gmres: false + VerboseObject: + Output File: none + Verbosity Level: low + +# Preconditioner Information + Preconditioner Type: MueLu + Preconditioner Types: + + Ifpack2: + Overlap: 1 + Prec Type: ILUT + + MueLu: + Matrix: + PDE equations: 2 + Factories: + myLineDetectionFact: + factory: LineDetectionFactory + 'linedetection: orientation': coordinates + mySemiCoarsenPFact1: + factory: SemiCoarsenPFactory + 'semicoarsen: coarsen rate': 14 + UncoupledAggregationFact2: + factory: UncoupledAggregationFactory + 'aggregation: ordering': graph + 'aggregation: max selected neighbors': 0 + 'aggregation: min agg size': 3 + 'aggregation: phase3 avoid singletons': true + MyCoarseMap2: + factory: CoarseMapFactory + Aggregates: UncoupledAggregationFact2 + myTentativePFact2: + 'tentative: calculate qr': true + factory: TentativePFactory + Aggregates: UncoupledAggregationFact2 + CoarseMap: MyCoarseMap2 + mySaPFact2: + 'sa: eigenvalue estimate num iterations': 10 + 'sa: damping factor': 1.33333e+00 + factory: SaPFactory + P: myTentativePFact2 + myTransferCoordinatesFact: + factory: CoordinatesTransferFactory + CoarseMap: MyCoarseMap2 + Aggregates: UncoupledAggregationFact2 + myTogglePFact: + factory: TogglePFactory + 'semicoarsen: number of levels': 2 + TransferFactories: + P1: mySemiCoarsenPFact1 + P2: mySaPFact2 + Ptent1: mySemiCoarsenPFact1 + Ptent2: myTentativePFact2 + Nullspace1: mySemiCoarsenPFact1 + Nullspace2: myTentativePFact2 + myRestrictorFact: + factory: TransPFactory + P: myTogglePFact + myToggleTransferCoordinatesFact: + factory: ToggleCoordinatesTransferFactory + Chosen P: myTogglePFact + TransferFactories: + Coordinates1: mySemiCoarsenPFact1 + Coordinates2: myTransferCoordinatesFact + myRAPFact: + factory: RAPFactory + P: myTogglePFact + R: myRestrictorFact + TransferFactories: + For Coordinates: myToggleTransferCoordinatesFact + myRepartitionHeuristicFact: + factory: RepartitionHeuristicFactory + A: myRAPFact + 'repartition: min rows per proc': 3000 + 'repartition: max imbalance': 1.327e+00 + 'repartition: start level': 1 + myZoltanInterface: + factory: ZoltanInterface + A: myRAPFact + Coordinates: myToggleTransferCoordinatesFact + number of partitions: myRepartitionHeuristicFact + myRepartitionFact: + factory: RepartitionFactory + A: myRAPFact + Partition: myZoltanInterface + 'repartition: remap parts': true + number of partitions: myRepartitionHeuristicFact + myRebalanceProlongatorFact: + factory: RebalanceTransferFactory + type: Interpolation + P: myTogglePFact + Coordinates: myToggleTransferCoordinatesFact + Nullspace: myTogglePFact + myRebalanceRestrictionFact: + factory: RebalanceTransferFactory + type: Restriction + R: myRestrictorFact + myRebalanceAFact: + factory: RebalanceAcFactory + A: myRAPFact + TransferFactories: { } + mySmoother1: + factory: TrilinosSmoother + type: LINESMOOTHING_BANDEDRELAXATION + 'smoother: pre or post': both + ParameterList: + 'relaxation: type': Gauss-Seidel + 'relaxation: sweeps': 1 + 'relaxation: damping factor': 1.0 + mySmoother3: + factory: TrilinosSmoother + type: RELAXATION + 'smoother: pre or post': both + ParameterList: + 'relaxation: type': Gauss-Seidel + 'relaxation: sweeps': 1 + 'relaxation: damping factor': 1.0 + mySmoother4: + factory: TrilinosSmoother + type: RELAXATION + 'smoother: pre or post': pre + ParameterList: + 'relaxation: type': Gauss-Seidel + 'relaxation: sweeps': 4 + 'relaxation: damping factor': 1.0 + Hierarchy: + max levels: 7 + 'coarse: max size': 2000 + verbosity: None + Finest: + Smoother: mySmoother1 + CoarseSolver: mySmoother4 + P: myRebalanceProlongatorFact + Nullspace: myRebalanceProlongatorFact + CoarseNumZLayers: myLineDetectionFact + LineDetection_Layers: myLineDetectionFact + LineDetection_VertLineIds: myLineDetectionFact + A: myRebalanceAFact + Coordinates: myRebalanceProlongatorFact + Importer: myRepartitionFact + All: + startLevel: 1 + Smoother: mySmoother4 + CoarseSolver: mySmoother4 + P: myRebalanceProlongatorFact + Nullspace: myRebalanceProlongatorFact + CoarseNumZLayers: myLineDetectionFact + LineDetection_Layers: myLineDetectionFact + LineDetection_VertLineIds: myLineDetectionFact + A: myRebalanceAFact + Coordinates: myRebalanceProlongatorFact + Importer: myRepartitionFact diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris.cfg b/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris.cfg new file mode 100644 index 0000000000..a7d2de6db7 --- /dev/null +++ b/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris.cfg @@ -0,0 +1,46 @@ +[ismip7_run_gris] + +# List of experiments to set up. +# Can be "all", "historical", "projections", "ctrl", or a +# comma-delimited list of experiment names. +exp_list = all + +# Number of tasks to use for each run +ntasks = 128 + +# Value to use for config_pio_stride. +pio_stride = 128 + +# Base path to the pre-processed ISMIP7 forcing files. +# Expected layout: +# {forcing_basepath}/{model}_{scenario}/atmosphere/ +# {forcing_basepath}/{model}_{scenario}/ocean_thermal_forcing/ +# User has to supply. +forcing_basepath = NotAvailable + +# Path to the initial condition file. User has to supply. +init_cond_path = NotAvailable + +# Path to the file for the basal melt parametrization coefficients. +melt_params_path = NotAvailable + +# Path to the region mask file +region_mask_path = NotAvailable + +# Path to the ocean thermal forcing climatology file for CTRL2015 runs. +ctrl_tf_climatology_path = NotAvailable + +# Path to the atmosphere climatology files for CTRL2015 runs. +ctrl_atm_climatology_path = NotAvailable + +# Path to OCX forcing. +ocx_forcing_path = NotAvailable + +# Calving method to use. Options: restore, von_mises +calving_method = von_mises + +# Path to the von Mises parameter fields. +von_mises_parameter_path = NotAvailable + +# Whether face melting should be included +use_face_melting = false diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice b/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice new file mode 100644 index 0000000000..36c5cdb0d0 --- /dev/null +++ b/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice @@ -0,0 +1,79 @@ + config_velocity_solver = 'FO' + config_do_velocity_reconstruction_for_external_dycore = .false. + config_unrealistic_velocity = 00.00159 + config_nonconvergence_error = .false. + + config_thickness_advection = 'fo' + config_tracer_advection = 'fo' + config_zero_sfcMassBalApplied_over_bare_land = .true. + + config_uplift_method = 'none' + + config_calving = 'none' + config_apply_calving_mask = .false. + config_restore_calving_front_prevent_retreat = .false. + config_calculate_damage = .true. + config_damage_calving_threshold = 0.95 + config_damage_calving_method = 'none' + config_calving_speed_limit = 0.00063492063 + config_restore_calving_front = .true. + config_remove_icebergs = .true. + config_remove_small_islands = .true. + config_distribute_unablatedVolumeDynCell = .true. + config_calving_error_threshold = 100000.0 + + config_thermal_solver = 'temperature' + config_thermal_calculate_bmb = .true. + config_temperature_init = 'file' + config_thermal_thickness = 0.0 + config_surface_air_temperature_source = 'file' + config_basal_heat_flux_source = 'file' + + config_basal_mass_bal_float = 'ismip6' + config_front_mass_bal_grounded = 'none' + config_add_ocean_thermal_forcing = 0.0 + + config_ice_density = 910.0 + config_ocean_density = 1028.0 + config_sea_level = 0.0 + config_flowLawExponent = 3.0 + config_dynamic_thickness = 10.0 + + config_dt = '0000-01-00_00:00:00' + config_time_integration = 'forward_euler' + config_adaptive_timestep = .true. + config_adaptive_timestep_calvingCFL_fraction = 0.8 + config_adaptive_timestep_include_calving = .true. + config_min_adaptive_timestep = 60 + config_max_adaptive_timestep = 3.154e7 + config_adaptive_timestep_CFL_fraction = 0.8 + config_adaptive_timestep_include_DCFL = .false. + config_adaptive_timestep_force_interval = '0001-00-00_00:00:00' + + config_do_restart = .true. + config_restart_timestamp_name = 'restart_timestamp' + config_start_time = 'file' + config_stop_time = '2301-01-01_00:00:00' + config_calendar_type = 'noleap' + + config_stats_interval = 0 + config_write_stats_on_startup = .false. + config_stats_cell_ID = 1 + config_write_output_on_startup = .true. + + config_always_compute_fem_grid = .true. + + config_ocean_connection_N = .false. + config_SGH = .false. + + config_AM_globalStats_enable = .true. + config_AM_globalStats_compute_interval = 'output_interval' + config_AM_globalStats_stream_name = 'globalStatsOutput' + config_AM_globalStats_compute_on_startup = .true. + config_AM_globalStats_write_on_startup = .true. + + config_AM_regionalStats_enable = .true. + config_AM_regionalStats_compute_interval = 'output_interval' + config_AM_regionalStats_stream_name = 'regionalStatsOutput' + config_AM_regionalStats_compute_on_startup = .true. + config_AM_regionalStats_write_on_startup = .true. diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py b/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py new file mode 100644 index 0000000000..1082af6c11 --- /dev/null +++ b/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py @@ -0,0 +1,304 @@ +import glob +import os +import shutil +import sys + +from compass.job import write_job_script +from compass.load_script import symlink_load_script +from compass.model import make_graph_file, run_model +from compass.step import Step + + +class SetUpExperiment(Step): + """ + A step for setting up an ISMIP7 GrIS experiment + """ + + def __init__(self, test_case, name, subdir, exp, exp_info): + """ + Set up a new experiment + + Parameters + ---------- + test_case : compass.testcase.TestCase + The test case this step belongs to + + name : str + The name of this step (same as the experiment name) + + subdir : str + Subdirectory for this step + + exp : str + Experiment identifier + + exp_info : dict + Dictionary with experiment metadata + """ + self.exp = exp + self.exp_info = exp_info + + super().__init__(test_case=test_case, name=name, subdir=subdir) + + def setup(self): # noqa: C901 + """ + Set up the experiment directory with all needed files. + """ + print(f" Setting up experiment {self.exp}") + + config = self.config + section = config['ismip7_run_gris'] + self.ntasks = section.getint('ntasks') + self.min_tasks = self.ntasks + forcing_basepath = section.get('forcing_basepath') + init_cond_path = section.get('init_cond_path') + init_cond_fname = os.path.split(init_cond_path)[-1] + melt_params_path = section.get('melt_params_path') + melt_params_fname = os.path.split(melt_params_path)[-1] + region_mask_path = section.get('region_mask_path') + region_mask_fname = os.path.split(region_mask_path)[-1] + calving_method = section.get('calving_method') + use_face_melting = section.getboolean('use_face_melting') + + exp_info = self.exp_info + scenario = exp_info['scenario'] + model = exp_info['model'] + is_historical = exp_info['is_historical'] + start_time = exp_info['start_time'] + stop_time = exp_info['stop_time'] + + resource_location = 'compass.landice.tests.ismip7_run.ismip7_gris' + + use_vM_calving = (calving_method == 'von_mises') + + # --- Determine forcing file paths --- + if scenario == 'ocx': + ocx_forcing_path = section.get('ocx_forcing_path') + forcing_dir = ocx_forcing_path + elif scenario == 'ctrl': + forcing_dir = None + else: + forcing_dir = os.path.join(forcing_basepath, + f"{model}_{scenario}") + + # --- Copy input files --- + if is_historical: + shutil.copy(init_cond_path, self.work_dir) + shutil.copy(melt_params_path, self.work_dir) + shutil.copy(region_mask_path, self.work_dir) + + # --- Find and copy forcing files --- + if scenario == 'ctrl': + ctrl_tf_path = section.get('ctrl_tf_climatology_path') + ctrl_atm_path = section.get('ctrl_atm_climatology_path') + tf_fname = os.path.split(ctrl_tf_path)[-1] + shutil.copy(ctrl_tf_path, self.work_dir) + + smb_files = glob.glob(os.path.join(ctrl_atm_path, '*smb*.nc')) + if len(smb_files) == 1: + smb_fname = os.path.split(smb_files[0])[-1] + shutil.copy(smb_files[0], self.work_dir) + else: + sys.exit(f"ERROR: Expected 1 SMB climatology file in " + f"{ctrl_atm_path}, found {len(smb_files)}") + + temp_files = glob.glob( + os.path.join(ctrl_atm_path, '*temperature*.nc')) + if len(temp_files) == 1: + temp_fname = os.path.split(temp_files[0])[-1] + shutil.copy(temp_files[0], self.work_dir) + else: + sys.exit(f"ERROR: Expected 1 temperature climatology file in " + f"{ctrl_atm_path}, found {len(temp_files)}") + + runoff_files = glob.glob( + os.path.join(ctrl_atm_path, '*runoff*.nc')) + runoff_fname = '' + if len(runoff_files) == 1: + runoff_fname = os.path.split(runoff_files[0])[-1] + shutil.copy(runoff_files[0], self.work_dir) + + smb_grad_files = glob.glob( + os.path.join(ctrl_atm_path, '*smb_gradient*.nc')) + smb_grad_fname = '' + if len(smb_grad_files) == 1: + smb_grad_fname = os.path.split(smb_grad_files[0])[-1] + shutil.copy(smb_grad_files[0], self.work_dir) + + temp_grad_files = glob.glob( + os.path.join(ctrl_atm_path, '*temperature_gradient*.nc')) + temp_grad_fname = '' + if len(temp_grad_files) == 1: + temp_grad_fname = os.path.split(temp_grad_files[0])[-1] + shutil.copy(temp_grad_files[0], self.work_dir) + + else: + atm_dir = os.path.join(forcing_dir, 'atmosphere') + ocean_dir = os.path.join(forcing_dir, 'ocean_thermal_forcing') + + smb_search = os.path.join(atm_dir, '*smb_*.nc') + smb_list = glob.glob(smb_search) + if len(smb_list) == 1: + smb_fname = os.path.split(smb_list[0])[-1] + shutil.copy(smb_list[0], self.work_dir) + else: + sys.exit(f"ERROR: Expected 1 SMB file at {smb_search}, " + f"found {len(smb_list)}") + + temp_search = os.path.join(atm_dir, '*temperature_*.nc') + temp_list = glob.glob(temp_search) + if len(temp_list) == 1: + temp_fname = os.path.split(temp_list[0])[-1] + shutil.copy(temp_list[0], self.work_dir) + else: + sys.exit(f"ERROR: Expected 1 temperature file at " + f"{temp_search}, found {len(temp_list)}") + + runoff_search = os.path.join(atm_dir, '*runoff_*.nc') + runoff_list = glob.glob(runoff_search) + runoff_fname = '' + if len(runoff_list) == 1: + runoff_fname = os.path.split(runoff_list[0])[-1] + shutil.copy(runoff_list[0], self.work_dir) + + smb_grad_search = os.path.join(atm_dir, '*smb_gradient_*.nc') + smb_grad_list = glob.glob(smb_grad_search) + smb_grad_fname = '' + if len(smb_grad_list) == 1: + smb_grad_fname = os.path.split(smb_grad_list[0])[-1] + shutil.copy(smb_grad_list[0], self.work_dir) + + temp_grad_search = os.path.join(atm_dir, + '*temperature_gradient_*.nc') + temp_grad_list = glob.glob(temp_grad_search) + temp_grad_fname = '' + if len(temp_grad_list) == 1: + temp_grad_fname = os.path.split(temp_grad_list[0])[-1] + shutil.copy(temp_grad_list[0], self.work_dir) + + # GrIS uses 2D thermal forcing + tf_search = os.path.join(ocean_dir, '*thermal_forcing_*.nc') + tf_list = glob.glob(tf_search) + if len(tf_list) == 1: + tf_fname = os.path.split(tf_list[0])[-1] + shutil.copy(tf_list[0], self.work_dir) + else: + sys.exit(f"ERROR: Expected 1 TF file at {tf_search}, " + f"found {len(tf_list)}") + + # --- Set up streams --- + if scenario == 'ctrl': + forcing_interval_monthly = 'initial_only' + forcing_interval_annual = 'initial_only' + else: + forcing_interval_monthly = '0000-01-00_00:00:00' + forcing_interval_annual = '0001-00-00_00:00:00' + + stream_replacements = { + 'input_file_init_cond': init_cond_fname if is_historical + else 'USE_RESTART_FILE_INSTEAD', + 'input_file_region_mask': region_mask_fname if is_historical + else 'USE_RESTART_FILE_INSTEAD', + 'input_file_melt_params': melt_params_fname, + 'input_file_SMB_forcing': smb_fname, + 'input_file_temperature_forcing': temp_fname, + 'input_file_TF_forcing': tf_fname, + 'input_file_runoff_forcing': runoff_fname, + 'input_file_smb_gradient_forcing': smb_grad_fname, + 'input_file_temperature_gradient_forcing': temp_grad_fname, + 'forcing_interval_monthly': forcing_interval_monthly, + 'forcing_interval_annual': forcing_interval_annual, + } + + self.add_streams_file( + resource_location, + 'streams.landice.template', + out_name='streams.landice', + template_replacements=stream_replacements) + + # --- Set up namelist --- + self.add_namelist_file( + resource_location, 'namelist.landice', + out_name='namelist.landice') + + # PIO options + pio_stride = section.getint('pio_stride') + io_tasks = self.ntasks // pio_stride + options = {'config_pio_stride': f'{pio_stride}', + 'config_pio_num_iotasks': f'{io_tasks}'} + self.add_namelist_options(options=options, + out_name='namelist.landice') + + if is_historical: + options = {'config_do_restart': ".false.", + 'config_start_time': f"'{start_time}'", + 'config_stop_time': f"'{stop_time}'"} + self.add_namelist_options(options=options, + out_name='namelist.landice') + else: + options = {'config_stop_time': f"'{stop_time}'"} + self.add_namelist_options(options=options, + out_name='namelist.landice') + + if use_vM_calving: + vM_path = section.get('von_mises_parameter_path') + options = { + 'config_calving': "'von_Mises_stress'", + 'config_restore_calving_front': ".false.", + 'config_floating_von_Mises_threshold_stress_source': "'data'", + 'config_grounded_von_Mises_threshold_stress_source': "'data'"} + self.add_namelist_options(options=options, + out_name='namelist.landice') + vM_stream_replacements = {'input_file_VM_params': vM_path} + self.add_streams_file( + resource_location, 'streams.vM_params', + out_name='streams.landice', + template_replacements=vM_stream_replacements) + + if use_face_melting: + options = { + 'config_front_mass_bal_grounded': "'ismip6'", + 'config_use_3d_thermal_forcing_for_face_melt': '.false.'} + self.add_namelist_options(options=options, + out_name='namelist.landice') + + # --- Symlink restart for projections/ctrl --- + if not is_historical: + hist_exp = f"historical_{model}" + os.symlink(f"../{hist_exp}/rst.2015-01-01.nc", + os.path.join(self.work_dir, 'rst.2015-01-01.nc')) + with open(os.path.join(self.work_dir, "restart_timestamp"), + "w") as text_file: + text_file.write("2015-01-01_00:00:00") + + # --- Add albany yaml, graph file, load script, job script --- + self.add_input_file( + filename='albany_input.yaml', + package=resource_location, + copy=True) + + make_graph_file(mesh_filename=init_cond_path, + graph_filename=os.path.join(self.work_dir, + 'graph.info')) + + symlink_load_script(self.work_dir) + + self.config.set('job', 'job_name', self.exp) + machine = self.config.get('deploy', 'machine') + pre_run_cmd = ('LOGDIR=previous_logs_`date +"%Y-%m-%d_%H-%M-%S"`;' + 'mkdir $LOGDIR; cp log* $LOGDIR; date') + post_run_cmd = "date" + write_job_script(self.config, machine, + target_cores=self.ntasks, min_cores=self.min_tasks, + work_dir=self.work_dir, + pre_run_commands=pre_run_cmd, + post_run_commands=post_run_cmd) + + self.add_model_as_input() + + def run(self): + """ + Run this step of the test case + """ + run_model(step=self, namelist='namelist.landice', + streams='streams.landice') diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template b/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template new file mode 100644 index 0000000000..30dd40ea92 --- /dev/null +++ b/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/streams.vM_params b/compass/landice/tests/ismip7_run/ismip7_gris/streams.vM_params new file mode 100644 index 0000000000..f7ce35a840 --- /dev/null +++ b/compass/landice/tests/ismip7_run/ismip7_gris/streams.vM_params @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/docs/developers_guide/landice/test_groups/index.rst b/docs/developers_guide/landice/test_groups/index.rst index 2556037c52..b0871ac2b5 100644 --- a/docs/developers_guide/landice/test_groups/index.rst +++ b/docs/developers_guide/landice/test_groups/index.rst @@ -21,6 +21,7 @@ Test groups ismip6_forcing ismip6_run ismip7_forcing + ismip7_run isunnguata_sermia kangerlussuaq koge_bugt_s diff --git a/docs/developers_guide/landice/test_groups/ismip7_run.rst b/docs/developers_guide/landice/test_groups/ismip7_run.rst new file mode 100644 index 0000000000..15199b4830 --- /dev/null +++ b/docs/developers_guide/landice/test_groups/ismip7_run.rst @@ -0,0 +1,116 @@ +.. _dev_landice_ismip7_run: + +ismip7_run +========== + +The ``ismip7_run`` test group +(:py:class:`compass.landice.tests.ismip7_run`) sets up experiments from +the ISMIP7 experimental protocol for both the Antarctic Ice Sheet (AIS) +and the Greenland Ice Sheet (GrIS). Optionally, the AIS test case +supports coupled MALI–Sea Level Model (SLM) simulations. +(see :ref:`landice_ismip7_run`). + +framework +--------- + +The ``ismip7_run`` test group +(:py:class:`compass.landice.tests.ismip7_run.Ismip7Run`) registers two +test cases: + +* :py:class:`compass.landice.tests.ismip7_run.ismip7_ais.Ismip7Ais` +* :py:class:`compass.landice.tests.ismip7_run.ismip7_gris.Ismip7Gris` + +There is no shared functionality between the two test cases at present. +Shared functions may be added in the future if the needed functionality +can be generalized. + +ismip7_ais +---------- + +The :py:class:`compass.landice.tests.ismip7_run.ismip7_ais.Ismip7Ais` +test case sets up an ensemble of ISMIP7 Antarctica simulations +(standalone MALI or coupled MALI-SLM). + +The constructor (``__init__``) does nothing other than allow the +``ismip7_ais`` test case to be listed by ``compass list`` without having +all individual experiments listed in a verbose listing. Each individual +experiment is a step rather than a test case to avoid excessive +subdirectories. + +The ``configure`` method parses the ``exp_list`` config option from the +``[ismip7_run_ais]`` section. It supports: + +* ``all`` — all 11 core experiments +* ``historical`` — just the two historical runs +* ``projections`` — the six SSP projection runs +* ``ctrl`` — the two CTRL2015 runs +* A comma-delimited list of specific experiment names + +Each selected experiment is added as a +:py:class:`~compass.landice.tests.ismip7_run.ismip7_ais.set_up_experiment.SetUpExperiment` +step and immediately removed from ``steps_to_run`` (experiments should be +submitted individually, not run through the test case). + +The ``run`` method raises an error instructing the user to submit batch +jobs for each experiment individually. + +set_up_experiment (AIS) +~~~~~~~~~~~~~~~~~~~~~~~ + +The class +:py:class:`compass.landice.tests.ismip7_run.ismip7_ais.set_up_experiment.SetUpExperiment` +defines a step for a single ISMIP7 AIS experiment. + +The ``setup`` method sets up the experiment directory by: + +1. Creating symlinks to forcing files from the conventional path layout + under ``forcing_basepath``. +2. Copying and populating the streams template with the correct forcing + filenames and intervals (monthly for SMB/temperature/runoff, annual + for lapse rates and thermal forcing, ``initial_only`` for melt + parameters). +3. Processing the namelist template for the experiment's time period + and restart frequency. +4. Adding calving-specific streams (face melting, von Mises params) if + configured. +5. Creating a restart symlink for projection experiments pointing to + the corresponding ESM's historical restart + (``../historical_{model}/rst.2015-01-01.nc``). +6. Setting up CTRL2015 experiments with constant-climate forcing + (``initial_only`` intervals). +7. Setting up the OCX experiment with reanalysis-based forcing. +8. If SLM coupling is enabled, adding a ``CreateSlmMappingFiles`` step + and writing the SLM namelist from the Jinja2 template. +9. Generating a ``graph.info`` file and a SLURM job script. +10. Symlinking the compass load script into the run directory. + +The ``run`` method executes MALI for the given experiment. + +create_slm_mapping_files +~~~~~~~~~~~~~~~~~~~~~~~~ + +The class +:py:class:`compass.landice.tests.ismip7_run.ismip7_ais.create_slm_mapping_files.CreateSlmMappingFiles` +creates mapping files between the MALI mesh and the SLM grid. This step +is only added when sea-level model coupling is enabled. + +ismip7_gris +----------- + +The :py:class:`compass.landice.tests.ismip7_run.ismip7_gris.Ismip7Gris` +test case mirrors ``ismip7_ais`` but for the Greenland Ice Sheet. + +Key differences from the AIS test case: + +* Ocean thermal forcing is 2D (depth-averaged) rather than 3D. +* No sea-level model coupling. +* Default calving method is ``von_mises``. +* Config section is ``[ismip7_run_gris]``. + +set_up_experiment (GrIS) +~~~~~~~~~~~~~~~~~~~~~~~~ + +The class +:py:class:`compass.landice.tests.ismip7_run.ismip7_gris.set_up_experiment.SetUpExperiment` +follows the same logic as the AIS version, with the differences noted +above (2D TF stream, no SLM support). diff --git a/docs/users_guide/landice/test_groups/index.rst b/docs/users_guide/landice/test_groups/index.rst index f744061134..6a49090c00 100644 --- a/docs/users_guide/landice/test_groups/index.rst +++ b/docs/users_guide/landice/test_groups/index.rst @@ -26,6 +26,7 @@ physics but that are not run routinely. ismip6_forcing ismip6_run ismip7_forcing + ismip7_run isunnguata_sermia kangerlussuaq koge_bugt_s diff --git a/docs/users_guide/landice/test_groups/ismip7_run.rst b/docs/users_guide/landice/test_groups/ismip7_run.rst new file mode 100644 index 0000000000..2eab9239c1 --- /dev/null +++ b/docs/users_guide/landice/test_groups/ismip7_run.rst @@ -0,0 +1,228 @@ +.. _landice_ismip7_run: + +ismip7_run +========== + +The ``landice/ismip7_run`` test group sets up one or more experiments from the +`ISMIP7 protocol `_ for both the +Antarctic Ice Sheet (AIS) and the Greenland Ice Sheet (GrIS). + +This functionality assumes the forcing files have already been generated using +the :ref:`landice_ismip7_forcing` test group and organized into the expected +directory layout. It creates a consistent set of run directories for the +requested experiments. Each experiment directory is self-contained with +namelists, streams, forcing symlinks, and a job script ready for submission. + +The test group includes two test cases: + +* ``ismip7_ais`` — Antarctic Ice Sheet experiments +* ``ismip7_gris`` — Greenland Ice Sheet experiments + +.. note:: + + This test group is not meant for automated running of experiments. + Expert knowledge is recommended for conducting the actual simulations. + Each experiment (step) should be submitted manually via its job script. + +.. _landice_ismip7_run_experiments: + +Experiment Matrix +----------------- + +The ISMIP7 core protocol defines 11 experiments per ice sheet: + +.. list-table:: + :header-rows: 1 + + * - Experiment + - Scenario + - Start + - End + - ESM + * - ``historical_CESM2-WACCM`` + - Historical + - ≥1850 + - 2014 + - CESM2-WACCM + * - ``historical_MRI-ESM2-0`` + - Historical + - ≥1850 + - 2014 + - MRI-ESM2-0 + * - ``ssp370_CESM2-WACCM`` + - SSP370 + - 2015 + - 2100 + - CESM2-WACCM + * - ``ssp370_MRI-ESM2-0`` + - SSP370 + - 2015 + - 2100 + - MRI-ESM2-0 + * - ``ssp126_CESM2-WACCM`` + - SSP126 + - 2015 + - 2300 + - CESM2-WACCM + * - ``ssp126_MRI-ESM2-0`` + - SSP126 + - 2015 + - 2300 + - MRI-ESM2-0 + * - ``ssp585_CESM2-WACCM`` + - SSP585 + - 2015 + - 2300 + - CESM2-WACCM + * - ``ssp585_MRI-ESM2-0`` + - SSP585 + - 2015 + - 2300 + - MRI-ESM2-0 + * - ``ctrl_CESM2-WACCM`` + - CTRL2015 + - 2015 + - 2300 + - CESM2-WACCM + * - ``ctrl_MRI-ESM2-0`` + - CTRL2015 + - 2015 + - 2300 + - MRI-ESM2-0 + * - ``ocx`` + - OCX + - 1990 + - 2025 + - (reanalysis) + +Unlike ISMIP6, ISMIP7 requires a **separate historical simulation per ESM**. +Projection experiments automatically symlink their restart file from the +corresponding ESM's historical run (e.g., +``ssp585_CESM2-WACCM`` → ``../historical_CESM2-WACCM/rst.2015-01-01.nc``). + +.. _landice_ismip7_run_usage: + +Usage +----- + +1. Process forcing data using :ref:`landice_ismip7_forcing`. + +2. Organize output into the expected directory layout:: + + {forcing_basepath}/ + ├── CESM2-WACCM_historical/ + │ ├── atmosphere/ + │ │ └── {mesh}_smb_CESM2-WACCM_historical_*.nc + │ └── ocean_thermal_forcing/ + │ └── {mesh}_thermal_forcing_CESM2-WACCM_historical_*.nc + ├── CESM2-WACCM_ssp585/ + │ ├── atmosphere/ + │ └── ocean_thermal_forcing/ + └── ... + +3. Create a user config file overriding the ``NotAvailable`` paths. + +4. Set up and run:: + + compass setup landice/ismip7_run/ismip7_ais -f my_ismip7_ais.cfg + # Then submit job scripts from individual experiment directories + +.. _landice_ismip7_run_config: + +config options +-------------- + +All config options should be reviewed and altered as needed. + +**AIS config** (``[ismip7_run_ais]``): + +.. code-block:: cfg + + [ismip7_run_ais] + + # Experiment list: "all", "historical", "projections", "ctrl", + # or comma-delimited experiment names + exp_list = all + + # Number of MPI tasks + ntasks = 128 + pio_stride = 128 + + # Base path to pre-processed forcing + forcing_basepath = NotAvailable + + # Initial condition and parameter files + init_cond_path = NotAvailable + melt_params_path = NotAvailable + region_mask_path = NotAvailable + + # Climatology files for CTRL2015 experiments + ctrl_tf_climatology_path = NotAvailable + ctrl_atm_climatology_path = NotAvailable + + # OCX forcing path + ocx_forcing_path = NotAvailable + + # Calving: restore or von_mises + calving_method = restore + von_mises_parameter_path = NotAvailable + + # Face melting + use_face_melting = false + + # Sea-level model coupling + sea_level_model = false + slm_input_ice = NotAvailable + slm_input_earth = NotAvailable + slm_earth_structure = prem_512.l60K2C.sum18p6.dum19p2.tz19p4.lm22 + slm_input_others = NotAvailable + nglv = 2048 + +**GrIS config** (``[ismip7_run_gris]``) is similar but without +sea-level model options and with ``calving_method = von_mises`` as default. + +.. _landice_ismip7_run_forcing_streams: + +Forcing Streams +--------------- + +ISMIP7 uses more forcing fields than ISMIP6, at mixed temporal resolutions: + +**Monthly forcing** (``input_interval = 0000-01-00_00:00:00``): + +* ``sfcMassBal`` — surface mass balance +* ``surfaceAirTemperature`` — surface air temperature +* ``ismip6Runoff`` — ice sheet runoff + +**Annual forcing** (``input_interval = 0001-00-00_00:00:00``): + +* ``sfcMassBalLapseRate`` — SMB elevation lapse rate +* ``surfaceAirTemperatureLapseRate`` — temperature lapse rate +* ``ismip6shelfMelt_3dThermalForcing`` (AIS) or + ``ismip6_2dThermalForcing`` (GrIS) — ocean thermal forcing + +**Static** (``input_interval = initial_only``): + +* ``ismip6shelfMelt_zOcean`` — ocean depth coordinates (AIS only) +* ``ismip6shelfMelt_deltaT``, ``ismip6shelfMelt_basin``, + ``ismip6shelfMelt_gamma0`` — melt parameterization coefficients + +For CTRL2015 experiments, all forcing intervals are set to +``initial_only`` (constant climate). + +.. _landice_ismip7_run_ais: + +ismip7_ais +---------- + +``landice/ismip7_run/ismip7_ais`` sets up AIS experiments with 3D ocean +thermal forcing (30 vertical layers) and optional sea-level model coupling. + +.. _landice_ismip7_run_gris: + +ismip7_gris +----------- + +``landice/ismip7_run/ismip7_gris`` sets up GrIS experiments with 2D +(depth-averaged) ocean thermal forcing. Sea-level model coupling is not +currently supported for GrIS. Von Mises calving is the default. From b5c8474e0e4e4ee0b4510614f237ae7aabed2439 Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Tue, 9 Jun 2026 12:35:21 -0700 Subject: [PATCH 02/24] Remove incorrect mode="forward;analysis" from streams files Remove incorrect mode="forward;analysis" from streams files. This line causes runs to terminate with an error. --- .../tests/ismip7_run/ismip7_ais/streams.landice.template | 8 -------- .../landice/tests/ismip7_run/ismip7_ais/streams.vM_params | 1 - .../tests/ismip7_run/ismip7_gris/streams.landice.template | 8 -------- .../tests/ismip7_run/ismip7_gris/streams.vM_params | 1 - 4 files changed, 18 deletions(-) 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 5c1a14e2a9..cfb4b7db8f 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template +++ b/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template @@ -21,7 +21,6 @@ @@ -30,7 +29,6 @@ diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/streams.vM_params b/compass/landice/tests/ismip7_run/ismip7_ais/streams.vM_params index f7ce35a840..d9ae1ca3f6 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/streams.vM_params +++ b/compass/landice/tests/ismip7_run/ismip7_ais/streams.vM_params @@ -2,7 +2,6 @@ diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template b/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template index 30dd40ea92..a48003c84d 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template +++ b/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template @@ -21,7 +21,6 @@ @@ -30,7 +29,6 @@ diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/streams.vM_params b/compass/landice/tests/ismip7_run/ismip7_gris/streams.vM_params index f7ce35a840..d9ae1ca3f6 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/streams.vM_params +++ b/compass/landice/tests/ismip7_run/ismip7_gris/streams.vM_params @@ -2,7 +2,6 @@ From e5a3f0836b17359ac1131aeb93a6138cda69a131 Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Tue, 9 Jun 2026 13:30:57 -0700 Subject: [PATCH 03/24] Fix issue finding forcing files Fix case mismatch between smb and SMB, as well as issue that confused SMB with SMB_gradient and temperature with temperature_gradient files. --- .../tests/ismip7_run/ismip7_ais/set_up_experiment.py | 12 ++++++++---- .../ismip7_run/ismip7_gris/set_up_experiment.py | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) 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 c9251e03f3..9ad6521e25 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 @@ -105,7 +105,8 @@ def setup(self): # noqa: C901 shutil.copy(ctrl_tf_path, self.work_dir) # Find atmosphere climatology files - smb_files = glob.glob(os.path.join(ctrl_atm_path, '*smb*.nc')) + smb_files = glob.glob(os.path.join(ctrl_atm_path, '*SMB*.nc')) + smb_files = [f for f in smb_files if 'gradient' not in f] if len(smb_files) == 1: smb_fname = os.path.split(smb_files[0])[-1] shutil.copy(smb_files[0], self.work_dir) @@ -115,6 +116,7 @@ def setup(self): # noqa: C901 temp_files = glob.glob( os.path.join(ctrl_atm_path, '*temperature*.nc')) + temp_files = [f for f in temp_files if 'gradient' not in f] if len(temp_files) == 1: temp_fname = os.path.split(temp_files[0])[-1] shutil.copy(temp_files[0], self.work_dir) @@ -131,7 +133,7 @@ def setup(self): # noqa: C901 runoff_fname = '' # runoff may not exist for ctrl smb_grad_files = glob.glob( - os.path.join(ctrl_atm_path, '*smb_gradient*.nc')) + os.path.join(ctrl_atm_path, '*SMB_gradient*.nc')) smb_grad_fname = '' if len(smb_grad_files) == 1: smb_grad_fname = os.path.split(smb_grad_files[0])[-1] @@ -150,8 +152,9 @@ def setup(self): # noqa: C901 ocean_dir = os.path.join(forcing_dir, 'ocean_thermal_forcing') # SMB forcing - smb_search = os.path.join(atm_dir, '*smb_*.nc') + smb_search = os.path.join(atm_dir, '*SMB_*.nc') smb_list = glob.glob(smb_search) + smb_list = [f for f in smb_list if 'gradient' not in f] if len(smb_list) == 1: smb_fname = os.path.split(smb_list[0])[-1] shutil.copy(smb_list[0], self.work_dir) @@ -162,6 +165,7 @@ def setup(self): # noqa: C901 # Temperature forcing temp_search = os.path.join(atm_dir, '*temperature_*.nc') temp_list = glob.glob(temp_search) + temp_list = [f for f in temp_list if 'gradient' not in f] if len(temp_list) == 1: temp_fname = os.path.split(temp_list[0])[-1] shutil.copy(temp_list[0], self.work_dir) @@ -178,7 +182,7 @@ def setup(self): # noqa: C901 shutil.copy(runoff_list[0], self.work_dir) # SMB gradient (lapse rate) - smb_grad_search = os.path.join(atm_dir, '*smb_gradient_*.nc') + smb_grad_search = os.path.join(atm_dir, '*SMB_gradient_*.nc') smb_grad_list = glob.glob(smb_grad_search) smb_grad_fname = '' if len(smb_grad_list) == 1: diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py b/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py index 1082af6c11..9739cdb59e 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py +++ b/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py @@ -94,7 +94,8 @@ def setup(self): # noqa: C901 tf_fname = os.path.split(ctrl_tf_path)[-1] shutil.copy(ctrl_tf_path, self.work_dir) - smb_files = glob.glob(os.path.join(ctrl_atm_path, '*smb*.nc')) + smb_files = glob.glob(os.path.join(ctrl_atm_path, '*SMB*.nc')) + smb_files = [f for f in smb_files if 'gradient' not in f] if len(smb_files) == 1: smb_fname = os.path.split(smb_files[0])[-1] shutil.copy(smb_files[0], self.work_dir) @@ -104,6 +105,7 @@ def setup(self): # noqa: C901 temp_files = glob.glob( os.path.join(ctrl_atm_path, '*temperature*.nc')) + temp_files = [f for f in temp_files if 'gradient' not in f] if len(temp_files) == 1: temp_fname = os.path.split(temp_files[0])[-1] shutil.copy(temp_files[0], self.work_dir) @@ -119,7 +121,7 @@ def setup(self): # noqa: C901 shutil.copy(runoff_files[0], self.work_dir) smb_grad_files = glob.glob( - os.path.join(ctrl_atm_path, '*smb_gradient*.nc')) + os.path.join(ctrl_atm_path, '*SMB_gradient*.nc')) smb_grad_fname = '' if len(smb_grad_files) == 1: smb_grad_fname = os.path.split(smb_grad_files[0])[-1] @@ -136,8 +138,9 @@ def setup(self): # noqa: C901 atm_dir = os.path.join(forcing_dir, 'atmosphere') ocean_dir = os.path.join(forcing_dir, 'ocean_thermal_forcing') - smb_search = os.path.join(atm_dir, '*smb_*.nc') + smb_search = os.path.join(atm_dir, '*SMB_*.nc') smb_list = glob.glob(smb_search) + smb_list = [f for f in smb_list if 'gradient' not in f] if len(smb_list) == 1: smb_fname = os.path.split(smb_list[0])[-1] shutil.copy(smb_list[0], self.work_dir) @@ -147,6 +150,7 @@ def setup(self): # noqa: C901 temp_search = os.path.join(atm_dir, '*temperature_*.nc') temp_list = glob.glob(temp_search) + temp_list = [f for f in temp_list if 'gradient' not in f] if len(temp_list) == 1: temp_fname = os.path.split(temp_list[0])[-1] shutil.copy(temp_list[0], self.work_dir) @@ -161,7 +165,7 @@ def setup(self): # noqa: C901 runoff_fname = os.path.split(runoff_list[0])[-1] shutil.copy(runoff_list[0], self.work_dir) - smb_grad_search = os.path.join(atm_dir, '*smb_gradient_*.nc') + smb_grad_search = os.path.join(atm_dir, '*SMB_gradient_*.nc') smb_grad_list = glob.glob(smb_grad_search) smb_grad_fname = '' if len(smb_grad_list) == 1: From f161e7faa979483e7543d2b4b63126e72baac663 Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Tue, 9 Jun 2026 13:32:03 -0700 Subject: [PATCH 04/24] Add test .cfg file for AIS --- .../ismip7_run/ismip7_ais/ismip7_ais_test.cfg | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg b/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg new file mode 100644 index 0000000000..34491b1058 --- /dev/null +++ b/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg @@ -0,0 +1,79 @@ +[ismip7_run_ais] + +# List of experiments to set up. +# Can be "all", "historical", "projections", "ctrl", or a +# comma-delimited list of experiment names. +# Valid experiment names: +# historical_CESM2-WACCM, historical_MRI-ESM2-0, +# ssp126_CESM2-WACCM, ssp126_MRI-ESM2-0, +# ssp370_CESM2-WACCM, ssp370_MRI-ESM2-0, +# ssp585_CESM2-WACCM, ssp585_MRI-ESM2-0, +# ctrl_CESM2-WACCM, ctrl_MRI-ESM2-0, +# ocx +exp_list = historical_CESM2-WACCM,ssp585_CESM2-WACCM + +# Number of tasks to use for each run +ntasks = 512 + +# Value to use for config_pio_stride. +# Should be divisible into ntasks +pio_stride = 128 + +# Base path to the pre-processed ISMIP7 forcing files. +# Expected layout: +# {forcing_basepath}/{model}_{scenario}/atmosphere/ +# {forcing_basepath}/{model}_{scenario}/ocean_thermal_forcing/ +# User has to supply. +forcing_basepath = /global/cfs/cdirs/m4288/users/trhille/ISMIP7/test_processing/AIS/ + +# Path to the initial condition file. User has to supply. +init_cond_path = /global/cfs/cdirs/fanssie/MALI_projects/ISMIP6-2300/initial_conditions/AIS_4to20km_20230105/relaxation_0TGmelt_10yr/relaxed_10yrs_4km.nc + +# Path to the file for the basal melt parametrization coefficients. +melt_params_path = /global/cfs/cdirs/m4288/users/trhille/ISMIP7/test_processing/AIS/climatology/basin_and_coeff_DeltaT_quadratic_non_local_gamma14500.nc + +# Path to the region mask file +region_mask_path = /global/cfs/cdirs/fanssie/MALI_projects/ISMIP6-2300/initial_conditions/AIS_4to20km_20230105/AIS_4to20km_r01_20220907.regionMask_ismip6.nc + +# Path to the ocean thermal forcing climatology file for CTRL2015 runs. +# This is the constant-climate 30-year mean (2000-2029) thermal forcing. +# User has to supply if running ctrl experiments. +ctrl_tf_climatology_path = NotAvailable + +# Path to the atmosphere climatology files for CTRL2015 runs. +# Directory containing constant-climate SMB, temperature, etc. +# User has to supply if running ctrl experiments. +ctrl_atm_climatology_path = NotAvailable + +# Path to OCX (observationally constrained experiment) forcing. +# User has to supply if running the ocx experiment. +ocx_forcing_path = NotAvailable + +# Calving method to use. Options: restore, von_mises +calving_method = restore + +# Path to the file containing the von Mises parameter fields. +# Only required if calving_method is set to 'von_mises'. +von_mises_parameter_path = NotAvailable + +# Whether face melting should be included in the runs +use_face_melting = true + +# True if running coupled MALI-sea level model simulation +sea_level_model = false + +# Path to the directory containing globally defined ice thickness +# field for the sea-level model +slm_input_ice = NotAvailable + +# Path to the directory containing earth model for the sea-level model +slm_input_earth = NotAvailable + +# Earth structure profile filename +slm_earth_structure = prem_512.l60K2C.sum18p6.dum19p2.tz19p4.lm22 + +# Path to the directory containing other SLM input files +slm_input_others = NotAvailable + +# Number of gauss-legendre nodes in latitude (typically multiple of 512) +nglv = 2048 From f126811178b566a9309bae1bf8a1027bc484b4e2 Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Tue, 9 Jun 2026 13:48:24 -0700 Subject: [PATCH 05/24] Symlink to forcing files instead of copying them to run directory Symlink to forcing files instead of copying them to run directory. This saves lots of time when running `compass setup` because some forcing files are dozens of GB in size. --- .../ismip7_ais/set_up_experiment.py | 55 ++++++++++++------- .../ismip7_gris/set_up_experiment.py | 55 ++++++++++++------- 2 files changed, 72 insertions(+), 38 deletions(-) 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 9ad6521e25..c939dbe56a 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 @@ -1,6 +1,5 @@ import glob import os -import shutil import sys from importlib import resources @@ -90,26 +89,34 @@ def setup(self): # noqa: C901 forcing_dir = os.path.join(forcing_basepath, f"{model}_{scenario}") - # --- Copy input files --- + # --- Symlink input files --- if is_historical: - shutil.copy(init_cond_path, self.work_dir) - shutil.copy(melt_params_path, self.work_dir) - shutil.copy(region_mask_path, self.work_dir) - - # --- Find and copy forcing files --- + os.symlink(init_cond_path, + os.path.join(self.work_dir, + os.path.basename(init_cond_path))) + os.symlink(melt_params_path, + os.path.join(self.work_dir, + os.path.basename(melt_params_path))) + os.symlink(region_mask_path, + os.path.join(self.work_dir, + os.path.basename(region_mask_path))) + + # --- Find and symlink forcing files --- if scenario == 'ctrl': # Control run: use climatology files ctrl_tf_path = section.get('ctrl_tf_climatology_path') ctrl_atm_path = section.get('ctrl_atm_climatology_path') tf_fname = os.path.split(ctrl_tf_path)[-1] - shutil.copy(ctrl_tf_path, self.work_dir) + os.symlink(ctrl_tf_path, + os.path.join(self.work_dir, tf_fname)) # Find atmosphere climatology files smb_files = glob.glob(os.path.join(ctrl_atm_path, '*SMB*.nc')) smb_files = [f for f in smb_files if 'gradient' not in f] if len(smb_files) == 1: smb_fname = os.path.split(smb_files[0])[-1] - shutil.copy(smb_files[0], self.work_dir) + os.symlink(smb_files[0], + os.path.join(self.work_dir, smb_fname)) else: sys.exit(f"ERROR: Expected 1 SMB climatology file in " f"{ctrl_atm_path}, found {len(smb_files)}") @@ -119,7 +126,8 @@ def setup(self): # noqa: C901 temp_files = [f for f in temp_files if 'gradient' not in f] if len(temp_files) == 1: temp_fname = os.path.split(temp_files[0])[-1] - shutil.copy(temp_files[0], self.work_dir) + os.symlink(temp_files[0], + os.path.join(self.work_dir, temp_fname)) else: sys.exit(f"ERROR: Expected 1 temperature climatology file in " f"{ctrl_atm_path}, found {len(temp_files)}") @@ -128,7 +136,8 @@ def setup(self): # noqa: C901 os.path.join(ctrl_atm_path, '*runoff*.nc')) if len(runoff_files) == 1: runoff_fname = os.path.split(runoff_files[0])[-1] - shutil.copy(runoff_files[0], self.work_dir) + os.symlink(runoff_files[0], + os.path.join(self.work_dir, runoff_fname)) else: runoff_fname = '' # runoff may not exist for ctrl @@ -137,14 +146,16 @@ def setup(self): # noqa: C901 smb_grad_fname = '' if len(smb_grad_files) == 1: smb_grad_fname = os.path.split(smb_grad_files[0])[-1] - shutil.copy(smb_grad_files[0], self.work_dir) + os.symlink(smb_grad_files[0], + os.path.join(self.work_dir, smb_grad_fname)) temp_grad_files = glob.glob( os.path.join(ctrl_atm_path, '*temperature_gradient*.nc')) temp_grad_fname = '' if len(temp_grad_files) == 1: temp_grad_fname = os.path.split(temp_grad_files[0])[-1] - shutil.copy(temp_grad_files[0], self.work_dir) + os.symlink(temp_grad_files[0], + os.path.join(self.work_dir, temp_grad_fname)) else: # Standard or OCX experiment: find forcing in forcing_dir @@ -157,7 +168,8 @@ def setup(self): # noqa: C901 smb_list = [f for f in smb_list if 'gradient' not in f] if len(smb_list) == 1: smb_fname = os.path.split(smb_list[0])[-1] - shutil.copy(smb_list[0], self.work_dir) + os.symlink(smb_list[0], + os.path.join(self.work_dir, smb_fname)) else: sys.exit(f"ERROR: Expected 1 SMB file at {smb_search}, " f"found {len(smb_list)}: {smb_list}") @@ -168,7 +180,8 @@ def setup(self): # noqa: C901 temp_list = [f for f in temp_list if 'gradient' not in f] if len(temp_list) == 1: temp_fname = os.path.split(temp_list[0])[-1] - shutil.copy(temp_list[0], self.work_dir) + os.symlink(temp_list[0], + os.path.join(self.work_dir, temp_fname)) else: sys.exit(f"ERROR: Expected 1 temperature file at " f"{temp_search}, found {len(temp_list)}") @@ -179,7 +192,8 @@ def setup(self): # noqa: C901 runoff_fname = '' if len(runoff_list) == 1: runoff_fname = os.path.split(runoff_list[0])[-1] - shutil.copy(runoff_list[0], self.work_dir) + os.symlink(runoff_list[0], + os.path.join(self.work_dir, runoff_fname)) # SMB gradient (lapse rate) smb_grad_search = os.path.join(atm_dir, '*SMB_gradient_*.nc') @@ -187,7 +201,8 @@ def setup(self): # noqa: C901 smb_grad_fname = '' if len(smb_grad_list) == 1: smb_grad_fname = os.path.split(smb_grad_list[0])[-1] - shutil.copy(smb_grad_list[0], self.work_dir) + os.symlink(smb_grad_list[0], + os.path.join(self.work_dir, smb_grad_fname)) # Temperature gradient (lapse rate) temp_grad_search = os.path.join(atm_dir, @@ -196,14 +211,16 @@ def setup(self): # noqa: C901 temp_grad_fname = '' if len(temp_grad_list) == 1: temp_grad_fname = os.path.split(temp_grad_list[0])[-1] - shutil.copy(temp_grad_list[0], self.work_dir) + os.symlink(temp_grad_list[0], + os.path.join(self.work_dir, temp_grad_fname)) # Thermal forcing tf_search = os.path.join(ocean_dir, '*thermal_forcing_*.nc') tf_list = glob.glob(tf_search) if len(tf_list) == 1: tf_fname = os.path.split(tf_list[0])[-1] - shutil.copy(tf_list[0], self.work_dir) + os.symlink(tf_list[0], + os.path.join(self.work_dir, tf_fname)) else: sys.exit(f"ERROR: Expected 1 TF file at {tf_search}, " f"found {len(tf_list)}: {tf_list}") diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py b/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py index 9739cdb59e..7520d7a6e0 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py +++ b/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py @@ -1,6 +1,5 @@ import glob import os -import shutil import sys from compass.job import write_job_script @@ -81,24 +80,32 @@ def setup(self): # noqa: C901 forcing_dir = os.path.join(forcing_basepath, f"{model}_{scenario}") - # --- Copy input files --- + # --- Symlink input files --- if is_historical: - shutil.copy(init_cond_path, self.work_dir) - shutil.copy(melt_params_path, self.work_dir) - shutil.copy(region_mask_path, self.work_dir) - - # --- Find and copy forcing files --- + os.symlink(init_cond_path, + os.path.join(self.work_dir, + os.path.basename(init_cond_path))) + os.symlink(melt_params_path, + os.path.join(self.work_dir, + os.path.basename(melt_params_path))) + os.symlink(region_mask_path, + os.path.join(self.work_dir, + os.path.basename(region_mask_path))) + + # --- Find and symlink forcing files --- if scenario == 'ctrl': ctrl_tf_path = section.get('ctrl_tf_climatology_path') ctrl_atm_path = section.get('ctrl_atm_climatology_path') tf_fname = os.path.split(ctrl_tf_path)[-1] - shutil.copy(ctrl_tf_path, self.work_dir) + os.symlink(ctrl_tf_path, + os.path.join(self.work_dir, tf_fname)) smb_files = glob.glob(os.path.join(ctrl_atm_path, '*SMB*.nc')) smb_files = [f for f in smb_files if 'gradient' not in f] if len(smb_files) == 1: smb_fname = os.path.split(smb_files[0])[-1] - shutil.copy(smb_files[0], self.work_dir) + os.symlink(smb_files[0], + os.path.join(self.work_dir, smb_fname)) else: sys.exit(f"ERROR: Expected 1 SMB climatology file in " f"{ctrl_atm_path}, found {len(smb_files)}") @@ -108,7 +115,8 @@ def setup(self): # noqa: C901 temp_files = [f for f in temp_files if 'gradient' not in f] if len(temp_files) == 1: temp_fname = os.path.split(temp_files[0])[-1] - shutil.copy(temp_files[0], self.work_dir) + os.symlink(temp_files[0], + os.path.join(self.work_dir, temp_fname)) else: sys.exit(f"ERROR: Expected 1 temperature climatology file in " f"{ctrl_atm_path}, found {len(temp_files)}") @@ -118,21 +126,24 @@ def setup(self): # noqa: C901 runoff_fname = '' if len(runoff_files) == 1: runoff_fname = os.path.split(runoff_files[0])[-1] - shutil.copy(runoff_files[0], self.work_dir) + os.symlink(runoff_files[0], + os.path.join(self.work_dir, runoff_fname)) smb_grad_files = glob.glob( os.path.join(ctrl_atm_path, '*SMB_gradient*.nc')) smb_grad_fname = '' if len(smb_grad_files) == 1: smb_grad_fname = os.path.split(smb_grad_files[0])[-1] - shutil.copy(smb_grad_files[0], self.work_dir) + os.symlink(smb_grad_files[0], + os.path.join(self.work_dir, smb_grad_fname)) temp_grad_files = glob.glob( os.path.join(ctrl_atm_path, '*temperature_gradient*.nc')) temp_grad_fname = '' if len(temp_grad_files) == 1: temp_grad_fname = os.path.split(temp_grad_files[0])[-1] - shutil.copy(temp_grad_files[0], self.work_dir) + os.symlink(temp_grad_files[0], + os.path.join(self.work_dir, temp_grad_fname)) else: atm_dir = os.path.join(forcing_dir, 'atmosphere') @@ -143,7 +154,8 @@ def setup(self): # noqa: C901 smb_list = [f for f in smb_list if 'gradient' not in f] if len(smb_list) == 1: smb_fname = os.path.split(smb_list[0])[-1] - shutil.copy(smb_list[0], self.work_dir) + os.symlink(smb_list[0], + os.path.join(self.work_dir, smb_fname)) else: sys.exit(f"ERROR: Expected 1 SMB file at {smb_search}, " f"found {len(smb_list)}") @@ -153,7 +165,8 @@ def setup(self): # noqa: C901 temp_list = [f for f in temp_list if 'gradient' not in f] if len(temp_list) == 1: temp_fname = os.path.split(temp_list[0])[-1] - shutil.copy(temp_list[0], self.work_dir) + os.symlink(temp_list[0], + os.path.join(self.work_dir, temp_fname)) else: sys.exit(f"ERROR: Expected 1 temperature file at " f"{temp_search}, found {len(temp_list)}") @@ -163,14 +176,16 @@ def setup(self): # noqa: C901 runoff_fname = '' if len(runoff_list) == 1: runoff_fname = os.path.split(runoff_list[0])[-1] - shutil.copy(runoff_list[0], self.work_dir) + os.symlink(runoff_list[0], + os.path.join(self.work_dir, runoff_fname)) smb_grad_search = os.path.join(atm_dir, '*SMB_gradient_*.nc') smb_grad_list = glob.glob(smb_grad_search) smb_grad_fname = '' if len(smb_grad_list) == 1: smb_grad_fname = os.path.split(smb_grad_list[0])[-1] - shutil.copy(smb_grad_list[0], self.work_dir) + os.symlink(smb_grad_list[0], + os.path.join(self.work_dir, smb_grad_fname)) temp_grad_search = os.path.join(atm_dir, '*temperature_gradient_*.nc') @@ -178,14 +193,16 @@ def setup(self): # noqa: C901 temp_grad_fname = '' if len(temp_grad_list) == 1: temp_grad_fname = os.path.split(temp_grad_list[0])[-1] - shutil.copy(temp_grad_list[0], self.work_dir) + os.symlink(temp_grad_list[0], + os.path.join(self.work_dir, temp_grad_fname)) # GrIS uses 2D thermal forcing tf_search = os.path.join(ocean_dir, '*thermal_forcing_*.nc') tf_list = glob.glob(tf_search) if len(tf_list) == 1: tf_fname = os.path.split(tf_list[0])[-1] - shutil.copy(tf_list[0], self.work_dir) + os.symlink(tf_list[0], + os.path.join(self.work_dir, tf_fname)) else: sys.exit(f"ERROR: Expected 1 TF file at {tf_search}, " f"found {len(tf_list)}") From 258d2262bb359c8fa377f7a8fcca6a1ccc48f395 Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Tue, 9 Jun 2026 14:11:43 -0700 Subject: [PATCH 06/24] Begin historical runs in 2000 instead of 1850 Begin historical runs in 2000 instead of 1850 and set proper reference_time for each input field. --- .../landice/tests/ismip7_run/ismip7_ais/__init__.py | 4 ++-- .../ismip7_run/ismip7_ais/streams.landice.template | 6 +++--- .../landice/tests/ismip7_run/ismip7_gris/__init__.py | 4 ++-- .../ismip7_run/ismip7_gris/streams.landice.template | 12 ++++++------ 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/__init__.py b/compass/landice/tests/ismip7_run/ismip7_ais/__init__.py index ba229244fe..c6e3a41c94 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': '1850-01-01_00:00:00', + 'start_time': '2000-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': '1850-01-01_00:00:00', + 'start_time': '2000-01-01_00:00:00', 'stop_time': '2015-01-01_00:00:00', 'is_historical': True}, 'ssp370_CESM2-WACCM': { 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 cfb4b7db8f..014a711aee 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template +++ b/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template @@ -31,7 +31,7 @@ type="input" filename_template="{{ input_file_SMB_forcing }}" input_interval="{{ forcing_interval_monthly }}" - reference_time="2000-01-01_00:00:00" + reference_time="2000-01-15_00:00:00" runtime_format="single_file"> @@ -40,7 +40,7 @@ type="input" filename_template="{{ input_file_temperature_forcing }}" input_interval="{{ forcing_interval_monthly }}" - reference_time="2000-01-01_00:00:00" + reference_time="2000-01-15_00:00:00" runtime_format="single_file"> @@ -77,7 +77,7 @@ type="input" filename_template="{{ input_file_runoff_forcing }}" input_interval="{{ forcing_interval_monthly }}" - reference_time="2000-01-01_00:00:00" + reference_time="2000-01-15_00:00:00" runtime_format="single_file"> diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py b/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py index 7874b7c25c..6ad5fbbe14 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py +++ b/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py @@ -9,12 +9,12 @@ EXPERIMENTS = { 'historical_CESM2-WACCM': { 'scenario': 'historical', 'model': 'CESM2-WACCM', - 'start_time': '1850-01-01_00:00:00', + 'start_time': '2000-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': '1850-01-01_00:00:00', + 'start_time': '2000-01-01_00:00:00', 'stop_time': '2015-01-01_00:00:00', 'is_historical': True}, 'ssp370_CESM2-WACCM': { diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template b/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template index a48003c84d..1652b057a4 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template +++ b/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template @@ -31,7 +31,7 @@ type="input" filename_template="{{ input_file_SMB_forcing }}" input_interval="{{ forcing_interval_monthly }}" - reference_time="2000-01-01_00:00:00" + reference_time="2000-01-15_00:00:00" runtime_format="single_file"> @@ -40,7 +40,7 @@ type="input" filename_template="{{ input_file_temperature_forcing }}" input_interval="{{ forcing_interval_monthly }}" - reference_time="2000-01-01_00:00:00" + reference_time="2000-01-15_00:00:00" runtime_format="single_file"> @@ -49,7 +49,7 @@ type="input" filename_template="{{ input_file_smb_gradient_forcing }}" input_interval="{{ forcing_interval_annual }}" - reference_time="2000-01-01_00:00:00" + reference_time="2000-01-15_00:00:00" runtime_format="single_file"> @@ -58,7 +58,7 @@ type="input" filename_template="{{ input_file_temperature_gradient_forcing }}" input_interval="{{ forcing_interval_annual }}" - reference_time="2000-01-01_00:00:00" + reference_time="2000-01-15_00:00:00" runtime_format="single_file"> @@ -67,7 +67,7 @@ type="input" filename_template="{{ input_file_TF_forcing }}" input_interval="{{ forcing_interval_monthly }}" - reference_time="2000-01-01_00:00:00" + reference_time="2000-01-15_00:00:00" runtime_format="single_file"> @@ -76,7 +76,7 @@ type="input" filename_template="{{ input_file_runoff_forcing }}" input_interval="{{ forcing_interval_monthly }}" - reference_time="2000-01-01_00:00:00" + reference_time="2000-01-15_00:00:00" runtime_format="single_file"> From b1d7ce14f4054f10acf19a805fe635c94d13118e Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Tue, 9 Jun 2026 14:13:09 -0700 Subject: [PATCH 07/24] Remove lapse rate fields from streams until they are added in MALI Remove lapse rate fields from streams for now, since they do not yet exist in MALI. Once they are added, revert this commit. --- .../ismip7_ais/streams.landice.template | 18 ------------------ .../ismip7_gris/streams.landice.template | 18 ------------------ 2 files changed, 36 deletions(-) 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 014a711aee..5f7c3aa418 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template +++ b/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template @@ -45,24 +45,6 @@ - - - - - - - - - - - - - - - - Date: Tue, 9 Jun 2026 14:46:20 -0700 Subject: [PATCH 08/24] Set maximum time step to one month Set maximum time step to one month, consistent with forcing intervals. --- compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice | 2 +- compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice b/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice index ceaf39f281..b71ed2f11c 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice +++ b/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice @@ -51,7 +51,7 @@ config_max_adaptive_timestep = 3.154e7 config_adaptive_timestep_CFL_fraction = 0.8 config_adaptive_timestep_include_DCFL = .false. - config_adaptive_timestep_force_interval = '0001-00-00_00:00:00' + config_adaptive_timestep_force_interval = '0000-01-00_00:00:00' config_do_restart = .true. config_restart_timestamp_name = 'restart_timestamp' diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice b/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice index 36c5cdb0d0..1e636ac3c7 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice +++ b/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice @@ -48,7 +48,7 @@ config_max_adaptive_timestep = 3.154e7 config_adaptive_timestep_CFL_fraction = 0.8 config_adaptive_timestep_include_DCFL = .false. - config_adaptive_timestep_force_interval = '0001-00-00_00:00:00' + config_adaptive_timestep_force_interval = '0000-01-00_00:00:00' config_do_restart = .true. config_restart_timestamp_name = 'restart_timestamp' From a88974f8e02f403c8c043190100044f8fb18b488 Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Tue, 9 Jun 2026 15:01:45 -0700 Subject: [PATCH 09/24] Begin simulations on Jan 15 instead of Jan 1 Begin simulations on Jan 15 instead of Jan 1 to be consistent with time stamps for most forcing. Note that this is not consistent with annual ocean thermal forcing for AIS. --- .../tests/ismip7_run/ismip7_ais/__init__.py | 22 +++++++++---------- .../ismip7_ais/set_up_experiment.py | 6 ++--- .../tests/ismip7_run/ismip7_gris/__init__.py | 22 +++++++++---------- .../ismip7_gris/set_up_experiment.py | 6 ++--- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/__init__.py b/compass/landice/tests/ismip7_run/ismip7_ais/__init__.py index c6e3a41c94..2165c03918 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/__init__.py +++ b/compass/landice/tests/ismip7_run/ismip7_ais/__init__.py @@ -12,57 +12,57 @@ EXPERIMENTS = { 'historical_CESM2-WACCM': { 'scenario': 'historical', 'model': 'CESM2-WACCM', - 'start_time': '2000-01-01_00:00:00', + 'start_time': '2000-01-15_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': '2000-01-15_00:00:00', 'stop_time': '2015-01-01_00:00:00', 'is_historical': True}, 'ssp370_CESM2-WACCM': { 'scenario': 'ssp370', 'model': 'CESM2-WACCM', - 'start_time': '2015-01-01_00:00:00', + 'start_time': '2015-01-15_00:00:00', 'stop_time': '2101-01-01_00:00:00', 'is_historical': False}, 'ssp370_MRI-ESM2-0': { 'scenario': 'ssp370', 'model': 'MRI-ESM2-0', - 'start_time': '2015-01-01_00:00:00', + 'start_time': '2015-01-15_00:00:00', 'stop_time': '2101-01-01_00:00:00', 'is_historical': False}, 'ssp126_CESM2-WACCM': { 'scenario': 'ssp126', 'model': 'CESM2-WACCM', - 'start_time': '2015-01-01_00:00:00', + 'start_time': '2015-01-15_00:00:00', 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ssp126_MRI-ESM2-0': { 'scenario': 'ssp126', 'model': 'MRI-ESM2-0', - 'start_time': '2015-01-01_00:00:00', + 'start_time': '2015-01-15_00:00:00', 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ssp585_CESM2-WACCM': { 'scenario': 'ssp585', 'model': 'CESM2-WACCM', - 'start_time': '2015-01-01_00:00:00', + 'start_time': '2015-01-15_00:00:00', 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ssp585_MRI-ESM2-0': { 'scenario': 'ssp585', 'model': 'MRI-ESM2-0', - 'start_time': '2015-01-01_00:00:00', + 'start_time': '2015-01-15_00:00:00', 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ctrl_CESM2-WACCM': { 'scenario': 'ctrl', 'model': 'CESM2-WACCM', - 'start_time': '2015-01-01_00:00:00', + 'start_time': '2015-01-15_00:00:00', 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ctrl_MRI-ESM2-0': { 'scenario': 'ctrl', 'model': 'MRI-ESM2-0', - 'start_time': '2015-01-01_00:00:00', + 'start_time': '2015-01-15_00:00:00', 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ocx': { 'scenario': 'ocx', 'model': None, - 'start_time': '1990-01-01_00:00:00', + 'start_time': '1990-01-15_00:00:00', 'stop_time': '2026-01-01_00:00:00', 'is_historical': True}, } 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 c939dbe56a..d49041ee31 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 @@ -358,11 +358,11 @@ def setup(self): # noqa: C901 # --- Symlink restart for projections/ctrl --- if not is_historical: hist_exp = f"historical_{model}" - os.symlink(f"../{hist_exp}/rst.2015-01-01.nc", - os.path.join(self.work_dir, 'rst.2015-01-01.nc')) + os.symlink(f"../{hist_exp}/rst.2015-01-15.nc", + os.path.join(self.work_dir, 'rst.2015-01-15.nc')) with open(os.path.join(self.work_dir, "restart_timestamp"), "w") as text_file: - text_file.write("2015-01-01_00:00:00") + text_file.write("2015-01-15_00:00:00") # --- Add albany yaml, graph file, load script, job script --- self.add_input_file( diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py b/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py index 6ad5fbbe14..10f3d92bfd 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py +++ b/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py @@ -9,57 +9,57 @@ EXPERIMENTS = { 'historical_CESM2-WACCM': { 'scenario': 'historical', 'model': 'CESM2-WACCM', - 'start_time': '2000-01-01_00:00:00', + 'start_time': '2000-01-15_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': '2000-01-15_00:00:00', 'stop_time': '2015-01-01_00:00:00', 'is_historical': True}, 'ssp370_CESM2-WACCM': { 'scenario': 'ssp370', 'model': 'CESM2-WACCM', - 'start_time': '2015-01-01_00:00:00', + 'start_time': '2015-01-15_00:00:00', 'stop_time': '2101-01-01_00:00:00', 'is_historical': False}, 'ssp370_MRI-ESM2-0': { 'scenario': 'ssp370', 'model': 'MRI-ESM2-0', - 'start_time': '2015-01-01_00:00:00', + 'start_time': '2015-01-15_00:00:00', 'stop_time': '2101-01-01_00:00:00', 'is_historical': False}, 'ssp126_CESM2-WACCM': { 'scenario': 'ssp126', 'model': 'CESM2-WACCM', - 'start_time': '2015-01-01_00:00:00', + 'start_time': '2015-01-15_00:00:00', 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ssp126_MRI-ESM2-0': { 'scenario': 'ssp126', 'model': 'MRI-ESM2-0', - 'start_time': '2015-01-01_00:00:00', + 'start_time': '2015-01-15_00:00:00', 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ssp585_CESM2-WACCM': { 'scenario': 'ssp585', 'model': 'CESM2-WACCM', - 'start_time': '2015-01-01_00:00:00', + 'start_time': '2015-01-15_00:00:00', 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ssp585_MRI-ESM2-0': { 'scenario': 'ssp585', 'model': 'MRI-ESM2-0', - 'start_time': '2015-01-01_00:00:00', + 'start_time': '2015-01-15_00:00:00', 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ctrl_CESM2-WACCM': { 'scenario': 'ctrl', 'model': 'CESM2-WACCM', - 'start_time': '2015-01-01_00:00:00', + 'start_time': '2015-01-15_00:00:00', 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ctrl_MRI-ESM2-0': { 'scenario': 'ctrl', 'model': 'MRI-ESM2-0', - 'start_time': '2015-01-01_00:00:00', + 'start_time': '2015-01-15_00:00:00', 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ocx': { 'scenario': 'ocx', 'model': None, - 'start_time': '1990-01-01_00:00:00', + 'start_time': '1990-01-15_00:00:00', 'stop_time': '2026-01-01_00:00:00', 'is_historical': True}, } diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py b/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py index 7520d7a6e0..bd4f2dc726 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py +++ b/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py @@ -286,11 +286,11 @@ def setup(self): # noqa: C901 # --- Symlink restart for projections/ctrl --- if not is_historical: hist_exp = f"historical_{model}" - os.symlink(f"../{hist_exp}/rst.2015-01-01.nc", - os.path.join(self.work_dir, 'rst.2015-01-01.nc')) + os.symlink(f"../{hist_exp}/rst.2015-01-15.nc", + os.path.join(self.work_dir, 'rst.2015-01-15.nc')) with open(os.path.join(self.work_dir, "restart_timestamp"), "w") as text_file: - text_file.write("2015-01-01_00:00:00") + text_file.write("2015-01-15_00:00:00") # --- Add albany yaml, graph file, load script, job script --- self.add_input_file( From 866ec8b0c59557ea21c9f6f40775f6431d7f7950 Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Wed, 10 Jun 2026 09:48:14 -0700 Subject: [PATCH 10/24] Always use face-melting Remove the option to turn face-melting off in the .cfg files. We always want to have face-melting turned on for ISMIP7, and having this option in the .cfg file exposes us to user error unnecessarily. --- .../ismip7_run/ismip7_ais/ismip7_ais.cfg | 3 -- .../ismip7_run/ismip7_ais/ismip7_ais_test.cfg | 3 -- .../ismip7_run/ismip7_ais/namelist.landice | 3 +- .../ismip7_ais/set_up_experiment.py | 14 -------- .../ismip7_run/ismip7_ais/streams.faceMelting | 34 ------------------- .../ismip7_run/ismip7_gris/ismip7_gris.cfg | 3 -- .../ismip7_run/ismip7_gris/namelist.landice | 3 +- .../ismip7_gris/set_up_experiment.py | 8 ----- 8 files changed, 4 insertions(+), 67 deletions(-) delete mode 100644 compass/landice/tests/ismip7_run/ismip7_ais/streams.faceMelting 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 ab88bd0b80..e229d7b8d8 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais.cfg +++ b/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais.cfg @@ -56,9 +56,6 @@ calving_method = restore # Only required if calving_method is set to 'von_mises'. von_mises_parameter_path = NotAvailable -# Whether face melting should be included in the runs -use_face_melting = false - # True if running coupled MALI-sea level model simulation sea_level_model = false diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg b/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg index 34491b1058..49b282b0cb 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg +++ b/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg @@ -56,9 +56,6 @@ calving_method = restore # Only required if calving_method is set to 'von_mises'. von_mises_parameter_path = NotAvailable -# Whether face melting should be included in the runs -use_face_melting = true - # 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 b71ed2f11c..4b91cc4bf1 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice +++ b/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice @@ -33,7 +33,8 @@ config_basal_heat_flux_source = 'file' config_basal_mass_bal_float = 'ismip6' - config_front_mass_bal_grounded = 'none' + config_front_mass_bal_grounded = 'ismip6' + config_use_3d_thermal_forcing_for_face_melt = .true. config_add_ocean_thermal_forcing = 0.0 config_ice_density = 910.0 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 d49041ee31..4c6170b244 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 @@ -61,7 +61,6 @@ def setup(self): # noqa: C901 region_mask_path = section.get('region_mask_path') region_mask_fname = os.path.split(region_mask_path)[-1] calving_method = section.get('calving_method') - use_face_melting = section.getboolean('use_face_melting') sea_level_model = section.getboolean('sea_level_model') exp_info = self.exp_info @@ -261,11 +260,6 @@ def setup(self): # noqa: C901 out_name='streams.landice', template_replacements=stream_replacements) - if use_face_melting: - self.add_streams_file( - resource_location, 'streams.faceMelting', - out_name='streams.landice') - # --- Set up namelist --- self.add_namelist_file( resource_location, 'namelist.landice', @@ -307,14 +301,6 @@ def setup(self): # noqa: C901 out_name='streams.landice', template_replacements=vM_stream_replacements) - # Face melting options - if use_face_melting: - options = { - 'config_front_mass_bal_grounded': "'ismip6'", - 'config_use_3d_thermal_forcing_for_face_melt': '.true.'} - 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.faceMelting b/compass/landice/tests/ismip7_run/ismip7_ais/streams.faceMelting deleted file mode 100644 index 8d387bc063..0000000000 --- a/compass/landice/tests/ismip7_run/ismip7_ais/streams.faceMelting +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris.cfg b/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris.cfg index a7d2de6db7..6f57581d5e 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris.cfg +++ b/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris.cfg @@ -41,6 +41,3 @@ calving_method = von_mises # Path to the von Mises parameter fields. von_mises_parameter_path = NotAvailable - -# Whether face melting should be included -use_face_melting = false diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice b/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice index 1e636ac3c7..6a38f22892 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice +++ b/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice @@ -30,7 +30,8 @@ config_basal_heat_flux_source = 'file' config_basal_mass_bal_float = 'ismip6' - config_front_mass_bal_grounded = 'none' + config_front_mass_bal_grounded = 'ismip6' + config_use_3d_thermal_forcing_for_face_melt = .false. config_add_ocean_thermal_forcing = 0.0 config_ice_density = 910.0 diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py b/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py index bd4f2dc726..f8561e7a10 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py +++ b/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py @@ -57,7 +57,6 @@ def setup(self): # noqa: C901 region_mask_path = section.get('region_mask_path') region_mask_fname = os.path.split(region_mask_path)[-1] calving_method = section.get('calving_method') - use_face_melting = section.getboolean('use_face_melting') exp_info = self.exp_info scenario = exp_info['scenario'] @@ -276,13 +275,6 @@ def setup(self): # noqa: C901 out_name='streams.landice', template_replacements=vM_stream_replacements) - if use_face_melting: - options = { - 'config_front_mass_bal_grounded': "'ismip6'", - 'config_use_3d_thermal_forcing_for_face_melt': '.false.'} - self.add_namelist_options(options=options, - out_name='namelist.landice') - # --- Symlink restart for projections/ctrl --- if not is_historical: hist_exp = f"historical_{model}" From 3711b914143a41186bff9cbbf3d2e713bbe7d2f7 Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Wed, 10 Jun 2026 09:57:21 -0700 Subject: [PATCH 11/24] Update streams to include time-averaged flux fields. Add time-averaged flux fields to annual output stream. --- .../ismip7_run/ismip7_ais/namelist.landice | 2 ++ .../ismip7_ais/streams.landice.template | 30 +------------------ .../ismip7_run/ismip7_gris/namelist.landice | 2 ++ .../ismip7_gris/streams.landice.template | 30 +------------------ 4 files changed, 6 insertions(+), 58 deletions(-) diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice b/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice index 4b91cc4bf1..485b23e83c 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice +++ b/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice @@ -53,6 +53,8 @@ config_adaptive_timestep_CFL_fraction = 0.8 config_adaptive_timestep_include_DCFL = .false. config_adaptive_timestep_force_interval = '0000-01-00_00:00:00' + config_timeaveraging_interval = '0001-00-00_00:00:00' + config_enable_timeAvgRestarts = .false. config_do_restart = .true. config_restart_timestamp_name = 'restart_timestamp' 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 5f7c3aa418..7c5230d61a 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template +++ b/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template @@ -103,35 +103,7 @@ - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - + Date: Wed, 10 Jun 2026 12:50:21 -0700 Subject: [PATCH 12/24] Set up Greenland-specific options For Greenland, we use the depth-integrated solver with Budd friction (hydrostatic N and q=1/3), crevasse-depth calving with a stress multiplier factor of 5, RK2 time integration, and 3rd order FCT. --- .../ismip7_run/ismip7_ais/namelist.landice | 1 + .../ismip7_run/ismip7_gris/albany_input.yaml | 13 +++--- .../ismip7_run/ismip7_gris/ismip7_gris.cfg | 2 +- .../ismip7_gris/ismip7_gris_test.cfg | 43 +++++++++++++++++++ .../ismip7_run/ismip7_gris/namelist.landice | 21 ++++++--- .../ismip7_gris/streams.landice.template | 10 ----- 6 files changed, 65 insertions(+), 25 deletions(-) create mode 100644 compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris_test.cfg diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice b/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice index 485b23e83c..03470752dc 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice +++ b/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice @@ -2,6 +2,7 @@ config_do_velocity_reconstruction_for_external_dycore = .false. config_unrealistic_velocity = 00.00159 config_nonconvergence_error = .false. + config_flowParamA_calculation = 'PB1982' config_thickness_advection = 'fo' config_tracer_advection = 'fo' diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/albany_input.yaml b/compass/landice/tests/ismip7_run/ismip7_gris/albany_input.yaml index e1a4dcd7c4..bb1a79a93b 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/albany_input.yaml +++ b/compass/landice/tests/ismip7_run/ismip7_gris/albany_input.yaml @@ -2,6 +2,7 @@ --- ANONYMOUS: Problem: + Depth Integrated Model: true LandIce Field Norm: sliding_velocity_basalside: Regularization Type: Given Value @@ -10,14 +11,12 @@ ANONYMOUS: BC 0: Basal Friction Coefficient: Type: Power Law - Power Exponent: 0.2 + Power Exponent: 0.333333333 Mu Type: Field - Effective Pressure Type: Constant - Effective Pressure: 1.0 - # Zero Effective Pressure On Floating Ice At Nodes: true - Zero Beta On Floating Ice: true - - Cubature Degree: 8 + Effective Pressure Type: Hydrostatic Computed At Nodes + Zero Effective Pressure On Floating Ice At Nodes: true + Zero Beta On Floating Ice: false + Use Pressurized Bed Above Sea Level: false # Discretization Description Discretization: diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris.cfg b/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris.cfg index 6f57581d5e..b108ee6463 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris.cfg +++ b/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris.cfg @@ -37,7 +37,7 @@ ctrl_atm_climatology_path = NotAvailable ocx_forcing_path = NotAvailable # Calving method to use. Options: restore, von_mises -calving_method = von_mises +calving_method = restore # Path to the von Mises parameter fields. von_mises_parameter_path = NotAvailable diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris_test.cfg b/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris_test.cfg new file mode 100644 index 0000000000..2d0847046f --- /dev/null +++ b/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris_test.cfg @@ -0,0 +1,43 @@ +[ismip7_run_gris] + +# List of experiments to set up. +# Can be "all", "historical", "projections", "ctrl", or a +# comma-delimited list of experiment names. +exp_list = historical_CESM2-WACCM + +# Number of tasks to use for each run +ntasks = 512 + +# Value to use for config_pio_stride. +pio_stride = 128 + +# Base path to the pre-processed ISMIP7 forcing files. +# Expected layout: +# {forcing_basepath}/{model}_{scenario}/atmosphere/ +# {forcing_basepath}/{model}_{scenario}/ocean_thermal_forcing/ +# User has to supply. +forcing_basepath = /global/cfs/cdirs/m4288/users/trhille/ISMIP7/test_processing/GIS + +# Path to the initial condition file. User has to supply. +init_cond_path = /global/cfs/cdirs/fanssie/MALI_input_files/GIS_1to10km_r02/GIS_1to10km_r02_20230202_m3.nc + +# Path to the file for the basal melt parametrization coefficients. +melt_params_path = NotAvailable + +# Path to the region mask file +region_mask_path = /global/cfs/cdirs/fanssie/MALI_input_files/GIS_1to10km_r02/GIS_1to10km_r02_20230202_ismip6_regionMasks.nc + +# Path to the ocean thermal forcing climatology file for CTRL2015 runs. +ctrl_tf_climatology_path = NotAvailable + +# Path to the atmosphere climatology files for CTRL2015 runs. +ctrl_atm_climatology_path = NotAvailable + +# Path to OCX forcing. +ocx_forcing_path = NotAvailable + +# Calving method to use. Options: restore, von_mises +calving_method = restore + +# Path to the von Mises parameter fields. +von_mises_parameter_path = NotAvailable diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice b/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice index b7fb5efbff..5bd7aefa34 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice +++ b/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice @@ -2,25 +2,31 @@ config_do_velocity_reconstruction_for_external_dycore = .false. config_unrealistic_velocity = 00.00159 config_nonconvergence_error = .false. + config_flowParamA_calculation = 'PB1982' - config_thickness_advection = 'fo' - config_tracer_advection = 'fo' + config_thickness_advection = 'fct' + config_tracer_advection = 'fct' + config_horiz_tracer_adv_order = 3 + config_advection_coef_3rd_order = 1.0 config_zero_sfcMassBalApplied_over_bare_land = .true. config_uplift_method = 'none' - config_calving = 'none' + config_calving = 'crevasse_depth' config_apply_calving_mask = .false. config_restore_calving_front_prevent_retreat = .false. - config_calculate_damage = .true. + config_calculate_damage = .false. config_damage_calving_threshold = 0.95 config_damage_calving_method = 'none' config_calving_speed_limit = 0.00063492063 - config_restore_calving_front = .true. + config_restore_calving_front = .false. config_remove_icebergs = .true. config_remove_small_islands = .true. config_distribute_unablatedVolumeDynCell = .true. config_calving_error_threshold = 100000.0 + config_apply_facemelt_strainrate_enhancement = .true. + config_calving_strainrate_scaling = 5.0 + config_thermal_solver = 'temperature' config_thermal_calculate_bmb = .true. @@ -29,7 +35,7 @@ config_surface_air_temperature_source = 'file' config_basal_heat_flux_source = 'file' - config_basal_mass_bal_float = 'ismip6' + config_basal_mass_bal_float = 'none' config_front_mass_bal_grounded = 'ismip6' config_use_3d_thermal_forcing_for_face_melt = .false. config_add_ocean_thermal_forcing = 0.0 @@ -41,7 +47,8 @@ config_dynamic_thickness = 10.0 config_dt = '0000-01-00_00:00:00' - config_time_integration = 'forward_euler' + config_time_integration = 'runge_kutta' + config_rk_order = 2 config_adaptive_timestep = .true. config_adaptive_timestep_calvingCFL_fraction = 0.8 config_adaptive_timestep_include_calving = .true. diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template b/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template index 3bb332d354..0c1548f758 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template +++ b/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template @@ -63,16 +63,6 @@ - - - - - - Date: Wed, 10 Jun 2026 12:53:58 -0700 Subject: [PATCH 13/24] End simulations on Jan 15 End simulations on Jan 15 instead of Jan 1 to be consistent with forcing time stamps. --- .../tests/ismip7_run/ismip7_ais/__init__.py | 22 +++++++++---------- .../ismip7_run/ismip7_ais/namelist.landice | 2 +- .../tests/ismip7_run/ismip7_gris/__init__.py | 22 +++++++++---------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/__init__.py b/compass/landice/tests/ismip7_run/ismip7_ais/__init__.py index 2165c03918..aad9fe9a52 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/__init__.py +++ b/compass/landice/tests/ismip7_run/ismip7_ais/__init__.py @@ -13,57 +13,57 @@ 'historical_CESM2-WACCM': { 'scenario': 'historical', 'model': 'CESM2-WACCM', 'start_time': '2000-01-15_00:00:00', - 'stop_time': '2015-01-01_00:00:00', + 'stop_time': '2015-01-15_00:00:00', 'is_historical': True}, 'historical_MRI-ESM2-0': { 'scenario': 'historical', 'model': 'MRI-ESM2-0', 'start_time': '2000-01-15_00:00:00', - 'stop_time': '2015-01-01_00:00:00', + 'stop_time': '2015-01-15_00:00:00', 'is_historical': True}, 'ssp370_CESM2-WACCM': { 'scenario': 'ssp370', 'model': 'CESM2-WACCM', 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2101-01-01_00:00:00', + 'stop_time': '2101-01-15_00:00:00', 'is_historical': False}, 'ssp370_MRI-ESM2-0': { 'scenario': 'ssp370', 'model': 'MRI-ESM2-0', 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2101-01-01_00:00:00', + 'stop_time': '2101-01-15_00:00:00', 'is_historical': False}, 'ssp126_CESM2-WACCM': { 'scenario': 'ssp126', 'model': 'CESM2-WACCM', 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-01_00:00:00', + 'stop_time': '2301-01-15_00:00:00', 'is_historical': False}, 'ssp126_MRI-ESM2-0': { 'scenario': 'ssp126', 'model': 'MRI-ESM2-0', 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-01_00:00:00', + 'stop_time': '2301-01-15_00:00:00', 'is_historical': False}, 'ssp585_CESM2-WACCM': { 'scenario': 'ssp585', 'model': 'CESM2-WACCM', 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-01_00:00:00', + 'stop_time': '2301-01-15_00:00:00', 'is_historical': False}, 'ssp585_MRI-ESM2-0': { 'scenario': 'ssp585', 'model': 'MRI-ESM2-0', 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-01_00:00:00', + 'stop_time': '2301-01-15_00:00:00', 'is_historical': False}, 'ctrl_CESM2-WACCM': { 'scenario': 'ctrl', 'model': 'CESM2-WACCM', 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-01_00:00:00', + 'stop_time': '2301-01-15_00:00:00', 'is_historical': False}, 'ctrl_MRI-ESM2-0': { 'scenario': 'ctrl', 'model': 'MRI-ESM2-0', 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-01_00:00:00', + 'stop_time': '2301-01-15_00:00:00', 'is_historical': False}, 'ocx': { 'scenario': 'ocx', 'model': None, 'start_time': '1990-01-15_00:00:00', - 'stop_time': '2026-01-01_00:00:00', + 'stop_time': '2026-01-15_00:00:00', 'is_historical': True}, } diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice b/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice index 03470752dc..19a7980237 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice +++ b/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice @@ -60,7 +60,7 @@ config_do_restart = .true. config_restart_timestamp_name = 'restart_timestamp' config_start_time = 'file' - config_stop_time = '2301-01-01_00:00:00' + config_stop_time = '2301-01-15_00:00:00' config_calendar_type = 'noleap' config_stats_interval = 0 diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py b/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py index 10f3d92bfd..cd0d236414 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py +++ b/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py @@ -10,57 +10,57 @@ 'historical_CESM2-WACCM': { 'scenario': 'historical', 'model': 'CESM2-WACCM', 'start_time': '2000-01-15_00:00:00', - 'stop_time': '2015-01-01_00:00:00', + 'stop_time': '2015-01-15_00:00:00', 'is_historical': True}, 'historical_MRI-ESM2-0': { 'scenario': 'historical', 'model': 'MRI-ESM2-0', 'start_time': '2000-01-15_00:00:00', - 'stop_time': '2015-01-01_00:00:00', + 'stop_time': '2015-01-15_00:00:00', 'is_historical': True}, 'ssp370_CESM2-WACCM': { 'scenario': 'ssp370', 'model': 'CESM2-WACCM', 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2101-01-01_00:00:00', + 'stop_time': '2101-01-15_00:00:00', 'is_historical': False}, 'ssp370_MRI-ESM2-0': { 'scenario': 'ssp370', 'model': 'MRI-ESM2-0', 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2101-01-01_00:00:00', + 'stop_time': '2101-01-15_00:00:00', 'is_historical': False}, 'ssp126_CESM2-WACCM': { 'scenario': 'ssp126', 'model': 'CESM2-WACCM', 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-01_00:00:00', + 'stop_time': '2301-01-15_00:00:00', 'is_historical': False}, 'ssp126_MRI-ESM2-0': { 'scenario': 'ssp126', 'model': 'MRI-ESM2-0', 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-01_00:00:00', + 'stop_time': '2301-01-15_00:00:00', 'is_historical': False}, 'ssp585_CESM2-WACCM': { 'scenario': 'ssp585', 'model': 'CESM2-WACCM', 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-01_00:00:00', + 'stop_time': '2301-01-15_00:00:00', 'is_historical': False}, 'ssp585_MRI-ESM2-0': { 'scenario': 'ssp585', 'model': 'MRI-ESM2-0', 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-01_00:00:00', + 'stop_time': '2301-01-15_00:00:00', 'is_historical': False}, 'ctrl_CESM2-WACCM': { 'scenario': 'ctrl', 'model': 'CESM2-WACCM', 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-01_00:00:00', + 'stop_time': '2301-01-15_00:00:00', 'is_historical': False}, 'ctrl_MRI-ESM2-0': { 'scenario': 'ctrl', 'model': 'MRI-ESM2-0', 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-01_00:00:00', + 'stop_time': '2301-01-15_00:00:00', 'is_historical': False}, 'ocx': { 'scenario': 'ocx', 'model': None, 'start_time': '1990-01-15_00:00:00', - 'stop_time': '2026-01-01_00:00:00', + 'stop_time': '2026-01-15_00:00:00', 'is_historical': True}, } From efeb0ed6f606c8dd926fc20550645059d5a9c072 Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Wed, 10 Jun 2026 14:53:01 -0700 Subject: [PATCH 14/24] Add --cpu-bind=cores to srun command Add --cpu-bind=cores to srun command. Testing doesn't show a noticeable difference when this is added, but this is how we run outside of COMPASS. --- compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais.cfg | 3 +++ .../landice/tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg | 3 +++ compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris.cfg | 3 +++ .../landice/tests/ismip7_run/ismip7_gris/ismip7_gris_test.cfg | 3 +++ compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice | 2 +- 5 files changed, 13 insertions(+), 1 deletion(-) 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 e229d7b8d8..dc26cc455f 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais.cfg +++ b/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais.cfg @@ -74,3 +74,6 @@ slm_input_others = NotAvailable # Number of gauss-legendre nodes in latitude (typically multiple of 512) nglv = 2048 + +[parallel] +parallel_executable = srun --label --cpu-bind=cores diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg b/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg index 49b282b0cb..4aa49a28f7 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg +++ b/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg @@ -74,3 +74,6 @@ slm_input_others = NotAvailable # Number of gauss-legendre nodes in latitude (typically multiple of 512) nglv = 2048 + +[parallel] +parallel_executable = srun --label --cpu-bind=cores diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris.cfg b/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris.cfg index b108ee6463..6a3f0a89a2 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris.cfg +++ b/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris.cfg @@ -41,3 +41,6 @@ calving_method = restore # Path to the von Mises parameter fields. von_mises_parameter_path = NotAvailable + +[parallel] +parallel_executable = srun --label --cpu-bind=cores diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris_test.cfg b/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris_test.cfg index 2d0847046f..61156dc35d 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris_test.cfg +++ b/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris_test.cfg @@ -41,3 +41,6 @@ calving_method = restore # Path to the von Mises parameter fields. von_mises_parameter_path = NotAvailable + +[parallel] +parallel_executable = srun --label --cpu-bind=cores diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice b/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice index 5bd7aefa34..ac218e1281 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice +++ b/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice @@ -63,7 +63,7 @@ config_do_restart = .true. config_restart_timestamp_name = 'restart_timestamp' config_start_time = 'file' - config_stop_time = '2301-01-01_00:00:00' + config_stop_time = '2301-01-15_00:00:00' config_calendar_type = 'noleap' config_stats_interval = 0 From ef1a09cdf071d689d9cb6e61469e925e962624c8 Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Wed, 10 Jun 2026 14:58:12 -0700 Subject: [PATCH 15/24] Use 1-year file interval for global and regional stats Creat a new global and regional stats file every year to reduce cost of I/O. Testing in E3SM runs with active Greenland show a significant slowdown due to I/O when the stats files get too long. 1 year is probably shorter than necessary, but will certainly avoid the I/O bottleneck. --- .../tests/ismip7_run/ismip7_ais/streams.landice.template | 8 ++++---- .../tests/ismip7_run/ismip7_gris/streams.landice.template | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) 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 7c5230d61a..97c11ed162 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template +++ b/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template @@ -108,8 +108,8 @@ Date: Thu, 11 Jun 2026 09:04:31 -0700 Subject: [PATCH 16/24] Use Jan 1 start and end dates instead of Jan 15 Use Jan 1 start and end dates instead of Jan 15. This is in line with interpreting the Jan 15 time-stamp in ISMIP7 forcing files as representing Jan 1 to 31, rather than Jan 15 to Feb 14. --- .../tests/ismip7_run/ismip7_ais/__init__.py | 44 +++++++++---------- .../ismip7_run/ismip7_ais/namelist.landice | 2 +- .../ismip7_ais/set_up_experiment.py | 6 +-- .../ismip7_ais/streams.landice.template | 6 +-- .../tests/ismip7_run/ismip7_gris/__init__.py | 44 +++++++++---------- .../ismip7_run/ismip7_gris/namelist.landice | 2 +- .../ismip7_gris/set_up_experiment.py | 6 +-- .../ismip7_gris/streams.landice.template | 8 ++-- 8 files changed, 59 insertions(+), 59 deletions(-) diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/__init__.py b/compass/landice/tests/ismip7_run/ismip7_ais/__init__.py index aad9fe9a52..c6e3a41c94 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/__init__.py +++ b/compass/landice/tests/ismip7_run/ismip7_ais/__init__.py @@ -12,58 +12,58 @@ EXPERIMENTS = { 'historical_CESM2-WACCM': { 'scenario': 'historical', 'model': 'CESM2-WACCM', - 'start_time': '2000-01-15_00:00:00', - 'stop_time': '2015-01-15_00:00:00', + 'start_time': '2000-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-15_00:00:00', - 'stop_time': '2015-01-15_00:00:00', + 'start_time': '2000-01-01_00:00:00', + 'stop_time': '2015-01-01_00:00:00', 'is_historical': True}, 'ssp370_CESM2-WACCM': { 'scenario': 'ssp370', 'model': 'CESM2-WACCM', - 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2101-01-15_00:00:00', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2101-01-01_00:00:00', 'is_historical': False}, 'ssp370_MRI-ESM2-0': { 'scenario': 'ssp370', 'model': 'MRI-ESM2-0', - 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2101-01-15_00:00:00', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2101-01-01_00:00:00', 'is_historical': False}, 'ssp126_CESM2-WACCM': { 'scenario': 'ssp126', 'model': 'CESM2-WACCM', - 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-15_00:00:00', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ssp126_MRI-ESM2-0': { 'scenario': 'ssp126', 'model': 'MRI-ESM2-0', - 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-15_00:00:00', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ssp585_CESM2-WACCM': { 'scenario': 'ssp585', 'model': 'CESM2-WACCM', - 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-15_00:00:00', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ssp585_MRI-ESM2-0': { 'scenario': 'ssp585', 'model': 'MRI-ESM2-0', - 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-15_00:00:00', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ctrl_CESM2-WACCM': { 'scenario': 'ctrl', 'model': 'CESM2-WACCM', - 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-15_00:00:00', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ctrl_MRI-ESM2-0': { 'scenario': 'ctrl', 'model': 'MRI-ESM2-0', - 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-15_00:00:00', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ocx': { 'scenario': 'ocx', 'model': None, - 'start_time': '1990-01-15_00:00:00', - 'stop_time': '2026-01-15_00:00:00', + 'start_time': '1990-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/namelist.landice b/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice index 19a7980237..03470752dc 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice +++ b/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice @@ -60,7 +60,7 @@ config_do_restart = .true. config_restart_timestamp_name = 'restart_timestamp' config_start_time = 'file' - config_stop_time = '2301-01-15_00:00:00' + config_stop_time = '2301-01-01_00:00:00' config_calendar_type = 'noleap' config_stats_interval = 0 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 4c6170b244..7b1455c9ce 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 @@ -344,11 +344,11 @@ def setup(self): # noqa: C901 # --- Symlink restart for projections/ctrl --- if not is_historical: hist_exp = f"historical_{model}" - os.symlink(f"../{hist_exp}/rst.2015-01-15.nc", - os.path.join(self.work_dir, 'rst.2015-01-15.nc')) + os.symlink(f"../{hist_exp}/rst.2015-01-01.nc", + os.path.join(self.work_dir, 'rst.2015-01-01.nc')) with open(os.path.join(self.work_dir, "restart_timestamp"), "w") as text_file: - text_file.write("2015-01-15_00:00:00") + text_file.write("2015-01-01_00:00:00") # --- Add albany yaml, graph file, load script, job script --- self.add_input_file( 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 97c11ed162..ac143e5979 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template +++ b/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template @@ -31,7 +31,7 @@ type="input" filename_template="{{ input_file_SMB_forcing }}" input_interval="{{ forcing_interval_monthly }}" - reference_time="2000-01-15_00:00:00" + reference_time="2000-01-01_00:00:00" runtime_format="single_file"> @@ -40,7 +40,7 @@ type="input" filename_template="{{ input_file_temperature_forcing }}" input_interval="{{ forcing_interval_monthly }}" - reference_time="2000-01-15_00:00:00" + reference_time="2000-01-01_00:00:00" runtime_format="single_file"> @@ -59,7 +59,7 @@ type="input" filename_template="{{ input_file_runoff_forcing }}" input_interval="{{ forcing_interval_monthly }}" - reference_time="2000-01-15_00:00:00" + reference_time="2000-01-01_00:00:00" runtime_format="single_file"> diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py b/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py index cd0d236414..6ad5fbbe14 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py +++ b/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py @@ -9,58 +9,58 @@ EXPERIMENTS = { 'historical_CESM2-WACCM': { 'scenario': 'historical', 'model': 'CESM2-WACCM', - 'start_time': '2000-01-15_00:00:00', - 'stop_time': '2015-01-15_00:00:00', + 'start_time': '2000-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-15_00:00:00', - 'stop_time': '2015-01-15_00:00:00', + 'start_time': '2000-01-01_00:00:00', + 'stop_time': '2015-01-01_00:00:00', 'is_historical': True}, 'ssp370_CESM2-WACCM': { 'scenario': 'ssp370', 'model': 'CESM2-WACCM', - 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2101-01-15_00:00:00', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2101-01-01_00:00:00', 'is_historical': False}, 'ssp370_MRI-ESM2-0': { 'scenario': 'ssp370', 'model': 'MRI-ESM2-0', - 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2101-01-15_00:00:00', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2101-01-01_00:00:00', 'is_historical': False}, 'ssp126_CESM2-WACCM': { 'scenario': 'ssp126', 'model': 'CESM2-WACCM', - 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-15_00:00:00', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ssp126_MRI-ESM2-0': { 'scenario': 'ssp126', 'model': 'MRI-ESM2-0', - 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-15_00:00:00', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ssp585_CESM2-WACCM': { 'scenario': 'ssp585', 'model': 'CESM2-WACCM', - 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-15_00:00:00', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ssp585_MRI-ESM2-0': { 'scenario': 'ssp585', 'model': 'MRI-ESM2-0', - 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-15_00:00:00', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ctrl_CESM2-WACCM': { 'scenario': 'ctrl', 'model': 'CESM2-WACCM', - 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-15_00:00:00', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ctrl_MRI-ESM2-0': { 'scenario': 'ctrl', 'model': 'MRI-ESM2-0', - 'start_time': '2015-01-15_00:00:00', - 'stop_time': '2301-01-15_00:00:00', + 'start_time': '2015-01-01_00:00:00', + 'stop_time': '2301-01-01_00:00:00', 'is_historical': False}, 'ocx': { 'scenario': 'ocx', 'model': None, - 'start_time': '1990-01-15_00:00:00', - 'stop_time': '2026-01-15_00:00:00', + 'start_time': '1990-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 ac218e1281..5bd7aefa34 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice +++ b/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice @@ -63,7 +63,7 @@ config_do_restart = .true. config_restart_timestamp_name = 'restart_timestamp' config_start_time = 'file' - config_stop_time = '2301-01-15_00:00:00' + config_stop_time = '2301-01-01_00:00:00' config_calendar_type = 'noleap' config_stats_interval = 0 diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py b/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py index f8561e7a10..c07a79bbbf 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py +++ b/compass/landice/tests/ismip7_run/ismip7_gris/set_up_experiment.py @@ -278,11 +278,11 @@ def setup(self): # noqa: C901 # --- Symlink restart for projections/ctrl --- if not is_historical: hist_exp = f"historical_{model}" - os.symlink(f"../{hist_exp}/rst.2015-01-15.nc", - os.path.join(self.work_dir, 'rst.2015-01-15.nc')) + os.symlink(f"../{hist_exp}/rst.2015-01-01.nc", + os.path.join(self.work_dir, 'rst.2015-01-01.nc')) with open(os.path.join(self.work_dir, "restart_timestamp"), "w") as text_file: - text_file.write("2015-01-15_00:00:00") + text_file.write("2015-01-01_00:00:00") # --- Add albany yaml, graph file, load script, job script --- self.add_input_file( diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template b/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template index 64e443a7ba..20ba57c258 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template +++ b/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template @@ -31,7 +31,7 @@ type="input" filename_template="{{ input_file_SMB_forcing }}" input_interval="{{ forcing_interval_monthly }}" - reference_time="2000-01-15_00:00:00" + reference_time="2000-01-01_00:00:00" runtime_format="single_file"> @@ -40,7 +40,7 @@ type="input" filename_template="{{ input_file_temperature_forcing }}" input_interval="{{ forcing_interval_monthly }}" - reference_time="2000-01-15_00:00:00" + reference_time="2000-01-01_00:00:00" runtime_format="single_file"> @@ -49,7 +49,7 @@ type="input" filename_template="{{ input_file_TF_forcing }}" input_interval="{{ forcing_interval_monthly }}" - reference_time="2000-01-15_00:00:00" + reference_time="2000-01-01_00:00:00" runtime_format="single_file"> @@ -58,7 +58,7 @@ type="input" filename_template="{{ input_file_runoff_forcing }}" input_interval="{{ forcing_interval_monthly }}" - reference_time="2000-01-15_00:00:00" + reference_time="2000-01-01_00:00:00" runtime_format="single_file"> From 35d45988c0fa9241cddfa12a6e4c929c84832116 Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Fri, 12 Jun 2026 09:03:27 -0700 Subject: [PATCH 17/24] Update default Greenland configuration Use a linear Budd bed, which behaves much more stably in testing than the q=1/3 runs. Also start historical GrIS simulations in 2007 to be consistent with BedMachine geometry. Reduce CFL fraction from 0.8 to 0.5 for added stability. --- compass/landice/tests/ismip7_run/ismip7_gris/__init__.py | 4 ++-- .../landice/tests/ismip7_run/ismip7_gris/albany_input.yaml | 2 +- .../landice/tests/ismip7_run/ismip7_gris/ismip7_gris_test.cfg | 2 +- compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py b/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py index 6ad5fbbe14..ab883d15e2 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py +++ b/compass/landice/tests/ismip7_run/ismip7_gris/__init__.py @@ -9,12 +9,12 @@ EXPERIMENTS = { 'historical_CESM2-WACCM': { 'scenario': 'historical', 'model': 'CESM2-WACCM', - 'start_time': '2000-01-01_00:00:00', + 'start_time': '2007-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': '2007-01-01_00:00:00', 'stop_time': '2015-01-01_00:00:00', 'is_historical': True}, 'ssp370_CESM2-WACCM': { diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/albany_input.yaml b/compass/landice/tests/ismip7_run/ismip7_gris/albany_input.yaml index bb1a79a93b..bdd3fa7108 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/albany_input.yaml +++ b/compass/landice/tests/ismip7_run/ismip7_gris/albany_input.yaml @@ -11,7 +11,7 @@ ANONYMOUS: BC 0: Basal Friction Coefficient: Type: Power Law - Power Exponent: 0.333333333 + Power Exponent: 1.0 Mu Type: Field Effective Pressure Type: Hydrostatic Computed At Nodes Zero Effective Pressure On Floating Ice At Nodes: true diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris_test.cfg b/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris_test.cfg index 61156dc35d..66343580fb 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris_test.cfg +++ b/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris_test.cfg @@ -19,7 +19,7 @@ pio_stride = 128 forcing_basepath = /global/cfs/cdirs/m4288/users/trhille/ISMIP7/test_processing/GIS # Path to the initial condition file. User has to supply. -init_cond_path = /global/cfs/cdirs/fanssie/MALI_input_files/GIS_1to10km_r02/GIS_1to10km_r02_20230202_m3.nc +init_cond_path = /global/cfs/cdirs/fanssie/MALI_input_files/GIS_1to10km_r02/GIS_1to10km_r02_20230202_remove_icebergs.nc # Path to the file for the basal melt parametrization coefficients. melt_params_path = NotAvailable diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice b/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice index 5bd7aefa34..f21f43f7c5 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice +++ b/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice @@ -54,7 +54,7 @@ config_adaptive_timestep_include_calving = .true. config_min_adaptive_timestep = 60 config_max_adaptive_timestep = 3.154e7 - config_adaptive_timestep_CFL_fraction = 0.8 + config_adaptive_timestep_CFL_fraction = 0.5 config_adaptive_timestep_include_DCFL = .false. config_adaptive_timestep_force_interval = '0000-01-00_00:00:00' config_timeaveraging_interval = '0001-00-00_00:00:00' From 6963b79f4660311c6289f2d3f97ff9cc40e113dd Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Fri, 12 Jun 2026 15:11:55 -0700 Subject: [PATCH 18/24] Revert "Remove lapse rate fields from streams until they are added in MALI" This reverts commit e559f6226cb775ef0de688a0f58f3124857bb0b3. --- .../ismip7_ais/streams.landice.template | 18 ++++++++++++++++++ .../ismip7_gris/streams.landice.template | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) 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 ac143e5979..0d67fcbbf9 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template +++ b/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template @@ -45,6 +45,24 @@ + + + + + + + + + + + + + + + + Date: Fri, 12 Jun 2026 15:31:51 -0700 Subject: [PATCH 19/24] Add streams and settings to handle SMB and SAT lapse rates --- .../landice/tests/ismip7_run/ismip7_ais/ismip7_ais.cfg | 3 +++ .../tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg | 5 ++++- .../landice/tests/ismip7_run/ismip7_ais/namelist.landice | 1 + .../tests/ismip7_run/ismip7_ais/set_up_experiment.py | 6 ++++++ .../tests/ismip7_run/ismip7_ais/streams.landice.template | 8 ++++++++ .../landice/tests/ismip7_run/ismip7_gris/ismip7_gris.cfg | 3 +++ .../tests/ismip7_run/ismip7_gris/ismip7_gris_test.cfg | 3 +++ .../landice/tests/ismip7_run/ismip7_gris/namelist.landice | 1 + .../tests/ismip7_run/ismip7_gris/set_up_experiment.py | 6 ++++++ .../tests/ismip7_run/ismip7_gris/streams.landice.template | 8 ++++++++ 10 files changed, 43 insertions(+), 1 deletion(-) 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 dc26cc455f..745e4c89f7 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais.cfg +++ b/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais.cfg @@ -32,6 +32,9 @@ init_cond_path = NotAvailable # Path to the file for the basal melt parametrization coefficients. melt_params_path = NotAvailable +# Path to the reference surface elevation file +reference_surface_path = NotAvailable + # Path to the region mask file region_mask_path = NotAvailable diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg b/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg index 4aa49a28f7..19c518aeb7 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg +++ b/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg @@ -10,7 +10,7 @@ # ssp585_CESM2-WACCM, ssp585_MRI-ESM2-0, # ctrl_CESM2-WACCM, ctrl_MRI-ESM2-0, # ocx -exp_list = historical_CESM2-WACCM,ssp585_CESM2-WACCM +exp_list = historical_CESM2-WACCM # Number of tasks to use for each run ntasks = 512 @@ -32,6 +32,9 @@ init_cond_path = /global/cfs/cdirs/fanssie/MALI_projects/ISMIP6-2300/initial_con # Path to the file for the basal melt parametrization coefficients. melt_params_path = /global/cfs/cdirs/m4288/users/trhille/ISMIP7/test_processing/AIS/climatology/basin_and_coeff_DeltaT_quadratic_non_local_gamma14500.nc +# Path to the reference surface elevation file +reference_surface_path = /global/cfs/cdirs/m4288/users/trhille/ISMIP7/forcing/AIS/upper_surface.nc + # Path to the region mask file region_mask_path = /global/cfs/cdirs/fanssie/MALI_projects/ISMIP6-2300/initial_conditions/AIS_4to20km_20230105/AIS_4to20km_r01_20220907.regionMask_ismip6.nc diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice b/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice index 03470752dc..2c3ab689af 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice +++ b/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice @@ -7,6 +7,7 @@ config_thickness_advection = 'fo' config_tracer_advection = 'fo' config_zero_sfcMassBalApplied_over_bare_land = .true. + config_apply_smb_sat_lapse_rate = .true. config_uplift_method = 'none' config_slm_coupling_interval = 5 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 7b1455c9ce..98d59d4c40 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 @@ -60,6 +60,8 @@ def setup(self): # noqa: C901 melt_params_fname = os.path.split(melt_params_path)[-1] region_mask_path = section.get('region_mask_path') region_mask_fname = os.path.split(region_mask_path)[-1] + reference_surface_path = section.get('reference_surface_path') + reference_surface_fname = os.path.split(reference_surface_path)[-1] calving_method = section.get('calving_method') sea_level_model = section.getboolean('sea_level_model') @@ -99,6 +101,9 @@ def setup(self): # noqa: C901 os.symlink(region_mask_path, os.path.join(self.work_dir, os.path.basename(region_mask_path))) + os.symlink(reference_surface_path, + os.path.join(self.work_dir, + os.path.basename(reference_surface_path))) # --- Find and symlink forcing files --- if scenario == 'ctrl': @@ -244,6 +249,7 @@ def setup(self): # noqa: C901 'input_file_region_mask': region_mask_fname if is_historical else 'USE_RESTART_FILE_INSTEAD', 'input_file_melt_params': melt_params_fname, + 'input_file_reference_surface': reference_surface_fname, 'input_file_SMB_forcing': smb_fname, 'input_file_temperature_forcing': temp_fname, 'input_file_TF_forcing': tf_fname, 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 0d67fcbbf9..b1314f860d 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template +++ b/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template @@ -92,6 +92,14 @@ + + + + + + + + Date: Mon, 15 Jun 2026 15:50:08 -0700 Subject: [PATCH 20/24] Update docs to include explanation of `reference_surface_path` Update docs to include explanation of `reference_surface_path`, used when applying lapse rates. --- .../landice/test_groups/ismip7_forcing.rst | 6 ++++++ .../landice/test_groups/ismip7_run.rst | 20 ++++++++++--------- .../landice/test_groups/ismip7_forcing.rst | 15 ++++++++++++++ .../landice/test_groups/ismip7_run.rst | 14 +++++++------ 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/docs/developers_guide/landice/test_groups/ismip7_forcing.rst b/docs/developers_guide/landice/test_groups/ismip7_forcing.rst index 72aa8c7411..3191ce9a6b 100644 --- a/docs/developers_guide/landice/test_groups/ismip7_forcing.rst +++ b/docs/developers_guide/landice/test_groups/ismip7_forcing.rst @@ -36,6 +36,12 @@ The module :py:mod:`compass.landice.tests.ismip7_forcing.configure` validates that all required config options in the ``[ismip7]`` section have been set by the user (i.e., are not ``NotAvailable``). +Repository-local example user configs are available at +``compass/landice/tests/ismip7_forcing/ismip7_forcing_test.cfg`` (AIS) and +``compass/landice/tests/ismip7_forcing/ismip7_forcing_test_gis.cfg`` (GrIS). +These are intended for development/testing and include environment-specific +paths. + create_mapfile ~~~~~~~~~~~~~~ diff --git a/docs/developers_guide/landice/test_groups/ismip7_run.rst b/docs/developers_guide/landice/test_groups/ismip7_run.rst index 15199b4830..fff9f7a494 100644 --- a/docs/developers_guide/landice/test_groups/ismip7_run.rst +++ b/docs/developers_guide/landice/test_groups/ismip7_run.rst @@ -65,24 +65,26 @@ The ``setup`` method sets up the experiment directory by: 1. Creating symlinks to forcing files from the conventional path layout under ``forcing_basepath``. -2. Copying and populating the streams template with the correct forcing +2. Symlinking the ``reference_surface_path`` file into the run directory, + where it is used by MALI when applying lapse rates. +3. Copying and populating the streams template with the correct forcing filenames and intervals (monthly for SMB/temperature/runoff, annual for lapse rates and thermal forcing, ``initial_only`` for melt parameters). -3. Processing the namelist template for the experiment's time period +4. Processing the namelist template for the experiment's time period and restart frequency. -4. Adding calving-specific streams (face melting, von Mises params) if +5. Adding calving-specific streams (face melting, von Mises params) if configured. -5. Creating a restart symlink for projection experiments pointing to +6. Creating a restart symlink for projection experiments pointing to the corresponding ESM's historical restart (``../historical_{model}/rst.2015-01-01.nc``). -6. Setting up CTRL2015 experiments with constant-climate forcing +7. Setting up CTRL2015 experiments with constant-climate forcing (``initial_only`` intervals). -7. Setting up the OCX experiment with reanalysis-based forcing. -8. If SLM coupling is enabled, adding a ``CreateSlmMappingFiles`` step +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. -9. Generating a ``graph.info`` file and a SLURM job script. -10. Symlinking the compass load script into the run directory. +10. Generating a ``graph.info`` file and a SLURM job script. +11. 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 1740f95a5f..e26d3f88e9 100644 --- a/docs/users_guide/landice/test_groups/ismip7_forcing.rst +++ b/docs/users_guide/landice/test_groups/ismip7_forcing.rst @@ -43,6 +43,21 @@ To use this test group, users need to: 5. Run the ``ocean_thermal`` test case for each model and scenario combination. +Example user config files are provided in the source tree for local testing: + +* ``compass/landice/tests/ismip7_forcing/ismip7_forcing_test.cfg`` + (AIS-focused example) +* ``compass/landice/tests/ismip7_forcing/ismip7_forcing_test_gis.cfg`` + (GrIS-focused example) + +These files contain machine-specific absolute paths and are intended as +templates, not portable defaults. Copy one and edit paths and options for +your environment before using it with ``compass setup ... -f USER.cfg``. + +The AIS example enables both ocean processing modes and uses a 2015-2300 +processing window for both atmosphere and ocean thermal scenario forcing. +The GrIS example enables scenario ocean processing only and uses 1980-2015. + .. _landice_ismip7_forcing_input_data: Input Data diff --git a/docs/users_guide/landice/test_groups/ismip7_run.rst b/docs/users_guide/landice/test_groups/ismip7_run.rst index 2eab9239c1..0aedd90ddc 100644 --- a/docs/users_guide/landice/test_groups/ismip7_run.rst +++ b/docs/users_guide/landice/test_groups/ismip7_run.rst @@ -151,10 +151,11 @@ All config options should be reviewed and altered as needed. # Base path to pre-processed forcing forcing_basepath = NotAvailable - # Initial condition and parameter files - init_cond_path = NotAvailable - melt_params_path = NotAvailable - region_mask_path = NotAvailable + # Initial condition and parameter files + init_cond_path = NotAvailable + melt_params_path = NotAvailable + reference_surface_path = NotAvailable + region_mask_path = NotAvailable # Climatology files for CTRL2015 experiments ctrl_tf_climatology_path = NotAvailable @@ -178,8 +179,9 @@ All config options should be reviewed and altered as needed. slm_input_others = NotAvailable nglv = 2048 -**GrIS config** (``[ismip7_run_gris]``) is similar but without -sea-level model options and with ``calving_method = von_mises`` as default. +**GrIS config** (``[ismip7_run_gris]``) is similar (including +``reference_surface_path``) but without sea-level model options and with +``calving_method = von_mises`` as default. .. _landice_ismip7_run_forcing_streams: From 8e150c8790f8785acfdae548f446f959806543f2 Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Mon, 29 Jun 2026 20:10:07 -0700 Subject: [PATCH 21/24] Switch to gregorian calendar per ismip conventions --- compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice | 2 +- compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice b/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice index 2c3ab689af..165f9611f6 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice +++ b/compass/landice/tests/ismip7_run/ismip7_ais/namelist.landice @@ -62,7 +62,7 @@ config_restart_timestamp_name = 'restart_timestamp' config_start_time = 'file' config_stop_time = '2301-01-01_00:00:00' - config_calendar_type = 'noleap' + config_calendar_type = 'gregorian' config_stats_interval = 0 config_write_stats_on_startup = .false. diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice b/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice index d5b1c59b63..3992001358 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice +++ b/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice @@ -65,7 +65,7 @@ config_restart_timestamp_name = 'restart_timestamp' config_start_time = 'file' config_stop_time = '2301-01-01_00:00:00' - config_calendar_type = 'noleap' + config_calendar_type = 'gregorian' config_stats_interval = 0 config_write_stats_on_startup = .false. From b4bc8bcf77e202e0ee2ee7a8eef881535e11fd4b Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Mon, 29 Jun 2026 20:18:35 -0700 Subject: [PATCH 22/24] Update streams: add TF, remove unneeded vars --- .../tests/ismip7_run/ismip7_ais/streams.landice.template | 5 ++--- .../tests/ismip7_run/ismip7_gris/streams.landice.template | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) 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 b1314f860d..5465926fb8 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template +++ b/compass/landice/tests/ismip7_run/ismip7_ais/streams.landice.template @@ -105,7 +105,7 @@ output_interval="0001-00-00_00:00:00" reference_time="2000-01-01_00:00:00" filename_interval="005-00-00_00:00:00" - filename_template="output/output_state_$Y.nc" + filename_template="output/output_2d_$Y.nc" type="output"> @@ -127,8 +127,7 @@ - - + diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template b/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template index 2eee40169c..26f74dd7c0 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template +++ b/compass/landice/tests/ismip7_run/ismip7_gris/streams.landice.template @@ -94,7 +94,7 @@ output_interval="0001-00-00_00:00:00" reference_time="2000-01-01_00:00:00" filename_interval="005-00-00_00:00:00" - filename_template="output/output_state_$Y.nc" + filename_template="output/output_2d_$Y.nc" type="output"> @@ -116,8 +116,7 @@ - - + From e25b09af50e266cbf56c0d0209f2682ea2ea9eb7 Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Mon, 20 Jul 2026 15:55:42 -0700 Subject: [PATCH 23/24] Final minor modifications --- .../landice/tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg | 2 +- .../landice/tests/ismip7_run/ismip7_gris/ismip7_gris_test.cfg | 4 ++-- compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg b/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg index 19c518aeb7..4d9f05318b 100644 --- a/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg +++ b/compass/landice/tests/ismip7_run/ismip7_ais/ismip7_ais_test.cfg @@ -10,7 +10,7 @@ # ssp585_CESM2-WACCM, ssp585_MRI-ESM2-0, # ctrl_CESM2-WACCM, ctrl_MRI-ESM2-0, # ocx -exp_list = historical_CESM2-WACCM +exp_list = historical_CESM2-WACCM,ssp585_CESM2-WACCM # Number of tasks to use for each run ntasks = 512 diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris_test.cfg b/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris_test.cfg index 4c0e8a4c94..9287dc1a1d 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris_test.cfg +++ b/compass/landice/tests/ismip7_run/ismip7_gris/ismip7_gris_test.cfg @@ -3,7 +3,7 @@ # List of experiments to set up. # Can be "all", "historical", "projections", "ctrl", or a # comma-delimited list of experiment names. -exp_list = historical_CESM2-WACCM +exp_list = historical_CESM2-WACCM,ssp585_CESM2-WACCM # Number of tasks to use for each run ntasks = 512 @@ -25,7 +25,7 @@ init_cond_path = /global/cfs/cdirs/fanssie/MALI_input_files/GIS_1to10km_r02/GIS_ melt_params_path = NotAvailable # Path to the reference surface elevation file -reference_surface_path = NotAvailable +reference_surface_path = /global/cfs/cdirs/m4288/users/trhille/ISMIP7/forcing/GIS/upper_surface.nc # Path to the region mask file region_mask_path = /global/cfs/cdirs/fanssie/MALI_input_files/GIS_1to10km_r02/GIS_1to10km_r02_20230202_ismip6_regionMasks.nc diff --git a/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice b/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice index 3992001358..d29250f7b6 100644 --- a/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice +++ b/compass/landice/tests/ismip7_run/ismip7_gris/namelist.landice @@ -26,7 +26,7 @@ config_distribute_unablatedVolumeDynCell = .true. config_calving_error_threshold = 100000.0 config_apply_facemelt_strainrate_enhancement = .true. - config_calving_strainrate_scaling = 5.0 + config_calving_strainrate_scaling = 1.0 config_thermal_solver = 'temperature' @@ -50,6 +50,7 @@ config_dt = '0000-01-00_00:00:00' config_time_integration = 'runge_kutta' config_rk_order = 2 + config_rk3_stages = 3 config_adaptive_timestep = .true. config_adaptive_timestep_calvingCFL_fraction = 0.8 config_adaptive_timestep_include_calving = .true. From bf3b972032be7f99d6b2cd62efd9a7d73c8c4b8a Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Mon, 20 Jul 2026 18:11:45 -0700 Subject: [PATCH 24/24] Minor corrections to docs --- docs/developers_guide/landice/test_groups/ismip7_run.rst | 2 +- docs/users_guide/landice/test_groups/ismip7_run.rst | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/developers_guide/landice/test_groups/ismip7_run.rst b/docs/developers_guide/landice/test_groups/ismip7_run.rst index fff9f7a494..46b1c81541 100644 --- a/docs/developers_guide/landice/test_groups/ismip7_run.rst +++ b/docs/developers_guide/landice/test_groups/ismip7_run.rst @@ -106,7 +106,7 @@ Key differences from the AIS test case: * Ocean thermal forcing is 2D (depth-averaged) rather than 3D. * No sea-level model coupling. -* Default calving method is ``von_mises``. +* Default calving method is ``crevasse_depth``. * Config section is ``[ismip7_run_gris]``. set_up_experiment (GrIS) diff --git a/docs/users_guide/landice/test_groups/ismip7_run.rst b/docs/users_guide/landice/test_groups/ismip7_run.rst index 0aedd90ddc..1d418eb849 100644 --- a/docs/users_guide/landice/test_groups/ismip7_run.rst +++ b/docs/users_guide/landice/test_groups/ismip7_run.rst @@ -180,8 +180,7 @@ All config options should be reviewed and altered as needed. nglv = 2048 **GrIS config** (``[ismip7_run_gris]``) is similar (including -``reference_surface_path``) but without sea-level model options and with -``calving_method = von_mises`` as default. +``reference_surface_path``) but without sea-level model options .. _landice_ismip7_run_forcing_streams: @@ -195,13 +194,13 @@ ISMIP7 uses more forcing fields than ISMIP6, at mixed temporal resolutions: * ``sfcMassBal`` — surface mass balance * ``surfaceAirTemperature`` — surface air temperature * ``ismip6Runoff`` — ice sheet runoff +* ``ismip6_2dThermalForcing`` (GrIS) — ocean thermal forcing **Annual forcing** (``input_interval = 0001-00-00_00:00:00``): * ``sfcMassBalLapseRate`` — SMB elevation lapse rate * ``surfaceAirTemperatureLapseRate`` — temperature lapse rate -* ``ismip6shelfMelt_3dThermalForcing`` (AIS) or - ``ismip6_2dThermalForcing`` (GrIS) — ocean thermal forcing +* ``ismip6shelfMelt_3dThermalForcing`` (AIS) **Static** (``input_interval = initial_only``): @@ -227,4 +226,4 @@ ismip7_gris ``landice/ismip7_run/ismip7_gris`` sets up GrIS experiments with 2D (depth-averaged) ocean thermal forcing. Sea-level model coupling is not -currently supported for GrIS. Von Mises calving is the default. +currently supported for GrIS. Crevasse-depth calving is the default.