Skip to content

Commit

Permalink
Merge pull request #13 from peverwhee/peverwhee-fork-dynamic-constitu…
Browse files Browse the repository at this point in the history
…ents

Add optional metadata field for dynamic constituent routine
  • Loading branch information
peverwhee authored Mar 1, 2024
2 parents f5b7250 + 2c58eed commit 8d2bd61
Show file tree
Hide file tree
Showing 15 changed files with 754 additions and 216 deletions.
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'
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'
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

0 comments on commit 8d2bd61

Please sign in to comment.