next up previous contents
Next: 5 Implementation of a Up: phys-interface Previous: 3 Physics Driver and   Contents


4 Utility Modules

The physics interface design makes use of several utility modules which are described in this section.

4.1 Physical constants

A common set of physical constants is made available to all packages by use association of module physconst. The constants required by a package should be listed in the only qualifier of the use statement. Most of these constants are set to values that are shared by all CCSM components (the actual values are set from the shr_const_mod module rather than being literal constants). Below is a summary of the currently defined values.

real(r8), parameter ::&
 r_universal = 6.02214e26*1.38065e-23, &! Universal gas constant (J/K/kmol)
 mwdry  =  28.966,         &! molecular weight dry air
 mwco2  =  44.,            &! molecular weight co2
 mwh2o  =  18.016,         &! molecular weight h2o
 mwn2o  =  44.,            &! molecular weight n2o
 mwch4  =  16.,            &! molecular weight ch4
 mwf11  = 136.,            &! molecular weight cfc11
 mwf12  = 120.,            &! molecular weight cfc12
 epsilo = mwh2o/mwdry,     &
 stebol = 5.67e-8,         &! Stefan-Boltzmann's constant (W/m2/K4)
 gravit = 9.80616,         &! Gravitational acceleration (m/s2)
 rga    = 1./gravit,       &
 rair   = r_universal/mwdry, &! Gas constant for dry air (J/kg/K)
 cpair  = 1004.64,         &! Specific heat of dry air (J/kg/K)
 cappa  = rair/cpair,      &
 pstd   = 101325.,         &! Standard pressure (Pa)
 tmelt  = 273.16,          &! Freezing point of water (K)
 rhodair= pstd/(rair*tmelt), &! density of dry air at STP (kg/m3)
 latvap = 2.501e6,         &! Latent heat of vaporization (J/kg)
 latice = 3.337e5,         &! Latent heat of fusion (J/kg)
 rhoh2o = 1.e3,            &! Density of liquid water (STP) (kg/m3)
 rh2o   = r_universal/mwh2o, &! Gas constant for water vapor (J/kg/K)
 cpwv   = 1.81e3,          &! Specific heat of water vapor (J/kg/K)
 cpvir  = cpwv/cpair - 1., &
 zvir   = rh2o/rair - 1.,  &! rh2o/rair - 1
 karman = .4                ! VonKarman constant

4.2 Output to history files

CAM provides for output via use association of the history module. Fields to be output are registered with the history module by calling the history methods (i.e., subroutines in the history module) addfld and add_default during initialization, and the writing of field data is accomplished by calls to subroutine outfld.

Each package must be able to record its net forcing to the output history file. To facilitate post-processing of model runs the forcings of particular processes have standard names which are given in section 6. It is the responsibility of the user who is replacing a standard CAM package to supply these quantities using the standard names. Any other diagnostic fields may be output by using the appropriate calls to addfld, add_default and outfld.

To register a field with the history module the first step is to call subroutine addfld which has the following interface:

subroutine addfld (fname, units, numlev, avgflag, long_name, &
   character(len=*), intent(in) :: &
     fname,    &! field name (8 char max)
     units,    &! field units (8 char max)
     long_name  ! long name of field
   character(len=1), intent(in) :: &
     avgflag    ! averaging flag: 'A' for average, 'I' for instantaneous,
                !  'X' for maximum, 'M' for minimum
   integer, intent(in) :: &
     numlev,   &! number of vertical levels
     type       ! decomposition type
end subroutine addfld

The decomposition type specifies the type of data structure passed to outfld. Parameters used to specify the decomposition types are public data members of the history module. The parameter physics_decomp should be used to indicate that outfld calls will pass data using the ``chunked'' data structure. A call to addfld will add the field to the ``master field list'', but the field will not automatically appear in output history files unless it is declared as a default field on one of the files. (The field will appear on an output history file even if it is not a default field for that file if it is specified in one of the namelist variables fincl1, ..., fincl6.) The add_default subroutine is used to declare the field as a default field on one of the history files. Its interface is:

subroutine add_default (name, tindex, flag)
   character(len=*), intent(in) :: name  ! field name
   character(len=1), intent(in) :: flag  ! averaging flag
   integer, intent(in) :: tindex         ! history file index (1 - 6)
end subroutine add_default

The averaging flag is specified in this call because a field can have different values in different history files. For example a temperature field can have time averaged values in history file 1 and instantaneous values at a different output frequency in file 2.

The output of field values is accomplished by calling subroutine outfld whose interface is:

subroutine outfld (fname, field, j)
   character(len=*),         intent(in) :: fname ! Field name
   real(r8), dimension(...), intent(in) :: field ! field values
   integer,                  intent(in) :: j     ! chunk or block index
end subroutine outfld

outfld is a generic function that takes either one or two-dimension input arrays. Examples of the use of these procedures are given in section 5.2.

4.3 Physics buffer

The module phys_buffer manages the physics buffer which stores fields that must be available across timesteps or that must be shared between physics packages during a single timestep. Fields that persist across timesteps must be written out to the restart files. The physics buffer module performs this task without any intervention from the implementor of a physics package.

To use the physics buffer a package only has to register the required fields, and then access the fields through pointers that are contained in the buffer. The buffer is implemented as an array of a derived type, and the derived type contains a pointer to the field data.

To register a field the pbuf_add method is used. It's interface is:

subroutine pbuf_add(name, scope, fdim, mdim, ldim, index)
   character(len=*), intent(in)  :: name   ! field name 
   character(len=*), intent(in)  :: scope  ! 'global' or 'physpkg'
   integer,          intent(in)  :: fdim   ! first generic field dimension
   integer,          intent(in)  :: mdim   ! middle generic field dimension
   integer,          intent(in)  :: ldim   ! last generic field dimension
   integer,          intent(out) :: index  ! index in the physics buffer

A field that must persist across timesteps should specify the scope as 'global'. These fields will be written to the restart file by the physics buffer module. Fields that only need to persist while physpkg is active should specify a scope of 'physpkg'. These fields are dynamically allocated and deallocated at the beginning and end of physpkg respectively.

The generic dimensions fdim, mdim, and ldim refer to the following generic field declaration which is used in the phys_grid methods that are responsible for gathering and scattering data between chunks and global fields.


To register a 2D field fdim, mdim, and ldim would all be set to $1$. To register a 3D field set fdim and ldim to $1$ and set mdim to pvers.

A package that stores a field for the purpose of computing time tendencies must save more that one time level if the dynamics package uses a multiple level time integration scheme. To register a field with time levels that depend on the dynamics package the ldim argument is set to pbuf_times which is public data of the phys_buffer module. The variable pbuf_times is set to $2$ for the eulerian dycore, and to $1$ for the finite volume and semi-Lagrangian dycores.

The output argument index is the index into the buffer array that is used to access the pointer to the field data. Typically a package that is registering a field in the buffer will save this index as module data so that it is readily available. The phys_buffer module also has a query method to obtain the index given the name that was used to register the field. This is how a package that needs fields from another package gains access to them. The interface to the query method pbuf_get_fld_idx is:

function pbuf_get_fld_idx(name)
   character(len=*), intent(in)  :: name   ! field name 
   integer :: pbuf_get_fld_idx

pbuf_get_fld_idx will issue an error message and call endrun if the name is not found in the buffer. The following code illustrates how to access a chunk of a 3D field from the buffer.

subroutine xxx(state, pbuf)   
   use physics_types, only: physics_state
   use phys_buffer,   only: pbuf_size_max, pbuf_fld, pbuf_get_fld_idx
   type(physics_state), intent(in ) :: state                       ! state
   type(pbuf_fld), intent(inout), dimension(pbuf_size_max) :: pbuf ! buffer
   integer :: lchnk    ! local chunk index
   integer :: fld_idx  ! index of field in physics buffer
   real(r8), pointer, dimension(:,:) :: fld  ! pointer to field data

   lchnk = state%lchnk
   fld_idx = pbuf_get_fld_idx('fld_name')
   fld => pbuf(fld_idx)%fld_ptr(1,1:pcols,1:pver,lchnk,1)

The pointer fld can be used just like an array that has been dimensioned (pcols,pver).

The physics buffer also has some methods to facilitate treating the last dimension as a circular buffer when it has been dimensioned with the module variable pbuf_times. The oldest time level is returned by the method pbuf_old_tim_idx. Successively newer time indices in the circular buffer can be obtained by successive calls to pbuf_next_tim_idx which takes an index as an input argument and returns the index which corresponds to the next newer time level.

4.4 Constituents

The constituents module is responsible for managing the names and physical properties of all trace constituents in a model run. It assigns the index values in the constituent arrays, and keeps track of whether or not the initial values of each constituent are to be read from the initial file. The packages that implement constituents (e.g., chemistry packages) are responsible for registering the names and properties of the constituents with the constituents module, which can then make these values known to other packages that require them. The water vapor constituent (Q), which is present in all runs, always corresponds to constituent index 1 in the constituent arrays.

Two classes of transported constituent are supported: advected and non-advected. Both classes undergo the subgrid-scale transports by the column physics parameterizations. Only the advected class undergoes the advective transport forced by the large-scale wind fields. Constituents with very short lifetimes, whose concentrations are determined by chemical equilibrium considerations rather than transport, should not be included in the constituent arrays. This type of constituent should be maintained as private data of the chemistry module and may be stored in the physics buffer if it needs to persist across timesteps.

The model arrays that contain constituent data are organized so that the advected constituents come first, followed by the non-advected constituents. The indices for the advected constituents are 1 through pcnst and the non-advected constituent indices are pcnst+1 through pcnst+pnats.

The array dimension for constituents ppcnst (=pcnst+pnats), along with the parameters pcnst and pnats are public data in the module constituents. Currently the parameters pcnst and pnats are set by the cpp macros PCNST and PNATS during the build process.

The interface for the constituent registration routine is:

subroutine cnst_add(name, type, mw, cp, qmin, ind, longname, readic)
   character(len=*), intent(in) ::&
      name   ! constituent name (8 character max)
   integer, intent(in) ::&
      type   ! flag indicating advected or non-advected constituent
   real(r8), intent(in) ::&
      mw,   &! molecular weight (g/mol)
      cp,   &! isobaric specific heat (J/kg/K)
      qmin   ! global minimum constituent mixing ratio (kg/kg)
   integer, intent(out) ::&
      ind    ! global constituent index (in q array)
   character(len=*), intent(in), optional :: &
      longname  ! value for long_name attribute in netcdf output
                ! (128 char max, defaults to name)
   logical, intent(in), optional :: &
      readic    ! true => read initial values from initial file
                ! (default: true)

The constituents module provides two parameters, advected and nonadvec, for the type flag values that indicate advected and non-advected constituents respectively. Consecutive calls to cnst_add for the same constituent type are guaranteed to assign consecutive global indices. The cnst_add method must be invoked before the model reads the initial conditions file so that the constituent names are available at that time. A physics package that adds constituents may determine whether or not initial values for those constituents should be read from the initial file by an appropriate setting of the readic argument of cnst_add. If this determination is to be made at run time via the setting of namelist variables, the physics package is responsible for managing the namelist variables. This is described in detail in section 5.1.1.

The constituents module provides the constituent names and properties via public data members:

character(len=16), dimension(ppcnst) :: cnst_name ! constituent names
real(r8), dimension(ppcnst) :: &
  cnst_mw,   &! molecular weight (g/mol)
  cnst_cp,   &! specific heat at constant pressure (J/kg/K)
  cnst_cv,   &! specific heat at constant volume (J/kg/K)
  cnst_rgas, &! specific gas constant (J/kg/K)
  qmin        ! global minimum constituent mixing ratio (kg/kg)

Physics packages that need to access particular constituent mixing ratios or other properties must be able to determine the appropriate constituent indices. The constituents module provides a query method cnst_get_ind that returns the global constituent index corresponding to a specified name. If the name is not found then the error handler endrun is called. The interface for cnst_get_ind is:

subroutine cnst_get_ind (name, ind)
   character(len=*), intent(in)  :: name         ! constituent name
   integer,          intent(out) :: cnst_get_ind ! global constituent index

4.5 Time manager

The physics_state structure contains the calendar day representative of the end of the current timestep. Additional information about the time and date of the current model timestep, or methods for performing simple date calculations are obtained from the time_manager module. The time manager also provides an alarm facility (not yet implemented) which may be used by a package to signal that certain actions should be performed at certain timesteps. The alarms are set up during the initialization process, and are queried each timestep. The time_manager module is fully described in [3].

4.6 Reference pressures

Reference pressures at the midpoints and interfaces of the model's vertical layers are available as public data members of module pressure. These members are:

real(r8), dimension(pver) ::&
   prefm,      &! reference pressures at midpoints
   prefd        ! reference pressure layer thickness
real(r8), dimension(pver+1) ::&
   prefi        ! reference pressures at interfaces

next up previous contents
Next: 5 Implementation of a Up: phys-interface Previous: 3 Physics Driver and   Contents
Brian Eaton 2002-09-18