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 debug switch to capgen (perform variable allocation checks etc) + fix spelling: var_compatability --> var_compatibility #512

Merged
merged 25 commits into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7682ec1
Add capability to parse Fortran pointer variables to fortran_tools/pa…
climbfuji Nov 8, 2023
a660e2f
Add --debug option to capgen (framework_env.py)
climbfuji Nov 8, 2023
a67b0bc
Add pointer attribute to Var class, add code to convert active attrib…
climbfuji Nov 8, 2023
e532774
Add debug checks for variables (scalars, arrays) before and after sch…
climbfuji Nov 8, 2023
ddae076
Fix typo in var_props.py
climbfuji Nov 8, 2023
29ee9ae
For advection tests, add --debug flag to capgen and update test reports
climbfuji Nov 8, 2023
de0891f
Add active attribute to variable water_vapor_specific_humidity in cap…
climbfuji Nov 8, 2023
b1b215d
For var_action tests, add --debug flag to capgen and update test reports
climbfuji Nov 8, 2023
adeef17
Clean up based on self-review
climbfuji Nov 8, 2023
7256311
Add scripts/parse_tools/fortran_conditional.py
climbfuji Nov 22, 2023
af16935
Cleanup: replace var_dicts with cldicts in write_debug_checks in suit…
climbfuji Nov 22, 2023
edb1bd5
Update comment on ddt_type property in metavar.py
climbfuji Nov 22, 2023
13b6363
Add doctests for conditional function of Var class
climbfuji Nov 22, 2023
fddde47
Add docstring documentation for add_var_debug_check and write_var_deb…
climbfuji Nov 28, 2023
8834299
Merge branch 'feature/capgen' of https://github.com/ncar/ccpp-framewo…
climbfuji Nov 29, 2023
b4f108b
Simplify logic for variable debug checks in suite_objects.py
climbfuji Nov 29, 2023
2e72cc8
Update variable lists for var_action_test
climbfuji Nov 29, 2023
3a4c056
Update scripts/framework_env.py
climbfuji Dec 11, 2023
464f62a
Fix wrong comment about group variables in scripts/suite_objects.py
climbfuji Dec 11, 2023
dfa59eb
In scripts/suite_objects.py: rename 'dummy' variables for var_debug_c…
climbfuji Dec 11, 2023
7367f98
Bug fix in scripts/suite_objects.py: also check variable allocations …
climbfuji Dec 15, 2023
fc6fec3
Remove stray debugging statement in scripts/suite_objects.py
climbfuji Dec 15, 2023
94b2755
Merge branch 'feature/capgen' of https://github.com/ncar/ccpp-framewo…
climbfuji Jan 18, 2024
70ae2b0
Fix spelling: compatability --> compatibility
climbfuji Jan 18, 2024
63aee18
Add missing instruction in test_prebuild/test_blocked_data/README.md
climbfuji Jan 18, 2024
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
20 changes: 19 additions & 1 deletion scripts/framework_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ def __init__(self, logger, ndict=None, verbose=0, clean=False,
host_files=None, scheme_files=None, suites=None,
preproc_directives=[], generate_docfiles=False, host_name='',
kind_types=[], use_error_obj=False, force_overwrite=False,
output_root=os.getcwd(), ccpp_datafile="datatable.xml"):
output_root=os.getcwd(), ccpp_datafile="datatable.xml",
debug = False):
"""Initialize a new CCPPFrameworkEnv object from the input arguments.
<ndict> is a dict with the parsed command-line arguments (or a
dictionary created with the necessary arguments).
Expand Down Expand Up @@ -198,6 +199,13 @@ def __init__(self, logger, ndict=None, verbose=0, clean=False,
self.__datatable_file = os.path.join(self.output_dir,
self.datatable_file)
# end if
# Enable or disable variable allocation checks
if ndict and ('debug' in ndict):
self.__debug = ndict['debug']
del ndict['debug']
else:
self.__debug = debug
# end if
self.__logger = logger
## Check to see if anything is left in dictionary
if ndict:
Expand Down Expand Up @@ -311,6 +319,12 @@ def datatable_file(self):
CCPPFrameworkEnv object."""
return self.__datatable_file

@property
def debug(self):
"""Return the <debug> property for this
CCPPFrameworkEnv object."""
return self.__debug

@property
def logger(self):
"""Return the <logger> property for this CCPPFrameworkEnv object."""
Expand Down Expand Up @@ -386,7 +400,11 @@ def parse_command_line(args, description, logger=None):
help="""Overwrite all CCPP-generated files, even
if unmodified""")

parser.add_argument("--debug", action='store_true', default=False,
help="Add variable allocation checks to assist debugging")

parser.add_argument("--verbose", action='count', default=0,
help="Log more activity, repeat for increased output")

pargs = parser.parse_args(args)
return CCPPFrameworkEnv(logger, vars(pargs))
50 changes: 50 additions & 0 deletions scripts/metavar.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from parse_tools import check_molar_mass
from parse_tools import ParseContext, ParseSource, type_name
from parse_tools import ParseInternalError, ParseSyntaxError, CCPPError
from parse_tools import FORTRAN_CONDITIONAL_REGEX_WORDS, FORTRAN_CONDITIONAL_REGEX
from var_props import CCPP_LOOP_DIM_SUBSTS, VariableProperty, VarCompatObj
from var_props import find_horizontal_dimension, find_vertical_dimension
from var_props import standard_name_to_long_name, default_kind_val
Expand Down Expand Up @@ -300,6 +301,8 @@ def __init__(self, prop_dict, source, run_env, context=None,
if 'units' not in prop_dict:
prop_dict['units'] = ""
# end if
# DH* To investigate later: Why is the DDT type
# copied into the kind attribute? Can we remove this?
prop_dict['kind'] = prop_dict['ddt_type']
del prop_dict['ddt_type']
self.__intrinsic = False
Expand Down Expand Up @@ -971,6 +974,53 @@ def has_vertical_dimension(self, dims=None):
# end if
return find_vertical_dimension(vdims)[0]

def conditional(self, vdicts):
"""Convert conditional expression from active attribute
(i.e. in standard name format) to local names based on vdict.
Return conditional and a list of variables needed to evaluate
the conditional.
>>> Var({'local_name' : 'foo', 'standard_name' : 'hi_mom', 'units' : 'm s-1', 'dimensions' : '()', 'type' : 'real',}, ParseSource('vname', 'HOST', ParseContext()), _MVAR_DUMMY_RUN_ENV).conditional([{}])
('.true.', [])
>>> Var({'local_name' : 'foo', 'standard_name' : 'hi_mom', 'units' : 'm s-1', 'dimensions' : '()', 'type' : 'real', 'active' : 'False'}, ParseSource('vname', 'HOST', ParseContext()), _MVAR_DUMMY_RUN_ENV).conditional([VarDictionary('bar', _MVAR_DUMMY_RUN_ENV, variables={})]) #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
Exception: Cannot find variable 'false' for generating conditional for 'False'
>>> Var({'local_name' : 'foo', 'standard_name' : 'hi_mom', 'units' : 'm s-1', 'dimensions' : '()', 'type' : 'real', 'active' : 'mom_gone'}, ParseSource('vname', 'HOST', ParseContext()), _MVAR_DUMMY_RUN_ENV).conditional([ VarDictionary('bar', _MVAR_DUMMY_RUN_ENV, variables=[Var({'local_name' : 'bar', 'standard_name' : 'mom_home', 'units' : '', 'dimensions' : '()', 'type' : 'logical'}, ParseSource('vname', 'HOST', ParseContext()), _MVAR_DUMMY_RUN_ENV)]) ]) #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
Exception: Cannot find variable 'mom_gone' for generating conditional for 'mom_gone'
>>> Var({'local_name' : 'foo', 'standard_name' : 'hi_mom', 'units' : 'm s-1', 'dimensions' : '()', 'type' : 'real', 'active' : 'mom_home'}, ParseSource('vname', 'HOST', ParseContext()), _MVAR_DUMMY_RUN_ENV).conditional([ VarDictionary('bar', _MVAR_DUMMY_RUN_ENV, variables=[Var({'local_name' : 'bar', 'standard_name' : 'mom_home', 'units' : '', 'dimensions' : '()', 'type' : 'logical'}, ParseSource('vname', 'HOST', ParseContext()), _MVAR_DUMMY_RUN_ENV)]) ])[0]
'bar'
>>> len(Var({'local_name' : 'foo', 'standard_name' : 'hi_mom', 'units' : 'm s-1', 'dimensions' : '()', 'type' : 'real', 'active' : 'mom_home'}, ParseSource('vname', 'HOST', ParseContext()), _MVAR_DUMMY_RUN_ENV).conditional([ VarDictionary('bar', _MVAR_DUMMY_RUN_ENV, variables=[Var({'local_name' : 'bar', 'standard_name' : 'mom_home', 'units' : '', 'dimensions' : '()', 'type' : 'logical'}, ParseSource('vname', 'HOST', ParseContext()), _MVAR_DUMMY_RUN_ENV)]) ])[1])
1
"""

active = self.get_prop_value('active')
conditional = ''
vars_needed = []

# Find all words in the conditional, for each of them look
# for a matching standard name in the list of known variables
items = FORTRAN_CONDITIONAL_REGEX.findall(active)
for item in items:
item = item.lower()
if item in FORTRAN_CONDITIONAL_REGEX_WORDS:
conditional += item
else:
# Keep integers
try:
int(item)
conditional += item
except ValueError:
dvar = None
for vdict in vdicts:
dvar = vdict.find_variable(standard_name=item, any_scope=True) # or any_scope=False ?
if dvar:
break
if not dvar:
raise Exception(f"Cannot find variable '{item}' for generating conditional for '{active}'")
conditional += dvar.get_prop_value('local_name')
vars_needed.append(dvar)
return (conditional, vars_needed)

def write_def(self, outfile, indent, wdict, allocatable=False,
dummy=False, add_intent=None, extra_space=0, public=False):
"""Write the definition line for the variable to <outfile>.
Expand Down
5 changes: 4 additions & 1 deletion scripts/parse_tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from xml_tools import find_schema_file, find_schema_version
from xml_tools import read_xml_file, validate_xml_file
from xml_tools import PrettyElementTree
from fortran_conditional import FORTRAN_CONDITIONAL_REGEX_WORDS, FORTRAN_CONDITIONAL_REGEX
# pylint: enable=wrong-import-position

__all__ = [
Expand Down Expand Up @@ -74,5 +75,7 @@
'set_log_to_stdout',
'type_name',
'unique_standard_name',
'validate_xml_file'
'validate_xml_file',
'FORTRAN_CONDITIONAL_REGEX_WORDS',
'FORTRAN_CONDITIONAL_REGEX'
]
13 changes: 13 additions & 0 deletions scripts/parse_tools/fortran_conditional.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env python3
#

"""Definitions to convert a conditional statement in the metadata, expressed in standard names,
into a Fortran conditional (used in an if statement), expressed in local names.
"""

import re

FORTRAN_CONDITIONAL_REGEX_WORDS = [' ', '(', ')', '==', '/=', '<=', '>=', '<', '>', '.eqv.', '.neqv.',
'.true.', '.false.', '.lt.', '.le.', '.eq.', '.ge.', '.gt.', '.ne.',
'.not.', '.and.', '.or.', '.xor.']
FORTRAN_CONDITIONAL_REGEX = re.compile(r"[\w']+|" + "|".join([word.replace('(','\(').replace(')', '\)') for word in FORTRAN_CONDITIONAL_REGEX_WORDS]))
Loading