SUBROUTINE CH_VERTAVG(CDBGTYP, pveta, pvtotal, ptop, pbtm, 1,3
     1                    qpeta, knflev, kfirst, plat, klat, pstate,
     1                    knulout,cvar,kgenoper,ktot,kmod,kobstyp)
C
      IMPLICIT NONE
C
C*    Declaration of arguments
C
      CHARACTER*(*) CDBGTYP
      CHARACTER*(*) cvar
      INTEGER knflev,knulout,kfirst,ktot,kgenoper,kmod,klat,kobstyp
      REAL*8 pveta(knflev),pstate(knflev),qpeta(knflev)
      REAL*8 pvtotal,plat
      REAL*8 pbtm,ptop
C
*---------------------------------------------------------------------
#if defined (DOC)
*
***s/r CH_VERTAVG -- Vertical averaging model to calculate partial (or total)
*                    column value of model state profile 'pveta' or used for
*                    adjoint calculations.
*
************************************
*
* NOT YET TESTED/VALIDATED!!!!
*
************************************
*
*Author  :  Y.J. Rochon, ARQX/MSC May 2005
*           - Based on CH_VERTINTG
*Revision:
*
** Purpose: Vertical avg in ln(p) to calculate partial (or total)
*           column value of model state profile 'pveta' or used for adjoint calc..
*           Layer boundaries are taken as mid-point between eta levels in lnP
*           coordinate. 
*
*           Applications:
*
*                  1) KMOD=0; Forward/innovation model: Produce the integral PVTOTAL
*                     given the background state profile PVETA.
*                  2) KMOD=1; Adjoint model: Create PVETA array given PVTOTAL.
*
*Arguments:
*
*  Input    pveta(nvlev)      -- background values at eta levels when kmod=0
*           pvtotal           -- Column amount when kmod=1
*           kmod              -- Flag indicating purpose of call:
*                                0: Use with forward model
*                                1: Use with adjoint of forward model.
*           knvlev            -- # of vertical levels
*           qpeta             -- pressure at eta levels
*           ptop              -- obs top - level pressure (in Pascal)
*           pbtm              -- obs bottom -level pressure (in Pascal)
*           kfirst            -- Initialization flag.
*                                When jfirst=1, calc peta,pres, and vmid
*           plat              -- Latitude of obs. (=ROBHDR(NMCLAT,obsindex)
*           klat              -- Latitude index (=MOBHDR(NCMTLA,obsindex)
*           knulout           -- Output unit index
*           cvar              -- Model variable name
*           pstate(knflev)    -- State profile for possible use in CH_GENOPER
*           CDBGTYP           -- 'HR' for high resolution (trial field) grid
*                                'BG' for low resolution (rebm) grid
*           kobstyp           -- Straight summation if kobstyp=4
*
*  Output   pvtotal           -- partial (or total column) value between
*                                pressure levels ptop and pbtm when kmod=0
*           pveta(knvlev)     -- Array for adjoint of forward model when kmod=1
*           ktot              -- Flag indicating of pvtotal (or pveta) was
*                                correctly produced (1 for yes)
*
*  Local common block
*           qpres             -- pressures at analysis layer boundaries
*           vh                -- Storage array for elements contributing
*                                to the forward model.
*
*Comments:
*
*     1. VH is an intermediate work array used for setting the forward model array ZH.
*
*        Description of i,j in vh(i,j):
*
*             i: eta/analysis level index (index for eta, qpeta and pveta)
*             j: layer index (index for layer between pressures qpres(j) & qpres(j+1))
*
*     2. Analysis layer boundaries set midpoint in alog(p) between analysis levels
*
*        N.B.: exp(0.5*(alog(x)+alog(y)) = sqrt(x*y)
*
*     3. Averaring in alog(P).
*
*---------------------------------------------------------------------
#endif
C
C*    Global variables
C
#include "pardim.cdk"
#include "comdim.cdk"
#include "comdimo.cdk"
#include "comgem.cdk"
#include "comcst.cdk"
#include "comphy.cdk"
#include "comoabdy.cdk"
#include "comoahdr.cdk"
#include "comoba.cdk"
#include "comnumbr.cdk"
#include "cvcord.cdk"
#include "comstate.cdk"
#include "comvarqc.cdk"
#include "comlun.cdk"
#include "commvohr.cdk"
C
C     Common block used only in this routine
C
      INTEGER ivh
      PARAMETER (ivh=2)
      REAL*8 vh(jpnflev,jpnflev)
      REAL*8 qpres(jpnflev+1)
      COMMON /VERTING/ qpres,vh
C
C*    Declaration of local variables
C
      INTEGER J,JK,ILMAX2,ILMIN2
      INTEGER ILMIN, ILMAX
      REAL*8 zet, zp, zp1, zp2, zp3, zr1, zr2, zr3,zsum,zhwhm
      REAL*8 zdumeta,zwin,zh(jpnflev),zhp(jpnflev),zg(jpnflev)
      INTEGER ch_igetmodlev
C
      EXTERNAL ch_igetmodlev
C
C*    Determine P boundaries of analysis layers and save weights for
C     use in setting innovation operator array.
C
C     N.B.: Boundaries of layers set to mid-point
C
      if (kfirst.eq.1) then
C
C        Initialize innovation operator element array to zero
C
         vh(:,:)=0.0D0
C
C        Calculate layer boundaries
C
         qpres(1)=qpeta(1)
         qpres(knflev+1)= qpeta(knflev)
C
         DO JK = 2, KNFLEV
            qpres(jk)=sqrt(qpeta(jk-1)*qpeta(jk))
         END DO
      end if
C
C*    Initialize innovation operator arrays to zero
C
C     ZH:  Initial innovation model array (other than conversion constants)
C     ZHP: Part of innovation operator not related to resolution
C     ZG:  Final innovation operator
C
      zh(:)=0.0D0
      zhp(:)=0.0D0
      zg(:)=0.0D0
C
C*    Verify vertical range
C
      ktot=1
C
      if ((ptop.le.qpeta(1).and.pbtm.le.qpeta(1)).or.ptop.ge.pbtm*0.99.or.
     &    (ptop.ge.qpeta(knflev).and.pbtm.ge.qpeta(knflev))) then
         if (kmod.eq.0) then
            pvtotal=0.0D0
         else
            pveta(:)=0.0D0
         end if
         ktot=0
         return
      end if
C
      if (ptop.le.qpeta(1)*1.01) ptop=qpeta(1)*1.001
      if (pbtm.gt.qpeta(knflev)*0.99) pbtm=qpeta(knflev)
C
C*    Find the range of vertical levels over which to perform the integration
C     and set innovation operator ZH over this range.
C
      ilmin=1
      ilmax=knflev
      if (ptop.le.qpres(1)*1.01.and.pbtm.ge.qpeta(knflev)*0.99) then
C
C        Total column integration part
C
         do j = 1,knflev
            zh(j)=log(qpres(j+1)/qpres(j))
            zhp(j)=1.0
         end do
C
      else
C
C        Partial column integration part (special treatment at boundaries)
C
C        Identify analysis layer boundaries just above and below obs layer.
C
         ilmin = CH_IGETMODLEV(ptop, qpres, 'top', knflev+1)
         ilmax = CH_IGETMODLEV(pbtm, qpres, 'btm', knflev+1)
C
         if (ilmin.eq.ilmax-1) then
C
C           Entire obs layer within one analysis layer
C
            j=ilmin
            if (j.lt.2) j=2
            if (j.gt.knflev-1) j=knflev-1
            zp1=log(qpeta(j-1))
            zp2=log(qpeta(j))
            zp=log(ptop*pbtm)/2.0
            zr1=(zp-zp2)/(zp1-zp2)
            zr2=(zp-zp1)/(zp2-zp1)
C
            zh(j-1)=log(pbtm/ptop)*zr1
            zh(j)=log(pbtm/ptop)*zr2
            zhp(j-1)=zr1
            zhp(j)=zr2
            ilmin=j-1
            ilmax=j
C
         else
C
C           Determine terms from the inner layers (excluding the lower and upper
C           boundary layers when these layers not covering entire analyses layers)
C
            if (pbtm.ge.qpeta(knflev)*0.99) then
               ilmax2=knflev
            else
               ilmax2=ilmax-1
            end if
            if (ptop.le.qpres(1)*1.01) then
               ilmin=1
               ilmin2=ilmin
            else
               ilmin2=ilmin
            end if
            if (ilmin2.le.ilmax2) then
               do j = ilmin2,ilmax2
                  zh(j)=log(qpres(j+1)/qpres(j))
                  zhp(j)=1.0
               end do
            end if
C
C           Determine terms from the lower and upper boundary layers
C           when these layers do not cover entire analyses layers.
C
            if (pbtm.lt.qpeta(knflev)*0.99) then
C
               j=ilmax+1
               if (j.gt.knflev) j=knflev
               if (j.lt.3) j=3
               zp1=log(qpeta(j-2))
               zp2=log(qpeta(j-1))
               zp3=log(qpeta(j))
               zp=log(qpres(ilmax)*pbtm)/2.0
               zr1=(zp-zp2)*(zp-zp3)/(zp1-zp2)/(zp1-zp3)
               zr2=(zp-zp1)*(zp-zp3)/(zp2-zp1)/(zp2-zp3)
               zr3=(zp-zp2)*(zp-zp1)/(zp3-zp2)/(zp3-zp1)
C
               zh(j-2)=zh(j-2)+log(pbtm/qpres(ilmax))*zr1
               zh(j-1)=zh(j-1)+log(pbtm/qpres(ilmax))*zr2
               zh(j)=zh(j)+log(pbtm/qpres(ilmax))*zr3
               zhp(j-2)=zhp(j-2)+zr1
               zhp(j-1)=zhp(j-1)+zr2
               zhp(j)=zhp(j)+zr3
               ilmax=j
C
            end if
C
            if (ptop.gt.qpres(1)*1.01) then
C
               j=ilmin-1
               if (j.lt.1) j=1
               if (j.gt.knflev-2) j=knflev-2
               zp1= log(qpeta(j))
               zp2= log(qpeta(j+1))
               zp3= log(qpeta(j+2))
               zp = log(qpres(ilmin)*ptop)/2.0
               zr1=(zp-zp2)*(zp-zp3)/(zp1-zp2)/(zp1-zp3)
               zr2=(zp-zp1)*(zp-zp3)/(zp2-zp1)/(zp2-zp3)
               zr3=(zp-zp2)*(zp-zp1)/(zp3-zp2)/(zp3-zp1)
C
               zh(j)=zh(j)+log(qpres(ilmin)/ptop)*zr1
               zh(j+1)=zh(j+1)+log(qpres(ilmin)/ptop)*zr2
               zh(j+2)=zh(j+2)+log(qpres(ilmin)/ptop)*zr3
               zhp(j)=zhp(j)+zr1
               zhp(j+1)=zhp(j+1)+zr2
               zhp(j+2)=zhp(j+2)+zr3
               ilmin=j
               if (ilmax.lt.j+2) ilmax=j+2
C
            end if
            if (ilmin.gt.ilmax-2) ilmin=ilmax-2
         end if
      end if
C
      zg(1:knflev)=zh(1:knflev)
      if (kobstyp.eq.4) zg(1:knflev)=zhp(1:knflev)
C      
      if (CDBGTYP.EQ.'BG'.and.kgenoper.eq.1.and.kobstyp.ne.4) then
C
C*       Determine generalized innovation operator.
C        Applicable only to increments.
C
         zwin=0.01
         CALL CH_GENOPER(plat,klat,knulout,qpeta,1,pstate,
     1        cvar,zwin,zh,zhp,zg,knflev)
      end if
C
      if (kmod.eq.0) then
C
C*       Forward model (innovation) calc.
C
         pvtotal=0.0D0
         pvtotal=dot_product(pveta(ilmin:ilmax),zg(ilmin:ilmax))
         if (kobstyp.ne.4) pvtotal=pvtotal/log(pbtm/ptop)
c         DO JK = ilmin,ilmax
c            pvtotal = pvtotal + pveta(JK)*zg(jk)/log(pbtm/ptop)
c         END DO
C
      else
C
C*       Adjoint of forward model calc.
C
         pveta(:)=0.0D0
         pveta(ilmin:ilmax)=pvtotal*zg(ilmin:ilmax)
         if (kobstyp.ne.4) pveta(ilmin:ilmax)=pveta(ilmin:ilmax)/log(pbtm/ptop)

c         DO JK=ilmin,ilmax
c            pveta(jk) = pvtotal*zg(jk)/log(pbtm/ptop)
c         END DO
C
      end if
C
      RETURN
      END