56class SchurPressureCorrectionPreconditioner
59 typename PSolver::backend_type>::value,
60 "Backends for pressure and flow preconditioners should coincide!");
65 typename PSolver::backend_type>::type backend_type;
67 typedef typename backend_type::value_type value_type;
68 typedef typename backend_type::col_type col_type;
69 typedef typename backend_type::ptr_type ptr_type;
70 typedef typename math::scalar_of<value_type>::type scalar_type;
71 typedef typename backend_type::matrix matrix;
72 typedef typename backend_type::vector vector;
73 typedef typename backend_type::params backend_params;
75 typedef typename BuiltinBackend<value_type, col_type, ptr_type>::matrix build_matrix;
79 typedef typename USolver::params usolver_params;
80 typedef typename PSolver::params psolver_params;
82 usolver_params usolver;
83 psolver_params psolver;
85 std::vector<char> pmask;
116 , approx_schur(
false)
123 : ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p, usolver)
124 , ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p, psolver)
125 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, type)
126 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, approx_schur)
127 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, adjust_p)
128 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, simplec_dia)
129 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, verbose)
133 n = p.get(
"pmask_size", n);
136 "Error in schur_complement parameters: "
137 "pmask_size is not set");
139 if (p.count(
"pmask_pattern")) {
142 std::string pattern = p.get(
"pmask_pattern", std::string());
143 switch (pattern[0]) {
145 int start = std::atoi(pattern.substr(1).c_str());
146 int stride = std::atoi(pattern.substr(3).c_str());
147 for (
size_t i = start; i < n; i += stride)
151 size_t m = std::atoi(pattern.c_str() + 1);
152 for (
size_t i = 0; i < std::min(m, n); ++i)
156 size_t m = std::atoi(pattern.c_str() + 1);
157 for (
size_t i = m; i < n; ++i)
161 precondition(
false,
"Unknown pattern in pmask_pattern");
164 else if (p.count(
"pmask")) {
166 pm = p.get(
"pmask", pm);
167 pmask.assign(
static_cast<char*
>(pm),
static_cast<char*
>(pm) + n);
171 "Error in schur_complement parameters: "
172 "neither pmask_pattern, nor pmask is set");
175 p.check_params({
"usolver",
"psolver",
"type",
"approx_schur",
"adjust_p",
"simplec_dia",
"pmask_size",
"verbose" },
176 {
"pmask",
"pmask_pattern" });
179 void get(
PropertyTree& p,
const std::string& path =
"")
const
181 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, usolver);
182 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, psolver);
183 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, type);
184 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, approx_schur);
185 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, adjust_p);
186 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, simplec_dia);
187 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, verbose);
191 template <
class Matrix>
192 SchurPressureCorrectionPreconditioner(
const Matrix& K,
194 const backend_params& bprm = backend_params())
196 , n(backend::nbRow(K))
200 init(std::make_shared<build_matrix>(K), bprm);
205 const backend_params& bprm = backend_params())
207 , n(backend::nbRow(*K))
214 template <
class Vec1,
class Vec2>
215 void apply(
const Vec1& rhs, Vec2&& x)
const
217 const auto one = math::identity<scalar_type>();
218 const auto zero = math::zero<scalar_type>();
220 backend::spmv(one, *x2u, rhs, zero, *rhs_u);
221 backend::spmv(one, *x2p, rhs, zero, *rhs_p);
226 report(
"U1", (*U)(*rhs_u, *u));
229 backend::spmv(-one, *Kpu, *u, one, *rhs_p);
233 report(
"P1", (*P)(*
this, *rhs_p, *p));
236 backend::spmv(-one, *Kup, *p, one, *rhs_u);
240 report(
"U2", (*U)(*rhs_u, *u));
242 else if (prm.type == 2) {
245 report(
"P", (*P)(*
this, *rhs_p, *p));
248 backend::spmv(-one, *Kup, *p, one, *rhs_u);
250 report(
"U", (*U)(*rhs_u, *u));
253 backend::spmv(one, *u2x, *u, zero, x);
254 backend::spmv(one, *p2x, *p, one, x);
257 template <
class Alpha,
class Vec1,
class Beta,
class Vec2>
258 void spmv(Alpha alpha,
const Vec1& x, Beta beta, Vec2& y)
const
260 const auto one = math::identity<scalar_type>();
261 const auto zero = math::zero<scalar_type>();
264 if (prm.adjust_p == 1) {
265 backend::spmv(alpha, P->system_matrix(), x, beta, y);
266 backend::vmul(alpha, *Ld, x, one, y);
268 else if (prm.adjust_p == 2) {
269 backend::spmv(alpha, *Lm, x, beta, y);
272 backend::spmv(alpha, P->system_matrix(), x, beta, y);
275 backend::spmv(one, *Kup, x, zero, *tmp);
277 if (prm.approx_schur) {
278 backend::vmul(one, *M, *tmp, zero, *u);
285 backend::spmv(-alpha, *Kpu, *u, one, y);
288 std::shared_ptr<matrix> system_matrix_ptr()
const
293 const matrix& system_matrix()
const
302 b += backend::bytes(*K);
303 b += backend::bytes(*Kup);
304 b += backend::bytes(*Kpu);
305 b += backend::bytes(*x2u);
306 b += backend::bytes(*x2p);
307 b += backend::bytes(*u2x);
308 b += backend::bytes(*p2x);
309 b += backend::bytes(*rhs_u);
310 b += backend::bytes(*rhs_p);
311 b += backend::bytes(*u);
312 b += backend::bytes(*p);
313 b += backend::bytes(*tmp);
314 b += backend::bytes(*U);
315 b += backend::bytes(*P);
318 b += backend::bytes(*M);
320 b += backend::bytes(*Ld);
322 b += backend::bytes(*Lm);
333 std::shared_ptr<matrix> K, Lm, Kup, Kpu, x2u, x2p, u2x, p2x;
334 std::shared_ptr<vector> rhs_u, rhs_p, u, p, tmp;
335 std::shared_ptr<typename backend_type::matrix_diagonal> M;
336 std::shared_ptr<typename backend_type::matrix_diagonal> Ld;
338 std::shared_ptr<USolver> U;
339 std::shared_ptr<PSolver> P;
341 void init(
const std::shared_ptr<build_matrix>& K,
const backend_params& bprm)
343 this->K = backend_type::copy_matrix(K, bprm);
346 auto Kuu = std::make_shared<build_matrix>();
347 auto Kpu = std::make_shared<build_matrix>();
348 auto Kup = std::make_shared<build_matrix>();
349 auto Kpp = std::make_shared<build_matrix>();
351 std::vector<ptrdiff_t> idx(n);
353 for (
size_t i = 0; i < n; ++i)
354 idx[i] = (prm.pmask[i] ? np++ : nu++);
356 Kuu->set_size(nu, nu,
true);
357 Kup->set_size(nu, np,
true);
358 Kpu->set_size(np, nu,
true);
359 Kpp->set_size(np, np,
true);
362 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
363 ptrdiff_t ci = idx[i];
364 char pi = prm.pmask[i];
365 for (
auto k = backend::row_begin(*K, i); k; ++k) {
366 char pj = prm.pmask[k.col()];
388 Kuu->set_nonzeros(Kuu->scan_row_sizes());
389 Kup->set_nonzeros(Kup->scan_row_sizes());
390 Kpu->set_nonzeros(Kpu->scan_row_sizes());
391 Kpp->set_nonzeros(Kpp->scan_row_sizes());
394 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
395 ptrdiff_t ci = idx[i];
396 char pi = prm.pmask[i];
398 ptrdiff_t uu_head = 0, up_head = 0, pu_head = 0, pp_head = 0;
401 pu_head = Kpu->ptr[ci];
402 pp_head = Kpp->ptr[ci];
405 uu_head = Kuu->ptr[ci];
406 up_head = Kup->ptr[ci];
409 for (
auto k = backend::row_begin(*K, i); k; ++k) {
410 ptrdiff_t j = k.col();
411 value_type v = k.value();
412 ptrdiff_t cj = idx[j];
413 char pj = prm.pmask[j];
417 Kpp->col[pp_head] = cj;
418 Kpp->val[pp_head] = v;
422 Kpu->col[pu_head] = cj;
423 Kpu->val[pu_head] = v;
429 Kup->col[up_head] = cj;
430 Kup->val[up_head] = v;
434 Kuu->col[uu_head] = cj;
435 Kuu->val[uu_head] = v;
443 if (prm.verbose >= 2) {
444 IO::mm_write(
"Kuu.mtx", *Kuu);
445 IO::mm_write(
"Kpp.mtx", *Kpp);
448 std::shared_ptr<numa_vector<value_type>> Kuu_dia;
450 if (prm.simplec_dia) {
451 Kuu_dia = std::make_shared<numa_vector<value_type>>(nu);
453 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
454 value_type s = math::zero<value_type>();
455 for (ptrdiff_t j = Kuu->ptr[i], e = Kuu->ptr[i + 1]; j < e; ++j) {
456 s += math::norm(Kuu->val[j]);
458 (*Kuu_dia)[i] = math::inverse(s);
463 Kuu_dia = diagonal(*Kuu,
true);
466 if (prm.adjust_p == 1) {
469 auto L = std::make_shared<numa_vector<value_type>>(np,
false);
472 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
473 value_type s = math::zero<value_type>();
474 for (ptrdiff_t j = Kpu->ptr[i], e = Kpu->ptr[i + 1]; j < e; ++j) {
475 ptrdiff_t k = Kpu->col[j];
476 value_type v = Kpu->val[j];
477 for (ptrdiff_t jj = Kup->ptr[k], ee = Kup->ptr[k + 1]; jj < ee; ++jj) {
478 if (Kup->col[jj] == i) {
479 s += v * (*Kuu_dia)[k] * Kup->val[jj];
486 for (ptrdiff_t j = Kpp->ptr[i], e = Kpp->ptr[i + 1]; j < e; ++j) {
487 if (Kpp->col[j] == i) {
494 Ld = backend_type::copy_vector(L, bprm);
496 else if (prm.adjust_p == 2) {
497 Lm = backend_type::copy_matrix(Kpp, bprm);
501 numa_vector<value_type> val(Kup->nbNonZero());
504 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
505 value_type d = (*Kuu_dia)[i];
506 for (ptrdiff_t j = Kup->ptr[i], e = Kup->ptr[i + 1]; j < e; ++j) {
507 val[j] = d * Kup->val[j];
512 build_matrix Kup_hat;
514 Kup_hat.own_data =
false;
515 Kup_hat.setNbRow(nu);
517 Kup_hat.setNbNonZero(Kup->nbNonZero());
518 Kup_hat.ptr.setPointerZeroCopy(Kup->ptr.data());
519 Kup_hat.col.setPointerZeroCopy(Kup->col.data());
520 Kup_hat.val.setPointerZeroCopy(val.data());
522 Kpp = sum(math::identity<value_type>(), *Kpp, -math::identity<value_type>(), *product(*Kpu, Kup_hat));
525 U = std::make_shared<USolver>(*Kuu, prm.usolver, bprm);
526 P = std::make_shared<PSolver>(*Kpp, prm.psolver, bprm);
528 this->Kup = backend_type::copy_matrix(Kup, bprm);
529 this->Kpu = backend_type::copy_matrix(Kpu, bprm);
531 rhs_u = backend_type::create_vector(nu, bprm);
532 rhs_p = backend_type::create_vector(np, bprm);
534 u = backend_type::create_vector(nu, bprm);
535 p = backend_type::create_vector(np, bprm);
537 tmp = backend_type::create_vector(nu, bprm);
539 if (prm.approx_schur)
540 M = backend_type::copy_vector(Kuu_dia, bprm);
543 auto x2u = std::make_shared<build_matrix>();
544 auto x2p = std::make_shared<build_matrix>();
545 auto u2x = std::make_shared<build_matrix>();
546 auto p2x = std::make_shared<build_matrix>();
548 x2u->set_size(nu, n,
true);
549 x2p->set_size(np, n,
true);
550 u2x->set_size(n, nu,
true);
551 p2x->set_size(n, np,
true);
554 ptrdiff_t x2u_head = 0, x2u_idx = 0;
555 ptrdiff_t x2p_head = 0, x2p_idx = 0;
556 ptrdiff_t u2x_head = 0, u2x_idx = 0;
557 ptrdiff_t p2x_head = 0, p2x_idx = 0;
559 for (
size_t i = 0; i < n; ++i) {
561 x2p->ptr[++x2p_idx] = ++x2p_head;
565 x2u->ptr[++x2u_idx] = ++x2u_head;
569 p2x->ptr[++p2x_idx] = p2x_head;
570 u2x->ptr[++u2x_idx] = u2x_head;
580 ptrdiff_t x2u_head = 0;
581 ptrdiff_t x2p_head = 0;
582 ptrdiff_t u2x_head = 0;
583 ptrdiff_t p2x_head = 0;
585 for (
size_t i = 0; i < n; ++i) {
586 ptrdiff_t j = idx[i];
589 x2p->col[x2p_head] = i;
590 x2p->val[x2p_head] = math::identity<value_type>();
593 p2x->col[p2x_head] = j;
594 p2x->val[p2x_head] = math::identity<value_type>();
598 x2u->col[x2u_head] = i;
599 x2u->val[x2u_head] = math::identity<value_type>();
602 u2x->col[u2x_head] = j;
603 u2x->val[u2x_head] = math::identity<value_type>();
609 this->x2u = backend_type::copy_matrix(x2u, bprm);
610 this->x2p = backend_type::copy_matrix(x2p, bprm);
611 this->u2x = backend_type::copy_matrix(u2x, bprm);
612 this->p2x = backend_type::copy_matrix(p2x, bprm);
615 friend std::ostream& operator<<(std::ostream& os,
const SchurPressureCorrectionPreconditioner& p)
617 os <<
"Schur complement (two-stage preconditioner)" << std::endl;
618 os <<
" Unknowns: " << p.n <<
"(" << p.np <<
")" << std::endl;
619 os <<
" Nonzeros: " << backend::nonzeros(p.system_matrix()) << std::endl;
620 os <<
" Memory: " << human_readable_memory(p.bytes()) << std::endl;
623 << *p.U << std::endl;
625 << *p.P << std::endl;
630 void report(
const std::string& name,
const SolverResult& r)
const
632 if (prm.verbose >= 1) {
633 std::cout << name <<
" (" << r.nbIteration() <<
", " << r.residual() <<
")\n";