From 74912bfd291d6210ceef3e5548a1585fd7a36fd4 Mon Sep 17 00:00:00 2001 From: Courtney Peverley Date: Sun, 4 Aug 2024 20:05:19 -0600 Subject: [PATCH 1/7] advection test passes --- scripts/ccpp_state_machine.py | 5 +- scripts/ccpp_suite.py | 8 +- scripts/constituents.py | 63 ++++----------- scripts/host_cap.py | 108 ++++++++++++++++++++++++-- scripts/metavar.py | 5 +- scripts/parse_tools/parse_checkers.py | 2 +- scripts/suite_objects.py | 21 ++++- src/ccpp_constituent_prop_mod.F90 | 3 + src/ccpp_constituent_prop_mod.meta | 11 +++ test/advection_test/cld_ice.F90 | 54 ++++++------- test/advection_test/cld_ice.meta | 26 ++++++- test/advection_test/cld_liq.F90 | 48 +++++++----- test/advection_test/cld_liq.meta | 26 ++++++- test/advection_test/run_test | 8 +- test/advection_test/test_host.F90 | 38 ++++++++- test/advection_test/test_reports.py | 10 ++- 16 files changed, 321 insertions(+), 115 deletions(-) diff --git a/scripts/ccpp_state_machine.py b/scripts/ccpp_state_machine.py index 0de2c7bd..832e0073 100644 --- a/scripts/ccpp_state_machine.py +++ b/scripts/ccpp_state_machine.py @@ -3,6 +3,7 @@ # CCPP framework imports from state_machine import StateMachine +_REG_ST = r"(?:register)" _INIT_ST = r"(?:init(?:ial(?:ize)?)?)" _FINAL_ST = r"(?:final(?:ize)?)" _RUN_ST = r"(?:run)" @@ -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), diff --git a/scripts/ccpp_suite.py b/scripts/ccpp_suite.py index 67e89ede..f9e4ff35 100644 --- a/scripts/ccpp_suite.py +++ b/scripts/ccpp_suite.py @@ -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' @@ -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 @@ -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: diff --git a/scripts/constituents.py b/scripts/constituents.py index 84f19b20..b7f8bf26 100644 --- a/scripts/constituents.py +++ b/scripts/constituents.py @@ -440,12 +440,11 @@ def write_constituent_use_statements(cap, suite_list, indent): @staticmethod def write_host_routines(cap, host, reg_funcname, init_funcname, num_const_funcname, query_const_funcname, copy_in_funcname, copy_out_funcname, cleanup_funcname, - const_obj_name, dyn_const_name, const_names_name, const_indices_name, + const_obj_name, dyn_const_names, const_names_name, const_indices_name, const_array_func, advect_array_func, prop_array_func, - const_index_func, suite_list, dyn_const_dict, err_vars): + const_index_func, suite_list, err_vars): """Write out the host model routine which will instantiate constituent fields for all the constituents in . - is a dictionary (key=scheme name) of dynamic constituent routines is a list of the host model's error variables. Also write out the following routines: : Initialize constituent data @@ -479,13 +478,6 @@ def write_host_routines(cap, host, reg_funcname, init_funcname, num_const_funcna cap.comment("Create constituent object for suites in ", 2) cap.blank_line() ConstituentVarDict.write_constituent_use_statements(cap, suite_list, 2) - # Conditionally include use statements for dynamic constituent routines - if len(dyn_const_dict) > 0: - cap.comment("Dynamic constituent routines", 2) - for scheme in dyn_const_dict: - cap.write(f"use {scheme}, only: {dyn_const_dict[scheme]}", 2) - # end for - # end if cap.blank_line() cap.comment("Dummy arguments", 2) cap.write(f"type({CONST_PROP_TYPE}), target, intent(in) :: " + \ @@ -501,15 +493,14 @@ def write_host_routines(cap, host, reg_funcname, init_funcname, num_const_funcna cap.write(f"integer{spc} :: index, index_start", 2) cap.write(f"integer{spc} :: field_ind", 2) cap.write(f"type({CONST_PROP_TYPE}), pointer :: const_prop => NULL()", 2) - # Declare dynamic constituent properties variables - for idx, scheme in enumerate(sorted(dyn_const_dict)): - cap.comment(f"dynamic constituent props variable for {scheme}", 2) - cap.write(f"type({CONST_PROP_TYPE}), allocatable :: dyn_const_prop_{idx}(:)", 2) - # end for + cap.write(f"character(len=512) :: stdname", 2) cap.blank_line() cap.write(f"{herrcode} = 0", 2) cap.write("num_consts = size(host_constituents, 1)", 2) cap.write("num_dyn_consts = 0", 2) + cap.write(f"do index = 1, size({dyn_const_names[0]})", 2) + cap.write(f"call {dyn_const_names[0]}(index)%standard_name(stdname)", 3) + cap.write("end do", 2) for suite in suite_list: const_dict = suite.constituent_dictionary() funcname = const_dict.num_consts_funcname() @@ -523,31 +514,6 @@ def write_host_routines(cap, host, reg_funcname, init_funcname, num_const_funcna cap.write("num_consts = num_consts + num_suite_consts", 2) # end for # Check for dynamic constituent routines - if len(dyn_const_dict) > 0: - cap.comment("Add in dynamic constituents", 2) - for idx, scheme in enumerate(sorted(dyn_const_dict)): - cap.write(f"call {dyn_const_dict[scheme]}(dyn_const_prop_{idx}, {obj_err_callstr})", 2) - cap.write(f"if ({herrcode} /= 0) then", 2) - cap.write("return", 3) - cap.write("end if", 2) - cap.write(f"num_dyn_consts = num_dyn_consts + size(dyn_const_prop_{idx})", 2) - # end for - cap.write("num_consts = num_consts + num_dyn_consts", 2) - cap.comment(f"Pack {dyn_const_name} array", 2) - cap.write(f"allocate({dyn_const_name}(num_dyn_consts), stat={herrcode})", 2) - cap.write(f"if ({herrcode} /= 0) then", 2) - cap.write(f"{herrmsg} = 'failed to allocate {dyn_const_name}'", 3) - cap.write("return", 3) - cap.write("end if", 2) - cap.write("index_start = 0", 2) - for idx, scheme in enumerate(sorted(dyn_const_dict)): - cap.write(f"do index = 1, size(dyn_const_prop_{idx}, 1)", 2) - cap.write(f"{dyn_const_name}(index + index_start) = dyn_const_prop_{idx}(index)", 3) - cap.write("end do", 2) - cap.write(f"index_start = index_start + size(dyn_const_prop_{idx}, 1)", 2) - cap.write(f"deallocate(dyn_const_prop_{idx})", 2) - # end for - # end if cap.comment("Initialize constituent data and field object", 2) stmt = f"call {const_obj_name}%initialize_table(num_consts)" cap.write(stmt, 2) @@ -564,10 +530,10 @@ def write_host_routines(cap, host, reg_funcname, init_funcname, num_const_funcna cap.write("end do", 2) cap.blank_line() # Register dynamic constituents - if len(dyn_const_dict) > 0: - cap.comment("Add dynamic constituent properties", 2) - cap.write(f"do index = 1, size({dyn_const_name}, 1)", 2) - cap.write(f"const_prop => {dyn_const_name}(index)", 3) + cap.comment("Add dynamic constituent properties", 2) + for dyn_const in dyn_const_names: + cap.write(f"do index = 1, size({dyn_const}, 1)", 2) + cap.write(f"const_prop => {dyn_const}(index)", 3) stmt = f"call {const_obj_name}%new_field(const_prop, {obj_err_callstr})" cap.write(stmt, 3) cap.write("nullify(const_prop)", 3) @@ -575,7 +541,7 @@ def write_host_routines(cap, host, reg_funcname, init_funcname, num_const_funcna cap.write("return", 4) cap.write("end if", 3) cap.write("end do", 2) - # end if + # end do # Register suite constituents for suite in suite_list: @@ -718,7 +684,12 @@ def write_host_routines(cap, host, reg_funcname, init_funcname, num_const_funcna cap.write(f"{substmt}()", 1) cap.comment("Deallocate dynamic constituent array", 2) cap.blank_line() - cap.write(f"deallocate({dyn_const_name})", 2) + for dyn_const in dyn_const_names: + cap.write(f"if (allocated({dyn_const})) then", 2) + cap.write(f"deallocate({dyn_const})", 3) + cap.write("end if", 2) + cap.write(f"call {const_obj_name}%reset()", 2) + # end if cap.write(f"end {substmt}", 1) # Write constituents routine cap.blank_line() diff --git a/scripts/host_cap.py b/scripts/host_cap.py index 91d91493..9628241b 100644 --- a/scripts/host_cap.py +++ b/scripts/host_cap.py @@ -190,6 +190,13 @@ def dynamic_constituent_array_name(host_model): hstr = f"{host_model.name}_dynamic_constituents" return unique_local_name(hstr, host_model) +############################################################################### +def suite_dynamic_constituent_array_name(host_model, suite): +############################################################################### + """Return the name of the allocatable dynamic constituent properites array""" + hstr = f"{suite}_dynamic_constituents" + return unique_local_name(hstr, host_model) + ############################################################################### def constituent_model_const_stdnames(host_model): ############################################################################### @@ -378,9 +385,12 @@ def add_constituent_vars(cap, host_model, suite_list, run_env): # end if ddt_lib.collect_ddt_fields(const_dict, const_var, run_env, skip_duplicates=True) - # Declare the allocatable dynamic constituents array - dyn_const_name = dynamic_constituent_array_name(host_model) - cap.write(f"type({CONST_PROP_TYPE}), allocatable, target :: {dyn_const_name}(:)", 1) + # Declare the allocatable dynamic constituents array(s) + # One per suite + for suite in suite_list: + dyn_const_name = suite_dynamic_constituent_array_name(host_model, suite.name) + cap.write(f"type({CONST_PROP_TYPE}), allocatable, target :: {dyn_const_name}(:)", 1) + # end if # Declare variable for the constituent standard names array max_csname = max([len(x) for x in const_stdnames]) if const_stdnames else 0 num_const_fields = len(const_stdnames) @@ -441,7 +451,8 @@ def add_constituent_vars(cap, host_model, suite_list, run_env): return const_dict ############################################################################### -def suite_part_call_list(host_model, const_dict, suite_part, subst_loop_vars): +def suite_part_call_list(host_model, const_dict, suite_part, subst_loop_vars, + dyn_const=False): ############################################################################### """Return the controlled call list for . is the constituent dictionary""" @@ -455,6 +466,12 @@ def suite_part_call_list(host_model, const_dict, suite_part, subst_loop_vars): for sp_var in spart_args: stdname = sp_var.get_prop_value('standard_name') sp_lname = sp_var.get_prop_value('local_name') + if sp_var.get_prop_value('type') == 'ccpp_constituent_properties_t': + if dyn_const: + hmvars.append("{}={}".format(sp_lname, sp_lname)) + # end if + continue + # end if var_dicts = [host_model, const_dict] # Figure out which dictionary has the variable for vdict in var_dicts: @@ -547,6 +564,7 @@ def write_host_cap(host_model, api, module_name, output_dir, run_env): # Create a dict of local variables for stage host_local_vars = VarDictionary(f"{host_model.name}_{stage}", run_env) + has_dyn_consts = False # Create part call lists # Look for any loop-variable mismatch for suite in api.suites: @@ -555,6 +573,22 @@ def write_host_cap(host_model, api, module_name, output_dir, run_env): spart_args = spart.call_list.variable_list() for sp_var in spart_args: stdname = sp_var.get_prop_value('standard_name') + # Skip any dynamic constituent objects in register phases + if sp_var.get_prop_value('type') == 'ccpp_constituent_properties_t': + if spart.phase() == 'register': + prop_dict = {'standard_name' : sp_var.get_prop_value('standard_name'), + 'local_name' : sp_var.get_prop_value('local_name'), + 'dimensions' : '(:)', 'units' : 'none', + 'allocatable' : True, 'ddt_type' : 'ccpp_constituent_properties_t'} + newvar = Var(prop_dict, _API_SOURCE, run_env) + host_local_vars.add_variable(newvar, run_env) + has_dyn_consts = True + continue + else: + errmsg = 'ccpp_constituent_properties_t object "{}" not allowed in "{}" phase' + raise CCPPError(errmsg.format(stdname, spart.phase())) + # end if + # end if hvar = const_dict.find_variable(standard_name=stdname, any_scope=True) if hvar is None: @@ -564,6 +598,20 @@ def write_host_cap(host_model, api, module_name, output_dir, run_env): # End for (loop over part variables) # End for (loop of suite parts) # End for (loop over suites) + if has_dyn_consts: + prop_dict = {'standard_name' : 'unused_count', + 'local_name' : 'num_dyn_consts', + 'dimensions' : '()', 'units' : 'count', + 'type' : 'integer'} + newvar = Var(prop_dict, _API_SOURCE, run_env) + host_local_vars.add_variable(newvar, run_env) + prop_dict = {'standard_name' : 'unused_index', + 'local_name' : 'const_index', + 'dimensions' : '()', 'units' : 'none', + 'type': 'integer'} + newvar = Var(prop_dict, _API_SOURCE, run_env) + host_local_vars.add_variable(newvar, run_env) + # end if run_stage = stage == 'run' # All interfaces need the suite name apivars = [_SUITE_NAME_VAR] @@ -616,9 +664,11 @@ def write_host_cap(host_model, api, module_name, output_dir, run_env): var.write_def(cap, 2, host_model) # End for for var in host_local_vars.variable_list(): - var.write_def(cap, 2, host_model) + var.write_def(cap, 2, host_model, + allocatable=var.get_prop_value('allocatable')) # End for cap.write('', 0) + cap.write('character(len=256) :: stdname', 2) # Write out the body clauses errmsg_name, errflg_name = api.get_errinfo_names() # Initialize err variables @@ -648,6 +698,47 @@ def write_host_cap(host_model, api, module_name, output_dir, run_env): cap.write(emsg, 4) cap.write("{errflg} = 1".format(errflg=errflg_name), 4) cap.write("end if", 3) + elif stage == 'register': + spart = suite.phase_group(stage) + dyn_const_array = suite_dynamic_constituent_array_name(host_model, suite.name) + call_str = suite_part_call_list(host_model, const_dict, spart, False, + dyn_const=True) + stmt = "call {}_{}({})" + cap.write(stmt.format(suite.name, stage, call_str), 3) + # Allocate the suite's dynamic constituents array + size_string = "0+" + for var in host_local_vars.variable_list(): + vtype = var.get_prop_value('type') + local_name = var.get_prop_value('local_name') + if vtype == 'ccpp_constituent_properties_t': + size_string += f"size({local_name})+" + # end if + # end for + if not has_dyn_consts: + cap.comment("Suite does not return dynamic constituents; allocate to zero", 3) + # end if + cap.write(f"allocate({dyn_const_array}({size_string[:-1]}))", 3) + if has_dyn_consts: + cap.comment("Pack the suite-level dynamic, run-time constituents array", 3) + cap.write("num_dyn_consts = 0", 3) + for var in host_local_vars.variable_list(): + vtype = var.get_prop_value('type') + local_name = var.get_prop_value('local_name') + if vtype != 'ccpp_constituent_properties_t': + continue + # end if + cap.write(f"do const_index = 1, size({local_name})", 3) + cap.write(f"call {local_name}(1)%standard_name(stdname, errcode=errflg, errmsg=errmsg)", 4) + cap.write(f"{dyn_const_array}(num_dyn_consts + const_index) = {local_name}(const_index)", 4) + cap.write(f"call {dyn_const_array}(num_dyn_consts + const_index)%standard_name(stdname, errcode=errflg, errmsg=errmsg)", 4) + cap.write("end do", 3) + cap.write(f"num_dyn_consts = num_dyn_consts + size({local_name})", 3) + cap.write(f"deallocate({local_name})", 3) + cap.write(f"do const_index = 1, size({dyn_const_array})", 3) + cap.write(f"call {dyn_const_array}(const_index)%standard_name(stdname, errcode=errflg, errmsg=errmsg)", 4) + cap.write("end do", 3) + # end for + else: spart = suite.phase_group(stage) call_str = suite_part_call_list(host_model, const_dict, @@ -675,13 +766,17 @@ def write_host_cap(host_model, api, module_name, output_dir, run_env): cap.write("", 0) const_names_name = constituent_model_const_stdnames(host_model) const_indices_name = constituent_model_const_indices(host_model) + dyn_const_names = list() + for suite in api.suites: + dyn_const_names.append(suite_dynamic_constituent_array_name(host_model, suite.name)) + # end for dyn_const_name = dynamic_constituent_array_name(host_model) ConstituentVarDict.write_host_routines(cap, host_model, reg_name, init_name, numconsts_name, queryconsts_name, copyin_name, copyout_name, cleanup_name, const_obj_name, - dyn_const_name, + dyn_const_names, const_names_name, const_indices_name, const_array_func, @@ -689,7 +784,6 @@ def write_host_cap(host_model, api, module_name, output_dir, run_env): prop_array_func, const_index_func, api.suites, - api.dyn_const_dict, err_vars) # End with return cap_filename diff --git a/scripts/metavar.py b/scripts/metavar.py index e84cd2b7..2c8146ac 100755 --- a/scripts/metavar.py +++ b/scripts/metavar.py @@ -1052,6 +1052,8 @@ def write_def(self, outfile, indent, wdict, allocatable=False, target=False, name = aref.group(1) # end if dims = self.get_dimensions() + #if (stdname == 'dynamic_constituents_for_cld_liq') and not allocatable: + #raise ParseInternalError('hi') if dims: if allocatable or dummy: dimstr = '(:' + ',:'*(len(dims) - 1) + ')' @@ -1896,10 +1898,11 @@ def declare_variables(self, outfile, indent, dummy=False, for standard_name in self.keys(): var = self.find_variable(standard_name=standard_name, any_scope=False) + allocatable = var.get_prop_value('allocatable') if self.include_var_in_list(var, std_vars=std_vars, loop_vars=loop_vars, consts=consts): self[standard_name].write_def(outfile, indent, self, - dummy=dummy) + dummy=dummy, allocatable=allocatable) # end if # end for diff --git a/scripts/parse_tools/parse_checkers.py b/scripts/parse_tools/parse_checkers.py index 1a0d1565..5458b674 100755 --- a/scripts/parse_tools/parse_checkers.py +++ b/scripts/parse_tools/parse_checkers.py @@ -229,7 +229,7 @@ def check_cf_standard_name(test_val, prop_dict, error): FORTRAN_DP_RE = re.compile(r"(?i)double\s*precision") FORTRAN_TYPE_RE = re.compile(r"(?i)type\s*\(\s*("+FORTRAN_ID+r")\s*\)") -_REGISTERED_FORTRAN_DDT_NAMES = list() +_REGISTERED_FORTRAN_DDT_NAMES = ['ccpp_constituent_properties_t'] ######################################################################## diff --git a/scripts/suite_objects.py b/scripts/suite_objects.py index 1056b8dd..b0065016 100755 --- a/scripts/suite_objects.py +++ b/scripts/suite_objects.py @@ -444,12 +444,17 @@ def add_call_list_variable(self, newvar, exists_ok=False, newvar = oldvar.clone(subst_dict, source_name=self.name, source_type=stype, context=self.context) # end if + stdname = newvar.get_prop_value('standard_name') + vtype = newvar.get_prop_value('type') + dimensions = newvar.get_prop_value('dimensions') self.call_list.add_variable(newvar, self.run_env, exists_ok=exists_ok, gen_unique=gen_unique, adjust_intent=True) # We need to make sure that this variable's dimensions are available for vardim in newvar.get_dim_stdnames(include_constants=False): + if vardim == '': + continue dvar = self.find_variable(standard_name=vardim, any_scope=True) if dvar is None: @@ -838,12 +843,26 @@ def match_variable(self, var, run_env): else: vmatch = None # end if - + found_var = False missing_vert = None new_vdims = list() var_vdim = var.has_vertical_dimension(dims=vdims) compat_obj = None + dict_var = None + if var.get_prop_value('type') == 'ccpp_constituent_properties_t': + if self.phase() == 'register': + found_var = True + new_vdims = [':'] + return found_var, dict_var, var_vdim, new_vdims, missing_vert, compat_obj + else: + errmsg = "Variables of type ccpp_constituent_properties_t only allowed in register phase: " + sname = var.get_prop_value('standard_name') + errmsg += ", {}".format(sname) + raise CCPPError(errmsg) + # end if + # end if + # Does this variable exist in the calling tree? dict_var = self.find_variable(source_var=var, any_scope=True) if dict_var is None: diff --git a/src/ccpp_constituent_prop_mod.F90 b/src/ccpp_constituent_prop_mod.F90 index 3370bff4..c4086099 100644 --- a/src/ccpp_constituent_prop_mod.F90 +++ b/src/ccpp_constituent_prop_mod.F90 @@ -26,6 +26,9 @@ module ccpp_constituent_prop_mod integer, parameter :: int_unassigned = -HUGE(1) real(kind_phys), parameter :: kphys_unassigned = HUGE(1.0_kind_phys) +!! \section arg_table_ccpp_constituent_properties_t +!! \htmlinclude ccpp_constituent_properties_t.html +!! type, public, extends(ccpp_hashable_char_t) :: ccpp_constituent_properties_t ! A ccpp_constituent_properties_t object holds relevant metadata ! for a constituent species and provides interfaces to access that data. diff --git a/src/ccpp_constituent_prop_mod.meta b/src/ccpp_constituent_prop_mod.meta index 99cf3145..d6d9a4fc 100644 --- a/src/ccpp_constituent_prop_mod.meta +++ b/src/ccpp_constituent_prop_mod.meta @@ -1,4 +1,15 @@ ######################################################################## + +[ccpp-table-properties] + name = ccpp_constituent_properties_t + type = ddt + +[ccpp-arg-table] + name = ccpp_constituent_properties_t + type = ddt + +######################################################################## + [ccpp-table-properties] name = ccpp_constituent_prop_ptr_t type = ddt diff --git a/test/advection_test/cld_ice.F90 b/test/advection_test/cld_ice.F90 index 0a1e13ee..18e1a7bc 100644 --- a/test/advection_test/cld_ice.F90 +++ b/test/advection_test/cld_ice.F90 @@ -8,15 +8,42 @@ MODULE cld_ice IMPLICIT NONE PRIVATE + PUBLIC :: cld_ice_register PUBLIC :: cld_ice_init PUBLIC :: cld_ice_run PUBLIC :: cld_ice_final - PUBLIC :: cld_ice_dynamic_constituents real(kind_phys), private :: tcld = HUGE(1.0_kind_phys) CONTAINS + !> \section arg_table_cld_ice_register Argument Table + !! \htmlinclude arg_table_cld_ice_register.html + !! + subroutine cld_ice_register(dyn_const_ice, errmsg, errcode) + use ccpp_constituent_prop_mod, only: ccpp_constituent_properties_t + type(ccpp_constituent_properties_t), allocatable, intent(inout) :: dyn_const_ice(:) + integer, intent(out) :: errcode + character(len=512), intent(out) :: errmsg + + errmsg = '' + errcode = 0 + allocate(dyn_const_ice(2), stat=errcode) + if (errcode /= 0) then + errmsg = 'Error allocating dyn_const in cld_ice_dynamic_constituents' + return + end if + call dyn_const_ice(1)%instantiate(std_name='dyn_const1', long_name='dyn const1', & + units='kg kg-1', default_value=0._kind_phys, & + vertical_dim='vertical_layer_dimension', advected=.true., & + min_value=1000._kind_phys, errcode=errcode, errmsg=errmsg) + call dyn_const_ice(2)%instantiate(std_name='dyn_const2_wrt_moist_air', long_name='dyn const2', & + units='kg kg-1', default_value=0._kind_phys, & + vertical_dim='vertical_layer_dimension', advected=.true., & + errcode=errcode, errmsg=errmsg) + + end subroutine cld_ice_register + !> \section arg_table_cld_ice_run Argument Table !! \htmlinclude arg_table_cld_ice_run.html !! @@ -93,31 +120,6 @@ subroutine cld_ice_final(errmsg, errflg) end subroutine cld_ice_final - subroutine cld_ice_dynamic_constituents(dyn_const, errcode, errmsg) - use ccpp_constituent_prop_mod, only: ccpp_constituent_properties_t - type(ccpp_constituent_properties_t), allocatable, intent(out) :: dyn_const(:) - integer, intent(out) :: errcode - character(len=512), intent(out) :: errmsg - - errmsg = '' - errcode = 0 - allocate(dyn_const(2), stat=errcode) - if (errcode /= 0) then - errmsg = 'Error allocating dyn_const in cld_ice_dynamic_constituents' - end if - call dyn_const(1)%instantiate(std_name='dyn_const1', long_name='dyn const1', & - units='kg kg-1', default_value=0._kind_phys, & - vertical_dim='vertical_layer_dimension', advected=.true., & - min_value=1000._kind_phys, errcode=errcode, errmsg=errmsg) - if (errcode /= 0) then - return - end if - call dyn_const(2)%instantiate(std_name='dyn_const2_wrt_moist_air', long_name='dyn const2', & - units='kg kg-1', default_value=0._kind_phys, & - vertical_dim='vertical_layer_dimension', advected=.true., & - errcode=errcode, errmsg=errmsg) - - end subroutine cld_ice_dynamic_constituents !! @} !! @} diff --git a/test/advection_test/cld_ice.meta b/test/advection_test/cld_ice.meta index c27c3c6d..ef3f6373 100644 --- a/test/advection_test/cld_ice.meta +++ b/test/advection_test/cld_ice.meta @@ -2,7 +2,31 @@ [ccpp-table-properties] name = cld_ice type = scheme - dynamic_constituent_routine = cld_ice_dynamic_constituents +[ccpp-arg-table] + name = cld_ice_register + type = scheme +[ dyn_const_ice ] + standard_name = dynamic_constituents_for_cld_ice + units = none + dimensions = (:) + allocatable = True + type = ccpp_constituent_properties_t + intent = inout +[ errmsg ] + standard_name = ccpp_error_message + long_name = Error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=512 + intent = out +[ errcode ] + standard_name = ccpp_error_code + long_name = Error flag for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out [ccpp-arg-table] name = cld_ice_run type = scheme diff --git a/test/advection_test/cld_liq.F90 b/test/advection_test/cld_liq.F90 index 63148c52..15a113b3 100644 --- a/test/advection_test/cld_liq.F90 +++ b/test/advection_test/cld_liq.F90 @@ -4,16 +4,42 @@ MODULE cld_liq USE ccpp_kinds, ONLY: kind_phys + use ccpp_constituent_prop_mod, only: ccpp_constituent_properties_t IMPLICIT NONE PRIVATE + PUBLIC :: cld_liq_register PUBLIC :: cld_liq_init PUBLIC :: cld_liq_run - PUBLIC :: cld_liq_dynamic_constituents CONTAINS + !> \section arg_table_cld_liq_register Argument Table + !! \htmlinclude arg_table_cld_liq_register.html + !! + subroutine cld_liq_register(dyn_const, errmsg, errflg) + type(ccpp_constituent_properties_t), allocatable, intent(inout) :: dyn_const(:) + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg + + character(len=256) :: stdname + + errmsg = '' + errflg = 0 + allocate(dyn_const(1), stat=errflg) + if (errflg /= 0) then + errmsg = 'Error allocating dyn_const in cld_liq_register' + return + end if + call dyn_const(1)%instantiate(std_name="dyn_const3", long_name='dyn const3', & + units='kg kg-1', default_value=1._kind_phys, & + vertical_dim='vertical_layer_dimension', advected=.true., & + errcode=errflg, errmsg=errmsg) + call dyn_const(1)%standard_name(stdname, errcode=errflg, errmsg=errmsg) + + end subroutine cld_liq_register + !> \section arg_table_cld_liq_run Argument Table !! \htmlinclude arg_table_cld_liq_run.html !! @@ -75,24 +101,4 @@ subroutine cld_liq_init(tfreeze, cld_liq_array, tcld, errmsg, errflg) end subroutine cld_liq_init - subroutine cld_liq_dynamic_constituents(dyn_const, errcode, errmsg) - use ccpp_constituent_prop_mod, only: ccpp_constituent_properties_t - type(ccpp_constituent_properties_t), allocatable, intent(out) :: dyn_const(:) - integer, intent(out) :: errcode - character(len=512), intent(out) :: errmsg - - errmsg = '' - errcode = 0 - allocate(dyn_const(1), stat=errcode) - if (errcode /= 0) then - errmsg = 'Error allocating dyn_const in cld_liq_dynamic_constituents' - end if - call dyn_const(1)%instantiate(std_name="dyn_const3", long_name='dyn const3', & - units='kg kg-1', default_value=1._kind_phys, & - vertical_dim='vertical_layer_dimension', advected=.true., & - errcode=errcode, errmsg=errmsg) - - end subroutine cld_liq_dynamic_constituents - - END MODULE cld_liq diff --git a/test/advection_test/cld_liq.meta b/test/advection_test/cld_liq.meta index 1b9373f9..86516c63 100644 --- a/test/advection_test/cld_liq.meta +++ b/test/advection_test/cld_liq.meta @@ -2,7 +2,31 @@ [ccpp-table-properties] name = cld_liq type = scheme - dynamic_constituent_routine = cld_liq_dynamic_constituents +[ccpp-arg-table] + name = cld_liq_register + type = scheme +[ dyn_const ] + standard_name = dynamic_constituents_for_cld_liq + dimensions = (:) + type = ccpp_constituent_properties_t + kind = len=512 + intent = inout + allocatable = true +[ errmsg ] + standard_name = ccpp_error_message + long_name = Error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=512 + intent = out +[ errflg ] + standard_name = ccpp_error_code + long_name = Error flag for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out [ccpp-arg-table] name = cld_liq_run type = scheme diff --git a/test/advection_test/run_test b/test/advection_test/run_test index 1d9a6d44..d83bda6a 100755 --- a/test/advection_test/run_test +++ b/test/advection_test/run_test @@ -127,11 +127,12 @@ ccpp_files="${utility_files},${host_files},${suite_files}" process_list="" module_list="cld_ice,cld_liq" dependencies="" -dyn_const_routines="cld_ice_dynamic_constituents,cld_liq_dynamic_constituents" suite_list="cld_suite" required_vars="ccpp_error_code,ccpp_error_message" required_vars="${required_vars},cloud_ice_dry_mixing_ratio" required_vars="${required_vars},cloud_liquid_dry_mixing_ratio" +required_vars="${required_vars},dynamic_constituents_for_cld_ice" +required_vars="${required_vars},dynamic_constituents_for_cld_liq" required_vars="${required_vars},horizontal_dimension" required_vars="${required_vars},horizontal_loop_begin" required_vars="${required_vars},horizontal_loop_end" @@ -142,6 +143,8 @@ required_vars="${required_vars},vertical_layer_dimension" required_vars="${required_vars},water_temperature_at_freezing" required_vars="${required_vars},water_vapor_specific_humidity" input_vars="cloud_ice_dry_mixing_ratio,cloud_liquid_dry_mixing_ratio" +input_vars="${input_vars},dynamic_constituents_for_cld_ice" +input_vars="${input_vars},dynamic_constituents_for_cld_liq" input_vars="${input_vars},horizontal_dimension" input_vars="${input_vars},horizontal_loop_begin" input_vars="${input_vars},horizontal_loop_end" @@ -153,6 +156,8 @@ input_vars="${input_vars},water_vapor_specific_humidity" output_vars="ccpp_error_code,ccpp_error_message" output_vars="${output_vars},cloud_ice_dry_mixing_ratio" output_vars="${output_vars},cloud_liquid_dry_mixing_ratio" +output_vars="${output_vars},dynamic_constituents_for_cld_ice" +output_vars="${output_vars},dynamic_constituents_for_cld_liq" output_vars="${output_vars},temperature" output_vars="${output_vars},water_vapor_specific_humidity" @@ -220,7 +225,6 @@ echo -e "\nChecking lists from command line" check_datatable ${report_prog} ${datafile} "--process-list" "${process_list}" check_datatable ${report_prog} ${datafile} "--module-list" ${module_list} check_datatable ${report_prog} ${datafile} "--dependencies" "${dependencies}" -check_datatable ${report_prog} ${datafile} "--dyn-const-routines" "${dyn_const_routines}" check_datatable ${report_prog} ${datafile} "--suite-list" ${suite_list} \ --sep ";" echo -e "\nChecking variables from command line" diff --git a/test/advection_test/test_host.F90 b/test/advection_test/test_host.F90 index fe1f9e0b..ec8cf678 100644 --- a/test/advection_test/test_host.F90 +++ b/test/advection_test/test_host.F90 @@ -231,6 +231,7 @@ subroutine test_host(retval, test_suites) use test_host_ccpp_cap, only: test_host_ccpp_initialize_constituents use test_host_ccpp_cap, only: test_host_ccpp_number_constituents use test_host_ccpp_cap, only: test_host_constituents_array + use test_host_ccpp_cap, only: test_host_ccpp_physics_register use test_host_ccpp_cap, only: test_host_ccpp_physics_initialize use test_host_ccpp_cap, only: test_host_ccpp_physics_timestep_initial use test_host_ccpp_cap, only: test_host_ccpp_physics_run @@ -321,6 +322,18 @@ subroutine test_host(retval, test_suites) errflg_final = -1 ! Notify test script that a failure occurred end if + ! Use the suite information to call the register phase + do sind = 1, num_suites + if (errflg == 0) then + call test_host_ccpp_physics_register( & + test_suites(sind)%suite_name, errmsg, errflg) + if (errflg /= 0) then + write(6, '(4a)') 'ERROR in register of ', & + trim(test_suites(sind)%suite_name), ': ', trim(errmsg) + exit + end if + end if + end do ! Register the constituents to find out what needs advecting ! DO A COUPLE OF TESTS FIRST @@ -358,8 +371,21 @@ subroutine test_host(retval, test_suites) end if ! Now try again but with a compatible constituent - should be ignored when ! the constituents object is created + ! Use the suite information to call the register phase + errflg = 0 call test_host_ccpp_deallocate_dynamic_constituents() deallocate(host_constituents) + do sind = 1, num_suites + if (errflg == 0) then + call test_host_ccpp_physics_register( & + test_suites(sind)%suite_name, errmsg, errflg) + if (errflg /= 0) then + write(6, '(4a)') 'ERROR in register of ', & + trim(test_suites(sind)%suite_name), ': ', trim(errmsg) + exit + end if + end if + end do allocate(host_constituents(2)) call host_constituents(1)%instantiate(std_name="specific_humidity", & long_name="Specific humidity", units="kg kg-1", & @@ -1008,9 +1034,9 @@ program test implicit none character(len=cs), target :: test_parts1(1) - character(len=cm), target :: test_invars1(7) - character(len=cm), target :: test_outvars1(6) - character(len=cm), target :: test_reqvars1(9) + character(len=cm), target :: test_invars1(9) + character(len=cm), target :: test_outvars1(8) + character(len=cm), target :: test_reqvars1(11) type(suite_info) :: test_suites(1) logical :: run_okay @@ -1019,6 +1045,8 @@ program test test_invars1 = (/ & 'cloud_ice_dry_mixing_ratio ', & 'cloud_liquid_dry_mixing_ratio ', & + 'dynamic_constituents_for_cld_liq ', & + 'dynamic_constituents_for_cld_ice ', & 'surface_air_pressure ', & 'temperature ', & 'time_step_for_physics ', & @@ -1030,6 +1058,8 @@ program test 'temperature ', & 'water_vapor_specific_humidity ', & 'cloud_liquid_dry_mixing_ratio ', & + 'dynamic_constituents_for_cld_liq ', & + 'dynamic_constituents_for_cld_ice ', & 'cloud_ice_dry_mixing_ratio ' /) test_reqvars1 = (/ & 'surface_air_pressure ', & @@ -1037,6 +1067,8 @@ program test 'time_step_for_physics ', & 'cloud_liquid_dry_mixing_ratio ', & 'cloud_ice_dry_mixing_ratio ', & + 'dynamic_constituents_for_cld_liq ', & + 'dynamic_constituents_for_cld_ice ', & 'water_temperature_at_freezing ', & 'water_vapor_specific_humidity ', & 'ccpp_error_message ', & diff --git a/test/advection_test/test_reports.py b/test/advection_test/test_reports.py index 1a34462a..3278dad8 100644 --- a/test/advection_test/test_reports.py +++ b/test/advection_test/test_reports.py @@ -74,6 +74,8 @@ def usage(errmsg=None): "water_vapor_specific_humidity", "cloud_ice_dry_mixing_ratio", "cloud_liquid_dry_mixing_ratio", + "dynamic_constituents_for_cld_ice", + "dynamic_constituents_for_cld_liq", # Added by --debug option "horizontal_dimension", "vertical_layer_dimension"] @@ -83,13 +85,17 @@ def usage(errmsg=None): "water_vapor_specific_humidity", "cloud_ice_dry_mixing_ratio", "cloud_liquid_dry_mixing_ratio", + "dynamic_constituents_for_cld_ice", + "dynamic_constituents_for_cld_liq", # Added by --debug option "horizontal_dimension", "vertical_layer_dimension"] _OUTPUT_VARS_CLD = ["ccpp_error_code", "ccpp_error_message", "water_vapor_specific_humidity", "temperature", "cloud_ice_dry_mixing_ratio", - "cloud_liquid_dry_mixing_ratio"] + "cloud_liquid_dry_mixing_ratio", + "dynamic_constituents_for_cld_ice", + "dynamic_constituents_for_cld_liq"] def fields_string(field_type, field_list, sep): """Create an error string for field(s), . @@ -155,8 +161,6 @@ def check_datatable(database, report_type, check_list, sep=','): _MODULE_LIST) NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("suite_list"), _SUITE_LIST) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("dyn_const_routines"), - _DYN_CONST_ROUTINES) print("\nChecking variables for CLD suite from python") NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("required_variables", value="cld_suite"), From 6a18120382b3dedf9fa4b9f4d1beca5f98f3209b Mon Sep 17 00:00:00 2001 From: Courtney Peverley Date: Sun, 4 Aug 2024 21:21:45 -0600 Subject: [PATCH 2/7] capgen test passes --- scripts/ccpp_suite.py | 9 +++++++-- scripts/constituents.py | 4 ---- scripts/metavar.py | 5 +---- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/scripts/ccpp_suite.py b/scripts/ccpp_suite.py index f9e4ff35..593759f5 100644 --- a/scripts/ccpp_suite.py +++ b/scripts/ccpp_suite.py @@ -566,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) diff --git a/scripts/constituents.py b/scripts/constituents.py index b7f8bf26..9225061f 100644 --- a/scripts/constituents.py +++ b/scripts/constituents.py @@ -493,14 +493,10 @@ def write_host_routines(cap, host, reg_funcname, init_funcname, num_const_funcna cap.write(f"integer{spc} :: index, index_start", 2) cap.write(f"integer{spc} :: field_ind", 2) cap.write(f"type({CONST_PROP_TYPE}), pointer :: const_prop => NULL()", 2) - cap.write(f"character(len=512) :: stdname", 2) cap.blank_line() cap.write(f"{herrcode} = 0", 2) cap.write("num_consts = size(host_constituents, 1)", 2) cap.write("num_dyn_consts = 0", 2) - cap.write(f"do index = 1, size({dyn_const_names[0]})", 2) - cap.write(f"call {dyn_const_names[0]}(index)%standard_name(stdname)", 3) - cap.write("end do", 2) for suite in suite_list: const_dict = suite.constituent_dictionary() funcname = const_dict.num_consts_funcname() diff --git a/scripts/metavar.py b/scripts/metavar.py index 2c8146ac..e84cd2b7 100755 --- a/scripts/metavar.py +++ b/scripts/metavar.py @@ -1052,8 +1052,6 @@ def write_def(self, outfile, indent, wdict, allocatable=False, target=False, name = aref.group(1) # end if dims = self.get_dimensions() - #if (stdname == 'dynamic_constituents_for_cld_liq') and not allocatable: - #raise ParseInternalError('hi') if dims: if allocatable or dummy: dimstr = '(:' + ',:'*(len(dims) - 1) + ')' @@ -1898,11 +1896,10 @@ def declare_variables(self, outfile, indent, dummy=False, for standard_name in self.keys(): var = self.find_variable(standard_name=standard_name, any_scope=False) - allocatable = var.get_prop_value('allocatable') if self.include_var_in_list(var, std_vars=std_vars, loop_vars=loop_vars, consts=consts): self[standard_name].write_def(outfile, indent, self, - dummy=dummy, allocatable=allocatable) + dummy=dummy) # end if # end for From 3e5658bd085755887015a51116c9470f7d2972ba Mon Sep 17 00:00:00 2001 From: Courtney Peverley Date: Mon, 5 Aug 2024 11:35:36 -0600 Subject: [PATCH 3/7] code cleanup and unit test fixes --- scripts/ccpp_capgen.py | 51 +-------- scripts/ccpp_datafile.py | 65 ----------- scripts/ccpp_suite.py | 10 +- scripts/constituents.py | 3 - scripts/host_cap.py | 8 -- scripts/metadata_table.py | 11 +- scripts/parse_tools/parse_checkers.py | 2 +- test/capgen_test/run_test | 2 + test/capgen_test/temp_adjust.F90 | 22 ++++ test/capgen_test/temp_adjust.meta | 24 ++++ test/capgen_test/test_host.F90 | 10 ++ test/capgen_test/test_host_mod.F90 | 1 + test/capgen_test/test_host_mod.meta | 8 +- test/capgen_test/test_reports.py | 1 + test/unit_tests/sample_files/test_host.meta | 1 - .../duplicate_dyn_const.F90 | 96 ---------------- .../duplicate_dyn_const.meta | 104 ------------------ .../dyn_const_not_present.F90 | 75 ------------- .../dyn_const_not_present.meta | 104 ------------------ .../dyn_const_not_present_nested.F90 | 100 ----------------- .../dyn_const_not_present_nested.meta | 104 ------------------ .../sample_scheme_files/temp_adjust.F90 | 42 +++---- .../sample_scheme_files/temp_adjust.meta | 33 +++++- test/unit_tests/test_metadata_scheme_file.py | 43 +------- test/unit_tests/test_metadata_table.py | 3 - 25 files changed, 131 insertions(+), 792 deletions(-) delete mode 100644 test/unit_tests/sample_scheme_files/duplicate_dyn_const.F90 delete mode 100644 test/unit_tests/sample_scheme_files/duplicate_dyn_const.meta delete mode 100644 test/unit_tests/sample_scheme_files/dyn_const_not_present.F90 delete mode 100644 test/unit_tests/sample_scheme_files/dyn_const_not_present.meta delete mode 100644 test/unit_tests/sample_scheme_files/dyn_const_not_present_nested.F90 delete mode 100644 test/unit_tests/sample_scheme_files/dyn_const_not_present_nested.meta diff --git a/scripts/ccpp_capgen.py b/scripts/ccpp_capgen.py index b16998f3..2aed12a7 100755 --- a/scripts/ccpp_capgen.py +++ b/scripts/ccpp_capgen.py @@ -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 against the code in the associated Fortran file, . @@ -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 ############################################################################### @@ -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: @@ -594,21 +576,6 @@ def parse_scheme_files(scheme_filenames, run_env, skip_ddt_check=False): # 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 @@ -674,24 +641,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: @@ -722,7 +677,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 diff --git a/scripts/ccpp_datafile.py b/scripts/ccpp_datafile.py index 20dee70d..6bb5e537 100755 --- a/scripts/ccpp_datafile.py +++ b/scripts/ccpp_datafile.py @@ -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, @@ -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 @@ -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("" \ - "dyn_const_get" \ - "dyn_const_2" \ - "") - >>> _retrieve_dyn_const_routines(table) - ['dyn_const_2', 'dyn_const_get'] - - # Test no dynamic constituent routines - >>> table = ET.fromstring("" \ - "") - >>> _retrieve_dyn_const_routines(table) - [] - - # Test missing dynamic constituent routines tag - >>> table = ET.fromstring("") - >>> _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): ############################################################################### @@ -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"): @@ -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 that lists all the constituent routines - for the suite - >>> file_entry = ET.fromstring("") - >>> _add_dyn_const_routine(file_entry, 'test_dyn_const', 'test_scheme') - >>> table_entry_pretty_print(file_entry, 0) - '\\n \\n \\n test_dyn_const\\n \\n\\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): ############################################################################### @@ -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) diff --git a/scripts/ccpp_suite.py b/scripts/ccpp_suite.py index 593759f5..b2d4c36e 100644 --- a/scripts/ccpp_suite.py +++ b/scripts/ccpp_suite.py @@ -626,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. is the list of Suite Definition Files to be parsed for data needed by the CCPP cap. @@ -635,14 +635,11 @@ def __init__(self, sdfs, host_model, scheme_headers, run_env, dyn_const_dict={}) is the list of parsed physics scheme metadata files. Every scheme referenced by an SDF in MUST be in this list, however, unused schemes are allowed. - is the dictionary (key = scheme name) of dynamic - constituent routine names 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 @@ -1198,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: diff --git a/scripts/constituents.py b/scripts/constituents.py index 9225061f..3764b4d8 100644 --- a/scripts/constituents.py +++ b/scripts/constituents.py @@ -489,14 +489,12 @@ def write_host_routines(cap, host, reg_funcname, init_funcname, num_const_funcna spc = ' '*37 cap.write(f"integer{spc} :: num_suite_consts", 2) cap.write(f"integer{spc} :: num_consts", 2) - cap.write(f"integer{spc} :: num_dyn_consts", 2) cap.write(f"integer{spc} :: index, index_start", 2) cap.write(f"integer{spc} :: field_ind", 2) cap.write(f"type({CONST_PROP_TYPE}), pointer :: const_prop => NULL()", 2) cap.blank_line() cap.write(f"{herrcode} = 0", 2) cap.write("num_consts = size(host_constituents, 1)", 2) - cap.write("num_dyn_consts = 0", 2) for suite in suite_list: const_dict = suite.constituent_dictionary() funcname = const_dict.num_consts_funcname() @@ -509,7 +507,6 @@ def write_host_routines(cap, host, reg_funcname, init_funcname, num_const_funcna cap.write("end if", 2) cap.write("num_consts = num_consts + num_suite_consts", 2) # end for - # Check for dynamic constituent routines cap.comment("Initialize constituent data and field object", 2) stmt = f"call {const_obj_name}%initialize_table(num_consts)" cap.write(stmt, 2) diff --git a/scripts/host_cap.py b/scripts/host_cap.py index 9628241b..f1bbef71 100644 --- a/scripts/host_cap.py +++ b/scripts/host_cap.py @@ -183,13 +183,6 @@ def constituent_model_object_name(host_model): # end if return hvar.get_prop_value('local_name') -############################################################################### -def dynamic_constituent_array_name(host_model): -############################################################################### - """Return the name of the allocatable dynamic constituent properites array""" - hstr = f"{host_model.name}_dynamic_constituents" - return unique_local_name(hstr, host_model) - ############################################################################### def suite_dynamic_constituent_array_name(host_model, suite): ############################################################################### @@ -770,7 +763,6 @@ def write_host_cap(host_model, api, module_name, output_dir, run_env): for suite in api.suites: dyn_const_names.append(suite_dynamic_constituent_array_name(host_model, suite.name)) # end for - dyn_const_name = dynamic_constituent_array_name(host_model) ConstituentVarDict.write_host_routines(cap, host_model, reg_name, init_name, numconsts_name, queryconsts_name, copyin_name, copyout_name, diff --git a/scripts/metadata_table.py b/scripts/metadata_table.py index c05fa5b4..942f8d81 100755 --- a/scripts/metadata_table.py +++ b/scripts/metadata_table.py @@ -272,7 +272,7 @@ class MetadataTable(): __table_start = re.compile(r"(?i)\s*\[\s*ccpp-table-properties\s*\]") def __init__(self, run_env, table_name_in=None, table_type_in=None, - dependencies=None, relative_path=None, dyn_const_routine=None, + dependencies=None, relative_path=None, known_ddts=None, var_dict=None, module=None, parse_object=None, skip_ddt_check=False): """Initialize a MetadataTable, either with a name, , and @@ -286,7 +286,6 @@ def __init__(self, run_env, table_name_in=None, table_type_in=None, self.__pobj = parse_object self.__dependencies = dependencies self.__relative_path = relative_path - self.__dyn_const_routine = dyn_const_routine self.__sections = [] self.__run_env = run_env if parse_object is None: @@ -408,8 +407,6 @@ def __init_from_file(self, known_ddts, run_env, skip_ddt_check=False): # end if elif key == 'relative_path': self.__relative_path = value - elif key == 'dynamic_constituent_routine': - self.__dyn_const_routine = value else: tok_type = "metadata table start property" self.__pobj.add_syntax_err(tok_type, token=value) @@ -491,12 +488,6 @@ def relative_path(self): """Return the relative path for the table's dependencies""" return self.__relative_path - @property - def dyn_const_routine(self): - """Return the name of the routine that will dynamically return - an array of constituent properties""" - return self.__dyn_const_routine - @property def run_env(self): """Return this table's CCPPFrameworkEnv object""" diff --git a/scripts/parse_tools/parse_checkers.py b/scripts/parse_tools/parse_checkers.py index 5458b674..469bf1d0 100755 --- a/scripts/parse_tools/parse_checkers.py +++ b/scripts/parse_tools/parse_checkers.py @@ -229,7 +229,7 @@ def check_cf_standard_name(test_val, prop_dict, error): FORTRAN_DP_RE = re.compile(r"(?i)double\s*precision") FORTRAN_TYPE_RE = re.compile(r"(?i)type\s*\(\s*("+FORTRAN_ID+r")\s*\)") -_REGISTERED_FORTRAN_DDT_NAMES = ['ccpp_constituent_properties_t'] +_REGISTERED_FORTRAN_DDT_NAMES = [] ######################################################################## diff --git a/test/capgen_test/run_test b/test/capgen_test/run_test index 3d21e2c2..0f826c69 100755 --- a/test/capgen_test/run_test +++ b/test/capgen_test/run_test @@ -147,6 +147,7 @@ output_vars_ddt="ccpp_error_code,ccpp_error_message" output_vars_ddt="${output_vars_ddt},model_times,number_of_model_times" required_vars_temp="ccpp_error_code,ccpp_error_message" required_vars_temp="${required_vars_temp},coefficients_for_interpolation" +required_vars_temp="${required_vars_temp},configuration_variable" required_vars_temp="${required_vars_temp},horizontal_dimension" required_vars_temp="${required_vars_temp},horizontal_loop_begin" required_vars_temp="${required_vars_temp},horizontal_loop_end" @@ -161,6 +162,7 @@ required_vars_temp="${required_vars_temp},vertical_interface_dimension" required_vars_temp="${required_vars_temp},vertical_layer_dimension" required_vars_temp="${required_vars_temp},water_vapor_specific_humidity" input_vars_temp="coefficients_for_interpolation" +input_vars_temp="${input_vars_temp},configuration_variable" input_vars_temp="${input_vars_temp},horizontal_dimension" input_vars_temp="${input_vars_temp},horizontal_loop_begin" input_vars_temp="${input_vars_temp},horizontal_loop_end" diff --git a/test/capgen_test/temp_adjust.F90 b/test/capgen_test/temp_adjust.F90 index 3c6b24f0..e9733786 100644 --- a/test/capgen_test/temp_adjust.F90 +++ b/test/capgen_test/temp_adjust.F90 @@ -8,12 +8,29 @@ MODULE temp_adjust IMPLICIT NONE PRIVATE + PUBLIC :: temp_adjust_register PUBLIC :: temp_adjust_init PUBLIC :: temp_adjust_run PUBLIC :: temp_adjust_finalize + logical :: module_level_config = .false. + CONTAINS + !> \section arg_table_temp_adjust_register Argument Table + !! \htmlinclude arg_table_temp_adjust_register.hml + !! + subroutine temp_adjust_register(config_var, errmsg, errflg) + logical, intent(in) :: config_var + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg + + module_level_config = config_var + errflg = 0 + errmsg = '' + + end subroutine temp_adjust_register + !> \section arg_table_temp_adjust_run Argument Table !! \htmlinclude arg_table_temp_adjust_run.html !! @@ -40,6 +57,11 @@ subroutine temp_adjust_run(foo, timestep, temp_prev, temp_layer, qv, ps, & errmsg = '' errflg = 0 + if (.not. module_level_config) then + ! do nothing + return + end if + do col_index = 1, foo temp_layer(col_index) = temp_layer(col_index) + temp_prev(col_index) if (present(qv)) qv(col_index) = qv(col_index) + 1.0_kind_phys diff --git a/test/capgen_test/temp_adjust.meta b/test/capgen_test/temp_adjust.meta index 420e9112..e3006508 100644 --- a/test/capgen_test/temp_adjust.meta +++ b/test/capgen_test/temp_adjust.meta @@ -3,6 +3,30 @@ type = scheme dependencies = qux.F90 relative_path = adjust +[ccpp-arg-table] + name = temp_adjust_register + type = scheme +[ config_var ] + standard_name = configuration_variable + type = logical + units = none + dimensions = () + intent = in +[ errmsg ] + standard_name = ccpp_error_message + long_name = Error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=512 + intent = out +[ errflg ] + standard_name = ccpp_error_code + long_name = Error flag for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out [ccpp-arg-table] name = temp_adjust_run type = scheme diff --git a/test/capgen_test/test_host.F90 b/test/capgen_test/test_host.F90 index ec352ae6..1958db99 100644 --- a/test/capgen_test/test_host.F90 +++ b/test/capgen_test/test_host.F90 @@ -187,6 +187,7 @@ end function check_suite subroutine test_host(retval, test_suites) use test_host_mod, only: ncols, num_time_steps + use test_host_ccpp_cap, only: test_host_ccpp_physics_register use test_host_ccpp_cap, only: test_host_ccpp_physics_initialize use test_host_ccpp_cap, only: test_host_ccpp_physics_timestep_initial use test_host_ccpp_cap, only: test_host_ccpp_physics_run @@ -237,6 +238,15 @@ subroutine test_host(retval, test_suites) return end if + ! Use the suite information to call the register phase + do sind = 1, num_suites + call test_host_ccpp_physics_register(test_suites(sind)%suite_name, & + errmsg, errflg) + if (errflg /= 0) then + write(6, '(4a)') 'ERROR in register of ', & + trim(test_suites(sind)%suite_name), ': ', trim(errmsg) + end if + end do ! Use the suite information to setup the run do sind = 1, num_suites call test_host_ccpp_physics_initialize(test_suites(sind)%suite_name, & diff --git a/test/capgen_test/test_host_mod.F90 b/test/capgen_test/test_host_mod.F90 index 43be333a..2ce1fbd6 100644 --- a/test/capgen_test/test_host_mod.F90 +++ b/test/capgen_test/test_host_mod.F90 @@ -15,6 +15,7 @@ module test_host_mod integer, parameter :: pcnst = 2 integer, parameter :: DiagDimStart = 2 integer, parameter :: index_qv = 1 + logical, parameter :: config_var = .true. real(kind_phys), allocatable :: temp_midpoints(:,:) real(kind_phys) :: temp_interfaces(ncols, pverP) real(kind_phys) :: coeffs(ncols) diff --git a/test/capgen_test/test_host_mod.meta b/test/capgen_test/test_host_mod.meta index a450ee67..ae0abd05 100644 --- a/test/capgen_test/test_host_mod.meta +++ b/test/capgen_test/test_host_mod.meta @@ -10,6 +10,12 @@ type = integer protected = True dimensions = () +[ config_var ] + standard_name = configuration_variable + units = none + type = logical + protected = True + dimensions = () [ ncols] standard_name = horizontal_dimension units = count @@ -95,4 +101,4 @@ long_name = coefficients for interpolation units = none dimensions = (horizontal_dimension) - type = real | kind = kind_phys \ No newline at end of file + type = real | kind = kind_phys diff --git a/test/capgen_test/test_reports.py b/test/capgen_test/test_reports.py index c9fc452d..8061102a 100644 --- a/test/capgen_test/test_reports.py +++ b/test/capgen_test/test_reports.py @@ -80,6 +80,7 @@ def usage(errmsg=None): _PROT_VARS_TEMP = ["horizontal_loop_begin", "horizontal_loop_end", "horizontal_dimension", "vertical_layer_dimension", "number_of_tracers", + "configuration_variable", # Added for --debug "index_of_water_vapor_specific_humidity", "vertical_interface_dimension"] diff --git a/test/unit_tests/sample_files/test_host.meta b/test/unit_tests/sample_files/test_host.meta index b3bbc001..f618f871 100644 --- a/test/unit_tests/sample_files/test_host.meta +++ b/test/unit_tests/sample_files/test_host.meta @@ -2,7 +2,6 @@ name = test_host type = host dependencies = - dynamic_constituent_routine = dyn_consts ######################################################################## [ccpp-arg-table] diff --git a/test/unit_tests/sample_scheme_files/duplicate_dyn_const.F90 b/test/unit_tests/sample_scheme_files/duplicate_dyn_const.F90 deleted file mode 100644 index 2eb43a89..00000000 --- a/test/unit_tests/sample_scheme_files/duplicate_dyn_const.F90 +++ /dev/null @@ -1,96 +0,0 @@ -! Test parameterization with a dynamic constituents routine with the same name as another parameterization's -! - -MODULE duplicate_dyn_const - - USE ccpp_kinds, ONLY: kind_phys - - IMPLICIT NONE - PRIVATE - - PUBLIC :: duplicate_dyn_const_init - PUBLIC :: duplicate_dyn_const_run - PUBLIC :: duplicate_dyn_const_finalize - PUBLIC :: dyn_consts - -CONTAINS - - !> \section arg_table_duplicate_dyn_const_run Argument Table - !! \htmlinclude arg_table_duplicate_dyn_const_run.html - !! - subroutine duplicate_dyn_const_run(foo, timestep, temp_prev, temp_layer, qv, ps, & - errmsg, errflg) - - integer, intent(in) :: foo - real(kind_phys), intent(in) :: timestep - real(kind_phys), intent(inout) :: qv(:) - real(kind_phys), intent(inout) :: ps(:) - REAL(kind_phys), intent(in) :: temp_prev(:) - REAL(kind_phys), intent(inout) :: temp_layer(foo) - character(len=512), intent(out) :: errmsg - integer, intent(out) :: errflg - !---------------------------------------------------------------- - - integer :: col_index - - errmsg = '' - errflg = 0 - - do col_index = 1, foo - temp_layer(col_index) = temp_layer(col_index) + temp_prev(col_index) - qv(col_index) = qv(col_index) + 1.0_kind_phys - end do - - END SUBROUTINE duplicate_dyn_const_run - - !> \section arg_table_duplicate_dyn_const_init Argument Table - !! \htmlinclude arg_table_duplicate_dyn_const_init.html - !! - subroutine duplicate_dyn_const_init (errmsg, errflg) - - character(len=512), intent(out) :: errmsg - integer, intent(out) :: errflg - - ! This routine currently does nothing - - errmsg = '' - errflg = 0 - - end subroutine duplicate_dyn_const_init - - !> \section arg_table_duplicate_dyn_const_finalize Argument Table - !! \htmlinclude arg_table_duplicate_dyn_const_finalize.html - !! - subroutine duplicate_dyn_const_finalize (errmsg, errflg) - - character(len=512), intent(out) :: errmsg - integer, intent(out) :: errflg - - ! This routine currently does nothing - - errmsg = '' - errflg = 0 - - end subroutine duplicate_dyn_const_finalize - - subroutine dyn_consts(dyn_const, errcode, errmsg) - use ccpp_constituent_prop_mod, only: ccpp_constituent_properties_t - type(ccpp_constituent_properties_t), allocatable, intent(out) :: dyn_const(:) - integer, intent(out) :: errcode - character(len=512), intent(out) :: errmsg - - errmsg = '' - errcode = 0 - allocate(dyn_const(1), stat=errcode) - if (errcode /= 0) then - errmsg = 'Error allocating dyn_const in dyn_consts' - end if - call dyn_const(1)%instantiate(std_name="dyn_const1", long_name='dyn const1', & - units='kg kg-1', default_value=1._kind_phys, & - vertical_dim='vertical_layer_dimension', advected=.true., & - errcode=errcode, errmsg=errmsg) - - end subroutine dyn_consts - - -END MODULE duplicate_dyn_const diff --git a/test/unit_tests/sample_scheme_files/duplicate_dyn_const.meta b/test/unit_tests/sample_scheme_files/duplicate_dyn_const.meta deleted file mode 100644 index f369f8b2..00000000 --- a/test/unit_tests/sample_scheme_files/duplicate_dyn_const.meta +++ /dev/null @@ -1,104 +0,0 @@ -[ccpp-table-properties] - name = duplicate_dyn_const - type = scheme - dynamic_constituent_routine = dyn_consts - -######################################################################## -[ccpp-arg-table] - name = duplicate_dyn_const_run - type = scheme -[ foo ] - standard_name = horizontal_loop_extent - type = integer - units = count - dimensions = () - intent = in -[ timestep ] - standard_name = time_step_for_physics - long_name = time step - units = s - dimensions = () - type = real - kind = kind_phys - intent = in -[ temp_prev ] - standard_name = potential_temperature_at_previous_timestep - units = K - dimensions = (horizontal_loop_extent) - type = real - kind = kind_phys - intent = in -[ temp_layer ] - standard_name = potential_temperature - units = K - dimensions = (horizontal_loop_extent) - type = real - kind = kind_phys - intent = inout -[ qv ] - standard_name = water_vapor_specific_humidity - units = kg kg-1 - dimensions = (horizontal_loop_extent) - type = real - kind = kind_phys - advected = true - intent = inout -[ ps ] - standard_name = surface_air_pressure - state_variable = true - type = real - kind = kind_phys - units = Pa - dimensions = (horizontal_loop_extent) - intent = inout -[ errmsg ] - standard_name = ccpp_error_message - long_name = Error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=512 - intent = out -[ errflg ] - standard_name = ccpp_error_code - long_name = Error flag for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out -[ccpp-arg-table] - name = duplicate_dyn_const_init - type = scheme -[ errmsg ] - standard_name = ccpp_error_message - long_name = Error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=512 - intent = out -[ errflg ] - standard_name = ccpp_error_code - long_name = Error flag for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out -[ccpp-arg-table] - name = duplicate_dyn_const_finalize - type = scheme -[ errmsg ] - standard_name = ccpp_error_message - long_name = Error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=512 - intent = out -[ errflg ] - standard_name = ccpp_error_code - long_name = Error flag for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out diff --git a/test/unit_tests/sample_scheme_files/dyn_const_not_present.F90 b/test/unit_tests/sample_scheme_files/dyn_const_not_present.F90 deleted file mode 100644 index 615f0467..00000000 --- a/test/unit_tests/sample_scheme_files/dyn_const_not_present.F90 +++ /dev/null @@ -1,75 +0,0 @@ -! Test parameterization that is missing the specified dynamic constituents routine -! - -MODULE temp_adjust - - USE ccpp_kinds, ONLY: kind_phys - - IMPLICIT NONE - PRIVATE - - PUBLIC :: temp_adjust_init - PUBLIC :: temp_adjust_run - PUBLIC :: temp_adjust_finalize - -CONTAINS - - !> \section arg_table_temp_adjust_run Argument Table - !! \htmlinclude arg_table_temp_adjust_run.html - !! - subroutine temp_adjust_run(foo, timestep, temp_prev, temp_layer, qv, ps, & - errmsg, errflg) - - integer, intent(in) :: foo - real(kind_phys), intent(in) :: timestep - real(kind_phys), intent(inout) :: qv(:) - real(kind_phys), intent(inout) :: ps(:) - REAL(kind_phys), intent(in) :: temp_prev(:) - REAL(kind_phys), intent(inout) :: temp_layer(foo) - character(len=512), intent(out) :: errmsg - integer, intent(out) :: errflg - !---------------------------------------------------------------- - - integer :: col_index - - errmsg = '' - errflg = 0 - - do col_index = 1, foo - temp_layer(col_index) = temp_layer(col_index) + temp_prev(col_index) - qv(col_index) = qv(col_index) + 1.0_kind_phys - end do - - END SUBROUTINE temp_adjust_run - - !> \section arg_table_temp_adjust_init Argument Table - !! \htmlinclude arg_table_temp_adjust_init.html - !! - subroutine temp_adjust_init (errmsg, errflg) - - character(len=512), intent(out) :: errmsg - integer, intent(out) :: errflg - - ! This routine currently does nothing - - errmsg = '' - errflg = 0 - - end subroutine temp_adjust_init - - !> \section arg_table_temp_adjust_finalize Argument Table - !! \htmlinclude arg_table_temp_adjust_finalize.html - !! - subroutine temp_adjust_finalize (errmsg, errflg) - - character(len=512), intent(out) :: errmsg - integer, intent(out) :: errflg - - ! This routine currently does nothing - - errmsg = '' - errflg = 0 - - end subroutine temp_adjust_finalize - -END MODULE temp_adjust diff --git a/test/unit_tests/sample_scheme_files/dyn_const_not_present.meta b/test/unit_tests/sample_scheme_files/dyn_const_not_present.meta deleted file mode 100644 index 05638ded..00000000 --- a/test/unit_tests/sample_scheme_files/dyn_const_not_present.meta +++ /dev/null @@ -1,104 +0,0 @@ -[ccpp-table-properties] - name = temp_adjust - type = scheme - dynamic_constituent_routine = dyn_consts - -######################################################################## -[ccpp-arg-table] - name = temp_adjust_run - type = scheme -[ foo ] - standard_name = horizontal_loop_extent - type = integer - units = count - dimensions = () - intent = in -[ timestep ] - standard_name = time_step_for_physics - long_name = time step - units = s - dimensions = () - type = real - kind = kind_phys - intent = in -[ temp_prev ] - standard_name = potential_temperature_at_previous_timestep - units = K - dimensions = (horizontal_loop_extent) - type = real - kind = kind_phys - intent = in -[ temp_layer ] - standard_name = potential_temperature - units = K - dimensions = (horizontal_loop_extent) - type = real - kind = kind_phys - intent = inout -[ qv ] - standard_name = water_vapor_specific_humidity - units = kg kg-1 - dimensions = (horizontal_loop_extent) - type = real - kind = kind_phys - advected = true - intent = inout -[ ps ] - standard_name = surface_air_pressure - state_variable = true - type = real - kind = kind_phys - units = Pa - dimensions = (horizontal_loop_extent) - intent = inout -[ errmsg ] - standard_name = ccpp_error_message - long_name = Error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=512 - intent = out -[ errflg ] - standard_name = ccpp_error_code - long_name = Error flag for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out -[ccpp-arg-table] - name = temp_adjust_init - type = scheme -[ errmsg ] - standard_name = ccpp_error_message - long_name = Error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=512 - intent = out -[ errflg ] - standard_name = ccpp_error_code - long_name = Error flag for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out -[ccpp-arg-table] - name = temp_adjust_finalize - type = scheme -[ errmsg ] - standard_name = ccpp_error_message - long_name = Error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=512 - intent = out -[ errflg ] - standard_name = ccpp_error_code - long_name = Error flag for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out diff --git a/test/unit_tests/sample_scheme_files/dyn_const_not_present_nested.F90 b/test/unit_tests/sample_scheme_files/dyn_const_not_present_nested.F90 deleted file mode 100644 index 259d4d66..00000000 --- a/test/unit_tests/sample_scheme_files/dyn_const_not_present_nested.F90 +++ /dev/null @@ -1,100 +0,0 @@ -! Test parameterization with no vertical level -! - -MODULE temp_adjust - - USE ccpp_kinds, ONLY: kind_phys - - IMPLICIT NONE - PRIVATE - - PUBLIC :: temp_adjust_init - PUBLIC :: temp_adjust_run - PUBLIC :: temp_adjust_finalize - PUBLIC :: dyn_consts - -CONTAINS - - !> \section arg_table_temp_adjust_run Argument Table - !! \htmlinclude arg_table_temp_adjust_run.html - !! - subroutine temp_adjust_run(foo, timestep, temp_prev, temp_layer, qv, ps, & - errmsg, errflg) - - integer, intent(in) :: foo - real(kind_phys), intent(in) :: timestep - real(kind_phys), intent(inout) :: qv(:) - real(kind_phys), intent(inout) :: ps(:) - REAL(kind_phys), intent(in) :: temp_prev(:) - REAL(kind_phys), intent(inout) :: temp_layer(foo) - character(len=512), intent(out) :: errmsg - integer, intent(out) :: errflg - !---------------------------------------------------------------- - - integer :: col_index - - errmsg = '' - errflg = 0 - - do col_index = 1, foo - temp_layer(col_index) = temp_layer(col_index) + temp_prev(col_index) - qv(col_index) = qv(col_index) + 1.0_kind_phys - end do - - END SUBROUTINE temp_adjust_run - - !> \section arg_table_temp_adjust_init Argument Table - !! \htmlinclude arg_table_temp_adjust_init.html - !! - subroutine temp_adjust_init (errmsg, errflg) - - character(len=512), intent(out) :: errmsg - integer, intent(out) :: errflg - - ! This routine currently does nothing - - errmsg = '' - errflg = 0 - - end subroutine temp_adjust_init - - !> \section arg_table_temp_adjust_finalize Argument Table - !! \htmlinclude arg_table_temp_adjust_finalize.html - !! - subroutine temp_adjust_finalize (errmsg, errflg) - - character(len=512), intent(out) :: errmsg - integer, intent(out) :: errflg - - ! This routine currently does nothing - - errmsg = '' - errflg = 0 - - end subroutine temp_adjust_finalize - - subroutine some_subroutine() - contains - subroutine dyn_consts(dyn_const, errcode, errmsg) - use ccpp_constituent_prop_mod, only: ccpp_constituent_properties_t - type(ccpp_constituent_properties_t), allocatable, intent(out) :: dyn_const(:) - integer, intent(out) :: errcode - character(len=512), intent(out) :: errmsg - - errmsg = '' - errcode = 0 - allocate(dyn_const(1), stat=errcode) - if (errcode /= 0) then - errmsg = 'Error allocating dyn_const in dyn_consts' - end if - call dyn_const(1)%instantiate(std_name="dyn_const1", long_name='dyn const1', & - units='kg kg-1', default_value=1._kind_phys, & - vertical_dim='vertical_layer_dimension', advected=.true., & - errcode=errcode, errmsg=errmsg) - - end subroutine dyn_consts - - end subroutine some_subroutine - - -END MODULE temp_adjust diff --git a/test/unit_tests/sample_scheme_files/dyn_const_not_present_nested.meta b/test/unit_tests/sample_scheme_files/dyn_const_not_present_nested.meta deleted file mode 100644 index 05638ded..00000000 --- a/test/unit_tests/sample_scheme_files/dyn_const_not_present_nested.meta +++ /dev/null @@ -1,104 +0,0 @@ -[ccpp-table-properties] - name = temp_adjust - type = scheme - dynamic_constituent_routine = dyn_consts - -######################################################################## -[ccpp-arg-table] - name = temp_adjust_run - type = scheme -[ foo ] - standard_name = horizontal_loop_extent - type = integer - units = count - dimensions = () - intent = in -[ timestep ] - standard_name = time_step_for_physics - long_name = time step - units = s - dimensions = () - type = real - kind = kind_phys - intent = in -[ temp_prev ] - standard_name = potential_temperature_at_previous_timestep - units = K - dimensions = (horizontal_loop_extent) - type = real - kind = kind_phys - intent = in -[ temp_layer ] - standard_name = potential_temperature - units = K - dimensions = (horizontal_loop_extent) - type = real - kind = kind_phys - intent = inout -[ qv ] - standard_name = water_vapor_specific_humidity - units = kg kg-1 - dimensions = (horizontal_loop_extent) - type = real - kind = kind_phys - advected = true - intent = inout -[ ps ] - standard_name = surface_air_pressure - state_variable = true - type = real - kind = kind_phys - units = Pa - dimensions = (horizontal_loop_extent) - intent = inout -[ errmsg ] - standard_name = ccpp_error_message - long_name = Error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=512 - intent = out -[ errflg ] - standard_name = ccpp_error_code - long_name = Error flag for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out -[ccpp-arg-table] - name = temp_adjust_init - type = scheme -[ errmsg ] - standard_name = ccpp_error_message - long_name = Error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=512 - intent = out -[ errflg ] - standard_name = ccpp_error_code - long_name = Error flag for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out -[ccpp-arg-table] - name = temp_adjust_finalize - type = scheme -[ errmsg ] - standard_name = ccpp_error_message - long_name = Error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=512 - intent = out -[ errflg ] - standard_name = ccpp_error_code - long_name = Error flag for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out diff --git a/test/unit_tests/sample_scheme_files/temp_adjust.F90 b/test/unit_tests/sample_scheme_files/temp_adjust.F90 index 4b78642d..4db1f2a8 100644 --- a/test/unit_tests/sample_scheme_files/temp_adjust.F90 +++ b/test/unit_tests/sample_scheme_files/temp_adjust.F90 @@ -11,10 +11,30 @@ MODULE temp_adjust PUBLIC :: temp_adjust_init PUBLIC :: temp_adjust_run PUBLIC :: temp_adjust_finalize - PUBLIC :: dyn_consts CONTAINS + !> \section arg_table_temp_adjust_register Argument Table + !! \htmlinclude arg_table_temp_adjust_register.html + !! + subroutine temp_adjust_register(config_var, dyn_const, errmsg, errflg) + logical, intent(in) :: config_var + type(ccpp_constituent_properties_t), allocatable, intent(out) :: dyn_const + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg + + if (.not. config_var) then + return + end if + + allocate(dyn_const(1)) + call dyn_const(1)%instantiate(std_name="dyn_const", long_name='dyn const', & + units='kg kg-1', default_value=1._kind_phys, & + vertical_dim='vertical_layer_dimension', advected=.true., & + errcode=errflg, errmsg=errmsg) + + end subroutine temp_adjust_register + !> \section arg_table_temp_adjust_run Argument Table !! \htmlinclude arg_table_temp_adjust_run.html !! @@ -73,24 +93,4 @@ subroutine temp_adjust_finalize (errmsg, errflg) end subroutine temp_adjust_finalize - subroutine dyn_consts (dyn_const, errcode, errmsg) - use ccpp_constituent_prop_mod, only: ccpp_constituent_properties_t - type(ccpp_constituent_properties_t), allocatable, intent(out) :: dyn_const(:) - integer, intent(out) :: errcode - character(len=512), intent(out) :: errmsg - - errmsg = '' - errcode = 0 - allocate(dyn_const(1), stat=errcode) - if (errcode /= 0) then - errmsg = 'Error allocating dyn_const in dyn_consts' - end if - call dyn_const(1)%instantiate(std_name="dyn_const1", long_name='dyn const1', & - units='kg kg-1', default_value=1._kind_phys, & - vertical_dim='vertical_layer_dimension', advected=.true., & - errcode=errcode, errmsg=errmsg) - - end subroutine dyn_consts - - END MODULE temp_adjust diff --git a/test/unit_tests/sample_scheme_files/temp_adjust.meta b/test/unit_tests/sample_scheme_files/temp_adjust.meta index 063409d6..4b96e316 100644 --- a/test/unit_tests/sample_scheme_files/temp_adjust.meta +++ b/test/unit_tests/sample_scheme_files/temp_adjust.meta @@ -1,9 +1,40 @@ [ccpp-table-properties] name = temp_adjust type = scheme - dynamic_constituent_routine = dyn_consts ######################################################################## +[ccpp-arg-table] + name = temp_adjust_register + type = scheme +[ config_var ] + standard_name = configuration_variable + type = logical + units = none + dimensions = () + intent = in +[ dyn_const ] + standard_name = dynamic_constituents_for_temp_adjust + type = ccpp_constituent_properties_t + units = none + dimensions = () + intent = out + allocatable = True +[ errmsg ] + standard_name = ccpp_error_message + long_name = Error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=512 + intent = out +[ errflg ] + standard_name = ccpp_error_code + long_name = Error flag for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out +######################################################################## [ccpp-arg-table] name = temp_adjust_run type = scheme diff --git a/test/unit_tests/test_metadata_scheme_file.py b/test/unit_tests/test_metadata_scheme_file.py index fb0ce2f4..feab8acb 100644 --- a/test/unit_tests/test_metadata_scheme_file.py +++ b/test/unit_tests/test_metadata_scheme_file.py @@ -35,10 +35,6 @@ - Correctly interpret Fortran with preprocessor logic which affects the subroutine statement and/or the dummy argument statements resulting in incorrect Fortran - - Correctly detect a missing dynamic constituent routine - in Fortran - - Correctly raise an error if there are two dynamic - constituent routines with the same name Assumptions: @@ -98,13 +94,15 @@ def test_good_scheme_file(self): "temp_adjust.meta")] # Exercise scheme_headers, table_dict = parse_scheme_files(scheme_files, - self._run_env) + self._run_env, + skip_ddt_check=True) # Verify size of returned list equals number of scheme headers # in the test file and that header (subroutine) names are - # 'temp_adjust_[init,run,finalize]' - self.assertEqual(len(scheme_headers), 3) + # 'temp_adjust_[register,init,run,finalize]' + self.assertEqual(len(scheme_headers), 4) # Verify header titles titles = [elem.title for elem in scheme_headers] + self.assertTrue('temp_adjust_register' in titles) self.assertTrue('temp_adjust_init' in titles) self.assertTrue('temp_adjust_run' in titles) self.assertTrue('temp_adjust_finalize' in titles) @@ -345,37 +343,6 @@ def test_scheme_ddt_only(self): scheme_headers, table_dict = parse_scheme_files(scheme_files, self._run_env_ccpp) - def test_not_present_dynamic_constituents_routine(self): - scheme_files = [os.path.join(self._sample_files_dir, - "dyn_const_not_present.meta")] - - with self.assertRaises(CCPPError) as context: - _, _ = parse_scheme_files(scheme_files, self._run_env_ccpp) - - emsg = "Dynamic constituent routine dyn_consts not found in fortran" - self.assertTrue(emsg in str(context.exception)) - - def test_not_present_nested_dynamic_constituents_routine(self): - scheme_files = [os.path.join(self._sample_files_dir, - "dyn_const_not_present_nested.meta")] - - with self.assertRaises(CCPPError) as context: - _, _ = parse_scheme_files(scheme_files, self._run_env_ccpp) - - emsg = "Dynamic constituent routine dyn_consts not found in fortran" - self.assertTrue(emsg in str(context.exception)) - - def test_duplicate_dynamic_constituents_routine_name(self): - scheme_files = [os.path.join(self._sample_files_dir, - "temp_adjust.meta"), - os.path.join(self._sample_files_dir, - "duplicate_dyn_const.meta")] - - with self.assertRaises(CCPPError) as context: - _, _ = parse_scheme_files(scheme_files, self._run_env_ccpp) - emsg = "ERROR: Dynamic constituent routine names must be unique." - self.assertTrue(emsg in str(context.exception)) - if __name__ == "__main__": unittest.main() diff --git a/test/unit_tests/test_metadata_table.py b/test/unit_tests/test_metadata_table.py index 08248150..94ed1e67 100755 --- a/test/unit_tests/test_metadata_table.py +++ b/test/unit_tests/test_metadata_table.py @@ -48,7 +48,6 @@ def test_good_host_file(self): #Verify that: # no dependencies is returned as '' # rel_path is returned as None - # dynamic_constituent_routine is returned as 'dyn_consts' # size of returned list equals number of headers in the test file # ccpp-table-properties name is 'test_host' dependencies = result[0].dependencies @@ -57,8 +56,6 @@ def test_good_host_file(self): self.assertEqual(len(dependencies), 0) self.assertIsNone(rel_path) self.assertEqual(len(result), 1) - dyn_const_routine = result[0].dyn_const_routine - self.assertEqual(dyn_const_routine, 'dyn_consts') titles = [elem.table_name for elem in result] self.assertIn('test_host', titles, msg="Header name 'test_host' is expected but not found") From 0a406bd9ad750ff88978372574db288edd063716 Mon Sep 17 00:00:00 2001 From: Courtney Peverley Date: Mon, 5 Aug 2024 11:59:18 -0600 Subject: [PATCH 4/7] switch to output only --- test/advection_test/cld_ice.F90 | 2 +- test/advection_test/cld_ice.meta | 2 +- test/advection_test/cld_liq.F90 | 2 +- test/advection_test/cld_liq.meta | 3 +-- test/advection_test/run_test | 2 -- test/advection_test/test_host.F90 | 4 +--- test/advection_test/test_reports.py | 2 -- 7 files changed, 5 insertions(+), 12 deletions(-) diff --git a/test/advection_test/cld_ice.F90 b/test/advection_test/cld_ice.F90 index 18e1a7bc..ee53529d 100644 --- a/test/advection_test/cld_ice.F90 +++ b/test/advection_test/cld_ice.F90 @@ -22,7 +22,7 @@ MODULE cld_ice !! subroutine cld_ice_register(dyn_const_ice, errmsg, errcode) use ccpp_constituent_prop_mod, only: ccpp_constituent_properties_t - type(ccpp_constituent_properties_t), allocatable, intent(inout) :: dyn_const_ice(:) + type(ccpp_constituent_properties_t), allocatable, intent(out) :: dyn_const_ice(:) integer, intent(out) :: errcode character(len=512), intent(out) :: errmsg diff --git a/test/advection_test/cld_ice.meta b/test/advection_test/cld_ice.meta index ef3f6373..e57d0b08 100644 --- a/test/advection_test/cld_ice.meta +++ b/test/advection_test/cld_ice.meta @@ -11,7 +11,7 @@ dimensions = (:) allocatable = True type = ccpp_constituent_properties_t - intent = inout + intent = out [ errmsg ] standard_name = ccpp_error_message long_name = Error message for error handling in CCPP diff --git a/test/advection_test/cld_liq.F90 b/test/advection_test/cld_liq.F90 index 15a113b3..ec19cb17 100644 --- a/test/advection_test/cld_liq.F90 +++ b/test/advection_test/cld_liq.F90 @@ -19,7 +19,7 @@ MODULE cld_liq !! \htmlinclude arg_table_cld_liq_register.html !! subroutine cld_liq_register(dyn_const, errmsg, errflg) - type(ccpp_constituent_properties_t), allocatable, intent(inout) :: dyn_const(:) + type(ccpp_constituent_properties_t), allocatable, intent(out) :: dyn_const(:) character(len=512), intent(out) :: errmsg integer, intent(out) :: errflg diff --git a/test/advection_test/cld_liq.meta b/test/advection_test/cld_liq.meta index 86516c63..093c13b7 100644 --- a/test/advection_test/cld_liq.meta +++ b/test/advection_test/cld_liq.meta @@ -9,8 +9,7 @@ standard_name = dynamic_constituents_for_cld_liq dimensions = (:) type = ccpp_constituent_properties_t - kind = len=512 - intent = inout + intent = out allocatable = true [ errmsg ] standard_name = ccpp_error_message diff --git a/test/advection_test/run_test b/test/advection_test/run_test index d83bda6a..143c7d7f 100755 --- a/test/advection_test/run_test +++ b/test/advection_test/run_test @@ -143,8 +143,6 @@ required_vars="${required_vars},vertical_layer_dimension" required_vars="${required_vars},water_temperature_at_freezing" required_vars="${required_vars},water_vapor_specific_humidity" input_vars="cloud_ice_dry_mixing_ratio,cloud_liquid_dry_mixing_ratio" -input_vars="${input_vars},dynamic_constituents_for_cld_ice" -input_vars="${input_vars},dynamic_constituents_for_cld_liq" input_vars="${input_vars},horizontal_dimension" input_vars="${input_vars},horizontal_loop_begin" input_vars="${input_vars},horizontal_loop_end" diff --git a/test/advection_test/test_host.F90 b/test/advection_test/test_host.F90 index ec8cf678..5146097b 100644 --- a/test/advection_test/test_host.F90 +++ b/test/advection_test/test_host.F90 @@ -1034,7 +1034,7 @@ program test implicit none character(len=cs), target :: test_parts1(1) - character(len=cm), target :: test_invars1(9) + character(len=cm), target :: test_invars1(7) character(len=cm), target :: test_outvars1(8) character(len=cm), target :: test_reqvars1(11) @@ -1045,8 +1045,6 @@ program test test_invars1 = (/ & 'cloud_ice_dry_mixing_ratio ', & 'cloud_liquid_dry_mixing_ratio ', & - 'dynamic_constituents_for_cld_liq ', & - 'dynamic_constituents_for_cld_ice ', & 'surface_air_pressure ', & 'temperature ', & 'time_step_for_physics ', & diff --git a/test/advection_test/test_reports.py b/test/advection_test/test_reports.py index 3278dad8..2061b796 100644 --- a/test/advection_test/test_reports.py +++ b/test/advection_test/test_reports.py @@ -85,8 +85,6 @@ def usage(errmsg=None): "water_vapor_specific_humidity", "cloud_ice_dry_mixing_ratio", "cloud_liquid_dry_mixing_ratio", - "dynamic_constituents_for_cld_ice", - "dynamic_constituents_for_cld_liq", # Added by --debug option "horizontal_dimension", "vertical_layer_dimension"] From 97b5047b0f25b51963e7526d47475b63ffbc82ca Mon Sep 17 00:00:00 2001 From: Courtney Peverley Date: Mon, 12 Aug 2024 13:34:15 -0600 Subject: [PATCH 5/7] address reviewer comments; remove debugging code --- scripts/ccpp_capgen.py | 1 - scripts/host_cap.py | 11 ++--------- scripts/suite_objects.py | 8 +++++++- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/scripts/ccpp_capgen.py b/scripts/ccpp_capgen.py index 2aed12a7..9eac0ecf 100755 --- a/scripts/ccpp_capgen.py +++ b/scripts/ccpp_capgen.py @@ -575,7 +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 return header_dict.values(), table_dict diff --git a/scripts/host_cap.py b/scripts/host_cap.py index f1bbef71..f19a534f 100644 --- a/scripts/host_cap.py +++ b/scripts/host_cap.py @@ -566,7 +566,7 @@ def write_host_cap(host_model, api, module_name, output_dir, run_env): spart_args = spart.call_list.variable_list() for sp_var in spart_args: stdname = sp_var.get_prop_value('standard_name') - # Skip any dynamic constituent objects in register phases + # Special handling for run-time constituents in register phase if sp_var.get_prop_value('type') == 'ccpp_constituent_properties_t': if spart.phase() == 'register': prop_dict = {'standard_name' : sp_var.get_prop_value('standard_name'), @@ -661,7 +661,6 @@ def write_host_cap(host_model, api, module_name, output_dir, run_env): allocatable=var.get_prop_value('allocatable')) # End for cap.write('', 0) - cap.write('character(len=256) :: stdname', 2) # Write out the body clauses errmsg_name, errflg_name = api.get_errinfo_names() # Initialize err variables @@ -696,8 +695,7 @@ def write_host_cap(host_model, api, module_name, output_dir, run_env): dyn_const_array = suite_dynamic_constituent_array_name(host_model, suite.name) call_str = suite_part_call_list(host_model, const_dict, spart, False, dyn_const=True) - stmt = "call {}_{}({})" - cap.write(stmt.format(suite.name, stage, call_str), 3) + cap.write(f"call {suite.name}_{stage}({call_str})", 3) # Allocate the suite's dynamic constituents array size_string = "0+" for var in host_local_vars.variable_list(): @@ -721,15 +719,10 @@ def write_host_cap(host_model, api, module_name, output_dir, run_env): continue # end if cap.write(f"do const_index = 1, size({local_name})", 3) - cap.write(f"call {local_name}(1)%standard_name(stdname, errcode=errflg, errmsg=errmsg)", 4) cap.write(f"{dyn_const_array}(num_dyn_consts + const_index) = {local_name}(const_index)", 4) - cap.write(f"call {dyn_const_array}(num_dyn_consts + const_index)%standard_name(stdname, errcode=errflg, errmsg=errmsg)", 4) cap.write("end do", 3) cap.write(f"num_dyn_consts = num_dyn_consts + size({local_name})", 3) cap.write(f"deallocate({local_name})", 3) - cap.write(f"do const_index = 1, size({dyn_const_array})", 3) - cap.write(f"call {dyn_const_array}(const_index)%standard_name(stdname, errcode=errflg, errmsg=errmsg)", 4) - cap.write("end do", 3) # end for else: diff --git a/scripts/suite_objects.py b/scripts/suite_objects.py index b0065016..335ad35b 100755 --- a/scripts/suite_objects.py +++ b/scripts/suite_objects.py @@ -453,8 +453,14 @@ def add_call_list_variable(self, newvar, exists_ok=False, adjust_intent=True) # We need to make sure that this variable's dimensions are available for vardim in newvar.get_dim_stdnames(include_constants=False): - if vardim == '': + # Unnamed dimensions are ok for allocatable variables + if vardim == '' and newvar.get_prop_value('allocatable'): continue + elif vardim == '': + emsg = f"{self.name}: Cannot have unnamed/empty string dimension" + raise ParseInternalError(emsg.format(self.name, + vardim, stdname)) + # end if dvar = self.find_variable(standard_name=vardim, any_scope=True) if dvar is None: From 073ed99583ed4e428e66810fe762f844ceac6281 Mon Sep 17 00:00:00 2001 From: peverwhee Date: Mon, 7 Oct 2024 10:26:50 -0600 Subject: [PATCH 6/7] add test that is expected to fail --- scripts/constituents.py | 2 +- scripts/suite_objects.py | 2 +- test/advection_test/CMakeLists.txt | 45 +++++++++++++++++++ test/advection_test/cld_liq.meta | 2 +- test/advection_test/cld_suite_error.xml | 9 ++++ test/advection_test/cld_suite_files_error.txt | 3 ++ test/advection_test/dlc_liq.F90 | 41 +++++++++++++++++ test/advection_test/dlc_liq.meta | 29 ++++++++++++ 8 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 test/advection_test/cld_suite_error.xml create mode 100644 test/advection_test/cld_suite_files_error.txt create mode 100644 test/advection_test/dlc_liq.F90 create mode 100644 test/advection_test/dlc_liq.meta diff --git a/scripts/constituents.py b/scripts/constituents.py index 3764b4d8..b1a08362 100644 --- a/scripts/constituents.py +++ b/scripts/constituents.py @@ -534,7 +534,7 @@ def write_host_routines(cap, host, reg_funcname, init_funcname, num_const_funcna cap.write("return", 4) cap.write("end if", 3) cap.write("end do", 2) - # end do + # end for # Register suite constituents for suite in suite_list: diff --git a/scripts/suite_objects.py b/scripts/suite_objects.py index 335ad35b..557e84f8 100755 --- a/scripts/suite_objects.py +++ b/scripts/suite_objects.py @@ -864,7 +864,7 @@ def match_variable(self, var, run_env): else: errmsg = "Variables of type ccpp_constituent_properties_t only allowed in register phase: " sname = var.get_prop_value('standard_name') - errmsg += ", {}".format(sname) + errmsg += f"'{sname}' found in {self.phase()} phase" raise CCPPError(errmsg) # end if # end if diff --git a/test/advection_test/CMakeLists.txt b/test/advection_test/CMakeLists.txt index 4aacdc18..c3f45190 100644 --- a/test/advection_test/CMakeLists.txt +++ b/test/advection_test/CMakeLists.txt @@ -20,8 +20,10 @@ get_filename_component(CCPP_ROOT "${TEST_ROOT}" DIRECTORY) # #------------------------------------------------------------------------------ LIST(APPEND SCHEME_FILES "cld_suite_files.txt") +LIST(APPEND SCHEME_FILES_ERROR "cld_suite_files_error.txt") LIST(APPEND HOST_FILES "test_host_data" "test_host_mod") LIST(APPEND SUITE_FILES "cld_suite.xml") +LIST(APPEND SUITE_FILES_ERROR "cld_suite_error.xml") # HOST is the name of the executable we will build. # We assume there are files ${HOST}.meta and ${HOST}.F90 in CMAKE_SOURCE_DIR SET(HOST "${CMAKE_PROJECT_NAME}") @@ -114,6 +116,13 @@ FOREACH(FILE ${SCHEME_FILES}) ENDFOREACH(FILE) string(REPLACE ";" "," SCHEME_METADATA "${SCHEME_FILES}") +# Create metadata and source file lists +FOREACH(FILE ${SCHEME_FILES_ERROR}) + FILE(STRINGS ${FILE} FILENAMES) + LIST(APPEND SCHEME_FILENAMES_ERROR ${FILENAMES}) +ENDFOREACH(FILE) +string(REPLACE ";" "," SCHEME_METADATA_ERROR "${SCHEME_FILES_ERROR}") + FOREACH(FILE ${SCHEME_FILENAMES}) # target_sources prefers absolute pathnames string(REPLACE ".meta" ".F90" TEMP "${FILE}") @@ -132,6 +141,42 @@ string(REPLACE ";" ".meta," HOST_METADATA "${HOST_FILES}") set(HOST_METADATA "${HOST_METADATA}.meta,${HOST}.meta") string(REPLACE ";" "," SUITE_XML "${SUITE_FILES}") +string(REPLACE ";" "," SUITE_XML_ERROR "${SUITE_FILES_ERROR}") + +# Run ccpp_capgen that we expect to fail +set(CAPGEN_CMD "${CCPP_FRAMEWORK}/ccpp_capgen.py") +list(APPEND CAPGEN_CMD "--host-files") +list(APPEND CAPGEN_CMD "${HOST_METADATA}") +list(APPEND CAPGEN_CMD "--scheme-files") +list(APPEND CAPGEN_CMD "${SCHEME_METADATA_ERROR}") +list(APPEND CAPGEN_CMD "--suites") +list(APPEND CAPGEN_CMD "${SUITE_XML_ERROR}") +list(APPEND CAPGEN_CMD "--host-name") +list(APPEND CAPGEN_CMD "test_host") +list(APPEND CAPGEN_CMD "--output-root") +list(APPEND CAPGEN_CMD "${CCPP_CAP_FILES}") +while (VERBOSITY GREATER 0) + list(APPEND CAPGEN_CMD "--verbose") + MATH(EXPR VERBOSITY "${VERBOSITY} - 1") +endwhile () +list(APPEND CAPGEN_CMD "--debug") +string(REPLACE ";" " " CAPGEN_STRING "${CAPGEN_CMD}") +MESSAGE(STATUS "Running: ${CAPGEN_STRING}") +EXECUTE_PROCESS(COMMAND ${CAPGEN_CMD} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE CAPGEN_OUT ERROR_VARIABLE CAPGEN_OUT RESULT_VARIABLE RES) +MESSAGE(STATUS "${CAPGEN_OUT}") +if (RES EQUAL 0) + MESSAGE(STATUS "CCPP cap generation completed") +else() + # Example: Validate the error message + string(FIND "${CAPGEN_OUT}" "Variables of type ccpp_constituent_properties_t only allowed in register phase" ERROR_INDEX) + + if (ERROR_INDEX GREATER -1) + MESSAGE(STATUS "Capgen build produces expected error message.") + else() + MESSAGE(FATAL_ERROR "CCPP cap generation did not generate expected error. Expected 'Variables of type ccpp_cosntituent_properties_t only allowed in register phase. Got: " ${CAPGEN_OUT}"") + endif() +endif(RES EQUAL 0) # Run ccpp_capgen set(CAPGEN_CMD "${CCPP_FRAMEWORK}/ccpp_capgen.py") diff --git a/test/advection_test/cld_liq.meta b/test/advection_test/cld_liq.meta index 093c13b7..da04ccf5 100644 --- a/test/advection_test/cld_liq.meta +++ b/test/advection_test/cld_liq.meta @@ -68,7 +68,7 @@ state_variable = true type = real kind = kind_phys - units = Pa + units = hPa dimensions = (horizontal_loop_extent) intent = in [ cld_liq_array ] diff --git a/test/advection_test/cld_suite_error.xml b/test/advection_test/cld_suite_error.xml new file mode 100644 index 00000000..80acac91 --- /dev/null +++ b/test/advection_test/cld_suite_error.xml @@ -0,0 +1,9 @@ + + + + + dlc_liq + cld_liq + cld_ice + + diff --git a/test/advection_test/cld_suite_files_error.txt b/test/advection_test/cld_suite_files_error.txt new file mode 100644 index 00000000..63ff75b0 --- /dev/null +++ b/test/advection_test/cld_suite_files_error.txt @@ -0,0 +1,3 @@ +cld_liq.meta +cld_ice.meta +dlc_liq.meta diff --git a/test/advection_test/dlc_liq.F90 b/test/advection_test/dlc_liq.F90 new file mode 100644 index 00000000..93230f81 --- /dev/null +++ b/test/advection_test/dlc_liq.F90 @@ -0,0 +1,41 @@ +! Test parameterization with a runtime constituents +! properties object outside of the register phase + +MODULE dlc_liq + + USE ccpp_kinds, ONLY: kind_phys + use ccpp_constituent_prop_mod, only: ccpp_constituent_properties_t + + IMPLICIT NONE + PRIVATE + + PUBLIC :: dlc_liq_init + +CONTAINS + + !> \section arg_table_dlc_liq_init Argument Table + !! \htmlinclude arg_table_dlc_liq_init.html + !! + subroutine dlc_liq_init(dyn_const, errmsg, errflg) + type(ccpp_constituent_properties_t), allocatable, intent(out) :: dyn_const(:) + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg + + character(len=256) :: stdname + + errmsg = '' + errflg = 0 + allocate(dyn_const(1), stat=errflg) + if (errflg /= 0) then + errmsg = 'Error allocating dyn_const in dlc_liq_init' + return + end if + call dyn_const(1)%instantiate(std_name="dyn_const3", long_name='dyn const3', & + units='kg kg-1', default_value=1._kind_phys, & + vertical_dim='vertical_layer_dimension', advected=.true., & + errcode=errflg, errmsg=errmsg) + call dyn_const(1)%standard_name(stdname, errcode=errflg, errmsg=errmsg) + + end subroutine dlc_liq_init + +END MODULE dlc_liq diff --git a/test/advection_test/dlc_liq.meta b/test/advection_test/dlc_liq.meta new file mode 100644 index 00000000..fedb6243 --- /dev/null +++ b/test/advection_test/dlc_liq.meta @@ -0,0 +1,29 @@ +# dlc_liq is a scheme that has a ccpp_constituent_properties_t variable +# outside of the register phase +[ccpp-table-properties] + name = dlc_liq + type = scheme +[ccpp-arg-table] + name = dlc_liq_init + type = scheme +[ dyn_const ] + standard_name = dynamic_constituents_for_dlc_liq + dimensions = (:) + type = ccpp_constituent_properties_t + intent = out + allocatable = true +[ errmsg ] + standard_name = ccpp_error_message + long_name = Error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=512 + intent = out +[ errflg ] + standard_name = ccpp_error_code + long_name = Error flag for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out From ca146bd9875c968764421d250eb1dfe7c12d6f66 Mon Sep 17 00:00:00 2001 From: peverwhee Date: Tue, 29 Oct 2024 15:41:16 -0600 Subject: [PATCH 7/7] address review comments; code cleanup --- scripts/host_cap.py | 15 ++++++--------- scripts/suite_objects.py | 6 +----- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/scripts/host_cap.py b/scripts/host_cap.py index f19a534f..3412e2cd 100644 --- a/scripts/host_cap.py +++ b/scripts/host_cap.py @@ -461,7 +461,7 @@ def suite_part_call_list(host_model, const_dict, suite_part, subst_loop_vars, sp_lname = sp_var.get_prop_value('local_name') if sp_var.get_prop_value('type') == 'ccpp_constituent_properties_t': if dyn_const: - hmvars.append("{}={}".format(sp_lname, sp_lname)) + hmvars.append(f"{sp_lname}={sp_lname}") # end if continue # end if @@ -578,8 +578,8 @@ def write_host_cap(host_model, api, module_name, output_dir, run_env): has_dyn_consts = True continue else: - errmsg = 'ccpp_constituent_properties_t object "{}" not allowed in "{}" phase' - raise CCPPError(errmsg.format(stdname, spart.phase())) + errmsg = f'ccpp_constituent_properties_t object "{stdname}" not allowed in "{spart.phase()}" phase' + raise CCPPError(errmsg) # end if # end if hvar = const_dict.find_variable(standard_name=stdname, @@ -700,8 +700,8 @@ def write_host_cap(host_model, api, module_name, output_dir, run_env): size_string = "0+" for var in host_local_vars.variable_list(): vtype = var.get_prop_value('type') - local_name = var.get_prop_value('local_name') if vtype == 'ccpp_constituent_properties_t': + local_name = var.get_prop_value('local_name') size_string += f"size({local_name})+" # end if # end for @@ -714,10 +714,10 @@ def write_host_cap(host_model, api, module_name, output_dir, run_env): cap.write("num_dyn_consts = 0", 3) for var in host_local_vars.variable_list(): vtype = var.get_prop_value('type') - local_name = var.get_prop_value('local_name') if vtype != 'ccpp_constituent_properties_t': continue # end if + local_name = var.get_prop_value('local_name') cap.write(f"do const_index = 1, size({local_name})", 3) cap.write(f"{dyn_const_array}(num_dyn_consts + const_index) = {local_name}(const_index)", 4) cap.write("end do", 3) @@ -752,10 +752,7 @@ def write_host_cap(host_model, api, module_name, output_dir, run_env): cap.write("", 0) const_names_name = constituent_model_const_stdnames(host_model) const_indices_name = constituent_model_const_indices(host_model) - dyn_const_names = list() - for suite in api.suites: - dyn_const_names.append(suite_dynamic_constituent_array_name(host_model, suite.name)) - # end for + dyn_const_names = [suite_dynamic_constituent_array_name(host_model, suite.name) for suite in api.suites] ConstituentVarDict.write_host_routines(cap, host_model, reg_name, init_name, numconsts_name, queryconsts_name, copyin_name, copyout_name, diff --git a/scripts/suite_objects.py b/scripts/suite_objects.py index 557e84f8..3fdbe8e6 100755 --- a/scripts/suite_objects.py +++ b/scripts/suite_objects.py @@ -444,9 +444,6 @@ def add_call_list_variable(self, newvar, exists_ok=False, newvar = oldvar.clone(subst_dict, source_name=self.name, source_type=stype, context=self.context) # end if - stdname = newvar.get_prop_value('standard_name') - vtype = newvar.get_prop_value('type') - dimensions = newvar.get_prop_value('dimensions') self.call_list.add_variable(newvar, self.run_env, exists_ok=exists_ok, gen_unique=gen_unique, @@ -458,8 +455,7 @@ def add_call_list_variable(self, newvar, exists_ok=False, continue elif vardim == '': emsg = f"{self.name}: Cannot have unnamed/empty string dimension" - raise ParseInternalError(emsg.format(self.name, - vardim, stdname)) + raise ParseInternalError(emsg) # end if dvar = self.find_variable(standard_name=vardim, any_scope=True)