C
C Program PFATUBES to modify the file 'CRT-T' with indices of triangles
C in order to enable interpolation within ray tubes formed by rays
C written by program CRTPFA.
C
C Version: 7.00
C Date: 2013, May 29
C                                                  
C Coded by Petr Bulant
C     Department of Geophysics, Charles University Prague,
C     Ke Karlovu 3, 121 16 Praha 2, Czech Republic,
C     http://sw3d.cz/staff/bulant.htm
C
C----------------------------------------------------------------------
C                                                    
C Description of data files:
C
C Input data read from the standard input device (*):
C     The data are read by the list directed input (free format) and
C     consist of a single string 'SEP':
C     'SEP'... String in apostrophes containing the name of the input
C             SEP parameter or history file with the input data.
C     No default, 'SEP' must be specified and cannot be blank.
C
C                                                     
C Input data file 'SEP':
C     File 'SEP' has the form of the
C     SEP
C     parameter file.  The parameters, which do not differ from their
C     defaults, need not be specified in file 'SEP'.
C Names of input files related to ray tracing (output of CRT):
C     CRTOUT='string'... File with the names of the output files of
C             program CRT.
C             For general description of file CRTOUT refer to file
C             writ.for.
C             Description specific to this program:
C               Just the first set of CRT output files is read from
C               file CRTOUT.  Only files
C               'CRT-R',
C               'CRT-I' and
C               'CRT-T'
C               are read.
C               File 'CRT-R' must contain all rays traced by CRT, not
C               only two-point rays.
C             Default: CRTOUT=' ' which means 'CRT-R'='r01.out',
C             'CRT-I'='r01i.out', 'CRT-T'='t01.out'
C Names of output files:
C     FTRGL1... Name of the output file with the triangles formed
C             by rays which belong each to other and thus enable
C             the interpolation within ray tubes.
C             No default, FTRGL1 must be specified
C     FTRGL2... Name of the output file with the triangles formed
C             by rays which do not belong each to other and do not
C             enable the interpolation within ray tubes.
C             No default, FTRGL2 must be specified
C Optional parameters specifying the form of the quantities
C written in the output formatted files:
C     MINDIG,MAXDIG=positive integers... See the description in file
C             forms.for.
C
C-----------------------------------------------------------------------
C
C Subroutines and external functions required:
      EXTERNAL LOWER,FORM2,LENGTH,ERROR,WARN,RSEP1,RSEP3T,
     *INDEXI,AP00,PTREAD,PTERAS,PTINDX,PTQW,PTPOLA
      INTEGER LENGTH
C     PTREAD,PTERAS,PTINDX,PTQW,PTPOLA... This file.
C     LOWER,LENGTH... File length.for.
C     ERROR,WARN... File error.for.
C     RSEP1,RSEP3T... File sep.for.
C     INDEXI... File indexi.for.
C     AP00... File ap.for.
C
C ...........................
C Common block /POINTC/ to store the results of complete ray tracing:
      INCLUDE 'pointc.inc'
C None of the storage locations of the common block are altered.
C ...........................
C Common block /PTCB/ to store the information about triangles and rays:
      INCLUDE 'pfatubes.inc'
C pfatubes.inc.
C
C.......................................................................
C
C     Auxiliary storage locations:
      INTEGER IRAY1,IRAY2,IRAY3
      INTEGER I1,I2,I3,I4,IT1,IIT1,JWAVES
      INTEGER I
      INTEGER LU0,LU1,LU2,LU3,LU4,LU5
      PARAMETER (LU0=10,LU1=1,LU2=2,LU3=3,LU4=4,LU5=5)
      REAL AUX
      CHARACTER*80 FILSEP,FILCRT,FILE1,FILE2,FILE3,CH,FTRGL1,FTRGL2
      CHARACTER*52 TXTERR
      LOGICAL LENDT
C
C-----------------------------------------------------------------------
C
C     Reading a name of the file with the input data:
      FILSEP=' '
      WRITE(*,'(A)') '+PFATUBES: Enter input filename: '
      READ(*,*) FILSEP
      IF (FILSEP.EQ.' ') THEN
C       PFATUBES-01
        CALL ERROR('PFATUBES-01: No input file specified')
C       Input file in the form of the SEP (Stanford Exploration Project)
C       parameter or history file must be specified.
C       There is no default filename.
      ENDIF
      WRITE(*,'(A)') '+PFATUBES: Reading input data.   '
C
C     Reading all the data from the SEP file into the memory:
      CALL RSEP1(LU1,FILSEP)
C
C     Reading filenames of the files with computed rays
C     and triangles:
      CALL RSEP3T('CRTOUT',FILCRT,' ')
      FILE1='r01.out'
      FILE2='r01i.out'
      FILE3='t01.out'
      IF (FILCRT.NE.' ') THEN
        OPEN (LU2,FILE=FILCRT,FORM='FORMATTED',STATUS='OLD')
        READ (LU2,*) FILE1,CH,FILE2,FILE3
        CLOSE (LU2)
      ENDIF
C
C     Opening the CRT output files:
      OPEN(LU1,FILE=FILE1,FORM='UNFORMATTED',STATUS='OLD')
      OPEN(LU2,FILE=FILE2,FORM='UNFORMATTED',STATUS='OLD')
      OPEN(LU3,FILE=FILE3,FORM='FORMATTED',STATUS='OLD')
      IRAY=0
      IWAVE=0
C
C     Reading filenames of the output files:
      CALL RSEP3T('FTRGL1',FTRGL1,' ')
      CALL RSEP3T('FTRGL2',FTRGL2,' ')
      IF ((FTRGL1.EQ.' ').OR.(FTRGL2.EQ.' ')) THEN
C       PFATUBES-02
        CALL ERROR('PFATUBES-02: No output file specified')
C       Output files FTRGL1 and FTRGL2 must be specified,
C       there is no default filename.
      ENDIF
C     Opening the output files:
      OPEN(LU4,FILE=FTRGL1)
      OPEN(LU5,FILE=FTRGL2)
C
C     Reading file with computed triangles,
C     sorting the rays in triangles:
      WRITE(*,'(A)') '+PFATUBES: Reading the file with triangles.'
      MRAMP=MRAM
      IFORM=99999
      FORMAT='(I6,I6,I6)'
      JWAVES=0
      LENDT=.FALSE.
      ISRCN =0
      IWAVEN=0
      READ(LU3,*,END=20) IRAY1,IRAY2,IRAY3
      WRITE(LU4,FORMAT) IRAY1,IRAY2,IRAY3
      WRITE(LU5,FORMAT) IRAY1,IRAY2,IRAY3
   8  CONTINUE
      NT=0
      NRAMP=0
      IRAYMI=999999
      IRAYMA=0
  10  CONTINUE
        IRAY1=0
        IRAY2=0
        IRAY3=0
        READ(LU3,*,END=20) IRAY1,IRAY2,IRAY3
        IF (IRAY1.EQ.0) THEN
C         New elementary wave:
          ISRCN =IRAY2
          IWAVEN=IRAY3
          GOTO 22
        ENDIF
        IF ((IRAY1.LE.0).OR.(IRAY2.LE.0).OR.(IRAY3.LT.0)) THEN
C         PFATUBES-03
          CALL ERROR('PFATUBES-03: Disorder in file ''CRT-T''')
C         The 'triangles' in the input file 'CRT-T' should be written
C         as three nonnegative integers (indices of rays), two of them
C         being positive (the third may equal zero in 2-D computations).
        ENDIF
        IF (IRAY1.GT.IRAYMA) IRAYMA=IRAY1
        IF (IRAY2.GT.IRAYMA) IRAYMA=IRAY2
        IF (IRAY3.GT.IRAYMA) IRAYMA=IRAY3
        IF (IRAY1.LT.IRAYMI)                    IRAYMI=IRAY1
        IF (IRAY2.LT.IRAYMI)                    IRAYMI=IRAY2
        IF ((IRAY3.NE.0).AND.(IRAY3.LT.IRAYMI)) IRAYMI=IRAY3
        IF (IRAY1.LT.IRAY2) THEN
          I=IRAY1
          IRAY1=IRAY2
          IRAY2=I
        ENDIF
        IF (IRAY2.LT.IRAY3) THEN
          I=IRAY2
          IRAY2=IRAY3
          IRAY3=I
        ENDIF
        IF (IRAY1.LT.IRAY2) THEN
          I=IRAY1
          IRAY1=IRAY2
          IRAY2=I
        ENDIF
        IF (NRAMP+6.GT.MRAMP) THEN
C         PFATUBES-04
          CALL ERROR('PFATUBES-04: Small array RAM')
        ENDIF
        NRAMP=NRAMP+1
        IRAM(NRAMP)=IRAY1
        NRAMP=NRAMP+1
        IRAM(NRAMP)=IRAY2
        NRAMP=NRAMP+1
        IRAM(NRAMP)=IRAY3
        NRAMP=NRAMP+3
        NT=NT+1
      GOTO 10
  20  CONTINUE
      LENDT=.TRUE.
      CLOSE(LU3)
  22  CONTINUE
      JWAVES=JWAVES+1
      IRAYMI=2*IRAYMI-1
      IRAYMA=2*IRAYMA
      NR=IRAYMA-IRAYMI+1
C
C     Check for the 'triangles' in case of 2D computation:
      IF (IRAM(3).EQ.0) THEN
C        DO 25, I1=9,6*NT,6
C          IF (IRAM(I1).NE.0) THEN
CC           PFATUBES-XX
C            CALL ERROR('PFATUBES-XX: Disorder in triangles.')
CC           The first 'triangle' is formed by two rays with zero
CC           instead of the third ray. This identifies 2-D calculation
CC           and all the 'triangles' should be formed by two rays and
CC           zero instead of the third ray. This is not the case of the
CC           current triangle. Check the input file 'CRT-T'.
C          ENDIF
C  25    CONTINUE
C        L3D=.FALSE.
C        L2D=.TRUE.
C       PFATUBES-05
        CALL ERROR('PFATUBES-05: 2-D calculation')
C       The first 'triangle' is formed by two rays with zero instead
C       of the third ray. This identifies 2-D calculation, which
C       is not yet coded in this program.
      ELSE
        L3D=.TRUE.
        L2D=.FALSE.
      ENDIF
C
C     Sorting the triangles:
      WRITE(*,'(A)') '+PFATUBES: Sorting the triangles.          '
      IF (NRAMP+2*NT.GT.MRAMP) THEN
C         PFATUBES-06
          CALL ERROR('PFATUBES-06: Small array RAM')
      ENDIF
      DO 30, I1=NRAMP+1,NRAMP+NT
        IRAM(I1)=IRAM((I1-NRAMP-1)*6+1)
  30  CONTINUE
      CALL INDEXI(NT,IRAM(NRAMP+1),IRAM(NRAMP+NT+1))
      DO 40, I1=NRAMP+1,NRAMP+NT
        IRAM(I1)=IRAM(I1+NT)
  40  CONTINUE
      NRAMP=NRAMP+NT
C
C
C     Forming an auxiliary array with information about when can be rays
C     erased from the memory ("deleting array"):
      IF (NRAMP+NR.GT.MRAMP) THEN
C       PFATUBES-07
        CALL ERROR('PFATUBES-07: Small array RAM')
      ENDIF
C     Marking all the rays as "not to be used":
      DO 50, I1=NRAMP+1,NRAMP+NR
        IRAM(I1)=0
  50  CONTINUE
      NRAMP=NRAMP+NR
      ORAYE=IRAYMI-1-7*NT
C     Marking rays which will be used:
C     Loop over the sorted indices of triangles:
      DO 60, I2=6*NT+1,7*NT
C       Address of the first record of the current triangle:
        I1=(IRAM(I2)-1)*6+1
C       Marking all the six rays corresponding to the triangle:
        I3=2*IRAM(I1)-1
        I4=2*IRAM(I1)
        IRAM(I3-ORAYE)=I4
        IRAM(I3+1-ORAYE)=I4
        I3=2*IRAM(I1+1)-1
        IRAM(I3-ORAYE)=I4
        IRAM(I3+1-ORAYE)=I4
        IF (IRAM(I1+2).NE.0) THEN
          I3=2*IRAM(I1+2)-1
          IRAM(I3-ORAYE)=I4
          IRAM(I3+1-ORAYE)=I4
        ENDIF
  60  CONTINUE
C
C
C     Forming an auxiliary array with information about addresses
C     of the ends of records for rays in array RAM ("addressing array"):
C     "Ray" IRAYMI-1:
      NRAMP=NRAMP+1
      IF (NRAMP.GT.MRAMP) THEN
C       PFATUBES-08
        CALL ERROR('PFATUBES-08: Small array RAM')
      ENDIF
      IRAM(NRAMP)=NRAMP+NR
C     All other rays:
      IF (NRAMP+NR.GT.MRAMP) THEN
C       PFATUBES-09
        CALL ERROR('PFATUBES-09: Small array RAM')
      ENDIF
      DO 70, I1=NRAMP+1,NRAMP+NR
        IRAM(I1)=0
  70  CONTINUE
      NRAMP=NRAMP+NR
      ORAYA=IRAYMI-1-7*NT-NR-1
C
C
C     Loop for all the triangles:
      IIT1=1
      I1=-1
  100 CONTINUE
C       Screen output:
        IT1=(IRAM(6*NT+IIT1)-1)*6+1
        I2=NINT((100.*IIT1)/(NT))
        IF (I2.NE.I1) THEN
          WRITE(*,'(''+'',79('' ''))')
          WRITE(*,'(A,1I2,A,1I4,A)')
     *    '+PFATUBES: Interpolating wave ',JWAVES,'. ',
     *                                    I2,'% of ray tubes completed.'
          I1=I2
        ENDIF
C
C       If necessary, reading new rays:
        IF
     *  (((IRAM(2*IRAM(IT1)-ORAYA+1).EQ.0).AND.(2*IRAM(IT1).NE.IRAYMA))
     *   .OR.
     *   ((IRAM(2*IRAM(IT1)-ORAYA  ).EQ.0).AND.(2*IRAM(IT1).EQ.IRAYMA)))
     *  CALL PTREAD(LU1,LU2,IT1)
C
C       Empting the array RAM to enable writing of possible interpolated
C       quantities:
        IF ((MRAMP-NRAMP).LT.(NINT(MAXRAM/10.))) CALL PTERAS
C
C       Calculating the indices of sides of the triangle:
        CALL PTINDX(IT1)
C
      IIT1=IIT1+1
      IF (IIT1.LE.NT) GOTO 100
C     End of the loop for all the triangles of the elementary wave.
C
C     Writing the resulting triangles:
      CALL PTQW(LU4,LU5)
C
      IF (.NOT.LENDT) THEN
C       Continuing with the next elementary wave:
        GOTO 8
      ENDIF
C
      CLOSE(LU1)
      CLOSE(LU2)
C
C
      WRITE(*,'(A)')
     *    '+PFATUBES: Done.                                            '
      STOP
      END
C
C
C=======================================================================
C
      SUBROUTINE PTQW(LU4,LU5)
C
C----------------------------------------------------------------------
C Subroutine to write the files with triangles of one elementary wave.
C
      INTEGER LU4,LU5
C Input:
C     LU4...  Number of logical unit corresponding to the file with
C             triangles whose rays belong each to other.
C     LU5...  Number of logical unit corresponding to the file with
C             triangles whose rays do not belong each to other.
C ...........................
C Common block /PTCB/ to store the information about triangles and rays:
      INCLUDE 'pfatubes.inc'
C pfatubes.inc.
C.......................................................................
C
C     Auxiliary storage locations:
      INTEGER II,I1,I2,I3,J1,J2,J3,IA
C
C-----------------------------------------------------------------------
C     Setting output format:
   1  CONTINUE
      IF (IRAYMA.GT.IFORM) THEN
        IFORM=IFORM*10+9
        IF (IFORM.GT.99999999) THEN
C         PFATUBES-10
          CALL ERROR('PFATUBES-10: Insufficient format for triangles')
C         Maximum space for indices of triangles is 9 positions
C         including the spaces.
        ENDIF
        FORMAT(3:3)=CHAR(ICHAR(FORMAT(3:3))+1)
        FORMAT(6:6)=FORMAT(3:3)
        FORMAT(9:9)=FORMAT(3:3)
        GOTO 1
      ENDIF
C
C     Writing the triangles of the elementary wave:
      DO 10, II=0,6*(NT-1),6
C       Indices of two sets of rays of the triangle:
        I1=IRAM(II+1)*2-1
        I2=IRAM(II+2)*2-1
        I3=IRAM(II+3)*2-1
        J1=IRAM(II+1)*2
        J2=IRAM(II+2)*2
        J3=IRAM(II+3)*2
        IF (IRAM(II+4)*IRAM(II+5)*IRAM(II+6).NE.1) THEN
C         Triangle where the rays do not belong each to other:
          WRITE(LU5,FORMAT) I1,I2,I3
          WRITE(LU5,FORMAT) J1,J2,J3
        ELSE
C         Triangle where the rays belong each to other:
          IF (IRAM(II+4).EQ.-1) THEN
            IA=I2
            I2=J2
            J2=IA
            IA=I3
            I3=J3
            J3=IA
          ENDIF
          IF (IRAM(II+5).EQ.-1) THEN
            IA=I3
            I3=J3
            J3=IA
          ENDIF
          WRITE(LU4,FORMAT) I1,I2,I3
          WRITE(LU4,FORMAT) J1,J2,J3
        ENDIF
  10  CONTINUE
C
      IF (ISRCN.NE.0) THEN
C       Writing index of the source and of the wave for the next
C       elementary wave:
        IFORM=99999
        FORMAT='(I6,I6,I6)'
        WRITE(LU4,FORMAT) 0,ISRCN,IWAVEN
        ISRCN =0
        IWAVEN=0
      ENDIF
C
      RETURN
      END
C
C
C=======================================================================
C
      SUBROUTINE PTREAD(LU1,LU2,IT1)
C
C----------------------------------------------------------------------
C Subroutine to read the unformatted output of program CRT and
C to write it into array (I)RAM.
C Reading the output files is completed by a simple invocation of
C subroutine AP00 of file 'ap.for'.
C
      INTEGER LU1,LU2,IT1
C Input:
C     LU1...  Number of logical unit corresponding to the file with
C             the quantities stored along rays.
C     LU2...  Number of logical unit corresponding to the file with
C             the quantities at the initial points of rays,
C             corresponding to file LU1.
C     IT1...  Position of the first ray of the actually processed
C             triangle in the array IRAM.
C No output.
C
C ...........................
C Common block /POINTC/ to store the results of complete ray tracing:
      INCLUDE 'pointc.inc'
C None of the storage locations of the common block are altered.
C ...........................
C Common block /PTCB/ to store the information about triangles and rays:
      INCLUDE 'pfatubes.inc'
C pfatubes.inc.
C.......................................................................
C
C     Auxiliary storage locations:
      INTEGER IRAY0,IWAVE0,I1
      CHARACTER*52 TXTERR
C     IRAY0.. Index of the last ray read in into the array RAM.
C
C-----------------------------------------------------------------------
C     Loop for the points of rays:
   10 CONTINUE
        IF ((NRAMP+2*NQ).GT.MRAMP) THEN
C         Empting the memory:
          CALL PTERAS
          IF ((NRAMP+2*NQ).GT.MRAMP) THEN
C           PFATUBES-11
            CALL ERROR('PFATUBES-11: Small array RAM')
          ENDIF
        ENDIF
C       Reading the results of the complete ray tracing:
        IRAY0=IRAY
        IWAVE0=IWAVE
        IF ((IRAY0.EQ.0).AND.(IWAVE0.EQ.0)) THEN
C         Reading the first point on a ray of the first wave:
          CALL AP00(0,LU1,LU2)
          IF (IWAVE.LT.1) GOTO 20
        ELSEIF (IWAVE.EQ.IWAVE0) THEN
C         Reading the next point on a ray of the actual wave:
          CALL AP00(0,LU1,LU2)
          IF (IWAVE.NE.IWAVE0) GOTO 20
        ENDIF
        IF (IRAY.LT.IRAYMI) GOTO 10
        IF (IRAY.GT.IRAYMA) GOTO 10
        IF ((IRAY-IRAY0).GE.2) THEN
C         Some rays skipped by AP00:
          DO 15, I1=IRAY0+1,IRAY-1
            IF (I1.GE.IRAYMI) THEN
              IRAM(I1-ORAYA)=IRAM(IRAY0-ORAYA)
            ENDIF
  15      CONTINUE
        ENDIF
        IF (IRAM(IRAY-ORAYE).NE.0) THEN
C         Writing the results of the complete ray tracing - recording
C         new point on a ray:
          IF (IPT.LE.1) THEN
            IF ((ISHEET.EQ.0).AND.(IRAY.EQ.IRAYMI)) THEN
C             PFATUBES-12
              CALL WARN
     *        ('PFATUBES-12: a ray with history 0 observed')
C             All the rays are probably of the same history 0. Only the
C             initial-value ray tracing was performed.  Width and shape
C             of ray tubes were not controlled.  The interpolation
C             in such a case makes sense only in smooth models.
C             Check the value of the parameter IPOINT in CRT input data
C             RPAR (4).
            ENDIF
C           New ray - recording the initial point:
C           Coordinates:
            RAM(NRAMP+1)=YI(3)
            RAM(NRAMP+2)=YI(4)
            RAM(NRAMP+3)=YI(5)
C           Index of surface:
            IRAM(NRAMP+4)=0
C           Sequential index of point:
            IRAM(NRAMP+5)=0
C           Complex-valued polarization vector:
            RAM(NRAMP+ 6)=0.
            RAM(NRAMP+ 7)=0.
            RAM(NRAMP+ 8)=0.
            RAM(NRAMP+ 9)=0.
            RAM(NRAMP+10)=0.
            RAM(NRAMP+11)=0.
            NRAMP=NRAMP+NQ
          ENDIF
C         Recording the new point:
C         Coordinates:
          RAM(NRAMP+1)=Y(3)
          RAM(NRAMP+2)=Y(4)
          RAM(NRAMP+3)=Y(5)
C         Index of surface:
          IRAM(NRAMP+4)=ISRF
C         Sequential index of point:
          IRAM(NRAMP+5)=IPT
C         Complex-valued polarization vector:
          CALL PTPOLA
          NRAMP=NRAMP+NQ
        ENDIF
        IRAM(IRAY-ORAYA)=NRAMP
CCC     IF ((IPT.LE.1).AND.(IRAY.GT.IRAM(IT1)).AND.(IRAY.NE.IRAYMA))
        IF ((NRAMP+2*NQ).GT.MRAMP) THEN
          IF (IRAY.LE.2*IRAM(IT1)) THEN
C           PFATUBES-13
            CALL ERROR('PFATUBES-13: Array RAM too small')
C           Reading of the rays needs to be terminated because
C           the array RAM is full, but the rays of the triangle IT1
C           were not yet read. The dimension MARAM of the array RAM
C           needs to be enlarged.
          ENDIF
          RETURN
        ENDIF
      GOTO 10
C
  20  CONTINUE
C     End of rays:
      IF (IRAY0.LT.IRAYMA) THEN
C       Some rays at the end of the CRT output file missing:
        DO 22, I1=IRAY0+1,IRAYMA
          IF (I1.GE.IRAYMI) THEN
            IRAM(I1-ORAYA)=NRAMP
          ENDIF
  22    CONTINUE
      ENDIF
      RETURN
      END
C
C
C=======================================================================
C
      SUBROUTINE PTPOLA
C
C----------------------------------------------------------------------
C Subroutine to calculate the complex-valued polarization vectors
C in the point of the ray which is currently stored in the common
C block POINTC.
C
C ...........................
C Common block /POINTC/ to store the results of complete ray tracing:
      INCLUDE 'pointc.inc'
C None of the storage locations of the common block are altered.
C ...........................
C Common block /PTCB/ to store the information about triangles and rays:
      INCLUDE 'pfatubes.inc'
C pfatubes.inc.
C.......................................................................
C
C     Auxiliary storage locations:
      REAL PR11,PI11,PR21,PI21,PR12,PI12,PR22,PI22,VAR11,VAR22,VAR12,
     *     VAI12,VAR21,VAI21,AUX,AR1,AI1,AR2,AI2,G11,G12,G13,G21,G22,
     *     G23,ER1,ER2,ER3,EI1,EI2,EI3
C
C-----------------------------------------------------------------------
      PR11=Y(28)
      PI11=Y(29)
      PR21=Y(30)
      PI21=Y(31)
      PR12=Y(32)
      PI12=Y(33)
      PR22=Y(34)
      PI22=Y(35)
      VAR11=PR11**2+PI11**2 + PR12**2+PI12**2
      VAR22=PR21**2+PI21**2 + PR22**2+PI22**2
      VAR12=PR11*PR21+PI11*PI21 + PR12*PR22+PI12*PI22
      VAI12=PI11*PR21-PR11*PI21 + PI12*PR22-PR12*PI22
      VAR21=PR21*PR11+PI21*PI11 + PR22*PR12+PI22*PI12
      VAI21=PI21*PR11-PR21*PI11 + PI22*PR12-PR22*PI12
      IF (VAR11.GE.VAR22) THEN
        AUX=1./SQRT(VAR11**2+VAR21**2+VAI21**2)
        AR1=AUX*VAR11
        AI1=0.
        AR2=AUX*VAR21
        AI2=AUX*VAI21
      ELSE
        AUX=1./SQRT(VAR22**2+VAR12**2+VAI12**2)
        AR1=AUX*VAR12
        AI1=AUX*VAI12
        AR2=AUX*VAR22
        AI2=0.
      ENDIF
      IF (NPV.LT.6) THEN
C       PFATUBES-14
        CALL ERROR('PFATUBES-14: Missing polarization vectors')
C       The S-vave reference polarization vectors need to be defined.
      ENDIF
      G11=PV(1)
      G12=PV(2)
      G13=PV(3)
      G21=PV(4)
      G22=PV(5)
      G23=PV(6)
      ER1=G11*AR1+G21*AR2
      ER2=G12*AR1+G22*AR2
      ER3=G13*AR1+G23*AR2
      EI1=G11*AI1+G21*AI2
      EI2=G12*AI1+G22*AI2
      EI3=G13*AI1+G23*AI2
      RAM(NRAMP+ 6)=ER1
      RAM(NRAMP+ 7)=EI1
      RAM(NRAMP+ 8)=ER2
      RAM(NRAMP+ 9)=EI2
      RAM(NRAMP+10)=ER3
      RAM(NRAMP+11)=EI3
      RETURN
      END
C
C
C=======================================================================
C
      SUBROUTINE PTERAS
C
C----------------------------------------------------------------------
C Subroutine for empting the array (I)RAM. All the parameters
C of all the rays, which will no more be used, are erased.
C
C No input.
C No output.
C
C ...........................
C Common block /POINTC/ to store the results of complete ray tracing:
      INCLUDE 'pointc.inc'
C     IRAY... Index of the ray being actually read in by CIREAD.
C             This procedure supposes, that any ray with higher
C             index than IRAY was not read in.
C None of the storage locations of the common block are altered.
C ...........................
C Common block /PTCB/ to store the information about triangles and rays:
      INCLUDE 'pfatubes.inc'
C pfatubes.inc.
C.......................................................................
C     Auxiliary storage locations:
      INTEGER I1,I2,J1
      INTEGER IADDRP
C     I1...   Controls main loop over rays.
C     I2...   Controls the loop over parameters of ray I1.
C     J1...   address of the last used record of array RAM.
C
C-----------------------------------------------------------------------
C     PFATUBES-15
      CALL ERROR('PFATUBES-15: PTERAS called')
C     This subroutine is not yet debugged.
      J1=IRAM(IRAYMI-1-ORAYA)
      IADDRP=J1
C     Loop for the rays:
      DO 20, I1=IRAYMI,IRAY
        IF (IRAM(I1-ORAYE).GE.(IRAY-1)) THEN
C         This ray is not to be erased:
          DO 10, I2=IADDRP+1,IRAM(I1-ORAYA)
            J1=J1+1
            IRAM(J1)=IRAM(I2)
   10     CONTINUE
        ELSE
C         This ray is to be erased:
          IRAM(I1-ORAYE)=0
        ENDIF
        IADDRP=IRAM(I1-ORAYA)
        IRAM(I1-ORAYA)=J1
   20 CONTINUE
      NRAMP=J1
      RETURN
      END
C=======================================================================
C
      SUBROUTINE PTINDX(IT1)
C
C----------------------------------------------------------------------
C Subroutine for calculation of indices of sides of the triangle
C
      INTEGER IT1
C Input:
C     IT1...  The address of the index of the first ray of the triangle,
C             for which the indices of sides are to be computed.
C No output.
C
C ...........................
      EXTERNAL PTLCOS
      LOGICAL PTLCOS
C ...........................
C Common block /PTCB/ to store the information about triangles and rays:
      INCLUDE 'pfatubes.inc'
C pfatubes.inc.
C.......................................................................
C     Auxiliary storage locations:
      INTEGER I1B,I2B,I3B,I1C,I2C,I3C,J1B,J2B,J3B,J1C,J2C,J3C
      INTEGER I1MA,I2MA,I3MA,J1,J2,ISID1,ISID2,ISID3
      LOGICAL LFIRST,LI1I2,LJ1J2,LI1J2,LJ1I2
C     I1B,I2B,I3B,I1C,I2C,I3C... Integers controling main loop over
C             points on the rays (along ray tube). Numbers 1,2,3 denote
C             the first, second and third ray, character B denotes
C             bottom of the ray cell and C denotes top of the ray cell.
C             Each integer contains the address just before
C             the parameters of the corresponding point:
C             the first parameter of the first point: RAM(I1B+1)
C     J1...   Counts the number of identical points of the ray cell
C             (J1=0,1,2,3).
C     J2...   Displays maximum sequential index of a point allowed
C             for actual ray cell.
C
C-----------------------------------------------------------------------
      IF (         (IRAM(2*IRAM(IT1  )-1-ORAYA).EQ.0) .OR.
     *             (IRAM(2*IRAM(IT1  )  -ORAYA).EQ.0) .OR.
     *             (IRAM(2*IRAM(IT1+1)-1-ORAYA).EQ.0) .OR.
     *             (IRAM(2*IRAM(IT1+1)  -ORAYA).EQ.0) .OR.
     *    (L3D.AND.(IRAM(2*IRAM(IT1+2)-1-ORAYA).EQ.0)).OR.
     *    (L3D.AND.(IRAM(2*IRAM(IT1+2)  -ORAYA).EQ.0))) THEN
C       PFATUBES-16
        CALL ERROR
     *     ('PFATUBES-16: Parameters of a ray not found in memory')
C       This error may be caused by wrong file CRT-R with
C       missing ray(s) (e.g. only two-point rays stored).
      ENDIF
C
      I1MA=IRAM(2*IRAM(IT1  )-ORAYA)-NQ
      I2MA=IRAM(2*IRAM(IT1+1)-ORAYA)-NQ
      IF (L3D) I3MA=IRAM(2*IRAM(IT1+2)-ORAYA)-NQ
C     The first ray cell:
      I1B=IRAM(2*IRAM(IT1  )-ORAYA-1)
      I2B=IRAM(2*IRAM(IT1+1)-ORAYA-1)
      IF (L3D) I3B=IRAM(2*IRAM(IT1+2)-ORAYA-1)
      J1B=IRAM(2*IRAM(IT1  )-1-ORAYA-1)
      J2B=IRAM(2*IRAM(IT1+1)-1-ORAYA-1)
      IF (L3D) J3B=IRAM(2*IRAM(IT1+2)-1-ORAYA-1)
      IF ((I1B.GT.I1MA).OR.(I2B.GT.I2MA).OR.(L3D.AND.(I3B.GT.I3MA)))
     *  RETURN
      I1C=I1B
      I2C=I2B
      IF (L3D) I3C=I3B
      J1C=J1B
      J2C=J2B
      IF (L3D) J3C=J3B
      LFIRST=.TRUE.
      ISID1=1
      ISID2=1
      ISID3=1
C     Loop for points on the rays (loop for ray cells):
C     J1 counts the number of points, which were not shifted.
C     J2 displays the sequential number of points, which is the
C        maximum allowed number for current cell.
  10  CONTINUE
        IF (L3D) THEN
          J1=3
          J2=MAX0(IRAM(I1B+5),IRAM(I2B+5),IRAM(I3B+5))
          IF ((IRAM(I1B+5).EQ.IRAM(I2B+5)).AND.
     *        (IRAM(I1B+5).EQ.IRAM(I3B+5)))  J2=J2+1
        ELSE
          J1=2
          J2=MAX0(IRAM(I1B+5),IRAM(I2B+5))
          IF (IRAM(I1B+5).EQ.IRAM(I2B+5))  J2=J2+1
        ENDIF
C       Forming standard ray cells:
        IF ((IRAM(I1B+4).EQ.0).AND.(IRAM(I1B+5).LT.J2)) THEN
          I1C=I1B+NQ
          J1C=J1B+NQ
          J1=J1-1
        ENDIF
        IF ((IRAM(I2B+4).EQ.0).AND.(IRAM(I2B+5).LT.J2)) THEN
          I2C=I2B+NQ
          J2C=J2B+NQ
          J1=J1-1
        ENDIF
        IF (L3D) THEN
          IF ((IRAM(I3B+4).EQ.0).AND.(IRAM(I3B+5).LT.J2)) THEN
            I3C=I3B+NQ
            J3C=J3B+NQ
            J1=J1-1
          ENDIF
        ENDIF
        IF ((L3D.AND.(J1.EQ.3)).OR.(L2D.AND.(J1.EQ.2))) THEN
          IF (L3D.AND.(IRAM(I1B+4).EQ.IRAM(I2B+4)).AND.
     *                (IRAM(I1B+4).EQ.IRAM(I3B+4))) THEN
C           Crossing the interface in 3D:
            I1B=I1B+NQ
            I2B=I2B+NQ
            I3B=I3B+NQ
            J1B=J1B+NQ
            J2B=J2B+NQ
            J3B=J3B+NQ
            J1=0
            IF ((I1B.GT.I1MA).OR.(I2B.GT.I2MA).OR.(I3B.GT.I3MA))
     *        RETURN
            IRAM(I1B+4)=0
            IRAM(I2B+4)=0
            IRAM(I3B+4)=0
            IRAM(J1B+4)=0
            IRAM(J2B+4)=0
            IRAM(J3B+4)=0
            I1C=I1B
            I2C=I2B
            I3C=I3B
            J1C=J1B
            J2C=J2B
            J3C=J3B
CCC         GOTO 10
          ELSEIF (L2D.AND.(IRAM(I1B+4).EQ.IRAM(I2B+4))) THEN
C           Crossing the interface in 2D:
            I1B=I1B+NQ
            I2B=I2B+NQ
            J1B=J1B+NQ
            J2B=J2B+NQ
            J1=0
            IF ((I1B.GT.I1MA).OR.(I2B.GT.I2MA))
     *        RETURN
            IRAM(I1B+4)=0
            IRAM(I2B+4)=0
            IRAM(J1B+4)=0
            IRAM(J2B+4)=0
            I1C=I1B
            I2C=I2B
            J1C=J1B
            J2C=J2B
CCC         GOTO 10
          ELSE
C           Moving the points in a complex block:
C           Forming standard ray cells:
            IF (IRAM(I1B+4).EQ.0) THEN
              I1C=I1B+NQ
              J1C=J1B+NQ
              J1=J1-1
            ENDIF
            IF (IRAM(I2B+4).EQ.0) THEN
              I2C=I2B+NQ
              J2C=J2B+NQ
              J1=J1-1
            ENDIF
            IF (L3D) THEN
              IF (IRAM(I3B+4).EQ.0) THEN
                I3C=I3B+NQ
                J3C=J3B+NQ
                J1=J1-1
              ENDIF
            ENDIF
            IF ((L3D.AND.(J1.EQ.3)).OR.(L2D.AND.(J1.EQ.2))) THEN
              IF ((I1B.GE.I1MA).AND.(I2B.GE.I2MA).AND.(I3B.GE.I3MA).AND.
     *            L3D) RETURN
              IF ((I1B.GE.I1MA).AND.(I2B.GE.I2MA).AND.L2D) RETURN
C             PFATUBES-17
              CALL ERROR
     *        ('PFATUBES-17: The points reached different interfaces')
C             This error should not appear.
C             Please contact the author.
            ENDIF
          ENDIF
        ENDIF
        IF ((I1C.GT.I1MA).OR.(I2C.GT.I2MA).OR.
     *      (L3D.AND.(I3C.GT.I3MA))) THEN
C         PFATUBES-18
          CALL ERROR('PFATUBES-18: point exceeded the ray.')
C         This error should not appear.
C         Please contact the author.
        ENDIF
C
C       The ray cell whose top is formed by points, whose parameters
C       can be found just behind the addresses I1C,I2C,I3C,J1C,J2C,J3C
C       is prepared for comparison of polarization vectors:
        IF (L2D) THEN
C         2-D case:
C         PFATUBES-19
          CALL ERROR('PFATUBES-19: 2-D calculation')
C         Not yet coded.
        ENDIF
        IF (L3D) THEN
C         Comparison of polarization vectors:
          IF (ISID1.NE.0) THEN
C           First side:
            LI1I2=PTLCOS(I1C,I2C)
            LJ1J2=PTLCOS(J1C,J2C)
            LI1J2=PTLCOS(I1C,J2C)
            LJ1I2=PTLCOS(J1C,I2C)
            IF     (LI1I2.AND.LJ1J2.AND.
     *              (.NOT.LI1J2).AND.(.NOT.LJ1I2)) THEN
              ISID1=1
            ELSEIF (LI1J2.AND.LJ1I2.AND.
     *              (.NOT.LI1I2).AND.(.NOT.LJ1J2)) THEN
              ISID1=-1
            ELSE
              ISID1=0
            ENDIF
          ENDIF
          IF (ISID2.NE.0) THEN
C           Second side:
            LI1I2=PTLCOS(I2C,I3C)
            LJ1J2=PTLCOS(J2C,J3C)
            LI1J2=PTLCOS(I2C,J3C)
            LJ1I2=PTLCOS(J2C,I3C)
            IF     (LI1I2.AND.LJ1J2.AND.
     *              (.NOT.LI1J2).AND.(.NOT.LJ1I2)) THEN
              ISID2=1
            ELSEIF (LI1J2.AND.LJ1I2.AND.
     *              (.NOT.LI1I2).AND.(.NOT.LJ1J2)) THEN
              ISID2=-1
            ELSE
              ISID2=0
            ENDIF
          ENDIF
          IF (ISID3.NE.0) THEN
C           Third side:
            LI1I2=PTLCOS(I3C,I1C)
            LJ1J2=PTLCOS(J3C,J1C)
            LI1J2=PTLCOS(I3C,J1C)
            LJ1I2=PTLCOS(J3C,I1C)
            IF     (LI1I2.AND.LJ1J2.AND.
     *              (.NOT.LI1J2).AND.(.NOT.LJ1I2)) THEN
              ISID3=1
            ELSEIF (LI1J2.AND.LJ1I2.AND.
     *              (.NOT.LI1I2).AND.(.NOT.LJ1J2)) THEN
              ISID3=-1
            ELSE
              ISID3=0
            ENDIF
          ENDIF
          IF (LFIRST) THEN
C           First points of the ray tube:
            IRAM(IT1+3)=ISID1
            IRAM(IT1+4)=ISID2
            IRAM(IT1+5)=ISID3
            LFIRST=.FALSE.
          ELSE
C           Other than the first points of the ray tube:
            IF (IRAM(IT1+3).NE.ISID1) THEN
              ISID1=0
              IRAM(IT1+3)=ISID1
            ENDIF
            IF (IRAM(IT1+4).NE.ISID2) THEN
              ISID2=0
              IRAM(IT1+4)=ISID2
            ENDIF
            IF (IRAM(IT1+5).NE.ISID3) THEN
              ISID3=0
              IRAM(IT1+5)=ISID3
            ENDIF
          ENDIF
          IF ((ISID1.EQ.0).AND.(ISID2.EQ.0).AND.(ISID3.EQ.0)) THEN
C           All sides formed by rays which do not belong each to other:
            RETURN
          ENDIF
        ENDIF
C       Continuing with the next ray cell:
        I1B=I1C
        I2B=I2C
        IF (L3D) I3B=I3C
        J1B=J1C
        J2B=J2C
        IF (L3D) J3B=J3C
      GOTO 10
C     End of the loop along the ray tube.
      END
C
C=======================================================================
C
      LOGICAL FUNCTION PTLCOS(IP1,IP2)
C
C----------------------------------------------------------------------
      INTEGER IP1,IP2
C     Subroutine to calculate cosinus of the angle of the
C     polarization vectors of two pints on the rays, and to decide
C     whether the two rays belong together or not.
C
C Input:
C     IP1,IP2 ... Addresses of the two points on the rays in array RAM.
C Output:
C     PTLCOS ... .TRUE. if the points belong each to other
C                .FALSE. otherwise
C ...........................
C Common block /PTCB/ to store the information about triangles and rays:
      INCLUDE 'pfatubes.inc'
C pfatubes.inc.
C.......................................................................
C     Auxiliary storage locations:
      REAL E1R1,E1I1,E1R2,E1I2,E1R3,E1I3,E2R1,E2I1,E2R2,E2I2,E2R3,E2I3,
     *     AUX1,AUX2,COSFI2
C     E1R1... First polarization vector, real part, first component
C     E2I3... Second polariz. vector, imaginary part, third component
C-----------------------------------------------------------------------
      E1R1=RAM(IP1+ 6)
      E1I1=RAM(IP1+ 7)
      E1R2=RAM(IP1+ 8)
      E1I2=RAM(IP1+ 9)
      E1R3=RAM(IP1+10)
      E1I3=RAM(IP1+11)
      E2R1=RAM(IP2+ 6)
      E2I1=RAM(IP2+ 7)
      E2R2=RAM(IP2+ 8)
      E2I2=RAM(IP2+ 9)
      E2R3=RAM(IP2+10)
      E2I3=RAM(IP2+11)
      AUX1=E1R1*E2R1+E1R2*E2R2+E1R3*E2R3+
     *     E1I1*E2I1+E1I2*E2I2+E1I3*E2I3
      AUX2=E1R1*E2I1+E1R2*E2I2+E1R3*E2I3-
     *    (E1I1*E2R1+E1I2*E2R2+E1I3*E2R3)
      COSFI2=AUX1**2+AUX2**2
      IF (COSFI2.GT.0.5) THEN
        PTLCOS=.TRUE.
      ELSE
        PTLCOS=.FALSE.
      ENDIF
      RETURN
      END
C
C=======================================================================
C
      INCLUDE 'error.for'
C     error.for
      INCLUDE 'ap.for'
C     ap.for
      INCLUDE 'forms.for'
C     forms.for
      INCLUDE 'length.for'
C     length.for
      INCLUDE 'sep.for'
C     sep.for
      INCLUDE 'indexi.for'
C     indexi.for.
C
C=======================================================================
C