MODULE EigenSolve
IMPLICIT NONE
CONTAINS
SUBROUTINE ArpackEigenSolve( Solver,Matrix,N,NEIG,EigValues,EigVectors )
USE Multigrid
IMPLICIT NONE
TYPE(Matrix_t), POINTER :: Matrix, A
TYPE(Solver_t), TARGET :: Solver
INTEGER :: N, NEIG, DPERM(n)
COMPLEX(KIND=dp) :: EigValues(:), EigVectors(:,:)
#ifdef USE_ARPACK
REAL(KIND=dp), TARGET :: WORKD(3*N), RESID(N),bb(N),xx(N)
REAL(KIND=dp), POINTER CONTIG :: x(:), b(:)
INTEGER :: IPARAM(11), IPNTR(14)
INTEGER, ALLOCATABLE :: Perm(:)
LOGICAL, ALLOCATABLE :: Choose(:)
CHARACTER(:), ALLOCATABLE :: Method
REAL(KIND=dp), ALLOCATABLE :: WORKL(:), D(:,:), WORKEV(:), V(:,:)
CHARACTER :: BMAT*1, Which*2, DirectMethod*100
INTEGER :: IDO, NCV, lWORKL, kinfo, i, j, k, l, p, IERR, iter, &
NCONV, maxitr, ishfts, mode, istat, Dofs
LOGICAL :: First, Stat, Direct = .FALSE., &
Iterative = .FALSE., NewSystem, Damped, Stability, &
NormalizeToUnity
LOGICAL :: Factorize, FreeFactorize,FoundFactorize,FoundFreeFactorize
REAL(KIND=dp) :: SigmaR, SigmaI, TOL, r
COMPLEX(KIND=dp) :: s
REAL(KIND=dp), POINTER CONTIG :: SaveValues(:), SaveRhs(:)
TYPE(ValueList_t), POINTER :: Params
CHARACTER(*), PARAMETER :: Caller = 'EigenSolve'
Params => Solver % Values
Damped = ListGetLogical( Params, 'Eigen System Damped', stat )
IF ( .NOT. stat ) Damped = .FALSE.
IF ( Damped ) THEN
CALL ArpackDampedEigenSolve( Solver, Matrix, 2*N, 2*NEIG, &
EigValues,EigVectors )
RETURN
END IF
Stability = ListGetLogical( Params, 'stability analysis', stat )
IF ( .NOT. stat ) Stability = .FALSE.
IF ( Stability ) THEN
CALL ArpackStabEigenSolve( Solver, Matrix, N, NEIG, EigValues,EigVectors )
RETURN
END IF
NCV = ListGetInteger( Params, 'Eigen System Lanczos Vectors', stat )
IF ( .NOT. stat ) NCV = 3*NEIG + 1
IF ( NCV <= NEIG ) THEN
CALL Fatal( Caller, &
'Number of Lanczos vectors must exceed the number of eigenvalues.' )
END IF
ALLOCATE( WORKL(3*NCV**2 + 6*NCV), D(NCV,3), &
WORKEV(3*NCV), V(n,NCV), CHOOSE(NCV), STAT=istat )
IF ( istat /= 0 ) THEN
CALL Fatal( Caller, 'Memory allocation error.' )
END IF
TOL = ListGetConstReal( Params, 'Eigen System Convergence Tolerance', stat )
IF ( .NOT. stat ) THEN
TOL = 100 * ListGetConstReal( Params, 'Linear System Convergence Tolerance' )
END IF
IDO = 0
kinfo = 0
lWORKL = 3*NCV**2 + 6*NCV
ishfts = 1
BMAT = 'G'
IF ( Matrix % Lumped ) THEN
Mode = 2
SELECT CASE( ListGetString(Params,'Eigen System Select',stat) )
CASE( 'smallest magnitude' )
Which = 'SM'
CASE( 'largest magnitude')
Which = 'LM'
CASE( 'smallest real part')
Which = 'SR'
CASE( 'largest real part')
Which = 'LR'
CASE( 'smallest imag part' )
Which = 'SI'
CASE( 'largest imag part' )
Which = 'LI'
CASE DEFAULT
Which = 'SM'
END SELECT
ELSE
Mode = 3
SELECT CASE( ListGetString(Params,'Eigen System Select',stat) )
CASE( 'smallest magnitude' )
Which = 'LM'
CASE( 'largest magnitude')
Which = 'SM'
CASE( 'smallest real part')
Which = 'LR'
CASE( 'largest real part')
Which = 'SR'
CASE( 'smallest imag part' )
Which = 'LI'
CASE( 'largest imag part' )
Which = 'SI'
CASE DEFAULT
Which = 'LM'
END SELECT
END IF
Maxitr = ListGetInteger( Params, 'Eigen System Max Iterations', stat )
IF ( .NOT. stat ) Maxitr = 300
IPARAM = 0
IPARAM(1) = ishfts
IPARAM(3) = maxitr
IPARAM(7) = mode
SigmaR = 0.0d0
SigmaI = 0.0d0
V = 0.0d0
Factorize = ListGetLogical( Params, &
'Linear System Refactorize', FoundFactorize )
CALL ListAddLogical( Params, 'Linear System Refactorize',.TRUE. )
FreeFactorize = ListGetLogical( Params, &
'Linear System Free Fctorization', FoundFreeFactorize )
CALL ListAddLogical( Params, &
'Linear System Free Factorization',.FALSE. )
IF ( .NOT. Matrix % Lumped ) THEN
SigmaR = ListGetConstReal( Params,'Eigen System Shift', stat )
IF ( SigmaR /= 0.0d0 ) THEN
Matrix % Values = Matrix % Values - SigmaR * Matrix % MassValues
END IF
Method = ListGetString( Params,'Linear System Solver', stat )
IF ( Method == 'direct' ) THEN
DirectMethod = ListGetString( Params, &
'Linear System Direct Method', stat )
SELECT CASE( DirectMethod )
CASE('umfpack', 'big umfpack', 'mumps', 'superlu', 'pardiso', 'cholmod')
CASE DEFAULT
Stat = CRS_ILUT(Matrix, 0.0d0)
END SELECT
END IF
END IF
iter = 1
NewSystem = .TRUE.
Iterative = ListGetString( Params, &
'Linear System Solver', stat ) == 'iterative'
stat = ListGetLogical( Params, 'No Precondition Recompute', stat )
IF ( Iterative .AND. Stat ) THEN
CALL ListAddLogical( Params, 'No Precondition Recompute', .FALSE. )
END IF
DO WHILE( ido /= 99 )
IF ( Matrix % Symmetric ) THEN
CALL DSAUPD ( ido, BMAT, n, Which, NEIG, TOL, &
RESID, NCV, V, n, IPARAM, IPNTR, WORKD, WORKL, lWORKL, kinfo )
ELSE
CALL DNAUPD ( ido, BMAT, n, Which, NEIG, TOL, &
RESID, NCV, v, n, IPARAM, IPNTR, WORKD, WORKL, lWORKL, kinfo )
END IF
IF (ido == -1 .OR. ido == 1) THEN
IF(InfoActive(20)) THEN
CALL Info(Caller,'Arpack reverse communication calls: '//I2S(iter))
ELSE
CALL Info(Caller, '.', .TRUE.)
END IF
iter = iter + 1
IF ( Matrix % Lumped ) THEN
CALL CRS_MatrixVectorMultiply( Matrix, WORKD(IPNTR(1)), WORKD(IPNTR(2)) )
DO i=0,n-1
WORKD( IPNTR(1)+i ) = WORKD( IPNTR(2)+i )
END DO
DO i=0,n-1
WORKD( IPNTR(2)+i ) = WORKD( IPNTR(1)+i ) / &
Matrix % MassValues( Matrix % Diag(i+1) )
END DO
ELSE
Dofs = Solver % Variable % Dofs
A => Matrix
x => workd(ipntr(2):ipntr(2)+n-1)
IF ( ido == -1 ) THEN
SaveValues => A % Values
A % Values => A % MassValues
CALL CRS_MatrixVectorMultiply( A, WORKD(IPNTR(1)), WORKD(IPNTR(2)) )
A % Values => SaveValues
DO i=0,n-1
WORKD( IPNTR(1)+i ) = WORKD( IPNTR(2)+i )
END DO
b => workd(ipntr(1):ipntr(1)+n-1)
ELSE
b => workd(ipntr(3):ipntr(3)+n-1)
END IF
SaveRhs => A % rhs
A % rhs => b
SELECT CASE( Method )
CASE('multigrid')
CALL MultiGridSolve( A, x, b, &
DOFs, Solver, Solver % MultiGridLevel, NewSystem )
CASE('iterative')
CALL IterSolver( A, x, b, Solver )
CASE('block')
CALL BlockSolveExt( A, x, b, Solver )
CASE ('direct')
CALL DirectSolver( A, x, b, Solver )
CASE DEFAULT
CALL Fatal(Caller,'Unknown linear system method: '//TRIM(Method))
END SELECT
A % rhs => SaveRhs
END IF
ELSE IF (ido == 2) THEN
IF ( Matrix % Lumped ) THEN
DO i=0,n-1
WORKD( IPNTR(2)+i ) = WORKD( IPNTR(1)+i ) * &
Matrix % MassValues( Matrix % Diag(i+1) )
END DO
ELSE
SaveValues => Matrix % Values
Matrix % Values => Matrix % MassValues
CALL CRS_MatrixVectorMultiply( Matrix, WORKD(IPNTR(1)), WORKD(IPNTR(2)) )
Matrix % Values => SaveValues
END IF
END IF
IF ( NewSystem .AND. ido /= 2 ) THEN
IF ( Iterative ) THEN
CALL ListAddLogical( Params, 'No Precondition Recompute', .TRUE. )
ELSE
CALL ListAddLogical( Params, 'Linear System Refactorize', .FALSE. )
END IF
NewSystem = .FALSE.
END IF
END DO
IF ( FoundFactorize ) THEN
CALL ListAddLogical( Params, 'Linear System Refactorize', Factorize )
ELSE
CALL ListRemove( Params, 'Linear System Refactorize' )
END IF
IF ( .NOT. FoundFreeFactorize ) THEN
CALL ListRemove( Params, 'Linear System Free Factorization' )
ELSE
CALL ListAddLogical( Params, 'Linear System Free Factorization', FreeFactorize )
END IF
IF ( kinfo /= 0 ) THEN
WRITE( Message, * ) 'Error with DNAUPD, info = ',kinfo
CALL Fatal( Caller, Message )
ELSE
D = 0.0d0
IF ( Matrix % Symmetric ) THEN
CALL DSEUPD ( .TRUE., 'A', Choose, D, V, N, SigmaR, &
BMAT, n, Which, NEIG, TOL, RESID, NCV, V, N, &
IPARAM, IPNTR, WORKD, WORKL, lWORKL, IERR )
ELSE
CALL DNEUPD ( .TRUE., 'A', Choose, D, D(1,2), &
V, N, SigmaR, SigmaI, WORKEV, BMAT, N, &
Which, NEIG, TOL, RESID, NCV, V, N, &
IPARAM, IPNTR, WORKD, WORKL, lWORKL, IERR )
END IF
IF (IERR /= 0) THEN
WRITE( Message, * ) ' Error with DNEUPD, info = ', IERR
CALL Fatal( Caller, Message )
END IF
IF ( kinfo == 1 ) THEN
CALL Fatal( Caller, 'Maximum number of iterations reached.' )
ELSE IF ( kinfo == 3 ) THEN
CALL Fatal( Caller, 'No shifts could be applied during implicit Arnoldi update, try increasing NCV.' )
END IF
ALLOCATE( Perm(NEIG) )
Perm = [ (i, i=1,NEIG) ]
DO i=1,NEIG
EigValues(i) = CMPLX( D(i,1), D(i,2),KIND=dp )
END DO
CALL SortC( NEIG, EigValues, Perm )
IF( MINVAL( Perm ) < 1 .OR. MAXVAL( Perm ) > NEIG ) THEN
CALL Fatal(Caller,'Reordering of EigenValues failed')
END IF
CALL Info( Caller, ' ', Level=4 )
CALL Info( Caller, 'Eigen system solution complete: ', Level=4 )
CALL Info( Caller, ' ', Level=4 )
WRITE( Message,'(A,ES12.3)') 'Convergence criterion is: ', TOL
CALL Info( Caller, Message, Level=7 )
CALL Info( Caller,'Number of converged Ritz values is: '//I2S(IPARAM(5)),Level=4)
CALL Info( Caller,'Number of update iterations taken: '//I2S(IPARAM(3)),Level=4)
CALL Info( Caller,'Computed '//I2S(NEIG)//' Eigen Values',Level=4)
IF ( SigmaR /= 0.0d0 ) THEN
Matrix % Values = Matrix % Values + SigmaR * Matrix % MassValues
END IF
k = 1
DO i=1,NEIG
p = Perm(i)
WRITE( Message,'(I0,A,2ES15.6)') i,': ',EigValues(i)
CALL Info( Caller, Message, Level=4 )
k = 1
DO j=1,p-1
IF ( D(j,2) == 0 ) THEN
k = k + 1
ELSE
k = k + 2
END IF
END DO
CALL Info(Caller,'Copying Eigenvectors to solution',Level=12)
DO j=1,N
IF ( D(p,2) /= 0.0d0 ) THEN
EigVectors(i,j) = CMPLX( V(j,k),V(j,k+1),KIND=dp )
ELSE
EigVectors(i,j) = CMPLX( V(j,k),0.0d0,KIND=dp )
END IF
END DO
END DO
IF ( ListGetLogical( Params, 'Eigen System Compute Residuals', stat ) ) THEN
CALL Info(Caller,'Computing eigen system residuals',Level=8)
CALL CheckResiduals( Matrix, Neig, EigValues, EigVectors )
END IF
CALL Info( Caller, '--------------------------------',Level=4 )
END IF
DEALLOCATE( WORKL, D, WORKEV, V, CHOOSE, Perm )
#else
CALL Fatal( Caller, 'Arpack Eigen System Solver not available!' )
#endif
END SUBROUTINE ArpackEigenSolve
SUBROUTINE ScaleEigenVectors( Matrix, EigVectors, NoEigen, NormalizeToUnity)
USE Multigrid
IMPLICIT NONE
TYPE(Matrix_t), TARGET :: Matrix
COMPLEX(KIND=dp) :: EigVectors(:,:)
INTEGER :: n, NoEigen
LOGICAL :: NormalizeToUnity
INTEGER :: i,j,k,l, mk, mj
REAL(KIND=dp) :: r
COMPLEX(KIND=dp) :: s, s1, mx
CHARACTER(*), PARAMETER :: Caller = 'ScaleEigenVectors'
CALL Info(Caller,'Scaling eigen vectors',Level=10)
n = Matrix % NumberOfRows
IF ( Matrix % Complex ) n = n / 2
DO i = 1, NoEigen
IF( Matrix % COMPLEX ) THEN
s = 0.0_dp
IF( NormalizeToUnity ) THEN
DO j=1,n
s1 = EigVectors(i,j) * CONJG(EigVectors(i,j))
IF( ABS( s1 ) > ABS( s ) ) s = s1
END DO
ELSE IF ( Matrix % Lumped ) THEN
DO j=1,n
s = s + ABS( EigVectors(i,j) )**2 * Matrix % MassValues( Matrix % Diag(2*j-1) )
END DO
ELSE
DO j=1,Matrix % NumberOfRows,2
DO l=Matrix % Rows(j),Matrix % Rows(j+1)-1,2
mx = CMPLX( Matrix % MassValues(l), -Matrix % MassValues(l+1), KIND=DP )
mj = (j-1)/2 + 1
mk = (Matrix % Cols(l)-1)/2 + 1
s = s + mx * CONJG( EigVectors(i,mj) ) * EigVectors(i,mk)
END DO
END DO
END IF
s = CMPLX( ParallelReduction( REAL(s) ), ParallelReduction( AIMAG(s) ), KIND=dp )
IF ( ABS(s) > 0 ) THEN
s = SQRT(s)
WRITE(Message,'(A,2ES12.3)') 'Normalizing Eigenvector with: ',REAL(s),AIMAG(s)
CALL Info(Caller,Message,Level=12)
EigVectors(i,1:n) = EigVectors(i,1:n) / s
ELSE
CALL Warn(Caller,'Eigenmode has zero amplitude!')
END IF
ELSE
r = 0.0_dp
IF( NormalizeToUnity ) THEN
DO j=1,n
r = MAX( r, ABS(EigVectors(i,j))**2 )
END DO
ELSE IF ( Matrix % Lumped ) THEN
DO j=1,n
r= r + ABS(EigVectors(i,j))**2 * &
Matrix % MassValues(Matrix % Diag(j))
END DO
ELSE
r = 0
DO j=1,n
DO l=Matrix % Rows(j), Matrix % Rows(j+1)-1
r = r + CONJG(EigVectors(i,j)) * Matrix % MassValues(l) * EigVectors(i,Matrix % Cols(l))
END DO
END DO
END IF
r = ParallelReduction(r)
IF( ABS(r - 1) < EPSILON( r ) ) THEN
CALL Info(Caller,'Eigenmode already normalized!',Level=12)
ELSE IF ( ABS(r) > 0 ) THEN
r = SQRT( r )
WRITE(Message,'(A,ES12.3)') 'Normalizing Eigenvector with: ',r
CALL Info(Caller,Message,Level=12)
EigVectors(i,:) = EigVectors(i,:) / r
ELSE
CALL Warn(Caller,'Eigenmode has zero amplitude!')
END IF
END IF
END DO
END SUBROUTINE ScaleEigenVectors
SUBROUTINE ExpandEigenVectors( Matrix, EigVectors, NoEigen, dofs )
USE Types
IMPLICIT NONE
TYPE(Matrix_t), TARGET :: Matrix
COMPLEX(KIND=dp) :: EigVectors(:,:)
INTEGER :: NoEigen
INTEGER :: dofs
COMPLEX(KIND=dp), ALLOCATABLE :: EigTmp(:)
INTEGER :: n,i,j,k,cdofs
COMPLEX(KIND=dp) :: s
CHARACTER(*), PARAMETER :: Caller = 'ExpandEigenVectors'
IF ( .NOT. Matrix % COMPLEX ) RETURN
CALL Info(Caller,'Expanding eigen vectors',Level=10)
n = Matrix % NumberOfRows / dofs
cdofs = dofs / 2
ALLOCATE(EigTmp(SIZE(EigVectors(1,:))))
DO i = 1, NoEigen
EigTmp = EigVectors(i,:)
DO j = 1, n
DO k = 1, cdofs
s = EigTmp(cdofs*(j-1)+k)
EigVectors(i,dofs*(j-1)+k) = REAL(s)
EigVectors(i,dofs*(j-1)+k+cdofs) = AIMAG(s)
END DO
END DO
END DO
END SUBROUTINE ExpandEigenVectors
SUBROUTINE CheckResiduals( Matrix, n, Eigs, EigVectors )
USE CRSMatrix
TYPE(Matrix_t), POINTER :: Matrix
INTEGER :: i,n,sz
COMPLEX(KIND=dp) :: Eigs(:), EigVectors(:,:)
REAL(KIND=dp), ALLOCATABLE :: x(:), y(:)
sz = Matrix % NumberOfRows
ALLOCATE( x(sz), y(sz) )
DO i=1,n
Matrix % Values = Matrix % Values - REAL(Eigs(i)) * Matrix % MassValues
x = REAL( EigVectors(i,1:sz) )
CALL CRS_MatrixVectorMultiply( Matrix, x, y )
Matrix % Values = Matrix % Values + REAL(Eigs(i)) * Matrix % MassValues
WRITE( Message, * ) 'L^2 Norm of the residual: ', i, SQRT(SUM(y**2))
CALL Info( 'CheckResiduals', Message, Level = 3 )
END DO
DEALLOCATE( x,y )
END SUBROUTINE CheckResiduals
SUBROUTINE ArpackStabEigenSolve( Solver, &
Matrix, N, NEIG, EigValues, EigVectors )
USE Multigrid
IMPLICIT NONE
TYPE(Matrix_t), POINTER :: Matrix
TYPE(Solver_t), TARGET :: Solver
INTEGER :: N, NEIG, DPERM(n)
COMPLEX(KIND=dp) :: EigValues(:), EigVectors(:,:)
#ifdef USE_ARPACK
REAL(KIND=dp), TARGET :: WORKD(3*N), RESID(N)
REAL(KIND=dp), POINTER CONTIG :: x(:), b(:)
INTEGER :: IPARAM(11), IPNTR(14)
INTEGER, ALLOCATABLE :: Perm(:)
LOGICAL, ALLOCATABLE :: Choose(:)
REAL(KIND=dp), ALLOCATABLE :: WORKL(:), D(:,:), V(:,:)
CHARACTER :: BMAT*1, Which*2, DirectMethod*200
INTEGER :: IDO, NCV, lWORKL, kinfo, i, j, k, l, p, IERR, iter, &
NCONV, maxitr, ishfts, mode, istat
LOGICAL :: First, Stat, Direct = .FALSE., FactorizeSetting, &
Iterative = .FALSE., NewSystem, &
rvec = .TRUE.
LOGICAL :: Factorize, FreeFactorize,FoundFactorize,FoundFreeFactorize
REAL(KIND=dp) :: SigmaR, SigmaI, TOL
COMPLEX(KIND=dp) :: s
REAL(KIND=dp), POINTER CONTIG :: SaveValues(:)
CHARACTER(*), PARAMETER :: Caller = 'StabEigenSolve'
IF ( Matrix % Lumped ) THEN
CALL Error(Caller,'Lumped matrices are not allowed in stability analysis.' )
END IF
NCV = 3 * NEIG + 1
lWORKL = NCV*(NCV+8)
ALLOCATE( WORKL(lWORKL), D(NCV,2), V(N,NCV), CHOOSE(NCV), STAT=istat )
IF ( istat /= 0 ) THEN
CALL Fatal(Caller, 'Memory allocation error.' )
END IF
TOL = ListGetConstReal( Solver % Values, 'Eigen System Convergence Tolerance', stat )
IF ( .NOT. stat ) THEN
TOL = 100 * ListGetConstReal( Solver % Values, 'Linear System Convergence Tolerance' )
END IF
IDO = 0
kinfo = 0
ishfts = 1
BMAT = 'G'
Mode = 2
SELECT CASE( ListGetString( Solver % Values,'Eigen System Select', stat ) )
CASE( 'smallest magnitude' )
Which = 'LM'
CASE( 'largest magnitude')
Which = 'SM'
CASE( 'smallest real part')
Which = 'LR'
CASE( 'largest real part')
Which = 'SR'
CASE( 'smallest imag part' )
Which = 'LI'
CASE( 'largest imag part' )
Which = 'SI'
CASE( 'smallest algebraic' )
Which = 'LA'
CASE( 'largest algebraic' )
Which = 'SA'
CASE DEFAULT
Which = 'LM'
END SELECT
Maxitr = ListGetInteger( Solver % Values, 'Eigen System Max Iterations', stat )
IF ( .NOT. stat ) Maxitr = 300
IPARAM = 0
IPARAM(1) = ishfts
IPARAM(3) = maxitr
IPARAM(7) = mode
SigmaR = 0.0d0
SigmaI = 0.0d0
V = 0.0d0
D = 0.0d0
Factorize = ListGetLogical( Solver % Values, &
'Linear System Refactorize', FoundFactorize )
CALL ListAddLogical( Solver % Values, 'Linear System Refactorize',.TRUE. )
FreeFactorize = ListGetLogical( Solver % Values, &
'Linear System Refactorize', FoundFreeFactorize )
CALL ListAddLogical( Solver % Values, &
'Linear System Free Factorization',.FALSE. )
Direct = ListGetString( Solver % Values, &
'Linear System Solver', stat ) == 'direct'
IF ( Direct ) THEN
DirectMethod = ListGetString( Solver % Values, &
'Linear System Direct Method', stat )
SELECT CASE( DirectMethod )
CASE('umfpack', 'big umfpack','mumps', 'superlu', 'pardiso', 'cholmod' )
CASE DEFAULT
Stat = CRS_ILUT(Matrix, 0.0d0)
END SELECT
END IF
Iterative = ListGetString( Solver % Values, &
'Linear System Solver', stat ) == 'iterative'
stat = ListGetLogical( Solver % Values, 'No Precondition Recompute', stat )
IF ( Iterative .AND. Stat ) THEN
CALL ListAddLogical( Solver % Values, 'No Precondition Recompute', .FALSE. )
END IF
iter = 1
NewSystem = .TRUE.
DO WHILE( ido /= 99 )
CALL DSAUPD( ido, BMAT, n, Which, NEIG, TOL, &
RESID, NCV, V, n, IPARAM, IPNTR, WORKD, WORKL, lWORKL, kinfo )
IF( ido==-1 .OR. ido==1 ) THEN
IF(InfoActive(20)) THEN
CALL Info(Caller,'Arpack reverse communication calls: '//I2S(iter))
ELSE
CALL Info(Caller, '.', .TRUE.)
END IF
iter = iter + 1
END IF
SELECT CASE( ido )
CASE( -1, 1 )
SaveValues => Matrix % Values
Matrix % Values => Matrix % MassValues
CALL CRS_MatrixVectorMultiply( Matrix, WORKD(IPNTR(1)), WORKD(IPNTR(2)) )
Matrix % Values => SaveValues
DO i=0,n-1
WORKD( IPNTR(1)+i ) = WORKD( IPNTR(2)+i )
END DO
IF ( Direct ) THEN
CALL DirectSolver( Matrix,WORKD(IPNTR(2)),WORKD(IPNTR(1)), Solver )
ELSE
x => workd(ipntr(2):ipntr(2)+n-1)
b => workd(ipntr(1):ipntr(1)+n-1)
IF ( Solver % MultiGridSolver ) THEN
CALL MultiGridSolve( Matrix, x, b, Solver % Variable % DOFs, &
Solver, Solver % MultiGridLevel, NewSystem )
ELSE
CALL IterSolver( Matrix, x, b, Solver )
END IF
END IF
CASE( 2 )
CALL CRS_MatrixVectorMultiply( Matrix, WORKD(IPNTR(1)), WORKD(IPNTR(2)) )
END SELECT
IF ( NewSystem .AND. ido /= 2 ) THEN
IF ( Iterative ) THEN
CALL ListAddLogical( Solver % Values, 'No Precondition Recompute', .TRUE. )
ELSE
CALL ListAddLogical( Solver % Values, 'Linear System Refactorize', .FALSE. )
END IF
NewSystem = .FALSE.
END IF
END DO
IF ( FoundFactorize ) THEN
CALL ListAddLogical( Solver % Values, 'Linear System Refactorize', Factorize )
ELSE
CALL ListRemove( Solver % Values, 'Linear System Refactorize' )
END IF
IF ( .NOT. FoundFreeFactorize ) THEN
CALL ListRemove( Solver % Values, 'Linear System Free Factorization' )
ELSE
CALL ListAddLogical( Solver % Values, 'Linear System Free Factorization', FreeFactorize )
END IF
IF ( kinfo /= 0 ) THEN
WRITE( Message, * ) 'Error with DSAUPD, info = ',kinfo
CALL Fatal( 'StabEigenSolve', Message )
ELSE
D = 0.0d0
rvec = .TRUE.
CALL DSEUPD ( rvec, 'A', Choose, D, V, N, SigmaR, &
BMAT, n, Which, NEIG, TOL, RESID, NCV, V, N, &
IPARAM, IPNTR, WORKD, WORKL, lWORKL, IERR )
IF (IERR /= 0) THEN
WRITE( Message, * ) ' Error with DSEUPD, info = ', IERR
CALL Fatal( Caller, Message )
END IF
IF ( kinfo == 1 ) THEN
CALL Fatal( Caller, 'Maximum number of iterations reached.' )
ELSE IF ( kinfo == 3 ) THEN
CALL Fatal( Caller, 'No shifts could be applied during implicit Arnoldi update, try increasing NCV.' )
END IF
ALLOCATE( Perm(NEIG) )
Perm = [ (i, i=1,NEIG) ]
DO i=1,NEIG
EigValues(i) = CMPLX( 1.0d0 / D(i,1), D(i,2),KIND=dp )
END DO
CALL SortC( NEIG, EigValues, Perm )
CALL Info( Caller, ' ', Level=4 )
CALL Info( Caller, 'EIGEN SYSTEM SOLUTION COMPLETE: ', Level=4 )
CALL Info( Caller, ' ', Level=4 )
WRITE( Message,'(A,ES12.3)') 'Convergence criterion is: ', TOL
CALL Info( Caller, Message, Level=7 )
CALL Info( Caller,'Number of converged Ritz values is: '//I2S(IPARAM(5)),Level=4)
CALL Info( Caller, ' ', Level=7 )
CALL Info( Caller, 'Computed Eigen Values: ', Level=4 )
CALL Info( Caller, '--------------------------------', Level=7 )
k = 1
DO i=1,NEIG
p = Perm(i)
WRITE( Message, * ) i,EigValues(i)
CALL Info( Caller, Message, Level=4 )
k = 1
DO j=1,p-1
IF ( D(j,2) == 0 ) THEN
k = k + 1
ELSE
k = k + 2
END IF
END DO
DO j=1,N
IF ( D(p,2) /= 0.0d0 ) THEN
EigVectors(i,j) = CMPLX( V(j,k),V(j,k+1),KIND=dp )
ELSE
EigVectors(i,j) = CMPLX( V(j,k),0.0d0,KIND=dp )
END IF
END DO
END DO
CALL Info( Caller, '--------------------------------',Level=4 )
END IF
DO i = 1,Neig
IF( REAL(EigValues(i)) < 0.0d0 ) THEN
EigVectors(i,:) = EigVectors(i,:) * CMPLX(0.0d0,1.0d0,KIND=dp)
END IF
END DO
DEALLOCATE( WORKL, D, V, CHOOSE, Perm )
#else
CALL Fatal( Caller, 'Arpack Eigen System Solver not available!' )
#endif
END SUBROUTINE ArpackStabEigenSolve
SUBROUTINE ArpackEigenSolveComplex( Solver,Matrix,N,NEIG, &
EigValues, EigVectors )
USE Multigrid
IMPLICIT NONE
TYPE(Matrix_t), POINTER :: Matrix, A
TYPE(Solver_t), TARGET :: Solver
INTEGER :: N, NEIG, DPERM(n)
COMPLEX(KIND=dp) :: EigValues(:), EigVectors(:,:)
#ifdef USE_ARPACK
COMPLEX(KIND=dp) :: WORKD(3*N), RESID(N)
INTEGER :: IPARAM(11), IPNTR(14)
INTEGER, ALLOCATABLE :: Perm(:)
LOGICAL, ALLOCATABLE :: Choose(:)
COMPLEX(KIND=dp), ALLOCATABLE :: WORKL(:), D(:), WORKEV(:), V(:,:)
CHARACTER :: BMAT*1, Which*2
INTEGER :: IDO, NCV, lWORKL, kinfo, i, j, k, l, p, IERR, iter, &
NCONV, maxitr, ishfts, mode, istat, dofs
LOGICAL :: First, Stat, Direct = .FALSE., FoundFactorize,&
Iterative = .FALSE., NewSystem, Factorize, FreeFactorize, FoundFreeFactorize
CHARACTER(:), ALLOCATABLE :: DirectMethod, Method
COMPLEX(KIND=dp) :: Sigma = 0.0d0, s
REAL(KIND=dp), TARGET :: x(2*n), b(2*n)
REAL(KIND=dp) :: SigmaR, SigmaI, TOL, RWORK(N)
REAL(KIND=dp), POINTER CONTIG :: SaveValues(:), SaveRhs(:)
TYPE(ValueList_t), POINTER :: Params
CHARACTER(*), PARAMETER :: Caller = 'EigenSolveComplex'
CALL Info(Caller,'Starting eigen system solution with complex matrices!',Level=6)
Params => Solver % Values
NCV = ListGetInteger( Params, 'Eigen System Lanczos Vectors', stat )
IF ( .NOT. stat ) NCV = 3*NEIG + 1
IF ( NCV <= NEIG ) THEN
CALL Fatal( 'EigenSolve', &
'Number of Lanczos vectors must exceed the number of eigenvalues.' )
END IF
ALLOCATE( WORKL(3*NCV**2 + 6*NCV), D(NCV), &
WORKEV(3*NCV), V(n,NCV+1), CHOOSE(NCV), STAT=istat )
IF ( istat /= 0 ) THEN
CALL Fatal(Caller, 'Memory allocation error.' )
END IF
TOL = ListGetConstReal( Solver % Values, 'Eigen System Convergence Tolerance', stat )
IF ( .NOT. stat ) THEN
TOL = 100 * ListGetConstReal( Solver % Values, 'Linear System Convergence Tolerance' )
END IF
lWORKL = 3*NCV**2 + 6*NCV
IDO = 0
kinfo = 0
ishfts = 1
BMAT = 'G'
IF ( Matrix % Lumped ) THEN
Mode = 2
SELECT CASE(ListGetString( Solver % Values, 'Eigen System Select',stat) )
CASE( 'smallest magnitude' )
Which = 'SM'
CASE( 'largest magnitude')
Which = 'LM'
CASE( 'smallest real part')
Which = 'SR'
CASE( 'largest real part')
Which = 'LR'
CASE( 'smallest imag part' )
Which = 'SI'
CASE( 'largest imag part' )
Which = 'LI'
CASE DEFAULT
Which = 'SM'
END SELECT
ELSE
Mode = 3
SELECT CASE(ListGetString( Solver % Values, 'Eigen System Select',stat) )
CASE( 'smallest magnitude' )
Which = 'LM'
CASE( 'largest magnitude')
Which = 'SM'
CASE( 'smallest real part')
Which = 'LR'
CASE( 'largest real part')
Which = 'SR'
CASE( 'smallest imag part' )
Which = 'LI'
CASE( 'largest imag part' )
Which = 'SI'
CASE DEFAULT
Which = 'LM'
END SELECT
END IF
Maxitr = ListGetInteger( Solver % Values, 'Eigen System Max Iterations', stat )
IF ( .NOT. stat ) Maxitr = 300
IPARAM = 0
IPARAM(1) = ishfts
IPARAM(3) = maxitr
IPARAM(7) = mode
SigmaR = 0
SigmaI = 0
V = 0
Factorize = ListGetLogical( Params, &
'Linear System Refactorize', FoundFactorize )
CALL ListAddLogical( Params, 'Linear System Refactorize',.TRUE. )
FreeFactorize = ListGetLogical( Params, &
'Linear System Refactorize', FoundFreeFactorize )
CALL ListAddLogical( Params, &
'Linear System Free Factorization',.FALSE. )
IF ( .NOT. Matrix % Lumped ) THEN
SigmaR = ListGetConstReal( Params,'Eigen System Shift', stat )
SigmaI = ListGetConstReal( Params,'Eigen System Shift Im', stat )
Sigma = CMPLX(SigmaR,SigmaI)
IF ( Sigma /= 0._dp ) THEN
Matrix % Values = Matrix % Values - Sigma * Matrix % MassValues
END IF
Method = ListGetString( Params,'Linear System Solver', stat )
IF ( Method == 'direct' ) THEN
DirectMethod = ListGetString( Params, &
'Linear System Direct Method', stat )
SELECT CASE( DirectMethod )
CASE('umfpack', 'big umfpack', 'mumps', 'superlu', 'pardiso', 'cholmod')
CASE DEFAULT
Stat = CRS_ComplexILUT(Matrix, 0._dp)
END SELECT
END IF
END IF
iter = 1
NewSystem = .TRUE.
Iterative = ListGetString( Solver % Values, &
'Linear System Solver', stat ) == 'iterative'
stat = ListGetLogical( Solver % Values, 'No Precondition Recompute', stat )
IF ( Iterative .AND. Stat ) THEN
CALL ListAddLogical( Solver % Values, 'No Precondition Recompute', .FALSE. )
END IF
A => Matrix
DO WHILE( ido /= 99 )
CALL ZNAUPD ( ido, BMAT, n, Which, NEIG, TOL, &
RESID, NCV, v, n, IPARAM, IPNTR, WORKD, WORKL, lWORKL, RWORK, kinfo )
IF (ido == -1 .OR. ido == 1) THEN
IF(InfoActive(20)) THEN
CALL Info(Caller,'Arpack reverse communication calls: '//I2S(iter))
ELSE
CALL Info(Caller, '.', .TRUE.)
END IF
Iter = Iter + 1
SaveRhs => A % rhs
A % rhs => b
Dofs = Solver % Variable % Dofs
IF ( ido == -1 ) THEN
SaveValues => A % Values
A % Values => A % MassValues
CALL CRS_ComplexMatrixVectorMultiply( A, WORKD(IPNTR(1)), WORKD(IPNTR(2)) )
A % Values => SaveValues
DO i=0,n-1
b(2*i+1) = REAL( WORKD( IPNTR(2)+i ) )
b(2*i+2) = AIMAG( WORKD( IPNTR(2)+i ) )
END DO
ELSE
DO i=0,n-1
b(2*i+1) = REAL( WORKD( IPNTR(3)+i ) )
b(2*i+2) = AIMAG( WORKD( IPNTR(3)+i ) )
END DO
END IF
DO i=0,n-1
x(2*i+1) = REAL( WORKD( IPNTR(2)+i ) )
x(2*i+2) = AIMAG( WORKD( IPNTR(2)+i ) )
END DO
SELECT CASE( Method )
CASE('multigrid')
CALL MultiGridSolve( A, x, b, &
DOFs, Solver, Solver % MultiGridLevel, NewSystem )
CASE('iterative')
CALL IterSolver( A, x, b, Solver )
CASE('block')
CALL BlockSolveExt( A, x, b, Solver )
CASE ('direct')
CALL DirectSolver( A, x, b, Solver )
CASE DEFAULT
CALL Fatal(Caller,'Unknown linear system method: '//TRIM(Method))
END SELECT
A % rhs => SaveRhs
DO i=0,n-1
WORKD( IPNTR(2)+i ) = CMPLX( x(2*i+1), x(2*i+2),KIND=dp )
END DO
ELSE IF (ido == 2) THEN
SaveValues => A % Values
A % Values => A % MassValues
CALL CRS_ComplexMatrixVectorMultiply(A, WORKD(IPNTR(1)), WORKD(IPNTR(2)) )
A % Values => SaveValues
END IF
IF ( NewSystem .AND. ido /= 2 ) THEN
IF ( Iterative ) THEN
CALL ListAddLogical( Solver % Values, 'No Precondition Recompute', .TRUE. )
ELSE
CALL ListAddLogical( Solver % Values, 'Linear System Refactorize', .FALSE. )
END IF
NewSystem = .FALSE.
END IF
END DO
CALL ListAddLogical( Solver % Values, 'Linear System Refactorize', .TRUE. )
CALL ListAddLogical( Solver % Values, &
'Linear System Free Factorization', .TRUE. )
IF ( kinfo /= 0 ) THEN
WRITE( Message, * ) 'Error with DNAUPD, info = ',kinfo
CALL Fatal( Caller, Message )
ELSE
D = 0.0d0
CALL ZNEUPD ( .TRUE., 'A', Choose, D, V, N, Sigma, WORKEV, BMAT, N, Which, NEIG, &
TOL, RESID, NCV, V, N, IPARAM, IPNTR, WORKD, WORKL, lWORKL, RWORK, IERR )
IF (IERR /= 0) THEN
WRITE( Message, * ) ' Error with DNEUPD, info = ', IERR
CALL Fatal( Caller, Message )
END IF
IF ( kinfo == 1 ) THEN
CALL Fatal( Caller, 'Maximum number of iterations reached.' )
ELSE IF ( kinfo == 3 ) THEN
CALL Fatal( Caller, 'No shifts could be applied during implicit Arnoldi update, try increasing NCV.' )
END IF
ALLOCATE( Perm(NEIG) )
Perm = [ (i, i=1,NEIG) ]
DO i=1,NEIG
EigValues(i) = D(i)
END DO
CALL SortC( NEIG, EigValues, Perm )
CALL Info( Caller, ' ', Level=4 )
CALL Info( Caller, 'EIGEN SYSTEM SOLUTION COMPLETE: ', Level=4 )
CALL Info( Caller, ' ', Level=4 )
WRITE( Message,'(A,ES12.3)') 'Convergence criterion is: ', TOL
CALL Info( Caller, Message, Level=7 )
CALL Info( Caller,'Number of converged Ritz values is: '//I2S(IPARAM(5)),Level=4)
CALL Info( Caller, ' ', Level=7 )
CALL Info( Caller, 'Computed Eigen Values: ', Level=4 )
CALL Info( Caller, '--------------------------------', Level=7 )
IF ( Sigma /= 0._dp ) THEN
Matrix % Values = Matrix % Values + Sigma * Matrix % MassValues
END IF
EigVectors = -1.0_dp
k = 1
DO i=1,NEIG
p = Perm(i)
WRITE( Message, * ) i,EigValues(i)
CALL Info( Caller, Message, Level=4 )
DO j=1,N
EigVectors(i,j) = V(j,p)
END DO
END DO
IF ( ListGetLogical( Params, 'Eigen System Compute Residuals', stat ) ) THEN
CALL Info(Caller,'Computing eigen system residuals',Level=8)
CALL CheckResidualsComplex( Matrix, Neig, EigValues, EigVectors )
END IF
CALL Info( Caller, '--------------------------------',Level=4 )
END IF
DEALLOCATE( WORKL, D, WORKEV, V, CHOOSE, Perm )
CALL Info(Caller,'Finished eigen system solution!',Level=8)
#else
CALL Fatal( Caller, 'Arpack Eigen System Solver not available!' )
#endif
END SUBROUTINE ArpackEigenSolveComplex
SUBROUTINE CheckResidualsComplex( Matrix, n, Eigs, EigVectors )
USE CRSMatrix
TYPE(Matrix_t), POINTER :: Matrix
INTEGER :: i,j,k,n,sz
COMPLEX(KIND=dp) :: Eigs(:), EigVectors(:,:)
REAL(KIND=dp), ALLOCATABLE, TARGET :: vals(:)
REAL(KIND=dp), POINTER CONTIG :: svals(:)
COMPLEX(KIND=dp) :: c,m
COMPLEX(KIND=dp), ALLOCATABLE :: x(:), y(:)
sz = Matrix % NumberOfRows/2
ALLOCATE( x(sz), y(sz), vals(size(matrix % values)) ); vals=0
DO i=1,n
DO j=1,sz
DO k=Matrix % Rows(2*j-1), Matrix % Rows(2*j)-1,2
c = CMPLX(Matrix % Values(k), -Matrix % Values(k+1),KIND=dp)
m = CMPLX(Matrix % MassValues(k), -Matrix% MassValues(k+1),KIND=dp)
c = c - eigs(i) * m
vals(k) = REAL(c)
vals(k+1) = -AIMAG(c)
END DO
END DO
x = EigVectors(i,:)
svals => Matrix % Values
Matrix % Values => vals
CALL CRS_ComplexMatrixVectorMultiply( Matrix, x, y )
Matrix % Values => svals
WRITE( Message, * ) 'L^2 Norm of the residual: ', i, SQRT(SUM(ABS(y)**2))
CALL Info( 'CheckResidualsComplex', Message, Level = 3 )
END DO
DEALLOCATE( x,y )
END SUBROUTINE CheckResidualsComplex
SUBROUTINE ArpackDampedEigenSolve( Solver, KMatrix, N, NEIG, EigValues, &
EigVectors )
USE Multigrid
USE ElementUtils
IMPLICIT NONE
TYPE(Matrix_t), POINTER :: KMatrix
TYPE(Solver_t), TARGET :: Solver
INTEGER :: N, NEIG, DPERM(n)
COMPLEX(KIND=dp) :: EigValues(:), EigVectors(:,:)
#ifdef USE_ARPACK
TYPE(Matrix_t), POINTER :: MMatrix, BMatrix
REAL(KIND=dp), TARGET :: WORKD(3*N), RESID(N)
REAL(KIND=dp), POINTER CONTIG :: x(:), b(:)
INTEGER :: IPARAM(11), IPNTR(14)
INTEGER, ALLOCATABLE :: Perm(:), kMap(:)
LOGICAL, ALLOCATABLE :: Choose(:)
CHARACTER(:), ALLOCATABLE :: str
COMPLEX(KIND=dp) :: s, EigTemp(NEIG)
REAL(KIND=dp), ALLOCATABLE :: WORKL(:), D(:,:), WORKEV(:), V(:,:)
CHARACTER :: BMAT*1, Which*2
INTEGER :: IDO, NCV, lWORKL, kinfo, i, j, k, l, p, IERR, iter, &
NCONV, maxitr, ishfts, mode, istat, DampedMaxIter, ILU
LOGICAL :: First, Stat, NewSystem, UseI = .FALSE.
REAL(KIND=dp) :: SigmaR, SigmaI, TOL, DampedTOL, IScale
CHARACTER(*), PARAMETER :: Caller = 'DampedEigenSolve'
IF ( KMatrix % Lumped ) THEN
CALL Error( Caller, 'Lumped matrixes are not allowed' )
END IF
IF ( ListGetString( Solver % Values, 'Linear System Solver', Stat ) &
== 'direct' ) THEN
CALL Error( Caller, 'Direct solver is not allowed' )
END IF
IF ( Solver % MultiGridSolver ) THEN
CALL Error( Caller, 'MultiGrid solver is not allowed' )
END IF
Stat = ListGetLogical( Solver % Values, &
'No Precondition Recompute', Stat )
IF ( Stat ) THEN
CALL ListAddLogical( Solver % Values, &
'No Precondition Recompute', .FALSE. )
END IF
NCV = 3 * NEIG + 1
ALLOCATE( WORKL(3*NCV**2 + 6*NCV), D(NCV,3), &
WORKEV(3*NCV), V(n,NCV), CHOOSE(NCV), STAT=istat )
CHOOSE = .FALSE.
Workl = 0.0d0
workev = 0.0d0
v = 0.0d0
d = 0.0d0
IF ( istat /= 0 ) THEN
CALL Fatal( Caller, 'Memory allocation error.' )
END IF
TOL = ListGetConstReal( Solver % Values, &
'Eigen System Convergence Tolerance', Stat )
IF ( .NOT. Stat ) THEN
TOL = 100 * ListGetConstReal( Solver % Values, &
'Linear System Convergence Tolerance' )
END IF
DampedMaxIter = ListGetInteger( Solver % Values, &
'Linear System Max Iterations', Stat, 1 )
IF ( .NOT. Stat ) DampedMaxIter = 100
DampedTOL = ListGetConstReal( Solver % Values, &
'Linear System Convergence Tolerance', Stat )
IF ( .NOT. Stat ) DampedTOL = TOL / 100
UseI = ListGetLogical( Solver % Values, &
'Eigen System Use Identity', Stat )
IF ( .NOT. Stat ) UseI = .TRUE.
IDO = 0
kinfo = 0
lWORKL = 3*NCV**2 + 6*NCV
ishfts = 1
BMAT = 'G'
Mode = 3
SELECT CASE( ListGetString(Solver % Values, 'Eigen System Select',Stat) )
CASE( 'smallest magnitude' )
Which = 'LM'
CASE( 'largest magnitude')
Which = 'SM'
CASE( 'smallest real part')
Which = 'LR'
CASE( 'largest real part')
Which = 'SR'
CASE( 'smallest imag part' )
Which = 'LI'
CASE( 'largest imag part' )
Which = 'SI'
CASE DEFAULT
Which = 'LM'
END SELECT
Maxitr = ListGetInteger(Solver % Values,'Eigen System Max Iterations',Stat)
IF ( .NOT. Stat ) Maxitr = 300
IPARAM = 0
IPARAM(1) = ishfts
IPARAM(3) = maxitr
IPARAM(7) = mode
SigmaR = 0.0d0
SigmaI = 0.0d0
V = 0.0d0
MMatrix => AllocateMatrix()
MMatrix % Values => KMatrix % MassValues
MMatrix % NumberOfRows = KMatrix % NumberOfRows
MMatrix % Rows => KMatrix % Rows
MMatrix % Cols => KMatrix % Cols
MMatrix % Diag => KMatrix % Diag
IScale = MAXVAL( ABS( MMatrix % Values ) )
BMatrix => AllocateMatrix()
BMatrix % NumberOfRows = KMatrix % NumberOfRows
BMatrix % Rows => KMatrix % Rows
BMatrix % Cols => KMatrix % Cols
BMatrix % Diag => KMatrix % Diag
BMatrix % Values => KMatrix % DampValues
str = ListGetString( Solver % Values, 'Linear System Preconditioning', Stat )
ILU = 0
IF ( .NOT. Stat ) THEN
CALL Warn( Caller, 'Using ILU0 preconditioning' )
ELSE
IF ( str == 'none' .OR. str == 'diagonal' .OR. &
str == 'ilut' .OR. str == 'multigrid' ) THEN
ILU = 0
CALL Warn( Caller, 'Useing ILU0 preconditioning' )
ELSE IF ( SEQL(str,'ilu') ) THEN
IF(LEN(str)>=4) ILU = ICHAR(str(4:4)) - ICHAR('0')
IF ( ILU < 0 .OR. ILU > 9 ) ILU = 0
ELSE
ILU = 0
CALL Warn( Caller,'Unknown preconditioner type, using ILU0' )
END IF
END IF
KMatrix % Cholesky = ListGetLogical( Solver % Values, &
'Linear System Symmetric ILU', Stat )
Stat = CRS_IncompleteLU( KMatrix, ILU, Solver % Values )
IF ( .NOT. UseI ) Stat = CRS_IncompleteLU( MMatrix, ILU, Solver % Values )
iter = 1
DO WHILE( ido /= 99 )
CALL DNAUPD ( ido, BMAT, n, Which, NEIG, TOL, RESID, NCV, v, n, &
IPARAM, IPNTR, WORKD, WORKL, lWORKL, kinfo )
SELECT CASE(ido)
CASE(-1 )
x => workd( ipntr(1) : ipntr(1)+n-1 )
b => workd( ipntr(2) : ipntr(2)+n-1 )
CALL EigenMGmv2( n/2, MMatrix, x, b, UseI, IScale )
DO i=1,n
x(i) = b(i)
END DO
CALL EigenBiCG( n, KMatrix, MMatrix, BMatrix, &
b, x, DampedMaxIter, DampedTOL, UseI, IScale )
CASE( 1 )
IF(InfoActive(20)) THEN
CALL Info(Caller,'Arpack reverse communication calls: '//I2S(iter))
ELSE
CALL Info(Caller, '.', .TRUE.)
END IF
iter = iter + 1
x => workd( ipntr(2) : ipntr(2)+n-1 )
b => workd( ipntr(3) : ipntr(3)+n-1 )
CALL EigenBiCG( n, KMatrix, MMatrix, BMatrix, &
x, b, DampedMaxIter, DampedTOL, UseI,IScale )
CASE( 2 )
x => workd( ipntr(1): ipntr(1)+n-1 )
b => workd( ipntr(2): ipntr(2)+n-1 )
CALL EigenMGmv2( N/2, MMatrix, x, b, UseI, IScale )
CASE DEFAULT
END SELECT
END DO
IF ( kinfo /= 0 ) THEN
WRITE( Message, * ) 'Error with DNAUPD, info = ',kinfo
CALL Fatal( Caller, Message )
ELSE
D = 0.0d0
CALL DNEUPD ( .TRUE., 'A', Choose, D, D(1,2), V, N, SigmaR, SigmaI, &
WORKEV, BMAT, N, Which, NEIG, TOL, RESID, NCV, V, N, IPARAM, IPNTR, &
WORKD, WORKL, lWORKL, IERR )
IF ( IERR /= 0 ) THEN
WRITE( Message, * ) ' Error with DNEUPD, info = ', IERR
CALL Fatal( Caller, Message )
END IF
IF ( kinfo == 1 ) THEN
CALL Fatal( Caller, 'Maximum number of iterations reached.' )
ELSE IF ( kinfo == 3 ) THEN
CALL Fatal( Caller, &
'No shifts could be applied during implicit Arnoldi update, try increasing NCV.' )
END IF
DO i = 1, NEIG
EigTemp(i) = CMPLX( D(i,1), D(i,2), KIND=dp )
END DO
ALLOCATE( kMap( NEIG ) )
kMap(1) = 1
DO i = 2, NEIG
IF ( AIMAG( EigTemp(i-1) ) == 0 ) THEN
kMap(i) = kMap(i-1) + 1
ELSE IF ( EigTemp(i) == CONJG( EigTemp(i-1) ) ) THEN
kMap(i) = kMap(i-1)
ELSE
kMap(i) = kMap(i-1) + 2
END IF
END DO
ALLOCATE( Perm( NEIG ) )
Perm = [ (i, i=1,NEIG) ]
CALL SortC( NEIG, EigTemp, Perm )
CALL Info( Caller, ' ', Level=4 )
CALL Info( Caller, 'EIGEN SYSTEM SOLUTION COMPLETE: ', Level=4 )
CALL Info( Caller, ' ', Level=4 )
WRITE( Message,'(A,ES12.3)') 'Convergence criterion is: ', TOL
CALL Info( Caller, Message, Level=7 )
CALL Info(Caller,'Number of converged Ritz values is: '//I2S(IPARAM(5)),Level=4)
CALL Info( Caller, ' ', Level=7 )
CALL Info( Caller, 'Computed Eigen Values: ', Level=4 )
CALL Info( Caller, '--------------------------------', Level=7 )
EigValues(1) = EigTemp(1)
WRITE( Message, * ) 1,EigValues(1)
CALL Info( Caller, Message, Level=4 )
p = Perm(1)
k = kMap(p)
IF( AIMAG( EigValues(1) ) == 0 ) THEN
DO j = 1, N/2
EigVectors(1,j) = CMPLX( V(j,k), 0.0d0,KIND=dp )
END DO
ELSE
DO j = 1, N/2
EigVectors(1,j) = CMPLX( V(j,k), V(j,k+1),KIND=dp )
END DO
END IF
l = 2
DO i = 2, NEIG/2
IF ( AIMAG( EigValues(i-1) ) /= 0 .AND. &
ABS(AIMAG(EigTemp(l))) == ABS(AIMAG(EigValues(i-1)))) l=l+1
EigValues(i) = EigTemp(l)
IF ( AIMAG( EigValues(i) ) < 0 ) THEN
EigValues(i) = CONJG( EigValues(i) )
END IF
WRITE( Message, * ) i,EigValues(i)
CALL Info( Caller, Message, Level=4 )
p = Perm(l)
k = kMap(p)
IF( AIMAG( EigValues(i) ) == 0 ) THEN
DO j = 1, N/2
EigVectors(i,j) = CMPLX( V(j,k), 0.0d0,KIND=dp )
END DO
ELSE
DO j = 1, N/2
EigVectors(i,j) = CMPLX( V(j,k), V(j,k+1),KIND=dp )
END DO
END IF
l = l + 1
END DO
DO i = 1, NEIG/2
s = 0.0d0
DO j=1,N/2
DO k = MMatrix % Rows(j), MMatrix % Rows(j+1)-1
s = s + MMatrix % Values(k) * &
CONJG( EigVectors(i,j) ) * EigVectors(i,MMatrix % Cols(k))
END DO
END DO
IF ( ABS(s) > 0 ) EigVectors(i,:) = EigVectors(i,:) / SQRT(s)
END DO
CALL Warn(Caller,'Check that the scaling is not done twice if you call this!')
CALL Info( Caller, '--------------------------------',Level=4 )
END IF
DEALLOCATE( WORKL, D, WORKEV, V, CHOOSE, Perm )
NULLIFY( MMatrix % Rows, MMatrix % Cols, MMatrix % Diag, MMatrix % Values )
CALL FreeMatrix( MMatrix )
NULLIFY( BMatrix % Rows, BMatrix % Cols, BMatrix % Diag, BMatrix % Values )
CALL FreeMatrix( BMatrix )
#else
CALL Fatal( Caller, 'Arpack Eigen System Solver not available!' )
#endif
END SUBROUTINE ArpackDampedEigenSolve
SUBROUTINE EigenBiCG( n, KMatrix, MMatrix, BMatrix, x, b, Rounds, TOL, UseI, IScale )
USE CRSMatrix
TYPE(Matrix_t), POINTER :: KMatrix, MMatrix, BMatrix
INTEGER :: Rounds
REAL(KIND=dp) :: TOL, IScale
REAL(KIND=dp) CONTIG :: x(:), b(:)
LOGICAL :: UseI
INTEGER :: i, n
REAL(KIND=dp) :: alpha, beta, omega, rho, oldrho, bnorm
REAL(KIND=dp) :: r(n), Ri(n), P(n), V(n), S(n), &
T(n), T1(n), T2(n), Tmp(n/2)
CALL EigenMGmv1( n/2, KMatrix, MMatrix, BMatrix, x, r, UseI, IScale )
r(1:n) = b(1:n) - r(1:n)
Ri(1:n) = r(1:n)
P(1:n) = 0
V(1:n) = 0
omega = 1
alpha = 0
oldrho = 1
Tmp = 0.0d0
bnorm = EigenMGdot( n,b,b )
CALL Info( 'EigenBiCG', '--------------------' )
CALL Info( 'EigenBiCG', 'Begin BiCG iteration' )
CALL Info( 'EigenBiCG', '--------------------' )
DO i=1,Rounds
rho = EigenMGdot( n, r, Ri )
beta = alpha * rho / ( oldrho * omega )
P(1:n) = r(1:n) + beta * (P(1:n) - omega*V(1:n))
Tmp(1:n/2) = P(1:n/2)
IF ( .NOT. UseI ) THEN
CALL CRS_LUSolve( n/2, MMatrix, Tmp(1:n/2) )
ELSE
Tmp(1:n/2) = Tmp(1:n/2) / IScale
END IF
V(n/2+1:n) = Tmp(1:n/2)
Tmp(1:n/2) = P(n/2+1:n)
CALL CRS_LUSolve( n/2, KMatrix, Tmp(1:n/2) )
V(1:n/2) = -1*Tmp(1:n/2)
T1(1:n) = V(1:n)
CALL EigenMGmv1( n/2, KMatrix, MMatrix, BMatrix, T1, V, UseI, IScale )
alpha = rho / EigenMGdot( n, Ri, V )
S(1:n) = r(1:n) - alpha * V(1:n)
Tmp(1:n/2) = S(1:n/2)
IF ( .NOT. UseI ) THEN
CALL CRS_LUSolve( n/2, MMatrix, Tmp(1:n/2) )
ELSE
Tmp(1:n/2) = Tmp(1:n/2) / IScale
END IF
T(n/2+1:n) = Tmp(1:n/2)
Tmp(1:n/2) = S(n/2+1:n)
CALL CRS_LUSolve( n/2, KMatrix, Tmp(1:n/2) )
T(1:n/2) = -1*Tmp(1:n/2)
T2(1:n) = T(1:n)
CALL EigenMGmv1( n/2, KMatrix, MMatrix, BMatrix, T2, T, UseI, IScale )
omega = EigenMGdot( n,T,S ) / EigenMGdot( n,T,T )
oldrho = rho
r(1:n) = S(1:n) - omega*T(1:n)
x(1:n) = x(1:n) + alpha*T1(1:n) + omega*T2(1:n)
WRITE(*,*) i,EigenMGdot( n,r,r ) / bnorm
IF ( EigenMGdot( n,r,r ) / bnorm < TOL ) THEN
CALL EigenMGmv1( n/2, KMatrix, MMatrix, BMatrix, x, r, UseI, IScale )
r(1:n) = b(1:n) - r(1:n)
WRITE( Message,* ) 'Correct residual:', EigenMGdot( n,r,r ) / bnorm
CALL Info( 'EigenBiCG', Message )
IF ( EigenMGdot( n,r,r ) / bnorm < TOL ) EXIT
END IF
END DO
IF ( EigenMGdot( n,r,r ) / bnorm >= TOL ) THEN
CALL Fatal( 'EigenBiCG', 'Failed to converge' )
END IF
END SUBROUTINE EigenBiCG
FUNCTION EigenMGdot( n, x, y ) RESULT(s)
USE Types
INTEGER :: n
REAL(KIND=dp) :: s, x(:), y(:)
s = DOT_PRODUCT( x(1:n), y(1:n) )
END FUNCTION EigenMGdot
SUBROUTINE EigenMGmv1( n, KMatrix, MMatrix, BMatrix, x, b, UseI, IScale )
USE CRSMatrix
INTEGER :: n
TYPE(Matrix_t), POINTER :: KMatrix, MMatrix, BMatrix
REAL(KIND=dp) :: IScale
REAL(KIND=dp) CONTIG :: x(:), b(:)
LOGICAL :: UseI
REAL(KIND=dp) :: Tmp(n)
Tmp = 0.0d0
b = 0.0d0
IF ( .NOT. UseI ) THEN
CALL CRS_MatrixVectorMultiply( MMatrix, x(n+1:2*n), Tmp(1:n) )
b(1:n) = b(1:n) + Tmp(1:n)
ELSE
b(1:n) = x(n+1:2*n) * IScale
END IF
CALL CRS_MatrixVectorMultiply( KMatrix, x(1:n), Tmp(1:n) )
b(n+1:2*n) = b(n+1:2*n) - Tmp(1:n)
CALL CRS_MatrixVectorMultiply( BMatrix, x(n+1:2*n), Tmp(1:n) )
b(n+1:2*n) = b(n+1:2*n) - Tmp(1:n)
END SUBROUTINE EigenMGmv1
SUBROUTINE EigenMGmv2( n, MMatrix, x, b, UseI, IScale )
USE CRSMatrix
INTEGER :: n
REAL(KIND=dp) CONTIG :: x(:), b(:)
REAL(KIND=dp) :: IScale
TYPE(Matrix_t), POINTER :: MMatrix
LOGICAL :: UseI
IF ( .NOT. UseI ) THEN
CALL CRS_MatrixVectorMultiply( MMatrix, x(1:n), b(1:n) )
ELSE
b(1:n) = x(1:n) * IScale
END IF
CALL CRS_MatrixVectorMultiply( MMatrix, x(n+1:2*n), b(n+1:2*n) )
END SUBROUTINE EigenMGmv2
END MODULE EigenSolve