Arcane  v4.1.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
ConjugateGradientSolver.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/* ConjugateGradientSolver.h (C) 2000-2026 */
9/* */
10/* Conjugate Gradient method. */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCCORE_ALINA_CONJUGATEGRADIENTSOLVER_H
13#define ARCCORE_ALINA_CONJUGATEGRADIENTSOLVER_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 <iostream>
27
28#include "arccore/alina/SolverUtils.h"
29#include "arccore/alina/SolverBase.h"
30
31/*---------------------------------------------------------------------------*/
32/*---------------------------------------------------------------------------*/
33
34namespace Arcane::Alina
35{
36
37/*---------------------------------------------------------------------------*/
38/*---------------------------------------------------------------------------*/
42struct ConjugateGradientSolverParams
43{
44 using params = ConjugateGradientSolverParams;
45
48
50 double tol = 1.0e-8;
51
53 double abstol = std::numeric_limits<double>::min();
54
60 bool ns_search = false;
61
63 bool verbose = false;
64
65 ConjugateGradientSolverParams() = default;
66
67 ConjugateGradientSolverParams(const PropertyTree& p)
68 : ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, maxiter)
69 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, tol)
70 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, abstol)
71 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, ns_search)
72 , ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, verbose)
73 {
74 p.check_params( { "maxiter", "tol", "abstol", "ns_search", "verbose" });
75 }
76
77 void get(PropertyTree& p, const std::string& path) const
78 {
79 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, maxiter);
80 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, tol);
81 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, abstol);
82 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, ns_search);
83 ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, verbose);
84 }
85};
86
87/*---------------------------------------------------------------------------*/
88/*---------------------------------------------------------------------------*/
94template <class Backend_, class InnerProduct = detail::default_inner_product>
96: public SolverBase
97{
98 public:
99
100 using Backend = Backend_;
101 using backend_type = Backend;
102 using BackendType = Backend;
103
104 typedef typename Backend::vector vector;
105 typedef typename Backend::value_type value_type;
106 typedef typename Backend::params backend_params;
107
108 typedef typename math::scalar_of<value_type>::type scalar_type;
109
110 typedef typename math::inner_product_impl<
111 typename math::rhs_of<value_type>::type>::return_type coef_type;
112
113 using params = ConjugateGradientSolverParams;
114
116 ConjugateGradientSolver(size_t n, const params& prm = params(),
117 const backend_params& backend_prm = backend_params(),
118 const InnerProduct& inner_product = InnerProduct())
119 : prm(prm)
120 , n(n)
121 , r(Backend::create_vector(n, backend_prm))
122 , s(Backend::create_vector(n, backend_prm))
123 , p(Backend::create_vector(n, backend_prm))
124 , q(Backend::create_vector(n, backend_prm))
125 , inner_product(inner_product)
126 {}
127
128 /* Computes the solution for the given system matrix \p A and the
129 * right-hand side \p rhs. Returns the number of iterations made and
130 * the achieved residual as a ``std::tuple``. The solution vector
131 * \p x provides initial approximation in input and holds the computed
132 * solution on output.
133 *
134 * The system matrix may differ from the matrix used during
135 * initialization. This may be used for the solution of non-stationary
136 * problems with slowly changing coefficients. There is a strong chance
137 * that a preconditioner built for a time step will act as a reasonably
138 * good preconditioner for several subsequent time steps [DeSh12]_.
139 */
140 template <class Matrix, class Precond, class Vec1, class Vec2>
141 SolverResult operator()(const Matrix& A, const Precond& P, const Vec1& rhs, Vec2&& x) const
142 {
143 static const coef_type one = math::identity<coef_type>();
144 static const coef_type zero = math::zero<coef_type>();
145
146 ScopedStreamModifier ss(std::cout);
147
148 scalar_type norm_rhs = norm(rhs);
149 if (norm_rhs < Alina::detail::eps<scalar_type>(1)) {
150 if (prm.ns_search) {
151 norm_rhs = math::identity<scalar_type>();
152 }
153 else {
154 backend::clear(x);
155 return SolverResult(0, norm_rhs);
156 }
157 }
158
159 scalar_type eps = std::max(prm.tol * norm_rhs, prm.abstol);
160
161 coef_type rho1 = 2 * eps * one;
162 coef_type rho2 = zero;
163
164 backend::residual(rhs, A, x, *r);
165 scalar_type res_norm = norm(*r);
166
167 Int32 iter = 0;
168 for (; iter < prm.maxiter && math::norm(res_norm) > eps; ++iter) {
169 P.apply(*r, *s);
170
171 rho2 = rho1;
172 rho1 = inner_product(*r, *s);
173
174 if (iter!=0)
175 backend::axpby(one, *s, rho1 / rho2, *p);
176 else
177 backend::copy(*s, *p);
178
179 backend::spmv(one, A, *p, zero, *q);
180
181 coef_type alpha = rho1 / inner_product(*q, *p);
182
183 backend::axpby(alpha, *p, one, x);
184 backend::axpby(-alpha, *q, one, *r);
185
186 res_norm = norm(*r);
187 if (prm.verbose && iter % 5 == 0)
188 std::cout << iter << "\t" << std::scientific << res_norm / norm_rhs << std::endl;
189 }
190
191 return SolverResult(iter, res_norm / norm_rhs);
192 }
193
204 template <class Precond, class Vec1, class Vec2>
205 SolverResult operator()(const Precond& P, const Vec1& rhs, Vec2&& x) const
206 {
207 return (*this)(P.system_matrix(), P, rhs, x);
208 }
209
210 size_t bytes() const
211 {
212 return backend::bytes(*r) +
213 backend::bytes(*s) +
214 backend::bytes(*p) +
215 backend::bytes(*q);
216 }
217
218 friend std::ostream& operator<<(std::ostream& os, const ConjugateGradientSolver& s)
219 {
220 return os << "Type: CG"
221 << "\nUnknowns: " << s.n
222 << "\nMemory footprint: " << human_readable_memory(s.bytes())
223 << std::endl;
224 }
225
226 public:
227
228 params prm;
229
230 private:
231
232 size_t n;
233
234 std::shared_ptr<vector> r;
235 std::shared_ptr<vector> s;
236 std::shared_ptr<vector> p;
237 std::shared_ptr<vector> q;
238
239 InnerProduct inner_product;
240
241 template <class Vec>
242 scalar_type norm(const Vec& x) const
243 {
244 return sqrt(math::norm(inner_product(x, x)));
245 }
246};
247
248/*---------------------------------------------------------------------------*/
249/*---------------------------------------------------------------------------*/
250
251} // namespace Arcane::Alina
252
253/*---------------------------------------------------------------------------*/
254/*---------------------------------------------------------------------------*/
255
256#endif
size_t bytes() const
Memory used in bytes.
ConjugateGradientSolver(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.
SolverResult operator()(const Precond &P, const Vec1 &rhs, Vec2 &&x) const
Computes the solution for the given right-hand side.
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 Conjugate Gradient solver.
bool ns_search
Ignore the trivial solution x=0 when rhs is zero.
bool verbose
Verbose output (show iterations and error)
double tol
Target relative residual error.
double abstol
Target absolute residual error.
Default implementation for inner product.