5. Suite and Group Caps¶
The connection between the host model and the physics schemes through the CCPP-Framework
is realized with caps on both sides as illustrated in Figure 1.1.
The CCPP prebuild script discussed in Chapter 3
generates the caps that connect the physics schemes to the CCPP-Framework.
This chapter describes the suite and group caps,
while the host model caps are described in Chapter 6.
These caps autogenerated by ccpp_prebuild.py
reside in the directory
defined by the CAPS_DIR
variable (see example in Listing 8.1).
5.1. Overview¶
When CCPP is built, the CCPP-Framework and physics are statically linked to the executable. This allows the best
performance and efficient memory use. This build requires metadata provided
by the host model and variables requested from the physics scheme. Only the variables required for
the specified suites are kept, requiring one or more SDFs (see left side of Figure 3.1)
as arguments to the ccpp_prebuild.py
script.
The CCPP prebuild step performs the tasks below.
Check requested vs provided variables by
standard_name
.Check units, rank, type. Perform unit conversions if a mismatch of units is detected and the required conversion has been implemented (see Section 5.2 for details).
Filter unused schemes and variables.
Create Fortran code for the static Application Programming Interface (API).
Create caps for groups and suite(s).
Populate makefiles with schemes and caps.
The prebuild step will produce the following files for the UFS Atmosphere:
List of variables provided by host model and required by physics:
ccpp/framework/doc/DevelopersGuide/CCPP_VARIABLES_FV3.tex
Makefile snippets that contain all caps to be compiled:
ccpp/physics/CCPP_CAPS.{cmake,mk}
Makefile snippets that contain all schemes to be compiled:
ccpp/physics/CCPP_SCHEMES.{cmake,mk}
List of CCPP types:
ccpp/physics/CCPP_TYPEDEFS.{cmake,mk}
List of variables provided by host model:
ccpp/physics/CCPP_VARIABLES_FV3.html
One cap per physics group (fast_physics, physics, radiation, time_vary, stochastic, …) for each suite:
ccpp/physics/ccpp_{suite_name}_{group_name}_cap.F90
Cap for each suite:
ccpp/physics/ccpp_{suite_name}_cap.F90
Autogenerated API (aka CCPP-Framework).
FV3/gfsphysics/CCPP_layer/ccpp_static_api.F90
ccpp_static_api.F90
is an interface,
which contains subroutines ccpp_physics_init
, ccpp_physics_run
and ccpp_physics_finalize
.
Each subroutine uses a suite_name
and an optional argument, group_name
, to call the groups
of a specified suite (e.g. fast_physics
, physics
, time_vary
, radiation
, stochastic
, etc.),
or to call the entire suite. For example, ccpp_static_api.F90
would contain module ccpp_static_api
with subroutines ccpp_physics_{init, run, finalize}
. The subroutine ccpp_physics_init
from the
autogenerated code using suites FV3_GFS_v15
and FV3_CPT_v0
is shown in Listing 5.2.
subroutine ccpp_physics_init(cdata, suite_name, group_name, ierr)
use ccpp_types, only : ccpp_t
implicit none
type(ccpp_t), intent(inout) :: cdata
character(len=*), intent(in) :: suite_name
character(len=*), optional, intent(in) :: group_name
integer, intent(out) :: ierr
ierr = 0
if (trim(suite_name)=="FV3_GFS_v15") then
if (present(group_name)) then
if (trim(group_name)=="fast_physics") then
ierr = FV3_GFS_v15_fast_physics_init_cap(cdata=cdata, CCPP_interstitial=CCPP_interstitial)
else if (trim(group_name)=="time_vary") then
ierr = FV3_GFS_v15_time_vary_init_cap(GFS_Interstitial=GFS_Interstitial, &
cdata=cdata,GFS_Data=GFS_Data, GFS_Control=GFS_Control)
else if (trim(group_name)=="radiation") then
ierr = FV3_GFS_v15_radiation_init_cap()
else if (trim(group_name)=="physics") then
ierr = FV3_GFS_v15_physics_init_cap(cdata=cdata, GFS_Control=GFS_Control)
else if (trim(group_name)=="stochastics") then
ierr = FV3_GFS_v15_stochastics_init_cap()
else
write(cdata%errmsg, '(*(a))') "Group " // trim(group_name) // " not found"
ierr = 1
end if
else
ierr = FV3_GFS_v15_init_cap(GFS_Interstitial=GFS_Interstitial, cdata=cdata,GFS_Control=GFS_Control, &
GFS_Data=GFS_Data, CCPP_interstitial=CCPP_interstitial)
end if
else if (trim(suite_name)=="FV3_CPT_v0") then
if (present(group_name)) then
if (trim(group_name)=="time_vary") then
ierr = FV3_CPT_v0_time_vary_init_cap(GFS_Interstitial=GFS_Interstitial, &
cdata=cdata,GFS_Data=GFS_Data, GFS_Control=GFS_Control)
else if (trim(group_name)=="radiation") then
ierr = FV3_CPT_v0_radiation_init_cap()
else if (trim(group_name)=="physics") then
ierr = FV3_CPT_v0_physics_init_cap(con_hfus=con_hfus, &
GFS_Control=GFS_Control,con_hvap=con_hvap, &
con_rd=con_rd,con_rv=con_rv,con_g=con_g, &
con_ttp=con_ttp,con_cp=con_cp,cdata=cdata)
else if (trim(group_name)=="stochastics") then
ierr = FV3_CPT_v0_stochastics_init_cap()
else
write(cdata%errmsg, '(*(a))') "Group " // trim(group_name) // " not found"
ierr = 1
end if
else
ierr = FV3_CPT_v0_init_cap(con_g=con_g, GFS_Data=GFS_Data,GFS_Control=GFS_Control, &
con_hvap=con_hvap,GFS_Interstitial=GFS_Interstitial, con_rd=con_rd,con_rv=con_rv, &
con_hfus=con_hfus, con_ttp=con_ttp,con_cp=con_cp,cdata=cdata)
end if
else
write(cdata%errmsg,'(*(a))'), 'Invalid suite ' // trim(suite_name)
ierr = 1
end if
cdata%errflg = ierr
end subroutine ccpp_physics_init
Listing 5.2: Code sample of subroutine ccpp_physics_init
contained in the autogenerated file
ccpp_static_api.F90
for the multi-suite build. This cap was generated using suites
FV3_GFS_v15
and FV3_CPT_v0
. Examples of the highlighted functions are shown below in
Listing 5.3 and Listing 5.4.
Note that if group_name is set, specified groups (i.e. FV3_GFS_v15_physics_init_cap
) are called for the
specified suite_name
. These functions are defined in ccpp_{suite_name}_{group_name}_cap.F90
, in this
case ccpp_FV3_GFS_v15_physics_cap.F90
. For example:
function FV3_GFS_v15_physics_init_cap(cdata,GFS_Control)&
result(ierr)
use ccpp_types, only: ccpp_t
use GFS_typedefs, only: GFS_control_type
implicit none
integer :: ierr
type(ccpp_t), intent(inout) :: cdata
type(GFS_control_type), intent(in) :: GFS_Control
ierr = 0
if (initialized) return
call lsm_noah_init(me=GFS_Control%me,isot=GFS_Control%isot,&
ivegsrc=GFS_Control%ivegsrc,nlunit=GFS_Control%nlunit, &
errmsg=cdata%errmsg,errflg=cdata%errflg)
if (cdata%errflg/=0) then
write(cdata%errmsg,'(a)') "An error occured in lsm_noah_init"
ierr=cdata%errflg
return
end if
call gfdl_cloud_microphys_init(me=GFS_Control%me, &
master=GFS_Control%master,nlunit=GFS_Control%nlunit, &
input_nml_file=GFS_Control%input_nml_file, &
logunit=GFS_Control%logunit,fn_nml=GFS_Control%fn_nml, &
imp_physics=GFS_Control%imp_physics, &
imp_physics_gfdl=GFS_Control%imp_physics_gfdl, &
do_shoc=GFS_Control%do_shoc, &
errmsg=cdata%errmsg,errflg=cdata%errflg)
if (cdata%errflg/=0) then
write(cdata%errmsg,'(a)') "An error occured in &
gfdl_cloud_microphys_init"
ierr=cdata%errflg
return
end if
initialized = .true.
end function FV3_GFS_v15_physics_init_cap
Listing 5.3: The FV3_GFS_v15_physics_init_cap
contained in the autogenerated file
ccpp_FV3_GFS_v15_physics_cap.F90
showing calls to the lsm_noah_init
, and
gfdl_cloud_microphys_init
subroutines for the build for suite ‘FV3_GFS_v15’ and group ‘physics’.
If the group_name is not specified for a specified suite_name, the suite is called from the autogenerated
ccpp_static_api.F90
, which calls the init
, run
and finalize
routines for each group.
Listing 5.4 is an example of FV3_GFS_v15_init_cap
.
function FV3_GFS_v15_init_cap(GFS_Interstitial, &
cdata,GFS_Control,GFS_Data,CCPP_interstitial) result(ierr)
use GFS_typedefs, only: GFS_interstitial_type
use ccpp_types, only: ccpp_t
use GFS_typedefs, only: GFS_control_type
use GFS_typedefs, only: GFS_data_type
use CCPP_typedefs, only: CCPP_interstitial_type
implicit none
integer :: ierr
type(GFS_interstitial_type), intent(inout) :: GFS_Interstitial(:)
type(ccpp_t), intent(inout) :: cdata
type(GFS_control_type), intent(inout) :: GFS_Control
type(GFS_data_type), intent(inout) :: GFS_Data(:)
type(CCPP_interstitial_type), intent(in) :: CCPP_interstitial
ierr = 0
ierr = FV3_GFS_v15_fast_physics_init_cap(cdata=cdata, CCPP_interstitial=CCPP_interstitial)
if (ierr/=0) return
ierr = FV3_GFS_v15_time_vary_init_cap (GFS_Interstitial=GFS_Interstitial,cdata=cdata, &
GFS_Data=GFS_Data,GFS_Control=GFS_Control)
if (ierr/=0) return
ierr = FV3_GFS_v15_radiation_init_cap()
if (ierr/=0) return
ierr = FV3_GFS_v15_physics_init_cap(cdata=cdata, &
GFS_Control=GFS_Control)
if (ierr/=0) return
ierr = FV3_GFS_v15_stochastics_init_cap()
if (ierr/=0) return
end function FV3_GFS_v15_init_cap
Listing 5.4: Condensed version of the FV3_GFS_v15_init_cap
function contained in the autogenerated
file ccpp_FV3_GFS_v15_cap.F90
showing calls to the group caps
FV3_GFS_v15_fast_physics_init_cap
, FV3_GFS_v15_time_vary_init_cap
, etc.
for the build where a group name is not specified.
5.2. Automatic unit conversions¶
The CCPP framework is capable of performing automatic unit conversions if a mismatch of units between the host model and a physics scheme is detected, provided that the required unit conversion has been implemented.
If a mismatch of units is detected and an automatic unit conversion can be performed, the CCPP prebuild script will document this with a log message as in the following example:
INFO: Comparing metadata for requested and provided variables ...
INFO: Automatic unit conversion from m to um for effective_radius_of_stratiform_cloud_ice_particle_in_um after returning from MODULE_mp_thompson SCHEME_mp_thompson SUBROUTINE_mp_thompson_run
INFO: Automatic unit conversion from m to um for effective_radius_of_stratiform_cloud_liquid_water_particle_in_um after returning from MODULE_mp_thompson SCHEME_mp_thompson SUBROUTINE_mp_thompson_run
INFO: Automatic unit conversion from m to um for effective_radius_of_stratiform_cloud_snow_particle_in_um after returning from MODULE_mp_thompson SCHEME_mp_thompson SUBROUTINE_mp_thompson_run
INFO: Generating schemes makefile/cmakefile snippet ...
The CCPP framework is performing only the minimum unit conversions necessary, depending on the
intent information of the variable in the parameterization’s metadata table. In the above example,
the cloud effective radii are intent(out)
variables, which means that no unit conversion is required
before entering the subroutine mp_thompson_run
. Below are examples for auto-generated code performing
automatic unit conversions from m
to um
or back, depending on the intent of the variable. The conversions
are performed in the individual physics scheme caps for the dynamic build, or the group caps for the build.
! var1 is intent(in)
call mp_thompson_run(...,recloud=1.0E-6_kind_phys*re_cloud,...,errmsg=cdata%errmsg,errflg=cdata%errflg)
ierr=cdata%errflg
! var1 is intent(inout)
allocate(tmpvar1, source=re_cloud)
tmpvar1 = 1.0E-6_kind_phys*re_cloud
call mp_thompson_run(...,re_cloud=tmpvar1,...,errmsg=cdata%errmsg,errflg=cdata%errflg)
ierr=cdata%errflg
re_cloud = 1.0E+6_kind_phys*tmpvar1
deallocate(tmpvar1)
! var1 is intent(out)
allocate(tmpvar1, source=re_cloud)
call mp_thompson_run(...,re_cloud=tmpvar1,...,errmsg=cdata%errmsg,errflg=cdata%errflg)
ierr=cdata%errflg
re_cloud = 1.0E+6_kind_phys*tmpvar1
deallocate(tmpvar1)
If a required unit conversion has not been implemented the CCPP prebuild script will generate an error message as follows:
INFO: Comparing metadata for requested and provided variables ...
ERROR: Error, automatic unit conversion from m to pc for effective_radius_of_stratiform_cloud_ice_particle_in_um in MODULE_mp_thompson SCHEME_mp_thompson SUBROUTINE_mp_thompson_run not implemented
All automatic unit conversions are implemented in ccpp/framework/scripts/conversion_tools/unit_conversion.py
,
new unit conversions can be added to this file by following the existing examples.