Arcane  4.2.3.0
Developer documentation
Loading...
Searching...
No Matches
AlinaLib.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/* AlinaLib.cc (C) 2000-2026 */
9/* */
10/* Public API for Alina. . */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "AlinaUtils.h"
15#include "arccore/alina/RelaxationRuntime.h"
16#include "arccore/alina/CoarseningRuntime.h"
17#include "arccore/alina/SolverRuntime.h"
18#include "arccore/alina/PreconditionedSolver.h"
19#include "arccore/alina/PreconditionerRuntime.h"
20#include "arccore/alina/DistributedSolverRuntime.h"
21#include "arccore/alina/DistributedPreconditioner.h"
22#include "arccore/alina/BuiltinBackend.h"
23#include "arccore/alina/AlinaLib.h"
24#include "arccore/alina/DistributedPreconditionedSolver.h"
25
26#include "arccore/message_passing/IMessagePassingMng.h"
27
28#include "arccore/trace/ITraceMng.h"
29
30#include "arccore/base/NotSupportedException.h"
31#include "arccore/base/NotImplementedException.h"
32
33#include <iostream>
34#include <memory>
35
36/*---------------------------------------------------------------------------*/
37/*---------------------------------------------------------------------------*/
38
39namespace Arcane::AlinaLib
40{
41using Arcane::IMessagePassingMng;
42
43/*---------------------------------------------------------------------------*/
44/*---------------------------------------------------------------------------*/
45
46//using Backend = Alina::BuiltinBackend<double>;
47using Backend = Alina::BuiltinBackend<double, Int32, Int32>;
48using PreconditionerType = Alina::PreconditionerRuntime<Backend>;
49using SequentialSolverType = Alina::PreconditionedSolver<PreconditionerType, Alina::SolverRuntime<Backend>>;
50
51//---------------------------------------------------------------------------
52
53using DistributedSolverType = Alina::DistributedPreconditionedSolver<Alina::DistributedPreconditioner<Backend>,
54 Alina::DistributedSolverRuntime<Backend>>;
55
56typedef double (*AlinaDefVecFunction)(int vec, ptrdiff_t coo, void* data);
57
58/*---------------------------------------------------------------------------*/
59/*---------------------------------------------------------------------------*/
60
61/*---------------------------------------------------------------------------*/
62/*---------------------------------------------------------------------------*/
63
64namespace
65{
67 _toConvInfo(const Alina::SolverResult& r)
68 {
70 x.iterations = r.nbIteration();
71 x.residual = r.residual();
72 return x;
73 }
74} // namespace
75
76/*---------------------------------------------------------------------------*/
77/*---------------------------------------------------------------------------*/
78
79void AlinaCSRMatrixView::
80dump(std::ostream& o) const
81{
82 const AlinaCSRMatrixView& matrix_view = *this;
83 Int32 nb_row = matrix_view.nbRow();
84 const auto default_precision{ o.precision() };
85 constexpr auto max_precision{ std::numeric_limits<long double>::digits10 + 1 };
86 o << std::setprecision(max_precision);
87 o << "MATRIX nb_row=" << nb_row << "\n";
88 auto rows_index = matrix_view.rowIndexes();
89 auto columns = matrix_view.columns();
90 auto values = matrix_view.values();
91 for (Int32 i = 0; i < nb_row; ++i) {
92 Int32 begin = rows_index[i];
93 Int32 end = rows_index[i + 1];
94 o << "ROW I=" << i << " index0=" << begin << " index1=" << end << "\n";
95 for (Int32 z = begin; z < end; ++z) {
96 o << " C=" << std::setw(8) << columns[z] << " V=" << values[z] << "\n";
97 }
98 }
99 o << std::setprecision(default_precision);
100}
101
102/*---------------------------------------------------------------------------*/
103/*---------------------------------------------------------------------------*/
104
106{
107 public:
108
109 Alina::PropertyTree m_properties;
110};
111
112/*---------------------------------------------------------------------------*/
113/*---------------------------------------------------------------------------*/
114
115AlinaParameters::
116AlinaParameters()
117: m_p(std::make_shared<AlinaParametersImpl>())
118{}
119
120/*---------------------------------------------------------------------------*/
121/*---------------------------------------------------------------------------*/
122
124setInt32(const char* name, Arcane::Int32 value)
125{
126 m_p->m_properties.put(name, value);
127}
128
130setInt64(const char* name, Arcane::Int64 value)
131{
132 m_p->m_properties.put(name, value);
133}
134
136setReal(const char* name, Arcane::Real value)
137{
138 m_p->m_properties.put(name, value);
139}
140
142setString(const char* name, const char* value)
143{
144 m_p->m_properties.put(name, value);
145}
146
148readFromJSON(const char* fname)
149{
150 Alina::PropertyTree& p = m_p->m_properties;
151 p.read_json(fname);
152}
153
154/*---------------------------------------------------------------------------*/
155/*---------------------------------------------------------------------------*/
156
157class AlinaSolverParametersImpl
158{
159 public:
160
161 AlinaSolverParametersImpl(MessagePassing::IMessagePassingMng* mpm, ITraceMng* tm)
162 {
163 if (mpm)
164 m_message_passing_mng = makeRef(mpm);
165 if (!tm)
166 tm = arccoreCreateDefaultTraceMng();
167 m_trace_mng = makeRef(tm);
168 }
169
170 public:
171
172 Alina::PropertyTree m_properties;
173 Ref<ITraceMng> m_trace_mng;
174 Ref<IMessagePassingMng> m_message_passing_mng;
175};
176
177/*---------------------------------------------------------------------------*/
178/*---------------------------------------------------------------------------*/
179
182{
183 m_p = std::make_shared<AlinaSolverParametersImpl>(nullptr,nullptr);
184}
185
186/*---------------------------------------------------------------------------*/
187/*---------------------------------------------------------------------------*/
188
191{
192 m_p = std::make_shared<AlinaSolverParametersImpl>(mpm,tm);
193}
194
195/*---------------------------------------------------------------------------*/
196/*---------------------------------------------------------------------------*/
197
198AlinaSolverParameters::
199~AlinaSolverParameters()
200{
201}
202
203/*---------------------------------------------------------------------------*/
204/*---------------------------------------------------------------------------*/
205
206ITraceMng* AlinaSolverParameters::
207traceMng() const
208{
209 return m_p->m_trace_mng.get();
210}
211
212/*---------------------------------------------------------------------------*/
213/*---------------------------------------------------------------------------*/
214
216setInt32(const char* name, Arcane::Int32 value)
217{
218 m_p->m_properties.put(name, value);
219}
220
222setInt64(const char* name, Arcane::Int64 value)
223{
224 m_p->m_properties.put(name, value);
225}
226
228setReal(const char* name, Arcane::Real value)
229{
230 m_p->m_properties.put(name, value);
231}
232
234setString(const char* name, const char* value)
235{
236 m_p->m_properties.put(name, value);
237}
238
240readFromJSON(const char* fname)
241{
242 Alina::PropertyTree& p = m_p->m_properties;
243 p.read_json(fname);
244}
245
246/*---------------------------------------------------------------------------*/
247/*---------------------------------------------------------------------------*/
248
249void AlinaSolverParameters::
250setSolverAbsoluteTolerance(Arcane::Real value)
251{
252 m_p->m_properties.put("solver.abstol", value);
253}
254void AlinaSolverParameters::
255setSolverRelativeTolerance(Arcane::Real value)
256{
257 m_p->m_properties.put("solver.tol", value);
258}
259void AlinaSolverParameters::
260setSolverMaxIteration(Arcane::Int32 value)
261{
262 m_p->m_properties.put("solver.maxiter", value);
263}
264void AlinaSolverParameters::
265setSolverVerbosity(Arcane::Int32 value)
266{
267 m_p->m_properties.put("solver.verbose", value);
268}
269
270/*---------------------------------------------------------------------------*/
271/*---------------------------------------------------------------------------*/
272
273void AlinaSolverParameters::
274setSolverPreconditioner(eAlinaPreconditionerType v)
275{
276 auto& x = m_p->m_properties;
277 switch (v) {
278 case eAlinaPreconditionerType::AMG:
279 x.put("precond.class", "amg");
280 break;
281 case eAlinaPreconditionerType::Diagonal:
282 x.put("precond.class", "relaxation");
283 x.put("precond.relax.type", "spai0");
284 break;
285 }
286}
287
288/*---------------------------------------------------------------------------*/
289/*---------------------------------------------------------------------------*/
290
291void AlinaSolverParameters::
292setSolverType(eAlinaSolverType v)
293{
294 const char* name = nullptr;
295 switch (v) {
296 case eAlinaSolverType::ConjugateGradient:
297 name = "cg";
298 break;
299 case eAlinaSolverType::BiCGStab:
300 name = "bicgstab";
301 break;
302 case eAlinaSolverType::GMRES:
303 name = "gmres";
304 break;
305 }
306 if (!name)
307 ARCCORE_THROW(NotSupportedException, "Invalid value '{0}' for solver type", static_cast<int>(v));
308 m_p->m_properties.put("solver.type", name);
309}
310
311/*---------------------------------------------------------------------------*/
312/*---------------------------------------------------------------------------*/
313
315checkSizes() const
316{
317 Int32 nb_row = nbRow();
318 Int32 n1 = m_row_indexes.size();
319 if (n1 != (nb_row + 1))
320 ARCCORE_FATAL("Bad size '{0}' for rowIndexes() (expected value = {1})", n1, nb_row + 1);
321 Int32 nb_value = m_row_indexes[nb_row];
322 Int32 n2 = m_columns.size();
323 Int32 n3 = m_values.size();
324 if (n2 != nb_value)
325 ARCCORE_FATAL("Bad size '{0}' for columns() (expected value = {1})", n2, nb_value);
326 if (n3 != nb_value)
327 ARCCORE_FATAL("Bad size '{0}' for values() (expected value = {1})", n3, nb_value);
328}
329
330/*---------------------------------------------------------------------------*/
331/*---------------------------------------------------------------------------*/
332
333/*---------------------------------------------------------------------------*/
334/*---------------------------------------------------------------------------*/
335
336class AlinaPreconditionerImpl
337{
338 public:
339
340 explicit AlinaPreconditionerImpl(PreconditionerType* preconditioner)
341 : m_preconditioner(preconditioner)
342 {}
343 ~AlinaPreconditionerImpl()
344 {
345 delete m_preconditioner;
346 }
347
348 PreconditionerType* m_preconditioner = nullptr;
349};
350
351/*---------------------------------------------------------------------------*/
352/*---------------------------------------------------------------------------*/
353
354AlinaPreconditioner::
355AlinaPreconditioner(int n,
356 const int* ptr,
357 const int* col,
358 const double* val,
359 const AlinaParameters* prm)
360{
361 SmallSpan<const int> ptr_range(ptr, n + 1);
362 SmallSpan<const int> col_range(col, ptr[n]);
363 SmallSpan<const double> val_range(val, ptr[n]);
364
365 auto A = std::make_tuple(n, ptr_range, col_range, val_range);
366
367 PreconditionerType* amg = nullptr;
368 Alina::AlinaContext context;
369 if (prm)
370 amg = new PreconditionerType(context, A, prm->m_p->m_properties);
371 else
372 amg = new PreconditionerType(context, A);
373 m_p = std::make_shared<AlinaPreconditionerImpl>(amg);
374}
375
376/*---------------------------------------------------------------------------*/
377/*---------------------------------------------------------------------------*/
378
380apply(const double* rhs, double* x)
381{
382 PreconditionerType* amg = m_p->m_preconditioner;
383
384 size_t n = Alina::backend::nbRow(amg->system_matrix());
385
386 SmallSpan<double> x_range(x, n);
387 SmallSpan<const double> rhs_range(rhs, n);
388
389 amg->apply(rhs_range, x_range);
390}
391
392/*---------------------------------------------------------------------------*/
393/*---------------------------------------------------------------------------*/
394
396report()
397{
398 std::cout << *(m_p->m_preconditioner) << std::endl;
399}
400
401/*---------------------------------------------------------------------------*/
402/*---------------------------------------------------------------------------*/
403
405{
406 public:
407
408 virtual ~IAlinaSolverImpl() = default;
409
410 public:
411
414
416 solveMatrix(const AlinaCSRMatrixView& matrix_view,
418 SmallSpan<double> x) = 0;
419
420 virtual void report(std::ostream& o) = 0;
421};
422
423/*---------------------------------------------------------------------------*/
424/*---------------------------------------------------------------------------*/
428class AlinaSequentialSolverImpl
429: public IAlinaSolverImpl
430{
431 public:
432
433 explicit AlinaSequentialSolverImpl(const AlinaCSRMatrixView& matrix_view,
434 const AlinaSolverParameters& prm)
435 {
436 matrix_view.checkSizes();
437
438 auto A = std::make_tuple(matrix_view.nbRow(), matrix_view.rowIndexes(),
439 matrix_view.columns(), matrix_view.values());
440
441 Alina::AlinaContext context;
442 m_solver = new SequentialSolverType(context, A, prm.m_p->m_properties);
443 ITraceMng* tm = prm.traceMng();
444 tm->info() << "Printing solver infos\n"
445 << (*m_solver) << "\n"
446 << "PARAMS: " << prm.m_p->m_properties;
448 m_solver->prm.get(ptree);
449 tm->info() << "SOLVER_PARAMS: " << ptree;
450 }
451 ~AlinaSequentialSolverImpl() override
452 {
453 delete m_solver;
454 }
455
457 {
458 Alina::SolverResult r = (*m_solver)(rhs, x);
459 return _toConvInfo(r);
460 }
461 AlinaConvergenceInfo solveMatrix(const AlinaCSRMatrixView& matrix_view,
463 SmallSpan<double> x) override
464 {
465 SequentialSolverType* slv = m_solver;
466
467 Int32 n = slv->size();
468 matrix_view.checkSizes();
469
470 if (n != matrix_view.nbRow())
471 ARCCORE_FATAL("Bad number of rows v={0} expected={1}", matrix_view.nbRow(), n);
472
473 auto A = std::make_tuple(matrix_view.nbRow(), matrix_view.rowIndexes(),
474 matrix_view.columns(), matrix_view.values());
475
476 Alina::SolverResult r = (*slv)(A, rhs, x);
477
478 return _toConvInfo(r);
479 }
480 void report(std::ostream& o) override
481 {
482 o << m_solver->precond() << "\n";
483 }
484
485 public:
486
487 SequentialSolverType* m_solver = nullptr;
488};
489
490/*---------------------------------------------------------------------------*/
491/*---------------------------------------------------------------------------*/
495class AlinaDistributedSolverImpl
496: public IAlinaSolverImpl
497{
498 public:
499
500 explicit AlinaDistributedSolverImpl(const AlinaCSRMatrixView& matrix_view,
501 const AlinaSolverParameters& params)
502 {
503 IMessagePassingMng* mpm = params.m_p->m_message_passing_mng.get();
504 matrix_view.checkSizes();
505
506 Alina::PropertyTree& prm = params.m_p->m_properties;
507
508 auto A = std::make_tuple(matrix_view.nbRow(), matrix_view.rowIndexes(),
509 matrix_view.columns(), matrix_view.values());
510
511 Alina::AlinaCommunicator mpi_comm(mpm);
512 Alina::AlinaContext context;
513 m_solver = new DistributedSolverType(context, mpi_comm, A, prm);
514
515 ITraceMng* tm = params.traceMng();
516 tm->info() << "Printing solver infos\n"
517 << (*m_solver) << "\n"
518 << "PARAMS: " << params.m_p->m_properties;
520 m_solver->prm.get(ptree);
521 tm->info() << "SOLVER_PARAMS: " << ptree;
522 }
523 ~AlinaDistributedSolverImpl()
524 {
525 delete m_solver;
526 }
527
528 public:
529
531 {
533
534 Alina::SolverResult r = (*m_solver)(rhs, x);
535
536 return _toConvInfo(r);
537 }
538
539 AlinaConvergenceInfo solveMatrix([[maybe_unused]] const AlinaCSRMatrixView& matrix_view,
540 [[maybe_unused]] SmallSpan<const double> rhs,
541 [[maybe_unused]] SmallSpan<double> x) override
542 {
543 ARCCORE_THROW(NotImplementedException, "Solve with different matrix");
544 }
545 void report([[maybe_unused]] std::ostream& o) override
546 {
547 }
548
549 public:
550
551 DistributedSolverType* m_solver = nullptr;
552};
553
554/*---------------------------------------------------------------------------*/
555/*---------------------------------------------------------------------------*/
556
557/*---------------------------------------------------------------------------*/
558/*---------------------------------------------------------------------------*/
559
561AlinaSolver(const AlinaSolverParameters& parameters, const AlinaCSRMatrixView& matrix_view)
562{
563 IMessagePassingMng* mpm = parameters.m_p->m_message_passing_mng.get();
564 if (mpm) {
565 m_p = std::make_shared<AlinaDistributedSolverImpl>(matrix_view, parameters);
566 }
567 else
568 m_p = std::make_shared<AlinaSequentialSolverImpl>(matrix_view, parameters);
569}
570
571/*---------------------------------------------------------------------------*/
572/*---------------------------------------------------------------------------*/
573
575report()
576{
577 m_p->report(std::cout);
578}
579
580/*---------------------------------------------------------------------------*/
581/*---------------------------------------------------------------------------*/
582
585{
586 return m_p->solve(rhs, x);
587}
588
589/*---------------------------------------------------------------------------*/
590/*---------------------------------------------------------------------------*/
591
593solveMatrix(const AlinaCSRMatrixView& matrix_view,
596{
597 return m_p->solveMatrix(matrix_view, rhs, x);
598}
599
600/*---------------------------------------------------------------------------*/
601/*---------------------------------------------------------------------------*/
602
603} // namespace Arcane::AlinaLib
604
605/*---------------------------------------------------------------------------*/
606/*---------------------------------------------------------------------------*/
#define ARCCORE_FATAL(...)
Macro throwing a FatalErrorException.
#define ARCCORE_THROW(exception_class,...)
Macro to throw an exception with formatting.
CSR Matrix view used in AlinaLib.
Definition AlinaLib.h:192
void checkSizes() const
Check that sizes are valid:
Definition AlinaLib.cc:315
Handle parameters for Alina.
Definition AlinaLib.h:89
void setInt64(const char *name, Int64 value)
Set Int64 parameter in the parameter list.
Definition AlinaLib.cc:130
void setString(const char *name, const char *value)
Set floating point parameter in the parameter list.
Definition AlinaLib.cc:142
void setInt32(const char *name, Int32 value)
Set Int32 parameter in the parameter list.
Definition AlinaLib.cc:124
void readFromJSON(const char *fname)
Read parameters from a JSON file.
Definition AlinaLib.cc:148
void setReal(const char *name, Real value)
Set floating point parameter in the parameter list.
Definition AlinaLib.cc:136
void report()
Printout preconditioner structure.
Definition AlinaLib.cc:396
void apply(const double *rhs, double *x)
Apply AMG preconditioner (x = M^(-1) * rhs).
Definition AlinaLib.cc:380
Handle parameters for solvers.
Definition AlinaLib.h:130
void readFromJSON(const char *fname)
Read parameters from a JSON file.
Definition AlinaLib.cc:240
void setString(const char *name, const char *value)
Set floating point parameter in the parameter list.
Definition AlinaLib.cc:234
void setInt32(const char *name, Int32 value)
Set Int32 parameter in the parameter list.
Definition AlinaLib.cc:216
void setReal(const char *name, Real value)
Set floating point parameter in the parameter list.
Definition AlinaLib.cc:228
void setInt64(const char *name, Int64 value)
Set Int64 parameter in the parameter list.
Definition AlinaLib.cc:222
AlinaSolverParameters()
Create a sequential solver.
Definition AlinaLib.cc:181
AlinaSolver(const AlinaSolverParameters &params, const AlinaCSRMatrixView &matrix_view)
Create a solver.
Definition AlinaLib.cc:561
void report()
Printout solver structure.
Definition AlinaLib.cc:575
AlinaConvergenceInfo solveMatrix(const AlinaCSRMatrixView &matrix_view, SmallSpan< const double > rhs, SmallSpan< double > x)
Solve the problem for the given matrix and the right-hand side.
Definition AlinaLib.cc:593
AlinaConvergenceInfo solve(SmallSpan< const double > rhs, SmallSpan< double > x)
Find solution for the given RHS.
Definition AlinaLib.cc:584
size_t size() const
Returns the size of the system matrix.
Class to store parameters as a hierarchical key/value tree.
Definition AlinaUtils.h:113
Result of a solution.
Definition AlinaUtils.h:56
virtual TraceMessage info()=0
Stream for an information message.
Interface of the message passing manager.
Reference to an instance.
View of an array of elements of type T.
Definition Span.h:803
std::int64_t Int64
Signed integer type of 64 bits.
double Real
Type representing a real number.
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Creates a reference on a pointer.
std::int32_t Int32
Signed integer type of 32 bits.
Convenience wrapper around MPI_Comm.