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

add checks of io layout to cmeps driver #496

Merged
merged 42 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
889d632
add checks of io layout to cmeps driver
anton-seaice Aug 29, 2024
76f2a33
move to python errors and PEP things
anton-seaice Aug 29, 2024
1b351d3
getting the greater checks the right way around
anton-seaice Aug 29, 2024
44d84b2
third time lucky
anton-seaice Aug 29, 2024
c937dd6
PEP
anton-seaice Aug 29, 2024
f572ba8
review feedback and improvements for corner cases
anton-seaice Aug 30, 2024
74ca45a
tidy
anton-seaice Aug 30, 2024
673b043
whitespace
anton-seaice Aug 30, 2024
5facb60
runconfig_get_component_list test
anton-seaice Aug 30, 2024
3871403
First pass of tests
anton-seaice Aug 30, 2024
9a6c663
tidy and PEP
anton-seaice Aug 30, 2024
511a462
PEP
anton-seaice Aug 30, 2024
75311eb
PEP
anton-seaice Aug 30, 2024
7176be8
PEP
anton-seaice Aug 30, 2024
673bbee
PEP
anton-seaice Aug 30, 2024
a78c951
PEP
anton-seaice Aug 30, 2024
1c6feb8
PEP
anton-seaice Aug 30, 2024
cf47586
PEP
anton-seaice Aug 30, 2024
b327c38
PEP
anton-seaice Aug 30, 2024
d102d1c
PEP
anton-seaice Aug 30, 2024
003717f
Split accessom3 tests into folder
anton-seaice Sep 2, 2024
a0c08be
add missing file
anton-seaice Sep 2, 2024
e455023
finalise testing
Sep 3, 2024
75cc917
PEP
Sep 3, 2024
552df25
PEP
Sep 3, 2024
1ff559c
PEP
Sep 3, 2024
618b471
PEP
Sep 3, 2024
70092ad
PEP
Sep 3, 2024
ef0576e
PEP
Sep 3, 2024
fce4b23
Better error wording
Sep 4, 2024
d09e4d1
fix pestride
Sep 4, 2024
0171f5e
PEP
Sep 4, 2024
d4a9371
PEP
Sep 4, 2024
cb31e76
constant for nuopc runseq
Sep 4, 2024
4d33af3
Update payu/models/cesm_cmeps.py
anton-seaice Sep 11, 2024
94760c3
Update payu/models/cesm_cmeps.py
anton-seaice Sep 11, 2024
b954482
Update payu/models/cesm_cmeps.py
anton-seaice Sep 16, 2024
8dddc49
Review comments
anton-seaice Sep 18, 2024
25c8c31
review comments & PEP
anton-seaice Sep 18, 2024
9ec70a6
review & PEP
anton-seaice Sep 18, 2024
09bee92
PEP
anton-seaice Sep 18, 2024
a90763b
PEP
anton-seaice Sep 18, 2024
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
110 changes: 95 additions & 15 deletions payu/models/cesm_cmeps.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@

import os
import re
import errno
import glob
import shutil
import multiprocessing

Expand All @@ -22,6 +20,9 @@
from payu.models.fms import fms_collate
from payu.models.mom6 import mom6_add_parameter_files

NUOPC_CONFIG = "nuopc.runconfig"
anton-seaice marked this conversation as resolved.
Show resolved Hide resolved
NUOPC_RUNSEQ = "nuopc.runseq"

# Add as needed
component_info = {
"mom": {
Expand Down Expand Up @@ -75,8 +76,8 @@ def __init__(self, expt, name, config):
self.config_files = [
"drv_in",
"fd.yaml",
"nuopc.runconfig",
"nuopc.runseq"
NUOPC_CONFIG,
NUOPC_RUNSEQ
]

self.realms = ["ocn", "ice", "wav", "atm", "rof", "cpl"]
Expand All @@ -85,7 +86,7 @@ def __init__(self, expt, name, config):
self.rpointers = [] # To be inferred from nuopc.runconfig

def get_runconfig(self, path):
self.runconfig = Runconfig(os.path.join(path, 'nuopc.runconfig'))
self.runconfig = Runconfig(os.path.join(path, NUOPC_CONFIG))

def get_components(self):
"""Get components from nuopc.runconfig"""
Expand Down Expand Up @@ -156,15 +157,9 @@ def setup(self):

self.runconfig.set("ALLCOMP_attributes", "start_type", start_type)

# Check pelayout makes sense
all_realms = self.realms + ["glc", "lnd"]
cpucount = int(
self.expt.config.get('ncpus', multiprocessing.cpu_count())
)
for realm in all_realms:
ntasks = int(self.runconfig.get("PELAYOUT_attributes", f"{realm}_ntasks"))
assert cpucount >= ntasks, "Insufficient cpus for the pelayout in nuopc.runconfig"

# run checks on nuopc.runfig
self._setup_checks()

# Ensure that restarts will be written at the end of each run
stop_n = self.runconfig.get("CLOCK_attributes", "stop_n")
stop_option = self.runconfig.get("CLOCK_attributes", "stop_option")
Expand All @@ -174,7 +169,7 @@ def setup(self):
mkdir_p(os.path.join(self.work_path, 'log'))
mkdir_p(os.path.join(self.work_path, 'timing'))

self.runconfig.write(os.path.join(self.work_path, 'nuopc.runconfig'))
self.runconfig.write(os.path.join(self.work_path, NUOPC_CONFIG))

# Horrible hack to make a link to the mod_def.ww3 input in the work
# directory
Expand All @@ -190,6 +185,76 @@ def setup(self):
# TODO: copied this from other models. Surely we want to exit here or something
print('payu: error: Unable to find mod_def.ww3 file in input directory')

def _setup_checks(self):
# check pelayout fits within requested cpucount
cpucount = int(
self.expt.config.get('ncpus', multiprocessing.cpu_count())
aidanheerdegen marked this conversation as resolved.
Show resolved Hide resolved
)
all_realms = self.realms
anton-seaice marked this conversation as resolved.
Show resolved Hide resolved
for realm in all_realms:
ntasks = int(self.runconfig.get("PELAYOUT_attributes", f"{realm}_ntasks"))
nthreads = int(self.runconfig.get("PELAYOUT_attributes", f"{realm}_nthreads"))
anton-seaice marked this conversation as resolved.
Show resolved Hide resolved
rootpe = int(self.runconfig.get("PELAYOUT_attributes", f"{realm}_rootpe"))
anton-seaice marked this conversation as resolved.
Show resolved Hide resolved
pestride = int(self.runconfig.get("PELAYOUT_attributes", f"{realm}_pestride"))

anton-seaice marked this conversation as resolved.
Show resolved Hide resolved
if nthreads < 1:
raise ValueError(f"The number of {realm}_nthreads ({nthreads}) in "
f"{NUOPC_CONFIG} must be at least 1.")

if nthreads > 1:
npes = nthreads*ntasks*pestride
anton-seaice marked this conversation as resolved.
Show resolved Hide resolved
# this is taken from
# https://github.com/ESCOMP/CMEPS/blob/5b7d76978e2fdc661ec2de4ba9834b985decadc6/cesm/driver/esm.F90#L1007
# this correct calculation might be (ntasks-1)*pestride*nthreads + nthreads
anton-seaice marked this conversation as resolved.
Show resolved Hide resolved
else:
npes = (ntasks-1)*pestride + 1
anton-seaice marked this conversation as resolved.
Show resolved Hide resolved
aidanheerdegen marked this conversation as resolved.
Show resolved Hide resolved

if (rootpe + npes) > cpucount:
anton-seaice marked this conversation as resolved.
Show resolved Hide resolved
raise ValueError(
f"Insufficient cpus for the {realm} pelayout in {NUOPC_CONFIG}"
)

# check iolayout
if realm == "cpl":
comp = "MED" # med and cpl names are both used in runconfig
else:
comp = realm.upper()
aidanheerdegen marked this conversation as resolved.
Show resolved Hide resolved
if comp in self.runconfig.get_component_list():
io_section = f"{comp}_modelio"
nc_type = self.runconfig.get(io_section, "pio_typename")
ioroot = int(self.runconfig.get(io_section, "pio_root"))

if ioroot >= npes:
raise ValueError(
f"{io_section} pio_root exceeds available PEs (max: {npes - 1}) "
f"in {NUOPC_CONFIG}."
)

match nc_type:
case "netcdf":
break
case "netcdf4p" | "pnetcdf":
if self.runconfig.get(io_section, "pio_async_interface") == ".false.":
niotasks = int(self.runconfig.get(io_section, "pio_numiotasks"))
iostride = int(self.runconfig.get(io_section, "pio_stride"))
aidanheerdegen marked this conversation as resolved.
Show resolved Hide resolved
if (ioroot + (niotasks-1)*iostride) >= npes:
raise ValueError(
f"The iolayout for {io_section} in {NUOPC_CONFIG} is "
"requesting out of range cpus"
)
# To-do: add coverage for pio_async == .true.
aidanheerdegen marked this conversation as resolved.
Show resolved Hide resolved
case "netcdf4c":
raise ValueError(
f"netcdf4c in {io_section} of {NUOPC_CONFIG} is deprecated, "
"use netcdf4p"
)
case _:
raise ValueError(
f"The iotype for {io_section} in {NUOPC_CONFIG} is "
'invalid, valid options are "netcdf", "pnetcdf" and "netcdf4p"'
anton-seaice marked this conversation as resolved.
Show resolved Hide resolved
)
return True

def archive(self):
super().archive()

Expand Down Expand Up @@ -313,6 +378,21 @@ def get(self, section, variable, value=None):
else:
return value

def get_component_list(self, value=None):
"""
Get the `component_list`
"""
m = re.search(
r'component_list:\s*(.*)',
self.contents
)

if m is not None:
components_str = m.group(1).strip()
return components_str.split()
else:
return value
aidanheerdegen marked this conversation as resolved.
Show resolved Hide resolved

def set(self, section, variable, new_value):
"""
Overwrite the value of any existing variable
Expand Down
Loading
Loading