ccpp-framework
ccpp-framework copied to clipboard
Constituent updates
Summary
Brings in optional metadata field to enable dynamic (run-time) constituents; also brings in a couple new methods for the constituent object.
closes #557
Description
Key dynamic constituent mods:
- ccpp_capgen.py: create dynamic constituent dictionary (key=scheme name) and pass into API()
- constituents.py: add handling of dynamic constituents to register constituents routine (including conditional call(s) to user-supplied routines); update error handling for register_constituents
Includes additional constituent object methods:
- set_water_species
- set_min_val
- set_molar_mass
Includes fixes to ensure consistent order of generated code (use statements, variables, etc)
Also brings back the .github/workflow/python.yaml workflow that got lost somehow
User interface changes?: Yes, but optional User can now use "dynamic_constituent_routine" metadata header field to point to a function contained within the module fortran.
Testing: Modified advection test to include dynamic constituent routines. Added doctests to ccpp_datafile
Generated code snippet
subroutine test_host_ccpp_register_constituents(host_constituents, errflg, errmsg)
! Create constituent object for suites in
use ccpp_constituent_prop_mod, only: ccpp_constituent_properties_t
! Suite constituent interfaces
use ccpp_cld_suite_cap, only: cld_suite_constituents_num_consts
use ccpp_cld_suite_cap, only: cld_suite_constituents_const_name
use ccpp_cld_suite_cap, only: cld_suite_constituents_copy_const
! Dynamic constituent routines
use cld_liq, only: cld_liq_dynamic_constituents
use cld_ice, only: cld_ice_dynamic_constituents
! Dummy arguments
type(ccpp_constituent_properties_t), target, intent(in) :: host_constituents(:)
character(len=512), intent(out) :: errmsg ! ccpp_error_message
integer, intent(out) :: errflg ! ccpp_error_code
! Local variables
integer :: num_suite_consts
integer :: num_consts
integer :: num_dyn_consts
integer :: index, index_start
integer :: field_ind
type(ccpp_constituent_properties_t), pointer :: const_prop
! dynamic constituent props variable for cld_ice
type(ccpp_constituent_properties_t), allocatable :: dyn_const_prop_0(:)
! dynamic constituent props variable for cld_liq
type(ccpp_constituent_properties_t), allocatable :: dyn_const_prop_1(:)
errflg = 0
num_consts = size(host_constituents, 1)
num_dyn_consts = 0
! Number of suite constants for cld_suite
num_suite_consts = cld_suite_constituents_num_consts(errflg=errflg, errmsg=errmsg)
if (errflg /= 0) then
return
end if
num_consts = num_consts + num_suite_consts
! Add in dynamic constituents
call cld_ice_dynamic_constituents(dyn_const_prop_0, errcode=errflg, errmsg=errmsg)
if (errflg /= 0) then
return
end if
num_dyn_consts = num_dyn_consts + size(dyn_const_prop_0)
call cld_liq_dynamic_constituents(dyn_const_prop_1, errcode=errflg, errmsg=errmsg)
if (errflg /= 0) then
return
end if
num_dyn_consts = num_dyn_consts + size(dyn_const_prop_1)
num_consts = num_consts + num_dyn_consts
! Pack dynamic_constituents array
allocate(dynamic_constituents(num_dyn_consts), stat=errflg)
if (errflg /= 0) then
errmsg = 'failed to allocate dynamic_constituents'
return
end if
index_start = 0
do index = 1, size(dyn_const_prop_0, 1)
dynamic_constituents(index + index_start) = dyn_const_prop_0(index)
end do
index_start = size(dyn_const_prop_0, 1)
deallocate(dyn_const_prop_0)
do index = 1, size(dyn_const_prop_1, 1)
dynamic_constituents(index + index_start) = dyn_const_prop_1(index)
end do
index_start = size(dyn_const_prop_1, 1)
deallocate(dyn_const_prop_1)
! Initialize constituent data and field object
call test_host_constituents_obj%initialize_table(num_consts)
! Add host model constituent metadata
do index = 1, size(host_constituents, 1)
const_prop => host_constituents(index)
call test_host_constituents_obj%new_field(const_prop, errcode=errflg, errmsg=errmsg)
nullify(const_prop)
if (errflg /= 0) then
return
end if
end do
! Add dynamic constituent properties
do index = 1, size(dynamic_constituents, 1)
const_prop => dynamic_constituents(index)
call test_host_constituents_obj%new_field(const_prop, errcode=errflg, errmsg=errmsg)
nullify(const_prop)
if (errflg /= 0) then
return
end if
end do
! Add cld_suite constituent metadata
num_suite_consts = cld_suite_constituents_num_consts(errflg=errflg, errmsg=errmsg)
if (errflg /= 0) then
return
end if
do index = 1, num_suite_consts
allocate(const_prop, stat=errflg)
if (errflg /= 0) then
errmsg = "ERROR allocating const_prop"
return
end if
call cld_suite_constituents_copy_const(index, const_prop, errflg=errflg, errmsg=errmsg)
if (errflg /= 0) then
return
end if
call test_host_constituents_obj%new_field(const_prop, errcode=errflg, errmsg=errmsg)
nullify(const_prop)
if (errflg /= 0) then
return
end if
end do
call test_host_constituents_obj%lock_table(errcode=errflg, errmsg=errmsg)
if (errflg /= 0) then
return
end if
! Set the index for each active constituent
do index = 1, SIZE(test_host_model_const_indices)
call test_host_constituents_obj%const_index(field_ind, &
test_host_model_const_stdnames(index), errcode=errflg, errmsg=errmsg)
if (errflg /= 0) then
return
end if
if (field_ind > 0) then
test_host_model_const_indices(index) = field_ind
else
errflg = 1
errmsg = 'No field index for '//trim(test_host_model_const_stdnames(index))
return
end if
end do
@peverwhee dyn_const_prop_0 and dyn_const_prop_1 are defined with the target attribute, but it's not needed. Is this intentional, or possibly an oversight/err by me in my previous commit?
@dustinswales not intentional! I removed the "target" attribute
Some test suggestion:
- Test for handling of duplicate compatible constituent
- Test for handling of duplicate semi-compatible constituent (e.g., unit difference), that the framework cannot handle.
- Test for handling of duplicate incompatible constituent
Some test suggestion:
- Test for handling of duplicate compatible constituent
- Test for handling of duplicate semi-compatible constituent (e.g., unit difference), that the framework cannot handle.
- Test for handling of duplicate incompatible constituent
Added logic to the constituents object to check for compatibility before adding a new constituent. Right now, that logic only checks a logical and character properties (advected, water species, thermo active, units). And added the following tests to the advection_test:
- Compatible constituent
- incompatible constituent
Also added unit tests to test parsing and fortran vs metadata comparisons
@gold2718 @mwaxmonsky Would you like to re-review before merging this?
@gold2718 @mwaxmonsky Would you like to re-review before merging this?
Sorry, can I have today?
@gold2718 @mwaxmonsky Would you like to re-review before merging this?
Sorry, can I have today?
Sure. We're trying to attach this to a set of UFS PRs that are on a queue to be final tested/merged early next week. If we can get final approval this week, it should be fine.