43class DistributedSchurPressureCorrection
45 using USolverBackendType =
typename USolver::backend_type;
46 using PSolverBackendType =
typename PSolver::backend_type;
48 static_assert(std::is_same<USolverBackendType, PSolverBackendType>::value,
49 "Backends for pressure and flow preconditioners should coincide!");
54 using BackendType = backend_type;
56 typedef typename backend_type::value_type value_type;
57 typedef typename math::scalar_of<value_type>::type scalar_type;
58 typedef typename backend_type::matrix bmatrix;
59 typedef typename backend_type::vector vector;
60 typedef typename backend_type::params backend_params;
64 typedef typename BuiltinBackend<value_type>::matrix build_matrix;
68 typedef typename USolver::params usolver_params;
69 typedef typename PSolver::params psolver_params;
71 usolver_params usolver;
72 psolver_params psolver;
74 std::vector<char> pmask;
88 bool approx_schur =
false;
92 bool simplec_dia =
true;
99 : ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p, usolver)
100 , ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p, psolver)
101 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, type)
102 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, approx_schur)
103 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, simplec_dia)
104 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, verbose)
108 n = p.get(
"pmask_size", n);
110 precondition(n > 0,
"Error in schur_complement parameters: pmask_size is not set");
112 if (p.count(
"pmask_pattern")) {
115 std::string pattern = p.get(
"pmask_pattern", std::string());
116 switch (pattern[0]) {
118 int start = std::atoi(pattern.substr(1).c_str());
119 int stride = std::atoi(pattern.substr(3).c_str());
120 for (
size_t i = start; i < n; i += stride)
124 size_t m = std::atoi(pattern.c_str() + 1);
125 for (
size_t i = 0; i < std::min(m, n); ++i)
129 size_t m = std::atoi(pattern.c_str() + 1);
130 for (
size_t i = m; i < n; ++i)
134 Alina::precondition(
false,
"Unknown pattern in pmask_pattern");
137 else if (p.count(
"pmask")) {
139 pm = p.get(
"pmask", pm);
140 pmask.assign(
static_cast<char*
>(pm),
static_cast<char*
>(pm) + n);
143 ARCANE_FATAL(
"Error in schur_complement parameters: neither pmask_pattern, nor pmask is set");
146 p.check_params({
"usolver",
"psolver",
"type",
"approx_schur",
"simplec_dia",
"pmask_size",
"verbose" },
147 {
"pmask",
"pmask_pattern" });
150 void get(
PropertyTree& p,
const std::string& path =
"")
const
152 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, usolver);
153 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, psolver);
154 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, type);
155 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, approx_schur);
156 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, simplec_dia);
157 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, verbose);
161 template <
class Matrix>
165 const backend_params& bprm = backend_params())
169 this->K = std::make_shared<matrix>(comm, K, backend::nbRow(K));
174 std::shared_ptr<matrix> K,
176 const backend_params& bprm = backend_params())
184 void init(
const backend_params& bprm)
186 using std::make_shared;
187 using std::make_tuple;
188 using std::shared_ptr;
191 auto _K_loc = K->local();
192 auto _K_rem = K->remote();
194 build_matrix& K_loc = *_K_loc;
195 build_matrix& K_rem = *_K_rem;
197 ptrdiff_t n = K->loc_rows();
200 ARCCORE_ALINA_TIC(
"count pressure/flow vars");
201 std::vector<ptrdiff_t> idx(n);
202 ptrdiff_t np = 0, nu = 0;
204 for (ptrdiff_t i = 0; i < n; ++i)
205 idx[i] = (prm.pmask[i] ? np++ : nu++);
206 ARCCORE_ALINA_TOC(
"count pressure/flow vars");
208 ARCCORE_ALINA_TIC(
"setup communication");
214 ptrdiff_t p_beg = pdomain[comm.rank];
215 ptrdiff_t u_beg = udomain[comm.rank];
217 const CommPattern& C = this->K->cpat();
218 ptrdiff_t nsend = C.send.count(), nrecv = C.recv.count();
219 std::vector<char> smask(nsend), rmask(nrecv);
220 std::vector<ptrdiff_t> s_idx(nsend), r_idx(nrecv);
222 for (ptrdiff_t i = 0; i < nsend; ++i) {
223 ptrdiff_t c = C.send.col[i];
224 smask[i] = prm.pmask[c];
225 s_idx[i] = idx[c] + (smask[i] ? p_beg : u_beg);
228 C.exchange(&smask[0], &rmask[0]);
229 C.exchange(&s_idx[0], &r_idx[0]);
230 ARCCORE_ALINA_TOC(
"setup communication");
234 ARCCORE_ALINA_TIC(
"schur blocks");
235 this->K->move_to_backend(bprm);
237 auto Kpp_loc = make_shared<build_matrix>();
238 auto Kpp_rem = make_shared<build_matrix>();
239 auto Kuu_loc = make_shared<build_matrix>();
240 auto Kuu_rem = make_shared<build_matrix>();
242 auto Kpu_loc = make_shared<build_matrix>();
243 auto Kpu_rem = make_shared<build_matrix>();
244 auto Kup_loc = make_shared<build_matrix>();
245 auto Kup_rem = make_shared<build_matrix>();
247 Kpp_loc->set_size(np, np,
true);
248 Kpp_rem->set_size(np, 0,
true);
250 Kuu_loc->set_size(nu, nu,
true);
251 Kuu_rem->set_size(nu, 0,
true);
253 Kpu_loc->set_size(np, nu,
true);
254 Kpu_rem->set_size(np, 0,
true);
256 Kup_loc->set_size(nu, np,
true);
257 Kup_rem->set_size(nu, 0,
true);
260 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
261 ptrdiff_t ci = idx[i];
262 char pi = prm.pmask[i];
264 for (
auto a = backend::row_begin(K_loc, i); a; ++a) {
265 char pj = prm.pmask[a.col()];
269 ++Kpp_loc->ptr[ci + 1];
272 ++Kpu_loc->ptr[ci + 1];
277 ++Kup_loc->ptr[ci + 1];
280 ++Kuu_loc->ptr[ci + 1];
285 for (
auto a = backend::row_begin(K_rem, i); a; ++a) {
286 char pj = rmask[a.col()];
290 ++Kpp_rem->ptr[ci + 1];
293 ++Kpu_rem->ptr[ci + 1];
298 ++Kup_rem->ptr[ci + 1];
301 ++Kuu_rem->ptr[ci + 1];
308 Kpp_loc->set_nonzeros(Kpp_loc->scan_row_sizes());
309 Kpp_rem->set_nonzeros(Kpp_rem->scan_row_sizes());
311 Kuu_loc->set_nonzeros(Kuu_loc->scan_row_sizes());
312 Kuu_rem->set_nonzeros(Kuu_rem->scan_row_sizes());
314 Kpu_loc->set_nonzeros(Kpu_loc->scan_row_sizes());
315 Kpu_rem->set_nonzeros(Kpu_rem->scan_row_sizes());
317 Kup_loc->set_nonzeros(Kup_loc->scan_row_sizes());
318 Kup_rem->set_nonzeros(Kup_rem->scan_row_sizes());
322 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
323 ptrdiff_t ci = idx[i];
324 char pi = prm.pmask[i];
326 ptrdiff_t pp_loc_head = 0, pp_rem_head = 0;
327 ptrdiff_t uu_loc_head = 0, uu_rem_head = 0;
328 ptrdiff_t pu_loc_head = 0, pu_rem_head = 0;
329 ptrdiff_t up_loc_head = 0, up_rem_head = 0;
332 pp_loc_head = Kpp_loc->ptr[ci];
333 pp_rem_head = Kpp_rem->ptr[ci];
334 pu_loc_head = Kpu_loc->ptr[ci];
335 pu_rem_head = Kpu_rem->ptr[ci];
338 uu_loc_head = Kuu_loc->ptr[ci];
339 uu_rem_head = Kuu_rem->ptr[ci];
340 up_loc_head = Kup_loc->ptr[ci];
341 up_rem_head = Kup_rem->ptr[ci];
344 for (
auto a = backend::row_begin(K_loc, i); a; ++a) {
345 ptrdiff_t j = a.col();
346 value_type v = a.value();
347 char pj = prm.pmask[j];
348 ptrdiff_t cj = idx[j];
352 Kpp_loc->col[pp_loc_head] = cj;
353 Kpp_loc->val[pp_loc_head] = v;
357 Kpu_loc->col[pu_loc_head] = cj;
358 Kpu_loc->val[pu_loc_head] = v;
364 Kup_loc->col[up_loc_head] = cj;
365 Kup_loc->val[up_loc_head] = v;
369 Kuu_loc->col[uu_loc_head] = cj;
370 Kuu_loc->val[uu_loc_head] = v;
376 for (
auto a = backend::row_begin(K_rem, i); a; ++a) {
377 ptrdiff_t j = a.col();
378 value_type v = a.value();
380 ptrdiff_t cj = r_idx[j];
384 Kpp_rem->col[pp_rem_head] = cj;
385 Kpp_rem->val[pp_rem_head] = v;
389 Kpu_rem->col[pu_rem_head] = cj;
390 Kpu_rem->val[pu_rem_head] = v;
396 Kup_rem->col[up_rem_head] = cj;
397 Kup_rem->val[up_rem_head] = v;
401 Kuu_rem->col[uu_rem_head] = cj;
402 Kuu_rem->val[uu_rem_head] = v;
410 auto Kpp = std::make_shared<matrix>(comm, Kpp_loc, Kpp_rem);
411 auto Kuu = std::make_shared<matrix>(comm, Kuu_loc, Kuu_rem);
413 Kpu = make_shared<matrix>(comm, Kpu_loc, Kpu_rem);
414 Kup = make_shared<matrix>(comm, Kup_loc, Kup_rem);
416 Kpu->move_to_backend(bprm);
417 Kup->move_to_backend(bprm);
418 ARCCORE_ALINA_TOC(
"schur blocks");
420 ARCCORE_ALINA_TIC(
"usolver")
421 U = make_shared<USolver>(comm, Kuu, prm.usolver, bprm);
422 ARCCORE_ALINA_TOC(
"usolver")
423 ARCCORE_ALINA_TIC(
"psolver")
424 P = make_shared<PSolver>(comm, Kpp, prm.psolver, bprm);
425 ARCCORE_ALINA_TOC(
"psolver")
427 ARCCORE_ALINA_TIC(
"other");
428 rhs_u = backend_type::create_vector(nu, bprm);
429 rhs_p = backend_type::create_vector(np, bprm);
431 u = backend_type::create_vector(nu, bprm);
432 p = backend_type::create_vector(np, bprm);
434 tmp = backend_type::create_vector(nu, bprm);
436 if (prm.approx_schur) {
437 std::shared_ptr<numa_vector<value_type>> Kuu_dia;
438 ARCCORE_ALINA_TIC(
"Kuu diagonal");
439 if (prm.simplec_dia) {
440 Kuu_dia = std::make_shared<numa_vector<value_type>>(nu,
false);
442 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
443 value_type s = math::zero<value_type>();
444 for (ptrdiff_t j = Kuu_loc->ptr[i], e = Kuu_loc->ptr[i + 1]; j < e; ++j) {
445 s += math::norm(Kuu_loc->val[j]);
447 for (ptrdiff_t j = Kuu_rem->ptr[i], e = Kuu_rem->ptr[i + 1]; j < e; ++j) {
448 s += math::norm(Kuu_rem->val[j]);
450 (*Kuu_dia)[i] = math::inverse(s);
455 Kuu_dia = diagonal(*Kuu_loc,
true);
458 M = backend_type::copy_vector(Kuu_dia, bprm);
459 ARCCORE_ALINA_TOC(
"Kuu diagonal");
463 ARCCORE_ALINA_TIC(
"scatter/gather");
464 auto x2u = std::make_shared<build_matrix>();
465 auto x2p = std::make_shared<build_matrix>();
466 auto u2x = std::make_shared<build_matrix>();
467 auto p2x = std::make_shared<build_matrix>();
469 x2u->set_size(nu, n,
true);
470 x2p->set_size(np, n,
true);
471 u2x->set_size(n, nu,
true);
472 p2x->set_size(n, np,
true);
475 ptrdiff_t x2u_head = 0, x2u_idx = 0;
476 ptrdiff_t x2p_head = 0, x2p_idx = 0;
477 ptrdiff_t u2x_head = 0, u2x_idx = 0;
478 ptrdiff_t p2x_head = 0, p2x_idx = 0;
480 for (ptrdiff_t i = 0; i < n; ++i) {
482 x2p->ptr[++x2p_idx] = ++x2p_head;
486 x2u->ptr[++x2u_idx] = ++x2u_head;
490 p2x->ptr[++p2x_idx] = p2x_head;
491 u2x->ptr[++u2x_idx] = u2x_head;
501 ptrdiff_t x2u_head = 0;
502 ptrdiff_t x2p_head = 0;
503 ptrdiff_t u2x_head = 0;
504 ptrdiff_t p2x_head = 0;
506 for (ptrdiff_t i = 0; i < n; ++i) {
507 ptrdiff_t j = idx[i];
510 x2p->col[x2p_head] = i;
511 x2p->val[x2p_head] = math::identity<value_type>();
514 p2x->col[p2x_head] = j;
515 p2x->val[p2x_head] = math::identity<value_type>();
519 x2u->col[x2u_head] = i;
520 x2u->val[x2u_head] = math::identity<value_type>();
523 u2x->col[u2x_head] = j;
524 u2x->val[u2x_head] = math::identity<value_type>();
530 this->x2u = backend_type::copy_matrix(x2u, bprm);
531 this->x2p = backend_type::copy_matrix(x2p, bprm);
532 this->u2x = backend_type::copy_matrix(u2x, bprm);
533 this->p2x = backend_type::copy_matrix(p2x, bprm);
534 ARCCORE_ALINA_TOC(
"scatter/gather");
537 std::shared_ptr<matrix> system_matrix_ptr()
const
542 const matrix& system_matrix()
const
547 template <
class Vec1,
class Vec2>
548 void apply(
const Vec1& rhs, Vec2&& x)
const
550 const auto one = math::identity<scalar_type>();
551 const auto zero = math::zero<scalar_type>();
553 ARCCORE_ALINA_TIC(
"split variables");
554 backend::spmv(one, *x2u, rhs, zero, *rhs_u);
555 backend::spmv(one, *x2p, rhs, zero, *rhs_p);
556 ARCCORE_ALINA_TOC(
"split variables");
560 ARCCORE_ALINA_TIC(
"solve U");
562 report(
"U1", (*U)(*rhs_u, *u));
563 ARCCORE_ALINA_TOC(
"solve U");
566 ARCCORE_ALINA_TIC(
"solve P");
567 backend::spmv(-one, *Kpu, *u, one, *rhs_p);
571 report(
"P", (*P)(*
this, *rhs_p, *p));
572 ARCCORE_ALINA_TOC(
"solve P");
575 ARCCORE_ALINA_TIC(
"Update U");
576 backend::spmv(-one, *Kup, *p, one, *rhs_u);
580 report(
"U2", (*U)(*rhs_u, *u));
581 ARCCORE_ALINA_TOC(
"Update U");
583 else if (prm.type == 2) {
585 ARCCORE_ALINA_TIC(
"solve P");
587 report(
"P", (*P)(*
this, *rhs_p, *p));
588 ARCCORE_ALINA_TOC(
"solve P");
591 ARCCORE_ALINA_TIC(
"solve U");
592 backend::spmv(-one, *Kup, *p, one, *rhs_u);
594 report(
"U", (*U)(*rhs_u, *u));
595 ARCCORE_ALINA_TOC(
"solve U");
598 ARCCORE_ALINA_TIC(
"merge variables");
599 backend::spmv(one, *u2x, *u, zero, x);
600 backend::spmv(one, *p2x, *p, one, x);
601 ARCCORE_ALINA_TOC(
"merge variables");
604 template <
class Alpha,
class Vec1,
class Beta,
class Vec2>
605 void spmv(Alpha alpha,
const Vec1& x, Beta beta, Vec2& y)
const
607 const auto one = math::identity<scalar_type>();
608 const auto zero = math::zero<scalar_type>();
611 ARCCORE_ALINA_TIC(
"matrix-free spmv");
612 backend::spmv(alpha, P->system_matrix(), x, beta, y);
614 backend::spmv(one, *Kup, x, zero, *tmp);
616 if (prm.approx_schur) {
617 backend::vmul(one, *M, *tmp, zero, *u);
623 backend::spmv(-alpha, *Kpu, *u, one, y);
624 ARCCORE_ALINA_TOC(
"matrix-free spmv");
633 typedef CommunicationPattern<backend_type> CommPattern;
634 mpi_communicator comm;
636 std::shared_ptr<bmatrix> x2p, x2u, p2x, u2x;
637 std::shared_ptr<matrix> K, Kpu, Kup;
638 std::shared_ptr<vector> rhs_u, rhs_p, u, p, tmp;
639 std::shared_ptr<typename backend_type::matrix_diagonal> M;
641 std::shared_ptr<USolver> U;
642 std::shared_ptr<PSolver> P;
644#ifdef ARCCORE_ALINA_DEBUG
645 void report(
const std::string& name,
const SolverResult& sr)
const
647 if (comm.rank == 0 && prm.report >= 1) {
648 std::cout << name <<
" (" << sr.nbIteration() <<
", " << sr.residual() <<
")\n";
652 void report(
const std::string&,
const SolverResult&)
const