Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/fem/src/EigenSolve.F90
3203 views
1
!/*****************************************************************************/
2
! *
3
! * Elmer, A Finite Element Software for Multiphysical Problems
4
! *
5
! * Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland
6
! *
7
! * This library is free software; you can redistribute it and/or
8
! * modify it under the terms of the GNU Lesser General Public
9
! * License as published by the Free Software Foundation; either
10
! * version 2.1 of the License, or (at your option) any later version.
11
! *
12
! * This library is distributed in the hope that it will be useful,
13
! * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
! * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
! * Lesser General Public License for more details.
16
! *
17
! * You should have received a copy of the GNU Lesser General Public
18
! * License along with this library (in file ../LGPL-2.1); if not, write
19
! * to the Free Software Foundation, Inc., 51 Franklin Street,
20
! * Fifth Floor, Boston, MA 02110-1301 USA
21
! *
22
! *****************************************************************************/
23
!
24
!/******************************************************************************
25
! *
26
! * This module provides various solution techniques for eigenvalue problems.
27
! * The module is based on the ARPACK example driver dndrv3 that has been modified
28
! * to fit the needs of ElmerSolver.
29
! *
30
! *
31
! * FILE: ndrv3.F SID: 2.4 DATE OF SID: 4/22/96 RELEASE: 2
32
! *
33
! * Example Authors: Richard Lehoucq, Danny Sorensen and Chao Yang
34
! * Dept. of Computational & Applied Mathematics
35
! * Rice University
36
! * Houston, Texas
37
! *
38
! ******************************************************************************
39
! *
40
! * Authors: Juha Ruokolainen
41
! * Email: [email protected]
42
! * Web: http://www.csc.fi/elmer
43
! * Address: CSC - IT Center for Science Ltd.
44
! * Keilaranta 14
45
! * 02101 Espoo, Finland
46
! *
47
! * Original Date: 21 Oct 2000
48
! *
49
! *****************************************************************************/
50
51
52
!----------------------------------------------------------------------------
53
!> Module containing ARPACK routines for the solution of Eigenvalue problems.
54
!----------------------------------------------------------------------------
55
!> \ingroup ElmerLib
56
!> \{
57
58
MODULE EigenSolve
59
60
IMPLICIT NONE
61
62
CONTAINS
63
64
!------------------------------------------------------------------------------
65
!> Solution of Eigen value problems using ARPACK library.
66
!------------------------------------------------------------------------------
67
SUBROUTINE ArpackEigenSolve( Solver,Matrix,N,NEIG,EigValues,EigVectors )
68
!------------------------------------------------------------------------------
69
USE Multigrid
70
71
IMPLICIT NONE
72
73
TYPE(Matrix_t), POINTER :: Matrix, A
74
TYPE(Solver_t), TARGET :: Solver
75
INTEGER :: N, NEIG, DPERM(n)
76
COMPLEX(KIND=dp) :: EigValues(:), EigVectors(:,:)
77
78
#ifdef USE_ARPACK
79
!
80
! %--------------%
81
! | Local Arrays |
82
! %--------------%
83
!
84
REAL(KIND=dp), TARGET :: WORKD(3*N), RESID(N),bb(N),xx(N)
85
REAL(KIND=dp), POINTER CONTIG :: x(:), b(:)
86
INTEGER :: IPARAM(11), IPNTR(14)
87
INTEGER, ALLOCATABLE :: Perm(:)
88
LOGICAL, ALLOCATABLE :: Choose(:)
89
CHARACTER(:), ALLOCATABLE :: Method
90
REAL(KIND=dp), ALLOCATABLE :: WORKL(:), D(:,:), WORKEV(:), V(:,:)
91
92
!
93
! %---------------%
94
! | Local Scalars |
95
! %---------------%
96
!
97
CHARACTER :: BMAT*1, Which*2, DirectMethod*100
98
INTEGER :: IDO, NCV, lWORKL, kinfo, i, j, k, l, p, IERR, iter, &
99
NCONV, maxitr, ishfts, mode, istat, Dofs
100
LOGICAL :: First, Stat, Direct = .FALSE., &
101
Iterative = .FALSE., NewSystem, Damped, Stability, &
102
NormalizeToUnity
103
104
LOGICAL :: Factorize, FreeFactorize,FoundFactorize,FoundFreeFactorize
105
REAL(KIND=dp) :: SigmaR, SigmaI, TOL, r
106
107
COMPLEX(KIND=dp) :: s
108
!
109
REAL(KIND=dp), POINTER CONTIG :: SaveValues(:), SaveRhs(:)
110
TYPE(ValueList_t), POINTER :: Params
111
112
CHARACTER(*), PARAMETER :: Caller = 'EigenSolve'
113
114
115
! %--------------------------------------%
116
! | Check if system is damped and if so, |
117
! | move to other subroutine |
118
! %--------------------------------------%
119
120
Params => Solver % Values
121
Damped = ListGetLogical( Params, 'Eigen System Damped', stat )
122
IF ( .NOT. stat ) Damped = .FALSE.
123
124
IF ( Damped ) THEN
125
CALL ArpackDampedEigenSolve( Solver, Matrix, 2*N, 2*NEIG, &
126
EigValues,EigVectors )
127
RETURN
128
END IF
129
130
! %----------------------------------------%
131
! | Check if stability analysis is defined |
132
! | and if so move to other subroutine |
133
! %----------------------------------------%
134
135
Stability = ListGetLogical( Params, 'stability analysis', stat )
136
IF ( .NOT. stat ) Stability = .FALSE.
137
138
IF ( Stability ) THEN
139
CALL ArpackStabEigenSolve( Solver, Matrix, N, NEIG, EigValues,EigVectors )
140
RETURN
141
END IF
142
143
! %-----------------------%
144
! | Executable Statements |
145
! %-----------------------%
146
!
147
! %----------------------------------------------------%
148
! | The number N is the dimension of the matrix. A |
149
! | generalized eigenvalue problem is solved (BMAT = |
150
! | 'G'.) NEV is the number of eigenvalues to be |
151
! | approximated. The user can modify NEV, NCV, WHICH |
152
! | to solve problems of different sizes, and to get |
153
! | different parts of the spectrum. However, The |
154
! | following conditions must be satisfied: |
155
! | N <= MAXN, |
156
! | NEV <= MAXNEV, |
157
! | NEV + 1 <= NCV <= MAXNCV |
158
! %----------------------------------------------------%
159
!
160
NCV = ListGetInteger( Params, 'Eigen System Lanczos Vectors', stat )
161
IF ( .NOT. stat ) NCV = 3*NEIG + 1
162
163
IF ( NCV <= NEIG ) THEN
164
CALL Fatal( Caller, &
165
'Number of Lanczos vectors must exceed the number of eigenvalues.' )
166
END IF
167
168
ALLOCATE( WORKL(3*NCV**2 + 6*NCV), D(NCV,3), &
169
WORKEV(3*NCV), V(n,NCV), CHOOSE(NCV), STAT=istat )
170
171
IF ( istat /= 0 ) THEN
172
CALL Fatal( Caller, 'Memory allocation error.' )
173
END IF
174
!
175
! %--------------------------------------------------%
176
! | The work array WORKL is used in DSAUPD as |
177
! | workspace. Its dimension LWORKL is set as |
178
! | illustrated below. The parameter TOL determines |
179
! | the stopping criterion. If TOL<=0, machine |
180
! | precision is used. The variable IDO is used for |
181
! | reverse communication and is initially set to 0. |
182
! | Setting INFO=0 indicates that a random vector is |
183
! | generated in DSAUPD to start the Arnoldi |
184
! | iteration. |
185
! %--------------------------------------------------%
186
!
187
!
188
189
TOL = ListGetConstReal( Params, 'Eigen System Convergence Tolerance', stat )
190
IF ( .NOT. stat ) THEN
191
TOL = 100 * ListGetConstReal( Params, 'Linear System Convergence Tolerance' )
192
END IF
193
194
IDO = 0
195
kinfo = 0
196
lWORKL = 3*NCV**2 + 6*NCV
197
!
198
! %---------------------------------------------------%
199
! | This program uses exact shifts with respect to |
200
! | the current Hessenberg matrix (IPARAM(1) = 1). |
201
! | IPARAM(3) specifies the maximum number of Arnoldi |
202
! | iterations allowed. Mode 2 of DSAUPD is used |
203
! | (IPARAM(7) = 2). All these options may be |
204
! | changed by the user. For details, see the |
205
! | documentation in DSAUPD. |
206
! %---------------------------------------------------%
207
!
208
ishfts = 1
209
BMAT = 'G'
210
IF ( Matrix % Lumped ) THEN
211
Mode = 2
212
SELECT CASE( ListGetString(Params,'Eigen System Select',stat) )
213
CASE( 'smallest magnitude' )
214
Which = 'SM'
215
CASE( 'largest magnitude')
216
Which = 'LM'
217
CASE( 'smallest real part')
218
Which = 'SR'
219
CASE( 'largest real part')
220
Which = 'LR'
221
CASE( 'smallest imag part' )
222
Which = 'SI'
223
CASE( 'largest imag part' )
224
Which = 'LI'
225
CASE DEFAULT
226
Which = 'SM'
227
END SELECT
228
ELSE
229
Mode = 3
230
SELECT CASE( ListGetString(Params,'Eigen System Select',stat) )
231
CASE( 'smallest magnitude' )
232
Which = 'LM'
233
CASE( 'largest magnitude')
234
Which = 'SM'
235
CASE( 'smallest real part')
236
Which = 'LR'
237
CASE( 'largest real part')
238
Which = 'SR'
239
CASE( 'smallest imag part' )
240
Which = 'LI'
241
CASE( 'largest imag part' )
242
Which = 'SI'
243
CASE DEFAULT
244
Which = 'LM'
245
END SELECT
246
END IF
247
248
Maxitr = ListGetInteger( Params, 'Eigen System Max Iterations', stat )
249
IF ( .NOT. stat ) Maxitr = 300
250
!
251
IPARAM = 0
252
IPARAM(1) = ishfts
253
IPARAM(3) = maxitr
254
IPARAM(7) = mode
255
256
SigmaR = 0.0d0
257
SigmaI = 0.0d0
258
V = 0.0d0
259
260
! Compute LU-factors for (A-\sigma M) (if consistent mass matrix)
261
!
262
Factorize = ListGetLogical( Params, &
263
'Linear System Refactorize', FoundFactorize )
264
CALL ListAddLogical( Params, 'Linear System Refactorize',.TRUE. )
265
266
FreeFactorize = ListGetLogical( Params, &
267
'Linear System Free Fctorization', FoundFreeFactorize )
268
CALL ListAddLogical( Params, &
269
'Linear System Free Factorization',.FALSE. )
270
271
IF ( .NOT. Matrix % Lumped ) THEN
272
SigmaR = ListGetConstReal( Params,'Eigen System Shift', stat )
273
IF ( SigmaR /= 0.0d0 ) THEN
274
Matrix % Values = Matrix % Values - SigmaR * Matrix % MassValues
275
END IF
276
277
Method = ListGetString( Params,'Linear System Solver', stat )
278
IF ( Method == 'direct' ) THEN
279
DirectMethod = ListGetString( Params, &
280
'Linear System Direct Method', stat )
281
282
SELECT CASE( DirectMethod )
283
CASE('umfpack', 'big umfpack', 'mumps', 'superlu', 'pardiso', 'cholmod')
284
CASE DEFAULT
285
Stat = CRS_ILUT(Matrix, 0.0d0)
286
END SELECT
287
END IF
288
END IF
289
290
!
291
! %-------------------------------------------%
292
! | M A I N L O O P (Reverse communication) |
293
! %-------------------------------------------%
294
!
295
iter = 1
296
NewSystem = .TRUE.
297
298
Iterative = ListGetString( Params, &
299
'Linear System Solver', stat ) == 'iterative'
300
301
stat = ListGetLogical( Params, 'No Precondition Recompute', stat )
302
IF ( Iterative .AND. Stat ) THEN
303
CALL ListAddLogical( Params, 'No Precondition Recompute', .FALSE. )
304
END IF
305
306
DO WHILE( ido /= 99 )
307
308
! %---------------------------------------------%
309
! | Repeatedly call the routine DSAUPD and take |
310
! | actions indicated by parameter IDO until |
311
! | either convergence is indicated or maxitr |
312
! | has been exceeded. |
313
! %---------------------------------------------%
314
!
315
IF ( Matrix % Symmetric ) THEN
316
CALL DSAUPD ( ido, BMAT, n, Which, NEIG, TOL, &
317
RESID, NCV, V, n, IPARAM, IPNTR, WORKD, WORKL, lWORKL, kinfo )
318
ELSE
319
CALL DNAUPD ( ido, BMAT, n, Which, NEIG, TOL, &
320
RESID, NCV, v, n, IPARAM, IPNTR, WORKD, WORKL, lWORKL, kinfo )
321
END IF
322
323
IF (ido == -1 .OR. ido == 1) THEN
324
325
IF(InfoActive(20)) THEN
326
CALL Info(Caller,'Arpack reverse communication calls: '//I2S(iter))
327
ELSE
328
CALL Info(Caller, '.', .TRUE.)
329
END IF
330
iter = iter + 1
331
332
!---------------------------------------------------------------------
333
! Perform y <--- OP*x = inv[M]*A*x (lumped mass)
334
! ido =-1 inv(A-sigmaR*M)*M*x
335
! ido = 1 inv(A-sigmaR*M)*z
336
!---------------------------------------------------------------------
337
338
IF ( Matrix % Lumped ) THEN
339
CALL CRS_MatrixVectorMultiply( Matrix, WORKD(IPNTR(1)), WORKD(IPNTR(2)) )
340
DO i=0,n-1
341
WORKD( IPNTR(1)+i ) = WORKD( IPNTR(2)+i )
342
END DO
343
DO i=0,n-1
344
WORKD( IPNTR(2)+i ) = WORKD( IPNTR(1)+i ) / &
345
Matrix % MassValues( Matrix % Diag(i+1) )
346
END DO
347
ELSE
348
349
Dofs = Solver % Variable % Dofs
350
A => Matrix
351
x => workd(ipntr(2):ipntr(2)+n-1)
352
353
IF ( ido == -1 ) THEN
354
SaveValues => A % Values
355
A % Values => A % MassValues
356
CALL CRS_MatrixVectorMultiply( A, WORKD(IPNTR(1)), WORKD(IPNTR(2)) )
357
A % Values => SaveValues
358
359
DO i=0,n-1
360
WORKD( IPNTR(1)+i ) = WORKD( IPNTR(2)+i )
361
END DO
362
b => workd(ipntr(1):ipntr(1)+n-1)
363
ELSE
364
b => workd(ipntr(3):ipntr(3)+n-1)
365
END IF
366
367
! Some strategies (such as 'block') may depend on that these are set properly
368
! to reflect the linear problem under study.
369
SaveRhs => A % rhs
370
A % rhs => b
371
372
SELECT CASE( Method )
373
CASE('multigrid')
374
CALL MultiGridSolve( A, x, b, &
375
DOFs, Solver, Solver % MultiGridLevel, NewSystem )
376
CASE('iterative')
377
CALL IterSolver( A, x, b, Solver )
378
CASE('block')
379
CALL BlockSolveExt( A, x, b, Solver )
380
CASE ('direct')
381
CALL DirectSolver( A, x, b, Solver )
382
CASE DEFAULT
383
CALL Fatal(Caller,'Unknown linear system method: '//TRIM(Method))
384
END SELECT
385
386
A % rhs => SaveRhs
387
END IF
388
389
ELSE IF (ido == 2) THEN
390
391
!
392
! %-----------------------------------------%
393
! | Perform y <--- M*x. |
394
! | Need the matrix vector multiplication |
395
! | routine here that takes WORKD(IPNTR(1)) |
396
! | as the input and returns the result to |
397
! | WORKD(IPNTR(2)). |
398
! %-----------------------------------------%
399
!
400
IF ( Matrix % Lumped ) THEN
401
DO i=0,n-1
402
WORKD( IPNTR(2)+i ) = WORKD( IPNTR(1)+i ) * &
403
Matrix % MassValues( Matrix % Diag(i+1) )
404
END DO
405
ELSE
406
SaveValues => Matrix % Values
407
Matrix % Values => Matrix % MassValues
408
CALL CRS_MatrixVectorMultiply( Matrix, WORKD(IPNTR(1)), WORKD(IPNTR(2)) )
409
Matrix % Values => SaveValues
410
END IF
411
END IF
412
413
IF ( NewSystem .AND. ido /= 2 ) THEN
414
IF ( Iterative ) THEN
415
CALL ListAddLogical( Params, 'No Precondition Recompute', .TRUE. )
416
ELSE
417
CALL ListAddLogical( Params, 'Linear System Refactorize', .FALSE. )
418
END IF
419
NewSystem = .FALSE.
420
END IF
421
END DO
422
423
IF ( FoundFactorize ) THEN
424
CALL ListAddLogical( Params, 'Linear System Refactorize', Factorize )
425
ELSE
426
CALL ListRemove( Params, 'Linear System Refactorize' )
427
END IF
428
429
IF ( .NOT. FoundFreeFactorize ) THEN
430
CALL ListRemove( Params, 'Linear System Free Factorization' )
431
ELSE
432
CALL ListAddLogical( Params, 'Linear System Free Factorization', FreeFactorize )
433
END IF
434
435
! %-----------------------------------------%
436
! | Either we have convergence, or there is |
437
! | an error. |
438
! %-----------------------------------------%
439
IF ( kinfo /= 0 ) THEN
440
!
441
! %--------------------------%
442
! | Error message, check the |
443
! | documentation in DNAUPD |
444
! %--------------------------%
445
!
446
WRITE( Message, * ) 'Error with DNAUPD, info = ',kinfo
447
CALL Fatal( Caller, Message )
448
!
449
ELSE
450
!
451
! %-------------------------------------------%
452
! | No fatal errors occurred. |
453
! | Post-Process using DSEUPD. |
454
! | |
455
! | Computed eigenvalues may be extracted. |
456
! | |
457
! | Eigenvectors may also be computed now if |
458
! | desired. (indicated by rvec = .true.) |
459
! %-------------------------------------------%
460
!
461
D = 0.0d0
462
IF ( Matrix % Symmetric ) THEN
463
CALL DSEUPD ( .TRUE., 'A', Choose, D, V, N, SigmaR, &
464
BMAT, n, Which, NEIG, TOL, RESID, NCV, V, N, &
465
IPARAM, IPNTR, WORKD, WORKL, lWORKL, IERR )
466
ELSE
467
CALL DNEUPD ( .TRUE., 'A', Choose, D, D(1,2), &
468
V, N, SigmaR, SigmaI, WORKEV, BMAT, N, &
469
Which, NEIG, TOL, RESID, NCV, V, N, &
470
IPARAM, IPNTR, WORKD, WORKL, lWORKL, IERR )
471
END IF
472
473
! %----------------------------------------------%
474
! | Eigenvalues are returned in the First column |
475
! | of the two dimensional array D and the |
476
! | corresponding eigenvectors are returned in |
477
! | the First NEV columns of the two dimensional |
478
! | array V if requested. Otherwise, an |
479
! | orthogonal basis for the invariant subspace |
480
! | corresponding to the eigenvalues in D is |
481
! | returned in V. |
482
! %----------------------------------------------%
483
!
484
IF (IERR /= 0) THEN
485
!
486
! %------------------------------------%
487
! | Error condition: |
488
! | Check the documentation of DNEUPD. |
489
! %------------------------------------%
490
!
491
WRITE( Message, * ) ' Error with DNEUPD, info = ', IERR
492
CALL Fatal( Caller, Message )
493
END IF
494
!
495
! %------------------------------------------%
496
! | Print additional convergence information |
497
! %------------------------------------------%
498
!
499
IF ( kinfo == 1 ) THEN
500
CALL Fatal( Caller, 'Maximum number of iterations reached.' )
501
ELSE IF ( kinfo == 3 ) THEN
502
CALL Fatal( Caller, 'No shifts could be applied during implicit Arnoldi update, try increasing NCV.' )
503
END IF
504
!
505
! Sort the eigenvalues to ascending order:
506
! ----------------------------------------
507
ALLOCATE( Perm(NEIG) )
508
Perm = [ (i, i=1,NEIG) ]
509
DO i=1,NEIG
510
EigValues(i) = CMPLX( D(i,1), D(i,2),KIND=dp )
511
END DO
512
CALL SortC( NEIG, EigValues, Perm )
513
IF( MINVAL( Perm ) < 1 .OR. MAXVAL( Perm ) > NEIG ) THEN
514
CALL Fatal(Caller,'Reordering of EigenValues failed')
515
END IF
516
517
!
518
! Extract the values to Elmer structures:
519
! -----------------------------------------
520
CALL Info( Caller, ' ', Level=4 )
521
CALL Info( Caller, 'Eigen system solution complete: ', Level=4 )
522
CALL Info( Caller, ' ', Level=4 )
523
WRITE( Message,'(A,ES12.3)') 'Convergence criterion is: ', TOL
524
CALL Info( Caller, Message, Level=7 )
525
CALL Info( Caller,'Number of converged Ritz values is: '//I2S(IPARAM(5)),Level=4)
526
CALL Info( Caller,'Number of update iterations taken: '//I2S(IPARAM(3)),Level=4)
527
CALL Info( Caller,'Computed '//I2S(NEIG)//' Eigen Values',Level=4)
528
529
! Restore matrix values, if modified when using shift:
530
! ---------------------------------------------------
531
IF ( SigmaR /= 0.0d0 ) THEN
532
Matrix % Values = Matrix % Values + SigmaR * Matrix % MassValues
533
END IF
534
535
! extract vectors:
536
! ----------------
537
k = 1
538
DO i=1,NEIG
539
p = Perm(i)
540
WRITE( Message,'(I0,A,2ES15.6)') i,': ',EigValues(i)
541
CALL Info( Caller, Message, Level=4 )
542
543
k = 1
544
DO j=1,p-1
545
IF ( D(j,2) == 0 ) THEN
546
k = k + 1
547
ELSE
548
k = k + 2
549
END IF
550
END DO
551
552
CALL Info(Caller,'Copying Eigenvectors to solution',Level=12)
553
554
DO j=1,N
555
IF ( D(p,2) /= 0.0d0 ) THEN
556
EigVectors(i,j) = CMPLX( V(j,k),V(j,k+1),KIND=dp )
557
ELSE
558
EigVectors(i,j) = CMPLX( V(j,k),0.0d0,KIND=dp )
559
END IF
560
END DO
561
562
! Normalization moved to ScaleEigenVectors
563
564
END DO
565
566
IF ( ListGetLogical( Params, 'Eigen System Compute Residuals', stat ) ) THEN
567
CALL Info(Caller,'Computing eigen system residuals',Level=8)
568
CALL CheckResiduals( Matrix, Neig, EigValues, EigVectors )
569
END IF
570
CALL Info( Caller, '--------------------------------',Level=4 )
571
END IF
572
573
DEALLOCATE( WORKL, D, WORKEV, V, CHOOSE, Perm )
574
575
#else
576
CALL Fatal( Caller, 'Arpack Eigen System Solver not available!' )
577
#endif
578
!
579
!------------------------------------------------------------------------------
580
END SUBROUTINE ArpackEigenSolve
581
!------------------------------------------------------------------------------
582
583
584
!------------------------------------------------------------------------------
585
!> Scale both real and complex valued eigenvectors.
586
!------------------------------------------------------------------------------
587
SUBROUTINE ScaleEigenVectors( Matrix, EigVectors, NoEigen, NormalizeToUnity)
588
589
USE Multigrid
590
591
IMPLICIT NONE
592
593
TYPE(Matrix_t), TARGET :: Matrix
594
COMPLEX(KIND=dp) :: EigVectors(:,:)
595
INTEGER :: n, NoEigen
596
LOGICAL :: NormalizeToUnity
597
598
INTEGER :: i,j,k,l, mk, mj
599
REAL(KIND=dp) :: r
600
COMPLEX(KIND=dp) :: s, s1, mx
601
602
CHARACTER(*), PARAMETER :: Caller = 'ScaleEigenVectors'
603
604
605
CALL Info(Caller,'Scaling eigen vectors',Level=10)
606
607
! Real case: Normalize eigenvector (x) so that x^T(M x) = 1
608
! Complex case: Normalize eigenvectors (x) so that x^H(M x) = 1
609
! (probably already done, but no harm in redoing!)
610
! Optionally normalize such that the maximum amplitude is set one.
611
! -----------------------------------------------------------------------------
612
613
n = Matrix % NumberOfRows
614
IF ( Matrix % Complex ) n = n / 2
615
616
DO i = 1, NoEigen
617
618
IF( Matrix % COMPLEX ) THEN
619
s = 0.0_dp
620
IF( NormalizeToUnity ) THEN
621
DO j=1,n
622
s1 = EigVectors(i,j) * CONJG(EigVectors(i,j))
623
IF( ABS( s1 ) > ABS( s ) ) s = s1
624
END DO
625
ELSE IF ( Matrix % Lumped ) THEN
626
DO j=1,n
627
s = s + ABS( EigVectors(i,j) )**2 * Matrix % MassValues( Matrix % Diag(2*j-1) )
628
END DO
629
ELSE
630
DO j=1,Matrix % NumberOfRows,2
631
DO l=Matrix % Rows(j),Matrix % Rows(j+1)-1,2
632
mx = CMPLX( Matrix % MassValues(l), -Matrix % MassValues(l+1), KIND=DP )
633
mj = (j-1)/2 + 1
634
mk = (Matrix % Cols(l)-1)/2 + 1
635
s = s + mx * CONJG( EigVectors(i,mj) ) * EigVectors(i,mk)
636
END DO
637
END DO
638
END IF
639
640
s = CMPLX( ParallelReduction( REAL(s) ), ParallelReduction( AIMAG(s) ), KIND=dp )
641
642
IF ( ABS(s) > 0 ) THEN
643
s = SQRT(s)
644
WRITE(Message,'(A,2ES12.3)') 'Normalizing Eigenvector with: ',REAL(s),AIMAG(s)
645
CALL Info(Caller,Message,Level=12)
646
EigVectors(i,1:n) = EigVectors(i,1:n) / s
647
ELSE
648
CALL Warn(Caller,'Eigenmode has zero amplitude!')
649
END IF
650
ELSE
651
r = 0.0_dp
652
IF( NormalizeToUnity ) THEN
653
DO j=1,n
654
r = MAX( r, ABS(EigVectors(i,j))**2 )
655
END DO
656
ELSE IF ( Matrix % Lumped ) THEN
657
DO j=1,n
658
r= r + ABS(EigVectors(i,j))**2 * &
659
Matrix % MassValues(Matrix % Diag(j))
660
END DO
661
ELSE
662
r = 0
663
DO j=1,n
664
DO l=Matrix % Rows(j), Matrix % Rows(j+1)-1
665
r = r + CONJG(EigVectors(i,j)) * Matrix % MassValues(l) * EigVectors(i,Matrix % Cols(l))
666
END DO
667
END DO
668
END IF
669
670
r = ParallelReduction(r)
671
672
IF( ABS(r - 1) < EPSILON( r ) ) THEN
673
CALL Info(Caller,'Eigenmode already normalized!',Level=12)
674
ELSE IF ( ABS(r) > 0 ) THEN
675
r = SQRT( r )
676
WRITE(Message,'(A,ES12.3)') 'Normalizing Eigenvector with: ',r
677
CALL Info(Caller,Message,Level=12)
678
EigVectors(i,:) = EigVectors(i,:) / r
679
ELSE
680
CALL Warn(Caller,'Eigenmode has zero amplitude!')
681
END IF
682
END IF
683
684
END DO
685
686
END SUBROUTINE ScaleEigenVectors
687
!------------------------------------------------------------------------------
688
689
690
!------------------------------------------------------------------------------
691
!> Expand complex valued eigenvector to a real that is actually the same vector ;-)
692
!------------------------------------------------------------------------------
693
SUBROUTINE ExpandEigenVectors( Matrix, EigVectors, NoEigen, dofs )
694
695
USE Types
696
697
IMPLICIT NONE
698
699
TYPE(Matrix_t), TARGET :: Matrix
700
COMPLEX(KIND=dp) :: EigVectors(:,:)
701
INTEGER :: NoEigen
702
INTEGER :: dofs
703
704
COMPLEX(KIND=dp), ALLOCATABLE :: EigTmp(:)
705
INTEGER :: n,i,j,k,cdofs
706
COMPLEX(KIND=dp) :: s
707
708
CHARACTER(*), PARAMETER :: Caller = 'ExpandEigenVectors'
709
710
IF ( .NOT. Matrix % COMPLEX ) RETURN
711
712
CALL Info(Caller,'Expanding eigen vectors',Level=10)
713
714
n = Matrix % NumberOfRows / dofs
715
cdofs = dofs / 2
716
717
ALLOCATE(EigTmp(SIZE(EigVectors(1,:))))
718
719
DO i = 1, NoEigen
720
721
EigTmp = EigVectors(i,:)
722
723
DO j = 1, n
724
DO k = 1, cdofs
725
s = EigTmp(cdofs*(j-1)+k)
726
EigVectors(i,dofs*(j-1)+k) = REAL(s)
727
EigVectors(i,dofs*(j-1)+k+cdofs) = AIMAG(s)
728
END DO
729
END DO
730
END DO
731
732
END SUBROUTINE ExpandEigenVectors
733
!------------------------------------------------------------------------------
734
735
736
737
!------------------------------------------------------------------------------
738
SUBROUTINE CheckResiduals( Matrix, n, Eigs, EigVectors )
739
!------------------------------------------------------------------------------
740
USE CRSMatrix
741
TYPE(Matrix_t), POINTER :: Matrix
742
INTEGER :: i,n,sz
743
COMPLEX(KIND=dp) :: Eigs(:), EigVectors(:,:)
744
745
REAL(KIND=dp), ALLOCATABLE :: x(:), y(:)
746
747
sz = Matrix % NumberOfRows
748
ALLOCATE( x(sz), y(sz) )
749
DO i=1,n
750
Matrix % Values = Matrix % Values - REAL(Eigs(i)) * Matrix % MassValues
751
x = REAL( EigVectors(i,1:sz) )
752
CALL CRS_MatrixVectorMultiply( Matrix, x, y )
753
Matrix % Values = Matrix % Values + REAL(Eigs(i)) * Matrix % MassValues
754
755
WRITE( Message, * ) 'L^2 Norm of the residual: ', i, SQRT(SUM(y**2))
756
CALL Info( 'CheckResiduals', Message, Level = 3 )
757
END DO
758
DEALLOCATE( x,y )
759
!------------------------------------------------------------------------------
760
END SUBROUTINE CheckResiduals
761
!------------------------------------------------------------------------------
762
763
764
!------------------------------------------------------------------------------
765
!> Solution of Eigen value problems using ARPACK library, stabilized version.
766
!------------------------------------------------------------------------------
767
SUBROUTINE ArpackStabEigenSolve( Solver, &
768
Matrix, N, NEIG, EigValues, EigVectors )
769
!------------------------------------------------------------------------------
770
USE Multigrid
771
772
IMPLICIT NONE
773
774
TYPE(Matrix_t), POINTER :: Matrix
775
TYPE(Solver_t), TARGET :: Solver
776
INTEGER :: N, NEIG, DPERM(n)
777
COMPLEX(KIND=dp) :: EigValues(:), EigVectors(:,:)
778
779
#ifdef USE_ARPACK
780
!
781
! %--------------%
782
! | Local Arrays |
783
! %--------------%
784
!
785
REAL(KIND=dp), TARGET :: WORKD(3*N), RESID(N)
786
REAL(KIND=dp), POINTER CONTIG :: x(:), b(:)
787
INTEGER :: IPARAM(11), IPNTR(14)
788
INTEGER, ALLOCATABLE :: Perm(:)
789
LOGICAL, ALLOCATABLE :: Choose(:)
790
REAL(KIND=dp), ALLOCATABLE :: WORKL(:), D(:,:), V(:,:)
791
!
792
! %---------------%
793
! | Local Scalars |
794
! %---------------%
795
!
796
CHARACTER :: BMAT*1, Which*2, DirectMethod*200
797
INTEGER :: IDO, NCV, lWORKL, kinfo, i, j, k, l, p, IERR, iter, &
798
NCONV, maxitr, ishfts, mode, istat
799
LOGICAL :: First, Stat, Direct = .FALSE., FactorizeSetting, &
800
Iterative = .FALSE., NewSystem, &
801
rvec = .TRUE.
802
LOGICAL :: Factorize, FreeFactorize,FoundFactorize,FoundFreeFactorize
803
REAL(KIND=dp) :: SigmaR, SigmaI, TOL
804
805
COMPLEX(KIND=dp) :: s
806
!
807
REAL(KIND=dp), POINTER CONTIG :: SaveValues(:)
808
809
CHARACTER(*), PARAMETER :: Caller = 'StabEigenSolve'
810
811
812
! %-----------------------%
813
! | Executable Statements |
814
! %-----------------------%
815
!
816
! %----------------------------------------------------%
817
! | The number N is the dimension of the matrix. A |
818
! | generalized eigenvalue problem is solved (BMAT = |
819
! | 'G'.) NEV is the number of eigenvalues to be |
820
! | approximated. The user can modify NEV, NCV, WHICH |
821
! | to solve problems of different sizes, and to get |
822
! | different parts of the spectrum. However, The |
823
! | following conditions must be satisfied: |
824
! | N <= MAXN, |
825
! | NEV <= MAXNEV, |
826
! | NEV + 1 <= NCV <= MAXNCV |
827
! %----------------------------------------------------%
828
!
829
IF ( Matrix % Lumped ) THEN
830
CALL Error(Caller,'Lumped matrices are not allowed in stability analysis.' )
831
END IF
832
833
NCV = 3 * NEIG + 1
834
835
lWORKL = NCV*(NCV+8)
836
837
ALLOCATE( WORKL(lWORKL), D(NCV,2), V(N,NCV), CHOOSE(NCV), STAT=istat )
838
839
IF ( istat /= 0 ) THEN
840
CALL Fatal(Caller, 'Memory allocation error.' )
841
END IF
842
843
TOL = ListGetConstReal( Solver % Values, 'Eigen System Convergence Tolerance', stat )
844
IF ( .NOT. stat ) THEN
845
TOL = 100 * ListGetConstReal( Solver % Values, 'Linear System Convergence Tolerance' )
846
END IF
847
!
848
! %---------------------------------------------------%
849
! | This program uses exact shifts with respect to |
850
! | the current Hessenberg matrix (IPARAM(1) = 1). |
851
! | IPARAM(3) specifies the maximum number of Arnoldi |
852
! | iterations allowed. Mode 2 of DSAUPD is used |
853
! | (IPARAM(7) = 2). All these options may be |
854
! | changed by the user. For details, see the |
855
! | documentation in DSAUPD. |
856
! %---------------------------------------------------%
857
!
858
IDO = 0
859
kinfo = 0
860
ishfts = 1
861
BMAT = 'G'
862
Mode = 2
863
864
SELECT CASE( ListGetString( Solver % Values,'Eigen System Select', stat ) )
865
CASE( 'smallest magnitude' )
866
Which = 'LM'
867
CASE( 'largest magnitude')
868
Which = 'SM'
869
CASE( 'smallest real part')
870
Which = 'LR'
871
CASE( 'largest real part')
872
Which = 'SR'
873
CASE( 'smallest imag part' )
874
Which = 'LI'
875
CASE( 'largest imag part' )
876
Which = 'SI'
877
CASE( 'smallest algebraic' )
878
Which = 'LA'
879
CASE( 'largest algebraic' )
880
Which = 'SA'
881
CASE DEFAULT
882
Which = 'LM'
883
END SELECT
884
885
Maxitr = ListGetInteger( Solver % Values, 'Eigen System Max Iterations', stat )
886
IF ( .NOT. stat ) Maxitr = 300
887
888
IPARAM = 0
889
IPARAM(1) = ishfts
890
IPARAM(3) = maxitr
891
IPARAM(7) = mode
892
893
SigmaR = 0.0d0
894
SigmaI = 0.0d0
895
V = 0.0d0
896
D = 0.0d0
897
898
Factorize = ListGetLogical( Solver % Values, &
899
'Linear System Refactorize', FoundFactorize )
900
CALL ListAddLogical( Solver % Values, 'Linear System Refactorize',.TRUE. )
901
902
FreeFactorize = ListGetLogical( Solver % Values, &
903
'Linear System Refactorize', FoundFreeFactorize )
904
CALL ListAddLogical( Solver % Values, &
905
'Linear System Free Factorization',.FALSE. )
906
907
Direct = ListGetString( Solver % Values, &
908
'Linear System Solver', stat ) == 'direct'
909
IF ( Direct ) THEN
910
DirectMethod = ListGetString( Solver % Values, &
911
'Linear System Direct Method', stat )
912
913
SELECT CASE( DirectMethod )
914
CASE('umfpack', 'big umfpack','mumps', 'superlu', 'pardiso', 'cholmod' )
915
CASE DEFAULT
916
Stat = CRS_ILUT(Matrix, 0.0d0)
917
END SELECT
918
END IF
919
920
Iterative = ListGetString( Solver % Values, &
921
'Linear System Solver', stat ) == 'iterative'
922
923
stat = ListGetLogical( Solver % Values, 'No Precondition Recompute', stat )
924
925
IF ( Iterative .AND. Stat ) THEN
926
CALL ListAddLogical( Solver % Values, 'No Precondition Recompute', .FALSE. )
927
END IF
928
!
929
! %-------------------------------------------%
930
! | M A I N L O O P (Reverse communication) |
931
! %-------------------------------------------%
932
!
933
iter = 1
934
NewSystem = .TRUE.
935
936
DO WHILE( ido /= 99 )
937
938
CALL DSAUPD( ido, BMAT, n, Which, NEIG, TOL, &
939
RESID, NCV, V, n, IPARAM, IPNTR, WORKD, WORKL, lWORKL, kinfo )
940
941
IF( ido==-1 .OR. ido==1 ) THEN
942
IF(InfoActive(20)) THEN
943
CALL Info(Caller,'Arpack reverse communication calls: '//I2S(iter))
944
ELSE
945
CALL Info(Caller, '.', .TRUE.)
946
END IF
947
iter = iter + 1
948
END IF
949
950
SELECT CASE( ido )
951
CASE( -1, 1 )
952
SaveValues => Matrix % Values
953
Matrix % Values => Matrix % MassValues
954
CALL CRS_MatrixVectorMultiply( Matrix, WORKD(IPNTR(1)), WORKD(IPNTR(2)) )
955
Matrix % Values => SaveValues
956
957
DO i=0,n-1
958
WORKD( IPNTR(1)+i ) = WORKD( IPNTR(2)+i )
959
END DO
960
961
IF ( Direct ) THEN
962
CALL DirectSolver( Matrix,WORKD(IPNTR(2)),WORKD(IPNTR(1)), Solver )
963
ELSE
964
x => workd(ipntr(2):ipntr(2)+n-1)
965
b => workd(ipntr(1):ipntr(1)+n-1)
966
967
IF ( Solver % MultiGridSolver ) THEN
968
CALL MultiGridSolve( Matrix, x, b, Solver % Variable % DOFs, &
969
Solver, Solver % MultiGridLevel, NewSystem )
970
ELSE
971
CALL IterSolver( Matrix, x, b, Solver )
972
END IF
973
974
END IF
975
976
CASE( 2 )
977
CALL CRS_MatrixVectorMultiply( Matrix, WORKD(IPNTR(1)), WORKD(IPNTR(2)) )
978
979
END SELECT
980
981
IF ( NewSystem .AND. ido /= 2 ) THEN
982
IF ( Iterative ) THEN
983
CALL ListAddLogical( Solver % Values, 'No Precondition Recompute', .TRUE. )
984
ELSE
985
CALL ListAddLogical( Solver % Values, 'Linear System Refactorize', .FALSE. )
986
END IF
987
NewSystem = .FALSE.
988
END IF
989
990
!-----------------------------------------------------------------------------------------
991
END DO ! ido == 99
992
993
IF ( FoundFactorize ) THEN
994
CALL ListAddLogical( Solver % Values, 'Linear System Refactorize', Factorize )
995
ELSE
996
CALL ListRemove( Solver % Values, 'Linear System Refactorize' )
997
END IF
998
999
IF ( .NOT. FoundFreeFactorize ) THEN
1000
CALL ListRemove( Solver % Values, 'Linear System Free Factorization' )
1001
ELSE
1002
CALL ListAddLogical( Solver % Values, 'Linear System Free Factorization', FreeFactorize )
1003
END IF
1004
!
1005
! %-----------------------------------------%
1006
! | Either we have convergence, or there is |
1007
! | an error. |
1008
! %-----------------------------------------%
1009
!
1010
IF ( kinfo /= 0 ) THEN
1011
WRITE( Message, * ) 'Error with DSAUPD, info = ',kinfo
1012
CALL Fatal( 'StabEigenSolve', Message )
1013
!
1014
ELSE
1015
D = 0.0d0
1016
rvec = .TRUE.
1017
1018
CALL DSEUPD ( rvec, 'A', Choose, D, V, N, SigmaR, &
1019
BMAT, n, Which, NEIG, TOL, RESID, NCV, V, N, &
1020
IPARAM, IPNTR, WORKD, WORKL, lWORKL, IERR )
1021
1022
! %----------------------------------------------%
1023
! | Eigenvalues are returned in the First column |
1024
! | of the two dimensional array D and the |
1025
! | corresponding eigenvectors are returned in |
1026
! | the First NEV columns of the two dimensional |
1027
! | array V if requested. Otherwise, an |
1028
! | orthogonal basis for the invariant subspace |
1029
! | corresponding to the eigenvalues in D is |
1030
! | returned in V. |
1031
! %----------------------------------------------%
1032
!
1033
IF (IERR /= 0) THEN
1034
WRITE( Message, * ) ' Error with DSEUPD, info = ', IERR
1035
CALL Fatal( Caller, Message )
1036
END IF
1037
!
1038
! %------------------------------------------%
1039
! | Print additional convergence information |
1040
! %------------------------------------------%
1041
!
1042
IF ( kinfo == 1 ) THEN
1043
CALL Fatal( Caller, 'Maximum number of iterations reached.' )
1044
ELSE IF ( kinfo == 3 ) THEN
1045
CALL Fatal( Caller, 'No shifts could be applied during implicit Arnoldi update, try increasing NCV.' )
1046
END IF
1047
!
1048
! Sort the eigenvalues to ascending order:
1049
! ----------------------------------------
1050
ALLOCATE( Perm(NEIG) )
1051
Perm = [ (i, i=1,NEIG) ]
1052
DO i=1,NEIG
1053
EigValues(i) = CMPLX( 1.0d0 / D(i,1), D(i,2),KIND=dp )
1054
END DO
1055
1056
CALL SortC( NEIG, EigValues, Perm )
1057
!
1058
! Extract the values to ELMER structures:
1059
! -----------------------------------------
1060
CALL Info( Caller, ' ', Level=4 )
1061
CALL Info( Caller, 'EIGEN SYSTEM SOLUTION COMPLETE: ', Level=4 )
1062
CALL Info( Caller, ' ', Level=4 )
1063
WRITE( Message,'(A,ES12.3)') 'Convergence criterion is: ', TOL
1064
CALL Info( Caller, Message, Level=7 )
1065
CALL Info( Caller,'Number of converged Ritz values is: '//I2S(IPARAM(5)),Level=4)
1066
CALL Info( Caller, ' ', Level=7 )
1067
CALL Info( Caller, 'Computed Eigen Values: ', Level=4 )
1068
CALL Info( Caller, '--------------------------------', Level=7 )
1069
k = 1
1070
1071
DO i=1,NEIG
1072
p = Perm(i)
1073
WRITE( Message, * ) i,EigValues(i)
1074
CALL Info( Caller, Message, Level=4 )
1075
1076
k = 1
1077
DO j=1,p-1
1078
IF ( D(j,2) == 0 ) THEN
1079
k = k + 1
1080
ELSE
1081
k = k + 2
1082
END IF
1083
END DO
1084
1085
DO j=1,N
1086
IF ( D(p,2) /= 0.0d0 ) THEN
1087
EigVectors(i,j) = CMPLX( V(j,k),V(j,k+1),KIND=dp )
1088
ELSE
1089
EigVectors(i,j) = CMPLX( V(j,k),0.0d0,KIND=dp )
1090
END IF
1091
END DO
1092
1093
! Normalizatin moved to ScaleEigenVectors
1094
END DO
1095
1096
CALL Info( Caller, '--------------------------------',Level=4 )
1097
1098
END IF
1099
1100
DO i = 1,Neig
1101
IF( REAL(EigValues(i)) < 0.0d0 ) THEN
1102
EigVectors(i,:) = EigVectors(i,:) * CMPLX(0.0d0,1.0d0,KIND=dp)
1103
END IF
1104
END DO
1105
1106
DEALLOCATE( WORKL, D, V, CHOOSE, Perm )
1107
#else
1108
CALL Fatal( Caller, 'Arpack Eigen System Solver not available!' )
1109
#endif
1110
!
1111
!------------------------------------------------------------------------------
1112
END SUBROUTINE ArpackStabEigenSolve
1113
!------------------------------------------------------------------------------
1114
1115
1116
!------------------------------------------------------------------------------
1117
SUBROUTINE ArpackEigenSolveComplex( Solver,Matrix,N,NEIG, &
1118
EigValues, EigVectors )
1119
!------------------------------------------------------------------------------
1120
!> Solution of Eigen value problems using ARPACK library, complex valued version.
1121
!------------------------------------------------------------------------------
1122
USE Multigrid
1123
1124
IMPLICIT NONE
1125
1126
TYPE(Matrix_t), POINTER :: Matrix, A
1127
TYPE(Solver_t), TARGET :: Solver
1128
INTEGER :: N, NEIG, DPERM(n)
1129
COMPLEX(KIND=dp) :: EigValues(:), EigVectors(:,:)
1130
1131
#ifdef USE_ARPACK
1132
!
1133
! %--------------%
1134
! | Local Arrays |
1135
! %--------------%
1136
!
1137
COMPLEX(KIND=dp) :: WORKD(3*N), RESID(N)
1138
INTEGER :: IPARAM(11), IPNTR(14)
1139
INTEGER, ALLOCATABLE :: Perm(:)
1140
LOGICAL, ALLOCATABLE :: Choose(:)
1141
COMPLEX(KIND=dp), ALLOCATABLE :: WORKL(:), D(:), WORKEV(:), V(:,:)
1142
1143
!
1144
! %---------------%
1145
! | Local Scalars |
1146
! %---------------%
1147
!
1148
CHARACTER :: BMAT*1, Which*2
1149
INTEGER :: IDO, NCV, lWORKL, kinfo, i, j, k, l, p, IERR, iter, &
1150
NCONV, maxitr, ishfts, mode, istat, dofs
1151
LOGICAL :: First, Stat, Direct = .FALSE., FoundFactorize,&
1152
Iterative = .FALSE., NewSystem, Factorize, FreeFactorize, FoundFreeFactorize
1153
1154
CHARACTER(:), ALLOCATABLE :: DirectMethod, Method
1155
COMPLEX(KIND=dp) :: Sigma = 0.0d0, s
1156
REAL(KIND=dp), TARGET :: x(2*n), b(2*n)
1157
REAL(KIND=dp) :: SigmaR, SigmaI, TOL, RWORK(N)
1158
!
1159
REAL(KIND=dp), POINTER CONTIG :: SaveValues(:), SaveRhs(:)
1160
1161
TYPE(ValueList_t), POINTER :: Params
1162
1163
CHARACTER(*), PARAMETER :: Caller = 'EigenSolveComplex'
1164
1165
!
1166
! %-----------------------%
1167
! | Executable Statements |
1168
! %-----------------------%
1169
!
1170
! %----------------------------------------------------%
1171
! | The number N is the dimension of the matrix. A |
1172
! | generalized eigenvalue problem is solved (BMAT = |
1173
! | 'G'.) NEV is the number of eigenvalues to be |
1174
! | approximated. The user can modify NEV, NCV, WHICH |
1175
! | to solve problems of different sizes, and to get |
1176
! | different parts of the spectrum. However, The |
1177
! | following conditions must be satisfied: |
1178
! | N <= MAXN, |
1179
! | NEV <= MAXNEV, |
1180
! | NEV + 1 <= NCV <= MAXNCV |
1181
! %----------------------------------------------------%
1182
!
1183
1184
CALL Info(Caller,'Starting eigen system solution with complex matrices!',Level=6)
1185
1186
Params => Solver % Values
1187
1188
NCV = ListGetInteger( Params, 'Eigen System Lanczos Vectors', stat )
1189
IF ( .NOT. stat ) NCV = 3*NEIG + 1
1190
1191
IF ( NCV <= NEIG ) THEN
1192
CALL Fatal( 'EigenSolve', &
1193
'Number of Lanczos vectors must exceed the number of eigenvalues.' )
1194
END IF
1195
1196
ALLOCATE( WORKL(3*NCV**2 + 6*NCV), D(NCV), &
1197
WORKEV(3*NCV), V(n,NCV+1), CHOOSE(NCV), STAT=istat )
1198
1199
IF ( istat /= 0 ) THEN
1200
CALL Fatal(Caller, 'Memory allocation error.' )
1201
END IF
1202
!
1203
! %--------------------------------------------------%
1204
! | The work array WORKL is used in DSAUPD as |
1205
! | workspace. Its dimension LWORKL is set as |
1206
! | illustrated below. The parameter TOL determines |
1207
! | the stopping criterion. If TOL<=0, machine |
1208
! | precision is used. The variable IDO is used for |
1209
! | reverse communication and is initially set to 0. |
1210
! | Setting INFO=0 indicates that a random vector is |
1211
! | generated in DSAUPD to start the Arnoldi |
1212
! | iteration. |
1213
! %--------------------------------------------------%
1214
!
1215
!
1216
TOL = ListGetConstReal( Solver % Values, 'Eigen System Convergence Tolerance', stat )
1217
IF ( .NOT. stat ) THEN
1218
TOL = 100 * ListGetConstReal( Solver % Values, 'Linear System Convergence Tolerance' )
1219
END IF
1220
1221
lWORKL = 3*NCV**2 + 6*NCV
1222
IDO = 0
1223
kinfo = 0
1224
!
1225
! %---------------------------------------------------%
1226
! | This program uses exact shifts with respect to |
1227
! | the current Hessenberg matrix (IPARAM(1) = 1). |
1228
! | IPARAM(3) specifies the maximum number of Arnoldi |
1229
! | iterations allowed. Mode 2 of DSAUPD is used |
1230
! | (IPARAM(7) = 2). All these options may be |
1231
! | changed by the user. For details, see the |
1232
! | documentation in DSAUPD. |
1233
! %---------------------------------------------------%
1234
!
1235
ishfts = 1
1236
BMAT = 'G'
1237
IF ( Matrix % Lumped ) THEN
1238
Mode = 2
1239
SELECT CASE(ListGetString( Solver % Values, 'Eigen System Select',stat) )
1240
CASE( 'smallest magnitude' )
1241
Which = 'SM'
1242
CASE( 'largest magnitude')
1243
Which = 'LM'
1244
CASE( 'smallest real part')
1245
Which = 'SR'
1246
CASE( 'largest real part')
1247
Which = 'LR'
1248
CASE( 'smallest imag part' )
1249
Which = 'SI'
1250
CASE( 'largest imag part' )
1251
Which = 'LI'
1252
CASE DEFAULT
1253
Which = 'SM'
1254
END SELECT
1255
ELSE
1256
Mode = 3
1257
SELECT CASE(ListGetString( Solver % Values, 'Eigen System Select',stat) )
1258
CASE( 'smallest magnitude' )
1259
Which = 'LM'
1260
CASE( 'largest magnitude')
1261
Which = 'SM'
1262
CASE( 'smallest real part')
1263
Which = 'LR'
1264
CASE( 'largest real part')
1265
Which = 'SR'
1266
CASE( 'smallest imag part' )
1267
Which = 'LI'
1268
CASE( 'largest imag part' )
1269
Which = 'SI'
1270
CASE DEFAULT
1271
Which = 'LM'
1272
END SELECT
1273
END IF
1274
!
1275
Maxitr = ListGetInteger( Solver % Values, 'Eigen System Max Iterations', stat )
1276
IF ( .NOT. stat ) Maxitr = 300
1277
1278
IPARAM = 0
1279
IPARAM(1) = ishfts
1280
IPARAM(3) = maxitr
1281
IPARAM(7) = mode
1282
1283
SigmaR = 0
1284
SigmaI = 0
1285
V = 0
1286
1287
! Compute LU-factors for (A-\sigma M) (if consistent mass matrix):
1288
! ----------------------------------------------------------------
1289
Factorize = ListGetLogical( Params, &
1290
'Linear System Refactorize', FoundFactorize )
1291
CALL ListAddLogical( Params, 'Linear System Refactorize',.TRUE. )
1292
1293
FreeFactorize = ListGetLogical( Params, &
1294
'Linear System Refactorize', FoundFreeFactorize )
1295
1296
CALL ListAddLogical( Params, &
1297
'Linear System Free Factorization',.FALSE. )
1298
1299
IF ( .NOT. Matrix % Lumped ) THEN
1300
SigmaR = ListGetConstReal( Params,'Eigen System Shift', stat )
1301
SigmaI = ListGetConstReal( Params,'Eigen System Shift Im', stat )
1302
Sigma = CMPLX(SigmaR,SigmaI)
1303
1304
IF ( Sigma /= 0._dp ) THEN
1305
Matrix % Values = Matrix % Values - Sigma * Matrix % MassValues
1306
END IF
1307
1308
Method = ListGetString( Params,'Linear System Solver', stat )
1309
IF ( Method == 'direct' ) THEN
1310
DirectMethod = ListGetString( Params, &
1311
'Linear System Direct Method', stat )
1312
1313
SELECT CASE( DirectMethod )
1314
CASE('umfpack', 'big umfpack', 'mumps', 'superlu', 'pardiso', 'cholmod')
1315
CASE DEFAULT
1316
Stat = CRS_ComplexILUT(Matrix, 0._dp)
1317
END SELECT
1318
END IF
1319
END IF
1320
1321
1322
!
1323
! %-------------------------------------------%
1324
! | M A I N L O O P (Reverse communication) |
1325
! %-------------------------------------------%
1326
!
1327
iter = 1
1328
NewSystem = .TRUE.
1329
1330
Iterative = ListGetString( Solver % Values, &
1331
'Linear System Solver', stat ) == 'iterative'
1332
1333
stat = ListGetLogical( Solver % Values, 'No Precondition Recompute', stat )
1334
1335
IF ( Iterative .AND. Stat ) THEN
1336
CALL ListAddLogical( Solver % Values, 'No Precondition Recompute', .FALSE. )
1337
END IF
1338
1339
A => Matrix
1340
1341
DO WHILE( ido /= 99 )
1342
! %---------------------------------------------%
1343
! | Repeatedly call the routine DSAUPD and take |
1344
! | actions indicated by parameter IDO until |
1345
! | either convergence is indicated or maxitr |
1346
! | has been exceeded. |
1347
! %---------------------------------------------%
1348
!
1349
CALL ZNAUPD ( ido, BMAT, n, Which, NEIG, TOL, &
1350
RESID, NCV, v, n, IPARAM, IPNTR, WORKD, WORKL, lWORKL, RWORK, kinfo )
1351
1352
IF (ido == -1 .OR. ido == 1) THEN
1353
IF(InfoActive(20)) THEN
1354
CALL Info(Caller,'Arpack reverse communication calls: '//I2S(iter))
1355
ELSE
1356
CALL Info(Caller, '.', .TRUE.)
1357
END IF
1358
Iter = Iter + 1
1359
!---------------------------------------------------------------------
1360
! Perform y <--- OP*x = inv[M]*A*x (lumped mass)
1361
! ido =-1 inv(A-sigmaR*M)*M*x
1362
! ido = 1 inv(A-sigmaR*M)*z
1363
!---------------------------------------------------------------------
1364
1365
! Some strategies (such as 'block') may depend on that these are set properly
1366
! to reflect the linear problem under study.
1367
SaveRhs => A % rhs
1368
A % rhs => b
1369
Dofs = Solver % Variable % Dofs
1370
1371
IF ( ido == -1 ) THEN
1372
SaveValues => A % Values
1373
A % Values => A % MassValues
1374
CALL CRS_ComplexMatrixVectorMultiply( A, WORKD(IPNTR(1)), WORKD(IPNTR(2)) )
1375
A % Values => SaveValues
1376
1377
DO i=0,n-1
1378
b(2*i+1) = REAL( WORKD( IPNTR(2)+i ) )
1379
b(2*i+2) = AIMAG( WORKD( IPNTR(2)+i ) )
1380
END DO
1381
ELSE
1382
DO i=0,n-1
1383
b(2*i+1) = REAL( WORKD( IPNTR(3)+i ) )
1384
b(2*i+2) = AIMAG( WORKD( IPNTR(3)+i ) )
1385
END DO
1386
END IF
1387
1388
DO i=0,n-1
1389
x(2*i+1) = REAL( WORKD( IPNTR(2)+i ) )
1390
x(2*i+2) = AIMAG( WORKD( IPNTR(2)+i ) )
1391
END DO
1392
1393
SELECT CASE( Method )
1394
CASE('multigrid')
1395
CALL MultiGridSolve( A, x, b, &
1396
DOFs, Solver, Solver % MultiGridLevel, NewSystem )
1397
CASE('iterative')
1398
CALL IterSolver( A, x, b, Solver )
1399
CASE('block')
1400
CALL BlockSolveExt( A, x, b, Solver )
1401
CASE ('direct')
1402
CALL DirectSolver( A, x, b, Solver )
1403
CASE DEFAULT
1404
CALL Fatal(Caller,'Unknown linear system method: '//TRIM(Method))
1405
END SELECT
1406
1407
A % rhs => SaveRhs
1408
1409
DO i=0,n-1
1410
WORKD( IPNTR(2)+i ) = CMPLX( x(2*i+1), x(2*i+2),KIND=dp )
1411
END DO
1412
!
1413
ELSE IF (ido == 2) THEN
1414
!
1415
! %-----------------------------------------%
1416
! | Perform y <--- M*x. |
1417
! | Need the matrix vector multiplication |
1418
! | routine here that takes WORKD(IPNTR(1)) |
1419
! | as the input and returns the result to |
1420
! | WORKD(IPNTR(2)). |
1421
! %-----------------------------------------%
1422
!
1423
SaveValues => A % Values
1424
A % Values => A % MassValues
1425
CALL CRS_ComplexMatrixVectorMultiply(A, WORKD(IPNTR(1)), WORKD(IPNTR(2)) )
1426
A % Values => SaveValues
1427
END IF
1428
1429
IF ( NewSystem .AND. ido /= 2 ) THEN
1430
IF ( Iterative ) THEN
1431
CALL ListAddLogical( Solver % Values, 'No Precondition Recompute', .TRUE. )
1432
ELSE
1433
CALL ListAddLogical( Solver % Values, 'Linear System Refactorize', .FALSE. )
1434
END IF
1435
NewSystem = .FALSE.
1436
END IF
1437
END DO
1438
1439
CALL ListAddLogical( Solver % Values, 'Linear System Refactorize', .TRUE. )
1440
CALL ListAddLogical( Solver % Values, &
1441
'Linear System Free Factorization', .TRUE. )
1442
!
1443
! %-----------------------------------------%
1444
! | Either we have convergence, or there is |
1445
! | an error. |
1446
! %-----------------------------------------%
1447
!
1448
IF ( kinfo /= 0 ) THEN
1449
!
1450
! %--------------------------%
1451
! | Error message, check the |
1452
! | documentation in DNAUPD |
1453
! %--------------------------%
1454
!
1455
WRITE( Message, * ) 'Error with DNAUPD, info = ',kinfo
1456
CALL Fatal( Caller, Message )
1457
!
1458
ELSE
1459
!
1460
! %-------------------------------------------%
1461
! | No fatal errors occurred. |
1462
! | Post-Process using DSEUPD. |
1463
! | |
1464
! | Computed eigenvalues may be extracted. |
1465
! | |
1466
! | Eigenvectors may also be computed now if |
1467
! | desired. (indicated by rvec = .true.) |
1468
! %-------------------------------------------%
1469
!
1470
D = 0.0d0
1471
CALL ZNEUPD ( .TRUE., 'A', Choose, D, V, N, Sigma, WORKEV, BMAT, N, Which, NEIG, &
1472
TOL, RESID, NCV, V, N, IPARAM, IPNTR, WORKD, WORKL, lWORKL, RWORK, IERR )
1473
1474
! %----------------------------------------------%
1475
! | Eigenvalues are returned in the First column |
1476
! | of the two dimensional array D and the |
1477
! | corresponding eigenvectors are returned in |
1478
! | the First NEV columns of the two dimensional |
1479
! | array V if requested. Otherwise, an |
1480
! | orthogonal basis for the invariant subspace |
1481
! | corresponding to the eigenvalues in D is |
1482
! | returned in V. |
1483
! %----------------------------------------------%
1484
!
1485
IF (IERR /= 0) THEN
1486
!
1487
! %------------------------------------%
1488
! | Error condition: |
1489
! | Check the documentation of DNEUPD. |
1490
! %------------------------------------%
1491
!
1492
WRITE( Message, * ) ' Error with DNEUPD, info = ', IERR
1493
CALL Fatal( Caller, Message )
1494
END IF
1495
!
1496
! %------------------------------------------%
1497
! | Print additional convergence information |
1498
! %------------------------------------------%
1499
!
1500
IF ( kinfo == 1 ) THEN
1501
CALL Fatal( Caller, 'Maximum number of iterations reached.' )
1502
ELSE IF ( kinfo == 3 ) THEN
1503
CALL Fatal( Caller, 'No shifts could be applied during implicit Arnoldi update, try increasing NCV.' )
1504
END IF
1505
!
1506
! Sort the eigenvalues to ascending order:
1507
! ----------------------------------------
1508
ALLOCATE( Perm(NEIG) )
1509
Perm = [ (i, i=1,NEIG) ]
1510
DO i=1,NEIG
1511
EigValues(i) = D(i)
1512
END DO
1513
CALL SortC( NEIG, EigValues, Perm )
1514
1515
!
1516
! Extract the values to ELMER structures:
1517
! -----------------------------------------
1518
CALL Info( Caller, ' ', Level=4 )
1519
CALL Info( Caller, 'EIGEN SYSTEM SOLUTION COMPLETE: ', Level=4 )
1520
CALL Info( Caller, ' ', Level=4 )
1521
WRITE( Message,'(A,ES12.3)') 'Convergence criterion is: ', TOL
1522
CALL Info( Caller, Message, Level=7 )
1523
CALL Info( Caller,'Number of converged Ritz values is: '//I2S(IPARAM(5)),Level=4)
1524
CALL Info( Caller, ' ', Level=7 )
1525
CALL Info( Caller, 'Computed Eigen Values: ', Level=4 )
1526
CALL Info( Caller, '--------------------------------', Level=7 )
1527
1528
! Restore matrix values, if modified when using shift:
1529
! ---------------------------------------------------
1530
IF ( Sigma /= 0._dp ) THEN
1531
Matrix % Values = Matrix % Values + Sigma * Matrix % MassValues
1532
END IF
1533
1534
EigVectors = -1.0_dp
1535
1536
!PRINT *,'NEIG:',NEIG,n,SIZE(EigVectors,1),SIZE(EigVectors,2),&
1537
! SIZE(V,1),SIZE(V,2)
1538
1539
k = 1
1540
DO i=1,NEIG
1541
p = Perm(i)
1542
WRITE( Message, * ) i,EigValues(i)
1543
CALL Info( Caller, Message, Level=4 )
1544
1545
DO j=1,N
1546
EigVectors(i,j) = V(j,p)
1547
END DO
1548
END DO
1549
1550
IF ( ListGetLogical( Params, 'Eigen System Compute Residuals', stat ) ) THEN
1551
CALL Info(Caller,'Computing eigen system residuals',Level=8)
1552
CALL CheckResidualsComplex( Matrix, Neig, EigValues, EigVectors )
1553
END IF
1554
CALL Info( Caller, '--------------------------------',Level=4 )
1555
!
1556
END IF
1557
1558
DEALLOCATE( WORKL, D, WORKEV, V, CHOOSE, Perm )
1559
1560
CALL Info(Caller,'Finished eigen system solution!',Level=8)
1561
1562
#else
1563
CALL Fatal( Caller, 'Arpack Eigen System Solver not available!' )
1564
#endif
1565
!
1566
!------------------------------------------------------------------------------
1567
END SUBROUTINE ArpackEigenSolveComplex
1568
!------------------------------------------------------------------------------
1569
1570
1571
!------------------------------------------------------------------------------
1572
SUBROUTINE CheckResidualsComplex( Matrix, n, Eigs, EigVectors )
1573
!------------------------------------------------------------------------------
1574
USE CRSMatrix
1575
TYPE(Matrix_t), POINTER :: Matrix
1576
INTEGER :: i,j,k,n,sz
1577
COMPLEX(KIND=dp) :: Eigs(:), EigVectors(:,:)
1578
1579
REAL(KIND=dp), ALLOCATABLE, TARGET :: vals(:)
1580
REAL(KIND=dp), POINTER CONTIG :: svals(:)
1581
COMPLEX(KIND=dp) :: c,m
1582
COMPLEX(KIND=dp), ALLOCATABLE :: x(:), y(:)
1583
1584
sz = Matrix % NumberOfRows/2
1585
ALLOCATE( x(sz), y(sz), vals(size(matrix % values)) ); vals=0
1586
DO i=1,n
1587
DO j=1,sz
1588
DO k=Matrix % Rows(2*j-1), Matrix % Rows(2*j)-1,2
1589
c = CMPLX(Matrix % Values(k), -Matrix % Values(k+1),KIND=dp)
1590
m = CMPLX(Matrix % MassValues(k), -Matrix% MassValues(k+1),KIND=dp)
1591
c = c - eigs(i) * m
1592
vals(k) = REAL(c)
1593
vals(k+1) = -AIMAG(c)
1594
END DO
1595
END DO
1596
1597
x = EigVectors(i,:)
1598
svals => Matrix % Values
1599
Matrix % Values => vals
1600
CALL CRS_ComplexMatrixVectorMultiply( Matrix, x, y )
1601
Matrix % Values => svals
1602
1603
WRITE( Message, * ) 'L^2 Norm of the residual: ', i, SQRT(SUM(ABS(y)**2))
1604
CALL Info( 'CheckResidualsComplex', Message, Level = 3 )
1605
END DO
1606
DEALLOCATE( x,y )
1607
!------------------------------------------------------------------------------
1608
END SUBROUTINE CheckResidualsComplex
1609
!------------------------------------------------------------------------------
1610
1611
1612
!------------------------------------------------------------------------------
1613
SUBROUTINE ArpackDampedEigenSolve( Solver, KMatrix, N, NEIG, EigValues, &
1614
EigVectors )
1615
!------------------------------------------------------------------------------
1616
!> Solution of Eigen value problems using ARPACK library, damped version.
1617
!------------------------------------------------------------------------------
1618
USE Multigrid
1619
USE ElementUtils
1620
1621
IMPLICIT NONE
1622
1623
TYPE(Matrix_t), POINTER :: KMatrix
1624
TYPE(Solver_t), TARGET :: Solver
1625
INTEGER :: N, NEIG, DPERM(n)
1626
COMPLEX(KIND=dp) :: EigValues(:), EigVectors(:,:)
1627
1628
#ifdef USE_ARPACK
1629
1630
! %--------------%
1631
! | Local Arrays |
1632
! %--------------%
1633
1634
TYPE(Matrix_t), POINTER :: MMatrix, BMatrix
1635
REAL(KIND=dp), TARGET :: WORKD(3*N), RESID(N)
1636
REAL(KIND=dp), POINTER CONTIG :: x(:), b(:)
1637
INTEGER :: IPARAM(11), IPNTR(14)
1638
INTEGER, ALLOCATABLE :: Perm(:), kMap(:)
1639
LOGICAL, ALLOCATABLE :: Choose(:)
1640
CHARACTER(:), ALLOCATABLE :: str
1641
COMPLEX(KIND=dp) :: s, EigTemp(NEIG)
1642
REAL(KIND=dp), ALLOCATABLE :: WORKL(:), D(:,:), WORKEV(:), V(:,:)
1643
1644
! %---------------%
1645
! | Local Scalars |
1646
! %---------------%
1647
1648
CHARACTER :: BMAT*1, Which*2
1649
INTEGER :: IDO, NCV, lWORKL, kinfo, i, j, k, l, p, IERR, iter, &
1650
NCONV, maxitr, ishfts, mode, istat, DampedMaxIter, ILU
1651
LOGICAL :: First, Stat, NewSystem, UseI = .FALSE.
1652
REAL(KIND=dp) :: SigmaR, SigmaI, TOL, DampedTOL, IScale
1653
1654
CHARACTER(*), PARAMETER :: Caller = 'DampedEigenSolve'
1655
1656
1657
! %-------------------------------------%
1658
! | So far only iterative solver |
1659
! | and non-lumped matrixes are allowed |
1660
! %-------------------------------------%
1661
1662
IF ( KMatrix % Lumped ) THEN
1663
CALL Error( Caller, 'Lumped matrixes are not allowed' )
1664
END IF
1665
1666
IF ( ListGetString( Solver % Values, 'Linear System Solver', Stat ) &
1667
== 'direct' ) THEN
1668
CALL Error( Caller, 'Direct solver is not allowed' )
1669
END IF
1670
1671
IF ( Solver % MultiGridSolver ) THEN
1672
CALL Error( Caller, 'MultiGrid solver is not allowed' )
1673
END IF
1674
1675
Stat = ListGetLogical( Solver % Values, &
1676
'No Precondition Recompute', Stat )
1677
1678
IF ( Stat ) THEN
1679
CALL ListAddLogical( Solver % Values, &
1680
'No Precondition Recompute', .FALSE. )
1681
END IF
1682
1683
1684
! %-----------------------%
1685
! | Executable Statements |
1686
! %-----------------------%
1687
1688
! %----------------------------------------------------%
1689
! | The number N is the dimension of the matrix. A |
1690
! | generalized eigenvalue problem is solved (BMAT = |
1691
! | 'G'.) NEV is the number of eigenvalues to be |
1692
! | approximated. The user can modify NEV, NCV, WHICH |
1693
! | to solve problems of different sizes, and to get |
1694
! | different parts of the spectrum. However, The |
1695
! | following conditions must be satisfied: |
1696
! | N <= MAXN, |
1697
! | NEV <= MAXNEV, |
1698
! | NEV + 1 <= NCV <= MAXNCV |
1699
! %----------------------------------------------------%
1700
1701
NCV = 3 * NEIG + 1
1702
1703
ALLOCATE( WORKL(3*NCV**2 + 6*NCV), D(NCV,3), &
1704
WORKEV(3*NCV), V(n,NCV), CHOOSE(NCV), STAT=istat )
1705
1706
CHOOSE = .FALSE.
1707
Workl = 0.0d0
1708
workev = 0.0d0
1709
v = 0.0d0
1710
d = 0.0d0
1711
1712
IF ( istat /= 0 ) THEN
1713
CALL Fatal( Caller, 'Memory allocation error.' )
1714
END IF
1715
1716
! %--------------------------------------------------%
1717
! | The work array WORKL is used in DSAUPD as |
1718
! | workspace. Its dimension LWORKL is set as |
1719
! | illustrated below. The parameter TOL determines |
1720
! | the stopping criterion. If TOL<=0, machine |
1721
! | precision is used. The variable IDO is used for |
1722
! | reverse communication and is initially set to 0. |
1723
! | Setting INFO=0 indicates that a random vector is |
1724
! | generated in DSAUPD to start the Arnoldi |
1725
! | iteration. |
1726
! %--------------------------------------------------%
1727
1728
TOL = ListGetConstReal( Solver % Values, &
1729
'Eigen System Convergence Tolerance', Stat )
1730
1731
IF ( .NOT. Stat ) THEN
1732
TOL = 100 * ListGetConstReal( Solver % Values, &
1733
'Linear System Convergence Tolerance' )
1734
END IF
1735
1736
DampedMaxIter = ListGetInteger( Solver % Values, &
1737
'Linear System Max Iterations', Stat, 1 )
1738
1739
IF ( .NOT. Stat ) DampedMaxIter = 100
1740
1741
DampedTOL = ListGetConstReal( Solver % Values, &
1742
'Linear System Convergence Tolerance', Stat )
1743
1744
IF ( .NOT. Stat ) DampedTOL = TOL / 100
1745
1746
UseI = ListGetLogical( Solver % Values, &
1747
'Eigen System Use Identity', Stat )
1748
1749
IF ( .NOT. Stat ) UseI = .TRUE.
1750
! IF ( .NOT. Stat ) UseI = .FALSE. Changed by Antti 2004-02-18
1751
1752
IDO = 0
1753
kinfo = 0
1754
lWORKL = 3*NCV**2 + 6*NCV
1755
! %---------------------------------------------------%
1756
! | This program uses exact shifts with respect to |
1757
! | the current Hessenberg matrix (IPARAM(1) = 1). |
1758
! | IPARAM(3) specifies the maximum number of Arnoldi |
1759
! | iterations allowed. Mode 2 of DSAUPD is used |
1760
! | (IPARAM(7) = 2). All these options may be |
1761
! | changed by the user. For details, see the |
1762
! | documentation in DSAUPD. |
1763
! %---------------------------------------------------%
1764
1765
ishfts = 1
1766
BMAT = 'G'
1767
Mode = 3
1768
1769
SELECT CASE( ListGetString(Solver % Values, 'Eigen System Select',Stat) )
1770
CASE( 'smallest magnitude' )
1771
Which = 'LM'
1772
1773
CASE( 'largest magnitude')
1774
Which = 'SM'
1775
1776
CASE( 'smallest real part')
1777
Which = 'LR'
1778
1779
CASE( 'largest real part')
1780
Which = 'SR'
1781
1782
CASE( 'smallest imag part' )
1783
Which = 'LI'
1784
1785
CASE( 'largest imag part' )
1786
Which = 'SI'
1787
1788
CASE DEFAULT
1789
Which = 'LM'
1790
END SELECT
1791
1792
Maxitr = ListGetInteger(Solver % Values,'Eigen System Max Iterations',Stat)
1793
IF ( .NOT. Stat ) Maxitr = 300
1794
1795
IPARAM = 0
1796
IPARAM(1) = ishfts
1797
IPARAM(3) = maxitr
1798
IPARAM(7) = mode
1799
1800
SigmaR = 0.0d0
1801
SigmaI = 0.0d0
1802
V = 0.0d0
1803
!------------------------------------------------------------------------------
1804
! Create M and B matrixes
1805
!------------------------------------------------------------------------------
1806
MMatrix => AllocateMatrix()
1807
MMatrix % Values => KMatrix % MassValues
1808
MMatrix % NumberOfRows = KMatrix % NumberOfRows
1809
MMatrix % Rows => KMatrix % Rows
1810
MMatrix % Cols => KMatrix % Cols
1811
MMatrix % Diag => KMatrix % Diag
1812
1813
IScale = MAXVAL( ABS( MMatrix % Values ) )
1814
1815
BMatrix => AllocateMatrix()
1816
BMatrix % NumberOfRows = KMatrix % NumberOfRows
1817
BMatrix % Rows => KMatrix % Rows
1818
BMatrix % Cols => KMatrix % Cols
1819
BMatrix % Diag => KMatrix % Diag
1820
BMatrix % Values => KMatrix % DampValues
1821
!------------------------------------------------------------------------------
1822
! ILU Preconditioning
1823
!------------------------------------------------------------------------------
1824
str = ListGetString( Solver % Values, 'Linear System Preconditioning', Stat )
1825
1826
ILU = 0
1827
IF ( .NOT. Stat ) THEN
1828
CALL Warn( Caller, 'Using ILU0 preconditioning' )
1829
ELSE
1830
IF ( str == 'none' .OR. str == 'diagonal' .OR. &
1831
str == 'ilut' .OR. str == 'multigrid' ) THEN
1832
1833
ILU = 0
1834
CALL Warn( Caller, 'Useing ILU0 preconditioning' )
1835
ELSE IF ( SEQL(str,'ilu') ) THEN
1836
IF(LEN(str)>=4) ILU = ICHAR(str(4:4)) - ICHAR('0')
1837
IF ( ILU < 0 .OR. ILU > 9 ) ILU = 0
1838
ELSE
1839
ILU = 0
1840
CALL Warn( Caller,'Unknown preconditioner type, using ILU0' )
1841
END IF
1842
END IF
1843
1844
KMatrix % Cholesky = ListGetLogical( Solver % Values, &
1845
'Linear System Symmetric ILU', Stat )
1846
1847
Stat = CRS_IncompleteLU( KMatrix, ILU, Solver % Values )
1848
IF ( .NOT. UseI ) Stat = CRS_IncompleteLU( MMatrix, ILU, Solver % Values )
1849
1850
! %-------------------------------------------%
1851
! | M A I N L O O P (Reverse communication) |
1852
! %-------------------------------------------%
1853
1854
iter = 1
1855
DO WHILE( ido /= 99 )
1856
1857
! %---------------------------------------------%
1858
! | Repeatedly call the routine DSAUPD and take |
1859
! | actions indicated by parameter IDO until |
1860
! | either convergence is indicated or maxitr |
1861
! | has been exceeded. |
1862
! %---------------------------------------------%
1863
CALL DNAUPD ( ido, BMAT, n, Which, NEIG, TOL, RESID, NCV, v, n, &
1864
IPARAM, IPNTR, WORKD, WORKL, lWORKL, kinfo )
1865
1866
SELECT CASE(ido)
1867
CASE(-1 )
1868
!
1869
! ido =-1 inv(A)*M*x:
1870
!----------------------------
1871
x => workd( ipntr(1) : ipntr(1)+n-1 )
1872
b => workd( ipntr(2) : ipntr(2)+n-1 )
1873
1874
CALL EigenMGmv2( n/2, MMatrix, x, b, UseI, IScale )
1875
DO i=1,n
1876
x(i) = b(i)
1877
END DO
1878
CALL EigenBiCG( n, KMatrix, MMatrix, BMatrix, &
1879
b, x, DampedMaxIter, DampedTOL, UseI, IScale )
1880
1881
CASE( 1 )
1882
!
1883
! ido =-1 inv(A)*z:
1884
!--------------------------
1885
IF(InfoActive(20)) THEN
1886
CALL Info(Caller,'Arpack reverse communication calls: '//I2S(iter))
1887
ELSE
1888
CALL Info(Caller, '.', .TRUE.)
1889
END IF
1890
iter = iter + 1
1891
1892
x => workd( ipntr(2) : ipntr(2)+n-1 )
1893
b => workd( ipntr(3) : ipntr(3)+n-1 )
1894
1895
CALL EigenBiCG( n, KMatrix, MMatrix, BMatrix, &
1896
x, b, DampedMaxIter, DampedTOL, UseI,IScale )
1897
1898
CASE( 2 )
1899
! %-----------------------------------------%
1900
! | Perform y <--- M*x. |
1901
! | Need the matrix vector multiplication |
1902
! | routine here that takes WORKD(IPNTR(1)) |
1903
! | as the input and returns the result to |
1904
! | WORKD(IPNTR(2)). |
1905
! %-----------------------------------------%
1906
x => workd( ipntr(1): ipntr(1)+n-1 )
1907
b => workd( ipntr(2): ipntr(2)+n-1 )
1908
CALL EigenMGmv2( N/2, MMatrix, x, b, UseI, IScale )
1909
1910
CASE DEFAULT
1911
END SELECT
1912
1913
END DO
1914
1915
! %-----------------------------------------%
1916
! | Either we have convergence, or there is |
1917
! | an error. |
1918
! %-----------------------------------------%
1919
!
1920
IF ( kinfo /= 0 ) THEN
1921
!
1922
! %--------------------------%
1923
! | Error message, check the |
1924
! | documentation in DNAUPD |
1925
! %--------------------------%
1926
!
1927
WRITE( Message, * ) 'Error with DNAUPD, info = ',kinfo
1928
CALL Fatal( Caller, Message )
1929
ELSE
1930
! %-------------------------------------------%
1931
! | No fatal errors occurred. |
1932
! | Post-Process using DSEUPD. |
1933
! | |
1934
! | Computed eigenvalues may be extracted. |
1935
! | |
1936
! | Eigenvectors may also be computed now if |
1937
! | desired. (indicated by rvec = .true.) |
1938
! %-------------------------------------------%
1939
1940
D = 0.0d0
1941
CALL DNEUPD ( .TRUE., 'A', Choose, D, D(1,2), V, N, SigmaR, SigmaI, &
1942
WORKEV, BMAT, N, Which, NEIG, TOL, RESID, NCV, V, N, IPARAM, IPNTR, &
1943
WORKD, WORKL, lWORKL, IERR )
1944
! %----------------------------------------------%
1945
! | Eigenvalues are returned in the First column |
1946
! | of the two dimensional array D and the |
1947
! | corresponding eigenvectors are returned in |
1948
! | the First NEV columns of the two dimensional |
1949
! | array V if requested. Otherwise, an |
1950
! | orthogonal basis for the invariant subspace |
1951
! | corresponding to the eigenvalues in D is |
1952
! | returned in V. |
1953
! %----------------------------------------------%
1954
1955
IF ( IERR /= 0 ) THEN
1956
! %------------------------------------%
1957
! | Error condition: |
1958
! | Check the documentation of DNEUPD. |
1959
! %------------------------------------%
1960
WRITE( Message, * ) ' Error with DNEUPD, info = ', IERR
1961
CALL Fatal( Caller, Message )
1962
END IF
1963
1964
! %------------------------------------------%
1965
! | Print additional convergence information |
1966
! %------------------------------------------%
1967
1968
IF ( kinfo == 1 ) THEN
1969
CALL Fatal( Caller, 'Maximum number of iterations reached.' )
1970
ELSE IF ( kinfo == 3 ) THEN
1971
CALL Fatal( Caller, &
1972
'No shifts could be applied during implicit Arnoldi update, try increasing NCV.' )
1973
END IF
1974
1975
! Sort the eigenvalues to ascending order:
1976
! ( and keep in mind the corresponding vector )
1977
! ---------------------------------------------
1978
DO i = 1, NEIG
1979
EigTemp(i) = CMPLX( D(i,1), D(i,2), KIND=dp )
1980
END DO
1981
1982
ALLOCATE( kMap( NEIG ) )
1983
kMap(1) = 1
1984
DO i = 2, NEIG
1985
IF ( AIMAG( EigTemp(i-1) ) == 0 ) THEN
1986
kMap(i) = kMap(i-1) + 1
1987
ELSE IF ( EigTemp(i) == CONJG( EigTemp(i-1) ) ) THEN
1988
kMap(i) = kMap(i-1)
1989
ELSE
1990
kMap(i) = kMap(i-1) + 2
1991
END IF
1992
END DO
1993
1994
ALLOCATE( Perm( NEIG ) )
1995
Perm = [ (i, i=1,NEIG) ]
1996
CALL SortC( NEIG, EigTemp, Perm )
1997
1998
! Extract the values to ELMER structures:
1999
! -----------------------------------------
2000
CALL Info( Caller, ' ', Level=4 )
2001
CALL Info( Caller, 'EIGEN SYSTEM SOLUTION COMPLETE: ', Level=4 )
2002
CALL Info( Caller, ' ', Level=4 )
2003
WRITE( Message,'(A,ES12.3)') 'Convergence criterion is: ', TOL
2004
CALL Info( Caller, Message, Level=7 )
2005
CALL Info(Caller,'Number of converged Ritz values is: '//I2S(IPARAM(5)),Level=4)
2006
CALL Info( Caller, ' ', Level=7 )
2007
CALL Info( Caller, 'Computed Eigen Values: ', Level=4 )
2008
CALL Info( Caller, '--------------------------------', Level=7 )
2009
2010
!------------------------------------------------------------------------------
2011
! Extracting the right eigen values and vectors.
2012
!------------------------------------------------------------------------------
2013
2014
! Take the first ones separately
2015
!------------------------------------------------------------------------------
2016
EigValues(1) = EigTemp(1)
2017
2018
WRITE( Message, * ) 1,EigValues(1)
2019
CALL Info( Caller, Message, Level=4 )
2020
2021
p = Perm(1)
2022
k = kMap(p)
2023
IF( AIMAG( EigValues(1) ) == 0 ) THEN
2024
DO j = 1, N/2
2025
EigVectors(1,j) = CMPLX( V(j,k), 0.0d0,KIND=dp )
2026
END DO
2027
ELSE
2028
DO j = 1, N/2
2029
EigVectors(1,j) = CMPLX( V(j,k), V(j,k+1),KIND=dp )
2030
END DO
2031
END IF
2032
2033
! Then take the rest of requested values
2034
!------------------------------------------------------------------------------
2035
l = 2
2036
DO i = 2, NEIG/2
2037
IF ( AIMAG( EigValues(i-1) ) /= 0 .AND. &
2038
ABS(AIMAG(EigTemp(l))) == ABS(AIMAG(EigValues(i-1)))) l=l+1
2039
2040
EigValues(i) = EigTemp(l)
2041
IF ( AIMAG( EigValues(i) ) < 0 ) THEN
2042
EigValues(i) = CONJG( EigValues(i) )
2043
END IF
2044
2045
WRITE( Message, * ) i,EigValues(i)
2046
CALL Info( Caller, Message, Level=4 )
2047
2048
p = Perm(l)
2049
k = kMap(p)
2050
IF( AIMAG( EigValues(i) ) == 0 ) THEN
2051
DO j = 1, N/2
2052
EigVectors(i,j) = CMPLX( V(j,k), 0.0d0,KIND=dp )
2053
END DO
2054
ELSE
2055
DO j = 1, N/2
2056
EigVectors(i,j) = CMPLX( V(j,k), V(j,k+1),KIND=dp )
2057
END DO
2058
END IF
2059
2060
l = l + 1
2061
END DO
2062
2063
DO i = 1, NEIG/2
2064
s = 0.0d0
2065
DO j=1,N/2
2066
DO k = MMatrix % Rows(j), MMatrix % Rows(j+1)-1
2067
s = s + MMatrix % Values(k) * &
2068
CONJG( EigVectors(i,j) ) * EigVectors(i,MMatrix % Cols(k))
2069
END DO
2070
END DO
2071
IF ( ABS(s) > 0 ) EigVectors(i,:) = EigVectors(i,:) / SQRT(s)
2072
END DO
2073
2074
CALL Warn(Caller,'Check that the scaling is not done twice if you call this!')
2075
2076
! Standard scaling moved to ScaleEigenVectors
2077
2078
2079
CALL Info( Caller, '--------------------------------',Level=4 )
2080
END IF
2081
2082
DEALLOCATE( WORKL, D, WORKEV, V, CHOOSE, Perm )
2083
2084
NULLIFY( MMatrix % Rows, MMatrix % Cols, MMatrix % Diag, MMatrix % Values )
2085
CALL FreeMatrix( MMatrix )
2086
2087
NULLIFY( BMatrix % Rows, BMatrix % Cols, BMatrix % Diag, BMatrix % Values )
2088
CALL FreeMatrix( BMatrix )
2089
#else
2090
CALL Fatal( Caller, 'Arpack Eigen System Solver not available!' )
2091
#endif
2092
!------------------------------------------------------------------------------
2093
END SUBROUTINE ArpackDampedEigenSolve
2094
!------------------------------------------------------------------------------
2095
2096
2097
2098
!------------------------------------------------------------------------------
2099
SUBROUTINE EigenBiCG( n, KMatrix, MMatrix, BMatrix, x, b, Rounds, TOL, UseI, IScale )
2100
!------------------------------------------------------------------------------
2101
USE CRSMatrix
2102
2103
TYPE(Matrix_t), POINTER :: KMatrix, MMatrix, BMatrix
2104
INTEGER :: Rounds
2105
REAL(KIND=dp) :: TOL, IScale
2106
REAL(KIND=dp) CONTIG :: x(:), b(:)
2107
LOGICAL :: UseI
2108
!------------------------------------------------------------------------------
2109
INTEGER :: i, n
2110
REAL(KIND=dp) :: alpha, beta, omega, rho, oldrho, bnorm
2111
REAL(KIND=dp) :: r(n), Ri(n), P(n), V(n), S(n), &
2112
T(n), T1(n), T2(n), Tmp(n/2)
2113
!------------------------------------------------------------------------------
2114
CALL EigenMGmv1( n/2, KMatrix, MMatrix, BMatrix, x, r, UseI, IScale )
2115
r(1:n) = b(1:n) - r(1:n)
2116
2117
Ri(1:n) = r(1:n)
2118
P(1:n) = 0
2119
V(1:n) = 0
2120
omega = 1
2121
alpha = 0
2122
oldrho = 1
2123
Tmp = 0.0d0
2124
2125
bnorm = EigenMGdot( n,b,b )
2126
2127
CALL Info( 'EigenBiCG', '--------------------' )
2128
CALL Info( 'EigenBiCG', 'Begin BiCG iteration' )
2129
CALL Info( 'EigenBiCG', '--------------------' )
2130
2131
DO i=1,Rounds
2132
rho = EigenMGdot( n, r, Ri )
2133
2134
beta = alpha * rho / ( oldrho * omega )
2135
P(1:n) = r(1:n) + beta * (P(1:n) - omega*V(1:n))
2136
!------------------------------------------------------------------------------
2137
Tmp(1:n/2) = P(1:n/2)
2138
2139
IF ( .NOT. UseI ) THEN
2140
CALL CRS_LUSolve( n/2, MMatrix, Tmp(1:n/2) )
2141
ELSE
2142
Tmp(1:n/2) = Tmp(1:n/2) / IScale
2143
END IF
2144
2145
V(n/2+1:n) = Tmp(1:n/2)
2146
2147
Tmp(1:n/2) = P(n/2+1:n)
2148
CALL CRS_LUSolve( n/2, KMatrix, Tmp(1:n/2) )
2149
V(1:n/2) = -1*Tmp(1:n/2)
2150
2151
T1(1:n) = V(1:n)
2152
CALL EigenMGmv1( n/2, KMatrix, MMatrix, BMatrix, T1, V, UseI, IScale )
2153
!------------------------------------------------------------------------------
2154
alpha = rho / EigenMGdot( n, Ri, V )
2155
S(1:n) = r(1:n) - alpha * V(1:n)
2156
!------------------------------------------------------------------------------
2157
Tmp(1:n/2) = S(1:n/2)
2158
2159
IF ( .NOT. UseI ) THEN
2160
CALL CRS_LUSolve( n/2, MMatrix, Tmp(1:n/2) )
2161
ELSE
2162
Tmp(1:n/2) = Tmp(1:n/2) / IScale
2163
END IF
2164
2165
T(n/2+1:n) = Tmp(1:n/2)
2166
2167
Tmp(1:n/2) = S(n/2+1:n)
2168
CALL CRS_LUSolve( n/2, KMatrix, Tmp(1:n/2) )
2169
T(1:n/2) = -1*Tmp(1:n/2)
2170
2171
T2(1:n) = T(1:n)
2172
CALL EigenMGmv1( n/2, KMatrix, MMatrix, BMatrix, T2, T, UseI, IScale )
2173
!------------------------------------------------------------------------------
2174
omega = EigenMGdot( n,T,S ) / EigenMGdot( n,T,T )
2175
oldrho = rho
2176
r(1:n) = S(1:n) - omega*T(1:n)
2177
x(1:n) = x(1:n) + alpha*T1(1:n) + omega*T2(1:n)
2178
!------------------------------------------------------------------------------
2179
WRITE(*,*) i,EigenMGdot( n,r,r ) / bnorm
2180
2181
IF ( EigenMGdot( n,r,r ) / bnorm < TOL ) THEN
2182
CALL EigenMGmv1( n/2, KMatrix, MMatrix, BMatrix, x, r, UseI, IScale )
2183
r(1:n) = b(1:n) - r(1:n)
2184
2185
WRITE( Message,* ) 'Correct residual:', EigenMGdot( n,r,r ) / bnorm
2186
CALL Info( 'EigenBiCG', Message )
2187
2188
IF ( EigenMGdot( n,r,r ) / bnorm < TOL ) EXIT
2189
END IF
2190
END DO
2191
2192
IF ( EigenMGdot( n,r,r ) / bnorm >= TOL ) THEN
2193
CALL Fatal( 'EigenBiCG', 'Failed to converge' )
2194
END IF
2195
!------------------------------------------------------------------------------
2196
END SUBROUTINE EigenBiCG
2197
!------------------------------------------------------------------------------
2198
2199
2200
2201
!------------------------------------------------------------------------------
2202
FUNCTION EigenMGdot( n, x, y ) RESULT(s)
2203
!------------------------------------------------------------------------------
2204
USE Types
2205
INTEGER :: n
2206
REAL(KIND=dp) :: s, x(:), y(:)
2207
2208
s = DOT_PRODUCT( x(1:n), y(1:n) )
2209
!------------------------------------------------------------------------------
2210
END FUNCTION EigenMGdot
2211
!------------------------------------------------------------------------------
2212
2213
2214
2215
!------------------------------------------------------------------------------
2216
SUBROUTINE EigenMGmv1( n, KMatrix, MMatrix, BMatrix, x, b, UseI, IScale )
2217
!------------------------------------------------------------------------------
2218
USE CRSMatrix
2219
2220
INTEGER :: n
2221
TYPE(Matrix_t), POINTER :: KMatrix, MMatrix, BMatrix
2222
REAL(KIND=dp) :: IScale
2223
REAL(KIND=dp) CONTIG :: x(:), b(:)
2224
LOGICAL :: UseI
2225
2226
REAL(KIND=dp) :: Tmp(n)
2227
2228
Tmp = 0.0d0
2229
b = 0.0d0
2230
2231
IF ( .NOT. UseI ) THEN
2232
CALL CRS_MatrixVectorMultiply( MMatrix, x(n+1:2*n), Tmp(1:n) )
2233
b(1:n) = b(1:n) + Tmp(1:n)
2234
ELSE
2235
b(1:n) = x(n+1:2*n) * IScale
2236
END IF
2237
2238
CALL CRS_MatrixVectorMultiply( KMatrix, x(1:n), Tmp(1:n) )
2239
b(n+1:2*n) = b(n+1:2*n) - Tmp(1:n)
2240
2241
CALL CRS_MatrixVectorMultiply( BMatrix, x(n+1:2*n), Tmp(1:n) )
2242
b(n+1:2*n) = b(n+1:2*n) - Tmp(1:n)
2243
!------------------------------------------------------------------------------
2244
END SUBROUTINE EigenMGmv1
2245
!------------------------------------------------------------------------------
2246
2247
!------------------------------------------------------------------------------
2248
SUBROUTINE EigenMGmv2( n, MMatrix, x, b, UseI, IScale )
2249
!------------------------------------------------------------------------------
2250
USE CRSMatrix
2251
2252
INTEGER :: n
2253
REAL(KIND=dp) CONTIG :: x(:), b(:)
2254
REAL(KIND=dp) :: IScale
2255
TYPE(Matrix_t), POINTER :: MMatrix
2256
LOGICAL :: UseI
2257
2258
IF ( .NOT. UseI ) THEN
2259
CALL CRS_MatrixVectorMultiply( MMatrix, x(1:n), b(1:n) )
2260
ELSE
2261
b(1:n) = x(1:n) * IScale
2262
END IF
2263
CALL CRS_MatrixVectorMultiply( MMatrix, x(n+1:2*n), b(n+1:2*n) )
2264
!------------------------------------------------------------------------------
2265
END SUBROUTINE EigenMGmv2
2266
!------------------------------------------------------------------------------
2267
2268
!------------------------------------------------------------------------------
2269
END MODULE EigenSolve
2270
!------------------------------------------------------------------------------
2271
2272
!> \} ElmerLib
2273
2274