    
!=======================================================================
!      Different advection schemes for buoyancy and other tracers
!=======================================================================


subroutine adv_flux(nx_,ny_,nz_,adv_fe,adv_fn,adv_ft,var)
!=======================================================================
!       advective tracer flux:  call different schemes
!=======================================================================
      use pyOM_module   
      implicit none
      real*8 :: adv_fe(nx_,ny_,nz_), adv_ft(nx_,ny_,nz_)
      real*8 :: adv_fn(nx_,ny_,nz_), var(nx_,ny_,nz_,3)
      integer :: nx_,ny_,nz_

      if (enable_quicker_advection) then
       call setcyclic3D_j2(nx_,ny_,nz_,var(:,:,:,taum1) )
       call adv_flux_quicker(nx_,ny_,nz_,adv_fe,adv_fn,adv_ft,var)
      else if (enable_4th_advection) then
       call setcyclic3D_j2(nx_,ny_,nz_,var(:,:,:,tau) )
       call adv_flux_4th(nx_,ny_,nz_,adv_fe,adv_fn,adv_ft,var)
      else if (enable_upwind_advection) then
       call adv_flux_upw(nx_,ny_,nz_,adv_fe,adv_fn,adv_ft,var)
      else
       call adv_flux_2th(nx_,ny_,nz_,adv_fe,adv_fn,adv_ft,var)
      endif
end subroutine adv_flux




subroutine adv_flux_2th(nx_,ny_,nz_,adv_fe,adv_fn,adv_ft,var)
!=======================================================================
!      2th order advective tracer flux
!=======================================================================
      use pyOM_module   
      implicit none
      integer :: i,j,k,js,je
      integer :: nx_,ny_,nz_
      real*8 :: adv_fe(nx_,ny_,nz_), adv_ft(nx_,ny_,nz_)
      real*8 :: adv_fn(nx_,ny_,nz_), var(nx_,ny_,nz_,3)
      real*8 :: totvel

      js=max(2,js_pe); je = min(je_pe,ny-1)
      do k=2,nz-1
       do j=js,je
        do i=1,nx-1
         totvel = u(i,j,k,tau)
         adv_fe(i,j,k)=0.5*(var(i,j,k,tau) + var(i+1,j,k,tau) )*totvel*maskU(i,j,k)
        enddo
       enddo
      enddo
      do k=2,nz-1
       do j=js,je
        do i=2,nx-1
         totvel = v(i,j,k,tau)
         adv_fn(i,j,k)=0.5*( var(i,j,k,tau) + var(i,j+1,k,tau) )*totvel*maskV(i,j,k)
        enddo
       enddo
      enddo
      do k=1,nz-1
       do j=js,je
        do i=2,nx-1
         totvel = w(i,j,k,tau)
         adv_ft(i,j,k)=0.5*( var(i,j,k,tau) + var(i,j,k+1,tau) )*totvel*maskW(i,j,k)
        enddo
       enddo
      enddo
end subroutine adv_flux_2th





subroutine adv_flux_4th(nx_,ny_,nz_,adv_fe,adv_fn,adv_ft,var)
!=======================================================================
!      4th order advective tracer flux
!      author:   r.c.pacanowski       e-mail rcp@gfdl.gov
!=======================================================================
      use pyOM_module   
      implicit none
      integer :: nx_,ny_,nz_
      real*8 :: adv_fe(nx_,ny_,nz_), adv_ft(nx_,ny_,nz_)
      real*8 :: adv_fn(nx_,ny_,nz_), var(nx_,ny_,nz_,3)
      integer :: i,j,k,js,je,ip2,im1,jp2,jm1,kp2,km1
      real*8,parameter  :: a2nd = 1.0,     b2nd = 0.0
      real*8,parameter  :: a4th = 7.0/6.0, b4th = -1.0/6.0
      real*8 :: mask

      js=max(2,js_pe); je=min(je_pe,ny-1)

      do j=js,je
       do k=2,nz-1
        do i=1,nx-1
         ip2=i+2
         if (ip2>nx.and..not.enable_cyclic_x) ip2=nx
         if (ip2>nx.and.     enable_cyclic_x) ip2=3
         im1=i-1
         if (im1<1.and..not. enable_cyclic_x) im1=1
         if (im1<1.and.      enable_cyclic_x) im1=nx-2
         mask = maskT(im1,j,k)*maskT(ip2,j,k)
         adv_fe(i,j,k) = 0.5*u(i,j,k,tau)*( &
             (a2nd*(1.0-mask) + a4th*mask)*(var(i,  j,k,tau) +var(i+1,j,k,tau))+ &
             (b2nd*(1.0-mask) + b4th*mask)*(var(im1,j,k,tau) +var(ip2,j,k,tau)))
        enddo
       enddo
      enddo

      do j=js,je
       do k=2,nz-1
        do i=2,nx-1
         jp2=j+2
         if (jp2>ny.and..not.enable_cyclic_y) jp2=ny
         if (jp2>ny.and.     enable_cyclic_y) jp2=3
         jm1=j-1
         if (jm1<1.and..not. enable_cyclic_y) jm1=1
         if (jm1<1.and.      enable_cyclic_y) jm1=ny-2
         mask = maskT(i,jm1,k)*maskT(i,jp2,k)
         adv_fn(i,j,k) = 0.5*v(i,j,k,tau)*(  &
             (a2nd*(1.0-mask) + a4th*mask)*(var(i,  j,k,tau) + var(i,j+1,k,tau))+  &
             (b2nd*(1.0-mask) + b4th*mask)*(var(i,jm1,k,tau) + var(i,jp2,k,tau)))
        enddo
       enddo
      enddo
 
      do j=js,je
       do k=1,nz-1
        do i=2,nx-1
         kp2=min(k+2,nz)
         km1=max(1,k-1)
         mask = maskT(i,j,km1)*maskT(i,j,kp2)
         adv_ft(i,j,k) = 0.5*w(i,j,k,tau)*(   &
               (a2nd*(1.0-mask) + a4th*mask)*(var(i,j,  k,tau) + var(i,j,k+1,tau))+   &
               (b2nd*(1.0-mask) + b4th*mask)*(var(i,j,km1,tau) + var(i,j,kp2,tau)))
        enddo
       enddo
      enddo

end subroutine adv_flux_4th






subroutine adv_flux_quicker(nx_,ny_,nz_,adv_fe,adv_fn,adv_ft,var)
!=======================================================================
!      3th order advective tracer flux
!=======================================================================
      use pyOM_module   
      implicit none
      integer :: nx_,ny_,nz_
      real*8 :: adv_fe(nx_,ny_,nz_), adv_ft(nx_,ny_,nz_)
      real*8 :: adv_fn(nx_,ny_,nz_), var(nx_,ny_,nz_,3)
      integer :: i,j,k,ip2,jp2,kp2,im1,jm1,km1,js,je
      real*8 :: totvel,upos,uneg,eastmsk,westmsk

      js=max(2,js_pe); je = min(je_pe,ny-1)
      do k=2,nz-1
       do j=js,je
        do i=1,nx-1
         ip2=i+2
         if (ip2>nx.and..not.enable_cyclic_x) ip2=nx
         if (ip2>nx.and.     enable_cyclic_x) ip2=3
         im1=i-1
         if (im1<1.and..not. enable_cyclic_x) im1=1
         if (im1<1.and.      enable_cyclic_x) im1=nx-2

         totvel = u(i,j,k,tau)
         upos = .5*(totvel + abs(totvel))  *maskt(i,j,k)*maskt(i+1,j,k)
         uneg = .5*(totvel - abs(totvel))  *maskt(i+1,j,k)*maskt(i,j,k)
         eastmsk=maskt(i,j,k)*(1-maskt(im1,j,k))
         westmsk=maskt(i+1,j,k)*(1-maskt(ip2,j,k))
         adv_fe(i,j,k) = 0.5*totvel*(var(i,j,k,tau)+var(i+1,j,k,tau))    &
              - 0.5*upos*(0.25*var(i+1,j,k,taum1)-0.5*var(i,j,k,taum1)    &
                     +0.25*(var(im1,j,k,taum1)*(1-eastmsk) +var(i,j,k,taum1)*eastmsk))    &
              - 0.5*uneg*(0.25*(var(ip2,j,k,taum1)*(1-westmsk)+    &
                var(i+1,j,k,taum1)*westmsk)-0.5*var(i+1,j,k,taum1) +0.25*var(i,j,k,taum1))
          enddo
        enddo
      enddo
      do k=2,nz-1
       do j=js,je
        do i=2,nx-1
         jp2=j+2
         if (jp2>ny.and..not.enable_cyclic_y) jp2=ny
         if (jp2>ny.and.     enable_cyclic_y) jp2=3
         jm1=j-1
         if (jm1<1.and..not. enable_cyclic_y) jm1=1
         if (jm1<1.and.      enable_cyclic_y) jm1=ny-2

         totvel = v(i,j,k,tau)
         upos = .5*(totvel + abs(totvel))  *maskt(i,j,k)*maskt(i,j+1,k)
         uneg = .5*(totvel - abs(totvel))  *maskt(i,j+1,k)*maskt(i,j,k)
         eastmsk=maskt(i,j,k)*(1-maskt(i,jm1,k))
         westmsk=maskt(i,j+1,k)*(1-maskt(i,jp2,k))
         adv_fn(i,j,k) = 0.5*totvel*(var(i,j,k,tau)+var(i,j+1,k,tau))    &
              - 0.5*upos*(0.25*var(i,j+1,k,taum1)-0.5*var(i,j,k,taum1)    &
                     +0.25*(var(i,jm1,k,taum1)*(1-eastmsk) +var(i,j,k,taum1)*eastmsk))    &
              - 0.5*uneg*(0.25*(var(i,jp2,k,taum1)*(1-westmsk)+    &
                var(i,j+1,k,taum1)*westmsk)-0.5*var(i,j+1,k,taum1)  +0.25*var(i,j,k,taum1))
          enddo
        enddo
      enddo
      do k=1,nz-1
       do j=js,je
        do i=2,nx-1
         kp2=min(k+2,nz)
         km1=max(1,k-1)
         totvel = w(i,j,k,tau)
         upos = .5*(totvel + abs(totvel))     *maskt(i,j,k)*maskt(i,j,k+1)
         uneg = .5*(totvel - abs(totvel))     *maskt(i,j,k+1)*maskt(i,j,k)
         eastmsk=maskt(i,j,k)*(1-maskt(i,j,km1))
         westmsk=maskt(i,j,k+1)*(1-maskt(i,j,kp2))
         adv_ft(i,j,k) = 0.5*totvel*(var(i,j,k,tau)+var(i,j,k+1,tau))    &
              - 0.5*upos*(0.25*var(i,j,k+1,taum1)-0.5*var(i,j,k,taum1)    &
                     +0.25*(var(i,j,km1,taum1)*(1-eastmsk)   +var(i,j,k,taum1)*eastmsk))    &
              - 0.5*uneg*(0.25*(var(i,j,kp2,taum1)*(1-westmsk)+    &
                var(i,j,k+1,taum1)*westmsk)-0.5*var(i,j,k+1,taum1)  +0.25*var(i,j,k,taum1))
          enddo
        enddo
      enddo
end subroutine adv_flux_quicker




subroutine adv_flux_upw(nx_,ny_,nz_,adv_fe,adv_fn,adv_ft,var)
!=======================================================================
!        upwind tracer flux:   F = U b^i 
!=======================================================================
      use pyOM_module   
      implicit none
      integer :: nx_,ny_,nz_
      real*8 :: adv_fe(nx_,ny_,nz_), adv_ft(nx_,ny_,nz_)
      real*8 :: adv_fn(nx_,ny_,nz_), var(nx_,ny_,nz_,3)
      integer :: i,j,k,js,je
      real*8 :: totvel

      js=max(2,js_pe); je = min(je_pe,ny-1)
      do k=2,nz-1
       do j=js,je
        do i=1,nx-1
         totvel = u(i,j,k,tau)
         adv_fe(i,j,k)=maskU(i,j,k)*(0.5*totvel*(var(i,j,k,taum1)+var(i+1,j,k,taum1)) &
         - 0.5*abs(totvel)*(var(i+1,j,k,taum1)-var(i,j,k,taum1) ) )
        enddo
       enddo
      enddo
      do k=2,nz-1
       do j=js,je
        do i=2,nx-1
         totvel = v(i,j,k,tau)
         adv_fn(i,j,k)=maskV(i,j,k)*(0.5*totvel*(var(i,j,k,taum1)+var(i,j+1,k,taum1))  &
         - 0.5*abs(totvel)*(var(i,j+1,k,taum1)-var(i,j,k,taum1) ) )
        enddo
       enddo
      enddo
      do k=1,nz-1
       do j=js,je
        do i=2,nx-1
         totvel = w(i,j,k,tau)
         adv_ft(i,j,k)=maskW(i,j,k)*( 0.5*totvel*(var(i,j,k,taum1)+var(i,j,k+1,taum1))  &
         - 0.5*abs(totvel)*(var(i,j,k+1,taum1)-var(i,j,k,taum1) ) )
        enddo
       enddo
      enddo
end subroutine adv_flux_upw



