C Copyright(C) 1999-2020 National Technology & Engineering Solutions
C of Sandia, LLC (NTESS).  Under the terms of Contract DE-NA0003525 with
C NTESS, the U.S. Government retains certain rights in this software.
C
C See packages/seacas/LICENSE for details

      SUBROUTINE SHLSRC(
     *  NDIM,     NPTS,     NPSRF,    NFSRF,    NISR,
     *  NRSR,     NRSS,     XYZSRF,   XYZPTS,   LINKSRF,
     *  ISRCHR,   RSRCHR,   NN,      IFSRF,     TOLSRCH,
     *  IERR    )

C-----------------------------------------------------------------------

C DESCRIPTION:

C THIS SUBROUTINE CALCULATES THE CLOSEST POINT PROBLEM
C BETWEEN 'KOUNTS' PAIRS OF POINTS AND SURFACES.

C-----------------------------------------------------------------------

C FORMAL PARAMETERS

C MEMORY      : P=PERMANENT, S=SCRATCH
C NAME        : IMPLICIT A-H,O-Z REAL, I-N INTEGER
C TYPE        : INPUT_STATUS/OUTPUT_STATUS (I=INPUT,O=OUTPUT,P=PASSED,
C               U=UNMODIFIED,-=UNDEFINED)
C DESCRIPTION : DESCRIPTION OF VARIABLE

C-----------------------------------------------------------------------

C CALLING ARGUMENTS

C MEMORY NAME     TYPE   DESCRIPTION
C ---    ----     ---    -----------
C  P     NDIM     I/U    DIMENSION OF PROBLEM=3
C  P     NPTS     I/U    NUMBER OF POINTS TO BE SEARCHED
C  P     NPSRF    I/U    NUMBER OF POINTS THAT DEFINE THE SURFACE
C  P     NFSRF    I/U    NUMBER OF SURFACES
C  P     NISR     I/U    NUMBER OF INTEGER SEARCH RESULTS (>=1)
C  P     NRSR     I/U    NUMBER OF REAL SEARCH RESULTS (>=4)
C  P     NRSS     I/U    NUMBER OF REAL SEARCH SCRATCH MEMORY (=10)
C  P     XYZSRF   I/U    XYZ COORDS OF POINTS DEFINING SURFACE
C  P     XYZPTS   I/U    XYZ COORDS OF POINTS TO BE SEARCHED
C  P     LINKSRF  I/U    CONNECTIVITY OF SURFACES OF SIZE (4*NFSRF),
C                        NUMBERS REFER TO LOCATIONS IN XYZSRF ARRAY
C  P     ISRCHR   I/O    INTEGER SEARCH RESULTS
C  P     RSRCHR   I/O    REAL SEARCH RESULTS
C  P     NN       I/U    POINT PAIRED WITH SURFACE IFSRF
C  P     IFSRF   I/U     SURFACE PAIRED WITH POINT NN
C  S     CTRCL    -/-    TRACKING ARRAY FOR KOUNTS POINT-SURFACE PAIRS
C  P     TOLSRCH  I/U    PROXIMITY TOLERANCE FOR POINT-TO-SURFACE SEARCH

C-----------------------------------------------------------------------

C INPUT/OUTPUT ARRAYS
      DIMENSION
     *  XYZPTS(NPTS,NDIM)   ,XYZSRF(NPSRF,NDIM)  ,LINKSRF(4,NFSRF)    ,
     *  ISRCHR(NISR,NPTS)   ,RSRCHR(NRSR,NPTS)
C SCRATCH ARRAYS
      DIMENSION CTRCL(10)

C ... Eliminate uninitialized variable warning...
      do i=1, 10
        ctrcl(i) = 0.0
      end do

      IF( NISR .LT. 1 .OR. NRSR .LT. 4 .OR. NRSS .LT. 10 )THEN
        IERR = 1
        RETURN
      ENDIF
      ZERO = 0
      ONE = 1

C COMPUTE SURFACE NORMALS AND STORE
      N1 = LINKSRF(1,IFSRF)
      N2 = LINKSRF(2,IFSRF)
      N3 = LINKSRF(3,IFSRF)
      N4 = LINKSRF(4,IFSRF)
      UX = -XYZSRF(N1,1) +XYZSRF(N2,1) +XYZSRF(N3,1) -XYZSRF(N4,1)
      UY = -XYZSRF(N1,2) +XYZSRF(N2,2) +XYZSRF(N3,2) -XYZSRF(N4,2)
      UZ = -XYZSRF(N1,3) +XYZSRF(N2,3) +XYZSRF(N3,3) -XYZSRF(N4,3)
      VX = -XYZSRF(N1,1) -XYZSRF(N2,1) +XYZSRF(N3,1) +XYZSRF(N4,1)
      VY = -XYZSRF(N1,2) -XYZSRF(N2,2) +XYZSRF(N3,2) +XYZSRF(N4,2)
      VZ = -XYZSRF(N1,3) -XYZSRF(N2,3) +XYZSRF(N3,3) +XYZSRF(N4,3)
      PMX = UY * VZ - UZ * VY
      PMY = UZ * VX - UX * VZ
      PMZ = UX * VY - UY * VX
      PMAG = SQRT( PMX*PMX + PMY*PMY + PMZ*PMZ )
      CTRCL(8)  = PMX / PMAG
      CTRCL(9)  = PMY / PMAG
      CTRCL(10) = PMZ / PMAG

C SURFACE NORMAL
      A4I = CTRCL(8)
      A4J = CTRCL(9)
      A4K = CTRCL(10)
C POINT LOCATION
      XSD = XYZPTS(NN,1)
      YSD = XYZPTS(NN,2)
      ZSD = XYZPTS(NN,3)
C NODE NUMBERS IN CURRENT SURFACE NODE LIST
      N1 = LINKSRF(1,IFSRF)
      N2 = LINKSRF(2,IFSRF)
      N3 = LINKSRF(3,IFSRF)
      N4 = LINKSRF(4,IFSRF)
C COMPUTE NORMAL DISTANCE FROM THE SURFACE TO THE POINT
C NOTE THAT A NEGATIVE DISTANCE IMPLIES THE POINT IS INSIDE THE FACE
      VX1S = XSD - XYZSRF(N1,1)
      VY1S = YSD - XYZSRF(N1,2)
      VZ1S = ZSD - XYZSRF(N1,3)
C DOT THE VECTOR FROM POINT 1 ON SURFACE TO THE POINT
C WITH THE OUTWARD UNIT NORMAL
      PROJN = VX1S*A4I + VY1S*A4J + VZ1S*A4K
C FIND CLOSEST POINT
      XC = XSD - PROJN*A4I
      YC = YSD - PROJN*A4J
      ZC = ZSD - PROJN*A4K
C DETERMINE IF THE CLOSEST POINT IS INSIDE THE SURFACE
      VX1 = XYZSRF(N1,1) - XC
      VY1 = XYZSRF(N1,2) - YC
      VZ1 = XYZSRF(N1,3) - ZC
      VX2 = XYZSRF(N2,1) - XC
      VY2 = XYZSRF(N2,2) - YC
      VZ2 = XYZSRF(N2,3) - ZC
      VX3 = XYZSRF(N3,1) - XC
      VY3 = XYZSRF(N3,2) - YC
      VZ3 = XYZSRF(N3,3) - ZC
      VX4 = XYZSRF(N4,1) - XC
      VY4 = XYZSRF(N4,2) - YC
      VZ4 = XYZSRF(N4,3) - ZC
      A1 = ( VY1*VZ2-VY2*VZ1)*A4I +
     *  (-VX1*VZ2+VX2*VZ1)*A4J +
     *  ( VX1*VY2-VX2*VY1)*A4K
      A2 = ( VY2*VZ3-VY3*VZ2)*A4I +
     *  (-VX2*VZ3+VX3*VZ2)*A4J +
     *  ( VX2*VY3-VX3*VY2)*A4K
      A3 = ( VY3*VZ4-VY4*VZ3)*A4I +
     *  (-VX3*VZ4+VX4*VZ3)*A4J +
     *  ( VX3*VY4-VX4*VY3)*A4K
      A4 = ( VY4*VZ1-VY1*VZ4)*A4I +
     *  (-VX4*VZ1+VX1*VZ4)*A4J +
     *  ( VX4*VY1-VX1*VY4)*A4K
C AREA COORDS
      XCOORD = (2*A4/(A4+A2) - 1)
      ECOORD = (2*A1/(A1+A3) - 1)
      CTRCL(1) = 0
      IF( ABS(PROJN)  .LE. TOLSRCH )THEN
        CTRCL(1) = IFSRF
        CTRCL(2) = XCOORD
        CTRCL(3) = ECOORD
        CTRCL(4) = PROJN
        CTRCL(5) = A4I
        CTRCL(6) = A4J
        CTRCL(7) = A4K
        IF( ABS(XCOORD) .GT. 1 .OR. ABS(ECOORD) .GT. 1 )
     *    CTRCL(1) = -CTRCL(1)
      ENDIF

C SURFACE NORMAL
      A4I = CTRCL(8)
      A4J = CTRCL(9)
      A4K = CTRCL(10)
C LOCAL COORDS
      XCOORD = CTRCL(2)
      ECOORD = CTRCL(3)
C NODE NUMBERS IN CURRENT SURFACE NODE LIST
      N1 = LINKSRF(1,IFSRF)
      N2 = LINKSRF(2,IFSRF)
      N3 = LINKSRF(3,IFSRF)
      N4 = LINKSRF(4,IFSRF)
      IF( XCOORD .GT. 1 ) THEN
        VXS = XYZSRF(N3,1) - XYZSRF(N2,1)
        VYS = XYZSRF(N3,2) - XYZSRF(N2,2)
        VZS = XYZSRF(N3,3) - XYZSRF(N2,3)
        VXP = XYZPTS(NN,1) - XYZSRF(N2,1)
        VYP = XYZPTS(NN,2) - XYZSRF(N2,2)
        VZP = XYZPTS(NN,3) - XYZSRF(N2,3)
C  PROJECTION OF VECTOR FROM SURFACE NODE TO POINT ONTO THE
C  VECTOR FROM SURFACE NODE 1 TO NODE 2, AND THE LOCAL COORD, S
        PROJPS = VXP*VXS + VYP*VYS + VZP*VZS
        VMAGPS = ABS(VXS*VXS+VYS*VYS+VZS*VZS)
C  LOCAL COORD. (S) ALONG 1-2
        SPS = PROJPS/VMAGPS
        SPS = MAX(ZERO,SPS)
        SPS = MIN(ONE,SPS)
C  NEAREST POINT ON LINE 1-2
        XC12 = XYZSRF(N2,1) + SPS*VXS
        YC12 = XYZSRF(N2,2) + SPS*VYS
        ZC12 = XYZSRF(N2,3) + SPS*VZS
C  VECTOR FROM NEAREST POINT TO SLAVE NODE
        VCS12X = XYZPTS(NN,1)-XC12
        VCS12Y = XYZPTS(NN,2)-YC12
        VCS12Z = XYZPTS(NN,3)-ZC12
C  DISTANCE FROM NEAREST POINT TO SLAVE NODE
        DISPS = SQRT(VCS12X*VCS12X+VCS12Y*VCS12Y+VCS12Z*VCS12Z)
C  DOT DISTANCE WITH SURFACE NORMAL TO DETERMINE POS. OR NEG. DIST.
        SDIS = VCS12X*A4I+VCS12Y*A4J+VCS12Z*A4K
        PROJN = SIGN(DISPS,SDIS)
C  RECOMPUTE LOCAL COORDS
        XCOORD = 1
        ECOORD = 2*SPS - 1
        IF( DISPS .LT. 1.E-6 )THEN
          VCS12X = A4I
          VCS12Y = A4J
          VCS12Z = A4K
          DISPS = 1.
        ENDIF
        CTRCL(1) = -IFSRF
        CTRCL(2) = XCOORD
        CTRCL(3) = ECOORD
        CTRCL(4) = PROJN
        CTRCL(5) = VCS12X/DISPS
        CTRCL(6) = VCS12Y/DISPS
        CTRCL(7) = VCS12Z/DISPS
      ENDIF

C SURFACE NORMAL
      A4I = CTRCL(8)
      A4J = CTRCL(9)
      A4K = CTRCL(10)
C LOCAL COORDS
      XCOORD = CTRCL(2)
      ECOORD = CTRCL(3)
C NODE NUMBERS IN CURRENT SURFACE NODE LIST
      N1 = LINKSRF(1,IFSRF)
      N2 = LINKSRF(2,IFSRF)
      N3 = LINKSRF(3,IFSRF)
      N4 = LINKSRF(4,IFSRF)
      IF( XCOORD .LT. -1 )THEN
        VXS = XYZSRF(N4,1) - XYZSRF(N1,1)
        VYS = XYZSRF(N4,2) - XYZSRF(N1,2)
        VZS = XYZSRF(N4,3) - XYZSRF(N1,3)
        VXP = XYZPTS(NN,1) - XYZSRF(N1,1)
        VYP = XYZPTS(NN,2) - XYZSRF(N1,2)
        VZP = XYZPTS(NN,3) - XYZSRF(N1,3)
C  PROJECTION OF VECTOR FROM SURFACE NODE TO POINT ONTO THE
C  VECTOR FROM SURFACE NODE 1 TO NODE 2, AND THE LOCAL COORD, S
        PROJPS = VXP*VXS + VYP*VYS + VZP*VZS
        VMAGPS = ABS(VXS*VXS+VYS*VYS+VZS*VZS)
C  LOCAL COORD. (S) ALONG 1-2
        SPS = PROJPS/VMAGPS
        SPS = MAX(ZERO,SPS)
        SPS = MIN(ONE,SPS)
C  NEAREST POINT ON LINE 1-2
        XC12 = XYZSRF(N1,1) + SPS*VXS
        YC12 = XYZSRF(N1,2) + SPS*VYS
        ZC12 = XYZSRF(N1,3) + SPS*VZS
C  VECTOR FROM NEAREST POINT TO SLAVE NODE
        VCS12X = XYZPTS(NN,1)-XC12
        VCS12Y = XYZPTS(NN,2)-YC12
        VCS12Z = XYZPTS(NN,3)-ZC12
C  DISTANCE FROM NEAREST POINT TO SLAVE NODE
        DISPS = SQRT(VCS12X*VCS12X+VCS12Y*VCS12Y+VCS12Z*VCS12Z)
C  DOT DISTANCE WITH SURFACE NORMAL TO DETERMINE POS. OR NEG. DIST.
        SDIS = VCS12X*A4I+VCS12Y*A4J+VCS12Z*A4K
        PROJN = SIGN(DISPS,SDIS)
C  RECOMPUTE LOCAL COORDS
        XCOORD = -1
        ECOORD = 2*SPS - 1
        IF( DISPS .LT. 1.E-6 )THEN
          VCS12X = A4I
          VCS12Y = A4J
          VCS12Z = A4K
          DISPS = 1.
        ENDIF
        CTRCL(1) = -IFSRF
        CTRCL(2) = XCOORD
        CTRCL(3) = ECOORD
        CTRCL(4) = PROJN
        CTRCL(5) = VCS12X/DISPS
        CTRCL(6) = VCS12Y/DISPS
        CTRCL(7) = VCS12Z/DISPS
      ENDIF

C SURFACE NORMAL
      A4I = CTRCL(8)
      A4J = CTRCL(9)
      A4K = CTRCL(10)
C LOCAL COORDS
      XCOORD = CTRCL(2)
      ECOORD = CTRCL(3)
C NODE NUMBERS IN CURRENT SURFACE NODE LIST
      N1 = LINKSRF(1,IFSRF)
      N2 = LINKSRF(2,IFSRF)
      N3 = LINKSRF(3,IFSRF)
      N4 = LINKSRF(4,IFSRF)
      IF( ECOORD .GT. 1 )THEN
        VXS = XYZSRF(N3,1) - XYZSRF(N4,1)
        VYS = XYZSRF(N3,2) - XYZSRF(N4,2)
        VZS = XYZSRF(N3,3) - XYZSRF(N4,3)
        VXP = XYZPTS(NN,1) - XYZSRF(N4,1)
        VYP = XYZPTS(NN,2) - XYZSRF(N4,2)
        VZP = XYZPTS(NN,3) - XYZSRF(N4,3)
C  PROJECTION OF VECTOR FROM SURFACE NODE TO POINT ONTO THE
C  VECTOR FROM SURFACE NODE 1 TO NODE 2, AND THE LOCAL COORD, S
        PROJPS = VXP*VXS + VYP*VYS + VZP*VZS
        VMAGPS = ABS(VXS*VXS+VYS*VYS+VZS*VZS)
C  LOCAL COORD. (S) ALONG 1-2
        SPS = PROJPS/VMAGPS
        SPS = MAX(ZERO,SPS)
        SPS = MIN(ONE,SPS)
C  NEAREST POINT ON LINE 1-2
        XC12 = XYZSRF(N4,1) + SPS*VXS
        YC12 = XYZSRF(N4,2) + SPS*VYS
        ZC12 = XYZSRF(N4,3) + SPS*VZS
C  VECTOR FROM NEAREST POINT TO SLAVE NODE
        VCS12X = XYZPTS(NN,1)-XC12
        VCS12Y = XYZPTS(NN,2)-YC12
        VCS12Z = XYZPTS(NN,3)-ZC12
C  DISTANCE FROM NEAREST POINT TO SLAVE NODE
        DISPS = SQRT(VCS12X*VCS12X+VCS12Y*VCS12Y+VCS12Z*VCS12Z)
C  DOT DISTANCE WITH SURFACE NORMAL TO DETERMINE POS. OR NEG. DIST.
        SDIS = VCS12X*A4I+VCS12Y*A4J+VCS12Z*A4K
        PROJN = SIGN(DISPS,SDIS)
C  RECOMPUTE LOCAL COORDS
        XCOORD = 2*SPS - 1
        ECOORD = 1
        IF( DISPS .LT. 1.E-6 )THEN
          VCS12X = A4I
          VCS12Y = A4J
          VCS12Z = A4K
          DISPS = 1.
        ENDIF
        CTRCL(1) = -IFSRF
        CTRCL(2) = XCOORD
        CTRCL(3) = ECOORD
        CTRCL(4) = PROJN
        CTRCL(5) = VCS12X/DISPS
        CTRCL(6) = VCS12Y/DISPS
        CTRCL(7) = VCS12Z/DISPS
      ENDIF

C SURFACE NORMAL
      A4I = CTRCL(8)
      A4J = CTRCL(9)
      A4K = CTRCL(10)
C LOCAL COORDS
      XCOORD = CTRCL(2)
      ECOORD = CTRCL(3)
C NODE NUMBERS IN CURRENT SURFACE NODE LIST
      N1 = LINKSRF(1,IFSRF)
      N2 = LINKSRF(2,IFSRF)
      N3 = LINKSRF(3,IFSRF)
      N4 = LINKSRF(4,IFSRF)
      IF( ECOORD .LT. -1 )THEN
        VXS = XYZSRF(N2,1) - XYZSRF(N1,1)
        VYS = XYZSRF(N2,2) - XYZSRF(N1,2)
        VZS = XYZSRF(N2,3) - XYZSRF(N1,3)
        VXP = XYZPTS(NN,1) - XYZSRF(N1,1)
        VYP = XYZPTS(NN,2) - XYZSRF(N1,2)
        VZP = XYZPTS(NN,3) - XYZSRF(N1,3)
C  PROJECTION OF VECTOR FROM SURFACE NODE TO POINT ONTO THE
C  VECTOR FROM SURFACE NODE 1 TO NODE 2, AND THE LOCAL COORD, S
        PROJPS = VXP*VXS + VYP*VYS + VZP*VZS
        VMAGPS = ABS(VXS*VXS+VYS*VYS+VZS*VZS)
C  LOCAL COORD. (S) ALONG 1-2
        SPS = PROJPS/VMAGPS
        SPS = MAX(ZERO,SPS)
        SPS = MIN(ONE,SPS)
C  NEAREST POINT ON LINE 1-2
        XC12 = XYZSRF(N1,1) + SPS*VXS
        YC12 = XYZSRF(N1,2) + SPS*VYS
        ZC12 = XYZSRF(N1,3) + SPS*VZS
C  VECTOR FROM NEAREST POINT TO SLAVE NODE
        VCS12X = XYZPTS(NN,1)-XC12
        VCS12Y = XYZPTS(NN,2)-YC12
        VCS12Z = XYZPTS(NN,3)-ZC12
C  DISTANCE FROM NEAREST POINT TO SLAVE NODE
        DISPS = SQRT(VCS12X*VCS12X+VCS12Y*VCS12Y+VCS12Z*VCS12Z)
C  DOT DISTANCE WITH SURFACE NORMAL TO DETERMINE POS. OR NEG. DIST.
        SDIS = VCS12X*A4I+VCS12Y*A4J+VCS12Z*A4K
        PROJN = SIGN(DISPS,SDIS)
C  RECOMPUTE LOCAL COORDS
        XCOORD = 2*SPS - 1
        ECOORD = -1
        IF( DISPS .LT. 1.E-6 )THEN
          VCS12X = A4I
          VCS12Y = A4J
          VCS12Z = A4K
          DISPS = 1.
        ENDIF
        CTRCL(1) = -IFSRF
        CTRCL(2) = XCOORD
        CTRCL(3) = ECOORD
        CTRCL(4) = PROJN
        CTRCL(5) = VCS12X/DISPS
        CTRCL(6) = VCS12Y/DISPS
        CTRCL(7) = VCS12Z/DISPS
      ENDIF

C SELECT THE CLOSEST SURFACE

      IF( NINT(CTRCL(1)) .NE. 0 )THEN

C STORE CURRENT SEARCH RESULTS
        IF( ISRCHR(1,NN) .EQ. 0 )THEN
C STORE INTEGER SEARCH RESULTS
          ISRCHR(1,NN) = NINT(ABS(CTRCL(1)))
          ITYPE = 1
          IF( NINT(CTRCL(1)) .LT. 0 ) ITYPE = 2
          IF( NISR .GE. 2 ) ISRCHR(2,NN) = ITYPE
C STORE INTEGER SEARCH RESULTS
          RSRCHR(1,NN) = CTRCL(5)
          RSRCHR(2,NN) = CTRCL(6)
          RSRCHR(3,NN) = CTRCL(7)
          RSRCHR(4,NN) = CTRCL(4)
          IF( NRSR .GE. 6 ) THEN
            RSRCHR(5,NN) = CTRCL(2)
            RSRCHR(6,NN) = CTRCL(3)
          ENDIF
        ELSE
C KEEP CURRENT SEARCH RESULTS ONLY IF CLOSER
          IF( ABS(CTRCL(4)) .LT. ABS(RSRCHR(4,NN)) )THEN
C STORE INTEGER SEARCH RESULTS
            ISRCHR(1,NN) = NINT(ABS(CTRCL(1)))
            ITYPE = 1
            IF( CTRCL(1) .LT. 0 ) ITYPE = 2
            IF( NISR .GE. 2 ) ISRCHR(2,NN) = ITYPE
C STORE INTEGER SEARCH RESULTS
            RSRCHR(1,NN) = CTRCL(5)
            RSRCHR(2,NN) = CTRCL(6)
            RSRCHR(3,NN) = CTRCL(7)
            RSRCHR(4,NN) = CTRCL(4)
            IF( NRSR .GE. 6 ) THEN
              RSRCHR(5,NN) = CTRCL(2)
              RSRCHR(6,NN) = CTRCL(3)
            ENDIF
          ENDIF
        ENDIF
      ENDIF

      RETURN
      END

