!! Copyright (C) Stichting Deltares, 2005-2020.
!!
!! 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 MOD_UTL
USE MOD_DBL
USE WINTERACTER
USE RESOURCE
USE MOD_CONFIG
USE MOD_PREF_PAR
USE MODPLOT
USE MOD_IDF_PAR
USE MOD_POLINT
USE IMODVAR
USE MOD_OSD
USE MOD_QKSORT
!## max. number of messages
INTEGER,PARAMETER :: MXMESSAGE=16
INTEGER,DIMENSION(MXMESSAGE) :: IMESSAGE
INTEGER,PARAMETER :: MAXUNITS=10000
CHARACTER(LEN=256),ALLOCATABLE,DIMENSION(:) :: LISTNAME
INTEGER,ALLOCATABLE,DIMENSION(:) :: ILIST
CHARACTER(LEN=2),PARAMETER :: NEWLINE=CHAR(13)//CHAR(10)
INTEGER,PARAMETER :: MAXLEN=52
CHARACTER(LEN=MAXLEN),POINTER,DIMENSION(:,:) :: VAR=>NULL(),VAR_TMP=>NULL(),DVAR=>NULL()
CHARACTER(LEN=MAXLEN),POINTER,DIMENSION(:) :: CCNST=>NULL()
INTEGER,ALLOCATABLE,DIMENSION(:) :: ICOL_VAR,IACT_VAR
!## max. variables/max. lines
INTEGER :: NV,NL,IV
TYPE PROCOBJ
INTEGER,DIMENSION(2) :: IFLAGS
INTEGER :: ID
CHARACTER(LEN=52) :: CID
END TYPE PROCOBJ
REAL(KIND=DP_KIND),PARAMETER,PRIVATE :: SDAY=86400.0D0
REAL(KIND=DP_KIND),DIMENSION(20) :: SXVALUE,SYVALUE
INTEGER :: NSX,NSY
CONTAINS
!###======================================================================
SUBROUTINE UTL_SETUP_ROTATIONMATRIX(R,ROT)
!###======================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN),DIMENSION(3) :: R
REAL(KIND=DP_KIND),DIMENSION(3,3),INTENT(OUT) :: ROT
REAL(KIND=DP_KIND) :: A,B,C
A=R(1); B=R(2); C=R(3)
ROT(1,1)= COS(A)*COS(B)
ROT(2,1)=(COS(A)*SIN(B)*SIN(C))-(SIN(A)*COS(C))
ROT(3,1)=(COS(A)*SIN(B)*COS(C))+(SIN(A)*SIN(C))
ROT(1,2)= SIN(A)*COS(B)
ROT(2,2)=(SIN(A)*SIN(B)*SIN(C))+(COS(A)*COS(C))
ROT(3,2)=(SIN(A)*SIN(B)*COS(C))-(COS(A)*SIN(C))
ROT(1,3)=-SIN(B)
ROT(2,3)=(COS(B)*SIN(C))
ROT(3,3)=(COS(B)*COS(C))
END SUBROUTINE UTL_SETUP_ROTATIONMATRIX
!#####=================================================================
SUBROUTINE UTL_GETIROWICOL(NODE,NROW,NCOL,ILAY,IROW,ICOL)
!#####=================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: NODE
INTEGER,INTENT(IN) :: NROW,NCOL
INTEGER,INTENT(OUT) :: ILAY,IROW,ICOL
INTEGER :: N
N=NODE
ILAY=N/(NCOL*NROW); IF(MOD(N,NCOL*NROW).NE.0)ILAY=ILAY+1
N=N-((ILAY-1)*NROW*NCOL)
IROW=N/NCOL; IF(MOD(N,NCOL).NE.0)IROW=IROW+1
N=N-((IROW-1)*NCOL)
ICOL=N
END SUBROUTINE UTL_GETIROWICOL
!#####=================================================================
SUBROUTINE UTL_MATMUL(A,B,C)
!#####=================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),DIMENSION(:,:),INTENT(IN) :: A
REAL(KIND=DP_KIND),DIMENSION(:,:),INTENT(IN) :: B
REAL(KIND=DP_KIND),DIMENSION(:,:),INTENT(OUT) :: C
INTEGER :: NCA,NRA,NCB,NRB,NCC,NRC,I,J,K
REAL(KIND=DP_KIND),ALLOCATABLE,DIMENSION(:,:) :: AT,BT,CT
NCA=SIZE(A,1); NRA=SIZE(A,2)
NCB=SIZE(B,1); NRB=SIZE(B,2)
NCC=SIZE(C,1); NRC=SIZE(C,2)
!## check
IF(NCA.NE.NRB)THEN; WRITE(*,*) 'COLUMN DIMENSIONS ARRAY A NEED TO BE EQUAL TO ROWS ARRAY B'; PAUSE; STOP; ENDIF
IF(NRA.NE.NRC)THEN; WRITE(*,*) 'ROWS DIMENSIONS ARRAY A NEED TO BE EQUAL TO ROWS ARRAY C'; PAUSE; STOP; ENDIF
IF(NCB.NE.NCC)THEN; WRITE(*,*) 'COLUMN DIMENSIONS ARRAY B NEED TO BE EQUAL TO COLUMN ARRAY C'; PAUSE; STOP; ENDIF
ALLOCATE(AT(NRA,NCA))
ALLOCATE(BT(NRB,NCB))
ALLOCATE(CT(NRC,NCC))
AT=TRANSPOSE(A)
BT=TRANSPOSE(B)
CT=TRANSPOSE(C)
CT=MATMUL(AT,BT)
C=TRANSPOSE(CT)
DEALLOCATE(AT,BT,CT)
RETURN
C=0.0D0
DO I=1,NCB; DO J=1,NRC
DO K=1,NCA
C(I,J)=C(I,J)+A(K,J)*B(I,K)
ENDDO
ENDDO; ENDDO
! C=MATMUL(A,B)
! C=0.0D0
! DO J=1,NRC
! DO K=1,NRA !SIZE(A,DIM=2)
! DO I=1,NCC
! C(I,J)=C(I,J)+A(I,K)*B(K,J)
! END DO
! END DO
! END DO
! L=SIZE(C,DIM=2)
! ICHUNK=512 ! I HAVE A 3MB CACHE SIZE (REAL*4)
! DO JJ=1,N,ICHUNK
! DO KK=1,L,ICHUNK
!
! DO J=JJ,MIN(JJ+ICHUNK-1,N)
! DO K=KK,MIN(KK+ICHUNK-1,L)
! DO I=1,M
! C(I,J)=C(I,J)+A(I,K)*B(K,J)
! END DO
! END DO
! END DO
!
! END DO
!END DO
END SUBROUTINE UTL_MATMUL
!###======================================================================
SUBROUTINE UTL_MF2005_MAXNO(FNAME,NP)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN),DIMENSION(:) :: NP
CHARACTER(LEN=*),INTENT(IN) :: FNAME
INTEGER :: I,IU,JU,IOS
CHARACTER(LEN=12) :: NAN
CHARACTER(LEN=256) :: LINE
IU=UTL_GETUNIT(); CALL OSD_OPEN(IU,FILE=FNAME ,STATUS='OLD' ,ACTION='READ' ,FORM='FORMATTED'); IF(IU.EQ.0)RETURN
JU=UTL_GETUNIT(); CALL OSD_OPEN(JU,FILE=FNAME(:LEN_TRIM(FNAME)-1),STATUS='UNKNOWN',ACTION='WRITE',FORM='FORMATTED'); IF(JU.EQ.0)RETURN
DO
READ(IU,'(A256)',IOSTAT=IOS) LINE; IF(IOS.NE.0)EXIT
IF(INDEX(LINE,'NaN').GT.0)THEN
DO I=1,SIZE(NP)
NAN='NaN'//TRIM(ITOS(I))//'#'
IF(INDEX(LINE,TRIM(NAN)).GT.0)LINE=UTL_SUBST(LINE,TRIM(NAN),ITOS(NP(I)))
ENDDO
ENDIF
WRITE(JU,'(A)') TRIM(LINE)
ENDDO
CLOSE(IU,STATUS='DELETE'); CLOSE(JU)
END SUBROUTINE UTL_MF2005_MAXNO
!###======================================================================
REAL(KIND=SP_KIND) FUNCTION UTL_D2R(X,PLACES)
!###======================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: X
INTEGER,INTENT(IN) :: PLACES
UTL_D2R = ANINT(X*(10.D0**PLACES))/(10.D0**PLACES)
END FUNCTION UTL_D2R
!###======================================================================
LOGICAL FUNCTION UTL_DRAWPOLYGON(XPOL,YPOL,MAXPOL,NPOL)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: MAXPOL
INTEGER,INTENT(OUT) :: NPOL
REAL(KIND=DP_KIND),DIMENSION(MAXPOL),INTENT(INOUT) :: XPOL,YPOL
INTEGER :: ITYPE
TYPE(WIN_MESSAGE) :: MESSAGE
LOGICAL :: LEX
REAL(KIND=DP_KIND) :: XC1,YC1,MOUSEX,MOUSEY
UTL_DRAWPOLYGON=.FALSE.
CALL WCURSORSHAPE(ID_CURSORPOLYGON)
NPOL=1
CALL IGRPLOTMODE(MODEXOR)
CALL IGRCOLOURN(WRGB(255,255,255))
CALL IGRFILLPATTERN(OUTLINE)
LEX=.FALSE.
DO
CALL WMESSAGE(ITYPE,MESSAGE)
MOUSEX=DBLE(MESSAGE%GX)+OFFSETX
MOUSEY=DBLE(MESSAGE%GY)+OFFSETY
SELECT CASE (ITYPE)
!## mouse-move
CASE (MOUSEMOVE)
CALL WINDOWSELECT(0)
CALL WINDOWOUTSTATUSBAR(1,'X:'//TRIM(RTOS(MOUSEX,'F',3))//' m, Y:'//TRIM(RTOS(MOUSEY,'F',3))//' m')
XC1=MOUSEX; YC1=MOUSEY
IF(NPOL.GT.1)THEN
CALL UTL_PLOT1BITMAP()
IF(LEX)CALL UTL_PLOTPOLYGON(SIZE(XPOL),NPOL,XPOL,YPOL)
LEX=.TRUE.
XPOL(NPOL)=XC1; YPOL(NPOL)=YC1
CALL UTL_PLOTPOLYGON(SIZE(XPOL),NPOL,XPOL,YPOL)
CALL UTL_PLOT2BITMAP()
ENDIF
CASE (MOUSEBUTDOWN)
CALL UTL_PLOT1BITMAP()
IF(LEX)CALL UTL_PLOTPOLYGON(SIZE(XPOL),NPOL,XPOL,YPOL)
SELECT CASE (MESSAGE%VALUE1)
!## left button
CASE (1)
XPOL(NPOL:NPOL+1)=XC1; YPOL(NPOL:NPOL+1)=YC1; NPOL=NPOL+1
CALL UTL_PLOTPOLYGON(SIZE(XPOL),NPOL,XPOL,YPOL)
CALL UTL_PLOT2BITMAP()
!## right button
CASE (3)
NPOL=NPOL-1
CALL UTL_PLOT2BITMAP()
EXIT
END SELECT
!## bitmap scrolled, renew top-left pixel coordinates
CASE (BITMAPSCROLLED)
MPW%IX=MESSAGE%VALUE1
MPW%IY=MESSAGE%VALUE2
END SELECT
END DO
CALL WCURSORSHAPE(CURARROW)
CALL IGRPLOTMODE(MODECOPY)
CALL IGRFILLPATTERN(OUTLINE)
UTL_DRAWPOLYGON=.TRUE.
END FUNCTION UTL_DRAWPOLYGON
!###======================================================================
SUBROUTINE UTL_PLOTPOLYGON(MAXPOL,NPOL,XPOL,YPOL)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: NPOL,MAXPOL
REAL(KIND=DP_KIND),INTENT(IN),DIMENSION(MAXPOL) :: XPOL,YPOL
IF(NPOL.EQ.2)THEN
CALL DBL_IGRJOIN(XPOL(1),YPOL(1),XPOL(2),YPOL(2),IOFFSET=1)
ELSE
CALL DBL_IGRPOLYGONCOMPLEX(XPOL,YPOL,NPOL,IOFFSET=1)
ENDIF
END SUBROUTINE UTL_PLOTPOLYGON
!###======================================================================
SUBROUTINE UTL_GETMIDPOINT(X,Y,N,XMID,YMID)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: N
REAL(KIND=DP_KIND),INTENT(IN),DIMENSION(N) :: X,Y
REAL(KIND=DP_KIND),INTENT(OUT) :: XMID,YMID
REAL(KIND=DP_KIND) :: X1,Y1,X2,Y2,DX,DY
INTEGER :: I,J,ISTEP
XMID=(MAXVAL(X)+MINVAL(X))/2.0D0
YMID=(MAXVAL(Y)+MINVAL(Y))/2.0D0
!## check whether point is inside polygon, if not try others - but limited, could be a line as polygon!
IF(DBL_IGRINSIDEPOLYGON(XMID,YMID,X,Y,N).NE.1)THEN
ISTEP=10
DOLOOP: DO
X1=MINVAL(X); Y1=MINVAL(Y)
X2=MAXVAL(X); Y2=MAXVAL(Y)
DX=(X2-X1)/REAL(ISTEP,8)
DY=(Y2-Y1)/REAL(ISTEP,8)
YMID=Y1
DO I=1,ISTEP
YMID=YMID+DY
XMID=X1
DO J=1,ISTEP
XMID=XMID+DX
IF(DBL_IGRINSIDEPOLYGON(XMID,YMID,X,Y,N).EQ.1)EXIT DOLOOP
ENDDO
ENDDO
ISTEP=ISTEP+1
IF(ISTEP.GT.10)EXIT
ENDDO DOLOOP
ENDIF
END SUBROUTINE UTL_GETMIDPOINT
!###======================================================================
SUBROUTINE UTL_CLEANLINE(LINE)
!###======================================================================
IMPLICIT NONE
INTEGER :: I
CHARACTER(LEN=*),INTENT(INOUT) :: LINE
DO; I=INDEX(TRIM(LINE),'>'); IF(I.EQ.0)EXIT; LINE(I:I)=' '; ENDDO
!## probably :-delimited
IF(INDEX(TRIM(LINE),';').GT.0)THEN
!## replace "," for "."
DO; I=INDEX(TRIM(LINE),','); IF(I.EQ.0)EXIT; LINE(I:I)='.'; ENDDO
DO; I=INDEX(TRIM(LINE),';'); IF(I.EQ.0)EXIT; LINE(I:I)=','; ENDDO
ENDIF
DO; I=INDEX(TRIM(LINE),' '); IF(I.EQ.0)EXIT; LINE(I:I)='_'; ENDDO
DO; I=INDEX(TRIM(LINE),'/'); IF(I.EQ.0)EXIT; LINE(I:I)='|'; ENDDO
END SUBROUTINE UTL_CLEANLINE
!###======================================================================
INTEGER FUNCTION UTL_DETERMINEIDFTYPE(XMIN,YMIN,XMAX,YMAX,CSIZE,NCOL,NROW)
!###======================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: XMIN,YMIN,XMAX,YMAX,CSIZE
INTEGER,INTENT(IN) :: NCOL,NROW
REAL(KIND=SP_KIND) :: XSMAX,YSMAX
INTEGER :: I
!## determine whether it need to be a double precision IDF file
XSMAX=REAL(XMIN,4); DO I=1,NCOL; XSMAX=XSMAX+REAL(CSIZE,4); ENDDO
YSMAX=REAL(YMIN,4); DO I=1,NROW; YSMAX=YSMAX+REAL(CSIZE,4); ENDDO
UTL_DETERMINEIDFTYPE=4
IF(.NOT.UTL_EQUALS_REAL(XMAX,REAL(XSMAX,8)).OR. &
.NOT.UTL_EQUALS_REAL(YMAX,REAL(YSMAX,8)))UTL_DETERMINEIDFTYPE=8
END FUNCTION UTL_DETERMINEIDFTYPE
!###======================================================================
INTEGER FUNCTION UTL_SELECTIEDGE(X,Y,XA1,YA1,XA2,YA2)
!###======================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: X,Y,XA1,YA1,XA2,YA2
REAL(KIND=DP_KIND) :: MIND,WX1,WX2,WY1,WY2
INTEGER :: IEDGE
INTEGER,DIMENSION(10) :: IDCURSOR
DATA IDCURSOR/CURARROW, ID_CURSORMOVELEFTRIGHT,ID_CURSORMOVELEFTRIGHT,ID_CURSORMOVEUPDOWN,ID_CURSORMOVEUPDOWN, &
ID_CURSORMOVENESW,ID_CURSORMOVENWSE, ID_CURSORMOVENESW, ID_CURSORMOVENWSE, ID_CURSORMOVE/
WX1=REAL(WINFOGRREAL(GRAPHICSUNITMINX),8) ! (7) left limit of main graphics area
WY1=REAL(WINFOGRREAL(GRAPHICSUNITMINY),8) ! (8) lower limit of main graphics area
WX2=REAL(WINFOGRREAL(GRAPHICSUNITMAXX),8) ! (9) right limit of main graphics area
WY2=REAL(WINFOGRREAL(GRAPHICSUNITMAXY),8) ! (10) upper limit of main graphics area
MIND=MIN(WX2-WX1,WY2-WY1)/250.0D0
IEDGE=0
IF(UTL_DIST(X,Y,XA1,YA1).LE.MIND)IEDGE=5
IF(UTL_DIST(X,Y,XA2,YA1).LE.MIND)IEDGE=6 !## lrc
IF(UTL_DIST(X,Y,XA2,YA2).LE.MIND)IEDGE=7 !## urc
IF(UTL_DIST(X,Y,XA1,YA2).LE.MIND)IEDGE=8 !## ulc
IF(IEDGE.EQ.0)THEN
IF(ABS(X-XA1).LE.MIND)THEN
IF(Y.GE.YA1.AND.Y.LE.YA2)IEDGE=1 !## west
ENDIF
IF(ABS(X-XA2).LE.MIND)THEN
IF(Y.GE.YA1.AND.Y.LE.YA2)IEDGE=2 !## east
ENDIF
IF(ABS(Y-YA1).LE.MIND)THEN
IF(X.GE.XA1.AND.X.LE.XA2)IEDGE=3 !## south
ENDIF
IF(ABS(Y-YA2).LE.MIND)THEN
IF(X.GE.XA1.AND.X.LE.XA2)IEDGE=4 !## north
ENDIF
ENDIF
IF(IEDGE.EQ.0)THEN
MIND=MIND*5.0D0
IF(UTL_DIST(X,Y,XA1,YA1).LE.MIND)IEDGE=9
IF(UTL_DIST(X,Y,XA2,YA1).LE.MIND)IEDGE=9
IF(UTL_DIST(X,Y,XA2,YA2).LE.MIND)IEDGE=9
IF(UTL_DIST(X,Y,XA1,YA2).LE.MIND)IEDGE=9
ENDIF
!## select something else
IF(WINFOMOUSE(MOUSECURSOR).NE.IDCURSOR(IEDGE+1))THEN
CALL WCURSORSHAPE(IDCURSOR(IEDGE+1))
ENDIF
UTL_SELECTIEDGE=IEDGE
END FUNCTION UTL_SELECTIEDGE
!###===============================================================================
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=UTL_GETUNIT()
OPEN(IU,FILE=FNAME,STATUS='OLD',FORM='UNFORMATTED',ACTION='READ',ACCESS='STREAM',IOSTAT=IOS)
IF(IOS.NE.0)RETURN
READ(IU,IOSTAT=IOS) IBYTE
!## record length
IF(IOS.EQ.0)UTL_GETRECORDLENGTH=(IBYTE-247)/256 !## in bytes
CLOSE(IU)
IF(UTL_GETRECORDLENGTH.LE.0)THEN
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'iMOD read recordlength of '//TRIM(ITOS(UTL_GETRECORDLENGTH)),'Error')
ENDIF
END FUNCTION UTL_GETRECORDLENGTH
!###===============================================================================
SUBROUTINE UTL_PLOTLINE(X,Z1,Z2,THICKNESS)
!###===============================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: THICKNESS
REAL(KIND=DP_KIND),INTENT(IN) :: X,Z1,Z2
CALL IGRLINEWIDTH(THICKNESS)
CALL DBL_IGRJOIN(X,Z1,X,Z2)
END SUBROUTINE UTL_PLOTLINE
!###===============================================================================
SUBROUTINE UTL_PLOTPOINT(X,Y,SYMBOL,FCT,LPROF)
!###===============================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: SYMBOL
LOGICAL,INTENT(IN) :: LPROF
REAL(KIND=DP_KIND),INTENT(IN) :: X,Y,FCT
REAL(KIND=DP_KIND) :: XWID,XHGH,CHW,CHH
INTEGER :: IFAM,ISTL,IOFFSET
IFAM=WINFOGRINTEGER(GRTEXTFAMILY)
ISTL=WINFOGRINTEGER(GRTEXTSTYLE)
XWID=REAL(WINFOGRREAL(GRAPHICSCHWIDTH),8)
XHGH=REAL(WINFOGRREAL(GRAPHICSCHHEIGHT),8)
IOFFSET=1; IF(LPROF)IOFFSET=0
CALL UTL_SETTEXTSIZE(CHW,CHH,FCT=FCT*5.0D0,IMARKER=1)
CALL DBL_WGRTEXTFONT(IFAMILY=0,TWIDTH=CHW,THEIGHT=CHH,ISTYLE=0)
CALL DBL_IGRMARKER(X,Y,SYMBOL,IOFFSET=IOFFSET)
END SUBROUTINE UTL_PLOTPOINT
!###===============================================================================
SUBROUTINE UTL_PLOTLABEL(X,Y,STRING,IATTRIB,NATTRIB,TWIDTH,THEIGHT,ATTRIB,LPROF,IEQ,IALIGN,GANGLE,CFORMAT)
!###===============================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: NATTRIB,IEQ,IALIGN
REAL(KIND=DP_KIND),INTENT(IN) :: TWIDTH,THEIGHT
CHARACTER(LEN=*),INTENT(IN),DIMENSION(NATTRIB) :: STRING,ATTRIB
INTEGER,DIMENSION(NATTRIB),INTENT(IN) :: IATTRIB
CHARACTER(LEN=*),INTENT(IN),OPTIONAL :: CFORMAT
LOGICAL,INTENT(IN) :: LPROF
REAL(KIND=DP_KIND),INTENT(IN) :: X,Y
REAL(KIND=DP_KIND),INTENT(IN),OPTIONAL :: GANGLE
REAL(KIND=DP_KIND) :: DX,DY,XC,YC,DXS,DYS
INTEGER :: I,J
CHARACTER(LEN=256) :: LINE,CLABEL
!## nothing to draw
IF(SUM(IATTRIB).EQ.0)RETURN
CALL IGRLINEWIDTH(1)
IF(LPROF)THEN
CALL DBL_WGRTEXTFONT(IFAMILY=TFONT,TWIDTH=TWIDTH*1.5D0,THEIGHT=THEIGHT*1.5D0,ISTYLE=0)
LINE=''
DO I=SIZE(IATTRIB),1,-1
IF(IATTRIB(I).EQ.1)THEN
J=0
IF(IBACKSLASH.EQ.1)THEN
J=INDEX(STRING(I),'\',.TRUE.)
IF(J.GT.0)J=J+1
ENDIF
J=MAX(1,J)
CLABEL=STRING(I)(J:)
!## try to make a nice real
CALL UTL_PLOTLABEL_REAL(CLABEL,CFORMAT)
IF(ILABELNAME.EQ.1)THEN
IF(LEN_TRIM(ATTRIB(I)).GT.0)THEN
LINE=TRIM(LINE)//TRIM(ATTRIB(I))//'= '//TRIM(CLABEL)//';'
ELSE
LINE=TRIM(LINE)//TRIM(CLABEL)//';'
ENDIF
ELSE
LINE=TRIM(LINE)//TRIM(CLABEL)//';'
ENDIF
ENDIF
ENDDO
I=INDEX(LINE,';',.TRUE.)
IF(I.GT.0)LINE(I:I)=''
!## place connection line
IF(PRESENT(GANGLE))THEN
CALL DBL_WGRTEXTORIENTATION(IALIGN=IALIGN,ANGLE=GANGLE)
ELSE
CALL DBL_WGRTEXTORIENTATION(IALIGN=IALIGN,ANGLE=90.0D0)
ENDIF
CALL DBL_WGRTEXTSTRING(X,Y,' '//TRIM(LINE),IOFFSET=1)
ELSE
CALL DBL_WGRTEXTFONT(IFAMILY=TFONT,TWIDTH=TWIDTH,THEIGHT=THEIGHT,ISTYLE=0)
!## size of text character width/height in user units
DXS=WINFOGRREAL(GRAPHICSCHWIDTH)
DYS=WINFOGRREAL(GRAPHICSCHHEIGHT)
IF(PRESENT(GANGLE))THEN
CALL DBL_WGRTEXTORIENTATION(IALIGN=IALIGN,ANGLE=GANGLE)
ELSE
CALL DBL_WGRTEXTORIENTATION(IALIGN=IALIGN,ANGLE=0.0D0)
ENDIF
!## get size of box over labels
DX=0.0D0
DO I=1,SIZE(IATTRIB)
IF(IATTRIB(I).EQ.1)THEN
J=0
IF(IBACKSLASH.EQ.1)THEN
J=INDEX(STRING(I),'\',.TRUE.)
IF(J.GT.0)J=J+1
ENDIF
J=MAX(1,J)
CLABEL=STRING(I)(J:)
!## try to make a nice real
CALL UTL_PLOTLABEL_REAL(CLABEL,CFORMAT)
IF(ILABELNAME.EQ.1)THEN
IF(LEN_TRIM(ATTRIB(I)).GT.0)THEN
DX=MAX(DX,WGRTEXTLENGTH('0'//TRIM(ATTRIB(I))//'= '//TRIM(CLABEL)//'0',0)*DXS)
ELSE
DX=MAX(DX,WGRTEXTLENGTH('0'//TRIM(CLABEL)//'0',0)*DXS)
ENDIF
ELSE
DX=MAX(DX,WGRTEXTLENGTH('0'//TRIM(CLABEL)//'0',0)*DXS)
ENDIF
ENDIF
END DO
!## size of box for text
DXS=DX
DX=(WINFOGRREAL(GRAPHICSUNITMAXX)-WINFOGRREAL(GRAPHICSUNITMINX))/250.0D0
DY= DYS*SUM(IATTRIB)
XC= X+DX
YC= Y-(DY/2.0D0)
DX= WGRTEXTLENGTH('0',0)*WINFOGRREAL(GRAPHICSCHWIDTH)
!## position labels in centre
IF(.TRUE.)THEN
XC=X
YC=Y-1.0D0*DYS
ENDIF
! CALL IGRFILLPATTERN(OUTLINE)
! CALL IGRCOLOURN(WRGB(0,0,0)) !## black
! CALL DBL_IGRRECTANGLE(XC-DX,YC+0.5D0*DYS,XC+DX+DXS,YC-DY-0.5D0*DYS,IOFFSET=1)
DO I=1,SIZE(IATTRIB)
IF(IATTRIB(I).EQ.1)THEN
IF(IEQ.GT.0)THEN
ELSE
CALL IGRFILLPATTERN(SOLID)
CALL IGRCOLOURN(WRGB(0,0,0))
ENDIF
J=0
IF(IBACKSLASH.EQ.1)THEN
J=INDEX(STRING(I),'\',.TRUE.)
IF(J.GT.0)J=J+1
ENDIF
J=MAX(1,J)
CLABEL=STRING(I)(J:)
!## try to make a nice real
CALL UTL_PLOTLABEL_REAL(CLABEL,CFORMAT)
IF(ILABELNAME.EQ.1)THEN
IF(LEN_TRIM(ATTRIB(I)).GT.0)THEN
CALL DBL_WGRTEXTSTRING(XC,YC,TRIM(ADJUSTL(ATTRIB(I)))//'= '//TRIM(ADJUSTL(CLABEL)),IOFFSET=1)
ELSE
CALL DBL_WGRTEXTSTRING(XC,YC,TRIM(ADJUSTL(CLABEL)),IOFFSET=1)
ENDIF
ELSE
CALL DBL_WGRTEXTSTRING(XC,YC,TRIM(ADJUSTL(CLABEL)),IOFFSET=1)
ENDIF
YC=YC-DYS
ENDIF
END DO
ENDIF
END SUBROUTINE UTL_PLOTLABEL
!###===============================================================================
SUBROUTINE UTL_PLOTLABEL_REAL(CLABEL,CFORMAT)
!###===============================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(INOUT) :: CLABEL
CHARACTER(LEN=*),INTENT(IN) :: CFORMAT
INTEGER :: IOS
REAL(DP_KIND) :: X
IF(TRIM(CFORMAT).EQ.'')RETURN
READ(CLABEL,*,IOSTAT=IOS) X
IF(IOS.NE.0)RETURN
IF(INDEX(CFORMAT,'(').GT.0)THEN
WRITE(CLABEL,CFORMAT,IOSTAT=IOS) X
ELSE
IF(INDEX(CFORMAT,'I').GT.0.OR.INDEX(CFORMAT,'I').GT.0)THEN
WRITE(CLABEL,'('//TRIM(CFORMAT)//')',IOSTAT=IOS) INT(X)
ELSE
WRITE(CLABEL,'('//TRIM(CFORMAT)//')',IOSTAT=IOS) X
ENDIF
ENDIF
IF(IOS.NE.0)RETURN
END SUBROUTINE UTL_PLOTLABEL_REAL
subroutine UTL_MODELLHS1(PDELR,ORGNCOL,newncol,&
IC1,IC2,OC1,OC2,INC,fincr,powr,&
NOMINCELL,NOMaxCELL,lclip)
! description:
! ------------------------------------------------------------------------------
!
!
! declaration section
! ------------------------------------------------------------------------------
implicit none
! arguments
INTEGER ORGNCOL,& ! (I) original number of columns
newncol,& ! (O) new number of columns
NOMINCELL,& ! (I) minimum number of cells (rows/columns)
! in an upscaled cell
NOMaxCELL,& ! (I) maximum number of cells (rows/columns)
! in an upscaled cell
IC1,& ! (I) column number 1 of unscaled area
IC2,& ! (I) column number 2 of unscaled area
OC1,& ! (O) column number 1 of scaled area
OC2 ! (O) column number 2 of scaled area
REAL(KIND=DP_KIND) INC,& ! (I) start increment factor
powr ! (I) power
REAL(KIND=DP_KIND) fincr ! (I) factor increment factor
! Used scale factor:
! f=fincr*(x-1)^powr+inc
! step=f*step
! x: cell position offset from AOI
INTEGER PDELR(ORGNCOL) ! (O) pointer from unscaled to scaled
! column numbers
logical lclip ! .true. use clip-edges
! .false. don't use clip edges
! clip edge: first and last upscaled cell
! exist of one unscaled cell
! local variables
INTEGER ISC,L,I,J,ICOL,CCOL,ncel,idir
integer maxscc ! maximum number of rows/columns to put together
real(KIND=DP_KIND) x
REAL(KIND=DP_KIND) STEP,f
! functions
! include files
! program section
! ------------------------------------------------------------------------------
! get Area Of Interest
isc = min(ic1,ic2)
ccol= max(ic1,ic2)
maxscc=nomaxcell
!##ccol fits minimal cell value
I=((INT((CCOL-ISC)/NOMINCELL)+1)*NOMINCELL)-1
CCOL=ISC+I
!##correct if ccol.gt.orgncol:i<0
I=ORGNCOL-CCOL
IF(I.LT.0)THEN
ISC=MAX(1,ISC+I)
CCOL=MAX(1,CCOL+I)
ENDIF
!##correct if ccol.lt.1
I=CCOL-1
IF(I.LT.0)THEN
! ISC =MIN(NCOL,ISC-I)
! CCOL=MIN(NCOL,CCOL-I)
ISC =MIN(ORGNCOL,ISC-I)
CCOL=MIN(ORGNCOL,CCOL-I)
ENDIF
!##computation of column-definition
! Area Of Interest
L=0
I=1
DO ICOL=ISC,CCOL
PDELR(ICOL)=L
! write(*,*) ' AOI icol,L: ',icol,L
I=I+1
IF(I.GT.NOMINCELL)THEN
I=1
L=L+1
ENDIF
END DO
IF(I.NE.1)L=L+1
! Area 'higher' and 'lower' than AOI
! 'lower' part
idir=-1
icol=isc
!--------
j =pdelr(icol)
icol=icol+idir
step=inc
x=1.
do while(icol.ge.1)
ncel=nint(step)*nomincell
ncel=min(ncel,maxscc)
j=j+idir
do i=icol,min(orgncol,max(icol+idir*(ncel-1),1)),idir
! write(*,*) ' i,j,ncel,step: ',i,j,ncel,step
pdelr(i)=j
! write(*,*) ' LOW icol,L: ',icol,L
enddo
icol=icol+idir*ncel
if (ncel.lt.maxscc) then
x=x+ncel
f=fincr*(x-1.)**powr+inc
step=f*step
endif
enddo
! 'upper' part
idir=+1
icol=ccol
!--------
j =pdelr(icol)
icol=icol+idir
step=inc
x=1.
do while(icol.le.orgncol)
ncel=nint(step)*nomincell
ncel=min(ncel,maxscc)
j=j+idir
do i=icol,min(orgncol,max(icol+idir*(ncel-1),1)),idir
! write(*,*) ' i,j,ncel,step: ',i,j,ncel,step
pdelr(i)=j
! write(*,*) ' UPP icol,L: ',icol,L
enddo
icol=icol+idir*ncel
if (ncel.lt.maxscc) then
x=x+ncel
f=fincr*(x-1.)**powr+inc
step=f*step
endif
enddo
! when clip option is active (lclip=.true.)
! The outermost active upscaled cell must consist at only 1 unscaled cell!
if (lclip) then
! set edge cells to a width of 1
if (pdelr(1).eq.pdelr(2)) then
pdelr(1)=pdelr(1)-1
endif
if (pdelr(orgncol).eq.pdelr(orgncol-1)) then
pdelr(orgncol)=pdelr(orgncol)+1
endif
endif
! renumber pdelr to let it undefined with value 1 in pdelr(1)
J=1-PDELR(1)
DO ICOL=1,orgncol
PDELR(ICOL)=PDELR(ICOL)+J
END DO
! assign number of scaled are cells
newncol=PDELR(orgncol)
! Area Of Interest in scaled area
! oc1=PDELR(ic1)
oc1=PDELR(min(size(pdelr),ic1))
! oc2=PDELR(ic2)
oc2=PDELR(min(size(pdelr),ic2))
! write(*,*) ' UTL_MODELLHS: nnew nold AOI ',newncol,orgncol,ic1,ic2
! write(*,*) PDELR
! end of program
end subroutine UTL_MODELLHS1
!###======================================================================
INTEGER FUNCTION UTL_GETUNITIPF(IPFNAME,TSTAT)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: IPFNAME
CHARACTER(LEN=*),INTENT(IN) :: TSTAT
LOGICAL :: LEX,LOPEN
CHARACTER(LEN=10) :: TSTATUS
TSTATUS=UTL_CAP(TSTAT,'U')
UTL_GETUNITIPF=0
INQUIRE(FILE=IPFNAME,OPENED=LOPEN)
IF(LOPEN)THEN
INQUIRE(FILE=IPFNAME,NUMBER=UTL_GETUNITIPF)
CLOSE(UTL_GETUNITIPF)
ENDIF
IF(TRIM(TSTATUS).EQ.'OLD')THEN
INQUIRE(FILE=IPFNAME,EXIST=LEX)
IF(.NOT.LEX)THEN
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'Cannot find'//CHAR(13)//TRIM(IPFNAME),'Warning')
RETURN
ENDIF
UTL_GETUNITIPF=UTL_GETUNIT()
CALL OSD_OPEN(UTL_GETUNITIPF,FILE=IPFNAME,STATUS=TSTATUS,FORM='FORMATTED',ACTION='READ,DENYWRITE')
ELSEIF(TRIM(TSTATUS).EQ.'UNKNOWN')THEN
INQUIRE(FILE=IPFNAME,EXIST=LEX)
IF(LEX)THEN
ENDIF
UTL_GETUNITIPF=UTL_GETUNIT()
CALL OSD_OPEN(UTL_GETUNITIPF,FILE=IPFNAME,STATUS=TSTATUS,FORM='FORMATTED',ACTION='WRITE,DENYREAD')
ENDIF
END FUNCTION UTL_GETUNITIPF
!###=========================================================================
SUBROUTINE UTL_GETHELP(TOPIC,CTOPIC)
!###=========================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: TOPIC,CTOPIC
LOGICAL :: LEX,LACROBAT
INTEGER :: ISTATUS,IEXCOD
CHARACTER(LEN=256) :: LINE
!## error/warning checking
IF(PREFVAL(4).EQ.'')THEN
CALL WMESSAGEBOX(OKONLY,COMMONOK,EXCLAMATIONICON,'You should specify the keyword HELPFILE in the Preference file of iMOD.'// &
'E.g. HELPFILE=D:\IMOD\HELP.PDF','Warning')
RETURN
ENDIF
INQUIRE(FILE=PREFVAL(4),EXIST=LEX)
IF(.NOT.LEX)THEN
CALL WMESSAGEBOX(OKONLY,COMMONOK,EXCLAMATIONICON,'Cannot find the specified HELPFILE='//TRIM(PREFVAL(4)),'Warning')
RETURN
ENDIF
LACROBAT=.TRUE.
!## acrobat reader
IF(PREFVAL(13).EQ.'')THEN
CALL WMESSAGEBOX(OKONLY,COMMONOK,EXCLAMATIONICON,'You should specify the keyword ACROBATREADER in the Preference file of iMOD.'// &
'E.g. ACROBATREADER=c:\Program Files (x86)\Adobe\Reader 11.0D0\Reader\AcroRd32.exe','Warning')
RETURN
ENDIF
INQUIRE(FILE=PREFVAL(13),EXIST=LEX)
IF(.NOT.LEX)THEN
CALL WMESSAGEBOX(OKONLY,COMMONOK,EXCLAMATIONICON,'Cannot find the specified ACROBATREADER='//TRIM(PREFVAL(13)),'Warning')
RETURN
ENDIF
!## acrobat reader
IF(LACROBAT)THEN
LINE='"'//TRIM(PREFVAL(13))//'" /A "nameddest='//TRIM(CTOPIC)//'" "'//TRIM(PREFVAL(4))//'"'
!## sumatra pdf
ELSE
LINE='"'//TRIM(PREFVAL(13))//'" -reuse-instance -named-dest sec:'//TRIM(CTOPIC)//' "'//TRIM(PREFVAL(4))//'"'
ENDIF
IF(IDPROC(1).NE.0)THEN
CALL IOSCOMMANDCHECK(IDPROC,ISTATUS,IEXCOD=IEXCOD)
!## killed
IF(ISTATUS.EQ.0)THEN
!## still running, kill it
ELSEIF(ISTATUS.EQ.1)THEN
CALL IOSCOMMANDKILL(IDPROC,0)
ENDIF
ENDIF
CALL IOSCOMMAND(LINE,PROCSILENT,IDPROC=IDPROC)
END SUBROUTINE UTL_GETHELP
!###================================================================================
SUBROUTINE UTL_STOREZOOMEXTENT()
!###================================================================================
IMPLICIT NONE
INTEGER :: I,J,N
ZM%IZOOM=ZM%IZOOM+1
ZM%NZOOM=ZM%IZOOM
N=SIZE(ZM%ZOOMXY,1)
IF(ZM%NZOOM.GT.N)THEN
ALLOCATE(ZM%ZOOMXY_BU(N+10,4))
DO I=1,N
DO J=1,4; ZM%ZOOMXY_BU(I,J)=ZM%ZOOMXY(I,J); ENDDO
ENDDO
IF(ASSOCIATED(ZM%ZOOMXY))DEALLOCATE(ZM%ZOOMXY)
ZM%ZOOMXY=>ZM%ZOOMXY_BU
ENDIF
ZM%ZOOMXY(ZM%NZOOM,1)=MPW%XMIN
ZM%ZOOMXY(ZM%NZOOM,2)=MPW%YMIN
ZM%ZOOMXY(ZM%NZOOM,3)=MPW%XMAX
ZM%ZOOMXY(ZM%NZOOM,4)=MPW%YMAX
END SUBROUTINE UTL_STOREZOOMEXTENT
!###======================================================================
SUBROUTINE UTL_TIMING(IBDT,IEDT,ELSEC)
!###======================================================================
IMPLICIT NONE
INTEGER, DIMENSION(8), INTENT(IN) :: IBDT,IEDT
REAL(KIND=DP_KIND), INTENT(OUT) :: ELSEC
INTEGER, PARAMETER :: NSPD = 86400
INTEGER, DIMENSION(12) :: IDPM(12)
DATA IDPM/31,28,31,30,31,30,31,31,30,31,30,31/ ! DAYS PER MONTH
INTEGER :: NDAYS, LEAP, IBD, IED, MB, ME, MC, M, NM
!## calculate elapsed time in days and seconds
NDAYS=0
LEAP=0
IF (MOD(IEDT(1),4).EQ.0) LEAP = 1
IBD = IBDT(3) ! begin day
IED = IEDT(3) ! end day
! find days
IF (IBDT(2).NE.IEDT(2)) THEN
! months differ
MB = IBDT(2) ! begin month
ME = IEDT(2) ! end month
NM = ME-MB+1 ! number of months to look at
IF (MB.GT.ME) NM = NM+12
MC=MB-1
DO 10 M=1,NM
MC=MC+1 ! MC IS CURRENT MONTH
IF (MC.EQ.13) MC = 1
IF (MC.EQ.MB) THEN
NDAYS = NDAYS+IDPM(MC)-IBD
IF (MC.EQ.2) NDAYS = NDAYS + LEAP
ELSEIF (MC.EQ.ME) THEN
NDAYS = NDAYS+IED
ELSE
NDAYS = NDAYS+IDPM(MC)
IF (MC.EQ.2) NDAYS = NDAYS + LEAP
ENDIF
10 CONTINUE
ELSEIF (IBD.LT.IED) THEN
! start and end in same month, only account for days
NDAYS = IED-IBD
ENDIF
ELSEC=NDAYS*NSPD
!
!## add or subtract seconds
ELSEC = ELSEC+(IEDT(5)-IBDT(5))*3600.0D0
ELSEC = ELSEC+(IEDT(6)-IBDT(6))*60.0D0
ELSEC = ELSEC+(IEDT(7)-IBDT(7))
ELSEC = ELSEC+(IEDT(8)-IBDT(8))*0.01D0
END SUBROUTINE UTL_TIMING
!###======================================================================
SUBROUTINE UTL_MINTHICKNESS(TOP,BOT,HK,VK,VA, &
TOP_BU,BOT_BU,HK_BU,VK_BU,VA_BU,BND,TH,MINTHICKNESS,NLAY,ICOL,IROW)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: NLAY,ICOL,IROW
INTEGER, PARAMETER :: DP_KIND=8
INTEGER,INTENT(INOUT),DIMENSION(NLAY) :: BND
REAL(KIND=DP_KIND),INTENT(INOUT),DIMENSION(NLAY) :: TOP,BOT,HK,VK,VA,TOP_BU,BOT_BU,HK_BU,VK_BU,VA_BU
REAL(KIND=DP_KIND),INTENT(INOUT),DIMENSION(NLAY,2) :: TH
REAL(KIND=DP_KIND),INTENT(IN) :: MINTHICKNESS
INTEGER :: ILAY,JLAY
REAL(KIND=DP_KIND) :: T,B,T1,T2,KD,MT,TT1,TT2,DT,TT,TC,KV
INTEGER :: IU,I
CHARACTER(LEN=24) :: FRM
!## make sure no negative-thicknesses in original set
DO ILAY=1,NLAY
IF(BND(ILAY).EQ.0)CYCLE
IF(ILAY.GT.1)TOP(ILAY)=MIN(TOP(ILAY),BOT(ILAY-1))
BOT(ILAY)=MIN(TOP(ILAY),BOT(ILAY))
ENDDO
TH=0.0D0
!## get thickness of aquifers
DO ILAY=1,NLAY; IF(BND(ILAY).EQ.0)CYCLE; TH(ILAY,1)=TOP(ILAY)-BOT(ILAY); ENDDO
!## get thickness of aquitards
DO ILAY=1,NLAY-1; IF(BND(ILAY).EQ.0.OR.BND(ILAY+1).EQ.0)CYCLE; TH(ILAY,2)=BOT(ILAY)-TOP(ILAY+1); ENDDO
!## need to have data
DO ILAY=1,NLAY
IF(BND(ILAY).NE.0)THEN
IF(TH(ILAY,1).GT.0.0D0)THEN
IF(HK(ILAY).LE.0.0D0)THEN
WRITE(*,'(A,4I5,F15.7)') 'HK',ICOL,IROW,ILAY,BND(ILAY),HK(ILAY)
BND(ILAY)=0; TH(ILAY,1)=0.0D0
ENDIF
IF(VA(ILAY).LE.0.0D0)THEN
WRITE(*,'(A,4I5,F15.7)') 'VA',ICOL,IROW,ILAY,BND(ILAY),VA(ILAY)
BND(ILAY)=0; TH(ILAY,1)=0.0D0
ENDIF
ENDIF
IF(TH(ILAY,2).GT.0.0D0)THEN
IF(VK(ILAY).LE.0.0D0)THEN
WRITE(*,'(A,4I5,F15.7)') 'VK',ICOL,IROW,ILAY,BND(ILAY),VK(ILAY)
TH(ILAY,2)=0.0D0
ENDIF
ENDIF
ENDIF
ENDDO
!## nothing to do
IF(SUM(TH(:,1))+SUM(TH(:,2)).EQ.0.0D0)RETURN
!## make backup
DO ILAY=1,NLAY
TOP_BU(ILAY)=TOP(ILAY); BOT_BU(ILAY)=BOT(ILAY); HK_BU(ILAY)=HK(ILAY); VA_BU(ILAY)=VA(ILAY)
IF(ILAY.LT.NLAY)VK_BU(ILAY) =VK(ILAY)
ENDDO
!## total thickness
TT1=0.0D0; TT2=0.0D0; DO ILAY=1,NLAY
IF(BND(ILAY).NE.0)THEN
TT1=TT1+TH(ILAY,1)
IF(ILAY.LE.NLAY)TT2=TT2+TH(ILAY,2)
ENDIF
ENDDO
!## minimal appropriate layer thickness
MT=(TT1+TT2)/DBLE(NLAY); MT=MIN(MINTHICKNESS,MT)
!## remove everything - model here is too thin
IF(MT.LT.0.25D0*MINTHICKNESS)THEN
DO ILAY=1,NLAY
BND(ILAY)=0
TOP(ILAY)=TOP(1)
BOT(ILAY)=TOP(1)
HK(ILAY)=0.0D0
VA(ILAY)=0.0D0
VK(ILAY)=0.0D0
ENDDO
RETURN
ENDIF
!## adjust thicknesses
DO ILAY=1,NLAY
!## skip inactive
IF(BND(ILAY).EQ.0)CYCLE
IF(TH(ILAY,1).LT.MT)THEN
DT=MT-TH(ILAY,1); TH(ILAY,1)=MT
!## reduce for this correction
DO JLAY=ILAY,NLAY
!## possible to correct from aquitard
TT=0.0D0
IF(JLAY.LT.NLAY)THEN
TT=TH(JLAY,2)-DT
IF(TT.GT.0.0D0)THEN
TT=DT
!## limited space
ELSE
TT=DT+TT
ENDIF
TH(JLAY,2)=TH(JLAY,2)-TT
ENDIF
!## reduced to be corrected quantity, stop if all corrected
DT=DT-TT; IF(DT.LE.0.0D0)EXIT
TT=0.0D0
!## possible to correct from aquifer
IF(JLAY.GT.ILAY)THEN
TT=TH(JLAY,1)-DT
!## enough space
IF(TT.GT.0.0D0)THEN
TT=DT
!## limited space
ELSE
TT=DT+TT
ENDIF
TH(JLAY,1)=TH(JLAY,1)-TT
ENDIF
!## reduced to be corrected quantity, stop if all corrected
DT=DT-TT; IF(DT.LE.0.0D0)EXIT
ENDDO
ENDIF
ENDDO
!## recompute new top/bottoms
DO ILAY=1,NLAY
IF(BND(ILAY).EQ.0)CYCLE
IF(ILAY.GT.1)TOP(ILAY)=BOT(ILAY-1)-TH(ILAY-1,2)
BOT(ILAY)=TOP(ILAY)-TH(ILAY,1)
ENDDO
!## may never exceed bottom
DO JLAY=NLAY,1,-1; IF(BND(JLAY).NE.0)EXIT; ENDDO
!## include aquitard
IF(JLAY.EQ.NLAY)THEN
TT=BOT_BU(JLAY)
ELSE
TT=TOP_BU(JLAY+1)
ENDIF
!## set all below to this "new" base
DO ILAY=JLAY+1,NLAY
BOT(ILAY)=TT; TOP(ILAY)=TT
ENDDO
DO ILAY=JLAY,1,-1
BOT(ILAY)=MAX(BOT(ILAY),TT)
TT=TT+MT
TOP(ILAY)=MAX(TOP(ILAY),TT)
ENDDO
TH=0.0D0
!## get thickness of aquifers
DO ILAY=1,NLAY; IF(BND(ILAY).EQ.0)CYCLE; TH(ILAY,1)=TOP(ILAY)-BOT(ILAY); ENDDO
!## get thickness of aquitards
DO ILAY=1,NLAY-1; IF(BND(ILAY).EQ.0)CYCLE; TH(ILAY,2)=BOT(ILAY)-TOP(ILAY+1); ENDDO
!## correct permeabilities for aquifers - leave k-aquitard intact
DO ILAY=1,NLAY
!## skip inactive cells
IF(BND(ILAY).EQ.0)CYCLE
KD=0.0D0
TC=0.0D0
!## add existing aquifers
DO JLAY=1,NLAY
T =MIN(TOP(ILAY),TOP_BU(JLAY))
B =MAX(BOT(ILAY),BOT_BU(JLAY))
TT=T-B
IF(TT.GT.0.0D0)THEN
KD=KD+TT*HK_BU(JLAY)
IF(VA_BU(JLAY).NE.0.0D0.AND.HK_BU(JLAY).NE.0.0D0)THEN
TC=TC+TT/(HK_BU(JLAY)/VA_BU(JLAY))
ENDIF
ENDIF
ENDDO
!## add existing aquitards
DO JLAY=1,NLAY-1
IF(BND(JLAY+1).EQ.0)CYCLE
T =MIN(TOP(ILAY),BOT_BU(JLAY))
B =MAX(BOT(ILAY),TOP_BU(JLAY+1))
TT=T-B
IF(TT.GT.0.0D0)THEN
IF(VK_BU(JLAY).NE.0.0D0)THEN
KD=KD+TT*VK_BU(JLAY)
TC=TC+TT/VK_BU(JLAY)
ENDIF
ENDIF
ENDDO
TT=TOP(ILAY)-BOT(ILAY)
HK(ILAY)=KD/TT
KV=HK(ILAY); IF(TC.NE.0.0D0)KV=TT/TC
VA(ILAY)=HK(ILAY)/KV
ENDDO
!## get thickness of aquifers
TH=0.0D0
DO ILAY=1,NLAY; IF(BND(ILAY).EQ.0)CYCLE; TH(ILAY,1)=TOP(ILAY)-BOT(ILAY); ENDDO
!## get thickness of aquitards
DO ILAY=1,NLAY-1; IF(BND(ILAY).EQ.0)CYCLE; TH(ILAY,2)=BOT(ILAY)-TOP(ILAY+1); ENDDO
!## get total sum of transmissivity
TT=0.0D0; DO ILAY=1,NLAY
IF(BND(ILAY).EQ.0)CYCLE
TT=TT+TH(ILAY,1)*HK(ILAY)
IF(ILAY.LT.NLAY)THEN
IF(BND(ILAY+1).NE.0)TT=TT+TH(ILAY,2)*VK(ILAY)
ENDIF
ENDDO
!## get total vertical resistance
TC=0.0D0; DO ILAY=1,NLAY
IF(BND(ILAY).EQ.0)CYCLE
TC=TC+TH(ILAY,1)/(HK(ILAY)/VA(ILAY))
IF(ILAY.LT.NLAY)THEN
IF(VK(ILAY).NE.0.0D0.AND.BND(ILAY+1).NE.0)TC=TC+TH(ILAY,2)/VK(ILAY)
ENDIF
ENDDO
TT1=TT; TT2=TC
!## get thickness of aquifers
TH=0.0D0
DO ILAY=1,NLAY; IF(BND(ILAY).EQ.0)CYCLE; TH(ILAY,1)=TOP_BU(ILAY)-BOT_BU(ILAY); ENDDO
!## get thickness of aquitards
DO ILAY=1,NLAY-1; IF(BND(ILAY).EQ.0)CYCLE; TH(ILAY,2)=BOT_BU(ILAY)-TOP_BU(ILAY+1); ENDDO
!## get total sum of transmissivity
TT=0.0D0; DO ILAY=1,NLAY
IF(BND(ILAY).EQ.0)CYCLE
TT=TT+TH(ILAY,1)*HK_BU(ILAY)
IF(ILAY.LT.NLAY)THEN
IF(BND(ILAY+1).NE.0)TT=TT+TH(ILAY,2)*VK_BU(ILAY)
ENDIF
ENDDO
!## get total vertical resistance
TC=0.0D0; DO ILAY=1,NLAY
IF(BND(ILAY).EQ.0)CYCLE
IF((HK_BU(ILAY)/VA_BU(ILAY)).GT.0.0D0)TC=TC+TH(ILAY,1)/(HK_BU(ILAY)/VA_BU(ILAY))
IF(ILAY.LT.NLAY)THEN
IF(BND(ILAY+1).NE.0)TC=TC+TH(ILAY,2)/VK_BU(ILAY)
ENDIF
ENDDO
T1=TT; T2=TC
IF(ABS(TT1-T1).GT.0.01D0*T1.OR.ABS(TT2-T2).GT.0.01D0*T2)THEN
IU=UTL_GETUNIT(); OPEN(IU,FILE='VAR.F90',STATUS='UNKNOWN',ACTION='WRITE',FORM='FORMATTED')
WRITE(IU,*) 'ICOL,IROW=',ICOL,IROW
WRITE(FRM,'(A3,I3.3,A10)') '(A,',NLAY,'(I5,A1),A)'
WRITE(IU,FRM) 'DATA BND/',(BND(I),',',I=1,NLAY-1),BND(NLAY),'/'
WRITE(FRM,'(A3,I3.3,A13)') '(A,',NLAY,'(F10.3,A1),A)'
WRITE(IU,FRM) 'DATA TOP/',(TOP(I),',',I=1,NLAY-1),TOP(NLAY),'/'
WRITE(IU,FRM) 'DATA BOT/',(BOT(I),',',I=1,NLAY-1),BOT(NLAY),'/'
WRITE(IU,FRM) 'DATA HK/',(HK(I),',',I=1,NLAY-1),HK(NLAY),'/'
WRITE(IU,FRM) 'DATA VA/',(VA(I),',',I=1,NLAY-1),VA(NLAY),'/'
WRITE(IU,FRM) 'DATA VK/',(VK(I),',',I=1,NLAY-1),VK(NLAY),'/'
WRITE(IU,FRM) 'DATA TOP_BU/',(TOP_BU(I),',',I=1,NLAY-1),TOP_BU(NLAY),'/'
WRITE(IU,FRM) 'DATA BOT_BU/',(BOT_BU(I),',',I=1,NLAY-1),BOT_BU(NLAY),'/'
WRITE(IU,FRM) 'DATA HK_BU/',(HK_BU(I),',',I=1,NLAY-1),HK_BU(NLAY),'/'
WRITE(IU,FRM) 'DATA VA_BU/',(VA_BU(I),',',I=1,NLAY-1),VA_BU(NLAY),'/'
WRITE(IU,FRM) 'DATA VK_BU/',(VK_BU(I),',',I=1,NLAY-1),VK_BU(NLAY),'/'
CLOSE(IU)
IF(ABS(TT1-T1).GT.0.01D0*T1)WRITE(*,'(/1X,A,2F15.7/)') 'Error in consistency check KD ',TT1,T1
IF(ABS(TT2-T2).GT.0.01D0*T2)WRITE(*,'(/1X,A,2F15.7/)') 'Error in consistency check VC ',TT2,T2
ENDIF
! !## minimal horizontal k first layer is 0.5m2/d
! ILAY=1; KD=(TOP(ILAY)-BOT(ILAY))*HK(ILAY)
! F=KD/0.5D0; IF(F.GT.0.0D0.AND.F.LT.1.0D0)HK(ILAY)=HK(ILAY)/F
END SUBROUTINE UTL_MINTHICKNESS
!###======================================================================
SUBROUTINE UTL_MINTHICKNESS_COMPLEX(TOP,BOT,HK,VK,VA, &
TOP_BU,BOT_BU,HK_BU,VK_BU,VA_BU,BND,TH,MINTHICKNESS)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(INOUT),DIMENSION(:) :: BND
REAL(KIND=DP_KIND),INTENT(INOUT),DIMENSION(:) :: TOP,BOT,HK,VK,VA,TOP_BU,BOT_BU,HK_BU,VK_BU,VA_BU
REAL(KIND=DP_KIND),INTENT(INOUT),DIMENSION(:,:) :: TH
REAL(KIND=DP_KIND),INTENT(IN) :: MINTHICKNESS
INTEGER :: NLAY,ILAY,IL !N,IL1,IL2
REAL(KIND=DP_KIND) :: K,T,B,T1,T2,B1,D,KD,VC,MT,F,TT1,TT2 !,K1,K2
NLAY=SIZE(BND)
!## make sure no negative-thicknesses in original set
DO ILAY=1,NLAY
IF(ILAY.GT.1)TOP(ILAY)=MIN(TOP(ILAY),BOT(ILAY-1))
BOT(ILAY)=MIN(TOP(ILAY),BOT(ILAY))
ENDDO
!## clean boundary for zero-thickness layers from the bottom
DO ILAY=NLAY,1,-1
IF(TOP(ILAY)-BOT(ILAY).EQ.0.0D0)THEN
BND(ILAY)=0
ELSE
EXIT
ENDIF
ENDDO
TH=0.0D0
!## get thickness of aquifers
DO ILAY=1,NLAY; TH(ILAY,1)=TOP(ILAY)-BOT(ILAY); ENDDO
!## get thickness of aquitards
DO ILAY=1,NLAY-1; TH(ILAY,2)=BOT(ILAY)-TOP(ILAY+1); ENDDO
!## need to have data
DO ILAY=1,NLAY
IF(TH(ILAY,1).GT.0)THEN
IF(HK(ILAY).LE.0.0)WRITE(*,*) 'HK',HK(ILAY),BND(ILAY)
IF(VA(ILAY).LE.0.0)WRITE(*,*) 'VA',VA(ILAY),BND(ILAY)
ENDIF
IF(TH(ILAY,2).GT.0)THEN
IF(VK(ILAY).LE.0.0)WRITE(*,*) 'VK',VK(ILAY),BND(ILAY)
ENDIF
ENDDO
!## nothing to do
IF(SUM(TH(:,1)).EQ.0.0D0)RETURN
!## make backup
DO ILAY=1,NLAY
TOP_BU(ILAY)=TOP(ILAY); BOT_BU(ILAY)=BOT(ILAY); HK_BU(ILAY)=HK(ILAY); VA_BU(ILAY)=VA(ILAY)
IF(ILAY.LT.NLAY)VK_BU(ILAY) =VK(ILAY)
ENDDO
!## total thickness
TT1=0.0D0; DO ILAY=1,NLAY; TT1=TT1+TH(ILAY,1); IF(ILAY.LE.NLAY)TT1=TT1+TH(ILAY,2); ENDDO
MT=MIN(MINTHICKNESS,TT1/DBLE(NLAY))
!## adjust thicknesses
D=0.0D0
DO ILAY=1,NLAY
!## aquifer to thin
IF(TH(ILAY,1).LT.MT)THEN
!## corrected by
D=D+(MT-TH(ILAY,1)); TH(ILAY,1)=MT
ENDIF
!## so go grab that from an aquitard - might become zero
IF(TH(ILAY,2).GT.0.0)THEN
!## what can be corrected in this aquitard
F=TH(ILAY,2)-D; D=0.0D0; IF(F.LT.0.0D0)D=ABS(F)
TH(ILAY,2)=MAX(0.0D0,F)
ENDIF
ENDDO
!## correct in case new thickness is more than original thickness - use fraction
TT2=0.0D0; DO ILAY=1,NLAY; TT2=TT2+TH(ILAY,1); IF(ILAY.LE.NLAY)TT2=TT2+TH(ILAY,2); ENDDO
IF(TT2.GT.TT1)THEN
F=TT1/TT2
DO ILAY=1,NLAY
TH(ILAY,1)=TH(ILAY,1)*F
TH(ILAY,2)=TH(ILAY,2)*F
ENDDO
ENDIF
!## check total thickness
TT2=0.0D0; DO ILAY=1,NLAY
TT2=TT2+TH(ILAY,1); IF(ILAY.LE.NLAY)TT2=TT2+TH(ILAY,2)
ENDDO
!## recompute all levels from the corrected thicknesses
DO ILAY=1,NLAY
IF(ILAY.GT.1)TOP(ILAY)=BOT(ILAY-1)-TH(ILAY-1,2)
BOT(ILAY)=TOP(ILAY)-TH(ILAY,1)
ENDDO
!## correct permeabilities for aquifers
DO ILAY=1,NLAY
!## skip inactive cells
IF(BND(ILAY).EQ.0)CYCLE
!## current corrected layer
T=TOP(ILAY); B=BOT(ILAY)
!## if layer thickness, leave it - could be possible most lower layer(s)
IF(T-B.LE.0.0D0)THEN
HK(ILAY)=0.0D0; VA(ILAY)=0.0D0
ELSE
KD=0.0D0; VC=0.0D0
DO IL=1,NLAY
!## skip inactive cells
IF(BND(IL).EQ.0)CYCLE
T1=TOP_BU(IL); B1=BOT_BU(IL)
D=MIN(T,T1)-MAX(B,B1)
!## part of aquifer
IF(D.GT.0.0D0)THEN
KD=KD+HK_BU(IL)*D
VC=VC+D/(HK_BU(IL)*VA_BU(IL))
ENDIF
IF(IL.LT.NLAY)THEN
T1=BOT_BU(IL); B1=TOP_BU(IL+1)
D=MIN(T,T1)-MAX(B,B1)
!## part of aquitard
IF(D.GT.0.0D0)THEN
KD=KD+VK_BU(IL)*D
VC=VC+D/(VK_BU(IL))
ENDIF
ENDIF
ENDDO
!## new parameters
HK(ILAY)=KD/(T-B)
K=HK(ILAY); IF(VC.GT.0.0)K=(T-B)/VC
VA(ILAY)=K/HK(ILAY)
ENDIF
ENDDO
!## correct permeabilities for aquitards
DO ILAY=1,NLAY-1
!## skip inactive cells
IF(BND(ILAY).EQ.0.OR.BND(ILAY+1).EQ.0)CYCLE
!## original layer
T=BOT_BU(ILAY); B=TOP_BU(ILAY+1)
!## if layer thickness, leave it - could be possible most lower layer(s)
IF(T-B.GT.0.0D0)THEN
!## previous c
VC=(T-B)/VK_BU(ILAY)
!## current corrected layer
T=BOT(ILAY); B=TOP(ILAY+1)
VK(ILAY)=(T-B)/VC
ENDIF
ENDDO
!## check before and after
!## get thickness of aquifers/aquitards
TH=0.0D0
!## make sure vka is not zero
DO ILAY=1,NLAY; IF(VA(ILAY).LE.0.0D0)VA(ILAY)=1.0D0; ENDDO
!## get total conductance
DO ILAY=1,NLAY; TH(ILAY,1)=TH(ILAY,1)+(TOP(ILAY) -BOT(ILAY) )*HK(ILAY); ENDDO
DO ILAY=1,NLAY-1; TH(ILAY,1)=TH(ILAY,1)+((BOT(ILAY)-TOP(ILAY+1))*VK(ILAY)); ENDDO
!## get total conductance
DO ILAY=1,NLAY; TH(ILAY,2)=TH(ILAY,2)+(TOP_BU(ILAY) -BOT_BU(ILAY) )*HK_BU(ILAY); ENDDO
DO ILAY=1,NLAY-1; TH(ILAY,2)=TH(ILAY,2)+((BOT_BU(ILAY)-TOP_BU(ILAY+1))*VK_BU(ILAY)); ENDDO
!## get total conductances
T1=SUM(TH(:,1)); T2=SUM(TH(:,2))
!## procent
F=100.0D0*(T1/T2); F=ABS(100.0D0-F)
IF(F.GT.0.5D0)THEN
!## get thickness of aquifers
WRITE(*,'(A3,4F9.2)') 'TKD',T1,T2,T2-T1,F
DO ILAY=1,NLAY
WRITE(*,'(I3,8F9.2)') ILAY,TOP(ILAY) ,BOT(ILAY) ,HK(ILAY) ,(TOP(ILAY) -BOT(ILAY)) *HK(ILAY), &
TOP_BU(ILAY),BOT_BU(ILAY),HK_BU(ILAY),(TOP_BU(ILAY)-BOT_BU(ILAY))*HK_BU(ILAY)
ENDDO
ENDIF
END SUBROUTINE UTL_MINTHICKNESS_COMPLEX
!###======================================================================
SUBROUTINE UTL_DRAWELLIPSE(X,Y,DX,DY,A)
!###======================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: X,Y,DX,DY,A
REAL(KIND=DP_KIND) :: THETA,DTHETA
REAL(KIND=DP_KIND) :: XP,YP,AR,FY
AR=A/(360.0D0/(2.0D0*PI))
FY=DY/DX
THETA=0.0D0; DTHETA=PI/50.0D0
DO
CALL UTL_POINTELLIPSE(X,Y,THETA,FY,DX,AR,XP,YP)
IF(THETA.EQ.0.0D0)THEN
CALL DBL_IGRMOVETO(XP,YP,IOFFSET=1)
ELSE
CALL DBL_IGRLINETO(XP,YP,IOFFSET=1)
ENDIF
THETA=THETA+DTHETA
IF(THETA.GT.2.0D0*PI)EXIT
ENDDO
END SUBROUTINE UTL_DRAWELLIPSE
!###======================================================================
SUBROUTINE UTL_POINTELLIPSE(X,Y,THETA,FY,DX,AR,XP,YP)
!###======================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: FY,THETA,DX,AR,X,Y
REAL(KIND=DP_KIND),INTENT(OUT) :: XP,YP
REAL(KIND=DP_KIND) :: XR,YR
!## ellipse
XP= DX*COS(THETA); XR=XP
YP=-FY*DX*SIN(THETA); YR=YP
!## rotation matrix
IF(AR.NE.0.0D0)THEN
XR= COS(AR)*XP-SIN(AR)*YP
YR= SIN(AR)*XP+COS(AR)*YP
! XR= COS(AR)*XP+SIN(AR)*YP
! YR=-SIN(AR)*XP+COS(AR)*YP
ENDIF
XP=X+XR
YP=Y+YR
END SUBROUTINE UTL_POINTELLIPSE
!###======================================================================
LOGICAL FUNCTION UTL_INSIDEELLIPSE(X0,Y0,DX,DY,A,XP,YP)
!###======================================================================
!https://stackoverflow.com/questions/7946187/point-and-ellipse-rotated-position-test-algorithm
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: XP,YP,X0,Y0,DX,DY,A
REAL(KIND=DP_KIND) :: X1,X2,X3,A2,B2,AR
UTL_INSIDEELLIPSE=.FALSE.
AR=A/(360.0D0/(2.0D0*PI))
!## perform backwards rotation
AR=-1.0D0*AR
X1=( (XP-X0)*COS(AR)+(YP-Y0)*SIN(AR) ) **2.0D0
X2=( (XP-X0)*SIN(AR)-(YP-Y0)*COS(AR) ) **2.0D0
A2= DX**2.0D0
B2= DY**2.0D0
X3=X1/A2+X2/B2
UTL_INSIDEELLIPSE=X3.LE.1.0D0
END FUNCTION UTL_INSIDEELLIPSE
!###======================================================================
LOGICAL FUNCTION UTL_INSIDEELLIPSOID(X0,Y0,Z0,XP,YP,ZP,ROT,RAN)
!###======================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: XP,YP,ZP,X0,Y0,Z0
REAL(KIND=DP_KIND),INTENT(IN),DIMENSION(3,3) :: ROT
REAL(KIND=DP_KIND),INTENT(IN),DIMENSION(3) :: RAN
REAL(KIND=DP_KIND),DIMENSION(3) :: X
INTEGER :: I
UTL_INSIDEELLIPSOID=.FALSE.
!## correct for point of origin
X(1)=XP-X0
X(2)=YP-Y0
X(3)=ZP-Z0
!## back-rotation for ellipsoid
X=MATMUL(X,ROT)
!## check whether point is inside ellipsoid
DO I=1,3
IF(RAN(I).EQ.0.0D0)CYCLE
X(I)=X(I)**2.0D0/RAN(I)**2.0D0
ENDDO
UTL_INSIDEELLIPSOID=SUM(X).LE.1.0D0
END FUNCTION UTL_INSIDEELLIPSOID
!###======================================================================
INTEGER FUNCTION UTL_COUNT_COLUMNS(LINE,SEP,BPV,EPV)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: LINE,SEP
INTEGER,DIMENSION(:),OPTIONAL,INTENT(OUT) :: BPV,EPV
INTEGER :: I,J,K,IOUT,NCSEP
CHARACTER(LEN=1),ALLOCATABLE,DIMENSION(:) :: CSEP
NCSEP=LEN_TRIM(SEP); ALLOCATE(CSEP(NCSEP))
DO I=1,NCSEP; CSEP(I)=SEP(I:I); ENDDO
IF(PRESENT(EPV))EPV=0
IF(PRESENT(BPV))THEN; BPV=0; BPV(1)=1; ENDIF
! !## remove duplicate spaces in Line
! DO
! IF(INDEX(LINE,' ').EQ.0)EXIT
! LINE=UTL_SUBST(LINE,' ',' ')
! ENDDO
!## look for first non-blank character
DO I=1,LEN_TRIM(LINE)
IF(LINE(I:I).NE.' ')EXIT
ENDDO
I=I-1
J=1; IOUT=1
DO
I=I+1
DO K=1,NCSEP
IF(LINE(I:I).EQ.CSEP(K).AND.IOUT.EQ.1)THEN
IF(PRESENT(EPV))EPV(J)=I-1
J=J+1
IF(PRESENT(BPV))THEN
IF(J.LE.SIZE(BPV))BPV(J)=I+1
ENDIF
EXIT
ENDIF
ENDDO
!## inside quoted string
IF(LINE(I:I).EQ.CHAR(34).OR. & !'
LINE(I:I).EQ.CHAR(39).OR. & !"
LINE(I:I).EQ.CHAR(96))IOUT=ABS(IOUT-1) !`
!## stop, whole line examined
IF(I.EQ.LEN_TRIM(LINE))EXIT
! !## stop if last character is a comma
! IF(LINE(I:I).EQ.',')EXIT
ENDDO
IF(PRESENT(EPV))THEN
IF(J.LE.SIZE(EPV))EPV(J)=LEN_TRIM(LINE)
ENDIF
!## number of columns is number of comma-delimiters + 1
IF(LINE(I:I).EQ.',')J=J-1
UTL_COUNT_COLUMNS=J
END FUNCTION UTL_COUNT_COLUMNS
!###======================================================================
INTEGER FUNCTION UTL_COUNT_STRINGS(LINE,STRING)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: LINE,STRING
INTEGER :: I,N
!## remove duplicate spaces in Line
I=LEN_TRIM(LINE); N=0
DO
I=INDEX(LINE(:I),TRIM(STRING),BACK=.TRUE.)
IF(I.EQ.0)EXIT; N=N+1; I=I-1; IF(I.LE.0)EXIT
ENDDO
UTL_COUNT_STRINGS=N
END FUNCTION UTL_COUNT_STRINGS
!###======================================================================
LOGICAL FUNCTION UTL_READPOINTER(IU,NPOINTER,IPOINTER,TXT,IOPT,EXCLVALUE,IECHO)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: IOPT,IU !## ioptional
INTEGER,INTENT(IN),OPTIONAL :: EXCLVALUE,IECHO !## wrong value
INTEGER,INTENT(OUT) :: NPOINTER
INTEGER,POINTER,DIMENSION(:) :: IPOINTER
CHARACTER(LEN=*),INTENT(IN) :: TXT
INTEGER :: IOS,I,N,JECHO,I1,I2
CHARACTER(LEN=100*256) :: LINE
JECHO=1; IF(PRESENT(IECHO))THEN
JECHO=IECHO
ENDIF
NPOINTER=0
IF(IOPT.EQ.0)THEN
UTL_READPOINTER=.FALSE.
IF(.NOT.UTL_READINITFILE(TRIM(TXT),LINE,IU,IOPT))RETURN
ELSEIF(IOPT.EQ.1)THEN
UTL_READPOINTER=.TRUE.
IF(.NOT.UTL_READINITFILE(TRIM(TXT),LINE,IU,IOPT))RETURN
ENDIF
I=INDEX(LINE,':')
IF(I.GT.0)THEN
READ(LINE(1:I-1),*) I1
READ(LINE(I+1:),*) I2
N=(I2-I1)+1
ELSE
N=UTL_COUNT_COLUMNS(LINE,',')
ENDIF
IF(ASSOCIATED(IPOINTER))THEN
NPOINTER=SIZE(IPOINTER)
IF(NPOINTER.NE.N)DEALLOCATE(IPOINTER)
ENDIF
NPOINTER=N
IF(.NOT.ASSOCIATED(IPOINTER))ALLOCATE(IPOINTER(NPOINTER))
IF(I.GT.0)THEN
DO I=1,NPOINTER; IPOINTER(I)=I1+I-1; ENDDO; IOS=0
ELSE
READ(LINE,*,IOSTAT=IOS) (IPOINTER(I),I=1,NPOINTER)
ENDIF
IF(IOS.NE.0)THEN
IF(JECHO.EQ.0)CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'ERROR READING '//TRIM(TXT),'Error')
IF(JECHO.EQ.1)WRITE(*,'(/1A/)') 'ERROR READING '//TRIM(TXT)
STOP
ENDIF
IF(JECHO.EQ.1)WRITE(*,'(99A)') TRIM(TXT)//'=',(TRIM(ITOS(IPOINTER(I)))//',',I=1,NPOINTER-1),TRIM(ITOS(IPOINTER(NPOINTER)))
IF(PRESENT(EXCLVALUE))THEN
DO,I=1,NPOINTER
IF(IPOINTER(I).EQ.EXCLVALUE)THEN
DEALLOCATE(IPOINTER); RETURN
ENDIF
ENDDO
ENDIF
UTL_READPOINTER=.TRUE.
END FUNCTION UTL_READPOINTER
!###======================================================================
LOGICAL FUNCTION UTL_READPOINTER_REAL(IU,NPOINTER,XPOINTER,TXT,IOPT,EXCLVALUE,IECHO)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: IOPT,IU !## ioptional
REAL(KIND=DP_KIND),INTENT(IN),OPTIONAL :: EXCLVALUE,IECHO !## wrong value
INTEGER,INTENT(OUT) :: NPOINTER
REAL(KIND=DP_KIND),POINTER,DIMENSION(:) :: XPOINTER
CHARACTER(LEN=*),INTENT(IN) :: TXT
INTEGER :: IOS,I,N,JECHO
CHARACTER(LEN=3*256) :: LINE
JECHO=1; IF(PRESENT(IECHO))THEN
JECHO=IECHO
ENDIF
NPOINTER=0
IF(IOPT.EQ.0)THEN
UTL_READPOINTER_REAL=.FALSE.
IF(.NOT.UTL_READINITFILE(TRIM(TXT),LINE,IU,0))RETURN
ELSEIF(IOPT.EQ.1)THEN
UTL_READPOINTER_REAL=.TRUE.
IF(.NOT.UTL_READINITFILE(TRIM(TXT),LINE,IU,1))RETURN
ENDIF
N=UTL_COUNT_COLUMNS(LINE,',')
IF(ASSOCIATED(XPOINTER))THEN
NPOINTER=SIZE(XPOINTER)
IF(NPOINTER.NE.N)DEALLOCATE(XPOINTER)
! IF(NPOINTER.LT.N)DEALLOCATE(XPOINTER)
ENDIF
NPOINTER=N
IF(.NOT.ASSOCIATED(XPOINTER))ALLOCATE(XPOINTER(NPOINTER))
READ(LINE,*,IOSTAT=IOS) (XPOINTER(I),I=1,NPOINTER)
IF(IOS.NE.0)THEN
IF(JECHO.EQ.0)CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'ERROR READING '//TRIM(TXT),'Error')
IF(JECHO.EQ.1)WRITE(*,'(/1A/)') 'ERROR READING '//TRIM(TXT); STOP
ENDIF
WRITE(*,'(A,99(F10.2,A1))') TRIM(TXT)//'=',(XPOINTER(I),',',I=1,NPOINTER)
IF(PRESENT(EXCLVALUE))THEN
DO,I=1,NPOINTER
IF(XPOINTER(I).EQ.EXCLVALUE)THEN
DEALLOCATE(XPOINTER); RETURN
ENDIF
ENDDO
ENDIF
UTL_READPOINTER_REAL=.TRUE.
END FUNCTION UTL_READPOINTER_REAL
!###======================================================================
LOGICAL FUNCTION UTL_READPOINTER_CHARACTER(IU,NPOINTER,CPOINTER,TXT,IOPT,IECHO)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: IOPT,IU !## ioptional
REAL(KIND=DP_KIND),INTENT(IN),OPTIONAL :: IECHO !## wrong value
INTEGER,INTENT(OUT) :: NPOINTER
CHARACTER(LEN=*),POINTER,DIMENSION(:) :: CPOINTER
CHARACTER(LEN=*),INTENT(IN) :: TXT
INTEGER :: IOS,I,N,JECHO
CHARACTER(LEN=3*256) :: LINE
JECHO=1; IF(PRESENT(IECHO))THEN
JECHO=IECHO
ENDIF
NPOINTER=0
IF(IOPT.EQ.0)THEN
UTL_READPOINTER_CHARACTER=.FALSE.
IF(.NOT.UTL_READINITFILE(TRIM(TXT),LINE,IU,0))RETURN
ELSEIF(IOPT.EQ.1)THEN
UTL_READPOINTER_CHARACTER=.TRUE.
IF(.NOT.UTL_READINITFILE(TRIM(TXT),LINE,IU,1))RETURN
ENDIF
N=UTL_COUNT_COLUMNS(LINE,',')
IF(ASSOCIATED(CPOINTER))THEN
NPOINTER=SIZE(CPOINTER)
IF(NPOINTER.NE.N)DEALLOCATE(CPOINTER)
! IF(NPOINTER.LT.N)DEALLOCATE(CPOINTER)
ENDIF
NPOINTER=N
IF(.NOT.ASSOCIATED(CPOINTER))ALLOCATE(CPOINTER(NPOINTER))
READ(LINE,*,IOSTAT=IOS) (CPOINTER(I),I=1,NPOINTER)
IF(IOS.NE.0)THEN
IF(JECHO.EQ.0)CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'ERROR READING '//TRIM(TXT),'Error')
IF(JECHO.EQ.1)WRITE(*,'(/1A/)') 'ERROR READING '//TRIM(TXT); STOP
ENDIF
WRITE(*,'(A,99(A,A1))') TRIM(TXT)//'=',(TRIM(CPOINTER(I)),',',I=1,NPOINTER)
UTL_READPOINTER_CHARACTER=.TRUE.
END FUNCTION UTL_READPOINTER_CHARACTER
!###======================================================================
SUBROUTINE UTL_MEASUREMAIN()
!###======================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),DIMENSION(:),POINTER :: XCRD,YCRD=>NULL()
INTEGER :: NCRD
IF(ASSOCIATED(XCRD))DEALLOCATE(XCRD)
IF(ASSOCIATED(YCRD))DEALLOCATE(YCRD)
CALL UTL_MEASURE(XCRD,YCRD,NCRD,ID_CURSORDISTANCE)
DEALLOCATE(XCRD,YCRD)
END SUBROUTINE UTL_MEASUREMAIN
!###======================================================================
SUBROUTINE UTL_MEASURE(XCRD,YCRD,NCRD,IDCURSOR)
!###======================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),DIMENSION(:),POINTER,INTENT(INOUT) :: XCRD,YCRD
REAL(KIND=DP_KIND),DIMENSION(:),POINTER :: XCRD_BU,YCRD_BU
REAL(KIND=DP_KIND) :: MOUSEX,MOUSEY
INTEGER,INTENT(IN) :: IDCURSOR
INTEGER,INTENT(OUT) :: NCRD
TYPE(WIN_MESSAGE) :: MESSAGE
INTEGER :: I,ITYPE,MAXCRD
LOGICAL :: LEX
CALL IGRPLOTMODE(MODEXOR); CALL IGRCOLOURN(WRGB(255,255,255))
CALL WCURSORSHAPE(IDCURSOR) !ID_CURSORDISTANCE)
CALL IGRFILLPATTERN(OUTLINE); CALL IGRLINETYPE(SOLIDLINE)
CALL WINDOWOUTSTATUSBAR(2,'Press right mouse button to stop')
MAXCRD=50; ALLOCATE(XCRD(MAXCRD),YCRD(MAXCRD))
LEX =.FALSE.; NCRD=0
DO
CALL WMESSAGE(ITYPE,MESSAGE)
MOUSEX=DBLE(MESSAGE%GX)+OFFSETX
MOUSEY=DBLE(MESSAGE%GY)+OFFSETY
SELECT CASE (ITYPE)
!## mouse-move
CASE (MOUSEMOVE)
CALL WINDOWSELECT(0)
CALL WINDOWOUTSTATUSBAR(1,'X:'//TRIM(RTOS(MOUSEX,'F',3))//' m, Y:'//TRIM(RTOS(MOUSEY,'F',3))//' m')
!## first point set
IF(NCRD.GE.2)THEN
CALL UTL_PLOT1BITMAP()
IF(LEX)CALL UTL_MEASUREPLOTSHAPE(XCRD,YCRD,NCRD)
LEX=.TRUE.; XCRD(NCRD)=MOUSEX; YCRD(NCRD)=MOUSEY
CALL UTL_MEASUREPLOTSHAPE(XCRD,YCRD,NCRD)
CALL UTL_PLOT2BITMAP()
ENDIF
CASE (MOUSEBUTDOWN)
CALL UTL_PLOT1BITMAP()
IF(LEX)CALL UTL_MEASUREPLOTSHAPE(XCRD,YCRD,NCRD)
SELECT CASE (MESSAGE%VALUE1)
!## left button
CASE (1)
!## increase memory
IF(NCRD+2.GT.MAXCRD)THEN
MAXCRD=MAXCRD+50; ALLOCATE(XCRD_BU(MAXCRD),YCRD_BU(MAXCRD))
DO I=1,NCRD; XCRD_BU(I)=XCRD(I); YCRD_BU(I)=YCRD(I); ENDDO
DEALLOCATE(XCRD,YCRD); XCRD=>XCRD_BU; YCRD=>YCRD_BU
ENDIF
NCRD=NCRD+1; IF(NCRD.EQ.1)NCRD=NCRD+1
DO I=NCRD-1,NCRD; XCRD(I)=MOUSEX; YCRD(I)=MOUSEY; ENDDO
CALL UTL_MEASUREPLOTSHAPE(XCRD,YCRD,NCRD)
CALL UTL_PLOT2BITMAP()
!## right button
CASE (3)
EXIT
END SELECT
!## bitmap scrolled, renew top-left pixel coordinates
CASE (BITMAPSCROLLED)
MPW%IX=MESSAGE%VALUE1; MPW%IY=MESSAGE%VALUE2
! CASE (EXPOSE)
! IF(WMENUGETSTATE(ID_PLOTLEGEND,2).EQ.1)CALL LEGPLOT_PLOTUPDATE(.FALSE.)
! CALL DBL_IGRUNITS(MPW%XMIN,MPW%YMIN,MPW%XMAX,MPW%YMAX)
END SELECT
END DO
NCRD=NCRD-1
CALL UTL_PLOT1BITMAP()
CALL UTL_MEASUREPLOTSHAPE(XCRD,YCRD,NCRD)
CALL UTL_MEASUREPLOTSHAPE(XCRD,YCRD,NCRD)
CALL UTL_PLOT2BITMAP()
CALL WCURSORSHAPE(CURARROW); CALL IGRPLOTMODE(MODECOPY)
CALL IGRFILLPATTERN(OUTLINE); CALL IGRLINETYPE(SOLIDLINE)
CALL WINDOWSELECT(0); CALL WINDOWOUTSTATUSBAR(2,''); CALL WINDOWOUTSTATUSBAR(3,''); CALL WINDOWOUTSTATUSBAR(4,'')
END SUBROUTINE UTL_MEASURE
!###======================================================================
SUBROUTINE UTL_MEASUREPLOTSHAPE(XCRD,YCRD,NCRD)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: NCRD
REAL(KIND=DP_KIND),DIMENSION(:),POINTER,INTENT(IN) :: XCRD,YCRD
INTEGER :: I
REAL(KIND=DP_KIND) :: TDIST,DIST
CHARACTER(LEN=256) :: STRING
CHARACTER(LEN=256) :: CDIST,CTDIST
CALL IGRFILLPATTERN(OUTLINE)
CALL DBL_IGRPOLYLINE(XCRD,YCRD,NCRD,IOFFSET=1)
TDIST=0.0D0; DIST =0.0D0
DO I=2,NCRD
DIST =SQRT((XCRD(I)-XCRD(I-1))**2.0D0+(YCRD(I)-YCRD(I-1))**2.0D0)
TDIST=DIST+TDIST
END DO
IF(TDIST.LT.1.0D0)THEN
CTDIST=TRIM(RTOS(TDIST*100.0D0 ,'F',3))//' cm'
ELSEIF(TDIST.LT.1000.0D0)THEN
CTDIST=TRIM(RTOS(TDIST ,'F',3))//' m'
ELSE
CTDIST=TRIM(RTOS(TDIST/1000.0D0,'F',3))//' km'
ENDIF
IF(DIST.LT.1.0D0)THEN
CDIST=TRIM(RTOS(DIST*100.0D0 ,'F',3))//' cm'
ELSEIF(DIST.LT.1000.0D0)THEN
CDIST=TRIM(RTOS(DIST ,'F',3))//' m'
ELSE
CDIST=TRIM(RTOS(DIST/1000.0D0,'F',3))//' km'
ENDIF
STRING='Total distance= '//TRIM(CTDIST)//'; Distance last segment= '//TRIM(CDIST)
CALL WINDOWOUTSTATUSBAR(4,STRING)
END SUBROUTINE UTL_MEASUREPLOTSHAPE
!###======================================================================
SUBROUTINE UTL_GETAXESCALES(XMIN,YMIN,XMAX,YMAX)
!###======================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: XMIN,YMIN,XMAX,YMAX
REAL(KIND=DP_KIND) :: DX,DY,X1,X2,Y1,Y2
INTEGER :: I
!## initially try 20 ticks
NSX=15; DX=UTL_GETNICEAXES(XMAX-XMIN,DBLE(NSX))
NSY=15; DY=UTL_GETNICEAXES(YMAX-YMIN,DBLE(NSY))
!## set first tick-marK
X1= DX*CEILING(XMIN/DX); Y1= DY*CEILING(YMIN/DY)
X2= DX*FLOOR(XMAX/DX); Y2= DY*FLOOR(YMAX/DY)
NSX=(X2-X1)/DX; NSX=NSX+1; NSY=(Y2-Y1)/DY; NSY=NSY+1
SXVALUE(1)=X1; DO I=2,NSX; SXVALUE(I)=SXVALUE(I-1)+DX; ENDDO
SYVALUE(1)=Y1; DO I=2,NSY; SYVALUE(I)=SYVALUE(I-1)+DY; ENDDO
END SUBROUTINE UTL_GETAXESCALES
!###======================================================================
REAL(KIND=DP_KIND) FUNCTION UTL_GETNICEAXES(R,NTIC)
!###======================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: R,NTIC
REAL(KIND=DP_KIND) :: S,M,TIC,RES
S=R/NTIC
M=10.0D0**FLOOR(LOG10(S))
RES=S/M
IF(RES.GT.5.0D0)THEN
TIC=10.0D0*M
ELSEIF(RES.GT.2.0D0)THEN
TIC=5.0D0*M
ELSEIF(RES.GT.1.0D0)THEN
TIC=2.0D0*M
ELSE
TIC=M
ENDIF
UTL_GETNICEAXES=TIC
END FUNCTION UTL_GETNICEAXES
!###======================================================================
CHARACTER(LEN=24) FUNCTION UTL_WRITENUMBER(X)
!###======================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: X
WRITE(UTL_WRITENUMBER,UTL_GETFORMAT(X)) X
END FUNCTION UTL_WRITENUMBER
!###======================================================================
CHARACTER(LEN=32) FUNCTION UTL_GETFORMAT(X)
!###======================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: X
CHARACTER(LEN=32) :: XC
INTEGER :: I,J,K,II,NDEC,NNUM,DIGITS
CHARACTER(LEN=1) :: F
!## number equal to a NaN
IF(X.NE.X.OR.X.GT.HUGE(1.0D0).OR.X.LT.-HUGE(1.0D0))THEN
UTL_GETFORMAT='*'
RETURN
ENDIF
WRITE(XC,'(G18.11)') X
XC=ADJUSTL(XC)
XC=UTL_CAP(XC,'U')
!## determine length of value
I=LEN_TRIM(XC); K=MAX(INDEX(XC,'D'),INDEX(XC,'E')); IF(K.GT.0)I=K-1
!## get numbers before digit
J=INDEX(XC,'.')
IF(J.GT.0)THEN
!## get first non-zero character
DO II=I,J+1,-1
IF(XC(II:II).NE.'0')EXIT
ENDDO
NDEC=MAX(0,II-J)
IF(K.GT.0)NDEC=MAX(NDEC,1)
NNUM=J-1+NDEC+1
ELSE
NDEC=0
NNUM=J-1
ENDIF
F='F'
IF(K.GT.0)THEN
READ(XC(K+2:),*) DIGITS
IF(DIGITS.NE.0)THEN
F='E'
NNUM=NNUM+4
ENDIF
ENDIF
IF(X.LT.0.0D0)NNUM=NNUM+1
WRITE(UTL_GETFORMAT,'(2A1,2(I2.2,A1))') '(',F,NNUM,'.',NDEC,')'
END FUNCTION UTL_GETFORMAT
!###======================================================================
SUBROUTINE UTL_DEBUGLEVEL(IONOFF)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: IONOFF
IF(IONOFF.EQ.0)THEN
CALL IDEBUGLEVEL(DBGSILENT)
ELSE
CALL IDEBUGLEVEL(ICDEBUGLEVEL)
ENDIF
END SUBROUTINE UTL_DEBUGLEVEL
!###====================================================================
FUNCTION UTL_REALTOSTRING(X)
!###====================================================================
IMPLICIT NONE
CHARACTER(LEN=20) :: UTL_REALTOSTRING,FSTRING
REAL(KIND=DP_KIND),INTENT(IN) :: X
INTEGER :: J,NSIG
INTEGER(KIND=DP_KIND) :: I
REAL(KIND=DP_KIND) :: F
CHARACTER(LEN=12) :: FRM
I=INT(X); F=X-I
UTL_REALTOSTRING=TRIM(ITOS_DBL(I))
IF(F.NE.0.0D0)THEN
NSIG=MAX(0,7-LEN_TRIM(UTL_REALTOSTRING))
WRITE(FRM,'(A5,I3.3,A1)') '(F17.',NSIG,')'
WRITE(FSTRING,FRM) F; FSTRING=ADJUSTL(FSTRING)
!## search backwards for first non-zero
DO J=LEN_TRIM(FSTRING),1,-1
IF(FSTRING(J:J).NE.'0')EXIT
ENDDO
IF(F.GT.0.0D0)UTL_REALTOSTRING=TRIM(UTL_REALTOSTRING)//'.'//FSTRING(3:J)
IF(F.LT.0.0D0)UTL_REALTOSTRING=TRIM(UTL_REALTOSTRING)//'.'//FSTRING(4:J)
ENDIF
!## add minus
IF(I.EQ.0.AND.X.LT.0.0D0)UTL_REALTOSTRING='-'//TRIM(UTL_REALTOSTRING)
END FUNCTION UTL_REALTOSTRING
!###====================================================================
SUBROUTINE UTL_RELPATHNAME(PATH,RFNAME,GFNAME)
!###====================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: PATH
CHARACTER(LEN=*),INTENT(INOUT) :: RFNAME
CHARACTER(LEN=*),INTENT(OUT) :: GFNAME
CHARACTER(LEN=256) :: ROOTNAME
!## check relative-pathnames
IF(INDEX(RFNAME,':').EQ.0)THEN
!## if file is given
IF(INDEX(PATH,'.').GT.0)THEN
ROOTNAME=PATH(:INDEX(PATH,'\',.TRUE.)-1)
ELSE
ROOTNAME=PATH
ENDIF
!## clip number of "..\" from the rootname
DO
IF(INDEX(RFNAME,'..\',.FALSE.).EQ.0)THEN
IF(INDEX(RFNAME,'.\',.FALSE.).EQ.0)EXIT
!## one point means same folder
RFNAME=RFNAME(INDEX(RFNAME,'.\',.FALSE.)+2:); EXIT
ELSE
RFNAME=RFNAME(INDEX(RFNAME,'..\',.FALSE.)+3:)
ENDIF
ROOTNAME=ROOTNAME(:INDEX(ROOTNAME,'\',.TRUE.)-1)
ENDDO
!## construct global filename
GFNAME=TRIM(ROOTNAME)//'\'//TRIM(RFNAME)
ELSE
!## drive letter found
GFNAME=RFNAME
ENDIF
!## remove double "\\" if exist
DO
IF(INDEX(GFNAME,'\\').EQ.0)EXIT
GFNAME=UTL_SUBST(GFNAME,'\\','\')
ENDDO
END SUBROUTINE UTL_RELPATHNAME
!###======================================================================
SUBROUTINE UTL_REL_TO_ABS(ROOT,FNAME)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*), INTENT(INOUT) :: ROOT
CHARACTER(LEN=*), INTENT(INOUT) :: FNAME
INTEGER :: M,N,IL
CHARACTER(LEN=1) :: SLASH
LOGICAL :: LREL
N = LEN_TRIM(FNAME)
IF (N==0) RETURN
CALL UTL_GETSLASH(SLASH)
FNAME = ADJUSTL(FNAME)
N = LEN_TRIM(FNAME)
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 UTL_REL_TO_ABS
!###===================================================================
SUBROUTINE UTL_GETSLASH(SLASH)
!###===================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(OUT) :: SLASH
IF(OS.EQ.1)THEN ! DOS
SLASH='\'
ELSEIF(OS.EQ.2)THEN ! UNIX
SLASH='/'
ENDIF
END SUBROUTINE UTL_GETSLASH
!###====================================================================
FUNCTION UTL_IMODVERSION(S1,S2)
!###====================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN),OPTIONAL :: S1,S2
CHARACTER(LEN=156) :: UTL_IMODVERSION
IF(LBETA)THEN
UTL_IMODVERSION=TRIM(BVERSION)//'-iMOD'
ELSE
UTL_IMODVERSION='iMOD'
ENDIF
IF(PRESENT(S1).AND.PRESENT(S2))THEN
UTL_IMODVERSION=TRIM(UTL_IMODVERSION)//' ['//TRIM(UTL_SUBST(RVERSION_EXE,S1,S2))//' '//TRIM(CCONFIG)//']'
ELSE
UTL_IMODVERSION=TRIM(UTL_IMODVERSION)//' ['//TRIM(RVERSION_EXE)//' '//TRIM(CCONFIG)//']'
ENDIF
IF(LEXPDATE)THEN
UTL_IMODVERSION=TRIM(UTL_IMODVERSION)//' !!! Expiring date: '//TRIM(JDATETOGDATE(UTL_IDATETOJDATE(EXPDATE)))//' !!!'
ENDIF
END FUNCTION UTL_IMODVERSION
!###====================================================================
LOGICAL FUNCTION UTL_PCK_READTXT(ICOL,STIME,ETIME,QT,FNAME,INDICATOR,THRESHOLD,ISS,NCOUNT)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: ICOL,INDICATOR,ISS
INTEGER(KIND=8),INTENT(IN) :: STIME,ETIME
CHARACTER(LEN=*),INTENT(IN) :: FNAME,THRESHOLD
REAL(KIND=DP_KIND),INTENT(OUT) :: QT
REAL(KIND=DP_KIND),INTENT(OUT) :: NCOUNT
INTEGER :: IR,I,IU,NR,NC,IOS,ITYPE,IZMAX !,SDATE
REAL(KIND=DP_KIND) :: Q1,QQ,Z,TZ,BZ,DZ,F,Z1,NQ,RTIME,TTIME
INTEGER(KIND=8) :: DBL_SDATE,DBL_EDATE
CHARACTER(LEN=24) :: ATTRIB
CHARACTER(LEN=256) :: LINE
REAL(KIND=DP_KIND),DIMENSION(:),ALLOCATABLE :: NODATA
CHARACTER(LEN=52),DIMENSION(:),ALLOCATABLE :: QD
UTL_PCK_READTXT=.FALSE.
!## transient(2)/steady-state(1)
QT=0.0D0
!## open textfiles with pump information
IU=UTL_GETUNIT()
OPEN(IU,FILE=FNAME,STATUS='OLD',ACTION='READ',FORM='FORMATTED',IOSTAT=IOS)
IF(IOS.NE.0)THEN
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'iMOD cannot find the associated txt file:'//CHAR(13)// &
TRIM(FNAME),'Error')
RETURN
ENDIF
READ(IU,*) NR; IF(NR.LE.0)THEN; CLOSE(IU); UTL_PCK_READTXT=.TRUE.; RETURN; ENDIF
READ(IU,'(A256)') LINE
READ(LINE,*,IOSTAT=IOS) NC,ITYPE
IF(IOS.NE.0)ITYPE=1
ITYPE=MAX(ITYPE,1)
!## what type of file?
SELECT CASE (ITYPE)
!## timeseries
CASE (1)
!## duration in days - transient
IF(ISS.EQ.2)THEN
TTIME=DIFFTIME(STIME,ETIME)
IF(TTIME.LE.0.0D0)THEN
CLOSE(IU); CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'Timestep size to extract data is '//TRIM(RTOS(TTIME,'E',7)),'Error')
RETURN
ENDIF
ENDIF
!## boreholes/seismic
CASE (2,3)
END SELECT
ALLOCATE(NODATA(NC),QD(NC)); QD=''
DO I=1,NC; READ(IU,*) ATTRIB,NODATA(I); ENDDO
!## timeseries
IF(ITYPE.EQ.1)THEN
DBL_SDATE=STIME
QQ=NODATA(ICOL)
NCOUNT=0.0D0
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.NE.NODATA(2))THEN
NCOUNT=NCOUNT+1
QT=QT+QQ
ENDIF
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=DIFFTIME(DBL_SDATE,DBL_EDATE)
!## add only if q ne nodata
IF(QQ.NE.NODATA(ICOL))THEN
QT=QT+RTIME*QQ
NCOUNT=NCOUNT+RTIME
ENDIF
ENDIF
IF(DBL_EDATE.LE.ETIME)THEN
!## get volume
READ(QD(ICOL),*) QQ
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.NODATA(ICOL).AND.IR.GT.NR)THEN
RTIME=DIFFTIME(DBL_SDATE,ETIME)
RTIME=MIN(TTIME,RTIME)
QT=QT+RTIME*QQ
NCOUNT=NCOUNT+RTIME
ENDIF
!## steady-state
IF(NCOUNT.GT.0.0D0)QT=QT/NCOUNT
UTL_PCK_READTXT=.TRUE.
!## itype=2 borehole; itype=3 seismic
ELSEIF(ITYPE.EQ.2.OR.ITYPE.EQ.3)THEN
QQ=0.0D0
!## get elevation in chronologic order
IF(ICOL.EQ.1)THEN
IZMAX=ABS(STIME)
!## get absolute value
DO IR=1,MIN(IZMAX,NR)
READ(IU,*) Z
ENDDO
!## get thickness of layer (stime) until first nodata value
IF(STIME.LT.INT(0,8))THEN
IF(Z.NE.NODATA(1))THEN
Z1=NODATA(1)
IR=MIN(IZMAX,NR)
DO
IR=IR+1; IF(IR.GT.NR)EXIT
READ(IU,*) Z1; IF(Z1.NE.NODATA(1))EXIT
ENDDO
!## get thickness
IF(Z1.NE.NODATA(1))THEN
Z=Z-Z1; IR=IZMAX+1
ELSE
Z=NODATA(1)
ENDIF
ENDIF
ENDIF
QT=Z
IF(Z.NE.NODATA(1).AND.IR.EQ.IZMAX+1)THEN
NCOUNT=1.0D0; UTL_PCK_READTXT=.TRUE.
ENDIF
!## get the average value for the choosen interval
ELSE
NQ=0.0D0; TZ=STIME/100.0D0; BZ=ETIME/100.0D0; DZ=TZ-BZ
IF(DZ.GT.0.0D0)THEN
DO IR=1,NR
READ(IU,*) Z,(QD(I),I=2,NC)
!## get first
IF(IR.GT.1)THEN
!## skip if equal to nodata
IF(Q1.NE.NODATA(ICOL))THEN
!## get fraction
IF(Z1.GE.BZ.AND.Z.LT.TZ)THEN
F=(MIN(TZ,Z1)-MAX(BZ,Z))/DZ
QT=QT+F*Q1
NQ=NQ+F
ENDIF
ENDIF
ENDIF
Z1=Z
!## apply indicator
IF(INDICATOR.GT.0)THEN
Q1=0.0D0; IF(TRIM(UTL_CAP(QD(ICOL),'U')).EQ.TRIM(UTL_CAP(THRESHOLD,'U')))Q1=1.0D0
ELSE
READ(QD(ICOL),*,IOSTAT=IOS) Q1
IF(IOS.NE.0)THEN
IF(IR.LT.NR)THEN
WRITE(*,'(/A/)') 'iMOD cannot read ['//TRIM(QD(ICOL))//'] into a number'; PAUSE; STOP
!## ignore last entry
ELSE
Q1=NODATA(ICOL)
ENDIF
ENDIF
ENDIF
IF(Z.LT.BZ)EXIT
ENDDO
ENDIF
IF(NQ.GT.0.0D0)THEN
NCOUNT=NQ
QT=QT/NQ
UTL_PCK_READTXT=.TRUE.
ENDIF
ENDIF
ENDIF
CLOSE(IU); DEALLOCATE(QD)
END FUNCTION UTL_PCK_READTXT
!###======================================================================
SUBROUTINE UTL_PCK_GETTLP(N,TLP,KH,TOP,BOT,Z1,Z2,MINKHT)
!###======================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),PARAMETER :: MAXPNT=0.0D0
INTEGER,INTENT(IN) :: N
REAL(KIND=DP_KIND),INTENT(IN) :: MINKHT
REAL(KIND=DP_KIND),INTENT(INOUT) :: Z1,Z2
REAL(KIND=DP_KIND),INTENT(IN),DIMENSION(N) :: KH,TOP,BOT
REAL(KIND=DP_KIND),INTENT(INOUT),DIMENSION(N) :: TLP
INTEGER :: ILAY
REAL(KIND=DP_KIND) :: ZM,ZT,ZB,ZC,FC,DZ
REAL(KIND=DP_KIND),ALLOCATABLE,DIMENSION(:) :: L,TL
INTEGER,ALLOCATABLE,DIMENSION(:) :: IL
ALLOCATE(L(N),TL(N),IL(N))
!## not thickness between z1 and z2 - look for correct modellayer
IF(Z1.EQ.Z2)THEN
TLP=0.0D0; ZM=Z1
DO ILAY=1,N
IF(ZM.GE.BOT(ILAY).AND.ZM.LE.TOP(ILAY))THEN
TLP(ILAY)=1.0D0; EXIT
ENDIF
ENDDO
ELSE
!## filterlength for each modellayer
L=0.0D0
DO ILAY=1,N
ZT=MIN(TOP(ILAY),Z1); ZB=MAX(BOT(ILAY),Z2); L(ILAY)=MAX(0.0D0,ZT-ZB)
ENDDO
TLP=0.0D0
!## well within any aquifer(s)
IF(SUM(L).GT.0.0D0)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.0D0)TLP=(1.0D0/SUM(L))*L; ENDDO
ENDIF
!## correct for dismatch with centre of modelcell
DO ILAY=1,N
IF(TLP(ILAY).GT.0.0D0)THEN
DZ= TOP(ILAY)-BOT(ILAY)
ZC=(TOP(ILAY)+BOT(ILAY))/2.0D0
ZT= MIN(TOP(ILAY),Z1)
ZB= MAX(BOT(ILAY),Z2)
FC=(ZT+ZB)/2.0D0
TLP(ILAY)=TLP(ILAY)*(1.0D0-(ABS(ZC-FC)/(0.5D0*DZ)))
ENDIF
ENDDO
!## normalize tlp() again
IF(SUM(TLP).GT.0.0D0)TLP=(1.0D0/SUM(TLP))*TLP
!## remove small transmissivities
IF(MINKHT.GT.0.0D0)THEN
ZT=SUM(TLP)
DO ILAY=1,N
DZ= TOP(ILAY)-BOT(ILAY)
IF(KH(ILAY)*DZ.LT.MINKHT)TLP(ILAY)=0.0D0
ENDDO
IF(SUM(TLP).GT.0.0D0)THEN
ZT=ZT/SUM(TLP); TLP=ZT*TLP
ENDIF
!## normalize tlp() again
IF(SUM(TLP).GT.0.0D0)TLP=(1.0D0/SUM(TLP))*TLP
ENDIF
ENDIF
!## nothing in model, whenever system on top of model, put them in first modellayer with thickness
IF(SUM(TLP).EQ.0.0D0)THEN
IF(Z1.GE.TOP(1))TLP(1)=1.0D0
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.0D0; EXIT; ENDIF
ENDDO
ENDIF
DEALLOCATE(L,TL,IL)
END SUBROUTINE UTL_PCK_GETTLP
!###======================================================================
SUBROUTINE UTL_LISTOFFILES(FNAME_IN,STRING,BACTION,TEXT,HELP)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(OUT) :: BACTION
INTEGER,PARAMETER :: STRLEN=256
INTEGER :: ITYPE
TYPE(WIN_MESSAGE) :: MESSAGE
CHARACTER(LEN=STRLEN),POINTER,DIMENSION(:),INTENT(INOUT) :: FNAME_IN
CHARACTER(LEN=*),INTENT(IN),DIMENSION(6) :: STRING
CHARACTER(LEN=STRLEN),POINTER,DIMENSION(:) :: FNAME=>NULL()
CHARACTER(LEN=STRLEN) :: EFNAME
CHARACTER(LEN=*),INTENT(IN),OPTIONAL :: TEXT
CHARACTER(LEN=256),INTENT(IN),OPTIONAL :: HELP
INTEGER,DIMENSION(:),ALLOCATABLE :: LRLIST,ILIST,JLIST
INTEGER :: N,DID,I,J,NL,NR
DID=WINFODIALOG(CURRENTDIALOG)
!## store copy of filenames
IF(ASSOCIATED(FNAME_IN))THEN
ALLOCATE(FNAME(SIZE(FNAME_IN)))
IF(STRING(1).EQ.'IMODMANAGER')THEN
DO I=1,SIZE(FNAME); FNAME(I)=FNAME_IN(I)(2:); ENDDO
ELSE
DO I=1,SIZE(FNAME); FNAME(I)=FNAME_IN(I); ENDDO
ENDIF
ENDIF
!## define "String" for changing names on push buttons and window title if "String" is available.
IF(STRING(1).EQ.'IMODMANAGER')THEN
CALL WDIALOGLOAD(ID_DLISTOFFILES2,ID_DLISTOFFILES2)
CALL WDIALOGPUTIMAGE(ID_RIGHT,ID_ICONRIGHT,1)
CALL WDIALOGPUTIMAGE(ID_LEFT,ID_ICONLEFT,1)
NR=0; NL=SIZE(FNAME_IN); ALLOCATE(LRLIST(NL),ILIST(NL),JLIST(NL))
!## all on left menu
DO I=1,SIZE(FNAME)
IF(FNAME_IN(I)(1:1).EQ.'-')LRLIST(I)= I
IF(FNAME_IN(I)(1:1).EQ.'+')LRLIST(I)=-I
ENDDO
ELSE
CALL WDIALOGLOAD(ID_DLISTOFFILES1,ID_DLISTOFFILES1)
CALL WDIALOGPUTIMAGE(ID_OPEN,ID_ICONOPEN,1)
CALL WDIALOGPUTIMAGE(ID_DELETE,ID_ICONDELETE,1)
ENDIF
CALL WDIALOGTITLE('Extra files')
IF(LEN_TRIM(STRING(2)).NE.0)CALL WDIALOGTITLE(TRIM(STRING(2))) !## changes title of dialog window
IF(LEN_TRIM(STRING(3)).NE.0)CALL WDIALOGPUTSTRING(IDCANCEL,TRIM(STRING(3))) !## changes text on close-button
IF(LEN_TRIM(STRING(4)).NE.0)CALL WDIALOGPUTSTRING(IDHELP,TRIM(STRING(4))) !## changes text on help-button
IF(LEN_TRIM(STRING(5)).NE.0)CALL WDIALOGPUTSTRING(IDOK,TRIM(STRING(5))) !## changes text on apply-button
IF(LEN_TRIM(STRING(6)).NE.0)CALL WDIALOGPUTSTRING(IDF_STRING1,TRIM(STRING(6))//': '//TRIM(TEXT))!## changes text on text field
IF(.NOT.PRESENT(HELP))CALL WDIALOGFIELDSTATE(IDHELP,3)
IF(STRING(1).EQ.'IMODMANAGER')THEN
CALL UTL_LISTOFFILES_FILLMENU(LRLIST,FNAME,FNAME_IN,ILIST,JLIST)
CALL WDIALOGFIELDSTATE(ID_RIGHT,0)
CALL WDIALOGFIELDSTATE(ID_LEFT,0)
ELSE
CALL UTL_LISTOFFILES_MANIPULATE(FNAME,STRLEN,0,EFNAME)
ENDIF
CALL UTL_DIALOGSHOW(-1,-1,0,3)
BACTION=0
DO
CALL WMESSAGE(ITYPE,MESSAGE)
SELECT CASE (ITYPE)
CASE(FIELDCHANGED)
!## previous field
SELECT CASE (MESSAGE%VALUE1)
CASE (IDF_MENU1)
END SELECT
!## next field
SELECT CASE (MESSAGE%VALUE2)
CASE (IDF_MENU1)
IF(STRING(1).EQ.'IMODMANAGER')THEN
CALL WDIALOGGETMENU(IDF_MENU1,ILIST)
CALL WDIALOGFIELDSTATE(ID_RIGHT,MIN(1,SUM(ILIST)))
ENDIF
CASE (IDF_MENU2)
IF(STRING(1).EQ.'IMODMANAGER')THEN
CALL WDIALOGGETMENU(IDF_MENU2,JLIST)
CALL WDIALOGFIELDSTATE(ID_LEFT,MIN(1,SUM(JLIST)))
ENDIF
END SELECT
CASE(PUSHBUTTON)
SELECT CASE (MESSAGE%VALUE1)
CASE (ID_OPEN)
IF(UTL_WSELECTFILE('Files ('//TRIM(STRING(1))//')|'//TRIM(STRING(1))//'|',LOADDIALOG+MUSTEXIST+PROMPTON+ &
DIRCHANGE+APPENDEXT+MULTIFILE,EFNAME,'Load Files ('//TRIM(STRING(1))//')'))CALL UTL_LISTOFFILES_MANIPULATE(FNAME,STRLEN,1,EFNAME)
CASE (ID_DELETE)
CALL WDIALOGGETMENU(IDF_MENU1,N,EFNAME)
CALL WMESSAGEBOX(YESNO,QUESTIONICON,COMMONNO,'Are you sure to remove the file from the list:'//CHAR(13)// &
TRIM(EFNAME),'Question'); IF(WINFODIALOG(4).EQ.1)CALL UTL_LISTOFFILES_MANIPULATE(FNAME,STRLEN,-1,EFNAME)
CASE (ID_RIGHT,ID_LEFT)
IF(MESSAGE%VALUE1.EQ.ID_RIGHT)THEN
!## get selected files in left menu field
CALL WDIALOGGETMENU(IDF_MENU1,ILIST)
J=0; DO I=1,SIZE(LRLIST)
IF(LRLIST(I).GT.0)THEN
J=J+1; IF(ILIST(J).EQ.1)LRLIST(I)=-1*LRLIST(I)
ENDIF
ENDDO
ELSE
!## get selected files in right menu field
CALL WDIALOGGETMENU(IDF_MENU2,JLIST)
J=0; DO I=1,SIZE(LRLIST)
IF(LRLIST(I).LT.0)THEN
J=J+1; IF(JLIST(J).EQ.1)LRLIST(I)=-1*LRLIST(I)
ENDIF
ENDDO
ENDIF
CALL UTL_LISTOFFILES_FILLMENU(LRLIST,FNAME,FNAME_IN,ILIST,JLIST)
CALL WDIALOGFIELDSTATE(ID_RIGHT,0); CALL WDIALOGFIELDSTATE(ID_LEFT,0)
CASE (IDOK)
BACTION=1
!## copy adjusted filename
IF(STRING(1).EQ.'IMODMANAGER')THEN
NR=0; DO I=1,SIZE(LRLIST)
IF(LRLIST(I).LT.0)THEN; NR=NR+1; FNAME(NR)=FNAME_IN(I); ENDIF
ENDDO
IF(ASSOCIATED(FNAME_IN))DEALLOCATE(FNAME_IN)
ALLOCATE(FNAME_IN(NR)); DO I=1,NR; FNAME_IN(I)=FNAME(I); ENDDO
ELSE
IF(ASSOCIATED(FNAME))THEN
ALLOCATE(FNAME_IN(SIZE(FNAME))); DO I=1,SIZE(FNAME); FNAME_IN(I)=FNAME(I); ENDDO
ENDIF
ENDIF
EXIT
CASE (IDHELP)
CALL UTL_LISTOFFILES_GETHELP(HELP)
CASE (IDCANCEL)
EXIT
END SELECT
END SELECT
ENDDO
IF(ASSOCIATED(FNAME))DEALLOCATE(FNAME)
IF(ALLOCATED(LRLIST))DEALLOCATE(LRLIST)
IF(ALLOCATED(ILIST))DEALLOCATE(ILIST); IF(ALLOCATED(JLIST))DEALLOCATE(JLIST)
CALL WDIALOGUNLOAD(); IF(DID.NE.0)CALL WDIALOGSELECT(DID)
END SUBROUTINE UTL_LISTOFFILES
!###======================================================================
SUBROUTINE UTL_LISTOFFILES_FILLMENU(LRLIST,FNAME,FNAME_IN,ILIST,JLIST)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),DIMENSION(:),INTENT(IN) :: FNAME_IN
CHARACTER(LEN=*),DIMENSION(:),INTENT(OUT) :: FNAME
INTEGER,DIMENSION(:),INTENT(INOUT) :: LRLIST,ILIST,JLIST
INTEGER :: NR,NL,I
!## fill left menu
NL=0; DO I=1,SIZE(LRLIST); IF(LRLIST(I).GT.0)THEN; NL=NL+1; FNAME(NL)=FNAME_IN(I)(INDEX(FNAME_IN(I),'\',.TRUE.)+1:); ENDIF; ENDDO
IF(NL.GT.0)THEN
ILIST=0; CALL WDIALOGPUTMENU(IDF_MENU1,FNAME,NL,ILIST)
CALL WDIALOGFIELDSTATE(IDF_MENU1,1)
ELSE
CALL WDIALOGCLEARFIELD(IDF_MENU1); CALL WDIALOGFIELDSTATE(IDF_MENU1,0)
ENDIF
!## fill right menu
NR=0; DO I=1,SIZE(LRLIST); IF(LRLIST(I).LT.0)THEN; NR=NR+1; FNAME(NR)=FNAME_IN(I)(INDEX(FNAME_IN(I),'\',.TRUE.)+1:); ENDIF; ENDDO
IF(NR.GT.0)THEN
JLIST=0; CALL WDIALOGPUTMENU(IDF_MENU2,FNAME,NR,JLIST)
CALL WDIALOGFIELDSTATE(IDF_MENU2,1)
ELSE
CALL WDIALOGCLEARFIELD(IDF_MENU2); CALL WDIALOGFIELDSTATE(IDF_MENU2,0)
ENDIF
END SUBROUTINE UTL_LISTOFFILES_FILLMENU
!###======================================================================
SUBROUTINE UTL_LISTOFFILES_MANIPULATE(FNAME,STRLEN,IADD,EFNAME)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: IADD,STRLEN
CHARACTER(LEN=STRLEN),INTENT(IN) :: EFNAME
CHARACTER(LEN=STRLEN),POINTER,DIMENSION(:),INTENT(INOUT) :: FNAME
CHARACTER(LEN=STRLEN),POINTER,DIMENSION(:) :: FNAME_BU
INTEGER :: I,J,K,II,ISEL,NFILE
CHARACTER(LEN=256) :: FLIST
CHARACTER(LEN=256),ALLOCATABLE,DIMENSION(:) :: FNAMES
NULLIFY(FNAME_BU)
!## get number of files selected
K=INDEX(EFNAME,CHAR(0))
IF(K.GT.0)THEN
FLIST=EFNAME
NFILE=0
I=K+1
DO WHILE(.TRUE.)
J=INDEX(FLIST(I:),CHAR(0))
NFILE=NFILE+1
IF(J.EQ.0)EXIT
I=I+J
END DO
ELSE
NFILE=1
ENDIF
!## collect filenames
ALLOCATE(FNAMES(NFILE))
DO II=1,NFILE
!## construct new name in multi-file selection mode
IF(NFILE.GT.1)THEN
I=INDEX(FLIST,CHAR(0))+1
DO K=1,II-1
J=INDEX(FLIST(I:),CHAR(0))
I=I+J
END DO
J=INDEX(FLIST(I:),CHAR(0))
K=INDEX(FLIST,CHAR(0))-1
IF(J.EQ.0)THEN
FNAMES(II)=FLIST(:K)//'\'//FLIST(I:)
ELSE
J=J+I
FNAMES(II)=FLIST(:K)//'\'//FLIST(I:J-1)
ENDIF
J=INDEXNOCASE(FNAMES(II),CHAR(0),.TRUE.)
IF(J.GT.0)FNAMES(II)=FNAMES(II)(:J-1)
ELSE
FNAMES(II)=EFNAME
ENDIF
ENDDO
DO II=1,NFILE
!## add file
IF(IADD.EQ.1)THEN
IF(ASSOCIATED(FNAME))THEN
!## check double files
! DO I=1,SIZE(FNAME); IF(TRIM(UTL_CAP(FNAME(I),'U')).EQ.TRIM(UTL_CAP(EFNAME,'U')))EXIT; ENDDO
DO I=1,SIZE(FNAME); IF(TRIM(UTL_CAP(FNAME(I),'U')).EQ.TRIM(UTL_CAP(FNAMES(II),'U')))EXIT; ENDDO
IF(I.LE.SIZE(FNAME))THEN
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'Current file already exists'//CHAR(13)//TRIM(FNAMES(II)),'Error')
! CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'Current file already exists'//CHAR(13)//TRIM(EFNAME),'Error')
RETURN
ELSE
ALLOCATE(FNAME_BU(SIZE(FNAME)+1))
DO I=1,SIZE(FNAME); FNAME_BU(I)=FNAME(I); ENDDO; FNAME_BU(I)=FNAMES(II); ISEL=I
! DO I=1,SIZE(FNAME); FNAME_BU(I)=FNAME(I); ENDDO; FNAME_BU(I)=EFNAME; ISEL=I
DEALLOCATE(FNAME)
ENDIF
ELSE
ALLOCATE(FNAME_BU(1)); FNAME_BU(1)=FNAMES(II); ISEL=1
! ALLOCATE(FNAME_BU(1)); FNAME_BU(1)=EFNAME; ISEL=1
ENDIF
FNAME=>FNAME_BU
!## remove file
ELSEIF(IADD.EQ.-1)THEN
IF(SIZE(FNAME)-1.GT.0)THEN
ALLOCATE(FNAME_BU(SIZE(FNAME)-1))
J=0; DO I=1,SIZE(FNAME)
IF(TRIM(UTL_CAP(FNAME(I),'U')).NE.TRIM(UTL_CAP(FNAMES(II),'U')))THEN
! IF(TRIM(UTL_CAP(FNAME(I),'U')).NE.TRIM(UTL_CAP(EFNAME,'U')))THEN
J=J+1; FNAME_BU(J)=FNAME(I)
ELSE
ISEL=J
ENDIF
ENDDO
DEALLOCATE(FNAME); FNAME=>FNAME_BU
ELSE
DEALLOCATE(FNAME)
ENDIF
ELSE
ISEL=1
ENDIF
ENDDO
IF(ASSOCIATED(FNAME))THEN
CALL WDIALOGPUTMENU(IDF_MENU1,FNAME,SIZE(FNAME),MAX(1,ISEL))
CALL WDIALOGFIELDSTATE(IDF_MENU1,1)
CALL WDIALOGFIELDSTATE(ID_DELETE,1)
ELSE
CALL WDIALOGPUTMENU(IDF_MENU1,(/'Add files ...'/),1,1)
CALL WDIALOGFIELDSTATE(IDF_MENU1,2)
CALL WDIALOGFIELDSTATE(ID_DELETE,2)
ENDIF
END SUBROUTINE UTL_LISTOFFILES_MANIPULATE
!###=========================================================================
SUBROUTINE UTL_LISTOFFILES_GETHELP(HELP)
!###=========================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: HELP
LOGICAL :: LEX
INTEGER :: I
CHARACTER(LEN=256) :: LINE
CHARACTER(LEN=10) :: EXT
!## error/warning checking
IF(TRIM(HELP).EQ.'')THEN
CALL WMESSAGEBOX(OKONLY,COMMONOK,EXCLAMATIONICON,'You should specify the keyword HELP in the *.INI file of the plugin.'// &
'E.g. HELP=D:\Plugin1\WaterbalanceTool\HELP.PDF','Warning')
RETURN
ENDIF
INQUIRE(FILE=TRIM(HELP),EXIST=LEX)
IF(.NOT.LEX)THEN
CALL WMESSAGEBOX(OKONLY,COMMONOK,EXCLAMATIONICON,'Cannot find the specified HELP= '//TRIM(HELP),'Warning')
RETURN
ENDIF
!#find file extension
I=INDEXNOCASE(TRIM(HELP),'.',.TRUE.)
EXT=HELP(I+1:)
!## open help file
IF(UTL_CAP(TRIM(EXT),'U').EQ.'PDF')THEN
!## acrobat reader
IF(PREFVAL(13).EQ.'')THEN
CALL WMESSAGEBOX(OKONLY,COMMONOK,EXCLAMATIONICON,'You should specify the keyword ACROBATREADER in the Preference file of iMOD.'// &
'E.g. ACROBATREADER=c:\Program Files (x86)\Adobe\Reader 11.0D0\Reader\AcroRd32.exe','Warning')
RETURN
ENDIF
INQUIRE(FILE=PREFVAL(13),EXIST=LEX)
IF(.NOT.LEX)THEN
CALL WMESSAGEBOX(OKONLY,COMMONOK,EXCLAMATIONICON,'Cannot find the specified ACROBATREADER='//TRIM(PREFVAL(13)),'Warning')
RETURN
ENDIF
LINE='"'//TRIM(PREFVAL(13))//' '//TRIM(HELP)//'"'
CALL IOSCOMMAND(LINE,PROCSILENT)
ELSEIF(UTL_CAP(TRIM(EXT),'U').EQ.'HTM')THEN
!## webpage
CALL WHELPFILE(TRIM(HELP))
ENDIF
END SUBROUTINE UTL_LISTOFFILES_GETHELP
!###======================================================================
SUBROUTINE UTL_READTXTFILE(FNAME,TEXT)
!###======================================================================
!## Subroutine to read text containing multiple lines
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(INOUT) :: TEXT
CHARACTER(LEN=:),ALLOCATABLE :: LINE
CHARACTER(LEN=*), INTENT(IN) :: FNAME
INTEGER :: IU,IOS,LENTXT
LOGICAL :: LEX
TEXT=''
INQUIRE(FILE=FNAME,EXIST=LEX)
IF(.NOT.LEX)THEN; TEXT='No textfile with additional information found.'; RETURN; ENDIF
IU=UTL_GETUNIT(); CALL OSD_OPEN(IU,FILE=FNAME,STATUS='OLD',ACTION='READ')
IF(IU.EQ.0)RETURN
LENTXT = LEN(TEXT)
ALLOCATE(CHARACTER(LEN=LENTXT) :: LINE)
DO
READ(IU,'(A)',IOSTAT=IOS) LINE
IF(IOS.NE.0)EXIT
IF(LEN_TRIM(TEXT).EQ.0)THEN
TEXT=TRIM(LINE)
ELSE
TEXT=TRIM(TEXT)//CHAR(13)//CHAR(10)//TRIM(LINE)
ENDIF
ENDDO
CLOSE(IU)
DEALLOCATE(LINE)
END SUBROUTINE UTL_READTXTFILE
!###===================================================================
SUBROUTINE UTL_MODEL1CHECKFNAME(FNAME,LU)
!###===================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: LU
CHARACTER(LEN=*),INTENT(IN) :: FNAME
REAL(KIND=DP_KIND) :: X
INTEGER :: IOS,I,J
LOGICAL :: LEX
IF(LEN_TRIM(FNAME).EQ.0)THEN
IF(LU.EQ.0)CALL UTL_PRINTTEXT('No file given',2)
IF(LU.GT.0)THEN
WRITE(LU,*) 'Error:'
WRITE(LU,*) ' No file given'
ENDIF
ENDIF
!get first non character
I=0
DO
I=I+1
J=ICHAR(FNAME(I:I))
IF(J.GT.32)EXIT
ENDDO
X=UTL_GETREAL(FNAME(I:),IOS)
IF(IOS.NE.0)THEN
INQUIRE(FILE=FNAME(I:),OPENED=LEX)
IF(LEX)RETURN
INQUIRE(FILE=FNAME(I:),EXIST=LEX)
IF(.NOT.LEX)THEN
IF(LU.EQ.0)CALL UTL_PRINTTEXT('File '//TRIM(FNAME(I:))//' does not exist !',2)
IF(LU.GT.0)THEN
WRITE(LU,*) 'Error:'
WRITE(LU,*) TRIM(FNAME(I:))//' does not exist!'
ENDIF
ENDIF
ENDIF
END SUBROUTINE UTL_MODEL1CHECKFNAME
!###====================================================================
SUBROUTINE UTL_APPLYFCT_R(A,NODATA,NROW,NCOL,FCT,IMP)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: NROW,NCOL
REAL(KIND=DP_KIND),INTENT(IN) :: FCT,IMP,NODATA
REAL(KIND=DP_KIND),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
END SUBROUTINE UTL_APPLYFCT_R
!###====================================================================
SUBROUTINE UTL_APPLYFCT_I(A,NODATA,NROW,NCOL,FCT,IMP)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: NROW,NCOL
REAL(KIND=DP_KIND),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
END SUBROUTINE UTL_APPLYFCT_I
!###===================================================================
SUBROUTINE UTL_STRING(LINE)
!###===================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(INOUT) :: LINE
CALL UTL_DELNULCHAR(LINE)
CALL UTL_DELCONTROLM(LINE)
END SUBROUTINE UTL_STRING
!###===================================================================
SUBROUTINE UTL_FILENAME(LINE)
!###===================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(INOUT) :: LINE
CALL UTL_SWAPSLASH(LINE)
LINE=ADJUSTL(LINE)
END SUBROUTINE UTL_FILENAME
!###===================================================================
SUBROUTINE UTL_DELNULCHAR(LINE)
!###===================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(INOUT) :: LINE
INTEGER :: I
!## find ^M (null character)
I=INDEX(LINE,CHAR(0))
IF(I.EQ.0)RETURN
!## replace by space
LINE(I:I)=CHAR(32)
END SUBROUTINE UTL_DELNULCHAR
!###===================================================================
SUBROUTINE UTL_DELCONTROLM(LINE)
!###===================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(INOUT) :: LINE
INTEGER :: I
!#find ^M (carriage return)
I=INDEX(LINE,CHAR(13))
IF(I.LE.0)RETURN
!#replace by space
LINE(I:I)=CHAR(32)
END SUBROUTINE UTL_DELCONTROLM
!###===================================================================
REAL(KIND=DP_KIND) FUNCTION UTL_GETREAL(LINE,IOS)
!###===================================================================
IMPLICIT NONE
INTEGER,INTENT(OUT) :: IOS
CHARACTER(LEN=*),INTENT(IN) :: LINE
READ(LINE,*,IOSTAT=IOS) UTL_GETREAL
IF(IOS.NE.0)UTL_GETREAL=0.0D0
END FUNCTION UTL_GETREAL
!###===================================================================
CHARACTER(LEN=256) FUNCTION UTL_GETFNAME(LINE)
!###===================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: LINE
INTEGER :: I,J,K
K=39
I=INDEX(LINE,CHAR(K),.FALSE.) !## '-tje
IF(I.EQ.0)THEN
K=34
I=INDEX(LINE,CHAR(K),.FALSE.) !## "-tje
ENDIF
!## quotes found, find other, to be sure it is consistent
IF(I.GT.0)THEN
J=INDEX(LINE,CHAR(K),.TRUE.)
IF(I.EQ.J)THEN
CALL UTL_PRINTTEXT('',0)
CALL UTL_PRINTTEXT('Missing second quote '//CHAR(K)//' in line:',0)
CALL UTL_PRINTTEXT(TRIM(LINE),0)
CALL UTL_PRINTTEXT('',2)
ENDIF
UTL_GETFNAME=LINE(I+1:J-1)
ELSE
!## search for comma's, backward
I=INDEX(TRIM(LINE),',',.TRUE.)
J=INDEX(TRIM(LINE),' ',.TRUE.)
UTL_GETFNAME=LINE(MAX(I+1,J+1):)
ENDIF
END FUNCTION UTL_GETFNAME
!###===================================================================
SUBROUTINE UTL_SWAPSLASH(LINE)
!###===================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(INOUT) :: LINE
INTEGER :: I,IFR,ITO
IF(OS.EQ.1)THEN
IFR=47
ITO=92
ELSEIF(OS.EQ.2)THEN
IFR=92
ITO=47
ENDIF
DO
I=INDEX(LINE,CHAR(IFR))
IF(I.EQ.0)EXIT
LINE(I:I)=CHAR(ITO)
ENDDO
END SUBROUTINE UTL_SWAPSLASH
!###======================================================================
SUBROUTINE UTL_DIR_LEVEL_UP(FNAME)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*), INTENT(INOUT) :: FNAME
INTEGER :: N
N = LEN_TRIM(FNAME)
IF (N==0) RETURN
IF (FNAME(1:1)=='.')THEN
WRITE(FNAME,'(2A)') '..\',TRIM(FNAME)
END IF
CALL UTL_SWAPSLASH(FNAME)
END SUBROUTINE UTL_DIR_LEVEL_UP
!###===================================================================
SUBROUTINE UTL_PRINTTEXT(TXT,TXTTYPE)
!###===================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: TXT
INTEGER,INTENT(IN) :: TXTTYPE
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)
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,TRIM(TXT),'Error')
CASE DEFAULT
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,TRIM(TXT),'Error')
END SELECT
END SUBROUTINE UTL_PRINTTEXT
!###======================================================================
SUBROUTINE UTL_GET_ANGLES(X,Y,Z,RX,RY,RZ)
!###======================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: X,Y,Z
REAL(KIND=DP_KIND),INTENT(OUT) :: RX,RY,RZ
REAL(KIND=DP_KIND) :: P,DXY,DXYZ
DXY =X**2.0D0+Y**2.0D0; IF(DXY.GT.0.0D0)DXY=SQRT(DXY)
DXYZ=X**2.0D0+Y**2.0D0+Z**2.0D0; IF(DXYZ.GT.0.0D0)DXYZ=SQRT(DXYZ)
!## get length of vector
P=0.0D0; IF(DXYZ.GT.0.0D0)P=DXYZ
RX=0.0D0
RY=0.0D0
RZ=0.0D0
IF(P.GT.0.0D0)THEN
!## get angle with x-axes
RX=ACOS(X/P)
!## get angle with x-axes
RY=ACOS(Y/P)
ENDIF
!## get angle with x-axes
IF(DXY.GT.0.0D0)RZ=ACOS(X/DXY)
! write(*,*) RX,RY,RZ
! write(*,*) RX*(360.0D0/(2.0*pi)),RY*(360.0D0/(2.0*pi)),RZ*(360.0D0/(2.0*pi))
END SUBROUTINE UTL_GET_ANGLES
!###======================================================================
SUBROUTINE UTL_ROTATE_XYZ(X,Y,Z,AX,AY,AZ)
!###======================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(INOUT) :: X,Y,Z
REAL(KIND=DP_KIND),INTENT(IN) :: AX,AY,AZ
REAL(KIND=DP_KIND) :: X1,Y1,Z1
!## perform rotation around z-axes
IF(AZ.NE.0.0D0)THEN
X1= COS(AZ)*X+SIN(AZ)*Y
Y1=-SIN(AZ)*X+COS(AZ)*Y
X=X1
Y=Y1
ENDIF
!## perform rotation around x-axes
IF(AX.NE.0.0D0)THEN
Y1=COS(AX)*Y-SIN(AX)*Z
Z1=SIN(AX)*Y+COS(AX)*Z
Y=Y1
Z=Z1
ENDIF
!## perform rotation around y-axes
IF(AY.NE.0.0D0)THEN
X1= COS(AY)*X-SIN(AY)*Z
Z1= SIN(AY)*X+COS(AY)*Z
X=X1
Z=Z1
ENDIF
END SUBROUTINE UTL_ROTATE_XYZ
!###======================================================================
SUBROUTINE UTL_PROFILE_GETVIEWBOX(X1,Y1,X2,Y2,XSIGHT,XYPOL,XMN,YMN,XMX,YMX)
!###======================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: X1,X2,Y1,Y2,XSIGHT
REAL(KIND=DP_KIND),INTENT(OUT) :: XMN,YMN,XMX,YMX
REAL(KIND=DP_KIND),DIMENSION(4,2),INTENT(OUT) :: XYPOL
CALL UTL_PROFILE_COMPVIEWBOX(X1,X2,Y1,Y2,XYPOL,XSIGHT)
XMN=MINVAL(XYPOL(:,1))
XMX=MAXVAL(XYPOL(:,1))
YMN=MINVAL(XYPOL(:,2))
YMX=MAXVAL(XYPOL(:,2))
END SUBROUTINE UTL_PROFILE_GETVIEWBOX
!###======================================================================
SUBROUTINE UTL_PROFILE_COMPVIEWBOX(X1,X2,Y1,Y2,XYPOL,XSIGHT)
!###======================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),PARAMETER :: RAD=360.0D0/(2.0*3.1415)
REAL(KIND=DP_KIND),INTENT(IN) :: X1,X2,Y1,Y2,XSIGHT
REAL(KIND=DP_KIND),INTENT(OUT),DIMENSION(4,2) :: XYPOL
REAL(KIND=DP_KIND) :: DX,DY,TNG
DX =X2-X1
DY =Y2-Y1
IF(DY.EQ.0.0D0)TNG=0.0D0
IF(ABS(DY).GT.0.0D0)TNG=ATAN2(DY,DX)
TNG=TNG+90.0D0/RAD
XYPOL(1,1)=X1+COS(TNG)*XSIGHT
XYPOL(1,2)=Y1+SIN(TNG)*XSIGHT
XYPOL(2,1)=X2+COS(TNG)*XSIGHT
XYPOL(2,2)=Y2+SIN(TNG)*XSIGHT
XYPOL(3,1)=X2-COS(TNG)*XSIGHT
XYPOL(3,2)=Y2-SIN(TNG)*XSIGHT
XYPOL(4,1)=X1-COS(TNG)*XSIGHT
XYPOL(4,2)=Y1-SIN(TNG)*XSIGHT
END SUBROUTINE UTL_PROFILE_COMPVIEWBOX
!###======================================================================
LOGICAL FUNCTION UTL_LOADIMAGE(BMPFNAME,N,IBMPDATA,IBATCH)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: BMPFNAME
INTEGER,INTENT(IN) :: N
INTEGER,INTENT(OUT),DIMENSION(N) :: IBMPDATA
INTEGER,INTENT(IN) :: IBATCH
CHARACTER(LEN=256) :: LINE
INTEGER :: I
LOGICAL :: LEX
UTL_LOADIMAGE=.TRUE.
INQUIRE(FILE=BMPFNAME,EXIST=LEX)
IF(.NOT.LEX)THEN
IF(IBATCH.EQ.0)CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'File: '//TRIM(BMPFNAME)//CHAR(13)//'does not exists','Error')
IF(IBATCH.EQ.1)WRITE(*,'(A)') 'File: '//TRIM(BMPFNAME)//' does not exists'
RETURN
ENDIF
!## clear existing error
I=WINFOERROR(1)
CALL IGRLOADIMAGEDATA(BMPFNAME,IBMPDATA)
I=WINFOERROR(1)
IF(I.EQ.0)RETURN
CALL WINFOERRORMESSAGE(I,LINE)
IF(IBATCH.EQ.0)CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'Error reading file:'//CHAR(13)// &
TRIM(BMPFNAME)//CHAR(13)//'Error message:'//CHAR(13)//TRIM(LINE),'Error')
IF(IBATCH.EQ.1)WRITE(*,'(A)') 'Error reading file:'//TRIM(BMPFNAME)//' Error message:'//TRIM(LINE)
UTL_LOADIMAGE=.FALSE.
END FUNCTION UTL_LOADIMAGE
!###======================================================================
INTEGER FUNCTION UTL_GETIDPROC(PROC,ICLEAN)
!###======================================================================
IMPLICIT NONE
TYPE(PROCOBJ),INTENT(INOUT),POINTER,DIMENSION(:) :: PROC
TYPE(PROCOBJ),POINTER,DIMENSION(:) :: PROC_BU
INTEGER,INTENT(IN) :: ICLEAN
INTEGER :: I,J,N,ISTATUS,IEXCOD
INTEGER,DIMENSION(2) :: PID
IF(ASSOCIATED(PROC))THEN
!## evaluate current status
DO I=1,SIZE(PROC)
PID=PROC(I)%ID
!## check running status
CALL IOSCOMMANDCHECK(PID,ISTATUS,IEXCOD=IEXCOD)
!## not running free, process
IF(ISTATUS.EQ.0)THEN
!## non-blocked process not stopped correctly
IF(PROC(I)%IFLAGS(2).EQ.0.AND.IEXCOD.NE.0)THEN
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'Error occured in previous start of program:'//CHAR(13)//TRIM(PROC(I)%CID)//CHAR(13)// &
'Program has stopped now, but you might check the batch file before starting again?','Information')
ENDIF
PROC(I)%ID=0; PROC(I)%CID=''; PROC(I)%IFLAGS=0
!## process is still running
ELSEIF(ISTATUS.EQ.1)THEN
ENDIF
ENDDO
ELSE
ALLOCATE(PROC(1)); PROC(1)%ID=0; PROC(1)%CID=''; PROC(1)%IFLAGS=0
ENDIF
N=SIZE(PROC)
!## clean
J=0; DO I=1,N
IF(PROC(I)%ID.NE.0)THEN
J=J+1; IF(I.NE.J)THEN; PROC(J)=PROC(I); ENDIF
ENDIF
ENDDO
DO I=J+1,N; PROC(I)%ID=0; PROC(I)%CID=''; PROC(I)%IFLAGS=0; ENDDO
!## find empty spot
DO I=1,SIZE(PROC); IF(PROC(I)%ID.EQ.0)EXIT; ENDDO; N=I
IF(ICLEAN.EQ.1)N=I-1
IF(N.EQ.0)THEN
IF(ASSOCIATED(PROC))DEALLOCATE(PROC)
ELSE
IF(N.NE.SIZE(PROC))THEN
ALLOCATE(PROC_BU(N)); DO I=1,N; PROC_BU(I)=PROC(I); ENDDO; DEALLOCATE(PROC)
ALLOCATE(PROC(N+1)); DO I=1,N+1; PROC(I)%ID=0; PROC(I)%CID=''; PROC(I)%IFLAGS=0; ENDDO
DO I=1,N; PROC(I)=PROC_BU(I); ENDDO; DEALLOCATE(PROC_BU)
ENDIF
ENDIF
UTL_GETIDPROC=N
END FUNCTION UTL_GETIDPROC
!###======================================================================
SUBROUTINE UTL_DELSPACE(LINE1,LINE2)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: LINE1
CHARACTER(LEN=*),INTENT(OUT) :: LINE2
INTEGER :: I,J,K
LINE2=''; K=0
J=0; DO I=1,LEN_TRIM(LINE1)
IF(LINE1(I:I).EQ.CHAR(34).OR.LINE1(I:I).EQ.CHAR(39))THEN
K=ABS(K-1)
ENDIF
!## copy non-spaces or inside quotes
IF(LINE1(I:I).NE.CHAR(32).OR.K.EQ.1)THEN
J=J+1; LINE2(J:J)=LINE1(I:I)
ENDIF
ENDDO
END SUBROUTINE UTL_DELSPACE
!###======================================================================
SUBROUTINE UTL_ADDQUOTES(LINE,QTYPE)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(INOUT) :: LINE
INTEGER,INTENT(IN) :: QTYPE !## 0: quotes anyhow 1: quotes if needed
IF(QTYPE.EQ.1)THEN
IF(INDEX(TRIM(LINE),' ').GT.0) LINE='"'//TRIM(LINE)//'"'
ELSE
LINE='"'//TRIM(LINE)//'"'
ENDIF
END SUBROUTINE UTL_ADDQUOTES
!###======================================================================
LOGICAL FUNCTION UTL_DATA_CSV(TXT,VAR,ICOL_VAR,IACT_VAR,CCNST)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),DIMENSION(:),INTENT(IN) :: TXT
INTEGER :: I,J,ITYPE,NP
CHARACTER(LEN=256) :: FNAME
TYPE(WIN_MESSAGE) :: MESSAGE
CHARACTER(LEN=*),POINTER,DIMENSION(:,:),INTENT(INOUT) :: VAR
CHARACTER(LEN=*),POINTER,DIMENSION(:),INTENT(INOUT) :: CCNST
INTEGER,ALLOCATABLE,DIMENSION(:),INTENT(INOUT) :: ICOL_VAR,IACT_VAR
UTL_DATA_CSV=.FALSE.
NP=SIZE(TXT)
IF(.NOT.UTL_WSELECTFILE('Load Comma Separated File (*.csv)|*.csv|',&
LOADDIALOG+MUSTEXIST+PROMPTON+DIRCHANGE+APPENDEXT,FNAME,&
'Load Comma Separated File (*.csv)'))RETURN
CALL UTL_MESSAGEHANDLE(0)
CALL UTL_GENLABELSREAD(FNAME,VAR,NL,NV)
CALL UTL_MESSAGEHANDLE(1)
IF(NV.LE.0)THEN
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'Cannot read column info (header) from file!','Error'); RETURN
ENDIF
CALL WDIALOGLOAD(ID_READCSV,ID_READCSV)
IF(SIZE(TXT).GT.WINFOGRID(IDF_GRID1,GRIDROWSMAX))THEN
CALL WDIALOGUNLOAD()
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'Cannot read more than '//TRIM(ITOS(WINFOGRID(IDF_GRID1,GRIDROWSMAX)))// &
' columns in this iMOD version','Error'); RETURN
ENDIF
CALL WGRIDROWS(IDF_GRID1,NP)
!## put parameters
CALL WGRIDPUTSTRING(IDF_GRID1,2,TXT,NP)
!## assign variable to parameter
IF(ALLOCATED(IACT_VAR))DEALLOCATE(IACT_VAR); ALLOCATE(IACT_VAR(NP))
IACT_VAR=1
CALL WGRIDPUTCHECKBOX(IDF_GRID1,1,IACT_VAR,NP)
IF(ALLOCATED(ICOL_VAR))DEALLOCATE(ICOL_VAR); ALLOCATE(ICOL_VAR(NP))
J=0; DO I=1,NP; J=J+1; IF(J.GT.NV)J=1; ICOL_VAR(I)=J; ENDDO
CALL WGRIDPUTMENU(IDF_GRID1,3,VAR(:,0),NV,ICOL_VAR,NP)
IF(ASSOCIATED(CCNST))DEALLOCATE(CCNST); ALLOCATE(CCNST(NP))
CCNST=''
CALL WGRIDPUTSTRING(IDF_GRID1,4,CCNST,NP)
CALL UTL_DIALOGSHOW(-1,-1,0,3)
DO
CALL WMESSAGE(ITYPE,MESSAGE)
SELECT CASE (ITYPE)
CASE (FIELDCHANGED)
SELECT CASE (MESSAGE%VALUE1)
CASE (IDF_GRID1)
CALL WGRIDGETCHECKBOX(IDF_GRID1,1,IACT_VAR,NP)
DO I=1,SIZE(IACT_VAR)
CALL WGRIDSTATECELL(IDF_GRID1,3,I,IACT_VAR(I))
CALL WGRIDSTATECELL(IDF_GRID1,4,I,IACT_VAR(I))
ENDDO
END SELECT
CASE (PUSHBUTTON)
SELECT CASE (MESSAGE%VALUE1)
CASE (IDOK)
CALL WGRIDGETCHECKBOX(IDF_GRID1,1,IACT_VAR,NP)
CALL WGRIDGETMENU(IDF_GRID1,3,ICOL_VAR,NP)
CALL WGRIDGETSTRING(IDF_GRID1,4,CCNST,NP)
UTL_DATA_CSV=.TRUE.
EXIT
CASE (IDHELP)
CALL UTL_GETHELP('2.5.10','iF.CSV')
CASE (IDCANCEL)
EXIT
END SELECT
END SELECT
ENDDO
CALL WDIALOGUNLOAD()
END FUNCTION UTL_DATA_CSV
!###======================================================================
SUBROUTINE UTL_GENLABELSGET(CID,JL,VARIABLE)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN),DIMENSION(:,:),POINTER :: VARIABLE
CHARACTER(LEN=*),INTENT(IN) :: CID
INTEGER,INTENT(OUT) :: JL
INTEGER :: SC,N,M,J
CHARACTER(LEN=52) :: STRING,GENSTR
IF(.NOT.ASSOCIATED(VARIABLE))RETURN
N=SIZE(VARIABLE,1); M=SIZE(VARIABLE,2)
JL=0; IF(N.LE.0.OR.M.LE.0)RETURN
SC=1 !## search column
!## evaluate the first
DO JL=1,M-1
STRING=VARIABLE(SC,JL)
!## math found
J=INDEX(TRIM(UTL_CAP(CID,'U')),',')
IF(J.GT.0)THEN
GENSTR=CID(:J-1)
ELSE
GENSTR=CID
ENDIF
IF(TRIM(UTL_CAP(GENSTR,'U')).EQ.TRIM(UTL_CAP(STRING,'U')))RETURN
END DO
IF(JL.GE.NL)JL=0
END SUBROUTINE UTL_GENLABELSGET
!###======================================================================
SUBROUTINE UTL_GENLABELSREAD(FNAME,VARIABLE,NVL,NVV,SKIPLINES,ILABELS)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: FNAME
CHARACTER(LEN=*),DIMENSION(:,:),POINTER,INTENT(INOUT) :: VARIABLE
INTEGER,INTENT(OUT) :: NVV,NVL
INTEGER,INTENT(IN),OPTIONAL :: SKIPLINES,ILABELS
INTEGER,ALLOCATABLE,DIMENSION(:) :: BPV,EPV
INTEGER :: ML,I,J,INCL,IOS,IU,INL
CHARACTER(LEN=1256) :: STRING
CHARACTER(LEN=MAXLEN),DIMENSION(:,:),POINTER :: DVARIABLE
!## initialize table of data for gen polygons
NVV =0
NVL =0
INCL=50
IU=UTL_GETUNIT()
CALL OSD_OPEN(IU,FILE=FNAME,STATUS='OLD',ACTION='READ',IOSTAT=IOS)
IF(IOS.NE.0)THEN
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'iMOD cannot OPEN/READ file called:'//CHAR(13)//&
TRIM(FNAME),'Error')
RETURN
ENDIF
!## estimate number of records
NVL=0; DO
READ(IU,'(A1256)',IOSTAT=IOS) STRING
IF(IOS.NE.0)EXIT
NVL=NVL+1
ENDDO
REWIND(IU)
IF(PRESENT(SKIPLINES))THEN
DO I=1,SKIPLINES; READ(IU,*); ENDDO
ENDIF
!## get number of variables
READ(IU,'(A1256)',IOSTAT=IOS) STRING
IF(IOS.NE.0)RETURN
IF(LEN_TRIM(STRING).EQ.0)RETURN
!## read the rest of the table in order to fill var(), 0=label
INL=-1
IF(PRESENT(ILABELS))INL=-ILABELS
NVV=UTL_COUNT_COLUMNS(STRING,',;')
ALLOCATE(BPV(NVV)); ALLOCATE(EPV(NVV))
ALLOCATE(VARIABLE(NVV,INL+1:NVL))
ML=NVL
NVL=INL
DO
NVL=NVL+1
IF(NVL.GT.ML)THEN
ALLOCATE(DVARIABLE(NVV,INL+1:ML+INCL))
!## copy current part
DO I=1,SIZE(VARIABLE,1); DO J=INL+1,ML; DVARIABLE(I,J)=VARIABLE(I,J); ENDDO; ENDDO
DEALLOCATE(VARIABLE)
VARIABLE=>DVARIABLE
ML=ML+INCL
NULLIFY(DVARIABLE)
ENDIF
!## get variables
NVV=UTL_COUNT_COLUMNS(STRING,',;',BPV=BPV,EPV=EPV)
DO I=1,NVV
VARIABLE(I,NVL)=''
IF(BPV(I).LE.LEN(STRING).AND. &
BPV(I).LE.EPV(I))THEN
!## maximize length of variable
J=(EPV(I)-BPV(I))+1; EPV(I)=BPV(I)+MIN(MAXLEN,J)-1
VARIABLE(I,NVL)=STRING(BPV(I):EPV(I))
ENDIF
END DO
READ(IU,'(A1256)',IOSTAT=IOS) STRING
IF(IOS.NE.0)EXIT
IF(LEN_TRIM(STRING).EQ.0)EXIT
ENDDO
CLOSE(IU)
IF(ALLOCATED(BPV))DEALLOCATE(BPV); IF(ALLOCATED(EPV))DEALLOCATE(EPV)
IF(NVL.NE.ML)THEN
NVV=MAX(NVV,SIZE(VARIABLE,1))
ALLOCATE(DVARIABLE(NVV,INL+1:NVL))
!## copy current part
DO I=1,SIZE(VARIABLE,1); DO J=INL+1,NVL; DVARIABLE(I,J)=VARIABLE(I,J); ENDDO; ENDDO
DEALLOCATE(VARIABLE)
VARIABLE=>DVARIABLE
NULLIFY(DVARIABLE)
ELSE
NVV=0; NVL=0
ENDIF
!## remove quotes
DO I=1,SIZE(VARIABLE,1); DO J=INL+1,NVL
READ(VARIABLE(I,J),*) VARIABLE(I,J)
ENDDO; ENDDO
END SUBROUTINE UTL_GENLABELSREAD
!###======================================================================
SUBROUTINE UTL_GENLABELSWRITE(FNAME,VAR)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: FNAME
CHARACTER(LEN=*),POINTER,DIMENSION(:,:),INTENT(IN) :: VAR
INTEGER :: IU,IOS,I,J
CHARACTER(LEN=512) :: LINE
!## nothing to write
IF(NL.LE.0)RETURN
IF(.NOT.ASSOCIATED(VAR))RETURN
IU=UTL_GETUNIT()
CALL OSD_OPEN(IU,FILE=FNAME,STATUS='UNKNOWN',ACTION='WRITE',IOSTAT=IOS)
IF(IOS.NE.0)THEN
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'iMOD cannot OPEN/WRITE associated data file called:'//CHAR(13)//&
TRIM(FNAME),'Error')
RETURN
ENDIF
DO I=0,NL
LINE=TRIM(VAR(1,I))
DO J=2,NV; LINE=TRIM(LINE)//','//TRIM(VAR(J,I)); END DO
WRITE(IU,'(A)') TRIM(LINE)
ENDDO
CLOSE(IU)
END SUBROUTINE UTL_GENLABELSWRITE
!###======================================================================
SUBROUTINE UTL_GENLABELSDEALLOCATE()
!###======================================================================
IMPLICIT NONE
IF(ASSOCIATED(VAR)) DEALLOCATE(VAR)
IF(ALLOCATED(ICOL_VAR))DEALLOCATE(ICOL_VAR)
IF(ALLOCATED(IACT_VAR))DEALLOCATE(IACT_VAR)
IF(ASSOCIATED(CCNST)) DEALLOCATE(CCNST)
END SUBROUTINE UTL_GENLABELSDEALLOCATE
!###======================================================================
REAL(KIND=DP_KIND) FUNCTION UTL_POLYGON1AREA(X,Y,N)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: N
REAL(KIND=DP_KIND),INTENT(IN),DIMENSION(N) :: X,Y
INTEGER :: I
UTL_POLYGON1AREA=0.0D0
DO I=1,N-1
UTL_POLYGON1AREA=UTL_POLYGON1AREA+0.5D0*((X(I)*Y(I+1))-(X(I+1)*Y(I)))
END DO
UTL_POLYGON1AREA=UTL_POLYGON1AREA+0.5D0*((X(N)*Y(1))-(X(1)*Y(N)))
END FUNCTION UTL_POLYGON1AREA
! !###======================================================================
! REAL(KIND=DP_KIND) FUNCTION UTL_POLYGON1AREA(X,Y,N)
! !###======================================================================
! IMPLICIT NONE
! INTEGER,INTENT(IN) :: N
! REAL(KIND=DP_KIND),INTENT(IN),DIMENSION(N) :: X,Y
! INTEGER :: I
! REAL(KIND=DP_KIND) :: XM,DY
!
! UTL_POLYGON1AREA=0.0D0
! DO I=1,N-1
! XM=(X(I)+X(I+1))/2.0D0
! DY=Y(I+1)-Y(I)
! UTL_POLYGON1AREA=UTL_POLYGON1AREA+(XM-XMIN)*DY
! ENDDO
!
! END FUNCTION UTL_POLYGON1AREA
!###======================================================================
REAL(KIND=DP_KIND) FUNCTION UTL_GETGAMMA(X1,Y1,X2,Y2,RANGE,C1,C0,KTYPE) !c1=sill-nugget c0=nugget
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: KTYPE
REAL(KIND=DP_KIND),INTENT(IN) :: X1,Y1,X2,Y2,RANGE,C1,C0
REAL(KIND=DP_KIND) :: DXY,H
DXY=UTL_DIST(X1,Y1,X2,Y2)
IF(DXY.GE.RANGE)THEN
UTL_GETGAMMA=C1; RETURN
ELSE
!## no part of kriging, beyond given range, equal to sill
SELECT CASE (ABS(KTYPE))
CASE (1) !## linear
H=DXY/RANGE
CASE (2) !## spherical = OKAY
H=(3.0D0*DXY)/(2.0D0*RANGE)-((DXY**3.0D0)/(2.0D0*RANGE**3.0D0))
CASE (3) !## exponential
H=1.0D0-10.0D0**(-3.0D0*DXY/RANGE)
CASE (4) !## gaussian
H=1.0D0-10.0D0**(-3.0D0*(DXY**2.0D0)/(RANGE**2.0D0))
CASE (5) !## power
H=DXY**0.5D0
CASE DEFAULT
WRITE(*,*) 'UNKNOWN KTYPE',KTYPE; PAUSE; STOP
END SELECT
ENDIF
UTL_GETGAMMA=(C1-C0)*H+C0
! KRIGING_GETGAMMA=C0+C1*H
END FUNCTION UTL_GETGAMMA
!###======================================================================
SUBROUTINE UTL_STDEF(X,N,NODATA,STDEV,XT,NPOP)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: N
INTEGER,INTENT(OUT) :: NPOP
REAL(KIND=DP_KIND),DIMENSION(N),INTENT(IN) :: X
REAL(KIND=DP_KIND),INTENT(IN) :: NODATA
REAL(KIND=DP_KIND),INTENT(OUT) :: XT,STDEV
INTEGER :: I
REAL(KIND=DP_KIND) :: XV
STDEV=0.0D0
NPOP=0
XT=0.0D0
DO I=1,N
IF(X(I).NE.NODATA)THEN
NPOP=NPOP+1
XT=XT+X(I)
ENDIF
ENDDO
IF(NPOP.LT.2)RETURN
XT=XT/DBLE(NPOP)
NPOP=0
XV=0.0D0
DO I=1,N
IF(X(I).NE.NODATA)THEN
NPOP=NPOP+1
XV=XV+(X(I)-XT)**2.0D0
ENDIF
END DO
IF(XV.LE.0.0D0)RETURN
!## sample standard deviation
STDEV=SQRT(XV/DBLE(NPOP-1))
END SUBROUTINE UTL_STDEF
!###======================================================================
REAL(KIND=DP_KIND) FUNCTION UTL_DIST(X1,Y1,X2,Y2)
!###======================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: X1,Y1,X2,Y2
REAL(KIND=DP_KIND) :: DX,DY
UTL_DIST=0.0D0
DX=(X1-X2)**2.0D0; DY=(Y1-Y2)**2.0D0
IF(DX+DY.NE.0.0D0)UTL_DIST=SQRT(DX+DY)
END FUNCTION UTL_DIST
!###======================================================================
REAL(KIND=DP_KIND) FUNCTION UTL_DIST_3D(X1,Y1,Z1,X2,Y2,Z2)
!###======================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: X1,Y1,Z1,X2,Y2,Z2
REAL(KIND=DP_KIND) :: DX,DY,DZ
UTL_DIST_3D=0.0D0
DX=(X2-X1)**2.0D0; DY=(Y2-Y1)**2.0D0; DZ=(Z2-Z1)**2.0D0
IF(DX+DY+DZ.NE.0.0D0)UTL_DIST_3D=SQRT(DX+DY+DZ)
END FUNCTION UTL_DIST_3D
!###======================================================================
LOGICAL FUNCTION UTL_WSELECTFILE(FILTERSTR,IFLAGS,FILEDIR,TITLE,FTYPE)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: FILTERSTR
CHARACTER(LEN=*),INTENT(INOUT) :: FILEDIR
INTEGER,INTENT(IN) :: IFLAGS
INTEGER,INTENT(OUT),OPTIONAL :: FTYPE
CHARACTER(LEN=*),INTENT(IN),OPTIONAL :: TITLE
INTEGER :: I,J,K,ISAVE
CHARACTER(LEN=10) :: EXT
INTEGER :: IFTYPE
UTL_WSELECTFILE=.FALSE.
!## store original filedir
ISAVE=1; IF(INDEX(FILEDIR,'*').GT.0)ISAVE=0
IF(ISAVE.EQ.1)FILEDIR=SAVEDIR
IFTYPE=1; IF(PRESENT(FTYPE))IFTYPE=FTYPE
DO
IF(PRESENT(TITLE))THEN
CALL WSELECTFILE(FILTERSTR,IFLAGS,FILEDIR,TITLE,IFTYPE=IFTYPE)
ELSE
CALL WSELECTFILE(FILTERSTR,IFLAGS,FILEDIR,IFTYPE=IFTYPE)
ENDIF
IF(WINFODIALOG(4).NE.1)THEN
FILEDIR=''
RETURN
ENDIF
!## check extent ...
I=INDEX(FILEDIR,'.',.TRUE.)
IF(I.EQ.0)EXIT
IF(INDEX(FILTERSTR,'*.*').LE.0)THEN
EXT=FILEDIR(I+1:)
J=INDEX(UTL_CAP_BIG(FILTERSTR(1:MIN(1024,LEN(FILTERSTR))),'U'),'*.'//TRIM(UTL_CAP(EXT,'U')))
IF(J.NE.0)EXIT
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'You should select a file that agrees the supplied filterstring:'//CHAR(13)// &
TRIM(FILTERSTR),'Error')
ELSE
EXIT
ENDIF
ENDDO
!## removes filename from directory name before saving
K=INDEX(FILEDIR,'\',.TRUE.)
!## save directory name into SAVEDIR
IF(ISAVE.EQ.1)SAVEDIR=FILEDIR(:K)
IF(PRESENT(FTYPE))FTYPE=IFTYPE
UTL_WSELECTFILE=.TRUE.
END FUNCTION UTL_WSELECTFILE
!###======================================================================
SUBROUTINE UTL_PLOT1BITMAP()
!###======================================================================
IMPLICIT NONE
CALL IGRSELECT(DRAWBITMAP,MPW%IBITMAP)
CALL DBL_IGRAREA(0.0D0,0.0D0,1.0D0,1.0D0)
CALL DBL_IGRUNITS(MPW%XMIN,MPW%YMIN,MPW%XMAX,MPW%YMAX,IOFFSET=1)
END SUBROUTINE UTL_PLOT1BITMAP
!###======================================================================
SUBROUTINE UTL_PLOT2BITMAP()
!###======================================================================
IMPLICIT NONE
CALL IGRSELECT(DRAWWIN)
CALL WINDOWSELECT(MPW%IWIN)
CALL WBITMAPVIEW(MPW%IBITMAP,MPW%IX,MPW%IY,MODELESS)
CALL DBL_IGRAREA(0.0D0,0.0D0,1.0D0,1.0D0)
CALL DBL_IGRUNITS(MPW%XMIN,MPW%YMIN,MPW%XMAX,MPW%YMAX,IOFFSET=1)
END SUBROUTINE UTL_PLOT2BITMAP
!###======================================================================
FUNCTION REALTOSTRING(X)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=20) :: REALTOSTRING
REAL(KIND=DP_KIND),INTENT(IN) :: X
INTEGER :: I
WRITE(REALTOSTRING,*) X
!eliminate all zero at the end!
DO I=LEN_TRIM(REALTOSTRING),1,-1
IF(REALTOSTRING(I:I).NE.'0')EXIT
END DO
IF(REALTOSTRING(I:I).EQ.'.'.OR.REALTOSTRING(I:I).EQ.',')I=I-1
REALTOSTRING=REALTOSTRING(1:I)
END FUNCTION REALTOSTRING
!###======================================================================
INTEGER FUNCTION UTL_IDFGETCLASS(LEG,GRD)
!###======================================================================
IMPLICIT NONE
TYPE(LEGENDOBJ),INTENT(IN) :: LEG
REAL(KIND=DP_KIND),INTENT(IN) :: GRD
INTEGER :: I
!## default=wit!
UTL_IDFGETCLASS=WRGB(255,255,255)
!## NaN
IF(GRD.NE.GRD)RETURN
IF(GRD.GT.LEG%CLASS(0).OR.GRD.LT.LEG%CLASS(LEG%NCLR))RETURN
CALL POL1LOCATE(LEG%CLASS,LEG%NCLR,REAL(GRD,8),I)
!## correct if equal to top-class boundary
IF(I.GT.0.AND.I.LE.LEG%NCLR)THEN !MXCLR)THEN
UTL_IDFGETCLASS=LEG%RGB(I)
ELSE
IF(UTL_EQUALS_REAL(GRD,LEG%CLASS(0)))UTL_IDFGETCLASS=LEG%RGB(1)
ENDIF
END FUNCTION UTL_IDFGETCLASS
!###======================================================================
SUBROUTINE UTL_IDFCURDIM(XMIN,YMIN,XMAX,YMAX,IDF,NC1,NC2,NR1,NR2)
!###======================================================================
IMPLICIT NONE
TYPE(IDFOBJ),INTENT(INOUT) :: IDF
REAL(KIND=DP_KIND),INTENT(IN) :: XMIN,YMIN,XMAX,YMAX
REAL(KIND=DP_KIND) :: D
INTEGER,INTENT(OUT) :: NC1,NC2,NR1,NR2
IF(IDF%IEQ.EQ.0)THEN
!## min. column
D =XMIN-IDF%XMIN
NC1=INT(D/IDF%DX)+1
IF(MOD(D,IDF%DX).NE.0.0D0)NC1=NC1+1
!## max. column
D =XMAX-IDF%XMIN
NC2=INT(D/IDF%DX)
!## min. row
D =IDF%YMAX-YMAX
NR1=INT(D/IDF%DY)+1
IF(MOD(D,IDF%DY).NE.0.0D0)NR1=NR1+1
!## max. row
D =IDF%YMAX-YMIN
NR2=INT(D/IDF%DY)
ELSE
!## min. column
CALL POL1LOCATE(IDF%SX,IDF%NCOL+1,REAL(XMIN,8),NC1)
!## max. column
CALL POL1LOCATE(IDF%SX,IDF%NCOL+1,REAL(XMAX,8),NC2)
!## min. row
CALL POL1LOCATE(IDF%SY,IDF%NROW+1,REAL(YMAX,8),NR1)
!## max. row
CALL POL1LOCATE(IDF%SY,IDF%NROW+1,REAL(YMIN,8),NR2)
ENDIF
NC1=MAX(1,NC1); NC1=MIN(NC1,IDF%NCOL)
NC2=MAX(1,NC2); NC2=MIN(NC2,IDF%NCOL)
NR1=MAX(1,NR1); NR1=MIN(NR1,IDF%NROW)
NR2=MAX(1,NR2); NR2=MIN(NR2,IDF%NROW)
IF(IDF%IEQ.EQ.1)THEN
IF(MPW%XMIN.GT.IDF%SX(NC1-1))NC1=NC1+1
IF(MPW%XMAX.LT.IDF%SX(NC2)) NC2=NC2-1
IF(MPW%YMAX.LT.IDF%SY(NR1-1))NR1=NR1+1
IF(MPW%YMIN.GT.IDF%SY(NR2)) NR2=NR2-1
ENDIF
END SUBROUTINE UTL_IDFCURDIM
!###======================================================================
SUBROUTINE UTL_IDFCRDCOR(X1,X2,Y1,Y2,WIDTH,HEIGTH)
!###======================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: WIDTH,HEIGTH
REAL(KIND=DP_KIND),INTENT(INOUT) :: X1,X2,Y1,Y2
REAL(KIND=DP_KIND) :: RAT1,RAT2,DX,DY,XC,YC
RAT1=WIDTH/HEIGTH; DX=X2-X1; DY=Y2-Y1; RAT2=DX/DY
XC=(X1+X2)/2.0D0; YC=(Y1+Y2)/2.0D0
!## area up
IF(RAT1.LT.1.0D0)THEN
!## box smaller than image
IF(RAT1.LT.RAT2)THEN
DY=0.5D0*DX/RAT1; Y1=YC-DY; Y2=YC+DY
!## image smaller than box
ELSE
DX=0.5D0*DY*RAT1; X1=XC-DX; X2=XC+DX
ENDIF
!## area flat
ELSE
!##
IF(RAT1.GT.RAT2)THEN
DX=0.5D0*DY*RAT1; X1=XC-DX; X2=XC+DX
!## figure flat too
ELSE
DY=0.5D0*DX/RAT1; Y1=YC-DY; Y2=YC+DY
ENDIF
ENDIF
END SUBROUTINE UTL_IDFCRDCOR
!###======================================================================
SUBROUTINE 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,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 UTL_FILLARRAY
!###======================================================================
SUBROUTINE 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(:) :: 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 UTL_READARRAY
!###======================================================================
LOGICAL FUNCTION UTL_READINITFILE(CKEY,LINE,IU,IOPT)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: IU,IOPT
CHARACTER(LEN=*),INTENT(IN) :: CKEY
CHARACTER(LEN=*),INTENT(OUT) :: LINE
INTEGER :: IOS,I,J,N,M,II,ITRY
CHARACTER(LEN=10) :: FRMT
CHARACTER(LEN=256) :: FNAME
CHARACTER(LEN=:),ALLOCATABLE :: STR
UTL_READINITFILE=.FALSE.
N=LEN(LINE); WRITE(FRMT,'(A2,I7.7,A1)') '(A',N,')'
!## backup line
ALLOCATE(CHARACTER(LEN=N) :: STR)
!## read from current position, if not found try from beginning
ITRY=1
DO
READ(IU,FRMT,IOSTAT=IOS) LINE
IF(IOS.NE.0)THEN
IF(ITRY.EQ.2)THEN
IF(IOPT.EQ.0)THEN
INQUIRE(UNIT=IU,NAME=FNAME); CLOSE(IU)
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'iMOD DID NOT find keyword: ['//TRIM(CKEY)//'] within Settings file:'// &
CHAR(13)//'['//TRIM(FNAME)//']','Error')
ENDIF
RETURN
ELSE
REWIND(IU)
ITRY=ITRY+1
CYCLE
ENDIF
ENDIF
STR=LINE
N=LEN(LINE)
M=256 !## length of utl_cap() function
!## split cap function in case
IF(N.GT.M)THEN
I=1; J=I+M-1
DO
LINE(I:J)=UTL_CAP(LINE(I:J),'U')
I=I+M
IF(I.GT.N)EXIT
J=MIN(N,I+M-1)
ENDDO
ELSE
LINE=UTL_CAP(LINE,'U')
ENDIF
II=INDEX(TRIM(LINE),'!') !## skip comment lines for keyword
I =INDEX(TRIM(LINE),TRIM(CKEY))
IF(II.EQ.0)II=I
!## okay, proper line found
IF(I.NE.0.AND.II.GE.I)THEN
!## make sure previous to i or j no character is available
IF(I.GE.2)THEN
IF(LINE(I-1:I-1).NE.' ')I=0 !## not correct
ENDIF
!## make sure next to i or j no character or "=" sign
IF(LINE(I+LEN_TRIM(CKEY):I+LEN_TRIM(CKEY)).NE.' '.AND. &
LINE(I+LEN_TRIM(CKEY):I+LEN_TRIM(CKEY)).NE.'=')I=0 !## not correct
J=INDEX(TRIM(LINE),'=')
IF(I.NE.0.AND.J.GT.I)EXIT
ENDIF
ENDDO
I=INDEX(LINE,'=')
IF(I.LE.0)THEN
INQUIRE(UNIT=IU,NAME=FNAME); CLOSE(IU)
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'iMOD misses "=" after keyword: ['//TRIM(CKEY)//'] within Settings file:'// &
CHAR(13)//'[ '//TRIM(FNAME)//' ]','Error')
RETURN
ENDIF
I=I+1
LINE(1:N-I+1)=STR(I:N)
!## remove leading space, if there is one
LINE=ADJUSTL(LINE)
DEALLOCATE(STR)
!## check whether there is an argment given ...
IF(TRIM(LINE).EQ.'')THEN
INQUIRE(UNIT=IU,NAME=FNAME); CLOSE(IU)
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'iMOD misses an argument after the "=" sign for keyword: ['//TRIM(CKEY)//'] within Settings file:'// &
CHAR(13)//'[ '//TRIM(FNAME)//' ]','Error')
RETURN
ENDIF
UTL_READINITFILE=.TRUE.
END FUNCTION UTL_READINITFILE
!###====================================================================
SUBROUTINE UTL_DRAWLEGENDBOX(XMIN,YMIN,XMAX,YMAX,ICLR,IWIDTH,ITYPE,IPATTERN,LEG,XT)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: IPATTERN !## 0=solid,1=line,2=dots
INTEGER,INTENT(IN) :: ICLR,IWIDTH,ITYPE
REAL(KIND=DP_KIND),INTENT(IN) :: XMIN,XMAX,YMAX
REAL(KIND=DP_KIND),INTENT(INOUT) :: YMIN
REAL(KIND=DP_KIND),INTENT(IN),OPTIONAL :: XT
TYPE(LEGENDOBJ),INTENT(INOUT),OPTIONAL :: LEG
REAL(KIND=DP_KIND) :: DX,DY,Y
INTEGER :: I
!## solid
IF(IPATTERN.EQ.0)THEN
CALL IGRCOLOURN(ICLR)
CALL IGRFILLPATTERN(SOLID)
CALL DBL_IGRRECTANGLE(XMIN,YMIN,XMAX,YMAX)
!## lines
ELSEIF(IPATTERN.EQ.1)THEN
!## clear it (white)
CALL IGRFILLPATTERN(SOLID)
CALL IGRCOLOURN(WRGB(255,255,255))
CALL DBL_IGRRECTANGLE(XMIN,YMIN,XMAX,YMAX)
CALL IGRCOLOURN(ICLR)
CALL IGRFILLPATTERN(OUTLINE)
CALL IGRLINETYPE(ITYPE)
CALL IGRLINEWIDTH(IWIDTH)
CALL DBL_IGRMOVETO(XMIN,YMIN)
DX=(XMAX-XMIN)/3.0
DY=(YMAX-YMIN)
CALL DBL_IGRLINETOREL(DX, DY)
CALL DBL_IGRLINETOREL(DX,-DY)
CALL DBL_IGRLINETOREL(DX, DY)
!## dots
ELSEIF(IPATTERN.EQ.2)THEN
!## clear it (white)
CALL IGRFILLPATTERN(SOLID)
CALL IGRCOLOURN(WRGB(255,255,255))
CALL DBL_IGRRECTANGLE(XMIN,YMIN,XMAX,YMAX)
DY=(XMAX-XMIN)/10.0D0
CALL IGRCOLOURN(ICLR)
CALL IGRFILLPATTERN(SOLID)
DX=(XMAX-XMIN)/4.0
DO I=1,3
CALL DBL_IGRCIRCLE(XMIN+(DX*REAL(I)),(YMAX+YMIN)/2.0,DY)
END DO
!## filled in (a) if present with legend (b) stripes
ELSEIF(IPATTERN.EQ.3)THEN
CALL IGRFILLPATTERN(SOLID)
!## use a legend if present
IF(PRESENT(LEG))THEN
IF(LEG%NCLR.GT.MXCLASS)THEN; DY=(3.0*(YMAX-YMIN))/REAL(LEG%NCLR); ELSE; DY=YMAX-YMIN; ENDIF; Y=YMAX
DO I=1,LEG%NCLR
CALL IGRCOLOURN(LEG%RGB(I)); CALL DBL_IGRRECTANGLE(XMIN,Y-DY,XMAX,Y)
IF(LEG%NCLR.LE.MXCLASS)THEN
CALL IGRCOLOURN(WRGB(0,0,0)); CALL DBL_WGRTEXTSTRING(XT,Y-(DY/2.0),TRIM(LEG%LEGTXT(I)))
ELSE
CALL IGRCOLOURN(WRGB(0,0,0))
IF(I.EQ.1) CALL DBL_WGRTEXTSTRING(XT,YMAX-(0.5*(YMAX-YMIN)),TRIM(LEG%LEGTXT(I)))
IF(I.EQ.LEG%NCLR)CALL DBL_WGRTEXTSTRING(XT,YMAX-(2.5*(YMAX-YMIN)),TRIM(LEG%LEGTXT(I)))
ENDIF
Y=Y-DY
END DO
YMIN=Y
ELSE
DX=(XMAX-XMIN)/10.0D0
DO I=1,9
IF(MOD(I,2).EQ.0)CALL IGRCOLOURN(ICLR)
IF(MOD(I,2).NE.0)CALL IGRCOLOURN(WRGB(255,255,255))
CALL DBL_IGRRECTANGLE(XMIN+(DX*REAL(I-1)),YMIN,XMIN+(DX*REAL(I)),YMAX)
END DO
ENDIF
ENDIF
CALL IGRFILLPATTERN(OUTLINE)
CALL IGRLINETYPE(SOLIDLINE)
CALL IGRLINEWIDTH(1)
CALL IGRCOLOURN(WRGB(225,225,225))
CALL DBL_IGRRECTANGLE(XMIN,YMIN,XMAX,YMAX)
CALL IGRCOLOURN(ICLR)
END SUBROUTINE
!###====================================================================
SUBROUTINE UTL_GETRELEVANTDIR(DIRNAMES,NDIR)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: NDIR
CHARACTER(LEN=*),INTENT(INOUT),DIMENSION(NDIR) :: DIRNAMES
INTEGER :: I,II,JJ,J
!## nothing to do
IF(NDIR.LE.0)RETURN
IF(NDIR.EQ.1)THEN
I=INDEX(DIRNAMES(1),'\',.TRUE.)
IF(I.NE.0)DIRNAMES(1)='..\'//DIRNAMES(1)(I+1:)
RETURN
ENDIF
DO I=1,NDIR
DIRNAMES(I)=UTL_CAP(DIRNAMES(I),'U')
END DO
II=0
JJ=0
DO WHILE(JJ.EQ.0)
II=II+1
DO I=1,NDIR
DO J=1,NDIR
IF(DIRNAMES(I)(II:II).NE.DIRNAMES(J)(II:II).AND.JJ.EQ.0)JJ=II!EXIT! LOOPII
END DO
END DO
ENDDO
DO I=1,NDIR
J=INDEX(DIRNAMES(I)(:II),'\',.TRUE.)
IF(J.NE.0)DIRNAMES(I)='..\'//DIRNAMES(I)(J+1:)
ENDDO
END SUBROUTINE UTL_GETRELEVANTDIR
!###====================================================================
SUBROUTINE UTL_GETDIRPART(IPART,DIR,DIRPART)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: IPART
CHARACTER(LEN=*),INTENT(IN) :: DIR
CHARACTER(LEN=*),INTENT(OUT) :: DIRPART
INTEGER :: I,J,K
DIRPART=''
IF(IPART.EQ.0)THEN
J=INDEX(DIR,':')
IF(J.EQ.0)RETURN
DIRPART=DIR(:J-1)
ELSE
K=1
DO I=1,IPART
J=INDEX(DIR(K:),'\')
!## nothing found for current ipart
IF(J.EQ.0)RETURN
K=J+1
ENDDO
J=INDEX(DIR(K:),'\')
IF(J.NE.0)DIRPART=DIR(K:J-1)
ENDIF
END SUBROUTINE UTL_GETDIRPART
!###====================================================================
SUBROUTINE UTL_SETTEXTSIZE(CHW,CHH,FCT,IMARKER)
!###====================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),PARAMETER :: INI_CHH=0.00333D0
REAL(KIND=DP_KIND),PARAMETER :: INI_CHW=0.00133D0
REAL(KIND=DP_KIND),OPTIONAL :: FCT
INTEGER,INTENT(IN),OPTIONAL :: IMARKER
REAL(KIND=DP_KIND),INTENT(OUT) :: CHW,CHH
REAL(KIND=DP_KIND) :: IWD,IHD,X1,X2,Y1,Y2,RAT,DY
IWD=REAL(WINFODRAWABLE(DRAWABLEWIDTH),8)
IHD=REAL(WINFODRAWABLE(DRAWABLEHEIGHT),8)
X1 =REAL(INFOGRAPHICS(GRAPHICSAREAMINX),8)
X2 =REAL(INFOGRAPHICS(GRAPHICSAREAMAXX),8)
Y1 =REAL(INFOGRAPHICS(GRAPHICSAREAMINY),8)
Y2 =REAL(INFOGRAPHICS(GRAPHICSAREAMAXY),8)
DY=1.0D0; IF(PRESENT(FCT))DY=FCT
CHH=INI_CHH
IF(PRESENT(IMARKER))THEN
IF(IMARKER.EQ.1)CHH=0.00133D0
ENDIF
CHH=CHH*FCT
CHW=INI_CHW*FCT
RAT=IWD/IHD
CHW=CHW/RAT
RAT=(X2-X1)/(Y2-Y1)
CHW=CHW/RAT
END SUBROUTINE UTL_SETTEXTSIZE
!###======================================================================
SUBROUTINE UTL_IMODFILLMENU(ID,DIRNAME,WC,F,N,IMENUTYPE,ISTORE,SETNAME,CORDER)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(OUT) :: N
INTEGER,INTENT(IN) :: ID,IMENUTYPE,ISTORE ! Dialog ID,*, *
CHARACTER(LEN=*),INTENT(IN),OPTIONAL :: SETNAME,CORDER !*, display ordered (1) or not (0)
CHARACTER(LEN=*),INTENT(IN) :: DIRNAME,WC,F ! Directoryname, Selection string, display type (file 'F' or directory 'D')
INTEGER :: I
CALL UTL_IMODFILLMENU_DEAL()
N=0
IF(LEN_TRIM(DIRNAME).EQ.0)THEN
IF(ID.NE.0)CALL WDIALOGCLEARFIELD(ID)
RETURN
ENDIF
IF(.NOT.IOSDIREXISTS(DIRNAME))THEN
IF(ID.NE.0)CALL WDIALOGCLEARFIELD(ID)
RETURN
ENDIF
CALL IOSDIRENTRYTYPE(F)
CALL IOSDIRCOUNT(DIRNAME,WC,N)
IF(N.EQ.0)THEN
IF(ID.NE.0)THEN
CALL WDIALOGCLEARFIELD(ID)
CALL WDIALOGFIELDSTATE(ID,2)
ENDIF
ELSE
ALLOCATE(LISTNAME(N))
IF(PRESENT(CORDER))THEN
CALL UTL_DIRINFO(DIRNAME,WC,LISTNAME,N,F,CORDER)
ELSE
CALL UTL_DIRINFO(DIRNAME,WC,LISTNAME,N,F)
ENDIF
IF(N.GT.0.AND.ID.NE.0)THEN
DO I=1,N; LISTNAME(I)=UTL_CAP(LISTNAME(I),'U'); END DO
CALL WDIALOGFIELDSTATE(ID,1)
IF(IMENUTYPE.EQ.0)THEN
IF(PRESENT(SETNAME))THEN
DO I=1,N; IF(UTL_CAP(LISTNAME(I),'U').EQ.UTL_CAP(SETNAME,'U'))EXIT; ENDDO
IF(I.LE.N)THEN
CALL WDIALOGPUTMENU(ID,LISTNAME,N,I)
ELSE
CALL WDIALOGPUTMENU(ID,LISTNAME,N,1)
ENDIF
ELSE
CALL WDIALOGPUTMENU(ID,LISTNAME,N,1)
ENDIF
ELSEIF(IMENUTYPE.EQ.1)THEN
ALLOCATE(ILIST(N)); ILIST=0
CALL WDIALOGPUTMENU(ID,LISTNAME(1:N),N,ILIST)
ENDIF
ELSE
IF(ID.NE.0)THEN
CALL WDIALOGCLEARFIELD(ID)
IF(IMENUTYPE.EQ.0)CALL WDIALOGFIELDSTATE(ID,2)
ENDIF
ENDIF
ENDIF
IF(ISTORE.EQ.0)CALL UTL_IMODFILLMENU_DEAL()
END SUBROUTINE UTL_IMODFILLMENU
!###====================================================================
SUBROUTINE UTL_IMODFILLMENU_DEAL()
!###====================================================================
IMPLICIT NONE
IF(ALLOCATED(ILIST))DEALLOCATE(ILIST)
IF(ALLOCATED(LISTNAME))DEALLOCATE(LISTNAME)
END SUBROUTINE UTL_IMODFILLMENU_DEAL
!###====================================================================
INTEGER FUNCTION GETITOPIC(CKEYWORD)
!###====================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: CKEYWORD
INTEGER :: I
GETITOPIC=0
DO I=1,MXTP
IF(TRIM(TP(I)%ACRNM).EQ.TRIM(CKEYWORD))GETITOPIC=I
ENDDO
END FUNCTION GETITOPIC
!###======================================================================
SUBROUTINE UTL_PLOTLOCATIONIDF(IDF,IROW,ICOL)
!###======================================================================
IMPLICIT NONE
TYPE(IDFOBJ),INTENT(IN) :: IDF
INTEGER,INTENT(IN) :: IROW,ICOL
REAL(KIND=DP_KIND) :: X1,X2,Y1,Y2
IF(IROW.EQ.0.OR.ICOL.EQ.0)RETURN
CALL IGRPLOTMODE(MODEXOR); CALL IGRFILLPATTERN(OUTLINE); CALL IGRLINEWIDTH(2)
CALL UTL_PLOT1BITMAP()
IF(IDF%IEQ.EQ.0)THEN
X1=IDF%XMIN+(ICOL-1)*IDF%DX; X2=IDF%XMIN+ ICOL *IDF%DX
Y1=IDF%YMAX-(IROW-1)*IDF%DY; Y2=IDF%YMAX- IROW *IDF%DY
ELSEIF(IDF%IEQ.EQ.1)THEN
X1=IDF%SX(ICOL-1); Y1=IDF%SY(IROW-1)
X2=IDF%SX(ICOL); Y2=IDF%SY(IROW)
ENDIF
!## selected cell
CALL DBL_IGRRECTANGLE(X1,Y1,X2,Y2,IOFFSET=1)
CALL IGRLINEWIDTH(1); CALL IGRLINETYPE(SOLIDLINE); CALL UTL_PLOT2BITMAP()
END SUBROUTINE UTL_PLOTLOCATIONIDF
!###======================================================================
SUBROUTINE UTL_HIDESHOWDIALOG(ID,ISHOW)
!###======================================================================
INTEGER,INTENT(IN) :: ID,ISHOW
INTEGER :: IX,IY,I
I=WINFOERROR(1)
CALL WDIALOGSELECT(ID)
I=WINFOERROR(1)
IF(ISHOW.EQ.0)THEN
CALL WDIALOGHIDE()
ELSE
IX=WINFODIALOG(DIALOGXPOS)
IY=WINFODIALOG(DIALOGYPOS)
CALL UTL_DIALOGSHOW(IX,IY,0,ISHOW)
ENDIF
END SUBROUTINE UTL_HIDESHOWDIALOG
!###======================================================================
SUBROUTINE UTL_DIALOGSHOW(IXPOS,IYPOS,IFIELD,ITYPE)
!###======================================================================
INTEGER,INTENT(IN) :: IFIELD,ITYPE,IXPOS,IYPOS
!INTEGER :: JFIELD,JTYPE
!Default values
!JFIELD=0 ; IF(PRESENT(IFIELD)) JFIELD=IFIELD
!JTYPE=2 ; IF(PRESENT(ITYPE)) JTYPE=ITYPE
!In Winteracter versions up to and including v12.0, a value of -1 could also be specified for either coordinate, to centre the dialog
!From Winteracter 13.0, to centre a dialog, either horizontally or vertically, omit the corresponding IXPOS/IYPOS argument
IF(IXPOS.EQ.-1.AND.IYPOS.EQ.-1) THEN
CALL WDIALOGSHOW(IFIELD=IFIELD,ITYPE=ITYPE)
ELSE
CALL WDIALOGSHOW(IXPOS,IYPOS,IFIELD,ITYPE)
ENDIF
END SUBROUTINE UTL_DIALOGSHOW
!###======================================================================
SUBROUTINE UTL_IDFGETLAYERS(IDFNAME,N,ILAY)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: N
CHARACTER(LEN=*),DIMENSION(N) :: IDFNAME
INTEGER :: I,J,K,IL,IOS
INTEGER,DIMENSION(:) :: ILAY
ILAY=0
DO I=1,N
J=INDEXNOCASE(IDFNAME(I),'_L',.TRUE.)
IF(J.NE.0)THEN
K=INDEXNOCASE(IDFNAME(I),'.IDF',.TRUE.)
IF(K.NE.0)THEN
J=J+2
K=K-1
READ(IDFNAME(I)(J:K),*,IOSTAT=IOS) IL
IF(IOS.EQ.0.AND.IL.GT.0)ILAY(IL)=1
ENDIF
ENDIF
END DO
END SUBROUTINE UTL_IDFGETLAYERS
!###======================================================================
SUBROUTINE UTL_IDFGETDATES(IDFNAME,N,M,O,MINDATE,MAXDATE,ID)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: N,ID
INTEGER(KIND=8),INTENT(OUT) :: MINDATE,MAXDATE
INTEGER,INTENT(OUT) :: M,O
CHARACTER(LEN=*),DIMENSION(N) :: IDFNAME
INTEGER :: I,IDATE,IYR,IMH,IDY,IHR,IMT,ISC
INTEGER(KIND=8) :: DIDATE
REAL(KIND=DP_KIND) :: DAYFRACTION
MINDATE=21000101000000
MAXDATE=19000101000000
M =0
O =0
DO I=1,N
IDATE=UTL_IDFGETDATE(IDFNAME(I),DAYFRACTION,IYR,IMH,IDY,IHR,IMT,ISC)
IF(IDATE.NE.0)THEN
O=O+1
DIDATE=YMDHMSTOITIME(IYR,IMH,IDY,IHR,IMT,ISC)
MINDATE=MIN(MINDATE,DIDATE)
MAXDATE=MAX(MAXDATE,DIDATE)
ELSE
IF(INDEX(UTL_CAP(IDFNAME(I),'U'),'_STEADY-STATE_').NE.0)M=M+1
ENDIF
IF(ID.NE.0)CALL WDIALOGPUTPROGRESSBAR(ID,1,1)
END DO
END SUBROUTINE UTL_IDFGETDATES
!###======================================================================
INTEGER FUNCTION UTL_IDFGETDATE(IDFNAME,DAYFRACTION,IYR,IMH,IDY,IHR,IMT,ISC,IDATEFULL)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: IDFNAME
REAL(KIND=DP_KIND),INTENT(OUT),OPTIONAL :: DAYFRACTION
INTEGER,INTENT(OUT),OPTIONAL :: IDY,IMH,IYR,IHR,IMT,ISC
INTEGER(KIND=DP_KIND),INTENT(OUT),OPTIONAL :: IDATEFULL
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
!## 14 digits
IF(II.EQ.1)THEN
IF(PRESENT(IDATEFULL))READ(IDFNAME(J:J+13),*) IDATEFULL
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
!## 8 digits
ELSE
IF(PRESENT(IDATEFULL))THEN
READ(IDFNAME(J:J+7),*) IDATEFULL; IDATEFULL=IDATEFULL*1000000
ENDIF
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
!###======================================================================
SUBROUTINE UTL_FILLDATES(IDY,IDM,IDD,JULD)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(OUT),OPTIONAL :: JULD
INTEGER,INTENT(IN) :: IDM,IDY,IDD
INTEGER :: M,Y,D,NDAY
CALL WDIALOGGETMENU(IDM,M)
CALL WDIALOGGETINTEGER(IDY,Y)
NDAY=WDATEDAYSINMONTH(Y,M)
CALL WDIALOGGETINTEGER(IDD,D)
CALL WDIALOGRANGEINTEGER(IDD,1,NDAY)
IF(D.GT.NDAY)CALL WDIALOGPUTINTEGER(IDD,NDAY)
D=MIN(D,NDAY)
IF(.NOT.PRESENT(JULD))RETURN
JULD=JD(Y,M,D)
END SUBROUTINE UTL_FILLDATES
!###======================================================================
SUBROUTINE UTL_FILLDATESDIALOG(ID,IDD,IDM,IDY,JD)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: ID,IDD,IDM,IDY,JD
INTEGER :: I,J,K
CALL WDIALOGSELECT(ID)
!## put begin date
CALL IDATETOGDATE(JD,I,J,K) !## id,iy,im,id
CALL WDIALOGPUTINTEGER(IDD,K)
CALL WDIALOGPUTINTEGER(IDY,I)
CALL WDIALOGPUTOPTION(IDM,J)
END SUBROUTINE UTL_FILLDATESDIALOG
!###======================================================================
FUNCTION ITOS(I)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: I
CHARACTER(LEN=10) :: TXT,ITOS
WRITE(TXT,'(I10)') I
ITOS=ADJUSTL(TXT)
END FUNCTION ITOS
!###======================================================================
FUNCTION LTOS(LEX,OC)
!###======================================================================
IMPLICIT NONE
LOGICAL,INTENT(IN) :: LEX
INTEGER,INTENT(IN) :: OC ! output control: 1=single, 2= full
CHARACTER(LEN=10) :: TXT,LTOS
! Function: Logical 2 string
IF(LEX) THEN ; WRITE(TXT,'(A)') 'TRUE' ;
ELSE ; WRITE(TXT,'(A)') 'FALSE' ; ENDIF
IF(OC.EQ.1) TXT=TXT(:1)
LTOS=ADJUSTL(TXT)
END FUNCTION LTOS
!###======================================================================
FUNCTION ITOS_DBL(I)
!###======================================================================
IMPLICIT NONE
INTEGER(KIND=DP_KIND),INTENT(IN) :: I
CHARACTER(LEN=16) :: TXT,ITOS_DBL
WRITE(TXT,'(I16)') I
ITOS_DBL=ADJUSTL(TXT)
END FUNCTION ITOS_DBL
!###======================================================================
CHARACTER(LEN=24) FUNCTION RTOS(X,F,NDEC)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: NDEC
REAL(KIND=DP_KIND),INTENT(IN) :: X
CHARACTER(LEN=1),INTENT(IN) :: F
CHARACTER(LEN=24) :: TXT,FRM
INTEGER :: IOS
IF(F.EQ.'*')THEN
WRITE(TXT,*,IOSTAT=IOS) X
ELSE
WRITE(FRM,'(2A1,I2.2,A1,I2.2,A1)') '(',F,LEN(RTOS),'.',NDEC,')'
WRITE(TXT,FRM,IOSTAT=IOS) X
ENDIF
IF(IOS.NE.0)TXT='error'
RTOS=ADJUSTL(TXT)
END FUNCTION RTOS
!###======================================================================
INTEGER FUNCTION UTL_GETUNIT()
!###======================================================================
IMPLICIT NONE
LOGICAL :: LEX
UTL_GETUNIT=19
DO
UTL_GETUNIT=UTL_GETUNIT+1
INQUIRE(UNIT=UTL_GETUNIT,OPENED=LEX)
IF(.NOT.LEX)EXIT
IF(UTL_GETUNIT.GT.MAXUNITS)EXIT
END DO
IF(LEX)THEN
CALL WMESSAGEBOX(OKONLY,COMMONOK,EXCLAMATIONICON,'iMOD cannot open more than '//TRIM(ITOS(MAXUNITS))//' files simultaneously!','ERROR')
UTL_GETUNIT=0
ENDIF
END FUNCTION UTL_GETUNIT
!###======================================================================
SUBROUTINE UTL_CLOSEUNITS()
!###======================================================================
IMPLICIT NONE
INTEGER :: I,J
LOGICAL :: LEX
DO I=20,MAXUNITS
J=I
INQUIRE(UNIT=J,OPENED=LEX)
IF(LEX.AND.J.GT.0)CLOSE(J)
END DO
END SUBROUTINE UTL_CLOSEUNITS
!###======================================================================
SUBROUTINE UTL_LISTOPENFILES()
!###======================================================================
IMPLICIT NONE
INTEGER,ALLOCATABLE,DIMENSION(:) :: UNITS,ICHECK
CHARACTER(LEN=256),ALLOCATABLE,DIMENSION(:) :: FNAME
INTEGER :: NOPEN,ITYPE,I,MXNROW
TYPE(WIN_MESSAGE) :: MESSAGE
!## get list of open unit numbers
ALLOCATE(FNAME(100),UNITS(100),ICHECK(100))
CALL INFOUNITS(FNAME,UNITS,SIZE(FNAME),NOPEN)
IF(NOPEN.EQ.0)THEN
DEALLOCATE(FNAME,UNITS,ICHECK)
CALL WMESSAGEBOX(OKONLY,INFORMATIONICON,COMMONOK,'No files currently opened.','Information')
RETURN
ENDIF
ICHECK=1
CALL WDIALOGLOAD(ID_DFILESOPEN,ID_DFILESOPEN)
MXNROW=WINFOGRID(IDF_GRID1,GRIDROWSMAX); NOPEN=MIN(NOPEN,MXNROW)
CALL WGRIDROWS(IDF_GRID1,NOPEN)
CALL WGRIDPUTCHECKBOX(IDF_GRID1,1,ICHECK,NOPEN)
CALL WGRIDPUTINTEGER(IDF_GRID1,2,UNITS,NOPEN)
CALL WGRIDPUTSTRING(IDF_GRID1,3,FNAME,NOPEN)
CALL UTL_DIALOGSHOW(-1,-1,0,3)
DO
CALL WMESSAGE(ITYPE,MESSAGE)
SELECT CASE (ITYPE)
CASE (PUSHBUTTON)
SELECT CASE (MESSAGE%VALUE1)
CASE (ID_SELECTALL)
CASE (ID_DESELECTALL)
CASE (IDOK)
CALL WGRIDGETINTEGER(IDF_GRID1,1,ICHECK,NOPEN)
DO I=1,SIZE(ICHECK); IF(ICHECK(I).EQ.1)CLOSE(UNITS(I)); ENDDO
!## check again
CALL INFOUNITS(FNAME,UNITS,SIZE(FNAME),NOPEN)
IF(NOPEN.EQ.0)EXIT
NOPEN=MIN(NOPEN,MXNROW)
ICHECK=1
CALL WGRIDROWS(IDF_GRID1,NOPEN)
CALL WGRIDPUTCHECKBOX(IDF_GRID1,1,ICHECK,NOPEN)
CALL WGRIDPUTINTEGER(IDF_GRID1,2,UNITS,NOPEN)
CALL WGRIDPUTSTRING(IDF_GRID1,3,FNAME,NOPEN)
CASE (IDHELP)
CASE (IDCANCEL)
EXIT
END SELECT
CASE (FIELDCHANGED)
END SELECT
ENDDO
DEALLOCATE(FNAME,UNITS,ICHECK)
CALL WDIALOGUNLOAD()
END SUBROUTINE UTL_LISTOPENFILES
!###======================================================================
SUBROUTINE INFOUNITS(FNAME,UNITS,N,NOPEN)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: N
INTEGER,INTENT(OUT) :: NOPEN
INTEGER,DIMENSION(N),INTENT(INOUT) :: UNITS
CHARACTER(LEN=*),DIMENSION(N),INTENT(INOUT) :: FNAME
INTEGER :: I,J
LOGICAL :: LEX
CHARACTER(LEN=256) :: FN
NOPEN=0; DO I=20,MAXUNITS
J=I
INQUIRE(UNIT=J,OPENED=LEX)
IF(LEX.AND.J.GT.0)THEN
INQUIRE(UNIT=J,NAME=FN)
NOPEN=NOPEN+1
!## stop getting open files
IF(NOPEN.GT.SIZE(FNAME))EXIT
FNAME(NOPEN)=FN
UNITS(NOPEN)=J
ENDIF
END DO
END SUBROUTINE INFOUNITS
!###======================================================================
SUBROUTINE UTL_CREATEDIR(DIRNAME)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: DIRNAME
INTEGER :: I,J
!## create/check entire directory
I=INDEX(DIRNAME,'\')+1
DO
J=INDEX(DIRNAME(I:),'\')
IF(J.EQ.0)EXIT
J=J+I
IF(.NOT.IOSDIREXISTS(DIRNAME(:J-2)))CALL IOSDIRMAKE(DIRNAME(:J-2))
I=J
END DO
!## only create folder, is there is a subfolder left
IF(INDEX(DIRNAME,'\').NE.0)THEN
!## last remaining of string
IF(.NOT.IOSDIREXISTS(TRIM(DIRNAME)))CALL IOSDIRMAKE(TRIM(DIRNAME))
ENDIF
END SUBROUTINE UTL_CREATEDIR
!###======================================================================
LOGICAL FUNCTION UTL_DEL1TREE(DIR)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: DIR
INTEGER :: I,IERROR
CHARACTER(LEN=256) :: CURDIR,DELDIR
UTL_DEL1TREE=.FALSE.
CALL IOSDIRNAME(CURDIR)
I=INDEXNOCASE(DIR,'\',.TRUE.)
!## clear existing error?
IERROR=INFOERROR(1)
CALL IOSDIRCHANGE(DIR(:I-1))
IERROR=INFOERROR(1)
!## dirchange error?
IF(IERROR.NE.0)THEN
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'Could not find directory:'//CHAR(13)// &
TRIM(DIR(:I-1)),'iMOD: Error')
RETURN
ENDIF
!## make sure to delete directory
CALL WMESSAGEBOX(YESNO,QUESTIONICON,COMMONNO,'Are you sure to delete'//CHAR(13)//TRIM(DIR),'Question?')
IF(WINFODIALOG(4).NE.1)RETURN
!## delete entire directory
DELDIR=DIR(I+1:)
CALL UTL_DEL2TREE(DELDIR)
CALL IOSDIRCHANGE(CURDIR)
UTL_DEL1TREE=.TRUE.
END FUNCTION UTL_DEL1TREE
!###======================================================================
RECURSIVE SUBROUTINE UTL_DEL2TREE(DIR)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=256),INTENT(IN) :: DIR
INTEGER,PARAMETER :: MXDIR=50
INTEGER :: I,NDIR,IERROR
CHARACTER(LEN=256),DIMENSION(MXDIR) :: RESDIR
CALL WINDOWOUTSTATUSBAR(4,'Delete directory '//TRIM(DIR)//'...')
!## clear existing error?
IERROR=INFOERROR(1)
!## go one level down
CALL IOSDIRCHANGE(DIR)
IERROR=INFOERROR(1)
!## dirchange error?
IF(IERROR.NE.0)THEN
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'Could not change towards directory:'//CHAR(13)// &
TRIM(DIR),'iMOD: Error')
RETURN
ENDIF
!## how many subdirectories exist?
NDIR=MXDIR
CALL IOSDIRENTRYTYPE('D')
CALL IOSDIRINFO(' ',' ',RESDIR,NDIR)
IF(NDIR.GT.MXDIR)THEN
CALL WMESSAGEBOX(OKONLY,INFORMATIONICON,COMMONOK,'MXDIR overwritten in del2tree()','ERROR')
RETURN
ENDIF
DO I=3,NDIR
CALL UTL_DEL2TREE(RESDIR(I))
END DO
!## delete all files in directory
CALL IOSDELETEFILE('*.*')
!## return one level up
CALL IOSDIRCHANGE('..')
CALL IOSDIRDELETE(DIR)
END SUBROUTINE UTL_DEL2TREE
!###======================================================================
SUBROUTINE UTL_WAITMESSAGE(IRAT,IRAT1,I1,I2,WAITTXT,IBOX)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: I1,I2
INTEGER,INTENT(INOUT) :: IRAT,IRAT1
CHARACTER(LEN=*),INTENT(IN) :: WAITTXT
INTEGER,OPTIONAL,INTENT(IN) :: IBOX
INTEGER :: JBOX
JBOX=4; IF(PRESENT(IBOX))JBOX=IBOX
IRAT=(I1*100)/I2
IF(IRAT.NE.IRAT1)THEN
CALL WINDOWOUTSTATUSBAR(JBOX,TRIM(WAITTXT)//' '//TRIM(ITOS(IRAT))//' %')
IRAT1=IRAT
ENDIF
END SUBROUTINE UTL_WAITMESSAGE
!###======================================================================
SUBROUTINE UTL_MESSAGEHANDLE(ONOFF)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: ONOFF
INTEGER :: I
IF(ONOFF.EQ.0)CALL WCURSORSHAPE(CURHOURGLASS)
IF(ONOFF.EQ.1)CALL WCURSORSHAPE(CURARROW)
DO I=1,MXMESSAGE
IF(IMESSAGE(I).EQ.1)THEN
IF(WINFOMESSAGE(I).NE.ONOFF)CALL WMESSAGEENABLE(I,ONOFF)
ENDIF
END DO
IF(ONOFF.EQ.0)RETURN
END SUBROUTINE UTL_MESSAGEHANDLE
!###======================================================================
SUBROUTINE UTL_MESSAGEHANDLE3D(ONOFF)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: ONOFF
!## default mousemove off
IMESSAGE(MOUSEMOVE)=ONOFF
END SUBROUTINE UTL_MESSAGEHANDLE3D
!###======================================================================
SUBROUTINE UTL_GETDAYANDMONTHFROMDAYNUMBER(DN,IY,ID,IM)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: DN,IY
INTEGER,INTENT(OUT) :: IM,ID
INTEGER :: TD
TD=0; DO IM=1,12
TD=TD+WDATEDAYSINMONTH(IY,IM)
IF(DN.LE.TD)EXIT
ENDDO
ID=WDATEDAYSINMONTH(IY,IM)-(TD-DN)
END SUBROUTINE UTL_GETDAYANDMONTHFROMDAYNUMBER
!###======================================================================
INTEGER FUNCTION UTL_GETDAYNUMBERFROMJD(JDATE)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: JDATE
INTEGER :: ID,IM,IY,JD1
CALL UTL_GDATE(JDATE,IY,IM,ID); JD1=JD(IY,1,1)
UTL_GETDAYNUMBERFROMJD=(JDATE-JD1)+1
END FUNCTION UTL_GETDAYNUMBERFROMJD
!###======================================================================
INTEGER FUNCTION UTL_GETCURRENTDATE()
!###======================================================================
IMPLICIT NONE
INTEGER :: IY,IM,ID
CALL IOSDATE(IY,IM,ID)
UTL_GETCURRENTDATE=IY*10000+IM*100+ID
END FUNCTION UTL_GETCURRENTDATE
!###======================================================================
CHARACTER(LEN=8) FUNCTION UTL_GETCURRENTTIME()
!###======================================================================
IMPLICIT NONE
INTEGER :: IH,IM,IS
CHARACTER(LEN=8) :: CTIME
CALL IOSTIME(IH,IM,IS)
WRITE(CTIME,'(3(I2.2,A1))') IH,':',IM,':',IS
UTL_GETCURRENTTIME=TRIM(CTIME)
END FUNCTION UTL_GETCURRENTTIME
!###======================================================================
FUNCTION JDATETOGDATE(I,DTYPE)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: I
INTEGER,INTENT(IN),OPTIONAL :: DTYPE
CHARACTER(LEN=10) :: JDATETOGDATE
INTEGER :: IY,IM,ID
IF(I.GT.0)THEN
CALL UTL_GDATE(I,IY,IM,ID)
ELSE
IY=0
IM=0
ID=0
ENDIF
IF(PRESENT(DTYPE))THEN
SELECT CASE (DTYPE)
CASE (0)
JDATETOGDATE=TRIM(ITOS(ID))//'-'//TRIM(ITOS(IM))//'-'//TRIM(ITOS(IY))
CASE (1)
JDATETOGDATE=TRIM(ITOS(ID))//'/'//TRIM(ITOS(IM))//'/'//TRIM(ITOS(IY))
CASE (2)
WRITE(JDATETOGDATE,'(I4.4,2I2.2)') IY,IM,ID
END SELECT
ELSE
JDATETOGDATE=TRIM(ITOS(ID))//'/'//TRIM(ITOS(IM))//'/'//TRIM(ITOS(IY))
ENDIF
END FUNCTION JDATETOGDATE
!###======================================================================
CHARACTER(LEN=20) FUNCTION JDATETOFDATE(X,JOFFSET,DTYPE)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: JOFFSET
INTEGER,INTENT(IN),OPTIONAL :: DTYPE
REAL(KIND=DP_KIND),INTENT(IN) :: X
CHARACTER(LEN=8) :: CTIME
REAL(KIND=DP_KIND) :: FTIME
INTEGER :: DDTYPE
IF(PRESENT(DTYPE))THEN
DDTYPE=DTYPE
ELSE
DDTYPE=0
ENDIF
JDATETOFDATE=JDATETOGDATE(INT(X)+JOFFSET,DTYPE)
FTIME=X-FLOOR(X)
CALL FTIMETOCTIME(FTIME,CTIME,DDTYPE)
IF(CTIME.NE.'00:00:00')THEN
IF(DDTYPE.EQ.2)THEN
JDATETOFDATE=TRIM(JDATETOFDATE)//TRIM(CTIME)
ELSE
JDATETOFDATE=TRIM(JDATETOFDATE)//' '//TRIM(CTIME)
ENDIF
ENDIF
END FUNCTION JDATETOFDATE
!###======================================================================
INTEGER FUNCTION GDATETOJDATE(CDATE)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(INOUT) :: CDATE
INTEGER :: IY,IM,ID,I,J,MD
INTEGER,DIMENSION(3) :: IOS
IOS=1
I=INDEX(CDATE,'/',.FALSE.)
IF(I.GT.0)THEN
READ(CDATE(1:I-1),*,IOSTAT=IOS(1)) ID
J=INDEX(CDATE,'/',.TRUE.)
IF(J.GT.0)THEN
READ(CDATE(J+1:),*,IOSTAT=IOS(3)) IY
IF(J-I.GT.0)READ(CDATE(I+1:J-1),*,IOSTAT=IOS(2)) IM
ENDIF
ENDIF
!## initialize default value
GDATETOJDATE=0
IM=MAX(1,MIN(12,IM))
MD=WDATEDAYSINMONTH(IY,IM)
ID=MAX(1,MIN(MD,ID))
!## error reading dates
IF(SUM(IOS).NE.0)RETURN
J =JD(IY,IM,ID)
CDATE =JDATETOGDATE(J)
GDATETOJDATE=J
END FUNCTION GDATETOJDATE
!###====================================================================
INTEGER FUNCTION UTL_IDATETOJDATE(IDATE)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: IDATE
INTEGER :: IY,IM,ID
CALL IDATETOGDATE(IDATE,IY,IM,ID)
UTL_IDATETOJDATE=JD(IY,IM,ID)
END FUNCTION UTL_IDATETOJDATE
!###====================================================================
INTEGER FUNCTION UTL_JDATETOIDATE(JDATE)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: JDATE
INTEGER :: IY,IM,ID
CALL UTL_GDATE(JDATE,IY,IM,ID)
UTL_JDATETOIDATE=IY*10000+IM*100+ID
END FUNCTION UTL_JDATETOIDATE
!###====================================================================
SUBROUTINE IDATETOGDATE(IDATE,IY,IM,ID)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: IDATE
INTEGER,INTENT(OUT) :: IY,IM,ID
IY = IDATE / 10000
IM = MOD( IDATE, 10000 ) / 100
ID = MOD( IDATE, 100 )
END SUBROUTINE IDATETOGDATE
!###====================================================================
SUBROUTINE FTIMETOITIME(FTIME,IH,IM,IS)
!###====================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: FTIME
INTEGER,INTENT(OUT) :: IH,IM,IS
INTEGER :: ITIME
ITIME=FTIME*SDAY
CALL ITIMETOGTIME(ITIME,IH,IM,IS)
END SUBROUTINE FTIMETOITIME
!###====================================================================
SUBROUTINE FTIMETOCTIME(FTIME,CTIME,DTYPE)
!###====================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: FTIME
CHARACTER(LEN=*),INTENT(OUT) :: CTIME
INTEGER,INTENT(IN),OPTIONAL :: DTYPE
INTEGER :: IH,IM,IS
INTEGER :: ITIME
ITIME=FTIME*SDAY
CALL ITIMETOGTIME(ITIME,IH,IM,IS)
IF(PRESENT(DTYPE))THEN
SELECT CASE (DTYPE)
CASE (0)
WRITE(CTIME,'(3(I2.2,A1))') IH,':',IM,':',IS
CASE (1)
WRITE(CTIME,'(3(I2.2,A1))') IH,'-',IM,'-',IS
CASE (2)
WRITE(CTIME,'(3I2.2)') IH,IM,IS
END SELECT
ELSE
WRITE(CTIME,'(3(I2.2,A1))') IH,':',IM,':',IS
ENDIF
END SUBROUTINE FTIMETOCTIME
!###====================================================================
SUBROUTINE ITIMETOCDATE(IDATE,CDATE)
!###====================================================================
IMPLICIT NONE
INTEGER(KIND=8),INTENT(IN) :: IDATE
CHARACTER(LEN=52) :: CDATE
INTEGER :: IYR,IMH,IDY,IHR,IMT,ISC
CALL ITIMETOGDATE(IDATE,IYR,IMH,IDY,IHR,IMT,ISC)
IF(IHR.EQ.0.AND.IMT.EQ.0.AND.ISC.EQ.0)THEN
WRITE(CDATE,'(I4.4,2(A1,I2.2))') IYR,'/',IMH,'/',IDY
ELSE
WRITE(CDATE,'(I4.4,5(A1,I2.2))') IYR,'/',IMH,'/',IDY,' ',IHR,':',IMT,':',ISC
ENDIF
END SUBROUTINE ITIMETOCDATE
!###====================================================================
REAL(KIND=DP_KIND) FUNCTION ITIMETOFTIME(ITIME)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: ITIME !## hhmmss notation
INTEGER :: IH,IM,IS
CALL ITIMETOHMS(ITIME,IH,IM,IS)
ITIMETOFTIME=(REAL(IH)*3600.0D0+REAL(IM)*60.0D0+REAL(IS))/SDAY
END FUNCTION ITIMETOFTIME
!###====================================================================
SUBROUTINE ITIMETOHMS(ITIME,IH,IM,IS)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: ITIME !## hhmmss notation
INTEGER,INTENT(OUT) :: IH,IM,IS
IH = ITIME / 10000
IM = MOD( ITIME, 10000 ) / 100
IS = MOD( ITIME, 100 )
END SUBROUTINE ITIMETOHMS
!###====================================================================
INTEGER FUNCTION HMSTOITIME(IH,IM,IS)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: IH,IM,IS
HMSTOITIME=IH*10000+IM*100+IS
END FUNCTION HMSTOITIME
!###====================================================================
INTEGER(KIND=8) FUNCTION YMDHMSTOITIME(IY,IM,ID,IH,IT,IS)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: IY,IM,ID,IH,IT,IS
INTEGER(KIND=8) :: IYD,IMD,IDD,IHD,ITD,ISD
IYD=IY
IMD=IM
IDD=ID
IHD=IH
ITD=IT
ISD=IS
YMDHMSTOITIME=IYD*10000000000+ &
IMD*100000000+ &
IDD*1000000+ &
IHD*10000+ &
ITD*100+ &
ISD
END FUNCTION YMDHMSTOITIME
!###====================================================================
SUBROUTINE 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 ITIMETOGDATE
!###====================================================================
INTEGER FUNCTION UTL_DIFFDATE(SDATE,EDATE,DDATE)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: SDATE,EDATE,DDATE
INTEGER,DIMENSION(2) :: IY,IM,ID
INTEGER :: SD,ED,N
SD=UTL_IDATETOJDATE(SDATE); ED=UTL_IDATETOJDATE(EDATE)
CALL IDATETOGDATE(SDATE,IY(1),IM(1),ID(1))
CALL IDATETOGDATE(EDATE,IY(2),IM(2),ID(2))
SELECT CASE (DDATE)
!## daily
CASE (1)
UTL_DIFFDATE=(ED-SD)+1
!## weekly
CASE (2)
N=((ED-SD)+1)
UTL_DIFFDATE=N/7
IF(MOD(N,7).NE.0)UTL_DIFFDATE=UTL_DIFFDATE+1
!## month
CASE (3)
IF(IY(2).GT.IY(1))THEN
N=(12-IM(1))+1
N=N+(((IY(2)-IY(1))-1)*12)
N=N+IM(2)
UTL_DIFFDATE=N
ELSE
UTL_DIFFDATE=(IM(2)-IM(1))+1
ENDIF
CASE (4)
UTL_DIFFDATE=(IY(2)-IY(1))+1
END SELECT
END FUNCTION UTL_DIFFDATE
!###====================================================================
REAL(KIND=DP_KIND) FUNCTION 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
REAL(KIND=DP_KIND) :: F1,F2,F
SD=SDATE/1000000; ED=EDATE/1000000
SD=UTL_IDATETOJDATE(SD); ED=UTL_IDATETOJDATE(ED)
DD=ED-SD
!## start time
CALL ITIMETOGDATE(SDATE,IYR1,IMH1,IDY1,IHR1,IMT1,ISC1)
F1=(REAL(IHR1)*3600.0D0+REAL(IMT1)*60.0D0+REAL(ISC1))/SDAY
!## end time
CALL ITIMETOGDATE(EDATE,IYR2,IMH2,IDY2,IHR2,IMT2,ISC2)
F2=(REAL(IHR2)*3600.0D0+REAL(IMT2)*60.0D0+REAL(ISC2))/SDAY
!## same day
IF(SD.EQ.ED)THEN
F=F2-F1
ELSE
F=1.0D0-F1+F2+(DD-1)
ENDIF
! IF(ED.GT.SD)THEN; F1=1.0D0-F1; DD=DD-1; ENDIF
! IF(ED.EQ.SD)THEN; F1=F2-F1; F2=0.0D0; ENDIF
DIFFTIME=F !DD+(F1+F2)
END FUNCTION DIFFTIME
!###====================================================================
REAL(KIND=DP_KIND) FUNCTION CTIMETOFTIME(CTIME)
!###====================================================================
IMPLICIT NONE
CHARACTER(LEN=*) :: CTIME
INTEGER :: IH,IM,IS
READ(CTIME,'(3(I2.0,1X))') IH,IM,IS
CTIMETOFTIME=(REAL(IH)*3600.0D0+REAL(IM)*60.0D0+REAL(IS))/SDAY
END FUNCTION CTIMETOFTIME
!###====================================================================
SUBROUTINE DECDEGREES_TO_DMS(DEGREES,D,M,S)
!###====================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: DEGREES
REAL(KIND=DP_KIND),INTENT(OUT) :: D,M,S
REAL(KIND=DP_KIND) :: F
D = INT(DEGREES)
F = 60.0D0 * (DEGREES - D)
M = INT(F)
S = F - M
END SUBROUTINE DECDEGREES_TO_DMS
!###====================================================================
SUBROUTINE 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 ITIMETOGTIME
!###====================================================================
INTEGER FUNCTION JD(YEAR,MONTH,DAY)
!###====================================================================
!Reference: Fliegel, H. F. & van Flandern, T. C. 1968, Communications of the ACM, 11, 657.
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
!###====================================================================
SUBROUTINE UTL_GDATE(JD,YEAR,MONTH,DAY)
!###====================================================================
!Reference: Fliegel, H. F. & van Flandern, T. C. 1968, Communications of the ACM, 11, 657.
IMPLICIT NONE
INTEGER,INTENT(IN) :: JD
INTEGER,INTENT(OUT) :: YEAR,MONTH,DAY
INTEGER :: I,J,K,L,N
L=JD+68569
N=4*L/146097
L=L-(146097*N+3)/4
I=4000*(L+1)/1461001
L=L-1461*I/4+31
J=80*L/2447
K=L-2447*J/80
L=J/11
J=J+2-12*L
I=100*(N-49)+I+L
YEAR =I
MONTH=J
DAY =K
END SUBROUTINE UTL_GDATE
!###====================================================================
FUNCTION UTL_SUBST(FNAME,SUB1,SUB2,IERROR)
!###====================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: SUB1,SUB2
CHARACTER(LEN=*),INTENT(IN) :: FNAME
INTEGER,INTENT(OUT),OPTIONAL :: IERROR
INTEGER :: I,J
CHARACTER(LEN=256) :: UTL_SUBST
UTL_SUBST=FNAME
IF(PRESENT(IERROR))THEN
IERROR=0
IF(INDEX(TRIM(UTL_CAP(FNAME,'U')),TRIM(REPLACESTRING)).GT.0.AND.LEN_TRIM(SUB2).EQ.0)THEN
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'File: '//TRIM(FNAME)//CHAR(13)//'Cannot replace $DBASE$ as DBASE is undefined in the PRF-file','Error')
IERROR=1; RETURN
ENDIF
ENDIF
I=INDEX(UTL_CAP(FNAME,'U'),TRIM(UTL_CAP(SUB1,'U')))
IF(I.EQ.0)RETURN
I=I-1
J=I+LEN(SUB1)+1
UTL_SUBST=FNAME(:I)//TRIM(SUB2)//FNAME(J:)
END FUNCTION UTL_SUBST
!###====================================================
SUBROUTINE UTL_CHECKNAME(FNAME,EXT)
!checks for existence of an extension EXT (for instance 'idf')
!and replaces fname including the extension (EXT) if not found.
!###====================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(INOUT) :: FNAME
CHARACTER(LEN=*),INTENT(IN) :: EXT
INTEGER :: I
I=INDEXNOCASE(FNAME,'.',.TRUE.)
IF(I.EQ.0)THEN
FNAME=TRIM(FNAME)//'.'//TRIM(EXT)
ELSE
FNAME=FNAME(:I)//TRIM(EXT)
ENDIF
END SUBROUTINE UTL_CHECKNAME
!###======================================================================
INTEGER FUNCTION UTL_INVERSECOLOUR(IRGB)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: IRGB
INTEGER :: IR,IG,IB
CALL WRGBSPLIT(IRGB,IR,IG,IB)
UTL_INVERSECOLOUR=WRGB(255-IR,255-IG,255-IB)
END FUNCTION UTL_INVERSECOLOUR
!###======================================================================
SUBROUTINE UTL_FADEOUTCOLOUR(ICLR,FCT)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(INOUT) :: ICLR
REAL(KIND=DP_KIND),INTENT(IN) :: FCT
INTEGER :: IR,IG,IB
IF(FCT.GT.1.0D0.OR.FCT.LE.0.0D0)RETURN
CALL WRGBSPLIT(ICLR,IR,IG,IB)
IR =IR+((255-IR)*FCT)
IG =IG+((255-IG)*FCT)
IB =IB+((255-IB)*FCT)
IR=MIN(255,MAX(0,IR))
IG=MIN(255,MAX(0,IG))
IB=MIN(255,MAX(0,IB))
!## faded colour becomes
ICLR=WRGB(IR,IG,IB)
END SUBROUTINE UTL_FADEOUTCOLOUR
!###======================================================================
SUBROUTINE UTL_EQUALNAMES_UNITTEST()
!###======================================================================
IMPLICIT NONE
write(*,*) '*' ,' TEST',0,UTL_EQUALNAMES('*','TEST',0)
write(*,*) 'T*' ,' TEST',0,UTL_EQUALNAMES('T*','TEST',0)
write(*,*) 't*' ,' TEST',1,UTL_EQUALNAMES('t*','TEST',1)
write(*,*) 'T*T' ,' TEST',1,UTL_EQUALNAMES('T*T','TEST',1)
write(*,*) 'T??T',' TEST',1,UTL_EQUALNAMES('T??T','TEST',1)
write(*,*) '*T' ,' TEST',1,UTL_EQUALNAMES('*T','TEST',1)
write(*,*) '*TS' ,' TEST',1,UTL_EQUALNAMES('*TS','TEST',1)
write(*,*) 'T?T' ,' TEST',1,UTL_EQUALNAMES('T?T','TEST',1)
write(*,*) 'T?S?',' TEST',1,UTL_EQUALNAMES('T?S?','TEST',1)
write(*,*) '*S?' ,' TEST',1,UTL_EQUALNAMES('*S?','TEST',1)
write(*,*) '*B31D011*' ,' cfB31D011gt',1,UTL_EQUALNAMES('*B31D011*','cfB31D011gt',1)
write(*,*) '*B31D011*' ,' cfB31D01gt',1,UTL_EQUALNAMES('*B31D011*','cfB31D01gt',1)
PAUSE
END SUBROUTINE UTL_EQUALNAMES_UNITTEST
!###======================================================================
LOGICAL FUNCTION UTL_EQUALNAMES(SEARCH,STRING,ICAP)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: SEARCH,STRING
INTEGER,OPTIONAL,INTENT(IN) :: ICAP
INTEGER :: I,J,N,M,ICASE
LOGICAL :: LEX
ICASE=0; IF(PRESENT(ICAP))ICASE=ICAP
N=LEN_TRIM(STRING)
M=LEN_TRIM(SEARCH)
!## test string on search
J=1; I=0; DO
LEX=.FALSE.; I=I+1
!## string finished before ending
IF(I.GT.N)EXIT
!## check wildcard
IF(SEARCH(J:J).EQ.'*')THEN
!## proceed to next character in search
J=J+1
IF(J.LE.M)THEN
LEX=.FALSE.
DO
IF(ICASE.EQ.0)THEN
IF(SEARCH(J:J).EQ.STRING(I:I))EXIT
ELSE
IF(UTL_CAP(SEARCH(J:J),'U').EQ.UTL_CAP(STRING(I:I),'U'))EXIT
ENDIF
I=I+1; IF(I.GT.N)EXIT
ENDDO
IF(I.LE.N)THEN; LEX=.TRUE.; J=J+1; ENDIF
ELSE
LEX=.TRUE.
ENDIF
!## check wildcard
ELSEIF(SEARCH(J:J).EQ.'?')THEN
!## proceed to next character in search
LEX=.TRUE.; J=J+1
ELSE
IF(ICASE.EQ.0)THEN
LEX=SEARCH(J:J).EQ.STRING(I:I)
ELSE
LEX=UTL_CAP(SEARCH(J:J),'U').EQ.UTL_CAP(STRING(I:I),'U')
ENDIF
IF(LEX)J=J+1
ENDIF
!## incorectness found
IF(.NOT.LEX)EXIT
IF(J.GT.M)EXIT
ENDDO
J=MIN(J,M); IF(SEARCH(J:J).EQ.'*')LEX=.TRUE.
UTL_EQUALNAMES=LEX
END FUNCTION UTL_EQUALNAMES
!###======================================================================
FUNCTION UTL_CAP(STR,TXT)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: TXT,STR
INTEGER :: I,J,K,B1,B2,N
CHARACTER(LEN=256) :: UTL_CAP
!## lowercase
IF(TXT.EQ.'l'.OR.TXT.EQ.'L')THEN
B1= 65
B2= 90
K = 32
!## uppercase
ELSEIF(TXT.EQ.'u'.OR.TXT.EQ.'U')THEN
B1= 97
B2= 122
K =-32
ENDIF
UTL_CAP=''
N=MIN(LEN(STR),LEN(UTL_CAP))
DO I=1,N
J=IACHAR(STR(I:I))
IF(J.GE.B1.AND.J.LE.B2)J=J+K
UTL_CAP(I:I)=ACHAR(J)
END DO
END FUNCTION UTL_CAP
!###======================================================================
FUNCTION UTL_CAP_BIG(STR,TXT)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: TXT,STR
INTEGER :: I,J,K,B1,B2
CHARACTER(LEN=1052) :: UTL_CAP_BIG
IF(TXT.EQ.'l'.OR.TXT.EQ.'L')THEN
B1= 65
B2= 90
K = 32
ELSEIF(TXT.EQ.'u'.OR.TXT.EQ.'U')THEN
B1= 97
B2= 122
K =-32
ENDIF
UTL_CAP_BIG=''
DO I=1,LEN_TRIM(STR)
J=IACHAR(STR(I:I))
IF(J.GE.B1.AND.J.LE.B2)J=J+K
UTL_CAP_BIG(I:I)=ACHAR(J)
END DO
END FUNCTION UTL_CAP_BIG
!###======================================================================
SUBROUTINE UTL_DIRINFO(DIR,WC,LISTNAME,N,FT,CORDER)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(INOUT) :: N
CHARACTER(LEN=*),INTENT(IN) :: DIR,WC,FT
CHARACTER(LEN=*),INTENT(OUT),DIMENSION(:) :: LISTNAME
CHARACTER(LEN=*),INTENT(IN),OPTIONAL :: CORDER
CHARACTER(LEN=512) :: LINE,BATFILE,TXTFILE
INTEGER :: IU,I,J,IOS
CALL UTL_DIRINFO_GETBATFILENAME(BATFILE,TXTFILE,IU)
IF(FT.EQ.'F'.OR.FT.EQ.'f')THEN
!## corder
IF(PRESENT(CORDER))THEN
LINE='dir /b /o'//TRIM(CORDER)//' "'//TRIM(DIR)//'\'//TRIM(WC)//'" > "'//TRIM(TXTFILE)//'"'
ELSE
LINE='dir /b /o "' //TRIM(DIR)//'\'//TRIM(WC)//'" > "'//TRIM(TXTFILE)//'"'
ENDIF
ELSEIF(FT.EQ.'D'.OR.FT.EQ.'d')THEN
IF(PRESENT(CORDER))THEN
LINE='dir /ad /b /o'//TRIM(CORDER)//' "'//TRIM(DIR)//'\'//TRIM(WC)//'" > "'//TRIM(TXTFILE)//'"'
ELSE
LINE='dir /ad /b /o "' //TRIM(DIR)//'\'//TRIM(WC)//'" > "'//TRIM(TXTFILE)//'"'
ENDIF
ENDIF
!## 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)
CALL IOSCOMMAND('"'//TRIM(BATFILE)//'"',PROCSILENT+PROCBLOCKED+PROCCMDPROC)
IU=UTL_GETUNIT()
CALL OSD_OPEN(IU,FILE=TXTFILE,ACTION='READ',FORM='FORMATTED')
IF(IU.LE.0)THEN
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'iMOD cannot OPEN: '//CHAR(13)//TRIM(TXTFILE),'Error')
IU=0; N=0; RETURN
ENDIF
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
READ(LINE,*,IOSTAT=IOS) LISTNAME(I)
IF(IOS.NE.0)EXIT
!## no more space in allocated array
IF(I.EQ.SIZE(LISTNAME))EXIT
END DO
!## number of variables
N=I
!## delete result txt file
CLOSE(IU,STATUS='DELETE')
!## delete batch file
I=WINFOERROR(1); CALL IOSDELETEFILE(BATFILE); I=WINFOERROR(1)
END SUBROUTINE UTL_DIRINFO
!###======================================================================
LOGICAL FUNCTION UTL_DIRINFO_POINTER(DIR,WC,LISTNAME,FT,CORDER)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: DIR,WC,FT
CHARACTER(LEN=*),INTENT(OUT),DIMENSION(:),POINTER :: LISTNAME
CHARACTER(LEN=*),INTENT(IN),OPTIONAL :: CORDER
CHARACTER(LEN=256),DIMENSION(:),POINTER :: C_LISTNAME
CHARACTER(LEN=512) :: LINE,BATFILE,TXTFILE
INTEGER :: IU,I,J,N,IOS
UTL_DIRINFO_POINTER=.FALSE.
IF(LEN(C_LISTNAME).LT.LEN(LISTNAME))CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'c_listname() "'//TRIM(TXTFILE)//'"'
ELSE
LINE='dir /b /o "' //TRIM(DIR)//'\'//TRIM(WC)//'" > "'//TRIM(TXTFILE)//'"'
ENDIF
ELSEIF(FT.EQ.'D'.OR.FT.EQ.'d')THEN
IF(PRESENT(CORDER))THEN
LINE='dir /ad /b /o'//TRIM(CORDER)//' "'//TRIM(DIR)//'\'//TRIM(WC)//'" > "'//TRIM(TXTFILE)//'"'
ELSE
LINE='dir /ad /b /o "' //TRIM(DIR)//'\'//TRIM(WC)//'" > "'//TRIM(TXTFILE)//'"'
ENDIF
ENDIF
!## 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)
CALL IOSCOMMAND('"'//TRIM(BATFILE)//'"',PROCSILENT+PROCBLOCKED+PROCCMDPROC)
IU=UTL_GETUNIT()
CALL OSD_OPEN(IU,FILE=TXTFILE,ACTION='READ',FORM='FORMATTED')
IF(IU.LE.0)THEN
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'iMOD cannot OPEN: '//CHAR(13)//TRIM(TXTFILE),'Error')
IU=0; N=0; RETURN
ENDIF
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
N=I
ALLOCATE(LISTNAME(N))
LISTNAME(1:N)=C_LISTNAME(1:N)
DEALLOCATE(C_LISTNAME)
!## delete txt-file
CLOSE(IU,STATUS='DELETE')
!## delete batch file
I=WINFOERROR(1); CALL IOSDELETEFILE(BATFILE); I=WINFOERROR(1)
UTL_DIRINFO_POINTER=.TRUE.
END FUNCTION UTL_DIRINFO_POINTER
!###======================================================================
SUBROUTINE UTL_DIRINFO_GETBATFILENAME(BATFILE,TXTFILE,IU)
!###======================================================================
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(OUT) :: BATFILE,TXTFILE
INTEGER,INTENT(OUT) :: IU
INTEGER :: ITRY,IOS,I
LOGICAL :: LEX
ITRY=-1; DO
ITRY=ITRY+1
IF(ITRY.EQ.0)THEN
BATFILE=TRIM(PREFVAL(1))//'\tmp\'//TRIM(OSD_GETENV('USERNAME'))//'_dir_imod.bat'
TXTFILE=TRIM(PREFVAL(1))//'\tmp\'//TRIM(OSD_GETENV('USERNAME'))//'_dir_imod.txt'
ELSE
BATFILE=TRIM(PREFVAL(1))//'\tmp\'//TRIM(OSD_GETENV('USERNAME'))//'_dir_imod'//TRIM(ITOS(ITRY))//'.bat'
TXTFILE=TRIM(PREFVAL(1))//'\tmp\'//TRIM(OSD_GETENV('USERNAME'))//'_dir_imod'//TRIM(ITOS(ITRY))//'.txt'
ENDIF
INQUIRE(FILE=BATFILE,EXIST=LEX)
! write(*,*) '"'//trim(batfile)//'"',lex
!## allready exist, try another
IF(LEX)CYCLE
IU=UTL_GETUNIT(); CALL OSD_OPEN(IU,FILE=BATFILE,ACTION='WRITE',FORM='FORMATTED',STATUS='REPLACE',IOSTAT=IOS,IQUESTION=0)
!## error opening, try another
IF(IOS.NE.0)THEN
IU=0; CYCLE
ENDIF
INQUIRE(FILE=TXTFILE,EXIST=LEX)
!## successfully deleted
IF(LEX)THEN
I=WINFOERROR(1)
CALL IOSDELETEFILE(TXTFILE)
I=WINFOERROR(1)
IF(I.EQ.ERROSCOMMAND)THEN
CLOSE(IU,STATUS='DELETE'); IU=0; CYCLE
ENDIF
ENDIF
EXIT
ENDDO
END SUBROUTINE UTL_DIRINFO_GETBATFILENAME
!###======================================================================
SUBROUTINE UTL_IDFSNAPTOGRID(MINX,MAXX,MINY,MAXY,CS,NCOL,NROW)
!###======================================================================
REAL(KIND=DP_KIND),INTENT(INOUT) :: MINX,MAXX,MINY,MAXY
REAL(KIND=DP_KIND),INTENT(IN) :: CS
INTEGER,INTENT(OUT) :: NCOL,NROW
REAL(KIND=DP_KIND) :: D
D=MOD(MINX,CS)
IF(D.NE.0.0D0)MINX=(MINX+(CS-D))-CS
D=MOD(MAXX,CS)
IF(D.NE.0.0D0)MAXX=(MAXX-D)+CS
D=MOD(MINY,CS)
IF(D.NE.0.0D0)MINY=(MINY+(CS-D))-CS
D=MOD(MAXY,CS)
IF(D.NE.0.0D0)MAXY=(MAXY-D)+CS
NCOL=INT((MAXX-MINX)/CS)
NROW=INT((MAXY-MINY)/CS)
END SUBROUTINE UTL_IDFSNAPTOGRID
!###======================================================================
SUBROUTINE UTL_IDFSNAPTONICEGRID(MINX,MAXX,MINY,MAXY,CS,NCOL,NROW,LMAX)
!###======================================================================
REAL(KIND=DP_KIND),INTENT(INOUT) :: MINX,MAXX,MINY,MAXY
REAL(KIND=DP_KIND),INTENT(IN) :: CS
INTEGER,INTENT(OUT) :: NCOL,NROW
LOGICAL,INTENT(IN),OPTIONAL :: LMAX !## snap grid outside (TRUE) or inside (FALSE) XY window
LOGICAL :: LLMAX
REAL(KIND=DP_KIND) :: D
!## make window fit to cell size + snap on cell size related nice grid
LLMAX=.TRUE.; IF(PRESENT(LMAX))LLMAX=LMAX
D=MOD(ABS(MINX),CS)
IF(D.NE.0.0D0)THEN
MINX=(MINX+(CS-D))-CS
IF(.NOT.LLMAX)MINX=MINX+CS
ENDIF
D=MOD(ABS(MAXX),CS)
IF(D.NE.0.0D0)THEN
MAXX=(MAXX-D)+CS
IF(.NOT.LLMAX)MAXX=MAXX-CS
ENDIF
D=MOD(ABS(MINY),CS)
IF(D.NE.0.0D0)THEN
MINY=(MINY+(CS-D))-CS
IF(.NOT.LLMAX)MINY=MINY+CS
ENDIF
D=MOD(ABS(MAXY),CS)
IF(D.NE.0.0D0)THEN
MAXY=(MAXY-D)+CS
IF(.NOT.LLMAX)MAXY=MAXY-CS
ENDIF
NCOL=INT((MAXX-MINX)/CS)
NROW=INT((MAXY-MINY)/CS)
END SUBROUTINE UTL_IDFSNAPTONICEGRID
!###======================================================================
SUBROUTINE UTL_IDFSNAPTOGRID_LLC(MINX,MAXX,MINY,MAXY,CSX,CSY,NCOL,NROW,LLC)
!###======================================================================
REAL(KIND=DP_KIND),INTENT(INOUT) :: MINX,MAXX,MINY,MAXY
REAL(KIND=DP_KIND),INTENT(IN) :: CSX,CSY
INTEGER,INTENT(OUT) :: NCOL,NROW
LOGICAL,INTENT(IN),OPTIONAL :: LLC
LOGICAL :: LLLC
!## make window fit to cell size. llc determines if llc or urc is fixed.
NCOL=(MAXX-MINX)/CSX
NROW=(MAXY-MINY)/CSY
LLLC=.TRUE.; IF(PRESENT(LLC))LLLC=LLC
IF(LLLC)THEN
MAXX=MINX+NCOL*CSX
MAXY=MINY+NROW*CSY
ELSE
MINX=MAXX-NCOL*CSX
MINY=MAXY-NROW*CSY
ENDIF
END SUBROUTINE UTL_IDFSNAPTOGRID_LLC
!###====================================================================
REAL(KIND=DP_KIND) FUNCTION UTL_GETMOSTFREQ(FREQ,MFREQ,NFREQ)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: MFREQ,NFREQ
REAL(KIND=DP_KIND),DIMENSION(MFREQ),INTENT(IN) :: FREQ
INTEGER :: I,MI,NI
NI=1 !number of unique
MI=NI !max. number of unique
UTL_GETMOSTFREQ=FREQ(NI)
DO I=2,NFREQ
IF(FREQ(I).NE.FREQ(I-1))THEN
IF(NI.GT.MI)THEN
UTL_GETMOSTFREQ=FREQ(I-1)
MI=NI
ENDIF
NI=1
ELSE
NI=NI+1
ENDIF
END DO
!test final
IF(NI.GT.MI) UTL_GETMOSTFREQ=FREQ(NFREQ)
END FUNCTION UTL_GETMOSTFREQ
! !###====================================================================
! REAL(KIND=DP_KIND) FUNCTION UTL_GETMOSTFREQ(FREQ,MFREQ,NFREQ,NODATA)
! !###====================================================================
! IMPLICIT NONE
! INTEGER,INTENT(IN) :: MFREQ,NFREQ
! REAL(KIND=DP_KIND),INTENT(IN) :: NODATA
! REAL(KIND=DP_KIND),DIMENSION(MFREQ),INTENT(IN) :: FREQ
! INTEGER :: I,IS,MI,NI
!
! UTL_GETMOSTFREQ=NODATA
!
! IS=0
! DO
! IS=IS+1
! IF(FREQ(IS).NE.NODATA)EXIT
! IF(IS.GE.NFREQ)RETURN !## nothing found ne nodata
! ENDDO
! UTL_GETMOSTFREQ=FREQ(IS)
! MI=1 !NI !max. number of unique
!
! NI=1
! IS=IS+1
! DO I=IS,NFREQ
! IF(FREQ(I).EQ.NODATA)CYCLE
! IF(FREQ(I).NE.FREQ(I-1))THEN
! IF(NI.GT.MI)THEN
! UTL_GETMOSTFREQ=FREQ(I-1)
! MI=NI
! ENDIF
! NI=1
! ELSE
! NI=NI+1
! ENDIF
! END DO
! !## test final
! IF(NI.GT.MI)UTL_GETMOSTFREQ=FREQ(NFREQ)
!
! END FUNCTION UTL_GETMOSTFREQ
!###====================================================
SUBROUTINE UTL_GETHIST(X,NX,NODATA,HIST,NHIST,MX,XHIST)
!###====================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: NX,NHIST !## size array,number of percentiles to be comp.
INTEGER,INTENT(OUT) :: MX !## number of values ne nodata
REAL(KIND=DP_KIND),INTENT(IN),DIMENSION(:) :: HIST !## percentile 0-100%
REAL(KIND=DP_KIND),INTENT(OUT),DIMENSION(:) :: XHIST !## yielding percentile(s)
REAL(KIND=DP_KIND),INTENT(IN) :: NODATA !## nodata value !,PERC
REAL(KIND=DP_KIND),DIMENSION(NX),INTENT(INOUT) :: X !## array
INTEGER :: I,J
XHIST=0.0D0; MX=0; IF(NX.LE.0)RETURN
DO I=1,NX
IF(X(I).EQ.NODATA)CYCLE
MX=MX+1
DO J=1,NHIST-1
IF(X(I).GT.HIST(J).AND.X(I).LE.HIST(J+1))THEN
XHIST(J)=XHIST(J)+1
EXIT
ENDIF
ENDDO
ENDDO
END SUBROUTINE UTL_GETHIST
!###====================================================
SUBROUTINE 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=DP_KIND),INTENT(IN),DIMENSION(:) :: PERC !## percentile 0-100%
REAL(KIND=DP_KIND),INTENT(OUT),DIMENSION(NPERC) :: XMED !## yielding percentile(s)
REAL(KIND=DP_KIND),INTENT(IN) :: NODATA !## nodata value !,PERC
REAL(KIND=DP_KIND),DIMENSION(NX),INTENT(INOUT) :: X !## array
INTEGER :: I,J,IP
REAL(KIND=DP_KIND) :: FRAC
XMED=NODATA; MX=0
IF(NX.LE.0)RETURN
!## only one sample
IF(NX.EQ.1)THEN
IF(X(1).NE.NODATA)THEN
XMED=X(1)
MX =1
ENDIF
RETURN
ENDIF
!## do not include nodata values for median-computation
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
CALL QKSORT_SGL(MX,X)
DO IP=1,NPERC
IF(PERC(IP).LE.0.0D0)THEN
XMED(IP)=X(1)
ELSEIF(PERC(IP).GE.100.0D0)THEN
XMED(IP)=X(MX)
ELSE
FRAC=1.0D0/(PERC(IP)/100.0D0)
IF(MOD(REAL(MX),FRAC).EQ.0.0D0)THEN
I=MAX(1,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.0D0
ENDIF
ENDIF
ENDDO
END SUBROUTINE UTL_GETMED
!###====================================================
SUBROUTINE UTL_GETMED_SIGN(X,SX,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=DP_KIND),INTENT(IN),DIMENSION(:) :: PERC !## percentile 0-100%
REAL(KIND=DP_KIND),INTENT(OUT),DIMENSION(NPERC) :: XMED !## yielding percentile(s)
REAL(KIND=DP_KIND),INTENT(IN) :: NODATA !## nodata value !,PERC
REAL(KIND=DP_KIND),DIMENSION(NX),INTENT(INOUT) :: X !## array
REAL(KIND=DP_KIND),DIMENSION(NX),INTENT(INOUT) :: SX !## sign-array
INTEGER :: I,J,IP
REAL(KIND=DP_KIND) :: FRAC
XMED=NODATA; MX=0
IF(NX.LE.0)RETURN
!## only one sample
IF(NX.EQ.1)THEN
IF(X(1).NE.NODATA)THEN
XMED=X(1)
MX =1
ENDIF
RETURN
ENDIF
!## do not include nodata values for median-computation
DO I=1,NX
IF(X(I).NE.NODATA)THEN
MX =MX+1
X(MX)=X(I)
SX(MX)=SX(I)
ENDIF
END DO
IF(MX.LE.0)RETURN
CALL QKSORT(MX,X,V2=SX) !,V3,V4,V5,V6,V7)
! CALL QKSORT_SGL(MX,X)
DO IP=1,NPERC
IF(PERC(IP).LE.0.0D0)THEN
XMED(IP)=X(1)
!## turn sign if needed
IF(SX(1).EQ.1.0D0)XMED(IP)=-1.0D0*XMED(IP)
ELSEIF(PERC(IP).GE.100.0D0)THEN
XMED(IP)=X(MX)
!## turn sign if needed
IF(SX(MX).EQ.1.0D0)XMED(IP)=-1.0D0*XMED(IP)
ELSE
FRAC=1.0D0/(PERC(IP)/100.0D0)
IF(MOD(REAL(MX),FRAC).EQ.0.0D0)THEN
I=MAX(1,INT(REAL(MX)/FRAC))
XMED(IP)=X(I)
!## turn sign if needed
IF(SX(I).EQ.1.0D0)XMED(IP)=-1.0D0*XMED(IP)
ELSE
I=MAX(1,INT(REAL(MX)/FRAC))
J=MIN(I+1,MX)
XMED(IP)=(X(I)+X(J))/2.0D0
!## turn sign if needed
IF(SX(I).EQ.1.0D0.OR.SX(J).EQ.1.0D0)XMED(IP)=-1.0D0*XMED(IP)
ENDIF
ENDIF
ENDDO
END SUBROUTINE UTL_GETMED_SIGN
!###====================================================
REAL(KIND=DP_KIND) FUNCTION UTL_GETPROB(X,N,NODATA,PROBVALUE) !,IABS)
!###====================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: N !,IABS !## size array,number of percentiles to be comp.
REAL(KIND=DP_KIND),INTENT(IN) :: PROBVALUE !## percentile 0-100%
REAL(KIND=DP_KIND),INTENT(IN) :: NODATA !## nodata value !,PERC
REAL(KIND=DP_KIND),DIMENSION(N),INTENT(IN) :: X !## array
INTEGER :: I,J,K
! REAL(KIND=DP_KIND) :: R
J=0; K=0; DO I=1,N
IF(X(I).EQ.NODATA)CYCLE
K=K+1
! IF(IABS.EQ.1)THEN
! IF(ABS(X(I)).GE.PROBVALUE)J=J+1
! ELSE
IF(X(I).GE.PROBVALUE)J=J+1
! ENDIF
ENDDO
!## scale to 100%
UTL_GETPROB=(REAL(J,8)/REAL(K,8))*100.0D0
END FUNCTION UTL_GETPROB
!###====================================================
SUBROUTINE UTL_GETMED_INVERSE(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=DP_KIND),INTENT(IN),DIMENSION(:) :: PERC !## percentile 0-100%
REAL(KIND=DP_KIND),INTENT(OUT),DIMENSION(:) :: XMED !## yielding percentile(s)
REAL(KIND=DP_KIND),INTENT(IN) :: NODATA !## nodata value
REAL(KIND=DP_KIND),DIMENSION(NX),INTENT(INOUT) :: X !## array
INTEGER :: I,IP
REAL(KIND=DP_KIND) :: FRAC
XMED=NODATA
IF(NX.LE.0)RETURN
!## only one sample
IF(NX.EQ.1)THEN
DO IP=1,NPERC
XMED(IP)=0.0D0
IF(X(1).LE.PERC(IP))XMED(IP)=1.0D0
ENDDO
MX =1
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 SHELLSORT(MX,X)
! ELSE
CALL QKSORT_SGL(MX,X) !MX,X)
! ENDIF
!## find appropriate values for percentiles
FRAC=1.0D0
DO IP=1,NPERC
IF(MX.EQ.1)THEN
XMED(IP)=0.0D0
IF(X(1).LE.PERC(IP))XMED(IP)=1.0D0
ELSE
IF(PERC(IP).LE.X(1))THEN
XMED(IP)=0.0D0
ELSEIF(PERC(IP).GT.X(MX))THEN
XMED(IP)=1.0D0
ELSE
DO I=2,MX
IF(X(I-1).LE.PERC(IP).AND. &
X(I) .GE.PERC(IP))THEN
FRAC=(PERC(IP)-X(I-1))/(X(I)-X(I-1))
XMED(IP)=(REAL(I-1)+FRAC)/REAL(MX)
EXIT
ENDIF
ENDDO
ENDIF
ENDIF
WRITE(*,*) 'PERC(IP)=',PERC(IP)
WRITE(*,*) 'XMED(IP)=',XMED(IP)
WRITE(*,*) 'FRAC =',FRAC
DO I=1,MX; WRITE(*,'(I10,F15.7)') I,X(I); ENDDO
ENDDO
END SUBROUTINE UTL_GETMED_INVERSE
!###======================================================================
INTEGER FUNCTION CALCPERIODS(ISTARTDATE,IENDDATE)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: ISTARTDATE,IENDDATE
CALCPERIODS=UTL_IDATETOJDATE(IENDDATE)-UTL_IDATETOJDATE(ISTARTDATE)+1
END FUNCTION CALCPERIODS
!###====================================================
SUBROUTINE UTL_GETUNIQUE(X,N,NU,NODATA)
!###====================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: N
INTEGER,INTENT(OUT) :: NU
REAL(KIND=DP_KIND),INTENT(IN),OPTIONAL :: NODATA
REAL(KIND=DP_KIND),INTENT(INOUT),DIMENSION(N) :: X
INTEGER :: I
CALL QKSORT_SGL(N,X) !N,X)
!## determine number of unique classes
IF(PRESENT(NODATA))THEN
NU=0
DO I=1,N
IF(NU.EQ.0)THEN
IF(X(I).NE.NODATA)THEN
NU=NU+1
X(NU)=X(I)
ENDIF
ELSE
IF(X(I).NE.X(NU).AND.X(I).NE.NODATA)THEN
NU =NU+1
X(NU)=X(I)
ENDIF
ENDIF
END DO
ELSE
NU=1
DO I=2,N
IF(X(I).NE.X(NU))THEN
NU =NU+1
X(NU)=X(I)
ENDIF
END DO
ENDIF
END SUBROUTINE UTL_GETUNIQUE
!###====================================================
SUBROUTINE UTL_GETUNIQUE_POINTER(X,N,NU,NODATA)
!###====================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: N
INTEGER,INTENT(OUT) :: NU
REAL(KIND=DP_KIND),INTENT(IN),OPTIONAL :: NODATA
REAL(KIND=DP_KIND),POINTER,INTENT(INOUT),DIMENSION(:) :: X
INTEGER :: I
CALL UTL_WSORT(X,1,N)
!## determine number of unique classes
IF(PRESENT(NODATA))THEN
NU=0
DO I=1,N
IF(NU.EQ.0)THEN
IF(X(I).NE.NODATA)THEN
NU=NU+1
X(NU)=X(I)
ENDIF
ELSE
IF(X(I).NE.X(NU).AND.X(I).NE.NODATA)THEN
NU =NU+1
X(NU)=X(I)
ENDIF
ENDIF
END DO
ELSE
NU=1
DO I=2,N
IF(X(I).NE.X(NU))THEN
NU =NU+1
X(NU)=X(I)
ENDIF
END DO
ENDIF
END SUBROUTINE UTL_GETUNIQUE_POINTER
!###====================================================
SUBROUTINE UTL_GETUNIQUE_INT(IX,N,NU,NODATA)
!###====================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: N
INTEGER,INTENT(OUT) :: NU
INTEGER,INTENT(INOUT),DIMENSION(:) :: 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 UTL_GETUNIQUE_DINT(IX,N,NU,NODATA)
!###====================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: N
INTEGER,INTENT(OUT) :: NU
INTEGER(KIND=8),INTENT(INOUT),DIMENSION(N) :: IX
INTEGER(KIND=8),INTENT(IN),OPTIONAL :: NODATA
INTEGER :: I
CALL SHELLSORT_DINT(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_DINT
!###====================================================
SUBROUTINE UTL_GETUNIQUE_CHAR(CH,N,NU)
!###====================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: N
INTEGER,INTENT(OUT) :: NU
CHARACTER(LEN=*),INTENT(INOUT),DIMENSION(N) :: CH
INTEGER :: I,J
!## determine number of unique classes
NU=1
DO I=2,N
DO J=1,NU
IF(CH(J).EQ.CH(I))EXIT !## get it already
ENDDO
IF(J.LE.NU)CYCLE
!## add new to unique string
NU=NU+1
CH(NU)=CH(I)
END DO
END SUBROUTINE UTL_GETUNIQUE_CHAR
!###====================================================
LOGICAL FUNCTION UTL_EQUALS_REAL(A,B)
!###====================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: A,B
REAL(KIND=DP_KIND) :: EPS
EPS=ABS(A)*EPSILON(A) ! SCALE EPSILON
IF(EPS.EQ.0.0D0)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
UTL_EQUALS_REAL=.FALSE. ! NOT EQUAL IF DIFFERENCE>EPS
ELSE
UTL_EQUALS_REAL=.TRUE. ! EQUAL OTHERWISE
ENDIF
END FUNCTION UTL_EQUALS_REAL
!###====================================================
SUBROUTINE PEUCKER_SIMPLIFYLINE(XC,YC,PDCODE,N)
!###====================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: N
REAL(KIND=DP_KIND),INTENT(IN),DIMENSION(N) :: XC,YC
REAL(KIND=DP_KIND),INTENT(OUT),DIMENSION(N) :: PDCODE
INTEGER :: MJ,J1,J2
REAL(KIND=DP_KIND) :: MD
PDCODE=-999.99D0
!## set first and last point, distance is zero
PDCODE(1)=0.0D0; PDCODE(N)=0.0D0
!## process each intermediate point
DO
!## get the start point (first empty spot)
DO J1=1,N-1; IF(PDCODE(J1).LT.0.0D0)EXIT; ENDDO
!## finished
IF(J1.EQ.N)EXIT
!## previous fixed point
J1=J1-1
!## get the end point (fixed point)
DO J2=J1+1,N; IF(PDCODE(J2).GE.0.0D0)EXIT; ENDDO
!## get the maximal distance in between i1 and i2 and tag it
CALL PEUCKER_CALCDISTANCE(J1,J2,N,XC,YC,MJ,MD)
!## tag decrease line segment to examine
IF(MJ.GT.0)PDCODE(MJ)=MD
ENDDO
END SUBROUTINE PEUCKER_SIMPLIFYLINE
!###====================================================
SUBROUTINE PEUCKER_CALCDISTANCE(J1,J2,N,XC,YC,MJ,MD)
!###====================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: N,J1,J2
REAL(KIND=DP_KIND),INTENT(OUT) :: MD
REAL(KIND=DP_KIND),INTENT(IN),DIMENSION(N) :: XC,YC
INTEGER,INTENT(OUT) :: MJ
INTEGER :: J
REAL(KIND=DP_KIND) :: B,A,D,Y,DX,DY
!## line equation
B=YC(J1)
DY=(YC(J2)-YC(J1))
DX=(XC(J2)-XC(J1))
A=10.0D10; IF(DX.NE.0.0D0)A=DY/DX
MD=-1.0D0; MJ=0
!## loop over all points
DO J=J1+1,J2-1
!## get point on line
Y=(XC(J)-XC(J1))*A+B
!## get difference between line and point
D=ABS(Y-YC(J))
!## keep this one is this is largers
IF(D.GT.MD)THEN
MD=D; MJ=J
ENDIF
ENDDO
END SUBROUTINE PEUCKER_CALCDISTANCE
!###====================================================================
REAL(KIND=DP_KIND) FUNCTION UTL_NASH_SUTCLIFFE(X,Y,N)
!###====================================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),PARAMETER :: TINYYN=0.01D0
INTEGER,INTENT(IN) :: N
REAL(KIND=DP_KIND),INTENT(IN),DIMENSION(N) :: X,Y !## x=head; y=obs
REAL(KIND=DP_KIND) :: XN,YN,YA
INTEGER :: I
!## compute nash-sutcliff
UTL_NASH_SUTCLIFFE=0.0D0
!## average observation
YA=0.0D0; DO I=1,N; YA=YA+Y(I) ; ENDDO; YA=YA/REAL(N)
XN=0.0D0; DO I=1,N; XN=XN+(Y(I)-X(I))**2.0D0 ; ENDDO
YN=0.0D0; DO I=1,N; YN=YN+(Y(I)-YA)**2.0D0 ; ENDDO
!## whenever the computed head is constant in time - assume a small yn
IF(YN.EQ.0.0D0)YN=TINYYN
UTL_NASH_SUTCLIFFE=1.0D0-XN/YN
END FUNCTION UTL_NASH_SUTCLIFFE
!###====================================================================
REAL(KIND=DP_KIND) FUNCTION UTL_GOODNESS_OF_FIT(X,Y,N)
!###====================================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: N
REAL(KIND=DP_KIND),INTENT(IN),DIMENSION(N) :: X,Y
REAL(KIND=DP_KIND) :: XN,YN,X1,X2,X3
INTEGER :: I
UTL_GOODNESS_OF_FIT=0.0D0
XN=SUM(X)/DBLE(N)
YN=SUM(Y)/DBLE(N)
X1=0.0D0; X2=0.0D0; X3=0.0D0
DO I=1,N
X1=X1+(X(I)-XN)*(Y(I)-YN)
X2=X2+(X(I)-XN)**2.0D0
X3=X3+(Y(I)-YN)**2.0D0
ENDDO
!## sample correlation coefficient
IF(X2.NE.0.0D0.AND.X3.NE.0.0D0)UTL_GOODNESS_OF_FIT=X1/SQRT(X2*X3)
END FUNCTION UTL_GOODNESS_OF_FIT
!###====================================================
SUBROUTINE UTL_FIT_REGRESSION(X,Y,NDATA,SIG,MWT,A,B,SIGA,SIGB,CHI2,Q)
!###====================================================
IMPLICIT NONE
INTEGER,INTENT(IN) :: NDATA,MWT
REAL(KIND=DP_KIND),INTENT(OUT) :: A,B,CHI2,Q,SIGA,SIGB
REAL(KIND=DP_KIND),DIMENSION(NDATA) :: X,Y,SIG
INTEGER :: I
REAL(KIND=DP_KIND) :: SIGDAT,SS,ST2,SX,SXOSS,SY,T,WT
SX =0.0D0
SY =0.0D0
ST2=0.0D0
B =0.0D0
IF(MWT.NE.0)THEN
SS=0.0D0
DO I=1,NDATA
WT=1.0D0/(SIG(I)**2)
SS=SS+WT
SX=SX+X(I)*WT
SY=SY+Y(I)*WT
ENDDO
ELSE
DO I=1,NDATA
SX=SX+X(I)
SY=SY+Y(I)
ENDDO
SS=FLOAT(NDATA)
ENDIF
SXOSS=SX/SS
IF(MWT.NE.0)THEN
DO I=1,NDATA
T=(X(I)-SXOSS)/SIG(I)
ST2=ST2+T*T
B=B+T*Y(I)/SIG(I)
ENDDO
ELSE
DO I=1,NDATA
T=X(I)-SXOSS
ST2=ST2+T*T
B=B+T*Y(I)
ENDDO
ENDIF
B=B/ST2
A=(SY-SX*B)/SS
SIGA=SQRT((1.0D0+SX*SX/(SS*ST2))/SS)
SIGB=SQRT(1.0D0/ST2)
CHI2=0.0D0
IF(MWT.EQ.0)THEN
DO I=1,NDATA
CHI2=CHI2+(Y(I)-A-B*X(I))**2
ENDDO
Q=1.0D0
SIGDAT=SQRT(CHI2/REAL(NDATA-2))
SIGA=SIGA*SIGDAT
SIGB=SIGB*SIGDAT
ELSE
DO I=1,NDATA
CHI2=CHI2+((Y(I)-A-B*X(I))/SIG(I))**2
ENDDO
Q=UTL_GAMMQ(REAL(0.5*(NDATA-2),8),REAL(0.5*CHI2,8))
ENDIF
END SUBROUTINE UTL_FIT_REGRESSION
!###====================================================
REAL(KIND=DP_KIND) FUNCTION UTL_GAMMQ(A,X)
!###====================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: A,X
REAL(KIND=DP_KIND) :: GAMMCF,GAMSER,GLN
IF(X.LT.0.0D0.OR.A.LE.0.0D0)PAUSE 'BAD ARGUMENT IN UTL_GAMMQ'
IF(X.LT.A+1.0D0)THEN
CALL UTL_GSER(GAMSER,A,X,GLN)
UTL_GAMMQ=1.0D0-GAMSER
ELSE
CALL UTL_GCF(GAMMCF,A,X,GLN)
UTL_GAMMQ=GAMMCF
ENDIF
END FUNCTION
!###====================================================
SUBROUTINE UTL_GSER(GAMSER,A,X,GLN)
!###====================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: A,X
REAL(KIND=DP_KIND),INTENT(OUT) :: GLN,GAMSER
INTEGER,PARAMETER :: ITMAX=100
REAL(KIND=DP_KIND),PARAMETER :: EPS=3.0E-7
INTEGER :: N
REAL(KIND=DP_KIND) :: AP,DEL,SUM
GLN=UTL_GAMMLN(A)
IF(X.LE.0.0D0)THEN
IF(X.LT.0.0D0)PAUSE 'X < 0 IN UTL_GSER'
GAMSER=0.0D0
RETURN
ENDIF
AP=A
SUM=1.0D0/A
DEL=SUM
DO N=1,ITMAX
AP=AP+1.0D0
DEL=DEL*X/AP
SUM=SUM+DEL
IF(ABS(DEL).LT.ABS(SUM)*EPS)GOTO 1
ENDDO
PAUSE 'A TOO LARGE, ITMAX TOO SMALL IN UTL_GSER'
1 GAMSER=SUM*EXP(-X+A*LOG(X)-GLN)
END SUBROUTINE UTL_GSER
!###====================================================
SUBROUTINE UTL_GCF(GAMMCF,A,X,GLN)
!###====================================================
IMPLICIT NONE
INTEGER,PARAMETER :: ITMAX=100
REAL(KIND=DP_KIND),PARAMETER :: EPS=3.0E-7,FPMIN=1.0D0-30
REAL(KIND=DP_KIND),INTENT(IN) :: A,X
REAL(KIND=DP_KIND),INTENT(OUT) :: GAMMCF,GLN
INTEGER :: I
REAL(KIND=DP_KIND) :: AN,B,C,D,DEL,H
GLN=UTL_GAMMLN(A)
B=X+1.0D0-A
C=1.0D0/FPMIN
D=1.0D0/B
H=D
DO I=1,ITMAX
AN=-I*(I-A)
B=B+2.0
D=AN*D+B
IF(ABS(D).LT.FPMIN)D=FPMIN
C=B+AN/C
IF(ABS(C).LT.FPMIN)C=FPMIN
D=1.0D0/D
DEL=D*C
H=H*DEL
IF(ABS(DEL-1.0D0).LT.EPS)GOTO 1
ENDDO
PAUSE 'A TOO LARGE, ITMAX TOOP SMALL IN UTL_GCF'
1 GAMMCF=EXP(-X+A*LOG(X)-GLN)*H
END SUBROUTINE UTL_GCF
!###====================================================
REAL(KIND=DP_KIND) FUNCTION UTL_GAMMLN(XX)
!###====================================================
IMPLICIT NONE
REAL(KIND=DP_KIND),INTENT(IN) :: XX
INTEGER :: J
REAL(KIND=DP_KIND),SAVE :: SER,STP,TMP,X,Y,COF(6)
DATA COF,STP/76.18009172947146D0,-86.50532032941677D0, &
24.01409824083091D0,-1.231739572450155D0,0.1208650973866179D-2, &
-0.5395239384953D-5,2.5066282746310005D0/
X=XX
Y=X
TMP=X+5.5D0
TMP=(X+0.5D0)*LOG(TMP)-TMP
SER=1.000000000190015D0
DO J=1,6
Y=Y+1.0D0
SER=SER+COF(J)/Y
ENDDO
UTL_GAMMLN=TMP+LOG(STP*SER/X)
END FUNCTION UTL_GAMMLN
!###======================================================================
SUBROUTINE UTL_SYSCOREINFO(NOCINT)
!###======================================================================
IMPLICIT NONE
INTEGER,INTENT(OUT) :: NOCINT
CHARACTER(LEN=512) :: LINE,BATFILE,TXTFILE
INTEGER :: IU,I,IOS
LOGICAL :: LEX
!## initial value
NOCINT=1
BATFILE=TRIM(PREFVAL(1))//'\tmp\'//TRIM(OSD_GETENV('USERNAME'))//'_syscore_imod.bat'
TXTFILE=TRIM(PREFVAL(1))//'\tmp\'//TRIM(OSD_GETENV('USERNAME'))//'_syscore_imod.txt'
IU=UTL_GETUNIT(); CALL OSD_OPEN(IU,FILE=BATFILE,ACTION='WRITE',FORM='FORMATTED',IOSTAT=IOS)
IF(IOS.NE.0)THEN
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'iMOD does not have priveleges to write CREATE: '//CHAR(13)//TRIM(BATFILE),'Error')
IU=0; RETURN
ENDIF
INQUIRE(FILE=TXTFILE,EXIST=LEX)
!## successfully deleted
IF(LEX)THEN
I=WINFOERROR(1)
CALL IOSDELETEFILE(TXTFILE)
I=WINFOERROR(1)
IF(I.EQ.ERROSCOMMAND)THEN
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'iMOD does not have priveleges to DELETE: '//CHAR(13)//TRIM(TXTFILE),'Error')
CLOSE(IU); IU=0; RETURN
ENDIF
ENDIF
LINE='wmic cpu get NumberOfCores > "'//TRIM(TXTFILE)//'"'
! LINE='echo %NUMBER_OF_PROCESSORS% > "'//TRIM(TXTFILE)//'"'
! LINE='wmic cpu get NumberOfLogicalProcessors > "'//TRIM(TXTFILE)//'"'
WRITE(IU,'(A)') TRIM(LINE)
CLOSE(IU)
CALL IOSCOMMAND('"'//TRIM(BATFILE)//'"',PROCSILENT+PROCBLOCKED+PROCCMDPROC)
IU=UTL_GETUNIT()
CALL OSD_OPEN(IU,FILE=TRIM(TXTFILE),STATUS='OLD',ACTION='READ')
IF(IU.LE.0)THEN
CALL WMESSAGEBOX(OKONLY,EXCLAMATIONICON,COMMONOK,'iMOD cannot OPEN: '//CHAR(13)//TRIM(TXTFILE),'Error')
IU=0; RETURN
ENDIF
!READ(IU,*,IOSTAT=IOS)
!READ(IU,*,IOSTAT=IOS) NOCINT
!IF(IOS.NE.0)NOCINT=-1
NOCINT=4
!## delete result txt file
CLOSE(IU,STATUS='DELETE')
END SUBROUTINE UTL_SYSCOREINFO
END MODULE MOD_UTL