24#pragma GCC diagnostic ignored "-Wdeprecated-copy"
25#pragma GCC diagnostic ignored "-Wint-in-bool-context"
27#include <boost/range/iterator_range.hpp>
28#include <boost/preprocessor/seq/for_each.hpp>
30#if defined(SOLVER_BACKEND_CUDA)
31#include "arccore/alina/CudaBackend.h"
32#include "arccore/alina/relaxation_cusparse_ilu0.h"
34#elif defined(SOLVER_BACKEND_EIGEN)
35#include "arccore/alina/EigenBackend.h"
38#ifndef SOLVER_BACKEND_BUILTIN
39#define SOLVER_BACKEND_BUILTIN
41#include "arccore/alina/BuiltinBackend.h"
42#include "arccore/alina/StaticMatrix.h"
43#include "arccore/alina/Adapters.h"
49#include <arccore/base/PlatformUtils.h>
50#include <arccore/base/String.h>
51#include <arccore/base/Convert.h>
53#include "arccore/alina/RelaxationRuntime.h"
54#include "arccore/alina/CoarseningRuntime.h"
55#include "arccore/alina/SolverRuntime.h"
56#include "arccore/alina/PreconditionerRuntime.h"
57#include "arccore/alina/PreconditionedSolver.h"
58#include "arccore/alina/AMG.h"
59#include "arccore/alina/Adapters.h"
60#include "arccore/alina/IO.h"
61#include "arccore/alina/Profiler.h"
63#include "arccore/common/internal/ProgramOptions.h"
65#include "SampleProblemCommon.h"
67#ifndef ARCCORE_ALINA_BLOCK_SIZES
68#define ARCCORE_ALINA_BLOCK_SIZES (3)(4)
73using Alina::precondition;
75#ifdef SOLVER_BACKEND_BUILTIN
77#include "./HypreComparer.h"
84 std::vector<ptrdiff_t>
const& ptr,
85 std::vector<ptrdiff_t>
const& col,
86 std::vector<double>
const& val,
87 std::vector<double>
const& rhs,
88 std::vector<double>& x,
91 auto& prof = Alina::Profiler::globalProfiler();
99 auto As = std::tie(rows, ptr, col, val);
100 auto Ab = Alina::adapter::block_matrix<value_type>(As);
102 std::tuple<size_t, double> info;
110 Solver solve(context, perm(Ab), prm);
113 std::cout << solve << std::endl;
115 rhs_type
const* fptr =
reinterpret_cast<rhs_type const*
>(&rhs[0]);
116 rhs_type* xptr =
reinterpret_cast<rhs_type*
>(&x[0]);
125 perm.inverse(X, xptr);
129 Solver solve(context, Ab, prm);
132 std::cout << solve << std::endl;
134 rhs_type
const* fptr =
reinterpret_cast<rhs_type const*
>(&rhs[0]);
135 rhs_type* xptr =
reinterpret_cast<rhs_type*
>(&x[0]);
144 std::copy(X.data(), X.data() + X.size(), xptr);
156 std::vector<ptrdiff_t>
const& ptr,
157 std::vector<ptrdiff_t>
const& col,
158 std::vector<double>
const& val,
159 std::vector<double>
const& rhs,
160 std::vector<double>& x,
163 std::cout <<
"Using scalar solve ptr_size=" <<
sizeof(ptrdiff_t)
164 <<
" ptr_type_size=" <<
sizeof(Backend::ptr_type)
165 <<
" col_type_size=" <<
sizeof(Backend::col_type)
166 <<
" value_type_size=" <<
sizeof(Backend::value_type)
168 auto& prof = Alina::Profiler::globalProfiler();
171#if defined(SOLVER_BACKEND_CUDA)
172 cusparseCreate(&bprm.cusparse_handle);
178 cudaGetDeviceProperties(&prop, dev);
179 std::cout << prop.name << std::endl
194 Solver solve(context, perm(std::tie(rows, ptr, col, val)), prm, bprm);
197 std::cout << solve << std::endl;
199 std::vector<double> tmp(rows);
201 perm.forward(rhs, tmp);
202 auto f_b = Backend::copy_vector(tmp, bprm);
204 perm.forward(x, tmp);
205 auto x_b = Backend::copy_vector(tmp, bprm);
208 info = solve(*f_b, *x_b);
211#if defined(SOLVER_BACKEND_CUDA)
212 thrust::copy(x_b->begin(), x_b->end(), tmp.begin());
214 std::copy(&(*x_b)[0], &(*x_b)[0] + rows, &tmp[0]);
217 perm.inverse(tmp, x);
221 Solver solve(context, std::tie(rows, ptr, col, val), prm, bprm);
224 std::cout << solve << std::endl;
226 auto f_b = Backend::copy_vector(rhs, bprm);
227 auto x_b = Backend::copy_vector(x, bprm);
230 info = solve(*f_b, *x_b);
233#if defined(SOLVER_BACKEND_CUDA)
234 thrust::copy(x_b->begin(), x_b->end(), x.begin());
236 std::copy(&(*x_b)[0], &(*x_b)[0] + rows, &x[0]);
243#define ARCCORE_ALINA_CALL_BLOCK_SOLVER(z, data, B) \
245 return block_solve<B>(context, prm, rows, ptr, col, val, rhs, x, reorder);
252 std::vector<ptrdiff_t>
const& ptr,
253 std::vector<ptrdiff_t>
const& col,
254 std::vector<double>
const& val,
255 std::vector<double>
const& rhs,
256 std::vector<double>& x,
260 switch (block_size) {
262 return scalar_solve(context, prm, rows, ptr, col, val, rhs, x, reorder);
263#if defined(SOLVER_BACKEND_BUILTIN)
264 BOOST_PP_SEQ_FOR_EACH(ARCCORE_ALINA_CALL_BLOCK_SOLVER, ~, ARCCORE_ALINA_BLOCK_SIZES)
267 precondition(
false,
"Unsupported block size");
274int main(
int argc,
char* argv[])
276 auto& prof = Alina::Profiler::globalProfiler();
277 namespace po = Arcane::ProgramOptions;
278 namespace io = Alina::IO;
286 desc.add_options()(
"help,h",
"Show this help.")(
"prm-file,P",
288 "Parameter file in json format. ")(
290 po::value<vector<string>>()->multitoken(),
291 "Parameters specified as name=value pairs. "
292 "May be provided multiple times. Examples:\n"
293 " -p solver.tol=1e-3\n"
294 " -p precond.coarse_enough=300")(
"matrix,A",
296 "System matrix in the MatrixMarket format. "
297 "When not specified, solves a Poisson problem in 3D unit cube. ")(
300 "The RHS vector in the MatrixMarket format. "
301 "When omitted, a vector of ones is used by default. "
302 "Should only be provided together with a system matrix. ")(
304 po::bool_switch()->default_value(
false),
305 "Use zero RHS vector. Implies --random-initial and solver.ns_search=true")(
307 po::bool_switch()->default_value(
false),
308 "Set RHS = Ax where x = 1")(
311 "The near null-space vectors in the MatrixMarket format. "
312 "Should be a dense matrix of size N*M, where N is the number of "
313 "unknowns, and M is the number of null-space vectors. "
314 "Should only be provided together with a system matrix. ")(
317 "Coordinate matrix where number of rows corresponds to the number of grid nodes "
318 "and the number of columns corresponds to the problem dimensionality (2 or 3). "
319 "Will be used to construct near null-space vectors as rigid body modes. "
320 "Should only be provided together with a system matrix. ")(
322 po::bool_switch()->default_value(
false),
323 "When specified, treat input files as binary instead of as MatrixMarket. "
324 "It is assumed the files were converted to binary format with mm2bin utility. ")(
326 po::bool_switch()->default_value(
false),
327 "Scale the matrix so that the diagonal is unit. ")(
329 po::value<int>()->default_value(1),
330 "The block size of the system matrix. "
331 "When specified, the system matrix is assumed to have block-wise structure. "
332 "This usually is the case for problems in elasticity, structural mechanics, "
333 "for coupled systems of PDE (such as Navier-Stokes equations), etc. ")(
335 po::value<int>()->default_value(32),
336 "The size of the Poisson problem to solve when no system matrix is given. "
337 "Specified as number of grid nodes along each dimension of a unit cube. "
338 "The resulting system will have n*n*n unknowns. ")(
340 po::value<double>()->default_value(1.0),
341 "The anisotropy value for the generated Poisson value. "
342 "Used to determine problem scaling along X, Y, and Z axes: "
343 "hy = hx * a, hz = hy * a.")(
345 po::bool_switch()->default_value(
false),
346 "When specified, the AMG hierarchy is not constructed. "
347 "Instead, the problem is solved using a single-level smoother as preconditioner. ")(
349 po::bool_switch()->default_value(
false),
350 "When specified, the matrix will be reordered to improve cache-locality")(
352 po::value<double>()->default_value(0),
353 "Value to use as initial approximation. ")(
355 po::bool_switch()->default_value(
false),
356 "Use random initial approximation. ")(
359 "Output file. Will be saved in the MatrixMarket format. "
360 "When omitted, the solution is not saved. ");
369 if (vm.count(
"help")) {
370 std::cout << desc << std::endl;
374 for (
int i = 0; i < argc; ++i) {
377 std::cout << argv[i];
379 std::cout << std::endl;
382 if (vm.count(
"prm-file")) {
383 prm.read_json(vm[
"prm-file"].as<string>());
386 if (vm.count(
"prm")) {
387 for (
const string& v : vm[
"prm"].as<vector<string>>()) {
393 vector<ptrdiff_t> ptr, col;
394 vector<double> val, rhs, null, x;
396 if (vm.count(
"matrix")) {
397 auto t = prof.scoped_tic(
"reading");
399 string Afile = vm[
"matrix"].as<
string>();
400 bool binary = vm[
"binary"].as<
bool>();
403 io::read_crs(Afile, rows, ptr, col, val);
407 std::tie(rows, cols) = io::mm_reader(Afile)(ptr, col, val);
408 precondition(rows == cols,
"Non-square system matrix");
411 if (vm.count(
"rhs")) {
412 string bfile = vm[
"rhs"].as<
string>();
417 io::read_dense(bfile, n, m, rhs);
420 std::tie(n, m) = io::mm_reader(bfile)(rhs);
423 precondition(n == rows && m == 1,
"The RHS vector has wrong size");
425 else if (vm[
"f1"].as<bool>()) {
427 for (
size_t i = 0; i < rows; ++i) {
429 for (ptrdiff_t j = ptr[i], e = ptr[i + 1]; j < e; ++j)
435 rhs.resize(rows, vm[
"f0"].as<bool>() ? 0.0 : 1.0);
438 if (vm.count(
"null")) {
439 string nfile = vm[
"null"].as<
string>();
444 io::read_dense(nfile, m, nv, null);
447 std::tie(m, nv) = io::mm_reader(nfile)(null);
450 precondition(m == rows,
"Near null-space vectors have wrong size");
452 else if (vm.count(
"coords")) {
453 string cfile = vm[
"coords"].as<
string>();
454 std::vector<double> coo;
459 io::read_dense(cfile, m, ndim, coo);
462 std::tie(m, ndim) = io::mm_reader(cfile)(coo);
465 precondition(m * ndim == rows && (ndim == 2 || ndim == 3),
"Coordinate matrix has wrong size");
467 nv = Alina::rigid_body_modes(ndim, coo, null);
471 prm.put(
"precond.coarsening.nullspace.cols", nv);
472 prm.put(
"precond.coarsening.nullspace.rows", rows);
473 prm.put(
"precond.coarsening.nullspace.B", &null[0]);
477 auto t = prof.scoped_tic(
"assembling");
478 rows = Alina::PoissonProblemGenerator::createSequentialMatrix(vm[
"size"].as<int>(), val, col, ptr, rhs, vm[
"anisotropy"].as<double>());
481 if (vm[
"scale"].as<bool>()) {
482 std::vector<double> dia(rows, 1.0);
484 for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(rows); ++i) {
486 for (ptrdiff_t j = ptr[i], e = ptr[i + 1]; j < e; ++j) {
488 d = 1 /
sqrt(val[j]);
495 for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(rows); ++i) {
497 for (ptrdiff_t j = ptr[i], e = ptr[i + 1]; j < e; ++j) {
498 val[j] *= dia[i] * dia[col[j]];
503 x.resize(rows, vm[
"initial"].as<double>());
504 if (vm[
"random-initial"].as<bool>() || vm[
"f0"].as<bool>()) {
506 std::uniform_real_distribution<double> rnd(-1, 1);
511 if (vm[
"f0"].as<bool>()) {
512 prm.put(
"solver.ns_search",
true);
515 int block_size = vm[
"block-size"].as<
int>();
516 std::cout <<
"BlockSize= " << block_size <<
"\n";
518 if (vm[
"single-level"].as<bool>())
519 prm.put(
"precond.class",
"relaxation");
522 bool do_hypre =
false;
524 do_hypre = v.value();
527#ifndef SOLVER_BACKEND_BUILTIN
531#ifdef SOLVER_BACKEND_BUILTIN
533 hypre_comparer.solve(rows, ptr, col, val, rhs, x, argc, argv);
537 solver_result = solve(context, prm, rows, ptr, col, val, rhs, x, block_size, vm[
"reorder"].as<bool>());
539 if (vm.count(
"output")) {
540 auto t = prof.scoped_tic(
"write");
541 Alina::IO::mm_write(vm[
"output"].as<string>(), &x[0], x.size());
544 std::cout <<
"Iterations: " << solver_result.nbIteration() << std::endl
545 <<
"Error: " << solver_result.residual() << std::endl
546 << prof << std::endl;
Convenience class that bundles together a preconditioner and an iterative solver.
Class to store parameters as a hierarchical key/value tree.
NUMA-aware vector container.
Template class for converting a type.
Fluent command-line parser builder.
Describes a set of command-line options.
Describes positional (non-option) arguments.
Stores parsed option values.
View of an array of elements of type T.
Unicode character string.
apfloat sqrt(apfloat v)
Square root of v.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Alina::detail::empty_params params
Runtime-configurable wrappers around iterative solvers.