Subversion Repositories lagranto.arpege

Rev

Blame | Last modification | View Log | Download | RSS feed

   
c     -----------------------------------------------------------------------
c     Nearest distance to a lat/lon point
c     -----------------------------------------------------------------------

      subroutine get_proxy (proxy,clon,clat,tra,ntra,ntim,ncol,radius)
     
c     Given a set of trajectories tra(ntra,ntim,ncol), find the closest point
c     to clon/clat and return the footprint of this trajectory at this
c     point: proxy(ntra,ncol+1); the parameter <ncol+1> of the trajectory will
c     become the minimum distance.

      implicit none
                
c     Declaration of parameters
      integer    ntra,ntim,ncol
      real       tra(ntra,ntim,ncol)
      real       proxy(ntra,ncol+1)
      real       radius
      real       clon,clat
      
c     Flag for tests
      integer      test
      parameter    (test=0)
      character*80 testfile
      parameter    (testfile='TEST.nc')
      
c     Number of grid points for the radius mask
      integer      nmax 
      parameter    (nmax = 400)     
      real         degkm
      parameter    (degkm = 111.)
      
c     Number of binary search steps
      integer      nbin
      parameter    (nbin=10)

c     Auxiliry variables
      integer      i,j,k
      real         lon,lat,rlon,rlat
      real         dist
      character*80 varname
      integer      rnx,rny
      real         rmask (nmax,nmax)
      real         rcount(nmax,nmax)
      real         rxmin,rymin,rdx,rdy
      integer      indx,indy
      integer      isnear
      real         near,near0,near1,nearm
      integer      j0,j1
      real         r0,r1,rm,frac
      real         rlon0,rlon1,rlonm,rlat0,rlat1,rlatm
      
c     Externals
      real       sdis
      external   sdis

c     Transform into clon/clat centered system
      do i=1,ntra
        do j=1,ntim
            lon = tra(i,j,2)
            lat = tra(i,j,3)
            call getenvir_f (clon,clat,0.,rlon,rlat,lon,lat,1)
            tra(i,j,2) = rlon
            tra(i,j,3) = rlat
        enddo
      enddo
      
c     Init the radius mask - define the grid resolution
      rdx   = 2.5 * radius / degkm / real(nmax)
      rdy   = 2.5 * radius / degkm / real(nmax)
      rnx   = nmax
      rny   = nmax
      rxmin = -real(rnx/2)*rdx
      rymin = -real(rny/2)*rdy
      do i=1,rnx
         do j=1,rny
              rlon = rxmin + real(i-1) * rdx
              rlat = rymin + real(j-1) * rdy
              dist = sdis(rlon,rlat,0.,0.)
              if ( dist.lt.radius ) then
                 rmask(i,j) = dist
              else
                rmask(i,j) = radius
              endif
         enddo
      enddo

c     Init counter for test
      if ( test.eq.1 ) then
        do i=1,rnx
          do j=1,rny
            rcount(i,j) = 0.
          enddo
        enddo
      endif


c     Loop over all trajectories
      do i=1,ntra
      
c        Decide whether trajectory comes close to point   
         isnear = 0
         near   = radius
         do j=1,ntim
            indx = nint( ( tra(i,j,2) - rxmin ) / rdx + 1. )
            indy = nint( ( tra(i,j,3) - rymin ) / rdy + 1. )
            if ( (indx.ge.1).and.(indx.le.rnx).and.
     >           (indy.ge.1).and.(indy.le.rny) )
     >      then
               if (rmask(indx,indy).lt.near) then
                   near   = rmask(indx,indy)
                   isnear = j
               endif
            endif
         enddo

c        No close point was found - go to next trajectory
         do k=1,ncol
            proxy(i,k) = tra(i,1,k)
         enddo
         proxy(i,ncol+1) = radius
         if ( isnear.eq.0 ) goto 310

c        Get the exact position and time with binary search
         j0 = isnear - 1
         if ( j0.eq.0 ) j0 = 1
         rlon0 = tra(i,j0,2)
         rlat0 = tra(i,j0,3)
         near0 = sdis(rlon0,rlat0,0.,0.)
         r0    = real(j0)

         j1 = isnear + 1
         if ( j1.gt.ntim ) j1 = ntim
         rlon1 = tra(i,j1,2)
         rlat1 = tra(i,j1,3)
         near1 = sdis(tra(i,j1,2),tra(i,j1,3),0.,0.)
         r1    = real(j1)

         do k=1,nbin
            rm    = 0.5 * ( r0 + r1 )
            rlatm = 0.5 * ( rlat0 + rlat1 )
            rlonm = 0.5 * ( rlon0 + rlon1 )
            nearm = sdis(rlonm,rlatm,0.,0.)
            if ( near0.lt.near1 ) then
               r1    = rm
               rlon1 = rlonm
               rlat1 = rlatm
               near1 = nearm
            else
               r0    = rm
               rlon0 = rlonm
               rlat0 = rlatm
               near0 = nearm
            endif
         enddo

c        Now get the final distance and position
         proxy(i,ncol+1) = nearm
         if ( test.eq.1 ) then
            indx = nint( ( rlonm - rxmin ) / rdx + 1. )
            indy = nint( ( rlatm - rymin ) / rdy + 1. )
            if ( (indx.ge.1).and.(indx.le.rnx).and.
     >           (indy.ge.1).and.(indy.le.rny) )
     >      then
               rcount(indx,indy) = rcount(indx,indy) + 1.
            endif
         endif

c        Get all values at exactly this position
         j0   = int(rm)
         frac = rm - real(j0)
         j1 = j0 + 1
         if (j1.gt.ntim ) j1 = ntim
         do k=1,ncol
            proxy(i,k) = (1.-frac)*tra(i,j0,k)+frac*tra(i,j1,k)
         enddo

c        Next trajectory
310      continue

      enddo
      
c     Transform into geo system
      do i=1,ntra
         rlon = proxy(i,2)
         rlat = proxy(i,3)
         call getenvir_f (clon,clat,0.,lon,lat,rlon,rlat,1)
         proxy(i,2) = lon
         proxy(i,3) = lat
      enddo
      
c     Write radius mask to netCDF file for tests
      if ( test.eq.1 ) then
        varname = 'MASK'
        call writecdf2D(testfile,varname,rmask,0.,
     >                    rdx,rdy,rxmin,rymin,rnx,rny,1,1)
        varname = 'COUNT'
        call writecdf2D(testfile,varname,rcount,0.,
     >                    rdx,rdy,rxmin,rymin,rnx,rny,0,1)
      endif

      end



c     --------------------------------------------------------------------------------
c     Forward coordinate transformation (True lon/lat -> Rotated lon/lat)
c     --------------------------------------------------------------------------------

      SUBROUTINE getenvir_f (clon,clat,rotation,
     >                       rlon,rlat,lon,lat,n)

      implicit none

c     Declaration of input and output parameters
      integer     n
      real        clon,clat,rotation
      real        lon(n), lat(n)
      real        rlon(n),rlat(n)

c     Auxiliary variables 
      real         pollon,pollat
      integer      i
      real         rlon1(n),rlat1(n)

c     Externals
      real     lmtolms,phtophs
      external lmtolms,phtophs

c     First rotation
      pollon=clon-180.
      if (pollon.lt.-180.) pollon=pollon+360.
      pollat=90.-clat
      do i=1,n

c        First rotation
         pollon=clon-180.
         if (pollon.lt.-180.) pollon=pollon+360.
         pollat=90.-clat
         rlon1(i)=lmtolms(lat(i),lon(i),pollat,pollon)
         rlat1(i)=phtophs(lat(i),lon(i),pollat,pollon)            

c        Second coordinate transformation
         pollon=-180.
         pollat=90.+rotation
         rlon(i)=90.+lmtolms(rlat1(i),rlon1(i)-90.,pollat,pollon)
         rlat(i)=phtophs(rlat1(i),rlon1(i)-90.,pollat,pollon)   
         
      enddo

      END   

c     --------------------------------------------------------------------------------
c     Backward coordinate transformation (Rotated lon/lat -> True lon/lat)
c     --------------------------------------------------------------------------------

      SUBROUTINE getenvir_b (clon,clat,rotation,
     >                       lon,lat,rlon,rlat,n)

      implicit none

c     Declaration of input and output parameters
      integer     n
      real        clon,clat,rotation
      real        lon(n), lat(n)
      real        rlon(n),rlat(n)

c     Auxiliary variables 
      real         pollon,pollat
      integer      i
      real         rlon1(n),rlat1(n)

c     Externals
      real         lmstolm,phstoph
      external     lmstolm,phstoph

c     First coordinate transformation (make the local coordinate system parallel to equator)
      pollon=-180.
      pollat=90.+rotation
      do i=1,n
         rlon1(i)=90.+lmstolm(rlat(i),rlon(i)-90.,pollat,pollon)
         rlat1(i)=phstoph(rlat(i),rlon(i)-90.,pollat,pollon)            
      enddo

c     Second coordinate transformation (make the local coordinate system parallel to equator)
      pollon=clon-180.
      if (pollon.lt.-180.) pollon=pollon+360.
      pollat=90.-clat
      do i=1,n
         lon(i)=lmstolm(rlat1(i),rlon1(i),pollat,pollon)
         lat(i)=phstoph(rlat1(i),rlon1(i),pollat,pollon)            
      enddo

      END
      
c     -----------------------------------------------------------------------
c     Spherical distance between lat/lon points
c     -----------------------------------------------------------------------

      real function sdis(xp,yp,xq,yq)
c
c     calculates spherical distance (in km) between two points given
c     by their spherical coordinates (xp,yp) and (xq,yq), respectively.
c
      real      re
      parameter (re=6370.)
      real      pi180
      parameter (pi180=3.14159/180.)
      real      xp,yp,xq,yq,arg

      arg=sin(pi180*yp)*sin(pi180*yq)+
     >    cos(pi180*yp)*cos(pi180*yq)*cos(pi180*(xp-xq))
      if (arg.lt.-1.) arg=-1.
      if (arg.gt.1.) arg=1.

      sdis=re*acos(arg)

      end