Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check CICE4 restart file dates #539

Merged
merged 15 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions payu/models/access.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import re
import shutil
import sys
import struct

# Extensions
import f90nml
Expand Down Expand Up @@ -218,6 +219,12 @@ def setup(self):
f90nml.write(cpl_nml, nml_work_path + '~')
shutil.move(nml_work_path + '~', nml_work_path)

if model.model_type == 'cice':
# Set up and check the cice restart files.
cice4_make_restart_pointer(model,
run_start_date,
previous_runtime)

anton-seaice marked this conversation as resolved.
Show resolved Hide resolved
# Now change the oasis runtime. This needs to be done after the others.
for model in self.expt.models:
if model.model_type == 'oasis':
Expand Down Expand Up @@ -333,3 +340,65 @@ def set_model_output_paths(self):

def collate(self):
pass


def cice4_make_restart_pointer(cice_model, run_start_date, previous_runtime):
"""
Generate restart pointer file 'ice.restart_file' specifying
the correct 'iced.YYYYMMDD' restart file, based on the run
start date.
Additionally check that the `iced.YYYYMNDD` restart file's header
has the correct previous runtime.
"""
# Expected iced restart file name based on start date
run_start_date_int = cal.date_to_int(run_start_date)
iced_restart_file = f"iced.{run_start_date_int:08d}"

if iced_restart_file not in cice_model.get_prior_restart_files():
msg = (f"Expected restart file {iced_restart_file} based on "
f"run start date {run_start_date_int} "
f"not found in {cice_model.prior_restart_path}.")
raise FileNotFoundError(msg)

res_ptr_path = os.path.join(cice_model.work_init_path,
'ice.restart_file')
if os.path.islink(res_ptr_path):
# If we've linked in a previous pointer it should be deleted
os.remove(res_ptr_path)

iced_path = os.path.join(cice_model.prior_restart_path,
iced_restart_file)

# Check that the prior run time in the iced restart header matches
# the previous runtime calculated from the calendar file.
cice4_check_date_consistency(cice_model, iced_path, previous_runtime)

with open(res_ptr_path, 'w') as res_ptr:
res_dir = cice_model.get_ptr_restart_dir()
res_ptr.write(os.path.join(res_dir, iced_restart_file))


def cice4_check_date_consistency(cice_model, iced_path, previous_runtime):
"""
Check that the previous runtime in iced restart file header
matches the runtime calculated from the calendar restart file.
"""
_, _, cice_iced_runtime, _ = read_binary_iced_header(iced_path)
if previous_runtime != cice_iced_runtime:
msg = (f"Previous runtime from calendar file "
f"{cice_model.start_date_nml_name}: {previous_runtime} "
"does not match previous runtime in restart"
f"file {iced_path}: {cice_iced_runtime}."
)
raise RuntimeError(msg)


def read_binary_iced_header(iced_path):
"""
Read header information from a CICE4 binary restart file.
"""
with open(iced_path, 'rb') as iced_file:
header = iced_file.read(24)
anton-seaice marked this conversation as resolved.
Show resolved Hide resolved
bint, istep0, time, time_forc = struct.unpack('>iidd', header)

return (bint, istep0, time, time_forc)
32 changes: 9 additions & 23 deletions payu/models/cice.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,29 +162,10 @@ def setup(self):
self.ice_in.patch(history_nml)

setup_nml = self.ice_in['setup_nml']
self._calc_runtime()

if self.prior_restart_path:
# Generate ice.restart_file
# TODO: better check of restart filename
iced_restart_file = None
iced_restart_files = [f for f in self.get_prior_restart_files()
if f.startswith('iced.')]

if len(iced_restart_files) > 0:
iced_restart_file = sorted(iced_restart_files)[-1]

if iced_restart_file is None:
raise FileNotFoundError(
f'No iced restart file found in {self.prior_restart_path}')

res_ptr_path = os.path.join(self.work_init_path,
'ice.restart_file')
if os.path.islink(res_ptr_path):
# If we've linked in a previous pointer it should be deleted
os.remove(res_ptr_path)
with open(res_ptr_path, 'w') as res_ptr:
res_dir = self.get_ptr_restart_dir()
print(os.path.join(res_dir, iced_restart_file), file=res_ptr)
self.make_restart_ptr()
anton-seaice marked this conversation as resolved.
Show resolved Hide resolved

# Update input namelist
setup_nml['runtype'] = 'continue'
Expand All @@ -198,8 +179,6 @@ def setup(self):
if setup_nml['restart']:
self.link_restart(setup_nml['pointer_file'])

self._calc_runtime()

# Write any changes to the work directory copy of the cice
# namelist
nml_path = os.path.join(self.work_path, self.ice_nml_fname)
Expand Down Expand Up @@ -351,3 +330,10 @@ def link_restart(self, fpath):
)

make_symlink(input_path, input_work_path)

def make_restart_ptr(self):
"""
CICE4 restart pointers are created by the access driver, where
the correct run start dates are available.
"""
pass
25 changes: 25 additions & 0 deletions payu/models/cice5.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,28 @@ def _calc_runtime(self):
the timing information in the cice_in.nml namelist.
"""
pass

def make_restart_ptr(self):
"""
Generate restart pointer which points to the latest iced.YYYYMMDD
restart file.
"""
iced_restart_file = None
iced_restart_files = [f for f in self.get_prior_restart_files()
if f.startswith('iced.')]

if len(iced_restart_files) > 0:
iced_restart_file = sorted(iced_restart_files)[-1]

if iced_restart_file is None:
raise FileNotFoundError(
f'No iced restart file found in {self.prior_restart_path}')

res_ptr_path = os.path.join(self.work_init_path,
'ice.restart_file')
if os.path.islink(res_ptr_path):
# If we've linked in a previous pointer it should be deleted
os.remove(res_ptr_path)
with open(res_ptr_path, 'w') as res_ptr:
res_dir = self.get_ptr_restart_dir()
res_ptr.write(os.path.join(res_dir, iced_restart_file))
Loading