Arcane  4.2.3.0
Developer documentation
Loading...
Searching...
No Matches
TestSolverCommon.h
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 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#ifndef TESTS_TEST_SOLVER_HPP
20#define TESTS_TEST_SOLVER_HPP
21
22#include "arccore/alina/AMG.h"
23#include "arccore/alina/SolverRuntime.h"
24#include "arccore/alina/CoarseningRuntime.h"
25#include "arccore/alina/RelaxationRuntime.h"
26#include "arccore/alina/Relaxation.h"
27#include "arccore/alina/PreconditionedSolver.h"
28#include "arccore/alina/Adapters.h"
29#include "arccore/alina/Profiler.h"
30
31#include "arccore/base/PlatformUtils.h"
32
33#include "SampleProblemCommon.h"
34
35using namespace Arcane;
36
37namespace
38{
40}
41
42//---------------------------------------------------------------------------
43
44template <class Backend, class Matrix>
45void test_solver(const Alina::AlinaContext& context,
46 const Matrix& A,
47 std::shared_ptr<typename Backend::vector> const& f,
48 std::shared_ptr<typename Backend::vector>& x,
49 Alina::eSolverType solver,
50 Alina::eRelaxationType relaxation,
51 Alina::eCoarserningType coarsening,
52 typename Backend::params const& bprm,
53 bool test_null_space = false)
54{
55 using namespace Arcane::Alina;
56
57 PropertyTree prm;
58 prm.put("precond.coarse_enough", 500);
59 prm.put("precond.coarsening.type", coarsening);
60 prm.put("precond.relax.type", relaxation);
61 prm.put("solver.type", solver);
62
63 typedef typename Backend::value_type value_type;
64 std::vector<double> null;
65
66 if (test_null_space && Alina::math::static_rows<value_type>::value == 1) {
67 Int64 n = Alina::backend::nbRow(*A);
68 null.resize(n, 1.0);
69
70 prm.put("precond.coarsening.nullspace.cols", 1);
71 prm.put("precond.coarsening.nullspace.rows", n);
72 prm.put("precond.coarsening.nullspace.B", &null[0]);
73 }
76 double t0 = Platform::getRealTime();
77 SolverType solve(context, A, prm, bprm);
78 double t1 = Platform::getRealTime();
79
80 std::cout << solve.precond() << std::endl;
81
82 Alina::backend::clear(*x);
83
84 double t2 = Platform::getRealTime();
85 Alina::SolverResult r = solve(*f, *x);
86 double t3 = Platform::getRealTime();
87
88 std::cout << "SOLVE: "
89 << std::setw(10) << solver
90 << std::setw(15) << relaxation
91 << std::setw(22) << coarsening
92 << " Iterations: " << std::setw(5) << r.nbIteration()
93 << " Error: " << std::setw(15) << r.residual()
94 << " Time0: " << std::setw(12) << (t1-t0)
95 << " Time1: " << std::setw(12) << (t3-t2) << "\n"
96 << std::endl;
97
98 ASSERT_NEAR(r.residual(), 0.0, 1e-4);
99}
100
101//---------------------------------------------------------------------------
102template <class Backend, class Matrix>
103void test_rap(const Alina::AlinaContext& context,
104 const Matrix& A,
105 std::shared_ptr<typename Backend::vector> const& f,
106 std::shared_ptr<typename Backend::vector>& x,
107 Alina::eSolverType solver,
108 Alina::eRelaxationType relaxation,
109 typename Backend::params const& bprm)
110{
112 prm.put("precond.type", relaxation);
113 prm.put("solver.type", solver);
114
117 solve(context, A, prm, bprm);
118
119 std::cout << "Using " << relaxation << " as preconditioner" << std::endl;
120
121 Alina::backend::clear(*x);
122
123 Alina::SolverResult r = solve(*f, *x);
124
125 std::cout << "Iterations: " << r.nbIteration() << std::endl
126 << "Error: " << r.residual() << std::endl;
127
128 ASSERT_NEAR(r.residual(), 0.0, 1e-4);
129}
130
131template <class Backend, class value_type, class col_type, class ptr_type, class rhs_type>
132void test_problem(const Alina::AlinaContext& context,
133 bool do_all_relaxation,
134 size_t n,
135 std::vector<ptr_type> ptr,
136 std::vector<col_type> col,
137 std::vector<value_type> val,
138 std::vector<rhs_type> rhs,
139 typename Backend::params const& bprm)
140{
141 Alina::eCoarserningType coarsening[] = {
142 Alina::eCoarserningType::aggregation,
143 Alina::eCoarserningType::smoothed_aggregation,
144 Alina::eCoarserningType::smoothed_aggr_emin,
145 Alina::eCoarserningType::ruge_stuben
146 };
147
148 Alina::eRelaxationType relaxation[] = {
149 Alina::eRelaxationType::spai0,
150 Alina::eRelaxationType::spai1,
151 Alina::eRelaxationType::damped_jacobi,
152 Alina::eRelaxationType::gauss_seidel,
153 Alina::eRelaxationType::ilu0,
154 Alina::eRelaxationType::iluk,
155 Alina::eRelaxationType::ilup,
156 Alina::eRelaxationType::ilut,
157 Alina::eRelaxationType::chebyshev
158 };
159
160 Alina::eSolverType solver[] = {
161 Alina::eSolverType::cg,
162 Alina::eSolverType::bicgstab,
163 Alina::eSolverType::bicgstabl,
164 Alina::eSolverType::gmres,
165 Alina::eSolverType::lgmres,
166 Alina::eSolverType::fgmres,
167 Alina::eSolverType::idrs
168 };
169
170 typename Backend::params prm;
171
172 auto y = Backend::copy_vector(rhs, prm);
173 auto x = Backend::create_vector(n, prm);
174
175 // Test solvers
176 for (Alina::eSolverType s : solver) {
177 std::cout << "Solver: " << s << std::endl;
178 try {
179 test_solver<Backend>(context, Alina::adapter::zero_copy_direct(n, ptr.data(), col.data(), val.data()),
180 y, x, s, relaxation[0], coarsening[0], bprm);
181 }
182 catch (const std::logic_error&) {
183 }
184 }
185
186 // Test smoothers
187 for (Alina::eRelaxationType r : relaxation) {
188 std::cout << "Relaxation: " << r << std::endl;
189 try {
190 test_solver<Backend>(context, Alina::adapter::zero_copy_direct(n, ptr.data(), col.data(), val.data()),
191 y, x, solver[0], r, coarsening[0], bprm);
192 }
193 catch (const std::logic_error&) {
194 }
195
196 try {
197 std::cout << "Relaxation as preconditioner: " << r << std::endl;
198
199 test_rap<Backend>(context, Alina::adapter::zero_copy_direct(n, ptr.data(), col.data(), val.data()),
200 y, x, solver[0], r, bprm);
201 }
202 catch (const std::logic_error&) {
203 }
204 }
205
206 // Test coarsening with several relaxation
207 for (Alina::eCoarserningType c : coarsening) {
208 std::cout << "Coarsening: " << c << std::endl;
209
210 for (Alina::eRelaxationType r : relaxation) {
211 std::cout << "Relaxation: " << r << std::endl;
212 try {
213 test_solver<Backend>(context, Alina::adapter::zero_copy_direct(n, ptr.data(), col.data(), val.data()),
214 y, x, solver[0], r, c, bprm);
215 }
216 catch (const std::logic_error&) {
217 }
218
219 switch (c) {
220 case Alina::eCoarserningType::aggregation:
221 case Alina::eCoarserningType::smoothed_aggregation:
222 case Alina::eCoarserningType::smoothed_aggr_emin:
223 test_solver<Backend>(context, Alina::adapter::zero_copy_direct(n, ptr.data(), col.data(), val.data()),
224 y, x, solver[0], r, c, bprm, /*test_null_space*/ true);
225 break;
226 default:
227 break;
228 }
229 // If we do not want all relaxation, break after the first one.
230 if (!do_all_relaxation)
231 break;
232 }
233 }
234}
235
236// Return the default size for the problem for function 'test_backend'
237extern "C++"
238Int32 getTestBackendDefaultProblemSize();
239
240template <class Backend>
241void test_backend(const Alina::AlinaContext& context, bool do_all_relaxation = false, Int32 problem_size = 0,
242 typename Backend::params const& bprm = typename Backend::params())
243{
244 typedef typename Backend::value_type value_type;
245 typedef typename Backend::col_type col_type;
246 typedef typename Backend::ptr_type ptr_type;
247 typedef typename Alina::math::rhs_of<value_type>::type rhs_type;
248
249 if (problem_size <= 0)
250 problem_size = getTestBackendDefaultProblemSize();
251
252 // Poisson 3D
253 {
254 std::vector<ptr_type> ptr;
255 std::vector<col_type> col;
256 std::vector<value_type> val;
257 std::vector<rhs_type> rhs;
258
259 size_t n = Alina::PoissonProblemGenerator::createSequentialMatrix(problem_size, val, col, ptr, rhs);
260
261 test_problem<Backend>(context, do_all_relaxation, n, ptr, col, val, rhs, bprm);
262 }
263
264 // Trivial problem
265 {
266 std::vector<ptr_type> ptr;
267 std::vector<col_type> col;
268 std::vector<value_type> val;
269 std::vector<rhs_type> rhs;
270
271 val.push_back(Alina::math::identity<value_type>());
272 val.push_back(Alina::math::identity<value_type>());
273 col.push_back(0);
274 col.push_back(1);
275 ptr.push_back(0);
276 ptr.push_back(1);
277 ptr.push_back(2);
278 rhs.push_back(Alina::math::constant<rhs_type>(1.0));
279 rhs.push_back(Alina::math::zero<rhs_type>());
280
281 size_t n = rhs.size();
282
283 test_problem<Backend>(context, do_all_relaxation, n, ptr, col, val, rhs, bprm);
284 }
285}
286
287/*---------------------------------------------------------------------------*/
288/*---------------------------------------------------------------------------*/
289
290#if defined(ARCCORE_HAS_ACCELERATOR_THREAD)
291#define ARCCORE_ALINA_TEST_DO_TEST_TASK(name1, name2, func) \
292 TEST(name1, name2##_task4) \
293 { \
294 func(false, 4); \
295 }
296#else
297#define ARCCORE_ALINA_TEST_DO_TEST_TASK(name1, name2, func)
298#endif
299
300#define ARCCORE_ALINA_TEST_DO_TEST_SEQUENTIAL(name1, name2, func) \
301 TEST(name1, name2) \
302 { \
303 func(false, 0); \
304 }
305
307#define ARCCORE_ALINA_TEST_DO_TEST_ACCELERATOR(name1, name2, func) \
308 ARCCORE_ALINA_TEST_DO_TEST_TASK(name1, name2, func); \
309 ARCCORE_ALINA_TEST_DO_TEST_SEQUENTIAL(name1, name2, func);
310
311/*---------------------------------------------------------------------------*/
312/*---------------------------------------------------------------------------*/
313
314#endif
Convenience class that bundles together a preconditioner and an iterative solver.
Profiler class.
Definition Profiler.h:50
Class to store parameters as a hierarchical key/value tree.
Definition AlinaUtils.h:113
Result of a solution.
Definition AlinaUtils.h:56
Matrix class, to be used by user.
Real getRealTime()
Real time used in seconds.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Runtime-configurable wrappers around iterative solvers.
Number of rows for statically sized matrix types.