Arcane  v4.1.10.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 * This file is based on the work on AMGCL library (version march 2026)
11 * which can be found at 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/program_options.hpp>
32#include <boost/range/iterator_range.hpp>
33#include <boost/scope_exit.hpp>
34
35#if defined(SOLVER_BACKEND_CUDA)
36# include "arccore/alina/CudaBackend.h"
37# include "arccore/alina/relaxation_cusparse_ilu0.h"
39#else
40# ifndef SOLVER_BACKEND_BUILTIN
41# define SOLVER_BACKEND_BUILTIN
42# endif
43#include "arccore/alina/BuiltinBackend.h"
45#endif
46
47#include "arccore/alina/IO.h"
48#include "arccore/alina/Adapters.h"
49#include "arccore/alina/AMG.h"
50#include "arccore/alina/CoarseningRuntime.h"
51#include "arccore/alina/RelaxationRuntime.h"
52#include "arccore/alina/DistributedPreconditionedSolver.h"
53#include "arccore/alina/DistributedSchurPressureCorrection.h"
54#include "arccore/alina/DistributedPreconditioner.h"
55#include "arccore/alina/DistributedSubDomainDeflation.h"
56#include "arccore/alina/DistributedSolverRuntime.h"
57#include "arccore/alina/DistributedDirectSolverRuntime.h"
58#include "arccore/alina/Profiler.h"
59
60using namespace Arcane;
61using namespace Arcane::Alina;
62
63using Alina::precondition;
64
65//---------------------------------------------------------------------------
66std::vector<ptrdiff_t>
67read_problem(const Alina::mpi_communicator& 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 // Read 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 // Reorder unknowns
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 // Read matrix chunk
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 // Count local nonzeros
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 // Read local matrix and rhs stripes
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();
182
183 int provided;
184 MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
185 BOOST_SCOPE_EXIT(void)
186 {
187 MPI_Finalize();
188 }
189 BOOST_SCOPE_EXIT_END
190
191 Alina::mpi_communicator world(MPI_COMM_WORLD);
192
193 if (world.rank == 0)
194 std::cout << "World size: " << world.size << std::endl;
195
196 // Read configuration from command line
197 namespace po = boost::program_options;
198 using std::string;
199 po::options_description desc("Options");
200
201 desc.add_options()("help,h", "show help")(
202 "matrix,A",
203 po::value<string>()->required(),
204 "The system matrix in binary format")(
205 "rhs,f",
206 po::value<string>(),
207 "The right-hand side in binary format")(
208 "part,s",
209 po::value<string>()->required(),
210 "Partitioning of the problem in MatrixMarket format")(
211 "pmask,m",
212 po::value<string>(),
213 "The pressure mask in binary format. Or, if the parameter has "
214 "the form '%n:m', then each (n+i*m)-th variable is treated as pressure.")(
215 "params,P",
216 po::value<string>(),
217 "parameter file in json format")(
218 "prm,p",
219 po::value<std::vector<string>>()->multitoken(),
220 "Parameters specified as name=value pairs. "
221 "May be provided multiple times. Examples:\n"
222 " -p solver.tol=1e-3\n"
223 " -p precond.coarse_enough=300");
224
225 po::variables_map vm;
226 po::store(po::parse_command_line(argc, argv, desc), vm);
227
228 if (vm.count("help")) {
229 if (world.rank == 0)
230 std::cout << desc << std::endl;
231 return 0;
232 }
233
234 po::notify(vm);
235
237 if (vm.count("params"))
238 prm.read_json(vm["params"].as<string>());
239
240 if (vm.count("prm")) {
241 for (const string& v : vm["prm"].as<std::vector<string>>()) {
242 prm.putKeyValue(v);
243 }
244 }
245
246 prof.tic("read problem");
247 std::vector<ptrdiff_t> ptr;
248 std::vector<ptrdiff_t> col;
249 std::vector<double> val;
250 std::vector<double> rhs;
251
252 std::vector<ptrdiff_t> domain = read_problem(
253 world,
254 vm["matrix"].as<string>(), vm["rhs"].as<string>(), vm["part"].as<string>(),
255 ptr, col, val, rhs);
256
257 ptrdiff_t chunk = domain[world.rank + 1] - domain[world.rank];
258 prof.toc("read problem");
259
260 std::vector<char> pm;
261 if (vm.count("pmask")) {
262 std::string pmask = vm["pmask"].as<string>();
263 prm.put("precond.pmask_size", chunk);
264
265 switch (pmask[0]) {
266 case '%':
267 case '<':
268 case '>':
269 prm.put("precond.pmask_pattern", pmask);
270 break;
271 default:
272 precondition(false, "Pressure mask may only be set with a pattern");
273 }
274 }
275
276 std::function<double(ptrdiff_t, unsigned)> dv = Alina::constant_deflation(1);
277 prm.put("precond.psolver.num_def_vec", 1);
278 prm.put("precond.psolver.def_vec", &dv);
279
280 Backend::params bprm;
281
282#if defined(SOLVER_BACKEND_VEXCL)
283 vex::Context ctx(vex::Filter::Env);
284 std::cout << ctx << std::endl;
285 bprm.q = ctx;
286#elif defined(SOLVER_BACKEND_CUDA)
287 cusparseCreate(&bprm.cusparse_handle);
288#endif
289
290 auto f = Backend::copy_vector(rhs, bprm);
291 auto x = Backend::create_vector(chunk, bprm);
292
293 Alina::backend::clear(*x);
294
295 MPI_Barrier(world);
296
297 prof.tic("setup");
309 Solver;
310
311 Solver solve(world, std::tie(chunk, ptr, col, val), prm, bprm);
312 double tm_setup = prof.toc("setup");
313
314 prof.tic("solve");
315 Alina::SolverResult r = solve(*f, *x);
316 double tm_solve = prof.toc("solve");
317
318 if (world.rank == 0) {
319 std::cout << "Iters: " << r.nbIteration() << std::endl
320 << "Error: " << r.residual() << std::endl
321 << prof << std::endl;
322 }
323}
Algebraic multigrid method.
Definition AMG.h:71
Runtime wrapper for distributed direct solvers.
Iterative solver wrapper for distributed linear systems.
Distributed Schur complement pressure correction preconditioner.
Distributed solver based on subdomain deflation.
Matrix market reader.
Definition IO.h:52
Allows to use an AMG smoother as standalone preconditioner.
Definition Relaxation.h:144
Result of a solving.
Definition AlinaUtils.h:52
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
Alina::detail::empty_params params
Pointwise constant deflation vectors.
Convenience wrapper around MPI_Comm.