diff --git a/scripts/ccpp_suite.py b/scripts/ccpp_suite.py index c5c6f4ab..d19ca4e8 100644 --- a/scripts/ccpp_suite.py +++ b/scripts/ccpp_suite.py @@ -22,6 +22,7 @@ from parse_tools import read_xml_file, validate_xml_file, find_schema_version from parse_tools import init_log, set_log_to_null from suite_objects import CallList, Group, Scheme +from metavar import CCPP_LOOP_VAR_STDNAMES # pylint: disable=too-many-lines @@ -286,13 +287,16 @@ def find_variable(self, standard_name=None, source_var=None, loop_subst=loop_subst) if var is None: # No dice? Check for a group variable which can be promoted - if standard_name in self.__gvar_stdnames: + # Don't promote loop standard names + if (standard_name in self.__gvar_stdnames and standard_name + not in CCPP_LOOP_VAR_STDNAMES): group = self.__gvar_stdnames[standard_name] var = group.find_variable(standard_name=standard_name, source_var=source_var, any_scope=False, search_call_list=srch_clist, loop_subst=loop_subst) + if var is not None: # Promote variable to suite level # Remove this entry to avoid looping back here diff --git a/scripts/metavar.py b/scripts/metavar.py index eb1973e1..3eb9cd79 100755 --- a/scripts/metavar.py +++ b/scripts/metavar.py @@ -1728,9 +1728,9 @@ def add_variable_dimensions(self, var, ignore_sources, to_dict=None, err_ret += f"{self.name}: " err_ret += f"Cannot find variable for dimension, {dimname}, of {vstdname}{ctx}" if dvar: - err_ret += f"\nFound {lname} from excluded source, '{dvar.source.ptype}'{dctx}" lname = dvar.get_prop_value('local_name') dctx = context_string(dvar.context) + err_ret += f"\nFound {lname} from excluded source, '{dvar.source.ptype}'{dctx}" # end if # end if # end if diff --git a/scripts/suite_objects.py b/scripts/suite_objects.py index dda5b23f..951e5c86 100755 --- a/scripts/suite_objects.py +++ b/scripts/suite_objects.py @@ -1535,13 +1535,31 @@ def add_var_transform(self, var, compat_obj, vert_dim): # If needed, modify vertical dimension for vertical orientation flipping _, vdim = find_vertical_dimension(var.get_dimensions()) - vdim_name = vert_dim.split(':')[-1] - group_vvar = self.__group.call_list.find_variable(vdim_name) - vname = group_vvar.get_prop_value('local_name') - lindices[vdim] = '1:'+vname - rindices[vdim] = '1:'+vname - if compat_obj.has_vert_transforms: - rindices[vdim] = vname+':1:-1' + if vdim >= 0: + vdims = vert_dim.split(':') + vdim_name = vdims[-1] + group_vvar = self.__group.call_list.find_variable(vdim_name) + if group_vvar is None: + raise CCPPError(f"add_var_transform: Cannot find dimension variable, {vdim_name}") + # end if + vname = group_vvar.get_prop_value('local_name') + if len(vdims) == 2: + sdim_name = vdims[0] + group_vvar = self.find_variable(sdim_name) + if group_vvar is None: + raise CCPPError(f"add_var_transform: Cannot find dimension variable, {sdim_name}") + # end if + sname = group_vvar.get_prop_value('local_name') + else: + sname = '1' + # end if + lindices[vdim] = sname+':'+vname + if compat_obj.has_vert_transforms: + rindices[vdim] = vname+':'+sname+':-1' + else: + rindices[vdim] = sname+':'+vname + # end if + # end if # If needed, modify horizontal dimension for loop substitution. # NOT YET IMPLEMENTED @@ -1614,9 +1632,12 @@ def write(self, outfile, errcode, errmsg, indent): for (var, internal_var) in self.__var_debug_checks: stmt = self.write_var_debug_check(var, internal_var, cldicts, outfile, errcode, errmsg, indent+1) # Write any reverse (pre-Scheme) transforms. - outfile.write('! Compute reverse (pre-scheme) transforms', indent+1) + if len(self.__reverse_transforms) > 0: + outfile.comment('Compute reverse (pre-scheme) transforms', indent+1) + # end if for (dummy, var, rindices, lindices, compat_obj) in self.__reverse_transforms: tstmt = self.write_var_transform(var, dummy, rindices, lindices, compat_obj, outfile, indent+1, False) + # end for # Write the scheme call. stmt = 'call {}({})' outfile.write('',indent+1) @@ -1624,10 +1645,12 @@ def write(self, outfile, errcode, errmsg, indent): outfile.write(stmt.format(self.subroutine_name, my_args), indent+1) # Write any forward (post-Scheme) transforms. outfile.write('',indent+1) - outfile.write('! Compute forward (post-scheme) transforms', indent+1) + if len(self.__forward_transforms) > 0: + outfile.comment('Compute forward (post-scheme) transforms', indent+1) + # end if for (var, dummy, lindices, rindices, compat_obj) in self.__forward_transforms: tstmt = self.write_var_transform(var, dummy, rindices, lindices, compat_obj, outfile, indent+1, True) - # + # end for outfile.write('', indent) outfile.write('end if', indent) @@ -1724,6 +1747,10 @@ def analyze(self, phase, group, scheme_library, suite_vars, level): local_dim = group.call_list.find_variable(standard_name=dim_name, any_scope=False) # end if + # If not found, check the suite level + if local_dim is None: + local_dim = group.suite.find_variable(standard_name=dim_name) + # end if if local_dim is None: emsg = 'No variable found for vertical loop dimension {}' raise ParseInternalError(emsg.format(self._dim_name)) diff --git a/scripts/var_props.py b/scripts/var_props.py index dc4c24c4..9a2fd7d0 100755 --- a/scripts/var_props.py +++ b/scripts/var_props.py @@ -821,6 +821,18 @@ class VarCompatObj: _DOCTEST_RUNENV).reverse_transform("var1_lname", "var2_lname", ('k',), ('nk-k+1',)) 'var1_lname(nk-k+1) = var2_lname(k)' + # Test that unit conversions with a scalar var works + >>> VarCompatObj("var_stdname", "real", "kind_phys", "Pa", [], "var1_lname", False, \ + "var_stdname", "real", "kind_phys", "hPa", [], "var2_lname", False, \ + _DOCTEST_RUNENV).forward_transform("var1_lname", "var2_lname", [], []) #doctest: +ELLIPSIS + 'var1_lname = 1.0E-2_kind_phys*var2_lname' + + # Test that unit conversions with a scalar var works + >>> VarCompatObj("var_stdname", "real", "kind_phys", "Pa", [], "var1_lname", False, \ + "var_stdname", "real", "kind_phys", "hPa", [], "var2_lname", False, \ + _DOCTEST_RUNENV).reverse_transform("var1_lname", "var2_lname", [], []) #doctest: +ELLIPSIS + 'var1_lname = 1.0E+2_kind_phys*var2_lname' + # Test that a 2-D var with unit conversion m->km works >>> VarCompatObj("var_stdname", "real", "kind_phys", "m", ['horizontal_dimension'], "var1_lname", False, \ "var_stdname", "real", "kind_phys", "km", ['horizontal_dimension'], "var2_lname", False, \ @@ -976,8 +988,13 @@ def forward_transform(self, lvar_lname, rvar_lname, rvar_indices, lvar_indices, "vertical_interface_dimension"). """ # Dimension transform (Indices handled externally) - rhs_term = f"{rvar_lname}({','.join(rvar_indices)})" - lhs_term = f"{lvar_lname}({','.join(lvar_indices)})" + if len(rvar_indices) == 0: + rhs_term = f"{rvar_lname}" + lhs_term = f"{lvar_lname}" + else: + rhs_term = f"{rvar_lname}({','.join(rvar_indices)})" + lhs_term = f"{lvar_lname}({','.join(lvar_indices)})" + # end if if self.has_kind_transforms: kind = self.__kind_transforms[1] @@ -1016,8 +1033,13 @@ def reverse_transform(self, lvar_lname, rvar_lname, rvar_indices, lvar_indices, "vertical_interface_dimension"). """ # Dimension transforms (Indices handled externally) - lhs_term = f"{lvar_lname}({','.join(lvar_indices)})" - rhs_term = f"{rvar_lname}({','.join(rvar_indices)})" + if len(rvar_indices) == 0: + rhs_term = f"{rvar_lname}" + lhs_term = f"{lvar_lname}" + else: + lhs_term = f"{lvar_lname}({','.join(lvar_indices)})" + rhs_term = f"{rvar_lname}({','.join(rvar_indices)})" + # end if if self.has_kind_transforms: kind = self.__kind_transforms[0] diff --git a/test/capgen_test/temp_suite.xml b/test/capgen_test/temp_suite.xml index 9974b02a..6fa836db 100644 --- a/test/capgen_test/temp_suite.xml +++ b/test/capgen_test/temp_suite.xml @@ -1,8 +1,10 @@ - + temp_set + + temp_calc_adjust temp_adjust diff --git a/test/capgen_test/test_host.F90 b/test/capgen_test/test_host.F90 index 55c7159e..056b30a0 100644 --- a/test/capgen_test/test_host.F90 +++ b/test/capgen_test/test_host.F90 @@ -355,7 +355,8 @@ program test implicit none - character(len=cs), target :: test_parts1(1) = (/ 'physics ' /) + character(len=cs), target :: test_parts1(2) = (/ 'physics1 ', & + 'physics2 ' /) character(len=cs), target :: test_parts2(1) = (/ 'data_prep ' /) character(len=cm), target :: test_invars1(6) = (/ & 'potential_temperature ', & diff --git a/test/var_compatibility_test/effr_calc.F90 b/test/var_compatibility_test/effr_calc.F90 index b877e99a..3a6caab0 100644 --- a/test/var_compatibility_test/effr_calc.F90 +++ b/test/var_compatibility_test/effr_calc.F90 @@ -16,7 +16,8 @@ module effr_calc !! \htmlinclude arg_table_effr_calc_run.html !! subroutine effr_calc_run(ncol, nlev, effrr_in, effrg_in, effrl_inout, & - effri_out, effrs_inout, has_graupel, errmsg, errflg) + effri_out, effrs_inout, has_graupel, scalar_var, & + errmsg, errflg) integer, intent(in) :: ncol integer, intent(in) :: nlev @@ -26,6 +27,7 @@ subroutine effr_calc_run(ncol, nlev, effrr_in, effrg_in, effrl_inout, & real(kind_phys), intent(out) :: effri_out(:,:) real(8),intent(inout) :: effrs_inout(:,:) logical, intent(in) :: has_graupel + real(kind_phys), intent(inout) :: scalar_var character(len=512), intent(out) :: errmsg integer, intent(out) :: errflg !---------------------------------------------------------------- @@ -44,6 +46,7 @@ subroutine effr_calc_run(ncol, nlev, effrr_in, effrg_in, effrl_inout, & effrl_inout = min(max(effrl_inout,re_qc_min),re_qc_max) effri_out = re_qi_avg effrs_inout = effrs_inout + 10.0 ! in micrometer + scalar_var = 2.0 ! in km end subroutine effr_calc_run diff --git a/test/var_compatibility_test/effr_calc.meta b/test/var_compatibility_test/effr_calc.meta index 14687f21..d1712f3a 100644 --- a/test/var_compatibility_test/effr_calc.meta +++ b/test/var_compatibility_test/effr_calc.meta @@ -66,6 +66,14 @@ dimensions = () type = logical intent = in +[ scalar_var ] + standard_name = scalar_variable_for_testing + long_name = scalar variable for testing + units = km + dimensions = () + type = real + kind = kind_phys + intent = inout [ errmsg ] standard_name = ccpp_error_message long_name = Error message for error handling in CCPP diff --git a/test/var_compatibility_test/run_test b/test/var_compatibility_test/run_test index 9239c5d1..76ad982e 100755 --- a/test/var_compatibility_test/run_test +++ b/test/var_compatibility_test/run_test @@ -140,6 +140,7 @@ 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},scalar_variable_for_testing" required_vars_var_compatibility="${required_vars_var_compatibility},vertical_layer_dimension" input_vars_var_compatibility="effective_radius_of_stratiform_cloud_graupel" input_vars_var_compatibility="${input_vars_var_compatibility},effective_radius_of_stratiform_cloud_liquid_water_particle" @@ -149,11 +150,13 @@ 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},scalar_variable_for_testing" 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},effective_radius_of_stratiform_cloud_ice_particle" 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_snow_particle" +output_vars_var_compatibility="${output_vars_var_compatibility},scalar_variable_for_testing" ## ## Run a database report and check the return string diff --git a/test/var_compatibility_test/test_host.F90 b/test/var_compatibility_test/test_host.F90 index 12215bd1..6e170607 100644 --- a/test/var_compatibility_test/test_host.F90 +++ b/test/var_compatibility_test/test_host.F90 @@ -351,21 +351,23 @@ program test character(len=cs), target :: test_parts1(1) = (/ 'radiation ' /) - character(len=cm), target :: test_invars1(5) = (/ & + character(len=cm), target :: test_invars1(6) = (/ & 'effective_radius_of_stratiform_cloud_rain_particle ', & 'effective_radius_of_stratiform_cloud_liquid_water_particle', & 'effective_radius_of_stratiform_cloud_snow_particle ', & 'effective_radius_of_stratiform_cloud_graupel ', & + 'scalar_variable_for_testing ', & 'flag_indicating_cloud_microphysics_has_graupel '/) - character(len=cm), target :: test_outvars1(5) = (/ & + character(len=cm), target :: test_outvars1(6) = (/ & 'ccpp_error_code ', & 'ccpp_error_message ', & 'effective_radius_of_stratiform_cloud_ice_particle ', & 'effective_radius_of_stratiform_cloud_liquid_water_particle', & - 'effective_radius_of_stratiform_cloud_snow_particle ' /) + 'effective_radius_of_stratiform_cloud_snow_particle ', & + 'scalar_variable_for_testing ' /) - character(len=cm), target :: test_reqvars1(8) = (/ & + character(len=cm), target :: test_reqvars1(9) = (/ & 'ccpp_error_code ', & 'ccpp_error_message ', & 'effective_radius_of_stratiform_cloud_rain_particle ', & @@ -373,6 +375,7 @@ program test 'effective_radius_of_stratiform_cloud_liquid_water_particle', & 'effective_radius_of_stratiform_cloud_snow_particle ', & 'effective_radius_of_stratiform_cloud_graupel ', & + 'scalar_variable_for_testing ', & 'flag_indicating_cloud_microphysics_has_graupel '/) type(suite_info) :: test_suites(1) diff --git a/test/var_compatibility_test/test_host_data.F90 b/test/var_compatibility_test/test_host_data.F90 index b17fb916..1980f95a 100644 --- a/test/var_compatibility_test/test_host_data.F90 +++ b/test/var_compatibility_test/test_host_data.F90 @@ -10,6 +10,7 @@ module test_host_data effrl, & ! effective radius of cloud liquid water effri, & ! effective radius of cloud ice effrg ! effective radius of cloud graupel + real(kind_phys) :: scalar_var end type physics_state public allocate_physics_state diff --git a/test/var_compatibility_test/test_host_data.meta b/test/var_compatibility_test/test_host_data.meta index 1d29572c..01ad7a4a 100644 --- a/test/var_compatibility_test/test_host_data.meta +++ b/test/var_compatibility_test/test_host_data.meta @@ -33,3 +33,10 @@ type = real kind = kind_phys active = (flag_indicating_cloud_microphysics_has_graupel) +[scalar_var] + standard_name = scalar_variable_for_testing + long_name = unused scalar variable + units = m + dimensions = () + type = real + kind = kind_phys diff --git a/test/var_compatibility_test/test_host_mod.F90 b/test/var_compatibility_test/test_host_mod.F90 index 2761d9fa..877e3432 100644 --- a/test/var_compatibility_test/test_host_mod.F90 +++ b/test/var_compatibility_test/test_host_mod.F90 @@ -27,6 +27,7 @@ subroutine init_data() phys_state%effrr = 1.0E-3 ! 1000 microns, in meter phys_state%effrl = 1.0E-4 ! 100 microns, in meter phys_state%effri = 5.0E-5 ! 50 microns, in meter + phys_state%scalar_var = 1.0 ! in m effrs = 5.0E-4 ! 500 microns, in meter if (mp_has_graupel) then phys_state%effrg = 2.5E-4 ! 250 microns, in meter @@ -40,6 +41,7 @@ logical function compare_data() real(kind_phys), parameter :: effrl_expected = 5.0E-5 ! 50 microns, in meter real(kind_phys), parameter :: effri_expected = 7.5E-5 ! 75 microns, in meter real(kind_phys), parameter :: effrs_expected = 5.1E-4 ! 510 microns, in meter + real(kind_phys), parameter :: scalar_expected = 2.0E3 ! 2 km, in meter real(kind_phys), parameter :: tolerance = 1.0E-6 ! used as scaling factor for expected value compare_data = .true. @@ -68,6 +70,12 @@ logical function compare_data() compare_data = .false. end if + if (abs( phys_state%scalar_var - scalar_expected) > tolerance*scalar_expected) then + write(6, '(a,e16.7,a,e16.7)') 'Error: max diff of scalar_var from expected value exceeds tolerance: ', & + abs( phys_state%scalar_var - scalar_expected), ' > ', tolerance*scalar_expected + compare_data = .false. + end if + end function compare_data end module test_host_mod diff --git a/test/var_compatibility_test/test_reports.py b/test/var_compatibility_test/test_reports.py index a56457bc..fd5e5203 100755 --- a/test/var_compatibility_test/test_reports.py +++ b/test/var_compatibility_test/test_reports.py @@ -72,11 +72,13 @@ def usage(errmsg=None): "effective_radius_of_stratiform_cloud_rain_particle", "effective_radius_of_stratiform_cloud_snow_particle", "effective_radius_of_stratiform_cloud_graupel", + "scalar_variable_for_testing", "flag_indicating_cloud_microphysics_has_graupel"] _OUTPUT_VARS_VAR_ACTION = ["ccpp_error_code", "ccpp_error_message", "effective_radius_of_stratiform_cloud_ice_particle", "effective_radius_of_stratiform_cloud_liquid_water_particle", - "effective_radius_of_stratiform_cloud_snow_particle"] + "effective_radius_of_stratiform_cloud_snow_particle", + "scalar_variable_for_testing"] _REQUIRED_VARS_VAR_ACTION = _INPUT_VARS_VAR_ACTION + _OUTPUT_VARS_VAR_ACTION def fields_string(field_type, field_list, sep):