C	subroutine to refine a "zero within a rectangle" of an 
C       analytic function

C	sven ivansson   1990




	SUBROUTINE DZEROHOLO (CDETSUB, X1,X2,Y1,Y2, DLOGREDUCFAKT,DDELT,
     $	XYTOL, PX,PY,XYTOLUT,RLNDET,CDET, IDZHFCALL,IDZHFAIL)
C	cdetsub          subroutine cdetsub (px,py, rlndet,cdet)  gives 
C	                 "the function" as  dexp(rlndet)*cdet  , "the 
C	                 function" must be analytic inside the rectangle 
C	                 and continuous up to the boundary and zero-free 
C	                 on the boundary  ,  up = px + i*py
C	x1,x2            horizontal limits of the rectangle
C	y1,y2            vertical limits of the rectangle
C	dlogreducfakt    "dlog" of required reduction factor in each step for 
C	                 the absolute value of "the function"
C	ddelt            distance-difference limit for "secant derivative"
C	xytol            desired accuracy for the zero (close to the borders 
C	                 of the rectangle it will be better, see "xytolut")
C	px,py          input/output (OBS)  real & imaginary part of the zero
C	                         should be "within the rectangle" on entry 
C	                         (otherwise the "midpoint" is used)
C	xytolut        output  estimated accuracy for the zero so that 
C	                 * xytolut is an upper bound for the Euclidean 
C	                   distance from (px,py) to the zero
C	                 * the "rectangle (px+-xytolut;py+-xytolut)" is 
C	                   within the "rectangle (x1,x2;y1,y2)"
C	rlndet,cdet    input/output (OBS)  give "function value" at (px,py)
C	idzhfcall      input/output (OBS)  total number of cdetsub calls
C	idzhfail       output  "return status":  0 for successful result
C	                         1 for "unsuccessful, try a smaller rectangle"
C	                         2 for "zero found on the boundary"

	IMPLICIT NONE

	REAL*8 X1,X2,Y1,Y2, DLOGREDUCFAKT,DDELT,XYTOL

	INTEGER IDZHFCALL
	REAL*8 PX,PY, RLNDET
	COMPLEX*16 CDET

	INTEGER IDZHFAIL
	REAL*8 XYTOLUT

	REAL*8 XSIDG2,YSIDG2, DDELTLOK, PXD,PYD, PXNEW,PYNEW, RLNDETD,
     $	RLNDETNEW, XDIFF,YDIFF, SLASK
	COMPLEX*16 CDETD,CDETNEW, ZDIFFD, ZDIFF, CSLASK

        EXTERNAL CDETSUB

	XSIDG2 = 0.5D0 * (X2-X1)
	YSIDG2 = 0.5D0 * (Y2-Y1)
	DDELTLOK = DMIN1 ( 0.5D0*DMIN1(XSIDG2,YSIDG2) , DDELT )

	IF (PX.LE.X1 .OR. X2.LE.PX .OR. PY.LE.Y1 .OR. Y2.LE.PY) THEN
	  PX = 0.5D0 * (X1+X2)
	  PY = 0.5D0 * (Y1+Y2)
	  IDZHFCALL = IDZHFCALL + 1
	  CALL CDETSUB (PX,PY, RLNDET,CDET)
	END IF
	IF (CDET.EQ.(0.0D0,0.0D0)) THEN
	  XYTOLUT = 0.0D0
	  IDZHFAIL = 0
	  RETURN
	END IF
	PXD = PX + DDELTLOK
	IF (PXD.GT.X2) PXD = PX - DDELTLOK
	PYD = PY
	ZDIFFD = DCMPLX(PX-PXD,0.0D0)

 100	IDZHFCALL = IDZHFCALL + 1
	CALL CDETSUB (PXD,PYD, RLNDETD,CDETD)
	IF (CDETD.EQ.(0.0D0,0.0D0)) THEN
	  PX = PXD
	  PY = PYD
	  XYTOLUT = 0.0D0
	  RLNDET = RLNDETD
	  CDET = CDETD
	  IF (X1.LT.PX .AND. PX.LT.X2 .AND. Y1.LT.PY .AND. PY.LT.Y2) THEN 
	    IDZHFAIL = 0
	  ELSE
	    IDZHFAIL = 2
	  END IF
	  RETURN
	END IF

 200	SLASK = RLNDETD - RLNDET
	IF (DABS(SLASK).GE.88.0D0) THEN     !  1.7*(10**38) "=" exp(88.2)
	  IDZHFAIL = 1
	  RETURN
	END IF
	CSLASK = 1 - DEXP(SLASK)*(CDETD/CDET)
	IF (CSLASK.EQ.(0.0D0,0.0D0)) THEN
	  IDZHFAIL = 1
	  RETURN
	END IF
	ZDIFF = - ZDIFFD / CSLASK          ! in general the "secant rule"

	XDIFF = DREAL(ZDIFF)
	YDIFF = DIMAG(ZDIFF)
	PXNEW = PX + XDIFF
	PYNEW = PY + YDIFF
	IF (PXNEW.LT.X1) THEN
	  PYNEW = PY + (X1-PX)*(YDIFF/XDIFF)
	  PXNEW = X1
	ELSE IF (PXNEW.GT.X2) THEN
	  PYNEW = PY + (X2-PX)*(YDIFF/XDIFF)
	  PXNEW = X2
	END IF
	IF (PYNEW.LT.Y1) THEN
	  PXNEW = PX + (Y1-PY)*(XDIFF/YDIFF)
	  PYNEW = Y1
	ELSE IF (PYNEW.GT.Y2) THEN
	  PXNEW = PX + (Y2-PY)*(XDIFF/YDIFF)
	  PXNEW = Y2
	END IF
	IF (PXNEW.LT.X1) PXNEW = X1
	IF (PXNEW.GT.X2) PXNEW = X2
	IF (PYNEW.LT.Y1) PYNEW = Y1
	IF (PYNEW.GT.Y2) PYNEW = Y2
	ZDIFF = DCMPLX(PXNEW-PX,PYNEW-PY)
	IF (ZDIFF.EQ.(0.0D0,0.0D0)) THEN
	  IDZHFAIL = 1           ! this is extremely cautious
	  RETURN
	END IF

	IDZHFCALL = IDZHFCALL + 1
	CALL CDETSUB (PXNEW,PYNEW, RLNDETNEW,CDETNEW)
	IF (CDETNEW.EQ.(0.0D0,0.0D0)) THEN
	  PX = PXNEW
	  PY = PYNEW
	  XYTOLUT = 0.0D0
	  RLNDET = RLNDETNEW
	  CDET = CDETNEW
	  IF (X1.LT.PX .AND. PX.LT.X2 .AND. Y1.LT.PY .AND. PY.LT.Y2) THEN 
	    IDZHFAIL = 0
	  ELSE
	    IDZHFAIL = 2
	  END IF
	  RETURN
	END IF

	SLASK = RLNDETNEW - RLNDET + DLOG(CDABS(CDETNEW/CDET))
	IF (SLASK.GE.DLOGREDUCFAKT) THEN
	  IDZHFAIL = 1
	  RETURN
	END IF

	SLASK = 1.414213562373095D0 * DMAX1 ( DABS(DREAL(ZDIFF)), 
     $	DABS(DIMAG(ZDIFF)) )   ! "cheap" upper bound for Euclidean norm
	IF (SLASK.GE.XYTOL) THEN
	ELSE IF ( (PXNEW-SLASK) .LE. X1 ) THEN
	ELSE IF ( (PXNEW+SLASK) .GE. X2 ) THEN
	ELSE IF ( (PYNEW-SLASK) .LE. Y1 ) THEN
	ELSE IF ( (PYNEW+SLASK) .GE. Y2 ) THEN
	ELSE
	  PX = PXNEW
	  PY = PYNEW
	  XYTOLUT = SLASK
	  RLNDET = RLNDETNEW
	  CDET = CDETNEW
	  IDZHFAIL = 0
	  RETURN
	END IF
	IF (SLASK.LE.DDELTLOK) THEN
	  PXD = PX
	  PYD = PY
	  RLNDETD = RLNDET
	  CDETD = CDET
	  PX = PXNEW
	  PY = PYNEW
	  RLNDET = RLNDETNEW
	  CDET = CDETNEW
	  ZDIFFD = DCMPLX(PX-PXD,PY-PYD)
	  GOTO 200
	ELSE
	  PXD = PXNEW + DDELTLOK
	  IF (PXD.GT.X2) PXD = PXNEW - DDELTLOK
	  PYD = PYNEW
	  PX = PXNEW
	  PY = PYNEW
	  RLNDET = RLNDETNEW
	  CDET = CDETNEW
	  ZDIFFD = DCMPLX(PX-PXD,0.0D0)
	  GOTO 100
	END IF

	END
