Arcane  v4.1.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
SchurPressureCorrectionPreconditioner.h
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* SchurPressureCorrectionPreconditioner.h (C) 2000-2026 */
9/* */
10/* Schur-complement pressure correction preconditioning scheme. */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCCORE_ALINA_PRECONDITIONERSCHURPRESSURECORRECTION_H
13#define ARCCORE_ALINA_PRECONDITIONERSCHURPRESSURECORRECTION_H
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16/*
17 * This file is based on the work on AMGCL library (version march 2026)
18 * which can be found at https://github.com/ddemidov/amgcl.
19 *
20 * Copyright (c) 2012-2022 Denis Demidov <dennis.demidov@gmail.com>
21 * SPDX-License-Identifier: MIT
22 */
23/*---------------------------------------------------------------------------*/
24/*---------------------------------------------------------------------------*/
25/*
26 * This algorithm is based on the following articles.
27 *
28 * [1] Elman, Howard, et al. "A taxonomy and comparison of parallel block
29 * multi-level preconditioners for the incompressible Navier–Stokes
30 * equations." Journal of Computational Physics 227.3 (2008): 1790-1808.
31 * [2] Gmeiner, Björn, et al. "A quantitative performance analysis for Stokes
32 * solvers at the extreme scale." arXiv preprint arXiv:1511.02134 (2015).
33 * [3] Vincent, C., and R. Boyer. "A preconditioned conjugate gradient
34 * Uzawa‐type method for the solution of the Stokes problem by mixed Q1–P0
35 * stabilized finite elements." International journal for numerical methods
36 * in fluids 14.3 (1992): 289-298.
37 */
38/*---------------------------------------------------------------------------*/
39/*---------------------------------------------------------------------------*/
40
41#include "arccore/alina/BuiltinBackend.h"
42#include "arccore/alina/AlinaUtils.h"
43#include "arccore/alina/IO.h"
44
45/*---------------------------------------------------------------------------*/
46/*---------------------------------------------------------------------------*/
47
48namespace Arcane::Alina::preconditioner
49{
50
51/*---------------------------------------------------------------------------*/
52/*---------------------------------------------------------------------------*/
53
55template <class USolver, class PSolver>
56class SchurPressureCorrectionPreconditioner
57{
58 static_assert(backend::backends_compatible<typename USolver::backend_type,
59 typename PSolver::backend_type>::value,
60 "Backends for pressure and flow preconditioners should coincide!");
61
62 public:
63
64 typedef typename detail::common_scalar_backend<typename USolver::backend_type,
65 typename PSolver::backend_type>::type backend_type;
66
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;
74
75 typedef typename BuiltinBackend<value_type, col_type, ptr_type>::matrix build_matrix;
76
77 struct params
78 {
79 typedef typename USolver::params usolver_params;
80 typedef typename PSolver::params psolver_params;
81
82 usolver_params usolver;
83 psolver_params psolver;
84
85 std::vector<char> pmask;
86
87 // Variant of block preconditioner to use in apply()
88 // 1: schur pressure correction:
89 // S p = fp - Kpu Kuu^-1 fu
90 // Kuu u = fu - Kup p
91 // 2: Block triangular:
92 // S p = fp
93 // Kuu u = fu - Kup p
94 int type;
95
96 // Approximate Kuu^-1 with inverted diagonal of Kuu during
97 // construction of matrix-less Schur complement.
98 // When false, USolver is used instead.
99 bool approx_schur;
100
101 // Adjust preconditioner matrix for the Schur complement system.
102 // That is, use
103 // Kpp when adjust_p == 0,
104 // Kpp - dia(Kpu * dia(Kuu)^-1 * Kup) when adjust_p == 1,
105 // Kpp - Kpu * dia(Kuu)^-1 * Kup when adjust_p == 2
106 int adjust_p;
107
108 // Use 1/sum_j(abs(Kuu_{i,j})) instead of dia(Kuu)^-1
109 // as approximation for the Kuu^-1 (as in SIMPLEC algorithm)
110 bool simplec_dia;
111
112 int verbose;
113
114 params()
115 : type(1)
116 , approx_schur(false)
117 , adjust_p(1)
118 , simplec_dia(true)
119 , verbose(0)
120 {}
121
122 params(const PropertyTree& p)
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)
130 {
131 size_t n = 0;
132
133 n = p.get("pmask_size", n);
134
135 precondition(n > 0,
136 "Error in schur_complement parameters: "
137 "pmask_size is not set");
138
139 if (p.count("pmask_pattern")) {
140 pmask.resize(n, 0);
141
142 std::string pattern = p.get("pmask_pattern", std::string());
143 switch (pattern[0]) {
144 case '%': {
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)
148 pmask[i] = 1;
149 } break;
150 case '<': {
151 size_t m = std::atoi(pattern.c_str() + 1);
152 for (size_t i = 0; i < std::min(m, n); ++i)
153 pmask[i] = 1;
154 } break;
155 case '>': {
156 size_t m = std::atoi(pattern.c_str() + 1);
157 for (size_t i = m; i < n; ++i)
158 pmask[i] = 1;
159 } break;
160 default:
161 precondition(false, "Unknown pattern in pmask_pattern");
162 }
163 }
164 else if (p.count("pmask")) {
165 void* pm = 0;
166 pm = p.get("pmask", pm);
167 pmask.assign(static_cast<char*>(pm), static_cast<char*>(pm) + n);
168 }
169 else {
170 precondition(false,
171 "Error in schur_complement parameters: "
172 "neither pmask_pattern, nor pmask is set");
173 }
174
175 p.check_params({ "usolver", "psolver", "type", "approx_schur", "adjust_p", "simplec_dia", "pmask_size", "verbose" },
176 { "pmask", "pmask_pattern" });
177 }
178
179 void get(PropertyTree& p, const std::string& path = "") const
180 {
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);
188 }
189 };
190
191 template <class Matrix>
192 SchurPressureCorrectionPreconditioner(const Matrix& K,
193 const params& prm = params(),
194 const backend_params& bprm = backend_params())
195 : prm(prm)
196 , n(backend::nbRow(K))
197 , np(0)
198 , nu(0)
199 {
200 init(std::make_shared<build_matrix>(K), bprm);
201 }
202
203 SchurPressureCorrectionPreconditioner(std::shared_ptr<build_matrix> K,
204 const params& prm = params(),
205 const backend_params& bprm = backend_params())
206 : prm(prm)
207 , n(backend::nbRow(*K))
208 , np(0)
209 , nu(0)
210 {
211 init(K, bprm);
212 }
213
214 template <class Vec1, class Vec2>
215 void apply(const Vec1& rhs, Vec2&& x) const
216 {
217 const auto one = math::identity<scalar_type>();
218 const auto zero = math::zero<scalar_type>();
219
220 backend::spmv(one, *x2u, rhs, zero, *rhs_u);
221 backend::spmv(one, *x2p, rhs, zero, *rhs_p);
222
223 if (prm.type == 1) {
224 // Kuu u = rhs_u
225 backend::clear(*u);
226 report("U1", (*U)(*rhs_u, *u));
227
228 // rhs_p -= Kpu u
229 backend::spmv(-one, *Kpu, *u, one, *rhs_p);
230
231 // S p = rhs_p
232 backend::clear(*p);
233 report("P1", (*P)(*this, *rhs_p, *p));
234
235 // rhs_u -= Kup p
236 backend::spmv(-one, *Kup, *p, one, *rhs_u);
237
238 // Kuu u = rhs_u
239 backend::clear(*u);
240 report("U2", (*U)(*rhs_u, *u));
241 }
242 else if (prm.type == 2) {
243 // S p = fp
244 backend::clear(*p);
245 report("P", (*P)(*this, *rhs_p, *p));
246
247 // Kuu u = fu - Kup p
248 backend::spmv(-one, *Kup, *p, one, *rhs_u);
249 backend::clear(*u);
250 report("U", (*U)(*rhs_u, *u));
251 }
252
253 backend::spmv(one, *u2x, *u, zero, x);
254 backend::spmv(one, *p2x, *p, one, x);
255 }
256
257 template <class Alpha, class Vec1, class Beta, class Vec2>
258 void spmv(Alpha alpha, const Vec1& x, Beta beta, Vec2& y) const
259 {
260 const auto one = math::identity<scalar_type>();
261 const auto zero = math::zero<scalar_type>();
262
263 // y = beta y + alpha S x, where S = Kpp - Kpu Kuu^-1 Kup
264 if (prm.adjust_p == 1) {
265 backend::spmv(alpha, P->system_matrix(), x, beta, y);
266 backend::vmul(alpha, *Ld, x, one, y);
267 }
268 else if (prm.adjust_p == 2) {
269 backend::spmv(alpha, *Lm, x, beta, y);
270 }
271 else {
272 backend::spmv(alpha, P->system_matrix(), x, beta, y);
273 }
274
275 backend::spmv(one, *Kup, x, zero, *tmp);
276
277 if (prm.approx_schur) {
278 backend::vmul(one, *M, *tmp, zero, *u);
279 }
280 else {
281 backend::clear(*u);
282 (*U)(*tmp, *u);
283 }
284
285 backend::spmv(-alpha, *Kpu, *u, one, y);
286 }
287
288 std::shared_ptr<matrix> system_matrix_ptr() const
289 {
290 return K;
291 }
292
293 const matrix& system_matrix() const
294 {
295 return *K;
296 }
297
298 size_t bytes() const
299 {
300 size_t b = 0;
301
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);
316
317 if (M)
318 b += backend::bytes(*M);
319 if (Ld)
320 b += backend::bytes(*Ld);
321 if (Lm)
322 b += backend::bytes(*Lm);
323
324 return b;
325 }
326
327 params prm;
328
329 private:
330
331 size_t n, np, nu;
332
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;
337
338 std::shared_ptr<USolver> U;
339 std::shared_ptr<PSolver> P;
340
341 void init(const std::shared_ptr<build_matrix>& K, const backend_params& bprm)
342 {
343 this->K = backend_type::copy_matrix(K, bprm);
344
345 // Extract matrix subblocks.
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>();
350
351 std::vector<ptrdiff_t> idx(n);
352
353 for (size_t i = 0; i < n; ++i)
354 idx[i] = (prm.pmask[i] ? np++ : nu++);
355
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);
360
361 arccoreParallelFor(0, n, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
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()];
367
368 if (pi) {
369 if (pj) {
370 ++Kpp->ptr[ci + 1];
371 }
372 else {
373 ++Kpu->ptr[ci + 1];
374 }
375 }
376 else {
377 if (pj) {
378 ++Kup->ptr[ci + 1];
379 }
380 else {
381 ++Kuu->ptr[ci + 1];
382 }
383 }
384 }
385 }
386 });
387
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());
392
393 arccoreParallelFor(0, n, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
394 for (ptrdiff_t i = begin; i < (begin + size); ++i) {
395 ptrdiff_t ci = idx[i];
396 char pi = prm.pmask[i];
397
398 ptrdiff_t uu_head = 0, up_head = 0, pu_head = 0, pp_head = 0;
399
400 if (pi) {
401 pu_head = Kpu->ptr[ci];
402 pp_head = Kpp->ptr[ci];
403 }
404 else {
405 uu_head = Kuu->ptr[ci];
406 up_head = Kup->ptr[ci];
407 }
408
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];
414
415 if (pi) {
416 if (pj) {
417 Kpp->col[pp_head] = cj;
418 Kpp->val[pp_head] = v;
419 ++pp_head;
420 }
421 else {
422 Kpu->col[pu_head] = cj;
423 Kpu->val[pu_head] = v;
424 ++pu_head;
425 }
426 }
427 else {
428 if (pj) {
429 Kup->col[up_head] = cj;
430 Kup->val[up_head] = v;
431 ++up_head;
432 }
433 else {
434 Kuu->col[uu_head] = cj;
435 Kuu->val[uu_head] = v;
436 ++uu_head;
437 }
438 }
439 }
440 }
441 });
442
443 if (prm.verbose >= 2) {
444 IO::mm_write("Kuu.mtx", *Kuu);
445 IO::mm_write("Kpp.mtx", *Kpp);
446 }
447
448 std::shared_ptr<numa_vector<value_type>> Kuu_dia;
449
450 if (prm.simplec_dia) {
451 Kuu_dia = std::make_shared<numa_vector<value_type>>(nu);
452 arccoreParallelFor(0, nu, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
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]);
457 }
458 (*Kuu_dia)[i] = math::inverse(s);
459 }
460 });
461 }
462 else {
463 Kuu_dia = diagonal(*Kuu, /*invert = */ true);
464 }
465
466 if (prm.adjust_p == 1) {
467 // Use (Kpp - dia(Kpu * dia(Kuu)^-1 * Kup))
468 // to setup the P preconditioner.
469 auto L = std::make_shared<numa_vector<value_type>>(np, false);
470
471 arccoreParallelFor(0, np, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
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];
480 break;
481 }
482 }
483 }
484
485 (*L)[i] = s;
486 for (ptrdiff_t j = Kpp->ptr[i], e = Kpp->ptr[i + 1]; j < e; ++j) {
487 if (Kpp->col[j] == i) {
488 Kpp->val[j] -= s;
489 break;
490 }
491 }
492 }
493 });
494 Ld = backend_type::copy_vector(L, bprm);
495 }
496 else if (prm.adjust_p == 2) {
497 Lm = backend_type::copy_matrix(Kpp, bprm);
498
499 // Use (Kpp - Kpu * dia(Kuu)^-1 * Kup)
500 // to setup the P preconditioner.
501 numa_vector<value_type> val(Kup->nbNonZero());
502
503 arccoreParallelFor(0, nu, ForLoopRunInfo{}, [&](Int32 begin, Int32 size) {
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];
508 }
509 }
510 });
511
512 build_matrix Kup_hat;
513
514 Kup_hat.own_data = false;
515 Kup_hat.setNbRow(nu);
516 Kup_hat.ncols = np;
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());
521
522 Kpp = sum(math::identity<value_type>(), *Kpp, -math::identity<value_type>(), *product(*Kpu, Kup_hat));
523 }
524
525 U = std::make_shared<USolver>(*Kuu, prm.usolver, bprm);
526 P = std::make_shared<PSolver>(*Kpp, prm.psolver, bprm);
527
528 this->Kup = backend_type::copy_matrix(Kup, bprm);
529 this->Kpu = backend_type::copy_matrix(Kpu, bprm);
530
531 rhs_u = backend_type::create_vector(nu, bprm);
532 rhs_p = backend_type::create_vector(np, bprm);
533
534 u = backend_type::create_vector(nu, bprm);
535 p = backend_type::create_vector(np, bprm);
536
537 tmp = backend_type::create_vector(nu, bprm);
538
539 if (prm.approx_schur)
540 M = backend_type::copy_vector(Kuu_dia, bprm);
541
542 // Scatter/Gather matrices
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>();
547
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);
552
553 {
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;
558
559 for (size_t i = 0; i < n; ++i) {
560 if (prm.pmask[i]) {
561 x2p->ptr[++x2p_idx] = ++x2p_head;
562 ++p2x_head;
563 }
564 else {
565 x2u->ptr[++x2u_idx] = ++x2u_head;
566 ++u2x_head;
567 }
568
569 p2x->ptr[++p2x_idx] = p2x_head;
570 u2x->ptr[++u2x_idx] = u2x_head;
571 }
572 }
573
574 x2u->set_nonzeros();
575 x2p->set_nonzeros();
576 u2x->set_nonzeros();
577 p2x->set_nonzeros();
578
579 {
580 ptrdiff_t x2u_head = 0;
581 ptrdiff_t x2p_head = 0;
582 ptrdiff_t u2x_head = 0;
583 ptrdiff_t p2x_head = 0;
584
585 for (size_t i = 0; i < n; ++i) {
586 ptrdiff_t j = idx[i];
587
588 if (prm.pmask[i]) {
589 x2p->col[x2p_head] = i;
590 x2p->val[x2p_head] = math::identity<value_type>();
591 ++x2p_head;
592
593 p2x->col[p2x_head] = j;
594 p2x->val[p2x_head] = math::identity<value_type>();
595 ++p2x_head;
596 }
597 else {
598 x2u->col[x2u_head] = i;
599 x2u->val[x2u_head] = math::identity<value_type>();
600 ++x2u_head;
601
602 u2x->col[u2x_head] = j;
603 u2x->val[u2x_head] = math::identity<value_type>();
604 ++u2x_head;
605 }
606 }
607 }
608
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);
613 }
614
615 friend std::ostream& operator<<(std::ostream& os, const SchurPressureCorrectionPreconditioner& p)
616 {
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;
621 os << std::endl;
622 os << "[ U ]\n"
623 << *p.U << std::endl;
624 os << "[ P ]\n"
625 << *p.P << std::endl;
626
627 return os;
628 }
629
630 void report(const std::string& name, const SolverResult& r) const
631 {
632 if (prm.verbose >= 1) {
633 std::cout << name << " (" << r.nbIteration() << ", " << r.residual() << ")\n";
634 }
635 }
636};
637
638/*---------------------------------------------------------------------------*/
639/*---------------------------------------------------------------------------*/
640
641} // namespace Arcane::Alina::preconditioner
642
643/*---------------------------------------------------------------------------*/
644/*---------------------------------------------------------------------------*/
645
646namespace Arcane::Alina::backend
647{
648
649/*---------------------------------------------------------------------------*/
650/*---------------------------------------------------------------------------*/
651
652template <class US, class PS, class Alpha, class Beta, class Vec1, class Vec2>
653struct spmv_impl<Alpha, preconditioner::SchurPressureCorrectionPreconditioner<US, PS>, Vec1, Beta, Vec2>
654{
655 static void apply(Alpha alpha, const preconditioner::SchurPressureCorrectionPreconditioner<US, PS>& A, const Vec1& x, Beta beta, Vec2& y)
656 {
657 A.spmv(alpha, x, beta, y);
658 }
659};
660
661template <class US, class PS, class Vec1, class Vec2, class Vec3>
662struct residual_impl<preconditioner::SchurPressureCorrectionPreconditioner<US, PS>, Vec1, Vec2, Vec3>
663{
664 static void apply(const Vec1& rhs, const preconditioner::SchurPressureCorrectionPreconditioner<US, PS>& A, const Vec2& x, Vec3& r)
665 {
666 backend::copy(rhs, r);
667 A.spmv(-1, x, 1, r);
668 }
669};
670
671/*---------------------------------------------------------------------------*/
672/*---------------------------------------------------------------------------*/
673
674} // namespace Arcane::Alina::backend
675
676/*---------------------------------------------------------------------------*/
677/*---------------------------------------------------------------------------*/
678
679#endif
Matrix class, to be used by user.
void arccoreParallelFor(const ComplexForLoopRanges< RankValue > &loop_ranges, const ForLoopRunInfo &run_info, const LambdaType &lambda_function, const ReducerArgs &... reducer_args)
Applique en concurrence la fonction lambda lambda_function sur l'intervalle d'itération donné par loo...
Definition ParallelFor.h:85
std::int32_t Int32
Type entier signé sur 32 bits.
Metafunction that checks if two backends are compatible.
Implementation for residual error compuatation.
Implementation for matrix-vector product.