! ! This file is part of SACAMOS, State of the Art CAble MOdels in 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-2017 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 write_cmatrix(Mat,dim,unit) ! SUBROUTINE write_cmatrix_re(Mat,dim,unit) ! SUBROUTINE write_cmatrix_im(Mat,dim,unit) ! SUBROUTINE cinvert_Gauss_Jordan(A,n,AI,dim) ! SUBROUTINE c_condition_number (A,n,condition_number,dim) ! ! NAME ! write_cmatrix ! ! DESCRIPTION ! write complex(dp) matrix to file or screen ! ! ! HISTORY ! ! started 2/12/15 CJS ! ! COMMENTS ! SUBROUTINE write_cmatrix(Mat,dim,unit) USE type_specifications IMPLICIT NONE ! variables passed to subroutine integer,intent(IN) :: dim ! matrix dimension integer,intent(IN) :: unit ! unit to write to. Set to zero for screen output. complex(dp),intent(IN) :: Mat(dim,dim) ! matrix to write ! local variables integer row,col ! START do row=1,dim if (unit.EQ.0) then write(*,*)(Mat(row,col),col=1,dim) else write(unit,*)(Mat(row,col),col=1,dim) end if end do 8000 format(1000ES16.6) END SUBROUTINE write_cmatrix ! ! NAME ! write_cmatrix_re ! ! DESCRIPTION ! write the real part of a complex(dp) matrix to file or screen ! ! HISTORY ! ! started 2/12/15 CJS ! ! COMMENTS ! SUBROUTINE write_cmatrix_re(Mat,dim,unit) USE type_specifications IMPLICIT NONE ! variables passed to subroutine integer,intent(IN) :: dim ! matrix dimension integer,intent(IN) :: unit ! unit to write to. Set to zero for screen output. complex(dp),intent(IN) :: Mat(dim,dim) ! matrix to write ! local variables integer row,col ! START do row=1,dim if (unit.EQ.0) then write(*,*)(dble(Mat(row,col)),col=1,dim) else write(unit,*)(dble(Mat(row,col)),col=1,dim) end if end do 8000 format(20ES16.6) END SUBROUTINE write_cmatrix_re ! ! NAME ! write_cmatrix_im ! ! DESCRIPTION ! write the real part of a complex(dp) matrix to file or screen ! ! ! HISTORY ! ! started 2/12/15 CJS ! ! COMMENTS ! SUBROUTINE write_cmatrix_im(Mat,dim,unit) USE type_specifications IMPLICIT NONE ! variables passed to subroutine integer,intent(IN) :: dim ! matrix dimension integer,intent(IN) :: unit ! unit to write to. Set to zero for screen output. complex(dp),intent(IN) :: Mat(dim,dim) ! matrix to write ! local variables integer row,col ! START do row=1,dim if (unit.EQ.0) then write(*,*)(AIMAG(Mat(row,col)),col=1,dim) else write(unit,*)(AIMAG(Mat(row,col)),col=1,dim) end if end do 8000 format(20ES16.6) END SUBROUTINE write_cmatrix_im ! ! NAME ! cinvert_Gauss_Jordan ! ! DESCRIPTION ! ! Invert the complex 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 cinvert_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 of matrix to invert complex(dp),intent(IN) :: A(dim,dim) ! matrix to invert complex(dp),intent(OUT) :: AI(dim,dim) ! inverse matrix integer,intent(INOUT) :: ierr ! error code ! local variables integer :: row,col,reduce_col,i real(dp) :: max_element complex(dp) :: pivot_element integer :: max_row integer :: pivot_row integer :: pivot_row_save(dim) complex(dp) :: row_multiplier complex(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 cinvert_Gauss_Jordan' if (ierr.NE.0) then run_status='ERROR: Singular matrix in cinvert_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,0d0)/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 cinvert_Gauss_Jordan ! ! NAME ! ! ! DESCRIPTION ! ! ! HISTORY ! ! started 2/12/15 CJS ! ! COMMENTS ! SUBROUTINE c_condition_number(A,n,condition_number,dim) ! Calculate the condition number of the complex matrix A USE type_specifications USE eispack IMPLICIT NONE ! variables passed to subroutine integer,intent(IN) :: dim ! matrix dimension integer,intent(IN) :: n ! size of matrix to process complex(dp),intent(IN) :: A(dim,dim) ! input matrix real(dp),intent(OUT) :: condition_number ! output condition number ! local variables complex(dp) :: AH(dim,dim) complex(dp) :: AHA(dim,dim) real(dp) :: Real_AHA(dim,dim) real(dp) :: singular_values(dim) integer :: row,col real(dp) :: max_eigenvalue real(dp) :: min_eigenvalue logical :: matu,matv integer :: ierr ! START ! calculate the Hermitian conjugate of A do row=1,n do col=1,n AH(row,col)=conjg(A(col,row)) end do end do AHA=matmul(AH,A) Real_AHA=dble(AHA) ! calculate the Singular Value Decomposition of AHA using Eispack matu=.FALSE. matv=.FALSE. ! we don't need the matrices U or V CALL svd ( n, n, Real_AHA, singular_values, matu, Real_AHA, matv, Real_AHA, ierr ) ! find the maximum and minimum magnitude of singular values max_eigenvalue=sqrt(abs(singular_values(1))) min_eigenvalue=sqrt(abs(singular_values(1))) do row=2,n ! Note that the singular values of A are equal to the square root of the singular values of AHA max_eigenvalue=max( max_eigenvalue,sqrt(abs(singular_values(row))) ) min_eigenvalue=min( min_eigenvalue,sqrt(abs(singular_values(row))) ) end do ! calculate the condition number if (min_eigenvalue.NE.0D0) then condition_number=max_eigenvalue/min_eigenvalue else ! set the condition number to something large ***** SHOULD PROBABLY USE A PARAMETER FROM MODULE constants HERE ***** condition_number=1D100 end if RETURN END SUBROUTINE c_condition_number