subroutine aptspht (r1, r2, r3, r4, tol, r5, r6, nerr)

ccbeg.
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
c
c                             SUBROUTINE APTSPHT
c
c     call aptspht (r1, r2, r3, r4, tol, r5, r6, nerr)
c
c     Version:  aptspht  Updated    2001 May 29 15:20.
c               aptspht  Originated 1999 January 5 16:00.
c
c     Author:   Arthur L. Edwards, LLNL, L-298, Telephone (925) 422-4123.
c
c
c     Purpose:  For the four mutually tangent spheres with radii r1, r2, r3
c               and r4, find the radii r5 and r6 of two additional spheres,
c               each tangent to the first four spheres.
c               Flag nerr indicates any input error, if not zero.
c
c     Method:   Defining the curvature b = 1 / r, negative if the tangency
c                 is on the inside of the sphere:
c                 s = b1 + b2 + b3 + b4 => 0
c                 p = b1*b2 + b2*b3 + b3*b4 + b4*b1 + b1*b3 + b2*b4
c                 t = b1**2 + b2**2 + b3**2  + b4**2 > 0
c                 q = 6 * p - 3 * t => 0
c                 g = t - p = b5 * b6
c                 If s < 0 (impossible):
c                   b6 = 0.5 * s - 0.5 * sqrt (q)
c                   b5 = g / b6
c                 If s = 0 (impossible?):
c                   b5 =  0.5 * sqrt (q)
c                   b6 = -0.5 * sqrt (q)
c                 If s > 0:
c                   b5 = 0.5 * s + 0.5 * sqrt (q)
c                   b6 = g / b5
c                 (Other more accurate forms are used when any of the
c                 first four radii are equal.)
c                 r5 = 1 / b5 (1.e99 if b5 = 0)
c                 r6 = 1 / b6 (1.e99 if b6 = 0).
c                 Special case:  if r1 + r2 + r3 = 0.  then r5 = r6 = r4.
c
c     Input:    r1, r2, r3, r4, tol.
c
c     Output:   r5, r6, nerr.
c
c     Calls: none 
c
c     Glossary:
c
c     nerr      Output   Indicates an input error, if not 0.
c                          1 if radii r1, r2, r3 and r4 are physically
c                            impossible.
c                          2 if any of the radii are zero.
c                          3 if r1 + r2 = 0.
c
c     r1 - r4   Input    The radii of four mutually tangent spheres.
c                          A negative radius indicates a sphere that surrounds
c                          the other three spheres.  A very large radius,
c                          relative to the other three, indicates a plane.
c
c     r5        Output   The radius of the sphere tangent to the first four
c                          spheres, in the space between them.
c                          Returned as -1.e99 if nerr = 1 or 2.
c
c     r6        Output   The radius of the sphere tangent to the first four
c                          spheres.
c                          A negative value of r5 means that sphere surrounds
c                          the first four spheres.
c                          A value of r5 near 1.e99 indicates a plane.
c                          Returned as -1.e99 if nerr = 1 or 2.
c
c     tol       Input    Numerical tolerance limit.
c                          On computers with 64-bit floating point numbers,
c                          recommend 1.e-5 to 1.e-11.
c
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
ccend.

cbugc***DEBUG begins.
cbug 9901 format (/ 'aptspht finding radii of spheres tangent to',
cbug     &  ' spheres with radii:' /
cbug     &  '  r1, r2     =',1p2e22.14 /
cbug     &  '  r3, r4     =',1p2e22.14 /
cbug     &  '  tol =       ',1pe22.14 )
cbug      write ( 3, 9901) r1, r2, r3, r4, tol
cbug      b5    = -1.e99
cbug      b6    = -1.e99
cbug      q     = -1.e99
cbug      s     = -1.e99
cbug      t     = -1.e99
cbug      g     = -1.e99
cbugc***DEBUG ends.

c.... Initialize.

      r5    = -1.e99
      r6    = -1.e99

      nerr = 0

c.... Test for input errors.

      if (r1 * r2 * r3 * r4 .eq. 0.0) then
        nerr = 2
        go to 210
      endif

      s12 = r1 + r2
      if (abs (s12) .le. tol * (abs (r1) + abs (r2))) s12 = 0.0
      if (s12 .eq. 0.0) then
        nerr = 3
        go to 210
      endif

c.... Find the curvatures of the first four spheres.

      b1 = 1.0 / r1
      b2 = 1.0 / r2
      b3 = 1.0 / r3
      b4 = 1.0 / r4
cbugcbugc***DEBUG begins.
cbugcbug 9801 format ('  b1, b2    = ',1p3e22.14 /
cbugcbug     &        '  b3, b4    = ',1p2e22.14 )
cbugcbug      write (3, 9801) b1, b2, b3, b4
cbugcbugc***DEBUG ends.

c.... Find the curvatures of the spheres tangent to spheres 1, 2, 3  and 4.

      s    = b1 + b2 + b3 + b4
      errs = tol * (abs (b1) + abs (b2) + abs (b3) + abs (b4))
cbugcbugc***DEBUG begins.
cbugcbug 9802 format ('  s, errs= ',1p2e22.14)
cbugcbug      write (3, 9802) s, errs
cbugcbugc***DEBUG ends.
      if (abs (s) .le. errs)  s = 0.0
cbugcbugc***DEBUG begins.
cbugcbug      write (3, 9802) s, errs
cbugcbugc***DEBUG ends.

c.... Test for the special case r1 + r2 + r3 = 0, r1 + r2 /= 0.

      scir  = r1 + r2 + r3
      errsc = tol * (abs (r1) + abs (r2) + abs (r3))
      if (abs (scir) .le. errsc) scir = 0.0

      if (scir .eq. 0.0) then         ! Special case.
        db = b1 + b2 + b3 - b4
        if (abs (db) .le. errs) then  ! Qualifies.
          r5 = r4
          r6 = r4
          go to 210
        else
          nerr = 1
          go to 210
        endif
      endif

c.... Solve the more general case.

      p    = b1*b2 + b2*b3 + b3*b1 + b1*b4 + b2*b4 + b3*b4
      errp = tol * (abs (b1 * b2) + abs (b2 * b3) +
     &              abs (b3 * b1) + abs (b1 * b4) +
     &              abs (b2 * b4) + abs (b3 * b4) )
cbugcbugc***DEBUG begins.
cbugcbug 9803 format ('  p, errp= ',1p2e22.14)
cbugcbug      write (3, 9803) p, errp
cbugcbugc***DEBUG ends.
      if (abs (p) .le. errp)  p = 0.0
cbugcbugc***DEBUG begins.
cbugcbug      write (3, 9803) p, errp
cbugcbugc***DEBUG ends.

      t    = b1**2 + b2**2 + b3**2 + b4**2
      errt = tol * (b1**2 + b2**2 + b3**2 + b4**2)
cbugcbugc***DEBUG begins.
cbugcbug 9804 format ('  t, errt= ',1p2e22.14)
cbugcbug      write (3, 9804) t, errt
cbugcbugc***DEBUG ends.

      q = 6.0 * p - 3.0 * t
      errq = 6.0 * errp + 3.0 * errt
cbugcbugc***DEBUG begins.
cbugcbug 9805 format ('  q, errq= ',1p2e22.14)
cbugcbug      write (3, 9805) q, errq
cbugcbugc***DEBUG ends.
      if (abs (q) .le. errq) q = 0.0
cbugcbugc***DEBUG begins.
cbugcbug      write (3, 9805) q, errq
cbugcbugc***DEBUG ends.

      if (q .lt. 0.0) then
        nerr = 1
        go to 210
      endif

c.... Find the differences between radii.

      d12   = r2 - r1
      err12 = tol * (abs (r1) + abs (r2))
      if (abs (d12) .le. err12) d12 = 0.0

      d13   = r3 - r1
      err13 = tol * (abs (r1) + abs (r3))
      if (abs (d13) .le. err13) d13 = 0.0

      d14   = r4 - r1
      err14 = tol * (abs (r1) + abs (r4))
      if (abs (d14) .le. err14) d14 = 0.0

      d23   = r3 - r2
      err23 = tol * (abs (r2) + abs (r3))
      if (abs (d23) .le. err23) d23 = 0.0

      d24   = r4 - r2
      err24 = tol * (abs (r2) + abs (r4))
      if (abs (d24) .le. err24) d24 = 0.0

      d34   = r4 - r3
      err34 = tol * (abs (r3) + abs (r4))
      if (abs (d34) .le. err34) d34 = 0.0

c.... Find q and g = b5 * b6 = t - p, by the most accurate equation..

      if ((d12 .eq. 0.0) .and. (d23 .eq. 0.0) .and. (d34 .eq. 0.0)) then
        q    = 24.0 * b1**2
        errq = 0.0
        g    = -2.0 * b1**2
        errg = 0.0
      elseif ((d12 .eq. 0.0) .and. (d23 .eq. 0.0)) then
        q    = 9.0 * b1 * (b1 + 2.0 * b4) - 3.0 * b4**2
        errq = tol * (9.0 * b1**2 + 18.0 * abs (b1 * b4) + 3.0 * b4**2)
        g    = b4 * (b4 - 3.0 * b1)
        errg = tol * (b4**2 - 3.0 * abs (b1 * b4))
      elseif ((d23 .eq. 0.0) .and. (d34 .eq. 0.0)) then
        q    = 9.0 * b2 * (b2 + 2.0 * b1) - 3.0 * b1**2
        errq = tol * (9.0 * b2**2 + 18.0 * abs (b2 * b1) + 3.0 * b1**2)
        g    = b1 * (b1 - 3.0 * b2)
        errg = tol * (b1**2 - 3.0 * abs (b1 * b2))
      elseif ((d14 .eq. 0.0) .and. (d34 .eq. 0.0)) then
        q    = 9.0 * b3 * (b3 + 2.0 * b2) - 3.0 * b2**2
        errq = tol * (9.0 * b3**2 + 18.0 * abs (b3 * b2) + 3.0 * b2**2)
        g    = b2 * (b2 - 3.0 * b3)
        errg = tol * (b2**2 - 3.0 * abs (b2 * b3))
      elseif ((d14 .eq. 0.0) .and. (d24 .eq. 0.0)) then
        q    = 9.0 * b4 * (b4 + 2.0 * b3) - 3.0 * b3**2
        errq = tol * (9.0 * b4**2 + 18.0 * abs (b4 * b3) + 3.0 * b3**2)
        g    = b3 * (b3 - 3.0 * b4)
        errg = tol * (b3**2 - 3.0 * abs (b3 * b4))
      elseif ((d12 .eq. 0.0) .and. (d34 .eq. 0.0)) then
        q    = 24.0 * b1 * b3
        errq = tol * 24.0 * abs (b1 * b3)
        g    = b1**2 + b3**2 - 4.0 * b1 * b3
        errg = tol * (b1**2 + b3**2 + 4.0 * abs (b1 * b3))
      elseif ((d13 .eq. 0.0) .and. (d24 .eq. 0.0)) then
        q    = 24.0 * b1 * b2
        errq = tol * 24.0 * abs (b1 * b2)
        g    = b1**2 + b2**2 - 4.0 * b1 * b2
        errg = tol * (b1**2 + b2**2 + 4.0 * abs (b1 * b2))
      elseif ((d14 .eq. 0.0) .and. (d23 .eq. 0.0)) then
        q    = 24.0 * b1 * b2
        errq = tol * 24.0 * abs (b1 * b2)
        g    = b1**2 + b2**2 - 4.0 * b1 * b2
        errg = tol * (b1**2 + b2**2 + 4.0 * abs (b1 * b2))
      elseif  (d12 .eq. 0.0) then
        q    = 12.0 * b1 * (b3 + b4) - 3.0 * (b3 - b4)**2
        errq = tol * (12.0 * (abs (b1 * b3) + abs (b1 * b4)) +
     &                6.0 * abs (b3 * b4) + 3.0 * (b3**2 + b4**2))
        g    = b1**2 + b3**2 + b4**2 - 2.0 * b1 * (b3 + b4) - b3 * b4
        errg = tol * (b1**2 + b3**2 + b4**2 + 2.0 * abs (b1 * b3) +
     &                2.0 * abs (b1 * b4) + 2.0 * abs (b3 * b4))
      elseif  (d23 .eq. 0.0) then
        q    = 12.0 * b2 * (b4 + b1) - 3.0 * (b4 - b1)**2
        errq = tol * (12.0 * (abs (b2 * b4) + abs (b2 * b1)) +
     &                6.0 * abs (b4 * b1) + 3.0 * (b4**2 + b1**2))
        g    = b2**2 + b4**2 + b1**2 - 2.0 * b2 * (b4 + b1) - b4 * b1
        errg = tol * (b2**2 + b4**2 + b1**2 + 2.0 * abs (b2 * b4) +
     &                2.0 * abs (b2 * b1) + 2.0 * abs (b4 * b1))
      elseif  (d34 .eq. 0.0) then
        q    = 12.0 * b3 * (b1 + b2) - 3.0 * (b1 - b2)**2
        errq = tol * (12.0 * (abs (b3 * b1) + abs (b3 * b2)) +
     &                6.0 * abs (b1 * b2) + 3.0 * (b1**2 + b2**2))
        g    = b3**2 + b1**2 + b2**2 - 2.0 * b3 * (b1 + b2) - b1 * b2
        errg = tol * (b3**2 + b1**2 + b2**2 + 2.0 * abs (b3 * b1) +
     &                2.0 * abs (b3 * b2) + 2.0 * abs (b1 * b2))
      elseif  (d14 .eq. 0.0) then
        q    = 12.0 * b4 * (b2 + b3) - 3.0 * (b2 - b3)**2
        errq = tol * (12.0 * (abs (b4 * b2) + abs (b4 * b3)) +
     &                6.0 * abs (b2 * b3) + 3.0 * (b2**2 + b3**2))
        g    = b4**2 + b2**2 + b3**2 - 2.0 * b4 * (b2 + b3) - b2 * b3
        errg = tol * (b4**2 + b2**2 + b3**2 + 2.0 * abs (b4 * b2) +
     &                2.0 * abs (b4 * b3) + 2.0 * abs (b2 * b3))
      elseif  (d13 .eq. 0.0) then
        q    = 12.0 * b1 * (b2 + b4) - 3.0 * (b2 - b4)**2
        errq = tol * (12.0 * (abs (b1 * b2) + abs (b1 * b4)) +
     &                6.0 * abs (b2 * b4) + 3.0 * (b2**2 + b4**2))
        g    = b1**2 + b2**2 + b4**2 - 2.0 * b1 * (b2 + b4) - b2 * b4
        errg = tol * (b1**2 + b2**2 + b4**2 + 2.0 * abs (b1 * b2) +
     &                2.0 * abs (b1 * b4) + 2.0 * abs (b2 * b4))
      elseif  (d24 .eq. 0.0) then
        q    = 12.0 * b2 * (b3 + b1) - 3.0 * (b3 - b1)**2
        errq = tol * (12.0 * (abs (b2 * b3) + abs (b2 * b1)) +
     &                6.0 * abs (b3 * b1) + 3.0 * (b3**2 + b1**2))
        g    = b2**2 + b3**2 + b1**2 - 2.0 * b2 * (b3 + b1) - b3 * b1
        errg = tol * (b2**2 + b3**2 + b1**2 + 2.0 * abs (b2 * b3) +
     &                2.0 * abs (b2 * b1) + 2.0 * abs (b3 * b1))
      else
        q    = 6.0 * p - 3.0 * t
        errq = 6.0 * errp + 3.0 * errt
        g    = t - p
        errg = errt + errp
      endif
cbugcbugc***DEBUG begins.
cbugcbug 9807 format ('  g, errg= ',1p2e22.14)
cbugcbug      write (3, 9807) g, errg
cbugcbugc***DEBUG ends.

      if (abs (q) .le. errq) q = 0.0
cbugcbugc***DEBUG begins.
cbugcbug      write (3, 9805) q, errq
cbugcbugc***DEBUG ends.

      if (q .lt. 0.0) then
        nerr = 1
        go to 210
      endif

      if (abs (g) .le. errg) g = 0.0
cbugcbugc***DEBUG begins.
cbugcbug      write (3, 9807) g, errg
cbugcbugc***DEBUG ends.

c.... Find the curvatures of spheres 5 and 6.

      if (s .lt. 0.0) then
        b6 = 0.5 * s - 0.5 * sqrt (q)
        b5 = g / b6
      elseif (s .eq. 0.0) then
        b5 =  0.5 * sqrt (q)
        b6 = -0.5 * sqrt (q)
      else
        b5 = 0.5 * s + 0.5 * sqrt (q)
        b6 = g / b5
      endif

c.... Find the radii of spheres 5 and 6.

      if (b5 .eq. 0.0) then
        r5 = 1.e99
      elseif (abs (b5) .ge. 1.e99) then
        r5 = 0.0
      else
        r5 = 1.0 / b5
      endif

      if (b6 .eq. 0.0) then
        r6 = 1.e99
      elseif (abs (b6) .ge. 1.e99) then
        r6 = 0.0
      else
        r6 = 1.0 / b6
      endif

c.... Return the smaller absolute radius as r5.

      if (abs (r6) .lt. abs (r5)) then
        rx = r5
        r5 = r6
        r6 = rx
      endif

  210 continue

cbugc***DEBUG begins.
cbug 9902 format (/ 'aptspht results:  nerr=',i3 /
cbug     &  '  q, s, p    =',1p3e22.14 /
cbug     &  '  t, g       =',1p2e22.14 /
cbug     &  '  b5, b6     =',1p2e22.14 /
cbug     &  '  r5, r6     =',1p2e22.14 )
cbug      write ( 3, 9902) nerr, q, s, p, t, g, b5, b6, r5, r6
cbugc***DEBUG ends.

      return

c.... End of subroutine aptspht.      (+1 line.)
      end

UCRL-WEB-209832