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>
184 DistributedSubDomainDeflation(
const AlinaContext& context,
188 const backend_params& bprm = backend_params())
190 , nrows(backend::nbRow(Astrip))
191 , ndv(prm.num_def_vec)
192 , dv_start(comm.size + 1, 0)
194 , q(backend_type::create_vector(nrows, bprm))
197 A = std::make_shared<matrix>(comm, Astrip, nrows);
198 init(context, prm, bprm);
203 std::shared_ptr<matrix> A,
205 const backend_params& bprm = backend_params())
207 , nrows(A->loc_rows())
208 , ndv(prm.num_def_vec)
210 , dv_start(comm.size + 1, 0)
212 , q(backend_type::create_vector(nrows, bprm))
215 init(context, prm, bprm);
218 void init(
const AlinaContext& context,
219 const params& prm = params(),
220 const backend_params& bprm = backend_params())
222 ARCCORE_ALINA_TIC(
"setup deflation");
223 using build_matrix = CSRMatrix<value_type, col_type, ptr_type>;
226 std::vector<ptrdiff_t> dv_size(comm.size);
232 mpAllGather(comm.m_message_passing_mng.get(), send_buf, receive_buf);
235 std::partial_sum(dv_size.begin(), dv_size.end(), dv_start.begin() + 1);
236 nz = dv_start.back();
240 dd = backend_type::create_vector(ndv, bprm);
242 auto az_loc = std::make_shared<build_matrix>();
243 auto az_rem = std::make_shared<build_matrix>();
245 auto a_loc = A->local();
246 auto a_rem = A->remote();
248 const CommunicationPattern<backend_type>& Acp = A->cpat();
251 ARCCORE_ALINA_TIC(
"copy deflation vectors");
253 std::vector<value_type> z(nrows);
254 for (
int j = 0; j < ndv; ++j) {
256 for (ptrdiff_t i = begin; i < (begin + size); ++i)
257 z[i] = prm.def_vec(i, j);
259 Z[j] = backend_type::copy_vector(z, bprm);
262 ARCCORE_ALINA_TOC(
"copy deflation vectors");
264 ARCCORE_ALINA_TIC(
"first pass");
265 az_loc->set_size(nrows, ndv,
true);
266 az_loc->set_nonzeros(nrows * dv_size[comm.rank]);
267 az_rem->set_size(nrows, 0,
true);
271 std::vector<ptrdiff_t> marker(Acp.recv.nbr.size(), -1);
273 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
274 ptrdiff_t az_loc_head = i * ndv;
275 az_loc->ptr[i + 1] = az_loc_head + ndv;
277 for (ptrdiff_t j = 0; j < ndv; ++j) {
278 az_loc->col[az_loc_head + j] = j;
279 az_loc->val[az_loc_head + j] = math::zero<value_type>();
282 for (ptrdiff_t j = a_loc->ptr[i], e = a_loc->ptr[i + 1]; j < e; ++j) {
283 ptrdiff_t c = a_loc->col[j];
284 value_type v = a_loc->val[j];
286 for (ptrdiff_t j = 0; j < ndv; ++j)
287 az_loc->val[az_loc_head + j] += v * prm.def_vec(c, j);
290 for (ptrdiff_t j = a_rem->ptr[i], e = a_rem->ptr[i + 1]; j < e; ++j) {
291 int d = Acp.domain(a_rem->col[j]);
293 if (marker[d] != i) {
295 az_rem->ptr[i + 1] += dv_size[d];
301 az_rem->set_nonzeros(az_rem->scan_row_sizes());
302 ARCCORE_ALINA_TOC(
"first pass");
305 ARCCORE_ALINA_TIC(
"local preconditioner");
306 P = std::make_shared<LocalPrecond>(context, *a_loc, prm.local, bprm);
307 ARCCORE_ALINA_TOC(
"local preconditioner");
309 A->set_local(P->system_matrix_ptr());
310 A->move_to_backend(bprm);
312 ARCCORE_ALINA_TIC(
"remote(A*Z)");
315 std::vector<ptrdiff_t> zrecv_ptr(Acp.recv.nbr.size() + 1, 0);
316 std::vector<ptrdiff_t> zcol_ptr;
317 zcol_ptr.reserve(Acp.recv.count() + 1);
318 zcol_ptr.push_back(0);
320 for (
size_t i = 0; i < Acp.recv.nbr.size(); ++i) {
321 ptrdiff_t ncols = Acp.recv.ptr[i + 1] - Acp.recv.ptr[i];
322 ptrdiff_t nvecs = dv_size[Acp.recv.nbr[i]];
323 ptrdiff_t size = nvecs * ncols;
324 zrecv_ptr[i + 1] = zrecv_ptr[i] + size;
326 for (ptrdiff_t j = 0; j < ncols; ++j)
327 zcol_ptr.push_back(zcol_ptr.back() + nvecs);
330 std::vector<value_type> zrecv(zrecv_ptr.back());
331 std::vector<value_type> zsend(Acp.send.count() * ndv);
333 for (
size_t i = 0; i < Acp.recv.nbr.size(); ++i) {
334 ptrdiff_t begin = zrecv_ptr[i];
335 ptrdiff_t size = zrecv_ptr[i + 1] - begin;
337 Acp.recv.req[i] = comm.doIReceive(&zrecv[begin], size, Acp.recv.nbr[i], tag_exc_vals);
340 for (
size_t i = 0, k = 0; i < Acp.send.count(); ++i)
341 for (ptrdiff_t j = 0; j < ndv; ++j, ++k)
342 zsend[k] = prm.def_vec(Acp.send.col[i], j);
344 for (
size_t i = 0; i < Acp.send.nbr.size(); ++i)
345 Acp.send.req[i] = comm.doISend(&zsend[ndv * Acp.send.ptr[i]], ndv * (Acp.send.ptr[i + 1] - Acp.send.ptr[i]),
346 Acp.send.nbr[i], tag_exc_vals);
348 comm.waitAll(Acp.recv.req);
349 comm.waitAll(Acp.send.req);
352 std::vector<ptrdiff_t> marker(nz, -1);
355 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
356 ptrdiff_t az_rem_head = az_rem->ptr[i];
357 ptrdiff_t az_rem_tail = az_rem_head;
359 for (
auto a = backend::row_begin(*a_rem, i); a; ++a) {
360 ptrdiff_t c = a.col();
361 value_type v = a.value();
364 ptrdiff_t d = Acp.recv.nbr[std::upper_bound(Acp.recv.ptr.begin(), Acp.recv.ptr.end(), c) -
365 Acp.recv.ptr.begin() - 1];
367 value_type* zval = &zrecv[zcol_ptr[c]];
368 for (ptrdiff_t j = 0, k = dv_start[d]; j < dv_size[d]; ++j, ++k) {
369 if (marker[k] < az_rem_head) {
370 marker[k] = az_rem_tail;
371 az_rem->col[az_rem_tail] = k;
372 az_rem->val[az_rem_tail] = v * zval[j];
376 az_rem->val[marker[k]] += v * zval[j];
382 ARCCORE_ALINA_TOC(
"remote(A*Z)");
385 ARCCORE_ALINA_TIC(
"assemble E");
388 std::vector<int> nbrs;
389 nbrs.reserve(1 + Acp.send.nbr.size() + Acp.recv.nbr.size());
391 Acp.send.nbr.begin(), Acp.send.nbr.end(),
392 Acp.recv.nbr.begin(), Acp.recv.nbr.end(),
393 std::back_inserter(nbrs));
394 nbrs.push_back(comm.rank);
397 E.set_size(ndv, nz,
false);
403 for (
int k = 0; k <= ndv; ++k)
406 E.setNbNonZero(E.ptr[ndv]);
407 E.set_nonzeros(E.ptr[ndv]);
411 multi_array<value_type, 3> erow(nthreads, ndv, nz);
412 std::fill_n(erow.data(), erow.size(), 0);
415 ptrdiff_t dv_offset = dv_start[comm.rank];
418 std::vector<value_type> z(ndv);
420 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
421 for (ptrdiff_t j = 0; j < ndv; ++j)
422 z[j] = prm.def_vec(i, j);
424 for (ptrdiff_t k = az_loc->ptr[i], e = az_loc->ptr[i + 1]; k < e; ++k) {
425 ptrdiff_t c = az_loc->col[k] + dv_offset;
426 value_type v = az_loc->val[k];
428 for (ptrdiff_t j = 0; j < ndv; ++j)
429 erow(tid, j, c) += v * z[j];
432 for (ptrdiff_t k = az_rem->ptr[i], e = az_rem->ptr[i + 1]; k < e; ++k) {
433 ptrdiff_t c = az_rem->col[k];
434 value_type v = az_rem->val[k];
436 for (ptrdiff_t j = 0; j < ndv; ++j)
437 erow(tid, j, c) += v * z[j];
443 for (
int i = 0; i < ndv; ++i) {
444 int row_head = E.ptr[i];
446 for (
int k = 0; k < dv_size[j]; ++k) {
447 int c = dv_start[j] + k;
448 value_type v = math::zero<value_type>();
449 for (
int t = 0; t < nthreads; ++t)
459 ARCCORE_ALINA_TOC(
"assemble E");
461 ARCCORE_ALINA_TIC(
"factorize E");
462 this->E = std::make_shared<DirectSolver>(comm, E, prm.dsolver);
463 ARCCORE_ALINA_TOC(
"factorize E");
465 ARCCORE_ALINA_TIC(
"finish(A*Z)");
466 AZ = std::make_shared<matrix>(comm, az_loc, az_rem);
467 AZ->move_to_backend(bprm);
468 ARCCORE_ALINA_TOC(
"finish(A*Z)");
469 ARCCORE_ALINA_TOC(
"setup deflation");
472 template <
class Vec1,
class Vec2>
473 void apply(
const Vec1& rhs, Vec2&& x)
const
478 std::tie(iters, error) = (*this)(rhs, x);
481 std::shared_ptr<matrix> system_matrix_ptr()
const
486 const matrix& system_matrix()
const
491 template <
class Matrix,
class Vec1,
class Vec2>
492 std::tuple<size_t, value_type> operator()(
493 const Matrix& A,
const Vec1& rhs, Vec2&& x)
const
495 std::tuple<size_t, value_type> cnv = S(make_sdd_projected_matrix(*
this, A), *P, rhs, x);
500 template <
class Vec1,
class Vec2>
501 std::tuple<size_t, value_type>
502 operator()(
const Vec1& rhs, Vec2&& x)
const
504 std::tuple<size_t, value_type> cnv = S(make_sdd_projected_matrix(*
this, *A), *P, rhs, x);
514 template <
class Vector>
515 void project(Vector& x)
const
517 const auto one = math::identity<scalar_type>();
519 ARCCORE_ALINA_TIC(
"project");
521 ARCCORE_ALINA_TIC(
"local inner product");
522 for (ptrdiff_t j = 0; j < ndv; ++j)
523 df[j] = backend::inner_product(x, *Z[j]);
524 ARCCORE_ALINA_TOC(
"local inner product");
526 coarse_solve(df, dx);
528 ARCCORE_ALINA_TIC(
"spmv");
529 backend::copy(dx, *dd);
530 backend::spmv(-one, *AZ, *dd, one, x);
531 ARCCORE_ALINA_TOC(
"spmv");
533 ARCCORE_ALINA_TOC(
"project");
538 static const int tag_exc_vals = 2011;
539 static const int tag_exc_dmat = 3011;
540 static const int tag_exc_dvec = 4011;
541 static const int tag_exc_lnnz = 5011;
543 AlinaCommunicator comm;
544 ptrdiff_t nrows, ndv, nz;
546 std::shared_ptr<matrix> A, AZ;
547 std::shared_ptr<LocalPrecond> P;
549 mutable std::vector<value_type> df, dx;
550 std::vector<ptrdiff_t> dv_start;
552 std::vector<std::shared_ptr<vector>> Z;
554 std::shared_ptr<DirectSolver> E;
556 std::shared_ptr<vector> q;
557 std::shared_ptr<vector> dd;
561 void coarse_solve(std::vector<value_type>& f, std::vector<value_type>& x)
const
563 ARCCORE_ALINA_TIC(
"coarse solve");
565 ARCCORE_ALINA_TOC(
"coarse solve");
568 template <
class Vec1,
class Vec2>
569 void postprocess(
const Vec1& rhs, Vec2& x)
const
571 const auto one = math::identity<scalar_type>();
573 ARCCORE_ALINA_TIC(
"postprocess");
576 backend::copy(rhs, *q);
577 backend::spmv(-one, *A, x, one, *q);
580 ARCCORE_ALINA_TIC(
"local inner product");
581 for (ptrdiff_t j = 0; j < ndv; ++j)
582 df[j] = backend::inner_product(*q, *Z[j]);
583 ARCCORE_ALINA_TOC(
"local inner product");
586 coarse_solve(df, dx);
589 backend::lin_comb(ndv, dx, Z, one, x);
591 ARCCORE_ALINA_TOC(
"postprocess");