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

Add capability to do unit conversations to capgen #504

Merged
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
c2b1f9b
Initial commit. Work in progress
Sep 22, 2023
a3353c7
Working.
Oct 11, 2023
bb86f8b
Housekeeping
Oct 11, 2023
92d00d8
Working with compatability object
Oct 20, 2023
adb0c38
Merge branch 'feature_capgen_unit_conversions_temp' into feature_capg…
Oct 20, 2023
eecc620
Revert change
Oct 20, 2023
592e15f
Omission from previous commit
Oct 20, 2023
a4b1c99
Omission from previous commit. again...
Oct 20, 2023
62a9d12
Omission from previous commit. again...
Oct 20, 2023
b603972
Merge branch 'feature/capgen' of https://github.com/NCAR/ccpp-framewo…
Oct 20, 2023
8d8589e
Cleanup VarCompatObj creation
dustinswales Oct 23, 2023
219f2e9
Bug fix for initialized_set_block (#503)
grantfirl Oct 23, 2023
3e14fa8
Vertical flipping working w/ new metadata attribute. Work in progress
dustinswales Oct 24, 2023
c29b0c0
Some more changes. Vertical flipping working
dustinswales Oct 25, 2023
19f6a30
Housekeeping
dustinswales Oct 25, 2023
aae4b43
Add kind transform to transform test
dustinswales Oct 25, 2023
c3d2b3a
Add local declaration of vertical extent, needed for vertical flipping
dustinswales Oct 26, 2023
ea01a47
Everything but getting the correct local variable name for the vertic…
dustinswales Oct 30, 2023
e47bf8f
Add snippet from Steve G. to get correct local_name for vertical_laye…
dustinswales Oct 31, 2023
253ad3a
Address reviewers comments
Nov 13, 2023
fe5f213
Address reviewers comments again
Nov 13, 2023
fc337a9
Address reviewers comments again again
Nov 13, 2023
3b04594
Merge branch 'feature/capgen' of https://github.com/NCAR/ccpp-framewo…
Nov 13, 2023
1db0447
Rename tests directory to test_prebuild
climbfuji Nov 30, 2023
f08fd63
Add test for ccpp_prebuild for blocked data structures
climbfuji Dec 1, 2023
a9e194a
Add CI tests for ccpp-prebuild
climbfuji Dec 1, 2023
3714ef8
Debugging CI workflow for prebuild
climbfuji Dec 1, 2023
d2e446e
Self-review
climbfuji Dec 1, 2023
998cc7b
Merge branch 'main' of https://github.com/NCAR/ccpp-framework into fe…
Dec 4, 2023
8d3af68
Merge branch 'feature/capgen' of https://github.com/NCAR/ccpp-framewo…
Dec 4, 2023
9b206f1
Revert "Merge branch 'main' of https://github.com/NCAR/ccpp-framework…
Dec 4, 2023
b5cc909
Activate var_action_test
Dec 4, 2023
4ec1cba
test_prebuild/test_blocked_data: 'use, intrinsic :: iso_fortran_env, …
climbfuji Dec 4, 2023
e6ffbd5
Fix unit tests for variable transformations. Reorganization a bit to …
Dec 4, 2023
e9c79eb
Cleanup forward/reverse transform terminology
Dec 4, 2023
bb4975a
Doc tests for transformations
Dec 4, 2023
265a05b
Add more inline documentation. Address reviewers comments.
Dec 5, 2023
0d0cfcd
Address reviewer comment
Dec 5, 2023
f280ef5
Update authors in CMakeList.
Dec 5, 2023
54e5462
Update authors in CMakeList.
Dec 5, 2023
1cc6da4
Address reviewer comment
Dec 5, 2023
0eca5c2
Merge pull request #515 from climbfuji/feature/ccpp_prebuild_blocked_…
climbfuji Dec 6, 2023
44f005f
Address comments
Dec 12, 2023
4aae9ad
Rename var_action test var_compatability
Dec 12, 2023
44d834b
Merge branch 'main' of https://github.com/NCAR/ccpp-framework into fe…
Dec 12, 2023
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
2 changes: 1 addition & 1 deletion scripts/ccpp_datafile.py
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,7 @@ def _new_var_entry(parent, var, full_entry=True):
"diagnostic_name", "diagnostic_name_fixed",
"kind", "persistence", "polymorphic", "protected",
"state_variable", "type", "units", "molar_mass",
"advected"])
"advected", "top_at_one"])
prop_list.extend(Var.constituent_property_names())
# end if
ventry = ET.SubElement(parent, "var")
Expand Down
8 changes: 6 additions & 2 deletions scripts/metavar.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ class Var:
default_in='.true.'),
VariableProperty('polymorphic', bool, optional_in=True,
default_in=False),
VariableProperty('top_at_one', bool, optional_in=True,
default_in=False),
VariableProperty('target', bool, optional_in=True,
default_in=False)]

Expand Down Expand Up @@ -376,15 +378,17 @@ def compatible(self, other, run_env):
sunits = self.get_prop_value('units')
sstd_name = self.get_prop_value('standard_name')
sloc_name = self.get_prop_value('local_name')
stopp = self.get_prop_value('top_at_one')
sdims = self.get_dimensions()
otype = other.get_prop_value('type')
okind = other.get_prop_value('kind')
ounits = other.get_prop_value('units')
ostd_name = other.get_prop_value('standard_name')
oloc_name = other.get_prop_value('local_name')
otopp = other.get_prop_value('top_at_one')
odims = other.get_dimensions()
compat = VarCompatObj(sstd_name, stype, skind, sunits, sdims, sloc_name,
ostd_name, otype, okind, ounits, odims, oloc_name,
compat = VarCompatObj(sstd_name, stype, skind, sunits, sdims, sloc_name, stopp,
ostd_name, otype, okind, ounits, odims, oloc_name, otopp,
run_env,
v1_context=self.context, v2_context=other.context)
if (not compat) and (run_env.logger is not None):
Expand Down
117 changes: 106 additions & 11 deletions scripts/suite_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from parse_tools import init_log, set_log_to_null
from var_props import is_horizontal_dimension, find_horizontal_dimension
from var_props import find_vertical_dimension
from var_props import VarCompatObj

# pylint: disable=too-many-lines

Expand Down Expand Up @@ -816,7 +817,7 @@ def find_variable(self, standard_name=None, source_var=None,
# end if
return found_var

def match_variable(self, var, vstdname=None, vdims=None):
def match_variable(self, var, run_env):
"""Try to find a source for <var> in this SuiteObject's dictionary
tree. Several items are returned:
found_var: True if a match was found
Expand All @@ -825,21 +826,19 @@ def match_variable(self, var, vstdname=None, vdims=None):
missing_vert: Vertical dim in parent but not in <var>
perm: Permutation (XXgoldyXX: Not yet implemented)
"""
if vstdname is None:
vstdname = var.get_prop_value('standard_name')
# end if
if vdims is None:
vdims = var.get_dimensions()
# end if
vstdname = var.get_prop_value('standard_name')
vdims = var.get_dimensions()
if (not vdims) and self.run_phase():
vmatch = VarDictionary.loop_var_match(vstdname)
else:
vmatch = None
# end if

found_var = False
missing_vert = None
new_vdims = list()
var_vdim = var.has_vertical_dimension(dims=vdims)
compat_obj = None
# Does this variable exist in the calling tree?
dict_var = self.find_variable(source_var=var, any_scope=True)
if dict_var is None:
Expand Down Expand Up @@ -872,6 +871,10 @@ def match_variable(self, var, vstdname=None, vdims=None):
new_vdims = list()
new_dict_dims = dict_dims
match = True
# Create compatability object, containing any necessary forward/reverse
# transforms from <var> and <dict_var>
compat_obj = var.compatible(dict_var, run_env)

# end if
# Add the variable to the parent call tree
if dict_dims == new_dict_dims:
Expand All @@ -894,7 +897,7 @@ def match_variable(self, var, vstdname=None, vdims=None):
# end if
# end if
# end if
return found_var, var_vdim, new_vdims, missing_vert
return found_var, var_vdim, new_vdims, missing_vert, compat_obj

def in_process_split(self):
"""Find out if we are in a process-split region"""
Expand Down Expand Up @@ -1077,6 +1080,8 @@ def __init__(self, scheme_xml, context, parent, run_env):
self.__lib = scheme_xml.get('lib', None)
self.__has_vertical_dimension = False
self.__group = None
self.__forward_transforms = list()
self.__reverse_transforms = list()
super().__init__(name, context, parent, run_env, active_call_list=True)

def update_group_call_list_variable(self, var):
Expand Down Expand Up @@ -1144,8 +1149,8 @@ def analyze(self, phase, group, scheme_library, suite_vars, level):
def_val = var.get_prop_value('default_value')
vdims = var.get_dimensions()
vintent = var.get_prop_value('intent')
args = self.match_variable(var, vstdname=vstdname, vdims=vdims)
found, vert_dim, new_dims, missing_vert = args
args = self.match_variable(var, self.run_env)
found, vert_dim, new_dims, missing_vert, compat_obj = args
if found:
if not self.has_vertical_dim:
self.__has_vertical_dimension = vert_dim is not None
Expand Down Expand Up @@ -1200,6 +1205,12 @@ def analyze(self, phase, group, scheme_library, suite_vars, level):
vstdname))
# end if
# end if
# Are there any forward/reverse transforms for this variable?
if compat_obj is not None and (compat_obj.has_vert_transforms or
compat_obj.has_unit_transforms or
compat_obj.has_kind_transforms):
self.add_var_transform(var, compat_obj, vert_dim)
peverwhee marked this conversation as resolved.
Show resolved Hide resolved

# end for
if self.needs_vertical is not None:
self.parent.add_part(self, replace=True) # Should add a vloop
Expand All @@ -1211,6 +1222,81 @@ def analyze(self, phase, group, scheme_library, suite_vars, level):
# end if
return scheme_mods

def add_var_transform(self, var, compat_obj, vert_dim):
"""Register any variable transformation needed by <var> for this Scheme.
For any transformation identified in <compat_obj>, create dummy variable
from <var> to perform the transformation. Determine the indices needed
for the transform and save for use during write stage"""

# Add dummy variable (<var>_local) needed for transformation.
dummy = var.clone(var.get_prop_value('local_name')+'_local')
self.__group.manage_variable(dummy)

# Create indices (default) for transform.
lindices = [':']*var.get_rank()
rindices = [':']*var.get_rank()

# 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 needed, modify horizontal dimension for loop substitution.
# NOT YET IMPLEMENTED
#hdim = find_horizontal_dimension(var.get_dimensions())
#if compat_obj.has_dim_transforms:

#
# Register any reverse (pre-Scheme) transforms.
#
if (var.get_prop_value('intent') != 'out'):
self.__reverse_transforms.append([dummy.get_prop_value('local_name'),
var.get_prop_value('local_name'),
rindices, lindices, compat_obj])

#
# Register any forward (post-Scheme) transforms.
#
if (var.get_prop_value('intent') != 'in'):
self.__forward_transforms.append([var.get_prop_value('local_name'),
dummy.get_prop_value('local_name'),
lindices, rindices, compat_obj])

def write_var_transform(self, var, dummy, rindices, lindices, compat_obj,
outfile, indent, forward):
"""Write variable transformation needed to call this Scheme in <outfile>.
<var> is the varaible that needs transformation before and after calling Scheme.
<dummy> is the local variable needed for the transformation..
<lindices> are the LHS indices of <dummy> for reverse transforms (before Scheme).
<rindices> are the RHS indices of <var> for reverse transforms (before Scheme).
<lindices> are the LHS indices of <var> for forward transforms (after Scheme).
<rindices> are the RHS indices of <dummy> for forward transforms (after Scheme).
"""
#
# Write reverse (pre-Scheme) transform.
#
if not forward:
# dummy(lindices) = var(rindices)
stmt = compat_obj.reverse_transform(lvar_lname=dummy,
rvar_lname=var,
lvar_indices=lindices,
rvar_indices=rindices)
#
# Write forward (post-Scheme) transform.
#
else:
# var(lindices) = dummy(rindices)
stmt = compat_obj.forward_transform(lvar_lname=var,
rvar_lname=dummy,
lvar_indices=rindices,
rvar_indices=lindices)
outfile.write(stmt, indent+1)

def write(self, outfile, errcode, indent):
# Unused arguments are for consistent write interface
# pylint: disable=unused-argument
Expand All @@ -1222,9 +1308,18 @@ def write(self, outfile, errcode, indent):
my_args = self.call_list.call_string(cldicts=cldicts,
is_func_call=True,
subname=self.subroutine_name)
stmt = 'call {}({})'

outfile.write('if ({} == 0) then'.format(errcode), indent)
# Write any reverse (pre-Scheme) transforms.
for (dummy, var, rindices, lindices, compat_obj) in self.__reverse_transforms:
tstmt = self.write_var_transform(var, dummy, rindices, lindices, compat_obj, outfile, indent, False)
# Write the scheme call.
stmt = 'call {}({})'
outfile.write(stmt.format(self.subroutine_name, my_args), indent+1)
# Write any forward (post-Scheme) transforms.
for (var, dummy, lindices, rindices, compat_obj) in self.__forward_transforms:
tstmt = self.write_var_transform(var, dummy, rindices, lindices, compat_obj, outfile, indent, True)
#
outfile.write('end if', indent)

def schemes(self):
Expand Down
Loading