LCOV - code coverage report
Current view: top level - src/78_effpot - m_spmat_csr.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 70.6 % 109 77
Test Date: 2026-11-10 15:53:16 Functions: 63.6 % 11 7
Branches: 28.8 % 222 64

             Branch data     Line data    Source code
       1                 :             : !!****m* ABINIT/m_spmat_csr
       2                 :             : !! NAME
       3                 :             : !! m_spmat_csr
       4                 :             : !!
       5                 :             : !! FUNCTION
       6                 :             : !! This module contains the a CSR (compressed row) format of sparse matrix.
       7                 :             : !! Efficient for mat vec multiplication.
       8                 :             : !! MPI matvec is also implemented.
       9                 :             : !! Datatypes:
      10                 :             : !!  CSR_mat_t: CSR matrix
      11                 :             : !!
      12                 :             : !! Subroutines:
      13                 :             : !! TODO: add this when F2003 doc style is determined.
      14                 :             : !!
      15                 :             : !!
      16                 :             : !! COPYRIGHT
      17                 :             : !! Copyright (C) 2001-2026 ABINIT group (hexu)
      18                 :             : !! This file is distributed under the terms of the
      19                 :             : !! GNU General Public License, see ~abinit/COPYING
      20                 :             : !! or http://www.gnu.org/copyleft/gpl.txt .
      21                 :             : !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt .
      22                 :             : !!
      23                 :             : !! SOURCE
      24                 :             : 
      25                 :             : #if defined HAVE_CONFIG_H
      26                 :             : #include "config.h"
      27                 :             : #endif
      28                 :             : #include "abi_common.h"
      29                 :             : 
      30                 :             : module m_spmat_csr
      31                 :             :   use defs_basis
      32                 :             :   use m_abicore
      33                 :             :   use m_xmpi
      34                 :             :   use m_errors
      35                 :             :   use m_spmat_base, only: base_mat2d_t
      36                 :             :   use m_mpi_scheduler
      37                 :             :   implicit none
      38                 :             : !!***
      39                 :             :   private
      40                 :             :   !!----------- CSR ------------------------
      41                 :             :   ! CSR sparse matrix
      42                 :             :   ! nnz: number of non-zeros.
      43                 :             :   ! icol : column index of entries .size:nnz
      44                 :             :   ! row_shift: row_shift(irow) to row_shift(irow+1)-1  are the index
      45                 :             :   !            of column and values for entries. size : nrow+1
      46                 :             :   ! val: values of non-zero entries. size(nnz)
      47                 :             :   !type, public, extends(base_mat_t) :: CSR_mat_t
      48                 :             :   type, public, extends(base_mat2d_t) :: CSR_mat_t
      49                 :             :      integer :: nnz
      50                 :             :      integer, allocatable :: icol(:), row_shift(:)
      51                 :             :      real(dp), allocatable:: val(:)
      52                 :             :      type(mpi_scheduler_t) :: mps
      53                 :             :    contains
      54                 :             :      procedure :: initialize
      55                 :             :      procedure :: set
      56                 :             :      procedure :: finalize=> csr_mat_t_finalize
      57                 :             :      procedure :: mv => csr_mat_t_mv ! mat vec multiplication serial version
      58                 :             :      procedure :: sync ! sync data to all mpi ranks
      59                 :             :      procedure :: mv_mpi => csr_mat_t_mv_mpi ! mpi version of mv
      60                 :             :      procedure :: mv_select_row =>csr_mat_t_mv_select_row ! mv of selected rows
      61                 :             :      procedure :: mv_one_row =>csr_mat_t_mv_one_row ! mv of one rows
      62                 :             :      procedure :: get_block => csr_mat_t_get_block  ! get a block into a dense matrix
      63                 :             :   end type CSR_mat_t
      64                 :             : 
      65                 :             : contains
      66                 :             : 
      67                 :             :   !-----------------------------------------------------------------------
      68                 :             :   !> @brief initialization
      69                 :             :   !> @param [in] mshape: shape of matrix, should be size 2.
      70                 :             :   !-----------------------------------------------------------------------
      71         [ -  + ]:           3 :   subroutine initialize(self, mshape)
      72                 :             :     class(csr_mat_t), intent(inout) :: self
      73                 :             :     integer, intent(in) :: mshape(:)
      74         [ -  + ]:           3 :     if (size(mshape)/=2) stop "mshape should be size 2"
      75                 :           3 :     call self%base_mat_t%initialize(mshape)
      76                 :           3 :     self%nrow=mshape(1)
      77                 :           3 :     self%ncol=mshape(2)
      78                 :           3 :   end subroutine initialize
      79                 :             : 
      80                 :             :   !-----------------------------------------------------------------------
      81                 :             :   !> @brief set the full csr matrix
      82                 :             :   !> @param [in] nnz: number of entries
      83                 :             :   !> @param [in] icol:
      84                 :             :   !> @param [in] row_shift:
      85                 :             :   !> @param [in] val: values:
      86                 :             :   !-----------------------------------------------------------------------
      87   [ -  +  -  -  :           3 :   subroutine set(self,  nnz, icol, row_shift, val)
          -  -  -  +  -  
          -  -  -  -  +  
             -  -  -  - ]
      88                 :             :     class(CSR_mat_t), intent(inout) :: self
      89                 :             :     integer, intent(in) :: nnz
      90                 :             :     ! i: col number of each entry
      91                 :             :     ! j: first 0, n1, n1+n2, ...
      92                 :             :     ! val(irow, irow+1) are the values of entries in row irow.
      93                 :             :     integer , intent(in), optional :: icol(:), row_shift(:)
      94                 :             :     real(dp), intent(in), optional :: val(:)
      95                 :             :     integer :: iproc
      96                 :             : 
      97                 :           3 :     iproc=xmpi_comm_rank(xmpi_world)
      98         [ -  + ]:           3 :     if (iproc/=0) then
      99                 :           0 :        ABI_ERROR("This function (CSR_MAT%set) should be only used on root node")
     100                 :             :     end if
     101                 :             : 
     102                 :           3 :     self%nnz=nnz
     103         [ +  - ]:           3 :     if(.not. allocated(self%icol)) then
     104   [ -  +  +  -  :           9 :        ABI_MALLOC(self%icol, (self%nnz))
          +  -  +  -  -  
             +  -  +  -  
                      + ]
     105                 :             :     endif
     106                 :             : 
     107         [ +  - ]:           3 :     if(.not. allocated(self%row_shift)) then
     108   [ +  -  -  +  :           9 :        ABI_MALLOC(self%row_shift, (self%nrow+1))
          +  -  +  -  +  
          -  -  +  -  +  
                   -  + ]
     109                 :             :     endif
     110                 :             : 
     111         [ +  - ]:           3 :     if(.not. allocated(self%val)) then
     112   [ -  +  +  -  :           9 :        ABI_MALLOC(self%val, (self%nnz))
          +  -  +  -  -  
             +  -  +  -  
                      + ]
     113                 :             :     endif
     114                 :             : 
     115         [ -  + ]:           3 :     if (present(icol)) then
     116         [ #  # ]:           0 :        self%icol(:)=icol(:)
     117                 :             :     end if
     118         [ -  + ]:           3 :     if (present(row_shift)) then
     119         [ #  # ]:           0 :        self%row_shift(:)=row_shift(:)
     120                 :             :     end if
     121         [ -  + ]:           3 :     if (present(icol)) then
     122         [ #  # ]:           0 :        self%val(:)=val(:)
     123                 :             :     end if
     124                 :             : 
     125                 :           3 :   end subroutine set
     126                 :             : 
     127                 :             :   !-----------------------------------------------------------------------
     128                 :             :   !> @brief sync the matrix from master node to all nodes
     129                 :             :   !> @param [in] master: the id of master node
     130                 :             :   !> @param [in] comm: the communicator
     131                 :             :   !> @param [in] nblock: the minimal block for assigning the tasks to nodes.
     132                 :             :   !-----------------------------------------------------------------------
     133                 :          18 :   subroutine sync(self, master, comm, nblock)
     134                 :             :     class (csr_mat_t), intent(inout) :: self
     135                 :             :     integer , intent(in) :: master, comm, nblock
     136                 :             :     integer :: ierr, iproc
     137                 :           2 :     iproc=xmpi_comm_rank(xmpi_world)
     138                 :             : 
     139                 :           2 :     call xmpi_barrier(xmpi_world)
     140                 :           2 :     call xmpi_bcast(self%ndim, master, comm, ierr)
     141                 :           2 :     call xmpi_bcast(self%ncol, master, comm, ierr)
     142                 :           2 :     call xmpi_bcast(self%nrow, master, comm, ierr)
     143                 :           2 :     call xmpi_bcast(self%nnz, master, comm, ierr)
     144                 :             : 
     145                 :           2 :     call self%mps%initialize(self%nrow/nblock, master, comm, nblock)
     146         [ -  + ]:           2 :     if (.not. self%mps%irank==master) then
     147         [ #  # ]:           0 :        if(.not. allocated(self%mshape)) then
     148   [ #  #  #  #  :           0 :           ABI_MALLOC(self%mshape, (self%ndim))
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     149                 :             :        endif
     150                 :             : 
     151         [ #  # ]:           0 :        if(.not. allocated(self%icol)) then
     152   [ #  #  #  #  :           0 :           ABI_MALLOC(self%icol, (self%nnz))
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     153                 :             :        endif
     154                 :             : 
     155         [ #  # ]:           0 :        if(.not. allocated(self%row_shift)) then
     156   [ #  #  #  #  :           0 :           ABI_MALLOC(self%row_shift, (self%nrow+1))
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     157                 :             :        endif
     158         [ #  # ]:           0 :        if(.not. allocated(self%val)) then
     159   [ #  #  #  #  :           0 :           ABI_MALLOC(self%val, (self%nnz))
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     160                 :             :        endif
     161                 :             :     end if
     162                 :             : 
     163                 :             :     ! TODO: no need to send all the data to all the
     164                 :             :     ! only the corresponding row data.
     165                 :           2 :     call xmpi_bcast(self%mshape, master, comm, ierr)
     166                 :           2 :     call xmpi_bcast(self%icol, master, comm, ierr)
     167                 :           2 :     call xmpi_bcast(self%row_shift, master, comm, ierr)
     168                 :           2 :     call xmpi_bcast(self%val, master, comm, ierr)
     169                 :           2 :   end subroutine sync
     170                 :             : 
     171                 :             : 
     172                 :             :   !-----------------------------------------------------------------------
     173                 :             :   !> @brief Finalize
     174                 :             :   !-----------------------------------------------------------------------
     175                 :           3 :   subroutine CSR_mat_t_finalize(self)
     176                 :             :     class(CSR_mat_t), intent(inout) :: self
     177                 :           3 :     self%ncol=0
     178                 :           3 :     self%nrow=0
     179                 :           3 :     self%nnz=0
     180                 :           3 :     self%ndim=0
     181                 :           3 :     call self%mps%finalize()
     182         [ +  - ]:           3 :     if(allocated(self%icol)) then
     183                 :           3 :        ABI_FREE(self%icol)
     184                 :             :     endif
     185         [ +  - ]:           3 :     if(allocated(self%row_shift)) then
     186                 :           3 :        ABI_FREE(self%row_shift)
     187                 :             :     endif
     188         [ +  - ]:           3 :     if(allocated(self%val)) then
     189                 :           3 :        ABI_FREE(self%val)
     190                 :             :     endif
     191         [ +  - ]:           3 :     if(allocated(self%mshape)) then
     192                 :           3 :        ABI_FREE(self%mshape)
     193                 :             :     endif
     194                 :           3 :   end subroutine CSR_mat_t_finalize
     195                 :             : 
     196                 :             : 
     197                 :             :   !-----------------------------------------------------------------------
     198                 :             :   !> @brief Matrix vector multiplication
     199                 :             :   !> @param [in] x : M x = b
     200                 :             :   !> @param [out] b: M x = b
     201                 :             :   !-----------------------------------------------------------------------
     202                 :       42000 :   subroutine CSR_mat_t_mv(self, x, b)
     203                 :             :     class(CSR_mat_t), intent(in):: self
     204                 :             :     real(dp), intent(in) :: x(self%ncol)
     205                 :             :     real(dp), intent(out) :: b(self%nrow)
     206                 :             :     integer::irow, i1, i2, i
     207         [ +  + ]:    43050000 :     b(:)=0.0d0
     208                 :             :     !$OMP PARALLEL DO private(i, i1, i2)
     209         [ +  + ]:    43050000 :     do irow=1, self%nrow
     210                 :    43008000 :         i1=self%row_shift(irow)
     211                 :    43008000 :         i2=self%row_shift(irow+1)-1
     212         [ +  + ]:  2881578000 :         do i=i1, i2
     213                 :  2881536000 :             b(irow)=b(irow)+ self%val(i)*x(self%icol(i))
     214                 :             :         end do
     215                 :             :     enddo
     216                 :             :     !$OMP END PARALLEL DO
     217                 :       42000 :   end subroutine CSR_mat_t_mv
     218                 :             : 
     219                 :             :   !-----------------------------------------------------------------------
     220                 :             :   !> @brief Matrix vector multiplication (mpi version)
     221                 :             :   !> @param [in] x : M x = b
     222                 :             :   !> @param [out] b: M x = b
     223                 :             :   !-----------------------------------------------------------------------
     224                 :        4006 :   subroutine CSR_mat_t_mv_mpi(self, x, b, bcastx, syncb)
     225                 :             :     class(CSR_mat_t), intent(in) :: self
     226                 :             :     real(dp), intent(inout) :: x(self%ncol)
     227                 :             :     logical, intent(in) :: bcastx, syncb
     228                 :             :     real(dp), intent(out) :: b(self%nrow)
     229                 :             :     !real(dp):: my_b(self%nrow)
     230                 :             :     integer :: ierr, irow,  i1, i2, i
     231         [ -  + ]:        4006 :     if (bcastx) then
     232                 :           0 :         call xmpi_bcast(x, 0, xmpi_world, ierr)
     233                 :             :     end if
     234                 :             :     !if (.not. iam_master) b(:)=0.0_dp
     235                 :             :     !my_b(:)=0.0_dp
     236         [ +  + ]:     2599894 :     b(:)=0.0_dp
     237         [ +  + ]:     2599894 :     do irow= self%mps%istart, self%mps%iend
     238                 :     2595888 :        i1=self%row_shift(irow)
     239                 :     2595888 :        i2=self%row_shift(irow+1)-1
     240         [ +  + ]:    70092982 :        do i=i1, i2
     241                 :    70088976 :           b(irow)=b(irow)+ self%val(i)*x(self%icol(i))
     242                 :             :        end do
     243                 :             :     enddo
     244                 :             :     ! TODO : use gather instead of reduce?
     245                 :             :     !call mpi_reduce(my_b, b, self%nrow, MPI_DOUBLE_PRECISION, MPI_SUM, 0, MPI_COMM_WORLD, ierr)
     246         [ -  + ]:        4006 :     if (syncb) then
     247                 :           0 :        call xmpi_sum_master(b, 0, xmpi_world, ierr )
     248                 :             :     endif
     249                 :        4006 :   end subroutine CSR_mat_t_mv_mpi
     250                 :             : 
     251                 :             :   !-----------------------------------------------------------------------
     252                 :             :   !> @brief multiple a row, indexed by  of M by x:   y_i=  Mij x_j
     253                 :             :   !> @param [in] nrow: number of rows.
     254                 :             :   !> @param [in] ind_row: indices i
     255                 :             :   !> @param [in]  x: x
     256                 :             :   !> @param [out]  y: y
     257                 :             :   !-----------------------------------------------------------------------
     258                 :           0 :   subroutine CSR_mat_t_mv_one_row(self,  j, x, y)
     259                 :             :     class(CSR_mat_t), intent(in)::self
     260                 :             :     integer, intent(in) ::j
     261                 :             :     real(dp), intent(in) :: x(self%ncol)
     262                 :             :     real(dp), intent(out) :: y
     263                 :             :     integer :: i,  i1, i2
     264                 :           0 :     y=0.0_dp
     265                 :           0 :     i1=self%row_shift(j)
     266                 :           0 :     i2=self%row_shift(j+1)-1
     267         [ #  # ]:           0 :     do i=i1, i2
     268                 :           0 :        y= y+self%val(i)*x(self%icol(i))
     269                 :             :     end do
     270                 :           0 :   end subroutine CSR_mat_t_mv_one_row
     271                 :             : 
     272                 :             : 
     273                 :             :   !-----------------------------------------------------------------------
     274                 :             :   !> @brief multiple a submatrix (rows indexed by i) of M by x:   y_i=\sum M_ij x_j
     275                 :             :   !> @param [in] nrow: number of rows.
     276                 :             :   !> @param [in] ind_row: indices i
     277                 :             :   !> @param [in]  x: x
     278                 :             :   !> @param [out]  y: y
     279                 :             :   !-----------------------------------------------------------------------
     280                 :           0 :   subroutine CSR_mat_t_mv_select_row(self, nrow, id_row, x, y)
     281                 :             :     class(CSR_mat_t), intent(in)::self
     282                 :             :     integer, intent(in) :: nrow,  id_row(nrow)
     283                 :             :     real(dp), intent(in) :: x(self%ncol)
     284                 :             :     real(dp), intent(out) :: y(nrow)
     285                 :             :     integer :: i, irow, i1, i2, j
     286         [ #  # ]:           0 :     y(:)=0.0_dp
     287         [ #  # ]:           0 :     do j=1, nrow
     288                 :           0 :        irow=id_row(j)
     289                 :           0 :        i1=self%row_shift(irow)
     290                 :           0 :        i2=self%row_shift(irow+1)-1
     291         [ #  # ]:           0 :        do i=i1, i2
     292                 :           0 :           y(j)= y(j)+self%val(i)*x(self%icol(i))
     293                 :             :        end do
     294                 :             :     end do
     295                 :           0 :   end subroutine CSR_mat_t_mv_select_row
     296                 :             : 
     297                 :         432 :   subroutine CSR_mat_t_get_block(self,irow_start, icol_start, nrow, ncol, blk)
     298                 :             :     class(CSR_mat_t), intent(in)::self
     299                 :             :     integer, intent(in) :: nrow,  irow_start, ncol, icol_start
     300                 :             :     real(dp), intent(out) :: blk(nrow, ncol)
     301                 :             :     integer :: i, irow, i1, i2, j, icol
     302   [ +  +  +  + ]:        5616 :     blk(:, :)=0.0_dp
     303         [ +  + ]:        1728 :     do j=1, nrow
     304                 :        1296 :        irow = irow_start+j-1
     305                 :        1296 :        i1=self%row_shift(irow)
     306                 :        1296 :        i2=self%row_shift(irow+1)-1
     307         [ +  + ]:       35424 :        do i=i1, i2
     308                 :       33696 :           icol = self%icol(i)
     309   [ +  +  -  + ]:       34992 :           if(icol>=icol_start .and. icol<icol_start+ncol) then
     310                 :           0 :               blk(j, icol-icol_start+1) = self%val(i)
     311                 :             :           endif
     312                 :             :        end do
     313                 :             :     end do
     314                 :         432 :   end subroutine CSR_mat_t_get_block
     315                 :             : 
     316                 :             : !  subroutine print(self)
     317                 :             : !    class(CSR_mat_t), intent(in) :: self
     318                 :             : !    print *, "icol:", self%icol
     319                 :             : !    print *, "row_shift:", self%row_shift
     320                 :             : !    print *, "val:", self%val
     321                 :             : !  end subroutine print
     322                 :             : 
     323   [ #  #  #  #  :           0 : end module m_spmat_csr
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
        

Generated by: LCOV version 2.3-1