Back to OASIS3 home
Modules used for the scrip
library (in oasis3/lib/scrip/src) : 
remap_gaussian_weight : contains necessary routines for
performing an interpolation using a distance-gaussian-weighted average
of n nearest neighbors
used in scrip.F,
      use
kinds_mod     !
defines common data types
      use constants    
! defines common constants
      use grids        
! module containing grid info
      use remap_vars   
! module containing remap info
      implicit none
!-----------------------------------------------------------------------
!
!     module variables
!
!-----------------------------------------------------------------------
      real (kind=dbl_kind), dimension(:),
allocatable, save ::
     &     coslat, sinlat,
! cosine, sine of grid lats (for distance)
     &     coslon, sinlon,
! cosine, sine of grid lons (for distance)
     &    
wgtstmp         ! an array to
hold the link weight
!***********************************************************************
      contains
!***********************************************************************
      subroutine
remap_gauswgt (lextrapdone,
num_neighbors, rl_varmul)
!-----------------------------------------------------------------------
!
!     this routine computes the inverse-distance
weights for a
!     nearest-neighbor interpolation.
!
!-----------------------------------------------------------------------
      LOGICAL ::
    
&          
lextrapdone   ! logical, true if EXTRAP done on field
      REAL (kind=real_kind) ::
     $   
rl_varmul            
! Gaussian variance
      INTEGER (kind=int_kind) ::
     &      
num_neighbors     ! number of neighbours
!-----------------------------------------------------------------------
!
!     local variables
!
!-----------------------------------------------------------------------
      logical (kind=log_kind),
dimension(num_neighbors) ::
     &    
nbr_mask        ! mask at nearest
neighbors
      
      integer (kind=int_kind) :: n,
     &    
dst_add,        ! destination address
     &    
nmap           
! index of current map being computed
      integer (kind=int_kind),
dimension(num_neighbors) ::
     &    
nbr_add         ! source
address at nearest neighbors
      real (kind=dbl_kind),
dimension(num_neighbors) ::
     &    
nbr_dist        ! angular distance
four nearest neighbors
      real (kind=dbl_kind) ::
     &    
coslat_dst,     ! cos(lat) of destination grid point
     &    
coslon_dst,     ! cos(lon) of destination grid point
     &    
sinlat_dst,     ! sin(lat) of destination grid point
     &    
sinlon_dst,     ! sin(lon) of destination grid point
     &    
dist_tot,       ! sum of neighbor
distances (for normalizing)
     &    
dist_average    ! average distance between the source
points
      logical (kind=log_kind) :: ll_allmask,
ll_nnei
      real (kind=dbl_kind) ::
    
&        distance
,plat,plon,src_latsnn, arg   ! angular distance
      real (kind=dbl_kind), dimension (1) ::
wgts_new
      integer (kind=int_kind) :: min_add_out,
max_add_out, 
    
&        srch_add, src_addnn
!-----------------------------------------------------------------------
!
      IF (nlogprt .GE. 2) THEN
         WRITE (UNIT =
nulou,FMT = *)' '
         WRITE (UNIT =
nulou,FMT = *)'Entering routine remap_gauswgt'
         CALL FLUSH(nulou)
      ENDIF
!-----------------------------------------------------------------------
!
!     compute mappings from grid1 to grid2
!
!-----------------------------------------------------------------------
      nmap = 1
      !***
      !*** allocate wgtstmp to be consistent
with store_link interface
      !***
      allocate (wgtstmp(num_wts))
      !***
      !*** compute cos, sin of lat/lon on
source grid for distance
      !*** calculations
      !***
      allocate (coslat(grid1_size),
coslon(grid1_size),
    
&         
sinlat(grid1_size), sinlon(grid1_size))
      coslat = cos(grid1_center_lat)
      coslon = cos(grid1_center_lon)
      sinlat = sin(grid1_center_lat)
      sinlon = sin(grid1_center_lon)
      !***
      !*** compute the average of the
distances between the source points
      !*** 
      call grid_dist_average(grid1_size,
    
&                      
coslat, coslon,
    
&                      
sinlat, sinlon,
    
&                      
dist_average)
      !***
      !*** loop over destination grid 
      !***
      grid_loop1: do dst_add = 1, grid2_size
        if (.not.
grid2_mask(dst_add)) cycle grid_loop1
        coslat_dst =
cos(grid2_center_lat(dst_add))
        coslon_dst =
cos(grid2_center_lon(dst_add))
        sinlat_dst =
sin(grid2_center_lat(dst_add))
        sinlon_dst =
sin(grid2_center_lon(dst_add))
        !***
        !*** find nearest grid
points on source grid and
        !*** distances to each point
        !***
        call
grid_search_nbrg(nbr_add, nbr_dist, 
    
&                       
min_add_out, max_add_out,
    
&                       
grid2_center_lat(dst_add),
    
&                       
grid2_center_lon(dst_add),
    
&                       
coslat_dst, coslon_dst, 
    
&                       
sinlat_dst, sinlon_dst,
    
&                       
bin_addr1, 
    
&                       
dist_average,  num_neighbors, rl_varmul)
        !***
        !*** compute weights based
on inverse distance
        !*** if mask is false,
eliminate those points
        !***
        dist_tot = zero
        do n=1,num_neighbors
          if
((grid1_mask(nbr_add(n))) .or.
    
&        (.not.
grid1_mask(nbr_add(n)) .and. lextrapdone)) THEN
           
nbr_dist(n) = one/nbr_dist(n)
           
dist_tot = dist_tot + nbr_dist(n)
           
nbr_mask(n) = .true.
          else
           
nbr_mask(n) = .false.
          endif
        end do
        !***
        !*** normalize weights and
store the link
        !***
        do n=1,num_neighbors
          if (nbr_mask(n))
then
           
wgtstmp(1) = nbr_dist(n)/dist_tot
            call
store_link_nbr(nbr_add(n), dst_add, wgtstmp, nmap)
           
grid2_frac(dst_add) = one
          endif
        end do
        ll_nnei = .false.
        IF (ll_nnei) THEN
           
ll_allmask= .true.
            do
n=1,num_neighbors
             
if (nbr_mask(n)) then
                 
ll_allmask=.false.
             
endif
            end
do
            if (
ll_allmask) THEN
               
IF (nlogprt .GE. 2) THEN
                   
WRITE(nulou,*)'ll_allmask true',src_addnn
                   
CALL FLUSH(nulou)
               
ENDIF
               
src_latsnn = bignum
               
do srch_add = min_add_out,max_add_out
                 
if (grid1_mask(srch_add) .or.
    
&               
(.not. grid1_mask(srch_add) 
    
&               
.and. lextrapdone)) THEN
                     
arg = coslat_dst*cos(grid1_center_lat(srch_add))*
    
&               
(coslon_dst*cos(grid1_center_lon(srch_add)) +
    
&               
sinlon_dst*sin(grid1_center_lon(srch_add)))+
    
&               
sinlat_dst*sin(grid1_center_lat(srch_add))
                     
IF (arg < -1.0d0) THEN
                         
arg = -1.0d0
                     
ELSE IF (arg > 1.0d0) THEN
                         
arg = 1.0d0
                     
END IF
                     
distance=acos(arg)
                     
                     
if (distance < src_latsnn) then
                         
src_addnn = srch_add
                         
src_latsnn = distance
                     
endif
                 
endif
               
end do
               
wgts_new(1) = 1.
               
grid2_frac(dst_add) = one
               
call store_link_nbr(src_addnn,dst_add ,wgts_new, nmap)
            endif
        endif
            
      end do grid_loop1
      deallocate (coslat, coslon, sinlat,
sinlon)
!-----------------------------------------------------------------------
!
!     compute mappings from grid2 to grid1 if
necessary
!
!-----------------------------------------------------------------------
      if (num_maps > 1) then
      nmap = 2
      !***
      !*** compute cos, sin of lat/lon on
source grid for distance
      !*** calculations
      !***
      allocate (coslat(grid2_size),
coslon(grid2_size),
    
&         
sinlat(grid2_size), sinlon(grid2_size))
      coslat = cos(grid2_center_lat)
      coslon = cos(grid2_center_lon)
      sinlat = sin(grid2_center_lat)
      sinlon = sin(grid2_center_lon)
      !***
      !*** compute the average of the
distances between the source points
      !*** 
      call grid_dist_average(grid2_size,
    
&                      
coslat, coslon,
    
&                      
sinlat, sinlon,
    
&                      
dist_average)
      !***
      !*** loop over destination grid 
      !***
      grid_loop2: do dst_add = 1, grid1_size
        if (.not.
grid1_mask(dst_add)) cycle grid_loop2
        coslat_dst =
cos(grid1_center_lat(dst_add))
        coslon_dst =
cos(grid1_center_lon(dst_add))
        sinlat_dst =
sin(grid1_center_lat(dst_add))
        sinlon_dst =
sin(grid1_center_lon(dst_add))
        !***
        !*** find four nearest grid
points on source grid and
        !*** distances to each point
        !***
        call
grid_search_nbrg(nbr_add, nbr_dist, 
    
&                       
min_add_out, max_add_out,
    
&                       
grid1_center_lat(dst_add),
    
&                       
grid1_center_lon(dst_add),
    
&                       
coslat_dst, coslon_dst, 
    
&                       
sinlat_dst, sinlon_dst,
    
&                       
bin_addr2, 
    
&                       
dist_average, num_neighbors, rl_varmul)
        !***
        !*** compute weights based
on inverse distance
        !*** if mask is false,
eliminate those points
        !***
        dist_tot = zero
        do n=1,num_neighbors
          if
(grid2_mask(nbr_add(n))) then
           
nbr_dist(n) = one/nbr_dist(n)
           
dist_tot = dist_tot + nbr_dist(n)
           
nbr_mask(n) = .true.
          else
           
nbr_mask(n) = .false.
          endif
        end do
        !***
        !*** normalize weights and
store the link
        !***
        do n=1,num_neighbors
          if (nbr_mask(n))
then
           
wgtstmp(1) = nbr_dist(n)/dist_tot
            call
store_link_nbr(dst_add, nbr_add(n), wgtstmp, nmap)
           
grid1_frac(dst_add) = one
          endif
        end do
        IF (ll_nnei) THEN
           
ll_allmask= .true.
            do
n=1,num_neighbors
             
if (nbr_mask(n)) then
                 
ll_allmask=.false.
             
endif
            end
do
            if (
ll_allmask) then
               
PRINT*, 'll_allmask true',src_addnn   
               
src_latsnn = bignum
               
do srch_add = min_add_out,max_add_out
                 
if (grid2_mask(srch_add) .or.
    
&               
(.not. grid2_mask(srch_add) 
    
&               
.and. lextrapdone)) THEN
                     
arg = coslat_dst*cos(grid2_center_lat(srch_add))*
    
&               
(coslon_dst*cos(grid2_center_lon(srch_add)) +
    
&               
sinlon_dst*sin(grid2_center_lon(srch_add)))+
    
&               
sinlat_dst*sin(grid2_center_lat(srch_add))
                     
IF (arg < -1.0d0) THEN
                         
arg = -1.0d0
                     
ELSE IF (arg > 1.0d0) THEN
                         
arg = 1.0d0
                     
END IF
                     
distance=acos(arg)
                     
if (distance < src_latsnn) then
                         
src_addnn = srch_add
                         
src_latsnn = distance
                     
endif
                 
endif
               
end do
               
wgts_new = 1.
               
grid1_frac(dst_add) = one
               
call store_link_nbr(dst_add, src_addnn, wgts_new, nmap)
            endif
        endif
      end do grid_loop2
      deallocate (coslat, coslon, sinlat,
sinlon)
      endif
      deallocate(wgtstmp)
!
      IF (nlogprt .GE. 2) THEN
         WRITE (UNIT =
nulou,FMT = *)' '
         WRITE (UNIT =
nulou,FMT = *)'Leaving routine remap_gauswgt'
         CALL FLUSH(nulou)
      ENDIF
!
!-----------------------------------------------------------------------
      end subroutine remap_gauswgt
!***********************************************************************
      subroutine grid_search_nbrg(nbr_add,
nbr_dist, min_add, max_add, 
    
&              
plat, plon,  
    
&              
coslat_dst, coslon_dst, sinlat_dst, sinlon_dst,
    
&              
src_bin_add, dst_average,
    
$              
num_neighbors, rl_varmul)
!-----------------------------------------------------------------------
!
!     this routine finds the closest num_neighbor
points to a search 
!     point and computes a distance to each of the
neighbors.
!
!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
!
!     input variables
!
!-----------------------------------------------------------------------
      integer (kind=int_kind), dimension(:,:),
intent(in) ::
    
&        src_bin_add ! search
bins for restricting search
      real (kind=dbl_kind), intent(in) ::
    
&       
plat,         ! latitude 
of the search point
    
&       
plon,         ! longitude of
the search point
    
&        coslat_dst,  
! cos(lat)  of the search point
    
&        coslon_dst,  
! cos(lon)  of the search point
    
&        sinlat_dst,  
! sin(lat)  of the search point
    
&        sinlon_dst,  
! sin(lon)  of the search point
    
&        dst_average  
! average distance between the source points
      REAL (kind=real_kind), intent(in) ::
    
&       
rl_varmul     ! Gaussian variance
      INTEGER (kind=int_kind) ::
     &      
num_neighbors     ! number of neighbours
!-----------------------------------------------------------------------
!
!     output variables
!
!-----------------------------------------------------------------------
      integer (kind=int_kind),
dimension(num_neighbors), intent(out) ::
    
&        nbr_add  ! address
of each of the closest points
      real (kind=dbl_kind),
dimension(num_neighbors), intent(out) ::
    
&        nbr_dist ! distance to
each of the closest points
      integer (kind=int_kind),intent(out) ::
min_add, max_add 
!-----------------------------------------------------------------------
!
!     local variables
!
!-----------------------------------------------------------------------
      integer (kind=int_kind) :: n, nmax,
nadd, nchk, ! dummy indices
    
&        nm1, np1, i, j, ip1,
im1, jp1, jm1
      real (kind=dbl_kind) ::
    
&        distance,
arg      ! angular distance
      real (kind=dbl_kind) ::
    
&       
variance      ! variance for the gaussian
FUNCTION
!-----------------------------------------------------------------------
!
!     loop over source grid and find nearest
neighbors
!
!-----------------------------------------------------------------------
      !***
      !*** restrict the search using search
bins
      !*** expand the bins to catch neighbors
      !***
      select case (restrict_type)
      case('LATITUDE')
        do n=1,num_srch_bins
          if (plat >=
bin_lats(1,n) .and. plat <= bin_lats(2,n)) then
           
min_add = src_bin_add(1,n)
           
max_add = src_bin_add(2,n)
            nm1
= max(n-1,1)
            np1
= min(n+1,num_srch_bins)
           
min_add = min(min_add,src_bin_add(1,nm1))
           
max_add = max(max_add,src_bin_add(2,nm1))
           
min_add = min(min_add,src_bin_add(1,np1))
           
max_add = max(max_add,src_bin_add(2,np1))
          endif
        end do
      case('LATLON')
        n = 0
        nmax =
nint(sqrt(real(num_srch_bins)))
        do j=1,nmax
        jp1 = min(j+1,nmax)
        jm1 = max(j-1,1)
        do i=1,nmax
          ip1 =
min(i+1,nmax)
          im1 = max(i-1,1)
          n = n+1
          if (plat >=
bin_lats(1,n) .and. plat <= bin_lats(2,n) .and.
    
&        plon >=
bin_lons(1,n) .and. plon <= bin_lons(2,n)) then
           
min_add = src_bin_add(1,n)
           
max_add = src_bin_add(2,n)
            nm1
= (jm1-1)*nmax + im1
            np1
= (jp1-1)*nmax + ip1
            nm1
= max(nm1,1)
            np1
= min(np1,num_srch_bins)
           
min_add = min(min_add,src_bin_add(1,nm1))
           
max_add = max(max_add,src_bin_add(2,nm1))
           
min_add = min(min_add,src_bin_add(1,np1))
           
max_add = max(max_add,src_bin_add(2,np1))
          endif
        end do
        end do
      end select
      !***
      !*** initialize distance and address
arrays
      !***
      nbr_add = 0
      nbr_dist = bignum
      variance =
rl_varmul*dst_average*dst_average
      do nadd=min_add,max_add
        !***
        !*** find distance to this
point
        !***
        arg =
sinlat_dst*sinlat(nadd) +
    
&        coslat_dst*coslat(nadd)*
     &      
(coslon_dst*coslon(nadd) +
    
&        sinlon_dst*sinlon(nadd))
        IF (arg < -1.0d0) THEN
            arg
= -1.0d0
        ELSE IF (arg > 1.0d0) THEN
            arg
= 1.0d0
        END IF
        distance = acos(arg)
        !distance = min(500.,
distance) !ts-sv
        !distance =
exp(.5*distance*distance/variance)
        !***
        !*** store the address and
distance if this is one of the
        !*** smallest four so far
        !***
        check_loop: do
nchk=1,num_neighbors
          if (distance
.lt. nbr_dist(nchk)) THEN
            do
n=num_neighbors,nchk+1,-1
             
nbr_add(n) = nbr_add(n-1)
             
nbr_dist(n) = nbr_dist(n-1)
            end
do
           
nbr_add(nchk) = nadd
           
nbr_dist(nchk) = distance
            exit
check_loop
          endif
        end do check_loop
      end do
      exp_loop: do nchk=1,num_neighbors
          nbr_dist(nchk) =
     &    
exp(.5*nbr_dist(nchk)*nbr_dist(nchk)/variance)
      end do exp_loop
!-----------------------------------------------------------------------
      end subroutine grid_search_nbrg 
!***********************************************************************
      subroutine store_link_nbr(add1, add2,
weights, nmap)
!-----------------------------------------------------------------------
!
!     this routine stores the address and weight
for this link in
!     the appropriate address and weight arrays and
resizes those
!     arrays if necessary.
!
!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
!
!     input variables
!
!-----------------------------------------------------------------------
      integer (kind=int_kind), intent(in) ::
    
&        add1,  ! address
on grid1
    
&        add2,  ! address
on grid2
    
&        nmap   !
identifies which direction for mapping
      real (kind=dbl_kind), dimension(:),
intent(in) ::
    
&        weights ! array of
remapping weights for this link
!-----------------------------------------------------------------------
!
!     increment number of links and check to see if
remap arrays need
!     to be increased to accomodate the new
link.  then store the
!     link.
!
!-----------------------------------------------------------------------
      select case (nmap)
      case(1)
        num_links_map1  =
num_links_map1 + 1
        if (num_links_map1 >
max_links_map1) 
     &     call
resize_remap_vars(1,resize_increment)
       
grid1_add_map1(num_links_map1) = add1
       
grid2_add_map1(num_links_map1) = add2
        wts_map1   
(:,num_links_map1) = weights
      case(2)
        num_links_map2  =
num_links_map2 + 1
        if (num_links_map2 >
max_links_map2) 
     &     call
resize_remap_vars(2,resize_increment)
       
grid1_add_map2(num_links_map2) = add1
       
grid2_add_map2(num_links_map2) = add2
        wts_map2   
(:,num_links_map2) = weights
      end select
!-----------------------------------------------------------------------
      end subroutine store_link_nbr
!***********************************************************************
      subroutine grid_dist_average(grid_size,
    
&                            
coslat_grid, coslon_grid,
    
&                            
sinlat_grid, sinlon_grid,
    
&                            
dist_average)
!-----------------------------------------------------------------------
!
!     this routine computes the average distance
between the points of a
!     grid.
!
!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
!
!     output variables
!
!-----------------------------------------------------------------------
      real (kind=dbl_kind), intent(out) ::
    
&        dist_average ! distance
to each of the closest points
!-----------------------------------------------------------------------
!
!     input variables
!
!-----------------------------------------------------------------------
      integer (kind=int_kind), intent(in) ::
    
&        grid_size  
      real (kind=dbl_kind), dimension(:),
intent(in) ::
    
&       
coslat_grid,   ! cos(lat)  of the grid points
    
&       
coslon_grid,   ! cos(lon)  of the grid points
    
&       
sinlat_grid,   ! sin(lat)  of the grid points
    
&       
sinlon_grid    ! sin(lon)  of the grid points
      REAL (kind=dbl_kind) :: arg
!-----------------------------------------------------------------------
!
!     local variables
!
!-----------------------------------------------------------------------
      integer (kind=int_kind) :: i
!
      IF (nlogprt .GE. 2) THEN
         WRITE (UNIT =
nulou,FMT = *)' '
         WRITE (UNIT =
nulou,FMT = *)
     &      
'Entering routine remap_dist_average'
         CALL FLUSH(nulou)
      ENDIF
!
!-----------------------------------------------------------------------
!
!     compute the distance over the grid and average
!
!-----------------------------------------------------------------------
      dist_average = 0.0
      DO i = 1, grid_size
        IF (i .eq. 1) THEN
            arg
= sinlat_grid(grid_size)*sinlat_grid(i) +
    
&         
coslat_grid(grid_size)*coslat_grid(i)*
    
&         
(coslon_grid(grid_size)*coslon_grid(i) +
    
&         
sinlon_grid(grid_size)*sinlon_grid(i))
            IF
(arg < -1.0d0) THEN
               
arg = -1.0d0
            ELSE
IF (arg > 1.0d0) THEN
               
arg = 1.0d0
            END
IF           
           
dist_average = dist_average + acos(arg)
            arg
= sinlat_grid(i)*sinlat_grid(i+1) +
    
&         
coslat_grid(i)*coslat_grid(i+1)*
    
&         
(coslon_grid(i)*coslon_grid(i+1) +
    
&         
sinlon_grid(i)*sinlon_grid(i+1))
            IF
(arg < -1.0d0) THEN
               
arg = -1.0d0
            ELSE
IF (arg > 1.0d0) THEN
               
arg = 1.0d0
            END
IF 
           
dist_average = dist_average + acos(arg)
            
        ELSE IF (i .eq. grid_size)
THEN
            arg
= sinlat_grid(i-1)*sinlat_grid(i) +
    
&         
coslat_grid(i-1)*coslat_grid(i)*
    
&         
(coslon_grid(i-1)*coslon_grid(i) +
    
&         
sinlon_grid(i-1)*sinlon_grid(i))
            IF
(arg < -1.0d0) THEN
               
arg = -1.0d0
            ELSE
IF (arg > 1.0d0) THEN
               
arg = 1.0d0
            END
IF 
           
dist_average = dist_average + acos(arg)
            arg
= sinlat_grid(i)*sinlat_grid(1) +
    
&         
coslat_grid(i)*coslat_grid(1)*
    
&         
(coslon_grid(i)*coslon_grid(1) +
    
&         
sinlon_grid(i)*sinlon_grid(1))
            IF
(arg < -1.0d0) THEN
               
arg = -1.0d0
            ELSE
IF (arg > 1.0d0) THEN
               
arg = 1.0d0
            END
IF 
           
dist_average = dist_average + acos(arg)
            
        ELSE
            arg
= sinlat_grid(i-1)*sinlat_grid(i) +
    
&         
coslat_grid(i-1)*coslat_grid(i)*
    
&         
(coslon_grid(i-1)*coslon_grid(i) +
    
&         
sinlon_grid(i-1)*sinlon_grid(i))
            IF
(arg < -1.0d0) THEN
               
arg = -1.0d0
            ELSE
IF (arg > 1.0d0) THEN
               
arg = 1.0d0
            END
IF            
           
dist_average = dist_average + acos(arg)
            arg
= sinlat_grid(i)*sinlat_grid(i+1) +
    
&         
coslat_grid(i)*coslat_grid(i+1)*
    
&         
(coslon_grid(i)*coslon_grid(i+1) +
    
&         
sinlon_grid(i)*sinlon_grid(i+1))
            IF
(arg < -1.0d0) THEN
               
arg = -1.0d0
            ELSE
IF (arg > 1.0d0) THEN
               
arg = 1.0d0
            END
IF             
           
dist_average = dist_average +
acos(arg)            
        END IF
      END DO
      dist_average = dist_average /
(2*grid_size)
!
      IF (nlogprt .GE. 2) THEN
         WRITE (UNIT =
nulou,FMT = *)' '
         WRITE (UNIT =
nulou,FMT = *)
     &      
'Leaving routine remap_dist_average'
         CALL FLUSH(nulou)
      ENDIF
!
      END subroutine grid_dist_average