Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/fem/src/DirectSolve.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
! * Authors: Juha Ruokolainen
27
! * Email: [email protected]
28
! * Web: http://www.csc.fi/elmer
29
! * Address: CSC - IT Center for Science Ltd.
30
! * Keilaranta 14
31
! * 02101 Espoo, Finland
32
! *
33
! * Original Date: 08 Jun 1997
34
! *
35
! *****************************************************************************/
36
37
!> \ingroup ElmerLib
38
!> \{
39
40
!------------------------------------------------------------------------------
41
!> Module containing the direct solvers for linear systems given in CRS format.
42
!> Included are Lapack band matrix solver, multifrontal Umfpack, MUMPS, SuperLU,
43
!> and Pardiso. Note that many of these are linked in with ElmerSolver only
44
!> if they are made available at the compilation time.
45
!------------------------------------------------------------------------------
46
47
#include "../config.h"
48
49
MODULE DirectSolve
50
51
USE CRSMatrix
52
USE BandMatrix
53
USE SParIterSolve
54
55
IMPLICIT NONE
56
57
CONTAINS
58
59
60
!------------------------------------------------------------------------------
61
!> Solver the complex linear system using direct band matrix solver from of Lapack.
62
!------------------------------------------------------------------------------
63
SUBROUTINE ComplexBandSolver( A,x,b, Free_fact )
64
!------------------------------------------------------------------------------
65
66
LOGICAL, OPTIONAL :: Free_Fact
67
TYPE(Matrix_t) :: A
68
REAL(KIND=dp) :: x(*),b(*)
69
!------------------------------------------------------------------------------
70
71
72
INTEGER :: i,j,k,istat,Subband,N
73
COMPLEX(KIND=dp), ALLOCATABLE :: BA(:,:)
74
75
REAL(KIND=dp), POINTER CONTIG :: Values(:)
76
INTEGER, POINTER CONTIG :: Rows(:), Cols(:), Diag(:)
77
78
SAVE BA
79
!------------------------------------------------------------------------------
80
81
IF ( PRESENT(Free_Fact) ) THEN
82
IF ( Free_Fact ) THEN
83
IF ( ALLOCATED(BA) ) DEALLOCATE(BA)
84
RETURN
85
END IF
86
END IF
87
88
Rows => A % Rows
89
Cols => A % Cols
90
Diag => A % Diag
91
Values => A % Values
92
93
n = A % NumberOfRows
94
x(1:n) = b(1:n)
95
n = n / 2
96
97
IF ( A % Format == MATRIX_CRS .AND. .NOT. A % Symmetric ) THEN
98
Subband = 0
99
DO i=1,N
100
DO j=Rows(2*i-1),Rows(2*i)-1,2
101
Subband = MAX(Subband,ABS((Cols(j)+1)/2-i))
102
END DO
103
END DO
104
105
IF ( .NOT.ALLOCATED( BA ) ) THEN
106
107
ALLOCATE( BA(3*SubBand+1,N),stat=istat )
108
109
IF ( istat /= 0 ) THEN
110
CALL Fatal( 'ComplexBandSolver', 'Memory allocation error.' )
111
END IF
112
113
ELSE IF ( SIZE(BA,1) /= 3*Subband+1 .OR. SIZE(BA,2) /= N ) THEN
114
115
DEALLOCATE( BA )
116
ALLOCATE( BA(3*SubBand+1,N),stat=istat )
117
118
IF ( istat /= 0 ) THEN
119
CALL Fatal( 'ComplexBandSolver', 'Memory allocation error.' )
120
END IF
121
122
END IF
123
124
BA = 0.0D0
125
DO i=1,N
126
DO j=Rows(2*i-1),Rows(2*i)-1,2
127
k = i - (Cols(j)+1)/2 + 2*Subband + 1
128
BA(k,(Cols(j)+1)/2) = CMPLX(Values(j), -Values(j+1), KIND=dp )
129
END DO
130
END DO
131
132
CALL SolveComplexBandLapack( N,1,BA,x,Subband,3*Subband+1 )
133
134
ELSE IF ( A % Format == MATRIX_CRS ) THEN
135
136
Subband = 0
137
DO i=1,N
138
DO j=Rows(2*i-1),Diag(2*i-1)
139
Subband = MAX(Subband,ABS((Cols(j)+1)/2-i))
140
END DO
141
END DO
142
143
IF ( .NOT.ALLOCATED( BA ) ) THEN
144
145
ALLOCATE( BA(SubBand+1,N),stat=istat )
146
147
IF ( istat /= 0 ) THEN
148
CALL Fatal( 'ComplexBandSolver', 'Memory allocation error.' )
149
END IF
150
151
ELSE IF ( SIZE(BA,1) /= Subband+1 .OR. SIZE(BA,2) /= N ) THEN
152
153
DEALLOCATE( BA )
154
ALLOCATE( BA(SubBand+1,N),stat=istat )
155
156
IF ( istat /= 0 ) THEN
157
CALL Fatal( 'ComplexBandSolver', 'Direct solver memory allocation error.' )
158
END IF
159
160
END IF
161
162
BA = 0.0D0
163
DO i=1,N
164
DO j=Rows(2*i-1),Diag(2*i-1)
165
k = i - (Cols(j)+1)/2 + 1
166
BA(k,(Cols(j)+1)/2) = CMPLX(Values(j), -Values(j+1), KIND=dp )
167
END DO
168
END DO
169
170
CALL SolveComplexSBandLapack( N,1,BA,x,Subband,Subband+1 )
171
172
END IF
173
!------------------------------------------------------------------------------
174
END SUBROUTINE ComplexBandSolver
175
!------------------------------------------------------------------------------
176
177
178
!------------------------------------------------------------------------------
179
!> Solver the real linear system using direct band matrix solver from of Lapack.
180
!------------------------------------------------------------------------------
181
SUBROUTINE BandSolver( A,x,b,Free_Fact )
182
!------------------------------------------------------------------------------
183
LOGICAL, OPTIONAL :: Free_Fact
184
TYPE(Matrix_t) :: A
185
REAL(KIND=dp) :: x(*),b(*)
186
!------------------------------------------------------------------------------
187
188
INTEGER :: i,j,k,istat,Subband,N
189
REAL(KIND=dp), ALLOCATABLE :: BA(:,:)
190
191
REAL(KIND=dp), POINTER CONTIG :: Values(:)
192
INTEGER, POINTER CONTIG :: Rows(:), Cols(:), Diag(:)
193
194
SAVE BA
195
!------------------------------------------------------------------------------
196
IF ( PRESENT(Free_Fact) ) THEN
197
IF ( Free_Fact ) THEN
198
IF ( ALLOCATED(BA) ) DEALLOCATE(BA)
199
RETURN
200
END IF
201
END IF
202
203
N = A % NumberOfRows
204
205
x(1:n) = b(1:n)
206
207
Rows => A % Rows
208
Cols => A % Cols
209
Diag => A % Diag
210
Values => A % Values
211
212
IF ( A % Format == MATRIX_CRS ) THEN ! .AND. .NOT. A % Symmetric ) THEN
213
Subband = 0
214
DO i=1,N
215
DO j=Rows(i),Rows(i+1)-1
216
Subband = MAX(Subband,ABS(Cols(j)-i))
217
END DO
218
END DO
219
220
IF ( .NOT.ALLOCATED( BA ) ) THEN
221
222
ALLOCATE( BA(3*SubBand+1,N),stat=istat )
223
224
IF ( istat /= 0 ) THEN
225
CALL Fatal( 'BandSolver', 'Memory allocation error.' )
226
END IF
227
228
ELSE IF ( SIZE(BA,1) /= 3*Subband+1 .OR. SIZE(BA,2) /= N ) THEN
229
230
DEALLOCATE( BA )
231
ALLOCATE( BA(3*SubBand+1,N),stat=istat )
232
233
IF ( istat /= 0 ) THEN
234
CALL Fatal( 'BandSolver', 'Memory allocation error.' )
235
END IF
236
237
END IF
238
239
BA = 0.0D0
240
DO i=1,N
241
DO j=Rows(i),Rows(i+1)-1
242
k = i - Cols(j) + 2*Subband + 1
243
BA(k,Cols(j)) = Values(j)
244
END DO
245
END DO
246
247
CALL SolveBandLapack( N,1,BA,x,Subband,3*Subband+1 )
248
249
ELSE IF ( A % Format == MATRIX_CRS ) THEN
250
251
Subband = 0
252
DO i=1,N
253
DO j=Rows(i),Diag(i)
254
Subband = MAX(Subband,ABS(Cols(j)-i))
255
END DO
256
END DO
257
258
IF ( .NOT.ALLOCATED( BA ) ) THEN
259
260
ALLOCATE( BA(SubBand+1,N),stat=istat )
261
262
IF ( istat /= 0 ) THEN
263
CALL Fatal( 'BandSolver', 'Memory allocation error.' )
264
END IF
265
266
ELSE IF ( SIZE(BA,1) /= Subband+1 .OR. SIZE(BA,2) /= N ) THEN
267
268
DEALLOCATE( BA )
269
ALLOCATE( BA(SubBand+1,N),stat=istat )
270
271
IF ( istat /= 0 ) THEN
272
CALL Fatal( 'BandSolver', 'Memory allocation error.' )
273
END IF
274
275
END IF
276
277
BA = 0.0D0
278
DO i=1,N
279
DO j=Rows(i),Diag(i)
280
k = i - Cols(j) + 1
281
BA(k,Cols(j)) = Values(j)
282
END DO
283
END DO
284
285
CALL SolveSBandLapack( N,1,BA,x,Subband,Subband+1 )
286
287
ELSE IF ( A % Format == MATRIX_BAND ) THEN
288
CALL SolveBandLapack( N,1,Values,x,Subband,3*Subband+1 )
289
ELSE IF ( A % Format == MATRIX_SBAND ) THEN
290
CALL SolveSBandLapack( N,1,Values,x,Subband,Subband+1 )
291
END IF
292
293
!------------------------------------------------------------------------------
294
END SUBROUTINE BandSolver
295
!------------------------------------------------------------------------------
296
297
298
!------------------------------------------------------------------------------
299
!> Solves a linear system using Umfpack multifrontal direct solver courtesy
300
!> of University of Florida.
301
!------------------------------------------------------------------------------
302
SUBROUTINE UMFPack_SolveSystem( Solver,A,x,b,Free_Fact )
303
!------------------------------------------------------------------------------
304
LOGICAL, OPTIONAL :: Free_Fact
305
TYPE(Matrix_t) :: A
306
TYPE(Solver_t) :: Solver
307
REAL(KIND=dp), TARGET :: x(*), b(*)
308
309
REAL(KIND=dp), POINTER CONTIG :: Values(:)
310
INTEGER, POINTER CONTIG :: Rows(:), Cols(:), Diag(:)
311
312
#include "../config.h"
313
#ifdef HAVE_UMFPACK
314
315
#ifdef ARCH_32_BITS
316
#define CAddrInt c_int32_t
317
#else
318
#define CAddrInt c_int64_t
319
#endif
320
! Standard int version
321
INTERFACE
322
SUBROUTINE umf4def( control ) &
323
BIND(C,name='umf4def')
324
USE, INTRINSIC :: ISO_C_BINDING
325
REAL(C_DOUBLE) :: control(*)
326
END SUBROUTINE umf4def
327
328
SUBROUTINE umf4sym( m,n,rows,cols,values,symbolic,control,iinfo ) &
329
BIND(C,name='umf4sym')
330
USE, INTRINSIC :: ISO_C_BINDING
331
INTEGER(C_INT) :: m,n,rows(*),cols(*)
332
INTEGER(CAddrInt) :: symbolic
333
REAL(C_DOUBLE) :: Values(*), control(*),iinfo(*)
334
END SUBROUTINE umf4sym
335
336
SUBROUTINE umf4num( rows,cols,values,symbolic,numeric, control,iinfo ) &
337
BIND(C,name='umf4num')
338
USE, INTRINSIC :: ISO_C_BINDING
339
INTEGER(C_INT) :: rows(*),cols(*)
340
INTEGER(CAddrInt) :: numeric, symbolic
341
REAL(C_DOUBLE) :: Values(*), control(*),iinfo(*)
342
END SUBROUTINE umf4num
343
344
SUBROUTINE umf4sol( sys, x, b, numeric, control, iinfo ) &
345
BIND(C,name='umf4sol')
346
USE, INTRINSIC :: ISO_C_BINDING
347
INTEGER(C_INT) :: sys
348
INTEGER(CAddrInt) :: numeric
349
REAL(C_DOUBLE) :: x(*), b(*), control(*), iinfo(*)
350
END SUBROUTINE umf4sol
351
352
SUBROUTINE umf4fsym(symbolic) &
353
BIND(C,name='umf4fsym')
354
USE, INTRINSIC :: ISO_C_BINDING
355
INTEGER(CAddrInt) :: symbolic
356
END SUBROUTINE umf4fsym
357
358
SUBROUTINE umf4fnum(numeric) &
359
BIND(C,name='umf4fnum')
360
USE, INTRINSIC :: ISO_C_BINDING
361
INTEGER(CAddrInt) :: numeric
362
END SUBROUTINE umf4fnum
363
364
END INTERFACE
365
366
! Long int version
367
INTERFACE
368
SUBROUTINE umf4_l_def( control ) &
369
BIND(C,name='umf4_l_def')
370
USE, INTRINSIC :: ISO_C_BINDING
371
REAL(C_DOUBLE) :: control(*)
372
END SUBROUTINE umf4_l_def
373
374
SUBROUTINE umf4_l_sym( m,n,rows,cols,values,symbolic,control,iinfo ) &
375
BIND(C,name='umf4_l_sym')
376
USE, INTRINSIC :: ISO_C_BINDING
377
!INTEGER(CAddrInt) ::m,n,rows(*),cols(*)
378
INTEGER(UMFPACK_LONG_FORTRAN_TYPE) :: m,n,rows(*),cols(*) !TODO: m,n of are called with AddrInt kind
379
INTEGER(CAddrInt) :: symbolic
380
REAL(C_DOUBLE) :: Values(*), control(*),iinfo(*)
381
END SUBROUTINE umf4_l_sym
382
383
SUBROUTINE umf4_l_num( rows,cols,values,symbolic,numeric, control,iinfo ) &
384
BIND(C,name='umf4_l_num')
385
USE, INTRINSIC :: ISO_C_BINDING
386
!INTEGER(CAddrInt) :: rows(*),cols(*)
387
INTEGER(UMFPACK_LONG_FORTRAN_TYPE) :: rows(*),cols(*)
388
INTEGER(CAddrInt) :: numeric, symbolic
389
REAL(C_DOUBLE) :: Values(*), control(*),iinfo(*)
390
END SUBROUTINE umf4_l_num
391
392
SUBROUTINE umf4_l_sol( sys, x, b, numeric, control, iinfo ) &
393
BIND(C,name='umf4_l_sol')
394
USE, INTRINSIC :: ISO_C_BINDING
395
!INTEGER(CAddrInt) :: sys
396
INTEGER(UMFPACK_LONG_FORTRAN_TYPE) :: sys
397
INTEGER(CAddrInt) :: numeric
398
REAL(C_DOUBLE) :: x(*), b(*), control(*), iinfo(*)
399
END SUBROUTINE umf4_l_sol
400
401
SUBROUTINE umf4_l_fnum(numeric) &
402
BIND(C,name='umf4_l_fnum')
403
USE, INTRINSIC :: ISO_C_BINDING
404
INTEGER(CAddrInt) :: numeric
405
END SUBROUTINE umf4_l_fnum
406
407
SUBROUTINE umf4_l_fsym(symbolic) &
408
BIND(C,name='umf4_l_fsym')
409
USE, INTRINSIC :: ISO_C_BINDING
410
INTEGER(CAddrInt) :: symbolic
411
END SUBROUTINE umf4_l_fsym
412
END INTERFACE
413
414
INTEGER :: i, n, status, sys
415
REAL(KIND=dp) :: iInfo(90), Control(20)
416
INTEGER(KIND=AddrInt) :: symbolic, zero=0
417
INTEGER(KIND=UMFPACK_LONG_FORTRAN_TYPE) :: ln, lsys
418
INTEGER(KIND=UMFPACK_LONG_FORTRAN_TYPE), ALLOCATABLE :: LRows(:), LCols(:)
419
420
SAVE iInfo, Control
421
422
LOGICAL :: Factorize, FreeFactorize, stat, BigMode
423
424
IF ( PRESENT(Free_Fact) ) THEN
425
IF ( Free_Fact ) THEN
426
IF ( A % UMFPack_Numeric/=0 ) THEN
427
CALL umf4fnum(A % UMFPack_Numeric)
428
A % UMFPack_Numeric = 0
429
END IF
430
RETURN
431
END IF
432
END IF
433
434
BigMode = ListGetString( Solver % Values, &
435
'Linear System Direct Method' ) == 'big umfpack'
436
437
Factorize = ListGetLogical( Solver % Values, &
438
'Linear System Refactorize', stat )
439
IF ( .NOT. stat ) Factorize = .TRUE.
440
441
n = A % NumberofRows
442
Rows => A % Rows
443
Cols => A % Cols
444
Diag => A % Diag
445
Values => A % Values
446
447
IF ( Factorize .OR. A% UmfPack_Numeric==0 ) THEN
448
IF ( A % UMFPack_Numeric /= 0 ) THEN
449
IF( BigMode ) THEN
450
CALL umf4_l_fnum( A % UMFPack_Numeric )
451
ELSE
452
CALL umf4fnum( A % UMFPack_Numeric )
453
END IF
454
A % UMFPack_Numeric = 0
455
END IF
456
457
IF ( BigMode ) THEN
458
ALLOCATE( LRows(SIZE(Rows)), LCols(SIZE(Cols)) )
459
460
DO i=1,n+1
461
LRows(i) = Rows(i)-1
462
END DO
463
464
DO i=1,SIZE(Cols)
465
LCols(i) = Cols(i)-1
466
END DO
467
468
ln = n ! TODO: Kludge: ln is AddrInt and n is regular INTEGER
469
CALL umf4_l_def( Control )
470
CALL umf4_l_sym( ln,ln, LRows, LCols, Values, Symbolic, Control, iInfo )
471
ELSE
472
Rows = Rows-1
473
Cols = Cols-1
474
CALL umf4def( Control )
475
CALL umf4sym( n,n, Rows, Cols, Values, Symbolic, Control, iInfo )
476
END IF
477
478
IF (iInfo(1)<0) THEN
479
PRINT *, 'Error occurred in umf4sym: ', iInfo(1)
480
STOP EXIT_ERROR
481
END IF
482
483
IF ( BigMode ) THEN
484
CALL umf4_l_num(LRows, LCols, Values, Symbolic, A % UMFPack_Numeric, Control, iInfo )
485
ELSE
486
CALL umf4num( Rows, Cols, Values, Symbolic, A % UMFPack_Numeric, Control, iInfo )
487
END IF
488
489
IF (iinfo(1)<0) THEN
490
PRINT*, 'Error occurred in umf4num: ', iinfo(1)
491
STOP EXIT_ERROR
492
ENDIF
493
494
IF ( BigMode ) THEN
495
DEALLOCATE( LRows, LCols )
496
CALL umf4_l_fsym( Symbolic )
497
ELSE
498
A % Rows = A % Rows+1
499
A % Cols = A % Cols+1
500
CALL umf4fsym( Symbolic )
501
END IF
502
END IF
503
504
IF ( BigMode ) THEN
505
lsys = 2
506
CALL umf4_l_sol( lsys, x, b, A % UMFPack_Numeric, Control, iInfo )
507
ELSE
508
sys = 2
509
CALL umf4sol( sys, x, b, A % UMFPack_Numeric, Control, iInfo )
510
END IF
511
512
IF (iinfo(1)<0) THEN
513
PRINT*, 'Error occurred in umf4sol: ', iinfo(1)
514
STOP EXIT_ERROR
515
END IF
516
517
FreeFactorize = ListGetLogical( Solver % Values, &
518
'Linear System Free Factorization', stat )
519
IF ( .NOT. stat ) FreeFactorize = .TRUE.
520
521
IF ( Factorize .AND. FreeFactorize ) THEN
522
IF ( BigMode ) THEN
523
CALL umf4_l_fnum(A % UMFPack_Numeric)
524
ELSE
525
CALL umf4fnum(A % UMFPack_Numeric)
526
END IF
527
A % UMFPack_Numeric = 0
528
END IF
529
#else
530
CALL Fatal( 'UMFPack_SolveSystem', 'UMFPACK Solver has not been installed.' )
531
#endif
532
!------------------------------------------------------------------------------
533
END SUBROUTINE UMFPack_SolveSystem
534
!------------------------------------------------------------------------------
535
536
537
!------------------------------------------------------------------------------
538
!> Solves a linear system using Cholmod multifrontal direct solver courtesy
539
!> of University of Florida.
540
!------------------------------------------------------------------------------
541
SUBROUTINE Cholmod_SolveSystem( Solver,A,x,b,Free_fact)
542
!------------------------------------------------------------------------------
543
LOGICAL, OPTIONAL :: Free_Fact
544
TYPE(Matrix_t) :: A
545
TYPE(Solver_t) :: Solver
546
REAL(KIND=dp) :: x(*), b(*)
547
548
INTERFACE
549
SUBROUTINE cholmod_ffree(chol) BIND(c,NAME="cholmod_ffree")
550
USE Types
551
INTEGER(KIND=AddrInt) :: chol
552
END SUBROUTINE cholmod_ffree
553
554
FUNCTION cholmod_ffactorize(n,rows,cols,vals,cmplx) RESULT(chol) BIND(c,NAME="cholmod_ffactorize")
555
USE Types
556
INTEGER :: n, cmplx, Rows(*), Cols(*)
557
REAL(KIND=dp) :: Vals(*)
558
INTEGER(KIND=dp) :: chol
559
END FUNCTION cholmod_ffactorize
560
561
SUBROUTINE cholmod_fsolve(chol, n, x,b) BIND(c,NAME="cholmod_fsolve")
562
USE Types
563
REAL(KIND=dp) :: x(*), b(*)
564
INTEGER :: n
565
INTEGER(KIND=dp) :: chol
566
END SUBROUTINE cholmod_fsolve
567
END INTERFACE
568
569
LOGICAL :: Factorize, FreeFactorize, Found
570
INTEGER :: i
571
REAL(KIND=dp), POINTER CONTIG :: Vals(:)
572
INTEGER, POINTER CONTIG :: Rows(:), Cols(:), Diag(:)
573
574
#ifdef HAVE_CHOLMOD
575
IF ( PRESENT(Free_Fact) ) THEN
576
IF ( Free_Fact ) THEN
577
IF ( A % Cholmod/=0 ) THEN
578
CALL cholmod_ffree(A % cholmod)
579
A % cholmod = 0
580
END IF
581
RETURN
582
END IF
583
END IF
584
585
Factorize = ListGetLogical( Solver % Values, &
586
'Linear System Refactorize', Found )
587
IF ( .NOT. Found ) Factorize = .TRUE.
588
589
IF ( Factorize .OR. A% cholmod==0 ) THEN
590
IF ( A % cholmod/=0 ) THEN
591
CALL cholmod_ffree(A % cholmod)
592
A % cholmod = 0
593
END IF
594
595
Rows => A % Rows
596
Cols => A % Cols
597
Vals => A % Values
598
599
Rows=Rows-1; Cols=Cols-1 ! c numbering
600
i=0
601
IF(A % Complex) i=1
602
A % Cholmod=cholmod_ffactorize(A % NumberOfRows, Rows, Cols, Vals, i)
603
Rows=Rows+1; Cols=Cols+1 ! fortran numbering
604
END IF
605
606
CALL cholmod_fsolve(A % cholmod, A % NumberOfRows, x, b);
607
608
FreeFactorize = ListGetLogical( Solver % Values, &
609
'Linear System Free Factorization', Found )
610
IF ( .NOT. Found ) FreeFactorize = .TRUE.
611
612
IF ( Factorize .AND. FreeFactorize ) THEN
613
CALL cholmod_ffree(A % cholmod)
614
A % cholmod = 0
615
END IF
616
#else
617
CALL Fatal( 'Cholmod_SolveSystem', 'Cholmod Solver has not been installed.' )
618
#endif
619
!------------------------------------------------------------------------------
620
END SUBROUTINE Cholmod_SolveSystem
621
!------------------------------------------------------------------------------
622
623
624
!------------------------------------------------------------------------------
625
!> Solves a linear system using SuiteSparseQR multifrontal direct solver courtesy
626
!> of University of Florida.
627
!------------------------------------------------------------------------------
628
SUBROUTINE SPQR_SolveSystem( Solver,A,x,b,Free_fact)
629
!------------------------------------------------------------------------------
630
LOGICAL, OPTIONAL :: Free_Fact
631
TYPE(Matrix_t) :: A
632
TYPE(Solver_t) :: Solver
633
REAL(KIND=dp) :: x(*), b(*)
634
635
INTEGER :: i
636
LOGICAL :: Factorize, FreeFactorize, Found
637
638
REAL(KIND=dp), POINTER CONTIG :: Vals(:)
639
INTEGER, POINTER CONTIG :: Rows(:), Cols(:), Diag(:)
640
641
INTERFACE
642
FUNCTION spqr_ffree(chol) RESULT(stat) BIND(c,NAME="spqr_ffree")
643
USE Types
644
INTEGER :: stat
645
INTEGER(KIND=AddrInt) :: chol
646
END FUNCTION spqr_ffree
647
648
FUNCTION spqr_ffactorize(n,rows,cols,vals) RESULT(chol) BIND(c,NAME="spqr_ffactorize")
649
USE Types
650
INTEGER :: n, rows(*), cols(*)
651
REAL(KIND=dp) :: vals(*)
652
INTEGER(KIND=AddrInt) :: chol
653
END FUNCTION spqr_ffactorize
654
655
SUBROUTINE spqr_fsolve(chol, n, x,b) BIND(c,NAME="spqr_fsolve")
656
USE Types
657
REAL(KIND=dp) :: x(*), b(*)
658
INTEGER :: n
659
INTEGER(KIND=AddrInt) :: chol
660
END SUBROUTINE spqr_fsolve
661
END INTERFACE
662
663
#ifdef HAVE_CHOLMOD
664
IF ( PRESENT(Free_Fact) ) THEN
665
IF ( Free_Fact ) THEN
666
IF ( A % Cholmod/=0 ) THEN
667
IF(spqr_ffree(A % cholmod)==0) A % Cholmod=0
668
END IF
669
RETURN
670
END IF
671
END IF
672
673
Factorize = ListGetLogical( Solver % Values, &
674
'Linear System Refactorize', Found )
675
IF ( .NOT. Found ) Factorize = .TRUE.
676
677
IF ( Factorize .OR. A% cholmod==0 ) THEN
678
IF ( A % cholmod/=0 ) THEN
679
i=spqr_ffree(A % cholmod)
680
A % cholmod = 0
681
END IF
682
683
Rows => A % Rows
684
Cols => A % Cols
685
Vals => A % Values
686
687
Rows=Rows-1; Cols=Cols-1 ! c numbering
688
A % Cholmod=spqr_ffactorize(A % NumberOfRows, Rows, Cols, Vals)
689
Rows=Rows+1; Cols=Cols+1 ! fortran numbering
690
END IF
691
692
CALL spqr_fsolve(A % cholmod, A % NumberOfRows, x, b);
693
694
FreeFactorize = ListGetLogical( Solver % Values, &
695
'Linear System Free Factorization', Found )
696
IF ( .NOT. Found ) FreeFactorize = .TRUE.
697
698
IF ( Factorize .AND. FreeFactorize ) THEN
699
i=spqr_ffree(A % cholmod)
700
A % cholmod = 0
701
END IF
702
#else
703
CALL Fatal( 'SPQR_SolveSystem', 'SPQR Solver has not been installed.' )
704
#endif
705
!------------------------------------------------------------------------------
706
END SUBROUTINE SPQR_SolveSystem
707
!------------------------------------------------------------------------------
708
709
710
!------------------------------------------------------------------------------
711
!> Solves a linear system using MUMPS direct solver. This is a legacy solver
712
!> with complicated dependencies. This is only available in parallel.
713
!------------------------------------------------------------------------------
714
SUBROUTINE Mumps_SolveSystem( Solver,A,x,b,Free_Fact )
715
!------------------------------------------------------------------------------
716
#ifdef HAVE_MUMPS
717
# if defined(ELMER_HAVE_MPI_MODULE)
718
USE mpi
719
# endif
720
#endif
721
722
LOGICAL, OPTIONAL :: Free_Fact
723
TYPE(Matrix_t) :: A
724
TYPE(Solver_t) :: Solver
725
REAL(KIND=dp), TARGET :: x(*), b(*)
726
727
#ifdef HAVE_MUMPS
728
# if defined(ELMER_HAVE_MPIF_HEADER)
729
INCLUDE 'mpif.h'
730
# endif
731
732
INTEGER, ALLOCATABLE :: Owner(:)
733
INTEGER :: i,j,n,ip,ierr,icntlft,nzloc
734
LOGICAL :: Factorize, FreeFactorize, stat, matsym, matspd, scaled
735
736
INTEGER, ALLOCATABLE :: memb(:)
737
INTEGER :: Comm_active, Group_active, Group_world
738
739
REAL(KIND=dp), ALLOCATABLE :: dbuf(:)
740
741
742
IF ( PRESENT(Free_Fact) ) THEN
743
IF ( Free_Fact ) THEN
744
IF ( ASSOCIATED(A % MumpsID) ) THEN
745
DEALLOCATE( A % MumpsID % irn_loc, &
746
A % MumpsID % jcn_loc, A % MumpsID % rhs, &
747
A % MumpsID % isol_loc, A % MumpsID % sol_loc, A % Gorder)
748
A % Gorder=>Null()
749
750
A % MumpsID % job = -2
751
CALL DMumps(A % MumpsID)
752
DEALLOCATE(A % MumpsID)
753
END IF
754
RETURN
755
END IF
756
END IF
757
758
Factorize = ListGetLogical( Solver % Values, &
759
'Linear System Refactorize', stat )
760
IF ( .NOT. stat ) Factorize = .TRUE.
761
762
IF ( Factorize .OR. .NOT.ASSOCIATED(A % MumpsID) ) THEN
763
IF ( ASSOCIATED(A % MumpsID) ) THEN
764
DEALLOCATE( A % MumpsID % irn_loc, &
765
A % MumpsID % jcn_loc, A % MumpsID % Rhs, &
766
A % MumpsID % isol_loc, A % MumpsID % sol_loc, A % Gorder)
767
A % MumpsID % job = -2
768
CALL DMumps(A % MumpsID)
769
DEALLOCATE(A % MumpsID)
770
END IF
771
772
ALLOCATE(A % MumpsID)
773
774
A % MumpsID % Comm = A % Comm
775
A % MumpsID % par = 1
776
A % MumpsID % job = -1
777
A % MumpsID % Keep = 0
778
779
matsym = ListGetLogical( Solver % Values, 'Linear System Symmetric', stat)
780
matspd = ListGetLogical( Solver % Values, 'Linear System Positive Definite', stat)
781
782
! force unsymmetric mode when "row equilibration" is used
783
scaled = ListGetLogical( Solver % Values, 'Linear System Scaling', stat)
784
IF(.NOT.stat) scaled = .TRUE.
785
IF(scaled) THEN
786
IF(ListGetLogical( Solver % Values, 'Linear System Row Equilibration',stat)) matsym=.FALSE.
787
END IF
788
789
IF(matsym) THEN
790
IF ( matspd) THEN
791
A % MumpsID % sym = 1
792
ELSE
793
A % MumpsID % sym = 0 ! 2=symmetric, but unsymmetric solver seems faster, at least in a few
794
! simple cases... more testing needed...
795
END IF
796
ELSE
797
A % MumpsID % sym = 0
798
END IF
799
800
CALL DMumps(A % MumpsID)
801
802
IF(ASSOCIATED(A % Gorder)) DEALLOCATE(A % Gorder)
803
804
IF(ASSOCIATED(A % ParallelInfo)) THEN
805
n = SIZE(A % ParallelInfo % GlobalDOFs)
806
807
ALLOCATE( A % Gorder(n), Owner(n) )
808
CALL ContinuousNumbering( A % ParallelInfo, &
809
A % Perm, A % Gorder, Owner )
810
811
CALL MPI_ALLREDUCE( SUM(Owner), A % MumpsID % n, &
812
1, MPI_INTEGER, MPI_SUM, A % MumpsID % Comm, ierr )
813
DEALLOCATE(Owner)
814
ELSE
815
CALL MPI_ALLREDUCE( A % NumberOfRows, A % MumpsId % n, &
816
1, MPI_INTEGER, MPI_MAX, A % Comm, ierr )
817
818
ALLOCATE(A % Gorder(A % NumberOFrows))
819
DO i=1,A % NumberOFRows
820
A % Gorder(i) = i
821
END DO
822
END IF
823
824
! Set matrix for Mumps (unsymmetric case)
825
IF (A % mumpsID % sym == 0) THEN
826
A % MumpsID % nz_loc = A % Rows(A % NumberOfRows+1)-1
827
828
ALLOCATE( A % MumpsID % irn_loc(A % MumpsID % nz_loc) )
829
DO i=1,A % NumberOfRows
830
ip = A % Gorder(i)
831
DO j=A % Rows(i),A % Rows(i+1)-1
832
A % MumpsID % irn_loc(j) = ip
833
END DO
834
END DO
835
836
ALLOCATE( A % MumpsID % jcn_loc(A % MumpsId % nz_loc) )
837
DO i=1,A % MumpsID % nz_loc
838
A % MumpsID % jcn_loc(i) = A % Gorder(A % Cols(i))
839
END DO
840
A % MumpsID % a_loc => A % values
841
ELSE
842
! Set matrix for Mumps (symmetric case)
843
nzloc = 0
844
DO i=1,A % NumberOfRows
845
! Only output lower triangular part to Mumps
846
DO j=A % Rows(i),A % Diag(i)
847
nzloc = nzloc + 1
848
END DO
849
END DO
850
851
A % MumpsID % nz_loc = nzloc
852
853
ALLOCATE( A % MumpsID % irn_loc(A % MumpsID % nz_loc) )
854
ALLOCATE( A % MumpsID % jcn_loc(A % MumpsId % nz_loc) )
855
ALLOCATE( A % MumpsID % A_loc(A % MumpsId % nz_loc) )
856
857
nzloc = 0
858
DO i=1,A % NumberOfRows
859
! Only output lower triangular part to Mumps
860
DO j=A % Rows(i),A % Diag(i)
861
nzloc = nzloc + 1
862
A % mumpsID % IRN_loc(nzloc) = A % Gorder(i)
863
A % mumpsID % A_loc(nzloc) = A % Values(j)
864
A % mumpsID % JCN_loc(nzloc) = A % Gorder(A % Cols(j))
865
END DO
866
END DO
867
END IF
868
869
870
ALLOCATE(A % MumpsID % rhs(A % MumpsId % n))
871
872
A % MumpsID % icntl(2) = 0 ! suppress printing of diagnostics and warnings
873
A % MumpsID % icntl(3) = 0 ! suppress statistics
874
A % MumpsID % icntl(4) = 1 ! the same as the two above, but doesn't seem to work.
875
A % MumpsID % icntl(5) = 0 ! matrix format 'assembled'
876
877
icntlft = ListGetInteger(Solver % Values, &
878
'mumps percentage increase working space', stat)
879
IF (stat) THEN
880
A % MumpsID % icntl(14) = icntlft
881
END IF
882
A % MumpsID % icntl(18) = 3 ! 'distributed' matrix
883
A % MumpsID % icntl(21) = 1 ! 'distributed' solution phase
884
885
A % MumpsID % job = 4
886
CALL DMumps(A % MumpsID)
887
CALL Flush(6)
888
889
A % MumpsID % lsol_loc = A % mumpsid % info(23)
890
ALLOCATE(A % MumpsID % sol_loc(A % MumpsId % lsol_loc))
891
ALLOCATE(A % MumpsID % isol_loc(A % MumpsId % lsol_loc))
892
END IF
893
894
! sum the rhs from all procs. Could be done
895
! for neighbours only (i guess):
896
! ------------------------------------------
897
A % MumpsID % RHS = 0
898
DO i=1,A % NumberOfRows
899
ip = A % Gorder(i)
900
A % MumpsId % RHS(ip) = b(i)
901
END DO
902
ALLOCATE( dbuf(A % MumpsID % n) )
903
dbuf = A % MumpsId % RHS
904
CALL MPI_ALLREDUCE( dbuf, A % MumpsID % RHS, &
905
A % MumpsID % n, MPI_DOUBLE_PRECISION, MPI_SUM, A % MumpsID % Comm, ierr )
906
907
! Solution:
908
! ---------
909
A % MumpsID % job = 3
910
CALL DMumps(A % MumpsID)
911
912
! Distribute the solution to all:
913
! -------------------------------
914
A % MumpsId % Rhs = 0
915
DO i=1,A % MumpsID % lsol_loc
916
A % MumpsID % RHS(A % MumpsID % isol_loc(i)) = &
917
A % MumpsID % sol_loc(i)
918
END DO
919
dbuf = A % MumpsId % RHS
920
CALL MPI_ALLREDUCE( dbuf, A % MumpsID % RHS, &
921
A % MumpsID % N, MPI_DOUBLE_PRECISION, MPI_SUM,A % MumpsID % Comm, ierr )
922
923
DEALLOCATE(dbuf)
924
925
! Select the values which belong to us:
926
! -------------------------------------
927
DO i=1,A % NumberOfRows
928
ip = A % Gorder(i)
929
x(i) = A % MumpsId % RHS(ip)
930
END DO
931
932
FreeFactorize = ListGetLogical( Solver % Values, &
933
'Linear System Free Factorization', stat )
934
IF ( .NOT. stat ) FreeFactorize = .TRUE.
935
936
IF ( Factorize .AND. FreeFactorize ) THEN
937
DEALLOCATE( A % MumpsID % irn_loc, &
938
A % MumpsID % jcn_loc, A % MumpsID % Rhs, &
939
A % MumpsID % isol_loc, A % MumpsID % sol_loc, A % Gorder)
940
941
IF ( A % MumpsID % Sym/=0 ) DEALLOCATE( A % MumpsID % A_loc )
942
943
A % Gorder=>Null()
944
945
A % MumpsID % job = -2
946
CALL DMumps(A % MumpsID)
947
DEALLOCATE(A % MumpsID)
948
A % MumpsId => NULL()
949
END IF
950
951
#else
952
CALL Fatal( 'Mumps_SolveSystem', 'MUMPS Solver has not been installed.' )
953
#endif
954
!------------------------------------------------------------------------------
955
END SUBROUTINE Mumps_SolveSystem
956
!------------------------------------------------------------------------------
957
958
959
!------------------------------------------------------------------------------
960
!> Solves local linear system using MUMPS direct solver. If the solved system
961
!> is singular, optionally one possible solution is returned.
962
!------------------------------------------------------------------------------
963
SUBROUTINE MumpsLocal_SolveSystem( Solver, A, x, b, Free_Fact )
964
!------------------------------------------------------------------------------
965
IMPLICIT NONE
966
967
TYPE(Matrix_t) :: A
968
TYPE(Solver_t) :: Solver
969
REAL(KIND=dp), TARGET :: x(*), b(*)
970
LOGICAL, OPTIONAL :: Free_Fact
971
972
INTEGER :: i
973
LOGICAL :: Factorize, FreeFactorize, stat
974
975
#ifdef HAVE_MUMPS
976
! Free local Mumps instance if requested
977
IF (PRESENT(Free_Fact)) THEN
978
IF (Free_Fact) THEN
979
CALL MumpsLocal_Free(A)
980
RETURN
981
END IF
982
END IF
983
984
! Refactorize local matrix if needed
985
Factorize = ListGetLogical( Solver % Values, &
986
'Linear System Refactorize', stat )
987
IF (.NOT. stat) Factorize = .TRUE.
988
989
IF (Factorize .OR. .NOT. ASSOCIATED(A % mumpsIDL)) THEN
990
CALL MumpsLocal_Factorize(Solver, A)
991
END IF
992
993
! Set RHS
994
A % mumpsIDL % NRHS = 1
995
A % mumpsIDL % LRHS = A % mumpsIDL % n
996
DO i=1,A % NumberOfRows
997
A % mumpsIDL % RHS(i) = b(i)
998
END DO
999
! We could use BLAS here..
1000
! CALL DCOPY(A % NumberOfRows, b, 1, A % mumpsIDL % RHS, 1)
1001
1002
! SOLUTION PHASE
1003
A % mumpsIDL % job = 3
1004
CALL DMumps(A % mumpsIDL)
1005
1006
! TODO: If solution is not local, redistribute the solution vector here
1007
1008
! Set local solution
1009
DO i=1,A % NumberOfRows
1010
x(i)=A % mumpsIDL % RHS(i)
1011
END DO
1012
! We could use BLAS here..
1013
! CALL DCOPY(A % NumberOfRows, A % mumpsIDL % RHS, 1, x, 1)
1014
1015
FreeFactorize = ListGetLogical( Solver % Values, &
1016
'Linear System Free Factorization', stat )
1017
IF (.NOT. stat) FreeFactorize = .TRUE.
1018
1019
IF (Factorize .AND. FreeFactorize) CALL MumpsLocal_Free(A)
1020
#else
1021
CALL Fatal( 'MumpsLocal_SolveSystem', 'MUMPS Solver has not been installed.' )
1022
#endif
1023
!------------------------------------------------------------------------------
1024
END SUBROUTINE MumpsLocal_SolveSystem
1025
!------------------------------------------------------------------------------
1026
1027
!------------------------------------------------------------------------------
1028
!> Factorize local matrix with Mumps
1029
!------------------------------------------------------------------------------
1030
SUBROUTINE MumpsLocal_Factorize(Solver, A)
1031
!------------------------------------------------------------------------------
1032
#ifdef HAVE_MUMPS
1033
# if defined(ELMER_HAVE_MPI_MODULE)
1034
USE mpi
1035
# endif
1036
#endif
1037
IMPLICIT NONE
1038
1039
TYPE(Solver_t) :: Solver
1040
TYPE(Matrix_t) :: A
1041
1042
#ifdef HAVE_MUMPS
1043
# if defined(ELMER_HAVE_MPIF_HEADER)
1044
INCLUDE 'mpif.h'
1045
# endif
1046
1047
INTEGER :: i, j, n, nz, allocstat, icntlft, ptype, nzloc
1048
LOGICAL :: matpd, matsym, nullpiv, stat
1049
1050
! INTEGER :: myrank, ierr
1051
! CHARACTER(len=32) :: buf
1052
1053
IF ( ASSOCIATED(A % mumpsIDL) ) THEN
1054
CALL MumpsLocal_Free(A)
1055
END IF
1056
1057
ALLOCATE(A % mumpsIDL)
1058
1059
! INITIALIZATION PHASE
1060
1061
! Initialize local instance of Mumps
1062
! TODO (Hybridization): change this if local system needs to be solved
1063
! with several cores
1064
A % mumpsIDL % COMM = MPI_COMM_SELF
1065
A % mumpsIDL % PAR = 1 ! Host (=self) takes part in factorization
1066
1067
! Check if matrix is symmetric or spd
1068
matsym = ListGetLogical(Solver % Values, &
1069
'Linear System Symmetric', stat)
1070
matpd = ListGetLogical(Solver % Values, &
1071
'Linear System Positive Definite', stat)
1072
1073
A % mumpsIDL % SYM = 0
1074
IF (matsym) THEN
1075
IF (matpd) THEN
1076
! Matrix is symmetric positive definite
1077
A % mumpsIDL % SYM = 1
1078
ELSE
1079
! Matrix is symmetric
1080
A % mumpsIDL % SYM = 2
1081
END IF
1082
ELSE
1083
! Matrix is unsymmetric
1084
A % mumpsIDL % SYM = 0
1085
END IF
1086
A % mumpsIDL % JOB = -1 ! Initialize
1087
CALL DMumps(A % mumpsIDL)
1088
1089
! FACTORIZE PHASE
1090
1091
! Set stdio parameters
1092
A % mumpsIDL % ICNTL(1) = 6 ! Error messages to stdout
1093
A % mumpsIDL % ICNTL(2) = -1 ! No diagnostic and warning messages
1094
A % mumpsIDL % ICNTL(3) = -1 ! No statistic messages
1095
A % mumpsIDL % ICNTL(4) = 1 ! Print only error messages
1096
1097
! Set matrix format
1098
A % mumpsIDL % ICNTL(5) = 0 ! Assembled matrix format
1099
A % mumpsIDL % ICNTL(18) = 0 ! Centralized matrix
1100
A % mumpsIDL % ICNTL(21) = 0 ! Centralized dense solution phase
1101
1102
! Check if solution of singular systems is ok
1103
A % mumpsIDL % ICNTL(24) = 0
1104
nullpiv = ListGetLogical(Solver % Values, &
1105
'Mumps Solve Singular', stat)
1106
IF (nullpiv) THEN
1107
A % mumpsIDL % ICNTL(24) = 1
1108
A % mumpsIDL % CNTL(1) = 1D-2 ! Pivoting threshold
1109
A % mumpsIDL % CNTL(3) = 1D-9 ! Null pivot detection threshold
1110
A % mumpsIDL % CNTL(5) = 1D6 ! Fixation value for null pivots
1111
A % mumpsIDL % CNTL(13) = 1 ! Do not use ScaLAPACK on the root node
1112
! TODO: if needed, here set CNTL(3) and CNTL(5) as parameters for
1113
! more accurate null pivot detection
1114
END IF
1115
1116
! Set permutation strategy for Mumps
1117
ptype = ListGetInteger(Solver % Values, &
1118
'Mumps Permutation Type', stat)
1119
IF (stat) THEN
1120
A % mumpsIDL % ICNTL(6) = ptype
1121
END IF
1122
1123
! TODO: Change this if system is larger than local.
1124
! For larger than local systems define global->local numbering
1125
n = A % NumberofRows
1126
nz = A % Rows(A % NumberOfRows+1)-1
1127
A % mumpsIDL % N = n
1128
A % mumpsIDL % NZ = nz
1129
! A % mumpsIDL % nz_loc = nz
1130
1131
! Allocate rows and columns for MUMPS
1132
ALLOCATE( A % mumpsIDL % IRN(nz), &
1133
A % mumpsIDL % JCN(nz), &
1134
A % mumpsIDL % A(nz), STAT=allocstat)
1135
IF (allocstat /= 0) THEN
1136
CALL Fatal('MumpsLocal_Factorize', &
1137
'Memory allocation for MUMPS row and column indices failed.')
1138
END IF
1139
1140
! Set matrix for Mumps (unsymmetric case)
1141
IF (A % mumpsIDL % sym == 0) THEN
1142
DO i=1,A % NumberOfRows
1143
DO j=A % Rows(i),A % Rows(i+1)-1
1144
A % mumpsIDL % IRN(j) = i
1145
END DO
1146
END DO
1147
1148
! Set columns and values
1149
DO i=1,A % mumpsIDL % nz
1150
A % mumpsIDL % JCN(i) = A % Cols(i)
1151
END DO
1152
DO i=1,A % mumpsIDL % nz
1153
A % mumpsIDL % A(i) = A % Values(i)
1154
END DO
1155
ELSE
1156
! Set matrix for Mumps (symmetric case)
1157
nzloc = 0
1158
DO i=1,A % NumberOfRows
1159
DO j=A % Rows(i),A % Rows(i+1)-1
1160
! Only output lower triangular part to Mumps
1161
IF (i<=A % Cols(j)) THEN
1162
nzloc = nzloc + 1
1163
A % mumpsIDL % IRN(nzloc) = i
1164
A % mumpsIDL % JCN(nzloc) = A % Cols(j)
1165
A % mumpsIDL % A(nzloc) = A % Values(j)
1166
END IF
1167
END DO
1168
END DO
1169
END IF
1170
1171
icntlft = ListGetInteger(Solver % Values, 'mumps percentage increase working space', stat)
1172
IF (stat) THEN
1173
A % mumpsIDL % ICNTL(14) = icntlft
1174
END IF
1175
1176
A % mumpsIDL % JOB = 1 ! Perform analysis
1177
CALL DMumps(A % mumpsIDL)
1178
CALL Flush(6)
1179
1180
! Check return status
1181
IF (A % mumpsIDL % INFO(1)<0) THEN
1182
CALL Fatal('MumpsLocal_Factorize','Mumps analysis phase failed')
1183
END IF
1184
1185
A % mumpsIDL % JOB = 2 ! Perform factorization
1186
CALL DMumps(A % mumpsIDL)
1187
CALL Flush(6)
1188
1189
! Check return status
1190
IF (A % mumpsIDL % INFO(1)<0) THEN
1191
CALL Fatal('MumpsLocal_Factorize','Mumps factorize phase failed')
1192
END IF
1193
1194
! Allocate RHS
1195
ALLOCATE(A % mumpsIDL % RHS(A % mumpsIDL % N), STAT=allocstat)
1196
IF (allocstat /= 0) THEN
1197
CALL Fatal('MumpsLocal_Factorize', &
1198
'Memory allocation for MUMPS solution vector and RHS failed.' )
1199
END IF
1200
#else
1201
CALL Fatal( 'MumpsLocal_Factorize', 'MUMPS Solver has not been installed.' )
1202
#endif
1203
!------------------------------------------------------------------------------
1204
END SUBROUTINE MumpsLocal_Factorize
1205
!------------------------------------------------------------------------------
1206
1207
!------------------------------------------------------------------------------
1208
!> Solve local nullspace using MUMPS direct solver. On exit, z will be
1209
!> allocated and will hold the jth local nullspace vectors as z(j,:).
1210
!------------------------------------------------------------------------------
1211
SUBROUTINE MumpsLocal_SolveNullSpace(Solver, A, z, nz)
1212
!------------------------------------------------------------------------------
1213
#ifdef HAVE_MUMPS
1214
# if defined(ELMER_HAVE_MPI_MODULE)
1215
USE mpi
1216
# endif
1217
#endif
1218
IMPLICIT NONE
1219
1220
TYPE(Solver_t) :: Solver
1221
TYPE(Matrix_t) :: A
1222
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:,:), TARGET :: z
1223
INTEGER :: nz, nrhs
1224
1225
#ifdef HAVE_MUMPS
1226
# if defined(ELMER_HAVE_MPIF_HEADER)
1227
INCLUDE 'mpif.h'
1228
# endif
1229
1230
INTEGER :: j,k,n, allocstat
1231
LOGICAL :: Factorize, FreeFactorize, stat
1232
1233
REAL(KIND=dp), DIMENSION(:), POINTER :: rhs_tmp, nspace
1234
1235
Factorize = ListGetLogical( Solver % Values,&
1236
'Linear System Refactorize', stat )
1237
IF (.NOT. stat) Factorize = .TRUE.
1238
1239
! Refactorize local matrix if needed
1240
IF ( Factorize .OR. (.NOT. ASSOCIATED(A % mumpsIDL)) ) THEN
1241
CALL MumpsLocal_Factorize(Solver, A)
1242
END IF
1243
1244
! Check symmetry condition
1245
IF (.NOT. (A % mumpsIDL % sym == 1 .OR. A % mumpsIDL % sym == 2)) THEN
1246
CALL Fatal( 'MumpsLocal_SolveNullSpace', &
1247
'Mumps null space computation not supported for unsymmetric matrices.')
1248
END IF
1249
1250
! Get the size of the local nullspace and allocate memory
1251
! TODO: this is incorrect, should be number of columns
1252
n = A % NumberOfRows
1253
nz = A % mumpsIDL % INFOG(28)
1254
1255
IF (nz == 0) THEN
1256
ALLOCATE(z(nz,n))
1257
RETURN
1258
END IF
1259
1260
ALLOCATE(nspace(n*nz), STAT=allocstat)
1261
IF (allocstat /= 0) THEN
1262
CALL Fatal( 'MumpsLocal_SolveNullSpace', &
1263
'Storage allocation for local nullspace failed.')
1264
END IF
1265
1266
rhs_tmp => A % mumpsIDL % RHS
1267
nrhs = A % mumpsIDL % NRHS
1268
A % mumpsIDL % RHS => nspace
1269
A % mumpsIDL % NRHS = nz
1270
1271
! Solve for the complete local nullspace
1272
A % mumpsIDL % JOB = 3
1273
A % mumpsIDL % ICNTL(25) = -1
1274
CALL DMumps(A % mumpsIDL)
1275
! Check return status
1276
IF (A % mumpsIDL % INFO(1)<0) THEN
1277
CALL Fatal('MumpsLocal_SolveNullSpace','Mumps nullspace solution failed')
1278
END IF
1279
1280
! Restore pointer to local solution vector
1281
A % mumpsIDL % ICNTL(25) = 0
1282
A % mumpsIDL % RHS => rhs_tmp
1283
A % mumpsIDL % NRHS = nrhs
1284
1285
FreeFactorize = ListGetLogical( Solver % Values, &
1286
'Linear System Free Factorization', stat )
1287
IF (.NOT. stat) FreeFactorize = .TRUE.
1288
1289
IF (Factorize .AND. FreeFactorize) THEN
1290
CALL MumpsLocal_Free(A)
1291
END IF
1292
1293
ALLOCATE(z(nz,n), STAT=allocstat)
1294
IF (allocstat /= 0) THEN
1295
CALL Fatal( 'MumpsLocal_SolveNullSpace', &
1296
'Storage allocation for local nullspace failed.')
1297
END IF
1298
1299
! Copy computed nullspace to z and deallocate nspace
1300
DO j=1,nz
1301
! z is row major, cannot use DCOPY here
1302
DO k=1,n
1303
z(j,k)=nspace(n*(j-1)+k)
1304
END DO
1305
END DO
1306
DEALLOCATE(nspace)
1307
#else
1308
CALL Fatal( 'MumpsLocal_SolveNullSpace', 'MUMPS Solver has not been installed.' )
1309
#endif
1310
!------------------------------------------------------------------------------
1311
END SUBROUTINE MumpsLocal_SolveNullSpace
1312
!------------------------------------------------------------------------------
1313
1314
!------------------------------------------------------------------------------
1315
!> Free local Mumps variables and solver internal allocations
1316
!------------------------------------------------------------------------------
1317
SUBROUTINE MumpsLocal_Free(A)
1318
!------------------------------------------------------------------------------
1319
IMPLICIT NONE
1320
1321
TYPE(Matrix_t) :: A
1322
1323
#ifdef HAVE_MUMPS
1324
IF (ASSOCIATED(A % mumpsIDL)) THEN
1325
! Deallocate Mumps structures
1326
DEALLOCATE( A % mumpsIDL % irn, A % mumpsIDL % jcn, &
1327
A % mumpsIDL % a, A % mumpsIDL % rhs)
1328
1329
! Free Mumps internal allocations
1330
A % mumpsIDL % job = -2
1331
CALL DMumps(A % mumpsIDL)
1332
DEALLOCATE(A % mumpsIDL)
1333
1334
A % mumpsIDL => Null()
1335
END IF
1336
#else
1337
CALL Fatal( 'MumpsLocal_Free', 'MUMPS Solver has not been installed.' )
1338
#endif
1339
!------------------------------------------------------------------------------
1340
END SUBROUTINE MumpsLocal_Free
1341
!------------------------------------------------------------------------------
1342
1343
1344
1345
!------------------------------------------------------------------------------
1346
!> Solves a linear system using SuperLU direct solver.
1347
!------------------------------------------------------------------------------
1348
SUBROUTINE SuperLU_SolveSystem( Solver,A,x,b,Free_Fact )
1349
!------------------------------------------------------------------------------
1350
LOGICAL, OPTIONAL :: Free_fact
1351
TYPE(Matrix_t) :: A
1352
TYPE(Solver_t) :: Solver
1353
REAL(KIND=dp), TARGET :: x(*), b(*)
1354
1355
#ifdef HAVE_SUPERLU
1356
LOGICAL :: stat, Factorize, FreeFactorize
1357
integer :: n, nnz, nrhs, iinfo, iopt, nprocs
1358
1359
interface
1360
subroutine solve_superlu( iopt, nprocs, n, nnz, nrhs, values, cols, &
1361
rows, b, ldb, factors, iinfo )
1362
use types
1363
integer :: iopt, nprocs, n, nnz, nrhs, cols(*), rows(*), ldb, iinfo
1364
real(kind=dp) :: values(*), b(*)
1365
integer(kind=addrint) :: factors
1366
end subroutine solve_superlu
1367
end interface
1368
1369
IF ( PRESENT(Free_Fact) ) THEN
1370
IF ( Free_Fact ) THEN
1371
IF ( A % SuperLU_Factors/= 0 ) THEN
1372
iopt = 3
1373
CALL Solve_SuperLU( iopt, nprocs, n, nnz, nrhs, A % Values, &
1374
A % Cols, A % Rows, x, n, A % SuperLU_Factors, iinfo )
1375
A % SuperLU_Factors = 0
1376
END IF
1377
RETURN
1378
END IF
1379
END IF
1380
1381
n = A % NumberOfRows
1382
nrhs = 1
1383
x(1:n) = b(1:n)
1384
nnz = A % Rows(n+1)-1
1385
1386
nprocs = ListGetInteger( Solver % Values, &
1387
'Linear System Number of Threads', stat )
1388
IF ( .NOT. stat ) nprocs = 1
1389
!
1390
Factorize = ListGetLogical( Solver % Values, &
1391
'Linear System Refactorize', stat )
1392
IF ( .NOT. stat ) Factorize = .TRUE.
1393
1394
IF ( Factorize .OR. A % SuperLU_Factors==0 ) THEN
1395
1396
IF ( A % SuperLU_Factors/= 0 ) THEN
1397
iopt = 3
1398
call Solve_SuperLU( iopt, nprocs, n, nnz, nrhs, A % Values, A % Cols, &
1399
A % Rows, x, n, A % SuperLU_Factors, iinfo )
1400
A % SuperLU_Factors=0
1401
END IF
1402
1403
! First, factorize the matrix. The factors are stored in *factors* handle.
1404
iopt = 1
1405
call Solve_SuperLU( iopt, nprocs, n, nnz, nrhs, A % Values, A % Cols, &
1406
A % Rows, x, n, A % SuperLU_Factors, iinfo )
1407
1408
if (iinfo .eq. 0) then
1409
write (*,*) 'Factorization succeeded'
1410
else
1411
write(*,*) 'INFO from factorization = ', iinfo
1412
endif
1413
END IF
1414
1415
!
1416
! Second, solve the system using the existing factors.
1417
iopt = 2
1418
call Solve_SuperLU( iopt, nprocs, n, nnz, nrhs, A % Values, A % Cols, &
1419
A % Rows, x, n, A % SuperLU_Factors, iinfo )
1420
!
1421
if (iinfo .eq. 0) then
1422
write (*,*) 'Solve succeeded'
1423
else
1424
write(*,*) 'INFO from triangular solve = ', iinfo
1425
endif
1426
1427
! Last, free the storage allocated inside SuperLU
1428
FreeFactorize = ListGetLogical( Solver % Values, &
1429
'Linear System Free Factorization', stat )
1430
IF ( .NOT. stat ) FreeFactorize = .TRUE.
1431
1432
IF ( Factorize .AND. FreeFactorize ) THEN
1433
iopt = 3
1434
call Solve_SuperLU( iopt, nprocs, n, nnz, nrhs, A % Values, A % Cols, &
1435
A % Rows, x, n, A % SuperLU_Factors, iinfo )
1436
A % SuperLU_Factors = 0
1437
END IF
1438
#endif
1439
!------------------------------------------------------------------------------
1440
END SUBROUTINE SuperLU_SolveSystem
1441
!------------------------------------------------------------------------------
1442
1443
1444
!------------------------------------------------------------------------------
1445
!> Permon solver
1446
!------------------------------------------------------------------------------
1447
SUBROUTINE Permon_SolveSystem( Solver,A,x,b,Free_Fact )
1448
!------------------------------------------------------------------------------
1449
#ifdef HAVE_FETI4I
1450
USE feti4i
1451
# if defined(ELMER_HAVE_MPI_MODULE)
1452
USE mpi
1453
# endif
1454
#endif
1455
1456
LOGICAL, OPTIONAL :: Free_Fact
1457
TYPE(Matrix_t) :: A
1458
TYPE(Solver_t) :: Solver
1459
REAL(KIND=dp), TARGET :: x(*), b(*)
1460
1461
#ifdef HAVE_FETI4I
1462
# if defined(ELMER_HAVE_MPIF_HEADER)
1463
INCLUDE 'mpif.h'
1464
# endif
1465
1466
INTEGER, ALLOCATABLE :: Owner(:)
1467
INTEGER :: i,j,n,nd,ip,ierr,icntlft,nzloc
1468
LOGICAL :: Factorize, FreeFactorize, stat, matsym, matspd, scaled
1469
1470
INTEGER :: n_dof_partition
1471
1472
INTEGER, ALLOCATABLE :: memb(:), DirichletInds(:), Neighbours(:), IntOptions(:)
1473
REAL(KIND=dp), ALLOCATABLE :: DirichletVals(:), RealOptions(:)
1474
INTEGER :: Comm_active, Group_active, Group_world
1475
1476
REAL(KIND=dp), ALLOCATABLE :: dbuf(:)
1477
1478
1479
n_dof_partition = A % NumberOfRows
1480
1481
! INTERFACE
1482
! FUNCTION Permon_InitSolve(n, gnum, nd, dinds, dvals, n_n, n_ranks) RESULT(handle) BIND(c,name='permon_initsolve')
1483
! USE, INTRINSIC :: ISO_C_BINDING
1484
! TYPE(C_PTR) :: handle
1485
! INTEGER(C_INT), VALUE :: n, nd, n_n
1486
! REAL(C_DOUBLE) :: dvals(*)
1487
! INTEGER(C_INT) :: gnum(*), dinds(*), n_ranks(*)
1488
! END FUNCTION Permon_Initsolve
1489
!
1490
! SUBROUTINE Permon_Solve( handle, x, b ) BIND(c,name='permon_solve')
1491
! USE, INTRINSIC :: ISO_C_BINDING
1492
! REAL(C_DOUBLE) :: x(*), b(*)
1493
! TYPE(C_PTR), VALUE :: handle
1494
! END SUBROUTINE Permon_solve
1495
! END INTERFACE
1496
1497
IF ( PRESENT(Free_Fact) ) THEN
1498
IF ( Free_Fact ) THEN
1499
RETURN
1500
END IF
1501
END IF
1502
1503
Factorize = ListGetLogical( Solver % Values, 'Linear System Refactorize', stat )
1504
IF ( .NOT. stat ) Factorize = .TRUE.
1505
1506
IF ( Factorize .OR. .NOT.C_ASSOCIATED(A % PermonSolverInstance) ) THEN
1507
IF ( C_ASSOCIATED(A % PermonSolverInstance) ) THEN
1508
CALL Fatal( 'Permon', 're-entry not implemented' )
1509
END IF
1510
1511
nd = COUNT(A % ConstrainedDOF)
1512
ALLOCATE(DirichletInds(nd), DirichletVals(nd))
1513
j = 0
1514
DO i=1,A % NumberOfRows
1515
IF(A % ConstrainedDOF(i)) THEN
1516
j = j + 1
1517
DirichletInds(j) = i; DirichletVals(j) = A % Dvalues(i)
1518
END IF
1519
END DO
1520
1521
!TODO sequential case not working
1522
n = 0
1523
ALLOCATE(neighbours(Parenv % PEs))
1524
DO i=1,ParEnv % PEs
1525
IF( ParEnv % IsNeighbour(i) .AND. i-1/=ParEnv % myPE) THEN
1526
n = n + 1
1527
neighbours(n) = i-1
1528
END IF
1529
END DO
1530
1531
!A % PermonSolverInstance = Permon_InitSolve( SIZE(A % ParallelInfo % GlobalDOFs), &
1532
! A % ParallelInfo % GlobalDOFs, nd, DirichletInds, DirichletVals, n, neighbours )
1533
1534
IF( n_dof_partition /= SIZE(A % ParallelInfo % GlobalDOFs) ) THEN
1535
CALL Fatal( 'Permon', &
1536
'inconsistency: A % NumberOfRows /= SIZE(A % ParallelInfo % GlobalDOFs' )
1537
END IF
1538
1539
ALLOCATE(IntOptions(10))
1540
ALLOCATE(RealOptions(1))
1541
1542
CALL FETI4ISetDefaultIntegerOptions(IntOptions)
1543
CALL FETI4ISetDefaultRealOptions(RealOptions)
1544
1545
CALL FETI4ICreateInstance(A % PermonSolverInstance, A % PermonMatrix, &
1546
A % NumberOfRows, b, A % ParallelInfo % GlobalDOFs, &
1547
n, neighbours, &
1548
nd, DirichletInds, DirichletVals, &
1549
IntOptions, RealOptions)
1550
END IF
1551
1552
!CALL Permon_Solve( A % PermonSolverInstance, x, b )
1553
CALL FETI4ISolve(A % PermonSolverInstance, n_dof_partition, x)
1554
#else
1555
CALL Fatal( 'Permon_SolveSystem', 'Permon Solver has not been installed.' )
1556
#endif
1557
!------------------------------------------------------------------------------
1558
END SUBROUTINE Permon_SolveSystem
1559
!------------------------------------------------------------------------------
1560
1561
1562
1563
!------------------------------------------------------------------------------
1564
!> Solves a linear system using Pardiso direct solver (from either MKL or
1565
!> official Pardiso distribution. If possible, MKL-version is used).
1566
!------------------------------------------------------------------------------
1567
SUBROUTINE Pardiso_SolveSystem( Solver,A,x,b,Free_fact )
1568
!------------------------------------------------------------------------------
1569
IMPLICIT NONE
1570
1571
TYPE(Solver_t) :: Solver
1572
TYPE(Matrix_t) :: A
1573
REAL(KIND=dp), TARGET :: x(*), b(*)
1574
LOGICAL, OPTIONAL :: Free_fact
1575
1576
! MKL version of Pardiso (interface is different)
1577
#if defined(HAVE_MKL)
1578
INTERFACE
1579
SUBROUTINE pardiso(pt, maxfct, mnum, mtype, phase, n, &
1580
values, rows, cols, perm, nrhs, iparm, msglvl, b, x, ierror)
1581
USE Types
1582
IMPLICIT NONE
1583
REAL(KIND=dp) :: values(*), b(*), x(*)
1584
INTEGER(KIND=AddrInt) :: pt(*)
1585
INTEGER :: perm(*), nrhs, iparm(*), msglvl, ierror
1586
INTEGER :: maxfct, mnum, mtype, phase, n, rows(*), cols(*)
1587
END SUBROUTINE pardiso
1588
1589
SUBROUTINE pardisoinit(pt, mtype, iparm)
1590
USE Types
1591
IMPLICIT NONE
1592
INTEGER(KIND=AddrInt) :: pt(*)
1593
INTEGER :: mtype
1594
INTEGER :: iparm(*)
1595
END SUBROUTINE pardisoinit
1596
END INTERFACE
1597
1598
INTEGER maxfct, mnum, mtype, phase, n, nrhs, ierror, msglvl
1599
INTEGER, POINTER :: Iparm(:)
1600
INTEGER i, j, k, nz, idum(1), nzutd
1601
LOGICAL :: Found, matsym, matpd
1602
REAL*8 :: ddum(1)
1603
1604
LOGICAL :: Factorize, FreeFactorize
1605
INTEGER :: tlen, allocstat
1606
CHARACTER(:), ALLOCATABLE :: mat_type
1607
1608
REAL(KIND=dp), POINTER :: values(:)
1609
INTEGER, POINTER :: rows(:), cols(:)
1610
1611
! Check if system needs to be refactorized
1612
Factorize = ListGetLogical( Solver % Values, &
1613
'Linear System Refactorize', Found )
1614
IF ( .NOT. Found ) Factorize = .TRUE.
1615
1616
! Set matrix type for Pardiso
1617
mat_type = ListGetString(Solver % Values,'Linear System Matrix Type',Found)
1618
1619
IF (Found) THEN
1620
SELECT CASE(mat_type)
1621
CASE('positive definite')
1622
mtype = 2
1623
CASE('symmetric indefinite')
1624
mtype = -2
1625
CASE('structurally symmetric')
1626
mtype = 1
1627
CASE('nonsymmetric', 'general')
1628
mtype = 11
1629
CASE DEFAULT
1630
mtype = 11
1631
END SELECT
1632
ELSE
1633
! Check if matrix is symmetric or spd
1634
matsym = ListGetLogical(Solver % Values, &
1635
'Linear System Symmetric', Found)
1636
1637
matpd = ListGetLogical(Solver % Values, &
1638
'Linear System Positive Definite', Found)
1639
1640
IF (matsym) THEN
1641
IF (matpd) THEN
1642
! Matrix is symmetric positive definite
1643
mtype = 2
1644
ELSE
1645
! Matrix is structurally symmetric (can't handle indefinite systems!!!!)
1646
mtype = 1
1647
END IF
1648
ELSE
1649
! Matrix is unsymmetric
1650
mtype = 11
1651
END IF
1652
END IF
1653
1654
! Free factorization if requested
1655
IF ( PRESENT(Free_Fact) ) THEN
1656
IF ( Free_Fact ) THEN
1657
IF(ASSOCIATED(A % PardisoId)) THEN
1658
phase = -1 ! release internal memory
1659
n = A % NumberOfRows
1660
maxfct = 1
1661
mnum = 1
1662
nrhs = 1
1663
msglvl = 0
1664
CALL pardiso(A % PardisoId, maxfct, mnum, mtype, phase, n, &
1665
ddum, idum, idum, idum, nrhs, A % PardisoParam, msglvl, ddum, ddum, ierror)
1666
DEALLOCATE(A % PardisoId, A % PardisoParam)
1667
A % PardisoId => NULL()
1668
A % PardisoParam => NULL()
1669
END IF
1670
RETURN
1671
END IF
1672
END IF
1673
1674
! Get number of rows and number of nonzero elements
1675
n = A % Numberofrows
1676
nz = A % Rows(n+1)-1
1677
1678
! Copy upper triangular part of symmetric positive definite system
1679
IF ( ABS(mtype) == 2 ) THEN
1680
nzutd = 0
1681
DO i=1,n
1682
nzutd = nzutd + A % Rows(i+1)-A % Diag(i)
1683
END DO
1684
1685
ALLOCATE( values(nzutd), cols(nzutd), rows(n+1), STAT=allocstat)
1686
IF (allocstat /= 0) THEN
1687
CALL Fatal('Pardiso_SolveSystem', &
1688
'Memory allocation for row and column indices failed')
1689
END IF
1690
1691
! Copy upper triangular part of A to Pardiso structure
1692
Rows(1)=1
1693
DO i=1,n
1694
! Set up row pointers and copy values
1695
nzutd = A % Rows(i+1)-A % Diag(i)
1696
Rows(i+1) = Rows(i)+nzutd
1697
DO j=0,nzutd-1
1698
Cols(Rows(i)+j)=A % Cols(A%Diag(i)+j)
1699
Values(Rows(i)+j)=A % Values(A%Diag(i)+j)
1700
END DO
1701
END DO
1702
1703
ELSE
1704
Cols => A % Cols
1705
Rows => A % Rows
1706
Values => A % Values
1707
END IF
1708
1709
! Set up parameters
1710
msglvl = 0 ! Do not write out any info
1711
maxfct = 1 ! Set up space for 1 matrix at most
1712
mnum = 1 ! Matrix to use in the solution phase (1st and only one)
1713
nrhs = 1 ! Use only one RHS
1714
iparm => A % PardisoParam
1715
1716
! Compute factorization if necessary
1717
IF ( Factorize .OR. .NOT.ASSOCIATED(A % PardisoID) ) THEN
1718
! Free factorization
1719
IF (ASSOCIATED(A % PardisoId)) THEN
1720
phase = -1 ! release internal memory
1721
CALL pardiso (A % PardisoId, maxfct, mnum, mtype, phase, n, &
1722
ddum, idum, idum, idum, nrhs, iparm, msglvl, ddum, ddum, ierror)
1723
DEALLOCATE(A % PardisoId, A % PardisoParam)
1724
A % PardisoId => NULL()
1725
A % PardisoParam => NULL()
1726
END IF
1727
1728
! Allocate pardiso internal structures
1729
ALLOCATE(A % PardisoId(64), A % PardisoParam(64), STAT=allocstat)
1730
IF (allocstat /= 0) THEN
1731
CALL Fatal('Pardiso_SolveSystem', &
1732
'Memory allocation for Pardiso failed')
1733
END IF
1734
iparm => A % PardisoParam
1735
iparm = 0
1736
A % PardisoId = 0
1737
1738
! Set up scaling values for solver based on matrix type
1739
CALL pardisoinit(A % PardisoId, mtype, iparm)
1740
1741
! Set up rest of parameters explicitly
1742
iparm(1)=1 ! Do not use solver default parameters
1743
iparm(2)=2 ! Minimize fill-in with nested dissection from Metis
1744
iparm(3)=0 ! Reserved
1745
iparm(4)=0 ! Always compute factorization
1746
iparm(5)=0 ! No user input permutation
1747
iparm(6)=0 ! Write solution vector to x
1748
iparm(8)=5 ! Number of iterative refinement steps
1749
iparm(18)=-1 ! Report nnz(L) and nnz(U)
1750
iparm(19)=0 ! Do not report Mflops
1751
iparm(27)=0 ! Do not check sparse matrix representation
1752
iparm(35)=0 ! Use Fortran style indexing
1753
iparm(60)=0 ! Use in-core version of Pardiso
1754
1755
! Perform analysis
1756
phase = 11 ! Analysis
1757
CALL pardiso(A % PardisoId, maxfct, mnum, mtype, phase, n, &
1758
values, rows, cols, idum, nrhs, iparm, msglvl, ddum, ddum, ierror)
1759
1760
IF (ierror /= 0) THEN
1761
WRITE(*,'(A,I0)') 'MKL Pardiso: ERROR=', ierror
1762
CALL Fatal('Pardiso_SolveSystem','Error during analysis phase')
1763
END IF
1764
1765
! Perform factorization
1766
phase = 22 ! Factorization
1767
CALL pardiso (A % pardisoId, maxfct, mnum, mtype, phase, n, &
1768
values, rows, cols, idum, nrhs, iparm, msglvl, ddum, ddum, ierror)
1769
1770
IF (ierror /= 0) THEN
1771
WRITE(*,'(A,I0)') 'MKL Pardiso: ERROR=', ierror
1772
CALL Fatal('Pardiso_SolveSystem','Error during factorization phase')
1773
END IF
1774
END IF ! Compute factorization
1775
1776
! Perform solve
1777
phase = 33 ! Solve, iterative refinement
1778
CALL pardiso(A % PardisoId, maxfct, mnum, mtype, phase, n, &
1779
values, rows, cols, idum, nrhs, iparm, msglvl, b, x, ierror)
1780
1781
IF (ierror /= 0) THEN
1782
WRITE(*,'(A,I0)') 'MKL Pardiso: ERROR=', ierror
1783
CALL Fatal('Pardiso_SolveSystem','Error during solve phase')
1784
END IF
1785
1786
! Release memory if needed
1787
FreeFactorize = ListGetLogical( Solver % Values, &
1788
'Linear System Free Factorization', Found )
1789
IF ( .NOT. Found ) FreeFactorize = .TRUE.
1790
1791
IF ( Factorize .AND. FreeFactorize ) THEN
1792
phase = -1 ! release internal memory
1793
CALL pardiso (A % PardisoId, maxfct, mnum, mtype, phase, n, &
1794
ddum, idum, idum, idum, nrhs, iparm, msglvl, ddum, ddum, ierror)
1795
1796
DEALLOCATE(A % PardisoId, A % PardisoParam)
1797
A % PardisoId => NULL()
1798
A % PardisoParam => NULL()
1799
END IF
1800
IF (ABS(mtype) == 2) DEALLOCATE(Values, Rows, Cols)
1801
1802
! Distribution version of Pardiso
1803
#elif defined(HAVE_PARDISO)
1804
!.. All other variables
1805
1806
INTERFACE
1807
SUBROUTINE pardiso(pt, maxfct, mnum, mtype, phase, n, &
1808
values, rows, cols, idum, nrhs, iparm, msglvl, b, x, ierror, dparm)
1809
USE Types
1810
REAL(KIND=dp) :: values(*), b(*), x(*), dparm(*)
1811
INTEGER(KIND=AddrInt) :: pt(*)
1812
INTEGER :: idum(*), nrhs, iparm(*), msglvl, ierror
1813
INTEGER :: maxfct, mnum, mtype, phase, n, rows(*), cols(*)
1814
END SUBROUTINE pardiso
1815
1816
SUBROUTINE pardisoinit(pt,mtype,solver,iparm,dparm,ierror)
1817
USE Types
1818
INTEGER :: mtype, iparm(*),ierror,solver
1819
REAL(KIND=dp) :: dparm(*)
1820
INTEGER(KIND=AddrInt) :: pt(*)
1821
END SUBROUTINE pardisoinit
1822
END INTERFACE
1823
1824
INTEGER maxfct, mnum, mtype, phase, n, nrhs, ierror, msglvl
1825
INTEGER, POINTER :: Iparm(:)
1826
INTEGER i, j, k, nz, idum(1)
1827
LOGICAL :: Found, Symm, Posdef
1828
REAL*8 waltime1, waltime2, ddum(1), dparm(64)
1829
1830
LOGICAL :: Factorize, FreeFactorize
1831
INTEGER :: tlen
1832
CHARACTER(LEN=16) :: threads
1833
1834
REAL(KIND=dp), POINTER :: values(:)
1835
INTEGER, POINTER :: rows(:), cols(:)
1836
1837
IF ( PRESENT(Free_Fact) ) THEN
1838
IF ( Free_Fact ) THEN
1839
IF(ASSOCIATED(A % PardisoId)) THEN
1840
phase = -1 ! release internal memory
1841
n = A % NumberOfRows
1842
mtype = 11
1843
maxfct = 1
1844
mnum = 1
1845
nrhs = 1
1846
msglvl = 0
1847
CALL pardiso(A % PardisoId, maxfct, mnum, mtype, phase, n, &
1848
ddum, idum, idum, idum, nrhs, A % PardisoParam, msglvl, ddum, ddum, ierror,dparm)
1849
DEALLOCATE(A % PardisoId, A % PardisoParam)
1850
A % PardisoId => NULL()
1851
A % PardisoParam => NULL()
1852
END IF
1853
RETURN
1854
END IF
1855
END IF
1856
1857
! .. Setup Pardiso control parameters und initialize the solvers
1858
! internal address pointers. This is only necessary for the FIRST
1859
! call of the PARDISO solver.
1860
!
1861
Factorize = ListGetLogical( Solver % Values, &
1862
'Linear System Refactorize', Found )
1863
IF ( .NOT. Found ) Factorize = .TRUE.
1864
1865
symm = ListGetLogical( Solver % Values, &
1866
'Linear System Symmetric', Found )
1867
1868
posdef = ListGetLogical( Solver % Values, &
1869
'Linear System Positive Definite', Found )
1870
1871
mtype = 11
1872
1873
cols => a % cols
1874
rows => a % rows
1875
values => a % values
1876
n = A % Numberofrows
1877
1878
IF ( posdef ) THEN
1879
nz = A % rows(n+1)-1
1880
allocate( values(nz), cols(nz), rows(n+1) )
1881
k = 1
1882
do i=1,n
1883
rows(i)=k
1884
do j=a % rows(i), a % rows(i+1)-1
1885
if ( a % cols(j)>=i .and. a % values(j) /= 0._dp ) then
1886
cols(k) = a % cols(j)
1887
values(k) = a % values(j)
1888
k = k + 1
1889
end if
1890
end do
1891
end do
1892
rows(n+1)=k
1893
mtype = 2
1894
ELSE IF ( symm ) THEN
1895
mtype = 1
1896
END IF
1897
1898
msglvl = 0 ! with statistical information
1899
maxfct = 1
1900
mnum = 1
1901
nrhs = 1
1902
iparm => A % PardisoParam
1903
1904
1905
IF ( Factorize .OR. .NOT.ASSOCIATED(A % PardisoID) ) THEN
1906
IF(ASSOCIATED(A % PardisoId)) THEN
1907
phase = -1 ! release internal memory
1908
CALL pardiso (A % PardisoId, maxfct, mnum, mtype, phase, n, &
1909
ddum, idum, idum, idum, nrhs, iparm, msglvl, ddum, ddum, ierror,dparm)
1910
DEALLOCATE(A % PardisoId, A % PardisoParam)
1911
A % PardisoId => NULL()
1912
A % PardisoParam => NULL()
1913
END IF
1914
1915
ALLOCATE(A % PardisoId(64), A % PardisoParam(64))
1916
iparm => A % PardisoParam
1917
CALL pardisoinit(A % PardisoId, mtype, 0, iparm, dparm, ierror )
1918
1919
!.. Reordering and Symbolic Factorization, This step also allocates
1920
! all memory that is necessary for the factorization
1921
!
1922
phase = 11 ! only reordering and symbolic factorization
1923
msglvl = 0 ! with statistical information
1924
maxfct = 1
1925
mnum = 1
1926
nrhs = 1
1927
1928
! .. Numbers of Processors ( value of OMP_NUM_THREADS )
1929
CALL envir( 'OMP_NUM_THREADS', threads, tlen )
1930
1931
iparm(3) = 1
1932
IF ( tlen>0 ) &
1933
READ(threads(1:tlen),*) iparm(3)
1934
IF (iparm(3)<=0) Iparm(3) = 1
1935
1936
CALL pardiso(A % PardisoId, maxfct, mnum, mtype, phase, n, &
1937
values, rows, cols, idum, nrhs, iparm, msglvl, ddum, ddum, ierror, dparm)
1938
1939
IF (ierror /= 0) THEN
1940
WRITE(*,*) 'The following ERROR was detected: ', ierror
1941
STOP EXIT_ERROR
1942
END IF
1943
1944
!.. Factorization.
1945
phase = 22 ! only factorization
1946
CALL pardiso (A % pardisoId, maxfct, mnum, mtype, phase, n, &
1947
values, rows, cols, idum, nrhs, iparm, msglvl, ddum, ddum, ierror, dparm)
1948
1949
IF (ierror /= 0) THEN
1950
WRITE(*,*) 'The following ERROR was detected: ', ierror
1951
STOP EXIT_ERROR
1952
ENDIF
1953
END IF
1954
1955
!.. Back substitution and iterative refinement
1956
phase = 33 ! only factorization
1957
iparm(8) = 0 ! max number of iterative refinement steps
1958
! (if perturbations occur in the factorization
1959
! phase, two refinement steps are taken)
1960
1961
CALL pardiso(A % PardisoId, maxfct, mnum, mtype, phase, n, &
1962
values, rows, cols, idum, nrhs, iparm, msglvl, b, x, ierror, dparm)
1963
1964
!.. Termination and release of memory
1965
FreeFactorize = ListGetLogical( Solver % Values, &
1966
'Linear System Free Factorization', Found )
1967
IF ( .NOT. Found ) FreeFactorize = .TRUE.
1968
1969
IF ( Factorize .AND. FreeFactorize ) THEN
1970
phase = -1 ! release internal memory
1971
CALL pardiso (A % PardisoId, maxfct, mnum, mtype, phase, n, &
1972
ddum, idum, idum, idum, nrhs, iparm, msglvl, ddum, ddum, ierror, dparm)
1973
1974
DEALLOCATE(A % PardisoId, A % PardisoParam)
1975
A % PardisoId => NULL()
1976
A % PardisoParam => NULL()
1977
END IF
1978
1979
IF(posdef) DEALLOCATE( values, rows, cols )
1980
#else
1981
CALL Fatal( 'Parsido_SolveSystem', 'Pardiso solver has not been installed.' )
1982
#endif
1983
1984
!------------------------------------------------------------------------------
1985
END SUBROUTINE Pardiso_SolveSystem
1986
!------------------------------------------------------------------------------
1987
1988
!------------------------------------------------------------------------------
1989
!> Solves a linear system using Cluster Pardiso direct solver from MKL
1990
!------------------------------------------------------------------------------
1991
SUBROUTINE CPardiso_SolveSystem( Solver,A,x,b,Free_fact )
1992
!------------------------------------------------------------------------------
1993
IMPLICIT NONE
1994
1995
TYPE(Solver_t) :: Solver
1996
TYPE(Matrix_t) :: A
1997
REAL(KIND=dp), TARGET :: x(*), b(*)
1998
LOGICAL, OPTIONAL :: Free_fact
1999
2000
! Cluster Pardiso
2001
#if defined(HAVE_MKL) && defined(HAVE_CPARDISO)
2002
INTERFACE
2003
SUBROUTINE cluster_sparse_solver(pt, maxfct, mnum, mtype, phase, n, &
2004
values, rows, cols, perm, nrhs, iparm, msglvl, b, x, comm, ierror)
2005
USE Types
2006
REAL(KIND=dp) :: values(*), b(*), x(*)
2007
INTEGER(KIND=AddrInt) :: pt(*)
2008
INTEGER :: perm(*), nrhs, iparm(*), msglvl, ierror
2009
INTEGER :: maxfct, mnum, mtype, phase, n, rows(*), cols(*), comm
2010
END SUBROUTINE cluster_sparse_solver
2011
END INTERFACE
2012
2013
INTEGER :: phase, n, ierror
2014
INTEGER, POINTER :: Iparm(:)
2015
INTEGER i, j, k, nz, nzutd, idum(1), nl, nt
2016
LOGICAL :: Found, matsym, matpd
2017
REAL(kind=dp) :: ddum(1)
2018
REAL(kind=dp), POINTER, DIMENSION(:) :: dbuf
2019
2020
LOGICAL :: Factorize, FreeFactorize
2021
INTEGER :: tlen, allocstat
2022
2023
REAL(KIND=dp), POINTER CONTIG :: values(:)
2024
INTEGER, POINTER CONTIG :: rows(:), cols(:)
2025
2026
! Free factorization if requested
2027
IF ( PRESENT(Free_Fact) ) THEN
2028
IF ( Free_Fact ) THEN
2029
CALL CPardiso_Free(A)
2030
END IF
2031
2032
RETURN
2033
END IF
2034
2035
! Check if system needs to be refactorized
2036
Factorize = ListGetLogical( Solver % Values, &
2037
'Linear System Refactorize', Found )
2038
IF ( .NOT. Found ) Factorize = .TRUE.
2039
2040
! Compute factorization if necessary
2041
IF ( Factorize .OR. .NOT.ASSOCIATED(A % CPardisoID) ) THEN
2042
CALL CPardiso_Factorize(Solver, A)
2043
END IF
2044
2045
! Get global start and end of domain
2046
nl = A % CPardisoId % iparm(41)
2047
nt = A % CPardisoId % iparm(42)
2048
2049
! Gather RHS
2050
A % CPardisoId % rhs = 0D0
2051
DO i=1,A % NumberOfRows
2052
A % CPardisoId % rhs(A % Gorder(i)-nl+1) = b(i)
2053
END DO
2054
2055
! Perform solve
2056
phase = 33 ! Solve, iterative refinement
2057
CALL cluster_sparse_solver(A % CPardisoId % ID, &
2058
A % CPardisoId % maxfct, A % CPardisoId % mnum, &
2059
A % CPardisoId % mtype, phase, A % CPardisoId % n, &
2060
A % CPardisoID % aa, A % CPardisoID % ia, A % CPardisoID % ja, idum, &
2061
A % CPardisoId % nrhs, A % CPardisoID % iparm, &
2062
A % CPardisoId % msglvl, A % CPardisoId % rhs, &
2063
A % CPardisoId % x, A % Comm, ierror)
2064
2065
IF (ierror /= 0) THEN
2066
WRITE(*,'(A,I0)') 'MKL CPardiso: ERROR=', ierror
2067
CALL Fatal('CPardiso_SolveSystem','Error during solve phase')
2068
END IF
2069
2070
! Distribute solution
2071
DO i=1,A % NumberOfRows
2072
x(i)=A % CPardisoId % x(A % Gorder(i)-nl+1)
2073
END DO
2074
2075
! Release memory if needed
2076
FreeFactorize = ListGetLogical( Solver % Values, &
2077
'Linear System Free Factorization', Found )
2078
IF ( .NOT. Found ) FreeFactorize = .TRUE.
2079
2080
IF ( Factorize .AND. FreeFactorize ) THEN
2081
CALL CPardiso_Free(A)
2082
END IF
2083
2084
#else
2085
CALL Fatal( 'CParsido_SolveSystem', 'Cluster Pardiso solver has not been installed.' )
2086
#endif
2087
!------------------------------------------------------------------------------
2088
END SUBROUTINE CPardiso_SolveSystem
2089
!------------------------------------------------------------------------------
2090
2091
#if defined(HAVE_MKL) && defined(HAVE_CPARDISO)
2092
SUBROUTINE CPardiso_Factorize(Solver, A)
2093
IMPLICIT NONE
2094
TYPE(Solver_t) :: Solver
2095
TYPE(Matrix_t) :: A
2096
2097
INTERFACE
2098
SUBROUTINE cluster_sparse_solver(pt, maxfct, mnum, mtype, phase, n, &
2099
values, rows, cols, perm, nrhs, iparm, msglvl, b, x, comm, ierror)
2100
USE Types
2101
REAL(KIND=dp) :: values(*), b(*), x(*)
2102
INTEGER(KIND=AddrInt) :: pt(*)
2103
INTEGER :: perm(*), nrhs, iparm(*), msglvl, ierror
2104
INTEGER :: maxfct, mnum, mtype, phase, n, rows(*), cols(*), comm
2105
END SUBROUTINE cluster_sparse_solver
2106
END INTERFACE
2107
2108
LOGICAL :: matsym, matpd, Found
2109
INTEGER :: i, j, k, rind, lrow, rptr, rsize, lind, tind
2110
INTEGER :: allocstat, n, nz, nzutd, nl, nt, nOwned, nhalo, ierror
2111
INTEGER :: phase, idum(1)
2112
REAL(kind=dp) :: ddum(1)
2113
REAL(kind=dp), DIMENSION(:), POINTER :: aa
2114
INTEGER, DIMENSION(:), POINTER CONTIG :: iparm, ia, ja, owner, dsize, iperm, Order
2115
2116
INTEGER :: fid
2117
CHARACTER(:), ALLOCATABLE :: mat_type
2118
2119
! Free old factorization if necessary
2120
IF (ASSOCIATED(A % CPardisoId)) THEN
2121
CALL CPardiso_Free(A)
2122
END IF
2123
2124
! Allocate Pardiso structure
2125
ALLOCATE(A % CPardisoId, STAT=allocstat)
2126
IF (allocstat /= 0) THEN
2127
CALL Fatal('CPardiso_Factorize', &
2128
'Memory allocation for CPardiso failed')
2129
END IF
2130
! Allocate control structures
2131
ALLOCATE(A % CPardisoId% ID(64), A % CPardisoId % IParm(64), STAT=allocstat)
2132
IF (allocstat /= 0) THEN
2133
CALL Fatal('CPardiso_Factorize', &
2134
'Memory allocation for CPardiso failed')
2135
END IF
2136
2137
iparm => A % CPardisoId % IParm
2138
! Initialize control parameters and solver Id's
2139
DO i=1,64
2140
iparm(i)=0
2141
END DO
2142
DO i=1,64
2143
A % CPardisoId % ID(i)=0
2144
END DO
2145
2146
! Set matrix type for CPardiso
2147
mat_type = ListGetString(Solver % Values,'Linear System Matrix Type',Found)
2148
IF (Found) THEN
2149
SELECT CASE(mat_type)
2150
CASE('positive definite')
2151
A % CPardisoID % mtype = 2
2152
CASE('symmetric indefinite')
2153
A % CPardisoID % mtype = -2
2154
CASE('structurally symmetric')
2155
A % CPardisoID % mtype = 1
2156
CASE('nonsymmetric', 'general')
2157
A % CPardisoID % mtype = 11
2158
CASE DEFAULT
2159
A % CPardisoID % mtype = 11
2160
END SELECT
2161
ELSE
2162
! Check if matrix is symmetric or spd
2163
matsym = ListGetLogical(Solver % Values, &
2164
'Linear System Symmetric', Found)
2165
2166
matpd = ListGetLogical(Solver % Values, &
2167
'Linear System Positive Definite', Found)
2168
2169
IF (matsym) THEN
2170
IF (matpd) THEN
2171
! Matrix is symmetric positive definite
2172
A % CPardisoID % mtype = 2
2173
ELSE
2174
! Matrix is structurally symmetric
2175
A % CPardisoID % mtype = 1
2176
END IF
2177
ELSE
2178
! Matrix is nonsymmetric
2179
A % CPardisoID % mtype = 11
2180
END IF
2181
END IF
2182
2183
! Set up continuous numbering for the whole computation domain
2184
n = SIZE(A % ParallelInfo % GlobalDOFs)
2185
ALLOCATE(A % Gorder(n), Owner(n), STAT=allocstat)
2186
IF (allocstat /= 0) THEN
2187
CALL Fatal('CPardiso_Factorize', &
2188
'Memory allocation for CPardiso global numbering failed')
2189
END IF
2190
CALL ContinuousNumbering(A % ParallelInfo, A % Perm, A % Gorder, Owner, nOwn=nOwned)
2191
2192
! Compute the number of global dofs
2193
CALL MPI_ALLREDUCE(nOwned, A % CPardisoId % n, &
2194
1, MPI_INTEGER, MPI_SUM, A % Comm, ierror)
2195
DEALLOCATE(Owner)
2196
2197
! Find bounds of domain
2198
nl = A % Gorder(1)
2199
nt = A % Gorder(1)
2200
DO i=2,n
2201
! NOTE: Matrix is structurally symmetric
2202
rind = A % Gorder(i)
2203
nl = MIN(rind, nl)
2204
nt = MAX(rind, nt)
2205
END DO
2206
2207
! Allocate temp storage for global numbering
2208
ALLOCATE(Order(n), iperm(n), STAT=allocstat)
2209
IF (allocstat /= 0) THEN
2210
CALL Fatal('CPardiso_Factorize', &
2211
'Memory allocation for CPardiso global numbering failed')
2212
END IF
2213
2214
! Sort global numbering to build matrix
2215
Order(1:n) = A % Gorder(1:n)
2216
DO i=1,n
2217
iperm(i)=i
2218
END DO
2219
CALL SortI(n, Order, iperm)
2220
2221
! Allocate storage for CPardiso matrix
2222
nhalo = (nt-nl+1)-n
2223
nz = A % Rows(A % NumberOfRows+1)-1
2224
IF (ABS(A % CPardisoID % mtype) == 2) THEN
2225
nzutd = ((nz-n)/2)+1 + n
2226
ALLOCATE(A % CPardisoID % ia(nt-nl+2), &
2227
A % CPardisoId % ja(nzutd+nhalo), &
2228
A % CPardisoId % aa(nzutd+nhalo), &
2229
STAT=allocstat)
2230
ELSE
2231
ALLOCATE(A % CPardisoID % ia(nt-nl+2), &
2232
A % CPardisoId % ja(nz+nhalo), &
2233
A % CPardisoId % aa(nz+nhalo), &
2234
STAT=allocstat)
2235
END IF
2236
IF (allocstat /= 0) THEN
2237
CALL Fatal('CPardiso_Factorize', &
2238
'Memory allocation for CPardiso matrix failed')
2239
END IF
2240
ia => A % CPardisoId % ia
2241
ja => A % CPardisoId % ja
2242
aa => A % CPardisoId % aa
2243
2244
! Build distributed CRS matrix
2245
ia(1) = 1
2246
lrow = 1 ! Next row to add
2247
rptr = 1 ! Pointer to next row to add, equals ia(lrow)
2248
lind = Order(1)-1 ! Row pointer for the first round
2249
2250
! Add rows of matrix
2251
DO i=1,n
2252
! Add empty rows until the beginning of the row to add
2253
! (first round adds nothing due to choice of lind)
2254
tind = Order(i)
2255
rsize = (tind-lind)-1
2256
2257
! Put zeroes to the diagonal
2258
DO j=1,rsize
2259
ia(lrow+j)=rptr+j
2260
ja(rptr+(j-1))=lind+j
2261
aa(rptr+(j-1))=0D0
2262
END DO
2263
! Set up row pointers
2264
rptr = rptr + rsize
2265
lrow = lrow + rsize
2266
2267
! Add next row
2268
rind = iperm(i)
2269
lind = A % rows(rind)
2270
tind = A % rows(rind+1)
2271
IF (ABS(A % CPardisoId % mtype) == 2) THEN
2272
! Add only upper triangular elements for symmetric matrices
2273
rsize = 0
2274
DO j=lind, tind-1
2275
IF (A % Gorder(A % Cols(j)) >= Order(i)) THEN
2276
ja(rptr+rsize)=A % Gorder(A % Cols(j))
2277
aa(rptr+rsize)=A % values(j)
2278
rsize = rsize + 1
2279
END IF
2280
END DO
2281
2282
ELSE
2283
rsize = tind-lind
2284
DO j=lind, tind-1
2285
ja(rptr+(j-lind))=A % Gorder(A % Cols(j))
2286
aa(rptr+(j-lind))=A % values(j)
2287
END DO
2288
END IF
2289
2290
! Sort column indices
2291
CALL SortF(rsize, ja(rptr:rptr+rsize), aa(rptr:rptr+rsize))
2292
2293
! Set up row pointers
2294
rptr = rptr + rsize
2295
lrow = lrow + 1
2296
ia(lrow) = rptr
2297
2298
lind = Order(i) ! Store row index for next round
2299
END DO
2300
2301
! Deallocate temp storage
2302
DEALLOCATE(Order, iperm)
2303
2304
! Set up parameters
2305
A % CPardisoId % msglvl = 0 ! Do not write out = 0 / write out = 1 info
2306
A % CPardisoId % maxfct = 1 ! Set up space for 1 matrix at most
2307
A % CPardisoId % mnum = 1 ! Matrix to use in the solution phase (1st and only one)
2308
A % CPardisoId % nrhs = 1 ! Use only one RHS
2309
ALLOCATE(A % CPardisoId % rhs(nt-nl+1), &
2310
A % CPardisoId % x(nt-nl+1), STAT=allocstat)
2311
IF (allocstat /= 0) THEN
2312
CALL Fatal('CPardiso_Factorize', &
2313
'Memory allocation for CPardiso rhs and solution vector x failed')
2314
END IF
2315
2316
! Set up parameters explicitly
2317
iparm(1)=1 ! Do not use = 1 / use = 0 solver default parameters
2318
iparm(2)=2 ! Minimize fill-in with OpenMP nested dissection
2319
iparm(5)=0 ! No user input permutation
2320
iparm(6)=0 ! Write solution vector to x
2321
iparm(8)=0 ! Number of iterative refinement steps
2322
IF (A % CPardisoID % mtype ==11 .OR. &
2323
A % CPardisoID % mtype == 13) THEN
2324
iparm(10)=13 ! Perturbation value 10^-iparm(10) in case of small pivots
2325
iparm(11)=1 ! Use scalings from symmetric weighted matching
2326
iparm(13)=1 ! Use permutations from nonsymmetric weighted matching
2327
ELSE
2328
iparm(10)=8 ! Perturbation value 10^-iparm(10) in case of small pivots
2329
iparm(11)=0 ! Do not use scalings from symmetric weighted matching
2330
iparm(13)=0 ! Do not use permutations from symmetric weighted matching
2331
END IF
2332
2333
iparm(21)=1 ! Do not use Bunch Kaufman pivoting
2334
iparm(27)=0 ! Do not check sparse matrix representation
2335
iparm(28)=0 ! Use double precision
2336
iparm(35)=0 ! Use Fortran indexing
2337
2338
! CPardiso matrix input format
2339
iparm(40) = 2 ! Distributed solution phase, distributed solution vector
2340
iparm(41) = nl ! Beginning of solution domain
2341
iparm(42) = nt ! End of solution domain
2342
2343
! Perform analysis
2344
phase = 11 ! Analysis
2345
CALL cluster_sparse_solver(A % CPardisoId % ID, &
2346
A % CPardisoId % maxfct, A % CPardisoId % mnum, &
2347
A % CPardisoId % mtype, phase, A % CPardisoId % n, &
2348
aa, ia, ja, idum, A % CPardisoId % nrhs, iparm, &
2349
A % CPardisoId % msglvl, &
2350
ddum, ddum, A % Comm, ierror)
2351
IF (ierror /= 0) THEN
2352
WRITE(*,'(A,I0)') 'MKL CPardiso: ERROR=', ierror
2353
CALL Fatal('CPardiso_SolveSystem','Error during analysis phase')
2354
END IF
2355
2356
! Perform factorization
2357
phase = 22 ! Factorization
2358
CALL cluster_sparse_solver(A % CPardisoId % ID, &
2359
A % CPardisoId % maxfct, A % CPardisoId % mnum, &
2360
A % CPardisoId % mtype, phase, A % CPardisoId % n, &
2361
aa, ia, ja, idum, A % CPardisoId % nrhs, iparm, &
2362
A % CPardisoId % msglvl, &
2363
ddum, ddum, A % Comm, ierror)
2364
IF (ierror /= 0) THEN
2365
WRITE(*,'(A,I0)') 'MKL CPardiso: ERROR=', ierror
2366
CALL Fatal('CPardiso_SolveSystem','Error during factorization phase')
2367
END IF
2368
END SUBROUTINE CPardiso_Factorize
2369
2370
2371
SUBROUTINE CPardiso_Free(A)
2372
IMPLICIT NONE
2373
2374
TYPE(Matrix_t) :: A
2375
INTERFACE
2376
SUBROUTINE cluster_sparse_solver(pt, maxfct, mnum, mtype, phase, n, &
2377
values, rows, cols, perm, nrhs, iparm, &
2378
msglvl, b, x, comm, ierror)
2379
USE Types
2380
REAL(KIND=dp) :: values(*), b(*), x(*)
2381
INTEGER(KIND=AddrInt) :: pt(*)
2382
INTEGER :: perm(*), nrhs, iparm(*), msglvl, ierror
2383
INTEGER :: maxfct, mnum, mtype, phase, n, rows(*), cols(*), comm
2384
END SUBROUTINE cluster_sparse_solver
2385
END INTERFACE
2386
2387
INTEGER :: ierror, phase, idum(1)
2388
REAL(kind=dp) :: ddum(1)
2389
2390
IF(ASSOCIATED(A % CPardisoId)) THEN
2391
phase = -1 ! release internal memory
2392
CALL cluster_sparse_solver(A % CPardisoId % ID, &
2393
A % CPardisoID % maxfct, A % CPardisoID % mnum, &
2394
A % CPardisoID % mtype, phase, A % CPardisoID % n, &
2395
A % CPardisoId % aa, A % CPardisoId % ia, A % CPardisoId % ja, &
2396
idum, A % CPardisoID % nrhs, A % CPardisoID % IParm, &
2397
A % CPardisoID % msglvl, ddum, ddum, A % Comm, ierror)
2398
2399
! Deallocate global ordering
2400
DEALLOCATE(A % Gorder)
2401
2402
! Deallocate control structures
2403
DEALLOCATE(A % CPardisoId % ID)
2404
DEALLOCATE(A % CPardisoID % IParm)
2405
! Deallocate matrix and permutation
2406
DEALLOCATE(A % CPardisoId % ia, A % CPardisoId % ja, &
2407
A % CPardisoId % aa, A % CPardisoID % rhs, &
2408
A % CPardisoID % x)
2409
! Deallocate CPardiso structure
2410
DEALLOCATE(A % CPardisoID)
2411
END IF
2412
END SUBROUTINE CPardiso_Free
2413
#endif
2414
2415
2416
!------------------------------------------------------------------------------
2417
SUBROUTINE DirectSolver( A,x,b,Solver,Free_Fact )
2418
!------------------------------------------------------------------------------
2419
2420
TYPE(Solver_t) :: Solver
2421
REAL(KIND=dp) :: x(*),b(*)
2422
TYPE(Matrix_t) :: A
2423
LOGICAL, OPTIONAL :: Free_Fact
2424
!------------------------------------------------------------------------------
2425
2426
LOGICAL :: GotIt
2427
CHARACTER(:), ALLOCATABLE :: Method
2428
!------------------------------------------------------------------------------
2429
2430
IF ( PRESENT(Free_Fact) ) THEN
2431
IF ( Free_Fact ) THEN
2432
CALL BandSolver( A, x, b, Free_Fact )
2433
CALL ComplexBandSolver( A, x, b, Free_Fact )
2434
#ifdef HAVE_MUMPS
2435
CALL Mumps_SolveSystem( Solver, A, x, b, Free_Fact )
2436
CALL MumpsLocal_SolveSystem( Solver, A, x, b, Free_Fact )
2437
#endif
2438
#if defined(HAVE_MKL) || defined(HAVE_PARDISO)
2439
CALL Pardiso_SolveSystem( Solver, A, x, b, Free_Fact )
2440
#endif
2441
#if defined(HAVE_MKL) && defined(HAVE_CPARDISO)
2442
CALL CPardiso_SolveSystem( Solver, A, x, b, Free_Fact )
2443
#endif
2444
#ifdef HAVE_SUPERLU
2445
CALL SuperLU_SolveSystem( Solver, A, x, b, Free_Fact )
2446
#endif
2447
#ifdef HAVE_UMFPACK
2448
CALL Umfpack_SolveSystem( Solver, A, x, b, Free_Fact )
2449
#endif
2450
#ifdef HAVE_CHOLMOD
2451
CALL SPQR_SolveSystem( Solver, A, x, b, Free_Fact )
2452
CALL Cholmod_SolveSystem( Solver, A, x, b, Free_Fact )
2453
#endif
2454
#ifdef HAVE_FETI4I
2455
CALL Permon_SolveSystem( Solver, A, x, b, Free_Fact )
2456
#endif
2457
RETURN
2458
RETURN
2459
END IF
2460
END IF
2461
2462
Method=ListGetString(Solver % Values,'Linear System Direct Method',GotIt)
2463
IF ( .NOT. GotIt ) Method = 'banded'
2464
2465
2466
CALL Info('DirectSolver','Using direct method: '//Method,Level=9)
2467
2468
#if !defined (HAVE_UMFPACK) && defined (HAVE_MUMPS)
2469
IF ( Method == 'umfpack' .OR. Method == 'big umfpack' ) THEN
2470
CALL Warn( 'CheckLinearSolverOptions', 'UMFPACK solver not installed, using MUMPS instead!' )
2471
Method = 'mumps'
2472
END IF
2473
#endif
2474
2475
SELECT CASE(Method)
2476
CASE( 'banded', 'symmetric banded' )
2477
IF ( .NOT. A % Complex ) THEN
2478
CALL BandSolver( A, x, b )
2479
ELSE
2480
CALL ComplexBandSolver( A, x, b )
2481
END IF
2482
2483
CASE( 'umfpack', 'big umfpack' )
2484
CALL Umfpack_SolveSystem( Solver, A, x, b )
2485
2486
CASE( 'cholmod' )
2487
CALL Cholmod_SolveSystem( Solver, A, x, b )
2488
2489
CASE( 'spqr' )
2490
CALL SPQR_SolveSystem( Solver, A, x, b )
2491
2492
CASE( 'mumps' )
2493
CALL Mumps_SolveSystem( Solver, A, x, b )
2494
2495
CASE( 'mumpslocal' )
2496
CALL MumpsLocal_SolveSystem( Solver, A, x, b )
2497
2498
CASE( 'superlu' )
2499
CALL SuperLU_SolveSystem( Solver, A, x, b )
2500
2501
CASE( 'permon' )
2502
CALL Permon_SolveSystem( Solver, A, x, b )
2503
2504
CASE( 'pardiso' )
2505
CALL Pardiso_SolveSystem( Solver, A, x, b )
2506
2507
CASE( 'cpardiso' )
2508
CALL CPardiso_SolveSystem( Solver, A, x, b )
2509
2510
CASE DEFAULT
2511
CALL Fatal( 'DirectSolver', 'Unknown direct solver method.' )
2512
END SELECT
2513
2514
! We should be able to trust that a direct strategy will return a converged
2515
! linear system.
2516
IF( ASSOCIATED( Solver % Variable ) ) THEN
2517
Solver % Variable % LinConverged = 1
2518
END IF
2519
2520
!------------------------------------------------------------------------------
2521
END SUBROUTINE DirectSolver
2522
!------------------------------------------------------------------------------
2523
2524
END MODULE DirectSolve
2525
2526
!> \} ElmerLib
2527
2528