deal.II version GIT relicensing-6842-g793a97d2aa 2026-10-02 14:00:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
tensor_product_matrix.h
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2017 - 2025 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13#ifndef dealii_tensor_product_matrix_h
14#define dealii_tensor_product_matrix_h
15
16
17#include <deal.II/base/config.h>
18
21#include <deal.II/base/mutex.h>
23
25
27
28#include <bitset>
29
30
32
33// Forward declarations
34#ifndef DOXYGEN
35template <typename>
36class Vector;
37template <typename>
38class FullMatrix;
39#endif
40
112template <int dim, typename Number, int n_rows_1d = -1>
114{
115public:
120 using value_type = Number;
121
126 static constexpr int n_rows_1d_static = n_rows_1d;
127
132
137 template <typename T>
139 const T &derivative_matrix);
140
158 template <typename T>
159 void
161
167 unsigned int
168 m() const;
169
175 unsigned int
176 n() const;
177
191 void
192 vmult(const ArrayView<Number> &dst, const ArrayView<const Number> &src) const;
193
199 void
201 const ArrayView<const Number> &src,
202 AlignedVector<Number> &tmp) const;
203
210 void
212 const ArrayView<const Number> &src) const;
213
217 std::size_t
219
220protected:
224 std::array<Table<2, Number>, dim> mass_matrix;
225
229 std::array<Table<2, Number>, dim> derivative_matrix;
230
235 std::array<AlignedVector<Number>, dim> eigenvalues;
236
241 std::array<Table<2, Number>, dim> eigenvectors;
242
243private:
248
253};
254
255
256
257namespace internal
258{
260 {
261 template <typename Number>
263 {
267 static constexpr std::size_t width = VectorizedArrayTrait::width();
268
270 std::pair<std::bitset<width>,
271 std::pair<Table<2, Number>, Table<2, Number>>>;
272
274 : eps(std::sqrt(std::numeric_limits<ScalarNumber>::epsilon()))
275 {}
276
277 bool
278 operator()(const MatrixPairType &left, const MatrixPairType &right) const
279 {
280 const auto &M_0 = left.second.first;
281 const auto &K_0 = left.second.second;
282 const auto &M_1 = right.second.first;
283 const auto &K_1 = right.second.second;
284
285 std::bitset<width> mask;
286
287 for (unsigned int v = 0; v < width; ++v)
288 mask[v] = left.first[v] && right.first[v];
289
290 const FloatingPointComparator<Number> comparator(
291 eps, false /*use relative tolerance*/, mask);
292
293 if (comparator(M_0, M_1))
294 return true;
295 else if (comparator(M_1, M_0))
296 return false;
297 else if (comparator(K_0, K_1))
298 return true;
299 else
300 return false;
301 }
302
303 private:
305 };
306 } // namespace TensorProductMatrixSymmetricSum
307} // namespace internal
308
309
310
334template <int dim, typename Number, int n_rows_1d = -1>
336{
337 using MatrixPairType = std::pair<Table<2, Number>, Table<2, Number>>;
338
339 using MatrixPairTypeWithMask = std::pair<
340 std::bitset<::internal::VectorizedArrayTrait<Number>::width()>,
342
343public:
348 {
353 const bool precompute_inverse_diagonal = true);
354
359
364 };
365
370 const AdditionalData &additional_data = AdditionalData());
371
376 void
377 reserve(const unsigned int size);
378
384 template <typename T>
385 void
386 insert(const unsigned int index, const T &Ms, const T &Ks);
387
392 void
394
398 void
399 apply_inverse(const unsigned int index,
400 const ArrayView<Number> &dst_in,
401 const ArrayView<const Number> &src_in) const;
402
406 std::size_t
408
417 std::size_t
419
420private:
425
430
435 std::vector<MatrixPairType> mass_and_derivative_matrices;
436
441 std::map<
443 unsigned int,
446
454 std::vector<unsigned int> indices;
455
460
465
470
475
480
484 std::vector<unsigned int> vector_ptr;
485
489 std::vector<unsigned int> matrix_ptr;
490
494 std::vector<unsigned int> vector_n_rows_1d;
495};
496
497
498/*----------------------- Inline functions ----------------------------------*/
499
500#ifndef DOXYGEN
501
502namespace internal
503{
505 {
514 template <typename Number>
515 void
516 spectral_assembly(const Number *mass_matrix,
517 const Number *derivative_matrix,
518 const unsigned int n_rows,
519 const unsigned int n_cols,
520 Number *eigenvalues,
521 Number *eigenvectors)
522 {
523 Assert(n_rows == n_cols, ExcNotImplemented());
524
525 std::vector<bool> constrained_dofs(n_rows, false);
526
527 for (unsigned int i = 0; i < n_rows; ++i)
528 {
529 if (mass_matrix[i + i * n_rows] == 0.0)
530 {
531 Assert(derivative_matrix[i + i * n_rows] == 0.0,
533
534 for (unsigned int j = 0; j < n_rows; ++j)
535 {
536 Assert(derivative_matrix[i + j * n_rows] == 0,
538 Assert(derivative_matrix[j + i * n_rows] == 0,
540 }
541
542 constrained_dofs[i] = true;
543 }
544 }
545
546 const auto transpose_fill_nm = [&constrained_dofs](Number *out,
547 const Number *in,
548 const unsigned int n,
549 const unsigned int m) {
550 for (unsigned int mm = 0, c = 0; mm < m; ++mm)
551 for (unsigned int nn = 0; nn < n; ++nn, ++c)
552 out[mm + nn * m] =
553 (mm == nn && constrained_dofs[mm]) ? Number(1.0) : in[c];
554 };
555
556 std::vector<::Vector<Number>> eigenvecs(n_rows);
557 LAPACKFullMatrix<Number> mass_copy(n_rows, n_cols);
558 LAPACKFullMatrix<Number> deriv_copy(n_rows, n_cols);
559
560 transpose_fill_nm(&(mass_copy(0, 0)), mass_matrix, n_rows, n_cols);
561 transpose_fill_nm(&(deriv_copy(0, 0)), derivative_matrix, n_rows, n_cols);
562
564 eigenvecs);
565 AssertDimension(eigenvecs.size(), n_rows);
566 for (unsigned int i = 0, c = 0; i < n_rows; ++i)
567 for (unsigned int j = 0; j < n_cols; ++j, ++c)
568 if (constrained_dofs[i] == false)
569 eigenvectors[c] = eigenvecs[j][i];
570
571 for (unsigned int i = 0; i < n_rows; ++i, ++eigenvalues)
572 *eigenvalues = deriv_copy.eigenvalue(i).real();
573 }
574
575
576
577 template <std::size_t dim, typename Number>
578 inline void
579 setup(const std::array<Table<2, Number>, dim> &mass_matrix,
580 const std::array<Table<2, Number>, dim> &derivative_matrix,
581 std::array<Table<2, Number>, dim> &eigenvectors,
582 std::array<AlignedVector<Number>, dim> &eigenvalues)
583 {
584 const unsigned int n_rows_1d = mass_matrix[0].n_cols();
585
586 for (unsigned int dir = 0; dir < dim; ++dir)
587 {
588 AssertDimension(n_rows_1d, mass_matrix[dir].n_cols());
589 AssertDimension(mass_matrix[dir].n_rows(), mass_matrix[dir].n_cols());
590 AssertDimension(mass_matrix[dir].n_rows(),
591 derivative_matrix[dir].n_rows());
592 AssertDimension(mass_matrix[dir].n_rows(),
593 derivative_matrix[dir].n_cols());
594
595 eigenvectors[dir].reinit(mass_matrix[dir].n_cols(),
596 mass_matrix[dir].n_rows());
597 eigenvalues[dir].resize(mass_matrix[dir].n_cols());
598 internal::TensorProductMatrixSymmetricSum::spectral_assembly<Number>(
599 &(mass_matrix[dir](0, 0)),
600 &(derivative_matrix[dir](0, 0)),
601 mass_matrix[dir].n_rows(),
602 mass_matrix[dir].n_cols(),
603 eigenvalues[dir].begin(),
604 &(eigenvectors[dir](0, 0)));
605 }
606 }
607
608
609
610 template <std::size_t dim, typename Number, std::size_t n_lanes>
611 inline void
612 setup(
613 const std::array<Table<2, VectorizedArray<Number, n_lanes>>, dim>
614 &mass_matrix,
615 const std::array<Table<2, VectorizedArray<Number, n_lanes>>, dim>
616 &derivative_matrix,
620 {
621 const unsigned int n_rows_1d = mass_matrix[0].n_cols();
622 constexpr unsigned int macro_size =
624 const std::size_t nm_flat_size_max = n_rows_1d * n_rows_1d * macro_size;
625 const std::size_t n_flat_size_max = n_rows_1d * macro_size;
626
627 std::vector<Number> mass_matrix_flat;
628 std::vector<Number> deriv_matrix_flat;
629 std::vector<Number> eigenvalues_flat;
630 std::vector<Number> eigenvectors_flat;
631 mass_matrix_flat.resize(nm_flat_size_max);
632 deriv_matrix_flat.resize(nm_flat_size_max);
633 eigenvalues_flat.resize(n_flat_size_max);
634 eigenvectors_flat.resize(nm_flat_size_max);
635 std::array<unsigned int, macro_size> offsets_nm;
636 std::array<unsigned int, macro_size> offsets_n;
637 for (unsigned int dir = 0; dir < dim; ++dir)
638 {
639 AssertDimension(n_rows_1d, mass_matrix[dir].n_cols());
640 AssertDimension(mass_matrix[dir].n_rows(), mass_matrix[dir].n_cols());
641 AssertDimension(mass_matrix[dir].n_rows(),
642 derivative_matrix[dir].n_rows());
643 AssertDimension(mass_matrix[dir].n_rows(),
644 derivative_matrix[dir].n_cols());
645
646 const unsigned int n_rows = mass_matrix[dir].n_rows();
647 const unsigned int n_cols = mass_matrix[dir].n_cols();
648 const unsigned int nm = n_rows * n_cols;
649 for (unsigned int vv = 0; vv < macro_size; ++vv)
650 offsets_nm[vv] = nm * vv;
651
652 vectorized_transpose_and_store<Number, n_lanes>(
653 false,
654 nm,
655 &(mass_matrix[dir](0, 0)),
656 offsets_nm.data(),
657 mass_matrix_flat.data());
658 vectorized_transpose_and_store<Number, n_lanes>(
659 false,
660 nm,
661 &(derivative_matrix[dir](0, 0)),
662 offsets_nm.data(),
663 deriv_matrix_flat.data());
664
665 const Number *mass_cbegin = mass_matrix_flat.data();
666 const Number *deriv_cbegin = deriv_matrix_flat.data();
667 Number *eigenvec_begin = eigenvectors_flat.data();
668 Number *eigenval_begin = eigenvalues_flat.data();
669 for (unsigned int lane = 0; lane < macro_size; ++lane)
670 internal::TensorProductMatrixSymmetricSum::spectral_assembly<
671 Number>(mass_cbegin + nm * lane,
672 deriv_cbegin + nm * lane,
673 n_rows,
674 n_cols,
675 eigenval_begin + n_rows * lane,
676 eigenvec_begin + nm * lane);
677
678 eigenvalues[dir].resize(n_rows);
679 eigenvectors[dir].reinit(n_rows, n_cols);
680 for (unsigned int vv = 0; vv < macro_size; ++vv)
681 offsets_n[vv] = n_rows * vv;
682 vectorized_load_and_transpose<Number, n_lanes>(
683 n_rows,
684 eigenvalues_flat.data(),
685 offsets_n.data(),
686 eigenvalues[dir].begin());
687 vectorized_load_and_transpose<Number, n_lanes>(
688 nm,
689 eigenvectors_flat.data(),
690 offsets_nm.data(),
691 &(eigenvectors[dir](0, 0)));
692 }
693 }
694
695
696
697 template <std::size_t dim, typename Number>
698 inline std::array<Table<2, Number>, dim>
699 convert(const std::array<Table<2, Number>, dim> &mass_matrix)
700 {
701 return mass_matrix;
702 }
703
704
705
706 template <std::size_t dim, typename Number>
707 inline std::array<Table<2, Number>, dim>
708 convert(const std::array<FullMatrix<Number>, dim> &mass_matrix)
709 {
710 std::array<Table<2, Number>, dim> mass_copy;
711
712 std::transform(mass_matrix.cbegin(),
713 mass_matrix.cend(),
714 mass_copy.begin(),
715 [](const FullMatrix<Number> &m) -> Table<2, Number> {
716 return m;
717 });
718
719 return mass_copy;
720 }
721
722
723
724 template <std::size_t dim, typename Number>
725 inline std::array<Table<2, Number>, dim>
726 convert(const Table<2, Number> &matrix)
727 {
728 std::array<Table<2, Number>, dim> matrices;
729
730 std::fill(matrices.begin(), matrices.end(), matrix);
731
732 return matrices;
733 }
734
735
736
737 template <int n_rows_1d_templated, std::size_t dim, typename Number>
738 void
739 vmult(Number *dst,
740 const Number *src,
742 const unsigned int n_rows_1d_non_templated,
743 const std::array<const Number *, dim> &mass_matrix,
744 const std::array<const Number *, dim> &derivative_matrix)
745 {
746 const unsigned int n_rows_1d = n_rows_1d_templated == 0 ?
747 n_rows_1d_non_templated :
748 n_rows_1d_templated;
749 const unsigned int n = Utilities::fixed_power<dim>(n_rows_1d);
750
751 tmp.resize_fast(n * 2);
752 Number *t = tmp.begin();
753
755 dim,
756 n_rows_1d_templated,
757 n_rows_1d_templated,
758 Number>
759 eval({}, {}, {}, n_rows_1d, n_rows_1d);
760
761 if (dim == 1)
762 {
763 const Number *A = derivative_matrix[0];
764 eval.template apply<0, false, false>(A, src, dst);
765 }
766
767 else if (dim == 2)
768 {
769 const Number *A0 = derivative_matrix[0];
770 const Number *M0 = mass_matrix[0];
771 const Number *A1 = derivative_matrix[1];
772 const Number *M1 = mass_matrix[1];
773 eval.template apply<0, false, false>(M0, src, t);
774 eval.template apply<1, false, false>(A1, t, dst);
775 eval.template apply<0, false, false>(A0, src, t);
776 eval.template apply<1, false, true>(M1, t, dst);
777 }
778
779 else if (dim == 3)
780 {
781 const Number *A0 = derivative_matrix[0];
782 const Number *M0 = mass_matrix[0];
783 const Number *A1 = derivative_matrix[1];
784 const Number *M1 = mass_matrix[1];
785 const Number *A2 = derivative_matrix[2];
786 const Number *M2 = mass_matrix[2];
787 eval.template apply<0, false, false>(M0, src, t + n);
788 eval.template apply<1, false, false>(M1, t + n, t);
789 eval.template apply<2, false, false>(A2, t, dst);
790 eval.template apply<1, false, false>(A1, t + n, t);
791 eval.template apply<0, false, false>(A0, src, t + n);
792 eval.template apply<1, false, true>(M1, t + n, t);
793 eval.template apply<2, false, true>(M2, t, dst);
794 }
795
796 else
798 }
799
800
801
802 template <int n_rows_1d_templated, std::size_t dim, typename Number>
803 void
804 apply_inverse(Number *dst,
805 const Number *src,
806 const unsigned int n_rows_1d_non_templated,
807 const std::array<const Number *, dim> &eigenvectors,
808 const std::array<const Number *, dim> &eigenvalues,
809 const Number *inverted_eigenvalues = nullptr)
810 {
811 const unsigned int n_rows_1d = n_rows_1d_templated == 0 ?
812 n_rows_1d_non_templated :
813 n_rows_1d_templated;
814
816 dim,
817 n_rows_1d_templated,
818 n_rows_1d_templated,
819 Number>
820 eval({}, {}, {}, n_rows_1d, n_rows_1d);
821
822 // NOTE: dof_to_quad has to be interpreted as 'dof to eigenvalue index'
823 // --> apply<.,true,.> (S,src,dst) calculates dst = S^T * src,
824 // --> apply<.,false,.> (S,src,dst) calculates dst = S * src,
825 // while the eigenvectors are stored column-wise in S, i.e.
826 // rows correspond to dofs whereas columns to eigenvalue indices!
827 if (dim == 1)
828 {
829 const Number *S = eigenvectors[0];
830 eval.template apply<0, true, false>(S, src, dst);
831
832 for (unsigned int i = 0; i < n_rows_1d; ++i)
833 if (inverted_eigenvalues)
834 dst[i] *= inverted_eigenvalues[i];
835 else
836 dst[i] /= eigenvalues[0][i];
837
838 eval.template apply<0, false, false>(S, dst, dst);
839 }
840
841 else if (dim == 2)
842 {
843 const Number *S0 = eigenvectors[0];
844 const Number *S1 = eigenvectors[1];
845 eval.template apply<0, true, false>(S0, src, dst);
846 eval.template apply<1, true, false>(S1, dst, dst);
847
848 for (unsigned int i1 = 0, c = 0; i1 < n_rows_1d; ++i1)
849 for (unsigned int i0 = 0; i0 < n_rows_1d; ++i0, ++c)
850 if (inverted_eigenvalues)
851 dst[c] *= inverted_eigenvalues[c];
852 else
853 dst[c] /= (eigenvalues[1][i1] + eigenvalues[0][i0]);
854
855 eval.template apply<1, false, false>(S1, dst, dst);
856 eval.template apply<0, false, false>(S0, dst, dst);
857 }
858
859 else if (dim == 3)
860 {
861 const Number *S0 = eigenvectors[0];
862 const Number *S1 = eigenvectors[1];
863 const Number *S2 = eigenvectors[2];
864 eval.template apply<0, true, false>(S0, src, dst);
865 eval.template apply<1, true, false>(S1, dst, dst);
866 eval.template apply<2, true, false>(S2, dst, dst);
867
868 for (unsigned int i2 = 0, c = 0; i2 < n_rows_1d; ++i2)
869 for (unsigned int i1 = 0; i1 < n_rows_1d; ++i1)
870 for (unsigned int i0 = 0; i0 < n_rows_1d; ++i0, ++c)
871 if (inverted_eigenvalues)
872 dst[c] *= inverted_eigenvalues[c];
873 else
874 dst[c] /= (eigenvalues[2][i2] + eigenvalues[1][i1] +
875 eigenvalues[0][i0]);
876
877 eval.template apply<2, false, false>(S2, dst, dst);
878 eval.template apply<1, false, false>(S1, dst, dst);
879 eval.template apply<0, false, false>(S0, dst, dst);
880 }
881
882 else
884 }
885
886
887
888 template <int n_rows_1d_templated, std::size_t dim, typename Number>
889 void
890 select_vmult(Number *dst,
891 const Number *src,
893 const unsigned int n_rows_1d,
894 const std::array<const Number *, dim> &mass_matrix,
895 const std::array<const Number *, dim> &derivative_matrix);
896
897
898
899 template <int n_rows_1d_templated, std::size_t dim, typename Number>
900 void
901 select_apply_inverse(Number *dst,
902 const Number *src,
903 const unsigned int n_rows_1d,
904 const std::array<const Number *, dim> &eigenvectors,
905 const std::array<const Number *, dim> &eigenvalues,
906 const Number *inverted_eigenvalues = nullptr);
907 } // namespace TensorProductMatrixSymmetricSum
908} // namespace internal
909
910
911template <int dim, typename Number, int n_rows_1d>
912inline unsigned int
914{
915 unsigned int m = mass_matrix[0].n_rows();
916 for (unsigned int d = 1; d < dim; ++d)
917 m *= mass_matrix[d].n_rows();
918 return m;
919}
920
921
922
923template <int dim, typename Number, int n_rows_1d>
924inline unsigned int
926{
927 unsigned int n = mass_matrix[0].n_cols();
928 for (unsigned int d = 1; d < dim; ++d)
929 n *= mass_matrix[d].n_cols();
930 return n;
931}
932
933
934
935template <int dim, typename Number, int n_rows_1d>
936inline void
938 const ArrayView<Number> &dst_view,
939 const ArrayView<const Number> &src_view) const
940{
941 std::scoped_lock lock(this->mutex);
942 this->vmult(dst_view, src_view, this->tmp_array);
943}
944
945
946
947template <int dim, typename Number, int n_rows_1d>
948inline void
950 const ArrayView<Number> &dst_view,
951 const ArrayView<const Number> &src_view,
952 AlignedVector<Number> &tmp_array) const
953{
954 AssertDimension(dst_view.size(), this->m());
955 AssertDimension(src_view.size(), this->n());
956
957 Number *dst = dst_view.begin();
958 const Number *src = src_view.begin();
959
960 std::array<const Number *, dim> mass_matrix, derivative_matrix;
961
962 for (unsigned int d = 0; d < dim; ++d)
963 {
964 mass_matrix[d] = &this->mass_matrix[d](0, 0);
965 derivative_matrix[d] = &this->derivative_matrix[d](0, 0);
966 }
967
968 const unsigned int n_rows_1d_non_templated = this->mass_matrix[0].n_rows();
969
970 if constexpr (n_rows_1d != -1)
971 internal::TensorProductMatrixSymmetricSum::vmult<n_rows_1d>(
972 dst,
973 src,
974 tmp_array,
975 n_rows_1d_non_templated,
976 mass_matrix,
977 derivative_matrix);
978 else
979 internal::TensorProductMatrixSymmetricSum::select_vmult<1>(
980 dst,
981 src,
982 tmp_array,
983 n_rows_1d_non_templated,
984 mass_matrix,
985 derivative_matrix);
986}
987
988
989
990template <int dim, typename Number, int n_rows_1d>
991inline void
993 const ArrayView<Number> &dst_view,
994 const ArrayView<const Number> &src_view) const
995{
996 AssertDimension(dst_view.size(), this->n());
997 AssertDimension(src_view.size(), this->m());
998
999 Number *dst = dst_view.begin();
1000 const Number *src = src_view.begin();
1001
1002 std::array<const Number *, dim> eigenvectors, eigenvalues;
1003
1004 for (unsigned int d = 0; d < dim; ++d)
1005 {
1006 eigenvectors[d] = &this->eigenvectors[d](0, 0);
1007 eigenvalues[d] = this->eigenvalues[d].data();
1008 }
1009
1010 const unsigned int n_rows_1d_non_templated = this->mass_matrix[0].n_rows();
1011
1012 if constexpr (n_rows_1d != -1)
1013 internal::TensorProductMatrixSymmetricSum::apply_inverse<n_rows_1d>(
1014 dst, src, n_rows_1d_non_templated, eigenvectors, eigenvalues);
1015 else
1016 internal::TensorProductMatrixSymmetricSum::select_apply_inverse<1>(
1017 dst, src, n_rows_1d_non_templated, eigenvectors, eigenvalues);
1018}
1019
1020
1021
1022template <int dim, typename Number, int n_rows_1d>
1023std::size_t
1025 const
1026{
1027 return MemoryConsumption::memory_consumption(mass_matrix) +
1028 MemoryConsumption::memory_consumption(derivative_matrix) +
1032}
1033
1034
1035
1036template <int dim, typename Number, int n_rows_1d>
1037template <typename T>
1039 TensorProductMatrixSymmetricSum(const T &mass_matrix,
1040 const T &derivative_matrix)
1041{
1042 reinit(mass_matrix, derivative_matrix);
1043}
1044
1045
1046
1047template <int dim, typename Number, int n_rows_1d>
1048template <typename T>
1049inline void
1051 const T &mass_matrix,
1052 const T &derivative_matrix)
1053{
1054 this->mass_matrix =
1055 internal::TensorProductMatrixSymmetricSum::convert<dim>(mass_matrix);
1056 this->derivative_matrix =
1057 internal::TensorProductMatrixSymmetricSum::convert<dim>(derivative_matrix);
1058
1059 internal::TensorProductMatrixSymmetricSum::setup(this->mass_matrix,
1060 this->derivative_matrix,
1061 this->eigenvectors,
1062 this->eigenvalues);
1063}
1064
1065
1066
1067template <int dim, typename Number, int n_rows_1d>
1069 AdditionalData::AdditionalData(const bool compress_matrices,
1070 const bool precompute_inverse_diagonal)
1071 : compress_matrices(compress_matrices)
1072 , precompute_inverse_diagonal(precompute_inverse_diagonal)
1073{}
1074
1075
1076
1077template <int dim, typename Number, int n_rows_1d>
1080 const AdditionalData &additional_data)
1081 : compress_matrices(additional_data.compress_matrices)
1082 , precompute_inverse_diagonal(additional_data.precompute_inverse_diagonal)
1083{}
1084
1085
1086
1087template <int dim, typename Number, int n_rows_1d>
1088void
1090 const unsigned int size)
1091{
1092 if (compress_matrices == false)
1093 mass_and_derivative_matrices.resize(size * dim);
1094 else
1095 indices.assign(size * dim, numbers::invalid_unsigned_int);
1096}
1097
1098
1099
1100template <int dim, typename Number, int n_rows_1d>
1101template <typename T>
1102void
1104 const unsigned int index,
1105 const T &Ms_in,
1106 const T &Ks_in)
1107{
1108 const auto Ms =
1109 internal::TensorProductMatrixSymmetricSum::convert<dim>(Ms_in);
1110 const auto Ks =
1111 internal::TensorProductMatrixSymmetricSum::convert<dim>(Ks_in);
1112
1113 for (unsigned int d = 0; d < dim; ++d)
1114 {
1115 if (compress_matrices == false)
1116 {
1117 const MatrixPairType matrix(Ms[d], Ks[d]);
1118 mass_and_derivative_matrices[index * dim + d] = matrix;
1119 }
1120 else
1121 {
1122 using VectorizedArrayTrait =
1124
1125 std::bitset<VectorizedArrayTrait::width()> mask;
1126
1127 for (unsigned int v = 0; v < VectorizedArrayTrait::width(); ++v)
1128 {
1129 typename VectorizedArrayTrait::value_type a = 0.0;
1130
1131 for (unsigned int i = 0; i < Ms[d].size(0); ++i)
1132 for (unsigned int j = 0; j < Ms[d].size(1); ++j)
1133 {
1134 a += std::abs(VectorizedArrayTrait::get(Ms[d][i][j], v));
1135 a += std::abs(VectorizedArrayTrait::get(Ks[d][i][j], v));
1136 }
1137
1138 mask[v] = (a != 0.0);
1139 }
1140
1141 const MatrixPairTypeWithMask matrix{mask, {Ms[d], Ks[d]}};
1142
1143 const auto ptr = cache.find(matrix);
1144
1145 if (ptr != cache.end())
1146 {
1147 const auto ptr_index = ptr->second;
1148 indices[index * dim + d] = ptr_index;
1149
1150 if ([&]() {
1151 for (unsigned int v = 0; v < VectorizedArrayTrait::width();
1152 ++v)
1153 if ((mask[v] == true) && (ptr->first.first[v] == false))
1154 return false;
1155
1156 return true;
1157 }())
1158 {
1159 // nothing to do
1160 }
1161 else
1162 {
1163 auto mask_new = ptr->first.first;
1164 auto Ms_new = ptr->first.second.first;
1165 auto Ks_new = ptr->first.second.second;
1166
1167 for (unsigned int v = 0; v < VectorizedArrayTrait::width();
1168 ++v)
1169 if (mask_new[v] == false && mask[v] == true)
1170 {
1171 mask_new[v] = true;
1172
1173 for (unsigned int i = 0; i < Ms_new.size(0); ++i)
1174 for (unsigned int j = 0; j < Ms_new.size(1); ++j)
1175 {
1176 VectorizedArrayTrait::get(Ms_new[i][j], v) =
1177 VectorizedArrayTrait::get(Ms[d][i][j], v);
1178 VectorizedArrayTrait::get(Ks_new[i][j], v) =
1179 VectorizedArrayTrait::get(Ks[d][i][j], v);
1180 }
1181 }
1182
1183 cache.erase(ptr);
1184
1185 const MatrixPairTypeWithMask entry_new{mask_new,
1186 {Ms_new, Ks_new}};
1187
1188 const auto ptr_ = cache.find(entry_new);
1189 AssertThrow(ptr_ == cache.end(), ExcNotImplemented());
1190
1191 cache[entry_new] = ptr_index;
1192 }
1193 }
1194 else
1195 {
1196 const auto size = cache.size();
1197 indices[index * dim + d] = size;
1198 cache[matrix] = size;
1199 }
1200 }
1201 }
1202}
1203
1204
1205
1206template <int dim, typename Number, int n_rows_1d>
1207void
1209{
1210 const auto store = [&](const unsigned int index,
1211 const MatrixPairType &M_and_K) {
1212 std::array<Table<2, Number>, 1> mass_matrix;
1213 mass_matrix[0] = M_and_K.first;
1214
1215 std::array<Table<2, Number>, 1> derivative_matrix;
1216 derivative_matrix[0] = M_and_K.second;
1217
1218 std::array<Table<2, Number>, 1> eigenvectors;
1219 std::array<AlignedVector<Number>, 1> eigenvalues;
1220
1221 internal::TensorProductMatrixSymmetricSum::setup(mass_matrix,
1222 derivative_matrix,
1224 eigenvalues);
1225
1226 for (unsigned int i = 0, m = matrix_ptr[index], v = vector_ptr[index];
1227 i < mass_matrix[0].n_rows();
1228 ++i, ++v)
1229 {
1230 for (unsigned int j = 0; j < mass_matrix[0].n_cols(); ++j, ++m)
1231 {
1232 this->mass_matrices[m] = mass_matrix[0][i][j];
1233 this->derivative_matrices[m] = derivative_matrix[0][i][j];
1234 this->eigenvectors[m] = eigenvectors[0][i][j];
1235 }
1236
1237 this->eigenvalues[v] = eigenvalues[0][i];
1238 }
1239 };
1240
1241 if (compress_matrices == false)
1242 {
1243 // case 1) no compression requested
1244
1245 AssertDimension(cache.size(), 0);
1246 AssertDimension(indices.size(), 0);
1247
1248 this->vector_ptr.resize(mass_and_derivative_matrices.size() + 1);
1249 this->matrix_ptr.resize(mass_and_derivative_matrices.size() + 1);
1250
1251 for (unsigned int i = 0; i < mass_and_derivative_matrices.size(); ++i)
1252 {
1253 const auto &M = mass_and_derivative_matrices[i].first;
1254
1255 this->vector_ptr[i + 1] = M.n_rows();
1256 this->matrix_ptr[i + 1] = M.n_rows() * M.n_cols();
1257 }
1258
1259 for (unsigned int i = 0; i < mass_and_derivative_matrices.size(); ++i)
1260 {
1261 this->vector_ptr[i + 1] += this->vector_ptr[i];
1262 this->matrix_ptr[i + 1] += this->matrix_ptr[i];
1263 }
1264
1265 this->mass_matrices.resize_fast(matrix_ptr.back());
1266 this->derivative_matrices.resize_fast(matrix_ptr.back());
1267 this->eigenvectors.resize_fast(matrix_ptr.back());
1268 this->eigenvalues.resize_fast(vector_ptr.back());
1269
1270 for (unsigned int i = 0; i < mass_and_derivative_matrices.size(); ++i)
1271 store(i, mass_and_derivative_matrices[i]);
1272
1273 mass_and_derivative_matrices.clear();
1274 }
1275 else if (cache.size() == indices.size())
1276 {
1277 // case 2) compression requested but none possible
1278
1279 this->vector_ptr.resize(cache.size() + 1);
1280 this->matrix_ptr.resize(cache.size() + 1);
1281
1282 std::map<unsigned int, MatrixPairType> inverted_cache;
1283
1284 for (const auto &i : cache)
1285 inverted_cache[i.second] = i.first.second;
1286
1287 for (unsigned int i = 0; i < indices.size(); ++i)
1288 {
1289 const auto &M = inverted_cache[indices[i]].first;
1290
1291 this->vector_ptr[i + 1] = M.n_rows();
1292 this->matrix_ptr[i + 1] = M.n_rows() * M.n_cols();
1293 }
1294
1295 for (unsigned int i = 0; i < cache.size(); ++i)
1296 {
1297 this->vector_ptr[i + 1] += this->vector_ptr[i];
1298 this->matrix_ptr[i + 1] += this->matrix_ptr[i];
1299 }
1300
1301 this->mass_matrices.resize_fast(matrix_ptr.back());
1302 this->derivative_matrices.resize_fast(matrix_ptr.back());
1303 this->eigenvectors.resize_fast(matrix_ptr.back());
1304 this->eigenvalues.resize_fast(vector_ptr.back());
1305
1306 for (unsigned int i = 0; i < indices.size(); ++i)
1307 store(i, inverted_cache[indices[i]]);
1308
1309 indices.clear();
1310 cache.clear();
1311 }
1312 else
1313 {
1314 // case 3) compress
1315
1316 this->vector_ptr.resize(cache.size() + 1);
1317 this->matrix_ptr.resize(cache.size() + 1);
1318
1319 for (const auto &i : cache)
1320 {
1321 const auto &M = i.first.second.first;
1322
1323 this->vector_ptr[i.second + 1] = M.n_rows();
1324 this->matrix_ptr[i.second + 1] = M.n_rows() * M.n_cols();
1325 }
1326
1327 for (unsigned int i = 0; i < cache.size(); ++i)
1328 {
1329 this->vector_ptr[i + 1] += this->vector_ptr[i];
1330 this->matrix_ptr[i + 1] += this->matrix_ptr[i];
1331 }
1332
1333 this->mass_matrices.resize_fast(matrix_ptr.back());
1334 this->derivative_matrices.resize_fast(matrix_ptr.back());
1335 this->eigenvectors.resize_fast(matrix_ptr.back());
1336 this->eigenvalues.resize_fast(vector_ptr.back());
1337
1338 for (const auto &i : cache)
1339 store(i.second, i.first.second);
1340
1341 cache.clear();
1342 }
1343
1344 if (precompute_inverse_diagonal)
1345 {
1346 if (dim == 1)
1347 {
1348 // 1D case: simply invert 1D eigenvalues
1349 for (unsigned int i = 0; i < this->eigenvalues.size(); ++i)
1350 this->eigenvalues[i] = Number(1.0) / this->eigenvalues[i];
1351 std::swap(this->inverted_eigenvalues, eigenvalues);
1352 }
1353 else
1354 {
1355 // 2D and 3D case: we have 2 or 3 1d eigenvalues so that we
1356 // need to combine these
1357
1358 // step 1) if eigenvalues/eigenvectors are compressed, we
1359 // need to compress the diagonal (the combination of ev
1360 // indices) as well. This is an optional step.
1361 std::vector<unsigned int> indices_ev;
1362
1363 if (indices.size() > 0)
1364 {
1365 // 1a) create cache (ev indics -> diag index)
1366 const unsigned int n_cells = indices.size() / dim;
1367 std::map<std::array<unsigned int, dim>, unsigned int> cache_ev;
1368 std::vector<unsigned int> cache_ev_idx(n_cells);
1369
1370 for (unsigned int i = 0, c = 0; i < n_cells; ++i)
1371 {
1372 std::array<unsigned int, dim> id;
1373
1374 for (unsigned int d = 0; d < dim; ++d, ++c)
1375 id[d] = indices[c];
1376
1377 const auto id_ptr = cache_ev.find(id);
1378
1379 if (id_ptr == cache_ev.end())
1380 {
1381 const auto size = cache_ev.size();
1382 cache_ev_idx[i] = size;
1383 cache_ev[id] = size;
1384 }
1385 else
1386 {
1387 cache_ev_idx[i] = id_ptr->second;
1388 }
1389 }
1390
1391 // 1b) store diagonal indices for each cell
1392 std::vector<unsigned int> new_indices;
1393 new_indices.reserve(indices.size() / dim * (dim + 1));
1394
1395 for (unsigned int i = 0, c = 0; i < n_cells; ++i)
1396 {
1397 for (unsigned int d = 0; d < dim; ++d, ++c)
1398 new_indices.push_back(indices[c]);
1399 new_indices.push_back(cache_ev_idx[i]);
1400 }
1401
1402 // 1c) transpose cache (diag index -> ev indices)
1403 indices_ev.resize(cache_ev.size() * dim);
1404 for (const auto &entry : cache_ev)
1405 for (unsigned int d = 0; d < dim; ++d)
1406 indices_ev[entry.second * dim + d] = entry.first[d];
1407
1408 std::swap(this->indices, new_indices);
1409 }
1410
1411 // step 2) allocate memory and set pointers
1412 const unsigned int n_diag =
1413 ((indices_ev.size() > 0) ? indices_ev.size() :
1414 (matrix_ptr.size() - 1)) /
1415 dim;
1416
1417 std::vector<unsigned int> new_vector_ptr(n_diag + 1, 0);
1418 std::vector<unsigned int> new_vector_n_rows_1d(n_diag, 0);
1419
1420 for (unsigned int i = 0; i < n_diag; ++i)
1421 {
1422 const unsigned int c = (indices_ev.size() > 0) ?
1423 indices_ev[dim * i + 0] :
1424 (dim * i + 0);
1425
1426 const unsigned int n_rows = vector_ptr[c + 1] - vector_ptr[c];
1427
1428 new_vector_n_rows_1d[i] = n_rows;
1429 new_vector_ptr[i + 1] = Utilities::pow(n_rows, dim);
1430 }
1431
1432 for (unsigned int i = 0; i < n_diag; ++i)
1433 new_vector_ptr[i + 1] += new_vector_ptr[i];
1434
1435 this->inverted_eigenvalues.resize(new_vector_ptr.back());
1436
1437 // step 3) loop over all unique diagonal entries and invert
1438 for (unsigned int i = 0; i < n_diag; ++i)
1439 {
1440 std::array<Number *, dim> evs;
1441
1442 for (unsigned int d = 0; d < dim; ++d)
1443 evs[d] =
1444 &this
1445 ->eigenvalues[this->vector_ptr[(indices_ev.size() > 0) ?
1446 indices_ev[dim * i + d] :
1447 (dim * i + d)]];
1448
1449 const unsigned int mm = new_vector_n_rows_1d[i];
1450 if (dim == 2)
1451 {
1452 for (unsigned int i1 = 0, c = 0; i1 < mm; ++i1)
1453 for (unsigned int i0 = 0; i0 < mm; ++i0, ++c)
1454 this->inverted_eigenvalues[new_vector_ptr[i] + c] =
1455 Number(1.0) / (evs[1][i1] + evs[0][i0]);
1456 }
1457 else
1458 {
1459 for (unsigned int i2 = 0, c = 0; i2 < mm; ++i2)
1460 for (unsigned int i1 = 0; i1 < mm; ++i1)
1461 for (unsigned int i0 = 0; i0 < mm; ++i0, ++c)
1462 this->inverted_eigenvalues[new_vector_ptr[i] + c] =
1463 Number(1.0) / (evs[2][i2] + evs[1][i1] + evs[0][i0]);
1464 }
1465 }
1466
1467 // step 4) clean up
1468 std::swap(this->vector_ptr, new_vector_ptr);
1469 std::swap(this->vector_n_rows_1d, new_vector_n_rows_1d);
1470 }
1471
1472 this->eigenvalues.clear();
1473 }
1474}
1475
1476
1477
1478template <int dim, typename Number, int n_rows_1d>
1479void
1481 apply_inverse(const unsigned int index,
1482 const ArrayView<Number> &dst_in,
1483 const ArrayView<const Number> &src_in) const
1484{
1485 Number *dst = dst_in.begin();
1486 const Number *src = src_in.begin();
1487
1488 if (this->eigenvalues.empty() == false)
1489 {
1490 std::array<const Number *, dim> eigenvectors;
1491 std::array<const Number *, dim> eigenvalues;
1492 unsigned int n_rows_1d_non_templated = 0;
1493
1494 for (unsigned int d = 0; d < dim; ++d)
1495 {
1496 const unsigned int translated_index =
1497 (indices.size() > 0) ? indices[dim * index + d] : (dim * index + d);
1498
1499 eigenvectors[d] =
1500 this->eigenvectors.data() + matrix_ptr[translated_index];
1501 eigenvalues[d] =
1502 this->eigenvalues.data() + vector_ptr[translated_index];
1503 n_rows_1d_non_templated =
1504 vector_ptr[translated_index + 1] - vector_ptr[translated_index];
1505 }
1506
1507 if constexpr (n_rows_1d != -1)
1508 internal::TensorProductMatrixSymmetricSum::apply_inverse<n_rows_1d>(
1509 dst, src, n_rows_1d_non_templated, eigenvectors, eigenvalues);
1510 else
1511 internal::TensorProductMatrixSymmetricSum::select_apply_inverse<1>(
1512 dst, src, n_rows_1d_non_templated, eigenvectors, eigenvalues);
1513 }
1514 else
1515 {
1516 std::array<const Number *, dim> eigenvectors;
1517 const Number *inverted_eigenvalues = nullptr;
1518 unsigned int n_rows_1d_non_templated = 0;
1519
1520 for (unsigned int d = 0; d < dim; ++d)
1521 {
1522 const unsigned int translated_index =
1523 (indices.size() > 0) ?
1524 indices[((dim == 1) ? 1 : (dim + 1)) * index + d] :
1525 (dim * index + d);
1526
1527 eigenvectors[d] =
1528 this->eigenvectors.data() + matrix_ptr[translated_index];
1529 }
1530
1531 {
1532 const unsigned int translated_index =
1533 ((indices.size() > 0) && (dim != 1)) ?
1534 indices[(dim + 1) * index + dim] :
1535 index;
1536
1537 inverted_eigenvalues =
1538 this->inverted_eigenvalues.data() + vector_ptr[translated_index];
1539 n_rows_1d_non_templated =
1540 (dim == 1) ?
1541 (vector_ptr[translated_index + 1] - vector_ptr[translated_index]) :
1542 vector_n_rows_1d[translated_index];
1543 }
1544
1545 if constexpr (n_rows_1d != -1)
1546 internal::TensorProductMatrixSymmetricSum::apply_inverse<n_rows_1d>(
1547 dst,
1548 src,
1549 n_rows_1d_non_templated,
1551 {},
1552 inverted_eigenvalues);
1553 else
1554 internal::TensorProductMatrixSymmetricSum::select_apply_inverse<1>(
1555 dst,
1556 src,
1557 n_rows_1d_non_templated,
1559 {},
1560 inverted_eigenvalues);
1561 }
1562}
1563
1564
1565
1566template <int dim, typename Number, int n_rows_1d>
1567std::size_t
1569 memory_consumption() const
1570{
1573 MemoryConsumption::memory_consumption(derivative_matrices) +
1578}
1579
1580
1581
1582template <int dim, typename Number, int n_rows_1d>
1583std::size_t
1585 storage_size() const
1586{
1587 if (matrix_ptr.empty())
1588 return 0; // if not initialized
1589
1590 return matrix_ptr.size() - 1;
1591}
1592
1593
1594
1595#endif
1596
1598
1599#endif
*  *  for(const auto &cell :triangulation.active_cell_iterators())
*  *  iterator begin()
void resize_fast(const size_type new_size)
iterator begin()
iterator begin() const
Definition array_view.h:755
std::size_t size() const
Definition array_view.h:737
std::complex< typename numbers::NumberTraits< number >::real_type > eigenvalue(const size_type i) const
void compute_generalized_eigenvalues_symmetric(LAPACKFullMatrix< number > &B, const number lower_bound, const number upper_bound, const number abs_accuracy, Vector< number > &eigenvalues, std::vector< Vector< number > > &eigenvectors, const types::blas_int itype=1)
void apply_inverse(const unsigned int index, const ArrayView< Number > &dst_in, const ArrayView< const Number > &src_in) const
std::vector< MatrixPairType > mass_and_derivative_matrices
std::pair< std::bitset<::internal::VectorizedArrayTrait< Number >::width()>, MatrixPairType > MatrixPairTypeWithMask
std::pair< Table< 2, Number >, Table< 2, Number > > MatrixPairType
void reserve(const unsigned int size)
void insert(const unsigned int index, const T &Ms, const T &Ks)
std::map< MatrixPairTypeWithMask, unsigned int, internal::TensorProductMatrixSymmetricSum::MatrixPairComparator< Number > > cache
TensorProductMatrixSymmetricSumCollection(const AdditionalData &additional_data=AdditionalData())
void vmult(const ArrayView< Number > &dst, const ArrayView< const Number > &src, AlignedVector< Number > &tmp) const
std::array< Table< 2, Number >, dim > eigenvectors
std::array< Table< 2, Number >, dim > derivative_matrix
void reinit(const T &mass_matrix, const T &derivative_matrix)
void apply_inverse(const ArrayView< Number > &dst, const ArrayView< const Number > &src) const
void vmult(const ArrayView< Number > &dst, const ArrayView< const Number > &src) const
std::size_t memory_consumption() const
std::array< Table< 2, Number >, dim > mass_matrix
std::array< AlignedVector< Number >, dim > eigenvalues
TensorProductMatrixSymmetricSum(const T &mass_matrix, const T &derivative_matrix)
constexpr void clear()
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_NOT_IMPLEMENTED()
Point< 2 > second
Definition grid_out.cc:4640
Point< 2 > first
Definition grid_out.cc:4639
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
static ::ExceptionBase & ExcInternalError()
#define AssertThrow(cond, exc)
std::size_t size
Definition mpi.cc:733
@ matrix
Contents is actually a matrix.
void mass_matrix(FullMatrix< double > &M, const FEValuesBase< dim > &fe, const double factor=1.)
Definition l2.h:55
std::enable_if_t< std::is_fundamental_v< T >, std::size_t > memory_consumption(const T &t)
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
*  *  *  RotationFunction< dim, Number >::RotationFunction Number(dim)
constexpr T pow(const T base, const int iexp)
Definition utilities.h:966
unsigned int n_cells(const internal::TriangulationImplementation::NumberCache< 1 > &c)
Definition tria.cc:15808
void reinit(MatrixBlock< MatrixType > &v, const BlockSparsityPattern &p)
constexpr unsigned int invalid_unsigned_int
Definition types.h:228
STL namespace.
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
AdditionalData(const bool compress_matrices=true, const bool precompute_inverse_diagonal=true)
bool operator()(const MatrixPairType &left, const MatrixPairType &right) const
std::pair< std::bitset< width >, std::pair< Table< 2, Number >, Table< 2, Number > > > MatrixPairType
static constexpr std::size_t width()
std::array< Number, 1 > eigenvalues(const SymmetricTensor< 2, 1, Number > &T)
std::array< std::pair< Number, Tensor< 1, dim, Number > >, dim > eigenvectors(const SymmetricTensor< 2, dim, Number > &T, const SymmetricTensorEigenvectorMethod method=SymmetricTensorEigenvectorMethod::ql_implicit_shifts)