20#pragma GCC diagnostic ignored "-Wdeprecated-copy"
21#pragma GCC diagnostic ignored "-Wint-in-bool-context"
27#include <boost/preprocessor/seq/for_each.hpp>
29#include "arccore/alina/BuiltinBackend.h"
30#include "arccore/alina/StaticMatrix.h"
31#include "arccore/alina/Adapters.h"
33#if defined(SOLVER_BACKEND_CUDA)
34#include "arccore/alina/CudaBackend.h"
35#include "arccore/alina/relaxation_cusparse_ilu0.h"
37#ifndef SOLVER_BACKEND_BUILTIN
38#define SOLVER_BACKEND_BUILTIN
42#include "arccore/alina/MessagePassingUtils.h"
43#include "arccore/alina/DistributedPreconditionedSolver.h"
44#include "arccore/alina/DistributedPreconditioner.h"
45#include "arccore/alina/DistributedSolverRuntime.h"
47#include "arccore/alina/IO.h"
48#include "arccore/alina/Profiler.h"
49#include "arccore/common/internal/ProgramOptions.h"
51#include "SampleProblemCommon.h"
53#ifndef ARCCORE_ALINA_BLOCK_SIZES
54#define ARCCORE_ALINA_BLOCK_SIZES (3)(4)
62 const std::string& A_file,
const std::string& rhs_file,
int block_size,
63 std::vector<ptrdiff_t>& ptr,
64 std::vector<ptrdiff_t>& col,
65 std::vector<double>& val,
66 std::vector<double>& rhs)
69 ptrdiff_t n = A_mm.rows();
71 ptrdiff_t chunk = (n + comm.size - 1) / comm.size;
72 if (chunk % block_size != 0) {
73 chunk += block_size - chunk % block_size;
76 ptrdiff_t row_beg = std::min(n, chunk * comm.rank);
77 ptrdiff_t row_end = std::min(n, row_beg + chunk);
79 chunk = row_end - row_beg;
81 A_mm(ptr, col, val, row_beg, row_end);
83 if (rhs_file.empty()) {
85 std::fill(rhs.begin(), rhs.end(), 1.0);
89 rhs_mm(rhs, row_beg, row_end);
98 const std::string& A_file,
const std::string& rhs_file,
int block_size,
99 std::vector<ptrdiff_t>& ptr,
100 std::vector<ptrdiff_t>& col,
101 std::vector<double>& val,
102 std::vector<double>& rhs)
104 ptrdiff_t n = Alina::IO::crs_size<ptrdiff_t>(A_file);
106 ptrdiff_t chunk = (n + comm.size - 1) / comm.size;
107 if (chunk % block_size != 0) {
108 chunk += block_size - chunk % block_size;
111 ptrdiff_t row_beg = std::min(n, chunk * comm.rank);
112 ptrdiff_t row_end = std::min(n, row_beg + chunk);
114 chunk = row_end - row_beg;
116 Alina::IO::read_crs(A_file, n, ptr, col, val, row_beg, row_end);
118 if (rhs_file.empty()) {
120 std::fill(rhs.begin(), rhs.end(), 1.0);
123 ptrdiff_t rows, cols;
124 Alina::IO::read_dense(rhs_file, rows, cols, rhs, row_beg, row_end);
131template <
class Backend,
class Matrix>
132std::shared_ptr<Alina::DistributedMatrix<Backend>>
135 Alina::eMatrixPartitionerType ptype,
int block_size = 1)
137 auto& prof = Alina::Profiler::globalProfiler();
138 typedef typename Backend::value_type val_type;
139 typedef typename Alina::math::rhs_of<val_type>::type rhs_type;
142 auto A = std::make_shared<DMatrix>(comm, Astrip);
144 if (comm.size == 1 || ptype == Alina::eMatrixPartitionerType::merge)
147 prof.tic(
"partition");
149 prm.put(
"type", ptype);
152 auto I = part(*A, block_size);
154 A = product(*J, *product(*A, *I));
156#if defined(SOLVER_BACKEND_BUILTIN)
158#elif defined(SOLVER_BACKEND_CUDA)
159 thrust::device_vector<rhs_type> new_rhs(J->loc_rows());
162 J->move_to_backend(bprm);
164 Alina::backend::spmv(1, *J, rhs, 0, new_rhs);
166 prof.toc(
"partition");
172#if defined(SOLVER_BACKEND_BUILTIN)
176 const std::vector<ptrdiff_t>& ptr,
177 const std::vector<ptrdiff_t>& col,
178 const std::vector<double>& val,
180 const std::vector<double>& f,
181 Alina::eMatrixPartitionerType ptype)
183 auto& prof = Alina::Profiler::globalProfiler();
199 reinterpret_cast<const rhs_type*
>(&f[0]) + chunk / B);
201 auto get_distributed_matrix = [&]() {
202 auto t = prof.scoped_tic(
"distributed matrix");
204 std::shared_ptr<DMatrix> A;
206 if (ptype != Alina::eMatrixPartitionerType::merge) {
207 A = partition<Backend>(comm,
208 Alina::adapter::block_matrix<val_type>(std::tie(chunk, ptr, col, val)),
209 rhs, bprm, ptype, prm.get(
"precond.coarsening.aggr.block_size", 1));
210 chunk = A->loc_rows();
213 A = std::make_shared<DMatrix>(
215 Alina::adapter::block_matrix<val_type>(std::tie(chunk, ptr, col, val)));
221 std::shared_ptr<DMatrix> A;
222 std::shared_ptr<Solver> solve;
225 auto t = prof.scoped_tic(
"setup");
226 A = get_distributed_matrix();
227 solve = std::make_shared<Solver>(comm, A, prm, bprm);
230 if (comm.rank == 0) {
231 std::cout << *solve << std::endl;
234 if (prm.get(
"precond.allow_rebuild",
false)) {
235 if (comm.rank == 0) {
236 std::cout <<
"Rebuilding the preconditioner..." << std::endl;
240 auto t = prof.scoped_tic(
"rebuild");
241 A = get_distributed_matrix();
242 solve->precond().rebuild(A);
245 if (comm.rank == 0) {
246 std::cout << *solve << std::endl;
256 if (comm.rank == 0) {
257 std::cout <<
"Iterations: " << r.nbIteration() << std::endl
258 <<
"Error: " << r.residual() << std::endl
259 << prof << std::endl;
267 const std::vector<ptrdiff_t>& ptr,
268 const std::vector<ptrdiff_t>& col,
269 const std::vector<double>& val,
271 const std::vector<double>& f,
272 Alina::eMatrixPartitionerType ptype)
274 auto& prof = Alina::Profiler::globalProfiler();
275#if defined(SOLVER_BACKEND_BUILTIN)
278#elif defined(SOLVER_BACKEND_CUDA)
282 std::cout <<
"Using scalar solve ptr_size=" <<
sizeof(ptrdiff_t)
283 <<
" ptr_type_size=" <<
sizeof(Backend::ptr_type)
284 <<
" col_type_size=" <<
sizeof(Backend::col_type)
285 <<
" value_type_size=" <<
sizeof(Backend::value_type)
294#if defined(SOLVER_BACKEND_BUILTIN)
296#elif defined(SOLVER_BACKEND_CUDA)
297 cusparseCreate(&bprm.cusparse_handle);
298 thrust::device_vector<double> rhs(f);
301 auto get_distributed_matrix = [&]() {
302 auto t = prof.scoped_tic(
"distributed matrix");
303 std::shared_ptr<DMatrix> A;
305 if (ptype != Alina::eMatrixPartitionerType::merge) {
306 A = partition<Backend>(comm,
307 std::tie(chunk, ptr, col, val), rhs, bprm, ptype,
308 prm.get(
"precond.coarsening.aggr.block_size", 1));
309 chunk = A->loc_rows();
312 A = std::make_shared<DMatrix>(comm, std::tie(chunk, ptr, col, val));
318 std::shared_ptr<DMatrix> A;
319 std::shared_ptr<Solver> solve;
322 auto t = prof.scoped_tic(
"setup");
323 A = get_distributed_matrix();
324 solve = std::make_shared<Solver>(comm, A, prm, bprm);
327 if (comm.rank == 0) {
328 std::cout <<
"SolverInfo:\n";
329 std::cout << *solve << std::endl;
332 if (prm.get(
"precond.allow_rebuild",
false)) {
333 if (comm.rank == 0) {
334 std::cout <<
"Rebuilding the preconditioner..." << std::endl;
338 auto t = prof.scoped_tic(
"rebuild");
339 A = get_distributed_matrix();
340 solve->precond().rebuild(A);
343 if (comm.rank == 0) {
344 std::cout << *solve << std::endl;
348#if defined(SOLVER_BACKEND_BUILTIN)
350#elif defined(SOLVER_BACKEND_CUDA)
351 thrust::device_vector<double> x(chunk, 0.0);
358 if (comm.rank == 0) {
359 std::cout <<
"Iterations: " << r.nbIteration() << std::endl
360 <<
"Error: " << r.residual() << std::endl
361 << prof << std::endl;
366int main(
int argc,
char* argv[])
368 auto& prof = Alina::Profiler::globalProfiler();
374 std::cout <<
"World size: " << comm.size << std::endl;
377 namespace po = Arcane::ProgramOptions;
380 desc.add_options()(
"help,h",
"show help");
381 desc.add_options()(
"matrix,A",
382 po::value<std::string>(),
383 "System matrix in the MatrixMarket format. "
384 "When not specified, a Poisson problem in 3D unit cube is assembled. ");
385 desc.add_options()(
"rhs,f",
386 po::value<std::string>()->default_value(
""),
387 "The RHS vector in the MatrixMarket format. "
388 "When omitted, a vector of ones is used by default. "
389 "Should only be provided together with a system matrix. ");
390 desc.add_options()(
"Ap",
391 po::value<std::vector<std::string>>()->multitoken(),
392 "Pre-partitioned matrix (single file per MPI process)");
393 desc.add_options()(
"fp",
394 po::value<std::vector<std::string>>()->multitoken(),
395 "Pre-partitioned RHS (single file per MPI process)");
396 desc.add_options()(
"binary,B",
397 po::bool_switch()->default_value(
false),
398 "When specified, treat input files as binary instead of as MatrixMarket. "
399 "It is assumed the files were converted to binary format with mm2bin utility. ");
400 desc.add_options()(
"block-size,b",
401 po::value<int>()->default_value(1),
402 "The block size of the system matrix. "
403 "When specified, the system matrix is assumed to have block-wise structure. "
404 "This usually is the case for problems in elasticity, structural mechanics, "
405 "for coupled systems of PDE (such as Navier-Stokes equations), etc. ");
406 desc.add_options()(
"partitioner,r",
407 po::value<Alina::eMatrixPartitionerType>()->default_value(
408#
if defined(ARCCORE_ALINA_HAVE_PARMETIS)
409 Alina::eMatrixPartitionerType::parmetis
411 Alina::eMatrixPartitionerType::merge
414 "Repartition the system matrix");
415 desc.add_options()(
"size,n",
416 po::value<ptrdiff_t>()->default_value(128),
418 desc.add_options()(
"prm-file,P",
419 po::value<std::string>(),
420 "Parameter file in json format. ");
421 desc.add_options()(
"prm,p",
422 po::value<std::vector<std::string>>()->multitoken(),
423 "Parameters specified as name=value pairs. "
424 "May be provided multiple times. Examples:\n"
425 " -p solver.tol=1e-3\n"
426 " -p precond.coarse_enough=300");
427 desc.add_options()(
"test-rebuild",
428 po::bool_switch()->default_value(
false),
429 "When specified, try to rebuild the solver before solving. ");
438 if (vm.count(
"help")) {
440 std::cout << desc << std::endl;
445 if (vm.count(
"prm-file")) {
446 prm.read_json(vm[
"prm-file"].as<std::string>());
449 if (vm.count(
"prm")) {
450 for (
const std::string& v : vm[
"prm"].as<std::vector<std::string>>()) {
456 std::vector<ptrdiff_t> ptr;
457 std::vector<ptrdiff_t> col;
458 std::vector<double> val;
459 std::vector<double> rhs;
461 int block_size = vm[
"block-size"].as<
int>();
462 int aggr_block = prm.get(
"precond.coarsening.aggr.block_size", 1);
464 bool binary = vm[
"binary"].as<
bool>();
465 Alina::eMatrixPartitionerType ptype = vm[
"partitioner"].as<Alina::eMatrixPartitionerType>();
467 if (vm.count(
"matrix")) {
470 n = read_binary(comm,
471 vm[
"matrix"].as<std::string>(),
472 vm[
"rhs"].as<std::string>(),
473 block_size * aggr_block, ptr, col, val, rhs);
476 n = read_matrix_market(comm,
477 vm[
"matrix"].as<std::string>(),
478 vm[
"rhs"].as<std::string>(),
479 block_size * aggr_block, ptr, col, val, rhs);
483 else if (vm.count(
"Ap")) {
485 ptype = Alina::eMatrixPartitionerType::merge;
487 std::vector<std::string> Aparts = vm[
"Ap"].as<std::vector<std::string>>();
488 comm.
check(Aparts.size() ==
static_cast<size_t>(comm.size),
489 "--Ap should have single entry per MPI process");
492 Alina::IO::read_crs(Aparts[comm.rank], n, ptr, col, val);
499 if (vm.count(
"fp")) {
500 std::vector<std::string> fparts = vm[
"fp"].as<std::vector<std::string>>();
501 comm.
check(fparts.size() ==
static_cast<size_t>(comm.size),
502 "--fp should have single entry per MPI process");
508 Alina::IO::read_dense(fparts[comm.rank], rows, cols, rhs);
514 comm.
check(rhs.size() ==
static_cast<size_t>(n),
"Wrong RHS size");
522 prof.tic(
"assemble");
523 n = sample_problem_distributed(comm.rank, comm.size,
524 vm[
"size"].as<ptrdiff_t>(),
525 block_size * aggr_block, ptr, col, val, rhs);
526 prof.toc(
"assemble");
529 if (vm[
"test-rebuild"].as<bool>()) {
530 prm.put(
"precond.allow_rebuild",
true);
533 switch (block_size) {
535#if defined(SOLVER_BACKEND_BUILTIN)
536#define ARCCORE_ALINA_CALL_BLOCK_SOLVER(z, data, B) \
538 solve_block<B>(comm, n, ptr, col, val, prm, rhs, ptype); \
541 BOOST_PP_SEQ_FOR_EACH(ARCCORE_ALINA_CALL_BLOCK_SOLVER, ~, ARCCORE_ALINA_BLOCK_SIZES)
543#undef ARCCORE_ALINA_CALL_BLOCK_SOLVER
547 solve_scalar(comm, n, ptr, col, val, prm, rhs, ptype);
551 std::cout <<
"Unsupported block size!" << std::endl;
Distributed Matrix using message passing.
Iterative solver wrapper for distributed linear systems.
Distributed Preconditioner.
Class to store parameters as a hierarchical key/value tree.
NUMA-aware vector container.
Matrix class, to be used by user.
Fluent command-line parser builder.
Describes a set of command-line options.
Describes positional (non-option) arguments.
Stores parsed option values.
__host__ __device__ Real3x3 transpose(const Real3x3 &t)
Transpose the matrix.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Alina::detail::empty_params params
Runtime-configurable wrapper around matrix partitioner.
Convenience wrapper around MPI_Comm.
void check(const Condition &cond, const Message &message)
Communicator-wise condition checking.
Convenience wrapper around MPI_Init_threads/MPI_Finalize.