Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/fem/src/ListMatrix.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
!> \ingroup ElmerLib
25
!> \{
26
27
28
MODULE ListMatrix
29
30
USE CRSMatrix
31
USE GeneralUtils
32
33
IMPLICIT NONE
34
35
INTEGER, PARAMETER :: LISTMATRIX_GROWTH = 1000
36
37
CONTAINS
38
39
!-------------------------------------------------------------------------------
40
!> Returns a handle to an allocated list matrix.
41
!-------------------------------------------------------------------------------
42
FUNCTION List_AllocateMatrix(N) RESULT(Matrix)
43
!-------------------------------------------------------------------------------
44
INTEGER :: i,n,istat
45
TYPE(ListMatrix_t), POINTER :: Matrix(:)
46
47
ALLOCATE( Matrix(n), STAT=istat )
48
IF( istat /= 0 ) THEN
49
CALL Fatal('List_AllocateMatrix','Allocation error for ListMatrix of size: '//I2S(n))
50
END IF
51
52
!$OMP PARALLEL
53
!$OMP DO
54
DO i=1,n
55
Matrix(i) % Head => NULL()
56
Matrix(i) % Level = 0
57
Matrix(i) % Degree = 0
58
END DO
59
!$OMP END DO NOWAIT
60
!$OMP END PARALLEL
61
!-------------------------------------------------------------------------------
62
END FUNCTION List_AllocateMatrix
63
!-------------------------------------------------------------------------------
64
65
66
!-------------------------------------------------------------------------------
67
!> Frees a list matrix.
68
!-------------------------------------------------------------------------------
69
SUBROUTINE List_FreeMatrix( N, List )
70
!-------------------------------------------------------------------------------
71
TYPE(ListMatrix_t), POINTER :: List(:)
72
INTEGER :: N
73
!-------------------------------------------------------------------------------
74
75
TYPE(ListMatrixEntry_t), POINTER :: p,p1
76
INTEGER :: i
77
!-------------------------------------------------------------------------------
78
IF ( .NOT. ASSOCIATED(List) ) RETURN
79
80
!$OMP PARALLEL DO &
81
!$OMP SHARED(List,N) &
82
!$OMP PRIVATE(p, p1) DEFAULT(NONE)
83
DO i=1,N
84
p => List(i) % Head
85
DO WHILE( ASSOCIATED(p) )
86
p1 => p % Next
87
DEALLOCATE( p )
88
p => p1
89
END DO
90
END DO
91
!$OMP END PARALLEL DO
92
DEALLOCATE( List )
93
!-------------------------------------------------------------------------------
94
END SUBROUTINE List_FreeMatrix
95
!-------------------------------------------------------------------------------
96
97
98
!-------------------------------------------------------------------------------
99
!> Enlarge a list matrix so that in can take in new entries.
100
!-------------------------------------------------------------------------------
101
FUNCTION List_EnlargeMatrix(Matrix,N) RESULT(NewMatrix)
102
!-------------------------------------------------------------------------------
103
INTEGER :: i,n
104
TYPE(ListMatrix_t), POINTER :: Matrix(:), NewMatrix(:)
105
106
NewMatrix => List_AllocateMatrix(n)
107
IF ( ASSOCIATED(Matrix) ) THEN
108
DO i=1,SIZE(Matrix)
109
NewMatrix(i)=Matrix(i)
110
END DO
111
DEALLOCATE(Matrix)
112
END IF
113
!-------------------------------------------------------------------------------
114
END FUNCTION List_EnlargeMatrix
115
!-------------------------------------------------------------------------------
116
117
!-------------------------------------------------------------------------------
118
!> Transfer the flexible list matrix to the more efficient CRS matrix that is
119
!> used in most places of the code. Here the target is the rows and columns of the matrix.
120
!-------------------------------------------------------------------------------
121
SUBROUTINE List_ToCRS(L,Rows,Cols,Diag)
122
!-------------------------------------------------------------------------------
123
TYPE(ListMatrix_t) :: L(:)
124
INTEGER :: i,j,n,istat
125
TYPE(Matrix_t), POINTER :: A
126
TYPE(ListMatrixEntry_t), POINTER :: P
127
INTEGER, POINTER CONTIG :: Rows(:),Cols(:),Diag(:)
128
129
DO n=SIZE(L),1,-1
130
IF ( L(n) % Degree>0 ) EXIT
131
END DO
132
133
ALLOCATE( Rows(n+1), Diag(n), STAT=istat)
134
IF(istat /= 0 ) THEN
135
CALL Fatal('List_ToCRS','Could not allocate memory for CRS Rows of size '//I2S(n))
136
END IF
137
138
139
Rows(1) = 1
140
DO i=1,n
141
Rows(i+1) = Rows(i) + L(i) % Degree
142
END DO
143
ALLOCATE( Cols(Rows(i+1)-1), Stat=istat)
144
IF(istat /= 0 ) THEN
145
CALL Fatal('List_ToCRS','Could not allocate memory for CRS Cols of size '//I2S(Rows(i+1)-1))
146
END IF
147
148
149
j = 0
150
DO i=1,n
151
P => L(i) % Head
152
DO WHILE(ASSOCIATED(P))
153
j = j + 1
154
Cols(j) = P % Index
155
P => P % Next
156
END DO
157
END DO
158
159
CALL Info('List_ToCRS',&
160
'Number of entries in CRS matrix: '//I2S(Rows(n+1)-1),Level=8)
161
162
A => AllocateMatrix()
163
A % NumberOfRows = n
164
A % Rows => Rows
165
A % Diag => Diag
166
A % Cols => Cols
167
CALL CRS_SortMatrix(A)
168
DEALLOCATE(A)
169
!-------------------------------------------------------------------------------
170
END SUBROUTINE List_ToCRS
171
!-------------------------------------------------------------------------------
172
173
174
!-------------------------------------------------------------------------------
175
!> Transfer the flexible list matrix to the more efficient CRS matrix that is
176
!> used in most places of the code. The matrix structure can accommodate both forms.
177
!-------------------------------------------------------------------------------
178
SUBROUTINE List_ToCRSMatrix(A)
179
!-------------------------------------------------------------------------------
180
TYPE(Matrix_t) :: A
181
182
TYPE(ListMatrix_t), POINTER :: L(:)
183
INTEGER :: i,j,k,n,m,istat
184
TYPE(ListMatrixEntry_t), POINTER :: P
185
INTEGER, POINTER CONTIG :: Rows(:),Cols(:),Diag(:)
186
REAL(KIND=dp), POINTER CONTIG :: Values(:)
187
188
IF( A % FORMAT /= MATRIX_LIST ) THEN
189
CALL Warn('List_ToCRSMatrix','The initial matrix type is not List')
190
RETURN
191
END IF
192
193
L => A % ListMatrix
194
195
IF( .NOT. ASSOCIATED( L ) ) THEN
196
A % FORMAT = MATRIX_CRS
197
A % NumberOfRows = 0
198
RETURN
199
END IF
200
201
DO n=SIZE(L),1,-1
202
IF ( L(n) % Degree > 0 ) EXIT
203
END DO
204
CALL Info('List_ToCRSMatrix','List size '//I2S(SIZE(L))//' vs. active rows '//I2S(n),Level=25)
205
206
ALLOCATE( Rows(n+1), Diag(n), STAT=istat)
207
IF(istat /= 0 ) THEN
208
CALL Fatal('List_ToCRSMatrix','Could not allocate memory for CRS Rows of size '//I2S(n))
209
END IF
210
211
Diag = 0
212
Rows(1) = 1
213
DO i=1,n
214
Rows(i+1) = Rows(i) + L(i) % Degree
215
END DO
216
217
m = Rows(n+1)-1
218
CALL Info('List_ToCRSMatrix',&
219
'Changing matrix type with number of non-zeros: '//I2S(m),Level=8)
220
221
ALLOCATE( Cols(m),Values(m),STAT=istat)
222
IF(istat /= 0 ) THEN
223
CALL Fatal('List_ToCRS','Could not allocate memory for CRS Cols & Values of size '//I2S(m))
224
END IF
225
226
j = 0
227
DO i=1,n
228
P => L(i) % Head
229
DO WHILE(ASSOCIATED(P))
230
j = j + 1
231
Cols(j) = P % Index
232
Values(j) = P % Val
233
P => P % Next
234
END DO
235
END DO
236
237
A % NumberOfRows = n
238
A % Rows => Rows
239
A % Diag => Diag
240
A % Cols => Cols
241
A % Values => Values
242
243
A % Ordered=.FALSE.
244
CALL CRS_SortMatrix( A )
245
246
CALL List_FreeMatrix( SIZE(L), L )
247
A % ListMatrix => NULL()
248
249
A % FORMAT = MATRIX_CRS
250
CALL Info('List_ToCRSMatrix','Matrix format changed from List to CRS', Level=12)
251
252
!-------------------------------------------------------------------------------
253
END SUBROUTINE List_ToCRSMatrix
254
!-------------------------------------------------------------------------------
255
256
257
258
!-------------------------------------------------------------------------------
259
!> Convert CRS matrix to list matrix
260
!-------------------------------------------------------------------------------
261
SUBROUTINE List_ToListMatrix(A,Truncate)
262
!-------------------------------------------------------------------------------
263
TYPE(Matrix_t) :: A
264
LOGICAL, OPTIONAL :: Truncate
265
266
INTEGER :: i,j,n
267
LOGICAL :: Trunc
268
TYPE(ListMatrixEntry_t), POINTER :: CList
269
270
Trunc=.FALSE.
271
IF(PRESENT(Truncate)) Trunc=Truncate
272
273
A % ListMatrix => List_AllocateMatrix(A % NumberOfRows)
274
275
DO i=1,A % NumberOfRows
276
A % ListMatrix(i) % Level = 0
277
A % ListMatrix(i) % Degree = 0
278
279
IF(A % Rows(i) == A % Rows(i+1)) THEN
280
A % ListMatrix(i) % Head => NULL()
281
CYCLE
282
END IF
283
284
ALLOCATE(A % ListMatrix(i) % Head)
285
Clist => A % ListMatrix(i) % Head
286
Clist % Next => NULL()
287
288
DO j=A % Rows(i), A % Rows(i+1)-1
289
IF(Trunc) THEN
290
IF (A % Cols(j) > A % NumberOfRows) EXIT
291
END IF
292
293
IF (j>A % Rows(i)) THEN
294
IF ( Clist % Index >= A % Cols(j) ) THEN
295
CALL Warn( 'List_ToListMatrix()', 'Input matrix not ordered ? ')
296
GOTO 100
297
END IF
298
ALLOCATE(Clist % Next)
299
Clist => Clist % Next
300
CList % Next => NULL()
301
END IF
302
303
CList % Val = A % Values(j)
304
CList % Index = A % Cols(j)
305
A % ListMatrix(i) % Degree = A % ListMatrix(i) % Degree + 1
306
END DO
307
END DO
308
309
GOTO 200
310
311
100 CONTINUE
312
313
! If not ordered input ...
314
315
CALL List_FreeMatrix(i,A % ListMatrix)
316
A % ListMatrix => Null()
317
318
DO i=1,A % NumberOfRows
319
DO j=A % Rows(i+1)-1,A % Rows(i),-1
320
IF(Trunc) THEN
321
IF (A % Cols(j) > A % NumberOfRows) CYCLE
322
END IF
323
CALL List_SetMatrixElement(A % ListMatrix,i,A % Cols(j),A % Values(j))
324
END DO
325
END DO
326
327
200 CONTINUE
328
329
A % FORMAT = MATRIX_LIST
330
331
IF( ASSOCIATED( A % Rows ) ) DEALLOCATE( A % Rows )
332
IF( ASSOCIATED( A % Cols ) ) DEALLOCATE( A % Cols )
333
IF( ASSOCIATED( A % Diag ) ) DEALLOCATE( A % Diag )
334
IF( ASSOCIATED( A % Values ) ) DEALLOCATE( A % Values )
335
336
A % Rows => Null()
337
A % Cols => Null()
338
A % Diag => Null()
339
A % Values => NULL()
340
341
! If the CRS matrix had a specific structure it is probably spoiled when going into
342
! free form matrix structure.
343
A % ndeg = -1
344
345
CALL Info('List_ToListMatrix','Matrix format changed from CRS to List', Level=7)
346
!-------------------------------------------------------------------------------
347
END SUBROUTINE List_ToListMatrix
348
!-------------------------------------------------------------------------------
349
350
351
!-------------------------------------------------------------------------------
352
FUNCTION List_GetMatrixIndex(List,k1,k2 ) RESULT(Entry)
353
!-------------------------------------------------------------------------------
354
TYPE(ListMatrix_t), POINTER :: List(:)
355
INTEGER :: k1,k2
356
TYPE(ListMatrixEntry_t), POINTER :: CList,Prev, Entry, Dummy
357
!-------------------------------------------------------------------------------
358
359
INTEGER :: i, istat
360
361
362
IF ( .NOT. ASSOCIATED(List) ) List=>List_AllocateMatrix(k1)
363
364
IF ( k1>SIZE(List) ) THEN
365
List => List_EnlargeMatrix(List,MAX(k1, &
366
SIZE(List)+LISTMATRIX_GROWTH) )
367
END IF
368
369
Clist => List(k1) % Head
370
371
IF ( .NOT. ASSOCIATED(Clist) ) THEN
372
Dummy => NULL()
373
Entry => List_GetMatrixEntry(k2, Dummy )
374
375
List(k1) % Degree = 1
376
List(k1) % Head => Entry
377
RETURN
378
END IF
379
380
NULLIFY( Prev )
381
DO WHILE( ASSOCIATED(CList) )
382
IF ( Clist % INDEX >= k2 ) EXIT
383
Prev => Clist
384
CList => CList % Next
385
END DO
386
387
IF ( ASSOCIATED( CList ) ) THEN
388
IF ( CList % INDEX == k2 ) THEN
389
Entry => Clist
390
RETURN
391
END IF
392
END IF
393
394
Entry => List_GetMatrixEntry(k2, CList)
395
IF ( ASSOCIATED( Prev ) ) THEN
396
Prev % Next => Entry
397
ELSE
398
List(k1) % Head => Entry
399
END IF
400
401
List(k1) % Degree = List(k1) % Degree + 1
402
!-------------------------------------------------------------------------------
403
END FUNCTION List_GetMatrixIndex
404
!-------------------------------------------------------------------------------
405
406
!-------------------------------------------------------------------------------
407
SUBROUTINE List_AddMatrixIndexes(List,k1,nk2,Ind)
408
! Add an array of sorted indeces to a row in ListMatrix_t. "ind" may
409
! contain duplicate entries.
410
!-------------------------------------------------------------------------------
411
IMPLICIT NONE
412
413
TYPE(ListMatrix_t) :: List(:)
414
INTEGER, INTENT(IN) :: k1, nk2
415
INTEGER, INTENT(IN) :: Ind(nk2)
416
417
TYPE(ListMatrixEntry_t), POINTER :: RowPtr, PrevPtr, Entry, Dummy
418
!-------------------------------------------------------------------------------
419
INTEGER :: i,k2,k2i,j, k,prevind
420
421
IF (k1>SIZE(List)) THEN
422
CALL Fatal('List_AddMatrixIndexes','Row index out of bounds: '//TRIM(I2S(k1)))
423
END IF
424
425
! Add each element in Ind to the row list
426
RowPtr => List(k1) % Head
427
428
! First element needs special treatment as it may modify
429
! the list starting point
430
IF (.NOT. ASSOCIATED(RowPtr)) THEN
431
Dummy => NULL()
432
Entry => List_GetMatrixEntry(Ind(1),Dummy)
433
List(k1) % Degree = 1
434
List(k1) % Head => Entry
435
k2i = 2
436
prevind = ind(1)
437
ELSE IF (RowPtr % Index > Ind(1)) THEN
438
Entry => List_GetMatrixEntry(Ind(1),RowPtr)
439
List(k1) % Degree = List(k1) % Degree + 1
440
List(k1) % Head => Entry
441
k2i = 2
442
prevind = ind(1)
443
ELSE IF (RowPtr % Index == Ind(1)) THEN
444
k2i = 2
445
prevind = ind(1)
446
ELSE
447
k2i = 1
448
prevind = -1
449
END IF
450
451
PrevPtr => List(k1) % Head
452
RowPtr => List(k1) % Head % Next
453
454
DO i=k2i,nk2
455
k2=Ind(i)
456
if (k2 == prevind) cycle
457
458
! Find a correct place place to add index to
459
DO WHILE( ASSOCIATED(RowPtr) )
460
IF (RowPtr % Index >= k2) EXIT
461
PrevPtr => RowPtr
462
RowPtr => RowPtr % Next
463
END DO
464
465
IF (ASSOCIATED(RowPtr)) THEN
466
! Do not add duplicates
467
IF (RowPtr % Index /= k2) THEN
468
! Create new element between PrevPtr and RowPtr
469
Entry => List_GetMatrixEntry(k2,RowPtr)
470
PrevPtr % Next => Entry
471
List(k1) % Degree = List(k1) % Degree + 1
472
473
! Advance to next element in list
474
PrevPtr => Entry
475
! RowPtr =>
476
ELSE
477
! Advance to next element in list
478
PrevPtr => RowPtr
479
RowPtr => RowPtr % Next
480
END IF
481
ELSE
482
EXIT
483
END IF
484
485
prevind = k2
486
END DO
487
488
DO j=i,nk2
489
k2 = Ind(j)
490
if (k2 == prevind) cycle
491
prevind = k2
492
493
Dummy => NULL()
494
Entry => List_GetMatrixEntry(k2,Dummy)
495
PrevPtr % Next => Entry
496
PrevPtr => PrevPtr % Next
497
List(k1) % Degree = List(k1) % Degree + 1
498
END DO
499
!-------------------------------------------------------------------------------
500
END SUBROUTINE List_AddMatrixIndexes
501
!-------------------------------------------------------------------------------
502
503
504
!-------------------------------------------------------------------------------
505
SUBROUTINE List_AddMatrixRow(List,k1,nk2,Ind,Vals,SortedInput)
506
! Add an array of sorted indeces to a row in ListMatrix_t. "ind" may
507
! contain duplicate entries.
508
!-------------------------------------------------------------------------------
509
IMPLICIT NONE
510
511
TYPE(ListMatrix_t) :: List(:)
512
LOGICAL, INTENT(IN), OPTIONAL :: SortedInput
513
INTEGER, INTENT(IN) :: k1, nk2
514
INTEGER, INTENT(INOUT) :: Ind(nk2)
515
REAL(KIND=dp), INTENT(INOUT) :: Vals(nk2)
516
517
TYPE(ListMatrixEntry_t), POINTER :: RowPtr, PrevPtr, Entry, Dummy
518
!-------------------------------------------------------------------------------
519
INTEGER :: i,k2,k2i,j, k,prevind
520
521
IF (k1>SIZE(List)) THEN
522
CALL Fatal('List_AddMatrixIndexes','Row index out of bounds: '//TRIM(I2S(k1)))
523
END IF
524
525
IF( PRESENT(SortedInput) ) THEN
526
IF ( .NOT. SortedInput ) CALL SortF(nk2, Ind, Vals)
527
ELSE
528
CALL SortF(nk2, Ind, Vals)
529
END IF
530
531
532
! Add each element in Ind to the row list
533
RowPtr => List(k1) % Head
534
535
! First element needs special treatment as it may modify
536
! the list starting point
537
IF (.NOT. ASSOCIATED(RowPtr)) THEN
538
Dummy => NULL()
539
Entry => List_GetMatrixEntry(Ind(1),Dummy)
540
Entry % Val = Vals(1)
541
List(k1) % Degree = 1
542
List(k1) % Head => Entry
543
k2i = 2
544
prevind = ind(1)
545
ELSE IF (RowPtr % Index > Ind(1)) THEN
546
Entry => List_GetMatrixEntry(Ind(1),RowPtr)
547
Entry % Val = Vals(1)
548
List(k1) % Degree = List(k1) % Degree + 1
549
List(k1) % Head => Entry
550
k2i = 2
551
prevind = IND(1)
552
ELSE IF (RowPtr % Index == Ind(1)) THEN
553
k2i = 2
554
prevind = ind(1)
555
RowPtr % Val = RowPtr % Val + Vals(1)
556
ELSE
557
k2i = 1
558
prevind = -1
559
END IF
560
561
PrevPtr => List(k1) % Head
562
RowPtr => List(k1) % Head % Next
563
564
DO i=k2i,nk2
565
k2 = Ind(i)
566
IF(k2 == prevind) THEN
567
CYCLE
568
END IF
569
570
! Find a correct place place to add index to
571
DO WHILE( ASSOCIATED(RowPtr) )
572
IF (RowPtr % Index >= k2) EXIT
573
PrevPtr => RowPtr
574
RowPtr => RowPtr % Next
575
END DO
576
577
IF (ASSOCIATED(RowPtr)) THEN
578
! Do not add duplicates
579
IF (RowPtr % Index /= k2) THEN
580
! Create new element between PrevPtr and RowPtr
581
Entry => List_GetMatrixEntry(k2,RowPtr)
582
Entry % Val = Vals(i)
583
PrevPtr % Next => Entry
584
List(k1) % Degree = List(k1) % Degree + 1
585
586
! Advance to next element in list
587
PrevPtr => Entry
588
ELSE
589
! Advance to next element in list
590
RowPtr % Val = RowPtr % Val + Vals(i)
591
PrevPtr => RowPtr
592
RowPtr => RowPtr % Next
593
END IF
594
ELSE
595
EXIT
596
END IF
597
598
prevind = k2
599
END DO
600
601
DO j=i,nk2
602
k2 = Ind(j)
603
IF (k2 == prevind) THEN
604
cycle
605
END IF
606
prevind = k2
607
608
Dummy => NULL()
609
Entry => List_GetMatrixEntry(k2,Dummy)
610
Entry % Val = Vals(j)
611
PrevPtr % Next => Entry
612
PrevPtr => PrevPtr % Next
613
List(k1) % Degree = List(k1) % Degree + 1
614
END DO
615
!-------------------------------------------------------------------------------
616
END SUBROUTINE List_AddMatrixRow
617
!-------------------------------------------------------------------------------
618
619
620
621
!-------------------------------------------------------------------------------
622
FUNCTION List_GetMatrixEntry(ind, next) RESULT(ListEntry)
623
!-------------------------------------------------------------------------------
624
IMPLICIT NONE
625
626
INTEGER, INTENT(IN) :: ind
627
TYPE(ListMatrixEntry_t), POINTER, INTENT(IN) :: next
628
TYPE(ListMatrixEntry_t), POINTER :: ListEntry
629
630
INTEGER :: istat
631
632
ALLOCATE(ListEntry, STAT=istat)
633
IF( istat /= 0 ) THEN
634
CALL Fatal('List_GetMatrixEntry','Could not allocate entry!')
635
END IF
636
637
ListEntry % Val = REAL(0,dp)
638
ListEntry % INDEX = ind
639
ListEntry % Next => next
640
!-------------------------------------------------------------------------------
641
END FUNCTION List_GetMatrixEntry
642
!-------------------------------------------------------------------------------
643
644
!-------------------------------------------------------------------------------
645
SUBROUTINE List_DeleteMatrixElement(List,k1,k2)
646
!-------------------------------------------------------------------------------
647
INTEGER :: k1,k2
648
TYPE(ListMatrix_t) :: List(:)
649
!-------------------------------------------------------------------------------
650
TYPE(ListMatrixEntry_t), POINTER :: Clist,Prev
651
652
Prev => NULL()
653
Clist => List(k1) % Head
654
DO WHILE(ASSOCIATED(Clist))
655
IF (Clist % Index >= k2) EXIT
656
Prev => Clist
657
Clist => Clist % Next
658
END DO
659
IF (.NOT.ASSOCIATED(Clist)) RETURN
660
661
IF (Clist % Index /= k2) RETURN
662
663
IF (ASSOCIATED(Prev)) THEN
664
Prev % Next => Clist % Next
665
ELSE
666
List(k1) % Head => Clist % Next
667
END IF
668
DEALLOCATE(Clist)
669
List(k1) % Degree = MAX(List(k1) % Degree-1,0)
670
!-------------------------------------------------------------------------------
671
END SUBROUTINE List_DeleteMatrixElement
672
!-------------------------------------------------------------------------------
673
674
675
!-------------------------------------------------------------------------------
676
SUBROUTINE List_DeleteRow(List,k1,Keep)
677
!-------------------------------------------------------------------------------
678
INTEGER :: k1,k2
679
LOGICAL, OPTIONAL :: Keep
680
TYPE(ListMatrix_t) :: List(:)
681
!-------------------------------------------------------------------------------
682
LOGICAL :: lKeep
683
INTEGER::n
684
TYPE(ListMatrixEntry_t), POINTER :: Clist,Next
685
686
n = SIZE(List)
687
IF(k1<=0.OR.k1>n) RETURN
688
689
Clist=>List(k1) % Head
690
DO WHILE(ASSOCIATED(Clist))
691
Next=>Clist % Next
692
DEALLOCATE(Clist)
693
Clist=>Next
694
END DO
695
696
lKeep = .FALSE.
697
IF(PRESENT(Keep)) lKeep = Keep
698
699
IF(lKeep) THEN
700
List(k1) % Degree=0
701
List(k1) % Head=>NULL()
702
ELSE
703
List(k1:n-1)=List(k1+1:n)
704
List(n) % Degree=0
705
List(n) % Head=>NULL()
706
END IF
707
!-------------------------------------------------------------------------------
708
END SUBROUTINE List_DeleteRow
709
!-------------------------------------------------------------------------------
710
711
712
!-------------------------------------------------------------------------------
713
SUBROUTINE List_DeleteCol(List,k1)
714
!-------------------------------------------------------------------------------
715
INTEGER :: k1
716
TYPE(ListMatrix_t) :: List(:)
717
!-------------------------------------------------------------------------------
718
INTEGER::i,n
719
TYPE(ListMatrixEntry_t), POINTER :: Clist,Prev
720
721
n=SIZE(List)
722
723
DO i=1,n
724
Prev => NULL()
725
Clist => List(i) % Head
726
DO WHILE(ASSOCIATED(Clist))
727
IF(Clist % Index>=k1) EXIT
728
Prev => Clist
729
Clist => Clist % Next
730
END DO
731
732
IF(.NOT.ASSOCIATED(Clist)) CYCLE
733
734
IF (Clist % Index==k1) THEN
735
IF(ASSOCIATED(Prev)) THEN
736
Prev % Next => Clist % Next
737
ELSE
738
List(i) % Head => Clist % Next
739
END IF
740
List(i) % Degree = MAX(List(i) % Degree-1,0)
741
DEALLOCATE(Clist)
742
END IF
743
END DO
744
!-------------------------------------------------------------------------------
745
END SUBROUTINE List_DeleteCol
746
!-------------------------------------------------------------------------------
747
748
749
!-------------------------------------------------------------------------------
750
SUBROUTINE List_AddToMatrixElement( List,k1,k2,Val,SetVal )
751
!-------------------------------------------------------------------------------
752
TYPE(ListMatrix_t), POINTER :: List(:)
753
INTEGER :: k1,k2
754
REAL(KIND=dp) :: Val
755
LOGICAL, OPTIONAL :: SetVal
756
!-------------------------------------------------------------------------------
757
TYPE(ListMatrixEntry_t), POINTER :: CList,Prev, Entry
758
LOGICAL :: Set
759
760
Set = .FALSE.
761
IF( PRESENT(SetVal)) Set = SetVal
762
763
Entry => List_GetMatrixIndex(List,k1,k2)
764
IF ( Set ) THEN
765
Entry % Val = Val
766
ELSE
767
Entry % Val = Entry % Val + Val
768
END IF
769
!-------------------------------------------------------------------------------
770
END SUBROUTINE List_AddToMatrixElement
771
!-------------------------------------------------------------------------------
772
773
!-------------------------------------------------------------------------------
774
SUBROUTINE List_AddMatrixIndex( List,k1,k2 )
775
!-------------------------------------------------------------------------------
776
TYPE(ListMatrix_t), POINTER :: List(:)
777
INTEGER :: k1,k2
778
!-------------------------------------------------------------------------------
779
TYPE(ListMatrixEntry_t), POINTER :: CList,Prev, Entry
780
LOGICAL :: Set
781
782
Entry => List_GetMatrixIndex(List,k1,k2)
783
!-------------------------------------------------------------------------------
784
END SUBROUTINE List_AddMatrixIndex
785
!-------------------------------------------------------------------------------
786
787
788
!-------------------------------------------------------------------------------
789
SUBROUTINE List_SetMatrixElement( List,k1,k2,Val,SetVal )
790
!-------------------------------------------------------------------------------
791
TYPE(ListMatrix_t), POINTER :: List(:)
792
INTEGER :: k1,k2
793
TYPE(ListMatrixEntry_t), POINTER :: CList,Prev, Entry
794
REAL(KIND=dp) :: Val
795
LOGICAL, OPTIONAL :: SetVal
796
797
CALL List_AddToMatrixElement( List,k1,k2,Val,.TRUE.)
798
!-------------------------------------------------------------------------------
799
END SUBROUTINE List_SetMatrixElement
800
!-------------------------------------------------------------------------------
801
802
803
!-------------------------------------------------------------------------------
804
FUNCTION List_GetMatrixElement( List,k1,k2 ) RESULT ( Val )
805
!-------------------------------------------------------------------------------
806
TYPE(ListMatrix_t), POINTER :: List(:)
807
INTEGER :: k1,k2
808
TYPE(ListMatrixEntry_t), POINTER :: CList,Prev, Entry
809
REAL(KIND=dp) :: Val
810
!-------------------------------------------------------------------------------
811
812
Val = 0.0_dp
813
814
IF ( .NOT. ASSOCIATED(List) ) RETURN
815
IF ( k1>SIZE(List) ) RETURN
816
Clist => List(k1) % Head
817
IF ( .NOT. ASSOCIATED(Clist) ) RETURN
818
819
NULLIFY( Prev )
820
DO WHILE( ASSOCIATED(CList) )
821
IF ( Clist % INDEX == k2 ) Val = CList % Val
822
IF ( Clist % INDEX >= k2 ) RETURN
823
Prev => Clist
824
CList => CList % Next
825
END DO
826
!-------------------------------------------------------------------------------
827
END FUNCTION List_GetMatrixElement
828
!-------------------------------------------------------------------------------
829
830
831
!-------------------------------------------------------------------------------
832
SUBROUTINE List_ZeroRow( List,k1 )
833
!-------------------------------------------------------------------------------
834
TYPE(ListMatrix_t), POINTER :: List(:)
835
INTEGER :: k1
836
!-------------------------------------------------------------------------------
837
TYPE(ListMatrixEntry_t), POINTER :: CList
838
839
IF ( .NOT. ASSOCIATED(List) ) THEN
840
CALL Warn('List_ZeroRow','No List matrix present!')
841
RETURN
842
END IF
843
844
IF ( k1 > SIZE(List) ) THEN
845
CALL Warn('List_ZeroRow','No such row!')
846
RETURN
847
END IF
848
849
Clist => List(k1) % Head
850
IF ( .NOT. ASSOCIATED(Clist) ) THEN
851
CALL Warn('List_ZeroRow','Row not associated!')
852
RETURN
853
END IF
854
855
DO WHILE( ASSOCIATED(CList) )
856
Clist % Val = 0.0_dp
857
CList => CList % Next
858
END DO
859
!-------------------------------------------------------------------------------
860
END SUBROUTINE List_ZeroRow
861
!-------------------------------------------------------------------------------
862
863
864
!-------------------------------------------------------------------------------
865
SUBROUTINE List_MoveRow( List,n1,n2,coeff,staycoeff )
866
!-------------------------------------------------------------------------------
867
TYPE(ListMatrix_t), POINTER :: List(:)
868
INTEGER :: n1, n2
869
REAL(KIND=dp), OPTIONAL :: coeff, staycoeff
870
!-------------------------------------------------------------------------------
871
INTEGER :: k2
872
REAL(KIND=dp) :: val, c, d
873
TYPE(ListMatrixEntry_t), POINTER :: CList
874
875
IF( PRESENT(coeff)) THEN
876
c = coeff
877
ELSE
878
c = 1.0_dp
879
END IF
880
881
IF( PRESENT(staycoeff)) THEN
882
d = staycoeff
883
ELSE
884
d = 0.0_dp
885
END IF
886
887
IF ( .NOT. ASSOCIATED(List) ) THEN
888
CALL Warn('List_MoveRow','No List matrix present!')
889
RETURN
890
END IF
891
892
IF ( n1 > SIZE(List) ) THEN
893
CALL Warn('List_MoveRow','No row to move!')
894
RETURN
895
END IF
896
897
Clist => List(n1) % Head
898
IF ( .NOT. ASSOCIATED(Clist) ) THEN
899
CALL Warn('List_MoveRow','Row not associated!')
900
RETURN
901
END IF
902
903
DO WHILE( ASSOCIATED(CList) )
904
k2 = Clist % Index
905
Val = Clist % Val
906
Clist % VAL = d * Val
907
908
! This could be made more optimal as all the entries are for the same row!
909
CALL List_AddToMatrixElement(List,n2,k2,c*Val)
910
911
CList => CList % Next
912
END DO
913
914
!-------------------------------------------------------------------------------
915
END SUBROUTINE List_MoveRow
916
!-------------------------------------------------------------------------------
917
918
919
! Exchange row structure between two matrix rows.
920
! Currently this is not optimal since we copy the structure back-and-forth.
921
!-------------------------------------------------------------------------------
922
SUBROUTINE List_ExchangeRowStructure( List,n1,n2 )
923
!-------------------------------------------------------------------------------
924
TYPE(ListMatrix_t), POINTER :: List(:)
925
INTEGER :: n1, n2
926
!-------------------------------------------------------------------------------
927
INTEGER :: k1, k2
928
TYPE(ListMatrixEntry_t), POINTER :: CList1, CList2, Lptr
929
930
IF ( .NOT. ASSOCIATED(List) ) THEN
931
CALL Warn('List_ExchangeRowStructure','No List matrix present!')
932
RETURN
933
END IF
934
935
Clist1 => List(n1) % Head
936
IF ( .NOT. ASSOCIATED(Clist1) ) THEN
937
CALL Warn('List__ExchangeRowStructure','Row1 not associated!')
938
RETURN
939
END IF
940
941
Clist2 => List(n2) % Head
942
IF ( .NOT. ASSOCIATED(Clist2) ) THEN
943
CALL Warn('List__ExchangeRowStructure','Row2 not associated!')
944
RETURN
945
END IF
946
947
DO WHILE( ASSOCIATED(CList1) )
948
k1 = Clist1 % Index
949
Lptr => List_GetMatrixIndex( List,n2,k1 )
950
CList1 => CList1 % Next
951
END DO
952
953
DO WHILE( ASSOCIATED(CList2) )
954
k2 = Clist2 % Index
955
Lptr => List_GetMatrixIndex( List,n1,k2 )
956
CList2 => CList2 % Next
957
END DO
958
959
!-------------------------------------------------------------------------------
960
END SUBROUTINE List_ExchangeRowStructure
961
!-------------------------------------------------------------------------------
962
963
964
965
!------------------------------------------------------------------------------
966
!> Add the entries of a local matrix to a list-format matrix.
967
!------------------------------------------------------------------------------
968
SUBROUTINE List_GlueLocalMatrix( A,N,Dofs,Indexes,LocalMatrix )
969
!------------------------------------------------------------------------------
970
TYPE(ListMatrix_t), POINTER :: A(:)
971
INTEGER :: N,DOFs, Indexes(:)
972
REAL(KIND=dp) :: LocalMatrix(:,:)
973
!------------------------------------------------------------------------------
974
! Local variables
975
!------------------------------------------------------------------------------
976
REAL(KIND=dp) :: Val
977
INTEGER :: i,j,k,l,c,Row,Col
978
979
DO i=1,n
980
IF (Indexes(i)<=0) CYCLE
981
DO k=0,Dofs-1
982
Row = Dofs*Indexes(i)-k
983
DO j=1,n
984
IF (Indexes(j)<=0) CYCLE
985
DO l=0,Dofs-1
986
Col = Dofs * Indexes(j) - l
987
Val = LocalMatrix(Dofs*i-k,Dofs*j-l)
988
CALL List_AddToMatrixElement(A,Row,Col,Val)
989
END DO
990
END DO
991
992
END DO
993
END DO
994
END SUBROUTINE List_GlueLocalMatrix
995
!------------------------------------------------------------------------------
996
997
!------------------------------------------------------------------------------
998
!> Add the entries of a local matrix to a list-format matrix by allowing
999
!> offsets
1000
!------------------------------------------------------------------------------
1001
SUBROUTINE List_GlueLocalSubMatrix( List,row0,col0,Nrow,Ncol, &
1002
RowInds,ColInds,RowDofs,ColDofs,LocalMatrix )
1003
!------------------------------------------------------------------------------
1004
TYPE(ListMatrix_t), POINTER :: List(:)
1005
INTEGER :: Nrow,Ncol,RowDofs,ColDofs,Col0,Row0,RowInds(:),ColInds(:)
1006
REAL(KIND=dp) :: LocalMatrix(:,:)
1007
!------------------------------------------------------------------------------
1008
! Local variables
1009
!------------------------------------------------------------------------------
1010
REAL(KIND=dp) :: Val
1011
INTEGER :: i,j,k,l,c,Row,Col
1012
1013
DO i=1,Nrow
1014
DO k=0,RowDofs-1
1015
IF ( RowInds(i) <= 0 ) CYCLE
1016
Row = Row0 + RowDofs * RowInds(i) - k
1017
1018
DO j=1,Ncol
1019
DO l=0,ColDofs-1
1020
IF ( ColInds(j) <= 0 ) CYCLE
1021
Col = Col0 + ColDofs * ColInds(j) - l
1022
Val = LocalMatrix(RowDofs*i-k,ColDofs*j-l)
1023
CALL List_AddToMatrixElement(List,Row,Col,Val)
1024
END DO
1025
END DO
1026
1027
END DO
1028
END DO
1029
END SUBROUTINE List_GlueLocalSubMatrix
1030
!------------------------------------------------------------------------------
1031
1032
END MODULE ListMatrix
1033
1034
!> \} ElmerLib
1035
1036
1037
1038