diff --git a/scripts/ccpp_suite.py b/scripts/ccpp_suite.py index d1a6e968..4b051f62 100644 --- a/scripts/ccpp_suite.py +++ b/scripts/ccpp_suite.py @@ -258,7 +258,8 @@ def groups(self): def find_variable(self, standard_name=None, source_var=None, any_scope=True, clone=None, - search_call_list=False, loop_subst=False): + search_call_list=False, loop_subst=False, + check_components=True): """Attempt to return the variable matching . if is None, the standard name from is used. It is an error to pass both and if @@ -278,7 +279,8 @@ def find_variable(self, standard_name=None, source_var=None, any_scope=any_scope, clone=None, search_call_list=srch_clist, - loop_subst=loop_subst) + loop_subst=loop_subst, + check_components=check_components) if var is None: # No dice? Check for a group variable which can be promoted # Don't promote loop standard names @@ -289,7 +291,8 @@ def find_variable(self, standard_name=None, source_var=None, source_var=source_var, any_scope=False, search_call_list=srch_clist, - loop_subst=loop_subst) + loop_subst=loop_subst, + check_components=check_components) if var is not None: # Promote variable to suite level @@ -341,7 +344,8 @@ def find_variable(self, standard_name=None, source_var=None, # Guess it is time to clone a different variable var = super().find_variable(standard_name=standard_name, source_var=source_var, - any_scope=any_scope, clone=clone) + any_scope=any_scope, clone=clone, + check_components=check_components) # end if return var @@ -459,7 +463,7 @@ def analyze(self, host_model, scheme_library, ddt_library, run_env): for x in item.schemes()])) item.analyze(phase, self, scheme_library, ddt_library, self.check_suite_state(phase), - self.set_suite_state(phase)) + self.set_suite_state(phase), host_model) # Look for group variables that need to be promoted to the suite # We need to promote any variable used later to the suite, however, # we do not yet know if it will be used. @@ -735,7 +739,8 @@ def __init__(self, sdfs, host_model, scheme_headers, run_env): if group.phase() == phase: self.__call_lists[phase].add_vars(group.call_list, run_env, - gen_unique=True) + gen_unique=True, + add_children=True) # end if # end for # end for diff --git a/scripts/constituents.py b/scripts/constituents.py index e7e182c0..d092bf4c 100644 --- a/scripts/constituents.py +++ b/scripts/constituents.py @@ -48,7 +48,8 @@ def __init__(self, name, parent_dict, run_env, variables=None): def find_variable(self, standard_name=None, source_var=None, any_scope=True, clone=None, - search_call_list=False, loop_subst=False): + search_call_list=False, loop_subst=False, + check_components=True): """Attempt to return the variable matching . if is None, the standard name from is used. It is an error to pass both and if @@ -86,7 +87,8 @@ def find_variable(self, standard_name=None, source_var=None, source_var=source_var, any_scope=any_scope, clone=None, search_call_list=srch_clist, - loop_subst=loop_subst) + loop_subst=loop_subst, + check_components=check_components) else: var = None # end if diff --git a/scripts/ddt_library.py b/scripts/ddt_library.py index 1c362108..42b97115 100644 --- a/scripts/ddt_library.py +++ b/scripts/ddt_library.py @@ -80,8 +80,8 @@ def intrinsic_elements(self, check_dict=None): # end if return pvalue - def clone(self, subst_dict, source_name=None, source_type=None, - context=None): + def clone(self, subst_dict=None, remove_intent=False, + source_name=None, source_type=None, context=None): """Create a clone of this VarDDT object's leaf Var with properties from overriding this variable's properties. may also be a string in which case only the local_name @@ -101,6 +101,21 @@ def clone(self, subst_dict, source_name=None, source_type=None, # end if return clone_var + def call_dimstring(self, var_dicts=None, explicit_dims=False, + loop_subst=False, prepend_varname=False): + """Return the dimensions string for a variable call for self.field. + If is True, prepend the VarDDT's local name sequence. + """ + if self.field is not None: + dimstr = self.field.call_dimstring( + var_dicts=var_dicts, explicit_dims=explicit_dims, + loop_subst=loop_subst, prepend_varname=prepend_varname) + # end if + # DH Copied from below: XXgoldyXX: Need to add dimensions to this + if prepend_varname: + dimstr = super().get_prop_value('local_name') + '%' + dimstr + return dimstr + def call_string(self, var_dict, loop_vars=None): """Return a legal call string of this VarDDT's local name sequence. """ @@ -288,7 +303,7 @@ def collect_ddt_fields(self, var_dict, var, run_env, # for a DDT, the variable also cannot be in our parent # dictionaries. stdname = dvar.get_prop_value('standard_name') - pvar = var_dict.find_variable(standard_name=stdname, any_scope=True) + pvar = var_dict.find_variable(standard_name=stdname, any_scope=True, check_components=False) if pvar and (not skip_duplicates): ntx = context_string(dvar.context) ctx = context_string(pvar.context) @@ -300,6 +315,8 @@ def collect_ddt_fields(self, var_dict, var, run_env, if not pvar: var_dict.add_variable(subvar, run_env) # end if + # Add this ddt variable to the parent DDT + var.add_component(subvar) # end for def ddt_modules(self, variable_list, ddt_mods=None): diff --git a/scripts/file_utils.py b/scripts/file_utils.py index 1cad8338..1342f72b 100644 --- a/scripts/file_utils.py +++ b/scripts/file_utils.py @@ -286,7 +286,7 @@ def move_modified_files(src_dir, dest_dir, overwrite=False, remove_src=False): if overwrite: fmove = True else: - fmove = filecmp.cmp(src_path, dest_path, shallow=False) + fmove = not filecmp.cmp(src_path, dest_path, shallow=False) # end if else: fmove = True diff --git a/scripts/fortran_tools/parse_fortran.py b/scripts/fortran_tools/parse_fortran.py index ab072afd..00e22fce 100644 --- a/scripts/fortran_tools/parse_fortran.py +++ b/scripts/fortran_tools/parse_fortran.py @@ -317,6 +317,10 @@ class FtypeCharacter(Ftype): 'Character(len=512)' >>> FtypeCharacter('character(*)', None).__str__() 'character(len=*)' + >>> FtypeCharacter('character(nf_file_length)', None).__str__() + 'character(len=nf_file_length)' + >>> FtypeCharacter('character(len=nf_file_length)', None).__str__() + 'character(len=nf_file_length)' >>> FtypeCharacter('character*7', None).__str__() #doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ParseSyntaxError: Invalid character declaration, 'character*7', at :1 @@ -335,9 +339,9 @@ class FtypeCharacter(Ftype): "character(len=15, kind=kind('b'))" """ - char_re = re.compile(r"(?i)(character)\s*(\([A-Za-z0-9,=*:\s\'\"()]+\))?") + char_re = re.compile(r"(?i)(character)\s*(\([A-Za-z0-9_,=*:\s\'\"()]+\))?") chartrail_re = re.compile(r"\s*[,:]|\s+[A-Z]") - oldchar_re = re.compile(r"(?i)(character)\s*(\*)\s*([0-9]+\s*)") + oldchar_re = re.compile(r"(?i)(character)\s*(\*)\s*([A-Za-z0-9_]+\s*)") oldchartrail_re = re.compile(r"\s*[,]|\s+[A-Z]") len_token_re = re.compile(r"(?i)([:]|[*]|[0-9]+|[A-Z][A-Z0-9_]*)$") diff --git a/scripts/host_cap.py b/scripts/host_cap.py index fb2e7012..b86450a3 100644 --- a/scripts/host_cap.py +++ b/scripts/host_cap.py @@ -500,7 +500,7 @@ def suite_part_call_list(host_model, const_dict, suite_part, subst_loop_vars, var_dicts = [host_model, const_dict] # Figure out which dictionary has the variable for vdict in var_dicts: - hvar = vdict.find_variable(standard_name=stdname, any_scope=False) + hvar = vdict.find_variable(standard_name=stdname, any_scope=False, check_components=False) if hvar is not None: var_dict = vdict break @@ -511,7 +511,7 @@ def suite_part_call_list(host_model, const_dict, suite_part, subst_loop_vars, raise CCPPError(errmsg) # End if if stdname not in CCPP_CONSTANT_VARS: - lname = var_dict.var_call_string(hvar, loop_vars=loop_vars) + lname = var_dict.var_call_string(hvar) hmvars.append(f"{sp_lname}={lname}") # End if # End for diff --git a/scripts/host_model.py b/scripts/host_model.py index c3beb447..587d1956 100644 --- a/scripts/host_model.py +++ b/scripts/host_model.py @@ -192,10 +192,16 @@ def variable_locations(self): # Now, find all the used module variables cap_modname = self.ccpp_cap_name() for name in lnames: + # Grab base local name; no dimensions + if '(' in name: + newname = name.split('(')[0] + else: + newname = name + # End if module = self.host_variable_module(name) used = self.__used_variables and (name in self.__used_variables) if module and used and (module != cap_modname): - varset.add((module, name)) + varset.add((module, newname)) # No else, either no module or a zero-length module name # End if # End for @@ -203,7 +209,8 @@ def variable_locations(self): def find_variable(self, standard_name=None, source_var=None, any_scope=False, clone=None, - search_call_list=False, loop_subst=False): + search_call_list=False, loop_subst=False, + check_components=True): """Return the host model variable matching or None If is True, substitute a begin:end range for an extent. """ @@ -211,7 +218,8 @@ def find_variable(self, standard_name=None, source_var=None, source_var=source_var, any_scope=any_scope, clone=clone, search_call_list=search_call_list, - loop_subst=loop_subst) + loop_subst=loop_subst, + check_components=check_components) if my_var is None: # Check our DDT library if standard_name is None: @@ -224,7 +232,8 @@ def find_variable(self, standard_name=None, source_var=None, # end if # Since we are the parent of the DDT library, only check that dict my_var = self.__ddt_dict.find_variable(standard_name=standard_name, - any_scope=False) + any_scope=False, + check_components=check_components) # End if if loop_subst: if my_var is None: @@ -257,7 +266,7 @@ def find_variable(self, standard_name=None, source_var=None, vdims = [x.strip() for x in imatch.group(2).split(',') if ':' not in x] for vname in vdims: - _ = self.find_variable(standard_name=vname) + _ = self.find_variable(standard_name=vname, check_components=check_components) # End for # End if if isinstance(my_var, VarDDT): diff --git a/scripts/metadata_table.py b/scripts/metadata_table.py index b657dd2c..c9085fae 100755 --- a/scripts/metadata_table.py +++ b/scripts/metadata_table.py @@ -296,6 +296,7 @@ def register_ddts(file_list): """ errors = "" ddt_names = set() + in_table = False for mfile in file_list: if os.path.exists(mfile): with open(mfile, 'r') as infile: @@ -1201,13 +1202,15 @@ def variable_list(self, std_vars=True, loop_vars=True, consts=True): loop_vars=loop_vars, consts=consts) - def find_variable(self, std_name, use_local_name=False): + def find_variable(self, std_name, use_local_name=False, check_components=True): """Find a variable in this header's dictionary""" var = None if use_local_name: var = self.__variables.find_local_name(std_name) else: - var = self.__variables.find_variable(std_name, any_scope=False) + var = self.__variables.find_variable(std_name, + any_scope=False, + check_components=check_components) # end if return var diff --git a/scripts/metavar.py b/scripts/metavar.py index cafdbf9f..247647ce 100755 --- a/scripts/metavar.py +++ b/scripts/metavar.py @@ -261,7 +261,7 @@ class Var: __var_propdict.update({p.name : p for p in __constituent_props}) # All constituent props are optional so no check - def __init__(self, prop_dict, source, run_env, context=None, + def __init__(self, prop_dict, source, run_env, is_ddt=False, components=None, context=None, clone_source=None, fortran_imports=None): """Initialize a new Var object. If is really a Var object, use that object's prop_dict. @@ -275,6 +275,11 @@ def __init__(self, prop_dict, source, run_env, context=None, """ self.__parent_var = None # for array references self.__children = list() # This Var's array references + if components: + self.__components = components + else: + self.__components = list() # This Var's DDT components + # end if self.__clone_source = clone_source self.__run_env = run_env if isinstance(prop_dict, Var): @@ -315,6 +320,9 @@ def __init__(self, prop_dict, source, run_env, context=None, else: self.__intrinsic = True # end if + if is_ddt: + self.__intrinsic = False + # end if for key in prop_dict: if Var.get_prop(key) is None: raise ParseSyntaxError("Invalid metadata variable property, '{}'".format(key), context=self.context) @@ -367,26 +375,44 @@ def __init__(self, prop_dict, source, run_env, context=None, # end if # end try - def compatible(self, other, run_env, is_tend=False): + def compatible(self, other, run_env, is_tend=False, is_host_var=False): """Return a VarCompatObj object which describes the equivalence, compatibility, or incompatibility between and . + If , reverse the variable properties. """ # We accept character(len=*) as compatible with # character(len=INTEGER_VALUE) - stype = self.get_prop_value('type') - skind = self.get_prop_value('kind') - sunits = self.get_prop_value('units') - sstd_name = self.get_prop_value('standard_name') - sloc_name = self.get_prop_value('local_name') - stopp = self.get_prop_value('top_at_one') - sdims = self.get_dimensions() - otype = other.get_prop_value('type') - okind = other.get_prop_value('kind') - ounits = other.get_prop_value('units') - ostd_name = other.get_prop_value('standard_name') - oloc_name = other.get_prop_value('local_name') - otopp = other.get_prop_value('top_at_one') - odims = other.get_dimensions() + if not is_host_var: + stype = self.get_prop_value('type') + skind = self.get_prop_value('kind') + sstd_name = self.get_prop_value('standard_name') + sloc_name = self.get_prop_value('local_name') + stopp = self.get_prop_value('top_at_one') + sdims = self.get_dimensions() + sunits = self.get_prop_value('units') + otype = other.get_prop_value('type') + okind = other.get_prop_value('kind') + ostd_name = other.get_prop_value('standard_name') + oloc_name = other.get_prop_value('local_name') + otopp = other.get_prop_value('top_at_one') + odims = other.get_dimensions() + ounits = other.get_prop_value('units') + else: + otype = self.get_prop_value('type') + okind = self.get_prop_value('kind') + ostd_name = self.get_prop_value('standard_name') + oloc_name = self.get_prop_value('local_name') + otopp = self.get_prop_value('top_at_one') + odims = self.get_dimensions() + ounits = self.get_prop_value('units') + stype = other.get_prop_value('type') + skind = other.get_prop_value('kind') + sstd_name = other.get_prop_value('standard_name') + sloc_name = other.get_prop_value('local_name') + stopp = other.get_prop_value('top_at_one') + sdims = other.get_dimensions() + sunits = other.get_prop_value('units') + # end if compat = VarCompatObj(sstd_name, stype, skind, sunits, sdims, sloc_name, stopp, ostd_name, otype, okind, ounits, odims, oloc_name, otopp, run_env, @@ -499,7 +525,7 @@ def clone(self, subst_dict=None, remove_intent=False, # end if psource = ParseSource(source_name, source_type, context) - return Var(cprop_dict, psource, self.run_env, clone_source=self) + return Var(cprop_dict, psource, self.run_env, is_ddt=self.is_ddt(), components=self.components, clone_source=self) def get_prop_value(self, name): """Return the value of key, if is in this variable's @@ -584,8 +610,8 @@ def handle_array_ref(self): # end if return lname, dimlist - def call_dimstring(self, var_dicts=None, - explicit_dims=False, loop_subst=False): + def call_dimstring(self, var_dicts=None, explicit_dims=False, + loop_subst=False, prepend_varname=False): """Return the dimensions string for a variable call. If is present, find and substitute a local_name for each standard_name in this variable's dimensions. @@ -593,9 +619,10 @@ def call_dimstring(self, var_dicts=None, If is True, include the variable's dimensions. If is True, apply a loop substitution, if found for any missing dimension. + If is True, prepend the local variable name. """ emsg = '' - _, dims = self.handle_array_ref() + varname, dims = self.handle_array_ref() if var_dicts is not None: dimlist = [] sepstr = '' @@ -618,6 +645,13 @@ def call_dimstring(self, var_dicts=None, if (not dvar) and add_dims: dnames = [] for stdname in dstdnames: + # Leave integers (parameters) alone + try: + if isinstance(int(stdname), int): + dnames.append(stdname) + continue + except ValueError: + pass for vdict in var_dicts: dvar = vdict.find_variable(standard_name=stdname, any_scope=False) @@ -664,18 +698,32 @@ def call_dimstring(self, var_dicts=None, lname = self.get_prop_value('local_name') raise CCPPError(emsg.format(vlnam=lname, ctx=ctx)) # end if - return dimstr + if prepend_varname: + return varname + dimstr + else: + return dimstr - def call_string(self, var_dict, loop_vars=None): + def call_string(self, var_dicts, loop_vars=None): """Construct the actual argument string for this Var by translating standard names to local names. String includes array bounds unless loop_vars is None. if is not None, look there first for array bounds, even if usage requires a loop substitution. """ + # DH* + if loop_vars: + raise Exception(f"DH DEBUG: WE DO USE loop_vars in call_string! '{loop_vars}'") + # *DH + if not isinstance(var_dicts, list): + var_dicts = [var_dicts] + # end if if loop_vars is None: call_str = self.get_prop_value('local_name') # Look for dims in case this is an array selection variable + # DH* + # Will this work with something like ddt1(some_index)%nested_ddt(other_index)%myvar(dimstring)? + # Is local_name guaranteed to be just the member of the innermost DDT? + # Better to use split_dims_from_name ... dind = call_str.find('(') if dind > 0: dimstr = call_str[dind+1:].rstrip()[:-1] @@ -684,6 +732,7 @@ def call_string(self, var_dict, loop_vars=None): else: dims = None # end if + # *DH else: call_str, dims = self.handle_array_ref() # end if @@ -701,8 +750,15 @@ def call_string(self, var_dict, loop_vars=None): lname = "" for item in dim.split(':'): if item: - dvar = var_dict.find_variable(standard_name=item, - any_scope=False) + for var_dict in var_dicts: + dvar = var_dict.find_variable(standard_name=item, + any_scope=False) + if dvar is not None: + iname = dvar.call_string(var_dict, + loop_vars=loop_vars) + break + # end if + # end for if dvar is None: try: dval = int(item) @@ -710,9 +766,6 @@ def call_string(self, var_dict, loop_vars=None): except ValueError: iname = None # end try - else: - iname = dvar.call_string(var_dict, - loop_vars=loop_vars) # end if else: iname = '' @@ -721,10 +774,9 @@ def call_string(self, var_dict, loop_vars=None): lname = lname + isep + iname isep = ':' else: - errmsg = 'No local variable {} in {}{}' + errmsg = 'No local variable {} in variable dictionaries' ctx = context_string(self.context) - dname = var_dict.name - raise CCPPError(errmsg.format(item, dname, ctx)) + raise CCPPError(errmsg.format(item, lname, ctx)) # end if # end for # end if @@ -850,8 +902,8 @@ def parent(self): @parent.setter def parent(self, parent_var): """Set this variable's parent if not already set""" - if self.__parent_var is not None: - emsg = 'Attempting to set parent for {} but parent already set' + if self.__parent_var is not None and self.__parent_var != parent_var: + emsg = 'Attempting to set parent for {} but different parent already set' lname = self.get_prop_value('local_name') raise ParseInternalError(emsg.format(lname)) # end if @@ -883,6 +935,14 @@ def children(self): # end if return iter(children) if children else None + @property + def components(self): + """Return the list of this object's components""" + return self.__components + + def add_component(self, new_component): + self.__components.append(new_component) + @property def var(self): "Return this object (base behavior for derived classes such as VarDDT)" @@ -1106,7 +1166,7 @@ def write_def(self, outfile, indent, wdict, allocatable=False, target=False, else: comma = ' ' # end if - if self.get_prop_value('target'): + if self.components: targ = ", target" else: targ = "" @@ -1134,21 +1194,6 @@ def write_def(self, outfile, indent, wdict, allocatable=False, target=False, name=name, dims=dimstr, cspace=cspace, sname=stdname), indent) - def write_ptr_def(self, outfile, indent, name, kind, dimstr, vtype, extra_space=0): - """Write the definition line for local null pointer declaration to .""" - comma = ', ' - if kind: - dstr = "{type}({kind}){cspace}pointer :: {name}{dims}{cspace2} => null()" - cspace = comma + ' '*(extra_space + 20 - len(vtype) - len(kind)) - cspace2 = ' '*(20 -len(name) - len(dimstr)) - else: - dstr = "{type}{cspace}pointer :: {name}{dims}{cspace2} => null()" - cspace = comma + ' '*(extra_space + 22 - len(vtype)) - cspace2 = ' '*(20 -len(name) - len(dimstr)) - # end if - outfile.write(dstr.format(type=vtype, kind=kind, name=name, dims=dimstr, - cspace=cspace, cspace2=cspace2), indent) - def is_ddt(self): """Return True iff is a DDT type.""" return not self.__intrinsic @@ -1604,7 +1649,7 @@ def variable_list(self, recursive=False, return vlist def add_variable(self, newvar, run_env, exists_ok=False, gen_unique=False, - adjust_intent=False): + adjust_intent=False, add_children=False): """Add if it does not conflict with existing entries If is True, attempting to add an identical copy is okay. If is True, a new local_name will be created if a @@ -1712,9 +1757,16 @@ def add_variable(self, newvar, run_env, exists_ok=False, gen_unique=False, if aref is not None: pname = aref.group(1).strip() pvar = self.find_local_name(pname) + array_pieces = aref.group(2).split(',') if pvar is not None: newvar.parent = pvar # end if + for array_piece in array_pieces: + if array_piece.strip() != ':': + pvar = self.find_variable(standard_name=array_piece.strip()) + if pvar: + newvar.add_child(pvar) + # end if # end if # If we make it to here without an exception, add the variable if standard_name not in self: @@ -1724,6 +1776,12 @@ def add_variable(self, newvar, run_env, exists_ok=False, gen_unique=False, if lname not in self.__local_names: self.__local_names[lname] = standard_name # end if + if newvar.children() and add_children: + for child in newvar.children(): + self.add_variable(child, run_env, exists_ok=exists_ok, gen_unique=gen_unique, + adjust_intent=adjust_intent) + # end for + # end if def remove_variable(self, standard_name): """Remove from the dictionary. @@ -1795,7 +1853,8 @@ def add_variable_dimensions(self, var, ignore_sources, suite_type, def find_variable(self, standard_name=None, source_var=None, any_scope=True, clone=None, - search_call_list=False, loop_subst=False): + search_call_list=False, loop_subst=False, + check_components=True): """Attempt to return the variable matching . if is None, the standard name from is used. It is an error to pass both and if @@ -1825,16 +1884,43 @@ def find_variable(self, standard_name=None, source_var=None, var = CCPP_CONSTANT_VARS[standard_name] elif standard_name in self: var = self[standard_name] - elif any_scope and (self.__parent_dict is not None): - src_clist = search_call_list - var = self.__parent_dict.find_variable(standard_name=standard_name, + else: + # Look in the DDTs + var = None + if check_components: + for var_check in self: + var_in_object = self[var_check] + ddt_components = var_in_object.components + for component in ddt_components: + if component.get_prop_value('standard_name') == standard_name: + var = component + else: + if component.children(): + for child in component.children(): + if child.get_prop_value('standard_name') == standard_name: + var = child + # end if + # end for + # end if + # end if + # end for + # end for + # end if + if not var: + if any_scope: + if self.__parent_dict is not None: + src_clist = search_call_list + var = self.__parent_dict.find_variable(standard_name=standard_name, source_var=source_var, any_scope=any_scope, clone=clone, search_call_list=src_clist, - loop_subst=loop_subst) - else: - var = None + loop_subst=loop_subst, + check_components=check_components) + else: + var = None + # end if + # end if # end if if (var is None) and (clone is not None): lname = clone.get_prop_value['local_name'] @@ -2128,6 +2214,20 @@ def new_internal_variable_name(self, prefix=None, max_len=63): # end while return newvar +def write_ptr_def(outfile, indent, name, kind, dimstr, vtype, extra_space=0): + """Write the definition line for local null pointer declaration to .""" + comma = ', ' + if kind: + dstr = "{type}({kind}){cspace}pointer :: {name}{dims}{cspace2} => null()" + cspace = comma + ' '*(extra_space + 20 - len(vtype) - len(kind)) + cspace2 = ' '*(20 -len(name) - len(dimstr)) + else: + dstr = "{type}{cspace}pointer :: {name}{dims}{cspace2} => null()" + cspace = comma + ' '*(extra_space + 22 - len(vtype)) + cspace2 = ' '*(20 -len(name) - len(dimstr)) + # end if + outfile.write(dstr.format(type=vtype, kind=kind, name=name, dims=dimstr, + cspace=cspace, cspace2=cspace2), indent) ############################################################################### # List of constant variables which are universally available diff --git a/scripts/suite_objects.py b/scripts/suite_objects.py index 3c846ed5..835f5a3f 100755 --- a/scripts/suite_objects.py +++ b/scripts/suite_objects.py @@ -11,13 +11,15 @@ # CCPP framework imports from ccpp_state_machine import CCPP_STATE_MACH, RUN_PHASE_NAME from code_block import CodeBlock -from constituents import ConstituentVarDict +from constituents import ConstituentVarDict, CONST_OBJ_STDNAME from framework_env import CCPPFrameworkEnv from metavar import Var, VarDictionary, VarLoopSubst from metavar import CCPP_CONSTANT_VARS, CCPP_LOOP_VAR_STDNAMES +from metavar import write_ptr_def from parse_tools import ParseContext, ParseSource, context_string from parse_tools import ParseInternalError, CCPPError from parse_tools import init_log, set_log_to_null +from ddt_library import VarDDT from var_props import is_horizontal_dimension, find_horizontal_dimension from var_props import find_vertical_dimension from var_props import VarCompatObj @@ -78,15 +80,16 @@ def __init__(self, name, run_env, routine=None): self.__routine = routine super().__init__(name, run_env) - def add_vars(self, call_list, run_env, gen_unique=False): + def add_vars(self, call_list, run_env, gen_unique=False, add_children=False): """Add new variables from another CallList ()""" for var in call_list.variable_list(): stdname = var.get_prop_value('standard_name') - self.add_variable(var, run_env, gen_unique=gen_unique, adjust_intent=True, exists_ok=True) + self.add_variable(var, run_env, gen_unique=gen_unique, adjust_intent=True, + exists_ok=True, add_children=add_children) # end for def add_variable(self, newvar, run_env, exists_ok=False, gen_unique=False, - adjust_intent=False): + adjust_intent=False, add_children=False): """Add as for VarDictionary but make sure that the variable has an intent with the default being intent(in). """ @@ -99,7 +102,8 @@ def add_variable(self, newvar, run_env, exists_ok=False, gen_unique=False, context=oldvar.context) # end if super().add_variable(newvar, run_env, exists_ok=exists_ok, - gen_unique=gen_unique, adjust_intent=adjust_intent) + gen_unique=gen_unique, adjust_intent=adjust_intent, + add_children=add_children) def call_string(self, cldicts=None, is_func_call=False, subname=None, sub_lname_list=None): """Return a dummy argument string for this call list. @@ -116,18 +120,39 @@ def call_string(self, cldicts=None, is_func_call=False, subname=None, sub_lname_ # Do not include constants stdname = var.get_prop_value('standard_name') if stdname not in CCPP_CONSTANT_VARS: + dimensions = var.get_dimensions() # Find the dummy argument name dummy = var.get_prop_value('local_name') # Now, find the local variable name if cldicts is not None: + # DH* I believe this can be folded into find_variable + # to ALWAYS search with any_scope=False first, and if + # not found look with any_scope=True if the argument + # any_scope=True is passed to find_variable for cldict in cldicts: dvar = cldict.find_variable(standard_name=stdname, any_scope=False) - if dvar is not None: + if dvar: + search_dict = cldict break - # end if # end for - if dvar is None: + if not dvar: + for cldict in cldicts: + dvar = cldict.find_variable(standard_name=stdname, + any_scope=True) + if dvar: + search_dict = cldict + break + # end for + # end if + # *DH + if dvar is not None: + var_in_call_list = True + if dvar.is_ddt(): + if dvar.components: + var_in_call_list = False + # end if + else: if subname is not None: errmsg = "{}: ".format(subname) else: @@ -137,11 +162,18 @@ def call_string(self, cldicts=None, is_func_call=False, subname=None, sub_lname_ clnames = [x.name for x in cldicts] raise CCPPError(errmsg.format(stdname, clnames)) # end if - lname = dvar.get_prop_value('local_name') + + dimensions = dvar.get_dimensions() + lname = dvar.call_string(cldicts) # Optional variables in the caps are associated with # local pointers of _ptr - if dvar.get_prop_value('optional'): + if var.get_prop_value('optional'): lname = dummy+'_ptr' + # Finally, handle the dimensions unless it's an allocatable var + elif not var.get_prop_value('allocatable'): + if dimensions: + lname= dvar.call_dimstring(var_dicts=cldicts, explicit_dims=True, loop_subst=self.routine.run_phase(), prepend_varname=True) + # end if # end if else: cldict = None @@ -163,22 +195,6 @@ def call_string(self, cldicts=None, is_func_call=False, subname=None, sub_lname_ # end if # end for # end if - if is_func_call: - if cldicts is not None: - use_dicts = cldicts - else: - use_dicts = [self] - # end if - run_phase = self.routine.run_phase() - # We only need dimensions for suite variables in run phase - need_dims = SuiteObject.is_suite_variable(dvar) and run_phase - vdims = var.call_dimstring(var_dicts=use_dicts, - explicit_dims=need_dims, - loop_subst=run_phase) - if _BLANK_DIMS_RE.match(vdims) is None: - lname = lname + vdims - # end if - # end if if is_func_call: arg_str += "{}{}={}".format(arg_sep, dummy, lname) else: @@ -367,7 +383,8 @@ def add_call_list_variable(self, newvar, exists_ok=False, self.call_list.add_variable(newvar, self.run_env, exists_ok=exists_ok, gen_unique=gen_unique, - adjust_intent=True) + adjust_intent=True, + add_children=True) # We need to make sure that this variable's dimensions are available for vardim in newvar.get_dim_stdnames(include_constants=False): # Unnamed dimensions are ok for allocatable variables @@ -620,7 +637,8 @@ def match_dimensions(self, need_dims, have_dims): def find_variable(self, standard_name=None, source_var=None, any_scope=True, clone=None, - search_call_list=False, loop_subst=False): + search_call_list=False, loop_subst=False, + check_components=True): """Find a matching variable to , create a local clone (if is True), or return None. First search the SuiteObject's internal dictionary, then its @@ -651,7 +669,8 @@ def find_variable(self, standard_name=None, source_var=None, source_var=source_var, any_scope=False, clone=None, search_call_list=scl, - loop_subst=loop_subst) + loop_subst=loop_subst, + check_components=check_components) if (not found_var) and (self.call_list is not None) and scl: # Don't clone yet, might find the variable further down found_var = self.call_list.find_variable(standard_name=stdname, @@ -659,7 +678,8 @@ def find_variable(self, standard_name=None, source_var=None, any_scope=False, clone=None, search_call_list=scl, - loop_subst=loop_subst) + loop_subst=loop_subst, + check_components=check_components) # end if loop_okay = VarDictionary.loop_var_okay(stdname, self.run_phase()) if not loop_okay: @@ -669,14 +689,15 @@ def find_variable(self, standard_name=None, source_var=None, # We do not have the variable, look to parents. found_var = self.parent.find_variable(standard_name=stdname, source_var=source_var, - any_scope=True, + any_scope=any_scope, clone=clone, search_call_list=scl, - loop_subst=loop_subst) + loop_subst=loop_subst, + check_components=check_components) # end if return found_var - def match_variable(self, var, run_env): + def match_variable(self, var, run_env, host_dict): """Try to find a source for in this SuiteObject's dictionary tree. Several items are returned: found_var: True if a match was found @@ -686,6 +707,7 @@ def match_variable(self, var, run_env): """ vstdname = var.get_prop_value('standard_name') vdims = var.get_dimensions() + local_var = None if (not vdims) and self.run_phase(): vmatch = VarDictionary.loop_var_match(vstdname) else: @@ -697,11 +719,12 @@ def match_variable(self, var, run_env): var_vdim = var.has_vertical_dimension(dims=vdims) compat_obj = None dict_var = None + scheme_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, compat_obj + return found_var, local_var, dict_var, var_vdim, new_vdims, compat_obj, scheme_var else: errmsg = "Variables of type ccpp_constituent_properties_t only allowed in register phase: " sname = var.get_prop_value('standard_name') @@ -710,6 +733,21 @@ def match_variable(self, var, run_env): # end if # end if + # Is this variable a member of a DDT? If so, look for the parent DDT + # and add that instead + # PEVERWHEE - note - currently not doing this for constituents + constituent = var.is_constituent() + if not constituent: + host_var = host_dict.find_variable(source_var=var, any_scope=False) + if host_var: + if isinstance(host_var, VarDDT): + local_var = host_var + scheme_var = var # Save Scheme for transform + var = host_var.var + vdims = [] + # end if + # 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: @@ -727,7 +765,7 @@ def match_variable(self, var, run_env): else: # Check dimensions dict_dims = dict_var.get_dimensions() - if vdims: + if vdims and not constituent: args = self.parent.match_dimensions(vdims, dict_dims) match, new_vdims, new_dict_dims, perm, err = args if perm is not None: @@ -743,23 +781,21 @@ def match_variable(self, var, run_env): new_dict_dims = dict_dims match = True # end if - # If variable is defined as "inactive" by the host, ensure that - # this variable is declared as "optional" by the scheme. If - # not satisfied, return error. - host_var_active = dict_var.get_prop_value('active') - scheme_var_optional = var.get_prop_value('optional') - if (not scheme_var_optional and host_var_active.lower() != '.true.'): - errmsg = "Non optional scheme arguments for conditionally allocatable variables" - sname = dict_var.get_prop_value('standard_name') - errmsg += ", {}".format(sname) - raise CCPPError(errmsg) - # end if + # Create compatability object, containing any necessary forward/reverse + # transforms from and + #compat_obj = var.compatible(dict_var, run_env) # Add the variable to the parent call tree if dict_dims == new_dict_dims: sdict = {} else: sdict = {'dimensions':new_dict_dims} # end if + # Add any DDT components from the host dictionary version of the variable + if not constituent: + for dict_var_component in dict_var.components: + var.add_component(dict_var_component) + # end for + # end if found_var = self.parent.add_variable_to_call_tree(var, subst_dict=sdict) if not match: @@ -778,9 +814,13 @@ def match_variable(self, var, run_env): # forward/reverse transforms to/from and . if dict_var is not None: dict_var = self.parent.find_variable(source_var=var, any_scope=True) - compat_obj = var.compatible(dict_var, run_env) + if scheme_var is not None: + compat_obj = var.compatible(scheme_var, run_env, is_host_var=True) + else: + compat_obj = var.compatible(dict_var, run_env) + # end if # end if - return found_var, dict_var, var_vdim, new_vdims, compat_obj + return found_var, dict_var, local_var, var_vdim, new_vdims, compat_obj, scheme_var def part(self, index, error=True): """Return one of this SuiteObject's parts raise an exception, or, @@ -965,7 +1005,7 @@ def is_local_variable(self, var): This is an override of the SuiteObject version""" return None - def analyze(self, phase, group, scheme_library, suite_vars, level): + def analyze(self, phase, group, scheme_library, suite_vars, level, host_dict): """Analyze the scheme's interface to prepare for writing""" self.__group = group my_header = None @@ -1000,26 +1040,45 @@ def analyze(self, phase, group, scheme_library, suite_vars, level): def_val = var.get_prop_value('default_value') vdims = var.get_dimensions() vintent = var.get_prop_value('intent') - args = self.match_variable(var, self.run_env) - found, dict_var, vert_dim, new_dims, compat_obj = args + args = self.match_variable(var, self.run_env, host_dict) + found, dict_var, local_var, var_vdim, new_dims, compat_obj, scheme_var = args + if dict_var: + if dict_var.is_ddt(): + subst_dict = {'intent':'inout'} + else: + subst_dict = {'intent': var.get_prop_value('intent')} + # end if + clone = dict_var.clone(subst_dict) + dict_var = clone + # end if if found: # Hack to get the missing dimensions promoted to the right place # Add variable allocation checks for group, suite and host variables if dict_var: - self.handle_downstream_variables(dict_var) - # end if - if not self.has_vertical_dim: - self.__has_vertical_dimension = vert_dim is not None + if local_var: + self.handle_downstream_variables(local_var) + else: + self.handle_downstream_variables(dict_var) + # end if # end if # We have a match, make sure var is in call list if new_dims == vdims: self.add_call_list_variable(var, exists_ok=True, gen_unique=True) - self.update_group_call_list_variable(var) + if dict_var: + self.update_group_call_list_variable(dict_var) + else: + self.update_group_call_list_variable(var) + # end if else: subst_dict = {'dimensions':new_dims} clone = var.clone(subst_dict) self.add_call_list_variable(clone, exists_ok=True) - self.update_group_call_list_variable(clone) + if dict_var: + clone = dict_var.clone(subst_dict) + self.update_group_call_list_variable(clone) + else: + self.update_group_call_list_variable(clone) + # end if # end if else: if vintent == 'out': @@ -1028,7 +1087,11 @@ def analyze(self, phase, group, scheme_library, suite_vars, level): raise ParseInternalError(errmsg) # end if # The Group will manage this variable - self.__group.manage_variable(var) + if dict_var: + self.__group.manage_variable(dict_var) + else: + self.__group.manage_variable(var) + # end if self.add_call_list_variable(var) elif def_val and (vintent != 'out'): if self.__group is None: @@ -1036,7 +1099,11 @@ def analyze(self, phase, group, scheme_library, suite_vars, level): raise ParseInternalError(errmsg) # end if # The Group will manage this variable - self.__group.manage_variable(var) + if dict_var: + self.__group.manage_variable(dict_var) + else: + self.__group.manage_variable(var) + # end if # We still need it in our call list (the group uses a clone) self.add_call_list_variable(var) else: @@ -1061,21 +1128,42 @@ def analyze(self, phase, group, scheme_library, suite_vars, level): if compat_obj is not None and (compat_obj.has_vert_transforms or compat_obj.has_unit_transforms or compat_obj.has_kind_transforms): - self.add_var_transform(var, compat_obj, vert_dim) + if scheme_var is not None: + self.add_var_transform(scheme_var, compat_obj) + else: + self.add_var_transform(var, compat_obj) + # end if has_transform = True # end if # Is this a conditionally allocated variable? - # If so, declare localpointer variable. This is needed to - # pass inactive (not present) status through the caps. + # If so, declare local pointer variable. This is needed to + # pass inactive (not present) status through the Scheme call_lists. if var.get_prop_value('optional'): - newvar_ptr = var.clone(var.get_prop_value('local_name')+'_ptr') - self.__optional_vars.append([dict_var, var, newvar_ptr, has_transform]) + #if dict_var: + self.add_optional_var(dict_var, var, has_transform) + # end if # end if # end for return scheme_mods + def add_optional_var(self, dict_var, var, has_transform): + """Add local pointer needed for optional variable(s) in Group Cap. Also, + add any host variables from active condition that are needed to associate + the local pointer correctly.""" + + lname = var.get_prop_value('local_name') + sname = var.get_prop_value('standard_name') + lname_ptr = lname + '_ptr' + newvar_ptr = var.clone(lname_ptr) + # Group write phase needs new pointer variable for declaration step. + self.__group.optional_vars.append(newvar_ptr) + # Scheme write phase needs more info for transformations/local-pointer assignments. + self.__optional_vars.append([dict_var, var, has_transform]) + return + # end def + def handle_downstream_variables(self, var): """Ensure all dimension and optional variable arguments are available""" # Get the basic attributes that decide whether we need @@ -1134,40 +1222,116 @@ def handle_downstream_variables(self, var): self.update_group_call_list_variable(udim_var) # end if - def associate_optional_var(self, dict_var, var, var_ptr, has_transform, cldicts, indent, outfile): - """Write local pointer association for optional variables.""" + def associate_optional_var(self, dict_var, var, has_transform, cldicts, indent, outfile): + """Write local pointer association for optional variable.""" + # Use the local name from the Scheme call list, append "_ptr" suffix. + standard_name = var.get_prop_value('standard_name') + dvar = self.__group.call_list.find_variable(standard_name=standard_name, any_scope=False) + search_dict = self.__group.call_list + if dvar: + var_in_call_list = True + # If we find a call_list variable that is a DDT, check to see if it has components. + # Variables that are components of a DDT are NOT part of the call_list. + if dvar.is_ddt(): + if dvar.components: + var_in_call_list = False + # end if + # end if + else: + var_in_call_list = False + # If it is not in the call list, try to find it + # in the local variables of this group subroutine. + dvar = self.__group.find_variable(standard_name=standard_name, any_scope=False) + if not dvar: + # This variable is handled by the group + # and is declared as a module variable + for var_dict in self.__group.suite_dicts(): + dvar = var_dict.find_variable(standard_name=standard_name, any_scope=False) + if dvar: + search_dict = var_dict + break + # end if + # end for + # end if + # end if + if not dvar: + raise Exception(f"No variable with standard name '{standard_name}' in cldicts") + # end if + + # Handle the dimensions... + dimensions = dvar.get_dimensions() + # Need to use local_name in Group's call list (self.__group.call_list), + # not the local_name in var. if (dict_var): - (conditional, _) = dict_var.conditional(cldicts) + (conditional, _) = dvar.conditional(cldicts) if (has_transform): lname = var.get_prop_value('local_name')+'_local' else: - lname = var.get_prop_value('local_name') + lname = dvar.call_dimstring(var_dicts=cldicts, explicit_dims=True, loop_subst=self.run_phase(), prepend_varname=True) + + # end if + lname_ptr = var.get_prop_value('local_name') + '_ptr' + # Scheme has optional varaible, host has varaible defined as Conditional (Active). + if conditional != '.true.': + outfile.write(f"if {conditional} then", indent) + outfile.write(f"{lname_ptr} => {lname}", indent+1) + outfile.write(f"end if", indent) + # Scheme has optional varaible, host has varaible defined as Mandatory. + else: + outfile.write(f"{lname_ptr} => {lname}", indent) # end if - lname_ptr = var_ptr.get_prop_value('local_name') - outfile.write(f"if {conditional} then", indent) - outfile.write(f"{lname_ptr} => {lname}", indent+1) - outfile.write(f"end if", indent) # end if + # end def - def assign_pointer_to_var(self, dict_var, var, var_ptr, has_transform, cldicts, indent, outfile): - """Assign local pointer to variable.""" + def nullify_optional_var(self, dict_var, var, has_transform, cldicts, indent, outfile): + """Write local pointer nullification for optional variable.""" + + standard_name = var.get_prop_value('standard_name') + dvar = self.__group.call_list.find_variable(standard_name=standard_name, any_scope=False) + search_dict = self.__group.call_list + if dvar: + var_in_call_list = True + else: + var_in_call_list = False + # If it is not in the call list, try to find it + # in the local variables of this group subroutine. + dvar = self.__group.find_variable(standard_name=standard_name, any_scope=False) + if not dvar: + # This variable is handled by the group + # and is declared as a module variable + for var_dict in self.__group.suite_dicts(): + dvar = var_dict.find_variable(standard_name=standard_name, any_scope=False) + if dvar: + search_dict = var_dict + break + # end if + # end for + # end if + # end if + + # Need to use local_name in Group's call list (self.__group.call_list), not + # the local_name in var. if (dict_var): - intent = var.get_prop_value('intent') - if (intent == 'out' or intent == 'inout'): - (conditional, _) = dict_var.conditional(cldicts) - if (has_transform): - lname = var.get_prop_value('local_name')+'_local' - else: - lname = var.get_prop_value('local_name') - # end if - lname_ptr = var_ptr.get_prop_value('local_name') + (conditional, vars_needed) = dvar.conditional(cldicts) + if (has_transform): + lname = dvar.get_prop_value('local_name')+'_local' + else: + lname = dvar.get_prop_value('local_name') + # end if + lname_ptr = var.get_prop_value('local_name') + '_ptr' + # Scheme has optional varaible, host has varaible defined as Conditional (Active). + if conditional != '.true.': outfile.write(f"if {conditional} then", indent) - outfile.write(f"{lname} = {lname_ptr}", indent+1) + outfile.write(f"nullify({lname_ptr})", indent+1) outfile.write(f"end if", indent) + # Scheme has optional varaible, host has varaible defined as Mandatory. + else: + outfile.write(f"nullify({lname_ptr})", indent) # end if # end if + # end def - def add_var_transform(self, var, compat_obj, vert_dim): + def add_var_transform(self, var, compat_obj): """Register any variable transformation needed by for this Scheme. For any transformation identified in , create dummy variable from to perform the transformation. Determine the indices needed @@ -1198,9 +1362,9 @@ def add_var_transform(self, var, compat_obj, vert_dim): rindices = [':']*var.get_rank() # If needed, modify vertical dimension for vertical orientation flipping - _, vdim = find_vertical_dimension(var.get_dimensions()) + var_vdim, vdim = find_vertical_dimension(var.get_dimensions()) if vdim >= 0: - vdims = vert_dim.split(':') + vdims = var_vdim.split(':') vdim_name = vdims[-1] group_vvar = self.__group.call_list.find_variable(vdim_name) if group_vvar is None: @@ -1226,9 +1390,24 @@ def add_var_transform(self, var, compat_obj, vert_dim): # end if # If needed, modify horizontal dimension for loop substitution. - # NOT YET IMPLEMENTED - #hdim = find_horizontal_dimension(var.get_dimensions()) - #if compat_obj.has_dim_transforms: + var_hdim,hdim = find_horizontal_dimension(var.get_dimensions()) + if var_hdim: + if self.run_phase(): + ldim = "horizontal_loop_begin" + udim = "horizontal_loop_end" + else: + ldim = "ccpp_constant_one" + udim = "horizontal_dimension" + # end if + lvar = self.find_variable(ldim) + if lvar is None: + raise CCPPError(f"add_var_transform: Cannot find dimension variable, {ldim}") + # end if + uvar = self.find_variable(udim) + if uvar is None: + raise CCPPError(f"add_var_transform: Cannot find dimension variable, {udim}") + # end if + rindices[hdim] = lvar.get_prop_value('local_name')+':'+uvar.get_prop_value('local_name') # Register any reverse (pre-Scheme) transforms. Also, save local_name used in # transform (used in write stage). @@ -1255,8 +1434,9 @@ def add_var_transform(self, var, compat_obj, vert_dim): local_trans_var.get_prop_value('local_name'), lindices, rindices, compat_obj]) # end if - def write_var_transform(self, var, dummy, rindices, lindices, compat_obj, - outfile, indent, forward): + + def write_var_transform(self, var, var_name, dummy, rindices, lindices, compat_obj, + outfile, indent, forward, cldicts): """Write variable transformation needed to call this Scheme in . is the variable that needs transformation before and after calling Scheme. is the local variable needed for the transformation.. @@ -1271,7 +1451,7 @@ def write_var_transform(self, var, dummy, rindices, lindices, compat_obj, if not forward: # dummy(lindices) = var(rindices) stmt = compat_obj.reverse_transform(lvar_lname=dummy, - rvar_lname=var, + rvar_lname=var_name, lvar_indices=lindices, rvar_indices=rindices) # @@ -1279,12 +1459,21 @@ def write_var_transform(self, var, dummy, rindices, lindices, compat_obj, # else: # var(lindices) = dummy(rindices) - stmt = compat_obj.forward_transform(lvar_lname=var, + stmt = compat_obj.forward_transform(lvar_lname=var_name, rvar_lname=dummy, lvar_indices=rindices, rvar_indices=lindices) # end if - outfile.write(stmt, indent) + + (conditional, vars_needed) = var.conditional(cldicts) + if conditional != '.true.': + outfile.write(f"if {conditional} then", indent) + outfile.write(stmt, indent+1) + outfile.write(f"end if", indent) + # Scheme has optional varaible, host has varaible defined as Mandatory. + else: + outfile.write(stmt, indent) + # end if def write(self, outfile, errcode, errmsg, indent): # Unused arguments are for consistent write interface @@ -1313,8 +1502,8 @@ def write(self, outfile, errcode, errmsg, indent): # from and replace its local_name with the local_name from the # Group's call_list. lvar = self.__group.call_list.find_variable(standard_name=var_sname) - lvar_lname = lvar.get_prop_value('local_name') - tstmt = self.write_var_transform(lvar_lname, dummy, rindices, lindices, compat_obj, outfile, indent+1, False) + lvar_lname = lvar.call_string(self.__group.call_list) + tstmt = self.write_var_transform(lvar, lvar_lname, dummy, rindices, lindices, compat_obj, outfile, indent+1, False, cldicts) # end for outfile.write('',indent+1) # @@ -1323,8 +1512,8 @@ def write(self, outfile, errcode, errmsg, indent): if self.__optional_vars: outfile.write('! Associate conditional variables', indent+1) # end if - for (dict_var, var, var_ptr, has_transform) in self.__optional_vars: - tstmt = self.associate_optional_var(dict_var, var, var_ptr, has_transform, cldicts, indent+1, outfile) + for (dict_var, var, has_transform) in self.__optional_vars: + tstmt = self.associate_optional_var(dict_var, var, has_transform, cldicts, indent+1, outfile) # end for # # Write the scheme call. @@ -1336,18 +1525,15 @@ def write(self, outfile, errcode, errmsg, indent): outfile.write(stmt.format(self.subroutine_name, my_args), indent+1) outfile.write('',indent+1) # end if + # - # Copy any local pointers. + # Nullify any local pointers. # - first_ptr_declaration=True - for (dict_var, var, var_ptr, has_transform) in self.__optional_vars: - if first_ptr_declaration: - outfile.write('! Copy any local pointers to dummy/local variables', indent+1) - first_ptr_declaration=False - # end if - tstmt = self.assign_pointer_to_var(dict_var, var, var_ptr, has_transform, cldicts, indent+1, outfile) - # end for - outfile.write('',indent+1) + if self.__optional_vars: + outfile.write('! Nullify conditional variables', indent+1) + # end if + for (dict_var, var, has_transform) in self.__optional_vars: + tstmt = self.nullify_optional_var(dict_var, var, has_transform, cldicts, indent+1, outfile) # # Write any forward (post-Scheme) transforms. # @@ -1361,8 +1547,8 @@ def write(self, outfile, errcode, errmsg, indent): # from and replace its local_name with the local_name from the # Group's call_list. lvar = self.__group.call_list.find_variable(standard_name=var_sname) - lvar_lname = lvar.get_prop_value('local_name') - tstmt = self.write_var_transform(lvar_lname, dummy, rindices, lindices, compat_obj, outfile, indent+1, True) + lvar_lname = lvar.call_string(self.__group.call_list) + tstmt = self.write_var_transform(lvar, lvar_lname, dummy, rindices, lindices, compat_obj, outfile, indent+1, True, cldicts) # end for outfile.write('', indent) outfile.write('end if', indent) @@ -1437,7 +1623,7 @@ def __init__(self, sub_xml, context, parent, run_env, loop_count=0): self.add_part(new_item) # end for - def analyze(self, phase, group, scheme_library, suite_vars, level): + def analyze(self, phase, group, scheme_library, suite_vars, level, host_dict): """Analyze the Subcycle's interface to prepare for writing""" if self.name is None: self.name = "subcycle_index{}".format(level) @@ -1451,7 +1637,7 @@ def analyze(self, phase, group, scheme_library, suite_vars, level): scheme_mods = set() for item in self.parts: smods = item.analyze(phase, group, scheme_library, - suite_vars, level+1) + suite_vars, level+1, host_dict) for smod in smods: scheme_mods.add(smod) # end for @@ -1530,6 +1716,7 @@ def __init__(self, group_xml, transition, parent, context, run_env): self._set_state = None self._ddt_library = None self.transform_locals = list() + self.optional_vars = list() def phase_match(self, scheme_name): """If scheme_name matches the group phase, return the group and @@ -1633,7 +1820,7 @@ def manage_variable(self, newvar): # end if def analyze(self, phase, suite_vars, scheme_library, ddt_library, - check_suite_state, set_suite_state): + check_suite_state, set_suite_state, host_dict): """Analyze the Group's interface to prepare for writing""" self._ddt_library = ddt_library # Sanity check for Group @@ -1646,7 +1833,7 @@ def analyze(self, phase, suite_vars, scheme_library, ddt_library, # Items can be schemes, subcycles or other objects # All have the same interface and return a set of module use # statements (lschemes) - lschemes = item.analyze(phase, self, scheme_library, suite_vars, 1) + lschemes = item.analyze(phase, self, scheme_library, suite_vars, 1, host_dict) for lscheme in lschemes: self._local_schemes.add(lscheme) # end for @@ -1692,7 +1879,8 @@ def allocate_dim_str(self, dims, context): def find_variable(self, standard_name=None, source_var=None, any_scope=True, clone=None, - search_call_list=False, loop_subst=False): + search_call_list=False, loop_subst=False, + check_components=True): """Find a matching variable to , create a local clone (if is True), or return None. This purpose of this special Group version is to record any constituent @@ -1702,7 +1890,8 @@ def find_variable(self, standard_name=None, source_var=None, source_var=source_var, any_scope=any_scope, clone=clone, search_call_list=search_call_list, - loop_subst=loop_subst) + loop_subst=loop_subst, + check_components=check_components) if fvar and fvar.is_constituent(): if fvar.source.ptype == ConstituentVarDict.constitutent_source_type(): # We found this variable in the constituent dictionary, @@ -1726,17 +1915,15 @@ def write(self, outfile, host_arglist, indent, const_mod, # end if # Collect information on local variables subpart_allocate_vars = {} - subpart_optional_vars = {} subpart_scalar_vars = {} allocatable_var_set = set() optional_var_set = set() pointer_var_set = list() - inactive_var_set = set() for item in [self]:# + self.parts: for var in item.declarations(): lname = var.get_prop_value('local_name') sname = var.get_prop_value('standard_name') - if (lname in subpart_allocate_vars) or (lname in subpart_optional_vars) or (lname in subpart_scalar_vars): + if (lname in subpart_allocate_vars) or (lname in subpart_scalar_vars): if subpart_allocate_vars[lname][0].compatible(var, self.run_env): pass # We already are going to declare this variable else: @@ -1744,50 +1931,18 @@ def write(self, outfile, host_arglist, indent, const_mod, raise ParseInternalError(errmsg.format(lname)) # end if else: - opt_var = var.get_prop_value('optional') dims = var.get_dimensions() if (dims is not None) and dims: - if opt_var: - if (self.call_list.find_variable(standard_name=sname)): - subpart_optional_vars[lname] = (var, item, opt_var) - optional_var_set.add(lname) - else: - inactive_var_set.add(var) - # end if - else: - subpart_allocate_vars[lname] = (var, item, opt_var) - allocatable_var_set.add(lname) - # end if - else: - subpart_scalar_vars[lname] = (var, item, opt_var) - # end if - # end if - # end for - # All optional dummy variables within group need to have - # an associated pointer array declared. - for cvar in self.call_list.variable_list(): - opt_var = cvar.get_prop_value('optional') - if opt_var: - name = cvar.get_prop_value('local_name')+'_ptr' - kind = cvar.get_prop_value('kind') - dims = cvar.get_dimensions() - if cvar.is_ddt(): - vtype = 'type' - else: - vtype = cvar.get_prop_value('type') - # end if - if dims: - dimstr = '(:' + ',:'*(len(dims) - 1) + ')' + subpart_allocate_vars[lname] = (var, item, False) + allocatable_var_set.add(lname) else: - dimstr = '' + subpart_scalar_vars[lname] = (var, item, False) # end if - pointer_var_set.append([name,kind,dimstr,vtype]) # end if # end for - # Any optional arguments that are not requested by the host need to have - # a local null pointer passed from the group to the scheme. - for ivar in inactive_var_set: - name = ivar.get_prop_value('local_name')+'_ptr' + # All optional variables for the Schemes need to have an associated pointer array declared. + for ivar in self.optional_vars: + name = ivar.get_prop_value('local_name') kind = ivar.get_prop_value('kind') dims = ivar.get_dimensions() if ivar.is_ddt(): @@ -1839,8 +1994,7 @@ def write(self, outfile, host_arglist, indent, const_mod, # Look for any DDT types call_vars = self.call_list.variable_list() all_vars = ([x[0] for x in subpart_allocate_vars.values()] + - [x[0] for x in subpart_scalar_vars.values()] + - [x[0] for x in subpart_optional_vars.values()]) + [x[0] for x in subpart_scalar_vars.values()]) all_vars.extend(call_vars) self._ddt_library.write_ddt_use_statements(all_vars, outfile, indent+1, pad=modmax) @@ -1854,7 +2008,7 @@ def write(self, outfile, host_arglist, indent, const_mod, # end if self.call_list.declare_variables(outfile, indent+1, dummy=True) # DECLARE local variables - if subpart_allocate_vars or subpart_scalar_vars or subpart_optional_vars: + if subpart_allocate_vars or subpart_scalar_vars: outfile.write('\n! Local Variables', indent+1) # end if # Scalars @@ -1874,18 +2028,14 @@ def write(self, outfile, host_arglist, indent, const_mod, allocatable=(key in allocatable_var_set), target=target) # end for - # Target arrays. - for key in subpart_optional_vars: - var = subpart_optional_vars[key][0] - spdict = subpart_optional_vars[key][1] - target = subpart_optional_vars[key][2] - var.write_def(outfile, indent+1, spdict, - allocatable=(key in optional_var_set), - target=target) # end for # Pointer variables + outfile.write('', 0) + if pointer_var_set: + outfile.write('! Local pointer variables', indent+1) + # end if for (name, kind, dim, vtype) in pointer_var_set: - var.write_ptr_def(outfile, indent+1, name, kind, dim, vtype) + write_ptr_def(outfile, indent+1, name, kind, dim, vtype) # end for outfile.write('', 0) # Get error variable names @@ -1941,12 +2091,6 @@ def write(self, outfile, host_arglist, indent, const_mod, alloc_str = self.allocate_dim_str(dims, var.context) outfile.write(alloc_stmt.format(lname, alloc_str), indent+1) # end for - for lname in optional_var_set: - var = subpart_optional_vars[lname][0] - dims = var.get_dimensions() - alloc_str = self.allocate_dim_str(dims, var.context) - outfile.write(alloc_stmt.format(lname, alloc_str), indent+1) - # end for # Allocate suite vars if allocate: outfile.write('\n! Allocate suite_vars', indent+1) @@ -1977,14 +2121,6 @@ def write(self, outfile, host_arglist, indent, const_mod, for lname in optional_var_set: outfile.write('if (allocated({})) {} deallocate({})'.format(lname,' '*(20-len(lname)),lname), indent+1) # end for - # Nullify local pointers - if pointer_var_set: - outfile.write('\n! Nullify local pointers', indent+1) - # end if - for (name, kind, dim, vtype) in pointer_var_set: - #cspace = ' '*(15-len(name)) - outfile.write('if (associated({})) {} nullify({})'.format(name,' '*(15-len(name)),name), indent+1) - # end fo # Deallocate suite vars if deallocate: for svar in suite_vars.variable_list(): diff --git a/test/README.md b/test/README.md index 03363532..62272d16 100644 --- a/test/README.md +++ b/test/README.md @@ -49,6 +49,7 @@ There are several `...` to enable tests: 3) `-DCCPP_RUN_CAPGEN_TEST=ON` Turns on only the capgen test 4) `-DCCPP_RUN_DDT_HOST_TEST=ON` Turns on only the ddt host test 5) `-DCCPP_RUN_VAR_COMPATIBILITY_TEST=ON` Turns on only the variable compatibility test +5) `-DCCPP_RUN_NESTED_SUITE_TEST=ON` Turns on only the nested suite test By default, the tests will build in debug mode. To enable release mode, you will need to set the build type: `-DCMAKE_BUILD_TYPE=Release` (or if you want release with debug symbols: `-DCMAKE_BUILD_TYPE=RelWithDebInfo`). diff --git a/test/advection_test/advection_test_reports.py b/test/advection_test/advection_test_reports.py index 4fbe8e68..9673b171 100644 --- a/test/advection_test/advection_test_reports.py +++ b/test/advection_test/advection_test_reports.py @@ -39,51 +39,49 @@ _SUITE_LIST = ["cld_suite"] _REQUIRED_VARS_CLD = ["ccpp_error_code", "ccpp_error_message", "horizontal_loop_begin", "horizontal_loop_end", - "surface_air_pressure", "temperature", + "physics_state_derived_type", + "index_of_water_vapor_specific_humidity", "tendency_of_cloud_liquid_dry_mixing_ratio", "time_step_for_physics", "water_temperature_at_freezing", - "water_vapor_specific_humidity", "cloud_ice_dry_mixing_ratio", "cloud_liquid_dry_mixing_ratio", - "ccpp_constituents", - "ccpp_constituent_tendencies", - "number_of_ccpp_constituents", + "ccpp_model_constituents_object", "dynamic_constituents_for_cld_ice", "dynamic_constituents_for_cld_liq", "test_banana_constituent_indices", "test_banana_name", "banana_array_dim", "test_banana_name_array", "test_banana_constituent_index", + "water_vapor_specific_humidity_not_state", # Added by --debug option "horizontal_dimension", "vertical_layer_dimension"] -_INPUT_VARS_CLD = ["surface_air_pressure", "temperature", - "horizontal_loop_begin", "horizontal_loop_end", +_INPUT_VARS_CLD = ["horizontal_loop_begin", "horizontal_loop_end", "time_step_for_physics", "water_temperature_at_freezing", - "water_vapor_specific_humidity", "cloud_ice_dry_mixing_ratio", "cloud_liquid_dry_mixing_ratio", "tendency_of_cloud_liquid_dry_mixing_ratio", - "ccpp_constituents", - "ccpp_constituent_tendencies", - "number_of_ccpp_constituents", + "ccpp_model_constituents_object", + "physics_state_derived_type", + "index_of_water_vapor_specific_humidity", "banana_array_dim", "test_banana_name_array", "test_banana_name", + "water_vapor_specific_humidity_not_state", # Added by --debug option "horizontal_dimension", "vertical_layer_dimension"] _OUTPUT_VARS_CLD = ["ccpp_error_code", "ccpp_error_message", - "water_vapor_specific_humidity", "temperature", "tendency_of_cloud_liquid_dry_mixing_ratio", "cloud_ice_dry_mixing_ratio", - "ccpp_constituents", - "ccpp_constituent_tendencies", + "ccpp_model_constituents_object", + "physics_state_derived_type", "cloud_liquid_dry_mixing_ratio", "dynamic_constituents_for_cld_ice", "dynamic_constituents_for_cld_liq", "dynamic_constituents_for_cld_liq", "test_banana_constituent_indices", - "test_banana_constituent_index"] + "test_banana_constituent_index", + "water_vapor_specific_humidity_not_state"] class TestAdvectionHostDataTables(unittest.TestCase, BaseTests.TestHostDataTables): diff --git a/test/advection_test/cld_ice.F90 b/test/advection_test/cld_ice.F90 index 3ace2f91..32f9e92e 100644 --- a/test/advection_test/cld_ice.F90 +++ b/test/advection_test/cld_ice.F90 @@ -48,13 +48,14 @@ end subroutine cld_ice_register !> \section arg_table_cld_ice_run Argument Table !! \htmlinclude arg_table_cld_ice_run.html !! - subroutine cld_ice_run(ncol, timestep, temp, qv, ps, cld_ice_array, & + subroutine cld_ice_run(ncol, timestep, temp, qv, qv_not_state, ps, cld_ice_array, & errmsg, errflg) integer, intent(in) :: ncol real(kind=kind_phys), intent(in) :: timestep real(kind=kind_phys), intent(inout) :: temp(:, :) real(kind=kind_phys), intent(inout) :: qv(:, :) + real(kind=kind_phys), intent(inout) :: qv_not_state(:, :) real(kind=kind_phys), intent(in) :: ps(:) real(kind=kind_phys), intent(inout) :: cld_ice_array(:, :) character(len=512), intent(out) :: errmsg @@ -75,6 +76,7 @@ subroutine cld_ice_run(ncol, timestep, temp, qv, ps, cld_ice_array, & frz = max(qv(icol, ilev) - 0.5_kind_phys, 0.0_kind_phys) cld_ice_array(icol, ilev) = cld_ice_array(icol, ilev) + frz qv(icol, ilev) = qv(icol, ilev) - frz + qv_not_state(icol, ilev) = qv_not_state(icol, ilev) - frz if (frz > 0.0_kind_phys) then temp(icol, ilev) = temp(icol, ilev) + 1.0_kind_phys end if diff --git a/test/advection_test/cld_ice.meta b/test/advection_test/cld_ice.meta index e57d0b08..63b0d749 100644 --- a/test/advection_test/cld_ice.meta +++ b/test/advection_test/cld_ice.meta @@ -58,6 +58,13 @@ type = real kind = kind_phys intent = inout +[ qv_not_state ] + standard_name = water_vapor_specific_humidity_not_state + units = kg kg-1 + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout [ ps ] standard_name = surface_air_pressure state_variable = true diff --git a/test/advection_test/cld_liq.F90 b/test/advection_test/cld_liq.F90 index cb02cf11..e12a667b 100644 --- a/test/advection_test/cld_liq.F90 +++ b/test/advection_test/cld_liq.F90 @@ -41,7 +41,7 @@ end subroutine cld_liq_register !> \section arg_table_cld_liq_run Argument Table !! \htmlinclude arg_table_cld_liq_run.html !! - subroutine cld_liq_run(ncol, timestep, tcld, temp, qv, ps, & + subroutine cld_liq_run(ncol, timestep, tcld, temp, qv, qv_not_state, ps, & cld_liq_tend, errmsg, errflg) integer, intent(in) :: ncol @@ -49,6 +49,7 @@ subroutine cld_liq_run(ncol, timestep, tcld, temp, qv, ps, & real(kind=kind_phys), intent(in) :: tcld real(kind=kind_phys), intent(inout) :: temp(:, :) real(kind=kind_phys), intent(inout) :: qv(:, :) + real(kind=kind_phys), intent(inout) :: qv_not_state(:, :) real(kind=kind_phys), intent(in) :: ps(:) real(kind=kind_phys), intent(inout) :: cld_liq_tend(:, :) character(len=512), intent(out) :: errmsg @@ -70,6 +71,7 @@ subroutine cld_liq_run(ncol, timestep, tcld, temp, qv, ps, & cond = min(qv(icol, ilev), 0.1_kind_phys) cld_liq_tend(icol, ilev) = cond qv(icol, ilev) = qv(icol, ilev) - cond + qv_not_state(icol, ilev) = qv_not_state(icol, ilev) - cond if (cond > 0.0_kind_phys) then temp(icol, ilev) = temp(icol, ilev) + (cond * 5.0_kind_phys) end if diff --git a/test/advection_test/cld_liq.meta b/test/advection_test/cld_liq.meta index b3ef3a0d..319b1463 100644 --- a/test/advection_test/cld_liq.meta +++ b/test/advection_test/cld_liq.meta @@ -63,6 +63,13 @@ type = real kind = kind_phys intent = inout +[ qv_not_state ] + standard_name = water_vapor_specific_humidity_not_state + units = kg kg-1 + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout [ ps ] standard_name = surface_air_pressure state_variable = true diff --git a/test/advection_test/test_advection_host_integration.F90 b/test/advection_test/test_advection_host_integration.F90 index 0ee54da7..f392bd88 100644 --- a/test/advection_test/test_advection_host_integration.F90 +++ b/test/advection_test/test_advection_host_integration.F90 @@ -7,60 +7,54 @@ program test implicit none character(len=cs), target :: test_parts1(1) - character(len=cm), target :: test_invars1(12) - character(len=cm), target :: test_outvars1(13) - character(len=cm), target :: test_reqvars1(18) + character(len=cm), target :: test_invars1(9) + character(len=cm), target :: test_outvars1(12) + character(len=cm), target :: test_reqvars1(15) type(suite_info) :: test_suites(1) logical :: run_okay test_parts1 = (/ 'physics '/) + test_invars1 = (/ & - 'banana_array_dim ', & + 'ccpp_model_constituents_object ', & 'cloud_ice_dry_mixing_ratio ', & 'cloud_liquid_dry_mixing_ratio ', & + 'physics_state_derived_type ', & 'tendency_of_cloud_liquid_dry_mixing_ratio', & - 'surface_air_pressure ', & - 'temperature ', & + 'banana_array_dim ', & 'time_step_for_physics ', & - 'water_temperature_at_freezing ', & - 'ccpp_constituent_tendencies ', & - 'ccpp_constituents ', & - 'number_of_ccpp_constituents ', & - 'water_vapor_specific_humidity ' /) + 'water_vapor_specific_humidity_not_state ', & + 'water_temperature_at_freezing ' /) test_outvars1 = (/ & - 'ccpp_error_message ', & - 'ccpp_error_code ', & - 'temperature ', & - 'water_vapor_specific_humidity ', & + 'ccpp_model_constituents_object ', & + 'water_vapor_specific_humidity_not_state ', & + 'cloud_ice_dry_mixing_ratio ', & 'cloud_liquid_dry_mixing_ratio ', & - 'ccpp_constituent_tendencies ', & - 'ccpp_constituents ', & - 'dynamic_constituents_for_cld_liq ', & - 'dynamic_constituents_for_cld_ice ', & + 'physics_state_derived_type ', & 'tendency_of_cloud_liquid_dry_mixing_ratio', & + 'ccpp_error_code ', & + 'ccpp_error_message ', & + 'dynamic_constituents_for_cld_ice ', & + 'dynamic_constituents_for_cld_liq ', & 'test_banana_constituent_index ', & - 'test_banana_constituent_indices ', & - 'cloud_ice_dry_mixing_ratio ' /) + 'test_banana_constituent_indices ' /) test_reqvars1 = (/ & - 'banana_array_dim ', & - 'surface_air_pressure ', & - 'temperature ', & - 'time_step_for_physics ', & + 'ccpp_model_constituents_object ', & + 'cloud_ice_dry_mixing_ratio ', & 'cloud_liquid_dry_mixing_ratio ', & + 'physics_state_derived_type ', & 'tendency_of_cloud_liquid_dry_mixing_ratio', & - 'cloud_ice_dry_mixing_ratio ', & - 'dynamic_constituents_for_cld_liq ', & - 'dynamic_constituents_for_cld_ice ', & + 'water_vapor_specific_humidity_not_state ', & + 'banana_array_dim ', & + 'time_step_for_physics ', & 'water_temperature_at_freezing ', & - 'ccpp_constituent_tendencies ', & - 'ccpp_constituents ', & - 'number_of_ccpp_constituents ', & - 'test_banana_constituent_index ', & - 'test_banana_constituent_indices ', & - 'water_vapor_specific_humidity ', & + 'ccpp_error_code ', & 'ccpp_error_message ', & - 'ccpp_error_code ' /) + 'dynamic_constituents_for_cld_ice ', & + 'dynamic_constituents_for_cld_liq ', & + 'test_banana_constituent_index ', & + 'test_banana_constituent_indices ' /) ! Setup expected test suite info test_suites(1)%suite_name = 'cld_suite' diff --git a/test/advection_test/test_host.F90 b/test/advection_test/test_host.F90 index cc8bbf89..df9812fa 100644 --- a/test/advection_test/test_host.F90 +++ b/test/advection_test/test_host.F90 @@ -78,7 +78,8 @@ logical function check_suite(test_suite) end if ! Check the input variables call ccpp_physics_suite_variables(test_suite%suite_name, test_list, & - errmsg, errflg, input_vars=.true., output_vars=.false.) + errmsg, errflg, input_vars=.true., output_vars=.false., & + struct_elements=.false.) if (errflg == 0) then check = check_list(test_list, test_suite%suite_input_vars, & 'input variable names', suite_name=test_suite%suite_name) @@ -92,7 +93,8 @@ logical function check_suite(test_suite) end if ! Check the output variables call ccpp_physics_suite_variables(test_suite%suite_name, test_list, & - errmsg, errflg, input_vars=.false., output_vars=.true.) + errmsg, errflg, input_vars=.false., output_vars=.true., & + struct_elements=.false.) if (errflg == 0) then check = check_list(test_list, test_suite%suite_output_vars, & 'output variable names', suite_name=test_suite%suite_name) @@ -106,7 +108,7 @@ logical function check_suite(test_suite) end if ! Check all required variables call ccpp_physics_suite_variables(test_suite%suite_name, test_list, & - errmsg, errflg) + errmsg, errflg, struct_elements=.false.) if (errflg == 0) then check = check_list(test_list, test_suite%suite_required_vars, & 'required variable names', suite_name=test_suite%suite_name) @@ -122,7 +124,7 @@ end function check_suite subroutine advect_constituents() use test_host_mod, only: phys_state, & - ncnst + ncnst, q_not_state use test_host_mod, only: twist_array ! Local variables @@ -130,6 +132,7 @@ subroutine advect_constituents() do q_ind = 1, ncnst ! Skip checks, they were done in constituents_in call twist_array(phys_state%q(:, :, q_ind)) + call twist_array(q_not_state(:, :, q_ind)) end do end subroutine advect_constituents diff --git a/test/advection_test/test_host_data.meta b/test/advection_test/test_host_data.meta index a676f141..3f757264 100644 --- a/test/advection_test/test_host_data.meta +++ b/test/advection_test/test_host_data.meta @@ -60,7 +60,6 @@ long_name = Array of constituent indices units = 1 dimensions = (banana_array_dim) - protected = true type = integer [ const_index ] standard_name = test_banana_constituent_index diff --git a/test/advection_test/test_host_mod.F90 b/test/advection_test/test_host_mod.F90 index 5099b9c1..ca417d45 100644 --- a/test/advection_test/test_host_mod.F90 +++ b/test/advection_test/test_host_mod.F90 @@ -18,11 +18,13 @@ module test_host_mod integer, parameter :: pverp = pver + 1 integer, protected :: ncnst = -1 integer, protected :: index_qv = -1 + integer, protected :: index_qv_not_state = -1 real(kind=kind_phys) :: dt real(kind=kind_phys), parameter :: tfreeze = 273.15_kind_phys type(physics_state) :: phys_state integer :: num_model_times = -1 integer, allocatable :: model_times(:) + real(kind=kind_phys), allocatable :: q_not_state(:,:,:) public :: init_data public :: compare_data @@ -58,9 +60,12 @@ subroutine init_data(constituent_array, index_qv_use, index_liq, index_ice, inde ncnst = size(constituent_array, 3) call allocate_physics_state(ncols, pver, constituent_array, phys_state) index_qv = index_qv_use + index_qv_not_state = index_qv_use ind_liq = index_liq ind_ice = index_ice allocate(check_vals(ncols, pver, ncnst)) + allocate(q_not_state(ncols, pver, ncnst)) + q_not_state = constituent_array check_vals(:, :, :) = 0.0_kind_phys check_vals(:, :, index_dyn) = 1.0_kind_phys do lev = 1, pver @@ -69,8 +74,10 @@ subroutine init_data(constituent_array, index_qv_use, index_liq, index_ice, inde do col = 1, ncols if (mod(col, 2) == 1) then phys_state%q(col, lev, index_qv) = qmax + q_not_state(col, lev, index_qv_not_state) = qmax else phys_state%q(col, lev, index_qv) = 0.0_kind_phys + q_not_state(col, lev, index_qv_not_state) = 0.0_kind_phys end if end do end do @@ -167,6 +174,19 @@ logical function compare_data(ncnst) phys_state%q(col, lev, cind), check compare_data = .false. end if + if (cind == index_qv_not_state) then + if (abs((q_not_state(col, lev, cind) - check) / denom) > & + tolerance) then + if (need_header) then + write(6, '(2(2x,a),3x,a,10x,a,14x,a)') & + 'COL', 'LEV', 'C#', 'Q NOT STATE', 'EXPECTED' + need_header = .false. + end if + write(6, '(3i5,2(3x,es15.7))') col, lev, cind, & + q_not_state(col, lev, cind), check + compare_data = .false. + end if + end if end do end do end do diff --git a/test/advection_test/test_host_mod.meta b/test/advection_test/test_host_mod.meta index 9f04a6fc..57bb5baa 100644 --- a/test/advection_test/test_host_mod.meta +++ b/test/advection_test/test_host_mod.meta @@ -34,6 +34,12 @@ type = integer protected = True dimensions = () +[ index_qv_not_state ] + standard_name = index_of_water_vapor_specific_humidity_not_state + units = index + type = integer + protected = True + dimensions = () [ dt ] standard_name = time_step_for_physics long_name = time step @@ -62,3 +68,15 @@ dimensions = (number_of_model_times) type = integer allocatable = True +[ q_not_state ] + standard_name = constituent_mixing_ratio_not_state + type = real + kind = kind_phys + units = kg kg-1 moist or dry air depending on type + dimensions = (horizontal_dimension, vertical_layer_dimension, number_of_tracers) +[ q_not_state(:,:,index_of_water_vapor_specific_humidity_not_state) ] + standard_name = water_vapor_specific_humidity_not_state + type = real + kind = kind_phys + units = kg kg-1 + dimensions = (horizontal_dimension, vertical_layer_dimension) diff --git a/test/capgen_test/capgen_test_reports.py b/test/capgen_test/capgen_test_reports.py index 3c683aab..3b72a8c3 100644 --- a/test/capgen_test/capgen_test_reports.py +++ b/test/capgen_test/capgen_test_reports.py @@ -47,9 +47,9 @@ _SUITE_LIST = ["ddt_suite", "temp_suite"] _INPUT_VARS_DDT = ["model_times", "number_of_model_times", "horizontal_loop_begin", "horizontal_loop_end", - "surface_air_pressure", "horizontal_dimension"] + "physics_state_derived_type", "horizontal_dimension"] _OUTPUT_VARS_DDT = ["ccpp_error_code", "ccpp_error_message", "model_times", - "surface_air_pressure", "number_of_model_times"] + "physics_state_derived_type", "number_of_model_times"] _REQUIRED_VARS_DDT = _INPUT_VARS_DDT + _OUTPUT_VARS_DDT _PROT_VARS_TEMP = ["horizontal_loop_begin", "horizontal_loop_end", "horizontal_dimension", "vertical_layer_dimension", @@ -65,26 +65,25 @@ "potential_temperature_at_interface", "coefficients_for_interpolation", "potential_temperature_increment", - "surface_air_pressure", "time_step_for_physics", - "water_vapor_specific_humidity", - "soil_levels", + "time_step_for_physics", + "physics_state_derived_type", + "do_cloud_fraction_adjustment", "temperature_at_diagnostic_levels", "array_variable_for_testing"] _INPUT_VARS_TEMP = ["potential_temperature", "potential_temperature_at_interface", "coefficients_for_interpolation", "potential_temperature_increment", - "surface_air_pressure", "time_step_for_physics", - "water_vapor_specific_humidity", - "soil_levels", + "time_step_for_physics", + "do_cloud_fraction_adjustment", + "physics_state_derived_type", "temperature_at_diagnostic_levels", "array_variable_for_testing"] _OUTPUT_VARS_TEMP = ["ccpp_error_code", "ccpp_error_message", "potential_temperature", "potential_temperature_at_interface", "coefficients_for_interpolation", - "surface_air_pressure", "water_vapor_specific_humidity", - "soil_levels", + "physics_state_derived_type", "temperature_at_diagnostic_levels", "array_variable_for_testing"] diff --git a/test/capgen_test/source_dir2/temp_set.F90 b/test/capgen_test/source_dir2/temp_set.F90 index be54b80c..c1942519 100644 --- a/test/capgen_test/source_dir2/temp_set.F90 +++ b/test/capgen_test/source_dir2/temp_set.F90 @@ -1,84 +1,84 @@ !Test 3D parameterization ! -module temp_set - - use ccpp_kinds, only: kind_phys, & - kind_temp - - implicit none - private - - public :: temp_set_init - public :: temp_set_timestep_initialize - public :: temp_set_run - public :: temp_set_finalize - -contains - - !> \section arg_table_temp_set_run Argument Table - !! \htmlinclude arg_table_temp_set_run.html - !! - subroutine temp_set_run(ncol, lev, timestep, temp_level, temp_diag, temp, ps, & - to_promote, promote_pcnst, slev_lbound, soil_levs, var_array, errmsg, errflg) - !---------------------------------------------------------------- - implicit none - !---------------------------------------------------------------- - - integer, intent(in) :: ncol, lev, slev_lbound - real(kind=kind_phys), intent(out) :: temp(:, :) - real(kind=kind_phys), intent(in) :: timestep - real(kind=kind_phys), intent(in) :: ps(:) - real(kind=kind_phys), intent(inout) :: temp_level(:, :) - real(kind=kind_phys), intent(inout) :: temp_diag(:, :) - real(kind=kind_phys), intent(inout) :: soil_levs(slev_lbound:) - real(kind=kind_phys), intent(inout) :: var_array(:, :, :, :) - real(kind=kind_temp), intent(out) :: to_promote(:, :) - real(kind=kind_phys), intent(out) :: promote_pcnst(:) - character(len=512), intent(out) :: errmsg - integer, intent(out) :: errflg - !---------------------------------------------------------------- - integer :: ilev - - integer :: col_index - integer :: lev_index - real(kind=kind_phys) :: internal_scalar_var +MODULE temp_set + + USE ccpp_kinds, ONLY: kind_phys, kind_temp + + IMPLICIT NONE + PRIVATE + + PUBLIC :: temp_set_init + PUBLIC :: temp_set_timestep_initialize + PUBLIC :: temp_set_run + PUBLIC :: temp_set_finalize + +CONTAINS + +!> \section arg_table_temp_set_run Argument Table +!! \htmlinclude arg_table_temp_set_run.html +!! + SUBROUTINE temp_set_run(ncol, lev, timestep, temp_level, temp_diag, temp, ps, & + to_promote, promote_pcnst, slev_lbound, soil_levs, var_array, cld_frac, errmsg, errflg) +!---------------------------------------------------------------- + IMPLICIT NONE +!---------------------------------------------------------------- + + integer, intent(in) :: ncol, lev, slev_lbound + REAL(kind_phys), intent(out) :: temp(:,:) + real(kind_phys), intent(in) :: timestep + real(kind_phys), intent(in) :: ps(:) + REAL(kind_phys), INTENT(inout) :: temp_level(:, :) + real(kind_phys), intent(inout) :: temp_diag(:,:) + real(kind_phys), intent(inout) :: soil_levs(slev_lbound:) + real(kind_phys), intent(inout) :: var_array(:,:,:,:) + real(kind_temp), intent(out) :: to_promote(:, :) + real(kind_phys), intent(out) :: promote_pcnst(:) + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg + real(kind_phys), intent(in), optional :: cld_frac(:,:) +!---------------------------------------------------------------- + integer :: ilev + + integer :: col_index + integer :: lev_index + real(kind_phys) :: internal_scalar_var errmsg = '' errflg = 0 ilev = size(temp_level, 2) if (ilev /= (lev + 1)) then - errflg = 1 - errmsg = 'Invalid value for ilev, must be lev+1' - return + errflg = 1 + errmsg = 'Invalid value for ilev, must be lev+1' + return end if do col_index = 1, ncol - do lev_index = 1, lev - temp(col_index, lev_index) = (temp_level(col_index, lev_index) & - + temp_level(col_index, lev_index + 1)) / 2.0_kind_phys - end do + do lev_index = 1, lev + temp(col_index, lev_index) = (temp_level(col_index, lev_index) & + + temp_level(col_index, lev_index + 1)) / 2.0_kind_phys + end do end do - var_array(:, :, :, :) = 1._kind_phys + var_array(:,:,:,:) = 1._kind_phys ! internal_scalar_var = soil_levs(slev_lbound) internal_scalar_var = soil_levs(0) - end subroutine temp_set_run + END SUBROUTINE temp_set_run - !> \section arg_table_temp_set_init Argument Table - !! \htmlinclude arg_table_temp_set_init.html - !! +!> \section arg_table_temp_set_init Argument Table +!! \htmlinclude arg_table_temp_set_init.html +!! subroutine temp_set_init(temp_inc_in, fudge, temp_inc_set, errmsg, errflg) - real(kind=kind_phys), intent(in) :: temp_inc_in - real(kind=kind_phys), intent(in) :: fudge - real(kind=kind_phys), intent(out) :: temp_inc_set - character(len=512), intent(out) :: errmsg - integer, intent(out) :: errflg + real(kind_phys), intent(in) :: temp_inc_in + real(kind_phys), intent(in) :: fudge + real(kind_phys), intent(out) :: temp_inc_set + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg temp_inc_set = temp_inc_in @@ -87,17 +87,17 @@ subroutine temp_set_init(temp_inc_in, fudge, temp_inc_set, errmsg, errflg) end subroutine temp_set_init - !> \section arg_table_temp_set_timestep_initialize Argument Table - !! \htmlinclude arg_table_temp_set_timestep_initialize.html - !! - subroutine temp_set_timestep_initialize(ncol, temp_inc, temp_level, & - errmsg, errflg) +!> \section arg_table_temp_set_timestep_initialize Argument Table +!! \htmlinclude arg_table_temp_set_timestep_initialize.html +!! + subroutine temp_set_timestep_initialize(ncol, temp_inc, temp_level, & + errmsg, errflg) - integer, intent(in) :: ncol - real(kind=kind_phys), intent(in) :: temp_inc - real(kind=kind_phys), intent(inout) :: temp_level(:, :) - character(len=512), intent(out) :: errmsg - integer, intent(out) :: errflg + integer, intent(in) :: ncol + real(kind_phys), intent(in) :: temp_inc + real(kind_phys), intent(inout) :: temp_level(:,:) + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg errmsg = '' errflg = 0 @@ -106,13 +106,13 @@ subroutine temp_set_timestep_initialize(ncol, temp_inc, temp_level, & end subroutine temp_set_timestep_initialize - !> \section arg_table_temp_set_finalize Argument Table - !! \htmlinclude arg_table_temp_set_finalize.html - !! +!> \section arg_table_temp_set_finalize Argument Table +!! \htmlinclude arg_table_temp_set_finalize.html +!! subroutine temp_set_finalize(errmsg, errflg) - character(len=512), intent(out) :: errmsg - integer, intent(out) :: errflg + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg ! This routine currently does nothing @@ -121,4 +121,4 @@ subroutine temp_set_finalize(errmsg, errflg) end subroutine temp_set_finalize -end module temp_set +END MODULE temp_set diff --git a/test/capgen_test/temp_set.meta b/test/capgen_test/temp_set.meta index 42bbb194..0e0a3b50 100644 --- a/test/capgen_test/temp_set.meta +++ b/test/capgen_test/temp_set.meta @@ -94,6 +94,15 @@ type = real kind = kind_phys intent = inout +[ cld_frac ] + standard_name = cloud_fraction + long_name = cloud fraction + type = real + kind = kind_phys + units = Pa + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in + optional = True [ errmsg ] standard_name = ccpp_error_message long_name = Error message for error handling in CCPP diff --git a/test/capgen_test/test_capgen_host_integration.F90 b/test/capgen_test/test_capgen_host_integration.F90 index 7f964178..29f63287 100644 --- a/test/capgen_test/test_capgen_host_integration.F90 +++ b/test/capgen_test/test_capgen_host_integration.F90 @@ -5,64 +5,65 @@ program test cs implicit none - character(len=cs), target :: test_parts1(2) = (/ 'physics1 ', & 'physics2 ' /) character(len=cs), target :: test_parts2(1) = (/ 'data_prep ' /) character(len=cm), target :: test_invars1(10) = (/ & - 'potential_temperature ', & - 'potential_temperature_at_interface ', & - 'coefficients_for_interpolation ', & - 'surface_air_pressure ', & - 'water_vapor_specific_humidity ', & - 'potential_temperature_increment ', & - 'soil_levels ', & - 'temperature_at_diagnostic_levels ', & - 'time_step_for_physics ', & - 'array_variable_for_testing ' /) - character(len=cm), target :: test_outvars1(10) = (/ & - 'potential_temperature ', & - 'potential_temperature_at_interface ', & - 'coefficients_for_interpolation ', & - 'surface_air_pressure ', & - 'water_vapor_specific_humidity ', & - 'soil_levels ', & - 'temperature_at_diagnostic_levels ', & - 'ccpp_error_code ', & - 'ccpp_error_message ', & - 'array_variable_for_testing ' /) + 'array_variable_for_testing ', & + 'coefficients_for_interpolation ', & + 'physics_state_derived_type ', & + 'potential_temperature ', & + 'potential_temperature_at_interface ', & + 'temperature_at_diagnostic_levels ', & + 'index_of_water_vapor_specific_humidity ', & + 'do_cloud_fraction_adjustment ', & + 'potential_temperature_increment ', & + 'time_step_for_physics '/) + + character(len=cm), target :: test_outvars1(9) = (/ & + 'array_variable_for_testing ', & + 'coefficients_for_interpolation ', & + 'physics_state_derived_type ', & + 'potential_temperature ', & + 'potential_temperature_at_interface ', & + 'temperature_at_diagnostic_levels ', & + 'index_of_water_vapor_specific_humidity ', & + 'ccpp_error_code ', & + 'ccpp_error_message '/) + character(len=cm), target :: test_reqvars1(12) = (/ & - 'potential_temperature ', & - 'potential_temperature_at_interface ', & - 'coefficients_for_interpolation ', & - 'surface_air_pressure ', & - 'water_vapor_specific_humidity ', & - 'potential_temperature_increment ', & - 'time_step_for_physics ', & - 'soil_levels ', & - 'temperature_at_diagnostic_levels ', & - 'ccpp_error_code ', & - 'ccpp_error_message ', & - 'array_variable_for_testing ' /) + 'array_variable_for_testing ', & + 'coefficients_for_interpolation ', & + 'physics_state_derived_type ', & + 'potential_temperature ', & + 'potential_temperature_at_interface ', & + 'temperature_at_diagnostic_levels ', & + 'index_of_water_vapor_specific_humidity ', & + 'do_cloud_fraction_adjustment ', & + 'potential_temperature_increment ', & + 'time_step_for_physics ', & + 'ccpp_error_code ', & + 'ccpp_error_message '/) character(len=cm), target :: test_invars2(3) = (/ & - 'model_times ', & - 'number_of_model_times ', & - 'surface_air_pressure ' /) + 'model_times ', & + 'number_of_model_times ', & + 'physics_state_derived_type ' /) character(len=cm), target :: test_outvars2(5) = (/ & - 'ccpp_error_code ', & - 'ccpp_error_message ', & - 'model_times ', & - 'surface_air_pressure ', & - 'number_of_model_times ' /) + 'number_of_model_times ', & + 'physics_state_derived_type ', & + 'ccpp_error_code ', & + 'ccpp_error_message ', & + 'model_times ' /) character(len=cm), target :: test_reqvars2(5) = (/ & - 'model_times ', & - 'number_of_model_times ', & - 'surface_air_pressure ', & - 'ccpp_error_code ', & - 'ccpp_error_message ' /) + 'number_of_model_times ', & + 'physics_state_derived_type ', & + 'model_times ', & + 'ccpp_error_code ', & + 'ccpp_error_message ' /) + type(suite_info) :: test_suites(2) logical :: run_okay diff --git a/test/capgen_test/test_host.F90 b/test/capgen_test/test_host.F90 index 258f0d91..8575c9b3 100644 --- a/test/capgen_test/test_host.F90 +++ b/test/capgen_test/test_host.F90 @@ -9,7 +9,7 @@ module test_prog ! Public data and interfaces integer, public, parameter :: cs = 16 - integer, public, parameter :: cm = 36 + integer, public, parameter :: cm = 64 !> \section arg_table_suite_info Argument Table !! \htmlinclude arg_table_suite_info.html diff --git a/test/capgen_test/test_host_data.F90 b/test/capgen_test/test_host_data.F90 index 32c421a4..f5c61048 100644 --- a/test/capgen_test/test_host_data.F90 +++ b/test/capgen_test/test_host_data.F90 @@ -14,7 +14,8 @@ module test_host_data real(kind=kind_phys), dimension(:, :), allocatable :: & u, & ! zonal wind (m/s) v, & ! meridional wind (m/s) - pmid ! midpoint pressure (Pa) + pmid, & ! midpoint pressure (Pa) + cld_frac ! cloud fraction (1) real(kind=kind_phys), dimension(:, :, :), allocatable :: & q ! constituent mixing ratio (kg/kg moist or dry air depending on type) end type physics_state diff --git a/test/capgen_test/test_host_data.meta b/test/capgen_test/test_host_data.meta index 0e73c060..f440587d 100644 --- a/test/capgen_test/test_host_data.meta +++ b/test/capgen_test/test_host_data.meta @@ -35,6 +35,14 @@ kind = kind_phys units = Pa dimensions = (horizontal_dimension, vertical_layer_dimension) +[ cld_frac ] + standard_name = cloud_fraction + long_name = cloud fraction + type = real + kind = kind_phys + units = Pa + dimensions = (horizontal_dimension, vertical_layer_dimension) + active = (do_cloud_fraction_adjustment) [ soil_levs ] standard_name = soil_levels long_name = soil levels diff --git a/test/capgen_test/test_host_mod.F90 b/test/capgen_test/test_host_mod.F90 index 48ee959b..f3acb09b 100644 --- a/test/capgen_test/test_host_mod.F90 +++ b/test/capgen_test/test_host_mod.F90 @@ -37,6 +37,7 @@ module test_host_mod integer, parameter :: num_time_steps = 2 real(kind=kind_phys), parameter :: tolerance = 1.0e-13_kind_phys real(kind=kind_phys) :: tint_save(ncols, pverp) + logical, parameter :: cfrac_adj = .false. public :: init_data public :: compare_data diff --git a/test/capgen_test/test_host_mod.meta b/test/capgen_test/test_host_mod.meta index 08627af0..dc89981a 100644 --- a/test/capgen_test/test_host_mod.meta +++ b/test/capgen_test/test_host_mod.meta @@ -131,3 +131,9 @@ units = none dimensions = (horizontal_dimension,2,4,6) type = real | kind = kind_phys +[ cfrac_adj ] + standard_name = do_cloud_fraction_adjustment + long_name = control for cloud fraction adjustment + units = none + dimensions = () + type = logical diff --git a/test/ddthost_test/ddthost_test_reports.py b/test/ddthost_test/ddthost_test_reports.py index 612cbbbf..eafec55a 100644 --- a/test/ddthost_test/ddthost_test_reports.py +++ b/test/ddthost_test/ddthost_test_reports.py @@ -45,11 +45,13 @@ "temp_calc_adjust", "temp_set"] _SUITE_LIST = ["ddt_suite", "temp_suite"] _INPUT_VARS_DDT = ["model_times", "number_of_model_times", - "horizontal_loop_begin", "horizontal_loop_end", - "surface_air_pressure", "horizontal_dimension", + "physics_state_derived_type", + "horizontal_dimension", "host_standard_ccpp_type"] _OUTPUT_VARS_DDT = ["ccpp_error_code", "ccpp_error_message", "model_times", - "number_of_model_times", "surface_air_pressure"] + "number_of_model_times", + "host_standard_ccpp_type", + "physics_state_derived_type"] _REQUIRED_VARS_DDT = _INPUT_VARS_DDT + _OUTPUT_VARS_DDT _PROT_VARS_TEMP = ["horizontal_loop_begin", "horizontal_loop_end", "horizontal_dimension", "vertical_layer_dimension", @@ -62,19 +64,22 @@ "potential_temperature_at_interface", "coefficients_for_interpolation", "potential_temperature_increment", - "surface_air_pressure", "time_step_for_physics", - "water_vapor_specific_humidity"] + "physics_state_derived_type", + "time_step_for_physics", + "host_standard_ccpp_type"] _INPUT_VARS_TEMP = ["potential_temperature", "potential_temperature_at_interface", "coefficients_for_interpolation", "potential_temperature_increment", - "surface_air_pressure", "time_step_for_physics", - "water_vapor_specific_humidity"] + "physics_state_derived_type", + "time_step_for_physics", + "host_standard_ccpp_type"] _OUTPUT_VARS_TEMP = ["ccpp_error_code", "ccpp_error_message", "potential_temperature", "potential_temperature_at_interface", "coefficients_for_interpolation", - "surface_air_pressure", "water_vapor_specific_humidity"] + "physics_state_derived_type", + "host_standard_ccpp_type"] class TestDdtHostDataTables(unittest.TestCase, BaseTests.TestHostDataTables): database = _DATABASE diff --git a/test/ddthost_test/environ_conditions.meta b/test/ddthost_test/environ_conditions.meta index 894e0e92..8f35244d 100644 --- a/test/ddthost_test/environ_conditions.meta +++ b/test/ddthost_test/environ_conditions.meta @@ -1,6 +1,7 @@ [ccpp-table-properties] name = environ_conditions type = scheme + [ccpp-arg-table] name = environ_conditions_run type = scheme @@ -27,6 +28,7 @@ dimensions = () type = integer intent = out + [ccpp-arg-table] name = environ_conditions_init type = scheme @@ -78,6 +80,7 @@ dimensions = () type = integer intent = out + [ccpp-arg-table] name = environ_conditions_finalize type = scheme diff --git a/test/ddthost_test/make_ddt.F90 b/test/ddthost_test/make_ddt.F90 index a0de4177..d1c26657 100644 --- a/test/ddthost_test/make_ddt.F90 +++ b/test/ddthost_test/make_ddt.F90 @@ -68,12 +68,10 @@ end subroutine make_ddt_run !> \section arg_table_make_ddt_init Argument Table !! \htmlinclude arg_table_make_ddt_init.html !! - subroutine make_ddt_init(nbox, ccpp_info, vmr, errmsg, errflg) - use host_ccpp_ddt, only: ccpp_info_t + subroutine make_ddt_init(nbox, vmr, errmsg, errflg) ! Dummy arguments integer, intent(in) :: nbox - type(ccpp_info_t), intent(in) :: ccpp_info type(vmr_type), intent(out) :: vmr character(len=512), intent(out) :: errmsg integer, intent(out) :: errflg diff --git a/test/ddthost_test/make_ddt.meta b/test/ddthost_test/make_ddt.meta index 4998e917..a252df09 100644 --- a/test/ddthost_test/make_ddt.meta +++ b/test/ddthost_test/make_ddt.meta @@ -76,11 +76,6 @@ units = count dimensions = () intent = in -[ ccpp_info ] - standard_name = host_standard_ccpp_type - type = ccpp_info_t - dimensions = () - intent = in [ vmr ] standard_name = volume_mixing_ratio_ddt dimensions = () diff --git a/test/ddthost_test/test_ddt_host_integration.F90 b/test/ddthost_test/test_ddt_host_integration.F90 index c3cef458..9845631e 100644 --- a/test/ddthost_test/test_ddt_host_integration.F90 +++ b/test/ddthost_test/test_ddt_host_integration.F90 @@ -1,82 +1,83 @@ program test - use test_prog, only: test_host, & - suite_info, & - cm, & - cs + use test_prog, only: test_host, suite_info, cm, cs - implicit none + implicit none - character(len=cs), target :: test_parts1(2) = (/ 'physics1 ', & - 'physics2 ' /) - character(len=cs), target :: test_parts2(1) = (/ 'data_prep ' /) - character(len=cm), target :: test_invars1(7) = (/ & - 'potential_temperature ', & - 'potential_temperature_at_interface ', & - 'coefficients_for_interpolation ', & - 'surface_air_pressure ', & - 'water_vapor_specific_humidity ', & - 'potential_temperature_increment ', & - 'time_step_for_physics ' /) - character(len=cm), target :: test_outvars1(7) = (/ & - 'potential_temperature ', & - 'potential_temperature_at_interface ', & - 'coefficients_for_interpolation ', & - 'surface_air_pressure ', & - 'water_vapor_specific_humidity ', & - 'ccpp_error_code ', & - 'ccpp_error_message ' /) - character(len=cm), target :: test_reqvars1(9) = (/ & - 'potential_temperature ', & - 'potential_temperature_at_interface ', & - 'coefficients_for_interpolation ', & - 'surface_air_pressure ', & - 'water_vapor_specific_humidity ', & - 'potential_temperature_increment ', & - 'time_step_for_physics ', & - 'ccpp_error_code ', & - 'ccpp_error_message ' /) + character(len=cs), target :: test_parts1(2) = (/ 'physics1 ', & + 'physics2 ' /) + character(len=cs), target :: test_parts2(1) = (/ 'data_prep ' /) + character(len=cm), target :: test_invars1(8) = (/ & + 'potential_temperature ', & + 'potential_temperature_at_interface ', & + 'coefficients_for_interpolation ', & + 'index_of_water_vapor_specific_humidity', & + 'host_standard_ccpp_type ', & + 'potential_temperature_increment ', & + 'physics_state_derived_type ', & + 'time_step_for_physics ' /) + character(len=cm), target :: test_outvars1(8) = (/ & + 'potential_temperature ', & + 'potential_temperature_at_interface ', & + 'coefficients_for_interpolation ', & + 'index_of_water_vapor_specific_humidity', & + 'host_standard_ccpp_type ', & + 'physics_state_derived_type ', & + 'ccpp_error_code ', & + 'ccpp_error_message ' /) + character(len=cm), target :: test_reqvars1(10) = (/ & + 'potential_temperature ', & + 'potential_temperature_at_interface ', & + 'coefficients_for_interpolation ', & + 'index_of_water_vapor_specific_humidity', & + 'host_standard_ccpp_type ', & + 'potential_temperature_increment ', & + 'physics_state_derived_type ', & + 'time_step_for_physics ', & + 'ccpp_error_code ', & + 'ccpp_error_message ' /) - character(len=cm), target :: test_invars2(4) = (/ & - 'model_times ', & - 'number_of_model_times ', & - 'surface_air_pressure ', & - 'host_standard_ccpp_type ' /) + character(len=cm), target :: test_invars2(4) = (/ & + 'model_times ', & + 'number_of_model_times ', & + 'physics_state_derived_type ', & + 'host_standard_ccpp_type ' /) - character(len=cm), target :: test_outvars2(5) = (/ & - 'ccpp_error_code ', & - 'ccpp_error_message ', & - 'model_times ', & - 'surface_air_pressure ', & - 'number_of_model_times ' /) + character(len=cm), target :: test_outvars2(6) = (/ & + 'ccpp_error_code ', & + 'ccpp_error_message ', & + 'model_times ', & + 'physics_state_derived_type ', & + 'host_standard_ccpp_type ', & + 'number_of_model_times ' /) - character(len=cm), target :: test_reqvars2(6) = (/ & - 'model_times ', & - 'number_of_model_times ', & - 'surface_air_pressure ', & - 'ccpp_error_code ', & - 'ccpp_error_message ', & - 'host_standard_ccpp_type ' /) - type(suite_info) :: test_suites(2) - logical :: run_okay + character(len=cm), target :: test_reqvars2(6) = (/ & + 'model_times ', & + 'number_of_model_times ', & + 'ccpp_error_code ', & + 'ccpp_error_message ', & + 'physics_state_derived_type ', & + 'host_standard_ccpp_type ' /) + type(suite_info) :: test_suites(2) + logical :: run_okay - ! Setup expected test suite info - test_suites(1)%suite_name = 'temp_suite' - test_suites(1)%suite_parts => test_parts1 - test_suites(1)%suite_input_vars => test_invars1 - test_suites(1)%suite_output_vars => test_outvars1 - test_suites(1)%suite_required_vars => test_reqvars1 - test_suites(2)%suite_name = 'ddt_suite' - test_suites(2)%suite_parts => test_parts2 - test_suites(2)%suite_input_vars => test_invars2 - test_suites(2)%suite_output_vars => test_outvars2 - test_suites(2)%suite_required_vars => test_reqvars2 + ! Setup expected test suite info + test_suites(1)%suite_name = 'temp_suite' + test_suites(1)%suite_parts => test_parts1 + test_suites(1)%suite_input_vars => test_invars1 + test_suites(1)%suite_output_vars => test_outvars1 + test_suites(1)%suite_required_vars => test_reqvars1 + test_suites(2)%suite_name = 'ddt_suite' + test_suites(2)%suite_parts => test_parts2 + test_suites(2)%suite_input_vars => test_invars2 + test_suites(2)%suite_output_vars => test_outvars2 + test_suites(2)%suite_required_vars => test_reqvars2 - call test_host(run_okay, test_suites) + call test_host(run_okay, test_suites) - if (run_okay) then - stop 0 - else - stop -1 - end if + if (run_okay) then + STOP 0 + else + STOP -1 + end if end program test diff --git a/test/ddthost_test/test_host.F90 b/test/ddthost_test/test_host.F90 index ebe175d9..c7db69c2 100644 --- a/test/ddthost_test/test_host.F90 +++ b/test/ddthost_test/test_host.F90 @@ -1,273 +1,271 @@ module test_prog - use ccpp_kinds, only: kind_phys + use ccpp_kinds, only: kind_phys - implicit none - private + implicit none + private - public test_host + public test_host - ! Public data and interfaces - integer, public, parameter :: cs = 16 - integer, public, parameter :: cm = 36 + ! Public data and interfaces + integer, public, parameter :: cs = 16 + integer, public, parameter :: cm = 38 - !> \section arg_table_suite_info Argument Table - !! \htmlinclude arg_table_suite_info.html - !! - type, public :: suite_info - character(len=cs) :: suite_name = '' - character(len=cs), pointer :: suite_parts(:) => null() - character(len=cm), pointer :: suite_input_vars(:) => null() - character(len=cm), pointer :: suite_output_vars(:) => null() - character(len=cm), pointer :: suite_required_vars(:) => null() - end type suite_info + !> \section arg_table_suite_info Argument Table + !! \htmlinclude arg_table_suite_info.html + !! + type, public :: suite_info + character(len=cs) :: suite_name = '' + character(len=cs), pointer :: suite_parts(:) => NULL() + character(len=cm), pointer :: suite_input_vars(:) => NULL() + character(len=cm), pointer :: suite_output_vars(:) => NULL() + character(len=cm), pointer :: suite_required_vars(:) => NULL() + end type suite_info contains - logical function check_suite(test_suite) - use test_host_ccpp_cap, only: ccpp_physics_suite_part_list - use test_host_ccpp_cap, only: ccpp_physics_suite_variables - use test_utils, only: check_list + logical function check_suite(test_suite) + use test_host_ccpp_cap, only: ccpp_physics_suite_part_list + use test_host_ccpp_cap, only: ccpp_physics_suite_variables + use test_utils, only: check_list - ! Dummy argument - type(suite_info), intent(in) :: test_suite - ! Local variables - integer :: sind - logical :: check - integer :: errflg - character(len=512) :: errmsg - character(len=128), allocatable :: test_list(:) + ! Dummy argument + type(suite_info), intent(in) :: test_suite + ! Local variables + integer :: sind + logical :: check + integer :: errflg + character(len=512) :: errmsg + character(len=128), allocatable :: test_list(:) - check_suite = .true. - write(6, *) "Checking suite ", trim(test_suite%suite_name) - ! First, check the suite parts - call ccpp_physics_suite_part_list(test_suite%suite_name, test_list, & - errmsg, errflg) - if (errflg == 0) then - check = check_list(test_list, test_suite%suite_parts, 'part names', & - suite_name=test_suite%suite_name) - else - check = .false. - write(6, '(a,i0,2a)') 'ERROR ', errflg, ': ', trim(errmsg) - end if - check_suite = check_suite .and. check - if (allocated(test_list)) then - deallocate(test_list) - end if - ! Check the input variables - call ccpp_physics_suite_variables(test_suite%suite_name, test_list, & - errmsg, errflg, input_vars=.true., output_vars=.false.) - if (errflg == 0) then - check = check_list(test_list, test_suite%suite_input_vars, & - 'input variable names', suite_name=test_suite%suite_name) - else - check = .false. - write(6, '(a,i0,2a)') 'ERROR ', errflg, ': ', trim(errmsg) - end if - check_suite = check_suite .and. check - if (allocated(test_list)) then - deallocate(test_list) - end if - ! Check the output variables - call ccpp_physics_suite_variables(test_suite%suite_name, test_list, & - errmsg, errflg, input_vars=.false., output_vars=.true.) - if (errflg == 0) then - check = check_list(test_list, test_suite%suite_output_vars, & - 'output variable names', suite_name=test_suite%suite_name) - else - check = .false. - write(6, '(a,i0,2a)') 'ERROR ', errflg, ': ', trim(errmsg) - end if - check_suite = check_suite .and. check - if (allocated(test_list)) then - deallocate(test_list) - end if - ! Check all required variables - call ccpp_physics_suite_variables(test_suite%suite_name, test_list, & - errmsg, errflg) - if (errflg == 0) then - check = check_list(test_list, test_suite%suite_required_vars, & - 'required variable names', suite_name=test_suite%suite_name) - else - check = .false. - write(6, '(a,i0,2a)') 'ERROR ', errflg, ': ', trim(errmsg) - end if - check_suite = check_suite .and. check - if (allocated(test_list)) then - deallocate(test_list) - end if - end function check_suite + check_suite = .true. + write(6, *) "Checking suite ", trim(test_suite%suite_name) + ! First, check the suite parts + call ccpp_physics_suite_part_list(test_suite%suite_name, test_list, & + errmsg, errflg) + if (errflg == 0) then + check = check_list(test_list, test_suite%suite_parts, 'part names', & + suite_name=test_suite%suite_name) + else + check = .false. + write(6, '(a,i0,2a)') 'ERROR ', errflg, ': ', trim(errmsg) + end if + check_suite = check_suite .and. check + if (allocated(test_list)) then + deallocate(test_list) + end if + ! Check the input variables + call ccpp_physics_suite_variables(test_suite%suite_name, test_list, & + errmsg, errflg, input_vars=.true., output_vars=.false.) + if (errflg == 0) then + check = check_list(test_list, test_suite%suite_input_vars, & + 'input variable names', suite_name=test_suite%suite_name) + else + check = .false. + write(6, '(a,i0,2a)') 'ERROR ', errflg, ': ', trim(errmsg) + end if + check_suite = check_suite .and. check + if (allocated(test_list)) then + deallocate(test_list) + end if + ! Check the output variables + call ccpp_physics_suite_variables(test_suite%suite_name, test_list, & + errmsg, errflg, input_vars=.false., output_vars=.true.) + if (errflg == 0) then + check = check_list(test_list, test_suite%suite_output_vars, & + 'output variable names', suite_name=test_suite%suite_name) + else + check = .false. + write(6, '(a,i0,2a)') 'ERROR ', errflg, ': ', trim(errmsg) + end if + check_suite = check_suite .and. check + if (allocated(test_list)) then + deallocate(test_list) + end if + ! Check all required variables + call ccpp_physics_suite_variables(test_suite%suite_name, test_list, & + errmsg, errflg) + if (errflg == 0) then + check = check_list(test_list, test_suite%suite_required_vars, & + 'required variable names', suite_name=test_suite%suite_name) + else + check = .false. + write(6, '(a,i0,2a)') 'ERROR ', errflg, ': ', trim(errmsg) + end if + check_suite = check_suite .and. check + if (allocated(test_list)) then + deallocate(test_list) + end if + end function check_suite - !> \section arg_table_test_host Argument Table - !! \htmlinclude arg_table_test_host.html - !! - subroutine test_host(retval, test_suites) - use host_ccpp_ddt, only: ccpp_info_t - use test_host_mod, only: ncols, & - num_time_steps - 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 - use test_host_ccpp_cap, only: test_host_ccpp_physics_timestep_final - use test_host_ccpp_cap, only: test_host_ccpp_physics_finalize - use test_host_ccpp_cap, only: ccpp_physics_suite_list - use test_host_mod, only: init_data, & - compare_data, & - check_model_times - use test_utils, only: check_list + !> \section arg_table_test_host Argument Table + !! \htmlinclude arg_table_test_host.html + !! + subroutine test_host(retval, test_suites) - type(suite_info), intent(in) :: test_suites(:) - logical, intent(out) :: retval + use host_ccpp_ddt, only: ccpp_info_t + use test_host_mod, only: ncols, num_time_steps + 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 + use test_host_ccpp_cap, only: test_host_ccpp_physics_timestep_final + use test_host_ccpp_cap, only: test_host_ccpp_physics_finalize + use test_host_ccpp_cap, only: ccpp_physics_suite_list + use test_host_mod, only: init_data, compare_data, check_model_times + use test_utils, only: check_list - logical :: check - integer :: col_start - integer :: index, sind - integer :: time_step - integer :: num_suites - character(len=128), allocatable :: suite_names(:) - type(ccpp_info_t) :: ccpp_info + type(suite_info), intent(in) :: test_suites(:) + logical, intent(out) :: retval - ! Initialize our 'data' - call init_data() + logical :: check + integer :: col_start + integer :: index, sind + integer :: time_step + integer :: num_suites + character(len=128), allocatable :: suite_names(:) + type(ccpp_info_t) :: ccpp_info - ! Gather and test the inspection routines - num_suites = size(test_suites) - call ccpp_physics_suite_list(suite_names) - retval = check_list(suite_names, test_suites(:)%suite_name, & - 'suite names') - write(6, *) 'Available suites are:' - do index = 1, size(suite_names) - do sind = 1, num_suites - if (trim(test_suites(sind)%suite_name) == & - trim(suite_names(index))) then - exit - end if - end do - write(6, '(i0,3a,i0,a)') index, ') ', trim(suite_names(index)), & - ' = test_suites(', sind, ')' - end do - if (retval) then - do sind = 1, num_suites - check = check_suite(test_suites(sind)) - retval = retval .and. check - end do - end if - !!! Return here if any check failed - if (.not. retval) then - return - end if + ! Initialize our 'data' + call init_data() - ! Use the suite information to setup the run - do sind = 1, num_suites - call test_host_ccpp_physics_initialize(test_suites(sind)%suite_name, & - ccpp_info) - if (ccpp_info%errflg /= 0) then - write(6, '(4a)') 'ERROR in initialize of ', & - trim(test_suites(sind)%suite_name), ': ', trim(ccpp_info%errmsg) - end if - end do - ! Loop over time steps - do time_step = 1, num_time_steps - ! Initialize the timestep - do sind = 1, num_suites - if (ccpp_info%errflg /= 0) then - exit - end if - if (ccpp_info%errflg == 0) then - call test_host_ccpp_physics_timestep_initial( & - test_suites(sind)%suite_name, ccpp_info) - end if - if (ccpp_info%errflg /= 0) then - write(6, '(3a)') trim(test_suites(sind)%suite_name), ': ', & - trim(ccpp_info%errmsg) - exit - end if - if (ccpp_info%errflg /= 0) then - exit - end if - end do - - do col_start = 1, ncols, 5 - if (ccpp_info%errflg /= 0) then - exit - end if - ccpp_info%col_start = col_start - ccpp_info%col_end = min(col_start + 4, ncols) + ! Gather and test the inspection routines + num_suites = size(test_suites) + call ccpp_physics_suite_list(suite_names) + retval = check_list(suite_names, test_suites(:)%suite_name, & + 'suite names') + write(6, *) 'Available suites are:' + do index = 1, size(suite_names) + do sind = 1, num_suites + if (trim(test_suites(sind)%suite_name) == & + trim(suite_names(index))) then + exit + end if + end do + write(6, '(i0,3a,i0,a)') index, ') ', trim(suite_names(index)), & + ' = test_suites(', sind, ')' + end do + if (retval) then + do sind = 1, num_suites + check = check_suite(test_suites(sind)) + retval = retval .and. check + end do + end if + !!! Return here if any check failed + if (.not. retval) then + return + end if - do sind = 1, num_suites + ! Use the suite information to setup the run + do sind = 1, num_suites + call test_host_ccpp_physics_initialize(test_suites(sind)%suite_name, & + ccpp_info) if (ccpp_info%errflg /= 0) then - exit + write(6, '(4a)') 'ERROR in initialize of ', & + trim(test_suites(sind)%suite_name), ': ', trim(ccpp_info%errmsg) end if - do index = 1, size(test_suites(sind)%suite_parts) - if (ccpp_info%errflg /= 0) then - exit - end if - if (ccpp_info%errflg == 0) then - call test_host_ccpp_physics_run( & - test_suites(sind)%suite_name, & - test_suites(sind)%suite_parts(index), & - ccpp_info) - end if - if (ccpp_info%errflg /= 0) then - write(6, '(5a)') trim(test_suites(sind)%suite_name), & - '/', trim(test_suites(sind)%suite_parts(index)), & - ': ', trim(ccpp_info%errmsg) - exit - end if + end do + ! Loop over time steps + do time_step = 1, num_time_steps + ! Initialize the timestep + do sind = 1, num_suites + if (ccpp_info%errflg /= 0) then + exit + end if + if (ccpp_info%errflg == 0) then + call test_host_ccpp_physics_timestep_initial( & + test_suites(sind)%suite_name, ccpp_info) + end if + if (ccpp_info%errflg /= 0) then + write(6, '(3a)') trim(test_suites(sind)%suite_name), ': ', & + trim(ccpp_info%errmsg) + exit + end if + if (ccpp_info%errflg /= 0) then + exit + end if end do - end do - end do - do sind = 1, num_suites - if (ccpp_info%errflg /= 0) then - exit - end if - if (ccpp_info%errflg == 0) then - call test_host_ccpp_physics_timestep_final( & - test_suites(sind)%suite_name, ccpp_info) - end if - if (ccpp_info%errflg /= 0) then - write(6, '(3a)') trim(test_suites(sind)%suite_name), ': ', & - trim(ccpp_info%errmsg) - exit - end if - end do - end do ! End time step loop + do col_start = 1, ncols, 5 + if (ccpp_info%errflg /= 0) then + exit + end if + ccpp_info%col_start = col_start + ccpp_info%col_end = MIN(col_start + 4, ncols) - do sind = 1, num_suites - if (ccpp_info%errflg /= 0) then - exit - end if - if (ccpp_info%errflg == 0) then - call test_host_ccpp_physics_finalize( & - test_suites(sind)%suite_name, ccpp_info) - end if - if (ccpp_info%errflg /= 0) then - write(6, '(3a)') test_suites(sind)%suite_parts(index), ': ', & - trim(ccpp_info%errmsg) - write(6, '(2a)') 'An error occurred in ccpp_timestep_final, ', & - 'Exiting...' - exit - end if - end do + do sind = 1, num_suites + if (ccpp_info%errflg /= 0) then + exit + end if + do index = 1, size(test_suites(sind)%suite_parts) + if (ccpp_info%errflg /= 0) then + exit + end if + if (ccpp_info%errflg == 0) then + call test_host_ccpp_physics_run( & + test_suites(sind)%suite_name, & + test_suites(sind)%suite_parts(index), & + ccpp_info) + end if + if (ccpp_info%errflg /= 0) then + write(6, '(5a)') trim(test_suites(sind)%suite_name), & + '/', trim(test_suites(sind)%suite_parts(index)), & + ': ', trim(ccpp_info%errmsg) + exit + end if + end do + end do + end do - if (ccpp_info%errflg == 0) then - ! Run finished without error, check answers - if (.not. check_model_times()) then - write(6, *) 'Model times error!' - ccpp_info%errflg = -1 - else if (compare_data()) then - write(6, *) 'Answers are correct!' - ccpp_info%errflg = 0 - else - write(6, *) 'Answers are not correct!' - ccpp_info%errflg = -1 - end if - end if + do sind = 1, num_suites + if (ccpp_info%errflg /= 0) then + exit + end if + if (ccpp_info%errflg == 0) then + call test_host_ccpp_physics_timestep_final( & + test_suites(sind)%suite_name, ccpp_info) + end if + if (ccpp_info%errflg /= 0) then + write(6, '(3a)') trim(test_suites(sind)%suite_name), ': ', & + trim(ccpp_info%errmsg) + exit + end if + end do + end do ! End time step loop + + do sind = 1, num_suites + if (ccpp_info%errflg /= 0) then + exit + end if + if (ccpp_info%errflg == 0) then + call test_host_ccpp_physics_finalize( & + test_suites(sind)%suite_name,ccpp_info) + end if + if (ccpp_info%errflg /= 0) then + write(6, '(3a)') test_suites(sind)%suite_parts(index), ': ', & + trim(ccpp_info%errmsg) + write(6,'(2a)') 'An error occurred in ccpp_timestep_final, ', & + 'Exiting...' + exit + end if + end do + + if (ccpp_info%errflg == 0) then + ! Run finished without error, check answers + if (.not. check_model_times()) then + write(6, *) 'Model times error!' + ccpp_info%errflg = -1 + else if (compare_data()) then + write(6, *) 'Answers are correct!' + ccpp_info%errflg = 0 + else + write(6, *) 'Answers are not correct!' + ccpp_info%errflg = -1 + end if + end if - retval = ccpp_info%errflg == 0 + retval = ccpp_info%errflg == 0 - end subroutine test_host + end subroutine test_host -end module test_prog + end module test_prog diff --git a/test/nested_suite_test/test_nested_suite_integration.F90 b/test/nested_suite_test/test_nested_suite_integration.F90 index 5e9c3009..d987e38a 100644 --- a/test/nested_suite_test/test_nested_suite_integration.F90 +++ b/test/nested_suite_test/test_nested_suite_integration.F90 @@ -1,91 +1,50 @@ program test_nested_suite_integration - use test_prog, only: test_host, & - suite_info, & - cm, & - cs - - implicit none - - character(len=cs), target :: test_parts1(3) = (/ & - 'radiation1 ', & - 'rad_lw_group ', & - 'rad_sw_group '/) - - character(len=cm), target :: test_invars1(18) = (/ & - 'effective_radius_of_stratiform_cloud_rain_particle ', & - 'effective_radius_of_stratiform_cloud_liquid_water_particle', & - 'effective_radius_of_stratiform_cloud_snow_particle ', & - 'effective_radius_of_stratiform_cloud_graupel ', & - 'cloud_graupel_number_concentration ', & - 'scalar_variable_for_testing ', & - 'turbulent_kinetic_energy ', & - 'turbulent_kinetic_energy2 ', & - 'scalar_variable_for_testing_a ', & - 'scalar_variable_for_testing_b ', & - 'scalar_variable_for_testing_c ', & - 'scheme_order_in_suite ', & - 'num_subcycles_for_effr ', & - 'flag_indicating_cloud_microphysics_has_graupel ', & - 'flag_indicating_cloud_microphysics_has_ice ', & - 'surface_downwelling_shortwave_radiation_flux ', & - 'surface_upwelling_shortwave_radiation_flux ', & - 'longwave_radiation_fluxes '/) - - character(len=cm), target :: test_outvars1(14) = (/ & - 'ccpp_error_code ', & - 'ccpp_error_message ', & - 'effective_radius_of_stratiform_cloud_ice_particle ', & - 'effective_radius_of_stratiform_cloud_liquid_water_particle', & - 'effective_radius_of_stratiform_cloud_rain_particle ', & - 'effective_radius_of_stratiform_cloud_snow_particle ', & - 'cloud_ice_number_concentration ', & - 'scalar_variable_for_testing ', & - 'scheme_order_in_suite ', & - 'surface_downwelling_shortwave_radiation_flux ', & - 'surface_upwelling_shortwave_radiation_flux ', & - 'turbulent_kinetic_energy ', & - 'turbulent_kinetic_energy2 ', & - 'longwave_radiation_fluxes '/) - - character(len=cm), target :: test_reqvars1(22) = (/ & - 'ccpp_error_code ', & - 'ccpp_error_message ', & - 'effective_radius_of_stratiform_cloud_rain_particle ', & - 'effective_radius_of_stratiform_cloud_ice_particle ', & - 'effective_radius_of_stratiform_cloud_liquid_water_particle', & - 'effective_radius_of_stratiform_cloud_snow_particle ', & - 'effective_radius_of_stratiform_cloud_graupel ', & - 'cloud_graupel_number_concentration ', & - 'cloud_ice_number_concentration ', & - 'scalar_variable_for_testing ', & - 'turbulent_kinetic_energy ', & - 'turbulent_kinetic_energy2 ', & - 'scalar_variable_for_testing_a ', & - 'scalar_variable_for_testing_b ', & - 'scalar_variable_for_testing_c ', & - 'scheme_order_in_suite ', & - 'num_subcycles_for_effr ', & - 'flag_indicating_cloud_microphysics_has_graupel ', & - 'flag_indicating_cloud_microphysics_has_ice ', & - 'surface_downwelling_shortwave_radiation_flux ', & - 'surface_upwelling_shortwave_radiation_flux ', & - 'longwave_radiation_fluxes '/) - - type(suite_info) :: test_suites(1) - logical :: run_okay - - ! Setup expected test suite info - test_suites(1)%suite_name = 'main_suite' - test_suites(1)%suite_parts => test_parts1 - test_suites(1)%suite_input_vars => test_invars1 - test_suites(1)%suite_output_vars => test_outvars1 - test_suites(1)%suite_required_vars => test_reqvars1 - - call test_host(run_okay, test_suites) - - if (run_okay) then - stop 0 - else - stop -1 - end if + use test_prog, only: test_host, suite_info, cm, cs + + implicit none + + character(len=cs), target :: test_parts1(3) = (/ & + 'radiation1 ', & + 'rad_lw_group ', & + 'rad_sw_group '/) + + character(len=cm), target :: test_invars1(5) = (/ & + 'effective_radius_of_stratiform_cloud_snow_particle', & + 'physics_state_derived_type ', & + 'flag_indicating_cloud_microphysics_has_graupel ', & + 'flag_indicating_cloud_microphysics_has_ice ', & + 'num_subcycles_for_effr '/) + + character(len=cm), target :: test_outvars1(4) = (/ & + 'effective_radius_of_stratiform_cloud_snow_particle', & + 'physics_state_derived_type ', & + 'ccpp_error_code ', & + 'ccpp_error_message '/) + + character(len=cm), target :: test_reqvars1(7) = (/ & + 'effective_radius_of_stratiform_cloud_snow_particle', & + 'physics_state_derived_type ', & + 'flag_indicating_cloud_microphysics_has_graupel ', & + 'flag_indicating_cloud_microphysics_has_ice ', & + 'num_subcycles_for_effr ', & + 'ccpp_error_code ', & + 'ccpp_error_message '/) + + type(suite_info) :: test_suites(1) + logical :: run_okay + + ! Setup expected test suite info + test_suites(1)%suite_name = 'main_suite' + test_suites(1)%suite_parts => test_parts1 + test_suites(1)%suite_input_vars => test_invars1 + test_suites(1)%suite_output_vars => test_outvars1 + test_suites(1)%suite_required_vars => test_reqvars1 + + call test_host(run_okay, test_suites) + + if (run_okay) then + STOP 0 + else + STOP -1 + end if end program test_nested_suite_integration diff --git a/test/utils/test_utils.F90 b/test/utils/test_utils.F90 index 3ae8d549..63be95d2 100644 --- a/test/utils/test_utils.F90 +++ b/test/utils/test_utils.F90 @@ -83,6 +83,5 @@ logical function check_list(test_list, chk_list, list_desc, suite_name) errmsg = '' end if end if - end function check_list end module test_utils diff --git a/test/var_compatibility_test/test_var_compatibility_integration.F90 b/test/var_compatibility_test/test_var_compatibility_integration.F90 index 4115face..71a3c2a5 100644 --- a/test/var_compatibility_test/test_var_compatibility_integration.F90 +++ b/test/var_compatibility_test/test_var_compatibility_integration.F90 @@ -1,88 +1,43 @@ program test_var_compatibility_integration - use test_prog, only: test_host, & - suite_info, & - cm, & - cs - - implicit none - - character(len=cs), target :: test_parts1(1) = (/ 'radiation ' /) - - character(len=cm), target :: test_invars1(18) = (/ & - 'effective_radius_of_stratiform_cloud_rain_particle ', & - 'effective_radius_of_stratiform_cloud_liquid_water_particle', & - 'effective_radius_of_stratiform_cloud_snow_particle ', & - 'effective_radius_of_stratiform_cloud_graupel ', & - 'cloud_graupel_number_concentration ', & - 'scalar_variable_for_testing ', & - 'turbulent_kinetic_energy ', & - 'turbulent_kinetic_energy2 ', & - 'scalar_variable_for_testing_a ', & - 'scalar_variable_for_testing_b ', & - 'scalar_variable_for_testing_c ', & - 'scheme_order_in_suite ', & - 'num_subcycles_for_effr ', & - 'flag_indicating_cloud_microphysics_has_graupel ', & - 'flag_indicating_cloud_microphysics_has_ice ', & - 'surface_downwelling_shortwave_radiation_flux ', & - 'surface_upwelling_shortwave_radiation_flux ', & - 'longwave_radiation_fluxes '/) - - character(len=cm), target :: test_outvars1(14) = (/ & - 'ccpp_error_code ', & - 'ccpp_error_message ', & - 'effective_radius_of_stratiform_cloud_ice_particle ', & - 'effective_radius_of_stratiform_cloud_liquid_water_particle', & - 'effective_radius_of_stratiform_cloud_rain_particle ', & - 'effective_radius_of_stratiform_cloud_snow_particle ', & - 'cloud_ice_number_concentration ', & - 'scalar_variable_for_testing ', & - 'scheme_order_in_suite ', & - 'surface_downwelling_shortwave_radiation_flux ', & - 'surface_upwelling_shortwave_radiation_flux ', & - 'turbulent_kinetic_energy ', & - 'turbulent_kinetic_energy2 ', & - 'longwave_radiation_fluxes '/) - - character(len=cm), target :: test_reqvars1(22) = (/ & - 'ccpp_error_code ', & - 'ccpp_error_message ', & - 'effective_radius_of_stratiform_cloud_rain_particle ', & - 'effective_radius_of_stratiform_cloud_ice_particle ', & - 'effective_radius_of_stratiform_cloud_liquid_water_particle', & - 'effective_radius_of_stratiform_cloud_snow_particle ', & - 'effective_radius_of_stratiform_cloud_graupel ', & - 'cloud_graupel_number_concentration ', & - 'cloud_ice_number_concentration ', & - 'scalar_variable_for_testing ', & - 'turbulent_kinetic_energy ', & - 'turbulent_kinetic_energy2 ', & - 'scalar_variable_for_testing_a ', & - 'scalar_variable_for_testing_b ', & - 'scalar_variable_for_testing_c ', & - 'scheme_order_in_suite ', & - 'num_subcycles_for_effr ', & - 'flag_indicating_cloud_microphysics_has_graupel ', & - 'flag_indicating_cloud_microphysics_has_ice ', & - 'surface_downwelling_shortwave_radiation_flux ', & - 'surface_upwelling_shortwave_radiation_flux ', & - 'longwave_radiation_fluxes '/) - - type(suite_info) :: test_suites(1) - logical :: run_okay - - ! Setup expected test suite info - test_suites(1)%suite_name = 'var_compatibility_suite' - test_suites(1)%suite_parts => test_parts1 - test_suites(1)%suite_input_vars => test_invars1 - test_suites(1)%suite_output_vars => test_outvars1 - test_suites(1)%suite_required_vars => test_reqvars1 - - call test_host(run_okay, test_suites) - - if (run_okay) then - stop 0 - else - stop -1 - end if + use test_prog, only: test_host, suite_info, cm, cs + + implicit none + + character(len=cs), target :: test_parts1(1) = (/ 'radiation ' /) + character(len=cm), target :: test_invars1(5) = (/ & + 'num_subcycles_for_effr ', & + 'flag_indicating_cloud_microphysics_has_graupel ', & + 'flag_indicating_cloud_microphysics_has_ice ', & + 'effective_radius_of_stratiform_cloud_snow_particle ', & + 'physics_state_derived_type '/) + character(len=cm), target :: test_outvars1(4) = (/ & + 'ccpp_error_code ', & + 'ccpp_error_message ', & + 'effective_radius_of_stratiform_cloud_snow_particle ', & + 'physics_state_derived_type '/) + character(len=cm), target :: test_reqvars1(7) = (/ & + 'ccpp_error_code ', & + 'ccpp_error_message ', & + 'num_subcycles_for_effr ', & + 'flag_indicating_cloud_microphysics_has_graupel ', & + 'flag_indicating_cloud_microphysics_has_ice ', & + 'effective_radius_of_stratiform_cloud_snow_particle ', & + 'physics_state_derived_type '/) + type(suite_info) :: test_suites(1) + logical :: run_okay + + ! Setup expected test suite info + test_suites(1)%suite_name = 'var_compatibility_suite' + test_suites(1)%suite_parts => test_parts1 + test_suites(1)%suite_input_vars => test_invars1 + test_suites(1)%suite_output_vars => test_outvars1 + test_suites(1)%suite_required_vars => test_reqvars1 + + call test_host(run_okay, test_suites) + + if (run_okay) then + STOP 0 + else + STOP -1 + end if end program test_var_compatibility_integration diff --git a/test/var_compatibility_test/var_compatibility_test_reports.py b/test/var_compatibility_test/var_compatibility_test_reports.py index ada612c7..795af1fc 100755 --- a/test/var_compatibility_test/var_compatibility_test_reports.py +++ b/test/var_compatibility_test/var_compatibility_test_reports.py @@ -12,7 +12,6 @@ """ import os import unittest - from test_stub import BaseTests _BUILD_DIR = os.path.join(os.path.abspath(os.environ['BUILD_DIR']), "test", "var_compatibility_test") @@ -39,38 +38,13 @@ _SUITE_LIST = ["var_compatibility_suite"] _DEPENDENCIES = [ os.path.join(_TEST_DIR, "module_rad_ddt.F90")] _INPUT_VARS_VAR_ACTION = ["horizontal_loop_begin", "horizontal_loop_end", "horizontal_dimension", "vertical_layer_dimension", - "effective_radius_of_stratiform_cloud_liquid_water_particle", - "effective_radius_of_stratiform_cloud_rain_particle", - "effective_radius_of_stratiform_cloud_snow_particle", - "effective_radius_of_stratiform_cloud_graupel", - "cloud_graupel_number_concentration", - "scalar_variable_for_testing", - "turbulent_kinetic_energy", - "turbulent_kinetic_energy2", - "scalar_variable_for_testing_a", - "scalar_variable_for_testing_b", - "scalar_variable_for_testing_c", - "scheme_order_in_suite", "flag_indicating_cloud_microphysics_has_graupel", "flag_indicating_cloud_microphysics_has_ice", - "surface_downwelling_shortwave_radiation_flux", - "surface_upwelling_shortwave_radiation_flux", - "longwave_radiation_fluxes", - "num_subcycles_for_effr"] -_OUTPUT_VARS_VAR_ACTION = ["ccpp_error_code", "ccpp_error_message", - "effective_radius_of_stratiform_cloud_ice_particle", - "effective_radius_of_stratiform_cloud_liquid_water_particle", - "effective_radius_of_stratiform_cloud_snow_particle", - "cloud_ice_number_concentration", - "effective_radius_of_stratiform_cloud_rain_particle", - "turbulent_kinetic_energy", - "turbulent_kinetic_energy2", - "scalar_variable_for_testing", - "scalar_variable_for_testing", - "surface_downwelling_shortwave_radiation_flux", - "surface_upwelling_shortwave_radiation_flux", - "longwave_radiation_fluxes", - "scheme_order_in_suite"] + "num_subcycles_for_effr", + "physics_state_derived_type", + "effective_radius_of_stratiform_cloud_snow_particle"] +_OUTPUT_VARS_VAR_ACTION = ["ccpp_error_code", "ccpp_error_message","physics_state_derived_type", + "effective_radius_of_stratiform_cloud_snow_particle"] _REQUIRED_VARS_VAR_ACTION = _INPUT_VARS_VAR_ACTION + _OUTPUT_VARS_VAR_ACTION