!-------------------------------------- LICENCE BEGIN ------------------------------------
!Environment Canada - Atmospheric Science and Technology License/Disclaimer,
!                     version 3; Last Modified: May 7, 2008.
!This is free but copyrighted software; you can use/redistribute/modify it under the terms
!of the Environment Canada - Atmospheric Science and Technology License/Disclaimer
!version 3 or (at your option) any later version that should be found at:
!http://collaboration.cmc.ec.gc.ca/science/rpn.comm/license.html
!
!This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
!without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
!See the above mentioned License/Disclaimer for more details.
!You should have received a copy of the License/Disclaimer along with this software;
!if not, you can write to: EC-RPN COMM Group, 2121 TransCanada, suite 500, Dorval (Quebec),
!CANADA, H9P 1J3; or send e-mail to service.rpn@ec.gc.ca
!-------------------------------------- LICENCE END --------------------------------------
!

      subroutine minv(ab,n,nd,scratch,det,eps,m,mode) 4,1
      implicit none
C
C     A subroutine that calculates the determinant and inverse of
C          a matrix, as well as solving systems of linear equations.
C     Martin J. McBride.  11/25/85.
C     General Electric CRD, Information System Operation.
C
#include "comlun.cdk"
      integer n,nd,m,mode,outer,row,col,i,scol,srow,pivcnt
      real*8 ab(nd,1),scratch(1),det,eps,mult,colnum,temp
      real*8 div
C  Initialize scratch space, with 1 to N holding the diagonal of the identity
C  matrix used to compute the inverse and N+1 to 2N holding the positions of
C  the first N columns of the matrix (for use when pivot occurs).
      do 5 i = 1,n
    5    scratch(i) = 1.0
      colnum = 1.0
      do 6 i = n+1,2*n
         scratch(i) = colnum
         colnum = colnum + 1.0
    6 continue

C  Make left, square matrix an upper triangular matrix.
      det = 0.0
      pivcnt = 0
      do 10 outer = 1,n-1
         if (abs(ab(outer,outer)) .le. eps) then
            call pivot2(ab,n,nd,outer,scratch,eps)
            if (ab(outer,outer) .eq. 0.0) then
               write(nulout,*) ' '
               write(nulout,*) '*************************************'
               write(nulout,*) '  MINV called with singular matrix.'
               write(nulout,*) '*************************************'
               write(nulout,*) ' '
               stop
            endif
            pivcnt = pivcnt + 1
         endif
         do 20 row = outer+1,n
            mult = ab(row,outer)/ab(outer,outer)
            do 30 col = outer,n+m
   30          ab(row,col) = ab(row,col) - ab(outer,col)*mult
            do 25 scol = 1,outer-1
   25          ab(row,scol) = ab(row,scol) - ab(outer,scol)*mult
            ab(row,outer) = ab(row,outer) - scratch(outer)*mult
   20    continue
   10 continue

C  Compute determinant.
      det = ab(1,1)
      do 40 i = 2,n
   40    det = det*ab(i,i)
      det = (-1.0)**pivcnt * det

C  Return if inverse is not to be found and there are no systems of equations
C  to solve.
      if (mode .eq. 0 .and. m .eq. 0) return

C  Place ones in diagonal of square matrix A.
      do 80 row = 1,n
         div = ab(row,row)
         do 90 col = 1,n+m
            ab(row,col) = ab(row,col)/div
   90    continue
         scratch(row) = scratch(row)/div
   80 continue

C  Reduce upper triangle to zeros to give matrix A = I.
      do 50 outer = 2,n
         do 60 row = outer-1,1,-1
            mult = ab(row,outer)/ab(outer,outer)
            do 70 col = outer,n+m
   70          ab(row,col) = ab(row,col) - ab(outer,col)*mult
            do 65 scol = 1,row-1
   65          ab(row,scol) = ab(row,scol) - ab(outer,scol)*mult
            scratch(row) = scratch(row) - ab(outer,row)*mult
            do 63 scol = row+1,outer-1
   63          ab(row,scol) = ab(row,scol) - ab(outer,scol)*mult
            ab(row,outer) = ab(row,outer) - scratch(outer)*mult
   60    continue
   50 continue

C  Move diagonals of inverse to matrix AB.
      do 85 i = 1,n
   85    ab(i,i) = scratch(i)

C  If pivot was made, switch rows corresponding to the columns that were
C  pivoted.
      if (pivcnt .eq. 0) return
      row = 1
      do 95 i = 1,n-1
         srow = int(scratch(row+n))
         if (srow .ne. row) then
            do 92 col = 1,n+m
               temp = ab(row,col)
               ab(row,col) = ab(srow,col)
               ab(srow,col) = temp
   92       continue
            temp = scratch(row+n)
            scratch(row+n) = scratch(srow+n)
            scratch(srow+n) = temp
         else
            row = row + 1
         endif
   95 continue

      return
      end