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