diff --git a/src/csr_mod.f90 b/src/csr_mod.f90
index 23afb72..ab2f57d 100644
--- a/src/csr_mod.f90
+++ b/src/csr_mod.f90
@@ -1,1255 +1,1255 @@
!>
!> @file csr_mod.f90
!>
!> @brief
!>
!> @copyright
!> Copyright (©) 2021 EPFL (Ecole Polytechnique Fédérale de Lausanne)
!> SPC (Swiss Plasma Center)
!>
!> SPClibs is free software: you can redistribute it and/or modify it under
!> the terms of the GNU Lesser General Public License as published by the Free
!> Software Foundation, either version 3 of the License, or (at your option)
!> any later version.
!>
!> SPClibs is distributed in the hope that it will be useful, but WITHOUT ANY
!> WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
!> FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
!>
!> You should have received a copy of the GNU Lesser General Public License
!> along with this program. If not, see .
!>
!> @author
!> (in alphabetical order)
!> @author Trach-Minh Tran
!>
MODULE csr
!
! CSR: Implement CSR (Compressed Sparse Row) matrice
!
! T.M. Tran, CRPP-EPFL
! October 2012
!
USE sparse
USE mumps_bsplines
IMPLICIT NONE
!
TYPE, EXTENDS(spmat) :: csr_mat
INTEGER :: mrows, ncols
INTEGER :: nnz = 0 ! Number of non-zeros
INTEGER :: nterms ! Number of terms in weak form
LOGICAL :: nlforce_zero ! Keep exixting nodes with zero value if .true.
INTEGER, POINTER :: irow(:) => NULL() ! points to start of row
INTEGER, POINTER :: idiag(:) => NULL() ! points to diagonal element
INTEGER, POINTER :: cols(:) => NULL() ! Column indices
DOUBLE PRECISION, POINTER :: val(:) => NULL() ! Elelement values
TYPE(mumps_mat), ALLOCATABLE :: mumps
END TYPE csr_mat
!
TYPE, EXTENDS(zspmat) :: zcsr_mat
INTEGER :: mrows, ncols
INTEGER :: nnz = 0 ! Number of non-zeros
INTEGER :: nterms ! Number of terms in weak form
LOGICAL :: nlforce_zero ! Keep exixting nodes with zero value if .true.
INTEGER, POINTER :: irow(:) => NULL() ! points to start of row
INTEGER, POINTER :: idiag(:) => NULL() ! points to diagonal element
INTEGER, POINTER :: cols(:) => NULL() ! Column indices
DOUBLE COMPLEX, POINTER :: val(:) => NULL() ! Elelement values
!
TYPE(zmumps_mat), ALLOCATABLE :: mumps
END TYPE zcsr_mat
!
INTERFACE init
MODULE PROCEDURE init_csr_mat, init_zcsr_mat
END INTERFACE init
INTERFACE clear_mat
MODULE PROCEDURE clear_csr_mat, clear_zcsr_mat
END INTERFACE clear_mat
INTERFACE updtmat
MODULE PROCEDURE updt_csr_mat, updt_zcsr_mat
END INTERFACE updtmat
INTERFACE putele
MODULE PROCEDURE putele_csr_mat, putele_zcsr_mat
END INTERFACE putele
INTERFACE getele
MODULE PROCEDURE getele_csr_mat, getele_zcsr_mat
END INTERFACE getele
INTERFACE putrow
MODULE PROCEDURE putrow_csr_mat, putrow_zcsr_mat
END INTERFACE putrow
INTERFACE getrow
MODULE PROCEDURE getrow_csr_mat, getrow_zcsr_mat
END INTERFACE getrow
INTERFACE getdiag
MODULE PROCEDURE getdiag_csr_mat, getdiag_zcsr_mat
END INTERFACE getdiag
INTERFACE putcol
MODULE PROCEDURE putcol_csr_mat, putcol_zcsr_mat
END INTERFACE putcol
INTERFACE getcol
MODULE PROCEDURE getcol_csr_mat, getcol_zcsr_mat
END INTERFACE getcol
INTERFACE to_mat
MODULE PROCEDURE to_csr_mat, to_zcsr_mat
END INTERFACE to_mat
INTERFACE vmx
MODULE PROCEDURE vmx_csr_mat, vmx_csr_matn, vmx_zcsr_mat, vmx_zcsr_matn
END INTERFACE vmx
INTERFACE destroy
MODULE PROCEDURE destroy_csr_mat, destroy_zcsr_mat
END INTERFACE destroy
INTERFACE putmat
MODULE PROCEDURE put_csr_mat, put_zcsr_mat
END INTERFACE putmat
!>>>>>
!>>>>> CONMAT
!>>>>
INTERFACE conmat
MODULE PROCEDURE conmat_1d_csr, conmat_2d_csr, conmat_1d_zcsr, conmat_2d_zcsr
END INTERFACE conmat
!>>>>
!>>>> MULTIGRID_MOD
!>>>>
INTERFACE femat
MODULE PROCEDURE femat_csr
END INTERFACE femat
INTERFACE matnorm
MODULE PROCEDURE matnorm_csr
END INTERFACE matnorm
INTERFACE kron
MODULE PROCEDURE kron_csr
END INTERFACE kron
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
CONTAINS
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE init_csr_mat(n, nterms, mat, nlforce_zero, ncols)
!
! Initialize an empty CSR matrix
!
INTEGER, INTENT(in) :: n, nterms
TYPE(csr_mat) :: mat
LOGICAL, OPTIONAL, INTENT(in) :: nlforce_zero
INTEGER, OPTIONAL, intent(in) :: ncols
!
CALL init(n, mat%spmat)
mat%mrows = n
mat%ncols = n
IF(PRESENT(ncols)) mat%ncols = ncols
mat%nterms = nterms
mat%nlforce_zero = .TRUE. ! Do not remove existing nodes with zero val
IF(PRESENT(nlforce_zero)) mat%nlforce_zero = nlforce_zero
!
END SUBROUTINE init_csr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE init_zcsr_mat(n, nterms, mat, nlforce_zero, ncols)
!
! Initialize an empty CSR matrix
!
INTEGER, INTENT(in) :: n, nterms
TYPE(zcsr_mat) :: mat
LOGICAL, OPTIONAL, INTENT(in) :: nlforce_zero
INTEGER, OPTIONAL, intent(in) :: ncols
!
CALL init(n, mat%zspmat)
mat%mrows = n
mat%ncols = n
IF(PRESENT(ncols)) mat%ncols = ncols
mat%nterms = nterms
mat%nlforce_zero = .TRUE. ! Do not remove existing nodes with zero val
IF(PRESENT(nlforce_zero)) mat%nlforce_zero = nlforce_zero
!
END SUBROUTINE init_zcsr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE clear_zcsr_mat(mat)
!
! Clear matrix, keeping its sparse structure unchanged
!
TYPE(zcsr_mat) :: mat
!
mat%val = (0.0d0,0.0d0)
END SUBROUTINE clear_zcsr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE clear_csr_mat(mat)
!
! Clear matrix, keeping its sparse structure unchanged
!
TYPE(csr_mat) :: mat
!
mat%val = 0.0d0
END SUBROUTINE clear_csr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE updt_csr_mat(mat, i, j, val)
!
! Update element Aij of csr matrix
!
TYPE(csr_mat) :: mat
INTEGER, INTENT(in) :: i, j
DOUBLE PRECISION, INTENT(in) :: val
INTEGER :: k, s, e
!
IF(mat%nnz.EQ.0) THEN ! Still using linked lists
CALL updtmat(mat%spmat, i, j, val)
ELSE
s = mat%irow(i)
e = mat%irow(i+1)-1
k = isearch(mat%cols(s:e), j)
IF( k.GE.0 ) THEN
mat%val(s+k) = mat%val(s+k)+val
ELSE
WRITE(*,'(a,2i6)') 'UPDT: i, j out of range ', i, j
STOP '*** Abnormal EXIT in MODULE csr_mod ***'
END IF
END IF
END SUBROUTINE updt_csr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE updt_zcsr_mat(mat, i, j, val)
!
! Update element Aij of csr matrix
!
TYPE(zcsr_mat) :: mat
INTEGER, INTENT(in) :: i, j
DOUBLE COMPLEX, INTENT(in) :: val
INTEGER :: k, s, e
!
IF(mat%nnz.EQ.0) THEN ! Still using linked lists
CALL updtmat(mat%zspmat, i, j, val)
ELSE
s = mat%irow(i)
e = mat%irow(i+1)-1
k = isearch(mat%cols(s:e), j)
IF( k.GE.0 ) THEN
mat%val(s+k) = mat%val(s+k)+val
ELSE
WRITE(*,'(a,2i6)') 'UPDT: i, j out of range ', i, j
STOP '*** Abnormal EXIT in MODULE csr_mod ***'
END IF
END IF
END SUBROUTINE updt_zcsr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE putele_csr_mat(mat, i, j, val)
!
! Put element (i,j) of matrix
!
TYPE(csr_mat) :: mat
INTEGER, INTENT(in) :: i, j
DOUBLE PRECISION, INTENT(in) :: val
INTEGER :: iput, jput
INTEGER :: k, s, e
!
iput = i
jput = j
!
IF(mat%nnz.EQ.0) THEN ! Still using linked lists
CALL putele(mat%spmat, iput, jput, val, &
& nlforce_zero=mat%nlforce_zero)
ELSE
s = mat%irow(iput)
e = mat%irow(iput+1)-1
k = isearch(mat%cols(s:e), jput)
IF( k.GE.0 ) THEN
mat%val(s+k) = val
ELSE
IF(ABS(val) .GT. EPSILON(0.0d0)) THEN ! Ok for zero val
WRITE(*,'(a,2i6)') 'PUTELE: i, j out of range ', i, j
PRINT*, 'val', val
PRINT*, 'matrix m, n', mat%mrows, mat%ncols
STOP '*** Abnormal EXIT in MODULE csr_mod ***'
END IF
END IF
END IF
END SUBROUTINE putele_csr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE putele_zcsr_mat(mat, i, j, val)
!
! Put element (i,j) of matrix
!
TYPE(zcsr_mat) :: mat
INTEGER, INTENT(in) :: i, j
DOUBLE COMPLEX, INTENT(in) :: val
INTEGER :: iput, jput
INTEGER :: k, s, e
!
iput = i
jput = j
!
IF(mat%nnz.EQ.0) THEN ! Still using linked lists
CALL putele(mat%zspmat, iput, jput, val, &
& nlforce_zero=mat%nlforce_zero)
ELSE
s = mat%irow(iput)
e = mat%irow(iput+1)-1
k = isearch(mat%cols(s:e), jput)
IF( k.GE.0 ) THEN
mat%val(s+k) = val
ELSE
IF(ABS(val) .GT. EPSILON(0.0d0)) THEN ! Ok for zero val
WRITE(*,'(a,2i6)') 'PUTELE: i, j out of range ', i, j
PRINT*, 'val', val
PRINT*, 'matrix m, n', mat%mrows, mat%ncols
STOP '*** Abnormal EXIT in MODULE csr_mod ***'
END IF
END IF
END IF
END SUBROUTINE putele_zcsr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE getele_csr_mat(mat, i, j, val)
!
! Get element (i,j) of sparse matrix
!
TYPE(csr_mat) :: mat
INTEGER, INTENT(in) :: i, j
DOUBLE PRECISION, INTENT(out) :: val
INTEGER :: iget, jget
INTEGER :: k, s, e
!
iget = i
jget = j
IF(mat%nnz.EQ.0) THEN ! Still using linked lists
CALL getele(mat%spmat, iget, jget, val)
ELSE
s = mat%irow(iget)
e = mat%irow(iget+1)-1
k = isearch(mat%cols(s:e), jget)
IF( k.GE.0 ) THEN
- val =mat%val(s+k)
+ val =mat%val(s+k)
ELSE
val = 0.0d0 ! Assume zero val if not found
END IF
END IF
END SUBROUTINE getele_csr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE getele_zcsr_mat(mat, i, j, val)
!
! Get element (i,j) of sparse matrix
!
TYPE(zcsr_mat) :: mat
INTEGER, INTENT(in) :: i, j
DOUBLE COMPLEX, INTENT(out) :: val
INTEGER :: iget, jget
INTEGER :: k, s, e
!
iget = i
jget = j
IF(mat%nnz.EQ.0) THEN ! Still using linked lists
CALL getele(mat%zspmat, iget, jget, val)
ELSE
s = mat%irow(iget)
e = mat%irow(iget+1)-1
k = isearch(mat%cols(s:e), jget)
IF( k.GE.0 ) THEN
- val =mat%val(s+k)
+ val =mat%val(s+k)
ELSE
val = 0.0d0 ! Assume zero val if not found
END IF
END IF
END SUBROUTINE getele_zcsr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE putrow_csr_mat(amat, i, arr)
!
! Put a row into sparse matrix
!
TYPE(csr_mat), INTENT(inout) :: amat
INTEGER, INTENT(in) :: i
DOUBLE PRECISION, INTENT(in) :: arr(:)
INTEGER :: s, e, j
!
IF(amat%nnz.EQ.0) THEN ! Still using linked lists
DO j=1,amat%ncols
CALL putele(amat, i, j, arr(j))
END DO
ELSE
s = amat%irow(i)
e = amat%irow(i+1)-1
DO j=s,e
amat%val(j) = arr(amat%cols(j))
END DO
END IF
END SUBROUTINE putrow_csr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE putrow_zcsr_mat(amat, i, arr)
!
! Put a row into sparse matrix
!
TYPE(zcsr_mat), INTENT(inout) :: amat
INTEGER, INTENT(in) :: i
DOUBLE COMPLEX, INTENT(in) :: arr(:)
INTEGER :: s, e, j
!
IF(amat%nnz.EQ.0) THEN ! Still using linked lists
DO j=1,amat%ncols
CALL putele(amat, i, j, arr(j))
END DO
ELSE
s = amat%irow(i)
e = amat%irow(i+1)-1
DO j=s,e
amat%val(j) = arr(amat%cols(j))
END DO
END IF
END SUBROUTINE putrow_zcsr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE getrow_csr_mat(amat, i, arr)
!
! Get a row from sparse matrix
!
TYPE(csr_mat), INTENT(in) :: amat
INTEGER, INTENT(in) :: i
DOUBLE PRECISION, INTENT(out) :: arr(:)
INTEGER :: s, e, j
!
arr = 0.0d0
IF(amat%nnz.EQ.0) THEN ! Still using linked lists
DO j=1,amat%ncols
CALL getele(amat, i, j, arr(j))
END DO
ELSE
s = amat%irow(i)
e = amat%irow(i+1)-1
DO j=s,e
arr(amat%cols(j)) = amat%val(j)
END DO
END IF
END SUBROUTINE getrow_csr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE getrow_zcsr_mat(amat, i, arr)
!
! Get a row from sparse matrix
!
TYPE(zcsr_mat), INTENT(in) :: amat
INTEGER, INTENT(in) :: i
DOUBLE COMPLEX, INTENT(out) :: arr(:)
INTEGER :: s, e, j
!
arr = 0.0d0
IF(amat%nnz.EQ.0) THEN ! Still using linked lists
DO j=1,amat%ncols
CALL getele(amat, i, j, arr(j))
END DO
ELSE
s = amat%irow(i)
e = amat%irow(i+1)-1
DO j=s,e
arr(amat%cols(j)) = amat%val(j)
END DO
END IF
END SUBROUTINE getrow_zcsr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE getdiag_csr_mat(amat, arr)
!
! Get the diagonal from matrix
!
TYPE(csr_mat), INTENT(in) :: amat
DOUBLE PRECISION, INTENT(out) :: arr(:)
!
! WARNING: assume that CSR matrix has been converted from linked lists
!
arr(:) = amat%val(amat%idiag(:))
END SUBROUTINE getdiag_csr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE getdiag_zcsr_mat(amat, arr)
!
! Get the diagonal from matrix
!
TYPE(zcsr_mat), INTENT(in) :: amat
DOUBLE COMPLEX, INTENT(out) :: arr(:)
!
! WARNING: assume that CSR matrix has been converted from linked lists
!
arr(:) = amat%val(amat%idiag(:))
END SUBROUTINE getdiag_zcsr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE putcol_csr_mat(amat, j, arr)
!
! Put a column into sparse matrix
!
TYPE(csr_mat), INTENT(inout) :: amat
INTEGER, INTENT(in) :: j
DOUBLE PRECISION, INTENT(in) :: arr(:)
INTEGER :: i
!
DO i=1,amat%mrows
CALL putele(amat, i, j, arr(i))
END DO
END SUBROUTINE putcol_csr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE putcol_zcsr_mat(amat, j, arr)
!
! Put a column into sparse matrix
!
TYPE(zcsr_mat), INTENT(inout) :: amat
INTEGER, INTENT(in) :: j
DOUBLE COMPLEX, INTENT(in) :: arr(:)
INTEGER :: i
!
DO i=1,amat%mrows
CALL putele(amat, i, j, arr(i))
END DO
END SUBROUTINE putcol_zcsr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE getcol_csr_mat(amat, j, arr)
!
! Get a column from sparse matrix
!
TYPE(csr_mat), INTENT(in) :: amat
INTEGER, INTENT(in) :: j
DOUBLE PRECISION, INTENT(out) :: arr(:)
INTEGER :: i
!
DO i=1,amat%mrows
CALL getele(amat, i, j, arr(i))
END DO
END SUBROUTINE getcol_csr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE getcol_zcsr_mat(amat, j, arr)
!
! Get a column from sparse matrix
!
TYPE(zcsr_mat), INTENT(in) :: amat
INTEGER, INTENT(in) :: j
DOUBLE COMPLEX, INTENT(out) :: arr(:)
INTEGER :: i
!
DO i=1,amat%mrows
CALL getele(amat, i, j, arr(i))
END DO
END SUBROUTINE getcol_zcsr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE to_csr_mat(mat, nlkeep)
!
! Convert linked list spmat to csr matrice structure
!
TYPE(csr_mat) :: mat
LOGICAL, INTENT(in), OPTIONAL :: nlkeep
INTEGER :: nnz_arr(mat%rank)
INTEGER :: i, nnz, rank, s, e
LOGICAL :: nlclean
!
nlclean = .TRUE.
IF(PRESENT(nlkeep)) THEN
nlclean = .NOT. nlkeep
END IF
!
! Allocate the csr matrix structure
!
nnz = get_count(mat%spmat, nnz_arr)
rank = mat%rank
mat%nnz = nnz
IF(ASSOCIATED(mat%irow)) DEALLOCATE(mat%irow)
IF(ASSOCIATED(mat%idiag)) DEALLOCATE(mat%idiag)
IF(ASSOCIATED(mat%cols)) DEALLOCATE(mat%cols)
IF(ASSOCIATED(mat%val)) DEALLOCATE(mat%val)
ALLOCATE(mat%irow(rank+1))
ALLOCATE(mat%idiag(rank))
ALLOCATE(mat%cols(nnz))
ALLOCATE(mat%val(nnz))
!
! Fill csr structure and optionally deallocate the sparse rows
!
mat%irow = 1
DO i=1,rank
mat%irow(i+1) = mat%irow(i) + nnz_arr(i)
s = mat%irow(i)
e = mat%irow(i+1)-1
CALL getrow(mat%spmat%row(i), mat%val(s:e), mat%cols(s:e))
mat%idiag(i) = isearch(mat%cols(s:e), i) + s
IF(nlclean) CALL destroy(mat%spmat%row(i))
END DO
!!$!
!!$! MUMPS mat for direct solver
!!$!
!!$ ALLOCATE(mat%mumps)
!!$ CALL csr2mumps(mat, mat%mumps)
END SUBROUTINE to_csr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE to_zcsr_mat(mat, nlkeep)
!
! Convert linked list spmat to csr matrice structure
!
TYPE(zcsr_mat) :: mat
LOGICAL, INTENT(in), OPTIONAL :: nlkeep
INTEGER :: nnz_arr(mat%rank)
INTEGER :: i, nnz, rank, s, e
LOGICAL :: nlclean
!
nlclean = .TRUE.
IF(PRESENT(nlkeep)) THEN
nlclean = .NOT. nlkeep
END IF
!
! Allocate the csr matrix structure
!
nnz = get_count(mat%zspmat, nnz_arr)
rank = mat%rank
mat%nnz = nnz
IF(ASSOCIATED(mat%irow)) DEALLOCATE(mat%irow)
IF(ASSOCIATED(mat%idiag)) DEALLOCATE(mat%idiag)
IF(ASSOCIATED(mat%cols)) DEALLOCATE(mat%cols)
IF(ASSOCIATED(mat%val)) DEALLOCATE(mat%val)
ALLOCATE(mat%irow(rank+1))
ALLOCATE(mat%idiag(rank))
ALLOCATE(mat%cols(nnz))
ALLOCATE(mat%val(nnz))
!
! Fill csr structure and optionally deallocate the sparse rows
!
mat%irow = 1
DO i=1,rank
mat%irow(i+1) = mat%irow(i) + nnz_arr(i)
s = mat%irow(i)
e = mat%irow(i+1)-1
CALL getrow(mat%zspmat%row(i), mat%val(s:e), mat%cols(s:e))
mat%idiag(i) = isearch(mat%cols(s:e), i) + s
IF(nlclean) CALL destroy(mat%zspmat%row(i))
END DO
!!$!
!!$! MUMPS mat for direct solver
!!$!
!!$ ALLOCATE(mat%mumps)
!!$ CALL csr2mumps(mat, mat%mumps)
END SUBROUTINE to_zcsr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE csr2mumps(mat, mat_mumps)
!
! Fill mumps structure (based on routine to_mumps_mat)
!
INCLUDE 'mpif.h'
TYPE(csr_mat) :: mat
TYPE(mumps_mat) :: mat_mumps
!
INTEGER :: i, rank, s, e
INTEGER :: comm, ierr, nnz_loc
!
CALL init(mat%rank, mat%nterms, mat_mumps)
!
comm = mat_mumps%mumps_par%COMM
mat_mumps%mumps_par%ICNTL(18) = 3 ! Distributed assembled matrix
!
! Allocate the Mumps matrix structure
! CSR format: (cols, irow, val) or (JCN, irow, A)
! COO format: (IRN, JCN, A) or (IRN, cols, val)
!
rank = mat_mumps%rank
nnz_loc = mat%nnz
mat_mumps%nnz_start = 0
CALL mpi_exscan(nnz_loc, mat_mumps%nnz_start, 1, MPI_INTEGER, MPI_SUM, comm, ierr)
mat_mumps%nnz_start = mat_mumps%nnz_start + 1
mat_mumps%nnz_end = mat_mumps%nnz_start + nnz_loc - 1
mat_mumps%nnz_loc = nnz_loc
CALL mpi_allreduce(nnz_loc, mat_mumps%nnz, 1, MPI_INTEGER, MPI_SUM, comm, ierr)
!
mat_mumps%mumps_par%N = rank
mat_mumps%mumps_par%NZ_loc = nnz_loc
!
mat_mumps%cols => mat%cols
mat_mumps%irow => mat%irow
mat_mumps%val => mat%val
!
! (A,JCN) picked from CSR mat
mat_mumps%mumps_par%A_loc => mat_mumps%val
mat_mumps%mumps_par%JCN_loc => mat_mumps%cols
!
! Determine IRN array
IF(ASSOCIATED(mat_mumps%mumps_par%IRN_loc)) DEALLOCATE(mat_mumps%mumps_par%IRN_loc)
ALLOCATE(mat_mumps%mumps_par%IRN_loc(nnz_loc))
DO i=mat_mumps%istart,mat_mumps%iend
s = mat_mumps%irow(i) - mat_mumps%nnz_start + 1
e = mat_mumps%irow(i+1) - mat_mumps%nnz_start
mat_mumps%mumps_par%IRN_loc(s:e) = i
END DO
CALL destroy(mat_mumps%mat)
NULLIFY(mat_mumps%mat)
-!
+!
END SUBROUTINE csr2mumps
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE zcsr2mumps(mat, mat_mumps)
!
! Fill mumps structure (based on routine to_mumps_mat)
!
INCLUDE 'mpif.h'
TYPE(zcsr_mat) :: mat
TYPE(zmumps_mat) :: mat_mumps
!
INTEGER :: i, rank, s, e
INTEGER :: comm, ierr, nnz_loc
!
CALL init(mat%rank, mat%nterms, mat_mumps)
!
comm = mat_mumps%mumps_par%COMM
mat_mumps%mumps_par%ICNTL(18) = 3 ! Distributed assembled matrix
!
! Allocate the Mumps matrix structure
! CSR format: (cols, irow, val) or (JCN, irow, A)
! COO format: (IRN, JCN, A) or (IRN, cols, val)
!
rank = mat_mumps%rank
nnz_loc = mat%nnz
mat_mumps%nnz_start = 0
CALL mpi_exscan(nnz_loc, mat_mumps%nnz_start, 1, MPI_INTEGER, MPI_SUM, comm, ierr)
mat_mumps%nnz_start = mat_mumps%nnz_start + 1
mat_mumps%nnz_end = mat_mumps%nnz_start + nnz_loc - 1
mat_mumps%nnz_loc = nnz_loc
CALL mpi_allreduce(nnz_loc, mat_mumps%nnz, 1, MPI_INTEGER, MPI_SUM, comm, ierr)
!
mat_mumps%mumps_par%N = rank
mat_mumps%mumps_par%NZ_loc = nnz_loc
!
mat_mumps%cols => mat%cols
mat_mumps%irow => mat%irow
mat_mumps%val => mat%val
!
! (A,JCN) picked from CSR mat
mat_mumps%mumps_par%A_loc => mat_mumps%val
mat_mumps%mumps_par%JCN_loc => mat_mumps%cols
!
! Determine IRN array
IF(ASSOCIATED(mat_mumps%mumps_par%IRN_loc)) DEALLOCATE(mat_mumps%mumps_par%IRN_loc)
ALLOCATE(mat_mumps%mumps_par%IRN_loc(nnz_loc))
DO i=mat_mumps%istart,mat_mumps%iend
s = mat_mumps%irow(i) - mat_mumps%nnz_start + 1
e = mat_mumps%irow(i+1) - mat_mumps%nnz_start
mat_mumps%mumps_par%IRN_loc(s:e) = i
END DO
CALL destroy(mat_mumps%mat)
NULLIFY(mat_mumps%mat)
-!
+!
END SUBROUTINE zcsr2mumps
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE destroy_csr_mat(mat)
!
! Deallocate csr mat
!
TYPE(csr_mat) :: mat
!
CALL destroy(mat%spmat)
IF(mat%nnz.GT.0) THEN
DEALLOCATE(mat%irow)
DEALLOCATE(mat%idiag)
DEALLOCATE(mat%cols)
DEALLOCATE(mat%val)
END IF
mat%nnz = 0
END SUBROUTINE destroy_csr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE destroy_zcsr_mat(mat)
!
! Deallocate csr mat
!
TYPE(zcsr_mat) :: mat
!
CALL destroy(mat%zspmat)
IF(mat%nnz.GT.0) THEN
DEALLOCATE(mat%irow)
DEALLOCATE(mat%idiag)
DEALLOCATE(mat%cols)
DEALLOCATE(mat%val)
END IF
mat%nnz = 0
END SUBROUTINE destroy_zcsr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
FUNCTION vmx_csr_mat(mat, xarr, transa_in) RESULT(yarr)
!
! Return product mat*x
!
TYPE(csr_mat) :: mat
DOUBLE PRECISION, INTENT(in) :: xarr(:)
CHARACTER(len=1), OPTIONAL, INTENT(in) :: transa_in
DOUBLE PRECISION :: yarr(SIZE(xarr))
!
DOUBLE PRECISION :: alpha=1.0d0, beta=0.0d0
CHARACTER(len=1) :: transa
CHARACTER(len=6) :: matdescra
INTEGER :: n, i, j
!
n = mat%rank
transa = 'N'
IF(PRESENT(transa_in)) transa = transa_in
!
#ifdef MKL
matdescra = 'g'
CALL mkl_dcsrmv(transa, n, n, alpha, matdescra, mat%val, &
& mat%cols, mat%irow(1), mat%irow(2), xarr, &
& beta, yarr)
#else
yarr = 0.0d0
DO i=1,mat%rank
DO j=mat%irow(i), mat%irow(i+1)-1
IF(transa .EQ. 'N') THEN
yarr(i) = yarr(i) + mat%val(j)*xarr(mat%cols(j))
ELSE
yarr(mat%cols(j)) = yarr(mat%cols(j)) + mat%val(j)*xarr(i)
END IF
END DO
END DO
#endif
!
END FUNCTION vmx_csr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
FUNCTION vmx_zcsr_mat(mat, xarr, transa_in) RESULT(yarr)
!
! Return product mat*x
!
TYPE(zcsr_mat) :: mat
DOUBLE COMPLEX, INTENT(in) :: xarr(:)
CHARACTER(len=1), OPTIONAL, INTENT(in) :: transa_in
DOUBLE COMPLEX :: yarr(SIZE(xarr))
!
DOUBLE COMPLEX :: alpha=(1.0d0,0.0d0), beta=(0.0d0,0.0d0)
CHARACTER(len=1) :: transa
CHARACTER(len=6) :: matdescra
INTEGER :: n, i, j
!
n = mat%rank
transa = 'N'
IF(PRESENT(transa_in)) transa = transa_in
!
#ifdef MKL
matdescra = 'g'
CALL mkl_zcsrmv(transa, n, n, alpha, matdescra, mat%val, &
& mat%cols, mat%irow(1), mat%irow(2), xarr, &
& beta, yarr)
#else
yarr = 0.0d0
DO i=1,mat%rank
DO j=mat%irow(i), mat%irow(i+1)-1
IF(transa .EQ. 'N') THEN
yarr(i) = yarr(i) + mat%val(j)*xarr(mat%cols(j))
ELSE
yarr(mat%cols(j)) = yarr(mat%cols(j)) + mat%val(j)*xarr(i)
END IF
END DO
END DO
#endif
!
END FUNCTION vmx_zcsr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
FUNCTION vmx_csr_matn(mat, xarr, transa_in) RESULT(yarr)
!
! Return product mat*x
!
TYPE(csr_mat) :: mat
DOUBLE PRECISION, INTENT(in) :: xarr(:,:)
CHARACTER(len=1), OPTIONAL, INTENT(in) :: transa_in
DOUBLE PRECISION :: yarr(SIZE(xarr,1),SIZE(xarr,2))
!
DOUBLE PRECISION :: alpha=1.0d0, beta=0.0d0
CHARACTER(len=1) :: transa
INTEGER :: n, nrhs, i, j
CHARACTER(len=6) :: matdescra
!
n = mat%rank
nrhs = SIZE(xarr,2)
transa = 'N'
IF(PRESENT(transa_in)) transa = transa_in
!
#ifdef MKL
matdescra = 'g'
CALL mkl_dcsrmm(transa, n, nrhs, n, alpha, matdescra, mat%val,&
& mat%cols, mat%irow(1), mat%irow(2), xarr, &
& n, beta, yarr, n)
#else
yarr = 0.0d0
DO i=1,n
DO j=mat%irow(i), mat%irow(i+1)-1
IF(transa .EQ. 'N') THEN
yarr(i,:) = yarr(i,:) + mat%val(j)*xarr(mat%cols(j),:)
ELSE
yarr(mat%cols(j),:) = yarr(mat%cols(j),:) + mat%val(j)*xarr(i,:)
END IF
END DO
END DO
#endif
!
END FUNCTION vmx_csr_matn
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
FUNCTION vmx_zcsr_matn(mat, xarr, transa_in) RESULT(yarr)
!
! Return product mat*x
!
TYPE(zcsr_mat) :: mat
DOUBLE COMPLEX, INTENT(in) :: xarr(:,:)
CHARACTER(len=1), OPTIONAL, INTENT(in) :: transa_in
DOUBLE COMPLEX :: yarr(SIZE(xarr,1),SIZE(xarr,2))
!
DOUBLE COMPLEX :: alpha=(1.0d0,0.0d0), beta=(0.0d0,0.0d0)
CHARACTER(len=1) :: transa
INTEGER :: n, nrhs, i, j
CHARACTER(len=6) :: matdescra
!
n = mat%rank
nrhs = SIZE(xarr,2)
transa = 'N'
IF(PRESENT(transa_in)) transa = transa_in
!
#ifdef MKL
matdescra = 'g'
CALL mkl_zcsrmm(transa, n, nrhs, n, alpha, matdescra, mat%val,&
& mat%cols, mat%irow(1), mat%irow(2), xarr, &
& n, beta, yarr, n)
#else
yarr = (0.0d0,0.0d0)
DO i=1,n
DO j=mat%irow(i), mat%irow(i+1)-1
IF(transa .EQ. 'N') THEN
yarr(i,:) = yarr(i,:) + mat%val(j)*xarr(mat%cols(j),:)
ELSE
yarr(mat%cols(j),:) = yarr(mat%cols(j),:) + mat%val(j)*xarr(i,:)
END IF
END DO
END DO
#endif
!
END FUNCTION vmx_zcsr_matn
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE conmat_1d_csr(spl, mat, coefeq, maxder)
!
! Construction of FE matrix mat for 1D differential operator
! using spline spl
!
USE bsplines
TYPE(csr_mat) :: mat
TYPE(spline1d), INTENT(in) :: spl
!
- INCLUDE '../../bsplines/src/conmat_1d.tpl'
+ INCLUDE 'conmat_1d.tpl'
END SUBROUTINE conmat_1d_csr
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE conmat_1d_zcsr(spl, mat, coefeq, maxder)
!
! Construction of FE matrix mat for 1D differential operator
! using spline spl
!
USE bsplines
TYPE(zcsr_mat) :: mat
TYPE(spline1d), INTENT(in) :: spl
!
- INCLUDE '../../bsplines/src/zconmat_1d.tpl'
+ INCLUDE 'zconmat_1d.tpl'
END SUBROUTINE conmat_1d_zcsr
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE conmat_2d_csr(spl, mat, coefeq, maxder, nat_order)
!
! Construction of FE matrix mat for 2D differential operator
! using spline spl
!
USE bsplines
TYPE(spline2d), INTENT(in) :: spl
TYPE(csr_mat) :: mat
!
- INCLUDE '../../bsplines/src/conmat.tpl'
+ INCLUDE 'conmat.tpl'
END SUBROUTINE conmat_2d_csr
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE conmat_2d_zcsr(spl, mat, coefeq, maxder, nat_order)
!
! Construction of FE matrix mat for 2D differential operator
! using spline spl
!
USE bsplines
TYPE(spline2d), INTENT(in) :: spl
TYPE(zcsr_mat) :: mat
!
- INCLUDE '../../bsplines/src/zconmat.tpl'
+ INCLUDE 'zconmat.tpl'
END SUBROUTINE conmat_2d_zcsr
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE femat_csr(spl, mat, coefeq, nterms)
!
! Compute fe matrix
!
USE bsplines
TYPE(spline1d), INTENT(in) :: spl
TYPE(csr_mat), INTENT(inout) :: mat
INTEGER, INTENT(in) :: nterms
INTERFACE
SUBROUTINE coefeq(x, idt, idw, c)
DOUBLE PRECISION, INTENT(in) :: x
INTEGER, INTENT(out) :: idt(:), idw(:)
DOUBLE PRECISION, INTENT(out) :: c(:)
END SUBROUTINE coefeq
END INTERFACE
!
INTEGER :: nrank, nx, nidbas
!
CALL get_dim(spl, nrank, nx, nidbas)
IF(spl%period) nrank = nx
IF(mat%nnz.EQ.0) THEN
WRITE(*,'(a,i0,a)') 'FEMAT: Initialize mat with ', &
& nterms, ' terms ...'
CALL init(nrank, nterms, mat)
END IF
CALL conmat(spl, mat, coefeq)
END SUBROUTINE femat_csr
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE put_csr_mat(fid, label, mat, str)
!
! Write matrix to hdf5 file
!
USE futils
!
INTEGER, INTENT(in) :: fid
CHARACTER(len=*), INTENT(in) :: label
TYPE(csr_mat) :: mat
CHARACTER(len=*), OPTIONAL, INTENT(in) :: str
!
IF(PRESENT(str)) THEN
CALL creatg(fid, label, str)
ELSE
CALL creatg(fid, label)
END IF
CALL attach(fid, label, 'RANK', mat%rank)
CALL attach(fid, label, 'NNZ', mat%nnz)
CALL putarr(fid, TRIM(label)//'/irow', mat%irow)
CALL putarr(fid, TRIM(label)//'/cols', mat%cols)
CALL putarr(fid, TRIM(label)//'/idiag', mat%idiag)
CALL putarr(fid, TRIM(label)//'/val', mat%val)
END SUBROUTINE put_csr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE put_zcsr_mat(fid, label, mat, str)
!
! Write matrix to hdf5 file
!
USE futils
!
INTEGER, INTENT(in) :: fid
CHARACTER(len=*), INTENT(in) :: label
TYPE(zcsr_mat) :: mat
CHARACTER(len=*), OPTIONAL, INTENT(in) :: str
!
IF(PRESENT(str)) THEN
CALL creatg(fid, label, str)
ELSE
CALL creatg(fid, label)
END IF
CALL attach(fid, label, 'RANK', mat%rank)
CALL attach(fid, label, 'NNZ', mat%nnz)
CALL putarr(fid, TRIM(label)//'/irow', mat%irow)
CALL putarr(fid, TRIM(label)//'/cols', mat%cols)
CALL putarr(fid, TRIM(label)//'/idiag', mat%idiag)
CALL putarr(fid, TRIM(label)//'/val', mat%val)
END SUBROUTINE put_zcsr_mat
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
DOUBLE PRECISION FUNCTION matnorm_csr(mat, p)
!
! Compute matrix norm
!
TYPE(csr_mat), INTENT(in) :: mat
CHARACTER(len=*), OPTIONAL, INTENT(in) :: p
!
CHARACTER(len=4) :: norm_type
INTEGER :: i, j
DOUBLE PRECISION :: temp(mat%rank)
!
norm_type = 'fro'
IF(PRESENT(p)) norm_type = p
!
SELECT CASE (norm_type)
CASE ('inf')
DO i=1,mat%rank
temp(i) = SUM(ABS(mat%val(mat%irow(i):mat%irow(i+1)-1)))
END DO
matnorm_csr = MAXVAL(temp)
CASE ('1')
temp = 0.0d0
DO i=1,mat%rank
DO j=mat%irow(i), mat%irow(i+1)-1
temp(mat%cols(j)) = temp(mat%cols(j)) + ABS(mat%val(j))
END DO
END DO
matnorm_csr = MAXVAL(temp)
CASE('fro')
matnorm_csr = SQRT(DOT_PRODUCT(mat%val, mat%val))
END SELECT
END FUNCTION matnorm_csr
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE full_to_csr(fullmat, mat)
!
! Convert full rectangular matrix to csr mat
!
DOUBLE PRECISION, INTENT(inout) :: fullmat(:,:)
TYPE(csr_mat), INTENT(out) :: mat
!
INTEGER :: m, n, nnz
INTEGER :: i, j, k
!
m = SIZE(fullmat,1)
n = SIZE(fullmat,2)
CALL init(m, 0, mat, ncols=n)
!
! Determine nnz of matrix
!
IF(ASSOCIATED(mat%irow)) DEALLOCATE(mat%irow)
IF(ASSOCIATED(mat%idiag)) DEALLOCATE(mat%idiag)
IF(ASSOCIATED(mat%cols)) DEALLOCATE(mat%cols)
IF(ASSOCIATED(mat%val)) DEALLOCATE(mat%val)
!
ALLOCATE(mat%irow(m+1))
ALLOCATE(mat%idiag(m))
!
! Clear matrix small elements of fullmat
WHERE( ABS(fullmat) < 1.d-8) fullmat=0.0d0
!
mat%irow(1) = 1
nnz = 0
DO i=1,m
DO j=1,n
- IF(ABS(fullmat(i,j)).GT.EPSILON(0.0d0)) THEN
+ IF(ABS(fullmat(i,j)).GT.EPSILON(0.0d0)) THEN
nnz = nnz+1
IF(m.EQ.n .AND. i.EQ.j) THEN ! Only for square matrix
mat%idiag(i) = nnz
END IF
END IF
END DO
mat%irow(i+1) = nnz+1
END DO
!
! Allocate and fill the csr matrix structure
!
mat%nnz = nnz
ALLOCATE(mat%cols(nnz))
ALLOCATE(mat%val(nnz))
k=0
DO i=1,m
DO j=1,n
- IF(ABS(fullmat(i,j)).GT.EPSILON(0.0d0)) THEN
+ IF(ABS(fullmat(i,j)).GT.EPSILON(0.0d0)) THEN
k=k+1
mat%cols(k) = j
mat%val(k) = fullmat(i,j)
END IF
END DO
END DO
END SUBROUTINE full_to_csr
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE full_to_zcsr(fullmat, mat)
!
! Convert full rectangular matrix to csr mat
!
DOUBLE COMPLEX, INTENT(inout) :: fullmat(:,:)
TYPE(zcsr_mat), INTENT(out) :: mat
!
INTEGER :: m, n, nnz
INTEGER :: i, j, k
!
m = SIZE(fullmat,1)
n = SIZE(fullmat,2)
CALL init(m, 0, mat, ncols=n)
!
! Determine nnz of matrix
!
IF(ASSOCIATED(mat%irow)) DEALLOCATE(mat%irow)
IF(ASSOCIATED(mat%idiag)) DEALLOCATE(mat%idiag)
IF(ASSOCIATED(mat%cols)) DEALLOCATE(mat%cols)
IF(ASSOCIATED(mat%val)) DEALLOCATE(mat%val)
!
ALLOCATE(mat%irow(m+1))
ALLOCATE(mat%idiag(m))
!
! Clear matrix small elements of fullmat
WHERE( ABS(fullmat) < 1.d-8) fullmat=(0.0d0,0.0d0)
!
mat%irow(1) = 1
nnz = 0
DO i=1,m
DO j=1,n
- IF(ABS(fullmat(i,j)).GT.EPSILON(0.0d0)) THEN
+ IF(ABS(fullmat(i,j)).GT.EPSILON(0.0d0)) THEN
nnz = nnz+1
IF(m.EQ.n .AND. i.EQ.j) THEN ! Only for square matrix
mat%idiag(i) = nnz
END IF
END IF
END DO
mat%irow(i+1) = nnz+1
END DO
!
! Allocate and fill the csr matrix structure
!
mat%nnz = nnz
ALLOCATE(mat%cols(nnz))
ALLOCATE(mat%val(nnz))
k=0
DO i=1,m
DO j=1,n
- IF(ABS(fullmat(i,j)).GT.EPSILON(0.0d0)) THEN
+ IF(ABS(fullmat(i,j)).GT.EPSILON(0.0d0)) THEN
k=k+1
mat%cols(k) = j
mat%val(k) = fullmat(i,j)
END IF
END DO
END DO
END SUBROUTINE full_to_zcsr
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE check_dom(mat)
!
! Check whether mat is strict diagonal dominabce.
-!
+!
TYPE(csr_mat), INTENT(in) :: mat
DOUBLE PRECISION :: arow(mat%rank), asum(mat%rank)
INTEGER :: n, i, j1, j2, jdiag
!
n = mat%rank
DO i=1,n
j1 = mat%irow(i)
jdiag = mat%idiag(i)
j2 = mat%irow(i+1)-1
asum(i) = SUM(ABS(mat%val(j1:j2))) / ABS(mat%val(jdiag)) - 1.0d0
END DO
WRITE(*,'(/a,1pe12.3)') 'Max of sum of off-diag', MAXVAL(asum)
!
END SUBROUTINE check_dom
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SUBROUTINE kron_csr(mata, matb, matc)
!
! Kronecker product of 2 CSR matrices
!
USE sparse, ONLY : isearch
TYPE(csr_mat), INTENT(in) :: mata, matb
TYPE(csr_mat), INTENT(out) :: matc
!
INTEGER :: m1, n1, nnz1, m2, n2, nnz2, m, n, nnz
INTEGER :: i,i1,i2,j1,s,s1,s2,e,e1,e2,k,nc2
!
m1 = mata%mrows
n1 = mata%ncols
nnz1 = mata%nnz
m2 = matb%mrows
n2 = matb%ncols
nnz2 = matb%nnz
m = m1*m2
n = n1*n2
nnz = nnz1*nnz2
!
CALL init(m, 0, matc, ncols=n)
matc%nnz = nnz
IF(ASSOCIATED(matc%irow)) DEALLOCATE(matc%irow)
IF(ASSOCIATED(matc%idiag)) DEALLOCATE(matc%idiag)
IF(ASSOCIATED(matc%cols)) DEALLOCATE(matc%cols)
IF(ASSOCIATED(matc%val)) DEALLOCATE(matc%val)
ALLOCATE(matc%irow(m+1))
IF(m.EQ.n) THEN
ALLOCATE(matc%idiag(m)) ! Only for square matrices
END IF
ALLOCATE(matc%cols(nnz))
ALLOCATE(matc%val(nnz))
!
k = 0
matc%irow(1) = 1
DO i1=1,m1
s1=mata%irow(i1)
e1=mata%irow(i1+1)-1
DO i2=1,m2
s2=matb%irow(i2)
e2=matb%irow(i2+1)-1
nc2=e2-s2+1
DO j1=s1,e1
matc%val(k+1:k+nc2) = mata%val(j1)*matb%val(s2:e2)
matc%cols(k+1:k+nc2) = (mata%cols(j1)-1)*n2 + matb%cols(s2:e2)
k = k+nc2
matc%irow((i1-1)*m2+i2+1) = k+1 ! Points to next row
END DO
END DO
END DO
!
! Search the diagonals
DO i=1,matc%mrows
s = matc%irow(i)
e = matc%irow(i+1)-1
matc%idiag(i) = isearch(matc%cols(s:e),i) + s
END DO
END SUBROUTINE kron_csr
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
END MODULE csr