Arcane  4.2.1.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.
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.