Arcane  4.2.2.0
Developer documentation
Loading...
Searching...
No Matches
DistributedBasicSolver.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#include "arccore/alina/BuiltinBackend.h"
20#include "arccore/alina/MessagePassingUtils.h"
21#include "arccore/alina/DistributedPreconditionedSolver.h"
22#include "arccore/alina/DistributedPreconditioner.h"
23#include "arccore/alina/DistributedSolverRuntime.h"
24
25#include "arccore/alina/Profiler.h"
26
27#include "arccore/common/internal/ProgramOptions.h"
28
29#include "arccore/trace/ITraceMng.h"
30
31#include "AlinaSamplesCommon.h"
32#include "SampleProblemCommon.h"
33
34#include <iostream>
35#include <vector>
36#include <string>
37
38using namespace Arcane;
39
40//---------------------------------------------------------------------------
41template <class Backend, class Matrix>
42std::shared_ptr<Alina::DistributedMatrix<Backend>>
43partition(Alina::mpi_communicator comm, const Matrix& Astrip,
44 typename Backend::vector& rhs, const typename Backend::params& bprm,
45 Alina::eMatrixPartitionerType ptype, int block_size = 1)
46{
47 auto& prof = Alina::Profiler::globalProfiler();
48 typedef typename Backend::value_type val_type;
49 typedef typename Alina::math::rhs_of<val_type>::type rhs_type;
51
52 auto A = std::make_shared<DMatrix>(comm, Astrip);
53
54 if (comm.size == 1 || ptype == Alina::eMatrixPartitionerType::merge)
55 return A;
56
57 prof.tic("partition");
59 prm.put("type", ptype);
61
62 auto I = part(*A, block_size);
63 auto J = transpose(*I);
64 A = product(*J, *product(*A, *I));
65
66 Alina::numa_vector<rhs_type> new_rhs(J->loc_rows());
67
68 J->move_to_backend(bprm);
69
70 Alina::backend::spmv(1, *J, rhs, 0, new_rhs);
71 rhs.swap(new_rhs);
72 prof.toc("partition");
73
74 return A;
75}
76
77//---------------------------------------------------------------------------
78void solve_scalar(Alina::mpi_communicator comm,
79 ptrdiff_t chunk,
80 const std::vector<ptrdiff_t>& ptr,
81 const std::vector<ptrdiff_t>& col,
82 const std::vector<double>& val,
83 const Alina::PropertyTree& prm,
84 const std::vector<double>& f,
85 Alina::eMatrixPartitionerType ptype)
86{
87 auto& prof = Alina::Profiler::globalProfiler();
88 //using Backend = Alina::BuiltinBackend<double>;
89
90 using BackendValueType = double;
92
93 std::cout << "Using scalar solve ptr_size=" << sizeof(ptrdiff_t)
94 << " ptr_type_size=" << sizeof(Backend::ptr_type)
95 << " col_type_size=" << sizeof(Backend::col_type)
96 << " value_type_size=" << sizeof(Backend::value_type)
97 << " chunk=" << chunk
98 << "\n";
99
100 typedef Alina::DistributedMatrix<Backend> DMatrix;
101
103 using RelaxationType = Alina::DistributedSPAI0Relaxation<Backend>;
104 // If we want to test dynamic backends:
105 //using CoarseningType = Alina::DistributedCoarseningRuntime<Backend>;
106 //using RelaxationType = Alina::DistributedRelaxationRuntime<Backend>,
107
108 using AMGPrecondType = Alina::DistributedAMG<Backend, CoarseningType, RelaxationType,
111
113
114 typename Backend::params bprm;
115
117
118 auto get_distributed_matrix = [&]() {
119 auto t = prof.scoped_tic("distributed matrix");
120 std::shared_ptr<DMatrix> A;
121
122 if (ptype != Alina::eMatrixPartitionerType::merge) {
123 A = partition<Backend>(comm,
124 std::tie(chunk, ptr, col, val), rhs, bprm, ptype,
125 prm.get("precond.coarsening.aggr.block_size", 1));
126 chunk = A->loc_rows();
127 }
128 else {
129 A = std::make_shared<DMatrix>(comm, std::tie(chunk, ptr, col, val));
130 }
131
132 return A;
133 };
134
135 std::shared_ptr<DMatrix> A;
136 std::shared_ptr<Solver> solve;
137
138 {
139 auto t = prof.scoped_tic("setup");
140 A = get_distributed_matrix();
141 solve = std::make_shared<Solver>(comm, A, prm, bprm);
143 solve->prm.get(prm2);
144 std::cout << "SOLVER parameters=" << prm2 << "\n";
145 }
146
147 if (comm.rank == 0) {
148 std::cout << "SolverInfo:\n";
149 std::cout << *solve << std::endl;
150 }
151
152 if (prm.get("precond.allow_rebuild", false)) {
153 if (comm.rank == 0) {
154 std::cout << "Rebuilding the preconditioner..." << std::endl;
155 }
156
157 {
158 auto t = prof.scoped_tic("rebuild");
159 A = get_distributed_matrix();
160 solve->precond().rebuild(A);
161 }
162
163 if (comm.rank == 0) {
164 std::cout << *solve << std::endl;
165 }
166 }
167
169
170 prof.tic("solve");
171 Alina::SolverResult r = (*solve)(rhs, x);
172 prof.toc("solve");
173
174 if (comm.rank == 0) {
175 std::cout << "Iterations: " << r.nbIteration() << std::endl
176 << "Error: " << r.residual() << std::endl
177 << prof << std::endl;
178 }
179}
180
181//---------------------------------------------------------------------------
182int main2(const Alina::SampleMainContext& ctx, int argc, char* argv[])
183{
184 ITraceMng* tm = ctx.traceMng();
185 auto& prof = Alina::Profiler::globalProfiler();
186
187 //Alina::mpi_init_thread mpi(&argc, &argv);
188 Alina::mpi_communicator comm(MPI_COMM_WORLD);
189
190 tm->info() << "World size: " << comm.size;
191
192 // Read configuration from command line
193 namespace po = Arcane::ProgramOptions;
194 po::options_description desc("Options");
195
196 auto default_partitioner_type = Alina::eMatrixPartitionerType::merge;
197#if defined(ARCCORE_ALINA_HAVE_PARMETIS)
198 default_partitioner_type = Alina::eMatrixPartitionerType::parmetis;
199#endif
200
201 desc.add_options()("help,h", "show help")("matrix,A",
202 po::value<std::string>(),
203 "System matrix in the MatrixMarket format. "
204 "When not specified, a Poisson problem in 3D unit cube is assembled. ");
205 desc.add_options()("partitioner,r",
206 po::value<Alina::eMatrixPartitionerType>()->default_value(
207 default_partitioner_type),
208 "Repartition the system matrix");
209 desc.add_options()("size,n",
210 po::value<ptrdiff_t>()->default_value(32),
211 "domain size");
212 desc.add_options()("prm-file,P", po::value<std::string>(),
213 "Parameter file in json format. ");
214 desc.add_options()("prm,p",
215 po::value<std::vector<std::string>>()->multitoken(),
216 "Parameters specified as name=value pairs. "
217 "May be provided multiple times. Examples:\n"
218 " -p solver.tol=1e-3\n"
219 " -p precond.coarse_enough=300");
220 desc.add_options()("test-rebuild",
221 po::bool_switch()->default_value(false),
222 "When specified, try to rebuild the solver before solving. ");
223
225 p.add("prm", -1);
226
228 po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
229 po::notify(vm);
230
231 if (vm.count("help")) {
232 if (comm.rank == 0)
233 std::cout << desc << std::endl;
234 return 0;
235 }
236
238 if (vm.count("prm-file")) {
239 prm.read_json(vm["prm-file"].as<std::string>());
240 }
241
242 if (vm.count("prm")) {
243 for (const std::string& v : vm["prm"].as<std::vector<std::string>>()) {
244 tm->info() << "PUT_KEY_VALUE v=" << v;
245 prm.putKeyValue(v);
246 }
247 }
248
249 ptrdiff_t n;
250 std::vector<ptrdiff_t> ptr;
251 std::vector<ptrdiff_t> col;
252 std::vector<double> val;
253 std::vector<double> rhs;
254
255 Alina::eMatrixPartitionerType ptype = vm["partitioner"].as<Alina::eMatrixPartitionerType>();
256
257 prof.tic("assemble");
258 Int64 matrix_size = vm["size"].as<ptrdiff_t>();
259 tm->info() << "Matrix size=" << matrix_size;
260 n = sample_problem_distributed(comm.rank, comm.size, matrix_size, 1, ptr, col, val, rhs);
261 prof.toc("assemble");
262
263 if (vm["test-rebuild"].as<bool>()) {
264 prm.put("precond.allow_rebuild", true);
265 }
266
267 solve_scalar(comm, n, ptr, col, val, prm, rhs, ptype);
268 return 0;
269}
270
271/*---------------------------------------------------------------------------*/
272/*---------------------------------------------------------------------------*/
273
274int main(int argc, char* argv[])
275{
276 return Arcane::Alina::SampleMainContext::execMain(main2, argc, argv);
277}
278
279/*---------------------------------------------------------------------------*/
280/*---------------------------------------------------------------------------*/
Runtime wrapper for distributed direct solvers.
Distributed Matrix using message passing.
Iterative solver wrapper for distributed linear systems.
Class to store parameters as a hierarchical key/value tree.
Definition AlinaUtils.h:112
Result of a solution.
Definition AlinaUtils.h:53
NUMA-aware vector container.
Definition NumaVector.h:42
virtual TraceMessage info()=0
Stream for an information message.
Matrix class, to be used by user.
Fluent command-line parser builder.
Describes a set of command-line options.
Describes positional (non-option) arguments.
Stores parsed option values.
__host__ __device__ Real3x3 transpose(const Real3x3 &t)
Transpose the matrix.
Definition MathUtils.h:265
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Distributed smoothed aggregation coarsening scheme.
Runtime-configurable wrapper around matrix partitioner.
Convenience wrapper around MPI_Comm.