20 subroutine horiz_interp_bilinear_new_1d_ ( Interp, lon_in, lat_in, lon_out, lat_out, &
24 type(horiz_interp_type),
intent(inout) :: Interp
25 real(FMS_HI_KIND_),
intent(in),
dimension(:) :: lon_in , lat_in
26 real(FMS_HI_KIND_),
intent(in),
dimension(:,:) :: lon_out, lat_out
27 integer,
intent(in),
optional :: verbose
28 logical,
intent(in),
optional :: src_modulo
30 logical :: src_is_modulo
31 integer :: nlon_in, nlat_in, nlon_out, nlat_out, n, m
32 integer :: ie, is, je, js, ln_err, lt_err, warns, iunit
33 real(FMS_HI_KIND_) :: wtw, wte, wts, wtn, lon, lat, tpi, hpi
34 real(FMS_HI_KIND_) :: glt_min, glt_max, gln_min, gln_max, min_lon, max_lon
35 integer,
parameter :: kindl = fms_hi_kind_
36 logical :: decreasing_lat
37 logical :: decreasing_lon
40 if(
present(verbose)) warns = verbose
41 src_is_modulo = .true.
42 if (
present(src_modulo)) src_is_modulo = src_modulo
44 decreasing_lat = .false.
45 if (lat_in(1) > lat_in(2)) decreasing_lat = .true.
47 decreasing_lon = .false.
48 if (lon_in(1) > lon_in(2)) decreasing_lon = .true.
50 hpi = 0.5_kindl * real(pi, fms_hi_kind_)
62 allocate ( interp % HI_KIND_TYPE_ % wti (
size(lon_out,1),
size(lon_out,2),2), &
63 interp % HI_KIND_TYPE_ % wtj (
size(lon_out,1),
size(lon_out,2),2), &
64 interp % i_lon (
size(lon_out,1),
size(lon_out,2),2), &
65 interp % j_lat (
size(lon_out,1),
size(lon_out,2),2))
68 nlon_in =
size(lon_in(:)) ; nlat_in =
size(lat_in(:))
69 nlon_out =
size(lon_out, 1); nlat_out =
size(lon_out, 2)
70 interp%nlon_src = nlon_in; interp%nlat_src = nlat_in
71 interp%nlon_dst = nlon_out; interp%nlat_dst = nlat_out
73 if(src_is_modulo)
then
74 if(lon_in(nlon_in) - lon_in(1) .gt. tpi + real(epsln, fms_hi_kind_)) &
75 call mpp_error(fatal,
'horiz_interp_bilinear_mod: '// &
76 'The range of source grid longitude should be no larger than tpi')
78 if(lon_in(1) .lt. 0.0_kindl .OR. lon_in(nlon_in) > tpi )
then
80 max_lon = lon_in(nlon_in)
89 if(src_is_modulo)
then
90 if(lon .lt. min_lon)
then
92 else if(lon .gt. max_lon)
then
97 if((lon .lt. lon_in(1)) .or. (lon .gt. lon_in(nlon_in))) &
98 call mpp_error(fatal,
'horiz_interp_bilinear_mod: ' //&
99 'when input grid is not modulo, output grid should locate inside input grid')
102 glt_min = min(lat,glt_min); glt_max = max(lat,glt_max)
103 gln_min = min(lon,gln_min); gln_max = max(lon,gln_max)
105 is = nearest_index(lon, lon_in )
106 if (decreasing_lon)
then
111 if( lon_in(is) .lt. lon ) is = max(is-1,1)
117 if( lon_in(is) .gt. lon ) is = max(is-1,1)
119 if( lon_in(is) .eq. lon .and. is .eq. nlon_in) is = max(is - 1,1)
120 ie = min(is+1,nlon_in)
121 if(lon_in(is) .ne. lon_in(ie) .and. (decreasing_lon .or. lon_in(is) .le. lon))
then
122 wtw = ( lon_in(ie) - lon) / (lon_in(ie) - lon_in(is) )
129 if (lon_in(ie) .ge. lon )
then
130 wtw = (lon_in(ie) -lon)/(lon_in(ie)-lon_in(is)+tpi+real(epsln,fms_hi_kind_))
132 wtw = (lon_in(ie)-lon+tpi+real(epsln,fms_hi_kind_))/(lon_in(ie)-lon_in(is)+tpi+real(epsln,fms_hi_kind_))
135 wte = 1.0_kindl - wtw
137 js = nearest_index(lat, lat_in )
138 if (decreasing_lat)
then
140 if( lat_in(js) .lt. lat ) js = max(js - 1, 1)
143 if( lat_in(js) .gt. lat ) js = max(js - 1, 1)
145 if( lat_in(js) .eq. lat .and. js .eq. nlat_in) js = max(js - 1, 1)
146 je = min(js + 1, nlat_in)
148 if ( lat_in(js) .ne. lat_in(je) .and. (decreasing_lat .or. lat_in(js) .le. lat))
then
149 wts = ( lat_in(je) - lat )/(lat_in(je)-lat_in(js))
158 wtn = 1.0_kindl - wts
160 interp % i_lon (m,n,1) = is; interp % i_lon (m,n,2) = ie
161 interp % j_lat (m,n,1) = js; interp % j_lat (m,n,2) = je
162 interp % HI_KIND_TYPE_ % wti (m,n,1) = wtw
163 interp % HI_KIND_TYPE_ % wti (m,n,2) = wte
164 interp % HI_KIND_TYPE_ % wtj (m,n,1) = wts
165 interp % HI_KIND_TYPE_ % wtj (m,n,2) = wtn
172 if (ln_err .eq. 1 .and. warns > 0)
then
173 write (iunit,
'(/,(1x,a))') &
174 '==> Warning: the geographic data set does not extend far ', &
175 ' enough east or west - a cyclic boundary ', &
176 ' condition was applied. check if appropriate '
177 write (iunit,
'(/,(1x,a,2f8.4))') &
178 ' data required between longitudes:', gln_min, gln_max, &
179 ' data set is between longitudes:', lon_in(1), lon_in(nlon_in)
183 if (lt_err .eq. 1 .and. warns > 0)
then
184 write (iunit,
'(/,(1x,a))') &
185 '==> Warning: the geographic data set does not extend far ',&
186 ' enough north or south - extrapolation from ',&
187 ' the nearest data was applied. this may create ',&
188 ' artificial gradients near a geographic pole '
189 write (iunit,
'(/,(1x,a,2f8.4))') &
190 ' data required between latitudes:', glt_min, glt_max, &
191 ' data set is between latitudes:', lat_in(1), lat_in(nlat_in)
193 interp% HI_KIND_TYPE_ % is_allocated = .true.
194 interp% interp_method = bilinear
198 end subroutine horiz_interp_bilinear_new_1d_
207 verbose, src_modulo, new_search, no_crash_when_not_found )
210 type(horiz_interp_type),
intent(inout) :: Interp
214 real(FMS_HI_KIND_),
intent(in),
dimension(:,:) :: lon_in
215 real(FMS_HI_KIND_),
intent(in),
dimension(:,:) :: lat_in
216 real(FMS_HI_KIND_),
intent(in),
dimension(:,:) :: lon_out
217 real(FMS_HI_KIND_),
intent(in),
dimension(:,:) :: lat_out
218 integer,
intent(in),
optional :: verbose
219 logical,
intent(in),
optional :: src_modulo
221 logical,
intent(in),
optional :: new_search
222 logical,
intent(in),
optional :: no_crash_when_not_found
224 logical :: src_is_modulo
225 integer :: nlon_in, nlat_in, nlon_out, nlat_out
226 integer :: m, n, is, ie, js, je, num_solution
227 real(FMS_HI_KIND_) :: lon, lat, quadra, x, y, y1, y2
228 real(FMS_HI_KIND_) :: a1, b1, c1, d1, a2, b2, c2, d2, a, b, c
229 real(FMS_HI_KIND_) :: lon1, lat1, lon2, lat2, lon3, lat3, lon4, lat4
230 real(FMS_HI_KIND_) :: tpi, lon_min, lon_max
231 real(FMS_HI_KIND_) :: epsln2
232 logical :: use_new_search, no_crash
234 integer,
parameter :: kindl=fms_hi_kind_
236 tpi = 2.0_kindl * real(pi, fms_hi_kind_)
239 if(
present(verbose)) warns = verbose
240 src_is_modulo = .true.
241 if (
present(src_modulo)) src_is_modulo = src_modulo
242 use_new_search = .false.
243 if (
present(new_search)) use_new_search = new_search
245 if(
present(no_crash_when_not_found)) no_crash = no_crash_when_not_found
248 if(
size(lon_out,1) /=
size(lat_out,1) .or.
size(lon_out,2) /=
size(lat_out,2) ) &
249 call mpp_error(fatal,
'horiz_interp_bilinear_mod: when using bilinear ' // &
250 'interplation, the output grids should be geographical grids')
252 if(
size(lon_in,1) /=
size(lat_in,1) .or.
size(lon_in,2) /=
size(lat_in,2) ) &
253 call mpp_error(fatal,
'horiz_interp_bilinear_mod: when using bilinear '// &
254 'interplation, the input grids should be geographical grids')
257 nlon_in =
size(lon_in,1) ; nlat_in =
size(lat_in,2)
258 nlon_out =
size(lon_out,1); nlat_out =
size(lon_out,2)
259 interp%nlon_src = nlon_in; interp%nlat_src = nlat_in
260 interp%nlon_dst = nlon_out; interp%nlat_dst = nlat_out
262 allocate ( interp % HI_KIND_TYPE_ % wti (
size(lon_out,1),
size(lon_out,2),2), &
263 interp % HI_KIND_TYPE_ % wtj (
size(lon_out,1),
size(lon_out,2),2), &
264 interp % i_lon (
size(lon_out,1),
size(lon_out,2),2), &
265 interp % j_lat (
size(lon_out,1),
size(lon_out,2),2))
268 if(use_new_search)
then
269 epsln2 = real(epsln,fms_hi_kind_)* 1.0e5_kindl
270 call find_neighbor_new_(interp, lon_in, lat_in, lon_out, lat_out, src_is_modulo, no_crash)
272 if(kindl == r8_kind)
then
277 call find_neighbor_(interp, lon_in, lat_in, lon_out, lat_out, src_is_modulo)
314 lon_min = minval(lon_in);
315 lon_max = maxval(lon_in);
321 if(lon .lt. lon_min)
then
323 else if(lon .gt. lon_max)
then
326 is = interp%i_lon(m,n,1); ie = interp%i_lon(m,n,2)
327 js = interp%j_lat(m,n,1); je = interp%j_lat(m,n,2)
328 if( is == dummy) cycle
329 lon1 = lon_in(is,js); lat1 = lat_in(is,js);
330 lon2 = lon_in(ie,js); lat2 = lat_in(ie,js);
331 lon3 = lon_in(ie,je); lat3 = lat_in(ie,je);
332 lon4 = lon_in(is,je); lat4 = lat_in(is,je);
333 if(lon .lt. lon_min)
then
334 lon1 = lon1 -tpi; lon4 = lon4 - tpi
335 else if(lon .gt. lon_max)
then
336 lon2 = lon2 +tpi; lon3 = lon3 + tpi
340 c1 = lon1+lon3-lon4-lon2
344 c2 = lat1+lat3-lat4-lat2
348 b = a1*b2-a2*b1+c1*d2-c2*d1+c2*lon-c1*lat
349 c = a2*lon-a1*lat+a1*d2-a2*d1
350 quadra = b*b-4._kindl*a*c
351 if(abs(quadra) < real(epsln, fms_hi_kind_)) quadra = 0.0_kindl
352 if(quadra < 0.0_kindl)
call mpp_error(fatal, &
353 "horiz_interp_bilinear_mod: No solution existed for this quadratic equation")
354 if ( abs(a) .lt. epsln2)
then
355 if( abs(b) .lt. real(epsln,fms_hi_kind_))
call mpp_error(fatal, &
356 "horiz_interp_bilinear_mod: no unique solution existed for this linear equation")
359 y1 = 0.5_kindl*(-b+sqrt(quadra))/a
360 y2 = 0.5_kindl*(-b-sqrt(quadra))/a
361 if(abs(y1) < epsln2) y1 = 0.0_kindl
362 if(abs(y2) < epsln2) y2 = 0.0_kindl
363 if(abs(1.0_kindl-y1) < epsln2) y1 = 1.0_kindl
364 if(abs(1.0_kindl-y2) < epsln2) y2 = 1.0_kindl
366 if(y1 >= 0.0_kindl .and. y1 <= 1.0_kindl)
then
368 num_solution = num_solution +1
370 if(y2 >= 0.0_kindl .and. y2 <= 1.0_kindl)
then
372 num_solution = num_solution + 1
374 if(num_solution == 0)
then
375 call mpp_error(fatal,
"horiz_interp_bilinear_mod: No solution found")
376 else if(num_solution == 2)
then
377 call mpp_error(fatal,
"horiz_interp_bilinear_mod: Two solutions found")
380 if(abs(a1+c1*y) < real(epsln,fms_hi_kind_))
call mpp_error(fatal, &
381 "horiz_interp_bilinear_mod: the denomenator is 0")
382 if(abs(y) < epsln2) y = 0.0_kindl
383 if(abs(1.0_kindl-y) < epsln2) y = 1.0_kindl
384 x = (lon-b1*y-d1)/(a1+c1*y)
385 if(abs(x) < epsln2) x = 0.0_kindl
386 if(abs(1.0_kindl-x) < epsln2) x = 1.0_kindl
389 if(use_new_search)
then
390 if (x < 0.0_kindl) x = 0.0_kindl
391 if (y < 0.0_kindl) y = 0.0_kindl
392 if (x > 1.0_kindl) x = 1.0_kindl
393 if (y > 1.0_kindl) y = 1.0_kindl
396 if( kindl == r8_kind )
then
397 if( x>1.0_kindl .or. x<0.0_kindl .or. y>1.0_kindl .or. y < 0.0_kindl) &
398 call mpp_error(fatal,
"horiz_interp_bilinear_mod: weight should be between 0 and 1, x=" &
399 //string(x)//
" y="//string(y))
401 if( x>1.0_kindl + epsln2 .or. x<0.0_kindl - epsln2 .or. &
402 y>1.0_kindl + epsln2 .or. y < 0.0_kindl - epsln2) &
403 call mpp_error(fatal,
"horiz_interp_bilinear_mod: weight should be between 0 and 1, x=" &
404 //string(x)//
" y="//string(y))
406 interp % HI_KIND_TYPE_ % wti(m,n,1)=1.0_kindl-x
407 interp % HI_KIND_TYPE_ % wti(m,n,2)=x
408 interp % HI_KIND_TYPE_ % wtj(m,n,1)=1.0_kindl-y
409 interp % HI_KIND_TYPE_ % wtj(m,n,2)=y
413 interp% HI_KIND_TYPE_ % is_allocated = .true.
414 interp% interp_method = bilinear
420 subroutine find_neighbor_ ( Interp, lon_in, lat_in, lon_out, lat_out, src_modulo )
421 type(horiz_interp_type),
intent(inout) :: Interp
422 real(FMS_HI_KIND_),
intent(in),
dimension(:,:) :: lon_in , lat_in
423 real(FMS_HI_KIND_),
intent(in),
dimension(:,:) :: lon_out, lat_out
424 logical,
intent(in) :: src_modulo
425 integer :: nlon_in, nlat_in, nlon_out, nlat_out
426 integer :: max_step, n, m, l, i, j, ip1, jp1, step
427 integer :: is, js, jstart, jend, istart, iend, npts
428 integer,
allocatable,
dimension(:) :: ilon, jlat
429 real(FMS_HI_KIND_) :: lon_min, lon_max, lon, lat, tpi
431 real(FMS_HI_KIND_) :: lon1, lat1, lon2, lat2, lon3, lat3, lon4, lat4
433 integer,
parameter :: kindl=fms_hi_kind_
435 tpi = 2.0_kindl*real(pi, fms_hi_kind_)
436 nlon_in =
size(lon_in,1) ; nlat_in =
size(lat_in,2)
437 nlon_out =
size(lon_out,1); nlat_out =
size(lon_out,2)
439 lon_min = minval(lon_in);
440 lon_max = maxval(lon_in);
442 max_step = max(nlon_in,nlat_in)
443 allocate(ilon(5*max_step), jlat(5*max_step) )
452 if(lon .lt. lon_min)
then
454 else if(lon .gt. lon_max)
then
458 if(lon .lt. lon_min .or. lon .gt. lon_max ) &
459 call mpp_error(fatal,
'horiz_interp_bilinear_mod: ' //&
460 'when input grid is not modulo, output grid should locate inside input grid')
463 if(m==1 .and. n==1)
then
464 j_loop:
do j = 1, nlat_in-1
475 lon1 = lon_in(i, j); lat1 = lat_in(i,j)
476 lon2 = lon_in(ip1,j); lat2 = lat_in(ip1,j)
477 lon3 = lon_in(ip1,jp1); lat3 = lat_in(ip1,jp1)
478 lon4 = lon_in(i, jp1); lat4 = lat_in(i, jp1)
480 if(lon .lt. lon_min .or. lon .gt. lon_max)
then
481 if(i .ne. nlon_in)
then
484 if(lon .lt. lon_min)
then
485 lon1 = lon1 -tpi; lon4 = lon4 - tpi
486 else if(lon .gt. lon_max)
then
487 lon2 = lon2 +tpi; lon3 = lon3 + tpi
492 if(lat .ge. intersect(lon1,lat1,lon2,lat2,lon))
then
493 if(lon .le. intersect(lat2,lon2,lat3,lon3,lat))
then
494 if(lat .le. intersect(lon3,lat3,lon4,lat4,lon))
then
495 if(lon .ge. intersect(lat4,lon4,lat1,lon1,lat))
then
497 interp % i_lon (m,n,1) = i; interp % i_lon (m,n,2) = ip1
498 interp % j_lat (m,n,1) = j; interp % j_lat (m,n,2) = jp1
508 do while ( .not. found .and. step .lt. max_step )
511 is = interp % i_lon (m,n-1,1)
512 js = interp % j_lat (m,n-1,1)
514 is = interp % i_lon (m-1,n,1)
515 js = interp % j_lat (m-1,n,1)
524 jstart = max(js-step,1)
525 jend = min(js+step,nlat_in)
532 else if (i > nlon_in)
then
535 if( i < 1 .or. i > nlon_in)
call mpp_error(fatal, &
536 'horiz_interp_bilinear_mod: max_step is too big, decrease max_step' )
538 if( i < 1 .or. i > nlon_in) cycle
550 if( istart < 1) istart = istart + nlon_in
551 if( iend > nlon_in) iend = iend - nlon_in
553 istart = max(istart,1)
554 iend = min(iend, nlon_in)
558 if( j < 1 .or. j > nlat_in .or. j==jstart .or. j==jend) cycle
574 else if (i > nlon_in)
then
577 if( i < 1 .or. i > nlon_in)
call mpp_error(fatal, &
578 'horiz_interp_bilinear_mod: max_step is too big, decrease max_step' )
580 if( i < 1 .or. i > nlon_in) cycle
604 if(jp1>nlat_in) cycle
605 lon1 = lon_in(i, j); lat1 = lat_in(i,j)
606 lon2 = lon_in(ip1,j); lat2 = lat_in(ip1,j)
607 lon3 = lon_in(ip1,jp1); lat3 = lat_in(ip1,jp1)
608 lon4 = lon_in(i, jp1); lat4 = lat_in(i, jp1)
610 if(lon .lt. lon_min .or. lon .gt. lon_max)
then
611 if(i .ne. nlon_in)
then
614 if(lon .lt. lon_min)
then
615 lon1 = lon1 -tpi; lon4 = lon4 - tpi
616 else if(lon .gt. lon_max)
then
617 lon2 = lon2 +tpi; lon3 = lon3 + tpi
622 if(lat .ge. intersect(lon1,lat1,lon2,lat2,lon))
then
623 if(lon .le. intersect(lat2,lon2,lat3,lon3,lat))
then
624 if(lat .le. intersect(lon3,lat3,lon4,lat4,lon))
then
625 if(lon .ge. intersect(lat4,lon4,lat1,lon1,lat))
then
628 interp % i_lon (m,n,1) = i; interp % i_lon (m,n,2) = ip1
629 interp % j_lat (m,n,1) = j; interp % j_lat (m,n,2) = jp1
640 print *,
'lon,lat=',lon*180.0_kindl/real(pi,fms_hi_kind_),lat*180.0_kindl/real(pi,fms_hi_kind_)
642 print *,
'is,ie= ',istart,iend
643 print *,
'js,je= ',jstart,jend
644 print *,
'lon_in(is,js)=',lon_in(istart,jstart)*180.0_kindl/real(pi,fms_hi_kind_)
645 print *,
'lon_in(ie,js)=',lon_in(iend,jstart)*180.0_kindl/real(pi,fms_hi_kind_)
646 print *,
'lat_in(is,js)=',lat_in(istart,jstart)*180.0_kindl/real(pi,fms_hi_kind_)
647 print *,
'lat_in(ie,js)=',lat_in(iend,jstart)*180.0_kindl/real(pi,fms_hi_kind_)
648 print *,
'lon_in(is,je)=',lon_in(istart,jend)*180.0_kindl/real(pi,fms_hi_kind_)
649 print *,
'lon_in(ie,je)=',lon_in(iend,jend)*180.0_kindl/real(pi,fms_hi_kind_)
650 print *,
'lat_in(is,je)=',lat_in(istart,jend)*180.0_kindl/real(pi,fms_hi_kind_)
651 print *,
'lat_in(ie,je)=',lat_in(iend,jend)*180.0_kindl/real(pi,fms_hi_kind_)
653 call mpp_error(fatal, &
654 'FIND_NEIGHBOR_: the destination point is not inside the source grid' )
667 real(fms_hi_kind_),
dimension(:),
intent(in) :: polyx
668 real(fms_hi_kind_),
dimension(:),
intent(in) :: polyy
669 real(fms_hi_kind_),
intent(in) :: x
670 real(fms_hi_kind_),
intent(in) :: y
672 integer :: i, j, nedges
673 real(fms_hi_kind_) :: xx
676 nedges =
size(polyx(:))
679 if( (polyy(i) < y .AND. polyy(j) >= y) .OR. (polyy(j) < y .AND. polyy(i) >= y) )
then
680 xx = polyx(i)+(y-polyy(i))/(polyy(j)-polyy(i))*(polyx(j)-polyx(i))
684 else if( xx < x )
then
699 type(horiz_interp_type),
intent(inout) :: Interp
700 real(FMS_HI_KIND_),
intent(in),
dimension(:,:) :: lon_in , lat_in
701 real(FMS_HI_KIND_),
intent(in),
dimension(:,:) :: lon_out, lat_out
702 logical,
intent(in) :: src_modulo, no_crash
703 integer :: nlon_in, nlat_in, nlon_out, nlat_out
704 integer :: max_step, n, m, l, i, j, ip1, jp1, step
705 integer :: is, js, jstart, jend, istart, iend, npts
706 integer,
allocatable,
dimension(:) :: ilon, jlat
707 real(FMS_HI_KIND_) :: lon_min, lon_max, lon, lat, tpi
709 real(FMS_HI_KIND_) :: polyx(4), polyy(4)
710 real(FMS_HI_KIND_) :: min_lon, min_lat, max_lon, max_lat
712 integer,
parameter :: step_div=8, kindl = fms_hi_kind_
714 tpi = 2.0_kindl * real(pi, fms_hi_kind_)
715 nlon_in =
size(lon_in,1) ; nlat_in =
size(lat_in,2)
716 nlon_out =
size(lon_out,1); nlat_out =
size(lon_out,2)
718 lon_min = minval(lon_in);
719 lon_max = maxval(lon_in);
721 max_step = min(nlon_in,nlat_in)/step_div
722 allocate(ilon(step_div*max_step), jlat(step_div*max_step) )
731 if(lon .lt. lon_min)
then
733 else if(lon .gt. lon_max)
then
737 if(lon .lt. lon_min .or. lon .gt. lon_max ) &
738 call mpp_error(fatal,
'horiz_interp_bilinear_mod: ' //&
739 'when input grid is not modulo, output grid should locate inside input grid')
742 if(m==1 .and. n==1)
then
743 j_loop:
do j = 1, nlat_in-1
755 polyx(1) = lon_in(i, j); polyy(1) = lat_in(i,j)
756 polyx(2) = lon_in(ip1,j); polyy(2) = lat_in(ip1,j)
757 polyx(3) = lon_in(ip1,jp1); polyy(3) = lat_in(ip1,jp1)
758 polyx(4) = lon_in(i, jp1); polyy(4) = lat_in(i, jp1)
759 if(lon .lt. lon_min .or. lon .gt. lon_max)
then
760 if(i .ne. nlon_in)
then
763 if(lon .lt. lon_min)
then
764 polyx(1) = polyx(1) -tpi; polyx(4) = polyx(4) - tpi
765 else if(lon .gt. lon_max)
then
766 polyx(2) = polyx(2) +tpi; polyx(3) = polyx(3) + tpi
771 min_lon = minval(polyx)
772 max_lon = maxval(polyx)
773 min_lat = minval(polyy)
774 max_lat = maxval(polyy)
785 interp % i_lon (m,n,1) = i; interp % i_lon (m,n,2) = ip1
786 interp % j_lat (m,n,1) = j; interp % j_lat (m,n,2) = jp1
793 do while ( .not. found .and. step .lt. max_step )
796 is = interp % i_lon (m,n-1,1)
797 js = interp % j_lat (m,n-1,1)
799 is = interp % i_lon (m-1,n,1)
800 js = interp % j_lat (m-1,n,1)
809 jstart = max(js-step,1)
810 jend = min(js+step,nlat_in)
817 else if (i > nlon_in)
then
820 if( i < 1 .or. i > nlon_in)
call mpp_error(fatal, &
821 'horiz_interp_bilinear_mod: max_step is too big, decrease max_step' )
823 if( i < 1 .or. i > nlon_in) cycle
838 if( istart < 1) istart = istart + nlon_in
839 if( iend > nlon_in) iend = iend - nlon_in
841 istart = max(istart,1)
842 iend = min(iend, nlon_in)
846 if( j < 1 .or. j > nlat_in) cycle
869 if(jp1>nlat_in) cycle
870 polyx(1) = lon_in(i, j); polyy(1) = lat_in(i,j)
871 polyx(2) = lon_in(ip1,j); polyy(2) = lat_in(ip1,j)
872 polyx(3) = lon_in(ip1,jp1); polyy(3) = lat_in(ip1,jp1)
873 polyx(4) = lon_in(i, jp1); polyy(4) = lat_in(i, jp1)
876 interp % i_lon (m,n,1) = i; interp % i_lon (m,n,2) = ip1
877 interp % j_lat (m,n,1) = j; interp % j_lat (m,n,2) = jp1
886 interp % i_lon (m,n,1:2) = dummy
887 interp % j_lat (m,n,1:2) = dummy
888 print*,
'lon,lat=',lon,lat
890 call mpp_error(fatal, &
891 'horiz_interp_bilinear_mod: the destination point is not inside the source grid' )
900 function intersect_(x1, y1, x2, y2, x)
901 real(FMS_HI_KIND_),
intent(in) :: x1, y1, x2, y2, x
902 real(FMS_HI_KIND_) :: INTERSECT_
904 intersect_ = (y2-y1)*(x-x1)/(x2-x1) + y1
908 end function intersect_
916 missing_value, missing_permit, new_handle_missing )
918 type (horiz_interp_type),
intent(in) :: Interp
921 real(FMS_HI_KIND_),
intent(in),
dimension(:,:) :: data_in
922 real(FMS_HI_KIND_),
intent(out),
dimension(:,:) :: data_out
923 integer,
intent(in),
optional :: verbose
925 real(FMS_HI_KIND_),
intent(in),
dimension(:,:),
optional :: mask_in
929 real(FMS_HI_KIND_),
intent(out),
dimension(:,:),
optional :: mask_out
931 real(FMS_HI_KIND_),
intent(in),
optional :: missing_value
932 integer,
intent(in),
optional :: missing_permit
933 logical,
intent(in),
optional :: new_handle_missing
935 integer :: nlon_in, nlat_in, nlon_out, nlat_out, n, m, &
936 is, ie, js, je, iverbose, max_missing, num_missing, &
937 miss_in, miss_out, iunit
938 real(FMS_HI_KIND_) :: dwtsum, wtsum, min_in, max_in, avg_in, &
939 min_out, max_out, avg_out, wtw, wte, wts, wtn
940 real(FMS_HI_KIND_) :: mask(size(data_in,1), size(data_in,2) )
941 logical :: set_to_missing, is_missing(4), new_handler
942 real(FMS_HI_KIND_) :: f1, f2, f3, f4, middle, w, s
943 integer,
parameter :: kindl = fms_hi_kind_
947 nlon_in = interp%nlon_src; nlat_in = interp%nlat_src
948 nlon_out = interp%nlon_dst; nlat_out = interp%nlat_dst
950 if(
present(mask_in))
then
956 if (
present(verbose))
then
962 if(
present(missing_permit))
then
963 max_missing = missing_permit
968 if(
present(new_handle_missing))
then
969 new_handler = new_handle_missing
971 new_handler = .false.
974 if(max_missing .gt. 3 .or. max_missing .lt. 0)
call mpp_error(fatal, &
975 'horiz_interp_bilinear_mod: missing_permit should be between 0 and 3')
977 if (
size(data_in,1) /= nlon_in .or.
size(data_in,2) /= nlat_in) &
978 call mpp_error(fatal,
'horiz_interp_bilinear_mod: size of input array incorrect')
980 if (
size(data_out,1) /= nlon_out .or.
size(data_out,2) /= nlat_out) &
981 call mpp_error(fatal,
'horiz_interp_bilinear_mod: size of output array incorrect')
984 if( .not.
present(missing_value) )
call mpp_error(fatal, &
985 "horiz_interp_bilinear_mod: misisng_value must be present when new_handle_missing is .true.")
986 if(
present(mask_in) )
call mpp_error(fatal, &
987 "horiz_interp_bilinear_mod: mask_in should not be present when new_handle_missing is .true.")
990 is = interp % i_lon (m,n,1); ie = interp % i_lon (m,n,2)
991 js = interp % j_lat (m,n,1); je = interp % j_lat (m,n,2)
992 wtw = interp % HI_KIND_TYPE_ % wti (m,n,1)
993 wte = interp % HI_KIND_TYPE_ % wti (m,n,2)
994 wts = interp % HI_KIND_TYPE_ % wtj (m,n,1)
995 wtn = interp % HI_KIND_TYPE_ % wtj (m,n,2)
999 set_to_missing = .false.
1000 if(data_in(is,js) == missing_value)
then
1001 num_missing = num_missing+1
1002 is_missing(1) = .true.
1003 if(wtw .GE. 0.5_kindl .AND. wts .GE. 0.5_kindl) set_to_missing = .true.
1006 if(data_in(ie,js) == missing_value)
then
1007 num_missing = num_missing+1
1008 is_missing(2) = .true.
1009 if(wte .GE. 0.5_kindl .AND. wts .GE. 0.5_kindl ) set_to_missing = .true.
1011 if(data_in(ie,je) == missing_value)
then
1012 num_missing = num_missing+1
1013 is_missing(3) = .true.
1014 if(wte .GE. 0.5_kindl .AND. wtn .GE. 0.5_kindl ) set_to_missing = .true.
1016 if(data_in(is,je) == missing_value)
then
1017 num_missing = num_missing+1
1018 is_missing(4) = .true.
1019 if(wtw .GE. 0.5_kindl .AND. wtn .GE. 0.5_kindl) set_to_missing = .true.
1022 if( num_missing == 4 .OR. set_to_missing )
then
1023 data_out(m,n) = missing_value
1024 if(
present(mask_out)) mask_out(m,n) = 0.0_kindl
1026 else if(num_missing == 0)
then
1033 else if(num_missing == 3)
then
1034 if(.not. is_missing(1) )
then
1035 data_out(m,n) = data_in(is,js)
1036 else if(.not. is_missing(2) )
then
1037 data_out(m,n) = data_in(ie,js)
1038 else if(.not. is_missing(3) )
then
1039 data_out(m,n) = data_in(ie,je)
1040 else if(.not. is_missing(4) )
then
1041 data_out(m,n) = data_in(is,je)
1043 if(
present(mask_out) ) mask_out(m,n) = 1.0_kindl
1046 if( num_missing == 1)
then
1047 if( is_missing(1) .OR. is_missing(3) )
then
1048 middle = 0.5_kindl *(data_in(ie,js)+data_in(is,je))
1050 middle = 0.5_kindl *(data_in(is,js)+data_in(ie,je))
1053 if( is_missing(1) .AND. is_missing(2) )
then
1054 middle = 0.5_kindl *(data_in(ie,je)+data_in(is,je))
1055 else if( is_missing(1) .AND. is_missing(3) )
then
1056 middle = 0.5_kindl *(data_in(ie,js)+data_in(is,je))
1057 else if( is_missing(1) .AND. is_missing(4) )
then
1058 middle = 0.5_kindl *(data_in(ie,js)+data_in(ie,je))
1059 else if( is_missing(2) .AND. is_missing(3) )
then
1060 middle = 0.5_kindl *(data_in(is,js)+data_in(is,je))
1061 else if( is_missing(2) .AND. is_missing(4) )
then
1062 middle = 0.5_kindl*(data_in(is,js)+data_in(ie,je))
1063 else if( is_missing(3) .AND. is_missing(4) )
then
1064 middle = 0.5_kindl*(data_in(is,js)+data_in(ie,js))
1068 if( wtw .GE. 0.5_kindl .AND. wts .GE. 0.5_kindl )
then
1069 w = 2.0_kindl*(wtw-0.5_kindl)
1070 s = 2.0_kindl*(wts-0.5_kindl)
1072 if(is_missing(2))
then
1075 f2 = 0.5_kindl*(data_in(is,js)+data_in(ie,js))
1078 if(is_missing(4))
then
1081 f4 = 0.5_kindl*(data_in(is,js)+data_in(is,je))
1083 else if( wte .GE. 0.5_kindl .AND. wts .GE. 0.5_kindl )
then
1084 w = 2.0_kindl*(1.0_kindl-wte)
1085 s = 2.0_kindl*(wts-0.5_kindl)
1087 if(is_missing(1))
then
1090 f1 = 0.5_kindl*(data_in(is,js)+data_in(ie,js))
1093 if(is_missing(3))
then
1096 f3 = 0.5_kindl*(data_in(ie,js)+data_in(ie,je))
1098 else if( wte .GE. 0.5_kindl .AND. wtn .GE. 0.5_kindl )
then
1099 w = 2.0_kindl*(1.0_kindl-wte)
1100 s = 2.0_kindl*(1.0_kindl-wtn)
1102 if(is_missing(2))
then
1105 f2 = 0.5_kindl*(data_in(ie,js)+data_in(ie,je))
1108 if(is_missing(4))
then
1111 f4 = 0.5_kindl*(data_in(ie,je)+data_in(is,je))
1113 else if( wtw .GE. 0.5_kindl .AND. wtn .GE. 0.5_kindl )
then
1114 w = 2.0_kindl*(wtw-0.5_kindl)
1115 s = 2.0_kindl*(1.0_kindl-wtn)
1117 if(is_missing(1))
then
1120 f1 = 0.5_kindl*(data_in(is,js)+data_in(is,je))
1123 if(is_missing(3))
then
1126 f3 = 0.5_kindl*(data_in(ie,je)+data_in(is,je))
1129 call mpp_error(fatal, &
1130 "horiz_interp_bilinear_mod: the point should be in one of the four zone")
1134 data_out(m,n) = f3 + (f4-f3)*w + (f2-f3)*s + ((f1-f2)+(f3-f4))*w*s
1135 if(
present(mask_out)) mask_out(m,n) = 1.0_kindl
1141 is = interp % i_lon (m,n,1); ie = interp % i_lon (m,n,2)
1142 js = interp % j_lat (m,n,1); je = interp % j_lat (m,n,2)
1143 wtw = interp % HI_KIND_TYPE_ % wti (m,n,1)
1144 wte = interp % HI_KIND_TYPE_ % wti (m,n,2)
1145 wts = interp % HI_KIND_TYPE_ % wtj (m,n,1)
1146 wtn = interp % HI_KIND_TYPE_ % wtj (m,n,2)
1148 if(
present(missing_value) )
then
1150 if(data_in(is,js) == missing_value)
then
1151 num_missing = num_missing+1
1152 mask(is,js) = 0.0_kindl
1154 if(data_in(ie,js) == missing_value)
then
1155 num_missing = num_missing+1
1156 mask(ie,js) = 0.0_kindl
1158 if(data_in(ie,je) == missing_value)
then
1159 num_missing = num_missing+1
1160 mask(ie,je) = 0.0_kindl
1162 if(data_in(is,je) == missing_value)
then
1163 num_missing = num_missing+1
1164 mask(is,je) = 0.0_kindl
1168 dwtsum = data_in(is,js)*mask(is,js)*wtw*wts &
1169 + data_in(ie,js)*mask(ie,js)*wte*wts &
1170 + data_in(ie,je)*mask(ie,je)*wte*wtn &
1171 + data_in(is,je)*mask(is,je)*wtw*wtn
1172 wtsum = mask(is,js)*wtw*wts + mask(ie,js)*wte*wts &
1173 + mask(ie,je)*wte*wtn + mask(is,je)*wtw*wtn
1175 if(.not.
present(mask_in) .and. .not.
present(missing_value)) wtsum = 1.0_kindl
1177 if(num_missing .gt. max_missing )
then
1178 data_out(m,n) = missing_value
1179 if(
present(mask_out)) mask_out(m,n) = 0.0_kindl
1180 else if(wtsum .lt. real(epsln, fms_hi_kind_))
then
1181 if(
present(missing_value))
then
1182 data_out(m,n) = missing_value
1184 data_out(m,n) = 0.0_kindl
1186 if(
present(mask_out)) mask_out(m,n) = 0.0_kindl
1188 data_out(m,n) = dwtsum/wtsum
1189 if(
present(mask_out)) mask_out(m,n) = wtsum
1197 if (iverbose > 0)
then
1201 call stats (data_in, min_in, max_in, avg_in, miss_in, missing_value, mask_in)
1204 call stats (data_out, min_out, max_out, avg_out, miss_out, missing_value, mask_out)
1209 write (iunit,901) min_in ,max_in, avg_in
1210 if (
present(mask_in))
write (iunit,903) miss_in
1211 write (iunit,902) min_out,max_out,avg_out
1212 if (
present(mask_out))
write (iunit,903) miss_out
1214 900
format (/,1x,10(
'-'),
' output from horiz_interp ',10(
'-'))
1215 901
format (
' input: min=',f16.9,
' max=',f16.9,
' avg=',f22.15)
1216 902
format (
' output: min=',f16.9,
' max=',f16.9,
' avg=',f22.15)
1217 903
format (
' number of missing points = ',i6)
1228 weight_file_source, interp_method, isw, iew, jsw, jew, nglon, nglat)
1229 type(horiz_interp_type),
intent(inout) :: Interp
1230 character(len=*),
intent(in) :: weight_filename
1231 real(FMS_HI_KIND_),
target,
intent(in) :: lat_out(:,:)
1232 real(FMS_HI_KIND_),
target,
intent(in) :: lon_out(:,:)
1233 real(FMS_HI_KIND_),
intent(in) :: lat_in(:)
1234 real(FMS_HI_KIND_),
intent(in) :: lon_in(:)
1235 character(len=*),
intent(in) :: weight_file_source
1236 character(len=*),
intent(in) :: interp_method
1237 integer,
intent(in) :: isw, iew, jsw, jew
1238 integer,
intent(in) :: nglon
1239 integer,
intent(in) :: nglat
1242 real(FMS_HI_KIND_),
allocatable :: var(:,:,:)
1243 type(fmsnetcdffile_t) :: weight_fileobj
1249 if (.not. open_file(weight_fileobj, weight_filename,
"read" )) &
1250 call mpp_error(fatal,
"Error opening the weight file:"//&
1251 &trim(weight_filename))
1254 select case (trim(weight_file_source))
1256 call get_dimension_size(weight_fileobj,
"nlon", nlon)
1257 if (nlon .ne. nglon) &
1258 call mpp_error(fatal,
"The nlon from the weight file is not the same as in the input grid."//&
1259 &
" From weight file:"//string(nlon)//
" from input grid:"//string(
size(lon_out,1)))
1260 call get_dimension_size(weight_fileobj,
"nlat", nlat)
1261 if (nlat .ne. nglat) &
1262 call mpp_error(fatal,
"The nlat from the weight file is not the same as in the input grid."//&
1263 &
" From weight file:"//string(nlat)//
" from input grid:"//string(
size(lon_out,2)))
1265 call mpp_error(fatal, trim(weight_file_source)//&
1266 &
" is not a supported weight file source. fregrid is the only supported weight file source." )
1269 interp%nlon_src =
size(lon_in(:)) ; interp%nlat_src =
size(lat_in(:))
1270 interp%nlon_dst =
size(lon_out,1); interp%nlat_dst =
size(lon_out,2)
1272 allocate ( interp % HI_KIND_TYPE_ % wti (interp%nlon_dst,interp%nlat_dst,2), &
1273 interp % HI_KIND_TYPE_ % wtj (interp%nlon_dst,interp%nlat_dst,2), &
1274 interp % i_lon (interp%nlon_dst,interp%nlat_dst,2), &
1275 interp % j_lat (interp%nlon_dst,interp%nlat_dst,2))
1280 allocate(var(interp%nlon_dst,interp%nlat_dst, 3))
1281 call read_data(weight_fileobj,
"index", var, corner=(/isw, jsw, 1/), edge_lengths=(/iew-isw+1, jew-jsw+1, 3/))
1285 interp % i_lon (:,:,1) = var(:,:,1)
1286 interp % i_lon (:,:,2) = interp % i_lon (:,:,1) + 1
1287 where (interp % i_lon (:,:,2) >
size(lon_in(:))) interp % i_lon (:,:,2) = 1
1289 interp % j_lat (:,:,1) = var(:,:,2)
1290 interp % j_lat (:,:,2) = interp % j_lat (:,:,1) + 1
1291 where (interp % j_lat (:,:,2) >
size(lat_in(:))) interp % j_lat (:,:,2) = 1
1295 allocate(var(interp%nlon_dst,interp%nlat_dst, 4))
1296 call read_data(weight_fileobj,
"weight", var, corner=(/isw, jsw, 1/), edge_lengths=(/iew-isw+1, jew-jsw+1, 4/))
1303 interp % HI_KIND_TYPE_ % wti = var(:,:,1:2)
1304 interp % HI_KIND_TYPE_ % wtj = var(:,:,3:4)
1307 interp% HI_KIND_TYPE_ % is_allocated = .true.
1308 interp% interp_method = bilinear
1309 interp% I_am_initialized = .true.
1310 call close_file(weight_fileobj)
subroutine find_neighbor_(Interp, lon_in, lat_in, lon_out, lat_out, src_modulo)
this routine will search the source grid to fine the grid box that encloses each destination grid.
subroutine horiz_interp_bilinear_new_2d_(Interp, lon_in, lat_in, lon_out, lat_out, verbose, src_modulo, new_search, no_crash_when_not_found)
Initialization routine.
subroutine find_neighbor_new_(Interp, lon_in, lat_in, lon_out, lat_out, src_modulo, no_crash)
this routine will search the source grid to fine the grid box that encloses each destination grid.
subroutine horiz_interp_read_weights_bilinear_(Interp, weight_filename, lon_out, lat_out, lon_in, lat_in, weight_file_source, interp_method, isw, iew, jsw, jew, nglon, nglat)
Subroutine for reading a weight file and use it to fill in the horiz interp type for the bilinear int...
subroutine horiz_interp_bilinear_(Interp, data_in, data_out, verbose, mask_in, mask_out, missing_value, missing_permit, new_handle_missing)
Subroutine for performing the horizontal interpolation between two grids.
logical function inside_polygon_(polyx, polyy, x, y)
The function will return true if the point x,y is inside a polygon, or false if it is not....
integer function stdout()
This function returns the current standard fortran unit numbers for output.