1 module module_interpolate
3 ! Routines for interpolation of data in latitude, longitude and time.
5 ! Author: Gathered from a number of places and put into the current format by Jim Edwards
9 ! use shr_kind_mod, only: r8 => shr_kind_r8
10 ! use abortutils, only: endrun
11 ! use scamMod, only: single_column
12 ! use cam_logfile, only: iulog
18 integer,parameter :: r8 = selected_real_kind(12) ! 8 byte real
19 ! integer,parameter :: r8 = selected_real_kind(8) ! 8 byte real
23 public :: interp_type, lininterp, vertinterp, bilin, get_timeinterp_factors
24 public :: lininterp_init, lininterp_finish
26 real(r8), pointer :: wgts(:)
27 real(r8), pointer :: wgtn(:)
28 integer, pointer :: jjm(:)
29 integer, pointer :: jjp(:)
32 module procedure lininterp_original
33 module procedure lininterp_full1d
34 module procedure lininterp1d
35 module procedure lininterp2d2d
36 module procedure lininterp2d1d
37 module procedure lininterp3d2d
42 subroutine lininterp_full1d (arrin, yin, nin, arrout, yout, nout)
43 integer, intent(in) :: nin, nout
44 real(r8), intent(in) :: arrin(nin), yin(nin), yout(nout)
45 real(r8), intent(out) :: arrout(nout)
46 type (interp_type) :: interp_wgts
48 call lininterp_init(yin, nin, yout, nout, 1, interp_wgts)
49 call lininterp1d(arrin, nin, arrout, nout, interp_wgts)
50 call lininterp_finish(interp_wgts)
52 end subroutine lininterp_full1d
54 subroutine lininterp_init(yin, nin, yout, nout, extrap_method, interp_wgts, &
58 ! Initialize a variable of type(interp_type) with weights for linear interpolation.
59 ! this variable can then be used in calls to lininterp1d and lininterp2d.
60 ! yin is a 1d array of length nin of locations to interpolate from - this array must
61 ! be monotonic but can be increasing or decreasing
62 ! yout is a 1d array of length nout of locations to interpolate to, this array need
64 ! extrap_method determines how to handle yout points beyond the bounds of yin
65 ! if 0 set values outside output grid to 0
66 ! if 1 set to boundary value
67 ! if 2 set to cyclic boundaries
68 ! optional values cyclicmin and cyclicmax can be used to set the bounds of the
69 ! cyclic mapping - these default to 0 and 360.
72 integer, intent(in) :: nin
73 integer, intent(in) :: nout
74 real(r8), intent(in) :: yin(:) ! input mesh
75 real(r8), intent(in) :: yout(:) ! output mesh
76 integer, intent(in) :: extrap_method ! if 0 set values outside output grid to 0
77 ! if 1 set to boundary value
78 ! if 2 set to cyclic boundaries
79 real(r8), intent(in), optional :: cyclicmin, cyclicmax
81 type (interp_type), intent(out) :: interp_wgts
83 real(r8) :: cmin, cmax
88 integer :: i, j, icount
90 real(r8), pointer :: wgts(:)
91 real(r8), pointer :: wgtn(:)
92 integer, pointer :: jjm(:)
93 integer, pointer :: jjp(:)
95 character(len=132) :: message
97 ! Check validity of input coordinate arrays: must be monotonically increasing,
98 ! and have a total of at least 2 elements
101 call wrf_abort !('LININTERP: Must have at least 2 input points for interpolation')
103 if(present(cyclicmin)) then
108 if(present(cyclicmax)) then
114 call wrf_abort !('LININTERP: cyclic min value must be < max value')
119 if (yin(j).gt.yin(j+1)) icount = icount + 1
121 if(icount.eq.nin-1) then
125 if (icount.gt.0) then
126 call wrf_abort !('LININTERP: Non-monotonic input coordinate array found')
128 allocate(interp_wgts%jjm(nout), &
129 interp_wgts%jjp(nout), &
130 interp_wgts%wgts(nout), &
131 interp_wgts%wgtn(nout))
133 jjm => interp_wgts%jjm
134 jjp => interp_wgts%jjp
135 wgts => interp_wgts%wgts
136 wgtn => interp_wgts%wgtn
139 ! Initialize index arrays for later checking
145 if(extrap_method.eq.0) then
147 ! For values which extend beyond boundaries, set weights
148 ! such that values will be 0.
152 if (yout(j).lt.yin(1)) then
158 else if (yout(j).gt.yin(nin)) then
166 if (yout(j).gt.yin(1)) then
172 else if (yout(j).lt.yin(nin)) then
181 else if(extrap_method.eq.1) then
183 ! For values which extend beyond boundaries, set weights
184 ! such that values will just be copied.
188 if (yout(j).le.yin(1)) then
194 else if (yout(j).gt.yin(nin)) then
202 if (yout(j).gt.yin(1)) then
208 else if (yout(j).le.yin(nin)) then
217 else if(extrap_method.eq.2) then
219 ! For values which extend beyond boundaries, set weights
220 ! for circular boundaries
222 dyinwrap = yin(1) + (cmax-cmin) - yin(nin)
223 avgdyin = abs(yin(nin)-yin(1))/(nin-1.)
224 ratio = dyinwrap/avgdyin
225 if (ratio < 0.9 .or. ratio > 1.1) then
226 write(message,*) 'Lininterp: Bad dyinwrap value =',dyinwrap,&
227 ' avg=', avgdyin, yin(1),yin(nin)
228 call wrf_message( trim(message) )
229 call wrf_abort !('interpolate_data')
234 if (yout(j) <= yin(1)) then
237 wgts(j) = (yin(1)-yout(j))/dyinwrap
238 wgtn(j) = (yout(j)+(cmax-cmin) - yin(nin))/dyinwrap
239 else if (yout(j) > yin(nin)) then
242 wgts(j) = (yin(1)+(cmax-cmin)-yout(j))/dyinwrap
243 wgtn(j) = (yout(j)-yin(nin))/dyinwrap
246 if (yout(j) > yin(1)) then
249 wgts(j) = (yin(1)-yout(j))/dyinwrap
250 wgtn(j) = (yout(j)+(cmax-cmin) - yin(nin))/dyinwrap
251 else if (yout(j) <= yin(nin)) then
254 wgts(j) = (yin(1)+(cmax-cmin)-yout(j))/dyinwrap
255 wgtn(j) = (yout(j)+(cmax-cmin)-yin(nin))/dyinwrap
263 ! Loop though output indices finding input indices and weights
268 if (yout(j).gt.yin(jj) .and. yout(j).le.yin(jj+1)) then
271 wgts(j) = (yin(jj+1)-yout(j))/(yin(jj+1)-yin(jj))
272 wgtn(j) = (yout(j)-yin(jj))/(yin(jj+1)-yin(jj))
280 if (yout(j).le.yin(jj) .and. yout(j).gt.yin(jj+1)) then
283 wgts(j) = (yin(jj+1)-yout(j))/(yin(jj+1)-yin(jj))
284 wgtn(j) = (yout(j)-yin(jj))/(yin(jj+1)-yin(jj))
295 extrap = 100.*extrap/real(nout,r8)
296 if (extrap.gt.50. ) then
297 write(message,*) 'interpolate_data:','yout=',minval(yout),maxval(yout),increasing,nout
298 call wrf_message( trim(message) )
299 write(message,*) 'interpolate_data:','yin=',yin(1),yin(nin)
300 call wrf_message( trim(message) )
301 write(message,*) 'interpolate_data:',extrap,' % of output grid will have to be extrapolated'
302 call wrf_message( trim(message) )
303 call wrf_abort !('interpolate_data: ')
308 ! Check that interp/extrap points have been found for all outputs
312 if (jjm(j).eq.0 .or. jjp(j).eq.0) icount = icount + 1
313 ratio=wgts(j)+wgtn(j)
314 if((ratio<0.9.or.ratio>1.1).and.extrap_method.ne.0) then
315 write(message,*) j, wgts(j),wgtn(j),jjm(j),jjp(j), increasing,extrap_method
316 call wrf_message( trim(message) )
317 call wrf_abort !('Bad weight computed in LININTERP_init')
320 if (icount.gt.0) then
321 call wrf_abort !('LININTERP: Point found without interp indices')
324 end subroutine lininterp_init
326 subroutine lininterp1d (arrin, n1, arrout, m1, interp_wgts)
327 !-----------------------------------------------------------------------
329 ! Purpose: Do a linear interpolation from input mesh to output
330 ! mesh with weights as set in lininterp_init.
333 ! Author: Jim Edwards
335 !-----------------------------------------------------------------------
336 !-----------------------------------------------------------------------
338 !-----------------------------------------------------------------------
342 integer, intent(in) :: n1 ! number of input latitudes
343 integer, intent(in) :: m1 ! number of output latitudes
345 real(r8), intent(in) :: arrin(n1) ! input array of values to interpolate
346 type(interp_type), intent(in) :: interp_wgts
347 real(r8), intent(out) :: arrout(m1) ! interpolated array
352 integer j ! latitude indices
353 integer, pointer :: jjm(:)
354 integer, pointer :: jjp(:)
356 real(r8), pointer :: wgts(:)
357 real(r8), pointer :: wgtn(:)
360 jjm => interp_wgts%jjm
361 jjp => interp_wgts%jjp
362 wgts => interp_wgts%wgts
363 wgtn => interp_wgts%wgtn
366 ! Do the interpolation
369 arrout(j) = arrin(jjm(j))*wgts(j) + arrin(jjp(j))*wgtn(j)
373 end subroutine lininterp1d
375 subroutine lininterp2d2d(arrin, n1, n2, arrout, m1, m2, wgt1, wgt2)
377 !-----------------------------------------------------------------------
381 integer, intent(in) :: n1, n2, m1, m2
382 real(r8), intent(in) :: arrin(n1,n2) ! input array of values to interpolate
383 type(interp_type), intent(in) :: wgt1, wgt2
384 real(r8), intent(out) :: arrout(m1,m2) ! interpolated array
388 integer i,j ! indices
389 integer, pointer :: iim(:), jjm(:)
390 integer, pointer :: iip(:), jjp(:)
392 real(r8), pointer :: wgts1(:), wgts2(:)
393 real(r8), pointer :: wgtn1(:), wgtn2(:)
395 real(r8) :: arrtmp(n1,m2)
410 arrtmp(i,j) = arrin(i,jjm(j))*wgts2(j) + arrin(i,jjp(j))*wgtn2(j)
416 arrout(i,j) = arrtmp(iim(i),j)*wgts1(i) + arrtmp(iip(i),j)*wgtn1(i)
420 end subroutine lininterp2d2d
421 subroutine lininterp2d1d(arrin, n1, n2, arrout, m1, wgt1, wgt2, fldname)
423 !-----------------------------------------------------------------------
427 integer, intent(in) :: n1, n2, m1
428 real(r8), intent(in) :: arrin(n1,n2) ! input array of values to interpolate
429 type(interp_type), intent(in) :: wgt1, wgt2
430 real(r8), intent(out) :: arrout(m1) ! interpolated array
431 character(len=*), intent(in), optional :: fldname(:)
436 integer, pointer :: iim(:), jjm(:)
437 integer, pointer :: iip(:), jjp(:)
439 real(r8), pointer :: wgts(:), wgte(:)
440 real(r8), pointer :: wgtn(:), wgtw(:)
453 arrout(i) = arrin(iim(i),jjm(i))*wgtw(i)*wgts(i)+arrin(iip(i),jjm(i))*wgte(i)*wgts(i) + &
454 arrin(iim(i),jjp(i))*wgtw(i)*wgtn(i)+arrin(iip(i),jjp(i))*wgte(i)*wgtn(i)
458 end subroutine lininterp2d1d
459 subroutine lininterp3d2d(arrin, n1, n2, n3, arrout, m1, len1, wgt1, wgt2)
461 !-----------------------------------------------------------------------
465 integer, intent(in) :: n1, n2, n3, m1, len1 ! m1 is to len1 as ncols is to pcols
466 real(r8), intent(in) :: arrin(n1,n2,n3) ! input array of values to interpolate
467 type(interp_type), intent(in) :: wgt1, wgt2
468 real(r8), intent(out) :: arrout(len1, n3) ! interpolated array
473 integer i, k ! indices
474 integer, pointer :: iim(:), jjm(:)
475 integer, pointer :: iip(:), jjp(:)
477 real(r8), pointer :: wgts(:), wgte(:)
478 real(r8), pointer :: wgtn(:), wgtw(:)
492 arrout(i,k) = arrin(iim(i),jjm(i),k)*wgtw(i)*wgts(i)+arrin(iip(i),jjm(i),k)*wgte(i)*wgts(i) + &
493 arrin(iim(i),jjp(i),k)*wgtw(i)*wgtn(i)+arrin(iip(i),jjp(i),k)*wgte(i)*wgtn(i)
497 end subroutine lininterp3d2d
502 subroutine lininterp_finish(interp_wgts)
503 type(interp_type) :: interp_wgts
505 deallocate(interp_wgts%jjm, &
510 nullify(interp_wgts%jjm, &
514 end subroutine lininterp_finish
516 subroutine lininterp_original (arrin, yin, nlev, nlatin, arrout, &
518 !-----------------------------------------------------------------------
520 ! Purpose: Do a linear interpolation from input mesh defined by yin to output
521 ! mesh defined by yout. Where extrapolation is necessary, values will
522 ! be copied from the extreme edge of the input grid. Vectorization is over
523 ! the vertical (nlev) dimension.
525 ! Method: Check validity of input, then determine weights, then do the N-S interpolation.
527 ! Author: Jim Rosinski
528 ! Modified: Jim Edwards so that there is no requirement of monotonacity on the yout array
530 !-----------------------------------------------------------------------
532 !-----------------------------------------------------------------------
536 integer, intent(in) :: nlev ! number of vertical levels
537 integer, intent(in) :: nlatin ! number of input latitudes
538 integer, intent(in) :: nlatout ! number of output latitudes
540 real(r8), intent(in) :: arrin(nlev,nlatin) ! input array of values to interpolate
541 real(r8), intent(in) :: yin(nlatin) ! input mesh
542 real(r8), intent(in) :: yout(nlatout) ! output mesh
544 real(r8), intent(out) :: arrout(nlev,nlatout) ! interpolated array
548 integer j, jj ! latitude indices
549 integer jjprev ! latitude indices
550 integer k ! level index
551 integer icount ! number of values
553 real(r8) extrap ! percent grid non-overlap
557 integer :: jjm(nlatout)
558 integer :: jjp(nlatout)
560 real(r8) :: wgts(nlatout)
561 real(r8) :: wgtn(nlatout)
563 ! Check validity of input coordinate arrays: must be monotonically increasing,
564 ! and have a total of at least 2 elements
566 if (nlatin.lt.2) then
567 call wrf_abort !('LININTERP: Must have at least 2 input points for interpolation')
572 if (yin(j).gt.yin(j+1)) icount = icount + 1
576 if (icount.gt.0) then
577 call wrf_abort !('LININTERP: Non-monotonic coordinate array(s) found')
580 ! Initialize index arrays for later checking
587 ! For values which extend beyond N and S boundaries, set weights
588 ! such that values will just be copied.
593 if (yout(j).le.yin(1)) then
599 else if (yout(j).gt.yin(nlatin)) then
609 ! Loop though output indices finding input indices and weights
613 if (yout(j).gt.yin(jj) .and. yout(j).le.yin(jj+1)) then
616 wgts(j) = (yin(jj+1)-yout(j))/(yin(jj+1)-yin(jj))
617 wgtn(j) = (yout(j)-yin(jj))/(yin(jj+1)-yin(jj))
623 ! Check that interp/extrap points have been found for all outputs
627 if (jjm(j).eq.0 .or. jjp(j).eq.0) then
631 if (icount.gt.0) then
632 call wrf_abort !('LININTERP: Point found without interp indices')
635 ! Do the interpolation
639 arrout(k,j) = arrin(k,jjm(j))*wgts(j) + arrin(k,jjp(j))*wgtn(j)
644 end subroutine lininterp_original
647 subroutine bilin (arrin, xin, yin, nlondin, nlonin, &
648 nlevdin, nlev, nlatin, arrout, xout, &
649 yout, nlondout, nlonout, nlevdout, nlatout)
650 !-----------------------------------------------------------------------
654 ! Do a bilinear interpolation from input mesh defined by xin, yin to output
655 ! mesh defined by xout, yout. Circularity is assumed in the x-direction so
656 ! input x-grid must be in degrees east and must start from Greenwich. When
657 ! extrapolation is necessary in the N-S direction, values will be copied
658 ! from the extreme edge of the input grid. Vectorization is over the
659 ! longitude dimension. Input grid is assumed rectangular. Output grid
660 ! is assumed ragged, i.e. xout is a 2-d mesh.
662 ! Method: Interpolate first in longitude, then in latitude.
664 ! Author: Jim Rosinski
666 !-----------------------------------------------------------------------
667 ! use shr_kind_mod, only: r8 => shr_kind_r8
668 ! use abortutils, only: endrun
669 !-----------------------------------------------------------------------
671 !-----------------------------------------------------------------------
672 integer,parameter :: r8 = selected_real_kind(12) ! 8 byte real
676 integer, intent(in) :: nlondin ! longitude dimension of input grid
677 integer, intent(in) :: nlonin ! number of real longitudes (input)
678 integer, intent(in) :: nlevdin ! vertical dimension of input grid
679 integer, intent(in) :: nlev ! number of vertical levels
680 integer, intent(in) :: nlatin ! number of input latitudes
681 integer, intent(in) :: nlatout ! number of output latitudes
682 integer, intent(in) :: nlondout ! longitude dimension of output grid
683 integer, intent(in) :: nlonout(nlatout) ! number of output longitudes per lat
684 integer, intent(in) :: nlevdout ! vertical dimension of output grid
686 real(r8), intent(in) :: arrin(nlondin,nlevdin,nlatin) ! input array of values to interpolate
687 real(r8), intent(in) :: xin(nlondin) ! input x mesh
688 real(r8), intent(in) :: yin(nlatin) ! input y mesh
689 real(r8), intent(in) :: xout(nlondout,nlatout) ! output x mesh
690 real(r8), intent(in) :: yout(nlatout) ! output y mesh
694 real(r8), intent(out) :: arrout(nlondout,nlevdout,nlatout) ! interpolated array
698 integer :: i, ii, iw, ie, iiprev ! longitude indices
699 integer :: j, jj, js, jn, jjprev ! latitude indices
700 integer :: k ! level index
701 integer :: icount ! number of bad values
703 real(r8) :: extrap ! percent grid non-overlap
704 real(r8) :: dxinwrap ! delta-x on input grid for 2-pi
705 real(r8) :: avgdxin ! avg input delta-x
706 real(r8) :: ratio ! compare dxinwrap to avgdxin
707 real(r8) :: sum ! sum of weights (used for testing)
711 integer :: iim(nlondout) ! interpolation index to the left
712 integer :: iip(nlondout) ! interpolation index to the right
713 integer :: jjm(nlatout) ! interpolation index to the south
714 integer :: jjp(nlatout) ! interpolation index to the north
716 real(r8) :: wgts(nlatout) ! interpolation weight to the north
717 real(r8) :: wgtn(nlatout) ! interpolation weight to the north
718 real(r8) :: wgte(nlondout) ! interpolation weight to the north
719 real(r8) :: wgtw(nlondout) ! interpolation weight to the north
720 real(r8) :: igrid(nlonin) ! interpolation weight to the north
722 character(len=132) :: message
724 ! Check validity of input coordinate arrays: must be monotonically increasing,
725 ! and have a total of at least 2 elements
727 if (nlonin < 2 .or. nlatin < 2) then
728 call wrf_abort ! ('BILIN: Must have at least 2 input points for interpolation')
731 if (xin(1) < 0._r8 .or. xin(nlonin) > 360._r8) then
732 call wrf_abort ! ('BILIN: Input x-grid must be between 0 and 360')
737 if (xin(i) >= xin(i+1)) icount = icount + 1
741 if (yin(j) >= yin(j+1)) icount = icount + 1
745 if (yout(j) >= yout(j+1)) icount = icount + 1
750 if (xout(i,j) >= xout(i+1,j)) icount = icount + 1
755 call wrf_abort ! ('BILIN: Non-monotonic coordinate array(s) found')
758 if (yout(nlatout) <= yin(1) .or. yout(1) >= yin(nlatin)) then
759 call wrf_abort ! ('BILIN: No overlap in y-coordinates')
763 if (xout(1,j) < 0._r8 .or. xout(nlonout(j),j) > 360._r8) then
764 call wrf_abort ! ('BILIN: Output x-grid must be between 0 and 360')
767 if (xout(nlonout(j),j) <= xin(1) .or. &
768 xout(1,j) >= xin(nlonin)) then
769 call wrf_abort ! ('BILIN: No overlap in x-coordinates')
773 ! Initialize index arrays for later checking
780 ! For values which extend beyond N and S boundaries, set weights
781 ! such that values will just be copied.
784 if (yout(js) > yin(1)) exit
792 if (yout(jn) <= yin(nlatin)) exit
799 ! Loop though output indices finding input indices and weights
803 do jj=jjprev,nlatin-1
804 if (yout(j) > yin(jj) .and. yout(j) <= yin(jj+1)) then
807 wgts(j) = (yin(jj+1) - yout(j)) / (yin(jj+1) - yin(jj))
808 wgtn(j) = (yout(j) - yin(jj)) / (yin(jj+1) - yin(jj))
812 call wrf_abort ! ('BILIN: Failed to find interp values')
816 dxinwrap = xin(1) + 360._r8 - xin(nlonin)
818 ! Check for sane dxinwrap values. Allow to differ no more than 10% from avg
820 avgdxin = (xin(nlonin)-xin(1))/(nlonin-1._r8)
821 ratio = dxinwrap/avgdxin
822 if (ratio < 0.9_r8 .or. ratio > 1.1_r8) then
823 write(message,*)'BILIN: Insane dxinwrap value =',dxinwrap,' avg=', avgdxin
824 call wrf_message( trim(message) )
829 ! Do not do on spmd since distributed output grid may be expected to fail this test
831 extrap = 100._r8*((js - 1._r8) + real(nlatout - jn,r8))/nlatout
832 if (extrap > 20._r8) then
833 write(message,*)'BILIN:',extrap,' % of N/S output grid will have to be extrapolated'
834 call wrf_message( trim(message) )
838 ! Check that interp/extrap points have been found for all outputs, and that
839 ! they are reasonable (i.e. within 32-bit roundoff)
843 if (jjm(j) == 0 .or. jjp(j) == 0) icount = icount + 1
844 sum = wgts(j) + wgtn(j)
845 if (sum < 0.99999_r8 .or. sum > 1.00001_r8) icount = icount + 1
846 if (wgts(j) < 0._r8 .or. wgts(j) > 1._r8) icount = icount + 1
847 if (wgtn(j) < 0._r8 .or. wgtn(j) > 1._r8) icount = icount + 1
851 call wrf_abort ! ('BILIN: something bad in latitude indices or weights')
854 ! Do the bilinear interpolation
858 ! Initialize index arrays for later checking
865 ! For values which extend beyond E and W boundaries, set weights such that
866 ! values will be interpolated between E and W edges of input grid.
869 if (xout(iw,j) > xin(1)) exit
872 wgtw(iw) = (xin(1) - xout(iw,j)) /dxinwrap
873 wgte(iw) = (xout(iw,j)+360._r8 - xin(nlonin))/dxinwrap
876 do ie=nlonout(j),1,-1
877 if (xout(ie,j) <= xin(nlonin)) exit
880 wgtw(ie) = (xin(1)+360._r8 - xout(ie,j)) /dxinwrap
881 wgte(ie) = (xout(ie,j) - xin(nlonin))/dxinwrap
884 ! Loop though output indices finding input indices and weights
888 do ii=iiprev,nlonin-1
889 if (xout(i,j) > xin(ii) .and. xout(i,j) <= xin(ii+1)) then
892 wgtw(i) = (xin(ii+1) - xout(i,j)) / (xin(ii+1) - xin(ii))
893 wgte(i) = (xout(i,j) - xin(ii)) / (xin(ii+1) - xin(ii))
897 call wrf_abort ! ('BILIN: Failed to find interp values')
903 if (iim(i) == 0 .or. iip(i) == 0) icount = icount + 1
904 sum = wgtw(i) + wgte(i)
905 if (sum < 0.99999_r8 .or. sum > 1.00001_r8) icount = icount + 1
906 if (wgtw(i) < 0._r8 .or. wgtw(i) > 1._r8) icount = icount + 1
907 if (wgte(i) < 0._r8 .or. wgte(i) > 1._r8) icount = icount + 1
911 write(message,*)'BILIN: j=',j,' Something bad in longitude indices or weights'
912 call wrf_message( trim(message) )
916 ! Do the interpolation, 1st in longitude then latitude
920 igrid(i) = arrin(i,k,jjm(j))*wgts(j) + arrin(i,k,jjp(j))*wgtn(j)
924 arrout(i,k,j) = igrid(iim(i))*wgtw(i) + igrid(iip(i))*wgte(i)
933 subroutine vertinterp(ncol, ncold, nlev, pmid, pout, arrin, arrout)
935 !-----------------------------------------------------------------------
938 ! Vertically interpolate input array to output pressure level
939 ! Copy values at boundaries.
945 !-----------------------------------------------------------------------
949 !------------------------------Arguments--------------------------------
950 integer , intent(in) :: ncol ! column dimension
951 integer , intent(in) :: ncold ! declared column dimension
952 integer , intent(in) :: nlev ! vertical dimension
953 real(r8), intent(in) :: pmid(ncold,nlev) ! input level pressure levels
954 real(r8), intent(in) :: pout ! output pressure level
955 real(r8), intent(in) :: arrin(ncold,nlev) ! input array
956 real(r8), intent(out) :: arrout(ncold) ! output array (interpolated)
957 !--------------------------------------------------------------------------
959 !---------------------------Local variables-----------------------------
960 integer i,k ! indices
961 integer kupper(ncold) ! Level indices for interpolation
962 real(r8) dpu ! upper level pressure difference
963 real(r8) dpl ! lower level pressure difference
964 logical found(ncold) ! true if input levels found
965 logical error ! error flag
966 !-----------------------------------------------------------------
968 ! Initialize index array and logical flags
976 ! Store level indices for interpolation.
977 ! If all indices for this level have been found,
978 ! do the interpolation
982 if ((.not. found(i)) .and. pmid(i,k)<pout .and. pout<=pmid(i,k+1)) then
989 ! If we've fallen through the k=1,nlev-1 loop, we cannot interpolate and
990 ! must extrapolate from the bottom or top data level for at least some
991 ! of the longitude points.
994 if (pout <= pmid(i,1)) then
995 arrout(i) = arrin(i,1)
996 else if (pout >= pmid(i,nlev)) then
997 arrout(i) = arrin(i,nlev)
998 else if (found(i)) then
999 dpu = pout - pmid(i,kupper(i))
1000 dpl = pmid(i,kupper(i)+1) - pout
1001 arrout(i) = (arrin(i,kupper(i) )*dpl + arrin(i,kupper(i)+1)*dpu)/(dpl + dpu)
1010 call wrf_abort ! ('VERTINTERP: ERROR FLAG')
1014 end subroutine vertinterp
1016 subroutine get_timeinterp_factors (cycflag, np1, cdayminus, cdayplus, cday, &
1018 !---------------------------------------------------------------------------
1020 ! Purpose: Determine time interpolation factors (normally for a boundary dataset)
1021 ! for linear interpolation.
1023 ! Method: Assume 365 days per year. Output variable fact1 will be the weight to
1024 ! apply to data at calendar time "cdayminus", and fact2 the weight to apply
1025 ! to data at time "cdayplus". Combining these values will produce a result
1026 ! valid at time "cday". Output arguments fact1 and fact2 will be between
1027 ! 0 and 1, and fact1 + fact2 = 1 to roundoff.
1029 ! Author: Jim Rosinski
1031 !---------------------------------------------------------------------------
1036 logical, intent(in) :: cycflag ! flag indicates whether dataset is being cycled yearly
1038 integer, intent(in) :: np1 ! index points to forward time slice matching cdayplus
1040 real(r8), intent(in) :: cdayminus ! calendar day of rearward time slice
1041 real(r8), intent(in) :: cdayplus ! calendar day of forward time slice
1042 real(r8), intent(in) :: cday ! calenar day to be interpolated to
1043 real(r8), intent(out) :: fact1 ! time interpolation factor to apply to rearward time slice
1044 real(r8), intent(out) :: fact2 ! time interpolation factor to apply to forward time slice
1046 character(len=*), intent(in) :: str ! string to be added to print in case of error (normally the callers name)
1050 real(r8) :: deltat ! time difference (days) between cdayminus and cdayplus
1051 real(r8), parameter :: daysperyear = 365. ! number of days in a year
1053 character(len=132) :: message
1055 ! Initial sanity checks
1057 if (np1 == 1 .and. .not. cycflag) then
1058 call wrf_abort ! ('GETFACTORS:'//str//' cycflag false and forward month index = Jan. not allowed')
1062 call wrf_abort ! ('GETFACTORS:'//str//' input arg np1 must be > 0')
1066 if ((cday < 1.) .or. (cday > (daysperyear+1.))) then
1067 write(message,*) 'GETFACTORS:', str, ' bad cday=',cday
1068 call wrf_message( trim(message) )
1073 write(message,*) 'GETFACTORS:', str, ' bad cday=',cday
1074 call wrf_message( trim(message) )
1079 ! Determine time interpolation factors. Account for December-January
1080 ! interpolation if dataset is being cycled yearly.
1082 if (cycflag .and. np1 == 1) then ! Dec-Jan interpolation
1083 deltat = cdayplus + daysperyear - cdayminus
1084 if (cday > cdayplus) then ! We are in December
1085 fact1 = (cdayplus + daysperyear - cday)/deltat
1086 fact2 = (cday - cdayminus)/deltat
1087 else ! We are in January
1088 fact1 = (cdayplus - cday)/deltat
1089 fact2 = (cday + daysperyear - cdayminus)/deltat
1092 deltat = cdayplus - cdayminus
1093 fact1 = (cdayplus - cday)/deltat
1094 fact2 = (cday - cdayminus)/deltat
1097 if (.not. valid_timeinterp_factors (fact1, fact2)) then
1098 write(message,*) 'GETFACTORS: ', str, ' bad fact1 and/or fact2=', fact1, fact2
1099 call wrf_message( trim(message) )
1104 end subroutine get_timeinterp_factors
1106 logical function valid_timeinterp_factors (fact1, fact2)
1107 !---------------------------------------------------------------------------
1109 ! Purpose: check sanity of time interpolation factors to within 32-bit roundoff
1111 !---------------------------------------------------------------------------
1114 real(r8), intent(in) :: fact1, fact2 ! time interpolation factors
1116 valid_timeinterp_factors = .true.
1118 ! The fact1 .ne. fact1 and fact2 .ne. fact2 comparisons are to detect NaNs.
1119 if (abs(fact1+fact2-1.) > 1.e-6 .or. &
1120 fact1 > 1.000001 .or. fact1 < -1.e-6 .or. &
1121 fact2 > 1.000001 .or. fact2 < -1.e-6 .or. &
1122 fact1 .ne. fact1 .or. fact2 .ne. fact2) then
1124 valid_timeinterp_factors = .false.
1128 end function valid_timeinterp_factors
1130 end module module_interpolate