presProfileOperators_mod

link to source code

Dependency Diagrams:

presProfileOperators_mod.svg

Direct Dependency Diagram

presProfileOperators_mod_rev.svg

Reverse Dependency Diagram

Description

MODULE presProfileOperators_mod (prefix=’ppo’ category=’8. Low-level utilities and constants’)

Purpose

Vertical interpolation, integration, and layer averaging subroutines. Includes the special routines designed to interpolate to the (widely spaced) RTTOV pressure levels.

Quick access

Routines

ppo_getlevelindex(), ppo_layeravginterpwgts(), ppo_lintv(), ppo_piecewiselinearwgts(), ppo_sublayerinterpwgts(), ppo_vertavgwgts(), ppo_vertintegwgts(), ppo_vertinterpwgts(), ppo_vertlayerssetup()

Needed modules

  • utilities_mod: MODULE utilities_mod (prefix=’utl’ category=’8. Low-level utilities and constants’)

Variables

Subroutines and functions

subroutine  presprofileoperators_mod/ppo_lintv(pvlev, pvi, kni, knprof, kno, ppo, pvo)
Purpose

To perform the vertical interpolation in log of pressure and constant-value extrapolation of one-dimensional vectors. Input pressure levels can vary for each profile.

Arguments
  • pvlev (kni,knprof) [real ,in] :: Vertical levels, pressure (source)

  • pvi (kni,knprof) [real ,in] :: Vector to be interpolated (source)

  • kni [integer ,in,] :: Number of input levels (source)

  • knprof [integer ,in,] :: Number of profiles

  • kno [integer ,in,] :: Number of output levels (destination)

  • ppo (kno,knprof) [real ,in] :: Vertical levels, pressure (destination)

  • pvo (kno,knprof) [real ,out] :: Interpolated profiles (destination)

Called from

ozo_get_profile()

subroutine  presprofileoperators_mod/ppo_vertinterpwgts(pressinput, presstarget, numinputlevs, numtargetlevs, wgts, kstart, kend[, method_opt[, skiptype_opt[, outbound_opt[, success_opt]]]])
Purpose

Determination of interpolation weights for interpolation to points in a profile. Applies interpolation in log(Pressure).

Input
pressInput

pressure on reference column levels assumed to be in ascending order

pressTarget

target pressure levels assumed to be in ascending order

numInputLevs

number of input/reference levels

numTargetLevs

number of target levels

Options
  • method_opt [character ,in,] ::

    Specified interpolation method :skipType_opt: Skipping processing of specific target levels depending on case:

    ’default’ - extrapolation allowed and skipping application via input success_opt only ‘noExtrap’ - no extrapolation as well as additional skipping via input success_opt ‘doAll&noExtrap’ - no extrapolation only (all other levels processed)

  • skiptype_opt [character ,in,] :: Skipping processing of specific target levels depending on case

Inout

Arguments
  • outbound_opt (numtargetlevs) [integer ,inout,] :: Flag indicating if obs outside model vertical range (0 for no)

  • success_opt (numtargetlevs) [logical ,inout,] :: success of interpolation

  • wgts (numtargetlevs,numinputlevs) [real ,out] :: Averaging weights

  • kstart (numtargetlevs) [integer ,out] :: Index of first relevant original/input level for each target level

  • kend (numtargetlevs) [integer ,out] :: Index of last relevant original/input level for each target level

  • pressinput (numinputlevs) [real ,in] :: pressure on reference column levels assumed in ascending order

  • presstarget (numtargetlevs) [real ,in] :: target pressure levels assumed to be in ascending order

  • numinputlevs [integer ,in,] :: # of original/input vertical levels

  • numtargetlevs [integer ,in,] :: # of target vertical levels

Output

Call to

ppo_piecewiselinearwgts(), ppo_layeravginterpwgts(), utl_abort()

subroutine  presprofileoperators_mod/ppo_piecewiselinearwgts(pvo, pvi, kno, kni, wgts, kstart[, validlevel_opt])
Purpose

To obtain peacewise linear interpolation weigths. Assumes pv*(i) < pv*(i+1). Constant values extrapolation is applied.

Arguments
  • pvo (kno) [real ,in] :: Vertical levels, pressure (destination)

  • pvi (kni) [real ,in] :: Vertical levels, pressure (source)

  • kno [integer ,in,] :: Number of output levels (destination)

  • kni [integer ,in,] :: Number of input levels (source)

  • wgts (kno,2) [real ,out] :: Interpolation weights (destination)

  • kstart (kno) [integer ,out] :: Index i of pvlev level associated to pvo(j,1); pvo(j,2) is for pvlev level i+1

  • validlevel_opt (kno) [logical ,out,]

Called from

ppo_vertinterpwgts()

subroutine  presprofileoperators_mod/ppo_layeravginterpwgts(px1, px2, kn1, kn2, pz, kstart, kend[, pzs1_opt[, pzs2_opt[, pzdps_opt[, rttov_opt[, validlevel_opt]]]]])
Purpose

Determine profile interpolation weights by considering integrations over of series of segments [PX1(KI-1),PX1(KI+1)] using piecewise linear weighting with weights of zero at KI-1 and KI+1 and max weight at KI. KI ranges from 1 to KN1.

Can also provide gradient contributions from both linear and non-linear components of interpolator. The non-linear components (case PZS* is present) stem from vertical coordinate independent variables (e.g. dependency on Ps). The gradients contributions from the linear components are the interpolation weights.

For the interpolation model f(x) where

f(v,x) = F(v)*x

~ F(vo)*xo + F(vo)*(x-xo) + (dF/dv)*xo*(v-vo) = F(vo)*x + (dF/dv)*xo*(v-vo) (eqn 1)

F(vo): array of interpolation weights

= array of gradients from the linear component

(dF/dv)*xo:

array of gradients from linearized component. (dF/dv) or (dF/dv)*(v-vo) provided when pzs* is present

Method:
  • Piecewise weighted interpolation in ln(P).

  • Journal reference: Rochon, Y.J., L. Garand, D.S. Turner, and S. Polavarapu. Jacobian mapping between coordinate systems in data assimilation, Q. J. of the Royal Met. Soc., vol 133, 1547-1558, 2007. (www.interscience.wiley.com) DOI:10.1002/qj.117

    URL: http://www3.interscience.wiley.com/cgi-bin/fulltext/116320452/PDFSTART

Comments

Assumption: PX1(i)<PX1(i+1) & PX2(i)<PX2(i+1)

  1. The input profile is now extrapolated at constant value.

The impact is of most practical significance for instruments where the weighting function peaks at or near the surface such as SSMI.

This approach increases the weights of contribution from the lowest and highest input domain levels for output layers intersecting these input domain boundaries. It consists of applying contant value extrapolation by introducing ‘fake’ or ‘virtual’ layers. For the lowest level of the input domain, as example, this implies creating a virtual surface layer which extends to the lower boundary of the output domain layer which contains the input domain surface. This increases the contributing weight of the surface which would be otherwise understimated in the original code due to the interpolator actually doing piecewise weighted averaging.

  1. COmment out use of ‘zb’ for consistency with RTTOV-9 when

Options

rttov_opt [logical ,in,] ::

Commented out use of ‘zb’ when .true. for consistency with RTTOV-9 See the four lines ending with !C1 and version 7 comment above.

3) A major reduction in computational time results from only assigning values to the non-zero ranges of the 2D output arrays. These ranges of the 2D areas are identified by ‘kstart’ and ‘kend’. Initialization to zero for values within these ranges is done using 1D work arrays ‘zpz’ and ‘zpzd’, with the resulting values then being assigned to the related elements of ‘PZ’ and ‘PZDPS’.

Therefore, elements of ‘PZ’ and ‘PZDPS’ outside these ranges could be undefined (i.e. NaN if not 0.0) and should not be used.

Other notable reductions in computational time stem (a) from inlining of ‘sublayer’ code (applied to a reduced degree in ‘layeravg’ as compared to ‘rttov_layeravg_*) and (b) from updating the start position ‘istart’ of the loops over J. The latter was faciliated by moving the loop over KI inside ‘layeravg’.

These improvements were originally devised and implemented by Deborah Salmond and Mats Hamrud (ECMWF) in the RTTOV-9 routines ‘rttov_layeravg*’.

4) Contributors to improvements and changes to the original version of ‘layeravg’ and to ‘rttov_layeravg*’: members of the RTTOV9 development team, namely Niels Bormann, Alan Geer, Deborah Salmond, and Mats Hamrud of ECMWF, Peter Rayer and Roger Saunders of the Met Office and Pascal Brunel of Meteo-France, and Y.J. Rochon (EC).

Arguments
  • px1 (kn1) [real ,in] :: Levels of output domain (e.g. lnP; in increasing values)

  • px2 (kn2) [real ,in] :: Levels of input domain (e.g. lnP; in increasing values)

  • kn1 [integer ,in,] :: Dimension of PX1

  • kn2 [integer ,in,] :: Dimension of other arrays

  • pz (kn1,kn2) [real ,out] :: Resultant accumulated weighting factors for interp from input to output domain

  • kstart (kn1) [integer ,out] :: Start index for relevant PZ row

  • kend (kn1) [integer ,out] :: End index of relevant PZ row

  • pzs1_opt (kn1) [real ,in,] :: dPX1/dv or perturbation dPX1/dv * delta(v) where PX1(v), e.g. v=Ps

  • pzs2_opt (kn2) [real ,in,] :: dPX2/dv or perturbation dPX2/dv * delta(v) where PX2(v), e.g. v=Ps

  • pzdps_opt (kn1,kn2) [real ,out,] :: dF/dv or perturbations (dF/dv)*(v-vo): Resultant accumulated factors for the gradients w.r.t. v (or perturbations) associated to coordinates

  • validlevel_opt (kn1) [logical ,in,] :: Logical indicating validity of each output level

Called from

ppo_vertinterpwgts()

Call to

ppo_sublayerinterpwgts()

subroutine  presprofileoperators_mod/ppo_sublayerinterpwgts(z1, z2, dzd, wgt1, wgt2, x1, x2, dxd, w1, w2, pzs1, pzs2, pxs1, pxs2, wps1, wps2, lgradpx, lgradpz)
Purpose

Determine weight coefficient contributions to w1 and w2 to assign to input domain (e.g. NWP model) variables at x1 and x2. Weights are determined from integration over the intersecting segment (y1,y2) of the ranges (x1,x2) for the input domain and (z1,z2) for the output domain. Integrals are approximated via the trapezoidal rule:

integral of f(x)=w(x)*t(x) from y1 to y2

= (f(y1)+f(y2))/2*(y2-y1) = w(y1)*t(y1)+w(y2)*t(y2) = w1*t(x1)+w2*t(x2) = w1*t1+w2*t2

This is synonomous to having an integrand linear in x.

In the above (and below) equation(s), w1 and w2 are contributions to the input values.

The weights for linearized contributions of non-linear interpolator components, i.e. gradient w.r.t. the vertical coordinate independent variable (e.g. v*=Ps), are calculated when LGRADP* is .true.:

pzps = pzps + (df/dx1)*(dx1/dvx1)+(df/dx2)*(dx2/dvx2)
  • (df/dz1)*(dz1/dvz1)+(df/dz2)*(dz2/dvz2)

= pzpz + (dw1/dx1*t1+dw2/dx1*t2)*pxs1
  • (dw1/dx2*t1+dw2/dx2*t2)*pxs2

  • (dw1/dz1*t1+dw2/dz1*t2)*pzs1

  • (dw1/dz2*t1+dw2/dz2*t2)*pzs2

This routine provides terms on the right-hand-side.

Note: pxs* and pzs* can be provided either as gradients or perturbations.

Method: - Piecewise weighted interpolation in ln(P). - Journal reference:

Rochon, Y.J., L. Garand, D.S. Turner, and S. Polavarapu. Jacobian mapping between coordinate systems in data assimilation, Q. J. of the Royal Met. Soc., vol 133, 1547-1558, 2007. (www.interscience.wiley.com) DOI:10.1002/qj.117

URL: http://www3.interscience.wiley.com/cgi-bin/fulltext/116320452/PDFSTART

Comments

Assumptions:

  1. x1<x2

  2. z1<z2

3) The ranges (z1,z2) and (x1,x2) overlap. The overlap region will be identified as (y1,y2) with y1<y2.

1) w(y1) and w(y2) are obtained by linear interpolation of the linear weighting function w with w(z1)=wgt1 and w(z2)=wgt2.

2) The w1 and w2 above are determined by expanding t(y1) and t(y2) as linear functions of t(x1)=t1 and t(x2)=t2.

  1. The factor of 1/2 in

    (f(y1)+f(y2))/2*(y2-y1)

    = w(y1)*t(y1)+w(y2)*t(y2)

is omitted as normalization is performed in the calling routine LAYERAVG.

4) The code version of the interpolator part of ‘int_sublayerInterpWgts’ provided for RTTOV-9 assumed the following conditions:

(wgt1,wgt2)=(0,1), d1=(y1-x1)=0 from y1=x1 or

wy1=0 from wgt1=0 and y1=z1,

or

(wgt1,wgt2)=(1,0), d2=(y2-x2)=0 when y2=x2 or

wy2=0 from wgt2=0 and y2=z2

and took account of the implications on d* and wy*.

The version presented here has each step accompanied by related equations. It does not assume the above restrictions on

Arguments
  • wgt1 [real ,in] ::

    Weight at z1 (0.0 or 1.0 or …) comments section of the RTTOV-9 module ‘rttov_sublayer’.

    5) When LGRADP*=.true., this routine provides terms needed for the gradients w.r.t.the vertical coordinate independent variable, e.g. Ps.

  • z1 [real ,in] :: Upper level of output domain half-layer (z1<z2)

  • z2 [real ,in] :: Lower level of output domain half-layer

  • dzd [real ,in] :: 1.0/(z2-z1)=1.0/dz

  • wgt2 [real ,in] :: Weight at z2 (1.0 or 0.0 or …)

  • x1 [real ,in] :: Upper boundary of input layer (x1<x2)

  • x2 [real ,in] :: Lower boundary of input layer

  • dxd [real ,in] :: 1.0/(x2-x1)=1.0/dx

  • w1 [real ,inout] :: Starting (in) and updated (out) weight assigned to variable at upper level x1

  • w2 [real ,inout] :: Starting (in) and updated (out) weight assigned to variable at upper level x2

  • pzs1 [real ,in] :: dz1/dvz or perturbation dz1/dvz * delta(vz)

  • pzs2 [real ,in] :: dz2/dvz or perturbation dz2/dvz * delta(vz)

  • pxs1 [real ,in] :: dx1/dvx or perturbation dx1/dvx * delta(vx) (required when LGRADPx=.true.)

  • pxs2 [real ,in] :: dx2/dvx or perturbation dx2/dvx * delta(vx)

  • wps1 [real ,inout] :: Starting (in) and updated (out) value of (pxs1*dw1/dx1 + pxs2*dw1/dx2 +pzs1*dw1/dz1 + pzs2*dw1/dz2)

  • wps2 [real ,inout] :: Starting (in) and updated (out) value of pxs1*dw2/dx1 + pxs2*dw2/dx2 +pzs1*dw2/dz1 + pzs2*dw2/dz2) (required when LGRADP*=.true.)

  • lgradpx [logical ,in] :: Input domain logical indicating if gradient w.r.t. vertical coordinate independent variable if required i.e. d/dv where P(v) (e.g. v=Ps).

  • lgradpz [logical ,in] :: Output domain logical indicating if gradient w.r.t. vertical coordinate independent variable if required i.e. d/dv where P(v) (e.g. v=Ps).

Called from

ppo_layeravginterpwgts()

Call to

utl_abort()

subroutine  presprofileoperators_mod/ppo_vertlayerssetup(operatortype, pressinput, numinputlevs)
Purpose

Preliminary calculations for producing components required for vertical integration (or averaging) w.r.t. pressure for the full vertical rangeor a set of target layers. To be called before routine ppo_vertIntegWgts or ppo_vertAvgWgts.

Integration calculations are performed appling quadratic interpolation in P between level.

Input
operatorType

‘integ’ for intergration; ‘avg’ for averaging

pressInput

Reference input levels

numInputLevs

# of model vertical levels

Output
boundaries(numInputLevs+1)

Input layer boundaries assuming provided input levels can be taken as mid-layer values.

weights

Second order Lagrangian interp integration weights or unity for averaging weights

Comments
  • This subroutine does the following:

    • Setting of layer boundaries

    • If integration, determining integration weights associated to second order Lagrangian interpolation. Otherwise, initialize weights to unity.

  • Layer boundaries are taken as mid-point between provided levels in lnP coordinate. Layer values are set to be the values interpolated to the mid-point in P within the various layers. Interpolation in P is done quadratically.

Arguments
  • operatortype [character ,in] :: ‘integ’ for integration; ‘avg’ for averaging

  • pressinput (numinputlevs) [real ,in] :: Reference input levels

  • numinputlevs [integer ,in,] :: # of model vertical levels

subroutine  presprofileoperators_mod/ppo_vertintegwgts(targetlayerstop, targetlayersbot, numinputlevs, numtargetlevs, kstart, kend, wgts[, wgts_opt[, skiptype_opt[, outbound_opt[, success_opt[, dealloc_opt]]]]])
Purpose

To calculate integration weights “wgts” required for vertical integration w.r.t. pressure for the full vertical range or a set of target layers. Given the calculated weights and a user intergrand array vector X, the integral for a given layer i would be given by sum(wgts(i,:)*X(:))

Integration calculations are performed applying quadratic interpolation in P between level.

Routine ppo_vertLayersSetup to be called beforehand to generate Lagrangian weights and related layer boundaries (arrays ‘weights’ and ‘boundaries’)

Input
targetLayersTop

top of target layers

targetLayersBot

bottom of target layers

numInputLevs

# of original/input vertical levels

numTargetLevs

# of target vertical levels

Arguments
  • kstart (numtargetlevs) [integer ,inout] :: Index of first relevant original/input level for each target level

  • kend (numtargetlevs) [integer ,inout] ::

    Index of last relevant original/input level for each target level

    If kstart and kend are non-zero on input, the input are initial estimates of the values.

    weights

    See routine ppo_vertLayersSetup

    boundaries

    Boundaries of input layers

    skipType_opt

    Skipping processing of specific target layers depending on case: ‘default’ - skipping application via input success_opt only ‘doAll&noExtrap’ - application of both success_opt and outbound_opt

  • outbound_opt (numtargetlevs) [integer ,inout,] :: Flag indicating if obs outside input vertical range (0 for no)

  • success_opt (numtargetlevs) [logical ,inout,] :: success of interpolation

  • wgts (numtargetlevs,numinputlevs) [real ,out] :: Averaging weights

  • wgts_opt (numtargetlevs,numinputlevs) [real ,out,] :: Part of averaging weights not related to resolution

  • targetlayerstop (numtargetlevs) [real ,in] :: top of target layers

  • targetlayersbot (numtargetlevs) [real ,in] :: bottom of target layers

  • numinputlevs [integer ,in] :: # of original/input vertical levels

  • numtargetlevs [integer ,in,] :: # of target vertical levels

Options
  • dealloc_opt [logical ,in,] :: Logical indicating if deallocation is desired when done

  • skiptype_opt [character ,in,] :: Skipping processing of specific target layers depending on case

Output

Call to

ppo_getlevelindex()

function  presprofileoperators_mod/ppo_getlevelindex(level, layerboundarylevels, topbtm, numboundaries)
Purpose

To get the vertical input level index for level within target layer and nearest specified layer boundary.

Arguments
  • level [real ,in] :: Target layer index

  • layerboundarylevels (numboundaries) [real ,in] :: Layer boundaries

  • topbtm [character ,in] :: indicating whether we are looking for top or bottom level

  • numboundaries [integer ,in,] :: Number of layer boundaries

Return

ppo_getlevelindex [integer ]

Called from

ppo_vertintegwgts(), ppo_vertavgwgts()

subroutine  presprofileoperators_mod/ppo_vertavgwgts(targetlayerstop, targetlayersbot, numinputlevs, numtargetlevs, kstart, kend, wgts[, wgts_opt[, skiptype_opt[, outbound_opt[, success_opt[, dealloc_opt]]]]])
Purpose

To calculate averaging weights “wgts” required for vertical averaging w.r.t. ln(pressure) for the full vertical range or a set of target layers. Given the calculated weights and a user input array vector X, the average for a given layer i would be given by sum(wgts(i,:)*X(:))

Routine ppo_vertLayersSetup to be called beforehand to initial weigths and related layer boundaries (arrays ‘weights’ and ‘boundaries’)

Input
targetLayersTop

top of target layers

targetLayersBot

bottom of target layers

numInputLevs

# of original/input vertical levels

numTargetLevs

# of target vertical levels

Arguments
  • kstart (numtargetlevs) [integer ,inout] :: Index of first relevant original/input level for each target level

  • kend (numtargetlevs) [integer ,inout] ::

    Index of last relevant original/input level for each target level

    If kstart and kend are non-zero on input, the input are initial estimates of the values.

    weights

    See routine ppo_vertLayersSetup

    boundaries

    Boundaries of input layers

    skipType_opt

    Skipping processing of specific target layers depending on case: ‘default’ - skipping application via input success_opt only ‘doAll&noExtrap’ - application of both success_opt and outbound_opt

  • outbound_opt (numtargetlevs) [integer ,inout,] :: Flag indicating if obs outside input vertical range (0 for no)

  • success_opt (numtargetlevs) [logical ,inout,] :: success of interpolation

  • wgts (numtargetlevs,numinputlevs) [real ,out] :: Averaging weights

  • wgts_opt (numtargetlevs,numinputlevs) [real ,out,] :: Part of averaging weights not related to resolution

  • targetlayerstop (numtargetlevs) [real ,in] :: top of target layers

  • targetlayersbot (numtargetlevs) [real ,in] :: bottom of target layers

  • numinputlevs [integer ,in] :: # of original/input vertical levels

  • numtargetlevs [integer ,in,] :: # of target vertical levels

Options
  • dealloc_opt [logical ,in,] :: Logical indicating if deallocation is desired when done

  • skiptype_opt [character ,in,] :: Skipping processing of specific target layers depending on case

Output

Call to

ppo_getlevelindex()