FE-Project
Loading...
Searching...
No Matches
scale_sparsemat.F90
Go to the documentation of this file.
1!-------------------------------------------------------------------------------
2!> Module common / sparsemat
3!!
4!! @par Description
5!! A module to treat sparse matrix and the associated operations
6!!
7!! @author Yuta Kawai, Xuanzhengbo Ren, and Team SCALE
8!!
9!<
10#include "scaleFElib.h"
12 !-----------------------------------------------------------------------------
13 !
14 !++ used modules
15 !
16 use scale_precision
17 use scale_io
18 use scale_prc
19 use scale_const, only: &
20 undef8 => const_undef8, &
21 const_eps
22
23 !-----------------------------------------------------------------------------
24 implicit none
25 private
26
27 !-----------------------------------------------------------------------------
28 !
29 !++ Public type & procedure
30 !
31
32 !> Derived type to manage a sparse matrix
33 type, public :: sparsemat
34 integer :: m !< Number of row of original matrix
35 integer :: n !< Number of column of original matrix
36 integer :: nnz !< Number of nonzero of the matrix
37 real(rp), allocatable :: val(:) !< Array storing the values of the nonzeros
38 integer, allocatable :: colidx(:) !< Array saving the column indices of the nonzeros
39
40 ! for CSR format
41 integer, allocatable :: rowptr(:) !< Array saving the start and end pointers of the nonzeros of the rows.
42 integer :: rowptrsize !< Size of rowPtr
43
44 ! for ELL format
45 integer :: col_size !< Size of column of compressed matrix for ELL format (maximum number of nonzeros in a row)
46
47 integer, private :: storage_format_id !< Number of row of original matrix
48 contains
49 procedure, public :: init => sparsemat_init
50 procedure, public :: final => sparsemat_final
51 procedure, public :: print => sparsemat_print
52 procedure, public :: replaceval => sparsemat_replceval
53 procedure, public :: getval => sparsemat_getval
54 procedure, public :: getstorageformatid => sparsemat_get_storage_format_id
55 end type sparsemat
56
58 module procedure sparsemat_matmul1
59 module procedure sparsemat_matmul1_2
60 module procedure sparsemat_matmul2
61 end interface
62 public :: sparsemat_matmul
63
64 !-----------------------------------------------------------------------------
65 !
66 !++ Public parameters & variables
67 !
68 integer, public, parameter :: sparsemat_storage_typeid_csr = 1 !< Storage format ID for CSR format
69 integer, public, parameter :: sparsemat_storage_typeid_ell = 2 !< Storage format ID for ELL format
70
71 !-----------------------------------------------------------------------------
72 !
73 !++ Private procedure
74 !
75 private :: sparsemat_matmul_csr_1
76 private :: sparsemat_matmul_csr_2
77 private :: sparsemat_matmul_ell_1
78 private :: sparsemat_matmul_ell_2
79
80 !-----------------------------------------------------------------------------
81 !
82 !++ Private parameters & variables
83 !
84
85 !-----------------------------------------------------------------------------
86
87contains
88 !> Initialize an object to manage a sparse matrix
89!OCL SERIAL
90 subroutine sparsemat_init( this, mat, &
91 EPS, storage_format )
92 implicit none
93
94 class(sparsemat), intent(inout) :: this
95 real(rp), intent(in) :: mat(:,:)
96 real(rp), optional, intent(in) :: eps
97 character(len=*), optional, intent(in) :: storage_format
98
99 integer :: i
100 integer :: j
101 integer :: l
102
103 integer :: val_counter
104 integer :: rowptr_counter
105
106 real(dp) :: tmp_val(size(mat)+1)
107 integer :: tmp_colind(size(mat)+1)
108 integer :: tmp_rowptr(0:size(mat,1)+1)
109
110 real(rp) :: eps_
111 character(len=H_MID) :: storage_format_ = 'CSR'
112
113 integer :: row_nonzero_counter(size(mat,1))
114 integer :: col_size_l
115 !---------------------------------------------------------------------------
116
117 !$acc enter data create(this)
118
119 this%M = size(mat,1)
120 this%N = size(mat,2)
121
122 val_counter = 1
123 rowptr_counter = 1
124 tmp_rowptr(1) = 1
125 tmp_val(:) = 0.0_rp
126
127 if (present(eps)) then
128 eps_ = eps
129 else
130 eps_ = const_eps * 500.0_rp ! ~ 1x10^-13
131 end if
132
133 if (present(storage_format)) then
134 storage_format_ = storage_format
135 end if
136
137 select case (storage_format_)
138 case ('CSR')
139 this%storage_format_id = sparsemat_storage_typeid_csr
140
141 do i=1, this%M
142 do j=1, this%N
143 if ( abs(mat(i,j)) > eps_ ) then
144 tmp_val(val_counter) = mat(i,j)
145 tmp_colind(val_counter) = j
146 val_counter = val_counter + 1
147 end if
148 end do
149 rowptr_counter = rowptr_counter + 1
150 tmp_rowptr(rowptr_counter) = val_counter
151 end do
152 case ('ELL')
153 this%storage_format_id = sparsemat_storage_typeid_ell
154
155 do i=1, this%M
156 row_nonzero_counter(i) = 0
157 do j=1, this%N
158 if ( abs(mat(i,j)) >= eps_ ) &
159 row_nonzero_counter(i) = row_nonzero_counter(i) + 1
160 end do
161 end do
162 this%col_size = maxval(row_nonzero_counter(:))
163 val_counter = this%M * this%col_size
164
165 tmp_val(:) = 0.0_rp
166 tmp_colind(:) = -1
167 do i=1, this%M
168 col_size_l = 0
169 do j=1,this%N
170 if ( abs(mat(i,j)) >= eps_ ) then
171 col_size_l = col_size_l + 1
172 l = i+(col_size_l-1)*this%M
173 tmp_val(l) = mat(i,j)
174 tmp_colind(l) = j
175 end if
176 end do
177 end do
178 case default
179 log_error("SparseMat_Init",*) 'Not appropriate names of storage format. Check!', trim(storage_format_)
180 call prc_abort
181 end select
182
183 this%nnz = val_counter
184 allocate( this%val(val_counter) )
185 allocate( this%colIdx(val_counter) )
186 this%val(:) = tmp_val(1:val_counter)
187 this%colIdx(:) = tmp_colind(1:val_counter)
188
189 select case (storage_format_)
190 case ('CSR')
191 allocate( this%rowPtr(rowptr_counter) )
192 this%rowPtr(:) = tmp_rowptr(1:rowptr_counter)
193 !$acc enter data copyin( this%rowPtr )
194 !$acc enter data attach( this%rowPtr )
195 this%rowPtrSize = rowptr_counter
196 case('ELL')
197 do l=2, val_counter
198 if (this%colIdx(l) == -1) then
199 this%colIdx(l) = this%colIdx(l-1)
200 end if
201 end do
202 end select
203 !$acc enter data copyin( this%val, this%colIdx )
204 !$acc enter data attach( this%val, this%colIdx )
205
206 !$acc update device( this%M, this%N, this%nnz, this%rowPtrSize, this%storage_format_id, this%col_size )
207
208 !write(*,*) "--- Mat ------"
209 !write(*,*) "shape:", shape(mat)
210 !write(*,*) "size:", size(mat)
211 ! do j=1, size(mat,2)
212 ! write(*,*) mat(:,j)
213 ! end do
214 !write(*,*) "--- Compressed Mat ------"
215 !write(*,*) "shape (Mat, colInd, rowPtr):", &
216 ! & shape(this%val), shape(this%colInd), shape(this%rowPtr)
217 ! write(*,*) "val:", this%val(:)
218 ! write(*,*) "colInd:", this%colInd(:)
219 ! write(*,*) "rowPtr:", this%rowPtr(:)
220
221 return
222 end subroutine sparsemat_init
223
224 !> Finalize an object to manage a sparse matrix
225!OCL SERIAL
226 subroutine sparsemat_final(this)
227 implicit none
228 class(sparsemat), intent(inout) :: this
229 !---------------------------------------------------------------------------
230
231 !$acc exit data detach( this%val, this%colIdx )
232 !$acc exit data delete( this%val, this%colIdx )
233 deallocate( this%val )
234 deallocate( this%colIdx )
235
236 select case( this%storage_format_id )
238 !$acc exit data detach( this%rowPtr )
239 !$acc exit data delete( this%rowPtr )
240 deallocate( this%rowPtr )
241 end select
242
243 !$acc exit data delete( this )
244
245 !write(*,*) "--- Finalize sparsemat ---"
246 return
247 end subroutine sparsemat_final
248
249 function sparsemat_getval(A, i, j) result(v)
250 class(sparsemat), intent(in) :: a
251 integer, intent(in) :: i, j
252
253 real(dp) ::v
254 integer :: n
255 integer :: jj
256 !---------------------------------------------------------------------------
257
258 v = undef8
259 select case( a%storage_format_id )
261 do n=a%rowPtr(i),a%rowPtr(i+1)-1
262 if (a%colIdx(n) == j) then
263 v = a%val(n); exit
264 end if
265 end do
267 do jj=1, a%col_size
268 n = i + (jj-1)*a%M
269 if (a%colIdx(n) == j) then
270 v = a%val(n); exit
271 end if
272 end do
273 end select
274
275 return
276 end function sparsemat_getval
277
278 subroutine sparsemat_replceval(A, i, j, v)
279
280 class(sparsemat), intent(inout) :: a
281 integer, intent(in) :: i, j
282 real(rp), intent(in) ::v
283
284 integer :: n
285 integer :: jj
286 !---------------------------------------------------------------------------
287
288 select case ( a%storage_format_id )
290 do n=a%rowPtr(i),a%rowPtr(i+1)-1
291 if (a%colIdx(n) == j) then
292 a%val(n) = v; exit
293 end if
294 end do
296 do jj=1, a%col_size
297 n = i + (jj-1)*a%M
298 if (a%colIdx(n) == j) then
299 a%val(n) = v; exit
300 end if
301 end do
302 end select
303
304 return
305 end subroutine sparsemat_replceval
306
307 subroutine sparsemat_print(A)
308 implicit none
309 class(sparsemat), intent(in) :: a
310
311 real(rp) :: row_val(a%n)
312 integer :: p
313 integer :: j1, j2
314 !---------------------------------------------------------------------------
315
316 write(*,*) "-- print matrix:"
317 write(*,'(a,i5,a,i5)') "orginal matrix shape:", a%M, 'x', a%N
318 write(*,'(a,i5)') "size of compressed matrix:", a%nnz
319 select case ( a%storage_format_id )
321 write(*,*) "rowPtr:", a%rowPtr(:)
322 end select
323 write(*,*) "colInd:", a%colIdx(:)
324 write(*,*) "val:"
325
326 select case ( a%storage_format_id )
328 j1 = a%rowPtr(1)
329 do p=1, a%rowPtrSize-1
330 j2 = a%rowPtr(p+1)
331 row_val(:) = 0.0_rp
332 row_val(a%colIdx(j1:j2-1)) = a%val(j1:j2-1)
333 write(*,*) row_val(:)
334 j1 = j2
335 end do
337 do p=1, a%M
338 row_val(:) = 0.0_rp
339 do j1=1, a%col_size
340 j2 = p + (j1-1)*a%M
341 row_val(a%colIdx(j2)) = a%val(j2)
342 end do
343 write(*,*) row_val(:)
344 end do
345 end select
346
347 return
348 end subroutine sparsemat_print
349
350 function sparsemat_get_storage_format_id( A ) result(id)
351 implicit none
352 class(sparsemat), intent(in) :: a
353 real(rp) :: id
354 !------------------------------------------------------
355
356 id = a%storage_format_id
357 return
358 end function sparsemat_get_storage_format_id
359
360 !> Matrix-vector multiplication for a sparse matrix
361!OCL SERIAL
362 subroutine sparsemat_matmul1(A, b, c)
363 implicit none
364
365 type(sparsemat), intent(in) :: A
366 real(RP), intent(in ) :: b(:)
367 real(RP), intent(out) :: c(A%M)
368
369 !---------------------------------------------------------------------------
370
371 !$acc routine vector
372
373 select case( a%storage_format_id )
375 call sparsemat_matmul_csr_1( a%val, a%colIdx, a%rowPtr, b, c, &
376 a%M, a%N, a%nnz, a%rowPtrSize )
378 call sparsemat_matmul_ell_1( a%val, a%colIdx, b, c, &
379 a%M, a%N, a%nnz, a%col_size )
380 end select
381
382 return
383 end subroutine sparsemat_matmul1
384
385 !> Matrix-vector multiplication for a sparse matrix with two vectors
386 !! This routine computes c = A * (b1 .* b2), where .* is the element-wise multiplication.
387!OCL SERIAL
388 subroutine sparsemat_matmul1_2(A, b1, b2, c)
389 implicit none
390
391 type(sparsemat), intent(in) :: A
392 real(RP), intent(in ) :: b1(:)
393 real(RP), intent(in ) :: b2(:)
394 real(RP), intent(out) :: c(A%M)
395
396 !---------------------------------------------------------------------------
397
398 !$acc routine vector
399
400 select case( a%storage_format_id )
402 call sparsemat_matmul_csr_1_2( a%val, a%colIdx, a%rowPtr, b1, b2, c, &
403 a%M, a%N, a%nnz, a%rowPtrSize )
405 call sparsemat_matmul_ell_1_2( a%val, a%colIdx, b1, b2, c, &
406 a%M, a%N, a%nnz, a%col_size )
407 end select
408
409 return
410 end subroutine sparsemat_matmul1_2
411
412 !> Matrix-matrix multiplication for a sparse matrix
413!OCL SERIAL
414 subroutine sparsemat_matmul2(A, b, c)
415 implicit none
416
417 type(sparsemat), intent(in) :: A
418 real(RP), intent(in ) :: b(:,:)
419 real(RP), intent(out) :: c(size(b,1),A%M)
420
421 !---------------------------------------------------------------------------
422
423 select case( a%storage_format_id )
425 call sparsemat_matmul_csr_2( a%val, a%colIdx, a%rowPtr, b, c, &
426 a%M, a%N, a%nnz, a%rowPtrSize, size(b,1) )
428 call sparsemat_matmul_ell_2( a%val, a%colIdx, b, c, &
429 a%M, a%N, a%nnz, a%col_size, size(b,1) )
430 end select
431
432 return
433 end subroutine sparsemat_matmul2
434
435!--- private ----------------------------------------------
436
437 !> Matrix-vector multiplication for a sparse matrix in CSR format
438!OCL SERIAL
439 subroutine sparsemat_matmul_csr_1(A, col_Ind, rowPtr, b, c, M, N, buf_size, rowPtr_size)
440 implicit none
441
442 integer, intent(in) :: M
443 integer, intent(in) :: N
444 integer, intent(in) :: buf_size
445 integer, intent(in) :: rowPtr_size
446 real(RP), intent(in) :: A(buf_size)
447 integer, intent(in) :: col_Ind(buf_size)
448 integer, intent(in) :: rowPtr(rowPtr_size)
449 real(RP), intent(in ) :: b(N)
450 real(RP), intent(out) :: c(M)
451
452 integer :: p, j
453 integer :: j1, j2
454 real(RP) :: s
455
456 !---------------------------------------------------------------------------
457
458 !$acc routine vector
459
460 !call mkl_dcsrgemv( 'N', rowPtr_size-1, A, rowPtr, col_Ind, b, c)
461
462 !$acc loop vector
463 do p=1, rowptr_size-1
464 j1 = rowptr(p)
465 j2 = rowptr(p+1)
466 s = 0.0_rp
467 do j=j1, j2-1
468 s = s + a(j) * b(col_ind(j))
469 end do
470 c(p) = s
471 end do
472
473 return
474 end subroutine sparsemat_matmul_csr_1
475
476 !> Matrix-vector multiplication for a sparse matrix in CSR format with two vectors
477 !! This routine computes c = A * (b1 .* b2), where .* is the element-wise multiplication.
478!OCL SERIAL
479 subroutine sparsemat_matmul_csr_1_2(A, col_Ind, rowPtr, b1, b2, c, M, N, buf_size, rowPtr_size)
480 implicit none
481
482 integer, intent(in) :: M
483 integer, intent(in) :: N
484 integer, intent(in) :: buf_size
485 integer, intent(in) :: rowPtr_size
486 real(RP), intent(in) :: A(buf_size)
487 integer, intent(in) :: col_Ind(buf_size)
488 integer, intent(in) :: rowPtr(rowPtr_size)
489 real(RP), intent(in ) :: b1(N)
490 real(RP), intent(in ) :: b2(N)
491 real(RP), intent(out) :: c(M)
492
493 integer :: p, j
494 integer :: j1, j2
495 real(RP) :: s
496
497 !---------------------------------------------------------------------------
498
499 !$acc routine vector
500
501 !call mkl_dcsrgemv( 'N', rowPtr_size-1, A, rowPtr, col_Ind, b, c)
502
503 !$acc loop vector
504 do p=1, rowptr_size-1
505 j1 = rowptr(p)
506 j2 = rowptr(p+1)
507 s = 0.0_rp
508 do j=j1, j2-1
509 s = s + a(j) * b1(col_ind(j)) * b2(col_ind(j))
510 end do
511 c(p) = s
512 end do
513
514 return
515 end subroutine sparsemat_matmul_csr_1_2
516
517 !> Matrix-matrix multiplication for a sparse matrix in CSR format
518!OCL SERIAL
519 subroutine sparsemat_matmul_csr_2(A, col_Ind, rowPtr, b, c, M, N, buf_size, rowPtr_size, NQ)
520 implicit none
521
522 integer, intent(in) :: M
523 integer, intent(in) :: N
524 integer, intent(in) :: NQ
525 integer, intent(in) :: buf_size
526 integer, intent(in) :: rowPtr_size
527 real(RP), intent(in) :: A(buf_size)
528 integer, intent(in) :: col_Ind(buf_size)
529 integer, intent(in) :: rowPtr(rowPtr_size)
530 real(RP), intent(in ) :: b(NQ,N)
531 real(RP), intent(out) :: c(NQ,M)
532
533 integer :: p, j
534 integer :: j1, j2
535
536 !---------------------------------------------------------------------------
537
538 !call mkl_dcsrgemv( 'N', rowPtr_size-1, A, rowPtr, col_Ind, b, c)
539 j1 = rowptr(1)
540 c(:,:) = 0.0_rp
541 do p=1, rowptr_size-1
542 j2 = rowptr(p+1)
543 do j=j1, j2-1
544 c(:,p) = c(:,p) + a(j) * b(:,col_ind(j))
545 end do
546 j1 = j2
547 end do
548
549 return
550 end subroutine sparsemat_matmul_csr_2
551
552 !> Matrix-vector multiplication for a sparse matrix in ELL format
553!OCL SERIAL
554 subroutine sparsemat_matmul_ell_1(A, col_Ind, b, c, M, N, buf_size, col_size)
555 implicit none
556
557 integer, intent(in) :: M
558 integer, intent(in) :: N
559 integer, intent(in) :: buf_size
560 integer, intent(in) :: col_size
561 real(RP), intent(in) :: A(buf_size)
562 integer, intent(in) :: col_Ind(buf_size)
563 real(RP), intent(in ) :: b(N)
564 real(RP), intent(out) :: c(M)
565
566 integer :: k, kk, i
567 integer :: j_ptr
568 !---------------------------------------------------------------------------
569
570 !$acc routine vector
571
572#ifdef _OPENACC
573 !$acc loop vector
574 do i=1, m
575 c(i) = 0.0_rp
576 end do
577#else
578 c(:) = 0.0_rp
579#endif
580
581 do k=1, col_size
582 kk = m * (k-1)
583 !$acc loop vector
584 do i=1, m
585 j_ptr = kk + i
586 c(i) = c(i) + a(j_ptr) * b(col_ind(j_ptr))
587 end do
588 end do
589
590 return
591 end subroutine sparsemat_matmul_ell_1
592
593 !> Matrix-vector multiplication for a sparse matrix in ELL format with two vectors
594 !! This routine computes c = A * (b1 .* b2), where .* is the element-wise multiplication.
595!OCL SERIAL
596 subroutine sparsemat_matmul_ell_1_2(A, col_Ind, b1, b2, c, M, N, buf_size, col_size)
597 implicit none
598
599 integer, intent(in) :: M
600 integer, intent(in) :: N
601 integer, intent(in) :: buf_size
602 integer, intent(in) :: col_size
603 real(RP), intent(in) :: A(buf_size)
604 integer, intent(in) :: col_Ind(buf_size)
605 real(RP), intent(in ) :: b1(N)
606 real(RP), intent(in ) :: b2(N)
607 real(RP), intent(out) :: c(M)
608
609 integer :: k, kk, i
610 integer :: j_ptr
611 !---------------------------------------------------------------------------
612
613 !$acc routine vector
614
615#ifdef _OPENACC
616 !$acc loop vector
617 do i=1, m
618 c(i) = 0.0_rp
619 end do
620#else
621 c(:) = 0.0_rp
622#endif
623
624 do k=1, col_size
625 kk = m * (k-1)
626 !$acc loop vector
627 do i=1, m
628 j_ptr = kk + i
629 c(i) = c(i) + a(j_ptr) * b1(col_ind(j_ptr)) * b2(col_ind(j_ptr))
630 end do
631 end do
632
633 return
634 end subroutine sparsemat_matmul_ell_1_2
635
636 !> Matrix-matrix multiplication for a sparse matrix in ELL format
637!OCL SERIAL
638 subroutine sparsemat_matmul_ell_2(A, col_Ind, b, c, M, N, buf_size, col_size, NQ)
639 implicit none
640
641 integer, intent(in) :: M
642 integer, intent(in) :: N
643 integer, intent(in) :: buf_size
644 integer, intent(in) :: col_size
645 integer, intent(in) :: NQ
646 real(RP), intent(in) :: A(buf_size)
647 integer, intent(in) :: col_Ind(buf_size)
648 real(RP), intent(in ) :: b(NQ,N)
649 real(RP), intent(out) :: c(NQ,M)
650
651 integer :: k, kk, i
652 integer :: j_ptr
653 !---------------------------------------------------------------------------
654
655 c(:,:) = 0.0_rp
656 do k=1, col_size
657 kk = m * (k-1)
658 do i=1, m
659 j_ptr = kk + i
660 c(:,i) = c(:,i) + a(j_ptr) * b(:,col_ind(j_ptr))
661 end do
662 end do
663
664 return
665 end subroutine sparsemat_matmul_ell_2
666
667end module scale_sparsemat
668
Module common / sparsemat.
integer, parameter, public sparsemat_storage_typeid_csr
Storage format ID for CSR format.
integer, parameter, public sparsemat_storage_typeid_ell
Storage format ID for ELL format.
Derived type to manage a sparse matrix.