Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/fem/src/Feti.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: 30 Mar 2011
34
! *
35
! *****************************************************************************/
36
37
!> \ingroup ElmerLib
38
!> \{
39
40
!-------------------------------------------------------------------------------
41
!> Basic FETI solver, for Poisson & Navier style of equations.
42
!-------------------------------------------------------------------------------
43
44
#include "../config.h"
45
46
MODULE FetiSolve
47
48
USE MeshUtils, ONLY : FindRigidBodyFixingNodes
49
USE DefUtils
50
IMPLICIT NONE
51
52
TYPE(ValueList_t), PRIVATE, POINTER :: Params => Null()
53
54
55
! Communication buffer stuff we send to our neighbours:
56
! -----------------------------------------------------
57
TYPE toSend_t
58
INTEGER :: n
59
REAL(KIND=dp), ALLOCATABLE :: buf(:)
60
INTEGER, ALLOCATABLE :: ifg(:), perm(:)
61
END TYPE toSend_t
62
63
! Communication buffer stuff we receive from our neighbours:
64
! ----------------------------------------------------------
65
TYPE toReceive_t
66
INTEGER :: n
67
INTEGER, ALLOCATABLE :: perm(:)
68
REAL(KIND=dp), ALLOCATABLE :: buf(:)
69
END TYPE toReceive_t
70
71
! The connectivity matrix 'B':
72
! ----------------------------
73
TYPE(Matrix_t), POINTER, SAVE :: Bmat=>Null()
74
75
! the null space or kernel of the input system A, also called
76
! R in the relevant FETI literature:
77
! ------------------------------------------------------------
78
INTEGER, PRIVATE, SAVE :: nz
79
INTEGER, PRIVATE, PARAMETER :: maxnz=20
80
REAL(KIND=dp), ALLOCATABLE, SAVE, PRIVATE ::z(:,:)
81
82
! Neighbour identification, local and global numbering of
83
! neighbour PEs:
84
! -------------------------------------------------------
85
INTEGER, PRIVATE, SAVE :: nneigh, FixInds(maxnz)
86
INTEGER, ALLOCATABLE, PRIVATE, SAVE :: lpnum(:), gpnum(:)
87
88
! Some global flags:
89
! ------------------
90
LOGICAL, PRIVATE, SAVE :: Precondition=.FALSE., TotalFETI=.FALSE., NullSpaceLC=.TRUE.,&
91
dumptofiles=.FALSE.
92
LOGICAL, PRIVATE, SAVE :: InitializeIf, InitializeLC, CPG, Refactorize, FetiAsPrec=.FALSE.
93
94
LOGICAL, ALLOCATABLE, PRIVATE, SAVE :: DirichletDOFs(:)
95
96
integer,allocatable::snd(:),asize(:),bsize(:),cnt(:),gbuf(:,:),ibuf(:,:)
97
integer::ierr,me,abeg,bbeg
98
integer::status(MPI_STATUS_SIZE)
99
100
#include "huti_fdefs.h"
101
102
CONTAINS
103
104
!> Send given buffer to given neighbour, either 'tags' in 'ifg'
105
!> (when initializing) or the interface values in 'buf':
106
! ------------------------------------------------------------
107
!------------------------------------------------------------------------------
108
SUBROUTINE FetiSend(proc, nin, buf, ifg, tag)
109
!------------------------------------------------------------------------------
110
INTEGER, OPTIONAL :: tag,ifg(:)
111
INTEGER :: proc, nin
112
REAL(KIND=dp), OPTIONAL :: buf(:)
113
!------------------------------------------------------------------------------
114
INTEGER :: ierr, zcnt, n
115
!------------------------------------------------------------------------------
116
n = nin
117
IF (PRESENT(buf).AND.n>0) THEN
118
zcnt=COUNT(buf(1:n)==0)
119
IF (zcnt==n) n=0
120
END IF
121
122
CALL MPI_BSEND( n, 1, MPI_INTEGER, &
123
proc, tag, ELMER_COMM_WORLD, ierr )
124
125
IF (n>0) THEN
126
IF (PRESENT(buf)) THEN
127
CALL MPI_BSEND( buf, n, MPI_DOUBLE_PRECISION, &
128
proc, tag+1, ELMER_COMM_WORLD, ierr )
129
END IF
130
131
IF (PRESENT(ifg)) THEN
132
CALL MPI_BSEND( ifg, n, MPI_INTEGER, &
133
proc, tag+2, ELMER_COMM_WORLD, ierr )
134
END IF
135
END IF
136
!------------------------------------------------------------------------------
137
END SUBROUTINE FetiSend
138
!------------------------------------------------------------------------------
139
140
141
!> Receive given buffer from a neighbour, either 'tags' to 'ifg'
142
!> (when initializing) or the interface values to 'buf', the id
143
!> of the sender returned in 'proc':
144
! ---------------------------------------------------------------
145
!------------------------------------------------------------------------------
146
SUBROUTINE FetiRecv(proc, n, buf, ifg, tag)
147
!------------------------------------------------------------------------------
148
INTEGER, OPTIONAL, ALLOCATABLE :: ifg(:)
149
INTEGER :: proc, n, tag
150
REAL(KIND=dp), OPTIONAL :: buf(:)
151
!------------------------------------------------------------------------------
152
INTEGER :: status(MPI_STATUS_SIZE)=0, ierr=0
153
!------------------------------------------------------------------------------
154
CALL MPI_RECV( n, 1, MPI_INTEGER, MPI_ANY_SOURCE, &
155
tag, ELMER_COMM_WORLD, status, ierr )
156
proc = status(MPI_SOURCE)
157
158
IF (n>0) THEN
159
IF (PRESENT(buf)) THEN
160
CALL MPI_RECV( buf, n, MPI_DOUBLE_PRECISION, proc, &
161
tag+1, ELMER_COMM_WORLD, status, ierr )
162
END IF
163
164
IF (PRESENT(ifg)) THEN
165
IF ( ALLOCATED(ifg) ) THEN
166
IF (SIZE(ifg)<n) DEALLOCATE(ifg)
167
END IF
168
IF ( .NOT. ALLOCATED(ifg)) ALLOCATE(ifg(n))
169
CALL MPI_RECV( ifg, n, MPI_INTEGER, proc, &
170
tag+2, ELMER_COMM_WORLD, status, ierr )
171
END IF
172
END IF
173
!------------------------------------------------------------------------------
174
END SUBROUTINE FetiRecv
175
!------------------------------------------------------------------------------
176
177
178
! Identify neighbour partitions:
179
! ------------------------------
180
!------------------------------------------------------------------------------
181
SUBROUTINE FetiGetNeighbours()
182
!------------------------------------------------------------------------------
183
INTEGER :: i
184
!------------------------------------------------------------------------------
185
IF ( ALLOCATED(gpnum) ) DEALLOCATE(gpnum)
186
IF ( ALLOCATED(lpnum) ) DEALLOCATE(lpnum)
187
188
ALLOCATE(gpnum(ParEnv % NumOfNeighbours),lpnum(0:ParEnv % PEs-1))
189
lpnum = 0; nneigh = 0
190
191
DO i=0,ParEnv % PEs-1
192
IF (ParEnv % IsNeighbour(i+1) .AND. ParEnv % Active(i+1)) THEN
193
nneigh=nneigh+1
194
lpnum(i) = nneigh
195
gpnum(nneigh) = i
196
END IF
197
END DO
198
!------------------------------------------------------------------------------
199
END SUBROUTINE FetiGetNeighbours
200
!------------------------------------------------------------------------------
201
202
203
!> First time communication with all neighbours where local
204
!> addresses of global tags are identified:
205
! --------------------------------------------------------
206
!------------------------------------------------------------------------------
207
SUBROUTINE FetiSendReceiveInit(sndLC, gdofs, ldofs, &
208
procs, toSend, toReceive, tag)
209
!------------------------------------------------------------------------------
210
INTEGER :: sndLC, tag, gdofs(:), ldofs(:), procs(:)
211
TYPE(toSend_t) :: toSend(:)
212
TYPE(toReceive_t) :: toReceive(:)
213
!------------------------------------------------------------------------------
214
INTEGER :: i,j,k,l,n,m,proc,lproc
215
LOGICAL :: Found
216
INTEGER, ALLOCATABLE :: gorder(:), igorder(:), ifg(:)
217
!------------------------------------------------------------------------------
218
DO i=1,nneigh
219
proc = gpnum(i)
220
CALL FetiSend(proc, toSend(i) % n, ifg=toSend(i) % ifg, tag=tag)
221
END DO
222
223
! Receive interface parts and store indices
224
! -----------------------------------------
225
ALLOCATE(gorder(sndLC), igorder(sndLC), ifg(sndLC))
226
gorder=[(i,i=1,sndLC)]
227
CALL SortI(sndLC, gdofs, gorder)
228
igorder(gorder)=[(i,i=1,sndLC)]
229
230
DO i=1,nneigh
231
CALL FetiRecv(proc, n, ifg=ifg, tag=tag)
232
233
lproc=lpnum(proc)
234
toReceive(lproc) % n = n
235
ALLOCATE(toReceive(lproc) % perm(n))
236
237
IF (n<=0) CYCLE
238
toReceive(lproc) % perm=0
239
DO j=1,n
240
k=SearchIAItem(sndLC,gdofs,ifg(j),gorder)
241
IF ( k<=0 ) THEN
242
PRINT*,'should not happen: ', parenv % mype, proc, ifg(j)
243
CYCLE
244
END IF
245
246
IF (proc/=procs(k)) THEN
247
248
! Account for multiple global dof tags in gdofs; they should
249
! be adjacent in the original order too:
250
! ----------------------------------------------------------
251
Found=.FALSE.
252
DO l=k+1,sndLC
253
m = igorder(l)
254
IF ( gdofs(m)/=ifg(j) ) EXIT
255
IF ( proc==procs(l) ) THEN
256
Found=.TRUE.; EXIT
257
END IF
258
END DO
259
260
IF (.NOT.Found) THEN
261
DO l=k-1,1,-1
262
m = igorder(l)
263
IF ( gdofs(m)/=ifg(j) ) EXIT
264
IF ( proc==procs(l) ) THEN
265
Found=.TRUE.; EXIT
266
END IF
267
END DO
268
IF (.NOT.Found) CYCLE
269
END IF
270
ELSE
271
l=k
272
END IF
273
toReceive(lproc) % perm(j)=ldofs(l)
274
END DO
275
END DO
276
!------------------------------------------------------------------------------
277
END SUBROUTINE FetiSendReceiveInit
278
!------------------------------------------------------------------------------
279
280
281
!> The neighbour send/receive communication, after initializations.
282
! ----------------------------------------------------------------
283
!------------------------------------------------------------------------------
284
SUBROUTINE FetiSendReceive(toSend, toReceive, tag, Fsum)
285
!------------------------------------------------------------------------------
286
REAL(KIND=dp), OPTIONAL :: Fsum(:)
287
INTEGER :: tag
288
TYPE(toSend_t) :: toSend(:)
289
TYPE(toReceive_t) :: toReceive(:)
290
!------------------------------------------------------------------------------
291
INTEGER :: i,j,k,l,n,m,proc, lproc
292
LOGICAL :: Found
293
REAL(KIND=dp), ALLOCATABLE :: buf(:)
294
!------------------------------------------------------------------------------
295
DO i=1,nneigh
296
proc = gpnum(i)
297
CALL FetiSend(proc, toSend(i) % n, toSend(i) % buf, tag=tag)
298
END DO
299
300
! Receive interface parts and sum values
301
! --------------------------------------
302
n = 0
303
DO i=1,nneigh
304
n=MAX(n,toReceive(i) % n)
305
END DO
306
ALLOCATE(buf(n))
307
308
DO i=1,nneigh
309
CALL FetiRecv(proc, n, buf, tag=tag)
310
lproc=lpnum(proc)
311
312
IF (.NOT.PRESENT(Fsum)) THEN
313
IF(.NOT.ALLOCATED(toReceive(lproc) % buf)) THEN
314
ALLOCATE(toReceive(lproc) % buf(Bmat % NumberOfRows))
315
END IF
316
toReceive(lproc) % buf=0._dp
317
END IF
318
319
DO j=1,n
320
l=toReceive(lproc) % perm(j)
321
IF (l>0) THEN
322
IF (PRESENT(Fsum)) THEN
323
Fsum(l)=Fsum(l)+buf(j)
324
ELSE
325
toReceive(lproc) % buf(l)=buf(j)
326
END IF
327
END IF
328
END DO
329
END DO
330
!------------------------------------------------------------------------------
331
END SUBROUTINE FetiSendReceive
332
!------------------------------------------------------------------------------
333
334
335
!------------------------------------------------------------------------------
336
!
337
!> Given local (owned L.C.'s) interface vector b, send and receive
338
!> all partition interface L.C's to/from neighbours. Place result
339
!> to partitionwise vector f. In effect f=B^Tb.
340
! ---------------------------------------------------------------
341
SUBROUTINE FetiSendRecvLC(A,f,b)
342
!------------------------------------------------------------------------------
343
IMPLICIT NONE
344
TYPE(Matrix_t) :: A
345
REAL(KIND=dp) :: f(:),b(:)
346
!------------------------------------------------------------------------------
347
INTEGER :: i,j,k,l,p,q,m,n,sz,nrows,proc,lproc
348
INTEGER :: sndLC, ownLC
349
LOGICAL :: Found
350
INTEGER, POINTER :: gtags(:)
351
LOGICAL, POINTER :: ig(:)
352
TYPE(NeighbourList_t), POINTER :: nb(:)
353
INTEGER, ALLOCATABLE :: gdofs(:), ldofs(:), procs(:)
354
355
REAL(KIND=dp) :: val
356
357
TYPE(toReceive_t), ALLOCATABLE, SAVE :: toReceive(:)
358
TYPE(toSend_t), ALLOCATABLE, SAVE :: toSend(:)
359
INTEGER, SAVE :: ninterface
360
INTEGER, ALLOCATABLE, SAVE :: lint(:)
361
!------------------------------------------------------------------------------
362
363
nrows = A % NumberOfRows
364
gtags => A % ParallelInfo % GlobalDofs
365
ig => A % ParallelInfo % GInterface
366
nb => A % ParallelInfo % NeighbourList
367
368
IF ( InitializeLC .OR. .NOT. ALLOCATED(toSend)) THEN
369
370
IF ( ALLOCATED(toSend) ) THEN
371
DO i=1,SIZE(toSend)
372
DEALLOCATE(toSend(i) % buf, toSend(i) % ifg, &
373
toSend(i) % perm, toReceive(i) % perm)
374
END DO
375
DEALLOCATE(toSend,toReceive,lint)
376
END IF
377
378
! Count sizes of send & receive buffers:
379
! --------------------------------------
380
ALLOCATE(toSend(nneigh),toReceive(nneigh))
381
382
ninterface=COUNT(ig)
383
ALLOCATE(lint(ninterface))
384
385
ninterface = 0
386
sndLC=0
387
toSend(:) % n=0
388
DO i=1,nrows
389
IF (ig(i).AND..NOT.DirichletDOFs(i)) THEN
390
ninterface=ninterface+1
391
lint(ninterface)=i
392
sz = SIZE(nb(i) % Neighbours)
393
proc=nb(i) % Neighbours(1)
394
IF (proc == ParEnv % myPE ) THEN
395
DO j=2,sz
396
lproc=lpnum(nb(i) % Neighbours(j))
397
toSend(lproc) % n = toSend(lproc) % n+1
398
END DO
399
ELSE
400
sndLC = sndLC+1
401
END IF
402
END IF
403
END DO
404
405
! Allocate send & receive buffers:
406
! --------------------------------------
407
DO i=1,nneigh
408
j=toSend(i) % n
409
ALLOCATE(toSend(i) % buf(j),toSend(i) % ifg(j), &
410
toSend(i) % perm(ninterface))
411
toSend(i) % perm=0
412
END DO
413
ALLOCATE(gdofs(sndLC), ldofs(sndLC), procs(sndLC))
414
415
! Extract send & receive dof tags:
416
! --------------------------------
417
sndLC=0
418
toSend(:) % n=0
419
DO i=1,ninterface
420
l = lint(i)
421
proc = nb(l) % Neighbours(1)
422
IF (proc == ParEnv % myPE ) THEN
423
sz = SIZE(nb(l) % Neighbours)
424
DO j=2,sz
425
lproc=lpnum(nb(l) % Neighbours(j))
426
k = toSend(lproc) % n+1
427
toSend(lproc) % perm(i) = k
428
toSend(lproc) % n = k
429
toSend(lproc) % ifg(k) = gtags(l)
430
END DO
431
ELSE
432
sndLC = sndLC+1
433
ldofs(sndLC) = l
434
procs(sndLC) = proc
435
gdofs(sndLC) = gtags(l)
436
END IF
437
END DO
438
439
! Send interface parts to neighbours, at initialization
440
! only store local indices of global tags
441
! ------------------------------------------------------
442
CALL FetiSendReceiveInit( sndLC, gdofs, ldofs, procs, &
443
toSend, toReceive, tag=100 )
444
445
DEALLOCATE(gdofs,ldofs,procs)
446
InitializeLC = .FALSE.
447
END IF
448
449
! Extract send & receive dof values of f=B^Tb
450
! -------------------------------------------
451
F = 0._dp
452
DO lproc=1,nneigh
453
toSend(lproc) % buf = 0._dp
454
END DO
455
456
DO i=1,Bmat % NumberOfRows
457
l = Bmat % Perm(i)
458
459
IF (l>0) THEN ! partition DOF number
460
m = lint(l) ! on interface
461
ELSE
462
m = -l ! internal D.B.C.
463
END IF
464
465
DO j=Bmat % Rows(i),Bmat % Rows(i+1)-1
466
val = Bmat % Values(j) * b(i)
467
IF ( Bmat % Cols(j) == ParEnv % MyPE ) THEN
468
F(m) = F(m) + val
469
ELSE IF ( l<=SIZE(lint)) THEN
470
! fill send buffer position of LC for DOF l (or m):
471
! -------------------------------------------------
472
lproc = lpnum(Bmat % Cols(j))
473
k = toSend(lproc) % perm(l)
474
toSend(lproc) % buf(k) = toSend(lproc) % buf(k)+val
475
END IF
476
END DO
477
END DO
478
479
! Send & reiceive interface parts to neighbours
480
! ------------------------------------
481
CALL FetiSendReceive(toSend, toReceive, tag=110, Fsum=F)
482
483
484
!------------------------------------------------------------------------------
485
END SUBROUTINE FetiSendRecvLC
486
!------------------------------------------------------------------------------
487
488
489
!------------------------------------------------------------------------------
490
!> Add Dirichlet BCs to set of Lagrange coefficients described by the 'B' matrix
491
!> (the total FETI scheme).
492
!
493
! Some thoughts:
494
!
495
! Trouble here is that in Elmer the Dirichlet BCs can be really varied and may,
496
! for example, include a (large) number of domain internal DOFs. Also, at first
497
! thought, P-elements with nontrivial Dirichlet BCs don't fit easily into this
498
! scheme as not all the coefficients are known from the input to data directly.
499
! At least you'd need multidof constraints...
500
!
501
! Only most simple cases handled here currently, should call DefaultDirichletBCs()
502
! eventually to take care of more details. Even then the Robin type of conditions
503
! would not be handled. Actually seems quite hard to ensure all 'floating' domains
504
! at all times.
505
!------------------------------------------------------------------------------
506
SUBROUTINE FetiAddDtoB(A, B, nLC)
507
!------------------------------------------------------------------------------
508
INTEGER :: nLC
509
TYPe(Matrix_t) :: A
510
TYPe(Matrix_t), POINTER :: B
511
!------------------------------------------------------------------------------
512
TYPE(Solver_t), POINTER :: Solver
513
INTEGER :: i,j,k,l,n,d,Active
514
INTEGER, ALLOCATABLE :: Perm(:), InEqualityFlag(:)
515
INTEGER, POINTER :: p(:)
516
LOGICAL :: Found,FoundUpper,FoundLower
517
LOGICAL, ALLOCATABLE :: Done(:)
518
REAL(KIND=dp) :: val,scale
519
REAL(KIND=dp), ALLOCATABLE :: Vals(:)
520
TYPE(ValueList_t), POINTER :: BC
521
TYPE(Element_t), POINTER :: Element
522
!------------------------------------------------------------------------------
523
Solver => GetSolver()
524
525
n = A % NumberOfRows
526
527
ALLOCATE(Perm(n),InEqualityFlag(n), B % RHS(n))
528
B % RHS=0._dp
529
Perm(1:nLC) = B % Perm
530
InEqualityFlag(1:nLC) = 0
531
532
IF (FetiAsPrec) THEN
533
DO i=1,n
534
IF ( DirichletDofs(i) ) THEN
535
nLC = nLC+1
536
Perm(nLC) = -i
537
B % RHS(nLC) = A % RHS(i)
538
CALL SetMatrixElement(B, nLC, ParEnv % myPE, 1._dp)
539
END IF
540
END DO
541
ELSE
542
d = Solver % Variable % DOFs
543
p => Solver % Variable % Perm
544
545
ALLOCATE(Vals(Solver % Mesh % MaxElementNodes), Done(n))
546
Done = .FALSE.
547
548
Active = GetNOFBoundaryElements()
549
DO i=1,Active
550
Element => GetBoundaryElement(i)
551
BC => GetBC()
552
553
IF (.NOT.ASSOCIATED(BC)) CYCLE
554
IF (.NOT. ActiveBoundaryElement()) CYCLE
555
556
n = GetElementNOFNodes()
557
DO j=1,d
558
IF (d>1) THEN
559
Vals(1:n)=GetReal(BC,ComponentName(Solver % Variable,j),Found)
560
ELSE
561
Vals(1:n)=GetReal(BC,Solver % Variable % Name,Found)
562
END IF
563
564
FoundUpper=.FALSE.
565
FoundLower=.FALSE.
566
IF(.NOT.Found) THEN
567
IF (d>1) THEN
568
Vals(1:n)=GetReal(BC,TRIM(ComponentName(Solver % Variable,j))//' Upper Limit',FoundUpper)
569
ELSE
570
Vals(1:n)=GetReal(BC,TRIM(Solver % Variable % Name)//' Upper Limit',FoundUpper)
571
END IF
572
573
IF(.NOT.FoundUpper) THEN
574
IF (d>1) THEN
575
Vals(1:n)=GetReal(BC,TRIM(ComponentName(Solver % Variable,j))//' Lower Limit',FoundLower)
576
ELSE
577
Vals(1:n)=GetReal(BC,TRIM(Solver % Variable % Name)//' Lower Limit',FoundLower)
578
END IF
579
END IF
580
END IF
581
582
IF (.NOT.(Found.OR.FoundUpper.OR.FoundLower)) CYCLE
583
584
DO k=1,n
585
l = p(Element % NodeIndexes(k))
586
IF (l<=0) CYCLE
587
588
l=d*(l-1)+j
589
IF(Done(l)) CYCLE
590
591
nLC = nLC+1
592
Done(l)=.TRUE.
593
594
! - sign here to indicate D-condition instead of interface
595
! compatibility conditions...:
596
! --------------------------------------------------------
597
Perm(nLC)=-l
598
IF(FoundUpper.OR.FoundLower) InEqualityFlag(nLC)=1
599
scale=1._dp
600
IF(FoundLower) THEN
601
scale = -1._dp
602
Vals(k)=-Vals(k)
603
END IF
604
605
IF (ASSOCIATED(A % DiagScaling)) THEN
606
B % RHS(nLC) = Vals(k)/A % DiagScaling(l)
607
CALL SetMatrixElement(B, nLC, ParEnv % myPE, scale)
608
ELSE
609
B % RHS(nLC) = Vals(k)
610
CALL SetMatrixElement(B, nLC, ParEnv % myPE, scale)
611
END IF
612
END DO
613
END DO
614
END DO
615
END IF
616
617
DEALLOCATE(B % Perm)
618
ALLOCATE(B % Perm(nLC), B % InvPerm(nLC))
619
B % Perm = Perm(1:nLC)
620
B % InvPerm = InEqualityFlag(1:nLC)
621
!------------------------------------------------------------------------------
622
END SUBROUTINE FetiAddDtoB
623
!------------------------------------------------------------------------------
624
625
626
!------------------------------------------------------------------------------
627
!> Extract interface values from partition vector b; send and
628
!> receive to/from neighbours. Only 'owned' interface dofs
629
!> placed to result vector f. At initialization also assemble
630
!> the 'B' connectivity matrix. In effect f=Bb;
631
!------------------------------------------------------------------------------
632
FUNCTION FetiSendRecvIf(A,f,b,g,l_i) RESULT(nLC)
633
! ----------------------------------------------------------
634
IMPLICIT NONE
635
TYPE(Matrix_t) :: A
636
INTEGER :: nLC
637
REAL(KIND=dp) :: f(:),b(:)
638
639
integer,optional :: l_i(0:)
640
real(kind=dp),optional :: g(:,:)
641
!------------------------------------------------------------------------------
642
INTEGER :: i,j,k,l,m,p,q,n,sz,nrows,proc,lproc,totnLC=0
643
TYPE(NeighbourList_t), POINTER :: nb(:)
644
LOGICAL :: Found, Own
645
INTEGER, POINTER :: gtags(:)
646
LOGICAL, POINTER :: ig(:)
647
INTEGER, ALLOCATABLE :: gdofs(:), ldofs(:), procs(:)
648
649
REAL(KIND=dp) :: val
650
REAL(KIND=dp), POINTER :: Fn(:)
651
652
TYPE(toSend_t), ALLOCATABLE, SAVE :: toSend(:)
653
INTEGER, SAVE :: ninterface
654
INTEGER, ALLOCATABLE, SAVE :: lint(:)
655
TYPE(toReceive_t), ALLOCATABLE, TARGET, SAVE :: toReceive(:)
656
!------------------------------------------------------------------------------
657
658
nrows = A % NumberOfRows
659
gtags => A % ParallelInfo % GlobalDofs
660
ig => A % ParallelInfo % GInterface
661
nb => A % ParallelInfo % NeighbourList
662
663
IF (InitializeIf .OR. .NOT. ALLOCATED(toSend) ) THEN
664
665
IF ( ALLOCATED(toSend) )THEN
666
DO i=1,SIZE(toSend)
667
DEALLOCATE(toSend(i) % buf, toSend(i) % ifg, toReceive(i) % perm)
668
IF (ALLOCATED(toReceive(i) % buf)) DEALLOCATE(toReceive(i) % buf)
669
END DO
670
DEALLOCATE(toSend,toReceive,lint)
671
END IF
672
ALLOCATE(toSend(nneigh),toReceive(nneigh))
673
674
ninterface=COUNT(ig)
675
ALLOCATE(lint(ninterface))
676
677
! Count sizes of send & receive buffers:
678
! --------------------------------------
679
ninterface=0
680
nLC=0
681
toSend(:) % n=0
682
DO i=1,nrows
683
IF (ig(i) .AND..NOT.DirichletDOFs(i)) THEN
684
ninterface=ninterface+1
685
lint(ninterface)=i
686
687
proc=nb(i) % Neighbours(1)
688
IF (proc == ParEnv % myPE ) THEN
689
nLC=nLC+SIZE(nb(i) % Neighbours)-1
690
ELSE
691
lproc=lpnum(proc)
692
toSend(lproc) % n = toSend(lproc) % n+1
693
END IF
694
END IF
695
END DO
696
697
! Allocate send & receive buffers:
698
! --------------------------------------
699
DO i=1,nneigh
700
j=toSend(i) % n
701
ALLOCATE(toSend(i) % buf(j), toSend(i) % ifg(j) )
702
END DO
703
ALLOCATE( gdofs(nLC), ldofs(nLC), procs(nLC) )
704
ldofs = [(i,i=1,nLC)];
705
706
! Extract send & receive dof tags; Allocate, initialize
707
! and assemble the 'B' connectivity matrix:
708
! -----------------------------------------------------
709
710
IF (ASSOCIATED(Bmat)) CALL FreeMatrix(Bmat)
711
Bmat => AllocateMatrix()
712
Bmat % ListMatrix => Null()
713
ALLOCATE(Bmat % Perm(nLC))
714
Bmat % Format = MATRIX_LIST
715
716
nLC=0
717
toSend(:) % n=0
718
DO i=1,ninterface
719
l = lint(i)
720
proc = nb(l) % Neighbours(1)
721
IF (proc == ParEnv % myPE) THEN
722
sz = SIZE(nb(l) % Neighbours)
723
DO j=1,sz-1
724
nLC = nLC+1
725
gdofs(nLC) = gtags(l)
726
procs(nLC) = nb(l) % Neighbours(j+1)
727
728
! Assemble the 'B' matrix, orthogonal connectivity for
729
! multiple sharings:
730
! u_2 = u_1,
731
! u_3 = (u_1+u_2)/2,
732
! u_4 = (u_1+u_2+u_3)/3
733
! ....
734
! (also normalized below...)
735
! -----------------------------------------------------
736
Bmat % Perm(nLC) = i
737
val = 1._dp/(j*SQRT(1+1._dp/j))
738
DO m=1,j
739
proc = nb(l) % Neighbours(m)
740
CALL SetMatrixElement(Bmat,nLC,proc,val)
741
END DO
742
proc = nb(l) % Neighbours(j+1)
743
CALL SetMatrixElement(Bmat,nLC,proc,-j*val)
744
745
! proc = nb(l) % Neighbours(1)
746
! CALL SetMatrixElement(Bmat,nLC,proc,1._dp)
747
! proc = nb(l) % Neighbours(j+1)
748
! CALL SetMatrixElement(Bmat,nLC,proc,-1._dp)
749
750
END DO
751
ELSE
752
lproc = lpnum(proc)
753
k = toSend(lproc) % n+1
754
toSend(lproc) % n = k
755
toSend(lproc) % ifg(k) = gtags(l)
756
END IF
757
END DO
758
759
! Send interface parts to neighbours
760
! ------------------------------------
761
CALL FetiSendReceiveInit( nLC, gdofs, ldofs, procs, &
762
toSend, toReceive, tag=200 )
763
764
! If 'Total' FETI add D-conditions to 'B':
765
! ----------------------------------------
766
totnLC=nLC
767
IF (TotalFeti) CALL FetiAddDtoB(A, Bmat, totNLC)
768
769
! Convert 'B' to CRS format:
770
! --------------------------
771
CALL List_ToCRSMatrix(Bmat)
772
773
774
DEALLOCATE(gdofs,ldofs,procs)
775
InitializeIf = .FALSE.
776
IF(dumptofiles) THEN
777
CALL SaveB(A,ninterface,lint)
778
RETURN
779
END IF
780
END IF
781
!------------------------------------------------------------------------------
782
783
784
! Extract send & receive dof values:
785
! ----------------------------------
786
toSend(:) % n=0
787
DO i=1,ninterface
788
l = lint(i)
789
proc = nb(l) % Neighbours(1)
790
IF (proc /= ParEnv % myPE ) THEN
791
lproc=lpnum(proc)
792
k = toSend(lproc) % n+1
793
toSend(lproc) % n = k
794
toSend(lproc) % buf(k) = b(l)
795
END IF
796
END DO
797
798
! Send & reiceive interface parts to neighbours
799
! ---------------------------------------------
800
CALL FetiSendReceive(toSend, toReceive, tag=210)
801
802
F = 0._dp
803
804
! Local contribution to f=Bb
805
! --------------------------
806
DO i=1,Bmat % NumberOfRows
807
l = Bmat % Perm(i)
808
IF (l>0) THEN ! m = Partition DOF number...
809
m = lint(l) ! ...for an interface DOF
810
ELSE
811
m = -l ! ...for a Dirichlet DOF
812
END IF
813
814
DO j=Bmat % Rows(i), Bmat % Rows(i+1)-1
815
IF (Bmat % Cols(j)==ParEnv % myPE) THEN
816
if (present(g)) then
817
! store the B_me*R_me for G'G assembly,
818
! if requested:
819
! --------------------------------------
820
if ( l_i(0)>0 ) &
821
g(i,l_i(0))=g(i,l_i(0))+Bmat%values(j)*b(m)
822
end if
823
F(i) = F(i) + Bmat % Values(j)*b(m); EXIT
824
END IF
825
END DO
826
END DO
827
828
829
! Neighbours contribution to f=Bb (this surely
830
! could be simplified....):
831
! ---------------------------------------------
832
DO lproc=1,nneigh
833
Fn => toReceive(lproc) % buf
834
nLC=0
835
DO i=1,ninterface
836
l = lint(i)
837
proc = nb(l) % Neighbours(1)
838
IF (proc == ParEnv % myPE ) THEN
839
q=nLC
840
sz=SIZE(nb(l) % Neighbours)
841
DO j=1,sz-1
842
nLC = nLC+1
843
IF (Fn(nLC)==0) CYCLE
844
DO m=1,sz-1
845
DO k=Bmat % Rows(q+m),Bmat % Rows(q+m+1)-1
846
IF (Bmat % Cols(k)==gpnum(lproc)) THEN
847
if(present(g)) then
848
! store the B_lproc*R_lproc for G'G assembly,
849
! if requested:
850
! --------------------------------------------
851
if ( l_i(lproc)>0 ) &
852
g(q+m,l_i(lproc))=g(q+m,l_i(lproc))+Bmat%values(k)*Fn(nLC)
853
end if
854
F(q+m) = F(q+m) + Bmat % Values(k)*Fn(nLC); EXIT
855
END IF
856
END DO
857
END DO
858
END DO
859
END IF
860
END DO
861
END DO
862
nLC = totnLC
863
!------------------------------------------------------------------------------
864
END FUNCTION FetiSendRecvIf
865
!------------------------------------------------------------------------------
866
867
868
!------------------------------------------------------------------------------
869
!> The projection of the vector T to the set of feasible solutions
870
!> orthogonal to the null space of A, defined by the condition:
871
!> z^T(f-B^T\lambda) (OP=0, 'z' a.k.a. 'R'). Also handle the initial
872
!> guess and the final extraction of the L.C.'s \alpha related to the
873
!> above condition (OP=1,2).
874
!------------------------------------------------------------------------------
875
SUBROUTINE FetiProject(A,n,T,OP,TOL)
876
!------------------------------------------------------------------------------
877
INTEGER :: n, &
878
OP !=0: T = (I-G*Ginv*G')T,
879
!=1: T = -(G*Ginv*G') T, note: input size: nz
880
!=2: T = (Ginv*G')T, note: output size: nz
881
! Ginv = (G'*G)^-1
882
REAL(KIND=dp) :: TOL
883
REAL(KIND=dp)::T(n)
884
TYPE(matrix_t) :: A
885
!------------------------------------------------------------------------------
886
REAL(KIND=dp) :: S(n),err1
887
INTEGER :: i,j,k,l,m,nlc,nrows
888
REAL(KIND=dp),ALLOCATABLE :: x(:),b(:),P(:),Q(:)
889
!------------------------------------------------------------------------------
890
integer :: ierr,stat(mpi_status_size),l_n,g_n, &
891
n_nbr,comm,i_type,d_type,me,mactive,maxnz,proc
892
logical :: iterative, found
893
integer,allocatable :: l_nz(:),g_nz(:),gg_nz(:),l_i(:),g_i(:),l_nbr(:)
894
real(kind=dp), allocatable :: l_g(:,:),l_gtg(:,:),g_x(:),g_b(:),g_gtg(:,:)
895
896
type(matrix_t), pointer :: gtg_m => null()
897
898
integer,save :: size, mygroup, grpsize, subsize, comm_group,solv_group,solv_comm,ir=0
899
integer, allocatable, save :: ranks(:,:),subsizes(:)
900
901
save :: g_nz,gg_nz,g_i,gtg_m,g_gtg,g_n,g_x,g_b,me,mactive
902
!------------------------------------------------------------------------------
903
!!call resettimer('project')
904
905
maxnz = parallelreduction(nz,2)
906
907
! check whether anything to do:
908
! -----------------------------
909
if (maxnz<=0) then
910
if (op==2) t=0
911
return
912
end if
913
914
CALL ListPushNameSpace('feti proj:')
915
916
nrows = A % NumberOfRows
917
ALLOCATE(x(nz),b(nz),P(nrows),Q(nrows));P=0; Q=0
918
919
iterative=getlogical(getsolverparams(), 'Feti CPG Projection Iterative', found)
920
921
if (.not.iterative) then
922
923
comm = a % comm
924
i_type = mpi_integer
925
d_type = mpi_double_precision
926
927
if (refactorize .and. op==1) then
928
!call resettimer('factorize setup')
929
930
do mactive=0,parenv % pes-1
931
if ( parenv % active(mactive+1) ) exit
932
end do
933
me = parenv % mype
934
935
! If not using CG, assemble and factorize the G'G matrix:
936
!
937
! NOTE for further development: Instead of using one task to do the
938
! assembling, factorizing & solving we could use parallel Cholesky
939
! factorization from SCALAPACK or, for example, MUMPS. Should not be
940
! such a big deal. This might be favorable, even necessary, when using
941
! (tens of) thousands of mpi tasks ...
942
! --------------------------------------------------------------------
943
944
! -------------------------------------------------------
945
946
! First get the size of the ker(A_i)'s from the neighbours:
947
! =========================================================
948
do i=1,nneigh
949
call mpi_bsend(nz,1,i_type,gpnum(i),400,comm,ierr)
950
end do
951
952
allocate(l_nz(0:nneigh))
953
do i=1,nneigh
954
call mpi_recv(l_nz(i),1,i_type,gpnum(i),400,comm,stat,ierr)
955
end do
956
l_nz(0)=nz
957
l_n=sum(l_nz)
958
959
! Get the 'G' matrix rows corresponding to our set of interface
960
! conditions (multiply by identity, and assemble the columns):
961
! ================================================================
962
963
! local sequential numbering for the \alpha's,
964
! based on position in the neighbour tables:
965
! ---------------------------------------------
966
if (allocated(g_i)) deallocate(g_i)
967
allocate(l_i(0:nneigh+1),g_i(0:nneigh+1))
968
l_i(0)=1
969
do i=1,nneigh+1
970
l_i(i)=l_i(i-1)+l_nz(i-1)
971
end do
972
g_i=l_i ! g_i used as a temporary below
973
974
! do the assembly of the (local) 'G' matrix:
975
! ------------------------------------------
976
allocate(l_g(n,l_n)); l_g=0
977
if (nz>0) x=0
978
do i=1,maxnz
979
! have we already consumed some set of \alpha's
980
! (own or neighbours)?
981
! ---------------------------------------------
982
do j=0,nneigh
983
if (g_i(j)<=0.or.g_i(j)>=l_i(j+1)) g_i(j)=-1
984
end do
985
986
if (i<=nz) x(i)=1
987
if (nz>0) p=matmul(x,z)
988
if (i<=nz) x(i)=0
989
990
nLC = FetiSendRecvIf(A,S,P,l_g,g_i)
991
g_i = g_i+1
992
993
! Seems necessary to slow some guys down. Note that
994
! everybody needs to iterate the same amount due to
995
! this, hence the overall max for the loopcount
996
! above. Could check if this is really necessary...
997
! well, maybe someone, someday....
998
! --------------------------------------------------
999
call parallelactivebarrier()
1000
end do
1001
deallocate(l_i,l_nz,g_i) !
1002
1003
! form local part of the G'G:
1004
! ============================
1005
allocate(l_gtg(l_n,l_n));l_gtg=0
1006
l_gtg=matmul(transpose(l_g),l_g)
1007
deallocate(l_g)
1008
1009
size = parenv % pes
1010
1011
grpsize=listgetinteger( params, 'Feti Projection Solution Group Size', &
1012
found,minv=1,maxv=size)
1013
if (.not.found) grpsize=1
1014
1015
if(allocated(ranks)) deallocate(ranks,subsizes)
1016
allocate(ranks(grpsize,size/grpsize+1),subsizes(grpsize))
1017
ranks=0;subsizes=0
1018
1019
ir=0
1020
do while(ir<size)
1021
do j=1,grpsize
1022
ir=ir+1
1023
if(ir>size) exit
1024
subsizes(j)=subsizes(j)+1
1025
end do
1026
end do
1027
1028
ir = 0
1029
do i=1,grpsize
1030
do j=1,subsizes(i)
1031
ranks(i,j)=ir
1032
ir = ir+1
1033
end do
1034
end do
1035
1036
mygroup=grpsize
1037
do i=1,grpsize-1
1038
if (me<ranks(i+1,1)) then
1039
mygroup = i
1040
exit
1041
end if
1042
end do
1043
mactive = ranks(mygroup,1)
1044
subsize = subsizes(mygroup)
1045
1046
call mpi_comm_group(comm, comm_group, ierr) ! Extract the original group handle
1047
call mpi_group_incl(comm_group,grpsize,ranks(:,1),solv_group,ierr)
1048
call mpi_comm_create(comm,solv_group,solv_comm,ierr)
1049
1050
1051
! form global G'G:
1052
! =================
1053
1054
do i=1,grpsize
1055
if (ranks(i,1)/=me) &
1056
call mpi_bsend(nz,1,i_type,ranks(i,1),401,comm,ierr)
1057
end do
1058
1059
if (me/=mactive) then
1060
1061
! send local G'G to 'mactive' task:
1062
! ----------------------------------
1063
call mpi_bsend(nneigh,1,i_type,mactive,402,comm,ierr)
1064
call mpi_bsend(gpnum,nneigh,i_type,mactive,403,comm,ierr)
1065
call mpi_bsend(l_gtg,l_n**2,d_type,mactive,404,comm,ierr)
1066
deallocate(l_gtg)
1067
1068
else ! me==mactive
1069
1070
! Assemble whole of the G'G from the parts:
1071
! -----------------------------------------
1072
1073
! get size of all the ker(A_i)'s:
1074
! -------------------------------
1075
if (allocated(g_nz)) deallocate(g_nz)
1076
allocate(g_nz(0:parenv % pes-1)); g_nz=0
1077
g_nz(me)=nz
1078
do i=0,parenv % pes-1
1079
if ( i==me .or. .not. parenv % active(i+1)) cycle
1080
call mpi_recv(g_nz(i),1,i_type,i,401,comm,stat,ierr)
1081
end do
1082
1083
! global sequential numbering for the \alpha's,
1084
! based on task id's:
1085
! ---------------------------------------------
1086
if(allocated(g_i)) deallocate(g_i)
1087
allocate(g_i(0:parenv % pes))
1088
g_i(0)=1
1089
do j=1,parenv % pes
1090
g_i(j)=g_i(j-1)+g_nz(j-1)
1091
end do
1092
g_n=sum(g_nz)
1093
1094
! Get storage for the (global) G'G:
1095
! ---------------------------------
1096
IF (ASSOCIATED(gtg_m)) CALL FreeMatrix(gtg_m)
1097
gtg_m=>AllocateMatrix()
1098
gtg_m % Comm = solv_comm
1099
gtg_m % format = MATRIX_LIST
1100
1101
! Assemble our own part...
1102
! ------------------------
1103
1104
allocate(l_nbr(0:nneigh))
1105
n_nbr=nneigh
1106
l_nbr(0)=me; l_nbr(1:n_nbr)=gpnum(1:n_nbr)
1107
1108
call addtogtg(gtg_m,l_gtg,n_nbr,l_nbr,g_nz,g_i)
1109
deallocate(l_gtg,l_nbr)
1110
1111
! ...and the rest of it:
1112
! ----------------------
1113
do i=1,subsize-1 ! -1 to count 'me' out
1114
call mpi_recv(n_nbr,1,i_type,mpi_any_source,402,comm,stat,ierr)
1115
proc=stat(mpi_source)
1116
1117
allocate(l_nbr(0:n_nbr))
1118
l_nbr(0)=proc
1119
call mpi_recv(l_nbr(1:),n_nbr,i_type,proc,403,comm,stat,ierr)
1120
1121
l_n=sum(g_nz(l_nbr))
1122
allocate(l_gtg(l_n,l_n))
1123
call mpi_recv(l_gtg,l_n**2,d_type,proc,404,comm,stat,ierr)
1124
1125
call addtogtg(gtg_m,l_gtg,n_nbr,l_nbr,g_nz,g_i)
1126
deallocate(l_gtg,l_nbr)
1127
end do
1128
1129
!
1130
! Factorize the G'G, and we are done initializing:
1131
! ------------------------------------------------
1132
call list_tocrsmatrix(gtg_m)
1133
1134
g_n=gtg_m % numberofrows
1135
allocate(g_x(g_n),g_b(g_n)); g_x=0; g_b=0
1136
1137
end if ! task 'mactive' doing the factoring (and later, solving)
1138
!call checktimer('factorize setup',delete=.true.)
1139
end if ! the first time G'G assembly and factorizing
1140
end if ! direct solver setup
1141
1142
IF (OP==1) THEN
1143
IF (nz>0) b=T(1:nz)
1144
ELSE
1145
CALL Gt(b,T)
1146
END IF
1147
1148
!
1149
! Solve x from G'Gx = b:
1150
! -----------------------
1151
if (iterative) then
1152
IF (nz>0) x=b
1153
CALL FCG(nz,x,b)
1154
else
1155
1156
!call resettimer('coarse prob')
1157
if (me==mactive) then
1158
1159
! assemble the r.h.s. vector:
1160
! ---------------------------
1161
1162
if (nz>0) g_b(g_i(me):g_i(me+1)-1) = b
1163
do i=2,subsize
1164
j=ranks(mygroup,i)
1165
if (g_nz(j)>0) &
1166
call mpi_recv(g_b(g_i(j):g_i(j+1)-1), g_nz(j), &
1167
d_type,j,405,comm,stat,ierr)
1168
end do
1169
1170
! solve x:
1171
! --------
1172
call directsolver(gtg_m,g_x,g_b,getsolver())
1173
1174
! distribute the result:
1175
! ----------------------
1176
do i=2,subsize
1177
j=ranks(mygroup,i)
1178
if (g_nz(j)>0) &
1179
call mpi_bsend(g_x(g_i(j):g_i(j+1)-1), &
1180
g_nz(j),d_type,j,406,comm,ierr)
1181
end do
1182
1183
! finally my own part:
1184
! --------------------
1185
if (nz>0) x(1:nz)=g_x(g_i(me):g_i(me+1)-1)
1186
else
1187
! send r.h.s.:
1188
! ------------
1189
if (nz>0) &
1190
call mpi_bsend(b,nz,d_type,mactive,405,comm,ierr)
1191
1192
! receive result:
1193
! --------------
1194
if (nz>0) &
1195
call mpi_recv(x,nz,d_type,mactive,406,comm,stat,ierr)
1196
endif
1197
call parallelactivebarrier()
1198
endif
1199
!call checktimer('coarse prob',delete=.true.)
1200
1201
SELECT CASE(OP)
1202
CASE(0)
1203
CALL G(x,S)
1204
T=T-S
1205
CASE(1)
1206
CALL G(x,S)
1207
T=-S
1208
CASE(2)
1209
T(1:nz)=x
1210
CASE DEFAULT
1211
CALL Fatal('Feti Procjection','Unknown projection OP.')
1212
END SELECT
1213
1214
CALL ListPopNameSpace()
1215
!call checktimer('project',delete=.true.)
1216
1217
CONTAINS
1218
1219
!------------------------------------------------------------------------------
1220
subroutine addtogtg(gtg_m,l_gtg,n_nbr,l_nbr,g_nz,g_i)
1221
!------------------------------------------------------------------------------
1222
real(kind=dp) :: l_gtg(:,:)
1223
type(matrix_t), pointer :: gtg_m
1224
integer :: n_nbr, l_nbr(0:), g_nz(0:), g_i(0:)
1225
!------------------------------------------------------------------------------
1226
integer :: i,j,k,l,g_r,g_c,l_r,l_c,l_i(0:n_nbr+1)
1227
!------------------------------------------------------------------------------
1228
l_i(0)=1
1229
do i=1,n_nbr+1
1230
l_i(i)=l_i(i-1)+g_nz(l_nbr(i-1))
1231
end do
1232
1233
do i=0,n_nbr
1234
do k=0,g_nz(l_nbr(i))-1
1235
l_c=l_i(i)+k
1236
g_c=g_i(l_nbr(i))+k
1237
do j=0,n_nbr
1238
do l=0,g_nz(l_nbr(j))-1
1239
l_r=l_i(j)+l
1240
g_r=g_i(l_nbr(j))+l
1241
if (abs(l_gtg(l_r,l_c))>aeps) &
1242
call addtomatrixelement(gtg_m,g_r,g_c,l_gtg(l_r,l_c))
1243
end do
1244
end do
1245
end do
1246
end do
1247
!------------------------------------------------------------------------------
1248
end subroutine addtogtg
1249
!------------------------------------------------------------------------------
1250
1251
1252
!------------------------------------------------------------------------------
1253
SUBROUTINE GtG(u,v)
1254
!------------------------------------------------------------------------------
1255
INTEGER :: nlc
1256
REAL(KIND=dp) :: u(:),v(:)
1257
1258
IF (nz>0) P=MATMUL(u,z)
1259
nlc = FetiSendRecvIf(A,S,P)
1260
1261
CALL FetiSendRecvLC(A,Q,S)
1262
IF (nz>0) v = MATMUL(z,Q)
1263
!------------------------------------------------------------------------------
1264
END SUBROUTINE GtG
1265
!------------------------------------------------------------------------------
1266
1267
1268
!------------------------------------------------------------------------------
1269
SUBROUTINE Gt(v,u)
1270
!------------------------------------------------------------------------------
1271
REAL(KIND=dp) ::v(:),u(:)
1272
1273
CALL FetiSendRecvLC(A,Q,u)
1274
IF (nz>0) v = MATMUL(z,Q)
1275
!------------------------------------------------------------------------------
1276
END SUBROUTINE Gt
1277
!------------------------------------------------------------------------------
1278
1279
1280
!------------------------------------------------------------------------------
1281
SUBROUTINE G(u,v)
1282
!------------------------------------------------------------------------------
1283
REAL(KIND=dp) :: u(:),v(:)
1284
INTEGER :: n
1285
1286
IF (nz>0) P=MATMUL(u,z)
1287
n = FetiSendRecvIf(A,v,P)
1288
!------------------------------------------------------------------------------
1289
END SUBROUTINE G
1290
!------------------------------------------------------------------------------
1291
1292
1293
!------------------------------------------------------------------------------
1294
SUBROUTINE FCG(n,x,b)
1295
!------------------------------------------------------------------------------
1296
INTEGER :: n
1297
REAL(KIND=dp) :: x(:),b(:)
1298
!------------------------------------------------------------------------------
1299
REAL(KIND=dp) :: beta,alpha,rho,prevrho,bnorm,err
1300
INTEGER :: iter
1301
REAL(KIND=dp) :: Ri(n),S(n),T(n)
1302
!------------------------------------------------------------------------------
1303
bnorm = SparNorm(n,b,1)
1304
IF ( bnorm==0 ) THEN
1305
x=0; RETURN;
1306
END IF
1307
1308
CALL GtG(x,T)
1309
Ri = -(T - b)
1310
1311
err = SparNorm(n,Ri,1)
1312
IF (err<TOL) RETURN
1313
1314
beta=0._dp
1315
DO iter=1,500
1316
rho = SparDotProd(n,Ri,1,Ri,1)
1317
IF (iter==1) THEN
1318
S = Ri
1319
ELSE
1320
beta = rho/prevrho
1321
S = Ri + beta*S
1322
END IF
1323
prevrho = rho
1324
1325
CALL GtG(S,T)
1326
alpha = rho/SparDotProd(n,S,1,T,1)
1327
x = x + alpha*S
1328
1329
Ri = Ri - alpha*T
1330
err = SparNorm(n,Ri,1)
1331
IF (err<TOL) EXIT
1332
END DO
1333
IF ( Parenv % MyPE==0 .AND. err>=TOL ) print*,'fcg not converged',err
1334
!------------------------------------------------------------------------------
1335
END SUBROUTINE FCG
1336
!------------------------------------------------------------------------------
1337
!------------------------------------------------------------------------------
1338
END SUBROUTINE FetiProject
1339
!------------------------------------------------------------------------------
1340
1341
1342
!------------------------------------------------------------------------------
1343
!> The C(onjugate) P(rojected) G(radient) iterative solver.
1344
!------------------------------------------------------------------------------
1345
SUBROUTINE FetiCPG(A,n,x,b,f,Solver,matvecsubr,precsubr,dotprodfun,normfun)
1346
!------------------------------------------------------------------------------
1347
TYPE(Solver_t) :: Solver
1348
TYPE(Matrix_t),pointer :: A
1349
INTEGER :: n
1350
REAL(KIND=dp) :: x(:),b(:), f(:),dotprodfun, normfun
1351
1352
EXTERNAL matvecsubr, precsubr, dotprodfun, normfun
1353
!------------------------------------------------------------------------------
1354
INTEGER :: i,j,m,iter,nnz,nLC,nrows,maxit,ipar(50), output,Restart,Saven
1355
REAL(KIND=dp) :: beta,alpha,rho,prevrho,bnorm,err0,err1,err2,TOL,dpar(1)
1356
LOGICAL :: Found,prec
1357
REAL(KIND=dp), ALLOCATABLE :: Ri(:),S(:),T(:),P(:), &
1358
Ssave(:,:), Psave(:,:), srho(:), rr(:)
1359
!------------------------------------------------------------------------------
1360
!call resettimer('cpg')
1361
nrows=A % NumberOfRows
1362
1363
Params => ListGetSolverParams()
1364
output = GetInteger( Params,'Linear System Residual Output', Found )
1365
IF (.NOT. Found ) output = 1
1366
maxit = GetInteger( Params,'Linear System Max Iterations')
1367
Restart = GetInteger( Params,'Linear System CPG Restart', Found)
1368
TOL = GetConstReal( Params,'Linear System Convergence Tolerance')
1369
1370
HUTI_NDIM=n
1371
bnorm = normfun(n,b,1)
1372
IF ( bnorm==0 ) THEN
1373
x=0; RETURN;
1374
END IF
1375
1376
ALLOCATE(T(n),S(n),Ri(n),rr(n))
1377
1378
x=0
1379
IF (nz>0) THEN
1380
m = SIZE(z,2)
1381
x(1:nz)=MATMUL(z,f(1:m))
1382
END IF
1383
CALL FetiProject(A,n,x,OP=1,TOL=1d-12)
1384
1385
CALL matvecsubr(x(1:n),T,ipar)
1386
Ri = -(T - b(1:n))
1387
CALL FetiProject(A,n,Ri,OP=0,TOL=1d-12)
1388
1389
err0 = normfun(n,Ri,1)
1390
err1 = err0 / bnorm
1391
IF ( output /= 0 .AND. ParEnv % MyPE==0 ) THEN
1392
PRINT*,' '
1393
PRINT*,' iter |ax-b| |ax-b|/b';
1394
PRINT*,' --------------------------------------------------';flush(6)
1395
PRINT*,0,err0,err1; Flush(6)
1396
END IF
1397
IF (err1<TOL) RETURN
1398
1399
IF (Restart>0) THEN
1400
Saven=0
1401
ALLOCATE(Ssave(n,Restart), Psave(n,Restart), P(n), srho(Restart))
1402
END IF
1403
1404
beta=0._dp
1405
DO iter=1,maxit
1406
!call resettimer('iter')
1407
IF (Restart>0) P=T
1408
1409
IF (Precondition) THEN
1410
CALL precsubr(T,Ri,ipar)
1411
CALL FetiProject(A,n,T,OP=0,TOL=1d-12)
1412
ELSE
1413
T=Ri
1414
END IF
1415
1416
rho = dotprodfun(n,Ri,1,T,1)
1417
IF ( iter==1 ) THEN
1418
S = T
1419
ELSE
1420
IF (Restart>0) THEN
1421
IF (Saven>=Restart) Saven=0
1422
saven=saven+1
1423
Ssave(:,Saven)=S
1424
Psave(:,Saven)=P
1425
srho(saven)=dotprodfun(n,S,1,P,1)
1426
S=T
1427
DO i=1,Saven
1428
P=Psave(:,i)
1429
beta=dotprodfun(n,T,1,P,1)/srho(i)
1430
S=S-beta*Ssave(:,i)
1431
END DO
1432
ELSE
1433
beta = rho/prevrho
1434
S = T + beta*S
1435
END IF
1436
END IF
1437
prevrho = rho
1438
1439
CALL matvecsubr(S,T,ipar)
1440
alpha = rho / dotprodfun(n,S,1,T,1)
1441
x(1:n) = x(1:n) + alpha*S
1442
1443
CALL FetiProject(A,n,T,OP=0,TOL=1d-12)
1444
Ri = Ri - alpha*T
1445
1446
err0 = normfun(n,Ri,1)
1447
err1 = err0 / bnorm
1448
1449
!err2 = FetiStopc(x,b,Ri,ipar,dpar)
1450
!CALL matvecsubr(x,rr,ipar)
1451
!rr = rr - b
1452
!CALL FetiProject(A,n,rr,OP=0,TOL=1d-12)
1453
!err2 = normfun(n,rr,1)
1454
1455
IF ( output>0 .AND. MOD(iter,output)==0) THEN
1456
IF (ParEnv % MyPE==0) THEN
1457
PRINT*,iter,err0,err1; Flush(6)
1458
END IF
1459
END IF
1460
1461
IF (err1<TOL) EXIT
1462
!call checktimer('iter',delete=.true.)
1463
END DO
1464
1465
CALL matvecsubr(x(1:n),T,ipar)
1466
T = -(T-b(1:n))
1467
CALL FetiProject(A,n,T,OP=2,TOL=1d-12)
1468
IF (nz>0) x(n+1:n+nz) = T(1:nz)
1469
!call checktimer('cpg',delete=.true.)
1470
!------------------------------------------------------------------------------
1471
END SUBROUTINE FetiCPG
1472
!------------------------------------------------------------------------------
1473
1474
1475
!------------------------------------------------------------------------------
1476
!> Compute null(A), return value is whether null(A) is nonempty.
1477
!------------------------------------------------------------------------------
1478
FUNCTION FetiFloatingDomain(A,Solver,FixInds,TOL) RESULT(Floating)
1479
!------------------------------------------------------------------------------
1480
USE EigenSolve
1481
TYPE(Matrix_t), POINTER :: A
1482
REAL(KIND=dp) :: TOL
1483
LOGICAL :: floating
1484
INTEGER :: FixInds(:)
1485
TYPE(Solver_t) :: Solver
1486
!------------------------------------------------------------------------------
1487
REAL(KIND=dp), PARAMETER :: floatEps = 1.0d-9
1488
REAL(KIND=dp), ALLOCATABLE :: x(:),tz(:,:)
1489
INTEGER, POINTER :: p(:)
1490
INTEGER :: i,j,k,n,m,dofs,neigs,dim,FixNodes(0:6)
1491
REAL(KIND=dp), POINTER :: coord_x(:),coord_y(:),coord_z(:), dscale(:)
1492
LOGICAL :: Found
1493
REAL(KIND=dp) :: xc,yc,zc,hc,ss
1494
INTEGER, ALLOCATABLE :: floatinds(:)
1495
COMPLEX(KIND=dp) :: EigValues(maxnz)
1496
COMPLEX(KIND=dp), ALLOCATABLE :: EigVectors(:,:)
1497
!------------------------------------------------------------------------------
1498
1499
Params => ListGetSolverParams()
1500
1501
dofs = Solver % Variable % DOFs
1502
n = A % NumberOfRows
1503
1504
IF(ALLOCATED(z)) DEALLOCATE(z)
1505
nz = 0
1506
1507
! We might be operating in a scaled system, i.e. solving
1508
! (DAD)y = Db; x=Dy
1509
! instead of the original system Ax=b, hence the scalings below:
1510
! --------------------------------------------------------------
1511
IF (ASSOCIATED(A % DiagScaling)) THEN
1512
dscale => A % DiagScaling
1513
ELSE
1514
ALLOCATE(dScale(n)); dscale=1._dp
1515
END IF
1516
1517
dim = CoordinateSystemDimension()
1518
1519
IF(dofs==1) THEN
1520
!
1521
! For Poisson, check if 1 in null space:
1522
! --------------------------------------
1523
1524
m = Solver % Mesh % NumberOfNodes
1525
p => Solver % Variable % Perm
1526
1527
! constant 1 (complications due to p-elements)
1528
! --------------------------------------------------
1529
nz=1
1530
ALLOCATE(z(nz,n))
1531
z = 0._dp
1532
DO i=1,m
1533
j=p(i)
1534
IF (j>0) z(1,j) = 1._dp / dscale(j)
1535
END DO
1536
1537
ALLOCATE(x(n));
1538
CALL MatrixVectorMultiply(A,z(1,:),x)
1539
Floating = ALL(ABS(x)<floatEps)
1540
1541
IF (.NOT.Floating) THEN
1542
DEALLOCATE(z); nz=0;
1543
ELSE
1544
CALL FindRigidBodyFixingNodes(Solver, FixNodes, p)
1545
Fixinds(1) = p(FixNodes(0))
1546
END IF
1547
IF (.NOT.ASSOCIATED(A % DiagScaling)) DEALLOCATE(dscale)
1548
NullSpaceLC=GetLogical(Params,'Feti Fixing Using L.C.',Found)
1549
RETURN
1550
ELSE IF (GetLogical(Params,'Feti Kernel Rot-Trans',Found)) THEN
1551
!
1552
! If requested, make null(A) using basic translations and rotations:
1553
! ------------------------------------------------------------------
1554
1555
m = Solver % Mesh % NumberOfNodes
1556
p => Solver % Variable % Perm
1557
1558
coord_x => Solver % Mesh % Nodes % x
1559
coord_y => Solver % Mesh % Nodes % y
1560
coord_z => Solver % Mesh % Nodes % z
1561
1562
xc = SUM(coord_x)/m
1563
yc = SUM(coord_y)/m
1564
zc = SUM(coord_z)/m
1565
hc = 0._dp
1566
hc = hc + (MAXVAL(coord_x)-MINVAL(coord_x))**2
1567
hc = hc + (MAXVAL(coord_y)-MINVAL(coord_y))**2
1568
hc = hc + (MAXVAL(coord_z)-MINVAL(coord_z))**2
1569
hc = SQRT(hc)
1570
1571
IF (dim==2) nz=dofs+1
1572
IF (dim==3) nz=dofs+dim
1573
ALLOCATE(tz(nz,n)); tz=0
1574
1575
DO i=1,m ! translations and potential levels
1576
IF (p(i) <= 0) CYCLE
1577
DO j=1,dofs
1578
k=dofs*(p(i)-1)+j
1579
tz(j,k) = 1._dp / dscale(k)
1580
END DO
1581
END DO
1582
1583
DO i=1,m
1584
IF (p(i) <= 0) CYCLE
1585
j=dofs*(p(i)-1)
1586
tz(dofs+1,j+1) = -(coord_y(i)-yc) / hc / dscale(j+1) ! rot about z
1587
tz(dofs+1,j+2) = (coord_x(i)-xc) / hc / dscale(j+2)
1588
1589
IF (dim>=3) THEN
1590
tz(dofs+2,j+2) = -(coord_z(i)-zc) / hc / dscale(j+2) ! rot about x
1591
tz(dofs+2,j+3) = (coord_y(i)-yc) / hc / dscale(j+3)
1592
1593
tz(dofs+3,j+1) = (coord_z(i)-zc) / hc / dscale(j+1) ! rot about y
1594
tz(dofs+3,j+3) = -(coord_x(i)-xc) / hc / dscale(j+3)
1595
END IF
1596
END DO
1597
IF (.NOT.ASSOCIATED(A % DiagScaling)) DEALLOCATE(dscale)
1598
1599
ALLOCATE(x(n),floatinds(nz))
1600
1601
! Check which of the translations & rotations & potential
1602
! levels are free:
1603
! --------------------------------------------------------
1604
j=nz
1605
nz=0
1606
DO i=1,j
1607
tz(i,:) = tz(i,:)/MAXVAL(ABS(tz(i,:)))
1608
CALL MatrixVectorMultiply(A,tz(i,:),x)
1609
IF (ALL(ABS(x)<floatEps)) THEN
1610
nz=nz+1
1611
FloatInds(nz)=i
1612
END IF
1613
END DO
1614
1615
! Set the DOFs to fix at FixNodes() nodes:
1616
! ----------------------------------------
1617
Floating=nz>0
1618
IF (Floating) THEN
1619
CALL FindRigidBodyFixingNodes(Solver, FixNodes, p)
1620
DO i=1,nz
1621
! FixInds(i) = dofs*(p(FixNodes(2*FloatInds(i)-1))-1)+FloatInds(i)
1622
1623
IF (FloatInds(i)==1) THEN ! x translation
1624
FixInds(i) = dofs*(p(FixNodes(0))-1)+1
1625
ELSE IF (FloatInds(i)==2) THEN ! y translation
1626
FixInds(i) = dofs*(p(FixNodes(0))-1)+2
1627
ELSE IF (dofs>2.AND.FloatInds(i)==3) THEN ! z translation
1628
FixInds(i) = dofs*(p(FixNodes(0))-1)+3
1629
ELSE IF (FloatInds(i)==dofs+1) THEN ! rot 'bout z
1630
FixInds(i) = dofs*(p(FixNodes(1))-1)+1
1631
ELSE IF (FloatInds(i)==dofs+2) THEN ! rot 'bout x
1632
FixInds(i) = dofs*(p(FixNodes(2))-1)+2
1633
ELSE IF (FloatInds(i)==dofs+3) THEN ! rot 'bout y
1634
FixInds(i) = dofs*(p(FixNodes(3))-1)+3
1635
ELSE ! the rest assumed potential like
1636
FixInds(i)=dofs*(p(FixNodes(0))-1)+FloatInds(i)
1637
END IF
1638
1639
END DO
1640
ALLOCATE(z(nz,n))
1641
z = tz(floatinds(1:nz),:)
1642
END IF
1643
NullSpaceLC=GetLogical(Params,'Feti Fixing Using L.C.',Found)
1644
RETURN
1645
END IF
1646
1647
1648
! By default assemble the ker(A) from the null frequency eigenmodes:
1649
! ==================================================================
1650
1651
! max deficiency:
1652
! ---------------
1653
IF (dim==2) THEN
1654
Neigs=4
1655
ELSE
1656
Neigs=20
1657
END IF
1658
1659
! Solution of few lowest eigenmodes:
1660
! ----------------------------------
1661
ALLOCATE(eigVectors(Neigs,n))
1662
1663
CALL ListPushNameSpace('feti:')
1664
1665
CALL ListAddString( Params, 'Feti: Linear System Solver', 'Direct' )
1666
Params=>ListGetSolverParams()
1667
CALL ListAddString( Params, 'Feti: Linear System Direct Method', 'umfpack' )
1668
Params=>ListGetSolverParams()
1669
1670
IF (.NOT.ListCheckPresent(Params,'Eigen System Convergence Tolerance')) &
1671
CALL ListAddConstReal( Params, &
1672
'Feti: Eigen System Convergence Tolerance', 1.0d-9)
1673
Params=>ListGetSolverParams()
1674
1675
IF (.NOT.ASSOCIATED(A % MassValues)) THEN
1676
ALLOCATE(A % MassValues(SIZE(A % Values)))
1677
A % MassValues=0
1678
A % Massvalues(A % Diag)=1/dscale
1679
CALL ArpackEigenSolve(Solver,A,n,NEigs,EigValues,EigVectors)
1680
DEALLOCATE(A % MassValues)
1681
ELSE
1682
CALL ArpackEigenSolve(Solver,A,n,NEigs,EigValues,EigVectors)
1683
END IF
1684
1685
! Delete factorization as we can't use the same factorization within FETI:
1686
! ------------------------------------------------------------------------
1687
CALL DirectSolver(A,x,x,Solver,Free_Fact=.TRUE.)
1688
1689
CALL ListPopNameSpace()
1690
1691
! Finally create null(A) from zero freq. eigenvectors:
1692
! ----------------------------------------------------
1693
DO nz=0,neigs-1
1694
IF (ABS(EigValues(nz+1))>floatEps) EXIT
1695
END DO
1696
1697
IF (nz>0) THEN
1698
ALLOCATE(z(nz,n))
1699
z(1:nz,:) = REAL(EigVectors(1:nz,:))
1700
END IF
1701
1702
DEALLOCATE(EigVectors)
1703
IF (.NOT.ASSOCIATED(A % DiagScaling)) DEALLOCATE(dscale)
1704
1705
Floating = nz>0
1706
NullSpaceLC=GetLogical(Params,'Feti Fixing Using L.C.',Found)
1707
IF(.NOT.Found) NullSpaceLC=.TRUE.
1708
1709
!------------------------------------------------------------------------------
1710
END FUNCTION FetiFloatingDomain
1711
!------------------------------------------------------------------------------
1712
1713
1714
!------------------------------------------------------------------------------
1715
!> Solve x from [A z^T; z 0] [x; \lambda] = [b 0]
1716
!> or A x = b, depending on how the system is set up.
1717
!------------------------------------------------------------------------------
1718
SUBROUTINE FetiDirectSolver(A,x,b,Solver)
1719
!------------------------------------------------------------------------------
1720
TYPE(Matrix_t), POINTER :: a
1721
TYPE(Solver_t) :: Solver
1722
REAL(KIND=dp), TARGET CONTIG :: x(:),b(:)
1723
!------------------------------------------------------------------------------
1724
INTEGER :: n
1725
REAL(KIND=dp), POINTER CONTIG :: tx(:),tb(:)
1726
!call resettimer('direct')
1727
n = A % NumberOfRows
1728
tx=>x
1729
tb=>b
1730
1731
IF (NullSpaceLC.AND.nz>0) THEN
1732
ALLOCATE(tx(n+nz),tb(n+nz))
1733
tb=0
1734
tb(1:n)=b
1735
A % NumberOfRows=n+nz
1736
END IF
1737
1738
CALL DirectSolver(A,tx,tb,Solver)
1739
1740
IF (NullSpaceLC.AND.nz>0) THEN
1741
A % NumberOfRows=n
1742
x=tx(1:n)
1743
DEALLOCATE(tx,tb)
1744
END IF
1745
!call checktimer('direct',delete=.true.)
1746
!------------------------------------------------------------------------------
1747
END SUBROUTINE FetiDirectSolver
1748
!------------------------------------------------------------------------------
1749
1750
1751
!------------------------------------------------------------------------------
1752
SUBROUTINE SaveKandF(A)
1753
!------------------------------------------------------------------------------
1754
TYPE(Matrix_t) :: A
1755
1756
INTEGER :: me, abeg,i,j
1757
INTEGER, ALLOCATABLE :: snd(:), asize(:), bsize(:)
1758
1759
me = Parenv % MyPE
1760
ALLOCATE(snd(0:Parenv%PEs-1),asize(0:Parenv%PEs-1),bsize(0:parenv%pes-1))
1761
snd=0
1762
snd(me)=A % NumberOfRows
1763
CALL MPI_ALLREDUCE( snd,asize,Parenv % PEs,MPI_INTEGER,MPI_MAX,&
1764
ELMER_COMM_WORLD,ierr)
1765
abeg = SUM(asize(0:me-1))
1766
1767
OPEN(1,file='f' // i2s(Parenv % MyPE))
1768
OPEN(2,file='k' // i2s(Parenv % MyPE))
1769
1770
WRITE(1,'(a)') '% domain: '//i2s(me)//' nrows:'//i2s(A % NumberOFRows)
1771
1772
WRITE(2,'(a)') '% domain:' // i2s(me)//' nnz:' // &
1773
i2s(A % Rows(A % NumberOfRows+1)-1) // ' nrows:' // &
1774
i2s(A % NumberOFRows) // ' gcols:'//i2s(SUM(asize))
1775
1776
DO i=1,A % NumberOfRows
1777
DO j=A % Rows(i),A % Rows(i+1)-1
1778
WRITE(2,*) abeg+i, abeg+A % Cols(j), A % Values(j)
1779
END DO
1780
WRITE(1,*) abeg+i, a % RHS(i)
1781
END DO
1782
CLOSE(2)
1783
!------------------------------------------------------------------------------
1784
END SUBROUTINE SaveKandF
1785
!------------------------------------------------------------------------------
1786
1787
1788
!------------------------------------------------------------------------------
1789
SUBROUTINE SaveR
1790
!------------------------------------------------------------------------------
1791
INTEGER :: i
1792
OPEN(2,File='r'//i2s(Parenv % MyPE))
1793
WRITE(2,'(a)') '% domain: '//i2s(ParEnv % MyPE)//' nz:'// &
1794
i2s(SIZE(z,1))//' nrows:'// i2s(SIZE(z,2))
1795
DO i=1,SIZE(z,2)
1796
WRITE(2,*) z(1:nz,i)
1797
END DO
1798
CLOSE(2)
1799
!------------------------------------------------------------------------------
1800
END SUBROUTINE SaveR
1801
!------------------------------------------------------------------------------
1802
1803
!------------------------------------------------------------------------------
1804
SUBROUTINE SaveB(A,ninterface,lint)
1805
TYPE(Matrix_t) :: A
1806
INTEGER :: lint(:)
1807
INTEGER :: ninterface
1808
!------------------------------------------------------------------------------
1809
INTEGER, ALLOCATABLE :: snd(:), asize(:), bsize(:), cnt(:),ibuf(:,:),gbuf(:,:)
1810
1811
INTEGER :: bbeg, i,j,k,l,proc,n,m,me
1812
1813
INTEGER, POINTER :: gtags(:)
1814
LOGICAL, POINTER :: ig(:)
1815
TYPE(NeighbourList_t), POINTER :: nb(:)
1816
1817
gtags => A % ParallelInfo % GlobalDofs
1818
ig => A % ParallelInfo % GInterface
1819
nb => A % ParallelInfo % NeighbourList
1820
1821
OPEN(4,FILE='b'//I2S(Parenv % MyPE))
1822
OPEN(5,FILE='brhs'//I2S(Parenv % MyPE))
1823
1824
me = ParEnv % MyPE
1825
1826
WRITE(4,'(a)') '% domain: '//i2s(me)//' nnz: '// &
1827
i2s(bMat % Rows(Bmat % NumberOfRows+1)-1) // &
1828
' nrows: ' // i2s(Bmat % NumberOfRows)
1829
1830
WRITE(5,'(a)') '% domain: '//i2s(ParEnv % MyPE)//' nrows:'// &
1831
i2s(Bmat % NumberOfRows)
1832
1833
ALLOCATE(snd(0:Parenv%PEs-1),asize(0:Parenv%PEs-1),bsize(0:parenv%pes-1))
1834
1835
snd=0
1836
snd(me)=A % NumberOfRows
1837
CALL MPI_ALLREDUCE( snd,asize,Parenv % PEs,MPI_INTEGER,MPI_MAX,&
1838
ELMER_COMM_WORLD,ierr)
1839
abeg = SUM(asize(0:me-1))
1840
1841
snd=0
1842
snd(me)=Bmat % NumberOFrows
1843
CALL MPI_ALLREDUCE( snd,bsize,ParEnv%PEs,MPI_INTEGER, &
1844
MPI_MAX, ELMER_COMM_WORLD,ierr)
1845
bbeg=sum(bsize(0:me-1))
1846
1847
ALLOCATE(cnt(0:parenv%pes-1))
1848
ALLOCATE(ibuf(ninterface,0:parenv%pes-1))
1849
ALLOCATE(gbuf(ninterface,0:parenv%pes-1))
1850
1851
cnt=0
1852
DO i=1,nInterface
1853
m = lint(i)
1854
DO j=1,SIZE(nb(m) % Neighbours)
1855
proc=nb(m) % Neighbours(j)
1856
IF(proc==me) CYCLE
1857
cnt(proc) = cnt(proc)+1
1858
ibuf(cnt(proc),proc)=m
1859
gbuf(cnt(proc),proc)=gtags(m)
1860
END DO
1861
END DO
1862
1863
DO i=1,ParEnv % PEs
1864
IF(.NOT. ParEnv % ISneighbour(i)) CYCLE
1865
proc=i-1
1866
CALL MPI_BSEND( cnt(proc), 1, MPI_INTEGER, proc, &
1867
800, ELMER_COMM_WORLD, ierr )
1868
IF(cnt(proc)>0) THEN
1869
CALL MPI_BSEND( gbuf(:,proc), cnt(proc), MPI_INTEGER, proc, &
1870
801, ELMER_COMM_WORLD, ierr )
1871
1872
CALL MPI_BSEND( ibuf(:,proc), cnt(proc), MPI_INTEGER, proc, &
1873
802, ELMER_COMM_WORLD, ierr )
1874
END IF
1875
END DO
1876
CALL ParallelActiveBarrier()
1877
1878
DO i=1,ParEnv % PEs
1879
IF(.NOT. ParEnv % IsNeighbour(i)) CYCLE
1880
proc=i-1
1881
CALL MPI_RECV( cnt(proc), 1, MPI_INTEGER, proc, &
1882
800, ELMER_COMM_WORLD, status, ierr )
1883
1884
IF(cnt(proc)>0) THEN
1885
CALL MPI_RECV( gbuf(:,proc), cnt(proc), MPI_INTEGER, proc, &
1886
801, ELMER_COMM_WORLD, status, ierr )
1887
1888
CALL MPI_RECV( ibuf(:,proc), cnt(proc), MPI_INTEGER, proc, &
1889
802, ELMER_COMM_WORLD, status, ierr )
1890
END IF
1891
END DO
1892
1893
DO i=1,Bmat % NumberOfRows
1894
l = Bmat % Perm(i)
1895
IF (l>0) THEN ! m = Partition DOF number...
1896
m = lint(l) ! ...for an interface DOF
1897
ELSE
1898
m = -l ! ...for a Dirichlet DOF
1899
END IF
1900
1901
WRITE(5,*) bbeg+i,Bmat% InvPerm(i), Bmat % RHS(i)
1902
1903
DO j=Bmat % Rows(i),Bmat % Rows(i+1)-1
1904
proc=Bmat % Cols(j)
1905
IF(proc==me) THEN
1906
WRITE(4,*) bbeg+i,m+abeg,bmat % values(j)
1907
ELSE
1908
DO k=1,cnt(proc)
1909
IF(gtags(m)==gbuf(k,proc)) EXIT
1910
END DO
1911
IF(k>cnt(proc)) stop 'aah'
1912
WRITE(4,*) bbeg+i,ibuf(k,proc)+sum(asize(0:proc-1)),Bmat % values(j)
1913
END IF
1914
END DO
1915
END DO
1916
1917
CLOSE(4)
1918
CLOSE(5)
1919
!------------------------------------------------------------------------------
1920
END SUBROUTINE SaveB
1921
!------------------------------------------------------------------------------
1922
1923
1924
1925
!------------------------------------------------------------------------------
1926
!> The FETI main routine: solve x from Ax=b using the F(inite) E(lement)
1927
!> T(earing) and I(nterconnect) method.
1928
!------------------------------------------------------------------------------
1929
SUBROUTINE Feti(A,x,b,Solver)
1930
! Just basic feti so far...
1931
! -------------------------
1932
!------------------------------------------------------------------------------
1933
TYPE(Matrix_t), POINTER :: A
1934
TYPE(Solver_t) :: Solver
1935
REAL(KIND=dp), target :: x(:),b(:)
1936
!------------------------------------------------------------------------------
1937
REAL(KIND=dp), ALLOCATABLE,target :: y(:)
1938
REAL(KIND=dp) :: alpha(maxnz), zz, TOL,mind,maxd
1939
INTEGER :: i,j,k,l,m,n,nd,q,d,nLC
1940
1941
TYPE(Mesh_t), POINTER :: Mesh
1942
LOGICAL :: Found, Floating=.FALSE., FetiInit, QR, MumpsLU, MumpsNS
1943
REAL(KIND=dp), POINTER :: xtmp(:),btmp(:),rtmp(:)
1944
INTEGER(KIND=AddrInt) :: mvProc, dotProc, nrmProc, stopcProc, precProc
1945
INTEGER(KIND=AddrInt) :: AddrFunc
1946
EXTERNAL :: AddrFunc
1947
1948
REAL(KIND=dp), POINTER CONTIG :: SaveValues(:)
1949
INTEGER, POINTER CONTIG :: SaveCols(:),SaveRows(:)
1950
INTEGER, POINTER :: p(:)
1951
1952
SAVE SaveValues, SaveCols, SaveRows
1953
1954
INTEGER, ALLOCATABLE :: Indexes(:)
1955
REAL(KIND=dP), ALLOCATABLE :: vals(:)
1956
1957
TYPE(Element_t), POINTER :: EL
1958
TYPE(ValueList_t), POINTER :: BC
1959
1960
#ifdef HAVE_CHOLMOD
1961
INTERFACE
1962
SUBROUTINE SPQR_NZ(chol,nz) BIND(c,NAME="spqr_nz")
1963
USE Types
1964
INTEGER :: nz
1965
INTEGER(Kind=AddrInt) :: chol
1966
END SUBROUTINE SPQR_NZ
1967
1968
SUBROUTINE SPQR_NullSpace(chol,n,nz,z) BIND(c,NAME="spqr_nullspace")
1969
USE Types
1970
INTEGER :: nz,n
1971
REAL(KIND=dp) :: z(*)
1972
INTEGER(Kind=AddrInt) :: chol
1973
END SUBROUTINE SPQR_NullSpace
1974
END INTERFACE
1975
#endif
1976
1977
!------------------------------------------------------------------------------
1978
1979
! Flag dirichlet d.o.f., to remove 'em from interface conditions:
1980
! ----------------------------------------------------------------
1981
IF(ALLOCATED(DirichletDOFs)) DEALLOCATE(DirichletDOFs)
1982
1983
ALLOCATE(DirichletDOFs(A % NumberOFRows))
1984
DirichletDOFs = .FALSE.
1985
1986
d = Solver % Variable % DOFs
1987
p => Solver % Variable % Perm
1988
ALLOCATE(Indexes(Solver % Mesh % MaxElementDOFs))
1989
DO i=1,GetNofBoundaryElements()
1990
El=>GetBoundaryElement(i)
1991
BC=>GetBC()
1992
IF(.NOT.ASSOCIATED(BC)) CYCLE
1993
nd = GetElementDOFs(Indexes)
1994
DO j=1,d
1995
IF (d>1) THEN
1996
IF(ListCheckPresent(BC,ComponentName(Solver % Variable,j))) &
1997
DirichletDOFs(d*(p(Indexes(1:nd))-1)+j)=.TRUE.
1998
ELSE
1999
IF(ListCheckPresent(BC,Solver % Variable % Name)) &
2000
DirichletDOFs(d*(p(Indexes(1:nd))-1)+j)=.TRUE.
2001
END IF
2002
END DO
2003
END DO
2004
DEALLOCATE(Indexes)
2005
2006
! Get various solution options:
2007
! ------------------------------
2008
Params => ListGetSolverParams()
2009
TOL=GetCReal( Params,'Linear System Convergence Tolerance')
2010
2011
! Check whether to use the 'total' FETI scheme:
2012
! ---------------------------------------------
2013
2014
TOL=GetCReal( Params,'Linear System Convergence Tolerance')
2015
2016
! Check whether to use the 'total' FETI scheme:
2017
! ---------------------------------------------
2018
TotalFeti = GetLogical(Params, 'Total Feti', Found)
2019
FetiAsPrec = GetLogical(Params, 'Feti Use As Preconditioner', Found)
2020
2021
! Tell 'DirectSolver' to factorize first time only:
2022
! -------------------------------------------------
2023
Refactorize=GetLogical(Params, 'Linear System Refactorize',Found)
2024
IF (.NOT.Found) Refactorize = .TRUE.
2025
CALL ListAddLogical(Params,'Linear System Refactorize',.FALSE.)
2026
2027
! Check if using local CGP, or (f.ex.) GCR from usual iterators:
2028
! --------------------------------------------------------------
2029
CPG = GetString(Params,'Linear System Iterative Method') == 'cpg'
2030
2031
! Check if QR decomposition to find the nullspace:
2032
! ------------------------------------------------
2033
QR = GetString(Params,'Linear System Direct Method') == 'spqr'
2034
2035
! Check if local Mumps decomposition can be used to find the nullspace
2036
! ---------------------------------------------------------------------
2037
MumpsLU = GetString(Params,'Linear System Direct Method') == 'mumpslocal'
2038
! Mark system as possibly singular for Mumps
2039
! ------------------------------------------
2040
IF (MumpsLU) &
2041
MumpsLU = ListGetLogical(Params, 'Mumps Solve Singular', Found)
2042
2043
n = A % NumberOfRows
2044
ALLOCATE(y(n))
2045
2046
! Initialize parallel matrix for the original system for
2047
! matrix-vector multiply in FetiStopc. NOT USED at the
2048
! moment.
2049
! ------------------------------------------------------
2050
! y=b
2051
! CALL ParallelInitSolve(A,x,y,rtmp)
2052
2053
dumptofiles = GetLogical( Params, 'Feti dump system', Found)
2054
IF(dumptofiles) THEN
2055
CALL Info( 'Feti:', 'Dumping Feti Description to files')
2056
CALL SaveKandF(A)
2057
END IF
2058
2059
IF(Refactorize) THEN
2060
InitializeLC = .TRUE.; InitializeIf = .TRUE.
2061
2062
! Check neighbouring partitions:
2063
! ------------------------------
2064
CALL FetiGetNeighbours()
2065
2066
! Check for floating domains, initialize null space z (a.k.a. R):
2067
! ---------------------------------------------------------------
2068
IF(.NOT.(QR.OR.MumpsLU)) THEN
2069
Floating=FetiFloatingDomain(A,Solver,FixInds,TOL)
2070
END IF
2071
END IF
2072
2073
! 'fix' A to allow solving local system:
2074
! ---------------------------------------
2075
IF (.NOT.(QR.OR.MumpsLU).AND.Floating) THEN
2076
saverows => a % rows
2077
savecols => a % cols
2078
savevalues => a % values
2079
2080
IF (NullSpaceLC) THEN
2081
! Fix z=null(A) with Lagrange coefficients
2082
! A_fix = [A z^T; z 0] ([x; \lambda]):
2083
! ------------------------------------------
2084
2085
allocate(a % rows(n+nz+1))
2086
k=count(a % values/=0)+2*count(z/=0)
2087
allocate(a % cols(k), a % values(k))
2088
l=1
2089
2090
do i=1,n
2091
a % rows(i)=l
2092
do j=saverows(i),saverows(i+1)-1
2093
IF ( savevalues(j)==0 ) CYCLE
2094
a % cols(l)=savecols(j)
2095
a % values(l)=savevalues(j)
2096
l=l+1
2097
end do
2098
do j=1,nz
2099
IF ( z(j,i)==0 ) CYCLE
2100
a % cols(l)=n+j
2101
a % values(l)=z(j,i)
2102
l=l+1
2103
end do
2104
end do
2105
2106
do j=1,nz
2107
a % rows(n+j)=l
2108
do i=1,n
2109
IF ( z(j,i)==0 ) CYCLE
2110
a % cols(l)=i
2111
a % values(l)=z(j,i)
2112
l=l+1
2113
end do
2114
end do
2115
a % rows(n+nz+1)=l
2116
ELSE
2117
! Fix z=null(A) with Dirichlet conditions on degrees
2118
! of freedom given by FloatingDomain():
2119
! ---------------------------------------------------
2120
ALLOCATE(A % Rows(n+1))
2121
k=SIZE(A % Values)
2122
ALLOCATE(A % Cols(k), A % Values(k))
2123
2124
A % Rows = SaveRows
2125
A % Cols = SaveCols
2126
A % Values = SaveValues
2127
2128
DO j=1,nz
2129
CALL CRS_SetSymmDirichlet(A,y,FixInds(j),0._dp)
2130
END DO
2131
END IF
2132
END IF
2133
2134
2135
! Compute and distribute r.h.s. for L.C.'s:
2136
! -SUM_part(B_i A_i^-1 b_i)
2137
! -----------------------------------------
2138
CALL FetiDirectSolver(A,x,b,Solver)
2139
x = -x
2140
nLC = FetiSendRecvIf(A,y,x)
2141
2142
! If using QR decomposition, find the null space
2143
! after factorizing:
2144
! ----------------------------------------------
2145
IF (Refactorize.AND.QR) THEN
2146
#ifdef HAVE_CHOLMOD
2147
CALL SPQR_NZ(A % Cholmod,nz) ! get null space size
2148
NullSpaceLC=.FALSE.
2149
Floating = nz/=0
2150
IF(ALLOCATED(z)) DEALLOCATE(z)
2151
ALLOCATE(z(nz,n))
2152
CALL SPQR_NullSpace(A % Cholmod,n,nz,z) ! get the null space
2153
#else
2154
CALL Fatal('Feti','Cholmod/SPQR solver has not been installed.')
2155
#endif
2156
END IF
2157
2158
! Find the null space by using LU decomposition and Mumps
2159
IF (Refactorize .AND. MumpsLU) THEN
2160
#ifdef HAVE_MUMPS
2161
IF(ALLOCATED(z)) DEALLOCATE(z)
2162
2163
! Solve local nullspace with Mumps
2164
CALL MumpsLocal_SolveNullSpace( Solver, A, z, nz )
2165
NullSpaceLC=.FALSE. ! What does this do?
2166
Floating = nz/=0 ! Is the domain a floating one
2167
#else
2168
CALL Fatal('Feti','Mumps has not been installed.')
2169
#endif
2170
END IF
2171
2172
mind=ParallelReduction(nz,1)
2173
maxd=ParallelReduction(nz,2)
2174
WRITE(Message,*) 'min/max nz:',FLOOR(mind+0.5_dp),FLOOR(maxd+0.5_dp)
2175
CALL Info('Feti:', Message,Level=6)
2176
2177
IF(dumptofiles) THEN
2178
CALL SaveR()
2179
CALL Info( 'Feti:', 'File dumping completed, exiting.')
2180
CALL ParallelFinalize(); STOP EXIT_OK
2181
END IF
2182
2183
2184
! add Dirichlet BC contribution to the r.h.s., if using Total FETI:
2185
! ------------------------------------------------------------------
2186
IF (TotalFeti) y(1:nLC)=y(1:nLC)+Bmat % RHS(1:nLC)
2187
2188
! Add Lagrange coefficient(s) for the projection condition
2189
! if not using the C(onjugate)P(rojected)G(radient) stuff:
2190
! --------------------------------------------------------
2191
IF (Floating .AND. .NOT. CPG) THEN
2192
y(nLC+1:nLC+nz)=-MATMUL(z,b)
2193
nLC = nLC+nz
2194
END IF
2195
2196
! CG iteration for the L.C.'s
2197
! ----------------------------
2198
Precondition = GetLogical( Params,'FETI Preconditioning', Found)
2199
IF (.NOT.Found) Precondition=.TRUE.
2200
x=0
2201
IF ( CPG ) THEN
2202
CALL FetiCPG(A,nLC,x,y,b,Solver, &
2203
FetiMV, FetiPrec, SParDotProd, SParNorm)
2204
ELSE
2205
precProc=AddrFunc(FetiPrec)
2206
mvProc=AddrFunc(FetiMV)
2207
nrmProc=AddrFunc(SParNorm)
2208
dotProc=AddrFunc(SParDotProd)
2209
CALL IterSolver(A,x,y,Solver,ndim=nLC,DotF=dotProc, &
2210
NormF=nrmProc, MatvecF=mvProc, precF=precProc )
2211
END IF
2212
2213
! Solve primary unknowns using L.C.'s:
2214
! x_i = A_i^-1(b_i + B_i^T\lambda) + R\alpha:
2215
! --------------------------------------------
2216
IF ( Floating ) THEN
2217
IF ( CPG ) THEN
2218
alpha(1:nz)=x(nLC+1:nLC+nz)
2219
ELSE
2220
alpha(1:nz)=x(nLC-nz+1:nLC)
2221
END IF
2222
END IF
2223
2224
CALL FetiSendRecvLC(A,y,x)
2225
y = y + b(1:n)
2226
CALL FetiDirectSolver(A,x,y,Solver)
2227
2228
IF (Floating) THEN
2229
x = x + MATMUL(alpha(1:nz),z)
2230
! DEALLOCATE(z)
2231
2232
IF(.NOT.(QR.OR.MumpsLU)) THEN
2233
DEALLOCATE(A % Values,A % Rows, A % Cols)
2234
A % Rows => SaveRows
2235
A % Cols => SaveCols
2236
A % Values => SaveValues
2237
END IF
2238
END IF
2239
2240
IF ( Refactorize ) THEN
2241
Refactorize=GetLogical(Params,'Linear System Free Factorization',Found)
2242
IF(.NOT.Found) Refactorize=.TRUE.
2243
IF(Refactorize) CALL DirectSolver(A,x,y,Solver,Free_Fact=.TRUE.)
2244
CALL ListAddLogical(Params,'Linear System Refactorize', .TRUE. )
2245
END IF
2246
2247
IF (TotalFeti .AND. FetiAsPrec) THEN
2248
! If using (total)Feti as a preconditioner and using sloppy
2249
! tolerances, forcing exact D-condtions afterwards seems to
2250
! help outer iteration convergence:
2251
! -------------------------------------------------------------
2252
DO i=1,n
2253
IF (DirichletDofs(i)) x(i)=b(i)
2254
END DO
2255
END IF
2256
2257
CALL ParallelActiveBarrier()
2258
!------------------------------------------------------------------------------
2259
END SUBROUTINE Feti
2260
!------------------------------------------------------------------------------
2261
2262
2263
!------------------------------------------------------------------------------
2264
!> Matrix-vector prod. for the L.C. equations:
2265
!> v_i = SUM_part(B_i A_i^-1 B_i^T u_i).
2266
!> Called from the CG iterator.
2267
! -------------------------------------------------------------------------
2268
SUBROUTINE FetiMV(u,v,ipar)
2269
!------------------------------------------------------------------------------
2270
INTEGER, DIMENSION(*) :: ipar
2271
REAL(KIND=dp) :: u(HUTI_NDIM), v(HUTI_NDIM), w(HUTI_NDIM)
2272
2273
REAL(KIND=dp), ALLOCATABLE :: x(:),b(:)
2274
INTEGER :: n,nLC
2275
TYPE(Matrix_t), POINTER :: A
2276
TYPE(Solver_t), POINTER :: Solver
2277
2278
!call resettimer('mv')
2279
Solver => GetSolver()
2280
A => GetMatrix()
2281
n = A % NumberOfRows
2282
2283
ALLOCATE(x(n),b(n))
2284
2285
CALL FetiSendRecvLC(A,b,u)
2286
CALL FetiDirectSolver(A,x,b,Solver)
2287
nLC = FetiSendRecvIf(A,v,x)
2288
2289
! If floating domain, update null space contributions
2290
! (if not using CPG):
2291
! ----------------------------------------------------
2292
IF ( .NOT. CPG ) THEN
2293
x=0
2294
IF (nz>0) x=MATMUL(u(nLC+1:nLC+nz),z)
2295
nLC = FetiSendRecvIf(A,w,x)
2296
v(1:nLC) = v(1:nLC) + w(1:nLC)
2297
IF (nz>0) v(nLC+1:nLC+nz) = MATMUL(z,b)
2298
END IF
2299
!call checktimer('mv',delete=.true.)
2300
!------------------------------------------------------------------------------
2301
END SUBROUTINE FetiMV
2302
!------------------------------------------------------------------------------
2303
2304
2305
!------------------------------------------------------------------------------
2306
!> Peconditioning for feti:
2307
!> u_i = SUM_part(B_i A_i B_i^T v_i)
2308
!> (the m-v could be written for the interface dofs only...)
2309
!> Called from the CG iterator.
2310
! -------------------------------------------------------------------------
2311
SUBROUTINE FetiPrec(u,v,ipar)
2312
!------------------------------------------------------------------------------
2313
INTEGER, DIMENSION(*) :: ipar
2314
REAL(KIND=dp) :: u(HUTI_NDIM), v(HUTI_NDIM)
2315
2316
REAL(KIND=dp), ALLOCATABLE, TARGET :: x(:),b(:)
2317
INTEGER :: n, nLC
2318
TYPE(Matrix_t), POINTER :: A
2319
TYPE(Solver_t), POINTER :: Solver
2320
!call resettimer('prec')
2321
2322
IF(.NOT.Precondition) THEN
2323
u=v
2324
RETURN
2325
END IF
2326
2327
A => GetMatrix()
2328
n = A % NumberOfRows
2329
2330
ALLOCATE(x(n+nz),b(n))
2331
2332
CALL FetiSendRecvLC(A,x,v)
2333
CALL MatrixVectorMultiply(A,x,b)
2334
nLC = FetiSendRecvIf(A,u,b)
2335
2336
! If floating domain, update null space contributions
2337
! (if not using CPG):
2338
! ----------------------------------------------------
2339
IF (.NOT. CPG .AND. nz>0) THEN
2340
u(nLC+1:nLC+nz)=v(nLC+1:nLC+nz)
2341
END IF
2342
!call checktimer('prec',delete=.true.)
2343
!------------------------------------------------------------------------------
2344
END SUBROUTINE FetiPrec
2345
!------------------------------------------------------------------------------
2346
2347
2348
! -------------------------------------------------------------------------
2349
!> Stop condition for the iteration. Use ||Ax-b||/||b|| from the
2350
!> originating system.
2351
!> Called from the CG iterator.
2352
!------------------------------------------------------------------------------
2353
FUNCTION FetiStopc(lx,lb,lr,ipar,dpar) RESULT(err)
2354
!------------------------------------------------------------------------------
2355
INTEGER :: ipar(*)
2356
REAL(KIND=dp) :: lx(HUTI_NDIM),lb(HUTI_NDIM),lr(HUTI_NDIM),dpar(*),err
2357
! -------------------------------------------------------------------------
2358
TYPE(Solver_t), POINTER :: Solver
2359
INTEGER :: n
2360
TYPE(Matrix_t), POINTER :: A,M
2361
REAL(KIND=dp), ALLOCATABLE :: x(:),y(:)
2362
REAL(KIND=dp), POINTER :: xtmp(:),b(:),r(:)
2363
2364
REAL(KIND=dp) :: llx(HUTI_NDIM)
2365
2366
Solver => GetSolver()
2367
A => GetMatrix()
2368
b => A % RHS
2369
n = A % NumberOfRows
2370
2371
ALLOCATE(x(n),y(n))
2372
2373
CALL FetiSendRecvLC(A,y,lx)
2374
y = y + b
2375
CALL FetiDirectSolver(A,x,y,Solver)
2376
2377
CALL ParallelActiveBarrier()
2378
! For floating domains:
2379
! ---------------------
2380
call FetiMV(lx,llx,ipar)
2381
llx=-(llx-lb)
2382
CALL FetiProject(A,HUTI_NDIM,llx,OP=2,TOL=1d-12)
2383
2384
IF (nz>0) THEN
2385
x = x + MATMUL(llx(1:nz),z)
2386
END IF
2387
2388
M => ParallelMatrix(A,xtmp,b,r)
2389
n = M % NumberOfRows
2390
2391
CALL ParallelUpdateSolve(A,x,y)
2392
CALL ParallelMatrixVector(A,xtmp,r)
2393
r = r - b
2394
err = ParallelNorm(n,r)/ParallelNorm(n,b)
2395
!------------------------------------------------------------------------------
2396
END FUNCTION FetiStopc
2397
!------------------------------------------------------------------------------
2398
2399
!------------------------------------------------------------------------------
2400
END MODULE FetiSolve
2401
!------------------------------------------------------------------------------
2402
2403
2404
!------------------------------------------------------------------------------
2405
!> Just a handle for SolveLinearSystem():
2406
!------------------------------------------------------------------------------
2407
SUBROUTINE FetiSolver(A,x,b,Solver)
2408
!------------------------------------------------------------------------------
2409
USE FetiSolve
2410
2411
TYPE(Matrix_t), POINTER :: A
2412
TYPE(Solver_t) :: Solver
2413
REAL(KIND=dp) :: x(:),b(:)
2414
!------------------------------------------------------------------------------
2415
CALL Feti(A,x,b,Solver)
2416
!------------------------------------------------------------------------------
2417
END SUBROUTINE FetiSolver
2418
!------------------------------------------------------------------------------
2419
2420
!> \}
2421
2422