Skip to content
Merged
2 changes: 1 addition & 1 deletion scripts/metavar.py
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,7 @@ def call_string(self, var_dict, loop_vars=None):
lname = ""
for item in dim.split(':'):
if item:
dvar = var_dict.find_variable(standard_name=item,
dvar = var_dict.find_variable(standard_name=item.lower(),
any_scope=False)
if dvar is None:
try:
Expand Down
129 changes: 96 additions & 33 deletions scripts/suite_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -1360,18 +1360,32 @@ def add_var_debug_check(self, var):
if not ':' in dim:
dim_var = self.find_variable(standard_name=dim)
if not dim_var:
raise Exception(f"No dimension with standard name '{dim}'")
self.update_group_call_list_variable(dim_var)
# To allow for numerical dimensions in metadata.
if not dim.isnumeric():
raise Exception(f"No dimension with standard name '{dim}'")
# end if
else:
self.update_group_call_list_variable(dim_var)
# end if
else:
(ldim, udim) = dim.split(":")
ldim_var = self.find_variable(standard_name=ldim)
if not ldim_var:
raise Exception(f"No dimension with standard name '{ldim}'")
# To allow for numerical dimensions in metadata.
if not ldim.isnumeric():
raise Exception(f"No dimension with standard name '{ldim}'")
# end if
# end if
self.update_group_call_list_variable(ldim_var)
udim_var = self.find_variable(standard_name=udim)
if not udim_var:
raise Exception(f"No dimension with standard name '{udim}'")
self.update_group_call_list_variable(udim_var)
# To allow for numerical dimensions in metadata.
if not udim.isnumeric():
raise Exception(f"No dimension with standard name '{udim}'")
# end if
else:
self.update_group_call_list_variable(udim_var)
# end if

# Add the variable to the list of variables to check. Record which internal_var to use.
self.__var_debug_checks.append([var, internal_var])
Expand Down Expand Up @@ -1436,6 +1450,7 @@ def write_var_debug_check(self, var, internal_var, cldicts, outfile, errcode, er
dimensions = var.get_dimensions()
active = var.get_prop_value('active')
allocatable = var.get_prop_value('allocatable')
vtype = var.get_prop_value('type')

# Need the local name from the group call list,
# from the locally-defined variables of the group,
Expand Down Expand Up @@ -1496,6 +1511,8 @@ def write_var_debug_check(self, var, internal_var, cldicts, outfile, errcode, er
dim_strings = []
lbound_strings = []
ubound_strings = []
dim_lengths = []
local_names = []
for dim in dimensions:
if not ':' in dim:
# In capgen, any true dimension (that is not a single index) does
Expand Down Expand Up @@ -1524,18 +1541,30 @@ def write_var_debug_check(self, var, internal_var, cldicts, outfile, errcode, er
for var_dict in cldicts:
dvar = var_dict.find_variable(standard_name=ldim, any_scope=False)
if dvar is not None:
ldim_lname = dvar.get_prop_value('local_name')
break
if not dvar:
raise Exception(f"No variable with standard name '{ldim}' in cldicts")
ldim_lname = dvar.get_prop_value('local_name')
# To allow for numerical dimensions in metadata.
if ldim.isnumeric():
ldim_lname = ldim
else:
raise Exception(f"No variable with standard name '{ldim}' in cldicts")
# endif
# endif
# Get dimension for upper bound
for var_dict in cldicts:
dvar = var_dict.find_variable(standard_name=udim, any_scope=False)
if dvar is not None:
udim_lname = dvar.get_prop_value('local_name')
break
if not dvar:
raise Exception(f"No variable with standard name '{udim}' in cldicts")
udim_lname = dvar.get_prop_value('local_name')
# To allow for numerical dimensions in metadata.
if udim.isnumeric():
udim_lname = udim
else:
raise Exception(f"No variable with standard name '{udim}' in cldicts")
# end if
# end if
# Assemble dimensions and bounds for size checking
dim_length = f'{udim_lname}-{ldim_lname}+1'
dim_string = ":"
Expand All @@ -1546,46 +1575,80 @@ def write_var_debug_check(self, var, internal_var, cldicts, outfile, errcode, er
lbound_strings.append(lbound_string)
ubound_strings.append(ubound_string)
array_size = f'{array_size}*({dim_length})'

dim_lengths.append(dim_length)
local_names.append(local_name)
# end for
# Various strings needed to get the right size
# and lower/upper bound of the array
dim_string = '(' + ','.join(dim_strings) + ')'
lbound_string = '(' + ','.join(lbound_strings) + ')'
ubound_string = '(' + ','.join(ubound_strings) + ')'

# Write size check
tmp_indent = indent
if conditional != '.true.':
tmp_indent = indent + 1
outfile.write(f"if {conditional} then", indent)
# end if
outfile.write(f"! Check size of array {local_name}", tmp_indent)
outfile.write(f"if (size({local_name}{dim_string}) /= {array_size}) then", tmp_indent)
outfile.write(f"write({errmsg}, '(a)') 'In group {self.__group.name} before {self.__subroutine_name}:'", tmp_indent+1)
outfile.write(f"write({errmsg}, '(2(a,i8))') 'for array {local_name}, expected size ', {array_size}, ' but got ', size({local_name})", tmp_indent+1)
outfile.write(f"{errcode} = 1", tmp_indent+1)
outfile.write(f"return", tmp_indent+1)
outfile.write(f"end if", tmp_indent)
if conditional != '.true.':
outfile.write(f"end if", indent)
# end if
outfile.write('',indent)

# Assign lower/upper bounds to internal_var (scalar) if intent is not out
if not intent == 'out':
internal_var_lname = internal_var.get_prop_value('local_name')
# - Only for types int and real.
if (vtype == "integer") or (vtype == "real"):
tmp_indent = indent
if conditional != '.true.':
tmp_indent = indent + 1
outfile.write(f"if {conditional} then", indent)
# end if
outfile.write(f"! Assign lower/upper bounds of {local_name} to {internal_var_lname}", tmp_indent)
outfile.write(f"{internal_var_lname} = {local_name}{lbound_string}", tmp_indent)
outfile.write(f"{internal_var_lname} = {local_name}{ubound_string}", tmp_indent)
outfile.write(f"! Check size of array {local_name}", tmp_indent)
outfile.write(f"if (size({local_name}{dim_string}) /= {array_size}) then", tmp_indent)
outfile.write(f"write({errmsg}, '(2(a,i8))') 'In group {self.__group.name} before "\
f"{self.__subroutine_name}: for array {local_name}, expected size ', "\
f"{array_size}, ' but got ', size({local_name})", tmp_indent+1)
outfile.write(f"{errcode} = 1", tmp_indent+1)
outfile.write(f"return", tmp_indent+1)
outfile.write(f"end if", tmp_indent)
if conditional != '.true.':
outfile.write(f"end if", indent)
# end if
outfile.write('',indent)
# end if

# Write size check for each dimension in array.
# - If intent is not out.
# - Only for types int and real.
if (vtype == "integer") or (vtype == "real"):
if not intent == 'out':
tmp_indent = indent
if conditional != '.true.':
tmp_indent = indent + 1
outfile.write(f"if {conditional} then", indent)
# end if
ndims = len(dim_lengths)

# Loop through dimensions in var and check if length of each dimension
# is the correct size. Skip for 1D variables.
if (ndims > 1):
for index, dim_length in enumerate(dim_lengths):
array_ref = '('
# Dimension(s) before current rank to be checked.
array_ref += '1,'*(index)
# Dimension to check.
array_ref += dim_strings[index]
# Dimension(s) after current rank to be checked.
array_ref += ',1'*(ndims-(index+1))
array_ref += ')'
#
outfile.write(f"! Check length of {local_names[index]}{array_ref}", tmp_indent)
outfile.write(f"if (size({local_names[index]}{array_ref}) /= {dim_length}) then ", \
tmp_indent)
outfile.write(f"write({errmsg}, '(2(a,i8))') 'In group {self.__group.name} before " \
f"{self.__subroutine_name}: for array {local_names[index]}{array_ref}, "\
f"expected size ', {dim_length}, ' but got ', " \
f"size({local_names[index]}{array_ref})", tmp_indent+1)
outfile.write(f"{errcode} = 1", tmp_indent+1)
outfile.write(f"return", tmp_indent+1)
outfile.write(f"end if", tmp_indent)
# end for
#end if
if conditional != '.true.':
outfile.write(f"end if", indent)
# end if
outfile.write('',indent)
# endif
# end if

def associate_optional_var(self, dict_var, var, var_ptr, has_transform, cldicts, indent, outfile):
"""Write local pointer association for optional variables."""
Expand Down
22 changes: 18 additions & 4 deletions test/capgen_test/run_test
Original file line number Diff line number Diff line change
Expand Up @@ -146,41 +146,55 @@ 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"
output_vars_ddt="${output_vars_ddt},model_times,number_of_model_times,surface_air_pressure"
required_vars_temp="ccpp_error_code,ccpp_error_message"
required_vars_temp="array_variable_for_testing"
required_vars_temp="${required_vars_temp},ccpp_error_code,ccpp_error_message"
required_vars_temp="${required_vars_temp},coefficients_for_interpolation"
required_vars_temp="${required_vars_temp},configuration_variable"
required_vars_temp="${required_vars_temp},horizontal_dimension"
required_vars_temp="${required_vars_temp},horizontal_loop_begin"
required_vars_temp="${required_vars_temp},horizontal_loop_end"
required_vars_temp="${required_vars_temp},index_of_water_vapor_specific_humidity"
required_vars_temp="${required_vars_temp},lower_bound_of_vertical_dimension_of_soil"
required_vars_temp="${required_vars_temp},number_of_tracers"
required_vars_temp="${required_vars_temp},potential_temperature"
required_vars_temp="${required_vars_temp},potential_temperature_at_interface"
required_vars_temp="${required_vars_temp},potential_temperature_increment"
required_vars_temp="${required_vars_temp},soil_levels"
required_vars_temp="${required_vars_temp},surface_air_pressure"
required_vars_temp="${required_vars_temp},temperature_at_diagnostic_levels"
required_vars_temp="${required_vars_temp},time_step_for_physics"
required_vars_temp="${required_vars_temp},upper_bound_of_vertical_dimension_of_soil"
required_vars_temp="${required_vars_temp},vertical_interface_dimension"
required_vars_temp="${required_vars_temp},vertical_layer_dimension"
required_vars_temp="${required_vars_temp},water_vapor_specific_humidity"
input_vars_temp="coefficients_for_interpolation"
input_vars_temp="array_variable_for_testing"
input_vars_temp="${input_vars_temp},coefficients_for_interpolation"
input_vars_temp="${input_vars_temp},configuration_variable"
input_vars_temp="${input_vars_temp},horizontal_dimension"
input_vars_temp="${input_vars_temp},horizontal_loop_begin"
input_vars_temp="${input_vars_temp},horizontal_loop_end"
input_vars_temp="${input_vars_temp},index_of_water_vapor_specific_humidity"
input_vars_temp="${input_vars_temp},lower_bound_of_vertical_dimension_of_soil"
input_vars_temp="${input_vars_temp},number_of_tracers"
input_vars_temp="${input_vars_temp},potential_temperature"
input_vars_temp="${input_vars_temp},potential_temperature_at_interface"
input_vars_temp="${input_vars_temp},potential_temperature_increment"
input_vars_temp="${input_vars_temp},surface_air_pressure,time_step_for_physics"
input_vars_temp="${input_vars_temp},soil_levels"
input_vars_temp="${input_vars_temp},surface_air_pressure"
input_vars_temp="${input_vars_temp},temperature_at_diagnostic_levels"
input_vars_temp="${input_vars_temp},time_step_for_physics"
input_vars_temp="${input_vars_temp},upper_bound_of_vertical_dimension_of_soil"
input_vars_temp="${input_vars_temp},vertical_interface_dimension"
input_vars_temp="${input_vars_temp},vertical_layer_dimension"
input_vars_temp="${input_vars_temp},water_vapor_specific_humidity"
output_vars_temp="ccpp_error_code,ccpp_error_message"
output_vars_temp="array_variable_for_testing"
output_vars_temp="${output_vars_temp},ccpp_error_code,ccpp_error_message"
output_vars_temp="${output_vars_temp},coefficients_for_interpolation"
output_vars_temp="${output_vars_temp},potential_temperature"
output_vars_temp="${output_vars_temp},potential_temperature_at_interface"
output_vars_temp="${output_vars_temp},soil_levels"
output_vars_temp="${output_vars_temp},surface_air_pressure"
output_vars_temp="${output_vars_temp},temperature_at_diagnostic_levels"
output_vars_temp="${output_vars_temp},water_vapor_specific_humidity"

##
Expand Down
16 changes: 13 additions & 3 deletions test/capgen_test/temp_set.F90
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,20 @@ MODULE temp_set
!> \section arg_table_temp_set_run Argument Table
!! \htmlinclude arg_table_temp_set_run.html
!!
SUBROUTINE temp_set_run(ncol, lev, timestep, temp_level, temp, ps, &
to_promote, promote_pcnst, errmsg, errflg)
SUBROUTINE temp_set_run(ncol, lev, timestep, temp_level, temp_diag, temp, ps, &
to_promote, promote_pcnst, slev_lbound, soil_levs, var_array, errmsg, errflg)
!----------------------------------------------------------------
IMPLICIT NONE
!----------------------------------------------------------------

integer, intent(in) :: ncol, lev
integer, intent(in) :: ncol, lev, slev_lbound
REAL(kind_phys), intent(out) :: temp(:,:)
real(kind_phys), intent(in) :: timestep
real(kind_phys), intent(in) :: ps(:)
REAL(kind_phys), INTENT(inout) :: temp_level(:, :)
real(kind_phys), intent(inout) :: temp_diag(:,:)
real(kind_phys), intent(inout) :: soil_levs(slev_lbound:)
real(kind_phys), intent(inout) :: var_array(:,:,:,:)
real(kind_phys), intent(out) :: to_promote(:, :)
real(kind_phys), intent(out) :: promote_pcnst(:)
character(len=512), intent(out) :: errmsg
Expand All @@ -38,6 +41,7 @@ SUBROUTINE temp_set_run(ncol, lev, timestep, temp_level, temp, ps, &

integer :: col_index
integer :: lev_index
real(kind_phys) :: internal_scalar_var

errmsg = ''
errflg = 0
Expand All @@ -56,6 +60,12 @@ SUBROUTINE temp_set_run(ncol, lev, timestep, temp_level, temp, ps, &
end do
end do

var_array(:,:,:,:) = 1._kind_phys

Comment thread
climbfuji marked this conversation as resolved.
!
internal_scalar_var = soil_levs(slev_lbound)
internal_scalar_var = soil_levs(0)

END SUBROUTINE temp_set_run

!> \section arg_table_temp_set_init Argument Table
Expand Down
29 changes: 29 additions & 0 deletions test/capgen_test/temp_set.meta
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@
type = real
kind = kind_phys
intent = inout
[ temp_diag ]
standard_name = temperature_at_diagnostic_levels
units = K
dimensions = (horizontal_loop_extent, 6)
type = real
kind = kind_phys
intent = inout
[ temp ]
standard_name = potential_temperature
units = K
Expand Down Expand Up @@ -61,6 +68,28 @@
type = real
kind = kind_phys
intent = out
[ slev_lbound ]
standard_name = lower_bound_of_vertical_dimension_of_soil
type = integer
units = count
dimensions = ()
intent = in
[ soil_levs ]
standard_name = soil_levels
long_name = soil levels
units = cm
dimensions = (lower_bound_of_vertical_dimension_of_soil:upper_bound_of_vertical_dimension_of_soil)
type = real
kind = kind_phys
intent = inout
[ var_array ]
standard_name = array_variable_for_testing
long_name = array variable for testing
units = none
dimensions = (horizontal_dimension,2,4,6)
type = real
kind = kind_phys
intent = inout
[ errmsg ]
standard_name = ccpp_error_message
long_name = Error message for error handling in CCPP
Expand Down
Loading