Arcane  4.2.3.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
DistributedSCHUR.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// Pour Eigen
20#pragma GCC diagnostic ignored "-Wdeprecated-copy"
21#pragma GCC diagnostic ignored "-Wint-in-bool-context"
22
23#include <iostream>
24#include <iterator>
25#include <iomanip>
26#include <fstream>
27#include <vector>
28#include <numeric>
29#include <cmath>
30
31#include <boost/range/iterator_range.hpp>
32
33#if defined(SOLVER_BACKEND_CUDA)
34# include "arccore/alina/CudaBackend.h"
35# include "arccore/alina/relaxation_cusparse_ilu0.h"
37#else
38# ifndef SOLVER_BACKEND_BUILTIN
39# define SOLVER_BACKEND_BUILTIN
40# endif
41#include "arccore/alina/BuiltinBackend.h"
43#endif
44
45#include "arccore/alina/IO.h"
46#include "arccore/alina/Adapters.h"
47#include "arccore/alina/AMG.h"
48#include "arccore/alina/CoarseningRuntime.h"
49#include "arccore/alina/RelaxationRuntime.h"
50#include "arccore/alina/DistributedPreconditionedSolver.h"
51#include "arccore/alina/DistributedSchurPressureCorrection.h"
52#include "arccore/alina/DistributedPreconditioner.h"
53#include "arccore/alina/DistributedSubDomainDeflation.h"
54#include "arccore/alina/DistributedSolverRuntime.h"
55#include "arccore/alina/DistributedDirectSolverRuntime.h"
56#include "arccore/alina/Profiler.h"
57
58#include "arccore/common/internal/ProgramOptions.h"
59
60using namespace Arcane;
61using namespace Arcane::Alina;
62
63using Alina::precondition;
64
65//---------------------------------------------------------------------------
66std::vector<ptrdiff_t>
67read_problem(const Alina::AlinaCommunicator& world,
68 const std::string& A_file,
69 const std::string& rhs_file,
70 const std::string& part_file,
71 std::vector<ptrdiff_t>& ptr,
72 std::vector<ptrdiff_t>& col,
73 std::vector<double>& val,
74 std::vector<double>& rhs)
75{
76 // Lit la partition
77 ptrdiff_t n, m;
78 std::vector<ptrdiff_t> domain(world.size + 1, 0);
79 std::vector<int> part;
80
81 std::tie(n, m) = Alina::IO::mm_reader(part_file)(part);
82 for (int p : part) {
83 ++domain[p + 1];
84 precondition(p < world.size, "MPI world does not correspond to partition");
85 }
86 std::partial_sum(domain.begin(), domain.end(), domain.begin());
87
88 ptrdiff_t chunk_beg = domain[world.rank];
89 ptrdiff_t chunk_end = domain[world.rank + 1];
90 ptrdiff_t chunk = chunk_end - chunk_beg;
91
92 // Réordonne les inconnues
93 std::vector<ptrdiff_t> order(n);
94 for (ptrdiff_t i = 0; i < n; ++i)
95 order[i] = domain[part[i]]++;
96
97 std::rotate(domain.begin(), domain.end() - 1, domain.end());
98 domain[0] = 0;
99
100 // Lit le bloc de la matrice
101 {
102 using namespace Arcane::Alina::IO;
103
104 std::ifstream A(A_file.c_str(), std::ios::binary);
105 precondition(A, "Failed to open matrix file (" + A_file + ")");
106
107 std::ifstream b(rhs_file.c_str(), std::ios::binary);
108 precondition(b, "Failed to open rhs file (" + rhs_file + ")");
109
110 ptrdiff_t rows;
111 precondition(read(A, rows), "File I/O error");
112 precondition(rows == n, "Matrix and partition have incompatible sizes");
113
114 ptr.clear();
115 ptr.reserve(chunk + 1);
116 ptr.push_back(0);
117
118 std::vector<ptrdiff_t> gptr(n + 1);
119 precondition(read(A, gptr), "File I/O error");
120
121 size_t col_beg = sizeof(rows) + sizeof(gptr[0]) * (n + 1);
122 size_t val_beg = col_beg + sizeof(col[0]) * gptr.back();
123 size_t rhs_beg = 2 * sizeof(ptrdiff_t);
124
125 // Compte les non-zéros locaux
126 for (ptrdiff_t i = 0; i < n; ++i)
127 if (part[i] == world.rank)
128 ptr.push_back(gptr[i + 1] - gptr[i]);
129
130 std::partial_sum(ptr.begin(), ptr.end(), ptr.begin());
131
132 col.clear();
133 col.reserve(ptr.back());
134 val.clear();
135 val.reserve(ptr.back());
136 rhs.clear();
137 rhs.reserve(chunk);
138
139 // Lit les bandes de la matrice et du membre de droite
140 for (ptrdiff_t i = 0; i < n; ++i) {
141 if (part[i] != world.rank)
142 continue;
143
144 ptrdiff_t c;
145 A.seekg(col_beg + gptr[i] * sizeof(c));
146 for (ptrdiff_t j = gptr[i], e = gptr[i + 1]; j < e; ++j) {
147 precondition(read(A, c), "File I/O error (1)");
148 col.push_back(order[c]);
149 }
150 }
151
152 for (ptrdiff_t i = 0; i < n; ++i) {
153 if (part[i] != world.rank)
154 continue;
155
156 double v;
157 A.seekg(val_beg + gptr[i] * sizeof(v));
158 for (ptrdiff_t j = gptr[i], e = gptr[i + 1]; j < e; ++j) {
159 precondition(read(A, v), "File I/O error (2)");
160 val.push_back(v);
161 }
162 }
163
164 for (ptrdiff_t i = 0; i < n; ++i) {
165 if (part[i] != world.rank)
166 continue;
167
168 double f;
169 b.seekg(rhs_beg + i * sizeof(f));
170 precondition(read(b, f), "File I/O error (3)");
171 rhs.push_back(f);
172 }
173 }
174
175 return domain;
176}
177
178//---------------------------------------------------------------------------
179int main(int argc, char* argv[])
180{
181 auto& prof = Alina::Profiler::globalProfiler();
183 auto mpm = StandaloneMpi::createAndInitializeMPI(&argc, &argv, MPI_THREAD_MULTIPLE);
184 Alina::AlinaCommunicator world(mpm);
185 Alina::AlinaContext context;
186 if (world.rank == 0)
187 std::cout << "World size: " << world.size << std::endl;
188
189 // Lit la configuration depuis la ligne de commande
190 namespace po = Arcane::ProgramOptions;
191 using std::string;
192 po::options_description desc("Options");
193
194 desc.add_options()("help,h", "show help")(
195 "matrix,A",
196 po::value<string>()->required(),
197 "La matrice du système au format binaire")(
198 "rhs,f",
199 po::value<string>(),
200 "Le membre de droite au format binaire")(
201 "part,s",
202 po::value<string>()->required(),
203 "Partitionnement du problème au format MatrixMarket")(
204 "pmask,m",
205 po::value<string>(),
206 "Le masque de pression au format binaire. Ou, si le paramètre a "
207 "la forme '%n:m', alors chaque variable (n+i*m)-ième est traitée comme une pression.")(
208 "params,P",
209 po::value<string>(),
210 "fichier de paramètres au format json")(
211 "prm,p",
212 po::value<std::vector<string>>()->multitoken(),
213 "Paramètres spécifiés sous forme de paires nom=valeur. "
214 "Peut être fourni plusieurs fois. Exemples :\n"
215 " -p solver.tol=1e-3\n"
216 " -p precond.coarse_enough=300");
217
219 po::store(po::parse_command_line(argc, argv, desc), vm);
220
221 if (vm.count("help")) {
222 if (world.rank == 0)
223 std::cout << desc << std::endl;
224 return 0;
225 }
226
227 po::notify(vm);
228
230 if (vm.count("params"))
231 prm.read_json(vm["params"].as<string>());
232
233 if (vm.count("prm")) {
234 for (const string& v : vm["prm"].as<std::vector<string>>()) {
235 prm.putKeyValue(v);
236 }
237 }
238
239 prof.tic("read problem");
240 std::vector<ptrdiff_t> ptr;
241 std::vector<ptrdiff_t> col;
242 std::vector<double> val;
243 std::vector<double> rhs;
244
245 std::vector<ptrdiff_t> domain = read_problem(
246 world,
247 vm["matrix"].as<string>(), vm["rhs"].as<string>(), vm["part"].as<string>(),
248 ptr, col, val, rhs);
249
250 ptrdiff_t chunk = domain[world.rank + 1] - domain[world.rank];
251 prof.toc("read problem");
252
253 std::vector<char> pm;
254 if (vm.count("pmask")) {
255 std::string pmask = vm["pmask"].as<string>();
256 prm.put("precond.pmask_size", chunk);
257
258 switch (pmask[0]) {
259 case '%':
260 case '<':
261 case '>':
262 prm.put("precond.pmask_pattern", pmask);
263 break;
264 default:
265 precondition(false, "Pressure mask may only be set with a pattern");
266 }
267 }
268
269 std::function<double(ptrdiff_t, unsigned)> dv = Alina::constant_deflation(1);
270 prm.put("precond.psolver.num_def_vec", 1);
271 prm.put("precond.psolver.def_vec", &dv);
272
273 Backend::params bprm;
274
275#if defined(SOLVER_BACKEND_VEXCL)
276 vex::Context ctx(vex::Filter::Env);
277 std::cout << ctx << std::endl;
278 bprm.q = ctx;
279#elif defined(SOLVER_BACKEND_CUDA)
280 cusparseCreate(&bprm.cusparse_handle);
281#endif
282
283 auto f = Backend::copy_vector(rhs, bprm);
284 auto x = Backend::create_vector(chunk, bprm);
285
286 Alina::backend::clear(*x);
287
288 world.barrier();
289
290 prof.tic("setup");
302 Solver;
303
304 Solver solve(context, world, std::tie(chunk, ptr, col, val), prm, bprm);
305 double tm_setup = prof.toc("setup");
306
307 prof.tic("solve");
308 Alina::SolverResult r = solve(*f, *x);
309 double tm_solve = prof.toc("solve");
310
311 if (world.rank == 0) {
312 std::cout << "Iters: " << r.nbIteration() << std::endl
313 << "Error: " << r.residual() << std::endl
314 << prof << std::endl;
315 }
316}
Algebraic multigrid method.
Definition AMG.h:71
Runtime wrapper for distributed direct solvers.
Iterative solver wrapper for distributed linear systems.
Préconditionneur de correction de pression par complément de Schur distribué.
Solveur distribué basé sur la déflation de sous-domaines.
Matrix market reader.
Definition IO.h:54
Classe pour stocker les paramètres sous forme d'arbre hiérarchique clé/valeur.
Definition AlinaUtils.h:113
Allows to use an AMG smoother as standalone preconditioner.
Definition Relaxation.h:144
Résultat d'une solution.
Definition AlinaUtils.h:56
Version autonome de IMessagePassingMng associée à un communicateur MPI.
Décrit un ensemble d'options en ligne de commande.
Stocke les valeurs d'options analysées.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Wrapper de commodité autour de MPI_Comm.
Vecteurs de déflation constants ponctuels.