Subversion Repositories lagranto.icon

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

      PROGRAM caltra

C     ********************************************************************
C     *                                                                  *
C     * Calculates trajectories                                          *
C     *                                                                  *
C     * Heini Wernli       first version:       April 1993               *
C     * Michael Sprenger   major upgrade:       2008-2009                *
C     *                                                                  *
C     ********************************************************************

      implicit none
      
c     --------------------------------------------------------------------
c     Declaration of parameters
c     --------------------------------------------------------------------

c     Maximum number of levels for input files
      integer   nlevmax
      parameter (nlevmax=100)

c     Maximum number of input files (dates, length of trajectories)
      integer   ndatmax
      parameter (ndatmax=500)

c     Numerical epsilon (for float comparison)
      real      eps
      parameter (eps=0.001)

c     Distance in m between 2 lat circles 
      real      deltay
      parameter (deltay=1.112E5)
      
c     Numerical method for the integration (0=iterative Euler, 1=Runge-Kutta)
      integer   imethod
      parameter (imethod=1)

c     Number of iterations for iterative Euler scheme
      integer   numit
      parameter (numit=3)

c     Input and output format for trajectories (see iotra.f)
      integer   inpmode
      integer   outmode

c     Filename prefix (typically 'P')
      character*1 prefix
      parameter   (prefix='P')

c     --------------------------------------------------------------------
c     Declaration of variables
c     --------------------------------------------------------------------

c     Input parameters
      integer                                fbflag          ! Flag for forward/backward mode
      integer                                numdat          ! Number of input files
      character*13                           dat(ndatmax)    ! Dates of input files
      real                                   timeinc         ! Time increment between input files
      real                                   per             ! Periodicity (=0 if none)
      integer                                ntra            ! Number of trajectories
      character*80                           cdfname         ! Name of output files
      real                                   ts              ! Time step
      real                                   tst,ten         ! Shift of start and end time relative to first data file
      integer                                deltout         ! Output time interval (in minutes)
      integer                                jflag           ! Jump flag (if =1 ground-touching trajectories reenter atmosphere)
      real                                   wfactor         ! Factor for vertical velocity field
      character*80                           strname         ! File with start positions
      character*80                           timecheck       ! Either 'yes' or 'no'
      real                                   balloon         ! vertical velocity for balloon sounding

c     Trajectories
      integer                                ncol            ! Number of columns for insput trajectories
      real,allocatable, dimension (:,:,:) :: trainp          ! Input start coordinates (ntra,1,ncol)
      real,allocatable, dimension (:,:,:) :: traout          ! Output trajectories (ntra,ntim,4)
      integer                                reftime(6)      ! Reference date
      character*80                           vars(200)       ! Field names
      real,allocatable, dimension (:)     :: xx0,yy0,pp0     ! Position of air parcels
      integer,allocatable, dimension (:)  :: leftflag        ! Flag for domain-leaving
      real                                   xx1,yy1,pp1     ! Updated position of air parcel
      integer                                leftcount       ! Number of domain leaving trajectories
      integer                                ntim            ! Number of output time steps

c     Meteorological fields
      real,allocatable, dimension (:)     :: uut0,uut1       ! Zonal wind
      real,allocatable, dimension (:)     :: vvt0,vvt1       ! Meridional wind
      real,allocatable, dimension (:)     :: wwt0,wwt1       ! Vertical wind

c     Grid description
      real,allocatable, dimension (:)     :: zuv,zw         ! 3d-model height for U, V, W grid
      real,allocatable, dimension (:)     :: zb             ! Surface height

      real                                   pollon,pollat   ! Longitude/latitude of pole
      real                                   polgam          ! Rotation of grid
      real                                   xmin,xmax       ! Zonal grid extension
      real                                   ymin,ymax       ! Meridional grid extension
      integer                                nx,ny,nz        ! Grid dimensions
      real                                   dx,dy           ! Horizontal grid resolution
      integer                                hem             ! Flag for hemispheric domain
      real                                   mdv             ! Missing data value
      integer                                fflag           ! Fplane flag (0/1)
      real                                   lat_fixed       ! fixed latitude for fplane

c     Auxiliary variables                 
      real                                   delta,rd
      integer                                itm,iloop,i,j,k,filo,lalo
      integer                                ierr,stat
      integer                                cdfid,fid
      real                                       tstart,time0,time1,time
      real                                   reltpos0,reltpos1
      real                                   xind,yind,pind,pp,sp,stagz
      character*80                           filename,varname
      integer                                reftmp(6)
      character                              ch
      real                                   frac,tload
      integer                                itim
      real                                   lon,lat,rlon,rlat

c     Externals 
      real                                   lmtolms        ! Grid rotation
      real                                   phtophs    
      real                                   lmstolm
      real                                   phstoph        
      external                               lmtolms,phtophs
      external                               lmstolm,phstoph
      real                                   phi2phirot
      real                                   phirot2phi
      real                                   rla2rlarot
      real                                   rlarot2rla
      external                               phi2phirot,phirot2phi
      external                               rla2rlarot,rlarot2rla

c     --------------------------------------------------------------------
c     Start of program, Read parameters
c     --------------------------------------------------------------------

c     Write start message
      print*,'========================================================='
      print*,'              *** START OF PROGRAM CALTRA ***'
      print*

c     Open the parameter file
      open(9,file='caltra.param')

c     Read flag for forward/backward mode (fbflag)
      read(9,*) fbflag

c     Read number of input files (numdat)
      read(9,*) numdat
      if (numdat.gt.ndatmax) then
        print*,' ERROR: too many input files ',numdat,ndatmax
        goto 993
      endif

c     Read list of input dates (dat, sort depending on forward/backward mode)
      if (fbflag.eq.1) then
        do itm=1,numdat
          read(9,'(a)') dat(itm)
        enddo
      else
        do itm=numdat,1,-1
          read(9,'(a)') dat(itm)
        enddo
      endif

c     Read time increment between input files (timeinc)
      read(9,*) timeinc

C     Read if data domain is periodic and its periodicity
      read(9,*) per

c     Read the number of trajectories and name of position file
      read(9,*) strname
      read(9,*) ntra
      read(9,*) ncol 
      if (ntra.eq.0) goto 991

C     Read the name of the output trajectory file and set the constants file
      read(9,*) cdfname

C     Read the timestep for trajectory calculation (convert from minutes to hours)
      read(9,*) ts
      ts=ts/60.        

C     Read shift of start and end time relative to first data file
      read(9,*) tst
      read(9,*) ten

C     Read output time interval (in minutes)
      read(9,*) deltout

C     Read jumpflag (if =1 ground-touching trajectories reenter the atmosphere)
      read(9,*) jflag

C     Read factor for vertical velocity field
      read(9,*) wfactor

c     Read the reference time and the time range
      read(9,*) reftime(1)                  ! year
      read(9,*) reftime(2)                  ! month
      read(9,*) reftime(3)                  ! day
      read(9,*) reftime(4)                  ! hour
      read(9,*) reftime(5)                  ! min
      read(9,*) reftime(6)                  ! time range (in min)

c     Read flag for 'no time check'
      read(9,*) timecheck

c     Read in fplane option and latitude
      read(9,*) fflag                       ! fplane flag (1/0)                         ! if fflag=1 -> fplane
      read(9,*) lat_fixed                   ! fixed latitude for f-plane

c     Read in vertical velocity for balloon sounding
      read(9,*) balloon                     ! will be added to vertical wind, in [m/s]

c     Close the input file
      close(9)

c     Calculate the number of output time steps
      ntim = abs(reftime(6)/deltout) + 1

c     Set the formats of the input and output files
      call mode_tra(inpmode,strname)
      call mode_tra(outmode,cdfname)
      if (outmode.eq.-1) outmode=1

c     Write some status information
      print*,'---- INPUT PARAMETERS -----------------------------------'
      print* 
      print*,'  Forward/Backward       : ',fbflag
      print*,'  #input files           : ',numdat
      print*,'  First/last input file  : ',trim(dat(1)),' ... ',
     >                                     trim(dat(numdat))
      print*,'  time increment         : ',timeinc
      print*,'  Output file            : ',trim(cdfname)
      print*,'  Time step (min)        : ',60.*ts
      write(*,'(a27,f7.2,f7.2)') '   Time shift (start,end) : ',tst,ten
      print*,'  Output time interval   : ',deltout
      print*,'  Jump flag              : ',jflag
      print*,'  Vertical wind (scale)  : ',wfactor
      print*,'  Trajectory pos file    : ',trim(strname)
      print*,'  # of trajectories      : ',ntra
      print*,'  # of output timesteps  : ',ntim
      if ( inpmode.eq.-1) then
         print*,'  Input format           : (lon,lat,p)-list'
      else
         print*,'  Input format           : ',inpmode
      endif
      print*,'  Output format          : ',outmode
      print*,'  Periodicity            : ',per
      print*,'  Time check             : ',trim(timecheck)
      if ( abs(balloon).gt.eps ) then
         print*
         print*,'  WARNING -> Lagranto in Sounding Mode'
         print*
         print*,'  Balloon velocity [m/s] : ',balloon
      endif
      print*

      print*,'---- FIXED NUMERICAL PARAMETERS -------------------------'
      print*
      print*,'  Numerical scheme       : ',imethod
      print*,'  Number of iterations   : ',numit
      print*,'  Filename prefix        : ',prefix
      print*,'  Missing data value     : ',mdv
      print*

c     Run a simple consistency check
      call do_timecheck(dat,numdat,timeinc,fbflag,reftime)

c     --------------------------------------------------------------------
c     Read grid parameters, checks and allocate memory
c     --------------------------------------------------------------------

c     Read the constant grid parameters (nx,ny,nz,xmin,xmax,ymin,ymax,pollon,pollat)
c     The negative <-fid> of the file identifier is used as a flag for parameter retrieval  
      filename = prefix//dat(1)
      varname  = 'U'
      nx       = 1
      ny       = 1
      nz       = 1
      tload   = -tst
      call input_open (fid,filename)
      call input_grid (-fid,varname,xmin,xmax,ymin,ymax,dx,dy,nx,ny,
     >                 tload,pollon,pollat,polgam,rd,rd,nz,rd,timecheck)
      call input_close(fid)

C     Check if the number of levels is too large
      if (nz.gt.nlevmax) goto 993

C     Set logical flag for periodic data set (hemispheric or not)
      hem = 0
      if (per.eq.0.) then
         delta=xmax-xmin-360.
         if (abs(delta+dx).lt.eps) then               ! Program aborts: arrays must be closed
            goto 992
        else if (abs(delta).lt.eps) then              ! Periodic and hemispheric
           hem=1
           per=360.
        endif
      else                                            ! Periodic and hemispheric
         hem=1
         per=xmax-xmin+dx
      endif
      
C     Allocate memory for some meteorological arrays
      allocate(uut0(nx*ny*nz),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array uut0 ***'   ! Zonal wind
      allocate(uut1(nx*ny*nz),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array uut1 ***'
      allocate(vvt0(nx*ny*nz),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array vvt0 ***'   ! Meridional wind
      allocate(vvt1(nx*ny*nz),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array vvt1 ***'
      allocate(wwt0(nx*ny*nz),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array wwt0 ***'   ! Vertical wind
      allocate(wwt1(nx*ny*nz),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array wwt1 ***'

c         Allocate memory for model grid
      allocate(zuv(nx*ny*nz),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array zu ***'     ! Z for U and V grid
      allocate(zw(nx*ny*nz),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array zw ***'     ! Z for W grid
      allocate(zb(nx*ny),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array zb ***'     ! surface height
      allocate(uut0(nx*ny*nz),stat=stat)

C     Get memory for trajectory arrays
      allocate(trainp(ntra,1,ncol),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array trainp   ***' ! Input start coordinates
      allocate(traout(ntra,ntim,4),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array traout   ***' ! Output trajectories
      allocate(xx0(ntra),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array xx0      ***' ! X position (longitude)
      allocate(yy0(ntra),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array yy0      ***' ! Y position (latitude)
      allocate(pp0(ntra),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array pp0      ***' ! Pressure
      allocate(leftflag(ntra),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array leftflag ***' ! Leaving-domain flag

c     Write some status information
      print*,'---- CONSTANT GRID PARAMETERS ---------------------------'
      print*
      print*,'  xmin,xmax     : ',xmin,xmax
      print*,'  ymin,ymax     : ',ymin,ymax
      print*,'  dx,dy         : ',dx,dy
      print*,'  pollon,pollat : ',pollon,pollat
      print*,'  polgam        : ',polgam
      print*,'  nx,ny,nz      : ',nx,ny,nz
      print*,'  per, hem      : ',per,hem
      print*

c     --------------------------------------------------------------------
c     Initialize the trajectory calculation
c     --------------------------------------------------------------------

c     Read start coordinates from file - Format (lon,lat,lev)
      if (inpmode.eq.-1) then
         open(fid,file=strname)
          do i=1,ntra
             read(fid,*) xx0(i),yy0(i),pp0(i)
          enddo
         close(fid)

c     Read start coordinates from trajectory file - check consistency of ref time
      else
         call ropen_tra(cdfid,strname,ntra,1,ncol,reftmp,vars,inpmode)
         call read_tra (cdfid,trainp,ntra,1,ncol,inpmode)
         do i=1,ntra
            time   = trainp(i,1,1)
            xx0(i) = trainp(i,1,2) 
            yy0(i) = trainp(i,1,3) 
            pp0(i) = trainp(i,1,4) 
         enddo
         call close_tra(cdfid,inpmode)

         if ( ( reftime(1).ne.reftmp(1) ).or.
     >        ( reftime(2).ne.reftmp(2) ).or.
     >        ( reftime(3).ne.reftmp(3) ).or.
     >        ( reftime(4).ne.reftmp(4) ).or.
     >        ( reftime(5).ne.reftmp(5) ) )
     >   then
            print*,' WARNING: Inconsistent reference times'
            write(*,'(5f8.2)') (reftime(i),i=1,5)
            write(*,'(5f8.2)') (reftmp (i),i=1,5)
            print*,'Enter a key to proceed...'
            stop
         endif
      endif

c     Rotate coordinates
      do i=1,ntra
         
         lon = xx0(i)
         lat = yy0(i)
         
         if ( abs(polgam).gt.eps ) then

           rlat = phi2phirot ( lat, lon, pollat, pollon )
           rlon = rla2rlarot ( lat, lon, pollat, pollon, polgam )

         else

            if ( abs(pollat-90.).gt.eps) then
               rlon = lmtolms(lat,lon,pollat,pollon)
               rlat = phtophs(lat,lon,pollat,pollon)
            else
               rlon = lon
               rlat = lat
            endif

         endif
         
         xx0(i) = rlon
         yy0(i) = rlat

      enddo

c     Set sign of time range
      reftime(6) = fbflag * reftime(6)
         
c     Write some status information
      print*,'---- REFERENCE DATE---------- ---------------------------'
      print*
      print*,' Reference time (year)  :',reftime(1)
      print*,'                (month) :',reftime(2)
      print*,'                (day)   :',reftime(3)
      print*,'                (hour)  :',reftime(4)
      print*,'                (min)   :',reftime(5)
      print*,' Time range             :',reftime(6),' min'
      print*

C     Save starting positions 
      itim = 1
      do i=1,ntra
         traout(i,itim,1) = 0.
         traout(i,itim,2) = xx0(i)
         traout(i,itim,3) = yy0(i)
         traout(i,itim,4) = pp0(i)
      enddo
      
c     Init the flag and the counter for trajectories leaving the domain
      leftcount=0
      do i=1,ntra
         leftflag(i)=0
      enddo

C     Convert time shifts <tst,ten> from <hh.mm> into fractional time
      call hhmm2frac(tst,frac)
      tst = frac
      call hhmm2frac(ten,frac)
      ten = frac

c     Read models heights for U, V, W grid
          filename = prefix//dat(1)
          call input_open (fid,filename)
          varname = 'U'
          stagz   =  0.
          call input_grid
     >    (fid,varname,xmin,xmax,ymin,ymax,dx,dy,nx,ny,
     >     tload,pollon,pollat,polgam,zuv,zb,nz,stagz,timecheck)
          varname = 'W'
          stagz   = -0.5
          call input_grid
     >    (fid,varname,xmin,xmax,ymin,ymax,dx,dy,nx,ny,
     >     tload,pollon,pollat,polgam,zw,zb,nz,stagz,timecheck)

      call input_close(fid)

c     -----------------------------------------------------------------------
c     Loop to calculate trajectories
c     -----------------------------------------------------------------------

c     Write some status information
      print*,'---- TRAJECTORIES ----------- ---------------------------'
      print*    

C     Set the time for the first data file (depending on forward/backward mode)
      if (fbflag.eq.1) then
        tstart = -tst
      else
        tstart = tst
      endif

c     Read wind fields and vertical grid from first file
      filename = prefix//dat(1)

      call frac2hhmm(tstart,tload)

      write(*,'(a16,a20,f7.2)') '  (file,time) : ',
     >                       trim(filename),tload

      call input_open (fid,filename)
      varname='U'                                      ! U
      call input_wind 
     >    (fid,varname,uut1,tload,stagz,mdv,
     >     xmin,xmax,ymin,ymax,dx,dy,nx,ny,nz,timecheck)
      varname='V'                                      ! V
      call input_wind 
     >    (fid,varname,vvt1,tload,stagz,mdv,
     >     xmin,xmax,ymin,ymax,dx,dy,nx,ny,nz,timecheck)
      varname='W'                                      ! W
      call input_wind 
     >    (fid,varname,wwt1,tload,stagz,mdv,
     >     xmin,xmax,ymin,ymax,dx,dy,nx,ny,nz,timecheck)      
      call input_close(fid)

c     Loop over all input files (time step is <timeinc>)
      do itm=1,numdat-1

c       Calculate actual and next time
        time0 = tstart+real(itm-1)*timeinc*fbflag
        time1 = time0+timeinc*fbflag

c       Copy old velocities to new ones
        do i=1,nx*ny*nz
           uut0(i)=uut1(i)
           vvt0(i)=vvt1(i)
           wwt0(i)=wwt1(i)
        enddo

c       Read wind fields and surface pressure at next time
        filename = prefix//dat(itm+1)

        call frac2hhmm(time1,tload)
        write(*,'(a16,a20,f7.2)') '  (file,time) : ',
     >                          trim(filename),tload

        call input_open (fid,filename)
        varname='U'                                     ! U
        call input_wind 
     >       (fid,varname,uut1,tload,stagz,mdv,
     >        xmin,xmax,ymin,ymax,dx,dy,nx,ny,nz,timecheck)
        varname='V'                                     ! V
        call input_wind 
     >       (fid,varname,vvt1,tload,stagz,mdv,
     >        xmin,xmax,ymin,ymax,dx,dy,nx,ny,nz,timecheck)
        varname='W'                                     ! W
        call input_wind 
     >       (fid,varname,wwt1,tload,stagz,mdv,
     >        xmin,xmax,ymin,ymax,dx,dy,nx,ny,nz,timecheck)      
        call input_close(fid)
        
C       Determine the first and last loop indices
        if (numdat.eq.2) then
          filo = nint(tst/ts)+1
          lalo = nint((timeinc-ten)/ts) 
        elseif ( itm.eq.1 ) then
          filo = nint(tst/ts)+1
          lalo = nint(timeinc/ts)
        else if (itm.eq.numdat-1) then
          filo = 1
          lalo = nint((timeinc-ten)/ts)
        else
          filo = 1
          lalo = nint(timeinc/ts)
        endif

c       Split the interval <timeinc> into computational time steps <ts>
        do iloop=filo,lalo

C         Calculate relative time position in the interval timeinc (0=beginning, 1=end)
          reltpos0 = ((real(iloop)-1.)*ts)/timeinc
          reltpos1 = real(iloop)*ts/timeinc

C         Initialize counter for domain leaving trajectories
          leftcount=0

c         Timestep for all trajectories
          do i=1,ntra

C           Check if trajectory has already left the data domain
            if (leftflag(i).ne.1) then  

c             Iterative Euler timestep (x0,y0,p0 -> x1,y1,p1)
              if (imethod.eq.1) then
                 call euler(
     >               xx1,yy1,pp1,leftflag(i),
     >               xx0(i),yy0(i),pp0(i),reltpos0,reltpos1,
     >               ts*3600,numit,jflag,mdv,wfactor,fbflag,
     >               zuv,zw,zb,uut0,uut1,vvt0,vvt1,wwt0,wwt1,
     >               xmin,ymin,dx,dy,per,hem,nx,ny,nz,fflag,
     >               lat_fixed,balloon)

c             Runge-Kutta timestep (x0,y0,p0 -> x1,y1,p1)
              else if (imethod.eq.2) then
                 call runge(
     >               xx1,yy1,pp1,leftflag(i),
     >               xx0(i),yy0(i),pp0(i),reltpos0,reltpos1,
     >               ts*3600,numit,jflag,mdv,wfactor,fbflag,
     >               zuv,zw,zb,uut0,uut1,vvt0,vvt1,wwt0,wwt1,
     >               xmin,ymin,dx,dy,per,hem,nx,ny,nz)

              endif

c             Update trajectory position, or increase number of trajectories leaving domain
              if (leftflag(i).eq.1) then
                leftcount=leftcount+1
                print*,'     -> Trajectory ',i,' leaves domain'
                xx0(i)=-999.
                yy0(i)=-999.
                pp0(i)=-999.
              else
                xx0(i)=xx1
                yy0(i)=yy1
                pp0(i)=pp1
              endif

c          Trajectory has already left data domain (mark as <mdv>)
           else
              xx0(i)=-999.
              yy0(i)=-999.
              pp0(i)=-999.
              
           endif

          enddo

C         Save positions only every deltout minutes
          delta = aint(iloop*60*ts/deltout)-iloop*60*ts/deltout
          if (abs(delta).lt.eps) then
            time = time0+reltpos1*timeinc*fbflag
            itim = itim + 1
            do i=1,ntra
               call frac2hhmm(time,tload)
               traout(i,itim,1) = tload
               if ( abs( pp0(i) + 999. ).lt.eps ) then
                   traout(i,itim,2) = traout(i,itim-1,2)
                   traout(i,itim,3) = traout(i,itim-1,3)
                   traout(i,itim,4) = -999.
               else
                   traout(i,itim,2) = xx0(i)
                   traout(i,itim,3) = yy0(i)
                   traout(i,itim,4) = pp0(i)
               endif
            enddo
          endif

        enddo

      enddo

c     Coordinate rotation
      do i=1,ntra
         do j=1,ntim

            rlon = traout(i,j,2)
            rlat = traout(i,j,3)

            if ( abs(polgam).gt.eps ) then

              lon = rlarot2rla (rlat, rlon, pollat, pollon, polgam)
              lat = phirot2phi (rlat, rlon, pollat, pollon, polgam)

            else

              if ( abs(pollat-90.).gt.eps) then
                 lon = lmstolm(rlat,rlon,pollat,pollon)
                 lat = phstoph(rlat,rlon,pollat,pollon)
              else
                 lon = rlon
                 lat = rlat
              endif
            
            endif
            
            traout(i,j,2) = lon
            traout(i,j,3) = lat

         enddo
      enddo

c     Write trajectory file
      vars(1)  ='time'
      vars(2)  ='lon'
      vars(3)  ='lat'
      vars(4)  ='z'
      call wopen_tra(cdfid,cdfname,ntra,ntim,4,reftime,vars,outmode)
      call write_tra(cdfid,traout,ntra,ntim,4,outmode)
      call close_tra(cdfid,outmode)   

c     Write some status information, and end of program message
      print*  
      print*,'---- STATUS INFORMATION --------------------------------'
      print*
      print*,'  #leaving domain    ', leftcount
      print*,'  #staying in domain ', ntra-leftcount
      print*
      print*,'              *** END OF PROGRAM CALTRA ***'
      print*,'========================================================='

      stop

c     ------------------------------------------------------------------
c     Exception handling
c     ------------------------------------------------------------------

 991  write(*,*) '*** ERROR: all start points outside the data domain'
      call exit(1)
      
 992  write(*,*) '*** ERROR: close arrays on files (prog. closear)'
      call exit(1)

 993  write(*,*) '*** ERROR: problems with array size'
      call exit(1)

      end 


c     *******************************************************************
c     * Time step : either Euler or Runge-Kutta                         *
c     *******************************************************************

C     Time-step from (x0,y0,p0) to (x1,y1,p1)
C
C     (x0,y0,p0) input  coordinates (long,lat,p) for starting point
C     (x1,y1,p1) output coordinates (long,lat,p) for end point
C     deltat     input  timestep in seconds
C     numit      input  number of iterations
C     jump       input  flag (=1 trajectories don't enter the ground)
C     left       output flag (=1 if trajectory leaves data domain)

c     -------------------------------------------------------------------
c     Iterative Euler time step
c     -------------------------------------------------------------------

      subroutine euler(x1,y1,p1,left,x0,y0,p0,reltpos0,reltpos1,
     >                 deltat,numit,jump,mdv,wfactor,fbflag,
     >                     zuv,zw,zb,uut0,uut1,vvt0,vvt1,wwt0,wwt1,
     >                 xmin,ymin,dx,dy,per,hem,nx,ny,nz,
     >                 fflag,lat_fixed,balloon)

      implicit none

c     Declaration of subroutine parameters
      integer      nx,ny,nz
      real         x1,y1,p1
      integer      left
      real             x0,y0,p0
      real         reltpos0,reltpos1
      real         deltat
      integer      numit
      integer      jump
      real         wfactor
      integer      fbflag
      real         zb(nx*ny)
      real         uut0(nx*ny*nz),uut1(nx*ny*nz)
      real             vvt0(nx*ny*nz),vvt1(nx*ny*nz)
      real         wwt0(nx*ny*nz),wwt1(nx*ny*nz)
      real         zuv(nx*ny*nz),zw(nx*ny*nz)
      real         xmin,ymin,dx,dy
      real         per
      integer      hem
      real         mdv
      integer      fflag
      real         lat_fixed
      real         balloon

c     Numerical and physical constants
      real         deltay
      parameter    (deltay=1.112E5)  ! Distance in m between 2 lat circles
      real         pi                       
      parameter    (pi=3.1415927)    ! Pi

c     Test flag
      integer      test
      parameter    (test=0)
      integer      maxindstep
      parameter    (maxindstep=5.)

c     Auxiliary variables
      real         xmax,ymax
      real             xind,yind,pind
      real             u0,v0,w0,u1,v1,w1,u,v,w,sp
      integer      icount
      character    ch
      real         xind0,yind0,zind0,xind1,yind1,zind1

c     Externals    
      real         int_index4
      external     int_index4

c     Reset the flag for domain-leaving
      left=0

c     Set the esat-north bounray of the domain
      xmax = xmin+real(nx-1)*dx
      ymax = ymin+real(ny-1)*dy

C     Interpolate wind fields to starting position (x0,y0,p0)
      call get_index4 (xind,yind,pind,x0,y0,p0,reltpos0,
     >                 zuv,zuv,zb,zb,3,nx,ny,nz,xmin,ymin,dx,dy,mdv)
      u0 = int_index4(uut0,uut1,nx,ny,nz,xind,yind,pind,reltpos0,mdv)
      v0 = int_index4(vvt0,vvt1,nx,ny,nz,xind,yind,pind,reltpos0,mdv)

      call get_index4 (xind,yind,pind,x0,y0,p0,reltpos0,
     >                 zw,zw,zb,zb,3,nx,ny,nz,xmin,ymin,dx,dy,mdv)
      w0 = int_index4(wwt0,wwt1,nx,ny,nz,xind,yind,pind,reltpos0,mdv)

c     In testmode: remember the indices at starting position
      if ( test.eq.1 ) then
           zind0 = pind
           xind0 = xind
           yind0 = yind
      endif

c     Force the near-surface wind to zero
      if (pind.lt.1.) w0=w0*pind

C     For first iteration take ending position equal to starting position
      x1=x0
      y1=y0
      p1=p0

C     Iterative calculation of new position
      do icount=1,numit

C        Calculate new winds for advection
         call get_index4 (xind,yind,pind,x1,y1,p1,reltpos1,
     >                    zuv,zuv,zb,zb,3,nx,ny,nz,xmin,ymin,dx,dy,mdv)
         u1 = int_index4(uut0,uut1,nx,ny,nz,xind,yind,pind,reltpos1,mdv)
         v1 = int_index4(vvt0,vvt1,nx,ny,nz,xind,yind,pind,reltpos1,mdv)

         call get_index4 (xind,yind,pind,x1,y1,p1,reltpos1,
     >                    zw,zw,zb,zb,3,nx,ny,nz,xmin,ymin,dx,dy,mdv)
         w1 = int_index4(wwt0,wwt1,nx,ny,nz,xind,yind,pind,reltpos1,mdv)

c        Force the near-surface wind to zero
         if (pind.lt.1.) w1=w1*pind
 
c        Get the new velocity in between
         u=(u0+u1)/2.
         v=(v0+v1)/2.
         w=(w0+w1)/2. + balloon
 
C        Calculate new positions (fplane or normal)
         if ( fflag.eq.1 ) then
            x1 = x0 + fbflag*u*deltat/(deltay*cos(lat_fixed*pi/180.))
            y1 = y0 + fbflag*v*deltat/deltay
            p1 = p0 + fbflag*wfactor*w*deltat
         else
            x1 = x0 + fbflag*u*deltat/(deltay*cos(y0*pi/180.))
            y1 = y0 + fbflag*v*deltat/deltay
            p1 = p0 + fbflag*wfactor*w*deltat
         endif

c       Handle pole problems (crossing and near pole trajectory)
        if ((hem.eq.1).and.(y1.gt.90.)) then
          y1=180.-y1
          x1=x1+per/2.
        endif
        if ((hem.eq.1).and.(y1.lt.-90.)) then
          y1=-180.-y1
          x1=x1+per/2.
        endif
        if (y1.gt.89.99) then
           y1=89.99
        endif

c       Handle crossings of the dateline
        if ((hem.eq.1).and.(x1.gt.xmin+per-dx)) then
           x1=xmin+amod(x1-xmin+dx,per)
        endif
        if ((hem.eq.1).and.(x1.lt.xmin)) then
           x1=xmin+per+amod(x1-xmin-dx,per)
        endif

C       Interpolate surface height to actual position
        call get_index4 (xind,yind,pind,x1,y1,0.,reltpos1,
     >                   zuv,zuv,zb,zb,3,
     >                   nx,ny,nz,xmin,ymin,dx,dy,mdv)
        sp = int_index4 (zb,zb,nx,ny,1,xind,yind,1.,reltpos1,mdv)

c       Handle trajectories which cross the lower boundary (jump flag)
        if ((jump.eq.1).and.(p1.lt.sp)) p1=sp+10.
 
C       Check if trajectory leaves data domain
        if ( ( (hem.eq.0).and.(x1.lt.xmin)    ).or.
     >       ( (hem.eq.0).and.(x1.gt.xmax-dx) ).or.
     >         (y1.lt.ymin).or.(y1.gt.ymax).or.(p1.lt.sp) )
     >  then
          left=1
          goto 100
        endif

      enddo

c     In test mode, get the indices at the final position
      if ( test.eq.1 ) then
         call get_index4 (xind,yind,pind,x1,y1,p1,reltpos1,
     >                    zuv,zuv,zb,zb,3,nx,ny,nz,xmin,ymin,dx,dy,mdv)
         xind1 = xind
         yind1 = yind
         call get_index4 (xind,yind,pind,x1,y1,p1,reltpos1,
     >                    zw,zw,zb,zb,3,nx,ny,nz,xmin,ymin,dx,dy,mdv)
         zind1 = pind

         if ( ( abs(xind1-xind0).gt.maxindstep ).or.
     >        ( abs(yind1-yind0).gt.maxindstep ).or.
     >        ( abs(zind1-zind0).gt.maxindstep ) )
     >   then
             print*
             print*,' ERROR: Index step too large : convergence problem'
             print*
             print*,'xind : ',xind0,' -> ',xind1,' : ',abs(xind1-xind0)
             print*,'yind : ',yind0,' -> ',yind1,' : ',abs(yind1-yind0)
             print*,'zind : ',zind0,' -> ',zind1,' : ',abs(zind1-zind0)
             print*
         endif

      endif

c     Exit point for subroutine
 100  continue

      return

      end

c     -------------------------------------------------------------------
c     Runge-Kutta (4th order) time-step
c     -------------------------------------------------------------------

      subroutine runge(x1,y1,p1,left,x0,y0,p0,reltpos0,reltpos1,
     >                 deltat,numit,jump,mdv,wfactor,fbflag,
     >                     zuv,zw,zb,uut0,uut1,vvt0,vvt1,wwt0,wwt1,
     >                 xmin,ymin,dx,dy,per,hem,nx,ny,nz)
     
      implicit none

c     Declaration of subroutine parameters
      integer      nx,ny,nz
      real         x1,y1,p1
      integer      left
      real             x0,y0,p0
      real         reltpos0,reltpos1
      real         deltat
      integer      numit
      integer      jump
      real         wfactor
      integer      fbflag
      real         zb(nx*ny)
      real         uut0(nx*ny*nz),uut1(nx*ny*nz)
      real             vvt0(nx*ny*nz),vvt1(nx*ny*nz)
      real         wwt0(nx*ny*nz),wwt1(nx*ny*nz)
      real         zuv(nx*ny*nz),zw(nx*ny*nz)
      real         xmin,ymin,dx,dy
      real         per
      integer      hem
      real         mdv

c     Numerical and physical constants
      real         deltay
      parameter    (deltay=1.112E5)  ! Distance in m between 2 lat circles
      real         pi                       
      parameter    (pi=3.1415927)    ! Pi

c     Auxiliary variables
      real         xmax,ymax
      real             xind,yind,pind
      real             u0,v0,w0,u1,v1,w1,u,v,w,sp
      integer      icount,n
      real         xs,ys,ps,xk(4),yk(4),pk(4)
      real         reltpos

c     Externals    
      real         int_index4
      external     int_index4

c     Reset the flag for domain-leaving
      left=0

c     Set the esat-north bounray of the domain
      xmax = xmin+real(nx-1)*dx
      ymax = ymin+real(ny-1)*dy

c     Apply the Runge Kutta scheme
      do n=1,4
 
c       Get intermediate position and relative time
        if (n.eq.1) then
          xs=0.
          ys=0.
          ps=0.
          reltpos=reltpos0
        else if (n.eq.4) then
          xs=xk(3)
          ys=yk(3)
          ps=pk(3)
          reltpos=reltpos1
        else
          xs=xk(n-1)/2.
          ys=yk(n-1)/2.
          ps=pk(n-1)/2.
          reltpos=(reltpos0+reltpos1)/2.
        endif
        
C       Calculate new winds for advection
        call get_index4 (xind,yind,pind,x0+xs,y0+ys,p0+ps,reltpos,
     >                   zuv,zuv,zb,zb,3,nx,ny,nz,xmin,ymin,dx,dy,mdv)
        u = int_index4(uut0,uut1,nx,ny,nz,xind,yind,pind,reltpos,mdv)
        v = int_index4(vvt0,vvt1,nx,ny,nz,xind,yind,pind,reltpos,mdv)

        call get_index4 (xind,yind,pind,x0+xs,y0+ys,p0+ps,reltpos,
     >                   zw,zw,zb,zb,3,nx,ny,nz,xmin,ymin,dx,dy,mdv)
        w = int_index4(wwt0,wwt1,nx,ny,nz,xind,yind,pind,reltpos,mdv)
         
c       Force the near-surface wind to zero
        if (pind.lt.1.) w1=w1*pind
 
c       Update position and keep them
        xk(n)=fbflag*u*deltat/(deltay*cos(y0*pi/180.))
        yk(n)=fbflag*v*deltat/deltay
        pk(n)=fbflag*w*deltat*wfactor

      enddo
 
C     Calculate new positions
      x1=x0+(1./6.)*(xk(1)+2.*xk(2)+2.*xk(3)+xk(4))
      y1=y0+(1./6.)*(yk(1)+2.*yk(2)+2.*yk(3)+yk(4))
      p1=p0+(1./6.)*(pk(1)+2.*pk(2)+2.*pk(3)+pk(4))

c     Handle pole problems (crossing and near pole trajectory)
      if ((hem.eq.1).and.(y1.gt.90.)) then
         y1=180.-y1
         x1=x1+per/2.
      endif
      if ((hem.eq.1).and.(y1.lt.-90.)) then
         y1=-180.-y1
         x1=x1+per/2.
      endif
      if (y1.gt.89.99) then
         y1=89.99
      endif
      
c     Handle crossings of the dateline
      if ((hem.eq.1).and.(x1.gt.xmin+per-dx)) then
         x1=xmin+amod(x1-xmin,per)
      endif
      if ((hem.eq.1).and.(x1.lt.xmin)) then
         x1=xmin+per+amod(x1-xmin,per)
      endif
      
C     Interpolate surface pressure to actual position
      call get_index4 (xind,yind,pind,x1,y1,0.,reltpos1,
     >                 zuv,zuv,zb,zb,3,
     >                 nx,ny,nz,xmin,ymin,dx,dy,mdv)
      sp = int_index4 (zb,zb,nx,ny,1,xind,yind,1,reltpos,mdv)

c     Handle trajectories which cross the lower boundary (jump flag)
      if ((jump.eq.1).and.(p1.lt.sp)) p1=sp+10.
      
C     Check if trajectory leaves data domain
      if ( ( (hem.eq.0).and.(x1.lt.xmin)    ).or.
     >     ( (hem.eq.0).and.(x1.gt.xmax-dx) ).or.
     >       (y1.lt.ymin).or.(y1.gt.ymax).or.(p1.lt.sp) )
     >then
         left=1
         goto 100
      endif
      
c     Exit point fdor subroutine
 100  continue

      return
      end