Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CCPP register phase #582

Merged
merged 9 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 3 additions & 49 deletions scripts/ccpp_capgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ def compare_fheader_to_mheader(meta_header, fort_header, logger):
###############################################################################
def check_fortran_against_metadata(meta_headers, fort_headers,
mfilename, ffilename, logger,
dyn_routines=None, fortran_routines=None):
fortran_routines=None):
###############################################################################
"""Compare a set of metadata headers from <mfilename> against the
code in the associated Fortran file, <ffilename>.
Expand Down Expand Up @@ -452,17 +452,6 @@ def check_fortran_against_metadata(meta_headers, fort_headers,
's' if num_errors > 1 else '',
mfilename, ffilename))
# end if
# Check that any dynamic constituent routines declared in the metadata are
# present in the Fortran
if dyn_routines:
for routine in dyn_routines:
if routine not in fortran_routines:
# throw an error - it's not in the Fortran
errmsg = f"Dynamic constituent routine {routine} not found in fortran {ffilename}"
raise CCPPError(errmsg)
# end if
# end for
# end if
# No return, an exception is raised on error

###############################################################################
Expand Down Expand Up @@ -561,15 +550,8 @@ def parse_scheme_files(scheme_filenames, run_env, skip_ddt_check=False):
for sect in [x.sections() for x in ftables]:
fheaders.extend(sect)
# end for
dyn_routines = []
for table in mtables:
if table.dyn_const_routine:
dyn_routines.append(table.dyn_const_routine)
# end if
# end for
check_fortran_against_metadata(mheaders, fheaders,
filename, fort_file, logger,
dyn_routines=dyn_routines,
fortran_routines=additional_routines)
# Check for duplicate tables, then add to dict
for table in mtables:
Expand All @@ -593,22 +575,6 @@ def parse_scheme_files(scheme_filenames, run_env, skip_ddt_check=False):
# end if
# end for
# end for
# Check for duplicate dynamic constituent routine names
dyn_val_dict = {}
for table in table_dict:
routine_name = table_dict[table].dyn_const_routine
if routine_name:
if routine_name in dyn_val_dict:
# dynamic constituent routines must have unique names
scheme_name = dyn_val_dict[routine_name]
errmsg = f"ERROR: Dynamic constituent routine names must be unique. Cannot add " \
f"{routine_name} for {table}. Routine already exists in {scheme_name}. "
raise CCPPError(errmsg)
else:
dyn_val_dict[routine_name] = table
# end if
# end if
# end for

return header_dict.values(), table_dict

Expand Down Expand Up @@ -674,24 +640,12 @@ def capgen(run_env, return_db=False):
# First up, handle the host files
host_model = parse_host_model_files(host_files, host_name, run_env)
# Next, parse the scheme files
# We always need to parse the ccpp_constituent_prop_ptr_t DDT
# We always need to parse the constituent DDTs
const_prop_mod = os.path.join(src_dir, "ccpp_constituent_prop_mod.meta")
if const_prop_mod not in scheme_files:
scheme_files= [const_prop_mod] + scheme_files
# end if
scheme_headers, scheme_tdict = parse_scheme_files(scheme_files, run_env)
# Pull out the dynamic constituent routines, if any
dyn_const_dict = {}
dyn_val_dict = {}
for table in scheme_tdict:
routine_name = scheme_tdict[table].dyn_const_routine
if routine_name is not None:
if routine_name not in dyn_val_dict:
dyn_const_dict[table] = routine_name
dyn_val_dict[routine_name] = table
# end if
# end if
# end for
if run_env.verbose:
ddts = host_model.ddt_lib.keys()
if ddts:
Expand Down Expand Up @@ -722,7 +676,7 @@ def capgen(run_env, return_db=False):
# end if
os.makedirs(outtemp_dir)
# end if
ccpp_api = API(sdfs, host_model, scheme_headers, run_env, dyn_const_dict)
ccpp_api = API(sdfs, host_model, scheme_headers, run_env)
cap_filenames = ccpp_api.write(outtemp_dir, run_env)
if run_env.generate_host_cap:
# Create a cap file
Expand Down
65 changes: 0 additions & 65 deletions scripts/ccpp_datafile.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@
{"report" : "dependencies", "type" : bool,
"help" : ("Return a list of scheme and host "
"dependency module names")},
{"report" : "dyn_const_routines", "type" : bool,
"help" : ("Return the constituent routines for a suite")},
{"report" : "suite_list", "type" : bool,
"help" : "Return a list of configured suite names"},
{"report" : "required_variables", "type" : str,
Expand Down Expand Up @@ -106,8 +104,6 @@ def __init__(self, action, value=True):
# Test a valid action
>>> DatatableReport('input_variables', False).action
'input_variables'
>>> DatatableReport('dyn_const_routines', True).value
True

# Test an invalid action
>>> DatatableReport('banana', True).value
Expand Down Expand Up @@ -400,40 +396,6 @@ def _retrieve_dependencies(table):
# end for
return sorted(result)

###############################################################################
def _retrieve_dyn_const_routines(table):
###############################################################################
"""Find and return a list of all scheme constituent routines.
# Test valid dynamic constituent routines
>>> table = ET.fromstring("<ccpp_datatable version='1.0'><dyn_const_routines>" \
"<dyn_const_routine parent='banana'>dyn_const_get" \
"</dyn_const_routine><dyn_const_routine>dyn_const_2" \
"</dyn_const_routine></dyn_const_routines></ccpp_datatable>")
>>> _retrieve_dyn_const_routines(table)
['dyn_const_2', 'dyn_const_get']

# Test no dynamic constituent routines
>>> table = ET.fromstring("<ccpp_datatable version='1.0'><dyn_const_routines>" \
"</dyn_const_routines></ccpp_datatable>")
>>> _retrieve_dyn_const_routines(table)
[]

# Test missing dynamic constituent routines tag
>>> table = ET.fromstring("<ccpp_datatable version='1.0'></ccpp_datatable>")
>>> _retrieve_dyn_const_routines(table)
Traceback (most recent call last):
...
ccpp_datafile.CCPPDatatableError: Could not find 'dyn_const_routines' element

"""
routines = table.find("dyn_const_routines")
if routines is None:
raise CCPPDatatableError("Could not find 'dyn_const_routines' element")
# end if
routine_names = [routine.text for routine in routines if routine.text]
# end for
return sorted(routine_names)

###############################################################################
def _find_var_dictionary(table, dict_name=None, dict_type=None):
###############################################################################
Expand Down Expand Up @@ -746,8 +708,6 @@ def datatable_report(datatable, action, sep, exclude_protected=False):
result = _retrieve_module_list(table)
elif action.action_is("dependencies"):
result = _retrieve_dependencies(table)
elif action.action_is("dyn_const_routines"):
result = _retrieve_dyn_const_routines(table)
elif action.action_is("suite_list"):
result = _retrieve_suite_list(table)
elif action.action_is("required_variables"):
Expand Down Expand Up @@ -1093,20 +1053,6 @@ def _add_dependencies(parent, scheme_depends, host_depends):
entry.text = sfile
# end for

###############################################################################
def _add_dyn_const_routine(file_entry, routine, scheme):
###############################################################################
"""Add a section to <parent> that lists all the constituent routines
for the suite
>>> file_entry = ET.fromstring("<ccpp_datatable><dyn_const_routines></dyn_const_routines></ccpp_datatable>")
>>> _add_dyn_const_routine(file_entry, 'test_dyn_const', 'test_scheme')
>>> table_entry_pretty_print(file_entry, 0)
'<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'
"""
entry = ET.SubElement(file_entry, "dyn_const_routine")
entry.text = routine
entry.set("parent", scheme)

###############################################################################
def _add_generated_files(parent, host_files, suite_files, ccpp_kinds, src_dir):
###############################################################################
Expand Down Expand Up @@ -1233,17 +1179,6 @@ def generate_ccpp_datatable(run_env, host_model, api, scheme_headers,
# end for
# end for
_add_dependencies(datatable, scheme_depends, host_depends)
# Add in all constituent routines
first_const_routine = True
for table in scheme_tdict:
if scheme_tdict[table].dyn_const_routine is not None:
if first_const_routine:
file_entry = ET.SubElement(datatable, "dyn_const_routines")
first_const_routine = False
# end if
_add_dyn_const_routine(file_entry, scheme_tdict[table].dyn_const_routine, table)
# end if
# end for
# Write tree
datatable_tree = PrettyElementTree(datatable)
datatable_tree.write(run_env.datatable_file)
Expand Down
5 changes: 4 additions & 1 deletion scripts/ccpp_state_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# CCPP framework imports
from state_machine import StateMachine

_REG_ST = r"(?:register)"
dustinswales marked this conversation as resolved.
Show resolved Hide resolved
_INIT_ST = r"(?:init(?:ial(?:ize)?)?)"
_FINAL_ST = r"(?:final(?:ize)?)"
_RUN_ST = r"(?:run)"
Expand All @@ -12,7 +13,9 @@
# Allowed CCPP transitions
# pylint: disable=bad-whitespace
RUN_PHASE_NAME = 'run'
CCPP_STATE_MACH = StateMachine((('initialize', 'uninitialized',
CCPP_STATE_MACH = StateMachine((('register', 'uninitialized',
'uninitialized', _REG_ST),
('initialize', 'uninitialized',
'initialized', _INIT_ST),
('timestep_initial', 'initialized',
'in_time_step', _TS_INIT_ST),
Expand Down
27 changes: 15 additions & 12 deletions scripts/ccpp_suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ class Suite(VarDictionary):
'''

# Note that these group names need to match CCPP_STATE_MACH
__register_group_name = 'register'

__initial_group_name = 'initialize'

__final_group_name = 'finalize'
Expand Down Expand Up @@ -205,6 +207,8 @@ def parse(self, run_env):
if run_env.logger and run_env.logger.isEnabledFor(logging.INFO):
run_env.logger.info(lmsg.format(self.name))
# end if
gname = Suite.__register_group_name
self.__suite_reg_group = self.new_group_from_name(gname, run_env)
gname = Suite.__initial_group_name
self.__suite_init_group = self.new_group_from_name(gname, run_env)
gname = Suite.__final_group_name
Expand All @@ -214,11 +218,13 @@ def parse(self, run_env):
gname = Suite.__timestep_final_group_name
self.__timestep_final_group = self.new_group_from_name(gname, run_env)
# Set up some groupings for later efficiency
self._beg_groups = [self.__suite_init_group.name,
self._beg_groups = [self.__suite_reg_group.name,
self.__suite_init_group.name,
self.__timestep_init_group.name]
self._end_groups = [self.__suite_final_group.name,
self.__timestep_final_group.name]
# Build hierarchical structure as in SDF
self.__groups.append(self.__suite_reg_group)
self.__groups.append(self.__suite_init_group)
self.__groups.append(self.__timestep_init_group)
for suite_item in suite_xml:
Expand Down Expand Up @@ -560,8 +566,13 @@ def write(self, output_dir, run_env):
outfile.end_module_header()
for group in self.__groups:
if group.name in self._beg_groups:
group.write(outfile, self.__host_arg_list_noloop,
1, const_mod, suite_vars=self, allocate=True)
if group.name == self.__suite_reg_group.name:
group.write(outfile, self.__host_arg_list_noloop,
1, const_mod, suite_vars=self)
else:
group.write(outfile, self.__host_arg_list_noloop,
1, const_mod, suite_vars=self, allocate=True)
# end if
elif group.name in self._end_groups:
group.write(outfile, self.__host_arg_list_noloop,
1, const_mod, suite_vars=self, deallocate=True)
Expand Down Expand Up @@ -615,7 +626,7 @@ class API(VarDictionary):
'kind':'len=*', 'units':'',
'dimensions':'()'}, _API_SOURCE, _API_DUMMY_RUN_ENV)

def __init__(self, sdfs, host_model, scheme_headers, run_env, dyn_const_dict={}):
def __init__(self, sdfs, host_model, scheme_headers, run_env):
"""Initialize this API.
<sdfs> is the list of Suite Definition Files to be parsed for
data needed by the CCPP cap.
Expand All @@ -624,14 +635,11 @@ def __init__(self, sdfs, host_model, scheme_headers, run_env, dyn_const_dict={})
<scheme_headers> is the list of parsed physics scheme metadata files.
Every scheme referenced by an SDF in <sdfs> MUST be in this list,
however, unused schemes are allowed.
<dyn_const_dict> is the dictionary (key = scheme name) of dynamic
constituent routine names
<run_env> is the CCPPFrameworkEnv object for this framework run.
"""
self.__module = 'ccpp_physics_api'
self.__host = host_model
self.__suites = list()
self.__dyn_const_dict = dyn_const_dict
super().__init__(self.module, run_env, parent_dict=self.host_model)
# Create a usable library out of scheme_headers
# Structure is dictionary of dictionaries
Expand Down Expand Up @@ -1187,11 +1195,6 @@ def suites(self):
"Return the list of this API's suites"
return self.__suites

@property
def dyn_const_dict(self):
"""Return the dynamic constituent routine dictionary"""
return self.__dyn_const_dict

###############################################################################
if __name__ == "__main__":
try:
Expand Down
Loading
Loading