Reference documentation for deal.II version 9.0.0
tensor_product_matrix.h
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2017 - 2018 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #ifndef dealii_tensor_product_matrix_h
17 #define dealii_tensor_product_matrix_h
18 
19 
20 #include <deal.II/base/array_view.h>
21 #include <deal.II/base/config.h>
22 #include <deal.II/base/thread_management.h>
23 #include <deal.II/lac/lapack_full_matrix.h>
24 #include <deal.II/matrix_free/tensor_product_kernels.h>
25 
26 DEAL_II_NAMESPACE_OPEN
27 
28 template <typename> class Vector;
29 template <typename> class FullMatrix;
30 template <typename> class VectorizedArray;
31 
66 template <int dim, typename Number, int size = -1>
68 {
69 public:
75  unsigned int m () const;
76 
82  unsigned int n () const;
83 
90  void vmult (const ArrayView<Number> &dst,
91  const ArrayView<const Number> &src) const;
92 
99  void apply_inverse (const ArrayView<Number> &dst,
100  const ArrayView<const Number> &src) const;
101 
102 protected:
107 
111  std::array<Table<2,Number>,dim> mass_matrix;
112 
116  std::array<Table<2,Number>,dim> derivative_matrix;
117 
122  std::array<AlignedVector<Number>,dim> eigenvalues;
123 
128  std::array<Table<2,Number>,dim> eigenvectors;
129 
130 private:
135 
140 };
141 
142 
143 
214 template <int dim, typename Number, int size = -1>
216  : public TensorProductMatrixSymmetricSumBase<dim,Number,size>
217 {
218 public:
222  TensorProductMatrixSymmetricSum () = default;
223 
230  const std::array<Table<2,Number>,dim> &derivative_matrix);
231 
238  const std::array<FullMatrix<Number>,dim> &derivative_matrix);
239 
246 
258  void reinit (const std::array<Table<2,Number>,dim> &mass_matrix,
259  const std::array<Table<2,Number>,dim> &derivative_matrix);
260 
266  void reinit (const std::array<FullMatrix<Number>,dim> &mass_matrix,
267  const std::array<FullMatrix<Number>,dim> &derivative_matrix);
268 
274  void reinit (const Table<2,Number> &mass_matrix,
276 
277 private:
286  template <typename MatrixArray>
287  void reinit_impl (MatrixArray &&mass_matrix,
288  MatrixArray &&derivative_matrix);
289 };
290 
291 
292 
301 template <int dim, typename Number, int size>
303  : public TensorProductMatrixSymmetricSumBase<dim,VectorizedArray<Number>,size>
304 {
305 public:
309  TensorProductMatrixSymmetricSum () = default;
310 
317  const std::array<Table<2,VectorizedArray<Number> >,dim> &derivative_matrix);
318 
326 
338  void reinit (const std::array<Table<2,VectorizedArray<Number> >,dim> &mass_matrix,
339  const std::array<Table<2,VectorizedArray<Number> >,dim> &derivative_matrix);
340 
348 
349 private:
358  template <typename MatrixArray>
359  void reinit_impl (MatrixArray &&mass_matrix,
360  MatrixArray &&derivative_matrix);
361 };
362 
363 
364 /*----------------------- Inline functions ----------------------------------*/
365 
366 #ifndef DOXYGEN
367 
368 namespace internal
369 {
370  namespace TensorProductMatrix
371  {
380  template <typename Number>
381  void
382  spectral_assembly (const Number *mass_matrix,
383  const Number *derivative_matrix,
384  const unsigned int n_rows,
385  const unsigned int n_cols,
386  Number *eigenvalues,
387  Number *eigenvectors)
388  {
389  Assert (n_rows == n_cols, ExcNotImplemented());
390 
391  auto &&transpose_fill_nm
392  = [](Number *out, const Number *in, const unsigned int n, const unsigned int m)
393  {
394  for (unsigned int mm = 0; mm < m; ++mm)
395  for (unsigned int nn = 0; nn < n; ++nn)
396  out[mm+nn*m] = *(in++);
397  };
398 
399  std::vector<::Vector<Number> > eigenvecs(n_rows);
400  LAPACKFullMatrix<Number> mass_copy(n_rows, n_cols);
401  LAPACKFullMatrix<Number> deriv_copy(n_rows, n_cols);
402 
403  transpose_fill_nm (&(mass_copy(0,0)), mass_matrix, n_rows, n_cols);
404  transpose_fill_nm (&(deriv_copy(0,0)), derivative_matrix, n_rows, n_cols);
405 
406  deriv_copy.compute_generalized_eigenvalues_symmetric (mass_copy, eigenvecs);
407  AssertDimension (eigenvecs.size(), n_rows);
408  for (unsigned int i=0; i<n_rows; ++i)
409  for (unsigned int j=0; j<n_cols; ++j, ++eigenvectors)
410  *eigenvectors = eigenvecs[j][i];
411 
412  for (unsigned int i=0; i<n_rows; ++i, ++eigenvalues)
413  *eigenvalues = deriv_copy.eigenvalue(i).real();
414  }
415  }
416 }
417 
418 
419 template <int dim, typename Number, int size>
420 inline
421 unsigned int
423 {
424  unsigned int m = mass_matrix[0].n_rows();
425  for (unsigned int d = 1; d < dim; ++d)
426  m *= mass_matrix[d].n_rows();
427  return m;
428 }
429 
430 
431 
432 template <int dim, typename Number, int size>
433 inline
434 unsigned int
436 {
437  unsigned int n = mass_matrix[0].n_cols();
438  for (unsigned int d = 1; d < dim; ++d)
439  n *= mass_matrix[d].n_cols();
440  return n;
441 }
442 
443 
444 
445 template <int dim, typename Number, int size>
446 inline
447 void
449 ::vmult (const ArrayView<Number> &dst_view,
450  const ArrayView<const Number> &src_view) const
451 {
452  AssertDimension (dst_view.size(), this->m());
453  AssertDimension (src_view.size(), this->n());
454  Threads::Mutex::ScopedLock lock(this->mutex);
455  const unsigned int n = Utilities::fixed_power<dim>(size > 0 ? size : eigenvalues[0].size());
456  tmp_array.resize_fast(n*2);
457  constexpr int kernel_size = size > 0 ? size : 0;
460  AlignedVector<Number> {}, mass_matrix[0].n_rows(), mass_matrix[0].n_rows());
461  Number *t = tmp_array.begin();
462  const Number *src = src_view.begin();
463  Number *dst = &(dst_view[0]);
464 
465  if (dim == 1)
466  {
467  const Number *A = &derivative_matrix[0](0,0);
468  eval.template apply<0, false, false> (A, src, dst);
469  }
470 
471  else if (dim == 2)
472  {
473  const Number *A0 = &derivative_matrix[0](0,0);
474  const Number *M0 = &mass_matrix[0](0,0);
475  const Number *A1 = &derivative_matrix[1](0,0);
476  const Number *M1 = &mass_matrix[1](0,0);
477  eval.template apply<0, false, false> (M0, src, t);
478  eval.template apply<1, false, false> (A1, t, dst);
479  eval.template apply<0, false, false> (A0, src, t);
480  eval.template apply<1, false, true> (M1, t, dst);
481  }
482 
483  else if (dim == 3)
484  {
485  const Number *A0 = &derivative_matrix[0](0,0);
486  const Number *M0 = &mass_matrix[0](0,0);
487  const Number *A1 = &derivative_matrix[1](0,0);
488  const Number *M1 = &mass_matrix[1](0,0);
489  const Number *A2 = &derivative_matrix[2](0,0);
490  const Number *M2 = &mass_matrix[2](0,0);
491  eval.template apply<0, false, false> (M0, src, t+n);
492  eval.template apply<1, false, false> (M1, t+n, t);
493  eval.template apply<2, false, false> (A2, t, dst);
494  eval.template apply<1, false, false> (A1, t+n, t);
495  eval.template apply<0, false, false> (A0, src, t+n);
496  eval.template apply<1, false, true> (M1, t+n, t);
497  eval.template apply<2, false, true> (M2, t, dst);
498  }
499 
500  else
501  AssertThrow(false, ExcNotImplemented());
502 }
503 
504 
505 
506 template <int dim, typename Number, int size>
507 inline
508 void
510 ::apply_inverse (const ArrayView<Number> &dst_view,
511  const ArrayView<const Number> &src_view) const
512 {
513  AssertDimension (dst_view.size(), this->n());
514  AssertDimension (src_view.size(), this->m());
515  Threads::Mutex::ScopedLock lock(this->mutex);
516  const unsigned int n = size > 0 ? size : eigenvalues[0].size();
517  tmp_array.resize_fast (Utilities::fixed_power<dim>(n));
518  constexpr int kernel_size = size > 0 ? size : 0;
521  AlignedVector<Number>(), mass_matrix[0].n_rows(), mass_matrix[0].n_rows());
522  Number *t = tmp_array.begin();
523  const Number *src = src_view.data();
524  Number *dst = &(dst_view[0]);
525 
526  // NOTE: dof_to_quad has to be interpreted as 'dof to eigenvalue index'
527  // --> apply<.,true,.> (S,src,dst) calculates dst = S^T * src,
528  // --> apply<.,false,.> (S,src,dst) calculates dst = S * src,
529  // while the eigenvectors are stored column-wise in S, i.e.
530  // rows correspond to dofs whereas columns to eigenvalue indices!
531  if (dim == 1)
532  {
533  const Number *S = &eigenvectors[0](0,0);
534  eval.template apply<0, true, false> (S, src, t);
535  for (unsigned int i=0; i<n; ++i)
536  t[i] /= eigenvalues[0][i];
537  eval.template apply<0, false, false> (S, t, dst);
538  }
539 
540  else if (dim == 2)
541  {
542  const Number *S0 = &(eigenvectors[0](0,0));
543  const Number *S1 = &(eigenvectors[1](0,0));
544  eval.template apply<0, true, false> (S0, src, t);
545  eval.template apply<1, true, false> (S1, t, dst);
546  for (unsigned int i1=0, c=0; i1<n; ++i1)
547  for (unsigned int i0=0; i0<n; ++i0, ++c)
548  dst[c] /= (eigenvalues[1][i1] + eigenvalues[0][i0]);
549  eval.template apply<0, false, false> (S0, dst, t);
550  eval.template apply<1, false, false> (S1, t, dst);
551  }
552 
553  else if (dim == 3)
554  {
555  const Number *S0 = &eigenvectors[0](0,0);
556  const Number *S1 = &eigenvectors[1](0,0);
557  const Number *S2 = &eigenvectors[2](0,0);
558  eval.template apply<0, true, false> (S0, src, t);
559  eval.template apply<1, true, false> (S1, t, dst);
560  eval.template apply<2, true, false> (S2, dst, t);
561  for (unsigned int i2=0, c=0; i2<n; ++i2)
562  for (unsigned int i1=0; i1<n; ++i1)
563  for (unsigned int i0=0; i0<n; ++i0, ++c)
564  t[c] /= (eigenvalues[2][i2] + eigenvalues[1][i1] + eigenvalues[0][i0]);
565  eval.template apply<0, false, false> (S0, t, dst);
566  eval.template apply<1, false, false> (S1, dst, t);
567  eval.template apply<2, false, false> (S2, t, dst);
568  }
569 
570  else
571  Assert(false, ExcNotImplemented());
572 }
573 
574 
575 // ------------------------------ TensorProductMatrixSymmetricSum ------------------------------
576 
577 template <int dim, typename Number, int size>
578 inline
580 ::TensorProductMatrixSymmetricSum (const std::array<Table<2,Number>, dim> &mass_matrix,
581  const std::array<Table<2,Number>, dim> &derivative_matrix)
582 {
583  reinit (mass_matrix, derivative_matrix);
584 }
585 
586 
587 
588 template <int dim, typename Number, int size>
589 inline
591 ::TensorProductMatrixSymmetricSum(const std::array<FullMatrix<Number>, dim> &mass_matrix,
592  const std::array<FullMatrix<Number>, dim> &derivative_matrix)
593 {
594  reinit (mass_matrix, derivative_matrix);
595 }
596 
597 
598 
599 template <int dim, typename Number, int size>
600 inline
603  const Table<2,Number> &derivative_matrix)
604 {
605  reinit (mass_matrix, derivative_matrix);
606 }
607 
608 
609 
610 template <int dim, typename Number, int size>
611 template <typename MatrixArray>
612 inline
613 void
615 ::reinit_impl (MatrixArray &&mass_matrices_,
616  MatrixArray &&derivative_matrices_)
617 {
618  auto &&mass_matrices = std::forward<MatrixArray>(mass_matrices_);
619  auto &&derivative_matrices = std::forward<MatrixArray>(derivative_matrices_);
620  this->mass_matrix = mass_matrices;
621  this->derivative_matrix = derivative_matrices;
622 
623  for (int dir = 0; dir < dim; ++dir)
624  {
625  Assert (size == -1 || (size > 0 && static_cast<unsigned int>(size) == mass_matrices[dir].n_rows()),
626  ExcDimensionMismatch(size, mass_matrices[dir].n_rows()));
627  AssertDimension (mass_matrices[dir].n_rows(), mass_matrices[dir].n_cols());
628  AssertDimension (mass_matrices[dir].n_rows(), derivative_matrices[dir].n_rows());
629  AssertDimension (mass_matrices[dir].n_rows(), derivative_matrices[dir].n_cols());
630 
631  this->eigenvectors[dir].reinit (mass_matrices[dir].n_cols(), mass_matrices[dir].n_rows());
632  this->eigenvalues[dir].resize (mass_matrices[dir].n_cols());
633  internal::TensorProductMatrix
634  ::spectral_assembly<Number> (&(mass_matrices[dir](0,0)),
635  &(derivative_matrices[dir](0,0)),
636  mass_matrices[dir].n_rows(),
637  mass_matrices[dir].n_cols(),
638  this->eigenvalues[dir].begin(),
639  &(this->eigenvectors[dir](0,0)));
640  }
641 }
642 
643 
644 
645 template <int dim, typename Number, int size>
646 inline
647 void
649 ::reinit (const std::array<Table<2,Number>, dim> &mass_matrix,
650  const std::array<Table<2,Number>, dim> &derivative_matrix)
651 {
652  reinit_impl (mass_matrix, derivative_matrix);
653 }
654 
655 
656 
657 template <int dim, typename Number, int size>
658 inline
659 void
661 ::reinit (const std::array<FullMatrix<Number>, dim> &mass_matrix,
662  const std::array<FullMatrix<Number>, dim> &derivative_matrix)
663 {
664  std::array<Table<2,Number>,dim> mass_copy;
665  std::array<Table<2,Number>,dim> deriv_copy;
666 
667  std::transform (mass_matrix.cbegin(), mass_matrix.cend(), mass_copy.begin(),
668  [] (const FullMatrix<Number> &m) ->Table<2,Number> {return m;});
669  std::transform (derivative_matrix.cbegin(), derivative_matrix.cend(), deriv_copy.begin(),
670  [] (const FullMatrix<Number> &m) ->Table<2,Number> {return m;});
671 
672  reinit_impl (std::move(mass_copy), std::move(deriv_copy));
673 }
674 
675 
676 
677 template <int dim, typename Number, int size>
678 inline
679 void
681 ::reinit (const Table<2,Number> &mass_matrix,
682  const Table<2,Number> &derivative_matrix)
683 {
684  std::array<Table<2,Number>,dim> mass_matrices;
685  std::array<Table<2,Number>,dim> derivative_matrices;
686 
687  std::fill (mass_matrices.begin(), mass_matrices.end(), mass_matrix);
688  std::fill (derivative_matrices.begin(), derivative_matrices.end(), derivative_matrix);
689 
690  reinit_impl (std::move(mass_matrices), std::move(derivative_matrices));
691 }
692 
693 
694 
695 // ------------------------------ vectorized spec.: TensorProductMatrixSymmetricSum ------------------------------
696 
697 template <int dim, typename Number, int size>
698 inline
700 ::TensorProductMatrixSymmetricSum (const std::array<Table<2,VectorizedArray<Number> >,dim> &mass_matrix,
701  const std::array<Table<2,VectorizedArray<Number> >,dim> &derivative_matrix)
702 {
703  reinit (mass_matrix, derivative_matrix);
704 }
705 
706 
707 
708 template <int dim, typename Number, int size>
709 inline
712  const Table<2,VectorizedArray<Number> > &derivative_matrix)
713 {
714  reinit (mass_matrix, derivative_matrix);
715 }
716 
717 
718 
719 template <int dim, typename Number, int size>
720 template <typename MatrixArray>
721 inline
722 void
724 ::reinit_impl (MatrixArray &&mass_matrices_,
725  MatrixArray &&derivative_matrices_)
726 {
727  auto &&mass_matrix = std::forward<MatrixArray>(mass_matrices_);
728  auto &&derivative_matrix = std::forward<MatrixArray>(derivative_matrices_);
729  this->mass_matrix = mass_matrix;
730  this->derivative_matrix = derivative_matrix;
731 
732  constexpr unsigned int macro_size = VectorizedArray<Number>::n_array_elements;
733  std::size_t n_rows_max = (size > 0) ? size : 0 ;
734  if (size == -1)
735  for (unsigned int d = 0; d < dim; ++d)
736  n_rows_max = std::max(n_rows_max, mass_matrix[d].n_rows());
737  const std::size_t nm_flat_size_max = n_rows_max * n_rows_max * macro_size;
738  const std::size_t n_flat_size_max = n_rows_max * macro_size;
739 
740  std::vector<Number> mass_matrix_flat;
741  std::vector<Number> deriv_matrix_flat;
742  std::vector<Number> eigenvalues_flat;
743  std::vector<Number> eigenvectors_flat;
744  mass_matrix_flat.resize (nm_flat_size_max);
745  deriv_matrix_flat.resize (nm_flat_size_max);
746  eigenvalues_flat.resize (n_flat_size_max);
747  eigenvectors_flat.resize (nm_flat_size_max);
748  std::array<unsigned int,macro_size> offsets_nm;
749  std::array<unsigned int,macro_size> offsets_n;
750  for (int dir = 0; dir < dim; ++dir)
751  {
752  Assert (size == -1 ||
753  (size > 0 && static_cast<unsigned int>(size) == mass_matrix[dir].n_rows()),
754  ExcDimensionMismatch(size, mass_matrix[dir].n_rows()));
755  AssertDimension (mass_matrix[dir].n_rows(), mass_matrix[dir].n_cols());
756  AssertDimension (mass_matrix[dir].n_rows(), derivative_matrix[dir].n_rows());
757  AssertDimension (mass_matrix[dir].n_rows(), derivative_matrix[dir].n_cols());
758 
759  const unsigned int n_rows = mass_matrix[dir].n_rows();
760  const unsigned int n_cols = mass_matrix[dir].n_cols();
761  const unsigned int nm = n_rows * n_cols;
762  for (unsigned int vv=0; vv<macro_size; ++vv)
763  offsets_nm[vv] = nm * vv;
764 
765  vectorized_transpose_and_store (false, nm, &(mass_matrix[dir](0,0)),
766  offsets_nm.cbegin(), mass_matrix_flat.data());
767  vectorized_transpose_and_store (false, nm, &(derivative_matrix[dir](0,0)),
768  offsets_nm.cbegin(), deriv_matrix_flat.data());
769 
770  const Number *mass_cbegin = mass_matrix_flat.data();
771  const Number *deriv_cbegin = deriv_matrix_flat.data();
772  Number *eigenvec_begin = eigenvectors_flat.data();
773  Number *eigenval_begin = eigenvalues_flat.data();
774  for (unsigned int lane = 0; lane < macro_size; ++lane)
775  internal::TensorProductMatrix
776  ::spectral_assembly<Number> (mass_cbegin+nm*lane, deriv_cbegin+nm*lane, n_rows, n_cols,
777  eigenval_begin+n_rows*lane, eigenvec_begin+nm*lane);
778 
779  this->eigenvalues[dir].resize (n_rows);
780  this->eigenvectors[dir].reinit (n_rows, n_cols);
781  for (unsigned int vv=0; vv<macro_size; ++vv)
782  offsets_n[vv] = n_rows * vv;
783  vectorized_load_and_transpose (n_rows, eigenvalues_flat.data(),
784  offsets_n.cbegin(), this->eigenvalues[dir].begin());
785  vectorized_load_and_transpose (nm, eigenvectors_flat.data(),
786  offsets_nm.cbegin(), &(this->eigenvectors[dir](0,0)));
787  }
788 }
789 
790 
791 
792 template <int dim, typename Number, int size>
793 inline
794 void
796 ::reinit (const std::array<Table<2,VectorizedArray<Number> >,dim> &mass_matrix,
797  const std::array<Table<2,VectorizedArray<Number> >,dim> &derivative_matrix)
798 {
799  reinit_impl (mass_matrix, derivative_matrix);
800 }
801 
802 
803 
804 template <int dim, typename Number, int size>
805 inline
806 void
808 ::reinit (const Table<2,VectorizedArray<Number> > &mass_matrix,
809  const Table<2,VectorizedArray<Number> > &derivative_matrix)
810 {
811  std::array<Table<2,VectorizedArray<Number> >,dim> mass_matrices;
812  std::array<Table<2,VectorizedArray<Number> >,dim> derivative_matrices;
813 
814  std::fill (mass_matrices.begin(), mass_matrices.end(), mass_matrix);
815  std::fill (derivative_matrices.begin(), derivative_matrices.end(), derivative_matrix);
816 
817  reinit_impl (std::move(mass_matrices), std::move(derivative_matrices));
818 }
819 
820 
821 
822 #endif
823 
824 DEAL_II_NAMESPACE_CLOSE
825 
826 #endif
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1248
iterator begin() const
Definition: array_view.h:378
std::array< std::pair< Number, Tensor< 1, dim, Number > >, std::integral_constant< int, dim >::value > eigenvectors(const SymmetricTensor< 2, dim, Number > &T, const SymmetricTensorEigenvectorMethod method=SymmetricTensorEigenvectorMethod::ql_implicit_shifts)
void reinit(const std::array< Table< 2, Number >, dim > &mass_matrix, const std::array< Table< 2, Number >, dim > &derivative_matrix)
std::array< Number, 1 > eigenvalues(const SymmetricTensor< 2, 1, Number > &T)
std::array< std::pair< Number, Tensor< 1, dim, Number > >, std::integral_constant< int, dim >::value > eigenvectors(const SymmetricTensor< 2, dim, Number > &T, const SymmetricTensorEigenvectorMethod method=SymmetricTensorEigenvectorMethod::ql_implicit_shifts)
std::array< Table< 2, Number >, dim > derivative_matrix
#define AssertThrow(cond, exc)
Definition: exceptions.h:1221
std::array< Table< 2, Number >, dim > mass_matrix
void reinit_impl(MatrixArray &&mass_matrix, MatrixArray &&derivative_matrix)
void vectorized_transpose_and_store(const bool add_into, const unsigned int n_entries, const VectorizedArray< Number > *in, const unsigned int *offsets, Number *out)
void mass_matrix(FullMatrix< double > &M, const FEValuesBase< dim > &fe, const double factor=1.)
Definition: l2.h:53
#define Assert(cond, exc)
Definition: exceptions.h:1142
std::array< Table< 2, Number >, dim > eigenvectors
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
std::size_t size() const
Definition: array_view.h:370
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
void vectorized_load_and_transpose(const unsigned int n_entries, const Number *in, const unsigned int *offsets, VectorizedArray< Number > *out)
std::array< AlignedVector< Number >, dim > eigenvalues
value_type * data() const noexcept
Definition: array_view.h:346
void vmult(const ArrayView< Number > &dst, const ArrayView< const Number > &src) const
static ::ExceptionBase & ExcNotImplemented()
std::array< Number, 1 > eigenvalues(const SymmetricTensor< 2, 1, Number > &T)
void apply_inverse(const ArrayView< Number > &dst, const ArrayView< const Number > &src) const