LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
Loading...
Searching...
No Matches
eigen_tools.h
1
9#ifndef INCG1cc1076600024d7ea537871be7fc1fc0
10#define INCG1cc1076600024d7ea537871be7fc1fc0
11
12// clang-format off
13#include "lf_assert.h" // must be included before eigen!
14// clang-format on
15
16#include <spdlog/fmt/ranges.h>
17
18#include <Eigen/Core>
19#include <utility>
20
21#include "lf_exception.h"
22
23namespace lf::base {
24
25namespace internal {
26
27struct IsEigenMatrixTester {
28 template <class SCALAR, int ROWS, int COLS, int OPTIONS, int MAX_ROWS,
29 int MAX_COLS>
30 static bool Test(
31 const Eigen::Matrix<SCALAR, ROWS, COLS, OPTIONS, MAX_ROWS, MAX_COLS>&,
32 int);
33
34 template <class T>
35 static float Test(const T&, long);
36};
37
38struct IsEigenArrayTester {
39 template <class SCALAR, int ROWS, int COLS, int OPTIONS, int MAX_ROWS,
40 int MAX_COLS>
41 static bool Test(
42 const Eigen::Array<SCALAR, ROWS, COLS, OPTIONS, MAX_ROWS, MAX_COLS>&,
43 int);
44
45 template <class T>
46 static float Test(const T&, long);
47};
48
49} // namespace internal
50
69template <class T, class SCALAR = void, int ROWS = -1, int COLS = -1>
70concept EigenMatrix =
71 std::is_same_v<decltype(internal::IsEigenMatrixTester::Test(
72 std::declval<T>(), 0)),
73 bool> &&
74 (std::same_as<SCALAR, void> || std::same_as<typename T::Scalar, SCALAR>) &&
75 (ROWS == -1 ||
76 std::remove_cvref_t<T>::RowsAtCompileTime == Eigen::Dynamic ||
77 std::remove_cvref_t<T>::RowsAtCompileTime == ROWS) &&
78 (COLS == -1 ||
79 std::remove_cvref_t<T>::ColsAtCompileTime == Eigen::Dynamic ||
80 std::remove_cvref_t<T>::ColsAtCompileTime == COLS);
81
85template <class T>
86concept EigenArray = std::is_same_v<
87 decltype(internal::IsEigenArrayTester::Test(std::declval<T>(), 0)), bool>;
88
89} // namespace lf::base
90
92
93// The following is needed to prohibit fmt to treat Eigen matrices/arrays as
94// ranges.
95template <class MATRIX>
96 requires(std::is_base_of_v<Eigen::DenseBase<MATRIX>, MATRIX>)
97struct fmt::is_range<MATRIX, char> {
98 static constexpr const bool value = false;
99};
100
106template <class MATRIX>
107 requires(std::is_base_of_v<Eigen::DenseBase<MATRIX>, MATRIX>)
108struct fmt::formatter<MATRIX> {
109 constexpr auto parse(const format_parse_context& ctx) {
110 const auto* it = ctx.begin();
111 const auto* end = ctx.end();
112
113 if (it != end && *it == '.') {
114 // Support precision:
115 ++it;
116 auto start = it;
117 while (is_digit(*it) && it != end) {
118 ++it;
119 }
120 precision = parse_unsigned_int(start, it);
121 } else {
122 precision = 4;
123 }
124
125 if (it != end && *it != '}') {
126 throw format_error("invalid format");
127 }
128
129 return it;
130 }
131
132 template <typename FormatContext>
133 auto format(const MATRIX& m, FormatContext& ctx) const {
134 std::stringstream ss; // NOLINT(misc-const-correctness)
135 const Eigen::IOFormat format(precision, 0, ", ", "\n", "[", "]");
136 ss << m.format(format);
137
138 auto it = ctx.out();
139 auto str = ss.str();
140 std::copy(str.begin(), str.end(), it);
141 return it;
142 }
143
144 private:
145 int precision = 4;
146
147 constexpr bool is_digit(char c) { return c <= '9' && c >= '0'; }
148 constexpr int parse_unsigned_int(const char* begin, const char* end) {
149 int result = 0;
150 while (begin != end) {
151 if (!is_digit(*begin)) {
152 throw "compile time error, this is not a digit."; // NOLINT(hicpp-exception-baseclass)
153 }
154 result += (*begin - '0');
155 result *= 10;
156 ++begin;
157 }
158 result = result / 10;
159 return result;
160 }
161};
163
164#endif // INCG1cc1076600024d7ea537871be7fc1fc0
Check if a given type T is a Eigen::Array<...>&
Definition eigen_tools.h:86
Check if a given type T is an Eigen::Matrix.
Definition eigen_tools.h:70
Contains basic functionality that is used by other parts of LehrFEM++.
Definition base.h:15