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

Bring rpointer changes to BLOM #513

Merged
merged 17 commits into from
Mar 20, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
163 changes: 121 additions & 42 deletions cime_config/buildnml
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,6 @@ def buildnml(case, caseroot, compname):
expect(blom_vcoord == "isopyc_bulkml" or turbclo == "null",
f"BLOM_VCOORD == {blom_vcoord} and BLOM_TURBULENT_CLOSURE == {turbclo} is not a valid combination")

#--------------------------
# Construct ParamGen objects:
#--------------------------

xml_fil = os.path.join(srcroot,"components","blom","cime_config","namelist_definition_blom.xml")
pg_blom = OcnInParamGen.from_namelist_xml(xml_fil)

#------------------------
# Loop over all instances:
Expand All @@ -115,6 +109,59 @@ def buildnml(case, caseroot, compname):

# Convert instance number to integer:
ninst = int(ninst_ocn)

# handle rpointers:
# after changes to rpointer files, now we can have multiple rpointers with timestamps
if ninst > 1:
# find all rpointers
rpointers_list = sorted(glob.glob(os.path.join(rundir, "rpointer.ocn*")))
timestmp_list = [None] * len(rpointers_list)
prev_inst_list = [None] * len(rpointers_list)
has_inst = [False] *len(rpointers_list)
for i in range(len(rpointers_list)):
rpointers_list[i] = os.path.basename(rpointers_list[i])
if (len(rpointers_list[i]) > 12 and len(rpointers_list[i]) < 30):
# there is no instance suffix but timestamp
has_inst[i] = False
timestmp_list[i] = rpointers_list[i][-16:-1]
elif len(rpointers_list[i]) > 30:
# both instance and timestamp
has_inst[i] = True
timestmp_list[i] = rpointers_list[i][-16:-1]
prev_inst_list[i] = int(rpointers_list[i][-21:-17])
elif len(rpointers_list[i]) > 12 and len(rpointers_list[i]) < 20:
# only instance
has_inst[i] = True
timestmp_list[i] = ""
prev_inst_list[i] = int(rpointers_list[i][-4:])
else:
# no instance no timestamp
has_inst[i] = False
timestmp_list[i] = ""
prev_inst_list[i] = -1
# check for instances in rpointers

if all(has_inst):
if prev_inst_list:
print(prev_inst_list)
if max(prev_inst_list) != ninst:
print('Number of instances in rpointers > 0 but not equal number or blom instances - exit now')
exit
else:
for i in range(len(rpointers_list)):
single_rpointer = os.path.join(rundir,rpointers_list[i])
inst_string = ""
if not has_inst[i]:
# this loop has to be inside, since there can be more than one rpointer.ocn per instance in the rundir.
for inst_counter in range(1, ninst+1):
inst_string = '_%04d' % inst_counter
inst_rpointer = os.path.join(rundir,"rpointer.ocn"+ inst_string + '.' + timestmp_list[i])
# only copy rpointers if instance rpointer does not exist already
if not os.path.isfile(inst_rpointer):
shutil.copy(single_rpointer,inst_rpointer)
# endif ninst>0
# if a user tries to run a case from a multi instance run with single instance
# they have to manually rename the rpointers and restart files

for inst_counter in range(1, ninst+1):

Expand All @@ -124,26 +171,21 @@ def buildnml(case, caseroot, compname):

if os.path.isfile(input_data_list):
os.remove(input_data_list)

#--------------------------
# Construct ParamGen objects:
#--------------------------
# paramgen has to be initilized for each instance separately.
xml_fil = os.path.join(srcroot,"components","blom","cime_config","namelist_definition_blom.xml")
pg_blom = OcnInParamGen.from_namelist_xml(xml_fil)

# -----------------------------------------------------
# Determine instance string
# -----------------------------------------------------

inst_string = ""
if ninst > 1:
single_case_rpointer = os.path.join(rundir, "rpointer.ocn")
inst_string = '_%04d' % inst_counter
instance_rpointer = os.path.join(rundir, "rpointer.ocn"+inst_string)

# If multi-instance case does not have restart file, use
# single-case restart for each instance

if os.path.isfile(single_case_rpointer) and \
not os.path.isfile(instance_rpointer):
shutil.copy(single_case_rpointer, instance_rpointer)
# End if
# End if


# -----------------------------------------------------
# Create blomconf/namelist
# -----------------------------------------------------
Expand Down Expand Up @@ -244,7 +286,7 @@ def buildnml(case, caseroot, compname):
var_list = ('DIN_LOC_ROOT', 'RUN_TYPE', 'BLOM_VCOORD','BLOM_NDEP_SCENARIO',
'CCSM_CO2_PPMV','OCN_CO2_TYPE',
'HAMOCC_SEDSPINUP_YR_START','HAMOCC_SEDSPINUP_YR_END',
'HAMOCC_SEDSPINUP_NCYCLE')
'HAMOCC_SEDSPINUP_NCYCLE')
for item in var_list:
case_dict[item] = case.get_value(item)

Expand All @@ -253,6 +295,43 @@ def buildnml(case, caseroot, compname):
#----------------------------------------------------
# Reset values of some variables
#----------------------------------------------------


icfile_inst = None
if run_type == 'hybrid' or run_type == 'branch':
icfile = "%s.blom.r.%s-%s.nc" %(run_refcase, run_refdate, run_reftod)
print(icfile)
#to start a multi-driver run from single instance run
if ninst > 1:
icfile_inst="%s.blom%s.r.%s-%s.nc" %(run_refcase,inst_string, run_refdate, run_reftod)
if (os.path.isfile(os.path.join(rundir,icfile)) and
(not os.path.isfile(os.path.join(rundir,icfile_inst)))):
shutil.copy(os.path.join(rundir, icfile),
os.path.join(rundir, icfile_inst))

icfile=icfile_inst

# since stage_refcase is done within CIME's create_namelists()
# before component namlist is created
# we have to make this absolute to make check_inputdata work.
pg_blom.set_value("icfile",os.path.join(rundir,icfile))
print(pg_blom.get_value("icfile"))

driver = case.get_value("COMP_INTERFACE")
if driver == 'mct':
pg_blom.set_value('rpoint','rpointer.ocn')
elif driver == 'nuopc':
# check for older rpointers happens in the ocn cap
drv_ptr = case.get_value("DRV_RESTART_POINTER")
if drv_ptr:
blom_ptr = drv_ptr.replace("cpl","ocn")
blom_ptr = blom_ptr.replace("_0001", inst_string)
else:
# non-timestamped rpointers are used in older runs
blom_ptr = pg_blom.set_value('rpoint','rpointer.ocn')
if os.path.exists(os.path.join(rundir, blom_ptr)):
pg_blom.set_value('rpoint', blom_ptr)


run_startdate = case.get_value("RUN_STARTDATE")
idate = run_startdate.replace('-','')
Expand All @@ -279,7 +358,7 @@ def buildnml(case, caseroot, compname):
namelist_file += inst_string

# Create BLOM namelist
groups=['limits','diffusion','merdia','secdia','diaphy','stream_sss','stream_sst' ]
groups=['limits','diffusion','merdia','secdia','diaphy','stream_sss','stream_sst', 'restart' ]

groups.append('cwmod')

Expand Down Expand Up @@ -318,33 +397,33 @@ def buildnml(case, caseroot, compname):
filename.write_text(filename.read_text().replace('mer_regflg2','mer_regflg(2,:)'))
filename.write_text(filename.read_text().replace('mer_regflg3','mer_regflg(3,:)'))
filename.write_text(filename.read_text().replace('mer_regflg4','mer_regflg(4,:)'))

print(pg_blom.get_value("icfile"))
# Write out blom.input_data_list
data_list_path = os.path.join(case.get_case_root(), "Buildconf", "blom.input_data_list")
if os.path.exists(data_list_path):
os.remove(data_list_path)
pg_blom.write_inputdata(data_list_path, groups)

# To compare with previous namelist generation, make namelist variable uppercase and
# use single quotes instead of back quotes and make sure that file variables set to UNSET
# get changed to blank quotes
namelist_file_temp = os.path.join(confdir, "ocn_in_temp")
with open(namelist_file, "r") as fread:
with open(namelist_file_temp, "w") as fwrite:
for line_read in fread:
# replace single quote with double quote to generate same namelist as using
# csh buildnml
line = line_read.replace('"',"'")
# make all namelists upper case to generate same namelist as using csh buildnml
tokens = line.split('=',maxsplit=1)
if len(tokens) == 2:
# Change UNSET values for files to lower case
if 'UNSET' in tokens[1]:
tokens[1] = "'unset'"
fwrite.write(f" {tokens[0].upper().strip()} = {tokens[1].strip()}\n")
else:
fwrite.write(line)
shutil.move(namelist_file_temp, namelist_file)
# To compare with previous namelist generation, make namelist variable uppercase and
# use single quotes instead of back quotes and make sure that file variables set to UNSET
# get changed to blank quotes
namelist_file_temp = os.path.join(confdir, "ocn_in_temp")
with open(namelist_file, "r") as fread:
with open(namelist_file_temp, "w") as fwrite:
for line_read in fread:
# replace single quote with double quote to generate same namelist as using
# csh buildnml
line = line_read.replace('"',"'")
# make all namelists upper case to generate same namelist as using csh buildnml
tokens = line.split('=',maxsplit=1)
if len(tokens) == 2:
# Change UNSET values for files to lower case
if 'UNSET' in tokens[1]:
tokens[1] = "'unset'"
fwrite.write(f" {tokens[0].upper().strip()} = {tokens[1].strip()}\n")
else:
fwrite.write(line)
shutil.move(namelist_file_temp, namelist_file)

###############################################################################
def _main_func():
Expand Down
2 changes: 1 addition & 1 deletion cime_config/config_pes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@
<ntasks_cpl>81</ntasks_cpl>
<ntasks_lnd>1</ntasks_lnd>
<ntasks_glc>1</ntasks_glc>
<ntasks_wav>1</ntasks_wav>
<ntasks_wav>80</ntasks_wav>
</ntasks>
<nthrds>
<nthrds_atm>1</nthrds_atm>
Expand Down
10 changes: 10 additions & 0 deletions cime_config/namelist_definition_blom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,16 @@
<desc>run type (a)</desc>
</entry>

<entry id="rpoint">
<category>limits</category>
<group>limits</group>
<values>
<value>unset</value>
</values>
<desc>name of the rpointer file (a)</desc>
<type>char</type>
</entry>

<entry id="grfile" is_inputdata="yes">
<type>char</type>
<category>limits</category>
Expand Down
67 changes: 67 additions & 0 deletions cime_config/testdefs/ExpectedTestFails.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?xml version= "1.0"?>

<expectedFails version="1.1">

<!-- Notes about the format of this file:

The required elements for a given failure are just:

<test name="...">
<phase name="...">
<status>...</status>
</phase>
</test>

There can be multiple phase blocks in a given test block.

In addition, a number of optional elements are allowed, which
currently are just for human consumption (not parsed by any
scripts):

- A phase block can contain an "issue" element, which gives the
issue number associated with this failure. (#123 refers to issue
#123 in the ESCOMP/ctsm repository. Issues in other repositories
should be specified as ORG/repo#123 - e.g., ESMCI/cime#123.)

- A phase block can contain a "comment" element, which gives any
sort of comment you desire.
-->


<!-- aux_clm test suite failures -->

<test name="ERP_Ld3_P256.T62_tn14.NOINYOC.betzy_intel">
<phase name="COMPARE_base_rest">
<status>FAIL</status>
<issue>BLOM#501</issue>
</phase>
</test>

<test name="ERP_Ld3_P256.T62_tn14.NOINYOC.betzy_gnu">
<phase name="COMPARE_base_rest">
<status>FAIL</status>
<issue>BLOM#501</issue>
</phase>
</test>

<test name="SMS_D_Ld1.T62_tn14.NOIIAOC20TR.betzy_intel">
<phase name="RUN">
<status>FAIL</status>
<issue>BLOM#510</issue>
</phase>
</test>

<test name="SMS_D_Ld1.T62_tn14_wtn14nw.NOINYOC_WW3.betzy_gnu.blom-wavice">
<phase name="RUN">
<status>FAIL</status>
<issue>NorESMhub/NorESM_CICE#9</issue>
</phase>
</test>

<test name="ERS_Ld3.T62_tn14_wtn14nw.NOINY_WW3.betzy_gnu.blom-wavice">
<phase name="RUN">
<status>FAIL</status>
<issue>NorESMhub/NorESM_CICE#9</issue>
</phase>
</test>
</expectedFails>
Loading