SUBROUTINE CH_oda_HTtr,8
C
      IMPLICIT NONE
C
C
*---------------------------------------------------------
#if defined (DOC)
*
***s/r CH_oda_HTtr - Apply adjoint of forward models (or TLM) for constituent obs
*                   for use in calculating the gradient of Jo
*
*Author  : Y.J. Rochon and Y. Yang, AQRB/MSC, July 2005
*          (original module name: ch_adjoint)
*
*Revision:
*          Y.J. Rochon, ARQX/EC, Feb 2007
*                - Addition of SUM(MOBDATA(NCMASS,IDATA:IDATEND)).NE.0 condition
*                  and IREJECT flag.
*          Y.J. Rochon ARQX, June 2008
*                - Addition of Doppler wind operator CH_DOPWIND
*                  (iobsnmb.eq.nvnumb(58))
*          Y.J. Rochon ARQX Aug 2010
*                - Added possible use of avg kernel matrices
*                - Reset ZVAR to ROBDATA8(NCMOMI,*) as done in other
*                  oda_HT* modules
*          Y.J. Rochon ARQI Feb 2013
*                - Added iobstyp=4 option
**
*    -------------------
*
**    Purpose: Apply adjoint of forward models (or TLM) for constituent obs
*              for use in calculating the gradient of Jo. Required output
*              is an updated GOMOBS field. 
*
*Arguments:
*
*  Input:
*                
*  Other:
*                  
*     IOBSTYP......Flag for observation handling and forward/adjoint 
*                  model selection. Provided by MOBHDR(NCMCORD1, IOBS).
*                  Set in CH_OBSTYP called by CH_RBBRPDATA.
*                  1:  Observation to be treated as point by point
*                      profile
*                  2:  Observation to be treated as piecewise
*                      constant profile (layer averages).
*                  3:  Observation to be treated as total or
*                      partial column amounts
*                  4:  Observation to be treated as piecewise sum
*
*Comments:
*
*-----------------------------------------------------------
#endif
C
C*    Global variables
C
#include "pardim.cdk"
#include "comdim.cdk"
#include "comdimo.cdk"
#include "comgem.cdk"
#include "comnumbr.cdk"
#include "comoabdy.cdk"
#include "comoahdr.cdk"
#include "comoba.cdk"
#include "comchem.cdk"
#include "comstate.cdk"
#include "commvo.cdk"
#include "commvo1.cdk"
#include "commvog.cdk"
#include "commvohr.cdk"
#include "comcst.cdk"
#include "cvcord.cdk"
#include "comlun.cdk"
#include "cparbrp.cdk"
C
      integer istart
      common /istart/istart
C
C*    Declaration of local variables
C
      INTEGER IOBS,IPOS,I1,I2
      INTEGER JDATA,J,IBEGIN,ILAST
      INTEGER IOBSNMB, IOBSTYP,IOBSLEV,IIFLAG
      INTEGER JOBS, IDATA, IDATEND,J1
      INTEGER IBEGIN1, ILAST1
      INTEGER JL,JLT,ILAT
      REAL*8 ZLAT
      INTEGER IDIM
      PARAMETER (IDIM=500)  ! Must be >= NFLEV
      REAL*8 ZOBSLEV(IDIM),ZOBSLEV2(IDIM),zvar(IDIM),zwork(IDIM)
      REAL*8 ZSTATE(nflev),ZVTR(IDIM),ZPRESS(NFLEV),ZTEMP(NFLEV)
      REAL*8 ZVTR2(IDIM),ZVAR2(IDIM), ZWORK2(IDIM)
      INTEGER INUM,INUMS
      INTEGER ITRCODE,IREJECT,IKERN
      INTEGER CH_KGETPOS
C
      EXTERNAL CH_KGETPOS
C
C     Initialization
C
      istart=0
C
C*    Loop over obs familes.
C
      DO J=1,NFILES
C
C       Check for target family
C          
        IF (CFAMTYP(J).EQ.'TR'.AND.NBEGINTYP(J).GT.0.AND.
     1        NENDTYP(J).GE.NBEGINTYP(J)) THEN
C
C         Identify range of observation reports
C
          IBEGIN=NBEGINTYP(J)
          ILAST=NENDTYP(J)
          IBEGIN1 = MOBDATA(NCMOBS,IBEGIN)
          ILAST1  = MOBDATA(NCMOBS,ILAST)
C
C         Loop over obs reports in a subfamily
C
          DO JOBS = IBEGIN1, ILAST1
C
C           Loop over obs in a report (normally only one obs in a report).
C
            INUM=MOBHDR(NCMNUM,JOBS)
            INUMS=MOBHDR(NCMNLV,JOBS)
            DO J1=1,INUM
C
C              Identify range of elements for an obs in the report
C
               IF (J1.EQ.1) THEN
                  IDATA   = MOBHDR(NCMRLN,JOBS)
                  IF (INUM.GT.1) INUMS=MOBDATA(NCMNUM1,IDATA)
                  IDATEND = INUMS + IDATA - 1
               ELSE
                  IDATA=IDATA+INUMS
                  IF (INUM.GT.1) INUMS=MOBDATA(NCMNUM1,IDATA)
                  IDATEND=INUMS+IDATA-1
               END IF   
C
C              Check observation vertical coordinate and convert
C              to pressure when necessary.
C
               CALL CH_VOBS_TO_P(NULOUT,JOBS,ZOBSLEV,ZOBSLEV2,
     1                IDATA,IDATEND,IOBSLEV,IDIM,IIFLAG)
               IF (IIFLAG.NE.0.OR.IOBSLEV.NE.INUMS) THEN
                  write(nulout,*) 'CH_oda_HTtr: Level inconsistency.'
                  CYCLE
               END IF
C
C              Obtain obs type to identify appropriate adjoint model.
C
               IOBSTYP  = MOBDATA(NCMCORD1,IDATA)
               IF (IOBSTYP.NE.1.AND.IOBSTYP.NE.2.AND.
     &             IOBSTYP.NE.3.AND.IOBSTYP.NE.4) CYCLE  
C
C              Obtain latitude of obs report
C         
               ZLAT=ROBHDR(NCMLAT,JOBS)
               ILAT=MOBHDR(NCMTLA,JOBS)
C     
               IOBSNMB = MOBDATA(NCMVNM,IDATA)
               IOBS = MOBDATA(NCMOBS,IDATA)
               IPOS = MOBDATA(NCMPOS,IDATA)
               ITRCODE = MOBDATA(NCMSPEC,IDATA)
C
               JLT = CH_KGETPOS(IOBSNMB, ITRCODE,CSTNID(JOBS))
               IF (JLT .LT. 0) THEN
                 write(nulout, *)' Species ', IOBSNMB, '  not to be assimilated!'
                 write(nulout,*) ITRCODE,CSTNID(JOBS),JOBS
                 CYCLE
               ENDIF
C
C*             Identify background/increment arrays at obs lat/long location
C               
               I1=1+IPOS*NFLEV
               I2=NFLEV+IPOS*NFLEV
               zstate(1:NFLEV)=GOMOBSG(I1:I2,iobs)
               ztemp(1:NFLEV)=GOMTG(1:NFLEV,IOBS)
               zpress(1:NFLEV)=RPPOBS(1:NFLEV,IOBS)
C
C*             Store required obs/sigma array at obs location.
C
c               zvar(1:inums) = ROBDATA8(NCMOMN,IDATA:IDATEND)
c     &                          /ROBDATA8(NCMOER,IDATA:IDATEND)
               zvar(1:inums)=ROBDATA8(NCMOMI,IDATA:IDATEND)
               
               zwork(1:NFLEV)=0.0D0
               zwork2(1:NFLEV)=0.0D0
C
               IREJECT=1
               IF (SUM(MOBDATA(NCMASS,IDATA:IDATEND)).NE.0) THEN
C
C*                Apply unit conversion and variable transformations to zstate
C                 (if required) when adjoint/TLM depend on the state.
C
                  IREJECT=0
                  zwork(1:NFLEV)=0.0D0
                  CALL CH_CONVERT(IOBSNMB,ITRCODE,speciesm(jlt),
     &                 CNAMANAL(JLT),ZWORK,ZSTATE,ZTEMP,ZPRESS,NFLEV,
     &                 'BG',0,NLOGTR,IREJECT)
                  zwork(1:NFLEV)=0.0D0 
               END IF  
               IF (IREJECT.EQ.1) CYCLE           
C
C*             If not rejected, select and apply adjoint of TLM.
C              for obs profile (with all elements at same lat/long)
C
C*             Application of adjoint of obs averaging kernel matrix
C              multiplication.
C
               IKERN=0
               IF (MOBHDR(NCMKER,JOBS).gt.0) IKERN=MOBHDR(NCMKER,JOBS)-INUM+J1
C
               If (iobstyp.eq.1) then
C
C                 Point profiles.
C
                  if (iobsnmb.eq.nvnumb(58)) then
C
C                    Doppler wind measurement
C
                     CALL CH_DOPWIND(MOBDATA(NCMASS,IDATA:IDATEND),
     &                          MOBDATA(NCMXTR,IDATA:IDATEND),
     &                          ROBDATA(NCMLYR,IDATA:IDATEND),INUMS,
     &                          NFLEV,ZOBSLEV,ZPRESS,ZVAR,ZVAR2,
     &                          ROBDATA(NCMDWN,IDATA:IDATEND),
     &                          ZWORK,ZWORK2,1,IDIM)
C
                  else 
C
                     CALL CH_VPROF(MOBDATA(NCMASS,IDATA:IDATEND),
     &                          MOBDATA(NCMXTR,IDATA:IDATEND),
     &                          ROBDATA(NCMLYR,IDATA:IDATEND),INUMS,
     &                          NFLEV,ZOBSLEV,ZPRESS,ZVAR,
     &                          ZWORK,1,IDIM,IKERN)  
                  end if
C
               ELSE IF (iobstyp.eq.2.or.iobstyp.eq.4) then
C
C                 Layer average observation elements. 
C
                  CALL CH_VAVG(INUMS,MOBDATA(NCMASS,IDATA:IDATEND),
     &                         MOBDATA(NCMXTR,IDATA:IDATEND),
     &                         ZVAR,ZWORK,'BG',zvtr,zobslev,zobslev2,
     &                         zpress,nflev,zlat,ilat,zstate,
     &                         CNAMANAL(JLT),1,iobstyp)
C
               ELSE IF (iobstyp.eq.3) then
C
C                 Total or partial column amounts.
C
                  CALL CH_VCOLM(INUMS,MOBDATA(NCMASS,IDATA:IDATEND),
     &                          MOBDATA(NCMXTR,IDATA:IDATEND),
     &                          ZVAR,ZWORK,'BG',zvtr,zobslev,zobslev2,
     &                          zpress,nflev,zlat,ilat,zstate,
     &                          CSTNID(JOBS),CNAMANAL(JLT),1,IKERN)
C
               END IF
C
C*             Apply adjoint of unit conversion and variable
C              transformations. (Assumed not needed for ZWORK2)
C
               CALL CH_CONVERT(IOBSNMB,ITRCODE,speciesm(jlt),
     &                 CNAMANAL(JLT),ZWORK,ZSTATE,ZTEMP,ZPRESS,
     &                 NFLEV,'BG',1,NLOGTR,IREJECT) 
C 
               GOMOBS(I1:I2,IOBS)=GOMOBS(I1:I2,IOBS)+ZWORK(1:NFLEV)
               if (iobsnmb.eq.nvnumb(58)) GOMOBS(I1+NFLEV:I2+NFLEV,IOBS)=
     &                GOMOBS(I1+NFLEV:I2+NFLEV,IOBS)+ZWORK2(1:NFLEV)
C
            END DO ! (J1)
          END DO ! (JOBS)
        ENDIF
      END DO ! (NFILES)
C
      RETURN
      END