Skip to content

Commit feaca34

Browse files
authored
Merge pull request #615 from NCAR/update_from_develop_2024-11-21
Update `main` with latest commits from `develop`
2 parents 9e1c3ab + 88970ea commit feaca34

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+1396
-1032
lines changed

.github/workflows/capgen_unit_tests.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: Capgen Unit Tests
33
on:
44
workflow_dispatch:
55
pull_request:
6-
branches: [feature/capgen, main]
6+
branches: [develop, main]
77

88
jobs:
99
unit_tests:
@@ -15,7 +15,7 @@ jobs:
1515
steps:
1616
- uses: actions/checkout@v3
1717
- name: update repos and install dependencies
18-
run: sudo apt-get update && sudo apt-get install -y build-essential ${{matrix.fortran-compiler}} cmake python3 git
18+
run: sudo apt-get update && sudo apt-get install -y build-essential ${{matrix.fortran-compiler}} cmake python3 git libxml2-utils
1919
- name: Run unit tests
2020
run: cd test && ./run_fortran_tests.sh
2121

.github/workflows/python.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: Python package
33
on:
44
workflow_dispatch:
55
pull_request:
6-
branches: [feature/capgen, main]
6+
branches: [develop, main]
77

88
jobs:
99
build:

scripts/ccpp_capgen.py

Lines changed: 3 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ def compare_fheader_to_mheader(meta_header, fort_header, logger):
400400
###############################################################################
401401
def check_fortran_against_metadata(meta_headers, fort_headers,
402402
mfilename, ffilename, logger,
403-
dyn_routines=None, fortran_routines=None):
403+
fortran_routines=None):
404404
###############################################################################
405405
"""Compare a set of metadata headers from <mfilename> against the
406406
code in the associated Fortran file, <ffilename>.
@@ -452,17 +452,6 @@ def check_fortran_against_metadata(meta_headers, fort_headers,
452452
's' if num_errors > 1 else '',
453453
mfilename, ffilename))
454454
# end if
455-
# Check that any dynamic constituent routines declared in the metadata are
456-
# present in the Fortran
457-
if dyn_routines:
458-
for routine in dyn_routines:
459-
if routine not in fortran_routines:
460-
# throw an error - it's not in the Fortran
461-
errmsg = f"Dynamic constituent routine {routine} not found in fortran {ffilename}"
462-
raise CCPPError(errmsg)
463-
# end if
464-
# end for
465-
# end if
466455
# No return, an exception is raised on error
467456

468457
###############################################################################
@@ -561,15 +550,8 @@ def parse_scheme_files(scheme_filenames, run_env, skip_ddt_check=False):
561550
for sect in [x.sections() for x in ftables]:
562551
fheaders.extend(sect)
563552
# end for
564-
dyn_routines = []
565-
for table in mtables:
566-
if table.dyn_const_routine:
567-
dyn_routines.append(table.dyn_const_routine)
568-
# end if
569-
# end for
570553
check_fortran_against_metadata(mheaders, fheaders,
571554
filename, fort_file, logger,
572-
dyn_routines=dyn_routines,
573555
fortran_routines=additional_routines)
574556
# Check for duplicate tables, then add to dict
575557
for table in mtables:
@@ -593,22 +575,6 @@ def parse_scheme_files(scheme_filenames, run_env, skip_ddt_check=False):
593575
# end if
594576
# end for
595577
# end for
596-
# Check for duplicate dynamic constituent routine names
597-
dyn_val_dict = {}
598-
for table in table_dict:
599-
routine_name = table_dict[table].dyn_const_routine
600-
if routine_name:
601-
if routine_name in dyn_val_dict:
602-
# dynamic constituent routines must have unique names
603-
scheme_name = dyn_val_dict[routine_name]
604-
errmsg = f"ERROR: Dynamic constituent routine names must be unique. Cannot add " \
605-
f"{routine_name} for {table}. Routine already exists in {scheme_name}. "
606-
raise CCPPError(errmsg)
607-
else:
608-
dyn_val_dict[routine_name] = table
609-
# end if
610-
# end if
611-
# end for
612578

613579
return header_dict.values(), table_dict
614580

@@ -674,24 +640,12 @@ def capgen(run_env, return_db=False):
674640
# First up, handle the host files
675641
host_model = parse_host_model_files(host_files, host_name, run_env)
676642
# Next, parse the scheme files
677-
# We always need to parse the ccpp_constituent_prop_ptr_t DDT
643+
# We always need to parse the constituent DDTs
678644
const_prop_mod = os.path.join(src_dir, "ccpp_constituent_prop_mod.meta")
679645
if const_prop_mod not in scheme_files:
680646
scheme_files= [const_prop_mod] + scheme_files
681647
# end if
682648
scheme_headers, scheme_tdict = parse_scheme_files(scheme_files, run_env)
683-
# Pull out the dynamic constituent routines, if any
684-
dyn_const_dict = {}
685-
dyn_val_dict = {}
686-
for table in scheme_tdict:
687-
routine_name = scheme_tdict[table].dyn_const_routine
688-
if routine_name is not None:
689-
if routine_name not in dyn_val_dict:
690-
dyn_const_dict[table] = routine_name
691-
dyn_val_dict[routine_name] = table
692-
# end if
693-
# end if
694-
# end for
695649
if run_env.verbose:
696650
ddts = host_model.ddt_lib.keys()
697651
if ddts:
@@ -722,7 +676,7 @@ def capgen(run_env, return_db=False):
722676
# end if
723677
os.makedirs(outtemp_dir)
724678
# end if
725-
ccpp_api = API(sdfs, host_model, scheme_headers, run_env, dyn_const_dict)
679+
ccpp_api = API(sdfs, host_model, scheme_headers, run_env)
726680
cap_filenames = ccpp_api.write(outtemp_dir, run_env)
727681
if run_env.generate_host_cap:
728682
# Create a cap file

scripts/ccpp_datafile.py

Lines changed: 0 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,6 @@
5858
{"report" : "dependencies", "type" : bool,
5959
"help" : ("Return a list of scheme and host "
6060
"dependency module names")},
61-
{"report" : "dyn_const_routines", "type" : bool,
62-
"help" : ("Return the constituent routines for a suite")},
6361
{"report" : "suite_list", "type" : bool,
6462
"help" : "Return a list of configured suite names"},
6563
{"report" : "required_variables", "type" : str,
@@ -106,8 +104,6 @@ def __init__(self, action, value=True):
106104
# Test a valid action
107105
>>> DatatableReport('input_variables', False).action
108106
'input_variables'
109-
>>> DatatableReport('dyn_const_routines', True).value
110-
True
111107
112108
# Test an invalid action
113109
>>> DatatableReport('banana', True).value
@@ -400,40 +396,6 @@ def _retrieve_dependencies(table):
400396
# end for
401397
return sorted(result)
402398

403-
###############################################################################
404-
def _retrieve_dyn_const_routines(table):
405-
###############################################################################
406-
"""Find and return a list of all scheme constituent routines.
407-
# Test valid dynamic constituent routines
408-
>>> table = ET.fromstring("<ccpp_datatable version='1.0'><dyn_const_routines>" \
409-
"<dyn_const_routine parent='banana'>dyn_const_get" \
410-
"</dyn_const_routine><dyn_const_routine>dyn_const_2" \
411-
"</dyn_const_routine></dyn_const_routines></ccpp_datatable>")
412-
>>> _retrieve_dyn_const_routines(table)
413-
['dyn_const_2', 'dyn_const_get']
414-
415-
# Test no dynamic constituent routines
416-
>>> table = ET.fromstring("<ccpp_datatable version='1.0'><dyn_const_routines>" \
417-
"</dyn_const_routines></ccpp_datatable>")
418-
>>> _retrieve_dyn_const_routines(table)
419-
[]
420-
421-
# Test missing dynamic constituent routines tag
422-
>>> table = ET.fromstring("<ccpp_datatable version='1.0'></ccpp_datatable>")
423-
>>> _retrieve_dyn_const_routines(table)
424-
Traceback (most recent call last):
425-
...
426-
ccpp_datafile.CCPPDatatableError: Could not find 'dyn_const_routines' element
427-
428-
"""
429-
routines = table.find("dyn_const_routines")
430-
if routines is None:
431-
raise CCPPDatatableError("Could not find 'dyn_const_routines' element")
432-
# end if
433-
routine_names = [routine.text for routine in routines if routine.text]
434-
# end for
435-
return sorted(routine_names)
436-
437399
###############################################################################
438400
def _find_var_dictionary(table, dict_name=None, dict_type=None):
439401
###############################################################################
@@ -746,8 +708,6 @@ def datatable_report(datatable, action, sep, exclude_protected=False):
746708
result = _retrieve_module_list(table)
747709
elif action.action_is("dependencies"):
748710
result = _retrieve_dependencies(table)
749-
elif action.action_is("dyn_const_routines"):
750-
result = _retrieve_dyn_const_routines(table)
751711
elif action.action_is("suite_list"):
752712
result = _retrieve_suite_list(table)
753713
elif action.action_is("required_variables"):
@@ -1093,20 +1053,6 @@ def _add_dependencies(parent, scheme_depends, host_depends):
10931053
entry.text = sfile
10941054
# end for
10951055

1096-
###############################################################################
1097-
def _add_dyn_const_routine(file_entry, routine, scheme):
1098-
###############################################################################
1099-
"""Add a section to <parent> that lists all the constituent routines
1100-
for the suite
1101-
>>> file_entry = ET.fromstring("<ccpp_datatable><dyn_const_routines></dyn_const_routines></ccpp_datatable>")
1102-
>>> _add_dyn_const_routine(file_entry, 'test_dyn_const', 'test_scheme')
1103-
>>> table_entry_pretty_print(file_entry, 0)
1104-
'<ccpp_datatable>\\n <dyn_const_routines />\\n <dyn_const_routine parent=test_scheme>\\n test_dyn_const\\n </dyn_const_routine>\\n</ccpp_datatable>\\n'
1105-
"""
1106-
entry = ET.SubElement(file_entry, "dyn_const_routine")
1107-
entry.text = routine
1108-
entry.set("parent", scheme)
1109-
11101056
###############################################################################
11111057
def _add_generated_files(parent, host_files, suite_files, ccpp_kinds, src_dir):
11121058
###############################################################################
@@ -1233,17 +1179,6 @@ def generate_ccpp_datatable(run_env, host_model, api, scheme_headers,
12331179
# end for
12341180
# end for
12351181
_add_dependencies(datatable, scheme_depends, host_depends)
1236-
# Add in all constituent routines
1237-
first_const_routine = True
1238-
for table in scheme_tdict:
1239-
if scheme_tdict[table].dyn_const_routine is not None:
1240-
if first_const_routine:
1241-
file_entry = ET.SubElement(datatable, "dyn_const_routines")
1242-
first_const_routine = False
1243-
# end if
1244-
_add_dyn_const_routine(file_entry, scheme_tdict[table].dyn_const_routine, table)
1245-
# end if
1246-
# end for
12471182
# Write tree
12481183
datatable_tree = PrettyElementTree(datatable)
12491184
datatable_tree.write(run_env.datatable_file)

scripts/ccpp_prebuild.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def parse_arguments():
5555
verbose = args.verbose
5656
debug = args.debug
5757
if args.suites:
58-
sdfs = ['suite_{0}.xml'.format(x) for x in args.suites.split(',')]
58+
sdfs = ['{0}.xml'.format(x) for x in args.suites.split(',')]
5959
else:
6060
sdfs = None
6161
builddir = args.builddir
@@ -181,8 +181,22 @@ def parse_suites(suites_dir, sdfs):
181181
logging.info('Parsing suite definition files ...')
182182
suites = []
183183
for sdf in sdfs:
184-
logging.info('Parsing suite definition file {0} ...'.format(os.path.join(suites_dir, sdf)))
185-
suite = Suite(sdf_name=os.path.join(suites_dir, sdf))
184+
sdf_file=os.path.join(suites_dir, sdf)
185+
if not os.path.exists(sdf_file):
186+
# If suite file not found, check old filename convention (suite_[suitename].xml)
187+
sdf_file_legacy=os.path.join(suites_dir, f"suite_{sdf}")
188+
if os.path.exists(sdf_file_legacy):
189+
logging.warning("Parsing suite definition file using legacy naming convention")
190+
logging.warning(f"Filename {os.path.basename(sdf_file_legacy)}")
191+
logging.warning(f"Suite name {sdf}")
192+
sdf_file=sdf_file_legacy
193+
else:
194+
logging.critical(f"Suite definition file {sdf_file} not found.")
195+
success = False
196+
return (success, suites)
197+
198+
logging.info(f'Parsing suite definition file {sdf_file} ...')
199+
suite = Suite(sdf_name=sdf_file)
186200
success = suite.parse()
187201
if not success:
188202
logging.error('Parsing suite definition file {0} failed.'.format(sdf))

scripts/ccpp_state_machine.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# CCPP framework imports
44
from state_machine import StateMachine
55

6+
_REG_ST = r"(?:register)"
67
_INIT_ST = r"(?:init(?:ial(?:ize)?)?)"
78
_FINAL_ST = r"(?:final(?:ize)?)"
89
_RUN_ST = r"(?:run)"
@@ -12,7 +13,9 @@
1213
# Allowed CCPP transitions
1314
# pylint: disable=bad-whitespace
1415
RUN_PHASE_NAME = 'run'
15-
CCPP_STATE_MACH = StateMachine((('initialize', 'uninitialized',
16+
CCPP_STATE_MACH = StateMachine((('register', 'uninitialized',
17+
'uninitialized', _REG_ST),
18+
('initialize', 'uninitialized',
1619
'initialized', _INIT_ST),
1720
('timestep_initial', 'initialized',
1821
'in_time_step', _TS_INIT_ST),

scripts/ccpp_suite.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ class Suite(VarDictionary):
7070
'''
7171

7272
# Note that these group names need to match CCPP_STATE_MACH
73+
__register_group_name = 'register'
74+
7375
__initial_group_name = 'initialize'
7476

7577
__final_group_name = 'finalize'
@@ -205,6 +207,8 @@ def parse(self, run_env):
205207
if run_env.logger and run_env.logger.isEnabledFor(logging.INFO):
206208
run_env.logger.info(lmsg.format(self.name))
207209
# end if
210+
gname = Suite.__register_group_name
211+
self.__suite_reg_group = self.new_group_from_name(gname, run_env)
208212
gname = Suite.__initial_group_name
209213
self.__suite_init_group = self.new_group_from_name(gname, run_env)
210214
gname = Suite.__final_group_name
@@ -214,11 +218,13 @@ def parse(self, run_env):
214218
gname = Suite.__timestep_final_group_name
215219
self.__timestep_final_group = self.new_group_from_name(gname, run_env)
216220
# Set up some groupings for later efficiency
217-
self._beg_groups = [self.__suite_init_group.name,
221+
self._beg_groups = [self.__suite_reg_group.name,
222+
self.__suite_init_group.name,
218223
self.__timestep_init_group.name]
219224
self._end_groups = [self.__suite_final_group.name,
220225
self.__timestep_final_group.name]
221226
# Build hierarchical structure as in SDF
227+
self.__groups.append(self.__suite_reg_group)
222228
self.__groups.append(self.__suite_init_group)
223229
self.__groups.append(self.__timestep_init_group)
224230
for suite_item in suite_xml:
@@ -560,8 +566,13 @@ def write(self, output_dir, run_env):
560566
outfile.end_module_header()
561567
for group in self.__groups:
562568
if group.name in self._beg_groups:
563-
group.write(outfile, self.__host_arg_list_noloop,
564-
1, const_mod, suite_vars=self, allocate=True)
569+
if group.name == self.__suite_reg_group.name:
570+
group.write(outfile, self.__host_arg_list_noloop,
571+
1, const_mod, suite_vars=self)
572+
else:
573+
group.write(outfile, self.__host_arg_list_noloop,
574+
1, const_mod, suite_vars=self, allocate=True)
575+
# end if
565576
elif group.name in self._end_groups:
566577
group.write(outfile, self.__host_arg_list_noloop,
567578
1, const_mod, suite_vars=self, deallocate=True)
@@ -615,7 +626,7 @@ class API(VarDictionary):
615626
'kind':'len=*', 'units':'',
616627
'dimensions':'()'}, _API_SOURCE, _API_DUMMY_RUN_ENV)
617628

618-
def __init__(self, sdfs, host_model, scheme_headers, run_env, dyn_const_dict={}):
629+
def __init__(self, sdfs, host_model, scheme_headers, run_env):
619630
"""Initialize this API.
620631
<sdfs> is the list of Suite Definition Files to be parsed for
621632
data needed by the CCPP cap.
@@ -624,14 +635,11 @@ def __init__(self, sdfs, host_model, scheme_headers, run_env, dyn_const_dict={})
624635
<scheme_headers> is the list of parsed physics scheme metadata files.
625636
Every scheme referenced by an SDF in <sdfs> MUST be in this list,
626637
however, unused schemes are allowed.
627-
<dyn_const_dict> is the dictionary (key = scheme name) of dynamic
628-
constituent routine names
629638
<run_env> is the CCPPFrameworkEnv object for this framework run.
630639
"""
631640
self.__module = 'ccpp_physics_api'
632641
self.__host = host_model
633642
self.__suites = list()
634-
self.__dyn_const_dict = dyn_const_dict
635643
super().__init__(self.module, run_env, parent_dict=self.host_model)
636644
# Create a usable library out of scheme_headers
637645
# Structure is dictionary of dictionaries
@@ -1187,11 +1195,6 @@ def suites(self):
11871195
"Return the list of this API's suites"
11881196
return self.__suites
11891197

1190-
@property
1191-
def dyn_const_dict(self):
1192-
"""Return the dynamic constituent routine dictionary"""
1193-
return self.__dyn_const_dict
1194-
11951198
###############################################################################
11961199
if __name__ == "__main__":
11971200
try:

scripts/ccpp_track_variables.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def create_metadata_filename_dict(metapath):
6969
with that scheme"""
7070

7171
metadata_dict = {}
72-
scheme_filenames = glob.glob(os.path.join(metapath, "*.meta"))
72+
scheme_filenames = glob.glob(os.path.join(metapath, "*.meta"), recursive=True)
7373
if not scheme_filenames:
7474
raise Exception(f'No files found in {metapath} with ".meta" extension')
7575

scripts/common.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
CCPP_STATIC_SUBROUTINE_NAME = 'ccpp_physics_{stage}'
7474

7575
# Filename pattern for suite definition files
76-
SUITE_DEFINITION_FILENAME_PATTERN = re.compile('^suite_(.*)\.xml$')
76+
SUITE_DEFINITION_FILENAME_PATTERN = re.compile('^(.*)\.xml$')
7777

7878
# Maximum number of concurrent CCPP instances per MPI task
7979
CCPP_NUM_INSTANCES = 200

0 commit comments

Comments
 (0)