Arcane  4.2.3.0
Developer documentation
Loading...
Searching...
No Matches
DistributedCPR.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// To remove warnings about deprecated Eigen usage.
20#pragma GCC diagnostic ignored "-Wdeprecated-copy"
21#pragma GCC diagnostic ignored "-Wint-in-bool-context"
22
23#include <boost/range/iterator_range.hpp>
24
25#include "arccore/alina/IO.h"
26#include "arccore/alina/Adapters.h"
27#include "arccore/alina/BuiltinBackend.h"
28#include "arccore/alina/DistributedPreconditionedSolver.h"
29#include "arccore/alina/DistributedCPRPreconditioner.h"
30#include "arccore/alina/DistributedAMG.h"
31#include "arccore/alina/DistributedCoarseningRuntime.h"
32#include "arccore/alina/DistributedRelaxationRuntime.h"
33#include "arccore/alina/DistributedSolverRuntime.h"
34#include "arccore/alina/DistributedDirectSolverRuntime.h"
35#include "arccore/alina/MatrixPartitionerRuntime.h"
36#include "arccore/alina/Profiler.h"
37#include "arccore/alina/AlinaUtils.h"
38
39#include "arccore/common/internal/ProgramOptions.h"
40
41using namespace Arcane;
42using namespace Arcane::Alina;
43
44using Alina::precondition;
45
46//---------------------------------------------------------------------------
47ptrdiff_t
48read_matrix_market(Alina::AlinaCommunicator comm,
49 const std::string& A_file, const std::string& rhs_file, int block_size,
50 std::vector<ptrdiff_t>& ptr,
51 std::vector<ptrdiff_t>& col,
52 std::vector<double>& val,
53 std::vector<double>& rhs)
54{
55 Alina::IO::mm_reader A_mm(A_file);
56 ptrdiff_t n = A_mm.rows();
57
58 ptrdiff_t chunk = (n + comm.size - 1) / comm.size;
59 if (chunk % block_size != 0) {
60 chunk += block_size - chunk % block_size;
61 }
62
63 ptrdiff_t row_beg = std::min(n, chunk * comm.rank);
64 ptrdiff_t row_end = std::min(n, row_beg + chunk);
65
66 chunk = row_end - row_beg;
67
68 A_mm(ptr, col, val, row_beg, row_end);
69
70 if (rhs_file.empty()) {
71 rhs.resize(chunk);
72 std::fill(rhs.begin(), rhs.end(), 1.0);
73 }
74 else {
75 Alina::IO::mm_reader rhs_mm(rhs_file);
76 rhs_mm(rhs, row_beg, row_end);
77 }
78
79 return chunk;
80}
81
82//---------------------------------------------------------------------------
83ptrdiff_t
84read_binary(Alina::AlinaCommunicator comm,
85 const std::string& A_file, const std::string& rhs_file, int block_size,
86 std::vector<ptrdiff_t>& ptr,
87 std::vector<ptrdiff_t>& col,
88 std::vector<double>& val,
89 std::vector<double>& rhs)
90{
91 ptrdiff_t n = Alina::IO::crs_size<ptrdiff_t>(A_file);
92
93 ptrdiff_t chunk = (n + comm.size - 1) / comm.size;
94 if (chunk % block_size != 0) {
95 chunk += block_size - chunk % block_size;
96 }
97
98 ptrdiff_t row_beg = std::min(n, chunk * comm.rank);
99 ptrdiff_t row_end = std::min(n, row_beg + chunk);
100
101 chunk = row_end - row_beg;
102
103 Alina::IO::read_crs(A_file, n, ptr, col, val, row_beg, row_end);
104
105 if (rhs_file.empty()) {
106 rhs.resize(chunk);
107 std::fill(rhs.begin(), rhs.end(), 1.0);
108 }
109 else {
110 ptrdiff_t rows, cols;
111 Alina::IO::read_dense(rhs_file, rows, cols, rhs, row_beg, row_end);
112 }
113
114 return chunk;
115}
116
117//---------------------------------------------------------------------------
118template <class Backend, class Matrix>
119std::shared_ptr<Alina::DistributedMatrix<Backend>>
120partition(Alina::AlinaCommunicator comm, const Matrix& Astrip,
121 std::vector<double>& rhs, const typename Backend::params& bprm,
122 Alina::eMatrixPartitionerType ptype, int block_size = 1)
123{
124 auto& prof = Alina::Profiler::globalProfiler();
125 typedef Alina::DistributedMatrix<Backend> DMatrix;
126
127 auto A = std::make_shared<DMatrix>(comm, Astrip);
128
129 if (comm.size == 1 || ptype == Alina::eMatrixPartitionerType::merge)
130 return A;
131
132 prof.tic("partition");
134 prm.put("type", ptype);
136
137 auto I = part(*A, block_size);
138 auto J = transpose(*I);
139 A = product(*J, *product(*A, *I));
140
141 std::vector<double> new_rhs(J->loc_rows());
142
143 J->move_to_backend(bprm);
144
145 Alina::backend::spmv(1, *J, rhs, 0, new_rhs);
146 rhs.swap(new_rhs);
147 prof.toc("partition");
148
149 return A;
150}
151
152//---------------------------------------------------------------------------
153
154int main(int argc, char* argv[])
155{
156 auto& prof = Alina::Profiler::globalProfiler();
157 auto mpm = MessagePassing::Mpi::StandaloneMpiMessagePassingMng::createAndInitializeMPI(&argc, &argv, MPI_THREAD_MULTIPLE);
158 Alina::AlinaCommunicator comm(mpm);
159
160 Alina::AlinaContext context;
161 if (comm.rank == 0)
162 std::cout << "World size: " << comm.size << std::endl;
163
164 // Read configuration from command line
165 namespace po = Arcane::ProgramOptions;
166 po::options_description desc("Options");
167
168 desc.add_options()("help,h", "show help");
169 desc.add_options()("matrix,A",
170 po::value<std::string>(),
171 "System matrix in the MatrixMarket format. "
172 "When not specified, a Poisson problem in 3D unit cube is assembled. ");
173 desc.add_options()("rhs,f",
174 po::value<std::string>()->default_value(""),
175 "The RHS vector in the MatrixMarket format. "
176 "When omitted, a vector of ones is used by default. "
177 "Should only be provided together with a system matrix. ");
178 desc.add_options()("binary,B",
179 po::bool_switch()->default_value(false),
180 "When specified, treat input files as binary instead of as MatrixMarket. "
181 "It is assumed the files were converted to binary format with mm2bin utility. ");
182 desc.add_options()("block-size,b",
183 po::value<int>()->default_value(1),
184 "The block size of the system matrix. ");
185 desc.add_options()("partitioner,r",
186 po::value<Alina::eMatrixPartitionerType>()->default_value(
187#if defined(ARCCORE_ALINA_HAVE_PARMETIS)
188 Alina::eMatrixPartitionerType::parmetis
189#endif
190 ),
191 "Repartition the system matrix");
192 desc.add_options()("prm-file,P",
193 po::value<std::string>(),
194 "Parameter file in json format. ");
195 desc.add_options()("prm,p",
196 po::value<std::vector<std::string>>()->multitoken(),
197 "Parameters specified as name=value pairs. "
198 "May be provided multiple times. Examples:\n"
199 " -p solver.tol=1e-3\n"
200 " -p precond.coarse_enough=300");
201
203 po::store(po::parse_command_line(argc, argv, desc), vm);
204 po::notify(vm);
205
206 if (vm.count("help")) {
207 if (comm.rank == 0)
208 std::cout << desc << std::endl;
209 return 0;
210 }
211
213 if (vm.count("prm-file")) {
214 prm.read_json(vm["prm-file"].as<std::string>());
215 }
216
217 if (vm.count("prm")) {
218 for (const std::string& v : vm["prm"].as<std::vector<std::string>>()) {
219 prm.putKeyValue(v);
220 }
221 }
222
223 ptrdiff_t n;
224 std::vector<ptrdiff_t> ptr;
225 std::vector<ptrdiff_t> col;
226 std::vector<double> val;
227 std::vector<double> rhs;
228
229 int block_size = vm["block-size"].as<int>();
230 prm.put("precond.block_size", block_size);
231
232 prof.tic("read");
233 if (vm["binary"].as<bool>()) {
234 n = read_binary(comm,
235 vm["matrix"].as<std::string>(),
236 vm["rhs"].as<std::string>(),
237 block_size, ptr, col, val, rhs);
238 }
239 else {
240 n = read_matrix_market(comm,
241 vm["matrix"].as<std::string>(),
242 vm["rhs"].as<std::string>(),
243 block_size, ptr, col, val, rhs);
244 }
245 prof.toc("read");
246
247 typedef Alina::BuiltinBackend<double> Backend;
248
249 auto A = partition<Backend>(comm,
250 std::tie(n, ptr, col, val), rhs, Backend::params(),
251 vm["partitioner"].as<Alina::eMatrixPartitionerType>(),
252 block_size);
253
254 prof.tic("setup");
255
256 using AMG = DistributedAMG<Backend,
261
264 AMG,
267 Solver;
268
269 Solver solve(context, comm, A, prm);
270 prof.toc("setup");
271
272 if (comm.rank == 0)
273 std::cout << solve << std::endl;
274
275 std::vector<double> x(rhs.size(), 0.0);
276
277 prof.tic("solve");
278 Alina::SolverResult r = solve(rhs, x);
279 prof.toc("solve");
280
281 if (comm.rank == 0) {
282 std::cout << "Iterations: " << r.nbIteration() << std::endl
283 << "Error: " << r.residual() << std::endl
284 << prof << std::endl;
285 }
286}
Algebraic multigrid method.
Definition AMG.h:71
Runtime wrapper for distributed direct solvers.
Distributed Matrix using message passing.
Iterative solver wrapper for distributed linear systems.
Matrix market reader.
Definition IO.h:54
Class to store parameters as a hierarchical key/value tree.
Definition AlinaUtils.h:113
Result of a solution.
Definition AlinaUtils.h:56
Matrix class, to be used by user.
static Ref< IMessagePassingMng > createAndInitializeMPI(int *argc, char **argv[], int wanted_thread_level)
Initialize MPI and creates a manager associated with the MPI_WORLD_COMM communicator.
Describes a set of command-line options.
Stores parsed option values.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Convenience wrapper around MPI_Comm.
Use a relaxation as a distributed preconditioner.
Distributed memory sparse approximate inverse relaxation scheme.
Runtime-configurable wrapper around matrix partitioner.