!! Copyright (C) Stichting Deltares, 2005-2017.
!!
!! This file is part of iMOD.
!!
!! This program is free software: you can redistribute it and/or modify
!! it under the terms of the GNU General Public License as published by
!! the Free Software Foundation, either version 3 of the License, or
!! (at your option) any later version.
!!
!! This program is distributed in the hope that it will be useful,
!! but WITHOUT ANY WARRANTY; 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 General Public License
!! along with this program. If not, see .
!!
!! Contact: imod.support@deltares.nl
!! Stichting Deltares
!! P.O. Box 177
!! 2600 MH Delft, The Netherlands.
MODULE IMOD_UTL
USE IMOD_IDF_PAR
REAL(KIND=8),POINTER,DIMENSION(:) :: XA,YA,XA_DUMMY,YA_DUMMY
REAL(KIND=8),POINTER,DIMENSION(:) :: ZA,FA,LN,ZA_DUMMY,FA_DUMMY,LN_DUMMY
INTEGER,POINTER,DIMENSION(:) :: CA,RA,CA_DUMMY,RA_DUMMY
REAL(KIND=8) :: XBEGIN,YBEGIN,A,B
INTEGER :: IHOR,IVER
INTEGER,PARAMETER :: NOS=3
INTEGER, SAVE :: OS = 1 !## operating system 1=dos,2=linux,3=unix
CHARACTER(LEN=20),DIMENSION(NOS),SAVE :: OSN
LOGICAL,PARAMETER :: LPWT=.TRUE. !## FALSE=USE OLD PWT PACKAGE, TRUE=USE NEW ONE
INTEGER,PARAMETER,PRIVATE :: MAXFILES=9999 !500
INTEGER,PARAMETER :: ICF = 1 ! Intel compiler: ICF = 1
INTEGER,SAVE :: IUOUT
INTEGER,DIMENSION(2),SAVE :: IFLAG
REAL(KIND=8),PARAMETER :: MSWPMV=0.0D0 !## add meter to surface level urban area
character(len=1024), parameter :: licfile = 'I_accepted_v4_2.txt'
integer, parameter :: nlic = 33
character(len=79), dimension(nlic) :: lic
integer, parameter :: nhdr = 40
character(len=79), dimension(nhdr) :: hdr
! 1234567890123456789012345678901234567890123456789012345678901234567890123456789
data hdr/'===============================================================================',&!01
'iMODFLOW Version 4_2, October 2017 ',&!02
' ',&!03
'Copyright (C) Stichting Deltares, 2005-2017. ',&!04
' ',&!05
'This Deltares-software executable is part of iMOD. iMOD is Deltares-software; ',&!06
'the source code of iMOD is also available as free open source software at ',&!07
'oss.deltares.nl. You may use the Deltares-software executables of iMOD without ',&!08
'any remuneration to be paid to Deltares if you accepted the iMOD Software ',&!09
'License Agreement (iMOD License) which is offered to you as a PDF-file; you ',&!10
'should have received a copy of this PDF-file with this Deltares-software ',&!01
'executable. If not, see ',&!02
'http://oss.deltares.nl/web/iMOD/iMOD_Software_License_Agreement. ',&!03
'Please go to the PDF-file of the iMOD License, read it and decide whether you ',&!04
'want or do not want to accept the iMOD License. ',&!05
' ',&!06
'According to the file "I_accepted_v4_2.txt" on your computer you accepted the ',&!07
'terms and conditions of the iMOD license; WARNING: IF IT WAS NOT YOU OR THE ',&!08
'LEGAL ENTITY ON WHOSE BEHALF YOU INTENT TO USE THE IMOD-EXECUTABLE, THAT ',&!09
'ACCEPTED THE TERMS AND CONDITIONS OF THE iMOD LICENSE YOU ARE NOT ENTITLED TO ',&!10
'USE THIS DELTARES-EXECUTABLE OF IMOD. In this case your use of this ',&!01
'Deltares-executable of the iMOD-software is prohibited and illegal: abort the ',&!02
'use of this Deltares-executable immediately and refrain from using the ',&!03
'Deltares-executables of iMOD. To make use of the Deltares-executables of iMOD ',&!04
'please make sure to accept the terms and conditions or have it lawfully ',&!05
'accepted by the legal entity on whose behalf you intent to use the ',&!06
'iMOD-executable byre-invoking the "I accept"-procedure; to re-invoke the ',&!07
'"I accept"-procedure abort the use of this Deltares-executable of iMOD, delete ',&!08
'the file "I_accepted_v4_2.txt", and invoke this Deltares-executable of iMOD ',&!09
'again. ',&!10
' ',&!01
'The iMOD software is distributed in the hope that it will be useful, but ',&!02
'WITHOUT ANY GUARANTEE OR (IMPLIED) WARRANTY. Any use of the ',&!03
'Deltares-executables of the iMOD-software is for your own risk. See the iMOD ',&!04
'License for more details. ',&!05
' ',&!06
'For more info, please contact: Stichting Deltares, P.O. Box 177, 2600 MH Delft,',&!07
'The Netherlands. Email: imod.support@deltares.nl. ',&!08
'===============================================================================',&!09
' '/ !10
! 1234567890123456789012345678901234567890123456789012345678901234567890123456789
data lic/'===============================================================================',&!01
'Copyright (C) Stichting Deltares, 2005-2017. ',&!02
' ',&!03
'This Deltares-software executable is part of iMOD. iMOD is Deltares-software; ',&!04
'the source code of iMOD is also available as free open source software at ',&!05
'oss.deltares.nl. You may use the Deltares-software executables of iMOD without ',&!06
'any remuneration to be paid to Deltares if you accepted the iMOD Software ',&!07
'License Agreement (iMOD License) which is offered to you as a PDF-file; you ',&!08
'should have received a copy of this PDF-file with this Deltares-software ',&!09
'executable. If not, see ',&!10
'http://oss.deltares.nl/web/iMOD/iMOD_Software_License_Agreement. ' ,&!01
'Please go to the PDF-file of the iMOD License, read it and decide whether you ',&!02
'want or do not want to accept the iMOD License. ',&!03
' ',&!04
'If you accept the iMOD License, please enter "Y" or "y" below this text and hit',&!05
'the Enter-key. ',&!06
' ',&!07
'If you do not accept the iMOD License, please do NOT enter "Y" or "y" below ',&!08
'this text and hit the Enter-key and refrain from using the Deltares-software ',&!09
'executables of iMOD; you may find a solution in downloading the source code of ',&!10
'the iMOD-software and compile the executables yourself (see oss.deltares.nl). ',&!01
' ',&!02
'Without your acceptance of the iMOD License the use of the Deltares-executables',&!03
'of the iMOD-software is prohibited and illegal. ',&!04
' ',&!05
'The iMOD software is distributed in the hope that it will be useful, but ',&!06
'WITHOUT ANY GUARANTEE OR (IMPLIED) WARRANTY. Any use of the ',&!07
'Deltares-executables of the iMOD-software is for your own risk. See the iMOD ',&!08
'License for more details. ',&!09
' ',&!10
'For more info, please contact: Stichting Deltares, P.O. Box 177, 2600 MH Delft,',&!01
'The Netherlands. Email: imod.support@deltares.nl. ',&!02
'==============================================================================='/ !03
CONTAINS
!###===============================================================================
INTEGER FUNCTION UTL_PUTRECORDLENGTH(NBYTES)
!###===============================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: NBYTES
UTL_PUTRECORDLENGTH=(NBYTES*256)+247
END FUNCTION UTL_PUTRECORDLENGTH
!###===============================================================================
INTEGER FUNCTION UTL_GETRECORDLENGTH(FNAME)
!###===============================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: FNAME
INTEGER :: IU,IBYTE,IOS
UTL_GETRECORDLENGTH=0
!## open file
IU=IMOD_UTL_GETUNIT()
OPEN(IU,FILE=FNAME,STATUS='OLD',FORM='UNFORMATTED',ACTION='READ',ACCESS='STREAM',IOSTAT=IOS)
IF(IOS.NE.0)THEN
WRITE(*,'(/A/)') 'Cannot read file: '//TRIM(FNAME)//' to get the recordlength'; STOP
ENDIF
READ(IU,IOSTAT=IOS) IBYTE
!## record length
IF(IOS.EQ.0)UTL_GETRECORDLENGTH=(IBYTE-247)/256 !## in bytes
CLOSE(IU)
END FUNCTION UTL_GETRECORDLENGTH
!###======================================================================
REAL FUNCTION UTL_DIST(X1,Y1,X2,Y2)
!###======================================================================
IMPLICIT NONE
REAL(KIND=8),INTENT(IN) :: X1,Y1,X2,Y2
REAL(KIND=8) :: DX,DY
UTL_DIST=0.0
DX=(X1-X2)**2.0; DY=(Y1-Y2)**2.0
IF(DX+DY.NE.0.0)UTL_DIST=SQRT(DX+DY)
END FUNCTION UTL_DIST
!###======================================================================
SUBROUTINE UTL_IDFGETLOC(IDF,IROW,ICOL,X,Y)
!###======================================================================
IMPLICIT NONE
TYPE(IDFOBJ),INTENT(IN) :: IDF
INTEGER,INTENT(IN) :: IROW,ICOL
REAL(KIND=8),INTENT(OUT) :: X,Y
IF(IDF%IEQ.EQ.0)THEN
X=IDF%XMIN+((ICOL-1)*IDF%DX)+0.5*IDF%DX
Y=IDF%YMAX-((IROW-1)*IDF%DY)-0.5*IDF%DY
ELSEIF(IDF%IEQ.EQ.1)THEN
X=(IDF%SX(ICOL-1)+IDF%SX(ICOL))/2.0
Y=(IDF%SY(IROW-1)+IDF%SY(IROW))/2.0
ENDIF
END SUBROUTINE UTL_IDFGETLOC
!###======================================================================
SUBROUTINE UTL_IDFIROWICOL(IDF,IROW,ICOL,X,Y)
!###======================================================================
IMPLICIT NONE
TYPE(IDFOBJ),INTENT(IN) :: IDF
REAL(KIND=8),INTENT(IN) :: X,Y
INTEGER,INTENT(OUT) :: ICOL,IROW
REAL(KIND=8) :: DX,DY
INTEGER :: I
REAL(KIND=8),PARAMETER :: TINY=0.001D0
REAL(KIND=8) :: XD, YD
XD=X; YD=Y
ICOL=0
IROW=0
IF(IDF%IEQ.EQ.0)THEN
!## similar to imod_utl_geticir
DX=X-IDF%XMIN
I=0; IF(MOD(DX,IDF%DX).NE.0.0)I=1
IF(XD+TINY.GT.REAL(IDF%XMIN,8).AND.XD-TINY.LT.REAL(IDF%XMAX,8))ICOL=INT((X-IDF%XMIN)/IDF%DX)+I
DY=IDF%YMAX-Y
I=0; IF(MOD(DY,IDF%DY).NE.0.0)I=1
IF(YD+TINY.GT.REAL(IDF%YMIN,8).AND.YD-TINY.LT.REAL(IDF%YMAX,8))IROW=INT((IDF%YMAX-Y)/IDF%DY)+I
ICOL=MIN(ICOL,IDF%NCOL)
IROW=MIN(IROW,IDF%NROW)
ELSEIF(IDF%IEQ.EQ.1)THEN
CALL IMOD_UTL_POL1LOCATED(IDF%SX,IDF%NCOL+1,XD,ICOL)
CALL IMOD_UTL_POL1LOCATED(IDF%SY,IDF%NROW+1,YD,IROW)
IF(ICOL.LT.0.OR.ICOL.GT.IDF%NCOL) ICOL=0
IF(IROW.LT.0.OR.IROW.GT.IDF%NROW) IROW=0
ENDIF
END SUBROUTINE UTL_IDFIROWICOL
!###======================================================================
SUBROUTINE UTL_KRIGING_MAIN(MD,XD,YD,ZD,DELR,DELC,NROW,NCOL,X,NODATA,RANGE,KTYPE,BLNKOUT)
!###======================================================================
USE IMOD_IDF_PAR
IMPLICIT NONE
INTEGER,INTENT(IN) :: NROW,NCOL,MD,KTYPE
REAL(KIND=8),INTENT(IN),DIMENSION(0:NROW) :: DELC
REAL(KIND=8),INTENT(IN),DIMENSION(0:NCOL) :: DELR
REAL(KIND=8),INTENT(INOUT),DIMENSION(NCOL,NROW) :: X
TYPE(IDFOBJ),INTENT(IN) :: BLNKOUT
REAL(KIND=8),INTENT(INOUT),DIMENSION(MD) :: XD,YD,ZD
REAL(KIND=8),INTENT(IN) :: NODATA
REAL(KIND=8),INTENT(INOUT) :: RANGE
INTEGER :: ND,IROW,ICOL,IZONE
REAL(KIND=8) :: XC,YC,MZ,KEST,KVAR
INTEGER :: ITYPE,NR,NC,MX,I,J,NAJ
REAL(KIND=8),PARAMETER :: NUGGET=0.0, SILL=100.0
CALL UTL_KRIGING_INIT(MD,XD,YD,ZD,ND,KTYPE,NODATA)
!## compute mean and substract values from mean - simple kriging
IF(KTYPE.GT.0)THEN
MZ=0.0; DO I=1,ND; MZ=MZ+ZD(I); ENDDO; IF(ND.GT.0.0)MZ=MZ/REAL(ND)
DO I=1,ND; ZD(I)=ZD(I)-MZ; ENDDO
ENDIF
DO IROW=1,NROW
DO ICOL=1,NCOL
IF(X(ICOL,IROW).NE.NODATA)CYCLE
XC=(DELR(ICOL-1)+DELR(ICOL))/2.0
YC=(DELC(IROW)+DELC(IROW-1))/2.0
!## get current zone number for this point
IZONE=INT(BLNKOUT%X(ICOL,IROW))
CALL UTL_KRIGING_FILLSYSTEM(XD,YD,ZD,ND,XC,YC,RANGE,SILL,NUGGET,KTYPE,MZ,KEST,KVAR,NODATA, &
IZONE,BLNKOUT)
X(ICOL,IROW)=KEST
ENDDO
ENDDO
END SUBROUTINE UTL_KRIGING_MAIN
!###======================================================================
SUBROUTINE UTL_KRIGING_FILLSYSTEM(XD,YD,ZD,ND,X,Y,RANGE,SILL,NUGGET, &
KTYPE,MZ,KEST,KVAR,NODATA,IZONE,BLNKOUT)
!###======================================================================
USE IMOD_IDF_PAR
IMPLICIT NONE
INTEGER,INTENT(IN) :: ND,KTYPE,IZONE
REAL(KIND=8),INTENT(OUT) :: KEST,KVAR
REAL(KIND=8),INTENT(IN) :: X,Y,RANGE,SILL,NUGGET,MZ,NODATA
REAL(KIND=8),INTENT(IN),DIMENSION(ND) :: XD,YD,ZD
TYPE(IDFOBJ),INTENT(IN) :: BLNKOUT
INTEGER :: I,J,IC,IR,NP,N,ID,JD,IROW,ICOL
REAL(KIND=8) :: DX,DY,DXY,GAMMA,H,MZZ,F
INTEGER,ALLOCATABLE,DIMENSION(:) :: SELID,SELD
INTEGER,ALLOCATABLE,DIMENSION(:,:) :: SELDQ
REAL(KIND=8),ALLOCATABLE,DIMENSION(:) :: B
REAL(KIND=8),ALLOCATABLE,DIMENSION(:,:) :: A
NP=ND; ALLOCATE(SELID(NP)); J=0
DO ID=1,NP
IF(UTL_DIST(XD(ID),YD(ID),X,Y).LE.RANGE)THEN
CALL UTL_IDFIROWICOL(BLNKOUT,IROW,ICOL,XD(ID),YD(ID))
!## same zone as original point
IF(BLNKOUT%X(ICOL,IROW).EQ.IZONE)THEN
J=J+1; SELID(J)=ID
ENDIF
ENDIF
ENDDO
NP=J
!## no points left, interpolated value equals nodata
IF(NP.LE.0)THEN
DEALLOCATE(SELID); KEST=NODATA; KVAR=0.0; RETURN
ENDIF
!## simple kriging (ktype.gt.0) and ordinary kriging (ktype.lt.0)
N=NP; IF(KTYPE.LT.0)N=NP+1
ALLOCATE(A(N,N),B(N))
A=0.0; B=0.0
DO I=1,NP
ID=SELID(I)
!## semivariance
GAMMA=UTL_KRIGING_GETGAMMA(XD(ID),YD(ID),XD(ID),YD(ID),RANGE,SILL,NUGGET,KTYPE)
!## variance
A(I,I)=SILL-GAMMA
DO J=I+1,NP
JD=SELID(J)
GAMMA=UTL_KRIGING_GETGAMMA(XD(ID),YD(ID),XD(JD),YD(JD),RANGE,SILL,NUGGET,KTYPE)
A(I,J)=SILL-GAMMA; A(J,I)=A(I,J)
ENDDO
ID=SELID(I)
GAMMA=UTL_KRIGING_GETGAMMA(XD(ID),YD(ID),X,Y,RANGE,SILL,NUGGET,KTYPE)
B(I)=SILL-GAMMA
ENDDO
!## ordinary kriging
IF(KTYPE.LT.0)THEN
!## fill for lambda
J=N
DO I=1,J; A(I,J)=1.0; A(J,I)=1.0; ENDDO; A(J,J)=0.0; B(J)=1.0
ENDIF
!## current point outside range of all others points
IF(SUM(B(1:NP)).EQ.0.0)THEN
KEST=NODATA
KVAR=0.0
ELSE
CALL UTL_LUDCMP(A,B,N)
!## ordinary kriging compute the local mean mzz instead of the global mean mz
IF(KTYPE.LT.0)THEN
MZZ=0.0; DO I=1,NP; ID=SELID(I); MZZ=MZZ+ZD(ID); ENDDO; MZZ=MZZ/REAL(NP)
ENDIF
KEST=0.0
DO I=1,NP
ID=SELID(I)
IF(KTYPE.GT.0)THEN
KEST=KEST+B(I)*ZD(ID)
ELSE
KEST=KEST+B(I)*(ZD(ID)-MZZ)
ENDIF
ENDDO
!## global mean (simple kriging)
IF(KTYPE.GT.0)KEST=KEST+MZ
!## local mean (ordinary kriging)
IF(KTYPE.LT.0)KEST=KEST+MZZ
!## estimation variance
KVAR=0.0
DO I=1,NP
ID=SELID(I)
GAMMA=UTL_KRIGING_GETGAMMA(XD(ID),YD(ID),X,Y,RANGE,SILL,NUGGET,KTYPE)
KVAR=KVAR+B(I)*(SILL-GAMMA)
ENDDO
IF(KTYPE.LT.0)KVAR=KVAR+B(N)
ENDIF
DEALLOCATE(SELID,A,B)
END SUBROUTINE UTL_KRIGING_FILLSYSTEM
!###======================================================================
REAL FUNCTION UTL_KRIGING_GETGAMMA(X1,Y1,X2,Y2,RANGE,C1,C0,KTYPE) !,SILL,NUGGET,KTYPE)
!###======================================================================
! gamma is function that yeld factor between 0.0 and 1.0
IMPLICIT NONE
INTEGER,INTENT(IN) :: KTYPE
REAL(KIND=8),INTENT(IN) :: X1,Y1,X2,Y2,RANGE,C1,C0 !SILL,NUGGET
REAL(KIND=8) :: DX,DY,DXY,H,F
INTEGER :: I
DX=(X1-X2)**2.0; DY=(Y1-Y2)**2.0; DXY=DX+DY
IF(DXY.GT.0.0)DXY=SQRT(DXY)
!## no part of kriging, beyond given range, equal to sill
IF(DXY.GE.RANGE)THEN
H=0.999
ELSE
SELECT CASE (ABS(KTYPE))
CASE (1) !## linear
H=DXY/RANGE
CASE (2) !## spherical
H=(3.0*DXY)/(2.0*RANGE)-(0.5*(DXY/RANGE)**3.0)
CASE (3) !## exponential
H=1.0-EXP(-3.0*(DXY/RANGE))
CASE (4) !## gaussian
H=1.0-EXP(-3.0*(DXY**2.0)/(RANGE**2.0))
CASE (5) !## power
H=DXY**0.5
CASE DEFAULT
WRITE(*,*) 'UNKNOWN KTYPE',KTYPE; PAUSE; STOP
END SELECT
ENDIF
UTL_KRIGING_GETGAMMA=C0+C1*H
END FUNCTION UTL_KRIGING_GETGAMMA
!###====================================================================
REAL FUNCTION UTL_KRIGING_RANGE(X1,X2,Y1,Y2)
!###====================================================================
IMPLICIT NONE
real(KIND=8),INTENT(IN) :: x1,y1,x2,y2
UTL_KRIGING_RANGE=0.9*SQRT((X2-X1)**2.0+(Y2-Y1)**2.0)
END FUNCTION UTL_KRIGING_RANGE
!###======================================================================
SUBROUTINE UTL_KRIGING_INIT(MD,XD,YD,ZD,ND,KTYPE,NODATA)
!###======================================================================
IMPLICIT NONE
REAL(KIND=8),PARAMETER :: XYCRIT=0.1 !## points wil be averaged if more near eachother
INTEGER,INTENT(IN) :: MD,KTYPE
REAL(KIND=8),INTENT(IN) :: NODATA
REAL(KIND=8),INTENT(INOUT),DIMENSION(MD) :: XD,YD,ZD
INTEGER,INTENT(OUT) :: ND
INTEGER :: I,J,N,IS,IE,IROW,ICOL
REAL(KIND=8) :: XP,YP,ZP
REAL(KIND=8),ALLOCATABLE,DIMENSION(:) :: XCOL,YROW
!## mark doubles with nodata and compute mean for those double points
DO I=1,MD
!## done allready
IF(ZD(I).EQ.NODATA)CYCLE
N=1; XP=XD(I); YP=YD(I); ZP=ZD(I)
DO J=I+1,MD
!## done allready
IF(ZD(J).EQ.NODATA)CYCLE
!## get distance between points
IF(UTL_DIST(XD(I),YD(I),XD(J),YD(J)).LE.XYCRIT)THEN
! IF(KRIGING_DIST(1,XD(I),YD(I),XD(J),YD(J),1,IDF,IBLANKOUT,BO_VALUE,XYCRIT,1.0,0.0,IBLNTYPE).LE.XYCRIT)THEN
N=N+1
ZP=ZP+ZD(J)
!## add point to existing point and turn location off
XP=XP+XD(J); YP=YP+YD(J); ZD(J)=NODATA
ENDIF
ENDDO
!## determine average spot
XD(I)=XP/REAL(N); YD(I)=YP/REAL(N)
ZD(I)=ZP/REAL(N)
END DO
!## eliminate doubles
J=0
DO I=1,MD
IF(ZD(I).NE.NODATA)THEN
J=J+1
IF(J.NE.I)THEN
XD(J)=XD(I); YD(J)=YD(I); ZD(J)=ZD(I)
ENDIF
ENDIF
END DO
ND=J
END SUBROUTINE UTL_KRIGING_INIT
!###====================================================================
subroutine utl_sortem(ib,ie,a,iperm,b,c,d,e,f,g,h)
!###====================================================================
IMPLICIT NONE
REAL,INTENT(INOUT),dimension(:) :: a,B,C,D,E,F,G,H !(*),b(*),c(*),d(*),e(*),f(*),g(*),h(*)
integer,DIMENSION(64) :: LT,UT !lt(64),ut(64),
INTEGER :: i,j,k,m,p,q
REAL :: XH,XG,XF,XE,XD,XC,XB,XA
REAL :: TH,TG,TF,TE,TD,TC,TB,TA
INTEGER :: IRING,IPERM,IA,IB,IC,ID,IE,IF,IG,IH
j = ie
m = 1
i = ib
iring = iperm+1
if (iperm.gt.7) iring=1
10 if (j-i-1) 100,90,15
15 p = (j+i)/2
ta = a(p)
a(p) = a(i)
go to (21,19,18,17,16,161,162,163),iring
163 th = h(p)
h(p) = h(i)
162 tg = g(p)
g(p) = g(i)
161 tf = f(p)
f(p) = f(i)
16 te = e(p)
e(p) = e(i)
17 td = d(p)
d(p) = d(i)
18 tc = c(p)
c(p) = c(i)
19 tb = b(p)
b(p) = b(i)
21 continue
!c
!c Start at the beginning of the segment, search for k such that a(k)>t
!c
q = j
k = i
20 k = k+1
if(k.gt.q) go to 60
if(a(k).le.ta) go to 20
!c
!c Such an element has now been found now search for a q such that a(q) 'unknown,formatted,readonly,shared,append' !rest default
! !## number of units 10-9999 for timeseries
! IF(IU.EQ.0)
IU=GETUNIT() !CFN_GETLUN(10,9999)
MESSAGE=''
!#dos
SELECT CASE (ACT)
CASE ('W','w')
! OPEN(IU,FILE=FNAME,STATUS='UNKNOWN',FORM='FORMATTED',ACTION='WRITE',IOSTAT=IOS)
MESSAGE='WRITE,UNKNOWN,FORMATTED'
CASE ('R','r')
CALL IMOD_UTL_MODEL1CHECKFNAME(FNAME,0)
! OPEN(IU,FILE=FNAME,STATUS='OLD',FORM='FORMATTED',ACTION='READ',IOSTAT=IOS)
MESSAGE='READONLY,SHARED,OLD,FORMATTED'
CASE ('A','a')
CALL IMOD_UTL_MODEL1CHECKFNAME(FNAME,0)
OPEN(IU,FILE=FNAME,STATUS='OLD',FORM='FORMATTED',ACCESS='APPEND',IOSTAT=IOS)
MESSAGE='OLD,FORMATTED,APPEND'
CASE DEFAULT
CALL IMOD_UTL_PRINTTEXT('Wrong open statement, cannot open sequential file: ['//TRIM(FNAME)//']',2)
END SELECT
IOS=OSD_OPEN2(IU,0,FNAME,TRIM(MESSAGE)) !unitnumber,recl,fname,string(options)
!#error occured opening idf-file
IF(IOS.NE.0)CALL IMOD_UTL_PRINTTEXT('Cannot open sequential file: ['//TRIM(FNAME)//']',2)
END SUBROUTINE
!###====================================================
SUBROUTINE IMOD_UTL_GETMED(X,NX,NODATA,PERC,NPERC,MX,XMED)
!###====================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: NX,NPERC !## size array,number of percentiles to be comp.
INTEGER,INTENT(OUT) :: MX !## number of values ne nodata
REAL(KIND=8),INTENT(IN),DIMENSION(:) :: PERC !## percentile 0-100%
REAL(KIND=8),INTENT(OUT),DIMENSION(:) :: XMED !## yielding percentile(s)
REAL(KIND=8),INTENT(IN) :: NODATA !## nodata value !,PERC
REAL(KIND=8),DIMENSION(NX),INTENT(INOUT) :: X !## array
INTEGER :: I,J,IP
REAL(KIND=8) :: FRAC
XMED=NODATA
IF(NX.LE.0)RETURN
!## only one sample
IF(NX.EQ.1)THEN
MX=0
IF(X(1).NE.NODATA)THEN
XMED=X(1)
MX =1
ENDIF
RETURN
ENDIF
!## do not include nodata values for median-computation
MX=0
DO I=1,NX
IF(X(I).NE.NODATA)THEN
MX =MX+1
X(MX)=X(I)
ENDIF
END DO
IF(MX.LE.0)RETURN
!## sort data, excl. nodata values
IF(MX.LE.100)THEN
CALL IMOD_UTL_SHELLSORT(MX,X)
ELSE
CALL IMOD_UTL_QKSORT(MX,MX,X)
ENDIF
DO IP=1,NPERC
IF(PERC(IP).LE.0.0)THEN
XMED(IP)=X(1)
ELSEIF(PERC(IP).GE.100.0)THEN
XMED(IP)=X(MX)
ELSE
FRAC=1.0/(PERC(IP)/100.0)
IF(MOD(REAL(MX),FRAC).EQ.0.0)THEN
I=INT(REAL(MX)/FRAC)
XMED(IP)=X(I)
ELSE
I=MAX(1,INT(REAL(MX)/FRAC))
J=MIN(I+1,MX)
XMED(IP)=(X(I)+X(J))/2.0
ENDIF
ENDIF
ENDDO
END SUBROUTINE IMOD_UTL_GETMED
!C====================================================
SUBROUTINE IMOD_UTL_QKSORT(NDIM,N,ARR)
!====================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: N,NDIM
REAL(KIND=8),INTENT(INOUT),DIMENSION(NDIM) :: ARR
INTEGER :: M,NSTACK
PARAMETER (M=7,NSTACK=50)
INTEGER :: I,IR,J,JSTACK,K,L,ISTACK(NSTACK)
REAL(KIND=8) :: A,TEMP
JSTACK=0
L=1
IR=N
1 IF(IR-L.LT.M)THEN
DO J=L+1,IR
A=ARR(J)
DO I=J-1,1,-1
IF(ARR(I).LE.A)GOTO 2
ARR(I+1)=ARR(I)
ENDDO
I=0
2 ARR(I+1)=A
ENDDO
IF(JSTACK.EQ.0)RETURN
IR=ISTACK(JSTACK)
L=ISTACK(JSTACK-1)
JSTACK=JSTACK-2
ELSE
K=(L+IR)/2
TEMP=ARR(K)
ARR(K)=ARR(L+1)
ARR(L+1)=TEMP
IF(ARR(L+1).GT.ARR(IR))THEN
TEMP=ARR(L+1)
ARR(L+1)=ARR(IR)
ARR(IR)=TEMP
ENDIF
IF(ARR(L).GT.ARR(IR))THEN
TEMP=ARR(L)
ARR(L)=ARR(IR)
ARR(IR)=TEMP
ENDIF
IF(ARR(L+1).GT.ARR(L))THEN
TEMP=ARR(L+1)
ARR(L+1)=ARR(L)
ARR(L)=TEMP
ENDIF
I=L+1
J=IR
A=ARR(L)
3 CONTINUE
I=I+1
IF(ARR(I).LT.A)GOTO 3
4 CONTINUE
J=J-1
IF(ARR(J).GT.A)GOTO 4
IF(J.LT.I)GOTO 5
TEMP=ARR(I)
ARR(I)=ARR(J)
ARR(J)=TEMP
GOTO 3
5 ARR(L)=ARR(J)
ARR(J)=A
JSTACK=JSTACK+2
IF(JSTACK.GT.NSTACK)PAUSE 'NSTACK TOO SMALL'
IF(IR-I+1.GT.J-L)THEN
ISTACK(JSTACK)=IR
ISTACK(JSTACK-1)=I
IR=J-1
ELSE
ISTACK(JSTACK)=J-1
ISTACK(JSTACK-1)=L
L=I
ENDIF
ENDIF
GOTO 1
END SUBROUTINE IMOD_UTL_QKSORT
!###======================================================================
SUBROUTINE IMOD_UTL_QKSORT2(ARR,BRR,NDIM,N)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: NDIM,N
REAL,INTENT(INOUT),DIMENSION(NDIM) :: ARR,BRR
INTEGER M,NSTACK
PARAMETER (M=7,NSTACK=50)
INTEGER I,IR,J,JSTACK,K,L,ISTACK(NSTACK)
REAL A,B,ATEMP,BTEMP
JSTACK=0
L=1
IR=N
1 IF(IR-L.LT.M)THEN
DO J=L+1,IR
A=ARR(J)
B=BRR(J)
DO I=J-1,1,-1
IF(ARR(I).LE.A)GOTO 2
ARR(I+1)=ARR(I)
BRR(I+1)=BRR(I)
ENDDO
I=0
2 ARR(I+1)=A
BRR(I+1)=B
ENDDO
IF(JSTACK.EQ.0)RETURN
IR=ISTACK(JSTACK)
L =ISTACK(JSTACK-1)
JSTACK=JSTACK-2
ELSE
K=(L+IR)/2
ATEMP =ARR(K)
BTEMP =BRR(K)
ARR(K) =ARR(L+1)
BRR(K) =BRR(L+1)
ARR(L+1)=ATEMP
BRR(L+1)=BTEMP
IF(ARR(L+1).GT.ARR(IR))THEN
ATEMP =ARR(L+1)
BTEMP =BRR(L+1)
ARR(L+1)=ARR(IR)
BRR(L+1)=BRR(IR)
ARR(IR)=ATEMP
BRR(IR)=BTEMP
ENDIF
IF(ARR(L).GT.ARR(IR))THEN
ATEMP =ARR(L)
BTEMP =BRR(L)
ARR(L) =ARR(IR)
BRR(L) =BRR(IR)
ARR(IR)=ATEMP
BRR(IR)=BTEMP
ENDIF
IF(ARR(L+1).GT.ARR(L))THEN
ATEMP =ARR(L+1)
BTEMP =BRR(L+1)
ARR(L+1)=ARR(L)
BRR(L+1)=BRR(L)
ARR(L) =ATEMP
BRR(L) =BTEMP
ENDIF
I=L+1
J=IR
A=ARR(L)
B=BRR(L)
3 CONTINUE
I=I+1
IF(ARR(I).LT.A)GOTO 3
4 CONTINUE
J=J-1
IF(ARR(J).GT.A)GOTO 4
IF(J.LT.I)GOTO 5
ATEMP =ARR(I)
BTEMP =BRR(I)
ARR(I)=ARR(J)
BRR(I)=BRR(J)
ARR(J)=ATEMP
BRR(J)=BTEMP
GOTO 3
5 ARR(L)=ARR(J)
BRR(L)=BRR(J)
ARR(J)=A
BRR(J)=B
JSTACK=JSTACK+2
IF(JSTACK.GT.NSTACK)PAUSE 'NSTACK TOO SMALL'
IF(IR-I+1.GT.J-L)THEN
ISTACK(JSTACK)=IR
ISTACK(JSTACK-1)=I
IR=J-1
ELSE
ISTACK(JSTACK)=J-1
ISTACK(JSTACK-1)=L
L=I
ENDIF
ENDIF
GOTO 1
END SUBROUTINE IMOD_UTL_QKSORT2
!###======================================================================
SUBROUTINE IMOD_UTL_QKSORT3(ARR,BRR) !,NDIM,N)
!###======================================================================
IMPLICIT NONE
!INTEGER,INTENT(IN) :: NDIM,N
INTEGER,INTENT(INOUT),DIMENSION(:) :: ARR,BRR
INTEGER :: N,M,NSTACK
PARAMETER (M=7,NSTACK=50)
INTEGER :: I,IR,J,JSTACK,K,L,ISTACK(NSTACK)
REAL :: A,B,ATEMP,BTEMP
N=SIZE(ARR)
JSTACK=0
L=1
IR=N
1 IF(IR-L.LT.M)THEN
DO J=L+1,IR
A=ARR(J)
B=BRR(J)
DO I=J-1,1,-1
IF(ARR(I).LE.A)GOTO 2
ARR(I+1)=ARR(I)
BRR(I+1)=BRR(I)
ENDDO
I=0
2 ARR(I+1)=A
BRR(I+1)=B
ENDDO
IF(JSTACK.EQ.0)RETURN
IR=ISTACK(JSTACK)
L =ISTACK(JSTACK-1)
JSTACK=JSTACK-2
ELSE
K=(L+IR)/2
ATEMP =ARR(K)
BTEMP =BRR(K)
ARR(K) =ARR(L+1)
BRR(K) =BRR(L+1)
ARR(L+1)=ATEMP
BRR(L+1)=BTEMP
IF(ARR(L+1).GT.ARR(IR))THEN
ATEMP =ARR(L+1)
BTEMP =BRR(L+1)
ARR(L+1)=ARR(IR)
BRR(L+1)=BRR(IR)
ARR(IR)=ATEMP
BRR(IR)=BTEMP
ENDIF
IF(ARR(L).GT.ARR(IR))THEN
ATEMP =ARR(L)
BTEMP =BRR(L)
ARR(L) =ARR(IR)
BRR(L) =BRR(IR)
ARR(IR)=ATEMP
BRR(IR)=BTEMP
ENDIF
IF(ARR(L+1).GT.ARR(L))THEN
ATEMP =ARR(L+1)
BTEMP =BRR(L+1)
ARR(L+1)=ARR(L)
BRR(L+1)=BRR(L)
ARR(L) =ATEMP
BRR(L) =BTEMP
ENDIF
I=L+1
J=IR
A=ARR(L)
B=BRR(L)
3 CONTINUE
I=I+1
IF(ARR(I).LT.A)GOTO 3
4 CONTINUE
J=J-1
IF(ARR(J).GT.A)GOTO 4
IF(J.LT.I)GOTO 5
ATEMP =ARR(I)
BTEMP =BRR(I)
ARR(I)=ARR(J)
BRR(I)=BRR(J)
ARR(J)=ATEMP
BRR(J)=BTEMP
GOTO 3
5 ARR(L)=ARR(J)
BRR(L)=BRR(J)
ARR(J)=A
BRR(J)=B
JSTACK=JSTACK+2
IF(JSTACK.GT.NSTACK)PAUSE 'NSTACK TOO SMALL'
IF(IR-I+1.GT.J-L)THEN
ISTACK(JSTACK)=IR
ISTACK(JSTACK-1)=I
IR=J-1
ELSE
ISTACK(JSTACK)=J-1
ISTACK(JSTACK-1)=L
L=I
ENDIF
ENDIF
GOTO 1
END SUBROUTINE IMOD_UTL_QKSORT3
!
!!###====================================================
!RECURSIVE SUBROUTINE IMOD_UTL_QKSORT3(A,AI)
!!###====================================================
!IMPLICIT NONE
!INTEGER, INTENT(IN OUT) :: A(:), AI(:)
!INTEGER :: SPLIT
!
!IF(SIZE(A) > 1) THEN
! CALL IMOD_UTL_PARTITION(A, AI, SPLIT)
! CALL IMOD_UTL_QKSORT3(A(:SPLIT-1),AI(:SPLIT-1))
! CALL IMOD_UTL_QKSORT3(A(SPLIT:),AI(SPLIT:))
!END IF
!
!END SUBROUTINE IMOD_UTL_QKSORT3
!
!!###====================================================
!SUBROUTINE IMOD_UTL_PARTITION(A,AI,MARKER)
!!###====================================================
!IMPLICIT NONE
!INTEGER, INTENT(IN OUT) :: A(:), AI(:)
!INTEGER, INTENT(OUT) :: MARKER
!INTEGER :: LEFT, RIGHT, PIVOT, TEMP
!
!PIVOT = (A(1) + A(SIZE(A))) / 2 ! AVERAGE OF FIRST AND LAST ELEMENTS TO PREVENT QUADRATIC
!LEFT = 0 ! BEHAVIOR WITH SORTED OR REVERSE SORTED DATA
!RIGHT = SIZE(A) + 1
!
!DO WHILE (LEFT < RIGHT)
! RIGHT = RIGHT - 1
! DO WHILE (A(RIGHT) > PIVOT)
! RIGHT = RIGHT-1
! END DO
! LEFT = LEFT + 1
! DO WHILE (A(LEFT) < PIVOT)
! LEFT = LEFT + 1
! END DO
! IF (LEFT < RIGHT) THEN
! TEMP = A(LEFT)
! A(LEFT) = A(RIGHT)
! A(RIGHT) = TEMP
!
! TEMP = AI(LEFT)
! AI(LEFT) = AI(RIGHT)
! AI(RIGHT) = TEMP
! END IF
!END DO
!
!IF (LEFT == RIGHT) THEN
! MARKER = LEFT + 1
!ELSE
! MARKER = LEFT
!END IF
!
!END SUBROUTINE IMOD_UTL_PARTITION
!###====================================================
SUBROUTINE IMOD_UTL_SHELLSORT(N,A)
!###====================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: N
REAL(KIND=8),DIMENSION(N),INTENT(INOUT) :: A
INTEGER :: I,J,INC
REAL(KIND=8) :: V
INC=1
1 INC=3*INC+1
IF(INC.LE.N)GOTO 1
2 CONTINUE
INC=INC/3
DO I=INC+1,N
V=A(I)
J=I
3 IF(A(J-INC).GT.V)THEN
A(J)=A(J-INC)
J=J-INC
IF(J.LE.INC)GOTO 4
GOTO 3
ENDIF
4 A(J)=V
END DO
IF(INC.GT.1)GOTO 2
END SUBROUTINE
!###==================================================================
SUBROUTINE IMOD_UTL_POL1INTMAIN(NCOL,NROW,NPC,NPR,XCRD,YCRD,ZCRD,DELR,DELC,X, &
IINT,NODATA)
!###==================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: NCOL,NROW,NPC,NPR,IINT
REAL(KIND=8),INTENT(IN) :: NODATA
REAL(KIND=8),DIMENSION(NPC),INTENT(IN) :: XCRD !fixed point x-coordinates
REAL(KIND=8),DIMENSION(NPR),INTENT(IN) :: YCRD !fixed point y-coordinates
REAL(KIND=8),DIMENSION(NPC,NPR),INTENT(IN) :: ZCRD !fixed point values
REAL(KIND=8),DIMENSION(0:NCOL),INTENT(IN) :: DELR
REAL(KIND=8),DIMENSION(0:NROW),INTENT(IN) :: DELC
REAL(KIND=8),DIMENSION(NCOL,NROW),INTENT(INOUT) :: X
REAL(KIND=8) :: Y,DY,X1,X2
INTEGER :: NMAX,IROW,ICOL !,ITYPE
!TYPE(WIN_MESSAGE) :: MESSAGE
REAL(KIND=8),ALLOCATABLE,DIMENSION(:) :: C,D,YMTMP,YNTMP
NMAX=MAX(NPR,NPC)
IF(ALLOCATED(C))DEALLOCATE(C)
IF(ALLOCATED(D))DEALLOCATE(D)
IF(ALLOCATED(YMTMP))DEALLOCATE(YMTMP)
IF(ALLOCATED(YNTMP))DEALLOCATE(YNTMP)
ALLOCATE(C(NMAX),D(NMAX),YNTMP(NPR),YMTMP(NPC))
!loop over all points!
DO IROW=1,NROW
DO ICOL=1,NCOL
IF(X(ICOL,IROW).NE.NODATA)THEN
X1=(DELR(ICOL-1)+DELR(ICOL))/2.0
X2=(DELC(IROW-1)+DELC(IROW))/2.0
CALL IMOD_UTL_POL2DINT(XCRD,YCRD,ZCRD,C,D,NMAX,YMTMP,YNTMP,NPC,NPR,X1,X2,Y,DY,IINT,NODATA)
X(ICOL,IROW)=Y
ENDIF
ENDDO
ENDDO
END SUBROUTINE IMOD_UTL_POL1INTMAIN
!###==================================================================
SUBROUTINE IMOD_UTL_POL2DINT(XCRD,YCRD,ZCRD,C,D,NMAX,YMTMP,YNTMP,NPC,NPR,XINT,&
YINT,Y,DY,IINT,NODATA)
!###==================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: NPC,NPR,NMAX,IINT
REAL(KIND=8),INTENT(IN) :: NODATA
REAL(KIND=8),DIMENSION(NPC),INTENT(IN) :: XCRD
REAL(KIND=8),DIMENSION(NPR),INTENT(IN) :: YCRD
REAL(KIND=8),DIMENSION(NPC,NPR) :: ZCRD
REAL(KIND=8),INTENT(IN) :: XINT,YINT
REAL(KIND=8),INTENT(OUT) :: DY,Y
REAL(KIND=8),DIMENSION(NPR),INTENT(INOUT) :: YNTMP
REAL(KIND=8),DIMENSION(NPC),INTENT(INOUT) :: YMTMP
REAL(KIND=8),DIMENSION(NMAX),INTENT(INOUT) :: C,D
INTEGER :: J,K,XPOS,XPOS1,XPOS2,DXPOS,YPOS,YPOS1,YPOS2,DYPOS,DPOS,IDATA,INODATA
REAL(KIND=8) :: YMEAN
CALL IMOD_UTL_POL1LOCATED(XCRD,NPC,XINT,XPOS)
CALL IMOD_UTL_POL1LOCATED(YCRD,NPR,YINT,YPOS)
DPOS =INT(SQRT(REAL(IINT))) !iint=4,dpos=2; iint=16,dpos=4
DPOS =DPOS/2
XPOS1=MAX(1,XPOS-(DPOS-1))
XPOS2=MIN(XPOS+DPOS,NPC)
DXPOS=(XPOS2-XPOS1)+1
YPOS1=MAX(1,YPOS-(DPOS-1))
YPOS2=MIN(YPOS+DPOS,NPR)
DYPOS=(YPOS2-YPOS1)+1
IDATA=0; INODATA=0; YMEAN = 0.
JL: DO J=XPOS1,XPOS2
DO K=YPOS1,YPOS2
YNTMP(K)=ZCRD(J,K)
IF(YNTMP(K).NE.NODATA)THEN
YMEAN = YMEAN + YNTMP(K)
IDATA=IDATA+1
ENDIF
END DO
END DO JL
IF (IDATA.GT.0) THEN
YMEAN = YMEAN/IDATA
JLOOP: DO J=XPOS1,XPOS2
DO K=YPOS1,YPOS2
YNTMP(K)=ZCRD(J,K)
IF(YNTMP(K).EQ.NODATA)THEN
YNTMP(K)=YMEAN
ENDIF
END DO
CALL IMOD_UTL_POL1DINT(YCRD(YPOS1),YNTMP(YPOS1),C,D,DYPOS,NMAX,YINT,YMTMP(J),DY)
END DO JLOOP
ELSE
INODATA=1
END IF
IF(INODATA.EQ.1)THEN
Y =NODATA
DY=0.0
ELSE
CALL IMOD_UTL_POL1DINT(XCRD(XPOS1),YMTMP(XPOS1),C,D,DXPOS,NMAX,XINT,Y,DY)
ENDIF
END SUBROUTINE IMOD_UTL_POL2DINT
!###==================================================================
SUBROUTINE IMOD_UTL_POL1DINT(XA,YA,C,D,NPR,NMAX,X,Y,DY)
!###==================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: NPR,NMAX
REAL(KIND=8),DIMENSION(NPR),INTENT(IN) :: XA,YA
REAL(KIND=8),DIMENSION(NMAX),INTENT(INOUT) :: C,D
REAL(KIND=8),INTENT(IN) :: X
REAL(KIND=8),INTENT(OUT) :: DY,Y
INTEGER :: I,M,NS
REAL(KIND=8) :: DEN,DIF,DIFT,HO,HP,W
NS =1
DIF=ABS(X-XA(1))
DO I=1,NPR
DIFT=ABS(X-XA(I))
IF(DIFT.LT.DIF)THEN
NS =I
DIF=DIFT
ENDIF
C(I)=YA(I)
D(I)=YA(I)
END DO
Y =YA(NS)
NS=NS-1
DO M=1,NPR-1
DO I=1,NPR-M
HO =XA(I)-X
HP =XA(I+M)-X
W =C(I+1)-D(I)
DEN=HO-HP
IF(DEN.EQ.0.0)PAUSE 'FAILURE IN POLINT' !occurs whenever two xa(i) are almost the same
DEN=W/DEN
D(I)=HP*DEN
C(I)=HO*DEN
END DO
IF(2*NS.LT.NPR-M)THEN
DY=C(NS+1)
ELSE
DY=D(NS)
NS=NS-1
ENDIF
Y=Y+DY
END DO
END SUBROUTINE IMOD_UTL_POL1DINT
!###==================================================================
SUBROUTINE IMOD_UTL_POL1LOCATEI(XX,N,X,J)
!###==================================================================
!return position such that x is within xx(j) and xx(j+1)
IMPLICIT NONE
INTEGER,INTENT(OUT) :: J
INTEGER,INTENT(IN) :: N
INTEGER,INTENT(IN) :: X
INTEGER,INTENT(IN),DIMENSION(N) :: XX
INTEGER :: JL,JM,JU
JL=0
JU=N+1
DO
IF(JU-JL.GT.1)THEN
JM=(JU+JL)/2
IF((XX(N).GT.XX(1)).EQV.(X.GT.XX(JM)))THEN
JL=JM
ELSE
JU=JM
ENDIF
ELSE
EXIT
ENDIF
ENDDO
J=JL
END SUBROUTINE IMOD_UTL_POL1LOCATEI
!!###==================================================================
!SUBROUTINE IMOD_UTL_POL1LOCATER(XX,N,X,J)
!!###==================================================================
!!return position such that x is within xx(j) and xx(j+1)
!IMPLICIT NONE
!INTEGER,INTENT(OUT) :: J
!INTEGER,INTENT(IN) :: N
!REAL,INTENT(IN) :: X
!REAL,INTENT(IN),DIMENSION(N) :: XX
!INTEGER :: JL,JM,JU
!
!JL=0
!JU=N+1
!DO
! IF(JU-JL.GT.1)THEN
! JM=(JU+JL)/2
! IF((XX(N).GT.XX(1)).EQV.(X.GT.XX(JM)))THEN
! JL=JM
! ELSE
! JU=JM
! ENDIF
! ELSE
! EXIT
! ENDIF
!ENDDO
!
!J=JL
!
!END SUBROUTINE IMOD_UTL_POL1LOCATER
!###==================================================================
SUBROUTINE IMOD_UTL_POL1LOCATED(XX,N,X,J)
!###==================================================================
!return position such that x is within xx(j) and xx(j+1)
IMPLICIT NONE
INTEGER,INTENT(OUT) :: J
INTEGER,INTENT(IN) :: N
DOUBLE PRECISION,INTENT(IN) :: X
REAL(KIND=8),INTENT(IN),DIMENSION(N) :: XX
INTEGER :: JL,JM,JU
JL=0
JU=N+1
DO
IF(JU-JL.GT.1)THEN
JM=(JU+JL)/2
IF((XX(N).GT.XX(1)).EQV.(X.GT.XX(JM)))THEN
JL=JM
ELSE
JU=JM
ENDIF
ELSE
EXIT
ENDIF
ENDDO
J=JL
END SUBROUTINE IMOD_UTL_POL1LOCATED
!###===================================================================
SUBROUTINE IMOD_UTL_OSSYSTEM()
!###===================================================================
IMPLICIT NONE
INTEGER :: VOS,OSD_GET_OS
! !#capsim/metaswap/none active?
!#get operating system
! VOS=OSD_GET_OS()
! OS =0
! IF(VOS.EQ.3)OS=1
! IF(VOS.EQ.2)OS=2
! IF(VOS.EQ.4)OS=2
OS=1
SELECT CASE (OS)
!## dos
CASE (1)
OSN(OS) ='DOS-mode'
!## linux/unix (beowulf)
CASE (2)
OSN(OS) ='UNIX/LINUX-mode'
!## something different
CASE DEFAULT
CALL IMOD_UTL_PRINTTEXT('No proper operating system!',2)
END SELECT
END SUBROUTINE IMOD_UTL_OSSYSTEM
!###===================================================================
SUBROUTINE IMOD_UTL_PRINTTEXT(TXT,TXTTYPE,IU)
!###===================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: TXT
INTEGER,INTENT(IN) :: TXTTYPE
INTEGER,INTENT(IN),OPTIONAL :: IU
logical :: pks7mpimasterwrite, lwrite
LOGICAL :: LEX
#ifdef PKSMPI
lwrite = pks7mpimasterwrite()
#else
lwrite = .true.
#endif
SELECT CASE (TXTTYPE)
!## file
CASE (0)
WRITE(*,'(A)') TRIM(TXT)
!## information
CASE (-1,1)
WRITE(*,'(A)') TRIM(TXT)
!IF(IFLAG(1).EQ.1)PAUSE
!## error
CASE (-2) ! NO STANDARD OUTPUT
CASE (2)
WRITE(*,'(A)')
WRITE(*,'(A)') 'Error occured!'
WRITE(*,'(A)') TRIM(TXT)
IF(IFLAG(1).EQ.1)PAUSE
CASE (3)
if (lwrite) WRITE(*,'(A)') TRIM(TXT)
CASE (-3)
if (lwrite) then
WRITE(*,'(A)')
WRITE(*,'(A)') 'Error occured!'
WRITE(*,'(A)') TRIM(TXT)
IF(IFLAG(1).EQ.1)PAUSE
end if
CASE DEFAULT
WRITE(*,'(A)') TRIM(TXT)
!IF(IFLAG(1).EQ.1)PAUSE
END SELECT
IF(TXTTYPE.LE.0)THEN !TXTTYPE.EQ.-1.OR.TXTTYPE.EQ.-2)THEN
IF (PRESENT(IU)) THEN
INQUIRE(UNIT=IU,OPENED=LEX)
IF(LEX)THEN
WRITE(IU,'(A)') TRIM(TXT)
CALL FLUSH(IU)
END IF
END IF
END IF
IF(TXTTYPE.EQ.2.OR.TXTTYPE.EQ.-3)THEN
CALL EXIT(1)
ENDIF
END SUBROUTINE IMOD_UTL_PRINTTEXT
!###====================================================================
REAL FUNCTION IMOD_UTL_GETMOSTFREQ(FREQ,MFREQ,NFREQ)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: MFREQ,NFREQ
REAL(KIND=8),DIMENSION(MFREQ),INTENT(IN) :: FREQ
INTEGER :: I,MI,NI
NI=1 !number of unique
MI=NI !max. number of unique
IMOD_UTL_GETMOSTFREQ=FREQ(NI)
DO I=2,NFREQ
IF(FREQ(I).NE.FREQ(I-1))THEN
IF(NI.GT.MI)THEN
IMOD_UTL_GETMOSTFREQ=FREQ(I-1)
MI=NI
ENDIF
NI=1
ELSE
NI=NI+1
ENDIF
END DO
!test final
IF(NI.GT.MI) IMOD_UTL_GETMOSTFREQ=FREQ(NFREQ)
END FUNCTION IMOD_UTL_GETMOSTFREQ
!###====================================================
SUBROUTINE UTL_GETUNIQUE_INT(IX,N,NU,NODATA)
!###====================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: N
INTEGER,INTENT(OUT) :: NU
INTEGER,INTENT(INOUT),DIMENSION(N) :: IX
INTEGER,INTENT(IN),OPTIONAL :: NODATA
INTEGER :: I
CALL SHELLSORT_INT(N,IX)
!## determine number of unique classes
IF(PRESENT(NODATA))THEN
NU=0
DO I=1,N
IF(NU.EQ.0)THEN
IF(IX(I).NE.NODATA)THEN
NU=NU+1
IX(NU)=IX(I)
ENDIF
ELSE
IF(IX(I).NE.IX(NU).AND.IX(I).NE.NODATA)THEN
NU =NU+1
IX(NU)=IX(I)
ENDIF
ENDIF
END DO
ELSE
!## determine number of unique classes
NU=1
DO I=2,N
IF(IX(I).NE.IX(NU))THEN
NU =NU+1
IX(NU)=IX(I)
ENDIF
END DO
ENDIF
END SUBROUTINE UTL_GETUNIQUE_INT
!###====================================================
SUBROUTINE SHELLSORT_INT(N,A)
!###====================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: N
INTEGER,DIMENSION(N) :: A
INTEGER :: I,J,INC
INTEGER :: V
INC=1
1 INC=3*INC+1
IF(INC.LE.N)GOTO 1
2 CONTINUE
INC=INC/3
DO I=INC+1,N
V=A(I)
J=I
3 IF(A(J-INC).GT.V)THEN
A(J)=A(J-INC)
J=J-INC
IF(J.LE.INC)GOTO 4
GOTO 3
ENDIF
4 A(J)=V
END DO
IF(INC.GT.1)GOTO 2
RETURN
END SUBROUTINE
!###======================================================================
INTEGER FUNCTION GETUNIT()
!###======================================================================
IMPLICIT NONE
LOGICAL :: LEX
DO GETUNIT=20,5000
INQUIRE(UNIT=GETUNIT,OPENED=LEX)
IF(.NOT.LEX)EXIT
END DO
IF(GETUNIT.GT.5000)THEN
WRITE(*,*) 'Can not open more than 500 files simultaneously!'
GETUNIT=0
ENDIF
END FUNCTION GETUNIT
!###====================================================================
INTEGER FUNCTION JD(YEAR,MONTH,DAY)
!###====================================================================
!EXTRACTED FROM THE INTERNET: http://aa.usno.navy.mil/faq/docs/JD_Formula.html
!COMPUTES THE JULIAN DATE (JD) GIVEN A GREGORIAN CALENDAR DATE (YEAR,MONTH,DAY).
!EXAMPLE: YEAR=1970,MONTH=1,DAY=1,JD=2440588
IMPLICIT NONE
INTEGER,INTENT(IN) :: YEAR,MONTH,DAY
INTEGER :: I,J,K
I =YEAR
J =MONTH
K =DAY
JD=K-32075+1461*(I+4800+(J-14)/12)/4+367*(J-2-(J-14)/12*12) &
/12-3*((I+4900+(J-14)/12)/100)/4
END FUNCTION JD
!###======================================================================
INTEGER FUNCTION UTL_IDFGETDATE(IDFNAME,DAYFRACTION,IYR,IMH,IDY,IHR,IMT,ISC)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: IDFNAME
REAL(KIND=8),INTENT(OUT),OPTIONAL :: DAYFRACTION
INTEGER,INTENT(OUT),OPTIONAL :: IDY,IMH,IYR,IHR,IMT,ISC
INTEGER :: IOS
INTEGER :: I,II,J,N,YR,MT,DY,HR,MN,SC
INTEGER,DIMENSION(2) :: NI
DATA NI/14,8/
!## initially no data
UTL_IDFGETDATE=0
!## try to find 16 numbers after eachother ...
!## try to find 8 numbers after eachother ...
DO II=1,2
N=0
!## start after last "\"-symbol
DO I=INDEX(IDFNAME,'\',.TRUE.)+1,LEN_TRIM(IDFNAME)
!## part of a number
SELECT CASE (ICHAR(IDFNAME(I:I)))
CASE (48:57)
!## count numbers
N=N+1
!## stop if total number is 8 or 14
IF(N.EQ.NI(II))EXIT
!## mark first position
IF(N.EQ.1)J=I
CASE DEFAULT
N=0
END SELECT
END DO
IF(N.EQ.NI(II))EXIT
!## nothing found
IF(II.EQ.2.AND.N.LT.NI(II))RETURN
ENDDO
!## default
IF(PRESENT(DAYFRACTION))DAYFRACTION=-1.0D0
IF(II.EQ.1)THEN
READ(IDFNAME(J:) ,'(I8) ',IOSTAT=IOS) UTL_IDFGETDATE
IF(PRESENT(DAYFRACTION))THEN
READ(IDFNAME(J+8:),'(3I2)',IOSTAT=IOS) HR,MN,SC
DAYFRACTION=REAL(HR*3600+MN*60+SC)/86400.0D0
DAYFRACTION=MAX(0.0D0,MIN(DAYFRACTION,1.0D0))
ENDIF
READ(IDFNAME(J:) ,'(I4,5I2)',IOSTAT=IOS) YR,MT,DY,HR,MN,SC
ELSE
READ(IDFNAME(J:) ,'(I8)',IOSTAT=IOS) UTL_IDFGETDATE
READ(IDFNAME(J:) ,'(I4,2I2)',IOSTAT=IOS) YR,MT,DY
HR=0; MN=0; SC=0
ENDIF
IF(PRESENT(IYR))IYR=YR
IF(PRESENT(IMH))IMH=MT
IF(PRESENT(IDY))IDY=DY
IF(PRESENT(IHR))IHR=HR
IF(PRESENT(IMT))IMT=MN
IF(PRESENT(ISC))ISC=SC
IF(IOS.NE.0)UTL_IDFGETDATE=0
END FUNCTION UTL_IDFGETDATE
!###====================================================================
INTEGER FUNCTION IDATETOJDATE(IDATE)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: IDATE
INTEGER :: IY,IM,ID
CALL IMOD_UTL_IDATETOGDATE(IDATE,IY,IM,ID)
IDATETOJDATE=JD(IY,IM,ID)
END FUNCTION IDATETOJDATE
!###====================================================================
SUBROUTINE IMOD_UTL_IDATETOGDATE(IDATE,IY,IM,ID)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: IDATE
INTEGER,INTENT(OUT) :: IY,IM,ID
CHARACTER(LEN=8) :: CDATE
IY = IDATE / 10000
IM = MOD( IDATE, 10000 ) / 100
ID = MOD( IDATE, 100 )
END SUBROUTINE IMOD_UTL_IDATETOGDATE
!###======================================================================
SUBROUTINE IMOD_UTL_FILLARRAY(IP,NP,B)
!###======================================================================
!# read binair number (e.g. 256) and returns array (/1,0,0,1,0,0,1/)
IMPLICIT NONE
INTEGER,INTENT(IN) :: NP
INTEGER,INTENT(IN) :: B
INTEGER,INTENT(OUT),DIMENSION(NP) :: IP
INTEGER :: I,BB
IP=0
BB=B
DO I=1,NP
IP(I)=MOD(BB,2)
BB=BB/2
END DO
!## make sure results are only 0/1 values
DO I=1,NP
IF(IP(I).LT.0.OR.IP(I).GT.1)IP(I)=0
END DO
END SUBROUTINE IMOD_UTL_FILLARRAY
!###======================================================================
SUBROUTINE IMOD_UTL_READARRAY(IP,NP,B)
!###======================================================================
!# write a binair-number given an array (/1,0,0,4,0,0,7/)
IMPLICIT NONE
INTEGER,INTENT(IN) :: NP
INTEGER,INTENT(OUT) :: B
INTEGER,INTENT(IN),DIMENSION(NP) :: IP
INTEGER :: I,J
B=0
DO I=1,NP
J=MAX(0,MIN(IP(I),1))
B=B+(J*(2**(I-1)))
END DO
END SUBROUTINE IMOD_UTL_READARRAY
!###====================================================================
FUNCTION IMOD_UTL_SUBST(FNAME,SUB1,SUB2)
!###====================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: SUB1,SUB2
CHARACTER(LEN=*),INTENT(IN) :: FNAME
INTEGER :: I,J
CHARACTER(LEN=256) :: IMOD_UTL_SUBST
IMOD_UTL_SUBST=FNAME
I=INDEX(FNAME,SUB1)
IF(I.EQ.0)RETURN
I=I-1
J=I+LEN_TRIM(SUB1)+1
IMOD_UTL_SUBST=FNAME(:I)//TRIM(SUB2)//FNAME(J:)
END FUNCTION IMOD_UTL_SUBST
!###====================================================================
SUBROUTINE IMOD_UTL_READIPF(STIME,ETIME,QT,FNAME,ISS)
!###====================================================================
IMPLICIT NONE
INTEGER(KIND=8),INTENT(IN) :: stime,etime
CHARACTER(LEN=*),INTENT(IN) :: FNAME
REAL,INTENT(OUT) :: QT
INTEGER, INTENT(IN) :: ISS
INTEGER :: IR,I,I1,I2,IU,NR,NC,IDATE,JDATE,NDATE,NAJ,N,IOS
REAL :: QQ,FRAC,Q1,RTIME,TTIME
CHARACTER(LEN=8),DIMENSION(:),ALLOCATABLE :: ATTRIB
REAL,DIMENSION(:),ALLOCATABLE :: NODATA
INTEGER(KIND=8) :: DBL_EDATE,DBL_SDATE
CHARACTER(LEN=52),DIMENSION(:),ALLOCATABLE :: QD
! STIME=SDATE
! ETIME=EDATE
QT=0.0
!## transient
IF(ISS.EQ.2)TTIME=UTL_DIFFTIME(stime,etime) !EDATE-SDATE
!## open textfiles with pump information
IU=IMOD_UTL_GETUNIT()
OPEN(IU,FILE=FNAME,FORM='FORMATTED',STATUS='OLD',ACTION='READ',SHARE='DENYNONE')
READ(IU,*,IOSTAT=IOS) NR
IF(IOS.NE.0)CALL IMOD_UTL_PRINTTEXT('Can not read number of rows in '//TRIM(FNAME),2)
IF(NR.GT.0.0)THEN
READ(IU,*,IOSTAT=IOS) NC
IF(IOS.NE.0)CALL IMOD_UTL_PRINTTEXT('Can not read number of columns in '//TRIM(FNAME),2)
ALLOCATE(ATTRIB(NC),NODATA(NC),QD(NC))
DO I=1,NC
READ(IU,*,IOSTAT=IOS) ATTRIB(I),NODATA(I)
IF(IOS.NE.0)CALL IMOD_UTL_PRINTTEXT('Can not read attribute '//TRIM(IMOD_UTL_ITOS(I))//' in '//TRIM(FNAME),2)
END DO
I1=1
QQ=0.0
DBL_SDATE=STIME
DO IR=1,NR
READ(IU,*) DBL_EDATE,(QD(I),I=2,NC)
!##steady-state
IF(ISS.EQ.1)THEN
!## get volume
READ(QD(2),*) QQ; IF(QQ.EQ.NODATA(2))QQ=0.0
QT=QT+QQ
ELSE
!## make double if needed
IF(DBL_EDATE.LT.100000000)DBL_EDATE=DBL_EDATE*1000000
IF(DBL_EDATE.GT.STIME)THEN
DBL_SDATE=MAX(DBL_SDATE,STIME)
DBL_EDATE=MIN(DBL_EDATE,ETIME)
RTIME=UTL_DIFFTIME(DBL_SDATE,DBL_EDATE)
QT=QT+RTIME*QQ
ENDIF
IF(DBL_EDATE.LE.ETIME)THEN
!## get volume
READ(QD(2),*) QQ; IF(QQ.EQ.NODATA(2))QQ=0.0
ENDIF
DBL_SDATE=DBL_EDATE
!## stop
IF(DBL_EDATE.GE.ETIME)EXIT
ENDIF
ENDDO
!## last record probably read, extent extraction up to end of stress-period
IF(QQ.NE.0.0.AND.IR.GT.NR)THEN
RTIME=UTL_DIFFTIME(DBL_SDATE,ETIME)
QT=QT+MIN(TTIME,RTIME)*QQ
ENDIF
!## steady-state
IF(ISS.EQ.1)THEN
IF(NR.GT.0)QT=QT/REAL(NR)
ELSE
QT=QT/TTIME
ENDIF
DEALLOCATE(ATTRIB,NODATA,QD)
ENDIF
CLOSE(IU)
RETURN
END SUBROUTINE IMOD_UTL_READIPF
!###====================================================================
SUBROUTINE imod_utl_ITIMETOGDATE(IDATE,IYR,IMH,IDY,IHR,IMT,ISC)
!###====================================================================
IMPLICIT NONE
INTEGER(KIND=8),INTENT(IN) :: IDATE
INTEGER,INTENT(OUT) :: IYR,IMH,IDY,IHR,IMT,ISC
IYR = IDATE / 10000000000
IMH = MOD( IDATE, 10000000000 ) / 100000000
IDY = MOD( IDATE, 100000000 ) / 1000000
IHR = MOD( IDATE, 1000000 ) / 10000
IMT = MOD( IDATE, 10000 ) / 100
ISC = MOD( IDATE, 100 )
END SUBROUTINE imod_utl_ITIMETOGDATE
!###====================================================================
SUBROUTINE imod_utl_ITIMETOGTIME(ITIME,IH,IM,IS)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: ITIME !## time seconds
INTEGER,INTENT(OUT) :: IH,IM,IS
IH = ITIME / 3600
IM = MOD( ITIME, 3600 ) / 60
IS = MOD( ITIME, 60 )
END SUBROUTINE imod_utl_ITIMETOGTIME
!###====================================================================
SUBROUTINE IMOD_UTL_STIMETOETIME(STIME,DELT,ETIME)
!###====================================================================
IMPLICIT NONE
INTEGER(KIND=8),INTENT(IN) :: STIME
INTEGER(KIND=8),INTENT(OUT) :: ETIME
REAL,INTENT(IN) :: DELT
REAL :: NSR
INTEGER :: NDAY,NS,NS1,NS2,IYR,IMH,IDY,IHR,IMT,ISC,SD
!## get julian date
SD=STIME/1000000
SD=IMOD_UTL_IDATETOJDATE(SD)
CALL IMOD_UTL_ITIMETOGDATE(STIME,IYR,IMH,IDY,IHR,IMT,ISC)
!## number of seconds in that day
NS1=REAL(IHR)*3600.0+REAL(IMT)*60.0+REAL(ISC)
!## number of days in timestep
NDAY= INT(DELT)
!## increase julian date
SD=SD+NDAY
!## remaining timesteps in seconds
NS2=(DELT-REAL(NDAY))*86400D0
!## add to seconds in current timestep
NS=NS1+NS2
!## fraction in days
NSR=REAL(NS)/86400.0
NDAY=INT(NSR)
SD=SD+NDAY
!## net seconds in new timestep
NSR=NSR-REAL(NDAY)
!## get number of hours/minutes/seconds
NS1=NSR*86400
CALL imod_utl_ITIMETOGTIME(NS1,IHR,IMT,ISC)
!## increase julian date
ETIME=INT(IMOD_UTL_JDATETOIDATE(SD),8)
ETIME=ETIME*1000000+IHR*10000+IMT*100+ISC
END SUBROUTINE IMOD_UTL_STIMETOETIME
!###====================================================================
REAL FUNCTION UTL_DIFFTIME(SDATE,EDATE)
!###====================================================================
IMPLICIT NONE
INTEGER(KIND=8),INTENT(IN) :: SDATE,EDATE
INTEGER :: IYR1,IMH1,IDY1,IHR1,IMT1,ISC1, &
IYR2,IMH2,IDY2,IHR2,IMT2,ISC2
INTEGER :: SD,ED,DD,IHR,IMT,ISC
REAL :: F1,F2,F
SD=SDATE/1000000; ED=EDATE/1000000
SD=IMOD_UTL_IDATETOJDATE(SD); ED=IMOD_UTL_IDATETOJDATE(ED)
DD=ED-SD
!## start time
CALL IMOD_UTL_ITIMETOGDATE(SDATE,IYR1,IMH1,IDY1,IHR1,IMT1,ISC1)
F1=(REAL(IHR1)*3600.0+REAL(IMT1)*60.0+REAL(ISC1))/86400
!## end time
CALL IMOD_UTL_ITIMETOGDATE(EDATE,IYR2,IMH2,IDY2,IHR2,IMT2,ISC2)
F2=(REAL(IHR2)*3600.0+REAL(IMT2)*60.0+REAL(ISC2))/86400
!## same day
IF(SD.EQ.ED)THEN
F=F2-F1
ELSE
F=1.0-F1+F2+(DD-1)
ENDIF
UTL_DIFFTIME=F
END FUNCTION UTL_DIFFTIME
!###======================================================================
LOGICAL FUNCTION IMOD_UTL_DIRINFO(DIR,WC,LISTNAME,FT)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: DIR,WC,FT
CHARACTER(LEN=*),INTENT(OUT),DIMENSION(:),POINTER :: LISTNAME
CHARACTER(LEN=256),DIMENSION(:),POINTER :: C_LISTNAME
CHARACTER(LEN=256) :: LINE
INTEGER :: IU,I,J,N,IOS
LOGICAL :: LEX
IMOD_UTL_DIRINFO=.FALSE.
IF(LEN(C_LISTNAME).LT.LEN(LISTNAME))CALL IMOD_UTL_PRINTTEXT('c_listname() "'//'.\dir_imod.txt"'
IF(FT.EQ.'D'.OR.FT.EQ.'d')LINE='dir /ad /b /o "'//TRIM(DIR)//'\'//TRIM(WC)//'" > ".\dir_imod.txt"'
!## remove \\
DO
I=INDEX(LINE,'\\')
IF(I.EQ.0)EXIT
LINE(I+1:256-1)=LINE(I+2:)
ENDDO
WRITE(IU,'(A)') TRIM(LINE)
CLOSE(IU)
LINE='.\dir.bat'
CALL SYSTEM(TRIM(LINE))
IU=IMOD_UTL_GETUNIT()
OPEN(IU,FILE='.\dir_imod.txt',ACTION='READ',FORM='FORMATTED')
IF(IOS.NE.0)CALL IMOD_UTL_PRINTTEXT('iMOD does not have priveleges to read: [.\dir_imod.txt]',2)
ALLOCATE(C_LISTNAME(50))
I=0
DO
READ(IU,'(A256)',IOSTAT=IOS) LINE
IF(IOS.NE.0)EXIT
J=LEN_TRIM(LINE)
IF(J.EQ.0)EXIT
LINE(2:J+1)=LINE(1:J)
LINE(1:1)='"'
LINE(J+2:J+2)='"'
I=I+1
IF(I.GT.SIZE(C_LISTNAME))THEN
N=SIZE(C_LISTNAME)
ALLOCATE(LISTNAME(N)); LISTNAME(1:N)=C_LISTNAME(1:N)
DEALLOCATE(C_LISTNAME); ALLOCATE(C_LISTNAME(N*2))
C_LISTNAME(1:N)=LISTNAME(1:N); DEALLOCATE(LISTNAME)
ENDIF
READ(LINE,*,IOSTAT=IOS) C_LISTNAME(I)
IF(IOS.NE.0)EXIT
END DO
CLOSE(IU)!,STATUS='DELETE')
N=I
ALLOCATE(LISTNAME(N))
LISTNAME(1:N)=C_LISTNAME(1:N)
DEALLOCATE(C_LISTNAME)
IMOD_UTL_DIRINFO=.TRUE.
END FUNCTION IMOD_UTL_DIRINFO
!###====================================================================
SUBROUTINE IMOD_UTL_APPLYFCT_D(A,NODATA,NROW,NCOL,FCT,IMP)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: NROW,NCOL
REAL(KIND=8),INTENT(IN) :: FCT,IMP,NODATA
REAL(KIND=8),INTENT(INOUT),DIMENSION(NCOL,NROW) :: A
INTEGER :: IROW,ICOL
DO IROW=1,NROW
DO ICOL=1,NCOL
IF(A(ICOL,IROW).NE.NODATA)THEN
A(ICOL,IROW)=A(ICOL,IROW)*FCT
A(ICOL,IROW)=A(ICOL,IROW)+IMP
ENDIF
END DO
END DO
RETURN
END SUBROUTINE IMOD_UTL_APPLYFCT_D
!###====================================================================
SUBROUTINE IMOD_UTL_APPLYFCT_I(A,NODATA,NROW,NCOL,FCT,IMP)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: NROW,NCOL
REAL,INTENT(IN) :: FCT,IMP,NODATA
INTEGER,INTENT(INOUT),DIMENSION(NCOL,NROW) :: A
INTEGER :: IROW,ICOL
DO IROW=1,NROW
DO ICOL=1,NCOL
IF(A(ICOL,IROW).NE.NODATA)THEN
A(ICOL,IROW)=A(ICOL,IROW)*FCT
A(ICOL,IROW)=A(ICOL,IROW)+IMP
ENDIF
END DO
END DO
RETURN
END SUBROUTINE IMOD_UTL_APPLYFCT_I
!###====================================================
LOGICAL FUNCTION IMOD_UTL_EQUALS_DOUBLE(A,B)
!###====================================================
IMPLICIT NONE
REAL(KIND=8), INTENT(IN) :: A, B
REAL(KIND=8) :: EPS
EPS=ABS(A)*EPSILON(A) ! SCALE EPSILON
IF(EPS.EQ.0.0)THEN
EPS=TINY (A) ! IF EPS UNDERFLOWED TO 0
! USE A VERY SMALL
! POSITIVE VALUE FOR EPSILON
END IF
IF(ABS(A-B).GT.EPS)THEN
IMOD_UTL_EQUALS_DOUBLE=.FALSE. ! NOT EQUAL IF DIFFERENCE>EPS
ELSE
IMOD_UTL_EQUALS_DOUBLE=.TRUE. ! EQUAL OTHERWISE
ENDIF
END FUNCTION IMOD_UTL_EQUALS_DOUBLE
!###====================================================================
SUBROUTINE IMOD_UTL_SCALE1PDELRC(XMIN,YMIN,XMAX,YMAX,DELC,DELR,PDELR,PDELC,NROW,NCOL,CS,NROWIDF,NCOLIDF,IU,IEQ,ITB)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: NROW,NCOL,NROWIDF,NCOLIDF,IU,IEQ,ITB
REAL(KIND=8),INTENT(IN) :: CS,XMIN,YMIN,XMAX,YMAX
REAL(KIND=8),INTENT(IN),DIMENSION(0:NCOL) :: DELR
REAL(KIND=8),INTENT(IN),DIMENSION(0:NROW) :: DELC
REAL(KIND=8) :: DX,DY,X,Y,D
INTEGER,INTENT(OUT),DIMENSION(2,NCOL) :: PDELR
INTEGER,INTENT(OUT),DIMENSION(2,NROW) :: PDELC
INTEGER :: I,J,IREC
CHARACTER(LEN=256) :: IDFNAME
REAL(KIND=8),ALLOCATABLE,DIMENSION(:) :: DELRIDF,DELCIDF
REAL(KIND=8) :: MIND
IF(XMIN.GT.DELR(0).OR.XMAX.LT.DELR(NCOL).OR.YMIN.GT.DELC(NROW).OR.YMAX.LT.DELC(0))THEN
INQUIRE(UNIT=IU,NAME=IDFNAME)
CALL IMOD_UTL_PRINTTEXT('=======================================',0)
CALL IMOD_UTL_PRINTTEXT('Warning!',0)
CALL IMOD_UTL_PRINTTEXT('File: '//TRIM(IDFNAME),0)
CALL IMOD_UTL_PRINTTEXT('Undersizes current model dimensions!',0)
IF(XMIN.GT.DELR(0))THEN
CALL IMOD_UTL_PRINTTEXT('XMIN IDF '//TRIM(IMOD_UTL_DTOS(XMIN,'F',2))//' > XMIN MODEL '//TRIM(IMOD_UTL_DTOS(DELR(0),'F',2)),0)
ENDIF
IF(XMAX.LT.DELR(NCOL))THEN
CALL IMOD_UTL_PRINTTEXT('XMAX IDF '//TRIM(IMOD_UTL_DTOS(XMAX,'F',2))//' < XMAX MODEL '//TRIM(IMOD_UTL_DTOS(DELR(NCOL),'F',2)),0)
ENDIF
IF(YMIN.GT.DELC(NROW))THEN
CALL IMOD_UTL_PRINTTEXT('YMIN IDF '//TRIM(IMOD_UTL_DTOS(YMIN,'F',2))//' > YMIN MODEL '//TRIM(IMOD_UTL_DTOS(DELC(NROW),'F',2)),0)
ENDIF
IF(YMAX.LT.DELC(0))THEN
CALL IMOD_UTL_PRINTTEXT('YMAX IDF '//TRIM(IMOD_UTL_DTOS(YMAX,'F',2))//' < YMAX MODEL '//TRIM(IMOD_UTL_DTOS(DELC(0),'F',2)),0)
ENDIF
! CALL PRINTTEXT('---------------------------------------',0)
! CALL PRINTTEXT('XMIN MODEL '//TRIM(RTOS(DELR(0),'F',2)),0)
! CALL PRINTTEXT('YMIN MODEL '//TRIM(RTOS(DELC(NROW),'F',2)),0)
! CALL PRINTTEXT('XMAX MODEL '//TRIM(RTOS(DELR(NCOL),'F',2)),0)
! CALL PRINTTEXT('YMAX MODEL '//TRIM(RTOS(DELC(0),'F',2)),0)
CALL IMOD_UTL_PRINTTEXT('=======================================',0)
CALL IMOD_UTL_PRINTTEXT('Error',2)
ENDIF
IF(ALLOCATED(DELRIDF))DEALLOCATE(DELRIDF)
IF(ALLOCATED(DELCIDF))DEALLOCATE(DELCIDF)
ALLOCATE(DELRIDF(0:NCOLIDF),DELCIDF(0:NROWIDF))
DELRIDF(0)=XMIN
DELCIDF(0)=YMAX
IF(IEQ.EQ.0)THEN
DO I=1,NCOLIDF; DELRIDF(I)=XMIN+REAL(I)*CS; ENDDO
DO I=1,NROWIDF; DELCIDF(I)=YMAX-REAL(I)*CS; ENDDO
ELSEIF(IEQ.EQ.1)THEN
IREC =10+ITB*2
DO I=1,NCOLIDF
IREC=IREC+1
READ(IU,REC=IREC+ICF) DELRIDF(I)
DELRIDF(I)=DELRIDF(I-1)+DELRIDF(I)
END DO
DO I=1,NROWIDF
IREC=IREC+1
READ(IU,REC=IREC+ICF) DELCIDF(I)
DELCIDF(I)=DELCIDF(I-1)-DELCIDF(I)
END DO
ENDIF
!## start/end column direction
DO I=1,NCOL
CALL IMOD_UTL_POL1LOCATED(DELRIDF,NCOLIDF+1,DELR(I-1),PDELR(1,I))
!## check whether position is exact equally
J=PDELR(1,I)
IF(J.LE.NCOLIDF)THEN
IF(DELRIDF(J).EQ.DELR(I-1))PDELR(1,I)=PDELR(1,I)+1
ENDIF
CALL IMOD_UTL_POL1LOCATED(DELRIDF,NCOLIDF+1,DELR(I),PDELR(2,I))
PDELR(1,I)=MIN(PDELR(1,I),NCOLIDF)
PDELR(2,I)=MIN(PDELR(2,I),NCOLIDF)
ENDDO
DO I=1,NROW
CALL IMOD_UTL_POL1LOCATED(DELCIDF,NROWIDF+1,DELC(I-1),PDELC(1,I))
CALL IMOD_UTL_POL1LOCATED(DELCIDF,NROWIDF+1,DELC(I),PDELC(2,I))
!## check whether position is exact equally
J=PDELC(2,I)
IF(J.LE.NROWIDF)THEN
IF(DELCIDF(J-1).EQ.DELC(I))PDELC(2,I)=PDELC(2,I)-1
ENDIF
PDELC(1,I)=MIN(PDELC(1,I),NROWIDF)
PDELC(2,I)=MIN(PDELC(2,I),NROWIDF)
ENDDO
IF(ALLOCATED(DELRIDF))DEALLOCATE(DELRIDF)
IF(ALLOCATED(DELCIDF))DEALLOCATE(DELCIDF)
DO I=1,NCOL
IF(PDELR(2,I).LT.PDELR(1,I))then
DX =(DELR(I-1)-XMIN)/CS
PDELR(1,I)=INT(DX)+1
WRITE(*,*) DELR(I-1),XMIN,DELR(I-1)-XMIN,DX,CS,PDELR(1,I)
DX =(DELR(I)-XMIN)/CS
PDELR(2,I)=INT(DX)+1
WRITE(*,*) DELR(I),XMIN,DELR(I)-XMIN,DX,INT(DX)+1,PDELR(2,I)
DX=DELR(I)-XMIN
IF(MOD(DX,CS).EQ.0.0)PDELR(2,I)=PDELR(2,I)-1
WRITE(*,*) DELR(I),XMIN,DELR(I)-XMIN,DX,PDELR(2,I),MOD(DX,CS)
CALL IMOD_UTL_PRINTTEXT('PDELR(2,I).LT.PDELR(1,I)',2)
ENDIF
ENDDO
DO I=1,NROW
IF(PDELC(2,I).LT.PDELC(1,I))THEN
DY=(YMAX-DELC(I-1))/CS
PDELC(1,I)=INT(DY)+1
WRITE(*,*) DELC(I-1),YMAX,YMAX-DELC(I-1),DY,CS,PDELC(1,I)
DY=(YMAX-DELC(I))
PDELC(2,I)=INT(DY)+1
WRITE(*,*) DELC(I),YMAX,YMAX-DELC(I),DY,PDELC(2,I)!,MOD(DY,CS)
DY=YMAX-DELC(I)
IF(MOD(DY,CS).EQ.0.0)PDELC(2,I)=PDELC(2,I)-1
WRITE(*,*) DELC(I),YMAX,YMAX-DELC(I),DY,PDELC(2,I),MOD(DY,CS)
CALL IMOD_UTL_PRINTTEXT('PDELC(2,I).LT.PDELC(1,I)',2)
ENDIF
ENDDO
!##adjust pdelr/pdelc in case reading idf is coarser, then you don't need to read it in again, values will be copied in READCOPYVALUES_R()
J=1
DO I=2,NCOL
IF(PDELR(1,I).EQ.PDELR(1,J).AND. &
PDELR(2,I).EQ.PDELR(2,J))THEN
PDELR(1,I)=-J
PDELR(2,I)=-J
ELSE
J=I
ENDIF
END DO
J=1
DO I=2,NROW
IF(PDELC(1,I).EQ.PDELC(1,J).AND. &
PDELC(2,I).EQ.PDELC(2,J))THEN
PDELC(1,I)=-J
PDELC(2,I)=-J
ELSE
J=I
ENDIF
END DO
RETURN
END SUBROUTINE IMOD_UTL_SCALE1PDELRC
!###======================================================================
SUBROUTINE IMOD_UTL_ST1CREATEIPF_GETTLP(N,TLP,KH,TOP,BOT,ZZ1,ZZ2,MINKH,ICLAY,CTXTFILE)
!###======================================================================
IMPLICIT NONE
REAL,PARAMETER :: MINP=0.0 ! 5
INTEGER,INTENT(IN) :: N,ICLAY
CHARACTER(LEN=*),INTENT(IN) :: CTXTFILE
REAL,INTENT(IN) :: ZZ1,ZZ2
REAL,INTENT(IN) :: MINKH
REAL,INTENT(IN),DIMENSION(N) :: KH,TOP,BOT
! REAL,INTENT(IN),DIMENSION(N-1) :: C
REAL,INTENT(INOUT),DIMENSION(N) :: TLP
INTEGER :: JLAY,ILAY,K,IDIFF
REAL :: ZM,ZT,ZB,ZC,FC,DZ,Z1,Z2
REAL,ALLOCATABLE,DIMENSION(:) :: L,TL
INTEGER,ALLOCATABLE,DIMENSION(:) :: IL
ALLOCATE(L(N),TL(N),IL(N))
Z1=ZZ1; Z2=ZZ2
IF(Z1.EQ.Z2)THEN
TLP=0.0; ZM=Z1
DO ILAY=1,N
IF(ZM.GE.BOT(ILAY).AND.ZM.LE.TOP(ILAY))THEN
TLP(ILAY)=1.0; EXIT
ENDIF
ENDDO
ELSE
!!## make sure thickness is not exactly zero, minimal thickness is 0.01m
!IDIFF=0; IF(Z1.EQ.Z2)THEN; Z1=Z1+0.005; Z2=Z2-0.005; IDIFF=1; ENDIF
!## filterlength for each modellayer
L=0.0
DO ILAY=1,N
ZT=MIN(TOP(ILAY),Z1); ZB=MAX(BOT(ILAY),Z2)
L(ILAY)=MAX(0.0,ZT-ZB)
ENDDO
TLP=0.0
!## well within any aquifer(s)
IF(SUM(L).GT.0.0)THEN
!## compute percentage and include sumkd, only if itype.eq.2
L=L*KH
!## percentage (0-1) L*KH
DO ILAY=1,N; IF(L(ILAY).NE.0.0)TLP=(1.0/SUM(L))*L; ENDDO
ENDIF
!## correct for dismatch with centre of modelcell
DO ILAY=1,N
IF(TLP(ILAY).GT.0.0)THEN
DZ= TOP(ILAY)-BOT(ILAY)
ZC=(TOP(ILAY)+BOT(ILAY))/2.0
ZT= MIN(TOP(ILAY),Z1)
ZB= MAX(BOT(ILAY),Z2)
FC=(ZT+ZB)/2.0
TLP(ILAY)=TLP(ILAY)*(1.0-(ABS(ZC-FC)/(0.5*DZ)))
ENDIF
ENDDO
!## normalize tlp() again
IF(SUM(TLP).GT.0.0)TLP=(1.0/SUM(TLP))*TLP
!## remove small percentages
DO ILAY=1,N; IF(TLP(ILAY).LT.MINP)TLP(ILAY)=0.0; ENDDO
!## normalize tlp() again
IF(SUM(TLP).GT.0.0)TLP=(1.0/SUM(TLP))*TLP
!## remove small transmissivities
IF(MINKH.GT.0.0)THEN
ZT=SUM(TLP)
DO ILAY=1,N
DZ=TOP(ILAY)-BOT(ILAY)
IF(KH(ILAY)*DZ.LT.MINKH)TLP(ILAY)=0.0
ENDDO
IF(SUM(TLP).GT.0.0)THEN
ZT=ZT/SUM(TLP)
!## normalize tlp() again
TLP=ZT*TLP
ENDIF
ENDIF
!## normalize tlp() again
IF(SUM(TLP).GT.0.0)TLP=(1.0/SUM(TLP))*TLP
ENDIF
! !## make sure only one layer is assigned whenever z1.eq.z2
! IF(IDIFF.EQ.1)THEN
! K=0; ZT=0.0; DO ILAY=1,N
! IF(ABS(TLP(ILAY)).GT.ZT)THEN
! ZT=ABS(TLP(ILAY)); K=ILAY
! ENDIF
! ENDDO
! !## not assigned to any layer
! IF(K.NE.0)THEN
! ZT=TLP(K)
! TLP=0.0; TLP(K)=1.0
! IF(ZT.LT.0.0)TLP(K)=-1.0*TLP(K)
! ENDIF
! ENDIF
!## nothing in model, whenever system on top of model, put them in first modellayer with thickness
IF(SUM(TLP).EQ.0.0)THEN
IF(Z1.GE.TOP(1))TLP(1)=1.0
ENDIF
!## if no layers has been used for the assignment, try to allocate it to aquifer of this interbed
IF(SUM(TLP).LE.0)THEN
TLP=0
DO ILAY=1,N-1
IF(BOT(ILAY).GE.Z1.AND.TOP(ILAY+1).LE.Z2)THEN; TLP(ILAY)=1.0; EXIT; ENDIF
ENDDO
ENDIF
DEALLOCATE(L,TL,IL)
END SUBROUTINE IMOD_UTL_ST1CREATEIPF_GETTLP
!###======================================================================
LOGICAL FUNCTION IMOD_UTL_HAS_EXT(FNAME,EXT)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*), INTENT(IN) :: FNAME
CHARACTER(LEN=*), INTENT(IN) :: EXT
CHARACTER(LEN=256) :: S
INTEGER :: I, N
S = TRIM(FNAME)
CALL IMOD_UTL_S_CAP(S,'l')
I = INDEX(S,'.',BACK=.TRUE.)
IF (I.GT.0) THEN
N = LEN_TRIM(EXT)
IMOD_UTL_HAS_EXT = (S(I+1:I+N) == TRIM(EXT))
ELSE
IMOD_UTL_HAS_EXT = .FALSE.
END IF
END FUNCTION IMOD_UTL_HAS_EXT
!###======================================================================
SUBROUTINE IMOD_UTL_REL_TO_ABS(ROOT,FNAME)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*), INTENT(INOUT) :: ROOT
CHARACTER(LEN=*), INTENT(INOUT) :: FNAME
INTEGER :: M, N, IL, I
CHARACTER(LEN=1) :: SLASH
LOGICAL :: LREL
N = LEN_TRIM(FNAME)
IF (N==0) RETURN
CALL IMOD_UTL_SWAPSLASH(FNAME)
CALL IMOD_UTL_GETSLASH(SLASH)
FNAME = ADJUSTL(FNAME)
N = LEN_TRIM(FNAME)
CALL IMOD_UTL_SWAPSLASH(ROOT)
M = LEN_TRIM(ROOT)
IF(ROOT(M:M).EQ.SLASH) THEN
ROOT = ROOT(1:M-1)
M = M - 1
END IF
IL = M + 1
LREL = .FALSE.
DO WHILE(.TRUE.)
IF(FNAME(1:1).NE.'.')EXIT
IF(FNAME(1:2).EQ.'.'//SLASH)THEN
LREL = .TRUE.
FNAME = FNAME(3:N)
N = LEN_TRIM(FNAME)
END IF
IF(FNAME(1:3).EQ.'..'//SLASH)THEN
LREL = .TRUE.
FNAME = FNAME(4:N)
N = LEN_TRIM(FNAME)
IL = INDEX(ROOT(1:IL-1),SLASH,BACK=.TRUE.)
END IF
END DO
IF(LREL) THEN
FNAME = ROOT(1:IL-1)//SLASH//TRIM(FNAME)
END IF
END SUBROUTINE IMOD_UTL_REL_TO_ABS
!###======================================================================
SUBROUTINE IMOD_UTL_ABS_PATH(PATH)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*), INTENT(INOUT) :: PATH
INTEGER :: LUN, I, N
CHARACTER(LEN=1024) :: ABSPATH
CALL IMOD_UTL_CREATEDIR(PATH)
N = LEN_TRIM(PATH)
IF(PATH(N:N).EQ.'\'.OR.PATH(N:N).EQ.'/')THEN
ABSPATH = TRIM(PATH)//'TEST.TXT'
ELSE
ABSPATH = TRIM(PATH)//'\TEST.TXT'
END IF
N = LEN_TRIM(ABSPATH)
#ifdef PKSMPI
CALL PKS7MPIFNAME(ABSPATH,N)
#endif
CALL IMOD_UTL_SWAPSLASH(ABSPATH)
IF(ABSPATH(1:2).EQ.'./')THEN
ABSPATH = ABSPATH(3:LEN_TRIM(ABSPATH))
END IF
LUN = IMOD_UTL_GETUNIT()
OPEN(UNIT=LUN,FILE=ABSPATH)
INQUIRE(UNIT=LUN,NAME=ABSPATH)
I = INDEX(ABSPATH,'\',.TRUE.)
IF (I.GT.0) ABSPATH = ABSPATH(1:I-1)
I = INDEX(ABSPATH,'/',.TRUE.)
IF (I.GT.0) ABSPATH = ABSPATH(1:I-1)
PATH = TRIM(ABSPATH)
CLOSE(LUN,STATUS='DELETE')
END SUBROUTINE IMOD_UTL_ABS_PATH
!###====================================================================
SUBROUTINE IMOD_UTL_GETRCL(NODE,NROW,NCOL,ILAY,IROW,ICOL)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: NROW,NCOL,NODE
INTEGER,INTENT(OUT) :: ILAY,IROW,ICOL
INTEGER :: K,INODE
real(kind=8) :: RNODE,RNODES
RNODE =DBLE(NODE)
RNODES=DBLE(NCOL*NROW)
INODE =NODE
K=1
IF(MOD(RNODE,RNODES).EQ.0.0)K=0
ILAY =INT(RNODE)/INT(RNODES)+K
INODE=INODE-((ILAY-1)*NCOL*NROW)
K=1
IF(MOD(INODE,NCOL).EQ.0)K=0
IROW=INT(INODE/NCOL)+K
ICOL=INODE-((IROW-1)*NCOL)
END SUBROUTINE IMOD_UTL_GETRCL
!###====================================================================
SUBROUTINE IMOD_UTL_READOPENFILE(IU,NROW,NCOL,FNAME,NODATA,XMIN,YMIN,XMAX,YMAX,CS,IEQ,ITB)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(OUT) :: NROW,NCOL,IU,IEQ,ITB
REAL(kind=8),INTENT(OUT) :: NODATA,XMIN,YMIN,CS,XMAX,YMAX
CHARACTER(LEN=*),INTENT(IN) :: FNAME
INTEGER :: IOS
REAL(kind=8) :: DX,DY
INTEGER(KIND=1) :: I1,I2,I3,I4
CALL IMOD_UTL_OPENIDF(IU,FNAME,'R',4)
IF(IU.LE.0)CALL IMOD_UTL_PRINTTEXT('Can not open '//TRIM(FNAME)//' for reading!',2)
READ(IU,REC=1+ICF) NCOL
READ(IU,REC=2+ICF) NROW
READ(IU,REC=3+ICF) XMIN
READ(IU,REC=4+ICF) XMAX
READ(IU,REC=5+ICF) YMIN
READ(IU,REC=6+ICF) YMAX
READ(IU,REC=9+ICF) NODATA
ITB=0
READ(IU,REC=10+ICF,IOSTAT=IOS) IEQ
IF(IOS.NE.0)RETURN
IF(IEQ.NE.0.AND.IEQ.NE.1)THEN
READ(IU,REC=10+ICF,IOSTAT=IOS) I1,I2,I3,I4
IF(IOS.NE.0)CALL IMOD_UTL_PRINTTEXT('iMOD can not read IEQ,ITB properly!',0)
IEQ=INT(I1)
ITB=INT(I2)
ENDIF
IF(IEQ.EQ.0)THEN
READ(IU,REC=11+ICF) DX
READ(IU,REC=12+ICF) DY
IF(DX.NE.DY)CALL IMOD_UTL_PRINTTEXT(TRIM(FNAME)//': dx ne dy',2)
ELSE
DX=0.0
DY=0.0
CALL IMOD_UTL_PRINTTEXT('Non-equidistantial IDF is used!',0)
ENDIF
CS=DX
RETURN
END SUBROUTINE IMOD_UTL_READOPENFILE
!###====================================================================
SUBROUTINE IMOD_UTL_GETICIR(XC,YC,ICOL,IROW,NCOL,NROW,DELR,DELC,SIMCSIZE,IEQ)
!###====================================================================
IMPLICIT NONE
REAL(KIND=8),INTENT(IN) :: XC,YC
INTEGER,INTENT(OUT) :: ICOL,IROW
INTEGER,INTENT(IN) :: NCOL,NROW
REAL(KIND=8), DIMENSION(0:NCOL), INTENT(IN) :: DELR
REAL(KIND=8), DIMENSION(0:NROW), INTENT(IN) :: DELC
REAL(KIND=8), INTENT(IN) :: SIMCSIZE
INTEGER, INTENT(IN) :: IEQ
REAL(KIND=8),PARAMETER :: TINY=0.001D0
REAL(KIND=8) :: XD, YD
REAL(KIND=8) :: DX,DY
INTEGER :: I
ICOL=0; IROW=0
XD = XC; YD = YC
IF(IEQ.EQ.0)THEN
dx=xc-delr(0)
i=0; if(mod(dx,simcsize).ne.0.0D0)i=1
if(xc+TINY.gt.delr(0).and.xc-TINY.lt.delr(ncol))icol=int(dx/simcsize)+i
dy=delc(0)-yc
i=0; if(mod(dy,simcsize).ne.0.0D0)i=1
if(yc+TINY.gt.delc(nrow).and.yc-TINY.lt.delc(0))irow=int(dy/simcsize)+i
icol=min(icol,ncol); irow=min(irow,nrow)
ELSE
CALL IMOD_UTL_POL1LOCATED(DELR,NCOL+1,XD,ICOL)
CALL IMOD_UTL_POL1LOCATED(DELC,NROW+1,YD,IROW)
IF(ICOL.LT.0.OR.ICOL.GT.NCOL) ICOL=0
IF(IROW.LT.0.OR.IROW.GT.NROW) IROW=0
ENDIF
END SUBROUTINE IMOD_UTL_GETICIR
!###======================================================================
SUBROUTINE IMOD_UTL_INTERSECT_EQUI(XMIN,XMAX,YMIN,YMAX,CSX_IN,CSY_IN,XIN1,XIN2,YIN1,YIN2,N,LHFB)
!###======================================================================
IMPLICIT NONE
REAL(KIND=8),INTENT(IN) :: XMIN,XMAX,YMIN,YMAX,CSX_IN,CSY_IN
REAL(KIND=8),INTENT(IN) :: XIN1,XIN2,YIN1,YIN2
INTEGER,INTENT(INOUT) :: N
LOGICAL,INTENT(IN) :: LHFB
REAL(KIND=8) :: X,Y,XMN,XMX,YMN,YMX,DX,DY,LENG,TD,X1,X2,Y1,Y2,CSX,CSY
INTEGER :: I,ICOL,IROW,ID,N_IN
N=0; X1=XIN1; Y1=YIN1; X2=XIN2; Y2=YIN2
IF(.NOT.ASSOCIATED(XA))ALLOCATE(XA(1000)); IF(.NOT.ASSOCIATED(YA))ALLOCATE(YA(1000))
IF(.NOT.ASSOCIATED(FA))ALLOCATE(FA(1000)); IF(.NOT.ASSOCIATED(LN))ALLOCATE(LN(1000))
IF(.NOT.ASSOCIATED(CA))ALLOCATE(CA(1000)); IF(.NOT.ASSOCIATED(RA))ALLOCATE(RA(1000))
CSX=CSX_IN
CSY=CSY_IN
IF(LHFB)THEN
CSX=CSX/2.0
CSY=CSY/2.0
ENDIF
N_IN=N
IF(.NOT.INTERSECT_EQUATION(XMIN,XMAX,YMIN,YMAX,X1,X2,Y1,Y2,N)) RETURN
!## find search box - result can be negative, does not matter!
IF(X1.LT.XMIN)THEN
XMN=XMIN
ELSE
I=1
XMN=XMIN+CSX*(INT((X1-XMIN)/CSX)+I)
ENDIF
IF(X2.GT.XMAX)THEN
XMX=XMAX
ELSE
I=0
DX=X2-XMIN
IF(MOD(DX,CSX).EQ.0.0)I=-1
XMX=XMIN+CSX*(INT((X2-XMIN)/CSX)+I)
ENDIF
Y=MIN(Y1,Y2)
IF(Y.LT.YMIN)THEN
YMN=YMIN
ELSE
I =0
DY=YMAX-Y
IF(MOD(DY,CSY).EQ.0.0)I=-1
YMN=YMAX-CSY*(INT((YMAX-Y)/CSY)+I)
ENDIF
Y=MAX(Y1,Y2)
IF(Y.GT.YMAX)THEN
YMX=Y
ELSE
I =1
YMX=YMAX-CSY*(INT((YMAX-Y)/CSY)+I)
ENDIF
!## not for horizontal lines
IF(IHOR.EQ.0)THEN
!## continue seach rest of intersections
!## try intersections with x-axes firstly
Y=YMN-CSY
DO
Y=Y+CSY
IF(Y.GT.YMX)EXIT
!## array overwritten
N=N+1; CALL INTERSECT_RESIZEVECTORS(N) !,XA,YA,ZA,FA,LN,CA,RA)
IF(IVER.EQ.1)THEN
XA(N)=X1 !## same as xmx
ELSE
XA(N)=(Y-B)/A
ENDIF
YA(N)=Y
ENDDO
ENDIF
!## not for vertical lines
IF(IVER.EQ.0)THEN
!## try intersections with y-axes secondly
X=XMN-CSX
DO
X=X+CSX
IF(X.GT.XMX)EXIT
!## array overwritten
N=N+1; CALL INTERSECT_RESIZEVECTORS(N) !,XA,YA,ZA,FA,LN,CA,RA)
XA(N)=X
IF(IHOR.EQ.1)THEN
YA(N)=Y1 !## same as ymx
ELSE
YA(N)=A*X+B
ENDIF
ENDDO
ENDIF
CSX=CSX_IN
CSY=CSY_IN
DX=X1-X2; DY=Y2-Y1
CALL INTERSECT_SORT(DX,DY,N_IN+1,N)
!## sample each of the point to determine irow/icol, overwrite point with this
!## skip first and last, they represented already by the second and one-last point
DO I=N_IN+2,N
!## mid point
X =(XA(I-1)+XA(I))/2.0
Y =(YA(I-1)+YA(I))/2.0
IF(X.GE.XMIN)THEN
ICOL=INT((X-XMIN)/CSX)+1
ELSE
ICOL=INT((X-XMIN)/CSX)-1
ENDIF
IF(Y.LE.YMAX)THEN
IROW=INT((YMAX-Y)/CSY)+1
ELSE
IROW=INT((YMAX-Y)/CSY)-1
ENDIF
TD=CSX*CSY; ID=0 !## fraction
CALL IMOD_UTL_INTERSECT_NCORNER(ID,TD,XMIN+(ICOL-1)*CSX,YMAX-(IROW-1)*CSY,X,Y,1)
CALL IMOD_UTL_INTERSECT_NCORNER(ID,TD,XMIN+ ICOL *CSX,YMAX-(IROW-1)*CSY,X,Y,2)
CALL IMOD_UTL_INTERSECT_NCORNER(ID,TD,XMIN+ ICOL *CSX,YMAX- IROW *CSY,X,Y,3)
CALL IMOD_UTL_INTERSECT_NCORNER(ID,TD,XMIN+(ICOL-1)*CSX,YMAX- IROW *CSY,X,Y,4)
FA(I-1)=REAL(ID)
DX =XA(I)-XA(I-1)
DY =YA(I)-YA(I-1)
LENG=DX**2.0+DY**2.0; IF(LENG.GT.0.0)LENG=SQRT(LENG)
!## store results in row/column indices
CA(I-1)=REAL(ICOL)
RA(I-1)=REAL(IROW)
LN(I-1)=LENG
END DO
N=N-1
END SUBROUTINE IMOD_UTL_INTERSECT_EQUI
!###======================================================================
SUBROUTINE IMOD_UTL_INTERSECT_NCORNER(ID,TD,X1,Y1,XC,YC,JD)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(INOUT) :: ID
REAL(KIND=8),INTENT(INOUT) :: TD
INTEGER,INTENT(IN) :: JD
REAL(KIND=8),INTENT(IN) :: X1,Y1,XC,YC
REAL(KIND=8) :: D
!## get nearest corner
D=(XC-X1)**2.0+(YC-Y1)**2.0
IF(D.GT.0.0)THEN
D=SQRT(D)
IF(D.LT.TD)THEN
ID=JD
TD=D
ENDIF
ELSE
ID=JD
TD=0.0
ENDIF
END SUBROUTINE IMOD_UTL_INTERSECT_NCORNER
!###======================================================================
SUBROUTINE IMOD_UTL_INTERSECT_NONEQUI(DELR,DELC,NROW,NCOL,XIN1,XIN2,YIN1,YIN2,N,LHFB)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: NROW,NCOL
REAL(KIND=8),INTENT(IN),DIMENSION(0:NCOL) :: DELR
REAL(KIND=8),INTENT(IN),DIMENSION(0:NROW) :: DELC
REAL(KIND=8),INTENT(IN) :: XIN1,XIN2,YIN1,YIN2
INTEGER,INTENT(INOUT) :: N
LOGICAL,INTENT(IN) :: LHFB
REAL(KIND=8) :: X,Y,XMN,XMX,YMN,YMX,DX,DY,LENG,XMIN,YMIN,XMAX,YMAX,X1,X2,Y1,Y2,CS,TD,CSX,CSY
INTEGER :: I,ICOL,IROW,IMN,JMN,ID,N_IN
X1=XIN1; Y1=YIN1; X2=XIN2; Y2=YIN2
IF(.NOT.ASSOCIATED(XA))ALLOCATE(XA(1000)); IF(.NOT.ASSOCIATED(YA))ALLOCATE(YA(1000))
IF(.NOT.ASSOCIATED(FA))ALLOCATE(FA(1000)); IF(.NOT.ASSOCIATED(LN))ALLOCATE(LN(1000))
IF(.NOT.ASSOCIATED(CA))ALLOCATE(CA(1000)); IF(.NOT.ASSOCIATED(RA))ALLOCATE(RA(1000))
XMIN=DELR(0)
XMAX=DELR(NCOL)
YMIN=DELC(NROW)
YMAX=DELC(0)
N_IN=N
IF(.NOT.INTERSECT_EQUATION(XMIN,XMAX,YMIN,YMAX,X1,X2,Y1,Y2,N))RETURN
!## continue search rest of intersections
!## try intersections with y-axes firstly
IMN=0; DO I=1,NROW
IF(DELC(I).GT.MIN(Y1,Y2))THEN; YMN=DELC(I); IMN=I; ENDIF
END DO
JMN=0; DO I=NROW,1,-1
IF(DELC(I).LT.MAX(Y1,Y2))THEN; YMX=DELC(I); JMN=I; ENDIF
END DO
IF(IMN.GT.0.AND.JMN.GT.0)THEN
!## not for horizontal lines
IF(IHOR.EQ.0)THEN
CS=DELC(IMN-1)-DELC(IMN)
IF(LHFB)CS=CS/2.0
Y =YMN-CS
DO
Y=Y+CS
IF(Y.GT.YMX)EXIT
N=N+1; CALL INTERSECT_RESIZEVECTORS(N)
IF(IVER.EQ.1)THEN
XA(N)=X1 !## same as xmx
ELSE
XA(N)=(Y-B)/A
ENDIF
YA(N)=Y
!## double intersections, for better estimate for hfb
IF(LHFB)THEN
Y=Y+CS
!## array overwritten
N=N+1; CALL INTERSECT_RESIZEVECTORS(N)
IF(IVER.EQ.1)THEN
XA(N)=X1 !## same as xmx
ELSE
XA(N)=(Y-B)/A
ENDIF
YA(N)=Y
ENDIF
IMN =IMN-1
!## model is not bigger than line-segment
IF(IMN.LE.0)EXIT
CS=DELC(IMN)-DELC(IMN+1)
IF(LHFB)CS=CS/2.0
ENDDO
ENDIF
ENDIF
!## try intersections with x-axes secondly
IMN=0; DO I=NCOL,1,-1
IF(DELR(I).GT.X1)THEN; XMN=DELR(I); IMN=I; ENDIF
END DO
JMN=0; DO I=0,NCOL
IF(DELR(I).LT.X2)THEN; XMX=DELR(I); JMN=I; ENDIF
END DO
IF(IMN.GT.0.AND.JMN.GT.0)THEN
!## not for vertical lines
IF(IVER.EQ.0)THEN
CS=DELR(IMN-1)-DELR(IMN)
IF(LHFB)CS=CS/2.0
X =XMN-CS
DO
X=X+CS
IF(X.GT.XMX)EXIT
N=N+1; CALL INTERSECT_RESIZEVECTORS(N)
XA(N)=X
IF(IHOR.EQ.1)THEN
YA(N)=Y1 !## same as ymx
ELSE
YA(N)=A*X+B
ENDIF
!## double intersections, for better estimate for hfb
IF(LHFB)THEN
X=X+CS
!## array overwritten
N=N+1; CALL INTERSECT_RESIZEVECTORS(N)
XA(N)=X
IF(IHOR.EQ.1)THEN
YA(N)=Y1 !## same as ymx
ELSE
YA(N)=A*X+B
ENDIF
ENDIF
IMN =IMN+1
!## model is not bigger than line-segment
IF(IMN.GT.NCOL)EXIT
CS=DELR(IMN)-DELR(IMN-1)
IF(LHFB)CS=CS/2.0
ENDDO
ENDIF
ENDIF
!## sort intersections, determined by the one with the largest difference
DX=X1-X2; DY=Y2-Y1
CALL INTERSECT_SORT(DX,DY,N_IN+1,N)
!## sample each of the point to determine irow/icol, overwrite point with this
!## skip first and last, they represented already by the second and one-last point
DO I=N_IN+2,N
!## mid point
X =(XA(I-1)+XA(I))/2.0
Y =(YA(I-1)+YA(I))/2.0
CALL IMOD_UTL_POL1LOCATED(DELR,NCOL+1,REAL(X,8),ICOL)
CALL IMOD_UTL_POL1LOCATED(DELC,NROW+1,REAL(Y,8),IROW)
ID=0 !## fraction
IF(ICOL.GE.1.AND.ICOL.LE.NCOL.AND. &
IROW.GE.1.AND.IROW.LE.NROW)THEN
CSX=DELR(ICOL)-DELR(ICOL-1)
CSY=DELC(IROW-1)-DELC(IROW)
TD=CSX*CSY
CALL IMOD_UTL_INTERSECT_NCORNER(ID,TD,DELR(ICOL-1),DELC(IROW-1),X,Y,1)
CALL IMOD_UTL_INTERSECT_NCORNER(ID,TD,DELR(ICOL) ,DELC(IROW-1),X,Y,2)
CALL IMOD_UTL_INTERSECT_NCORNER(ID,TD,DELR(ICOL) ,DELC(IROW) ,X,Y,3)
CALL IMOD_UTL_INTERSECT_NCORNER(ID,TD,DELR(ICOL-1),DELC(IROW) ,X,Y,4)
ELSE
ICOL=0; IROW=0
ENDIF
FA(I-1)=REAL(ID)
DX =XA(I)-XA(I-1)
DY =YA(I)-YA(I-1)
LENG=DX**2.0+DY**2.0; IF(LENG.GT.0.0)LENG=SQRT(LENG)
!## store results in row/column indices
CA(I-1)=REAL(ICOL)
RA(I-1)=REAL(IROW)
LN(I-1)=LENG
END DO
N=N-1
END SUBROUTINE IMOD_UTL_INTERSECT_NONEQUI
!###======================================================================
SUBROUTINE INTERSECT_NULLIFY()
!###======================================================================
IMPLICIT NONE
NULLIFY(XA,YA,FA,LN,CA,RA)
END SUBROUTINE INTERSECT_NULLIFY
!###======================================================================
SUBROUTINE INTERSECT_DEALLOCATE()
!###======================================================================
IMPLICIT NONE
IF(ASSOCIATED(XA))DEALLOCATE(XA)
IF(ASSOCIATED(YA))DEALLOCATE(YA)
IF(ASSOCIATED(FA))DEALLOCATE(FA)
IF(ASSOCIATED(LN))DEALLOCATE(LN)
IF(ASSOCIATED(CA))DEALLOCATE(CA)
IF(ASSOCIATED(RA))DEALLOCATE(RA)
END SUBROUTINE INTERSECT_DEALLOCATE
!###======================================================================
SUBROUTINE INTERSECT_RESIZEVECTORS(N)
!###======================================================================
IMPLICIT NONE
INTEGER,PARAMETER :: DN=100
INTEGER,INTENT(IN) :: N
INTEGER :: MM,NN,I
IF(N.LE.SIZE(XA))RETURN
NN=SIZE(XA)
MM=NN+DN
ALLOCATE(XA_DUMMY(MM),YA_DUMMY(MM),FA_DUMMY(MM),LN_DUMMY(MM),CA_DUMMY(MM),RA_DUMMY(MM))
DO I=1,NN
XA_DUMMY(I)=XA(I)
YA_DUMMY(I)=YA(I)
FA_DUMMY(I)=FA(I)
LN_DUMMY(I)=LN(I)
CA_DUMMY(I)=CA(I)
RA_DUMMY(I)=RA(I)
ENDDO
DEALLOCATE(XA,YA,FA,LN,CA,RA)
XA=>XA_DUMMY
YA=>YA_DUMMY
FA=>FA_DUMMY
LN=>LN_DUMMY
CA=>CA_DUMMY
RA=>RA_DUMMY
END SUBROUTINE INTERSECT_RESIZEVECTORS
!###======================================================================
LOGICAL FUNCTION INTERSECT_EQUATION(XMIN,XMAX,YMIN,YMAX,X1,X2,Y1,Y2,N)
!###======================================================================
IMPLICIT NONE
REAL(KIND=8),INTENT(IN) :: XMIN,XMAX,YMIN,YMAX
REAL(KIND=8),INTENT(INOUT) :: X1,X2,Y1,Y2
INTEGER,INTENT(INOUT) :: N
REAL(KIND=8) :: X,Y,DX,DY
INTERSECT_EQUATION=.FALSE.
XBEGIN=X1; YBEGIN=Y1
!## arrange x1,x2,y1,y2 such that x1