!======================================================================
! CROCO is a branch of ROMS developped at IRD, INRIA, 
! Ifremer, CNRS and Univ. Toulouse III  in France
! The two other branches from UCLA (Shchepetkin et al)
! and Rutgers University (Arango et al) are under MIT/X style license.
! CROCO specific routines (nesting) are under CeCILL-C license.
!
! CROCO website : http://www.croco-ocean.org
!======================================================================
!
#include "cppdefs.h"
#if defined SSH_TIDES || defined UV_TIDES || defined POT_TIDES
      subroutine clm_tides (tile)
!
!================================================== Robert Hetland ===
!  Copyright (c) 2000 Rutgers/UCLA                                   !
!================================================ Hernan G. Arango ===
!                                                                    !
!  This routine adds tidal elevation (m) and tidal currents (m/s) to !
!  sea surface height and 2D momentum climatologies, respectively.   !
!                                                                    !
!=====================================================================
!
      implicit none
      integer tile, trd, omp_get_thread_num
# include "param.h"
# include "private_scratch.h"
# include "compute_tile_bounds.h"
!
      trd=omp_get_thread_num()
      call clm_tides_tile (Istr,Iend,Jstr,Jend,
     &                     A2d(1,1,trd),A2d(1,2,trd),A2d(1,3,trd),
     &                     A2d(1,4,trd),A2d(1,5,trd),A2d(1,6,trd),
     &                                               A2d(1,7,trd))
      return
      end
!
!*********************************************************************
      subroutine clm_tides_tile (Istr,Iend,Jstr,Jend,Cangle,Sangle,
     &                           Cphase,Sphase,Etide,Utide,Vtide)
!*********************************************************************
!
# ifdef TIDES_MAS
      USE MOD_TIDES_MAS
# endif
      implicit none
# ifndef TIDES_MAS
#  include "param.h"
# endif
# include "climat.h"
# include "grid.h"
# include "scalars.h"
# include "tides.h"
# include "boundary.h"
!
# ifdef TIDES_MAS
      CHARACTER (len=19)    :: cdate,tool_sectodat
      logical :: flag=.false.
      INTEGER               :: ian,imois,ijour,iheure,iminu,isec,jjulien
      integer :: nn,l,k,kk
      INTEGER, dimension(0:10) :: esp_corres=(/1,2,3,4,5,0,6,0,7,0,8/)
# endif
      integer
     &     Iend, Istr, Jend, Jstr, i, j, itide
      real
     &     angle, phase, omega_loc, ramp, cff
      real
     &        Cangle(PRIVATE_2D_SCRATCH_ARRAY),
     &        Cphase(PRIVATE_2D_SCRATCH_ARRAY),
     &        Sangle(PRIVATE_2D_SCRATCH_ARRAY),
     &        Sphase(PRIVATE_2D_SCRATCH_ARRAY),
     &        Etide(PRIVATE_2D_SCRATCH_ARRAY),
     &        Utide(PRIVATE_2D_SCRATCH_ARRAY),
     &        Vtide(PRIVATE_2D_SCRATCH_ARRAY)
!
# include "compute_auxiliary_bounds.h"
# ifdef MPI
#  define IRANGE Istr-1,Iend+1
#  define JRANGE Jstr-1,Jend+1
# else
#  define IRANGE IstrR,IendR
#  define JRANGE JstrR,JendR
# endif
!
      angle=0.
      phase=0.
      ramp=1.
# ifdef TIDERAMP
      ramp=TANH(dt*sec2day*float(iic-1))
# endif
      cff=2.*pi*time
!
# if defined SSH_TIDES
#  ifdef TIDES_MAS
!-------------
! MAS INIT
!-------------
      IF (FIRST_RST_TIME_STEP) THEN
!$acc kernels if(compute_on_device) default(present)

! lecture des conditions aux limites
!-----------------------------------
! a faire une bonne fois pour toute
!----------------------------------
!
       IF (WESTERN_EDGE) THEN
        do j=JstrR,JendR
         num(:)=0
         rouest(:,:,j,:)=0.0
         gouest(:,:,j,:)=0.0
         nomd(:,:)=0
         fr1(:,:)=0.0
         fr2(:,:)=0.0
         do i=1,tide_nbharmcp
          if (l_presence(nu(i))) then
           nol=ide(nu(i))
           ir0=rr0(nu(i))
           ir1=rr1(nu(i))
           ir2=rr2(nu(i))
           k=esp_corres(int(nol/100000))
           num(k)=num(k)+1
           nn=num(k)
           do l=1,2
            rouest(nn,k,j,l)=SSH_Tamp(Istr+l-2,j,i)*100.0
            gouest(nn,k,j,l)=SSH_Tphase(Istr+l-2,j,i)
            nomd(nn,k)=nol
            if(ir0 < 0) gouest(nn,k,j,l)=gouest(nn,k,j,l)+180.0
            fr1(nn,k)=ir1/float(ir0)
            fr2(nn,k)=ir2/float(ir0)
            hnouest(129,j,l)=-999.
           end do
          endif
         end do
        end do
       ENDIF
!
       IF (EASTERN_EDGE) THEN
        do j=JstrR,JendR
         num(:)=0
         rest(:,:,j,:)=0.0
         gest(:,:,j,:)=0.0
         nomd(:,:)=0
         fr1(:,:)=0.0
         fr2(:,:)=0.0
         do i=1,tide_nbharmcp
          if (l_presence(nu(i))) then
           nol=ide(nu(i))
           ir0=rr0(nu(i))
           ir1=rr1(nu(i))
           ir2=rr2(nu(i))
           k=esp_corres(int(nol/100000))
           num(k)=num(k)+1
           nn=num(k)
           do l=1,2
            rest(nn,k,j,l)=SSH_Tamp(Iend+l-1,j,i)*100.0
            gest(nn,k,j,l)=SSH_Tphase(Iend+l-1,j,i)
            nomd(nn,k)=nol
            if(ir0 < 0) gest(nn,k,j,l)=gest(nn,k,j,l)+180.0
            fr1(nn,k)=ir1/float(ir0)
            fr2(nn,k)=ir2/float(ir0)
            hnest(129,j,l)=-999.
           end do
          endif
         end do
        end do
       ENDIF
!
       IF (NORTHERN_EDGE) THEN
        do i=IstrR,IendR
         num(:)=0
         rnord(:,:,i,:)=0.0
         gnord(:,:,i,:)=0.0
         fr1(:,:)=0.0
         fr2(:,:)=0.0
         do j=1,tide_nbharmcp
          if (l_presence(nu(j))) then
           nol=ide(nu(j))
           ir0=rr0(nu(j))
           ir1=rr1(nu(j))
           ir2=rr2(nu(j))
           k=esp_corres(int(nol/100000))
           num(k)=num(k)+1
           nn=num(k)
           do l=1,2
            rnord(nn,k,i,l)=SSH_Tamp(i,Jend+l-1,j)*100.0
            gnord(nn,k,i,l)=SSH_Tphase(i,Jend+l-1,j)
            if(ir0 < 0) gnord(nn,k,i,l)=gnord(nn,k,i,l)+180.0
            nomd(nn,k)=nol
            fr1(nn,k)=ir1/float(ir0)
            fr2(nn,k)=ir2/float(ir0)
            hnnord(129,i,l)=-999.
           end do
          end if
         end do
        end do
       ENDIF
!
       IF (SOUTHERN_EDGE) THEN
        do i=IstrR,IendR
         num(:)=0
         rsud(:,:,i,:)=0.0
         gsud(:,:,i,:)=0.0
         fr1(:,:)=0.0
         fr2(:,:)=0.0
         do j=1,tide_nbharmcp
          if (l_presence(nu(j))) then
           nol=ide(nu(j))
           ir0=rr0(nu(j))
           ir1=rr1(nu(j))
           ir2=rr2(nu(j))
           k=esp_corres(int(nol/100000))
           num(k)=num(k)+1
           nn=num(k)
           do l=1,2
            rsud(nn,k,i,l)=SSH_Tamp(i,Jstr+l-2,j)*100.0
            gsud(nn,k,i,l)=SSH_Tphase(i,Jstr+l-2,j)
            if(ir0 < 0) gsud(nn,k,i,l)=gsud(nn,k,i,l)+180.0
            nomd(nn,k)=nol
            fr1(nn,k)=ir1/float(ir0)
            fr2(nn,k)=ir2/float(ir0)
            hnsud(129,i,l)=-999.
           end do
          end if
         end do
        end do
       ENDIF

!$acc end kernels     
      ENDIF ! FIRST TIME STEP
#  endif /* MAS INIT */

#  ifndef TIDES_MAS
!$acc kernels if(compute_on_device) default(present)
!---------------------------------------------------------------------
!  Add tidal elevation (m) to sea surface height climatology.
!---------------------------------------------------------------------
!
      do j=JRANGE
        do i=IRANGE
          Etide(i,j)=0.
        enddo
      enddo
      do itide=1,Ntides
        if (Tperiod(itide).gt.0.) then
          omega_loc=cff/Tperiod(itide)
          do j=JRANGE
            do i=IRANGE
              Etide(i,j)=Etide(i,j)+ramp*
     &                   SSH_Tamp(i,j,itide)*
     &                   COS(omega_loc-SSH_Tphase(i,j,itide))
#   ifdef MASKING
              Etide(i,j)=Etide(i,j)*rmask(i,j)
#   endif
            enddo
          enddo
        endif
      enddo
!$acc end kernels      
#  else
!--------------------------------------------
! USE MAS COMPOSITION FOR HARMONIC PREDICTION
!--------------------------------------------
      cdate = tool_sectodat(time)
      CALL tool_decompdate(cdate,ijour,imois,ian,iheure,iminu,isec)
      tempis =iheure*3600.0+iminu*60.0+isec
!
! calcul des 128 hauteurs par jour
!---------------------------------
!
      t_0=0.0
      k=0
      if(ijour /= jourmem) then

       if (SOUTHERN_EDGE) then
        do i=IstrR,IendR
         do l=1,2
           if(rmask(i,Jstr+l-2)/=0)
     &      call ma1(flag,mynode,i,l,
     &    t_0,ijour,imois,ian,hnsud(1,i,l),rsud(1,1,i,l),
     &                 gsud(1,1,i,l),nomd,fr1,fr2,num)
         end do
        end do
       end if

       if (NORTHERN_EDGE) then
        do i=IstrR,IendR
         do l=1,2
           if(rmask(i,Jend+l-1)/=0)  then
             call ma1(flag,mynode,i,l,t_0,
     &                ijour,imois,ian,hnnord(1,i,l),rnord(1,1,i,l),
     &                gnord(1,1,i,l),nomd,fr1,fr2,num)
           end if
         end do
        end do
       end if

       if (WESTERN_EDGE) then
        do j=JstrR,JendR
         do l=1,2
           if(rmask(Istr+l-2,j)/=0)   then
             call ma1(flag,mynode,j,l,
     &            t_0,ijour,imois,ian,hnouest(1,j,l),rouest(1,1,j,l),
     &            gouest(1,1,j,l),nomd,fr1,fr2,num)
           endif
         end do
        end do
       end if

       if (EASTERN_EDGE) then
        do j=JstrR,JendR
         do l=1,2
           if(rmask(Iend+l-1,j)/=0)
     &     call ma1(flag,mynode,j,l
     &         ,t_0,ijour,imois,ian,hnest(1,j,l),rest(1,1,j,l),
     &         gest(1,1,j,l),nomd,fr1,fr2,num)
         end do
        end do
       end if

      end if

      jourmem=ijour

! interpolation parmi les 128 hauteurs par jour
!----------------------------------------------

       if (SOUTHERN_EDGE) then
        do i=IstrR,IendR
         do l=1,2
           if(rmask(i,Jstr+l-2)/=0)
     &        call ma7(flag,tempis,hnsud(1,i,l),Etide(i,Jstr+l-2),k)
         end do
        end do
       end if

       if (NORTHERN_EDGE) then
        do i=IstrR,IendR
         do l=1,2
           if(rmask(i,Jend+l-1)/=0) then
           call ma7(flag,tempis,hnnord(1,i,l),Etide(i,Jend+l-1),k)
           endif
         end do
        end do
       end if

       if (WESTERN_EDGE) then
        do j=JstrR,JendR
         do l=1,2
           if(rmask(Istr+l-2,j)/=0) then
            call ma7(flag,tempis,hnouest(1,j,l),Etide(Istr+l-2,j),k)
           endif
         end do
        end do
       end if

       if (EASTERN_EDGE) then
        do j=JstrR,JendR
         do l=1,2
           if(rmask(Iend+l-1,j)/=0)
     &       call ma7(flag,tempis,hnest(1,j,l),Etide(Iend+l-1,j),k)
         end do
        end do
       end if
#   ifdef MASKING
       do j=JRANGE
         do i=IRANGE
           Etide(i,j)=Etide(i,j)*ramp*rmask(i,j)
         end do
       end do
#   endif
!$acc end kernels
#  endif /* MAS COMPOSITION */
!$acc kernels if(compute_on_device) default(present)
!----------------------------------------------------------------
!  Add sub-tidal forcing and adjust climatology to include tides.
!----------------------------------------------------------------
#  if defined ZCLIMATOLOGY
      do j=JRANGE
        do i=IRANGE
          ssh(i,j)=ssh(i,j)+Etide(i,j)
#   ifdef WET_DRY
          if (ssh(i,j) .lt. Dcrit(i,j)-h(i,j)) then
            ssh(i,j)=Dcrit(i,j)-h(i,j)
          endif
#   endif
        enddo
      enddo
#  endif /* ZCLIMATOLOGY */
!----------------------------------------------------------------
!  If appropriate, load tidal forcing into boundary arrays.
!----------------------------------------------------------------
#  ifdef Z_FRC_BRY
#   if defined OBC_WEST
      if (WESTERN_EDGE) then
        do j=JstrR,JendR
          zetabry_west(j)=zetabry_west(j)+Etide(Istr-1,j)
#    ifdef WET_DRY
          if (zetabry_west(j) .lt. Dcrit(Istr-1,j)-h(Istr-1,j)) then
            zetabry_west(j)=Dcrit(Istr-1,j)-h(Istr-1,j)
          endif
#    endif
        enddo
      endif
#   endif
#   if defined OBC_EAST
      if (EASTERN_EDGE) then
        do j=JstrR,JendR
          zetabry_east(j)=zetabry_east(j)+Etide(Iend+1,j)
#    ifdef WET_DRY
          if (zetabry_east(j) .lt. Dcrit(Iend+1,j)-h(Iend+1,j)) then
            zetabry_east(j)=Dcrit(Iend+1,j)-h(Iend+1,j)
          endif
#    endif
        enddo
      endif
#   endif
#   if defined OBC_SOUTH
      if (SOUTHERN_EDGE) then
        do i=IstrR,IendR
          zetabry_south(i)=zetabry_south(i)+Etide(i,Jstr-1)
#    ifdef WET_DRY
          if (zetabry_south(i) .lt. Dcrit(i,Jstr-1)-h(i,Jstr-1)) then
            zetabry_south(i)=Dcrit(i,Jstr-1)-h(i,Jstr-1)
          endif
#    endif
        enddo
      endif
#   endif
#   if defined OBC_NORTH
      if (NORTHERN_EDGE) then
        do i=IstrR,IendR
          zetabry_north(i)=zetabry_north(i)+Etide(i,Jend+1)
#    ifdef WET_DRY
          if (zetabry_north(i) .lt. Dcrit(i,Jend+1)-h(i,Jend+1)) then
            zetabry_north(i)=Dcrit(i,Jend+1)-h(i,Jend+1)
          endif
#    endif
        enddo
      endif
#   endif
#  endif /* Z_FRC_BRY */
!$acc end kernels
# endif /* SSH_TIDES */
!
# if defined UV_TIDES
!$acc kernels if(compute_on_device) default(present)
!
!---------------------------------------------------------------------
!  Add tidal currents (m/s) to 2D momentum climatologies.
!---------------------------------------------------------------------
!
      do j=JstrR,JendR
        do i=Istr,IendR
          Utide(i,j)=0.
        enddo
      enddo
      do j=Jstr,JendR
        do i=IstrR,IendR
          Vtide(i,j)=0.
        enddo
      enddo
      do itide=1,Ntides
        if (Tperiod(itide).gt.0.) then
          omega_loc=cff/Tperiod(itide)
          do j=Jstr-1,JendR
            do i=Istr-1,IendR
              angle=UV_Tangle(i,j,itide)
#  ifdef CURVGRID
     &                      -angler(i,j)
#  endif
              phase=omega_loc-UV_Tphase(i,j,itide)
              Cangle(i,j)=COS(angle)
              Cphase(i,j)=COS(phase)
              Sangle(i,j)=SIN(angle)
              Sphase(i,j)=SIN(phase)
            enddo
          enddo
          do j=JstrR,JendR
            do i=Istr,IendR
              Utide(i,j)=Utide(i,j)+ramp*
     &                        0.125*((UV_Tmajor(i-1,j,itide)+
     &                                UV_Tmajor(i  ,j,itide))*
     &                               (Cangle(i-1,j)+Cangle(i,j))*
     &                               (Cphase(i-1,j)+Cphase(i,j))-
     &                               (UV_Tminor(i-1,j,itide)+
     &                                UV_Tminor(i  ,j,itide))*
     &                               (Sangle(i-1,j)+Sangle(i,j))*
     &                               (Sphase(i-1,j)+Sphase(i,j)))
#  ifdef MASKING
             Utide(i,j)=Utide(i,j)*umask(i,j)
#  endif
            enddo
          enddo
          do j=Jstr,JendR
            do i=IstrR,IendR
              Vtide(i,j)=Vtide(i,j)+ramp*
     &                        0.125*((UV_Tmajor(i,j-1,itide)+
     &                                UV_Tmajor(i,j  ,itide))*
     &                               (Sangle(i,j-1)+Sangle(i,j))*
     &                               (Cphase(i,j-1)+Cphase(i,j))+
     &                               (UV_Tminor(i,j-1,itide)+
     &                                UV_Tminor(i,j  ,itide))*
     &                               (Cangle(i,j-1)+Cangle(i,j))*
     &                               (Sphase(i,j-1)+Sphase(i,j)))
#  ifdef MASKING
              Vtide(i,j)=Vtide(i,j)*vmask(i,j)
#  endif
            enddo
          enddo
        endif
      enddo
#  if defined M2CLIMATOLOGY
!
!  Add sub-tidal forcing and adjust climatology to include tides.
!
      do j=JstrR,JendR
        do i=Istr,IendR
          ubclm(i,j)=ubclm(i,j)+Utide(i,j)
        enddo
      enddo
      do j=Jstr,JendR
        do i=IstrR,IendR
          vbclm(i,j)=vbclm(i,j)+Vtide(i,j)
        enddo
      enddo
#  endif
!
!  If appropriate, load tidal forcing into boundary arrays.
!
#  ifdef M2_FRC_BRY
#   ifdef OBC_WEST
      if (WESTERN_EDGE) THEN
        do j=JstrR,JendR
          ubarbry_west(j)=ubarbry_west(j)+Utide(Istr,j)
        enddo
        do j=Jstr,JendR
          vbarbry_west(j)=vbarbry_west(j)+Vtide(Istr-1,j)
        enddo
      endif
#   endif
#   ifdef OBC_EAST
      if (EASTERN_EDGE) THEN
        do j=JstrR,JendR
          ubarbry_east(j)=ubarbry_east(j)+Utide(Iend+1,j)
        enddo
        do j=Jstr,JendR
          vbarbry_east(j)=vbarbry_east(j)+Vtide(Iend+1,j)
        enddo
      endif
#   endif
#   ifdef OBC_SOUTH
      if (SOUTHERN_EDGE) THEN
        do i=Istr,IendR
          ubarbry_south(i)=ubarbry_south(i)+Utide(i,Jstr-1)
        enddo
        do i=IstrR,IendR
          vbarbry_south(i)=vbarbry_south(i)+Vtide(i,Jstr)
        enddo
      endif
#   endif
#   ifdef OBC_NORTH
      if (NORTHERN_EDGE) THEN
        do i=Istr,IendR
          ubarbry_north(i)=ubarbry_north(i)+Utide(i,Jend+1)
        enddo
        do i=IstrR,IendR
          vbarbry_north(i)=vbarbry_north(i)+Vtide(i,Jend+1)
        enddo
      endif
#   endif
#  endif /* M2_FRC_BRY */
!$acc end kernels
# endif /* UV_TIDES */

# if defined POT_TIDES
!$acc kernels if(compute_on_device) default(present)
!
!-----------------------------------------------------------------------
!  Compute tidal potential (m)
!  -- > to be applied as a pressure-gradient force
!       in prsgrd (if SOLVE3D) or step2d (if not SOLVE3D)
!-----------------------------------------------------------------------
!
      do j=JstrR,JendR
        do i=IstrR,IendR
          Ptide(i,j)=0.
        enddo
      enddo
      do itide=1,Ntides
        if (Tperiod(itide).gt.0.) then
          omega_loc=cff/Tperiod(itide)
          do j=JstrR,JendR
            do i=IstrR,IendR
              Ptide(i,j)=Ptide(i,j)+
     &                   ramp*POT_Tamp(i,j,itide)*
     &                   COS(omega_loc-POT_Tphase(i,j,itide))
#  ifdef MASKING
              Ptide(i,j)=Ptide(i,j)*rmask(i,j)
#  endif
            enddo
          enddo
        endif
      enddo

!$acc end kernels
#  if defined EW_PERIODIC || defined NS_PERIODIC || defined  MPI
      call exchange_r2d_tile (Istr,Iend,Jstr,Jend,
     &                        Ptide(START_2D_ARRAY))
#  endif

# endif /* POT_TIDES */

#else
      subroutine clm_tides_empty
#endif /* SSH_TIDES || UV_TIDES */
      return
      end
