Path: blob/devel/elmerice/Solvers/Grid2DInterpolator.F90
3203 views
!/*****************************************************************************/1! *2! * Elmer/Ice, a glaciological add-on to Elmer3! * http://elmerice.elmerfem.org4! *5! *6! * This program is free software; you can redistribute it and/or7! * modify it under the terms of the GNU General Public License8! * as published by the Free Software Foundation; either version 29! * of the License, or (at your option) any later version.10! *11! * This program is distributed in the hope that it will be useful,12! * but WITHOUT ANY WARRANTY; without even the implied warranty of13! * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14! * GNU General Public License for more details.15! *16! * You should have received a copy of the GNU General Public License17! * along with this program (in file fem/GPL-2); if not, write to the18! * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,19! * Boston, MA 02110-1301, USA.20! *21! *****************************************************************************/22! ******************************************************************************23! *24! * Authors:25! * Email:26! * Web: http://elmerice.elmerfem.org27! *28! * Original Date:29! *30! *****************************************************************************31!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!32!33! Interpolate data given on a regular 2D regular grid in an ASCII file (x y Value)34! in the mesh nodes using bilinear interpolation35! The data are ordered such that36! x1 y1 val1137! x2 y1 val2138! ...39! xn y1 valn140! x1 y2 val1241! ...42! xn yn valnn43!44! The grid is described by giving:45! (x0, y0) the left-bottom corner coordinate46! (lx, ly) the x and y lengths of the covered domain47! (Nx, Ny) the number of cells in x and y directions48! No data are given by -9999 with a tolerance of 0.00149! These can be over-ridden in the sif by 'no data' and 'no data tol'50!51!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!52SUBROUTINE Grid2DInterpolator( Model,Solver,dt,TransientSimulation )5354USE DefUtils5556IMPLICIT NONE57TYPE(Solver_t), TARGET :: Solver58TYPE(Model_t) :: Model59REAL(KIND=dp) :: dt60LOGICAL :: TransientSimulation6162TYPE(ValueList_t), POINTER :: Params63TYPE(Variable_t), POINTER :: Var64REAL(KIND=dp), POINTER :: Values(:)65INTEGER, POINTER :: Perm(:)6667REAL(KIND=DP) :: Rmin, Rmax68REAL(KIND=DP) :: x, y, z, x0, y0, lx, ly, dx, dy69REAL(KIND=DP), ALLOCATABLE :: xb(:), yb(:), zb(:), xbaux(:), ybaux(:), zbaux(:)70REAL(KIND=dp) :: noDataVal, noDataTol, posTol71REAL(KIND=dp), PARAMETER :: noDataValDefault = -9999.0, noDataTolDefault = 0.001, posTolDefault= 1.0D-067273INTEGER,parameter :: io=2074INTEGER :: ok, Nx, Ny, Nb, Nbaux, OutNode75INTEGER :: i, j, k, l, kmin, NoVar7677CHARACTER(LEN=MAX_NAME_LEN) :: VariableName, DataF78CHARACTER(LEN=MAX_NAME_LEN) :: Name, FName, ParaName79CHARACTER(LEN=MAX_NAME_LEN), PARAMETER :: SolverName='Grid2DInterpolator'8081LOGICAL :: GotVar, Found, InvertOrder, FillIn, UnFoundFatal=.TRUE.8283NULLIFY(Params,Var,Values,Perm)8485Params => GetSolverParams()8687! Read variable to initialize and Data88NoVar=089GotVar=.True.9091DO WHILE(GotVar)92NoVar = NoVar + 193WRITE (Name,'(A,I0)') 'Variable ',NoVar9495VariableName = ListGetString( Params, TRIM(Name), GotVar )96IF (.NOT.GotVar) EXIT9798Var => VariableGet(Model % Mesh % Variables, VariableName,UnFoundFatal=UnFoundFatal )99Values => Var % Values100Perm => Var % Perm101102WRITE (FName,'(A,I0,A)') 'Variable ',NoVar,' Data File'103DataF = ListGetString( Params, TRIM(FName), Found, UnFoundFatal )104105WRITE (ParaName,'(A,I0,A)') 'Variable ',NoVar,' x0'106x0 = ListGetConstReal( Params, TRIM(ParaName), Found,UnFoundFatal=UnFoundFatal)107108WRITE (ParaName,'(A,I0,A)') 'Variable ',NoVar,' y0'109y0 = ListGetConstReal( Params, TRIM(ParaName), Found,UnFoundFatal=UnFoundFatal )110111WRITE (ParaName,'(A,I0,A)') 'Variable ',NoVar,' lx'112lx = ListGetConstReal( Params, TRIM(ParaName), Found,UnFoundFatal=UnFoundFatal )113114WRITE (ParaName,'(A,I0,A)') 'Variable ',NoVar,' ly'115ly = ListGetConstReal( Params, TRIM(ParaName), Found,UnFoundFatal=UnFoundFatal )116117WRITE (ParaName,'(A,I0,A)') 'Variable ',NoVar,' Nx'118Nx = ListGetInteger( Params, TRIM(ParaName), Found ,UnFoundFatal=UnFoundFatal)119120WRITE (ParaName,'(A,I0,A)') 'Variable ',NoVar,' Ny'121Ny = ListGetInteger( Params, TRIM(ParaName), Found ,UnFoundFatal=UnFoundFatal)122123WRITE (ParaName,'(A,I0,A)') 'Variable ',NoVar,' Invert'124InvertOrder = GetLogical( Params, TRIM(ParaName), Found )125IF (.NOT.Found) THEN126InvertOrder = .FALSE.127END IF128IF (InvertOrder) THEN129WRITE(message,'(A,A,I0)')'Inverting order (row major) for variable ', 'Variable ',NoVar130CALL INFO(Trim(SolverName),Trim(message),Level=1)131END IF132133WRITE (ParaName,'(A,I0,A)') 'Variable ',NoVar,' Fill'134FillIn = GetLogical( Params, TRIM(ParaName), Found )135IF (.NOT.Found) THEN136FillIn = .FALSE.137END IF138IF (FillIn) THEN139WRITE(message,'(A,A,I0)')'Filling empty entries for ', 'Variable ',NoVar140CALL INFO(Trim(SolverName),Trim(message),Level=1)141END IF142143WRITE (ParaName,'(A,I0,A)') 'Variable ',NoVar,' no data'144noDataVal = ListGetConstReal( Params, TRIM(ParaName), Found )145IF (.NOT.Found) then146noDataVal = noDataValDefault147WRITE(message,'(A,A,A,e14.8)')'Keyword <',Trim(ParaName), &148'> not found, using default ',noDataValDefault149CALL INFO(SolverName, Message, Level=3)150END IF151152WRITE (ParaName,'(A,I0,A)') 'Variable ',NoVar,' no data tol'153noDataTol = ListGetConstReal( Params, TRIM(ParaName), Found )154IF (.NOT.Found) then155noDataTol = noDataTolDefault156WRITE(message,'(A,A,A,e14.8)')'Keyword <',Trim(ParaName), &157'> not found, using default ',noDataTolDefault158CALL INFO(SolverName, Message, Level=3)159END IF160161WRITE (ParaName,'(A,I0,A)') 'Variable ',NoVar,' position tol'162posTol = ListGetConstReal( Params, TRIM(ParaName), Found )163IF (.NOT.Found) then164posTol = posTolDefault165WRITE(message,'(A,A,A,e14.8)')'Keyword <',Trim(ParaName), &166'> not found, using default ',posTolDefault167CALL INFO(SolverName, Message, Level=3)168END IF169170OPEN(unit = io, file = TRIM(DataF), status = 'old',iostat = ok)171172IF (ok /= 0) THEN173WRITE(message,'(A,A)') 'Unable to open file ',TRIM(DataF)174CALL FATAL(Trim(SolverName),Trim(message))175END IF176177Nb = Nx*Ny178179ALLOCATE(xb(Nb), yb(Nb), zb(Nb), xbaux(Nb), ybaux(Nb), zbaux(Nb))180181! read data182DO i = 1, Nb183READ(io,*,iostat = ok, end=100) xbaux(i), ybaux(i), zbaux(i)184END DO185100 Nbaux = Nb - i186IF (Nbaux > 0) THEN187WRITE(message,'(I0,A,I0,A,A)') Nbaux,' out of ',Nb,' datasets in file ', TRIM(DataF)188CALL INFO(Trim(SolverName),Trim(message))189END IF190CLOSE(io)191192! Make some verifications and - in case - manipulation193!on the DEM structure194dx = lx / (Nx-1.0)195dy = ly / (Ny-1.0)196k = 0197l = 0198IF (.NOT.InvertOrder) THEN199DO j = 1, Ny200y = y0 + dy*(j-1)201DO i = 1, Nx202k = k + 1203x = x0 + dx*(i-1)204IF (.NOT.FillIn) THEN205xb(k) = xbaux(k)206yb(k) = ybaux(k)207zb(k) = zbaux(k)208IF ((ABS(x-xbaux(k))>posTol*dx).OR.(ABS(y-ybaux(k))>posTol*dy)) THEN209210WRITE(Message,'(A,A)')'Structure of the DEM is not conforming to what is given in the sif for ',TRIM(FName)211CALL INFO(SolverName, Message, Level=1)212WRITE(Message,'(A,i4,A,i4,A,e14.8,2x,e14.8,A,e14.8,2x,e14.8,A)') &213'Variable', NoVar, ': Found that point ',k,&214' coordinate is (',xbaux(k),ybaux(k),&215'), whereas it should be (',x,y,')'216CALL FATAL(SolverName, Message)217END IF218ELSE219IF ((ABS(x-xbaux(l+1))>posTol*dx).OR.(ABS(y-ybaux(l+1))>posTol*dy)) THEN220xb(k) = x221yb(k) = y222zb(k) = noDataVal ! setting to NaN223ELSE224l=l+1225xb(k) = xbaux(l)226yb(k) = ybaux(l)227zb(k) = zbaux(l)228END IF229END IF230END DO231END DO232ELSE ! inverse order233DO i = 1, Nx234x = x0 + dx*(i-1)235DO j = 1, Ny236k = k + 1237y = y0 + dy*(j-1)238239IF (.NOT.FillIn) THEN240xb((j-1)*Nx + i) = xbaux(k)241yb((j-1)*Nx + i) = ybaux(k)242zb((j-1)*Nx + i) = zbaux(k)243IF ((ABS(x-xb((j-1)*Nx + i))>posTol*dx).OR.(ABS(y-yb((j-1)*Nx + i))>posTol*dy)) THEN244245WRITE(Message,'(A,A)')'Structure of the DEM is not conforming to what is given in the sif for ',TRIM(FName)246CALL INFO(SolverName, Message, Level=1)247WRITE(Message,'(A,i4,A,i4,A,e14.8,2x,e14.8,A,e14.8,2x,e14.8,A)') &248'Variable', NoVar, ':Found that point ',k,&249' coordinate is (',xb((j-1)*Nx),yb((j-1)*Nx + i),'),&250whereas 3 it should be (',x,y,')'251CALL FATAL(SolverName, Message)252END IF253ELSE254IF ((ABS(x-xbaux(l+1))>posTol*dx).OR.(ABS(y-ybaux(l+1))>posTol*dy)) THEN255xb((j-1)*Nx + i) = x256yb((j-1)*Nx + i) = y257zb((j-1)*Nx + i) = noDataVal ! setting to NaN258ELSE259l=l+1260xb((j-1)*Nx + i) = xbaux(l)261yb((j-1)*Nx + i) = ybaux(l)262zb((j-1)*Nx + i) = zbaux(l)263END IF264END IF265266END DO267END DO268END IF269270OutNode = 0271Rmax = 0.0272DO i=1,Model % Mesh % NumberOfNodes273x = Model % Mesh % Nodes % x(i)274y = Model % Mesh % Nodes % y(i)275Rmin = 0.0276CALL InterpolateDEM(x,y,xb,yb,zb,Nx,Ny,x0,y0,lx,ly,Rmin,z,noDataVal,noDataTol)277if ( perm(i) .eq. 0 ) CYCLE278Values(Perm(i)) = z279IF (Rmin > 0.0) THEN280OutNode = OutNode + 1281IF (Rmin > Rmax) Rmax = Rmin282END IF283END DO284285! Give information on the number of Nodes which are outside of the286! DEM domain287IF (OutNode > 0) THEN288WRITE( Message, '(I0,A,A)' )OutNode,' nodes where found outside of &289the DEM domain in ',TRIM(DataF)290CALL Info( TRIM(SolverName), Message, Level=3 )291WRITE( Message, '(A,e14.8)' )'The farthest DEM point used to evaluate &292the nodal value was: ', Rmax293CALL Info( TRIM(SolverName), Message, Level=3 )294END IF295296DEALLOCATE(xb, yb, zb, xbaux, ybaux, zbaux)297END DO298299CALL INFO(Trim(SolverName), '----------ALL DONE----------',Level=5)300301END SUBROUTINE Grid2DInterpolator302303304!!!!!!!!!!!!!!!!!!!305! Subroutine InterpolateDEM306!!------------------------------------------------------------------------------!!307SUBROUTINE InterpolateDEM (x, y, xb, yb, zb, Nbx, Nby, xb0, yb0, lbx, lby, Rmin, zbed, noDataVal, noDataTol)308USE DefUtils309IMPLICIT NONE310REAL(KIND=dp),INTENT(IN) :: noDataVal, noDataTol311INTEGER :: imin, Npt, t312INTEGER :: NMAX, i, j, Nb, Nbx, Nby, ib, ix, iy313REAL(KIND=dp) :: x, y, zbed, xb0, yb0, x1, x2, y1, y2, zi(2,2)314REAL(KIND=dp) :: R, Rmin, lbx, lby, dbx, dby315REAL(KIND=dp) :: xb(Nbx*Nby), yb(Nbx*Nby), zb(Nbx*Nby)316317! Find zbed for that point from the Bedrock MNT318dbx = lbx / (Nbx-1.0)319dby = lby / (Nby-1.0)320Nb = Nbx*Nby321322ix = INT((x-xb0)/dbx)+1323iy = INT((y-yb0)/dby)+1324ib = Nbx * (iy - 1) + ix325326! if we are already at the end of the domain then collapse the 2 by 2 interpolation327! square to just 2 points at the end of the domain (else we get interpolation involving328! points at the beginning of the domain). This comment refers to the x direction.329IF (MOD(ib,Nbx) .eq. 0.0) THEN330zi(2,1) = noDataVal331zi(2,2) = noDataVal332ELSE333IF ( (ib+1).gt.size(zb) ) THEN334zi(2,1) = noDataVal335ELSE336zi(2,1) = zb(ib+1)337END IF338IF ( (ib+Nbx+1).gt.size(zb) ) THEN339zi(2,2) = noDataVal340ELSE341zi(2,2) = zb(ib + Nbx + 1)342END IF343END IF344345x1 = xb(ib)346IF ( (ib+1).gt.size(xb) ) THEN347x2 = noDataVal348ELSE349x2 = xb(ib+1)350END IF351352y1 = yb(ib)353IF ( (ib+Nbx).gt.size(yb) ) THEN354y2 = noDataVal355ELSE356y2 = yb(ib + Nbx)357END IF358359IF ( (ib).gt.size(zb) ) THEN360zi(1,1) = noDataVal361ELSE362zi(1,1) = zb(ib)363END IF364IF ( (ib+Nbx).gt.size(zb) ) THEN365zi(1,2) = noDataVal366ELSE367zi(1,2) = zb(ib + Nbx)368END IF369370IF ( (isNoData(zi(1,1))).OR. &371(isNoData(zi(1,2))).OR. &372(isNoData(zi(2,1))).OR. &373(isNoData(zi(2,2))) ) THEN374375IF ( (isNoData(zi(1,1))).AND. &376(isNoData(zi(1,2))).AND. &377(isNoData(zi(2,1))).AND. &378(isNoData(zi(2,2))) ) THEN379380! Find the nearest point available if all neighbouring points have noData381Rmin = 9999999.0382DO i=1, Nb383IF (.NOT.isNoData(zb(i))) THEN384R = SQRT((x-xb(i))**2.0+(y-yb(i))**2.0)385IF (R<Rmin) THEN386Rmin = R387imin = i388END IF389END IF390END DO391zbed = zb(imin)392393ELSE394! Mean value over the available data if only some points have noData395zbed = 0.0396Npt = 0397DO i=1, 2398DO J=1, 2399IF (.NOT. isNoData(zi(i,j))) THEN400zbed = zbed + zi(i,j)401Npt = Npt + 1402END IF403END DO404END DO405zbed = zbed / Npt406END IF407ELSE408! linear interpolation is only carried out if all 4 neighbouring points have data.409zbed = (zi(1,1)*(x2-x)*(y2-y)+zi(2,1)*(x-x1)*(y2-y)+zi(1,2)*(x2-x)*(y-y1)+zi(2,2)*(x-x1)*(y-y1))/(dbx*dby)410END IF411412413CONTAINS414415LOGICAL FUNCTION isNoData(val)416417IMPLICIT NONE418REAL(KIND=dp),INTENT(IN) :: val419420IF ((val .GT. noDataVal-noDataTol) .AND. (val .LT. noDataVal+noDataTol)) THEN421isNoData = .TRUE.422ELSE423isNoData = .FALSE.424END IF425426RETURN427428END FUNCTION isNoData429430END SUBROUTINE InterpolateDEM431432433434