27#if defined(SOLVER_BACKEND_CUDA)
36#include "DomainPartition.h"
40#include <boost/scope_exit.hpp>
43#include <boost/multi_array.hpp>
44#if defined(SOLVER_BACKEND_CUDA)
45#include "arccore/alina/CudaBackend.h"
46#include "arccore/alina/relaxation_cusparse_ilu0.h"
49#ifndef SOLVER_BACKEND_BUILTIN
50#define SOLVER_BACKEND_BUILTIN
52#include "arccore/alina/BuiltinBackend.h"
56#include "arccore/alina/PreconditionedSolver.h"
57#include "arccore/alina/AMG.h"
58#include "arccore/alina/CoarseningRuntime.h"
59#include "arccore/alina/RelaxationRuntime.h"
60#include "arccore/alina/PreconditionerRuntime.h"
61#include "arccore/alina/DistributedDirectSolverRuntime.h"
62#include "arccore/alina/DistributedSolverRuntime.h"
63#include "arccore/alina/DistributedSubDomainDeflation.h"
64#include "arccore/alina/Adapters.h"
65#include "arccore/alina/Profiler.h"
67#include "arccore/common/internal/ProgramOptions.h"
69#include "AlinaSamplesCommon.h"
73struct partitioned_deflation
76 std::vector<unsigned> domain;
78 partitioned_deflation(boost::array<ptrdiff_t, 2> LO,
79 boost::array<ptrdiff_t, 2> HI,
83 DomainPartition<2> part(LO, HI, nparts);
85 ptrdiff_t nx = HI[0] - LO[0] + 1;
86 ptrdiff_t ny = HI[1] - LO[1] + 1;
88 domain.resize(nx * ny);
89 for (
unsigned p = 0; p < nparts; ++p) {
90 boost::array<ptrdiff_t, 2> lo = part.domain(p).min_corner();
91 boost::array<ptrdiff_t, 2> hi = part.domain(p).max_corner();
93 for (
int j = lo[1]; j <= hi[1]; ++j) {
94 for (
int i = lo[0]; i <= hi[0]; ++i) {
95 domain[(j - LO[1]) * nx + (i - LO[0])] = p;
101 size_t dim()
const {
return nparts; }
103 double operator()(ptrdiff_t i,
unsigned j)
const
105 return domain[i] == j;
109struct linear_deflation
111 std::vector<double> x;
112 std::vector<double> y;
114 linear_deflation(ptrdiff_t chunk,
115 boost::array<ptrdiff_t, 2> lo,
116 boost::array<ptrdiff_t, 2> hi)
118 double hx = 1.0 / (hi[0] - lo[0]);
119 double hy = 1.0 / (hi[1] - lo[1]);
121 ptrdiff_t nx = hi[0] - lo[0] + 1;
122 ptrdiff_t ny = hi[1] - lo[1] + 1;
127 for (ptrdiff_t j = 0; j < ny; ++j) {
128 for (ptrdiff_t i = 0; i < nx; ++i) {
129 x.push_back(i * hx - 0.5);
130 y.push_back(j * hy - 0.5);
135 size_t dim()
const {
return 3; }
137 double operator()(ptrdiff_t i,
unsigned j)
const
151struct bilinear_deflation
154 std::vector<double> v;
156 bilinear_deflation(ptrdiff_t n,
158 boost::array<ptrdiff_t, 2> lo,
159 boost::array<ptrdiff_t, 2> hi)
165 { lo[0] > 0 || lo[1] > 0, hi[0] + 1 < n || lo[1] > 0 },
166 { lo[0] > 0 || hi[1] + 1 < n, hi[0] + 1 < n || hi[1] + 1 < n }
169 for (
int j = 0; j < 2; ++j)
170 for (
int i = 0; i < 2; ++i)
181 v.resize(chunk * nv, 0);
183 double* dv = v.data();
185 ptrdiff_t nx = hi[0] - lo[0] + 1;
186 ptrdiff_t ny = hi[1] - lo[1] + 1;
188 double hx = 1.0 / (nx - 1);
189 double hy = 1.0 / (ny - 1);
191 for (
int j = 0; j < 2; ++j) {
192 for (
int i = 0; i < 2; ++i) {
196 boost::multi_array_ref<double, 2> V(dv, boost::extents[ny][nx]);
198 for (ptrdiff_t jj = 0; jj < ny; ++jj) {
200 double b = std::abs((1 - j) - y);
201 for (ptrdiff_t ii = 0; ii < nx; ++ii) {
204 double a = std::abs((1 - i) - x);
214 size_t dim()
const {
return nv; }
216 double operator()(ptrdiff_t i,
unsigned j)
const
218 return v[j * chunk + i];
222#ifndef SOLVER_BACKEND_CUDA
226 std::vector<double> v;
228 mba_deflation(ptrdiff_t n,
230 boost::array<ptrdiff_t, 2> lo,
231 boost::array<ptrdiff_t, 2> hi)
237 { lo[0] > 0 || lo[1] > 0, hi[0] + 1 < n || lo[1] > 0 },
238 { lo[0] > 0 || hi[1] + 1 < n, hi[0] + 1 < n || hi[1] + 1 < n }
241 for (
int j = 0; j < 2; ++j)
242 for (
int i = 0; i < 2; ++i)
246 v.resize(chunk * nv, 0);
248 double* dv = v.data();
249 std::fill(dv, dv + chunk, 1.0);
252 ptrdiff_t nx = hi[0] - lo[0] + 1;
253 ptrdiff_t ny = hi[1] - lo[1] + 1;
255 double hx = 1.0 / (nx - 1);
256 double hy = 1.0 / (ny - 1);
258 std::array<double, 2> cmin = { -0.01, -0.01 };
259 std::array<double, 2> cmax = { 1.01, 1.01 };
260 std::array<size_t, 2> grid = { 3, 3 };
262 std::array<std::array<double, 2>, 4> coo;
263 std::array<double, 4> val;
265 for (
int j = 0, idx = 0; j < 2; ++j) {
266 for (
int i = 0; i < 2; ++i, ++idx) {
272 for (
int j = 0, idx = 0; j < 2; ++j) {
273 for (
int i = 0; i < 2; ++i, ++idx) {
277 std::fill(val.begin(), val.end(), 0.0);
280 mba::MBA<2> interp(cmin, cmax, grid, coo, val, 8, 1e-8, 0.5, zero);
282 boost::multi_array_ref<double, 2> V(dv, boost::extents[ny][nx]);
284 for (
int jj = 0; jj < ny; ++jj)
285 for (
int ii = 0; ii < nx; ++ii) {
286 std::array<double, 2> p = { ii * hx, jj * hy };
287 V[jj][ii] = interp(p);
295 size_t dim()
const {
return nv; }
297 double operator()(ptrdiff_t i,
unsigned j)
const
299 return v[j * chunk + i];
302 static double zero(
const std::array<double, 2>&)
309struct harmonic_deflation
312 std::vector<double> v;
314 harmonic_deflation(ptrdiff_t n,
316 boost::array<ptrdiff_t, 2> lo,
317 boost::array<ptrdiff_t, 2> hi)
323 { lo[0] > 0 || lo[1] > 0, hi[0] + 1 < n || lo[1] > 0 },
324 { lo[0] > 0 || hi[1] + 1 < n, hi[0] + 1 < n || hi[1] + 1 < n }
327 for (
int j = 0; j < 2; ++j)
328 for (
int i = 0; i < 2; ++i)
339 v.resize(chunk * nv, 0);
340 double* dv = v.data();
342 ptrdiff_t nx = hi[0] - lo[0] + 1;
343 ptrdiff_t ny = hi[1] - lo[1] + 1;
345 std::vector<Int32> ptr;
346 std::vector<Int32> col;
347 std::vector<double> val;
348 std::vector<double> rhs(chunk, 0.0);
350 ptr.reserve(chunk + 1);
351 col.reserve(chunk * 5);
352 val.reserve(chunk * 5);
356 for (
int j = 0, k = 0; j < ny; ++j) {
357 for (
int i = 0; i < nx; ++i, ++k) {
359 (i == 0 && j == 0) ||
360 (i == 0 && j == ny - 1) ||
361 (i == nx - 1 && j == 0) ||
362 (i == nx - 1 && j == ny - 1)) {
371 col.push_back(k + nx);
374 else if (j == ny - 1) {
375 col.push_back(k - nx);
379 col.push_back(k - nx);
380 val.push_back(-0.25);
382 col.push_back(k + nx);
383 val.push_back(-0.25);
387 col.push_back(k + 1);
390 else if (i == nx - 1) {
391 col.push_back(k - 1);
395 col.push_back(k - 1);
396 val.push_back(-0.25);
398 col.push_back(k + 1);
399 val.push_back(-0.25);
403 ptr.push_back(col.size());
412 solve(Alina::adapter::zero_copy(chunk, ptr.data(), col.data(), val.data()));
414 for (
int j = 0; j < 2; ++j) {
415 for (
int i = 0; i < 2; ++i) {
419 ptrdiff_t idx = i * (nx - 1) + j * (ny - 1) * nx;
432 size_t dim()
const {
return nv; }
434 double operator()(ptrdiff_t i,
unsigned j)
const
436 return v[j * chunk + i];
442 const DomainPartition<2>& part;
443 const std::vector<ptrdiff_t>& dom;
446 const std::vector<ptrdiff_t>& d)
451 ptrdiff_t operator()(ptrdiff_t i, ptrdiff_t j)
const
453 boost::array<ptrdiff_t, 2> p = { { i, j } };
454 std::pair<int, ptrdiff_t> v = part.index(p);
455 return dom[v.first] + v.second;
461 auto& prof = Alina::Profiler::globalProfiler();
466 std::cout <<
"World size: " << world.size << std::endl;
470 std::string deflation_type =
"bilinear";
472 auto coarsening = Alina::eCoarserningType::smoothed_aggregation;
473 auto relaxation = Alina::eRelaxationType::spai0;
474 auto iterative_solver = Alina::eSolverType::bicgstabl;
475 auto direct_solver = Alina::eDistributedDirectSolverType::skyline_lu;
477 bool just_relax =
false;
478 bool symm_dirichlet =
true;
479 std::string problem =
"laplace2d";
480 std::string parameter_file;
481 std::string out_file;
483 namespace po = Arcane::ProgramOptions;
486 desc.add_options()(
"help,h",
"show help")(
488 po::value<std::string>(&problem)->default_value(problem),
489 "laplace2d, recirc2d")(
491 po::value<bool>(&symm_dirichlet)->default_value(symm_dirichlet),
492 "Utiliser des conditions de Dirichlet symétriques dans laplace2d")(
494 po::value<ptrdiff_t>(&n)->default_value(n),
495 "taille du domaine")(
497 po::value<Alina::eCoarserningType>(&coarsening)->default_value(coarsening),
498 "ruge_stuben, aggregation, smoothed_aggregation, smoothed_aggr_emin")(
500 po::value<Alina::eRelaxationType>(&relaxation)->default_value(relaxation),
501 "gauss_seidel, ilu0, iluk, ilut, damped_jacobi, spai0, spai1, chebyshev")(
503 po::value<Alina::eSolverType>(&iterative_solver)->default_value(iterative_solver),
504 "cg, bicgstab, bicgstabl, gmres")(
506 po::value<Alina::eDistributedDirectSolverType>(&direct_solver)->default_value(direct_solver),
508#ifdef ARCCORE_ALINA_HAVE_PASTIX
513 po::value<std::string>(&deflation_type)->default_value(deflation_type),
514 "constant, partitioned, linear, bilinear, mba, harmonic")(
516 po::value<int>()->default_value(16),
517 "nombre de partitions pour la déflation partitionnée")(
519 po::value<std::string>(¶meter_file),
520 "fichier de paramètres au format json")(
522 po::value<std::vector<std::string>>()->multitoken(),
523 "Paramètres spécifiés sous forme de paires nom=valeur. "
524 "Peut être fourni plusieurs fois. Exemples :\n"
525 " -p solver.tol=1e-3\n"
526 " -p precond.coarse_enough=300")(
528 po::bool_switch(&just_relax),
529 "Ne pas créer la hiérarchie AMG, utiliser la relaxation comme préconditionneur")(
531 po::value<std::string>(&out_file),
532 "fichier de sortie");
535 po::store(po::parse_command_line(argc, argv, desc), vm);
538 if (vm.count(
"help")) {
539 std::cout << desc << std::endl;
544 if (vm.count(
"params"))
545 prm.read_json(parameter_file);
547 if (vm.count(
"prm")) {
548 for (
const std::string& v : vm[
"prm"].as<std::vector<std::string>>()) {
553 prm.put(
"isolver.type", iterative_solver);
554 prm.put(
"dsolver.type", direct_solver);
556 const ptrdiff_t n2 = n * n;
557 const double hinv = (n - 1);
558 const double h2i = (n - 1) * (n - 1);
559 const double h = 1 / hinv;
561 boost::array<ptrdiff_t, 2> lo = { { 0, 0 } };
562 boost::array<ptrdiff_t, 2> hi = { { n - 1, n - 1 } };
564 prof.tic(
"partition");
565 DomainPartition<2> part(lo, hi, world.size);
566 ptrdiff_t chunk = part.size(world.rank);
568 std::vector<ptrdiff_t> domain(world.size + 1);
571 mpAllGather(world.m_message_passing_mng.get(), send_buf, receive_buf);
572 std::partial_sum(domain.begin(), domain.end(), domain.begin());
574 lo = part.domain(world.rank).min_corner();
575 hi = part.domain(world.rank).max_corner();
576 prof.toc(
"partition");
580 prof.tic(
"deflation");
581 std::function<double(ptrdiff_t,
unsigned)> dv;
584 if (deflation_type ==
"constant") {
587 else if (deflation_type ==
"partitioned") {
588 ndv = vm[
"subparts"].as<
int>();
591 else if (deflation_type ==
"linear") {
595 else if (deflation_type ==
"bilinear") {
599#ifndef SOLVER_BACKEND_CUDA
601 else if (deflation_type ==
"mba") {
607 else if (deflation_type ==
"harmonic") {
613 throw std::runtime_error(
"Unsupported deflation type");
616 prm.put(
"num_def_vec", ndv);
617 prm.put(
"def_vec", &dv);
618 prof.toc(
"deflation");
620 prof.tic(
"assemble");
621 std::vector<ptrdiff_t> ptr;
622 std::vector<ptrdiff_t> col;
623 std::vector<double> val;
624 std::vector<double> rhs;
626 ptr.reserve(chunk + 1);
627 col.reserve(chunk * 5);
628 val.reserve(chunk * 5);
633 if (problem ==
"recirc2d") {
634 const double eps = 1e-5;
636 for (ptrdiff_t j = lo[1]; j <= hi[1]; ++j) {
638 for (ptrdiff_t i = lo[0]; i <= hi[0]; ++i) {
641 if (i == 0 || j == 0 || i + 1 == n || j + 1 == n) {
642 col.push_back(renum(i, j));
645 sin(M_PI * x) + sin(M_PI * y) +
646 sin(13 * M_PI * x) + sin(13 * M_PI * y));
649 double a = -sin(M_PI * x) * cos(M_PI * y) * hinv;
650 double b = sin(M_PI * y) * cos(M_PI * x) * hinv;
653 col.push_back(renum(i, j - 1));
654 val.push_back(-eps * h2i - std::max(b, 0.0));
658 col.push_back(renum(i - 1, j));
659 val.push_back(-eps * h2i - std::max(a, 0.0));
662 col.push_back(renum(i, j));
663 val.push_back(4 * eps * h2i + fabs(a) + fabs(b));
666 col.push_back(renum(i + 1, j));
667 val.push_back(-eps * h2i + std::min(a, 0.0));
671 col.push_back(renum(i, j + 1));
672 val.push_back(-eps * h2i + std::min(b, 0.0));
677 ptr.push_back(col.size());
682 for (ptrdiff_t j = lo[1]; j <= hi[1]; ++j) {
683 for (ptrdiff_t i = lo[0]; i <= hi[0]; ++i) {
684 if (!symm_dirichlet && (i == 0 || j == 0 || i + 1 == n || j + 1 == n)) {
685 col.push_back(renum(i, j));
691 col.push_back(renum(i, j - 1));
696 col.push_back(renum(i - 1, j));
700 col.push_back(renum(i, j));
701 val.push_back(4 * h2i);
704 col.push_back(renum(i + 1, j));
709 col.push_back(renum(i, j + 1));
715 ptr.push_back(col.size());
719 prof.toc(
"assemble");
723#if defined(SOLVER_BACKEND_CUDA)
724 cusparseCreate(&bprm.cusparse_handle);
727 auto f = Backend::copy_vector(rhs, bprm);
728 auto x = Backend::create_vector(chunk, bprm);
730 Alina::backend::clear(*x);
733 prm.put(
"local.class",
"relaxation");
734 prm.put(
"local.type", relaxation);
737 prm.put(
"local.coarsening.type", coarsening);
738 prm.put(
"local.relax.type", relaxation);
746 SDD solve(world, std::tie(chunk, ptr, col, val), prm, bprm);
753 if (world.rank == 0) {
754 std::cout <<
"Itérations : " << r.nbIteration() << std::endl
755 <<
"Erreur : " << r.residual() << std::endl
756 << prof << std::endl;
761int main(
int argc,
char* argv[])
763 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 --
Alina::detail::empty_params params
Smoothed aggregation coarsening.
Vecteurs de déflation constants ponctuels.
Wrapper de commodité autour de MPI_Comm.