diff --git a/config/config_tests.xml b/config/config_tests.xml
index 68dc4d1e714..4ebbbbb6a61 100644
--- a/config/config_tests.xml
+++ b/config/config_tests.xml
@@ -508,7 +508,7 @@ NODEFAIL Tests restart upon detected node failure. Generates fake failu
none
$STOP_OPTION
$STOP_N
- 1
+ 1
1
1
1
diff --git a/scripts/lib/CIME/SystemTests/mcc.py b/scripts/lib/CIME/SystemTests/mcc.py
index 872fb1eb09c..2db5706de5b 100644
--- a/scripts/lib/CIME/SystemTests/mcc.py
+++ b/scripts/lib/CIME/SystemTests/mcc.py
@@ -26,9 +26,9 @@ def __init__(self, case):
def _case_one_setup(self):
# The multicoupler case will increase the number of tasks by the
# number of requested couplers.
- self._case.set_value("NINST_CPL", self._test_instances)
+ self._case.set_value("COUPLER_COUNT", self._test_instances)
case_setup(self._case, test_mode=False, reset=True)
def _case_two_setup(self):
- self._case.set_value("NINST_CPL", 1)
+ self._case.set_value("COUPLER_COUNT", 1)
case_setup(self._case, test_mode=True, reset=True)
diff --git a/scripts/lib/CIME/XML/env_mach_pes.py b/scripts/lib/CIME/XML/env_mach_pes.py
index d89472eb36c..c169d313c89 100644
--- a/scripts/lib/CIME/XML/env_mach_pes.py
+++ b/scripts/lib/CIME/XML/env_mach_pes.py
@@ -19,6 +19,32 @@ def __init__(self, case_root=None, infile="env_mach_pes.xml", components=None):
schema = os.path.join(get_cime_root(), "config", "xml_schemas", "env_mach_pes.xsd")
EnvBase.__init__(self, case_root, infile, schema=schema)
+ def set_value(self, vid, value, subgroup=None, ignore_type=False):
+ """
+ Set the value of an entry-id field to value
+ Returns the value or None if not found
+ subgroup is ignored in the general routine and applied in specific methods
+ """
+ vid, comp, iscompvar = self.check_if_comp_var(vid, None)
+ if vid == "COUPLER_COUNT":
+ if value > 1:
+ for othercomp in self._components:
+ if othercomp != "CPL":
+ ninst_string = "NINST_{}".format(othercomp)
+ expect(self.get_value(ninst_string)==1,
+ "Cannot change COUPLER_COUNT value if {} > 1".format(ninst_string))
+ elif value < 0:
+ # negative value effectively overrides safety check
+ value = -value
+ elif vid == "NINST":
+ if value > 1:
+ coupler_count = self.get_value("COUPLER_COUNT")
+ expect(coupler_count == 1,"Cannot change NINST value if COUPLER_COUNT > 1")
+ elif value < 0:
+ # negative value effectively overrides safety check
+ value = -value
+ return EnvBase.set_value(self, vid, value,subgroup=subgroup, ignore_type=ignore_type)
+
def get_value(self, vid, attribute=None, resolved=True, subgroup=None, pes_per_node=None): # pylint: disable=arguments-differ
value = EnvBase.get_value(self, vid, attribute, resolved, subgroup)
@@ -63,7 +89,7 @@ def get_total_tasks(self, comp_classes):
pstrid = self.get_value("PSTRID", attribute={"component":comp})
tt = rootpe + (ntasks - 1) * pstrid + 1
total_tasks = max(tt, total_tasks)
- total_tasks *= self.get_value("NINST_CPL")
+ total_tasks *= self.get_value("COUPLER_COUNT")
return total_tasks
def get_tasks_per_node(self, total_tasks, max_thread_count):
diff --git a/scripts/lib/CIME/build.py b/scripts/lib/CIME/build.py
index 5d0772b11d5..e19ee7f53e8 100644
--- a/scripts/lib/CIME/build.py
+++ b/scripts/lib/CIME/build.py
@@ -398,14 +398,16 @@ def _case_build_impl(caseroot, case, sharedlib_only, model_only):
complist = []
for comp_class in comp_classes:
- ninst = case.get_value("NINST_{}".format(comp_class))
if comp_class == "CPL":
+ ninst = case.get_value("COUPLER_COUNT")
config_dir = None
+ expect(ninst is not None,"Failed to get COUPLER_COUNT value")
else:
+ ninst = case.get_value("NINST_{}".format(comp_class))
config_dir = os.path.dirname(case.get_value("CONFIG_{}_FILE".format(comp_class)))
+ expect(ninst is not None,"Failed to get ninst for comp_class {}".format(comp_class))
comp = case.get_value("COMP_{}".format(comp_class))
thrds = case.get_value("NTHRDS_{}".format(comp_class))
- expect(ninst is not None,"Failed to get ninst for comp_class {}".format(comp_class))
complist.append((comp_class.lower(), comp, thrds, ninst, config_dir ))
os.environ["COMP_{}".format(comp_class)] = comp
diff --git a/scripts/lib/CIME/case.py b/scripts/lib/CIME/case.py
index 19d429ebfb5..4a7151f97ff 100644
--- a/scripts/lib/CIME/case.py
+++ b/scripts/lib/CIME/case.py
@@ -718,7 +718,7 @@ def _setup_mach_pes(self, pecount, ncouplers, ninst, machine_name, mpilib):
for compclass in self._component_classes:
key = "NINST_{}".format(compclass)
if compclass == "CPL":
- mach_pes_obj.set_value(key, ncouplers)
+ mach_pes_obj.set_value("COUPLER_COUNT", ncouplers)
continue
# ESP models are currently limited to 1 instance
if compclass == "ESP":
@@ -1070,7 +1070,7 @@ def create_caseroot(self, clone=False):
for component_class in self._component_classes:
if component_class == "CPL":
append_status("Using %s coupler instances" %
- (self.get_value("NINST_CPL")),
+ (self.get_value("COUPLER_COUNT")),
"README.case", caseroot=self._caseroot)
continue
comp_grid = "{}_GRID".format(component_class)
diff --git a/scripts/lib/CIME/case_run.py b/scripts/lib/CIME/case_run.py
index 157aa134782..45eb7d7a683 100644
--- a/scripts/lib/CIME/case_run.py
+++ b/scripts/lib/CIME/case_run.py
@@ -152,10 +152,10 @@ def post_run_check(case, lid):
rundir = case.get_value("RUNDIR")
model = case.get_value("MODEL")
- cpl_ninst = case.get_value("NINST_CPL")
+ coupler_count = case.get_value("COUPLER_COUNT")
cpl_logs = []
- if cpl_ninst > 1:
- for inst in range(cpl_ninst):
+ if coupler_count > 1:
+ for inst in range(coupler_count):
cpl_logs.append(os.path.join(rundir, "cpl_%04d.log." % (inst+1) + lid))
else:
cpl_logs = [os.path.join(rundir, "cpl" + ".log." + lid)]
@@ -176,7 +176,7 @@ def post_run_check(case, lid):
with open(cpl_logfile, 'r') as fd:
if 'SUCCESSFUL TERMINATION' in fd.read():
count_ok += 1
- if count_ok != cpl_ninst:
+ if count_ok != coupler_count:
expect(False, "Model did not complete - see {} \n " .format(cpl_logfile))
###############################################################################
diff --git a/scripts/lib/CIME/case_setup.py b/scripts/lib/CIME/case_setup.py
index 87acf02bb2b..890791fa224 100644
--- a/scripts/lib/CIME/case_setup.py
+++ b/scripts/lib/CIME/case_setup.py
@@ -34,7 +34,7 @@ def _build_usernl_files(case, model, comp):
expect(os.path.isdir(model_dir),
"cannot find cime_config directory {} for component {}".format(model_dir, comp))
- ninst = case.get_value("NINST_CPL")
+ ninst = case.get_value("COUPLER_COUNT")
if comp == "cpl":
if not os.path.exists("user_nl_cpl"):
shutil.copy(os.path.join(model_dir, "user_nl_cpl"), ".")
@@ -126,13 +126,14 @@ def _case_setup_impl(case, caseroot, clean=False, test_mode=False, reset=False):
# In CIME there can be multiple instances of each component model (an ensemble) NINST is the instance of that component.
for comp in models:
if comp == "CPL":
- continue
- ninst = case.get_value("NINST_{}".format(comp))
+ ninst = case.get_value("COUPLER_COUNT")
+ else:
+ ninst = case.get_value("NINST_{}".format(comp))
ntasks = case.get_value("NTASKS_{}".format(comp))
# ESP models are currently limited to 1 instance
expect((comp != "ESP") or (ninst == 1),
"ESP components may only have one instance")
- if ninst > ntasks:
+ if ninst > ntasks and comp != "CPL":
if ntasks == 1:
case.set_value("NTASKS_{}".format(comp), ninst)
else:
diff --git a/scripts/lib/CIME/case_st_archive.py b/scripts/lib/CIME/case_st_archive.py
index 0305b30c2b2..fe493cba1fa 100644
--- a/scripts/lib/CIME/case_st_archive.py
+++ b/scripts/lib/CIME/case_st_archive.py
@@ -45,8 +45,11 @@ def _get_datenames(case, last_date=None):
###############################################################################
def _get_ninst_info(case, compclass):
###############################################################################
-
- ninst = case.get_value('NINST_' + compclass.upper())
+ comp = compclass.upper()
+ if comp == "CPL":
+ ninst = case.get_value("COUPLER_COUNT")
+ else:
+ ninst = case.get_value('NINST_' + compclass.upper())
ninst_strings = []
if ninst is None:
ninst = 1
diff --git a/scripts/lib/CIME/get_timing.py b/scripts/lib/CIME/get_timing.py
index a00cd26705f..156526ef148 100644
--- a/scripts/lib/CIME/get_timing.py
+++ b/scripts/lib/CIME/get_timing.py
@@ -93,7 +93,7 @@ def gettime(self, heading_padded):
return (0, 0, False)
def getTiming(self):
- ninst = self.case.get_value("NINST_CPL")
+ ninst = self.case.get_value("COUPLER_COUNT")
if ninst > 1:
for inst in range(ninst):
self._getTiming(inst+1)
diff --git a/scripts/lib/CIME/preview_namelists.py b/scripts/lib/CIME/preview_namelists.py
index 8e44762d05a..6cd43c807dd 100644
--- a/scripts/lib/CIME/preview_namelists.py
+++ b/scripts/lib/CIME/preview_namelists.py
@@ -63,7 +63,7 @@ def create_namelists(case, component=None):
# Note - cpl must be last in the loop below so that in generating its namelist,
# it can use xml vars potentially set by other component's buildnml scripts
xmlfac = {}
- cpl_ninst = case.get_value("NINST_CPL")
+ coupler_count = case.get_value("COUPLER_COUNT")
models = case.get_values("COMP_CLASSES")
models += [models.pop(0)]
for model in models:
@@ -73,13 +73,13 @@ def create_namelists(case, component=None):
if model_str == "cpl":
compname = "drv"
complist = [m for m in models if m.upper() != "CPL"]
- if cpl_ninst > 1:
- xmlfac = {"NINST" : cpl_ninst, "NTASKS" : 1}
+ if coupler_count > 1:
+ xmlfac = {"NINST" : -(coupler_count), "NTASKS" : 1}
else:
compname = case.get_value("COMP_{}".format(model_str.upper()))
complist = [model_str.upper()]
- if cpl_ninst > 1:
- xmlfac = {"NINST" : cpl_ninst, "NTASKS" : cpl_ninst}
+ if coupler_count > 1:
+ xmlfac = {"NINST" : -(coupler_count), "NTASKS" : coupler_count}
xmlsave = {}
for k in xmlfac.keys():
@@ -98,12 +98,14 @@ def create_namelists(case, component=None):
if "python" in first_line:
mod = imp.load_source("buildnml", cmd)
logger.info(" Calling {} buildnml".format(compname))
- for key, value in xmlsave.items():
- case.set_value(key, xmlfac[key.split('_')[0]] * value)
-
+ if coupler_count > 1:
+ for key, value in xmlsave.items():
+ case.set_value(key, xmlfac[key.split('_')[0]] * value)
mod.buildnml(case, caseroot, compname)
- for key, value in xmlsave.items():
- case.set_value(key, value)
+ if coupler_count > 1:
+ for key, value in xmlsave.items():
+ case.set_value(key, value)
+
case.flush()
else:
raise SyntaxError
@@ -119,14 +121,16 @@ def create_namelists(case, component=None):
if do_run_cmd:
logger.info(" Running {} buildnml".format(compname))
- for key, value in xmlsave.items():
- case.set_value(key, xmlfac[key.split('_')[0]] * value)
- case.flush()
+ if coupler_count > 1:
+ for key, value in xmlsave.items():
+ case.set_value(key, xmlfac[key.split('_')[0]] * value)
+ case.flush()
output = run_cmd_no_fail("{} {}".format(cmd, caseroot), verbose=False)
logger.info(output)
- for key, value in xmlsave.items():
- case.set_value(key, value)
- case.flush()
+ if coupler_count > 1:
+ for key, value in xmlsave.items():
+ case.set_value(key, value)
+ case.flush()
# refresh case xml object from file
case.read_xml()
diff --git a/src/drivers/mct/cime_config/buildnml b/src/drivers/mct/cime_config/buildnml
index fc06d7f33ed..954507d0268 100755
--- a/src/drivers/mct/cime_config/buildnml
+++ b/src/drivers/mct/cime_config/buildnml
@@ -254,8 +254,10 @@ def _create_component_modelio_namelists(case, files):
config = {}
config['component'] = model
entries = nmlgen.init_defaults(infiles, config, skip_entry_loop=True)
-
- inst_count = case.get_value("NINST_" + model.upper())
+ if model == "cpl":
+ inst_count = case.get_value("COUPLER_COUNT")
+ else:
+ inst_count = case.get_value("NINST_" + model.upper())
inst_string = ""
inst_index = 1
diff --git a/src/drivers/mct/cime_config/config_component.xml b/src/drivers/mct/cime_config/config_component.xml
index 592b372f393..8e779ea813c 100644
--- a/src/drivers/mct/cime_config/config_component.xml
+++ b/src/drivers/mct/cime_config/config_component.xml
@@ -1933,10 +1933,17 @@
ROOTPE (mpi task in MPI_COMM_WORLD) for each component
+
+ integer
+ 1
+ mach_pes
+ env_mach_pes.xml
+ Number of couplers in ensemble: if COUPLER_COUNT > 1 then NINST must be 1 for all components.
+
+
integer
- 1
1
1
1
@@ -1948,7 +1955,7 @@
mach_pes
env_mach_pes.xml
- Number of instances for each component
+ Number of instances for each component in single coupler mode
diff --git a/src/drivers/mct/cime_config/namelist_definition_drv.xml b/src/drivers/mct/cime_config/namelist_definition_drv.xml
index c96ae3b67a5..8e70add66cc 100644
--- a/src/drivers/mct/cime_config/namelist_definition_drv.xml
+++ b/src/drivers/mct/cime_config/namelist_definition_drv.xml
@@ -44,15 +44,15 @@
-
+
integer
cime_cpl_inst
cime_cpl_inst
- Number of CESM coupler instances.
+ Number of CESM coupler instances. If > 1 then all component instances must equal 1.
- $NINST_CPL
+ $COUPLER_COUNT