50struct DistributedPMISAggregation
52 typedef typename Backend::value_type value_type;
53 typedef typename math::scalar_of<value_type>::type scalar_type;
56 using build_matrix = Backend::matrix;
57 using col_type = Backend::col_type;
58 using ptr_type = Backend::ptr_type;
60 using bool_matrix = bool_backend::matrix;
68 double eps_strong = 0.08;
76 : ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p,
nullspace)
77 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, eps_strong)
78 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, block_size)
80 p.check_params({
"nullspace",
"eps_strong",
"block_size" });
85 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path,
nullspace);
86 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, eps_strong);
87 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, block_size);
92 std::shared_ptr<DistributedMatrix<bool_backend>> conn;
93 std::shared_ptr<matrix> p_tent;
95 DistributedPMISAggregation(
const matrix& A, params& prm)
98 ptrdiff_t n = A.loc_rows();
102 if (prm.block_size == 1) {
103 conn = conn_strength(A, prm.eps_strong);
105 ptrdiff_t naggr = aggregates(*conn, state, owner);
106 p_tent = tentative_prolongation(A.comm(), n, naggr, state, owner);
109 typedef typename math::scalar_of<value_type>::type scalar;
110 using sbackend = BuiltinBackend<scalar, col_type, ptr_type>;
112 ptrdiff_t np = n / prm.block_size;
114 assert(np * prm.block_size == n &&
"Matrix size should be divisible by block_size");
116 DistributedMatrix<sbackend> A_pw(A.comm(),
117 pointwise_matrix(*A.local(), prm.block_size),
118 pointwise_matrix(*A.remote(), prm.block_size));
120 auto conn_pw = conn_strength(A_pw, prm.eps_strong);
122 UniqueArray<ptrdiff_t> state_pw(np);
123 UniqueArray<int> owner_pw(np);
125 ptrdiff_t naggr = aggregates(*conn_pw, state_pw, owner_pw);
127 conn = std::make_shared<DistributedMatrix<bool_backend>>(A.comm(),
128 expand_conn(*A.local(), *A_pw.local(), *conn_pw->local(), prm.block_size),
129 expand_conn(*A.remote(), *A_pw.remote(), *conn_pw->remote(), prm.block_size));
132 for (ptrdiff_t ip = begin; ip < (begin + size); ++ip) {
133 ptrdiff_t i = ip * prm.block_size;
134 ptrdiff_t s = state_pw[ip];
135 int o = owner_pw[ip];
137 for (
unsigned k = 0; k < prm.block_size; ++k) {
138 state[i + k] = (s < 0) ? s : (s * prm.block_size + k);
144 p_tent = tentative_prolongation(A.comm(), n, naggr * prm.block_size, state, owner);
148 std::shared_ptr<DistributedMatrix<bool_backend>>
149 squared_interface(
const DistributedMatrix<bool_backend>& A)
151 const CommunicationPattern<bool_backend>& C = A.cpat();
153 bool_matrix& A_loc = *A.local();
154 bool_matrix& A_rem = *A.remote();
156 ptrdiff_t A_rows = A.loc_rows();
158 ptrdiff_t A_beg = A.loc_col_shift();
159 ptrdiff_t A_end = A_beg + A_rows;
161 auto a_nbr = remote_rows(C, A,
false);
162 bool_matrix& A_nbr = *a_nbr;
166 UniqueArray<ptrdiff_t> rem_cols(A_rem.nbNonZero() + A_nbr.nbNonZero());
168 std::copy(A_nbr.col.data(), A_nbr.col.data() + A_nbr.nbNonZero(),
169 std::copy(A_rem.col.data(), A_rem.col.data() + A_rem.nbNonZero(), rem_cols.begin()));
171 std::sort(rem_cols.begin(), rem_cols.end());
172 rem_cols.erase(std::unique(rem_cols.begin(), rem_cols.end()), rem_cols.end());
174 ptrdiff_t n_rem_cols = 0;
175 std::unordered_map<ptrdiff_t, int> rem_idx(2 * rem_cols.size());
176 for (ptrdiff_t c : rem_cols) {
177 if (c >= A_beg && c < A_end)
179 rem_idx[c] = n_rem_cols++;
183 auto s_loc = std::make_shared<bool_matrix>();
184 auto s_rem = std::make_shared<bool_matrix>();
186 bool_matrix& S_loc = *s_loc;
187 bool_matrix& S_rem = *s_rem;
189 S_loc.set_size(A_rows, A_rows,
false);
190 S_rem.set_size(A_rows, 0,
false);
195 ARCCORE_ALINA_TIC(
"analyze");
197 UniqueArray<ptrdiff_t> loc_marker(A_rows, -1);
198 UniqueArray<ptrdiff_t> rem_marker(n_rem_cols, -1);
200 for (ptrdiff_t ia = begin; ia < (begin + size); ++ia) {
201 ptrdiff_t loc_cols = 0;
202 ptrdiff_t rem_cols = 0;
204 for (ptrdiff_t ja = A_rem.ptr[ia], ea = A_rem.ptr[ia + 1]; ja < ea; ++ja) {
205 ptrdiff_t ca = C.local_index(A_rem.col[ja]);
207 for (ptrdiff_t jb = A_nbr.ptr[ca], eb = A_nbr.ptr[ca + 1]; jb < eb; ++jb) {
208 ptrdiff_t cb = A_nbr.col[jb];
210 if (cb >= A_beg && cb < A_end) {
213 if (loc_marker[cb] != ia) {
221 if (rem_marker[cb] != ia) {
229 for (ptrdiff_t ja = A_loc.ptr[ia], ea = A_loc.ptr[ia + 1]; ja < ea; ++ja) {
230 ptrdiff_t ca = A_loc.col[ja];
232 for (ptrdiff_t jb = A_rem.ptr[ca], eb = A_rem.ptr[ca + 1]; jb < eb; ++jb) {
233 ptrdiff_t cb = rem_idx[A_rem.col[jb]];
235 if (rem_marker[cb] != ia) {
243 for (ptrdiff_t ja = A_loc.ptr[ia], ea = A_loc.ptr[ia + 1]; ja < ea; ++ja) {
244 ptrdiff_t ca = A_loc.col[ja];
246 for (ptrdiff_t jb = A_loc.ptr[ca], eb = A_loc.ptr[ca + 1]; jb < eb; ++jb) {
247 ptrdiff_t cb = A_loc.col[jb];
249 if (loc_marker[cb] != ia) {
257 S_rem.ptr[ia + 1] = rem_cols;
258 S_loc.ptr[ia + 1] = rem_cols ? loc_cols : 0;
261 ARCCORE_ALINA_TOC(
"analyze");
263 S_loc.set_nonzeros(S_loc.scan_row_sizes(),
false);
264 S_rem.set_nonzeros(S_rem.scan_row_sizes(),
false);
266 ARCCORE_ALINA_TIC(
"compute");
268 UniqueArray<ptrdiff_t> loc_marker(A_rows, -1);
269 UniqueArray<ptrdiff_t> rem_marker(n_rem_cols, -1);
271 for (ptrdiff_t ia = begin; ia < (begin + size); ++ia) {
272 ptrdiff_t loc_beg = S_loc.ptr[ia];
273 ptrdiff_t rem_beg = S_rem.ptr[ia];
274 ptrdiff_t loc_end = loc_beg;
275 ptrdiff_t rem_end = rem_beg;
277 if (rem_beg == S_rem.ptr[ia + 1])
280 for (ptrdiff_t ja = A_loc.ptr[ia], ea = A_loc.ptr[ia + 1]; ja < ea; ++ja) {
281 ptrdiff_t ca = A_loc.col[ja];
283 for (ptrdiff_t jb = A_loc.ptr[ca], eb = A_loc.ptr[ca + 1]; jb < eb; ++jb) {
284 ptrdiff_t cb = A_loc.col[jb];
286 if (loc_marker[cb] < loc_beg) {
287 loc_marker[cb] = loc_end;
288 S_loc.col[loc_end] = cb;
293 for (ptrdiff_t jb = A_rem.ptr[ca], eb = A_rem.ptr[ca + 1]; jb < eb; ++jb) {
294 ptrdiff_t gb = A_rem.col[jb];
295 ptrdiff_t cb = rem_idx[gb];
297 if (rem_marker[cb] < rem_beg) {
298 rem_marker[cb] = rem_end;
299 S_rem.col[rem_end] = gb;
305 for (ptrdiff_t ja = A_rem.ptr[ia], ea = A_rem.ptr[ia + 1]; ja < ea; ++ja) {
306 ptrdiff_t ca = C.local_index(A_rem.col[ja]);
308 for (ptrdiff_t jb = A_nbr.ptr[ca], eb = A_nbr.ptr[ca + 1]; jb < eb; ++jb) {
309 ptrdiff_t gb = A_nbr.col[jb];
311 if (gb >= A_beg && gb < A_end) {
312 ptrdiff_t cb = gb - A_beg;
314 if (loc_marker[cb] < loc_beg) {
315 loc_marker[cb] = loc_end;
316 S_loc.col[loc_end] = cb;
321 ptrdiff_t cb = rem_idx[gb];
323 if (rem_marker[cb] < rem_beg) {
324 rem_marker[cb] = rem_end;
325 S_rem.col[rem_end] = gb;
333 ARCCORE_ALINA_TOC(
"compute");
335 return std::make_shared<DistributedMatrix<bool_backend>>(A.comm(), s_loc, s_rem);
339 std::shared_ptr<DistributedMatrix<bool_backend>>
340 conn_strength(
const DistributedMatrix<B>& A, scalar_type eps_strong)
342 typedef typename B::value_type val_type;
343 typedef CSRMatrix<val_type> B_matrix;
345 ARCCORE_ALINA_TIC(
"conn_strength");
346 ptrdiff_t n = A.loc_rows();
348 const B_matrix& A_loc = *A.local();
349 const B_matrix& A_rem = *A.remote();
350 const CommunicationPattern<B>& C = A.cpat();
352 scalar_type eps_squared = eps_strong * eps_strong;
354 auto d = diagonal(A_loc);
355 numa_vector<val_type>& D = *d;
357 UniqueArray<val_type> D_loc(C.send.count());
358 UniqueArray<val_type> D_rem(C.recv.count());
360 for (
size_t i = 0, nv = C.send.count(); i < nv; ++i)
361 D_loc[i] = D[C.send.col[i]];
363 if (D_loc.size() != 0)
364 C.exchange(&D_loc[0], &D_rem[0]);
366 auto s_loc = std::make_shared<bool_matrix>();
367 auto s_rem = std::make_shared<bool_matrix>();
369 bool_matrix& S_loc = *s_loc;
370 bool_matrix& S_rem = *s_rem;
372 S_loc.set_size(n, n,
true);
373 S_rem.set_size(n, 0,
true);
375 S_loc.val.resize(A_loc.nbNonZero());
376 S_rem.val.resize(A_rem.nbNonZero());
379 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
380 val_type eps_dia_i = eps_squared * D[i];
382 for (ptrdiff_t j = A_loc.ptr[i], e = A_loc.ptr[i + 1]; j < e; ++j) {
383 ptrdiff_t c = A_loc.col[j];
384 val_type v = A_loc.val[j];
386 if ((S_loc.val[j] = (c == i || (eps_dia_i * D[c] < v * v))))
390 for (ptrdiff_t j = A_rem.ptr[i], e = A_rem.ptr[i + 1]; j < e; ++j) {
391 ptrdiff_t c = C.local_index(A_rem.col[j]);
392 val_type v = A_rem.val[j];
394 if ((S_rem.val[j] = (eps_dia_i * D_rem[c] < v * v)))
400 S_loc.setNbNonZero(S_loc.scan_row_sizes());
401 S_rem.setNbNonZero(S_rem.scan_row_sizes());
403 S_loc.col.resize(S_loc.nbNonZero());
404 S_rem.col.resize(S_rem.nbNonZero());
407 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
408 ptrdiff_t loc_head = S_loc.ptr[i];
409 ptrdiff_t rem_head = S_rem.ptr[i];
411 for (ptrdiff_t j = A_loc.ptr[i], e = A_loc.ptr[i + 1]; j < e; ++j)
413 S_loc.col[loc_head++] = A_loc.col[j];
415 for (ptrdiff_t j = A_rem.ptr[i], e = A_rem.ptr[i + 1]; j < e; ++j)
417 S_rem.col[rem_head++] = A_rem.col[j];
420 ARCCORE_ALINA_TOC(
"conn_strength");
422 return std::make_shared<DistributedMatrix<bool_backend>>(A.comm(), s_loc, s_rem);
425 ptrdiff_t aggregates(
const DistributedMatrix<bool_backend>& A,
426 UniqueArray<ptrdiff_t>& loc_state,
427 UniqueArray<int>& loc_owner)
429 ARCCORE_ALINA_TIC(
"PMIS");
430 static const int tag_exc_cnt = 4001;
431 static const int tag_exc_pts = 4002;
433 const bool_matrix& A_loc = *A.local();
434 const bool_matrix& A_rem = *A.remote();
436 ptrdiff_t n = A_loc.nbRow();
438 mpi_communicator comm = A.comm();
441 ARCCORE_ALINA_TIC(
"symbolic square");
442 auto S = squared_interface(A);
443 const bool_matrix& S_loc = *S->local();
444 const bool_matrix& S_rem = *S->remote();
445 const CommunicationPattern<bool_backend>& Sp = S->cpat();
446 ARCCORE_ALINA_TOC(
"symbolic square");
449 ptrdiff_t n_undone = 0;
450 UniqueArray<ptrdiff_t> rem_state(Sp.recv.count(), DistributedPMISAggregation::undone);
451 UniqueArray<int> rem_owner(Sp.recv.count(), -1);
452 UniqueArray<ptrdiff_t> send_state(Sp.send.count());
453 UniqueArray<int> send_owner(Sp.send.count());
456 std::atomic<ptrdiff_t> atomic_n_undone = 0;
458 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
459 ptrdiff_t wl = A_loc.ptr[i + 1] - A_loc.ptr[i];
460 ptrdiff_t wr = S_rem.ptr[i + 1] - S_rem.ptr[i];
463 loc_state[i] = DistributedPMISAggregation::deleted;
467 loc_state[i] = DistributedPMISAggregation::undone;
474 n_undone = n - atomic_n_undone;
477 for (ptrdiff_t i = 0, m = Sp.send.count(); i < m; ++i)
478 send_state[i] = loc_state[Sp.send.col[i]];
479 if (send_state.size() != 0)
480 Sp.exchange(&send_state[0], &rem_state[0]);
482 UniqueArray<UniqueArray<ptrdiff_t>> send_pts(Sp.recv.nbr.size());
483 UniqueArray<ptrdiff_t> recv_pts;
485 UniqueArray<MessagePassing::Request> send_cnt_req(Sp.recv.nbr.size());
486 UniqueArray<MessagePassing::Request> send_pts_req(Sp.recv.nbr.size());
490 UniqueArray<ptrdiff_t> nbr;
493 for (
size_t i = 0; i < Sp.recv.nbr.size(); ++i)
497 for (ptrdiff_t i = 0; i < n; ++i) {
498 if (loc_state[i] != DistributedPMISAggregation::undone)
501 if (S_rem.ptr[i + 1] > S_rem.ptr[i]) {
503 bool selectable =
true;
504 for (ptrdiff_t j = S_rem.ptr[i], e = S_rem.ptr[i + 1]; j < e; ++j) {
506 std::tie(d, c) = Sp.remote_info(S_rem.col[j]);
508 if (rem_state[c] == DistributedPMISAggregation::undone && Sp.recv.nbr[d] > comm.rank) {
517 ptrdiff_t
id = naggr++;
518 loc_owner[i] = comm.rank;
523 for (ptrdiff_t j = A_loc.ptr[i], e = A_loc.ptr[i + 1]; j < e; ++j) {
524 ptrdiff_t c = A_loc.col[j];
526 if (loc_state[c] == DistributedPMISAggregation::undone)
528 loc_owner[c] = comm.rank;
533 for (ptrdiff_t j = A_rem.ptr[i], e = A_rem.ptr[i + 1]; j < e; ++j) {
534 ptrdiff_t c = A_rem.col[j];
536 std::tie(d, k) = Sp.remote_info(c);
540 send_pts[d].push_back(c);
541 send_pts[d].push_back(
id);
545 for (ptrdiff_t j = S_loc.ptr[i], e = S_loc.ptr[i + 1]; j < e; ++j) {
546 ptrdiff_t c = S_loc.col[j];
547 if (c != i && loc_state[c] == DistributedPMISAggregation::undone) {
548 loc_owner[c] = comm.rank;
554 for (ptrdiff_t j = S_rem.ptr[i], e = S_rem.ptr[i + 1]; j < e; ++j) {
555 ptrdiff_t c = S_rem.col[j];
557 std::tie(d, k) = Sp.remote_info(c);
559 if (rem_state[k] == DistributedPMISAggregation::undone) {
561 send_pts[d].push_back(c);
562 send_pts[d].push_back(
id);
568 ptrdiff_t
id = naggr++;
569 loc_owner[i] = comm.rank;
575 for (ptrdiff_t j = A_loc.ptr[i], e = A_loc.ptr[i + 1]; j < e; ++j) {
576 ptrdiff_t c = A_loc.col[j];
578 if (c != i && loc_state[c] != DistributedPMISAggregation::deleted) {
579 if (loc_state[c] == DistributedPMISAggregation::undone)
581 loc_owner[c] = comm.rank;
587 for (ptrdiff_t k : nbr) {
588 for (ptrdiff_t j = A_loc.ptr[k], e = A_loc.ptr[k + 1]; j < e; ++j) {
589 ptrdiff_t c = A_loc.col[j];
590 if (c != k && loc_state[c] == DistributedPMISAggregation::undone) {
591 loc_owner[c] = comm.rank;
601 for (
size_t i = 0; i < Sp.recv.nbr.size(); ++i) {
602 int npts = send_pts[i].size();
603 send_cnt_req[i] = comm.doISend(&npts, 1, Sp.recv.nbr[i], tag_exc_cnt);
607 send_pts_req[i] = comm.doISend(&send_pts[i][0], npts, Sp.recv.nbr[i], tag_exc_pts);
610 for (
size_t i = 0; i < Sp.send.nbr.size(); ++i) {
612 comm.doReceive(&npts, 1, Sp.send.nbr[i], tag_exc_cnt);
616 recv_pts.resize(npts);
617 comm.doReceive(&recv_pts[0], npts, Sp.send.nbr[i], tag_exc_pts);
619 for (
int k = 0; k < npts; k += 2) {
620 ptrdiff_t c = recv_pts[k] - Sp.loc_col_shift();
621 ptrdiff_t
id = recv_pts[k + 1];
623 if (loc_state[c] == DistributedPMISAggregation::undone)
626 loc_owner[c] = Sp.send.nbr[i];
631 for (
size_t i = 0; i < Sp.recv.nbr.size(); ++i) {
632 int npts = send_pts[i].size();
633 comm.wait(send_cnt_req[i]);
636 comm.wait(send_pts_req[i]);
639 for (ptrdiff_t i = 0, m = Sp.send.count(); i < m; ++i)
640 send_state[i] = loc_state[Sp.send.col[i]];
641 if (send_state.size() != 0)
642 Sp.exchange(&send_state[0], &rem_state[0]);
644 if (0 == comm.reduceSum(n_undone))
650 ARCCORE_ALINA_TIC(
"drop empty aggregates");
651 for (ptrdiff_t i = 0, m = Sp.send.count(); i < m; ++i)
652 send_owner[i] = loc_owner[Sp.send.col[i]];
653 if (send_owner.size() != 0)
654 Sp.exchange(&send_owner[0], &rem_owner[0]);
656 UniqueArray<ptrdiff_t> new_id(naggr + 1, 0);
657 for (ptrdiff_t i = 0; i < n; ++i) {
658 if (loc_owner[i] == comm.rank && loc_state[i] >= 0)
659 new_id[loc_state[i] + 1] = 1;
662 for (
size_t i = 0; i < Sp.recv.count(); ++i) {
663 if (rem_owner[i] == comm.rank && rem_state[i] >= 0)
664 new_id[rem_state[i] + 1] = 1;
667 std::partial_sum(new_id.begin(), new_id.end(), new_id.begin());
669 if (comm.reduceSum(naggr - new_id.back()) > 0) {
670 naggr = new_id.back();
672 for (ptrdiff_t i = 0; i < n; ++i) {
673 if (loc_owner[i] == comm.rank && loc_state[i] >= 0) {
674 loc_state[i] = new_id[loc_state[i]];
678 for (
size_t i = 0; i < Sp.recv.nbr.size(); ++i) {
682 for (
auto p = Sp.remote_begin(); p != Sp.remote_end(); ++p) {
683 ptrdiff_t c = p->first;
686 std::tie(d, k) = p->second;
688 if (rem_owner[k] == comm.rank && rem_state[k] >= 0) {
689 send_pts[d].push_back(c);
690 send_pts[d].push_back(new_id[rem_state[k]]);
694 for (
size_t i = 0; i < Sp.recv.nbr.size(); ++i) {
695 int npts = send_pts[i].size();
696 send_cnt_req[i] = comm.doISend(&npts, 1, Sp.recv.nbr[i], tag_exc_cnt);
700 send_pts_req[i] = comm.doISend(&send_pts[i][0], npts, Sp.recv.nbr[i], tag_exc_pts);
703 for (
size_t i = 0; i < Sp.send.nbr.size(); ++i) {
705 comm.doReceive(&npts, 1, Sp.send.nbr[i], tag_exc_cnt);
709 recv_pts.resize(npts);
710 comm.doReceive(&recv_pts[0], npts, Sp.send.nbr[i], tag_exc_pts);
712 for (
int k = 0; k < npts; k += 2) {
713 ptrdiff_t c = recv_pts[k] - Sp.loc_col_shift();
714 ptrdiff_t
id = recv_pts[k + 1];
720 for (
size_t i = 0; i < Sp.recv.nbr.size(); ++i) {
721 int npts = send_pts[i].size();
722 comm.wait(send_cnt_req[i]);
725 comm.wait(send_pts_req[i]);
729 ARCCORE_ALINA_TOC(
"drop empty aggregates");
730 ARCCORE_ALINA_TOC(
"PMIS");
735 std::shared_ptr<matrix>
736 tentative_prolongation(mpi_communicator comm, ptrdiff_t n, ptrdiff_t naggr,
737 UniqueArray<ptrdiff_t>& state, UniqueArray<int>& owner)
739 auto p_loc = std::make_shared<build_matrix>();
740 auto p_rem = std::make_shared<build_matrix>();
741 build_matrix& P_loc = *p_loc;
742 build_matrix& P_rem = *p_rem;
744 ARCCORE_ALINA_TIC(
"tentative prolongation");
746 if (
int null_cols = prm.nullspace.cols) {
747 ptrdiff_t nba = naggr / prm.block_size;
749 UniqueArray<ptrdiff_t> fdom = comm.exclusive_sum(n);
750 UniqueArray<ptrdiff_t> cdom = comm.exclusive_sum(naggr);
752 UniqueArray<int> scounts(comm.size, 0);
753 UniqueArray<int> rcounts(comm.size);
758 P_loc.set_size(n, null_cols * nba,
true);
759 P_rem.set_size(n, 0,
true);
762 ptrdiff_t loc_dofs = 0;
764 for (ptrdiff_t i = 0; i < n; ++i) {
765 if (state[i] == DistributedPMISAggregation::deleted)
768 if (owner[i] == comm.rank) {
769 P_loc.ptr[i + 1] = null_cols;
773 P_rem.ptr[i + 1] = null_cols;
780 MPI_Ialltoall(scounts.data(), 1, MPI_INT,
781 rcounts.data(), 1, MPI_INT,
784 P_loc.set_nonzeros(P_loc.scan_row_sizes());
785 P_rem.set_nonzeros(P_rem.scan_row_sizes());
787 MPI_Wait(&req, MPI_STATUS_IGNORE);
791 for (
int i = 0; i < comm.size; ++i) {
798 UniqueArray<int> send_nbr;
799 send_nbr.reserve(snbr);
800 UniqueArray<int> recv_nbr;
801 recv_nbr.reserve(rnbr);
802 UniqueArray<int> send_ptr;
803 send_ptr.reserve(snbr + 1);
804 send_ptr.push_back(0);
805 UniqueArray<int> recv_ptr;
806 recv_ptr.reserve(rnbr + 1);
807 recv_ptr.push_back(0);
809 for (
int i = 0; i < comm.size; ++i) {
811 send_nbr.push_back(i);
812 send_ptr.push_back(send_ptr.back() + scounts[i]);
815 recv_nbr.push_back(i);
816 recv_ptr.push_back(recv_ptr.back() + rcounts[i]);
820 int send_dofs = send_ptr.back();
821 int recv_dofs = recv_ptr.back();
823 UniqueArray<ptrdiff_t> send_agg(send_dofs);
824 UniqueArray<ptrdiff_t> send_dof(send_dofs);
825 UniqueArray<double> send_row(send_dofs * null_cols);
827 UniqueArray<ptrdiff_t> recv_agg(recv_dofs);
828 UniqueArray<ptrdiff_t> recv_dof(recv_dofs);
829 UniqueArray<double> recv_row(recv_dofs * null_cols);
832 UniqueArray<ptrdiff_t> send_rank_ptr(comm.size + 1);
833 send_rank_ptr[0] = 0;
834 std::partial_sum(scounts.begin(), scounts.end(), send_rank_ptr.begin() + 1);
835 for (ptrdiff_t i = 0; i < n; ++i) {
839 if (s == DistributedPMISAggregation::deleted)
844 auto head = send_rank_ptr[o]++;
847 send_dof[head] = i + fdom[comm.rank];
848 std::copy_n(&prm.nullspace.B[i * null_cols], null_cols, &send_row[head * null_cols]);
852 UniqueArray<MessagePassing::Request> send_req(3 * snbr);
853 UniqueArray<MessagePassing::Request> recv_req(3 * rnbr);
855 for (
int i = 0; i < rnbr; ++i) {
858 int w = recv_ptr[i + 1] - p;
860 MessagePassing::Request* req = &recv_req[3 * i];
862 req[0] = comm.doIReceive(&recv_agg[p], w, n, tag_exc_agg);
863 req[1] = comm.doIReceive(&recv_dof[p], w, n, tag_exc_dof);
864 req[2] = comm.doIReceive(&recv_row[null_cols * p], null_cols * w, n, tag_exc_row);
867 for (
int i = 0; i < snbr; ++i) {
870 int w = send_ptr[i + 1] - p;
872 MessagePassing::Request* req = &send_req[3 * i];
874 req[0] = comm.doISend(&send_agg[p], w, n, tag_exc_agg);
875 req[1] = comm.doISend(&send_dof[p], w, n, tag_exc_dof);
876 req[2] = comm.doISend(&send_row[null_cols * p], null_cols * w, n, tag_exc_row);
879 ARCCORE_ALINA_TIC(
"MPI Wait");
880 comm.waitAll(recv_req);
881 comm.waitAll(send_req);
882 ARCCORE_ALINA_TOC(
"MPI Wait");
887 UniqueArray<std::tuple<ptrdiff_t, ptrdiff_t, double*, value_type*>> order;
888 order.reserve(loc_dofs + recv_dofs);
889 for (ptrdiff_t i = 0; i < n; ++i) {
893 if (s == DistributedPMISAggregation::deleted)
898 order.emplace_back(s / prm.block_size, i + fdom[comm.rank],
899 &prm.nullspace.B[i * null_cols], &P_loc.val[P_loc.ptr[i]]);
901 for (ptrdiff_t i = 0; i < recv_dofs; ++i) {
902 order.emplace_back(recv_agg[i] / prm.block_size, recv_dof[i],
903 &recv_row[i * null_cols],
nullptr);
905 std::sort(order.begin(), order.end());
907 UniqueArray<ptrdiff_t> aggr_ptr(nba + 1, 0);
908 for (
size_t i = 0; i < order.size(); ++i)
909 ++aggr_ptr[std::get<0>(order[i]) + 1];
910 std::partial_sum(aggr_ptr.begin(), aggr_ptr.end(), aggr_ptr.begin());
914 UniqueArray<double> Bnew;
915 Bnew.resize(nba * null_cols * null_cols);
918 Alina::detail::QRFactorization<double> qr;
919 UniqueArray<double> Bpart;
921 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
922 auto aggr_beg = aggr_ptr[i];
923 auto aggr_end = aggr_ptr[i + 1];
924 auto d = aggr_end - aggr_beg;
926 Bpart.resize(d * null_cols);
928 for (ptrdiff_t j = aggr_beg, r = 0; j < aggr_end; ++j, ++r) {
929 auto src = std::get<2>(order[j]);
930 for (
int c = 0; c < null_cols; ++c)
931 Bpart[r + d * c] = src[c];
934 qr.factorize(d, null_cols, &Bpart[0], Alina::detail::col_major);
936 for (ptrdiff_t r = 0, k = i * null_cols * null_cols; r < null_cols; ++r)
937 for (
int c = 0; c < null_cols; ++c, ++k)
938 Bnew[k] = qr.R(r, c);
940 for (ptrdiff_t j = aggr_beg, r = 0; j < aggr_end; ++j, ++r) {
941 auto src = std::get<2>(order[j]);
942 auto dst = std::get<3>(order[j]);
947 for (
int c = 0; c < null_cols; ++c)
948 dst[c] = qr.Q(r, c) * math::identity<value_type>();
951 for (
int c = 0; c < null_cols; ++c)
960 for (
int i = 0; i < snbr; ++i) {
963 int w = send_ptr[i + 1] - p;
964 send_req[i] = comm.doIReceive(&send_row[null_cols * p], null_cols * w, n, tag_exc_row);
967 for (
int i = 0; i < rnbr; ++i) {
970 int w = recv_ptr[i + 1] - p;
971 recv_req[i] = comm.doISend(&recv_row[null_cols * p], null_cols * w, n, tag_exc_row);
976 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
977 ptrdiff_t s = state[i];
978 if (s == DistributedPMISAggregation::deleted)
982 if (d == comm.rank) {
983 auto col = &P_loc.col[P_loc.ptr[i]];
984 for (
int j = 0; j < null_cols; ++j) {
985 col[j] = null_cols * s / prm.block_size + j;
989 auto col = &P_rem.col[P_rem.ptr[i]];
990 for (
int j = 0; j < null_cols; ++j) {
991 col[j] = null_cols * (s + cdom[d]) / prm.block_size + j;
997 ARCCORE_ALINA_TIC(
"MPI Wait");
998 comm.waitAll(send_req);
999 comm.waitAll(recv_req);
1000 ARCCORE_ALINA_TOC(
"MPI Wait");
1003 for (ptrdiff_t k = 0; k < send_dofs; ++k) {
1004 auto i = send_dof[k] - fdom[comm.rank];
1005 auto src = &send_row[k * null_cols];
1006 auto dst = &P_rem.val[P_rem.ptr[i]];
1008 for (ptrdiff_t j = 0; j < null_cols; ++j) {
1009 dst[j] = src[j] * math::identity<value_type>();
1013 std::swap(prm.nullspace.B, Bnew);
1016 UniqueArray<ptrdiff_t> dom = comm.exclusive_sum(naggr);
1018 P_loc.set_size(n, naggr,
true);
1019 P_rem.set_size(n, 0,
true);
1022 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
1023 if (state[i] == DistributedPMISAggregation::deleted)
1026 if (owner[i] == comm.rank) {
1035 P_loc.set_nonzeros(P_loc.scan_row_sizes());
1036 P_rem.set_nonzeros(P_rem.scan_row_sizes());
1039 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
1040 ptrdiff_t s = state[i];
1041 if (s == DistributedPMISAggregation::deleted)
1045 if (d == comm.rank) {
1046 P_loc.col[P_loc.ptr[i]] = s;
1047 P_loc.val[P_loc.ptr[i]] = math::identity<value_type>();
1050 P_rem.col[P_rem.ptr[i]] = s + dom[d];
1051 P_rem.val[P_rem.ptr[i]] = math::identity<value_type>();
1056 ARCCORE_ALINA_TOC(
"tentative prolongation");
1058 return std::make_shared<matrix>(comm, p_loc, p_rem);
1061 template <
class pw_matrix>
1062 std::shared_ptr<bool_matrix>
1063 expand_conn(
const build_matrix& A,
const pw_matrix& Ap,
const bool_matrix& Cp,
1064 unsigned block_size)
const
1066 ptrdiff_t np = Cp.nbRow();
1067 ptrdiff_t n = np * block_size;
1069 auto c = std::make_shared<bool_matrix>();
1070 bool_matrix& C = *c;
1072 C.set_size(n, n,
true);
1073 C.val.resize(A.nbNonZero());
1076 UniqueArray<ptrdiff_t> j(block_size);
1077 UniqueArray<ptrdiff_t> e(block_size);
1079 for (ptrdiff_t ip = begin; ip < (begin + size); ++ip) {
1080 ptrdiff_t ia = ip * block_size;
1082 for (
unsigned k = 0; k < block_size; ++k) {
1083 j[k] = A.ptr[ia + k];
1084 e[k] = A.ptr[ia + k + 1];
1087 for (ptrdiff_t jp = Ap.ptr[ip], ep = Ap.ptr[ip + 1]; jp < ep; ++jp) {
1088 ptrdiff_t cp = Ap.col[jp];
1089 bool sp = Cp.val[jp];
1091 ptrdiff_t col_end = (cp + 1) * block_size;
1093 for (
unsigned k = 0; k < block_size; ++k) {
1094 ptrdiff_t beg = j[k];
1095 ptrdiff_t end = e[k];
1097 while (beg < end && A.col[beg] < col_end) {
1101 ++C.ptr[ia + k + 1];
1110 C.setNbNonZero(C.scan_row_sizes());
1111 C.col.resize(C.nbNonZero());
1114 UniqueArray<ptrdiff_t> j(block_size);
1115 UniqueArray<ptrdiff_t> e(block_size);
1116 UniqueArray<ptrdiff_t> h(block_size);
1118 for (ptrdiff_t ip = begin; ip < (begin + size); ++ip) {
1119 ptrdiff_t ia = ip * block_size;
1121 for (
unsigned k = 0; k < block_size; ++k) {
1122 j[k] = A.ptr[ia + k];
1123 e[k] = A.ptr[ia + k + 1];
1124 h[k] = C.ptr[ia + k];
1127 for (ptrdiff_t jp = Ap.ptr[ip], ep = Ap.ptr[ip + 1]; jp < ep; ++jp) {
1128 ptrdiff_t cp = Ap.col[jp];
1129 bool sp = Cp.val[jp];
1131 ptrdiff_t col_end = (cp + 1) * block_size;
1133 for (
unsigned k = 0; k < block_size; ++k) {
1134 ptrdiff_t beg = j[k];
1135 ptrdiff_t end = e[k];
1136 ptrdiff_t hed = h[k];
1138 while (beg < end && A.col[beg] < col_end) {
1140 C.col[hed++] = A.col[beg];
1156 static const int undone = -2;
1157 static const int deleted = -1;
1159 static const int tag_exc_agg = 4011;
1160 static const int tag_exc_dof = 4012;
1161 static const int tag_exc_row = 4013;