SUBROUTINE HSATANG(KDLEN,KLEN,KOBSTYPE,KSERIES,KCDTYP,KSATGRP,PNVANG,PZEANG)

!**** *HSATANG* - Set viewing angle and zenith angle

!     E. ANDERSSON            ECMWF          21/06/00

!     PURPOSE
!     -------

!     Set viewing angle and zenith angle

!**   INTERFACE
!     ---------
!     *CALL* *HSATANG(KDLEN,KLEN,KSERIES,KCDTYP,KSATGRP,PNVANG,PZEANG)
!     WHERE KDLEN   = First dimension, observations
!           KLEN    = Actual number of observations
!           KOBSTYPE= Observation type
!           KSERIES = Series
!           KCDTYP  = Code type
!           KSATGRP = Satellite data group
!           PNVANG  = Nadir viewing angle
!           PZEANG  = Zenith angle

!        HSATANG is called from HRADP/tl/ad

!**   METHOD
!     ------
!**   EXTERNALS
!     ---------

!**   MODIFICATIONS
!     -------------
!     Erik Andersson  21/06/00 : Original
!     Niels Bormann   21/09/01 : Zenith angle for AMV/SATOBs
!     Matt Szyndel    23/03/05 : Add MTSAT and FY-2
!     P Bauer, G Kelly, N Bormann   05/02/06 : Add AMSRE, SSMIS, TMI
!     T. Auligne      09/12/05 : Default Nadir Viewing Angle set to RMDI 
!     A. Collard      01/03/07 : Add IASI
!     A. Geer         14/04/08 : All-sky 4D-Var of microwave imagers
!     Q. Lu           11/03/09 : Add FY3A 
!     W. Bell         26/11/09 : Add windsat block
!     ------------------------------------------------------------------

USE PARKIND1  ,ONLY : JPIM     ,JPRB
USE YOMHOOK   ,ONLY : LHOOK,   DR_HOOK

USE YOMCOCTP , ONLY : NGTHRB   , NSATOB   , NSSMI
USE YOMANCS  , ONLY : RADIANS  ,RDEGREES   ,RMDI
USE YOMTVRAD , ONLY : MSENSOR_HIRS,MSENSOR_MSU,MSENSOR_SSU,&
 & MSENSOR_IRAS,MSENSOR_MWTS,MSENSOR_MWHS,MSENSOR_MWRI, &
 & MSENSOR_AMSUA,MSENSOR_AMSUB,MSENSOR_MHS,MXSENSOR,&
 & MSENSOR_VTPR1,MSENSOR_VTPR2,MSENSOR_AIRS,MSENSOR_AMSRE,MSENSOR_SSMIS,&
 & MSERIES_TRMM,MSENSOR_SSMI, MSENSOR_TMI,MSENSOR_IASI, MSENSOR_WINDSAT, &
 & MSERIES_NOAA,MSERIES_DMSP,MSERIES_METEOSAT,&
 & MSERIES_GOES,MSERIES_EOS,MSERIES_MTSAT,MSERIES_FY2,MSERIES_FY3,&
 & MSERIES_METOP,MSERIES_CORIOLIS, SATGRP_TABLE  
USE YOMDB
USE YOMCST   , ONLY : RA

IMPLICIT NONE

INTEGER(KIND=JPIM),INTENT(IN)    :: KDLEN
INTEGER(KIND=JPIM),INTENT(IN)    :: KLEN 
INTEGER(KIND=JPIM),INTENT(IN)    :: KOBSTYPE 
INTEGER(KIND=JPIM),INTENT(IN)    :: KSERIES 
INTEGER(KIND=JPIM),INTENT(IN)    :: KCDTYP 
INTEGER(KIND=JPIM),INTENT(IN)    :: KSATGRP 
REAL(KIND=JPRB)   ,INTENT(OUT)   :: PNVANG(KDLEN) 
REAL(KIND=JPRB)   ,INTENT(OUT)   :: PZEANG(KDLEN) 
REAL(KIND=JPRB), PARAMETER :: ZPSATALT=825000.0_JPRB  ! Nominal satellite altitude N15
REAL(KIND=JPRB) :: ZRATOE
REAL(KIND=JPRB) :: ZSWATH_WIDTH(0:MXSENSOR)
REAL(KIND=JPRB) :: ZFOV_SPACING(0:MXSENSOR)
INTEGER(KIND=JPIM) :: ISENSOR,IFOVOB,JOBS
REAL(KIND=JPRB) :: ZHOOK_HANDLE

#include "openmp_obs.h"

IF (LHOOK) CALL DR_HOOK('HSATANG',0,ZHOOK_HANDLE)
ZRATOE=(ZPSATALT+RA)/RA

!     ------------------------------------------------------------------
!*    1.       Extract zenith angle and nadir viewing angle
!              --------------------------------------------

IF(KCDTYP == NGTHRB .OR. KCDTYP == NSSMI) THEN
  ZSWATH_WIDTH(:)=0.0_JPRB
  ZSWATH_WIDTH(MSENSOR_HIRS )=49.50_JPRB
  ZSWATH_WIDTH(MSENSOR_MSU  )=47.37_JPRB
  ZSWATH_WIDTH(MSENSOR_SSU  )=40.00_JPRB
  ZSWATH_WIDTH(MSENSOR_IRAS )=49.50_JPRB
  ZSWATH_WIDTH(MSENSOR_MWTS )=48.30_JPRB
  ZSWATH_WIDTH(MSENSOR_MWHS )=53.35_JPRB
  ZSWATH_WIDTH(MSENSOR_MWRI )=52.50_JPRB
  ZSWATH_WIDTH(MSENSOR_AMSUA)=48.333333_JPRB
  ZSWATH_WIDTH(MSENSOR_AMSUB)=48.95_JPRB
  ZSWATH_WIDTH(MSENSOR_MHS  )=48.95_JPRB
  ZSWATH_WIDTH(MSENSOR_VTPR1)=30.30_JPRB
  ZSWATH_WIDTH(MSENSOR_VTPR2)=30.30_JPRB
  ZSWATH_WIDTH(MSENSOR_AIRS )=48.95_JPRB
  ZSWATH_WIDTH(MSENSOR_SSMI )=51.20_JPRB
  ZSWATH_WIDTH(MSENSOR_SSMIS )=72.00_JPRB
  ZSWATH_WIDTH(MSENSOR_AMSRE )=61.00_JPRB
  ZSWATH_WIDTH(MSENSOR_TMI )=65.00_JPRB
  ZSWATH_WIDTH(MSENSOR_WINDSAT )=65.00_JPRB
  ZSWATH_WIDTH(:)=ZSWATH_WIDTH(:)*RADIANS

  ZFOV_SPACING(:)=0.0_JPRB
  ZFOV_SPACING(MSENSOR_HIRS )=1.800_JPRB
  ZFOV_SPACING(MSENSOR_MSU  )=9.474_JPRB
  ZFOV_SPACING(MSENSOR_SSU  )=11.429_JPRB
  ZFOV_SPACING(MSENSOR_IRAS )=1.800_JPRB
  ZFOV_SPACING(MSENSOR_MWTS )=6.900_JPRB
  ZFOV_SPACING(MSENSOR_MWHS )=1.100_JPRB
  ZFOV_SPACING(MSENSOR_MWRI )=0.4393305_JPRB
  ZFOV_SPACING(MSENSOR_AMSUA)=3.333333_JPRB
  ZFOV_SPACING(MSENSOR_AMSUB)=1.100_JPRB
  ZFOV_SPACING(MSENSOR_MHS  )=1.100_JPRB
  ZFOV_SPACING(MSENSOR_VTPR1)=2.754_JPRB
  ZFOV_SPACING(MSENSOR_VTPR2)=2.754_JPRB
  ZFOV_SPACING(MSENSOR_AIRS )=1.100_JPRB
  ZFOV_SPACING(MSENSOR_SSMI )=1.625_JPRB
  ZFOV_SPACING(MSENSOR_SSMIS )=2.441_JPRB
  ZFOV_SPACING(MSENSOR_AMSRE )=0.625_JPRB
  ZFOV_SPACING(MSENSOR_TMI )=0.628_JPRB
  ZFOV_SPACING(MSENSOR_WINDSAT )=1.6456_JPRB
  ZFOV_SPACING(:)=ZFOV_SPACING(:)*RADIANS
ENDIF

!*          1.1   SATOBS
IF( KOBSTYPE == NSATOB) THEN
  PZEANG(1:KLEN) = SATHDR(1:KLEN,MDB_ZENITH_AT_SAT)
  PNVANG(1:KLEN) = RMDI
ELSE

!*          1.2   Select by series, first NOAA-series
  SELECT CASE(KSERIES)
  CASE(MSERIES_NOAA)

!*          1.2.1 TOVS 1c radiances.
    IF(KCDTYP == NGTHRB) THEN
      ISENSOR=SATGRP_TABLE(KSATGRP)%sensor
      DO JOBS = 1,KLEN
        IFOVOB = NINT(SATHDR(JOBS,MDB_SCANPOS_AT_RADIANCE))
        PNVANG(JOBS)= -ZSWATH_WIDTH(ISENSOR)+(IFOVOB-1)*ZFOV_SPACING(ISENSOR)

        IF(     ISENSOR == MSENSOR_AMSUA .OR. ISENSOR == MSENSOR_AMSUB &
         & .OR. ISENSOR == MSENSOR_MHS       &
         & .OR. SATGRP_TABLE(KSATGRP)%rtid >= 16) THEN  
          PZEANG(JOBS) = SATHDR(JOBS,MDB_ZENITH_AT_SAT)
        ELSE
          PZEANG(JOBS) = ABS(ASIN( SIN(PNVANG(JOBS)) *ZRATOE))*RDEGREES
        ENDIF
        PNVANG(JOBS) = PNVANG(JOBS)*RDEGREES
      ENDDO

!*          1.2.2 Other codetypes are nadir
    ELSE
      PNVANG(1:KLEN)= 0.0_JPRB
      PZEANG(1:KLEN)= 0.0_JPRB
    ENDIF

!*          1.3   DMSP SSM/I, SSM/IS
  CASE(MSERIES_DMSP)

    PZEANG(1:KLEN)= 53.1_JPRB

    ! Fake nadir viewing angle is defined for scan bias correction use
    IF(KCDTYP == NGTHRB .OR. KCDTYP == NSSMI) THEN
      ISENSOR=SATGRP_TABLE(KSATGRP)%sensor
      DO JOBS = 1,KLEN
        IF(KCDTYP == NGTHRB)THEN
          IFOVOB = NINT(SATHDR(JOBS,MDB_SCANPOS_AT_RADIANCE))
        ELSE 
          IFOVOB = NINT(SATHDR(JOBS,MDB_SCANPOS_AT_RADIANCE))
        ENDIF
        PNVANG(JOBS)= -ZSWATH_WIDTH(ISENSOR)+(IFOVOB-1)*ZFOV_SPACING(ISENSOR)
        PNVANG(JOBS) = PNVANG(JOBS)*RDEGREES
      ENDDO
    ENDIF  

!*          1.4   Geostationary CSR data
  CASE(MSERIES_METEOSAT,MSERIES_GOES,MSERIES_MTSAT,MSERIES_FY2)
    PZEANG(1:KLEN) = SATHDR(1:KLEN,MDB_ZENITH_AT_SAT)
    PNVANG(1:KLEN) = RMDI
    
!*          1.5   EOS AMSR-E, AIRS
  CASE(MSERIES_EOS)
    PNVANG(1:KLEN)= 0.0_JPRB
    PZEANG(1:KLEN)= 0.0_JPRB
    
    IF(KCDTYP == NGTHRB .OR. KCDTYP == NSSMI) THEN
      ISENSOR=SATGRP_TABLE(KSATGRP)%sensor
      IF (ISENSOR == MSENSOR_AMSRE) THEN

        PZEANG(1:KLEN)= 55.0_JPRB     
        ! Fake nadir viewing angle is defined for scan bias correction use
        IF(KCDTYP == NGTHRB) THEN
          ISENSOR=SATGRP_TABLE(KSATGRP)%sensor
          DO JOBS = 1,KLEN
            IF(KCDTYP == NGTHRB) THEN
              IFOVOB = NINT(SATHDR(JOBS,MDB_SCANPOS_AT_RADIANCE))
            ELSEIF (KCDTYP == NSSMI) THEN
              IFOVOB = NINT(SATHDR(JOBS,MDB_SCANPOS_AT_RADIANCE)) ! Rainy obs use SSMI table
            ENDIF
            PNVANG(JOBS)= -ZSWATH_WIDTH(ISENSOR)+(IFOVOB-1)*ZFOV_SPACING(ISENSOR)
            PNVANG(JOBS) = PNVANG(JOBS)*RDEGREES
          ENDDO
        ENDIF

      ELSEIF (ISENSOR == MSENSOR_AIRS) THEN
        DO JOBS = 1,KLEN
          IFOVOB = NINT(SATHDR(JOBS,MDB_SCANPOS_AT_RADIANCE))
          PNVANG(JOBS)= -ZSWATH_WIDTH(ISENSOR)+(IFOVOB-1)*ZFOV_SPACING(ISENSOR)
          PZEANG(JOBS) = ABS(ASIN( SIN(PNVANG(JOBS))*ZRATOE))
          PNVANG(JOBS) = PNVANG(JOBS)*RDEGREES
          PZEANG(JOBS) = SATHDR(JOBS,MDB_ZENITH_AT_SAT)
        ENDDO
      ENDIF

!*          1.5.2 Other codetypes are nadir
    ELSE
      PNVANG(1:KLEN)= 0.0_JPRB
      PZEANG(1:KLEN)= 0.0_JPRB
    ENDIF

!*          1.6   METOP
  CASE(MSERIES_METOP)

!*          1.6.1 TOVS 1c radiances.
    IF(KCDTYP == NGTHRB) THEN
      ISENSOR=SATGRP_TABLE(KSATGRP)%sensor
      IF (ISENSOR == MSENSOR_IASI) THEN
         DO JOBS = 1,KLEN
            PZEANG(JOBS) = SATHDR(JOBS,MDB_ZENITH_AT_SAT)
            IF (PZEANG(JOBS) == RMDI) THEN
               PNVANG(JOBS) = RMDI
            ELSE
               PNVANG(JOBS)= ABS(ASIN( SIN(PZEANG(JOBS)*RADIANS)/ZRATOE))
               IFOVOB = NINT(SATHDR(JOBS,MDB_SCANPOS_AT_RADIANCE))
               IF (IFOVOB <= 59) THEN
                  PNVANG(JOBS) = -PNVANG(JOBS)*RDEGREES
               ELSE
                  PNVANG(JOBS) =  PNVANG(JOBS)*RDEGREES
               ENDIF
            ENDIF
         ENDDO
      ELSE
         DO JOBS = 1,KLEN
            IFOVOB = NINT(SATHDR(JOBS,MDB_SCANPOS_AT_RADIANCE))
            PNVANG(JOBS)= -ZSWATH_WIDTH(ISENSOR)+(IFOVOB-1)* &
&                            ZFOV_SPACING(ISENSOR)
            IF(     ISENSOR == MSENSOR_AMSUA .OR. ISENSOR == MSENSOR_AMSUB &
                 & .OR. ISENSOR == MSENSOR_MHS ) THEN  
               PZEANG(JOBS) = SATHDR(JOBS,MDB_ZENITH_AT_SAT)
            ELSE
               PZEANG(JOBS) = ABS(ASIN( SIN(PNVANG(JOBS)) *ZRATOE))*RDEGREES
            ENDIF
            PNVANG(JOBS) = PNVANG(JOBS)*RDEGREES
         ENDDO
      ENDIF
!*          1.6.2 Other codetypes are nadir
    ELSE
      PNVANG(1:KLEN)= 0.0_JPRB
      PZEANG(1:KLEN)= 0.0_JPRB
    ENDIF

!*          1.7   TRMM
  CASE(MSERIES_TRMM)

    IF(KCDTYP == NGTHRB) THEN
      PZEANG(1:KLEN) = SATHDR(1:KLEN, MDB_ZENITH_AT_SAT) ! Clear (ATOVS table)
    ELSEIF (KCDTYP == NSSMI) THEN
      PZEANG(1:KLEN) = RMDI
!     Rainy assimilation - zenith angle is not used but if required should 
!     be added as follows:
!     PZEANG(1:KLEN) = SATHDR(1:KLEN, MDB_ZENITH_AT_SAT) ! (SSMI table, modify sat_ssmi.sql)
    ENDIF

    ! Fake nadir viewing angle is defined for scan bias correction use
    IF(KCDTYP == NGTHRB .OR. KCDTYP == NSSMI) THEN
      ISENSOR=SATGRP_TABLE(KSATGRP)%sensor
      DO JOBS = 1,KLEN
        IF(KCDTYP == NGTHRB) THEN
          IFOVOB = NINT(SATHDR(JOBS,MDB_SCANPOS_AT_RADIANCE))
        ELSEIF (KCDTYP == NSSMI) THEN
          IFOVOB = NINT(SATHDR(JOBS,MDB_SCANPOS_AT_RADIANCE)) ! Rainy obs use SSMI table
        ENDIF
        PNVANG(JOBS)= -ZSWATH_WIDTH(ISENSOR)+(IFOVOB-1)*ZFOV_SPACING(ISENSOR)
        PNVANG(JOBS) = PNVANG(JOBS)*RDEGREES
      ENDDO
    ENDIF

!*          1.7   CORIOLIS WINDSAT
  CASE(MSERIES_CORIOLIS)

    PZEANG(1:KLEN)= 53.1_JPRB

    ! Fake nadir viewing angle is defined for scan bias correction use
    IF(KCDTYP == NSSMI) THEN
      ISENSOR=SATGRP_TABLE(KSATGRP)%sensor
      DO JOBS = 1,KLEN
        IFOVOB = NINT(SATHDR(JOBS,MDB_SCANPOS_AT_RADIANCE))
        PNVANG(JOBS)= -ZSWATH_WIDTH(ISENSOR)+(IFOVOB-1)*ZFOV_SPACING(ISENSOR)
        PNVANG(JOBS) = PNVANG(JOBS)*RDEGREES
      ENDDO
    ENDIF  

!*          1.8   FY-3
  CASE(MSERIES_FY3)
    IF(KCDTYP == NGTHRB .OR. KCDTYP == NSSMI) THEN
      ISENSOR=SATGRP_TABLE(KSATGRP)%sensor
      DO JOBS = 1,KLEN
        IF(KCDTYP == NGTHRB) THEN
          PZEANG(1:KLEN) = SATHDR(1:KLEN, MDB_ZENITH_AT_SAT)
          IFOVOB = NINT(SATHDR(JOBS,MDB_SCANPOS_AT_RADIANCE))
        ELSEIF (KCDTYP == NSSMI) THEN
          PZEANG(1:KLEN)= 52.5_JPRB
          IFOVOB = NINT(SATHDR(JOBS,MDB_SCANPOS_AT_RADIANCE)) ! Rainy obs use SSMI table
        ENDIF
        PNVANG(JOBS)= -ZSWATH_WIDTH(ISENSOR)+(IFOVOB-1)*ZFOV_SPACING(ISENSOR)
        PNVANG(JOBS) = PNVANG(JOBS)*RDEGREES
      ENDDO
    ENDIF

!*          1.9   Default
  CASE DEFAULT
    PZEANG(1:KLEN) = 0.0_JPRB
    PNVANG(1:KLEN) = RMDI
  END SELECT

ENDIF

IF (LHOOK) CALL DR_HOOK('HSATANG',1,ZHOOK_HANDLE)
END SUBROUTINE HSATANG
