Skip to content

Commit

Permalink
Merge pull request #397 from hollyhan/add_ismip6_run_testgroup
Browse files Browse the repository at this point in the history
Add ismip6 run testgroup

This PR adds a test group on running Antarctic simulations for the ISMIP6 2300 experimental protocol https://www.climate-cryosphere.org/wiki/index.php?title=ISMIP6-Projections2300-Antarctica.

Each experiment is a step that is meant to be run manually. A user must specify input files and experiments to set up in the config file.
  • Loading branch information
matthewhoffman authored Apr 10, 2023
2 parents 3f830d7 + 0873f31 commit a4720fb
Show file tree
Hide file tree
Showing 21 changed files with 1,366 additions and 7 deletions.
22 changes: 16 additions & 6 deletions compass/job/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from jinja2 import Template
from importlib import resources
import os
from importlib import resources

import numpy as np
from jinja2 import Template


def write_job_script(config, machine, target_cores, min_cores, work_dir,
suite=''):
suite='', pre_run_commands='', post_run_commands=''):
"""
Parameters
Expand All @@ -28,6 +29,14 @@ def write_job_script(config, machine, target_cores, min_cores, work_dir,
suite : str, optional
The name of the suite
pre_run_commands : str, optional
Optional commands to be inserted into job script prior to calling
compass run
post_run_commands : str, optional
Optional commands to be inserted into job script after calling of
compass run
"""

if config.has_option('parallel', 'account'):
Expand All @@ -38,8 +47,8 @@ def write_job_script(config, machine, target_cores, min_cores, work_dir,
cores_per_node = config.getint('parallel', 'cores_per_node')

# as a rule of thumb, let's do the geometric mean between min and target
cores = np.sqrt(target_cores*min_cores)
nodes = int(np.ceil(cores/cores_per_node))
cores = np.sqrt(target_cores * min_cores)
nodes = int(np.ceil(cores / cores_per_node))

partition = config.get('job', 'partition')
if partition == '<<<default>>>':
Expand Down Expand Up @@ -87,7 +96,8 @@ def write_job_script(config, machine, target_cores, min_cores, work_dir,
text = template.render(job_name=job_name, account=account,
nodes=f'{nodes}', wall_time=wall_time, qos=qos,
partition=partition, constraint=constraint,
suite=suite)
suite=suite, pre_run_commands=pre_run_commands,
post_run_commands=post_run_commands)
text = _clean_up_whitespace(text)
if suite == '':
script_filename = 'job_script.sh'
Expand Down
3 changes: 2 additions & 1 deletion compass/job/job_script.template
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@
{%- endif %}

source load_compass_env.sh
{{ pre_run_commands }}
compass run {{suite}}

{{ post_run_commands }}
2 changes: 2 additions & 0 deletions compass/landice/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from compass.landice.tests.humboldt import Humboldt
from compass.landice.tests.hydro_radial import HydroRadial
from compass.landice.tests.ismip6_forcing import Ismip6Forcing
from compass.landice.tests.ismip6_run import Ismip6Run
from compass.landice.tests.kangerlussuaq import Kangerlussuaq
from compass.landice.tests.koge_bugt_s import KogeBugtS
from compass.landice.tests.mismipplus import MISMIPplus
Expand Down Expand Up @@ -38,6 +39,7 @@ def __init__(self):
self.add_test_group(Humboldt(mpas_core=self))
self.add_test_group(HydroRadial(mpas_core=self))
self.add_test_group(Ismip6Forcing(mpas_core=self))
self.add_test_group(Ismip6Run(mpas_core=self))
self.add_test_group(Kangerlussuaq(mpas_core=self))
self.add_test_group(KogeBugtS(mpas_core=self))
self.add_test_group(MISMIPplus(mpas_core=self))
Expand Down
22 changes: 22 additions & 0 deletions compass/landice/tests/ismip6_run/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from compass.landice.tests.ismip6_run.ismip6_ais_proj2300 import (
Ismip6AisProj2300,
)
from compass.testgroup import TestGroup


class Ismip6Run(TestGroup):
"""
A test group for automated setup of a suite of standardized
ISMIP6 simulations
Attributes
----------
"""
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='ismip6_run')

self.add_test_case(Ismip6AisProj2300(test_group=self))
82 changes: 82 additions & 0 deletions compass/landice/tests/ismip6_run/ismip6_ais_proj2300/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import os

from compass.landice.tests.ismip6_run.ismip6_ais_proj2300.set_up_experiment import ( # noqa
SetUpExperiment,
)
from compass.testcase import TestCase


class Ismip6AisProj2300(TestCase):
"""
A test case for automated setup of a suite of standardized
simulations for ISMIP6-Projections2300-Antarctica
See: https://www.climate-cryosphere.org/wiki/index.php?title=ISMIP6-Projections2300-Antarctica) # noqa
"""

def __init__(self, test_group):
"""
Create the test case
Parameters
----------
test_group : compass.landice.tests.ismip6_run.Ismip6Run
The test group that this test case belongs to
"""
name = 'ismip6_ais_proj2300'

super().__init__(test_group=test_group, name=name,
subdir=name)

def configure(self):
"""
Set up the desired ISMIP6 AIS 2300 experiments.
Read the list from the config of which experiments the
user wants to set up. Call thee add_step method and add the
experiment to steps_to_run. Those operations are typically done
in the constructor, but they are done here so that the list to set up
can be adjusted in the config, and the config is not available until
this point.
"""

# user can specify any of: 'all', 'tier1', 'tier2', or a
# comma-delimited list (or a single experiment)
exp_list = self.config.get('ismip6_run_ais_2300', 'exp_list')
if exp_list == "tier1":
exp_list = ['hist', 'ctrlAE'] + \
[f'expAE{i:02}' for i in range(1, 7)]
elif exp_list == "tier2":
exp_list = [f'expAE{i:02}' for i in range(7, 15)]
elif exp_list == "all":
exp_list = ['hist', 'ctrlAE'] + \
[f'expAE{i:02}' for i in range(1, 15)]
else:
exp_list = exp_list.split(",")
mesh_res = self.config.getint('ismip6_run_ais_2300', 'mesh_res')

for exp in exp_list:
if os.path.exists(os.path.join(self.work_dir, exp)):
print(f"WARNING: {exp} path already exists; skipping. "
"Please remove the directory "
f"{os.path.join(self.work_dir, exp)} and execute "
"'compass setup' again to set this experiment up.")
else:
exp_name = f'{exp}_{mesh_res:02}'
self.add_step(
SetUpExperiment(test_case=self, name=exp_name,
subdir=exp_name, exp=exp))
# Do not add experiments to step to steps_to_run;
# each experiment (step) should be run manually
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.")

# no validate() method is needed
Loading

0 comments on commit a4720fb

Please sign in to comment.