Arcane  4.2.1.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#include <boost/scope_exit.hpp>
33
34#if defined(SOLVER_BACKEND_CUDA)
35# include "arccore/alina/CudaBackend.h"
36# include "arccore/alina/relaxation_cusparse_ilu0.h"
38#else
39# ifndef SOLVER_BACKEND_BUILTIN
40# define SOLVER_BACKEND_BUILTIN
41# endif
42#include "arccore/alina/BuiltinBackend.h"
44#endif
45
46#include "arccore/alina/IO.h"
47#include "arccore/alina/Adapters.h"
48#include "arccore/alina/AMG.h"
49#include "arccore/alina/CoarseningRuntime.h"
50#include "arccore/alina/RelaxationRuntime.h"
51#include "arccore/alina/DistributedPreconditionedSolver.h"
52#include "arccore/alina/DistributedSchurPressureCorrection.h"
53#include "arccore/alina/DistributedPreconditioner.h"
54#include "arccore/alina/DistributedSubDomainDeflation.h"
55#include "arccore/alina/DistributedSolverRuntime.h"
56#include "arccore/alina/DistributedDirectSolverRuntime.h"
57#include "arccore/alina/Profiler.h"
58
59#include "arccore/common/internal/ProgramOptions.h"
60
61using namespace Arcane;
62using namespace Arcane::Alina;
63
64using Alina::precondition;
65
66//---------------------------------------------------------------------------
67std::vector<ptrdiff_t>
68read_problem(const Alina::mpi_communicator& world,
69 const std::string& A_file,
70 const std::string& rhs_file,
71 const std::string& part_file,
72 std::vector<ptrdiff_t>& ptr,
73 std::vector<ptrdiff_t>& col,
74 std::vector<double>& val,
75 std::vector<double>& rhs)
76{
77 // Lit la partition
78 ptrdiff_t n, m;
79 std::vector<ptrdiff_t> domain(world.size + 1, 0);
80 std::vector<int> part;
81
82 std::tie(n, m) = Alina::IO::mm_reader(part_file)(part);
83 for (int p : part) {
84 ++domain[p + 1];
85 precondition(p < world.size, "MPI world does not correspond to partition");
86 }
87 std::partial_sum(domain.begin(), domain.end(), domain.begin());
88
89 ptrdiff_t chunk_beg = domain[world.rank];
90 ptrdiff_t chunk_end = domain[world.rank + 1];
91 ptrdiff_t chunk = chunk_end - chunk_beg;
92
93 // Réordonne les inconnues
94 std::vector<ptrdiff_t> order(n);
95 for (ptrdiff_t i = 0; i < n; ++i)
96 order[i] = domain[part[i]]++;
97
98 std::rotate(domain.begin(), domain.end() - 1, domain.end());
99 domain[0] = 0;
100
101 // Lit le bloc de la matrice
102 {
103 using namespace Arcane::Alina::IO;
104
105 std::ifstream A(A_file.c_str(), std::ios::binary);
106 precondition(A, "Failed to open matrix file (" + A_file + ")");
107
108 std::ifstream b(rhs_file.c_str(), std::ios::binary);
109 precondition(b, "Failed to open rhs file (" + rhs_file + ")");
110
111 ptrdiff_t rows;
112 precondition(read(A, rows), "File I/O error");
113 precondition(rows == n, "Matrix and partition have incompatible sizes");
114
115 ptr.clear();
116 ptr.reserve(chunk + 1);
117 ptr.push_back(0);
118
119 std::vector<ptrdiff_t> gptr(n + 1);
120 precondition(read(A, gptr), "File I/O error");
121
122 size_t col_beg = sizeof(rows) + sizeof(gptr[0]) * (n + 1);
123 size_t val_beg = col_beg + sizeof(col[0]) * gptr.back();
124 size_t rhs_beg = 2 * sizeof(ptrdiff_t);
125
126 // Compte les non-zéros locaux
127 for (ptrdiff_t i = 0; i < n; ++i)
128 if (part[i] == world.rank)
129 ptr.push_back(gptr[i + 1] - gptr[i]);
130
131 std::partial_sum(ptr.begin(), ptr.end(), ptr.begin());
132
133 col.clear();
134 col.reserve(ptr.back());
135 val.clear();
136 val.reserve(ptr.back());
137 rhs.clear();
138 rhs.reserve(chunk);
139
140 // Lit les bandes de la matrice et du membre de droite
141 for (ptrdiff_t i = 0; i < n; ++i) {
142 if (part[i] != world.rank)
143 continue;
144
145 ptrdiff_t c;
146 A.seekg(col_beg + gptr[i] * sizeof(c));
147 for (ptrdiff_t j = gptr[i], e = gptr[i + 1]; j < e; ++j) {
148 precondition(read(A, c), "File I/O error (1)");
149 col.push_back(order[c]);
150 }
151 }
152
153 for (ptrdiff_t i = 0; i < n; ++i) {
154 if (part[i] != world.rank)
155 continue;
156
157 double v;
158 A.seekg(val_beg + gptr[i] * sizeof(v));
159 for (ptrdiff_t j = gptr[i], e = gptr[i + 1]; j < e; ++j) {
160 precondition(read(A, v), "File I/O error (2)");
161 val.push_back(v);
162 }
163 }
164
165 for (ptrdiff_t i = 0; i < n; ++i) {
166 if (part[i] != world.rank)
167 continue;
168
169 double f;
170 b.seekg(rhs_beg + i * sizeof(f));
171 precondition(read(b, f), "File I/O error (3)");
172 rhs.push_back(f);
173 }
174 }
175
176 return domain;
177}
178
179//---------------------------------------------------------------------------
180int main(int argc, char* argv[])
181{
182 auto& prof = Alina::Profiler::globalProfiler();
183
184 int provided;
185 MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
186 BOOST_SCOPE_EXIT(void)
187 {
188 MPI_Finalize();
189 }
190 BOOST_SCOPE_EXIT_END
191
192 Alina::mpi_communicator world(MPI_COMM_WORLD);
193
194 if (world.rank == 0)
195 std::cout << "World size: " << world.size << std::endl;
196
197 // Lit la configuration depuis la ligne de commande
198 namespace po = Arcane::ProgramOptions;
199 using std::string;
200 po::options_description desc("Options");
201
202 desc.add_options()("help,h", "show help")(
203 "matrix,A",
204 po::value<string>()->required(),
205 "La matrice du système au format binaire")(
206 "rhs,f",
207 po::value<string>(),
208 "Le membre de droite au format binaire")(
209 "part,s",
210 po::value<string>()->required(),
211 "Partitionnement du problème au format MatrixMarket")(
212 "pmask,m",
213 po::value<string>(),
214 "Le masque de pression au format binaire. Ou, si le paramètre a "
215 "la forme '%n:m', alors chaque variable (n+i*m)-ième est traitée comme une pression.")(
216 "params,P",
217 po::value<string>(),
218 "fichier de paramètres au format json")(
219 "prm,p",
220 po::value<std::vector<string>>()->multitoken(),
221 "Paramètres spécifiés sous forme de paires nom=valeur. "
222 "Peut être fourni plusieurs fois. Exemples :\n"
223 " -p solver.tol=1e-3\n"
224 " -p precond.coarse_enough=300");
225
227 po::store(po::parse_command_line(argc, argv, desc), vm);
228
229 if (vm.count("help")) {
230 if (world.rank == 0)
231 std::cout << desc << std::endl;
232 return 0;
233 }
234
235 po::notify(vm);
236
238 if (vm.count("params"))
239 prm.read_json(vm["params"].as<string>());
240
241 if (vm.count("prm")) {
242 for (const string& v : vm["prm"].as<std::vector<string>>()) {
243 prm.putKeyValue(v);
244 }
245 }
246
247 prof.tic("read problem");
248 std::vector<ptrdiff_t> ptr;
249 std::vector<ptrdiff_t> col;
250 std::vector<double> val;
251 std::vector<double> rhs;
252
253 std::vector<ptrdiff_t> domain = read_problem(
254 world,
255 vm["matrix"].as<string>(), vm["rhs"].as<string>(), vm["part"].as<string>(),
256 ptr, col, val, rhs);
257
258 ptrdiff_t chunk = domain[world.rank + 1] - domain[world.rank];
259 prof.toc("read problem");
260
261 std::vector<char> pm;
262 if (vm.count("pmask")) {
263 std::string pmask = vm["pmask"].as<string>();
264 prm.put("precond.pmask_size", chunk);
265
266 switch (pmask[0]) {
267 case '%':
268 case '<':
269 case '>':
270 prm.put("precond.pmask_pattern", pmask);
271 break;
272 default:
273 precondition(false, "Pressure mask may only be set with a pattern");
274 }
275 }
276
277 std::function<double(ptrdiff_t, unsigned)> dv = Alina::constant_deflation(1);
278 prm.put("precond.psolver.num_def_vec", 1);
279 prm.put("precond.psolver.def_vec", &dv);
280
281 Backend::params bprm;
282
283#if defined(SOLVER_BACKEND_VEXCL)
284 vex::Context ctx(vex::Filter::Env);
285 std::cout << ctx << std::endl;
286 bprm.q = ctx;
287#elif defined(SOLVER_BACKEND_CUDA)
288 cusparseCreate(&bprm.cusparse_handle);
289#endif
290
291 auto f = Backend::copy_vector(rhs, bprm);
292 auto x = Backend::create_vector(chunk, bprm);
293
294 Alina::backend::clear(*x);
295
296 MPI_Barrier(world);
297
298 prof.tic("setup");
310 Solver;
311
312 Solver solve(world, std::tie(chunk, ptr, col, val), prm, bprm);
313 double tm_setup = prof.toc("setup");
314
315 prof.tic("solve");
316 Alina::SolverResult r = solve(*f, *x);
317 double tm_solve = prof.toc("solve");
318
319 if (world.rank == 0) {
320 std::cout << "Iters: " << r.nbIteration() << std::endl
321 << "Error: " << r.residual() << std::endl
322 << prof << std::endl;
323 }
324}
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:112
Allows to use an AMG smoother as standalone preconditioner.
Definition Relaxation.h:144
Résultat d'une solution.
Definition AlinaUtils.h:53
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 --
Vecteurs de déflation constants ponctuels.
Wrapper de commodité autour de MPI_Comm.