Skip to content

Commit

Permalink
Added null pointers to caps when scheme has optional argument, but no…
Browse files Browse the repository at this point in the history
…t provided by host
  • Loading branch information
dustinswales committed Feb 8, 2024
1 parent 423dc71 commit aa59672
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 30 deletions.
130 changes: 101 additions & 29 deletions scripts/suite_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -1237,7 +1237,7 @@ def analyze(self, phase, group, scheme_library, suite_vars, level):
# end if

# Is this a conditionally allocated variable?
# If so, declare local target and pointer varaibles. This is needed to
# If so, declare localpointer varaible. This is needed to
# pass inactive (not present) status through the caps.
if var.get_prop_value('optional'):
newvar_ptr = var.clone(var.get_prop_value('local_name')+'_ptr')
Expand Down Expand Up @@ -1538,31 +1538,17 @@ def write_var_debug_check(self, var, internal_var, cldicts, outfile, errcode, er
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+1)
outfile.write(f"{internal_var_lname} = {local_name}{lbound_string}", tmp_indent+1)
outfile.write(f"{internal_var_lname} = {local_name}{ubound_string}", tmp_indent+1)
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)
if conditional != '.true.':
outfile.write(f"end if", indent)
# end if
outfile.write('',indent)

def associate_optional_var(self, dict_var, var, var_ptr, has_transform, cldicts, indent, outfile):
"""Write local pointer association for optional variables."""
(conditional, _) = dict_var.conditional(cldicts)
if (has_transform):
lname = var.get_prop_value('local_name')+'_local'
else:
lname = var.get_prop_value('local_name')
# end if
lname_ptr = var_ptr.get_prop_value('local_name')
outfile.write(f"if {conditional} then", indent)
outfile.write(f"{lname_ptr} => {lname}", indent+1)
outfile.write(f"end if", indent)

def assign_pointer_to_var(self, dict_var, var, var_ptr, has_transform, cldicts, indent, outfile):
"""Assign local pointer to variable."""
intent = var.get_prop_value('intent')
if (intent == 'out' or intent == 'inout'):
if (dict_var):
(conditional, _) = dict_var.conditional(cldicts)
if (has_transform):
lname = var.get_prop_value('local_name')+'_local'
Expand All @@ -1571,8 +1557,27 @@ def assign_pointer_to_var(self, dict_var, var, var_ptr, has_transform, cldicts,
# end if
lname_ptr = var_ptr.get_prop_value('local_name')
outfile.write(f"if {conditional} then", indent)
outfile.write(f"{lname} = {lname_ptr}", indent+1)
outfile.write(f"{lname_ptr} => {lname}", indent+1)
outfile.write(f"end if", indent)
# end if

def assign_pointer_to_var(self, dict_var, var, var_ptr, has_transform, cldicts, indent, outfile):
"""Assign local pointer to variable."""
if (dict_var):
intent = var.get_prop_value('intent')
if (intent == 'out' or intent == 'inout'):
(conditional, _) = dict_var.conditional(cldicts)
if (has_transform):
lname = var.get_prop_value('local_name')+'_local'
else:
lname = var.get_prop_value('local_name')
# end if
lname_ptr = var_ptr.get_prop_value('local_name')
outfile.write(f"if {conditional} then", indent)
outfile.write(f"{lname} = {lname_ptr}", indent+1)
outfile.write(f"end if", indent)
# end if
# end if

def add_var_transform(self, var, compat_obj, vert_dim):
"""Register any variable transformation needed by <var> for this Scheme.
Expand Down Expand Up @@ -1669,11 +1674,20 @@ def write(self, outfile, errcode, errmsg, indent):
# coming from the group's call list)
#
if self.__var_debug_checks:
outfile.write('! Run debug tests', indent+1)
outfile.write('! ##################################################################', indent+1)
outfile.write('! Begin debug tests', indent+1)
outfile.write('! ##################################################################', indent+1)
outfile.write('', indent+1)
# end if
for (var, internal_var) in self.__var_debug_checks:
stmt = self.write_var_debug_check(var, internal_var, cldicts, outfile, errcode, errmsg, indent+1)
# end for
if self.__var_debug_checks:
outfile.write('! ##################################################################', indent+1)
outfile.write('! End debug tests', indent+1)
outfile.write('! ##################################################################', indent+1)
outfile.write('', indent+1)
# end if
#
# Write any reverse (pre-Scheme) transforms.
#
Expand Down Expand Up @@ -2252,12 +2266,17 @@ def write(self, outfile, host_arglist, indent, const_mod,
# end if
# Collect information on local variables
subpart_vars = {}
subpart_opts = {}
subpart_scl = {}
allocatable_var_set = set()
optional_var_set = set()
pointer_var_set = list()
inactive_var_set = set()
for item in [self]:# + self.parts:
for var in item.declarations():
lname = var.get_prop_value('local_name')
if lname in subpart_vars:
sname = var.get_prop_value('standard_name')
if (lname in subpart_vars) or (lname in subpart_opts) or (lname in subpart_scl):
if subpart_vars[lname][0].compatible(var, self.run_env):
pass # We already are going to declare this variable
else:
Expand All @@ -2266,10 +2285,20 @@ def write(self, outfile, host_arglist, indent, const_mod,
# end if
else:
opt_var = var.get_prop_value('optional')
subpart_vars[lname] = (var, item, opt_var)
dims = var.get_dimensions()
if (dims is not None) and dims:
allocatable_var_set.add(lname)
if opt_var:
if (self.call_list.find_variable(standard_name=sname)):
subpart_opts[lname] = (var, item, opt_var)
optional_var_set.add(lname)
else:
inactive_var_set.add(var)
else:
subpart_vars[lname] = (var, item, opt_var)
allocatable_var_set.add(lname)
# end if
else:
subpart_scl[lname] = (var, item, opt_var)
# end if
# end if
# end for
Expand All @@ -2294,6 +2323,25 @@ def write(self, outfile, host_arglist, indent, const_mod,
pointer_var_set.append([name,kind,dimstr,vtype])
# end if
# end for
# Any optional arguments that are not requested by the host need to have
# a local null pointer passed from the group to the scheme.
for ivar in inactive_var_set:
name = ivar.get_prop_value('local_name')+'_ptr'
kind = ivar.get_prop_value('kind')
dims = ivar.get_dimensions()
if ivar.is_ddt():
vtype = 'type'
else:
vtype = ivar.get_prop_value('type')
# end if
if dims:
dimstr = '(:' + ',:'*(len(dims) - 1) + ')'
else:
dimstr = ''
# end if
pointer_var_set.append([name,kind,dimstr,vtype])
# end for

# end for
# First, write out the subroutine header
subname = self.name
Expand Down Expand Up @@ -2330,10 +2378,19 @@ def write(self, outfile, host_arglist, indent, const_mod,
self.run_env.logger.debug(msg.format(self.name, call_vars))
# end if
self.call_list.declare_variables(outfile, indent+1, dummy=True)
# DECLARE local variables
if subpart_vars:
outfile.write('\n! Local Variables', indent+1)
# end if
# Write out local variables
# Scalars
for key in subpart_scl:
var = subpart_scl[key][0]
spdict = subpart_scl[key][1]
target = subpart_scl[key][2]
var.write_def(outfile, indent+1, spdict,
allocatable=False, target=target)
# end for
# Allocatable arrays
for key in subpart_vars:
var = subpart_vars[key][0]
spdict = subpart_vars[key][1]
Expand All @@ -2342,10 +2399,16 @@ def write(self, outfile, host_arglist, indent, const_mod,
allocatable=(key in allocatable_var_set),
target=target)
# end for
# Write out local pointer variables.
if pointer_var_set:
outfile.write('\n! Local Pointer variables', indent+1)
# end if
# Target arrays.
for key in subpart_opts:
var = subpart_opts[key][0]
spdict = subpart_opts[key][1]
target = subpart_opts[key][2]
var.write_def(outfile, indent+1, spdict,
allocatable=(key in optional_var_set),
target=target)
# end for
# Pointer variables.
for (name, kind, dim, vtype) in pointer_var_set:
var.write_ptr_def(outfile, indent+1, name, kind, dim, vtype)
# end for
Expand Down Expand Up @@ -2395,6 +2458,12 @@ def write(self, outfile, host_arglist, indent, const_mod,
alloc_str = self.allocate_dim_str(dims, var.context)
outfile.write(alloc_stmt.format(lname, alloc_str), indent+1)
# end for
for lname in optional_var_set:
var = subpart_opts[lname][0]
dims = var.get_dimensions()
alloc_str = self.allocate_dim_str(dims, var.context)
outfile.write(alloc_stmt.format(lname, alloc_str), indent+1)
# end for
# Allocate suite vars
if allocate:
outfile.write('\n! Allocate suite_vars', indent+1)
Expand Down Expand Up @@ -2429,6 +2498,9 @@ def write(self, outfile, host_arglist, indent, const_mod,
for lname in allocatable_var_set:
outfile.write('deallocate({})'.format(lname), indent+1)
# end for
for lname in optional_var_set:
outfile.write('deallocate({})'.format(lname), indent+1)
# end for
# Nullify local pointers
if pointer_var_set:
outfile.write('\n! Nullify local pointers', indent+1)
Expand Down
3 changes: 2 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,7 @@ module effr_calc
!! \htmlinclude arg_table_effr_calc_run.html
!!
subroutine effr_calc_run(ncol, nlev, effrr_in, effrg_in, ncg_in, nci_out, &
effrl_inout, effri_out, effrs_inout, errmsg, errflg)
effrl_inout, effri_out, effrs_inout, ncl_out, errmsg, errflg)

integer, intent(in) :: ncol
integer, intent(in) :: nlev
Expand All @@ -27,6 +27,7 @@ subroutine effr_calc_run(ncol, nlev, effrr_in, effrg_in, ncg_in, nci_out, &
real(kind_phys), intent(inout) :: effrl_inout(:,:)
real(kind_phys), intent(out),optional :: effri_out(:,:)
real(8),intent(inout) :: effrs_inout(:,:)
real(kind_phys), intent(out),optional :: ncl_out(:,:)
character(len=512), intent(out) :: errmsg
integer, intent(out) :: errflg
!----------------------------------------------------------------
Expand Down
9 changes: 9 additions & 0 deletions test/var_compatibility_test/effr_calc.meta
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,15 @@
kind = 8
intent = inout
top_at_one = .true.
[ncl_out]
standard_name = cloud_liquid_number_concentration
long_name = number concentration of cloud liquid
units = kg-1
dimensions = (horizontal_loop_extent,vertical_layer_dimension)
type = real
kind = kind_phys
intent = out
optional=.true.
[ errmsg ]
standard_name = ccpp_error_message
long_name = Error message for error handling in CCPP
Expand Down

0 comments on commit aa59672

Please sign in to comment.