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 Matrix& K,
132 const backend_params& bprm = backend_params())
134 , n(backend::nbRow(K))
136 init(std::make_shared<build_matrix>(K), bprm,
142 const backend_params& bprm = backend_params())
144 , n(backend::nbRow(*K))
150 template <
class Vec1,
class Vec2>
151 void apply(
const Vec1& rhs, Vec2&& x)
const
153 const auto one = math::identity<scalar_type>();
154 const auto zero = math::zero<scalar_type>();
156 ARCCORE_ALINA_TIC(
"sprecond");
158 ARCCORE_ALINA_TOC(
"sprecond");
159 backend::residual(rhs, S->system_matrix(), x, *rs);
161 backend::spmv(one, *Fpp, *rs, zero, *rp);
162 ARCCORE_ALINA_TIC(
"pprecond");
164 ARCCORE_ALINA_TOC(
"pprecond");
166 backend::spmv(one, *Scatter, *xp, one, x);
169 std::shared_ptr<matrix> system_matrix_ptr()
const
171 return S->system_matrix_ptr();
174 const matrix& system_matrix()
const
176 return S->system_matrix();
184 template <
class Matrix>
185 void partial_update(
const Matrix& K,
186 bool update_transfer_ops =
true,
187 const backend_params& bprm = backend_params())
189 auto K_ptr = std::make_shared<build_matrix>(K);
191 S = std::make_shared<SPrecond>(K_ptr, prm.sprecond, bprm);
192 if (update_transfer_ops) {
197 std::integral_constant<
bool, math::static_rows<value_type>::value == 1>());
207 std::shared_ptr<PPrecond> P;
208 std::shared_ptr<SPrecond> S;
210 std::shared_ptr<matrix_p> Fpp, Scatter;
211 std::shared_ptr<vector> rs;
212 std::shared_ptr<vector_p> rp, xp;
216 std::tuple<std::shared_ptr<build_matrix_p>, std::shared_ptr<build_matrix_p>>
217 first_scalar_pass(std::shared_ptr<build_matrix> K,
bool get_app =
true)
219 typedef typename backend::row_iterator<build_matrix>::type row_iterator;
220 const int B = prm.block_size;
221 const ptrdiff_t N = (prm.active_rows ? prm.active_rows : n);
225 auto fpp = std::make_shared<build_matrix_p>();
226 fpp->set_size(np, n);
227 fpp->set_nonzeros(n);
230 std::shared_ptr<build_matrix_p> App;
232 App = std::make_shared<build_matrix_p>();
233 App->set_size(np, np,
true);
237 std::vector<value_type> a_dia(B), a_off(B), a_top(B);
238 std::vector<row_iterator> k;
241 for (
Int32 ip = begin_ip; ip < (begin_ip + ip_size); ++ip) {
244 ptrdiff_t cur_col = 0;
246 std::fill(a_dia.begin(), a_dia.end(), 0);
247 std::fill(a_off.begin(), a_off.end(), 0);
248 std::fill(a_top.begin(), a_top.end(), 0);
251 for (
int i = 0; i < B; ++i) {
252 k.push_back(backend::row_begin(*K, ik + i));
254 if (k.back() && k.back().col() < N) {
255 ptrdiff_t col = k.back().col() / B;
261 cur_col = std::min(cur_col, col);
270 ptrdiff_t end = (cur_col + 1) * B;
272 for (
int i = 0; i < B; ++i) {
273 for (; k[i] && k[i].col() < end; ++k[i]) {
274 ptrdiff_t c = k[i].col() % B;
275 value_type v = k[i].value();
278 a_top[c] += std::abs(v);
286 a_off[i] += std::abs(v);
294 for (
int i = 0; i < B; ++i) {
295 if (k[i] && k[i].col() < N) {
296 ptrdiff_t col = k[i].col() / B;
302 cur_col = std::min(cur_col, col);
308 for (
int i = 0; i < B; ++i) {
309 fpp->col[ik + i] = ik + i;
312 if (!prm.weights.empty())
313 delta *= prm.weights[ik + i];
316 if (a_dia[i] < prm.eps_dd * a_off[i])
319 if (a_top[i] < prm.eps_ps * std::abs(a_dia[0]))
323 fpp->val[ik + i] = delta;
326 fpp->ptr[ip + 1] = ik + B;
330 App->set_nonzeros(App->scan_row_sizes());
332 return std::make_tuple(fpp, App);
335 void init(std::shared_ptr<build_matrix> K,
const backend_params bprm, std::true_type)
337 typedef typename backend::row_iterator<build_matrix>::type row_iterator;
338 const int B = prm.block_size;
339 const ptrdiff_t N = (prm.active_rows ? prm.active_rows : n);
341 precondition(prm.weights.empty() || prm.weights.size() ==
static_cast<size_t>(N),
342 "CPR: weights size is not equal to number of active rows.");
346 std::shared_ptr<build_matrix_p> fpp, App;
347 std::tie(fpp, App) = first_scalar_pass(K);
349 auto scatter = std::make_shared<build_matrix_p>();
350 scatter->set_size(n, np);
351 scatter->set_nonzeros(np);
355 std::vector<row_iterator> k;
358 for (ptrdiff_t ip = begin_ip; ip < (begin_ip + ip_size); ++ip) {
359 ptrdiff_t ik = ip * B;
360 ptrdiff_t head = App->ptr[ip];
362 ptrdiff_t cur_col = 0;
364 value_type_p* d = &fpp->val[ik];
367 for (
int i = 0; i < B; ++i) {
368 k.push_back(backend::row_begin(*K, ik + i));
370 if (k.back() && k.back().col() < N) {
371 ptrdiff_t col = k.back().col() / B;
377 cur_col = std::min(cur_col, col);
383 ptrdiff_t end = (cur_col + 1) * B;
384 value_type_p app = 0;
386 for (
int i = 0; i < B; ++i) {
387 for (; k[i] && k[i].col() < end; ++k[i]) {
388 if (k[i].col() % B == 0) {
389 app += d[i] * k[i].value();
394 App->col[head] = cur_col;
395 App->val[head] = app;
400 for (
int i = 0; i < B; ++i) {
401 if (k[i] && k[i].col() < N) {
402 ptrdiff_t col = k[i].col() / B;
408 cur_col = std::min(cur_col, col);
414 scatter->col[ip] = ip;
415 scatter->val[ip] = math::identity<value_type>();
418 for (
int i = 0; i < B; ++i) {
421 scatter->ptr[ik + i + 1] = nnz;
426 for (
size_t i = N; i < n; ++i)
427 scatter->ptr[i + 1] = scatter->ptr[i];
429 ARCCORE_ALINA_TIC(
"pprecond");
430 P = std::make_shared<PPrecond>(App, prm.pprecond, bprm);
431 ARCCORE_ALINA_TOC(
"pprecond");
432 ARCCORE_ALINA_TIC(
"sprecond");
433 S = std::make_shared<SPrecond>(K, prm.sprecond, bprm);
434 ARCCORE_ALINA_TOC(
"sprecond");
436 Fpp = backend_type_p::copy_matrix(fpp, bprm);
437 Scatter = backend_type_p::copy_matrix(scatter, bprm);
439 rp = backend_type_p::create_vector(np, bprm);
440 xp = backend_type_p::create_vector(np, bprm);
441 rs = backend_type::create_vector(n, bprm);
444 void update_transfer(std::shared_ptr<build_matrix> K,
const backend_params bprm, std::true_type)
446 auto fpp = std::get<0>(first_scalar_pass(K,
false));
447 Fpp = backend_type_p::copy_matrix(fpp, bprm);
450 void init(std::shared_ptr<build_matrix> K,
const backend_params bprm, std::false_type)
452 const int B = math::static_rows<value_type>::value;
453 const ptrdiff_t N = (prm.active_rows ? prm.active_rows : n);
456 prm.weights.empty() || prm.weights.size() ==
static_cast<size_t>(N * B),
457 "CPR: weights size is not equal to number of active rows.");
461 auto fpp = std::make_shared<build_matrix_p>();
462 fpp->set_size(np, np * B);
463 fpp->set_nonzeros(np * B);
466 auto scatter = std::make_shared<build_matrix_p>();
467 scatter->set_size(np * B, np);
468 scatter->set_nonzeros(np);
471 auto App = std::make_shared<build_matrix_p>();
472 App->set_size(np, np,
true);
473 App->set_nonzeros(K->nbNonZero());
477 for (ptrdiff_t i = begin_ip; i < (begin_ip + ip_size); ++i) {
478 ptrdiff_t ik = i * B;
479 for (
int k = 0; k < B; ++k, ++ik) {
481 scatter->ptr[ik + 1] = i + 1;
483 fpp->ptr[i + 1] = ik;
485 scatter->val[i] = math::identity<value_type_p>();
487 ptrdiff_t row_beg = K->ptr[i];
488 ptrdiff_t row_end = K->ptr[i + 1];
489 App->ptr[i + 1] = row_end;
491 value_type_p* d = &fpp->val[i * B];
492 const double* w = prm.weights.empty() ? nullptr : &prm.weights[i * B];
494 std::array<value_type_p, B> a_dia{};
495 std::array<value_type_p, B> a_off{};
496 std::array<value_type_p, B> a_top{};
498 for (ptrdiff_t j = row_beg; j < row_end; ++j) {
499 ptrdiff_t c = K->col[j];
500 value_type v = K->val[j];
502 for (
int k = 0; k < B; ++k) {
503 a_top[k] += std::abs(v(0, k));
508 a_off[k] += std::abs(v(k, 0));
513 for (
int k = 0; k < B; ++k) {
515 (a_dia[k] < prm.eps_dd * a_off[k] ||
516 a_top[k] < prm.eps_ps * std::abs(a_dia[0]))) {
520 d[k] = w ? w[k] : 1.0;
524 for (ptrdiff_t j = row_beg; j < row_end; ++j) {
525 App->col[j] = K->col[j];
527 value_type_p app = 0;
528 for (
int k = 0; k < B; ++k)
529 app += d[k] * K->val[j](k, 0);
536 ARCCORE_ALINA_TIC(
"pprecond");
537 P = std::make_shared<PPrecond>(App, prm.pprecond, bprm);
538 ARCCORE_ALINA_TOC(
"pprecond");
539 ARCCORE_ALINA_TIC(
"sprecond");
540 S = std::make_shared<SPrecond>(K, prm.sprecond, bprm);
541 ARCCORE_ALINA_TOC(
"sprecond");
543 Fpp = backend_type_p::copy_matrix(fpp, bprm);
544 Scatter = backend_type_p::copy_matrix(scatter, bprm);
546 rp = backend_type_p::create_vector(np, bprm);
547 xp = backend_type_p::create_vector(np, bprm);
548 rs = backend_type::create_vector(n, bprm);
551 void update_transfer(std::shared_ptr<build_matrix> K,
const backend_params bprm, std::false_type)
553 const int B = math::static_rows<value_type>::value;
554 const ptrdiff_t N = (prm.active_rows ? prm.active_rows : n);
556 precondition(prm.weights.empty() || prm.weights.size() ==
static_cast<size_t>(N * B),
557 "CPR: weights size is not equal to number of active rows.");
561 auto fpp = std::make_shared<build_matrix_p>();
562 fpp->set_size(np, np * B);
563 fpp->set_nonzeros(np * B);
567 for (ptrdiff_t i = begin_ip; i < (begin_ip + ip_size); ++i) {
569 ptrdiff_t ik = i * B;
570 for (
int k = 0; k < B; ++k, ++ik) {
573 fpp->ptr[i + 1] = ik;
575 ptrdiff_t row_beg = K->ptr[i];
576 ptrdiff_t row_end = K->ptr[i + 1];
578 value_type_p* d = &fpp->val[i * B];
579 const double* w = prm.weights.empty() ? nullptr : &prm.weights[i * B];
581 std::array<value_type_p, B> a_dia{};
582 std::array<value_type_p, B> a_off{};
583 std::array<value_type_p, B> a_top{};
585 for (ptrdiff_t j = row_beg; j < row_end; ++j) {
586 ptrdiff_t c = K->col[j];
587 value_type v = K->val[j];
589 for (
int k = 0; k < B; ++k) {
590 a_top[k] += std::abs(v(0, k));
595 a_off[k] += std::abs(v(k, 0));
600 for (
int k = 0; k < B; ++k) {
602 (a_dia[k] < prm.eps_dd * a_off[k] ||
603 a_top[k] < prm.eps_ps * std::abs(a_dia[0]))) {
607 d[k] = w ? w[k] : 1.0;
611 Fpp = backend_type_p::copy_matrix(fpp, bprm);
615 friend std::ostream& operator<<(std::ostream& os,
const CPRDynamicRowSumPreconditioner& p)
617 os <<
"CPR_DRS (two-stage preconditioner)\n"
618 "### Pressure preconditioner:\n"
620 "### Global preconditioner:\n"
621 << *p.S << std::endl;