C NCLFORTSTART c tst subroutine arealinint2dx (mxi,nyi,ngrd,xi,yi,zi,wxi,wyi,zimsg c tst+ ,mcyc,ncyc,mxo,nyo,xo,yo,zo,critpc c tst+ ,debug,ier) c tst implicit none c ! INPUT c tst integer mxi, nyi, ngrd, mxo, nyo, c tst+ mcyc, ncyc, debug, ier c tst double precision zi(mxi,nyi,ngrd), xi(mxi), yi(nyi) c tst double precision wxi(mxi), wyi(nyi), zimsg, critpc c tst double precision xo(mxo) , yo(nyo) c ! OUTPUT c tst double precision zo(mxo,nyo,ngrd) C NCLEND c ! LOCAL c MH: The interface should allocate. c tst double precision xilft(mxi), xirgt(mxi), dxi(mxi) c tst double precision yibot(nyi), yitop(nyi), dyi(nyi) c tst double precision xolft(mxo), xorgt(mxo) c tst double precision fracx(mxi,mxo), fracy(nyi,nyo) c tst double precision ziwrk(mxi,nyi), zowrk(mxo,nyo) c tst double precision yiwrk(nyi), yowrk(nyo) c tst integer indx(2,mxo), indy(2,nyo) c ! interface sets the following c tst ier = 0 c tst ncyc = 0 c tst debug = 0 c tst critpc = 100 ! this may change via attribi]ute c tst do n=1,mxi c tst wxi(n) = 1.0d0 ! always c tst end do c tst ( if wyi is a scalar) c tst do n=1,nyi c tst wyi(n) = 1.0d0 c tst end do c tst call arealinint2da (mxi,nyi,ngrd,xi,yi,zi,wxi,wyi,zimsg c tst+ ,mcyc,ncyc,mxo,nyo,xo,yo,zo,critpc,debug,ier c tst+ ,xilft,xirgt, yibot, yitop, dyi c tst+ ,xolft, xorgt, yiwrk, yowrk c tst+ ,fracx, fracy, ziwrk, zowrk, indx, indy) c tst return c tst end C NCLFORTSTART subroutine arealinint2da(mxi,nyi,ngrd,xi,yi,zi,wxi,wyi,zimsg + ,mcyc,ncyc,mxo,nyo,xo,yo,zo,critpc,debug + ,ier + ,xilft,xirgt, yibot, yitop, dyi + ,xolft, xorgt, yiwrk, yowrk + ,fracx, fracy, ziwrk, zowrk, indx, indy) implicit none c ! INPUT integer mxi, nyi, ngrd, mxo, nyo, + mcyc, ncyc, debug, ier double precision zi(mxi,nyi,ngrd), xi(mxi), yi(nyi) double precision wxi(mxi), wyi(nyi), zimsg, critpc double precision xo(mxo) , yo(nyo) double precision xilft(mxi), xirgt(mxi), dxi(mxi) double precision yibot(nyi), yitop(nyi), dyi(nyi) double precision xolft(mxo), xorgt(mxo) double precision fracx(mxi,mxo), fracy(nyi,nyo) double precision ziwrk(mxi,nyi), zowrk(mxo,nyo) double precision yiwrk(nyi), yowrk(nyo) integer indx(2,mxo), indy(2,nyo) c ! OUTPUT double precision zo(mxo,nyo,ngrd) C NCLEND c ! LOCAL integer ni, mi, ng, no, mo, kmsg, kbox, + nn, mm, niStrt, niLast, miStrt, miLast, + monoxi, monoyi, monoxo, monoyo, + ierx, iery double precision sz, sw, dwf, boxpc c The rather cumbersome code below allows users to input c to input arrays in which the yi/yo coordinates can be c in arbitrary mono order: (a) Both mono {in/de}creasing, c (b) one mono {in/de}creasing and the other {de/in}creasing. ier = 0 c just in case of early termination: initializing returned zo to msg do ng=1,ngrd do no=1,nyo do mo=1,mxo zo(mo,no,ng) = zimsg end do end do end do c check to see if yi is monotonically increasing or decreasing monoyi = 1 if ((yi(2)-yi(1)).lt.0.0d0) monoyi = -1 monoyo = 1 if ((yo(2)-yo(1)).lt.0.0d0) monoyo = -1 monoxi = 1 if ((xi(2)-xi(1)).lt.0.0d0) then monoxi = -1 ier = -2 c print *, "code does not handle monotonically decreasing xi" return end if monoxo = 1 if ((xo(2)-xo(1)).lt.0.0d0) then monoxo = -1 ier = -2 c print *, "code does not handle monotonically decreasing xo" return end if c define area cells: take advantage of the fact that this is c . regular rectilinear grid. The grid spacing may be unequal. c If the 'y' direction is mono decreasing then reorder call areacells (mxi, mxo, xi, xo, mcyc + ,xilft, xirgt, dxi, fracx, indx, debug) c ! reorder or not ? if (monoyi.gt.0) then c ! no reorder necessary do ni=1,nyi yiwrk(ni) = yi(ni) end do else c ! reorder the 'yi' to mono increasing do ni=1,nyi yiwrk(ni) = yi(nyi-ni+1) end do end if if (monoyo.gt.0) then do no=1,nyo yowrk(no) = yo(no) end do else do no=1,nyo yowrk(no) = yo(nyo-no+1) end do end if c ! yiwrk and yowrk are both mono increasing call areacells (nyi, nyo, yiwrk, yowrk, ncyc + ,yibot, yitop, dyi, fracy, indy, debug) if (debug.eq.1) then do mo=1,mxo print *,"indx: ",mo,indx(1,mo),indx(2,mo) end do do no=1,nyo print *,"indy: ",no,indy(1,no),indy(2,no) end do end if c check to make sure that the output grid is lower resolution c . conchkres requires monotonic input c . Return if either the 'xo' or 'yo' is higher c . resolution than the input grid. call conchkres (xi,mxi,xo,mxo,ierx) call conchkres (yiwrk,nyi,yowrk,nyo,iery) if (ierx.ne.0 .or. iery.ne.0) then ier = -5 return end if c for each grid and for each output point (mo,no,ng) c . reverse the order if input was decreasing in 'y' do ng=1,ngrd c ! separate sections/loops for efficiency if (monoyi.gt.0) then c ! no reorddr necessary do ni=1,nyi do mi=1,mxi ziwrk(mi,ni) = zi(mi,ni,ng) end do end do else c ! reorder the 'yi' indices [ note: nn ] do ni=1,nyi nn = nyi-ni+1 do mi=1,mxi ziwrk(mi,ni) = zi(mi,nn,ng) end do end do end if c ! initialize interpolated grid do no=1,nyo do mo=1,mxo zowrk(mo,no) = zimsg end do end do c ! loop over each output point do no=1,nyo do mo=1,mxo c extract the input indices that affect the output grid values. c . indx/indy are the 'pointers' to the sub-area of the c . output grid. miStrt = indx(1,mo) miLast = indx(2,mo) niStrt = indy(1,no) niLast = indy(2,no) if (niStrt.gt.0 .and. miStrt.gt.0) then c compute the weighted sum value for the output grid point kbox = 0 kmsg = 0 sz = 0.0d0 sw = 0.0d0 do nn=niStrt,niLast do mm=miStrt,miLast kbox = kbox+1 c c c if (zi(mm,nn,ng).ne.zimsg) then if (ziwrk(mm,nn).ne.zimsg) then dwf= wxi(mm)*wyi(nn)*fracx(mm,mo)*fracy(nn,no) c c c sz = sz + zi(mm,nn,ng)*dwf sz = sz + ziwrk(mm,nn)*dwf sw = sw + dwf else kmsg = kmsg+1 c critpc=100.0 means all values must be present. Skip out at 1st msg value if (critpc.eq.100d0) go to 10 end if end do end do c boxpc: percent 'good' values boxpc = 100.0d0*(dble(kbox-kmsg)/dble(kbox)) c compute the weighted area value for the output grid point c . only if there were no msg pts. if (sw.gt.0.0d0 .and. boxpc.ge.critpc ) then c c c zo(mo,no,ng) = sz/sw zowrk(mo,no) = sz/sw if (debug.eq.1 .and. ng.eq.1) then print *, mo,no,zowrk(mo,no)," : ",boxpc end if end if 10 continue end if ! if (zi(mi,ni,ng).ne.zimsg ) end do ! end: do mo=1,mxo end do ! end: do no=1,nxo c ! place in return grid: separate for efficiency if (monoyo.gt.0) then c ! no reorder necessary do no=1,nyo do mo=1,mxo zo(mo,no,ng) = zowrk(mo,no) end do end do else c ! reorder the 'y' [ note: nn ] do no=1,nyo nn = nyo-no+1 do mo=1,mxo zo(mo,no,ng) = zowrk(mo,nn) end do end do end if end do ! end: do ng=1,ngrd return end subroutine areacells (nxi, nxo, xi, xo, icyc + ,xilft, xirgt, dxi, fracx, indx, debug) c This was originally written for "x" but it works for c . *any* mononotonically increasing 1d array c . lft<==>bot , rgt<==>top , dx<==>dy , fracx<==>fracy , indx<==>indy c . nxi<==>nyi , nxo<==>nyo implicit none integer nxi, nxo, icyc, debug double precision xi(nxi), xilft(nxi), xirgt(nxi), dxi(nxi) double precision xo(nxo), xolft(nxo), xorgt(nxo) integer indx(2,nxo) double precision fracx(nxi,nxo) integer ni, no c left and right cell boundaries for input and output do ni=2,nxi-1 xilft(ni) = 0.5d0*(xi(ni-1)+xi(ni)) xirgt(ni) = 0.5d0*(xi(ni+1)+xi(ni)) end do do no=2,nxo-1 xolft(no) = 0.5d0*(xo(no-1)+xo(no)) xorgt(no) = 0.5d0*(xo(no+1)+xo(no)) end do c left/right boundaries xirgt(1) = 0.5d0*(xi(2) +xi(1)) xorgt(1) = 0.5d0*(xo(2) +xo(1)) xilft(nxi) = 0.5d0*(xi(nxi)+xi(nxi-1)) xolft(nxo) = 0.5d0*(xo(nxo)+xo(nxo-1)) c non-periodic [icyc=0] or periodic [icyc=1] left/right boundaries if (icyc.eq.0) then c half width ends xilft(1) = xi(1) xolft(1) = xo(1) xirgt(nxi) = xi(nxi) xorgt(nxo) = xo(nxo) else c full width ends xilft(1) = xi(1) - 0.5d0*(xi(2)-xi(1)) xolft(1) = xo(1) - 0.5d0*(xo(2)-xo(1)) xirgt(nxi) = xi(nxi) + 0.5d0*(xi(nxi)-xi(nxi-1)) xorgt(nxo) = xo(nxo) + 0.5d0*(xo(nxo)-xo(nxo-1)) end if c nominal (full width) dx do ni=1,nxi dxi(ni) = xirgt(ni)-xilft(ni) end do c for each output point: c . find portion of xi cell boundaries c . within each output [xo] cell boundary c do no=1,nxo indx(1,no) = 0 indx(2,no) = 0 c Find all xi points between the xo cell coundaries c NCL would use the "ind" function for the "i-1,nxi" loop c . isave = ind(xi.ge.xolft(n) .and. xi.le.xorgt(n)) c f90 could use the "where" construct do ni=1,nxi fracx(ni,no) = 0.0d0 c skip if outside cell boundaries: xi < xolft xi > xorgt c . xi < xolft go to next iteration c . xi > xorgt go to next output point if (xi(ni).lt. xolft(no)) go to 10 if (xi(ni).gt. xorgt(no)) go to 20 c xi must be within xo cell boundaries: xolft <= xi <= xorgt if (xilft(ni).ge.xolft(no) .and. xirgt(ni).le.xorgt(no))then c xi cell boundaries totally within xo cell boundaries c xolft [xilft xi xirgt] xorgt c [------- dx --------] xorgt fracx(ni,no) = 1.0d0 elseif(xilft(ni).lt.xolft(no) .and. + xirgt(ni).ge.xolft(no) .and. + xi(ni).ge.xolft(no) ) then c xolft xi xorgt c left cell boundary overlap: xilft xirgt c [---- dx------] fracx(ni,no) = (xirgt(ni)-xolft(no))/dxi(ni) elseif(xirgt(ni).gt.xorgt(no) .and. + xilft(ni).lt.xorgt(no) .and. + xi(ni).le.xorgt(no) ) then c xolft xi xorgt c right cell boundary overlap: xilft xirgt c [------ dx -------] fracx(ni,no) = (xorgt(no)-xilft(ni))/dxi(ni) end if c for efficiency when computing the values, c . save the 'start' and 'end' subscripts if (indx(1,no).eq.0) indx(1,no) = ni indx(2,no) = ni 10 continue ! if (xi(ni).lt. xolft(no)) go to 10 end do ! end "ni" 20 continue ! if (xi(ni).gt. xorgt(no)) go to 20 end do ! end "no" return end subroutine conchkres (zi,nzi,zo,nzo,ier) implicit none integer nzi, nzo, ier double precision zi(nzi), zo(nzo) integer n double precision dzimin, dzomin ier = 0 dzimin = 1d20 do n=2,nzi if (abs(zi(n)-zi(n-1)) .lt. dzimin) dzimin = abs(zi(n)-zi(n-1)) end do dzomin = 1d20 do n=2,nzo if (abs(zo(n)-zo(n-1)) .lt. dzomin) dzomin = abs(zo(n)-zo(n-1)) end do if (dzomin.lt.dzimin) ier = 5 return end