Arcane  4.2.3.0
Developer documentation
Loading...
Searching...
No Matches
DistributedRuntimeBP.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 <iostream>
20#include <vector>
21#include <string>
22#include <utility>
23#include <numeric>
24
25#include <boost/range/iterator_range.hpp>
26
27#include "arccore/alina/BuiltinBackend.h"
28#include "arccore/alina/PreconditionerRuntime.h"
29#include "arccore/alina/Adapters.h"
30#include "arccore/alina/DistributedPreconditionedSolver.h"
31#include "arccore/alina/DistributedSolverRuntime.h"
32#include "arccore/alina/DistributedPreconditioner.h"
33#include "arccore/alina/Profiler.h"
34#include "arccore/alina/AlinaUtils.h"
35
36// For compilation test only
37#include "arccore/alina/DistributedSolver.h"
38
39// For compilation test only
40#include "arccore/alina/DistributedRelaxationRuntime.h"
41
42#include "arccore/common/internal/ProgramOptions.h"
43
44#include "DomainPartition.h"
45
46using namespace Arcane;
47using namespace Arcane::Alina;
48
49using Alina::precondition;
50
51//---------------------------------------------------------------------------
52struct renumbering
53{
54 const DomainPartition<2>& part;
55 const std::vector<ptrdiff_t>& dom;
56
57 renumbering(const DomainPartition<2>& p,
58 const std::vector<ptrdiff_t>& d)
59 : part(p)
60 , dom(d)
61 {}
62
63 ptrdiff_t operator()(ptrdiff_t i, ptrdiff_t j) const
64 {
65 boost::array<ptrdiff_t, 2> p = { { i, j } };
66 std::pair<int, ptrdiff_t> v = part.index(p);
67 return dom[v.first] + v.second;
68 }
69};
70
71//---------------------------------------------------------------------------
72
73template <template <class> class Precond, class Matrix>
75solve(const AlinaContext& context,
76 const AlinaCommunicator& comm,
77 const PropertyTree& prm,
78 const Matrix& A)
79{
80 auto& prof = Alina::Profiler::globalProfiler();
81
82 typedef Alina::BuiltinBackend<double> Backend;
83
85
86 const size_t n = Alina::backend::nbRow(A);
87
88 std::vector<double> rhs(n, 1), x(n, 0);
89
90 prof.tic("setup");
91 Solver solve(context, comm, A, prm);
92 prof.toc("setup");
93
94 {
95 auto t2 = prof.scoped_tic("solve");
96 return solve(rhs, x);
97 }
98}
99
100//---------------------------------------------------------------------------
101
102int main(int argc, char* argv[])
103{
104 auto& prof = Alina::Profiler::globalProfiler();
105 namespace po = Arcane::ProgramOptions;
106
107 using std::string;
108 using std::vector;
109
110 Alina::AlinaContext context;
111 po::options_description desc("Options");
112
113 desc.add_options()("help,h", "Show this help.");
114 desc.add_options()("prm-file,P",
115 po::value<string>(),
116 "Parameter file in json format. ");
117 desc.add_options()("prm,p",
118 po::value<vector<string>>()->multitoken(),
119 "Parameters specified as name=value pairs. "
120 "May be provided multiple times. Examples:\n"
121 " -p solver.tol=1e-3\n"
122 " -p precond.coarse_enough=300");
123 desc.add_options()("size,n",
124 po::value<int>()->default_value(1024),
125 "The size of the Poisson problem to solve. "
126 "Specified as number of grid nodes along each dimension of a unit square. "
127 "The resulting system will have n*n unknowns. ");
128 desc.add_options()("single-level,1",
129 po::bool_switch()->default_value(false),
130 "When specified, the AMG hierarchy is not constructed. "
131 "Instead, the problem is solved using a single-level smoother as preconditioner. ");
132 desc.add_options()("initial,x",
133 po::value<double>()->default_value(0),
134 "Value to use as initial approximation. ");
135
137 po::store(po::parse_command_line(argc, argv, desc), vm);
138 po::notify(vm);
139
140 if (vm.count("help")) {
141 std::cout << desc << std::endl;
142 return 0;
143 }
144
146 if (vm.count("prm-file")) {
147 prm.read_json(vm["prm-file"].as<string>());
148 }
149
150 if (vm.count("prm")) {
151 for (const string& v : vm["prm"].as<vector<string>>()) {
152 prm.putKeyValue(v);
153 }
154 }
155
156 auto mpm = MessagePassing::Mpi::StandaloneMpiMessagePassingMng::createAndInitializeMPI(&argc, &argv, MPI_THREAD_MULTIPLE);
157 Alina::AlinaCommunicator world(mpm);
158
159 if (world.rank == 0)
160 std::cout << "World size: " << world.size << std::endl;
161
162 const ptrdiff_t n = vm["size"].as<int>();
163 const double h2i = (n - 1) * (n - 1);
164
165 boost::array<ptrdiff_t, 2> lo = { { 0, 0 } };
166 boost::array<ptrdiff_t, 2> hi = { { n - 1, n - 1 } };
167
168 prof.tic("partition");
169 DomainPartition<2> part(lo, hi, world.size);
170 ptrdiff_t chunk = part.size(world.rank);
171
172 std::vector<ptrdiff_t> domain(world.size + 1);
173 ConstArrayView<ptrdiff_t> send_buf(1, &chunk);
174 ArrayView<ptrdiff_t> receive_buf(world.size, &domain[1]);
175 mpAllGather(world.m_message_passing_mng.get(), send_buf, receive_buf);
176 std::partial_sum(domain.begin(), domain.end(), domain.begin());
177
178 lo = part.domain(world.rank).min_corner();
179 hi = part.domain(world.rank).max_corner();
180 prof.toc("partition");
181
182 renumbering renum(part, domain);
183
184 prof.tic("assemble");
185 std::vector<ptrdiff_t> ptr;
186 std::vector<ptrdiff_t> col;
187 std::vector<double> val;
188 std::vector<double> rhs;
189
190 ptr.reserve(chunk + 1);
191 col.reserve(chunk * 5);
192 val.reserve(chunk * 5);
193
194 ptr.push_back(0);
195
196 for (ptrdiff_t j = lo[1]; j <= hi[1]; ++j) {
197 for (ptrdiff_t i = lo[0]; i <= hi[0]; ++i) {
198 if (j > 0) {
199 col.push_back(renum(i, j - 1));
200 val.push_back(-h2i);
201 }
202
203 if (i > 0) {
204 col.push_back(renum(i - 1, j));
205 val.push_back(-h2i);
206 }
207
208 col.push_back(renum(i, j));
209 val.push_back(4 * h2i);
210
211 if (i + 1 < n) {
212 col.push_back(renum(i + 1, j));
213 val.push_back(-h2i);
214 }
215
216 if (j + 1 < n) {
217 col.push_back(renum(i, j + 1));
218 val.push_back(-h2i);
219 }
220
221 ptr.push_back(col.size());
222 }
223 }
224 prof.toc("assemble");
225
226 bool single_level = vm["single-level"].as<bool>();
227
228 if (single_level)
229 prm.put("precond.class", "relaxation");
230
231 Alina::SolverResult r = solve<Alina::PreconditionerRuntime>(context, world, prm, std::tie(chunk, ptr, col, val));
232
233 if (world.rank == 0) {
234 std::cout << "Iterations: " << r.nbIteration() << std::endl
235 << "Error: " << r.residual() << std::endl
236 << std::endl
237 << prof << std::endl;
238 }
239}
Iterative solver wrapper for distributed linear systems.
Class to store parameters as a hierarchical key/value tree.
Definition AlinaUtils.h:113
Result of a solution.
Definition AlinaUtils.h:56
Modifiable view of an array of type T.
Constant view of an array of type T.
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.
void mpAllGather(IMessagePassingMng *pm, const ISerializer *send_serializer, ISerializer *receive_serialize)
allGather() message for serialization
Definition Messages.cc:319
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Convenience wrapper around MPI_Comm.