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

Constituents #495

Merged
merged 13 commits into from
Nov 29, 2023
Merged
39 changes: 32 additions & 7 deletions scripts/ccpp_capgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@
from host_model import HostModel
from metadata_table import parse_metadata_file, SCHEME_HEADER_TYPE
from parse_tools import init_log, set_log_level, context_string
from parse_tools import register_fortran_ddt_name
from parse_tools import CCPPError, ParseInternalError

## Capture the Framework root
__SCRIPT_PATH = os.path.dirname(__file__)
__FRAMEWORK_ROOT = os.path.abspath(os.path.join(__SCRIPT_PATH, os.pardir))
_SCRIPT_PATH = os.path.dirname(__file__)
_FRAMEWORK_ROOT = os.path.abspath(os.path.join(_SCRIPT_PATH, os.pardir))
_SRC_ROOT = os.path.join(_FRAMEWORK_ROOT, "src")
## Init this now so that all Exceptions can be trapped
_LOGGER = init_log(os.path.basename(__file__))

Expand All @@ -43,6 +45,11 @@
## Metadata table types where order is significant
_ORDERED_TABLE_TYPES = [SCHEME_HEADER_TYPE]

## CCPP Framework supported DDT types
_CCPP_FRAMEWORK_DDT_TYPES = ["ccpp_hash_table_t",
"ccpp_hashable_t",
"ccpp_hashable_char_t"]

###############################################################################
def delete_pathnames_from_file(capfile, logger):
###############################################################################
Expand Down Expand Up @@ -578,12 +585,22 @@ def capgen(run_env):
# Try to create output_dir (let it crash if it fails)
os.makedirs(run_env.output_dir)
# end if
# Pre-register base CCPP DDT types:
for ddt_name in _CCPP_FRAMEWORK_DDT_TYPES:
register_fortran_ddt_name(ddt_name)
# end for
src_dir = os.path.join(_FRAMEWORK_ROOT, "src")
host_files = run_env.host_files
host_name = run_env.host_name
scheme_files = run_env.scheme_files
# We need to create three lists of files, hosts, schemes, and SDFs
host_files = create_file_list(run_env.host_files, ['meta'], 'Host',
run_env.logger)
# The host model needs to know about the constituents module
const_mod = os.path.join(_SRC_ROOT, "ccpp_constituent_prop_mod.meta")
if const_mod not in host_files:
host_files.append(const_mod)
# end if
scheme_files = create_file_list(run_env.scheme_files, ['meta'],
'Scheme', run_env.logger)
sdfs = create_file_list(run_env.suites, ['xml'], 'Suite', run_env.logger)
Expand All @@ -594,11 +611,19 @@ def capgen(run_env):
# end if
# First up, handle the host files
host_model = parse_host_model_files(host_files, host_name, run_env)
# We always need to parse the ccpp_constituent_prop_ptr_t DDT
##XXgoldyXX: Should this be in framework_env.py?
gold2718 marked this conversation as resolved.
Show resolved Hide resolved
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
# Next, parse the scheme files
scheme_headers, scheme_tdict = parse_scheme_files(scheme_files, run_env)
ddts = host_model.ddt_lib.keys()
if ddts and run_env.logger and run_env.logger.isEnabledFor(logging.DEBUG):
run_env.logger.debug("DDT definitions = {}".format(ddts))
if run_env.logger and run_env.logger.isEnabledFor(logging.DEBUG):
ddts = host_model.ddt_lib.keys()
if ddts:
run_env.logger.debug("DDT definitions = {}".format(ddts))
# end if
# end if
plist = host_model.prop_list('local_name')
if run_env.logger and run_env.logger.isEnabledFor(logging.DEBUG):
Expand Down Expand Up @@ -628,7 +653,8 @@ def capgen(run_env):
cap_filenames = ccpp_api.write(outtemp_dir, run_env)
if run_env.generate_host_cap:
# Create a cap file
host_files = [write_host_cap(host_model, ccpp_api,
cap_module = host_model.ccpp_cap_name()
host_files = [write_host_cap(host_model, ccpp_api, cap_module,
outtemp_dir, run_env)]
else:
host_files = list()
Expand All @@ -646,7 +672,6 @@ def capgen(run_env):
# end if
# Finally, create the database of generated files and caps
# This can be directly in output_dir because it will not affect dependencies
src_dir = os.path.join(__FRAMEWORK_ROOT, "src")
generate_ccpp_datatable(run_env, host_model, ccpp_api,
scheme_headers, scheme_tdict, host_files,
cap_filenames, kinds_file, src_dir)
Expand Down
3 changes: 2 additions & 1 deletion scripts/ccpp_datafile.py
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,8 @@ def _new_var_entry(parent, var, full_entry=True):
prop_list.extend(["allocatable", "active", "default_value",
"diagnostic_name", "diagnostic_name_fixed",
"kind", "persistence", "polymorphic", "protected",
"state_variable", "type", "units"])
"state_variable", "type", "units", "molar_mass",
"advected"])
prop_list.extend(Var.constituent_property_names())
# end if
ventry = ET.SubElement(parent, "var")
Expand Down
20 changes: 17 additions & 3 deletions scripts/ccpp_suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -810,32 +810,46 @@ def write_req_vars_sub(self, ofile, errmsg_name, errcode_name):
input_vars = [set(), set(), set()] # leaves, arrrays, leaf elements
inout_vars = [set(), set(), set()] # leaves, arrrays, leaf elements
output_vars = [set(), set(), set()] # leaves, arrrays, leaf elements
const_initialized_in_physics = {}
for part in suite.groups:
for var in part.call_list.variable_list():
phase = part.phase()
stdname = var.get_prop_value("standard_name")
intent = var.get_prop_value("intent")
protected = var.get_prop_value("protected")
constituent = var.is_constituent()
if stdname not in const_initialized_in_physics:
const_initialized_in_physics[stdname] = False
# end if
if (parent is not None) and (not protected):
pvar = parent.find_variable(standard_name=stdname)
if pvar is not None:
protected = pvar.get_prop_value("protected")
# end if
# end if
elements = var.intrinsic_elements(check_dict=self.parent)
if (intent == 'in') and (not protected):
elements = var.intrinsic_elements(check_dict=self.parent,
ddt_lib=self.__ddt_lib)
if (intent == 'in') and (not protected) and (not const_initialized_in_physics[stdname]):
if isinstance(elements, list):
input_vars[1].add(stdname)
input_vars[2].update(elements)
else:
input_vars[0].add(stdname)
# end if
elif intent == 'inout':
elif intent == 'inout' and (not const_initialized_in_physics[stdname]):
if isinstance(elements, list):
inout_vars[1].add(stdname)
inout_vars[2].update(elements)
else:
inout_vars[0].add(stdname)
# end if
elif (intent == 'out' and phase != 'initialize' and constituent
gold2718 marked this conversation as resolved.
Show resolved Hide resolved
and not const_initialized_in_physics[stdname]):
# constituents HAVE to be initialized in the init phase because the dycore needs to advect them
emsg = "constituent variable '{}' cannot be initialized in the '{}' phase"
raise CCPPError(emsg.format(stdname, phase))
mwaxmonsky marked this conversation as resolved.
Show resolved Hide resolved
elif intent == 'out' and constituent and phase == 'initialize':
const_initialized_in_physics[stdname] = True
elif intent == 'out':
if isinstance(elements, list):
output_vars[1].add(stdname)
Expand Down
Loading