740MatrixCSR<U, V, W, X>::MatrixCSR(
const SparsityType& p,
BlockMode mode)
741 : _index_maps({p.index_map(0), p.index_map(1)}), _block_mode(mode),
742 _bs({p.block_size(0), p.block_size(1)}),
743 _data(p.graph().first.size() * _bs[0] * _bs[1], 0),
744 _cols(p.graph().first.begin(), p.graph().first.end()),
745 _row_ptr(p.graph().second.begin(), p.graph().second.end()),
751 for (
int i = 0; i < 2; ++i)
753 auto im = _index_maps[i];
754 std::int32_t size_local = im->size_local() * _bs[i];
755 std::span ghost_i = im->ghosts();
756 std::vector<std::int64_t> ghosts;
757 const std::vector<int> ghost_owner_i(im->owners().begin(),
759 std::vector<int> src_rank;
760 for (std::size_t j = 0; j < ghost_i.size(); ++j)
762 for (
int k = 0; k < _bs[i]; ++k)
764 ghosts.push_back(ghost_i[j] * _bs[i] + k);
765 src_rank.push_back(ghost_owner_i[j]);
769 std::array<std::vector<int>, 2> src_dest0
770 = {std::vector(_index_maps[i]->src().begin(),
771 _index_maps[i]->src().end()),
772 std::vector(_index_maps[i]->dest().begin(),
773 _index_maps[i]->dest().end())};
774 _index_maps[i] = std::make_shared<common::IndexMap>(
775 _index_maps[i]->comm(), size_local, src_dest0, ghosts, src_rank);
780 column_container_type new_cols;
781 new_cols.reserve(_data.size());
782 rowptr_container_type new_row_ptr{0};
783 new_row_ptr.reserve(_row_ptr.size() * _bs[0]);
784 std::span<const std::int32_t> num_diag_nnz = p.off_diagonal_offsets();
785 for (std::size_t i = 0; i < _row_ptr.size() - 1; ++i)
788 for (
int q0 = 0; q0 < _bs[0]; ++q0)
790 _off_diagonal_offset.push_back(new_row_ptr.back()
791 + num_diag_nnz[i] * _bs[1]);
792 for (
auto j = _row_ptr[i]; j < _row_ptr[i + 1]; ++j)
794 for (
int q1 = 0; q1 < _bs[1]; ++q1)
795 new_cols.push_back(_cols[j] * _bs[1] + q1);
797 new_row_ptr.push_back(new_cols.size());
801 _row_ptr = new_row_ptr;
808 std::span<const std::int32_t> num_diag_nnz = p.off_diagonal_offsets();
809 _off_diagonal_offset.reserve(num_diag_nnz.size());
810 std::ranges::transform(num_diag_nnz, _row_ptr,
811 std::back_inserter(_off_diagonal_offset),
816 std::array local_size
817 = {_index_maps[0]->size_local(), _index_maps[1]->size_local()};
819 = {_index_maps[0]->local_range(), _index_maps[1]->local_range()};
820 std::span ghosts1 = _index_maps[1]->ghosts();
822 std::span ghosts0 = _index_maps[0]->ghosts();
823 std::span src_ranks = _index_maps[0]->src();
824 std::span dest_ranks = _index_maps[0]->dest();
828 MPI_Dist_graph_create_adjacent(_index_maps[0]->comm(), dest_ranks.size(),
829 dest_ranks.data(), MPI_UNWEIGHTED,
830 src_ranks.size(), src_ranks.data(),
831 MPI_UNWEIGHTED, MPI_INFO_NULL,
false, &comm);
832 _comm = dolfinx::MPI::Comm(comm,
false);
836 _ghost_row_to_rank.reserve(_index_maps[0]->owners().
size());
837 for (
int r : _index_maps[0]->owners())
839 auto it = std::ranges::lower_bound(src_ranks, r);
840 assert(it != src_ranks.end() and *it == r);
841 std::size_t pos = std::ranges::distance(src_ranks.begin(), it);
842 _ghost_row_to_rank.push_back(pos);
846 std::vector<std::int32_t> data_per_proc(src_ranks.size(), 0);
847 for (std::size_t i = 0; i < _ghost_row_to_rank.size(); ++i)
849 assert(_ghost_row_to_rank[i] < (
int)data_per_proc.size());
850 std::size_t pos = local_size[0] + i;
851 data_per_proc[_ghost_row_to_rank[i]] += _row_ptr[pos + 1] - _row_ptr[pos];
855 _val_send_disp.resize(src_ranks.size() + 1, 0);
856 std::partial_sum(data_per_proc.begin(), data_per_proc.end(),
857 std::next(_val_send_disp.begin()));
860 std::vector<std::int64_t> ghost_index_data(2 * _val_send_disp.back());
862 std::vector<int> insert_pos = _val_send_disp;
863 for (std::size_t i = 0; i < _ghost_row_to_rank.size(); ++i)
865 int rank = _ghost_row_to_rank[i];
866 std::int32_t row_id = local_size[0] + i;
867 for (
int j = _row_ptr[row_id]; j < _row_ptr[row_id + 1]; ++j)
870 std::int32_t idx_pos = 2 * insert_pos[
rank];
873 ghost_index_data[idx_pos] = ghosts0[i];
874 if (std::int32_t col_local = _cols[j]; col_local < local_size[1])
875 ghost_index_data[idx_pos + 1] = col_local + local_range[1][0];
877 ghost_index_data[idx_pos + 1] = ghosts1[col_local - local_size[1]];
879 insert_pos[
rank] += 1;
885 std::vector<std::int64_t> ghost_index_array;
886 std::vector<int> recv_disp;
888 std::vector<int> send_sizes;
889 std::ranges::transform(data_per_proc, std::back_inserter(send_sizes),
890 [](
auto x) {
return 2 * x; });
892 std::vector<int> recv_sizes(dest_ranks.size());
893 send_sizes.reserve(1);
894 recv_sizes.reserve(1);
895 MPI_Neighbor_alltoall(send_sizes.data(), 1, MPI_INT, recv_sizes.data(), 1,
896 MPI_INT, _comm.
comm());
899 std::vector<int> send_disp{0};
900 std::partial_sum(send_sizes.begin(), send_sizes.end(),
901 std::back_inserter(send_disp));
903 std::partial_sum(recv_sizes.begin(), recv_sizes.end(),
904 std::back_inserter(recv_disp));
906 ghost_index_array.resize(recv_disp.back());
907 MPI_Neighbor_alltoallv(ghost_index_data.data(), send_sizes.data(),
908 send_disp.data(), MPI_INT64_T,
909 ghost_index_array.data(), recv_sizes.data(),
910 recv_disp.data(), MPI_INT64_T, _comm.
comm());
915 _val_recv_disp.resize(recv_disp.size());
916 int bs2 = _bs[0] * _bs[1];
917 std::ranges::transform(recv_disp, _val_recv_disp.begin(),
918 [&bs2](
auto d) { return bs2 * d / 2; });
919 std::ranges::transform(_val_send_disp, _val_send_disp.begin(),
920 [&bs2](
auto d) { return d * bs2; });
923 std::vector<std::pair<std::int64_t, std::int32_t>> global_to_local;
924 global_to_local.reserve(ghosts1.size());
925 for (std::int64_t idx : ghosts1)
926 global_to_local.push_back({idx, global_to_local.size() + local_size[1]});
927 std::ranges::sort(global_to_local);
931 for (std::size_t i = 0; i < ghost_index_array.size(); i += 2)
934 std::int32_t local_row = ghost_index_array[i] -
local_range[0][0];
935 assert(local_row >= 0 and local_row < local_size[0]);
938 std::int32_t local_col = ghost_index_array[i + 1] -
local_range[1][0];
939 if (local_col < 0 or local_col >= local_size[1])
941 auto it = std::ranges::lower_bound(
942 global_to_local, std::pair(ghost_index_array[i + 1], -1),
943 [](
auto a,
auto b) {
return a.first < b.first; });
944 assert(it != global_to_local.end()
945 and it->first == ghost_index_array[i + 1]);
946 local_col = it->second;
948 auto cit0 = std::next(_cols.begin(), _row_ptr[local_row]);
949 auto cit1 = std::next(_cols.begin(), _row_ptr[local_row + 1]);
952 auto cit = std::lower_bound(cit0, cit1, local_col);
954 assert(*cit == local_col);
955 std::size_t d = std::ranges::distance(_cols.begin(), cit);
956 _unpack_pos.push_back(d);
959 _unpack_pos.shrink_to_fit();
995 std::span<const std::int64_t> Arow_ptr(
row_ptr().data(), nrowslocal + 1);
996 std::span<const std::int32_t> Acols(
cols().data(), Arow_ptr[nrowslocal]);
997 std::span<const std::int64_t> Aoff_diag_offset(
off_diag_offset().data(),
999 std::span<const Scalar> Avalues(
values().data(),
1000 Arow_ptr[nrowslocal] * _bs[0] * _bs[1]);
1002 std::span<const Scalar> _x = x.
array();
1003 std::span<Scalar> _y = y.
array();
1005 std::span<const std::int64_t> Arow_begin(Arow_ptr.data(), nrowslocal);
1006 std::span<const std::int64_t> Arow_end(Arow_ptr.data() + 1, nrowslocal);
1012 impl::spmv<Scalar>(Avalues, Arow_begin, Aoff_diag_offset, Acols, _x, _y,
1013 _bs[0], std::integral_constant<int, 1>{});
1015 else if (_bs[1] == 2)
1017 impl::spmv<Scalar>(Avalues, Arow_begin, Aoff_diag_offset, Acols, _x, _y,
1018 _bs[0], std::integral_constant<int, 2>{});
1020 else if (_bs[1] == 3)
1022 impl::spmv<Scalar>(Avalues, Arow_begin, Aoff_diag_offset, Acols, _x, _y,
1023 _bs[0], std::integral_constant<int, 3>{});
1027 impl::spmv<Scalar>(Avalues, Arow_begin, Aoff_diag_offset, Acols, _x, _y,
1038 impl::spmv<Scalar>(Avalues, Aoff_diag_offset, Arow_end, Acols, _x, _y,
1039 _bs[0], std::integral_constant<int, 1>{});
1041 else if (_bs[1] == 2)
1043 impl::spmv<Scalar>(Avalues, Aoff_diag_offset, Arow_end, Acols, _x, _y,
1044 _bs[0], std::integral_constant<int, 2>{});
1046 else if (_bs[1] == 3)
1048 impl::spmv<Scalar>(Avalues, Aoff_diag_offset, Arow_end, Acols, _x, _y,
1049 _bs[0], std::integral_constant<int, 3>{});
1053 impl::spmv<Scalar>(Avalues, Aoff_diag_offset, Arow_end, Acols, _x, _y,
1065 std::span<const std::int64_t> Arow_ptr(
row_ptr().data(), nrowslocal + 1);
1066 std::span<const std::int32_t> Acols(
cols().data(), Arow_ptr[nrowslocal]);
1067 std::span<const std::int64_t> Aoff_diag_offset(
off_diag_offset().data(),
1069 std::span<const Scalar> Avalues(
values().data(),
1070 Arow_ptr[nrowslocal] * _bs[0] * _bs[1]);
1072 std::span<const Scalar> _x = x.
array();
1073 std::span<Scalar> _y = y.
array();
1075 std::span<const std::int64_t> Arow_begin(Arow_ptr.data(), nrowslocal);
1076 std::span<const std::int64_t> Arow_end(Arow_ptr.data() + 1, nrowslocal);
1081 std::int32_t ncolslocal =
index_map(1)->size_local();
1082 std::fill(std::next(_y.begin(), ncolslocal * _bs[1]), _y.end(), Scalar(0));
1085 impl::spmvT<Scalar>(Avalues, Aoff_diag_offset, Arow_end, Acols, _x, _y,
1086 _bs[0], std::integral_constant<int, 1>{});
1088 else if (_bs[1] == 2)
1090 impl::spmvT<Scalar>(Avalues, Aoff_diag_offset, Arow_end, Acols, _x, _y,
1091 _bs[0], std::integral_constant<int, 2>{});
1093 else if (_bs[1] == 3)
1095 impl::spmvT<Scalar>(Avalues, Aoff_diag_offset, Arow_end, Acols, _x, _y,
1096 _bs[0], std::integral_constant<int, 3>{});
1100 impl::spmvT<Scalar>(Avalues, Aoff_diag_offset, Arow_end, Acols, _x, _y,
1108 impl::spmvT<Scalar>(Avalues, Arow_begin, Aoff_diag_offset, Acols, _x, _y,
1109 _bs[0], std::integral_constant<int, 1>{});
1111 else if (_bs[1] == 2)
1113 impl::spmvT<Scalar>(Avalues, Arow_begin, Aoff_diag_offset, Acols, _x, _y,
1114 _bs[0], std::integral_constant<int, 2>{});
1116 else if (_bs[1] == 3)
1118 impl::spmvT<Scalar>(Avalues, Arow_begin, Aoff_diag_offset, Acols, _x, _y,
1119 _bs[0], std::integral_constant<int, 3>{});
1123 impl::spmvT<Scalar>(Avalues, Arow_begin, Aoff_diag_offset, Acols, _x, _y,