SUBROUTINE CH_oda_Htr(CDBGTYP),7
C
IMPLICIT NONE
C
C* Declaration of arguments
C
CHARACTER*(*) CDBGTYP
C
*---------------------------------------------------------
#if defined (DOC)
*
***s/r CH_JOCALC - Computation of Jo contribution and the residuals
* for all observations of the TR (constituents) family.
*
*Author : Y. J. Rochon and Y. Yang, AQRB/MSC, July 2005
* Original module name: ch_jocalc
*
*Revision:
* Y.J. Rochon, ARQX/EC, Feb 2007
* - Addition of IREJECT flag and
* SUM(MOBDATA(NCMASS,IDATA:IDATEND)).NE.0 condition
* - Added option of applying day/night/near-terminator
* obs acceptance criteria
* Y.J. Rochon ARQX, Apr 2008
* - Addition of obs simulation option with LSIMOB=.TRUE.
* 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
* Y.J. Rochon ARQI Feb 2013
* - Added iobstyp=4 option
*
* -------------------
*
** Purpose: Computation of Jo contributions and the residuals
* for all observations of the TR (constituents) family.
*
*Arguments:
*
* INPUT
*
* CDBGTYP: 'HR' for high resolution (trial field) grid (for gom*hr)
* 'BG' for low resolution (rebm) grid
*
* OUTPUT
*
*
* OTHER:
*
* IOBSTYP......Flag for observation handling and forward model selection.
* defined 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:
*
*
* 1) This routine must be quasi-identical to CH_SETFGE.
* When the call to a new TLM is added to CH_JOCALC,
* then it should also be added to CH_SETFGE.
*
* 2) Other output: ROBDATA8(NCMOMN,*), ROBDATA8(NCMOMA,*),
* ROBDATA8(NCMOMI,*), and updated MOBDATA(NCMASS,*)
* and MOBDATA(NCMXTR,*)
*
*-----------------------------------------------------------
#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 "commvog.cdk"
#include "commvohr.cdk"
#include "comcst.cdk"
#include "comct0.cdk"
#include "comvarqc.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,ILMAX,ILAT
INTEGER IDIM
PARAMETER (IDIM=500) ! Must be >= JPNFLEV
REAL*8 ZOBSLEV(IDIM),ZOBSLEV2(IDIM),ZTRIAL(IDIM)
REAL*8 ZLAT,ZSTATE(JPNFLEV),ZVTR(IDIM),ZLON,ZTODEG
REAL*8 ZPRESS(JPNFLEV),ZTEMP(JPNFLEV),ZALT(JPNFLEV)
REAL*8 ZVTR2(IDIM),ZTRIAL2(IDIM),ZOER,ZDUM(JPNFLEV)
INTEGER ITRCODE,ICOND(IDIM)
INTEGER IC,INUMS,INUM,IREJECT,IKERN
INTEGER CH_KGETPOS
C
EXTERNAL CH_KGETPOS
C
C Note on loops:
C
C J: 1 to NFILES : Obs family counter for CMA data arrays
C JOBS: IBEGIN1 to ILAST1 : Obs report counter within family
C J1: 1 to INUM : Obs (profile) counter within report
C INUM=1 for report with single obs profile.
C
C One obs can consist of one or more obs elements.
C
C* Initialization
C
istart=0
ZTODEG=180./RPI
C
C* Number of background/increment vertical levels
C
ILMAX = NFLEV
IF (CDBGTYP.eq.'HR'.or.CDBGTYP.eq.'hr') ILMAX=NLEVTRL
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 (profiles) 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_Htr: Level inconsistency.'
CYCLE
END IF
C
C Obtain obs type to identify appropriate forward model (or TLM).
C
IOBSTYP = MOBDATA(NCMCORD1,IDATA)
C
IF (IOBSTYP.NE.1.AND.IOBSTYP.NE.2.AND.
& IOBSTYP.NE.3.AND.IOBSTYP.NE.4) CYCLE
C
C Obtain latitude and longitude of obs report
C
ZLAT=ROBHDR(NCMLAT,JOBS)
ILAT=MOBHDR(NCMTLA,JOBS)
ZLON=ROBHDR(NCMLON,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
END IF
C
C* Identify background/increment arrays at obs lat/long location
C
ZSTATE(1:ILMAX)=0.0
I1=1+IPOS*ILMAX
I2=ILMAX+IPOS*ILMAX
if (CDBGTYP .eq. 'HR' .or. CDBGTYP .eq. 'hr') then
zvtr(1:ILMAX) = GOMOBSHR(I1:I2,iobs)
if (iobsnmb.eq.nvnumb(58)) zvtr2(1:ILMAX) =
& GOMOBSHR(I1+ILMAX:I2+ILMAX,iobs)
ztemp(1:ILMAX)=GOMTHR(1:ILMAX,IOBS)
zpress(1:ILMAX)=RPPOBSHR(1:ILMAX,IOBS)
else
zvtr(1:ILMAX) = GOMOBS(I1:I2,iobs)
if (iobsnmb.eq.nvnumb(58)) zvtr2(1:ILMAX) =
& GOMOBS(I1+ILMAX:I2+ILMAX,iobs)
zstate(1:ILMAX)=GOMOBSG(I1:I2,iobs)
ztemp(1:ILMAX)=GOMTG(1:ILMAX,IOBS)
zpress(1:ILMAX)=RPPOBS(1:ILMAX,IOBS)
end if
C
C* Initialize ROBDATA8 to zero at obs location
C
ROBDATA8(NCMOMA,IDATA:IDATEND)=0.0D0
ZTRIAL(1:INUMS)=0.0D0
ZTRIAL2(1:INUMS)=0.0D0
C
IREJECT=1
IF (SUM(MOBDATA(NCMASS,IDATA:IDATEND)).NE.0) THEN
C
IREJECT=0
C
C Apply day/night/near-terminator criterion if requested
C For acceptance, point must be either under day or
C night condition for both the obs time and analysis
C time.
C
IF (daynightp(jlt).gt.0.0.and.
& (CDBGTYP.EQ.'HR'.or.CDBGTYP.EQ.'hr')) THEN
C
IF (MOBDATA(NCMVCO,IDATA).NE.0) THEN
IF (MOBDATA(NCMVCO,IDATA).EQ.2) THEN
ZALT(:)=-1.0 ! Obs coord. not altitude
ELSE
C Obs vert. coord. is altitude (m)
ZALT(1:INUMS)=
& ROBDATA8(NCMPPP,IDATA:IDATEND)
END IF
call ch_termcond(zlat*ztodeg,zlon*ztodeg,
& MOBHDR(NCMDAT,JOBS),MOBHDR(NCMETM,JOBS),
& INUMS,ZOBSLEV,ZALT,daynightp(jlt),
& zpress(1:ILMAX),
& GOMGZHR(1:ILMAX,IOBS)/RG,
& ILMAX,NULOUT,ICOND)
WHERE (ICOND(1:INUMS).EQ.0)
MOBDATA(NCMASS,IDATA:IDATEND)=0
MOBDATA(NCMFLG,IDATA:IDATEND)=
& MOBDATA(NCMFLG,IDATA:IDATEND)+131072+512
C ! Same flag as for QCvar rejection
ENDWHERE
IF (SUM(MOBDATA(NCMASS,IDATA:IDATEND)).EQ.0)
& IREJECT=1
END IF
END IF
C
C Apply unit conversion factor and variable
C transformations to ensure consistency of F(x)/Hx units
C with obs units.
C
IF (IREJECT.EQ.0) THEN
CALL CH_CONVERT
(IOBSNMB,ITRCODE,speciesm(jlt),
& CNAMANAL(JLT),ZVTR,ZSTATE,ZTEMP,ZPRESS,ILMAX,
& CDBGTYP,0,NLOGTR,IREJECT)
IF (IREJECT.EQ.1) THEN
WRITE(NULOUT,*)
& 'CH_ods_Htr: Obs rejected via CH_CONVERT: ',
& CNAMANAL(JLT)
MOBDATA(NCMASS,IDATA:IDATEND)=0
MOBDATA(NCMFLG,IDATA:IDATEND)=
& MOBDATA(NCMFLG,IDATA:IDATEND)+131072+512
C ! Same flag as for QCvar rejection
END IF
END IF
END IF
IF (IREJECT.EQ.1) CYCLE
C
C* If not rejected, select and apply forward model
C "F(x)" (or TLM "Hx") for obs profile (with all
C elements at same lat/long)
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,
& ILMAX,ZOBSLEV,ZPRESS,ZVTR,ZVTR2,
& ROBDATA(NCMDWN,IDATA:IDATEND),
& ZTRIAL,ZTRIAL2,0,IDIM)
C
else
C
CALL CH_VPROF
(MOBDATA(NCMASS,IDATA:IDATEND),
& MOBDATA(NCMXTR,IDATA:IDATEND),
& ROBDATA(NCMLYR,IDATA:IDATEND),INUMS,
& ILMAX,ZOBSLEV,ZPRESS,ZVTR,ZTRIAL,0,IDIM,IKERN)
C
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),
& ZTRIAL,ZDUM,
& CDBGTYP,ZVTR,zobslev,zobslev2,
& zpress,ilmax,zlat,ilat,zstate,
& CNAMANAL(JLT),0,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),
& ZTRIAL,ZDUM,
& CDBGTYP,ZVTR,zobslev,zobslev2,
& zpress,ilmax,zlat,ilat,zstate,
& CSTNID(JOBS),CNAMANAL(JLT),0,IKERN)
C
END IF
C
C* Update flags
C
IF (.NOT.LSIMOB.AND.(CDBGTYP.eq.'HR'.or.CDBGTYP.eq.'hr')) THEN
WHERE (MOBDATA(NCMXTR,IDATA:IDATEND).eq.2)
& MOBDATA(NCMFLG,IDATA:IDATEND)=
& MOBDATA(NCMFLG,IDATA:IDATEND)+262144+512
WHERE (MOBDATA(NCMXTR,IDATA:IDATEND).eq.1)
& MOBDATA(NCMFLG,IDATA:IDATEND)=
& MOBDATA(NCMFLG,IDATA:IDATEND)+2048
END IF
C
IF (.NOT.LSIMOB ) THEN
C
C* Store Hdx into CMA instead of calculating difference and divide
C by std. dev. since these will be done in separate routines
C
WHERE (MOBDATA(NCMASS,IDATA:IDATEND).EQ.1.and.
& MOBDATA(NCMXTR,IDATA:IDATEND).eq.0)
ROBDATA8(NCMOMA,IDATA:IDATEND)= ztrial(1:INUMS)
ENDWHERE
ELSE
C
C* Store simulated/forecast value as observations
C
WHERE (MOBDATA(NCMASS,IDATA:IDATEND).EQ.1.and.
& MOBDATA(NCMXTR,IDATA:IDATEND).eq.0)
ROBDATA8(NCMOMA,IDATA:IDATEND)=0.0D0
ROBDATA8(NCMVAR,IDATA:IDATEND)=ztrial(1:INUMS)
ENDWHERE
END IF
C
END DO ! (J1)
END DO ! (JOBS)
END IF
END DO ! (NFILES)
C
RETURN
END