Arcane  4.2.1.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
DistributedBasicSolver.cc
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/*---------------------------------------------------------------------------*/
9/*
10 * Ce fichier est basé sur le travail sur la bibliothèque AMGCL (version mars 2026)
11 * qui peut être trouvée à https://github.com/ddemidov/amgcl.
12 *
13 * Copyright (c) 2012-2022 Denis Demidov <dennis.demidov@gmail.com>
14 * SPDX-License-Identifier: MIT
15 */
16/*---------------------------------------------------------------------------*/
17/*---------------------------------------------------------------------------*/
18
19#include "arccore/alina/BuiltinBackend.h"
20#include "arccore/alina/StaticMatrix.h"
21#include "arccore/alina/Adapters.h"
22#include "arccore/alina/MessagePassingUtils.h"
23#include "arccore/alina/DistributedPreconditionedSolver.h"
24#include "arccore/alina/DistributedPreconditioner.h"
25#include "arccore/alina/DistributedSolverRuntime.h"
26
27#include "arccore/alina/IO.h"
28#include "arccore/alina/Profiler.h"
29
30#include "arccore/common/internal/ProgramOptions.h"
31
32#include "arccore/trace/ITraceMng.h"
33
34#include "AlinaSamplesCommon.h"
35
36#include <iostream>
37#include <vector>
38#include <string>
39
40using namespace Arcane;
41
42namespace math = Alina::math;
43
44//---------------------------------------------------------------------------
45ptrdiff_t
46assemble_poisson3d(Alina::mpi_communicator comm,
47 ptrdiff_t n, int block_size,
48 std::vector<ptrdiff_t>& ptr,
49 std::vector<ptrdiff_t>& col,
50 std::vector<double>& val,
51 std::vector<double>& rhs)
52{
53 ptrdiff_t n3 = n * n * n;
54
55 ptrdiff_t chunk = (n3 + comm.size - 1) / comm.size;
56 if (chunk % block_size != 0) {
57 chunk += block_size - chunk % block_size;
58 }
59 ptrdiff_t row_beg = std::min(n3, chunk * comm.rank);
60 ptrdiff_t row_end = std::min(n3, row_beg + chunk);
61 chunk = row_end - row_beg;
62
63 ptr.clear();
64 ptr.reserve(chunk + 1);
65 col.clear();
66 col.reserve(chunk * 7);
67 val.clear();
68 val.reserve(chunk * 7);
69
70 rhs.resize(chunk);
71 std::fill(rhs.begin(), rhs.end(), 1.0);
72
73 const double h2i = (n - 1) * (n - 1);
74 ptr.push_back(0);
75
76 for (ptrdiff_t idx = row_beg; idx < row_end; ++idx) {
77 ptrdiff_t k = idx / (n * n);
78 ptrdiff_t j = (idx / n) % n;
79 ptrdiff_t i = idx % n;
80
81 if (k > 0) {
82 col.push_back(idx - n * n);
83 val.push_back(-h2i);
84 }
85
86 if (j > 0) {
87 col.push_back(idx - n);
88 val.push_back(-h2i);
89 }
90
91 if (i > 0) {
92 col.push_back(idx - 1);
93 val.push_back(-h2i);
94 }
95
96 col.push_back(idx);
97 val.push_back(6 * h2i);
98
99 if (i + 1 < n) {
100 col.push_back(idx + 1);
101 val.push_back(-h2i);
102 }
103
104 if (j + 1 < n) {
105 col.push_back(idx + n);
106 val.push_back(-h2i);
107 }
108
109 if (k + 1 < n) {
110 col.push_back(idx + n * n);
111 val.push_back(-h2i);
112 }
113
114 ptr.push_back(col.size());
115 }
116
117 return chunk;
118}
119
120//---------------------------------------------------------------------------
121template <class Backend, class Matrix>
122std::shared_ptr<Alina::DistributedMatrix<Backend>>
123partition(Alina::mpi_communicator comm, const Matrix& Astrip,
124 typename Backend::vector& rhs, const typename Backend::params& bprm,
125 Alina::eMatrixPartitionerType ptype, int block_size = 1)
126{
127 auto& prof = Alina::Profiler::globalProfiler();
128 typedef typename Backend::value_type val_type;
129 typedef typename Alina::math::rhs_of<val_type>::type rhs_type;
130 typedef Alina::DistributedMatrix<Backend> DMatrix;
131
132 auto A = std::make_shared<DMatrix>(comm, Astrip);
133
134 if (comm.size == 1 || ptype == Alina::eMatrixPartitionerType::merge)
135 return A;
136
137 prof.tic("partition");
139 prm.put("type", ptype);
141
142 auto I = part(*A, block_size);
143 auto J = transpose(*I);
144 A = product(*J, *product(*A, *I));
145
146 Alina::numa_vector<rhs_type> new_rhs(J->loc_rows());
147
148 J->move_to_backend(bprm);
149
150 Alina::backend::spmv(1, *J, rhs, 0, new_rhs);
151 rhs.swap(new_rhs);
152 prof.toc("partition");
153
154 return A;
155}
156
157//---------------------------------------------------------------------------
158void solve_scalar(Alina::mpi_communicator comm,
159 ptrdiff_t chunk,
160 const std::vector<ptrdiff_t>& ptr,
161 const std::vector<ptrdiff_t>& col,
162 const std::vector<double>& val,
163 const Alina::PropertyTree& prm,
164 const std::vector<double>& f,
165 Alina::eMatrixPartitionerType ptype)
166{
167 auto& prof = Alina::Profiler::globalProfiler();
168 //using Backend = Alina::BuiltinBackend<double>;
169
170 using BackendValueType = double;
172
173 std::cout << "Using scalar solve ptr_size=" << sizeof(ptrdiff_t)
174 << " ptr_type_size=" << sizeof(Backend::ptr_type)
175 << " col_type_size=" << sizeof(Backend::col_type)
176 << " value_type_size=" << sizeof(Backend::value_type)
177 << "\n";
178
179 typedef Alina::DistributedMatrix<Backend> DMatrix;
180
182 using RelaxationType = Alina::DistributedSPAI0Relaxation<Backend>;
183 // Si on veut tester les backend dynamiques:
184 //using CoarseningType = Alina::DistributedCoarseningRuntime<Backend>;
185 //using RelaxationType = Alina::DistributedRelaxationRuntime<Backend>,
186
187 using AMGPrecondType = Alina::DistributedAMG<Backend, CoarseningType, RelaxationType,
190
192
193 typename Backend::params bprm;
194
196
197 auto get_distributed_matrix = [&]() {
198 auto t = prof.scoped_tic("distributed matrix");
199 std::shared_ptr<DMatrix> A;
200
201 if (ptype != Alina::eMatrixPartitionerType::merge) {
202 A = partition<Backend>(comm,
203 std::tie(chunk, ptr, col, val), rhs, bprm, ptype,
204 prm.get("precond.coarsening.aggr.block_size", 1));
205 chunk = A->loc_rows();
206 }
207 else {
208 A = std::make_shared<DMatrix>(comm, std::tie(chunk, ptr, col, val));
209 }
210
211 return A;
212 };
213
214 std::shared_ptr<DMatrix> A;
215 std::shared_ptr<Solver> solve;
216
217 {
218 auto t = prof.scoped_tic("setup");
219 A = get_distributed_matrix();
220 solve = std::make_shared<Solver>(comm, A, prm, bprm);
222 solve->prm.get(prm2);
223 std::cout << "SOLVER parameters=" << prm2 << "\n";
224 }
225
226 if (comm.rank == 0) {
227 std::cout << "SolverInfo:\n";
228 std::cout << *solve << std::endl;
229 }
230
231 if (prm.get("precond.allow_rebuild", false)) {
232 if (comm.rank == 0) {
233 std::cout << "Rebuilding the preconditioner..." << std::endl;
234 }
235
236 {
237 auto t = prof.scoped_tic("rebuild");
238 A = get_distributed_matrix();
239 solve->precond().rebuild(A);
240 }
241
242 if (comm.rank == 0) {
243 std::cout << *solve << std::endl;
244 }
245 }
246
248
249 prof.tic("solve");
250 Alina::SolverResult r = (*solve)(rhs, x);
251 prof.toc("solve");
252
253 if (comm.rank == 0) {
254 std::cout << "Iterations: " << r.nbIteration() << std::endl
255 << "Error: " << r.residual() << std::endl
256 << prof << std::endl;
257 }
258}
259
260//---------------------------------------------------------------------------
261int main2(const Alina::SampleMainContext& ctx, int argc, char* argv[])
262{
263 ITraceMng* tm = ctx.traceMng();
264 auto& prof = Alina::Profiler::globalProfiler();
265
266 //Alina::mpi_init_thread mpi(&argc, &argv);
267 Alina::mpi_communicator comm(MPI_COMM_WORLD);
268
269 tm->info() << "World size: " << comm.size;
270
271 // Lire la configuration à partir de la ligne de commande
272 namespace po = Arcane::ProgramOptions;
273 po::options_description desc("Options");
274
275 auto default_partitioner_type = Alina::eMatrixPartitionerType::merge;
276#if defined(ARCCORE_ALINA_HAVE_PARMETIS)
277 default_partitioner_type = Alina::eMatrixPartitionerType::parmetis;
278#endif
279
280 desc.add_options()("help,h", "affiche l'aide")("matrix,A",
281 po::value<std::string>(),
282 "Matrice système au format MatrixMarket. "
283 "Si non spécifié, un problème de Poisson dans un cube unitaire 3D est assemblé. ");
284 desc.add_options()("partitioner,r",
285 po::value<Alina::eMatrixPartitionerType>()->default_value(
286 default_partitioner_type),
287 "Répartition de la matrice système");
288 desc.add_options()("size,n",
289 po::value<ptrdiff_t>()->default_value(32),
290 "taille du domaine");
291 desc.add_options()("prm-file,P", po::value<std::string>(),
292 "Fichier de paramètres au format json. ");
293 desc.add_options()("prm,p",
294 po::value<std::vector<std::string>>()->multitoken(),
295 "Paramètres spécifiés sous forme de paires nom=valeur. "
296 "Peut être fourni plusieurs fois. Exemples :\n"
297 " -p solver.tol=1e-3\n"
298 " -p precond.coarse_enough=300");
299 desc.add_options()("test-rebuild",
300 po::bool_switch()->default_value(false),
301 "Lorsqu'il est spécifié, tente de reconstruire le solveur avant de résoudre. ");
302
304 p.add("prm", -1);
305
307 po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
308 po::notify(vm);
309
310 if (vm.count("help")) {
311 if (comm.rank == 0)
312 std::cout << desc << std::endl;
313 return 0;
314 }
315
317 if (vm.count("prm-file")) {
318 prm.read_json(vm["prm-file"].as<std::string>());
319 }
320
321 if (vm.count("prm")) {
322 for (const std::string& v : vm["prm"].as<std::vector<std::string>>()) {
323 tm->info() << "PUT_KEY_VALUE v=" << v;
324 prm.putKeyValue(v);
325 }
326 }
327
328 ptrdiff_t n;
329 std::vector<ptrdiff_t> ptr;
330 std::vector<ptrdiff_t> col;
331 std::vector<double> val;
332 std::vector<double> rhs;
333
334 Alina::eMatrixPartitionerType ptype = vm["partitioner"].as<Alina::eMatrixPartitionerType>();
335
336 prof.tic("assemble");
337 Int64 matrix_size = vm["size"].as<ptrdiff_t>();
338 tm->info() << "Taille de la matrice=" << matrix_size;
339 n = assemble_poisson3d(comm, matrix_size, 1, ptr, col, val, rhs);
340 prof.toc("assemble");
341
342 if (vm["test-rebuild"].as<bool>()) {
343 prm.put("precond.allow_rebuild", true);
344 }
345
346 solve_scalar(comm, n, ptr, col, val, prm, rhs, ptype);
347 return 0;
348}
349
350/*---------------------------------------------------------------------------*/
351/*---------------------------------------------------------------------------*/
352
353int main(int argc, char* argv[])
354{
355 return Arcane::Alina::SampleMainContext::execMain(main2, argc, argv);
356}
357
358/*---------------------------------------------------------------------------*/
359/*---------------------------------------------------------------------------*/
Runtime wrapper for distributed direct solvers.
Distributed Matrix using message passing.
Iterative solver wrapper for distributed linear systems.
Classe pour stocker les paramètres sous forme d'arbre hiérarchique clé/valeur.
Definition AlinaUtils.h:112
Résultat d'une solution.
Definition AlinaUtils.h:53
NUMA-aware vector container.
Definition NumaVector.h:42
Interface du gestionnaire de traces.
virtual TraceMessage info()=0
Flot pour un message d'information.
Matrix class, to be used by user.
Constructeur d'analyseur d'arguments en ligne de commande fluide.
Décrit un ensemble d'options en ligne de commande.
Décrit les arguments positionnels (non-options).
Stocke les valeurs d'options analysées.
Espace de nom pour les fonctions mathématiques.
Definition MathUtils.h:36
__host__ __device__ Real3x3 transpose(const Real3x3 &t)
Transpose la matrice.
Definition MathUtils.h:265
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Distributed smoothed aggregation coarsening scheme.
Runtime-configurable wrapper around matrix partitioner.
Wrapper de commodité autour de MPI_Comm.