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 metadata field for dynamic constituent routine #13

Merged
merged 9 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 17 additions & 1 deletion scripts/ccpp_capgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,22 @@ def capgen(run_env, return_db=False):
scheme_files= [const_prop_mod] + scheme_files
# end if
scheme_headers, scheme_tdict = parse_scheme_files(scheme_files, run_env)
# Pull out the dynamic constituent routines, if any
dyn_const_dict = {}
for table in scheme_tdict:
routine_name = scheme_tdict[table].dyn_const_routine
if routine_name is not None:
if routine_name not in dyn_const_dict.values():
dyn_const_dict[table] = routine_name
else:
# dynamic constituent routines must have unique names
scheme_name = list(dyn_const_dict.keys())[list(dyn_const_dict.values()).index(routine_name)]
errmsg = f"ERROR: Dynamic constituent routine names must be unique. Cannot add " \
f"{routine_name} for {table}. Routine already exists in {scheme_name}. "
raise CCPPError(errmsg)
# end if
# end if
# end for
if run_env.verbose:
ddts = host_model.ddt_lib.keys()
if ddts:
Expand Down Expand Up @@ -655,7 +671,7 @@ def capgen(run_env, return_db=False):
# end if
os.makedirs(outtemp_dir)
# end if
ccpp_api = API(sdfs, host_model, scheme_headers, run_env)
ccpp_api = API(sdfs, host_model, scheme_headers, run_env, dyn_const_dict)
cap_filenames = ccpp_api.write(outtemp_dir, run_env)
if run_env.generate_host_cap:
# Create a cap file
Expand Down
347 changes: 334 additions & 13 deletions scripts/ccpp_datafile.py

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion scripts/ccpp_suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,7 @@ class API(VarDictionary):
'kind':'len=*', 'units':'',
'dimensions':'()'}, _API_SOURCE, _API_DUMMY_RUN_ENV)

def __init__(self, sdfs, host_model, scheme_headers, run_env):
def __init__(self, sdfs, host_model, scheme_headers, run_env, dyn_const_dict={}):
"""Initialize this API.
<sdfs> is the list of Suite Definition Files to be parsed for
data needed by the CCPP cap.
Expand All @@ -593,11 +593,14 @@ def __init__(self, sdfs, host_model, scheme_headers, run_env):
<scheme_headers> is the list of parsed physics scheme metadata files.
Every scheme referenced by an SDF in <sdfs> MUST be in this list,
however, unused schemes are allowed.
<dyn_const_dict> is the dictionary (key = scheme name) of dynamic
constituent routine names
<run_env> is the CCPPFrameworkEnv object for this framework run.
"""
self.__module = 'ccpp_physics_api'
self.__host = host_model
self.__suites = list()
self.__dyn_const_dict = dyn_const_dict
super().__init__(self.module, run_env, parent_dict=self.host_model)
# Create a usable library out of scheme_headers
# Structure is dictionary of dictionaries
Expand Down Expand Up @@ -1153,6 +1156,11 @@ def suites(self):
"Return the list of this API's suites"
return self.__suites

@property
def dyn_const_dict(self):
"""Return the dynamic constituent routine dictionary"""
return self.__dyn_const_dict

###############################################################################
if __name__ == "__main__":
try:
Expand Down
386 changes: 207 additions & 179 deletions scripts/constituents.py

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion scripts/host_cap.py
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,9 @@ def write_host_cap(host_model, api, module_name, output_dir, run_env):
advect_array_func,
prop_array_func,
const_index_func,
api.suites, err_vars)
api.suites,
api.dyn_const_dict,
err_vars)
# End with
return cap_filename

Expand Down
13 changes: 11 additions & 2 deletions scripts/metadata_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,8 +270,8 @@ class MetadataTable():
__table_start = re.compile(r"(?i)\s*\[\s*ccpp-table-properties\s*\]")

def __init__(self, run_env, table_name_in=None, table_type_in=None,
dependencies=None, relative_path=None, known_ddts=None,
var_dict=None, module=None, parse_object=None):
dependencies=None, relative_path=None, dyn_const_routine=None,
known_ddts=None, var_dict=None, module=None, parse_object=None):
"""Initialize a MetadataTable, either with a name, <table_name_in>, and
type, <table_type_in>, or with information from a file (<parse_object>).
if <parse_object> is None, <dependencies> and <relative_path> are
Expand All @@ -283,6 +283,7 @@ def __init__(self, run_env, table_name_in=None, table_type_in=None,
self.__pobj = parse_object
self.__dependencies = dependencies
self.__relative_path = relative_path
self.__dyn_const_routine = dyn_const_routine
self.__sections = []
self.__run_env = run_env
if parse_object is None:
Expand Down Expand Up @@ -395,6 +396,8 @@ def __init_from_file(self, known_ddts, run_env):
# end if
elif key == 'relative_path':
self.__relative_path = value
elif key == 'dynamic_constituent_routine':
self.__dyn_const_routine = value
else:
tok_type = "metadata table start property"
self.__pobj.add_syntax_err(tok_type, token=value)
Expand Down Expand Up @@ -475,6 +478,12 @@ def relative_path(self):
"""Return the relative path for the table's dependencies"""
return self.__relative_path

@property
def dyn_const_routine(self):
"""Return the name of the routine that will dynamically return
an array of constituent properties"""
return self.__dyn_const_routine

@property
def run_env(self):
"""Return this table's CCPPFrameworkEnv object"""
Expand Down
18 changes: 14 additions & 4 deletions scripts/var_props.py
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,19 @@ class VarCompatObj:
_DOCTEST_RUNENV) #doctest: +ELLIPSIS
<var_props.VarCompatObj object at 0x...>

# Test that a 1-D var with no vertical transform works
>>> VarCompatObj("var_stdname", "real", "kind_phys", "m", ['vertical_layer_dimension'], "var1_lname", False, \
"var_stdname", "real", "kind_phys", "m", ['vertical_layer_dimension'], "var2_lname", False, \
_DOCTEST_RUNENV) #doctest: +ELLIPSIS
<var_props.VarCompatObj object at 0x...>

# Test that a 1-D var with vertical flipping works and that it
# produces the correct reverse transformation
>>> VarCompatObj("var_stdname", "real", "kind_phys", "m", ['vertical_layer_dimension'], "var1_lname", False,\
"var_stdname", "real", "kind_phys", "m", ['vertical_layer_dimension'], "var2_lname", True, \
_DOCTEST_RUNENV).reverse_transform("var1_lname", "var2_lname", ('k',), ('nk-k+1',))
'var1_lname(nk-k+1) = var2_lname(k)'

# Test that a 2-D var with unit conversion m->km works
>>> VarCompatObj("var_stdname", "real", "kind_phys", "m", ['horizontal_dimension'], "var1_lname", False, \
"var_stdname", "real", "kind_phys", "km", ['horizontal_dimension'], "var2_lname", False, \
Expand Down Expand Up @@ -928,12 +941,9 @@ def __init__(self, var1_stdname, var1_type, var1_kind, var1_units,
# end if
if self.__compat:
# Check dimensions
##XXgoldyXX: For now, we always have to create a dimension
## transform because we do not know if the vertical
## dimension is flipped.
if var1_dims or var2_dims:
_, vdim_ind = find_vertical_dimension(var1_dims)
if (var1_dims != var2_dims) or (vdim_ind >= 0):
if (var1_dims != var2_dims):
self.__dim_transforms = self._get_dim_transforms(var1_dims,
var2_dims)
self.__compat = self.__dim_transforms is not None
Expand Down
27 changes: 27 additions & 0 deletions test/advection_test/cld_ice.F90
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ MODULE cld_ice
PUBLIC :: cld_ice_init
PUBLIC :: cld_ice_run
PUBLIC :: cld_ice_final
PUBLIC :: cld_ice_dynamic_constituents

real(kind_phys), private :: tcld = HUGE(1.0_kind_phys)

Expand Down Expand Up @@ -91,6 +92,32 @@ subroutine cld_ice_final(errmsg, errflg)
errflg = 0

end subroutine cld_ice_final

subroutine cld_ice_dynamic_constituents(dyn_const, errcode, errmsg)
use ccpp_constituent_prop_mod, only: ccpp_constituent_properties_t
type(ccpp_constituent_properties_t), allocatable, intent(out) :: dyn_const(:)
integer, intent(out) :: errcode
character(len=512), intent(out) :: errmsg

errmsg = ''
errcode = 0
allocate(dyn_const(2), stat=errcode)
if (errcode /= 0) then
errmsg = 'Error allocating dyn_const in cld_ice_dynamic_constituents'
nusbaume marked this conversation as resolved.
Show resolved Hide resolved
end if
call dyn_const(1)%instantiate(std_name='dyn_const1', long_name='dyn const1', &
units='kg kg-1', default_value=0._kind_phys, &
vertical_dim='vertical_layer_dimension', advected=.true., &
min_value=1000._kind_phys, errcode=errcode, errmsg=errmsg)
if (errcode /= 0) then
return
end if
call dyn_const(2)%instantiate(std_name='dyn_const2_wrt_moist_air', long_name='dyn const2', &
units='kg kg-1', default_value=0._kind_phys, &
vertical_dim='vertical_layer_dimension', advected=.true., &
errcode=errcode, errmsg=errmsg)

end subroutine cld_ice_dynamic_constituents
!! @}
!! @}

Expand Down
1 change: 1 addition & 0 deletions test/advection_test/cld_ice.meta
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
[ccpp-table-properties]
name = cld_ice
type = scheme
dynamic_constituent_routine = cld_ice_dynamic_constituents
[ccpp-arg-table]
name = cld_ice_run
type = scheme
Expand Down
21 changes: 21 additions & 0 deletions test/advection_test/cld_liq.F90
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ MODULE cld_liq

PUBLIC :: cld_liq_init
PUBLIC :: cld_liq_run
PUBLIC :: cld_liq_dynamic_constituents

CONTAINS

Expand Down Expand Up @@ -74,4 +75,24 @@ subroutine cld_liq_init(tfreeze, cld_liq_array, tcld, errmsg, errflg)

end subroutine cld_liq_init

subroutine cld_liq_dynamic_constituents(dyn_const, errcode, errmsg)
use ccpp_constituent_prop_mod, only: ccpp_constituent_properties_t
type(ccpp_constituent_properties_t), allocatable, intent(out) :: dyn_const(:)
integer, intent(out) :: errcode
character(len=512), intent(out) :: errmsg

errmsg = ''
errcode = 0
allocate(dyn_const(1), stat=errcode)
if (errcode /= 0) then
errmsg = 'Error allocating dyn_const in cld_liq_dynamic_constituents'
nusbaume marked this conversation as resolved.
Show resolved Hide resolved
end if
call dyn_const(1)%instantiate(std_name="dyn_const3", long_name='dyn const3', &
units='kg kg-1', default_value=1._kind_phys, &
vertical_dim='vertical_layer_dimension', advected=.true., &
errcode=errcode, errmsg=errmsg)

end subroutine cld_liq_dynamic_constituents


END MODULE cld_liq
1 change: 1 addition & 0 deletions test/advection_test/cld_liq.meta
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
[ccpp-table-properties]
name = cld_liq
type = scheme
dynamic_constituent_routine = cld_liq_dynamic_constituents
[ccpp-arg-table]
name = cld_liq_run
type = scheme
Expand Down
2 changes: 2 additions & 0 deletions test/advection_test/run_test
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ ccpp_files="${utility_files},${host_files},${suite_files}"
process_list=""
module_list="cld_ice,cld_liq"
dependencies=""
dyn_const_routines="cld_ice_dynamic_constituents,cld_liq_dynamic_constituents"
suite_list="cld_suite"
required_vars="ccpp_error_code,ccpp_error_message"
required_vars="${required_vars},cloud_ice_dry_mixing_ratio"
Expand Down Expand Up @@ -219,6 +220,7 @@ echo -e "\nChecking lists from command line"
check_datatable ${report_prog} ${datafile} "--process-list" "${process_list}"
check_datatable ${report_prog} ${datafile} "--module-list" ${module_list}
check_datatable ${report_prog} ${datafile} "--dependencies" "${dependencies}"
check_datatable ${report_prog} ${datafile} "--dyn-const-routines" "${dyn_const_routines}"
check_datatable ${report_prog} ${datafile} "--suite-list" ${suite_list} \
--sep ";"
echo -e "\nChecking variables from command line"
Expand Down
Loading
Loading