27#if defined(SOLVER_BACKEND_CUDA)
36#include "DomainPartition.h"
42#include <boost/multi_array.hpp>
43#if defined(SOLVER_BACKEND_CUDA)
44#include "arccore/alina/CudaBackend.h"
45#include "arccore/alina/relaxation_cusparse_ilu0.h"
48#ifndef SOLVER_BACKEND_BUILTIN
49#define SOLVER_BACKEND_BUILTIN
51#include "arccore/alina/BuiltinBackend.h"
55#include "arccore/alina/PreconditionedSolver.h"
56#include "arccore/alina/AMG.h"
57#include "arccore/alina/CoarseningRuntime.h"
58#include "arccore/alina/RelaxationRuntime.h"
59#include "arccore/alina/PreconditionerRuntime.h"
60#include "arccore/alina/DistributedDirectSolverRuntime.h"
61#include "arccore/alina/DistributedSolverRuntime.h"
62#include "arccore/alina/DistributedSubDomainDeflation.h"
63#include "arccore/alina/Adapters.h"
64#include "arccore/alina/Profiler.h"
66#include "arccore/common/internal/ProgramOptions.h"
68#include "AlinaSamplesCommon.h"
72struct partitioned_deflation
75 std::vector<unsigned> domain;
77 partitioned_deflation(boost::array<ptrdiff_t, 2> LO,
78 boost::array<ptrdiff_t, 2> HI,
82 DomainPartition<2> part(LO, HI, nparts);
84 ptrdiff_t nx = HI[0] - LO[0] + 1;
85 ptrdiff_t ny = HI[1] - LO[1] + 1;
87 domain.resize(nx * ny);
88 for (
unsigned p = 0; p < nparts; ++p) {
89 boost::array<ptrdiff_t, 2> lo = part.domain(p).min_corner();
90 boost::array<ptrdiff_t, 2> hi = part.domain(p).max_corner();
92 for (
int j = lo[1]; j <= hi[1]; ++j) {
93 for (
int i = lo[0]; i <= hi[0]; ++i) {
94 domain[(j - LO[1]) * nx + (i - LO[0])] = p;
100 size_t dim()
const {
return nparts; }
102 double operator()(ptrdiff_t i,
unsigned j)
const
104 return domain[i] == j;
108struct linear_deflation
110 std::vector<double> x;
111 std::vector<double> y;
113 linear_deflation(ptrdiff_t chunk,
114 boost::array<ptrdiff_t, 2> lo,
115 boost::array<ptrdiff_t, 2> hi)
117 double hx = 1.0 / (hi[0] - lo[0]);
118 double hy = 1.0 / (hi[1] - lo[1]);
120 ptrdiff_t nx = hi[0] - lo[0] + 1;
121 ptrdiff_t ny = hi[1] - lo[1] + 1;
126 for (ptrdiff_t j = 0; j < ny; ++j) {
127 for (ptrdiff_t i = 0; i < nx; ++i) {
128 x.push_back(i * hx - 0.5);
129 y.push_back(j * hy - 0.5);
134 size_t dim()
const {
return 3; }
136 double operator()(ptrdiff_t i,
unsigned j)
const
150struct bilinear_deflation
153 std::vector<double> v;
155 bilinear_deflation(ptrdiff_t n,
157 boost::array<ptrdiff_t, 2> lo,
158 boost::array<ptrdiff_t, 2> hi)
164 { lo[0] > 0 || lo[1] > 0, hi[0] + 1 < n || lo[1] > 0 },
165 { lo[0] > 0 || hi[1] + 1 < n, hi[0] + 1 < n || hi[1] + 1 < n }
168 for (
int j = 0; j < 2; ++j)
169 for (
int i = 0; i < 2; ++i)
180 v.resize(chunk * nv, 0);
182 double* dv = v.data();
184 ptrdiff_t nx = hi[0] - lo[0] + 1;
185 ptrdiff_t ny = hi[1] - lo[1] + 1;
187 double hx = 1.0 / (nx - 1);
188 double hy = 1.0 / (ny - 1);
190 for (
int j = 0; j < 2; ++j) {
191 for (
int i = 0; i < 2; ++i) {
195 boost::multi_array_ref<double, 2> V(dv, boost::extents[ny][nx]);
197 for (ptrdiff_t jj = 0; jj < ny; ++jj) {
199 double b = std::abs((1 - j) - y);
200 for (ptrdiff_t ii = 0; ii < nx; ++ii) {
203 double a = std::abs((1 - i) - x);
213 size_t dim()
const {
return nv; }
215 double operator()(ptrdiff_t i,
unsigned j)
const
217 return v[j * chunk + i];
221#ifndef SOLVER_BACKEND_CUDA
225 std::vector<double> v;
227 mba_deflation(ptrdiff_t n,
229 boost::array<ptrdiff_t, 2> lo,
230 boost::array<ptrdiff_t, 2> hi)
236 { lo[0] > 0 || lo[1] > 0, hi[0] + 1 < n || lo[1] > 0 },
237 { lo[0] > 0 || hi[1] + 1 < n, hi[0] + 1 < n || hi[1] + 1 < n }
240 for (
int j = 0; j < 2; ++j)
241 for (
int i = 0; i < 2; ++i)
245 v.resize(chunk * nv, 0);
247 double* dv = v.data();
248 std::fill(dv, dv + chunk, 1.0);
251 ptrdiff_t nx = hi[0] - lo[0] + 1;
252 ptrdiff_t ny = hi[1] - lo[1] + 1;
254 double hx = 1.0 / (nx - 1);
255 double hy = 1.0 / (ny - 1);
257 std::array<double, 2> cmin = { -0.01, -0.01 };
258 std::array<double, 2> cmax = { 1.01, 1.01 };
259 std::array<size_t, 2> grid = { 3, 3 };
261 std::array<std::array<double, 2>, 4> coo;
262 std::array<double, 4> val;
264 for (
int j = 0, idx = 0; j < 2; ++j) {
265 for (
int i = 0; i < 2; ++i, ++idx) {
271 for (
int j = 0, idx = 0; j < 2; ++j) {
272 for (
int i = 0; i < 2; ++i, ++idx) {
276 std::fill(val.begin(), val.end(), 0.0);
279 mba::MBA<2> interp(cmin, cmax, grid, coo, val, 8, 1e-8, 0.5, zero);
281 boost::multi_array_ref<double, 2> V(dv, boost::extents[ny][nx]);
283 for (
int jj = 0; jj < ny; ++jj)
284 for (
int ii = 0; ii < nx; ++ii) {
285 std::array<double, 2> p = { ii * hx, jj * hy };
286 V[jj][ii] = interp(p);
294 size_t dim()
const {
return nv; }
296 double operator()(ptrdiff_t i,
unsigned j)
const
298 return v[j * chunk + i];
301 static double zero(
const std::array<double, 2>&)
308struct harmonic_deflation
311 std::vector<double> v;
313 harmonic_deflation(ptrdiff_t n,
315 boost::array<ptrdiff_t, 2> lo,
316 boost::array<ptrdiff_t, 2> hi)
324 { lo[0] > 0 || lo[1] > 0, hi[0] + 1 < n || lo[1] > 0 },
325 { lo[0] > 0 || hi[1] + 1 < n, hi[0] + 1 < n || hi[1] + 1 < n }
328 for (
int j = 0; j < 2; ++j)
329 for (
int i = 0; i < 2; ++i)
340 v.resize(chunk * nv, 0);
341 double* dv = v.data();
343 ptrdiff_t nx = hi[0] - lo[0] + 1;
344 ptrdiff_t ny = hi[1] - lo[1] + 1;
346 std::vector<Int32> ptr;
347 std::vector<Int32> col;
348 std::vector<double> val;
349 std::vector<double> rhs(chunk, 0.0);
351 ptr.reserve(chunk + 1);
352 col.reserve(chunk * 5);
353 val.reserve(chunk * 5);
357 for (
int j = 0, k = 0; j < ny; ++j) {
358 for (
int i = 0; i < nx; ++i, ++k) {
360 (i == 0 && j == 0) ||
361 (i == 0 && j == ny - 1) ||
362 (i == nx - 1 && j == 0) ||
363 (i == nx - 1 && j == ny - 1)) {
372 col.push_back(k + nx);
375 else if (j == ny - 1) {
376 col.push_back(k - nx);
380 col.push_back(k - nx);
381 val.push_back(-0.25);
383 col.push_back(k + nx);
384 val.push_back(-0.25);
388 col.push_back(k + 1);
391 else if (i == nx - 1) {
392 col.push_back(k - 1);
396 col.push_back(k - 1);
397 val.push_back(-0.25);
399 col.push_back(k + 1);
400 val.push_back(-0.25);
404 ptr.push_back(col.size());
413 solve(context, Alina::adapter::zero_copy(chunk, ptr.data(), col.data(), val.data()));
415 for (
int j = 0; j < 2; ++j) {
416 for (
int i = 0; i < 2; ++i) {
420 ptrdiff_t idx = i * (nx - 1) + j * (ny - 1) * nx;
433 size_t dim()
const {
return nv; }
435 double operator()(ptrdiff_t i,
unsigned j)
const
437 return v[j * chunk + i];
443 const DomainPartition<2>& part;
444 const std::vector<ptrdiff_t>& dom;
447 const std::vector<ptrdiff_t>& d)
452 ptrdiff_t operator()(ptrdiff_t i, ptrdiff_t j)
const
454 boost::array<ptrdiff_t, 2> p = { { i, j } };
455 std::pair<int, ptrdiff_t> v = part.index(p);
456 return dom[v.first] + v.second;
462 auto& prof = Alina::Profiler::globalProfiler();
466 std::cout <<
"World size: " << world.size << std::endl;
471 std::string deflation_type =
"bilinear";
473 auto coarsening = Alina::eCoarserningType::smoothed_aggregation;
474 auto relaxation = Alina::eRelaxationType::spai0;
475 auto iterative_solver = Alina::eSolverType::bicgstabl;
476 auto direct_solver = Alina::eDistributedDirectSolverType::skyline_lu;
478 bool just_relax =
false;
479 bool symm_dirichlet =
true;
480 std::string problem =
"laplace2d";
481 std::string parameter_file;
482 std::string out_file;
484 namespace po = Arcane::ProgramOptions;
487 desc.add_options()(
"help,h",
"show help")(
489 po::value<std::string>(&problem)->default_value(problem),
490 "laplace2d, recirc2d")(
492 po::value<bool>(&symm_dirichlet)->default_value(symm_dirichlet),
493 "Utiliser des conditions de Dirichlet symétriques dans laplace2d")(
495 po::value<ptrdiff_t>(&n)->default_value(n),
496 "taille du domaine")(
498 po::value<Alina::eCoarserningType>(&coarsening)->default_value(coarsening),
499 "ruge_stuben, aggregation, smoothed_aggregation, smoothed_aggr_emin")(
501 po::value<Alina::eRelaxationType>(&relaxation)->default_value(relaxation),
502 "gauss_seidel, ilu0, iluk, ilut, damped_jacobi, spai0, spai1, chebyshev")(
504 po::value<Alina::eSolverType>(&iterative_solver)->default_value(iterative_solver),
505 "cg, bicgstab, bicgstabl, gmres")(
507 po::value<Alina::eDistributedDirectSolverType>(&direct_solver)->default_value(direct_solver),
509#ifdef ARCCORE_ALINA_HAVE_PASTIX
514 po::value<std::string>(&deflation_type)->default_value(deflation_type),
515 "constant, partitioned, linear, bilinear, mba, harmonic")(
517 po::value<int>()->default_value(16),
518 "nombre de partitions pour la déflation partitionnée")(
520 po::value<std::string>(¶meter_file),
521 "fichier de paramètres au format json")(
523 po::value<std::vector<std::string>>()->multitoken(),
524 "Paramètres spécifiés sous forme de paires nom=valeur. "
525 "Peut être fourni plusieurs fois. Exemples :\n"
526 " -p solver.tol=1e-3\n"
527 " -p precond.coarse_enough=300")(
529 po::bool_switch(&just_relax),
530 "Ne pas créer la hiérarchie AMG, utiliser la relaxation comme préconditionneur")(
532 po::value<std::string>(&out_file),
533 "fichier de sortie");
536 po::store(po::parse_command_line(argc, argv, desc), vm);
539 if (vm.count(
"help")) {
540 std::cout << desc << std::endl;
545 if (vm.count(
"params"))
546 prm.read_json(parameter_file);
548 if (vm.count(
"prm")) {
549 for (
const std::string& v : vm[
"prm"].as<std::vector<std::string>>()) {
554 prm.put(
"isolver.type", iterative_solver);
555 prm.put(
"dsolver.type", direct_solver);
557 const ptrdiff_t n2 = n * n;
558 const double hinv = (n - 1);
559 const double h2i = (n - 1) * (n - 1);
560 const double h = 1 / hinv;
562 boost::array<ptrdiff_t, 2> lo = { { 0, 0 } };
563 boost::array<ptrdiff_t, 2> hi = { { n - 1, n - 1 } };
565 prof.tic(
"partition");
566 DomainPartition<2> part(lo, hi, world.size);
567 ptrdiff_t chunk = part.size(world.rank);
569 std::vector<ptrdiff_t> domain(world.size + 1);
572 mpAllGather(world.m_message_passing_mng.get(), send_buf, receive_buf);
573 std::partial_sum(domain.begin(), domain.end(), domain.begin());
575 lo = part.domain(world.rank).min_corner();
576 hi = part.domain(world.rank).max_corner();
577 prof.toc(
"partition");
581 prof.tic(
"deflation");
582 std::function<double(ptrdiff_t,
unsigned)> dv;
585 if (deflation_type ==
"constant") {
588 else if (deflation_type ==
"partitioned") {
589 ndv = vm[
"subparts"].as<
int>();
592 else if (deflation_type ==
"linear") {
596 else if (deflation_type ==
"bilinear") {
600#ifndef SOLVER_BACKEND_CUDA
602 else if (deflation_type ==
"mba") {
608 else if (deflation_type ==
"harmonic") {
614 throw std::runtime_error(
"Unsupported deflation type");
617 prm.put(
"num_def_vec", ndv);
618 prm.put(
"def_vec", &dv);
619 prof.toc(
"deflation");
621 prof.tic(
"assemble");
622 std::vector<ptrdiff_t> ptr;
623 std::vector<ptrdiff_t> col;
624 std::vector<double> val;
625 std::vector<double> rhs;
627 ptr.reserve(chunk + 1);
628 col.reserve(chunk * 5);
629 val.reserve(chunk * 5);
634 if (problem ==
"recirc2d") {
635 const double eps = 1e-5;
637 for (ptrdiff_t j = lo[1]; j <= hi[1]; ++j) {
639 for (ptrdiff_t i = lo[0]; i <= hi[0]; ++i) {
642 if (i == 0 || j == 0 || i + 1 == n || j + 1 == n) {
643 col.push_back(renum(i, j));
646 sin(M_PI * x) + sin(M_PI * y) +
647 sin(13 * M_PI * x) + sin(13 * M_PI * y));
650 double a = -sin(M_PI * x) * cos(M_PI * y) * hinv;
651 double b = sin(M_PI * y) * cos(M_PI * x) * hinv;
654 col.push_back(renum(i, j - 1));
655 val.push_back(-eps * h2i - std::max(b, 0.0));
659 col.push_back(renum(i - 1, j));
660 val.push_back(-eps * h2i - std::max(a, 0.0));
663 col.push_back(renum(i, j));
664 val.push_back(4 * eps * h2i + fabs(a) + fabs(b));
667 col.push_back(renum(i + 1, j));
668 val.push_back(-eps * h2i + std::min(a, 0.0));
672 col.push_back(renum(i, j + 1));
673 val.push_back(-eps * h2i + std::min(b, 0.0));
678 ptr.push_back(col.size());
683 for (ptrdiff_t j = lo[1]; j <= hi[1]; ++j) {
684 for (ptrdiff_t i = lo[0]; i <= hi[0]; ++i) {
685 if (!symm_dirichlet && (i == 0 || j == 0 || i + 1 == n || j + 1 == n)) {
686 col.push_back(renum(i, j));
692 col.push_back(renum(i, j - 1));
697 col.push_back(renum(i - 1, j));
701 col.push_back(renum(i, j));
702 val.push_back(4 * h2i);
705 col.push_back(renum(i + 1, j));
710 col.push_back(renum(i, j + 1));
716 ptr.push_back(col.size());
720 prof.toc(
"assemble");
724#if defined(SOLVER_BACKEND_CUDA)
725 cusparseCreate(&bprm.cusparse_handle);
728 auto f = Backend::copy_vector(rhs, bprm);
729 auto x = Backend::create_vector(chunk, bprm);
731 Alina::backend::clear(*x);
734 prm.put(
"local.class",
"relaxation");
735 prm.put(
"local.type", relaxation);
738 prm.put(
"local.coarsening.type", coarsening);
739 prm.put(
"local.relax.type", relaxation);
747 SDD solve(context, world, std::tie(chunk, ptr, col, val), prm, bprm);
754 if (world.rank == 0) {
755 std::cout <<
"Itérations : " << r.nbIteration() << std::endl
756 <<
"Erreur : " << r.residual() << std::endl
757 << prof << std::endl;
762int main(
int argc,
char* argv[])
764 return Arcane::Alina::SampleMainContext::execMain(main2, argc, argv);
Runtime wrapper for distributed direct solvers.
Solveur distribué basé sur la déflation de sous-domaines.
Generalized Minimal Residual (GMRES) method.
Convenience class that bundles together a preconditioner and an iterative solver.
Classe pour stocker les paramètres sous forme d'arbre hiérarchique clé/valeur.
Vue modifiable d'un tableau d'un type T.
Vue constante d'un tableau de type T.
Décrit un ensemble d'options en ligne de commande.
Stocke les valeurs d'options analysées.
Vue d'un tableau d'éléments de type T.
void mpAllGather(IMessagePassingMng *pm, const ISerializer *send_serializer, ISerializer *receive_serialize)
Message allGather() pour une sérialisation.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Wrapper de commodité autour de MPI_Comm.
Alina::detail::empty_params params
Raffinement par agrégation lissée.
Vecteurs de déflation constants ponctuels.