OGS
ReflectionIPData.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#pragma once
5
6#include <boost/mp11.hpp>
7
11#include "ReflectionData.h"
12
14{
15namespace detail
16{
24template <typename T>
25struct is_raw_data : std::false_type
26{
27};
28
29template <>
30struct is_raw_data<double> : std::true_type
31{
32};
33
34template <int N>
35struct is_raw_data<Eigen::Matrix<double, N, 1, Eigen::ColMajor, N, 1>>
36 : std::true_type
37{
38};
39
40template <int N, int M>
41struct is_raw_data<Eigen::Matrix<double, N, M, Eigen::RowMajor, N, M>>
42 : std::true_type
43{
44};
45
46template <typename T>
48
49template <typename T>
51
52template <>
53struct NumberOfRows<double> : std::integral_constant<unsigned, 1>
54{
55};
56
57template <int N>
58struct NumberOfRows<Eigen::Matrix<double, N, 1, Eigen::ColMajor, N, 1>>
59 : std::integral_constant<unsigned, N>
60{
61};
62
63template <int N, int M>
64struct NumberOfRows<Eigen::Matrix<double, N, M, Eigen::RowMajor, N, M>>
65 : std::integral_constant<unsigned, N>
66{
67};
68
69template <typename T>
71
72template <>
73struct NumberOfColumns<double> : std::integral_constant<unsigned, 1>
74{
75};
76
77template <int N>
78struct NumberOfColumns<Eigen::Matrix<double, N, 1, Eigen::ColMajor, N, 1>>
79 : std::integral_constant<unsigned, 1>
80{
81};
82
83template <int N, int M>
84struct NumberOfColumns<Eigen::Matrix<double, N, M, Eigen::RowMajor, N, M>>
85 : std::integral_constant<unsigned, M>
86{
87};
88
89template <typename T>
91 : std::integral_constant<unsigned,
92 NumberOfRows<T>::value * NumberOfColumns<T>::value>
93{
94};
95
96template <typename T>
97concept has_reflect = requires { T::reflect(); };
98
99template <typename... Ts>
100auto reflect(std::type_identity<std::tuple<Ts...>> /*unused*/)
101{
102 using namespace boost::mp11;
103
104 // The types Ts... must be unique. Duplicate types are incompatible with the
105 // concept of "reflected" I/O: they would lead to duplicate names for the
106 // I/O data.
107 static_assert(mp_is_set_v<mp_list<Ts...>>);
108
109 return reflectWithoutName<std::tuple<Ts...>>(
110 [](auto& tuple_) -> auto& { return std::get<Ts>(tuple_); }...);
111}
112
113template <has_reflect T>
114auto reflect(std::type_identity<T> /*unused*/)
115{
116 return T::reflect();
117}
118
119template <typename T>
120concept has_ioName = requires(T* t) { ioName(t); };
121
122template <typename T, typename Tag>
123auto reflect(std::type_identity<BaseLib::StrongType<T, Tag>> /*unused*/)
124{
126
127 auto accessor = [](auto& o) -> auto& { return *o; };
128
129 // Maybe in the future we might want to lift the following two constraints.
130 // But beware: that generalization has to be tested thoroughly such that we
131 // don't accidentally produce I/O data without name and the like.
132 static_assert(
134 /* We use ioName(Tag* tag), because it works with an incomplete type
135 * Tag, as opposed to ioName(Tag tag), i.e. declaring
136 * std::string_view ioName(struct SomeTag*);
137 * is possible, whereas
138 * std::string_view ioName(struct SomeTag);
139 * is not.
140 * This choice makes the code for every ioName() definition rather
141 * compact.
142 */
143 "For I/O of StrongType<T, Tag> you have to define an ioName(Tag* tag) "
144 "function returning the name used for I/O.");
145 static_assert(
147 "I/O of StrongTypes is supported only for StrongTypes wrapping 'raw "
148 "data' such as double values, vectors and matrices.");
149
150 return std::tuple{makeReflectionData<ST>(
151 std::string{ioName(static_cast<Tag*>(nullptr))}, std::move(accessor))};
152}
153
154template <typename T>
155concept is_reflectable = requires {
156 ProcessLib::Reflection::detail::reflect(std::type_identity<T>{});
157};
158
214template <int Dim, typename Accessor_IPDataVecInLocAsm,
215 typename Accessor_CurrentLevelFromIPDataVecElement>
217{
218 static_assert(!std::is_reference_v<Accessor_IPDataVecInLocAsm>);
219 static_assert(
220 !std::is_reference_v<Accessor_CurrentLevelFromIPDataVecElement>);
221
222 Accessor_IPDataVecInLocAsm accessor_ip_data_vec_in_loc_asm;
223 Accessor_CurrentLevelFromIPDataVecElement
225
226 template <typename LocAsm>
227 std::vector<double> operator()(LocAsm const& loc_asm) const
228 {
229 using IPDataVector = std::remove_cvref_t<
230 std::invoke_result_t<Accessor_IPDataVecInLocAsm, LocAsm const&>>;
231 using IPDataVectorElement = typename IPDataVector::value_type;
232
233 // the concrete IP data, e.g. double or Eigen::Vector
234 using ConcreteIPData = std::remove_cvref_t<
235 std::invoke_result_t<Accessor_CurrentLevelFromIPDataVecElement,
236 IPDataVectorElement const&>>;
238 "This method only deals with raw data. The given "
239 "ConcreteIPData is not raw data.");
240
241 constexpr unsigned num_rows = NumberOfRows<ConcreteIPData>::value;
242 constexpr unsigned num_cols = NumberOfColumns<ConcreteIPData>::value;
243 constexpr unsigned num_comp = num_rows * num_cols;
244 auto const& ip_data_vector = accessor_ip_data_vec_in_loc_asm(loc_asm);
245 auto const num_ips = ip_data_vector.size();
246
247 std::vector<double> result(num_comp * num_ips);
248
249 for (std::size_t ip = 0; ip < num_ips; ++ip)
250 {
251 auto const& ip_data_vector_element = ip_data_vector[ip];
252 auto const& ip_data =
254 ip_data_vector_element);
255
256 if constexpr (num_comp == 1)
257 {
258 // scalar
259 result[ip] = ip_data;
260 }
261 else if constexpr (num_rows == MathLib::KelvinVector::
263 num_cols == 1)
264 {
265 // Kelvin vector
266 auto const converted =
268 ip_data);
269
270 for (unsigned comp = 0; comp < num_comp; ++comp)
271 {
272 result[ip * num_comp + comp] = converted[comp];
273 }
274 }
275 else if constexpr (num_cols == MathLib::KelvinVector::
277 num_rows == 1)
278 {
279 static_assert(
280 num_rows != 1 /* always false in this branch */,
281 "We support Kelvin column-vectors, but not Kelvin "
282 "row-vectors. The latter are unusual and confusion with "
283 "generic vectors might be possible.");
284 }
285 else if constexpr (num_rows == 1 || num_cols == 1)
286 {
287 // row or column vector
288 for (unsigned comp = 0; comp < num_comp; ++comp)
289 {
290 result[ip * num_comp + comp] = ip_data[comp];
291 }
292 }
293 else
294 {
295 // matrix
296 // row-major traversal
297 for (unsigned row = 0; row < num_rows; ++row)
298 {
299 for (unsigned col = 0; col < num_cols; ++col)
300 {
301 result[ip * num_comp + row * num_cols + col] =
302 ip_data(row, col);
303 }
304 }
305 }
306 }
307 return result;
308 }
309};
310
311// Convenience function for template argument deduction with
312// GetFlattenedIPDataFromLocAsm
313template <int Dim, typename Accessor_IPDataVecInLocAsm,
314 typename Accessor_CurrentLevelFromIPDataVecElement>
315GetFlattenedIPDataFromLocAsm<
316 Dim, std::remove_cvref_t<Accessor_IPDataVecInLocAsm>,
317 std::remove_cvref_t<Accessor_CurrentLevelFromIPDataVecElement>>
319 Accessor_IPDataVecInLocAsm accessor_ip_data_vec_in_loc_asm,
320 Accessor_CurrentLevelFromIPDataVecElement
321 accessor_current_level_from_ip_data_vec_element)
322{
323 return {std::forward<Accessor_IPDataVecInLocAsm>(
324 accessor_ip_data_vec_in_loc_asm),
325 std::forward<Accessor_CurrentLevelFromIPDataVecElement>(
326 accessor_current_level_from_ip_data_vec_element)};
327}
328
329// Convenience function for template argument deduction with
330// GetFlattenedIPDataFromLocAsm. Overload of the function above with less
331// arguments.
332template <int Dim, typename Accessor_IPDataVecInLocAsm>
334 Accessor_IPDataVecInLocAsm&& accessor_ip_data_vec_in_loc_asm)
335{
337 std::forward<Accessor_IPDataVecInLocAsm>(
338 accessor_ip_data_vec_in_loc_asm),
339 std::identity{});
340}
341
352template <int Dim, typename Callback, typename ReflectionDataTuple,
353 typename Accessor_IPDataVecInLocAsm,
354 typename Accessor_CurrentLevelFromIPDataVecElement>
356 Callback const& callback, ReflectionDataTuple const& reflection_data,
357 Accessor_IPDataVecInLocAsm const& accessor_ip_data_vec_in_loc_asm,
358 Accessor_CurrentLevelFromIPDataVecElement const&
359 accessor_current_level_from_ip_data_vec_element)
360{
362 "The passed reflection data is not a std::tuple.");
363 static_assert(
364 std::is_same_v<ReflectionDataTuple,
365 boost::mp11::mp_rename<ReflectionDataTuple, std::tuple>>,
366 "The passed reflection data is not a std::tuple.");
367
368 boost::mp11::tuple_for_each(
369 reflection_data,
370 [&accessor_ip_data_vec_in_loc_asm,
371 &accessor_current_level_from_ip_data_vec_element,
372 &callback]<typename Class, typename Accessor>(
373 ReflectionData<Class, Accessor> const& refl_data)
374 {
375 using MemberRef = std::invoke_result_t<Accessor, Class const&>;
376 using Member = std::remove_cvref_t<MemberRef>;
377
378 auto accessor_member_from_ip_data_vec_element =
379 [accessor_next_level = refl_data.accessor,
380 accessor_current_level_from_ip_data_vec_element](
381 auto const& ip_data_vec_element) -> Member const&
382 {
383 return accessor_next_level(
384 accessor_current_level_from_ip_data_vec_element(
385 ip_data_vec_element));
386 };
387
388 if constexpr (is_reflectable<Member>)
389 {
391 callback, detail::reflect(std::type_identity<Member>{}),
392 accessor_ip_data_vec_in_loc_asm,
393 accessor_member_from_ip_data_vec_element);
394 }
395 else
396 {
397 static_assert(is_raw_data_v<Member>,
398 "The current member is not reflectable, so we "
399 "expect it to be raw data.");
400
401 constexpr unsigned num_comp = NumberOfComponents<Member>::value;
402
403 assert(!refl_data.name.empty());
404 callback(refl_data.name, num_comp,
406 accessor_ip_data_vec_in_loc_asm,
407 accessor_member_from_ip_data_vec_element));
408 }
409 });
410}
411
412// Overload of the function above with less arguments
413template <int Dim, typename Callback, typename ReflectionDataTuple,
414 typename Accessor_IPDataVecInLocAsm>
416 Callback const& callback,
417 ReflectionDataTuple const& reflection_data,
418 Accessor_IPDataVecInLocAsm const& accessor_ip_data_vec_in_loc_asm)
419{
421 callback, reflection_data, accessor_ip_data_vec_in_loc_asm,
422 std::identity{});
423}
424
425} // namespace detail
426
438template <int Dim, typename LocAsmIF, typename Callback, typename ReflData>
439void forEachReflectedFlattenedIPDataAccessor(ReflData const& reflection_data,
440 Callback const& callback)
441{
442 using namespace boost::mp11;
443
444 static_assert(mp_is_list_v<ReflData>,
445 "The passed reflection data is not a std::tuple.");
446 static_assert(std::is_same_v<ReflData, mp_rename<ReflData, std::tuple>>,
447 "The passed reflection data is not a std::tuple.");
448
449 tuple_for_each(
450 reflection_data,
451 [&callback]<typename Class, typename Accessor>(
452 ReflectionData<Class, Accessor> const& refl_data)
453 {
454 static_assert(std::is_same_v<Class, LocAsmIF>,
455 "The currently processed reflection data is not for "
456 "the given LocAsmIF but for a different class.");
457
458 using AccessorResultRef =
459 std::invoke_result_t<Accessor, Class const&>;
460 using AccessorResult = std::remove_cvref_t<AccessorResultRef>;
461
462 // AccessorResult must be a std::vector<SomeType, SomeAllocator>. We
463 // check that, now.
464 static_assert(
465 mp_is_list_v<AccessorResult>); // std::vector<SomeType,
466 // SomeAllocator> is a list in
467 // the Boost MP11 sense
468 static_assert(
469 std::is_same_v<AccessorResult,
470 mp_rename<AccessorResult, std::vector>>,
471 "We expect a std::vector, here.");
472 // Now, we know that AccessorResult is std::vector<Member>. To be
473 // more specific, AccessorResult is a std::vector<IPData> and Member
474 // is IPData.
475 using Member = typename AccessorResult::value_type;
476
477 auto accessor_ip_data_vec_in_loc_asm =
478 [ip_data_vector_accessor =
479 refl_data.accessor](LocAsmIF const& loc_asm) -> auto const&
480 { return ip_data_vector_accessor(loc_asm); };
481
482 if constexpr (detail::is_reflectable<Member>)
483 {
485 callback,
486 detail::reflect(std::type_identity<Member>{}),
487 accessor_ip_data_vec_in_loc_asm);
488 }
489 else
490 {
491 static_assert(detail::is_raw_data_v<Member>,
492 "The current member is not reflectable, so we "
493 "expect it to be raw data.");
494
495 constexpr unsigned num_comp =
497
498 assert(!refl_data.name.empty());
499 callback(refl_data.name, num_comp,
501 accessor_ip_data_vec_in_loc_asm));
502 }
503 });
504}
505} // namespace ProcessLib::Reflection
Eigen::Matrix< double, 4, 1 > kelvinVectorToSymmetricTensor(Eigen::Matrix< double, 4, 1, Eigen::ColMajor, 4, 1 > const &v)
constexpr int kelvin_vector_dimensions(int const displacement_dim)
Kelvin vector dimensions for given displacement dimension.
GetFlattenedIPDataFromLocAsm< Dim, std::remove_cvref_t< Accessor_IPDataVecInLocAsm >, std::remove_cvref_t< Accessor_CurrentLevelFromIPDataVecElement > > getFlattenedIPDataFromLocAsm(Accessor_IPDataVecInLocAsm accessor_ip_data_vec_in_loc_asm, Accessor_CurrentLevelFromIPDataVecElement accessor_current_level_from_ip_data_vec_element)
auto reflect(std::type_identity< std::tuple< Ts... > >)
void forEachReflectedFlattenedIPDataAccessor(Callback const &callback, ReflectionDataTuple const &reflection_data, Accessor_IPDataVecInLocAsm const &accessor_ip_data_vec_in_loc_asm, Accessor_CurrentLevelFromIPDataVecElement const &accessor_current_level_from_ip_data_vec_element)
auto makeReflectionData(Accessor &&accessor)
void forEachReflectedFlattenedIPDataAccessor(ReflData const &reflection_data, Callback const &callback)
auto reflectWithoutName(Accessors &&... accessors)
constexpr bool mp_is_set_v
constexpr bool mp_is_list_v
Accessor_CurrentLevelFromIPDataVecElement accessor_current_level_from_ip_data_vec_element
std::vector< double > operator()(LocAsm const &loc_asm) const