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 capgen 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_capgen.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_capgen.py script.
The CCPP capgen step performs the tasks below.
Parse Scheme and Host metadata and source files, compare argument list(s) consistency, check for requested vs provided variables by
standard_name, and also check for any Suite variables.Check units, dimensions, type. Add variable transformation if a mismatch of units/type is detected and the required conversion has been implemented (see
Section %sfor details).Filter unused schemes and variables.
Create caps for groups and suite(s).
Create Host caps
Create CCPP *datatable.
Populate target lists in CMakeLists.txt with scheme files, dependency files, and autogenerated cap files from datatable
The capgen datatable step will produce the following file lists for any host model. Note that the location of these files varies between the host models and whether an in-source or out-of-source build is used.
List of CCPP Scheme files:
SCHEME_FORTRAN_FILES
List of CCPP dependency files:
CAPGEN_DEPENDENCIES
List of autogenerated caps:
CAPGEN_FILES
List of Host model files:
HOST_FORTRAN_FILES
One cap per physics group (fast_physics, physics, radiation, time_vary, stochastic, …) for each suite:
ccpp_{suite_name}_{group_name}_cap.F90
Cap for each suite:
ccpp_{suite_name}_cap.F90
Autogenerated API (aka CCPP Framework).
{host_name}_ccpp_cap.F90
{host_name}_ccpp_cap.F90 is an interface, which contains subroutines ccpp_register, ccpp_init, ccpp_physics_init,
ccpp_physics_timestep_init, ccpp_physics_run, ccpp_physics_timestep_final, and ccpp_physics_final.
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, ufs_ccpp_cap.F90 would contain module ufs_ccpp_cap
with subroutines ccpp_physics_{register, init, physics_init, timestep_init, run, timestep_final, final}. Interested users
should run ccpp_capgen.py as appropriate for their model and inspect these auto-generated files.
5.2. Automatic variable 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. Similarly, the framework can also perform type conversions between host and scheme variables.
If a mismatch of units is detected and an automatic unit conversion can be performed, the CCPP capgen script will document this with a log message as in the following example:
DJS: THERE ARE NO MESSAGES MADE BY CAPGEN WHEN REGISTERING VARIABLE CONVERSION.
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. 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 Suite caps, before and after calling the Scheme.
module ccpp_suite_name
...
subroutine physics_run(lb, ub, ..., errmsg, errflg)
...
real(kind=kind_phys), dimension(lb:ub, levs) :: re_cloud_l
real(kind=kind_phys), dimension(lb:ub, levs) :: re_cloudice_l
real(kind=kind_dbl), dimension(lb:ub, levs) :: re_cloudsnow_1
...
! re_cloud is intent(in), re_cloudice is intent(inout), re_cloudsnow has intent(out) and is of type R8.
re_cloud_l = 1.0E-6_kind_phys*re_cloud
re_cloudice_l = 1.0E-6_kind_phys*re_cloud_ice
re_cloudsnow_1 = real(re_cloudsnow, type=R8)
call mp_thompson_run(...,re_cloud=re_cloud_l,re_cloudice=re_cloudice_l,re_cloudliq=re_cloudliq_l...,errmsg=errmsg,errflg=errflg)
re_cloudice = 1.0E+6_kind_phys* re_cloudice_l
re_cloudsnow = real(re_cloudsnow_1,type=kind_phys)
If a required unit conversion has not been implemented the CCPP capgen script will generate an error message as follows:
Variable 'prsl' (standard_name='air_pressure'): host units 'Pa' differ from scheme 'mp_thompson' units 'PaPaPa' but no unit conversion is known; add a conversion to metadata/unit_conversion.py or fix the metadata
All automatic unit conversions are implemented in ccpp-framework/capgen/metadata/unit_conversion.py,
new unit conversions can be added to this file by following the existing examples.
5.3. Optional Scheme variables¶
For Scheme’s with optional arguments, the CCPP framework generates local pointers in the Group cap. These local pointers are associated within the Group cap, just prior to calling the Scheme.
module ccpp_suite_name
use ccpp_suite_name_types, only:real_kind_phys_rank1_ptr_type
...
subroutine physics_run(lb, ub, ..., errmsg, errflg)
...
type(real_kind_phys_rank1_ptr_type) :: nwfa2d_p
...
if ((do_thompson) .and. (ltaerosol .or. mraerosol)) then
nwfa2d_p%ptr => nwfa2d(lb:ub)
else
nullify(nwfa2d_p%ptr)
end if
! re_cloud is optional in mp_thompson_run
call mp_thompson_run(..., nwfa2d=nwfa2d_p%ptr,...,errmsg=errmsg,errflg=errflg)