Subversion Repositories lagranto.icon

Rev

Rev 3 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

      PROGRAM trace

C     ********************************************************************
C     *                                                                  *
C     * Pseudo-lidar plots along 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     Conversion factors
      real      pi180                                   ! deg -> rad
      parameter (pi180=3.14159/180.)
      real      deg2km                                  ! deg -> km (at equator)
      parameter (deg2km=111.)

c     Prefix for primary and secondary fields
      character charp
      character chars
      parameter (charp='P')
      parameter (chars='S')

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

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

c     Input parameters
      character*80                           inpfile         ! Input trajectory file
      character*80                           outfile         ! Output netCDF file
      character*80                           outmode         ! Output mode (sum,mean)
      integer                                ntra            ! Number of trajectories
      integer                                ncol            ! Number of columns (including time, lon, lat, p)
      integer                                ntim            ! Number of times per trajectory
      integer                                ntrace0         ! Number of trace variables
      character*80                           tvar(200)       ! Tracing variable name (only the variable)
      character*1                            tfil(200)       ! Filename prefix 
      real                                   fac(200)        ! Scaling factor 
      integer                                compfl(200)     ! Computation flag (1=compute)
      integer                                vector(200)     ! Flag for vectorial transformation
      integer                                nvector         ! Counter of vectorial variables
      integer                                numdat          ! Number of input files
      character*13                           dat(ndatmax)    ! Dates of input files
      real                                   timeinc         ! Time increment between input files
      real                                   tst             ! Time shift of start relative to first data file
      real                                   ten             ! Time shift of end relatiev to first data file  
      character*20                           startdate       ! First time/date on trajectory
      character*20                           enddate         ! Last time/date on trajectory
      character*80                           timecheck       ! Either 'yes' or 'no'
      character*80                           intmode         ! Interpolation mode ('normal', 'nearest')
          real                                   zmin,zmax       ! Pressure range for output grid
          integer                                nlev            ! Number of pressure levels in output grid
          character*80                           centering       ! Centering around trajectory position ('yes','no')

c     Trajectories
      real,allocatable, dimension (:,:,:) :: trainp          ! Input trajectories (ntra,ntim,ncol)
      integer                                reftime(6)      ! Reference date
      character*80                           varsinp(100)    ! Field names for input trajectory
      integer                                fid,fod         ! File identifier for inp and out trajectories
      real                                   x0,y0,z0        ! Position of air parcel (physical space)
      real                                   reltpos0        ! Relative time of air parcel
      real                                   xind,yind,zind  ! Position of air parcel (grid space)
      integer                                fbflag          ! Flag for forward (1) or backward (-1) trajectories

c     Meteorological fields from input file
      real,allocatable, dimension (:)     :: zbt0,zbt1       ! Topography
      real,allocatable, dimension (:)     :: z3t0,z3t1       ! 3d height
      real,allocatable, dimension (:)     :: f3t0,f3t1       ! 3d field for tracing 
      real,allocatable, dimension (:)     :: v3t0,v3t1       ! second component for vector field
      character*80                           svars(100)      ! List of variables on S file
      character*80                           pvars(100)      ! List of variables on P file
      integer                                n_svars         ! Number of variables on S file
      integer                                n_pvars         ! Number of variables on P file
      
c     Input grid description
      real                                   pollon,pollat   ! Longitude/latitude of pole
      real                                   polgam          ! Grid rotation
      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
      integer                                per             ! Flag for periodic domain
      real                                   stagz           ! Vertical staggering
      real                                   mdv             ! Missing data value

c         Output grid  and fields
      real                                   levels(1000)    ! Ouput levels
      real                                   times (1000)    ! Output times
          real,allocatable, dimension (:,:)   :: out_pos         ! Position of trajectories
          real,allocatable, dimension (:,:)   :: out_val         ! Output lidar field
          real,allocatable, dimension (:,:)   :: out_cnt         ! # output lidar sum ups


c     Auxiliary variables
      integer                                i,j,k,l,n,m
      real                                   rd
      character*80                           filename
      real                                   time0,time1,reltpos
      integer                                itime0,itime1
      integer                                stat
      real                                   tstart
      integer                                iloaded0,iloaded1
      real                                   f0,v0
      real                                   frac
      real                                   tload,tfrac
      integer                                isok
      character                              ch
      integer                                ind
      integer                                ind1,ind2,ind3,ind4,ind5
      integer                                ind6,ind7,ind8,ind9,ind0
      integer                                noutside
      real                                   delta
      integer                                itrace0
      character*80                           string
      character*80                           cdfname
      character*80                           varname
      real                                   time
      character*80                           longname
      character*80                           unit
      integer                                ind_time
      integer                                ind_pre
      real                                   lon,lat,rlon,rlat
      character*80                           name
      integer                                ipoint
      real                                   urot,vrot,u,v

c     Externals 
      real                                   int_index4
      external                               int_index4

      real                                   lmtolms
      real                                   phtophs
      real                                   lmstolm
      real                                   phstoph
      external                               lmtolms,phtophs
      external                               lmstolm,phstoph

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

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

c     Read parameters
      open(10,file='trace.param')
       read(10,*) inpfile
       read(10,*) outfile
       read(10,*) outmode
       read(10,*) startdate
       read(10,*) enddate 
       read(10,*) fbflag
       read(10,*) numdat
       if ( fbflag.eq.1) then
          do i=1,numdat
             read(10,'(a)') dat(i)
          enddo
       else
          do i=numdat,1,-1
             read(10,'(a)') dat(i)
          enddo
       endif
       read(10,*) timeinc
       read(10,*) tst
       read(10,*) ten
       read(10,*) ntra
       read(10,*) ntim
       read(10,*) ncol
       read(10,*) ntrace0
       do i=1,ntrace0
          read(10,*) tvar(i), fac(i), compfl(i), tfil(i)
       enddo
       read(10,*) n_pvars
       do i=1,n_pvars
          read(10,*) pvars(i)
       enddo
       read(10,*) n_svars
       do i=1,n_svars
          read(10,*) svars(i)
       enddo
       read(10,*) timecheck
       read(10,*) intmode
       read(10,*) zmin,zmax,nlev
       read(10,*) centering
      close(10)
    
c     Remove commented tracing fields
      itrace0 = 1
      do while ( itrace0.le.ntrace0) 
         string = tvar(itrace0)
         if ( string(1:1).eq.'#' ) then
            do i=itrace0,ntrace0-1
               tvar(i)   = tvar(i+1)
               fac(i)    = fac(i+1)
               compfl(i) = compfl(i+1)
               tfil(i)   = tfil(i+1)
            enddo
            ntrace0 = ntrace0 - 1
         else
            itrace0 = itrace0 + 1
         endif
      enddo

c     Check whether it is a vectorial variable - if yes, split it into
c     its two components and mark it as vectorial
      nvector = 0
      i       = 1
      do while ( i.le.ntrace0 )
          name   = tvar(i)
          ipoint = 0
          do j=1,80
             if ( name(j:j).eq.'.' ) ipoint = j
          enddo
          if ( ipoint.ne.0 ) then
             nvector   = nvector + 1
                 tvar(i)   = trim ( name(1:ipoint-1) )
                 vector(i) = nvector
                 do j=i+1,ntrace0
                        tvar  (j+1) = tvar  (j)
                    fac   (j+1) = fac   (j)
                    compfl(j+1) = compfl(j)
                    tfil  (j+1) = tfil  (j)
                 enddo
                 tvar  (i+1) = trim( name(ipoint+1:80) )
                 fac   (i+1) = fac   (i)
                 compfl(i+1) = compfl(i)
                 tfil  (i+1) = tfil  (i)
                 vector(i+1) = nvector
                 ntrace0     = ntrace0 + 1
                 i = i + 1
          else
             vector(i) = 0
          endif
          i = i + 1
      enddo

c     Set the formats of the input  files
      call mode_tra(inpmode,inpfile)
      if (inpmode.eq.-1) inpmode=1

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     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 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 = charp//dat(1)
      varname  = 'U'
      nx       = 1
      ny       = 1
      nz       = 1
      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     Allocate memory for some meteorological arrays
      allocate(zbt0(nx*ny),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array zbt0 ***'   ! Topography
      allocate(zbt1(nx*ny),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array zbt1 ***'
      allocate(z3t0(nx*ny*nz),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array z3t0 ***'   ! 3d model height
      allocate(z3t1(nx*ny*nz),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array z3t1 ***'
      allocate(f3t0(nx*ny*nz),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array f3t0 ***'   ! Lidar field
      allocate(f3t1(nx*ny*nz),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array f3t1 ***'
      allocate(v3t0(nx*ny*nz),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array v3t0 ***'   ! Second component for vector field
      allocate(v3t1(nx*ny*nz),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array v3t1 ***'

c         Allocate memory for output field
          allocate(out_pos(ntim,nlev),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array out_pos ***'
          allocate(out_val(ntim,nlev),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array out_val ***'
          allocate(out_cnt(ntim,nlev),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array out_cnt ***'

C     Get memory for trajectory arrays
      allocate(trainp(ntra,ntim,ncol),stat=stat)
      if (stat.ne.0) print*,'*** error allocating array tra      ***' 

c     Set the flags for periodic domains
      if ( abs(xmax-xmin-360.).lt.eps ) then
         per = 1
      elseif ( abs(xmax-xmin-360.+dx).lt.eps ) then
         per = 2
      else
         per = 0
      endif

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
            print*,' ERROR: arrays must be closed... Stop'
         else if (abs(delta).lt.eps) then ! Periodic and hemispheric
           hem=1
           per=360.
        endif
      else                                            ! Periodic and hemispheric
         hem=1
      endif

c     Write some status information
      print*,'---- INPUT PARAMETERS -----------------------------------'
      print*
      print*,'  Input trajectory file  : ',trim(inpfile)
      print*,'  Format of input file   : ',inpmode
      print*,'  Output netCDF    file  : ',trim(outfile)
      print*,'  Format of output file  : ',trim(outmode)
      print*,'  Forward/backward       : ',fbflag
      print*,'  #tra                   : ',ntra
      print*,'  #col                   : ',ncol
      print*,'  #tim                   : ',ntim
      print*,'  No time check          : ',trim(timecheck)
      print*,'  Interpolation mode     : ',trim(intmode)
      do i=1,ntrace0
         if (compfl(i).eq.0) then
            write(*,'(a20,a10,f10.2,a3,1x,a1,a20,i2)')
     >                 '   Tracing field          : ',
     >                 trim(tvar(i)), fac(i), ' 0 ', tfil(i),
     >                 ' -> vector/scalar : ',vector(i)
         else
            print*,'  Tracing field          : ',
     >                trim(tvar(i)),' : online calc not supported'
         endif
      enddo
      print*,'  Output (zmin,zmax,n)   : ',zmin,zmax,nlev
      print*,'  Centering              : ',trim(centering)
      print*
      print*,'---- INPUT DATA FILES -----------------------------------'
      print*
      call frac2hhmm(tstart,tload)
      print*,'  Time of 1st data file  : ',tload
      print*,'  #input files           : ',numdat
      print*,'  time increment         : ',timeinc
      call frac2hhmm(tst,tload)
      print*,'  Shift of start         : ',tload
      call frac2hhmm(ten,tload)
      print*,'  Shift of end           : ',tload
      print*,'  First/last input file  : ',trim(dat(1)),
     >                                     ' ... ',
     >                                     trim(dat(numdat))
      print*,'  Primary variables      : ',trim(pvars(1))
      do i=2,n_pvars
         print*,'                         : ',trim(pvars(i))
      enddo
      if ( n_svars.ge.1 ) then
         print*,'  Secondary variables    : ',trim(svars(1))
         do i=2,n_svars
            print*,'                         : ',trim(svars(i))
         enddo
      endif
      print*
      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     Load the input trajectories
c     --------------------------------------------------------------------

c     Read the input trajectory file
      call ropen_tra(fid,inpfile,ntra,ntim,ncol,reftime,varsinp,inpmode)
      call read_tra (fid,trainp,ntra,ntim,ncol,inpmode)
      call close_tra(fid,inpmode)

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

            lon = trainp(i,j,2)
            lat = trainp(i,j,3)

            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

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

         enddo
      enddo

c     Check that first four columns correspond to time,lon,lat,z
      if ( (varsinp(1).ne.'time' ).or.
     >     (varsinp(2).ne.'xpos' ).and.(varsinp(2).ne.'lon' ).or.
     >     (varsinp(3).ne.'ypos' ).and.(varsinp(3).ne.'lat' ).or.
     >     (varsinp(4).ne.'zpos' ).and.(varsinp(4).ne.'z'   ) )
     >then
         print*,' ERROR: problem with input trajectories ...'
         stop
      endif
      varsinp(1) = 'time'
      varsinp(2) = 'lon'
      varsinp(3) = 'lat'
      varsinp(4) = 'z'

c     Write some status information of the input trajectories
      print*,'---- INPUT TRAJECTORIES ---------------------------------'
      print*
      print*,' Start date             : ',trim(startdate)
      print*,' End date               : ',trim(enddate)
      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 (min)       : ',reftime(6)
      do i=1,ncol
         print*,' Var                    :',i,trim(varsinp(i))
      enddo
      print*

c     Check that first time is 0 - otherwise the tracing will produce
c     wrong results because later in the code only absolute times are
c     considered: <itime0   = int(abs(tfrac-tstart)/timeinc) + 1>. This 
c     will be changed in a future version.
      if ( abs( trainp(1,1,1) ).gt.eps ) then
         print*,' ERROR: First time of trajectory must be 0, i.e. '
         print*,'     correspond to the reference date. Otherwise'
         print*,'     the tracing will give wrong results... STOP'
         stop
      endif
      
c     Run a simple consistency check
      call do_timecheck(dat,numdat,timeinc,fbflag,reftime)

c     --------------------------------------------------------------------
c     Trace the fields (fields available on input files)
c     --------------------------------------------------------------------

      print*
      print*,'---- LIDAR FROM PRIMARY AND SECONDARY DATA FILES ------'

c     Loop over all tracing fields
      do i=1,ntrace0

c             Skip all fields marked for online calculation
          if ( compfl(i).eq.1 ) goto 110
         
c             Init the output fields: position and lidar field
              do k=1,ntim
                do l=1,nlev
                        out_pos(k,l) = 0.
                    out_val(k,l) = 0.
                    out_cnt(k,l) = 0.
                 enddo
              enddo

c         Write some status information
          print*
          print*,' Now lidaring           : ',
     >         trim(tvar(i)),compfl(i),' ',trim(tfil(i))

c         Special handling for vectorial fields: we need the second component
c             of the vector field and must transform them. Remember the  two vector
c             components in <ind0> and <ind1>.
              if ( vector(i).ne.0 ) then
                 ind0 = i
                 do m=1,ntrace0
                   if ( (vector(i).eq.vector(m)).and.(i.ne.m) ) then
                      ind1 = m
                   endif
                 enddo
              endif

c         Reset flags for load manager
          iloaded0 = -1
          iloaded1 = -1

c         Reset the counter for fields outside domain
          noutside = 0

c         Loop over all times
          do j=1,ntim

c            Convert trajectory time from hh.mm to fractional time
             call hhmm2frac(trainp(1,j,1),tfrac)

c            Get the times which are needed
             itime0   = int(abs(tfrac-tstart)/timeinc) + 1
             time0    = tstart + fbflag * real(itime0-1) * timeinc
             itime1   = itime0 + 1
             time1    = time0 + fbflag * timeinc
             if ( itime1.gt.numdat ) then
                itime1 = itime0
                time1  = time0
             endif

c            Load manager: Check whether itime0 can be copied from itime1
             if ( itime0.eq.iloaded1 ) then
                f3t0     = f3t1
                v3t0     = v3t1
                z3t0     = z3t1
                zbt0     = zbt1
                iloaded0 = itime0
             endif

c            Load manager: Check whether itime1 can be copied from itime0
             if ( itime1.eq.iloaded0 ) then
                f3t1     = f3t0
                v3t1     = v3t0
                z3t1     = z3t0
                zbt1     = zbt0
                iloaded1 = itime1
             endif

c            Load manager:  Load first time (tracing variable and grid)
             if ( itime0.ne.iloaded0 ) then

                filename = tfil(i)//dat(itime0)
                call frac2hhmm(time0,tload)
                varname  = tvar(i) 
                write(*,'(a23,a20,a3,a5,f7.2)') 
     >               '    -> loading          : ',
     >               trim(filename),'  ',trim(varname),tload
                call input_open (fid,filename)
                call input_wind 
     >               (fid,varname,f3t0,tload,stagz,mdv,
     >               xmin,xmax,ymin,ymax,dx,dy,nx,ny,nz,timecheck)     
                call input_grid      
     >          (fid,varname,xmin,xmax,ymin,ymax,dx,dy,nx,ny,
     >          tload,pollon,pollat,polgam,z3t0,zbt0,nz,stagz,timecheck)
                call input_close(fid)
                
                if ( vector(i).ne.0 ) then
                   filename = tfil(i)//dat(itime0)
                   call frac2hhmm(time0,tload)
                   varname  = tvar(ind1)
                   write(*,'(a23,a20,a3,a5,f7.2)')
     >                     '    -> loading (vector) : ',
     >                      trim(filename),'  ',trim(varname),tload
                   call input_open (fid,filename)
                   call input_wind
     >                  (fid,varname,v3t0,tload,stagz,mdv,
     >                  xmin,xmax,ymin,ymax,dx,dy,nx,ny,nz,timecheck)
                   call input_close(fid)
                endif

                iloaded0 = itime0
                
             endif

c            Load manager: Load second time (tracing variable and grid)
             if ( itime1.ne.iloaded1 ) then
                
                filename = tfil(i)//dat(itime1)
                call frac2hhmm(time1,tload)
                varname  = tvar(i) 
                write(*,'(a23,a20,a3,a5,f7.2)') 
     >               '    -> loading          : ',
     >               trim(filename),'  ',trim(varname),tload
                call input_open (fid,filename)
                call input_wind 
     >               (fid,varname,f3t1,tload,stagz,mdv,
     >               xmin,xmax,ymin,ymax,dx,dy,nx,ny,nz,timecheck)
                call input_grid      
     >          (fid,varname,xmin,xmax,ymin,ymax,dx,dy,nx,ny,
     >          tload,pollon,pollat,polgam,z3t1,zbt1,nz,stagz,timecheck)
                call input_close(fid)
                
                if ( vector(i).ne.0 ) then
                    filename = tfil(i)//dat(itime1)
                    call frac2hhmm(time1,tload)
                    varname  = tvar(ind1)
                    write(*,'(a23,a20,a3,a5,f7.2)')
     >                      '    -> loading (vector) : ',
     >                      trim(filename),'  ',trim(varname),tload
                    call input_open (fid,filename)
                    call input_wind
     >                   (fid,varname,v3t1,tload,stagz,mdv,
     >                    xmin,xmax,ymin,ymax,dx,dy,nx,ny,nz,timecheck)
                    call input_close(fid)
                endif

                iloaded1 = itime1
                
             endif

c            Loop over all trajectories
             do k=1,ntra
                
c               Set the horizontal position where to interpolate to
                x0       = trainp(k,j,2)                          ! Longitude
                y0       = trainp(k,j,3)                          ! Latitude

c               Set the relative time
                call hhmm2frac(trainp(k,j,1),tfrac)
                reltpos0 = fbflag * (tfrac-time0)/timeinc    
                   
c               Handle periodic boundaries in zonal direction
                if ( (x0.gt.xmax).and.(per.ne.0) ) x0 = x0 - 360.
                if ( (x0.lt.xmin).and.(per.ne.0) ) x0 = x0 + 360.

c               Handle pole problems for hemispheric data (taken from caltra.f)
                if ((hem.eq.1).and.(y0.gt.90.)) then
                   y0=180.-y0
                   x0=x0+per/2.
                endif
                if ((hem.eq.1).and.(y0.lt.-90.)) then
                   y0=-180.-y0
                   x0=x0+per/2.
                endif
                if (y0.gt.89.99) then
                   y0=89.99
                endif

c               Loop over height profile
                    do l=1,nlev

c                 Set the pressure where to interpolate to
                      z0 = zmin + real(l-1)/real(nlev-1) * (zmax-zmin)
                      if ( centering.eq.'yes' )then
                          z0 = z0 + trainp(k,j,4)
                      endif

C                 Get the index where to interpolate (x0,y0,p0)
                  if ( (abs(x0-mdv).gt.eps).and.
     >                 (abs(y0-mdv).gt.eps) )
     >            then
                     call get_index4 (xind,yind,zind,x0,y0,z0,reltpos0,
     >                                z3t0,z3t1,zbt0,zbt1,3,
     >                                nx,ny,nz,xmin,ymin,dx,dy,mdv)
                  else
                     xind = mdv
                     yind = mdv
                     zind = mdv
                  endif

c                 If requested, apply nearest-neighbor interpolation
                  if ( intmode.eq.'nearest') then
                   
                     xind = real( nint(xind) )
                     yind = real( nint(yind) )
                     zind = real( nint(zind) )
                   
                     if ( xind.lt.1.  ) xind = 1.
                     if ( xind.gt.nx  ) xind = real(nx)
                     if ( yind.lt.1.  ) yind = 1.
                     if ( yind.gt.ny  ) yind = real(ny)

                     if ( zind.lt.1.  ) zind = 1.
                     if ( zind.gt.nz  ) zind = real(nz)

                  endif

c                 Do the interpolation: everthing is ok
                  if ( (xind.ge.1.).and.(xind.le.real(nx)).and.
     >                 (yind.ge.1.).and.(yind.le.real(ny)).and.
     >                 (zind.ge.1.).and.(zind.le.real(nz)) )
     >            then
                     f0 = int_index4(f3t0,f3t1,nx,ny,nz,
     >                               xind,yind,zind,reltpos0,mdv)
                      else
                         f0 = mdv
                      endif

c                     For a vector field, we need the second component
                      if((vector(i).ne.0).and.(abs(f0-mdv).gt.eps))then
                           v0 = int_index4(v3t0,v3t1,nx,ny,nz,
     >                                  xind,yind,zind,reltpos0,mdv)
                      else
                           v0 = mdv
                      endif

c                     Let's do a rotation for vector fields - we need the
c                     second vector component, but will not save it!
                      if ( (abs(f0-mdv).gt.eps).and.
     >                 (abs(v0-mdv).gt.eps) ) then
     >
                      if ( ind0.lt.ind1 ) then
                          urot = f0
                          vrot = v0
                          call uvrot2uv (urot,vrot,y0,x0,
     >                                   pollat,pollon,u,v)
                          f0 = u
                          v0 = v
                      else
                          urot = v0
                          vrot = f0
                          call uvrot2uv (urot,vrot,y0,x0,
     >                                   pollat,pollon,u,v)
                          f0 = v
                          v0 = u
                      endif

                  endif

c                     Save result to output array
                  if (abs(f0-mdv).gt.eps) then
                     out_val(j,l) = out_val(j,l) + f0 * fac(i)
                     out_cnt(j,l) = out_cnt(j,l) + 1.

                      endif

c              End loop over all pressure levels
                   enddo

c                  Save the output trajectory position
                   ind_time = j
                   if ( centering.eq.'no' ) then
                      ind_pre  = nint( real(nlev) *
     >                         ( (trainp(k,j,4) - zmin)/(zmax-zmin) ) + 1.)
                   else
                          ind_pre  = nint( real(nlev) *
     >                         ( (0.            - zmin)/(zmax-zmin) ) + 1.)
                   endif

                   if ( (ind_time.ge.1).and.(ind_time.le.ntim).and.
     >              (ind_pre .ge.1).and.(ind_pre .le.nlev) )
     >         then
                    out_pos(ind_time,ind_pre) =
     >                                  out_pos(ind_time,ind_pre) + 1.
                   endif

c                End loop over all trajectories
             enddo

c             End loop over all times
          enddo

c             Write the trajectory position to netCDF file - only once
              if ( i.eq.1 ) then
                  cdfname  = outfile
                  varname  = 'POSITION'
                  longname = 'position of trajectory points'
                  unit     = 'none'
                  time     = 0.
              do k=1,nlev
                levels(k) = zmin + real(k-1)/real(nlev-1) * (zmax-zmin)
              enddo
              do k=1,ntim
                 times(k) = trainp(1,k,1)
              enddo
              call writecdf2D_cf
     >            (cdfname,varname,longname,unit,out_pos,time,levels,
     >             times,nlev,ntim,1,1)
              endif

c             If no valid lidar count: set the field to missing data
          do k=1,ntim
                do l=1,nlev
                        if (abs(out_cnt(k,l)).lt.eps) then
                                out_val(k,l) = mdv
                    endif
                 enddo
          enddo

c             If requested, calculate the mean of the lidar field
              if ( outmode.eq.'mean' ) then
                do k=1,ntim
                        do l=1,nlev
                                if ( (abs(out_val(k,l)-mdv).gt.eps).and.
     >                   (abs(out_cnt(k,l)    ).gt.0. ) )
     >              then
                                        out_val(k,l) = out_val(k,l) / out_cnt(k,l)
                            endif
                         enddo
                  enddo
              endif

c             Write the lidar field and count
              cdfname  = outfile
              if (outmode.eq.'sum' ) then
                 varname  = trim(tvar(i))//'_SUM'
              elseif (outmode.eq.'mean' ) then
                 varname  = trim(tvar(i))//'_MEAN'
              endif
              longname = 'sum over all '//trim(tvar(i))//' profiles'
              unit     = 'not given'
              time     = 0.
          call writecdf2D_cf
     >            (cdfname,varname,longname,unit,out_val,time,levels,
     >             times,nlev,ntim,0,1)

                  cdfname  = outfile
              varname  = trim(tvar(i))//'_CNT'
              longname = 'counts of all '//trim(tvar(i))//' profiles'
              unit     = 'not given'
              time     = 0.
          call writecdf2D_cf
     >            (cdfname,varname,longname,unit,out_cnt,time,levels,
     >             times,nlev,ntim,0,1)

c         Exit point for loop over all tracing variables
 110      continue

c          End loop over all lidar variables
       enddo


c     --------------------------------------------------------------------
c     Write output to netCDF file
c     --------------------------------------------------------------------

c     Write status information
      print*
      print*,'---- WRITE OUTPUT LIDAR FIELDS --------------------------'
      print*


c     Write some status information, and end of program message
      print*  
      print*,'---- STATUS INFORMATION --------------------------------'
      print*
      print*,' ok'
      print*
      print*,'              *** END OF PROGRAM LIDAR ***'
      print*,'========================================================='


      end 


c     ********************************************************************
c     * INPUT / OUTPUT SUBROUTINES                                       *
c     ********************************************************************https://questionpro.com/t/CNFr6ZHxARs

c     --------------------------------------------------------------------
c     Subroutines to write the CF netcdf output file
c     --------------------------------------------------------------------

      subroutine writecdf2D_cf
     >          (cdfname,varname,longname,unit,arr,time,levels,times,
     >           npre,ntim,crefile,crevar)

c     Create and write to the CF netcdf file <cdfname>. The variable
c     with name <varname> and with time <time> is written. The data
c     are in the two-dimensional array <arr>.  The flags <crefile> and
c     <crevar> determine whether the file and/or the variable should
c     be created.

      USE netcdf

      IMPLICIT NONE

c     Declaration of input parameters
      character*80 cdfname
      character*80 varname,longname,unit
      integer      npre,ntim
      real         arr(ntim,npre)
      real         levels(npre)
      real         times (ntim)
      real         time
      integer      crefile,crevar

c     Local variables
      integer      ierr
      integer      ncID
      integer      LevDimId,    varLevID
      integer      TimeDimID,   varTimeID
      real         timeindex
      integer      i
      integer      nvars,varids(100)
      integer      ndims,dimids(100)
      real         timelist(1000)
      integer      ntimes
      integer      ind
      integer      varID

c     Quick an dirty solution for fieldname conflict
      if ( varname.eq.'time' ) varname = 'TIME'

c     Initially set error to indicate no errors.
      ierr = 0

c     ---- Create the netCDF - skip if <crefile=0> ----------------------
      if ( crefile.ne.1 ) goto 100

c     Create the file
      ierr = nf90_create(trim(cdfname), NF90_CLOBBER, ncID)

c     Define dimensions
      ierr=nf90_def_dim(ncID,'level',npre, LevDimID )
      ierr=nf90_def_dim(ncID,'time' ,ntim, TimeDimID)

c     Define coordinate Variables
      ierr = nf90_def_var(ncID,'level',NF90_FLOAT,
     >     (/ LevDimID /),varLevID)
      ierr = nf90_put_att(ncID, varLevID, "standard_name","level")
      ierr = nf90_put_att(ncID, varLevID, "units"        ,"m")

      ierr = nf90_def_var(ncID,'time',NF90_FLOAT,
     >     (/ TimeDimID /), varTimeID)
      ierr = nf90_put_att(ncID, varTimeID, "long_name",    "time")
      ierr = nf90_put_att(ncID, varTimeID, "units",       "hours")

c     Write global attributes
      ierr = nf90_put_att(ncID, NF90_GLOBAL, 'Conventions', 'CF-1.0')
      ierr = nf90_put_att(ncID, NF90_GLOBAL, 'title',
     >     'pseudo-lidar from trajectory file')
      ierr = nf90_put_att(ncID, NF90_GLOBAL, 'source',
     >     'Lagranto Trajectories')
      ierr = nf90_put_att(ncID, NF90_GLOBAL, 'institution',
     >     'ETH Zurich, IACETH')

c     Check whether the definition was successful
      ierr = nf90_enddef(ncID)
      if (ierr.gt.0) then
         print*, 'An error occurred while attempting to ',
     >        'finish definition mode.'
         stop
      endif

c     Write coordinate data
      ierr = nf90_put_var(ncID,varLevID  ,levels)
      ierr = nf90_put_var(ncID,varTimeID ,times )

c     Close netCDF file
      ierr = nf90_close(ncID)

 100  continue

c     ---- Define a new variable - skip if <crevar=0> -----------------------

      if ( crevar.ne.1 ) goto 110

c     Open the file for read/write access
      ierr = nf90_open  (trim(cdfname), NF90_WRITE  , ncID)

c     Get the IDs for dimensions
      ierr = nf90_inq_dimid(ncID,'level', LevDimID )
      ierr = nf90_inq_dimid(ncID,'time' , TimeDimID)

c     Enter define mode
      ierr = nf90_redef(ncID)

c     Write definition and add attributes
      ierr = nf90_def_var(ncID,varname,NF90_FLOAT,
     >                   (/ TimeDimID, LevDimID /),varID)
      ierr = nf90_put_att(ncID, varID, "long_name" , longname )
      ierr = nf90_put_att(ncID, varID, "units"     , unit     )
      ierr = nf90_put_att(ncID, varID, '_FillValue', -999.99  )

c     Check whether definition was successful
      ierr = nf90_enddef(ncID)
      if (ierr.gt.0) then
         print*, 'An error occurred while attempting to ',
     >           'finish definition mode.'
         stop
      endif

c     Close netCDF file
      ierr = nf90_close(ncID)

 110  continue

c     ---- Write data --------------------------------------------------

c     Open the file for read/write access
      ierr = nf90_open  (trim(cdfname), NF90_WRITE , ncID)

c     Get the varID
      ierr = nf90_inq_varid(ncID,varname, varID )
      if (ierr.ne.0) then
         print*,'Variable ',trim(varname),' is not defined on ',
     >          trim(cdfname)
         stop
      endif

c     Write data block
      ierr = nf90_put_var(ncID,varID,arr,
     >                    start = (/ 1, 1 /),
     >                    count = (/ ntim, npre/) )

c     Check whether writing was successful
      ierr = nf90_close(ncID)
      if (ierr.ne.0) then
         write(*,*) trim(nf90_strerror(ierr))
         write(*,*) 'An error occurred while attempting to ',
     >              'close the netcdf file.'
         write(*,*) 'in clscdf_CF'
      endif

      end