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