!======================================================================
! 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"
#ifdef RANDOM_WALK

      subroutine random_walk (indx,nfltmax)
      implicit none
# include "param.h"
# include "grid.h"
# include "floats.h"
# include "scalars.h"
# include "ocean3d.h"
# ifdef RANDOM_VERTICAL
#  include "mixing.h"
# endif

      integer i,k,ierr,iseed,ifix,jfix,zfix
      integer nfltmax,indx(nfltmax), iflt
      real randz(nfltmax+1), deltaw
# ifdef DIEL_MIGRATION
      real tofday, wflag, wmig
# endif
# ifdef RANDOM_HORIZONTAL
      real kh, epsl, lxy, deltau
# endif
      integer i1,i2, j1,j2, k1,k2
      real p1,p2, q1,q2, r1,r2,znow
     & ,d1, d2, temp, sum,temp2,maxdepth

!  in the case of some larvae (e.g. crab) the
!  vertical migration is limited by some maximum
!  in depth

      maxdepth=-60.

# ifdef IBM
      if(ibmdata(ibmzoe,iflt).eq.1.) then
        maxdepth =-18.
      elseif(ibmdata(ibmzoe,iflt).eq.2.) then
        maxdepth =-18.
      elseif(ibmdata(ibmzoe,iflt).eq.3.) then
        maxdepth =-21.
      elseif(ibmdata(ibmzoe,iflt).eq.4.) then
        maxdepth =-27.
      elseif(ibmdata(ibmzoe,iflt).eq.5.) then
        maxdepth =-30.
      endif
# endif

!
!  We calculate a velocity fluctuation based on a
!  a random number (uniformly distribute between  [0 1])
!  scaled by the vertical tracer mixing Ak and its vertical gradient
!
!  deltaw=sqrt(2*Akt/dt)*random_n+(dAkt/dz)
!

!
!  A similar estimate is done for the horiz. diffusion
!  using Kh = epsl(1/3) L(4/3) we take epsl = 10-7
!  L will be the larges unresolved scale. Here
!  we use (grid cell)/2.0
!
# ifdef RANDOM_HORIZONTAL
      epsl=.0000001
# endif

# ifdef DIEL_MIGRATION

!  A wmig is added in case of forced (time dependent)
!  vertical migration. Particles sink from 10 - 12 pm.
!  and rise from 4 -6 am. The rising process is not so
!  dramatic as the the sinking one. Some of the particles
!  do not surface completely. To simulate that in the surfacing
!  phase we add a random fluctuation.

      tofday=tdays-int(tdays)
      if(tofday.gt.0.9167 .and. tofday.lt.1) then
        wflag =  1.
      elseif(tofday.gt.0.1667 .and. tofday.lt.0.25) then
        wflag =  -1.
      else
        wflag = 0.
      endif
# endif

# if defined RANDOM_VERTICAL || defined RANDOM_HORIZONTAL
! calculate random number varing a "seed" with tdays
! wich will be stored in vector of with the same size
! of the number of floats. NOTE: the firts element of the vector
! is fixed and is not used

      do i=1,nfltmax+1
       randz(i)=0.
      enddo

      iseed = int(tdays*10+
     &  track(ixgrd,nfp1,1)*10+
     &  track(iygrd,nfp1,1)*10+
     &  track(izgrd,nfp1,1)*10)
      call urng (iseed, randz, nfltmax+1, ierr)
# endif

      do i=1,nfltmax
        iflt=indx(i)
        ifix=int(track(ixgrd,nfp1,iflt))
        d1=track(ixgrd,nfp1,iflt)-ifix
        jfix=int(track(iygrd,nfp1,iflt))
        d2=track(iygrd,nfp1,iflt)-jfix
        zfix=int(track(izgrd,nfp1,iflt))

        deltaw=0.
# ifdef RANDOM_VERTICAL
        deltaw=sqrt(2.*max(Akt(ifix,jfix,zfix,1),0.)/dt)*
     &         (randz(i+1)*2.-1.) +dAktdz(ifix,jfix,zfix)

! In future interpolate Akt dAktdz to float position.
c       write(*,*)iflt,randz(i+1),dAktdz(ifix,jfix,zfix),
c    &          Akt(ifix,jfix,zfix,1),deltaw

# endif

# ifdef DIEL_MIGRATION
        if(wflag.ne.0.) then
! scale vertical velocity by depth
          wmig = wflag*30./(60.*60.)    ! 30 m./ hour
          if(wflag.lt.0.) then
            deltaw=wmig
          else
!           deltaw=wmig
            deltaw=deltaw+0.7*wmig+0.3*wmig*(randz(i+1)*2.-1.)
!           deltaw=deltaw+wmig+0.5*wmig*(randz(i+1)*2.-1.)
          endif
        endif
# endif

!
! Calculate new vertical float position. First gets former
! position and adds the random displacement
!
! get actual depth.

        znow=0.

c       write(*,*) ' RANDOM WALK '
c       write(*,*) 'track(izgrd)', track(izgrd,nfp1,iflt)
c       write(*,*) 'Random displacement ', deltaw*dt

        k1=int(track(izgrd,nfp1,iflt))
        r2=track(izgrd,nfp1,iflt) - float(k1)
        r1=1.-r2
        k1=max(k1,   0)
        k2=min(k1+1, N)

        i1=int(track(ixgrd,nfp1,iflt))
        i2=i1+1
        p2=track(ixgrd,nfp1,iflt)-float(i1)
        p1=1.-p2

        j1=int(track(iygrd,nfp1,iflt))
        j2=j1+1
        q2=track(iygrd,nfp1,iflt)-float(j1)
        q1=1.0-q2

        znow=p1*q1*(r1*z_w(i1,j1,k1)+r2*z_w(i1,j1,k2))
     &              +p2*q1*(r1*z_w(i2,j1,k1)+r2*z_w(i2,j1,k2))
     &              +p1*q2*(r1*z_w(i1,j2,k1)+r2*z_w(i1,j2,k2))
     &              +p2*q2*(r1*z_w(i2,j2,k1)+r2*z_w(i2,j2,k2))

c       write(*,*) 'ZNOW ', znow
        znow=znow+deltaw*dt
c       write(*,*) 'ZNOW upgraded', znow

! put some limits to znow to prevent having values above sea level
! and under bot.

        znow=max(z_w(ifix,jfix,1),znow)
!       znow=min(z_w(ifix,jfix,N)-z_w(ifix,jfix,N)*0.02,znow)
        znow=min(z_w(ifix,jfix,N-1),znow)
# ifdef DIEL_MIGRATION
        znow=max(znow,maxdepth)
# endif

! use Capet code to get new sigma level for the float

        track(izgrd,nfp1,iflt)=0.
        sum=0.
        do k1=0,1
          ifix=ifix+k1
          do k2=0,1
            jfix=jfix+k2
            temp=((1-k1)*(1-d1)+k1*d1)*
     &           ((1-k2)*(1-d2)+k2*d2)
            sum=sum+temp
            do k=N,1,-1
             if ((z_w(ifix,jfix,k)-znow)*
     &              (znow-z_w(ifix,jfix,k-1)).ge.0.0) then
                temp2=(float(k-1)+
     &              (znow-z_w(ifix,jfix,k-1))/Hz(ifix,jfix,k))
                track(izgrd,nfp1,iflt)=track(izgrd,nfp1,iflt)+temp2*
     &                            temp

             endif
            enddo !  -> k
          enddo !  -> k2
        enddo !  -> k1
        if (sum .ne. 0) then
          track(izgrd,nfp1,iflt)=track(izgrd,nfp1,iflt)/sum
        endif
        track(izgrd,nfp1,iflt)=max(0.,min(float(N),
     &                     track(izgrd,nfp1,iflt)))
c       write(*,*) 'new track ', track(izgrd,nfp1,iflt)

# ifdef RANDOM_HORIZONTAL
! calculate the horizontal random walk and scale by grid cell size

        lxy =((1./pn(ifix,jfix))+(1./pm(ifix,jfix)))/2.
        kh  = epsl**(1./3.)*lxy**(4./3.)

        deltau=sqrt(2.*kh/dt)*(randz(i+1)*2.-1.)
     &        *tanh(dt*sec2day*float(iic-ntstart))
        track(ixgrd,nfp1,iflt)=track(ixgrd,nfp1,iflt)+
     &       deltau*umask(ifix,jfix)*dt/lxy

! to have different rand numb. in the directions
! we use the inverse of the random number vector in
! y direction

        deltau=sqrt(2.*kh/dt)*(randz(nfltmax+1-i+1)*2.-1.)
     &        *tanh(dt*sec2day*float(iic-ntstart))
        track(iygrd,nfp1,iflt)=track(iygrd,nfp1,iflt)+
     &       deltau*vmask(ifix,jfix)*dt/lxy
!
! These random horizontal excursions are not isopycnal
! In a way they also generate some vertical random variability
!
# endif

      enddo !  -> nfltmax

      end !  -> random_walk

      subroutine urng (ix, x, n, ierr)
!
!=======================================================================
!                                                                      !
!  Uniform random-number generator from the NSWC Library               !
!                                                                      !
!  Uses the recursion ix = ix*a mod p, where 0 < ix < p                !
!                                                                      !
!  Written by Linus Schrage, University of Chicago. Adapted for NSWC   !
!  Library by A. H. Morris. Modernised & included in ROMS by Mark      !
!  Hadfield, NIWA.                                                     !
!                                                                      !
!=======================================================================
!
!  Imported variable declarations.
!
      integer, intent(in) :: n

      integer, intent(inout) :: ix

      integer, intent(out) :: ierr

!#ifdef ASSUMED_SHAPE
!      real(8), intent(out) :: x(:)
!#else
      real(8), intent(out) :: x(n)
!#endif
!
!  Local variable declarations.
!
      integer, parameter :: a = 16807          ! 7^5
      integer, parameter :: b15 = 32768        ! 2^15
      integer, parameter :: b16 = 65536        ! 2^16
      integer, parameter :: p = 2147483647     ! 2^31-1

      integer :: fhi, k, l, leftlo, xalo, xhi

      real(8), parameter :: s = 0.465661E-09
!
!-----------------------------------------------------------------------
!  Generate random numbers.
!-----------------------------------------------------------------------
!

      if (n.le.0) then
        ierr=1
        return
      endif
      if ((ix.le.0).or.(ix.ge.p)) then
         ierr=2
         return
      endif
!
      ierr=0
!
      do l=1,n
!
! Get 15 high order bits of "ix".
!
        xhi=ix/b16
!
! Get 16 lower bits of ix and multiply with "a".
!
        xalo=(ix-xhi*b16)*a
!
! Get 15 high order bits of the product.
!
        leftlo=xalo/b16
!
! Form the 31 highest bits of "a*ix".
!
        fhi=xhi*a+leftlo
!
! Obtain the overflow past the 31st bit of "a*ix".
!
        k=fhi/b15
!
! Assemble all the parts and presubtract "p". The parentheses are
! essential.
!
        ix=(((xalo-leftlo*b16)-p)+(fhi-k*b15)*b16)+k
!
! Add "p" if necessary.
!
        if (ix.lt.0) ix=ix+p
!
! Rescale "ix", to interpret it as a value between 0 and 1.
! the scale factor "s" is selected to be as near "1/p" as is
! appropriate in order that the floating value for "ix = 1",
! namely "s", be roughly the same distance from 0 as "(p-1)*s"
! is from 1. The current value for "s" assures us that "x(l)"
! is less than 1 for any floating point arithmetic of 6
! or more digits.
!
         x(l)=real(ix,8)*s
      enddo
      return
      end

#else
      subroutine random_walk_empty
      end
#endif    /* RANDOM_WALK */
