Arcane  v4.1.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
DistributedMatrixMarketSolver.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 <algorithm>
29#include <numeric>
30#include <cmath>
31#include <cassert>
32
33#include <boost/scope_exit.hpp>
34
35#include <boost/program_options.hpp>
36
37#include "arccore/alina/AMG.h"
38#include "arccore/alina/CoarseningRuntime.h"
39#include "arccore/alina/RelaxationRuntime.h"
40#include "arccore/alina/DistributedSubDomainDeflation.h"
41#include "arccore/alina/DistributedSolverRuntime.h"
42#include "arccore/alina/DistributedDirectSolverRuntime.h"
43#include "arccore/alina/Profiler.h"
44
45using namespace Arcane;
46using namespace Arcane::Alina;
47
48using Alina::precondition;
49
50//---------------------------------------------------------------------------
51std::vector<ptrdiff_t>
52read_problem(const Alina::mpi_communicator& world,
53 const std::string& A_file,
54 const std::string& rhs_file,
55 const std::string& part_file,
56 int block_size,
57 std::vector<ptrdiff_t>& ptr,
58 std::vector<ptrdiff_t>& col,
59 std::vector<double>& val,
60 std::vector<double>& rhs)
61{
62 // Read partition
63 std::vector<int> part;
64 std::vector<ptrdiff_t> domain(world.size + 1, 0);
65 ptrdiff_t n = 0;
66 std::string line;
67
68 {
69 std::ifstream f(part_file.c_str());
70 precondition(f, "Failed to open part file (" + part_file + ")");
71
72 while (std::getline(f, line)) {
73 if (line[0] == '%')
74 continue;
75 std::istringstream is(line);
76 ptrdiff_t cols;
77 precondition(is >> n >> cols, "Unsupported format in matrix file");
78 break;
79 }
80
81 precondition(n, "Zero sized partition vector");
82 precondition(n % block_size == 0, "Matrix size is not divisible by block_size");
83
84 part.reserve(n);
85
86 while (std::getline(f, line)) {
87 if (line[0] == '%')
88 continue;
89 std::istringstream is(line);
90 int p;
91 precondition(is >> p, "Unsupported format in part file");
92 precondition(p < world.size, "MPI world does not correspond to partition");
93
94 part.push_back(p);
95 ++domain[p + 1];
96 }
97
98 std::partial_sum(domain.begin(), domain.end(), domain.begin());
99 }
100
101 ptrdiff_t chunk_beg = domain[world.rank];
102 ptrdiff_t chunk_end = domain[world.rank + 1];
103 ptrdiff_t chunk = chunk_end - chunk_beg;
104
105 // Reorder unknowns
106 std::vector<ptrdiff_t> order(n);
107 {
108 for (ptrdiff_t i = 0; i < n; ++i) {
109 int p = part[i];
110 int j = domain[p]++;
111
112 order[i] = j;
113 }
114
115 std::rotate(domain.begin(), domain.end() - 1, domain.end());
116 domain[0] = 0;
117 }
118
119 // Read matrix chunk
120 {
121 std::ifstream A(A_file.c_str());
122 precondition(A, "Failed to open matrix file (" + A_file + ")");
123
124 ptrdiff_t nnz = 0;
125 while (std::getline(A, line)) {
126 if (line[0] == '%')
127 continue;
128 std::istringstream is(line);
129 ptrdiff_t rows, m;
130 precondition(is >> rows >> m >> nnz, "Unsupported format in matrix file");
131 precondition(rows == n, "Matrix and partition have incompatible sizes");
132 precondition(n == m, "Non-square matrix in matrix file");
133 break;
134 }
135
136 {
137 std::vector<ptrdiff_t> I, J;
138 std::vector<double> V;
139
140 ptr.clear();
141 ptr.resize(chunk + 1, 0);
142
143 while (std::getline(A, line)) {
144 if (line[0] == '%')
145 continue;
146 std::istringstream is(line);
147 ptrdiff_t i, j;
148 double v;
149 precondition(is >> i >> j >> v, "Unsupported format in matrix file");
150 --i;
151 --j;
152
153 if (part[i] != world.rank)
154 continue;
155
156 ++ptr[order[i] + 1 - chunk_beg];
157
158 I.push_back(order[i] - chunk_beg);
159 J.push_back(order[j]);
160 V.push_back(v);
161 }
162
163 std::partial_sum(ptr.begin(), ptr.end(), ptr.begin());
164
165 ptrdiff_t loc_nnz = ptr.back();
166
167 col.clear();
168 col.resize(loc_nnz);
169 val.clear();
170 val.resize(loc_nnz);
171
172 for (ptrdiff_t i = 0; i < loc_nnz; ++i) {
173 ptrdiff_t row = I[i];
174 col[ptr[row]] = J[i];
175 val[ptr[row]] = V[i];
176 ++ptr[row];
177 }
178 std::rotate(ptr.begin(), ptr.end() - 1, ptr.end());
179 ptr[0] = 0;
180 }
181 }
182
183 // Read RHS chunk.
184 {
185 std::ifstream f(rhs_file.c_str());
186 precondition(f, "Failed to open rhs file (" + rhs_file + ")");
187
188 while (std::getline(f, line)) {
189 if (line[0] == '%')
190 continue;
191 std::istringstream is(line);
192 ptrdiff_t rows, cols;
193 precondition(is >> rows >> cols, "Unsupported format in matrix file");
194 precondition(rows == n, "RHS size should coincide with matrix size");
195 break;
196 }
197
198 rhs.clear();
199 rhs.reserve(chunk);
200
201 ptrdiff_t pos = 0;
202 while (std::getline(f, line)) {
203 if (line[0] == '%')
204 continue;
205 std::istringstream is(line);
206 double v;
207 precondition(is >> v, "Unsupported format in RHS file");
208
209 if (part[pos++] != world.rank)
210 continue;
211
212 rhs.push_back(v);
213 }
214
215 assert(rhs.size() + 1 == ptr.size());
216 }
217
218 return domain;
219}
220
221//---------------------------------------------------------------------------
222int main(int argc, char* argv[])
223{
224 auto& prof = Alina::Profiler::globalProfiler();
225 int provided;
226 MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
227 BOOST_SCOPE_EXIT(void)
228 {
229 MPI_Finalize();
230 }
231 BOOST_SCOPE_EXIT_END
232
233 Alina::mpi_communicator world(MPI_COMM_WORLD);
234
235 if (world.rank == 0)
236 std::cout << "World size: " << world.size << std::endl;
237
238 // Read configuration from command line
239 auto coarsening = Alina::eCoarserningType::smoothed_aggregation;
240 auto relaxation = Alina::eRelaxationType::spai0;
241 auto iterative_solver = Alina::eSolverType::bicgstabl;
242 auto direct_solver = Alina::eDistributedDirectSolverType::skyline_lu;
243 std::string parameter_file;
244 std::string A_file = "A.mtx";
245 std::string rhs_file = "b.mtx";
246 std::string part_file = "partition.mtx";
247 std::string out_file;
248
249 namespace po = boost::program_options;
250 po::options_description desc("Options");
251
252 desc.add_options()("help,h", "show help")(
253 "coarsening,c",
254 po::value<Alina::eCoarserningType>(&coarsening)->default_value(coarsening),
255 "ruge_stuben, aggregation, smoothed_aggregation, smoothed_aggr_emin")(
256 "relaxation,r",
257 po::value<Alina::eRelaxationType>(&relaxation)->default_value(relaxation),
258 "gauss_seidel, ilu0, damped_jacobi, spai0, chebyshev")(
259 "iter_solver,i",
260 po::value<Alina::eSolverType>(&iterative_solver)->default_value(iterative_solver),
261 "cg, bicgstab, bicgstabl, gmres")(
262 "dir_solver,d",
263 po::value<Alina::eDistributedDirectSolverType>(&direct_solver)->default_value(direct_solver),
264 "skyline_lu"
265#ifdef ARCCORE_ALINA_HAVE_PASTIX
266 ", pastix"
267#endif
268 )(
269 "params,p",
270 po::value<std::string>(&parameter_file),
271 "parameter file in json format")(
272 "matrix,A",
273 po::value<std::string>(&A_file)->default_value(A_file),
274 "The system matrix in MatrixMarket format")(
275 "rhs,b",
276 po::value<std::string>(&rhs_file)->default_value(rhs_file),
277 "The right-hand side in MatrixMarket format")(
278 "part,s",
279 po::value<std::string>(&part_file)->default_value(part_file),
280 "Partitioning of the problem in MatrixMarket format")(
281 "output,o",
282 po::value<std::string>(&out_file),
283 "The output file (saved in MatrixMarket format)");
284
285 po::variables_map vm;
286 po::store(po::parse_command_line(argc, argv, desc), vm);
287 po::notify(vm);
288
289 if (vm.count("help")) {
290 if (world.rank == 0)
291 std::cout << desc << std::endl;
292 return 0;
293 }
294
296 if (vm.count("params"))
297 prm.read_json(parameter_file);
298
299 prm.put("local.coarsening.type", coarsening);
300 prm.put("local.relax.type", relaxation);
301 prm.put("isolver.type", iterative_solver);
302 prm.put("dsolver.type", direct_solver);
303
304 int block_size = prm.get("precond.coarsening.aggr.block_size", 1);
305
306 prof.tic("read problem");
307 std::vector<ptrdiff_t> ptr;
308 std::vector<ptrdiff_t> col;
309 std::vector<double> val;
310 std::vector<double> rhs;
311
312 std::vector<ptrdiff_t> domain = read_problem(
313 world, A_file, rhs_file, part_file, block_size, ptr, col, val, rhs);
314
315 ptrdiff_t chunk = domain[world.rank + 1] - domain[world.rank];
316 prof.toc("read problem");
317
318 prof.tic("setup");
325
326 std::function<double(ptrdiff_t, unsigned)> dv = Alina::constant_deflation(block_size);
327 prm.put("num_def_vec", block_size);
328 prm.put("def_vec", &dv);
329
330 SDD solve(world, std::tie(chunk, ptr, col, val), prm);
331 double tm_setup = prof.toc("setup");
332
333 std::vector<double> x(chunk, 0);
334
335 prof.tic("solve");
336 size_t iters;
337 double resid;
338 std::tie(iters, resid) = solve(rhs, x);
339 double tm_solve = prof.toc("solve");
340
341 if (vm.count("output")) {
342 prof.tic("save");
343 for (int r = 0; r < world.size; ++r) {
344 if (r == world.rank) {
345 std::ofstream f(out_file.c_str(), r == 0 ? std::ios::trunc : std::ios::app);
346
347 if (r == 0) {
348 f << "%%MatrixMarket matrix array real general\n"
349 << domain.back() << " 1\n";
350 }
351
352 std::ostream_iterator<double> oi(f, "\n");
353 std::copy(x.begin(), x.end(), oi);
354 }
355 MPI_Barrier(world);
356 }
357 prof.toc("save");
358 }
359
360 if (world.rank == 0) {
361 std::cout << "Iterations: " << iters << std::endl
362 << "Error: " << resid << std::endl
363 << std::endl
364 << prof << std::endl;
365 }
366}
Algebraic multigrid method.
Definition AMG.h:71
Runtime wrapper for distributed direct solvers.
Distributed solver based on subdomain deflation.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
Runtime configurable relaxation.
Pointwise constant deflation vectors.
Convenience wrapper around MPI_Comm.