C
C Subroutine file 'mat.for' with subroutines dealing with matrices.
C
C Version: 6.10
C Date: 2007, June 7
C
C.......................................................................
C
C This file consists of the following external procedures:
C     WMATH.. Subroutine designed to write a matrix header file.
C             WMATH
C     RMATH.. Subroutine designed to read a matrix header file.
C             RMATH
C     WMATD.. Subroutine designed to write a matrix data file.
C             WMATD
C     RMATD.. Subroutine designed to read a matrix data file.
C             RMATD
C     WMATR.. Auxiliary subroutine to WMATD, designed to write the array
C             of matrix elements into a file.
C             WMATR
C     TMATR...Subroutine to transpose a matrix.
C             TMATR
C     SMATRE..Subroutine to extend sparse symmetric or antisymmetric
C             matrix into sparse general matrix.
C             SMATRE
C     SMATR...Subroutine to reorganize sparse matrix in the memory from
C             the form "as on a disk" to the form "as in the memory"
C             or back.
C             SMATR
C     RAMATR..Subroutine to reorganize indices and values of elements
C             of sparse matrix in the memory from the form "as on
C             a disk" to the form "as in the memory" or back.
C             Auxiliary subroutine to SMATR.
C             RAMATR
C     GSMATR..Subroutine to change normal (not sparse) matrix into
C             the sparse matrix.
C             GSMATR
C     SGMATR..Subroutine to change sparse matrix into the normal
C             (not sparse) matrix.
C             SGMATR
C     GSMAT...Subroutine to change normal (not sparse) matrix into
C             the sparse matrix if the matrix is sparser than given
C             limit.
C             GSMAT
C     NELMAT..Integer function to calculate total number of elements
C             of a non-sparse matrix.
C             NELMAT
C     NSPMAT..Integer function to calculate number of zero elements
C             of a non-sparse matrix.
C             NSPMAT
C     ISYM ...Integer function to assign the integer corresponding
C             to the symmetry.
C             ISYM
C     MSHIFT..Subroutine designed to shift the matrix in memory.
C             MSHIFT
C Subroutines to enable functionality of some programs which
C do not use above subroutines directly:
C     OMAT... Subroutine designed to set the form of the file for
C             reading or writing a matrix, and to open the file.
C             OMAT
C     WMAT... Subroutine designed to write a given matrix into the given
C             file.
C             WMAT
C     RMAT... Subroutine designed to read a matrix from the given file.
C             RMAT
C
C=======================================================================
C                                                     
C Storage of the matrices in the memory:
C     Normal (not sparse) matrices:
C             Normal matrices are usually identified by the value of
C             NSPAR=-1.   For normal matrices all the values
C             of the matrix are stored columnwise, starting with
C             from the first value of the first column to the last value
C             of the first column, then the second column, and so on
C             to the value of the last element of the last column.
C             If the matrix is other than general, only the elements
C             corresponding to the given symmetry are stored, e.g. for
C             diagonal matrix only the values of the diagonal elements
C             are stored.
C     Sparse matrices:
C             Sparse matrices are usually identified by the value of
C             NSPAR nonnegative. NSPAR is then the number of zero
C             elements of the matrix, NSPAR=0 means that the matrix
C             is stored as sparse, but it has all elements nonzero.
C             There are two forms of storage of the sparse matrices,
C             described usually by parameter ISTOR:
C       ISTOR=0 ... form "as on a disk": in this form the first NN
C             storage locations of the matrix contain matrix indices
C             of the nonzero elements of the matrix written in integer
C             array. Matrix index of an element of a matrix is
C             the sequence number, in which the element would be written
C             in the general matrix.  This means that the matrix index
C             is influenced only by the number of rows and of columns
C             of the matrix, not by the symmetry of the matrix.
C             The next NN storage locations contain the values of the
C             nonzero elements of the matrix written in real array.
C             In this form the matrix occupies 2*NN storage locations.
C       ISTOR=1 ... form "as in the memory": in this form the first
C             storage location contains the address in the array
C             just before the first nonzero element, this address
C             may be understood as the address of the end of column
C             number zero.  Next M2 storage locations contain
C             the addresses of the ends of all the columns
C             of the matrix.  The nonzero elements of column J
C             of the matrix are thus stored in
C             ARRAY(IARRAY(OARRAY+J-1)+1) to ARRAY(IARRAY(OARRAY+J)),
C             where OARRAY is the address of the first storage location
C             of the matrix.  Next 2*NN storage locations contain the
C             nonzero elements of the matrix stored columnwise. Each
C             element occupies two storage locations, the first one
C             containing index of the row of the element written
C             in the integer array, the second one containing the value
C             of the element written in the real array.  In this form
C             the matrix occupies 1+M2+2*NN storage locations.
C
C For detailed description of the forms of the files with matrices
C and of the parameters describing the matrices
C refer to file forms.htm.
C
C=======================================================================
C
C     
C
      SUBROUTINE WMATH(LU,FILEH,FILED,M1,M2,NSPARS,SYMM,FORM)
      INTEGER LU,M1,M2,NSPARS
      CHARACTER*(*) FILEH,FILED,SYMM,FORM
C
C Subroutine designed to write the matrix header file.
C
C Input:
C     LU...   Logical unit number of the matrix header output file.
C             The output matrix header file is opened, written, and
C             closed.
C     FILEH.. String containing the name of the matrix header file.
C             The matrix header file has the form of the SEP parameter
C             file.
C             If FILEH=' ', no action is done.
C     FILED.. String containing the name of the matrix data file.
C             If FILED=' ', default filename is determined and returned.
C     M1...   Number of rows of the matrix.
C     M2...   Number of columns of the matrix.
C     NSPARS... Sparseness of the matrix data file:
C             NSPARS.LT.0: Matrix is stored element by element.
C             NSPARS.GE.0: Matrix is stored as a sparse matrix.
C               NSPARS is the number of zero matrix elements.
C     SYMM... Symmetry of the matrix data file:
C             SYMMETRY=' ': General matrix.
C             SYMMETRY='sym': Symmetric matrix.
C             SYMMETRY='skew': Skew matrix.
C             SYMMETRY='diag': Diagonal matrix.
C     FORM... Form of the matrix data file:
C             FORM='formatted': Formatted file.
C             FORM='unformatted': Unformatted file.
C             If FORM=' ', default FORM is determined and returned.
C
C Output:
C     FILED.. If FILED=' ' on input, default filename is determined
C             and returned.
C             Otherwise, the input value of FILED is returned.
C     FORM... If FORM=' ' on input, default FORM for writing
C             is determined and returned.
C             Otherwise, the input value of FORM is converted to
C             lowercase and returned.
C
C Subroutines and external functions required:
      EXTERNAL LENGTH,LOWER,WSEP3I,WSEP3T,RSEP3T
      INTEGER  LENGTH
C     LENGTH,LOWER... File 'length.for'.
C     WSEP3I,WSEP3T,RSEP3T... File 'sep.for'.
C
C Coded by Ludek Klimes and Petr Bulant
C
C-----------------------------------------------------------------------
C
      INTEGER L
      CHARACTER*72 TXTERR
C
      IF(FILEH.EQ.' ') THEN
        RETURN
      END IF
C
C     Opening the matrix header file:
      OPEN(LU,FILE=FILEH,ERR=100)
C
C     Default data file name:
      IF(FILED.EQ.' ') THEN
        L=LENGTH(FILEH)
        IF (L.GE.4) THEN
          IF (FILEH(L-3:L-3).EQ.'.') THEN
            L=L-1
          ENDIF
        ENDIF
        L=L+1
        FILED=FILEH
        FILED(L:L)='@'
      END IF
C
C     Default form of the data file:
      IF(FORM.EQ.' ') THEN
        CALL RSEP3T('FORMM',FORM,'formatted')
        CALL LOWER(FORM)
      END IF
      IF (FORM.NE.'formatted'.AND.FORM.NE.'unformatted') THEN
C       MAT-01
        CALL ERROR('MAT-01: Wrong value of FORMM.')
C       Input parameter FORMM, if specified,
C       must equal either 'formatted' or 'unformatted'.
      ENDIF
C
C     Writing the values of the parameters describing the output matrix:
      CALL WSEP3T(LU,'IN',FILED)
      CALL WSEP3I(LU,'M1',M1)
      CALL WSEP3I(LU,'M2',M2)
      CALL WSEP3I(LU,'SPARSE',NSPARS)
      CALL WSEP3T(LU,'SYMMETRY',SYMM)
      CALL WSEP3T(LU,'FORM',FORM)
C
      CLOSE(LU)
      RETURN
  100 CONTINUE
C     MAT-27
      WRITE(TXTERR,'(A,A,A)') 'MAT-27: Error when opening file ''',
     *FILEH(1:MIN0(LENGTH(FILEH),37)),'''.'
      CALL ERROR(TXTERR)
      END
C
C=======================================================================
C
C     
C
      SUBROUTINE RMATH(LU,FILEH,FILED,M1,M2,NSPARS,SYMM,FORM,NELEM)
      INTEGER LU,M1,M2,NSPARS,NELEM
      CHARACTER*(*) FILEH,FILED,SYMM,FORM
C
C Subroutine designed to read the matrix header file.
C
C Input:
C     LU...   Logical unit number of the input matrix header file.
C             The input matrix header file is opened, read, and
C             closed.
C     FILEH.. String containing the name of the matrix header file.
C             The matrix header file has the form of the SEP parameter
C             file.
C             If FILEH=' ', no file is read and defaults are returned.
C The input parameters are not altered.
C
C Output:
C     FILED.. String containing the name of the matrix data file.
C     M1...   Number of rows of the matrix.
C     M2...   Number of columns of the matrix.
C     NSPARS... Sparseness of the matrix data file:
C             NSPARS.LT.0: Matrix is stored element by element.
C             NSPARS.GE.0: Matrix is stored as a sparse matrix.
C               NSPARS is the number of zero matrix elements.
C     SYMM... Symmetry of the matrix data file:
C             SYMMETRY=' ': General matrix.
C             SYMMETRY='sym': Symmetric matrix.
C             SYMMETRY='skew': Skew matrix.
C             SYMMETRY='diag': Diagonal matrix.
C     FORM... Form of the matrix data file:
C             FORM='formatted': Formatted file.
C             FORM='unformatted': Unformatted file.
C     NELEM.. Number of elements of the matrix.
C
C Subroutines and external functions required:
      EXTERNAL LENGTH,SSEP,RSEP1,RSEP3I,RSEP3T,ISYM,NELMAT
      INTEGER  LENGTH,ISYM,NELMAT
C     LENGTH... File 'length.for'.
C     SSEP,RSEP1,RSEP3I,RSEP3T... File 'sep.for'.
C
C Coded by Ludek Klimes and Petr Bulant
C
C-----------------------------------------------------------------------
C
      CHARACTER*80 FILEDD
      INTEGER L,ISYMM
C
C     Number of SEP parameter sets (NSEP=1 is the input history file):
      INTEGER NSEP
      SAVE NSEP
      DATA NSEP/1/
C
C     Switching to a new parameter set and reading the matrix header:
      NSEP=NSEP+1
      CALL SSEP(NSEP)
      CALL RSEP1(LU,FILEH)
C
C     Reading the values of the parameters describing the input matrix:
      L=LENGTH(FILEH)
      IF (L.GE.4) THEN
        IF (FILEH(L-3:L-3).EQ.'.') THEN
          L=L-1
        ENDIF
      ENDIF
      L=L+1
      FILEDD=FILEH
      FILEDD(L:L)='@'
      CALL RSEP3T('IN',FILED,FILEDD)
      CALL RSEP3I('M1',M1,1)
      CALL RSEP3I('M2',M2,1)
      CALL RSEP3I('SPARSE',NSPARS,-1)
      CALL RSEP3T('SYMMETRY',SYMM,' ')
      CALL RSEP3T('FORM',FORM,'formatted')
C
C     Converting input strings to lowercase:
      CALL LOWER(SYMM)
      CALL LOWER(FORM)
C
C     Number NELEM of stored matrix elements:
      ISYMM=ISYM(SYMM)
      NELEM=NELMAT(M1,M2,ISYMM)
      IF (NSPARS.GE.0) NELEM=NELEM-NSPARS
C
      CALL SSEP(1)
      RETURN
      END
C
C=======================================================================
C
C     
C
      SUBROUTINE WMATD(LU,FILED,NSPARS,FORM,NELEM,IARRAY,ARRAY)
      CHARACTER*(*) FILED,FORM
      INTEGER LU,NSPARS,NELEM,IARRAY(*)
      REAL ARRAY(*)
C
C Subroutine designed to write a given matrix into the matrix data file.
C
C Input:
C     LU...   Logical unit number to be used for the output.
C     FILED...Destination filename.  If not blank, the file will be
C             opened and closed.  If blank, the file is assumed to be
C             already open, and will not be closed in this subroutine.
C     NSPARS... Sparseness of the matrix data file:
C             NSPARS.LT.0: Matrix is stored element by element.
C             NSPARS.GE.0: Matrix is stored as a sparse matrix.
C               NSPARS is the number of zero matrix elements.
C     FORM... Form of the matrix data file:
C             FORM='formatted': Formatted file.
C             FORM='unformatted': Unformatted file.
C     NELEM.. Number of elements of the matrix.
C     IARRAY..Indices of the non-zero matrix elements if the matrix is
C             to be stored as a sparse matrix.
C             The matrix elements are indexed from 1 to N.  For N refer
C             to the description of argument ARRAY below.
C             The number of non-zero matrix elements is NELEM=N-NSPARS.
C             Integer array IARRAY is not used if NSPARS.LT.0.
C     ARRAY.. Elements of the given matrix stored columnwise.
C             For NSPARS.LT.0, all N matrix elements will be stored:
C               For a general matrix, ARRAY has N=M1*M2 components.
C               For a symmetric matrix, just elements from the first row
C                 to the diagonal are stored for each column, i.e.,
C                 ARRAY has N=M1*(M1+1)/2 components.
C               For a skew matrix, just elements above the diagonal are
C                 stored for each column, i.e., ARRAY has N=M1*(M1-1)/2
C                 components.
C               For a diagonal matrix, just N=M1 diagonal elements are
C                 to be stored.
C             For NSPARS.GE.0, NELEM=N-NSPARS indices of non-zero matrix
C               elements from IARRAY, and the corresponding NELEM
C               matrix elements from ARRAY will be stored.
C               The matrix elements are assumed to be located in array
C               ARRAY in the positions from ARRAY(NELEM+1) to
C               ARRAY(NELEM+NELEM).
C
C No output.
C
C Subroutines and external functions required:
      EXTERNAL LENGTH,LOWER,WARRAI,WMATR
C     LENGTH,LOWER... File 'length.for'.
C
C Coded by Ludek Klimes and Petr Bulant
C
C-----------------------------------------------------------------------
C
C     Local storage locations:
      INTEGER N,O
      CHARACTER*72 TXTERR
C     N...    Number of matrix elements to be stored.
C     O...    Position of the first matrix element in ARRAY.
C
C.......................................................................
C
C     Form of the file with the matrix, opening the file:
      IF(FILED.NE.' ') THEN
        WRITE(*,'(2A)') '+Writing: ',FILED(1:MIN0(LENGTH(FILED),70))
        OPEN(LU,FILE=FILED,FORM=FORM,ERR=100)
      END IF
C
      N=NELEM
C
C     Writing the matrix:
      O=1
      IF(NSPARS.GE.0) THEN
        CALL WARRAI(LU,' ',FORM,.FALSE.,0,.FALSE.,0,N,IARRAY)
        O=N+1
      END IF
      CALL WMATR(LU,FORM,N,ARRAY(O))
C
C     Closing output file:
      IF(FILED.NE.' ') THEN
        CLOSE(LU)
        WRITE(*,'(1A)')
     *  '+                                                             '
      END IF
      RETURN
  100 CONTINUE
C     MAT-28
      WRITE(TXTERR,'(A,A,A)') 'MAT-28: Error when opening file ''',
     *FILED(1:MIN0(LENGTH(FILED),37)),'''.'
      CALL ERROR(TXTERR)
      END
C
C=======================================================================
C
C     
C
      SUBROUTINE RMATD(LU,FILED,NSPARS,FORM,NELEM,IARRAY,ARRAY)
      CHARACTER*(*) FILED,FORM
      INTEGER LU,NSPARS,NELEM,IARRAY(*)
      REAL ARRAY(*)
C
C Subroutine designed to read a matrix from the matrix data file.
C
C Input:
C     LU...   Logical unit number to be used for the input.
C     FILED...Name of the matrix data file.  If not blank, the file will
C             be opened and closed.  If blank, the file is assumed to be
C             already open, and will not be closed in this subroutine.
C     NSPARS... Sparseness of the matrix data file:
C             NSPARS.LT.0: Matrix is stored element by element.
C             NSPARS.GE.0: Matrix is stored as a sparse matrix.
C               NSPARS is the number of zero matrix elements.
C     FORM... Form of the matrix data file:
C             FORM='formatted': Formatted file.
C             FORM='unformatted': Unformatted file.
C     NELEM.. Number of elements of the matrix.
C
C Output:
C     IARRAY..Indices of the non-zero matrix elements if the matrix is
C             stored as a sparse matrix.
C             The matrix elements are indexed from 1 to N.  For N refer
C             to the description of argument ARRAY below.
C             The number of non-zero matrix elements is NELEM=N-NSPARS.
C             Integer array IARRAY is not used if NSPARS.LT.0.
C     ARRAY.. Elements of the given matrix stored columnwise.
C             For NSPARS.LT.0, all N matrix elements are stored:
C               For a general matrix, ARRAY has N=M1*M2 components.
C               For a symmetric matrix, just elements from the first row
C                 to the diagonal are stored for each column, i.e.,
C                 ARRAY has N=M1*(M1+1)/2 components.
C               For a skew matrix, just elements above the diagonal are
C                 stored for each column, i.e., ARRAY has N=M1*(M1-1)/2
C                 components.
C               For a diagonal matrix, just N=M1 diagonal elements are
C                 stored.
C             For NSPARS.GE.0, NELEM=N-NSPARS indices of non-zero matrix
C               elements are read to the array IARRAY, and the
C               corresponding NELEM matrix elements are read to
C               the array ARRAY. The matrix elements are read in array
C               ARRAY into the positions from ARRAY(NELEM+1) to
C               ARRAY(NELEM+NELEM).
C
C Subroutines and external functions required:
      EXTERNAL LENGTH,LOWER,RARRAI,RARRAY
C     LENGTH,LOWER... File 'length.for'.
C
C Coded by Ludek Klimes and Petr Bulant
C
C-----------------------------------------------------------------------
C
C     Local storage locations:
      INTEGER N,O
      CHARACTER*72 TXTERR
C     N...    Number of stored matrix elements.
C     O...    Position of the first matrix element in ARRAY.
C
C.......................................................................
C
C     Opening the file with matrix data:
      IF(FILED.NE.' ') THEN
        WRITE(*,'(2A)') '+Reading: ',FILED(1:MIN0(LENGTH(FILED),70))
        OPEN(LU,FILE=FILED,FORM=FORM,STATUS='OLD',ERR=100)
      END IF
C
C     Reading the matrix:
      N=NELEM
      O=1
      IF(NSPARS.GE.0) THEN
        CALL RARRAI(LU,' ',FORM,.FALSE.,0,N,IARRAY)
        O=N+1
      END IF
      CALL RARRAY(LU,' ',FORM,.FALSE.,0.,N,ARRAY(O))
C
C     Closing input file:
      IF(FILED.NE.' ') THEN
        CLOSE(LU)
        WRITE(*,'(1A)')
     *  '+                                                             '
      END IF
      RETURN
  100 CONTINUE
C     MAT-29
      WRITE(TXTERR,'(A,A,A)') 'MAT-29: Error when opening file ''',
     *FILED(1:MIN0(LENGTH(FILED),37)),'''.'
      CALL ERROR(TXTERR)
      END
C
C=======================================================================
C
C     
C
      SUBROUTINE WMATR(LU,FORM,N,ARRAY)
      CHARACTER*(*) FORM
      INTEGER LU,N
      REAL ARRAY(N)
C
C Subroutine designed to write a given array of matrix elements into the
C file.
C
C Input:
C     LU...   Logical unit number to be used for the output.
C             The file should be already opened, and is not closed after
C             writing.
C     FORM... Form of the matrix data file in lowercase:
C             FORM='formatted': Formatted file.
C             FORM='unformatted': Unformatted file.
C     N...    Number of matrix elements.
C     ARRAY...Array of matrix elements.
C
C No output.
C
C                                                  
C Input SEP parameter:
C     NUMLIN=positive integer... Number of the numbers to be written
C             to each line of the output file.
C             NUMLIN must be less than 100 (99 at most).
C             Default: NUMLIN=5
C
C Coded by Ludek Klimes and Petr Bulant
C
C-----------------------------------------------------------------------
C
C     Local storage locations:
      CHARACTER*14 FORMAT
C     FORMAT..String containing the output format.
C
      INTEGER NUMLIN
      SAVE NUMLIN
      DATA NUMLIN/-1/
C
C.......................................................................
C
C     Setting output format:
      IF (NUMLIN.EQ.-1) THEN
        CALL RSEP3I('NUMLIN',NUMLIN,5)
      ENDIF
      FORMAT='(00(G13.7,1X))'
      FORMAT(3:3)=CHAR(ICHAR('0')+MOD(NUMLIN,10))
      FORMAT(2:2)=CHAR(ICHAR('0')+    NUMLIN/10 )
C
C     Writing the array:
      IF (FORM.EQ.'formatted') THEN
        WRITE(LU,FORMAT) ARRAY
      ELSE
        WRITE(LU)        ARRAY
      ENDIF
C
      RETURN
      END
C=======================================================================
C
C     
C
      SUBROUTINE TMATR(M1,M2,SYM,NSPAR,NELEM,IARRAY,ARRAY,
     *                 IATMP,ATMP,MTMP)
      CHARACTER*(*) SYM
      INTEGER M1,M2,NSPAR,NELEM,MTMP
      REAL     ARRAY(*),ATMP(*)
      INTEGER IARRAY(*),IATMP(*)
C
C Subroutine designed to transpose a matrix.
C Sparse matrix to be transposed must be stored in form "as on a disk".
C
C Input:
C     M1...   Number of rows of the matrix.
C     M2...   Number of columns of the matrix.
C     SYM ... Symmetry of the matrix.
C     NSPAR...Sparseness of the matrix.
C     NELEM...Number of elements of the matrix.
C     IARRAY..Components of the given matrix.
C     ARRAY...Components of the given matrix.
C     For detailed description of the parameters describing the matrices
C     refer to file forms.htm.
C     Detailed description of storage of matrices in the memory
C     is given above.
C     MTMP .. Dimension of auxiliary arrays IATMP and ATMP.
C
C Output:
C     M1...   Number of rows of the transposed matrix.
C     M2...   Number of columns of the transposed matrix.
C     IARRAY..Components of the transposed matrix.
C     ARRAY...Components of the transposed matrix.
C
C Coded by Petr Bulant
C
C-----------------------------------------------------------------------
C
C Subroutines and external functions required:
      EXTERNAL ERROR,INDEXI
C
C     Local storage location:
      INTEGER I1,I2,I3
      CHARACTER*72 TXTERR
C
C.......................................................................
C
      IF (SYM.EQ.'sym'.OR.SYM.EQ.'diag') THEN
C       Symmetric or diagonal matrix
        RETURN
      ENDIF
      IF (SYM.EQ.'skew') THEN
C       Antisymmetric matrix
        IF (NSPAR.GE.0) THEN
C         Sparse matrix
          DO 1, I1=NELEM+1,2*NELEM
            ARRAY(I1)=-ARRAY(I1)
  1       CONTINUE
        ELSE
C         Normal (not sparse) matrix
          DO 10, I1=1,NELEM
            ARRAY(I1)=-ARRAY(I1)
  10      CONTINUE
        ENDIF
        RETURN
      ENDIF
C     General matrix:
      IF (NSPAR.GE.0) THEN
C       Transposing sparse matrix:
        IF (2*NELEM.GT.MTMP) THEN
C         MAT-02
          WRITE(TXTERR,'(A,I9,A)')
     *    'MAT-02: Array RAM too small,',2*NELEM-MTMP,' units missing.'
          CALL ERROR(TXTERR)
        ENDIF
        DO 2, I3=1,NELEM
          I1=MOD((IARRAY(I3)-1),M1)+1
          I2=(IARRAY(I3)-1)/M1+1
          IARRAY(I3)=(I1-1)*M2+I2
          IATMP(I3)=IARRAY(I3)
          ATMP(NELEM+I3)=ARRAY(NELEM+I3)
   2    CONTINUE
        CALL INDEXI(NELEM,IATMP,IARRAY)
        DO 3, I3=1,NELEM
          ARRAY(NELEM+I3)=ATMP(NELEM+IARRAY(I3))
          IARRAY(I3)=IATMP(IARRAY(I3))
   3    CONTINUE
      ELSE
C       Transposing normal (not sparse) matrix:
        IF (NELEM.GT.MTMP) THEN
C         MAT-03
          WRITE(TXTERR,'(A,I9,A)')
     *    'MAT-03: Array RAM too small,',NELEM-MTMP,' units missing.'
          CALL ERROR(TXTERR)
        ENDIF
        DO 30, I2=1,M2
          DO 20, I1=1,M1
            ATMP((I1-1)*M2+I2)=ARRAY((I2-1)*M1+I1)
  20      CONTINUE
  30    CONTINUE
        DO 40, I1=1,NELEM
          ARRAY(I1)=ATMP(I1)
  40    CONTINUE
      ENDIF
      I1=M1
      M1=M2
      M2=I1
C
      RETURN
      END
C
C=======================================================================
C
C     
C
      SUBROUTINE SMATRE(M1,M2,SYM,NSPAR,NELEM,
     *                  IARRAY,ARRAY,MARRAY,NARRAY,ISTOR)
      CHARACTER*(*) SYM
      INTEGER M1,M2,NSPAR,NELEM,NARRAY,MARRAY,ISTOR
      REAL     ARRAY(*)
      INTEGER IARRAY(*)
C
C Subroutine designed to extend sparse symmetric or antisymmetric
C matrix to the sparse general matrix.
C Sparse matrix to be extended must be stored in form "as on a disk".
C
C Input:
C     M1...   Number of rows of the matrix.
C     M2...   Number of columns of the matrix.
C     SYM ... Symmetry of the matrix.
C     NSPAR...Sparseness of the matrix.
C     NELEM...Number of elements of the matrix.
C     NARRAY..Number of storage locations for the matrix.
C     IARRAY..Components of the given matrix.
C     ARRAY...Components of the given matrix.
C     ISTOR...Form of the given matrix.
C     For detailed description of the parameters describing the matrices
C     refer to file forms.htm.
C     Detailed description of storage of matrices in the memory
C     is given above.
C     MARRAY..Dimension of array ARRAY.
C
C Output:
C     SYM ... SYM=' '. New symmetry of the matrix (general matrix).
C     NSPAR...Sparseness of the extended matrix.
C     NELEM...Number of elements of the extended matrix.
C     NARRAY..Number of storage locations for the extended matrix.
C     IARRAY..Components of the extended matrix.
C     ARRAY...Components of the extended matrix.
C
C Coded by Petr Bulant
C
C-----------------------------------------------------------------------
C
C Subroutines and external functions required:
      EXTERNAL ERROR,INDEXI
C
C     Local storage location:
      INTEGER I1,I2,I3,I4,NNE
      REAL SYMMUL
      CHARACTER*72 TXTERR
C
C.......................................................................
C
      IF ((NSPAR.LT.0).OR.((SYM.NE.'sym').AND.(SYM.NE.'skew')).OR.
     *    (MARRAY.LT.NARRAY).OR.(ISTOR.NE.0)) THEN
C       MAT-04
        CALL ERROR('MAT-04: Wrong invocation of SMATRE.')
      ENDIF
C     Calculating the new number of elements in the extended matrix:
      NNE=NELEM
      DO 1, I3=1,NELEM
        I1=MOD((IARRAY(I3)-1),M1)+1
        I2=(IARRAY(I3)-1)/M1+1
        IF (I1.NE.I2) NNE=NNE+1
   1  CONTINUE
      IF (4*NNE.GT.MARRAY) THEN
C       MAT-05
        WRITE(TXTERR,'(A,I9,A)')
     *  'MAT-05: Array RAM too small,',4*NNE-MARRAY,' units missing.'
        CALL ERROR(TXTERR)
      ENDIF
C     Multiplication switch for symmetric or antisymmetric matrix:
      IF (SYM.EQ.'sym') THEN
        SYMMUL=1.
      ELSE
        SYMMUL=-1.
      ENDIF
C     Filling the auxiliary arrays:
      I4=0
      DO 2, I3=1,NELEM
        I4=I4+1
        I1=MOD((IARRAY(I3)-1),M1)+1
        I2=(IARRAY(I3)-1)/M1+1
        IARRAY(2*NNE+I4)=IARRAY(I3)
        ARRAY(3*NNE+I4)=ARRAY(NELEM+I3)
        IF (I1.NE.I2) THEN
          I4=I4+1
          IARRAY(2*NNE+I4)=(I1-1)*M2+I2
          ARRAY(3*NNE+I4)=SYMMUL*ARRAY(NELEM+I3)
        ENDIF
   2  CONTINUE
C     Sorting:
      CALL INDEXI(NNE,IARRAY(2*NNE+1),IARRAY)
C     Copying back the sorted matrix elements:
      DO 3, I3=1,NNE
        ARRAY(NNE+I3)=ARRAY(3*NNE+IARRAY(I3))
        IARRAY(I3)=IARRAY(2*NNE+IARRAY(I3))
   3  CONTINUE
C
      NELEM=NNE
      NARRAY=2*NNE
      SYM=' '
      RETURN
      END
C
C=======================================================================
C
C     
C
      SUBROUTINE SMATR(M1,M2,NSPAR,NELEM,
     *                 IARRAY,ARRAY,MARRAY,OARRAY,NARRAY,ISTOR)
      INTEGER M1,M2,NSPAR,NELEM,OARRAY,NARRAY,MARRAY,ISTOR
      REAL     ARRAY(*)
      INTEGER IARRAY(*)
C
C Subroutine designed to change a sparse matrix from form "as on a disk"
C to form "as in the memory" or back.
C
C Input:
C     M1...   Number of rows of the matrix.
C     M2...   Number of columns of the matrix.
C     NSPAR...Sparseness of the matrix.
C     NELEM...Number of elements of the matrix.
C     OARRAY..Address of the first storage location in array ARRAY
C             to be used for the matrix.
C     NARRAY..Number of storage locations for the matrix.
C     IARRAY..Components of the given matrix.
C     ARRAY...Components of the given matrix.
C     ISTOR...Form of the given matrix.
C     For detailed description of the parameters describing the matrices
C     refer to file forms.htm.
C     Detailed description of storage of matrices in the memory
C     is given above.
C     MARRAY..Dimension of array ARRAY.
C
C Output:
C     OARRAY..New address of the first storage location in array ARRAY.
C     NARRAY..New number of storage locations for the matrix.
C     IARRAY..Components of the given matrix.
C     ARRAY...Components of the given matrix.
C     ISTOR...New form of the given matrix, opposite to the input.
C
C Coded by Petr Bulant
C
C-----------------------------------------------------------------------
C
C Subroutines and external functions required:
      EXTERNAL ERROR,RAMATR
C
C     Local storage location:
      INTEGER I1,I2,I3,I4,I20,NN,OAROLD,OARNEW
      CHARACTER*72 TXTERR
C
C.......................................................................
C
      IF (NSPAR.LT.0) THEN
C       MAT-06
        CALL ERROR('MAT-06: Wrong invocation of SMATR.')
      ENDIF
      OAROLD=OARRAY
      IF (ISTOR.EQ.0) THEN
C       Rearranging sparse matrix from the form 'as on a disk'
C       to the form 'as in the memory':
        NN=NELEM
        OARNEW=MARRAY-2*NN-M2
        IF (((OARNEW+M2).LT.(OAROLD+NN)).OR.(OARNEW.LT.1)) THEN
C         MAT-07
          WRITE(TXTERR,'(A,I9,A)')
     *    'MAT-07: Array RAM too small,',OAROLD+NN-OARNEW-M2,
     *    ' units missing.'
          CALL ERROR(TXTERR)
        ENDIF
C       Moving the indices and the values to the new positions:
        DO 2, I3=NN,1,-1
          ARRAY(OARNEW+M2+2*I3)=ARRAY(OAROLD+NN+I3-1)
          IARRAY(OARNEW+M2+2*I3-1)=IARRAY(OAROLD+I3-1)
   2    CONTINUE
C       Calculating end addresses of the columns,
C       changing matrix indices of elements to the row numbers:
        I20=M2+1
        DO 4, I3=NN,1,-1
          I1=MOD((IARRAY(OARNEW+M2+2*I3-1)-1),M1)+1
          I2=(IARRAY(OARNEW+M2+2*I3-1)-1)/M1+1
          IARRAY(OARNEW+M2+2*I3-1)=I1
          IF (I2.NE.I20) THEN
            DO 3, I4=I20-1,I2,-1
              IARRAY(OARNEW+I4)=OARNEW+M2+2*I3
   3        CONTINUE
            I20=I2
          ENDIF
   4    CONTINUE
        DO 5, I4=I20-1,0,-1
          IARRAY(OARNEW+I4)=OARNEW+M2
   5    CONTINUE
        NARRAY=1+M2+2*NN
        ISTOR=1
      ELSE
C       Rearranging sparse matrix from the form 'as in the memory'
C       to the form 'as on a disk':
        OARNEW=1
C       Changing indices of rows to matrix indices:
        DO 20, I2=1,M2
          DO 18, I3=IARRAY(OAROLD+I2-1)+1,IARRAY(OAROLD+I2)-1,2
            I1=IARRAY(I3)
            IARRAY(I3)=(I2-1)*M1+I1
  18      CONTINUE
  20    CONTINUE
        CALL RAMATR(ARRAY,IARRAY,OAROLD+M2+1,2*NELEM,OARNEW,ISTOR)
        NARRAY=2*NELEM
      ENDIF
      OARRAY=OARNEW
C
      RETURN
      END
C
C=======================================================================
C
C     
C
      SUBROUTINE RAMATR(ARRAY,IARRAY,OA,NA,OANEW,ISTOR)
      INTEGER OA,NA,OANEW,ISTOR
      REAL     ARRAY(*)
      INTEGER IARRAY(*)
C
C Subroutine designed to Reorganize Array with a matrix from the form
C "as on a disk" to the form "as in the memory" or back.  This
C subroutine reorganizes indices and values of the matrix from the form
C "all indices, all values" to the form "index, value, index, value, .."
C or back, it does not change the indices.
C For ISTOR=1 on input the value OA must be less than OANEW.
C For ISTOR=0 on input the value OA must be greater than OANEW.
C
C Input:
C     OA ...  Address of the first storage location in array ARRAY
C             used for the index of the first element of the matrix.
C     OANEW...New address of the first storage location in array ARRAY
C             to be used for the index of the first element
C             of the reorganized matrix.
C     NA ...  Number of storage locations for the indices and values
C             of the matrix elements.
C     ISTOR...Form of the given matrix.
C     IARRAY..Components of the given matrix.
C     ARRAY...Components of the given matrix.
C     Detailed description of storage of matrices in the memory
C     is given above.
C
C Output:
C     IARRAY..Reorganized components of the given matrix.
C     ARRAY...Reorganized components of the given matrix.
C     ISTOR...New form of the given matrix, opposite to the input.
C
C Coded by Petr Bulant
C
C-----------------------------------------------------------------------
C
C Subroutines and external functions required:
      EXTERNAL ERROR
C
C     Local storage location:
      INTEGER I1,I2,I3,I4,J2,J3,J4,NN
      CHARACTER*72 TXTERR
C
C.......................................................................
C
      NN=NA/2
      IF (ISTOR.EQ.0) THEN
C       IF (I1.GT.J2) THEN
C         MAT-08
C         WRITE(TXTERR,'(A,I9,A)')
C    *    'MAT-08: Array RAM too small,',I1-J2,' units missing.'
C         CALL ERROR(TXTERR)
C       ENDIF
        CALL ERROR('MAT-08: Option ISTOR.EQ.0 is not yet coded.')
      ELSEIF (ISTOR.EQ.1) THEN
C       Rearranging the matrix to the form 'as on a disk':
        IF (OANEW.GE.OA) THEN
C         MAT-09
          CALL ERROR('MAT-09: Wrong invocation of RAMATR')
C         If ISTOR=1, OANEW must be less than OA.
        ENDIF
C       Moving the indices to the new positions, while the values stay
C       on place, and only if there is no place for the indices, then
C       the values are collected and shifted towards the end of ARRAY.
C       J2 points just before the collected values
C       J3 points to the end of the collected values
        J2=OA
        J3=OA+1
        DO 34, I3=1,NN
          I1=OANEW+I3-1
          I2=OA+2*I3-2
          IF (I1.GT.J2) THEN
            J4=I2-2
            DO 31, I4=I2-3,J3,-2
              ARRAY(J4)=ARRAY(I4)
              J4=J4-1
  31        CONTINUE
            DO 32, I4=J3-1,J2+1,-1
              ARRAY(J4)=ARRAY(I4)
              J4=J4-1
  32        CONTINUE
            J3=I2-1
            J2=J4
            IF (I1.GT.J2) THEN
C             MAT-10
              WRITE(TXTERR,'(A,I9,A)')
     *        'MAT-10: Array RAM too small,',I1-J2,' units missing.'
              CALL ERROR(TXTERR)
C             This error should not appear.
            ENDIF
          ENDIF
          IARRAY(I1)=IARRAY(I2)
  34    CONTINUE
C       Indices are moved, now collecting the rest of values
C       and moving them to the end of ARRAY:
        I2=OA+2*NN
        J4=I2-2
        DO 35, I4=I2-3,J3,-2
          ARRAY(J4)=ARRAY(I4)
          J4=J4-1
  35    CONTINUE
        DO 36, I4=J3-1,J2+1,-1
          ARRAY(J4)=ARRAY(I4)
          J4=J4-1
  36    CONTINUE
        J2=J4
C       Moving the values to the new positions:
        DO 38, I3=1,NN
          ARRAY(OANEW+NN+I3-1)=ARRAY(J2+I3)
  38    CONTINUE
        ISTOR=0
      ENDIF
C
      RETURN
      END
C
C=======================================================================
C
C     
C
      SUBROUTINE GSMATR(M1,M2,SYM,NSPAR,NELEM,ARRAY,IARRAY,MARRAY,
     *                  OARRAY,NARRAY,ISTOR)
      CHARACTER*(*) SYM
      INTEGER M1,M2,NSPAR,NELEM,OARRAY,NARRAY,MARRAY,ISTOR
      REAL     ARRAY(*)
      INTEGER IARRAY(*)
C
C Subroutine designed to change normal (not sparse) matrix to the
C sparse matrix.
C
C Input:
C     M1...   Number of rows of the matrix.
C     M2...   Number of columns of the matrix.
C     SYM ... Symmetry of the matrix.
C     NSPAR...Sparseness of the matrix. Must be NSPAR.LT.0 on input.
C     NELEM...Number of elements of the matrix.
C     OARRAY..Address of the first storage location in array ARRAY
C             used for the matrix.
C     NARRAY..Number of storage locations for the matrix.
C     IARRAY..Components of the given matrix.
C     ARRAY...Components of the given matrix.
C     ISTOR...Form to be used for the given matrix.
C             ISTOR=0 ... form "as on a disk"
C             ISTOR=1 ... form "as in the memory"
C     For detailed description of the parameters describing the matrices
C     refer to file forms.htm.
C     Detailed description of storage of matrices in the memory
C     is given above.
C     MARRAY..Dimension of array ARRAY.
C
C Output:
C     NSPAR...Sparseness of the matrix.
C     NELEM...Number of elements of the matrix.
C     NARRAY..New number of storage locations for the matrix.
C     IARRAY..Components of the given matrix.
C     ARRAY...Components of the given matrix.
C
C Coded by Petr Bulant
C
C-----------------------------------------------------------------------
C
C Subroutines and external functions required:
      EXTERNAL ERROR,RAMATR,NSPMAT
      INTEGER NSPMAT
C
C     Local storage location:
      INTEGER I1,I2,I3,I4,I20,I11,I12,J1,NN
      CHARACTER*72 TXTERR
C
C.......................................................................
C
      IF ((NSPAR.GE.0).OR.(NELEM.NE.NARRAY)) THEN
C       MAT-11
        CALL ERROR('MAT-11: Wrong invocation of GSMATR.')
      ENDIF
C
C     Number NSPAR of zero and NELEM of nonzero elements:
      NSPAR=NSPMAT(NARRAY,ARRAY(OARRAY))
      NELEM=NARRAY-NSPAR
      NN=NELEM
      IF (((ISTOR.EQ.0).AND.((1+2*NN+1).GT.(MARRAY))).OR.
     *    ((ISTOR.EQ.1).AND.((1+M2+2*NN).GT.(MARRAY)))) THEN
C       MAT-12
        IF (ISTOR.EQ.0) THEN
          I1=1+2*NN+1-MARRAY
        ELSE
          I1=1+M2+2*NN-MARRAY
        ENDIF
        WRITE(TXTERR,'(A,I9,A)')
     *  'MAT-12: Array RAM too small,',I1,' units missing.'
        CALL ERROR(TXTERR)
      ENDIF
C     Moving the nonzero elements of the matrix to the end of ARRAY,
C     storing the corresponding matrix indices of the elements:
      J1=MARRAY
      I3=OARRAY-1+NARRAY
      DO 20, I2=M2,1,-1
        IF (SYM.EQ.'diag') THEN
          I11=I2
          I12=I2
        ELSEIF (SYM.EQ.'sym') THEN
          I11=I2
          I12=1
        ELSEIF (SYM.EQ.'skew') THEN
          I11=I2-1
          I12=1
        ELSE
          I11=M1
          I12=1
        ENDIF
        DO 18, I1=I11,I12,-1
          IF (ARRAY(I3).NE.0.) THEN
            IF (J1-1.LT.I3) THEN
C             MAT-13
              WRITE(TXTERR,'(A,I9,A)')
     *        'MAT-13: Array RAM too small,',I3-J1+1,' units missing.'
              CALL ERROR(TXTERR)
            ENDIF
            ARRAY(J1)=ARRAY(I3)
            IARRAY(J1-1)=(I2-1)*M1+I1
            J1=J1-2
          ENDIF
          I3=I3-1
  18    CONTINUE
  20  CONTINUE
      IF (I3.NE.OARRAY-1) THEN
C       MAT-14
        WRITE(TXTERR,'(A,I9,A)')
     *  'MAT-14: Array RAM too small,',OARRAY-1-I3,' units missing.'
        CALL ERROR(TXTERR)
      ENDIF
C     J1 now points just before the index of the first nonzero element
      IF (ISTOR.EQ.0) THEN
C       Rearranging the matrix to the form 'as on a disk':
        ISTOR=1
        CALL RAMATR(ARRAY,IARRAY,J1+1,2*NN,OARRAY,ISTOR)
        NARRAY=2*NN
      ELSE
C       Rearranging the matrix to the form 'as in the memory':
C       Moving the indices and the values to the new positions:
        DO 42, I3=1,NN
          ARRAY(OARRAY+M2+2*I3)=ARRAY(J1+2*I3)
          IARRAY(OARRAY+M2+2*I3-1)=IARRAY(J1+2*I3-1)
  42    CONTINUE
C       Calculating end addresses of the columns,
C       changing matrix indices of the elements to the row numbers:
        I20=M2+1
        DO 44, I3=NN,1,-1
          I1=MOD(IARRAY(OARRAY+M2+2*I3-1),M1)
          IF (I1.EQ.0) I1=M1
          I2=(IARRAY(OARRAY+M2+2*I3-1)-1)/M1+1
          IARRAY(OARRAY+M2+2*I3-1)=I1
          IF (I2.NE.I20) THEN
            DO 43, I4=I20-1,I2,-1
              IARRAY(OARRAY+I4)=OARRAY+M2+2*I3
  43        CONTINUE
            I20=I2
          ENDIF
  44    CONTINUE
        DO 45, I4=I20-1,0,-1
          IARRAY(OARRAY+I4)=OARRAY+M2
  45    CONTINUE
        NARRAY=1+M2+2*NN
      ENDIF
C
      RETURN
      END
C
C=======================================================================
C
C     
C
      SUBROUTINE SGMATR(M1,M2,SYM,NSPAR,NELEM,ARRAY,IARRAY,MARRAY,
     *                  OARRAY,NARRAY,ISTOR)
      CHARACTER*(*) SYM
      INTEGER M1,M2,NSPAR,NELEM,OARRAY,NARRAY,MARRAY,ISTOR
      REAL     ARRAY(*)
      INTEGER IARRAY(*)
C
C Subroutine designed to change sparse matrix to the normal (not sparse)
C matrix.
C
C Input:
C     M1...   Number of rows of the matrix.
C     M2...   Number of columns of the matrix.
C     SYM ... Symmetry of the matrix.
C     NSPAR...Sparseness of the matrix. NSPAR.GE.0 is assumed on input.
C     OARRAY..Address of the first storage location in array ARRAY
C             used for the matrix.
C     NARRAY..Number of storage locations for the matrix.
C     IARRAY..Components of the given matrix.
C     ARRAY...Components of the given matrix.
C     ISTOR...Form of the given matrix.
C             ISTOR=0 ... form "as on a disk"
C             ISTOR=1 ... form "as in the memory"
C     For detailed description of the parameters describing the matrices
C     refer to file forms.htm.
C     Detailed description of storage of matrices in the memory
C     is given above.
C     MARRAY..Dimension of array ARRAY.
C
C Output:
C     NSPAR...Sparseness of the matrix. NSPAR=-1 on output.
C     NELEM...Number of elements of the matrix.
C     ISTOR...Form of the given matrix. ISTOR=0 on output.
C     OARRAY..New address of the first storage location in array ARRAY.
C     NARRAY..New number of storage locations for the matrix.
C     IARRAY..Components of the given matrix.
C     ARRAY...Components of the given matrix.
C
C Coded by Petr Bulant
C
C-----------------------------------------------------------------------
C
C Subroutines and external functions required:
      EXTERNAL ERROR,ISYM,NELMAT
      INTEGER ISYM,NELMAT
C
C     Local storage location:
      INTEGER ISY,I1,I2,I3,J1,J2,J3,I11,I12
      CHARACTER*72 TXTERR
C
C.......................................................................
C
      IF (NSPAR.LT.0) THEN
C       MAT-15
        CALL ERROR('MAT-15: Wrong invocation of SGMATR.')
      ENDIF
C
      ISY=ISYM(SYM)
C
      IF (ISTOR.EQ.0) THEN
C       Rewriting the matrix from the sparse form "as on the disk"
C       to the normal (not sparse) form:
        J2=NELMAT(M1,M2,ISY)
        J3=J2
        IF (OARRAY+NELEM+J2-1.GT.MARRAY) THEN
C         MAT-16
          WRITE(TXTERR,'(A,I9,A)')
     *    'MAT-16: Array RAM too small,',OARRAY+NELEM+J2-1-MARRAY,
     *    ' units missing.'
          CALL ERROR(TXTERR)
        ENDIF
        J1=NELEM
C       J1 is the index in sparse matrix, J2 in the non-sparse matrix
        DO 4, I2=M2,1,-1
C         I2 is the number of column
          I12=1
          IF     (ISY.EQ.1) THEN
            I11=I2
            I12=I2
          ELSEIF (ISY.EQ.2) THEN
            I11=I2
          ELSEIF (ISY.EQ.3) THEN
            I11=I2-1
          ELSE
            I11=M1
          ENDIF
          DO 2, I1=I11,I12,-1
C           I1 is the number of line
            I3=(I2-1)*M1+I1
C           I3 is the matrix index of the element [I1,I2]
            IF     (IARRAY(OARRAY-1+J1).LT.I3) THEN
              ARRAY(OARRAY-1+NELEM+J2)=0.
            ELSEIF (IARRAY(OARRAY-1+J1).EQ.I3) THEN
              ARRAY(OARRAY-1+NELEM+J2)=ARRAY(OARRAY-1+NELEM+J1)
              J1=J1-1
            ELSE
C             MAT-17
              CALL ERROR('MAT-17: Disorder in SGMATR')
C             This error should not appear.
            ENDIF
            J2=J2-1
   2      CONTINUE
   4    CONTINUE
        IF ((J1.NE.0).OR.(J2.NE.0)) THEN
C         MAT-18
          CALL ERROR('MAT-18: Disorder in SGMATR')
C         This error should not appear.
        ENDIF
        NSPAR=-1
        J2=NELEM
        NELEM=J3
        NARRAY=J3
        CALL MSHIFT(M1,M2,ISY,NSPAR,NELEM,IARRAY,ARRAY,MARRAY,
     *                  OARRAY+J2,NARRAY,ISTOR,OARRAY)
        RETURN
      ENDIF
C     Rewriting the matrix from the sparse form "as in the memory"
C     to the normal (not sparse) form:
      J2=MARRAY
      DO 20, I2=M2,1,-1
C       Initiating storage locations for column I2:
        IF (ISY.EQ.1) THEN
          J1=J2-1
        ELSEIF (ISY.EQ.2) THEN
          J1=J2-I2
        ELSEIF (ISY.EQ.3) THEN
          J1=J2-I2+1
        ELSE
          J1=J2-M1
        ENDIF
        IF (J1.LE.IARRAY(OARRAY+I2)) THEN
C         MAT-19
          WRITE(TXTERR,'(A,I9,A)')
     *    'MAT-19: Array RAM too small,',IARRAY(OARRAY+I2)-J1,
     *    ' units missing.'
          CALL ERROR(TXTERR)
        ENDIF
        DO 8, I3=J1+1,J2
          ARRAY(I3)=0.
   8    CONTINUE
C       Rewriting column I2:
        DO 10, I3=IARRAY(OARRAY+I2),IARRAY(OARRAY+I2-1)+2,-2
          I1=IARRAY(I3-1)
          IF ( (ISY.EQ.4).OR.
     *        ((ISY.EQ.1).AND.(I1.EQ.I2)).OR.
     *        ((ISY.EQ.2) .AND.(I1.LE.I2)).OR.
     *        ((ISY.EQ.3).AND.(I1.LT.I2))) THEN
            IF (ISY.EQ.1) THEN
              ARRAY(J1+1)=ARRAY(I3)
            ELSE
              ARRAY(J1+I1)=ARRAY(I3)
            ENDIF
          ENDIF
  10    CONTINUE
        J2=J1
  20  CONTINUE
      NARRAY=MARRAY-J2
C     Shifting the matrix to the beginning of ARRAY:
      J2=J2+1
      DO 30, I1=J2,MARRAY
        ARRAY(OARRAY+I1-J2)=ARRAY(I1)
  30  CONTINUE
      NELEM=NARRAY
      NSPAR=-1
      ISTOR=0
C
      RETURN
      END
C
C=======================================================================
C
C     
C
      SUBROUTINE GSMAT(M1,M2,SYM,NSPAR,NELEM,ARRAY,IARRAY,MARRAY,
     *                  OARRAY,NARRAY,ISTOR,RSPAR)
      CHARACTER*(*) SYM
      INTEGER M1,M2,NSPAR,NELEM,OARRAY,NARRAY,MARRAY,ISTOR
      REAL     ARRAY(*),RSPAR
      INTEGER IARRAY(*)
C
C Subroutine designed to calculate the number NSPAR of zero elements
C of a normal (not sparse) matrix, and to change the matrix into the
C sparse matrix if NSPAR/NELEM .GE. RSPAR.
C If the matrix is changed to sparse, it is written to the beginning
C of arrays IARRAY and ARRAY.
C The subroutine uses whole arrays ARRAY and IARRAY.
C
C Input:
C     M1...   Number of rows of the matrix.
C     M2...   Number of columns of the matrix.
C     SYM ... Symmetry of the matrix.
C     NSPAR...Sparseness of the matrix.
C             NSPAR.LT.0 is assumed on input.
C     NELEM...Number of elements of the matrix.
C     OARRAY..Address of the first storage location in array ARRAY
C             used for the matrix.
C     NARRAY..Number of storage locations for the matrix.
C     ARRAY...Components of the given matrix.
C     For detailed description of the parameters describing the matrices
C     refer to file forms.htm.
C     Detailed description of storage of matrices in the memory
C     is given above.
C     MARRAY..Dimension of array ARRAY.
C     RSPAR...Minimum rate of sparseness to change the matrix
C             into the sparse matrix.
C
C Output:
C     NSPAR...Sparseness of the matrix.
C             For NSPAR.LT.0 on output, there are no changes on output.
C     NELEM...Number of elements of the matrix.
C     OARRAY..New address of the first storage location in array ARRAY.
C             For NSPAR.GE.0 on output OARRAY=1 on output.
C     NARRAY..New number of storage locations for the matrix.
C     IARRAY..Components of the given matrix.
C     ARRAY...Components of the given matrix.
C     ISTOR...Form of the matrix:
C             For NSPAR.GE.0 on output ISTOR=0 on output,
C             i.e. form "as on a disk".
C     RSPAR...Rate of sparseness of the matrix. (Number of zero elements
C             of the matrix divided by the number of all elements.)
C
C Coded by Petr Bulant
C
C-----------------------------------------------------------------------
C
C Subroutines and external functions required:
      EXTERNAL ERROR,NSPMAT,GSMATR
      INTEGER NSPMAT
C
C     Local storage location:
      INTEGER I1,NN
      REAL RSP0
C
C.......................................................................
C
      IF ((NSPAR.GE.0).OR.(NELEM.NE.NARRAY)) THEN
C       MAT-20
        CALL ERROR('MAT-20: Wrong invocation of GSMAT.')
      ENDIF
C     Number of zero elements:
      NN=NSPMAT(NARRAY,ARRAY(OARRAY))
      RSP0=RSPAR
      RSPAR=FLOAT(NN)/FLOAT(NARRAY)
      IF (RSPAR.LT.RSP0) THEN
C       Matrix will stay non-sparse.
        RETURN
      ENDIF
C     Moving the matrix to the beginning of ARRAY:
      IF (OARRAY.NE.1) THEN
        DO 10, I1=1,NELEM
          ARRAY(I1)=ARRAY(OARRAY+I1-1)
  10    CONTINUE
        OARRAY=1
      ENDIF
C     Changing the matrix into the sparse matrix:
      ISTOR=0
      CALL GSMATR(M1,M2,SYM,NSPAR,NELEM,ARRAY,IARRAY,MARRAY,
     *                  OARRAY,NARRAY,ISTOR)
C
      RETURN
      END
C
C=======================================================================
C
C     
C
      INTEGER FUNCTION NELMAT(M1,M2,ISYM)
      INTEGER M1,M2,ISYM
C
C Integer function to calculate number of elements of non-sparse matrix.
C
C Input:
C     M1...   Number of rows of the matrix.
C     M2...   Number of columns of the matrix.
C     ISYM... Index of the symmetry of the matrix.
C
C Output:
C     NELMAT. Number of elements of M1*M2 non-sparse matrix
C             of given symmetry. Note that for indices corresponding to
C             symmetries 'diag', 'sym' and 'skew' number M2 is used
C             to calculate NELMAT.
C
C Coded by Petr Bulant
C
C-----------------------------------------------------------------------
C
      IF     (ISYM.EQ.4) THEN
C       General matrix
        NELMAT=M1*M2
      ELSEIF (ISYM.EQ.2) THEN
C       Symmetric matrix
        NELMAT=M2*(M2+1)/2
      ELSEIF (ISYM.EQ.3) THEN
C       Skew matrix
        NELMAT=M2*(M2-1)/2
      ELSEIF (ISYM.EQ.1) THEN
C       Diagonal matrix
        NELMAT=M2
      ELSE
C       MAT-21
        CALL ERROR('MAT-21: Wrong index of matrix symmetry.')
C       Input argument ISYM should be equal to 1, 2, 3 or 4.
      ENDIF
C
      RETURN
      END
C
C=======================================================================
C
C     
C
      INTEGER FUNCTION NSPMAT(NELEM,ARRAY)
      INTEGER NELEM
      REAL ARRAY(*)
C
C Integer function to calculate number of zero elements of non-sparse
c matrix.
C
C Input:
C     NELEM...Number of elements of the matrix.
C     ARRAY...Elements of the matrix.
C
C Output:
C     NSPMAT..Number of zero elements of the matrix.
C
C Coded by Petr Bulant
C
      INTEGER I
C-----------------------------------------------------------------------
C
      NSPMAT=0
      DO 10, I=1,NELEM
        IF (ARRAY(I).EQ.0.) NSPMAT=NSPMAT+1
  10  CONTINUE
C
      RETURN
      END
C
C
C=======================================================================
C
C     
C
      INTEGER FUNCTION ISYM(SYM)
      CHARACTER*(*) SYM
C
C Integer function to assign the integer corresponding to the symmetry.
C
C Input:
C     SYM ... Symmetry of a matrix.
C
C Output:
C     ISYM... Integer number corresponding to the symmetry SYM.
C
C Coded by Petr Bulant
C
C-----------------------------------------------------------------------
C
      IF     (SYM.EQ.'diag') THEN
        ISYM=1
      ELSEIF (SYM.EQ.'sym' ) THEN
        ISYM=2
      ELSEIF (SYM.EQ.'skew') THEN
        ISYM=3
      ELSEIF (SYM.EQ.' '   ) THEN
        ISYM=4
      ELSE
C       MAT-22
        CALL ERROR('MAT-22: Wrong matrix symmetry.')
C       Input argument SYM should be equal
C       to one of strings ' ', 'sym', 'skew', 'diag'.
      ENDIF
C
      RETURN
      END
C
C=======================================================================
C
C     
C
      SUBROUTINE MSHIFT(M1,M2,ISYM,NSPAR,NELEM,IARRAY,ARRAY,MARRAY,
     *                  OARRAY,NARRAY,ISTOR,OARNEW)
      INTEGER M1,M2,ISYM,NSPAR,NELEM,OARRAY,NARRAY,MARRAY,ISTOR,OARNEW
      REAL     ARRAY(*)
      INTEGER IARRAY(*)
C
C Subroutine designed to shift the matrix in arrays IARRAY and ARRAY
C to the new position OARNEW.
C
C Input:
C     M1...   Number of rows of the matrix.
C     M2...   Number of columns of the matrix.
C     ISYM... Index of symmetry of the matrix.
C     NSPAR...Sparseness of the matrix.
C     NELEM...Number of elements of the matrix.
C     IARRAY..Components of the given matrix.
C     ARRAY...Components of the given matrix.
C     MARRAY..Dimension of arrays IARRAY and ARRAY.
C     OARRAY..Address of the first storage location in arrays ARRAY
C             and IARRAY used for the matrix.
C     NARRAY..Number of storage locations for the matrix.
C     ISTOR...Form used for the matrix if the matrix is sparse.
C             ISTOR=0 ... form "as on a disk"
C             ISTOR=1 ... form "as in the memory"
C     OARNEW..Address of the first storage location in arrays ARRAY
C             and IARRAY where the matrix is to be shifted.
C     For detailed description of the parameters describing the matrices
C     refer to file forms.htm.
C     Detailed description of storage of matrices in the memory
C     is given above.
C
C Output:
C     OARRAY..OARRAY is put to OARNEW.
C     IARRAY..Components of the shifted matrix.
C     ARRAY...Components of the shifted matrix.
C
C Coded by Petr Bulant
C
C-----------------------------------------------------------------------
C
C     Local storage location:
      INTEGER II,ISHIFT
C
C.......................................................................
C
      IF ((OARNEW.LT.1).OR.(OARNEW+NARRAY-1.GT.MARRAY).OR.
     *    (OARRAY.LT.1).OR.(OARRAY+NARRAY-1.GT.MARRAY)) THEN
C       MAT-23
        CALL ERROR('MAT-23: Wrong invocation of MSHIFT.')
C       Storage locations OARRAY to OARRAY+NARRAY and
C       OARNEW to OARNEW+NARRAY must fit into the memory.
C       This error should not appear.
      ENDIF
C
      IF (OARNEW.EQ.OARRAY) RETURN
C
      IF (NSPAR.LT.0) THEN
C       Non-sparse matrix:
        IF (OARNEW.LT.OARRAY) THEN
          DO 10, II=0,NARRAY-1
            ARRAY(OARNEW+II)=ARRAY(OARRAY+II)
  10      CONTINUE
        ELSE
          DO 11, II=NARRAY-1,0,-1
            ARRAY(OARNEW+II)=ARRAY(OARRAY+II)
  11      CONTINUE
        ENDIF
      ELSE
C       Sparse martix:
        IF (ISTOR.EQ.0) THEN
C         Form "as on disk":
          IF (OARNEW.LT.OARRAY) THEN
            DO 20, II=0,NELEM-1
              IARRAY(OARNEW+II)=IARRAY(OARRAY+II)
  20        CONTINUE
            DO 21, II=0,NELEM-1
              ARRAY (OARNEW+NELEM+II)=ARRAY(OARRAY+NELEM+II)
  21        CONTINUE
          ELSE
            DO 22, II=NELEM-1,0,-1
              ARRAY (OARNEW+NELEM+II)=ARRAY(OARRAY+NELEM+II)
  22        CONTINUE
            DO 23, II=NELEM-1,0,-1
              IARRAY(OARNEW+II)=IARRAY(OARRAY+II)
  23        CONTINUE
          ENDIF
        ELSE
C         Form "as in the memory":
          ISHIFT=OARNEW-OARRAY
          IF (OARNEW.LT.OARRAY) THEN
            DO 30, II=0,M2
              IARRAY(OARNEW+II)=IARRAY(OARRAY+II)+ISHIFT
  30        CONTINUE
            DO 31, II=0,NELEM-1
              IARRAY(OARNEW+M2+1+II*2)  =IARRAY(OARRAY+M2+1+II*2)
               ARRAY(OARNEW+M2+1+II*2+1)= ARRAY(OARRAY+M2+1+II*2+1)
  31        CONTINUE
          ELSE
            DO 32, II=NELEM-1,0,-1
               ARRAY(OARNEW+M2+1+II*2+1)= ARRAY(OARRAY+M2+1+II*2+1)
              IARRAY(OARNEW+M2+1+II*2)  =IARRAY(OARRAY+M2+1+II*2)
  32        CONTINUE
            DO 33, II=M2,0,-1
              IARRAY(OARNEW+II)=IARRAY(OARRAY+II)+ISHIFT
  33        CONTINUE
          ENDIF
        ENDIF
      ENDIF
C
      OARRAY=OARNEW
      RETURN
      END
C
C=======================================================================
C
C     
C
      SUBROUTINE OMAT(LU,FILE,IRW,FORMM)
      CHARACTER*(*) FILE,FORMM
      INTEGER LU,IRW
C
C Subroutine for backward compatibility.
C
C Coded by Petr Bulant
C
C-----------------------------------------------------------------------
      RETURN
      END
C
C=======================================================================
C
C     
C
      SUBROUTINE WMAT(LU,FILE,M1,M2,OUT)
      CHARACTER*(*) FILE
      INTEGER LU,M1,M2
      REAL OUT(*)
C
C Subroutine for backward compatibility.  WMATH and WMATD should be used
C instead fo using WMAT.
C Subroutine designed to write a given matrix into the file.
C
C Input:
C     LU...   Logical unit number to be used for the output.
C     FILE... Destination header file name.  Must not be blank.
C     M1...   Number of rows of the given matrix.
C     M2...   M2=0 for a symmetric matrix,
C             M2=-1 for a diagonal matrix,
C             M2=number of columns for a general matrix.
C     OUT...  Components of the given matrix stored columnwise.
C             For a symmetric matrix, just components from the first row
C             to the diagonal are stored for each column, i.e., array
C             OUT has M1*(M1+1)/2 matrix components.
C             For a diagonal matrix, just M1 diagonal components are
C             stored.
C
C No output.
C
C Coded by Ludek Klimes and Petr Bulant
C
C-----------------------------------------------------------------------
C
C     Local storage locations:
C
      EXTERNAL ISYM,NELMAT,WMATD,WMATH,ERROR
      INTEGER  ISYM,NELMAT
      CHARACTER*13 FORMM
      INTEGER I2,NELEM
C
C     FORMM ..Form of the files with matrices.
C
C.......................................................................
C
      CHARACTER*80 FILED
      CHARACTER*4 SYMM
      INTEGER IOUT(1)
C
      IF (FILE.EQ.' ') THEN
C       MAT-24
        CALL ERROR('MAT-24: Matrix header file not given')
C       In this version of WMAT, the matrix header file
C       must be specified and sequential writing of matrix data file
C       is not allowed.
      ENDIF
      FORMM=' '
      FILED=' '
      IF(M2.EQ.0) THEN
C       Symmetric matrix
        I2=M1
        SYMM='sym'
      ELSEIF(M2.EQ.-1) THEN
C       Diagonal matrix
        I2=M1
        SYMM='diag'
      ELSE
C       General matrix
        I2=M2
        SYMM=' '
      END IF
      NELEM=NELMAT(M1,I2,ISYM(SYMM))
      CALL WMATH(LU,FILE,FILED,M1,I2,-1,SYMM,FORMM)
      CALL WMATD(LU,FILED,-1,FORMM,NELEM,IOUT,OUT)
      RETURN
      END
C
C=======================================================================
C
C     
C
      SUBROUTINE RMAT(LU,FILE,M1,M2,ARRAY)
      CHARACTER*(*) FILE
      INTEGER LU,M1,M2
      REAL ARRAY(*)
C
C Subroutine for backward compatibility.  RMATH and RMATD should be used
C instead fo using RMAT.
C Subroutine designed to read a matrix from the file.
C
C Input:
C     LU...   Logical unit number to be used for the input.
C     FILE... Destination header file name.  Must not be blank.
C     M1...   Number of rows of the matrix.
C     M2...   M2=0 for a symmetric matrix,
C             M2=1 for a diagonal matrix,
C             M2=number of columns for a general matrix.
C
C Output:
C     ARRAY...Components of the given matrix stored columnwise.
C             For a symmetric matrix, just components from the first row
C             to the diagonal are stored for each column, i.e., array
C             out has M1*(M1+1)/2 matrix components.
C             For a diagonal matrix, just M1 diagonal components are
C             stored.
C
C Coded by Ludek Klimes and Petr Bulant
C
C-----------------------------------------------------------------------
C
      EXTERNAL RMATD,RMATH,ERROR
C     Local storage location:
      CHARACTER*13 FORMM
      CHARACTER*80 FILED
      CHARACTER*4 SYMM
      INTEGER IOUT(1),M1R,M2R,NSPAR,NELEM
C
      IF (FILE.EQ.' ') THEN
C       MAT-25
        CALL ERROR('MAT-25: Matrix header file not given')
C       In this version of RMAT, the matrix header file
C       must be specified and sequential reading of matrix data file
C       is not allowed.
      ENDIF
      CALL RMATH(LU,FILE,FILED,M1R,M2R,NSPAR,SYMM,FORMM,NELEM)
      IF ((M1.NE.M1R).OR.(NSPAR.GE.0).OR.(SYMM.EQ.'skew').OR.
     *    ((SYMM.EQ.'sym' ).AND.(M2.NE.0)).OR.
     *    ((SYMM.EQ.' '   ).AND.(M2.NE.M2R)).OR.
     *    ((SYMM.EQ.'diag').AND.(M2.NE.1))) THEN
C       MAT-26
        CALL ERROR('MAT-26: Unexpected values in matrix header file.')
C       Some of the values of the matrix header file differs from
C       the values estimated using input parameters M1 and M2.
C       For example, this version of RMAT cannot deal with sparse
C       matrices.
      ENDIF
      CALL RMATD(LU,FILED,NSPAR,FORMM,NELEM,IOUT,ARRAY)
      RETURN
      END
C
C=======================================================================
C