Arcane  4.2.2.0
Developer documentation
Loading...
Searching...
No Matches
DistributedRuntimeSDD3D.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 the 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 <iomanip>
21#include <fstream>
22#include <vector>
23#include <array>
24#include <numeric>
25#include <cmath>
26
27// To remove warnings about deprecated Eigen usage.
28//#pragma GCC diagnostic ignored "-Wdeprecated-copy"
29//ragma GCC diagnostic ignored "-Wint-in-bool-context"
30
31#if defined(SOLVER_BACKEND_CUDA)
32// This seems not defined with CUDA
33namespace boost::math
34{
35class rounding_error
36{};
37} // namespace boost::math
38#endif
39
40#include <boost/scope_exit.hpp>
41
42#if defined(SOLVER_BACKEND_CUDA)
43# include "arccore/alina/CudaBackend.h"
44# include "arccore/alina/relaxation_cusparse_ilu0.h"
46#else
47# ifndef SOLVER_BACKEND_BUILTIN
48# define SOLVER_BACKEND_BUILTIN
49# endif
50#include "arccore/alina/BuiltinBackend.h"
52#endif
53
54#include "arccore/trace/ITraceMng.h"
55
56#include "arccore/alina/DistributedDirectSolverRuntime.h"
57#include "arccore/alina/DistributedSolverRuntime.h"
58#include "arccore/alina/DistributedSubDomainDeflation.h"
59#include "arccore/alina/AMG.h"
60#include "arccore/alina/CoarseningRuntime.h"
61#include "arccore/alina/RelaxationRuntime.h"
62#include "arccore/alina/Profiler.h"
63
64#include "arccore/common/internal/ProgramOptions.h"
65
66#include "AlinaSamplesCommon.h"
67
68using namespace Arcane;
69using namespace Arcane::Alina;
70
71#include "DomainPartition.h"
72
74{
75 size_t nv;
76 std::vector<double> x;
77 std::vector<double> y;
78 std::vector<double> z;
79
80 deflation_vectors(ptrdiff_t n, size_t nv = 4)
81 : nv(nv)
82 , x(n)
83 , y(n)
84 , z(n)
85 {}
86
87 size_t dim() const { return nv; }
88
89 double operator()(ptrdiff_t i, int j) const
90 {
91 switch (j) {
92 default:
93 case 0:
94 return 1;
95 case 1:
96 return x[i];
97 case 2:
98 return y[i];
99 case 3:
100 return z[i];
101 }
102 }
103};
104
105struct renumbering
106{
107 const DomainPartition<3>& part;
108 const std::vector<ptrdiff_t>& dom;
109
110 renumbering(const DomainPartition<3>& p,
111 const std::vector<ptrdiff_t>& d)
112 : part(p)
113 , dom(d)
114 {}
115
116 ptrdiff_t operator()(ptrdiff_t i, ptrdiff_t j, ptrdiff_t k) const
117 {
118 boost::array<ptrdiff_t, 3> p = { { i, j, k } };
119 std::pair<int, ptrdiff_t> v = part.index(p);
120 return dom[v.first] + v.second;
121 }
122};
123
124int main2(const Alina::SampleMainContext& ctx, int argc, char* argv[])
125{
126 auto& prof = Alina::Profiler::globalProfiler();
127 ITraceMng* tm = ctx.traceMng();
128 Alina::mpi_communicator world(MPI_COMM_WORLD);
129
130 tm->info() << "World size: " << world.size;
131
132 // Read configuration from command line
133 ptrdiff_t n = 128;
134 bool constant_deflation = false;
135
136 auto coarsening = Alina::eCoarserningType::smoothed_aggregation;
137 auto relaxation = Alina::eRelaxationType::spai0;
138 auto iterative_solver = Alina::eSolverType::bicgstabl;
139 auto direct_solver = Alina::eDistributedDirectSolverType::skyline_lu;
140
141 bool just_relax = false;
142 bool symm_dirichlet = true;
143 std::string parameter_file;
144
145 namespace po = Arcane::ProgramOptions;
146 po::options_description desc("Options");
147
148 desc.add_options()("help,h", "show help")(
149 "symbc",
150 po::value<bool>(&symm_dirichlet)->default_value(symm_dirichlet),
151 "Use symmetric Dirichlet conditions in laplace2d")(
152 "size,n",
153 po::value<ptrdiff_t>(&n)->default_value(n),
154 "domain size")(
155 "coarsening,c",
156 po::value<Alina::eCoarserningType>(&coarsening)->default_value(coarsening),
157 "ruge_stuben, aggregation, smoothed_aggregation, smoothed_aggr_emin")(
158 "relaxation,r",
159 po::value<Alina::eRelaxationType>(&relaxation)->default_value(relaxation),
160 "gauss_seidel, ilu0, iluk, ilut, damped_jacobi, spai0, spai1, chebyshev")(
161 "iter_solver,i",
162 po::value<Alina::eSolverType>(&iterative_solver)->default_value(iterative_solver),
163 "cg, bicgstab, bicgstabl, gmres")(
164 "dir_solver,d",
165 po::value<Alina::eDistributedDirectSolverType>(&direct_solver)->default_value(direct_solver),
166 "skyline_lu"
167#ifdef ARCCORE_ALINA_HAVE_EIGEN
168 ", eigen_splu"
169#endif
170 )(
171 "cd",
172 po::bool_switch(&constant_deflation),
173 "Use constant deflation (linear deflation is used by default)")(
174 "params,P",
175 po::value<std::string>(&parameter_file),
176 "parameter file in json format")(
177 "prm,p",
178 po::value<std::vector<std::string>>()->multitoken(),
179 "Parameters specified as name=value pairs. "
180 "May be provided multiple times. Examples:\n"
181 " -p solver.tol=1e-3\n"
182 " -p precond.coarse_enough=300")(
183 "just-relax,0",
184 po::bool_switch(&just_relax),
185 "Do not create AMG hierarchy, use relaxation as preconditioner");
186
188 po::store(po::parse_command_line(argc, argv, desc), vm);
189 po::notify(vm);
190
191 if (vm.count("help")) {
192 std::cout << desc << std::endl;
193 return 0;
194 }
195
197 if (vm.count("params"))
198 prm.read_json(parameter_file);
199
200 if (vm.count("prm")) {
201 for (const std::string& v : vm["prm"].as<std::vector<std::string>>()) {
202 prm.putKeyValue(v);
203 }
204 }
205
206 prm.put("isolver.type", iterative_solver);
207 prm.put("dsolver.type", direct_solver);
208
209 boost::array<ptrdiff_t, 3> lo = { { 0, 0, 0 } };
210 boost::array<ptrdiff_t, 3> hi = { { n - 1, n - 1, n - 1 } };
211
212 prof.tic("partition");
213 DomainPartition<3> part(lo, hi, world.size);
214 ptrdiff_t chunk = part.size(world.rank);
215
216 std::vector<ptrdiff_t> domain(world.size + 1);
217 ConstArrayView<ptrdiff_t> send_buf(1, &chunk);
218 ArrayView<ptrdiff_t> receive_buf(world.size, &domain[1]);
219 mpAllGather(world.m_message_passing_mng.get(), send_buf, receive_buf);
220 std::partial_sum(domain.begin(), domain.end(), domain.begin());
221
222 lo = part.domain(world.rank).min_corner();
223 hi = part.domain(world.rank).max_corner();
224
225 renumbering renum(part, domain);
226
227 deflation_vectors def(chunk, constant_deflation ? 1 : 4);
228 for (ptrdiff_t k = lo[2]; k <= hi[2]; ++k) {
229 for (ptrdiff_t j = lo[1]; j <= hi[1]; ++j) {
230 for (ptrdiff_t i = lo[0]; i <= hi[0]; ++i) {
231 boost::array<ptrdiff_t, 3> p = { { i, j, k } };
232 std::pair<int, ptrdiff_t> v = part.index(p);
233
234 def.x[v.second] = (i - (lo[0] + hi[0]) / 2);
235 def.y[v.second] = (j - (lo[1] + hi[1]) / 2);
236 def.z[v.second] = (k - (lo[2] + hi[2]) / 2);
237 }
238 }
239 }
240 prof.toc("partition");
241
242 prof.tic("assemble");
243 std::vector<ptrdiff_t> ptr;
244 std::vector<ptrdiff_t> col;
245 std::vector<double> val;
246 std::vector<double> rhs;
247
248 ptr.reserve(chunk + 1);
249 col.reserve(chunk * 7);
250 val.reserve(chunk * 7);
251 rhs.reserve(chunk);
252
253 ptr.push_back(0);
254
255 const double h2i = (n - 1) * (n - 1);
256
257 for (ptrdiff_t k = lo[2]; k <= hi[2]; ++k) {
258 for (ptrdiff_t j = lo[1]; j <= hi[1]; ++j) {
259 for (ptrdiff_t i = lo[0]; i <= hi[0]; ++i) {
260
261 if (!symm_dirichlet && (i == 0 || j == 0 || k == 0 || i + 1 == n || j + 1 == n || k + 1 == n)) {
262 col.push_back(renum(i, j, k));
263 val.push_back(1);
264 rhs.push_back(0);
265 }
266 else {
267 if (k > 0) {
268 col.push_back(renum(i, j, k - 1));
269 val.push_back(-h2i);
270 }
271
272 if (j > 0) {
273 col.push_back(renum(i, j - 1, k));
274 val.push_back(-h2i);
275 }
276
277 if (i > 0) {
278 col.push_back(renum(i - 1, j, k));
279 val.push_back(-h2i);
280 }
281
282 col.push_back(renum(i, j, k));
283 val.push_back(6 * h2i);
284
285 if (i + 1 < n) {
286 col.push_back(renum(i + 1, j, k));
287 val.push_back(-h2i);
288 }
289
290 if (j + 1 < n) {
291 col.push_back(renum(i, j + 1, k));
292 val.push_back(-h2i);
293 }
294
295 if (k + 1 < n) {
296 col.push_back(renum(i, j, k + 1));
297 val.push_back(-h2i);
298 }
299
300 rhs.push_back(1);
301 }
302 ptr.push_back(col.size());
303 }
304 }
305 }
306 prof.toc("assemble");
307
308 Backend::params bprm;
309
310#if defined(SOLVER_BACKEND_VEXCL)
311 vex::Context ctx(vex::Filter::Env);
312 std::cout << ctx << std::endl;
313 bprm.q = ctx;
314#elif defined(SOLVER_BACKEND_CUDA)
315 cusparseCreate(&bprm.cusparse_handle);
316#endif
317
318 auto f = Backend::copy_vector(rhs, bprm);
319 auto x = Backend::create_vector(chunk, bprm);
320
321 Alina::backend::clear(*x);
322
323 size_t iters;
324 double resid;
325
326 std::function<double(ptrdiff_t, unsigned)> def_vec = std::cref(def);
327 prm.put("num_def_vec", def.dim());
328 prm.put("def_vec", &def_vec);
329
330 if (just_relax) {
331 prm.put("local.type", relaxation);
332
333 prof.tic("setup");
337
338 SDD solve(world, std::tie(chunk, ptr, col, val), prm, bprm);
339 prof.toc("setup");
340
341 prof.tic("solve");
342 std::tie(iters, resid) = solve(*f, *x);
343 prof.toc("solve");
344 }
345 else {
346 prm.put("local.coarsening.type", coarsening);
347 prm.put("local.relax.type", relaxation);
348
349 prof.tic("setup");
353
354 SDD solve(world, std::tie(chunk, ptr, col, val), prm, bprm);
355 prof.toc("setup");
356
357 prof.tic("solve");
358 std::tie(iters, resid) = solve(*f, *x);
359 prof.toc("solve");
360 }
361
362 tm->info() << "Iterations: " << iters << "\n"
363 << "Error: " << resid << "\n\n"
364 << prof << "\n";
365 return 0;
366}
367
368int main(int argc, char* argv[])
369{
370 return Arcane::Alina::SampleMainContext::execMain(main2, argc, argv);
371}
Runtime wrapper for distributed direct solvers.
Distributed solver based on subdomain deflation.
Class to store parameters as a hierarchical key/value tree.
Definition AlinaUtils.h:112
Modifiable view of an array of type T.
Constant view of an array of type T.
virtual TraceMessage info()=0
Stream for an information message.
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:309
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Pointwise constant deflation vectors.
Convenience wrapper around MPI_Comm.