diff --git a/cime_config/cam_autogen.py b/cime_config/cam_autogen.py index 1ad5af89..f6c9a69d 100644 --- a/cime_config/cam_autogen.py +++ b/cime_config/cam_autogen.py @@ -359,8 +359,7 @@ def _update_genccpp_dir(utility_files, genccpp_dir): ############################################################################### def generate_registry(data_search, build_cache, atm_root, bldroot, - source_mods_dir, dycore, gen_fort_indent, - reg_config=None): + source_mods_dir, dycore, gen_fort_indent): ############################################################################### """ Generate the CAM data source and metadata from the registry, @@ -382,14 +381,14 @@ def generate_registry(data_search, build_cache, atm_root, bldroot, if os.path.exists(genreg_dir): do_gen_registry = build_cache.registry_mismatch(gen_reg_file, registry_files, - dycore, reg_config) + dycore) else: os.makedirs(genreg_dir) do_gen_registry = True # End if if do_gen_registry: for reg_file in registry_files: - retvals = gen_registry(reg_file, dycore, reg_config, genreg_dir, + retvals = gen_registry(reg_file, dycore, genreg_dir, gen_fort_indent, source_mods_dir, atm_root, logger=_LOGGER, schema_paths=data_search, error_on_no_validate=True) @@ -407,7 +406,7 @@ def generate_registry(data_search, build_cache, atm_root, bldroot, # Save build details in the build cache reg_file_paths = [x.file_path for x in reg_file_list if x.file_path] build_cache.update_registry(gen_reg_file, registry_files, dycore, - reg_config, reg_file_paths, ic_names) + reg_file_paths, ic_names) else: # If we did not run the registry generator, retrieve info from cache reg_file_paths = build_cache.reg_file_list() diff --git a/cime_config/cam_build_cache.py b/cime_config/cam_build_cache.py index 7d4f886f..2bda072e 100644 --- a/cime_config/cam_build_cache.py +++ b/cime_config/cam_build_cache.py @@ -215,7 +215,6 @@ def __init__(self, build_cache): self.__gen_init_file = None self.__registry_files = {} self.__dycore = None - self.__config = None self.__sdfs = {} self.__schemes = {} self.__host_files = {} @@ -244,8 +243,6 @@ def __init__(self, build_cache): self.__registry_files[new_entry.key] = new_entry elif item.tag == 'dycore': self.__dycore = item.text - elif item.tag == 'config': - self.__config = item.text elif item.tag == 'reg_gen_file': self.__reg_gen_files.append(clean_xml_text(item)) elif item.tag == 'ic_name_entry': @@ -316,11 +313,10 @@ def __init__(self, build_cache): # end if def update_registry(self, gen_reg_file, registry_source_files, - dycore, config, reg_file_list, ic_names): + dycore, reg_file_list, ic_names): """Replace the registry cache data with input data """ self.__dycore = dycore - self.__config = config self.__gen_reg_file = FileStatus(gen_reg_file, 'generate_registry_file') self.__registry_files = {} for rfile in registry_source_files: @@ -393,8 +389,6 @@ def write(self): # end for dycore = ET.SubElement(registry, 'dycore') dycore.text = self.__dycore - config = ET.SubElement(registry, 'config') - config.text = self.__config for rgen_file in self.__reg_gen_files: rgen_entry = ET.SubElement(registry, 'reg_gen_file') rgen_entry.text = rgen_file @@ -450,14 +444,13 @@ def write(self): #End with def registry_mismatch(self, gen_reg_file, registry_source_files, - dycore, config): + dycore): """ Determine if the registry input data differs from the data stored in our cache. Return True if the data differs. """ mismatch = False mismatch = (not self.__dycore) or (self.__dycore != dycore) - mismatch = mismatch or (self.__config != config) if not mismatch: mismatch = self.__gen_reg_file.hash_mismatch(gen_reg_file) # end if @@ -467,7 +460,7 @@ def registry_mismatch(self, gen_reg_file, registry_source_files, my_reg_keys = set(self.__registry_files.keys()) test_reg_keys = {FileStatus.gen_key(x) for x in registry_source_files} - mismatch = (my_reg_keys != test_reg_keys) + mismatch = my_reg_keys != test_reg_keys for ref_file in registry_source_files: if mismatch: break @@ -522,7 +515,7 @@ def ccpp_mismatch(self, sdfs, scheme_files, host_files, if not mismatch: my_scheme_keys = set(self.__schemes.keys()) test_scheme_keys = {FileStatus.gen_key(x) for x in scheme_files} - mismatch = (my_scheme_keys != test_scheme_keys) + mismatch = my_scheme_keys != test_scheme_keys for ref_file in scheme_files: if mismatch: break @@ -537,7 +530,7 @@ def ccpp_mismatch(self, sdfs, scheme_files, host_files, if not mismatch: my_host_keys = set(self.__host_files.keys()) test_host_keys = {FileStatus.gen_key(x) for x in host_files} - mismatch = (my_host_keys != test_host_keys) + mismatch = my_host_keys != test_host_keys for ref_file in host_files: if mismatch: break @@ -564,7 +557,7 @@ def xml_nl_mismatch(self, create_nl_file, xml_files): # Note that this method will ignore duplicated files. my_xml_keys = set(self.__xml_files.keys()) test_xml_keys = {FileStatus.gen_key(x) for x in xml_files.values()} - mismatch = (my_xml_keys != test_xml_keys) + mismatch = my_xml_keys != test_xml_keys for ref_file in xml_files.values(): if mismatch: break diff --git a/src/data/generate_registry_data.py b/src/data/generate_registry_data.py index 7541c56a..33adc954 100755 --- a/src/data/generate_registry_data.py +++ b/src/data/generate_registry_data.py @@ -50,8 +50,8 @@ def write_ccpp_table_header(name, outfile): ############################################################################### """Write the standard Fortran comment block for a CCPP header (module, type, scheme).""" - outfile.write(r"!> \section arg_table_{} Argument Table".format(name), 0) - outfile.write(r"!! \htmlinclude {}.html".format(name), 0) + outfile.write(rf"!> \section arg_table_{name} Argument Table", 0) + outfile.write(rf"!! \htmlinclude {name}.html", 0) ############################################################################### class TypeEntry: @@ -161,9 +161,10 @@ def __init__(self, elem_node, local_name, dimensions, known_types, self.__local_index_name = local_index_name self.__local_index_name_str = local_index_name_str self.__allocatable = elem_node.get('allocatable', default=alloc_default) - self.__advected = elem_node.get("advected", default=False) - self.__tstep_init = elem_node.get("phys_timestep_init_zero", - default=tstep_init_default) + self.__constituent = elem_node.get("constituent", default=False) + self.__advected = elem_node.get("advected", default=False) + self.__tstep_init = elem_node.get("phys_timestep_init_zero", + default=tstep_init_default) if self.__allocatable == "none": self.__allocatable = "" # end if @@ -283,7 +284,7 @@ def write_initial_value(self, outfile, indent, init_var, ddt_str, physconst_vars outfile.write(f"if ({init_var}) then", indent) outfile.write(f"{var_name} = {init_val}", indent+1) if self.initial_val_vars and self.initial_val_vars.issubset(physconst_vars): - outfile.write(f"call mark_as_initialized('{self.standard_name}')", indent+1) + outfile.write(f"call mark_as_initialized('{self.standard_name}')", indent+1) # end if outfile.write("end if", indent) # end if @@ -390,6 +391,11 @@ def is_ddt(self): """Return True iff this variable is a derived type""" return self.__type.ddt + @property + def is_constituent(self): + """Return True if this variable is a constituent""" + return self.__constituent + @property def is_advected(self): """Return True if this variable is advected""" @@ -498,8 +504,9 @@ class Variable(VarBase): # Constant dimensions __CONSTANT_DIMENSIONS = {'ccpp_constant_one' : 1, 'ccpp_constant_zero' : 0} - __VAR_ATTRIBUTES = ["access", "advected", "allocatable", "dycore", - "extends", "kind", "local_name", "name", + __VAR_ATTRIBUTES = ["access", "advected", "allocatable", + "constituent", "dycore", "extends", + "kind", "local_name", "name", "phys_timestep_init_zero", "standard_name", "type", "units", "version"] @@ -613,6 +620,11 @@ def __init__(self, var_node, known_types, vdict, logger): def write_metadata(self, outfile): """Write out this variable as CCPP metadata""" + #If variable is a constituent, + #then don't add to metadata file: + if self.is_constituent: + return + # end if if self.access != "private": super().write_metadata(outfile) if (self.allocatable == "parameter") or self.protected: @@ -636,6 +648,11 @@ def write_definition(self, outfile, access, indent, attribute is suppressed (e.g., for a DDT, even 'protected' variables cannot have the protected attribute. """ + #If variable is a constituent, then don't add + #to source file: + if self.is_constituent: + return + # end if # Protected string if has_protect and self.protected: pro_str = "protected" @@ -681,7 +698,7 @@ def write_definition(self, outfile, access, indent, if self.initial_value: if self.allocatable == "pointer": init_str = f" => {self.initial_value}" - elif not (self.allocatable[0:11] == 'allocatable'): + elif not self.allocatable[0:11] == 'allocatable': init_str = f" = {self.initial_value}" # end if (no else, do not initialize allocatable fields) # end if @@ -703,6 +720,11 @@ def write_allocate_routine(self, outfile, indent, is a string to use to write reallocate test code. is a prefix string (e.g., state%). """ + #If variable is a constituent, then don't add + #to source file: + if self.is_constituent: + return + # end if # Be careful about dimensions, scalars have none, not '()' if self.dimensions: dimension_string = self.dimension_string @@ -768,7 +790,11 @@ def write_tstep_init_routine(self, outfile, indent, of the variable initiliazation code even if not directly specified in the registry itself. """ - + #If variable is a constituent, then don't add + #to source file: + if self.is_constituent: + return + # end if # Be careful about dimensions, scalars have none, not '()' if self.dimensions: dimension_string = self.dimension_string @@ -899,15 +925,17 @@ def add_variable(self, newvar): # end if self[local_name.lower()] = newvar self.__standard_names.append(std_name.lower()) - for dim in newvar.dimensions: - dimstrs = [x.strip() for x in dim.split(':')] - for ddim in dimstrs: - lname = Variable.constant_dimension(ddim) - if not lname: - self.__dimensions.add(dim.lower()) - # end if + if not newvar.is_constituent: #Don't add dimensions if a constituent + for dim in newvar.dimensions: + dimstrs = [x.strip() for x in dim.split(':')] + for ddim in dimstrs: + lname = Variable.constant_dimension(ddim) + if not lname: + self.__dimensions.add(dim.lower()) + # end if + # end for # end for - # end for + # end if (constituent) # Parse out all strings from initial value all_strings = _ALL_STRINGS_REGEX.findall(newvar.initial_value) init_val_vars = set() @@ -915,7 +943,7 @@ def add_variable(self, newvar): # Exclude NULL and nan variables for var in all_strings: if var.lower() not in excluded_initializations: - init_val_vars.add(var) + init_val_vars.add(var) # end if # end if self.__initial_value_vars.update(init_val_vars) @@ -1027,17 +1055,16 @@ class DDT: ############################################################################### """Registry DDT""" - def __init__(self, ddt_node, known_types, var_dict, dycore, config, logger): + def __init__(self, ddt_node, known_types, var_dict, dycore): """Initialize a DDT from registry XML () is the dictionary where variables referenced in must reside. Each DDT variable is removed from - >>> DDT(ET.fromstring('ice_cream'), TypeRegistry(), VarDict("foo", "module", None), 'eul', None, None) #doctest: +IGNORE_EXCEPTION_DETAIL + >>> DDT(ET.fromstring('ice_cream'), TypeRegistry(), VarDict("foo", "module", None), 'eul') #doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): CCPPError: Unknown DDT element type, 'dessert', in 'physics_state' """ self.__type = ddt_node.get('type') - self.__logger = logger self.__data = [] extends = ddt_node.get('extends', default=None) if extends is None: @@ -1108,7 +1135,7 @@ def write_metadata(self, outfile): def write_definition(self, outfile, access, indent): """Write out the Fortran definition for this DDT - >>> DDT(ET.fromstring('>'), TypeRegistry(), VarDict("foo", "module", None), 'eul', None, None).write_definition(None, 'public', 0) #doctest: +IGNORE_EXCEPTION_DETAIL + >>> DDT(ET.fromstring('>'), TypeRegistry(), VarDict("foo", "module", None), 'eul').write_definition(None, 'public', 0) #doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): CCPPError: DDT, 'physics_state', has no member variables """ @@ -1168,13 +1195,13 @@ class File: ############################################################################### """Object describing a file object in a registry file - >>> File(ET.fromstring(''), TypeRegistry(), 'eul', "", None) #doctest: +IGNORE_EXCEPTION_DETAIL + >>> File(ET.fromstring(''), TypeRegistry(), 'eul', None) #doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): CCPPError: Illegal use entry, no reference - >>> File(ET.fromstring(''), TypeRegistry(), 'eul', "", None) #doctest: +IGNORE_EXCEPTION_DETAIL + >>> File(ET.fromstring(''), TypeRegistry(), 'eul', None) #doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): CCPPError: Illegal use entry, no module - >>> File(ET.fromstring(''), TypeRegistry(), 'eul', "", None) #doctest: +IGNORE_EXCEPTION_DETAIL + >>> File(ET.fromstring(''), TypeRegistry(), 'eul', None) #doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): CCPPError: Unknown registry File element, 'user' """ @@ -1186,7 +1213,7 @@ class File: 'number_of_constituents' : 4} __min_dim_key = 5 # For sorting unknown dimensions - def __init__(self, file_node, known_types, dycore, config, + def __init__(self, file_node, known_types, dycore, logger, gen_code=True, file_path=None): """Initialize a File object from a registry node (XML)""" self.__var_dict = VarDict(file_node.get('name'), file_node.get('type'), @@ -1202,8 +1229,7 @@ def __init__(self, file_node, known_types, dycore, config, if obj.tag in ['variable', 'array']: self.add_variable(obj, logger) elif obj.tag == 'ddt': - newddt = DDT(obj, self.__known_types, self.__var_dict, - dycore, config, logger) + newddt = DDT(obj, self.__known_types, self.__var_dict, dycore) self.add_ddt(newddt, logger=logger) elif obj.tag == 'use': module = obj.get('module', default=None) @@ -1481,7 +1507,7 @@ def parse_command_line(args, description): return pargs ############################################################################### -def metadata_file_to_files(file_path, known_types, dycore, config, run_env): +def metadata_file_to_files(file_path, known_types, dycore, run_env): ############################################################################### """Read the metadata file at and convert it to a registry File object. @@ -1507,8 +1533,8 @@ def metadata_file_to_files(file_path, known_types, dycore, config, run_env): # end if section = f'' sect_xml = ET.fromstring(section) - mfile = File(sect_xml, known_types, dycore, config, - run_env.logger, gen_code=False, file_path=file_path) + mfile = File(sect_xml, known_types, dycore, run_env.logger, + gen_code=False, file_path=file_path) # Add variables # Note, we only support one section per table for host variables sections = mtable.sections() @@ -1561,8 +1587,7 @@ def metadata_file_to_files(file_path, known_types, dycore, config, run_env): # end for vnode_str += '\n' var_node = ET.fromstring(vnode_str) - new_ddt = DDT(var_node, known_types, mfile.var_dict, - dycore, config, run_env.logger) + new_ddt = DDT(var_node, known_types, mfile.var_dict, dycore) mfile.add_ddt(new_ddt, logger=run_env.logger) # end if mfiles.append(mfile) @@ -1570,7 +1595,7 @@ def metadata_file_to_files(file_path, known_types, dycore, config, run_env): return mfiles ############################################################################### -def write_registry_files(registry, dycore, config, outdir, src_mod, src_root, +def write_registry_files(registry, dycore, outdir, src_mod, src_root, reg_dir, indent, logger): ############################################################################### """Write metadata and source files for to @@ -1579,7 +1604,7 @@ def write_registry_files(registry, dycore, config, outdir, src_mod, src_root, is useful if a metadata file path has "$SRCROOT" is used as a parent path if a metadata file is a relative path. - >>> File(ET.fromstring(''), TypeRegistry(), 'eul', "", None) #doctest: +IGNORE_EXCEPTION_DETAIL + >>> File(ET.fromstring(''), TypeRegistry(), 'eul', None) #doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): CCPPError: Unknown registry object type, 'variable' """ @@ -1594,7 +1619,7 @@ def write_registry_files(registry, dycore, config, outdir, src_mod, src_root, logger.info(f"Parsing {section.tag}, {sec_name}, from registry") # end if if section.tag == 'file': - files.append(File(section, known_types, dycore, config, logger)) + files.append(File(section, known_types, dycore, logger)) elif section.tag == 'metadata_file': # Find the correct file path and parse that metadata file relative_file_path = section.text @@ -1622,7 +1647,7 @@ def write_registry_files(registry, dycore, config, outdir, src_mod, src_root, # end if # end if meta_files = metadata_file_to_files(file_path, known_types, - dycore, config, run_env) + dycore, run_env) files.extend(meta_files) else: emsg = "Unknown registry object type, '{}'" @@ -1709,7 +1734,7 @@ def _create_ic_name_dict(registry): return ic_name_dict ############################################################################### -def gen_registry(registry_file, dycore, config, outdir, indent, +def gen_registry(registry_file, dycore, outdir, indent, src_mod, src_root, loglevel=None, logger=None, schema_paths=None, error_on_no_validate=False): ############################################################################### @@ -1782,7 +1807,7 @@ def gen_registry(registry_file, dycore, config, outdir, indent, emsg = f"Parsing registry, {library_name}" logger.debug(emsg) reg_dir = os.path.dirname(registry_file) - files = write_registry_files(registry, dycore, config, outdir, src_mod, + files = write_registry_files(registry, dycore, outdir, src_mod, src_root, reg_dir, indent, logger) # See comment in _create_ic_name_dict ic_names = _create_ic_name_dict(registry) @@ -1807,7 +1832,7 @@ def main(): # end if retvals = gen_registry(args.registry_file, args.dycore.lower(), - args.config, outdir, args.indent, args.source_mods, + outdir, args.indent, args.source_mods, args.source_root, loglevel=loglevel) return retvals diff --git a/src/data/registry.xml b/src/data/registry.xml index f0e3f708..c9dd29e7 100644 --- a/src/data/registry.xml +++ b/src/data/registry.xml @@ -1,7 +1,7 @@ - + $SRCROOT/src/utils/spmd_utils.meta $SRCROOT/src/control/cam_logfile.meta @@ -373,5 +373,31 @@ horizontal_dimension vertical_layer_dimension zvir + + + + Water vapor mass mixing ratio with respect to moist air plus all airborne condensates + Q cnst_Q + + + Cloud water mass mixing ratio with respect to moist air plus all airborne condensates + CLDLIQ cnst_CLDLIQ + + + Cloud ice mass mixing ratio with respect to moist air plus all airborne condensates + CLDICE cnst_CLDICE + + + rain mass mixing ratio with respect to moist air plus all airborne condensates + RAINQM cnst_RAINQM + diff --git a/src/data/registry_v1_0.xsd b/src/data/registry_v1_0.xsd index e752443e..81f756dc 100644 --- a/src/data/registry_v1_0.xsd +++ b/src/data/registry_v1_0.xsd @@ -106,6 +106,15 @@ + + + + + + @@ -132,17 +141,16 @@ - + + + + + + - - - @@ -159,10 +167,9 @@ - - + + + @@ -195,15 +202,16 @@ - - + + + + @@ -237,8 +245,9 @@ - - + + + diff --git a/src/data/write_init_files.py b/src/data/write_init_files.py index c07b6535..1567ddbd 100644 --- a/src/data/write_init_files.py +++ b/src/data/write_init_files.py @@ -130,7 +130,7 @@ def write_init_files(cap_database, ic_names, outdir, # Gather all the host model variables that are required by # any of the compiled CCPP physics suites. - host_vars, retmsg = gather_ccpp_req_vars(cap_database) + host_vars, constituent_set, retmsg = gather_ccpp_req_vars(cap_database) # Quit now if there are missing variables if retmsg: @@ -234,17 +234,17 @@ def write_init_files(cap_database, ic_names, outdir, host_dict = cap_database.host_model_dict() # Collect imported host variables - host_imports = collect_host_var_imports(host_vars, host_dict) + host_imports = collect_host_var_imports(host_vars, host_dict, constituent_set) # Write physics_read_data subroutine: write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports, - phys_check_fname_str) + phys_check_fname_str, constituent_set) outfile.blank_line() # Write physics_check_data subroutine: write_phys_check_subroutine(outfile, host_dict, host_vars, host_imports, - phys_check_fname_str) + phys_check_fname_str, constituent_set) # -------------------------------------- @@ -268,11 +268,9 @@ def __init__(self, message): ################# ############################################################################## -def _find_and_add_host_variable(stdname, host_dict, const_dicts, var_dict): +def _find_and_add_host_variable(stdname, host_dict, var_dict): """Find in and add it to if found and not of type, 'host'. - If is not in but is in one of the , - it is considered found but not added to . If not found, add to . If found and added to , also process the standard names of any intrinsic sub-elements of . @@ -289,30 +287,22 @@ def _find_and_add_host_variable(stdname, host_dict, const_dicts, var_dict): if isinstance(ielem, list): for sname in ielem: smissing = _find_and_add_host_variable(sname, host_dict, - const_dicts, var_dict) + var_dict) missing_vars.extend(smissing) # end for # end if # end if if not hvar: - cvar = None - for cdict in const_dicts: - cvar = cdict.find_variable(stdname) - if cvar: - break - # end if - # end for - if not cvar: - missing_vars.append(stdname) - # end if + missing_vars.append(stdname) # end if return missing_vars ############################################################################## def gather_ccpp_req_vars(cap_database): """ - Generate a list of host-model variables required by the CCPP physics - suites potentially being used in this model run. + Generate a list of host-model and constituent variables + required by the CCPP physics suites potentially being used + in this model run. is the database object returned by capgen. It is an error if any physics suite variable is not accessible in the host model. @@ -325,12 +315,10 @@ def gather_ccpp_req_vars(cap_database): # Key is standard name, value is host-model or constituent variable req_vars = {} missing_vars = set() + constituent_vars = set() retmsg = "" # Host model dictionary host_dict = cap_database.host_model_dict() - # Constituent dictionaries - const_dicts = [cap_database.constituent_dictionary(s) - for s in cap_database.suite_list()] # Create CCPP datatable required variables-listing object: # XXgoldyXX: Choose only some phases here? @@ -338,13 +326,23 @@ def gather_ccpp_req_vars(cap_database): for cvar in cap_database.call_list(phase).variable_list(): stdname = cvar.get_prop_value('standard_name') intent = cvar.get_prop_value('intent') + is_const = cvar.get_prop_value('advected') if ((intent in _INPUT_TYPES) and (stdname not in req_vars) and (stdname not in _EXCLUDED_STDNAMES)): - # We need to work with the host model version of this variable - missing = _find_and_add_host_variable(stdname, host_dict, - const_dicts, req_vars) - missing_vars.update(missing) + if is_const: + #Variable is a constituent, so may not be known + #until runtime, but still need variable names in order + #to read from a file if need be: + req_vars[stdname] = cvar + + #Add variable to constituent set: + constituent_vars.add(stdname) + else: + # We need to work with the host model version of this variable + missing = _find_and_add_host_variable(stdname, host_dict, + req_vars) + missing_vars.update(missing) # end if # end if (do not include output variables) # end for (loop over call list) @@ -355,7 +353,7 @@ def gather_ccpp_req_vars(cap_database): retmsg = f"Error: Missing required host variables: {mvlist}" # end if # Return the required variables as a list - return list(req_vars.values()), retmsg + return list(req_vars.values()), constituent_vars, retmsg ########################## #FORTRAN WRITING FUNCTIONS @@ -371,7 +369,7 @@ def write_ic_params(outfile, host_vars, ic_names): """ #Create new Fortran integer parameter to store total number of variables: - outfile.write("!Total number of physics-related variables:", 1) + outfile.comment("Total number of physics-related variables:", 1) num_pvars = len(host_vars) outfile.write(f"integer, public, parameter :: phys_var_num = {num_pvars}", 1) @@ -396,7 +394,7 @@ def write_ic_params(outfile, host_vars, ic_names): #Create final Fortran integer parameter to store max length of #input variable name string: - outfile.write("!Max length of input (IC) file variable names:", 1) + outfile.comment("Max length of input (IC) file variable names:", 1) # We need to look either in ic_names or the host variable max_loclen = 0 for hvar in host_vars: @@ -623,7 +621,7 @@ def _get_host_model_import(hvar, import_dict, host_dict): raise CamInitWriteError(f"Missing host indices: {mi_str}.") # end if -def collect_host_var_imports(host_vars, host_dict): +def collect_host_var_imports(host_vars, host_dict, constituent_set): """Construct a dictionary of host-model variables to import keyed by host-model module name. is used to look up array-reference indices. @@ -642,6 +640,11 @@ def collect_host_var_imports(host_vars, host_dict): if hvar.source.ptype == 'host': continue # end if + # We also do not want to import constituent variables, as they + # should be automatically handled by the constituents object: + if hvar.get_prop_value('standard_name') in constituent_set: + continue + # end if _get_host_model_import(hvar, use_vars_write_dict, host_dict) # end for return [[x, sorted(use_vars_write_dict[x])] for x in use_vars_write_dict] @@ -756,7 +759,7 @@ def get_dimension_info(hvar): return vdim_name, legal_dims, fail_reason def write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports, - phys_check_fname_str): + phys_check_fname_str, constituent_set): """ Write the "physics_read_data" subroutine, which @@ -784,6 +787,12 @@ def write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports, var_stdname = hvar.get_prop_value('standard_name') var_locname = hvar.call_string(host_dict) + # Ignore any variable that is listed as a constiutuent, + # as they will be handled separately by the constituents object: + if var_stdname in constituent_set: + continue + # end if + # Set "if-statement" call string: call_string_key = f"case ('{var_stdname}')" @@ -834,7 +843,7 @@ def write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports, "prot_no_init_idx", "const_idx"]], ["cam_ccpp_cap", ["ccpp_physics_suite_variables", "cam_constituents_array", "cam_model_const_properties"]], ["ccpp_kinds", ["kind_phys"]], - [phys_check_fname_str, ["phys_var_stdnames", + [phys_check_fname_str, ["phys_var_num", "phys_var_stdnames", "input_var_names", "std_name_len"]], ["ccpp_constituent_prop_mod", ["ccpp_constituent_prop_ptr_t"]], ["cam_logfile", ["iulog"]]] @@ -867,8 +876,10 @@ def write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports, outfile.blank_line() outfile.write("character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message", 2) outfile.write("integer :: errflg !CCPP framework error flag", 2) + outfile.write("integer :: n !Loop control variable", 2) outfile.write("integer :: name_idx !Input variable array index", 2) outfile.write("integer :: constituent_idx !Constituent table index", 2) + outfile.write("integer :: const_input_idx !input_var_names index for a consituent", 2) outfile.write("integer :: req_idx !Required variable array index", 2) outfile.write("integer :: suite_idx !Suite array index", 2) outfile.write("character(len=2) :: sep !String separator used to print err messages", 2) @@ -974,7 +985,21 @@ def write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports, outfile.blank_line() outfile.write("var_found = .false.", 6) outfile.write("field_data_ptr => cam_constituents_array()", 6) - outfile.write("call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found)", 6) + outfile.blank_line() + outfile.comment("Check if constituent standard name in registered SIMA standard names list:", 6) + outfile.write("if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then", 6) + outfile.comment("Find array index to extract correct input names:", 7) + outfile.write("do n=1, phys_var_num", 7) + outfile.write("if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then", 8) + outfile.write("const_input_idx = n", 9) + outfile.write("exit", 9) + outfile.write("end if", 8) + outfile.write("end do", 7) + outfile.write("call read_field(file, ccpp_required_data(req_idx), input_var_names(:,const_input_idx), 'lev', timestep, field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found)", 7) + outfile.write("else", 6) + outfile.comment("If not in standard names list, then just use constituent name as input file name:",7) + outfile.write("call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found)", 7) + outfile.write("end if", 6) outfile.write("if(.not. var_found) then", 6) outfile.write("const_props => cam_model_const_properties()", 7) outfile.write("constituent_has_default = .false.", 7) @@ -1056,7 +1081,7 @@ def write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports, ##### def write_phys_check_subroutine(outfile, host_dict, host_vars, host_imports, - phys_check_fname_str): + phys_check_fname_str, constituent_set): """ Write the "physics_check_data" subroutine, which @@ -1082,6 +1107,12 @@ def write_phys_check_subroutine(outfile, host_dict, host_vars, host_imports, var_stdname = hvar.get_prop_value('standard_name') var_locname = hvar.call_string(host_dict) + # Ignore any variable that is listed as a constiutuent, + # as they will be handled separately by the constituents object: + if var_stdname in constituent_set: + continue + # end if + # Set "if-statement" call string: call_string_key = f"case ('{var_stdname}')" @@ -1126,9 +1157,10 @@ def write_phys_check_subroutine(outfile, host_dict, host_vars, host_imports, ["phys_vars_init_check", ["is_read_from_file"]], ["ioFileMod", ["cam_get_file"]], ["cam_pio_utils", ["cam_pio_openfile", "cam_pio_closefile"]], - [f"{phys_check_fname_str}", ["phys_var_stdnames", - "input_var_names", - "std_name_len"]]] + [phys_check_fname_str, ["phys_var_num", + "phys_var_stdnames", + "input_var_names", + "std_name_len"]]] # Add in host model data use statements use_stmts.extend(host_imports) @@ -1161,8 +1193,10 @@ def write_phys_check_subroutine(outfile, host_dict, host_vars, host_imports, outfile.blank_line() outfile.write("character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message", 2) outfile.write("integer :: errflg !CCPP framework error flag", 2) + outfile.write("integer :: n !Loop control variable", 2) outfile.write("integer :: name_idx !Input variable array index", 2) outfile.write("integer :: constituent_idx !Index of variable in constituent array", 2) + outfile.write("integer :: const_input_idx !input_var_names index for a consituent", 2) outfile.write("integer :: req_idx !Required variable array index", 2) outfile.write("integer :: suite_idx !Suite array index", 2) outfile.write("character(len=SHR_KIND_CL) :: ncdata_check_loc", 2) @@ -1236,7 +1270,22 @@ def write_phys_check_subroutine(outfile, host_dict, host_vars, host_imports, outfile.write("if (constituent_idx > -1) then", 4) outfile.comment("The required variable is a constituent. Call check variable routine on the relevant index of the constituent array", 5) outfile.write("field_data_ptr => cam_advected_constituents_array()", 5) - outfile.write("call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), ccpp_required_data(req_idx), min_difference, min_relative_value, is_first)", 5) + outfile.blank_line() + outfile.comment("Check if constituent standard name in registered SIMA standard names list:", 5) + outfile.write("if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then", 5) + outfile.comment("Find array index to extract correct input names:", 6) + outfile.write("do n=1, phys_var_num", 6) + outfile.write("if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then", 7) + outfile.write("const_input_idx = n", 8) + outfile.write("exit", 8) + outfile.write("end if", 7) + outfile.write("end do", 6) + outfile.write("call check_field(file, input_var_names(:,const_input_idx), 'lev', timestep, field_data_ptr(:,:,constituent_idx), ccpp_required_data(req_idx), min_difference, min_relative_value, is_first)", 6) + outfile.write("else", 5) + outfile.comment("If not in standard names list, then just use constituent name as input file name:",6) + outfile.write("call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), ccpp_required_data(req_idx), min_difference, min_relative_value, is_first)", 6) + outfile.write("end if", 5) + outfile.write("else", 4) outfile.comment("The required variable is not a constituent. Check if the variable was read from a file", 5) diff --git a/src/physics/utils/physics_data.F90 b/src/physics/utils/physics_data.F90 index b5627660..939ec33f 100644 --- a/src/physics/utils/physics_data.F90 +++ b/src/physics/utils/physics_data.F90 @@ -61,6 +61,18 @@ integer function find_input_name_idx(stdname, use_init_variables, constituent_in find_input_name_idx = no_exist_idx constituent_index = no_exist_idx + !First check if quantity is a constituent: + call const_get_index(trim(stdname), find_input_name_idx, abort=.false., warning=.false.) + if (find_input_name_idx < 0) then + find_input_name_idx = no_exist_idx + else + constituent_index = find_input_name_idx + find_input_name_idx = const_idx + !Return from function here, + !as variable has already been found: + return + end if + !Loop through physics variable standard names: do idx = 1, phys_var_num !Check if provided name is in required names array: @@ -86,7 +98,7 @@ integer function find_input_name_idx(stdname, use_init_variables, constituent_in !If not already initialized, then pass on the real array index: find_input_name_idx = idx end if - !Exit function: + !Exit physics variable name loop: exit end if end do @@ -100,22 +112,11 @@ integer function find_input_name_idx(stdname, use_init_variables, constituent_in end if end do end if - ! If still not found, look in the constituent hash table - if (find_input_name_idx == no_exist_idx) then - call const_get_index(trim(stdname), find_input_name_idx, abort=.false., warning=.false.) - if (find_input_name_idx < 0) then - find_input_name_idx = no_exist_idx - else - constituent_index = find_input_name_idx - find_input_name_idx = const_idx - end if - end if - end function find_input_name_idx - function arr2str(name_array) + pure function arr2str(name_array) ! Dummy arguments character(len=*), intent(in) :: name_array(:) character(len=256) :: arr2str @@ -369,6 +370,11 @@ subroutine check_field_2d(file, var_names, timestep, current_value, & max_diff(2) = real(iam, kind_phys) !MPI rank for this task call cam_pio_find_var(file, var_names, found_name, vardesc, var_found) + if (.not. var_found) then + !Try searching again using the variable standard name: + call cam_pio_find_var(file, [stdname], found_name, vardesc, var_found) + end if + if (var_found) then call cam_read_field(found_name, file, buffer, var_found, & timelevel=timestep, log_output=.false.) @@ -492,6 +498,10 @@ subroutine check_field_3d(file, var_names, vcoord_name, timestep, & max_diff(2) = real(iam, kind_phys) !MPI rank for this task call cam_pio_find_var(file, var_names, found_name, vardesc, var_found) + if (.not. var_found) then + !Try searching again using the variable standard name: + call cam_pio_find_var(file, [stdname], found_name, vardesc, var_found) + end if if (var_found) then if (trim(vcoord_name) == 'lev') then diff --git a/test/unit/sample_files/build_cache_files/bad_ccpp_tag_build_cache.xml b/test/unit/sample_files/build_cache_files/bad_ccpp_tag_build_cache.xml index bb1b5d21..54f383f5 100644 --- a/test/unit/sample_files/build_cache_files/bad_ccpp_tag_build_cache.xml +++ b/test/unit/sample_files/build_cache_files/bad_ccpp_tag_build_cache.xml @@ -5,7 +5,6 @@ none - /yellow/brick/road/munchkin.meta brain heart diff --git a/test/unit/sample_files/build_cache_files/bad_reg_tag_build_cache.xml b/test/unit/sample_files/build_cache_files/bad_reg_tag_build_cache.xml index 0f30ad1b..1063c0b9 100644 --- a/test/unit/sample_files/build_cache_files/bad_reg_tag_build_cache.xml +++ b/test/unit/sample_files/build_cache_files/bad_reg_tag_build_cache.xml @@ -5,7 +5,6 @@ none - /yellow/brick/road/munchkin.meta brain heart diff --git a/test/unit/sample_files/build_cache_files/bad_section_tag_build_cache.xml b/test/unit/sample_files/build_cache_files/bad_section_tag_build_cache.xml index 7d454ab6..ffde0dcb 100644 --- a/test/unit/sample_files/build_cache_files/bad_section_tag_build_cache.xml +++ b/test/unit/sample_files/build_cache_files/bad_section_tag_build_cache.xml @@ -5,7 +5,6 @@ none - /yellow/brick/road/munchkin.meta brain heart diff --git a/test/unit/sample_files/build_cache_files/example_build_cache.xml b/test/unit/sample_files/build_cache_files/example_build_cache.xml index 4c7ac6ff..f10dfd27 100644 --- a/test/unit/sample_files/build_cache_files/example_build_cache.xml +++ b/test/unit/sample_files/build_cache_files/example_build_cache.xml @@ -5,7 +5,6 @@ none - /yellow/brick/road/munchkin.meta brain heart diff --git a/test/unit/sample_files/build_cache_files/update_ccpp_build_cache.xml b/test/unit/sample_files/build_cache_files/update_ccpp_build_cache.xml index d25d8d4a..7b84bf52 100644 --- a/test/unit/sample_files/build_cache_files/update_ccpp_build_cache.xml +++ b/test/unit/sample_files/build_cache_files/update_ccpp_build_cache.xml @@ -5,7 +5,6 @@ none - /yellow/brick/road/munchkin.meta brain heart diff --git a/test/unit/sample_files/build_cache_files/update_init_gen_build_cache.xml b/test/unit/sample_files/build_cache_files/update_init_gen_build_cache.xml index b431b5d1..62a8909a 100644 --- a/test/unit/sample_files/build_cache_files/update_init_gen_build_cache.xml +++ b/test/unit/sample_files/build_cache_files/update_init_gen_build_cache.xml @@ -5,7 +5,6 @@ none - /yellow/brick/road/munchkin.meta brain heart diff --git a/test/unit/sample_files/build_cache_files/update_reg_build_cache.xml b/test/unit/sample_files/build_cache_files/update_reg_build_cache.xml index f394d8f3..e773ee2c 100644 --- a/test/unit/sample_files/build_cache_files/update_reg_build_cache.xml +++ b/test/unit/sample_files/build_cache_files/update_reg_build_cache.xml @@ -5,7 +5,6 @@ banana - tmp/cam_build_cache/test_reg.xml heart brain diff --git a/test/unit/sample_files/reg_good_simple.xml b/test/unit/sample_files/reg_good_simple.xml index 3ffa531d..66451ae0 100644 --- a/test/unit/sample_files/reg_good_simple.xml +++ b/test/unit/sample_files/reg_good_simple.xml @@ -20,5 +20,11 @@ horizontal_dimension lon + + + The coolest constituent imaginable + COOL_CAT cnst_COOL_CAT + diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_4D.F90 b/test/unit/sample_files/write_init_files/phys_vars_init_check_4D.F90 index a13f32c0..a0a4e78d 100644 --- a/test/unit/sample_files/write_init_files/phys_vars_init_check_4D.F90 +++ b/test/unit/sample_files/write_init_files/phys_vars_init_check_4D.F90 @@ -32,14 +32,14 @@ module phys_vars_init_check_4D integer, public, parameter :: INITIALIZED = 1 integer, public, parameter :: PARAM = 2 integer, public, parameter :: READ_FROM_FILE = 3 - !Total number of physics-related variables: + ! Total number of physics-related variables: integer, public, parameter :: phys_var_num = 2 integer, public, parameter :: phys_const_num = 15 !Max length of physics-related variable standard names: integer, public, parameter :: std_name_len = 25 - !Max length of input (IC) file variable names: + ! Max length of input (IC) file variable names: integer, public, parameter :: ic_name_len = 5 ! Physics-related input variable standard names: diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_bvd.F90 b/test/unit/sample_files/write_init_files/phys_vars_init_check_bvd.F90 index da57da0a..e2442382 100644 --- a/test/unit/sample_files/write_init_files/phys_vars_init_check_bvd.F90 +++ b/test/unit/sample_files/write_init_files/phys_vars_init_check_bvd.F90 @@ -32,14 +32,14 @@ module phys_vars_init_check_bvd integer, public, parameter :: INITIALIZED = 1 integer, public, parameter :: PARAM = 2 integer, public, parameter :: READ_FROM_FILE = 3 - !Total number of physics-related variables: + ! Total number of physics-related variables: integer, public, parameter :: phys_var_num = 2 integer, public, parameter :: phys_const_num = 15 !Max length of physics-related variable standard names: integer, public, parameter :: std_name_len = 25 - !Max length of input (IC) file variable names: + ! Max length of input (IC) file variable names: integer, public, parameter :: ic_name_len = 5 ! Physics-related input variable standard names: diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_cnst.F90 b/test/unit/sample_files/write_init_files/phys_vars_init_check_cnst.F90 new file mode 100644 index 00000000..365fe4c7 --- /dev/null +++ b/test/unit/sample_files/write_init_files/phys_vars_init_check_cnst.F90 @@ -0,0 +1,244 @@ +! +! This work (Common Community Physics Package Framework), identified by +! NOAA, NCAR, CU/CIRES, is free of known copyright restrictions and is +! placed in the public domain. +! +! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +! FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +! THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +! IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +! CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +!> +!! @brief Auto-generated Initialization-checking source file +!! +! +module phys_vars_init_check_cnst + + + implicit none + private + +!! public interfaces + public :: mark_as_initialized + public :: mark_as_read_from_file + public :: is_initialized + public :: is_read_from_file + +!! Parameterized initialized_vars options - order matters + integer, public, parameter :: UNINITIALIZED = 0 + integer, public, parameter :: INITIALIZED = 1 + integer, public, parameter :: PARAM = 2 + integer, public, parameter :: READ_FROM_FILE = 3 + ! Total number of physics-related variables: + integer, public, parameter :: phys_var_num = 3 + integer, public, parameter :: phys_const_num = 15 + + !Max length of physics-related variable standard names: + integer, public, parameter :: std_name_len = 25 + + ! Max length of input (IC) file variable names: + integer, public, parameter :: ic_name_len = 13 + + ! Physics-related input variable standard names: + character(len=25), public, protected :: phys_var_stdnames(phys_var_num) = (/ & + 'potential_temperature ', & + 'air_pressure_at_sea_level', & + 'super_cool_cat_const ' /) + + character(len=36), public, protected :: phys_const_stdnames(phys_const_num) = (/ & + "ccpp_constituent_minimum_values ", & + "ccpp_constituent_properties ", & + "ccpp_constituents ", & + "ccpp_error_code ", & + "ccpp_error_message ", & + "do_log_output ", & + "log_output_unit ", & + "mpi_communicator ", & + "mpi_rank ", & + "mpi_root ", & + "number_of_ccpp_advected_constituents", & + "number_of_ccpp_constituents ", & + "number_of_mpi_tasks ", & + "suite_name ", & + "suite_part " /) + !Array storing all registered IC file input names for each variable: + character(len=13), public, protected :: input_var_names(2, phys_var_num) = reshape((/ & + 'theta ', 'pot_temp ', & + 'slp ', 'sea_lev_pres ', & + 'COOL_CAT ', 'cnst_COOL_CAT' /), (/2, phys_var_num/)) + + ! Array indicating whether or not variable is protected: + logical, public, protected :: protected_vars(phys_var_num)= (/ & + .false., & + .false., & + .false. /) + + ! Variable state (UNINITIALIZED, INTIIALIZED, PARAM or READ_FROM_FILE): + integer, public, protected :: initialized_vars(phys_var_num)= (/ & + UNINITIALIZED, & + UNINITIALIZED, & + UNINITIALIZED /) + + +CONTAINS + + subroutine mark_as_initialized(varname) + + ! This subroutine marks the variable, , as + ! INITIALIZED in the `initialized_vars` array, + ! which means any initialization check should + ! now return True. + + ! Dummy argument + character(len=*), intent(in) :: varname !Variable name being marked + + ! Local variable + integer :: stdnam_idx !Standard name array index + + ! Search for in the standard name array: + do stdnam_idx = 1, phys_var_num + if (trim(phys_var_stdnames(stdnam_idx)) == trim(varname)) then + ! Only set to INITIALIZED if state is UNINITIALIZED + if (initialized_vars(stdnam_idx) < PARAM) then + initialized_vars(stdnam_idx) = INITIALIZED + end if + exit ! Exit loop once variable has been found and initialized + end if + end do + + ! No match is not an error because only + ! contains variables required by a physics suite. + + end subroutine mark_as_initialized + + subroutine mark_as_read_from_file(varname) + + ! This subroutine marks the varible, , as READ_FROM_FILE in the + ! initialized_vars array + + use cam_abortutils, only: endrun + + ! Dummy argument + character(len=*), intent(in) :: varname ! Variable name being marked + + ! Local variables + integer :: stdnam_idx ! Standard name array index + logical :: found_var ! .true. if is in arr. + character(len=*), parameter :: subname = 'mark_as_read_from_file' + + found_var = .false. + ! Set variable to READ_FROM_FILE: + do stdnam_idx = 1, phys_var_num + if (trim(phys_var_stdnames(stdnam_idx)) == trim(varname)) then + ! It is an error if the variable has already been set to PARAM + if (initialized_vars(stdnam_idx) == PARAM) then + call endrun("Variable '"//trim(varname)// & + "' was read from file, but is a parameter") + end if + initialized_vars(stdnam_idx) = READ_FROM_FILE + + ! Indicate variable has been found: + found_var = .true. + exit ! Exit loop once variable has been found and marked + end if + end do + + if (.not. found_var) then + ! This condition is an internal error, it should not happen + call endrun(subname//": Variable '"//trim(varname)// & + "' is missing from phys_var_stdnames array.") + end if + + end subroutine mark_as_read_from_file + + logical function is_initialized(varname) + + ! This function checks if the variable, , is already + ! initialized according to the 'initialized_vars' array. + + use cam_abortutils, only: endrun + + ! Dummy argument + character(len=*), intent(in) :: varname ! Variable name being checked + + ! Local variables + integer :: stdnam_idx ! Standard name array index + logical :: found ! Check that was found + character(len=*), parameter :: subname = 'is_initialized: ' + + is_initialized = .false. + found = .false. + + ! Check if variable is initialized (PARAM, INITIALIZED, or READ_FROM_FILE) + do stdnam_idx = 1, phys_var_num + if (trim(phys_var_stdnames(stdnam_idx)) == trim(varname)) then + is_initialized = (initialized_vars(stdnam_idx) > UNINITIALIZED) + found = .true. + exit ! Exit loop once variable has been found and checked + end if + end do + + if (.not. found) then + ! This condition is an internal error, it should not happen + call endrun(subname//": Variable '"//trim(varname)// & + "' is missing from phys_var_stdnames array.") + end if + + end function is_initialized + + subroutine is_read_from_file(varname, is_read, stdnam_idx_out) + + ! This subroutine checks if the variable, , is read from + ! file according to the 'initialized_vars' array. + + use cam_abortutils, only: endrun + + ! Dummy arguments + character(len=*), intent(in) :: varname ! Variable name being checked + logical, intent(out) :: is_read ! Set to .true. if from file + integer, optional, intent(out) :: stdnam_idx_out + + ! Local variables + + integer :: stdnam_idx ! Standard name array index + logical :: found ! Check that was found + character(len=*), parameter :: subname = 'is_read_from_file: ' + + is_read = .false. + found = .false. + + ! Return .true. if the variable's status is READ_FROM_FILE: + do stdnam_idx = 1, phys_var_num + if (trim(phys_var_stdnames(stdnam_idx)) == trim(varname)) then + is_read = (initialized_vars(stdnam_idx) == READ_FROM_FILE) + ! Mark as found: + found = .true. + exit ! Exit loop once variable has been found and checked + end if + end do + + if (.not. found) then + ! Check to see if this is an internally-protected variable + do stdnam_idx = 1, phys_const_num + if (trim(phys_const_stdnames(stdnam_idx)) == trim(varname)) then + found = .true. + exit ! Exit loop once variable has been found + end if + end do + end if + + if (.not. found) then + ! This condition is an internal error, it should not happen + call endrun(subname//": Variable '"//trim(varname)// & + "' is missing from phys_var_stdnames array.") + end if + if (present(stdnam_idx_out)) then + stdnam_idx_out = stdnam_idx + end if + + end subroutine is_read_from_file + +end module phys_vars_init_check_cnst diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_ddt.F90 b/test/unit/sample_files/write_init_files/phys_vars_init_check_ddt.F90 index 386aa066..eb05327e 100644 --- a/test/unit/sample_files/write_init_files/phys_vars_init_check_ddt.F90 +++ b/test/unit/sample_files/write_init_files/phys_vars_init_check_ddt.F90 @@ -32,14 +32,14 @@ module phys_vars_init_check_ddt integer, public, parameter :: INITIALIZED = 1 integer, public, parameter :: PARAM = 2 integer, public, parameter :: READ_FROM_FILE = 3 - !Total number of physics-related variables: + ! Total number of physics-related variables: integer, public, parameter :: phys_var_num = 2 integer, public, parameter :: phys_const_num = 15 !Max length of physics-related variable standard names: integer, public, parameter :: std_name_len = 25 - !Max length of input (IC) file variable names: + ! Max length of input (IC) file variable names: integer, public, parameter :: ic_name_len = 5 ! Physics-related input variable standard names: diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_ddt2.F90 b/test/unit/sample_files/write_init_files/phys_vars_init_check_ddt2.F90 index 027b422f..57476344 100644 --- a/test/unit/sample_files/write_init_files/phys_vars_init_check_ddt2.F90 +++ b/test/unit/sample_files/write_init_files/phys_vars_init_check_ddt2.F90 @@ -32,14 +32,14 @@ module phys_vars_init_check_ddt2 integer, public, parameter :: INITIALIZED = 1 integer, public, parameter :: PARAM = 2 integer, public, parameter :: READ_FROM_FILE = 3 - !Total number of physics-related variables: + ! Total number of physics-related variables: integer, public, parameter :: phys_var_num = 2 integer, public, parameter :: phys_const_num = 15 !Max length of physics-related variable standard names: integer, public, parameter :: std_name_len = 25 - !Max length of input (IC) file variable names: + ! Max length of input (IC) file variable names: integer, public, parameter :: ic_name_len = 5 ! Physics-related input variable standard names: diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_ddt_array.F90 b/test/unit/sample_files/write_init_files/phys_vars_init_check_ddt_array.F90 index 6290f927..acb20531 100644 --- a/test/unit/sample_files/write_init_files/phys_vars_init_check_ddt_array.F90 +++ b/test/unit/sample_files/write_init_files/phys_vars_init_check_ddt_array.F90 @@ -32,14 +32,14 @@ module phys_vars_init_check_ddt_array integer, public, parameter :: INITIALIZED = 1 integer, public, parameter :: PARAM = 2 integer, public, parameter :: READ_FROM_FILE = 3 - !Total number of physics-related variables: + ! Total number of physics-related variables: integer, public, parameter :: phys_var_num = 2 integer, public, parameter :: phys_const_num = 15 !Max length of physics-related variable standard names: integer, public, parameter :: std_name_len = 25 - !Max length of input (IC) file variable names: + ! Max length of input (IC) file variable names: integer, public, parameter :: ic_name_len = 39 ! Physics-related input variable standard names: diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_host_var.F90 b/test/unit/sample_files/write_init_files/phys_vars_init_check_host_var.F90 index 344b299e..80bcd703 100644 --- a/test/unit/sample_files/write_init_files/phys_vars_init_check_host_var.F90 +++ b/test/unit/sample_files/write_init_files/phys_vars_init_check_host_var.F90 @@ -32,14 +32,14 @@ module phys_vars_init_check_host_var integer, public, parameter :: INITIALIZED = 1 integer, public, parameter :: PARAM = 2 integer, public, parameter :: READ_FROM_FILE = 3 - !Total number of physics-related variables: + ! Total number of physics-related variables: integer, public, parameter :: phys_var_num = 1 integer, public, parameter :: phys_const_num = 15 !Max length of physics-related variable standard names: integer, public, parameter :: std_name_len = 25 - !Max length of input (IC) file variable names: + ! Max length of input (IC) file variable names: integer, public, parameter :: ic_name_len = 3 ! Physics-related input variable standard names: diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_mf.F90 b/test/unit/sample_files/write_init_files/phys_vars_init_check_mf.F90 index e71a22a0..affe1bc7 100644 --- a/test/unit/sample_files/write_init_files/phys_vars_init_check_mf.F90 +++ b/test/unit/sample_files/write_init_files/phys_vars_init_check_mf.F90 @@ -32,14 +32,14 @@ module phys_vars_init_check_mf integer, public, parameter :: INITIALIZED = 1 integer, public, parameter :: PARAM = 2 integer, public, parameter :: READ_FROM_FILE = 3 - !Total number of physics-related variables: + ! Total number of physics-related variables: integer, public, parameter :: phys_var_num = 2 integer, public, parameter :: phys_const_num = 15 !Max length of physics-related variable standard names: integer, public, parameter :: std_name_len = 25 - !Max length of input (IC) file variable names: + ! Max length of input (IC) file variable names: integer, public, parameter :: ic_name_len = 5 ! Physics-related input variable standard names: diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_no_horiz.F90 b/test/unit/sample_files/write_init_files/phys_vars_init_check_no_horiz.F90 index 962c9ddd..aa7f2cca 100644 --- a/test/unit/sample_files/write_init_files/phys_vars_init_check_no_horiz.F90 +++ b/test/unit/sample_files/write_init_files/phys_vars_init_check_no_horiz.F90 @@ -32,14 +32,14 @@ module phys_vars_init_check_no_horiz integer, public, parameter :: INITIALIZED = 1 integer, public, parameter :: PARAM = 2 integer, public, parameter :: READ_FROM_FILE = 3 - !Total number of physics-related variables: + ! Total number of physics-related variables: integer, public, parameter :: phys_var_num = 2 integer, public, parameter :: phys_const_num = 15 !Max length of physics-related variable standard names: integer, public, parameter :: std_name_len = 25 - !Max length of input (IC) file variable names: + ! Max length of input (IC) file variable names: integer, public, parameter :: ic_name_len = 5 ! Physics-related input variable standard names: diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_noreq.F90 b/test/unit/sample_files/write_init_files/phys_vars_init_check_noreq.F90 index b5f92ab5..9e656376 100644 --- a/test/unit/sample_files/write_init_files/phys_vars_init_check_noreq.F90 +++ b/test/unit/sample_files/write_init_files/phys_vars_init_check_noreq.F90 @@ -32,14 +32,14 @@ module phys_vars_init_check_noreq integer, public, parameter :: INITIALIZED = 1 integer, public, parameter :: PARAM = 2 integer, public, parameter :: READ_FROM_FILE = 3 - !Total number of physics-related variables: + ! Total number of physics-related variables: integer, public, parameter :: phys_var_num = 0 integer, public, parameter :: phys_const_num = 15 !Max length of physics-related variable standard names: integer, public, parameter :: std_name_len = 0 - !Max length of input (IC) file variable names: + ! Max length of input (IC) file variable names: integer, public, parameter :: ic_name_len = 0 ! Physics-related input variable standard names: diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_param.F90 b/test/unit/sample_files/write_init_files/phys_vars_init_check_param.F90 index b3a471b9..0516bff5 100644 --- a/test/unit/sample_files/write_init_files/phys_vars_init_check_param.F90 +++ b/test/unit/sample_files/write_init_files/phys_vars_init_check_param.F90 @@ -32,14 +32,14 @@ module phys_vars_init_check_param integer, public, parameter :: INITIALIZED = 1 integer, public, parameter :: PARAM = 2 integer, public, parameter :: READ_FROM_FILE = 3 - !Total number of physics-related variables: + ! Total number of physics-related variables: integer, public, parameter :: phys_var_num = 3 integer, public, parameter :: phys_const_num = 15 !Max length of physics-related variable standard names: integer, public, parameter :: std_name_len = 26 - !Max length of input (IC) file variable names: + ! Max length of input (IC) file variable names: integer, public, parameter :: ic_name_len = 5 ! Physics-related input variable standard names: diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_protect.F90 b/test/unit/sample_files/write_init_files/phys_vars_init_check_protect.F90 index 35ab2551..5cbf54e3 100644 --- a/test/unit/sample_files/write_init_files/phys_vars_init_check_protect.F90 +++ b/test/unit/sample_files/write_init_files/phys_vars_init_check_protect.F90 @@ -32,14 +32,14 @@ module phys_vars_init_check_protect integer, public, parameter :: INITIALIZED = 1 integer, public, parameter :: PARAM = 2 integer, public, parameter :: READ_FROM_FILE = 3 - !Total number of physics-related variables: + ! Total number of physics-related variables: integer, public, parameter :: phys_var_num = 2 integer, public, parameter :: phys_const_num = 15 !Max length of physics-related variable standard names: integer, public, parameter :: std_name_len = 25 - !Max length of input (IC) file variable names: + ! Max length of input (IC) file variable names: integer, public, parameter :: ic_name_len = 5 ! Physics-related input variable standard names: diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_scalar.F90 b/test/unit/sample_files/write_init_files/phys_vars_init_check_scalar.F90 index e4a28525..b0ea0ae1 100644 --- a/test/unit/sample_files/write_init_files/phys_vars_init_check_scalar.F90 +++ b/test/unit/sample_files/write_init_files/phys_vars_init_check_scalar.F90 @@ -32,14 +32,14 @@ module phys_vars_init_check_scalar integer, public, parameter :: INITIALIZED = 1 integer, public, parameter :: PARAM = 2 integer, public, parameter :: READ_FROM_FILE = 3 - !Total number of physics-related variables: + ! Total number of physics-related variables: integer, public, parameter :: phys_var_num = 2 integer, public, parameter :: phys_const_num = 15 !Max length of physics-related variable standard names: integer, public, parameter :: std_name_len = 25 - !Max length of input (IC) file variable names: + ! Max length of input (IC) file variable names: integer, public, parameter :: ic_name_len = 5 ! Physics-related input variable standard names: diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_simple.F90 b/test/unit/sample_files/write_init_files/phys_vars_init_check_simple.F90 index a144fc5e..5f471607 100644 --- a/test/unit/sample_files/write_init_files/phys_vars_init_check_simple.F90 +++ b/test/unit/sample_files/write_init_files/phys_vars_init_check_simple.F90 @@ -32,14 +32,14 @@ module phys_vars_init_check_simple integer, public, parameter :: INITIALIZED = 1 integer, public, parameter :: PARAM = 2 integer, public, parameter :: READ_FROM_FILE = 3 - !Total number of physics-related variables: + ! Total number of physics-related variables: integer, public, parameter :: phys_var_num = 2 integer, public, parameter :: phys_const_num = 15 !Max length of physics-related variable standard names: integer, public, parameter :: std_name_len = 25 - !Max length of input (IC) file variable names: + ! Max length of input (IC) file variable names: integer, public, parameter :: ic_name_len = 5 ! Physics-related input variable standard names: diff --git a/test/unit/sample_files/write_init_files/physics_inputs_4D.F90 b/test/unit/sample_files/write_init_files/physics_inputs_4D.F90 index e9d1b72f..485178a6 100644 --- a/test/unit/sample_files/write_init_files/physics_inputs_4D.F90 +++ b/test/unit/sample_files/write_init_files/physics_inputs_4D.F90 @@ -36,7 +36,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia use physics_data, only: read_field, find_input_name_idx, no_exist_idx, init_mark_idx, prot_no_init_idx, const_idx use cam_ccpp_cap, only: ccpp_physics_suite_variables, cam_constituents_array, cam_model_const_properties use ccpp_kinds, only: kind_phys - use phys_vars_init_check_4D, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_4D, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use physics_types_4D, only: slp, theta @@ -58,8 +58,10 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Constituent table index + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=2) :: sep !String separator used to print err messages @@ -135,8 +137,23 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia var_found = .false. field_data_ptr => cam_constituents_array() - call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & - field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call read_field(file, ccpp_required_data(req_idx), input_var_names(:,const_input_idx), 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + else + ! If not in standard names list, then just use constituent name as input file name: + call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + end if if(.not. var_found) then const_props => cam_model_const_properties() constituent_has_default = .false. @@ -209,7 +226,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, use phys_vars_init_check, only: is_read_from_file use ioFileMod, only: cam_get_file use cam_pio_utils, only: cam_pio_openfile, cam_pio_closefile - use phys_vars_init_check_4D, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_4D, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use physics_types_4D, only: slp, theta ! Dummy arguments @@ -231,8 +248,10 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Index of variable in constituent array + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=SHR_KIND_CL) :: ncdata_check_loc @@ -281,8 +300,23 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, if (constituent_idx > -1) then ! The required variable is a constituent. Call check variable routine on the relevant index of the constituent array field_data_ptr => cam_advected_constituents_array() - call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & - ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call check_field(file, input_var_names(:,const_input_idx), 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + else + ! If not in standard names list, then just use constituent name as input file name: + call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + end if else ! The required variable is not a constituent. Check if the variable was read from a file ! Find IC file input name array index for required variable: diff --git a/test/unit/sample_files/write_init_files/physics_inputs_bvd.F90 b/test/unit/sample_files/write_init_files/physics_inputs_bvd.F90 index cea57a66..2ba6d993 100644 --- a/test/unit/sample_files/write_init_files/physics_inputs_bvd.F90 +++ b/test/unit/sample_files/write_init_files/physics_inputs_bvd.F90 @@ -36,7 +36,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia use physics_data, only: read_field, find_input_name_idx, no_exist_idx, init_mark_idx, prot_no_init_idx, const_idx use cam_ccpp_cap, only: ccpp_physics_suite_variables, cam_constituents_array, cam_model_const_properties use ccpp_kinds, only: kind_phys - use phys_vars_init_check_bvd, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_bvd, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use physics_types_bad_vertdim, only: slp, theta @@ -58,8 +58,10 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Constituent table index + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=2) :: sep !String separator used to print err messages @@ -135,8 +137,23 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia var_found = .false. field_data_ptr => cam_constituents_array() - call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & - field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call read_field(file, ccpp_required_data(req_idx), input_var_names(:,const_input_idx), 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + else + ! If not in standard names list, then just use constituent name as input file name: + call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + end if if(.not. var_found) then const_props => cam_model_const_properties() constituent_has_default = .false. @@ -209,7 +226,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, use phys_vars_init_check, only: is_read_from_file use ioFileMod, only: cam_get_file use cam_pio_utils, only: cam_pio_openfile, cam_pio_closefile - use phys_vars_init_check_bvd, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_bvd, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use physics_types_bad_vertdim, only: slp, theta ! Dummy arguments @@ -231,8 +248,10 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Index of variable in constituent array + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=SHR_KIND_CL) :: ncdata_check_loc @@ -281,8 +300,23 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, if (constituent_idx > -1) then ! The required variable is a constituent. Call check variable routine on the relevant index of the constituent array field_data_ptr => cam_advected_constituents_array() - call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & - ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call check_field(file, input_var_names(:,const_input_idx), 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + else + ! If not in standard names list, then just use constituent name as input file name: + call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + end if else ! The required variable is not a constituent. Check if the variable was read from a file ! Find IC file input name array index for required variable: diff --git a/test/unit/sample_files/write_init_files/physics_inputs_cnst.F90 b/test/unit/sample_files/write_init_files/physics_inputs_cnst.F90 new file mode 100644 index 00000000..5470f528 --- /dev/null +++ b/test/unit/sample_files/write_init_files/physics_inputs_cnst.F90 @@ -0,0 +1,364 @@ +! +! This work (Common Community Physics Package Framework), identified by +! NOAA, NCAR, CU/CIRES, is free of known copyright restrictions and is +! placed in the public domain. +! +! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +! FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +! THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +! IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +! CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +!> +!! @brief Auto-generated Initial conditions source file, physics_inputs_cnst.F90 +!! +! +module physics_inputs_cnst + + + implicit none + private + + +!! public interfaces + public :: physics_read_data + public :: physics_check_data + +CONTAINS + + subroutine physics_read_data(file, suite_names, timestep, read_initialized_variables) + use pio, only: file_desc_t + use cam_abortutils, only: endrun + use spmd_utils, only: masterproc + use shr_kind_mod, only: SHR_KIND_CS, SHR_KIND_CL, SHR_KIND_CX + use physics_data, only: read_field, find_input_name_idx, no_exist_idx, init_mark_idx, prot_no_init_idx, const_idx + use cam_ccpp_cap, only: ccpp_physics_suite_variables, cam_constituents_array, cam_model_const_properties + use ccpp_kinds, only: kind_phys + use phys_vars_init_check_cnst, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len + use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t + use cam_logfile, only: iulog + use physics_types_simple, only: slp, theta + + ! Dummy arguments + type(file_desc_t), intent(inout) :: file + character(len=SHR_KIND_CS), intent(in) :: suite_names(:) !Names of CCPP suites + integer, intent(in) :: timestep + logical, optional, intent(in) :: read_initialized_variables + + ! Local variables: + + ! Character array containing all CCPP-required variable standard names: + character(len=std_name_len), allocatable :: ccpp_required_data(:) + + ! Strings which store names of any missing or non-initialized vars: + character(len=SHR_KIND_CL) :: missing_required_vars + character(len=SHR_KIND_CL) :: protected_non_init_vars + + character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message + integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable + integer :: name_idx !Input variable array index + integer :: constituent_idx !Constituent table index + integer :: const_input_idx !input_var_names index for a consituent + integer :: req_idx !Required variable array index + integer :: suite_idx !Suite array index + character(len=2) :: sep !String separator used to print err messages + character(len=2) :: sep2 !String separator used to print err messages + character(len=2) :: sep3 !String separator used to print err messages + real(kind=kind_phys), pointer :: field_data_ptr(:,:,:) + logical :: var_found !Bool to determine if consituent found in data files + + ! Fields needed for getting default data value for constituents + type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) + real(kind=kind_phys) :: constituent_default_value + integer :: constituent_errflg + character(len=512) :: constituent_errmsg + logical :: constituent_has_default + + ! Logical to default optional argument to False: + logical :: use_init_variables + + ! Initalize missing and non-initialized variables strings: + missing_required_vars = ' ' + protected_non_init_vars = ' ' + sep = '' + sep2 = '' + sep3 = '' + + ! Initialize use_init_variables based on whether it was input to function: + if (present(read_initialized_variables)) then + use_init_variables = read_initialized_variables + else + use_init_variables = .false. + end if + + ! Loop over CCPP physics/chemistry suites: + do suite_idx = 1, size(suite_names, 1) + + ! Search for all needed CCPP input variables, so that they can be read from input file if need be: + call ccpp_physics_suite_variables(suite_names(suite_idx), ccpp_required_data, errmsg, errflg, input_vars=.true., output_vars=.false.) + + ! Loop over all required variables and read from file if uninitialized: + do req_idx = 1, size(ccpp_required_data, 1) + + ! Find IC file input name array index for required variable: + name_idx = find_input_name_idx(ccpp_required_data(req_idx), use_init_variables, constituent_idx) + + ! Check for special index values: + select case (name_idx) + + case (init_mark_idx) + + ! If variable is already initialized, then do nothing. + + case (no_exist_idx) + + ! If an index was never found, then save variable name and check the rest of the variables, after which the model simulation will + ! end: + missing_required_vars(len_trim(missing_required_vars)+1:) = trim(sep)//trim(ccpp_required_data(req_idx)) + + ! Update character separator to now include comma: + sep = ', ' + + case (prot_no_init_idx) + + ! If an index was found for a protected variable, but that variable was never marked as initialized, then save the variable name + ! and check the rest of the variables, after which the model simulation will end: + protected_non_init_vars(len_trim(protected_non_init_vars)+1:) = trim(sep2)//trim(ccpp_required_data(req_idx)) + + ! Update character separator to now include comma: + sep2 = ', ' + + case (const_idx) + + ! If an index was found in the constituent hash table, then read in the data to that index of the constituent array + + var_found = .false. + field_data_ptr => cam_constituents_array() + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call read_field(file, ccpp_required_data(req_idx), input_var_names(:,const_input_idx), 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + else + ! If not in standard names list, then just use constituent name as input file name: + call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + end if + if(.not. var_found) then + const_props => cam_model_const_properties() + constituent_has_default = .false. + call const_props(constituent_idx)%has_default(constituent_has_default, constituent_errflg, constituent_errmsg) + if (constituent_errflg /= 0) then + call endrun(constituent_errmsg, file=__FILE__, line=__LINE__) + end if + if (constituent_has_default) then + call const_props(constituent_idx)%default_value(constituent_default_value, constituent_errflg, constituent_errmsg) + if (constituent_errflg /= 0) then + call endrun(constituent_errmsg, file=__FILE__, line=__LINE__) + end if + field_data_ptr(:,:,constituent_idx) = constituent_default_value + if (masterproc) then + write(iulog,*) 'Consitituent ', ccpp_required_data(req_idx), ' initialized to default value: ', constituent_default_value + end if + else + field_data_ptr(:,:,constituent_idx) = 0._kind_phys + if (masterproc) then + write(iulog,*) 'Constituent ', ccpp_required_data(req_idx), ' default value not configured. Setting to 0.' + end if + end if + end if + + case default + + ! Read variable from IC file: + + select case (trim(phys_var_stdnames(name_idx))) + case ('potential_temperature') + call read_field(file, 'potential_temperature', input_var_names(:,name_idx), 'lev', timestep, theta) + + case ('air_pressure_at_sea_level') + call read_field(file, 'air_pressure_at_sea_level', input_var_names(:,name_idx), timestep, slp) + + end select !read variables + end select !special indices + + end do !Suite-required variables + + ! End simulation if there are missing input variables that are required: + if (len_trim(missing_required_vars) > 0) then + call endrun("Required variables missing from registered list of input variables: "//& + trim(missing_required_vars)) + end if + + ! End simulation if there are protected input variables that are not initialized: + if (len_trim(protected_non_init_vars) > 0) then + call endrun("Required, protected input variables are not initialized: "//& + trim(protected_non_init_vars)) + end if + + ! Deallocate required variables array for use in next suite: + deallocate(ccpp_required_data) + + end do !CCPP suites + + end subroutine physics_read_data + + subroutine physics_check_data(file_name, suite_names, timestep, min_difference, min_relative_value) + use pio, only: file_desc_t, pio_nowrite + use cam_abortutils, only: endrun + use shr_kind_mod, only: SHR_KIND_CS, SHR_KIND_CL, SHR_KIND_CX + use physics_data, only: check_field, find_input_name_idx, no_exist_idx, init_mark_idx, prot_no_init_idx, const_idx + use cam_ccpp_cap, only: ccpp_physics_suite_variables, cam_advected_constituents_array + use cam_constituents, only: const_get_index + use ccpp_kinds, only: kind_phys + use cam_logfile, only: iulog + use spmd_utils, only: masterproc + use phys_vars_init_check, only: is_read_from_file + use ioFileMod, only: cam_get_file + use cam_pio_utils, only: cam_pio_openfile, cam_pio_closefile + use phys_vars_init_check_cnst, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len + use physics_types_simple, only: slp, theta + + ! Dummy arguments + character(len=SHR_KIND_CL), intent(in) :: file_name + character(len=SHR_KIND_CS), intent(in) :: suite_names(:) !Names of CCPP suites + integer, intent(in) :: timestep + real(kind_phys), intent(in) :: min_difference + real(kind_phys), intent(in) :: min_relative_value + + ! Local variables: + + ! Character array containing all CCPP-required variable standard names: + character(len=std_name_len), allocatable :: ccpp_required_data(:) + + ! Strings which store names of any missing or non-initialized vars: + character(len=SHR_KIND_CL) :: missing_required_vars + character(len=SHR_KIND_CL) :: protected_non_init_vars + character(len=SHR_KIND_CL) :: missing_input_names + + character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message + integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable + integer :: name_idx !Input variable array index + integer :: constituent_idx !Index of variable in constituent array + integer :: const_input_idx !input_var_names index for a consituent + integer :: req_idx !Required variable array index + integer :: suite_idx !Suite array index + character(len=SHR_KIND_CL) :: ncdata_check_loc + type(file_desc_t), pointer :: file + logical :: file_found + logical :: is_first + logical :: is_read + real(kind=kind_phys), pointer :: field_data_ptr(:,:,:) + + ! Initalize missing and non-initialized variables strings: + missing_required_vars = ' ' + protected_non_init_vars = ' ' + missing_input_names = ' ' + nullify(file) + is_first = .true. + + if (masterproc) then + write(iulog,*) '' + write(iulog,*) '********** Physics Check Data Results **********' + write(iulog,*) '' + write(iulog,*) 'TIMESTEP: ', timestep + end if + if (file_name == 'UNSET') then + write(iulog,*) 'WARNING: Namelist variable ncdata_check is UNSET.', ' Model will run, but physics check data will not be printed' + return + end if + ! Open check file: + call cam_get_file(file_name, ncdata_check_loc, allow_fail=.true., lexist=file_found, log_info=.false.) + if (.not. file_found) then + write(iulog,*) 'WARNING: Check file ', trim(file_name), ' not found. Model will run, but physics check data will not be printed' + return + end if + allocate(file) + call cam_pio_openfile(file, ncdata_check_loc, pio_nowrite, log_info=.false.) + ! Loop over CCPP physics/chemistry suites: + do suite_idx = 1, size(suite_names, 1) + + ! Search for all needed CCPP input variables, so that they can be read from input file if need be: + call ccpp_physics_suite_variables(suite_names(suite_idx), ccpp_required_data, errmsg, errflg, input_vars=.true., output_vars=.false.) + + ! Loop over all required variables as specified by CCPP suite: + do req_idx = 1, size(ccpp_required_data, 1) + + ! First check if the required variable is a constituent: + call const_get_index(ccpp_required_data(req_idx), constituent_idx, abort=.false., warning=.false.) + if (constituent_idx > -1) then + ! The required variable is a constituent. Call check variable routine on the relevant index of the constituent array + field_data_ptr => cam_advected_constituents_array() + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call check_field(file, input_var_names(:,const_input_idx), 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + else + ! If not in standard names list, then just use constituent name as input file name: + call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + end if + else + ! The required variable is not a constituent. Check if the variable was read from a file + ! Find IC file input name array index for required variable: + call is_read_from_file(ccpp_required_data(req_idx), is_read, stdnam_idx_out=name_idx) + if (.not. is_read) then + cycle + end if + ! Check variable vs input check file: + + select case (trim(phys_var_stdnames(name_idx))) + case ('potential_temperature') + call check_field(file, input_var_names(:,name_idx), 'lev', timestep, theta, 'potential_temperature', min_difference, & + min_relative_value, is_first) + + case ('air_pressure_at_sea_level') + call check_field(file, input_var_names(:,name_idx), timestep, slp, 'air_pressure_at_sea_level', min_difference, min_relative_value, & + is_first) + + end select !check variables + end if !check if constituent + end do !Suite-required variables + + ! Deallocate required variables array for use in next suite: + deallocate(ccpp_required_data) + + end do !CCPP suites + + ! Close check file: + call cam_pio_closefile(file) + deallocate(file) + nullify(file) + if (is_first) then + if (masterproc) then + write(iulog,*) '' + write(iulog,*) 'No differences found!' + end if + end if + if (masterproc) then + write(iulog,*) '' + write(iulog,*) '********** End Physics Check Data Results **********' + write(iulog,*) '' + end if + end subroutine physics_check_data + +end module physics_inputs_cnst diff --git a/test/unit/sample_files/write_init_files/physics_inputs_ddt.F90 b/test/unit/sample_files/write_init_files/physics_inputs_ddt.F90 index ec482da2..e88b21d0 100644 --- a/test/unit/sample_files/write_init_files/physics_inputs_ddt.F90 +++ b/test/unit/sample_files/write_init_files/physics_inputs_ddt.F90 @@ -36,7 +36,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia use physics_data, only: read_field, find_input_name_idx, no_exist_idx, init_mark_idx, prot_no_init_idx, const_idx use cam_ccpp_cap, only: ccpp_physics_suite_variables, cam_constituents_array, cam_model_const_properties use ccpp_kinds, only: kind_phys - use phys_vars_init_check_ddt, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_ddt, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use physics_types_ddt, only: phys_state, slp @@ -58,8 +58,10 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Constituent table index + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=2) :: sep !String separator used to print err messages @@ -135,8 +137,23 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia var_found = .false. field_data_ptr => cam_constituents_array() - call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & - field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call read_field(file, ccpp_required_data(req_idx), input_var_names(:,const_input_idx), 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + else + ! If not in standard names list, then just use constituent name as input file name: + call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + end if if(.not. var_found) then const_props => cam_model_const_properties() constituent_has_default = .false. @@ -209,7 +226,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, use phys_vars_init_check, only: is_read_from_file use ioFileMod, only: cam_get_file use cam_pio_utils, only: cam_pio_openfile, cam_pio_closefile - use phys_vars_init_check_ddt, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_ddt, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use physics_types_ddt, only: phys_state, slp ! Dummy arguments @@ -231,8 +248,10 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Index of variable in constituent array + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=SHR_KIND_CL) :: ncdata_check_loc @@ -281,8 +300,23 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, if (constituent_idx > -1) then ! The required variable is a constituent. Call check variable routine on the relevant index of the constituent array field_data_ptr => cam_advected_constituents_array() - call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & - ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call check_field(file, input_var_names(:,const_input_idx), 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + else + ! If not in standard names list, then just use constituent name as input file name: + call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + end if else ! The required variable is not a constituent. Check if the variable was read from a file ! Find IC file input name array index for required variable: diff --git a/test/unit/sample_files/write_init_files/physics_inputs_ddt2.F90 b/test/unit/sample_files/write_init_files/physics_inputs_ddt2.F90 index d42bf2d0..efda3f1a 100644 --- a/test/unit/sample_files/write_init_files/physics_inputs_ddt2.F90 +++ b/test/unit/sample_files/write_init_files/physics_inputs_ddt2.F90 @@ -36,7 +36,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia use physics_data, only: read_field, find_input_name_idx, no_exist_idx, init_mark_idx, prot_no_init_idx, const_idx use cam_ccpp_cap, only: ccpp_physics_suite_variables, cam_constituents_array, cam_model_const_properties use ccpp_kinds, only: kind_phys - use phys_vars_init_check_ddt2, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_ddt2, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use physics_types_ddt2, only: phys_state @@ -58,8 +58,10 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Constituent table index + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=2) :: sep !String separator used to print err messages @@ -135,8 +137,23 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia var_found = .false. field_data_ptr => cam_constituents_array() - call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & - field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call read_field(file, ccpp_required_data(req_idx), input_var_names(:,const_input_idx), 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + else + ! If not in standard names list, then just use constituent name as input file name: + call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + end if if(.not. var_found) then const_props => cam_model_const_properties() constituent_has_default = .false. @@ -209,7 +226,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, use phys_vars_init_check, only: is_read_from_file use ioFileMod, only: cam_get_file use cam_pio_utils, only: cam_pio_openfile, cam_pio_closefile - use phys_vars_init_check_ddt2, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_ddt2, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use physics_types_ddt2, only: phys_state ! Dummy arguments @@ -231,8 +248,10 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Index of variable in constituent array + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=SHR_KIND_CL) :: ncdata_check_loc @@ -281,8 +300,23 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, if (constituent_idx > -1) then ! The required variable is a constituent. Call check variable routine on the relevant index of the constituent array field_data_ptr => cam_advected_constituents_array() - call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & - ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call check_field(file, input_var_names(:,const_input_idx), 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + else + ! If not in standard names list, then just use constituent name as input file name: + call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + end if else ! The required variable is not a constituent. Check if the variable was read from a file ! Find IC file input name array index for required variable: diff --git a/test/unit/sample_files/write_init_files/physics_inputs_ddt_array.F90 b/test/unit/sample_files/write_init_files/physics_inputs_ddt_array.F90 index 603bf85a..f4e2e12f 100644 --- a/test/unit/sample_files/write_init_files/physics_inputs_ddt_array.F90 +++ b/test/unit/sample_files/write_init_files/physics_inputs_ddt_array.F90 @@ -36,7 +36,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia use physics_data, only: read_field, find_input_name_idx, no_exist_idx, init_mark_idx, prot_no_init_idx, const_idx use cam_ccpp_cap, only: ccpp_physics_suite_variables, cam_constituents_array, cam_model_const_properties use ccpp_kinds, only: kind_phys - use phys_vars_init_check_ddt_array, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_ddt_array, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use physics_types_ddt_array, only: ix_theta, phys_state @@ -58,8 +58,10 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Constituent table index + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=2) :: sep !String separator used to print err messages @@ -135,8 +137,23 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia var_found = .false. field_data_ptr => cam_constituents_array() - call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & - field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call read_field(file, ccpp_required_data(req_idx), input_var_names(:,const_input_idx), 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + else + ! If not in standard names list, then just use constituent name as input file name: + call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + end if if(.not. var_found) then const_props => cam_model_const_properties() constituent_has_default = .false. @@ -209,7 +226,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, use phys_vars_init_check, only: is_read_from_file use ioFileMod, only: cam_get_file use cam_pio_utils, only: cam_pio_openfile, cam_pio_closefile - use phys_vars_init_check_ddt_array, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_ddt_array, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use physics_types_ddt_array, only: ix_theta, phys_state ! Dummy arguments @@ -231,8 +248,10 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Index of variable in constituent array + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=SHR_KIND_CL) :: ncdata_check_loc @@ -281,8 +300,23 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, if (constituent_idx > -1) then ! The required variable is a constituent. Call check variable routine on the relevant index of the constituent array field_data_ptr => cam_advected_constituents_array() - call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & - ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call check_field(file, input_var_names(:,const_input_idx), 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + else + ! If not in standard names list, then just use constituent name as input file name: + call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + end if else ! The required variable is not a constituent. Check if the variable was read from a file ! Find IC file input name array index for required variable: diff --git a/test/unit/sample_files/write_init_files/physics_inputs_host_var.F90 b/test/unit/sample_files/write_init_files/physics_inputs_host_var.F90 index a84e1ca4..e268638e 100644 --- a/test/unit/sample_files/write_init_files/physics_inputs_host_var.F90 +++ b/test/unit/sample_files/write_init_files/physics_inputs_host_var.F90 @@ -36,7 +36,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia use physics_data, only: read_field, find_input_name_idx, no_exist_idx, init_mark_idx, prot_no_init_idx, const_idx use cam_ccpp_cap, only: ccpp_physics_suite_variables, cam_constituents_array, cam_model_const_properties use ccpp_kinds, only: kind_phys - use phys_vars_init_check_host_var, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_host_var, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use physics_types_host_var, only: slp @@ -58,8 +58,10 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Constituent table index + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=2) :: sep !String separator used to print err messages @@ -135,8 +137,23 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia var_found = .false. field_data_ptr => cam_constituents_array() - call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & - field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call read_field(file, ccpp_required_data(req_idx), input_var_names(:,const_input_idx), 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + else + ! If not in standard names list, then just use constituent name as input file name: + call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + end if if(.not. var_found) then const_props => cam_model_const_properties() constituent_has_default = .false. @@ -206,7 +223,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, use phys_vars_init_check, only: is_read_from_file use ioFileMod, only: cam_get_file use cam_pio_utils, only: cam_pio_openfile, cam_pio_closefile - use phys_vars_init_check_host_var, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_host_var, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use physics_types_host_var, only: slp ! Dummy arguments @@ -228,8 +245,10 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Index of variable in constituent array + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=SHR_KIND_CL) :: ncdata_check_loc @@ -278,8 +297,23 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, if (constituent_idx > -1) then ! The required variable is a constituent. Call check variable routine on the relevant index of the constituent array field_data_ptr => cam_advected_constituents_array() - call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & - ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call check_field(file, input_var_names(:,const_input_idx), 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + else + ! If not in standard names list, then just use constituent name as input file name: + call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + end if else ! The required variable is not a constituent. Check if the variable was read from a file ! Find IC file input name array index for required variable: diff --git a/test/unit/sample_files/write_init_files/physics_inputs_mf.F90 b/test/unit/sample_files/write_init_files/physics_inputs_mf.F90 index 9bfe067d..cfcc2d4a 100644 --- a/test/unit/sample_files/write_init_files/physics_inputs_mf.F90 +++ b/test/unit/sample_files/write_init_files/physics_inputs_mf.F90 @@ -36,7 +36,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia use physics_data, only: read_field, find_input_name_idx, no_exist_idx, init_mark_idx, prot_no_init_idx, const_idx use cam_ccpp_cap, only: ccpp_physics_suite_variables, cam_constituents_array, cam_model_const_properties use ccpp_kinds, only: kind_phys - use phys_vars_init_check_mf, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_mf, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use ref_theta, only: theta @@ -59,8 +59,10 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Constituent table index + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=2) :: sep !String separator used to print err messages @@ -136,8 +138,23 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia var_found = .false. field_data_ptr => cam_constituents_array() - call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & - field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call read_field(file, ccpp_required_data(req_idx), input_var_names(:,const_input_idx), 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + else + ! If not in standard names list, then just use constituent name as input file name: + call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + end if if(.not. var_found) then const_props => cam_model_const_properties() constituent_has_default = .false. @@ -210,7 +227,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, use phys_vars_init_check, only: is_read_from_file use ioFileMod, only: cam_get_file use cam_pio_utils, only: cam_pio_openfile, cam_pio_closefile - use phys_vars_init_check_mf, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_mf, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use ref_theta, only: theta use physics_types_mf, only: slp @@ -233,8 +250,10 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Index of variable in constituent array + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=SHR_KIND_CL) :: ncdata_check_loc @@ -283,8 +302,23 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, if (constituent_idx > -1) then ! The required variable is a constituent. Call check variable routine on the relevant index of the constituent array field_data_ptr => cam_advected_constituents_array() - call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & - ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call check_field(file, input_var_names(:,const_input_idx), 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + else + ! If not in standard names list, then just use constituent name as input file name: + call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + end if else ! The required variable is not a constituent. Check if the variable was read from a file ! Find IC file input name array index for required variable: diff --git a/test/unit/sample_files/write_init_files/physics_inputs_no_horiz.F90 b/test/unit/sample_files/write_init_files/physics_inputs_no_horiz.F90 index 2af65351..268b9988 100644 --- a/test/unit/sample_files/write_init_files/physics_inputs_no_horiz.F90 +++ b/test/unit/sample_files/write_init_files/physics_inputs_no_horiz.F90 @@ -36,7 +36,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia use physics_data, only: read_field, find_input_name_idx, no_exist_idx, init_mark_idx, prot_no_init_idx, const_idx use cam_ccpp_cap, only: ccpp_physics_suite_variables, cam_constituents_array, cam_model_const_properties use ccpp_kinds, only: kind_phys - use phys_vars_init_check_no_horiz, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_no_horiz, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use physics_types_no_horiz, only: slp, theta @@ -58,8 +58,10 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Constituent table index + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=2) :: sep !String separator used to print err messages @@ -135,8 +137,23 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia var_found = .false. field_data_ptr => cam_constituents_array() - call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & - field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call read_field(file, ccpp_required_data(req_idx), input_var_names(:,const_input_idx), 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + else + ! If not in standard names list, then just use constituent name as input file name: + call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + end if if(.not. var_found) then const_props => cam_model_const_properties() constituent_has_default = .false. @@ -209,7 +226,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, use phys_vars_init_check, only: is_read_from_file use ioFileMod, only: cam_get_file use cam_pio_utils, only: cam_pio_openfile, cam_pio_closefile - use phys_vars_init_check_no_horiz, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_no_horiz, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use physics_types_no_horiz, only: slp, theta ! Dummy arguments @@ -231,8 +248,10 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Index of variable in constituent array + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=SHR_KIND_CL) :: ncdata_check_loc @@ -281,8 +300,23 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, if (constituent_idx > -1) then ! The required variable is a constituent. Call check variable routine on the relevant index of the constituent array field_data_ptr => cam_advected_constituents_array() - call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & - ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call check_field(file, input_var_names(:,const_input_idx), 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + else + ! If not in standard names list, then just use constituent name as input file name: + call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + end if else ! The required variable is not a constituent. Check if the variable was read from a file ! Find IC file input name array index for required variable: diff --git a/test/unit/sample_files/write_init_files/physics_inputs_noreq.F90 b/test/unit/sample_files/write_init_files/physics_inputs_noreq.F90 index facc3791..a8c5d3de 100644 --- a/test/unit/sample_files/write_init_files/physics_inputs_noreq.F90 +++ b/test/unit/sample_files/write_init_files/physics_inputs_noreq.F90 @@ -36,7 +36,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia use physics_data, only: read_field, find_input_name_idx, no_exist_idx, init_mark_idx, prot_no_init_idx, const_idx use cam_ccpp_cap, only: ccpp_physics_suite_variables, cam_constituents_array, cam_model_const_properties use ccpp_kinds, only: kind_phys - use phys_vars_init_check_noreq, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_noreq, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog @@ -57,8 +57,10 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Constituent table index + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=2) :: sep !String separator used to print err messages @@ -134,8 +136,23 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia var_found = .false. field_data_ptr => cam_constituents_array() - call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & - field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call read_field(file, ccpp_required_data(req_idx), input_var_names(:,const_input_idx), 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + else + ! If not in standard names list, then just use constituent name as input file name: + call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + end if if(.not. var_found) then const_props => cam_model_const_properties() constituent_has_default = .false. @@ -202,7 +219,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, use phys_vars_init_check, only: is_read_from_file use ioFileMod, only: cam_get_file use cam_pio_utils, only: cam_pio_openfile, cam_pio_closefile - use phys_vars_init_check_noreq, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_noreq, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len ! Dummy arguments character(len=SHR_KIND_CL), intent(in) :: file_name @@ -223,8 +240,10 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Index of variable in constituent array + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=SHR_KIND_CL) :: ncdata_check_loc @@ -273,8 +292,23 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, if (constituent_idx > -1) then ! The required variable is a constituent. Call check variable routine on the relevant index of the constituent array field_data_ptr => cam_advected_constituents_array() - call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & - ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call check_field(file, input_var_names(:,const_input_idx), 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + else + ! If not in standard names list, then just use constituent name as input file name: + call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + end if else ! The required variable is not a constituent. Check if the variable was read from a file ! Find IC file input name array index for required variable: diff --git a/test/unit/sample_files/write_init_files/physics_inputs_param.F90 b/test/unit/sample_files/write_init_files/physics_inputs_param.F90 index 7e1c3165..a5652d9e 100644 --- a/test/unit/sample_files/write_init_files/physics_inputs_param.F90 +++ b/test/unit/sample_files/write_init_files/physics_inputs_param.F90 @@ -36,7 +36,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia use physics_data, only: read_field, find_input_name_idx, no_exist_idx, init_mark_idx, prot_no_init_idx, const_idx use cam_ccpp_cap, only: ccpp_physics_suite_variables, cam_constituents_array, cam_model_const_properties use ccpp_kinds, only: kind_phys - use phys_vars_init_check_param, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_param, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use physics_types_param, only: g, slp, theta @@ -58,8 +58,10 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Constituent table index + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=2) :: sep !String separator used to print err messages @@ -135,8 +137,23 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia var_found = .false. field_data_ptr => cam_constituents_array() - call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & - field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call read_field(file, ccpp_required_data(req_idx), input_var_names(:,const_input_idx), 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + else + ! If not in standard names list, then just use constituent name as input file name: + call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + end if if(.not. var_found) then const_props => cam_model_const_properties() constituent_has_default = .false. @@ -212,7 +229,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, use phys_vars_init_check, only: is_read_from_file use ioFileMod, only: cam_get_file use cam_pio_utils, only: cam_pio_openfile, cam_pio_closefile - use phys_vars_init_check_param, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_param, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use physics_types_param, only: g, slp, theta ! Dummy arguments @@ -234,8 +251,10 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Index of variable in constituent array + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=SHR_KIND_CL) :: ncdata_check_loc @@ -284,8 +303,23 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, if (constituent_idx > -1) then ! The required variable is a constituent. Call check variable routine on the relevant index of the constituent array field_data_ptr => cam_advected_constituents_array() - call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & - ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call check_field(file, input_var_names(:,const_input_idx), 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + else + ! If not in standard names list, then just use constituent name as input file name: + call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + end if else ! The required variable is not a constituent. Check if the variable was read from a file ! Find IC file input name array index for required variable: diff --git a/test/unit/sample_files/write_init_files/physics_inputs_protect.F90 b/test/unit/sample_files/write_init_files/physics_inputs_protect.F90 index c4936522..b4b15066 100644 --- a/test/unit/sample_files/write_init_files/physics_inputs_protect.F90 +++ b/test/unit/sample_files/write_init_files/physics_inputs_protect.F90 @@ -36,7 +36,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia use physics_data, only: read_field, find_input_name_idx, no_exist_idx, init_mark_idx, prot_no_init_idx, const_idx use cam_ccpp_cap, only: ccpp_physics_suite_variables, cam_constituents_array, cam_model_const_properties use ccpp_kinds, only: kind_phys - use phys_vars_init_check_protect, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_protect, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use physics_types_protected, only: slp, theta @@ -58,8 +58,10 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Constituent table index + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=2) :: sep !String separator used to print err messages @@ -135,8 +137,23 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia var_found = .false. field_data_ptr => cam_constituents_array() - call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & - field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call read_field(file, ccpp_required_data(req_idx), input_var_names(:,const_input_idx), 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + else + ! If not in standard names list, then just use constituent name as input file name: + call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + end if if(.not. var_found) then const_props => cam_model_const_properties() constituent_has_default = .false. @@ -209,7 +226,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, use phys_vars_init_check, only: is_read_from_file use ioFileMod, only: cam_get_file use cam_pio_utils, only: cam_pio_openfile, cam_pio_closefile - use phys_vars_init_check_protect, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_protect, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use physics_types_protected, only: slp, theta ! Dummy arguments @@ -231,8 +248,10 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Index of variable in constituent array + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=SHR_KIND_CL) :: ncdata_check_loc @@ -281,8 +300,23 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, if (constituent_idx > -1) then ! The required variable is a constituent. Call check variable routine on the relevant index of the constituent array field_data_ptr => cam_advected_constituents_array() - call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & - ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call check_field(file, input_var_names(:,const_input_idx), 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + else + ! If not in standard names list, then just use constituent name as input file name: + call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + end if else ! The required variable is not a constituent. Check if the variable was read from a file ! Find IC file input name array index for required variable: diff --git a/test/unit/sample_files/write_init_files/physics_inputs_scalar.F90 b/test/unit/sample_files/write_init_files/physics_inputs_scalar.F90 index 2772bb19..9ab6d635 100644 --- a/test/unit/sample_files/write_init_files/physics_inputs_scalar.F90 +++ b/test/unit/sample_files/write_init_files/physics_inputs_scalar.F90 @@ -36,7 +36,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia use physics_data, only: read_field, find_input_name_idx, no_exist_idx, init_mark_idx, prot_no_init_idx, const_idx use cam_ccpp_cap, only: ccpp_physics_suite_variables, cam_constituents_array, cam_model_const_properties use ccpp_kinds, only: kind_phys - use phys_vars_init_check_scalar, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_scalar, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use physics_types_scalar_var, only: slp, theta @@ -58,8 +58,10 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Constituent table index + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=2) :: sep !String separator used to print err messages @@ -135,8 +137,23 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia var_found = .false. field_data_ptr => cam_constituents_array() - call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & - field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call read_field(file, ccpp_required_data(req_idx), input_var_names(:,const_input_idx), 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + else + ! If not in standard names list, then just use constituent name as input file name: + call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + end if if(.not. var_found) then const_props => cam_model_const_properties() constituent_has_default = .false. @@ -209,7 +226,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, use phys_vars_init_check, only: is_read_from_file use ioFileMod, only: cam_get_file use cam_pio_utils, only: cam_pio_openfile, cam_pio_closefile - use phys_vars_init_check_scalar, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_scalar, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use physics_types_scalar_var, only: slp, theta ! Dummy arguments @@ -231,8 +248,10 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Index of variable in constituent array + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=SHR_KIND_CL) :: ncdata_check_loc @@ -281,8 +300,23 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, if (constituent_idx > -1) then ! The required variable is a constituent. Call check variable routine on the relevant index of the constituent array field_data_ptr => cam_advected_constituents_array() - call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & - ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call check_field(file, input_var_names(:,const_input_idx), 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + else + ! If not in standard names list, then just use constituent name as input file name: + call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + end if else ! The required variable is not a constituent. Check if the variable was read from a file ! Find IC file input name array index for required variable: diff --git a/test/unit/sample_files/write_init_files/physics_inputs_simple.F90 b/test/unit/sample_files/write_init_files/physics_inputs_simple.F90 index 0f6a82b6..7f81c115 100644 --- a/test/unit/sample_files/write_init_files/physics_inputs_simple.F90 +++ b/test/unit/sample_files/write_init_files/physics_inputs_simple.F90 @@ -36,7 +36,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia use physics_data, only: read_field, find_input_name_idx, no_exist_idx, init_mark_idx, prot_no_init_idx, const_idx use cam_ccpp_cap, only: ccpp_physics_suite_variables, cam_constituents_array, cam_model_const_properties use ccpp_kinds, only: kind_phys - use phys_vars_init_check_simple, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_simple, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use physics_types_simple, only: slp, theta @@ -58,8 +58,10 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Constituent table index + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=2) :: sep !String separator used to print err messages @@ -135,8 +137,23 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia var_found = .false. field_data_ptr => cam_constituents_array() - call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & - field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call read_field(file, ccpp_required_data(req_idx), input_var_names(:,const_input_idx), 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + else + ! If not in standard names list, then just use constituent name as input file name: + call read_field(file, ccpp_required_data(req_idx), [ccpp_required_data(req_idx)], 'lev', timestep, & + field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found) + end if if(.not. var_found) then const_props => cam_model_const_properties() constituent_has_default = .false. @@ -209,7 +226,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, use phys_vars_init_check, only: is_read_from_file use ioFileMod, only: cam_get_file use cam_pio_utils, only: cam_pio_openfile, cam_pio_closefile - use phys_vars_init_check_simple, only: phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_simple, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len use physics_types_simple, only: slp, theta ! Dummy arguments @@ -231,8 +248,10 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, character(len=SHR_KIND_CX) :: errmsg !CCPP framework error message integer :: errflg !CCPP framework error flag + integer :: n !Loop control variable integer :: name_idx !Input variable array index integer :: constituent_idx !Index of variable in constituent array + integer :: const_input_idx !input_var_names index for a consituent integer :: req_idx !Required variable array index integer :: suite_idx !Suite array index character(len=SHR_KIND_CL) :: ncdata_check_loc @@ -281,8 +300,23 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, if (constituent_idx > -1) then ! The required variable is a constituent. Call check variable routine on the relevant index of the constituent array field_data_ptr => cam_advected_constituents_array() - call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & - ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + + ! Check if constituent standard name in registered SIMA standard names list: + if(any(phys_var_stdnames == ccpp_required_data(req_idx))) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(ccpp_required_data(req_idx))) then + const_input_idx = n + exit + end if + end do + call check_field(file, input_var_names(:,const_input_idx), 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + else + ! If not in standard names list, then just use constituent name as input file name: + call check_field(file, [ccpp_required_data(req_idx)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), & + ccpp_required_data(req_idx), min_difference, min_relative_value, is_first) + end if else ! The required variable is not a constituent. Check if the variable was read from a file ! Find IC file input name array index for required variable: diff --git a/test/unit/sample_files/write_init_files/simple_build_cache_template.xml b/test/unit/sample_files/write_init_files/simple_build_cache_template.xml index c4920aae..e587e34c 100644 --- a/test/unit/sample_files/write_init_files/simple_build_cache_template.xml +++ b/test/unit/sample_files/write_init_files/simple_build_cache_template.xml @@ -1,12 +1,11 @@ TAG1 - + TAG2 - - + + none - diff --git a/test/unit/sample_files/write_init_files/simple_host.F90 b/test/unit/sample_files/write_init_files/simple_host.F90 index f15e376a..cb0f88a3 100644 --- a/test/unit/sample_files/write_init_files/simple_host.F90 +++ b/test/unit/sample_files/write_init_files/simple_host.F90 @@ -29,12 +29,16 @@ subroutine simple_sub() character(len=128), allocatable :: part_names(:) character(len=512) :: errmsg integer :: errflg + integer :: pcols integer :: col_start integer :: col_end integer :: ncols integer, protected :: pver real(kind_phys) :: dtime_phys + ! Declare a horizontal dimension: + pcols = 5 + ! Initialize our 'data' call init_temp() diff --git a/test/unit/sample_files/write_init_files/simple_host.meta b/test/unit/sample_files/write_init_files/simple_host.meta index 3794185e..faf7f884 100644 --- a/test/unit/sample_files/write_init_files/simple_host.meta +++ b/test/unit/sample_files/write_init_files/simple_host.meta @@ -4,6 +4,12 @@ [ccpp-arg-table] name = simple_sub type = host +[ pcols ] + standard_name = horizontal_dimension + type = integer + units = count + dimensions = () + protected = True [ col_start ] standard_name = horizontal_loop_begin type = integer diff --git a/test/unit/sample_files/write_init_files/simple_reg.xml b/test/unit/sample_files/write_init_files/simple_reg.xml index 653582dc..94c4ae28 100644 --- a/test/unit/sample_files/write_init_files/simple_reg.xml +++ b/test/unit/sample_files/write_init_files/simple_reg.xml @@ -18,5 +18,11 @@ horizontal_dimension eddy_len + + + The coolest constituent imaginable + COOL_CAT cnst_COOL_CAT + diff --git a/test/unit/sample_files/write_init_files/temp_adjust_cnst.F90 b/test/unit/sample_files/write_init_files/temp_adjust_cnst.F90 new file mode 100644 index 00000000..0f4b5d7f --- /dev/null +++ b/test/unit/sample_files/write_init_files/temp_adjust_cnst.F90 @@ -0,0 +1,87 @@ +!simple demonstration parameterization +! + +MODULE temp_adjust + + USE ccpp_kinds, ONLY: kind_phys + + IMPLICIT NONE + PRIVATE + + PUBLIC :: temp_adjust_init + PUBLIC :: temp_adjust_run + PUBLIC :: temp_adjust_finalize + +CONTAINS + +!> \section arg_table_temp_adjust_run Argument Table +!! \htmlinclude arg_table_temp_adjust_run.html +!! + SUBROUTINE temp_adjust_run(nbox, lev, temp_layer, & + slp, cool_cat, timestep, errmsg, errflg) +!---------------------------------------------------------------- + IMPLICIT NONE +!---------------------------------------------------------------- + + integer, intent(in) :: nbox, lev + REAL(kind_phys), intent(inout) :: temp_layer(:, :) + real(kind_phys), intent(in) :: slp(:) + real(kind_phys), intent(inout) :: cool_cat(:,:) + real(kind_phys), intent(in) :: timestep + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg +!---------------------------------------------------------------- + + integer :: box_index + integer :: lev_index + + errmsg = '' + errflg = 0 + + do box_index = 1, nbox + do lev_index = 1, lev + temp_layer(box_index, lev_index) = temp_layer(box_index, lev_index) & + + 1.0_kind_phys + + !Add a made-up term which uses slp: + temp_layer(box_index, lev_index) = temp_layer(box_index, lev_index) & + + 0._kind_phys*slp(box_index) + end do + end do + + !Why this cool cat is the bee's knees: + cool_cat(:,:) = 0._kind_phys + + END SUBROUTINE temp_adjust_run + +!> \section arg_table_temp_adjust_init Argument Table +!! \htmlinclude arg_table_temp_adjust_init.html +!! + subroutine temp_adjust_init (errmsg, errflg) + + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg + + ! This routine currently does nothing + + errmsg = '' + errflg = 0 + + end subroutine temp_adjust_init + +!> \section arg_table_temp_adjust_finalize Argument Table +!! \htmlinclude arg_table_temp_adjust_finalize.html +!! + subroutine temp_adjust_finalize (errmsg, errflg) + + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg + + ! This routine currently does nothing + + errmsg = '' + errflg = 0 + + end subroutine temp_adjust_finalize + +END MODULE temp_adjust diff --git a/test/unit/sample_files/write_init_files/temp_adjust_cnst.meta b/test/unit/sample_files/write_init_files/temp_adjust_cnst.meta new file mode 100644 index 00000000..941bc24c --- /dev/null +++ b/test/unit/sample_files/write_init_files/temp_adjust_cnst.meta @@ -0,0 +1,99 @@ +[ccpp-table-properties] + name = temp_adjust + type = scheme +[ccpp-arg-table] + name = temp_adjust_run + type = scheme +[ nbox ] + standard_name = horizontal_loop_extent + type = integer + units = count + dimensions = () + intent = in +[ lev ] + standard_name = vertical_layer_dimension + type = integer + units = count + dimensions = () + intent = in +[ temp_layer ] + standard_name = potential_temperature + units = K + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[ slp ] + standard_name = air_pressure_at_sea_level + units = Pa + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + intent = in +[ cool_cat ] + standard_name = super_cool_cat_const + units = kg kg-1 + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout + advected = True +[ timestep ] + standard_name = timestep_for_physics + long_name = time step + units = s + dimensions = () + type = real + kind = kind_phys + intent = in +[ errmsg ] + standard_name = ccpp_error_message + long_name = Error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=512 + intent = out +[ errflg ] + standard_name = ccpp_error_code + long_name = Error flag for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out +[ccpp-arg-table] + name = temp_adjust_init + type = scheme +[ errmsg ] + standard_name = ccpp_error_message + long_name = Error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=512 + intent = out +[ errflg ] + standard_name = ccpp_error_code + long_name = Error flag for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out +[ccpp-arg-table] + name = temp_adjust_finalize + type = scheme +[ errmsg ] + standard_name = ccpp_error_message + long_name = Error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=512 + intent = out +[ errflg ] + standard_name = ccpp_error_code + long_name = Error flag for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out diff --git a/test/unit/sample_files/write_init_files/var_bad_vertdim.xml b/test/unit/sample_files/write_init_files/var_bad_vertdim.xml index 4108f44c..80e7f97e 100644 --- a/test/unit/sample_files/write_init_files/var_bad_vertdim.xml +++ b/test/unit/sample_files/write_init_files/var_bad_vertdim.xml @@ -3,11 +3,6 @@ - - Number of horizontal columns - 0 - diff --git a/test/unit/test_build_cache.py b/test/unit/test_build_cache.py index 0b4cdc74..c3152367 100644 --- a/test/unit/test_build_cache.py +++ b/test/unit/test_build_cache.py @@ -108,7 +108,7 @@ def setUpClass(cls): remove_files(glob.iglob(os.path.join(_TMP_DIR, '*.*'))) #Set path to test registry file, which will be used in - #various tests below as a stand-in for all teeded files: + #various tests below as a stand-in for all needed files: test_reg_file = os.path.join(_WRITE_INIT_DIR, "param_reg.xml") #Copy test registry file to local "tmp" directory: @@ -427,7 +427,7 @@ def test_update_registry(self): #Update registry fields: test_cache.update_registry(tmp_test_reg, [tmp_test_reg], - dycore, None, [tmp_test_reg], ic_names) + dycore, [tmp_test_reg], ic_names) #Write updated fields to build cache file: test_cache.write() @@ -462,7 +462,7 @@ def test_registry_mismatch_good_match(self): test_cache = BuildCacheCAM(cache_file) #Run registry_mismatch function: - reg_match = test_cache.registry_mismatch(reg_file, [reg_file], "none", None) + reg_match = test_cache.registry_mismatch(reg_file, [reg_file], "none") #Check that function returns False: self.assertFalse(reg_match) @@ -492,7 +492,7 @@ def test_registry_mismatch_diff_dycore(self): new_dycore = "se" #Run registry_mismatch function: - reg_match = test_cache.registry_mismatch(reg_file, [reg_file], new_dycore, None) + reg_match = test_cache.registry_mismatch(reg_file, [reg_file], new_dycore) #Check that function returns True: self.assertTrue(reg_match) @@ -522,7 +522,7 @@ def test_registry_mismatch_diff_reg_file(self): test_cache = BuildCacheCAM(cache_file) #Run registry_mismatch function: - reg_match = test_cache.registry_mismatch(reg_file, [new_file], "none", None) + reg_match = test_cache.registry_mismatch(reg_file, [new_file], "none") #Check that function returns True: self.assertTrue(reg_match) @@ -553,35 +553,7 @@ def test_registry_mismatch_diff_gen_file(self): test_cache = BuildCacheCAM(cache_file) #Run registry_mismatch function: - reg_match = test_cache.registry_mismatch(new_file, [reg_file], "none", None) - - #Check that function returns True: - self.assertTrue(reg_match) - - #++++++++++++++++ - - def test_registry_mismatch_diff_config(self): - - """ - Check that the 'registry_mismatch' - function returns True when the there is - a change in the registry config options - being used. - """ - - #Set path to already-existing cache file used by test_write_init_files: - cache_file = os.path.join(_WRITE_INIT_DIR, "simple_build_cache_template.xml") - - #Set path to registry generator file listed in build_cache file. - #Please note that in this sample file the registry XML file is listed, - #and not a python file as would normally be the case: - reg_file = os.path.join(_WRITE_INIT_DIR, "simple_reg.xml") - - #Create new build cache object: - test_cache = BuildCacheCAM(cache_file) - - #Run registry_mismatch function: - reg_match = test_cache.registry_mismatch(reg_file, [reg_file], "none", "banana") + reg_match = test_cache.registry_mismatch(new_file, [reg_file], "none") #Check that function returns True: self.assertTrue(reg_match) diff --git a/test/unit/test_cam_autogen.py b/test/unit/test_cam_autogen.py index b5a59628..58f54daa 100644 --- a/test/unit/test_cam_autogen.py +++ b/test/unit/test_cam_autogen.py @@ -83,12 +83,12 @@ def __init__(self): pass def update_registry(self, gen_reg_file, registry_files, - dycore, reg_config): + dycore): """Fake version of 'update_regsitry' method""" def registry_mismatch(self, gen_reg_file, registry_files, - dycore, reg_config): + dycore): """ Fake version of 'registry_mismatch' method. diff --git a/test/unit/test_registry.py b/test/unit/test_registry.py index 00530bb1..98d0a232 100644 --- a/test/unit/test_registry.py +++ b/test/unit/test_registry.py @@ -94,7 +94,7 @@ def test_good_simple_registry(self): out_meta = os.path.join(_TMP_DIR, out_source_name + '.meta') remove_files([out_source, out_meta]) # Run test - retcode, files, _ = gen_registry(filename, 'fv', {}, _TMP_DIR, 2, + retcode, files, _ = gen_registry(filename, 'fv', _TMP_DIR, 2, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -136,7 +136,7 @@ def test_good_ddt_registry(self): out_meta = os.path.join(_TMP_DIR, out_meta_name) remove_files([out_source, out_meta]) # Run dycore - retcode, files, _ = gen_registry(filename, dycore, {}, _TMP_DIR, 2, + retcode, files, _ = gen_registry(filename, dycore, _TMP_DIR, 2, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -183,7 +183,7 @@ def test_good_ddt_registry2(self): out_meta = os.path.join(_TMP_DIR, out_meta_name) remove_files([out_source, out_meta]) # Run dycore - retcode, files, _ = gen_registry(filename, 'se', {}, _TMP_DIR, 2, + retcode, files, _ = gen_registry(filename, 'se', _TMP_DIR, 2, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -223,7 +223,7 @@ def test_good_array(self): out_meta = os.path.join(_TMP_DIR, out_meta_name) remove_files([out_source, out_meta]) # Run dycore - retcode, files, _ = gen_registry(filename, 'se', {}, _TMP_DIR, 2, + retcode, files, _ = gen_registry(filename, 'se', _TMP_DIR, 2, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -261,7 +261,7 @@ def test_good_metadata_file_registry(self): out_meta = os.path.join(_TMP_DIR, out_name + '.meta') remove_files([out_source, out_meta]) # generate registry - retcode, files, _ = gen_registry(filename, 'se', {}, _TMP_DIR, 2, + retcode, files, _ = gen_registry(filename, 'se', _TMP_DIR, 2, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -315,7 +315,7 @@ def test_diff_src_root_metadata_file_registry(self): shutil.copy(meta_file, tmp_src_dir) # Generate registry - retcode, files, _ = gen_registry(filename, 'se', {}, _TMP_DIR, 2, + retcode, files, _ = gen_registry(filename, 'se', _TMP_DIR, 2, _SRC_MOD_DIR, _TMP_DIR, loglevel=logging.ERROR, error_on_no_validate=True) @@ -372,7 +372,7 @@ def test_SourceMods_metadata_file_registry(self): shutil.copy(meta_file, source_mod_file) # Generate registry - retcode, files, _ = gen_registry(filename, 'se', {}, _TMP_DIR, 2, + retcode, files, _ = gen_registry(filename, 'se', _TMP_DIR, 2, tmp_src_dir, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -423,7 +423,7 @@ def test_good_complete_registry(self): remove_files([out_source, out_meta]) # Run test - retcode, files, _ = gen_registry(filename, 'se', {}, _TMP_DIR, 2, + retcode, files, _ = gen_registry(filename, 'se', _TMP_DIR, 2, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -484,7 +484,7 @@ def test_no_metadata_file_registry(self): # Run test with self.assertRaises(ValueError) as verr: - _ = gen_registry(filename, 'se', {}, _TMP_DIR, 2, + _ = gen_registry(filename, 'se', _TMP_DIR, 2, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -530,7 +530,7 @@ def test_parameter(self): # End for tree.write(filename) # Run test - retcode, files, _ = gen_registry(filename, 'eul', {}, _TMP_DIR, 2, + retcode, files, _ = gen_registry(filename, 'eul', _TMP_DIR, 2, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -576,7 +576,7 @@ def test_bad_registry_version(self): # Run test with self.assertRaises(ValueError) as verr: - _ = gen_registry(filename, 'fv', {}, _TMP_DIR, 2, + _ = gen_registry(filename, 'fv', _TMP_DIR, 2, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -620,7 +620,7 @@ def test_missing_standard_name(self): # Run test with self.assertRaises(ValueError) as verr: - _ = gen_registry(filename, 'fv', {}, _TMP_DIR, 2, + _ = gen_registry(filename, 'fv', _TMP_DIR, 2, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -664,7 +664,7 @@ def test_bad_dimensions(self): tree.write(filename) # Run test with self.assertRaises(ValueError) as verr: - _ = gen_registry(filename, 'eul', {}, _TMP_DIR, 2, + _ = gen_registry(filename, 'eul', _TMP_DIR, 2, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -710,7 +710,7 @@ def test_unknown_dimensions(self): # Run test with self.assertRaises(ValueError) as verr: - _ = gen_registry(filename, 'eul', {}, _TMP_DIR, 2, + _ = gen_registry(filename, 'eul', _TMP_DIR, 2, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -756,7 +756,7 @@ def test_no_init_value(self): tree.write(filename) # Run test with self.assertRaises(ValueError) as verr: - _ = gen_registry(filename, 'eul', {}, _TMP_DIR, 2, + _ = gen_registry(filename, 'eul', _TMP_DIR, 2, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -807,7 +807,7 @@ def test_duplicate_type(self): # Run test vmsg = 'Failed to flag a duplicate DDT type' with self.assertRaises(ValueError, msg=vmsg) as verr: - _ = gen_registry(filename, 'eul', {}, _TMP_DIR, 2, + _ = gen_registry(filename, 'eul', _TMP_DIR, 2, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -849,7 +849,7 @@ def test_ddt_with_kind(self): tree.write(filename) # Run test with self.assertRaises(ValueError) as verr: - _ = gen_registry(filename, 'eul', {}, _TMP_DIR, 2, + _ = gen_registry(filename, 'eul', _TMP_DIR, 2, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -891,7 +891,7 @@ def test_ddt_with_unknown_type(self): tree.write(filename) # Run test with self.assertRaises(ValueError) as verr: - _ = gen_registry(filename, 'eul', {}, _TMP_DIR, 2, + _ = gen_registry(filename, 'eul', _TMP_DIR, 2, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -934,7 +934,7 @@ def test_ddt_with_unknown_extends(self): tree.write(filename) # Run test with self.assertRaises(ValueError) as verr: - _ = gen_registry(filename, 'eul', {}, _TMP_DIR, 2, + _ = gen_registry(filename, 'eul', _TMP_DIR, 2, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -984,7 +984,7 @@ def test_ddt_with_incompatible_attr(self): tree.write(filename) # Run test with self.assertRaises(ValueError) as verr: - _ = gen_registry(filename, 'eul', {}, _TMP_DIR, 2, + _ = gen_registry(filename, 'eul', _TMP_DIR, 2, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -1029,7 +1029,7 @@ def test_ddt_with_unknown_variable(self): tree.write(filename) # Run test with self.assertRaises(ValueError) as verr: - _ = gen_registry(filename, 'eul', {}, _TMP_DIR, 2, + _ = gen_registry(filename, 'eul',_TMP_DIR, 2, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -1073,7 +1073,7 @@ def test_duplicate_local_name(self): tree.write(filename) # Run test with self.assertRaises(ValueError) as verr: - _ = gen_registry(filename, 'eul', {}, _TMP_DIR, 2, + _ = gen_registry(filename, 'eul', _TMP_DIR, 2, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -1119,7 +1119,7 @@ def test_duplicate_standard_name(self): # Run test with self.assertRaises(ValueError) as verr: - _ = gen_registry(filename, 'eul', {}, _TMP_DIR, 2, + _ = gen_registry(filename, 'eul', _TMP_DIR, 2, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -1167,7 +1167,7 @@ def test_missing_use_statement(self): tree.write(filename) # Run test with self.assertRaises(ValueError) as verr: - _ = gen_registry(filename, 'eul', {}, _TMP_DIR, 2, + _ = gen_registry(filename, 'eul', _TMP_DIR, 2, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -1191,8 +1191,7 @@ def test_bad_metadata_file_dup_section(self): # Run test with self.assertRaises(ValueError) as verr: - metadata_file_to_files(infilename, TypeRegistry(), 'eul', {}, - run_env) + metadata_file_to_files(infilename, TypeRegistry(), 'eul', run_env) # Check exception message emsg = "module, 'physics_types_simple', table already contains " emsg += f"'physics_types_simple', at {infilename}:36" @@ -1211,8 +1210,7 @@ def test_bad_metadata_file_no_table(self): # Run test with self.assertRaises(ValueError) as verr: - metadata_file_to_files(infilename, TypeRegistry(), 'eul', {}, - run_env) + metadata_file_to_files(infilename, TypeRegistry(), 'eul', run_env) # Check exception message emsg = "Missing metadata section ([ccpp-arg-table]) for physics_types_simple" self.assertEqual(emsg, str(verr.exception).split('\n', maxsplit=1)[0]) diff --git a/test/unit/test_write_init_files.py b/test/unit/test_write_init_files.py index 4fba21fb..86351216 100644 --- a/test/unit/test_write_init_files.py +++ b/test/unit/test_write_init_files.py @@ -155,7 +155,7 @@ def test_simple_reg_write_init(self): check_init_out, phys_input_out]) # Generate registry files: - _ = gen_registry(filename, 'se', {}, _TMP_DIR, 3, + _ = gen_registry(filename, 'se', _TMP_DIR, 3, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -199,6 +199,89 @@ def test_simple_reg_write_init(self): self.assertTrue(filecmp.cmp(phys_input_in, phys_input_out, shallow=False), msg=amsg) + def test_simple_reg_constituent_write_init(self): + """ + Test that the 'write_init_files' function + generates the correct Fortran code given + a simple registry and CCPP physics suite with + only regular variables plus a registered constituent. + """ + + # Setup registry inputs: + filename = os.path.join(_INIT_SAMPLES_DIR, "simple_reg.xml") + out_source_name = "physics_types_simple" + out_source = os.path.join(_TMP_DIR, out_source_name + '.F90') + out_meta = os.path.join(_TMP_DIR, out_source_name + '.meta') + + # Setup capgen inputs: + model_host = os.path.join(_INIT_SAMPLES_DIR,"simple_host.meta") + sdf = os.path.join(_INIT_SAMPLES_DIR,"suite_simple.xml") + scheme_files = os.path.join(_INIT_SAMPLES_DIR, "temp_adjust_cnst.meta") + cap_datafile = os.path.join(_TMP_DIR, "datatable_cnst.xml") + + host_files = [model_host, out_meta] + + # Setup write_init_files inputs: + vic_name = "phys_vars_init_check_cnst.F90" + pi_name = "physics_inputs_cnst.F90" + check_init_out = os.path.join(_TMP_DIR, vic_name) + phys_input_out = os.path.join(_TMP_DIR, pi_name) + # Setup comparison files + check_init_in = os.path.join(_INIT_SAMPLES_DIR, vic_name) + phys_input_in = os.path.join(_INIT_SAMPLES_DIR, pi_name) + + # Create local logger: + logger = logging.getLogger("write_init_files_constituent") + + # Clear all temporary output files: + remove_files([out_source, out_meta, cap_datafile, + check_init_out, phys_input_out]) + + # Generate registry files: + _, _, ic_names = gen_registry(filename, 'se', _TMP_DIR, 3, + _SRC_MOD_DIR, _CAM_ROOT, + loglevel=logging.ERROR, + error_on_no_validate=True) + + # Generate CCPP capgen files: + kind_types = ['kind_phys=REAL64'] + run_env = CCPPFrameworkEnv(logger, host_files=host_files, + scheme_files=scheme_files, suites=sdf, + preproc_directives='', + generate_docfiles=False, + host_name='cam', kind_types=kind_types, + use_error_obj=False, + force_overwrite=True, + output_root=_TMP_DIR, + ccpp_datafile=cap_datafile) + + cap_database = capgen(run_env, return_db=True) + + # Generate physics initialization files: + retmsg = write_init.write_init_files(cap_database, ic_names, _TMP_DIR, + find_file, _INC_SEARCH_DIRS, + 3, logger, + phys_check_filename=vic_name, + phys_input_filename=pi_name) + + # Check return message: + amsg = f"Test failure: retmsg={retmsg}" + self.assertEqual(retmsg, '', msg=amsg) + + # Make sure each output file was created: + amsg = f"{check_init_out} does not exist" + self.assertTrue(os.path.exists(check_init_out), msg=amsg) + amsg = f"{phys_input_out} does not exist" + self.assertTrue(os.path.exists(phys_input_out), msg=amsg) + + # For each output file, make sure it matches input file + amsg = f"{check_init_out} does not match {check_init_in}" + self.assertTrue(filecmp.cmp(check_init_in, check_init_out, + shallow=False), msg=amsg) + amsg = f"{phys_input_out} does not match {phys_input_in}" + self.assertTrue(filecmp.cmp(phys_input_in, phys_input_out, + shallow=False), msg=amsg) + def test_no_reqvar_write_init(self): """ Test that the 'write_init_files' function @@ -237,7 +320,7 @@ def test_no_reqvar_write_init(self): check_init_out, phys_input_out]) # Generate registry files: - _ = gen_registry(filename, 'se', {}, _TMP_DIR, 3, + _ = gen_registry(filename, 'se', _TMP_DIR, 3, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -320,7 +403,7 @@ def test_protected_reg_write_init(self): check_init_out, phys_input_out]) # Generate registry files: - _, files, _ = gen_registry(filename, 'se', {}, _TMP_DIR, 3, + _, files, _ = gen_registry(filename, 'se', _TMP_DIR, 3, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -404,7 +487,7 @@ def test_host_input_var_write_init(self): check_init_out, phys_input_out]) # Generate registry files: - _ = gen_registry(filename, 'se', {}, _TMP_DIR, 3, + _ = gen_registry(filename, 'se', _TMP_DIR, 3, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -489,7 +572,7 @@ def test_no_horiz_var_write_init(self): remove_files([out_source, out_meta, cap_datafile, check_init_out, phys_input_out]) # Generate registry files: - _, files, _ = gen_registry(filename, 'se', {}, _TMP_DIR, 3, + _, files, _ = gen_registry(filename, 'se', _TMP_DIR, 3, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -564,7 +647,7 @@ def test_scalar_var_write_init(self): check_init_out, phys_input_out]) # Generate registry files: - _, files, _ = gen_registry(filename, 'se', {}, _TMP_DIR, 3, + _, files, _ = gen_registry(filename, 'se', _TMP_DIR, 3, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -639,7 +722,7 @@ def test_4d_var_write_init(self): check_init_out, phys_input_out]) # Generate registry files: - _, files, _ = gen_registry(filename, 'se', {}, _TMP_DIR, 3, + _, files, _ = gen_registry(filename, 'se', _TMP_DIR, 3, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -713,7 +796,7 @@ def test_ddt_reg_write_init(self): remove_files([out_source, out_meta, cap_datafile, check_init_out, phys_input_out]) # Generate registry files: - _ = gen_registry(filename, 'se', {}, _TMP_DIR, 3, + _ = gen_registry(filename, 'se', _TMP_DIR, 3, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -795,7 +878,7 @@ def test_ddt2_reg_write_init(self): check_init_out, phys_input_out]) # Generate registry files: - _, files, _ = gen_registry(filename, 'se', {}, _TMP_DIR, 3, + _, files, _ = gen_registry(filename, 'se', _TMP_DIR, 3, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -876,7 +959,7 @@ def test_ddt_array_reg_write_init(self): check_init_out, phys_input_out]) # Generate registry files: - _ = gen_registry(filename, 'se', {}, _TMP_DIR, 3, + _ = gen_registry(filename, 'se', _TMP_DIR, 3, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -957,7 +1040,7 @@ def test_meta_file_reg_write_init(self): check_init_out, phys_input_out]) # Generate registry files: - _ = gen_registry(filename, 'se', {}, _TMP_DIR, 3, + _ = gen_registry(filename, 'se', _TMP_DIR, 3, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -1038,7 +1121,7 @@ def test_parameter_reg_write_init(self): check_init_out, phys_input_out]) # Generate registry files: - _ = gen_registry(filename, 'se', {}, _TMP_DIR, 3, + _ = gen_registry(filename, 'se', _TMP_DIR, 3, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -1122,7 +1205,7 @@ def test_bad_vertical_dimension(self): check_init_out, phys_input_out]) # Generate registry files: - _ = gen_registry(filename, 'se', {}, _TMP_DIR, 3, + _ = gen_registry(filename, 'se', _TMP_DIR, 3, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) diff --git a/src/data/inputnames_to_stdnames.py b/tools/inputnames_to_stdnames.py similarity index 100% rename from src/data/inputnames_to_stdnames.py rename to tools/inputnames_to_stdnames.py diff --git a/src/data/stdnames_to_inputnames_dictionary.xml b/tools/stdnames_to_inputnames_dictionary.xml similarity index 100% rename from src/data/stdnames_to_inputnames_dictionary.xml rename to tools/stdnames_to_inputnames_dictionary.xml