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 "Use symmetric Dirichlet conditions in laplace2d")(
494 po::value<ptrdiff_t>(&n)->default_value(n),
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 "number of partitions for partitioned deflation")(
519 po::value<std::string>(¶meter_file),
520 "parameter file in json format")(
522 po::value<std::vector<std::string>>()->multitoken(),
523 "Parameters specified as name=value pairs. "
524 "May be provided multiple times. Examples:\n"
525 " -p solver.tol=1e-3\n"
526 " -p precond.coarse_enough=300")(
528 po::bool_switch(&just_relax),
529 "Do not create AMG hierarchy, use relaxation as preconditioner")(
531 po::value<std::string>(&out_file),
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 <<
"Iterations: " << r.nbIteration() << std::endl
755 <<
"Error: " << 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.
Distributed solver based on subdomain deflation.
Generalized Minimal Residual (GMRES) method.
Convenience class that bundles together a preconditioner and an iterative solver.
Modifiable view of an array of type T.
Constant view of an array of type T.
Describes a set of command-line options.
Stores parsed option values.
View of an array of elements of type T.
void mpAllGather(IMessagePassingMng *pm, const ISerializer *send_serializer, ISerializer *receive_serialize)
allGather() message for serialization
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Alina::detail::empty_params params
Smoothed aggregation coarsening.
Pointwise constant deflation vectors.
Convenience wrapper around MPI_Comm.