!-------------------------------------- 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/r adw_trajsp_ad - ADJ of adw_trajsp_tl 
*
#include "model_macros_f.h"
*

      subroutine adw_trajsp_ad ( F_lon, F_lat, F_x, F_y, F_z, F_u, F_v, 2
     %                                  F_latm,F_xm,F_ym,F_zm,F_um,F_vm,
     %                           F_dt,i0,in,j0,jn)
*
      implicit none
*
      real F_lon (*),F_lat (*),F_x (*),F_y (*),F_z (*),F_u (*),F_v (*),F_dt
      real           F_latm(*),F_xm(*),F_ym(*),F_zm(*),F_um(*),F_vm(*)
      integer i0,in,j0,jn
*
*author
*     monique tanguay 
*
*revision
* v2_31 - Tanguay M.        - initial MPI version
* v3_00 - Tanguay M.        - adapt to restructured adw_main 
* v3_02 - Tanguay M.        - correction when abs(F_zm)=1
* v3_11 - Tanguay M.        - AIXport+Opti+OpenMP for TLM-ADJ
* v3_20 - Tanguay M.        - Move division when denominators are zero
*
*language
*     fortran 77
*
*object
*     see id section
*
*ADJ of
*arguments
*______________________________________________________________________
*              |                                                 |     |
* NAME         | DESCRIPTION                                     | I/O |
*--------------|-------------------------------------------------|-----|
*              |                                                 |     |
* F_lon        | upwind longitudes at central time               |  o  |
* F_lat        | upwind latitudes at central time                |  o  |
* F_x          | upwind x cartesian positions at central time    |  o  |
* F_y          | upwind y cartesian positions at central time    |  o  |
* F_z          | upwind z cartesian positions at central time    |  o  |
* F_u          | real E-W wind components at upwind positions    |  i  |
* F_v          | real N-S wind components at upwind positions    |  i  |
* F_dt         | timestep lenght                                 |  i  |
*______________|_________________________________________________|_____|
*
*implicits
#include "glb_ld.cdk"
#include "adw.cdk"
#include "dcst.cdk"
*
************************************************************************
      integer n, ij, nij, vnij, i, j, k
*
      real*8  pdsa_8, pdca_8, pdcai_8, pdso_8, pdco_8, pdx_8, pdy_8, pdz_8,
     %        pdux_8, pduy_8, pduz_8, pdsinal_8, pdcosal_8, r2pi_8, TWO_8, ZERO_8
*
      parameter (TWO_8 = 2.0)
      parameter (ZERO_8= 0.0)
*
      real*8  pdsam_8, pdcam_8, pdcaim_8, pdsom_8,    pdcom_8,
     %        pduxm_8, pduym_8, pduzm_8,  pdsinalm_8, pdcosalm_8,
     %        pduxm1_8,pduym1_8,pduzm1_8, pdsinalm1_8,pdsinalm2_8
*
      real*8  rsxyzm_8(i0:in,j0:jn), rxyzm_8
*
      real*8  xcosm_8(i0:in,j0:jn), ycosm_8(i0:in,j0:jn)
      real*8  xsinm_8(i0:in,j0:jn), ysinm_8(i0:in,j0:jn)
      real*8  yrecm_8(i0:in,j0:jn)
*
      real*8  cos2m_8 (i0:in,j0:jn), suv2m_8 (i0:in,j0:jn), sz2m_8 (i0:in,j0:jn)
      real*8  xy2m_8  (i0:in,j0:jn), slam_8  (i0:in,j0:jn)
      real*8  rcos2m_8(i0:in,j0:jn)
      real*8  rxy2m_8 (i0:in,j0:jn)
*
      real zm3
*
      real F_xm1(l_ni*l_nj*l_nk)
      real F_ym1(l_ni*l_nj*l_nk)
      real F_zm1(l_ni*l_nj*l_nk)
*
************************************************************************
      nij  = l_ni*l_nj
      vnij = (in-i0+1)*(jn-j0+1)
*
      r2pi_8 = TWO_8 * Dcst_pi_8
************************************************************************
*
*     Zero adjoint work space
*     -----------------------
      pdsa_8   = ZERO_8
      pdca_8   = ZERO_8
      pdcai_8  = ZERO_8
      pdso_8   = ZERO_8
      pdco_8   = ZERO_8
      pdux_8   = ZERO_8
      pduy_8   = ZERO_8
      pduz_8   = ZERO_8
      pdsinal_8= ZERO_8
      pdcosal_8= ZERO_8
*
*     START REBUILD TRAJECTORY
*     ------------------------
!$omp parallel do private (n,ij,
!$omp%   pdsa_8,pdca_8,pdcai_8,pdso_8,pdco_8,pdx_8,pdy_8,pdz_8,
!$omp%   pdux_8, pduy_8, pduz_8, pdsinal_8, pdcosal_8,
!$omp%   pdsam_8,pdcam_8,pdcaim_8,pdsom_8,pdcom_8,
!$omp%   pduxm_8,pduym_8,pduzm_8,pdsinalm_8,pdcosalm_8,
!$omp%   pduxm1_8,pduym1_8,pduzm1_8, pdsinalm1_8,pdsinalm2_8,
!$omp%   rsxyzm_8, rxyzm_8,
!$omp%   xcosm_8,ycosm_8,xsinm_8,ysinm_8,yrecm_8,
!$omp%   cos2m_8,suv2m_8,sz2m_8,xy2m_8,slam_8,
!$omp%   rcos2m_8,rxy2m_8,zm3)
      do k=l_nk,1,-1
*
*        Pre-calculations (START) 
*        ------------------------ 
         do j=j0,jn
         do i=i0,in
            n = (k-1)*nij + ((j-1)*l_ni) + i
*
            xcosm_8(i,j) = F_latm(n)
            suv2m_8(i,j) = sqrt( F_um(n) ** 2 + F_vm(n) ** 2 )
            xsinm_8(i,j) = suv2m_8(i,j) * F_dt
*
         end do
         end do
*
         call vcos(ycosm_8,  xcosm_8, vnij)
         call vsin(ysinm_8,  xsinm_8, vnij)
         call vrec(yrecm_8,  ycosm_8, vnij)
*
*        Pre-calculations (END) 
*        ---------------------- 
*
         do j=jn,j0,-1
         do i=in,i0,-1
         n = (k-1)*nij + ((j-1)*l_ni) + i
*
         ij = mod( n-1, nij ) + 1
************************************************************************
* cartesian coordinates of grid points                                 *
************************************************************************
         pdx_8 = Adw_cx2d_8(ij)
         pdy_8 = Adw_sx2d_8(ij)
         pdz_8 = Adw_sy2d_8(ij)
************************************************************************
* if very small wind set upwind point to grid point                    *
************************************************************************
         if ( abs(F_um(n))+abs(F_vm(n)) .ge. 1.e-10 ) then 
*
         pdx_8 = pdx_8 * Adw_cy2d_8(ij)
         pdy_8 = pdy_8 * Adw_cy2d_8(ij)
*
************************************************************************
* sin and cosin of first guess of upwind positions                     *
************************************************************************
         pdsam_8  = F_zm(n)
         pdcam_8  = ycosm_8(i,j) 
         pdcaim_8 = yrecm_8(i,j) 
         pdsom_8  = F_ym(n) * pdcaim_8
         pdcom_8  = F_xm(n) * pdcaim_8
*
************************************************************************
* wind components in cartesian coordinate at upwind positions          *
************************************************************************
         pduxm1_8 = ( - F_um(n) * pdsom_8 - F_vm(n) * pdcom_8 * pdsam_8 )
         pduym1_8 = (   F_um(n) * pdcom_8 - F_vm(n) * pdsom_8 * pdsam_8 )
         pduzm1_8 =     F_vm(n) * pdcam_8
*
         pdsinalm1_8 = pdx_8 * pduxm1_8 + pdy_8 * pduym1_8 + pdz_8 * pduzm1_8
         pduxm_8 = pduxm1_8 - pdx_8 * pdsinalm1_8
         pduym_8 = pduym1_8 - pdy_8 * pdsinalm1_8
         pduzm_8 = pduzm1_8 - pdz_8 * pdsinalm1_8
*
         rsxyzm_8(i,j)= 1./sqrt( pduxm_8 * pduxm_8 + pduym_8 * pduym_8 + pduzm_8 * pduzm_8 )
*
         pdcosalm_8  = sqrt( ( 1.0 + ysinm_8(i,j) ) * ( 1.0 - ysinm_8(i,j) ) )
         pdsinalm2_8 = ysinm_8(i,j) * rsxyzm_8(i,j) 
*
         F_xm1(n) = F_xm(n)
         F_ym1(n) = F_ym(n)
         F_zm1(n) = F_zm(n)
*
         F_xm(n) = pdcosalm_8 * pdx_8 - pdsinalm2_8 * pduxm_8
         F_ym(n) = pdcosalm_8 * pdy_8 - pdsinalm2_8 * pduym_8
         F_zm(n) = pdcosalm_8 * pdz_8 - pdsinalm2_8 * pduzm_8
*
         endif
*
         enddo
         enddo
*
*        Pre-calculations (START) 
*        ------------------------ 
         do j=j0,jn
         do i=i0,in
            n = (k-1)*nij + ((j-1)*l_ni) + i

            zm3 = F_zm(n)
*
            if ( F_zm(n) .lt. -1.0D0 ) then
                 zm3 = -1.0D0
            elseif ( F_zm(n) .gt.  1.0D0 ) then
                 zm3 =  1.0D0
            endif
*
            sz2m_8 (i,j) = sqrt(1.0 - zm3*zm3)
            xy2m_8 (i,j) = F_xm(n)*F_xm(n) + F_ym(n)*F_ym(n)
            cos2m_8(i,j) = ycosm_8(i,j) **2
*
         enddo
         enddo
*
         call vrec(rxy2m_8,  xy2m_8,  vnij)
         call vsin(slam_8,   xcosm_8, vnij)
         call vrec(rcos2m_8, cos2m_8, vnij)
*
*        Pre-calculations (END) 
*        ---------------------- 
*
*        END REBUILD TRAJECTORY
*        ----------------------
*
         do j=jn,j0,-1
         do i=in,i0,-1
         n = (k-1)*nij + ((j-1)*l_ni) + i
*
         ij = mod( n-1, nij ) + 1
*
*        ------------------------------------------------------------------
*        ADJOINT of DO LOOP
*        ------------------------------------------------------------------
*
*        TRAJECTORY
*        ----------
************************************************************************
* cartesian coordinates of grid points                                 *
************************************************************************
         pdx_8 = Adw_cx2d_8(ij)
         pdy_8 = Adw_sx2d_8(ij)
         pdz_8 = Adw_sy2d_8(ij)
*
         zm3 = F_zm(n)
*
         if ( F_zm(n) .lt. -1.0D0 ) then
            zm3 = -1.0D0
         elseif ( F_zm(n) .gt.  1.0D0 ) then
            zm3 =  1.0D0
         endif
*
*        ADJ
*        ---
         F_y(n)   =  F_xm(n)*F_lon(n)*rxy2m_8(i,j) + F_y(n)
         F_x(n)   = -F_ym(n)*F_lon(n)*rxy2m_8(i,j) + F_x(n)
         F_lon(n) = ZERO_8 
*
         if ( abs(zm3) .ne. 1.0D0 ) then
           F_z(n)   = F_lat(n) / sz2m_8(i,j) +  F_z(n)
           F_lat(n) = ZERO_8 
         else
           F_lat(n) = 0.0D0
         endif
*
         if ( F_zm(n) .lt. -1.0D0 ) then
           F_z (n) =  0.0D0
         elseif ( F_zm(n) .gt.  1.0D0 ) then
           F_z (n) =  0.0D0
         endif
*
************************************************************************
* if very small wind set upwind point to grid point                    *
************************************************************************
         if ( abs(F_um(n))+abs(F_vm(n)) .ge. 1.e-10 ) then 
*
*        TRAJECTORY
*        ----------
         pdx_8 = pdx_8 * Adw_cy2d_8(ij)
         pdy_8 = pdy_8 * Adw_cy2d_8(ij)
*
*        TRAJECTORY
*        ----------
************************************************************************
* sin and cosin of first guess of upwind positions                     *
************************************************************************
         pdsam_8  = F_zm1(n)
         pdcam_8  = ycosm_8(i,j) 
         pdcaim_8 = yrecm_8(i,j) 
         pdsom_8  = F_ym1(n) * pdcaim_8
         pdcom_8  = F_xm1(n) * pdcaim_8
*
*        TRAJECTORY
*        ----------
************************************************************************
* wind components in cartesian coordinate at upwind positions          *
************************************************************************
         pduxm1_8 = ( - F_um(n) * pdsom_8 - F_vm(n) * pdcom_8 * pdsam_8 )
         pduym1_8 = (   F_um(n) * pdcom_8 - F_vm(n) * pdsom_8 * pdsam_8 )
         pduzm1_8 = F_vm(n) * pdcam_8
*
*        TRAJECTORY
*        ----------
         pdsinalm1_8 = pdx_8 * pduxm1_8 + pdy_8 * pduym1_8 + pdz_8 * pduzm1_8
         pduxm_8     = pduxm1_8 - pdx_8 * pdsinalm1_8
         pduym_8     = pduym1_8 - pdy_8 * pdsinalm1_8
         pduzm_8     = pduzm1_8 - pdz_8 * pdsinalm1_8
*
         pdcosalm_8  = sqrt( ( 1.0 + ysinm_8(i,j) ) * ( 1.0 - ysinm_8(i,j) ) )
         pdsinalm2_8 = ysinm_8(i,j) * rsxyzm_8(i,j) 
*
         rxyzm_8     = 1./( pduxm_8 * pduxm_8 + pduym_8 * pduym_8 + pduzm_8 * pduzm_8 )
*
*        ADJ
*        ---
         pdcosal_8 =   F_x(n) * pdx_8
     %               + F_y(n) * pdy_8
     %               + F_z(n) * pdz_8
         pdsinal_8 = - F_x(n) * pduxm_8
     %               - F_y(n) * pduym_8
     %               - F_z(n) * pduzm_8
*
         pdux_8    = -pdsinalm2_8 * pduxm_8 * pdsinal_8 * rxyzm_8
     %               -pdsinalm2_8 * F_x(n)
*
         pduy_8    = -pdsinalm2_8 * pduym_8 * pdsinal_8 * rxyzm_8
     %               -pdsinalm2_8 * F_y(n)
*
         pduz_8    = -pdsinalm2_8 * pduzm_8 * pdsinal_8 * rxyzm_8
     %               -pdsinalm2_8 * F_z(n)
*
         pdsinal_8 = pdsinal_8 * rsxyzm_8(i,j) 
*
         F_u(n)  = -F_dt* ysinm_8(i,j)* F_um(n)*pdcosal_8/ suv2m_8(i,j) + F_u(n)
         F_v(n)  = -F_dt* ysinm_8(i,j)* F_vm(n)*pdcosal_8/ suv2m_8(i,j) + F_v(n)
         F_u(n)  =  F_dt* pdcosalm_8  * F_um(n)*pdsinal_8/ suv2m_8(i,j) + F_u(n)
         F_v(n)  =  F_dt* pdcosalm_8  * F_vm(n)*pdsinal_8/ suv2m_8(i,j) + F_v(n)
*
*        ADJ
*        ---
         pdsinal_8 = - pdx_8 * pdux_8 - pdy_8 * pduy_8 - pdz_8 * pduz_8
*
         pdux_8    = pdx_8 * pdsinal_8 + pdux_8
         pduy_8    = pdy_8 * pdsinal_8 + pduy_8
         pduz_8    = pdz_8 * pdsinal_8 + pduz_8
*
************************************************************************
* ADJ of
* wind components in cartesian coordinate at upwind positions          *
************************************************************************
         F_u(n)  =  - pdux_8 * pdsom_8
     %              + pduy_8 * pdcom_8 + F_u(n)
         F_v(n)  =  - pdux_8 * pdcom_8 * pdsam_8
     %              - pduy_8 * pdsom_8 * pdsam_8
     %              + pduz_8 * pdcam_8 + F_v(n)
*
         pdco_8  = - F_vm(n) *( pdux_8 * pdsam_8 )
     %             + F_um(n) *  pduy_8
         F_x(n)  = pdco_8 * pdcaim_8
*
         pdso_8  = - F_um(n) *  pdux_8
     %             - F_vm(n) *( pduy_8 * pdsam_8 )
         F_y(n)  = pdso_8 * pdcaim_8
*
************************************************************************
* ADJ of
* sin and cosin of first guess of upwind positions                     *
************************************************************************
         pdcai_8 = F_ym1(n) * pdso_8   +
     %             F_xm1(n) * pdco_8
         F_lat(n)= -slam_8(i,j) * (-pdcai_8  * rcos2m_8(i,j)  + F_vm(n) * pduz_8) 
*
         F_z(n)  = - F_vm(n) *( pdcom_8 * pdux_8 )
     %             - F_vm(n) *( pdsom_8 * pduy_8 )
*
      else
*
*     -------------
*     NOTHING TO DO
*     -------------
*
      endif
*
      enddo
      enddo
*
      enddo
!$omp end parallel do
*
      return
      end