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>
24#include <unordered_map>
49 explicit operator bool()
const {
return b; }
55 explicit operator bool()
const {
return b; }
205 return m_csr.
mat.data();
261 template <
typename F>
294 template <
typename U,
template<
typename>
class M,
typename N>
friend
297 template <
typename U,
template<
typename>
class M>
friend
300 template <
typename U,
template<
typename>
class M>
friend
304 template <
typename U>
friend class AMG;
318 template <
typename I>
320 Long nentries,
Long const* row_offset);
338 void set_num_neighbors ();
342 Long m_row_begin = 0;
344 Long m_col_begin = 0;
351 bool m_split =
false;
398 int m_num_neighbors = -1;
445 template <
typename C>
471 col_index(std::exchange(rhs.col_index,
nullptr)),
472 mat(std::exchange(rhs.mat,
nullptr)),
478 col_index = std::exchange(rhs.col_index,
nullptr);
479 mat = std::exchange(rhs.mat,
nullptr);
511inline bool spmat_comm_is_local (AlgPartition
const& row_partition,
512 AlgPartition
const& col_partition)
514 int const rp = row_partition.singleActiveProc();
515 int const cp = col_partition.singleActiveProc();
516 return row_partition.numActiveProcs() <= 1
517 && col_partition.numActiveProcs() <= 1
518 && (rp < 0 || cp < 0 || rp == cp);
522void transpose (CsrView<T>
const& csrt, CsrView<T const>
const& csr)
524 Long nrows = csr.nrows;
525 Long ncols = csrt.nrows;
528 if (nrows <= 0 || ncols <= 0 || nnz <= 0) {
529 auto* p = csrt.row_offset;
536#if defined(AMREX_USE_CUDA)
538 cusparseHandle_t handle;
542 cudaDataType data_type;
543 if constexpr (std::is_same_v<T,float>) {
544 data_type = CUDA_R_32F;
545 }
else if constexpr (std::is_same_v<T,double>) {
546 data_type = CUDA_R_64F;
547 }
else if constexpr (std::is_same_v<T,GpuComplex<float>>) {
548 data_type = CUDA_C_32F;
549 }
else if constexpr (std::is_same_v<T,GpuComplex<double>>) {
550 data_type = CUDA_C_64F;
552 amrex::Abort(
"SpMatrix transpose: unsupported data type");
557 CsrIndex<int,Gpu::DeviceVector> ci, cit;
559 cit.col_index.resize(csrt.nnz);
560 cit.row_offset.resize(csrt.nrows+1);
561 auto const* csr_col_index = ci.col_index.data();
562 auto const* csr_row_offset = ci.row_offset.data();
563 auto* csrt_col_index = cit.col_index.data();
564 auto* csrt_row_offset = cit.row_offset.data();
566 std::size_t buffer_size;
568 cusparseCsr2cscEx2_bufferSize(handle,
int(nrows),
int(ncols),
int(nnz),
569 csr.mat, csr_row_offset, csr_col_index,
570 csrt.mat, csrt_row_offset, csrt_col_index,
571 data_type, CUSPARSE_ACTION_NUMERIC,
572 CUSPARSE_INDEX_BASE_ZERO,
573 CUSPARSE_CSR2CSC_ALG1,
579 cusparseCsr2cscEx2(handle,
int(nrows),
int(ncols),
int(nnz),
580 csr.mat, csr_row_offset, csr_col_index,
581 csrt.mat, csrt_row_offset, csrt_col_index,
582 data_type, CUSPARSE_ACTION_NUMERIC,
583 CUSPARSE_INDEX_BASE_ZERO,
584 CUSPARSE_CSR2CSC_ALG1,
593#elif defined(AMREX_USE_HIP)
595 rocsparse_handle handle;
596 AMREX_ROCSPARSE_SAFE_CALL(rocsparse_create_handle(&handle));
597 AMREX_ROCSPARSE_SAFE_CALL(rocsparse_set_stream(handle,
Gpu::gpuStream()));
599 constexpr bool same_int = (
sizeof(rocsparse_int) ==
sizeof(
Long));
601 rocsparse_int
const* csr_col_index;
602 rocsparse_int
const* csr_row_offset;
603 rocsparse_int* csrt_col_index;
604 rocsparse_int* csrt_row_offset;
605 CsrIndex<rocsparse_int,Gpu::DeviceVector> ci, cit;
606 if constexpr (same_int) {
607 csr_col_index =
reinterpret_cast<rocsparse_int const*
>(csr.col_index);
608 csr_row_offset =
reinterpret_cast<rocsparse_int const*
>(csr.row_offset);
609 csrt_col_index =
reinterpret_cast<rocsparse_int*
>(csrt.col_index);
610 csrt_row_offset =
reinterpret_cast<rocsparse_int*
>(csrt.row_offset);
614 cit.col_index.resize(csrt.nnz);
615 cit.row_offset.resize(csrt.nrows+1);
616 csr_col_index = ci.col_index.data();
617 csr_row_offset = ci.row_offset.data();
618 csrt_col_index = cit.col_index.data();
619 csrt_row_offset = cit.row_offset.data();
622 std::size_t buffer_size;
623 AMREX_ROCSPARSE_SAFE_CALL(
624 rocsparse_csr2csc_buffer_size(handle, rocsparse_int(nrows),
625 rocsparse_int(ncols), rocsparse_int(nnz),
626 csr_row_offset, csr_col_index,
627 rocsparse_action_numeric,
632 if constexpr (std::is_same_v<T,float>) {
633 AMREX_ROCSPARSE_SAFE_CALL(
634 rocsparse_scsr2csc(handle, rocsparse_int(nrows),
635 rocsparse_int(ncols), rocsparse_int(nnz),
636 csr.mat, csr_row_offset, csr_col_index,
637 csrt.mat, csrt_col_index, csrt_row_offset,
638 rocsparse_action_numeric,
639 rocsparse_index_base_zero,
641 }
else if constexpr (std::is_same_v<T,double>) {
642 AMREX_ROCSPARSE_SAFE_CALL(
643 rocsparse_dcsr2csc(handle, rocsparse_int(nrows),
644 rocsparse_int(ncols), rocsparse_int(nnz),
645 csr.mat, csr_row_offset, csr_col_index,
646 csrt.mat, csrt_col_index, csrt_row_offset,
647 rocsparse_action_numeric,
648 rocsparse_index_base_zero,
650 }
else if constexpr (std::is_same_v<T,GpuComplex<float>>) {
651 AMREX_ROCSPARSE_SAFE_CALL(
652 rocsparse_ccsr2csc(handle, rocsparse_int(nrows),
653 rocsparse_int(ncols), rocsparse_int(nnz),
654 (rocsparse_float_complex*)csr.mat, csr_row_offset, csr_col_index,
655 (rocsparse_float_complex*)csrt.mat, csrt_col_index, csrt_row_offset,
656 rocsparse_action_numeric,
657 rocsparse_index_base_zero,
659 }
else if constexpr (std::is_same_v<T,GpuComplex<double>>) {
660 AMREX_ROCSPARSE_SAFE_CALL(
661 rocsparse_zcsr2csc(handle, rocsparse_int(nrows),
662 rocsparse_int(ncols), rocsparse_int(nnz),
663 (rocsparse_double_complex*)csr.mat, csr_row_offset, csr_col_index,
664 (rocsparse_double_complex*)csrt.mat, csrt_col_index, csrt_row_offset,
665 rocsparse_action_numeric,
666 rocsparse_index_base_zero,
669 amrex::Abort(
"SpMatrix transpose: unsupported data type");
672 if constexpr (!same_int) {
677 AMREX_ROCSPARSE_SAFE_CALL(rocsparse_destroy_handle(handle));
680#elif defined(AMREX_USE_SYCL)
682 mkl::sparse::matrix_handle_t handle_in{};
683 mkl::sparse::matrix_handle_t handle_out{};
684 mkl::sparse::init_matrix_handle(&handle_in);
685 mkl::sparse::init_matrix_handle(&handle_out);
687#if defined(INTEL_MKL_VERSION) && (INTEL_MKL_VERSION < 20250300)
689 mkl::sparse::set_csr_data(Gpu::Device::streamQueue(), handle_in, nrows, ncols,
690 mkl::index_base::zero, (
Long*)csr.row_offset,
691 (
Long*)csr.col_index, (T*)csr.mat);
692 mkl::sparse::set_csr_data(Gpu::Device::streamQueue(), handle_out, ncols, nrows,
693 mkl::index_base::zero, (
Long*)csrt.row_offset,
694 (
Long*)csrt.col_index, (T*)csrt.mat);
696 mkl::sparse::set_csr_data(Gpu::Device::streamQueue(), handle_in, nrows, ncols, nnz,
697 mkl::index_base::zero, (
Long*)csr.row_offset,
698 (
Long*)csr.col_index, (T*)csr.mat);
699 mkl::sparse::set_csr_data(Gpu::Device::streamQueue(), handle_out, ncols, nrows, nnz,
700 mkl::index_base::zero, (
Long*)csrt.row_offset,
701 (
Long*)csrt.col_index, (T*)csrt.mat);
704 mkl::sparse::omatcopy(Gpu::Device::streamQueue(), mkl::transpose::trans,
705 handle_in, handle_out);
707 mkl::sparse::release_matrix_handle(Gpu::Device::streamQueue(), &handle_in);
708 auto ev = mkl::sparse::release_matrix_handle(Gpu::Device::streamQueue(), &handle_out);
717 auto* p = csrt.row_offset;
723#pragma omp parallel for
725 for (
Long i = 0; i < nnz; ++i) {
726 auto col = csr.col_index[i];
728#pragma omp atomic update
734 Vector<Long> current_pos(ncols+1);
736 for (
Long i = 0; i < ncols; ++i) {
738 current_pos[i+1] = p[i+1];
743 for (
Long i = 0; i < nrows; ++i) {
744 for (
Long idx = csr.row_offset[i]; idx < csr.row_offset[i+1]; ++idx) {
745 auto col = csr.col_index[idx];
746 Long dest = current_pos[col]++;
747 csrt.mat[dest] = csr.mat[idx];
748 csrt.col_index[dest] = i;
756template <
typename T,
template<
typename>
class Allocator>
758 : m_partition(std::move(partition)),
759 m_row_begin(m_partition[ParallelDescriptor::MyProc()]),
760 m_row_end(m_partition[ParallelDescriptor::MyProc()+1])
765template <
typename T,
template<
typename>
class Allocator>
767 : m_partition(std::move(partition)),
768 m_row_begin(m_partition[ParallelDescriptor::MyProc()]),
769 m_row_end(m_partition[ParallelDescriptor::MyProc()+1]),
771 m_csr(std::move(csr))
774template <
typename T,
template<
typename>
class Allocator>
777 m_partition = std::move(partition);
781 define_doit(nnz_per_row);
784template <
typename T,
template<
typename>
class Allocator>
790 m_partition = std::move(partition);
794 m_csr = std::move(csr);
796 if (! is_sorted) { m_csr.
sort(); }
799template <
typename T,
template<
typename>
class Allocator>
805 nnz_per_row = std::max(nnz_per_row, 0);
806 Long nlocalrows = this->numLocalRows();
807 m_nnz = nlocalrows*nnz_per_row;
808 m_csr.
mat.resize(m_nnz);
816 poffset[lrow] = lrow*nnz_per_row;
820template <
typename T,
template<
typename>
class Allocator>
823 Long const* col_index,
Long nentries,
829 m_partition = std::move(partition);
838 Long nlocalrows = this->numLocalRows();
839 m_csr.
mat.resize(nentries);
842 m_csr.
nnz = nentries;
849 if (nentries <
Long(std::numeric_limits<int>::max())) {
850 define_and_filter_doit<int>(mat, col_index, nentries, row_offset);
852 define_and_filter_doit<Long>(mat, col_index, nentries, row_offset);
867template <
typename T,
template<
typename>
class Allocator>
874template <
typename T,
template<
typename>
class Allocator>
879 split_csr(col_partition);
883 m_col_partition = col_partition;
887template <
typename T,
template<
typename>
class Allocator>
891 Long nentries,
Long const* row_offset)
894 auto* ps = psum.
data();
895 m_nnz = Scan::PrefixSum<I>(I(nentries),
897 return col_index[i] >= 0 && mat[i] != 0; },
901 Long nlocalrows = this->numLocalRows();
902 m_csr.
mat.resize(m_nnz);
906 auto* pmat = m_csr.
mat.data();
909 auto actual_nnz = m_nnz;
913 if (col_index[i] >= 0 && mat[i] != 0) {
914 pmat[ps[i]] = mat[i];
915 pcol[ps[i]] = col_index[i];
918 if (i <= nlocalrows) {
919 prow[i] = (i < nlocalrows && row_offset[i] < nentries)
920 ?
Long(ps[row_offset[i]]) : actual_nnz;
926template <
typename T,
template<
typename>
class Allocator>
947 auto const& remote_cols = m_remote_cols_v;
954 auto const& csr = m_csr;
956 auto const& csr_r = m_csr_remote;
957 auto const& ri_ltor = m_ri_ltor;
958 auto const& remote_cols = m_remote_cols_v;
965 nnz += m_csr_remote.
nnz;
969 ofs << m_row_begin <<
" " << m_row_end <<
" " << nnz <<
"\n";
970 for (
Long i = 0, nrows = numLocalRows(); i < nrows; ++i) {
974 for (
Long j = 0; j < nnz_row; ++j) {
975 ofs << i+m_row_begin <<
" " << col[j]+m_col_begin <<
" " << mat[j] <<
"\n";
978 if (i <
Long(ri_ltor.
size()) && ri_ltor[i] >= 0) {
979 Long ii = ri_ltor[i];
983 for (
Long j = 0; j < nnz_row; ++j) {
984 ofs << i+m_row_begin <<
" " << remote_cols[col[j]] <<
" " << mat[j] <<
"\n";
991template <
typename T,
template<
typename>
class Allocator>
1000 Long nlocalrows = this->numLocalRows();
1001 Long rowbegin = this->globalRowBegin();
1002 auto* pmat = m_csr.
mat.data();
1003 auto* pcolindex = m_csr.
col_index.data();
1007 f(rowbegin+lrow, pcolindex+prowoffset[lrow], pmat+prowoffset[lrow]);
1010 if (! is_sorted) { m_csr.
sort(); }
1013template <
typename T,
template<
typename>
class Allocator>
1016 if (m_diagonal.
empty()) {
1017 m_diagonal.
define(this->partition());
1022 auto offset = m_split ?
Long(0) : m_row_begin;
1023 Long nrows = this->numLocalRows();
1027 for (
Long j = row[i]; j < row[i+1]; ++j) {
1028 if (i == col[j] -
offset) {
1039template <
typename T,
template<
typename>
class Allocator>
1044 auto const& a = this->const_parcsr();
1048 for (
auto idx = a.csr0.row_offset[i];
1049 idx < a.csr0.row_offset[i+1]; ++idx) {
1050 s += a.csr0.mat[idx];
1052 if (a.csr1.nnz > 0 && a.row_map[i] >= 0) {
1053 auto ii = a.row_map[i];
1054 for (
auto idx = a.csr1.row_offset[ii];
1055 idx < a.csr1.row_offset[ii+1]; ++idx) {
1056 s += a.csr1.mat[idx];
1064template <
typename T,
template<
typename>
class Allocator>
1069 m_csr_remote.
view(),
1077# ifdef AMREX_USE_GPU
1078 m_remote_cols_dv.
data()
1080 m_remote_cols_v.data()
1088template <
typename T,
template<
typename>
class Allocator>
1102# ifdef AMREX_USE_GPU
1103 m_remote_cols_dv.
data()
1105 m_remote_cols_v.data()
1113template <
typename T,
template<
typename>
class Allocator>
1116 return this->const_parcsr();
1119template <
typename T,
template<
typename>
class Allocator>
1122#ifndef AMREX_USE_MPI
1125 if (detail::spmat_comm_is_local(this->partition(),
x.partition())) {
return; }
1127 this->prepare_comm_mv(
x.partition());
1133 auto const nrecvs =
int(m_comm_mv.recv_from.size());
1137 auto* p_recv = m_comm_mv.recv_buffer;
1138 for (
int irecv = 0; irecv < nrecvs; ++irecv) {
1139 BL_MPI_REQUIRE(MPI_Irecv(p_recv,
1140 m_comm_mv.recv_counts[irecv], mpi_t_type,
1141 m_comm_mv.recv_from[irecv], mpi_tag, mpi_comm,
1142 &(m_comm_mv.recv_reqs[irecv])));
1143 p_recv += m_comm_mv.recv_counts[irecv];
1145 AMREX_ASSERT(p_recv == m_comm_mv.recv_buffer + m_comm_mv.total_counts_recv);
1148 auto const nsends =
int(m_comm_mv.send_to.size());
1156 auto* p_send = m_comm_mv.send_buffer;
1157 for (
int isend = 0; isend < nsends; ++isend) {
1158 auto count = m_comm_mv.send_counts[isend];
1159 BL_MPI_REQUIRE(MPI_Isend(p_send, count, mpi_t_type, m_comm_mv.send_to[isend],
1160 mpi_tag, mpi_comm, &(m_comm_mv.send_reqs[isend])));
1163 AMREX_ASSERT(p_send == m_comm_mv.send_buffer + m_comm_mv.total_counts_send);
1168template <
typename T,
template<
typename>
class Allocator>
1171#ifndef AMREX_USE_MPI
1174 if (detail::spmat_comm_is_local(this->partition(), m_col_partition)) {
return; }
1176 if ( ! m_comm_mv.recv_reqs.empty()) {
1178 BL_MPI_REQUIRE(MPI_Waitall(
int(m_comm_mv.recv_reqs.size()),
1179 m_comm_mv.recv_reqs.data(),
1180 mpi_statuses.data()));
1183 unpack_buffer_mv(
y);
1185 if ( ! m_comm_mv.send_reqs.empty()) {
1187 BL_MPI_REQUIRE(MPI_Waitall(
int(m_comm_mv.send_reqs.size()),
1188 m_comm_mv.send_reqs.data(),
1189 mpi_statuses.data()));
1195 m_comm_mv.send_reqs.clear();
1196 m_comm_mv.recv_reqs.clear();
1200template <
typename T,
template<
typename>
class Allocator>
1204 if (detail::spmat_comm_is_local(this->partition(), col_partition)) {
return; }
1206 this->split_csr(col_partition);
1215 if (m_csr_remote.
nnz > 0) {
1216 m_comm_tr.csrt.nnz = m_csr_remote.
nnz;
1217 m_comm_tr.csrt.nrows = m_remote_cols_v.
size();
1219 (
sizeof(T)*m_comm_tr.csrt.nnz);
1221 (
sizeof(
Long)*m_comm_tr.csrt.nnz);
1223 (
sizeof(
Long)*(m_comm_tr.csrt.nrows+1));
1226 csr_comm.
resize(m_comm_tr.csrt.nrows, m_comm_tr.csrt.nnz);
1227 auto const& csrv_comm = csr_comm.
view();
1229 auto const& csrv_comm = m_comm_tr.csrt;
1231 detail::transpose(csrv_comm, m_csr_remote.
const_view());
1232 auto row_begin = m_row_begin;
1233 auto ri_rtol = m_ri_rtol.
data();
1234 auto* col_index = csrv_comm.col_index;
1237 auto gjt =ri_rtol[col_index[idx]] + row_begin;
1238 col_index[idx] = gjt;
1243 csrv_comm. mat + csrv_comm.nnz,
1244 m_comm_tr.csrt.mat);
1246 csrv_comm. col_index,
1247 csrv_comm. col_index + csrv_comm.nnz,
1248 m_comm_tr.csrt.col_index);
1250 csrv_comm. row_offset,
1251 csrv_comm. row_offset + csrv_comm.nrows+1,
1252 m_comm_tr.csrt.row_offset);
1257 if (m_num_neighbors < 0) { set_num_neighbors(); }
1263 mpi_requests.reserve(nprocs);
1264 if (m_csr_remote.
nnz > 0) {
1266 for (
int iproc = 0; iproc < nprocs; ++iproc) {
1268 for (
Long i = 0; i <
Long(m_remote_cols_vv[iproc].size()); ++i) {
1269 n += m_comm_tr.csrt.row_offset[it+1] - m_comm_tr.csrt.row_offset[it];
1275 std::array<int,2> nn{
int(n),
int(m_remote_cols_vv[iproc].size())};
1276 BL_MPI_REQUIRE(MPI_Isend(nn.data(), 2, MPI_INT, iproc, mpi_tag,
1277 mpi_comm, &(mpi_requests.back())));
1278 m_comm_tr.send_to.push_back(iproc);
1279 m_comm_tr.send_counts.push_back(nn);
1287 for (
int irecv = 0; irecv < m_num_neighbors; ++irecv) {
1289 BL_MPI_REQUIRE(MPI_Probe(MPI_ANY_SOURCE, mpi_tag, mpi_comm, &mpi_status));
1290 int sender = mpi_status.MPI_SOURCE;
1291 std::array<int,2> nn;
1292 BL_MPI_REQUIRE(MPI_Recv(nn.data(), 2, MPI_INT, sender, mpi_tag,
1293 mpi_comm, &mpi_status));
1294 m_comm_tr.recv_from.push_back(sender);
1295 m_comm_tr.recv_counts.push_back(nn);
1296 m_comm_tr.total_counts_recv[0] += nn[0];
1297 m_comm_tr.total_counts_recv[1] += nn[1];
1300 if (! mpi_requests.empty()) {
1302 BL_MPI_REQUIRE(MPI_Waitall(
int(mpi_requests.
size()), mpi_requests.data(),
1303 mpi_statuses.data()));
1315 auto const nrecvs =
int(m_comm_tr.recv_from.size());
1318 (
sizeof(T) * m_comm_tr.total_counts_recv[0]);
1320 (
sizeof(
Long) * m_comm_tr.total_counts_recv[0]);
1322 (
sizeof(
Long) * (m_comm_tr.total_counts_recv[1]+nrecvs));
1324 (
sizeof(
Long) * m_comm_tr.total_counts_recv[1]);
1325 m_comm_tr.recv_buffer_offset.push_back({0,0,0,0});
1327 for (
int irecv = 0; irecv < nrecvs; ++irecv) {
1328 auto [os0, os1, os2, os3] = m_comm_tr.recv_buffer_offset.back();
1329 auto [n0, n1] = m_comm_tr.recv_counts[irecv];
1330 auto recv_from_rank = m_comm_tr.recv_from[irecv];
1331 BL_MPI_REQUIRE(MPI_Irecv(m_comm_tr.recv_buffer_mat + os0,
1337 &(m_comm_tr.recv_reqs[irecv*4])));
1338 BL_MPI_REQUIRE(MPI_Irecv(m_comm_tr.recv_buffer_col_index + os1,
1344 &(m_comm_tr.recv_reqs[irecv*4+1])));
1345 BL_MPI_REQUIRE(MPI_Irecv(m_comm_tr.recv_buffer_row_offset + os2,
1351 &(m_comm_tr.recv_reqs[irecv*4+2])));
1352 BL_MPI_REQUIRE(MPI_Irecv(m_comm_tr.recv_buffer_idx_map + os3,
1358 &(m_comm_tr.recv_reqs[irecv*4+3])));
1359 m_comm_tr.recv_buffer_offset.push_back({os0 + n0,
1366 auto const nsends =
int(m_comm_tr.send_to.size());
1369 Long os0 = 0, os1 = 0;
1370 for (
int isend = 0; isend < nsends; ++isend) {
1371 auto [n0, n1] = m_comm_tr.send_counts[isend];
1372 auto send_to_rank = m_comm_tr.send_to[isend];
1373 BL_MPI_REQUIRE(MPI_Isend(m_comm_tr.csrt.mat + os0,
1379 &(m_comm_tr.send_reqs[isend*4])));
1380 BL_MPI_REQUIRE(MPI_Isend(m_comm_tr.csrt.col_index + os0,
1386 &(m_comm_tr.send_reqs[isend*4+1])));
1387 BL_MPI_REQUIRE(MPI_Isend(m_comm_tr.csrt.row_offset + os1,
1393 &(m_comm_tr.send_reqs[isend*4+2])));
1394 BL_MPI_REQUIRE(MPI_Isend(m_remote_cols_vv[send_to_rank].data(),
1400 &(m_comm_tr.send_reqs[isend*4+3])));
1410template <
typename T,
template<
typename>
class Allocator>
1414 if (detail::spmat_comm_is_local(this->partition(), AT.
partition())) {
return; }
1416 this->comm_tr_recv_wait();
1420 this->comm_tr_clear();
1428template <
typename T,
template<
typename>
class Allocator>
1431 if (! m_comm_tr.recv_reqs.empty()) {
1433 BL_MPI_REQUIRE(MPI_Waitall(
int(m_comm_tr.recv_reqs.size()),
1434 m_comm_tr.recv_reqs.data(),
1435 mpi_statuses.data()));
1439template <
typename T,
template<
typename>
class Allocator>
1442 if (! m_comm_tr.send_reqs.empty()) {
1444 BL_MPI_REQUIRE(MPI_Waitall(
int(m_comm_tr.send_reqs.size()),
1445 m_comm_tr.send_reqs.data(),
1446 mpi_statuses.data()));
1449 if (m_comm_tr.csrt.nnz > 0) {
1454 if (m_comm_tr.recv_buffer_mat) {
1467template <
typename T,
template<
typename>
class Allocator>
1479 m_col_partition = col_partition;
1491 auto* p_pfsum = pfsum.
data();
1492 auto col_begin = m_col_begin;
1493 auto col_end = m_col_end;
1494 if (m_csr.
nnz <
Long(std::numeric_limits<int>::max())) {
1495 auto const* pcol = m_csr.
col_index.data();
1496 local_nnz = Scan::PrefixSum<int>(
int(m_nnz),
1498 return (pcol[i] >= col_begin &&
1499 pcol[i] < col_end); },
1504 auto const* pcol = m_csr.
col_index.data();
1505 local_nnz = Scan::PrefixSum<Long>(m_nnz,
1507 return (pcol[i] >= col_begin &&
1508 pcol[i] < col_end); },
1514 m_csr.
nnz = local_nnz;
1515 Long remote_nnz = m_nnz - local_nnz;
1516 m_csr_remote.
nnz = remote_nnz;
1518 if (local_nnz != m_nnz) {
1519 m_csr_remote.
mat.resize(remote_nnz);
1520 m_csr_remote.
col_index.resize(remote_nnz);
1523 auto const* pmat = m_csr.
mat.data();
1524 auto const* pcol = m_csr.
col_index.data();
1525 auto* pmat_l = new_mat.
data();
1526 auto* pcol_l = new_col.
data();
1527 auto* pmat_r = m_csr_remote.
mat.data();
1528 auto* pcol_r = m_csr_remote.
col_index.data();
1531 auto ps = p_pfsum[i];
1532 auto local = (pcol[i] >= col_begin &&
1535 pmat_l[ps] = pmat[i];
1536 pcol_l[ps] = pcol[i] - col_begin;
1538 pmat_r[i-ps] = pmat[i];
1539 pcol_r[i-ps] = pcol[i];
1545 auto* pro_r = m_csr_remote.
row_offset.data();
1546 auto total_nnz = m_nnz;
1549 if (i < noffset-1) {
1550 auto ro_l = (pro[i] < total_nnz) ? p_pfsum[pro[i]] : local_nnz;
1551 pro_r[i] = pro[i] - ro_l;
1555 pro_r[i] = remote_nnz;
1559 m_csr.
mat.swap(new_mat);
1567 m_ri_ltor.
resize(old_size-1);
1568 m_ri_rtol.
resize(old_size-1);
1569 auto* p_ltor = m_ri_ltor.
data();
1570 auto* p_rtol = m_ri_rtol.
data();
1572 auto const* p_ro = m_csr_remote.
row_offset.data();
1573 auto* p_tro = trimmed_row_offset.
data();
1575 if (old_size <
Long(std::numeric_limits<int>::max())) {
1577 new_size = Scan::PrefixSum<int>(
int(old_size),
1579 if (i+1 < old_size) {
1580 return (p_ro[i+1] > p_ro[i]);
1588 }
else if (p_ro[i] > p_ro[i-1]) {
1591 if (i+1 < old_size) {
1592 if (p_ro[i+1] > p_ro[i]) {
1603 new_size = Scan::PrefixSum<Long>(old_size,
1605 if (i+1 < old_size) {
1606 return (p_ro[i+1] > p_ro[i]);
1614 }
else if (p_ro[i] > p_ro[i-1]) {
1617 if (i+1 < old_size) {
1618 if (p_ro[i+1] > p_ro[i]) {
1629 m_ri_rtol.
resize(new_size-1);
1630 trimmed_row_offset.
resize(new_size);
1635 m_remote_row_offset = std::move(trimmed_row_offset);
1636 std::swap(m_csr_remote.
row_offset, m_remote_row_offset);
1639 }
else if (col_begin > 0) {
1644 update_remote_col_index(m_csr_remote,
true);
1649template <
typename T,
template<
typename>
class Allocator>
1650template <
typename C>
1657 m_remote_cols_v.clear();
1658 m_remote_cols_vv.clear();
1659 m_remote_cols_vv.resize(nprocs);
1661 m_remote_cols_dv.
clear();
1664 if (csrr.nnz == 0) {
return; }
1669 if (in_device_memory) {
1670 m_remote_cols_v.resize(csrr.nnz);
1672 csrr.col_index.begin(),
1673 csrr.col_index.end(),
1674 m_remote_cols_v.begin());
1679 m_remote_cols_v.assign(csrr.col_index.begin(),
1680 csrr.col_index.end());
1686 m_remote_cols_dv.
resize(m_remote_cols_v.
size());
1688 m_remote_cols_v.begin(),
1689 m_remote_cols_v.end(),
1690 m_remote_cols_dv.
data());
1694 auto const& cp = this->m_col_partition.
dataVector();
1696 m_remote_cols_v.back() < cp.back());
1697 auto it = cp.cbegin();
1698 for (
auto c : m_remote_cols_v) {
1699 it = std::find_if(it, cp.cend(), [&] (
auto x) { return x > c; });
1700 if (it != cp.cend()) {
1701 int iproc =
int(std::distance(cp.cbegin(),it)) - 1;
1702 m_remote_cols_vv[iproc].push_back(c);
1704 amrex::Abort(
"SpMatrix::update_remote_col_index: how did this happen?");
1709 std::map<Long,Long> gtol;
1710 for (
Long i = 0, N =
Long(m_remote_cols_v.
size()); i < N; ++i) {
1711 gtol[m_remote_cols_v[i]] = i;
1715 if (in_device_memory) {
1718 csrr.col_index.begin(),
1719 csrr.col_index.end(),
1720 host_col_index.
begin());
1722 for (
auto& c : host_col_index) {
1726 host_col_index.
begin(),
1727 host_col_index.
end(),
1728 csrr.col_index.begin());
1733 for (
auto& c : csrr.col_index) {
1739template <
typename T,
template<
typename>
class Allocator>
1742 if (m_num_neighbors >= 0) {
return; }
1749 for (
int iproc = 0; iproc < nprocs; ++iproc) {
1750 connection[iproc] = m_remote_cols_vv[iproc].empty() ? 0 : 1;
1753 m_num_neighbors = 0;
1754 BL_MPI_REQUIRE(MPI_Reduce_scatter
1755 (connection.data(), &m_num_neighbors, reduce_scatter_counts.data(),
1756 mpi_int, MPI_SUM, mpi_comm));
1759template <
typename T,
template<
typename>
class Allocator>
1762 if (m_comm_mv.prepared) {
return; }
1766 this->split_csr(col_partition);
1773 if (m_num_neighbors < 0) { set_num_neighbors(); }
1776 mpi_requests.reserve(nprocs);
1777 for (
int iproc = 0; iproc < nprocs; ++iproc) {
1778 if ( ! m_remote_cols_vv[iproc].empty()) {
1780 auto const sz = m_remote_cols_vv[iproc].
size();
1781 if (sz >
static_cast<Long>(std::numeric_limits<int>::max())) {
1782 amrex::Abort(
"SpMatrix::prepare_comm_mv: remote column payload exceeds MPI int count range.");
1784 auto const msg_count =
static_cast<int>(sz);
1786 BL_MPI_REQUIRE(MPI_Isend(m_remote_cols_vv[iproc].data(),
1788 mpi_long, iproc, mpi_tag, mpi_comm,
1789 &(mpi_requests.back())));
1790 m_comm_mv.recv_from.push_back(iproc);
1791 m_comm_mv.recv_counts.push_back(msg_count);
1795 m_comm_mv.total_counts_recv =
Long(m_remote_cols_v.
size());
1798 m_comm_mv.total_counts_send = 0;
1799 for (
int isend = 0; isend < m_num_neighbors; ++isend) {
1801 BL_MPI_REQUIRE(MPI_Probe(MPI_ANY_SOURCE, mpi_tag, mpi_comm, &mpi_status));
1802 int receiver = mpi_status.MPI_SOURCE;
1804 BL_MPI_REQUIRE(MPI_Get_count(&mpi_status, mpi_long, &count));
1805 m_comm_mv.send_to.push_back(receiver);
1806 m_comm_mv.send_counts.push_back(count);
1807 send_indices[isend].resize(count);
1808 BL_MPI_REQUIRE(MPI_Recv(send_indices[isend].data(), count, mpi_long,
1809 receiver, mpi_tag, mpi_comm, &mpi_status));
1810 m_comm_mv.total_counts_send += count;
1813 m_comm_mv.send_indices.resize(m_comm_mv.total_counts_send);
1815 send_indices_all.
reserve(m_comm_mv.total_counts_send);
1816 for (
auto const& vl : send_indices) {
1822 m_comm_mv.send_indices.begin());
1825 if (! mpi_requests.empty()) {
1827 BL_MPI_REQUIRE(MPI_Waitall(
int(mpi_requests.
size()), mpi_requests.data(),
1828 mpi_statuses.data()));
1831 m_comm_mv.prepared =
true;
1834template <
typename T,
template<
typename>
class Allocator>
1837 auto*
pdst = m_comm_mv.send_buffer;
1838 auto* pidx = m_comm_mv.send_indices.data();
1839 auto const& vv = v.
view();
1840 auto const nsends =
Long(m_comm_mv.send_indices.size());
1843 pdst[i] = vv(pidx[i]);
1847template <
typename T,
template<
typename>
class Allocator>
1850 auto const& csr = m_csr_remote;
1856 auto const* rtol = m_ri_rtol.
data();
1861 auto const nrr =
Long(csr.row_offset.size())-1;
1865 for (
Long j = row[i]; j < row[i+1]; ++j) {
1866 r += mat[j] * px[col[j]];
1873template <
typename T,
template<
typename>
class Allocator>
1878 m_col_partition = col_partition;
1886 if (nnz == 0) {
return; }
1901 auto& csrr = m_csr_remote;
1903 csrr.
mat.resize(nnz);
1911 std::iota(order.begin(), order.end(), 0);
1912 std::sort(order.begin(), order.end(), [&] (
int a,
int b) {
1913 return ctr.recv_from[a] < ctr.recv_from[b]; });
1917 for (
int i : order) {
1926 for (
int lr = 0; lr < nrow_i; ++lr) {
1927 Long const gr = idx_map[lr];
1928 while (p < nrows && ri_map[p] < gr) { ++p; }
1931 row_nnz[p] +=
int(row_offset[lr+1] - row_offset[lr]);
1935 std::exclusive_scan(row_nnz.begin(), row_nnz.end(), csrr.
row_offset.begin(),
1941 for (
int i : order) {
1953 for (
int lr = 0; lr < nrow_i; ++lr) {
1954 Long const gr = idx_map[lr];
1955 while (p < nrows && ri_map[p] < gr) { ++p; }
1958 auto os_src = row_offset[lr] - row_offset[0];
1959 auto nvals = row_offset[lr+1] - row_offset[lr];
1960 auto os_dst = rowpos[p];
1961 std::memcpy(csrr. mat.data()+os_dst, mat+os_src,
1963 std::memcpy(csrr.
col_index.data()+os_dst, col_index+os_src,
1964 sizeof(
Long)*nvals);
1972 auto row_begin = m_row_begin;
1976 rtol[i] -= row_begin;
1982 update_remote_col_index(csrr,
false);
1990template <
typename T,
template<
typename>
class Allocator>
1996 this->prepare_comm_mv(B.partition());
1998 auto const& cm = m_comm_mv;
1999 auto const nrecvs =
int(cm.recv_from.size());
2000 auto const nsends =
int(cm.send_to.size());
2006 ext.
nrows = cm.total_counts_recv;
2009 auto const b0 = B.m_csr.const_view();
2010 auto const b1 = B.remote_full_const_view();
2011 Long const b_row_begin = B.m_row_begin;
2012 Long const nsend_rows = cm.total_counts_send;
2019 auto* pcnt = d_cnt.
data();
2022 Long const lr = send_idx[i] - b_row_begin;
2023 pcnt[i] = (b0.row_offset[lr+1] - b0.row_offset[lr])
2024 + (b1.row_offset[lr+1] - b1.row_offset[lr]);
2034 reqs.reserve(nrecvs+nsends);
2036 for (
int i = 0; i < nrecvs; ++i) {
2038 BL_MPI_REQUIRE(MPI_Irecv(h_recv.
data()+os, cm.recv_counts[i], mpi_long,
2039 cm.recv_from[i], tag, mpi_comm, &reqs.back()));
2040 os += cm.recv_counts[i];
2043 for (
int i = 0; i < nsends; ++i) {
2045 BL_MPI_REQUIRE(MPI_Isend(h_send.
data()+os, cm.send_counts[i], mpi_long,
2046 cm.send_to[i], tag, mpi_comm, &reqs.back()));
2047 os += cm.send_counts[i];
2049 if (! reqs.empty()) {
2051 BL_MPI_REQUIRE(MPI_Waitall(
int(reqs.
size()), reqs.data(), stats.data()));
2058 for (
Long i = 0; i < n; ++i) {
2059 Long const c = v[i];
2065 to_offsets(h_recv, ext.
nrows);
2066 to_offsets(h_send, nsend_rows);
2068 Long const send_nnz = h_send[nsend_rows];
2071 for (
int i = 0, r = 0; i < nrecvs; ++i) {
2072 recv_nnz[i] = h_recv[r+cm.recv_counts[i]] - h_recv[r];
2073 r += cm.recv_counts[i];
2074 if (recv_nnz[i] >=
Long(std::numeric_limits<int>::max())) {
2075 amrex::Abort(
"SpMatrix::fetch_remote_rows_mm: message exceeds MPI int count range.");
2078 for (
int i = 0, r = 0; i < nsends; ++i) {
2079 send_nnz_v[i] = h_send[r+cm.send_counts[i]] - h_send[r];
2080 r += cm.send_counts[i];
2081 if (send_nnz_v[i] >=
Long(std::numeric_limits<int>::max())) {
2082 amrex::Abort(
"SpMatrix::fetch_remote_rows_mm: message exceeds MPI int count range.");
2098 rreqs.reserve(2*nrecvs);
2100 for (
int i = 0; i < nrecvs; ++i) {
2101 if (recv_nnz[i] > 0) {
2102 auto n =
int(recv_nnz[i]);
2104 BL_MPI_REQUIRE(MPI_Irecv(ext.
col_index+os, n, mpi_long, cm.recv_from[i],
2105 tag_c, mpi_comm, &rreqs.back()));
2107 BL_MPI_REQUIRE(MPI_Irecv(ext.
mat+os, n, mpi_t, cm.recv_from[i],
2108 tag_m, mpi_comm, &rreqs.back()));
2114 Long* send_col =
nullptr;
2115 T* send_mat =
nullptr;
2119 auto const* poff = d_send_off.
data();
2120 Long const b_col_begin = B.m_col_begin;
2122 auto const* b_rcols = B.m_remote_cols_dv.data();
2124 auto const* b_rcols = B.m_remote_cols_v.data();
2130 constexpr Long gmax = std::numeric_limits<Long>::max();
2131 Long const lr = send_idx[i] - b_row_begin;
2133 Long q0 = b0.row_offset[lr];
2134 Long q1 = b1.row_offset[lr];
2135 Long const e0 = b0.row_offset[lr+1];
2136 Long const e1 = b1.row_offset[lr+1];
2137 while (q0 < e0 || q1 < e1) {
2138 Long const g0 = (q0 < e0) ? b0.col_index[q0] + b_col_begin : gmax;
2139 Long const g1 = (q1 < e1) ? b_rcols[b1.col_index[q1]] : gmax;
2142 send_mat[p] = b0.mat[q0];
2146 send_mat[p] = b1.mat[q1];
2154 sreqs.reserve(2*nsends);
2156 for (
int i = 0; i < nsends; ++i) {
2157 if (send_nnz_v[i] > 0) {
2158 auto n =
int(send_nnz_v[i]);
2160 BL_MPI_REQUIRE(MPI_Isend(send_col+os, n, mpi_long, cm.send_to[i],
2161 tag_c, mpi_comm, &sreqs.back()));
2163 BL_MPI_REQUIRE(MPI_Isend(send_mat+os, n, mpi_t, cm.send_to[i],
2164 tag_m, mpi_comm, &sreqs.back()));
2165 os += send_nnz_v[i];
2170 if (! rreqs.empty()) {
2172 BL_MPI_REQUIRE(MPI_Waitall(
int(rreqs.
size()), rreqs.data(), stats.data()));
2174 if (! sreqs.empty()) {
2176 BL_MPI_REQUIRE(MPI_Waitall(
int(sreqs.
size()), sreqs.data(), stats.data()));
2185template <
typename T,
template<
typename>
class Allocator>
2188 if (! m_remote_row_offset.
empty()) {
return; }
2192 auto nrows = m_csr.
nrows();
2193 m_remote_row_offset.
resize(nrows+1);
2194 auto* pro_full = m_remote_row_offset.
data();
2195 auto const* pro_comp = m_csr_remote.
row_offset.data();
2196 auto const* ri_ltor = m_ri_ltor.
data();
2197 auto nnz_r = m_csr_remote.
nnz;
2198 if (nnz_r == 0 || m_ri_ltor.
empty()) {
2202 }
else if (nnz_r <
Long(std::numeric_limits<int>::max())) {
2203 Scan::PrefixSum<int>(nrows,
2205 Long rrow = ri_ltor[i];
2209 return int(pro_comp[rrow+1]-pro_comp[rrow]);
2219 Scan::PrefixSum<Long>(nrows,
2221 Long rrow = ri_ltor[i];
2225 return pro_comp[rrow+1]-pro_comp[rrow];
2237template <
typename T,
template<
typename>
class Allocator>
2240 if (m_remote_row_offset.
empty()) {
2241 expand_remote_row_offset();
2244 csr_view.row_offset = m_remote_row_offset.
data();
2245 csr_view.nrows = m_csr.
nrows();
#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:50
bool empty() const
True if the partition contains no rows.
Definition AMReX_AlgPartition.H:40
Vector< Long > const & dataVector() const
Underlying array describing row offsets (size nproc+1).
Definition AMReX_AlgPartition.H:67
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
bool empty() const
True if the local storage holds zero entries.
Definition AMReX_AlgVector.H:68
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
void clear() noexcept
Definition AMReX_PODVector.H:652
T * data() noexcept
Definition AMReX_PODVector.H:672
bool empty() const noexcept
Definition AMReX_PODVector.H:658
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:63
void finishComm_tr(SpMatrix< T, Allocator > &AT)
Complete transpose communication, writing the assembled matrix into AT.
Definition AMReX_SpMatrix.H:1411
void split_csr(AlgPartition const &col_partition)
Definition AMReX_SpMatrix.H:1468
void setColumnPartition(AlgPartition const &col_partition)
Definition AMReX_SpMatrix.H:876
Long globalRowBegin() const
Inclusive global index begin on this process.
Definition AMReX_SpMatrix.H:198
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:890
Long * rowOffset()
Don't use this beyond initial setup.
Definition AMReX_SpMatrix.H:215
void sortCSR()
Definition AMReX_SpMatrix.H:869
void pack_buffer_mv(AlgVector< T, AllocT > const &v)
Definition AMReX_SpMatrix.H:1835
void unpack_buffer_mv(AlgVector< T, AllocT > &v)
Definition AMReX_SpMatrix.H:1848
void update_remote_col_index(C &csrr, bool in_device_memory)
Definition AMReX_SpMatrix.H:1651
void startComm_tr(AlgPartition const &col_partition)
Initiate communication required to build the transpose with column partition col_partition.
Definition AMReX_SpMatrix.H:1201
void comm_tr_clear()
Definition AMReX_SpMatrix.H:1440
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:801
T * data()
Don't use this beyond initial setup.
Definition AMReX_SpMatrix.H:203
friend class AMG
Definition AMReX_SpMatrix.H:304
Long numGlobalRows() const
Global row count.
Definition AMReX_SpMatrix.H:193
SpMatrix & operator=(SpMatrix const &)=delete
T value_type
Definition AMReX_SpMatrix.H:65
CsrView< T const > remote_full_const_view() const
Off-diagonal part with the full (untrimmed) row offsets.
Definition AMReX_SpMatrix.H:2238
RemoteRowsMM fetch_remote_rows_mm(SpMatrix< T, Allocator > const &B)
Definition AMReX_SpMatrix.H:1991
Allocator< U > allocator_type
Definition AMReX_SpMatrix.H:66
Long globalRowEnd() const
Exclusive global index end on this process.
Definition AMReX_SpMatrix.H:200
Long numLocalNonZeros() const
Number of nonzeros stored locally.
Definition AMReX_SpMatrix.H:195
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:1040
AlgPartition const & columnPartition() const
Return the column partition used for matrix-vector and matrix-matrix multiplications.
Definition AMReX_SpMatrix.H:188
void printToFile(std::string const &file) const
Definition AMReX_SpMatrix.H:928
ParCsr< T const > const_parcsr() const
Const-qualified alias of parcsr() for convenience.
Definition AMReX_SpMatrix.H:1089
SpMatrix(SpMatrix const &)=delete
ParCsr< T > parcsr()
Build GPU-friendly CSR views split into diagonal/off-diagonal blocks.
Definition AMReX_SpMatrix.H:1065
SpMatrix(SpMatrix &&)=default
Long numLocalRows() const
Number of rows owned by this rank.
Definition AMReX_SpMatrix.H:191
AlgPartition const & partition() const
Row partition describing how matrix rows are distributed across ranks.
Definition AMReX_SpMatrix.H:179
AlgVector< T, AllocT > const & diagonalVector() const
Return diagonal elements in a square matrix.
Definition AMReX_SpMatrix.H:1014
Long * columnIndex()
Don't use this beyond initial setup.
Definition AMReX_SpMatrix.H:209
void comm_tr_recv_wait()
Definition AMReX_SpMatrix.H:1429
void finishComm_mv(AlgVector< T, AllocT > &y)
Finish halo exchanges and accumulate contributions into y.
Definition AMReX_SpMatrix.H:1169
Allocator< T > AllocT
Definition AMReX_SpMatrix.H:69
friend SpMatrix< U, M > SpGEMM(SpMatrix< U, M > const &A, SpMatrix< U, M > const &B, AlgPartition const &col_partition)
struct amrex::SpMatrix::CommTR m_comm_tr
void expand_remote_row_offset() const
Definition AMReX_SpMatrix.H:2186
void prepare_comm_mv(AlgPartition const &col_partition)
Definition AMReX_SpMatrix.H:1760
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:1120
friend SpMatrix< U, M > transpose(SpMatrix< U, M > const &A, AlgPartition const &col_partition)
void unpack_buffer_tr(CommTR const &ctr, AlgPartition const &col_partition)
Definition AMReX_SpMatrix.H:1874
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:993
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:775
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 struct amrex::Scan::Type::Inclusive inclusive
static constexpr RetSum noRetSum
Definition AMReX_Scan.H:35
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 nrows() const
Number of logical rows represented by the CSR offset array.
Definition AMReX_CSR.H:57
Long nnz
Definition AMReX_CSR.H:54
void sort()
Sort each row by column index. Uses GPU acceleration when possible.
Definition AMReX_CSR.H:141
CsrView< T > view()
Mutable view of the underlying buffers.
Definition AMReX_CSR.H:78
CsrView< T const > const_view() const
Convenience alias for view() const.
Definition AMReX_CSR.H:93
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:47
bool b
Definition AMReX_SpMatrix.H:48
Valid CSR means all entries are valid. It may be sorted ro unsorted.
Definition AMReX_SpMatrix.H:53
bool b
Definition AMReX_SpMatrix.H:54
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:37
Long const *__restrict__ col_map
Definition AMReX_SpMatrix.H:43
Long const *__restrict__ row_map
Definition AMReX_SpMatrix.H:42
CsrView< T > csr1
Definition AMReX_SpMatrix.H:39
Long col_begin
Definition AMReX_SpMatrix.H:41
Long row_begin
Definition AMReX_SpMatrix.H:40
CsrView< T > csr0
Definition AMReX_SpMatrix.H:38
static MPI_Datatype type()
Definition AMReX_SpMatrix.H:402
T * send_buffer
Definition AMReX_SpMatrix.H:411
bool prepared
Definition AMReX_SpMatrix.H:418
Vector< int > recv_counts
Definition AMReX_SpMatrix.H:408
Long total_counts_recv
Definition AMReX_SpMatrix.H:416
Vector< int > recv_from
Definition AMReX_SpMatrix.H:407
T * recv_buffer
Definition AMReX_SpMatrix.H:415
Vector< int > send_counts
Definition AMReX_SpMatrix.H:404
Long total_counts_send
Definition AMReX_SpMatrix.H:412
Gpu::DeviceVector< Long > send_indices
Definition AMReX_SpMatrix.H:405
Vector< MPI_Request > recv_reqs
Definition AMReX_SpMatrix.H:414
Vector< int > send_to
Definition AMReX_SpMatrix.H:403
Vector< MPI_Request > send_reqs
Definition AMReX_SpMatrix.H:410
Definition AMReX_SpMatrix.H:421
Vector< std::array< int, 2 > > send_counts
Definition AMReX_SpMatrix.H:425
Long * recv_buffer_col_index
Definition AMReX_SpMatrix.H:438
Vector< MPI_Request > send_reqs
Definition AMReX_SpMatrix.H:426
Vector< MPI_Request > recv_reqs
Definition AMReX_SpMatrix.H:430
Vector< int > send_to
Definition AMReX_SpMatrix.H:424
std::array< Long, 2 > total_counts_recv
Definition AMReX_SpMatrix.H:432
Long * recv_buffer_row_offset
Definition AMReX_SpMatrix.H:439
Vector< std::array< int, 2 > > recv_counts
Definition AMReX_SpMatrix.H:429
CsrView< T > csrt
Definition AMReX_SpMatrix.H:422
T * recv_buffer_mat
Definition AMReX_SpMatrix.H:437
Vector< std::array< Long, 4 > > recv_buffer_offset
Definition AMReX_SpMatrix.H:433
Vector< int > recv_from
Definition AMReX_SpMatrix.H:428
Long * recv_buffer_idx_map
Definition AMReX_SpMatrix.H:440
Rows of another matrix fetched for SpGEMM. Column indices are global.
Definition AMReX_SpMatrix.H:458
container_type< Long > row_offset
Definition AMReX_SpMatrix.H:459
RemoteRowsMM(RemoteRowsMM &&rhs) noexcept
Definition AMReX_SpMatrix.H:469
RemoteRowsMM(RemoteRowsMM const &)=delete
Long nnz
Definition AMReX_SpMatrix.H:463
~RemoteRowsMM()
Definition AMReX_SpMatrix.H:466
Long * col_index
Definition AMReX_SpMatrix.H:460
RemoteRowsMM & operator=(RemoteRowsMM const &)=delete
Long nrows
Definition AMReX_SpMatrix.H:462
void clear()
Definition AMReX_SpMatrix.H:485
T * mat
Definition AMReX_SpMatrix.H:461
Definition AMReX_ccse-mpi.H:55