|
15 | 15 |
|
16 | 16 | # SCREAM imports |
17 | 17 | from eamxx_buildnml_impl import get_valid_selectors, get_child, refine_type, \ |
18 | | - resolve_all_inheritances, gen_atm_proc_group, check_all_values |
| 18 | + resolve_all_inheritances, gen_atm_proc_group, check_all_values, find_node |
19 | 19 | from atm_manip import apply_atm_procs_list_changes_from_buffer, apply_non_atm_procs_list_changes_from_buffer |
20 | 20 |
|
21 | 21 | from utils import ensure_yaml # pylint: disable=no-name-in-module |
|
29 | 29 | # Cime imports |
30 | 30 | from standard_script_setup import * # pylint: disable=wildcard-import |
31 | 31 | from CIME.utils import expect, safe_copy, SharedArea |
| 32 | +from CIME.test_status import TestStatus, RUN_PHASE |
32 | 33 |
|
33 | 34 | logger = logging.getLogger(__name__) # pylint: disable=undefined-variable |
34 | 35 |
|
@@ -104,6 +105,121 @@ def do_cime_vars(entry, case, refine=False, extra=None): |
104 | 105 |
|
105 | 106 | return entry |
106 | 107 |
|
| 108 | +############################################################################### |
| 109 | +def perform_consistency_checks(case, xml): |
| 110 | +############################################################################### |
| 111 | + """ |
| 112 | + There may be separate parts of the xml that must satisfy some consistency |
| 113 | + Here, we run any such check, so we can catch errors before submit time |
| 114 | +
|
| 115 | + >>> from eamxx_buildnml_impl import MockCase |
| 116 | + >>> xml_str = ''' |
| 117 | + ... <params> |
| 118 | + ... <rrtmgp> |
| 119 | + ... <rad_frequency type="integer">3</rad_frequency> |
| 120 | + ... </rrtmgp> |
| 121 | + ... </params> |
| 122 | + ... ''' |
| 123 | + >>> import xml.etree.ElementTree as ET |
| 124 | + >>> xml = ET.fromstring(xml_str) |
| 125 | + >>> case = MockCase({'ATM_NCPL':'24', 'REST_N':24, 'REST_OPTION':'nsteps'}) |
| 126 | + >>> perform_consistency_checks(case,xml) |
| 127 | + >>> case = MockCase({'ATM_NCPL':'24', 'REST_N':2, 'REST_OPTION':'nsteps'}) |
| 128 | + >>> perform_consistency_checks(case,xml) |
| 129 | + Traceback (most recent call last): |
| 130 | + CIME.utils.CIMEError: ERROR: rrtmgp::rad_frequency (3 steps) incompatible with restart frequency (2 steps). |
| 131 | + Please, ensure restart happens on a step when rad is ON |
| 132 | + >>> case = MockCase({'ATM_NCPL':'24', 'REST_N':10800, 'REST_OPTION':'nseconds'}) |
| 133 | + >>> perform_consistency_checks(case,xml) |
| 134 | + >>> case = MockCase({'ATM_NCPL':'24', 'REST_N':7200, 'REST_OPTION':'nseconds'}) |
| 135 | + >>> perform_consistency_checks(case,xml) |
| 136 | + Traceback (most recent call last): |
| 137 | + CIME.utils.CIMEError: ERROR: rrtmgp::rad_frequency incompatible with restart frequency. |
| 138 | + Please, ensure restart happens on a step when rad is ON |
| 139 | + rest_tstep: 7200 |
| 140 | + rad_testep: 10800.0 |
| 141 | + >>> case = MockCase({'ATM_NCPL':'24', 'REST_N':180, 'REST_OPTION':'nminutes'}) |
| 142 | + >>> perform_consistency_checks(case,xml) |
| 143 | + >>> case = MockCase({'ATM_NCPL':'24', 'REST_N':120, 'REST_OPTION':'nminutes'}) |
| 144 | + >>> perform_consistency_checks(case,xml) |
| 145 | + Traceback (most recent call last): |
| 146 | + CIME.utils.CIMEError: ERROR: rrtmgp::rad_frequency incompatible with restart frequency. |
| 147 | + Please, ensure restart happens on a step when rad is ON |
| 148 | + rest_tstep: 7200 |
| 149 | + rad_testep: 10800.0 |
| 150 | + >>> case = MockCase({'ATM_NCPL':'24', 'REST_N':6, 'REST_OPTION':'nhours'}) |
| 151 | + >>> perform_consistency_checks(case,xml) |
| 152 | + >>> case = MockCase({'ATM_NCPL':'24', 'REST_N':8, 'REST_OPTION':'nhours'}) |
| 153 | + >>> perform_consistency_checks(case,xml) |
| 154 | + Traceback (most recent call last): |
| 155 | + CIME.utils.CIMEError: ERROR: rrtmgp::rad_frequency incompatible with restart frequency. |
| 156 | + Please, ensure restart happens on a step when rad is ON |
| 157 | + rest_tstep: 28800 |
| 158 | + rad_testep: 10800.0 |
| 159 | + >>> case = MockCase({'ATM_NCPL':'12', 'REST_N':2, 'REST_OPTION':'ndays'}) |
| 160 | + >>> perform_consistency_checks(case,xml) |
| 161 | + >>> case = MockCase({'ATM_NCPL':'10', 'REST_N':2, 'REST_OPTION':'ndays'}) |
| 162 | + >>> perform_consistency_checks(case,xml) |
| 163 | + Traceback (most recent call last): |
| 164 | + CIME.utils.CIMEError: ERROR: rrtmgp::rad_frequency incompatible with restart frequency. |
| 165 | + Please, ensure restart happens on a step when rad is ON |
| 166 | + For daily (or less frequent) restart, rad_frequency must divide ATM_NCPL |
| 167 | + """ |
| 168 | + |
| 169 | + # RRTMGP can be supercycled. Restarts cannot fall in the middle |
| 170 | + # of a rad superstep |
| 171 | + rrtmgp = find_node(xml,"rrtmgp") |
| 172 | + rest_opt = case.get_value("REST_OPTION") |
| 173 | + is_test = case.get_value("TEST") |
| 174 | + caseraw = case.get_value("CASE") |
| 175 | + caseroot = case.get_value("CASEROOT") |
| 176 | + casebaseid = case.get_value("CASEBASEID") |
| 177 | + if rrtmgp is not None and rest_opt is not None and rest_opt not in ["never","none"]: |
| 178 | + rest_n = int(case.get_value("REST_N")) |
| 179 | + rad_freq = int(find_node(rrtmgp,"rad_frequency").text) |
| 180 | + atm_ncpl = int(case.get_value("ATM_NCPL")) |
| 181 | + atm_tstep = 86400 / atm_ncpl |
| 182 | + rad_tstep = atm_tstep * rad_freq |
| 183 | + |
| 184 | + # Some tests (ERS) make late (run-phase) changes, so we cannot validate restart |
| 185 | + # settings until RUN phase |
| 186 | + is_test_not_yet_run = False |
| 187 | + if is_test: |
| 188 | + test_name = casebaseid if casebaseid is not None else caseraw |
| 189 | + ts = TestStatus(test_dir=caseroot, test_name=test_name) |
| 190 | + phase = ts.get_latest_phase() |
| 191 | + if phase != RUN_PHASE: |
| 192 | + is_test_not_yet_run = True |
| 193 | + |
| 194 | + if rad_freq==1 or is_test_not_yet_run: |
| 195 | + pass |
| 196 | + elif rest_opt in ["nsteps", "nstep"]: |
| 197 | + expect (rest_n % rad_freq == 0, |
| 198 | + f"rrtmgp::rad_frequency ({rad_freq} steps) incompatible with " |
| 199 | + f"restart frequency ({rest_n} steps).\n" |
| 200 | + " Please, ensure restart happens on a step when rad is ON") |
| 201 | + elif rest_opt in ["nseconds", "nsecond", "nminutes", "nminute", "nhours", "nhour"]: |
| 202 | + if rest_opt in ["nseconds", "nsecond"]: |
| 203 | + factor = 1 |
| 204 | + elif rest_opt in ["nminutes", "nminute"]: |
| 205 | + factor = 60 |
| 206 | + else: |
| 207 | + factor = 3600 |
| 208 | + |
| 209 | + rest_tstep = factor*rest_n |
| 210 | + expect (rest_tstep % rad_tstep == 0, |
| 211 | + "rrtmgp::rad_frequency incompatible with restart frequency.\n" |
| 212 | + " Please, ensure restart happens on a step when rad is ON\n" |
| 213 | + f" rest_tstep: {rest_tstep}\n" |
| 214 | + f" rad_testep: {rad_tstep}") |
| 215 | + |
| 216 | + else: |
| 217 | + # for "very infrequent" restarts, we request rad_freq to divide atm_ncpl |
| 218 | + expect (atm_ncpl % rad_freq ==0, |
| 219 | + "rrtmgp::rad_frequency incompatible with restart frequency.\n" |
| 220 | + " Please, ensure restart happens on a step when rad is ON\n" |
| 221 | + " For daily (or less frequent) restart, rad_frequency must divide ATM_NCPL") |
| 222 | + |
107 | 223 | ############################################################################### |
108 | 224 | def ordered_dump(data, item, Dumper=yaml.SafeDumper, **kwds): |
109 | 225 | ############################################################################### |
@@ -627,6 +743,8 @@ def _create_raw_xml_file_impl(case, xml, filepath=None): |
627 | 743 |
|
628 | 744 | raise e |
629 | 745 |
|
| 746 | + perform_consistency_checks (case, xml) |
| 747 | + |
630 | 748 | return xml |
631 | 749 |
|
632 | 750 | ############################################################################### |
|
0 commit comments