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)
177 const std::vector<ptrdiff_t>& ptr,
178 const std::vector<ptrdiff_t>& col,
179 const std::vector<double>& val,
181 const std::vector<double>& f,
182 Alina::eMatrixPartitionerType ptype)
184 auto& prof = Alina::Profiler::globalProfiler();
200 reinterpret_cast<const rhs_type*
>(&f[0]) + chunk / B);
202 auto get_distributed_matrix = [&]() {
203 auto t = prof.scoped_tic(
"distributed matrix");
205 std::shared_ptr<DMatrix> A;
207 if (ptype != Alina::eMatrixPartitionerType::merge) {
208 A = partition<Backend>(comm,
209 Alina::adapter::block_matrix<val_type>(std::tie(chunk, ptr, col, val)),
210 rhs, bprm, ptype, prm.get(
"precond.coarsening.aggr.block_size", 1));
211 chunk = A->loc_rows();
214 A = std::make_shared<DMatrix>(
216 Alina::adapter::block_matrix<val_type>(std::tie(chunk, ptr, col, val)));
222 std::shared_ptr<DMatrix> A;
223 std::shared_ptr<Solver> solve;
226 auto t = prof.scoped_tic(
"setup");
227 A = get_distributed_matrix();
228 solve = std::make_shared<Solver>(context, comm, A, prm, bprm);
231 if (comm.rank == 0) {
232 std::cout << *solve << std::endl;
235 if (prm.get(
"precond.allow_rebuild",
false)) {
236 if (comm.rank == 0) {
237 std::cout <<
"Rebuilding the preconditioner..." << std::endl;
241 auto t = prof.scoped_tic(
"rebuild");
242 A = get_distributed_matrix();
243 solve->precond().rebuild(A);
246 if (comm.rank == 0) {
247 std::cout << *solve << std::endl;
257 if (comm.rank == 0) {
258 std::cout <<
"Iterations: " << r.nbIteration() << std::endl
259 <<
"Error: " << r.residual() << std::endl
260 << prof << std::endl;
269 const std::vector<ptrdiff_t>& ptr,
270 const std::vector<ptrdiff_t>& col,
271 const std::vector<double>& val,
273 const std::vector<double>& f,
274 Alina::eMatrixPartitionerType ptype)
276 auto& prof = Alina::Profiler::globalProfiler();
277#if defined(SOLVER_BACKEND_BUILTIN)
280#elif defined(SOLVER_BACKEND_CUDA)
284 std::cout <<
"Using scalar solve ptr_size=" <<
sizeof(ptrdiff_t)
285 <<
" ptr_type_size=" <<
sizeof(Backend::ptr_type)
286 <<
" col_type_size=" <<
sizeof(Backend::col_type)
287 <<
" value_type_size=" <<
sizeof(Backend::value_type)
296#if defined(SOLVER_BACKEND_BUILTIN)
298#elif defined(SOLVER_BACKEND_CUDA)
299 cusparseCreate(&bprm.cusparse_handle);
300 thrust::device_vector<double> rhs(f);
303 auto get_distributed_matrix = [&]() {
304 auto t = prof.scoped_tic(
"distributed matrix");
305 std::shared_ptr<DMatrix> A;
307 if (ptype != Alina::eMatrixPartitionerType::merge) {
308 A = partition<Backend>(comm,
309 std::tie(chunk, ptr, col, val), rhs, bprm, ptype,
310 prm.get(
"precond.coarsening.aggr.block_size", 1));
311 chunk = A->loc_rows();
314 A = std::make_shared<DMatrix>(comm, std::tie(chunk, ptr, col, val));
320 std::shared_ptr<DMatrix> A;
321 std::shared_ptr<Solver> solve;
324 auto t = prof.scoped_tic(
"setup");
325 A = get_distributed_matrix();
326 solve = std::make_shared<Solver>(context, comm, A, prm, bprm);
329 if (comm.rank == 0) {
330 std::cout <<
"SolverInfo:\n";
331 std::cout << *solve << std::endl;
334 if (prm.get(
"precond.allow_rebuild",
false)) {
335 if (comm.rank == 0) {
336 std::cout <<
"Rebuilding the preconditioner..." << std::endl;
340 auto t = prof.scoped_tic(
"rebuild");
341 A = get_distributed_matrix();
342 solve->precond().rebuild(A);
345 if (comm.rank == 0) {
346 std::cout << *solve << std::endl;
350#if defined(SOLVER_BACKEND_BUILTIN)
352#elif defined(SOLVER_BACKEND_CUDA)
353 thrust::device_vector<double> x(chunk, 0.0);
360 if (comm.rank == 0) {
361 std::cout <<
"Iterations: " << r.nbIteration() << std::endl
362 <<
"Error: " << r.residual() << std::endl
363 << prof << std::endl;
368int main(
int argc,
char* argv[])
370 auto& prof = Alina::Profiler::globalProfiler();
375 std::cout <<
"World size: " << comm.size << std::endl;
379 namespace po = Arcane::ProgramOptions;
382 desc.add_options()(
"help,h",
"show help");
383 desc.add_options()(
"matrix,A",
384 po::value<std::string>(),
385 "System matrix in the MatrixMarket format. "
386 "When not specified, a Poisson problem in 3D unit cube is assembled. ");
387 desc.add_options()(
"rhs,f",
388 po::value<std::string>()->default_value(
""),
389 "The RHS vector in the MatrixMarket format. "
390 "When omitted, a vector of ones is used by default. "
391 "Should only be provided together with a system matrix. ");
392 desc.add_options()(
"Ap",
393 po::value<std::vector<std::string>>()->multitoken(),
394 "Pre-partitioned matrix (single file per MPI process)");
395 desc.add_options()(
"fp",
396 po::value<std::vector<std::string>>()->multitoken(),
397 "Pre-partitioned RHS (single file per MPI process)");
398 desc.add_options()(
"binary,B",
399 po::bool_switch()->default_value(
false),
400 "When specified, treat input files as binary instead of as MatrixMarket. "
401 "It is assumed the files were converted to binary format with mm2bin utility. ");
402 desc.add_options()(
"block-size,b",
403 po::value<int>()->default_value(1),
404 "The block size of the system matrix. "
405 "When specified, the system matrix is assumed to have block-wise structure. "
406 "This usually is the case for problems in elasticity, structural mechanics, "
407 "for coupled systems of PDE (such as Navier-Stokes equations), etc. ");
408 desc.add_options()(
"partitioner,r",
409 po::value<Alina::eMatrixPartitionerType>()->default_value(
410#
if defined(ARCCORE_ALINA_HAVE_PARMETIS)
411 Alina::eMatrixPartitionerType::parmetis
413 Alina::eMatrixPartitionerType::merge
416 "Repartition the system matrix");
417 desc.add_options()(
"size,n",
418 po::value<ptrdiff_t>()->default_value(128),
420 desc.add_options()(
"prm-file,P",
421 po::value<std::string>(),
422 "Parameter file in json format. ");
423 desc.add_options()(
"prm,p",
424 po::value<std::vector<std::string>>()->multitoken(),
425 "Parameters specified as name=value pairs. "
426 "May be provided multiple times. Examples:\n"
427 " -p solver.tol=1e-3\n"
428 " -p precond.coarse_enough=300");
429 desc.add_options()(
"test-rebuild",
430 po::bool_switch()->default_value(
false),
431 "When specified, try to rebuild the solver before solving. ");
440 if (vm.count(
"help")) {
442 std::cout << desc << std::endl;
447 if (vm.count(
"prm-file")) {
448 prm.read_json(vm[
"prm-file"].as<std::string>());
451 if (vm.count(
"prm")) {
452 for (
const std::string& v : vm[
"prm"].as<std::vector<std::string>>()) {
458 std::vector<ptrdiff_t> ptr;
459 std::vector<ptrdiff_t> col;
460 std::vector<double> val;
461 std::vector<double> rhs;
463 int block_size = vm[
"block-size"].as<
int>();
464 int aggr_block = prm.get(
"precond.coarsening.aggr.block_size", 1);
466 bool binary = vm[
"binary"].as<
bool>();
467 Alina::eMatrixPartitionerType ptype = vm[
"partitioner"].as<Alina::eMatrixPartitionerType>();
469 if (vm.count(
"matrix")) {
472 n = read_binary(comm,
473 vm[
"matrix"].as<std::string>(),
474 vm[
"rhs"].as<std::string>(),
475 block_size * aggr_block, ptr, col, val, rhs);
478 n = read_matrix_market(comm,
479 vm[
"matrix"].as<std::string>(),
480 vm[
"rhs"].as<std::string>(),
481 block_size * aggr_block, ptr, col, val, rhs);
485 else if (vm.count(
"Ap")) {
487 ptype = Alina::eMatrixPartitionerType::merge;
489 std::vector<std::string> Aparts = vm[
"Ap"].as<std::vector<std::string>>();
490 comm.
check(Aparts.size() ==
static_cast<size_t>(comm.size),
491 "--Ap should have single entry per MPI process");
494 Alina::IO::read_crs(Aparts[comm.rank], n, ptr, col, val);
501 if (vm.count(
"fp")) {
502 std::vector<std::string> fparts = vm[
"fp"].as<std::vector<std::string>>();
503 comm.
check(fparts.size() ==
static_cast<size_t>(comm.size),
504 "--fp should have single entry per MPI process");
510 Alina::IO::read_dense(fparts[comm.rank], rows, cols, rhs);
516 comm.
check(rhs.size() ==
static_cast<size_t>(n),
"Wrong RHS size");
524 prof.tic(
"assemble");
525 n = Alina::PoissonProblemGenerator::createDistributedMatrix(comm.rank, comm.size,
526 vm[
"size"].as<ptrdiff_t>(),
527 block_size * aggr_block, ptr, col, val, rhs);
528 prof.toc(
"assemble");
531 if (vm[
"test-rebuild"].as<bool>()) {
532 prm.put(
"precond.allow_rebuild",
true);
535 switch (block_size) {
537#if defined(SOLVER_BACKEND_BUILTIN)
538#define ARCCORE_ALINA_CALL_BLOCK_SOLVER(z, data, B) \
540 solve_block<B>(context, comm, n, ptr, col, val, prm, rhs, ptype); \
543 BOOST_PP_SEQ_FOR_EACH(ARCCORE_ALINA_CALL_BLOCK_SOLVER, ~, ARCCORE_ALINA_BLOCK_SIZES)
545#undef ARCCORE_ALINA_CALL_BLOCK_SOLVER
549 solve_scalar(context, comm, n, ptr, col, val, prm, rhs, ptype);
553 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.
static Ref< IMessagePassingMng > createAndInitializeMPI(int *argc, char **argv[], int wanted_thread_level)
Initialize MPI and creates a manager associated with the MPI_WORLD_COMM communicator.
Fluent command-line parser builder.
Describes a set of command-line options.
Describes positional (non-option) arguments.
Stores parsed option values.
Reference to an instance.
__host__ __device__ Real3x3 transpose(const Real3x3 &t)
Transpose the matrix.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Convenience wrapper around MPI_Comm.
void check(bool cond, const String &message)
Communicator-wise condition checking.
Alina::detail::empty_params params
Runtime-configurable wrapper around matrix partitioner.