!-------------------------------------- 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 --------------------------------------
***s/p v4d_gauss2gem_ad - Adjoint of v4d_gauss2gem  
*
#include "model_macros_f.h"
*

      subroutine v4d_gauss2gem_ad( ut1, vt1, tpt1, hut1, st1, DIST_DIM,  1,7
     %                             gut1,gvt1,gtpt1,ghut1,gst1,nigauss,njgauss,Nk)
*
      use v4dz
      use v4d_interint0
*
      implicit none
*
      integer nigauss,njgauss,DIST_DIM,Nk
      real gut1 (nigauss,njgauss,Nk), gvt1 (nigauss,njgauss,Nk),
     %     gtpt1(nigauss,njgauss,Nk), ghut1(nigauss,njgauss,Nk),
     %     gst1 (nigauss,njgauss)
*
      real ut1  (DIST_SHAPE,Nk), vt1 (DIST_SHAPE,Nk),
     %     tpt1 (DIST_SHAPE,Nk), hut1(DIST_SHAPE,Nk),
     %     st1  (DIST_SHAPE)
*
*author M.Tanguay
*
*revision
* v3_00 - Tanguay M.        - initial MPI version
* v3_01 - Tanguay M.        - introduce gem2gauss for singular vectors
* v3_01 - Buehner M.        - external already_done
* v3_02 - Buehner M.        - V4dzga_degree in namelist var4d
* v3_11 - Tanguay M.        - Introduce Grd_gauss_L 
*                           - Remove V4dg_ga_eq_ge_L
* v3_30 - Fillion L.        - Same grid when LAM 
*
*object
*  see id section
*
*arguments
*
*implicits
#include "glb_ld.cdk"
#include "grd.cdk"
#include "geomg.cdk"
#include "geomn.cdk"
#include "dcst.cdk"
#include "lun.cdk"
#include "hgc.cdk"
#include "ptopo.cdk"
#include "v4dg.cdk"
*
      integer  ezqkdef,gdxyfll,gdrls,ezgdef 
      external ezqkdef,gdxyfll,gdrls,ezgdef
*
      integer gdin,gdout,i,j,k,n,i1,i2,j1,j2,ni,nj,
     %        ier,status
*
      real,   allocatable, dimension(:,:) :: zo,wo
      real,   allocatable, dimension(:)   :: groots,lat,lon
      real*8, allocatable, dimension(:)   :: x_8,y_8 
*
      real,   pointer, dimension(:,:) :: fldscint,flduint,fldvint,fld2d 
*
      real*8, parameter :: ZERO_8 = 0.0
      real*8, parameter :: HALF_8 = 0.5  
      real*8, parameter ::  ONE_8 = 1.0
      real*8, parameter ::  TWO_8 = 2.0
      real*8, parameter ::CLXXX_8 = 180.0
      real*8  deg2rad_8
*
      logical same_grid_L
*
      if(G_lam) then
        same_grid_L = .true.
      else
        same_grid_L = V4dzgauss_ni.eq.G_ni.and.V4dzgauss_nj.eq.G_nj.and.Grd_gauss_L
      endif
*
*     Set parameters of interpolation 
*     -------------------------------
      if(Ptopo_myproc.eq.0.and..not.V4dzga_already_done_L) then
*
*        ---------------------------------------------------------
*        Type of interpolation V4dzga_degree now in namelist var4d
*        ---------------------------------------------------------
*        NOTE: 1= Linear and 3=Cubic Lagrange
*        ---------------------------------------------------------
*
*        Type of input grid
*        ------------------
         V4dzga_grtypi = 'G' 
*
*        ----------------------------------------------------------
*        Convert output grid from lat-lon to grid input index px-py
*        ----------------------------------------------------------
*
*        Define output grid = global GEM scalar Z grid
*        ---------------------------------------------
         gdout = ezgdef(G_ni,G_nj,'Z',Hgc_gxtyp_s,
     %           Hgc_ig1ro, Hgc_ig2ro, Hgc_ig3ro, Hgc_ig4ro,
     %           Geomn_longs, Geomn_latgs)
*
         V4dzga_npts = G_ni*G_nj
*
*        Define lat-lon of OUTPUT grid as 2D-field
*        -----------------------------------------
         allocate ( lon(V4dzga_npts), STAT=status )
         allocate ( lat(V4dzga_npts), STAT=status )
*
*        Prescribe global GEM scalar Z grid lat-lon 
*        ------------------------------------------
*
         do j=1,G_nj
         do i=1,G_ni
            n = G_ni*(j-1) + i
            lon(n) = Geomn_longs(i)
            lat(n) = Geomn_latgs(j)
         enddo
         enddo
*
*        Allocations OUTPUT grid parameters
*        ----------------------------------
         allocate ( V4dzga_px(V4dzga_npts), STAT=status )
         allocate ( V4dzga_py(V4dzga_npts), STAT=status )
*
*        Define input grid = Gaussian grid 
*        ---------------------------------
         gdin = ezqkdef (nigauss,njgauss,'G',0,0,0,0,0)
*
*        Index in INPUT grid of each lat lon point in OUTPUT grid
*        --------------------------------------------------------
         ier = gdxyfll(gdin,V4dzga_px,V4dzga_py,lat,lon,V4dzga_npts)
*
         deallocate( lat, STAT=status )
         deallocate( lon, STAT=status )
*
         ier = gdrls(gdin )
         ier = gdrls(gdout)
*
*        ---------------------------------------------------------
*        Initialize dimensions I1,I2,J1,J2,NI,NJ,NK, axes AX,AY
*        and differences CX,CY of input grid used in interpolation
*        ---------------------------------------------------------
         V4dzga_i1 = 1 
         V4dzga_i2 = nigauss 
         V4dzga_j1 = 1 
         V4dzga_j2 = njgauss 
*
*        Keep horizontal dimensions of input grid used in interpolation
*        --------------------------------------------------------------
         i1 = V4dzga_i1 
         i2 = V4dzga_i2 
         j1 = V4dzga_j1 
         j2 = V4dzga_j2 
*
*        ni = Period if grid='G'
*        -----------------------
         ni = i2-i1+1
*
*        Maximal dimension in Y
*        ----------------------
         nj = j2-j1+1
*
*        Vertical dimension Nk is known 
*        ------------------------------
*
*        Define axes of input grid 
*        -------------------------
         allocate ( V4dzga_ax(ni), STAT=status )
         allocate ( V4dzga_ay(nj), STAT=status )
*
         do i=1,ni
            V4dzga_ax(i) = float(i-1) * (360./float(ni))
         enddo
*
         allocate ( groots(nj), STAT=status )
*
         call ez_glat (V4dzga_ay,groots,nj,0)
*
         deallocate( groots, STAT=status )
*
*        Evaluate AX,AY differences in CX,CY for cubic interpolation
*        -----------------------------------------------------------
         if(V4dzga_degree.eq.3) then
*
            allocate ( V4dzga_cx(6*(ni)), STAT=status )
            allocate ( V4dzga_cy(6*(nj)), STAT=status )
*
            call v4d_nwtncof (V4dzga_cx,V4dzga_cy,V4dzga_ax,V4dzga_ay,
     %                        i1,i2,j1,j2,ni,V4dzga_grtypi)
*
         endif
*
*        Define grid quantities used to evaluate model fields at poles 
*        -------------------------------------------------------------
         allocate ( x_8(0:ni+1),     STAT=status )
         allocate ( y_8(nj),         STAT=status )
*
         allocate ( V4dzga_wx_8 (ni), STAT=status )
         allocate ( V4dzga_cox_8(ni), STAT=status )
         allocate ( V4dzga_six_8(ni), STAT=status )
         allocate ( V4dzga_siy_8(nj), STAT=status )
*
         deg2rad_8 = acos( -ONE_8 )/CLXXX_8
*
         do i=1,ni
            x_8(i) =  V4dzga_ax(i) * deg2rad_8
         enddo
         x_8(   0) = (V4dzga_ax(ni)-360.0)*deg2rad_8
         x_8(ni+1) = (V4dzga_ax( 1)+360.0)*deg2rad_8
*
         do j=1,nj
            y_8(j) =  V4dzga_ay(j) * deg2rad_8
         enddo
*
         do i=1,ni
            V4dzga_wx_8 (i) = (x_8(i+1) - x_8(i-1))*HALF_8 / (TWO_8*Dcst_pi_8)
            V4dzga_cox_8(i) = cos ( x_8(i) )
            V4dzga_six_8(i) = sin ( x_8(i) )
         enddo
*
         do j=1,nj
           V4dzga_siy_8(j) = sin ( y_8(j) )
         enddo
*
         deallocate( x_8, STAT=status )
         deallocate( y_8, STAT=status )
*
         V4dzga_already_done_L = .true.
*
      elseif(Ptopo_myproc.eq.0) then
*
         i1 = V4dzga_i1
         i2 = V4dzga_i2
         j1 = V4dzga_j1
         j2 = V4dzga_j2
*
      endif
*
*     Adjoint of
*     Interpolate 3D-Var Gaussian grid to GEM scalar Z grid
*     -----------------------------------------------------
*
      if(Ptopo_myproc.eq.0) then
*        ------------------------------------------------
*        Allocate fields on output grid in reverse format
*        ------------------------------------------------
         allocate ( fldscint(Nk,V4dzga_npts), STAT=status )
         allocate ( flduint (Nk,V4dzga_npts), STAT=status )
         allocate ( fldvint (Nk,V4dzga_npts), STAT=status )
         allocate ( fld2d   ( 1,V4dzga_npts), STAT=status )
*
*        -----------------------------------------------------------
*        Allocate fields on output grid with V4dzga_npts = G_ni*G_nj
*        -----------------------------------------------------------
         allocate ( zo      (G_ni*G_nj,G_nk), STAT=status )
         allocate ( wo      (G_ni*G_nj,G_nk), STAT=status )
      endif
*
*     Zero adjoint work fields
*     ------------------------
      if(Ptopo_myproc.eq.0) then
         do n = 1,V4dzga_npts
         do k = 1,Nk
            fldscint(k,n) = ZERO_8
            flduint (k,n) = ZERO_8
            fldvint (k,n) = ZERO_8
         enddo
         enddo
         do n = 1,V4dzga_npts
            fld2d(1,n) = ZERO_8
         enddo
         do k = 1,G_nk
         do n = 1,G_ni*G_nj
            zo(n,k) = ZERO_8 
            wo(n,k) = ZERO_8 
         enddo
         enddo
      endif
*
*     Adjoint of 
*     --------------------
*     Vector interpolation
*     --------------------
*
*     Adjoint of 
*     Global distribution
*     -------------------
      call rpn_comm_coll(wo,1,G_ni,1,G_nj,G_ni,G_nj,G_nk,0,0,1,
     %                   vt1,LDIST_DIM,G_halox,G_haloy,ier)
      call rpn_comm_coll(zo,1,G_ni,1,G_nj,G_ni,G_nj,G_nk,0,0,1,
     %                   ut1,LDIST_DIM,G_halox,G_haloy,ier)
*
*     Zero adjoint variables
*     ----------------------
      do k =1,Nk
      do j =l_miny,l_maxy
      do i =l_minx,l_maxx
         ut1(i,j,k) = ZERO_8
         vt1(i,j,k) = ZERO_8
      enddo
      enddo
      enddo
*
      if(Ptopo_myproc.eq.0) then
*
      if(.not.same_grid_L) then
*
*       Adjoint of
*       Reserve order of indices
*       ------------------------
        do k =1,Nk
        do n =1,V4dzga_npts
           fldvint(k,n) = wo(n,k) + fldvint(k,n)
           wo     (n,k) = ZERO_8 
           flduint(k,n) = zo(n,k) + flduint(k,n)
           zo     (n,k) = ZERO_8 
        end do
        end do
*
*       Adjoint of
*       -----------------------------------------------------
*       Preparation for polar correction and interpolation of
*       wind fields FLDU,FLDV at positions px,py
*       -----------------------------------------------------
        call v4d_uvint0_ad (flduint,fldvint,V4dzga_px,V4dzga_py,V4dzga_npts,
     %                      gut1,gvt1,V4dzga_ax,V4dzga_ay,V4dzga_cx,V4dzga_cy,
     %                      V4dzga_wx_8,V4dzga_cox_8,V4dzga_six_8,V4dzga_siy_8,
     %                      i1,i2,j1,j2,Nk,V4dzga_grtypi,V4dzga_degree,'UV')
*
      else
*
        do k = 1,Nk
        do j = 1,njgauss
        do i = 1,nigauss
           n = nigauss*(j-1) + i
           gvt1(i,j,k) = wo(n,k) + gvt1(i,j,k)
           gut1(i,j,k) = zo(n,k) + gut1(i,j,k)
           wo(n,k) = ZERO_8 
           zo(n,k) = ZERO_8 
        end do
        end do
        end do
*
      endif
*
      endif
*
*     Adjoint of
*     ----------------------------------------
*     Scalar interpolation of surface pressure
*     ----------------------------------------
*
*     Adjoint of
*     Global distribution
*     -------------------
      call rpn_comm_coll(zo,1,G_ni,1,G_nj,G_ni,G_nj,1,0,0,1,
     %                   st1, LDIST_DIM,G_halox,G_haloy,ier)
*
*     Zero adjoint variables
*     ----------------------
      do j =l_miny,l_maxy
      do i =l_minx,l_maxx
         st1(i,j) = ZERO_8
      enddo
      enddo
*
      if(Ptopo_myproc.eq.0) then
*
      if(.not.same_grid_L) then
*
*       Adjoint of
*       Reserve order of indices
*       ------------------------
        do n = 1,V4dzga_npts
           fld2d(1,n) = zo(n,1) + fld2d(1,n)
           zo   (n,1) = ZERO_8 
        end do
*
*       -----------------------------------------------------
*       Preparation for polar correction and interpolation of
*       scalar field FLDSC at positions px,py
*       -----------------------------------------------------
        call v4d_scint0_ad (    fld2d,V4dzga_px,V4dzga_py,V4dzga_npts,gst1,
     %                      V4dzga_ax,V4dzga_ay,V4dzga_cx,V4dzga_cy,V4dzga_wx_8,
     %                      i1,i2,j1,j2,1,V4dzga_grtypi,V4dzga_degree,'4S')
*
      else
*
        do j = 1,njgauss
        do i = 1,nigauss
           n = nigauss*(j-1) + i
           gst1(i,j) = zo(n,1) + gst1(i,j)
           zo(n,1) = ZERO_8
        end do
        end do
*
      endif
*
      endif
*
*     Adjoint of
*     --------------------------------
*     Scalar interpolation of humidity 
*     --------------------------------
*
*     Adjoint of
*     Global distribution
*     -------------------
      call rpn_comm_coll(zo,1,G_ni,1,G_nj,G_ni,G_nj,G_nk,0,0,1,
     %                   hut1,LDIST_DIM,G_halox,G_haloy,ier)
*
*     Zero adjoint variables
*     ----------------------
      do k =1,Nk
      do j =l_miny,l_maxy
      do i =l_minx,l_maxx
         hut1(i,j,k) = ZERO_8
      enddo
      enddo
      enddo
*
      if(Ptopo_myproc.eq.0) then
*
      if(.not.same_grid_L) then
*
*       Adjoint of
*       Reserve order of indices
*       ------------------------
        do k = 1,Nk
        do n = 1,V4dzga_npts
           fldscint(k,n) = zo(n,k) + fldscint(k,n)
           zo      (n,k) = ZERO_8
        end do
        end do
*
*       -----------------------------------------------------
*       Preparation for polar correction and interpolation of
*       scalar field FLDSC at positions px,py
*       -----------------------------------------------------
        call v4d_scint0_ad ( fldscint,V4dzga_px,V4dzga_py,V4dzga_npts,ghut1,
     %                      V4dzga_ax,V4dzga_ay,V4dzga_cx,V4dzga_cy,V4dzga_wx_8,
     %                      i1,i2,j1,j2,Nk,V4dzga_grtypi,V4dzga_degree,'HU')
*
      else  
*
        do k = 1,Nk
        do j = 1,njgauss
        do i = 1,nigauss
           n = nigauss*(j-1) + i
           ghut1(i,j,k) = zo(n,k) + ghut1(i,j,k)
           zo(n,k) = ZERO_8
        end do
        end do
        end do
*
      endif
*
      endif
*
*     Adjoint of
*     -----------------------------------
*     Scalar interpolation of temperature
*     -----------------------------------
*
*     Adjoint of
*     Global distribution
*     -------------------
      call rpn_comm_coll(zo,1,G_ni,1,G_nj,G_ni,G_nj,G_nk,0,0,1,
     %                   tpt1,LDIST_DIM,G_halox,G_haloy,ier)
*
*     Zero adjoint variables
*     ----------------------
      do k =1,Nk
      do j =l_miny,l_maxy
      do i =l_minx,l_maxx
         tpt1(i,j,k) = ZERO_8
      enddo
      enddo
      enddo
*
      if(Ptopo_myproc.eq.0) then
*
      if(.not.same_grid_L) then
*
*       Adjoint of
*       Reserve order of indices
*       ------------------------
        do k = 1,Nk
        do n = 1,V4dzga_npts
           fldscint(k,n) = zo(n,k) + fldscint(k,n)
           zo      (n,k) = ZERO_8 
        end do
        end do
*
*       -----------------------------------------------------
*       Preparation for polar correction and interpolation of
*       scalar field FLDSC at positions px,py
*       -----------------------------------------------------
        call v4d_scint0_ad ( fldscint,V4dzga_px,V4dzga_py,V4dzga_npts,gtpt1,
     %                      V4dzga_ax,V4dzga_ay,V4dzga_cx,V4dzga_cy,V4dzga_wx_8,
     %                      i1,i2,j1,j2,Nk,V4dzga_grtypi,V4dzga_degree,'4T')
*
      else
*
        do k = 1,Nk
        do j = 1,njgauss
        do i = 1,nigauss
           n = nigauss*(j-1) + i
           gtpt1(i,j,k) = zo(n,k) + gtpt1(i,j,k)
           zo(n,k) = ZERO_8
        end do
        end do
        end do
*
      endif
*
      endif
*
*     ------------
*     Deallocation
*     ------------
      if(Ptopo_myproc.eq.0) then
         deallocate( zo,      STAT=status )
         deallocate( wo,      STAT=status )
         deallocate( fldscint,STAT=status )
         deallocate( flduint, STAT=status )
         deallocate( fldvint, STAT=status )
         deallocate( fld2d,   STAT=status )
      endif
*
      return
      end