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 optional attribute to Capgen #529

Merged
merged 24 commits into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
964b776
Add optional keyword. Work in progress.
dustinswales Jan 30, 2024
bcdb37e
Merge remote-tracking branch 'me/test_active_attribute' into add_opti…
dustinswales Jan 30, 2024
224fad3
Work in progress.
dustinswales Jan 30, 2024
aa652cd
Add optional attribute to varaible declarations in caps
dustinswales Jan 30, 2024
462d08b
Merge branch 'test_active_attribute' of https://github.com/dustinswal…
dustinswales Jan 31, 2024
9248678
Work in progress
dustinswales Feb 1, 2024
7a0c4c9
added active logic to pointer association
dustinswales Feb 2, 2024
a1a701b
Merge branch 'feature/capgen' of https://github.com/NCAR/ccpp-framewo…
dustinswales Feb 5, 2024
423dc71
Working now
dustinswales Feb 8, 2024
aa59672
Added null pointers to caps when scheme has optional argument, but no…
dustinswales Feb 8, 2024
7b20265
Address reviewers comments. Add whitespace to autogenerated code for …
dustinswales Feb 12, 2024
d7bad29
Revert some changes
dustinswales Feb 12, 2024
9337a2e
Add optional attribute to capgen test
dustinswales Feb 12, 2024
3e4f88f
Fix doctests.
dustinswales Feb 12, 2024
80da2a5
Fix doctest again
dustinswales Feb 12, 2024
c34496f
Fix doctest again again
dustinswales Feb 12, 2024
9125aae
Fix doctest again again again
dustinswales Feb 12, 2024
34aa7f5
Update scripts/metavar.py
dustinswales Feb 22, 2024
a9ae401
Merge branch 'feature/capgen' of https://github.com/NCAR/ccpp-framewo…
dustinswales Feb 22, 2024
adad650
Address reviewers comments
dustinswales Mar 4, 2024
00a905f
Update scripts/suite_objects.py
dustinswales Mar 6, 2024
b4991be
Update scripts/suite_objects.py
dustinswales Mar 6, 2024
b0ad2df
Update scripts/suite_objects.py
dustinswales Mar 6, 2024
809fc91
Merge branch 'feature/capgen' of https://github.com/NCAR/ccpp-framewo…
dustinswales Mar 6, 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
11 changes: 11 additions & 0 deletions scripts/ccpp_capgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,17 @@ def compare_fheader_to_mheader(meta_header, fort_header, logger):
lname = mvar.get_prop_value('local_name')
arrayref = is_arrayspec(lname)
fvar, find = find_var_in_list(lname, flist)
# Check for consistency between optional variables in metadata and
# optional variables in fortran. Error if optional attribute is
# missing from fortran declaration.
mopt = mvar.get_prop_value('optional')
if find and mopt:
fopt = fvar.get_prop_value('optional')
if (not fopt):
errmsg = 'Missing optional attribute in fortran declaration for variable {}, in file {}'
errors_found = add_error(errors_found, errmsg.format(mname,title))
# end if
# end if
if mind >= flen:
if arrayref:
# Array reference, variable not in Fortran table
Expand Down
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", "top_at_one"])
"advected", "top_at_one", "optional"])
prop_list.extend(Var.constituent_property_names())
# end if
ventry = ET.SubElement(parent, "var")
Expand Down
2 changes: 1 addition & 1 deletion scripts/fortran_tools/parse_fortran.py
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ def parse_fortran_var_decl(line, source, run_env):
>>> parse_fortran_var_decl("integer :: foo = 0", ParseSource('foo.F90', 'module', ParseContext()), _DUMMY_RUN_ENV)[0].get_prop_value('local_name')
'foo'
>>> parse_fortran_var_decl("integer :: foo", ParseSource('foo.F90', 'module', ParseContext()), _DUMMY_RUN_ENV)[0].get_prop_value('optional')

False
>>> parse_fortran_var_decl("integer, optional :: foo", ParseSource('foo.F90', 'module', ParseContext()), _DUMMY_RUN_ENV)[0].get_prop_value('optional')
'True'
>>> parse_fortran_var_decl("integer, dimension(:) :: foo", ParseSource('foo.F90', 'module', ParseContext()), _DUMMY_RUN_ENV)[0].get_prop_value('dimensions')
Expand Down
55 changes: 39 additions & 16 deletions scripts/metavar.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,9 @@ class Var:
>>> Var({'local_name' : 'foo', 'standard_name' : 'hi_mom', 'units' : 'm s-1', 'dimensions' : '()', 'type' : 'real', 'intent' : 'ino'}, ParseSource('vname', 'SCHEME', ParseContext()), _MVAR_DUMMY_RUN_ENV) #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
ParseSyntaxError: Invalid intent variable property, 'ino', at <standard input>:1
>>> Var({'local_name' : 'foo', 'standard_name' : 'hi_mom', 'units' : 'm s-1', 'dimensions' : '()', 'type' : 'real', 'intent' : 'in', 'optional' : 'false'}, ParseSource('vname', 'SCHEME', ParseContext()), _MVAR_DUMMY_RUN_ENV) #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
ParseSyntaxError: Invalid variable property name, 'optional', at <standard input>:1
>>> Var({'local_name' : 'foo', 'standard_name' : 'hi_mom', 'units' : 'm s-1', 'dimensions' : '()', 'type' : 'real', 'intent' : 'in', 'optional' : 'false'}, ParseSource('vname', 'SCHEME', ParseContext()), _MVAR_DUMMY_RUN_ENV) #doctest: +ELLIPSIS
<metavar.Var hi_mom: foo at 0x...>
dustinswales marked this conversation as resolved.
Show resolved Hide resolved

# Check that two variables that differ in their units - m vs km - are compatible
>>> Var({'local_name' : 'foo', 'standard_name' : 'hi_mom', 'units' : 'm', \
'dimensions' : '()', 'type' : 'real', 'intent' : 'in'}, \
Expand Down Expand Up @@ -207,6 +207,8 @@ class Var:
default_in=False),
VariableProperty('top_at_one', bool, optional_in=True,
default_in=False),
VariableProperty('optional', bool, optional_in=True,
default_in=False),
VariableProperty('target', bool, optional_in=True,
default_in=False)]

Expand Down Expand Up @@ -1025,7 +1027,7 @@ def conditional(self, vdicts):
vars_needed.append(dvar)
return (conditional, vars_needed)

def write_def(self, outfile, indent, wdict, allocatable=False,
def write_def(self, outfile, indent, wdict, allocatable=False, target=False,
dummy=False, add_intent=None, extra_space=0, public=False):
"""Write the definition line for the variable to <outfile>.
If <dummy> is True, include the variable's intent.
Expand Down Expand Up @@ -1077,23 +1079,30 @@ def write_def(self, outfile, indent, wdict, allocatable=False,
raise CCPPError(errmsg.format(name))
# end if
# end if
optional = self.get_prop_value('optional')
if protected and dummy:
intent_str = 'intent(in) '
elif allocatable:
if dimstr or polymorphic:
intent_str = 'allocatable '
intent_str = 'allocatable '
if target:
intent_str = 'allocatable,'
dustinswales marked this conversation as resolved.
Show resolved Hide resolved
intent_str += ' target'
else:
intent_str = ' '*13
# end if
elif intent is not None:
alloval = self.get_prop_value('allocatable')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be True here given the elif allocatable above? If it can, then what if is also optional?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure of the purpose of alloval here?
If we are in this block of code, the variable is not an allocatable?

if (intent.lower()[-3:] == 'out') and alloval:
intent_str = f"allocatable, intent({intent})"
elif optional:
intent_str = f"intent({intent}),{' '*(5 - len(intent))}"
intent_str += 'target, optional '
else:
intent_str = f"intent({intent}){' '*(5 - len(intent))}"
# end if
elif not dummy:
intent_str = ''
intent_str = ' '*20
else:
intent_str = ' '*13
# end if
Expand All @@ -1111,26 +1120,40 @@ def write_def(self, outfile, indent, wdict, allocatable=False,
extra_space -= len(targ)
if self.is_ddt():
if polymorphic:
dstr = "class({kind}){cspc}{intent} :: {name}{dims} ! {sname}"
cspc = comma + ' '*(extra_space + 12 - len(kind))
dstr = "class({kind}){cspace}{intent} :: {name}{dims}"
cspace = comma + ' '*(extra_space + 12 - len(kind))
else:
dstr = "type({kind}){cspc}{intent} :: {name}{dims} ! {sname}"
cspc = comma + ' '*(extra_space + 13 - len(kind))
dstr = "type({kind}){cspace}{intent} :: {name}{dims}"
cspace = comma + ' '*(extra_space + 13 - len(kind))
# end if
else:
if kind:
dstr = "{type}({kind}){cspc}{intent} :: {name}{dims} ! {sname}"
cspc = comma + ' '*(extra_space + 17 - len(vtype) - len(kind))
dstr = "{type}({kind}){cspace}{intent} :: {name}{dims}"
cspace = comma + ' '*(extra_space + 17 - len(vtype) - len(kind))
else:
dstr = "{type}{cspc}{intent} :: {name}{dims} ! {sname}"
cspc = comma + ' '*(extra_space + 19 - len(vtype))
dstr = "{type}{cspace}{intent} :: {name}{dims}"
cspace = comma + ' '*(extra_space + 19 - len(vtype))
# end if
# end if

outfile.write(dstr.format(type=vtype, kind=kind, intent=intent_str,
name=name, dims=dimstr, cspc=cspc,
name=name, dims=dimstr, cspace=cspace,
sname=stdname), indent)

def write_ptr_def(self, outfile, indent, name, kind, dimstr, vtype, extra_space=0):
"""Write the definition line for local null pointer declaration to <outfile>."""
comma = ', '
if kind:
dstr = "{type}({kind}){cspace}pointer :: {name}{dims}{cspace2} => null()"
cspace = comma + ' '*(extra_space + 20 - len(vtype) - len(kind))
cspace2 = ' '*(20 -len(name) - len(dimstr))
else:
dstr = "{type}{cspace}pointer :: {name}{dims}{cspace2} => null()"
cspace = comma + ' '*(extra_space + 22 - len(vtype))
cspace2 = ' '*(20 -len(name) - len(dimstr))
# end if
outfile.write(dstr.format(type=vtype, kind=kind, name=name, dims=dimstr,
cspace=cspace, cspace2=cspace2), indent)

def is_ddt(self):
"""Return True iff <self> is a DDT type."""
return not self.__intrinsic
Expand Down
Loading
Loading