!-------------------------------------- LICENCE BEGIN ------------------------------------
!Environment Canada - Atmospheric Science and Technology License/Disclaimer,
!                     version 3; Last Modified: May 7, 2008.
!This is free but copyrighted software; you can use/redistribute/modify it under the terms
!of the Environment Canada - Atmospheric Science and Technology License/Disclaimer
!version 3 or (at your option) any later version that should be found at:
!http://collaboration.cmc.ec.gc.ca/science/rpn.comm/license.html
!
!This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
!without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
!See the above mentioned License/Disclaimer for more details.
!You should have received a copy of the License/Disclaimer along with this software;
!if not, you can write to: EC-RPN COMM Group, 2121 TransCanada, suite 500, Dorval (Quebec),
!CANADA, H9P 1J3; or send e-mail to service.rpn@ec.gc.ca
!-------------------------------------- LICENCE END --------------------------------------
!

      SUBROUTINE att2phi(lcolumn,lcolumng) 1,13
*
***s/r att2phi - adjoint of Temperature to phi transformation
*              - input and output are GZ, TT, PS, HU in lcolumn
*
*Author  : S. Pellerin *ARMA/AES September 1998
*
      use MathPhysConstants_mod
      use columnData_mod 
      IMPLICIT NONE
      type(struct_columnData) :: lcolumn,lcolumng
      type(struct_vco), pointer :: vco_anl
      integer jobs,jlev,nlev_T
      real*8 :: zcon, zalpha
      real*8, allocatable :: vma(:),vmb(:),vmc(:)
      real*8, allocatable :: vmd(:),vme(:),vmf(:)
      real*8, allocatable :: tv_tmp(:,:)
      real*8, pointer :: tt_column(:),hu_column(:)
      real*8, pointer :: gz_column_t(:),gz_column_m(:),ps_column(:)
*
      nlev_T = col_getNumLev(lcolumn,'TH')
      allocate(vma(nlev_T))
      allocate(vmb(nlev_T))
      allocate(vmc(nlev_T))
      allocate(vmd(nlev_T))
      allocate(vme(nlev_T))
      allocate(vmf(nlev_T))
      allocate(tv_tmp(nlev_T,col_getNumCol(lcolumn)))

      vco_anl => col_getVco(lcolumng)
      zalpha=0.0D0
      call matapat(vco_anl%dhyb_m,zalpha,nlev_T,vma,vmb,vmc,vmd,vme,vmf)

      call avtap
c
c*    Adjoint of preparation r.h.s. for TL-Hydrostatic equation
c     ---------------------------------------------------------
c
!$OMP PARALLEL DO PRIVATE(jobs,jlev,zcon,tt_column,
!$OMP& hu_column,ps_column)
      do jobs = 1, col_getNumCol(lcolumn)

        tt_column   => col_getColumn(lcolumn,jobs,'TT')
        hu_column   => col_getColumn(lcolumn,jobs,'HU')
        ps_column   => col_getColumn(lcolumn,jobs,'P0')

        do jlev = 1, nlev_T
c
c         zcon = d(lcolumng%rtapfac)/d(ps)
c
          zcon   = (vco_anl%db_dhyb_M(jlev)-
     +              vco_anl%db_M(jlev)*lcolumng%rtapfac(jlev,jobs))/
     +              col_getPressure(lcolumng,jlev,jobs,'TH')
          ps_column(1)=ps_column(1)+
     &          col_getElem(lcolumng,jlev,jobs,'TT')*zcon * tv_tmp(jlev,jobs)

          tv_tmp(jlev,jobs)=lcolumng%rtapfac(jlev,jobs)*tv_tmp(jlev,jobs)

        enddo
        do jlev = 1, nlev_T
          tt_column(jlev) = tt_column(jlev)+
     &              lcolumng%oltv(1,jlev,jobs)*tv_tmp(jlev,jobs)
          hu_column(jlev) = hu_column(jlev)+
     &              lcolumng%oltv(2,jlev,jobs)*tv_tmp(jlev,jobs)
        enddo
      enddo
!$OMP END PARALLEL DO

      deallocate(vma)
      deallocate(vmb)
      deallocate(vmc)
      deallocate(vmd)
      deallocate(vme)
      deallocate(vmf)
      deallocate(tv_tmp)

      return

      contains


      SUBROUTINE AVTAP 1,4
*S/P AVTAP: Adjoint de VTAP
C
C AUTHOR: Luc Fillion - ARMA/AES CAN, 21 jul, 11 sep 98
C
      use MathPhysConstants_mod
      IMPLICIT NONE
      INTEGER  jobs, IKLEVM2, JK, IK
      REAL*8     ZAK, ZBK, ZCK, ZCON2
      integer mythread,numthd,omp_get_thread_num,omp_get_num_threads
c
      ZCON2 = -MPC_RGAS_DRY_AIR_R8
      IKLEVM2 = nlev_T-2
!$OMP PARALLEL PRIVATE(jobs,ik,jk,mythread,numthd,zak,zbk,zck,
!$OMP+                 gz_column_t,gz_column_m)
      mythread=omp_get_thread_num()+1
      numthd=omp_get_num_threads()
      do jobs = mythread, col_getNumCol(lcolumn),numthd
        gz_column_m => col_getColumn(lcolumn,jobs,'GZ','MM')
        gz_column_t => col_getColumn(lcolumn,jobs,'GZ','TH')
        gz_column_t(:) = gz_column_t(:) + gz_column_m(:)
        do jk=1,nlev_T
          tv_tmp(jk,jobs) = 0.0d0
        enddo
c
        do jk=iklevm2,1,-1
          ik = nlev_T-1-jk
          zak = -2.0D0*ZCON2*vma(ik+1)
          zbk = -2.0D0*ZCON2*vmb(ik+1)
          zck = -2.0D0*ZCON2*vmc(ik+1)
          tv_tmp(ik,jobs)   = tv_tmp(ik,jobs)+
     &                        gz_column_t(ik)*zak
          tv_tmp(ik+1,jobs) = tv_tmp(ik+1,jobs)+
     &                        gz_column_t(ik)*zbk
          tv_tmp(ik+2,jobs) = tv_tmp(ik+2,jobs)+
     &                        gz_column_t(ik)*zck
          gz_column_t(ik+2) = gz_column_t(ik+2)+gz_column_t(ik)
          gz_column_t(ik)  = 0.0D0
        enddo

        ZAK = -2.0D0*ZCON2*VMA(nlev_T)
        ZBK = -2.0D0*ZCON2*VMB(nlev_T)
        ZCK = -2.0D0*ZCON2*VMC(nlev_T)
        tv_tmp(nlev_T-1,jobs) = tv_tmp(nlev_T-1,jobs)+
     &             ZAK*gz_column_t(nlev_T-1)
        tv_tmp(nlev_T,jobs)   = tv_tmp(nlev_T,jobs)+
     &             ZBK*gz_column_t(nlev_T-1)
        tv_tmp(nlev_T-2,jobs) = tv_tmp(nlev_T-2,jobs)+
     &             ZCK*gz_column_t(nlev_T-1)
        gz_column_t(nlev_T-1)= 0.0D0
        gz_column_t(nlev_T)  = 0.0D0
      enddo
!$OMP END PARALLEL
C
      return
      end subroutine avtap

      end subroutine att2phi