From 4f1cbc57ed001edcb34920cf82e0068b11a4dacf Mon Sep 17 00:00:00 2001 From: Spencer Wong Date: Mon, 12 Aug 2024 16:07:05 +1000 Subject: [PATCH 1/6] Trial at patching ice history requests into namelist --- payu/models/access.py | 25 +++++++++++++++++++++++++ payu/models/cice.py | 1 + 2 files changed, 26 insertions(+) diff --git a/payu/models/access.py b/payu/models/access.py index a542f5cf..8ce66b2d 100644 --- a/payu/models/access.py +++ b/payu/models/access.py @@ -51,6 +51,11 @@ def __init__(self, expt, name, config): if model.model_type == 'cice5': model.access_restarts.append(['u_star.nc', 'sicemass.nc']) + + if model.model_type == 'cice': + model.history_nml_fname = 'ice_history.nml' + model.optional_config_files.append(model.history_nml_fname) + def setup(self): if not self.top_level_model: @@ -86,6 +91,26 @@ def setup(self): if os.path.isfile(f_src): make_symlink(f_src, f_dst) + if model.model_type == 'cice': + # Patch the cice namelist with the history requests + # if a separate history namelist exists. + history_nml_fpath = os.path.join(model.control_path, + model.history_nml_fname) + if os.path.isfile(history_nml_fpath): + history_nml = f90nml.read(history_nml_fpath) + work_ice_nml_path = os.path.join( + model.work_path, + model.ice_nml_fname + ) + #TODO: This requires that cice.py's setup has already been + # called so that the ice_nml exists in the control directory. + # Is this always the case?? + work_ice_nml = f90nml.read(work_ice_nml_path) + print("SPENCER: patching ice namelist") + print(work_ice_nml_path) + work_ice_nml.patch(history_nml) + work_ice_nml.write(work_ice_nml_path, force = True) + if model.model_type in ('cice', 'matm'): # Update the supplemental OASIS namelists diff --git a/payu/models/cice.py b/payu/models/cice.py index 0ba13822..82715474 100644 --- a/payu/models/cice.py +++ b/payu/models/cice.py @@ -247,6 +247,7 @@ def setup(self): # Force creation of a dump (restart) file at end of run setup_nml['dump_last'] = True + # Write the prepared cice namelist into the work directory nml_path = os.path.join(self.work_path, self.ice_nml_fname) self.ice_in.write(nml_path, force=True) From 297666aaba5079c5582b5161e7ae7fb4189c4016 Mon Sep 17 00:00:00 2001 From: anton-seaice Date: Tue, 13 Aug 2024 16:23:16 +1000 Subject: [PATCH 2/6] move changes from access class to cice class and fix dump_last --- payu/models/access.py | 24 ------------------------ payu/models/cice.py | 14 ++++++++++++-- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/payu/models/access.py b/payu/models/access.py index 8ce66b2d..c4cbc19d 100644 --- a/payu/models/access.py +++ b/payu/models/access.py @@ -51,10 +51,6 @@ def __init__(self, expt, name, config): if model.model_type == 'cice5': model.access_restarts.append(['u_star.nc', 'sicemass.nc']) - - if model.model_type == 'cice': - model.history_nml_fname = 'ice_history.nml' - model.optional_config_files.append(model.history_nml_fname) def setup(self): @@ -90,26 +86,6 @@ def setup(self): if os.path.isfile(f_src): make_symlink(f_src, f_dst) - - if model.model_type == 'cice': - # Patch the cice namelist with the history requests - # if a separate history namelist exists. - history_nml_fpath = os.path.join(model.control_path, - model.history_nml_fname) - if os.path.isfile(history_nml_fpath): - history_nml = f90nml.read(history_nml_fpath) - work_ice_nml_path = os.path.join( - model.work_path, - model.ice_nml_fname - ) - #TODO: This requires that cice.py's setup has already been - # called so that the ice_nml exists in the control directory. - # Is this always the case?? - work_ice_nml = f90nml.read(work_ice_nml_path) - print("SPENCER: patching ice namelist") - print(work_ice_nml_path) - work_ice_nml.patch(history_nml) - work_ice_nml.write(work_ice_nml_path, force = True) if model.model_type in ('cice', 'matm'): diff --git a/payu/models/cice.py b/payu/models/cice.py index 82715474..4dbae595 100644 --- a/payu/models/cice.py +++ b/payu/models/cice.py @@ -45,6 +45,8 @@ def __init__(self, expt, name, config): self.ice_nml_fname = 'cice_in.nml' + self.history_nml_fname = 'ice_history.nml' #only used by payu + self.set_timestep = self.set_local_timestep self.copy_inputs = False @@ -156,6 +158,13 @@ def get_access_ptr_restart_dir(self): def setup(self): super(Cice, self).setup() + # If there is a seperate ice_history.nml, update the cice namelist with its contents + history_nml_fpath = os.path.join(self.control_path, + self.history_nml_fname) + if os.path.isfile(history_nml_fpath): + history_nml = f90nml.read(history_nml_fpath) + self.ice_in.patch(history_nml) + setup_nml = self.ice_in['setup_nml'] init_date = datetime.date(year=setup_nml['year_init'], month=1, day=1) @@ -244,8 +253,9 @@ def setup(self): assert(total_runtime % setup_nml['dt'] == 0) setup_nml['istep0'] = int(total_runtime / setup_nml['dt']) - # Force creation of a dump (restart) file at end of run - setup_nml['dump_last'] = True + if self.model_type != 'cice' : #model_type==cice5 + # Force creation of a dump (restart) file at end of run + setup_nml['dump_last'] = True # Write the prepared cice namelist into the work directory nml_path = os.path.join(self.work_path, self.ice_nml_fname) From 4c4d741213f3e5b18e49ee8722070d4d721de6e7 Mon Sep 17 00:00:00 2001 From: anton-seaice Date: Tue, 13 Aug 2024 16:35:42 +1000 Subject: [PATCH 3/6] PEP --- payu/models/access.py | 3 +-- payu/models/cice.py | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/payu/models/access.py b/payu/models/access.py index c4cbc19d..a542f5cf 100644 --- a/payu/models/access.py +++ b/payu/models/access.py @@ -52,7 +52,6 @@ def __init__(self, expt, name, config): if model.model_type == 'cice5': model.access_restarts.append(['u_star.nc', 'sicemass.nc']) - def setup(self): if not self.top_level_model: return @@ -86,7 +85,7 @@ def setup(self): if os.path.isfile(f_src): make_symlink(f_src, f_dst) - + if model.model_type in ('cice', 'matm'): # Update the supplemental OASIS namelists diff --git a/payu/models/cice.py b/payu/models/cice.py index 4dbae595..9cc6daf4 100644 --- a/payu/models/cice.py +++ b/payu/models/cice.py @@ -45,7 +45,7 @@ def __init__(self, expt, name, config): self.ice_nml_fname = 'cice_in.nml' - self.history_nml_fname = 'ice_history.nml' #only used by payu + self.history_nml_fname = 'ice_history.nml' # only used by payu self.set_timestep = self.set_local_timestep @@ -158,7 +158,8 @@ def get_access_ptr_restart_dir(self): def setup(self): super(Cice, self).setup() - # If there is a seperate ice_history.nml, update the cice namelist with its contents + # If there is a seperate ice_history.nml, + # update the cice namelist with its contents history_nml_fpath = os.path.join(self.control_path, self.history_nml_fname) if os.path.isfile(history_nml_fpath): @@ -253,11 +254,10 @@ def setup(self): assert(total_runtime % setup_nml['dt'] == 0) setup_nml['istep0'] = int(total_runtime / setup_nml['dt']) - if self.model_type != 'cice' : #model_type==cice5 + if self.model_type != 'cice': # model_type==cice5 # Force creation of a dump (restart) file at end of run setup_nml['dump_last'] = True - # Write the prepared cice namelist into the work directory nml_path = os.path.join(self.work_path, self.ice_nml_fname) self.ice_in.write(nml_path, force=True) From 3832137e4ccf26ade1c932d867a83dd40a5fda78 Mon Sep 17 00:00:00 2001 From: anton-seaice Date: Tue, 13 Aug 2024 16:36:17 +1000 Subject: [PATCH 4/6] PEP --- payu/models/cice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/payu/models/cice.py b/payu/models/cice.py index 9cc6daf4..e18d8ed7 100644 --- a/payu/models/cice.py +++ b/payu/models/cice.py @@ -158,7 +158,7 @@ def get_access_ptr_restart_dir(self): def setup(self): super(Cice, self).setup() - # If there is a seperate ice_history.nml, + # If there is a seperate ice_history.nml, # update the cice namelist with its contents history_nml_fpath = os.path.join(self.control_path, self.history_nml_fname) From c750e6fe078b6010a221e73415c572f8d296eea7 Mon Sep 17 00:00:00 2001 From: anton-seaice Date: Thu, 15 Aug 2024 14:10:55 +1000 Subject: [PATCH 5/6] tests --- test/models/test_cice.py | 144 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 test/models/test_cice.py diff --git a/test/models/test_cice.py b/test/models/test_cice.py new file mode 100644 index 00000000..13b91a10 --- /dev/null +++ b/test/models/test_cice.py @@ -0,0 +1,144 @@ +import os +import shutil + +import pytest +import f90nml + +import payu + +from test.common import cd +from test.common import tmpdir, ctrldir, labdir, expt_workdir, ctrldir_basename +from test.common import write_config, write_metadata +from test.common import make_inputs, make_exe + +verbose = True + +DEFAULT_CICE_NML = { + "setup_nml": { + "history_dir": "./HISTORY/", + "restart_dir": "./RESTART/", + "year_init": 9999, + "days_per_year": 360, + "ice_ic": "default", + "restart": ".false.", + "pointer_file": "./RESTART/ice.restart_file", + "runtype": "initial", + "npt": 99999, + "dt": 1, + }, + "grid_nml": {"grid_file": "./INPUT/grid.nc", "kmt_file": "./INPUT/kmt.nc"}, + "icefields_nml": {"f_icy": "x"}, +} +CICE_NML_NAME = "cice_in.nml" +HIST_NML_NAME = "ice_history.nml" + + +def setup_module(module): + """ + Put any test-wide setup code in here, e.g. creating test files + """ + if verbose: + print("setup_module module:%s" % module.__name__) + + # Should be taken care of by teardown, in case remnants lying around + try: + shutil.rmtree(tmpdir) + except FileNotFoundError: + pass + + try: + tmpdir.mkdir() + labdir.mkdir() + ctrldir.mkdir() + expt_workdir.mkdir(parents=True) + make_inputs() + make_exe() + write_metadata() + except Exception as e: + print(e) + + config = { + "laboratory": "lab", + "jobname": "testrun", + "model": "cice", + "exe": "test.exe", + "experiment": ctrldir_basename, + "metadata": {"enable": False}, + } + write_config(config) + + +def teardown_module(module): + """ + Put any test-wide teardown code in here, e.g. removing test outputs + """ + if verbose: + print("teardown_module module:%s" % module.__name__) + + try: + shutil.rmtree(tmpdir) + print("removing tmp") + except Exception as e: + print(e) + + +# Confirm that 1: payu overwrites cice_in with ice_history +# 2: payu works without ice_history.nml +# 3: payu overwrites cice_in and allows additional fields +# In all cases confirm dump_last is not added to model_type='cice' +@pytest.mark.parametrize( + "ice_history", + [ + {"icefields_nml": { "f_icy": "m" }}, + False, + {"icefields_nml": {"f_icy": "m", "f_new": "y"}}, + ], +) +def test_setup(ice_history): + cice_nml = DEFAULT_CICE_NML + + # create the files parsed by setup: + # 1. a restart pointer file + with cd(expt_workdir): + os.mkdir(cice_nml["setup_nml"]["restart_dir"]) + with open(cice_nml["setup_nml"]["pointer_file"], "w") as f: + f.write("./RESTART/ice.r") + f.close() + + with cd(ctrldir): + # 2. Create config.nml + f90nml.write(cice_nml, CICE_NML_NAME) + if ice_history: + f90nml.write(ice_history, HIST_NML_NAME) + + lab = payu.laboratory.Laboratory(lab_path=str(labdir)) + expt = payu.experiment.Experiment(lab, reproduce=False) + model = expt.models[0] + + # Function to test + model.setup() + + # Check config files are moved to model's work path + work_path_files = os.listdir(model.work_path) + assert CICE_NML_NAME in work_path_files + + # Check cice_in was patched with ice_history + work_input_fpath = os.path.join(model.work_path, CICE_NML_NAME) + input_nml = f90nml.read(work_input_fpath) + if ice_history: + assert input_nml["icefields_nml"] == ice_history["icefields_nml"] + else: + assert input_nml["icefields_nml"] == DEFAULT_CICE_NML["icefields_nml"] + + # Check dump_last doesn't exist + with pytest.raises(KeyError, match="dump_last"): + input_nml["setup_nml"]["dump_last"] + + # cleanup + with cd(expt_workdir): + os.remove(cice_nml["setup_nml"]["pointer_file"]) + os.rmdir(cice_nml["setup_nml"]["restart_dir"]) + with cd(ctrldir): + os.remove(CICE_NML_NAME) + if ice_history: + os.remove(HIST_NML_NAME) From 64e356c76d1ff86afb2c49789d45eb23fa9f1055 Mon Sep 17 00:00:00 2001 From: anton-seaice Date: Thu, 15 Aug 2024 14:15:22 +1000 Subject: [PATCH 6/6] move dump_last to cice5 driver only --- payu/models/cice.py | 4 ---- payu/models/cice5.py | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/payu/models/cice.py b/payu/models/cice.py index e18d8ed7..8f058117 100644 --- a/payu/models/cice.py +++ b/payu/models/cice.py @@ -254,10 +254,6 @@ def setup(self): assert(total_runtime % setup_nml['dt'] == 0) setup_nml['istep0'] = int(total_runtime / setup_nml['dt']) - if self.model_type != 'cice': # model_type==cice5 - # Force creation of a dump (restart) file at end of run - setup_nml['dump_last'] = True - nml_path = os.path.join(self.work_path, self.ice_nml_fname) self.ice_in.write(nml_path, force=True) diff --git a/payu/models/cice5.py b/payu/models/cice5.py index 0a498b6d..08bac794 100644 --- a/payu/models/cice5.py +++ b/payu/models/cice5.py @@ -53,6 +53,9 @@ def set_local_timestep(self, t_step): self.ice_in.write(ice_in_path, force=True) def setup(self): + # Force creation of a dump (restart) file at end of run + self.ice_in['setup_nml']['dump_last'] = True + super(Cice5, self).setup() # Make log dir