From d221725c6bcccc822dd5b82c7f499d20d78ca4ec Mon Sep 17 00:00:00 2001 From: Cheryl Craig Date: Mon, 22 Jul 2024 14:03:59 -0600 Subject: [PATCH 01/19] Change to get cam_sima_zm to compile --- Externals_CAM.cfg | 2 +- cime_config/atm_in_paramgen.py | 16 ++++-- cime_config/cam_autogen.py | 22 +++++++++ src/data/physconst.meta | 4 +- src/data/registry.xml | 86 +++++++++++++++++++++++++++++++++ src/physics/utils/phys_comp.F90 | 3 +- 6 files changed, 126 insertions(+), 7 deletions(-) diff --git a/Externals_CAM.cfg b/Externals_CAM.cfg index 0968b6da..43c64dcc 100644 --- a/Externals_CAM.cfg +++ b/Externals_CAM.cfg @@ -17,7 +17,7 @@ required = True local_path = src/physics/ncar_ccpp protocol = git repo_url = https://github.com/ESCOMP/atmospheric_physics -tag = atmos_phys0_02_003 +tag = atmos_phys0_02_006 required = True [externals_description] diff --git a/cime_config/atm_in_paramgen.py b/cime_config/atm_in_paramgen.py index b492a64b..a42df61a 100644 --- a/cime_config/atm_in_paramgen.py +++ b/cime_config/atm_in_paramgen.py @@ -1495,11 +1495,21 @@ def write(self, output_path): # Write all variables within that group (sorted alphabetically): for var in sorted(self._data[nml_group], key=var_sort_key): #Extract variable value(s): - val = self._data[nml_group][var]["values"].strip() + val = self._data[nml_group][var]["values"] #.strip() - #If no value is set then move to the next variable: + #Raise error if no value found: if val is None: - continue + emsg = f"Namelist entry '{var}' is missing a " + emsg += "valid/default 'value' element." + raise AtmInParamGenError(emsg) + else: + #If value found then strip white space: + val = val.strip() + #End if + + #If no value is set then move to the next variable: + #if val is None: + # continue #End if #Extract variable type: diff --git a/cime_config/cam_autogen.py b/cime_config/cam_autogen.py index f6c9a69d..a4810968 100644 --- a/cime_config/cam_autogen.py +++ b/cime_config/cam_autogen.py @@ -604,6 +604,28 @@ def generate_physics_suites(build_cache, preproc_defs, host_name, # end for # end if + #WARNING: THIS SHOULD BE DELETED ONCE DEPENDENCIES ARE ENABLED!!!!!! - CHERYL AND JESSE + ######################################################################################## + if do_gen_ccpp: + # Set CCPP physics "to_be_ccppized" path + atm_phys_tobe_dir = os.path.join(atm_phys_src_dir, "to_be_ccppized") + + # Check that directory exists + if not os.path.isdir(atm_phys_tobe_dir): + #CAM-SIMA will likely not run without this, so raise an error + emsg = "ERROR: Unable to find CCPP physics 'to_be_ccppized' directory:\n" + emsg += f" {atm_phys_tobe_dir}\n Have you run 'checkout_externals'?" + raise CamAutoGenError(emsg) + # end if + + # Copy all "to_be_ccppized" source files to the build directory + atm_phys_tobe_files = glob.glob(os.path.join(atm_phys_tobe_dir, "*.F90")) + for tobe_file in atm_phys_tobe_files: + shutil.copy(tobe_file, physics_blddir) + # end for + # end if + ########################################################################################### + if do_gen_ccpp or do_gen_nl: # save build details in the build cache build_cache.update_ccpp(sdfs, scheme_files, host_files, xml_files, diff --git a/src/data/physconst.meta b/src/data/physconst.meta index b3646d73..504553d8 100644 --- a/src/data/physconst.meta +++ b/src/data/physconst.meta @@ -25,7 +25,7 @@ dimensions = () protected = True [ cpliq ] - standard_name = specific_heat_of_liquid_water_at_20c + standard_name = specific_heat_of_liquid_water_at_constant_pressure long_name = Specific heat of fresh H2O units = J kg-1 K-1 type = real | kind = kind_phys @@ -268,7 +268,7 @@ dimensions = () protected = True [ epsilo ] - standard_name = ratio_of_h2o_to_dry_air_molecular_weights + standard_name = ratio_of_water_vapor_to_dry_air_molecular_weights units = 1 type = real | kind = kind_phys dimensions = () diff --git a/src/data/registry.xml b/src/data/registry.xml index c9dd29e7..59bf30d0 100644 --- a/src/data/registry.xml +++ b/src/data/registry.xml @@ -399,5 +399,91 @@ rain mass mixing ratio with respect to moist air plus all airborne condensates RAINQM cnst_RAINQM + + + + horizontal_dimension + landfrac cam_in_landfrac + + + + + + horizontal_dimension + pblh pbuf_pblh + + + + + horizontal_dimension + tpert pbuf_tpert + + + horizontal_dimension vertical_layer_dimension + ICWMRDP pbuf_ICWMRDP + + + horizontal_dimension vertical_layer_dimension + + + horizontal_dimension vertical_layer_dimension + CLD pbuf_CLD + + + .true. + + + 1 + + + horizontal_dimension vertical_layer_dimension + + + + + + + number_of_ccpp_constituents + + + horizontal_dimension vertical_layer_dimension number_of_ccpp_constituents + diff --git a/src/physics/utils/phys_comp.F90 b/src/physics/utils/phys_comp.F90 index c3e91bf9..558df5e8 100644 --- a/src/physics/utils/phys_comp.F90 +++ b/src/physics/utils/phys_comp.F90 @@ -137,6 +137,7 @@ subroutine phys_init() use physics_types, only: allocate_physics_types_fields use cam_ccpp_cap, only: cam_ccpp_physics_initialize use cam_ccpp_cap, only: ccpp_physics_suite_part_list + use cam_constituents, only: num_advected ! Local variables integer :: i_group @@ -144,7 +145,7 @@ subroutine phys_init() call cam_thermo_init(columns_on_task, pver, pverp) call allocate_physics_types_fields(columns_on_task, pver, pverp, & - set_init_val_in=.true., reallocate_in=.false.) + num_advected, set_init_val_in=.true., reallocate_in=.false.) call cam_ccpp_physics_initialize(phys_suite_name) if (errcode /= 0) then call endrun('cam_ccpp_physics_initialize: '//trim(errmsg)) From 7e164e5faf9fbce24b1e9bc61097f563375b3fa0 Mon Sep 17 00:00:00 2001 From: Cheryl Craig Date: Wed, 24 Jul 2024 14:51:32 -0600 Subject: [PATCH 02/19] Remove nsteps from registry as now in there --- src/data/registry.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/data/registry.xml b/src/data/registry.xml index 8c7b4793..6885e776 100644 --- a/src/data/registry.xml +++ b/src/data/registry.xml @@ -484,10 +484,6 @@ standard_name="index_of_last_column_of_gathered_deep_convection_arrays" units="index" type="integer" > - - Date: Wed, 7 Aug 2024 14:48:25 -0600 Subject: [PATCH 03/19] Fix typo in metadata file --- src/data/ref_pres.meta | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/ref_pres.meta b/src/data/ref_pres.meta index 2d1f591f..1caf116f 100644 --- a/src/data/ref_pres.meta +++ b/src/data/ref_pres.meta @@ -35,7 +35,7 @@ dimensions = () protected = True [ trop_cloud_top_lev ] - standard_name = index_of_pressure_at_troposhere_cloud_top + standard_name = index_of_pressure_at_troposphere_cloud_top units = index type = integer dimensions = () From 18a608f8211979368760df433c5eedf9ea611dbb Mon Sep 17 00:00:00 2001 From: Cheryl Craig Date: Wed, 14 Aug 2024 13:24:23 -0600 Subject: [PATCH 04/19] Updates to aid in getting ZM running in CAM-SIMA --- src/data/registry.xml | 10 +++++++--- src/utils/time_manager.F90 | 4 ++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/data/registry.xml b/src/data/registry.xml index 6885e776..8699911f 100644 --- a/src/data/registry.xml +++ b/src/data/registry.xml @@ -466,7 +466,8 @@ + units="flag" type="logical" + access="protected" > .true. + allocatable="allocatable" + access="protected" > number_of_ccpp_constituents + allocatable="allocatable" + access="protected" > horizontal_dimension vertical_layer_dimension number_of_ccpp_constituents + 0 diff --git a/src/utils/time_manager.F90 b/src/utils/time_manager.F90 index 566f84b6..539c2408 100644 --- a/src/utils/time_manager.F90 +++ b/src/utils/time_manager.F90 @@ -84,6 +84,8 @@ subroutine timemgr_init( & ref_tod, stop_ymd, stop_tod, curr_ymd, curr_tod, & perpetual_run, perpetual_ymd, initial_run) + use phys_vars_init_check, only: mark_as_initialized + ! Initialize the time manager. ! Arguments @@ -152,6 +154,8 @@ subroutine timemgr_init( & call timemgr_print() end if + call mark_as_initialized('current_timestep_number') + end subroutine timemgr_init !=========================================================================== From 3c63ad17d6baec97ff8177b791716f070b80c322 Mon Sep 17 00:00:00 2001 From: Courtney Peverley Date: Thu, 19 Sep 2024 18:55:36 -0600 Subject: [PATCH 05/19] read in all constituents from file; not just build-time ones --- cime_config/cam_autogen.py | 13 +- cime_config/cam_build_cache.py | 16 +- cime_config/cam_config.py | 4 +- src/data/generate_registry_data.py | 29 ++- src/data/write_init_files.py | 229 ++++++++++++------ .../update_reg_build_cache.xml | 2 + .../phys_vars_init_check_cnst.F90 | 10 +- .../write_init_files/physics_inputs_4D.F90 | 175 +++++++------ .../write_init_files/physics_inputs_bvd.F90 | 149 +++++++----- .../write_init_files/physics_inputs_cnst.F90 | 149 +++++++----- .../write_init_files/physics_inputs_ddt.F90 | 175 +++++++------ .../write_init_files/physics_inputs_ddt2.F90 | 149 +++++++----- .../physics_inputs_ddt_array.F90 | 149 +++++++----- .../physics_inputs_host_var.F90 | 149 +++++++----- .../write_init_files/physics_inputs_mf.F90 | 177 ++++++++------ .../physics_inputs_no_horiz.F90 | 149 +++++++----- .../write_init_files/physics_inputs_noreq.F90 | 149 +++++++----- .../write_init_files/physics_inputs_param.F90 | 149 +++++++----- .../physics_inputs_protect.F90 | 149 +++++++----- .../physics_inputs_scalar.F90 | 149 +++++++----- .../physics_inputs_simple.F90 | 149 +++++++----- test/unit/test_build_cache.py | 4 +- test/unit/test_cam_autogen.py | 8 +- test/unit/test_registry.py | 18 +- test/unit/test_write_init_files.py | 40 +-- 25 files changed, 1448 insertions(+), 1091 deletions(-) diff --git a/cime_config/cam_autogen.py b/cime_config/cam_autogen.py index eeb31229..e5d7b32d 100644 --- a/cime_config/cam_autogen.py +++ b/cime_config/cam_autogen.py @@ -392,7 +392,7 @@ def generate_registry(data_search, build_cache, atm_root, bldroot, gen_fort_indent, source_mods_dir, atm_root, logger=_LOGGER, schema_paths=data_search, error_on_no_validate=True) - retcode, reg_file_list, ic_names = retvals + retcode, reg_file_list, ic_names, constituents = retvals # Raise error if gen_registry failed: if retcode != 0: emsg = "ERROR:Unable to generate CAM data structures from {}, err = {}" @@ -406,14 +406,15 @@ 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_file_paths, ic_names) + reg_file_paths, ic_names, constituents) else: # If we did not run the registry generator, retrieve info from cache reg_file_paths = build_cache.reg_file_list() ic_names = build_cache.ic_names() + constituents = build_cache.constituents() # End if - return genreg_dir, do_gen_registry, reg_file_paths, ic_names + return genreg_dir, do_gen_registry, reg_file_paths, ic_names, constituents ############################################################################### def generate_physics_suites(build_cache, preproc_defs, host_name, @@ -629,7 +630,7 @@ def generate_physics_suites(build_cache, preproc_defs, host_name, ############################################################################### def generate_init_routines(build_cache, bldroot, force_ccpp, force_init, source_mods_dir, gen_fort_indent, - cap_database, ic_names): + cap_database, ic_names, constituents): ############################################################################### """ Generate the host model initialization source code files @@ -667,8 +668,8 @@ def generate_init_routines(build_cache, bldroot, force_ccpp, force_init, # within write_init_files (so that write_init_files can be the place # where the source include files are stored). source_paths = [source_mods_dir, _REG_GEN_DIR] - retmsg = write_init_files(cap_database, ic_names, init_dir, - _find_file, source_paths, + retmsg = write_init_files(cap_database, ic_names, constituents, + init_dir, _find_file, source_paths, gen_fort_indent, _LOGGER) #Check that script ran properly: diff --git a/cime_config/cam_build_cache.py b/cime_config/cam_build_cache.py index 2bda072e..70b31853 100644 --- a/cime_config/cam_build_cache.py +++ b/cime_config/cam_build_cache.py @@ -226,6 +226,7 @@ def __init__(self, build_cache): self.__kind_types = {} self.__reg_gen_files = [] self.__ic_names = {} + self.__constituents = [] if os.path.exists(build_cache): # Initialize build cache state _, cache = read_xml_file(build_cache) @@ -252,6 +253,10 @@ def __init__(self, build_cache): # end if itext = clean_xml_text(item) self.__ic_names[stdname].append(itext) + elif item.tag == 'constituent_entry': + stdname = item.get('standard_name') + itext = clean_xml_text(item) + self.__constituents.append(itext) else: emsg = "ERROR: Unknown registry tag, '{}'" raise ValueError(emsg.format(item.tag)) @@ -313,7 +318,7 @@ def __init__(self, build_cache): # end if def update_registry(self, gen_reg_file, registry_source_files, - dycore, reg_file_list, ic_names): + dycore, reg_file_list, ic_names, constituents): """Replace the registry cache data with input data """ self.__dycore = dycore @@ -328,6 +333,7 @@ def update_registry(self, gen_reg_file, registry_source_files, # ic_names are the initial condition variable names from the registry, # and should already be of type dict: self.__ic_names = ic_names + self.__constituents = constituents def update_ccpp(self, suite_definition_files, scheme_files, host_files, xml_files, namelist_meta_files, namelist_groups, @@ -400,6 +406,10 @@ def write(self): ic_entry.text = ic_name # end for # end for + for stdname in self.__constituents: + const_entry = ET.SubElement(registry, 'constituent_entry') + const_entry.text = stdname + # end for # CCPP ccpp = ET.SubElement(new_cache, 'CCPP') for sfile in self.__sdfs.values(): @@ -603,5 +613,9 @@ def ic_names(self): """Return a copy of the registry initial conditions dictionary""" return dict(self.__ic_names) + def constituents(self): + """Return a copy of the registry constituents list""" + return list(self.__constituents) + ############# # End of file diff --git a/cime_config/cam_config.py b/cime_config/cam_config.py index 80bef16e..d2a5fcb6 100644 --- a/cime_config/cam_config.py +++ b/cime_config/cam_config.py @@ -838,7 +838,7 @@ def generate_cam_src(self, gen_fort_indent): retvals = generate_registry(data_search, build_cache, self.__atm_root, self.__bldroot, source_mods_dir, dyn, gen_fort_indent) - reg_dir, force_ccpp, reg_files, ic_names = retvals + reg_dir, force_ccpp, reg_files, ic_names, constituents = retvals #Add registry path to config object: reg_dir_desc = "Location of auto-generated registry code." @@ -871,7 +871,7 @@ def generate_cam_src(self, gen_fort_indent): init_dir = generate_init_routines(build_cache, self.__bldroot, force_ccpp, force_init, source_mods_dir, gen_fort_indent, - capgen_db, ic_names) + capgen_db, ic_names, constituents) #Add registry path to config object: init_dir_desc = "Location of auto-generated physics initialization code." diff --git a/src/data/generate_registry_data.py b/src/data/generate_registry_data.py index 33adc954..022c176f 100755 --- a/src/data/generate_registry_data.py +++ b/src/data/generate_registry_data.py @@ -1733,6 +1733,31 @@ def _create_ic_name_dict(registry): # end for return ic_name_dict +############################################################################### +def _create_constituent_list(registry): +############################################################################### + """ + Create a list of all constituents found in the registry. + To be used by write_init_files.py - need to keep track + of all constituent variables, not just ones required by + CCPP metadata, to handle runtime constituents + """ + constituent_list = [] + for section in registry: + if section.tag == 'file': + for obj in section: + if obj.tag == 'variable': + if obj.get('constituent'): + stdname = obj.get('standard_name') + constituent_list.append(stdname) + # end if (ignore non-constituents) + # end if (ignore other node types) + # end for + # end if (ignore other node types) + # end for + return constituent_list + + ############################################################################### def gen_registry(registry_file, dycore, outdir, indent, src_mod, src_root, loglevel=None, logger=None, @@ -1802,6 +1827,7 @@ def gen_registry(registry_file, dycore, outdir, indent, retcode = 1 files = None ic_names = None + constituents = None else: library_name = registry.get('name') emsg = f"Parsing registry, {library_name}" @@ -1811,9 +1837,10 @@ def gen_registry(registry_file, dycore, outdir, indent, src_root, reg_dir, indent, logger) # See comment in _create_ic_name_dict ic_names = _create_ic_name_dict(registry) + constituents = _create_constituent_list(registry) retcode = 0 # Throw exception on error # end if - return retcode, files, ic_names + return retcode, files, ic_names, constituents def main(): """Function to execute when module called as a script""" diff --git a/src/data/write_init_files.py b/src/data/write_init_files.py index aa93962e..6bf443f0 100644 --- a/src/data/write_init_files.py +++ b/src/data/write_init_files.py @@ -46,7 +46,7 @@ #Main function ############## -def write_init_files(cap_database, ic_names, outdir, +def write_init_files(cap_database, ic_names, constituents, outdir, file_find_func, source_paths, indent, logger, phys_check_filename=None, phys_input_filename=None): @@ -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, constituent_set, retmsg = gather_ccpp_req_vars(cap_database) + host_vars, constituent_set, retmsg = gather_ccpp_req_vars(cap_database, constituents) # Quit now if there are missing variables if retmsg: @@ -173,12 +173,12 @@ def write_init_files(cap_database, ic_names, outdir, # end for # Write public parameters: - retvals = write_ic_params(outfile, host_vars, ic_names) + retvals = write_ic_params(outfile, host_vars, ic_names, constituents) ic_names, ic_max_len, stdname_max_len = retvals # Write initial condition arrays: write_ic_arrays(outfile, ic_names, ic_max_len, - stdname_max_len, host_vars) + stdname_max_len, host_vars, constituents) # Add "contains" statement: outfile.end_module_header() @@ -244,7 +244,7 @@ def write_init_files(cap_database, ic_names, outdir, # Write physics_check_data subroutine: write_phys_check_subroutine(outfile, host_dict, host_vars, host_imports, - phys_check_fname_str, constituent_set) + phys_check_fname_str, constituent_set, constituents) # -------------------------------------- @@ -298,7 +298,7 @@ def _find_and_add_host_variable(stdname, host_dict, var_dict): return missing_vars ############################################################################## -def gather_ccpp_req_vars(cap_database): +def gather_ccpp_req_vars(cap_database, registry_constituents): """ Generate a list of host-model and constituent variables required by the CCPP physics suites potentially being used @@ -331,13 +331,12 @@ def gather_ccpp_req_vars(cap_database): (stdname not in req_vars) and (stdname not in _EXCLUDED_STDNAMES)): 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) + #Add variable to required variable list if it's not a registry constituent + if stdname not in registry_constituents: + req_vars[stdname] = cvar + # end if else: # We need to work with the host model version of this variable missing = _find_and_add_host_variable(stdname, host_dict, @@ -359,7 +358,7 @@ def gather_ccpp_req_vars(cap_database): #FORTRAN WRITING FUNCTIONS ########################## -def write_ic_params(outfile, host_vars, ic_names): +def write_ic_params(outfile, host_vars, ic_names, constituents): """ Write public parameter declarations needed @@ -370,7 +369,7 @@ def write_ic_params(outfile, host_vars, ic_names): #Create new Fortran integer parameter to store total number of variables: outfile.comment("Total number of physics-related variables:", 1) - num_pvars = len(host_vars) + num_pvars = len(host_vars) + len(constituents) outfile.write(f"integer, public, parameter :: phys_var_num = {num_pvars}", 1) num_cvars = len(_EXCLUDED_STDNAMES) @@ -419,7 +418,7 @@ def write_ic_params(outfile, host_vars, ic_names): ###### def write_ic_arrays(outfile, ic_name_dict, ic_max_len, - stdname_max_len, host_vars): + stdname_max_len, host_vars, constituents): """ Write initial condition arrays to store @@ -428,7 +427,7 @@ def write_ic_arrays(outfile, ic_name_dict, ic_max_len, """ #Create variable name array string lists: - num_input_vars = len(host_vars) + num_input_vars = len(host_vars) + len(constituents) stdname_strs = [] ic_name_strs = [] @@ -445,6 +444,10 @@ def write_ic_arrays(outfile, ic_name_dict, ic_max_len, # for each variable with the proper length, : for hvar in host_vars: var_stdname = hvar.get_prop_value('standard_name') + if var_stdname in constituents: + # skip registry constituents; we'll tackle these after + continue + # end if # Create standard_name string with proper size, and append to list: stdname_strs.append(f"'{var_stdname: <{stdname_max_len}}'") @@ -465,6 +468,26 @@ def write_ic_arrays(outfile, ic_name_dict, ic_max_len, ic_name_strs.append(', '.join(f"'{n}'" for n in ic_names_with_spaces)) # end for + # Add any constituent variables: + for const in constituents: + stdname_strs.append(f"'{const: <{stdname_max_len}}'") + + #Extract input (IC) names list: + ic_names = ic_name_dict[const] + + # Determine number of IC names for variable: + ic_name_num = len(ic_names) + + #Pad the ic_names to ic_max_len: + ic_names_with_spaces = [f"{x: <{ic_max_len}}" for x in ic_names] + if ic_name_num < max_ic_num: + ic_names_with_spaces.extend(fake_ic_names[:-ic_name_num]) + # end if + + #Append new ic_names to string list: + ic_name_strs.append(', '.join(f"'{n}'" for n in ic_names_with_spaces)) + # end if + #Write arrays to Fortran file: #---------------------------- @@ -550,6 +573,17 @@ def write_ic_arrays(outfile, ic_name_dict, ic_max_len, #Write line to file: outfile.write(log_arr_str, 2) # end for + for var_num, var_name in enumerate(constituents): + # If at the end of the list, then update suffix: + if var_num == num_input_vars-len(host_vars)-1: + arr_suffix = ' /)' + # end if + #Set array values: + log_arr_str = '.false.' + arr_suffix + + #Write line to file: + outfile.write(log_arr_str, 2) + # end for outfile.blank_line() @@ -565,7 +599,6 @@ def write_ic_arrays(outfile, ic_name_dict, ic_max_len, #variable is a parameter: arr_suffix = ', &' for var_num, hvar in enumerate(host_vars): - var_stdname = hvar.get_prop_value('standard_name') #If at the end of the list, then update suffix: if var_num == num_input_vars-1: arr_suffix = ' /)' @@ -579,6 +612,16 @@ def write_ic_arrays(outfile, ic_name_dict, ic_max_len, #Write line to file: outfile.write(log_arr_str, 2) # end for + for var_num, varname in enumerate(constituents): + #If at the end of the list, then update suffix: + if var_num == num_input_vars-len(host_vars)-1: + arr_suffix = ' /)' + # end if + #Set array values: + log_arr_str = 'UNINITIALIZED' + arr_suffix + #Write line to file: + outfile.write(log_arr_str, 2) + # end for outfile.blank_line() #---------------------------- @@ -841,10 +884,13 @@ def write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports, ["physics_data", ["read_field", "find_input_name_idx", "no_exist_idx", "init_mark_idx", "prot_no_init_idx", "const_idx"]], - ["cam_ccpp_cap", ["ccpp_physics_suite_variables", "cam_constituents_array", "cam_model_const_properties"]], + ["cam_ccpp_cap", ["ccpp_physics_suite_variables", + "cam_constituents_array", + "cam_model_const_properties"]], ["ccpp_kinds", ["kind_phys"]], [phys_check_fname_str, ["phys_var_num", "phys_var_stdnames", - "input_var_names", "std_name_len"]], + "input_var_names", "std_name_len", + "is_initialized"]], ["ccpp_constituent_prop_mod", ["ccpp_constituent_prop_ptr_t"]], ["cam_logfile", ["iulog"]]] @@ -887,6 +933,7 @@ def write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports, outfile.write("character(len=2) :: sep3 !String separator used to print err messages", 2) outfile.write("real(kind=kind_phys), pointer :: field_data_ptr(:,:,:)", 2) outfile.write("logical :: var_found !Bool to determine if consituent found in data files", 2) + outfile.write("character(len=std_name_len) :: std_name !Variable to hold constiutent standard name", 2) outfile.blank_line() outfile.comment("Fields needed for getting default data value for constituents", 2) outfile.write("type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:)", 2) @@ -981,48 +1028,7 @@ def write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports, # Handle the case where the required variable is a constituent outfile.write("case (const_idx)", 5) outfile.blank_line() - outfile.comment("If an index was found in the constituent hash table, then read in the data to that index of the constituent array", 6) - outfile.blank_line() - outfile.write("var_found = .false.", 6) - outfile.write("field_data_ptr => cam_constituents_array()", 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) - outfile.write("call const_props(constituent_idx)%has_default(constituent_has_default, constituent_errflg, constituent_errmsg)", 7) - outfile.write("if (constituent_errflg /= 0) then", 7) - outfile.write("call endrun(constituent_errmsg, file=__FILE__, line=__LINE__)", 8) - outfile.write("end if", 7) - outfile.write("if (constituent_has_default) then", 7) - outfile.write("call const_props(constituent_idx)%default_value(constituent_default_value, constituent_errflg, constituent_errmsg)", 8) - outfile.write("if (constituent_errflg /= 0) then", 8) - outfile.write("call endrun(constituent_errmsg, file=__FILE__, line=__LINE__)", 9) - outfile.write("end if", 8) - outfile.write("field_data_ptr(:,:,constituent_idx) = constituent_default_value", 8) - outfile.write("if (masterproc) then", 8) - outfile.write("write(iulog,*) 'Consitituent ', trim(ccpp_required_data(req_idx)), ' initialized to default value: ', constituent_default_value", 9) - outfile.write("end if", 8) - outfile.write("else", 7) - outfile.write("field_data_ptr(:,:,constituent_idx) = 0._kind_phys", 8) - outfile.write("if (masterproc) then", 8) - outfile.write("write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.'", 9) - outfile.write("end if", 8) - outfile.write("end if", 7) - outfile.write("end if", 6) + outfile.comment("If an index was found in the constituent hash table, then do nothing, this will be handled later", 6) outfile.blank_line() # start default case steps: @@ -1072,6 +1078,60 @@ def write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports, # End suite loop: outfile.write(" end do !CCPP suites", 2) outfile.blank_line() + + # Read in constituent data + outfile.comment("Read in constituent variables if not using init variables", 2) + outfile.write("field_data_ptr => cam_constituents_array()", 2) + outfile.write("const_props => cam_model_const_properties()", 2) + outfile.blank_line() + outfile.comment("Iterate over all registered constituents", 2) + outfile.write("do constituent_idx = 1, size(const_props)", 2) + outfile.write("var_found = .false.", 3) + outfile.comment("Check if constituent standard name in registered SIMA standard names list:", 3) + outfile.write("call const_props(constituent_idx)%standard_name(std_name)", 3) + outfile.write("if(any(phys_var_stdnames == trim(std_name))) then", 3) + outfile.comment("Don't read the variable in if it's already initialized", 4) + outfile.write("if (is_initialized(std_name)) then", 4) + outfile.write("cycle", 5) + outfile.write("end if", 4) + outfile.comment("Find array index to extract correct input names:", 4) + outfile.write("do n=1, phys_var_num", 4) + outfile.write("if(trim(phys_var_stdnames(n)) == trim(std_name)) then", 5) + outfile.write("const_input_idx = n", 6) + outfile.write("exit", 6) + outfile.write("end if", 5) + outfile.write("end do", 4) + outfile.write("call read_field(file, std_name, 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)", 4) + outfile.write("else", 3) + outfile.comment("If not in standard names list, then just use constituent name as input file name:",4) + outfile.write("call read_field(file, std_name, [std_name], 'lev', timestep, field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found)", 4) + outfile.write("end if", 3) + outfile.write("if(.not. var_found) then", 3) + outfile.write("constituent_has_default = .false.", 4) + outfile.write("call const_props(constituent_idx)%has_default(constituent_has_default, constituent_errflg, constituent_errmsg)", 4) + outfile.write("if (constituent_errflg /= 0) then", 4) + outfile.write("call endrun(constituent_errmsg, file=__FILE__, line=__LINE__)", 5) + outfile.write("end if", 4) + outfile.write("if (constituent_has_default) then", 4) + outfile.write("call const_props(constituent_idx)%default_value(constituent_default_value, constituent_errflg, constituent_errmsg)", 5) + outfile.write("if (constituent_errflg /= 0) then", 5) + outfile.write("call endrun(constituent_errmsg, file=__FILE__, line=__LINE__)", 6) + outfile.write("end if", 5) + outfile.write("field_data_ptr(:,:,constituent_idx) = constituent_default_value", 5) + outfile.write("if (masterproc) then", 5) + outfile.write("write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' initialized to default value: ', constituent_default_value", 6) + outfile.write("end if", 5) + outfile.write("else", 4) + outfile.write("field_data_ptr(:,:,constituent_idx) = 0._kind_phys", 5) + outfile.write("if (masterproc) then", 5) + outfile.write("write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.'", 6) + outfile.write("end if", 5) + outfile.write("end if", 4) + outfile.write("end if", 3) + outfile.write("end do", 2) + outfile.blank_line() + + # start default case steps: # End subroutine: outfile.write("end subroutine physics_read_data", 1) @@ -1081,7 +1141,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, constituent_set): + phys_check_fname_str, constituent_set, constituents): """ Write the "physics_check_data" subroutine, which @@ -1149,7 +1209,9 @@ def write_phys_check_subroutine(outfile, host_dict, host_vars, host_imports, ["physics_data", ["check_field", "find_input_name_idx", "no_exist_idx", "init_mark_idx", "prot_no_init_idx", "const_idx"]], - ["cam_ccpp_cap", ["ccpp_physics_suite_variables", "cam_advected_constituents_array"]], + ["cam_ccpp_cap", ["ccpp_physics_suite_variables", + "cam_advected_constituents_array", + "cam_model_const_properties"]], ["cam_constituents", ["const_get_index"]], ["ccpp_kinds", ["kind_phys"]], ["cam_logfile", ["iulog"]], @@ -1157,6 +1219,7 @@ 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"]], + ["ccpp_constituent_prop_mod", ["ccpp_constituent_prop_ptr_t"]], [phys_check_fname_str, ["phys_var_num", "phys_var_stdnames", "input_var_names", @@ -1204,7 +1267,9 @@ def write_phys_check_subroutine(outfile, host_dict, host_vars, host_imports, outfile.write("logical :: file_found", 2) outfile.write("logical :: is_first", 2) outfile.write("logical :: is_read", 2) + outfile.write("character(len=std_name_len) :: std_name !Variable to hold constiutent standard name", 2) outfile.write("real(kind=kind_phys), pointer :: field_data_ptr(:,:,:)", 2) + outfile.write("type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:)", 2) outfile.blank_line() # Initialize variables: @@ -1268,24 +1333,7 @@ def write_phys_check_subroutine(outfile, host_dict, host_vars, host_imports, outfile.comment("First check if the required variable is a constituent:", 4) outfile.write("call const_get_index(ccpp_required_data(req_idx), constituent_idx, abort=.false., warning=.false.)", 4) 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.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("cycle", 5) outfile.write("else", 4) outfile.comment("The required variable is not a constituent. Check if the variable was read from a file", 5) @@ -1321,6 +1369,27 @@ def write_phys_check_subroutine(outfile, host_dict, host_vars, host_imports, # End suite loop: outfile.write("end do !CCPP suites", 2) outfile.blank_line() + outfile.comment("Check constituent variables", 2) + outfile.write("field_data_ptr => cam_advected_constituents_array()", 2) + outfile.write("const_props => cam_model_const_properties()", 2) + outfile.blank_line() + outfile.write("do constituent_idx = 1, size(const_props)", 2) + outfile.comment("Check if constituent standard name in registered SIMA standard names list:", 3) + outfile.write("call const_props(constituent_idx)%standard_name(std_name)", 3) + outfile.write("if(any(phys_var_stdnames == std_name)) then", 3) + outfile.comment("Find array index to extract correct input names:", 4) + outfile.write("do n=1, phys_var_num", 4) + outfile.write("if(trim(phys_var_stdnames(n)) == trim(std_name)) then", 5) + outfile.write("const_input_idx = n", 6) + outfile.write("exit", 6) + outfile.write("end if", 5) + outfile.write("end do", 4) + outfile.write("call check_field(file, input_var_names(:,const_input_idx), 'lev', timestep, field_data_ptr(:,:,constituent_idx), std_name, min_difference, min_relative_value, is_first)", 4) + outfile.write("else", 3) + outfile.comment("If not in standard names list, then just use constituent name as input file name:",4) + outfile.write("call check_field(file, [std_name], 'lev', timestep, field_data_ptr(:,:,constituent_idx), std_name, min_difference, min_relative_value, is_first)", 4) + outfile.write("end if", 3) + outfile.write("end do", 2) # Close check file outfile.comment("Close check file:", 2) 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 e773ee2c..5a4273b9 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 @@ -8,6 +8,8 @@ tmp/cam_build_cache/test_reg.xml heart brain + cnst_1 + cnst_2 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 index 365fe4c7..515e0307 100644 --- 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 @@ -40,7 +40,7 @@ module phys_vars_init_check_cnst integer, public, parameter :: std_name_len = 25 ! Max length of input (IC) file variable names: - integer, public, parameter :: ic_name_len = 13 + integer, public, parameter :: ic_name_len = 12 ! Physics-related input variable standard names: character(len=25), public, protected :: phys_var_stdnames(phys_var_num) = (/ & @@ -65,10 +65,10 @@ module phys_vars_init_check_cnst "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/)) + character(len=12), 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)= (/ & 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 75efc762..fcb3802a 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_num, 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, is_initialized use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use physics_types_4D, only: slp, theta @@ -69,6 +69,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name ! Fields needed for getting default data value for constituents type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) @@ -133,51 +134,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default @@ -212,23 +169,76 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end do !CCPP suites + ! Read in constituent variables if not using init variables + field_data_ptr => cam_constituents_array() + const_props => cam_model_const_properties() + + ! Iterate over all registered constituents + do constituent_idx = 1, size(const_props) + var_found = .false. + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == trim(std_name))) then + ! Don't read the variable in if it's already initialized + if (is_initialized(std_name)) then + cycle + end if + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) then + const_input_idx = n + exit + end if + end do + call read_field(file, std_name, 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, std_name, [std_name], '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 + 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,*) 'Constituent ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + end if + end if + end if + end do + 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_4D, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len - use physics_types_4D, only: slp, theta + 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, cam_model_const_properties + 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 ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t + 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 character(len=SHR_KIND_CL), intent(in) :: file_name @@ -260,7 +270,9 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, logical :: file_found logical :: is_first logical :: is_read + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name real(kind=kind_phys), pointer :: field_data_ptr(:,:,:) + type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) ! Initalize missing and non-initialized variables strings: missing_required_vars = ' ' @@ -299,25 +311,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, ! 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 + cycle 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: @@ -344,6 +338,29 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, end do !CCPP suites + ! Check constituent variables + field_data_ptr => cam_advected_constituents_array() + const_props => cam_model_const_properties() + + do constituent_idx = 1, size(const_props) + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == std_name)) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) 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), std_name, & + 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, [std_name], 'lev', timestep, field_data_ptr(:,:,constituent_idx), std_name, min_difference, min_relative_value, & + is_first) + end if + end do ! Close check file: call cam_pio_closefile(file) deallocate(file) 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 46cc2b53..5bf9cf29 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_num, 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, is_initialized use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use physics_types_bad_vertdim, only: slp, theta @@ -69,6 +69,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name ! Fields needed for getting default data value for constituents type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) @@ -133,51 +134,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default @@ -212,6 +169,58 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end do !CCPP suites + ! Read in constituent variables if not using init variables + field_data_ptr => cam_constituents_array() + const_props => cam_model_const_properties() + + ! Iterate over all registered constituents + do constituent_idx = 1, size(const_props) + var_found = .false. + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == trim(std_name))) then + ! Don't read the variable in if it's already initialized + if (is_initialized(std_name)) then + cycle + end if + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) then + const_input_idx = n + exit + end if + end do + call read_field(file, std_name, 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, std_name, [std_name], '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 + 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,*) 'Constituent ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + end if + end if + end if + end do + end subroutine physics_read_data subroutine physics_check_data(file_name, suite_names, timestep, min_difference, min_relative_value) @@ -219,7 +228,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, 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_ccpp_cap, only: ccpp_physics_suite_variables, cam_advected_constituents_array, cam_model_const_properties use cam_constituents, only: const_get_index use ccpp_kinds, only: kind_phys use cam_logfile, only: iulog @@ -227,6 +236,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 ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t 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 @@ -260,7 +270,9 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, logical :: file_found logical :: is_first logical :: is_read + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name real(kind=kind_phys), pointer :: field_data_ptr(:,:,:) + type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) ! Initalize missing and non-initialized variables strings: missing_required_vars = ' ' @@ -299,25 +311,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, ! 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 + cycle 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: @@ -344,6 +338,29 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, end do !CCPP suites + ! Check constituent variables + field_data_ptr => cam_advected_constituents_array() + const_props => cam_model_const_properties() + + do constituent_idx = 1, size(const_props) + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == std_name)) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) 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), std_name, & + 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, [std_name], 'lev', timestep, field_data_ptr(:,:,constituent_idx), std_name, min_difference, min_relative_value, & + is_first) + end if + end do ! Close check file: call cam_pio_closefile(file) deallocate(file) 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 index 2289adfd..7c830ac2 100644 --- a/test/unit/sample_files/write_init_files/physics_inputs_cnst.F90 +++ b/test/unit/sample_files/write_init_files/physics_inputs_cnst.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_cnst, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len + use phys_vars_init_check_cnst, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len, is_initialized use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use physics_types_simple, only: slp, theta @@ -69,6 +69,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name ! Fields needed for getting default data value for constituents type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) @@ -133,51 +134,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default @@ -212,6 +169,58 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end do !CCPP suites + ! Read in constituent variables if not using init variables + field_data_ptr => cam_constituents_array() + const_props => cam_model_const_properties() + + ! Iterate over all registered constituents + do constituent_idx = 1, size(const_props) + var_found = .false. + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == trim(std_name))) then + ! Don't read the variable in if it's already initialized + if (is_initialized(std_name)) then + cycle + end if + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) then + const_input_idx = n + exit + end if + end do + call read_field(file, std_name, 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, std_name, [std_name], '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 + 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,*) 'Constituent ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + end if + end if + end if + end do + end subroutine physics_read_data subroutine physics_check_data(file_name, suite_names, timestep, min_difference, min_relative_value) @@ -219,7 +228,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, 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_ccpp_cap, only: ccpp_physics_suite_variables, cam_advected_constituents_array, cam_model_const_properties use cam_constituents, only: const_get_index use ccpp_kinds, only: kind_phys use cam_logfile, only: iulog @@ -227,6 +236,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 ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t 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 @@ -260,7 +270,9 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, logical :: file_found logical :: is_first logical :: is_read + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name real(kind=kind_phys), pointer :: field_data_ptr(:,:,:) + type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) ! Initalize missing and non-initialized variables strings: missing_required_vars = ' ' @@ -299,25 +311,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, ! 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 + cycle 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: @@ -345,6 +339,29 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, end do !CCPP suites + ! Check constituent variables + field_data_ptr => cam_advected_constituents_array() + const_props => cam_model_const_properties() + + do constituent_idx = 1, size(const_props) + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == std_name)) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) 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), std_name, & + 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, [std_name], 'lev', timestep, field_data_ptr(:,:,constituent_idx), std_name, min_difference, min_relative_value, & + is_first) + end if + end do ! Close check file: call cam_pio_closefile(file) deallocate(file) 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 de9adfea..1810ede6 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_num, 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, is_initialized use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use physics_types_ddt, only: phys_state, slp @@ -69,6 +69,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name ! Fields needed for getting default data value for constituents type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) @@ -133,51 +134,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default @@ -212,23 +169,76 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end do !CCPP suites + ! Read in constituent variables if not using init variables + field_data_ptr => cam_constituents_array() + const_props => cam_model_const_properties() + + ! Iterate over all registered constituents + do constituent_idx = 1, size(const_props) + var_found = .false. + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == trim(std_name))) then + ! Don't read the variable in if it's already initialized + if (is_initialized(std_name)) then + cycle + end if + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) then + const_input_idx = n + exit + end if + end do + call read_field(file, std_name, 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, std_name, [std_name], '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 + 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,*) 'Constituent ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + end if + end if + end if + end do + 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_ddt, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len - use physics_types_ddt, only: phys_state, slp + 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, cam_model_const_properties + 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 ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t + 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 character(len=SHR_KIND_CL), intent(in) :: file_name @@ -260,7 +270,9 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, logical :: file_found logical :: is_first logical :: is_read + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name real(kind=kind_phys), pointer :: field_data_ptr(:,:,:) + type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) ! Initalize missing and non-initialized variables strings: missing_required_vars = ' ' @@ -299,25 +311,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, ! 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 + cycle 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: @@ -345,6 +339,29 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, end do !CCPP suites + ! Check constituent variables + field_data_ptr => cam_advected_constituents_array() + const_props => cam_model_const_properties() + + do constituent_idx = 1, size(const_props) + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == std_name)) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) 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), std_name, & + 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, [std_name], 'lev', timestep, field_data_ptr(:,:,constituent_idx), std_name, min_difference, min_relative_value, & + is_first) + end if + end do ! Close check file: call cam_pio_closefile(file) deallocate(file) 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 2dc7d3b9..ba66a2cf 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_num, 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, is_initialized use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use physics_types_ddt2, only: phys_state @@ -69,6 +69,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name ! Fields needed for getting default data value for constituents type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) @@ -133,51 +134,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default @@ -212,6 +169,58 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end do !CCPP suites + ! Read in constituent variables if not using init variables + field_data_ptr => cam_constituents_array() + const_props => cam_model_const_properties() + + ! Iterate over all registered constituents + do constituent_idx = 1, size(const_props) + var_found = .false. + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == trim(std_name))) then + ! Don't read the variable in if it's already initialized + if (is_initialized(std_name)) then + cycle + end if + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) then + const_input_idx = n + exit + end if + end do + call read_field(file, std_name, 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, std_name, [std_name], '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 + 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,*) 'Constituent ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + end if + end if + end if + end do + end subroutine physics_read_data subroutine physics_check_data(file_name, suite_names, timestep, min_difference, min_relative_value) @@ -219,7 +228,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, 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_ccpp_cap, only: ccpp_physics_suite_variables, cam_advected_constituents_array, cam_model_const_properties use cam_constituents, only: const_get_index use ccpp_kinds, only: kind_phys use cam_logfile, only: iulog @@ -227,6 +236,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 ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t 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 @@ -260,7 +270,9 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, logical :: file_found logical :: is_first logical :: is_read + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name real(kind=kind_phys), pointer :: field_data_ptr(:,:,:) + type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) ! Initalize missing and non-initialized variables strings: missing_required_vars = ' ' @@ -299,25 +311,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, ! 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 + cycle 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: @@ -345,6 +339,29 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, end do !CCPP suites + ! Check constituent variables + field_data_ptr => cam_advected_constituents_array() + const_props => cam_model_const_properties() + + do constituent_idx = 1, size(const_props) + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == std_name)) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) 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), std_name, & + 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, [std_name], 'lev', timestep, field_data_ptr(:,:,constituent_idx), std_name, min_difference, min_relative_value, & + is_first) + end if + end do ! Close check file: call cam_pio_closefile(file) deallocate(file) 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 620eceed..dd7140bb 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_num, 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, is_initialized 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 @@ -69,6 +69,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name ! Fields needed for getting default data value for constituents type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) @@ -133,51 +134,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default @@ -212,6 +169,58 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end do !CCPP suites + ! Read in constituent variables if not using init variables + field_data_ptr => cam_constituents_array() + const_props => cam_model_const_properties() + + ! Iterate over all registered constituents + do constituent_idx = 1, size(const_props) + var_found = .false. + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == trim(std_name))) then + ! Don't read the variable in if it's already initialized + if (is_initialized(std_name)) then + cycle + end if + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) then + const_input_idx = n + exit + end if + end do + call read_field(file, std_name, 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, std_name, [std_name], '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 + 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,*) 'Constituent ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + end if + end if + end if + end do + end subroutine physics_read_data subroutine physics_check_data(file_name, suite_names, timestep, min_difference, min_relative_value) @@ -219,7 +228,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, 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_ccpp_cap, only: ccpp_physics_suite_variables, cam_advected_constituents_array, cam_model_const_properties use cam_constituents, only: const_get_index use ccpp_kinds, only: kind_phys use cam_logfile, only: iulog @@ -227,6 +236,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 ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t 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 @@ -260,7 +270,9 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, logical :: file_found logical :: is_first logical :: is_read + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name real(kind=kind_phys), pointer :: field_data_ptr(:,:,:) + type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) ! Initalize missing and non-initialized variables strings: missing_required_vars = ' ' @@ -299,25 +311,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, ! 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 + cycle 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: @@ -345,6 +339,29 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, end do !CCPP suites + ! Check constituent variables + field_data_ptr => cam_advected_constituents_array() + const_props => cam_model_const_properties() + + do constituent_idx = 1, size(const_props) + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == std_name)) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) 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), std_name, & + 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, [std_name], 'lev', timestep, field_data_ptr(:,:,constituent_idx), std_name, min_difference, min_relative_value, & + is_first) + end if + end do ! Close check file: call cam_pio_closefile(file) deallocate(file) 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 34d18e84..484c4007 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_num, 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, is_initialized use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use physics_types_host_var, only: slp @@ -69,6 +69,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name ! Fields needed for getting default data value for constituents type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) @@ -133,51 +134,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default @@ -209,6 +166,58 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end do !CCPP suites + ! Read in constituent variables if not using init variables + field_data_ptr => cam_constituents_array() + const_props => cam_model_const_properties() + + ! Iterate over all registered constituents + do constituent_idx = 1, size(const_props) + var_found = .false. + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == trim(std_name))) then + ! Don't read the variable in if it's already initialized + if (is_initialized(std_name)) then + cycle + end if + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) then + const_input_idx = n + exit + end if + end do + call read_field(file, std_name, 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, std_name, [std_name], '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 + 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,*) 'Constituent ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + end if + end if + end if + end do + end subroutine physics_read_data subroutine physics_check_data(file_name, suite_names, timestep, min_difference, min_relative_value) @@ -216,7 +225,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, 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_ccpp_cap, only: ccpp_physics_suite_variables, cam_advected_constituents_array, cam_model_const_properties use cam_constituents, only: const_get_index use ccpp_kinds, only: kind_phys use cam_logfile, only: iulog @@ -224,6 +233,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 ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t 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 @@ -257,7 +267,9 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, logical :: file_found logical :: is_first logical :: is_read + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name real(kind=kind_phys), pointer :: field_data_ptr(:,:,:) + type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) ! Initalize missing and non-initialized variables strings: missing_required_vars = ' ' @@ -296,25 +308,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, ! 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 + cycle 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: @@ -338,6 +332,29 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, end do !CCPP suites + ! Check constituent variables + field_data_ptr => cam_advected_constituents_array() + const_props => cam_model_const_properties() + + do constituent_idx = 1, size(const_props) + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == std_name)) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) 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), std_name, & + 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, [std_name], 'lev', timestep, field_data_ptr(:,:,constituent_idx), std_name, min_difference, min_relative_value, & + is_first) + end if + end do ! Close check file: call cam_pio_closefile(file) deallocate(file) 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 868c512b..73667769 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_num, 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, is_initialized use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use ref_theta, only: theta @@ -70,6 +70,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name ! Fields needed for getting default data value for constituents type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) @@ -134,51 +135,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default @@ -213,24 +170,77 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end do !CCPP suites + ! Read in constituent variables if not using init variables + field_data_ptr => cam_constituents_array() + const_props => cam_model_const_properties() + + ! Iterate over all registered constituents + do constituent_idx = 1, size(const_props) + var_found = .false. + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == trim(std_name))) then + ! Don't read the variable in if it's already initialized + if (is_initialized(std_name)) then + cycle + end if + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) then + const_input_idx = n + exit + end if + end do + call read_field(file, std_name, 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, std_name, [std_name], '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 + 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,*) 'Constituent ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + end if + end if + end if + end do + 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_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 + 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, cam_model_const_properties + 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 ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t + 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 ! Dummy arguments character(len=SHR_KIND_CL), intent(in) :: file_name @@ -262,7 +272,9 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, logical :: file_found logical :: is_first logical :: is_read + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name real(kind=kind_phys), pointer :: field_data_ptr(:,:,:) + type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) ! Initalize missing and non-initialized variables strings: missing_required_vars = ' ' @@ -301,25 +313,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, ! 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 + cycle 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: @@ -347,6 +341,29 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, end do !CCPP suites + ! Check constituent variables + field_data_ptr => cam_advected_constituents_array() + const_props => cam_model_const_properties() + + do constituent_idx = 1, size(const_props) + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == std_name)) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) 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), std_name, & + 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, [std_name], 'lev', timestep, field_data_ptr(:,:,constituent_idx), std_name, min_difference, min_relative_value, & + is_first) + end if + end do ! Close check file: call cam_pio_closefile(file) deallocate(file) 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 96453a7f..c229e563 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_num, 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, is_initialized use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use physics_types_no_horiz, only: slp, theta @@ -69,6 +69,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name ! Fields needed for getting default data value for constituents type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) @@ -133,51 +134,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default @@ -212,6 +169,58 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end do !CCPP suites + ! Read in constituent variables if not using init variables + field_data_ptr => cam_constituents_array() + const_props => cam_model_const_properties() + + ! Iterate over all registered constituents + do constituent_idx = 1, size(const_props) + var_found = .false. + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == trim(std_name))) then + ! Don't read the variable in if it's already initialized + if (is_initialized(std_name)) then + cycle + end if + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) then + const_input_idx = n + exit + end if + end do + call read_field(file, std_name, 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, std_name, [std_name], '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 + 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,*) 'Constituent ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + end if + end if + end if + end do + end subroutine physics_read_data subroutine physics_check_data(file_name, suite_names, timestep, min_difference, min_relative_value) @@ -219,7 +228,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, 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_ccpp_cap, only: ccpp_physics_suite_variables, cam_advected_constituents_array, cam_model_const_properties use cam_constituents, only: const_get_index use ccpp_kinds, only: kind_phys use cam_logfile, only: iulog @@ -227,6 +236,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 ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t 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 @@ -260,7 +270,9 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, logical :: file_found logical :: is_first logical :: is_read + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name real(kind=kind_phys), pointer :: field_data_ptr(:,:,:) + type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) ! Initalize missing and non-initialized variables strings: missing_required_vars = ' ' @@ -299,25 +311,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, ! 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 + cycle 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: @@ -344,6 +338,29 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, end do !CCPP suites + ! Check constituent variables + field_data_ptr => cam_advected_constituents_array() + const_props => cam_model_const_properties() + + do constituent_idx = 1, size(const_props) + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == std_name)) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) 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), std_name, & + 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, [std_name], 'lev', timestep, field_data_ptr(:,:,constituent_idx), std_name, min_difference, min_relative_value, & + is_first) + end if + end do ! Close check file: call cam_pio_closefile(file) deallocate(file) 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 2d532a63..a1703efe 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_num, 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, is_initialized use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog @@ -68,6 +68,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name ! Fields needed for getting default data value for constituents type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) @@ -132,51 +133,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default @@ -205,6 +162,58 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end do !CCPP suites + ! Read in constituent variables if not using init variables + field_data_ptr => cam_constituents_array() + const_props => cam_model_const_properties() + + ! Iterate over all registered constituents + do constituent_idx = 1, size(const_props) + var_found = .false. + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == trim(std_name))) then + ! Don't read the variable in if it's already initialized + if (is_initialized(std_name)) then + cycle + end if + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) then + const_input_idx = n + exit + end if + end do + call read_field(file, std_name, 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, std_name, [std_name], '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 + 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,*) 'Constituent ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + end if + end if + end if + end do + end subroutine physics_read_data subroutine physics_check_data(file_name, suite_names, timestep, min_difference, min_relative_value) @@ -212,7 +221,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, 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_ccpp_cap, only: ccpp_physics_suite_variables, cam_advected_constituents_array, cam_model_const_properties use cam_constituents, only: const_get_index use ccpp_kinds, only: kind_phys use cam_logfile, only: iulog @@ -220,6 +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 ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use phys_vars_init_check_noreq, only: phys_var_num, phys_var_stdnames, input_var_names, std_name_len ! Dummy arguments @@ -252,7 +262,9 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, logical :: file_found logical :: is_first logical :: is_read + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name real(kind=kind_phys), pointer :: field_data_ptr(:,:,:) + type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) ! Initalize missing and non-initialized variables strings: missing_required_vars = ' ' @@ -291,25 +303,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, ! 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 + cycle 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: @@ -329,6 +323,29 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, end do !CCPP suites + ! Check constituent variables + field_data_ptr => cam_advected_constituents_array() + const_props => cam_model_const_properties() + + do constituent_idx = 1, size(const_props) + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == std_name)) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) 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), std_name, & + 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, [std_name], 'lev', timestep, field_data_ptr(:,:,constituent_idx), std_name, min_difference, min_relative_value, & + is_first) + end if + end do ! Close check file: call cam_pio_closefile(file) deallocate(file) 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 0136b24c..ab098ff6 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_num, 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, is_initialized use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use physics_types_param, only: g, slp, theta @@ -69,6 +69,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name ! Fields needed for getting default data value for constituents type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) @@ -133,51 +134,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default @@ -215,6 +172,58 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end do !CCPP suites + ! Read in constituent variables if not using init variables + field_data_ptr => cam_constituents_array() + const_props => cam_model_const_properties() + + ! Iterate over all registered constituents + do constituent_idx = 1, size(const_props) + var_found = .false. + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == trim(std_name))) then + ! Don't read the variable in if it's already initialized + if (is_initialized(std_name)) then + cycle + end if + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) then + const_input_idx = n + exit + end if + end do + call read_field(file, std_name, 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, std_name, [std_name], '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 + 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,*) 'Constituent ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + end if + end if + end if + end do + end subroutine physics_read_data subroutine physics_check_data(file_name, suite_names, timestep, min_difference, min_relative_value) @@ -222,7 +231,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, 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_ccpp_cap, only: ccpp_physics_suite_variables, cam_advected_constituents_array, cam_model_const_properties use cam_constituents, only: const_get_index use ccpp_kinds, only: kind_phys use cam_logfile, only: iulog @@ -230,6 +239,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 ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t 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 @@ -263,7 +273,9 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, logical :: file_found logical :: is_first logical :: is_read + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name real(kind=kind_phys), pointer :: field_data_ptr(:,:,:) + type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) ! Initalize missing and non-initialized variables strings: missing_required_vars = ' ' @@ -302,25 +314,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, ! 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 + cycle 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: @@ -351,6 +345,29 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, end do !CCPP suites + ! Check constituent variables + field_data_ptr => cam_advected_constituents_array() + const_props => cam_model_const_properties() + + do constituent_idx = 1, size(const_props) + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == std_name)) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) 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), std_name, & + 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, [std_name], 'lev', timestep, field_data_ptr(:,:,constituent_idx), std_name, min_difference, min_relative_value, & + is_first) + end if + end do ! Close check file: call cam_pio_closefile(file) deallocate(file) 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 b5c6e5f4..d0395c3a 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_num, 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, is_initialized use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use physics_types_protected, only: slp, theta @@ -69,6 +69,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name ! Fields needed for getting default data value for constituents type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) @@ -133,51 +134,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default @@ -212,6 +169,58 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end do !CCPP suites + ! Read in constituent variables if not using init variables + field_data_ptr => cam_constituents_array() + const_props => cam_model_const_properties() + + ! Iterate over all registered constituents + do constituent_idx = 1, size(const_props) + var_found = .false. + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == trim(std_name))) then + ! Don't read the variable in if it's already initialized + if (is_initialized(std_name)) then + cycle + end if + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) then + const_input_idx = n + exit + end if + end do + call read_field(file, std_name, 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, std_name, [std_name], '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 + 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,*) 'Constituent ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + end if + end if + end if + end do + end subroutine physics_read_data subroutine physics_check_data(file_name, suite_names, timestep, min_difference, min_relative_value) @@ -219,7 +228,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, 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_ccpp_cap, only: ccpp_physics_suite_variables, cam_advected_constituents_array, cam_model_const_properties use cam_constituents, only: const_get_index use ccpp_kinds, only: kind_phys use cam_logfile, only: iulog @@ -227,6 +236,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 ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t 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 @@ -260,7 +270,9 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, logical :: file_found logical :: is_first logical :: is_read + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name real(kind=kind_phys), pointer :: field_data_ptr(:,:,:) + type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) ! Initalize missing and non-initialized variables strings: missing_required_vars = ' ' @@ -299,25 +311,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, ! 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 + cycle 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: @@ -345,6 +339,29 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, end do !CCPP suites + ! Check constituent variables + field_data_ptr => cam_advected_constituents_array() + const_props => cam_model_const_properties() + + do constituent_idx = 1, size(const_props) + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == std_name)) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) 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), std_name, & + 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, [std_name], 'lev', timestep, field_data_ptr(:,:,constituent_idx), std_name, min_difference, min_relative_value, & + is_first) + end if + end do ! Close check file: call cam_pio_closefile(file) deallocate(file) 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 065fb36f..07ca4c12 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_num, 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, is_initialized use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use physics_types_scalar_var, only: slp, theta @@ -69,6 +69,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name ! Fields needed for getting default data value for constituents type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) @@ -133,51 +134,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default @@ -212,6 +169,58 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end do !CCPP suites + ! Read in constituent variables if not using init variables + field_data_ptr => cam_constituents_array() + const_props => cam_model_const_properties() + + ! Iterate over all registered constituents + do constituent_idx = 1, size(const_props) + var_found = .false. + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == trim(std_name))) then + ! Don't read the variable in if it's already initialized + if (is_initialized(std_name)) then + cycle + end if + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) then + const_input_idx = n + exit + end if + end do + call read_field(file, std_name, 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, std_name, [std_name], '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 + 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,*) 'Constituent ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + end if + end if + end if + end do + end subroutine physics_read_data subroutine physics_check_data(file_name, suite_names, timestep, min_difference, min_relative_value) @@ -219,7 +228,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, 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_ccpp_cap, only: ccpp_physics_suite_variables, cam_advected_constituents_array, cam_model_const_properties use cam_constituents, only: const_get_index use ccpp_kinds, only: kind_phys use cam_logfile, only: iulog @@ -227,6 +236,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 ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t 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 @@ -260,7 +270,9 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, logical :: file_found logical :: is_first logical :: is_read + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name real(kind=kind_phys), pointer :: field_data_ptr(:,:,:) + type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) ! Initalize missing and non-initialized variables strings: missing_required_vars = ' ' @@ -299,25 +311,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, ! 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 + cycle 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: @@ -344,6 +338,29 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, end do !CCPP suites + ! Check constituent variables + field_data_ptr => cam_advected_constituents_array() + const_props => cam_model_const_properties() + + do constituent_idx = 1, size(const_props) + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == std_name)) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) 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), std_name, & + 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, [std_name], 'lev', timestep, field_data_ptr(:,:,constituent_idx), std_name, min_difference, min_relative_value, & + is_first) + end if + end do ! Close check file: call cam_pio_closefile(file) deallocate(file) 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 f4eb298c..37e8cb6f 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_num, 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, is_initialized use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t use cam_logfile, only: iulog use physics_types_simple, only: slp, theta @@ -69,6 +69,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name ! Fields needed for getting default data value for constituents type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) @@ -133,51 +134,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default @@ -212,6 +169,58 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end do !CCPP suites + ! Read in constituent variables if not using init variables + field_data_ptr => cam_constituents_array() + const_props => cam_model_const_properties() + + ! Iterate over all registered constituents + do constituent_idx = 1, size(const_props) + var_found = .false. + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == trim(std_name))) then + ! Don't read the variable in if it's already initialized + if (is_initialized(std_name)) then + cycle + end if + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) then + const_input_idx = n + exit + end if + end do + call read_field(file, std_name, 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, std_name, [std_name], '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 + 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,*) 'Constituent ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + end if + end if + end if + end do + end subroutine physics_read_data subroutine physics_check_data(file_name, suite_names, timestep, min_difference, min_relative_value) @@ -219,7 +228,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, 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_ccpp_cap, only: ccpp_physics_suite_variables, cam_advected_constituents_array, cam_model_const_properties use cam_constituents, only: const_get_index use ccpp_kinds, only: kind_phys use cam_logfile, only: iulog @@ -227,6 +236,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 ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t 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 @@ -260,7 +270,9 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, logical :: file_found logical :: is_first logical :: is_read + character(len=std_name_len) :: std_name !Variable to hold constiutent standard name real(kind=kind_phys), pointer :: field_data_ptr(:,:,:) + type(ccpp_constituent_prop_ptr_t), pointer :: const_props(:) ! Initalize missing and non-initialized variables strings: missing_required_vars = ' ' @@ -299,25 +311,7 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, ! 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 + cycle 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: @@ -345,6 +339,29 @@ subroutine physics_check_data(file_name, suite_names, timestep, min_difference, end do !CCPP suites + ! Check constituent variables + field_data_ptr => cam_advected_constituents_array() + const_props => cam_model_const_properties() + + do constituent_idx = 1, size(const_props) + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == std_name)) then + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) 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), std_name, & + 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, [std_name], 'lev', timestep, field_data_ptr(:,:,constituent_idx), std_name, min_difference, min_relative_value, & + is_first) + end if + end do ! Close check file: call cam_pio_closefile(file) deallocate(file) diff --git a/test/unit/test_build_cache.py b/test/unit/test_build_cache.py index c3152367..cb9ad96c 100644 --- a/test/unit/test_build_cache.py +++ b/test/unit/test_build_cache.py @@ -425,9 +425,11 @@ def test_update_registry(self): ic_names = {"Only_had_a": ["heart", "brain"]} dycore = "banana" + constituents = ['cnst_1', 'cnst_2'] + #Update registry fields: test_cache.update_registry(tmp_test_reg, [tmp_test_reg], - dycore, [tmp_test_reg], ic_names) + dycore, [tmp_test_reg], ic_names, constituents) #Write updated fields to build cache file: test_cache.write() diff --git a/test/unit/test_cam_autogen.py b/test/unit/test_cam_autogen.py index 58f54daa..4a786aab 100644 --- a/test/unit/test_cam_autogen.py +++ b/test/unit/test_cam_autogen.py @@ -158,6 +158,10 @@ def ic_names(self): return {} + def constituents(self): + """Fake version of 'constituents' property.""" + return [] + # pylint: enable=no-self-use # pylint: enable=unused-argument @@ -515,7 +519,7 @@ def test_generate_registry(self): test_data_search = [os.path.join(_CAM_ROOT_DIR, "src", "data")] #Set expected output tuple: - expected_results = (f'{self.test_bldroot}'+os.sep+'cam_registry', False, [], {}) + expected_results = (f'{self.test_bldroot}'+os.sep+'cam_registry', False, [], {}, []) #Run registry generation function: gen_results = generate_registry(test_data_search, self.test_cache, _CAM_ROOT_DIR, @@ -670,7 +674,7 @@ def test_generate_init_routines(self): #Run init routines generation function: gen_path = generate_init_routines(self.test_cache, self.test_bldroot, False, False, - self.test_src_mods_dir, self.fort_indent, None, {}) + self.test_src_mods_dir, self.fort_indent, None, {}, []) #Check that the output path matches what is expected: self.assertEqual(gen_path, expected_path) diff --git a/test/unit/test_registry.py b/test/unit/test_registry.py index 98d0a232..fcb19d04 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) @@ -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) diff --git a/test/unit/test_write_init_files.py b/test/unit/test_write_init_files.py index 86351216..1150192e 100644 --- a/test/unit/test_write_init_files.py +++ b/test/unit/test_write_init_files.py @@ -175,7 +175,7 @@ def test_simple_reg_write_init(self): cap_database = capgen(run_env, return_db=True) # Generate physics initialization files: - retmsg = write_init.write_init_files(cap_database, {}, _TMP_DIR, + retmsg = write_init.write_init_files(cap_database, {}, [], _TMP_DIR, find_file, _INC_SEARCH_DIRS, 3, logger, phys_check_filename=vic_name, @@ -238,7 +238,7 @@ def test_simple_reg_constituent_write_init(self): check_init_out, phys_input_out]) # Generate registry files: - _, _, ic_names = gen_registry(filename, 'se', _TMP_DIR, 3, + _, _, ic_names, constituents = gen_registry(filename, 'se', _TMP_DIR, 3, _SRC_MOD_DIR, _CAM_ROOT, loglevel=logging.ERROR, error_on_no_validate=True) @@ -258,7 +258,7 @@ def test_simple_reg_constituent_write_init(self): cap_database = capgen(run_env, return_db=True) # Generate physics initialization files: - retmsg = write_init.write_init_files(cap_database, ic_names, _TMP_DIR, + retmsg = write_init.write_init_files(cap_database, ic_names, constituents, _TMP_DIR, find_file, _INC_SEARCH_DIRS, 3, logger, phys_check_filename=vic_name, @@ -340,7 +340,7 @@ def test_no_reqvar_write_init(self): cap_database = capgen(run_env, return_db=True) # Generate physics initialization files: - retmsg = write_init.write_init_files(cap_database, {}, _TMP_DIR, + retmsg = write_init.write_init_files(cap_database, {}, [], _TMP_DIR, find_file, _INC_SEARCH_DIRS, 3, logger, phys_check_filename=vic_name, @@ -403,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) @@ -423,7 +423,7 @@ def test_protected_reg_write_init(self): cap_database = capgen(run_env, return_db=True) # Generate physics initialization files: - retmsg = write_init.write_init_files(cap_database, {}, _TMP_DIR, + retmsg = write_init.write_init_files(cap_database, {}, [], _TMP_DIR, find_file, _INC_SEARCH_DIRS, 3, logger, phys_check_filename=vic_name, @@ -507,7 +507,7 @@ def test_host_input_var_write_init(self): cap_database = capgen(run_env, return_db=True) # Generate physics initialization files: - retmsg = write_init.write_init_files(cap_database, {}, _TMP_DIR, + retmsg = write_init.write_init_files(cap_database, {}, [], _TMP_DIR, find_file, _INC_SEARCH_DIRS, 3, logger, phys_check_filename=vic_name, @@ -572,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) @@ -592,7 +592,7 @@ def test_no_horiz_var_write_init(self): cap_database = capgen(run_env, return_db=True) # Run test - _ = write_init.write_init_files(cap_database, {}, _TMP_DIR, + _ = write_init.write_init_files(cap_database, {}, [], _TMP_DIR, find_file, _INC_SEARCH_DIRS, 3, logger, phys_check_filename=vic_name, @@ -647,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) @@ -667,7 +667,7 @@ def test_scalar_var_write_init(self): cap_database = capgen(run_env, return_db=True) # Run test - _ = write_init.write_init_files(cap_database, {}, _TMP_DIR, + _ = write_init.write_init_files(cap_database, {}, [], _TMP_DIR, find_file, _INC_SEARCH_DIRS, 3, logger, phys_check_filename=vic_name, @@ -722,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) @@ -741,7 +741,7 @@ def test_4d_var_write_init(self): cap_database = capgen(run_env, return_db=True) # Run test - retmsg = write_init.write_init_files(cap_database, {}, _TMP_DIR, + retmsg = write_init.write_init_files(cap_database, {}, [], _TMP_DIR, find_file, _INC_SEARCH_DIRS, 3, logger, phys_check_filename=vic_name, @@ -815,7 +815,7 @@ def test_ddt_reg_write_init(self): cap_database = capgen(run_env, return_db=True) # Generate physics initialization files: - retmsg = write_init.write_init_files(cap_database, {}, _TMP_DIR, + retmsg = write_init.write_init_files(cap_database, {}, [], _TMP_DIR, find_file, _INC_SEARCH_DIRS, 3, logger, phys_check_filename=vic_name, @@ -878,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) @@ -897,7 +897,7 @@ def test_ddt2_reg_write_init(self): cap_database = capgen(run_env, return_db=True) # Generate physics initialization files: - retmsg = write_init.write_init_files(cap_database, {}, _TMP_DIR, + retmsg = write_init.write_init_files(cap_database, {}, [], _TMP_DIR, find_file, _INC_SEARCH_DIRS, 3, logger, phys_check_filename=vic_name, @@ -978,7 +978,7 @@ def test_ddt_array_reg_write_init(self): cap_database = capgen(run_env, return_db=True) # Generate physics initialization files: - retmsg = write_init.write_init_files(cap_database, {}, _TMP_DIR, + retmsg = write_init.write_init_files(cap_database, {}, [], _TMP_DIR, find_file, _INC_SEARCH_DIRS, 3, logger, phys_check_filename=vic_name, @@ -1059,7 +1059,7 @@ def test_meta_file_reg_write_init(self): cap_database = capgen(run_env, return_db=True) # Generate physics initialization files: - retmsg = write_init.write_init_files(cap_database, {}, _TMP_DIR, + retmsg = write_init.write_init_files(cap_database, {}, [], _TMP_DIR, find_file, _INC_SEARCH_DIRS, 3, logger, phys_check_filename=vic_name, @@ -1140,7 +1140,7 @@ def test_parameter_reg_write_init(self): cap_database = capgen(run_env, return_db=True) # Generate physics initialization files: - retmsg = write_init.write_init_files(cap_database, {}, _TMP_DIR, + retmsg = write_init.write_init_files(cap_database, {}, [], _TMP_DIR, find_file, _INC_SEARCH_DIRS, 3, logger, phys_check_filename=vic_name, @@ -1224,7 +1224,7 @@ def test_bad_vertical_dimension(self): cap_database = capgen(run_env, return_db=True) # Run test - retmsg = write_init.write_init_files(cap_database, {}, _TMP_DIR, + retmsg = write_init.write_init_files(cap_database, {}, [], _TMP_DIR, find_file, _INC_SEARCH_DIRS, 3, logger, phys_check_filename=vic_name, From 28becd1e95ab0277c4736d9cbc50428fd6e88f03 Mon Sep 17 00:00:00 2001 From: Courtney Peverley Date: Thu, 19 Sep 2024 19:11:41 -0600 Subject: [PATCH 06/19] clarify variable name --- cime_config/cam_autogen.py | 12 ++++++------ cime_config/cam_config.py | 4 ++-- src/data/generate_registry_data.py | 4 ++-- src/data/write_init_files.py | 28 ++++++++++++++-------------- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/cime_config/cam_autogen.py b/cime_config/cam_autogen.py index e5d7b32d..7cc1d9f1 100644 --- a/cime_config/cam_autogen.py +++ b/cime_config/cam_autogen.py @@ -392,7 +392,7 @@ def generate_registry(data_search, build_cache, atm_root, bldroot, gen_fort_indent, source_mods_dir, atm_root, logger=_LOGGER, schema_paths=data_search, error_on_no_validate=True) - retcode, reg_file_list, ic_names, constituents = retvals + retcode, reg_file_list, ic_names, registry_constituents = retvals # Raise error if gen_registry failed: if retcode != 0: emsg = "ERROR:Unable to generate CAM data structures from {}, err = {}" @@ -406,15 +406,15 @@ 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_file_paths, ic_names, constituents) + reg_file_paths, ic_names, registry_constituents) else: # If we did not run the registry generator, retrieve info from cache reg_file_paths = build_cache.reg_file_list() ic_names = build_cache.ic_names() - constituents = build_cache.constituents() + registry_constituents = build_cache.constituents() # End if - return genreg_dir, do_gen_registry, reg_file_paths, ic_names, constituents + return genreg_dir, do_gen_registry, reg_file_paths, ic_names, registry_constituents ############################################################################### def generate_physics_suites(build_cache, preproc_defs, host_name, @@ -630,7 +630,7 @@ def generate_physics_suites(build_cache, preproc_defs, host_name, ############################################################################### def generate_init_routines(build_cache, bldroot, force_ccpp, force_init, source_mods_dir, gen_fort_indent, - cap_database, ic_names, constituents): + cap_database, ic_names, registry_constituents): ############################################################################### """ Generate the host model initialization source code files @@ -668,7 +668,7 @@ def generate_init_routines(build_cache, bldroot, force_ccpp, force_init, # within write_init_files (so that write_init_files can be the place # where the source include files are stored). source_paths = [source_mods_dir, _REG_GEN_DIR] - retmsg = write_init_files(cap_database, ic_names, constituents, + retmsg = write_init_files(cap_database, ic_names, registry_constituents, init_dir, _find_file, source_paths, gen_fort_indent, _LOGGER) diff --git a/cime_config/cam_config.py b/cime_config/cam_config.py index d2a5fcb6..afb298a9 100644 --- a/cime_config/cam_config.py +++ b/cime_config/cam_config.py @@ -838,7 +838,7 @@ def generate_cam_src(self, gen_fort_indent): retvals = generate_registry(data_search, build_cache, self.__atm_root, self.__bldroot, source_mods_dir, dyn, gen_fort_indent) - reg_dir, force_ccpp, reg_files, ic_names, constituents = retvals + reg_dir, force_ccpp, reg_files, ic_names, registry_constituents = retvals #Add registry path to config object: reg_dir_desc = "Location of auto-generated registry code." @@ -871,7 +871,7 @@ def generate_cam_src(self, gen_fort_indent): init_dir = generate_init_routines(build_cache, self.__bldroot, force_ccpp, force_init, source_mods_dir, gen_fort_indent, - capgen_db, ic_names, constituents) + capgen_db, ic_names, registry_constituents) #Add registry path to config object: init_dir_desc = "Location of auto-generated physics initialization code." diff --git a/src/data/generate_registry_data.py b/src/data/generate_registry_data.py index 022c176f..79c2ff5a 100755 --- a/src/data/generate_registry_data.py +++ b/src/data/generate_registry_data.py @@ -1837,10 +1837,10 @@ def gen_registry(registry_file, dycore, outdir, indent, src_root, reg_dir, indent, logger) # See comment in _create_ic_name_dict ic_names = _create_ic_name_dict(registry) - constituents = _create_constituent_list(registry) + registry_constituents = _create_constituent_list(registry) retcode = 0 # Throw exception on error # end if - return retcode, files, ic_names, constituents + return retcode, files, ic_names, registry_constituents def main(): """Function to execute when module called as a script""" diff --git a/src/data/write_init_files.py b/src/data/write_init_files.py index 6bf443f0..500787ab 100644 --- a/src/data/write_init_files.py +++ b/src/data/write_init_files.py @@ -46,7 +46,7 @@ #Main function ############## -def write_init_files(cap_database, ic_names, constituents, outdir, +def write_init_files(cap_database, ic_names, registry_constituents, outdir, file_find_func, source_paths, indent, logger, phys_check_filename=None, phys_input_filename=None): @@ -130,7 +130,7 @@ def write_init_files(cap_database, ic_names, constituents, outdir, # Gather all the host model variables that are required by # any of the compiled CCPP physics suites. - host_vars, constituent_set, retmsg = gather_ccpp_req_vars(cap_database, constituents) + host_vars, constituent_set, retmsg = gather_ccpp_req_vars(cap_database, registry_constituents) # Quit now if there are missing variables if retmsg: @@ -173,12 +173,12 @@ def write_init_files(cap_database, ic_names, constituents, outdir, # end for # Write public parameters: - retvals = write_ic_params(outfile, host_vars, ic_names, constituents) + retvals = write_ic_params(outfile, host_vars, ic_names, registry_constituents) ic_names, ic_max_len, stdname_max_len = retvals # Write initial condition arrays: write_ic_arrays(outfile, ic_names, ic_max_len, - stdname_max_len, host_vars, constituents) + stdname_max_len, host_vars, registry_constituents) # Add "contains" statement: outfile.end_module_header() @@ -244,7 +244,7 @@ def write_init_files(cap_database, ic_names, constituents, outdir, # Write physics_check_data subroutine: write_phys_check_subroutine(outfile, host_dict, host_vars, host_imports, - phys_check_fname_str, constituent_set, constituents) + phys_check_fname_str, constituent_set) # -------------------------------------- @@ -358,7 +358,7 @@ def gather_ccpp_req_vars(cap_database, registry_constituents): #FORTRAN WRITING FUNCTIONS ########################## -def write_ic_params(outfile, host_vars, ic_names, constituents): +def write_ic_params(outfile, host_vars, ic_names, registry_constituents): """ Write public parameter declarations needed @@ -369,7 +369,7 @@ def write_ic_params(outfile, host_vars, ic_names, constituents): #Create new Fortran integer parameter to store total number of variables: outfile.comment("Total number of physics-related variables:", 1) - num_pvars = len(host_vars) + len(constituents) + num_pvars = len(host_vars) + len(registry_constituents) outfile.write(f"integer, public, parameter :: phys_var_num = {num_pvars}", 1) num_cvars = len(_EXCLUDED_STDNAMES) @@ -418,7 +418,7 @@ def write_ic_params(outfile, host_vars, ic_names, constituents): ###### def write_ic_arrays(outfile, ic_name_dict, ic_max_len, - stdname_max_len, host_vars, constituents): + stdname_max_len, host_vars, registry_constituents): """ Write initial condition arrays to store @@ -427,7 +427,7 @@ def write_ic_arrays(outfile, ic_name_dict, ic_max_len, """ #Create variable name array string lists: - num_input_vars = len(host_vars) + len(constituents) + num_input_vars = len(host_vars) + len(registry_constituents) stdname_strs = [] ic_name_strs = [] @@ -444,7 +444,7 @@ def write_ic_arrays(outfile, ic_name_dict, ic_max_len, # for each variable with the proper length, : for hvar in host_vars: var_stdname = hvar.get_prop_value('standard_name') - if var_stdname in constituents: + if var_stdname in registry_constituents: # skip registry constituents; we'll tackle these after continue # end if @@ -469,7 +469,7 @@ def write_ic_arrays(outfile, ic_name_dict, ic_max_len, # end for # Add any constituent variables: - for const in constituents: + for const in registry_constituents: stdname_strs.append(f"'{const: <{stdname_max_len}}'") #Extract input (IC) names list: @@ -573,7 +573,7 @@ def write_ic_arrays(outfile, ic_name_dict, ic_max_len, #Write line to file: outfile.write(log_arr_str, 2) # end for - for var_num, var_name in enumerate(constituents): + for var_num, var_name in enumerate(registry_constituents): # If at the end of the list, then update suffix: if var_num == num_input_vars-len(host_vars)-1: arr_suffix = ' /)' @@ -612,7 +612,7 @@ def write_ic_arrays(outfile, ic_name_dict, ic_max_len, #Write line to file: outfile.write(log_arr_str, 2) # end for - for var_num, varname in enumerate(constituents): + for var_num, varname in enumerate(registry_constituents): #If at the end of the list, then update suffix: if var_num == num_input_vars-len(host_vars)-1: arr_suffix = ' /)' @@ -1141,7 +1141,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, constituent_set, constituents): + phys_check_fname_str, constituent_set): """ Write the "physics_check_data" subroutine, which From 75cdffbdf84c4b3542758cf089ff4e76d5366e6a Mon Sep 17 00:00:00 2001 From: Courtney Peverley Date: Thu, 19 Sep 2024 19:24:27 -0600 Subject: [PATCH 07/19] fix bug from copied code --- src/data/write_init_files.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/write_init_files.py b/src/data/write_init_files.py index 500787ab..5957a63d 100644 --- a/src/data/write_init_files.py +++ b/src/data/write_init_files.py @@ -1119,12 +1119,12 @@ def write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports, outfile.write("end if", 5) outfile.write("field_data_ptr(:,:,constituent_idx) = constituent_default_value", 5) outfile.write("if (masterproc) then", 5) - outfile.write("write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' initialized to default value: ', constituent_default_value", 6) + outfile.write("write(iulog,*) 'Constituent ', trim(std_name), ' initialized to default value: ', constituent_default_value", 6) outfile.write("end if", 5) outfile.write("else", 4) outfile.write("field_data_ptr(:,:,constituent_idx) = 0._kind_phys", 5) outfile.write("if (masterproc) then", 5) - outfile.write("write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.'", 6) + outfile.write("write(iulog,*) 'Constituent ', trim(std_name), ' default value not configured. Setting to 0.'", 6) outfile.write("end if", 5) outfile.write("end if", 4) outfile.write("end if", 3) From 006f41214d7c264ed8a735163c38e09f4548d330 Mon Sep 17 00:00:00 2001 From: Courtney Peverley Date: Thu, 19 Sep 2024 23:27:46 -0600 Subject: [PATCH 08/19] fix unit tests --- test/unit/sample_files/write_init_files/physics_inputs_4D.F90 | 4 ++-- .../unit/sample_files/write_init_files/physics_inputs_bvd.F90 | 4 ++-- .../sample_files/write_init_files/physics_inputs_cnst.F90 | 4 ++-- .../unit/sample_files/write_init_files/physics_inputs_ddt.F90 | 4 ++-- .../sample_files/write_init_files/physics_inputs_ddt2.F90 | 4 ++-- .../write_init_files/physics_inputs_ddt_array.F90 | 4 ++-- .../sample_files/write_init_files/physics_inputs_host_var.F90 | 4 ++-- test/unit/sample_files/write_init_files/physics_inputs_mf.F90 | 4 ++-- .../sample_files/write_init_files/physics_inputs_no_horiz.F90 | 4 ++-- .../sample_files/write_init_files/physics_inputs_noreq.F90 | 4 ++-- .../sample_files/write_init_files/physics_inputs_param.F90 | 4 ++-- .../sample_files/write_init_files/physics_inputs_protect.F90 | 4 ++-- .../sample_files/write_init_files/physics_inputs_scalar.F90 | 4 ++-- .../sample_files/write_init_files/physics_inputs_simple.F90 | 4 ++-- 14 files changed, 28 insertions(+), 28 deletions(-) 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 fcb3802a..e8476971 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 @@ -210,12 +210,12 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end if field_data_ptr(:,:,constituent_idx) = constituent_default_value if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' initialized to default value: ', constituent_default_value + write(iulog,*) 'Constituent ', trim(std_name), ' initialized to default value: ', constituent_default_value end if else field_data_ptr(:,:,constituent_idx) = 0._kind_phys if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + write(iulog,*) 'Constituent ', trim(std_name), ' default value not configured. Setting to 0.' end if end if end if 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 5bf9cf29..976c8981 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 @@ -210,12 +210,12 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end if field_data_ptr(:,:,constituent_idx) = constituent_default_value if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' initialized to default value: ', constituent_default_value + write(iulog,*) 'Constituent ', trim(std_name), ' initialized to default value: ', constituent_default_value end if else field_data_ptr(:,:,constituent_idx) = 0._kind_phys if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + write(iulog,*) 'Constituent ', trim(std_name), ' default value not configured. Setting to 0.' end if end if end if 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 index 7c830ac2..dbd43ff8 100644 --- a/test/unit/sample_files/write_init_files/physics_inputs_cnst.F90 +++ b/test/unit/sample_files/write_init_files/physics_inputs_cnst.F90 @@ -210,12 +210,12 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end if field_data_ptr(:,:,constituent_idx) = constituent_default_value if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' initialized to default value: ', constituent_default_value + write(iulog,*) 'Constituent ', trim(std_name), ' initialized to default value: ', constituent_default_value end if else field_data_ptr(:,:,constituent_idx) = 0._kind_phys if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + write(iulog,*) 'Constituent ', trim(std_name), ' default value not configured. Setting to 0.' end if end if end if 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 1810ede6..126b459c 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 @@ -210,12 +210,12 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end if field_data_ptr(:,:,constituent_idx) = constituent_default_value if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' initialized to default value: ', constituent_default_value + write(iulog,*) 'Constituent ', trim(std_name), ' initialized to default value: ', constituent_default_value end if else field_data_ptr(:,:,constituent_idx) = 0._kind_phys if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + write(iulog,*) 'Constituent ', trim(std_name), ' default value not configured. Setting to 0.' end if end if end if 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 ba66a2cf..90ccfb50 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 @@ -210,12 +210,12 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end if field_data_ptr(:,:,constituent_idx) = constituent_default_value if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' initialized to default value: ', constituent_default_value + write(iulog,*) 'Constituent ', trim(std_name), ' initialized to default value: ', constituent_default_value end if else field_data_ptr(:,:,constituent_idx) = 0._kind_phys if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + write(iulog,*) 'Constituent ', trim(std_name), ' default value not configured. Setting to 0.' end if end if end if 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 dd7140bb..5aa6eead 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 @@ -210,12 +210,12 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end if field_data_ptr(:,:,constituent_idx) = constituent_default_value if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' initialized to default value: ', constituent_default_value + write(iulog,*) 'Constituent ', trim(std_name), ' initialized to default value: ', constituent_default_value end if else field_data_ptr(:,:,constituent_idx) = 0._kind_phys if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + write(iulog,*) 'Constituent ', trim(std_name), ' default value not configured. Setting to 0.' end if end if end if 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 484c4007..c63724fc 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 @@ -207,12 +207,12 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end if field_data_ptr(:,:,constituent_idx) = constituent_default_value if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' initialized to default value: ', constituent_default_value + write(iulog,*) 'Constituent ', trim(std_name), ' initialized to default value: ', constituent_default_value end if else field_data_ptr(:,:,constituent_idx) = 0._kind_phys if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + write(iulog,*) 'Constituent ', trim(std_name), ' default value not configured. Setting to 0.' end if end if end if 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 73667769..862bdd95 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 @@ -211,12 +211,12 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end if field_data_ptr(:,:,constituent_idx) = constituent_default_value if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' initialized to default value: ', constituent_default_value + write(iulog,*) 'Constituent ', trim(std_name), ' initialized to default value: ', constituent_default_value end if else field_data_ptr(:,:,constituent_idx) = 0._kind_phys if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + write(iulog,*) 'Constituent ', trim(std_name), ' default value not configured. Setting to 0.' end if end if end if 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 c229e563..ae3fed69 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 @@ -210,12 +210,12 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end if field_data_ptr(:,:,constituent_idx) = constituent_default_value if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' initialized to default value: ', constituent_default_value + write(iulog,*) 'Constituent ', trim(std_name), ' initialized to default value: ', constituent_default_value end if else field_data_ptr(:,:,constituent_idx) = 0._kind_phys if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + write(iulog,*) 'Constituent ', trim(std_name), ' default value not configured. Setting to 0.' end if end if end if 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 a1703efe..56327041 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 @@ -203,12 +203,12 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end if field_data_ptr(:,:,constituent_idx) = constituent_default_value if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' initialized to default value: ', constituent_default_value + write(iulog,*) 'Constituent ', trim(std_name), ' initialized to default value: ', constituent_default_value end if else field_data_ptr(:,:,constituent_idx) = 0._kind_phys if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + write(iulog,*) 'Constituent ', trim(std_name), ' default value not configured. Setting to 0.' end if end if end if 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 ab098ff6..2052b72b 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 @@ -213,12 +213,12 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end if field_data_ptr(:,:,constituent_idx) = constituent_default_value if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' initialized to default value: ', constituent_default_value + write(iulog,*) 'Constituent ', trim(std_name), ' initialized to default value: ', constituent_default_value end if else field_data_ptr(:,:,constituent_idx) = 0._kind_phys if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + write(iulog,*) 'Constituent ', trim(std_name), ' default value not configured. Setting to 0.' end if end if end if 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 d0395c3a..91eeaf8b 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 @@ -210,12 +210,12 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end if field_data_ptr(:,:,constituent_idx) = constituent_default_value if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' initialized to default value: ', constituent_default_value + write(iulog,*) 'Constituent ', trim(std_name), ' initialized to default value: ', constituent_default_value end if else field_data_ptr(:,:,constituent_idx) = 0._kind_phys if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + write(iulog,*) 'Constituent ', trim(std_name), ' default value not configured. Setting to 0.' end if end if end if 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 07ca4c12..9b1333f7 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 @@ -210,12 +210,12 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end if field_data_ptr(:,:,constituent_idx) = constituent_default_value if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' initialized to default value: ', constituent_default_value + write(iulog,*) 'Constituent ', trim(std_name), ' initialized to default value: ', constituent_default_value end if else field_data_ptr(:,:,constituent_idx) = 0._kind_phys if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + write(iulog,*) 'Constituent ', trim(std_name), ' default value not configured. Setting to 0.' end if end if end if 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 37e8cb6f..e0473e59 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 @@ -210,12 +210,12 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia end if field_data_ptr(:,:,constituent_idx) = constituent_default_value if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' initialized to default value: ', constituent_default_value + write(iulog,*) 'Constituent ', trim(std_name), ' initialized to default value: ', constituent_default_value end if else field_data_ptr(:,:,constituent_idx) = 0._kind_phys if (masterproc) then - write(iulog,*) 'Constituent ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' + write(iulog,*) 'Constituent ', trim(std_name), ' default value not configured. Setting to 0.' end if end if end if From 6bfe67a6edd20d2a30f464484b83ca77b8a0e81e Mon Sep 17 00:00:00 2001 From: Cheryl Craig Date: Mon, 23 Sep 2024 09:30:39 -0600 Subject: [PATCH 09/19] Update registry for ZM --- src/data/registry.xml | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/data/registry.xml b/src/data/registry.xml index 8699911f..93a8bf99 100644 --- a/src/data/registry.xml +++ b/src/data/registry.xml @@ -451,12 +451,6 @@ horizontal_dimension vertical_layer_dimension ICWMRDP pbuf_ICWMRDP - - horizontal_dimension vertical_layer_dimension - + units="index" type="integer" + access="protected" > 1 horizontal_dimension vertical_layer_dimension - - Date: Wed, 25 Sep 2024 14:32:31 -0600 Subject: [PATCH 10/19] fix air composition standard names; add more water species to registry --- src/data/air_composition.F90 | 6 +++--- src/data/registry.xml | 12 ++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/data/air_composition.F90 b/src/data/air_composition.F90 index f202ae97..e84fc837 100644 --- a/src/data/air_composition.F90 +++ b/src/data/air_composition.F90 @@ -346,8 +346,8 @@ subroutine air_composition_init() ! ! CLDICE ! - case('cloud_ice_water_mixing_ratio_wrt_moist_air_and_condensed_water') - call air_species_info('cloud_ice_water_mixing_ratio_wrt_moist_air_and_condensed_water', & + case('cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water') + call air_species_info('cloud_ice_mixing_ratio_wrt_moist_air_and_condensed_water', & ix, mw) thermodynamic_active_species_idx(icnst) = ix thermodynamic_active_species_cp (icnst) = cpice @@ -408,7 +408,7 @@ subroutine air_composition_init() ! ! GRAUQM ! - case('graupel_water_mixing_ratio_wrt_moist_air_and_conedensed_water') + case('graupel_water_mixing_ratio_wrt_moist_air_and_condensed_water') call air_species_info('graupel_water_mixing_ratio_wrt_moist_air_and_condensed_water', & ix, mw) thermodynamic_active_species_idx(icnst) = ix diff --git a/src/data/registry.xml b/src/data/registry.xml index 57a9ae3b..e22dabf5 100644 --- a/src/data/registry.xml +++ b/src/data/registry.xml @@ -406,5 +406,17 @@ rain mass mixing ratio with respect to moist air plus all airborne condensates RAINQM cnst_RAINQM + + snow mass mixing ratio with respect to moist air plus all airborne condensates + SNOWQM cnst_SNOWQM + + + graupel mass mixing ratio with respect to moist air plus all airborne condensates + GRAUQM cnst_GRAUQM + From 30656a2d40df47bb99e19e0f1970e469abd93542 Mon Sep 17 00:00:00 2001 From: Cheryl Craig Date: Fri, 27 Sep 2024 14:22:33 -0600 Subject: [PATCH 11/19] fix missing line from merge conflict --- src/data/registry.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/data/registry.xml b/src/data/registry.xml index afe7bd05..86dac801 100644 --- a/src/data/registry.xml +++ b/src/data/registry.xml @@ -426,6 +426,7 @@ units="kg kg-1" type="real" constituent="true"> graupel mass mixing ratio with respect to moist air plus all airborne condensates GRAUQM cnst_GRAUQM + Date: Fri, 3 Jan 2025 13:07:36 -0700 Subject: [PATCH 12/19] Update unit test sample files --- .../write_init_files/physics_inputs_4D.F90 | 46 +------ .../write_init_files/physics_inputs_bvd.F90 | 46 +------ .../write_init_files/physics_inputs_cnst.F90 | 46 +------ .../write_init_files/physics_inputs_ddt.F90 | 46 +------ .../write_init_files/physics_inputs_ddt2.F90 | 46 +------ .../physics_inputs_ddt_array.F90 | 46 +------ .../physics_inputs_host_var.F90 | 115 +++++++----------- .../write_init_files/physics_inputs_mf.F90 | 46 +------ .../physics_inputs_no_horiz.F90 | 46 +------ .../physics_inputs_protect.F90 | 46 +------ .../physics_inputs_scalar.F90 | 46 +------ .../physics_inputs_simple.F90 | 46 +------ 12 files changed, 58 insertions(+), 563 deletions(-) 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 1869cf3c..f7b78f09 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 @@ -135,51 +135,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default 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 fdcf7480..de773cc5 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 @@ -135,51 +135,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default 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 index 2b969403..b7897809 100644 --- a/test/unit/sample_files/write_init_files/physics_inputs_cnst.F90 +++ b/test/unit/sample_files/write_init_files/physics_inputs_cnst.F90 @@ -135,51 +135,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default 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 4a247156..db732939 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 @@ -135,51 +135,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default 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 c3d04837..ad60820f 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 @@ -135,51 +135,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default 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 44535731..0f6795c3 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 @@ -135,51 +135,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default 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 50d2181d..e15415d8 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 @@ -171,76 +171,55 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia field_data_ptr => cam_constituents_array() const_props => cam_model_const_properties() - ! 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 ', trim(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 ', trim(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 ('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)) + ! Iterate over all registered constituents + do constituent_idx = 1, size(const_props) + var_found = .false. + ! Check if constituent standard name in registered SIMA standard names list: + call const_props(constituent_idx)%standard_name(std_name) + if(any(phys_var_stdnames == trim(std_name))) then + ! Don't read the variable in if it's already initialized + if (is_initialized(std_name)) then + cycle + end if + ! Find array index to extract correct input names: + do n=1, phys_var_num + if(trim(phys_var_stdnames(n)) == trim(std_name)) then + const_input_idx = n + exit + end if + end do + call read_field(file, std_name, 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, std_name, [std_name], 'lev', timestep, field_data_ptr(:,:,constituent_idx), mark_as_read=.false., & + error_on_not_found=.false., var_found=var_found) 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)) + if(.not. var_found) then + 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,*) 'Constituent ', trim(std_name), ' initialized to default value: ', constituent_default_value + end if + else + ! Intialize to constituent's configured minimum value + call const_props(constituent_idx)%minimum(constituent_min_value, constituent_errflg, constituent_errmsg) + field_data_ptr(:,:,constituent_idx) = constituent_min_value + if (masterproc) then + write(iulog,*) 'Constituent ', trim(std_name), ' default value not configured. Setting to 0.' + end if + end if end if - - ! Deallocate required variables array for use in next suite: - deallocate(ccpp_required_data) - - end do !CCPP suites + end do end subroutine physics_read_data 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 bb3ba43a..88b30b1a 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 @@ -136,51 +136,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default 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 d2f81150..2b76aaa3 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 @@ -135,51 +135,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default 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 406f8da0..ffdaa70b 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 @@ -135,51 +135,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default 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 efc0d190..99602499 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 @@ -135,51 +135,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default 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 0cad0c2c..737614df 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 @@ -135,51 +135,7 @@ subroutine physics_read_data(file, suite_names, timestep, read_initialized_varia 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 ', trim(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 ', trim(ccpp_required_data(req_idx)), ' default value not configured. Setting to 0.' - end if - end if - end if + ! If an index was found in the constituent hash table, then do nothing, this will be handled later case default From c33eb21181ec841957f0b0bddb6b11a03c5cce16 Mon Sep 17 00:00:00 2001 From: Cheryl Craig Date: Mon, 6 Jan 2025 16:16:08 -0700 Subject: [PATCH 13/19] Fix cloud_area_fraction conflict --- src/data/registry.xml | 1 + src/physics/utils/musica_ccpp_dependencies.F90 | 8 +------- src/physics/utils/musica_ccpp_dependencies.meta | 6 ------ 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/data/registry.xml b/src/data/registry.xml index 4faa74db..b44fde3b 100644 --- a/src/data/registry.xml +++ b/src/data/registry.xml @@ -533,6 +533,7 @@ units="fraction" type="real" kind="kind_phys" allocatable="allocatable"> horizontal_dimension vertical_layer_dimension + 0.7_kind_phys CLD pbuf_CLD Date: Mon, 27 Jan 2025 16:01:09 -0700 Subject: [PATCH 14/19] Address reviewer comments --- .gitmodules | 2 +- cime_config/testdefs/testlist_cam.xml | 9 +++++++++ src/data/ref_pres.meta | 4 ++-- src/data/registry.xml | 4 ++-- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.gitmodules b/.gitmodules index ae8c3a76..ff98f992 100644 --- a/.gitmodules +++ b/.gitmodules @@ -20,7 +20,7 @@ [submodule "ncar-physics"] path = src/physics/ncar_ccpp url = https://github.com/ESCOMP/atmospheric_physics - fxtag = 74e905b7a0ee5b2d2bfc3e3dd942eb9963398373 + fxtag = atmos_phys0_08_000 fxrequired = AlwaysRequired fxDONOTUSEurl = https://github.com/ESCOMP/atmospheric_physics [submodule "ccs_config"] diff --git a/cime_config/testdefs/testlist_cam.xml b/cime_config/testdefs/testlist_cam.xml index 316e8e74..28eaa1cb 100644 --- a/cime_config/testdefs/testlist_cam.xml +++ b/cime_config/testdefs/testlist_cam.xml @@ -43,6 +43,15 @@ + + + + + + + + + diff --git a/src/data/ref_pres.meta b/src/data/ref_pres.meta index 1caf116f..bf95e6c8 100644 --- a/src/data/ref_pres.meta +++ b/src/data/ref_pres.meta @@ -35,7 +35,7 @@ dimensions = () protected = True [ trop_cloud_top_lev ] - standard_name = index_of_pressure_at_troposphere_cloud_top + standard_name = vertical_layer_index_of_troposphere_cloud_top units = index type = integer dimensions = () @@ -65,7 +65,7 @@ dimensions = () protected = True [ nbot_molec ] - standard_name = index_of_pressure_at_bottom_of_molecular_diffusion + standard_name = vertical_layer_index_at_bottom_of_molecular_diffusion units = index type = integer dimensions = () diff --git a/src/data/registry.xml b/src/data/registry.xml index b44fde3b..443740c0 100644 --- a/src/data/registry.xml +++ b/src/data/registry.xml @@ -521,7 +521,7 @@ horizontal_dimension tpert pbuf_tpert - @@ -548,7 +548,7 @@ access="protected" > 1 - From 74b935d3317309fc7b4973c708ef6d7e8cf0b008 Mon Sep 17 00:00:00 2001 From: mwaxmonsky <137746677+mwaxmonsky@users.noreply.github.com> Date: Tue, 11 Feb 2025 12:10:53 -0500 Subject: [PATCH 15/19] Initial pFUnit Integration (#326) Tag name (required for release branches): Originator(s): @mwaxmonsky Description (include the issue title, and the keyword ['closes', 'fixes', 'resolves'] followed by the issue number): Describe any changes made to build system: None Describe any changes made to the namelist: None List any changes to the defaults for the input datasets (e.g. boundary datasets): None List all files eliminated and why: None List all files added and what they do: A .github/workflows/fortran_unit_tests.yml - Initial workflow file to support unit testing in CI A src/core_utils/CMakeLists.txt A test/unit-fortran/CMakeLists.txt A test/unit-fortran/src/core_utils/CMakeLists.txt - Initial unit test build infrastructure. A src/core_utils/string_core_utils.F90 A test/unit-fortran/src/core_utils/test_string_core_utils.pf - Refactored string utils and unit tests without dependencies List all existing files that have been modified, and describe the changes: (Helpful git command: `git diff --name-status development...`) R085 test/run_unit_tests.sh test/run_python_unit_tests.sh R100 test/unit/.coveragerc test/unit/python/.coveragerc R100 test/unit/sample_files/atm_in_files/test_attr_in test/unit/python/sample_files/atm_in_files/test_attr_in R100 test/unit/sample_files/atm_in_files/test_cmplx_array_atm_in test/unit/python/sample_files/atm_in_files/test_cmplx_array_atm_in R100 test/unit/sample_files/atm_in_files/test_extra_nml_def.xml test/unit/python/sample_files/atm_in_files/test_extra_nml_def.xml R100 test/unit/sample_files/atm_in_files/test_extra_nml_same_group.xml test/unit/python/sample_files/atm_in_files/test_extra_nml_same_group.xml R100 test/unit/sample_files/atm_in_files/test_extra_nml_same_var.xml test/unit/python/sample_files/atm_in_files/test_extra_nml_same_var.xml R100 test/unit/sample_files/atm_in_files/test_missing_elems.xml test/unit/python/sample_files/atm_in_files/test_missing_elems.xml R100 test/unit/sample_files/atm_in_files/test_multi_attr_in test/unit/python/sample_files/atm_in_files/test_multi_attr_in R100 test/unit/sample_files/atm_in_files/test_multi_xml_in test/unit/python/sample_files/atm_in_files/test_multi_xml_in R100 test/unit/sample_files/atm_in_files/test_nl_duplicate_atm_in test/unit/python/sample_files/atm_in_files/test_nl_duplicate_atm_in R100 test/unit/sample_files/atm_in_files/test_simple_atm_in test/unit/python/sample_files/atm_in_files/test_simple_atm_in R100 test/unit/sample_files/atm_in_files/test_simple_nml_def.xml test/unit/python/sample_files/atm_in_files/test_simple_nml_def.xml R100 test/unit/sample_files/atm_in_files/test_third_nml_def.xml test/unit/python/sample_files/atm_in_files/test_third_nml_def.xml R100 test/unit/sample_files/atm_in_files/test_user_in test/unit/python/sample_files/atm_in_files/test_user_in R100 test/unit/sample_files/atm_in_files/test_user_nl_allow_dupl_var test/unit/python/sample_files/atm_in_files/test_user_nl_allow_dupl_var R100 test/unit/sample_files/atm_in_files/test_user_nl_bad_equals test/unit/python/sample_files/atm_in_files/test_user_nl_bad_equals R100 test/unit/sample_files/atm_in_files/test_user_nl_dupl_var test/unit/python/sample_files/atm_in_files/test_user_nl_dupl_var R100 test/unit/sample_files/atm_in_files/test_user_nl_no_equals test/unit/python/sample_files/atm_in_files/test_user_nl_no_equals R100 test/unit/sample_files/atm_in_files/test_user_nl_simple test/unit/python/sample_files/atm_in_files/test_user_nl_simple R100 test/unit/sample_files/atm_in_files/test_user_nl_undefined_var test/unit/python/sample_files/atm_in_files/test_user_nl_undefined_var R100 test/unit/sample_files/autogen_files/two_scheme_banana.F90 test/unit/python/sample_files/autogen_files/two_scheme_banana.F90 R100 test/unit/sample_files/autogen_files/two_scheme_banana.meta test/unit/python/sample_files/autogen_files/two_scheme_banana.meta R100 test/unit/sample_files/autogen_files/two_scheme_banana_namelist.xml test/unit/python/sample_files/autogen_files/two_scheme_banana_namelist.xml R100 test/unit/sample_files/banana_namelist.xml test/unit/python/sample_files/banana_namelist.xml R100 test/unit/sample_files/build_cache_files/bad_ccpp_tag_build_cache.xml test/unit/python/sample_files/build_cache_files/bad_ccpp_tag_build_cache.xml R100 test/unit/sample_files/build_cache_files/bad_reg_tag_build_cache.xml test/unit/python/sample_files/build_cache_files/bad_reg_tag_build_cache.xml R100 test/unit/sample_files/build_cache_files/bad_section_tag_build_cache.xml test/unit/python/sample_files/build_cache_files/bad_section_tag_build_cache.xml R100 test/unit/sample_files/build_cache_files/example_build_cache.xml test/unit/python/sample_files/build_cache_files/example_build_cache.xml R100 test/unit/sample_files/build_cache_files/update_ccpp_build_cache.xml test/unit/python/sample_files/build_cache_files/update_ccpp_build_cache.xml R100 test/unit/sample_files/build_cache_files/update_init_gen_build_cache.xml test/unit/python/sample_files/build_cache_files/update_init_gen_build_cache.xml R100 test/unit/sample_files/build_cache_files/update_reg_build_cache.xml test/unit/python/sample_files/build_cache_files/update_reg_build_cache.xml R100 test/unit/sample_files/hist_config_files/amwg_hist_config test/unit/python/sample_files/hist_config_files/amwg_hist_config R100 test/unit/sample_files/hist_config_files/atm_in_flat test/unit/python/sample_files/hist_config_files/atm_in_flat R100 test/unit/sample_files/hist_config_files/atm_in_multi test/unit/python/sample_files/hist_config_files/atm_in_multi R100 test/unit/sample_files/hist_config_files/rad_config test/unit/python/sample_files/hist_config_files/rad_config R100 test/unit/sample_files/hist_config_files/user_nl_cam_flat test/unit/python/sample_files/hist_config_files/user_nl_cam_flat R100 test/unit/sample_files/hist_config_files/user_nl_cam_multi test/unit/python/sample_files/hist_config_files/user_nl_cam_multi R100 test/unit/sample_files/kumquat_namelist.xml test/unit/python/sample_files/kumquat_namelist.xml R100 test/unit/sample_files/namelist_files/banana_namelist.F90 test/unit/python/sample_files/namelist_files/banana_namelist.F90 R100 test/unit/sample_files/namelist_files/banana_namelist.meta test/unit/python/sample_files/namelist_files/banana_namelist.meta R100 test/unit/sample_files/namelist_files/cam_ccpp_scheme_namelists_double_def.F90 test/unit/python/sample_files/namelist_files/cam_ccpp_scheme_namelists_double_def.F90 R100 test/unit/sample_files/namelist_files/cam_ccpp_scheme_namelists_single_def.F90 test/unit/python/sample_files/namelist_files/cam_ccpp_scheme_namelists_single_def.F90 R100 test/unit/sample_files/namelist_files/kumquat_namelist.F90 test/unit/python/sample_files/namelist_files/kumquat_namelist.F90 R100 test/unit/sample_files/namelist_files/kumquat_namelist.meta test/unit/python/sample_files/namelist_files/kumquat_namelist.meta R100 test/unit/sample_files/phys_types_dup_section.meta test/unit/python/sample_files/phys_types_dup_section.meta R100 test/unit/sample_files/phys_types_no_table.meta test/unit/python/sample_files/phys_types_no_table.meta R100 test/unit/sample_files/physics_types_complete.F90 test/unit/python/sample_files/physics_types_complete.F90 R100 test/unit/sample_files/physics_types_complete.meta test/unit/python/sample_files/physics_types_complete.meta R100 test/unit/sample_files/physics_types_ddt2.F90 test/unit/python/sample_files/physics_types_ddt2.F90 R100 test/unit/sample_files/physics_types_ddt2.meta test/unit/python/sample_files/physics_types_ddt2.meta R100 test/unit/sample_files/physics_types_ddt_array.F90 test/unit/python/sample_files/physics_types_ddt_array.F90 R100 test/unit/sample_files/physics_types_ddt_array.meta test/unit/python/sample_files/physics_types_ddt_array.meta R100 test/unit/sample_files/physics_types_ddt_eul.F90 test/unit/python/sample_files/physics_types_ddt_eul.F90 R100 test/unit/sample_files/physics_types_ddt_eul.meta test/unit/python/sample_files/physics_types_ddt_eul.meta R100 test/unit/sample_files/physics_types_ddt_fv.F90 test/unit/python/sample_files/physics_types_ddt_fv.F90 R100 test/unit/sample_files/physics_types_ddt_fv.meta test/unit/python/sample_files/physics_types_ddt_fv.meta R100 test/unit/sample_files/physics_types_ddt_se.F90 test/unit/python/sample_files/physics_types_ddt_se.F90 R100 test/unit/sample_files/physics_types_ddt_se.meta test/unit/python/sample_files/physics_types_ddt_se.meta R100 test/unit/sample_files/physics_types_parameter.F90 test/unit/python/sample_files/physics_types_parameter.F90 R100 test/unit/sample_files/physics_types_parameter.meta test/unit/python/sample_files/physics_types_parameter.meta R100 test/unit/sample_files/physics_types_simple.F90 test/unit/python/sample_files/physics_types_simple.F90 R100 test/unit/sample_files/physics_types_simple.meta test/unit/python/sample_files/physics_types_simple.meta R100 test/unit/sample_files/ref_pres.meta test/unit/python/sample_files/ref_pres.meta R100 test/unit/sample_files/ref_pres_SourceMods.meta test/unit/python/sample_files/ref_pres_SourceMods.meta R098 test/unit/sample_files/reg_bad_xml.xml test/unit/python/sample_files/reg_bad_xml.xml R098 test/unit/sample_files/reg_good_complete.xml test/unit/python/sample_files/reg_good_complete.xml R100 test/unit/sample_files/reg_good_ddt.xml test/unit/python/sample_files/reg_good_ddt.xml R100 test/unit/sample_files/reg_good_ddt2.xml test/unit/python/sample_files/reg_good_ddt2.xml R100 test/unit/sample_files/reg_good_ddt_array.xml test/unit/python/sample_files/reg_good_ddt_array.xml R096 test/unit/sample_files/reg_good_mf.xml test/unit/python/sample_files/reg_good_mf.xml R100 test/unit/sample_files/reg_good_simple.xml test/unit/python/sample_files/reg_good_simple.xml R100 test/unit/sample_files/rotten_namelist.xml test/unit/python/sample_files/rotten_namelist.xml R100 test/unit/sample_files/write_init_files/ddt2_reg.xml test/unit/python/sample_files/write_init_files/ddt2_reg.xml R100 test/unit/sample_files/write_init_files/ddt_array_reg.xml test/unit/python/sample_files/write_init_files/ddt_array_reg.xml R100 test/unit/sample_files/write_init_files/ddt_reg.xml test/unit/python/sample_files/write_init_files/ddt_reg.xml R100 test/unit/sample_files/write_init_files/host_var_host.F90 test/unit/python/sample_files/write_init_files/host_var_host.F90 R100 test/unit/sample_files/write_init_files/host_var_host.meta test/unit/python/sample_files/write_init_files/host_var_host.meta R100 test/unit/sample_files/write_init_files/host_var_reg.xml test/unit/python/sample_files/write_init_files/host_var_reg.xml R088 test/unit/sample_files/write_init_files/mf_reg.xml test/unit/python/sample_files/write_init_files/mf_reg.xml R100 test/unit/sample_files/write_init_files/missing_ICs_reg.xml test/unit/python/sample_files/write_init_files/missing_ICs_reg.xml R100 test/unit/sample_files/write_init_files/no_horiz_dim_reg.xml test/unit/python/sample_files/write_init_files/no_horiz_dim_reg.xml R100 test/unit/sample_files/write_init_files/no_req_var_reg.xml test/unit/python/sample_files/write_init_files/no_req_var_reg.xml R100 test/unit/sample_files/write_init_files/param_reg.xml test/unit/python/sample_files/write_init_files/param_reg.xml R100 test/unit/sample_files/write_init_files/phys_vars_init_check_4D.F90 test/unit/python/sample_files/write_init_files/phys_vars_init_check_4D.F90 R100 test/unit/sample_files/write_init_files/phys_vars_init_check_bvd.F90 test/unit/python/sample_files/write_init_files/phys_vars_init_check_bvd.F90 R100 test/unit/sample_files/write_init_files/phys_vars_init_check_cnst.F90 test/unit/python/sample_files/write_init_files/phys_vars_init_check_cnst.F90 R100 test/unit/sample_files/write_init_files/phys_vars_init_check_ddt.F90 test/unit/python/sample_files/write_init_files/phys_vars_init_check_ddt.F90 R100 test/unit/sample_files/write_init_files/phys_vars_init_check_ddt2.F90 test/unit/python/sample_files/write_init_files/phys_vars_init_check_ddt2.F90 R100 test/unit/sample_files/write_init_files/phys_vars_init_check_ddt_array.F90 test/unit/python/sample_files/write_init_files/phys_vars_init_check_ddt_array.F90 R100 test/unit/sample_files/write_init_files/phys_vars_init_check_host_var.F90 test/unit/python/sample_files/write_init_files/phys_vars_init_check_host_var.F90 R100 test/unit/sample_files/write_init_files/phys_vars_init_check_mf.F90 test/unit/python/sample_files/write_init_files/phys_vars_init_check_mf.F90 R100 test/unit/sample_files/write_init_files/phys_vars_init_check_no_horiz.F90 test/unit/python/sample_files/write_init_files/phys_vars_init_check_no_horiz.F90 R100 test/unit/sample_files/write_init_files/phys_vars_init_check_noreq.F90 test/unit/python/sample_files/write_init_files/phys_vars_init_check_noreq.F90 R100 test/unit/sample_files/write_init_files/phys_vars_init_check_param.F90 test/unit/python/sample_files/write_init_files/phys_vars_init_check_param.F90 R100 test/unit/sample_files/write_init_files/phys_vars_init_check_parameter.F90 test/unit/python/sample_files/write_init_files/phys_vars_init_check_parameter.F90 R100 test/unit/sample_files/write_init_files/phys_vars_init_check_protect.F90 test/unit/python/sample_files/write_init_files/phys_vars_init_check_protect.F90 R100 test/unit/sample_files/write_init_files/phys_vars_init_check_scalar.F90 test/unit/python/sample_files/write_init_files/phys_vars_init_check_scalar.F90 R100 test/unit/sample_files/write_init_files/phys_vars_init_check_simple.F90 test/unit/python/sample_files/write_init_files/phys_vars_init_check_simple.F90 R100 test/unit/sample_files/write_init_files/physics_inputs_4D.F90 test/unit/python/sample_files/write_init_files/physics_inputs_4D.F90 R100 test/unit/sample_files/write_init_files/physics_inputs_bvd.F90 test/unit/python/sample_files/write_init_files/physics_inputs_bvd.F90 R100 test/unit/sample_files/write_init_files/physics_inputs_cnst.F90 test/unit/python/sample_files/write_init_files/physics_inputs_cnst.F90 R100 test/unit/sample_files/write_init_files/physics_inputs_ddt.F90 test/unit/python/sample_files/write_init_files/physics_inputs_ddt.F90 R100 test/unit/sample_files/write_init_files/physics_inputs_ddt2.F90 test/unit/python/sample_files/write_init_files/physics_inputs_ddt2.F90 R100 test/unit/sample_files/write_init_files/physics_inputs_ddt_array.F90 test/unit/python/sample_files/write_init_files/physics_inputs_ddt_array.F90 R100 test/unit/sample_files/write_init_files/physics_inputs_host_var.F90 test/unit/python/sample_files/write_init_files/physics_inputs_host_var.F90 R100 test/unit/sample_files/write_init_files/physics_inputs_mf.F90 test/unit/python/sample_files/write_init_files/physics_inputs_mf.F90 R100 test/unit/sample_files/write_init_files/physics_inputs_no_horiz.F90 test/unit/python/sample_files/write_init_files/physics_inputs_no_horiz.F90 R100 test/unit/sample_files/write_init_files/physics_inputs_noreq.F90 test/unit/python/sample_files/write_init_files/physics_inputs_noreq.F90 R100 test/unit/sample_files/write_init_files/physics_inputs_param.F90 test/unit/python/sample_files/write_init_files/physics_inputs_param.F90 R100 test/unit/sample_files/write_init_files/physics_inputs_parameter.F90 test/unit/python/sample_files/write_init_files/physics_inputs_parameter.F90 R100 test/unit/sample_files/write_init_files/physics_inputs_protect.F90 test/unit/python/sample_files/write_init_files/physics_inputs_protect.F90 R100 test/unit/sample_files/write_init_files/physics_inputs_scalar.F90 test/unit/python/sample_files/write_init_files/physics_inputs_scalar.F90 R100 test/unit/sample_files/write_init_files/physics_inputs_simple.F90 test/unit/python/sample_files/write_init_files/physics_inputs_simple.F90 R100 test/unit/sample_files/write_init_files/protected_reg.xml test/unit/python/sample_files/write_init_files/protected_reg.xml R100 test/unit/sample_files/write_init_files/ref_theta.F90 test/unit/python/sample_files/write_init_files/ref_theta.F90 R100 test/unit/sample_files/write_init_files/ref_theta.meta test/unit/python/sample_files/write_init_files/ref_theta.meta R100 test/unit/sample_files/write_init_files/ref_two.F90 test/unit/python/sample_files/write_init_files/ref_two.F90 R100 test/unit/sample_files/write_init_files/ref_two.meta test/unit/python/sample_files/write_init_files/ref_two.meta R100 test/unit/sample_files/write_init_files/scalar_var_reg.xml test/unit/python/sample_files/write_init_files/scalar_var_reg.xml R100 test/unit/sample_files/write_init_files/simple_build_cache_template.xml test/unit/python/sample_files/write_init_files/simple_build_cache_template.xml R100 test/unit/sample_files/write_init_files/simple_host.F90 test/unit/python/sample_files/write_init_files/simple_host.F90 R100 test/unit/sample_files/write_init_files/simple_host.meta test/unit/python/sample_files/write_init_files/simple_host.meta R100 test/unit/sample_files/write_init_files/simple_reg.xml test/unit/python/sample_files/write_init_files/simple_reg.xml R100 test/unit/sample_files/write_init_files/suite_simple.xml test/unit/python/sample_files/write_init_files/suite_simple.xml R100 test/unit/sample_files/write_init_files/temp_adjust.F90 test/unit/python/sample_files/write_init_files/temp_adjust.F90 R100 test/unit/sample_files/write_init_files/temp_adjust.meta test/unit/python/sample_files/write_init_files/temp_adjust.meta R100 test/unit/sample_files/write_init_files/temp_adjust_4D.F90 test/unit/python/sample_files/write_init_files/temp_adjust_4D.F90 R100 test/unit/sample_files/write_init_files/temp_adjust_4D.meta test/unit/python/sample_files/write_init_files/temp_adjust_4D.meta R100 test/unit/sample_files/write_init_files/temp_adjust_bvd.F90 test/unit/python/sample_files/write_init_files/temp_adjust_bvd.F90 R100 test/unit/sample_files/write_init_files/temp_adjust_bvd.meta test/unit/python/sample_files/write_init_files/temp_adjust_bvd.meta R100 test/unit/sample_files/write_init_files/temp_adjust_cnst.F90 test/unit/python/sample_files/write_init_files/temp_adjust_cnst.F90 R100 test/unit/sample_files/write_init_files/temp_adjust_cnst.meta test/unit/python/sample_files/write_init_files/temp_adjust_cnst.meta R100 test/unit/sample_files/write_init_files/temp_adjust_no_horiz.F90 test/unit/python/sample_files/write_init_files/temp_adjust_no_horiz.F90 R100 test/unit/sample_files/write_init_files/temp_adjust_no_horiz.meta test/unit/python/sample_files/write_init_files/temp_adjust_no_horiz.meta R100 test/unit/sample_files/write_init_files/temp_adjust_noreq.F90 test/unit/python/sample_files/write_init_files/temp_adjust_noreq.F90 R100 test/unit/sample_files/write_init_files/temp_adjust_noreq.meta test/unit/python/sample_files/write_init_files/temp_adjust_noreq.meta R100 test/unit/sample_files/write_init_files/temp_adjust_param.F90 test/unit/python/sample_files/write_init_files/temp_adjust_param.F90 R100 test/unit/sample_files/write_init_files/temp_adjust_param.meta test/unit/python/sample_files/write_init_files/temp_adjust_param.meta R100 test/unit/sample_files/write_init_files/temp_adjust_scalar.F90 test/unit/python/sample_files/write_init_files/temp_adjust_scalar.F90 R100 test/unit/sample_files/write_init_files/temp_adjust_scalar.meta test/unit/python/sample_files/write_init_files/temp_adjust_scalar.meta R100 test/unit/sample_files/write_init_files/theta_ddt.F90 test/unit/python/sample_files/write_init_files/theta_ddt.F90 R100 test/unit/sample_files/write_init_files/theta_ddt.meta test/unit/python/sample_files/write_init_files/theta_ddt.meta R100 test/unit/sample_files/write_init_files/var_4D_reg.xml test/unit/python/sample_files/write_init_files/var_4D_reg.xml R100 test/unit/sample_files/write_init_files/var_bad_vertdim.xml test/unit/python/sample_files/write_init_files/var_bad_vertdim.xml R099 test/unit/test_atm_in_paramgen.py test/unit/python/test_atm_in_paramgen.py R099 test/unit/test_build_cache.py test/unit/python/test_build_cache.py R099 test/unit/test_cam_autogen.py test/unit/python/test_cam_autogen.py R099 test/unit/test_cam_config.py test/unit/python/test_cam_config.py R098 test/unit/test_create_readnl_files.py test/unit/python/test_create_readnl_files.py R099 test/unit/test_hist_config.py test/unit/python/test_hist_config.py R099 test/unit/test_registry.py test/unit/python/test_registry.py R099 test/unit/test_write_init_files.py test/unit/python/test_write_init_files.py - Moved python tests and associated files from top level test directory to python specific directory to allow other language based tests. M src/utils/string_utils.F90 - Removed unused code (`last_sig_char`, `lower_to_upper`, `upper_to_lower`, `last_index`, and `increment_string`), made formatting consistent, and refactored portable string util code to core equivalent so this layer handles non-portable code and then calls core util code. M .github/workflows/python_unit_tests.yml M .gitignore M cime_config/cam_autogen.py - Updated python test paths to new directory. M cime_config/buildlib - Adding `core_utils` directory to list of source directories. If there are new failures (compared to the `test/existing-test-failures.txt` file), have them OK'd by the gatekeeper, note them here, and add them to the file. If there are baseline differences, include the test and the reason for the diff. What is the nature of the change? Roundoff? derecho/intel/aux_sima: derecho/gnu/aux_sima: If this changes climate describe any run(s) done to evaluate the new climate in enough detail that it(they) could be reproduced: CAM-SIMA date used for the baseline comparison tests if different than latest: --- .github/workflows/fortran_unit_tests.yml | 73 ++++ .github/workflows/python_unit_tests.yml | 7 +- .gitignore | 2 +- cime_config/buildlib | 3 +- cime_config/cam_autogen.py | 2 +- src/core_utils/CMakeLists.txt | 9 + src/core_utils/string_core_utils.F90 | 162 ++++++++ src/utils/string_utils.F90 | 384 ++---------------- ...unit_tests.sh => run_python_unit_tests.sh} | 16 +- test/unit/fortran/CMakeLists.txt | 32 ++ .../fortran/src/core_utils/CMakeLists.txt | 3 + .../src/core_utils/test_string_core_utils.pf | 287 +++++++++++++ test/unit/{ => python}/.coveragerc | 0 .../sample_files/atm_in_files/test_attr_in | 0 .../atm_in_files/test_cmplx_array_atm_in | 0 .../atm_in_files/test_extra_nml_def.xml | 0 .../test_extra_nml_same_group.xml | 0 .../atm_in_files/test_extra_nml_same_var.xml | 0 .../atm_in_files/test_missing_elems.xml | 0 .../atm_in_files/test_multi_attr_in | 0 .../atm_in_files/test_multi_xml_in | 0 .../atm_in_files/test_nl_duplicate_atm_in | 0 .../atm_in_files/test_simple_atm_in | 0 .../atm_in_files/test_simple_nml_def.xml | 0 .../atm_in_files/test_third_nml_def.xml | 0 .../sample_files/atm_in_files/test_user_in | 0 .../atm_in_files/test_user_nl_allow_dupl_var | 0 .../atm_in_files/test_user_nl_bad_equals | 0 .../atm_in_files/test_user_nl_dupl_var | 0 .../atm_in_files/test_user_nl_no_equals | 0 .../atm_in_files/test_user_nl_simple | 0 .../atm_in_files/test_user_nl_undefined_var | 0 .../autogen_files/two_scheme_banana.F90 | 0 .../autogen_files/two_scheme_banana.meta | 0 .../two_scheme_banana_namelist.xml | 0 .../sample_files/banana_namelist.xml | 0 .../bad_ccpp_tag_build_cache.xml | 0 .../bad_reg_tag_build_cache.xml | 0 .../bad_section_tag_build_cache.xml | 0 .../build_cache_files/example_build_cache.xml | 0 .../update_ccpp_build_cache.xml | 0 .../update_init_gen_build_cache.xml | 0 .../update_reg_build_cache.xml | 0 .../hist_config_files/amwg_hist_config | 0 .../hist_config_files/atm_in_flat | 0 .../hist_config_files/atm_in_multi | 0 .../sample_files/hist_config_files/rad_config | 0 .../hist_config_files/user_nl_cam_flat | 0 .../hist_config_files/user_nl_cam_multi | 0 .../sample_files/kumquat_namelist.xml | 0 .../namelist_files/banana_namelist.F90 | 0 .../namelist_files/banana_namelist.meta | 0 .../cam_ccpp_scheme_namelists_double_def.F90 | 0 .../cam_ccpp_scheme_namelists_single_def.F90 | 0 .../namelist_files/kumquat_namelist.F90 | 0 .../namelist_files/kumquat_namelist.meta | 0 .../sample_files/phys_types_dup_section.meta | 0 .../sample_files/phys_types_no_table.meta | 0 .../sample_files/physics_types_complete.F90 | 0 .../sample_files/physics_types_complete.meta | 0 .../sample_files/physics_types_ddt2.F90 | 0 .../sample_files/physics_types_ddt2.meta | 0 .../sample_files/physics_types_ddt_array.F90 | 0 .../sample_files/physics_types_ddt_array.meta | 0 .../sample_files/physics_types_ddt_eul.F90 | 0 .../sample_files/physics_types_ddt_eul.meta | 0 .../sample_files/physics_types_ddt_fv.F90 | 0 .../sample_files/physics_types_ddt_fv.meta | 0 .../sample_files/physics_types_ddt_se.F90 | 0 .../sample_files/physics_types_ddt_se.meta | 0 .../sample_files/physics_types_parameter.F90 | 0 .../sample_files/physics_types_parameter.meta | 0 .../sample_files/physics_types_simple.F90 | 0 .../sample_files/physics_types_simple.meta | 0 .../{ => python}/sample_files/ref_pres.meta | 0 .../sample_files/ref_pres_SourceMods.meta | 0 .../{ => python}/sample_files/reg_bad_xml.xml | 2 +- .../sample_files/reg_good_complete.xml | 2 +- .../sample_files/reg_good_ddt.xml | 0 .../sample_files/reg_good_ddt2.xml | 0 .../sample_files/reg_good_ddt_array.xml | 0 .../{ => python}/sample_files/reg_good_mf.xml | 2 +- .../sample_files/reg_good_simple.xml | 0 .../sample_files/rotten_namelist.xml | 0 .../write_init_files/ddt2_reg.xml | 0 .../write_init_files/ddt_array_reg.xml | 0 .../sample_files/write_init_files/ddt_reg.xml | 0 .../write_init_files/host_var_host.F90 | 0 .../write_init_files/host_var_host.meta | 0 .../write_init_files/host_var_reg.xml | 0 .../sample_files/write_init_files/mf_reg.xml | 2 +- .../write_init_files/missing_ICs_reg.xml | 0 .../write_init_files/no_horiz_dim_reg.xml | 0 .../write_init_files/no_req_var_reg.xml | 0 .../write_init_files/param_reg.xml | 0 .../phys_vars_init_check_4D.F90 | 0 .../phys_vars_init_check_bvd.F90 | 0 .../phys_vars_init_check_cnst.F90 | 0 .../phys_vars_init_check_ddt.F90 | 0 .../phys_vars_init_check_ddt2.F90 | 0 .../phys_vars_init_check_ddt_array.F90 | 0 .../phys_vars_init_check_host_var.F90 | 0 .../phys_vars_init_check_mf.F90 | 0 .../phys_vars_init_check_no_horiz.F90 | 0 .../phys_vars_init_check_noreq.F90 | 0 .../phys_vars_init_check_param.F90 | 0 .../phys_vars_init_check_parameter.F90 | 0 .../phys_vars_init_check_protect.F90 | 0 .../phys_vars_init_check_scalar.F90 | 0 .../phys_vars_init_check_simple.F90 | 0 .../write_init_files/physics_inputs_4D.F90 | 0 .../write_init_files/physics_inputs_bvd.F90 | 0 .../write_init_files/physics_inputs_cnst.F90 | 0 .../write_init_files/physics_inputs_ddt.F90 | 0 .../write_init_files/physics_inputs_ddt2.F90 | 0 .../physics_inputs_ddt_array.F90 | 0 .../physics_inputs_host_var.F90 | 0 .../write_init_files/physics_inputs_mf.F90 | 0 .../physics_inputs_no_horiz.F90 | 0 .../write_init_files/physics_inputs_noreq.F90 | 0 .../write_init_files/physics_inputs_param.F90 | 0 .../physics_inputs_parameter.F90 | 0 .../physics_inputs_protect.F90 | 0 .../physics_inputs_scalar.F90 | 0 .../physics_inputs_simple.F90 | 0 .../write_init_files/protected_reg.xml | 0 .../write_init_files/ref_theta.F90 | 0 .../write_init_files/ref_theta.meta | 0 .../sample_files/write_init_files/ref_two.F90 | 0 .../write_init_files/ref_two.meta | 0 .../write_init_files/scalar_var_reg.xml | 0 .../simple_build_cache_template.xml | 0 .../write_init_files/simple_host.F90 | 0 .../write_init_files/simple_host.meta | 0 .../write_init_files/simple_reg.xml | 0 .../write_init_files/suite_simple.xml | 0 .../write_init_files/temp_adjust.F90 | 0 .../write_init_files/temp_adjust.meta | 0 .../write_init_files/temp_adjust_4D.F90 | 0 .../write_init_files/temp_adjust_4D.meta | 0 .../write_init_files/temp_adjust_bvd.F90 | 0 .../write_init_files/temp_adjust_bvd.meta | 0 .../write_init_files/temp_adjust_cnst.F90 | 0 .../write_init_files/temp_adjust_cnst.meta | 0 .../write_init_files/temp_adjust_no_horiz.F90 | 0 .../temp_adjust_no_horiz.meta | 0 .../write_init_files/temp_adjust_noreq.F90 | 0 .../write_init_files/temp_adjust_noreq.meta | 0 .../write_init_files/temp_adjust_param.F90 | 0 .../write_init_files/temp_adjust_param.meta | 0 .../write_init_files/temp_adjust_scalar.F90 | 0 .../write_init_files/temp_adjust_scalar.meta | 0 .../write_init_files/theta_ddt.F90 | 0 .../write_init_files/theta_ddt.meta | 0 .../write_init_files/var_4D_reg.xml | 0 .../write_init_files/var_bad_vertdim.xml | 0 .../unit/{ => python}/test_atm_in_paramgen.py | 2 +- test/unit/{ => python}/test_build_cache.py | 2 +- test/unit/{ => python}/test_cam_autogen.py | 2 +- test/unit/{ => python}/test_cam_config.py | 2 +- .../{ => python}/test_create_readnl_files.py | 14 +- test/unit/{ => python}/test_hist_config.py | 2 +- test/unit/{ => python}/test_registry.py | 4 +- .../{ => python}/test_write_init_files.py | 2 +- 164 files changed, 640 insertions(+), 378 deletions(-) create mode 100644 .github/workflows/fortran_unit_tests.yml create mode 100644 src/core_utils/CMakeLists.txt create mode 100644 src/core_utils/string_core_utils.F90 rename test/{run_unit_tests.sh => run_python_unit_tests.sh} (85%) create mode 100644 test/unit/fortran/CMakeLists.txt create mode 100644 test/unit/fortran/src/core_utils/CMakeLists.txt create mode 100644 test/unit/fortran/src/core_utils/test_string_core_utils.pf rename test/unit/{ => python}/.coveragerc (100%) rename test/unit/{ => python}/sample_files/atm_in_files/test_attr_in (100%) rename test/unit/{ => python}/sample_files/atm_in_files/test_cmplx_array_atm_in (100%) rename test/unit/{ => python}/sample_files/atm_in_files/test_extra_nml_def.xml (100%) rename test/unit/{ => python}/sample_files/atm_in_files/test_extra_nml_same_group.xml (100%) rename test/unit/{ => python}/sample_files/atm_in_files/test_extra_nml_same_var.xml (100%) rename test/unit/{ => python}/sample_files/atm_in_files/test_missing_elems.xml (100%) rename test/unit/{ => python}/sample_files/atm_in_files/test_multi_attr_in (100%) rename test/unit/{ => python}/sample_files/atm_in_files/test_multi_xml_in (100%) rename test/unit/{ => python}/sample_files/atm_in_files/test_nl_duplicate_atm_in (100%) rename test/unit/{ => python}/sample_files/atm_in_files/test_simple_atm_in (100%) rename test/unit/{ => python}/sample_files/atm_in_files/test_simple_nml_def.xml (100%) rename test/unit/{ => python}/sample_files/atm_in_files/test_third_nml_def.xml (100%) rename test/unit/{ => python}/sample_files/atm_in_files/test_user_in (100%) rename test/unit/{ => python}/sample_files/atm_in_files/test_user_nl_allow_dupl_var (100%) rename test/unit/{ => python}/sample_files/atm_in_files/test_user_nl_bad_equals (100%) rename test/unit/{ => python}/sample_files/atm_in_files/test_user_nl_dupl_var (100%) rename test/unit/{ => python}/sample_files/atm_in_files/test_user_nl_no_equals (100%) rename test/unit/{ => python}/sample_files/atm_in_files/test_user_nl_simple (100%) rename test/unit/{ => python}/sample_files/atm_in_files/test_user_nl_undefined_var (100%) rename test/unit/{ => python}/sample_files/autogen_files/two_scheme_banana.F90 (100%) rename test/unit/{ => python}/sample_files/autogen_files/two_scheme_banana.meta (100%) rename test/unit/{ => python}/sample_files/autogen_files/two_scheme_banana_namelist.xml (100%) rename test/unit/{ => python}/sample_files/banana_namelist.xml (100%) rename test/unit/{ => python}/sample_files/build_cache_files/bad_ccpp_tag_build_cache.xml (100%) rename test/unit/{ => python}/sample_files/build_cache_files/bad_reg_tag_build_cache.xml (100%) rename test/unit/{ => python}/sample_files/build_cache_files/bad_section_tag_build_cache.xml (100%) rename test/unit/{ => python}/sample_files/build_cache_files/example_build_cache.xml (100%) rename test/unit/{ => python}/sample_files/build_cache_files/update_ccpp_build_cache.xml (100%) rename test/unit/{ => python}/sample_files/build_cache_files/update_init_gen_build_cache.xml (100%) rename test/unit/{ => python}/sample_files/build_cache_files/update_reg_build_cache.xml (100%) rename test/unit/{ => python}/sample_files/hist_config_files/amwg_hist_config (100%) rename test/unit/{ => python}/sample_files/hist_config_files/atm_in_flat (100%) rename test/unit/{ => python}/sample_files/hist_config_files/atm_in_multi (100%) rename test/unit/{ => python}/sample_files/hist_config_files/rad_config (100%) rename test/unit/{ => python}/sample_files/hist_config_files/user_nl_cam_flat (100%) rename test/unit/{ => python}/sample_files/hist_config_files/user_nl_cam_multi (100%) rename test/unit/{ => python}/sample_files/kumquat_namelist.xml (100%) rename test/unit/{ => python}/sample_files/namelist_files/banana_namelist.F90 (100%) rename test/unit/{ => python}/sample_files/namelist_files/banana_namelist.meta (100%) rename test/unit/{ => python}/sample_files/namelist_files/cam_ccpp_scheme_namelists_double_def.F90 (100%) rename test/unit/{ => python}/sample_files/namelist_files/cam_ccpp_scheme_namelists_single_def.F90 (100%) rename test/unit/{ => python}/sample_files/namelist_files/kumquat_namelist.F90 (100%) rename test/unit/{ => python}/sample_files/namelist_files/kumquat_namelist.meta (100%) rename test/unit/{ => python}/sample_files/phys_types_dup_section.meta (100%) rename test/unit/{ => python}/sample_files/phys_types_no_table.meta (100%) rename test/unit/{ => python}/sample_files/physics_types_complete.F90 (100%) rename test/unit/{ => python}/sample_files/physics_types_complete.meta (100%) rename test/unit/{ => python}/sample_files/physics_types_ddt2.F90 (100%) rename test/unit/{ => python}/sample_files/physics_types_ddt2.meta (100%) rename test/unit/{ => python}/sample_files/physics_types_ddt_array.F90 (100%) rename test/unit/{ => python}/sample_files/physics_types_ddt_array.meta (100%) rename test/unit/{ => python}/sample_files/physics_types_ddt_eul.F90 (100%) rename test/unit/{ => python}/sample_files/physics_types_ddt_eul.meta (100%) rename test/unit/{ => python}/sample_files/physics_types_ddt_fv.F90 (100%) rename test/unit/{ => python}/sample_files/physics_types_ddt_fv.meta (100%) rename test/unit/{ => python}/sample_files/physics_types_ddt_se.F90 (100%) rename test/unit/{ => python}/sample_files/physics_types_ddt_se.meta (100%) rename test/unit/{ => python}/sample_files/physics_types_parameter.F90 (100%) rename test/unit/{ => python}/sample_files/physics_types_parameter.meta (100%) rename test/unit/{ => python}/sample_files/physics_types_simple.F90 (100%) rename test/unit/{ => python}/sample_files/physics_types_simple.meta (100%) rename test/unit/{ => python}/sample_files/ref_pres.meta (100%) rename test/unit/{ => python}/sample_files/ref_pres_SourceMods.meta (100%) rename test/unit/{ => python}/sample_files/reg_bad_xml.xml (98%) rename test/unit/{ => python}/sample_files/reg_good_complete.xml (98%) rename test/unit/{ => python}/sample_files/reg_good_ddt.xml (100%) rename test/unit/{ => python}/sample_files/reg_good_ddt2.xml (100%) rename test/unit/{ => python}/sample_files/reg_good_ddt_array.xml (100%) rename test/unit/{ => python}/sample_files/reg_good_mf.xml (96%) rename test/unit/{ => python}/sample_files/reg_good_simple.xml (100%) rename test/unit/{ => python}/sample_files/rotten_namelist.xml (100%) rename test/unit/{ => python}/sample_files/write_init_files/ddt2_reg.xml (100%) rename test/unit/{ => python}/sample_files/write_init_files/ddt_array_reg.xml (100%) rename test/unit/{ => python}/sample_files/write_init_files/ddt_reg.xml (100%) rename test/unit/{ => python}/sample_files/write_init_files/host_var_host.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/host_var_host.meta (100%) rename test/unit/{ => python}/sample_files/write_init_files/host_var_reg.xml (100%) rename test/unit/{ => python}/sample_files/write_init_files/mf_reg.xml (88%) rename test/unit/{ => python}/sample_files/write_init_files/missing_ICs_reg.xml (100%) rename test/unit/{ => python}/sample_files/write_init_files/no_horiz_dim_reg.xml (100%) rename test/unit/{ => python}/sample_files/write_init_files/no_req_var_reg.xml (100%) rename test/unit/{ => python}/sample_files/write_init_files/param_reg.xml (100%) rename test/unit/{ => python}/sample_files/write_init_files/phys_vars_init_check_4D.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/phys_vars_init_check_bvd.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/phys_vars_init_check_cnst.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/phys_vars_init_check_ddt.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/phys_vars_init_check_ddt2.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/phys_vars_init_check_ddt_array.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/phys_vars_init_check_host_var.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/phys_vars_init_check_mf.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/phys_vars_init_check_no_horiz.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/phys_vars_init_check_noreq.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/phys_vars_init_check_param.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/phys_vars_init_check_parameter.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/phys_vars_init_check_protect.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/phys_vars_init_check_scalar.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/phys_vars_init_check_simple.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/physics_inputs_4D.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/physics_inputs_bvd.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/physics_inputs_cnst.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/physics_inputs_ddt.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/physics_inputs_ddt2.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/physics_inputs_ddt_array.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/physics_inputs_host_var.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/physics_inputs_mf.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/physics_inputs_no_horiz.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/physics_inputs_noreq.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/physics_inputs_param.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/physics_inputs_parameter.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/physics_inputs_protect.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/physics_inputs_scalar.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/physics_inputs_simple.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/protected_reg.xml (100%) rename test/unit/{ => python}/sample_files/write_init_files/ref_theta.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/ref_theta.meta (100%) rename test/unit/{ => python}/sample_files/write_init_files/ref_two.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/ref_two.meta (100%) rename test/unit/{ => python}/sample_files/write_init_files/scalar_var_reg.xml (100%) rename test/unit/{ => python}/sample_files/write_init_files/simple_build_cache_template.xml (100%) rename test/unit/{ => python}/sample_files/write_init_files/simple_host.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/simple_host.meta (100%) rename test/unit/{ => python}/sample_files/write_init_files/simple_reg.xml (100%) rename test/unit/{ => python}/sample_files/write_init_files/suite_simple.xml (100%) rename test/unit/{ => python}/sample_files/write_init_files/temp_adjust.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/temp_adjust.meta (100%) rename test/unit/{ => python}/sample_files/write_init_files/temp_adjust_4D.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/temp_adjust_4D.meta (100%) rename test/unit/{ => python}/sample_files/write_init_files/temp_adjust_bvd.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/temp_adjust_bvd.meta (100%) rename test/unit/{ => python}/sample_files/write_init_files/temp_adjust_cnst.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/temp_adjust_cnst.meta (100%) rename test/unit/{ => python}/sample_files/write_init_files/temp_adjust_no_horiz.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/temp_adjust_no_horiz.meta (100%) rename test/unit/{ => python}/sample_files/write_init_files/temp_adjust_noreq.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/temp_adjust_noreq.meta (100%) rename test/unit/{ => python}/sample_files/write_init_files/temp_adjust_param.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/temp_adjust_param.meta (100%) rename test/unit/{ => python}/sample_files/write_init_files/temp_adjust_scalar.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/temp_adjust_scalar.meta (100%) rename test/unit/{ => python}/sample_files/write_init_files/theta_ddt.F90 (100%) rename test/unit/{ => python}/sample_files/write_init_files/theta_ddt.meta (100%) rename test/unit/{ => python}/sample_files/write_init_files/var_4D_reg.xml (100%) rename test/unit/{ => python}/sample_files/write_init_files/var_bad_vertdim.xml (100%) rename test/unit/{ => python}/test_atm_in_paramgen.py (99%) rename test/unit/{ => python}/test_build_cache.py (99%) rename test/unit/{ => python}/test_cam_autogen.py (99%) rename test/unit/{ => python}/test_cam_config.py (99%) rename test/unit/{ => python}/test_create_readnl_files.py (98%) rename test/unit/{ => python}/test_hist_config.py (99%) rename test/unit/{ => python}/test_registry.py (99%) rename test/unit/{ => python}/test_write_init_files.py (99%) diff --git a/.github/workflows/fortran_unit_tests.yml b/.github/workflows/fortran_unit_tests.yml new file mode 100644 index 00000000..8b298ebf --- /dev/null +++ b/.github/workflows/fortran_unit_tests.yml @@ -0,0 +1,73 @@ +name: Fortran Unit Tests + +on: + push: + branches: + - development + - main + pull_request: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref || github.run_id }} + cancel-in-progress: true + +jobs: + gcc-toolchain: + runs-on: ubuntu-latest + strategy: + matrix: + version: [12, 13, 14] + env: + CC: gcc-${{ matrix.version }} + CXX: g++-${{ matrix.version }} + FC: gfortran-${{ matrix.version }} + steps: + - name: Checkout cam-sima + uses: actions/checkout@v4 + + - name: Build pFUnit + run: | + git clone --depth 1 --branch v4.10.0 https://github.com/Goddard-Fortran-Ecosystem/pFUnit.git + cd pFUnit + cmake -B./build -S. + cd build + make install + + - name: Build cam-sima + run: | + cmake \ + -DCMAKE_PREFIX_PATH=/home/runner/work/CAM-SIMA/CAM-SIMA/pFUnit/build/installed \ + -DCAM_SIMA_ENABLE_CODE_COVERAGE=ON \ + -B./build \ + -S./test/unit/fortran + cd build + make + + - name: Run fortran unit tests + run: | + cd build && ctest -V --output-on-failure --output-junit test_results.xml + + - name: Upload unit test results + uses: actions/upload-artifact@v4 + with: + name: unit-test-results-${{ env.FC }} + path: build/test_results.xml + + - name: Setup GCov + run: | + python3 -m venv venv + source venv/bin/activate + pip3 install gcovr + + - name: Run Gcov + run: | + source venv/bin/activate + cd build + gcovr --gcov-executable gcov-${{ matrix.version }} -r .. --filter '\.\./src' --html cam_sima_code_coverage.html --txt + + - name: Upload code coverage results + uses: actions/upload-artifact@v4 + with: + name: code-coverage-results-${{ env.FC }} + path: build/cam_sima_code_coverage.html diff --git a/.github/workflows/python_unit_tests.yml b/.github/workflows/python_unit_tests.yml index 395412e6..429ceca7 100644 --- a/.github/workflows/python_unit_tests.yml +++ b/.github/workflows/python_unit_tests.yml @@ -1,6 +1,7 @@ name: Python Unit Tests on: + workflow_dispatch: pull_request: types: [opened, synchronize, reopened] push: @@ -16,12 +17,12 @@ jobs: #a PR is either opened or synced (i.e. additional commits are pushed #to branch involved in PR). python_unit_tests: - if: github.event_name == 'pull_request' || github.repository == 'ESCOMP/CAM-SIMA' + if: github.event_name == 'pull_request' || github.repository == 'ESCOMP/CAM-SIMA' || github.event_name == 'workflow_dispatch' runs-on: ubuntu-latest strategy: matrix: #All of these python versions will be used to run tests: - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] fail-fast: false steps: # Acquire github action routines: @@ -56,4 +57,4 @@ jobs: pytest src/data --doctest-modules # Run all python unit tests: - pytest test/unit + pytest test/unit/python diff --git a/.gitignore b/.gitignore index 7d6f4be2..8ca10c01 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ buildnmlc # Ignore test output test/include/*.mod test/include/*.o -test/unit/tmp +test/unit/python/tmp test/system/*.log test/system/cime-tests.o* test_driver_*.sh diff --git a/cime_config/buildlib b/cime_config/buildlib index 33f1d3ec..c564a4b6 100755 --- a/cime_config/buildlib +++ b/cime_config/buildlib @@ -101,7 +101,8 @@ def _build_cam(): os.path.join(atm_root, "src", "history", "buffers", "src"), os.path.join(atm_root, "src", "history", "buffers", "src", "hash"), os.path.join(atm_root, "src", "history", "buffers", "src", "util"), - os.path.join(atm_root, "src", "utils")] + os.path.join(atm_root, "src", "utils"), + os.path.join(atm_root, "src", "core_utils")] for path in phys_dirs: if path not in paths: paths.append(path) diff --git a/cime_config/cam_autogen.py b/cime_config/cam_autogen.py index e08b1f5b..581c98d1 100644 --- a/cime_config/cam_autogen.py +++ b/cime_config/cam_autogen.py @@ -132,7 +132,7 @@ def _find_scheme_source(source_dirs, metadata_file_name): doctests: 1. Check that the function can correctly find source and namelist files: - >>> _find_scheme_source([os.path.join(_CAM_ROOT_DIR, "test", "unit", "sample_files", \ + >>> _find_scheme_source([os.path.join(_CAM_ROOT_DIR, "test", "unit", "python", "sample_files", \ "autogen_files")], "two_scheme_banana") # doctest: +ELLIPSIS ('...two_scheme_banana.F90', '...two_scheme_banana_namelist.xml') diff --git a/src/core_utils/CMakeLists.txt b/src/core_utils/CMakeLists.txt new file mode 100644 index 00000000..9919672f --- /dev/null +++ b/src/core_utils/CMakeLists.txt @@ -0,0 +1,9 @@ +set(CORE_UTILS_SRC string_core_utils.F90) + +# core_utils is not integrated into the CMake build of any top level +# project yet and this CMake is for testing purposes only. +# Making a change to this project's CMake will not impact the build of +# a parent project at this time. +add_library(core_utils ${CORE_UTILS_SRC}) +target_include_directories(core_utils PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) + diff --git a/src/core_utils/string_core_utils.F90 b/src/core_utils/string_core_utils.F90 new file mode 100644 index 00000000..cffd8a0e --- /dev/null +++ b/src/core_utils/string_core_utils.F90 @@ -0,0 +1,162 @@ +module string_core_utils + + implicit none + private + + public :: core_to_str ! Convert integer to left justified string + public :: core_int_date_to_yyyymmdd ! Convert encoded date integer to "yyyy-mm-dd" format + public :: core_int_seconds_to_hhmmss ! Convert integer seconds past midnight to "hh:mm:ss" format + public :: core_stringify ! Convert one or more values of any intrinsic data types to a character string for pretty printing + +CONTAINS + + character(len=10) pure function core_to_str(n) + ! return default integer as a left justified string + + integer, intent(in) :: n + + write(core_to_str,'(i0)') n + + end function core_to_str + + character(len=10) pure function core_int_date_to_yyyymmdd (date) + ! Undefined behavior if date <= 0 + + ! Input arguments + integer, intent(in) :: date + + ! Local variables + integer :: year ! year of yyyy-mm-dd + integer :: month ! month of yyyy-mm-dd + integer :: day ! day of yyyy-mm-dd + + year = date / 10000 + month = (date - year*10000) / 100 + day = date - year*10000 - month*100 + + write(core_int_date_to_yyyymmdd, '(i4.4,A,i2.2,A,i2.2)') & + year,'-',month,'-',day + + end function core_int_date_to_yyyymmdd + + character(len=8) pure function core_int_seconds_to_hhmmss (seconds) + ! Undefined behavior if seconds outside [0, 86400] + + ! Input arguments + integer, intent(in) :: seconds + + ! Local variables + integer :: hours ! hours of hh:mm:ss + integer :: minutes ! minutes of hh:mm:ss + integer :: secs ! seconds of hh:mm:ss + + hours = seconds / 3600 + minutes = (seconds - hours*3600) / 60 + secs = (seconds - hours*3600 - minutes*60) + + write(core_int_seconds_to_hhmmss,'(i2.2,A,i2.2,A,i2.2)') & + hours,':',minutes,':',secs + + end function core_int_seconds_to_hhmmss + + !> Convert one or more values of any intrinsic data types to a character string for pretty printing. + !> If `value` contains more than one element, the elements will be stringified, delimited by `separator`, then concatenated. + !> If `value` contains exactly one element, the element will be stringified without using `separator`. + !> If `value` contains zero element or is of unsupported data types, an empty character string is produced. + !> If `separator` is not supplied, it defaults to `, ` (i.e., a comma and a space). + !> (KCW, 2024-02-04) + pure function core_stringify(value, separator) + use, intrinsic :: iso_fortran_env, only: int32, int64, real32, real64 + + class(*), intent(in) :: value(:) + character(*), optional, intent(in) :: separator + character(:), allocatable :: core_stringify + + integer, parameter :: sizelimit = 1024 + + character(:), allocatable :: buffer, delimiter, format + integer :: i, n, offset + + if (present(separator)) then + delimiter = separator + else + delimiter = ', ' + end if + + n = min(size(value), sizelimit) + + if (n == 0) then + core_stringify = '' + return + end if + + select type (value) + type is (character(*)) + allocate(character(len(value) * n + len(delimiter) * (n - 1)) :: buffer) + + buffer(:) = '' + offset = 0 + + do i = 1, n + if (len(delimiter) > 0 .and. i > 1) then + buffer(offset + 1:offset + len(delimiter)) = delimiter + offset = offset + len(delimiter) + end if + + if (len_trim(adjustl(value(i))) > 0) then + buffer(offset + 1:offset + len_trim(adjustl(value(i)))) = trim(adjustl(value(i))) + offset = offset + len_trim(adjustl(value(i))) + end if + end do + type is (integer(int32)) + allocate(character(11 * n + len(delimiter) * (n - 1)) :: buffer) + allocate(character(17 + len(delimiter) + floor(log10(real(n))) + 1) :: format) + + write(format, '(a, i0, 3a)') '(ss, ', n, '(i0, :, "', delimiter, '"))' + write(buffer, format) value + type is (integer(int64)) + allocate(character(20 * n + len(delimiter) * (n - 1)) :: buffer) + allocate(character(17 + len(delimiter) + floor(log10(real(n))) + 1) :: format) + + write(format, '(a, i0, 3a)') '(ss, ', n, '(i0, :, "', delimiter, '"))' + write(buffer, format) value + type is (logical) + allocate(character(1 * n + len(delimiter) * (n - 1)) :: buffer) + allocate(character(13 + len(delimiter) + floor(log10(real(n))) + 1) :: format) + + write(format, '(a, i0, 3a)') '(', n, '(l1, :, "', delimiter, '"))' + write(buffer, format) value + type is (real(real32)) + allocate(character(13 * n + len(delimiter) * (n - 1)) :: buffer) + + if (maxval(abs(value)) < 1.0e5_real32) then + allocate(character(20 + len(delimiter) + floor(log10(real(n))) + 1) :: format) + write(format, '(a, i0, 3a)') '(ss, ', n, '(f13.6, :, "', delimiter, '"))' + else + allocate(character(23 + len(delimiter) + floor(log10(real(n))) + 1) :: format) + write(format, '(a, i0, 3a)') '(ss, ', n, '(es13.6e2, :, "', delimiter, '"))' + end if + + write(buffer, format) value + type is (real(real64)) + allocate(character(13 * n + len(delimiter) * (n - 1)) :: buffer) + + if (maxval(abs(value)) < 1.0e5_real64) then + allocate(character(20 + len(delimiter) + floor(log10(real(n))) + 1) :: format) + write(format, '(a, i0, 3a)') '(ss, ', n, '(f13.6, :, "', delimiter, '"))' + else + allocate(character(23 + len(delimiter) + floor(log10(real(n))) + 1) :: format) + write(format, '(a, i0, 3a)') '(ss, ', n, '(es13.6e2, :, "', delimiter, '"))' + end if + + write(buffer, format) value + class default + core_stringify = '' + return + end select + + core_stringify = trim(buffer) + + end function core_stringify + +end module string_core_utils diff --git a/src/utils/string_utils.F90 b/src/utils/string_utils.F90 index 223d54da..c3d10b79 100644 --- a/src/utils/string_utils.F90 +++ b/src/utils/string_utils.F90 @@ -4,390 +4,84 @@ module string_utils use shr_string_mod, only: to_lower => shr_string_toLower use cam_logfile, only: iulog use cam_abortutils, only: endrun + use string_core_utils, only: core_int_date_to_yyyymmdd, core_int_seconds_to_hhmmss + use string_core_utils, only: stringify=>core_stringify, to_str=>core_to_str implicit none private ! Public interface methods - public :: strlist_get_ind ! Gets the index of a given string in a list of strings - public :: date2yyyymmdd ! convert encoded date integer to "yyyy-mm-dd" format - public :: sec2hms ! convert integer seconds past midnight to "hh:mm:ss" format - public :: increment_string ! increments a string - public :: last_sig_char ! Position of last significant character in string - public :: to_str ! convert integer to left justified string + public :: date2yyyymmdd ! Convert encoded date integer to "yyyy-mm-dd" format + public :: sec2hms ! Convert integer seconds past midnight to "hh:mm:ss" format + public :: to_str ! Convert integer to left justified string public :: stringify ! Convert one or more values of any intrinsic data types to a character string for pretty printing - ! Private module variables - integer, parameter :: lower_to_upper = iachar("A") - iachar("a") - integer, parameter :: upper_to_lower = iachar("a") - iachar("A") - CONTAINS - !========================================================================================= - subroutine strlist_get_ind(strlist, str, ind, abort) - ! Get the index of a given string in a list of strings. Optional abort argument - ! allows returning control to caller when the string is not found. Default - ! behavior is to call endrun when string is not found. - - ! Arguments - character(len=*), intent(in) :: strlist(:) ! list of strings - character(len=*), intent(in) :: str ! string to search for - integer, intent(out) :: ind ! index of str in strlist - logical, optional, intent(in) :: abort ! flag controlling abort + ! Get the index of a given string in a list of strings. Optional abort argument + ! allows returning control to caller when the string is not found. Default + ! behavior is to call endrun when string is not found. + + ! Arguments + character(len=*), intent(in) :: strlist(:) ! list of strings + character(len=*), intent(in) :: str ! string to search for + integer, intent(out) :: ind ! index of str in strlist + logical, optional, intent(in) :: abort ! flag controlling abort + + ! Local variables + integer :: m + logical :: abort_on_error + character(len=*), parameter :: sub='strlist_get_ind' + + ! Find string in list + do m = 1, size(strlist) + if (str == strlist(m)) then + ind = m + return + end if + end do - ! Local variables - integer :: m - logical :: abort_on_error - character(len=*), parameter :: sub='strlist_get_ind' - !---------------------------------------------------------------------------- + ! String not found + abort_on_error = .true. + if (present(abort)) abort_on_error = abort - ! Find string in list - do m = 1, size(strlist) - if (str == strlist(m)) then - ind = m - return + if (abort_on_error) then + write(iulog, *) sub//': FATAL: string:', trim(str), ' not found in list:', strlist(:) + call endrun(sub//': FATAL: string not found') end if - end do - - ! String not found - abort_on_error = .true. - if (present(abort)) abort_on_error = abort - - if (abort_on_error) then - write(iulog, *) sub//': FATAL: string:', trim(str), ' not found in list:', strlist(:) - call endrun(sub//': FATAL: string not found') - end if - ! error return - ind = -1 + ! error return + ind = -1 end subroutine strlist_get_ind - !========================================================================================= - character(len=10) function date2yyyymmdd (date) - ! Input arguments - integer, intent(in) :: date - - ! Local workspace - - integer :: year ! year of yyyy-mm-dd - integer :: month ! month of yyyy-mm-dd - integer :: day ! day of yyyy-mm-dd - + if (date < 0) then + write(iulog,*)'DATE2YYYYMMDD: negative date not allowed' call endrun ('DATE2YYYYMMDD: negative date not allowed') end if - year = date / 10000 - month = (date - year*10000) / 100 - day = date - year*10000 - month*100 - - write(date2yyyymmdd,80) year, month, day - 80 format(i4.4,'-',i2.2,'-',i2.2) + date2yyyymmdd = core_int_date_to_yyyymmdd(date) end function date2yyyymmdd - !========================================================================================= - character(len=8) function sec2hms (seconds) - ! Input arguments - integer, intent(in) :: seconds - ! Local workspace - - integer :: hours ! hours of hh:mm:ss - integer :: minutes ! minutes of hh:mm:ss - integer :: secs ! seconds of hh:mm:ss - if (seconds < 0 .or. seconds > 86400) then write(iulog,*)'SEC2HMS: bad input seconds:', seconds call endrun ('SEC2HMS: bad input seconds: '//stringify((/seconds/))) end if - hours = seconds / 3600 - minutes = (seconds - hours*3600) / 60 - secs = (seconds - hours*3600 - minutes*60) - - write(sec2hms,80) hours, minutes, secs - 80 format(i2.2,':',i2.2,':',i2.2) + sec2hms = core_int_seconds_to_hhmmss(seconds) end function sec2hms - !========================================================================================= - - integer function increment_string(str, increment) - !----------------------------------------------------------------------- - ! ... Increment a string whose ending characters are digits. - ! The incremented integer must be in the range [0 - (10**n)-1] - ! where n is the number of trailing digits. - ! Return values: - ! - ! 0 success - ! -1 error: no trailing digits in string - ! -2 error: incremented integer is out of range - !----------------------------------------------------------------------- - - !----------------------------------------------------------------------- - ! ... Dummy variables - !----------------------------------------------------------------------- - character(len=*), intent(inout) :: str ! string with trailing digits - ! increment: value to increment string (may be negative) - integer, intent(in) :: increment - - !----------------------------------------------------------------------- - ! ... Local variables - !----------------------------------------------------------------------- - integer :: ind ! index - integer :: lstr ! number of significant characters in string - integer :: lnd ! position of last non-digit - integer :: ndigit ! number of trailing digits - integer :: ival ! integer value of trailing digits - integer :: exp ! power of ten related to most sig digit processed - integer :: digit ! integer value of a single digit - - lstr = last_sig_char(str) - lnd = last_index(str) - ndigit = lstr - lnd - - if (ndigit == 0) then - increment_string = -1 - return - end if - - !----------------------------------------------------------------------- - ! ... Calculate integer corresponding to trailing digits. - !----------------------------------------------------------------------- - ival = 0 - exp = 1 - do ind = lstr, lnd+1, -1 - digit = ICHAR(str(ind:ind)) - ICHAR('0') - ival = ival + (digit * exp) - exp = exp * 10 - end do - - !----------------------------------------------------------------------- - ! ... Increment the integer and test for range - !----------------------------------------------------------------------- - exp = exp - 1 - ival = ival + increment - if (ival < 0 .or. ival > exp) then - increment_string = -2 - return - end if - - !----------------------------------------------------------------------- - ! ... Record new values - !----------------------------------------------------------------------- - do ind = lstr, lnd+1, -1 - str(ind:ind) = ACHAR(MOD(ival, 10) + ICHAR('0')) - ival = ival / 10 - end do - - increment_string = 0 - - end function increment_string - - !=========================================================================== - - integer function last_index(cstr) - !----------------------------------------------------------------------- - ! ... Position of last non-digit in the first input token. - ! Return values: - ! > 0 => position of last non-digit - ! = 0 => token is all digits (or empty) - !----------------------------------------------------------------------- - !----------------------------------------------------------------------- - ! ... Dummy arguments - !----------------------------------------------------------------------- - character(len=*), intent(in) :: cstr ! Input character string - - !----------------------------------------------------------------------- - ! ... Local variables - !----------------------------------------------------------------------- - integer :: lsc ! last sig char - integer :: index - integer :: digit - - lsc = last_sig_char(cstr) - if (lsc == 0) then ! empty string - last_index = 0 - return - end if - - do index = lsc, 1, -1 - digit = ICHAR(cstr(index:index)) - ICHAR('0') - if ((digit < 0) .or. (digit > 9)) then - last_index = index - return - end if - end do - - last_index = 0 ! all characters are digits - - end function last_index - - !=========================================================================== - - integer function last_sig_char(cstr) - !----------------------------------------------------------------------- - ! ... Position of last significant character in string. - ! Here significant means non-blank or non-null. - ! Return values: - ! > 0 => position of last significant character - ! = 0 => no significant characters in string - !----------------------------------------------------------------------- - !----------------------------------------------------------------------- - ! ... Dummy arguments - !----------------------------------------------------------------------- - character(len=*), intent(in) :: cstr ! Input character string - - !----------------------------------------------------------------------- - ! ... Local variables - !----------------------------------------------------------------------- - integer :: slen - integer :: index - - slen = len_trim(cstr) - if (slen == 0) then - last_sig_char = 0 - return - end if - - do index = slen, 1, -1 - if ( (cstr(index:index) /= ' ') .and. & - (cstr(index:index) /= ACHAR(0))) then - exit - end if - end do - last_sig_char = index - - end function last_sig_char - - !=========================================================================== - - character(len=10) function to_str(n) - - ! return default integer as a left justified string - - ! arguments - integer, intent(in) :: n - !---------------------------------------------------------------------------- - - write(to_str,'(i0)') n - - end function to_str - - !=========================================================================== - - !> Convert one or more values of any intrinsic data types to a character string for pretty printing. - !> If `value` contains more than one element, the elements will be stringified, delimited by `separator`, then concatenated. - !> If `value` contains exactly one element, the element will be stringified without using `separator`. - !> If `value` contains zero element or is of unsupported data types, an empty character string is produced. - !> If `separator` is not supplied, it defaults to `, ` (i.e., a comma and a space). - !> (KCW, 2024-02-04) - pure function stringify(value, separator) - use, intrinsic :: iso_fortran_env, only: int32, int64, real32, real64 - - class(*), intent(in) :: value(:) - character(*), optional, intent(in) :: separator - character(:), allocatable :: stringify - - integer, parameter :: sizelimit = 1024 - - character(:), allocatable :: buffer, delimiter, format - integer :: i, n, offset - - if (present(separator)) then - delimiter = separator - else - delimiter = ', ' - end if - - n = min(size(value), sizelimit) - - if (n == 0) then - stringify = '' - - return - end if - - select type (value) - type is (character(*)) - allocate(character(len(value) * n + len(delimiter) * (n - 1)) :: buffer) - - buffer(:) = '' - offset = 0 - - do i = 1, n - if (len(delimiter) > 0 .and. i > 1) then - buffer(offset + 1:offset + len(delimiter)) = delimiter - offset = offset + len(delimiter) - end if - - if (len_trim(adjustl(value(i))) > 0) then - buffer(offset + 1:offset + len_trim(adjustl(value(i)))) = trim(adjustl(value(i))) - offset = offset + len_trim(adjustl(value(i))) - end if - end do - type is (integer(int32)) - allocate(character(11 * n + len(delimiter) * (n - 1)) :: buffer) - allocate(character(17 + len(delimiter) + floor(log10(real(n))) + 1) :: format) - - write(format, '(a, i0, 3a)') '(ss, ', n, '(i0, :, "', delimiter, '"))' - write(buffer, format) value - type is (integer(int64)) - allocate(character(20 * n + len(delimiter) * (n - 1)) :: buffer) - allocate(character(17 + len(delimiter) + floor(log10(real(n))) + 1) :: format) - - write(format, '(a, i0, 3a)') '(ss, ', n, '(i0, :, "', delimiter, '"))' - write(buffer, format) value - type is (logical) - allocate(character(1 * n + len(delimiter) * (n - 1)) :: buffer) - allocate(character(13 + len(delimiter) + floor(log10(real(n))) + 1) :: format) - - write(format, '(a, i0, 3a)') '(', n, '(l1, :, "', delimiter, '"))' - write(buffer, format) value - type is (real(real32)) - allocate(character(13 * n + len(delimiter) * (n - 1)) :: buffer) - - if (maxval(abs(value)) < 1.0e5_real32) then - allocate(character(20 + len(delimiter) + floor(log10(real(n))) + 1) :: format) - write(format, '(a, i0, 3a)') '(ss, ', n, '(f13.6, :, "', delimiter, '"))' - else - allocate(character(23 + len(delimiter) + floor(log10(real(n))) + 1) :: format) - write(format, '(a, i0, 3a)') '(ss, ', n, '(es13.6e2, :, "', delimiter, '"))' - end if - - write(buffer, format) value - type is (real(real64)) - allocate(character(13 * n + len(delimiter) * (n - 1)) :: buffer) - - if (maxval(abs(value)) < 1.0e5_real64) then - allocate(character(20 + len(delimiter) + floor(log10(real(n))) + 1) :: format) - write(format, '(a, i0, 3a)') '(ss, ', n, '(f13.6, :, "', delimiter, '"))' - else - allocate(character(23 + len(delimiter) + floor(log10(real(n))) + 1) :: format) - write(format, '(a, i0, 3a)') '(ss, ', n, '(es13.6e2, :, "', delimiter, '"))' - end if - - write(buffer, format) value - class default - stringify = '' - - return - end select - - stringify = trim(buffer) - end function stringify - -!========================================================================================= - end module string_utils diff --git a/test/run_unit_tests.sh b/test/run_python_unit_tests.sh similarity index 85% rename from test/run_unit_tests.sh rename to test/run_python_unit_tests.sh index a68cbf08..ec4a9d78 100755 --- a/test/run_unit_tests.sh +++ b/test/run_python_unit_tests.sh @@ -69,21 +69,21 @@ run_doctest cime_config/atm_in_paramgen.py # CAM history config doctests: run_doctest cime_config/hist_config.py # CAM config unit tests: -run_unittest test/unit/test_cam_config.py +run_unittest test/unit/python/test_cam_config.py # CAM autogen unit tests: -run_unittest test/unit/test_cam_autogen.py +run_unittest test/unit/python/test_cam_autogen.py # CAM build cache unit tests: -run_unittest test/unit/test_build_cache.py +run_unittest test/unit/python/test_build_cache.py # Registry generator unit tests: -run_unittest test/unit/test_registry.py +run_unittest test/unit/python/test_registry.py # Namelist reader autogeneration unit tests -run_unittest test/unit/test_create_readnl_files.py +run_unittest test/unit/python/test_create_readnl_files.py # Physics variable init (phys_init) generator unit tests: -run_unittest test/unit/test_write_init_files.py +run_unittest test/unit/python/test_write_init_files.py # ParamGen atm_in namelist writer unit tests: -run_unittest test/unit/test_atm_in_paramgen.py +run_unittest test/unit/python/test_atm_in_paramgen.py # CAM history config unit tests -run_unittest test/unit/test_hist_config.py +run_unittest test/unit/python/test_hist_config.py # Report if [ ${NUMERRORS} -gt 0 ]; then diff --git a/test/unit/fortran/CMakeLists.txt b/test/unit/fortran/CMakeLists.txt new file mode 100644 index 00000000..965f1581 --- /dev/null +++ b/test/unit/fortran/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.18) + +project(CAM-SIMA-core-utils LANGUAGES Fortran) + +option(CAM_SIMA_ENABLE_TESTS "Run pFUnit unit tests" OFF) +option(CAM_SIMA_ENABLE_CODE_COVERAGE "Run code coverage tool" OFF) + +if(NOT CAM-SIMA-core-utils_IS_TOP_LEVEL) + message(WARNING "CAM-SIMA-core-utils is not integrated into the CMake build of any top level " + "project yet and this CMake is for testing purposes only. " + "Making a change to this project's CMake will not impact the build of " + "a parent project at this time.") +endif() + +# Overwrite the init flags chosen by CMake +if(${CMAKE_Fortran_COMPILER_ID} MATCHES "GNU") + add_compile_options("-ffree-line-length-none") +endif() + +if(CAM_SIMA_ENABLE_CODE_COVERAGE) + add_compile_options(-O0 --coverage) + add_link_options(--coverage) +endif() + +add_subdirectory(${CMAKE_SOURCE_DIR}/../../../src/core_utils ${CMAKE_BINARY_DIR}/src) + +if(CAM_SIMA_ENABLE_TESTS OR CAM_SIMA_ENABLE_CODE_COVERAGE) +set(CMAKE_BUILD_TYPE Debug) + find_package(PFUNIT REQUIRED) + enable_testing() + add_subdirectory(src/core_utils) +endif() diff --git a/test/unit/fortran/src/core_utils/CMakeLists.txt b/test/unit/fortran/src/core_utils/CMakeLists.txt new file mode 100644 index 00000000..b288a189 --- /dev/null +++ b/test/unit/fortran/src/core_utils/CMakeLists.txt @@ -0,0 +1,3 @@ +add_pfunit_ctest(core_utils_tests + TEST_SOURCES test_string_core_utils.pf + LINK_LIBRARIES core_utils) diff --git a/test/unit/fortran/src/core_utils/test_string_core_utils.pf b/test/unit/fortran/src/core_utils/test_string_core_utils.pf new file mode 100644 index 00000000..a87c670d --- /dev/null +++ b/test/unit/fortran/src/core_utils/test_string_core_utils.pf @@ -0,0 +1,287 @@ +@test +subroutine test_integer_one_to_str() + use funit + use string_core_utils, only : core_to_str + + integer :: to_convert + + to_convert = 1 + + @assertEqual("1", core_to_str(to_convert)) +end subroutine test_integer_one_to_str + +@test +subroutine test_integer_with_leading_zeros_to_str() + use funit + use string_core_utils, only : core_to_str + + integer :: to_convert + character(len=10) :: actual + + to_convert = 001 + actual = core_to_str(to_convert) + + @assertEqual("1", actual) +end subroutine test_integer_with_leading_zeros_to_str + +@test +subroutine test_integer_with_trailing_zeros_to_str() + use funit + use string_core_utils, only : core_to_str + + integer :: to_convert + character(len=10) :: actual + + to_convert = 100 + actual = core_to_str(to_convert) + + @assertEqual("100", actual) +end subroutine test_integer_with_trailing_zeros_to_str + +@test +subroutine test_one_int_date_to_yyyymmdd() + use funit + use string_core_utils, only : core_int_date_to_yyyymmdd + + integer :: to_convert + character(len=10) :: actual + + to_convert = 1 + actual = core_int_date_to_yyyymmdd(to_convert) + + @assertEqual("0000-00-01", actual) +end subroutine test_one_int_date_to_yyyymmdd + +@test +subroutine test_zero_int_seconds_to_hhmmss() + use funit + use string_core_utils, only : core_int_seconds_to_hhmmss + + integer :: to_convert + character(len=8) :: actual + + to_convert = 0 + actual = core_int_seconds_to_hhmmss(to_convert) + + @assertEqual("00:00:00", actual) +end subroutine test_zero_int_seconds_to_hhmmss + +@test +subroutine test_stringify_empty_arrays() + use, intrinsic :: iso_fortran_env, only: int32, int64, real32, real64 + use funit + use string_core_utils, only: core_stringify + + character(128), allocatable :: carr(:) + integer(int32), allocatable :: i32arr(:) + integer(int64), allocatable :: i64arr(:) + logical, allocatable :: larr(:) + real(real32), allocatable :: r32arr(:) + real(real64), allocatable :: r64arr(:) + + + allocate(carr(0), i32arr(0), i64arr(0), larr(0), r32arr(0), r64arr(0)) + + @assertEqual("", core_stringify(carr)) + @assertEqual("", core_stringify(i32arr)) + @assertEqual("", core_stringify(i64arr)) + @assertEqual("", core_stringify(larr)) + @assertEqual("", core_stringify(r32arr)) + @assertEqual("", core_stringify(r64arr)) + +end subroutine test_stringify_empty_arrays + +! Ignoring this test due to a bug in the GNU compiler >= v12. +! https://github.com/ESCOMP/CAM-SIMA/pull/326#discussion_r1909520600 +@test(#ifndef= __GNUC__) +subroutine test_stringify_character_array + use funit + use string_core_utils, only: core_stringify + + character(128), allocatable :: carr(:) + allocate(carr(10)) + + carr(:) = [ character(len(carr)) :: & + ' Talc', 'Gypsum', 'Calcite', 'Fluorite', 'Apatite', & + 'Orthoclase', 'Quartz', ' Topaz', 'Corundum', 'Diamond' ] + + @assertEqual('Talc, Gypsum, Calcite, Fluorite, Apatite, Orthoclase, Quartz, Topaz, Corundum, Diamond', core_stringify(carr)) + @assertEqual('TalcPhysics state variables updated by dynamical core - $SRCROOT/test/unit/sample_files/ref_pres.meta + $SRCROOT/test/unit/python/sample_files/ref_pres.meta diff --git a/test/unit/sample_files/reg_good_complete.xml b/test/unit/python/sample_files/reg_good_complete.xml similarity index 98% rename from test/unit/sample_files/reg_good_complete.xml rename to test/unit/python/sample_files/reg_good_complete.xml index a18660ba..9ef13746 100644 --- a/test/unit/sample_files/reg_good_complete.xml +++ b/test/unit/python/sample_files/reg_good_complete.xml @@ -106,5 +106,5 @@ Physics state variables updated by dynamical core - $SRCROOT/test/unit/sample_files/ref_pres.meta + $SRCROOT/test/unit/python/sample_files/ref_pres.meta diff --git a/test/unit/sample_files/reg_good_ddt.xml b/test/unit/python/sample_files/reg_good_ddt.xml similarity index 100% rename from test/unit/sample_files/reg_good_ddt.xml rename to test/unit/python/sample_files/reg_good_ddt.xml diff --git a/test/unit/sample_files/reg_good_ddt2.xml b/test/unit/python/sample_files/reg_good_ddt2.xml similarity index 100% rename from test/unit/sample_files/reg_good_ddt2.xml rename to test/unit/python/sample_files/reg_good_ddt2.xml diff --git a/test/unit/sample_files/reg_good_ddt_array.xml b/test/unit/python/sample_files/reg_good_ddt_array.xml similarity index 100% rename from test/unit/sample_files/reg_good_ddt_array.xml rename to test/unit/python/sample_files/reg_good_ddt_array.xml diff --git a/test/unit/sample_files/reg_good_mf.xml b/test/unit/python/sample_files/reg_good_mf.xml similarity index 96% rename from test/unit/sample_files/reg_good_mf.xml rename to test/unit/python/sample_files/reg_good_mf.xml index 618cb8c2..d39f356e 100644 --- a/test/unit/sample_files/reg_good_mf.xml +++ b/test/unit/python/sample_files/reg_good_mf.xml @@ -41,5 +41,5 @@ Physics state variables updated by dynamical core - $SRCROOT/test/unit/sample_files/ref_pres.meta + $SRCROOT/test/unit/python/sample_files/ref_pres.meta diff --git a/test/unit/sample_files/reg_good_simple.xml b/test/unit/python/sample_files/reg_good_simple.xml similarity index 100% rename from test/unit/sample_files/reg_good_simple.xml rename to test/unit/python/sample_files/reg_good_simple.xml diff --git a/test/unit/sample_files/rotten_namelist.xml b/test/unit/python/sample_files/rotten_namelist.xml similarity index 100% rename from test/unit/sample_files/rotten_namelist.xml rename to test/unit/python/sample_files/rotten_namelist.xml diff --git a/test/unit/sample_files/write_init_files/ddt2_reg.xml b/test/unit/python/sample_files/write_init_files/ddt2_reg.xml similarity index 100% rename from test/unit/sample_files/write_init_files/ddt2_reg.xml rename to test/unit/python/sample_files/write_init_files/ddt2_reg.xml diff --git a/test/unit/sample_files/write_init_files/ddt_array_reg.xml b/test/unit/python/sample_files/write_init_files/ddt_array_reg.xml similarity index 100% rename from test/unit/sample_files/write_init_files/ddt_array_reg.xml rename to test/unit/python/sample_files/write_init_files/ddt_array_reg.xml diff --git a/test/unit/sample_files/write_init_files/ddt_reg.xml b/test/unit/python/sample_files/write_init_files/ddt_reg.xml similarity index 100% rename from test/unit/sample_files/write_init_files/ddt_reg.xml rename to test/unit/python/sample_files/write_init_files/ddt_reg.xml diff --git a/test/unit/sample_files/write_init_files/host_var_host.F90 b/test/unit/python/sample_files/write_init_files/host_var_host.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/host_var_host.F90 rename to test/unit/python/sample_files/write_init_files/host_var_host.F90 diff --git a/test/unit/sample_files/write_init_files/host_var_host.meta b/test/unit/python/sample_files/write_init_files/host_var_host.meta similarity index 100% rename from test/unit/sample_files/write_init_files/host_var_host.meta rename to test/unit/python/sample_files/write_init_files/host_var_host.meta diff --git a/test/unit/sample_files/write_init_files/host_var_reg.xml b/test/unit/python/sample_files/write_init_files/host_var_reg.xml similarity index 100% rename from test/unit/sample_files/write_init_files/host_var_reg.xml rename to test/unit/python/sample_files/write_init_files/host_var_reg.xml diff --git a/test/unit/sample_files/write_init_files/mf_reg.xml b/test/unit/python/sample_files/write_init_files/mf_reg.xml similarity index 88% rename from test/unit/sample_files/write_init_files/mf_reg.xml rename to test/unit/python/sample_files/write_init_files/mf_reg.xml index 0183dd50..e39c9eaf 100644 --- a/test/unit/sample_files/write_init_files/mf_reg.xml +++ b/test/unit/python/sample_files/write_init_files/mf_reg.xml @@ -14,5 +14,5 @@ eddy_len - $SRCROOT/test/unit/sample_files/write_init_files/ref_theta.meta + $SRCROOT/test/unit/python/sample_files/write_init_files/ref_theta.meta diff --git a/test/unit/sample_files/write_init_files/missing_ICs_reg.xml b/test/unit/python/sample_files/write_init_files/missing_ICs_reg.xml similarity index 100% rename from test/unit/sample_files/write_init_files/missing_ICs_reg.xml rename to test/unit/python/sample_files/write_init_files/missing_ICs_reg.xml diff --git a/test/unit/sample_files/write_init_files/no_horiz_dim_reg.xml b/test/unit/python/sample_files/write_init_files/no_horiz_dim_reg.xml similarity index 100% rename from test/unit/sample_files/write_init_files/no_horiz_dim_reg.xml rename to test/unit/python/sample_files/write_init_files/no_horiz_dim_reg.xml diff --git a/test/unit/sample_files/write_init_files/no_req_var_reg.xml b/test/unit/python/sample_files/write_init_files/no_req_var_reg.xml similarity index 100% rename from test/unit/sample_files/write_init_files/no_req_var_reg.xml rename to test/unit/python/sample_files/write_init_files/no_req_var_reg.xml diff --git a/test/unit/sample_files/write_init_files/param_reg.xml b/test/unit/python/sample_files/write_init_files/param_reg.xml similarity index 100% rename from test/unit/sample_files/write_init_files/param_reg.xml rename to test/unit/python/sample_files/write_init_files/param_reg.xml diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_4D.F90 b/test/unit/python/sample_files/write_init_files/phys_vars_init_check_4D.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/phys_vars_init_check_4D.F90 rename to test/unit/python/sample_files/write_init_files/phys_vars_init_check_4D.F90 diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_bvd.F90 b/test/unit/python/sample_files/write_init_files/phys_vars_init_check_bvd.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/phys_vars_init_check_bvd.F90 rename to test/unit/python/sample_files/write_init_files/phys_vars_init_check_bvd.F90 diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_cnst.F90 b/test/unit/python/sample_files/write_init_files/phys_vars_init_check_cnst.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/phys_vars_init_check_cnst.F90 rename to test/unit/python/sample_files/write_init_files/phys_vars_init_check_cnst.F90 diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_ddt.F90 b/test/unit/python/sample_files/write_init_files/phys_vars_init_check_ddt.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/phys_vars_init_check_ddt.F90 rename to test/unit/python/sample_files/write_init_files/phys_vars_init_check_ddt.F90 diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_ddt2.F90 b/test/unit/python/sample_files/write_init_files/phys_vars_init_check_ddt2.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/phys_vars_init_check_ddt2.F90 rename to test/unit/python/sample_files/write_init_files/phys_vars_init_check_ddt2.F90 diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_ddt_array.F90 b/test/unit/python/sample_files/write_init_files/phys_vars_init_check_ddt_array.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/phys_vars_init_check_ddt_array.F90 rename to test/unit/python/sample_files/write_init_files/phys_vars_init_check_ddt_array.F90 diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_host_var.F90 b/test/unit/python/sample_files/write_init_files/phys_vars_init_check_host_var.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/phys_vars_init_check_host_var.F90 rename to test/unit/python/sample_files/write_init_files/phys_vars_init_check_host_var.F90 diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_mf.F90 b/test/unit/python/sample_files/write_init_files/phys_vars_init_check_mf.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/phys_vars_init_check_mf.F90 rename to test/unit/python/sample_files/write_init_files/phys_vars_init_check_mf.F90 diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_no_horiz.F90 b/test/unit/python/sample_files/write_init_files/phys_vars_init_check_no_horiz.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/phys_vars_init_check_no_horiz.F90 rename to test/unit/python/sample_files/write_init_files/phys_vars_init_check_no_horiz.F90 diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_noreq.F90 b/test/unit/python/sample_files/write_init_files/phys_vars_init_check_noreq.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/phys_vars_init_check_noreq.F90 rename to test/unit/python/sample_files/write_init_files/phys_vars_init_check_noreq.F90 diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_param.F90 b/test/unit/python/sample_files/write_init_files/phys_vars_init_check_param.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/phys_vars_init_check_param.F90 rename to test/unit/python/sample_files/write_init_files/phys_vars_init_check_param.F90 diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_parameter.F90 b/test/unit/python/sample_files/write_init_files/phys_vars_init_check_parameter.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/phys_vars_init_check_parameter.F90 rename to test/unit/python/sample_files/write_init_files/phys_vars_init_check_parameter.F90 diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_protect.F90 b/test/unit/python/sample_files/write_init_files/phys_vars_init_check_protect.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/phys_vars_init_check_protect.F90 rename to test/unit/python/sample_files/write_init_files/phys_vars_init_check_protect.F90 diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_scalar.F90 b/test/unit/python/sample_files/write_init_files/phys_vars_init_check_scalar.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/phys_vars_init_check_scalar.F90 rename to test/unit/python/sample_files/write_init_files/phys_vars_init_check_scalar.F90 diff --git a/test/unit/sample_files/write_init_files/phys_vars_init_check_simple.F90 b/test/unit/python/sample_files/write_init_files/phys_vars_init_check_simple.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/phys_vars_init_check_simple.F90 rename to test/unit/python/sample_files/write_init_files/phys_vars_init_check_simple.F90 diff --git a/test/unit/sample_files/write_init_files/physics_inputs_4D.F90 b/test/unit/python/sample_files/write_init_files/physics_inputs_4D.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/physics_inputs_4D.F90 rename to test/unit/python/sample_files/write_init_files/physics_inputs_4D.F90 diff --git a/test/unit/sample_files/write_init_files/physics_inputs_bvd.F90 b/test/unit/python/sample_files/write_init_files/physics_inputs_bvd.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/physics_inputs_bvd.F90 rename to test/unit/python/sample_files/write_init_files/physics_inputs_bvd.F90 diff --git a/test/unit/sample_files/write_init_files/physics_inputs_cnst.F90 b/test/unit/python/sample_files/write_init_files/physics_inputs_cnst.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/physics_inputs_cnst.F90 rename to test/unit/python/sample_files/write_init_files/physics_inputs_cnst.F90 diff --git a/test/unit/sample_files/write_init_files/physics_inputs_ddt.F90 b/test/unit/python/sample_files/write_init_files/physics_inputs_ddt.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/physics_inputs_ddt.F90 rename to test/unit/python/sample_files/write_init_files/physics_inputs_ddt.F90 diff --git a/test/unit/sample_files/write_init_files/physics_inputs_ddt2.F90 b/test/unit/python/sample_files/write_init_files/physics_inputs_ddt2.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/physics_inputs_ddt2.F90 rename to test/unit/python/sample_files/write_init_files/physics_inputs_ddt2.F90 diff --git a/test/unit/sample_files/write_init_files/physics_inputs_ddt_array.F90 b/test/unit/python/sample_files/write_init_files/physics_inputs_ddt_array.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/physics_inputs_ddt_array.F90 rename to test/unit/python/sample_files/write_init_files/physics_inputs_ddt_array.F90 diff --git a/test/unit/sample_files/write_init_files/physics_inputs_host_var.F90 b/test/unit/python/sample_files/write_init_files/physics_inputs_host_var.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/physics_inputs_host_var.F90 rename to test/unit/python/sample_files/write_init_files/physics_inputs_host_var.F90 diff --git a/test/unit/sample_files/write_init_files/physics_inputs_mf.F90 b/test/unit/python/sample_files/write_init_files/physics_inputs_mf.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/physics_inputs_mf.F90 rename to test/unit/python/sample_files/write_init_files/physics_inputs_mf.F90 diff --git a/test/unit/sample_files/write_init_files/physics_inputs_no_horiz.F90 b/test/unit/python/sample_files/write_init_files/physics_inputs_no_horiz.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/physics_inputs_no_horiz.F90 rename to test/unit/python/sample_files/write_init_files/physics_inputs_no_horiz.F90 diff --git a/test/unit/sample_files/write_init_files/physics_inputs_noreq.F90 b/test/unit/python/sample_files/write_init_files/physics_inputs_noreq.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/physics_inputs_noreq.F90 rename to test/unit/python/sample_files/write_init_files/physics_inputs_noreq.F90 diff --git a/test/unit/sample_files/write_init_files/physics_inputs_param.F90 b/test/unit/python/sample_files/write_init_files/physics_inputs_param.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/physics_inputs_param.F90 rename to test/unit/python/sample_files/write_init_files/physics_inputs_param.F90 diff --git a/test/unit/sample_files/write_init_files/physics_inputs_parameter.F90 b/test/unit/python/sample_files/write_init_files/physics_inputs_parameter.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/physics_inputs_parameter.F90 rename to test/unit/python/sample_files/write_init_files/physics_inputs_parameter.F90 diff --git a/test/unit/sample_files/write_init_files/physics_inputs_protect.F90 b/test/unit/python/sample_files/write_init_files/physics_inputs_protect.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/physics_inputs_protect.F90 rename to test/unit/python/sample_files/write_init_files/physics_inputs_protect.F90 diff --git a/test/unit/sample_files/write_init_files/physics_inputs_scalar.F90 b/test/unit/python/sample_files/write_init_files/physics_inputs_scalar.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/physics_inputs_scalar.F90 rename to test/unit/python/sample_files/write_init_files/physics_inputs_scalar.F90 diff --git a/test/unit/sample_files/write_init_files/physics_inputs_simple.F90 b/test/unit/python/sample_files/write_init_files/physics_inputs_simple.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/physics_inputs_simple.F90 rename to test/unit/python/sample_files/write_init_files/physics_inputs_simple.F90 diff --git a/test/unit/sample_files/write_init_files/protected_reg.xml b/test/unit/python/sample_files/write_init_files/protected_reg.xml similarity index 100% rename from test/unit/sample_files/write_init_files/protected_reg.xml rename to test/unit/python/sample_files/write_init_files/protected_reg.xml diff --git a/test/unit/sample_files/write_init_files/ref_theta.F90 b/test/unit/python/sample_files/write_init_files/ref_theta.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/ref_theta.F90 rename to test/unit/python/sample_files/write_init_files/ref_theta.F90 diff --git a/test/unit/sample_files/write_init_files/ref_theta.meta b/test/unit/python/sample_files/write_init_files/ref_theta.meta similarity index 100% rename from test/unit/sample_files/write_init_files/ref_theta.meta rename to test/unit/python/sample_files/write_init_files/ref_theta.meta diff --git a/test/unit/sample_files/write_init_files/ref_two.F90 b/test/unit/python/sample_files/write_init_files/ref_two.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/ref_two.F90 rename to test/unit/python/sample_files/write_init_files/ref_two.F90 diff --git a/test/unit/sample_files/write_init_files/ref_two.meta b/test/unit/python/sample_files/write_init_files/ref_two.meta similarity index 100% rename from test/unit/sample_files/write_init_files/ref_two.meta rename to test/unit/python/sample_files/write_init_files/ref_two.meta diff --git a/test/unit/sample_files/write_init_files/scalar_var_reg.xml b/test/unit/python/sample_files/write_init_files/scalar_var_reg.xml similarity index 100% rename from test/unit/sample_files/write_init_files/scalar_var_reg.xml rename to test/unit/python/sample_files/write_init_files/scalar_var_reg.xml diff --git a/test/unit/sample_files/write_init_files/simple_build_cache_template.xml b/test/unit/python/sample_files/write_init_files/simple_build_cache_template.xml similarity index 100% rename from test/unit/sample_files/write_init_files/simple_build_cache_template.xml rename to test/unit/python/sample_files/write_init_files/simple_build_cache_template.xml diff --git a/test/unit/sample_files/write_init_files/simple_host.F90 b/test/unit/python/sample_files/write_init_files/simple_host.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/simple_host.F90 rename to test/unit/python/sample_files/write_init_files/simple_host.F90 diff --git a/test/unit/sample_files/write_init_files/simple_host.meta b/test/unit/python/sample_files/write_init_files/simple_host.meta similarity index 100% rename from test/unit/sample_files/write_init_files/simple_host.meta rename to test/unit/python/sample_files/write_init_files/simple_host.meta diff --git a/test/unit/sample_files/write_init_files/simple_reg.xml b/test/unit/python/sample_files/write_init_files/simple_reg.xml similarity index 100% rename from test/unit/sample_files/write_init_files/simple_reg.xml rename to test/unit/python/sample_files/write_init_files/simple_reg.xml diff --git a/test/unit/sample_files/write_init_files/suite_simple.xml b/test/unit/python/sample_files/write_init_files/suite_simple.xml similarity index 100% rename from test/unit/sample_files/write_init_files/suite_simple.xml rename to test/unit/python/sample_files/write_init_files/suite_simple.xml diff --git a/test/unit/sample_files/write_init_files/temp_adjust.F90 b/test/unit/python/sample_files/write_init_files/temp_adjust.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/temp_adjust.F90 rename to test/unit/python/sample_files/write_init_files/temp_adjust.F90 diff --git a/test/unit/sample_files/write_init_files/temp_adjust.meta b/test/unit/python/sample_files/write_init_files/temp_adjust.meta similarity index 100% rename from test/unit/sample_files/write_init_files/temp_adjust.meta rename to test/unit/python/sample_files/write_init_files/temp_adjust.meta diff --git a/test/unit/sample_files/write_init_files/temp_adjust_4D.F90 b/test/unit/python/sample_files/write_init_files/temp_adjust_4D.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/temp_adjust_4D.F90 rename to test/unit/python/sample_files/write_init_files/temp_adjust_4D.F90 diff --git a/test/unit/sample_files/write_init_files/temp_adjust_4D.meta b/test/unit/python/sample_files/write_init_files/temp_adjust_4D.meta similarity index 100% rename from test/unit/sample_files/write_init_files/temp_adjust_4D.meta rename to test/unit/python/sample_files/write_init_files/temp_adjust_4D.meta diff --git a/test/unit/sample_files/write_init_files/temp_adjust_bvd.F90 b/test/unit/python/sample_files/write_init_files/temp_adjust_bvd.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/temp_adjust_bvd.F90 rename to test/unit/python/sample_files/write_init_files/temp_adjust_bvd.F90 diff --git a/test/unit/sample_files/write_init_files/temp_adjust_bvd.meta b/test/unit/python/sample_files/write_init_files/temp_adjust_bvd.meta similarity index 100% rename from test/unit/sample_files/write_init_files/temp_adjust_bvd.meta rename to test/unit/python/sample_files/write_init_files/temp_adjust_bvd.meta diff --git a/test/unit/sample_files/write_init_files/temp_adjust_cnst.F90 b/test/unit/python/sample_files/write_init_files/temp_adjust_cnst.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/temp_adjust_cnst.F90 rename to test/unit/python/sample_files/write_init_files/temp_adjust_cnst.F90 diff --git a/test/unit/sample_files/write_init_files/temp_adjust_cnst.meta b/test/unit/python/sample_files/write_init_files/temp_adjust_cnst.meta similarity index 100% rename from test/unit/sample_files/write_init_files/temp_adjust_cnst.meta rename to test/unit/python/sample_files/write_init_files/temp_adjust_cnst.meta diff --git a/test/unit/sample_files/write_init_files/temp_adjust_no_horiz.F90 b/test/unit/python/sample_files/write_init_files/temp_adjust_no_horiz.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/temp_adjust_no_horiz.F90 rename to test/unit/python/sample_files/write_init_files/temp_adjust_no_horiz.F90 diff --git a/test/unit/sample_files/write_init_files/temp_adjust_no_horiz.meta b/test/unit/python/sample_files/write_init_files/temp_adjust_no_horiz.meta similarity index 100% rename from test/unit/sample_files/write_init_files/temp_adjust_no_horiz.meta rename to test/unit/python/sample_files/write_init_files/temp_adjust_no_horiz.meta diff --git a/test/unit/sample_files/write_init_files/temp_adjust_noreq.F90 b/test/unit/python/sample_files/write_init_files/temp_adjust_noreq.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/temp_adjust_noreq.F90 rename to test/unit/python/sample_files/write_init_files/temp_adjust_noreq.F90 diff --git a/test/unit/sample_files/write_init_files/temp_adjust_noreq.meta b/test/unit/python/sample_files/write_init_files/temp_adjust_noreq.meta similarity index 100% rename from test/unit/sample_files/write_init_files/temp_adjust_noreq.meta rename to test/unit/python/sample_files/write_init_files/temp_adjust_noreq.meta diff --git a/test/unit/sample_files/write_init_files/temp_adjust_param.F90 b/test/unit/python/sample_files/write_init_files/temp_adjust_param.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/temp_adjust_param.F90 rename to test/unit/python/sample_files/write_init_files/temp_adjust_param.F90 diff --git a/test/unit/sample_files/write_init_files/temp_adjust_param.meta b/test/unit/python/sample_files/write_init_files/temp_adjust_param.meta similarity index 100% rename from test/unit/sample_files/write_init_files/temp_adjust_param.meta rename to test/unit/python/sample_files/write_init_files/temp_adjust_param.meta diff --git a/test/unit/sample_files/write_init_files/temp_adjust_scalar.F90 b/test/unit/python/sample_files/write_init_files/temp_adjust_scalar.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/temp_adjust_scalar.F90 rename to test/unit/python/sample_files/write_init_files/temp_adjust_scalar.F90 diff --git a/test/unit/sample_files/write_init_files/temp_adjust_scalar.meta b/test/unit/python/sample_files/write_init_files/temp_adjust_scalar.meta similarity index 100% rename from test/unit/sample_files/write_init_files/temp_adjust_scalar.meta rename to test/unit/python/sample_files/write_init_files/temp_adjust_scalar.meta diff --git a/test/unit/sample_files/write_init_files/theta_ddt.F90 b/test/unit/python/sample_files/write_init_files/theta_ddt.F90 similarity index 100% rename from test/unit/sample_files/write_init_files/theta_ddt.F90 rename to test/unit/python/sample_files/write_init_files/theta_ddt.F90 diff --git a/test/unit/sample_files/write_init_files/theta_ddt.meta b/test/unit/python/sample_files/write_init_files/theta_ddt.meta similarity index 100% rename from test/unit/sample_files/write_init_files/theta_ddt.meta rename to test/unit/python/sample_files/write_init_files/theta_ddt.meta diff --git a/test/unit/sample_files/write_init_files/var_4D_reg.xml b/test/unit/python/sample_files/write_init_files/var_4D_reg.xml similarity index 100% rename from test/unit/sample_files/write_init_files/var_4D_reg.xml rename to test/unit/python/sample_files/write_init_files/var_4D_reg.xml diff --git a/test/unit/sample_files/write_init_files/var_bad_vertdim.xml b/test/unit/python/sample_files/write_init_files/var_bad_vertdim.xml similarity index 100% rename from test/unit/sample_files/write_init_files/var_bad_vertdim.xml rename to test/unit/python/sample_files/write_init_files/var_bad_vertdim.xml diff --git a/test/unit/test_atm_in_paramgen.py b/test/unit/python/test_atm_in_paramgen.py similarity index 99% rename from test/unit/test_atm_in_paramgen.py rename to test/unit/python/test_atm_in_paramgen.py index 69d0d353..5ea26d6c 100644 --- a/test/unit/test_atm_in_paramgen.py +++ b/test/unit/python/test_atm_in_paramgen.py @@ -30,7 +30,7 @@ #Add directory to python path: _TEST_DIR = os.path.abspath(os.path.dirname(__file__)) -_CAM_ROOT_DIR = os.path.join(_TEST_DIR, os.pardir, os.pardir) +_CAM_ROOT_DIR = os.path.join(_TEST_DIR, os.pardir, os.pardir, os.pardir) _CIME_CONF_DIR = os.path.abspath(os.path.join(_CAM_ROOT_DIR, "cime_config")) _SAMPLES_DIR = os.path.join(os.path.join(_TEST_DIR, "sample_files"), "atm_in_files") diff --git a/test/unit/test_build_cache.py b/test/unit/python/test_build_cache.py similarity index 99% rename from test/unit/test_build_cache.py rename to test/unit/python/test_build_cache.py index 39dc59d2..e211635e 100644 --- a/test/unit/test_build_cache.py +++ b/test/unit/python/test_build_cache.py @@ -32,7 +32,7 @@ #Add directory to python path: _CWD = os.getcwd() _CURRDIR = os.path.abspath(os.path.dirname(__file__)) -_CAM_ROOT_DIR = os.path.join(_CURRDIR, os.pardir, os.pardir) +_CAM_ROOT_DIR = os.path.join(_CURRDIR, os.pardir, os.pardir, os.pardir) _CAM_CONF_DIR = os.path.abspath(os.path.join(_CAM_ROOT_DIR, "cime_config")) _PRE_TMP_DIR = os.path.join(_CURRDIR, "tmp") _TMP_DIR = os.path.join(_PRE_TMP_DIR, "cam_build_cache") diff --git a/test/unit/test_cam_autogen.py b/test/unit/python/test_cam_autogen.py similarity index 99% rename from test/unit/test_cam_autogen.py rename to test/unit/python/test_cam_autogen.py index 4a786aab..c5317a65 100644 --- a/test/unit/test_cam_autogen.py +++ b/test/unit/python/test_cam_autogen.py @@ -32,7 +32,7 @@ #Add directory to python path: _CURRDIR = os.path.abspath(os.path.dirname(__file__)) -_CAM_ROOT_DIR = os.path.join(_CURRDIR, os.pardir, os.pardir) +_CAM_ROOT_DIR = os.path.join(_CURRDIR, os.pardir, os.pardir, os.pardir) _CAM_CONF_DIR = os.path.abspath(os.path.join(_CAM_ROOT_DIR, "cime_config")) _CCPP_DIR = os.path.join(_CAM_ROOT_DIR, "ccpp_framework", "scripts") diff --git a/test/unit/test_cam_config.py b/test/unit/python/test_cam_config.py similarity index 99% rename from test/unit/test_cam_config.py rename to test/unit/python/test_cam_config.py index da994535..74e38bee 100644 --- a/test/unit/test_cam_config.py +++ b/test/unit/python/test_cam_config.py @@ -30,7 +30,7 @@ #Add directory to python path: CURRDIR = os.path.abspath(os.path.dirname(__file__)) -CAM_ROOT_DIR = os.path.join(CURRDIR, os.pardir, os.pardir) +CAM_ROOT_DIR = os.path.join(CURRDIR, os.pardir, os.pardir, os.pardir) CAM_CONF_DIR = os.path.abspath(os.path.join(CAM_ROOT_DIR, "cime_config")) #Add "cime_config" directory to python path: diff --git a/test/unit/test_create_readnl_files.py b/test/unit/python/test_create_readnl_files.py similarity index 98% rename from test/unit/test_create_readnl_files.py rename to test/unit/python/test_create_readnl_files.py index 5e92caf9..a6681743 100644 --- a/test/unit/test_create_readnl_files.py +++ b/test/unit/python/test_create_readnl_files.py @@ -22,7 +22,7 @@ import xml.etree.ElementTree as ET _TEST_DIR = os.path.dirname(os.path.abspath(__file__)) -_CAM_ROOT = os.path.abspath(os.path.join(_TEST_DIR, os.pardir, os.pardir)) +_CAM_ROOT = os.path.abspath(os.path.join(_TEST_DIR, os.pardir, os.pardir, os.pardir)) _CCPP_DIR = os.path.join(_CAM_ROOT, "ccpp_framework", "scripts") _CIME_CONFIG_DIR = os.path.join(_CAM_ROOT, "cime_config") _XML_SAMPLES_DIR = os.path.join(_TEST_DIR, "sample_files") @@ -409,18 +409,18 @@ def test_double_namelist_def(self): # Check logger lmsgs = [("INFO:test_double_namelist_def:Reading CAM physics " \ "namelist definition file, ", - "test/unit/sample_files/banana_namelist.xml'"), + "test/unit/python/sample_files/banana_namelist.xml'"), ("INFO:test_double_namelist_def:Writing metadata file, ", - "unit/tmp/namelist_files/banana_namelist.meta"), + "unit/python/tmp/namelist_files/banana_namelist.meta"), ("INFO:test_double_namelist_def:Writing Fortran module, ", - "unit/tmp/namelist_files/banana_namelist.F90"), + "unit/python/tmp/namelist_files/banana_namelist.F90"), ("INFO:test_double_namelist_def:Reading CAM physics " \ "namelist definition file, ", - "test/unit/sample_files/kumquat_namelist.xml'"), + "test/unit/python/sample_files/kumquat_namelist.xml'"), ("INFO:test_double_namelist_def:Writing metadata file, ", - "test/unit/tmp/namelist_files/kumquat_namelist.meta"), + "test/unit/python/tmp/namelist_files/kumquat_namelist.meta"), ("INFO:test_double_namelist_def:Writing Fortran module, ", - "test/unit/tmp/namelist_files/kumquat_namelist.F90")] + "test/unit/python/tmp/namelist_files/kumquat_namelist.F90")] comp_lmsgs = cmp_log.output amsg = "Test failure: Number of log output messages, " \ f"{len(comp_lmsgs)} does not match what is expected, " \ diff --git a/test/unit/test_hist_config.py b/test/unit/python/test_hist_config.py similarity index 99% rename from test/unit/test_hist_config.py rename to test/unit/python/test_hist_config.py index fa5435f6..57fad85f 100644 --- a/test/unit/test_hist_config.py +++ b/test/unit/python/test_hist_config.py @@ -20,7 +20,7 @@ import unittest __TEST_DIR = os.path.dirname(os.path.abspath(__file__)) -_CAM_ROOT = os.path.abspath(os.path.join(__TEST_DIR, os.pardir, os.pardir)) +_CAM_ROOT = os.path.abspath(os.path.join(__TEST_DIR, os.pardir, os.pardir, os.pardir)) __CIME_CONFIG_DIR = os.path.join(_CAM_ROOT, "cime_config") _SAMPLE_FILES_DIR = os.path.join(__TEST_DIR, "sample_files", "hist_config_files") diff --git a/test/unit/test_registry.py b/test/unit/python/test_registry.py similarity index 99% rename from test/unit/test_registry.py rename to test/unit/python/test_registry.py index 6fff5360..adde7797 100644 --- a/test/unit/test_registry.py +++ b/test/unit/python/test_registry.py @@ -22,7 +22,7 @@ import xml.etree.ElementTree as ET __TEST_DIR = os.path.dirname(os.path.abspath(__file__)) -_CAM_ROOT = os.path.abspath(os.path.join(__TEST_DIR, os.pardir, os.pardir)) +_CAM_ROOT = os.path.abspath(os.path.join(__TEST_DIR, os.pardir, os.pardir, os.pardir)) __REGISTRY_DIR = os.path.join(_CAM_ROOT, "src", "data") _SAMPLE_FILES_DIR = os.path.join(__TEST_DIR, "sample_files") _TMP_DIR = os.path.join(__TEST_DIR, "tmp") @@ -325,7 +325,7 @@ def test_diff_src_root_metadata_file_registry(self): remove_files([out_source, out_meta]) # Create new directory: - tmp_src_dir = os.path.join(_TMP_DIR, "test", "unit", \ + tmp_src_dir = os.path.join(_TMP_DIR, "test", "unit", "python", \ "sample_files") if not os.path.exists(tmp_src_dir): os.makedirs(tmp_src_dir) diff --git a/test/unit/test_write_init_files.py b/test/unit/python/test_write_init_files.py similarity index 99% rename from test/unit/test_write_init_files.py rename to test/unit/python/test_write_init_files.py index 903df86d..dd3154b1 100644 --- a/test/unit/test_write_init_files.py +++ b/test/unit/python/test_write_init_files.py @@ -20,7 +20,7 @@ import logging __TEST_DIR = os.path.dirname(os.path.abspath(__file__)) -_CAM_ROOT = os.path.abspath(os.path.join(__TEST_DIR, os.pardir, os.pardir)) +_CAM_ROOT = os.path.abspath(os.path.join(__TEST_DIR, os.pardir, os.pardir, os.pardir)) __CCPP_DIR = os.path.join(_CAM_ROOT, "ccpp_framework", "scripts") __REGISTRY_DIR = os.path.join(_CAM_ROOT, "src", "data") _REG_SAMPLES_DIR = os.path.join(__TEST_DIR, "sample_files") From ddd0301817a127aa12938bd46105bc3fb00f2592 Mon Sep 17 00:00:00 2001 From: Cheryl Craig Date: Wed, 12 Feb 2025 14:20:58 -0700 Subject: [PATCH 16/19] Address reviewer comments --- cime_config/atm_in_paramgen.py | 7 +------ src/data/registry.xml | 9 ++------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/cime_config/atm_in_paramgen.py b/cime_config/atm_in_paramgen.py index b13b0bc3..e41a2056 100644 --- a/cime_config/atm_in_paramgen.py +++ b/cime_config/atm_in_paramgen.py @@ -1495,7 +1495,7 @@ def write(self, output_path): # Write all variables within that group (sorted alphabetically): for var in sorted(self._data[nml_group], key=var_sort_key): #Extract variable value(s): - val = self._data[nml_group][var]["values"] #.strip() + val = self._data[nml_group][var]["values"] #Raise error if no value found: if val is None: @@ -1507,11 +1507,6 @@ def write(self, output_path): val = val.strip() #End if - #If no value is set then move to the next variable: - #if val is None: - # continue - #End if - #Extract variable type: if "type" in self._data[nml_group][var]: var_type = self._data[nml_group][var]["type"].strip() diff --git a/src/data/registry.xml b/src/data/registry.xml index 443740c0..ca875b67 100644 --- a/src/data/registry.xml +++ b/src/data/registry.xml @@ -502,7 +502,6 @@ - horizontal_dimension pblh pbuf_pblh - - horizontal_dimension tpert pbuf_tpert - @@ -548,7 +543,7 @@ access="protected" > 1 - From 8f40effed01f1e5401b8d4904b4c4892487e611d Mon Sep 17 00:00:00 2001 From: Cheryl Craig Date: Thu, 13 Feb 2025 08:56:52 -0700 Subject: [PATCH 17/19] Add ZM testing frameworkd --- .../cam/outfrq_zm_derecho/shell_commands | 1 + .../cam/outfrq_zm_derecho/user_nl_cam | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 cime_config/testdefs/testmods_dirs/cam/outfrq_zm_derecho/shell_commands create mode 100644 cime_config/testdefs/testmods_dirs/cam/outfrq_zm_derecho/user_nl_cam diff --git a/cime_config/testdefs/testmods_dirs/cam/outfrq_zm_derecho/shell_commands b/cime_config/testdefs/testmods_dirs/cam/outfrq_zm_derecho/shell_commands new file mode 100644 index 00000000..39a7de12 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/cam/outfrq_zm_derecho/shell_commands @@ -0,0 +1 @@ + ./xmlchange CAM_CONFIG_OPTS="--dyn none --physics-suites zhang_mcfarlane" diff --git a/cime_config/testdefs/testmods_dirs/cam/outfrq_zm_derecho/user_nl_cam b/cime_config/testdefs/testmods_dirs/cam/outfrq_zm_derecho/user_nl_cam new file mode 100644 index 00000000..5e558274 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/cam/outfrq_zm_derecho/user_nl_cam @@ -0,0 +1,16 @@ +ncdata='/glade/campaign/cesm/community/amwg/sima_baselines/cam_sima_test_snapshots/cam_ne3pg3_ZM_snapshot_derecho_gnu_before_c20250116.nc' +ncdata_check='/glade/campaign/cesm/community/amwg/sima_baselines/cam_sima_test_snapshots/cam_ne3pg3_ZM_snapshot_derecho_gnu_after_c20250116.nc' +debug_output=0 +pver=32 +zmconv_momcd=.7D0 +zmconv_momcu=.7D0 +zmconv_num_cin=1 +hist_add_inst_fields;h1: ZMDT, ZMDQ, CAPE, FREQZM, CMFMC_DP, ZMMU, ZMMD, DLFZM, PCONVT, PCONVB, ZMFLXPRC, ZMFLXSNW +hist_add_inst_fields;h1: ZMNTPRPD, ZMNTSNPD, ZMEIHEAT, PRECCDZM, PRECZ +hist_add_inst_fields;h1: ZMUPGU, ZMUPGD, ZMVPGU, ZMVPGD, ZMICUU, ZMICUD, ZMICVU, ZMICVD +hist_add_inst_fields;h1: EVAPTZM, FZSNTZM, EVSNTZM, EVAPQZM +hist_add_inst_fields;h1: ZMMTU, ZMMTV, ZMMTT +hist_add_inst_fields;h1: ZMDLIQ, ZMDICE +hist_output_frequency;h1: 1*nstep +hist_precision;h1: REAL64 +hist_max_frames;h1: 1 From 0da902413aeb94812ccb939285286a5de0646ee8 Mon Sep 17 00:00:00 2001 From: Jesse Nusbaumer Date: Thu, 13 Feb 2025 11:56:21 -0700 Subject: [PATCH 18/19] Add unit test for new error exception in namelist writing routine. --- src/physics/ncar_ccpp | 2 +- test/unit/python/test_atm_in_paramgen.py | 72 +++++++++++++++++++++++- 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/src/physics/ncar_ccpp b/src/physics/ncar_ccpp index 74e905b7..89b62864 160000 --- a/src/physics/ncar_ccpp +++ b/src/physics/ncar_ccpp @@ -1 +1 @@ -Subproject commit 74e905b7a0ee5b2d2bfc3e3dd942eb9963398373 +Subproject commit 89b628646b1506f36b35e67038552f09fb0662e6 diff --git a/test/unit/python/test_atm_in_paramgen.py b/test/unit/python/test_atm_in_paramgen.py index 5ea26d6c..96872b6e 100644 --- a/test/unit/python/test_atm_in_paramgen.py +++ b/test/unit/python/test_atm_in_paramgen.py @@ -11,7 +11,7 @@ python test_atm_in_paramgen.py -v -which will currently run 23 tests, all of which should pass. +which will currently run 24 tests, all of which should pass. """ #---------------------------------------- @@ -279,6 +279,76 @@ def test_namelist_from_xml_using_multi_attrs(self): #++++++++++++++++++++++++++++++++++++++++++++++++ + def test_namelist_xml_bad_value_entry(self): + + """ + Check that AtmInParamGen throws the correct + error message when an XML namelist file + has an entry with a non-valid value. + """ + + # Create fake CIME case: + fcase = FakeCase() + + # Create namelist attribute dictionary: + nml_attr_dict = {"bird" : "goose", "never_read" : "0"} + + # Get XML file path to original sample file: + xml_base_fil = os.path.join(_SAMPLES_DIR, "test_simple_nml_def.xml") + + # Open base XML file: + base_tree = ET.parse(xml_base_fil) + base_root = base_tree.getroot() + + # Write new namelist entry with "bad" value: + bad_namelist_string = \ + """ + + integer + more_testing + please_fail + + Let's make sure we don't have + a good default value + Default: None! + + + 3 + 5 + + + """ + + bad_xml_entry = ET.fromstring(bad_namelist_string) + + # Add new namelist entry back to original namelist XML tree: + base_root.append(bad_xml_entry) + + # Write out new, temporary XML namelist file for testing: + xml_test_fil = os.path.join(_TMP_DIR, "test_bad_value_nml_def.xml") + base_tree.write(xml_test_fil, encoding="utf-8", xml_declaration=True) + + # Create ParamGen object: + pg_test = AtmInParamGen.from_namelist_xml(xml_test_fil) + + # Set all ParamGen namelist values: + pg_test.reduce_atm_in(fcase, nml_attr_dict) + + # Set atm_in filename to write to (should never get to this point): + test_output = os.path.join(_TMP_DIR, "test_bad_xml_value_entry_in") + + # Attempt to write namelist using ParamGen: + with self.assertRaises(AtmInParamGenError) as cerr: + pg_test.write(test_output) + + # Check exception message + emsg = "Namelist entry 'bad_default_entry' is missing" + emsg += " a valid/default 'value' element." + + self.assertEqual(emsg, str(cerr.exception)) + + #++++++++++++++++++++++++++++++++++++++++++++++++ + def test_namelist_xml_missing_elems(self): """ From 8b4d5417ab00b6a6e2d09b00c0a35812055605bf Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Fri, 14 Feb 2025 15:55:58 -0500 Subject: [PATCH 19/19] Update teout standard name for check_energy; bring in check_energy diagnostic output (#339) Tag name (required for release branches): sima0_03_000 Originator(s): @jimmielin Description (include the issue title, and the keyword ['closes', 'fixes', 'resolves'] followed by the issue number): Closes https://github.com/ESCOMP/atmospheric_physics/issues/161, https://github.com/ESCOMP/atmospheric_physics/issues/166, https://github.com/ESCOMP/atmospheric_physics/issues/176: - Fixes Add check_energy related history output variables to check_energy_diagnostics https://github.com/ESCOMP/atmospheric_physics/issues/161 - Fixes Need to remove old CAM suite definition files [#166](https://github.com/ESCOMP/atmospheric_physics/issues/166) as well (but other PRs might get to it first) since I'm modifying the SDF files in this PR anyway - Fixes Update standard name for teout [#176](https://github.com/ESCOMP/atmospheric_physics/issues/176) (updates teout standard name to vertically_integrated_total_energy_using_dycore_energy_formula_at_end_of_physics_timestep) Companion PRs: - https://github.com/ESCOMP/atmospheric_physics/pull/178 - https://github.com/ESCOMP/atmospheric_physics/pull/169 Describe any changes made to build system: N/A Describe any changes made to the namelist: N/A List any changes to the defaults for the input datasets (e.g. boundary datasets): N/A List all files eliminated and why: N/A List all files added and what they do: N/A List all existing files that have been modified, and describe the changes: (Helpful git command: `git diff --name-status development...`) ``` Updates teout standard name to vertically_integrated_total_energy_using_dycore_energy_formula_at_end_of_physics_timestep M src/data/registry.xml M src/dynamics/mpas/dyn_comp.F90 M src/dynamics/none/dyn_grid.F90 M src/dynamics/se/dyn_comp.F90 Updates atmospheric_physics submodule. M .gitmodules M src/physics/ncar_ccpp Notes that CAM7 test is preexisting failure. M test/existing-test-failures.txt ``` If there are new failures (compared to the `test/existing-test-failures.txt` file), have them OK'd by the gatekeeper, note them here, and add them to the file. If there are baseline differences, include the test and the reason for the diff. What is the nature of the change? Roundoff? ``` derecho/intel/aux_sima: SMS_Ln9.mpasa480_mpasa480.FKESSLER.derecho_intel.cam-outfrq_kessler_mpas_derecho (Overall: DIFF) details: SMS_Ln9.ne5pg3_ne5pg3_mg37.FKESSLER.derecho_intel.cam-outfrq_se_cslam (Overall: DIFF) details: SMS_Ln9.ne5pg3_ne5pg3_mg37.FTJ16.derecho_intel.cam-outfrq_se_cslam (Overall: DIFF) details: - baseline differences due to new thermo_water_update scheme in Kessler and TJ2016. SMS_Ln9.ne5pg3_ne5pg3_mg37.FCAM7.derecho_intel.cam-outfrq_se_cslam_analy_ic (Overall: FAIL) details: - pre-existing failure in CAM7 tests ``` ``` derecho/gnu/aux_sima: SMS_Ln2.ne3pg3_ne3pg3_mg37.FPHYStest.derecho_gnu.cam-outfrq_kessler_derecho (Overall: NLFAIL) details: FAIL SMS_Ln2.ne3pg3_ne3pg3_mg37.FPHYStest.derecho_gnu.cam-outfrq_kessler_derecho NLCOMP - suite_kessler.xml changed to suite_kessler_test.xml, NLCOMP failure for physics_suite. the actual run passes BFB SMS_Ln9.mpasa480_mpasa480.FKESSLER.derecho_gnu.cam-outfrq_kessler_mpas_derecho (Overall: DIFF) details: SMS_Ln9.ne5pg3_ne5pg3_mg37.FKESSLER.derecho_gnu.cam-outfrq_se_cslam (Overall: DIFF) details: SMS_Ln9.ne5pg3_ne5pg3_mg37.FTJ16.derecho_gnu.cam-outfrq_se_cslam (Overall: DIFF) details: - baseline differences due to new thermo_water_update scheme in Kessler and TJ2016. SMS_Ln9.ne5pg3_ne5pg3_mg37.FCAM7.derecho_gnu.cam-outfrq_se_cslam_analy_ic (Overall: FAIL) details: - pre-existing failure in CAM7 tests ``` If this changes climate describe any run(s) done to evaluate the new climate in enough detail that it(they) could be reproduced: CAM-SIMA date used for the baseline comparison tests if different than latest: --- .gitmodules | 2 +- .../testmods_dirs/cam/outfrq_kessler_derecho/shell_commands | 2 +- src/data/registry.xml | 4 ++-- src/dynamics/mpas/dyn_comp.F90 | 2 +- src/dynamics/none/dyn_grid.F90 | 2 +- src/dynamics/se/dyn_comp.F90 | 2 +- src/physics/ncar_ccpp | 2 +- test/existing-test-failures.txt | 5 ++++- 8 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.gitmodules b/.gitmodules index ff98f992..257ce8a2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -20,7 +20,7 @@ [submodule "ncar-physics"] path = src/physics/ncar_ccpp url = https://github.com/ESCOMP/atmospheric_physics - fxtag = atmos_phys0_08_000 + fxtag = 252b500a93c89f36ece7d8ba08fd8eb025279eaa fxrequired = AlwaysRequired fxDONOTUSEurl = https://github.com/ESCOMP/atmospheric_physics [submodule "ccs_config"] diff --git a/cime_config/testdefs/testmods_dirs/cam/outfrq_kessler_derecho/shell_commands b/cime_config/testdefs/testmods_dirs/cam/outfrq_kessler_derecho/shell_commands index fbf520ab..617bfa8e 100644 --- a/cime_config/testdefs/testmods_dirs/cam/outfrq_kessler_derecho/shell_commands +++ b/cime_config/testdefs/testmods_dirs/cam/outfrq_kessler_derecho/shell_commands @@ -1 +1 @@ - ./xmlchange CAM_CONFIG_OPTS="--dyn none --physics-suites kessler" + ./xmlchange CAM_CONFIG_OPTS="--dyn none --physics-suites kessler_test" diff --git a/src/data/registry.xml b/src/data/registry.xml index ca875b67..f0c5c858 100644 --- a/src/data/registry.xml +++ b/src/data/registry.xml @@ -256,7 +256,7 @@ tw_cur state_tw_cur Total energy using dynamical core formula at the end of physics timestep @@ -343,7 +343,7 @@ vertically_integrated_total_energy_using_dycore_energy_formula vertically_integrated_total_water_at_start_of_physics_timestep vertically_integrated_total_water - vertically_integrated_total_energy_at_end_of_physics_timestep + vertically_integrated_total_energy_using_dycore_energy_formula_at_end_of_physics_timestep tendency_of_air_temperature_due_to_model_physics diff --git a/src/dynamics/mpas/dyn_comp.F90 b/src/dynamics/mpas/dyn_comp.F90 index f6e3a10a..0ef66d33 100644 --- a/src/dynamics/mpas/dyn_comp.F90 +++ b/src/dynamics/mpas/dyn_comp.F90 @@ -1072,8 +1072,8 @@ subroutine mark_variables_as_initialized() ! While we are not responsible for initializing or updating them, we still need to help mark them as initialized. ! These variables are to be set externally by the `check_energy_chng` CCPP physics scheme. - call mark_as_initialized('vertically_integrated_total_energy_at_end_of_physics_timestep') call mark_as_initialized('vertically_integrated_total_energy_using_dycore_energy_formula') + call mark_as_initialized('vertically_integrated_total_energy_using_dycore_energy_formula_at_end_of_physics_timestep') call mark_as_initialized('vertically_integrated_total_energy_using_dycore_energy_formula_at_start_of_physics_timestep') call mark_as_initialized('vertically_integrated_total_energy_using_physics_energy_formula') call mark_as_initialized('vertically_integrated_total_energy_using_physics_energy_formula_at_start_of_physics_timestep') diff --git a/src/dynamics/none/dyn_grid.F90 b/src/dynamics/none/dyn_grid.F90 index ba1bf0ba..8d2b0431 100644 --- a/src/dynamics/none/dyn_grid.F90 +++ b/src/dynamics/none/dyn_grid.F90 @@ -703,7 +703,7 @@ subroutine find_energy_formula(file, grid_is_latlon) call mark_as_initialized("vertically_integrated_total_energy_using_dycore_energy_formula") call mark_as_initialized("vertically_integrated_total_water_at_start_of_physics_timestep") call mark_as_initialized("vertically_integrated_total_water") - call mark_as_initialized("vertically_integrated_total_energy_at_end_of_physics_timestep") + call mark_as_initialized("vertically_integrated_total_energy_using_dycore_energy_formula_at_end_of_physics_timestep") end subroutine find_energy_formula diff --git a/src/dynamics/se/dyn_comp.F90 b/src/dynamics/se/dyn_comp.F90 index 4f70ae2c..3ce1fee6 100644 --- a/src/dynamics/se/dyn_comp.F90 +++ b/src/dynamics/se/dyn_comp.F90 @@ -1873,7 +1873,7 @@ subroutine read_inidat(dyn_in) call mark_as_initialized("vertically_integrated_total_energy_using_dycore_energy_formula") call mark_as_initialized("vertically_integrated_total_water_at_start_of_physics_timestep") call mark_as_initialized("vertically_integrated_total_water") - call mark_as_initialized("vertically_integrated_total_energy_at_end_of_physics_timestep") + call mark_as_initialized("vertically_integrated_total_energy_using_dycore_energy_formula_at_end_of_physics_timestep") end subroutine read_inidat diff --git a/src/physics/ncar_ccpp b/src/physics/ncar_ccpp index 89b62864..252b500a 160000 --- a/src/physics/ncar_ccpp +++ b/src/physics/ncar_ccpp @@ -1 +1 @@ -Subproject commit 89b628646b1506f36b35e67038552f09fb0662e6 +Subproject commit 252b500a93c89f36ece7d8ba08fd8eb025279eaa diff --git a/test/existing-test-failures.txt b/test/existing-test-failures.txt index 2328b59d..75ca84fd 100644 --- a/test/existing-test-failures.txt +++ b/test/existing-test-failures.txt @@ -1 +1,4 @@ -All clear! +SMS_Ln9.ne5pg3_ne5pg3_mg37.FCAM7.derecho_intel.cam-outfrq_se_cslam_analy_ic (Overall: FAIL) details: +SMS_Ln9.ne5pg3_ne5pg3_mg37.FCAM7.derecho_gnu.cam-outfrq_se_cslam_analy_ic (Overall: FAIL) details: +- CAM7 suite will not work without a PBL scheme +- CAM7 suite will not work with snapshot fields in registry.xml even if initial_value is defined (CAM-SIMA#359)