DiFfRG
Loading...
Searching...
No Matches
tuples.hh
Go to the documentation of this file.
1#pragma once
2
3// standard library
4#include <cmath>
5#include <cstring>
6#include <string_view>
7#include <tuple>
8#include <utility>
9
10// DiFfRG
12
13namespace DiFfRG
14{
18 constexpr bool strings_equal(char const *a, char const *b) { return std::string_view(a) == b; }
19
27 template <typename tuple_type, FixedString... strs> struct named_tuple {
28 static_assert(sizeof...(strs) == std::tuple_size_v<tuple_type>,
29 "Number of names must match number of elements in tuple");
30 tuple_type tuple;
31
32 constexpr operator tuple_type &() { return tuple; }
33
34 static constexpr size_t size = sizeof...(strs);
35 static constexpr std::array<const char *, size> names{{strs...}};
36
37 // If two names are the same, the program should not compile
38 static_assert(
39 []<size_t... I>(std::index_sequence<I...>) {
40 for (size_t i : {I...})
41 for (size_t j : {I...})
42 if (i != j && strings_equal(names[i], names[j])) return false;
43 return true;
44 }(std::make_index_sequence<size>{}),
45 "Names of a named_tuple must be unique!");
46
47 named_tuple(tuple_type &&t) : tuple(t) {}
48 named_tuple(tuple_type &t) : tuple(t) {}
49
50 template <typename... T> static constexpr auto as(std::tuple<T...> &&tup)
51 {
52 return named_tuple<std::tuple<T...>, strs...>(tup);
53 }
54 template <typename... T> static constexpr auto as(std::tuple<T...> &tup)
55 {
56 return named_tuple<std::tuple<T...>, strs...>(tup);
57 }
58
59 static consteval size_t get_idx(const char *name)
60 {
61 size_t running_sum = 0;
62 for (size_t i = 0; i < names.size(); ++i) {
63 // this is a way to compare two strings at compile time https://stackoverflow.com/a/53762940
64 if (strings_equal(names[i], name)) return i;
65 running_sum += 1;
66 }
67 // produce a compile-time error if the name is not found in the list
68 return size != running_sum ? 0
69 : throw std::invalid_argument(
70 "named_tuple::get_idx: Name \"" + std::string(name) +
71 "\" not found. Available names are: " + ((std::string(strs) + "; ") + ...));
72 }
73
74 template <size_t idx> auto &get() { return std::get<idx>(tuple); }
75 template <size_t idx> const auto &get() const { return std::get<idx>(tuple); }
76 };
77
81 template <FixedString name, typename tuple_type, FixedString... strs>
83 {
84 constexpr size_t idx = named_tuple<tuple_type, strs...>::get_idx(name);
85 return ob.template get<idx>();
86 }
87 template <FixedString name, typename tuple_type, FixedString... strs>
89 {
90 constexpr size_t idx = named_tuple<tuple_type, strs...>::get_idx(name);
91 return ob.template get<idx>();
92 }
93 template <FixedString name, typename tuple_type, FixedString... strs>
94 constexpr auto &get(const named_tuple<tuple_type, strs...> &ob)
95 {
96 return std::get<named_tuple<tuple_type, strs...>::get_idx(name)>(ob.tuple);
97 }
98
99 template <size_t idx, typename tuple_type, FixedString... strs>
100 constexpr auto &get(named_tuple<tuple_type, strs...> &ob)
101 {
102 return ob.template get<idx>();
103 }
104 template <size_t idx, typename tuple_type, FixedString... strs>
105 constexpr auto &get(named_tuple<tuple_type, strs...> &&ob)
106 {
107 return ob.template get<idx>();
108 }
109 template <size_t idx, typename tuple_type, FixedString... strs>
110 constexpr auto &get(const named_tuple<tuple_type, strs...> &ob)
111 {
112 return ob.template get<idx>();
113 }
114} // namespace DiFfRG
115
116namespace std
117{
118 template <size_t idx, typename tuple_type, DiFfRG::FixedString... strs>
120 {
121 return ob.template get<idx>();
122 }
123 template <size_t idx, typename tuple_type, DiFfRG::FixedString... strs>
125 {
126 return ob.template get<idx>();
127 }
128 template <size_t idx, typename tuple_type, DiFfRG::FixedString... strs>
130 {
131 return ob.template get<idx>();
132 }
133
134 // tuple_size_v
135 template <typename tuple_type, DiFfRG::FixedString... strs>
136 struct tuple_size<DiFfRG::named_tuple<tuple_type, strs...>> : std::integral_constant<size_t, sizeof...(strs)> {
137 };
138} // namespace std
139
140// Intense Voodoo
141namespace DiFfRG
142{
143 // ----------------------------------------------------------------------
144 // AD helpers. The following are used to process the jacobians via
145 // automatic differentiation. Most of these methods are used in the
146 // file model/AD.hh
147 // ----------------------------------------------------------------------
148
152 template <typename NT, uint N, uint M = N> class SimpleMatrix
153 {
154 public:
156
160 NT &operator()(const uint n, const uint m) { return data[n * M + m]; }
161
165 const NT &operator()(const uint n, const uint m) const { return data[n * M + m]; }
166
170 void clear()
171 {
172 for (uint i = 0; i < N * M; ++i)
173 data[i] = 0.;
174 }
175
179 bool is_finite() const
180 {
181 if constexpr (std::is_floating_point_v<NT> || std::is_same_v<NT, autodiff::real>) {
182 for (uint i = 0; i < N * M; ++i)
183 if (!isfinite(data[i])) return false;
184 }
185 return true;
186 }
187
191 void print() const
192 {
193 for (uint i = 0; i < N; ++i) {
194 for (uint j = 0; j < M; ++j)
195 std::cout << data[i * M + j] << " ";
196 std::cout << std::endl;
197 }
198 }
199
200 private:
201 std::array<NT, N * M> data;
202 };
203 template <uint n, typename NT, typename Vector> std::array<NT, n> vector_to_array(const Vector &v)
204 {
205 std::array<NT, n> x;
206 for (uint i = 0; i < n; ++i)
207 x[i] = v[i];
208 return x;
209 }
210
211 template <typename T, std::size_t... Indices>
212 auto vectorToTupleHelper(const std::vector<T> &v, std::index_sequence<Indices...>)
213 {
214 return std::tie(v[Indices]...);
215 }
216 template <std::size_t N, typename T> auto vector_to_tuple(const std::vector<T> &v)
217 {
218 assert(v.size() >= N);
219 return vectorToTupleHelper(v, std::make_index_sequence<N>());
220 }
221
222 template <typename Head, typename... Tail> constexpr auto tuple_tail(const std::tuple<Head, Tail...> &t)
223 {
224 return std::apply([](auto & /*head*/, auto &...tail) { return std::tie(tail...); }, t);
225 }
226 // also for named tuple
227 template <typename tuple_type, FixedString... strs>
229 {
230 return tuple_tail(t.tuple);
231 }
232
233 template <int i, typename Head, typename... Tail> constexpr auto tuple_last(const std::tuple<Head, Tail...> &t)
234 {
235 if constexpr (sizeof...(Tail) == i)
236 return std::apply([](auto & /*head*/, auto &...tail) { return std::tie(tail...); }, t);
237 else
238 return std::apply([](auto & /*head*/, auto &...tail) { return tuple_last<i>(std::tie(tail...)); }, t);
239 }
240 // also for named tuple
241 template <int i, typename tuple_type, FixedString... strs>
243 {
244 return tuple_last<i>(t.tuple);
245 }
246
247 template <int i, typename Head, typename... Tail> constexpr auto tuple_first(const std::tuple<Head, Tail...> &t)
248 {
249 if constexpr (i == 0)
250 return std::tuple();
251 else if constexpr (i == 1)
252 return std::apply([](auto &head, auto &.../*tail*/) { return std::tie(head); }, t);
253 else
254 return std::apply(
255 [](auto &head, auto &...tail) {
256 return std::tuple_cat(std::tie(head), tuple_first<i - 1>(std::tie(tail...)));
257 },
258 t);
259 }
260 // also for named tuple
261 template <int i, typename tuple_type, FixedString... strs>
263 {
264 return tuple_first<i>(t.tuple);
265 }
266
267 // ----------------------------------------------------------------------
268 // Helper functions to get the local solution at a given q_index.
269 // This is specifically for the local solutions of the subsystems,
270 // i.e. only used by the LDG assembler.
271 // ----------------------------------------------------------------------
272
273 template <typename T, size_t N, size_t... IDXs>
274 auto _local_sol_tuple(const std::array<T, N> &a, std::index_sequence<IDXs...>, uint q_index)
275 {
276 return std::tie(a[IDXs][q_index]...);
277 }
278 template <typename T, size_t N> auto local_sol_q(const std::array<T, N> &a, uint q_index)
279 {
280 return _local_sol_tuple(a, std::make_index_sequence<N>{}, q_index);
281 }
282
283 template <typename T_inner, typename Model, size_t... IDXs> auto _jacobian_tuple(std::index_sequence<IDXs...>)
284 {
285 return std::tuple{SimpleMatrix<T_inner, Model::Components::count_fe_functions(0),
286 Model::Components::count_fe_functions(IDXs)>()...};
287 }
288 template <typename T_inner, typename Model> auto jacobian_tuple()
289 {
290 return _jacobian_tuple<T_inner, Model>(std::make_index_sequence<Model::Components::count_fe_subsystems()>{});
291 }
292
293 template <typename T_inner, typename Model, size_t... IDXs> auto _jacobian_2_tuple(std::index_sequence<IDXs...>)
294 {
295 return std::tuple{std::array<
296 SimpleMatrix<T_inner, Model::Components::count_fe_functions(0), Model::Components::count_fe_functions(IDXs)>,
297 2>()...};
298 }
299 template <typename T_inner, typename Model> auto jacobian_2_tuple()
300 {
301 return _jacobian_2_tuple<T_inner, Model>(std::make_index_sequence<Model::Components::count_fe_subsystems()>{});
302 }
303} // namespace DiFfRG
A simple NxM-matrix class, which is used for cell-wise Jacobians.
Definition tuples.hh:153
const NT & operator()(const uint n, const uint m) const
Access the matrix entry at (n,m).
Definition tuples.hh:165
NT & operator()(const uint n, const uint m)
Access the matrix entry at (n,m).
Definition tuples.hh:160
SimpleMatrix()
Definition tuples.hh:155
std::array< NT, N *M > data
Definition tuples.hh:201
void clear()
Set all entries to zero.
Definition tuples.hh:170
bool is_finite() const
Check whether the matrix contains only finite values.
Definition tuples.hh:179
void print() const
Print the matrix to the console.
Definition tuples.hh:191
Definition complex_math.hh:14
constexpr auto tuple_tail(const std::tuple< Head, Tail... > &t)
Definition tuples.hh:222
auto _jacobian_tuple(std::index_sequence< IDXs... >)
Definition tuples.hh:283
constexpr auto & get(named_tuple< tuple_type, strs... > &ob)
get a reference to the element with the given name
Definition tuples.hh:82
constexpr auto tuple_first(const std::tuple< Head, Tail... > &t)
Definition tuples.hh:247
auto _jacobian_2_tuple(std::index_sequence< IDXs... >)
Definition tuples.hh:293
auto local_sol_q(const std::array< T, N > &a, uint q_index)
Definition tuples.hh:278
auto jacobian_tuple()
Definition tuples.hh:288
auto _local_sol_tuple(const std::array< T, N > &a, std::index_sequence< IDXs... >, uint q_index)
Definition tuples.hh:274
constexpr bool strings_equal(char const *a, char const *b)
Check if two strings are equal at compile time.
Definition tuples.hh:18
auto vectorToTupleHelper(const std::vector< T > &v, std::index_sequence< Indices... >)
Definition tuples.hh:212
auto vector_to_tuple(const std::vector< T > &v)
Definition tuples.hh:216
auto jacobian_2_tuple()
Definition tuples.hh:299
std::array< NT, n > vector_to_array(const Vector &v)
Definition tuples.hh:203
unsigned int uint
Definition utils.hh:22
constexpr auto tuple_last(const std::tuple< Head, Tail... > &t)
Definition tuples.hh:233
FixedString(char const (&)[N]) -> FixedString< N - 1 >
bool isfinite(const autodiff::Real< N, T > &x)
Finite-ness check for autodiff::real.
Definition math.hh:26
Definition tuples.hh:117
constexpr auto & get(DiFfRG::named_tuple< tuple_type, strs... > &ob)
Definition tuples.hh:119
A fixed size compile-time string.
Definition fixed_string.hh:10
A class to store a tuple with elements that can be accessed by name. The names are stored as FixedStr...
Definition tuples.hh:27
named_tuple(tuple_type &&t)
Definition tuples.hh:47
tuple_type tuple
Definition tuples.hh:30
static constexpr auto as(std::tuple< T... > &&tup)
Definition tuples.hh:50
const auto & get() const
Definition tuples.hh:75
static consteval size_t get_idx(const char *name)
Definition tuples.hh:59
static constexpr auto as(std::tuple< T... > &tup)
Definition tuples.hh:54
static constexpr size_t size
Definition tuples.hh:34
auto & get()
Definition tuples.hh:74
static constexpr std::array< const char *, size > names
Definition tuples.hh:35
named_tuple(tuple_type &t)
Definition tuples.hh:48