129class DistributedSubDomainDeflation
133 typedef typename LocalPrecond::backend_type backend_type;
134 typedef typename backend_type::params backend_params;
138 typename LocalPrecond::params local;
139 typename IterativeSolver::params isolver;
140 typename DirectSolver::params dsolver;
143 Int32 num_def_vec = 0;
146 std::function<double(ptrdiff_t,
unsigned)> def_vec;
151 : ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p, local)
152 , ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p, isolver)
153 , ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p, dsolver)
154 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, num_def_vec)
157 ptr = p.get(
"def_vec", ptr);
159 precondition(ptr,
"Error in subdomain_deflation parameters: def_vec is not set");
161 def_vec = *
static_cast<std::function<
double(ptrdiff_t,
unsigned)
>*>(ptr);
163 p.check_params({
"local",
"isolver",
"dsolver",
"num_def_vec",
"def_vec" });
166 void get(
PropertyTree& p,
const std::string& path)
const
168 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, local);
169 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, isolver);
170 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, dsolver);
171 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, num_def_vec);
175 typedef typename backend_type::value_type value_type;
176 typedef typename math::scalar_of<value_type>::type scalar_type;
177 typedef typename backend_type::matrix bmatrix;
178 using col_type = backend_type::col_type;
179 using ptr_type = backend_type::ptr_type;
180 typedef typename backend_type::vector vector;
183 template <
class Matrix>
187 const backend_params& bprm = backend_params())
189 , nrows(backend::nbRow(Astrip))
190 , ndv(prm.num_def_vec)
191 , dv_start(comm.size + 1, 0)
193 , q(backend_type::create_vector(nrows, bprm))
196 A = std::make_shared<matrix>(comm, Astrip, nrows);
201 std::shared_ptr<matrix> A,
203 const backend_params& bprm = backend_params())
205 , nrows(A->loc_rows())
206 , ndv(prm.num_def_vec)
208 , dv_start(comm.size + 1, 0)
210 , q(backend_type::create_vector(nrows, bprm))
216 void init(
const params& prm = params(),
217 const backend_params& bprm = backend_params())
219 ARCCORE_ALINA_TIC(
"setup deflation");
220 using build_matrix = CSRMatrix<value_type, col_type, ptr_type>;
223 std::vector<ptrdiff_t> dv_size(comm.size);
229 mpAllGather(comm.m_message_passing_mng.get(), send_buf, receive_buf);
232 std::partial_sum(dv_size.begin(), dv_size.end(), dv_start.begin() + 1);
233 nz = dv_start.back();
237 dd = backend_type::create_vector(ndv, bprm);
239 auto az_loc = std::make_shared<build_matrix>();
240 auto az_rem = std::make_shared<build_matrix>();
242 auto a_loc = A->local();
243 auto a_rem = A->remote();
245 const CommunicationPattern<backend_type>& Acp = A->cpat();
248 ARCCORE_ALINA_TIC(
"copy deflation vectors");
250 std::vector<value_type> z(nrows);
251 for (
int j = 0; j < ndv; ++j) {
253 for (ptrdiff_t i = begin; i < (begin + size); ++i)
254 z[i] = prm.def_vec(i, j);
256 Z[j] = backend_type::copy_vector(z, bprm);
259 ARCCORE_ALINA_TOC(
"copy deflation vectors");
261 ARCCORE_ALINA_TIC(
"first pass");
262 az_loc->set_size(nrows, ndv,
true);
263 az_loc->set_nonzeros(nrows * dv_size[comm.rank]);
264 az_rem->set_size(nrows, 0,
true);
268 std::vector<ptrdiff_t> marker(Acp.recv.nbr.size(), -1);
270 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
271 ptrdiff_t az_loc_head = i * ndv;
272 az_loc->ptr[i + 1] = az_loc_head + ndv;
274 for (ptrdiff_t j = 0; j < ndv; ++j) {
275 az_loc->col[az_loc_head + j] = j;
276 az_loc->val[az_loc_head + j] = math::zero<value_type>();
279 for (ptrdiff_t j = a_loc->ptr[i], e = a_loc->ptr[i + 1]; j < e; ++j) {
280 ptrdiff_t c = a_loc->col[j];
281 value_type v = a_loc->val[j];
283 for (ptrdiff_t j = 0; j < ndv; ++j)
284 az_loc->val[az_loc_head + j] += v * prm.def_vec(c, j);
287 for (ptrdiff_t j = a_rem->ptr[i], e = a_rem->ptr[i + 1]; j < e; ++j) {
288 int d = Acp.domain(a_rem->col[j]);
290 if (marker[d] != i) {
292 az_rem->ptr[i + 1] += dv_size[d];
298 az_rem->set_nonzeros(az_rem->scan_row_sizes());
299 ARCCORE_ALINA_TOC(
"first pass");
302 ARCCORE_ALINA_TIC(
"local preconditioner");
303 P = std::make_shared<LocalPrecond>(*a_loc, prm.local, bprm);
304 ARCCORE_ALINA_TOC(
"local preconditioner");
306 A->set_local(P->system_matrix_ptr());
307 A->move_to_backend(bprm);
309 ARCCORE_ALINA_TIC(
"remote(A*Z)");
312 std::vector<ptrdiff_t> zrecv_ptr(Acp.recv.nbr.size() + 1, 0);
313 std::vector<ptrdiff_t> zcol_ptr;
314 zcol_ptr.reserve(Acp.recv.count() + 1);
315 zcol_ptr.push_back(0);
317 for (
size_t i = 0; i < Acp.recv.nbr.size(); ++i) {
318 ptrdiff_t ncols = Acp.recv.ptr[i + 1] - Acp.recv.ptr[i];
319 ptrdiff_t nvecs = dv_size[Acp.recv.nbr[i]];
320 ptrdiff_t size = nvecs * ncols;
321 zrecv_ptr[i + 1] = zrecv_ptr[i] + size;
323 for (ptrdiff_t j = 0; j < ncols; ++j)
324 zcol_ptr.push_back(zcol_ptr.back() + nvecs);
327 std::vector<value_type> zrecv(zrecv_ptr.back());
328 std::vector<value_type> zsend(Acp.send.count() * ndv);
330 for (
size_t i = 0; i < Acp.recv.nbr.size(); ++i) {
331 ptrdiff_t begin = zrecv_ptr[i];
332 ptrdiff_t size = zrecv_ptr[i + 1] - begin;
334 Acp.recv.req[i] = comm.doIReceive(&zrecv[begin], size, Acp.recv.nbr[i], tag_exc_vals);
337 for (
size_t i = 0, k = 0; i < Acp.send.count(); ++i)
338 for (ptrdiff_t j = 0; j < ndv; ++j, ++k)
339 zsend[k] = prm.def_vec(Acp.send.col[i], j);
341 for (
size_t i = 0; i < Acp.send.nbr.size(); ++i)
342 Acp.send.req[i] = comm.doISend(&zsend[ndv * Acp.send.ptr[i]], ndv * (Acp.send.ptr[i + 1] - Acp.send.ptr[i]),
343 Acp.send.nbr[i], tag_exc_vals);
345 comm.waitAll(Acp.recv.req);
346 comm.waitAll(Acp.send.req);
349 std::vector<ptrdiff_t> marker(nz, -1);
352 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
353 ptrdiff_t az_rem_head = az_rem->ptr[i];
354 ptrdiff_t az_rem_tail = az_rem_head;
356 for (
auto a = backend::row_begin(*a_rem, i); a; ++a) {
357 ptrdiff_t c = a.col();
358 value_type v = a.value();
361 ptrdiff_t d = Acp.recv.nbr[std::upper_bound(Acp.recv.ptr.begin(), Acp.recv.ptr.end(), c) -
362 Acp.recv.ptr.begin() - 1];
364 value_type* zval = &zrecv[zcol_ptr[c]];
365 for (ptrdiff_t j = 0, k = dv_start[d]; j < dv_size[d]; ++j, ++k) {
366 if (marker[k] < az_rem_head) {
367 marker[k] = az_rem_tail;
368 az_rem->col[az_rem_tail] = k;
369 az_rem->val[az_rem_tail] = v * zval[j];
373 az_rem->val[marker[k]] += v * zval[j];
379 ARCCORE_ALINA_TOC(
"remote(A*Z)");
382 ARCCORE_ALINA_TIC(
"assemble E");
385 std::vector<int> nbrs;
386 nbrs.reserve(1 + Acp.send.nbr.size() + Acp.recv.nbr.size());
388 Acp.send.nbr.begin(), Acp.send.nbr.end(),
389 Acp.recv.nbr.begin(), Acp.recv.nbr.end(),
390 std::back_inserter(nbrs));
391 nbrs.push_back(comm.rank);
394 E.set_size(ndv, nz,
false);
400 for (
int k = 0; k <= ndv; ++k)
403 E.setNbNonZero(E.ptr[ndv]);
404 E.set_nonzeros(E.ptr[ndv]);
408 multi_array<value_type, 3> erow(nthreads, ndv, nz);
409 std::fill_n(erow.data(), erow.size(), 0);
412 ptrdiff_t dv_offset = dv_start[comm.rank];
415 std::vector<value_type> z(ndv);
417 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
418 for (ptrdiff_t j = 0; j < ndv; ++j)
419 z[j] = prm.def_vec(i, j);
421 for (ptrdiff_t k = az_loc->ptr[i], e = az_loc->ptr[i + 1]; k < e; ++k) {
422 ptrdiff_t c = az_loc->col[k] + dv_offset;
423 value_type v = az_loc->val[k];
425 for (ptrdiff_t j = 0; j < ndv; ++j)
426 erow(tid, j, c) += v * z[j];
429 for (ptrdiff_t k = az_rem->ptr[i], e = az_rem->ptr[i + 1]; k < e; ++k) {
430 ptrdiff_t c = az_rem->col[k];
431 value_type v = az_rem->val[k];
433 for (ptrdiff_t j = 0; j < ndv; ++j)
434 erow(tid, j, c) += v * z[j];
440 for (
int i = 0; i < ndv; ++i) {
441 int row_head = E.ptr[i];
443 for (
int k = 0; k < dv_size[j]; ++k) {
444 int c = dv_start[j] + k;
445 value_type v = math::zero<value_type>();
446 for (
int t = 0; t < nthreads; ++t)
456 ARCCORE_ALINA_TOC(
"assemble E");
458 ARCCORE_ALINA_TIC(
"factorize E");
459 this->E = std::make_shared<DirectSolver>(comm, E, prm.dsolver);
460 ARCCORE_ALINA_TOC(
"factorize E");
462 ARCCORE_ALINA_TIC(
"finish(A*Z)");
463 AZ = std::make_shared<matrix>(comm, az_loc, az_rem);
464 AZ->move_to_backend(bprm);
465 ARCCORE_ALINA_TOC(
"finish(A*Z)");
466 ARCCORE_ALINA_TOC(
"setup deflation");
469 template <
class Vec1,
class Vec2>
470 void apply(
const Vec1& rhs, Vec2&& x)
const
475 std::tie(iters, error) = (*this)(rhs, x);
478 std::shared_ptr<matrix> system_matrix_ptr()
const
483 const matrix& system_matrix()
const
488 template <
class Matrix,
class Vec1,
class Vec2>
489 std::tuple<size_t, value_type> operator()(
490 const Matrix& A,
const Vec1& rhs, Vec2&& x)
const
492 std::tuple<size_t, value_type> cnv = S(make_sdd_projected_matrix(*
this, A), *P, rhs, x);
497 template <
class Vec1,
class Vec2>
498 std::tuple<size_t, value_type>
499 operator()(
const Vec1& rhs, Vec2&& x)
const
501 std::tuple<size_t, value_type> cnv = S(make_sdd_projected_matrix(*
this, *A), *P, rhs, x);
511 template <
class Vector>
512 void project(Vector& x)
const
514 const auto one = math::identity<scalar_type>();
516 ARCCORE_ALINA_TIC(
"project");
518 ARCCORE_ALINA_TIC(
"local inner product");
519 for (ptrdiff_t j = 0; j < ndv; ++j)
520 df[j] = backend::inner_product(x, *Z[j]);
521 ARCCORE_ALINA_TOC(
"local inner product");
523 coarse_solve(df, dx);
525 ARCCORE_ALINA_TIC(
"spmv");
526 backend::copy(dx, *dd);
527 backend::spmv(-one, *AZ, *dd, one, x);
528 ARCCORE_ALINA_TOC(
"spmv");
530 ARCCORE_ALINA_TOC(
"project");
535 static const int tag_exc_vals = 2011;
536 static const int tag_exc_dmat = 3011;
537 static const int tag_exc_dvec = 4011;
538 static const int tag_exc_lnnz = 5011;
540 mpi_communicator comm;
541 ptrdiff_t nrows, ndv, nz;
543 std::shared_ptr<matrix> A, AZ;
544 std::shared_ptr<LocalPrecond> P;
546 mutable std::vector<value_type> df, dx;
547 std::vector<ptrdiff_t> dv_start;
549 std::vector<std::shared_ptr<vector>> Z;
551 std::shared_ptr<DirectSolver> E;
553 std::shared_ptr<vector> q;
554 std::shared_ptr<vector> dd;
558 void coarse_solve(std::vector<value_type>& f, std::vector<value_type>& x)
const
560 ARCCORE_ALINA_TIC(
"coarse solve");
562 ARCCORE_ALINA_TOC(
"coarse solve");
565 template <
class Vec1,
class Vec2>
566 void postprocess(
const Vec1& rhs, Vec2& x)
const
568 const auto one = math::identity<scalar_type>();
570 ARCCORE_ALINA_TIC(
"postprocess");
573 backend::copy(rhs, *q);
574 backend::spmv(-one, *A, x, one, *q);
577 ARCCORE_ALINA_TIC(
"local inner product");
578 for (ptrdiff_t j = 0; j < ndv; ++j)
579 df[j] = backend::inner_product(*q, *Z[j]);
580 ARCCORE_ALINA_TOC(
"local inner product");
583 coarse_solve(df, dx);
586 backend::lin_comb(ndv, dx, Z, one, x);
588 ARCCORE_ALINA_TOC(
"postprocess");