Arcane  v4.1.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
DistributedRuntimeSDD.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 <iomanip>
21#include <fstream>
22#include <vector>
23#include <numeric>
24#include <cmath>
25#include <stdexcept>
26
27#if defined(SOLVER_BACKEND_CUDA)
28// This seems not defined with CUDA
29namespace boost::math
30{
31class rounding_error
32{};
33} // namespace boost::math
34#endif
35
36#include "DomainPartition.h"
37
38#include "MBA.h"
39
40#include <boost/scope_exit.hpp>
41#include <memory>
42#include <boost/program_options.hpp>
43
44#include <boost/multi_array.hpp>
45#if defined(SOLVER_BACKEND_CUDA)
46#include "arccore/alina/CudaBackend.h"
47#include "arccore/alina/relaxation_cusparse_ilu0.h"
49#else
50#ifndef SOLVER_BACKEND_BUILTIN
51#define SOLVER_BACKEND_BUILTIN
52#endif
53#include "arccore/alina/BuiltinBackend.h"
55#endif
56
57#include "arccore/alina/PreconditionedSolver.h"
58#include "arccore/alina/AMG.h"
59#include "arccore/alina/CoarseningRuntime.h"
60#include "arccore/alina/RelaxationRuntime.h"
61#include "arccore/alina/PreconditionerRuntime.h"
62#include "arccore/alina/DistributedDirectSolverRuntime.h"
63#include "arccore/alina/DistributedSolverRuntime.h"
64#include "arccore/alina/DistributedSubDomainDeflation.h"
65#include "arccore/alina/Adapters.h"
66#include "arccore/alina/Profiler.h"
67#include "AlinaSamplesCommon.h"
68
69using namespace Arcane;
70
71struct partitioned_deflation
72{
73 unsigned nparts;
74 std::vector<unsigned> domain;
75
76 partitioned_deflation(boost::array<ptrdiff_t, 2> LO,
77 boost::array<ptrdiff_t, 2> HI,
78 unsigned nparts)
79 : nparts(nparts)
80 {
81 DomainPartition<2> part(LO, HI, nparts);
82
83 ptrdiff_t nx = HI[0] - LO[0] + 1;
84 ptrdiff_t ny = HI[1] - LO[1] + 1;
85
86 domain.resize(nx * ny);
87 for (unsigned p = 0; p < nparts; ++p) {
88 boost::array<ptrdiff_t, 2> lo = part.domain(p).min_corner();
89 boost::array<ptrdiff_t, 2> hi = part.domain(p).max_corner();
90
91 for (int j = lo[1]; j <= hi[1]; ++j) {
92 for (int i = lo[0]; i <= hi[0]; ++i) {
93 domain[(j - LO[1]) * nx + (i - LO[0])] = p;
94 }
95 }
96 }
97 }
98
99 size_t dim() const { return nparts; }
100
101 double operator()(ptrdiff_t i, unsigned j) const
102 {
103 return domain[i] == j;
104 }
105};
106
107struct linear_deflation
108{
109 std::vector<double> x;
110 std::vector<double> y;
111
112 linear_deflation(ptrdiff_t chunk,
113 boost::array<ptrdiff_t, 2> lo,
114 boost::array<ptrdiff_t, 2> hi)
115 {
116 double hx = 1.0 / (hi[0] - lo[0]);
117 double hy = 1.0 / (hi[1] - lo[1]);
118
119 ptrdiff_t nx = hi[0] - lo[0] + 1;
120 ptrdiff_t ny = hi[1] - lo[1] + 1;
121
122 x.reserve(chunk);
123 y.reserve(chunk);
124
125 for (ptrdiff_t j = 0; j < ny; ++j) {
126 for (ptrdiff_t i = 0; i < nx; ++i) {
127 x.push_back(i * hx - 0.5);
128 y.push_back(j * hy - 0.5);
129 }
130 }
131 }
132
133 size_t dim() const { return 3; }
134
135 double operator()(ptrdiff_t i, unsigned j) const
136 {
137 switch (j) {
138 default:
139 case 0:
140 return 1;
141 case 1:
142 return x[i];
143 case 2:
144 return y[i];
145 }
146 }
147};
148
149struct bilinear_deflation
150{
151 size_t nv, chunk;
152 std::vector<double> v;
153
154 bilinear_deflation(ptrdiff_t n,
155 ptrdiff_t chunk,
156 boost::array<ptrdiff_t, 2> lo,
157 boost::array<ptrdiff_t, 2> hi)
158 : nv(0)
159 , chunk(chunk)
160 {
161 // See which neighbors we have.
162 int neib[2][2] = {
163 { lo[0] > 0 || lo[1] > 0, hi[0] + 1 < n || lo[1] > 0 },
164 { lo[0] > 0 || hi[1] + 1 < n, hi[0] + 1 < n || hi[1] + 1 < n }
165 };
166
167 for (int j = 0; j < 2; ++j)
168 for (int i = 0; i < 2; ++i)
169 if (neib[j][i])
170 ++nv;
171
172 if (nv == 0) {
173 // Single MPI process?
174 nv = 1;
175 v.resize(chunk, 1);
176 return;
177 }
178
179 v.resize(chunk * nv, 0);
180
181 double* dv = v.data();
182
183 ptrdiff_t nx = hi[0] - lo[0] + 1;
184 ptrdiff_t ny = hi[1] - lo[1] + 1;
185
186 double hx = 1.0 / (nx - 1);
187 double hy = 1.0 / (ny - 1);
188
189 for (int j = 0; j < 2; ++j) {
190 for (int i = 0; i < 2; ++i) {
191 if (!neib[j][i])
192 continue;
193
194 boost::multi_array_ref<double, 2> V(dv, boost::extents[ny][nx]);
195
196 for (ptrdiff_t jj = 0; jj < ny; ++jj) {
197 double y = jj * hy;
198 double b = std::abs((1 - j) - y);
199 for (ptrdiff_t ii = 0; ii < nx; ++ii) {
200 double x = ii * hx;
201
202 double a = std::abs((1 - i) - x);
203 V[jj][ii] = a * b;
204 }
205 }
206
207 dv += chunk;
208 }
209 }
210 }
211
212 size_t dim() const { return nv; }
213
214 double operator()(ptrdiff_t i, unsigned j) const
215 {
216 return v[j * chunk + i];
217 }
218};
219
220#ifndef SOLVER_BACKEND_CUDA
221struct mba_deflation
222{
223 size_t chunk, nv;
224 std::vector<double> v;
225
226 mba_deflation(ptrdiff_t n,
227 ptrdiff_t chunk,
228 boost::array<ptrdiff_t, 2> lo,
229 boost::array<ptrdiff_t, 2> hi)
230 : chunk(chunk)
231 , nv(1)
232 {
233 // See which neighbors we have.
234 int neib[2][2] = {
235 { lo[0] > 0 || lo[1] > 0, hi[0] + 1 < n || lo[1] > 0 },
236 { lo[0] > 0 || hi[1] + 1 < n, hi[0] + 1 < n || hi[1] + 1 < n }
237 };
238
239 for (int j = 0; j < 2; ++j)
240 for (int i = 0; i < 2; ++i)
241 if (neib[j][i])
242 ++nv;
243
244 v.resize(chunk * nv, 0);
245
246 double* dv = v.data();
247 std::fill(dv, dv + chunk, 1.0);
248 dv += chunk;
249
250 ptrdiff_t nx = hi[0] - lo[0] + 1;
251 ptrdiff_t ny = hi[1] - lo[1] + 1;
252
253 double hx = 1.0 / (nx - 1);
254 double hy = 1.0 / (ny - 1);
255
256 std::array<double, 2> cmin = { -0.01, -0.01 };
257 std::array<double, 2> cmax = { 1.01, 1.01 };
258 std::array<size_t, 2> grid = { 3, 3 };
259
260 std::array<std::array<double, 2>, 4> coo;
261 std::array<double, 4> val;
262
263 for (int j = 0, idx = 0; j < 2; ++j) {
264 for (int i = 0; i < 2; ++i, ++idx) {
265 coo[idx][0] = i;
266 coo[idx][1] = j;
267 }
268 }
269
270 for (int j = 0, idx = 0; j < 2; ++j) {
271 for (int i = 0; i < 2; ++i, ++idx) {
272 if (!neib[j][i])
273 continue;
274
275 std::fill(val.begin(), val.end(), 0.0);
276 val[idx] = 1.0;
277
278 mba::MBA<2> interp(cmin, cmax, grid, coo, val, 8, 1e-8, 0.5, zero);
279
280 boost::multi_array_ref<double, 2> V(dv, boost::extents[ny][nx]);
281
282 for (int jj = 0; jj < ny; ++jj)
283 for (int ii = 0; ii < nx; ++ii) {
284 std::array<double, 2> p = { ii * hx, jj * hy };
285 V[jj][ii] = interp(p);
286 }
287
288 dv += chunk;
289 }
290 }
291 }
292
293 size_t dim() const { return nv; }
294
295 double operator()(ptrdiff_t i, unsigned j) const
296 {
297 return v[j * chunk + i];
298 }
299
300 static double zero(const std::array<double, 2>&)
301 {
302 return 0;
303 }
304};
305#endif
306
307struct harmonic_deflation
308{
309 size_t nv, chunk;
310 std::vector<double> v;
311
312 harmonic_deflation(ptrdiff_t n,
313 ptrdiff_t chunk,
314 boost::array<ptrdiff_t, 2> lo,
315 boost::array<ptrdiff_t, 2> hi)
316 : nv(0)
317 , chunk(chunk)
318 {
319 // See which neighbors we have.
320 int neib[2][2] = {
321 { lo[0] > 0 || lo[1] > 0, hi[0] + 1 < n || lo[1] > 0 },
322 { lo[0] > 0 || hi[1] + 1 < n, hi[0] + 1 < n || hi[1] + 1 < n }
323 };
324
325 for (int j = 0; j < 2; ++j)
326 for (int i = 0; i < 2; ++i)
327 if (neib[j][i])
328 ++nv;
329
330 if (nv == 0) {
331 // Single MPI process?
332 nv = 1;
333 v.resize(chunk, 1);
334 return;
335 }
336
337 v.resize(chunk * nv, 0);
338 double* dv = v.data();
339
340 ptrdiff_t nx = hi[0] - lo[0] + 1;
341 ptrdiff_t ny = hi[1] - lo[1] + 1;
342
343 std::vector<ptrdiff_t> ptr;
344 std::vector<ptrdiff_t> col;
345 std::vector<double> val;
346 std::vector<double> rhs(chunk, 0.0);
347
348 ptr.reserve(chunk + 1);
349 col.reserve(chunk * 5);
350 val.reserve(chunk * 5);
351
352 ptr.push_back(0);
353
354 for (int j = 0, k = 0; j < ny; ++j) {
355 for (int i = 0; i < nx; ++i, ++k) {
356 if (
357 (i == 0 && j == 0) ||
358 (i == 0 && j == ny - 1) ||
359 (i == nx - 1 && j == 0) ||
360 (i == nx - 1 && j == ny - 1)) {
361 col.push_back(k);
362 val.push_back(1);
363 }
364 else {
365 col.push_back(k);
366 val.push_back(1.0);
367
368 if (j == 0) {
369 col.push_back(k + nx);
370 val.push_back(-0.5);
371 }
372 else if (j == ny - 1) {
373 col.push_back(k - nx);
374 val.push_back(-0.5);
375 }
376 else {
377 col.push_back(k - nx);
378 val.push_back(-0.25);
379
380 col.push_back(k + nx);
381 val.push_back(-0.25);
382 }
383
384 if (i == 0) {
385 col.push_back(k + 1);
386 val.push_back(-0.5);
387 }
388 else if (i == nx - 1) {
389 col.push_back(k - 1);
390 val.push_back(-0.5);
391 }
392 else {
393 col.push_back(k - 1);
394 val.push_back(-0.25);
395
396 col.push_back(k + 1);
397 val.push_back(-0.25);
398 }
399 }
400
401 ptr.push_back(col.size());
402 }
403 }
404
410 solve(Alina::adapter::zero_copy(chunk, ptr.data(), col.data(), val.data()));
411
412 for (int j = 0; j < 2; ++j) {
413 for (int i = 0; i < 2; ++i) {
414 if (!neib[j][i])
415 continue;
416
417 ptrdiff_t idx = i * (nx - 1) + j * (ny - 1) * nx;
418 rhs[idx] = 1.0;
419
420 SmallSpan<double> x(dv, chunk);
421 solve(rhs, x);
422
423 rhs[idx] = 0.0;
424
425 dv += chunk;
426 }
427 }
428 }
429
430 size_t dim() const { return nv; }
431
432 double operator()(ptrdiff_t i, unsigned j) const
433 {
434 return v[j * chunk + i];
435 }
436};
437
438struct renumbering
439{
440 const DomainPartition<2>& part;
441 const std::vector<ptrdiff_t>& dom;
442
443 renumbering(const DomainPartition<2>& p,
444 const std::vector<ptrdiff_t>& d)
445 : part(p)
446 , dom(d)
447 {}
448
449 ptrdiff_t operator()(ptrdiff_t i, ptrdiff_t j) const
450 {
451 boost::array<ptrdiff_t, 2> p = { { i, j } };
452 std::pair<int, ptrdiff_t> v = part.index(p);
453 return dom[v.first] + v.second;
454 }
455};
456
457int main2(const Alina::SampleMainContext& ctx, int argc, char* argv[])
458{
459 auto& prof = Alina::Profiler::globalProfiler();
460
461 Alina::mpi_communicator world(MPI_COMM_WORLD);
462
463 if (world.rank == 0)
464 std::cout << "World size: " << world.size << std::endl;
465
466 // Read configuration from command line
467 ptrdiff_t n = 1024;
468 std::string deflation_type = "bilinear";
469
470 auto coarsening = Alina::eCoarserningType::smoothed_aggregation;
471 auto relaxation = Alina::eRelaxationType::spai0;
472 auto iterative_solver = Alina::eSolverType::bicgstabl;
473 auto direct_solver = Alina::eDistributedDirectSolverType::skyline_lu;
474
475 bool just_relax = false;
476 bool symm_dirichlet = true;
477 std::string problem = "laplace2d";
478 std::string parameter_file;
479 std::string out_file;
480
481 namespace po = boost::program_options;
482 po::options_description desc("Options");
483
484 desc.add_options()("help,h", "show help")(
485 "problem",
486 po::value<std::string>(&problem)->default_value(problem),
487 "laplace2d, recirc2d")(
488 "symbc",
489 po::value<bool>(&symm_dirichlet)->default_value(symm_dirichlet),
490 "Use symmetric Dirichlet conditions in laplace2d")(
491 "size,n",
492 po::value<ptrdiff_t>(&n)->default_value(n),
493 "domain size")(
494 "coarsening,c",
495 po::value<Alina::eCoarserningType>(&coarsening)->default_value(coarsening),
496 "ruge_stuben, aggregation, smoothed_aggregation, smoothed_aggr_emin")(
497 "relaxation,r",
498 po::value<Alina::eRelaxationType>(&relaxation)->default_value(relaxation),
499 "gauss_seidel, ilu0, iluk, ilut, damped_jacobi, spai0, spai1, chebyshev")(
500 "iter_solver,i",
501 po::value<Alina::eSolverType>(&iterative_solver)->default_value(iterative_solver),
502 "cg, bicgstab, bicgstabl, gmres")(
503 "dir_solver,d",
504 po::value<Alina::eDistributedDirectSolverType>(&direct_solver)->default_value(direct_solver),
505 "skyline_lu"
506#ifdef ARCCORE_ALINA_HAVE_PASTIX
507 ", pastix"
508#endif
509 )(
510 "deflation,v",
511 po::value<std::string>(&deflation_type)->default_value(deflation_type),
512 "constant, partitioned, linear, bilinear, mba, harmonic")(
513 "subparts",
514 po::value<int>()->default_value(16),
515 "number of partitions for partitioned deflation")(
516 "params,P",
517 po::value<std::string>(&parameter_file),
518 "parameter file in json format")(
519 "prm,p",
520 po::value<std::vector<std::string>>()->multitoken(),
521 "Parameters specified as name=value pairs. "
522 "May be provided multiple times. Examples:\n"
523 " -p solver.tol=1e-3\n"
524 " -p precond.coarse_enough=300")(
525 "just-relax,0",
526 po::bool_switch(&just_relax),
527 "Do not create AMG hierarchy, use relaxation as preconditioner")(
528 "out,o",
529 po::value<std::string>(&out_file),
530 "out file");
531
532 po::variables_map vm;
533 po::store(po::parse_command_line(argc, argv, desc), vm);
534 po::notify(vm);
535
536 if (vm.count("help")) {
537 std::cout << desc << std::endl;
538 return 0;
539 }
540
542 if (vm.count("params"))
543 prm.read_json(parameter_file);
544
545 if (vm.count("prm")) {
546 for (const std::string& v : vm["prm"].as<std::vector<std::string>>()) {
547 prm.putKeyValue(v);
548 }
549 }
550
551 prm.put("isolver.type", iterative_solver);
552 prm.put("dsolver.type", direct_solver);
553
554 const ptrdiff_t n2 = n * n;
555 const double hinv = (n - 1);
556 const double h2i = (n - 1) * (n - 1);
557 const double h = 1 / hinv;
558
559 boost::array<ptrdiff_t, 2> lo = { { 0, 0 } };
560 boost::array<ptrdiff_t, 2> hi = { { n - 1, n - 1 } };
561
562 prof.tic("partition");
563 DomainPartition<2> part(lo, hi, world.size);
564 ptrdiff_t chunk = part.size(world.rank);
565
566 std::vector<ptrdiff_t> domain(world.size + 1);
567 MPI_Allgather(&chunk, 1, Alina::mpi_datatype<ptrdiff_t>(),
568 &domain[1], 1, Alina::mpi_datatype<ptrdiff_t>(), world);
569 std::partial_sum(domain.begin(), domain.end(), domain.begin());
570
571 lo = part.domain(world.rank).min_corner();
572 hi = part.domain(world.rank).max_corner();
573 prof.toc("partition");
574
575 renumbering renum(part, domain);
576
577 prof.tic("deflation");
578 std::function<double(ptrdiff_t, unsigned)> dv;
579 Int32 ndv = 1;
580
581 if (deflation_type == "constant") {
583 }
584 else if (deflation_type == "partitioned") {
585 ndv = vm["subparts"].as<int>();
586 dv = partitioned_deflation(lo, hi, ndv);
587 }
588 else if (deflation_type == "linear") {
589 ndv = 3;
590 dv = linear_deflation(chunk, lo, hi);
591 }
592 else if (deflation_type == "bilinear") {
593 bilinear_deflation bld(n, chunk, lo, hi);
594 ndv = bld.dim();
595 dv = bld;
596#ifndef SOLVER_BACKEND_CUDA
597 }
598 else if (deflation_type == "mba") {
599 mba_deflation mba(n, chunk, lo, hi);
600 ndv = mba.dim();
601 dv = mba;
602#endif
603 }
604 else if (deflation_type == "harmonic") {
605 harmonic_deflation hd(n, chunk, lo, hi);
606 ndv = hd.dim();
607 dv = hd;
608 }
609 else {
610 throw std::runtime_error("Unsupported deflation type");
611 }
612
613 prm.put("num_def_vec", ndv);
614 prm.put("def_vec", &dv);
615 prof.toc("deflation");
616
617 prof.tic("assemble");
618 std::vector<ptrdiff_t> ptr;
619 std::vector<ptrdiff_t> col;
620 std::vector<double> val;
621 std::vector<double> rhs;
622
623 ptr.reserve(chunk + 1);
624 col.reserve(chunk * 5);
625 val.reserve(chunk * 5);
626 rhs.reserve(chunk);
627
628 ptr.push_back(0);
629
630 if (problem == "recirc2d") {
631 const double eps = 1e-5;
632
633 for (ptrdiff_t j = lo[1]; j <= hi[1]; ++j) {
634 double y = h * j;
635 for (ptrdiff_t i = lo[0]; i <= hi[0]; ++i) {
636 double x = h * i;
637
638 if (i == 0 || j == 0 || i + 1 == n || j + 1 == n) {
639 col.push_back(renum(i, j));
640 val.push_back(1);
641 rhs.push_back(
642 sin(M_PI * x) + sin(M_PI * y) +
643 sin(13 * M_PI * x) + sin(13 * M_PI * y));
644 }
645 else {
646 double a = -sin(M_PI * x) * cos(M_PI * y) * hinv;
647 double b = sin(M_PI * y) * cos(M_PI * x) * hinv;
648
649 if (j > 0) {
650 col.push_back(renum(i, j - 1));
651 val.push_back(-eps * h2i - std::max(b, 0.0));
652 }
653
654 if (i > 0) {
655 col.push_back(renum(i - 1, j));
656 val.push_back(-eps * h2i - std::max(a, 0.0));
657 }
658
659 col.push_back(renum(i, j));
660 val.push_back(4 * eps * h2i + fabs(a) + fabs(b));
661
662 if (i + 1 < n) {
663 col.push_back(renum(i + 1, j));
664 val.push_back(-eps * h2i + std::min(a, 0.0));
665 }
666
667 if (j + 1 < n) {
668 col.push_back(renum(i, j + 1));
669 val.push_back(-eps * h2i + std::min(b, 0.0));
670 }
671
672 rhs.push_back(1.0);
673 }
674 ptr.push_back(col.size());
675 }
676 }
677 }
678 else {
679 for (ptrdiff_t j = lo[1]; j <= hi[1]; ++j) {
680 for (ptrdiff_t i = lo[0]; i <= hi[0]; ++i) {
681 if (!symm_dirichlet && (i == 0 || j == 0 || i + 1 == n || j + 1 == n)) {
682 col.push_back(renum(i, j));
683 val.push_back(1);
684 rhs.push_back(0);
685 }
686 else {
687 if (j > 0) {
688 col.push_back(renum(i, j - 1));
689 val.push_back(-h2i);
690 }
691
692 if (i > 0) {
693 col.push_back(renum(i - 1, j));
694 val.push_back(-h2i);
695 }
696
697 col.push_back(renum(i, j));
698 val.push_back(4 * h2i);
699
700 if (i + 1 < n) {
701 col.push_back(renum(i + 1, j));
702 val.push_back(-h2i);
703 }
704
705 if (j + 1 < n) {
706 col.push_back(renum(i, j + 1));
707 val.push_back(-h2i);
708 }
709
710 rhs.push_back(1);
711 }
712 ptr.push_back(col.size());
713 }
714 }
715 }
716 prof.toc("assemble");
717
718 Backend::params bprm;
719
720#if defined(SOLVER_BACKEND_CUDA)
721 cusparseCreate(&bprm.cusparse_handle);
722#endif
723
724 auto f = Backend::copy_vector(rhs, bprm);
725 auto x = Backend::create_vector(chunk, bprm);
726
727 Alina::backend::clear(*x);
728
729 if (just_relax) {
730 prm.put("local.class", "relaxation");
731 prm.put("local.type", relaxation);
732 }
733 else {
734 prm.put("local.coarsening.type", coarsening);
735 prm.put("local.relax.type", relaxation);
736 }
737
738 prof.tic("setup");
742
743 SDD solve(world, std::tie(chunk, ptr, col, val), prm, bprm);
744 prof.toc("setup");
745
746 prof.tic("solve");
747 Alina::SolverResult r = solve(*f, *x);
748 prof.toc("solve");
749
750 if (world.rank == 0) {
751 std::cout << "Iterations: " << r.nbIteration() << std::endl
752 << "Error: " << r.residual() << std::endl
753 << prof << std::endl;
754 }
755 return 0;
756}
757
758int main(int argc, char* argv[])
759{
760 return Arcane::Alina::SampleMainContext::execMain(main2, argc, argv);
761}
Runtime wrapper for distributed direct solvers.
Distributed solver based on subdomain deflation.
Generalized Minimal Residual (GMRES) method.
Convenience class that bundles together a preconditioner and an iterative solver.
Result of a solving.
Definition AlinaUtils.h:52
Vue d'un tableau d'éléments de type T.
Definition Span.h:801
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
Alina::detail::empty_params params
Gauss-Seidel relaxation.
Definition Relaxation.h:510
Smoothed aggregation coarsening.
Pointwise constant deflation vectors.
Convenience wrapper around MPI_Comm.