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 %s for 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)