1#ifndef AMREX_SP_MATRIX_H_
2#define AMREX_SP_MATRIX_H_
3#include <AMReX_Config.H>
11#if defined(AMREX_USE_CUDA)
13#elif defined(AMREX_USE_HIP)
14# include <rocsparse/rocsparse.h>
15#elif defined(AMREX_USE_SYCL)
16# include <mkl_version.h>
17# include <oneapi/mkl/spblas.hpp>
23#include <unordered_map>
47 explicit operator bool()
const {
return b; }
53 explicit operator bool()
const {
return b; }
203 return m_csr.
mat.data();
258 template <
typename F>
291 template <
typename U,
template<
typename>
class M,
typename N>
friend
294 template <
typename U,
template<
typename>
class M>
friend
297 template <
typename U>
friend class AMG;
311 template <
typename I>
313 Long nentries,
Long const* row_offset);
331 void set_num_neighbors ();
335 Long m_row_begin = 0;
337 Long m_col_begin = 0;
344 bool m_split =
false;
377 int m_num_neighbors = -1;
424 template <
typename C>
439inline bool spmat_comm_is_local (AlgPartition
const& row_partition,
440 AlgPartition
const& col_partition)
442 int const rp = row_partition.singleActiveProc();
443 int const cp = col_partition.singleActiveProc();
444 return row_partition.numActiveProcs() <= 1
445 && col_partition.numActiveProcs() <= 1
446 && (rp < 0 || cp < 0 || rp == cp);
450void transpose (CsrView<T>
const& csrt, CsrView<T const>
const& csr)
452 Long nrows = csr.nrows;
453 Long ncols = csrt.nrows;
456 if (nrows <= 0 || ncols <= 0 || nnz <= 0) {
458 auto* p = csrt.row_offset;
466#if defined(AMREX_USE_CUDA)
468 cusparseHandle_t handle;
472 cudaDataType data_type;
473 if constexpr (std::is_same_v<T,float>) {
474 data_type = CUDA_R_32F;
475 }
else if constexpr (std::is_same_v<T,double>) {
476 data_type = CUDA_R_64F;
477 }
else if constexpr (std::is_same_v<T,GpuComplex<float>>) {
478 data_type = CUDA_C_32F;
479 }
else if constexpr (std::is_same_v<T,GpuComplex<double>>) {
480 data_type = CUDA_C_64F;
482 amrex::Abort(
"SpMatrix transpose: unsupported data type");
486 ncols <
Long(std::numeric_limits<int>::max()) &&
487 nnz <
Long(std::numeric_limits<int>::max()));
489 auto* csr_col_index = (
int*)
The_Arena()->
alloc(csr.nnz*
sizeof(
int));
491 auto* csrt_col_index = (
int*)
The_Arena()->
alloc(csrt.nnz*
sizeof(
int));
497 csr_col_index[i] = int(csr.col_index[i]);
499 if (i < csr.nrows+1) {
500 csr_row_offset[i] = int(csr.row_offset[i]);
504 std::size_t buffer_size;
506 cusparseCsr2cscEx2_bufferSize(handle,
int(nrows),
int(ncols),
int(nnz),
507 csr.mat, csr_row_offset, csr_col_index,
508 csrt.mat, csrt_row_offset, csrt_col_index,
509 data_type, CUSPARSE_ACTION_NUMERIC,
510 CUSPARSE_INDEX_BASE_ZERO,
511 CUSPARSE_CSR2CSC_ALG1,
517 cusparseCsr2cscEx2(handle,
int(nrows),
int(ncols),
int(nnz),
518 csr.mat, csr_row_offset, csr_col_index,
519 csrt.mat, csrt_row_offset, csrt_col_index,
520 data_type, CUSPARSE_ACTION_NUMERIC,
521 CUSPARSE_INDEX_BASE_ZERO,
522 CUSPARSE_CSR2CSC_ALG1,
528 csrt.col_index[i] = csrt_col_index[i];
530 if (i < csrt.nrows+1) {
531 csrt.row_offset[i] = csrt_row_offset[i];
543#elif defined(AMREX_USE_HIP)
545 rocsparse_handle handle;
546 AMREX_ROCSPARSE_SAFE_CALL(rocsparse_create_handle(&handle));
547 AMREX_ROCSPARSE_SAFE_CALL(rocsparse_set_stream(handle,
Gpu::gpuStream()));
550 ncols <
Long(std::numeric_limits<rocsparse_int>::max()) &&
551 nnz <
Long(std::numeric_limits<rocsparse_int>::max()));
553 rocsparse_int* csr_col_index;
554 rocsparse_int* csr_row_offset;
555 rocsparse_int* csrt_col_index;
556 rocsparse_int* csrt_row_offset;
557 if (std::is_same_v<rocsparse_int,Long>) {
558 csr_col_index = (rocsparse_int*)csr.col_index;
559 csr_row_offset = (rocsparse_int*)csr.row_offset;
560 csrt_col_index = (rocsparse_int*)csrt.col_index;
561 csrt_row_offset = (rocsparse_int*)csrt.row_offset;
563 csr_col_index = (rocsparse_int*)
The_Arena()->
alloc(csr.nnz*
sizeof(rocsparse_int));
564 csr_row_offset = (rocsparse_int*)
The_Arena()->
alloc((csr.nrows+1)*
sizeof(rocsparse_int));
565 csrt_col_index = (rocsparse_int*)
The_Arena()->
alloc(csrt.nnz*
sizeof(rocsparse_int));
566 csrt_row_offset = (rocsparse_int*)
The_Arena()->
alloc((csrt.nrows+1)*
sizeof(rocsparse_int));
570 csr_col_index[i] = rocsparse_int(csr.col_index[i]);
572 if (i < csr.nrows+1) {
573 csr_row_offset[i] = rocsparse_int(csr.row_offset[i]);
578 std::size_t buffer_size;
579 AMREX_ROCSPARSE_SAFE_CALL(
580 rocsparse_csr2csc_buffer_size(handle, rocsparse_int(nrows),
581 rocsparse_int(ncols), rocsparse_int(nnz),
582 csr_row_offset, csr_col_index,
583 rocsparse_action_numeric,
588 if constexpr (std::is_same_v<T,float>) {
589 AMREX_ROCSPARSE_SAFE_CALL(
590 rocsparse_scsr2csc(handle, rocsparse_int(nrows),
591 rocsparse_int(ncols), rocsparse_int(nnz),
592 csr.mat, csr_row_offset, csr_col_index,
593 csrt.mat, csrt_col_index, csrt_row_offset,
594 rocsparse_action_numeric,
595 rocsparse_index_base_zero,
597 }
else if constexpr (std::is_same_v<T,double>) {
598 AMREX_ROCSPARSE_SAFE_CALL(
599 rocsparse_dcsr2csc(handle, rocsparse_int(nrows),
600 rocsparse_int(ncols), rocsparse_int(nnz),
601 csr.mat, csr_row_offset, csr_col_index,
602 csrt.mat, csrt_col_index, csrt_row_offset,
603 rocsparse_action_numeric,
604 rocsparse_index_base_zero,
606 }
else if constexpr (std::is_same_v<T,GpuComplex<float>>) {
607 AMREX_ROCSPARSE_SAFE_CALL(
608 rocsparse_ccsr2csc(handle, rocsparse_int(nrows),
609 rocsparse_int(ncols), rocsparse_int(nnz),
610 (rocsparse_float_complex*)csr.mat, csr_row_offset, csr_col_index,
611 (rocsparse_float_complex*)csrt.mat, csrt_col_index, csrt_row_offset,
612 rocsparse_action_numeric,
613 rocsparse_index_base_zero,
615 }
else if constexpr (std::is_same_v<T,GpuComplex<double>>) {
616 AMREX_ROCSPARSE_SAFE_CALL(
617 rocsparse_zcsr2csc(handle, rocsparse_int(nrows),
618 rocsparse_int(ncols), rocsparse_int(nnz),
619 (rocsparse_double_complex*)csr.mat, csr_row_offset, csr_col_index,
620 (rocsparse_double_complex*)csrt.mat, csrt_col_index, csrt_row_offset,
621 rocsparse_action_numeric,
622 rocsparse_index_base_zero,
625 amrex::Abort(
"SpMatrix transpose: unsupported data type");
628 if (! std::is_same_v<rocsparse_int,Long>) {
632 csrt.col_index[i] = csrt_col_index[i];
634 if (i < csrt.nrows+1) {
635 csrt.row_offset[i] = csrt_row_offset[i];
641 AMREX_ROCSPARSE_SAFE_CALL(rocsparse_destroy_handle(handle));
643 if (! std::is_same_v<rocsparse_int,Long>) {
650#elif defined(AMREX_USE_SYCL)
652 mkl::sparse::matrix_handle_t handle_in{};
653 mkl::sparse::matrix_handle_t handle_out{};
654 mkl::sparse::init_matrix_handle(&handle_in);
655 mkl::sparse::init_matrix_handle(&handle_out);
657#if defined(INTEL_MKL_VERSION) && (INTEL_MKL_VERSION < 20250300)
659 mkl::sparse::set_csr_data(Gpu::Device::streamQueue(), handle_in, nrows, ncols,
660 mkl::index_base::zero, (
Long*)csr.row_offset,
661 (
Long*)csr.col_index, (T*)csr.mat);
662 mkl::sparse::set_csr_data(Gpu::Device::streamQueue(), handle_out, ncols, nrows,
663 mkl::index_base::zero, (
Long*)csrt.row_offset,
664 (
Long*)csrt.col_index, (T*)csrt.mat);
666 mkl::sparse::set_csr_data(Gpu::Device::streamQueue(), handle_in, nrows, ncols, nnz,
667 mkl::index_base::zero, (
Long*)csr.row_offset,
668 (
Long*)csr.col_index, (T*)csr.mat);
669 mkl::sparse::set_csr_data(Gpu::Device::streamQueue(), handle_out, ncols, nrows, nnz,
670 mkl::index_base::zero, (
Long*)csrt.row_offset,
671 (
Long*)csrt.col_index, (T*)csrt.mat);
674 mkl::sparse::omatcopy(Gpu::Device::streamQueue(), mkl::transpose::trans,
675 handle_in, handle_out);
677 mkl::sparse::release_matrix_handle(Gpu::Device::streamQueue(), &handle_in);
678 auto ev = mkl::sparse::release_matrix_handle(Gpu::Device::streamQueue(), &handle_out);
687 auto* p = csrt.row_offset;
693#pragma omp parallel for
695 for (
Long i = 0; i < nnz; ++i) {
696 auto col = csr.col_index[i];
698#pragma omp atomic update
704 Vector<Long> current_pos(ncols+1);
706 for (
Long i = 0; i < ncols; ++i) {
708 current_pos[i+1] = p[i+1];
713 for (
Long i = 0; i < nrows; ++i) {
714 for (
Long idx = csr.row_offset[i]; idx < csr.row_offset[i+1]; ++idx) {
715 auto col = csr.col_index[idx];
716 Long dest = current_pos[col]++;
717 csrt.mat[dest] = csr.mat[idx];
718 csrt.col_index[dest] = i;
726template <
typename T,
template<
typename>
class Allocator>
728 : m_partition(std::move(partition)),
729 m_row_begin(m_partition[ParallelDescriptor::MyProc()]),
730 m_row_end(m_partition[ParallelDescriptor::MyProc()+1])
735template <
typename T,
template<
typename>
class Allocator>
737 : m_partition(std::move(partition)),
738 m_row_begin(m_partition[ParallelDescriptor::MyProc()]),
739 m_row_end(m_partition[ParallelDescriptor::MyProc()+1]),
741 m_csr(std::move(csr))
744template <
typename T,
template<
typename>
class Allocator>
747 m_partition = std::move(partition);
751 define_doit(nnz_per_row);
754template <
typename T,
template<
typename>
class Allocator>
760 m_partition = std::move(partition);
764 m_csr = std::move(csr);
766 if (! is_sorted) { m_csr.sort(); }
769template <
typename T,
template<
typename>
class Allocator>
773 if (nnz_per_row <= 0) {
return; };
777 Long nlocalrows = this->numLocalRows();
778 m_nnz = nlocalrows*nnz_per_row;
779 m_csr.mat.resize(m_nnz);
780 m_csr.col_index.resize(m_nnz);
781 m_csr.row_offset.resize(nlocalrows+1);
784 auto* poffset = m_csr.row_offset.data();
787 poffset[lrow] = lrow*nnz_per_row;
791template <
typename T,
template<
typename>
class Allocator>
794 Long const* col_index,
Long nentries,
800 m_partition = std::move(partition);
809 Long nlocalrows = this->numLocalRows();
810 m_csr.mat.resize(nentries);
811 m_csr.col_index.resize(nentries);
812 m_csr.row_offset.resize(nlocalrows+1);
813 m_csr.nnz = nentries;
816 m_csr.col_index.begin());
818 m_csr.row_offset.begin());
820 if (nentries <
Long(std::numeric_limits<int>::max())) {
821 define_and_filter_doit<int>(mat, col_index, nentries, row_offset);
823 define_and_filter_doit<Long>(mat, col_index, nentries, row_offset);
838template <
typename T,
template<
typename>
class Allocator>
845template <
typename T,
template<
typename>
class Allocator>
849 Long nentries,
Long const* row_offset)
852 auto* ps = psum.
data();
853 m_nnz = Scan::PrefixSum<I>(I(nentries),
855 return col_index[i] >= 0 && mat[i] != 0; },
859 Long nlocalrows = this->numLocalRows();
860 m_csr.mat.resize(m_nnz);
861 m_csr.col_index.resize(m_nnz);
862 m_csr.row_offset.resize(nlocalrows+1);
864 auto* pmat = m_csr.mat.data();
865 auto* pcol = m_csr.col_index.data();
866 auto* prow = m_csr.row_offset.data();
867 auto actual_nnz = m_nnz;
871 if (col_index[i] >= 0 && mat[i] != 0) {
872 pmat[ps[i]] = mat[i];
873 pcol[ps[i]] = col_index[i];
876 if (i < nlocalrows) {
877 prow[i] = (row_offset[i] < nentries) ?
Long(ps[row_offset[i]]) : actual_nnz;
878 if (i == nlocalrows - 1) {
879 prow[nlocalrows] = actual_nnz;
886template <
typename T,
template<
typename>
class Allocator>
907 auto const& remote_cols = m_remote_cols_v;
914 auto const& csr = m_csr;
916 auto const& csr_r = m_csr_remote;
917 auto const& ri_ltor = m_ri_ltor;
918 auto const& remote_cols = m_remote_cols_v;
923 Long nnz = m_csr.nnz;
925 nnz += m_csr_remote.nnz;
929 ofs << m_row_begin <<
" " << m_row_end <<
" " << nnz <<
"\n";
930 for (
Long i = 0, nrows = numLocalRows(); i < nrows; ++i) {
934 for (
Long j = 0; j < nnz_row; ++j) {
935 ofs << i+m_row_begin <<
" " << col[j]+m_col_begin <<
" " << mat[j] <<
"\n";
938 if (i <
Long(ri_ltor.
size()) && ri_ltor[i] >= 0) {
939 Long ii = ri_ltor[i];
943 for (
Long j = 0; j < nnz_row; ++j) {
944 ofs << i+m_row_begin <<
" " << remote_cols[col[j]] <<
" " << mat[j] <<
"\n";
951template <
typename T,
template<
typename>
class Allocator>
960 Long nlocalrows = this->numLocalRows();
961 Long rowbegin = this->globalRowBegin();
962 auto* pmat = m_csr.mat.data();
963 auto* pcolindex = m_csr.col_index.data();
964 auto* prowoffset = m_csr.row_offset.data();
967 f(rowbegin+lrow, pcolindex+prowoffset[lrow], pmat+prowoffset[lrow]);
970 if (! is_sorted) { m_csr.sort(); }
973template <
typename T,
template<
typename>
class Allocator>
976 if (m_diagonal.empty()) {
977 m_diagonal.
define(this->partition());
982 auto offset = m_split ?
Long(0) : m_row_begin;
983 Long nrows = this->numLocalRows();
987 for (
Long j = row[i]; j < row[i+1]; ++j) {
988 if (i == col[j] -
offset) {
999template <
typename T,
template<
typename>
class Allocator>
1004 auto const& a = this->const_parcsr();
1008 for (
auto idx = a.csr0.row_offset[i];
1009 idx < a.csr0.row_offset[i+1]; ++idx) {
1010 s += a.csr0.mat[idx];
1012 if (a.csr1.nnz > 0 && a.row_map[i] >= 0) {
1013 auto ii = a.row_map[i];
1014 for (
auto idx = a.csr1.row_offset[ii];
1015 idx < a.csr1.row_offset[ii+1]; ++idx) {
1016 s += a.csr1.mat[idx];
1024template <
typename T,
template<
typename>
class Allocator>
1029 m_csr_remote.view(),
1037# ifdef AMREX_USE_GPU
1038 m_remote_cols_dv.data()
1040 m_remote_cols_v.data()
1048template <
typename T,
template<
typename>
class Allocator>
1054 m_csr_remote.const_view(),
1062# ifdef AMREX_USE_GPU
1063 m_remote_cols_dv.data()
1065 m_remote_cols_v.data()
1073template <
typename T,
template<
typename>
class Allocator>
1076 return this->const_parcsr();
1079template <
typename T,
template<
typename>
class Allocator>
1082#ifndef AMREX_USE_MPI
1085 if (detail::spmat_comm_is_local(this->partition(),
x.partition())) {
return; }
1087 this->prepare_comm_mv(
x.partition());
1093 auto const nrecvs =
int(m_comm_mv.recv_from.size());
1097 auto* p_recv = m_comm_mv.recv_buffer;
1098 for (
int irecv = 0; irecv < nrecvs; ++irecv) {
1099 BL_MPI_REQUIRE(MPI_Irecv(p_recv,
1100 m_comm_mv.recv_counts[irecv], mpi_t_type,
1101 m_comm_mv.recv_from[irecv], mpi_tag, mpi_comm,
1102 &(m_comm_mv.recv_reqs[irecv])));
1103 p_recv += m_comm_mv.recv_counts[irecv];
1105 AMREX_ASSERT(p_recv == m_comm_mv.recv_buffer + m_comm_mv.total_counts_recv);
1108 auto const nsends =
int(m_comm_mv.send_to.size());
1116 auto* p_send = m_comm_mv.send_buffer;
1117 for (
int isend = 0; isend < nsends; ++isend) {
1118 auto count = m_comm_mv.send_counts[isend];
1119 BL_MPI_REQUIRE(MPI_Isend(p_send, count, mpi_t_type, m_comm_mv.send_to[isend],
1120 mpi_tag, mpi_comm, &(m_comm_mv.send_reqs[isend])));
1123 AMREX_ASSERT(p_send == m_comm_mv.send_buffer + m_comm_mv.total_counts_send);
1128template <
typename T,
template<
typename>
class Allocator>
1131#ifndef AMREX_USE_MPI
1134 if (detail::spmat_comm_is_local(this->partition(), m_col_partition)) {
return; }
1136 if ( ! m_comm_mv.recv_reqs.empty()) {
1138 BL_MPI_REQUIRE(MPI_Waitall(
int(m_comm_mv.recv_reqs.size()),
1139 m_comm_mv.recv_reqs.data(),
1140 mpi_statuses.data()));
1143 unpack_buffer_mv(
y);
1145 if ( ! m_comm_mv.send_reqs.empty()) {
1147 BL_MPI_REQUIRE(MPI_Waitall(
int(m_comm_mv.send_reqs.size()),
1148 m_comm_mv.send_reqs.data(),
1149 mpi_statuses.data()));
1155 m_comm_mv.send_reqs.clear();
1156 m_comm_mv.recv_reqs.clear();
1160template <
typename T,
template<
typename>
class Allocator>
1164 if (detail::spmat_comm_is_local(this->partition(), col_partition)) {
return; }
1166 this->split_csr(col_partition);
1175 if (m_csr_remote.nnz > 0) {
1176 m_comm_tr.csrt.nnz = m_csr_remote.nnz;
1177 m_comm_tr.csrt.nrows = m_remote_cols_v.size();
1179 (
sizeof(T)*m_comm_tr.csrt.nnz);
1181 (
sizeof(
Long)*m_comm_tr.csrt.nnz);
1183 (
sizeof(
Long)*(m_comm_tr.csrt.nrows+1));
1186 csr_comm.
resize(m_comm_tr.csrt.nrows, m_comm_tr.csrt.nnz);
1187 auto const& csrv_comm = csr_comm.
view();
1189 auto const& csrv_comm = m_comm_tr.csrt;
1191 detail::transpose(csrv_comm, m_csr_remote.const_view());
1192 auto row_begin = m_row_begin;
1193 auto ri_rtol = m_ri_rtol.data();
1194 auto* col_index = csrv_comm.col_index;
1197 auto gjt =ri_rtol[col_index[idx]] + row_begin;
1198 col_index[idx] = gjt;
1203 csrv_comm. mat + csrv_comm.nnz,
1204 m_comm_tr.csrt.mat);
1206 csrv_comm. col_index,
1207 csrv_comm. col_index + csrv_comm.nnz,
1208 m_comm_tr.csrt.col_index);
1210 csrv_comm. row_offset,
1211 csrv_comm. row_offset + csrv_comm.nrows+1,
1212 m_comm_tr.csrt.row_offset);
1217 if (m_num_neighbors < 0) { set_num_neighbors(); }
1223 mpi_requests.reserve(nprocs);
1224 if (m_csr_remote.nnz > 0) {
1226 for (
int iproc = 0; iproc < nprocs; ++iproc) {
1228 for (
Long i = 0; i <
Long(m_remote_cols_vv[iproc].size()); ++i) {
1229 n += m_comm_tr.csrt.row_offset[it+1] - m_comm_tr.csrt.row_offset[it];
1235 std::array<int,2> nn{
int(n),
int(m_remote_cols_vv[iproc].size())};
1236 BL_MPI_REQUIRE(MPI_Isend(nn.data(), 2, MPI_INT, iproc, mpi_tag,
1237 mpi_comm, &(mpi_requests.back())));
1238 m_comm_tr.send_to.push_back(iproc);
1239 m_comm_tr.send_counts.push_back(nn);
1247 for (
int irecv = 0; irecv < m_num_neighbors; ++irecv) {
1249 BL_MPI_REQUIRE(MPI_Probe(MPI_ANY_SOURCE, mpi_tag, mpi_comm, &mpi_status));
1250 int sender = mpi_status.MPI_SOURCE;
1251 std::array<int,2> nn;
1252 BL_MPI_REQUIRE(MPI_Recv(nn.data(), 2, MPI_INT, sender, mpi_tag,
1253 mpi_comm, &mpi_status));
1254 m_comm_tr.recv_from.push_back(sender);
1255 m_comm_tr.recv_counts.push_back(nn);
1256 m_comm_tr.total_counts_recv[0] += nn[0];
1257 m_comm_tr.total_counts_recv[1] += nn[1];
1260 if (! mpi_requests.empty()) {
1262 BL_MPI_REQUIRE(MPI_Waitall(
int(mpi_requests.
size()), mpi_requests.data(),
1263 mpi_statuses.data()));
1275 auto const nrecvs =
int(m_comm_tr.recv_from.size());
1278 (
sizeof(T) * m_comm_tr.total_counts_recv[0]);
1280 (
sizeof(
Long) * m_comm_tr.total_counts_recv[0]);
1282 (
sizeof(
Long) * (m_comm_tr.total_counts_recv[1]+nrecvs));
1284 (
sizeof(
Long) * m_comm_tr.total_counts_recv[1]);
1285 m_comm_tr.recv_buffer_offset.push_back({0,0,0,0});
1287 for (
int irecv = 0; irecv < nrecvs; ++irecv) {
1288 auto [os0, os1, os2, os3] = m_comm_tr.recv_buffer_offset.back();
1289 auto [n0, n1] = m_comm_tr.recv_counts[irecv];
1290 auto recv_from_rank = m_comm_tr.recv_from[irecv];
1291 BL_MPI_REQUIRE(MPI_Irecv(m_comm_tr.recv_buffer_mat + os0,
1297 &(m_comm_tr.recv_reqs[irecv*4])));
1298 BL_MPI_REQUIRE(MPI_Irecv(m_comm_tr.recv_buffer_col_index + os1,
1304 &(m_comm_tr.recv_reqs[irecv*4+1])));
1305 BL_MPI_REQUIRE(MPI_Irecv(m_comm_tr.recv_buffer_row_offset + os2,
1311 &(m_comm_tr.recv_reqs[irecv*4+2])));
1312 BL_MPI_REQUIRE(MPI_Irecv(m_comm_tr.recv_buffer_idx_map + os3,
1318 &(m_comm_tr.recv_reqs[irecv*4+3])));
1319 m_comm_tr.recv_buffer_offset.push_back({os0 + n0,
1326 auto const nsends =
int(m_comm_tr.send_to.size());
1329 Long os0 = 0, os1 = 0;
1330 for (
int isend = 0; isend < nsends; ++isend) {
1331 auto [n0, n1] = m_comm_tr.send_counts[isend];
1332 auto send_to_rank = m_comm_tr.send_to[isend];
1333 BL_MPI_REQUIRE(MPI_Isend(m_comm_tr.csrt.mat + os0,
1339 &(m_comm_tr.send_reqs[isend*4])));
1340 BL_MPI_REQUIRE(MPI_Isend(m_comm_tr.csrt.col_index + os0,
1346 &(m_comm_tr.send_reqs[isend*4+1])));
1347 BL_MPI_REQUIRE(MPI_Isend(m_comm_tr.csrt.row_offset + os1,
1353 &(m_comm_tr.send_reqs[isend*4+2])));
1354 BL_MPI_REQUIRE(MPI_Isend(m_remote_cols_vv[send_to_rank].data(),
1360 &(m_comm_tr.send_reqs[isend*4+3])));
1370template <
typename T,
template<
typename>
class Allocator>
1374 if (detail::spmat_comm_is_local(this->partition(), AT.
partition())) {
return; }
1376 if (! m_comm_tr.recv_reqs.empty()) {
1378 BL_MPI_REQUIRE(MPI_Waitall(
int(m_comm_tr.recv_reqs.size()),
1379 m_comm_tr.recv_reqs.data(),
1380 mpi_statuses.data()));
1385 if (! m_comm_tr.send_reqs.empty()) {
1387 BL_MPI_REQUIRE(MPI_Waitall(
int(m_comm_tr.send_reqs.size()),
1388 m_comm_tr.send_reqs.data(),
1389 mpi_statuses.data()));
1392 if (m_comm_tr.csrt.nnz > 0) {
1397 if (m_comm_tr.recv_buffer_mat) {
1411template <
typename T,
template<
typename>
class Allocator>
1423 m_col_partition = col_partition;
1435 auto* p_pfsum = pfsum.
data();
1436 auto col_begin = m_col_begin;
1437 auto col_end = m_col_end;
1438 if (m_csr.nnz <
Long(std::numeric_limits<int>::max())) {
1439 auto const* pcol = m_csr.col_index.data();
1440 local_nnz = Scan::PrefixSum<int>(
int(m_nnz),
1442 return (pcol[i] >= col_begin &&
1443 pcol[i] < col_end); },
1448 auto const* pcol = m_csr.col_index.data();
1449 local_nnz = Scan::PrefixSum<Long>(m_nnz,
1451 return (pcol[i] >= col_begin &&
1452 pcol[i] < col_end); },
1458 m_csr.nnz = local_nnz;
1459 Long remote_nnz = m_nnz - local_nnz;
1460 m_csr_remote.nnz = remote_nnz;
1462 if (local_nnz != m_nnz) {
1463 m_csr_remote.mat.resize(remote_nnz);
1464 m_csr_remote.col_index.resize(remote_nnz);
1467 auto const* pmat = m_csr.mat.data();
1468 auto const* pcol = m_csr.col_index.data();
1469 auto* pmat_l = new_mat.
data();
1470 auto* pcol_l = new_col.
data();
1471 auto* pmat_r = m_csr_remote.mat.data();
1472 auto* pcol_r = m_csr_remote.col_index.data();
1475 auto ps = p_pfsum[i];
1476 auto local = (pcol[i] >= col_begin &&
1479 pmat_l[ps] = pmat[i];
1480 pcol_l[ps] = pcol[i] - col_begin;
1482 pmat_r[i-ps] = pmat[i];
1483 pcol_r[i-ps] = pcol[i];
1486 auto noffset =
Long(m_csr.row_offset.size());
1487 auto* pro = m_csr.row_offset.data();
1488 m_csr_remote.row_offset.resize(noffset);
1489 auto* pro_r = m_csr_remote.row_offset.data();
1490 auto total_nnz = m_nnz;
1493 if (i < noffset-1) {
1494 auto ro_l = (pro[i] < total_nnz) ? p_pfsum[pro[i]] : local_nnz;
1495 pro_r[i] = pro[i] - ro_l;
1499 pro_r[i] = remote_nnz;
1503 m_csr.mat.swap(new_mat);
1504 m_csr.col_index.swap(new_col);
1509 Long old_size = m_csr_remote.row_offset.size();
1510 m_ri_ltor.resize(old_size-1);
1511 m_ri_rtol.resize(old_size-1);
1512 auto* p_ltor = m_ri_ltor.data();
1513 auto* p_rtol = m_ri_rtol.data();
1515 auto const* p_ro = m_csr_remote.row_offset.data();
1516 auto* p_tro = trimmed_row_offset.
data();
1518 if (old_size <
Long(std::numeric_limits<int>::max())) {
1520 new_size = Scan::PrefixSum<int>(
int(old_size),
1522 if (i+1 < old_size) {
1523 return (p_ro[i+1] > p_ro[i]);
1531 }
else if (p_ro[i] > p_ro[i-1]) {
1534 if (i+1 < old_size) {
1535 if (p_ro[i+1] > p_ro[i]) {
1546 new_size = Scan::PrefixSum<Long>(old_size,
1548 if (i+1 < old_size) {
1549 return (p_ro[i+1] > p_ro[i]);
1557 }
else if (p_ro[i] > p_ro[i-1]) {
1560 if (i+1 < old_size) {
1561 if (p_ro[i+1] > p_ro[i]) {
1572 m_ri_rtol.resize(new_size-1);
1573 trimmed_row_offset.
resize(new_size);
1575 m_ri_rtol.shrink_to_fit();
1578 m_csr_remote.row_offset.swap(trimmed_row_offset);
1581 }
else if (col_begin > 0) {
1582 auto* pcol = m_csr.col_index.data();
1586 update_remote_col_index(m_csr_remote,
true);
1591template <
typename T,
template<
typename>
class Allocator>
1592template <
typename C>
1599 m_remote_cols_v.clear();
1600 m_remote_cols_vv.clear();
1601 m_remote_cols_vv.resize(nprocs);
1603 m_remote_cols_dv.clear();
1606 if (csrr.nnz == 0) {
return; }
1611 if (in_device_memory) {
1612 m_remote_cols_v.resize(csrr.nnz);
1614 csrr.col_index.begin(),
1615 csrr.col_index.end(),
1616 m_remote_cols_v.begin());
1621 m_remote_cols_v.assign(csrr.col_index.begin(),
1622 csrr.col_index.end());
1628 m_remote_cols_dv.resize(m_remote_cols_v.size());
1630 m_remote_cols_v.begin(),
1631 m_remote_cols_v.end(),
1632 m_remote_cols_dv.data());
1636 auto const& cp = this->m_col_partition.dataVector();
1638 m_remote_cols_v.back() < cp.back());
1639 auto it = cp.cbegin();
1640 for (
auto c : m_remote_cols_v) {
1641 it = std::find_if(it, cp.cend(), [&] (
auto x) { return x > c; });
1642 if (it != cp.cend()) {
1643 int iproc =
int(std::distance(cp.cbegin(),it)) - 1;
1644 m_remote_cols_vv[iproc].push_back(c);
1646 amrex::Abort(
"SpMatrix::update_remote_col_index: how did this happen?");
1651 std::map<Long,Long> gtol;
1652 for (
Long i = 0, N =
Long(m_remote_cols_v.size()); i < N; ++i) {
1653 gtol[m_remote_cols_v[i]] = i;
1657 if (in_device_memory) {
1660 csrr.col_index.begin(),
1661 csrr.col_index.end(),
1662 host_col_index.
begin());
1664 for (
auto& c : host_col_index) {
1668 host_col_index.
begin(),
1669 host_col_index.
end(),
1670 csrr.col_index.begin());
1675 for (
auto& c : csrr.col_index) {
1681template <
typename T,
template<
typename>
class Allocator>
1684 if (m_num_neighbors >= 0) {
return; }
1691 for (
int iproc = 0; iproc < nprocs; ++iproc) {
1692 connection[iproc] = m_remote_cols_vv[iproc].empty() ? 0 : 1;
1695 m_num_neighbors = 0;
1696 BL_MPI_REQUIRE(MPI_Reduce_scatter
1697 (connection.data(), &m_num_neighbors, reduce_scatter_counts.data(),
1698 mpi_int, MPI_SUM, mpi_comm));
1701template <
typename T,
template<
typename>
class Allocator>
1704 if (m_comm_mv.prepared) {
return; }
1708 this->split_csr(col_partition);
1715 if (m_num_neighbors < 0) { set_num_neighbors(); }
1718 mpi_requests.reserve(nprocs);
1719 for (
int iproc = 0; iproc < nprocs; ++iproc) {
1720 if ( ! m_remote_cols_vv[iproc].empty()) {
1722 auto const sz = m_remote_cols_vv[iproc].
size();
1723 if (sz >
static_cast<Long>(std::numeric_limits<int>::max())) {
1724 amrex::Abort(
"SpMatrix::prepare_comm_mv: remote column payload exceeds MPI int count range.");
1726 auto const msg_count =
static_cast<int>(sz);
1728 BL_MPI_REQUIRE(MPI_Isend(m_remote_cols_vv[iproc].data(),
1730 mpi_long, iproc, mpi_tag, mpi_comm,
1731 &(mpi_requests.back())));
1732 m_comm_mv.recv_from.push_back(iproc);
1733 m_comm_mv.recv_counts.push_back(msg_count);
1737 m_comm_mv.total_counts_recv =
Long(m_remote_cols_v.size());
1740 m_comm_mv.total_counts_send = 0;
1741 for (
int isend = 0; isend < m_num_neighbors; ++isend) {
1743 BL_MPI_REQUIRE(MPI_Probe(MPI_ANY_SOURCE, mpi_tag, mpi_comm, &mpi_status));
1744 int receiver = mpi_status.MPI_SOURCE;
1746 BL_MPI_REQUIRE(MPI_Get_count(&mpi_status, mpi_long, &count));
1747 m_comm_mv.send_to.push_back(receiver);
1748 m_comm_mv.send_counts.push_back(count);
1749 send_indices[isend].resize(count);
1750 BL_MPI_REQUIRE(MPI_Recv(send_indices[isend].data(), count, mpi_long,
1751 receiver, mpi_tag, mpi_comm, &mpi_status));
1752 m_comm_mv.total_counts_send += count;
1755 m_comm_mv.send_indices.resize(m_comm_mv.total_counts_send);
1757 send_indices_all.
reserve(m_comm_mv.total_counts_send);
1758 for (
auto const& vl : send_indices) {
1764 m_comm_mv.send_indices.begin());
1767 if (! mpi_requests.empty()) {
1769 BL_MPI_REQUIRE(MPI_Waitall(
int(mpi_requests.
size()), mpi_requests.data(),
1770 mpi_statuses.data()));
1773 m_comm_mv.prepared =
true;
1776template <
typename T,
template<
typename>
class Allocator>
1779 auto*
pdst = m_comm_mv.send_buffer;
1780 auto* pidx = m_comm_mv.send_indices.data();
1781 auto const& vv = v.
view();
1782 auto const nsends =
Long(m_comm_mv.send_indices.size());
1785 pdst[i] = vv(pidx[i]);
1789template <
typename T,
template<
typename>
class Allocator>
1792 auto const& csr = m_csr_remote;
1798 auto const* rtol = m_ri_rtol.data();
1803 auto const nrr =
Long(csr.row_offset.size())-1;
1807 for (
Long j = row[i]; j < row[i+1]; ++j) {
1808 r += mat[j] * px[col[j]];
1815template <
typename T,
template<
typename>
class Allocator>
1820 m_col_partition = col_partition;
1824 m_ri_ltor.resize(m_csr.nrows(), -1);
1828 if (nnz == 0) {
return; }
1843 auto& csrr = m_csr_remote;
1845 csrr.
mat.resize(nnz);
1852 for (
int i = 0; i < nb; ++i) {
1861 for (
int lr = 0; lr < nrow_i; ++lr) {
1862 Long const gr = idx_map[lr];
1863 while (p < nrows && ri_map[p] < gr) { ++p; }
1866 row_nnz[p] +=
int(row_offset[lr+1] - row_offset[lr]);
1871 std::partial_sum(row_nnz.begin(), row_nnz.end(), csrr.
row_offset.begin()+1);
1876 for (
int i = 0; i < nb; ++i) {
1888 for (
int lr = 0; lr < nrow_i; ++lr) {
1889 Long const gr = idx_map[lr];
1890 while (p < nrows && ri_map[p] < gr) { ++p; }
1893 auto os_src = row_offset[lr] - row_offset[0];
1894 auto nvals = row_offset[lr+1] - row_offset[lr];
1895 auto os_dst = rowpos[p];
1896 std::memcpy(csrr. mat.data()+os_dst, mat+os_src,
1898 std::memcpy(csrr.
col_index.data()+os_dst, col_index+os_src,
1899 sizeof(
Long)*nvals);
1905 m_ri_rtol.resize(nrows);
1908 auto row_begin = m_row_begin;
1912 rtol[i] -= row_begin;
1918 update_remote_col_index(csrr,
false);
#define AMREX_ASSERT(EX)
Definition AMReX_BLassert.H:38
#define AMREX_ALWAYS_ASSERT(EX)
Definition AMReX_BLassert.H:50
#define AMREX_RESTRICT
Definition AMReX_Extension.H:37
#define AMREX_CUSPARSE_SAFE_CALL(call)
Definition AMReX_GpuError.H:101
#define AMREX_GPU_ERROR_CHECK()
Definition AMReX_GpuError.H:151
#define AMREX_GPU_DEVICE
Definition AMReX_GpuQualifiers.H:18
Convenience header for the core AMReX GPU facilities.
Array4< int const > offset
Definition AMReX_HypreMLABecLap.cpp:1131
Real * pdst
Definition AMReX_HypreMLABecLap.cpp:1132
Definition AMReX_AlgPartition.H:21
Long numGlobalRows() const
Total number of rows covered by the partition.
Definition AMReX_AlgPartition.H:47
Distributed dense vector that mirrors the layout of an AlgPartition.
Definition AMReX_AlgVector.H:29
Long numLocalRows() const
Number of entries stored on this rank.
Definition AMReX_AlgVector.H:74
T const * data() const
Definition AMReX_AlgVector.H:85
void define(Long global_size)
Resize/repartition the vector to span global_size rows.
Definition AMReX_AlgVector.H:255
Table1D< T const, Long > view() const
Definition AMReX_AlgVector.H:94
virtual void free(void *pt)=0
Free a previously allocated block pointed to by pt.
virtual void * alloc(std::size_t sz)=0
Allocate sz bytes from this arena.
Dynamically allocated vector for trivially copyable data.
Definition AMReX_PODVector.H:308
void reserve(size_type a_capacity, GrowthStrategy strategy=GrowthStrategy::Poisson)
Definition AMReX_PODVector.H:819
size_type size() const noexcept
Definition AMReX_PODVector.H:654
void shrink_to_fit()
Definition AMReX_PODVector.H:826
iterator begin() noexcept
Definition AMReX_PODVector.H:680
void resize(size_type a_new_size, GrowthStrategy strategy=GrowthStrategy::Poisson)
Definition AMReX_PODVector.H:734
iterator end() noexcept
Definition AMReX_PODVector.H:684
T * data() noexcept
Definition AMReX_PODVector.H:672
void push_back(const T &a_value)
Definition AMReX_PODVector.H:633
Distributed CSR matrix that manages storage and GPU-friendly partitions.
Definition AMReX_SpMatrix.H:61
void finishComm_tr(SpMatrix< T, Allocator > &AT)
Complete transpose communication, writing the assembled matrix into AT.
Definition AMReX_SpMatrix.H:1371
void split_csr(AlgPartition const &col_partition)
Definition AMReX_SpMatrix.H:1412
Long globalRowBegin() const
Inclusive global index begin.
Definition AMReX_SpMatrix.H:196
void define_and_filter_doit(T const *mat, Long const *col_index, Long nentries, Long const *row_offset)
Private helper (exposed for CUDA) that copies/filters CSR arrays into device storage.
Definition AMReX_SpMatrix.H:848
Long * rowOffset()
Don't use this beyond initial setup.
Definition AMReX_SpMatrix.H:213
void sortCSR()
Definition AMReX_SpMatrix.H:840
void pack_buffer_mv(AlgVector< T, AllocT > const &v)
Definition AMReX_SpMatrix.H:1777
void unpack_buffer_mv(AlgVector< T, AllocT > &v)
Definition AMReX_SpMatrix.H:1790
void update_remote_col_index(C &csrr, bool in_device_memory)
Definition AMReX_SpMatrix.H:1593
void startComm_tr(AlgPartition const &col_partition)
Initiate communication required to build the transpose with column partition col_partition.
Definition AMReX_SpMatrix.H:1161
void define_doit(int nnz_per_row)
Private helper (exposed for CUDA) that allocates fixed-connectivity matrices with nnz_per_row entries...
Definition AMReX_SpMatrix.H:771
T * data()
Don't use this beyond initial setup.
Definition AMReX_SpMatrix.H:201
friend class AMG
Definition AMReX_SpMatrix.H:297
Long numGlobalRows() const
Global row count.
Definition AMReX_SpMatrix.H:191
SpMatrix & operator=(SpMatrix const &)=delete
friend SpMatrix< U, M > transpose(SpMatrix< U, M > const &A, AlgPartition col_partition)
T value_type
Definition AMReX_SpMatrix.H:63
Allocator< U > allocator_type
Definition AMReX_SpMatrix.H:64
Long globalRowEnd() const
Exclusive global index end.
Definition AMReX_SpMatrix.H:198
Long numLocalNonZeros() const
Number of nonzeros stored locally.
Definition AMReX_SpMatrix.H:193
struct amrex::SpMatrix::CommMV m_comm_mv
AlgVector< T, AllocT > rowSum() const
Sum the values in each local row and return the result as an AlgVector.
Definition AMReX_SpMatrix.H:1000
AlgPartition const & columnPartition() const
Return the column partition used for matrix-vector and matrix-matrix multiplications.
Definition AMReX_SpMatrix.H:186
void printToFile(std::string const &file) const
Definition AMReX_SpMatrix.H:888
ParCsr< T const > const_parcsr() const
Const-qualified alias of parcsr() for convenience.
Definition AMReX_SpMatrix.H:1049
SpMatrix(SpMatrix const &)=delete
ParCsr< T > parcsr()
Build GPU-friendly CSR views split into diagonal/off-diagonal blocks.
Definition AMReX_SpMatrix.H:1025
SpMatrix(SpMatrix &&)=default
Long numLocalRows() const
Number of rows owned by this rank.
Definition AMReX_SpMatrix.H:189
AlgPartition const & partition() const
Row partition describing how matrix rows are distributed across ranks.
Definition AMReX_SpMatrix.H:177
AlgVector< T, AllocT > const & diagonalVector() const
Return (and cache) the diagonal entries of a square matrix.
Definition AMReX_SpMatrix.H:974
Long * columnIndex()
Don't use this beyond initial setup.
Definition AMReX_SpMatrix.H:207
void finishComm_mv(AlgVector< T, AllocT > &y)
Finish halo exchanges and accumulate contributions into y.
Definition AMReX_SpMatrix.H:1129
Allocator< T > AllocT
Definition AMReX_SpMatrix.H:67
struct amrex::SpMatrix::CommTR m_comm_tr
void prepare_comm_mv(AlgPartition const &col_partition)
Definition AMReX_SpMatrix.H:1702
void startComm_mv(AlgVector< T, AllocT > const &x)
Prepare halo exchanges for a subsequent SpMV using x as the source vector.
Definition AMReX_SpMatrix.H:1080
void unpack_buffer_tr(CommTR const &ctr, AlgPartition const &col_partition)
Definition AMReX_SpMatrix.H:1816
friend void SpMV(AlgVector< U, N > &y, SpMatrix< U, M > const &A, AlgVector< U, N > const &x)
void setVal(F const &f, CsrSorted is_sorted)
Initialize matrix entries using a row-wise functor.
Definition AMReX_SpMatrix.H:953
void define(AlgPartition partition, int nnz_per_row)
Allocate storage for a default-constructed matrix with a fixed number of nonzeros per row.
Definition AMReX_SpMatrix.H:745
This class is a thin wrapper around std::vector. Unlike vector, Vector::operator[] provides bound che...
Definition AMReX_Vector.H:29
Long size() const noexcept
Definition AMReX_Vector.H:54
amrex_long Long
Definition AMReX_INT.H:30
void ParallelForOMP(T n, L const &f) noexcept
Performance-portable kernel launch function with optional OpenMP threading.
Definition AMReX_GpuLaunch.H:328
Arena * The_Comms_Arena()
Definition AMReX_Arena.cpp:875
Arena * The_Pinned_Arena()
Definition AMReX_Arena.cpp:855
Arena * The_Arena()
Definition AMReX_Arena.cpp:815
int MyProc() noexcept
Definition AMReX_ParallelDescriptor.H:128
int NProcs() noexcept
Definition AMReX_ParallelDescriptor.H:255
void copyAsync(HostToDevice, InIter begin, InIter end, OutIter result) noexcept
A host-to-device copy routine. Note this is just a wrapper around memcpy, so it assumes contiguous st...
Definition AMReX_GpuContainers.H:228
static constexpr DeviceToDevice deviceToDevice
Definition AMReX_GpuContainers.H:107
static constexpr DeviceToHost deviceToHost
Definition AMReX_GpuContainers.H:106
static constexpr HostToDevice hostToDevice
Definition AMReX_GpuContainers.H:105
void streamSynchronize() noexcept
Definition AMReX_GpuDevice.H:310
gpuStream_t gpuStream() noexcept
Definition AMReX_GpuDevice.H:291
MPI_Comm CommunicatorSub() noexcept
sub-communicator for current frame
Definition AMReX_ParallelContext.H:70
int NProcsSub() noexcept
number of ranks in current frame
Definition AMReX_ParallelContext.H:74
int SeqNum() noexcept
Returns sequential message sequence numbers, usually used as tags for send/recv.
Definition AMReX_ParallelDescriptor.H:678
static constexpr struct amrex::Scan::Type::Exclusive exclusive
static constexpr RetSum retSum
Definition AMReX_Scan.H:34
static constexpr int MPI_REQUEST_NULL
Definition AMReX_ccse-mpi.H:57
Definition AMReX_Amr.cpp:50
__host__ __device__ void ignore_unused(const Ts &...)
No-op helper that marks variables as intentionally unused.
Definition AMReX.H:259
amrex::ArenaAllocator< T > DefaultAllocator
Definition AMReX_GpuAllocators.H:205
void ParallelFor(TypeList< CTOs... > ctos, std::array< int, sizeof...(CTOs)> const &runtime_options, T N, F &&f)
Definition AMReX_CTOParallelForImpl.H:202
void duplicateCSR(C c, CSR< T, AD > &dst, CSR< T, AS > const &src)
Definition AMReX_CSR.H:120
void Abort(const std::string &msg)
Print a fatal-error message to stderr and abort execution.
Definition AMReX.cpp:242
const int[]
Definition AMReX_BLProfiler.cpp:1665
void RemoveDuplicates(Vector< T > &vec)
Definition AMReX_Vector.H:210
V< Long > row_offset
Definition AMReX_CSR.H:53
Long nnz
Definition AMReX_CSR.H:54
CsrView< T > view()
Mutable view of the underlying buffers.
Definition AMReX_CSR.H:78
void resize(Long num_rows, Long num_non_zeros)
Resize the storage to accommodate num_rows and num_non_zeros entries.
Definition AMReX_CSR.H:70
V< Long > col_index
Definition AMReX_CSR.H:52
V< T > mat
Definition AMReX_CSR.H:51
Sorted CSR means for each row the column indices are sorted.
Definition AMReX_SpMatrix.H:45
bool b
Definition AMReX_SpMatrix.H:46
Valid CSR means all entries are valid. It may be sorted ro unsorted.
Definition AMReX_SpMatrix.H:51
bool b
Definition AMReX_SpMatrix.H:52
Lightweight non-owning CSR view that can point to host or device buffers.
Definition AMReX_CSR.H:34
GPU-ready non-owning CSR data container.
Definition AMReX_SpMatrix.H:35
Long const *__restrict__ col_map
Definition AMReX_SpMatrix.H:41
Long const *__restrict__ row_map
Definition AMReX_SpMatrix.H:40
CsrView< T > csr1
Definition AMReX_SpMatrix.H:37
Long col_begin
Definition AMReX_SpMatrix.H:39
Long row_begin
Definition AMReX_SpMatrix.H:38
CsrView< T > csr0
Definition AMReX_SpMatrix.H:36
static MPI_Datatype type()
Definition AMReX_SpMatrix.H:381
T * send_buffer
Definition AMReX_SpMatrix.H:390
bool prepared
Definition AMReX_SpMatrix.H:397
Vector< int > recv_counts
Definition AMReX_SpMatrix.H:387
Long total_counts_recv
Definition AMReX_SpMatrix.H:395
Vector< int > recv_from
Definition AMReX_SpMatrix.H:386
T * recv_buffer
Definition AMReX_SpMatrix.H:394
Vector< int > send_counts
Definition AMReX_SpMatrix.H:383
Long total_counts_send
Definition AMReX_SpMatrix.H:391
Gpu::DeviceVector< Long > send_indices
Definition AMReX_SpMatrix.H:384
Vector< MPI_Request > recv_reqs
Definition AMReX_SpMatrix.H:393
Vector< int > send_to
Definition AMReX_SpMatrix.H:382
Vector< MPI_Request > send_reqs
Definition AMReX_SpMatrix.H:389
Definition AMReX_SpMatrix.H:400
Vector< std::array< int, 2 > > send_counts
Definition AMReX_SpMatrix.H:404
Long * recv_buffer_col_index
Definition AMReX_SpMatrix.H:417
Vector< MPI_Request > send_reqs
Definition AMReX_SpMatrix.H:405
Vector< MPI_Request > recv_reqs
Definition AMReX_SpMatrix.H:409
Vector< int > send_to
Definition AMReX_SpMatrix.H:403
std::array< Long, 2 > total_counts_recv
Definition AMReX_SpMatrix.H:411
Long * recv_buffer_row_offset
Definition AMReX_SpMatrix.H:418
Vector< std::array< int, 2 > > recv_counts
Definition AMReX_SpMatrix.H:408
CsrView< T > csrt
Definition AMReX_SpMatrix.H:401
T * recv_buffer_mat
Definition AMReX_SpMatrix.H:416
Vector< std::array< Long, 4 > > recv_buffer_offset
Definition AMReX_SpMatrix.H:412
Vector< int > recv_from
Definition AMReX_SpMatrix.H:407
Long * recv_buffer_idx_map
Definition AMReX_SpMatrix.H:419
Definition AMReX_ccse-mpi.H:55