OGS
ReflectionIPData.h
Go to the documentation of this file.
1
11#pragma once
12
13#include <boost/mp11.hpp>
14
16#include "BaseLib/StrongType.h"
18#include "ReflectionData.h"
19
21{
22namespace detail
23{
31template <typename T>
32struct is_raw_data : std::false_type
33{
34};
35
36template <>
37struct is_raw_data<double> : std::true_type
38{
39};
40
41template <int N>
42struct is_raw_data<Eigen::Matrix<double, N, 1, Eigen::ColMajor, N, 1>>
43 : std::true_type
44{
45};
46
47template <int N, int M>
48struct is_raw_data<Eigen::Matrix<double, N, M, Eigen::RowMajor, N, M>>
49 : std::true_type
50{
51};
52
53template <typename T>
55
56template <typename T>
58
59template <>
60struct NumberOfRows<double> : std::integral_constant<unsigned, 1>
61{
62};
63
64template <int N>
65struct NumberOfRows<Eigen::Matrix<double, N, 1, Eigen::ColMajor, N, 1>>
66 : std::integral_constant<unsigned, N>
67{
68};
69
70template <int N, int M>
71struct NumberOfRows<Eigen::Matrix<double, N, M, Eigen::RowMajor, N, M>>
72 : std::integral_constant<unsigned, N>
73{
74};
75
76template <typename T>
78
79template <>
80struct NumberOfColumns<double> : std::integral_constant<unsigned, 1>
81{
82};
83
84template <int N>
85struct NumberOfColumns<Eigen::Matrix<double, N, 1, Eigen::ColMajor, N, 1>>
86 : std::integral_constant<unsigned, 1>
87{
88};
89
90template <int N, int M>
91struct NumberOfColumns<Eigen::Matrix<double, N, M, Eigen::RowMajor, N, M>>
92 : std::integral_constant<unsigned, M>
93{
94};
95
96template <typename T>
98 : std::integral_constant<unsigned,
99 NumberOfRows<T>::value * NumberOfColumns<T>::value>
100{
101};
102
103template <typename T>
104concept has_reflect = requires
105{
106 T::reflect();
107};
108
109template <typename... Ts>
110auto reflect(std::type_identity<std::tuple<Ts...>>)
111{
112 using namespace boost::mp11;
113
114 // The types Ts... must be unique. Duplicate types are incompatible with the
115 // concept of "reflected" I/O: they would lead to duplicate names for the
116 // I/O data.
117 static_assert(mp_is_set_v<mp_list<Ts...>>);
118
119 return reflectWithoutName<std::tuple<Ts...>>(
120 [](auto& tuple_) -> auto& { return std::get<Ts>(tuple_); }...);
121}
122
123template <has_reflect T>
124auto reflect(std::type_identity<T>)
125{
126 return T::reflect();
127}
128
129template <typename T>
130concept has_ioName = requires(T* t)
131{
132 ioName(t);
133};
134
135template <typename T, typename Tag>
136auto reflect(std::type_identity<BaseLib::StrongType<T, Tag>>)
137{
139
140 auto accessor = [](auto& o) -> auto&
141 {
142 return *o;
143 };
144
145 // Maybe in the future we might want to lift the following two constraints.
146 // But beware: that generalization has to be tested thoroughly such that we
147 // don't accidentally produce I/O data without name and the like.
148 static_assert(
150 /* We use ioName(Tag* tag), because it works with an incomplete type
151 * Tag, as opposed to ioName(Tag tag), i.e. declaring
152 * std::string_view ioName(struct SomeTag*);
153 * is possible, whereas
154 * std::string_view ioName(struct SomeTag);
155 * is not.
156 * This choice makes the code for every ioName() definition rather
157 * compact.
158 */
159 "For I/O of StrongType<T, Tag> you have to define an ioName(Tag* tag) "
160 "function returning the name used for I/O.");
161 static_assert(
162 is_raw_data_v<T>,
163 "I/O of StrongTypes is supported only for StrongTypes wrapping 'raw "
164 "data' such as double values, vectors and matrices.");
165
166 return std::tuple{makeReflectionData<ST>(
167 std::string{ioName(static_cast<Tag*>(nullptr))}, std::move(accessor))};
168}
169
170template <typename T>
171concept is_reflectable = requires
172{
173 ProcessLib::Reflection::detail::reflect(std::type_identity<T>{});
174};
175
231template <int Dim, typename Accessor_IPDataVecInLocAsm,
232 typename Accessor_CurrentLevelFromIPDataVecElement>
234{
235 static_assert(!std::is_reference_v<Accessor_IPDataVecInLocAsm>);
236 static_assert(
237 !std::is_reference_v<Accessor_CurrentLevelFromIPDataVecElement>);
238
239 Accessor_IPDataVecInLocAsm accessor_ip_data_vec_in_loc_asm;
240 Accessor_CurrentLevelFromIPDataVecElement
242
243 template <typename LocAsm>
244 std::vector<double> operator()(LocAsm const& loc_asm) const
245 {
246 using IPDataVector = std::remove_cvref_t<
247 std::invoke_result_t<Accessor_IPDataVecInLocAsm, LocAsm const&>>;
248 using IPDataVectorElement = typename IPDataVector::value_type;
249
250 // the concrete IP data, e.g. double or Eigen::Vector
251 using ConcreteIPData = std::remove_cvref_t<
252 std::invoke_result_t<Accessor_CurrentLevelFromIPDataVecElement,
253 IPDataVectorElement const&>>;
255 "This method only deals with raw data. The given "
256 "ConcreteIPData is not raw data.");
257
258 constexpr unsigned num_rows = NumberOfRows<ConcreteIPData>::value;
259 constexpr unsigned num_cols = NumberOfColumns<ConcreteIPData>::value;
260 constexpr unsigned num_comp = num_rows * num_cols;
261 auto const& ip_data_vector = accessor_ip_data_vec_in_loc_asm(loc_asm);
262 auto const num_ips = ip_data_vector.size();
263
264 std::vector<double> result(num_comp * num_ips);
265
266 for (std::size_t ip = 0; ip < num_ips; ++ip)
267 {
268 auto const& ip_data_vector_element = ip_data_vector[ip];
269 auto const& ip_data =
271 ip_data_vector_element);
272
273 if constexpr (num_comp == 1)
274 {
275 // scalar
276 result[ip] = ip_data;
277 }
278 else if constexpr (num_rows == MathLib::KelvinVector::
280 num_cols == 1)
281 {
282 // Kelvin vector
283 auto const converted =
285 ip_data);
286
287 for (unsigned comp = 0; comp < num_comp; ++comp)
288 {
289 result[ip * num_comp + comp] = converted[comp];
290 }
291 }
292 else if constexpr (num_cols == MathLib::KelvinVector::
294 num_rows == 1)
295 {
296 static_assert(
297 num_rows != 1 /* always false in this branch */,
298 "We support Kelvin column-vectors, but not Kelvin "
299 "row-vectors. The latter are unusual and confusion with "
300 "generic vectors might be possible.");
301 }
302 else if constexpr (num_rows == 1 || num_cols == 1)
303 {
304 // row or column vector
305 for (unsigned comp = 0; comp < num_comp; ++comp)
306 {
307 result[ip * num_comp + comp] = ip_data[comp];
308 }
309 }
310 else
311 {
312 // matrix
313 // row-major traversal
314 for (unsigned row = 0; row < num_rows; ++row)
315 {
316 for (unsigned col = 0; col < num_cols; ++col)
317 {
318 result[ip * num_comp + row * num_cols + col] =
319 ip_data(row, col);
320 }
321 }
322 }
323 }
324 return result;
325 }
326};
327
328// Convenience function for template argument deduction with
329// GetFlattenedIPDataFromLocAsm
330template <int Dim, typename Accessor_IPDataVecInLocAsm,
331 typename Accessor_CurrentLevelFromIPDataVecElement>
332GetFlattenedIPDataFromLocAsm<
333 Dim, std::remove_cvref_t<Accessor_IPDataVecInLocAsm>,
334 std::remove_cvref_t<Accessor_CurrentLevelFromIPDataVecElement>>
336 Accessor_IPDataVecInLocAsm accessor_ip_data_vec_in_loc_asm,
337 Accessor_CurrentLevelFromIPDataVecElement
338 accessor_current_level_from_ip_data_vec_element)
339{
340 return {std::forward<Accessor_IPDataVecInLocAsm>(
341 accessor_ip_data_vec_in_loc_asm),
342 std::forward<Accessor_CurrentLevelFromIPDataVecElement>(
343 accessor_current_level_from_ip_data_vec_element)};
344}
345
346// Convenience function for template argument deduction with
347// GetFlattenedIPDataFromLocAsm. Overload of the function above with less
348// arguments.
349template <int Dim, typename Accessor_IPDataVecInLocAsm>
351 Accessor_IPDataVecInLocAsm&& accessor_ip_data_vec_in_loc_asm)
352{
353 return getFlattenedIPDataFromLocAsm<Dim>(
354 std::forward<Accessor_IPDataVecInLocAsm>(
355 accessor_ip_data_vec_in_loc_asm),
356 std::identity{});
357}
358
369template <int Dim, typename Callback, typename ReflectionDataTuple,
370 typename Accessor_IPDataVecInLocAsm,
371 typename Accessor_CurrentLevelFromIPDataVecElement>
373 Callback const& callback, ReflectionDataTuple const& reflection_data,
374 Accessor_IPDataVecInLocAsm const& accessor_ip_data_vec_in_loc_asm,
375 Accessor_CurrentLevelFromIPDataVecElement const&
376 accessor_current_level_from_ip_data_vec_element)
377{
378 static_assert(boost::mp11::mp_is_list_v<ReflectionDataTuple>,
379 "The passed reflection data is not a std::tuple.");
380 static_assert(
381 std::is_same_v<ReflectionDataTuple,
382 boost::mp11::mp_rename<ReflectionDataTuple, std::tuple>>,
383 "The passed reflection data is not a std::tuple.");
384
385 boost::mp11::tuple_for_each(
386 reflection_data,
387 [&accessor_ip_data_vec_in_loc_asm,
388 &accessor_current_level_from_ip_data_vec_element,
389 &callback]<typename Class, typename Accessor>(
390 ReflectionData<Class, Accessor> const& refl_data)
391 {
392 using MemberRef = std::invoke_result_t<Accessor, Class const&>;
393 using Member = std::remove_cvref_t<MemberRef>;
394
395 auto accessor_member_from_ip_data_vec_element =
396 [accessor_next_level = refl_data.accessor,
397 accessor_current_level_from_ip_data_vec_element](
398 auto const& ip_data_vec_element) -> Member const&
399 {
400 return accessor_next_level(
401 accessor_current_level_from_ip_data_vec_element(
402 ip_data_vec_element));
403 };
404
405 if constexpr (is_reflectable<Member>)
406 {
407 forEachReflectedFlattenedIPDataAccessor<Dim>(
408 callback, detail::reflect(std::type_identity<Member>{}),
409 accessor_ip_data_vec_in_loc_asm,
410 accessor_member_from_ip_data_vec_element);
411 }
412 else
413 {
414 static_assert(is_raw_data_v<Member>,
415 "The current member is not reflectable, so we "
416 "expect it to be raw data.");
417
418 constexpr unsigned num_comp = NumberOfComponents<Member>::value;
419
420 assert(!refl_data.name.empty());
421 callback(refl_data.name, num_comp,
422 getFlattenedIPDataFromLocAsm<Dim>(
423 accessor_ip_data_vec_in_loc_asm,
424 accessor_member_from_ip_data_vec_element));
425 }
426 });
427}
428
429// Overload of the function above with less arguments
430template <int Dim, typename Callback, typename ReflectionDataTuple,
431 typename Accessor_IPDataVecInLocAsm>
433 Callback const& callback,
434 ReflectionDataTuple const& reflection_data,
435 Accessor_IPDataVecInLocAsm const& accessor_ip_data_vec_in_loc_asm)
436{
437 forEachReflectedFlattenedIPDataAccessor<Dim>(
438 callback, reflection_data, accessor_ip_data_vec_in_loc_asm,
439 std::identity{});
440}
441
442} // namespace detail
443
455template <int Dim, typename LocAsmIF, typename Callback, typename ReflData>
456void forEachReflectedFlattenedIPDataAccessor(ReflData const& reflection_data,
457 Callback const& callback)
458{
459 using namespace boost::mp11;
460
461 static_assert(mp_is_list_v<ReflData>,
462 "The passed reflection data is not a std::tuple.");
463 static_assert(std::is_same_v<ReflData, mp_rename<ReflData, std::tuple>>,
464 "The passed reflection data is not a std::tuple.");
465
466 tuple_for_each(
467 reflection_data,
468 [&callback]<typename Class, typename Accessor>(
469 ReflectionData<Class, Accessor> const& refl_data)
470 {
471 static_assert(std::is_same_v<Class, LocAsmIF>,
472 "The currently processed reflection data is not for "
473 "the given LocAsmIF but for a different class.");
474
475 using AccessorResultRef =
476 std::invoke_result_t<Accessor, Class const&>;
477 using AccessorResult = std::remove_cvref_t<AccessorResultRef>;
478
479 // AccessorResult must be a std::vector<SomeType, SomeAllocator>. We
480 // check that, now.
481 static_assert(
482 mp_is_list_v<AccessorResult>); // std::vector<SomeType,
483 // SomeAllocator> is a list in
484 // the Boost MP11 sense
485 static_assert(
486 std::is_same_v<AccessorResult,
487 mp_rename<AccessorResult, std::vector>>,
488 "We expect a std::vector, here.");
489 // Now, we know that AccessorResult is std::vector<Member>. To be
490 // more specific, AccessorResult is a std::vector<IPData> and Member
491 // is IPData.
492 using Member = typename AccessorResult::value_type;
493
494 auto accessor_ip_data_vec_in_loc_asm =
495 [ip_data_vector_accessor =
496 refl_data.accessor](LocAsmIF const& loc_asm) -> auto const&
497 {
498 return ip_data_vector_accessor(loc_asm);
499 };
500
501 if constexpr (detail::is_reflectable<Member>)
502 {
503 detail::forEachReflectedFlattenedIPDataAccessor<Dim>(
504 callback,
505 detail::reflect(std::type_identity<Member>{}),
506 accessor_ip_data_vec_in_loc_asm);
507 }
508 else
509 {
510 static_assert(detail::is_raw_data_v<Member>,
511 "The current member is not reflectable, so we "
512 "expect it to be raw data.");
513
514 constexpr unsigned num_comp =
516
517 assert(!refl_data.name.empty());
518 callback(refl_data.name, num_comp,
519 detail::getFlattenedIPDataFromLocAsm<Dim>(
520 accessor_ip_data_vec_in_loc_asm));
521 }
522 });
523}
524} // 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)
void forEachReflectedFlattenedIPDataAccessor(ReflData const &reflection_data, Callback const &callback)
auto reflectWithoutName(Accessors &&... accessors)
Accessor_CurrentLevelFromIPDataVecElement accessor_current_level_from_ip_data_vec_element
std::vector< double > operator()(LocAsm const &loc_asm) const