!>
!> @file p2p_mat.tpl
!>
!> @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
!>
INTEGER, INTENT(in) :: dest
CHARACTER(len=*), INTENT(in) :: extyp ! ('send', 'recv', 'sendrecv')
CHARACTER(len=*), INTENT(in) :: op ! ('put', 'updt')
INTEGER, INTENT(in) :: comm
!
INTEGER :: ierr
INTEGER :: nrank, nnz, nnz_rem
INTEGER :: i, s, idx, bufsize, position
CHARACTER(len=1), ALLOCATABLE :: sbuf(:), rbuf(:)
INTEGER, ALLOCATABLE :: irow(:), cols(:)
!--------------------------------------------------------------------------
! 1.0 Prologue
!
nrank = mat%rank
nnz = get_count(mat)
CALL mpi_sendrecv(nnz, 1, MPI_INTEGER, dest, 0, &
& nnz_rem, 1, MPI_INTEGER, dest, 0, &
& comm, MPI_STATUS_IGNORE, ierr)
!--------------------------------------------------------------------------
! 2.0 Send or sendrecv
!
IF(extyp.EQ.'send' .OR. extyp.EQ.'sendrecv') THEN
!
! Allocate packed send buffer
bufsize = 0
CALL mpi_pack_size(nrank+1, MPI_INTEGER, comm, s, ierr); bufsize=bufsize+s
CALL mpi_pack_size(nnz, MPI_INTEGER, comm, s, ierr); bufsize=bufsize+s
CALL mpi_pack_size(nnz, mpi_type, comm, s, ierr); bufsize=bufsize+s
ALLOCATE(sbuf(bufsize))
!
! Obtain matrix CSR arrays and pack
CALL to_mat(mat, nlkeep=.TRUE.)
position = 0
CALL mpi_pack(mat%irow, nrank+1, MPI_INTEGER, sbuf, bufsize, position, comm, ierr)
CALL mpi_pack(mat%cols, nnz, MPI_INTEGER, sbuf, bufsize, position, comm, ierr)
CALL mpi_pack(mat%val, nnz, mpi_type, sbuf, bufsize, position, comm, ierr)
DEALLOCATE(mat%irow)
DEALLOCATE(mat%cols)
DEALLOCATE(mat%val)
!
! Communicate packed buffer
IF(extyp.EQ.'send') THEN
CALL mpi_send(sbuf, position, MPI_PACKED, dest, 0, comm, ierr)
DEALLOCATE(sbuf)
END IF
END IF
!--------------------------------------------------------------------------
! 3.0 Sendrecv or recv
!
IF(extyp.EQ.'recv' .OR. extyp.EQ.'sendrecv') THEN
!
! Allocate unpacked received buffer
bufsize = 0
CALL mpi_pack_size(nrank+1, MPI_INTEGER, comm, s, ierr); bufsize=bufsize+s
CALL mpi_pack_size(nnz_rem, MPI_INTEGER, comm, s, ierr); bufsize=bufsize+s
CALL mpi_pack_size(nnz_rem, mpi_type, comm, s, ierr); bufsize=bufsize+s
ALLOCATE(rbuf(bufsize))
!
! Communicate packed buffer
IF(extyp.EQ.'recv') THEN
CALL mpi_recv(rbuf, bufsize, MPI_PACKED, dest, 0, comm, MPI_STATUS_IGNORE, ierr)
ELSE IF(extyp.EQ.'sendrecv') THEN
CALL mpi_sendrecv(sbuf, position, MPI_PACKED, dest, 0, &
& rbuf, bufsize, MPI_PACKED, dest, 0, &
& comm, MPI_STATUS_IGNORE, ierr)
DEALLOCATE(sbuf)
END IF
!
! Unpacked rbuf
ALLOCATE(irow(nrank+1))
ALLOCATE(cols(nnz_rem))
ALLOCATE(val(nnz_rem))
position = 0
CALL mpi_unpack(rbuf, bufsize, position, irow, nrank+1, MPI_INTEGER, comm, ierr)
CALL mpi_unpack(rbuf, bufsize, position, cols, nnz_rem, MPI_INTEGER, comm, ierr)
CALL mpi_unpack(rbuf, bufsize, position, val, nnz_rem, mpi_type, comm, ierr)
DEALLOCATE(rbuf)
!
! Update/replace sparse matrix
DO i=1,nrank
DO idx=irow(i),irow(i+1)-1
IF(op.EQ.'updt') THEN
CALL updtmat(mat, i, cols(idx), val(idx))
ELSE IF(op.EQ.'put') THEN
CALL putele(mat, i, cols(idx), val(idx))
END IF
END DO
END DO
DEALLOCATE(irow)
DEALLOCATE(cols)
DEALLOCATE(val)
!
END IF
!--------------------------------------------------------------------------