Arcane  v4.1.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
BiCGStabSolver.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/* BiCGStabSolver.h (C) 2000-2026 */
9/* */
10/* BiCGStab iterative method. . */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCCORE_ALINA_BICGSTAB_H
13#define ARCCORE_ALINA_BICGSTAB_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#include "arccore/alina/SolverUtils.h"
27#include "arccore/alina/SolverBase.h"
28
29/*---------------------------------------------------------------------------*/
30/*---------------------------------------------------------------------------*/
31
32namespace Arcane::Alina
33{
34
35/*---------------------------------------------------------------------------*/
36/*---------------------------------------------------------------------------*/
40struct BiCGStabSolverParams
41{
42 using params = BiCGStabSolverParams;
43
45 ePreconditionerSideType pside = ePreconditionerSideType::right;
46
49
51 double tol = 1.0e-8;
52
54 double abstol = std::numeric_limits<double>::min();
55
57 bool check_after = false;
58
60 //** Useful for searching for the null-space vectors of the system */
61 bool ns_search = false;
62
64 bool verbose = false;
65
66 BiCGStabSolverParams() = default;
67
68 BiCGStabSolverParams(const PropertyTree& p)
69 : ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, pside)
70 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, maxiter)
71 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, tol)
72 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, abstol)
73 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, check_after)
74 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, ns_search)
75 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, verbose)
76 {
77 p.check_params( { "pside", "maxiter", "tol", "abstol", "check_after", "ns_search", "verbose" });
78 }
79
80 void get(PropertyTree& p, const std::string& path) const
81 {
82 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, pside);
83 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, maxiter);
84 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, tol);
85 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, abstol);
86 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, check_after);
87 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, ns_search);
88 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, verbose);
89 }
90};
91
92/*---------------------------------------------------------------------------*/
93/*---------------------------------------------------------------------------*/
101template <class Backend, class InnerProduct = detail::default_inner_product>
103: public SolverBase
104{
105 public:
106
107 using backend_type = Backend;
108 using BackendType = Backend;
109
110 typedef typename Backend::vector vector;
111 typedef typename Backend::value_type value_type;
112 typedef typename Backend::params backend_params;
113
114 typedef typename math::scalar_of<value_type>::type scalar_type;
115
116 typedef typename math::inner_product_impl<
117 typename math::rhs_of<value_type>::type>::return_type coef_type;
118
119 using params = BiCGStabSolverParams;
120
123 const params& prm = params(),
124 const backend_params& backend_prm = backend_params(),
125 const InnerProduct& inner_product = InnerProduct())
126 : prm(prm)
127 , n(n)
128 , r(Backend::create_vector(n, backend_prm))
129 , p(Backend::create_vector(n, backend_prm))
130 , v(Backend::create_vector(n, backend_prm))
131 , s(Backend::create_vector(n, backend_prm))
132 , t(Backend::create_vector(n, backend_prm))
133 , rh(Backend::create_vector(n, backend_prm))
134 , T(Backend::create_vector(n, backend_prm))
135 , inner_product(inner_product)
136 {}
137
138 /* Computes the solution for the given system matrix \p A and the
139 * right-hand side \p rhs. Returns the number of iterations made and
140 * the achieved residual as a ``std::tuple``. The solution vector
141 * \p x provides initial approximation in input and holds the computed
142 * solution on output.
143 *
144 * The system matrix may differ from the matrix used during
145 * initialization. This may be used for the solution of non-stationary
146 * problems with slowly changing coefficients. There is a strong chance
147 * that a preconditioner built for a time step will act as a reasonably
148 * good preconditioner for several subsequent time steps [DeSh12]_.
149 */
150 template <class Matrix, class Precond, class Vec1, class Vec2>
151 SolverResult operator()(const Matrix& A, const Precond& P, const Vec1& rhs, Vec2&& x) const
152 {
153 static const coef_type one = math::identity<coef_type>();
154 static const coef_type zero = math::zero<coef_type>();
155
156 ScopedStreamModifier ss(std::cout);
157
158 scalar_type norm_rhs = norm(rhs);
159 if (norm_rhs < Alina::detail::eps<scalar_type>(1)) {
160 if (prm.ns_search) {
161 norm_rhs = math::identity<scalar_type>();
162 }
163 else {
164 backend::clear(x);
165 return SolverResult(0, norm_rhs);
166 }
167 }
168
169 if (prm.pside == ePreconditionerSideType::left) {
170 backend::residual(rhs, A, x, *rh);
171 P.apply(*rh, *r);
172 }
173 else {
174 backend::residual(rhs, A, x, *r);
175 }
176 backend::copy(*r, *rh);
177
178 scalar_type eps = std::max(norm_rhs * prm.tol, prm.abstol);
179 scalar_type res = prm.check_after ? 2 * eps : norm(*r);
180
181 coef_type rho1 = zero;
182 coef_type rho2 = zero;
183 coef_type alpha = zero;
184 coef_type omega = zero;
185
186 Int32 iter = 0;
187 for (bool first = true; res > eps && iter < prm.maxiter; ++iter) {
188
189 rho2 = rho1;
190 rho1 = inner_product(*r, *rh);
191
192 if (first) {
193 backend::copy(*r, *p);
194 first = false;
195 }
196 else {
197 precondition(!math::is_zero(rho2), "Zero rho in BiCGStab");
198 coef_type beta = (rho1 * alpha) / (rho2 * omega);
199 backend::axpbypcz(one, *r, -beta * omega, *v, beta, *p);
200 }
201
202 preconditioner_spmv(prm.pside, P, A, *p, *v, *T);
203
204 alpha = rho1 / inner_product(*rh, *v);
205
206 if (prm.pside == ePreconditionerSideType::left) {
207 backend::axpby(alpha, *p, one, x);
208 }
209 else {
210 backend::axpby(alpha, *T, one, x);
211 }
212
213 backend::axpbypcz(one, *r, -alpha, *v, zero, *s);
214
215 if ((res = norm(*s)) > eps) {
216 preconditioner_spmv(prm.pside, P, A, *s, *t, *T);
217
218 omega = inner_product(*t, *s) / inner_product(*t, *t);
219
220 precondition(!math::is_zero(omega), "Zero omega in BiCGStab");
221
222 if (prm.pside == ePreconditionerSideType::left) {
223 backend::axpby(omega, *s, one, x);
224 }
225 else {
226 backend::axpby(omega, *T, one, x);
227 }
228
229 backend::axpbypcz(one, *s, -omega, *t, zero, *r);
230
231 res = norm(*r);
232 }
233
234 if (prm.verbose && iter % 5 == 0)
235 std::cout << iter << "\t" << std::scientific << res / norm_rhs << std::endl;
236 }
237
238 return SolverResult(iter, res / norm_rhs);
239 }
240
241 /*
242 * Computes the solution for the given right-hand side \p rhs. The
243 * system matrix is the same that was used for the setup of the
244 * preconditioner \p P. Returns the number of iterations made and the
245 * achieved residual as a ``std::tuple``. The solution vector \p x
246 * provides initial approximation in input and holds the computed
247 * solution on output.
248 */
249 template <class Precond, class Vec1, class Vec2>
250 SolverResult operator()(const Precond& P, const Vec1& rhs, Vec2&& x) const
251 {
252 return (*this)(P.system_matrix(), P, rhs, x);
253 }
254
255 size_t bytes() const
256 {
257 return backend::bytes(*r) +
258 backend::bytes(*p) +
259 backend::bytes(*v) +
260 backend::bytes(*s) +
261 backend::bytes(*t) +
262 backend::bytes(*rh) +
263 backend::bytes(*T);
264 }
265
266 friend std::ostream& operator<<(std::ostream& os, const BiCGStabSolver& s)
267 {
268 return os << "Type: BiCGStab"
269 << "\nUnknowns: " << s.n
270 << "\nMemory footprint: " << human_readable_memory(s.bytes())
271 << std::endl;
272 }
273
274 public:
275
276 params prm;
277
278 private:
279
280 size_t n;
281
282 std::shared_ptr<vector> r;
283 std::shared_ptr<vector> p;
284 std::shared_ptr<vector> v;
285 std::shared_ptr<vector> s;
286 std::shared_ptr<vector> t;
287 std::shared_ptr<vector> rh;
288 std::shared_ptr<vector> T;
289
290 InnerProduct inner_product;
291
292 template <class Vec>
293 scalar_type norm(const Vec& x) const
294 {
295 return sqrt(math::norm(inner_product(x, x)));
296 }
297};
298
299/*---------------------------------------------------------------------------*/
300/*---------------------------------------------------------------------------*/
301
302} // namespace Arcane::Alina
303
304/*---------------------------------------------------------------------------*/
305/*---------------------------------------------------------------------------*/
306
307#endif
BiConjugate Gradient Stabilized (BiCGSTAB) method.
BiCGStabSolver(size_t n, const params &prm=params(), const backend_params &backend_prm=backend_params(), const InnerProduct &inner_product=InnerProduct())
Preallocates necessary data structures for the system of size n.
size_t bytes() const
Memory used in bytes.
Save ostream flags in constructor, restore in destructor.
Base class for solvers.
Definition SolverBase.h:31
Result of a solving.
Definition AlinaUtils.h:52
Matrix class, to be used by user.
std::int32_t Int32
Type entier signé sur 32 bits.
Parameters for BiConjugate Gradient Stabilized solver.
bool check_after
Always do at least one iteration.
bool verbose
Verbose output (show iterations and error)
double abstol
Target absolute residual error.
Int32 maxiter
Maximum number of iterations.
double tol
Target relative residual error.
ePreconditionerSideType pside
Preconditioning kind (left/right).
bool ns_search
Ignore the trivial solution x=0 when rhs is zero.
Default implementation for inner product.