Arcane  4.2.3.0
Developer documentation
Loading...
Searching...
No Matches
DeflatedSolver.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/*---------------------------------------------------------------------------*/
9/*
10 * This file is based on the work on the AMGCL library (version March 2026)
11 * which can be found at https://github.com/ddemidov/amgcl.
12 *
13 * Copyright (c) 2012-2022 Denis Demidov <dennis.demidov@gmail.com>
14 * SPDX-License-Identifier: MIT
15 */
16/*---------------------------------------------------------------------------*/
17/*---------------------------------------------------------------------------*/
18
19#include <iostream>
20#include <string>
21
22#include "arccore/alina/BuiltinBackend.h"
23#include "arccore/alina/RelaxationRuntime.h"
24#include "arccore/alina/CoarseningRuntime.h"
25#include "arccore/alina/SolverRuntime.h"
26#include "arccore/alina/PreconditionerRuntime.h"
27#include "arccore/alina/DeflatedSolver.h"
28#include "arccore/alina/AMG.h"
29#include "arccore/alina/Adapters.h"
30#include "arccore/alina/IO.h"
31#include "arccore/alina/Profiler.h"
32
33#include "arccore/common/internal/ProgramOptions.h"
34
35using namespace Arcane;
36
37using Alina::precondition;
38
39//---------------------------------------------------------------------------
40int main(int argc, char* argv[])
41{
42 auto& prof = Alina::Profiler::globalProfiler();
43
44 namespace po = Arcane::ProgramOptions;
45 namespace io = Alina::IO;
46
47 using std::string;
48 using std::vector;
49
50 Alina::AlinaContext context;
51 po::options_description desc("Options");
52
53 desc.add_options()("help,h", "Show this help.");
54 desc.add_options()("prm-file,P",
55 po::value<string>(),
56 "Parameter file in json format. ");
57 desc.add_options()("prm,p",
58 po::value<vector<string>>()->multitoken(),
59 "Parameters specified as name=value pairs. "
60 "May be provided multiple times. Examples:\n"
61 " -p solver.tol=1e-3\n"
62 " -p precond.coarse_enough=300");
63 desc.add_options()("matrix,A",
64 po::value<string>()->required(),
65 "System matrix in the MatrixMarket format.");
66 desc.add_options()("rhs,f",
67 po::value<string>(),
68 "The RHS vector in the MatrixMarket format. "
69 "When omitted, a vector of ones is used by default. "
70 "Should only be provided together with a system matrix. ");
71 desc.add_options()("defvec,D",
72 po::value<string>(),
73 "The near null-space vectors in the MatrixMarket format. ");
74 desc.add_options()("coords,C",
75 po::value<string>(),
76 "Coordinate matrix where number of rows corresponds to the number of grid nodes "
77 "and the number of columns corresponds to the problem dimensionality (2 or 3). "
78 "Will be used to construct near null-space vectors as rigid body modes. ");
79 desc.add_options()("binary,B",
80 po::bool_switch()->default_value(false),
81 "When specified, treat input files as binary instead of as MatrixMarket. "
82 "It is assumed the files were converted to binary format with mm2bin utility. ");
83 desc.add_options()("single-level,1",
84 po::bool_switch()->default_value(false),
85 "When specified, the AMG hierarchy is not constructed. "
86 "Instead, the problem is solved using a single-level smoother as preconditioner. ");
87 desc.add_options()("output,o",
88 po::value<string>(),
89 "Output file. Will be saved in the MatrixMarket format. "
90 "When omitted, the solution is not saved. ");
91
93 p.add("prm", -1);
94
96 po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
97 po::notify(vm);
98
99 if (vm.count("help")) {
100 std::cout << desc << std::endl;
101 return 0;
102 }
103
104 for (int i = 0; i < argc; ++i) {
105 if (i)
106 std::cout << " ";
107 std::cout << argv[i];
108 }
109 std::cout << std::endl;
110
112 if (vm.count("prm-file")) {
113 prm.read_json(vm["prm-file"].as<string>());
114 }
115
116 if (vm.count("prm")) {
117 for (const string& v : vm["prm"].as<vector<string>>()) {
118 prm.putKeyValue(v);
119 }
120 }
121
122 if (!vm.count("defvec") && !vm.count("coords")) {
123 std::cerr << "Either defvec or coords should be given" << std::endl;
124 return 1;
125 }
126
127 ptrdiff_t rows, nv;
128 vector<ptrdiff_t> ptr, col;
129 vector<double> val, rhs, z;
130
131 {
132 auto t = prof.scoped_tic("reading");
133
134 string Afile = vm["matrix"].as<string>();
135 bool binary = vm["binary"].as<bool>();
136
137 if (binary) {
138 io::read_crs(Afile, rows, ptr, col, val);
139 }
140 else {
141 ptrdiff_t cols;
142 std::tie(rows, cols) = io::mm_reader(Afile)(ptr, col, val);
143 precondition(rows == cols, "Non-square system matrix");
144 }
145
146 if (vm.count("rhs")) {
147 string bfile = vm["rhs"].as<string>();
148
149 ptrdiff_t n, m;
150
151 if (binary) {
152 io::read_dense(bfile, n, m, rhs);
153 }
154 else {
155 std::tie(n, m) = io::mm_reader(bfile)(rhs);
156 }
157
158 precondition(n == rows && m == 1, "The RHS vector has wrong size");
159 }
160 else {
161 rhs.resize(rows, 1.0);
162 }
163
164 if (vm.count("defvec")) {
165 string nfile = vm["defvec"].as<string>();
166 std::vector<double> N;
167
168 ptrdiff_t m;
169
170 if (binary) {
171 io::read_dense(nfile, m, nv, N);
172 }
173 else {
174 std::tie(m, nv) = io::mm_reader(nfile)(N);
175 }
176
177 precondition(m == rows, "Deflation vectors have wrong size");
178
179 z.resize(N.size());
180 for (ptrdiff_t i = 0; i < rows; ++i)
181 for (ptrdiff_t j = 0; j < nv; ++j)
182 z[i + j * rows] = N[i * nv + j];
183 }
184 else if (vm.count("coords")) {
185 string cfile = vm["coords"].as<string>();
186 std::vector<double> coo;
187
188 ptrdiff_t m, ndim;
189
190 if (binary) {
191 io::read_dense(cfile, m, ndim, coo);
192 }
193 else {
194 std::tie(m, ndim) = io::mm_reader(cfile)(coo);
195 }
196
197 precondition(m * ndim == rows && (ndim == 2 || ndim == 3), "Coordinate matrix has wrong size");
198
199 nv = Alina::rigid_body_modes(ndim, coo, z, /*transpose = */ true);
200 }
201
202 prm.put("nvec", nv);
203 prm.put("vec", z.data());
204 }
205
206 std::vector<double> x(rows, 0);
207
208 if (vm["single-level"].as<bool>())
209 prm.put("precond.class", "relaxation");
210
211 typedef Alina::BuiltinBackend<double> Backend;
214 Solver;
215
216 auto A = std::tie(rows, ptr, col, val);
217
218 prof.tic("setup");
219 Solver solve(context, A, prm);
220 prof.toc("setup");
221
222 prof.tic("solve");
223 Alina::SolverResult result = solve(rhs, x);
224 prof.toc("solve");
225
226 if (vm.count("output")) {
227 auto t = prof.scoped_tic("write");
228 Alina::IO::mm_write(vm["output"].as<string>(), x.data(), x.size());
229 }
230
231 std::vector<double> r(rows);
232 Alina::backend::residual(rhs, A, x, r);
233
234 std::cout << "Iterations: " << result.nbIteration() << std::endl
235 << "Error: " << result.residual() << std::endl
236 << "True error: " << sqrt(Alina::backend::inner_product(r, r)) / sqrt(Alina::backend::inner_product(rhs, rhs))
237 << prof << std::endl;
238}
Iterative preconditioned solver with deflation.
Class to store parameters as a hierarchical key/value tree.
Definition AlinaUtils.h:113
Result of a solution.
Definition AlinaUtils.h:56
Fluent command-line parser builder.
Describes a set of command-line options.
Describes positional (non-option) arguments.
Stores parsed option values.
apfloat sqrt(apfloat v)
Square root of v.
Definition MathApfloat.h:69
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Runtime-configurable wrappers around iterative solvers.