New URL for NEMO forge!   http://forge.nemo-ocean.eu

Since March 2022 along with NEMO 4.2 release, the code development moved to a self-hosted GitLab.
This present forge is now archived and remained online for history.
bilinear_interp.f90 in utils/tools_dev_r12970_AGRIF_CMEMS/DOMAINcfg/src – NEMO

source: utils/tools_dev_r12970_AGRIF_CMEMS/DOMAINcfg/src/bilinear_interp.f90 @ 13024

Last change on this file since 13024 was 13024, checked in by rblod, 4 years ago

First version of new nesting tools merged with domaincfg, see ticket #2129

File size: 40.0 KB
Line 
1!
2MODULE bilinear_interp
3  !
4  USE agrif_modutil
5  !
6  !************************************************************************
7  !                           *
8  ! MODULE  BILINEAR INTERP                  *
9  !                           *
10  ! bilinear interpolation routines from SCRIP package         *     
11  !                           *
12  !http://climate.lanl.gov/Software/SCRIP/            *
13  !                           *
14  !Bilinear remapping                     *
15  !                           *
16  !************************************************************************
17  !     
18  !-----------------------------------------------------------------------
19  IMPLICIT NONE
20
21  !-----------------------------------------------------------------------
22  !     variables that describe each grid
23  !-----------------------------------------------------------------------
24  !
25  INTEGER :: grid1_size,grid2_size,grid1_rank, grid2_rank
26  !     
27  INTEGER, DIMENSION(:), ALLOCATABLE :: grid1_dims, grid2_dims 
28 
29
30  !-----------------------------------------------------------------------
31  !     grid coordinates and masks
32  !-----------------------------------------------------------------------
33  !
34  LOGICAL, DIMENSION(:), ALLOCATABLE :: grid1_mask,grid2_mask       
35  ! each grid center in radians
36  REAL*8,DIMENSION(:), ALLOCATABLE :: &
37       grid1_center_lat,  &
38       grid1_center_lon,  & 
39       grid2_center_lat,  &
40       grid2_center_lon,  &
41       grid1_frac,        & ! fractional area of grid cells
42       grid2_frac           ! participating in remapping
43  !
44  ! lat/lon bounding box for use in restricting grid searches
45  !
46  REAL*8,DIMENSION(:,:), ALLOCATABLE :: grid1_bound_box,grid2_bound_box   
47  !
48  !-----------------------------------------------------------------------
49  !     bins for restricting searches
50  !-----------------------------------------------------------------------
51  !
52  ! num of bins for restricted srch
53  INTEGER, PARAMETER :: num_srch_bins = 90 
54  !
55  ! min,max adds for grid cells in this lat bin
56  !
57  INTEGER,DIMENSION(:,:), ALLOCATABLE :: bin_addr1,bin_addr2 
58  !
59  ! min,max longitude for each search bin
60  !
61  REAL*8, DIMENSION(:,:), ALLOCATABLE  :: bin_lats,bin_lons 
62
63  REAL*8, PARAMETER :: zero   = 0.0,  &
64       one    = 1.0,  &
65       two    = 2.0,  &
66       three  = 3.0,  &
67       four   = 4.0,  &
68       five   = 5.0,  & 
69       half   = 0.5,  &
70       quart  = 0.25, &
71       bignum = 1.e+20, &
72       tiny   = 1.e-14, &
73       pi     = 3.14159265359, &
74       pi2    = two*pi, &
75       pih    = half*pi       
76
77  REAL*8, PARAMETER :: deg2rad = pi/180.
78  !
79  ! max iteration count for i,j iteration
80  !   
81  INTEGER , PARAMETER :: max_iter = 100   
82  !
83  ! convergence criterion
84  !
85  REAL*8, PARAMETER :: converge = 1.e-10
86
87
88 
89  INTEGER, PARAMETER :: norm_opt_none    = 1 &
90       ,norm_opt_dstarea = 2 &
91       ,norm_opt_frcarea = 3
92  !
93  INTEGER, PARAMETER :: map_type_conserv  = 1 &
94       ,map_type_bilinear = 2 &
95       ,map_type_bicubic  = 3 &
96       ,map_type_distwgt  = 4
97  !
98  INTEGER :: max_links_map1  &  ! current size of link arrays
99       ,num_links_map1  &  ! actual number of links for remapping
100       ,max_links_map2  &  ! current size of link arrays
101       ,num_links_map2  &  ! actual number of links for remapping
102       ,num_maps        &  ! num of remappings for this grid pair
103       ,num_wts         &  ! num of weights used in remapping
104       ,map_type        &  ! identifier for remapping method
105       ,norm_opt        &  ! option for normalization (conserv only)
106       ,resize_increment ! default amount to increase array size
107
108  INTEGER , DIMENSION(:), ALLOCATABLE :: &
109       grid1_add_map1, &  ! grid1 address for each link in mapping 1
110       grid2_add_map1, &  ! grid2 address for each link in mapping 1
111       grid1_add_map2, &  ! grid1 address for each link in mapping 2
112       grid2_add_map2    ! grid2 address for each link in mapping 2
113
114  REAL*8, DIMENSION(:,:), ALLOCATABLE ::   &
115       wts_map1, &   ! map weights for each link (num_wts,max_links)
116       wts_map2     ! map weights for each link (num_wts,max_links)
117  !
118CONTAINS 
119  !     
120!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
121  !************************************************************************
122  !   SUBROUTINE GRID_INIT
123  !************************************************************************
124!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
125  !
126  SUBROUTINE get_remap_matrix(grid1_lat,grid2_lat,grid1_lon,grid2_lon,mask, &
127       remap_matrix,source_add,destination_add)
128    !
129    !-----------------------------------------------------------------------
130    !this routine makes any necessary changes (e.g. for 0,2pi longitude range)
131    !-----------------------------------------------------------------------
132    !
133    REAL*8,DIMENSION(:,:) :: grid1_lat,grid2_lat,grid1_lon,grid2_lon
134    LOGICAL,DIMENSION(:,:) :: mask
135    !     
136    INTEGER,DIMENSION(:),ALLOCATABLE :: source_add,destination_add 
137    REAL*8,DIMENSION(:,:), ALLOCATABLE :: remap_matrix       
138    !
139    !-----------------------------------------------------------------------
140    ! local variables
141    !-----------------------------------------------------------------------
142    !
143    INTEGER :: n,nele,i,j,ip1,jp1,n_add,e_add,ne_add,nx,ny
144    INTEGER :: xpos,ypos
145    !         
146    ! integer mask
147    !
148    INTEGER, DIMENSION(:), ALLOCATABLE :: imask 
149    !
150    ! lat/lon intervals for search bins
151    !
152    REAL*8 :: dlat,dlon           
153    !     
154    ! temps for computing bounding boxes
155    !
156    REAL*8, DIMENSION(4) :: tmp_lats, tmp_lons 
157    !
158    !      write(*,*)'proceed to Bilinear interpolation ...'
159    !
160!    IF(ALLOCATED(wts_map1)) DEALLOCATE(wts_map1)
161!    IF(ALLOCATED(grid1_add_map1)) DEALLOCATE(grid1_add_map1)
162!    IF(ALLOCATED(grid2_add_map1)) DEALLOCATE(grid2_add_map1)
163
164
165    !
166    ALLOCATE(grid1_dims(2),grid2_dims(2))
167    !     
168    grid1_dims(1) = SIZE(grid1_lat,2)
169    grid1_dims(2) = SIZE(grid1_lat,1)
170    grid2_dims(1) = SIZE(grid2_lat,2)
171    grid2_dims(2) = SIZE(grid2_lat,1)
172    grid1_size = SIZE(grid1_lat,2) * SIZE(grid1_lat,1)
173    grid2_size = SIZE(grid2_lat,2) * SIZE(grid2_lat,1) 
174    !     
175    !-----------------------------------------------------------------------
176    !     allocate grid coordinates/masks and read data
177    !-----------------------------------------------------------------------
178    !     
179    ALLOCATE( grid2_mask(grid2_size),         &
180         grid1_bound_box (4,grid1_size), &
181         grid2_bound_box (4,grid2_size), &
182         grid1_frac      (grid1_size),   &
183         grid2_frac      (grid2_size))
184    ALLOCATE(imask(grid1_size))
185    !                 
186    !     
187    grid1_frac = zero
188    grid2_frac = zero
189
190    !
191    ! 2D array -> 1D array
192    !
193    ALLOCATE(grid1_center_lat(SIZE(grid1_lat,1)*SIZE(grid1_lat,2)))
194    CALL tab2Dto1D(grid1_lat,grid1_center_lat)
195
196    ALLOCATE(grid1_center_lon(SIZE(grid1_lon,1)*SIZE(grid1_lon,2)))
197    CALL tab2Dto1D(grid1_lon,grid1_center_lon)
198
199    ALLOCATE(grid2_center_lat(SIZE(grid2_lat,1)*SIZE(grid2_lat,2)))
200    CALL tab2Dto1D(grid2_lat,grid2_center_lat)
201
202    ALLOCATE(grid2_center_lon(SIZE(grid2_lon,1)*SIZE(grid2_lon,2)))     
203    CALL tab2Dto1D(grid2_lon,grid2_center_lon) 
204
205    ALLOCATE(grid1_mask(SIZE(grid1_lat,1)*SIZE(grid1_lat,2)))
206    CALL logtab2Dto1D(mask,grid1_mask)
207    !     
208    !      Write(*,*) ,'grid1_mask = ',grid1_mask                 
209    !
210    ! degrees to radian
211    !
212    grid1_center_lat = grid1_center_lat*deg2rad
213    grid1_center_lon = grid1_center_lon*deg2rad
214    grid2_center_lat = grid2_center_lat*deg2rad
215    grid2_center_lon = grid2_center_lon*deg2rad
216
217    !-----------------------------------------------------------------------
218    !     convert longitudes to 0,2pi interval
219    !-----------------------------------------------------------------------
220
221    WHERE (grid1_center_lon .GT. pi2)  grid1_center_lon =       &
222         grid1_center_lon - pi2
223    WHERE (grid1_center_lon .LT. zero) grid1_center_lon =       &
224         grid1_center_lon + pi2
225    WHERE (grid2_center_lon .GT. pi2)  grid2_center_lon =       &
226         grid2_center_lon - pi2
227    WHERE (grid2_center_lon .LT. zero) grid2_center_lon =       &
228         grid2_center_lon + pi2
229
230    !-----------------------------------------------------------------------
231    !
232    !     make sure input latitude range is within the machine values
233    !     for +/- pi/2
234    !
235    !-----------------------------------------------------------------------
236
237    WHERE (grid1_center_lat >  pih) grid1_center_lat =  pih
238    WHERE (grid1_center_lat < -pih) grid1_center_lat = -pih
239    WHERE (grid2_center_lat >  pih) grid2_center_lat =  pih
240    WHERE (grid2_center_lat < -pih) grid2_center_lat = -pih
241
242    !-----------------------------------------------------------------------
243    !
244    !     compute bounding boxes for restricting future grid searches
245    !
246    !-----------------------------------------------------------------------
247    !
248    nx = grid1_dims(1)
249    ny = grid1_dims(2)
250
251    DO n=1,grid1_size
252
253       !*** find N,S and NE points to this grid point
254
255       j = (n - 1)/nx +1
256       i = n - (j-1)*nx
257
258       IF (i < nx) THEN
259          ip1 = i + 1
260       ELSE
261          !*** assume cyclic
262          ip1 = 1
263          !*** but if it is not, correct
264          e_add = (j - 1)*nx + ip1
265          IF (ABS(grid1_center_lat(e_add) -     &
266               grid1_center_lat(n   )) > pih) THEN
267             ip1 = i
268          ENDIF
269          ip1=nx
270       ENDIF
271
272       IF (j < ny) THEN
273          jp1 = j+1
274       ELSE
275          !*** assume cyclic
276          jp1 = 1
277          !*** but if it is not, correct
278          n_add = (jp1 - 1)*nx + i
279          IF (ABS(grid1_center_lat(n_add) -             &
280               grid1_center_lat(n   )) > pih) THEN
281             jp1 = j
282          ENDIF
283          jp1=ny
284       ENDIF
285
286       n_add = (jp1 - 1)*nx + i
287       e_add = (j - 1)*nx + ip1
288       ne_add = (jp1 - 1)*nx + ip1
289
290       !*** find N,S and NE lat/lon coords and check bounding box
291
292       tmp_lats(1) = grid1_center_lat(n)
293       tmp_lats(2) = grid1_center_lat(e_add)
294       tmp_lats(3) = grid1_center_lat(ne_add)
295       tmp_lats(4) = grid1_center_lat(n_add)
296
297       tmp_lons(1) = grid1_center_lon(n)
298       tmp_lons(2) = grid1_center_lon(e_add)
299       tmp_lons(3) = grid1_center_lon(ne_add)
300       tmp_lons(4) = grid1_center_lon(n_add)
301
302       grid1_bound_box(1,n) = MINVAL(tmp_lats)
303       grid1_bound_box(2,n) = MAXVAL(tmp_lats)
304
305       grid1_bound_box(3,n) = MINVAL(tmp_lons)
306       grid1_bound_box(4,n) = MAXVAL(tmp_lons)
307    END DO
308
309    nx = grid2_dims(1)
310    ny = grid2_dims(2)
311
312    DO n=1,grid2_size
313
314       !*** find N,S and NE points to this grid point
315
316       j = (n - 1)/nx +1
317       i = n - (j-1)*nx
318
319       IF (i < nx) THEN
320          ip1 = i + 1
321       ELSE
322          !*** assume cyclic
323          ip1 = 1
324          !*** but if it is not, correct
325          e_add = (j - 1)*nx + ip1
326          IF (ABS(grid2_center_lat(e_add) -  &
327               grid2_center_lat(n   )) > pih) THEN
328             ip1 = i
329          ENDIF
330       ENDIF
331
332       IF (j < ny) THEN
333          jp1 = j+1
334       ELSE
335          !*** assume cyclic
336          jp1 = 1
337          !*** but if it is not, correct
338          n_add = (jp1 - 1)*nx + i
339          IF (ABS(grid2_center_lat(n_add) -  &
340               grid2_center_lat(n   )) > pih) THEN
341             jp1 = j
342          ENDIF
343       ENDIF
344
345       n_add = (jp1 - 1)*nx + i
346       e_add = (j - 1)*nx + ip1
347       ne_add = (jp1 - 1)*nx + ip1
348
349       !*** find N,S and NE lat/lon coords and check bounding box
350
351       tmp_lats(1) = grid2_center_lat(n)
352       tmp_lats(2) = grid2_center_lat(e_add)
353       tmp_lats(3) = grid2_center_lat(ne_add)
354       tmp_lats(4) = grid2_center_lat(n_add)
355
356       tmp_lons(1) = grid2_center_lon(n)
357       tmp_lons(2) = grid2_center_lon(e_add)
358       tmp_lons(3) = grid2_center_lon(ne_add)
359       tmp_lons(4) = grid2_center_lon(n_add)
360
361       grid2_bound_box(1,n) = MINVAL(tmp_lats)
362       grid2_bound_box(2,n) = MAXVAL(tmp_lats)
363       grid2_bound_box(3,n) = MINVAL(tmp_lons)
364       grid2_bound_box(4,n) = MAXVAL(tmp_lons)
365    END DO
366    !
367    !
368    !
369    WHERE (ABS(grid1_bound_box(4,:) - grid1_bound_box(3,:)) > pi)
370       grid1_bound_box(3,:) = zero
371       grid1_bound_box(4,:) = pi2
372    END WHERE
373
374    WHERE (ABS(grid2_bound_box(4,:) - grid2_bound_box(3,:)) > pi)
375       grid2_bound_box(3,:) = zero
376       grid2_bound_box(4,:) = pi2
377    END WHERE
378
379    !***
380    !*** try to check for cells that overlap poles
381    !***
382
383    WHERE (grid1_center_lat > grid1_bound_box(2,:)) &
384         grid1_bound_box(2,:) = pih
385
386    WHERE (grid1_center_lat < grid1_bound_box(1,:)) &
387         grid1_bound_box(1,:) = -pih
388
389    WHERE (grid2_center_lat > grid2_bound_box(2,:)) &
390         grid2_bound_box(2,:) = pih
391
392    WHERE (grid2_center_lat < grid2_bound_box(1,:)) &
393         grid2_bound_box(1,:) = -pih
394
395    !-----------------------------------------------------------------------
396    !     set up and assign address ranges to search bins in order to
397    !     further restrict later searches
398    !-----------------------------------------------------------------------
399
400    ALLOCATE(bin_addr1(2,num_srch_bins))
401    ALLOCATE(bin_addr2(2,num_srch_bins))
402    ALLOCATE(bin_lats (2,num_srch_bins))
403    ALLOCATE(bin_lons (2,num_srch_bins))
404
405    dlat = pi/num_srch_bins
406
407    DO n=1,num_srch_bins
408       bin_lats(1,n) = (n-1)*dlat - pih
409       bin_lats(2,n) =     n*dlat - pih
410       bin_lons(1,n) = zero
411       bin_lons(2,n) = pi2
412       bin_addr1(1,n) = grid1_size + 1
413       bin_addr1(2,n) = 0
414       bin_addr2(1,n) = grid2_size + 1
415       bin_addr2(2,n) = 0
416    END DO
417
418    DO nele=1,grid1_size
419       DO n=1,num_srch_bins
420          IF (grid1_bound_box(1,nele) <= bin_lats(2,n) .AND.   &
421               grid1_bound_box(2,nele) >= bin_lats(1,n)) THEN
422             bin_addr1(1,n) = MIN(nele,bin_addr1(1,n))
423             bin_addr1(2,n) = MAX(nele,bin_addr1(2,n))
424          ENDIF
425       END DO
426    END DO
427
428    DO nele=1,grid2_size
429       DO n=1,num_srch_bins
430          IF (grid2_bound_box(1,nele) <= bin_lats(2,n) .AND.    &
431               grid2_bound_box(2,nele) >= bin_lats(1,n)) THEN
432             bin_addr2(1,n) = MIN(nele,bin_addr2(1,n))
433             bin_addr2(2,n) = MAX(nele,bin_addr2(2,n))
434          ENDIF
435       END DO
436    END DO
437    !
438    CALL init_remap_vars 
439    CALL remap_bilin
440
441    ALLOCATE(remap_matrix(SIZE(wts_map1,1),SIZE(wts_map1,2)), &
442         source_add(SIZE(grid1_add_map1)),       &
443         destination_add(SIZE(grid2_add_map1)))
444
445    DO j = 1,SIZE(wts_map1,2)
446       DO i = 1,SIZE(wts_map1,1)
447
448          remap_matrix(i,j) = wts_map1(i,j)
449
450       END DO
451    END DO
452
453
454    source_add(:) = grid1_add_map1(:)
455    destination_add(:) = grid2_add_map1(:)               
456    !
457    WHERE(destination_add == 0)
458       destination_add = 1
459    END WHERE
460
461    WHERE(source_add == 0)
462       source_add = 1
463    END WHERE
464    !               
465    !DEALLOCATE(grid1_bound_box,grid2_bound_box,grid1_center_lat,grid1_center_lon)
466    !DEALLOCATE(grid2_center_lat,grid2_center_lon,grid2_add_map1,grid1_add_map1,wts_map1)
467    !DEALLOCATE(grid1_frac,grid2_frac,grid1_dims,grid2_dims,grid2_mask,imask)
468    !DEALLOCATE(bin_addr1,bin_addr2,bin_lats,bin_lons)
469    !DEALLOCATE(grid1_mask)   
470    !
471    !-----------------------------------------------------------------------
472
473  END SUBROUTINE get_remap_matrix
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498  !***********************************************************************
499!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
500  !************************************************************************
501  !   SUBROUTINE REMAP_BILINEAR
502  !************************************************************************
503!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
504
505  SUBROUTINE remap_bilin
506
507    !-----------------------------------------------------------------------
508    !     this routine computes the weights for a bilinear interpolation.
509    !-----------------------------------------------------------------------
510
511    !-----------------------------------------------------------------------
512    !     local variables
513    !-----------------------------------------------------------------------
514
515    INTEGER :: n,icount,dst_add,iter,nmap,nbmasked   
516    !       
517    ! address for the four source points
518    !
519    INTEGER, DIMENSION(4) :: src_add,involved_pts
520    INTEGER, DIMENSION(1) :: minlon
521    INTEGER, DIMENSION(1) :: minlat
522    REAL*8, DIMENSION(4) :: distx,disty
523    REAL*8 :: normalize
524    !               
525    ! latitudes longitudes of four bilinear corners
526    !
527    REAL*8, DIMENSION(4) :: src_lats,src_lons
528    !
529    ! bilinear weights for four corners
530    !     
531    REAL*8, DIMENSION(4) :: wgts           
532    !
533    REAL*8 :: &
534         plat, plon,       &  ! lat/lon coords of destination point
535         iguess, jguess,   &  ! current guess for bilinear coordinate
536         thguess, phguess, &  ! current guess for lat/lon coordinate
537         deli, delj,       &  ! corrections to i,j
538         dth1, dth2, dth3, &  ! some latitude  differences
539         dph1, dph2, dph3, &  ! some longitude differences
540         dthp, dphp,       &  ! difference between point and sw corner
541         mat1, mat2, mat3, mat4, &  ! matrix elements
542         determinant, &     ! matrix determinant
543         sum_wgts          ! sum of weights for normalization
544
545    INTEGER lastsrc_add 
546    REAL*8,DIMENSION(:),ALLOCATABLE :: cos_grid1_center_lat   
547    REAL*8,DIMENSION(:),ALLOCATABLE :: cos_grid1_center_lon
548    REAL*8,DIMENSION(:),ALLOCATABLE :: sin_grid1_center_lat
549    REAL*8,DIMENSION(:),ALLOCATABLE :: sin_grid1_center_lon
550    INTEGER :: i
551    !     
552    grid2_mask = .TRUE.
553    !     
554    !     
555    nmap = 1
556    !
557    !***
558    !*** loop over destination grid
559    !***
560    !      print*,'grid2_size =',grid2_size
561    !     
562    lastsrc_add=1
563    !
564    Allocate(cos_grid1_center_lat(size(grid1_center_lat)))
565    Allocate(sin_grid1_center_lat(size(grid1_center_lat)))
566    Allocate(cos_grid1_center_lon(size(grid1_center_lon)))
567    Allocate(sin_grid1_center_lon(size(grid1_center_lon)))
568
569    do i=1,size(grid1_center_lat)
570        cos_grid1_center_lat(i)=cos(grid1_center_lat(i))
571        sin_grid1_center_lat(i)=sin(grid1_center_lat(i))
572    ENDDO
573
574    do i=1,size(grid1_center_lon)
575        cos_grid1_center_lon(i)=cos(grid1_center_lon(i))
576        sin_grid1_center_lon(i)=sin(grid1_center_lon(i))
577    ENDDO
578
579    grid_loop1: DO dst_add = 1, grid2_size
580
581       IF (.NOT. grid2_mask(dst_add)) CYCLE grid_loop1
582       !       
583       plat = grid2_center_lat(dst_add)
584       plon = grid2_center_lon(dst_add)
585       !***
586       !*** find nearest square of grid points on source grid
587       !***
588       CALL grid_search_bilin(src_add, src_lats, src_lons,          &
589            plat, plon, grid1_dims,               &
590            grid1_center_lat, cos_grid1_center_lat, sin_grid1_center_lat, &
591            grid1_center_lon, cos_grid1_center_lon, sin_grid1_center_lon,  & 
592            grid1_bound_box, bin_addr1, bin_addr2,lastsrc_add)           
593       !***
594       !*** check to see if points are land points
595       !***
596       !   
597       IF (src_add(1) > 0) THEN
598          !     
599          DO n=1,4
600             !           if(.not. grid1_mask(src_add(n))) nbmasked = nbmasked + 1
601             IF(.NOT. grid1_mask(src_add(n))) src_add(1) = 0
602          END DO
603          !
604       ENDIF
605       !
606       !
607
608       !***
609       !*** if point found, find local i,j coordinates for weights
610       !***
611       IF (src_add(1) > 0) THEN
612          grid2_frac(dst_add) = one
613          !***
614          !*** iterate to find i,j for bilinear approximation
615          !***
616          dth1 = src_lats(2) - src_lats(1)
617          dth2 = src_lats(4) - src_lats(1)
618          dth3 = src_lats(3) - src_lats(2) - dth2
619
620          dph1 = src_lons(2) - src_lons(1)
621          dph2 = src_lons(4) - src_lons(1)
622          dph3 = src_lons(3) - src_lons(2)
623
624          IF (dph1 >  three*pih) dph1 = dph1 - pi2
625          IF (dph2 >  three*pih) dph2 = dph2 - pi2
626          IF (dph3 >  three*pih) dph3 = dph3 - pi2
627          IF (dph1 < -three*pih) dph1 = dph1 + pi2
628          IF (dph2 < -three*pih) dph2 = dph2 + pi2
629          IF (dph3 < -three*pih) dph3 = dph3 + pi2
630
631          dph3 = dph3 - dph2
632
633          iguess = half
634          jguess = half
635
636          iter_loop1: DO iter=1,max_iter
637
638             dthp = plat - src_lats(1) - dth1*iguess -        &
639                  dth2*jguess - dth3*iguess*jguess
640             dphp = plon - src_lons(1)
641
642             IF (dphp >  three*pih) dphp = dphp - pi2
643             IF (dphp < -three*pih) dphp = dphp + pi2
644
645             dphp = dphp - dph1*iguess - dph2*jguess -        &
646                  dph3*iguess*jguess
647
648             mat1 = dth1 + dth3*jguess
649             mat2 = dth2 + dth3*iguess
650             mat3 = dph1 + dph3*jguess
651             mat4 = dph2 + dph3*iguess
652
653             determinant = mat1*mat4 - mat2*mat3
654
655             deli = (dthp*mat4 - mat2*dphp)/determinant
656             delj = (mat1*dphp - dthp*mat3)/determinant
657
658             IF (ABS(deli) < converge .AND.                   &
659                  ABS(delj) < converge) EXIT iter_loop1
660
661             iguess = iguess + deli
662             jguess = jguess + delj
663
664          END DO iter_loop1
665
666          IF (iter <= max_iter) THEN
667
668             !***
669             !*** successfully found i,j - compute weights
670             !***
671
672             wgts(1) = (one-iguess)*(one-jguess)
673             wgts(2) = iguess*(one-jguess)
674             wgts(3) = iguess*jguess
675             wgts(4) = (one-iguess)*jguess
676             !               
677             !
678             CALL store_link_bilin(dst_add, src_add, wgts, nmap)
679
680          ELSE
681             PRINT *,'Point coords: ',plat,plon
682             PRINT *,'Dest grid lats: ',src_lats
683             PRINT *,'Dest grid lons: ',src_lons
684             PRINT *,'Dest grid addresses: ',src_add
685             PRINT *,'Current i,j : ',iguess, jguess
686             STOP 'Iteration for i,j exceed max iteration count'
687          ENDIF
688          !
689          !***
690          !*** search for bilinear failed - use a distance-weighted
691          !*** average instead (this is typically near the pole)
692          !***
693       ELSE IF (src_add(1) < 0) THEN
694
695          src_add = ABS(src_add)
696          icount = 0
697          DO n=1,4
698             !           
699             IF (grid1_mask(src_add(n))) THEN
700                icount = icount + 1
701             ELSE
702                src_lats(n) = zero
703             ENDIF
704             !     
705          END DO
706
707          IF (icount > 0) THEN
708             !   
709             !*** renormalize weights
710             !
711             sum_wgts = SUM(src_lats)
712             wgts(1) = src_lats(1)/sum_wgts
713             wgts(2) = src_lats(2)/sum_wgts
714             wgts(3) = src_lats(3)/sum_wgts
715             wgts(4) = src_lats(4)/sum_wgts
716             !
717             grid2_frac(dst_add) = one
718             CALL store_link_bilin(dst_add, src_add, wgts, nmap)
719          ENDIF
720
721          !
722       ENDIF
723    END DO grid_loop1
724    !     
725    !      Call sort_add(grid2_add_map1, grid1_add_map1, wts_map1)   
726    !               
727    !
728    !-----------------------------------------------------------------------
729
730    deallocate(cos_grid1_center_lat)
731    deallocate(cos_grid1_center_lon)
732    deallocate(sin_grid1_center_lat)
733    deallocate(sin_grid1_center_lon)
734  END SUBROUTINE remap_bilin
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753  !***********************************************************************
754!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
755  !************************************************************************
756  !   SUBROUTINE GRID_SEARCH_BILIN
757  !************************************************************************
758!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
759  !
760  SUBROUTINE grid_search_bilin(src_add, src_lats, src_lons,   &
761       plat, plon, src_grid_dims,      &
762       src_center_lat, cos_src_center_lat, sin_src_center_lat, &
763       src_center_lon, cos_src_center_lon, sin_src_center_lon,& 
764       src_grid_bound_box,             &
765       src_bin_add, dst_bin_add,lastsrc_add)
766
767    !-----------------------------------------------------------------------
768    !
769    !     this routine finds the location of the search point plat, plon
770    !     in the source grid and returns the corners needed for a bilinear
771    !     interpolation.
772    !
773    !-----------------------------------------------------------------------
774
775    !-----------------------------------------------------------------------
776    !     output variables
777    !-----------------------------------------------------------------------
778    !
779    ! address of each corner point enclosing P
780    !
781    INTEGER,DIMENSION(4) :: src_add 
782    REAL*8,DIMENSION(4) :: src_lats,src_lons 
783    !     
784    !-----------------------------------------------------------------------
785    !     input variables
786    !-----------------------------------------------------------------------
787    !
788    ! latitude, longitude of the search point
789    !
790    REAL*8, INTENT(in) :: plat,plon   
791    !
792    ! size of each src grid dimension
793    !
794    INTEGER, DIMENSION(2), INTENT(in) :: src_grid_dims 
795    !
796    ! latitude, longitude of each src grid center
797    !
798    REAL*8, DIMENSION(:), INTENT(in) :: src_center_lat,src_center_lon 
799    REAL*8, DIMENSION(:), INTENT(in) :: cos_src_center_lat
800    REAL*8, DIMENSION(:), INTENT(in) :: sin_src_center_lat
801    REAL*8, DIMENSION(:), INTENT(in) :: cos_src_center_lon
802    REAL*8, DIMENSION(:), INTENT(in) :: sin_src_center_lon
803    !
804    ! bound box for source grid
805    !
806    REAL*8, DIMENSION(:,:), INTENT(in) :: src_grid_bound_box 
807    !
808    ! latitude bins for restricting searches
809    !
810    INTEGER, DIMENSION(:,:), INTENT(in) ::src_bin_add,dst_bin_add 
811
812    INTEGER,OPTIONAL :: lastsrc_add
813    INTEGER :: loopsrc,l1,l2
814    !     
815    !-----------------------------------------------------------------------
816    !     local variables
817    !-----------------------------------------------------------------------
818    !
819    INTEGER :: n,next_n,srch_add,nx, ny,min_add, max_add,  &
820         i, j, jp1, ip1, n_add, e_add, ne_add
821
822
823    REAL*8 ::  vec1_lat, vec1_lon,vec2_lat, vec2_lon, cross_product,  &
824         cross_product_last,coslat_dst, sinlat_dst, coslon_dst, &
825         sinlon_dst,dist_min, distance 
826
827    !-----------------------------------------------------------------------
828    !     restrict search first using bins
829    !-----------------------------------------------------------------------
830
831    src_add = 0
832
833    min_add = SIZE(src_center_lat)
834    max_add = 1
835    DO n=1,num_srch_bins
836       IF (plat >= bin_lats(1,n) .AND. plat <= bin_lats(2,n) .AND. &
837            plon >= bin_lons(1,n) .AND. plon <= bin_lons(2,n)) THEN
838          min_add = MIN(min_add, src_bin_add(1,n))
839          max_add = MAX(max_add, src_bin_add(2,n))
840       ENDIF
841    END DO
842
843    !-----------------------------------------------------------------------
844    !     now perform a more detailed search
845    !-----------------------------------------------------------------------
846
847    nx = src_grid_dims(1)
848    ny = src_grid_dims(2)
849
850    loopsrc=0
851    DO WHILE (loopsrc <= max_add)
852
853
854       l1=MAX(min_add,lastsrc_add-loopsrc)
855       l2=MIN(max_add,lastsrc_add+loopsrc)     
856
857       loopsrc = loopsrc+1
858
859       srch_loop: DO srch_add = l1,l2,MAX(l2-l1,1)
860
861          !*** first check bounding box
862
863          IF (plat <= src_grid_bound_box(2,srch_add) .AND. & 
864               plat >= src_grid_bound_box(1,srch_add) .AND.  &
865               plon <= src_grid_bound_box(4,srch_add) .AND.  &
866               plon >= src_grid_bound_box(3,srch_add)) THEN
867             !***
868             !*** we are within bounding box so get really serious
869             !***
870             !*** determine neighbor addresses
871             !
872             j = (srch_add - 1)/nx +1
873             i = srch_add - (j-1)*nx
874             !
875             IF (i < nx) THEN
876                ip1 = i + 1
877             ELSE
878                ip1 = 1
879             ENDIF
880             !
881             IF (j < ny) THEN
882                jp1 = j+1
883             ELSE
884                jp1 = 1
885             ENDIF
886             !
887             n_add = (jp1 - 1)*nx + i
888             e_add = (j - 1)*nx + ip1
889             ne_add = (jp1 - 1)*nx + ip1
890             !
891             src_lats(1) = src_center_lat(srch_add)
892             src_lats(2) = src_center_lat(e_add)
893             src_lats(3) = src_center_lat(ne_add)
894             src_lats(4) = src_center_lat(n_add)
895             !
896             src_lons(1) = src_center_lon(srch_add)
897             src_lons(2) = src_center_lon(e_add)
898             src_lons(3) = src_center_lon(ne_add)
899             src_lons(4) = src_center_lon(n_add)
900             !
901             !***
902             !*** for consistency, we must make sure all lons are in
903             !*** same 2pi interval
904             !***
905             !
906             vec1_lon = src_lons(1) - plon
907             IF (vec1_lon >  pi) THEN
908                src_lons(1) = src_lons(1) - pi2
909             ELSE IF (vec1_lon < -pi) THEN
910                src_lons(1) = src_lons(1) + pi2
911             ENDIF
912             DO n=2,4
913                vec1_lon = src_lons(n) - src_lons(1)
914                IF (vec1_lon >  pi) THEN
915                   src_lons(n) = src_lons(n) - pi2
916                ELSE IF (vec1_lon < -pi) THEN
917                   src_lons(n) = src_lons(n) + pi2
918                ENDIF
919             END DO
920             !
921             corner_loop: DO n=1,4
922                next_n = MOD(n,4) + 1
923                !***
924                !*** here we take the cross product of the vector making
925                !*** up each box side with the vector formed by the vertex
926                !*** and search point.  if all the cross products are
927                !*** positive, the point is contained in the box.
928                !***
929                vec1_lat = src_lats(next_n) - src_lats(n)
930                vec1_lon = src_lons(next_n) - src_lons(n)
931                vec2_lat = plat - src_lats(n)
932                vec2_lon = plon - src_lons(n)
933                !***
934                !*** check for 0,2pi crossings
935                !***
936                IF (vec1_lon >  three*pih) THEN
937                   vec1_lon = vec1_lon - pi2
938                ELSE IF (vec1_lon < -three*pih) THEN
939                   vec1_lon = vec1_lon + pi2
940                ENDIF
941                IF (vec2_lon >  three*pih) THEN
942                   vec2_lon = vec2_lon - pi2
943                ELSE IF (vec2_lon < -three*pih) THEN
944                   vec2_lon = vec2_lon + pi2
945                ENDIF
946                !
947                cross_product = vec1_lon*vec2_lat - vec2_lon*vec1_lat
948                !
949                !***
950                !*** if cross product is less than zero, this cell
951                !*** doesn't work
952                !***
953                IF (n == 1) cross_product_last = cross_product
954                IF (cross_product*cross_product_last < zero) &
955                     EXIT corner_loop
956                cross_product_last = cross_product
957                !
958             END DO corner_loop
959             !***
960             !*** if cross products all same sign, we found the location
961             !***
962             IF (n > 4) THEN
963                src_add(1) = srch_add
964                src_add(2) = e_add
965                src_add(3) = ne_add
966                src_add(4) = n_add
967                !
968                lastsrc_add = srch_add
969                RETURN
970             ENDIF
971             !***
972             !*** otherwise move on to next cell
973             !***
974          ENDIF !bounding box check
975       END DO srch_loop
976
977
978    ENDDO
979
980
981    !***
982    !*** if no cell found, point is likely either in a box that
983    !*** straddles either pole or is outside the grid.  fall back
984    !*** to a distance-weighted average of the four closest
985    !*** points.  go ahead and compute weights here, but store
986    !*** in src_lats and return -add to prevent the parent
987    !*** routine from computing bilinear weights
988    !***
989    !print *,'Could not find location for ',plat,plon
990    !print *,'Using nearest-neighbor average for this point'
991    !
992    coslat_dst = COS(plat)
993    sinlat_dst = SIN(plat)
994    coslon_dst = COS(plon)
995    sinlon_dst = SIN(plon)
996    !
997    dist_min = bignum
998    src_lats = bignum
999    DO srch_add = min_add,max_add
1000       ! distance = ACOS(coslat_dst*COS(src_center_lat(srch_add))*   &
1001       !      (coslon_dst*COS(src_center_lon(srch_add)) +   &
1002       !      sinlon_dst*SIN(src_center_lon(srch_add)))+   &
1003       !      sinlat_dst*SIN(src_center_lat(srch_add)))
1004
1005       distance = ACOS(coslat_dst*cos_src_center_lat(srch_add)*   &
1006            (coslon_dst*cos_src_center_lon(srch_add) +   &
1007            sinlon_dst*sin_src_center_lon(srch_add))+   &
1008            sinlat_dst*sin_src_center_lat(srch_add))
1009
1010       IF (distance < dist_min) THEN
1011          sort_loop: DO n=1,4
1012             IF (distance < src_lats(n)) THEN
1013                DO i=4,n+1,-1
1014                   src_add (i) = src_add (i-1)
1015                   src_lats(i) = src_lats(i-1)
1016                END DO
1017                src_add (n) = -srch_add
1018                src_lats(n) = distance
1019                dist_min = src_lats(4)
1020                EXIT sort_loop
1021             ENDIF
1022          END DO sort_loop
1023       ENDIF
1024    END DO
1025    !
1026    src_lons = one/(src_lats + tiny)
1027    distance = SUM(src_lons)
1028    src_lats = src_lons/distance
1029
1030    !-----------------------------------------------------------------------
1031
1032  END SUBROUTINE grid_search_bilin
1033
1034
1035  !***********************************************************************
1036!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1037  !************************************************************************
1038  !   SUBROUTINE STORE_LINK_BILIN
1039  !************************************************************************
1040!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1041
1042  SUBROUTINE store_link_bilin(dst_add, src_add, weights, nmap)
1043
1044    !-----------------------------------------------------------------------
1045    !     this routine stores the address and weight for four links
1046    !     associated with one destination point in the appropriate address
1047    !     and weight arrays and resizes those arrays if necessary.
1048    !-----------------------------------------------------------------------
1049
1050    !-----------------------------------------------------------------------
1051    !     input variables
1052    !-----------------------------------------------------------------------
1053    !
1054    INTEGER :: dst_add,nmap
1055    !
1056    INTEGER, DIMENSION(4) :: src_add
1057    !
1058    REAL*8, DIMENSION(4) :: weights 
1059
1060    !-----------------------------------------------------------------------
1061    !
1062    !     local variables
1063    !
1064    !-----------------------------------------------------------------------
1065
1066    INTEGER :: n,num_links_old   
1067
1068    !-----------------------------------------------------------------------
1069    !     increment number of links and check to see if remap arrays need
1070    !     to be increased to accomodate the new link.  then store the
1071    !     link.
1072    !-----------------------------------------------------------------------
1073
1074    num_links_old  = num_links_map1
1075    num_links_map1 = num_links_old + 4
1076
1077    IF (num_links_map1 > max_links_map1) &
1078         CALL resize_remap_vars(1,resize_increment)
1079
1080    DO n=1,4
1081       grid1_add_map1(num_links_old+n) = src_add(n)
1082       grid2_add_map1(num_links_old+n) = dst_add
1083       wts_map1    (1,num_links_old+n) = weights(n)
1084    END DO
1085
1086    !-----------------------------------------------------------------------
1087
1088  END SUBROUTINE store_link_bilin
1089
1090
1091
1092
1093
1094
1095
1096
1097!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1098  !************************************************************************
1099  !   SUBROUTINE INIT_REMAP_VARS
1100  !************************************************************************
1101!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1102  !
1103  SUBROUTINE init_remap_vars
1104
1105    !-----------------------------------------------------------------------
1106    !
1107    !     this routine initializes some variables and provides an initial
1108    !     allocation of arrays (fairly large so frequent resizing
1109    !     unnecessary).
1110    !
1111    !-----------------------------------------------------------------------
1112
1113    !-----------------------------------------------------------------------
1114    !     determine the number of weights
1115    !-----------------------------------------------------------------------
1116    num_wts = 1     ! bilinear interpolation
1117    !-----------------------------------------------------------------------
1118    !     initialize num_links and set max_links to four times the largest
1119    !     of the destination grid sizes initially (can be changed later).
1120    !     set a default resize increment to increase the size of link
1121    !     arrays if the number of links exceeds the initial size 
1122    !-----------------------------------------------------------------------
1123
1124    num_links_map1 = 0
1125    max_links_map1 = 4*grid2_size
1126    IF (num_maps > 1) THEN
1127       num_links_map2 = 0
1128       max_links_map1 = MAX(4*grid1_size,4*grid2_size)
1129       max_links_map2 = max_links_map1
1130    ENDIF
1131
1132    resize_increment = 0.1*MAX(grid1_size,grid2_size)
1133
1134    !-----------------------------------------------------------------------
1135    !     allocate address and weight arrays for mapping 1 
1136    !-----------------------------------------------------------------------
1137
1138    ALLOCATE (grid1_add_map1(max_links_map1),    &
1139         grid2_add_map1(max_links_map1),    &
1140         wts_map1(num_wts, max_links_map1))
1141
1142    grid1_add_map1 = 0.
1143    grid2_add_map1 = 0.
1144    wts_map1 = 0.
1145
1146    !-----------------------------------------------------------------------
1147
1148  END SUBROUTINE init_remap_vars
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163  !***********************************************************************
1164!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1165  !************************************************************************
1166  !   SUBROUTINE RESIZE_REMAP_VAR
1167  !************************************************************************
1168!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1169
1170  SUBROUTINE resize_remap_vars(nmap, increment)
1171
1172    !-----------------------------------------------------------------------
1173    !     this routine resizes remapping arrays by increasing(decreasing)
1174    !     the max_links by increment
1175    !-----------------------------------------------------------------------
1176
1177    !-----------------------------------------------------------------------
1178    !     input variables
1179    !-----------------------------------------------------------------------
1180
1181    INTEGER ::     &
1182         nmap,      &     ! identifies which mapping array to resize
1183         increment       ! the number of links to add(subtract) to arrays
1184
1185    !-----------------------------------------------------------------------
1186    !     local variables
1187    !-----------------------------------------------------------------------
1188
1189    INTEGER ::    &
1190         ierr,    &  ! error flag
1191         mxlinks   ! size of link arrays
1192
1193    INTEGER, DIMENSION(:), ALLOCATABLE ::    &
1194         add1_tmp,   & ! temp array for resizing address arrays
1195         add2_tmp  ! temp array for resizing address arrays
1196    !
1197    ! temp array for resizing weight arrays
1198    !
1199    REAL*8, DIMENSION(:,:), ALLOCATABLE :: wts_tmp   
1200    !
1201    !-----------------------------------------------------------------------
1202    !***
1203    !*** allocate temporaries to hold original values
1204    !***
1205    mxlinks = SIZE(grid1_add_map1)
1206    ALLOCATE (add1_tmp(mxlinks), add2_tmp(mxlinks), &
1207         wts_tmp(num_wts,mxlinks))
1208
1209    add1_tmp = grid1_add_map1
1210    add2_tmp = grid2_add_map1
1211    wts_tmp  = wts_map1
1212
1213    !***
1214    !*** deallocate originals and increment max_links then
1215    !*** reallocate arrays at new size
1216    !***
1217
1218    DEALLOCATE (grid1_add_map1, grid2_add_map1, wts_map1)
1219    max_links_map1 = mxlinks + increment
1220    ALLOCATE (grid1_add_map1(max_links_map1),    &
1221         grid2_add_map1(max_links_map1),    &
1222         wts_map1(num_wts,max_links_map1))
1223    !***
1224    !*** restore original values from temp arrays and
1225    !*** deallocate temps
1226    !***
1227    mxlinks = MIN(mxlinks, max_links_map1)
1228    grid1_add_map1(1:mxlinks) = add1_tmp (1:mxlinks)
1229    grid2_add_map1(1:mxlinks) = add2_tmp (1:mxlinks)
1230    wts_map1    (:,1:mxlinks) = wts_tmp(:,1:mxlinks)
1231    DEALLOCATE(add1_tmp, add2_tmp, wts_tmp)
1232
1233    !-----------------------------------------------------------------------
1234    !
1235  END SUBROUTINE resize_remap_vars
1236  !
1237  !************************************************************************
1238  !
1239END MODULE bilinear_interp
1240
1241!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1242
Note: See TracBrowser for help on using the repository browser.