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

Constituent index lookup #622

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions scripts/ccpp_datafile.py
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,8 @@ def _add_generated_files(parent, host_files, suite_files, ccpp_kinds, src_dir):
entry = ET.SubElement(utilities, "file")
entry.text = os.path.join(src_dir, "ccpp_constituent_prop_mod.F90")
entry = ET.SubElement(utilities, "file")
entry.text = os.path.join(src_dir, "ccpp_scheme_utils.F90")
entry = ET.SubElement(utilities, "file")
entry.text = os.path.join(src_dir, "ccpp_hashable.F90")
entry = ET.SubElement(utilities, "file")
entry.text = os.path.join(src_dir, "ccpp_hash_table.F90")
Expand Down
3 changes: 3 additions & 0 deletions scripts/constituents.py
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,8 @@ def write_host_routines(cap, host, reg_funcname, init_funcname, num_const_funcna
cap.write(f"{substmt}(ncols, num_layers, {err_dummy_str})", 1)
cap.comment("Initialize constituent data", 2)
cap.blank_line()
cap.write("use ccpp_scheme_utils, only: ccpp_initialize_constituent_ptr", 2)
cap.blank_line()
cap.comment("Dummy arguments", 2)
cap.write("integer, intent(in) :: ncols", 2)
cap.write("integer, intent(in) :: num_layers", 2)
Expand All @@ -617,6 +619,7 @@ def write_host_routines(cap, host, reg_funcname, init_funcname, num_const_funcna
cap.blank_line()
call_str = f"call {const_obj_name}%lock_data(ncols, num_layers, {obj_err_callstr})"
cap.write(call_str, 2)
cap.write(f"call ccpp_initialize_constituent_ptr({const_obj_name})", 2)
cap.write(f"end {substmt}", 1)
# Write num_consts routine
substmt = f"subroutine {num_const_funcname}"
Expand Down
16 changes: 0 additions & 16 deletions scripts/host_cap.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,6 @@ def constituent_initialize_subname(host_model):
Because this is a user interface API function, the name is fixed."""
return f"{host_model.name}_ccpp_initialize_constituents"

###############################################################################
def constituent_initialize_subname(host_model):
###############################################################################
"""Return the name of the subroutine used to initialize the
constituents for this run.
Because this is a user interface API function, the name is fixed."""
return f"{host_model.name}_ccpp_initialize_constituents"

###############################################################################
def constituent_num_consts_funcname(host_model):
###############################################################################
Expand All @@ -125,14 +117,6 @@ def query_scheme_constituents_funcname(host_model):
Because this is a user interface API function, the name is fixed."""
return f"{host_model.name}_ccpp_is_scheme_constituent"

###############################################################################
def query_scheme_constituents_funcname(host_model):
###############################################################################
"""Return the name of the function to return True if the standard name
passed in matches an existing constituent
Because this is a user interface API function, the name is fixed."""
return f"{host_model.name}_ccpp_is_scheme_constituent"

###############################################################################
def constituent_copyin_subname(host_model):
###############################################################################
Expand Down
2 changes: 1 addition & 1 deletion src/ccpp_constituent_prop_mod.F90
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ module ccpp_constituent_prop_mod
integer, parameter :: mass_mixing_ratio = -5
integer, parameter :: volume_mixing_ratio = -6
integer, parameter :: number_concentration = -7
integer, parameter :: int_unassigned = -HUGE(1)
integer, public, parameter :: int_unassigned = -HUGE(1)
real(kind_phys), parameter :: kphys_unassigned = HUGE(1.0_kind_phys)

!! \section arg_table_ccpp_constituent_properties_t
Expand Down
101 changes: 101 additions & 0 deletions src/ccpp_scheme_utils.F90
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
module ccpp_scheme_utils

! Module of utilities available to CCPP schemes

use ccpp_constituent_prop_mod, only: ccpp_model_constituents_t, int_unassigned

implicit none
private

!! Public interfaces
public :: ccpp_initialize_constituent_ptr ! Used by framework to initialize
public :: ccpp_constituent_index ! Lookup index constituent by name
public :: ccpp_constituent_indices ! Lookup indices of consitutents by name

!! Private module variables & interfaces

! initialized set to .true. once hash table pointer is initialized
logical :: initialized = .false.
type(ccpp_model_constituents_t), pointer :: constituent_obj => NULL()

private :: uninitialized

contains

subroutine uninitialized(caller, errcode, errmsg)
! Dummy arguments
character(len=*), intent(in) :: caller
integer, optional, intent(out) :: errcode
character(len=*), optional, intent(out) :: errmsg

if (.not. initialized) then
if (present(errcode)) then
errcode = 1
end if
if (present(errmsg)) then
errmsg = trim(caller)//' FAILED, module not initialized'
end if
end if
end subroutine uninitialized

subroutine ccpp_initialize_constituent_ptr(const_obj)
! Dummy arguments
type(ccpp_model_constituents_t), pointer, intent(in) :: const_obj

if (.not. initialized) then
peverwhee marked this conversation as resolved.
Show resolved Hide resolved
constituent_obj => const_obj
initialized = .true.
end if
end subroutine ccpp_initialize_constituent_ptr

subroutine ccpp_constituent_index(standard_name, const_index, errcode, errmsg)
Copy link
Collaborator

Choose a reason for hiding this comment

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

General design question - what is the anticipated usage of these interfaces on the physics side?

As written, the code would return int_unassigned for the index if the provided constituent isn't present. So would it be expected that the physics would check for int_unassigned after calling ccpp_constituent_index?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Great question. The benefit I see in returning int_unassigned is you can include logic for handling configurations that do not have all the constituents you might be looking for. On the other hand, it complicates just looking for errcode. Feedback @climbfuji, @dustinswales, everyone?

Copy link
Collaborator

Choose a reason for hiding this comment

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

@gold2718 @peverwhee I haven't thought through how we would tackle implementing the constituents feature in the UFS, so I don't have a strong opinion. On the physics side, having to check that index ne int_unassigned before using index seems sensible to me. At least with my (limited) understanding.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this makes sense. Someone may want to iterate over constituents to see what is available and what not. That is, not every call to this scheme should result in errflg /= success.

! Dummy arguments
character(len=*), intent(in) :: standard_name
integer, intent(out) :: const_index
integer, optional, intent(out) :: errcode
character(len=*), optional, intent(out) :: errmsg

! Local variable
character(len=*), parameter :: subname = 'ccpp_constituent_index'

if (initialized) then
call constituent_obj%const_index(const_index, standard_name, &
errcode, errmsg)
else
const_index = int_unassigned
call uninitialized(subname)
end if
end subroutine ccpp_constituent_index

subroutine ccpp_constituent_indices(standard_names, const_inds, errcode, errmsg)
! Dummy arguments
character(len=*), intent(in) :: standard_names(:)
integer, intent(out) :: const_inds(:)
integer, optional, intent(out) :: errcode
character(len=*), optional, intent(out) :: errmsg

! Local variables
integer :: indx
character(len=*), parameter :: subname = 'ccpp_constituent_indices'

const_inds = int_unassigned
if (initialized) then
if (size(const_inds) < size(standard_names)) then
errcode = 1
errmsg = subname//': const_inds too small'
Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe a slightly clearer error message?

errmsg = subname//': const_inds array too small. Must be greater than or equal to the size of standard_names'

else
do indx = 1, size(standard_names)
! For each std name in <standard_names>, find the const. index
call constituent_obj%const_index(const_inds(indx), &
standard_names(indx), errcode, errmsg)
if (errcode /= 0) then
exit
end if
end do
end if
else
call uninitialized(subname)
end if
end subroutine ccpp_constituent_indices

end module ccpp_scheme_utils
1 change: 1 addition & 0 deletions test/advection_test/cld_suite.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

<suite name="cld_suite" version="1.0">
<group name="physics">
<scheme>const_indices</scheme>
<scheme>cld_liq</scheme>
<scheme>apply_constituent_tendencies</scheme>
<scheme>cld_ice</scheme>
Expand Down
1 change: 1 addition & 0 deletions test/advection_test/cld_suite_files.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
cld_liq.meta
cld_ice.meta
apply_constituent_tendencies.meta
const_indices.meta
77 changes: 77 additions & 0 deletions test/advection_test/const_indices.F90
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
! Test collection of constituent indices
!

MODULE const_indices

USE ccpp_kinds, ONLY: kind_phys

IMPLICIT NONE
PRIVATE

PUBLIC :: const_indices_init
PUBLIC :: const_indices_run

CONTAINS

!> \section arg_table_const_indices_run Argument Table
!! \htmlinclude arg_table_const_indices_run.html
!!
subroutine const_indices_run(const_std_name, num_consts, test_stdname_array, &
const_index, const_inds, errmsg, errflg)
use ccpp_scheme_utils, only: ccpp_constituent_index, ccpp_constituent_indices

character(len=*), intent(in) :: const_std_name
integer, intent(in) :: num_consts
character(len=*), intent(in) :: test_stdname_array(:)
integer, intent(out) :: const_index
integer, intent(out) :: const_inds(:)
character(len=512), intent(out) :: errmsg
integer, intent(out) :: errflg
!----------------------------------------------------------------

integer :: indx

errmsg = ''
errflg = 0

! Find the constituent index for <const_std_name>
call ccpp_constituent_index(const_std_name, const_index, errflg, errmsg)
if (errflg == 0) then
call ccpp_constituent_indices(test_stdname_array, const_inds, errflg, errmsg)
end if
Copy link
Collaborator

Choose a reason for hiding this comment

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

would it be worthwhile to also test that calling ccpp_constituent_indices with a constituent that's NOT in the object doesn't produce an error?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yep, will do, good call.


end subroutine const_indices_run

!> \section arg_table_const_indices_init Argument Table
!! \htmlinclude arg_table_const_indices_init.html
!!
subroutine const_indices_init(const_std_name, num_consts, test_stdname_array, &
const_index, const_inds, errmsg, errflg)
use ccpp_scheme_utils, only: ccpp_constituent_index, ccpp_constituent_indices

character(len=*), intent(in) :: const_std_name
integer, intent(in) :: num_consts
character(len=*), intent(in) :: test_stdname_array(:)
integer, intent(out) :: const_index
integer, intent(out) :: const_inds(:)
character(len=512), intent(out) :: errmsg
integer, intent(out) :: errflg
!----------------------------------------------------------------

integer :: indx

errmsg = ''
errflg = 0

! Find the constituent index for <const_std_name>
call ccpp_constituent_index(const_std_name, const_index, errflg, errmsg)
if (errflg == 0) then
call ccpp_constituent_indices(test_stdname_array, const_inds, errflg, errmsg)
end if

end subroutine const_indices_init

!! @}
!! @}

END MODULE const_indices
108 changes: 108 additions & 0 deletions test/advection_test/const_indices.meta
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# const_indices just returns some constituent indices as a test
[ccpp-table-properties]
name = const_indices
type = scheme
[ccpp-arg-table]
name = const_indices_run
type = scheme
[ const_std_name ]
standard_name = test_banana_name
type = character | kind = len=*
units = 1
dimensions = ()
protected = true
intent = in
[ num_consts ]
standard_name = banana_array_dim
long_name = Size of test_banana_name_array
units = 1
dimensions = ()
type = integer
intent = in
[ test_stdname_array ]
standard_name = test_banana_name_array
type = character | kind = len=*
units = count
dimensions = (banana_array_dim)
intent = in
[ const_index ]
standard_name = test_banana_constituent_index
long_name = Constituent index
units = 1
dimensions = ()
type = integer
intent = out
[ const_inds ]
standard_name = test_banana_constituent_indices
long_name = Array of constituent indices
units = 1
dimensions = (banana_array_dim)
type = integer
intent = out
[ errmsg ]
standard_name = ccpp_error_message
long_name = Error message for error handling in CCPP
units = none
dimensions = ()
type = character
kind = len=512
intent = out
[ errflg ]
standard_name = ccpp_error_code
long_name = Error flag for error handling in CCPP
units = 1
dimensions = ()
type = integer
intent = out
[ccpp-arg-table]
name = const_indices_init
type = scheme
[ const_std_name ]
standard_name = test_banana_name
type = character | kind = len=*
units = 1
dimensions = ()
protected = true
intent = in
[ num_consts ]
standard_name = banana_array_dim
long_name = Size of test_banana_name_array
units = 1
dimensions = ()
type = integer
intent = in
[ test_stdname_array ]
standard_name = test_banana_name_array
type = character | kind = len=*
units = count
dimensions = (banana_array_dim)
intent = in
[ const_index ]
standard_name = test_banana_constituent_index
long_name = Constituent index
units = 1
dimensions = ()
type = integer
intent = out
[ const_inds ]
standard_name = test_banana_constituent_indices
long_name = Array of constituent indices
units = 1
dimensions = (banana_array_dim)
type = integer
intent = out
[ errmsg ]
standard_name = ccpp_error_message
long_name = Error message for error handling in CCPP
units = none
dimensions = ()
type = character
kind = len=512
intent = out
[ errflg ]
standard_name = ccpp_error_code
long_name = Error flag for error handling in CCPP
units = 1
dimensions = ()
type = integer
intent = out
Loading
Loading