!
! This file is part of SACAMOS, State of the Art CAble MOdels for Spice.
! It was developed by the University of Nottingham and the Netherlands Aerospace
! Centre (NLR) for ESA under contract number 4000112765/14/NL/HK.
!
! Copyright (C) 2016-2018 University of Nottingham
!
! SACAMOS is free software: you can redistribute it and/or modify it under the
! terms of the GNU General Public License as published by the Free Software
! Foundation, either version 3 of the License, or (at your option) any later
! version.
!
! SACAMOS 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 GNU General Public License
! for more details.
!
! A copy of the GNU General Public License version 3 can be found in the
! file GNU_GPL_v3 in the root or at .
!
! SACAMOS uses the EISPACK library (in /SRC/EISPACK). EISPACK is subject to
! the GNU Lesser General Public License. A copy of the GNU Lesser General Public
! License version can be found in the file GNU_LGPL in the root of EISPACK
! (/SRC/EISPACK ) or at .
!
! The University of Nottingham can be contacted at: ggiemr@nottingham.ac.uk
!
!
! SUBROUTINE dwrite_matrix(a,ar,ac,dim,unit)
! SUBROUTINE dread_matrix(a,ar,ac,dim,unit)
! SUBROUTINE dinvert_Gauss_Jordan(A,ar,AI,dim)
!
!_____________________________________________________________________
!
! NAME
! dwrite_matrix
!
! DESCRIPTION
! write real(dp) matrix to file or screen
!
!
! SEE ALSO
!
!
! HISTORY
!
! started 26/04/15 CJS
!
! COMMENTS
!
!
SUBROUTINE dwrite_matrix(a,ar,ac,dim,unit)
! Modules used
USE type_specifications
IMPLICIT NONE
! variables passed to subroutine
integer,intent(IN) :: dim ! matrix dimension
integer,intent(IN) :: unit ! output unit. Set to zero to output to screen
real(dp),intent(IN) :: a(dim,dim) ! matrix to write
integer,intent(IN) :: ar,ac ! number of rows and columns to write
! Local variables
integer row,i
! START
do row=1,ar
if (unit.NE.0) then
write(unit,8000)(a(row,i),i=1,ac)
else
write(*,8000)(a(row,i),i=1,ac)
end if
end do
8000 format (1000ES16.8)
! END
RETURN
END SUBROUTINE dwrite_matrix
!
!_____________________________________________________________________
!
! NAME
! dread_matrix
!
! DESCRIPTION
! read real(dp) matrix from file
!
! SEE ALSO
!
!
! HISTORY
!
! started 2/12/15 CJS
!
! COMMENTS
!
!
SUBROUTINE dread_matrix(a,ar,ac,dim,unit)
! Modules used
USE type_specifications
IMPLICIT NONE
! variables passed to subroutine
integer,intent(IN) :: dim ! matrix dimension
integer,intent(IN) :: unit ! input unit
real(dp),intent(OUT) :: a(dim,dim) ! matrix to write
integer,intent(IN) :: ar,ac ! number of rows and columns to read
! Local variables
integer row,i
! START
do row=1,ar
if (unit.NE.0) then
read(unit,*)(a(row,i),i=1,ac)
else
read(*,*)(a(row,i),i=1,ac)
end if
end do
! END
RETURN
END SUBROUTINE dread_matrix
!
! NAME
! dread_matrix
!
! DESCRIPTION
!
! Invert the real matrix A using Gauss Jordan method with pivoting and return the result in AI
! ierr=0 on the successful calculation of the inverse
! If a singular matrix is found then:
! if ierr.EQ.0 on input then the program stops
! if ierr.NE.0 on input then the program returns with ierr=1
!
! HISTORY
!
! started 2/12/15 CJS
!
! COMMENTS
!
SUBROUTINE dinvert_Gauss_Jordan(A,n,AI,dim,ierr)
USE type_specifications
USE general_module
IMPLICIT NONE
! variables passed to subroutine
integer,intent(IN) :: dim ! matrix dimension
integer,intent(IN) :: n ! size iof matrix to invert
real(dp),intent(IN) :: A(dim,dim) ! matrix to invert
real(dp),intent(OUT) :: AI(dim,dim) ! matrix inverse
integer,intent(INOUT) :: ierr
! local variables
integer :: row,col,reduce_col,i
real(dp) :: max_element
real(dp) :: pivot_element
integer :: max_row
integer :: pivot_row
integer :: pivot_row_save(dim)
real(dp) :: row_multiplier
real(dp) :: swap
! START
! copy A to AI
AI(1:n,1:n)= A(1:n,1:n)
pivot_row_save(1:dim)=0
! loop over columns of the matrix and reduce each column in turn to identity matrix column
do reduce_col=1,n
! find the largest element in this column and use as the pivot element
max_element=0d0
max_row=0
do row=reduce_col,n
if (abs(AI(row,reduce_col)).GT.max_element) then
max_element=abs(AI(row,reduce_col))
max_row=row
end if
end do
if (max_row.eq.0) then
! all elements are zero so singular matrix
if (verbose) write(*,*)'Singular matrix found in dinvert_Gauss_Jordan'
if (ierr.NE.0) then
run_status='ERROR: Singular matrix in dinvert_Gauss_Jordan'
CALL write_program_status()
STOP 1
else
ierr=1
RETURN
end if
end if
pivot_row=max_row
pivot_row_save(reduce_col)=pivot_row
! swap pivot row with the row reduce_col
if (pivot_row.ne.reduce_col) then
do col=1,n
swap=AI(reduce_col,col)
AI(reduce_col,col)=AI(pivot_row,col)
AI(pivot_row,col)=swap
end do
end if
pivot_row=reduce_col
pivot_element=AI(reduce_col,reduce_col)
! operate on pivot row
do col=1,n
if (col.ne.reduce_col) then
AI(pivot_row,col) = AI(pivot_row,col)/pivot_element
else
AI(pivot_row,col) = 1d0/pivot_element
end if
end do
! operate on rows other than the pivot row
do row=1,n
if (row.ne.pivot_row) then
row_multiplier=AI(row,reduce_col)
do col=1,n
if (col.ne.reduce_col) then
AI(row,col) = AI(row,col)- AI(pivot_row,col)*row_multiplier
else
AI(row,reduce_col) =-AI(pivot_row,reduce_col)*row_multiplier
end if
end do
end if ! not pivot row
end do ! next row
end do ! next column of the matrix to reduce
do reduce_col=n,1,-1
if (reduce_col.ne.pivot_row_save(reduce_col)) then
! rows were swapped so must swap the corresponding columns
do row=1,n
swap=AI(row,pivot_row_save(reduce_col))
AI(row,pivot_row_save(reduce_col))=AI(row,reduce_col)
AI(row,reduce_col)=swap
end do
end if
end do
ierr=0
RETURN
END SUBROUTINE dinvert_Gauss_Jordan