Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/fem/src/ListMatrixArray.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: Mikko Byckling
27
! *
28
! * Original Date: 25 September 2017
29
! *
30
! ****************************************************************************/
31
32
!> \ingroup ElmerLib
33
!> \{
34
35
36
MODULE ListMatrixArray
37
USE Messages
38
USE Types
39
USE GeneralUtils, ONLY : I2S
40
41
IMPLICIT NONE
42
CONTAINS
43
44
!-------------------------------------------------------------------------------
45
!> Allocates an empty array list matrix.
46
!-------------------------------------------------------------------------------
47
SUBROUTINE ListMatrixArray_Allocate(ListMatrixArray, N, PoolSize, Atomic)
48
IMPLICIT NONE
49
TYPE(ListMatrixArray_t) :: ListMatrixArray
50
INTEGER,INTENT(IN) :: N
51
INTEGER, OPTIONAL :: PoolSize
52
LOGICAL, OPTIONAL :: Atomic
53
54
INTEGER :: i,istat, nthr, TID, psize
55
LOGICAL :: InitLocks
56
57
psize = 1024
58
IF (PRESENT(PoolSize)) psize = PoolSize
59
60
InitLocks = .FALSE.
61
IF (PRESENT(Atomic)) InitLocks = Atomic
62
63
! Allocate ListMatrix and associated pools
64
nthr = 1
65
!$ nthr = omp_get_max_threads()
66
ALLOCATE( ListMatrixArray % Rows(n), &
67
ListMatrixArray % Pool(nthr), STAT=istat )
68
IF( istat /= 0 ) THEN
69
CALL Fatal('ListMatrixArray_AllocateMatrix',&
70
'Allocation error for ListMatrix of size: '//I2S(n))
71
END IF
72
IF (InitLocks) CALL ListMatrixArray_InitializeAtomic(ListMatrixArray)
73
74
!$OMP PARALLEL &
75
!$OMP SHARED(ListMatrixArray, N, psize) &
76
!$OMP PRIVATE(i, TID) DEFAULT(NONE)
77
78
TID = 1
79
!$ TID = omp_get_thread_num()+1
80
81
CALL ListMatrixPool_Initialize(ListMatrixArray % Pool(TID), psize)
82
83
!$OMP DO
84
DO i=1,N
85
ListMatrixArray % Rows(i) % Head => NULL()
86
ListMatrixArray % Rows(i) % Level = 0
87
ListMatrixArray % Rows(i) % Degree = 0
88
END DO
89
!$OMP END DO NOWAIT
90
!$OMP END PARALLEL
91
END SUBROUTINE ListMatrixArray_Allocate
92
93
!-------------------------------------------------------------------------------
94
!> Free an array list matrix.
95
!-------------------------------------------------------------------------------
96
SUBROUTINE ListMatrixArray_Free( ListMatrixArray )
97
IMPLICIT NONE
98
TYPE(ListMatrixArray_t) :: ListMatrixArray
99
100
TYPE(ListMatrixEntryPool_t), POINTER :: p, p1
101
INTEGER :: N,TID
102
103
N = SIZE(ListMatrixArray % Pool)
104
!$OMP PARALLEL &
105
!$OMP SHARED(ListMatrixArray, N) &
106
!$OMP PRIVATE(p, p1, TID) DEFAULT(NONE)
107
108
!$OMP DO
109
DO TID=1,N
110
CALL ListMatrixPool_Free(ListMatrixArray % Pool(TID))
111
END DO
112
!$OMP END DO
113
!$OMP END PARALLEL
114
115
CALL ListMatrixArray_FreeAtomic(ListMatrixArray)
116
117
DEALLOCATE(ListMatrixArray % Rows, ListMatrixArray % Pool)
118
END SUBROUTINE ListMatrixArray_Free
119
120
SUBROUTINE ListMatrixArray_InitializeAtomic(ListMatrixArray)
121
IMPLICIT NONE
122
TYPE(ListMatrixArray_t) :: ListMatrixArray
123
124
INTEGER :: i, N, istat
125
126
#ifdef _OPENMP
127
N = SIZE(ListMatrixArray % Rows)
128
129
ALLOCATE( ListMatrixArray % RowLocks(n), STAT=istat )
130
IF( istat /= 0 ) THEN
131
CALL Fatal('ListMatrixArray_InitializeAtomic',&
132
'Allocation error for ListMatrix row locks of size: '//I2S(n))
133
END IF
134
135
!$OMP PARALLEL DO &
136
!$OMP SHARED(ListMatrixArray,N) &
137
!$OMP PRIVATE(i) DEFAULT(NONE)
138
DO i=1,N
139
CALL omp_init_lock(ListMatrixArray % RowLocks(i))
140
END DO
141
!$OMP END PARALLEL DO
142
#endif
143
END SUBROUTINE ListMatrixArray_InitializeAtomic
144
145
SUBROUTINE ListMatrixArray_FreeAtomic(ListMatrixArray)
146
IMPLICIT NONE
147
TYPE(ListMatrixArray_t) :: ListMatrixArray
148
149
INTEGER :: i, N
150
151
#ifdef _OPENMP
152
IF (ALLOCATED(ListMatrixArray % RowLocks)) THEN
153
N = SIZE(ListMatrixArray % RowLocks)
154
155
!$OMP PARALLEL DO &
156
!$OMP SHARED(ListMatrixArray,N) &
157
!$OMP PRIVATE(i) DEFAULT(NONE)
158
DO i=1,N
159
CALL omp_destroy_lock(ListMatrixArray % RowLocks(i))
160
END DO
161
!$OMP END PARALLEL DO
162
163
DEALLOCATE(ListMatrixArray % RowLocks)
164
END IF
165
#endif
166
END SUBROUTINE ListMatrixArray_FreeAtomic
167
168
SUBROUTINE ListMatrixArray_LockRow(ListMatrixArray, row, Atomic)
169
IMPLICIT NONE
170
TYPE(ListMatrixArray_t) :: ListMatrixArray
171
INTEGER, INTENT(IN) :: row
172
LOGICAL, OPTIONAL :: Atomic
173
174
#ifdef _OPENMP
175
IF (PRESENT(ATOMIC)) THEN
176
IF (Atomic) CALL omp_set_lock(ListMatrixArray % RowLocks(row))
177
END IF
178
#endif
179
END SUBROUTINE ListMatrixArray_LockRow
180
181
SUBROUTINE ListMatrixArray_UnlockRow(ListMatrixArray, row, Atomic)
182
IMPLICIT NONE
183
TYPE(ListMatrixArray_t) :: ListMatrixArray
184
INTEGER, INTENT(IN) :: row
185
LOGICAL, OPTIONAL :: Atomic
186
187
#ifdef _OPENMP
188
IF (PRESENT(ATOMIC)) THEN
189
IF (Atomic) CALL omp_unset_lock(ListMatrixArray % RowLocks(row))
190
END IF
191
#endif
192
END SUBROUTINE ListMatrixArray_UnlockRow
193
194
!-------------------------------------------------------------------------------
195
!> Transfer sparsity pattern of the array list matrix format to a graph format,
196
!> used in most places of the code.
197
!-------------------------------------------------------------------------------
198
SUBROUTINE ListMatrixArray_ToGraph( ListMatrixArray, Graph)
199
IMPLICIT NONE
200
TYPE(ListMatrixArray_t) :: ListMatrixArray
201
TYPE(Graph_t) :: Graph
202
203
! TODO
204
CALL Fatal('ListMatrixArray_ToGraph','Not implemented yet!')
205
END SUBROUTINE ListMatrixArray_ToGraph
206
207
!-------------------------------------------------------------------------------
208
!> Transfer the flexible list matrix to the more efficient CRS matrix that is
209
!> used in most places of the code. The matrix structure can accommodate both forms.
210
!-------------------------------------------------------------------------------
211
SUBROUTINE ListMatrixArray_ToCRSMatrix( ListMatrixArray, CRSMatrix )
212
IMPLICIT NONE
213
TYPE(ListMatrixArray_t) :: ListMatrixArray
214
TYPE(Matrix_t) :: CRSMatrix
215
216
! TODO
217
CALL Fatal('ListMatrixArray_ToCRSMatrix','Not implemented yet!')
218
END SUBROUTINE ListMatrixArray_ToCRSMatrix
219
220
SUBROUTINE ListMatrixArray_FromCRSMatrix( ListMatrixArray, CRSMatrix )
221
IMPLICIT NONE
222
TYPE(ListMatrixArray_t) :: ListMatrixArray
223
TYPE(Matrix_t) :: CRSMatrix
224
225
! TODO
226
CALL Fatal('ListMatrixArray_FromCRSMatrix','Not implemented yet!')
227
END SUBROUTINE ListMatrixArray_FromCRSMatrix
228
229
!-------------------------------------------------------------------------------
230
!> Add index (row,col) to the matrix sparsity structure
231
!-------------------------------------------------------------------------------
232
SUBROUTINE ListMatrixArray_AddEntry(ListMatrixArray, row, col, val, Atomic)
233
IMPLICIT NONE
234
TYPE(ListMatrixArray_t) :: ListMatrixArray
235
INTEGER, INTENT(IN) :: row, col
236
REAL(KIND=dp), OPTIONAL :: val
237
LOGICAL, OPTIONAL :: Atomic
238
239
TYPE(ListMatrixEntry_t), POINTER :: CEntryPtr, PEntryPtr, NEntryPtr
240
INTEGER :: TID
241
242
TID = 1
243
!$ TID = omp_get_thread_num() + 1
244
245
CALL ListMatrixArray_LockRow(ListMatrixArray, row, Atomic)
246
247
CEntryPtr => ListMatrixArray % Rows(row) % Head
248
IF (.NOT. ASSOCIATED(CEntryPtr)) THEN
249
! Empty matrix row, add entry and return
250
ListMatrixArray % Rows(row) % Head => &
251
ListMatrixPool_GetListEntry(ListMatrixArray % Pool(TID), col, NULL())
252
ListMatrixArray % Rows(row) % Degree = 1
253
CALL ListMatrixArray_UnlockRow(ListMatrixArray, row, Atomic)
254
RETURN
255
ELSE IF (CEntryPtr % Index == col) THEN
256
! Do not add duplicates, nothing to do!
257
CALL ListMatrixArray_UnlockRow(ListMatrixArray, row, Atomic)
258
RETURN
259
ELSE IF (CEntryPtr % Index > col) THEN
260
! Add a new entry to the Head of list
261
ListMatrixArray % Rows(row) % Head => &
262
ListMatrixPool_GetListEntry(ListMatrixArray % Pool(TID), col, CEntryPtr)
263
ListMatrixArray % Rows(row) % Degree = &
264
ListMatrixArray % Rows(row) % Degree + 1
265
CALL ListMatrixArray_UnlockRow(ListMatrixArray, row, Atomic)
266
RETURN
267
END IF
268
269
! Search a correct place for the element
270
PEntryPtr => CEntryPtr
271
CEntryPtr => CEntryPtr % Next
272
273
DO WHILE( ASSOCIATED(CEntryPtr) )
274
! Do not add duplicates
275
IF (CEntryPtr % Index == col) THEN
276
CALL ListMatrixArray_UnlockRow(ListMatrixArray, row, Atomic)
277
RETURN
278
END IF
279
! Place found, exit search loop
280
IF (CEntryPtr % Index > col) EXIT
281
282
PEntryPtr => CEntryPtr
283
CEntryPtr => CEntryPtr % Next
284
END DO
285
286
! Add entry to the correct place in the list
287
PEntryPtr % Next => ListMatrixPool_GetListEntry(ListMatrixArray % Pool(TID), col, CEntryPtr)
288
ListMatrixArray % Rows(row) % Degree = &
289
ListMatrixArray % Rows(row) % Degree + 1
290
CALL ListMatrixArray_UnlockRow(ListMatrixArray, row, Atomic)
291
END SUBROUTINE ListMatrixArray_AddEntry
292
293
!-------------------------------------------------------------------------------
294
!> Add indexes on a single row to the matrix sparsity structure.
295
!-------------------------------------------------------------------------------
296
SUBROUTINE ListMatrixArray_AddEntries(ListMatrixArray, row, nentry, Indexes, Perm, Atomic)
297
IMPLICIT NONE
298
TYPE(ListMatrixArray_t) :: ListMatrixArray
299
INTEGER, INTENT(IN) :: row, nentry
300
INTEGER, INTENT(IN) :: Indexes(nentry), Perm(nentry)
301
LOGICAL, OPTIONAL :: Atomic
302
303
TYPE(ListMatrixEntry_t), POINTER :: CEntryPtr, PEntryPtr, NEntryPtr
304
INTEGER :: TID, centry, sentry, rentry, col
305
306
TID = 1
307
!$ TID = omp_get_thread_num() + 1
308
309
CALL ListMatrixArray_LockRow(ListMatrixArray, row, Atomic)
310
311
CEntryPtr => ListMatrixArray % Rows(row) % Head
312
sentry = 1
313
col = Indexes(Perm(1))
314
IF (.NOT. ASSOCIATED(CEntryPtr)) THEN
315
! Empty matrix row, add entry and continue
316
CEntryPtr => ListMatrixPool_GetListEntry(ListMatrixArray % Pool(TID), col, NULL())
317
ListMatrixArray % Rows(row) % Head => CEntryPtr
318
ListMatrixArray % Rows(row) % Degree = 1
319
sentry = 2
320
ELSE IF (CEntryPtr % Index == col) THEN
321
! Do not add duplicates, continue with next element!
322
sentry = 2
323
ELSE IF (CEntryPtr % Index > col) THEN
324
! Add a new entry to the Head of list
325
NEntryPtr => ListMatrixPool_GetListEntry(ListMatrixArray % Pool(TID), col, CEntryPtr)
326
CEntryPtr => NEntryPtr
327
ListMatrixArray % Rows(row) % Head => CEntryPtr
328
ListMatrixArray % Rows(row) % Degree = &
329
ListMatrixArray % Rows(row) % Degree + 1
330
sentry = 2
331
END IF
332
333
! Search a correct place for the element
334
PEntryPtr => CEntryPtr
335
CEntryPtr => CEntryPtr % Next
336
337
DO centry=sentry,nentry
338
col=Indexes(Perm(centry))
339
340
! Find a correct place to add index to
341
DO WHILE( ASSOCIATED(CEntryPtr) )
342
IF (CEntryPtr % Index >= col) EXIT
343
PEntryPtr => CEntryPtr
344
CEntryPtr => PEntryPtr % Next
345
END DO
346
347
IF (ASSOCIATED(CEntryPtr)) THEN
348
! Do not add duplicates
349
IF (CEntryPtr % Index /= col) THEN
350
! Create new element between PEntryPtr and CEntryPtr
351
NEntryPtr => ListMatrixPool_GetListEntry(ListMatrixArray % Pool(TID), col, CEntryPtr)
352
PEntryPtr % Next => NEntryPtr
353
ListMatrixArray % Rows(row) % Degree = &
354
ListMatrixArray % Rows(row) % Degree + 1
355
356
! Advance to next element in list
357
PEntryPtr => NEntryPtr
358
CEntryPtr => NEntryPtr % Next
359
ELSE
360
! Advance to next element in list
361
PEntryPtr => CEntryPtr
362
CEntryPtr => CEntryPtr % Next
363
END IF
364
ELSE
365
! List matrix row contains no more entries
366
EXIT
367
END IF
368
END DO
369
370
! Add rest of the entries in Indexes to list matrix row (if any)
371
DO rentry=centry,nentry
372
col=Indexes(Perm(rentry))
373
NEntryPtr => ListMatrixPool_GetListEntry(ListMatrixArray % Pool(TID), col, NULL())
374
PEntryPtr % Next => NEntryPtr
375
PEntryPtr => NEntryPtr
376
ListMatrixArray % Rows(row) % Degree = &
377
ListMatrixArray % Rows(row) % Degree + 1
378
END DO
379
380
CALL ListMatrixArray_UnlockRow(ListMatrixArray, row, Atomic)
381
END SUBROUTINE ListMatrixArray_AddEntries
382
383
!-------------------------------------------------------------------------------
384
!> Delete entry (row,col) from the matrix sparsity structure
385
!-------------------------------------------------------------------------------
386
SUBROUTINE ListMatrixArray_DeleteEntry(ListMatrixArray, row, col, Atomic)
387
IMPLICIT NONE
388
TYPE(ListMatrixArray_t) :: ListMatrixArray
389
INTEGER, INTENT(IN) :: row, col
390
LOGICAL, OPTIONAL :: Atomic
391
392
TYPE(ListMatrixEntry_t), POINTER :: CEntryPtr, PEntryPtr
393
INTEGER :: TID
394
LOGICAL :: NotFound
395
396
TID = 1
397
!$ TID = omp_get_thread_num() + 1
398
399
CALL ListMatrixArray_LockRow(ListMatrixArray, row, Atomic)
400
401
! Search for element from the list
402
PEntryPtr => NULL()
403
CEntryPtr => ListMatrixArray % Rows(row) % Head
404
DO WHILE( ASSOCIATED(CEntryPtr) )
405
IF (CEntryPtr % Index >= col) EXIT
406
407
PEntryPtr => CEntryPtr
408
CEntryPtr => CEntryPtr % Next
409
END DO
410
411
IF (ASSOCIATED(CEntryPtr)) THEN
412
IF (CEntryPtr % Index == col) THEN
413
! Element found, delete it from list and add it to
414
! the pooled list of deleted entries
415
IF (ASSOCIATED(PEntryPtr)) THEN
416
PEntryPtr % Next => CEntryPtr % Next
417
ELSE
418
ListMatrixArray % Rows(row) % Head => CEntryPtr % Next
419
END IF
420
CALL ListMatrixPool_AddDeletedEntry(ListMatrixArray % Pool(TID), CEntryPtr)
421
422
ListMatrixArray % Rows(row) % Degree = &
423
MAX(ListMatrixArray % Rows(row) % Degree - 1, 0)
424
END IF
425
END IF
426
427
CALL ListMatrixArray_UnlockRow(ListMatrixArray, row, Atomic)
428
END SUBROUTINE ListMatrixArray_DeleteEntry
429
430
!-------------------------------------------------------------------------------
431
!> ListMatrixPool support routines
432
!-------------------------------------------------------------------------------
433
SUBROUTINE ListMatrixPool_Initialize(Pool, PoolSize)
434
IMPLICIT NONE
435
436
TYPE(ListMatrixPool_t) :: Pool
437
INTEGER, INTENT(IN) :: PoolSize
438
439
Pool % EntryPool => NULL()
440
Pool % Deleted => NULL()
441
Pool % PoolSize = PoolSize
442
CALL ListMatrixPool_EnLarge(Pool)
443
END SUBROUTINE ListMatrixPool_Initialize
444
445
SUBROUTINE ListMatrixPool_Enlarge(Pool)
446
IMPLICIT NONE
447
448
TYPE(ListMatrixPool_t) :: Pool
449
450
TYPE(ListMatrixEntryPool_t), POINTER :: EntryPool
451
452
INTEGER :: astat
453
454
ALLOCATE(EntryPool, STAT=astat)
455
IF (astat == 0) ALLOCATE(EntryPool % Entries(Pool % PoolSize), STAT=astat)
456
IF (astat /= 0) THEN
457
CALL Fatal('ListMatrixPool_Enlarge','Pool allocation failed')
458
END IF
459
460
EntryPool % NextIndex = 1
461
462
EntryPool % Next => Pool % EntryPool
463
Pool % EntryPool => EntryPool
464
END SUBROUTINE ListMatrixPool_Enlarge
465
466
SUBROUTINE ListMatrixPool_Free(Pool)
467
IMPLICIT NONE
468
469
TYPE(ListMatrixPool_t) :: Pool
470
TYPE(ListMatrixEntryPool_t), POINTER :: EntryPool, EntryPoolNext
471
472
EntryPool => Pool % EntryPool
473
DO WHILE (ASSOCIATED(EntryPool))
474
EntryPoolNext => EntryPool % Next
475
DEALLOCATE(EntryPool % Entries)
476
DEALLOCATE(EntryPool)
477
EntryPool => EntryPoolNext
478
END DO
479
END SUBROUTINE ListMatrixPool_Free
480
481
FUNCTION ListMatrixPool_GetListEntry(Pool, ind, Next) RESULT(ListEntry)
482
IMPLICIT NONE
483
484
TYPE(ListMatrixPool_t) :: Pool
485
INTEGER, INTENT(IN) :: ind
486
TYPE(ListMatrixEntry_t), POINTER :: Next
487
488
TYPE(ListMatrixEntry_t), POINTER :: ListEntry
489
490
! Check if deleted entries are available
491
IF (ASSOCIATED(Pool % Deleted)) THEN
492
ListEntry => Pool % Deleted
493
Pool % Deleted => ListEntry % Next
494
ELSE
495
! No deleted entries available, allocate a new pool if necessary
496
IF (Pool % PoolSize < Pool % EntryPool % NextIndex) THEN
497
CALL ListMatrixPool_Enlarge(Pool)
498
END IF
499
500
! Get next element from pool
501
ListEntry => Pool % EntryPool % Entries(Pool % EntryPool % NextIndex)
502
Pool % EntryPool % NextIndex = Pool % EntryPool % NextIndex + 1
503
END IF
504
505
ListEntry % Index = ind
506
ListEntry % Next => Next
507
END FUNCTION ListMatrixPool_GetListEntry
508
509
SUBROUTINE ListMatrixPool_AddDeletedEntry(Pool, DEntry)
510
IMPLICIT NONE
511
512
TYPE(ListMatrixPool_t) :: Pool
513
TYPE(ListMatrixEntry_t), POINTER :: DEntry
514
515
! Add new deleted entry to the head of the deleted entries list
516
DEntry % Next => Pool % Deleted
517
Pool % Deleted => DEntry
518
END SUBROUTINE ListMatrixPool_AddDeletedEntry
519
520
END MODULE ListMatrixArray
521
522
!> \} ElmerLib
523
524