45class CPRPreconditioner
48 "Pressure backend should have scalar value type!");
51 typename PPrecond::backend_type,
52 typename SPrecond::backend_type>::value,
53 "Backends for pressure and flow preconditioners should coincide!");
57 typedef typename SPrecond::backend_type backend_type;
58 typedef typename PPrecond::backend_type backend_type_p;
60 typedef typename backend_type::value_type value_type;
61 typedef typename backend_type::matrix matrix;
62 typedef typename backend_type::vector vector;
63 typedef typename backend_type_p::value_type value_type_p;
64 typedef typename backend_type_p::matrix matrix_p;
65 typedef typename backend_type_p::vector vector_p;
67 typedef typename backend_type::params backend_params;
69 typedef typename BuiltinBackend<value_type>::matrix build_matrix;
70 typedef typename BuiltinBackend<value_type_p>::matrix build_matrix_p;
72 typedef typename math::scalar_of<value_type>::type scalar_type;
76 typedef typename PPrecond::params pprecond_params;
77 typedef typename SPrecond::params sprecond_params;
79 pprecond_params pprecond;
80 sprecond_params sprecond;
84 Int32 active_rows = 0;
89 : ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p, pprecond)
90 , ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p, sprecond)
91 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, block_size)
92 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, active_rows)
94 p.check_params({
"pprecond",
"sprecond",
"block_size",
"active_rows" });
97 void get(
PropertyTree& p,
const std::string& path =
"")
const
99 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, pprecond);
100 ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, sprecond);
101 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, block_size);
102 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, active_rows);
106 template <
class Matrix>
107 CPRPreconditioner(
const Matrix& K,
109 const backend_params& bprm = backend_params())
111 , n(backend::nbRow(K))
113 init(std::make_shared<build_matrix>(K), bprm,
119 const backend_params& bprm = backend_params())
121 , n(backend::nbRow(*K))
127 template <
class Vec1,
class Vec2>
128 void apply(
const Vec1& rhs, Vec2&& x)
const
130 const auto one = math::identity<scalar_type>();
131 const auto zero = math::zero<scalar_type>();
133 ARCCORE_ALINA_TIC(
"sprecond");
135 ARCCORE_ALINA_TOC(
"sprecond");
136 backend::residual(rhs, S->system_matrix(), x, *rs);
138 backend::spmv(one, *Fpp, *rs, zero, *rp);
139 ARCCORE_ALINA_TIC(
"pprecond");
141 ARCCORE_ALINA_TOC(
"pprecond");
143 backend::spmv(one, *Scatter, *xp, one, x);
146 std::shared_ptr<matrix> system_matrix_ptr()
const
148 return S->system_matrix_ptr();
151 const matrix& system_matrix()
const
153 return S->system_matrix();
156 template <
class Matrix>
157 void partial_update(
const Matrix& K,
158 bool update_transfer_ops =
true,
159 const backend_params& bprm = backend_params())
161 auto K_ptr = std::make_shared<build_matrix>(K);
163 S = std::make_shared<SPrecond>(K_ptr, prm.sprecond, bprm);
164 if (update_transfer_ops) {
169 std::integral_constant<
bool, math::static_rows<value_type>::value == 1>());
179 std::shared_ptr<PPrecond> P;
180 std::shared_ptr<SPrecond> S;
182 std::shared_ptr<matrix_p> Fpp, Scatter;
183 std::shared_ptr<vector> rs;
184 std::shared_ptr<vector_p> rp, xp;
188 std::tuple<std::shared_ptr<build_matrix_p>, std::shared_ptr<build_matrix_p>>
189 first_scalar_pass(std::shared_ptr<build_matrix> K,
bool get_app =
true)
191 typedef typename backend::row_iterator<build_matrix>::type row_iterator;
192 const int B = prm.block_size;
193 const ptrdiff_t N = (prm.active_rows ? prm.active_rows : n);
197 auto fpp = std::make_shared<build_matrix_p>();
198 fpp->set_size(np, N);
199 fpp->set_nonzeros(N);
202 std::shared_ptr<build_matrix_p> App;
205 App = std::make_shared<build_matrix>();
206 App->set_size(np, np,
true);
212 std::vector<row_iterator> k;
214 multi_array<scalar_type, 2> v(B, B);
216 for (ptrdiff_t ip = begin; ip < (begin + size); ++ip) {
217 ptrdiff_t ik = ip * B;
219 ptrdiff_t cur_col = 0;
222 for (
int i = 0; i < B; ++i) {
223 k.push_back(backend::row_begin(*K, ik + i));
225 if (k.back() && k.back().col() < N) {
226 ptrdiff_t col = k.back().col() / B;
232 cur_col = std::min(cur_col, col);
236 fpp->col[ik + i] = ik + i;
238 fpp->ptr[ip + 1] = ik + B;
244 ptrdiff_t end = (cur_col + 1) * B;
250 for (
int i = 0; i < B; ++i)
251 for (
int j = 0; j < B; ++j)
254 for (
int i = 0; i < B; ++i)
255 for (; k[i] && k[i].col() < end; ++k[i])
256 v(k[i].col() % B, i) = k[i].value();
258 invert(v.data(), &fpp->val[ik]);
266 for (
int i = 0; i < B; ++i)
267 while (k[i] && k[i].col() < end)
273 for (
int i = 0; i < B; ++i) {
274 if (k[i] && k[i].col() < N) {
275 ptrdiff_t col = k[i].col() / B;
281 cur_col = std::min(cur_col, col);
290 App->set_nonzeros(App->scan_row_sizes());
292 return std::make_tuple(fpp, App);
296 void init(std::shared_ptr<build_matrix> K,
const backend_params bprm, std::true_type)
298 typedef typename backend::row_iterator<build_matrix>::type row_iterator;
299 const int B = prm.block_size;
300 const ptrdiff_t N = (prm.active_rows ? prm.active_rows : n);
304 std::shared_ptr<build_matrix_p> fpp, App;
305 std::tie(fpp, App) = first_scalar_pass(K);
307 auto scatter = std::make_shared<build_matrix_p>();
308 scatter->set_size(n, np);
309 scatter->set_nonzeros(np);
313 std::vector<row_iterator> k;
316 for (ptrdiff_t ip = begin; ip < (begin + size); ++ip) {
317 ptrdiff_t ik = ip * B;
318 ptrdiff_t head = App->ptr[ip];
322 value_type_p* d = &fpp->val[ik];
325 for (
int i = 0; i < B; ++i) {
326 k.push_back(backend::row_begin(*K, ik + i));
328 if (k.back() && k.back().col() < N) {
329 ptrdiff_t col = k.back().col() / B;
335 cur_col = std::min(cur_col, col);
341 ptrdiff_t end = (cur_col + 1) * B;
342 value_type_p app = 0;
344 for (
int i = 0; i < B; ++i) {
345 for (; k[i] && k[i].col() < end; ++k[i]) {
346 if (k[i].col() % B == 0) {
347 app += d[i] * k[i].value();
352 App->col[head] = cur_col;
353 App->val[head] = app;
358 for (
int i = 0; i < B; ++i) {
359 if (k[i] && k[i].col() < N) {
360 ptrdiff_t col = k[i].col() / B;
366 cur_col = std::min(cur_col, col);
372 scatter->col[ip] = ip;
373 scatter->val[ip] = math::identity<value_type_p>();
376 for (
int i = 0; i < B; ++i) {
379 scatter->ptr[ik + i + 1] = nnz;
384 for (
size_t i = N; i < n; ++i)
385 scatter->ptr[i + 1] = scatter->ptr[i];
387 ARCCORE_ALINA_TIC(
"pprecond");
388 P = std::make_shared<PPrecond>(App, prm.pprecond, bprm);
389 ARCCORE_ALINA_TOC(
"pprecond");
390 ARCCORE_ALINA_TIC(
"sprecond");
391 S = std::make_shared<SPrecond>(K, prm.sprecond, bprm);
392 ARCCORE_ALINA_TOC(
"sprecond");
394 Fpp = backend_type_p::copy_matrix(fpp, bprm);
395 Scatter = backend_type_p::copy_matrix(scatter, bprm);
397 rp = backend_type_p::create_vector(np, bprm);
398 xp = backend_type_p::create_vector(np, bprm);
399 rs = backend_type::create_vector(n, bprm);
402 void update_transfer(std::shared_ptr<build_matrix> K,
const backend_params bprm, std::true_type)
404 auto fpp = std::get<0>(first_scalar_pass(K,
false));
405 Fpp = backend_type_p::copy_matrix(fpp, bprm);
409 void init(std::shared_ptr<build_matrix> K,
const backend_params bprm, std::false_type)
411 const int B = math::static_rows<value_type>::value;
412 const ptrdiff_t N = (prm.active_rows ? prm.active_rows : n);
416 auto fpp = std::make_shared<build_matrix_p>();
417 fpp->set_size(np, np * B);
418 fpp->set_nonzeros(np * B);
421 auto scatter = std::make_shared<build_matrix_p>();
422 scatter->set_size(np * B, np);
423 scatter->set_nonzeros(np);
426 auto App = std::make_shared<build_matrix_p>();
427 App->set_size(np, np,
true);
428 App->set_nonzeros(K->nbNonZero());
432 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
433 ptrdiff_t ik = i * B;
434 for (
int k = 0; k < B; ++k, ++ik) {
436 scatter->ptr[ik + 1] = i + 1;
439 fpp->ptr[i + 1] = ik;
441 scatter->val[i] = math::identity<value_type_p>();
443 ptrdiff_t row_beg = K->ptr[i];
444 ptrdiff_t row_end = K->ptr[i + 1];
445 App->ptr[i + 1] = row_end;
448 value_type_p* d = &fpp->val[i * B];
449 for (ptrdiff_t j = row_beg; j < row_end; ++j) {
450 if (K->col[j] == i) {
451 value_type v = math::adjoint(K->val[j]);
457 for (ptrdiff_t j = row_beg; j < row_end; ++j) {
458 value_type_p app = 0;
459 for (
int k = 0; k < B; ++k)
460 app += d[k] * K->val[j](k, 0);
462 App->col[j] = K->col[j];
468 ARCCORE_ALINA_TIC(
"pprecond");
469 P = std::make_shared<PPrecond>(App, prm.pprecond, bprm);
470 ARCCORE_ALINA_TOC(
"pprecond");
471 ARCCORE_ALINA_TIC(
"sprecond");
472 S = std::make_shared<SPrecond>(K, prm.sprecond, bprm);
473 ARCCORE_ALINA_TOC(
"sprecond");
475 Fpp = backend_type_p::copy_matrix(fpp, bprm);
476 Scatter = backend_type_p::copy_matrix(scatter, bprm);
478 rp = backend_type_p::create_vector(np, bprm);
479 xp = backend_type_p::create_vector(np, bprm);
480 rs = backend_type::create_vector(n, bprm);
483 void update_transfer(std::shared_ptr<build_matrix> K,
const backend_params bprm, std::false_type)
485 const int B = math::static_rows<value_type>::value;
486 const ptrdiff_t N = (prm.active_rows ? prm.active_rows : n);
490 auto fpp = std::make_shared<build_matrix_p>();
491 fpp->set_size(np, np * B);
492 fpp->set_nonzeros(np * B);
496 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
497 ptrdiff_t ik = i * B;
498 for (
int k = 0; k < B; ++k, ++ik) {
502 fpp->ptr[i + 1] = ik;
504 ptrdiff_t row_beg = K->ptr[i];
505 ptrdiff_t row_end = K->ptr[i + 1];
508 value_type_p* d = &fpp->val[i * B];
509 for (ptrdiff_t j = row_beg; j < row_end; ++j) {
510 if (K->col[j] == i) {
511 value_type v = math::adjoint(K->val[j]);
518 Fpp = backend_type_p::copy_matrix(fpp, bprm);
523 void invert(scalar_type* A, value_type_p* y)
525 const int B = math::static_rows<value_type>::value == 1 ? prm.block_size : math::static_rows<value_type>::value;
528 for (
int k = 0; k < B; ++k) {
529 scalar_type d = A[k * B + k];
530 assert(!math::is_zero(d));
531 for (
int i = k + 1; i < B; ++i) {
533 for (
int j = k + 1; j < B; ++j)
534 A[i * B + j] -= A[i * B + k] * A[k * B + j];
540 for (
int i = 0; i < B; ++i) {
541 value_type_p b =
static_cast<value_type_p
>(i == 0);
542 for (
int j = 0; j < i; ++j)
543 b -= A[i * B + j] * y[j];
548 for (
int i = B; i-- > 0;) {
549 for (
int j = i + 1; j < B; ++j)
550 y[i] -= A[i * B + j] * y[j];
551 y[i] /= A[i * B + i];
555 friend std::ostream& operator<<(std::ostream& os,
const CPRPreconditioner& p)
557 os <<
"CPR (two-stage preconditioner)\n"
558 "### Pressure preconditioner:\n"
560 "### Global preconditioner:\n"
561 << *p.S << std::endl;