From 391a1885a7d634b80ea5a629cb79bd5676e1f0ff Mon Sep 17 00:00:00 2001 From: Jim Edwards Date: Wed, 28 Aug 2024 15:49:27 -0600 Subject: [PATCH 01/19] fix the restart tests by using ceil instead of int --- CIME/SystemTests/system_tests_common.py | 6 +++--- CIME/non_py/cprnc | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CIME/SystemTests/system_tests_common.py b/CIME/SystemTests/system_tests_common.py index 3c1f3e99830..08a0be6b1c7 100644 --- a/CIME/SystemTests/system_tests_common.py +++ b/CIME/SystemTests/system_tests_common.py @@ -38,7 +38,7 @@ ) import CIME.build as build -import glob, gzip, time, traceback, os +import glob, gzip, time, traceback, os, math from contextlib import ExitStack logger = logging.getLogger(__name__) @@ -173,8 +173,8 @@ def _set_restart_interval(self): else: expect(False, f"stop_option {stop_option} not available for this test") - stop_n = int(stop_n * factor // coupling_secs) - rest_n = int((stop_n // 2 + 1) * coupling_secs / factor) + stop_n = math.ceil(stop_n * factor // coupling_secs) + rest_n = math.ceil((stop_n // 2 + 1) * coupling_secs / factor) expect(stop_n > 0, "Bad STOP_N: {:d}".format(stop_n)) diff --git a/CIME/non_py/cprnc b/CIME/non_py/cprnc index e3eaa5346ec..9276b219750 160000 --- a/CIME/non_py/cprnc +++ b/CIME/non_py/cprnc @@ -1 +1 @@ -Subproject commit e3eaa5346ecd50aef8b60fdf54b98cb1c13a24b1 +Subproject commit 9276b219750881633d8673c72ec80ac821f96d82 From b0bf7f02d8cb0753535836b104b53b570ab0d0de Mon Sep 17 00:00:00 2001 From: Jim Edwards Date: Wed, 28 Aug 2024 16:01:37 -0600 Subject: [PATCH 02/19] no ceil needed for stop_n --- CIME/SystemTests/system_tests_common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIME/SystemTests/system_tests_common.py b/CIME/SystemTests/system_tests_common.py index 08a0be6b1c7..7295ea67ca1 100644 --- a/CIME/SystemTests/system_tests_common.py +++ b/CIME/SystemTests/system_tests_common.py @@ -173,7 +173,7 @@ def _set_restart_interval(self): else: expect(False, f"stop_option {stop_option} not available for this test") - stop_n = math.ceil(stop_n * factor // coupling_secs) + stop_n = stop_n * factor // coupling_secs rest_n = math.ceil((stop_n // 2 + 1) * coupling_secs / factor) expect(stop_n > 0, "Bad STOP_N: {:d}".format(stop_n)) From 1be3e4af563a6f1c684819149f6f7a68cf544b83 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Thu, 29 Aug 2024 00:25:52 -0700 Subject: [PATCH 03/19] Fixes black formatting --- CIME/code_checker.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/CIME/code_checker.py b/CIME/code_checker.py index 4c05f22e477..fdc1eedefd8 100644 --- a/CIME/code_checker.py +++ b/CIME/code_checker.py @@ -45,11 +45,14 @@ def _run_pylint(all_files, interactive): # cmd_options +=",relative-import" # add init-hook option - cmd_options += ' --init-hook=\'import sys; sys.path.extend(("%s","%s","%s","%s"))\'' % ( - os.path.join(cimeroot, "CIME"), - os.path.join(cimeroot, "CIME", "Tools"), - os.path.join(cimeroot, "scripts", "fortran_unit_testing", "python"), - os.path.join(srcroot, "components", "cmeps", "cime_config", "runseq"), + cmd_options += ( + ' --init-hook=\'import sys; sys.path.extend(("%s","%s","%s","%s"))\'' + % ( + os.path.join(cimeroot, "CIME"), + os.path.join(cimeroot, "CIME", "Tools"), + os.path.join(cimeroot, "scripts", "fortran_unit_testing", "python"), + os.path.join(srcroot, "components", "cmeps", "cime_config", "runseq"), + ) ) files = " ".join(all_files) From adc832719636e099281ff7d9c971fcf0e8d98a72 Mon Sep 17 00:00:00 2001 From: Jim Edwards Date: Thu, 29 Aug 2024 07:39:38 -0600 Subject: [PATCH 04/19] update pre-commit --- CIME/code_checker.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/CIME/code_checker.py b/CIME/code_checker.py index 4c05f22e477..fdc1eedefd8 100644 --- a/CIME/code_checker.py +++ b/CIME/code_checker.py @@ -45,11 +45,14 @@ def _run_pylint(all_files, interactive): # cmd_options +=",relative-import" # add init-hook option - cmd_options += ' --init-hook=\'import sys; sys.path.extend(("%s","%s","%s","%s"))\'' % ( - os.path.join(cimeroot, "CIME"), - os.path.join(cimeroot, "CIME", "Tools"), - os.path.join(cimeroot, "scripts", "fortran_unit_testing", "python"), - os.path.join(srcroot, "components", "cmeps", "cime_config", "runseq"), + cmd_options += ( + ' --init-hook=\'import sys; sys.path.extend(("%s","%s","%s","%s"))\'' + % ( + os.path.join(cimeroot, "CIME"), + os.path.join(cimeroot, "CIME", "Tools"), + os.path.join(cimeroot, "scripts", "fortran_unit_testing", "python"), + os.path.join(srcroot, "components", "cmeps", "cime_config", "runseq"), + ) ) files = " ".join(all_files) From c53f13c16479760dbdb232e69654063614a64e49 Mon Sep 17 00:00:00 2001 From: Jim Edwards Date: Thu, 29 Aug 2024 09:43:14 -0600 Subject: [PATCH 05/19] resolve cprnc diff --- CIME/non_py/cprnc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIME/non_py/cprnc b/CIME/non_py/cprnc index 9276b219750..e3eaa5346ec 160000 --- a/CIME/non_py/cprnc +++ b/CIME/non_py/cprnc @@ -1 +1 @@ -Subproject commit 9276b219750881633d8673c72ec80ac821f96d82 +Subproject commit e3eaa5346ecd50aef8b60fdf54b98cb1c13a24b1 From e009c578f2158db28a4e2279542e6f6462707031 Mon Sep 17 00:00:00 2001 From: Jim Edwards Date: Thu, 29 Aug 2024 13:34:40 -0600 Subject: [PATCH 06/19] stop_n must be int --- CIME/SystemTests/system_tests_common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIME/SystemTests/system_tests_common.py b/CIME/SystemTests/system_tests_common.py index 7295ea67ca1..42e1b897e58 100644 --- a/CIME/SystemTests/system_tests_common.py +++ b/CIME/SystemTests/system_tests_common.py @@ -173,7 +173,7 @@ def _set_restart_interval(self): else: expect(False, f"stop_option {stop_option} not available for this test") - stop_n = stop_n * factor // coupling_secs + stop_n = int(stop_n * factor // coupling_secs) rest_n = math.ceil((stop_n // 2 + 1) * coupling_secs / factor) expect(stop_n > 0, "Bad STOP_N: {:d}".format(stop_n)) From 7654e796b061e5789b1494250a803969dbd3f467 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 30 Aug 2024 10:20:03 -0600 Subject: [PATCH 07/19] Fix for PES append feature --- CIME/case/case.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIME/case/case.py b/CIME/case/case.py index 2f2d44aaca3..6f9082b0aa4 100644 --- a/CIME/case/case.py +++ b/CIME/case/case.py @@ -1234,7 +1234,7 @@ def _setup_mach_pes(self, pecount, multi_driver, ninst, machine_name, mpilib): and value.endswith("'") ): value = value[1:-1] - if append[key]: + if key in append and append[key]: ovalue = self.get_value(key) self.set_value(key, value + " " + ovalue) From e351ccaf0f2b79aade8090ce3416ad48fd63401b Mon Sep 17 00:00:00 2001 From: James Foucar Date: Tue, 3 Sep 2024 15:54:33 -0600 Subject: [PATCH 08/19] create_test: add --driver support for e3sm Also, fix a couple issues in driver handling in test_scheduler. --- CIME/scripts/create_test.py | 10 ++++++++++ CIME/test_scheduler.py | 32 +++++++++++++++++++++----------- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/CIME/scripts/create_test.py b/CIME/scripts/create_test.py index 07a10689b3c..74dd60e8c19 100755 --- a/CIME/scripts/create_test.py +++ b/CIME/scripts/create_test.py @@ -260,6 +260,11 @@ def parse_command_line(args, description): "\nNOTE: this can also be done after the fact with bless_test_results", ) + parser.add_argument( + "--driver", + help="Override driver specified in tests and use this one.", + ) + default = get_default_setting(config, "COMPILER", None, check_main=True) parser.add_argument( @@ -775,6 +780,7 @@ def parse_command_line(args, description): args.workflow, args.chksum, args.force_rebuild, + args.driver, ) @@ -936,6 +942,7 @@ def create_test( workflow, chksum, force_rebuild, + driver, ): ############################################################################### impl = TestScheduler( @@ -977,6 +984,7 @@ def create_test( workflow=workflow, chksum=chksum, force_rebuild=force_rebuild, + driver=driver, ) success = impl.run_tests( @@ -1081,6 +1089,7 @@ def _main_func(description=None): workflow, chksum, force_rebuild, + driver, ) = parse_command_line(sys.argv, description) success = False @@ -1134,6 +1143,7 @@ def _main_func(description=None): workflow, chksum, force_rebuild, + driver, ) run_count += 1 diff --git a/CIME/test_scheduler.py b/CIME/test_scheduler.py index e1dc99400f4..bbe5efedf7b 100644 --- a/CIME/test_scheduler.py +++ b/CIME/test_scheduler.py @@ -209,11 +209,12 @@ def __init__( workflow=None, chksum=False, force_rebuild=False, + driver=None, ): ########################################################################### self._cime_root = get_cime_root() self._cime_model = get_model() - self._cime_driver = get_cime_default_driver() + self._cime_driver = driver if driver is not None else get_cime_default_driver() self._save_timing = save_timing self._queue = queue self._test_data = ( @@ -649,6 +650,7 @@ def _create_newcase_phase(self, test): mpilib = None ninst = 1 ncpl = 1 + driver = self._cime_driver if case_opts is not None: for case_opt in case_opts: # pylint: disable=not-an-iterable if case_opt.startswith("M"): @@ -681,15 +683,16 @@ def _create_newcase_phase(self, test): ) ) elif case_opt.startswith("V"): - self._cime_driver = case_opt[1:] - create_newcase_cmd += " --driver {}".format(self._cime_driver) + driver = case_opt[1:] + + create_newcase_cmd += " --driver {}".format(driver) if ( "--ninst" in create_newcase_cmd and not "--multi-driver" in create_newcase_cmd ): if "--driver nuopc" in create_newcase_cmd or ( - "--driver" not in create_newcase_cmd and self._cime_driver == "nuopc" + "--driver" not in create_newcase_cmd and driver == "nuopc" ): expect(False, "_N option not supported by nuopc driver, use _C instead") @@ -704,7 +707,7 @@ def _create_newcase_phase(self, test): self._log_output(test, error) return False, error - files = Files(comp_interface=self._cime_driver) + files = Files(comp_interface=driver) testmods_dir = files.get_value( "TESTS_MODS_DIR", {"component": component} ) @@ -783,9 +786,16 @@ def _xml_phase(self, test): test_dir = self._get_test_dir(test) envtest = EnvTest(test_dir) + # Find driver. It may be different for the current test if V testopt is used + driver = self._cime_driver + if case_opts is not None: + for case_opt in case_opts: # pylint: disable=not-an-iterable + if case_opt.startswith("V"): + driver = case_opt[1:] + # Determine list of component classes that this coupler/driver knows how # to deal with. This list follows the same order as compset longnames follow. - files = Files(comp_interface=self._cime_driver) + files = Files(comp_interface=driver) ufs_driver = os.environ.get("UFS_DRIVER") attribute = None if ufs_driver: @@ -793,13 +803,11 @@ def _xml_phase(self, test): drv_config_file = files.get_value("CONFIG_CPL_FILE", attribute=attribute) - if self._cime_driver == "nuopc" and not os.path.exists(drv_config_file): + if driver == "nuopc" and not os.path.exists(drv_config_file): drv_config_file = files.get_value("CONFIG_CPL_FILE", {"component": "cpl"}) expect( os.path.exists(drv_config_file), - "File {} not found, cime driver {}".format( - drv_config_file, self._cime_driver - ), + "File {} not found, cime driver {}".format(drv_config_file, driver), ) drv_comp = Component(drv_config_file, "CPL") @@ -924,7 +932,9 @@ def _xml_phase(self, test): elif opt.startswith("A"): # A option is for testing in ASYNC IO mode, only available with nuopc driver and pio2 envtest.set_test_parameter("PIO_ASYNC_INTERFACE", "TRUE") - envtest.set_test_parameter("CIME_DRIVER", "nuopc") + expect( + driver == "nuopc", "ASYNC IO mode only works with nuopc driver" + ) envtest.set_test_parameter("PIO_VERSION", "2") match = re.match("A([0-9]+)x?([0-9])*", opt) envtest.set_test_parameter("PIO_NUMTASKS_CPL", match.group(1)) From 9004f499d881bf99341dfbe230b8f28bc6e59554 Mon Sep 17 00:00:00 2001 From: Michael Kelleher Date: Wed, 4 Sep 2024 10:09:13 -0500 Subject: [PATCH 09/19] Import shutil --- CIME/SystemTests/mvk.py | 2 +- CIME/SystemTests/pgn.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CIME/SystemTests/mvk.py b/CIME/SystemTests/mvk.py index 854dce74472..4efe3ee48cf 100644 --- a/CIME/SystemTests/mvk.py +++ b/CIME/SystemTests/mvk.py @@ -10,7 +10,7 @@ import json import logging -from shutils import copytree +from shutil import copytree import CIME.test_status import CIME.utils diff --git a/CIME/SystemTests/pgn.py b/CIME/SystemTests/pgn.py index 83199ec674e..07ac1f4cb08 100644 --- a/CIME/SystemTests/pgn.py +++ b/CIME/SystemTests/pgn.py @@ -16,7 +16,7 @@ import logging from collections import OrderedDict -from shutils import copytree +from shutil import copytree import pandas as pd import numpy as np From bef6909b2ce5f68a19babe9746acd8f8daa6aeb3 Mon Sep 17 00:00:00 2001 From: Jim Edwards Date: Mon, 9 Sep 2024 10:47:14 -0600 Subject: [PATCH 10/19] make the hidden status of batch jobs xml dependent - currently hardcoded for case.st_archive only --- CIME/Tools/xmlchange | 1 - CIME/XML/env_batch.py | 13 ++++++++----- CIME/data/config/xml_schemas/config_workflow.xsd | 2 ++ CIME/utils.py | 7 +++++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/CIME/Tools/xmlchange b/CIME/Tools/xmlchange index 46debd906a2..4101f9b5dba 100755 --- a/CIME/Tools/xmlchange +++ b/CIME/Tools/xmlchange @@ -55,7 +55,6 @@ from standard_script_setup import * from CIME.utils import ( expect, convert_to_type, - get_batch_script_for_job, Timeout, ) from CIME.status import append_case_status diff --git a/CIME/XML/env_batch.py b/CIME/XML/env_batch.py index b444a29333a..266f3d1e150 100644 --- a/CIME/XML/env_batch.py +++ b/CIME/XML/env_batch.py @@ -32,6 +32,7 @@ def __init__(self, case_root=None, infile="env_batch.xml", read_only=False): initialize an object interface to file env_batch.xml in the case directory """ self._batchtype = None + self._hidden_batch_script = {} # This arbitrary setting should always be overwritten self._default_walltime = "00:20:00" schema = os.path.join(utils.get_schema_path(), "env_batch.xsd") @@ -257,7 +258,9 @@ def make_batch_script(self, input_template, job, case, outfile=None): subgroup=job, overrides=overrides, ) - output_name = get_batch_script_for_job(job) if outfile is None else outfile + env_workflow = case.get_env("workflow") + self._hidden_batch_script[job] = env_workflow.get_value("hidden", subgroup=job) + output_name = get_batch_script_for_job(job, hidden=self._hidden_batch_script[job]) if outfile is None else outfile logger.info("Creating file {}".format(output_name)) with open(output_name, "w") as fd: fd.write(output_text) @@ -745,7 +748,7 @@ def submit_jobs( alljobs = [ j for j in alljobs - if os.path.isfile(os.path.join(self._caseroot, get_batch_script_for_job(j))) + if os.path.isfile(os.path.join(self._caseroot, get_batch_script_for_job(j, hidden=self._hidden_batch_script[j]))) ] startindex = 0 @@ -1071,7 +1074,7 @@ def _submit_single_job( batchsubmit, submitargs, batchredirect, - get_batch_script_for_job(job), + get_batch_script_for_job(job, hidden=self._hidden_batch_script[job]), ) elif batch_env_flag: sequence = ( @@ -1079,14 +1082,14 @@ def _submit_single_job( submitargs, run_args, batchredirect, - os.path.join(self._caseroot, get_batch_script_for_job(job)), + os.path.join(self._caseroot, get_batch_script_for_job(job, hidden=self._hidden_batch_script[job])), ) else: sequence = ( batchsubmit, submitargs, batchredirect, - os.path.join(self._caseroot, get_batch_script_for_job(job)), + os.path.join(self._caseroot, get_batch_script_for_job(job, hidden=self._hidden_batch_script[job])), run_args, ) diff --git a/CIME/data/config/xml_schemas/config_workflow.xsd b/CIME/data/config/xml_schemas/config_workflow.xsd index 14a82586c08..6a10b167347 100644 --- a/CIME/data/config/xml_schemas/config_workflow.xsd +++ b/CIME/data/config/xml_schemas/config_workflow.xsd @@ -13,6 +13,7 @@ + @@ -57,6 +58,7 @@ + diff --git a/CIME/utils.py b/CIME/utils.py index 0973647823b..1b7337d1669 100644 --- a/CIME/utils.py +++ b/CIME/utils.py @@ -2530,8 +2530,11 @@ def run_bld_cmd_ensure_logging(cmd, arg_logger, from_dir=None, timeout=None): expect(stat == 0, filter_unicode(errput)) -def get_batch_script_for_job(job): - return job if "st_archive" in job else "." + job +def get_batch_script_for_job(job, hidden="True"): + # this if statement is for backward compatibility + if job == "case.st_archive" and not hidden: + hidden = "False" + return "." + job if not hidden or hidden == "True" else job def string_in_list(_string, _list): From 72b1b6e9d3cb3331828d360c3e80b6c3e022cd23 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Mon, 9 Sep 2024 13:18:43 -0600 Subject: [PATCH 11/19] Fix BFAILs, they need to be considered DIFF --- CIME/test_status.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CIME/test_status.py b/CIME/test_status.py index da818b2aca3..13e52497126 100644 --- a/CIME/test_status.py +++ b/CIME/test_status.py @@ -468,8 +468,8 @@ def _get_overall_status_based_on_phases( if rv in [NAMELIST_FAIL_STATUS, TEST_PASS_STATUS]: phase_responsible_for_status = phase # need to further inspect message to determine - # phase status - if "DIFF" in data[1]: + # phase status. BFAILs need to be a DIFF + if "DIFF" in data[1] or TEST_NO_BASELINES_COMMENT in data[1]: rv = TEST_DIFF_STATUS elif "ERROR" in data[1]: rv = TEST_FAIL_STATUS From 47ea873d8db28a479a039175c703a533cdab0ff9 Mon Sep 17 00:00:00 2001 From: Jim Edwards Date: Mon, 9 Sep 2024 13:35:21 -0600 Subject: [PATCH 12/19] fix underscore issue --- CIME/XML/env_batch.py | 58 +++++++++++++++++++++++++++++--- CIME/tests/test_sys_cime_case.py | 3 +- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/CIME/XML/env_batch.py b/CIME/XML/env_batch.py index 266f3d1e150..655f33ddee2 100644 --- a/CIME/XML/env_batch.py +++ b/CIME/XML/env_batch.py @@ -260,7 +260,18 @@ def make_batch_script(self, input_template, job, case, outfile=None): ) env_workflow = case.get_env("workflow") self._hidden_batch_script[job] = env_workflow.get_value("hidden", subgroup=job) - output_name = get_batch_script_for_job(job, hidden=self._hidden_batch_script[job]) if outfile is None else outfile + output_name = ( + get_batch_script_for_job( + job, + hidden=( + self._hidden_batch_script[job] + if job in self._hidden_batch_script + else None + ), + ) + if outfile is None + else outfile + ) logger.info("Creating file {}".format(output_name)) with open(output_name, "w") as fd: fd.write(output_text) @@ -748,7 +759,17 @@ def submit_jobs( alljobs = [ j for j in alljobs - if os.path.isfile(os.path.join(self._caseroot, get_batch_script_for_job(j, hidden=self._hidden_batch_script[j]))) + if os.path.isfile( + os.path.join( + self._caseroot, + get_batch_script_for_job( + j, + hidden=self._hidden_batch_script[j] + if j in self._hidden_batch_script + else None, + ), + ) + ) ] startindex = 0 @@ -1074,7 +1095,14 @@ def _submit_single_job( batchsubmit, submitargs, batchredirect, - get_batch_script_for_job(job, hidden=self._hidden_batch_script[job]), + get_batch_script_for_job( + job, + hidden=( + self._hidden_batch_script[job] + if job in self._hidden_batch_script + else None + ), + ), ) elif batch_env_flag: sequence = ( @@ -1082,14 +1110,34 @@ def _submit_single_job( submitargs, run_args, batchredirect, - os.path.join(self._caseroot, get_batch_script_for_job(job, hidden=self._hidden_batch_script[job])), + os.path.join( + self._caseroot, + get_batch_script_for_job( + job, + hidden=( + self._hidden_batch_script[job] + if job in self._hidden_batch_script + else None + ), + ), + ), ) else: sequence = ( batchsubmit, submitargs, batchredirect, - os.path.join(self._caseroot, get_batch_script_for_job(job, hidden=self._hidden_batch_script[job])), + os.path.join( + self._caseroot, + get_batch_script_for_job( + job, + hidden=( + self._hidden_batch_script[job] + if job in self._hidden_batch_script + else None + ), + ), + ), run_args, ) diff --git a/CIME/tests/test_sys_cime_case.py b/CIME/tests/test_sys_cime_case.py index 4b226ff3b46..d07456eb570 100644 --- a/CIME/tests/test_sys_cime_case.py +++ b/CIME/tests/test_sys_cime_case.py @@ -731,7 +731,8 @@ def test_self_build_cprnc(self): ) self.run_cmd_assert_result( - "./xmlchange CCSM_CPRNC=this_is_a_broken_cprnc", from_dir=casedir + "./xmlchange CCSM_CPRNC=this_is_a_broken_cprnc --file env_test.xml", + from_dir=casedir, ) self.run_cmd_assert_result("./case.build", from_dir=casedir) self.run_cmd_assert_result("./case.submit", from_dir=casedir) From ad8d32fd45be787af35629ee1dc0781b59f0c80a Mon Sep 17 00:00:00 2001 From: Jim Edwards Date: Tue, 10 Sep 2024 11:25:02 -0600 Subject: [PATCH 13/19] make hidden a logical --- CIME/XML/env_batch.py | 8 +++++++- CIME/data/config/xml_schemas/config_workflow.xsd | 2 +- CIME/tests/test_sys_create_newcase.py | 2 +- CIME/utils.py | 8 ++++---- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/CIME/XML/env_batch.py b/CIME/XML/env_batch.py index 655f33ddee2..69a6560ae49 100644 --- a/CIME/XML/env_batch.py +++ b/CIME/XML/env_batch.py @@ -259,7 +259,13 @@ def make_batch_script(self, input_template, job, case, outfile=None): overrides=overrides, ) env_workflow = case.get_env("workflow") - self._hidden_batch_script[job] = env_workflow.get_value("hidden", subgroup=job) + + hidden = env_workflow.get_value("hidden", subgroup=job) + if hidden is None or hidden == "True" or hidden == "true": + self._hidden_batch_script[job] = True + else: + self._hidden_batch_script[job] = False + output_name = ( get_batch_script_for_job( job, diff --git a/CIME/data/config/xml_schemas/config_workflow.xsd b/CIME/data/config/xml_schemas/config_workflow.xsd index 6a10b167347..5b09913a4b6 100644 --- a/CIME/data/config/xml_schemas/config_workflow.xsd +++ b/CIME/data/config/xml_schemas/config_workflow.xsd @@ -13,7 +13,7 @@ - + diff --git a/CIME/tests/test_sys_create_newcase.py b/CIME/tests/test_sys_create_newcase.py index b99ca4f10c4..1be636aff36 100644 --- a/CIME/tests/test_sys_create_newcase.py +++ b/CIME/tests/test_sys_create_newcase.py @@ -74,7 +74,7 @@ def test_a_createnewcase(self): # on systems (like github workflow) that do not have batch, set this for the next test if batch_system == "none": self.run_cmd_assert_result( - './xmlchange --subgroup case.run BATCH_COMMAND_FLAGS="-q \$JOB_QUEUE"', + r'./xmlchange --subgroup case.run BATCH_COMMAND_FLAGS="-q \$JOB_QUEUE"', from_dir=testdir, ) diff --git a/CIME/utils.py b/CIME/utils.py index 1b7337d1669..85fa30017b0 100644 --- a/CIME/utils.py +++ b/CIME/utils.py @@ -2530,11 +2530,11 @@ def run_bld_cmd_ensure_logging(cmd, arg_logger, from_dir=None, timeout=None): expect(stat == 0, filter_unicode(errput)) -def get_batch_script_for_job(job, hidden="True"): +def get_batch_script_for_job(job, hidden=None): # this if statement is for backward compatibility - if job == "case.st_archive" and not hidden: - hidden = "False" - return "." + job if not hidden or hidden == "True" else job + if hidden is None: + hidden = job != "case.st_archive" + return "." + job if hidden else job def string_in_list(_string, _list): From a86c8f3e90d84799cc4bd37e8903f3e2dee5c226 Mon Sep 17 00:00:00 2001 From: Jim Edwards Date: Tue, 10 Sep 2024 13:30:11 -0600 Subject: [PATCH 14/19] case.st_archive is special for backward compatibility --- CIME/XML/env_batch.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CIME/XML/env_batch.py b/CIME/XML/env_batch.py index 69a6560ae49..fddb7dbc16f 100644 --- a/CIME/XML/env_batch.py +++ b/CIME/XML/env_batch.py @@ -261,7 +261,12 @@ def make_batch_script(self, input_template, job, case, outfile=None): env_workflow = case.get_env("workflow") hidden = env_workflow.get_value("hidden", subgroup=job) - if hidden is None or hidden == "True" or hidden == "true": + # case.st_archive is not hidden for backward compatibility + if ( + (job != "case.st_archive" and hidden is None) + or hidden == "True" + or hidden == "true" + ): self._hidden_batch_script[job] = True else: self._hidden_batch_script[job] = False From c565ac117042af7c02ec3c0eda20306b19d83b29 Mon Sep 17 00:00:00 2001 From: Jim Edwards Date: Thu, 12 Sep 2024 14:04:01 -0600 Subject: [PATCH 15/19] improve functionality of hidden workflow flag --- CIME/XML/env_batch.py | 39 +++++++-------------------------------- CIME/XML/env_workflow.py | 12 ++++++++++++ 2 files changed, 19 insertions(+), 32 deletions(-) diff --git a/CIME/XML/env_batch.py b/CIME/XML/env_batch.py index fddb7dbc16f..6925126c8b5 100644 --- a/CIME/XML/env_batch.py +++ b/CIME/XML/env_batch.py @@ -32,7 +32,6 @@ def __init__(self, case_root=None, infile="env_batch.xml", read_only=False): initialize an object interface to file env_batch.xml in the case directory """ self._batchtype = None - self._hidden_batch_script = {} # This arbitrary setting should always be overwritten self._default_walltime = "00:20:00" schema = os.path.join(utils.get_schema_path(), "env_batch.xsd") @@ -213,6 +212,7 @@ def get_job_overrides(self, job, case): thread_count, ngpus_per_node, ) = env_workflow.get_job_specs(case, job) + overrides = {} if total_tasks: @@ -258,18 +258,6 @@ def make_batch_script(self, input_template, job, case, outfile=None): subgroup=job, overrides=overrides, ) - env_workflow = case.get_env("workflow") - - hidden = env_workflow.get_value("hidden", subgroup=job) - # case.st_archive is not hidden for backward compatibility - if ( - (job != "case.st_archive" and hidden is None) - or hidden == "True" - or hidden == "true" - ): - self._hidden_batch_script[job] = True - else: - self._hidden_batch_script[job] = False output_name = ( get_batch_script_for_job( @@ -509,6 +497,7 @@ def get_batch_directives(self, case, job, overrides=None, output_format="default """ """ result = [] directive_prefix = None + self._hidden_batch_script[job] = self.hidden_status(case, job) roots = self.get_children("batch_system") queue = case.get_value("JOB_QUEUE", subgroup=job) @@ -774,10 +763,7 @@ def submit_jobs( os.path.join( self._caseroot, get_batch_script_for_job( - j, - hidden=self._hidden_batch_script[j] - if j in self._hidden_batch_script - else None, + j, hidden=env_workflow.hidden_job(case, j) ), ) ) @@ -1100,6 +1086,7 @@ def _submit_single_job( set_continue_run=resubmit_immediate, submit_resubmits=workflow and not resubmit_immediate, ) + env_workflow = case.get_env("workflow") if batch_system == "lsf" and not batch_env_flag: sequence = ( run_args, @@ -1108,11 +1095,7 @@ def _submit_single_job( batchredirect, get_batch_script_for_job( job, - hidden=( - self._hidden_batch_script[job] - if job in self._hidden_batch_script - else None - ), + hidden=env_workflow.hidden_job(case, job), ), ) elif batch_env_flag: @@ -1125,11 +1108,7 @@ def _submit_single_job( self._caseroot, get_batch_script_for_job( job, - hidden=( - self._hidden_batch_script[job] - if job in self._hidden_batch_script - else None - ), + hidden=env_workflow.hidden_job(case, job), ), ), ) @@ -1142,11 +1121,7 @@ def _submit_single_job( self._caseroot, get_batch_script_for_job( job, - hidden=( - self._hidden_batch_script[job] - if job in self._hidden_batch_script - else None - ), + hidden=env_workflow.hidden_job(case, job), ), ), run_args, diff --git a/CIME/XML/env_workflow.py b/CIME/XML/env_workflow.py index c59ff23aba4..8eaa7171ce8 100644 --- a/CIME/XML/env_workflow.py +++ b/CIME/XML/env_workflow.py @@ -5,6 +5,7 @@ from CIME.XML.standard_module_setup import * from CIME.XML.env_base import EnvBase from CIME.utils import get_cime_root + import re, math logger = logging.getLogger(__name__) @@ -21,6 +22,7 @@ def __init__(self, case_root=None, infile="env_workflow.xml", read_only=False): # schema = os.path.join(get_cime_root(), "CIME", "config", "xml_schemas", "env_workflow.xsd") # TODO: define schema for this file schema = None + self._hidden = {} super(EnvWorkflow, self).__init__( case_root, infile, schema=schema, read_only=read_only ) @@ -89,7 +91,17 @@ def get_type_info(self, vid): ) return type_info + def hidden_job(self, case, job): + if job not in self._hidden: + self.get_job_specs(case, job) + return self._hidden[job] + def get_job_specs(self, case, job): + hidden = self.get_value("hidden", subgroup=job) + self._hidden[job] = (hidden is None and job != "case.st_archive") or ( + hidden is not None and hidden.lower() == "true" + ) + task_count = case.get_resolved_value(self.get_value("task_count", subgroup=job)) tasks_per_node = case.get_resolved_value( self.get_value("tasks_per_node", subgroup=job) From 31c39e656829f49596331cf18a61e18e10f1524d Mon Sep 17 00:00:00 2001 From: Jim Edwards Date: Fri, 13 Sep 2024 06:16:04 -0600 Subject: [PATCH 16/19] make env_workflow an object --- CIME/XML/env_batch.py | 55 +++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/CIME/XML/env_batch.py b/CIME/XML/env_batch.py index 6925126c8b5..907060e270f 100644 --- a/CIME/XML/env_batch.py +++ b/CIME/XML/env_batch.py @@ -39,6 +39,7 @@ def __init__(self, case_root=None, infile="env_batch.xml", read_only=False): case_root, infile, schema=schema, read_only=read_only ) self._batchtype = self.get_batch_system_type() + self._env_workflow = None # pylint: disable=arguments-differ def set_value(self, item, value, subgroup=None, ignore_type=False): @@ -204,14 +205,15 @@ def set_batch_system(self, batchobj, batch_system_type=None): lock_file(os.path.basename(batchobj.filename), self._caseroot) def get_job_overrides(self, job, case): - env_workflow = case.get_env("workflow") + if not self._env_workflow: + self._env_workflow = case.get_env("workflow") ( total_tasks, num_nodes, tasks_per_node, thread_count, ngpus_per_node, - ) = env_workflow.get_job_specs(case, job) + ) = self._env_workflow.get_job_specs(case, job) overrides = {} @@ -261,12 +263,7 @@ def make_batch_script(self, input_template, job, case, outfile=None): output_name = ( get_batch_script_for_job( - job, - hidden=( - self._hidden_batch_script[job] - if job in self._hidden_batch_script - else None - ), + job, hidden=self._env_workflow.hidden_job(case, job) ) if outfile is None else outfile @@ -287,8 +284,8 @@ def set_job_defaults(self, batch_jobs, case): if self._batchtype == "none": return - env_workflow = case.get_env("workflow") - known_jobs = env_workflow.get_jobs() + + known_jobs = self._env_workflow.get_jobs() for job, jsect in batch_jobs: if job not in known_jobs: @@ -445,11 +442,13 @@ def set_job_defaults(self, batch_jobs, case): seconds = convert_to_seconds(walltime) full_bab_time = convert_to_babylonian_time(seconds) walltime = format_time(walltime_format, "%H:%M:%S", full_bab_time) + if not self._env_workflow: + self._env_workflow = case.get_env("workflow") - env_workflow.set_value( + self._env_workflow.set_value( "JOB_QUEUE", self.text(queue), subgroup=job, ignore_type=False ) - env_workflow.set_value("JOB_WALLCLOCK_TIME", walltime, subgroup=job) + self._env_workflow.set_value("JOB_WALLCLOCK_TIME", walltime, subgroup=job) logger.debug( "Job {} queue {} walltime {}".format(job, self.text(queue), walltime) ) @@ -497,7 +496,6 @@ def get_batch_directives(self, case, job, overrides=None, output_format="default """ """ result = [] directive_prefix = None - self._hidden_batch_script[job] = self.hidden_status(case, job) roots = self.get_children("batch_system") queue = case.get_value("JOB_QUEUE", subgroup=job) @@ -753,9 +751,11 @@ def submit_jobs( waiting to resubmit at the end of the first sequence workflow is a logical indicating whether only "job" is submitted or the workflow sequence starting with "job" is submitted """ - env_workflow = case.get_env("workflow") + external_workflow = case.get_value("EXTERNAL_WORKFLOW") - alljobs = env_workflow.get_jobs() + if not self._env_workflow: + self._env_workflow = case.get_env("workflow") + alljobs = self._env_workflow.get_jobs() alljobs = [ j for j in alljobs @@ -763,7 +763,7 @@ def submit_jobs( os.path.join( self._caseroot, get_batch_script_for_job( - j, hidden=env_workflow.hidden_job(case, j) + j, hidden=self._env_workflow.hidden_job(case, j) ), ) ) @@ -782,7 +782,9 @@ def submit_jobs( if index < startindex: continue try: - prereq = env_workflow.get_value("prereq", subgroup=job, resolved=False) + prereq = self._env_workflow.get_value( + "prereq", subgroup=job, resolved=False + ) if ( external_workflow or prereq is None @@ -801,7 +803,9 @@ def submit_jobs( ), ) if prereq: - jobs.append((job, env_workflow.get_value("dependency", subgroup=job))) + jobs.append( + (job, self._env_workflow.get_value("dependency", subgroup=job)) + ) if self._batchtype == "cobalt": break @@ -1086,7 +1090,7 @@ def _submit_single_job( set_continue_run=resubmit_immediate, submit_resubmits=workflow and not resubmit_immediate, ) - env_workflow = case.get_env("workflow") + if batch_system == "lsf" and not batch_env_flag: sequence = ( run_args, @@ -1095,7 +1099,7 @@ def _submit_single_job( batchredirect, get_batch_script_for_job( job, - hidden=env_workflow.hidden_job(case, job), + hidden=self._env_workflow.hidden_job(case, job), ), ) elif batch_env_flag: @@ -1108,7 +1112,7 @@ def _submit_single_job( self._caseroot, get_batch_script_for_job( job, - hidden=env_workflow.hidden_job(case, job), + hidden=self._env_workflow.hidden_job(case, job), ), ), ) @@ -1121,7 +1125,7 @@ def _submit_single_job( self._caseroot, get_batch_script_for_job( job, - hidden=env_workflow.hidden_job(case, job), + hidden=self._env_workflow.hidden_job(case, job), ), ), run_args, @@ -1414,12 +1418,13 @@ def compare_xml(self, other): def make_all_batch_files(self, case): machdir = case.get_value("MACHDIR") - env_workflow = case.get_env("workflow") logger.info("Creating batch scripts") - jobs = env_workflow.get_jobs() + if not self._env_workflow: + self._env_workflow = case.get_env("workflow") + jobs = self._env_workflow.get_jobs() for job in jobs: template = case.get_resolved_value( - env_workflow.get_value("template", subgroup=job) + self._env_workflow.get_value("template", subgroup=job) ) if os.path.isabs(template): input_batch_script = template From b05eada301352c0476114661274485ad4e733999 Mon Sep 17 00:00:00 2001 From: Jim Edwards Date: Fri, 13 Sep 2024 06:19:32 -0600 Subject: [PATCH 17/19] make env_workflow an attribute of env_batch --- CIME/XML/env_batch.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CIME/XML/env_batch.py b/CIME/XML/env_batch.py index 907060e270f..580a8e9d434 100644 --- a/CIME/XML/env_batch.py +++ b/CIME/XML/env_batch.py @@ -260,6 +260,8 @@ def make_batch_script(self, input_template, job, case, outfile=None): subgroup=job, overrides=overrides, ) + if not self._env_workflow: + self._env_workflow = case.get_env("workflow") output_name = ( get_batch_script_for_job( @@ -285,6 +287,8 @@ def set_job_defaults(self, batch_jobs, case): if self._batchtype == "none": return + if not self._env_workflow: + self._env_workflow = case.get_env("workflow") known_jobs = self._env_workflow.get_jobs() for job, jsect in batch_jobs: From 35305d25227bf4529f13cb98cb16c12caa0f170c Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 13 Sep 2024 12:52:54 -0600 Subject: [PATCH 18/19] Mark SETUP as FAIL if case.cmpgen_namelists fails. --- CIME/test_scheduler.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/CIME/test_scheduler.py b/CIME/test_scheduler.py index bbe5efedf7b..da99dacb69b 100644 --- a/CIME/test_scheduler.py +++ b/CIME/test_scheduler.py @@ -1020,10 +1020,14 @@ def _setup_phase(self, test): from_dir=test_dir, env=env, ) - expect( - cmdstat in [0, TESTS_FAILED_ERR_CODE], - "Fatal error in case.cmpgen_namelists: {}".format(output), - ) + try: + expect( + cmdstat in [0, TESTS_FAILED_ERR_CODE], + "Fatal error in case.cmpgen_namelists: {}".format(output), + ) + except Exception: + self._update_test_status_file(test, SETUP_PHASE, TEST_FAIL_STATUS) + raise if self._single_exe: with Case(self._get_test_dir(test), read_only=False) as case: From 777cd60420b2d2a674e7dc186dd4f661c4f9f3f9 Mon Sep 17 00:00:00 2001 From: Alex Domingo Date: Fri, 20 Sep 2024 13:32:26 +0200 Subject: [PATCH 19/19] avoid breaking Python environment by prepending CIME paths to PYTHONPATH --- CIME/utils.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/CIME/utils.py b/CIME/utils.py index 85fa30017b0..e84d614b12b 100644 --- a/CIME/utils.py +++ b/CIME/utils.py @@ -820,12 +820,10 @@ def run_cmd( # or build a relative path and append `sys.path` to import # `standard_script_setup`. Providing `PYTHONPATH` fixes protential # broken paths in external python. - env.update( - { - "CIMEROOT": f"{get_cime_root()}", - "PYTHONPATH": f"{get_cime_root()}:{get_tools_path()}", - } - ) + env_pythonpath = os.environ.get("PYTHONPATH", "").split(":") + cime_pythonpath = [f"{get_cime_root()}", f"{get_tools_path()}"] + env_pythonpath + env["PYTHONPATH"] = ":".join(filter(None, cime_pythonpath)) + env["CIMEROOT"] = f"{get_cime_root()}" if timeout: with Timeout(timeout):