Skip to content

Commit

Permalink
Merge pull request #2969 from samsrabin/simplify-tower-types
Browse files Browse the repository at this point in the history
Simplify run_tower tower types
  • Loading branch information
samsrabin authored Feb 20, 2025
2 parents 0d44388 + a91c855 commit 7a4365d
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 298 deletions.
93 changes: 2 additions & 91 deletions python/ctsm/site_and_regional/neon_site.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,97 +34,8 @@ class NeonSite(TowerSite):
A class for encapsulating neon sites.
"""

def build_base_case(
self,
cesmroot,
output_root,
res,
compset,
user_mods_dirs=None,
overwrite=False,
setup_only=False,
):
if user_mods_dirs is None:
user_mods_dirs = [
os.path.join(
self.cesmroot, "cime_config", "usermods_dirs", "clm", "NEON", self.name
)
]
case_path = super().build_base_case(
cesmroot,
output_root,
res,
compset,
user_mods_dirs,
overwrite=overwrite,
setup_only=setup_only,
)

return case_path

# pylint: disable=too-many-statements
def run_case(
self,
base_case_root,
run_type,
prism,
user_version,
tower_type=None,
user_mods_dirs=None,
overwrite=False,
setup_only=False,
no_batch=False,
rerun=False,
experiment=False,
no_input_data_check=False,
xmlchange=None,
):
"""
Run case.
Args:
self
base_case_root: str, opt
file path of base case
run_type: str, opt
transient, post_ad, or ad case, default transient
prism: bool, opt
if True, use PRISM precipitation, default False
user_version: str, opt
default 'latest'
overwrite: bool, opt
default False
setup_only: bool, opt
default False; if True, set up but do not run case
no_batch: bool, opt
default False
rerun: bool, opt
default False
experiment: str, opt
name of experiment, default False
no_input_data_check: bool, opt
default False
"""
user_mods_dirs = [
os.path.join(self.cesmroot, "cime_config", "usermods_dirs", "clm", "NEON", self.name)
]
tower_type = "NEON"

super().run_case(
base_case_root,
run_type,
prism,
user_version,
tower_type,
user_mods_dirs,
overwrite,
setup_only,
no_batch,
rerun,
experiment,
no_input_data_check,
xmlchange,
)
def __init__(self, *args, **kwargs):
super().__init__("NEON", *args, **kwargs)

def modify_user_nl(self, case_root, run_type, rundir, site_lines=None):
# TODO: include neon-specific user namelist lines, using this as just an example currently
Expand Down
95 changes: 2 additions & 93 deletions python/ctsm/site_and_regional/plumber_site.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,99 +33,8 @@ class Plumber2Site(TowerSite):
A class for encapsulating plumber sites.
"""

def build_base_case(
self,
cesmroot,
output_root,
res,
compset,
user_mods_dirs=None,
overwrite=False,
setup_only=False,
):
if user_mods_dirs is None:
user_mods_dirs = [
os.path.join(
self.cesmroot, "cime_config", "usermods_dirs", "clm", "PLUMBER2", self.name
)
]
case_path = super().build_base_case(
cesmroot,
output_root,
res,
compset,
user_mods_dirs,
overwrite=overwrite,
setup_only=setup_only,
)

return case_path

# pylint: disable=too-many-statements
def run_case(
self,
base_case_root,
run_type,
prism,
user_version,
tower_type=None,
user_mods_dirs=None,
overwrite=False,
setup_only=False,
no_batch=False,
rerun=False,
experiment=False,
no_input_data_check=False,
xmlchange=None,
):
"""
Run case.
Args:
self
base_case_root: str, opt
file path of base case
run_type: str, opt
transient, post_ad, or ad case, default ad
(ad case is default because PLUMBER requires spinup)
prism: bool, opt
if True, use PRISM precipitation, default False
Note: only supported for NEON sites
user_version: str, opt
default 'latest'; this could be useful later
This is currently only implemented with neon (not plumber) sites
overwrite: bool, opt
default False
setup_only: bool, opt
default False; if True, set up but do not run case
no_batch: bool, opt
default False
rerun: bool, opt
default False
experiment: str, opt
name of experiment, default False
"""
user_mods_dirs = [
os.path.join(
self.cesmroot, "cime_config", "usermods_dirs", "clm", "PLUMBER2", self.name
)
]
tower_type = "PLUMBER"
super().run_case(
base_case_root,
run_type,
prism,
user_version,
tower_type,
user_mods_dirs,
overwrite,
setup_only,
no_batch,
rerun,
experiment,
no_input_data_check,
xmlchange,
)
def __init__(self, *args, **kwargs):
super().__init__("PLUMBER2", *args, **kwargs)

def set_ref_case(self, case):
super().set_ref_case(case)
Expand Down
8 changes: 4 additions & 4 deletions python/ctsm/site_and_regional/run_tower.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,9 +263,9 @@ def main(description):
if run_from_postad:
neon_site.finidat = None
if not base_case_root:
user_mods_dirs = None
neon_site.set_default_user_mods_dirs()
base_case_root = neon_site.build_base_case(
cesmroot, output_root, res, compset, user_mods_dirs, overwrite, setup_only
cesmroot, output_root, res, compset, overwrite, setup_only
)
logger.info("-----------------------------------")
logger.info("Running CTSM for neon site : %s", neon_site.name)
Expand Down Expand Up @@ -294,9 +294,9 @@ def main(description):
if run_from_postad:
plumber_site.finidat = None
if not base_case_root:
user_mods_dirs = None
plumber_site.set_default_user_mods_dirs()
base_case_root = plumber_site.build_base_case(
cesmroot, output_root, res, compset, user_mods_dirs, overwrite, setup_only
cesmroot, output_root, res, compset, overwrite, setup_only
)
logger.info("-----------------------------------")
logger.info("Running CTSM for plumber site : %s", plumber_site.name)
Expand Down
60 changes: 44 additions & 16 deletions python/ctsm/site_and_regional/tower_site.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@

logger = logging.getLogger(__name__)


# pylint: disable=too-many-instance-attributes
class TowerSite:
"""
Expand All @@ -41,12 +40,23 @@ class TowerSite:
-------
"""

def __init__(self, name, start_year, end_year, start_month, end_month, finidat):
def __init__(
self,
tower_type,
name,
start_year,
end_year,
start_month,
end_month,
finidat,
user_mods_dirs=None,
):
"""
Initializes TowerSite with the given arguments.
Parameters
----------
"""
self.tower_type = tower_type
self.name = name
self.start_year = int(start_year)
self.end_year = int(end_year)
Expand All @@ -55,6 +65,14 @@ def __init__(self, name, start_year, end_year, start_month, end_month, finidat):
self.cesmroot = path_to_ctsm_root()
self.finidat = finidat

if user_mods_dirs is None:
self.set_default_user_mods_dirs()
elif not isinstance(user_mods_dirs, list):
abort("Input user_mods_dirs is NOT a list as expected: " + str(user_mods_dirs))
else:
self.user_mods_dirs = user_mods_dirs
self.check_user_mods_dirs()

def __str__(self):
"""
Converts ingredients of the TowerSite to string for printing.
Expand All @@ -69,10 +87,29 @@ def __str__(self):
),
)

def set_default_user_mods_dirs(self):
"""
Sets user_mods_dirs to the default
"""
self.user_mods_dirs = [
os.path.join(
self.cesmroot, "cime_config", "usermods_dirs", "clm", self.tower_type, self.name
)
]
self.check_user_mods_dirs()

def check_user_mods_dirs(self):
"""
Checks that every user_mod_dir exists
"""
for dirtree in self.user_mods_dirs:
if not os.path.isdir(dirtree):
abort("Input user_mods_dirs dirtreetory does NOT exist: " + str(dirtree))

# TODO: Refactor to shorten this so the disable can be removed
# pylint: disable=too-many-statements
def build_base_case(
self, cesmroot, output_root, res, compset, user_mods_dirs, overwrite=False, setup_only=False
self, cesmroot, output_root, res, compset, overwrite=False, setup_only=False
):
"""
Function for building a base_case to clone.
Expand All @@ -91,8 +128,6 @@ def build_base_case(
base_case resolution or gridname
compset (str):
base case compset
user_mods_dirs (str):
path to the user-mod-directory to use
overwrite (bool) :
Flag to overwrite the case if exists
setup_only (bool) :
Expand All @@ -111,11 +146,6 @@ def build_base_case(
abort("Input compset is NOT a boolean as expected: " + str(compset))
if not isinstance(setup_only, bool):
abort("Input setup_only is NOT a boolean as expected: " + str(setup_only))
if not isinstance(user_mods_dirs, list):
abort("Input user_mods_dirs is NOT a list as expected: " + str(user_mods_dirs))
for dirtree in user_mods_dirs:
if not os.path.isdir(dirtree):
abort("Input user_mods_dirs dirtreetory does NOT exist: " + str(dirtree))

print("---- building a base case -------")
# pylint: disable=attribute-defined-outside-init
Expand All @@ -130,7 +160,7 @@ def build_base_case(
case_path = os.path.join(output_root, self.name)

logger.info("base_case_name : %s", self.name)
logger.info("user_mods_dir : %s", user_mods_dirs[0])
logger.info("user_mods_dir : %s", self.user_mods_dirs[0])

if overwrite and os.path.isdir(case_path):
print("Removing the existing case at: {}".format(case_path))
Expand All @@ -150,7 +180,7 @@ def build_base_case(
run_unsupported=True,
answer="r",
output_root=output_root,
user_mods_dirs=user_mods_dirs,
user_mods_dirs=self.user_mods_dirs,
driver="nuopc",
)

Expand Down Expand Up @@ -289,8 +319,6 @@ def run_case(
run_type,
prism,
user_version,
tower_type,
user_mods_dirs,
overwrite,
setup_only,
no_batch,
Expand Down Expand Up @@ -398,7 +426,7 @@ def run_case(
# that the shell_commands file is copied, as well as taking care of the DATM inputs.
# See https://github.com/ESCOMP/CTSM/pull/1872#pullrequestreview-1169407493
#
basecase.create_clone(case_root, keepexe=True, user_mods_dirs=user_mods_dirs)
basecase.create_clone(case_root, keepexe=True, user_mods_dirs=self.user_mods_dirs)

with Case(case_root, read_only=False) as case:
if run_type != "transient":
Expand All @@ -407,7 +435,7 @@ def run_case(
case.set_value("STOP_OPTION", "ndays")
case.set_value("REST_OPTION", "end")
case.set_value("CONTINUE_RUN", False)
if tower_type == "NEON":
if self.tower_type == "NEON":
case.set_value("NEONVERSION", version)
if prism:
case.set_value("CLM_USRDAT_NAME", "NEON.PRISM")
Expand Down
Loading

0 comments on commit 7a4365d

Please sign in to comment.