Arcane  4.2.3.0
Developer documentation
Loading...
Searching...
No Matches
DistributedPreconditioner.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/* DistributedPreconditioner.h (C) 2000-2026 */
9/* */
10/* Runtime wrapper around mpi preconditioners. */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCCORE_ALINA_MPI_DISTRIBUTEDPRECONDITIONER_H
13#define ARCCORE_ALINA_MPI_DISTRIBUTEDPRECONDITIONER_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/BuiltinBackend.h"
29#include "arccore/alina/DistributedAMG.h"
30#include "arccore/alina/DistributedInnerProduct.h"
31#include "arccore/alina/DistributedCoarseningRuntime.h"
32#include "arccore/alina/DistributedRelaxationRuntime.h"
33#include "arccore/alina/DistributedDirectSolverRuntime.h"
34#include "arccore/alina/MatrixPartitionerRuntime.h"
35#include "arccore/alina/DistributedRelaxation.h"
36#include "arccore/alina/DistributedMatrix.h"
37
38/*---------------------------------------------------------------------------*/
39/*---------------------------------------------------------------------------*/
40
41namespace Arcane::Alina
42{
43
44/*---------------------------------------------------------------------------*/
45/*---------------------------------------------------------------------------*/
46
48enum class eDistributedPreconditionerType
49{
50 amg,
51 relaxation
52};
53
54inline std::ostream& operator<<(std::ostream& os, eDistributedPreconditionerType p)
55{
56 switch (p) {
57 case eDistributedPreconditionerType::amg:
58 return os << "amg";
59 case eDistributedPreconditionerType::relaxation:
60 return os << "relaxation";
61 default:
62 return os << "???";
63 }
64}
65
66inline std::istream& operator>>(std::istream& in, eDistributedPreconditionerType& p)
67{
68 std::string val;
69 in >> val;
70
71 if (val == "amg")
72 p = eDistributedPreconditionerType::amg;
73 else if (val == "relaxation")
74 p = eDistributedPreconditionerType::relaxation;
75 else
76 throw std::invalid_argument("Invalid preconditioner class. "
77 "Valid choices are: amg, relaxation");
78
79 return in;
80}
81
82/*---------------------------------------------------------------------------*/
83/*---------------------------------------------------------------------------*/
87template <class Backend>
88class DistributedPreconditioner
89{
90 public:
91
92 using backend_type = Backend;
93 using BackendType = Backend;
94 typedef typename backend_type::params backend_params;
95 typedef PropertyTree params;
96 typedef typename backend_type::value_type value_type;
98
99 using AMGPrecondType = DistributedAMG<Backend,
104
105 template <class Matrix>
106 DistributedPreconditioner(const AlinaContext& context,
108 const Matrix& Astrip,
109 params prm = params(),
110 const backend_params& bprm = backend_params())
111 : _class(prm.get("class", eDistributedPreconditionerType::amg))
112 , handle(0)
113 {
114 init(context, std::make_shared<matrix>(comm, Astrip, backend::nbRow(Astrip)), prm, bprm);
115 }
116
117 DistributedPreconditioner(const AlinaContext& context,
119 std::shared_ptr<matrix> A,
120 params prm = params(),
121 const backend_params& bprm = backend_params())
122 : _class(prm.get("class", eDistributedPreconditionerType::amg))
123 , handle(0)
124 {
125 init(context, A, prm, bprm);
126 }
127
128 ~DistributedPreconditioner()
129 {
130 switch (_class) {
131 case eDistributedPreconditionerType::amg: {
132 delete static_cast<AMGPrecondType*>(handle);
133 } break;
134 case eDistributedPreconditionerType::relaxation: {
136 Precond;
137
138 delete static_cast<Precond*>(handle);
139 } break;
140 default:
141 break;
142 }
143 }
144
145 template <class Matrix>
146 void rebuild(const Matrix& A,
147 const backend_params& bprm = backend_params())
148 {
149 switch (_class) {
150 case eDistributedPreconditionerType::amg: {
151 static_cast<AMGPrecondType*>(handle)->rebuild(A, bprm);
152 } break;
153 default:
154 std::cerr << "rebuild is a noop unless the preconditioner is AMG" << std::endl;
155 return;
156 }
157 }
158
159 template <class Vec1, class Vec2>
160 void apply(const Vec1& rhs, Vec2&& x) const
161 {
162 switch (_class) {
163 case eDistributedPreconditionerType::amg: {
164 static_cast<AMGPrecondType*>(handle)->apply(rhs, x);
165 } break;
166 case eDistributedPreconditionerType::relaxation: {
168
169 static_cast<Precond*>(handle)->apply(rhs, x);
170 } break;
171 default:
172 throw std::invalid_argument("Unsupported preconditioner class");
173 }
174 }
175
177 std::shared_ptr<matrix> system_matrix_ptr() const
178 {
179 switch (_class) {
180 case eDistributedPreconditionerType::amg: {
181 return static_cast<AMGPrecondType*>(handle)->system_matrix_ptr();
182 }
183 case eDistributedPreconditionerType::relaxation: {
185
186 return static_cast<Precond*>(handle)->system_matrix_ptr();
187 }
188 default:
189 throw std::invalid_argument("Unsupported preconditioner class");
190 }
191 }
192
193 const matrix& system_matrix() const
194 {
195 return *system_matrix_ptr();
196 }
197
198 friend std::ostream& operator<<(std::ostream& os, const DistributedPreconditioner& p)
199 {
200 switch (p._class) {
201 case eDistributedPreconditionerType::amg: {
202 return os << *static_cast<AMGPrecondType*>(p.handle);
203 }
204 case eDistributedPreconditionerType::relaxation: {
205 typedef AsDistributedPreconditioner<DistributedRelaxationRuntime<Backend>> Precond;
206
207 return os << *static_cast<Precond*>(p.handle);
208 }
209 default:
210 throw std::invalid_argument("Unsupported preconditioner class");
211 }
212 }
213
214 private:
215
216 eDistributedPreconditionerType _class;
217 void* handle;
218
219 void init(const AlinaContext& context, std::shared_ptr<matrix> A, params& prm, const backend_params& bprm)
220 {
221 if (!prm.erase("class"))
222 ARCCORE_ALINA_PARAM_MISSING("class");
223
224 switch (_class) {
225 case eDistributedPreconditionerType::amg: {
226 handle = new AMGPrecondType(context, A->comm(), A, prm, bprm);
227 } break;
228 case eDistributedPreconditionerType::relaxation: {
229 typedef AsDistributedPreconditioner<DistributedRelaxationRuntime<Backend>> Precond;
230
231 handle = new Precond(context, A->comm(), A, prm, bprm);
232 } break;
233 default:
234 ARCCORE_FATAL("Unsupported preconditioner class '{0}'", _class);
235 }
236 }
237};
238
239/*---------------------------------------------------------------------------*/
240/*---------------------------------------------------------------------------*/
244template <class Precond>
245class DistributedBlockPreconditioner
246{
247 public:
248
249 typedef typename Precond::params params;
250 typedef typename Precond::backend_type backend_type;
251 using BackendType = backend_type;
252 typedef typename backend_type::params backend_params;
253
254 typedef typename backend_type::value_type value_type;
255 typedef typename backend_type::matrix bmatrix;
256 typedef DistributedMatrix<backend_type> matrix;
257
258 template <class Matrix>
259 DistributedBlockPreconditioner(const AlinaContext& context,
261 const Matrix& Astrip,
262 const params& prm = params(),
263 const backend_params& bprm = backend_params())
264 {
265 A = std::make_shared<matrix>(comm, Astrip, backend::nbRow(Astrip));
266 P = std::make_shared<Precond>(context, A->local(), prm, bprm);
267 A->set_local(P->system_matrix_ptr());
268 A->move_to_backend(bprm);
269 }
270
271 DistributedBlockPreconditioner(const AlinaContext& context,
273 std::shared_ptr<matrix> A,
274 const params& prm = params(),
275 const backend_params& bprm = backend_params())
276 : A(A)
277 {
278 P = std::make_shared<Precond>(context, A->local(), prm, bprm);
279 A->set_local(P->system_matrix_ptr());
280 A->move_to_backend(bprm);
281 }
282
283 std::shared_ptr<matrix> system_matrix_ptr() const
284 {
285 return A;
286 }
287
288 const matrix& system_matrix() const
289 {
290 return *A;
291 }
292
293 template <class Vec1, class Vec2>
294 void apply(const Vec1& rhs, Vec2&& x) const
295 {
296 P->apply(rhs, x);
297 }
298
299 private:
300
301 std::shared_ptr<matrix> A;
302 std::shared_ptr<Precond> P;
303};
304
305/*---------------------------------------------------------------------------*/
306/*---------------------------------------------------------------------------*/
307
308} // namespace Arcane::Alina
309
310/*---------------------------------------------------------------------------*/
311/*---------------------------------------------------------------------------*/
312
313#endif
#define ARCCORE_FATAL(...)
Macro throwing a FatalErrorException.
Runtime wrapper for distributed direct solvers.
Distributed Matrix using message passing.
std::shared_ptr< matrix > system_matrix_ptr() const
Returns the system matrix from the finest level.
Class to store parameters as a hierarchical key/value tree.
Definition AlinaUtils.h:113
Matrix class, to be used by user.
Convenience wrapper around MPI_Comm.
Use a relaxation as a distributed preconditioner.
Distributed memory sparse approximate inverse relaxation scheme.
Runtime-configurable wrapper around matrix partitioner.