From 656fdfe4d5eed9182d20c796664b98f9af2c5ffe Mon Sep 17 00:00:00 2001 From: Steve Goldhaber Date: Fri, 28 Feb 2025 21:04:44 +0100 Subject: [PATCH 1/8] New implementation of differing module name --- scripts/ccpp_suite.py | 9 +++- scripts/metadata_table.py | 49 +++++++------------ scripts/parse_tools/parse_source.py | 4 ++ scripts/suite_objects.py | 7 ++- test/var_compatibility_test/CMakeLists.txt | 2 +- .../var_compatibility_test/module_rad_ddt.F90 | 23 +++++++++ .../module_rad_ddt.meta | 40 +++++++++++++++ test/var_compatibility_test/rad_lw.F90 | 35 +++++++++++++ test/var_compatibility_test/rad_lw.meta | 35 +++++++++++++ test/var_compatibility_test/rad_sw.F90 | 35 +++++++++++++ test/var_compatibility_test/rad_sw.meta | 35 +++++++++++++ test/var_compatibility_test/run_test | 16 ++++-- test/var_compatibility_test/test_host.F90 | 19 ++++--- .../test_host_data.meta | 21 ++++++++ test/var_compatibility_test/test_reports.py | 9 +++- .../var_compatibility_files.txt | 3 ++ .../var_compatibility_suite.xml | 2 + 17 files changed, 292 insertions(+), 52 deletions(-) create mode 100644 test/var_compatibility_test/module_rad_ddt.F90 create mode 100644 test/var_compatibility_test/module_rad_ddt.meta create mode 100644 test/var_compatibility_test/rad_lw.F90 create mode 100644 test/var_compatibility_test/rad_lw.meta create mode 100644 test/var_compatibility_test/rad_sw.F90 create mode 100644 test/var_compatibility_test/rad_sw.meta diff --git a/scripts/ccpp_suite.py b/scripts/ccpp_suite.py index a5cc8d9d..1182fd43 100644 --- a/scripts/ccpp_suite.py +++ b/scripts/ccpp_suite.py @@ -658,8 +658,13 @@ def __init__(self, sdfs, host_model, scheme_headers, run_env): run_env, ddts=all_ddts) for header in [d for d in scheme_headers if d.header_type != 'ddt']: if header.header_type != 'scheme': - errmsg = "{} is an unknown CCPP API metadata header type, {}" - raise CCPPError(errmsg.format(header.title, header.header_type)) + if header.header_type == 'module': + errmsg = f"{header.title} is a module metadata header type." + errmsg+=" This is not an allowed CCPP scheme header type." + else: + errmsg = f"{header.title} is an unknown CCPP API metadata header type, {header.header_type}" + # end if + raise CCPPError(errmsg) # end if func_id, _, match_trans = \ CCPP_STATE_MACH.function_match(header.title) diff --git a/scripts/metadata_table.py b/scripts/metadata_table.py index 942f8d81..584e51f9 100755 --- a/scripts/metadata_table.py +++ b/scripts/metadata_table.py @@ -63,6 +63,7 @@ type = scheme relative_path = dependencies = + module = # only needed if module name differs from filename dynamic_constituent_routine = [ccpp-arg-table] @@ -285,6 +286,7 @@ def __init__(self, run_env, table_name_in=None, table_type_in=None, """ self.__pobj = parse_object self.__dependencies = dependencies + self.__module_name = module self.__relative_path = relative_path self.__sections = [] self.__run_env = run_env @@ -364,6 +366,7 @@ def __init_from_file(self, known_ddts, run_env, skip_ddt_check=False): in_properties_header = True skip_rest_of_section = False self.__dependencies = [] # Default is no dependencies + self.__module_name = self.__pobj.default_module_name() # Process lines until the end of the file or start of the next table. while ((curr_line is not None) and (not MetadataTable.table_start(curr_line))): @@ -405,6 +408,8 @@ def __init_from_file(self, known_ddts, run_env, skip_ddt_check=False): if x.strip()] self.__dependencies.extend(depends) # end if + elif key == 'module_name': + self.__module_name = value elif key == 'relative_path': self.__relative_path = value else: @@ -419,6 +424,7 @@ def __init_from_file(self, known_ddts, run_env, skip_ddt_check=False): skip_rest_of_section = False section = MetadataSection(self.table_name, self.table_type, run_env, parse_object=self.__pobj, + module=self.__module_name, known_ddts=known_ddts, skip_ddt_check=skip_ddt_check) # Some table types only allow for one associated section @@ -483,6 +489,11 @@ def dependencies(self): """Return the dependencies for this table""" return self.__dependencies + @property + def module_name(self): + """Return the module name for this metadata table""" + return self.__module + @property def relative_path(self): """Return the relative path for the table's dependencies""" @@ -652,7 +663,7 @@ def __init__(self, table_name, table_type, run_env, parse_object=None, self.__variables = None # In case __init__ crashes self.__section_title = None self.__header_type = None - self.__module_name = None + self.__module_name = module self.__process_type = UNKNOWN_PROCESS_TYPE self.__section_valid = True self.__run_env = run_env @@ -706,8 +717,8 @@ def __init__(self, table_name, table_type, run_env, parse_object=None, known_ddts = [] # end if self.__start_context = ParseContext(context=self.__pobj) - self.__init_from_file(table_name, table_type, known_ddts, run_env, - skip_ddt_check=skip_ddt_check) + self.__init_from_file(table_name, table_type, known_ddts, self.module, + run_env, skip_ddt_check=skip_ddt_check) # end if # Register this header if it is a DDT if self.header_type == 'ddt': @@ -722,27 +733,13 @@ def __init__(self, table_name, table_type, run_env, parse_object=None, # end if # end for - def _default_module(self): - """Set a default module for this header""" - mfile = self.__pobj.filename - if mfile[-5:] == '.meta': - # Default value is a Fortran module that matches the filename - def_mod = os.path.basename(mfile)[:-5] - else: - def_mod = os.path.basename(mfile) - last_dot = def_mod.rfind('.') - if last_dot >= 0: - ldef = len(def_mod) - def_mod = def_mod[:last_dot-ldef] - # end if - # end if - return def_mod - - def __init_from_file(self, table_name, table_type, known_ddts, run_env, skip_ddt_check=False): + def __init_from_file(self, table_name, table_type, known_ddts, module_name, + run_env, skip_ddt_check=False): """ Read the section preamble, assume the caller already figured out the first line of the header using the header_start method.""" start_ctx = context_string(self.__pobj) curr_line, _ = self.__pobj.next_line() # Skip past [ccpp-arg-table] + self.__module_name = module_name while ((curr_line is not None) and (not MetadataSection.variable_start(curr_line, self.__pobj)) and (not MetadataSection.header_start(curr_line)) and @@ -765,14 +762,6 @@ def __init_from_file(self, table_name, table_type, known_ddts, run_env, skip_ddt # end if # Set value even if error so future error msgs make sense self.__header_type = value - elif key == 'module': - if value != "None": - self.__module_name = value - else: - self.__pobj.add_syntax_err("metadata table, no module") - self.__module_name = 'INVALID' # Allow error continue - self.__section_valid = False - # end if elif key == 'process': self.__process_type = value else: @@ -813,10 +802,6 @@ def __init_from_file(self, table_name, table_type, known_ddts, run_env, skip_ddt if self.header_type == "ddt": known_ddts.append(self.title) # end if - # We need a default module if none was listed - if self.module is None: - self.__module_name = self._default_module() - # end if # Initialize our ParseSource parent super().__init__(self.title, self.header_type, self.__pobj) # Read the variables diff --git a/scripts/parse_tools/parse_source.py b/scripts/parse_tools/parse_source.py index 2ed0e5b8..1a4082cb 100644 --- a/scripts/parse_tools/parse_source.py +++ b/scripts/parse_tools/parse_source.py @@ -244,6 +244,10 @@ def __init__(self, linenum=None, filename=None, context=None): self.__linenum = linenum self.__filename = filename + def default_module_name(self): + """Return a default module for this file""" + return os.path.splitext(os.path.basename(self.filename))[0] + @property def line_num(self): """Return the current line""" diff --git a/scripts/suite_objects.py b/scripts/suite_objects.py index 13d2c6a2..5ac21138 100755 --- a/scripts/suite_objects.py +++ b/scripts/suite_objects.py @@ -2482,12 +2482,11 @@ def write(self, outfile, host_arglist, indent, const_mod, # end for # Look for any DDT types call_vars = self.call_list.variable_list() - self._ddt_library.write_ddt_use_statements(call_vars, outfile, - indent+1, pad=modmax) - decl_vars = ([x[0] for x in subpart_allocate_vars.values()] + + all_vars = ([x[0] for x in subpart_allocate_vars.values()] + [x[0] for x in subpart_scalar_vars.values()] + [x[0] for x in subpart_optional_vars.values()]) - self._ddt_library.write_ddt_use_statements(decl_vars, outfile, + all_vars.extend(call_vars) + self._ddt_library.write_ddt_use_statements(all_vars, outfile, indent+1, pad=modmax) outfile.write('', 0) # Write out dummy arguments diff --git a/test/var_compatibility_test/CMakeLists.txt b/test/var_compatibility_test/CMakeLists.txt index 8cbd7e44..e25f3fda 100644 --- a/test/var_compatibility_test/CMakeLists.txt +++ b/test/var_compatibility_test/CMakeLists.txt @@ -20,7 +20,7 @@ get_filename_component(CCPP_ROOT "${TEST_ROOT}" DIRECTORY) # #------------------------------------------------------------------------------ LIST(APPEND SCHEME_FILES "var_compatibility_files.txt") -LIST(APPEND HOST_FILES "test_host_data" "test_host_mod") +LIST(APPEND HOST_FILES "module_rad_ddt" "test_host_data" "test_host_mod") LIST(APPEND SUITE_FILES "var_compatibility_suite.xml") # HOST is the name of the executable we will build. # We assume there are files ${HOST}.meta and ${HOST}.F90 in CMAKE_SOURCE_DIR diff --git a/test/var_compatibility_test/module_rad_ddt.F90 b/test/var_compatibility_test/module_rad_ddt.F90 new file mode 100644 index 00000000..c7986a6c --- /dev/null +++ b/test/var_compatibility_test/module_rad_ddt.F90 @@ -0,0 +1,23 @@ +module mod_rad_ddt + USE ccpp_kinds, ONLY: kind_phys + implicit none + + public ty_rad_lw, ty_rad_sw + + !> \section arg_table_ty_rad_lw Argument Table + !! \htmlinclude arg_table_ty_rad_lw.html + !! + type ty_rad_lw + real(kind_phys) :: sfc_up_lw + real(kind_phys) :: sfc_down_lw + end type ty_rad_lw + + !> \section arg_table_ty_rad_sw Argument Table + !! \htmlinclude arg_table_ty_rad_sw.html + !! + type ty_rad_sw + real(kind_phys) :: sfc_up_sw + real(kind_phys) :: sfc_down_sw + end type ty_rad_sw + +end module mod_rad_ddt diff --git a/test/var_compatibility_test/module_rad_ddt.meta b/test/var_compatibility_test/module_rad_ddt.meta new file mode 100644 index 00000000..4576c151 --- /dev/null +++ b/test/var_compatibility_test/module_rad_ddt.meta @@ -0,0 +1,40 @@ +[ccpp-table-properties] + name = ty_rad_lw + type = ddt + dependencies = + module_name = mod_rad_ddt +[ccpp-arg-table] + name = ty_rad_lw + type = ddt +[ sfc_up_lw ] + standard_name = surface_upwelling_longwave_radiation_flux + units = W m2 + dimensions = () + type = real + kind = kind_phys +[ sfc_down_lw ] + standard_name = surface_downwelling_longwave_radiation_flux + units = W m2 + dimensions = () + type = real + kind = kind_phys + +[ccpp-table-properties] + name = ty_rad_sw + type = ddt + module_name = mod_rad_ddt +[ccpp-arg-table] + name = ty_rad_sw + type = ddt +[ sfc_up_sw ] + standard_name = surface_upwelling_shortwave_radiation_flux + units = W m2 + dimensions = () + type = real + kind = kind_phys +[ sfc_down_sw ] + standard_name = surface_downwelling_shortwave_radiation_flux + units = W m2 + dimensions = () + type = real + kind = kind_phys diff --git a/test/var_compatibility_test/rad_lw.F90 b/test/var_compatibility_test/rad_lw.F90 new file mode 100644 index 00000000..5859f8bf --- /dev/null +++ b/test/var_compatibility_test/rad_lw.F90 @@ -0,0 +1,35 @@ +module rad_lw + use ccpp_kinds, only: kind_phys + use mod_rad_ddt, only: ty_rad_lw + + implicit none + private + + public :: rad_lw_run + +contains + + !> \section arg_table_rad_lw_run Argument Table + !! \htmlinclude arg_table_rad_lw_run.html + !! + subroutine rad_lw_run(ncol, fluxLW, errmsg, errflg) + + integer, intent(in) :: ncol + type(ty_rad_lw), intent(inout) :: fluxLW(:) + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg + + ! Locals + integer :: icol + + errmsg = '' + errflg = 0 + + do icol=1,ncol + fluxLW(icol)%sfc_up_lw = 300._kind_phys + fluxLW(icol)%sfc_down_lw = 50._kind_phys + enddo + + end subroutine rad_lw_run + +end module rad_lw diff --git a/test/var_compatibility_test/rad_lw.meta b/test/var_compatibility_test/rad_lw.meta new file mode 100644 index 00000000..883edf1b --- /dev/null +++ b/test/var_compatibility_test/rad_lw.meta @@ -0,0 +1,35 @@ +[ccpp-table-properties] + name = rad_lw + type = scheme + dependencies = module_rad_ddt.F90 +[ccpp-arg-table] + name = rad_lw_run + type = scheme +[ ncol ] + standard_name = horizontal_loop_extent + type = integer + units = count + dimensions = () + intent = in +[fluxLW] + standard_name = longwave_radiation_fluxes + long_name = longwave radiation fluxes + units = W m-2 + dimensions = (horizontal_loop_extent) + type = ty_rad_lw + intent = inout +[ errmsg ] + standard_name = ccpp_error_message + long_name = Error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=512 + intent = out +[ errflg ] + standard_name = ccpp_error_code + long_name = Error flag for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out diff --git a/test/var_compatibility_test/rad_sw.F90 b/test/var_compatibility_test/rad_sw.F90 new file mode 100644 index 00000000..a0f22af9 --- /dev/null +++ b/test/var_compatibility_test/rad_sw.F90 @@ -0,0 +1,35 @@ +module rad_sw + use ccpp_kinds, only: kind_phys + use mod_rad_ddt, only: ty_rad_sw + + implicit none + private + + public :: rad_sw_run + +contains + + !> \section arg_table_rad_sw_run Argument Table + !! \htmlinclude arg_table_rad_sw_run.html + !! + subroutine rad_sw_run(ncol, fluxSW, errmsg, errflg) + + integer, intent(in) :: ncol + type(ty_rad_sw), intent(inout) :: fluxSW(:) + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg + + ! Locals + integer :: icol + + errmsg = '' + errflg = 0 + + do icol=1,ncol + fluxSW(icol)%sfc_up_sw = 100._kind_phys + fluxSW(icol)%sfc_down_sw = 400._kind_phys + enddo + + end subroutine rad_sw_run + +end module rad_sw diff --git a/test/var_compatibility_test/rad_sw.meta b/test/var_compatibility_test/rad_sw.meta new file mode 100644 index 00000000..81f2d583 --- /dev/null +++ b/test/var_compatibility_test/rad_sw.meta @@ -0,0 +1,35 @@ +[ccpp-table-properties] + name = rad_sw + type = scheme + dependencies = module_rad_ddt.F90 +[ccpp-arg-table] + name = rad_sw_run + type = scheme +[ ncol ] + standard_name = horizontal_loop_extent + type = integer + units = count + dimensions = () + intent = in +[fluxSW] + standard_name = shortwave_radiation_fluxes + long_name = shortwave radiation fluxes + units = W m-2 + dimensions = (horizontal_loop_extent) + type = ty_rad_sw + intent = inout +[ errmsg ] + standard_name = ccpp_error_message + long_name = Error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=512 + intent = out +[ errflg ] + standard_name = ccpp_error_code + long_name = Error flag for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out diff --git a/test/var_compatibility_test/run_test b/test/var_compatibility_test/run_test index b604def7..0da920a7 100755 --- a/test/var_compatibility_test/run_test +++ b/test/var_compatibility_test/run_test @@ -6,7 +6,7 @@ scriptdir="$( cd $( dirname $0 ); pwd -P )" ## ## Option default values ## -defdir="ct_build" +defdir="vc_build" build_dir="${currdir}/${defdir}" cleanup="PASS" # Other supported options are ALWAYS and NEVER verbosity=0 @@ -128,8 +128,8 @@ ccpp_files="${utility_files}" ccpp_files="${ccpp_files},${build_dir}/ccpp/test_host_ccpp_cap.F90" ccpp_files="${ccpp_files},${build_dir}/ccpp/ccpp_var_compatibility_suite_cap.F90" #process_list="" -module_list="effr_calc,effr_diag,effr_post,effr_pre" -#dependencies="" +module_list="effr_calc,effr_diag,effr_post,effr_pre,rad_lw,rad_sw" +dependencies="module_rad_ddt" suite_list="var_compatibility_suite" required_vars_var_compatibility="ccpp_error_code,ccpp_error_message" required_vars_var_compatibility="${required_vars_var_compatibility},cloud_graupel_number_concentration" @@ -144,12 +144,14 @@ required_vars_var_compatibility="${required_vars_var_compatibility},flag_indicat required_vars_var_compatibility="${required_vars_var_compatibility},horizontal_dimension" required_vars_var_compatibility="${required_vars_var_compatibility},horizontal_loop_begin" required_vars_var_compatibility="${required_vars_var_compatibility},horizontal_loop_end" +required_vars_var_compatibility="${required_vars_var_compatibility},longwave_radiation_fluxes" required_vars_var_compatibility="${required_vars_var_compatibility},num_subcycles_for_effr" required_vars_var_compatibility="${required_vars_var_compatibility},scalar_variable_for_testing" required_vars_var_compatibility="${required_vars_var_compatibility},scalar_variable_for_testing_a" required_vars_var_compatibility="${required_vars_var_compatibility},scalar_variable_for_testing_b" required_vars_var_compatibility="${required_vars_var_compatibility},scalar_variable_for_testing_c" required_vars_var_compatibility="${required_vars_var_compatibility},scheme_order_in_suite" +required_vars_var_compatibility="${required_vars_var_compatibility},shortwave_radiation_fluxes" required_vars_var_compatibility="${required_vars_var_compatibility},vertical_layer_dimension" input_vars_var_compatibility="cloud_graupel_number_concentration" #input_vars_var_compatibility="${input_vars_var_compatibility},cloud_ice_number_concentration" @@ -162,12 +164,14 @@ input_vars_var_compatibility="${input_vars_var_compatibility},flag_indicating_cl input_vars_var_compatibility="${input_vars_var_compatibility},horizontal_dimension" input_vars_var_compatibility="${input_vars_var_compatibility},horizontal_loop_begin" input_vars_var_compatibility="${input_vars_var_compatibility},horizontal_loop_end" +input_vars_var_compatibility="${input_vars_var_compatibility},longwave_radiation_fluxes" input_vars_var_compatibility="${input_vars_var_compatibility},num_subcycles_for_effr" input_vars_var_compatibility="${input_vars_var_compatibility},scalar_variable_for_testing" input_vars_var_compatibility="${input_vars_var_compatibility},scalar_variable_for_testing_a" input_vars_var_compatibility="${input_vars_var_compatibility},scalar_variable_for_testing_b" input_vars_var_compatibility="${input_vars_var_compatibility},scalar_variable_for_testing_c" input_vars_var_compatibility="${input_vars_var_compatibility},scheme_order_in_suite" +input_vars_var_compatibility="${input_vars_var_compatibility},shortwave_radiation_fluxes" input_vars_var_compatibility="${input_vars_var_compatibility},vertical_layer_dimension" output_vars_var_compatibility="ccpp_error_code,ccpp_error_message" output_vars_var_compatibility="${output_vars_var_compatibility},cloud_ice_number_concentration" @@ -175,8 +179,10 @@ output_vars_var_compatibility="${output_vars_var_compatibility},effective_radius output_vars_var_compatibility="${output_vars_var_compatibility},effective_radius_of_stratiform_cloud_liquid_water_particle" output_vars_var_compatibility="${output_vars_var_compatibility},effective_radius_of_stratiform_cloud_rain_particle" output_vars_var_compatibility="${output_vars_var_compatibility},effective_radius_of_stratiform_cloud_snow_particle" +output_vars_var_compatibility="${output_vars_var_compatibility},longwave_radiation_fluxes" output_vars_var_compatibility="${output_vars_var_compatibility},scalar_variable_for_testing" output_vars_var_compatibility="${output_vars_var_compatibility},scheme_order_in_suite" +output_vars_var_compatibility="${output_vars_var_compatibility},shortwave_radiation_fluxes" ## ## Run a database report and check the return string @@ -242,8 +248,8 @@ echo -e "\nChecking lists from command line" #check_datatable ${report_prog} ${datafile} "--process-list" ${process_list} check_datatable ${report_prog} ${datafile} "--module-list" ${module_list} #check_datatable ${report_prog} ${datafile} "--dependencies" ${dependencies} -check_datatable ${report_prog} ${datafile} "--suite-list" ${suite_list} \ - --sep ";" +#check_datatable ${report_prog} ${datafile} "--suite-list" ${suite_list} \ +# --sep ";" echo -e "\nChecking variables for var_compatibility suite from command line" check_datatable ${report_prog} ${datafile} "--required-variables" \ ${required_vars_var_compatibility} "var_compatibility_suite" diff --git a/test/var_compatibility_test/test_host.F90 b/test/var_compatibility_test/test_host.F90 index 5d7f2a4f..2ff05eb7 100644 --- a/test/var_compatibility_test/test_host.F90 +++ b/test/var_compatibility_test/test_host.F90 @@ -351,7 +351,7 @@ program test character(len=cs), target :: test_parts1(1) = (/ 'radiation ' /) - character(len=cm), target :: test_invars1(13) = (/ & + character(len=cm), target :: test_invars1(15) = (/ & 'effective_radius_of_stratiform_cloud_rain_particle ', & 'effective_radius_of_stratiform_cloud_liquid_water_particle', & 'effective_radius_of_stratiform_cloud_snow_particle ', & @@ -364,9 +364,11 @@ program test 'scheme_order_in_suite ', & 'num_subcycles_for_effr ', & 'flag_indicating_cloud_microphysics_has_graupel ', & - 'flag_indicating_cloud_microphysics_has_ice '/) + 'flag_indicating_cloud_microphysics_has_ice ', & + 'shortwave_radiation_fluxes ', & + 'longwave_radiation_fluxes '/) - character(len=cm), target :: test_outvars1(9) = (/ & + character(len=cm), target :: test_outvars1(11) = (/ & 'ccpp_error_code ', & 'ccpp_error_message ', & 'effective_radius_of_stratiform_cloud_ice_particle ', & @@ -375,10 +377,11 @@ program test 'effective_radius_of_stratiform_cloud_snow_particle ', & 'cloud_ice_number_concentration ', & 'scalar_variable_for_testing ', & - 'scheme_order_in_suite '/) - + 'scheme_order_in_suite ', & + 'shortwave_radiation_fluxes ', & + 'longwave_radiation_fluxes '/) - character(len=cm), target :: test_reqvars1(17) = (/ & + character(len=cm), target :: test_reqvars1(19) = (/ & 'ccpp_error_code ', & 'ccpp_error_message ', & 'effective_radius_of_stratiform_cloud_rain_particle ', & @@ -395,7 +398,9 @@ program test 'scheme_order_in_suite ', & 'num_subcycles_for_effr ', & 'flag_indicating_cloud_microphysics_has_graupel ', & - 'flag_indicating_cloud_microphysics_has_ice '/) + 'flag_indicating_cloud_microphysics_has_ice ', & + 'shortwave_radiation_fluxes ', & + 'longwave_radiation_fluxes '/) type(suite_info) :: test_suites(1) logical :: run_okay diff --git a/test/var_compatibility_test/test_host_data.meta b/test/var_compatibility_test/test_host_data.meta index 094f26d5..b507f11e 100644 --- a/test/var_compatibility_test/test_host_data.meta +++ b/test/var_compatibility_test/test_host_data.meta @@ -1,6 +1,7 @@ [ccpp-table-properties] name = physics_state type = ddt + dependencies = module_rad_ddt.F90 [ccpp-arg-table] name = physics_state type = ddt @@ -59,6 +60,18 @@ dimensions = () type = real kind = kind_phys +[fluxSW] + standard_name = shortwave_radiation_fluxes + long_name = shortwave radiation fluxes + units = W m-2 + dimensions = (horizontal_dimension) + type = ty_rad_sw +[fluxLW] + standard_name = longwave_radiation_fluxes + long_name = longwave radiation fluxes + units = W m-2 + dimensions = (horizontal_dimension) + type = ty_rad_lw [scalar_varA] standard_name = scalar_variable_for_testing_a long_name = unused scalar variable A @@ -91,3 +104,11 @@ units = None dimensions = () type = integer + +[ccpp-table-properties] + name = test_host_data + type = module + dependencies = module_rad_ddt.F90 +[ccpp-arg-table] + name = test_host_data + type = module diff --git a/test/var_compatibility_test/test_reports.py b/test/var_compatibility_test/test_reports.py index 7519d456..ad0cb60e 100755 --- a/test/var_compatibility_test/test_reports.py +++ b/test/var_compatibility_test/test_reports.py @@ -66,8 +66,9 @@ def usage(errmsg=None): _CCPP_FILES = _UTILITY_FILES + \ [os.path.join(_BUILD_DIR, "ccpp", "test_host_ccpp_cap.F90"), os.path.join(_BUILD_DIR, "ccpp", "ccpp_var_compatibility_suite_cap.F90")] -_MODULE_LIST = ["effr_calc", "effr_diag", "effr_post", "effr_pre"] +_MODULE_LIST = ["effr_calc", "effr_diag", "effr_post", "effr_pre", "rad_lw", "rad_sw"] _SUITE_LIST = ["var_compatibility_suite"] +_DEPENDENCIES = [ os.path.join(_TEST_DIR, "module_rad_ddt.F90")] _INPUT_VARS_VAR_ACTION = ["horizontal_loop_begin", "horizontal_loop_end", "horizontal_dimension", "vertical_layer_dimension", "effective_radius_of_stratiform_cloud_liquid_water_particle", "effective_radius_of_stratiform_cloud_rain_particle", @@ -81,6 +82,8 @@ def usage(errmsg=None): "scheme_order_in_suite", "flag_indicating_cloud_microphysics_has_graupel", "flag_indicating_cloud_microphysics_has_ice", + "shortwave_radiation_fluxes", + "longwave_radiation_fluxes", "num_subcycles_for_effr"] _OUTPUT_VARS_VAR_ACTION = ["ccpp_error_code", "ccpp_error_message", "effective_radius_of_stratiform_cloud_ice_particle", @@ -89,6 +92,8 @@ def usage(errmsg=None): "cloud_ice_number_concentration", "effective_radius_of_stratiform_cloud_rain_particle", "scalar_variable_for_testing", + "shortwave_radiation_fluxes", + "longwave_radiation_fluxes", "scheme_order_in_suite"] _REQUIRED_VARS_VAR_ACTION = _INPUT_VARS_VAR_ACTION + _OUTPUT_VARS_VAR_ACTION @@ -155,6 +160,8 @@ def check_datatable(database, report_type, check_list, _MODULE_LIST) NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("suite_list"), _SUITE_LIST) +NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("dependencies"), + _DEPENDENCIES) print("\nChecking variables for var_compatibility suite from python") NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("required_variables", value="var_compatibility_suite"), diff --git a/test/var_compatibility_test/var_compatibility_files.txt b/test/var_compatibility_test/var_compatibility_files.txt index 6d83c980..71df1054 100644 --- a/test/var_compatibility_test/var_compatibility_files.txt +++ b/test/var_compatibility_test/var_compatibility_files.txt @@ -1,4 +1,7 @@ +module_rad_ddt.meta effr_calc.meta effr_diag.meta effr_pre.meta effr_post.meta +rad_lw.meta +rad_sw.meta diff --git a/test/var_compatibility_test/var_compatibility_suite.xml b/test/var_compatibility_test/var_compatibility_suite.xml index a5d4eb48..a168e2ef 100644 --- a/test/var_compatibility_test/var_compatibility_suite.xml +++ b/test/var_compatibility_test/var_compatibility_suite.xml @@ -10,5 +10,7 @@ effr_post effr_diag + rad_lw + rad_sw From eeb16c2a2e0e5c0e48b1e2279a9de0464dc4884b Mon Sep 17 00:00:00 2001 From: Steve Goldhaber Date: Fri, 28 Feb 2025 21:53:30 +0100 Subject: [PATCH 2/8] Fix doctests --- scripts/metadata_table.py | 132 +++++++++++++++++++------------------- 1 file changed, 65 insertions(+), 67 deletions(-) diff --git a/scripts/metadata_table.py b/scripts/metadata_table.py index 584e51f9..622c4ff3 100755 --- a/scripts/metadata_table.py +++ b/scripts/metadata_table.py @@ -529,87 +529,87 @@ def table_start(cls, line): class MetadataSection(ParseSource): """Class to hold all information from a metadata header >>> from framework_env import CCPPFrameworkEnv - >>> _DUMMY_RUN_ENV = CCPPFrameworkEnv(None, {'host_files':'', \ - 'scheme_files':'', \ + >>> _DUMMY_RUN_ENV = CCPPFrameworkEnv(None, {'host_files':'', \ + 'scheme_files':'', \ 'suites':''}) - >>> MetadataSection("footable", "scheme", _DUMMY_RUN_ENV, \ - parse_object=ParseObject("foobar.txt", \ - ["name = footable", "type = scheme", "module = foo", \ - "[ im ]", "standard_name = horizontal_loop_extent", \ - "long_name = horizontal loop extent, start at 1", \ - "units = index | type = integer", \ + >>> MetadataSection("footable", "scheme", _DUMMY_RUN_ENV, module="foo", \ + parse_object=ParseObject("foobar.txt", \ + ["name = footable", "type = scheme", \ + "[ im ]", "standard_name = horizontal_loop_extent", \ + "long_name = horizontal loop extent, start at 1", \ + "units = index | type = integer", \ "dimensions = () | intent = in"])) #doctest: +ELLIPSIS - >>> MetadataSection("footable", "scheme", _DUMMY_RUN_ENV, \ - parse_object=ParseObject("foobar.txt", \ - ["name = footable", "type = scheme", "module = foobar", \ - "[ im ]", "standard_name = horizontal_loop_extent", \ - "long_name = horizontal loop extent, start at 1", \ - "units = index | type = integer", \ + >>> MetadataSection("footable", "scheme", _DUMMY_RUN_ENV, module="foobar", \ + parse_object=ParseObject("foobar.txt", \ + ["name = footable", "type = scheme", \ + "[ im ]", "standard_name = horizontal_loop_extent", \ + "long_name = horizontal loop extent, start at 1", \ + "units = index | type = integer", \ "dimensions = () | intent = in"])).find_variable('horizontal_loop_extent') #doctest: +ELLIPSIS - >>> MetadataSection("footable", "scheme", _DUMMY_RUN_ENV, \ - parse_object=ParseObject("foobar.txt", \ - ["name = footable", "type = scheme", "module = foobar", \ - "process = microphysics", "[ im ]", \ - "standard_name = horizontal_loop_extent", \ - "long_name = horizontal loop extent, start at 1", \ - "units = index | type = integer", \ + >>> MetadataSection("footable", "scheme", _DUMMY_RUN_ENV, module="foobar", \ + parse_object=ParseObject("foobar.txt", \ + ["name = footable", "type = scheme", \ + "process = microphysics", "[ im ]", \ + "standard_name = horizontal_loop_extent", \ + "long_name = horizontal loop extent, start at 1", \ + "units = index | type = integer", \ "dimensions = () | intent = in"])).find_variable('horizontal_loop_extent') #doctest: +ELLIPSIS - >>> MetadataSection("footable", "scheme", _DUMMY_RUN_ENV, \ - parse_object=ParseObject("foobar.txt", \ - ["name = footable", "type=scheme", "module = foo", \ - "[ im ]", "standard_name = horizontal_loop_extent", \ - "long_name = horizontal loop extent, start at 1", \ - "units = index | type = integer", \ - "dimensions = () | intent = in", \ + >>> MetadataSection("footable", "scheme", _DUMMY_RUN_ENV, module="foo", \ + parse_object=ParseObject("foobar.txt", \ + ["name = footable", "type=scheme", \ + "[ im ]", "standard_name = horizontal_loop_extent", \ + "long_name = horizontal loop extent, start at 1", \ + "units = index | type = integer", \ + "dimensions = () | intent = in", \ " subroutine foo()"])).find_variable('horizontal_loop_extent') #doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): parse_source.ParseSyntaxError: Invalid variable property syntax, 'subroutine foo()', at foobar.txt:9 - >>> MetadataSection("footable", "scheme", _DUMMY_RUN_ENV, \ - parse_object=ParseObject("foobar.txt", \ - ["name = footable", "type = scheme", "module=foobar", \ - "[ im ]", "standard_name = horizontal_loop_extent", \ - "long_name = horizontal loop extent, start at 1", \ - "units = index | type = integer", \ - "dimensions = () | intent = in", \ + >>> MetadataSection("footable", "scheme", _DUMMY_RUN_ENV, module="foobar", \ + parse_object=ParseObject("foobar.txt", \ + ["name = footable", "type = scheme", \ + "[ im ]", "standard_name = horizontal_loop_extent", \ + "long_name = horizontal loop extent, start at 1", \ + "units = index | type = integer", \ + "dimensions = () | intent = in", \ ""], line_start=0)).find_variable('horizontal_loop_extent').get_prop_value('local_name') 'im' - >>> MetadataSection("footable", "scheme", _DUMMY_RUN_ENV, \ - parse_object=ParseObject("foobar.txt", \ - ["name = footable", "type = scheme" \ - "[ im ]", "standard_name = horizontalloop extent", \ - "long_name = horizontal loop extent, start at 1", \ - "units = index | type = integer", \ - "dimensions = () | intent = in", \ + >>> MetadataSection("footable", "scheme", _DUMMY_RUN_ENV, module="foo", \ + parse_object=ParseObject("foobar.txt", \ + ["name = footable", "type = scheme" \ + "[ im ]", "standard_name = horizontalloop extent", \ + "long_name = horizontal loop extent, start at 1", \ + "units = index | type = integer", \ + "dimensions = () | intent = in", \ ""], line_start=0)).find_variable('horizontal_loop_extent') - >>> MetadataSection("footable", "scheme", _DUMMY_RUN_ENV, \ - parse_object=ParseObject("foobar.txt", \ - ["[ccpp-arg-table]", "name = foobar", "type = scheme" \ - "[ im ]", "standard_name = horizontal loop extent", \ - "long_name = horizontal loop extent, start at 1", \ - "units = index | type = integer", \ - "dimensions = () | intent = in", \ + >>> MetadataSection("footable", "scheme", _DUMMY_RUN_ENV, module="foo", \ + parse_object=ParseObject("foobar.txt", \ + ["[ccpp-arg-table]", "name = foobar", "type = scheme" \ + "[ im ]", "standard_name = horizontal loop extent", \ + "long_name = horizontal loop extent, start at 1", \ + "units = index | type = integer", \ + "dimensions = () | intent = in", \ ""], line_start=0)).find_variable('horizontal_loop_extent') - >>> MetadataSection("foobar", "scheme", _DUMMY_RUN_ENV, \ - parse_object=ParseObject("foobar.txt", \ - ["name = foobar", "module = foo" \ - "[ im ]", "standard_name = horizontal loop extent", \ - "long_name = horizontal loop extent, start at 1", \ - "units = index | type = integer", \ - "dimensions = () | intent = in", \ + >>> MetadataSection("foobar", "scheme", _DUMMY_RUN_ENV, module="foo", \ + parse_object=ParseObject("foobar.txt", \ + ["name = foobar" \ + "[ im ]", "standard_name = horizontal loop extent", \ + "long_name = horizontal loop extent, start at 1", \ + "units = index | type = integer", \ + "dimensions = () | intent = in", \ ""], line_start=0)).find_variable('horizontal_loop_extent') - >>> MetadataSection("foobar", "scheme", _DUMMY_RUN_ENV, \ - parse_object=ParseObject("foobar.txt", \ - ["name = foobar", "foo = bar" \ - "[ im ]", "standard_name = horizontal loop extent", \ - "long_name = horizontal loop extent, start at 1", \ - "units = index | type = integer", \ - "dimensions = () | intent = in", \ + >>> MetadataSection("foobar", "scheme", _DUMMY_RUN_ENV, module="foo", \ + parse_object=ParseObject("foobar.txt", \ + ["name = foobar", "foo = bar" \ + "[ im ]", "standard_name = horizontal loop extent", \ + "long_name = horizontal loop extent, start at 1", \ + "units = index | type = integer", \ + "dimensions = () | intent = in", \ ""], line_start=0)).find_variable('horizontal_loop_extent') >>> MetadataSection.header_start('[ ccpp-arg-table ]') @@ -693,9 +693,7 @@ def __init__(self, table_name, table_type, run_env, parse_object=None, if mismatch: raise CCPPError(mismatch) # end if - if module is not None: - self.__module_name = module - else: + if module is None: perr = "MetadataSection requires a module name" self.__pobj.add_syntax_err(perr) self.__section_valid = False @@ -766,7 +764,7 @@ def __init_from_file(self, table_name, table_type, known_ddts, module_name, self.__process_type = value else: self.__pobj.add_syntax_err("metadata table start property", - token=value) + token=key) self.__process_type = 'INVALID' # Allow error continue self.__section_valid = False # end if From cfe5c8d57fc8db6c61a1dbf586ed4980a6b19fe5 Mon Sep 17 00:00:00 2001 From: Steve Goldhaber Date: Fri, 28 Feb 2025 21:58:23 +0100 Subject: [PATCH 3/8] Fix unit test failure caused by previous error message cleanup --- test/unit_tests/test_metadata_table.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit_tests/test_metadata_table.py b/test/unit_tests/test_metadata_table.py index 94ed1e67..abf48b67 100755 --- a/test/unit_tests/test_metadata_table.py +++ b/test/unit_tests/test_metadata_table.py @@ -208,7 +208,7 @@ def test_bad_table_key(self): _ = parse_metadata_file(filename, known_ddts, self._DUMMY_RUN_ENV) #print("The exception is", context.exception) - emsg = "Invalid metadata table start property, 'something', at " + emsg = "Invalid metadata table start property, 'banana', at " self.assertTrue(emsg in str(context.exception)) def test_bad_line_split(self): From 4a97ab511b1da86531584229ffbe4a6534373a12 Mon Sep 17 00:00:00 2001 From: Steve Goldhaber Date: Fri, 28 Feb 2025 23:11:01 +0100 Subject: [PATCH 4/8] Add scheme file with different module name as test --- scripts/metadata_table.py | 2 +- test/var_compatibility_test/effr_pre.F90 | 6 +++--- test/var_compatibility_test/effr_pre.meta | 1 + test/var_compatibility_test/run_test | 2 +- test/var_compatibility_test/test_reports.py | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/scripts/metadata_table.py b/scripts/metadata_table.py index 622c4ff3..d33e6c64 100755 --- a/scripts/metadata_table.py +++ b/scripts/metadata_table.py @@ -414,7 +414,7 @@ def __init_from_file(self, known_ddts, run_env, skip_ddt_check=False): self.__relative_path = value else: tok_type = "metadata table start property" - self.__pobj.add_syntax_err(tok_type, token=value) + self.__pobj.add_syntax_err(tok_type, token=key) # end if # end for curr_line, _ = self.__pobj.next_line() diff --git a/test/var_compatibility_test/effr_pre.F90 b/test/var_compatibility_test/effr_pre.F90 index 51f1c373..17a3b187 100644 --- a/test/var_compatibility_test/effr_pre.F90 +++ b/test/var_compatibility_test/effr_pre.F90 @@ -1,7 +1,7 @@ !Test unit conversions for intent in, inout, out variables ! -module effr_pre +module mod_effr_pre use ccpp_kinds, only: kind_phys @@ -56,5 +56,5 @@ subroutine effr_pre_run( effrr_inout, scalar_var, errmsg, errflg) endif end subroutine effr_pre_run - - end module effr_pre + +end module mod_effr_pre diff --git a/test/var_compatibility_test/effr_pre.meta b/test/var_compatibility_test/effr_pre.meta index 9c1fcf8e..251b4175 100644 --- a/test/var_compatibility_test/effr_pre.meta +++ b/test/var_compatibility_test/effr_pre.meta @@ -1,6 +1,7 @@ [ccpp-table-properties] name = effr_pre type = scheme + module_name = mod_effr_pre dependencies = ######################################################################## [ccpp-arg-table] diff --git a/test/var_compatibility_test/run_test b/test/var_compatibility_test/run_test index 0da920a7..cbaf8083 100755 --- a/test/var_compatibility_test/run_test +++ b/test/var_compatibility_test/run_test @@ -128,7 +128,7 @@ ccpp_files="${utility_files}" ccpp_files="${ccpp_files},${build_dir}/ccpp/test_host_ccpp_cap.F90" ccpp_files="${ccpp_files},${build_dir}/ccpp/ccpp_var_compatibility_suite_cap.F90" #process_list="" -module_list="effr_calc,effr_diag,effr_post,effr_pre,rad_lw,rad_sw" +module_list="effr_calc,effr_diag,effr_post,mod_effr_pre,rad_lw,rad_sw" dependencies="module_rad_ddt" suite_list="var_compatibility_suite" required_vars_var_compatibility="ccpp_error_code,ccpp_error_message" diff --git a/test/var_compatibility_test/test_reports.py b/test/var_compatibility_test/test_reports.py index ad0cb60e..4fd2863f 100755 --- a/test/var_compatibility_test/test_reports.py +++ b/test/var_compatibility_test/test_reports.py @@ -66,7 +66,7 @@ def usage(errmsg=None): _CCPP_FILES = _UTILITY_FILES + \ [os.path.join(_BUILD_DIR, "ccpp", "test_host_ccpp_cap.F90"), os.path.join(_BUILD_DIR, "ccpp", "ccpp_var_compatibility_suite_cap.F90")] -_MODULE_LIST = ["effr_calc", "effr_diag", "effr_post", "effr_pre", "rad_lw", "rad_sw"] +_MODULE_LIST = ["effr_calc", "effr_diag", "effr_post", "mod_effr_pre", "rad_lw", "rad_sw"] _SUITE_LIST = ["var_compatibility_suite"] _DEPENDENCIES = [ os.path.join(_TEST_DIR, "module_rad_ddt.F90")] _INPUT_VARS_VAR_ACTION = ["horizontal_loop_begin", "horizontal_loop_end", "horizontal_dimension", "vertical_layer_dimension", From 8349e0ce070a08026470e226af58b1143f42aad0 Mon Sep 17 00:00:00 2001 From: Steve Goldhaber Date: Mon, 17 Mar 2025 17:40:35 +0100 Subject: [PATCH 5/8] Allow host model DDTs to be inputs to schemes --- scripts/ccpp_capgen.py | 12 ++-- scripts/metadata_table.py | 98 ++++++++++++++++++++++++++++--- test/ddthost_test/make_ddt.F90 | 4 +- test/ddthost_test/make_ddt.meta | 5 ++ test/ddthost_test/run_test | 2 + test/ddthost_test/test_host.F90 | 10 ++-- test/ddthost_test/test_reports.py | 3 +- 7 files changed, 114 insertions(+), 20 deletions(-) diff --git a/scripts/ccpp_capgen.py b/scripts/ccpp_capgen.py index 9eac0ecf..c18fa5e8 100755 --- a/scripts/ccpp_capgen.py +++ b/scripts/ccpp_capgen.py @@ -25,7 +25,7 @@ from framework_env import parse_command_line from host_cap import write_host_cap from host_model import HostModel -from metadata_table import parse_metadata_file, SCHEME_HEADER_TYPE +from metadata_table import parse_metadata_file, register_ddts, SCHEME_HEADER_TYPE from parse_tools import init_log, set_log_level, context_string from parse_tools import register_fortran_ddt_name from parse_tools import CCPPError, ParseInternalError @@ -524,7 +524,8 @@ def parse_host_model_files(host_filenames, host_name, run_env): return host_model ############################################################################### -def parse_scheme_files(scheme_filenames, run_env, skip_ddt_check=False): +def parse_scheme_files(scheme_filenames, run_env, skip_ddt_check=False, + known_ddts=list()): ############################################################################### """ Gather information from scheme files (e.g., init, run, and finalize @@ -532,7 +533,6 @@ def parse_scheme_files(scheme_filenames, run_env, skip_ddt_check=False): """ table_dict = {} # Duplicate check and for dependencies processing header_dict = {} # To check for duplicates - known_ddts = list() logger = run_env.logger for filename in scheme_filenames: logger.info('Reading CCPP schemes from {}'.format(filename)) @@ -643,9 +643,11 @@ def capgen(run_env, return_db=False): # We always need to parse the constituent DDTs const_prop_mod = os.path.join(src_dir, "ccpp_constituent_prop_mod.meta") if const_prop_mod not in scheme_files: - scheme_files= [const_prop_mod] + scheme_files + scheme_files = [const_prop_mod] + scheme_files # end if - scheme_headers, scheme_tdict = parse_scheme_files(scheme_files, run_env) + host_ddts = register_ddts(host_files) + scheme_headers, scheme_tdict = parse_scheme_files(scheme_files, run_env, + known_ddts=host_ddts) if run_env.verbose: ddts = host_model.ddt_lib.keys() if ddts: diff --git a/scripts/metadata_table.py b/scripts/metadata_table.py index d33e6c64..ff15d1fe 100755 --- a/scripts/metadata_table.py +++ b/scripts/metadata_table.py @@ -168,7 +168,7 @@ def _parse_config_line(line, context): else: properties = line.strip().split('|') for prop in properties: - pitems = prop.split('=', 1) + pitems = [x.strip() for x in prop.split('=', 1)] if len(pitems) >= 2: parse_items.append(pitems) else: @@ -246,8 +246,8 @@ def find_scheme_names(filename): props = _parse_config_line(line, context) for prop in props: # Look for name property - key = prop[0].strip().lower() - value = prop[1].strip() + key = prop[0].lower() + value = prop[1] if key == 'name': scheme_names.append(value) # end if @@ -265,6 +265,86 @@ def find_scheme_names(filename): ######################################################################## +def register_ddts(file_list): + """Scan the metadata files in and register all + DDT tables found. + Return a list of the DDTs type names found. + """ + errors = "" + ddt_names = set() + for mfile in file_list: + if os.path.exists(mfile): + with open(mfile, 'r') as infile: + fin_lines = infile.readlines() + # end with + pobj = ParseObject(mfile, fin_lines) + in_table = False # Line number of table start + ddt_name = "" + table_is_ddt = False + # Search the file for ccpp-table-properties sections + curr_line, line_num = pobj.next_line() + while(curr_line): + if in_table: + # We are in a table properties sec, look for name and type + if MetadataSection.header_start(curr_line) or \ + MetadataTable.table_start(curr_line): + # We have exited the table, record if a DDT + if table_is_ddt: + if ddt_name: + ddt_names.add(ddt_name) + else: + emsg = "Unnamed CCPP metadata table" + pobj.add_syntax_err(emsg) + # end if + # end if + in_table = False + ddt_name = "" + table_is_ddt = False + else: + for prop in _parse_config_line(curr_line, context=pobj): + if prop[0].lower() == 'name': + ddt_name = prop[1].lower() + elif prop[0].lower() == 'type': + table_is_ddt = prop[1].lower() == 'ddt' + # end if + # end for + # end if + elif MetadataTable.table_start(curr_line): + in_table = line_num + 1 + # end if + curr_line, line_num = pobj.next_line() + # end while + if pobj.error_message: + if errors: + errors += "\n" + # end if + errors += pobj.error_message + # end if + else: + if errors: + errors += "\n" + # end if + errors += f"Metadata file, '{mfile}', not found." + # end if + # end for + if in_table: + # This is a malformed CCPP metadata file! + if errors: + errors += "\n" + # end if + errors += f"Malformed CCPP metadata file, '{mfile}'" + # end if + if errors: + raise CCPPError(f"{errors}") + else: + for ddt in ddt_names: + register_fortran_ddt_name(ddt) + # end for + # end if + return list(ddt_names) + +######################################################################## + class MetadataTable(): """Class to hold a CCPP Metadata table including the table header (ccpp-table-properties section) and all of the associated table @@ -379,8 +459,8 @@ def __init_from_file(self, known_ddts, run_env, skip_ddt_check=False): # Process the properties in this table header line for prop in _parse_config_line(curr_line, self.__pobj): # Manually parse name, type, and table properties - key = prop[0].strip().lower() - value = prop[1].strip() + key = prop[0].lower() + value = prop[1] if key == 'name': self.__table_name = value elif key == 'type': @@ -744,8 +824,8 @@ def __init_from_file(self, table_name, table_type, known_ddts, module_name, (not MetadataTable.table_start(curr_line))): for prop in _parse_config_line(curr_line, self.__pobj): # Manually parse name, type, and module properties - key = prop[0].strip().lower() - value = prop[1].strip() + key = prop[0].lower() + value = prop[1] if key == 'name': self.__section_title = value elif key == 'type': @@ -866,8 +946,8 @@ def parse_variable(self, curr_line, known_ddts, skip_ddt_check=False): if valid_line: properties = _parse_config_line(curr_line, self.__pobj) for prop in properties: - pname = prop[0].strip().lower() - pval_str = prop[1].strip() + pname = prop[0].lower() + pval_str = prop[1] if ((pname == 'type') and (not check_fortran_intrinsic(pval_str, error=False))): if skip_ddt_check or pval_str in known_ddts: diff --git a/test/ddthost_test/make_ddt.F90 b/test/ddthost_test/make_ddt.F90 index e94aaff4..c9d0832b 100644 --- a/test/ddthost_test/make_ddt.F90 +++ b/test/ddthost_test/make_ddt.F90 @@ -69,10 +69,12 @@ end subroutine make_ddt_run !> \section arg_table_make_ddt_init Argument Table !! \htmlinclude arg_table_make_ddt_init.html !! - subroutine make_ddt_init(nbox, vmr, errmsg, errflg) + subroutine make_ddt_init(nbox, ccpp_info, vmr, errmsg, errflg) + use host_ccpp_ddt, only: ccpp_info_t ! Dummy arguments integer, intent(in) :: nbox + type(ccpp_info_t), intent(in) :: ccpp_info type(vmr_type), intent(out) :: vmr character(len=512), intent(out) :: errmsg integer, intent(out) :: errflg diff --git a/test/ddthost_test/make_ddt.meta b/test/ddthost_test/make_ddt.meta index b9dbd8a9..4f5c9a00 100644 --- a/test/ddthost_test/make_ddt.meta +++ b/test/ddthost_test/make_ddt.meta @@ -76,6 +76,11 @@ units = count dimensions = () intent = in +[ ccpp_info ] + standard_name = host_standard_ccpp_type + type = ccpp_info_t + dimensions = () + intent = in [ vmr ] standard_name = volume_mixing_ratio_ddt dimensions = () diff --git a/test/ddthost_test/run_test b/test/ddthost_test/run_test index 98b934b4..964bface 100755 --- a/test/ddthost_test/run_test +++ b/test/ddthost_test/run_test @@ -136,12 +136,14 @@ suite_list="ddt_suite;temp_suite" required_vars_ddt="ccpp_error_code,ccpp_error_message,horizontal_dimension" required_vars_ddt="${required_vars_ddt},horizontal_loop_begin" required_vars_ddt="${required_vars_ddt},horizontal_loop_end" +required_vars_ddt="${required_vars_ddt},host_standard_ccpp_type" required_vars_ddt="${required_vars_ddt},model_times" required_vars_ddt="${required_vars_ddt},number_of_model_times" required_vars_ddt="${required_vars_ddt},surface_air_pressure" input_vars_ddt="horizontal_dimension" input_vars_ddt="${input_vars_ddt},horizontal_loop_begin" input_vars_ddt="${input_vars_ddt},horizontal_loop_end" +input_vars_ddt="${input_vars_ddt},host_standard_ccpp_type" input_vars_ddt="${input_vars_ddt},model_times,number_of_model_times" input_vars_ddt="${input_vars_ddt},surface_air_pressure" output_vars_ddt="ccpp_error_code,ccpp_error_message" diff --git a/test/ddthost_test/test_host.F90 b/test/ddthost_test/test_host.F90 index d060e59e..12c4aeb0 100644 --- a/test/ddthost_test/test_host.F90 +++ b/test/ddthost_test/test_host.F90 @@ -386,10 +386,11 @@ program test 'ccpp_error_code ', & 'ccpp_error_message ' /) - character(len=cm), target :: test_invars2(3) = (/ & + character(len=cm), target :: test_invars2(4) = (/ & 'model_times ', & 'number_of_model_times ', & - 'surface_air_pressure ' /) + 'surface_air_pressure ', & + 'host_standard_ccpp_type ' /) character(len=cm), target :: test_outvars2(5) = (/ & 'ccpp_error_code ', & @@ -398,12 +399,13 @@ program test 'surface_air_pressure ', & 'number_of_model_times ' /) - character(len=cm), target :: test_reqvars2(5) = (/ & + character(len=cm), target :: test_reqvars2(6) = (/ & 'model_times ', & 'number_of_model_times ', & 'surface_air_pressure ', & 'ccpp_error_code ', & - 'ccpp_error_message ' /) + 'ccpp_error_message ', & + 'host_standard_ccpp_type ' /) type(suite_info) :: test_suites(2) logical :: run_okay diff --git a/test/ddthost_test/test_reports.py b/test/ddthost_test/test_reports.py index e2904a6e..6fec8be4 100644 --- a/test/ddthost_test/test_reports.py +++ b/test/ddthost_test/test_reports.py @@ -64,7 +64,8 @@ _SUITE_LIST = ["ddt_suite", "temp_suite"] _INPUT_VARS_DDT = ["model_times", "number_of_model_times", "horizontal_loop_begin", "horizontal_loop_end", - "surface_air_pressure", "horizontal_dimension"] + "surface_air_pressure", "horizontal_dimension", + "host_standard_ccpp_type"] _OUTPUT_VARS_DDT = ["ccpp_error_code", "ccpp_error_message", "model_times", "number_of_model_times", "surface_air_pressure"] _REQUIRED_VARS_DDT = _INPUT_VARS_DDT + _OUTPUT_VARS_DDT From e260dd53ab626aaee3d26b601a6b619968e3d436 Mon Sep 17 00:00:00 2001 From: Steve Goldhaber Date: Sun, 13 Apr 2025 21:49:59 +0200 Subject: [PATCH 6/8] Host model uses DDT defined in schemes. --- scripts/ccpp_capgen.py | 11 +++++++---- scripts/metadata_table.py | 8 ++++++-- test/var_compatibility_test/CMakeLists.txt | 2 +- test/var_compatibility_test/test_host_data.F90 | 17 ++++++++++++++++- 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/scripts/ccpp_capgen.py b/scripts/ccpp_capgen.py index c18fa5e8..31421571 100755 --- a/scripts/ccpp_capgen.py +++ b/scripts/ccpp_capgen.py @@ -468,7 +468,8 @@ def duplicate_item_error(title, filename, itype, orig_item): raise CCPPError(errmsg.format(**edict)) ############################################################################### -def parse_host_model_files(host_filenames, host_name, run_env): +def parse_host_model_files(host_filenames, host_name, run_env, + known_ddts=list()): ############################################################################### """ Gather information from host files (e.g., DDTs, registry) and @@ -476,7 +477,6 @@ def parse_host_model_files(host_filenames, host_name, run_env): """ header_dict = {} table_dict = {} - known_ddts = list() logger = run_env.logger for filename in host_filenames: logger.info('Reading host model data from {}'.format(filename)) @@ -637,8 +637,11 @@ def capgen(run_env, return_db=False): if run_env.generate_docfiles: raise CCPPError("--generate-docfiles not yet supported") # end if - # First up, handle the host files - host_model = parse_host_model_files(host_files, host_name, run_env) + # The host model may depend on suite DDTs + scheme_ddts = register_ddts(scheme_files) + # Handle the host files + host_model = parse_host_model_files(host_files, host_name, run_env, + known_ddts=scheme_ddts) # Next, parse the scheme files # We always need to parse the constituent DDTs const_prop_mod = os.path.join(src_dir, "ccpp_constituent_prop_mod.meta") diff --git a/scripts/metadata_table.py b/scripts/metadata_table.py index ff15d1fe..125b308c 100755 --- a/scripts/metadata_table.py +++ b/scripts/metadata_table.py @@ -283,7 +283,7 @@ def register_ddts(file_list): table_is_ddt = False # Search the file for ccpp-table-properties sections curr_line, line_num = pobj.next_line() - while(curr_line): + while(curr_line is not None): if in_table: # We are in a table properties sec, look for name and type if MetadataSection.header_start(curr_line) or \ @@ -297,7 +297,11 @@ def register_ddts(file_list): pobj.add_syntax_err(emsg) # end if # end if - in_table = False + if MetadataTable.table_start(curr_line): + in_table = line_num + 1 + else: + in_table = False + # end if ddt_name = "" table_is_ddt = False else: diff --git a/test/var_compatibility_test/CMakeLists.txt b/test/var_compatibility_test/CMakeLists.txt index e25f3fda..34734c06 100644 --- a/test/var_compatibility_test/CMakeLists.txt +++ b/test/var_compatibility_test/CMakeLists.txt @@ -20,7 +20,7 @@ get_filename_component(CCPP_ROOT "${TEST_ROOT}" DIRECTORY) # #------------------------------------------------------------------------------ LIST(APPEND SCHEME_FILES "var_compatibility_files.txt") -LIST(APPEND HOST_FILES "module_rad_ddt" "test_host_data" "test_host_mod") +LIST(APPEND HOST_FILES "test_host_data" "test_host_mod") LIST(APPEND SUITE_FILES "var_compatibility_suite.xml") # HOST is the name of the executable we will build. # We assume there are files ${HOST}.meta and ${HOST}.F90 in CMAKE_SOURCE_DIR diff --git a/test/var_compatibility_test/test_host_data.F90 b/test/var_compatibility_test/test_host_data.F90 index 2c5e3409..964c88e7 100644 --- a/test/var_compatibility_test/test_host_data.F90 +++ b/test/var_compatibility_test/test_host_data.F90 @@ -1,6 +1,7 @@ module test_host_data - use ccpp_kinds, only: kind_phys + use ccpp_kinds, only: kind_phys + use mod_rad_ddt, only: ty_rad_lw, ty_rad_sw implicit none private @@ -15,6 +16,10 @@ module test_host_data effrg, & ! effective radius of cloud graupel ncg, & ! number concentration of cloud graupel nci ! number concentration of cloud ice + type(ty_rad_lw), dimension(:), allocatable :: & + fluxLW ! Longwave radiation fluxes + type(ty_rad_sw), dimension(:), allocatable :: & + fluxSW ! Shortwave radiation fluxes real(kind_phys) :: scalar_var real(kind_phys) :: scalar_varA real(kind_phys) :: scalar_varB @@ -72,6 +77,16 @@ subroutine allocate_physics_state(cols, levels, state, has_graupel, has_ice) allocate(state%nci(cols, levels)) endif + if (allocated(state%fluxLW)) then + deallocate(state%fluxLW) + end if + allocate(state%fluxLW(cols)) + + if (allocated(state%fluxSW)) then + deallocate(state%fluxSW) + end if + allocate(state%fluxSW(cols)) + ! Initialize scheme counter. state%scheme_order = 1 ! Initialize subcycle counter. From f4e57b1b894492fedc71167aa9e1c7094fe2a3bd Mon Sep 17 00:00:00 2001 From: Steve Goldhaber Date: Sun, 13 Apr 2025 22:07:04 +0200 Subject: [PATCH 7/8] Uncomment and fix var_compatibility_test checks --- test/var_compatibility_test/run_test | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/var_compatibility_test/run_test b/test/var_compatibility_test/run_test index cbaf8083..be8f1f6c 100755 --- a/test/var_compatibility_test/run_test +++ b/test/var_compatibility_test/run_test @@ -1,6 +1,6 @@ #! /bin/bash -currdir="`pwd -P`" +currdir="$(pwd -P)" scriptdir="$( cd $( dirname $0 ); pwd -P )" ## @@ -129,7 +129,7 @@ ccpp_files="${ccpp_files},${build_dir}/ccpp/test_host_ccpp_cap.F90" ccpp_files="${ccpp_files},${build_dir}/ccpp/ccpp_var_compatibility_suite_cap.F90" #process_list="" module_list="effr_calc,effr_diag,effr_post,mod_effr_pre,rad_lw,rad_sw" -dependencies="module_rad_ddt" +dependencies="${scriptdir}/module_rad_ddt.F90" suite_list="var_compatibility_suite" required_vars_var_compatibility="ccpp_error_code,ccpp_error_message" required_vars_var_compatibility="${required_vars_var_compatibility},cloud_graupel_number_concentration" @@ -245,11 +245,11 @@ check_datatable ${report_prog} ${datafile} "--suite-files" ${suite_files} check_datatable ${report_prog} ${datafile} "--utility-files" ${utility_files} check_datatable ${report_prog} ${datafile} "--ccpp-files" ${ccpp_files} echo -e "\nChecking lists from command line" -#check_datatable ${report_prog} ${datafile} "--process-list" ${process_list} +check_datatable ${report_prog} ${datafile} "--process-list" ${process_list} check_datatable ${report_prog} ${datafile} "--module-list" ${module_list} -#check_datatable ${report_prog} ${datafile} "--dependencies" ${dependencies} -#check_datatable ${report_prog} ${datafile} "--suite-list" ${suite_list} \ -# --sep ";" +check_datatable ${report_prog} ${datafile} "--dependencies" ${dependencies} +check_datatable ${report_prog} ${datafile} "--suite-list" ${suite_list} \ + --sep ";" echo -e "\nChecking variables for var_compatibility suite from command line" check_datatable ${report_prog} ${datafile} "--required-variables" \ ${required_vars_var_compatibility} "var_compatibility_suite" From 6c2d326a43d1e4fc6f344b70e0b10cfb87104432 Mon Sep 17 00:00:00 2001 From: Steve Goldhaber Date: Mon, 21 Apr 2025 22:11:14 +0200 Subject: [PATCH 8/8] Fix typo --- scripts/metadata_table.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/metadata_table.py b/scripts/metadata_table.py index 125b308c..bd388716 100755 --- a/scripts/metadata_table.py +++ b/scripts/metadata_table.py @@ -576,7 +576,7 @@ def dependencies(self): @property def module_name(self): """Return the module name for this metadata table""" - return self.__module + return self.__module_name @property def relative_path(self):