Arcane  4.2.1.0
Developer documentation
Loading...
Searching...
No Matches
DistributedSubDomainDeflation.h
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* DistributedSubDomainDeflation.h (C) 2000-2026 */
9/* */
10/* Distributed solver based on subdomain deflation. */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCCORE_ALINA_DISTRIBUTEDSUBDOMAINDEFLATION_H
13#define ARCCORE_ALINA_DISTRIBUTEDSUBDOMAINDEFLATION_H
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16/*
17 * This file is based on the work on AMGCL library (version march 2026)
18 * which can be found at https://github.com/ddemidov/amgcl.
19 *
20 * Copyright (c) 2012-2022 Denis Demidov <dennis.demidov@gmail.com>
21 * SPDX-License-Identifier: MIT
22 */
23/*---------------------------------------------------------------------------*/
24/*---------------------------------------------------------------------------*/
25
26#include "arccore/alina/BuiltinBackend.h"
27#include "arccore/alina/Adapters.h"
28#include "arccore/alina/MessagePassingUtils.h"
29#include "arccore/alina/DistributedSkylineLUDirectSolver.h"
30#include "arccore/alina/DistributedInnerProduct.h"
31#include "arccore/alina/DistributedMatrix.h"
32
33#include <vector>
34#include <algorithm>
35#include <numeric>
36#include <memory>
37#include <functional>
38
39/*---------------------------------------------------------------------------*/
40/*---------------------------------------------------------------------------*/
41
42namespace Arcane::Alina
43{
44
45/*---------------------------------------------------------------------------*/
46/*---------------------------------------------------------------------------*/
47
50{
51 const int block_size;
57 constant_deflation(int block_size = 1)
58 : block_size(block_size)
59 {}
60
61 int dim() const
62 {
63 return block_size;
64 }
65
66 int operator()(ptrdiff_t row, int j) const
67 {
68 return row % block_size == j;
69 }
70};
71
72/*---------------------------------------------------------------------------*/
73/*---------------------------------------------------------------------------*/
74
75template <class SDD, class Matrix>
76struct sdd_projected_matrix
77{
78 typedef typename SDD::value_type value_type;
79
80 const SDD& S;
81 const Matrix& A;
82
83 sdd_projected_matrix(const SDD& S, const Matrix& A)
84 : S(S)
85 , A(A)
86 {}
87
88 template <class T, class Vec1, class Vec2>
89 void mul(T alpha, const Vec1& x, T beta, Vec2& y) const
90 {
91 ARCCORE_ALINA_TIC("top/spmv");
92 backend::spmv(alpha, A, x, beta, y);
93 ARCCORE_ALINA_TOC("top/spmv");
94
95 S.project(y);
96 }
97
98 template <class Vec1, class Vec2, class Vec3>
99 void residual(const Vec1& f, const Vec2& x, Vec3& r) const
100 {
101 ARCCORE_ALINA_TIC("top/residual");
102 backend::residual(f, A, x, r);
103 ARCCORE_ALINA_TOC("top/residual");
104
105 S.project(r);
106 }
107};
108
109/*---------------------------------------------------------------------------*/
110/*---------------------------------------------------------------------------*/
111
112template <class SDD, class Matrix>
113sdd_projected_matrix<SDD, Matrix> make_sdd_projected_matrix(const SDD& S, const Matrix& A)
114{
116}
117
118/*---------------------------------------------------------------------------*/
119/*---------------------------------------------------------------------------*/
120
126template <class LocalPrecond,
127 class IterativeSolver,
128 class DirectSolver = DistributedSkylineLUDirectSolver<typename LocalPrecond::backend_type>>
129class DistributedSubDomainDeflation
130{
131 public:
132
133 typedef typename LocalPrecond::backend_type backend_type;
134 typedef typename backend_type::params backend_params;
135
136 struct params
137 {
138 typename LocalPrecond::params local;
139 typename IterativeSolver::params isolver;
140 typename DirectSolver::params dsolver;
141
142 // Number of deflation vectors.
143 Int32 num_def_vec = 0;
144
145 // Value of deflation vector at the given row and column.
146 std::function<double(ptrdiff_t, unsigned)> def_vec;
147
148 params() {}
149
150 params(const PropertyTree& p)
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)
155 {
156 void* ptr = 0;
157 ptr = p.get("def_vec", ptr);
158
159 precondition(ptr, "Error in subdomain_deflation parameters: def_vec is not set");
160
161 def_vec = *static_cast<std::function<double(ptrdiff_t, unsigned)>*>(ptr);
162
163 p.check_params({ "local", "isolver", "dsolver", "num_def_vec", "def_vec" });
164 }
165
166 void get(PropertyTree& p, const std::string& path) const
167 {
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);
172 }
173 };
174
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;
181 typedef DistributedMatrix<backend_type> matrix;
182
183 template <class Matrix>
184 DistributedSubDomainDeflation(mpi_communicator comm,
185 const Matrix& Astrip,
186 const params& prm = params(),
187 const backend_params& bprm = backend_params())
188 : comm(comm)
189 , nrows(backend::nbRow(Astrip))
190 , ndv(prm.num_def_vec)
191 , dv_start(comm.size + 1, 0)
192 , Z(ndv)
193 , q(backend_type::create_vector(nrows, bprm))
194 , S(nrows, prm.isolver, bprm, DistributedInnerProduct(comm))
195 {
196 A = std::make_shared<matrix>(comm, Astrip, nrows);
197 init(prm, bprm);
198 }
199
201 std::shared_ptr<matrix> A,
202 const params& prm = params(),
203 const backend_params& bprm = backend_params())
204 : comm(comm)
205 , nrows(A->loc_rows())
206 , ndv(prm.num_def_vec)
207 , A(A)
208 , dv_start(comm.size + 1, 0)
209 , Z(ndv)
210 , q(backend_type::create_vector(nrows, bprm))
211 , S(nrows, prm.isolver, bprm, DistributedInnerProduct(comm))
212 {
213 init(prm, bprm);
214 }
215
216 void init(const params& prm = params(),
217 const backend_params& bprm = backend_params())
218 {
219 ARCCORE_ALINA_TIC("setup deflation");
220 using build_matrix = CSRMatrix<value_type, col_type, ptr_type>;
221
222 // Lets see how many deflation vectors are there.
223 std::vector<ptrdiff_t> dv_size(comm.size);
224
225 {
226 ConstArrayView<ptrdiff_t> send_buf(1, &ndv);
227 ArrayView<ptrdiff_t> receive_buf(comm.size, &dv_size[0]);
228
229 mpAllGather(comm.m_message_passing_mng.get(), send_buf, receive_buf);
230 }
231
232 std::partial_sum(dv_size.begin(), dv_size.end(), dv_start.begin() + 1);
233 nz = dv_start.back();
234
235 df.resize(ndv);
236 dx.resize(ndv);
237 dd = backend_type::create_vector(ndv, bprm);
238
239 auto az_loc = std::make_shared<build_matrix>();
240 auto az_rem = std::make_shared<build_matrix>();
241
242 auto a_loc = A->local();
243 auto a_rem = A->remote();
244
245 const CommunicationPattern<backend_type>& Acp = A->cpat();
246
247 // Fill deflation vectors.
248 ARCCORE_ALINA_TIC("copy deflation vectors");
249 {
250 std::vector<value_type> z(nrows);
251 for (int j = 0; j < ndv; ++j) {
252 arccoreParallelFor(0, nrows, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
253 for (ptrdiff_t i = begin; i < (begin + size); ++i)
254 z[i] = prm.def_vec(i, j);
255 });
256 Z[j] = backend_type::copy_vector(z, bprm);
257 }
258 }
259 ARCCORE_ALINA_TOC("copy deflation vectors");
260
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);
265 // 1. Build local part of AZ matrix.
266 // 2. Count remote nonzeros
267 arccoreParallelFor(0, nrows, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
268 std::vector<ptrdiff_t> marker(Acp.recv.nbr.size(), -1);
269
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;
273
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>();
277 }
278
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];
282
283 for (ptrdiff_t j = 0; j < ndv; ++j)
284 az_loc->val[az_loc_head + j] += v * prm.def_vec(c, j);
285 }
286
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]);
289
290 if (marker[d] != i) {
291 marker[d] = i;
292 az_rem->ptr[i + 1] += dv_size[d];
293 }
294 }
295 }
296 });
297
298 az_rem->set_nonzeros(az_rem->scan_row_sizes());
299 ARCCORE_ALINA_TOC("first pass");
300
301 // Create local preconditioner.
302 ARCCORE_ALINA_TIC("local preconditioner");
303 P = std::make_shared<LocalPrecond>(*a_loc, prm.local, bprm);
304 ARCCORE_ALINA_TOC("local preconditioner");
305
306 A->set_local(P->system_matrix_ptr());
307 A->move_to_backend(bprm);
308
309 ARCCORE_ALINA_TIC("remote(A*Z)");
310 /* Construct remote part of AZ */
311 // Exchange deflation vectors
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);
316
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;
322
323 for (ptrdiff_t j = 0; j < ncols; ++j)
324 zcol_ptr.push_back(zcol_ptr.back() + nvecs);
325 }
326
327 std::vector<value_type> zrecv(zrecv_ptr.back());
328 std::vector<value_type> zsend(Acp.send.count() * ndv);
329
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;
333
334 Acp.recv.req[i] = comm.doIReceive(&zrecv[begin], size, Acp.recv.nbr[i], tag_exc_vals);
335 }
336
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);
340
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);
344
345 comm.waitAll(Acp.recv.req);
346 comm.waitAll(Acp.send.req);
347
348 arccoreParallelFor(0, nrows, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
349 std::vector<ptrdiff_t> marker(nz, -1);
350
351 // AZ_rem = Arem * Z
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;
355
356 for (auto a = backend::row_begin(*a_rem, i); a; ++a) {
357 ptrdiff_t c = a.col();
358 value_type v = a.value();
359
360 // Domain the column belongs to
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];
363
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];
370 ++az_rem_tail;
371 }
372 else {
373 az_rem->val[marker[k]] += v * zval[j];
374 }
375 }
376 }
377 }
378 });
379 ARCCORE_ALINA_TOC("remote(A*Z)");
380
381 /* Build solver for the deflated matrix E. */
382 ARCCORE_ALINA_TIC("assemble E");
383
384 // Count nonzeros in E.
385 std::vector<int> nbrs; // processes we are talking to
386 nbrs.reserve(1 + Acp.send.nbr.size() + Acp.recv.nbr.size());
387 std::set_union(
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);
392
393 build_matrix E;
394 E.set_size(ndv, nz, false);
395
396 {
397 ptrdiff_t nnz = 0;
398 for (int j : nbrs)
399 nnz += dv_size[j];
400 for (int k = 0; k <= ndv; ++k)
401 E.ptr[k] = k * nnz;
402 }
403 E.setNbNonZero(E.ptr[ndv]);
404 E.set_nonzeros(E.ptr[ndv]);
405
406 // Build local strip of E.
407 int nthreads = ConcurrencyBase::maxAllowedThread();
408 multi_array<value_type, 3> erow(nthreads, ndv, nz);
409 std::fill_n(erow.data(), erow.size(), 0);
410
411 {
412 ptrdiff_t dv_offset = dv_start[comm.rank];
413 arccoreParallelFor(0, nrows, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
414 const int tid = TaskFactory::currentTaskThreadIndex();
415 std::vector<value_type> z(ndv);
416
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);
420
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];
424
425 for (ptrdiff_t j = 0; j < ndv; ++j)
426 erow(tid, j, c) += v * z[j];
427 }
428
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];
432
433 for (ptrdiff_t j = 0; j < ndv; ++j)
434 erow(tid, j, c) += v * z[j];
435 }
436 }
437 });
438 }
439
440 for (int i = 0; i < ndv; ++i) {
441 int row_head = E.ptr[i];
442 for (int j : nbrs) {
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)
447 v += erow(t, i, c);
448
449 E.col[row_head] = c;
450 E.val[row_head] = v;
451
452 ++row_head;
453 }
454 }
455 }
456 ARCCORE_ALINA_TOC("assemble E");
457
458 ARCCORE_ALINA_TIC("factorize E");
459 this->E = std::make_shared<DirectSolver>(comm, E, prm.dsolver);
460 ARCCORE_ALINA_TOC("factorize E");
461
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");
467 }
468
469 template <class Vec1, class Vec2>
470 void apply(const Vec1& rhs, Vec2&& x) const
471 {
472 size_t iters;
473 double error;
474 backend::clear(x);
475 std::tie(iters, error) = (*this)(rhs, x);
476 }
477
478 std::shared_ptr<matrix> system_matrix_ptr() const
479 {
480 return A;
481 }
482
483 const matrix& system_matrix() const
484 {
485 return *A;
486 }
487
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
491 {
492 std::tuple<size_t, value_type> cnv = S(make_sdd_projected_matrix(*this, A), *P, rhs, x);
493 postprocess(rhs, x);
494 return cnv;
495 }
496
497 template <class Vec1, class Vec2>
498 std::tuple<size_t, value_type>
499 operator()(const Vec1& rhs, Vec2&& x) const
500 {
501 std::tuple<size_t, value_type> cnv = S(make_sdd_projected_matrix(*this, *A), *P, rhs, x);
502 postprocess(rhs, x);
503 return cnv;
504 }
505
506 size_t size() const
507 {
508 return nrows;
509 }
510
511 template <class Vector>
512 void project(Vector& x) const
513 {
514 const auto one = math::identity<scalar_type>();
515
516 ARCCORE_ALINA_TIC("project");
517
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");
522
523 coarse_solve(df, dx);
524
525 ARCCORE_ALINA_TIC("spmv");
526 backend::copy(dx, *dd);
527 backend::spmv(-one, *AZ, *dd, one, x);
528 ARCCORE_ALINA_TOC("spmv");
529
530 ARCCORE_ALINA_TOC("project");
531 }
532
533 private:
534
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;
539
540 mpi_communicator comm;
541 ptrdiff_t nrows, ndv, nz;
542
543 std::shared_ptr<matrix> A, AZ;
544 std::shared_ptr<LocalPrecond> P;
545
546 mutable std::vector<value_type> df, dx;
547 std::vector<ptrdiff_t> dv_start;
548
549 std::vector<std::shared_ptr<vector>> Z;
550
551 std::shared_ptr<DirectSolver> E;
552
553 std::shared_ptr<vector> q;
554 std::shared_ptr<vector> dd;
555
556 IterativeSolver S;
557
558 void coarse_solve(std::vector<value_type>& f, std::vector<value_type>& x) const
559 {
560 ARCCORE_ALINA_TIC("coarse solve");
561 (*E)(f, x);
562 ARCCORE_ALINA_TOC("coarse solve");
563 }
564
565 template <class Vec1, class Vec2>
566 void postprocess(const Vec1& rhs, Vec2& x) const
567 {
568 const auto one = math::identity<scalar_type>();
569
570 ARCCORE_ALINA_TIC("postprocess");
571
572 // q = rhs - Ax
573 backend::copy(rhs, *q);
574 backend::spmv(-one, *A, x, one, *q);
575
576 // df = transp(Z) * (rhs - Ax)
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");
581
582 // dx = inv(E) * df
583 coarse_solve(df, dx);
584
585 // x += Z * dx
586 backend::lin_comb(ndv, dx, Z, one, x);
587
588 ARCCORE_ALINA_TOC("postprocess");
589 }
590};
591
592/*---------------------------------------------------------------------------*/
593/*---------------------------------------------------------------------------*/
594
595} // namespace Arcane::Alina
596
597/*---------------------------------------------------------------------------*/
598/*---------------------------------------------------------------------------*/
599
600namespace Arcane::Alina::backend
601{
602
603template <class SDD, class Matrix,
604 class Alpha, class Beta, class Vec1, class Vec2>
605struct spmv_impl<Alpha, sdd_projected_matrix<SDD, Matrix>, Vec1, Beta, Vec2>
606{
608
609 static void apply(Alpha alpha, const M& A, const Vec1& x, Beta beta, Vec2& y)
610 {
611 A.mul(alpha, x, beta, y);
612 }
613};
614
615template <class SDD, class Matrix, class Vec1, class Vec2, class Vec3>
616struct residual_impl<sdd_projected_matrix<SDD, Matrix>, Vec1, Vec2, Vec3>
617{
619
620 static void apply(const Vec1& rhs, const M& A, const Vec2& x, Vec3& r)
621 {
622 A.residual(rhs, x, r);
623 }
624};
625
626/*---------------------------------------------------------------------------*/
627/*---------------------------------------------------------------------------*/
628
629} // namespace Arcane::Alina::backend
630
631/*---------------------------------------------------------------------------*/
632/*---------------------------------------------------------------------------*/
633
634#endif
Distributed Matrix using message passing.
Distributed solver based on subdomain deflation.
Modifiable view of an array of type T.
static Int32 maxAllowedThread()
Maximum number of allowed threads for multi-threading.
Constant view of an array of type T.
Matrix class, to be used by user.
static Int32 currentTaskThreadIndex()
Index (between 0 and nbAllowedThread()-1) of the thread executing the current task.
void mpAllGather(IMessagePassingMng *pm, const ISerializer *send_serializer, ISerializer *receive_serialize)
allGather() message for serialization
Definition Messages.cc:309
void arccoreParallelFor(const ComplexForLoopRanges< RankValue, IndexType_ > &loop_ranges, const ForLoopRunInfo &run_info, const LambdaType &lambda_function, const ReducerArgs &... reducer_args)
Applies the lambda function lambda_function concurrently over the iteration interval given by loop_ra...
Definition ParallelFor.h:86
std::int32_t Int32
Signed integer type of 32 bits.
Inner product for distributed vectors.
Implementation for residual error compuatation.
Implementation for matrix-vector product.
constant_deflation(int block_size=1)
Constructor.
Convenience wrapper around MPI_Comm.