!======================================================================
! 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
!======================================================================
!
#ifndef CHILD
!
# include "cppdefs.h"
# if defined SOLVE3D && defined TRACERS
      subroutine t3dbc_tile(Istr,Iend,Jstr,Jend,indx,itrc,grad)
#  ifdef AGRIF
      use Agrif_Util
      integer Istr,Iend,Jstr,Jend,indx,itrc
      real grad(PRIVATE_2D_SCRATCH_ARRAY)
      if (Agrif_Root()) then
        call t3dbc_parent_tile(Istr,Iend,Jstr,Jend,indx,itrc,grad)
      else
        call t3dbc_child_tile(Istr,Iend,Jstr,Jend,indx,itrc,grad)
c        call t3dbc_interp_tile(Istr,Iend,Jstr,Jend,indx,itrc)
      endif
      return
      end
!
! PARENT
!
      subroutine t3dbc_parent_tile(Istr,Iend,Jstr,Jend,indx,itrc,grad)
#  endif
!
! Set lateral boundary conditions for tracer field t(:,:,:,indx,itrc)
! for the parent grid.
!
# endif /* SOLVE3D */
#else
# if defined SOLVE3D && defined TRACERS
!
! CHILD
!
      subroutine t3dbc_child_tile(Istr,Iend,Jstr,Jend,indx,itrc,grad)
!
! Set lateral boundary conditions for tracer field t(:,:,:,indx,itrc)
! for the child grid.
!
# endif /* SOLVE3D */
#endif /* CHILD */
#if defined SOLVE3D && defined TRACERS
!
! Common Code
!
# include "set_obc_definitions.h"
!
      implicit none
# include "param.h"
# include "grid.h"
# include "ocean3d.h"
# include "climat.h"
# include "scalars.h"
# include "boundary.h"
      integer Istr,Iend,Jstr,Jend,indx,itrc,i,j,k
      real    grad(PRIVATE_2D_SCRATCH_ARRAY)
      real    eps, cff,
     &        cx,cy, dft,dfx,dfy, tau,tau_in,tau_out
      parameter (eps=1.E-20)
!
# include "compute_auxiliary_bounds.h"
!
! Interpolations of the parent values to get tbry_east or tclm
!
# ifdef CHILD
      call t3dbc_interp_tile(Istr,Iend,Jstr,Jend,indx,itrc)
# endif
!
# if defined T_FRC_BRY || defined TCLIMATOLOGY
      tau_in=dt*tauT_in
      tau_out=dt*tauT_out
# endif
!
!$acc kernels if(compute_on_device) default(present)
# ifndef EW_COM_PERIODIC
!
!====================================================================
!                            WESTERN BC
!====================================================================
      if (WESTERN_EDGE) then
#  if defined OBC_COM_WEST && (defined OBC_COM_TSPECIFIED || \
                               defined OBC_COM_TSPECIFIED_WEST)
!                                            Western edge Specified BC
!                                            ======= ==== ========= ==
        do k=1,N
          do j=Jstr,Jend
#   ifdef T_FRC_BRY
              t(Istr-1,j,k,indx,itrc)=tbry_west(j,k,itrc)
#   else
              t(Istr-1,j,k,indx,itrc)=tclm(Istr-1,j,k,itrc)
#   endif
#   ifdef MASKING
     &                                       *rmask(Istr-1,j)
#   endif
         enddo
        enddo
#  elif defined OBC_COM_WEST && defined OBC_COM_TORLANSKI
!                                           Western edge radiation BC
!                                           ======= ==== ========= ==
        do k=1,N
!$acc loop vector
          do j=Jstr,Jend+1
            grad(Istr-1,j)=( t(Istr-1,j  ,k,nstp,itrc)
     &                      -t(Istr-1,j-1,k,nstp,itrc))
#   ifdef MASKING
     &                                 *vmask(Istr-1,j)
#   endif
            grad(Istr  ,j)=( t(Istr  ,j  ,k,nstp,itrc)
     &                      -t(Istr  ,j-1,k,nstp,itrc))
#   ifdef MASKING
     &                                   *vmask(Istr,j)
#   endif
          enddo
!$acc loop vector
          do j=Jstr,Jend
            dft=t(Istr,j,k,nstp,itrc)-t(Istr  ,j,k,indx,itrc)
            dfx=t(Istr,j,k,indx,itrc)-t(Istr+1,j,k,indx,itrc)

            if (dfx*dft .lt. 0.) then
              dft=0.                  ! <-- cancel, if inflow
#   if defined T_FRC_BRY || defined TCLIMATOLOGY
              tau=tau_in
            else
              tau=tau_out
#   endif
            endif
            if (dft*(grad(Istr,j)+grad(Istr,j+1)) .gt. 0.) then
              dfy=grad(Istr,j)
            else
              dfy=grad(Istr,j+1)
            endif
            cff=max(dfx*dfx+dfy*dfy, eps)
            cx=dft*dfx
            cy=min(cff,max(dft*dfy,-cff))
            t(Istr-1,j,k,indx,itrc)=(  cff*t(Istr-1,j,k,nstp,itrc)
     &                                   +cx*t(Istr,j,k,indx,itrc)
     &                                -max(cy,0.)*grad(Istr-1,j  )
     &                                -min(cy,0.)*grad(Istr-1,j+1)
     &                                                  )/(cff+cx)
#   if defined T_FRC_BRY || defined TCLIMATOLOGY
            t(Istr-1,j,k,indx,itrc)=(1.-tau)*t(Istr-1,j,k,indx,itrc)
#    ifdef T_FRC_BRY
     &                                    +tau*tbry_west(j,k,itrc)
#    else
     &                                    +tau*tclm(Istr-1,j,k,itrc)
#    endif
#   endif
#   ifdef MASKING
            t(Istr-1,j,k,indx,itrc)=t(Istr-1,j,k,indx,itrc)
     &                                      *rmask(Istr-1,j)
#   endif
          enddo
        enddo
#  elif defined OBC_COM_WEST && defined OBC_COM_TUPWIND
!                                               Western edge Upwind BC
!                                               ======= ==== ====== ==
        do k=1,N
          do j=Jstr,Jend
            if (u(Istr+1,j,k,nstp).lt.0.) then
              t(Istr-1,j,k,indx,itrc)=t(Istr,j,k,indx,itrc)
#   ifdef T_FRC_BRY
              t(Istr-1,j,k,indx,itrc)=tbry_west(j,k,itrc)
#   endif
            else
#   ifdef T_FRC_BRY
              t(Istr-1,j,k,indx,itrc)=tbry_west(j,k,itrc)
#   else
              t(Istr-1,j,k,indx,itrc)=tclm(Istr-1,j,k,itrc)
#   endif
           endif
#   ifdef MASKING
              t(Istr-1,j,k,indx,itrc)=t(Istr-1,j,k,indx,itrc)
     &                                       *rmask(Istr-1,j)
#   endif
         enddo
        enddo
!
#  else
        do k=1,N
          do j=Jstr,Jend
!                                            Western edge gradient BC
!                                            ======= ==== ======== ==
            t(Istr-1,j,k,indx,itrc)=t(Istr,j,k,indx,itrc)
#   ifdef MASKING
     &                              *rmask(Istr-1,j)
#   endif
          enddo
        enddo
#  endif
      endif     ! <-- WESTERN_EDGE
!
!====================================================================
!                            EASTERN BC
!====================================================================
      if (EASTERN_EDGE) then
#  if defined OBC_COM_EAST && (defined OBC_COM_TSPECIFIED || \
                               defined OBC_COM_TSPECIFIED_EAST)
!                                            Eastern edge Specified BC
!                                            ======= ==== ========= ==
        do k=1,N
          do j=Jstr,Jend
#   ifdef T_FRC_BRY
            t(Iend+1,j,k,indx,itrc)=tbry_east(j,k,itrc)
#   else
            t(Iend+1,j,k,indx,itrc)=tclm(Iend+1,j,k,itrc)
#   endif
#   ifdef MASKING
     &                                   *rmask(Iend+1,j)
#   endif
          enddo
        enddo
#  elif defined OBC_COM_EAST && defined OBC_COM_TORLANSKI
!                                           Eastern edge radiation BC
!                                           ======= ==== ========= ==
        do k=1,N
!$acc loop vector
          do j=Jstr,Jend+1
           grad(Iend  ,j)=( t(Iend  ,j  ,k,nstp,itrc)
     &                     -t(Iend  ,j-1,k,nstp,itrc))
#   ifdef MASKING
     &                                  *vmask(Iend,j)
#   endif
           grad(Iend+1,j)=( t(Iend+1,j  ,k,nstp,itrc)
     &                     -t(Iend+1,j-1,k,nstp,itrc))
#   ifdef MASKING
     &                                *vmask(Iend+1,j)
#   endif
          enddo
!$acc loop vector
          do j=Jstr,Jend
            dft=t(Iend,j,k,nstp,itrc)-t(Iend  ,j,k,indx,itrc)
            dfx=t(Iend,j,k,indx,itrc)-t(Iend-1,j,k,indx,itrc)
            if (dfx*dft .lt. 0.) then
              dft=0.                  ! <-- cancel, if inflow
#   if defined T_FRC_BRY || defined TCLIMATOLOGY
              tau=tau_in
            else
              tau=tau_out
#   endif
            endif
            if (dft*(grad(Iend,j)+grad(Iend,j+1)) .gt. 0.) then
              dfy=grad(Iend,j)
            else
              dfy=grad(Iend,j+1)
            endif
            cff=max(dfx*dfx+dfy*dfy, eps)
            cx=dft*dfx
            cy=min(cff,max(dft*dfy,-cff))
            t(Iend+1,j,k,indx,itrc)=(  cff*t(Iend+1,j,k,nstp,itrc)
     &                                   +cx*t(Iend,j,k,indx,itrc)
     &                                -max(cy,0.)*grad(Iend+1,j  )
     &                                -min(cy,0.)*grad(Iend+1,j+1)
     &                                                  )/(cff+cx)
#   if defined T_FRC_BRY || defined TCLIMATOLOGY
            t(Iend+1,j,k,indx,itrc)=(1.-tau)*t(Iend+1,j,k,indx,itrc)
#    ifdef T_FRC_BRY
     &                                      +tau*tbry_east(j,k,itrc)
#    else
     &                                    +tau*tclm(Iend+1,j,k,itrc)
#    endif
#   endif
#   ifdef MASKING
            t(Iend+1,j,k,indx,itrc)=t(Iend+1,j,k,indx,itrc)
     &                                     *rmask(Iend+1,j)
#   endif
          enddo
        enddo
#  elif defined OBC_COM_EAST && defined OBC_COM_TUPWIND
!                                            Eastern edge Upwind BC
!                                            ======= ==== ====== ==
        do k=1,N
          do j=Jstr,Jend
            if (u(Iend-1,j,k,nstp).gt.0.) then
              t(Iend+1,j,k,indx,itrc)=t(Iend,j,k,indx,itrc)
            else
#   ifdef T_FRC_BRY
              t(Iend+1,j,k,indx,itrc)=tbry_east(j,k,itrc)
#   else
              t(Iend+1,j,k,indx,itrc)=tclm(Iend+1,j,k,itrc)
#   endif
            endif
#   ifdef MASKING
              t(Iend+1,j,k,indx,itrc)=t(Iend+1,j,k,indx,itrc)
     &                                       *rmask(Iend+1,j)
#   endif
          enddo
        enddo
!
#  else
!                                            Eastern edge gradient BC
!                                            ======= ==== ======== ==
        do k=1,N
          do j=Jstr,Jend
            t(Iend+1,j,k,indx,itrc)=t(Iend,j,k,indx,itrc)
#   ifdef MASKING
     &                                   *rmask(Iend+1,j)
#   endif
          enddo
        enddo
#  endif
      endif    ! <-- EASTERN_EDGE
# endif        /* !EW_COM_PERIODIC */

# ifndef NS_COM_PERIODIC
!
!====================================================================
!                            SOUTHERN BC
!====================================================================
      if (SOUTHERN_EDGE) then
#  if defined OBC_COM_SOUTH && (defined OBC_COM_TSPECIFIED || \
                                defined OBC_COM_TSPECIFIED_SOUTH)
!                                           Southern edge Specified BC
!                                           ======== ==== ========= ==
        do k=1,N
          do i=Istr,Iend
#   ifdef T_FRC_BRY
            t(i,Jstr-1,k,indx,itrc)=tbry_south(i,k,itrc)
#   else
            t(i,Jstr-1,k,indx,itrc)=tclm(i,Jstr-1,k,itrc)
#   endif
#   ifdef MASKING
     &                                   *rmask(i,Jstr-1)
#   endif
          enddo
        enddo
#  elif defined OBC_COM_SOUTH && defined OBC_COM_TORLANSKI
!                                          Southern edge radiation BC
!                                          ======== ==== ========= ==
        do k=1,N
          do i=Istr,Iend+1
            grad(i,Jstr  )=( t(i  ,Jstr  ,k,nstp,itrc)
     &                      -t(i-1,Jstr  ,k,nstp,itrc))
#   ifdef MASKING
     &                                   *umask(i,Jstr)
#   endif
            grad(i,Jstr-1)=( t(i  ,Jstr-1,k,nstp,itrc)
     &                      -t(i-1,Jstr-1,k,nstp,itrc))
#   ifdef MASKING
     &                                *umask(i,Jstr-1)
#   endif
          enddo
          do i=Istr,Iend
            dft=t(i,Jstr,k,nstp,itrc)-t(i,Jstr  ,k,indx,itrc)
            dfx=t(i,Jstr,k,indx,itrc)-t(i,Jstr+1,k,indx,itrc)
            if (dfx*dft .lt. 0.) then
              dft=0.                   ! <-- cancel, if inflow
#   if defined T_FRC_BRY || defined TCLIMATOLOGY
              tau=tau_in
            else
              tau=tau_out
#   endif
            endif
            if (dft*(grad(i,Jstr)+grad(i+1,Jstr)) .gt. 0.) then
              dfy=grad(i,Jstr)
            else
              dfy=grad(i+1,Jstr)
            endif
            cff=max(dfx*dfx+dfy*dfy, eps)
            cx=dft*dfx
            cy=min(cff,max(dft*dfy,-cff))
            t(i,Jstr-1,k,indx,itrc)=(  cff*t(i,Jstr-1,k,nstp,itrc)
     &                                   +cx*t(i,Jstr,k,indx,itrc)
     &                                -max(cy,0.)*grad(i  ,Jstr-1)
     &                                -min(cy,0.)*grad(i+1,Jstr-1)
     &                                                  )/(cff+cx)
#   if defined T_FRC_BRY || defined TCLIMATOLOGY
            t(i,Jstr-1,k,indx,itrc)=(1.-tau)*t(i,Jstr-1,k,indx,itrc)
#    ifdef T_FRC_BRY
     &                                     +tau*tbry_south(i,k,itrc)
#    else
     &                                    +tau*tclm(i,Jstr-1,k,itrc)
#    endif
#   endif
#   ifdef MASKING
            t(i,Jstr-1,k,indx,itrc)=t(i,Jstr-1,k,indx,itrc)
     &                                     *rmask(i,Jstr-1)
#   endif
          enddo
        enddo
#  elif defined OBC_COM_SOUTH && defined OBC_COM_TUPWIND
!                                           Southern edge Upwind BC
!                                           ======== ==== ====== ==
        do k=1,N
          do i=Istr,Iend
            if (v(i,Jstr+1,k,nstp).lt.0.) then
              t(i,Jstr-1,k,indx,itrc)=t(i,Jstr,k,indx,itrc)
            else
#   ifdef T_FRC_BRY
              t(i,Jstr-1,k,indx,itrc)=tbry_south(i,k,itrc)
#   else
              t(i,Jstr-1,k,indx,itrc)=tclm(i,Jstr-1,k,itrc)
#   endif
            endif
#   ifdef MASKING
              t(i,Jstr-1,k,indx,itrc)=t(i,Jstr-1,k,indx,itrc)
     &                                       *rmask(i,Jstr-1)
#   endif
          enddo
        enddo
!
#  else
!                                           Southern edge gradient BC
!                                           ======== ==== ======== ==
        do k=1,N
          do i=Istr,Iend
            t(i,Jstr-1,k,indx,itrc)=t(i,Jstr,k,indx,itrc)
#   ifdef MASKING
     &                                   *rmask(i,Jstr-1)
#   endif
          enddo
        enddo
#  endif
      endif    ! <-- SOUTHERN_EDGE
!
!====================================================================
!                            NORTHERN BC
!====================================================================
      if (NORTHERN_EDGE) then
#  if defined OBC_COM_NORTH && (defined OBC_COM_TSPECIFIED || \
                                defined OBC_COM_TSPECIFIED_NORTH)
!                                           Northern edge Specified BC
!                                           ======== ==== ========= ==
        do k=1,N
          do i=Istr,Iend
#   ifdef T_FRC_BRY
            t(i,Jend+1,k,indx,itrc)=tbry_north(i,k,itrc)
#   else
            t(i,Jend+1,k,indx,itrc)=tclm(i,Jend+1,k,itrc)
#   endif
#   ifdef MASKING
     &                                   *rmask(i,Jend+1)
#   endif
          enddo
        enddo

#  elif defined OBC_COM_NORTH && defined OBC_COM_TORLANSKI
!                                          Northern edge radiation BC
!                                          ======== ==== ========= ==
        do k=1,N
          do i=Istr,Iend+1
            grad(i,Jend  )=( t(i  ,Jend  ,k,nstp,itrc)
     &                      -t(i-1,Jend  ,k,nstp,itrc))
#   ifdef MASKING
     &                                   *umask(i,Jend)
#   endif
            grad(i,Jend+1)=( t(i  ,Jend+1,k,nstp,itrc)
     &                      -t(i-1,Jend+1,k,nstp,itrc))
#   ifdef MASKING
     &                                 *umask(i,Jend+1)
#   endif
          enddo
          do i=Istr,Iend
            dft=t(i,Jend,k,nstp,itrc)-t(i,Jend  ,k,indx,itrc)
            dfx=t(i,Jend,k,indx,itrc)-t(i,Jend-1,k,indx,itrc)
            if (dfx*dft .lt. 0.) then
              dft=0.                          ! <-- cancel, if inflow
#   if defined T_FRC_BRY || defined TCLIMATOLOGY
              tau=tau_in
            else
              tau=tau_out
#   endif
            endif
            if (dft*(grad(i,Jend)+grad(i+1,Jend)) .gt. 0.) then
              dfy=grad(i,Jend)
            else
              dfy=grad(i+1,Jend)
            endif
            cff=max(dfx*dfx+dfy*dfy, eps)
            cx=dft*dfx
            cy=min(cff,max(dft*dfy,-cff))
            t(i,Jend+1,k,indx,itrc)=( cff*t(i,Jend+1,k,nstp,itrc)
     &                                 +cx*t(i,Jend  ,k,indx,itrc)
     &                                -max(cy,0.)*grad(i  ,Jend+1)
     &                                -min(cy,0.)*grad(i+1,Jend+1)
     &                                                 )/(cff+cx)
#   if defined T_FRC_BRY || defined TCLIMATOLOGY
            t(i,Jend+1,k,indx,itrc)=(1.-tau)*t(i,Jend+1,k,indx,itrc)
#    ifdef T_FRC_BRY
     &                                     +tau*tbry_north(i,k,itrc)
#    else
     &                                    +tau*tclm(i,Jend+1,k,itrc)
#    endif
#   endif
#   ifdef MASKING
            t(i,Jend+1,k,indx,itrc)=t(i,Jend+1,k,indx,itrc)
     &                                     *rmask(i,Jend+1)
#   endif
          enddo
        enddo
#  elif defined OBC_COM_NORTH && defined OBC_COM_TUPWIND
!                                           Northern edge Upwind BC
!                                           ======== ==== ====== ==
        do k=1,N
          do i=Istr,Iend
            if (v(i,Jend-1,k,nstp).gt.0.) then
              t(i,Jend+1,k,indx,itrc)=t(i,Jend,k,indx,itrc)
            else
#   ifdef T_FRC_BRY
              t(i,Jend+1,k,indx,itrc)=tbry_north(i,k,itrc)
#   else
              t(i,Jend+1,k,indx,itrc)=tclm(i,Jend+1,k,itrc)
#   endif
            endif
#   ifdef MASKING
              t(i,Jend+1,k,indx,itrc)=t(i,Jend+1,k,indx,itrc)
     &                                       *rmask(i,Jend+1)
#   endif
          enddo
        enddo
!
#  else
!                                           Northern edge gradient BC
!                                           ======== ==== ======== ==
        do k=1,N
          do i=Istr,Iend
            t(i,Jend+1,k,indx,itrc)=t(i,Jend,k,indx,itrc)
#   ifdef MASKING
     &                                   *rmask(i,Jend+1)
#   endif
          enddo
        enddo
#  endif
      endif    ! <-- NORTHERN_EDGE
# endif /* ! NS_COM_PERIODIC */

                           ! Corners between adjacent open boundaries
                           ! ======= ======= ======== ==== ==========

# if defined OBC_COM_SOUTH && defined OBC_COM_WEST
      if (SOUTHERN_EDGE .and. WESTERN_EDGE) then
        do k=1,N
          t(Istr-1,Jstr-1,k,indx,itrc)=0.5*
     &                          ( t(Istr,Jstr-1,k,indx,itrc)
     &                           +t(Istr-1,Jstr,k,indx,itrc))
#  ifdef MASKING
     &                                 *rmask(Istr-1,Jstr-1)
#  endif
        enddo
      endif
# endif
# if defined OBC_COM_SOUTH && defined OBC_COM_EAST
      if (SOUTHERN_EDGE .and. EASTERN_EDGE) then
        do k=1,N
          t(Iend+1,Jstr-1,k,indx,itrc)=0.5*
     &                          (t(Iend,Jstr-1,k,indx,itrc)
     &                          +t(Iend+1,Jstr,k,indx,itrc))
#  ifdef MASKING
     &                                 *rmask(Iend+1,Jstr-1)
#  endif
        enddo
      endif
# endif
# if defined OBC_COM_NORTH && defined OBC_COM_WEST
      if (NORTHERN_EDGE .and. WESTERN_EDGE) then
        do k=1,N
          t(Istr-1,Jend+1,k,indx,itrc)=0.5*
     &                          ( t(Istr,Jend+1,k,indx,itrc)
     &                           +t(Istr-1,Jend,k,indx,itrc))
#  ifdef MASKING
     &                                 *rmask(Istr-1,Jend+1)
#  endif
        enddo
      endif
# endif
# if defined OBC_COM_NORTH && defined OBC_COM_EAST
      if (NORTHERN_EDGE .and. EASTERN_EDGE) then
        do k=1,N
          t(Iend+1,Jend+1,k,indx,itrc)=0.5*
     &                          ( t(Iend,Jend+1,k,indx,itrc)
     &                           +t(Iend+1,Jend,k,indx,itrc))
#  ifdef MASKING
     &                                 *rmask(Iend+1,Jend+1)
#  endif
        enddo
      endif
# endif
!$acc end kernels
      return
      end
#else
      subroutine t3dbc_empty
      end
#endif /* SOLVE3D */
#ifndef CHILD
# define CHILD
# ifdef AGRIF
#  include "t3dbc.F"
# endif
# undef CHILD
#endif  /* !CHILD */
