droots Subroutine

subroutine droots(Ng, Hmin, Jflag, X0, X1, G0, G1, Gx, X, Jroot)

This subroutine finds the leftmost root of a set of arbitrary functions gi(x) (i = 1,…,NG) in an interval (X0,X1). Only roots of odd multiplicity (i.e. changes of sign of the gi) are found. Here the sign of X1 - X0 is arbitrary, but is constant for a given problem, and -leftmost- means nearest to X0. The values of the vector-valued function g(x) = (gi, i=1…NG) are communicated through the call sequence of DROOTS. The method used is the Illinois algorithm.

#### Reference: Kathie L. Hiebert and Lawrence F. Shampine, Implicitly Defined Output Points for Solutions of ODEs, Sandia Report SAND80-0180, February 1980.

Description of parameters.

NG

number of functions gi, or the number of components of the vector valued function g(x). Input only.

HMIN

resolution parameter in X. Input only. When a root is found, it is located only to within an error of HMIN in X. Typically, HMIN should be set to something on the order of 100 * UROUND * MAX(ABS(X0),ABS(X1)), where UROUND is the unit roundoff of the machine.

JFLAG

integer flag for input and output communication.

On input, set JFLAG = 0 on the first call for the problem, and leave it unchanged until the problem is completed. (The problem is completed when JFLAG .ge. 2 on return.)

On output

JFLAG

:JFLAG has the following values and meanings:

      JFLAG = 1 means DROOTS needs a value of g(x).  Set GX = g(X)
                and call DROOTS again.
      JFLAG = 2 means a root has been found.  The root is
                at X, and GX contains g(X).  (Actually, X is the
                rightmost approximation to the root on an interval
                (X0,X1) of size HMIN or less.)
      JFLAG = 3 means X = X1 is a root, with one or more of the gi
                being zero at X1 and no sign changes in (X0,X1).
                GX contains g(X) on output.
      JFLAG = 4 means no roots (of odd multiplicity) were
                found in (X0,X1) (no sign changes).
X0,X1

endpoints of the interval where roots are sought. X1 and X0 are input when JFLAG = 0 (first call), and must be left unchanged between calls until the problem is completed. X0 and X1 must be distinct, but X1 - X0 may be of either sign. However, the notion of -left- and -right- will be used to mean nearer to X0 or X1, respectively. When JFLAG .ge. 2 on return, X0 and X1 are output, and are the endpoints of the relevant interval.

G0,G1

arrays of length NG containing the vectors g(X0) and g(X1), respectively. When JFLAG = 0, G0 and G1 are input and none of the G0(i) should be zero. When JFLAG .ge. 2 on return, G0 and G1 are output.

GX

array of length NG containing g(X). GX is input when JFLAG = 1, and output when JFLAG .ge. 2.

X

independent variable value. Output only. When JFLAG = 1 on output, X is the point at which g(x) is to be evaluated and loaded into GX.

  When JFLAG = 2 or 3, X is the root.

  When JFLAG = 4, X is the right endpoint of the interval, X1.
JROOT

integer array of length NG. Output only. When JFLAG = 2 or 3, JROOT indicates which components of g(x) have a root at X. JROOT(i) is 1 if the i-th component has a root, and JROOT(i) = 0 otherwise.

Arguments

Type IntentOptional Attributes Name
integer :: Ng
real(kind=dp), intent(in) :: Hmin
integer, intent(inout) :: Jflag
real(kind=dp), intent(inout) :: X0
real(kind=dp), intent(inout) :: X1
real(kind=dp) :: G0(Ng)
real(kind=dp) :: G1(Ng)
real(kind=dp) :: Gx(Ng)
real(kind=dp), intent(out) :: X
integer, intent(out) :: Jroot(Ng)

Variables

Type Visibility Attributes Name Initial
real(kind=dp), public, parameter :: five = 5.0d0
real(kind=dp), public :: fracint
real(kind=dp), public :: fracsub
real(kind=dp), public, parameter :: half = 0.5d0
integer, public :: i
integer, public :: imxold
integer, public :: nxlast
logical, public :: sgnchg
real(kind=dp), public :: t2
real(kind=dp), public, parameter :: tenth = 0.1d0
real(kind=dp), public :: tmax
logical, public :: xroot
real(kind=dp), public, parameter :: zero = 0.0d0
logical, public :: zroot

Source Code

subroutine droots(Ng,Hmin,Jflag,X0,X1,G0,G1,Gx,X,Jroot)
!
integer                      :: Ng
real(kind=dp),intent(in)     :: Hmin
integer,intent(inout)        :: Jflag
real(kind=dp),intent(inout)  :: X0
real(kind=dp),intent(inout)  :: X1
real(kind=dp)                :: G0(Ng)
real(kind=dp)                :: G1(Ng)
real(kind=dp)                :: Gx(Ng)
real(kind=dp),intent(out)    :: X
integer,intent(out)          :: Jroot(Ng)
!
real(kind=dp) :: fracint , fracsub , t2 , tmax
integer :: i , imxold , nxlast
logical :: sgnchg , xroot , zroot
!
real(kind=dp) , parameter :: five=5.0d0 , half=0.5d0 , tenth=0.1d0 , zero=0.0d0
!
   if ( Jflag==1 ) then
   !  Check to see in which interval g changes sign. -----------------------
      imxold = dlsr%imax
      dlsr%imax = 0
      tmax = zero
      zroot = .false.
      do i = 1 , Ng
         if ( abs(Gx(i))<=zero ) then
            zroot = .true.
         !  Neither G0(i) nor GX(i) can be zero at this point. -------------------
         elseif ( sign(1.0D0,G0(i))/=sign(1.0D0,Gx(i)) ) then
            t2 = abs(Gx(i)/(Gx(i)-G0(i)))
            if ( t2>tmax ) then
               tmax = t2
               dlsr%imax = i
            endif
         endif
      enddo
      if ( dlsr%imax>0 ) then
         sgnchg = .true.
      else
         sgnchg = .false.
         dlsr%imax = imxold
      endif
      nxlast = dlsr%last
      if ( sgnchg ) then
   !  Sign change between X0 and X2, so replace X1 with X2. ----------------
         X1 = dlsr%x2
         !X!call dcopy(Ng,Gx,1,G1,1)
         G1(1:Ng) = Gx(1:Ng)!X!
         dlsr%last = 1
         xroot = .false.
      elseif ( .not.zroot ) then
   !  No sign change between X0 and X2.  Replace X0 with X2. ---------------
         !X!call dcopy(Ng,Gx,1,G0,1)
         G0(1:Ng) = Gx(1:Ng)!X!
         X0 = dlsr%x2
         dlsr%last = 0
         xroot = .false.
      else
   !  Zero value at X2 and no sign change in (X0,X2), so X2 is a root. -----
         X1 = dlsr%x2
         !X!call dcopy(Ng,Gx,1,G1,1)
         G1(1:Ng) = Gx(1:Ng)!X!
         xroot = .true.
      endif
      if ( abs(X1-X0)<=Hmin ) xroot = .true.
   else
   !  JFLAG .ne. 1.  Check for change in sign of g or zero at X1. ----------
      dlsr%imax = 0
      tmax = zero
      zroot = .false.
      do i = 1 , Ng
         if ( abs(G1(i))<=zero ) then
            zroot = .true.
   !  At this point, G0(i) has been checked and cannot be zero. ------------
         elseif ( sign(1.0D0,G0(i))/=sign(1.0D0,G1(i)) ) then
            t2 = abs(G1(i)/(G1(i)-G0(i)))
            if ( t2>tmax ) then
               tmax = t2
               dlsr%imax = i
            endif
         endif
      enddo
      if ( dlsr%imax>0 ) then
         sgnchg = .true.
      else
         sgnchg = .false.
      endif
      if ( .not.sgnchg ) then
   !
   !  No sign change in the interval.  Check for zero at right endpoint. ---
         if ( zroot ) then
            !
            !  Zero value at X1 and no sign change in (X0,X1).  Return JFLAG = 3. ---
            X = X1
            !X!call dcopy(Ng,G1,1,Gx,1)
            Gx(1:Ng) = G1(1:Ng)!X!
            do i = 1 , Ng
               Jroot(i) = 0
               if ( abs(G1(i))<=zero ) Jroot(i) = 1
            enddo
            Jflag = 3
            return
         endif
   !
   !  No sign changes in this interval.  Set X = X1, return JFLAG = 4. -----
         !X!call dcopy(Ng,G1,1,Gx,1)
         Gx(1:Ng) = G1(1:Ng)!X!
         X = X1
         Jflag = 4
         return
      else
   !  There is a sign change.  Find the first root in the interval. --------
         xroot = .false.
         nxlast = 0
         dlsr%last = 1
      endif
   endif
   !
   !  Repeat until the first root in the interval is found.  Loop point. ---
   if ( xroot ) then
   !
   !  Return with X1 as the root.  Set JROOT.  Set X = X1 and GX = G1. -----
      Jflag = 2
      X = X1
      !X!call dcopy(Ng,G1,1,Gx,1)
      Gx(1:Ng) = G1(1:Ng)!X!
      do i = 1 , Ng
         Jroot(i) = 0
         if ( abs(G1(i))>zero ) then
            if ( sign(1.0D0,G0(i))/=sign(1.0D0,G1(i)) ) Jroot(i) = 1
         else
            Jroot(i) = 1
         endif
      enddo
   else
      if ( nxlast/=dlsr%last ) then
         dlsr%alpha = 1.0D0
      elseif ( dlsr%last==0 ) then
         dlsr%alpha = 2.0D0*dlsr%alpha
      else
         dlsr%alpha = 0.5D0*dlsr%alpha
      endif
      dlsr%x2 = X1 - (X1-X0)*G1(dlsr%imax)/(G1(dlsr%imax)-dlsr%alpha*G0(dlsr%imax))
   !  If X2 is too close to X0 or X1, adjust it inward, by a fractional ----
   !  distance that is between 0.1 and 0.5. --------------------------------
      if ( abs(dlsr%x2-X0)<half*Hmin ) then
         fracint = abs(X1-X0)/Hmin
         fracsub = tenth
         if ( fracint<=five ) fracsub = half/fracint
         dlsr%x2 = X0 + fracsub*(X1-X0)
      endif
      if ( abs(X1-dlsr%x2)<half*Hmin ) then
         fracint = abs(X1-X0)/Hmin
         fracsub = tenth
         if ( fracint<=five ) fracsub = half/fracint
         dlsr%x2 = X1 - fracsub*(X1-X0)
      endif
      Jflag = 1
      X = dlsr%x2
   !  Return to the calling routine to get a value of GX = g(X). -----------
   endif
end subroutine droots