46class CPRDynamicRowSumPreconditioner
49 "Pressure backend should have scalar value type!");
52 typename PPrecond::backend_type,
53 typename SPrecond::backend_type>::value,
54 "Backends for pressure and flow preconditioners should coincide!");
58 typedef typename SPrecond::backend_type backend_type;
59 typedef typename PPrecond::backend_type backend_type_p;
61 typedef typename backend_type::value_type value_type;
62 typedef typename math::scalar_of<value_type>::type scalar_type;
63 typedef typename backend_type::matrix matrix;
64 typedef typename backend_type::vector vector;
65 typedef typename backend_type_p::value_type value_type_p;
66 typedef typename backend_type_p::matrix matrix_p;
67 typedef typename backend_type_p::vector vector_p;
69 typedef typename backend_type::params backend_params;
71 typedef typename BuiltinBackend<value_type>::matrix build_matrix;
72 typedef typename BuiltinBackend<value_type_p>::matrix build_matrix_p;
76 typedef typename PPrecond::params pprecond_params;
77 typedef typename SPrecond::params sprecond_params;
79 pprecond_params pprecond;
80 sprecond_params sprecond;
83 Int32 active_rows = 0;
87 std::vector<double> weights;
92 : ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p, pprecond)
93 , ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p, sprecond)
94 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, block_size)
95 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, active_rows)
96 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, eps_dd)
97 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, eps_ps)
102 ptr = p.get(
"weights", ptr);
103 n = p.get(
"weights_size", n);
107 "Error in cpr_wdrs parameters: "
108 "weights is set, but weights_size is not");
111 static_cast<double*
>(ptr),
112 static_cast<double*
>(ptr) + n);
115 p.check_params({
"pprecond",
"sprecond",
"block_size",
"active_rows",
"eps_dd",
"eps_ps",
"weights",
"weights_size" });
118 void get(
PropertyTree& p,
const std::string& path =
"")
const
120 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, pprecond);
121 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, sprecond);
122 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, block_size);
123 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, active_rows);
124 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, eps_dd);
125 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, eps_ps);
129 template <
class Matrix>
130 CPRDynamicRowSumPreconditioner(
const AlinaContext& context,
133 const backend_params& bprm = backend_params())
135 , n(backend::nbRow(K))
137 init(context, std::make_shared<build_matrix>(K), bprm,
142 std::shared_ptr<build_matrix> K,
144 const backend_params& bprm = backend_params())
146 , n(backend::nbRow(*K))
148 init(context, K, bprm,
152 template <
class Vec1,
class Vec2>
153 void apply(
const Vec1& rhs, Vec2&& x)
const
155 const auto one = math::identity<scalar_type>();
156 const auto zero = math::zero<scalar_type>();
158 ARCCORE_ALINA_TIC(
"sprecond");
160 ARCCORE_ALINA_TOC(
"sprecond");
161 backend::residual(rhs, S->system_matrix(), x, *rs);
163 backend::spmv(one, *Fpp, *rs, zero, *rp);
164 ARCCORE_ALINA_TIC(
"pprecond");
166 ARCCORE_ALINA_TOC(
"pprecond");
168 backend::spmv(one, *Scatter, *xp, one, x);
171 std::shared_ptr<matrix> system_matrix_ptr()
const
173 return S->system_matrix_ptr();
176 const matrix& system_matrix()
const
178 return S->system_matrix();
186 template <
class Matrix>
187 void partial_update(
const Matrix& K,
188 bool update_transfer_ops =
true,
189 const backend_params& bprm = backend_params())
191 auto K_ptr = std::make_shared<build_matrix>(K);
193 S = std::make_shared<SPrecond>(K_ptr, prm.sprecond, bprm);
194 if (update_transfer_ops) {
199 std::integral_constant<
bool, math::static_rows<value_type>::value == 1>());
209 std::shared_ptr<PPrecond> P;
210 std::shared_ptr<SPrecond> S;
212 std::shared_ptr<matrix_p> Fpp, Scatter;
213 std::shared_ptr<vector> rs;
214 std::shared_ptr<vector_p> rp, xp;
218 std::tuple<std::shared_ptr<build_matrix_p>, std::shared_ptr<build_matrix_p>>
219 first_scalar_pass(std::shared_ptr<build_matrix> K,
bool get_app =
true)
221 typedef typename backend::row_iterator<build_matrix>::type row_iterator;
222 const int B = prm.block_size;
223 const ptrdiff_t N = (prm.active_rows ? prm.active_rows : n);
227 auto fpp = std::make_shared<build_matrix_p>();
228 fpp->set_size(np, n);
229 fpp->set_nonzeros(n);
232 std::shared_ptr<build_matrix_p> App;
234 App = std::make_shared<build_matrix_p>();
235 App->set_size(np, np,
true);
239 std::vector<value_type> a_dia(B), a_off(B), a_top(B);
240 std::vector<row_iterator> k;
243 for (
Int32 ip = begin_ip; ip < (begin_ip + ip_size); ++ip) {
246 ptrdiff_t cur_col = 0;
248 std::fill(a_dia.begin(), a_dia.end(), 0);
249 std::fill(a_off.begin(), a_off.end(), 0);
250 std::fill(a_top.begin(), a_top.end(), 0);
253 for (
int i = 0; i < B; ++i) {
254 k.push_back(backend::row_begin(*K, ik + i));
256 if (k.back() && k.back().col() < N) {
257 ptrdiff_t col = k.back().col() / B;
263 cur_col = std::min(cur_col, col);
272 ptrdiff_t end = (cur_col + 1) * B;
274 for (
int i = 0; i < B; ++i) {
275 for (; k[i] && k[i].col() < end; ++k[i]) {
276 ptrdiff_t c = k[i].col() % B;
277 value_type v = k[i].value();
280 a_top[c] += std::abs(v);
288 a_off[i] += std::abs(v);
296 for (
int i = 0; i < B; ++i) {
297 if (k[i] && k[i].col() < N) {
298 ptrdiff_t col = k[i].col() / B;
304 cur_col = std::min(cur_col, col);
310 for (
int i = 0; i < B; ++i) {
311 fpp->col[ik + i] = ik + i;
314 if (!prm.weights.empty())
315 delta *= prm.weights[ik + i];
318 if (a_dia[i] < prm.eps_dd * a_off[i])
321 if (a_top[i] < prm.eps_ps * std::abs(a_dia[0]))
325 fpp->val[ik + i] = delta;
328 fpp->ptr[ip + 1] = ik + B;
332 App->set_nonzeros(App->scan_row_sizes());
334 return std::make_tuple(fpp, App);
337 void init(
const AlinaContext& context, std::shared_ptr<build_matrix> K,
const backend_params bprm, std::true_type)
339 typedef typename backend::row_iterator<build_matrix>::type row_iterator;
340 const int B = prm.block_size;
341 const ptrdiff_t N = (prm.active_rows ? prm.active_rows : n);
343 precondition(prm.weights.empty() || prm.weights.size() ==
static_cast<size_t>(N),
344 "CPR: weights size is not equal to number of active rows.");
348 std::shared_ptr<build_matrix_p> fpp, App;
349 std::tie(fpp, App) = first_scalar_pass(K);
351 auto scatter = std::make_shared<build_matrix_p>();
352 scatter->set_size(n, np);
353 scatter->set_nonzeros(np);
357 std::vector<row_iterator> k;
360 for (ptrdiff_t ip = begin_ip; ip < (begin_ip + ip_size); ++ip) {
361 ptrdiff_t ik = ip * B;
362 ptrdiff_t head = App->ptr[ip];
364 ptrdiff_t cur_col = 0;
366 value_type_p* d = &fpp->val[ik];
369 for (
int i = 0; i < B; ++i) {
370 k.push_back(backend::row_begin(*K, ik + i));
372 if (k.back() && k.back().col() < N) {
373 ptrdiff_t col = k.back().col() / B;
379 cur_col = std::min(cur_col, col);
385 ptrdiff_t end = (cur_col + 1) * B;
386 value_type_p app = 0;
388 for (
int i = 0; i < B; ++i) {
389 for (; k[i] && k[i].col() < end; ++k[i]) {
390 if (k[i].col() % B == 0) {
391 app += d[i] * k[i].value();
396 App->col[head] = cur_col;
397 App->val[head] = app;
402 for (
int i = 0; i < B; ++i) {
403 if (k[i] && k[i].col() < N) {
404 ptrdiff_t col = k[i].col() / B;
410 cur_col = std::min(cur_col, col);
416 scatter->col[ip] = ip;
417 scatter->val[ip] = math::identity<value_type>();
420 for (
int i = 0; i < B; ++i) {
423 scatter->ptr[ik + i + 1] = nnz;
428 for (
size_t i = N; i < n; ++i)
429 scatter->ptr[i + 1] = scatter->ptr[i];
431 ARCCORE_ALINA_TIC(
"pprecond");
432 P = std::make_shared<PPrecond>(context, App, prm.pprecond, bprm);
433 ARCCORE_ALINA_TOC(
"pprecond");
434 ARCCORE_ALINA_TIC(
"sprecond");
435 S = std::make_shared<SPrecond>(context, K, prm.sprecond, bprm);
436 ARCCORE_ALINA_TOC(
"sprecond");
438 Fpp = backend_type_p::copy_matrix(fpp, bprm);
439 Scatter = backend_type_p::copy_matrix(scatter, bprm);
441 rp = backend_type_p::create_vector(np, bprm);
442 xp = backend_type_p::create_vector(np, bprm);
443 rs = backend_type::create_vector(n, bprm);
446 void update_transfer(std::shared_ptr<build_matrix> K,
const backend_params bprm, std::true_type)
448 auto fpp = std::get<0>(first_scalar_pass(K,
false));
449 Fpp = backend_type_p::copy_matrix(fpp, bprm);
452 void init(
const AlinaContext& context, std::shared_ptr<build_matrix> K,
453 const backend_params bprm, std::false_type)
455 const int B = math::static_rows<value_type>::value;
456 const ptrdiff_t N = (prm.active_rows ? prm.active_rows : n);
459 prm.weights.empty() || prm.weights.size() ==
static_cast<size_t>(N * B),
460 "CPR: weights size is not equal to number of active rows.");
464 auto fpp = std::make_shared<build_matrix_p>();
465 fpp->set_size(np, np * B);
466 fpp->set_nonzeros(np * B);
469 auto scatter = std::make_shared<build_matrix_p>();
470 scatter->set_size(np * B, np);
471 scatter->set_nonzeros(np);
474 auto App = std::make_shared<build_matrix_p>();
475 App->set_size(np, np,
true);
476 App->set_nonzeros(K->nbNonZero());
480 for (ptrdiff_t i = begin_ip; i < (begin_ip + ip_size); ++i) {
481 ptrdiff_t ik = i * B;
482 for (
int k = 0; k < B; ++k, ++ik) {
484 scatter->ptr[ik + 1] = i + 1;
486 fpp->ptr[i + 1] = ik;
488 scatter->val[i] = math::identity<value_type_p>();
490 ptrdiff_t row_beg = K->ptr[i];
491 ptrdiff_t row_end = K->ptr[i + 1];
492 App->ptr[i + 1] = row_end;
494 value_type_p* d = &fpp->val[i * B];
495 const double* w = prm.weights.empty() ? nullptr : &prm.weights[i * B];
497 std::array<value_type_p, B> a_dia{};
498 std::array<value_type_p, B> a_off{};
499 std::array<value_type_p, B> a_top{};
501 for (ptrdiff_t j = row_beg; j < row_end; ++j) {
502 ptrdiff_t c = K->col[j];
503 value_type v = K->val[j];
505 for (
int k = 0; k < B; ++k) {
506 a_top[k] += std::abs(v(0, k));
511 a_off[k] += std::abs(v(k, 0));
516 for (
int k = 0; k < B; ++k) {
518 (a_dia[k] < prm.eps_dd * a_off[k] ||
519 a_top[k] < prm.eps_ps * std::abs(a_dia[0]))) {
523 d[k] = w ? w[k] : 1.0;
527 for (ptrdiff_t j = row_beg; j < row_end; ++j) {
528 App->col[j] = K->col[j];
530 value_type_p app = 0;
531 for (
int k = 0; k < B; ++k)
532 app += d[k] * K->val[j](k, 0);
539 ARCCORE_ALINA_TIC(
"pprecond");
540 P = std::make_shared<PPrecond>(context, App, prm.pprecond, bprm);
541 ARCCORE_ALINA_TOC(
"pprecond");
542 ARCCORE_ALINA_TIC(
"sprecond");
543 S = std::make_shared<SPrecond>(context, K, prm.sprecond, bprm);
544 ARCCORE_ALINA_TOC(
"sprecond");
546 Fpp = backend_type_p::copy_matrix(fpp, bprm);
547 Scatter = backend_type_p::copy_matrix(scatter, bprm);
549 rp = backend_type_p::create_vector(np, bprm);
550 xp = backend_type_p::create_vector(np, bprm);
551 rs = backend_type::create_vector(n, bprm);
554 void update_transfer(std::shared_ptr<build_matrix> K,
const backend_params bprm, std::false_type)
556 const int B = math::static_rows<value_type>::value;
557 const ptrdiff_t N = (prm.active_rows ? prm.active_rows : n);
559 precondition(prm.weights.empty() || prm.weights.size() ==
static_cast<size_t>(N * B),
560 "CPR: weights size is not equal to number of active rows.");
564 auto fpp = std::make_shared<build_matrix_p>();
565 fpp->set_size(np, np * B);
566 fpp->set_nonzeros(np * B);
570 for (ptrdiff_t i = begin_ip; i < (begin_ip + ip_size); ++i) {
572 ptrdiff_t ik = i * B;
573 for (
int k = 0; k < B; ++k, ++ik) {
576 fpp->ptr[i + 1] = ik;
578 ptrdiff_t row_beg = K->ptr[i];
579 ptrdiff_t row_end = K->ptr[i + 1];
581 value_type_p* d = &fpp->val[i * B];
582 const double* w = prm.weights.empty() ? nullptr : &prm.weights[i * B];
584 std::array<value_type_p, B> a_dia{};
585 std::array<value_type_p, B> a_off{};
586 std::array<value_type_p, B> a_top{};
588 for (ptrdiff_t j = row_beg; j < row_end; ++j) {
589 ptrdiff_t c = K->col[j];
590 value_type v = K->val[j];
592 for (
int k = 0; k < B; ++k) {
593 a_top[k] += std::abs(v(0, k));
598 a_off[k] += std::abs(v(k, 0));
603 for (
int k = 0; k < B; ++k) {
605 (a_dia[k] < prm.eps_dd * a_off[k] ||
606 a_top[k] < prm.eps_ps * std::abs(a_dia[0]))) {
610 d[k] = w ? w[k] : 1.0;
614 Fpp = backend_type_p::copy_matrix(fpp, bprm);
618 friend std::ostream& operator<<(std::ostream& os,
const CPRDynamicRowSumPreconditioner& p)
620 os <<
"CPR_DRS (two-stage preconditioner)\n"
621 "### Pressure preconditioner:\n"
623 "### Global preconditioner:\n"
624 << *p.S << std::endl;