blob: 9366870d133513fb62b9b42f4adccdf90fe31d86 [file] [log] [blame]
c
c gaussInterp routine -- Gaussian weighted smoothing in lat, lon, and time
c
c Based on Ed Armstrong's routines. Designed to be called from python using f2py.
c
c
c Gaussian weighting = exp( vfactor * (((x - x0)/sx)^2 + ((y - y0)/sy)^2 + ((t - t0)/st)^2 ))
c
c where deltas are distances in lat, lon and time and sx, sy, st are one e-folding sigmas.
c
c Cutoffs for neighbors allowed in the interpolation are set by distance in lat/lon (see wlat/wlon);
c for time all epochs are included.
subroutine gaussInterp_f(var, mask,
& time, lat, lon,
& outlat, outlon,
& wlat, wlon,
& slat, slon, stime,
& vfactor,
& missingValue,
& verbose,
& vinterp, vweight, status,
& ntime, nlat, nlon, noutlat, noutlon)
implicit none
integer*4 ntime, nlat, nlon
c ! prepared 3D array of variable data over time, lon, & lat
real*4 var(ntime, nlat, nlon)
c ! variable to be interpolated, over ntime epochs
integer*1 mask(ntime, nlat, nlon)
c ! pixel quality mask
integer*4 time(ntime)
c ! time epochs to gaussian-interpolate over
real*4 lat(nlat)
! latitude corrdinate vector
real*4 lon(nlon)
! longitude corrdinate vector
cf2py intent(in) var, mask, time, lat, lon !! annotations for f2py processor
integer*4 noutlat, noutlon
real*4 outlat(noutlat), outlon(noutlon)
c ! lat/lon grid to interpolate to
cf2py intent(in) outlat, outlon
real*4 wlat, wlon
c ! window of lat/lon neighbors to gaussian weight, expressed in delta lat (degrees)
c ! if an integer, then it is the number of neighbors on EACH side
cf2py intent(in) wlat, wlon
real*4 slat, slon, stime
c ! sigma for gaussian downweighting with distance in lat, lon, & time
cf2py intent(in) slat, slon, stime
real*4 vfactor
c ! factor in front of gaussian expression
real*4 missingValue
c ! value to mark missing values in interp result
integer*4 verbose
c ! integer to set verbosity level
cf2py intent(in) vfactor, missingValue
real*4 vinterp(noutlat, noutlon)
c ! interpolated variable using gaussians, missing values not counted
real*4 vweight(noutlat, noutlon)
c ! weight of values interpolated (can be zero), if so should become missing value
integer*4 status
c ! negative status indicates error
cf2py intent(out) vinterp, vweight, status
integer*4 clamp
integer*4 imin, imax, jmin, jmax, itmp
integer*4 iin, jin, kin
integer*4 iMidTime
integer*4 i, j, iwlat, iwlon
real*4 wlat2, wlon2, lat1, lon1, dlat, dlon, fac
real*4 varmin, varmax, val
real*8 midTime
logical*1 nLatNeighbors, nLonNeighbors
write(6, *) 'Echoing inputs ...'
write(6, *) 'ntime, nlat, nlon:', ntime, nlat, nlon
write(6, *) 'noutlat, noutlon:', noutlat, noutlon
write(6, *) 'wlat, wlon:', wlat, wlon
write(6, *) 'slat, slon, stime:', slat, slon, stime
write(6, *) 'vfactor:', vfactor
write(6, *) 'missingValue:', missingValue
status = 0
if (int(wlat) .eq. wlat) then
iwlat = int(wlat)
nLatNeighbors = .TRUE.
write(6, *) 'Using', iwlat,
& 'neighbors on each side in the lat direction.'
else
nLatNeighbors = .FALSE.
end if
if (int(wlon) .eq. wlon) then
iwlon = int(wlon)
nLonNeighbors = .TRUE.
write(6, *) 'Using', iwlon,
& 'neighbors on each side in the lon direction.'
else
nLonNeighbors = .FALSE.
end if
wlat2 = wlat / 2.
wlon2 = wlon / 2.
lat1 = lat(1)
lon1 = lon(1)
dlat = lat(2) - lat(1)
dlon = lon(2) - lon(1)
iMidTime = int(ntime/2 + 0.5)
midTime = time(iMidTime)
if (verbose .gt. 3) then
write(6, *) 'time:', time
write(6, *) 'lat:', lat
write(6, *) 'lon:', lon
write(6, *) 'outlat:', outlat
write(6, *) 'outlon:', outlon
c write(6, *) 'mask(iMidTime):', mask(iMidTime,:,:)
write(6, *) 'var(iMidTime):', var(iMidTime,:,:)
end if
do i = 1, noutlat
if (verbose .gt. 1) write(6, *) outlat(i)
do j = 1, noutlon
vinterp(i,j) = 0.0
vweight(i,j) = 0.0
if (verbose .gt. 3) then
write(6, *) '(i,j) = ', i, j
write(6, *) '(outlat,outlon) = ', outlat(i), outlon(j)
end if
if (nLatNeighbors) then
imin = clamp(i - iwlat, 1, nlat)
imax = clamp(i + iwlat, 1, nlat)
else
imin = clamp(int((outlat(i) - wlat2 - lat1)/dlat + 0.5),
& 1, nlat)
imax = clamp(int((outlat(i) + wlat2 - lat1)/dlat + 0.5),
& 1, nlat)
end if
if (imin .gt. imax) then
c ! input latitudes descending, so swap
itmp = imin
imin = imax
imax = itmp
end if
if (nLonNeighbors) then
jmin = clamp(j - iwlon, 1, nlon)
jmax = clamp(j + iwlon, 1, nlon)
else
jmin = clamp(int((outlon(j) - wlon2 - lon1)/dlon + 0.5),
& 1, nlon)
jmax = clamp(int((outlon(j) + wlon2 - lon1)/dlon + 0.5),
& 1, nlon)
end if
if (verbose .gt. 2) then
write(6, *) '(imin,imax,minlat,maxlat) = ',
& imin, imax, lat(imin), lat(imax)
write(6, *) '(jmin,jmax,minlon,maxlon) = ',
& jmin, jmax, lon(jmin), lon(jmax)
end if
if (verbose .gt. 4 .and. i .eq. noutlat/2
& .and. j .eq. noutlon/2) then
write(6, *) 'Echoing factors ...'
end if
do kin = 1, ntime
varmin = 0.
varmax = 0.
do iin = imin, imax
do jin = jmin, jmax
if (mask(kin,iin,jin) .eq. 0) then
fac = exp( vfactor *
& (((outlat(i) - lat(iin))/slat)**2
& + ((outlon(j) - lon(jin))/slon)**2
& + ((midTime - time(kin))/stime)**2))
val = var(kin,iin,jin)
if (verbose .gt. 4 .and. i .eq. noutlat/2
& .and. j .eq. noutlon/2) then
write(6, *) kin, iin, jin, time(kin),
& lat(iin), lon(jin), val, fac, val*fac
end if
vinterp(i,j) = vinterp(i,j) + val * fac
vweight(i,j) = vweight(i,j) + fac
if (verbose .gt. 3) then
varmin = min(varmin, val)
varmax = max(varmax, val)
end if
end if
end do
end do
if (verbose .gt. 3) then
write(6, *) '(itime, varmin, varmax) = ',
& kin, varmin, varmax
end if
end do
if (vweight(i,j).ne. 0.0) then
vinterp(i,j) = vinterp(i,j) / vweight(i,j)
else
vinterp(i,j) = missingValue
end if
end do
end do
return
end
integer*4 function clamp(i, n, m)
integer*4 i, n, m
clamp = i
if (i .lt. n) clamp = n
if (i .gt. m) clamp = m
end