38 use fms_mod,
only: write_version_number
57 integer,
parameter ::
dummy = -999
61 #include<file_version.h> 78 call write_version_number(
"HORIZ_INTERP_BILINEAR_MOD", version)
91 type(horiz_interp_type),
intent(inout) :: Interp
92 real,
intent(in),
dimension(:) :: lon_in , lat_in
93 real,
intent(in),
dimension(:,:) :: lon_out, lat_out
94 integer,
intent(in),
optional :: verbose
95 logical,
intent(in),
optional :: src_modulo
97 logical :: src_is_modulo
98 integer :: nlon_in, nlat_in, nlon_out, nlat_out, n, m
99 integer :: ie, is, je, js, ln_err, lt_err, warns, unit
100 real :: wtw, wte, wts, wtn, lon, lat, tpi, hpi
101 real :: glt_min, glt_max, gln_min, gln_max, min_lon, max_lon
104 if(
present(verbose)) warns = verbose
105 src_is_modulo = .true.
106 if (
present(src_modulo)) src_is_modulo = src_modulo
120 allocate ( interp % wti (
size(lon_out,1),
size(lon_out,2),2), &
121 interp % wtj (
size(lon_out,1),
size(lon_out,2),2), &
122 interp % i_lon (
size(lon_out,1),
size(lon_out,2),2), &
123 interp % j_lat (
size(lon_out,1),
size(lon_out,2),2))
126 nlon_in =
size(lon_in(:)) ; nlat_in =
size(lat_in(:))
127 nlon_out =
size(lon_out, 1); nlat_out =
size(lon_out, 2)
128 interp%nlon_src = nlon_in; interp%nlat_src = nlat_in
129 interp%nlon_dst = nlon_out; interp%nlat_dst = nlat_out
131 if(src_is_modulo)
then 132 if(lon_in(nlon_in) - lon_in(1) .gt. tpi +
epsln) &
133 call mpp_error(fatal,
'horiz_interp_bilinear_mod: '// &
134 'The range of source grid longitude should be no larger than tpi')
136 if(lon_in(1) .lt. 0.0 .OR. lon_in(nlon_in) > tpi )
then 138 max_lon = lon_in(nlon_in)
147 if(src_is_modulo)
then 148 if(lon .lt. min_lon)
then 150 else if(lon .gt. max_lon)
then 155 if((lon .lt. lon_in(1)) .or. (lon .gt. lon_in(nlon_in))) &
156 call mpp_error(fatal,
'horiz_interp_bilinear_mod: ' //&
157 'when input grid is not modulo, output grid should locate inside input grid')
160 glt_min =
min(lat,glt_min); glt_max =
max(lat,glt_max)
161 gln_min =
min(lon,gln_min); gln_max =
max(lon,gln_max)
163 is =
indp(lon, lon_in )
164 if( lon_in(is) .gt. lon ) is =
max(is-1,1)
165 if( lon_in(is) .eq. lon .and. is .eq. nlon_in) is =
max(is - 1,1)
166 ie =
min(is+1,nlon_in)
167 if(lon_in(is) .ne. lon_in(ie) .and. lon_in(is) .le. lon)
then 168 wtw = ( lon_in(ie) - lon) / (lon_in(ie) - lon_in(is) )
175 if (lon_in(ie) .ge. lon )
then 176 wtw = (lon_in(ie) -lon)/(lon_in(ie)-lon_in(is)+tpi+
epsln)
178 wtw = (lon_in(ie) -lon+tpi+
epsln)/(lon_in(ie)-lon_in(is)+tpi+
epsln)
183 js =
indp(lat, lat_in )
185 if( lat_in(js) .gt. lat ) js =
max(js - 1, 1)
186 if( lat_in(js) .eq. lat .and. js .eq. nlat_in) js =
max(js - 1, 1)
187 je =
min(js + 1, nlat_in)
189 if ( lat_in(js) .ne. lat_in(je) .and. lat_in(js) .le. lat)
then 190 wts = ( lat_in(je) - lat )/(lat_in(je)-lat_in(js))
201 interp % i_lon (m,n,1) = is; interp % i_lon (m,n,2) = ie
202 interp % j_lat (m,n,1) = js; interp % j_lat (m,n,2) = je
203 interp % wti (m,n,1) = wtw
204 interp % wti (m,n,2) = wte
205 interp % wtj (m,n,1) = wts
206 interp % wtj (m,n,2) = wtn
213 if (ln_err .eq. 1 .and. warns > 0)
then 214 write (unit,
'(/,(1x,a))') &
215 '==> Warning: the geographic data set does not extend far ', &
216 ' enough east or west - a cyclic boundary ', &
217 ' condition was applied. check if appropriate ' 218 write (unit,
'(/,(1x,a,2f8.4))') &
219 ' data required between longitudes:', gln_min, gln_max, &
220 ' data set is between longitudes:', lon_in(1), lon_in(nlon_in)
224 if (lt_err .eq. 1 .and. warns > 0)
then 225 write (unit,
'(/,(1x,a))') &
226 '==> Warning: the geographic data set does not extend far ',&
227 ' enough north or south - extrapolation from ',&
228 ' the nearest data was applied. this may create ',&
229 ' artificial gradients near a geographic pole ' 230 write (unit,
'(/,(1x,a,2f8.4))') &
231 ' data required between latitudes:', glt_min, glt_max, &
232 ' data set is between latitudes:', lat_in(1), lat_in(nlat_in)
286 verbose, src_modulo, new_search, no_crash_when_not_found )
289 type(horiz_interp_type),
intent(inout) :: Interp
290 real,
intent(in),
dimension(:,:) :: lon_in , lat_in
291 real,
intent(in),
dimension(:,:) :: lon_out, lat_out
292 integer,
intent(in),
optional :: verbose
293 logical,
intent(in),
optional :: src_modulo
294 logical,
intent(in),
optional :: new_search
295 logical,
intent(in),
optional :: no_crash_when_not_found
297 logical :: src_is_modulo
298 integer :: nlon_in, nlat_in, nlon_out, nlat_out
299 integer :: m, n, is, ie, js, je, num_solution
300 real :: lon, lat, quadra, x, y, y1, y2
301 real :: a1, b1, c1, d1, a2, b2, c2, d2, a, b, c
302 real :: lon1, lat1, lon2, lat2, lon3, lat3, lon4, lat4
303 real :: tpi, lon_min, lon_max
305 logical :: use_new_search, no_crash
310 if(
present(verbose)) warns = verbose
311 src_is_modulo = .true.
312 if (
present(src_modulo)) src_is_modulo = src_modulo
313 use_new_search = .false.
314 if (
present(new_search)) use_new_search = new_search
316 if(
present(no_crash_when_not_found)) no_crash = no_crash_when_not_found
319 if(
size(lon_out,1) /=
size(lat_out,1) .or.
size(lon_out,2) /=
size(lat_out,2) ) &
320 call mpp_error(fatal,
'horiz_interp_bilinear_mod: when using bilinear ' // &
321 'interplation, the output grids should be geographical grids')
323 if(
size(lon_in,1) /=
size(lat_in,1) .or.
size(lon_in,2) /=
size(lat_in,2) ) &
324 call mpp_error(fatal,
'horiz_interp_bilinear_mod: when using bilinear '// &
325 'interplation, the input grids should be geographical grids')
328 nlon_in =
size(lon_in,1) ; nlat_in =
size(lat_in,2)
329 nlon_out =
size(lon_out,1); nlat_out =
size(lon_out,2)
330 interp%nlon_src = nlon_in; interp%nlat_src = nlat_in
331 interp%nlon_dst = nlon_out; interp%nlat_dst = nlat_out
333 allocate ( interp % wti (
size(lon_out,1),
size(lon_out,2),2), &
334 interp % wtj (
size(lon_out,1),
size(lon_out,2),2), &
335 interp % i_lon (
size(lon_out,1),
size(lon_out,2),2), &
336 interp % j_lat (
size(lon_out,1),
size(lon_out,2),2))
339 if(use_new_search)
then 341 call find_neighbor_new(interp, lon_in, lat_in, lon_out, lat_out, src_is_modulo, no_crash)
344 call find_neighbor(interp, lon_in, lat_in, lon_out, lat_out, src_is_modulo)
381 lon_min = minval(lon_in);
382 lon_max = maxval(lon_in);
388 if(lon .lt. lon_min)
then 390 else if(lon .gt. lon_max)
then 393 is = interp%i_lon(m,n,1); ie = interp%i_lon(m,n,2)
394 js = interp%j_lat(m,n,1); je = interp%j_lat(m,n,2)
395 if( is ==
dummy) cycle
396 lon1 = lon_in(is,js); lat1 = lat_in(is,js);
397 lon2 = lon_in(ie,js); lat2 = lat_in(ie,js);
398 lon3 = lon_in(ie,je); lat3 = lat_in(ie,je);
399 lon4 = lon_in(is,je); lat4 = lat_in(is,je);
400 if(lon .lt. lon_min)
then 401 lon1 = lon1 -tpi; lon4 = lon4 - tpi
402 else if(lon .gt. lon_max)
then 403 lon2 = lon2 +tpi; lon3 = lon3 + tpi
407 c1 = lon1+lon3-lon4-lon2
411 c2 = lat1+lat3-lat4-lat2
415 b = a1*b2-a2*b1+c1*d2-c2*d1+c2*lon-c1*lat
416 c = a2*lon-a1*lat+a1*d2-a2*d1
418 if(abs(quadra) <
epsln) quadra = 0.0
420 "horiz_interp_bilinear_mod: No solution existed for this quadratic equation")
421 if ( abs(a) .lt. epsln2)
then 423 "horiz_interp_bilinear_mod: no unique solution existed for this linear equation")
426 y1 = 0.5*(-b+sqrt(quadra))/a
427 y2 = 0.5*(-b-sqrt(quadra))/a
428 if(abs(y1) < epsln2) y1 = 0.0
429 if(abs(y2) < epsln2) y2 = 0.0
430 if(abs(1.0-y1) < epsln2) y1 = 1.0
431 if(abs(1.0-y2) < epsln2) y2 = 1.0
433 if(y1 >= 0.0 .and. y1 <= 1.0)
then 435 num_solution = num_solution +1
437 if(y2 >= 0.0 .and. y2 <= 1.0)
then 439 num_solution = num_solution + 1
441 if(num_solution == 0)
then 442 call mpp_error(fatal,
"horiz_interp_bilinear_mod: No solution found")
443 else if(num_solution == 2)
then 444 call mpp_error(fatal,
"horiz_interp_bilinear_mod: Two solutions found")
448 "horiz_interp_bilinear_mod: the denomenator is 0")
449 if(abs(y) < epsln2) y = 0.0
450 if(abs(1.0-y) < epsln2) y = 1.0
451 x = (lon-b1*y-d1)/(a1+c1*y)
452 if(abs(x) < epsln2) x = 0.0
453 if(abs(1.0-x) < epsln2) x = 1.0
456 if(use_new_search)
then 462 if( x>1. .or. x<0. .or. y>1. .or. y < 0.)
call mpp_error(fatal, &
463 "horiz_interp_bilinear_mod: weight should be between 0 and 1")
464 interp % wti(m,n,1)=1.0-x; interp % wti(m,n,2)=x
465 interp % wtj(m,n,1)=1.0-y; interp % wtj(m,n,2)=y
475 subroutine find_neighbor( Interp, lon_in, lat_in, lon_out, lat_out, src_modulo )
476 type(horiz_interp_type),
intent(inout) :: Interp
477 real,
intent(in),
dimension(:,:) :: lon_in , lat_in
478 real,
intent(in),
dimension(:,:) :: lon_out, lat_out
479 logical,
intent(in) :: src_modulo
480 integer :: nlon_in, nlat_in, nlon_out, nlat_out
481 integer :: max_step, n, m, l, i, j, ip1, jp1, step
482 integer :: is, js, jstart, jend, istart, iend, npts
483 integer,
allocatable,
dimension(:) :: ilon, jlat
484 real :: lon_min, lon_max, lon, lat, tpi
486 real :: lon1, lat1, lon2, lat2, lon3, lat3, lon4, lat4
489 nlon_in =
size(lon_in,1) ; nlat_in =
size(lat_in,2)
490 nlon_out =
size(lon_out,1); nlat_out =
size(lon_out,2)
492 lon_min = minval(lon_in);
493 lon_max = maxval(lon_in);
495 max_step =
max(nlon_in,nlat_in)
496 allocate(ilon(5*max_step), jlat(5*max_step) )
505 if(lon .lt. lon_min)
then 507 else if(lon .gt. lon_max)
then 511 if(lon .lt. lon_min .or. lon .gt. lon_max ) &
512 call mpp_error(fatal,
'horiz_interp_bilinear_mod: ' //&
513 'when input grid is not modulo, output grid should locate inside input grid')
516 if(m==1 .and. n==1)
then 517 j_loop:
do j = 1, nlat_in-1
528 lon1 = lon_in(i, j); lat1 = lat_in(i,j)
529 lon2 = lon_in(ip1,j); lat2 = lat_in(ip1,j)
530 lon3 = lon_in(ip1,jp1); lat3 = lat_in(ip1,jp1)
531 lon4 = lon_in(i, jp1); lat4 = lat_in(i, jp1)
533 if(lon .lt. lon_min .or. lon .gt. lon_max)
then 534 if(i .ne. nlon_in)
then 537 if(lon .lt. lon_min)
then 538 lon1 = lon1 -tpi; lon4 = lon4 - tpi
539 else if(lon .gt. lon_max)
then 540 lon2 = lon2 +tpi; lon3 = lon3 + tpi
545 if(lat .ge.
intersect(lon1,lat1,lon2,lat2,lon))
then 546 if(lon .le.
intersect(lat2,lon2,lat3,lon3,lat))
then 547 if(lat .le.
intersect(lon3,lat3,lon4,lat4,lon))
then 548 if(lon .ge.
intersect(lat4,lon4,lat1,lon1,lat))
then 550 interp % i_lon (m,n,1) = i; interp % i_lon (m,n,2) = ip1
551 interp % j_lat (m,n,1) = j; interp % j_lat (m,n,2) = jp1
561 do while ( .not. found .and. step .lt. max_step )
564 is = interp % i_lon (m,n-1,1)
565 js = interp % j_lat (m,n-1,1)
567 is = interp % i_lon (m-1,n,1)
568 js = interp % j_lat (m-1,n,1)
577 jstart =
max(js-step,1)
578 jend =
min(js+step,nlat_in)
585 else if (i > nlon_in)
then 588 if( i < 1 .or. i > nlon_in)
call mpp_error(fatal, &
589 'horiz_interp_bilinear_mod: max_step is too big, decrease max_step' )
591 if( i < 1 .or. i > nlon_in) cycle
603 if( istart < 1) istart = istart + nlon_in
604 if( iend > nlon_in) iend = iend - nlon_in
606 istart =
max(istart,1)
607 iend =
min(iend, nlon_in)
611 if( j < 1 .or. j > nlat_in .or. j==jstart .or. j==jend) cycle
627 else if (i > nlon_in)
then 630 if( i < 1 .or. i > nlon_in)
call mpp_error(fatal, &
631 'horiz_interp_bilinear_mod: max_step is too big, decrease max_step' )
633 if( i < 1 .or. i > nlon_in) cycle
657 if(jp1>nlat_in) cycle
658 lon1 = lon_in(i, j); lat1 = lat_in(i,j)
659 lon2 = lon_in(ip1,j); lat2 = lat_in(ip1,j)
660 lon3 = lon_in(ip1,jp1); lat3 = lat_in(ip1,jp1)
661 lon4 = lon_in(i, jp1); lat4 = lat_in(i, jp1)
663 if(lon .lt. lon_min .or. lon .gt. lon_max)
then 664 if(i .ne. nlon_in)
then 667 if(lon .lt. lon_min)
then 668 lon1 = lon1 -tpi; lon4 = lon4 - tpi
669 else if(lon .gt. lon_max)
then 670 lon2 = lon2 +tpi; lon3 = lon3 + tpi
675 if(lat .ge.
intersect(lon1,lat1,lon2,lat2,lon))
then 676 if(lon .le.
intersect(lat2,lon2,lat3,lon3,lat))
then 677 if(lat .le.
intersect(lon3,lat3,lon4,lat4,lon))
then 678 if(lon .ge.
intersect(lat4,lon4,lat1,lon1,lat))
then 681 interp % i_lon (m,n,1) = i; interp % i_lon (m,n,2) = ip1
682 interp % j_lat (m,n,1) = j; interp % j_lat (m,n,2) = jp1
693 print *,
'lon,lat=',lon*180./
pi,lat*180./
pi 695 print *,
'is,ie= ',istart,iend
696 print *,
'js,je= ',jstart,jend
697 print *,
'lon_in(is,js)=',lon_in(istart,jstart)*180./
pi 698 print *,
'lon_in(ie,js)=',lon_in(iend,jstart)*180./
pi 699 print *,
'lat_in(is,js)=',lat_in(istart,jstart)*180./
pi 700 print *,
'lat_in(ie,js)=',lat_in(iend,jstart)*180./
pi 701 print *,
'lon_in(is,je)=',lon_in(istart,jend)*180./
pi 702 print *,
'lon_in(ie,je)=',lon_in(iend,jend)*180./
pi 703 print *,
'lat_in(is,je)=',lat_in(istart,jend)*180./
pi 704 print *,
'lat_in(ie,je)=',lat_in(iend,jend)*180./
pi 707 'find_neighbor: the destination point is not inside the source grid' )
726 real,
dimension(:),
intent(in) :: polyx, polyy
727 real,
intent(in) :: x, y
729 integer :: i, j, nedges
733 nedges =
size(polyx(:))
736 if( (polyy(i) < y .AND. polyy(j) >= y) .OR. (polyy(j) < y .AND. polyy(i) >= y) )
then 737 xx = polyx(i)+(y-polyy(i))/(polyy(j)-polyy(i))*(polyx(j)-polyx(i))
741 else if( xx < x )
then 755 subroutine find_neighbor_new( Interp, lon_in, lat_in, lon_out, lat_out, src_modulo, no_crash )
756 type(horiz_interp_type),
intent(inout) :: Interp
757 real,
intent(in),
dimension(:,:) :: lon_in , lat_in
758 real,
intent(in),
dimension(:,:) :: lon_out, lat_out
759 logical,
intent(in) :: src_modulo, no_crash
760 integer :: nlon_in, nlat_in, nlon_out, nlat_out
761 integer :: max_step, n, m, l, i, j, ip1, jp1, step
762 integer :: is, js, jstart, jend, istart, iend, npts
763 integer,
allocatable,
dimension(:) :: ilon, jlat
764 real :: lon_min, lon_max, lon, lat, tpi
766 real :: polyx(4), polyy(4)
767 real :: min_lon, min_lat, max_lon, max_lat
769 integer,
parameter :: step_div=8
772 nlon_in =
size(lon_in,1) ; nlat_in =
size(lat_in,2)
773 nlon_out =
size(lon_out,1); nlat_out =
size(lon_out,2)
775 lon_min = minval(lon_in);
776 lon_max = maxval(lon_in);
778 max_step =
min(nlon_in,nlat_in)/step_div
779 allocate(ilon(step_div*max_step), jlat(step_div*max_step) )
788 if(lon .lt. lon_min)
then 790 else if(lon .gt. lon_max)
then 794 if(lon .lt. lon_min .or. lon .gt. lon_max ) &
795 call mpp_error(fatal,
'horiz_interp_bilinear_mod: ' //&
796 'when input grid is not modulo, output grid should locate inside input grid')
799 if(m==1 .and. n==1)
then 800 j_loop:
do j = 1, nlat_in-1
812 polyx(1) = lon_in(i, j); polyy(1) = lat_in(i,j)
813 polyx(2) = lon_in(ip1,j); polyy(2) = lat_in(ip1,j)
814 polyx(3) = lon_in(ip1,jp1); polyy(3) = lat_in(ip1,jp1)
815 polyx(4) = lon_in(i, jp1); polyy(4) = lat_in(i, jp1)
816 if(lon .lt. lon_min .or. lon .gt. lon_max)
then 817 if(i .ne. nlon_in)
then 820 if(lon .lt. lon_min)
then 821 polyx(1) = polyx(1) -tpi; polyx(4) = polyx(4) - tpi
822 else if(lon .gt. lon_max)
then 823 polyx(2) = polyx(2) +tpi; polyx(3) = polyx(3) + tpi
828 min_lon = minval(polyx)
829 max_lon = maxval(polyx)
830 min_lat = minval(polyy)
831 max_lat = maxval(polyy)
842 interp % i_lon (m,n,1) = i; interp % i_lon (m,n,2) = ip1
843 interp % j_lat (m,n,1) = j; interp % j_lat (m,n,2) = jp1
850 do while ( .not. found .and. step .lt. max_step )
853 is = interp % i_lon (m,n-1,1)
854 js = interp % j_lat (m,n-1,1)
856 is = interp % i_lon (m-1,n,1)
857 js = interp % j_lat (m-1,n,1)
866 jstart =
max(js-step,1)
867 jend =
min(js+step,nlat_in)
874 else if (i > nlon_in)
then 877 if( i < 1 .or. i > nlon_in)
call mpp_error(fatal, &
878 'horiz_interp_bilinear_mod: max_step is too big, decrease max_step' )
880 if( i < 1 .or. i > nlon_in) cycle
895 if( istart < 1) istart = istart + nlon_in
896 if( iend > nlon_in) iend = iend - nlon_in
898 istart =
max(istart,1)
899 iend =
min(iend, nlon_in)
903 if( j < 1 .or. j > nlat_in) cycle
926 if(jp1>nlat_in) cycle
927 polyx(1) = lon_in(i, j); polyy(1) = lat_in(i,j)
928 polyx(2) = lon_in(ip1,j); polyy(2) = lat_in(ip1,j)
929 polyx(3) = lon_in(ip1,jp1); polyy(3) = lat_in(ip1,jp1)
930 polyx(4) = lon_in(i, jp1); polyy(4) = lat_in(i, jp1)
933 interp % i_lon (m,n,1) = i; interp % i_lon (m,n,2) = ip1
934 interp % j_lat (m,n,1) = j; interp % j_lat (m,n,2) = jp1
943 interp % i_lon (m,n,1:2) =
dummy 944 interp % j_lat (m,n,1:2) =
dummy 945 print*,
'lon,lat=',lon,lat
948 'horiz_interp_bilinear_mod: the destination point is not inside the source grid' )
958 real,
intent(in) :: x1, y1, x2, y2, x
1014 missing_value, missing_permit, new_handle_missing )
1017 real,
intent(in),
dimension(:,:) :: data_in
1018 real,
intent(out),
dimension(:,:) :: data_out
1019 integer,
intent(in),
optional :: verbose
1020 real,
intent(in),
dimension(:,:),
optional :: mask_in
1021 real,
intent(out),
dimension(:,:),
optional :: mask_out
1022 real,
intent(in),
optional :: missing_value
1023 integer,
intent(in),
optional :: missing_permit
1024 logical,
intent(in),
optional :: new_handle_missing
1026 integer :: nlon_in, nlat_in, nlon_out, nlat_out, n, m, &
1027 is, ie, js, je, iverbose, max_missing, num_missing, &
1028 miss_in, miss_out, unit
1029 real :: dwtsum, wtsum, min_in, max_in, avg_in, &
1030 min_out, max_out, avg_out, wtw, wte, wts, wtn
1031 real :: mask(
size(data_in,1),
size(data_in,2) )
1032 logical :: set_to_missing, is_missing(4), new_handler
1033 real :: f1, f2, f3, f4, middle, w, s
1037 nlon_in = interp%nlon_src; nlat_in = interp%nlat_src
1038 nlon_out = interp%nlon_dst; nlat_out = interp%nlat_dst
1040 if(
present(mask_in))
then 1046 if (
present(verbose))
then 1052 if(
present(missing_permit))
then 1053 max_missing = missing_permit
1058 if(
present(new_handle_missing))
then 1059 new_handler = new_handle_missing
1061 new_handler = .false.
1064 if(max_missing .gt. 3 .or. max_missing .lt. 0)
call mpp_error(fatal, &
1065 'horiz_interp_bilinear_mod: missing_permit should be between 0 and 3')
1067 if (
size(data_in,1) /= nlon_in .or.
size(data_in,2) /= nlat_in) &
1068 call mpp_error(fatal,
'horiz_interp_bilinear_mod: size of input array incorrect')
1070 if (
size(data_out,1) /= nlon_out .or.
size(data_out,2) /= nlat_out) &
1071 call mpp_error(fatal,
'horiz_interp_bilinear_mod: size of output array incorrect')
1073 if(new_handler)
then 1074 if( .not.
present(missing_value) )
call mpp_error(fatal, &
1075 "horiz_interp_bilinear_mod: misisng_value must be present when new_handle_missing is .true.")
1076 if(
present(mask_in) )
call mpp_error(fatal, &
1077 "horiz_interp_bilinear_mod: mask_in should not be present when new_handle_missing is .true.")
1080 is = interp % i_lon (m,n,1); ie = interp % i_lon (m,n,2)
1081 js = interp % j_lat (m,n,1); je = interp % j_lat (m,n,2)
1082 wtw = interp % wti (m,n,1)
1083 wte = interp % wti (m,n,2)
1084 wts = interp % wtj (m,n,1)
1085 wtn = interp % wtj (m,n,2)
1087 is_missing = .false.
1089 set_to_missing = .false.
1090 if(data_in(is,js) == missing_value)
then 1091 num_missing = num_missing+1
1092 is_missing(1) = .true.
1093 if(wtw .GE. 0.5 .AND. wts .GE. 0.5) set_to_missing = .true.
1096 if(data_in(ie,js) == missing_value)
then 1097 num_missing = num_missing+1
1098 is_missing(2) = .true.
1099 if(wte .GE. 0.5 .AND. wts .GE. 0.5) set_to_missing = .true.
1101 if(data_in(ie,je) == missing_value)
then 1102 num_missing = num_missing+1
1103 is_missing(3) = .true.
1104 if(wte .GE. 0.5 .AND. wtn .GE. 0.5) set_to_missing = .true.
1106 if(data_in(is,je) == missing_value)
then 1107 num_missing = num_missing+1
1108 is_missing(4) = .true.
1109 if(wtw .GE. 0.5 .AND. wtn .GE. 0.5) set_to_missing = .true.
1112 if( num_missing == 4 .OR. set_to_missing )
then 1113 data_out(m,n) = missing_value
1114 if(
present(mask_out)) mask_out(m,n) = 0.0
1116 else if(num_missing == 0)
then 1123 else if(num_missing == 3)
then 1124 if(.not. is_missing(1) )
then 1125 data_out(m,n) = data_in(is,js)
1126 else if(.not. is_missing(2) )
then 1127 data_out(m,n) = data_in(ie,js)
1128 else if(.not. is_missing(3) )
then 1129 data_out(m,n) = data_in(ie,je)
1130 else if(.not. is_missing(4) )
then 1131 data_out(m,n) = data_in(is,je)
1133 if(
present(mask_out) ) mask_out(m,n) = 1.0
1136 if( num_missing == 1)
then 1137 if( is_missing(1) .OR. is_missing(3) )
then 1138 middle = 0.5*(data_in(ie,js)+data_in(is,je))
1140 middle = 0.5*(data_in(is,js)+data_in(ie,je))
1143 if( is_missing(1) .AND. is_missing(2) )
then 1144 middle = 0.5*(data_in(ie,je)+data_in(is,je))
1145 else if( is_missing(1) .AND. is_missing(3) )
then 1146 middle = 0.5*(data_in(ie,js)+data_in(is,je))
1147 else if( is_missing(1) .AND. is_missing(4) )
then 1148 middle = 0.5*(data_in(ie,js)+data_in(ie,je))
1149 else if( is_missing(2) .AND. is_missing(3) )
then 1150 middle = 0.5*(data_in(is,js)+data_in(is,je))
1151 else if( is_missing(2) .AND. is_missing(4) )
then 1152 middle = 0.5*(data_in(is,js)+data_in(ie,je))
1153 else if( is_missing(3) .AND. is_missing(4) )
then 1154 middle = 0.5*(data_in(is,js)+data_in(ie,js))
1158 if( wtw .GE. 0.5 .AND. wts .GE. 0.5 )
then 1162 if(is_missing(2))
then 1165 f2 = 0.5*(data_in(is,js)+data_in(ie,js))
1168 if(is_missing(4))
then 1171 f4 = 0.5*(data_in(is,js)+data_in(is,je))
1173 else if( wte .GE. 0.5 .AND. wts .GE. 0.5 )
then 1177 if(is_missing(1))
then 1180 f1 = 0.5*(data_in(is,js)+data_in(ie,js))
1183 if(is_missing(3))
then 1186 f3 = 0.5*(data_in(ie,js)+data_in(ie,je))
1188 else if( wte .GE. 0.5 .AND. wtn .GE. 0.5 )
then 1192 if(is_missing(2))
then 1195 f2 = 0.5*(data_in(ie,js)+data_in(ie,je))
1198 if(is_missing(4))
then 1201 f4 = 0.5*(data_in(ie,je)+data_in(is,je))
1203 else if( wtw .GE. 0.5 .AND. wtn .GE. 0.5 )
then 1207 if(is_missing(1))
then 1210 f1 = 0.5*(data_in(is,js)+data_in(is,je))
1213 if(is_missing(3))
then 1216 f3 = 0.5*(data_in(ie,je)+data_in(is,je))
1220 "horiz_interp_bilinear_mod: the point should be in one of the four zone")
1224 data_out(m,n) = f3 + (f4-f3)*w + (f2-f3)*s + ((f1-f2)+(f3-f4))*w*s
1225 if(
present(mask_out)) mask_out(m,n) = 1.0
1231 is = interp % i_lon (m,n,1); ie = interp % i_lon (m,n,2)
1232 js = interp % j_lat (m,n,1); je = interp % j_lat (m,n,2)
1233 wtw = interp % wti (m,n,1)
1234 wte = interp % wti (m,n,2)
1235 wts = interp % wtj (m,n,1)
1236 wtn = interp % wtj (m,n,2)
1238 if(
present(missing_value) )
then 1240 if(data_in(is,js) == missing_value)
then 1241 num_missing = num_missing+1
1244 if(data_in(ie,js) == missing_value)
then 1245 num_missing = num_missing+1
1248 if(data_in(ie,je) == missing_value)
then 1249 num_missing = num_missing+1
1252 if(data_in(is,je) == missing_value)
then 1253 num_missing = num_missing+1
1258 dwtsum = data_in(is,js)*mask(is,js)*wtw*wts &
1259 + data_in(ie,js)*mask(ie,js)*wte*wts &
1260 + data_in(ie,je)*mask(ie,je)*wte*wtn &
1261 + data_in(is,je)*mask(is,je)*wtw*wtn
1262 wtsum = mask(is,js)*wtw*wts + mask(ie,js)*wte*wts &
1263 + mask(ie,je)*wte*wtn + mask(is,je)*wtw*wtn
1265 if(.not.
present(mask_in) .and. .not.
present(missing_value)) wtsum = 1.0
1267 if(num_missing .gt. max_missing )
then 1268 data_out(m,n) = missing_value
1269 if(
present(mask_out)) mask_out(m,n) = 0.0
1270 else if(wtsum .lt.
epsln)
then 1271 if(
present(missing_value))
then 1272 data_out(m,n) = missing_value
1276 if(
present(mask_out)) mask_out(m,n) = 0.0
1278 data_out(m,n) = dwtsum/wtsum
1279 if(
present(mask_out)) mask_out(m,n) = wtsum
1287 if (iverbose > 0)
then 1291 call stats (data_in, min_in, max_in, avg_in, miss_in, missing_value, mask_in)
1294 call stats (data_out, min_out, max_out, avg_out, miss_out, missing_value, mask_out)
1299 write (unit,901) min_in ,max_in, avg_in
1300 if (
present(mask_in))
write (unit,903) miss_in
1301 write (unit,902) min_out,max_out,avg_out
1302 if (
present(mask_out))
write (unit,903) miss_out
1304 900
format (/,1x,10(
'-'),
' output from horiz_interp ',10(
'-'))
1305 901
format (
' input: min=',f16.9,
' max=',f16.9,
' avg=',f22.15)
1306 902
format (
' output: min=',f16.9,
' max=',f16.9,
' avg=',f22.15)
1307 903
format (
' number of missing points = ',i6)
1342 if(
associated(interp%wti))
deallocate(interp%wti)
1343 if(
associated(interp%wtj))
deallocate(interp%wtj)
1344 if(
associated(interp%i_lon))
deallocate(interp%i_lon)
1345 if(
associated(interp%j_lat))
deallocate(interp%j_lat)
1352 function indp (value, array)
1354 real,
dimension(:),
intent(in) :: array
1355 real,
intent(in) :: value
1378 if (array(i) .lt. array(i-1))
then 1381 ' => Error: array must be monotonically increasing in "indp"' , &
1382 ' when searching for nearest element to value=',
value 1383 write (unit,*)
' array(i) < array(i-1) for i=',i
1384 write (unit,*)
' array(i) for i=1..ia follows:' 1388 if (
value .lt. array(1) .or.
value .gt. array(ia))
then 1389 if (
value .lt. array(1))
indp = 1
1390 if (
value .gt. array(ia))
indp = ia
1394 do while (i .le. ia .and. keep_going)
1396 if (
value .le. array(i))
then 1398 if (array(i)-
value .gt.
value-array(i-1))
indp = i-1
1399 keep_going = .false.
subroutine find_neighbor_new(Interp, lon_in, lat_in, lon_out, lat_out, src_modulo, no_crash)
real function intersect(x1, y1, x2, y2, x)
subroutine find_neighbor(Interp, lon_in, lat_in, lon_out, lat_out, src_modulo)
subroutine, public horiz_interp_bilinear(Interp, data_in, data_out, verbose, mask_in, mask_out, missing_value, missing_permit, new_handle_missing)
subroutine, public stats(dat, low, high, avg, miss, missing_value, mask)
subroutine, public horiz_interp_bilinear_del(Interp)
logical module_is_initialized
logical function inside_polygon(polyx, polyy, x, y)
integer function indp(value, array)
subroutine, public horiz_interp_bilinear_init
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)
************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************subroutine READ_RECORD_CORE_(unit, field, nwords, data, start, axsiz) integer, intent(in) ::unit type(fieldtype), intent(in) ::field integer, intent(in) ::nwords MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in) ::start(:), axsiz(:) integer(SHORT_KIND) ::i2vals(nwords)!rab used in conjunction with transfer intrinsic to determine size of a variable integer(KIND=1) ::one_byte(8) integer ::word_sz!#ifdef __sgi integer(INT_KIND) ::ivals(nwords) real(FLOAT_KIND) ::rvals(nwords)!#else! integer ::ivals(nwords)! real ::rvals(nwords)!#endif real(DOUBLE_KIND) ::r8vals(nwords) pointer(ptr1, i2vals) pointer(ptr2, ivals) pointer(ptr3, rvals) pointer(ptr4, r8vals) if(mpp_io_stack_size< nwords) call mpp_io_set_stack_size(nwords) call mpp_error(FATAL, 'MPP_READ currently requires use_netCDF option') end subroutine READ_RECORD_CORE_ subroutine READ_RECORD_(unit, field, nwords, data, time_level, domain, position, tile_count, start_in, axsiz_in)!routine that is finally called by all mpp_read routines to perform the read!a non-netCDF record contains:! field ID! a set of 4 coordinates(is:ie, js:je) giving the data subdomain! a timelevel and a timestamp(=NULLTIME if field is static)! 3D real data(stored as 1D)!if you are using direct access I/O, the RECL argument to OPEN must be large enough for the above!in a global direct access file, record position on PE is given by %record.!Treatment of timestamp:! We assume that static fields have been passed without a timestamp.! Here that is converted into a timestamp of NULLTIME.! For non-netCDF fields, field is treated no differently, but is written! with a timestamp of NULLTIME. There is no check in the code to prevent! the user from repeatedly writing a static field. integer, intent(in) ::unit, nwords type(fieldtype), intent(in) ::field MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in), optional ::time_level type(domain2D), intent(in), optional ::domain integer, intent(in), optional ::position, tile_count integer, intent(in), optional ::start_in(:), axsiz_in(:) integer, dimension(size(field%axes(:))) ::start, axsiz integer ::tlevel !, subdomain(4) integer ::i, error, is, ie, js, je, isg, ieg, jsg, jeg type(domain2d), pointer ::io_domain=> tlevel if(PRESENT(start_in) .AND. PRESENT(axsiz_in)) then if(size(start(! the data domain and compute domain must refer to the subdomain being passed ! In this ! since that attempts to gather all data on PE size(field%axes(:)) axsiz(i)
subroutine horiz_interp_bilinear_new_1d(Interp, lon_in, lat_in, lon_out, lat_out, verbose, src_modulo)
real(fp), parameter, public pi