Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bugfixes for multiple groups and scalar variable transforms #542

Merged
merged 5 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion scripts/ccpp_suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion scripts/metavar.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
47 changes: 37 additions & 10 deletions scripts/suite_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -1614,20 +1632,25 @@ 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)
outfile.write('! Call scheme', indent+1)
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)

Expand Down Expand Up @@ -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))
Expand Down
30 changes: 26 additions & 4 deletions scripts/var_props.py
Original file line number Diff line number Diff line change
Expand Up @@ -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, \
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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]
Expand Down
4 changes: 3 additions & 1 deletion test/capgen_test/temp_suite.xml
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>

<suite name="temp_suite" version="1.0">
<group name="physics">
<group name="physics1">
<scheme>temp_set</scheme>
</group>
<group name="physics2">
<scheme>temp_calc_adjust</scheme>
<scheme>temp_adjust</scheme>
</group>
Expand Down
3 changes: 2 additions & 1 deletion test/capgen_test/test_host.F90
Original file line number Diff line number Diff line change
Expand Up @@ -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 ', &
Expand Down
5 changes: 4 additions & 1 deletion test/var_compatibility_test/effr_calc.F90
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
!----------------------------------------------------------------
Expand All @@ -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

Expand Down
8 changes: 8 additions & 0 deletions test/var_compatibility_test/effr_calc.meta
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions test/var_compatibility_test/run_test
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
Expand Down
11 changes: 7 additions & 4 deletions test/var_compatibility_test/test_host.F90
Original file line number Diff line number Diff line change
Expand Up @@ -351,28 +351,31 @@ 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 ', &
'effective_radius_of_stratiform_cloud_ice_particle ', &
'effective_radius_of_stratiform_cloud_liquid_water_particle', &
'effective_radius_of_stratiform_cloud_snow_particle ', &
'effective_radius_of_stratiform_cloud_graupel ', &
'scalar_variable_for_testing ', &
'flag_indicating_cloud_microphysics_has_graupel '/)

type(suite_info) :: test_suites(1)
Expand Down
1 change: 1 addition & 0 deletions test/var_compatibility_test/test_host_data.F90
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions test/var_compatibility_test/test_host_data.meta
Original file line number Diff line number Diff line change
Expand Up @@ -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
8 changes: 8 additions & 0 deletions test/var_compatibility_test/test_host_mod.F90
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -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
4 changes: 3 additions & 1 deletion test/var_compatibility_test/test_reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
Loading