
C	subroutine "dispcurve" to compute dispersion curve using grderiv

C	Sven Ivansson 1993






	SUBROUTINE DISPCURVE ( HSTEPFSUBPRE, NFR,CFREQARR, USTART, 
     $	DSFMIN,DSFMAX,  DSFFAKTMAX, DSUMAX, DRELGOALFAKT, RSUG2, 
     $	DLOGREDUCFAKT,DDELT,XYTOL, NFROK,UCURVE,DUDFCURVE,UGRCURVE, 
     $	IGRCALL,IASFAIL, TERM)
C	hstepfsubpre         for hstepfsub in "dpcfsub.inc"
C	nfr                  number of complex frequencies
C	cfreqarr(1:nfr)      complex frequencies 
C	                         ( cfreqarr(1) is the start frequency )
C	ustart               mode-u at cfreqarr(1), it must not be on a 
C	                         branch-cut
C	dsfmin               minimal absolute freq step that is handled 
C	                     (strict limit), always take  dsfmin >= 0.0d0
C	dsfmax               maximal absolute freq step
C	dsffaktmax           maximal factor for change of "planned" freq steps
C	dsumax               maximum allowed absolute "planned" change of u 
C	                     in each freq step
C	drelgoalfakt         for choosing "next freq step", always take  
C	                     drelgoalfakt < 1.0d0
C	rsug2                half-width for u tolerance rectangle to dzeroholo
C	dlogreducfakt        "dlog" of required reduction factor in each step 
C	                     for the absolute value of "the function"  
C	                     ("dzeroholo")
C	ddelt                distance-difference limit for "secant derivative"
C	                     ("dzeroholo")
C	xytol                desired accuracy for the zeros  ("dzeroholo")
C	nfrok               output number of complex frequencies ok
C	ucurve(1:nfrok)     output  u values with ucurve(1):=ustart
C	dudfcurve(1:nfrok)  output  du/df values
C	ugrcurve(1:nfrok)   output  group-u values 
C	igrcall             input/output (OBS)  performed number of function 
C	                                                         evaluations 
C	iasfail             output  0 upon successful result
C	                            1 for inappropriate cfreqarr
C	                            2 for zero "deriv-du" encountered
C	                            3 for "dsf<=dsfmin"
C	term                input .true. for successive ucurve output on 
C	                    terminal

	USE INMODELa

	IMPLICIT NONE

	INCLUDE 'RPPARAMETER.INC'
C	nol <= noldim

	INCLUDE 'INPARAM.INC'
C	note: "icuttyp,isheettyp" etc must be set from calling program
	INCLUDE 'DPCFSUB.INC'

	INTEGER NFR
	REAL*8 HSTEPFSUBPRE, DSFMIN,DSFMAX, 
     $	DSFFAKTMAX, DSUMAX, DRELGOALFAKT, RSUG2, 
     $	DLOGREDUCFAKT,DDELT,XYTOL
	COMPLEX*16 USTART, 
     $	CFREQARR(*)
	LOGICAL TERM

	INTEGER IGRCALL

	INTEGER NFROK, IASFAIL
	COMPLEX*16 UCURVE(*), DUDFCURVE(*), UGRCURVE(*)

	INTEGER NXTFR, IDZHFAIL
	REAL*8 RLNDET,DLNDO,DLNDU, SFTOT, SF,SFOLD, DSF,DSFOLD, 
     $	RSUG2NOW, PX,PY, X1,X2,Y1,Y2, XYTOLUT, PI, PI2,PI2INV
	COMPLEX*16 CFREQRIKT, CFREQ,CFREQOLD, UP,UPOLD, 
     $	CDET,DERIVDO,DERIVDU, DUDO
	LOGICAL CUTTING

	EXTERNAL GRVALUESUB

	DATA PI /3.141592653589793D0/

	CALL CUTSUB_REINIT

	PI2 = 2*PI
	PI2INV = 1/PI2

	IF (U0.NE.(1.0D0,0.0D0)) STOP 3415   ! u,up must be interchangeable; 
C	branch-points and -cuts must be frequency-independent

	IF ( DSFMIN.LT.0.0D0 .OR. DRELGOALFAKT.GE.1.0D0 ) STOP 27  ! safety

	CFREQ = CFREQARR(1)
	OMEG = PI2 * CFREQ
	HSTEPFSUB = HSTEPFSUBPRE / CDABS(CFREQ)      ! obs
	RK0 = OMEG                 ! note that "u0=(1.0d0,0.0d0)"
	OMEG2 = OMEG*OMEG

	IGRCALL = IGRCALL + 1
	CALL GRDERIV ( USTART, RLNDET,CDET, DLNDO,DERIVDO, 
     $	DLNDU,DERIVDU )                         ! note: u,up interchangeable
	IF (DERIVDU.EQ.(0.0D0,0.0D0)) THEN
	  IASFAIL = 2        ! zero "deriv-u" encountered
	  NFROK = 0
	  RETURN
	END IF
	DUDO = - DEXP(DLNDO-DLNDU) * DERIVDO/DERIVDU
	UCURVE(1) = USTART
	DUDFCURVE(1) = PI2*DUDO
	UGRCURVE(1) = USTART + OMEG*DUDO

	NXTFR = 2
	CFREQRIKT = CFREQARR(2) - CFREQ
	SFTOT = CDABS(CFREQRIKT)
	IF (SFTOT.EQ.0.0D0) THEN
	  IASFAIL = 1
	  NFROK = 1
	  RETURN
	END IF
	CFREQRIKT = CFREQRIKT/SFTOT
	SF = 0.0D0

	DSFOLD = DSFMAX
	UP = USTART                             ! note: u,up interchangeable

	DO WHILE (NXTFR.LE.NFR)

	  CFREQOLD = CFREQ
	  SFOLD = SF
	  UPOLD = UP
	  IF (DUDO.NE.(0.0D0,0.0D0)) THEN
	    DSF = DRELGOALFAKT * DMIN1 ( DSFMAX , PI2INV*DSUMAX/CDABS(DUDO) )
	  ELSE
	    DSF = DRELGOALFAKT * DSFMAX
	  END IF
	  IF ( DSF .GT. DSFFAKTMAX*DSFOLD ) DSF = DSFFAKTMAX*DSFOLD
 100	  IF (DSF.LE.DSFMIN) THEN
	    IASFAIL = 3
	    NFROK = NXTFR - 1
	    RETURN
	  END IF
	  DSFOLD = DSF
	  SF = SFOLD + DSF
	  IF (SF.LT.SFTOT) THEN
	    CFREQ = CFREQOLD + DSF*CFREQRIKT
	  ELSE
	    SF = SFTOT
	    CFREQ = CFREQARR(NXTFR)
	  END IF

	  OMEG = PI2 * CFREQ
	  HSTEPFSUB = HSTEPFSUBPRE / CDABS(CFREQ)      ! obs
	  RK0 = OMEG                 ! note that "u0=(1.0d0,0.0d0)"
	  OMEG2 = OMEG*OMEG

	  X1 = DREAL(UP)
	  Y1 = DIMAG(UP)
	  UP = UPOLD + PI2*(CFREQ-CFREQOLD)*DUDO   ! note: u,up interchangeable
	  PX = DREAL(UP)
	  PY = DIMAG(UP)
	  CALL CUTSUB ( X1,PX,Y1,PY, CUTTING )
	  IF (CUTTING) THEN 
	    SF = SFOLD
	    DSF = 0.5D0 * CDABS(CFREQ-CFREQOLD)
	    GOTO 100
	  END IF
	  PX = 0.01D0*X1 + 0.99D0*PX    ! cutting border-safety
	  PY = 0.01D0*Y1 + 0.99D0*PY    ! cutting border-safety
	  UP = DCMPLX(PX,PY)                    ! note: u,up interchangeable
	  IGRCALL = IGRCALL + 1
	  CALL GRVALUE ( UP, RLNDET,CDET )
	  RSUG2NOW = RSUG2
 200	  X1 = PX - RSUG2NOW
	  X2 = PX + RSUG2NOW
	  Y1 = PY - RSUG2NOW
	  Y2 = PY + RSUG2NOW
	  CALL CUTSUB ( X1,X2,Y1,Y2, CUTTING )
	  IF (CUTTING) THEN 
	    RSUG2NOW = 0.5D0 * RSUG2NOW
	    GOTO 200
	  END IF
	  CALL DZEROHOLO ( GRVALUESUB, X1,X2,Y1,Y2, DLOGREDUCFAKT,
     $	  DDELT,XYTOL, PX,PY,XYTOLUT,RLNDET,CDET, IGRCALL,IDZHFAIL )
	  IF (IDZHFAIL.NE.0) THEN
	    SF = SFOLD
	    DSF = 0.5D0 * CDABS(CFREQ-CFREQOLD)
	    GOTO 100
	  END IF

	  UP = DCMPLX(PX,PY)                ! note: u,up interchangeable
	  CALL GRDERIVREST ( UP, DLNDO,DERIVDO, DLNDU,DERIVDU )
	  IF (DERIVDU.EQ.(0.0D0,0.0D0)) THEN
	    IASFAIL = 2        ! zero "deriv-u" encountered
	    NFROK = NXTFR - 1
	    RETURN
	  END IF
	  DUDO = - DEXP(DLNDO-DLNDU) * DERIVDO/DERIVDU

	  IF (CFREQ.EQ.CFREQARR(NXTFR)) THEN
	    UCURVE(NXTFR) = UP                  ! note: u,up interchangeable
	    IF (TERM) WRITE(*,*) SNGL(DREAL(CFREQ)),UP
	    DUDFCURVE(NXTFR) = PI2*DUDO         ! note: u,up interchangeable
	    UGRCURVE(NXTFR) = UP + OMEG*DUDO    ! note: u,up interchangeable
	    NXTFR = NXTFR + 1
	    CFREQRIKT = CFREQARR(NXTFR) - CFREQ
	    SFTOT = CDABS(CFREQRIKT)
	    IF (SFTOT.EQ.0.0D0) THEN
	      IASFAIL = 1
	      NFROK = NXTFR - 1
	      RETURN
	    END IF
	    CFREQRIKT = CFREQRIKT / SFTOT
	    SF = 0.0D0
	  END IF

	END DO

	IASFAIL = 0
	NFROK = NFR
	RETURN
	END




	SUBROUTINE CUTSUB ( X1,X2,Y1,Y2, CUTTING )
C	to test if the input rectangle intersects the branch-cuts
C	must have  x1 <= x2  and  y1 <= y2

	IMPLICIT NONE

	INCLUDE 'INPARAM.INC'

	REAL*8 X1,X2,Y1,Y2
	LOGICAL CUTTING

	INTEGER IGANG, IC, INUTI, ISLASK
	REAL*8 XBP(4), YBP(4), XYHYP(4)
	LOGICAL CUT(4)
	SAVE IGANG, CUT, XBP,YBP,XYHYP
	DATA IGANG /0/

	GOTO 10

	ENTRY CUTSUB_REINIT
	IGANG = 0
	RETURN

 10	IF (IGANG.EQ.0) THEN
	  IF (UPBPA.NE.(0.0D0,0.0D0)) THEN
	    CUT(1) = .TRUE.
	    IF (UPBPB.NE.(0.0D0,0.0D0)) THEN
	      CUT(2) = .TRUE.
	    ELSE
	      CUT(2) = .FALSE.
	    END IF
	  ELSE
	    CUT(1) = .FALSE.
	    CUT(2) = .FALSE.
	  END IF
	  IF (CUT(1)) THEN
	    XBP(1) = DREAL(UPBPA)
	    YBP(1) = DIMAG(UPBPA)
	    XYHYP(1) = XBP(1)*YBP(1)
	  END IF
	  IF (CUT(2)) THEN
	    XBP(2) = DREAL(UPBPB)
	    YBP(2) = DIMAG(UPBPB)
	    XYHYP(2) = XBP(2)*YBP(2)
	  END IF
	  IF (UPBPASURF.NE.(0.0D0,0.0D0)) THEN
	    CUT(3) = .TRUE.
	    IF (UPBPBSURF.NE.(0.0D0,0.0D0)) THEN
	      CUT(4) = .TRUE.
	    ELSE
	      CUT(4) = .FALSE.
	    END IF
	  ELSE
	    CUT(3) = .FALSE.
	    CUT(4) = .FALSE.
	  END IF
	  IF (CUT(3)) THEN
	    XBP(3) = DREAL(UPBPASURF)
	    YBP(3) = DIMAG(UPBPASURF)
	    XYHYP(3) = XBP(3)*YBP(3)
	  END IF
	  IF (CUT(4)) THEN
	    XBP(4) = DREAL(UPBPBSURF)
	    YBP(4) = DIMAG(UPBPBSURF)
	    XYHYP(4) = XBP(4)*YBP(4)
	  END IF
	  IGANG = 1
	END IF

	CUTTING = .FALSE.   ! temporary

	DO IC = 1, 4

	  IF (CUT(IC)) THEN
	    IF (X1.GT.XBP(IC)) THEN
	    ELSE IF (X2.LT.-XBP(IC)) THEN
	    ELSE IF ( -XBP(IC).LT.Y1 .AND. Y2.LT.XBP(IC) ) THEN
	    ELSE
C	      now treating y1
	      IF (DABS(Y1).LT.YBP(IC)) THEN
	        INUTI = 1
	      ELSE
	        IF (ICUTTYP.EQ.1) THEN
C	          now the point "x1,y1"
	          IF ( X1*Y1 .LT. XYHYP(IC) ) THEN
	            INUTI = 1
	          ELSE
	            INUTI = 0
	          END IF
C	          now the point "x2,y1"
	          IF ( X2*Y1 .LT. XYHYP(IC) ) THEN
	            ISLASK = 1
	          ELSE
	            ISLASK = 0
	          END IF
	        ELSE
	          IF (ICUTTYP.NE.2) STOP 45178      ! not implemented
C	          now the point "x1,y1"
	          IF ( X1.LT.0.0D0 .AND. Y1.GT.0.0D0 ) THEN
	            INUTI = 1
	          ELSE IF ( X1.GT.0.0D0 .AND. Y1.LT.0.0D0 ) THEN
	            INUTI = 1
	          ELSE IF ( DABS(X1) .LT. XBP(IC) ) THEN
	            INUTI = 1
	          ELSE
	            INUTI = 0
	          END IF
C	          now the point "x2,y1"
	          IF ( X2.LT.0.0D0 .AND. Y1.GT.0.0D0 ) THEN
	            ISLASK = 1
	          ELSE IF ( X2.GT.0.0D0 .AND. Y1.LT.0.0D0 ) THEN
	            ISLASK = 1
	          ELSE IF ( DABS(X2) .LT. XBP(IC) ) THEN
	            ISLASK = 1
	          ELSE
	            ISLASK = 0
	          END IF
	        END IF
	        IF (ISLASK.NE.INUTI) THEN
	          CUTTING = .TRUE.
	          GOTO 999
	        END IF
	      END IF
C	      now treating y2
	      IF (DABS(Y2).LT.YBP(IC)) THEN
	        IF (INUTI.NE.1) THEN
	          CUTTING = .TRUE.
	          GOTO 999
	        END IF
	      ELSE
	        IF (ICUTTYP.EQ.1) THEN
C	          now the point "x1,y2"
	          IF ( X1*Y2 .LT. XYHYP(IC) ) THEN
	            IF (INUTI.NE.1) THEN
	              CUTTING = .TRUE.
	              GOTO 999
	            END IF
	          ELSE
	            IF (INUTI.NE.0) THEN
	              CUTTING = .TRUE.
	              GOTO 999
	            END IF
	          END IF
C	          now the point "x2,y2"
	          IF ( X2*Y2 .LT. XYHYP(IC) ) THEN
	            IF (INUTI.NE.1) THEN
	              CUTTING = .TRUE.
	              GOTO 999
	            END IF
	          ELSE
	            IF (INUTI.NE.0) THEN
	              CUTTING = .TRUE.
	              GOTO 999
	            END IF
	          END IF
	        ELSE
	          IF (ICUTTYP.NE.2) STOP 45178      ! not implemented
C	          now the point "x1,y2"
	          IF ( X1.LT.0.0D0 .AND. Y2.GT.0.0D0 ) THEN
	            IF (INUTI.NE.1) THEN
	              CUTTING = .TRUE.
	              GOTO 999
	            END IF
	          ELSE IF ( X1.GT.0.0D0 .AND. Y2.LT.0.0D0 ) THEN
	            IF (INUTI.NE.1) THEN
	              CUTTING = .TRUE.
	              GOTO 999
	            END IF
	          ELSE IF ( DABS(X1) .LT. XBP(IC) ) THEN
	            IF (INUTI.NE.1) THEN
	              CUTTING = .TRUE.
	              GOTO 999
	            END IF
	          ELSE
	            IF (INUTI.NE.0) THEN
	              CUTTING = .TRUE.
	              GOTO 999
	            END IF
	          END IF
C	          now the point "x2,y2"
	          IF ( X2.LT.0.0D0 .AND. Y2.GT.0.0D0 ) THEN
	            IF (INUTI.NE.1) THEN
	              CUTTING = .TRUE.
	              GOTO 999
	            END IF
	          ELSE IF ( X2.GT.0.0D0 .AND. Y2.LT.0.0D0 ) THEN
	            IF (INUTI.NE.1) THEN
	              CUTTING = .TRUE.
	              GOTO 999
	            END IF
	          ELSE IF ( DABS(X2) .LT. XBP(IC) ) THEN
	            IF (INUTI.NE.1) THEN
	              CUTTING = .TRUE.
	              GOTO 999
	            END IF
	          ELSE
	            IF (INUTI.NE.0) THEN
	              CUTTING = .TRUE.
	              GOTO 999
	            END IF
	          END IF
	        END IF
	      END IF
	    END IF
	  END IF

	END DO

 999	RETURN
	END	
