Arcane  4.2.2.0
Developer documentation
Loading...
Searching...
No Matches
AlinaUtils.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/* AlinaUtils.h (C) 2000-2026 */
9/* */
10/* Various utilities. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13#ifndef ARCCORE_ALINA_ALINAUTILS_H
14#define ARCCORE_ALINA_ALINAUTILS_H
15/*---------------------------------------------------------------------------*/
16/*---------------------------------------------------------------------------*/
17/*
18 * This file is based on the work on AMGCL library (version march 2026)
19 * which can be found at https://github.com/ddemidov/amgcl.
20 *
21 * Copyright (c) 2012-2022 Denis Demidov <dennis.demidov@gmail.com>
22 * SPDX-License-Identifier: MIT
23 */
24/*---------------------------------------------------------------------------*/
25/*---------------------------------------------------------------------------*/
26
27#pragma GCC diagnostic ignored "-Wconversion"
28#pragma GCC diagnostic ignored "-Wsign-compare"
29
30#include "arccore/alina/AlinaGlobal.h"
31
32#include "arccore/base/Ref.h"
33#include "arccore/base/FatalErrorException.h"
34#include "arccore/base/ForLoopRunInfo.h"
35#include "arccore/concurrency/ParallelFor.h"
36
37#include <set>
38#include <complex>
39#include <cstddef>
40#include <tuple>
41
42/*---------------------------------------------------------------------------*/
43/*---------------------------------------------------------------------------*/
44
45namespace Arcane::Alina
46{
47
48/*---------------------------------------------------------------------------*/
49/*---------------------------------------------------------------------------*/
50
52class ARCCORE_ALINA_EXPORT SolverResult
53{
54 public:
55
56 SolverResult() = default;
57 SolverResult(const std::tuple<size_t, double>& v)
58 : m_nb_iteration(get<0>(v))
59 , m_residual(get<1>(v))
60 {}
61 SolverResult(const std::tuple<size_t, float>& v)
62 : m_nb_iteration(get<0>(v))
63 , m_residual(get<1>(v))
64 {}
65 SolverResult(size_t nb_iteration, double residual)
66 : m_nb_iteration(nb_iteration)
67 , m_residual(residual)
68 {}
69
70 operator std::tuple<size_t, double>() const { return { m_nb_iteration, m_residual }; }
71
72 public:
73
74 constexpr Int32 nbIteration() const { return static_cast<Int32>(m_nb_iteration); }
75 constexpr double residual() const { return m_residual; }
76
77 private:
78
79 size_t m_nb_iteration = 0;
80 double m_residual = 0.0;
81};
82
83/*---------------------------------------------------------------------------*/
84/*---------------------------------------------------------------------------*/
85
86namespace detail
87{
88 class PropertyWrapper;
90 class ARCCORE_ALINA_EXPORT empty_params
91 {
92 public:
93
94 empty_params() {}
95
96 empty_params(const PropertyTree& ap);
97 void get(PropertyTree&, const std::string&) const {}
98 };
99
100} // namespace detail
101
102/*---------------------------------------------------------------------------*/
103/*---------------------------------------------------------------------------*/
111class ARCCORE_ALINA_EXPORT PropertyTree
112{
113 public:
114
117
118 public:
119
120 PropertyTree();
121 PropertyTree(const PropertyTree& rhs);
122 ~PropertyTree();
123
124 public:
125
126 Int32 get(const char* param_type, Int32 default_value) const;
127 Int64 get(const char* param_type, Int64 default_value) const;
128 size_t get(const char* param_type, size_t default_value) const
129 {
130 return get(param_type, static_cast<Int64>(default_value));
131 }
132 double get(const char* param_type, double default_value) const;
133 double* get(const char* param_type, double* default_value) const;
134 void* get(const char* param_type, void* default_value) const;
135 std::string get(const char* param_type, const std::string& default_value) const;
136
137 template <typename DataType> DataType
138 get(const char* param_type, const DataType& default_value) const
139 requires(std::is_enum_v<DataType>)
140 {
141 std::ostringstream default_ostr;
142 default_ostr << default_value;
143 std::string s = get(param_type, default_ostr.str());
144 std::istringstream istr(s);
145 DataType enum_value;
146 istr >> enum_value;
147 if (istr.bad())
148 ARCCORE_FATAL("Can not convert '{0}' to enumeration", s);
149 return enum_value;
150 }
151
152 void put(const std::string& path, Int32 value);
153 void put(const std::string& path, Int64 value);
154 void put(const std::string& path, size_t value)
155 {
156 put(path, static_cast<Int64>(value));
157 }
158
159 void put(const std::string& path, double value);
160 void put(const std::string& path, const std::string& value);
161 void put(const std::string& path, double* value);
162 void put(const std::string& path, void* value);
163
164 template <typename DataType> void
165 put(const std::string& path, const DataType& value)
166 requires(std::is_enum_v<DataType>)
167 {
168 // Convert enum to string.
169 std::ostringstream ostr;
170 ostr << value;
171 put(path, ostr.str());
172 }
173
174 // Put parameter in form "key=value" into the property tree
175 void putKeyValue(const std::string& param);
176
177 PropertyTree get_child_empty(const std::string& path) const;
178 bool erase(const char* name);
179 size_t count(const char* name) const;
180
181 // NOTE: Does not seems to be used.
182 void _addChild(const std::string& path, const char* name, const PropertyTree& obj);
183
184 public:
185
186 void read_json(const std::string& filename);
187
188 public:
189
190 void check_params(const std::set<std::string>& names) const;
191 void check_params(const std::set<std::string>& names, const std::set<std::string>& opt_names) const;
192 ARCCORE_ALINA_EXPORT friend std::ostream& operator<<(std::ostream& o, const PropertyTree& obj);
193
194 private:
195
196 void* m_property_tree = nullptr;
197 bool m_is_own = false;
198};
199
200} // namespace Arcane::Alina
201
202/*---------------------------------------------------------------------------*/
203/*---------------------------------------------------------------------------*/
204
205#include "arccore/alina/ScopedStreamModifier.h"
206
219#ifdef ARCCORE_ALINA_PROFILING
220#if !defined(ARCCORE_ALINA_TIC) || !defined(ARCCORE_ALINA_TOC)
221#include "arccore/alina/Profiler.h"
222#define ARCCORE_ALINA_TIC(name) ::Arcane::Alina::Profiler::globalTic(name);
223#define ARCCORE_ALINA_TOC(name) ::Arcane::Alina::Profiler::globalToc(name);
224#endif
225#endif
226
227#ifndef ARCCORE_ALINA_TIC
228#define ARCCORE_ALINA_TIC(name)
229#endif
230#ifndef ARCCORE_ALINA_TOC
231#define ARCCORE_ALINA_TOC(name)
232#endif
233
234#define ARCCORE_ALINA_DEBUG_SHOW(x) \
235 std::cout << std::setw(20) << #x << ": " \
236 << std::setw(15) << std::setprecision(8) << std::scientific \
237 << (x) << std::endl
238
239/*---------------------------------------------------------------------------*/
240/*---------------------------------------------------------------------------*/
241
242namespace Arcane::Alina
243{
244
245/*---------------------------------------------------------------------------*/
246/*---------------------------------------------------------------------------*/
247
249template <class Condition, class Message>
250void precondition(const Condition& condition, const Message& message)
251{
252#ifdef _MSC_VER
253#pragma warning(push)
254#pragma warning(disable : 4800)
255#endif
256 if (!condition)
257 throw std::runtime_error(message);
258#ifdef _MSC_VER
259#pragma warning(pop)
260#endif
261}
262
263/*---------------------------------------------------------------------------*/
264/*---------------------------------------------------------------------------*/
265
266#define ARCCORE_ALINA_PARAMS_IMPORT_VALUE(p, name) \
267 name(p.get(#name, params().name))
268
269#define ARCCORE_ALINA_PARAMS_IMPORT_CHILD(p, name) \
270 name(p.get_child_empty(#name))
271
272#define ARCCORE_ALINA_PARAMS_EXPORT_VALUE(p, path, name) \
273 p.put(std::string(path) + #name, name)
274
275namespace detail
276{
277
278 template <typename T>
279 inline void params_export_child(PropertyTree& ap,
280 const std::string& path,
281 const char* name, const T& obj)
282 {
283 obj.get(ap, std::string(path) + name + ".");
284 }
285
286 // NOTE GG: This method is not used in the tests.
287 template <>
288 inline void params_export_child(PropertyTree& ap,
289 const std::string& path, const char* name,
290 const PropertyTree& obj)
291 {
292 ap._addChild(path, name, obj);
293 }
294
295} // namespace detail
296
297#define ARCCORE_ALINA_PARAMS_EXPORT_CHILD(p, path, name) \
298 ::Arcane::Alina::detail::params_export_child(p, path, #name, name)
299
300/*---------------------------------------------------------------------------*/
301/*---------------------------------------------------------------------------*/
302
303// Missing parameter action
304#ifndef ARCCORE_ALINA_PARAM_MISSING
305#define ARCCORE_ALINA_PARAM_MISSING(name) (void)0
306#endif
307
308/*---------------------------------------------------------------------------*/
309/*---------------------------------------------------------------------------*/
310
311// N-dimensional dense matrix
312template <class T, int N>
313class multi_array
314{
315 static_assert(N > 0, "Wrong number of dimensions");
316
317 public:
318
319 template <class... I>
320 multi_array(I... n)
321 {
322 static_assert(sizeof...(I) == N, "Wrong number of dimensions");
323 buf.resize(init(n...));
324 }
325
326 size_t size() const
327 {
328 return buf.size();
329 }
330
331 int stride(int i) const
332 {
333 return strides[i];
334 }
335
336 template <class... I>
337 T operator()(I... i) const
338 {
339 static_assert(sizeof...(I) == N, "Wrong number of indices");
340 return buf[index(i...)];
341 }
342
343 template <class... I>
344 T& operator()(I... i)
345 {
346 static_assert(sizeof...(I) == N, "Wrong number of indices");
347 return buf[index(i...)];
348 }
349
350 const T* data() const
351 {
352 return buf.data();
353 }
354
355 T* data()
356 {
357 return buf.data();
358 }
359
360 private:
361
362 std::array<int, N> strides;
363 std::vector<T> buf;
364
365 template <class... I>
366 int index(int i, I... tail) const
367 {
368 return strides[N - sizeof...(I) - 1] * i + index(tail...);
369 }
370
371 int index(int i) const
372 {
373 return strides[N - 1] * i;
374 }
375
376 template <class... I>
377 int init(int i, I... tail)
378 {
379 int size = init(tail...);
380 strides[N - sizeof...(I) - 1] = size;
381 return i * size;
382 }
383
384 int init(int i)
385 {
386 strides[N - 1] = 1;
387 return i;
388 }
389};
390
391template <class T>
392class circular_buffer
393{
394 public:
395
396 circular_buffer(size_t n)
397 : start(0)
398 {
399 buf.reserve(n);
400 }
401
402 size_t size() const
403 {
404 return buf.size();
405 }
406
407 void push_back(const T& v)
408 {
409 if (buf.size() < buf.capacity()) {
410 buf.push_back(v);
411 }
412 else {
413 buf[start] = v;
414 start = (start + 1) % buf.capacity();
415 }
416 }
417
418 const T& operator[](size_t i) const
419 {
420 return buf[(start + i) % buf.capacity()];
421 }
422
423 T& operator[](size_t i)
424 {
425 return buf[(start + i) % buf.capacity()];
426 }
427
428 void clear()
429 {
430 buf.clear();
431 start = 0;
432 }
433
434 private:
435
436 size_t start;
437 std::vector<T> buf;
438};
439
440namespace detail
441{
442
443 template <class T>
444 T eps(size_t n)
445 {
446 return 2 * std::numeric_limits<T>::epsilon() * n;
447 }
448
449} // namespace detail
450
451template <class T> struct is_complex : std::false_type
452{};
453template <class T> struct is_complex<std::complex<T>> : std::true_type
454{};
455
456inline std::string human_readable_memory(size_t bytes)
457{
458 static const char* suffix[] = { "B", "K", "M", "G", "T" };
459
460 int i = 0;
461 double m = static_cast<double>(bytes);
462 for (; i < 4 && m >= 1024.0; ++i, m /= 1024.0)
463 ;
464
465 std::ostringstream s;
466 s << std::fixed << std::setprecision(2) << m << " " << suffix[i];
467 return s.str();
468}
469
470namespace detail
471{
472
473 class non_copyable
474 {
475 protected:
476
477 non_copyable() = default;
478 ~non_copyable() = default;
479
480 non_copyable(non_copyable const&) = delete;
481 void operator=(non_copyable const& x) = delete;
482 };
483
487 template <typename Col, typename Val>
488 void sort_row(Col* col, Val* val, int n)
489 {
490 for (int j = 1; j < n; ++j) {
491 Col c = col[j];
492 Val v = val[j];
493
494 int i = j - 1;
495
496 while (i >= 0 && col[i] > c) {
497 col[i + 1] = col[i];
498 val[i + 1] = val[i];
499 i--;
500 }
501
502 col[i + 1] = c;
503 val[i + 1] = v;
504 }
505 }
506
507} // namespace detail
508
509namespace error
510{
511
513 {};
514
515} // namespace error
516} // namespace Arcane::Alina
517
518namespace std
519{
520
521// Read pointers from input streams.
522// This allows exchanging pointers through the property tree.
523template <class T>
524inline istream& operator>>(istream& is, T*& ptr)
525{
527
528 size_t val;
529 is >> std::hex >> val;
530
531 ptr = reinterpret_cast<T*>(val);
532
533 return is;
534}
535
536} // namespace std
537
538#endif
#define ARCCORE_FATAL(...)
Macro throwing a FatalErrorException.
Management of references to a C++ class.
Class to store parameters as a hierarchical key/value tree.
Definition AlinaUtils.h:112
Save ostream flags in constructor, restore in destructor.
Class to handle empty parameter list.
Definition AlinaUtils.h:91
std::int64_t Int64
Signed integer type of 64 bits.
std::istream & operator>>(std::istream &istr, eItemKind &item_kind)
Input operator from a stream.
std::int32_t Int32
Signed integer type of 32 bits.