v0.16.3
Loading...
Searching...
No Matches
Templates.hpp
Go to the documentation of this file.
1/** \file Templates.hpp
2 * \brief Templates declarations
3 */
4
5#ifndef __TEMPLATES_HPP__
6#define __TEMPLATES_HPP__
7
8namespace MoFEM {
9
10/** @name Data layout helpers
11 * Traits describing tensor storage layout conventions.
12 * @{
13 */
15template <DataLayout DL> struct DataLayoutTraits;
17 static constexpr bool isGaussByCoeffs = true;
18 static constexpr bool isCoeffsByGauss = false;
19};
21 static constexpr bool isGaussByCoeffs = false;
22 static constexpr bool isCoeffsByGauss = true;
23};
24/** @} */
25
26/** @name Adaptor functions
27 * Views that wrap raw storage as vector or matrix adaptors.
28 * @{
29 */
30/**
31 * @brief Get Vector adaptor
32 *
33 * \code
34 *
35 * double *a;
36 * CHKERR VecGetArray(v,&a);
37 *
38 * for(int n = 0; n != nodes; ++n) {
39 *
40 * auto a = getVectorAdaptor(&a[3*n], 3);
41 * double dot = inner_prod(a, a);
42 *
43 * }
44 *
45 * CHKERR VecRetsoreArray(v,&a);
46 * \endcode
47 *
48 */
49template <typename T1> inline auto getVectorAdaptor(T1 ptr, const size_t n) {
50 typedef typename std::remove_pointer<T1>::type T;
52 ublas::shallow_array_adaptor<T>(n, ptr));
53};
54
55/**
56 * @brief Get Matrix adaptor
57 *
58 * \code
59 *
60 * double *a;
61 * CHKERR VecGetArray(v,&a);
62 *
63 * for(int n = 0; n != nodes; ++n) {
64 *
65 * auto F = getMatrixAdaptor(&a[3*3*n], 3, 3);
66 * MatrixDouble C = prod(F, trans(F));
67 *
68 * }
69 *
70 * CHKERR VecRetsoreArray(v,&a);
71 * \endcode
72 *
73 */
74template <typename T1>
75inline auto getMatrixAdaptor(T1 ptr, const size_t n, const size_t m) {
76 typedef typename std::remove_pointer<T1>::type T;
78 n, m, ublas::shallow_array_adaptor<T>(n * m, ptr));
79};
80/** @} */
81
82/** @name Generic utility helpers
83 * Shared template utilities used across the header.
84 * @{
85 */
86/**
87 * This small utility that cascades two key extractors will be
88 * used throughout the boost example
89 * <a
90 * href=http://www.boost.org/doc/libs/1_53_0/libs/multi_index/example/complex_structs.cpp>
91 * http://www.boost.org/doc/libs/1_53_0/libs/multi_index/example/complex_structs.cpp
92 * </a>
93 */
94template <class KeyExtractor1, class KeyExtractor2> struct KeyFromKey {
95public:
96 typedef typename KeyExtractor1::result_type result_type;
97
98 KeyFromKey(const KeyExtractor1 &key1_ = KeyExtractor1(),
99 const KeyExtractor2 &key2_ = KeyExtractor2())
100 : key1(key1_), key2(key2_) {}
101
102 template <typename Arg> result_type operator()(Arg &arg) const {
103 return key1(key2(arg));
104 }
105
106private:
107 KeyExtractor1 key1;
108 KeyExtractor2 key2;
109};
110
111template <typename id_type> struct LtBit {
112 inline bool operator()(const id_type &valueA, const id_type &valueB) const {
113 return valueA.to_ulong() < valueB.to_ulong();
114 }
115};
116
117template <typename id_type> struct EqBit {
118 inline bool operator()(const id_type &valueA, const id_type &valueB) const {
119 return valueA.to_ulong() == valueB.to_ulong();
120 }
121};
122
123template <typename id_type> struct HashBit {
124 inline unsigned int operator()(const id_type &value) const {
125 return value.to_ulong();
126 }
127};
128
129template <class X> inline std::string toString(X x) {
130 std::ostringstream buffer;
131 buffer << x;
132 return buffer.str();
133}
134/** @} */
135
136/** @name Tensor0 functions
137 * Scalar tensor access helpers.
138 * @{
139 */
140template <int S, class V> struct GetFTensor0FromVecImpl {
141 static inline auto get(V &data) {
142 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0))>>;
143 return FTensor::Tensor0<FTensor::PackPtr<T *, S>>(data.data().data());
144 }
145};
146
147/**
148* \brief Get tensor rank 0 (scalar) form data vector
149
150Example how to use it.
151\code
152VectorDouble vec;
153vec.resize(nb_gauss_pts,false);
154vec.clear();
155auto t0 = getFTensor0FromVec<1>(vec);
156for(int gg = 0;gg!=nb_gauss_pts;gg++) {
157
158 ++t0;
159}
160\endcode
161
162*/
163template <int S = 1, class V> static inline auto getFTensor0FromVec(V &data) {
165}
166
167template <int S, class M> struct GetFTensor0FromMatImpl {
168 static inline auto get(M &data) {
169#ifndef NDEBUG
170 // We can do rows, or columns, does not matter for rank 0 tensor, but we need to be sure that one of them is 1
171 if (data.size1() != 1 && data.size2() != 1)
172 THROW_MESSAGE("getFTensor0FromMat: wrong size of data matrix, number of "
173 "rows should be 1 but is " +
174 boost::lexical_cast<std::string>(data.size1()));
175#endif
176 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
177 return FTensor::Tensor0<FTensor::PackPtr<T *, S>>(data.data().data());
178 }
179};
180
181/**
182* \brief Get tensor rank 0 (scalar) form data vector
183
184Example how to use it.
185\code
186MatrixDouble vec;
187vec.resize(1, nb_gauss_pts, false);
188vec.clear();
189auto t0 = getFTensor0FromMat<1>(vec);
190for(int gg = 0;gg!=nb_gauss_pts;gg++) {
191
192 ++t0;
193}
194\endcode
195
196*/
197template <int S = 1, class M> inline auto getFTensor0FromMat(M &data) {
199}
200
201template <int S = 1, class T, class A>
202inline auto getFTensor0FromMat(boost::weak_ptr<MatrixDouble> data_ptr) {
203#ifndef NDEBUG
204 if (data_ptr.expired())
205 THROW_MESSAGE("getFTensor0FromMat: data pointer expired");
206#endif
207 return GetFTensor0FromMatImpl<S, MatrixDouble>::get(*data_ptr.lock());
208}
209
210template <int S = 1>
211inline auto getFTensor0FromMat(boost::shared_ptr<MatrixDouble> data_ptr) {
212#ifndef NDEBUG
213 if (!data_ptr)
214 THROW_MESSAGE("getFTensor0FromMat: data pointer is not available");
215#endif
217}
218
219/**
220 * \brief Get tensor rank 0 (scalar) from pointer
221 */
222template <int S = 1, class T> static inline auto getFTensor0FromPtr(T *ptr) {
224}
225/** @} */
226
227/** @name Tensor1 functions
228 * Rank-1 tensor construction helpers.
229 * @{
230 */
231template <int Tensor_Dim, int S, class DL, class M>
233
234template <int Tensor_Dim, int S, class M>
235struct GetFTensor1FromMatImpl<Tensor_Dim, S,
237 static inline auto get(M &data, int rr, int cc) {
238 // Preserve const matrix elements in the non-owning tensor view.
239 using T = std::remove_reference_t<decltype(data(0, 0))>;
240 constexpr int stride = S == -1 ? Tensor_Dim : S;
241 static_assert(
242 stride % Tensor_Dim == 0,
243 "getFTensor1FromMat: stride should be a multiple of Tensor_Dim");
244
245#ifndef NDEBUG
246 if (data.size2() != Tensor_Dim)
248 "getFTensor1FromMat<" + boost::lexical_cast<std::string>(Tensor_Dim) +
249 ">: wrong size of data matrix, number of columns should be " +
250 boost::lexical_cast<std::string>(Tensor_Dim) + " but is " +
251 boost::lexical_cast<std::string>(data.size2()));
252 auto *first = &data(rr + 0, cc + 0);
253 auto *last = &data(rr + 0, cc + 0 + Tensor_Dim - 1);
254 if (last - first != Tensor_Dim - 1)
255 THROW_MESSAGE("getFTensor1FromMat<" +
256 boost::lexical_cast<std::string>(Tensor_Dim) +
257 ">: row slice is not contiguous");
258
259#endif
261 &data(rr + 0, cc + 0));
262 }
263};
264
265template <int S, class M>
267 M> {
268 static inline auto get(M &data, int rr, int cc) {
269 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
270 constexpr int stride = S == -1 ? 1 : S;
271
272#ifndef NDEBUG
273 if (data.size1() % 3 != 0)
275 "getFTensor1FromMat<3>: wrong size of data matrix, number of "
276 "rows modulo of 3 but is " +
277 boost::lexical_cast<std::string>(data.size1()));
278#endif
280 &data(rr + 0, cc + 0), &data(rr + 1, cc + 0), &data(rr + 2, cc + 0));
281 }
282};
283
284template <int S, class M>
286 M> {
287 static inline auto get(M &data, int rr, int cc) {
288 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
289 constexpr int stride = S == -1 ? 1 : S;
290#ifndef NDEBUG
291 if (data.size1() % 4 != 0)
293 "getFTensor1FromMat<4>: wrong size of data matrix, number of "
294 "rows should be 4 but is " +
295 boost::lexical_cast<std::string>(data.size1()));
296#endif
298 &data(rr + 0, cc + 0), &data(rr + 1, cc + 0), &data(rr + 2, cc + 0),
299 &data(rr + 3, cc + 0));
300 }
301};
302
303template <int S, class M>
305 M> {
306 static inline auto get(M &data, int rr, int cc) {
307 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
308 constexpr int stride = S == -1 ? 1 : S;
309#ifndef NDEBUG
310 if (data.size1() % 6 != 0)
312 "getFTensor1FromMat<6>: wrong size of data matrix, number of "
313 "rows should be 6 but is " +
314 boost::lexical_cast<std::string>(data.size1()));
315#endif
317 &data(rr + 0, cc + 0), &data(rr + 1, cc + 0), &data(rr + 2, cc + 0),
318 &data(rr + 3, cc + 0), &data(rr + 4, cc + 0), &data(rr + 5, cc + 0));
319 }
320};
321
322template <int S, class M>
324 M> {
325 static inline auto get(M &data, int rr, int cc) {
326 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
327 constexpr int stride = S == -1 ? 1 : S;
328#ifndef NDEBUG
329 if (data.size1() % 9 != 0)
331 "getFTensor1FromMat<9>: wrong size of data matrix, number of "
332 "rows should be 9 but is " +
333 boost::lexical_cast<std::string>(data.size1()));
334#endif
336 &data(rr + 0, cc + 0), &data(rr + 1, cc + 0), &data(rr + 2, cc + 0),
337 &data(rr + 3, cc + 0), &data(rr + 4, cc + 0), &data(rr + 5, cc + 0),
338 &data(rr + 6, cc + 0), &data(rr + 7, cc + 0), &data(rr + 8, cc + 0));
339 }
340};
341
342template <int S, class M>
344 M> {
345 static inline auto get(M &data, int rr, int cc) {
346 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
347 constexpr int stride = S == -1 ? 1 : S;
348#ifndef NDEBUG
349 if (data.size1() % 2 != 0)
351 "getFTensor1FromMat<2>: wrong size of data matrix, number of "
352 "row should be 2 but is " +
353 boost::lexical_cast<std::string>(data.size1()));
354#endif
356 &data(rr + 0, cc + 0), &data(rr + 1, cc + 0));
357 }
358};
359
360template <int S, class M>
362 M> {
363 static inline auto get(M &data, int rr, int cc) {
364 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
365 constexpr int stride = S == -1 ? 1 : S;
367 &data(rr + 0, cc + 0));
368 }
369};
370
371/**
372 * \brief Get tensor rank 1 (vector) form data matrix
373 */
374template <int Tensor_Dim, int S = -1,
375 class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>,
376 class M = MatrixDouble>
377inline auto getFTensor1FromMat(M &data, int rr = 0, int cc = 0) {
379}
380
381template <int Tensor_Dim, int S = -1,
382 class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>,
383 class M = MatrixDouble>
386 std::declval<M &>(), 0, 0));
387
388template <int Tensor_Dim, int S = -1,
390inline auto getFTensor1FromMat(boost::weak_ptr<MatrixDouble> data, int rr = 0,
391 int cc = 0) {
392#ifndef NDEBUG
393 if (!data.lock()) {
395 "Data matrix is not available");
396 }
397#endif
399 *data.lock(), rr, cc);
400}
401
402template <int Tensor_Dim, int S = -1,
403 class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>>
404inline auto getFTensor1FromMat(boost::shared_ptr<MatrixDouble> data, int rr = 0,
405 int cc = 0) {
406#ifndef NDEBUG
407 if (!data) {
409 "Data matrix is not available");
410 }
411#endif
413 cc);
414}
415
416template <int Tensor_Dim, int S = Tensor_Dim, typename T = double>
417inline auto getFTensor1FromPtr(T *ptr) {
418 return FTensor::Tensor1<FTensor::CursorPtr<T *, S>, Tensor_Dim>(ptr);
419}
420
421template <int Tensor_Dim, int S = Tensor_Dim>
422inline auto getFTensor1FromPtr(std::complex<double> *ptr) {
423 return getFTensor1FromPtr<Tensor_Dim, S, std::complex<double>>(ptr);
424}
425
426#ifdef WITH_ADOL_C
427template <int Tensor_Dim, int S = Tensor_Dim>
428inline auto getFTensor1FromPtr(adouble *ptr) {
429 return getFTensor1FromPtr<Tensor_Dim, S, adouble>(ptr);
430}
431#endif
432
433template <int Tensor_Dim, int S = Tensor_Dim, typename T = VectorDouble>
434inline auto getFTensor1FromArray(T &data) {
435 static_assert(S % Tensor_Dim == 0,
436 "getFTensor1FromArray(VectorDouble&) requires S to be a "
437 "multiple of Tensor_Dim");
438
439#ifndef NDEBUG
440 if (data.size() % S != 0) {
442 "getFTensor1FromArray: data size should be divisible by "
443 "pack stride dimension");
444 }
445#endif
446 return getFTensor1FromPtr<Tensor_Dim, S>(data.data().data());
447}
448
449/**
450 * @brief Get FTensor1 from array
451 *
452 * \todo Generalize for different arrays and data types
453 *
454 * @tparam DIM
455 * @param data
456 * @param rr
457 * @return FTensor::Tensor1<FTensor::PackPtr<double *, DIM>, DIM>
458 */
459template <int DIM, int S>
460inline auto getFTensor1FromArrayDiag(MatrixDouble &data, const size_t rr);
461
462template <>
464 const size_t rr) {
465 return FTensor::Tensor1<FTensor::PackPtr<double *, 2>, 2>{&data(rr + 0, 0),
466 &data(rr + 1, 1)};
467}
468
469template <>
471 const size_t rr) {
473 &data(rr + 0, 0), &data(rr + 1, 1), &data(rr + 2, 2)};
474}
475/** @} */
476
477/** @name Tensor2 functions
478 * Rank-2 tensor construction and array helper routines.
479 * @{
480 */
481template <int Tensor_Dim1, int Tensor_Dim2, int S, class DL, class M>
483 static inline auto get(M &data, int rr = 0, int cc = 0) {
484 // Preserve const matrix elements in the non-owning tensor view.
485 using T = std::remove_reference_t<decltype(data(0, 0))>;
486 constexpr int stride =
487 S == -1 ? (DL::isGaussByCoeffs ? Tensor_Dim1 * Tensor_Dim2 : 1) : S;
488 if constexpr (DL::isGaussByCoeffs) {
489 static_assert(stride % (Tensor_Dim1 * Tensor_Dim2) == 0,
490 "getFTensor2FromMat: stride should be a multiple of "
491 "Tensor_Dim1 * Tensor_Dim2");
492
493#ifndef NDEBUG
494 if (data.size2() != Tensor_Dim1 * Tensor_Dim2) {
496 "getFTensor2FromMat<" +
497 boost::lexical_cast<std::string>(Tensor_Dim1) + "," +
498 boost::lexical_cast<std::string>(Tensor_Dim2) +
499 ">: wrong size of columns in data matrix, should be " +
500 boost::lexical_cast<std::string>(Tensor_Dim1 * Tensor_Dim2) +
501 " but is " + boost::lexical_cast<std::string>(data.size2()));
502 }
503 auto *first = &data(rr + 0, cc + 0);
504 auto *last = &data(rr + 0, cc + 0 + Tensor_Dim1 * Tensor_Dim2 - 1);
505 if (last - first != Tensor_Dim1 * Tensor_Dim2 - 1) {
506 THROW_MESSAGE("getFTensor2FromMat<" +
507 boost::lexical_cast<std::string>(Tensor_Dim1) + "," +
508 boost::lexical_cast<std::string>(Tensor_Dim2) +
509 ">: row slice is not contiguous");
510 }
511#endif
513 Tensor_Dim2>(&data(rr + 0, cc + 0));
514 } else if constexpr (DL::isCoeffsByGauss) {
515 std::array<T *, Tensor_Dim1 * Tensor_Dim2> ptrs;
516#ifndef NDEBUG
517 if (data.size1() != Tensor_Dim1 * Tensor_Dim2) {
519 "getFTensor2FromMat<" +
520 boost::lexical_cast<std::string>(Tensor_Dim1) + "," +
521 boost::lexical_cast<std::string>(Tensor_Dim2) +
522 ">: wrong size of rows in data matrix, should be " +
523 boost::lexical_cast<std::string>(Tensor_Dim1 * Tensor_Dim2) +
524 " but is " + boost::lexical_cast<std::string>(data.size1()));
525 }
526#endif
527 for (auto i = 0; i != Tensor_Dim1 * Tensor_Dim2; ++i)
528 ptrs[i] = &data(rr + i, cc + 0);
530 Tensor_Dim2>(ptrs);
531 } else {
532 static_assert(!std::is_same<M, M>::value,
533 "Unsupported data layout for getFTensor2FromMatImpl");
534 }
535 }
536};
537
538/**
539 * \brief Get tensor rank 2 (matrix) form data matrix
540 */
541template <int Tensor_Dim1, int Tensor_Dim2, int S = -1,
542 class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>,
543 class M = MatrixDouble>
547
548template <int Tensor_Dim0, int Tensor_Dim1, int S = -1,
549 class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>,
550 class M = MatrixDouble>
553 std::declval<M &>(), 0, 0));
554
555/**
556 * \brief Get tensor rank 2 (matrix) form data matrix
557 */
558template <int Tensor_Dim1, int Tensor_Dim2, int S = -1,
560inline auto getFTensor2FromMat(boost::weak_ptr<MatrixDouble> data_ptr) {
561#ifndef NDEBUG
562 if (!data_ptr.lock()) {
564 "Data matrix is not available");
565 }
566#endif
567 return GetFTensor2FromMatImpl<Tensor_Dim1, Tensor_Dim2, S, DL,
568 MatrixDouble>::get(*(data_ptr.lock()));
569}
570
571/**
572 * \brief Get tensor rank 2 (matrix) form data matrix
573 */
574template <int Tensor_Dim1, int Tensor_Dim2, int S = -1,
575 class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>>
576inline auto getFTensor2FromMat(boost::shared_ptr<MatrixDouble> data_ptr) {
577#ifndef NDEBUG
578 if (!data_ptr) {
580 "Data matrix is not available");
581 }
582#endif
583 return GetFTensor2FromMatImpl<Tensor_Dim1, Tensor_Dim2, S, DL,
584 MatrixDouble>::get(*data_ptr);
585}
586
587template <int Tensor_Dim1, int Tensor_Dim2, int S = -1>
589 auto matrix_data =
590 getMatrixAdaptor(&data[0], data.size() / Tensor_Dim1 * Tensor_Dim2,
591 Tensor_Dim1 * Tensor_Dim2);
592 return GetFTensor2FromMatImpl<Tensor_Dim1, Tensor_Dim2, S,
594 decltype(matrix_data)>::get(matrix_data);
595}
596
597template <int Tensor_Dim1, int Tensor_Dim2, int S = -1,
598 class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>>
599inline auto getFTensor2FromPtr(double *ptr) {
600 if constexpr (DL::isGaussByCoeffs) {
601 auto matrix_data = getMatrixAdaptor(ptr, 1, Tensor_Dim1 * Tensor_Dim2);
602 return GetFTensor2FromMatImpl<Tensor_Dim1, Tensor_Dim2, S, DL,
603 decltype(matrix_data)>::get(matrix_data);
604 } else if constexpr (DL::isCoeffsByGauss) {
605 auto matrix_data = getMatrixAdaptor(ptr, Tensor_Dim1 * Tensor_Dim2, 1);
606 return GetFTensor2FromMatImpl<Tensor_Dim1, Tensor_Dim2, S, DL,
607 decltype(matrix_data)>::get(matrix_data);
608 }
609}
610
611template <int Tensor_Dim1, int Tensor_Dim2, int S = -1,
612 class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>>
613inline auto getFTensor2FromPtr(std::complex<double> *ptr) {
614 if constexpr (DL::isGaussByCoeffs) {
615 auto matrix_data = getMatrixAdaptor(ptr, 1, Tensor_Dim1 * Tensor_Dim2);
616 return GetFTensor2FromMatImpl<Tensor_Dim1, Tensor_Dim2, S, DL,
617 decltype(matrix_data)>::get(matrix_data);
618 } else if constexpr (DL::isCoeffsByGauss) {
619 auto matrix_data = getMatrixAdaptor(ptr, Tensor_Dim1 * Tensor_Dim2, 1);
620 return GetFTensor2FromMatImpl<Tensor_Dim1, Tensor_Dim2, S, DL,
621 decltype(matrix_data)>::get(matrix_data);
622 }
623}
624
625/**
626 * @brief Make Tensor2 for HVec base from pointer
627 *
628 * @tparam DIM
629 * @param ptr
630 * @return FTensor::Tensor2<FTensor::PackPtr<double *, DIM1 * DIM2>, DIM1, DIM2>
631 */
632template <int DIM1, int DIM2> inline auto getFTensor2HVecFromPtr(double *ptr);
633
634template <> inline auto getFTensor2HVecFromPtr<3, 2>(double *ptr) {
636 ptr + HVEC0_0, ptr + HVEC0_1,
637
638 ptr + HVEC1_0, ptr + HVEC1_1,
639
640 ptr + HVEC2_0, ptr + HVEC2_1);
641}
642
643template <> inline auto getFTensor2HVecFromPtr<3, 3>(double *ptr) {
645 ptr + HVEC0_0, ptr + HVEC0_1, ptr + HVEC0_2,
646
647 ptr + HVEC1_0, ptr + HVEC1_1, ptr + HVEC1_2,
648
649 ptr + HVEC2_0, ptr + HVEC2_1, ptr + HVEC2_2);
650}
651/**
652 * @brief Get FTensor2 from array
653 *
654 * \note Generalize for other data types
655 *
656 * @tparam DIM1
657 * @tparam DIM2
658 * @tparam S
659 * @param data
660 * @return FTensor::Tensor2<FTensor::PackPtr<T *, S>, DIM1, DIM2>
661 */
662template <int DIM1, int DIM2, int S, class M> struct GetFTensor2FromArrayImpl {
664 inline static auto get(M &data, const size_t rr, const size_t cc = 0) {
665 return make(data, rr, cc, std::make_index_sequence<DIM1 * DIM2>{});
666 }
667
668private:
669 template <size_t... Is>
670 inline static auto make(M &data, const size_t rr, const size_t cc,
671 std::index_sequence<Is...>) {
672 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
674 &data(rr + Is / DIM2, cc + Is % DIM2)...};
675 }
676};
677
678/**
679 * @brief Get FTensor2 from array
680 *
681 * \note Generalize for other data types
682 *
683 * @tparam DIM1
684 * @tparam DIM2
685 * @tparam S
686 * @param data
687 * @return FTensor::Tensor2<T *, DIM1, DIM2>
688 */
689template <int DIM1, int DIM2, class M> struct GetFTensor2FromArrayRawPtrImpl;
690
691template <class M> struct GetFTensor2FromArrayRawPtrImpl<2, 2, M> {
693 inline static auto get(M &data, const size_t rr, const size_t cc,
694 const int ss = 0) {
695 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
697 &data(rr + 0, cc + 0), &data(rr + 0, cc + 1),
698
699 &data(rr + 1, cc + 0), &data(rr + 1, cc + 1), ss);
700 }
701};
702
703template <class M> struct GetFTensor2FromArrayRawPtrImpl<3, 3, M> {
705 inline static auto get(M &data, const size_t rr, const size_t cc,
706 const int ss = 0) {
707 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
709 &data(rr + 0, cc + 0), &data(rr + 0, cc + 1), &data(rr + 0, cc + 2),
710 &data(rr + 1, cc + 0), &data(rr + 1, cc + 1), &data(rr + 1, cc + 2),
711 &data(rr + 2, cc + 0), &data(rr + 2, cc + 1), &data(rr + 2, cc + 2),
712 ss);
713 }
714};
715
716template <int DIM1, int DIM2, int S>
717inline auto getFTensor2FromArray(MatrixDouble &data, const size_t rr,
718 const size_t cc = 0) {
720 cc);
721}
722
723template <int DIM1, int DIM2>
724inline auto getFTensor2FromArray(MatrixDouble &data, const size_t rr,
725 const size_t cc, const int ss) {
727 cc, ss);
728}
729
730#ifdef WITH_ADOL_C
731template <int DIM1, int DIM2, int S>
732inline auto getFTensor2FromArray(MatrixADouble &data, const size_t rr) {
734}
735#endif
736/** @} */
737
738/** @name Tensor2_symmetric functions
739 * Symmetric rank-2 tensor construction and conversion helpers.
740 * @{
741 */
742template <int Tensor_Dim, int S, class DL, class M>
744
745template <int Tensor_Dim, int S, class M>
747 Tensor_Dim, S, DataLayoutTraits<DataLayout::GaussByCoeffs>, M> {
748 static inline auto get(M &data, int rr = 0, int cc = 0) {
749 // Preserve const matrix elements in the non-owning tensor view.
750 using T = std::remove_reference_t<decltype(data(0, 0))>;
751 constexpr int symm_size = (Tensor_Dim * (Tensor_Dim + 1)) / 2;
752 constexpr int stride = S == -1 ? symm_size : S;
753 static_assert(stride % symm_size == 0,
754 "getFTensor2SymmetricFromMat: stride should be a multiple of "
755 "symm_size");
756
757#ifndef NDEBUG
758 if (data.size2() != symm_size)
760 "getFTensor2SymmetricFromMat<" +
761 boost::lexical_cast<std::string>(Tensor_Dim) +
762 ">: wrong size of data matrix, number of columns should be " +
763 boost::lexical_cast<std::string>(symm_size) + " but is " +
764 boost::lexical_cast<std::string>(data.size2()));
765 auto *first = &data(rr + 0, cc + 0);
766 auto *last = &data(rr + 0, cc + 0 + symm_size - 1);
767 if (last - first != symm_size - 1)
768 THROW_MESSAGE("getFTensor2SymmetricFromMat<" +
769 boost::lexical_cast<std::string>(Tensor_Dim) +
770 ">: row slice is not contiguous");
771#endif
773 Tensor_Dim>(&data(rr + 0, cc + 0));
774 }
775};
776
777template <int S, class M>
780 static inline auto get(M &data, int rr = 0, int cc = 0) {
781 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
782 constexpr int stride = S == -1 ? 1 : S;
783#ifndef NDEBUG
784 constexpr int symm_size = 6;
785 if (data.size1() != symm_size)
787 "getFTensor2SymmetricFromMat<3>: wrong size of data matrix, "
788 "number of rows should be 6 but is " +
789 boost::lexical_cast<std::string>(data.size1()));
790#endif
792 &data(rr + 0, cc + 0), &data(rr + 1, cc + 0), &data(rr + 2, cc + 0),
793 &data(rr + 3, cc + 0), &data(rr + 4, cc + 0), &data(rr + 5, cc + 0));
794 }
795};
796
797template <int S, class M>
800 static inline auto get(M &data, int rr = 0, int cc = 0) {
801 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
802 constexpr int stride = S == -1 ? 1 : S;
803#ifndef NDEBUG
804 constexpr int symm_size = 3;
805 if (data.size1() != symm_size)
807 "getFTensor2SymmetricFromMat<2>: wrong size of data matrix, "
808 "number of rows should be 3 but is " +
809 boost::lexical_cast<std::string>(data.size1()));
810#endif
812 &data(rr + 0, cc + 0), &data(rr + 1, cc + 0), &data(rr + 2, cc + 0));
813 }
814};
815
816/**
817 * \brief Get symmetric tensor rank 2 (matrix) form data matrix
818 */
819template <int Tensor_Dim, int S = -1,
820 class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>,
821 class M = MatrixDouble>
825
826template <int Tensor_Dim, int S = -1,
827 class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>,
828 class M = MatrixDouble>
831 std::declval<M &>(), 0, 0));
832
833template <int Tensor_Dim, int S = -1,
835static inline auto
836getFTensor2SymmetricFromMat(boost::weak_ptr<MatrixDouble> data_ptr) {
837#ifndef NDEBUG
838 if (data_ptr.expired()) {
840 "Data matrix is not available");
841 }
842#endif
844 *data_ptr.lock());
845}
846
847template <int Tensor_Dim, int S = -1,
848 class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>>
849static inline auto
850getFTensor2SymmetricFromMat(boost::shared_ptr<MatrixDouble> data_ptr) {
851#ifndef NDEBUG
852 if (!data_ptr) {
854 "Data matrix is not available");
855 }
856#endif
858 *data_ptr);
859}
860
861template <int Tensor_Dim> inline auto getFTensor2SymmetricFromPtr(double *ptr) {
862 auto matrix_data =
863 getMatrixAdaptor(ptr, 1, Tensor_Dim * (Tensor_Dim + 1) / 2);
866 decltype(matrix_data)>::get(matrix_data, 0, 0);
867}
868
869#ifdef WITH_ADOL_C
870template <int Tensor_Dim>
872 auto matrix_data =
873 getMatrixAdaptor(ptr, 1, Tensor_Dim * (Tensor_Dim + 1) / 2);
876 decltype(matrix_data)>::get(matrix_data, 0, 0);
877}
878#endif
879/**
880 * @brief Make symmetric Tensor2 from pointer, taking lower triangle of matrix
881 *
882 * @tparam DIM
883 * @param ptr
884 * @return FTensor::Tensor2<FTensor::PackPtr<double *, DIM1 * DIM2>, DIM1, DIM2>
885 */
886template <int DIM> inline auto getFTensor2SymmetricLowerFromPtr(double *ptr);
887
888template <> inline auto getFTensor2SymmetricLowerFromPtr<3>(double *ptr) {
890 ptr + HVEC0_0, ptr + HVEC0_1, ptr + HVEC0_2,
891
892 ptr + HVEC1_0, ptr + HVEC1_1,
893
894 ptr + HVEC2_2);
895};
896
897template <> inline auto getFTensor2SymmetricLowerFromPtr<2>(double *ptr) {
899 ptr + 0, ptr + 1, ptr + 3);
900};
901// Template function for conversion of symmetric tensor to non-symmetric
902
903template <int DIM, class T>
906 FTensor::Index<'i', DIM> i;
907 FTensor::Index<'j', DIM> j;
908 full(i, j) = symm(i, j);
909 return full;
910}
911/** @} */
912
913/** @name Tensor3 functions
914 * Rank-3 tensor construction helpers.
915 * @{
916 */
917template <int Tensor_Dim0, int Tensor_Dim1, int Tensor_Dim2, int S, class DL,
918 class M>
920
921template <int Tensor_Dim0, int Tensor_Dim1, int Tensor_Dim2, int S, class M>
922struct GetFTensor3FromMatImpl<Tensor_Dim0, Tensor_Dim1, Tensor_Dim2, S,
924 static inline auto get(M &data, int rr = 0, int cc = 0) {
925 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
926 constexpr int tensor_size = Tensor_Dim0 * Tensor_Dim1 * Tensor_Dim2;
927 constexpr int stride = S == -1 ? tensor_size : S;
928 static_assert(
929 stride % tensor_size == 0,
930 "getFTensor3FromMat: stride should be a multiple of tensor_size");
931
932#ifndef NDEBUG
933 if (data.size2() != tensor_size) {
934 THROW_MESSAGE("getFTensor3FromMat<" +
935 boost::lexical_cast<std::string>(Tensor_Dim0) + "," +
936 boost::lexical_cast<std::string>(Tensor_Dim1) + "," +
937 boost::lexical_cast<std::string>(Tensor_Dim2) +
938 ">: wrong size of columns in data matrix, should be " +
939 boost::lexical_cast<std::string>(tensor_size) + " but is " +
940 boost::lexical_cast<std::string>(data.size2()));
941 }
942 auto *first = &data(rr + 0, cc + 0);
943 auto *last = &data(rr + 0, cc + 0 + tensor_size - 1);
944 if (last - first != tensor_size - 1)
945 THROW_MESSAGE("getFTensor3FromMat<" +
946 boost::lexical_cast<std::string>(Tensor_Dim0) + "," +
947 boost::lexical_cast<std::string>(Tensor_Dim1) + "," +
948 boost::lexical_cast<std::string>(Tensor_Dim2) +
949 ">: row slice is not contiguous");
950#endif
952 Tensor_Dim1, Tensor_Dim2>{&data(rr + 0, cc + 0)};
953 }
954};
955
956template <int Tensor_Dim0, int Tensor_Dim1, int Tensor_Dim2, int S, class M>
957struct GetFTensor3FromMatImpl<Tensor_Dim0, Tensor_Dim1, Tensor_Dim2, S,
959 static inline auto get(M &data, int rr = 0, int cc = 0) {
960 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
961 constexpr int tensor_size = Tensor_Dim0 * Tensor_Dim1 * Tensor_Dim2;
962 constexpr int stride = S == -1 ? 1 : S;
963 std::array<T *, tensor_size> ptrs;
964#ifndef NDEBUG
965 if (data.size1() != tensor_size) {
966 THROW_MESSAGE("getFTensor3FromMat<" +
967 boost::lexical_cast<std::string>(Tensor_Dim0) + "," +
968 boost::lexical_cast<std::string>(Tensor_Dim1) + "," +
969 boost::lexical_cast<std::string>(Tensor_Dim2) +
970 ">: wrong size of rows in data matrix, should be " +
971 boost::lexical_cast<std::string>(tensor_size) + " but is " +
972 boost::lexical_cast<std::string>(data.size1()));
973 }
974#endif
975 for (auto i = 0; i != tensor_size; ++i)
976 ptrs[i] = &data(rr + i, cc + 0);
978 Tensor_Dim1, Tensor_Dim2>(ptrs);
979 }
980};
981
982/**
983 * @brief Get tensor rank 3 (non symmetries) form data matrix
984 *
985 * @tparam Tensor_Dim0 dimension of first index
986 * @tparam Tensor_Dim1 dimension of second index
987 * @tparam Tensor_Dim2 dimension of third index
988 * @tparam S shift size
989 * @tparam DL data layout
990 * @tparam M matrix type
991 * @param data data container
992 * @return FTensor::Tensor3<FTensor::PackPtr<T *, S>, Tensor_Dim0,
993 Tensor_Dim1, Tensor_Dim2>
994 */
995template <int Tensor_Dim0, int Tensor_Dim1, int Tensor_Dim2, int S = -1,
996 class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>,
997 class M = MatrixDouble>
998static inline auto getFTensor3FromMat(M &data, int rr = 0, int cc = 0) {
999 return GetFTensor3FromMatImpl<Tensor_Dim0, Tensor_Dim1, Tensor_Dim2, S, DL,
1000 M>::get(data, rr, cc);
1001}
1002
1003template <int Tensor_Dim0, int Tensor_Dim1, int Tensor_Dim2, int S = -1,
1004 class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>,
1005 class M = MatrixDouble>
1007 decltype(GetFTensor3FromMatImpl<Tensor_Dim0, Tensor_Dim1, Tensor_Dim2, S,
1008 DL, M>::get(std::declval<M &>(), 0, 0));
1009
1010template <int Tensor_Dim0, int Tensor_Dim1, int Tensor_Dim2, int S = -1,
1012static inline auto getFTensor3FromMat(boost::weak_ptr<MatrixDouble> data_ptr,
1013 int rr = 0, int cc = 0) {
1014#ifndef NDEBUG
1015 if (!data_ptr.lock()) {
1017 "Data matrix is not available");
1018 }
1019#endif
1020 return GetFTensor3FromMatImpl<Tensor_Dim0, Tensor_Dim1, Tensor_Dim2, S, DL,
1021 MatrixDouble>::get(*data_ptr.lock(), rr, cc);
1022}
1023
1024template <int Tensor_Dim0, int Tensor_Dim1, int Tensor_Dim2, int S = -1,
1025 class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>>
1026static inline auto getFTensor3FromMat(boost::shared_ptr<MatrixDouble> data_ptr,
1027 int rr = 0, int cc = 0) {
1028#ifndef NDEBUG
1029 if (!data_ptr) {
1031 "Data matrix is not available");
1032 }
1033#endif
1034 return GetFTensor3FromMatImpl<Tensor_Dim0, Tensor_Dim1, Tensor_Dim2, S, DL,
1035 MatrixDouble>::get(*data_ptr, rr, cc);
1036}
1037/*
1038 * @brief Make Tensor3 from pointer
1039 *
1040 * @tparam DIM
1041 * @param ptr
1042 * @return FTensor::Tensor3<FTensor::PackPtr<double *, DIM1 * DIM2* DIM3>, DIM1,
1043 * DIM2, DIM3>
1044 */
1045template <int DIM1, int DIM2, int DIM3>
1047 DIM2, DIM3>
1049 static_assert(DIM1 == DIM1 || DIM2 != DIM2 || DIM3 != DIM3,
1050 "Such getFTensor3FromPtr is not implemented");
1051}
1052
1053template <>
1055getFTensor3FromPtr<3, 2, 2>(double *ptr) {
1057 ptr + 0, ptr + 1, ptr + 2, ptr + 3, ptr + 4, ptr + 5, ptr + 6, ptr + 7,
1058 ptr + 8, ptr + 9, ptr + 10, ptr + 11);
1059}
1060
1061template <>
1063getFTensor3FromPtr<3, 3, 3>(double *ptr) {
1065 ptr + 0, ptr + 1, ptr + 2, ptr + 3, ptr + 4, ptr + 5, ptr + 6, ptr + 7,
1066 ptr + 8, ptr + 9, ptr + 10, ptr + 11, ptr + 12, ptr + 13, ptr + 14,
1067 ptr + 15, ptr + 16, ptr + 17, ptr + 18, ptr + 19, ptr + 20, ptr + 21,
1068 ptr + 22, ptr + 23, ptr + 24, ptr + 25, ptr + 26);
1069}
1070/** @} */
1071
1072/** @name Dg functions
1073 * Helpers for third-order tensors symmetric in the first two indices.
1074 * @{
1075 */
1076template <int Tensor_Dim01, int Tensor_Dim2, int S, class DL, class M>
1078
1079template <int Tensor_Dim01, int Tensor_Dim2, int S, class M>
1080struct GetFTensor3DgFromMatImpl<Tensor_Dim01, Tensor_Dim2, S,
1082 M> {
1083 static inline auto get(M &data, int rr = 0, int cc = 0) {
1084 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
1085 constexpr int symm_size_01 = (Tensor_Dim01 * (Tensor_Dim01 + 1)) / 2;
1086 constexpr int dg_size = symm_size_01 * Tensor_Dim2;
1087 constexpr int stride = S == -1 ? dg_size : S;
1088 static_assert(
1089 stride % dg_size == 0,
1090 "getFTensor3DgFromMat: stride should be a multiple of dg_size");
1091
1092#ifndef NDEBUG
1093 if (data.size2() != dg_size) {
1095 "getFTensor3DgFromMat<" +
1096 boost::lexical_cast<std::string>(Tensor_Dim01) + ", " +
1097 boost::lexical_cast<std::string>(Tensor_Dim2) +
1098 ">: wrong size of data matrix, number of columns should be " +
1099 boost::lexical_cast<std::string>(dg_size) + " but is " +
1100 boost::lexical_cast<std::string>(data.size2()));
1101 }
1102 auto *first = &data(rr + 0, cc + 0);
1103 auto *last = &data(rr + 0, cc + 0 + dg_size - 1);
1104 if (last - first != dg_size - 1)
1105 THROW_MESSAGE("getFTensor3DgFromMat<" +
1106 boost::lexical_cast<std::string>(Tensor_Dim01) + ", " +
1107 boost::lexical_cast<std::string>(Tensor_Dim2) +
1108 ">: row slice is not contiguous");
1109#endif
1111 Tensor_Dim2>{&data(rr + 0, cc + 0)};
1112 }
1113};
1114
1115template <int S, class M>
1118 static inline auto get(M &data, int rr = 0, int cc = 0) {
1119 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
1120 constexpr int stride = S == -1 ? 1 : S;
1121
1122#ifndef NDEBUG
1123 constexpr int dg_size = 1;
1124 if (data.size1() != dg_size)
1126 "getFTensor3DgFromMat<1, 1>: wrong size of data matrix, number "
1127 "of rows should be 1 but is " +
1128 boost::lexical_cast<std::string>(data.size1()));
1129#endif
1131 &data(rr + 0, cc + 0)};
1132 }
1133};
1134
1135template <int S, class M>
1138 static inline auto get(M &data, int rr = 0, int cc = 0) {
1139 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
1140 constexpr int stride = S == -1 ? 1 : S;
1141#ifndef NDEBUG
1142 constexpr int dg_size = 6;
1143 if (data.size1() != dg_size) {
1145 "getFTensor3DgFromMat<2, 2>: wrong size of data matrix, number "
1146 "of rows should be 6 but is " +
1147 boost::lexical_cast<std::string>(data.size1()));
1148 }
1149#endif
1151 &data(rr + 0, cc + 0), &data(rr + 1, cc + 0), &data(rr + 2, cc + 0),
1152 &data(rr + 3, cc + 0), &data(rr + 4, cc + 0), &data(rr + 5, cc + 0)};
1153 }
1154};
1155
1156template <int S, class M>
1159 static inline auto get(M &data, int rr = 0, int cc = 0) {
1160 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
1161 constexpr int stride = S == -1 ? 1 : S;
1162#ifndef NDEBUG
1163 constexpr int dg_size = 18;
1164 if (data.size1() != dg_size) {
1166 "getFTensor3DgFromMat<3, 3>: wrong size of data matrix, number "
1167 "of rows should be 18 but is " +
1168 boost::lexical_cast<std::string>(data.size1()));
1169 }
1170#endif
1172 &data(rr + 0, cc + 0), &data(rr + 1, cc + 0), &data(rr + 2, cc + 0),
1173 &data(rr + 3, cc + 0), &data(rr + 4, cc + 0), &data(rr + 5, cc + 0),
1174 &data(rr + 6, cc + 0), &data(rr + 7, cc + 0), &data(rr + 8, cc + 0),
1175 &data(rr + 9, cc + 0), &data(rr + 10, cc + 0), &data(rr + 11, cc + 0),
1176 &data(rr + 12, cc + 0), &data(rr + 13, cc + 0), &data(rr + 14, cc + 0),
1177 &data(rr + 15, cc + 0), &data(rr + 16, cc + 0), &data(rr + 17, cc + 0)};
1178 }
1179};
1180
1181/**
1182 * @brief Get symmetric tensor rank 3 on the first two indices from
1183 * form data matrix
1184 *
1185 * @tparam Tensor_Dim01 dimension of first two indicies
1186 * @tparam Tensor_Dim2 dimension of last index
1187 * @tparam S Memory shift
1188 * @tparam DL data layout
1189 * @tparam M matrix type
1190 * @param data data container
1191 * @return FTensor::Dg<FTensor::PackPtr<T *, S>, Tensor_Dim01, Tensor_Dim2>
1192 */
1193template <int Tensor_Dim01, int Tensor_Dim2, int S = -1,
1194 class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>,
1195 class M = MatrixDouble>
1196static inline auto getFTensor3DgFromMat(M &data) {
1198 data);
1199}
1200
1201template <int Tensor_Dim01, int Tensor_Dim2, int S = -1,
1202 class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>,
1203 class M = MatrixDouble>
1206 std::declval<M &>(), 0, 0));
1207
1208template <int Tensor_Dim01, int Tensor_Dim2, int S = -1,
1210static inline auto
1211getFTensor3DgFromMat(boost::weak_ptr<MatrixDouble> data_ptr) {
1212#ifndef NDEBUG
1213 if (!data_ptr.lock()) {
1215 "Data matrix is not available");
1216 }
1217#endif
1218 return GetFTensor3DgFromMatImpl<Tensor_Dim01, Tensor_Dim2, S, DL,
1219 MatrixDouble>::get(*(data_ptr.lock()));
1220}
1221
1222template <int Tensor_Dim01, int Tensor_Dim2, int S = -1,
1223 class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>>
1224static inline auto
1225getFTensor3DgFromMat(boost::shared_ptr<MatrixDouble> data_ptr) {
1226#ifndef NDEBUG
1227 if (!data_ptr) {
1229 "Data matrix is not available");
1230 }
1231#endif
1232 return GetFTensor3DgFromMatImpl<Tensor_Dim01, Tensor_Dim2, S, DL,
1233 MatrixDouble>::get(*data_ptr);
1234}
1235
1236template <int Tensor_Dim01, int Tensor_Dim2, int S, class T = double>
1237static inline auto getFTensor3DgFromPtr(T *ptr) {
1238 constexpr auto dg_size =
1239 ((Tensor_Dim01 * (Tensor_Dim01 + 1)) / 2) * Tensor_Dim2;
1240 auto matrix_data = getMatrixAdaptor(ptr, 1, dg_size);
1241 return GetFTensor3DgFromMatImpl<Tensor_Dim01, Tensor_Dim2, S,
1243 decltype(matrix_data)>::get(matrix_data);
1244}
1245/** @} */
1246
1247/** @name Tensor4 functions
1248 * Rank-4 tensor construction helpers.
1249 * @{
1250 */
1251template <class T, int Tensor_Dim0, int Tensor_Dim1, int Tensor_Dim2,
1252 int Tensor_Dim3, int S, std::size_t... Is>
1253static inline auto makeFTensor4FromPtrArray(
1254 const std::array<T *, Tensor_Dim0 * Tensor_Dim1 * Tensor_Dim2 * Tensor_Dim3>
1255 &ptrs,
1256 std::index_sequence<Is...>) {
1257 return FTensor::Tensor4<FTensor::PackPtr<T *, S>, Tensor_Dim0, Tensor_Dim1,
1258 Tensor_Dim2, Tensor_Dim3>(ptrs[Is]...);
1259}
1260
1261template <int Tensor_Dim0, int Tensor_Dim1, int Tensor_Dim2, int Tensor_Dim3,
1262 int S, class DL, class M>
1264 static inline auto get(M &data, int rr = 0, int cc = 0) {
1265 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
1266 constexpr int tensor_size =
1267 Tensor_Dim0 * Tensor_Dim1 * Tensor_Dim2 * Tensor_Dim3;
1268 constexpr int stride =
1269 S == -1 ? (DL::isGaussByCoeffs ? tensor_size : 1) : S;
1270 if constexpr (DL::isGaussByCoeffs) {
1271 static_assert(
1272 stride % tensor_size == 0,
1273 "getFTensor4FromMat: stride should be a multiple of tensor_size");
1274
1275#ifndef NDEBUG
1276 if (data.size2() != tensor_size) {
1277 THROW_MESSAGE("getFTensor4FromMat<" +
1278 boost::lexical_cast<std::string>(Tensor_Dim0) + "," +
1279 boost::lexical_cast<std::string>(Tensor_Dim1) + "," +
1280 boost::lexical_cast<std::string>(Tensor_Dim2) + "," +
1281 boost::lexical_cast<std::string>(Tensor_Dim3) +
1282 ">: wrong size of columns in data matrix, should be " +
1283 boost::lexical_cast<std::string>(tensor_size) +
1284 " but is " +
1285 boost::lexical_cast<std::string>(data.size2()));
1286 }
1287 auto *first = &data(rr + 0, cc + 0);
1288 auto *last = &data(rr + 0, cc + 0 + tensor_size - 1);
1289 if (last - first != tensor_size - 1) {
1290 THROW_MESSAGE("getFTensor4FromMat<" +
1291 boost::lexical_cast<std::string>(Tensor_Dim0) + "," +
1292 boost::lexical_cast<std::string>(Tensor_Dim1) + "," +
1293 boost::lexical_cast<std::string>(Tensor_Dim2) + "," +
1294 boost::lexical_cast<std::string>(Tensor_Dim3) +
1295 ">: row slice is not contiguous");
1296 }
1297#endif
1299 Tensor_Dim1, Tensor_Dim2, Tensor_Dim3>{
1300 &data(rr + 0, cc + 0)};
1301 } else if constexpr (DL::isCoeffsByGauss) {
1302 std::array<T *, tensor_size> ptrs;
1303#ifndef NDEBUG
1304 if (data.size1() != tensor_size) {
1305 THROW_MESSAGE("getFTensor4FromMat<" +
1306 boost::lexical_cast<std::string>(Tensor_Dim0) + "," +
1307 boost::lexical_cast<std::string>(Tensor_Dim1) + "," +
1308 boost::lexical_cast<std::string>(Tensor_Dim2) + "," +
1309 boost::lexical_cast<std::string>(Tensor_Dim3) +
1310 ">: wrong size of rows in data matrix, should be " +
1311 boost::lexical_cast<std::string>(tensor_size) +
1312 " but is " +
1313 boost::lexical_cast<std::string>(data.size1()));
1314 }
1315#endif
1316 for (auto i = 0; i != tensor_size; ++i)
1317 ptrs[i] = &data(rr + i, cc + 0);
1318 return makeFTensor4FromPtrArray<T, Tensor_Dim0, Tensor_Dim1, Tensor_Dim2,
1319 Tensor_Dim3, stride>(
1320 ptrs, std::make_index_sequence<tensor_size>{});
1321 } else {
1322 static_assert(!std::is_same<M, M>::value,
1323 "Unsupported data layout for getFTensor4FromMatImpl");
1324 }
1325 }
1326};
1327
1328/**
1329 * @brief Get tensor rank 4 (non symmetric) form data matrix
1330 *
1331 * @tparam Tensor_Dim0 dimension of first index
1332 * @tparam Tensor_Dim1 dimension of second index
1333 * @tparam Tensor_Dim2 dimension of third index
1334 * @tparam Tensor_Dim3 dimension of fourth index
1335 * @tparam S Memory shift
1336 * @tparam DL Data layout
1337 * @tparam M Matrix type
1338 * @param data data container
1339 * @return FTensor tensor rank 4 view matching the selected data layout
1340 */
1341template <int Tensor_Dim0, int Tensor_Dim1, int Tensor_Dim2, int Tensor_Dim3,
1342 int S = -1, class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>,
1343 class M = MatrixDouble>
1344static inline auto getFTensor4FromMat(M &data) {
1345 return GetFTensor4FromMatImpl<Tensor_Dim0, Tensor_Dim1, Tensor_Dim2,
1346 Tensor_Dim3, S, DL, M>::get(data);
1347}
1348
1349template <int Tensor_Dim0, int Tensor_Dim1, int Tensor_Dim2, int Tensor_Dim3,
1350 int S = -1, class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>,
1351 class M = MatrixDouble>
1353 decltype(GetFTensor4FromMatImpl<Tensor_Dim0, Tensor_Dim1, Tensor_Dim2,
1354 Tensor_Dim3, S, DL,
1355 M>::get(std::declval<M &>(), 0, 0));
1356
1357template <int Tensor_Dim0, int Tensor_Dim1, int Tensor_Dim2, int Tensor_Dim3,
1358 int S = -1, class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>>
1359static inline auto getFTensor4FromMat(boost::weak_ptr<MatrixDouble> data_ptr) {
1360#ifndef NDEBUG
1361 if (!data_ptr.lock()) {
1363 "Data matrix is not available");
1364 }
1365#endif
1366 return GetFTensor4FromMatImpl<Tensor_Dim0, Tensor_Dim1, Tensor_Dim2,
1367 Tensor_Dim3, S, DL,
1368 MatrixDouble>::get(*data_ptr.lock());
1369}
1370
1371template <int Tensor_Dim0, int Tensor_Dim1, int Tensor_Dim2, int Tensor_Dim3,
1372 int S = -1, class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>>
1373static inline auto
1374getFTensor4FromMat(boost::shared_ptr<MatrixDouble> data_ptr) {
1375#ifndef NDEBUG
1376 if (!data_ptr) {
1378 "Data matrix is not available");
1379 }
1380#endif
1381 return GetFTensor4FromMatImpl<Tensor_Dim0, Tensor_Dim1, Tensor_Dim2,
1382 Tensor_Dim3, S, DL,
1383 MatrixDouble>::get(*data_ptr);
1384}
1385
1386template <int DIM1, int DIM2, int DIM3, int DIM4, int S = -1, class T = double>
1387inline auto getFTensor4FromPtr(T *ptr) {
1388 auto matrix_data = getMatrixAdaptor(ptr, 1, DIM1 * DIM2 * DIM3 * DIM4);
1389 return GetFTensor4FromMatImpl<DIM1, DIM2, DIM3, DIM4, S,
1391 decltype(matrix_data)>::get(matrix_data);
1392}
1393/** @} */
1394
1395/** @name Ddg functions
1396 * Helpers for fourth-order tensors symmetric in index pairs.
1397 * @{
1398 */
1399template <int Tensor_Dim01, int Tensor_Dim23, int S, class DL, class M>
1401
1402template <int Tensor_Dim01, int Tensor_Dim23, int S, class M>
1403struct GetFTensor4DdgFromMatImpl<Tensor_Dim01, Tensor_Dim23, S,
1405 M> {
1406 static inline auto get(M &data, int rr = 0, int cc = 0) {
1407 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
1408 constexpr int symm_size_01 = (Tensor_Dim01 * (Tensor_Dim01 + 1)) / 2;
1409 constexpr int symm_size_23 = (Tensor_Dim23 * (Tensor_Dim23 + 1)) / 2;
1410 constexpr int ddg_size = symm_size_01 * symm_size_23;
1411 constexpr int stride = S == -1 ? ddg_size : S;
1412 static_assert(
1413 stride % ddg_size == 0,
1414 "Stride should be a multiple of the size of the symmetric tensor");
1415
1416#ifndef NDEBUG
1417 if (data.size2() != ddg_size) {
1419 "getFTensor4DdgFromMat<" +
1420 boost::lexical_cast<std::string>(Tensor_Dim01) + ", " +
1421 boost::lexical_cast<std::string>(Tensor_Dim23) +
1422 ">: wrong size of data matrix, number of columns should be " +
1423 boost::lexical_cast<std::string>(ddg_size) + " but is " +
1424 boost::lexical_cast<std::string>(data.size2()));
1425 }
1426 auto *first = &data(rr + 0, cc + 0);
1427 auto *last = &data(rr + 0, cc + 0 + ddg_size - 1);
1428 if (last - first != ddg_size - 1)
1429 THROW_MESSAGE("getFTensor4DdgFromMat<" +
1430 boost::lexical_cast<std::string>(Tensor_Dim01) + ", " +
1431 boost::lexical_cast<std::string>(Tensor_Dim23) +
1432 ">: row slice is not contiguous");
1433#endif
1435 Tensor_Dim23>{&data(rr + 0, cc + 0)};
1436 }
1437};
1438
1439template <int S, class M>
1442 static inline auto get(M &data, int rr = 0, int cc = 0) {
1443 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
1444 constexpr int stride = S == -1 ? 1 : S;
1445#ifndef NDEBUG
1446 constexpr int ddg_size = 1;
1447 if (data.size1() != ddg_size)
1449 "getFTensor4DdgFromMat<1, 1>: wrong size of data matrix, number "
1450 "of rows should be 1 but is " +
1451 boost::lexical_cast<std::string>(data.size1()));
1452#endif
1454 &data(rr + 0, cc + 0)};
1455 }
1456};
1457
1458template <int S, class M>
1461 static inline auto get(M &data, int rr = 0, int cc = 0) {
1462 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
1463 constexpr int stride = S == -1 ? 1 : S;
1464#ifndef NDEBUG
1465 constexpr int ddg_size = 9;
1466 if (data.size1() != ddg_size) {
1468 "getFTensor4DdgFromMat<2, 2>: wrong size of data matrix, number "
1469 "of rows should be 9 but is " +
1470 boost::lexical_cast<std::string>(data.size1()));
1471 }
1472#endif
1474 &data(rr + 0, cc + 0), &data(rr + 1, cc + 0), &data(rr + 2, cc + 0),
1475 &data(rr + 3, cc + 0), &data(rr + 4, cc + 0), &data(rr + 5, cc + 0),
1476 &data(rr + 6, cc + 0), &data(rr + 7, cc + 0), &data(rr + 8, cc + 0)};
1477 }
1478};
1479
1480template <int S, class M>
1483 static inline auto get(M &data, int rr = 0, int cc = 0) {
1484 using T = std::remove_cv_t<std::remove_reference_t<decltype(data(0, 0))>>;
1485 constexpr int stride = S == -1 ? 1 : S;
1486#ifndef NDEBUG
1487 constexpr int ddg_size = 36;
1488 if (data.size1() != ddg_size) {
1490 "getFTensor4DdgFromMat<3, 3>: wrong size of data matrix, number "
1491 "of rows should be 36 but is " +
1492 boost::lexical_cast<std::string>(data.size1()));
1493 }
1494#endif
1496 &data(rr + 0, cc + 0), &data(rr + 1, cc + 0), &data(rr + 2, cc + 0),
1497 &data(rr + 3, cc + 0), &data(rr + 4, cc + 0), &data(rr + 5, cc + 0),
1498 &data(rr + 6, cc + 0), &data(rr + 7, cc + 0), &data(rr + 8, cc + 0),
1499 &data(rr + 9, cc + 0), &data(rr + 10, cc + 0), &data(rr + 11, cc + 0),
1500 &data(rr + 12, cc + 0), &data(rr + 13, cc + 0), &data(rr + 14, cc + 0),
1501 &data(rr + 15, cc + 0), &data(rr + 16, cc + 0), &data(rr + 17, cc + 0),
1502 &data(rr + 18, cc + 0), &data(rr + 19, cc + 0), &data(rr + 20, cc + 0),
1503 &data(rr + 21, cc + 0), &data(rr + 22, cc + 0), &data(rr + 23, cc + 0),
1504 &data(rr + 24, cc + 0), &data(rr + 25, cc + 0), &data(rr + 26, cc + 0),
1505 &data(rr + 27, cc + 0), &data(rr + 28, cc + 0), &data(rr + 29, cc + 0),
1506 &data(rr + 30, cc + 0), &data(rr + 31, cc + 0), &data(rr + 32, cc + 0),
1507 &data(rr + 33, cc + 0), &data(rr + 34, cc + 0), &data(rr + 35, cc + 0)};
1508 }
1509};
1510
1511/**
1512 * @brief Get symmetric tensor rank 4 on first two and last indices from
1513 * form data matrix
1514 *
1515 * @tparam Tensor_Dim01 dimension of first two indicies
1516 * @tparam Tensor_Dim23 dimension of second two indicies
1517 * @tparam Memory shift
1518 * @tparam M matrix type
1519 * @param data data container
1520 * @return FTensor::Ddg<FTensor::PackPtr<T *, S>, Tensor_Dim01, TensorDim23>
1521 */
1522template <int Tensor_Dim01, int Tensor_Dim23, int S = -1,
1523 class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>,
1524 class M = MatrixDouble>
1529
1530template <int Tensor_Dim01, int Tensor_Dim23, int S = -1,
1531 class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>,
1532 class M = MatrixDouble>
1534 decltype(GetFTensor4DdgFromMatImpl<Tensor_Dim01, Tensor_Dim23, S, DL,
1535 M>::get(std::declval<M &>(), 0, 0));
1536
1537template <int Tensor_Dim01, int Tensor_Dim23, int S = -1,
1539static inline auto getFTensor4DdgFromMat(boost::weak_ptr<MatrixDouble> data) {
1540#ifndef NDEBUG
1541 if (!data.lock()) {
1543 "Data matrix is not available");
1544 }
1545#endif
1546 return GetFTensor4DdgFromMatImpl<Tensor_Dim01, Tensor_Dim23, S, DL,
1547 MatrixDouble>::get(*data.lock());
1548}
1549
1550template <int Tensor_Dim01, int Tensor_Dim23, int S = -1,
1551 class DL = DataLayoutTraits<DataLayout::GaussByCoeffs>>
1552static inline auto
1553getFTensor4DdgFromMat(boost::shared_ptr<MatrixDouble> data_ptr) {
1554#ifndef NDEBUG
1555 if (!data_ptr) {
1557 "Data matrix is not available");
1558 }
1559#endif
1560 return GetFTensor4DdgFromMatImpl<Tensor_Dim01, Tensor_Dim23, S, DL,
1561 MatrixDouble>::get(*data_ptr);
1562}
1563
1564template <int Tensor_Dim01, int Tensor_Dim23, int S, class T = double>
1565static inline auto getFTensor4DdgFromPtr(T *ptr) {
1566 constexpr auto symm_size01 = (Tensor_Dim01 * (Tensor_Dim01 + 1)) / 2;
1567 constexpr auto symm_size23 = (Tensor_Dim23 * (Tensor_Dim23 + 1)) / 2;
1568 constexpr auto symm_size = symm_size01 * symm_size23;
1569 auto matrix_data = getMatrixAdaptor(ptr, 1, symm_size);
1570 return GetFTensor4DdgFromMatImpl<Tensor_Dim01, Tensor_Dim23, S,
1572 decltype(matrix_data)>::get(matrix_data);
1573}
1574/** @} */
1575
1576/** @name Matrix sizeing helpers
1577 * Matrix size helpers
1578 * @{
1579*/
1580
1581template <class Tensor, class DL> struct MatrixSizeHelper;
1582
1583template <class T, int S, int Tensor_Dim>
1585 FTensor::Tensor1<FTensor::CursorPtr<T *, S>, Tensor_Dim>,
1586 DataLayoutTraits<DataLayout::GaussByCoeffs>> {
1587 template <class M>
1588 static inline auto size(M &m, const size_t nb_integration_pts) {
1589 if (m.size1() != nb_integration_pts || m.size2() != Tensor_Dim) {
1590 m.resize(nb_integration_pts, Tensor_Dim, false);
1591 }
1592 return [&m]() {
1593 return GetFTensor1FromMatImpl<Tensor_Dim, S,
1595 M>::get(m, 0, 0);
1596 };
1597 }
1598 template <class M>
1599 static inline auto get(M &m,
1600 [[maybe_unused]] const size_t nb_integration_pts) {
1601#ifndef NDEBUG
1602 if (S == -1 || S == Tensor_Dim) {
1603 if (m.size1() != nb_integration_pts) {
1606 "Matrix size is not compatible with the number of "
1607 "integration points: expected " +
1608 boost::lexical_cast<std::string>(nb_integration_pts) +
1609 " but got " + boost::lexical_cast<std::string>(m.size1()));
1610 }
1611 }
1612#endif
1613 return [&m]() {
1614 return GetFTensor1FromMatImpl<Tensor_Dim, S,
1616 M>::get(m, 0, 0);
1617 };
1618 }
1619};
1620
1621template <class T, int S, int Tensor_Dim0, int Tensor_Dim1>
1623 FTensor::Tensor2<FTensor::CursorPtr<T *, S>, Tensor_Dim0, Tensor_Dim1>,
1624 DataLayoutTraits<DataLayout::GaussByCoeffs>> {
1625 template <class M>
1626 static inline auto size(M &m, const size_t nb_integration_pts) {
1627 if (m.size1() != nb_integration_pts ||
1628 m.size2() != Tensor_Dim0 * Tensor_Dim1) {
1629 m.resize(nb_integration_pts, Tensor_Dim0 * Tensor_Dim1, false);
1630 }
1631 return [&m]() {
1632 return GetFTensor2FromMatImpl<Tensor_Dim0, Tensor_Dim1, S,
1634 M>::get(m, 0, 0);
1635 };
1636 }
1637 template <class M>
1638 static inline auto get(M &m,
1639 [[maybe_unused]] const size_t nb_integration_pts) {
1640#ifndef NDEBUG
1641 if (S == -1 || S == Tensor_Dim0 * Tensor_Dim1) {
1642 if (m.size1() != nb_integration_pts) {
1645 "Matrix size is not compatible with the number of "
1646 "integration points: expected " +
1647 boost::lexical_cast<std::string>(nb_integration_pts) +
1648 " but got " + boost::lexical_cast<std::string>(m.size1()));
1649 }
1650 }
1651#endif
1652 return [&m]() {
1653 return GetFTensor2FromMatImpl<Tensor_Dim0, Tensor_Dim1, S,
1655 M>::get(m, 0, 0);
1656 };
1657 }
1658};
1659
1660template <class T, int S, int Tensor_Dim>
1662 FTensor::Tensor2_symmetric<FTensor::CursorPtr<T *, S>, Tensor_Dim>,
1663 DataLayoutTraits<DataLayout::GaussByCoeffs>> {
1664 template <class M>
1665 static inline auto size(M &m, const size_t nb_integration_pts) {
1666 constexpr int symm_size = (Tensor_Dim * (Tensor_Dim + 1)) / 2;
1667 if (m.size1() != nb_integration_pts || m.size2() != symm_size) {
1668 m.resize(nb_integration_pts, symm_size, false);
1669 }
1670 return [&m]() {
1673 M>::get(m, 0, 0);
1674 };
1675 }
1676 template <class M>
1677 static inline auto get(M &m,
1678 [[maybe_unused]] const size_t nb_integration_pts) {
1679#ifndef NDEBUG
1680 constexpr int symm_size = (Tensor_Dim * (Tensor_Dim + 1)) / 2;
1681 if (S == -1 || S == symm_size) {
1682 if (m.size1() != nb_integration_pts) {
1685 "Matrix size is not compatible with the number of "
1686 "integration points: expected " +
1687 boost::lexical_cast<std::string>(nb_integration_pts) +
1688 " but got " + boost::lexical_cast<std::string>(m.size1()));
1689 }
1690 }
1691#endif
1692 return [&m]() {
1695 M>::get(m, 0, 0);
1696 };
1697 }
1698};
1699
1700template <class T, int S, int Tensor_Dim0, int Tensor_Dim1, int Tensor_Dim2>
1701struct MatrixSizeHelper<FTensor::Tensor3<FTensor::CursorPtr<T *, S>,
1702 Tensor_Dim0, Tensor_Dim1, Tensor_Dim2>,
1703 DataLayoutTraits<DataLayout::GaussByCoeffs>> {
1704 template <class M>
1705 static inline auto size(M &m, const size_t nb_integration_pts) {
1706 constexpr int tensor_size = Tensor_Dim0 * Tensor_Dim1 * Tensor_Dim2;
1707 if (m.size1() != nb_integration_pts || m.size2() != tensor_size) {
1708 m.resize(nb_integration_pts, tensor_size, false);
1709 }
1710 return [&m]() {
1711 return GetFTensor3FromMatImpl<Tensor_Dim0, Tensor_Dim1, Tensor_Dim2, S,
1713 M>::get(m, 0, 0);
1714 };
1715 }
1716 template <class M>
1717 static inline auto get(M &m,
1718 [[maybe_unused]] const size_t nb_integration_pts) {
1719#ifndef NDEBUG
1720 constexpr int tensor_size = Tensor_Dim0 * Tensor_Dim1 * Tensor_Dim2;
1721 if (S == -1 || S == tensor_size) {
1722 if (m.size1() != nb_integration_pts) {
1725 "Matrix size is not compatible with the number of "
1726 "integration points: expected " +
1727 boost::lexical_cast<std::string>(nb_integration_pts) +
1728 " but got " + boost::lexical_cast<std::string>(m.size1()));
1729 }
1730 }
1731#endif
1732 return [&m]() {
1733 return GetFTensor3FromMatImpl<Tensor_Dim0, Tensor_Dim1, Tensor_Dim2, S,
1735 M>::get(m, 0, 0);
1736 };
1737 }
1738};
1739
1740template <class T, int S, int Tensor_Dim01, int Tensor_Dim2>
1742 FTensor::Dg<FTensor::CursorPtr<T *, S>, Tensor_Dim01, Tensor_Dim2>,
1743 DataLayoutTraits<DataLayout::GaussByCoeffs>> {
1744 template <class M>
1745 static inline auto size(M &m, const size_t nb_integration_pts) {
1746 constexpr int dg_size =
1747 ((Tensor_Dim01 * (Tensor_Dim01 + 1)) / 2) * Tensor_Dim2;
1748 if (m.size1() != nb_integration_pts || m.size2() != dg_size) {
1749 m.resize(nb_integration_pts, dg_size, false);
1750 }
1751 return [&m]() {
1753 Tensor_Dim01, Tensor_Dim2, S,
1755 };
1756 }
1757 template <class M>
1758 static inline auto get(M &m,
1759 [[maybe_unused]] const size_t nb_integration_pts) {
1760#ifndef NDEBUG
1761 constexpr int dg_size =
1762 ((Tensor_Dim01 * (Tensor_Dim01 + 1)) / 2) * Tensor_Dim2;
1763 if (S == -1 || S == dg_size) {
1764 if (m.size1() != nb_integration_pts) {
1767 "Matrix size is not compatible with the number of "
1768 "integration points: expected " +
1769 boost::lexical_cast<std::string>(nb_integration_pts) +
1770 " but got " + boost::lexical_cast<std::string>(m.size1()));
1771 }
1772 }
1773#endif
1774 return [&m]() {
1776 Tensor_Dim01, Tensor_Dim2, S,
1778 };
1779 }
1780};
1781
1782template <class T, int S, int Tensor_Dim0, int Tensor_Dim1, int Tensor_Dim2,
1783 int Tensor_Dim3>
1785 FTensor::Tensor4<FTensor::CursorPtr<T *, S>, Tensor_Dim0, Tensor_Dim1,
1786 Tensor_Dim2, Tensor_Dim3>,
1787 DataLayoutTraits<DataLayout::GaussByCoeffs>> {
1788 template <class M>
1789 static inline auto size(M &m, const size_t nb_integration_pts) {
1790 constexpr int tensor_size =
1791 Tensor_Dim0 * Tensor_Dim1 * Tensor_Dim2 * Tensor_Dim3;
1792 if (m.size1() != nb_integration_pts || m.size2() != tensor_size) {
1793 m.resize(nb_integration_pts, tensor_size, false);
1794 }
1795 return [&m]() {
1797 Tensor_Dim0, Tensor_Dim1, Tensor_Dim2, Tensor_Dim3, S,
1799 };
1800 }
1801 template <class M>
1802 static inline auto get(M &m,
1803 [[maybe_unused]] const size_t nb_integration_pts) {
1804#ifndef NDEBUG
1805 if (S == -1 || S == Tensor_Dim0 * Tensor_Dim1 * Tensor_Dim2 * Tensor_Dim3) {
1806 if (m.size1() != nb_integration_pts) {
1809 "Matrix size is not compatible with the number of "
1810 "integration points: expected " +
1811 boost::lexical_cast<std::string>(nb_integration_pts) +
1812 " but got " + boost::lexical_cast<std::string>(m.size1()));
1813 }
1814 }
1815#endif
1816 return [&m]() {
1818 Tensor_Dim0, Tensor_Dim1, Tensor_Dim2, Tensor_Dim3, S,
1820 };
1821 }
1822};
1823
1824template <class T, int S, int Tensor_Dim01, int Tensor_Dim23>
1826 FTensor::Ddg<FTensor::CursorPtr<T *, S>, Tensor_Dim01, Tensor_Dim23>,
1827 DataLayoutTraits<DataLayout::GaussByCoeffs>> {
1828 template <class M>
1829 static inline auto size(M &m, const size_t nb_integration_pts) {
1830 constexpr int ddg_size = ((Tensor_Dim01 * (Tensor_Dim01 + 1)) / 2) *
1831 ((Tensor_Dim23 * (Tensor_Dim23 + 1)) / 2);
1832 if (m.size1() != nb_integration_pts || m.size2() != ddg_size) {
1833 m.resize(nb_integration_pts, ddg_size, false);
1834 }
1835 return [&m]() {
1837 Tensor_Dim01, Tensor_Dim23, S,
1839 };
1840 }
1841 template <class M>
1842 static inline auto get(M &m,
1843 [[maybe_unused]] const size_t nb_integration_pts) {
1844#ifndef NDEBUG
1845 constexpr int ddg_size = ((Tensor_Dim01 * (Tensor_Dim01 + 1)) / 2) *
1846 ((Tensor_Dim23 * (Tensor_Dim23 + 1)) / 2);
1847 if (S == -1 || S == ddg_size) {
1848
1849 if (m.size1() != nb_integration_pts) {
1852 "Matrix size is not compatible with the number of "
1853 "integration points: expected " +
1854 boost::lexical_cast<std::string>(nb_integration_pts) +
1855 " but got " + boost::lexical_cast<std::string>(m.size1()));
1856 }
1857 }
1858#endif
1859 return [&m]() {
1861 Tensor_Dim01, Tensor_Dim23, S,
1863 };
1864 }
1865};
1866
1867/** @} */
1868
1869/** @name Voigt notation helpers
1870 * Conversions between tensor views and Voigt-like storage.
1871 * @{
1872 */
1873// Template functions for conversion to Voigt notation for 2nd order tensors
1874
1875template <int DIM, typename T> inline auto getVoigtVec(T &t_mat) {
1876 if constexpr (DIM == 3) {
1877 return std::array<double, 9>{t_mat(0, 0), t_mat(1, 1), t_mat(2, 2),
1878 t_mat(0, 1), t_mat(1, 0), t_mat(0, 2),
1879 t_mat(2, 0), t_mat(1, 2), t_mat(2, 1)};
1880 } else {
1881 return std::array<double, 5>{t_mat(0, 0), t_mat(1, 1), 1.0, t_mat(0, 1),
1882 t_mat(1, 0)};
1883 }
1884}
1885
1886template <int DIM, typename T> inline auto getVoigtVecSymm(T &t_mat) {
1887 constexpr double sqr2 = boost::math::constants::root_two<double>();
1888
1889 if constexpr (DIM == 3) {
1890 return std::array<double, 9>{t_mat(0, 0),
1891 t_mat(1, 1),
1892 t_mat(2, 2),
1893 sqr2 * t_mat(0, 1),
1894 sqr2 * t_mat(0, 2),
1895 sqr2 * t_mat(1, 2),
1896 0.0,
1897 0.0,
1898 0.0};
1899 } else {
1900 return std::array<double, 4>{t_mat(0, 0), t_mat(1, 1), 0.0,
1901 sqr2 * t_mat(0, 1)};
1902 }
1903}
1904
1905template <typename T>
1906inline auto getVoigtVecAxisymm(T &t_mat, const double hoop_term) {
1907 array<double, 5> vec{t_mat(0, 0), t_mat(1, 1), 1. + hoop_term, t_mat(0, 1),
1908 t_mat(1, 0)};
1909
1910 return vec;
1911}
1912
1913template <typename T>
1914inline auto getVoigtVecSymmAxisymm(T &t_mat, const double hoop_term) {
1915 constexpr double sqr2 = boost::math::constants::root_two<double>();
1916
1917 array<double, 4> vec_sym{t_mat(0, 0), t_mat(1, 1), hoop_term,
1918 sqr2 * t_mat(0, 1)};
1919 return vec_sym;
1920}
1921/** @} */
1922
1923/** @name Linear algebra helpers
1924 * LAPACK-backed matrix and eigenvalue utilities.
1925 * @{
1926 */
1927// list of lapack wrappers
1928/**
1929 * @brief compute matrix inverse with lapack dgetri
1930 *
1931 * @param mat input square matrix / output inverse matrix
1932 * @return MoFEMErrorCode
1933 */
1936
1937 const size_t M = mat.size1();
1938 const size_t N = mat.size2();
1939
1940 if (M != N)
1941 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1942 "The input matrix for inverse computation is not square %zu != %zu",
1943 M, N);
1944
1945 int *ipv = new int[N];
1946 int lwork = N * N;
1947 double *work = new double[lwork];
1948 int info;
1949 info = lapack_dgetrf(N, N, &*mat.data().begin(), N, ipv);
1950 if (info != 0)
1951 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "lapack error info = %d",
1952 info);
1953 info = lapack_dgetri(N, &*mat.data().begin(), N, ipv, work, lwork);
1954 if (info != 0)
1955 SETERRQ(PETSC_COMM_SELF, MOFEM_OPERATION_UNSUCCESSFUL,
1956 "lapack error info = %d", info);
1957
1958 delete[] ipv;
1959 delete[] work;
1960
1962}
1963/**
1964 * @brief solve linear system with lapack dgesv
1965 *
1966 * @param mat input lhs square matrix / output L and U from the factorization
1967 * @param f input rhs vector / output solution vector
1968 * @return MoFEMErrorCode
1969 */
1972
1973 const size_t M = mat.size1();
1974 const size_t N = mat.size2();
1975
1976 if (M == 0 || M != N)
1977 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1978 "The input matrix for inverse computation is not square %zu != %zu",
1979 M, N);
1980 if (f.size() != M)
1981 f.resize(M, false);
1982
1983 const int nrhs = 1;
1984 int info;
1985 int *ipiv = new int[M];
1986 info = lapack_dgesv(M, nrhs, &*mat.data().begin(), M, ipiv,
1987 &*f.data().begin(), M);
1988 if (info != 0) {
1989 SETERRQ(PETSC_COMM_SELF, MOFEM_OPERATION_UNSUCCESSFUL,
1990 "error lapack solve dgesv info = %d", info);
1991 }
1992
1993 delete[] ipiv;
1995}
1996
1997/**
1998 * @brief Solve linear system of equations using Lapack
1999 *
2000 * @param mat
2001 * @param f
2002 * @return MoFEMErrorCode
2003 */
2005 VectorDouble &f) {
2007 // copy matrix since on output lapack returns factorisation
2008 auto mat_copy = mat;
2009 CHKERR solveLinearSystem(mat_copy, f);
2011}
2012
2013/** check if two doubles are approximately equal */
2014template <typename T = double> inline bool isEq(const T a, const T b) {
2015 const double eps = 100 * std::numeric_limits<T>::epsilon();
2016 const auto abs_max =
2017 std::max(static_cast<T>(1), std::max(std::abs(a), std::abs(b)));
2018 return std::abs(a - b) <= eps * abs_max;
2019}
2020
2021template <int DIM, typename T = double>
2023 return getVectorAdaptor(&vec(0), DIM);
2024}
2025
2026template <int DIM1, int DIM2, typename T = double>
2028 return getMatrixAdaptor(&mat(0, 0), DIM1, DIM2);
2029}
2030
2031/**
2032 * @brief Get the Uniq Nb objects
2033 *
2034 * @tparam DIM
2035 * @param ptr
2036 * @return auto
2037 */
2038template <int DIM, typename T = double>
2040 std::array<double, DIM> tmp;
2041 std::copy(vec.data().begin(), vec.data().begin() + DIM, tmp.begin());
2042 std::sort(tmp.begin(), tmp.end());
2043 std::size_t n_unique = 1;
2044 for (int i = 1; i < DIM; ++i) {
2045 if (!isEq(tmp[i], tmp[i - 1])) {
2046 ++n_unique;
2047 }
2048 }
2049 return n_unique;
2050}
2051
2052template <int DIM, typename T = double>
2056 if constexpr (DIM == 2) {
2058 }
2059 static_assert(DIM == 2 || DIM == 3, "That works only for DIM = 3");
2061 int i = 0, j = 1, k = 2;
2062 if (isEq<T>(eig(0), eig(1))) {
2063 i = 0;
2064 j = 2;
2065 k = 1;
2066 } else if (isEq<T>(eig(0), eig(2))) {
2067 i = 0;
2068 j = 1;
2069 k = 2;
2070 } else if (isEq<T>(eig(1), eig(2))) {
2071 i = 1;
2072 j = 0;
2073 k = 2;
2074 }
2075 const std::array<T, 9> eigen_vec_c{
2076 eigen_vec(i, 0), eigen_vec(i, 1), eigen_vec(i, 2),
2077 eigen_vec(j, 0), eigen_vec(j, 1), eigen_vec(j, 2),
2078 eigen_vec(k, 0), eigen_vec(k, 1), eigen_vec(k, 2)};
2079 const std::array<T, 3> eig_c{eig(i), eig(j), eig(k)};
2080 std::copy(eigen_vec_c.begin(), eigen_vec_c.end(), eigen_vec.data().begin());
2081 std::copy(eig_c.begin(), eig_c.end(), eig.data().begin());
2083}
2084
2085template <int DIM, typename T = double>
2087 return getUniqNb<DIM, T>(convertToShallow(vec), FTensor::Number<DIM>{});
2088}
2089
2090template <int DIM, typename T = double>
2092 FTensor::Tensor2<T, DIM, DIM> &eigen_vec) {
2093 return sortEigenVals<DIM, T>(convertToShallow(eig),
2094 convertToShallow(eigen_vec),
2096}
2097
2098/**
2099 * @brief compute eigenvalues of a symmetric matrix using lapack dsyev
2100 *
2101 * LAPACK `dsyev` returns eigenvectors as columns of the column-major matrix
2102 * `Q`. Since MoFEM passes the raw buffer of `eigen_vec` directly to LAPACK
2103 * and then accesses the same buffer with C++ indexing, `eigen_vec(i, j)`
2104 * stores `Q(j, i)`. Therefore, in MoFEM convention, row `i` of `eigen_vec`
2105 * stores eigenvector `i`, and `Q = eigen_vec^T` in the usual linear algebra
2106 * notation with eigenvectors in columns.
2107 *
2108 * @param mat input symmetric matrix
2109 * @param eig output eigen values sorted
2110 * @param eigen_vec output matrix of eigen vectors in MoFEM convention
2111 * @return MoFEMErrorCode
2112 */
2114 VectorDouble &eig,
2115 MatrixDouble &eigen_vec) {
2117
2118 const size_t M = mat.size1();
2119 const size_t N = mat.size2();
2120
2121 if (M == 0 || M != N)
2122 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
2123 "The input matrix for eigen value computation is not square %zu "
2124 "!= %zu",
2125 M, N);
2126 if (eig.size() != M)
2127 eig.resize(M, false);
2128
2129 eigen_vec = mat;
2130 const int n = M;
2131 const int lda = M;
2132 const int size = (M + 2) * M;
2133 int lwork = size;
2134 double *work = new double[size];
2135
2136 if (lapack_dsyev('V', 'U', n, &*eigen_vec.data().begin(), lda,
2137 &*eig.data().begin(), work, lwork) > 0)
2138 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
2139 "The algorithm failed to compute eigenvalues.");
2140
2141 delete[] work;
2143}
2144
2145/**
2146 * @brief compute eigenvalues of a symmetric matrix using lapack dsyev
2147 *
2148 * LAPACK `dsyev` returns eigenvectors as columns of the column-major matrix
2149 * `Q`. Since MoFEM passes the raw buffer of `eigen_vec` directly to LAPACK
2150 * and then accesses the same buffer with C++ indexing, `eigen_vec(i, j)`
2151 * stores `Q(j, i)`. Therefore, in MoFEM convention, row `i` of `eigen_vec`
2152 * stores eigenvector `i`, and `Q = eigen_vec^T` in the usual linear algebra
2153 * notation with eigenvectors in columns.
2154 *
2155 * @tparam DIM
2156 * @param eigen_vec input / output DIM x DIM matrix of eigen vectors in MoFEM
2157 * convention
2158 * @param eig output eigen values sorted
2159 * @return MoFEMErrorCode
2160 */
2161template <int DIM, typename T1, typename T2>
2162inline MoFEMErrorCode
2166
2167 const int n = DIM;
2168 const int lda = DIM;
2169 const int lwork = (DIM + 2) * DIM;
2170 std::array<double, (DIM + 2) * DIM> work;
2171
2172 if (lapack_dsyev('V', 'U', n, &eigen_vec(0, 0), lda, &eig(0), work.data(),
2173 lwork) > 0)
2174 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
2175 "The algorithm failed to compute eigenvalues.");
2177}
2178
2179/**
2180 * @brief compute eigenvalues of a symmetric tensor using lapack dsyev
2181 *
2182 * LAPACK `dsyev` returns eigenvectors as columns of the column-major matrix
2183 * `Q`. Since MoFEM passes the raw buffer of `eigen_vec` directly to LAPACK
2184 * and then accesses the same buffer with C++ indexing, `eigen_vec(i, j)`
2185 * stores `Q(j, i)`. Therefore, in MoFEM convention, row `i` of `eigen_vec`
2186 * stores eigenvector `i`, and `Q = eigen_vec^T` in the usual linear algebra
2187 * notation with eigenvectors in columns.
2188 *
2189 * @tparam DIM
2190 * @param mat input tensor pointer of size DIM x DIM
2191 * @param eig output eigen values sorted
2192 * @param eigen_vec output matrix of eigen vectors in MoFEM convention
2193 * @return MoFEMErrorCode
2194 */
2195template <int DIM, typename T1, typename T2, typename T3>
2196inline MoFEMErrorCode
2199 FTensor::Tensor2<T3, DIM, DIM> &eigen_vec) {
2201 for (int ii = 0; ii != DIM; ii++)
2202 for (int jj = 0; jj != DIM; jj++)
2203 eigen_vec(ii, jj) = mat(ii, jj);
2204
2205 CHKERR computeEigenValuesSymmetric(eigen_vec, eig);
2206
2208}
2209
2210/** @} */
2211
2212/** @name Tensor algebra helpers
2213 * Determinant and inverse routines for tensor-valued objects.
2214 * @{
2215 */
2216/**
2217 * @brief Calculate the determinant of a 3x3 matrix or a tensor of rank 2
2218 *
2219 * @tparam T
2220 * @param t
2221 * @return double
2222 */
2223template <typename T> static inline auto determinantTensor3by3(T &t) {
2224 return t(0, 0) * t(1, 1) * t(2, 2) + t(1, 0) * t(2, 1) * t(0, 2) +
2225 t(2, 0) * t(0, 1) * t(1, 2) - t(0, 0) * t(2, 1) * t(1, 2) -
2226 t(2, 0) * t(1, 1) * t(0, 2) - t(1, 0) * t(0, 1) * t(2, 2);
2227}
2228
2229/**
2230 * @brief Calculate the determinant of a 2x2 matrix or a tensor of rank 2
2231 *
2232 * @tparam T
2233 * @param t
2234 * @return double
2235 */
2236template <typename T> static inline auto determinantTensor2by2(T &t) {
2237 return t(0, 0) * t(1, 1) - t(0, 1) * t(1, 0);
2238}
2239
2240template <typename T, int DIM> struct DeterminantTensorImpl;
2241
2242template <typename T> struct DeterminantTensorImpl<T, 3> {
2243 static inline auto get(T &t) { return determinantTensor3by3(t); }
2244};
2245
2246template <typename T> struct DeterminantTensorImpl<T, 2> {
2247 static auto get(T &t) { return determinantTensor2by2(t); }
2248};
2249
2250/**
2251 * @brief Calculate the determinant of a tensor of rank DIM
2252 */
2253template <typename T, int DIM>
2257
2258/**
2259 * @brief Calculate the determinant of a tensor of rank DIM
2260 */
2261template <typename T, int DIM>
2265
2266/**
2267 * \brief Calculate inverse of tensor rank 2 at integration points
2268
2269 */
2270template <int Tensor_Dim, class T, class L, class A>
2271inline MoFEMErrorCode invertTensor3by3(ublas::matrix<T, L, A> &jac_data,
2272 ublas::vector<T, A> &det_data,
2273 ublas::matrix<T, L, A> &inv_jac_data) {
2275 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
2276 "Specialization for this template not yet implemented");
2278}
2279
2280template <>
2281inline MoFEMErrorCode
2283 MatrixDouble &jac_data, VectorDouble &det_data, MatrixDouble &inv_jac_data);
2284
2285/**
2286 * \brief Calculate determinant 3 by 3
2287
2288 */
2289template <class T1, class T2>
2295
2296/**
2297 * \brief Calculate determinant 2 by 2
2298
2299 */
2300template <class T1, class T2>
2306
2307/**
2308 * \brief Calculate matrix inverse 3 by 3
2309
2310 */
2311template <class T1, class T2, class T3>
2312inline MoFEMErrorCode invertTensor3by3(T1 &t, T2 &det, T3 &inv_t) {
2314 const auto a = t(0, 0), b = t(0, 1), c = t(0, 2);
2315 const auto d = t(1, 0), e = t(1, 1), f = t(1, 2);
2316 const auto g = t(2, 0), h = t(2, 1), i = t(2, 2);
2317 const auto inv_det = 1.0 / det;
2318 inv_t(0, 0) = (e * i - f * h) * inv_det;
2319 inv_t(0, 1) = (c * h - b * i) * inv_det;
2320 inv_t(0, 2) = (b * f - c * e) * inv_det;
2321 inv_t(1, 0) = (f * g - d * i) * inv_det;
2322 inv_t(1, 1) = (a * i - c * g) * inv_det;
2323 inv_t(1, 2) = (c * d - a * f) * inv_det;
2324 inv_t(2, 0) = (d * h - e * g) * inv_det;
2325 inv_t(2, 1) = (b * g - a * h) * inv_det;
2326 inv_t(2, 2) = (a * e - b * d) * inv_det;
2328}
2329
2330/**
2331 * \brief Calculate matrix inverse 2 by 2
2332
2333 */
2334template <class T1, class T2, class T3>
2335inline MoFEMErrorCode invertTensor2by2(T1 &t, T2 &det, T3 &inv_t) {
2337 const auto a = t(0, 0);
2338 const auto b = t(0, 1);
2339 const auto c = t(1, 0);
2340 const auto d = t(1, 1);
2341 inv_t(0, 0) = d / det;
2342 inv_t(0, 1) = -b / det;
2343 inv_t(1, 0) = -c / det;
2344 inv_t(1, 1) = a / det;
2346}
2347
2348/**
2349 * \brief Calculate matrix inverse, overload for symmetric tensor
2350
2351 */
2352template <typename T1, typename T2, typename T3>
2353inline MoFEMErrorCode
2357 const auto a = t(0, 0);
2358 const auto b = t(0, 1);
2359 const auto c = t(0, 2);
2360 const auto d = t(1, 1);
2361 const auto e = t(1, 2);
2362 const auto f = t(2, 2);
2363 const auto inv_det = 1.0 / det;
2364 inv_t(0, 0) = (d * f - e * e) * inv_det;
2365 inv_t(0, 1) = (c * e - b * f) * inv_det;
2366 inv_t(0, 2) = (b * e - c * d) * inv_det;
2367 inv_t(1, 1) = (a * f - c * c) * inv_det;
2368 inv_t(1, 2) = (b * c - a * e) * inv_det;
2369 inv_t(2, 2) = (a * d - b * b) * inv_det;
2371}
2372
2373/**
2374 * \brief Calculate matrix inverse, overload for symmetric tensor
2375
2376 */
2377template <typename T1, typename T2, typename T3>
2378inline MoFEMErrorCode
2382 const auto a = t(0, 0);
2383 const auto b = t(0, 1);
2384 const auto d = t(1, 1);
2385 const auto inv_det = 1.0 / det;
2386 inv_t(0, 0) = d * inv_det;
2387 inv_t(0, 1) = -b * inv_det;
2388 inv_t(1, 1) = a * inv_det;
2390}
2391
2392template <typename T1, typename T2, typename T3, int DIM>
2394
2395template <typename T1, typename T2, typename T3>
2396struct InvertTensorImpl<T1, T2, T3, 3> {
2397 inline static MoFEMErrorCode invert(T1 &t, T2 &det, T3 &inv_t) {
2398 return invertTensor3by3(t, det, inv_t);
2399 }
2400};
2401
2402template <typename T1, typename T2, typename T3>
2403struct InvertTensorImpl<T1, T2, T3, 2> {
2404 inline static MoFEMErrorCode invert(T1 &t, T2 &det, T3 &inv_t) {
2405 return invertTensor2by2(t, det, inv_t);
2406 }
2407};
2408
2409template <typename T1, typename T2, typename T3, int DIM>
2410static inline MoFEMErrorCode
2417
2418template <typename T1, typename T2, typename T3, int DIM>
2419static inline MoFEMErrorCode
2426/** @} */
2427
2428/** @name Mesh and range helpers
2429 * Utility types and helpers for mesh entities, ranges, and handles.
2430 * @{
2431 */
2432/**
2433 * @brief Extract entity handle form multi-index container
2434 *
2435 */
2437 template <typename Iterator>
2438 static inline EntityHandle extract(const Iterator &it) {
2439 return (*it)->getEnt();
2440 }
2441};
2442
2443/**
2444 * @brief Insert ordered mofem multi-index into range
2445 *
2446 * \note Inserted range has to be ordered.
2447 *
2448 * \code
2449 * auto hi_rit = refEntsPtr->upper_bound(start);
2450 * auto hi_rit = refEntsPtr->upper_bound(end);
2451 * Range to_erase;
2452 * insertOrdered(to_erase, RefEntExtractor(), rit, hi_rit);
2453 * \endcode
2454 *
2455 * @tparam Iterator
2456 * @param r
2457 * @param begin_iter
2458 * @param end_iter
2459 * @return moab::Range::iterator
2460 */
2461template <typename Extractor, typename Iterator>
2462moab::Range::iterator insertOrdered(Range &r, Extractor, Iterator begin_iter,
2463 Iterator end_iter) {
2464 moab::Range::iterator hint = r.begin();
2465 while (begin_iter != end_iter) {
2466 size_t j = 0;
2467 auto bi = Extractor::extract(begin_iter);
2468 Iterator pj = begin_iter;
2469 while (pj != end_iter && (bi + j) == Extractor::extract(pj)) {
2470 ++pj;
2471 ++j;
2472 }
2473 hint = r.insert(hint, bi, bi + (j - 1));
2474 begin_iter = pj;
2475 }
2476 return hint;
2477};
2478
2479/**
2480 * @brief Do nothing, used to rebuild database
2481 *
2482 */
2485 template <typename T> inline void operator()(T &e) {}
2486};
2487
2488/**
2489 * @brief Template used to reconstruct multi-index
2490 *
2491 * @tparam MI multi-index
2492 * @tparam Modifier
2493 * @param mi
2494 * @param mo
2495 * @return MoFEMErrorCode
2496 */
2497template <typename MI, typename MO = Modify_change_nothing>
2499 MO &&mo = Modify_change_nothing()) {
2501 for (auto it = mi.begin(); it != mi.end(); ++it) {
2502 if (!const_cast<MI &>(mi).modify(it, mo))
2503 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
2504 "Houston we have a problem");
2505 }
2507}
2508
2510 TempMeshset(moab::Interface &moab) : moab(moab) {
2511 rval = moab.create_meshset(MESHSET_SET, meshset);
2513 }
2515 operator EntityHandle() const { return meshset; }
2516 auto get_ptr() { return &meshset; }
2517
2518private:
2520 rval = moab.delete_entities(&meshset, 1);
2522 }
2523 EntityHandle meshset;
2524 moab::Interface &moab;
2525};
2526
2527/**
2528 * @brief Create smart pointer to temporary meshset
2529 *
2530 */
2531inline auto get_temp_meshset_ptr(moab::Interface &moab) {
2532 return boost::make_shared<TempMeshset>(moab);
2533};
2534
2535inline auto id_from_handle(const EntityHandle h) {
2536 return static_cast<EntityID>(h & MB_ID_MASK);
2537};
2538
2539/**
2540 * @brief get type from entity handle
2541 *
2542 */
2543inline auto type_from_handle(const EntityHandle h) {
2544 return static_cast<EntityType>(h >> MB_ID_WIDTH);
2545};
2546
2547/**
2548 * @brief get entity handle from type and id
2549 *
2550 */
2551inline auto ent_form_type_and_id(const EntityType type, const EntityID id) {
2552 return (static_cast<EntityHandle>(type) << MB_ID_WIDTH) | id;
2553};
2554
2555/**
2556 * @brief get entity dimension form handle
2557 *
2558 */
2559inline auto dimension_from_handle(const EntityHandle h) {
2560 return moab::CN::Dimension(type_from_handle(h));
2561};
2562
2563/**
2564 * @brief get entity type name from handle
2565 *
2566 */
2567inline auto type_name_from_handle(const EntityHandle h) {
2568 return moab::CN::EntityTypeName(type_from_handle(h));
2569};
2570
2571/**
2572 * @brief get field bit id from bit number
2573 *
2574 */
2575inline auto field_bit_from_bit_number(const int bit_number) {
2576 return BitFieldId().set(bit_number - 1);
2577};
2578
2579/**
2580 * @brief Insert ranges
2581 *
2582 * @tparam I
2583 * @param f
2584 * @param s
2585 * @param tester
2586 * @param inserter
2587 * @return auto
2588 */
2589template <typename I>
2590auto rangeInserter(const I f, const I s, boost::function<bool(I it)> tester,
2591 boost::function<MoFEMErrorCode(I f, I s)> inserter) {
2593
2594 auto first = f;
2595 while (first != s)
2596 if (tester(first)) {
2597
2598 auto second = first;
2599 ++second;
2600
2601 while (second != s) {
2602 if (tester(second))
2603 ++second;
2604 else
2605 break;
2606 }
2607
2608 CHKERR inserter(first, second);
2609
2610 first = second;
2611 if (first != s)
2612 ++first;
2613
2614 } else {
2615 ++first;
2616 }
2617
2619}
2620
2621/**
2622 * @brief Create Array
2623 *
2624 * See:
2625 * <a
2626 * href="https://stackoverflow.com/questions/50942556/current-status-of-stdmake-array">See
2627 * stack overflow</a>
2628 *
2629 * @tparam Dest
2630 * @tparam Arg
2631 * @param arg
2632 * @return constexpr auto
2633 */
2634template <typename Dest = void, typename... Arg>
2635constexpr auto make_array(Arg &&...arg) {
2636 if constexpr (std::is_same<void, Dest>::value)
2637 return std::array<std::common_type_t<std::decay_t<Arg>...>, sizeof...(Arg)>{
2638 {std::forward<Arg>(arg)...}};
2639 else
2640 return std::array<Dest, sizeof...(Arg)>{{std::forward<Arg>(arg)...}};
2641}
2642/** @} */
2643
2644/** @name FTensor index aliases
2645 * Convenient aliases for commonly used FTensor indices.
2646 * @{
2647 */
2648template <int DIM> using i_FTIndex = FTensor::Index<'i', DIM>;
2649template <int DIM> using j_FTIndex = FTensor::Index<'j', DIM>;
2650template <int DIM> using k_FTIndex = FTensor::Index<'k', DIM>;
2651template <int DIM> using l_FTIndex = FTensor::Index<'l', DIM>;
2652template <int DIM> using m_FTIndex = FTensor::Index<'m', DIM>;
2653template <int DIM> using n_FTIndex = FTensor::Index<'n', DIM>;
2654template <int DIM> using o_FTIndex = FTensor::Index<'o', DIM>;
2655template <int DIM> using p_FTIndex = FTensor::Index<'p', DIM>;
2656template <int DIM> using x_FTIndex = FTensor::Index<'x', DIM>;
2657template <int DIM> using y_FTIndex = FTensor::Index<'y', DIM>;
2658template <int DIM> using I_FTIndex = FTensor::Index<'I', DIM>;
2659template <int DIM> using J_FTIndex = FTensor::Index<'J', DIM>;
2660template <int DIM> using K_FTIndex = FTensor::Index<'K', DIM>;
2661template <int DIM> using L_FTIndex = FTensor::Index<'L', DIM>;
2662template <int DIM> using M_FTIndex = FTensor::Index<'M', DIM>;
2663template <int DIM> using N_FTIndex = FTensor::Index<'N', DIM>;
2664template <int DIM> using O_FTIndex = FTensor::Index<'O', DIM>;
2665template <int DIM> using Z_FTIndex = FTensor::Index<'Z', DIM>;
2666template <int DIM> using Y_FTIndex = FTensor::Index<'Y', DIM>;
2667
2668#define FTENSOR_INDEX(DIM, I) I##_FTIndex<DIM> I;
2669
2670#define FTENSOR_INDEX_DECL(r, DIM, I) FTENSOR_INDEX(DIM, I)
2671
2672#define FTENSOR_INDEXES(DIM, ...) \
2673 BOOST_PP_SEQ_FOR_EACH(FTENSOR_INDEX_DECL, DIM, \
2674 BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
2675
2676template <typename T> struct parent_of;
2677/** @} */
2678
2679} // namespace MoFEM
2680
2681#endif //__TEMPLATES_HPP__
std::string type
SmartPetscObj< Vec > work
PetscInt size
constexpr double a
static const double eps
#define MB_ID_MASK
#define MOAB_THROW(err)
Check error code of MoAB function and throw MoFEM exception.
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define MB_ID_WIDTH
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ MOFEM_OPERATION_UNSUCCESSFUL
Definition definitions.h:34
@ MOFEM_DATA_INCONSISTENCY
Definition definitions.h:31
@ MOFEM_INVALID_DATA
Definition definitions.h:36
@ MOFEM_NOT_IMPLEMENTED
Definition definitions.h:32
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
@ HVEC1_1
@ HVEC0_1
@ HVEC1_0
@ HVEC2_1
@ HVEC1_2
@ HVEC2_2
@ HVEC2_0
@ HVEC0_2
@ HVEC0_0
#define CHKERR
Inline error check.
#define MoFEMFunctionBeginHot
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
#define THROW_MESSAGE(msg)
Throw MoFEM exception.
FTensor::Index< 'i', SPACE_DIM > i
const double c
speed of light (cm/ns)
const double n
refractive index of diffusive medium
static __CLPK_integer lapack_dgesv(__CLPK_integer n, __CLPK_integer nrhs, __CLPK_doublereal *a, __CLPK_integer lda, __CLPK_integer *ipiv, __CLPK_doublereal *b, __CLPK_integer ldb)
static __CLPK_integer lapack_dgetrf(__CLPK_integer m, __CLPK_integer n, __CLPK_doublereal *a, __CLPK_integer lda, __CLPK_integer *ipiv)
static __CLPK_integer lapack_dsyev(char jobz, char uplo, __CLPK_integer n, __CLPK_doublereal *a, __CLPK_integer lda, __CLPK_doublereal *w, __CLPK_doublereal *work, __CLPK_integer lwork)
static __CLPK_integer lapack_dgetri(__CLPK_integer n, __CLPK_doublereal *a, __CLPK_integer lda, __CLPK_integer *ipiv, __CLPK_doublereal *work, __CLPK_integer lwork)
constexpr int DIM2
Definition level_set.cpp:22
constexpr int DIM1
Definition level_set.cpp:21
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
Tensors class implemented by Walter Landry.
Definition FTensor.hpp:51
static MoFEMErrorCodeGeneric< moab::ErrorCode > rval
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
std::bitset< BITFIELDID_SIZE > BitFieldId
Field Id.
Definition Types.hpp:42
ublas::vector< T, ublas::shallow_array_adaptor< T > > VectorShallowArrayAdaptor
Definition Types.hpp:114
UBlasMatrix< double > MatrixDouble
Definition Types.hpp:77
UBlasMatrix< adouble > MatrixADouble
Definition Types.hpp:80
ublas::matrix< T, ublas::row_major, ublas::shallow_array_adaptor< T > > MatrixShallowArrayAdaptor
Definition Types.hpp:120
UBlasVector< double > VectorDouble
Definition Types.hpp:68
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
auto getVectorAdaptor(T1 ptr, const size_t n)
Get Vector adaptor.
Definition Templates.hpp:49
auto type_from_handle(const EntityHandle h)
get type from entity handle
static auto getFTensor4FromMat(M &data)
Get tensor rank 4 (non symmetric) form data matrix.
decltype(GetFTensor2SymmetricFromMatImpl< Tensor_Dim, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor2SymmetricFromMatType
auto sortEigenVals(VectorShallowArrayAdaptor< T > eig, MatrixShallowArrayAdaptor< T > eigen_vec, FTensor::Number< DIM >)
auto getVoigtVecAxisymm(T &t_mat, const double hoop_term)
auto getFTensor2FromMat(M &data)
Get tensor rank 2 (matrix) form data matrix.
bool isEq(const T a, const T b)
auto to_non_symm(const FTensor::Tensor2_symmetric< T, DIM > &symm)
static auto getFTensor3FromMat(M &data, int rr=0, int cc=0)
Get tensor rank 3 (non symmetries) form data matrix.
auto getFTensor2SymmetricLowerFromPtr< 3 >(double *ptr)
auto getFTensor2SymmetricFromPtr(double *ptr)
auto getFTensor2SymmetricLowerFromPtr< 2 >(double *ptr)
FTensor::Tensor3< FTensor::PackPtr< double *, 12 >, 3, 2, 2 > getFTensor3FromPtr< 3, 2, 2 >(double *ptr)
auto getVoigtVec(T &t_mat)
MoFEMErrorCode reconstructMultiIndex(const MI &mi, MO &&mo=Modify_change_nothing())
Template used to reconstruct multi-index.
auto getUniqNb(VectorShallowArrayAdaptor< T > vec, FTensor::Number< DIM >)
Get the Uniq Nb objects.
auto getFTensor2FromVec(VectorDouble &data)
moab::Range::iterator insertOrdered(Range &r, Extractor, Iterator begin_iter, Iterator end_iter)
Insert ordered mofem multi-index into range.
decltype(GetFTensor4FromMatImpl< Tensor_Dim0, Tensor_Dim1, Tensor_Dim2, Tensor_Dim3, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor4FromMatType
MoFEMErrorCode invertTensor2by2(T1 &t, T2 &det, T3 &inv_t)
Calculate matrix inverse 2 by 2.
static auto getFTensor2SymmetricFromMat(M &data)
Get symmetric tensor rank 2 (matrix) form data matrix.
MoFEMErrorCode computeMatrixInverse(MatrixDouble &mat)
compute matrix inverse with lapack dgetri
auto getFTensor1FromArrayDiag(MatrixDouble &data, const size_t rr)
Get FTensor1 from array.
auto getFTensor2HVecFromPtr< 3, 2 >(double *ptr)
auto id_from_handle(const EntityHandle h)
static auto getFTensor3DgFromPtr(T *ptr)
auto getFTensor1FromArray(T &data)
auto convertToShallow(FTensor::Tensor1< T, DIM > &vec)
auto dimension_from_handle(const EntityHandle h)
get entity dimension form handle
auto getFTensor1FromArrayDiag< 2, 2 >(MatrixDouble &data, const size_t rr)
MoFEMErrorCode solveLinearSystem(MatrixDouble &mat, VectorDouble &f)
solve linear system with lapack dgesv
static auto determinantTensor2by2(T &t)
Calculate the determinant of a 2x2 matrix or a tensor of rank 2.
auto getFTensor2HVecFromPtr(double *ptr)
Make Tensor2 for HVec base from pointer.
auto type_name_from_handle(const EntityHandle h)
get entity type name from handle
static auto getFTensor3DgFromMat(M &data)
Get symmetric tensor rank 3 on the first two indices from form data matrix.
auto getFTensor2HVecFromPtr< 3, 3 >(double *ptr)
MoFEMErrorCode invertTensor3by3(ublas::matrix< T, L, A > &jac_data, ublas::vector< T, A > &det_data, ublas::matrix< T, L, A > &inv_jac_data)
Calculate inverse of tensor rank 2 at integration points.
decltype(GetFTensor4DdgFromMatImpl< Tensor_Dim01, Tensor_Dim23, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor4DdgFromMatType
MoFEMErrorCode invertTensor3by3< 3, double, ublas::row_major, DoubleAllocator >(MatrixDouble &jac_data, VectorDouble &det_data, MatrixDouble &inv_jac_data)
auto getFTensor1FromPtr(T *ptr)
static MoFEMErrorCode invertTensor(FTensor::Tensor2< T1, DIM, DIM > &t, T2 &det, FTensor::Tensor2< T3, DIM, DIM > &inv_t)
static auto getFTensor4DdgFromPtr(T *ptr)
constexpr auto make_array(Arg &&...arg)
Create Array.
auto getMatrixAdaptor(T1 ptr, const size_t n, const size_t m)
Get Matrix adaptor.
Definition Templates.hpp:75
auto getFTensor1FromMat(M &data, int rr=0, int cc=0)
Get tensor rank 1 (vector) form data matrix.
auto getFTensor4FromPtr(T *ptr)
auto getFTensor2FromArray(MatrixDouble &data, const size_t rr, const size_t cc=0)
static auto determinantTensor(FTensor::Tensor2< T, DIM, DIM > &t)
Calculate the determinant of a tensor of rank DIM.
auto field_bit_from_bit_number(const int bit_number)
get field bit id from bit number
static auto getFTensor0FromPtr(T *ptr)
Get tensor rank 0 (scalar) from pointer.
std::string toString(X x)
decltype(GetFTensor1FromMatImpl< Tensor_Dim, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor1FromMatType
auto getFTensor2SymmetricLowerFromPtr(double *ptr)
Make symmetric Tensor2 from pointer, taking lower triangle of matrix.
static auto getFTensor4DdgFromMat(M &data)
Get symmetric tensor rank 4 on first two and last indices from form data matrix.
auto getFTensor2FromPtr(double *ptr)
auto getVoigtVecSymm(T &t_mat)
static auto makeFTensor4FromPtrArray(const std::array< T *, Tensor_Dim0 *Tensor_Dim1 *Tensor_Dim2 *Tensor_Dim3 > &ptrs, std::index_sequence< Is... >)
auto getFTensor0FromMat(M &data)
Get tensor rank 0 (scalar) form data vector.
auto get_temp_meshset_ptr(moab::Interface &moab)
Create smart pointer to temporary meshset.
decltype(GetFTensor3DgFromMatImpl< Tensor_Dim01, Tensor_Dim2, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor3DgFromMatType
MoFEMErrorCode computeEigenValuesSymmetric(const MatrixDouble &mat, VectorDouble &eig, MatrixDouble &eigen_vec)
compute eigenvalues of a symmetric matrix using lapack dsyev
static auto getFTensor0FromVec(V &data)
Get tensor rank 0 (scalar) form data vector.
FTensor::Tensor3< FTensor::PackPtr< double *, 27 >, 3, 3, 3 > getFTensor3FromPtr< 3, 3, 3 >(double *ptr)
static auto determinantTensor3by3(T &t)
Calculate the determinant of a 3x3 matrix or a tensor of rank 2.
decltype(GetFTensor3FromMatImpl< Tensor_Dim0, Tensor_Dim1, Tensor_Dim2, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor3FromMatType
auto getVoigtVecSymmAxisymm(T &t_mat, const double hoop_term)
FTensor::Tensor3< FTensor::PackPtr< double *, DIM1 *DIM2 *DIM3 >, DIM1, DIM2, DIM3 > getFTensor3FromPtr(double *ptr)
decltype(GetFTensor2FromMatImpl< Tensor_Dim0, Tensor_Dim1, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor2FromMatType
auto rangeInserter(const I f, const I s, boost::function< bool(I it)> tester, boost::function< MoFEMErrorCode(I f, I s)> inserter)
Insert ranges.
auto getFTensor1FromArrayDiag< 3, 3 >(MatrixDouble &data, const size_t rr)
auto ent_form_type_and_id(const EntityType type, const EntityID id)
get entity handle from type and id
constexpr IntegrationType I
double h
constexpr double t
plate stiffness
Definition plate.cpp:58
constexpr double g
FTensor::Index< 'm', 3 > m
const int N
Definition speed_test.cpp:3
bool operator()(const id_type &valueA, const id_type &valueB) const
static auto get(M &data)
static auto get(V &data)
Get FTensor2 from array.
static auto get(M &data, const size_t rr, const size_t cc=0)
static auto make(M &data, const size_t rr, const size_t cc, std::index_sequence< Is... >)
static auto get(M &data, const size_t rr, const size_t cc, const int ss=0)
static auto get(M &data, const size_t rr, const size_t cc, const int ss=0)
static auto get(M &data, int rr=0, int cc=0)
static auto get(M &data, int rr=0, int cc=0)
unsigned int operator()(const id_type &value) const
static MoFEMErrorCode invert(T1 &t, T2 &det, T3 &inv_t)
static MoFEMErrorCode invert(T1 &t, T2 &det, T3 &inv_t)
KeyExtractor1 key1
result_type operator()(Arg &arg) const
KeyFromKey(const KeyExtractor1 &key1_=KeyExtractor1(), const KeyExtractor2 &key2_=KeyExtractor2())
Definition Templates.hpp:98
KeyExtractor2 key2
KeyExtractor1::result_type result_type
Definition Templates.hpp:96
bool operator()(const id_type &valueA, const id_type &valueB) const
Do nothing, used to rebuild database.
Extract entity handle form multi-index container.
static EntityHandle extract(const Iterator &it)
EntityHandle meshset
moab::Interface & moab
TempMeshset(moab::Interface &moab)