next up previous contents
Next: 6 CAM Physics Package Up: phys-interface Previous: 4 Utility Modules   Contents


5 Implementation of a Generic Interface

This section describes the CAM interface module for a generic physics package. We assume that the physics package is implemented in a module, and that the CAM specific interfaces are implemented in a separate module. To obtain maximum benefit from the data encapsulation capability provided by Fortran 90 modules we recommend that the default access of the interface module be set to private via use of the private statement. Use of the only qualifier in all use statements is also recommended. This prevents a used module from introducing unwanted names into a scope, and also provides documentation of where variables and procedures come from.

The public methods of the CAM interface are summarized here, and described in detail below. The prefix param_XXXX is used to indicate a generic parameterization. Section 6 provides the specific names used for the CAM parameterizations.

This method is for registering fields that are managed by the physics buffer module, and for registering constituents in the constituent arrays.

A package that manages constituents is responsible for initializing the constituent mixing ratios (by default they will be initialized to zero). This may be done by reading values from the initial file (set the namelist variable readtrace to .true., or by providing this method.

This method is for package specific initialization including setting time-invariant constants, specifying fields to be included in the history files, and opening datasets.

This method is for per timestep initialization, for example time interpolation on fields from a boundary dataset.

This method calls the package run method which computes the one step tendencies.

This interface breaks the package initialization into several parts and is closely tied to CAM's initialization. We expect that a redesign of CAM's initialization will allow a simpler interface for the package initialization. But as that task is yet to be accomplished, we present a flexible interface that works with the current (as of CAM-2.0.1) CAM code.

The calling sequence of these methods is as follows. Implications of this sequence will be discussed in the sections that detail the method interfaces.

    ! dynamics and physics grids initialized
        ! moist physics, chemistry, and radiation packages
      ! surface processes
        ! PBL, turbulence, gravity wave drag

5.1 Input from namelist

The only input facility currently available is Fortran's namelist. A package gains access to namelist input via public data in the interface module. The module variables are placed in the namelist, which is declared in procedure parse_namelist, and are made available via use association. This technique requires code modifications in parse_namelist unless the user is replacing a standard CAM package and can make use of the namelist variables already in place (these are detailed in section 6 on the specific CAM interfaces).

5.1.1 Template for input from namelist

This template illustrates how a package would obtain namelist input for the variable var_in. The default value of the namelist variable is set with an initialization statement in the module; not in an executable statement in parse_namelist. A separate namelist statement is used for the variables used by each package. The namelist group is ccmexp for all namelist statements.

module param_XXXX
! Public data for namelist input
   integer, public ::&
      var_in = 0       ! set default values with initialization statements
end module param_XXXX

subroutine parse_namelist
   use param_XXXX, only: var_in
   namelist /ccmexp/ ...
   namelist /ccmexp/ var_in    ! input for param_XXXX
   read (5,ccmexp,iostat=ierr)
end subroutine parse_namelist

When the model runs in a distributed memory mode there is one extra step that must be taken. Since the namelist is only read on the master processor, subroutine distnl must be modified as follows to communicate var_in to the other MPI tasks:

subroutine distnl
   use param_XXXX, only: var_in
   call mpibcast(var_in, 1, mpiint, 0, mpicom)
end subroutine distnl

5.2 Public interface methods

This section provides detailed examples of each of the public interface methods. These methods provide the CAM specific interface, and contain the calls to the physics package's public methods. We assume that the physics package is contained in its own module and that its public methods are the only means by which the it communicates with the interface module, as required by the column physics interchange standards [1] [2].

The examples will assume that the interface is implemented in a module called param_XXXX, and that the physics package is implemented in a module called pkg_XXXX. The public interface methods will be presented with only the relevent declarations of the containing module.

5.2.1 param_XXXX_register

The param_XXXX_register procedure is provided by packages to register constituent names and the corresponding physical properties, or to register the names and shapes of fields to be maintained across timesteps by the physics buffer. The registration method is separate from the initialization method because the constituent names must be known prior to reading initial condition data, and the package initialization procedure isn't called until after the initial file has been read. The registering of fields in the physics buffer must also happen early in the initialization process because the buffer must be allocated before the restart file is read during a restart run.

This routine is called from the CAM routine register which is called after parse_namelist. The following sample code registers an advected constituent and space for both a global field and a field which is local to physpkg in the physics buffer.

module param_XXXX
   use shr_kind_mod,  only: r8=>shr_kind_r8
   public :: param_XXXX_register()
! Local variables
   integer :: &
     ixcnst1,   &! global constituent index
     ixbuffld1, &! physics buffer index for BUFFLD1
     ixbuffld2   ! physics buffer index for BUFFLD2
subroutine param_XXXX_register()
   use constituents,  only: cnst_add, advected
   use phys_buffer,   only: pbuf_add
   use ppgrid,        only: pver
   implicit none
! request space in constituent array
   call cnst_add('CNST1', advected, 44.,  666., 0., ixcnst1)
! request space in phys buffer for fields that persist across timesteps
   call pbuf_add('BUFFLD1', 'global', 1,1,1, .false., ixbuffld1)
! Request phys buffer space for fields that are local to physpkg.
   call pbuf_add('BUFFLD2', 'physpkg', 1,pver,1, .false., ixbuffld2)
end subroutine param_XXXX_register
end module param_XXXX

5.2.2 param_XXXX_init_cnst

CAM initializes constituents in subroutine read_inidat. To make efficient use of memory only a single global constituent array is allocated and this array is subsequently scattered to the individual MPI processes when running in SPMD mode. read_inidat contains a loop over constituents and depending on the value of the namelist parameter readtrace either reads values from the initial file or calls the param_XXXX_init_cnst subroutines. Since read_inidat does not know which physics package is responsible for initializing each constituent it calls all the initializing subroutines with the name of the constituent as an argument and it is the responsibility of each param_XXXX_init_cnst subroutine to check whether or not it can intialize the requested constituent, and to return a global constituent array when appropriate.

The following sample code calls the physics package constituent initializer pkg_XXXX_init_cnst when the constituent that it knows how to initialize (CNST1) is requested. Note that the fld argument of param_XXXX_init_cnst has intent inout because the input values must be preserved when it is not known how to initialize the requested constituent.

module param_XXXX
   use shr_kind_mod,  only: r8=>shr_kind_r8
   public :: param_XXXX_init_cnst
subroutine param_XXXX_init_cnst(cnst_name, fld)
   use pmgrid,        only: plon, plev, plat
   use pkg_XXXX,      only: pkg_XXXX_init_cnst
   implicit none
   character(len=*),                    intent(in)    :: cnst_name
   real(r8), dimension(plon,plev,plat), intent(inout) :: fld
   if (cnst_name == 'CNST1') then
     call pkg_XXXX_init_cnst(fld)
   end if
end subroutine param_XXXX_init_cnst
end module param_XXXX

5.2.3 param_XXXX_init

The param_XXXX_init procedure is intended to perform time independent initializations. This procedure is called from subroutine inti after the initial data has been read and the model's prognostic variables have been initialized. Typically param_XXXX_init calls the physics package's initialization routine and registers the names of its output fields with the history module.

The following sample code calls the physics package initializer pkg_XXXX_init which does package specific initializations and sets the values of some physical constants. We assume that this package will produce tendencies for the dry static energy and all the constituents. It must therefore record those tendencies on the output history file. The names given to those tendencies in this example are arbitrary. However, if the tendencies have standard names (section 6), those names should be used to aid the post-processing of the output files. In the example we have also called add_default for each field to add the field to the default list for the primary history file.

module param_XXXX
   use ppgrid,        only: ppcnst
   public :: param_XXXX_init
! Local variables
   character(len=32) :: htendnam, qtendnam(ppcnst)  ! tendency names
subroutine param_XXXX_init()
   use physconst,     only: cpair, cpwv, gravit, rair
   use history,       only: addfld, physics_decomp, add_default
   use constituents,  only: cnst_name
   use pkg_XXXX,      only: pkg_XXXX_init
   implicit none

   call pkg_XXXX_init(cpair, cpwv, gravit, rair)

! Register output fields with the history module.
   htendnam = 'H_DTphys'
   do i = 1, ppcnst
      qtendnam(i) = cnst_name(i)//'_DTphys'
   end do
   call addfld(htendnam, 'J/kg/s', pver, 'A', &
               'heating rate due to phys', physics_decomp)
   call add_default(htendnam, 1, ' ')
   do i = 1, ppcnst
      call addfld(qtendnam(i), 'kg/kg/s', pver, 'A', &
                  cnst_name(i)//' tendency due to phys', physics_decomp)
      call add_default(qtendnam(i), 1, ' ')
   end do
end subroutine param_XXXX_init
end module param_XXXX

5.2.4 param_XXXX_timestep_init

Subroutine param_XXXX_timestep_init is called at the top of the physics driver from subroutine advnce on each timestep. The reason this subroutine is separated from param_XXXX_timestep_tend is to provide an opportunity in a section of code that is not threaded for a package to perform per timestep tasks, such as interpolation of boundary data. This may involve reading data from files which only happens on the master MPI process, and communicating results to all MPI processes. This type of communication must occur in a non-threaded code region.

5.2.5 param_XXXX_timestep_tend

The param_XXXX_timestep_tend procedure provides the interface to the package's run procedure. It is called each timestep from either tphysbc or tphysac. The called package is expected to return tendencies of the model state for one model timestep. It is possible that the package subdivides the model timestep, or does nothing during a given timestep.

We illustrate wrapping the following generic run procedure for a package that returns tendencies for the dry static energy and constituent fields.

module pkg_XXXX
   public :: pkg_XXXX_run
subroutine pkg_XXXX_run(dt, pcol, ncol, plev, ppcnst, &
                        dse, q, dhdt, dqdt )
   implicit none
   real(rkind), intent(in) ::&
      dt       ! timestep in seconds
   integer, intent(in) ::&
      pcol,   &! column dimension
      ncol,   &! number of columns
      plev,   &! level dimension
      ppcnst   ! constituent dimension
   real(rkind), dimension(pcol,plev), intent(in) ::&
      t        ! temperature (K)
   real(rkind), dimension(pcol,plev,ppcnst), intent(in) ::&
      q        ! constituent mixing ratio (kg/kg moist air)
   real(rkind), dimension(pcol,plev), intent(out) ::&
      dhdt     ! heating rate (J/kg/s)
   real(rkind), dimension(pcol,plev,ppcnst), intent(out) ::&
      dqdt     ! constituent tendency (kg/kg moist air/s)
end subroutine pkg_XXXX_run
end module pkg_XXXX

The physics package real kind can be set using the kind parameter from the shr_kind_mod module. This is not necessary if rkind has been independently set to ensure 8-byte real values.

The interface routine translates between the CAM derived types and the primitive types passed through the physics package run procedure.

module param_XXXX
   use shr_kind_mod,  only: r8=>shr_kind_r8
   use ppgrid,        only: pcols, pver, ppcnst
   public :: param_XXXX_timestep_tend
! Local variables
   character(len=32) :: htendnam, qtendnam(ppcnst)  ! tendency names
subroutine param_XXXX_timestep_tend(state, ptend, dt, pbuf)
   use physics_types, only: physics_state, physics_ptend, physics_ptend_reset
   use phys_buffer,   only: pbuf_size_max, pbuf_fld
   use history,       only: outfld
   use pkg_XXXX,      only: pkg_XXXX_run
   implicit none
! Arguments
   type(physics_state), intent(in)  :: state          ! state variables
   type(physics_ptend), intent(out) :: ptend          ! package tendencies
   real(r8),            intent(in)  :: dt             ! timestep
   type(pbuf_fld), intent(inout), dimension(pbuf_size_max) :: pbuf  ! physics buffer
! Local variables
   integer :: lchnk                     ! chunk identifier
   integer :: ncol                      ! number of atmospheric columns in chunk
   real(r8), pointer, dimension(:)   :: buffld1  ! physics buffer field1
   real(r8), pointer, dimension(:,:) :: buffld2  ! physics buffer field2

! Initialize output tendency structure
   call physics_ptend_reset(ptend)
   ptend%name  = 'param_XXXX'
   ptend%ls    = .true.
   ptend%lq    = .true.
! Initialize chunk id and size
   lchnk = state%lchnk
   ncol  = state%ncol
! associate local pointers with fields in the physics buffer
   buffld1 => pbuf(ixbuffld1)%fld_ptr(1,1:pcols,1,     lchnk,1)
   buffld2 => pbuf(ixbuffld2)%fld_ptr(1,1:pcols,1:pver,lchnk,1)

! set up and call physics package driver
   call pkg_XXXX_run(dt, pcols, ncol, pver, ppcnst, &
                     state%t, state%q, ptend%dhdt, ptend%dqdt, &
                     buffld1, buffld2 )
! write tendencies to history file
   call outfld(htendnam, ptend%dhdt, lchnk)
   do i = 1, ppcnst
      call outfld(qtendnam(i), ptend%dqdt(1,1,i), lchnk)
   end do
! update boundary quantities
   ptend%hflx_srf = 0.
   ptend%hflx_top = 0.
   ptend%cflx_srf = 0.
   ptend%cflx_top = 0.
end subroutine param_XXXX_timestep_tend
end module param_XXXX

The logical flags of the physics_ptend type are set to indicate which tendencies are returned by the physics package. The physics package's run routine is called with actual arguments from the CAM modules that specify array dimensions, and from the components of the CAM's derived types. On return from pkg_XXXX_run the outfld calls are made to put the package's forcings onto the output history file.

next up previous contents
Next: 6 CAM Physics Package Up: phys-interface Previous: 4 Utility Modules   Contents
Brian Eaton 2002-09-18