Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4102bdb
Merge pull request #638 from dustinswales/swales_sync_main
mkavulich Feb 4, 2025
b140da3
Update src/CMakeLists.txt: use modern cmake features to install Fortr…
climbfuji Mar 12, 2025
463d5ad
Add missing 'include(GNUInstallDirs)' in src/CMakeLists.txt
climbfuji Mar 19, 2025
11359cb
Update src/CMakeLists.txt: use modern cmake features to install Fortr…
grantfirl Apr 16, 2025
c8fd894
Merge branch 'develop' of https://github.com/ncar/ccpp-framework into…
climbfuji Jul 24, 2025
cd2c99b
Merge branch 'develop' of https://github.com/ncar/ccpp-framework into…
climbfuji Aug 21, 2025
3256121
Update main from develop 2025/07/24 --> 2025/08/21 (#668)
mkavulich Aug 28, 2025
addae26
Create test to illustrate GNU failure
Sep 26, 2025
324c1d9
Merge commit 'addae26f14e127d525c040262d908acf99d70639' into HEAD
Sep 26, 2025
5771816
add parent ddt to group calling list
peverwhee Jan 13, 2026
e595616
find variable working for parent/children, but need to sort of const …
peverwhee Feb 12, 2026
3bd7057
back out ddt library addition to run env
peverwhee Feb 19, 2026
781269a
framework generates but constituents passing individually with wrong …
peverwhee Feb 19, 2026
71a1221
commit latest
peverwhee Feb 24, 2026
f4a05b9
non-constituent ddts being passed through to suite cap
peverwhee Feb 24, 2026
413acab
cleanup
peverwhee Feb 24, 2026
8fc24dd
Initial commit
Mar 5, 2026
1eb706f
Merge branch 'develop' of https://github.com/NCAR/ccpp-framework into…
Mar 16, 2026
dae14d2
Use full DDT reference in Scheme call_list
Mar 16, 2026
b88d5d2
Merge branch 'bug/unalloc_var_to_Group' of https://github.com/dustins…
Mar 16, 2026
42c2898
Some more changes
dustinswales Mar 16, 2026
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
17 changes: 11 additions & 6 deletions scripts/ccpp_suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,8 @@ def groups(self):

def find_variable(self, standard_name=None, source_var=None,
any_scope=True, clone=None,
search_call_list=False, loop_subst=False):
search_call_list=False, loop_subst=False,
check_components=True):
"""Attempt to return the variable matching <standard_name>.
if <standard_name> is None, the standard name from <source_var> is used.
It is an error to pass both <standard_name> and <source_var> if
Expand All @@ -278,7 +279,8 @@ def find_variable(self, standard_name=None, source_var=None,
any_scope=any_scope,
clone=None,
search_call_list=srch_clist,
loop_subst=loop_subst)
loop_subst=loop_subst,
check_components=check_components)
if var is None:
# No dice? Check for a group variable which can be promoted
# Don't promote loop standard names
Expand All @@ -289,7 +291,8 @@ def find_variable(self, standard_name=None, source_var=None,
source_var=source_var,
any_scope=False,
search_call_list=srch_clist,
loop_subst=loop_subst)
loop_subst=loop_subst,
check_components=check_components)

if var is not None:
# Promote variable to suite level
Expand Down Expand Up @@ -341,7 +344,8 @@ def find_variable(self, standard_name=None, source_var=None,
# Guess it is time to clone a different variable
var = super().find_variable(standard_name=standard_name,
source_var=source_var,
any_scope=any_scope, clone=clone)
any_scope=any_scope, clone=clone,
check_components=check_components)
# end if
return var

Expand Down Expand Up @@ -459,7 +463,7 @@ def analyze(self, host_model, scheme_library, ddt_library, run_env):
for x in item.schemes()]))
item.analyze(phase, self, scheme_library, ddt_library,
self.check_suite_state(phase),
self.set_suite_state(phase))
self.set_suite_state(phase), host_model)
# Look for group variables that need to be promoted to the suite
# We need to promote any variable used later to the suite, however,
# we do not yet know if it will be used.
Expand Down Expand Up @@ -735,7 +739,8 @@ def __init__(self, sdfs, host_model, scheme_headers, run_env):
if group.phase() == phase:
self.__call_lists[phase].add_vars(group.call_list,
run_env,
gen_unique=True)
gen_unique=True,
add_children=True)
# end if
# end for
# end for
Expand Down
6 changes: 4 additions & 2 deletions scripts/constituents.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ def __init__(self, name, parent_dict, run_env, variables=None):

def find_variable(self, standard_name=None, source_var=None,
any_scope=True, clone=None,
search_call_list=False, loop_subst=False):
search_call_list=False, loop_subst=False,
check_components=True):
"""Attempt to return the variable matching <standard_name>.
if <standard_name> is None, the standard name from <source_var> is used.
It is an error to pass both <standard_name> and <source_var> if
Expand Down Expand Up @@ -86,7 +87,8 @@ def find_variable(self, standard_name=None, source_var=None,
source_var=source_var,
any_scope=any_scope, clone=None,
search_call_list=srch_clist,
loop_subst=loop_subst)
loop_subst=loop_subst,
check_components=check_components)
else:
var = None
# end if
Expand Down
8 changes: 5 additions & 3 deletions scripts/ddt_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ def intrinsic_elements(self, check_dict=None):
# end if
return pvalue

def clone(self, subst_dict, source_name=None, source_type=None,
context=None):
def clone(self, subst_dict=None, remove_intent=False,
source_name=None, source_type=None, context=None):
"""Create a clone of this VarDDT object's leaf Var with properties
from <subst_dict> overriding this variable's properties.
<subst_dict> may also be a string in which case only the local_name
Expand Down Expand Up @@ -288,7 +288,7 @@ def collect_ddt_fields(self, var_dict, var, run_env,
# for a DDT, the variable also cannot be in our parent
# dictionaries.
stdname = dvar.get_prop_value('standard_name')
pvar = var_dict.find_variable(standard_name=stdname, any_scope=True)
pvar = var_dict.find_variable(standard_name=stdname, any_scope=True, check_components=False)
if pvar and (not skip_duplicates):
ntx = context_string(dvar.context)
ctx = context_string(pvar.context)
Expand All @@ -300,6 +300,8 @@ def collect_ddt_fields(self, var_dict, var, run_env,
if not pvar:
var_dict.add_variable(subvar, run_env)
# end if
# Add this ddt variable to the parent DDT
var.add_component(subvar)
# end for

def ddt_modules(self, variable_list, ddt_mods=None):
Expand Down
2 changes: 1 addition & 1 deletion scripts/host_cap.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@ def suite_part_call_list(host_model, const_dict, suite_part, subst_loop_vars,
var_dicts = [host_model, const_dict]
# Figure out which dictionary has the variable
for vdict in var_dicts:
hvar = vdict.find_variable(standard_name=stdname, any_scope=False)
hvar = vdict.find_variable(standard_name=stdname, any_scope=False, check_components=False)
if hvar is not None:
var_dict = vdict
break
Expand Down
11 changes: 7 additions & 4 deletions scripts/host_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,15 +203,17 @@ def variable_locations(self):

def find_variable(self, standard_name=None, source_var=None,
any_scope=False, clone=None,
search_call_list=False, loop_subst=False):
search_call_list=False, loop_subst=False,
check_components=True):
"""Return the host model variable matching <standard_name> or None
If <loop_subst> is True, substitute a begin:end range for an extent.
"""
my_var = super().find_variable(standard_name=standard_name,
source_var=source_var,
any_scope=any_scope, clone=clone,
search_call_list=search_call_list,
loop_subst=loop_subst)
loop_subst=loop_subst,
check_components=check_components)
if my_var is None:
# Check our DDT library
if standard_name is None:
Expand All @@ -224,7 +226,8 @@ def find_variable(self, standard_name=None, source_var=None,
# end if
# Since we are the parent of the DDT library, only check that dict
my_var = self.__ddt_dict.find_variable(standard_name=standard_name,
any_scope=False)
any_scope=False,
check_components=check_components)
# End if
if loop_subst:
if my_var is None:
Expand Down Expand Up @@ -257,7 +260,7 @@ def find_variable(self, standard_name=None, source_var=None,
vdims = [x.strip() for x in imatch.group(2).split(',')
if ':' not in x]
for vname in vdims:
_ = self.find_variable(standard_name=vname)
_ = self.find_variable(standard_name=vname, check_components=check_components)
# End for
# End if
if isinstance(my_var, VarDDT):
Expand Down
7 changes: 5 additions & 2 deletions scripts/metadata_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ def register_ddts(file_list):
"""
errors = ""
ddt_names = set()
in_table = False
for mfile in file_list:
if os.path.exists(mfile):
with open(mfile, 'r') as infile:
Expand Down Expand Up @@ -1201,13 +1202,15 @@ def variable_list(self, std_vars=True, loop_vars=True, consts=True):
loop_vars=loop_vars,
consts=consts)

def find_variable(self, std_name, use_local_name=False):
def find_variable(self, std_name, use_local_name=False, check_components=True):
"""Find a variable in this header's dictionary"""
var = None
if use_local_name:
var = self.__variables.find_local_name(std_name)
else:
var = self.__variables.find_variable(std_name, any_scope=False)
var = self.__variables.find_variable(std_name,
any_scope=False,
check_components=check_components)
# end if
return var

Expand Down
106 changes: 81 additions & 25 deletions scripts/metavar.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ class Var:
__var_propdict.update({p.name : p for p in __constituent_props})
# All constituent props are optional so no check

def __init__(self, prop_dict, source, run_env, context=None,
def __init__(self, prop_dict, source, run_env, is_ddt=False, components=None, context=None,
clone_source=None, fortran_imports=None):
"""Initialize a new Var object.
If <prop_dict> is really a Var object, use that object's prop_dict.
Expand All @@ -275,6 +275,11 @@ def __init__(self, prop_dict, source, run_env, context=None,
"""
self.__parent_var = None # for array references
self.__children = list() # This Var's array references
if components:
self.__components = components
else:
self.__components = list() # This Var's DDT components
# end if
self.__clone_source = clone_source
self.__run_env = run_env
if isinstance(prop_dict, Var):
Expand Down Expand Up @@ -315,6 +320,9 @@ def __init__(self, prop_dict, source, run_env, context=None,
else:
self.__intrinsic = True
# end if
if is_ddt:
self.__intrinsic = False
# end if
for key in prop_dict:
if Var.get_prop(key) is None:
raise ParseSyntaxError("Invalid metadata variable property, '{}'".format(key), context=self.context)
Expand Down Expand Up @@ -499,7 +507,7 @@ def clone(self, subst_dict=None, remove_intent=False,
# end if
psource = ParseSource(source_name, source_type, context)

return Var(cprop_dict, psource, self.run_env, clone_source=self)
return Var(cprop_dict, psource, self.run_env, is_ddt=self.is_ddt(), components=self.components, clone_source=self)

def get_prop_value(self, name):
"""Return the value of key, <name> if <name> is in this variable's
Expand Down Expand Up @@ -883,6 +891,14 @@ def children(self):
# end if
return iter(children) if children else None

@property
def components(self):
"""Return the list of this object's components"""
return self.__components

def add_component(self, new_component):
self.__components.append(new_component)

@property
def var(self):
"Return this object (base behavior for derived classes such as VarDDT)"
Expand Down Expand Up @@ -1134,21 +1150,6 @@ def write_def(self, outfile, indent, wdict, allocatable=False, target=False,
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 Expand Up @@ -1604,7 +1605,7 @@ def variable_list(self, recursive=False,
return vlist

def add_variable(self, newvar, run_env, exists_ok=False, gen_unique=False,
adjust_intent=False):
adjust_intent=False, add_children=False):
"""Add <newvar> if it does not conflict with existing entries
If <exists_ok> is True, attempting to add an identical copy is okay.
If <gen_unique> is True, a new local_name will be created if a
Expand Down Expand Up @@ -1712,9 +1713,16 @@ def add_variable(self, newvar, run_env, exists_ok=False, gen_unique=False,
if aref is not None:
pname = aref.group(1).strip()
pvar = self.find_local_name(pname)
array_pieces = aref.group(2).split(',')
if pvar is not None:
newvar.parent = pvar
# end if
for array_piece in array_pieces:
if array_piece.strip() != ':':
pvar = self.find_variable(standard_name=array_piece.strip())
if pvar:
newvar.add_child(pvar)
# end if
# end if
# If we make it to here without an exception, add the variable
if standard_name not in self:
Expand All @@ -1724,6 +1732,12 @@ def add_variable(self, newvar, run_env, exists_ok=False, gen_unique=False,
if lname not in self.__local_names:
self.__local_names[lname] = standard_name
# end if
if newvar.children() and add_children:
for child in newvar.children():
self.add_variable(child, run_env, exists_ok=exists_ok, gen_unique=gen_unique,
adjust_intent=adjust_intent)
# end for
# end if

def remove_variable(self, standard_name):
"""Remove <standard_name> from the dictionary.
Expand Down Expand Up @@ -1795,7 +1809,8 @@ def add_variable_dimensions(self, var, ignore_sources, suite_type,

def find_variable(self, standard_name=None, source_var=None,
any_scope=True, clone=None,
search_call_list=False, loop_subst=False):
search_call_list=False, loop_subst=False,
check_components=True):
"""Attempt to return the variable matching <standard_name>.
if <standard_name> is None, the standard name from <source_var> is used.
It is an error to pass both <standard_name> and <source_var> if
Expand Down Expand Up @@ -1825,16 +1840,43 @@ def find_variable(self, standard_name=None, source_var=None,
var = CCPP_CONSTANT_VARS[standard_name]
elif standard_name in self:
var = self[standard_name]
elif any_scope and (self.__parent_dict is not None):
src_clist = search_call_list
var = self.__parent_dict.find_variable(standard_name=standard_name,
else:
# Look in the DDTs
var = None
if check_components:
for var_check in self:
var_in_object = self[var_check]
ddt_components = var_in_object.components
for component in ddt_components:
if component.get_prop_value('standard_name') == standard_name:
var = component
else:
if component.children():
for child in component.children():
if child.get_prop_value('standard_name') == standard_name:
var = child
# end if
# end for
# end if
# end if
# end for
# end for
# end if
if not var:
if any_scope:
if self.__parent_dict is not None:
src_clist = search_call_list
var = self.__parent_dict.find_variable(standard_name=standard_name,
source_var=source_var,
any_scope=any_scope,
clone=clone,
search_call_list=src_clist,
loop_subst=loop_subst)
else:
var = None
loop_subst=loop_subst,
check_components=check_components)
else:
var = None
# end if
# end if
# end if
if (var is None) and (clone is not None):
lname = clone.get_prop_value['local_name']
Expand Down Expand Up @@ -2128,6 +2170,20 @@ def new_internal_variable_name(self, prefix=None, max_len=63):
# end while
return newvar

def write_ptr_def(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)
###############################################################################

# List of constant variables which are universally available
Expand Down
Loading
Loading