Bembel
H2Matrix.hpp
1 // This file is part of Bembel, the higher order C++ boundary element library.
2 //
3 // Copyright (C) 2022 see <http://www.bembel.eu>
4 //
5 // It was written as part of a cooperation of J. Doelz, H. Harbrecht, S. Kurz,
6 // M. Multerer, S. Schoeps, and F. Wolf at Technische Universitaet Darmstadt,
7 // Universitaet Basel, and Universita della Svizzera italiana, Lugano. This
8 // source code is subject to the GNU General Public License version 3 and
9 // provided WITHOUT ANY WARRANTY, see <http://www.bembel.eu> for further
10 // information.
11 #ifndef BEMBEL_SRC_H2MATRIX_H2MATRIX_HPP_
12 #define BEMBEL_SRC_H2MATRIX_H2MATRIX_HPP_
13 
26 namespace Eigen {
28 template <typename ScalarT>
29 class H2Matrix;
31 namespace internal {
32 template <typename ScalarT>
33 struct traits<H2Matrix<ScalarT>> {
34  typedef ScalarT Scalar;
35  typedef int StorageIndex;
36  typedef H2 StorageKind;
37  typedef MatrixXpr XprKind;
38  enum {
39  RowsAtCompileTime = Dynamic,
40  ColsAtCompileTime = Dynamic,
41  MaxRowsAtCompileTime = Dynamic,
42  MaxColsAtCompileTime = Dynamic,
43  Flags = NestByRefBit
44  };
45 };
46 
47 // this struct is necessary for compatibility with iterative solvers
48 template <typename ScalarT>
49 struct is_ref_compatible<H2Matrix<ScalarT>> {
50  enum { value = false };
51 };
52 template <typename ScalarT>
53 struct is_ref_compatible<const H2Matrix<ScalarT>>
54  : is_ref_compatible<H2Matrix<ScalarT>> {};
55 
56 } // namespace internal
57 
58 // actual definition of the class
59 template <typename ScalarT>
60 class H2Matrix : public H2MatrixBase<H2Matrix<ScalarT>> {
61  public:
65  // Required typedefs, constants and so on.
66  typedef ScalarT Scalar;
67  typedef typename NumTraits<ScalarT>::Real RealScalar;
68  typedef Index StorageIndex;
69  enum {
70  ColsAtCompileTime = Dynamic,
71  MaxColsAtCompileTime = Dynamic,
72  IsRowMajor = false,
73  Flags = NestByRefBit
74  };
75  // Minimum specialisation of EigenBase methods
76  Index rows() const { return transformation_matrix_.cols(); }
77  Index cols() const { return transformation_matrix_.cols(); }
78  // Definition of the matrix multiplication
79  template <typename Rhs>
80  Product<H2Matrix, Rhs, AliasFreeProduct> operator*(
81  const MatrixBase<Rhs>& x) const {
82  return Product<H2Matrix, Rhs, AliasFreeProduct>(*this, x.derived());
83  }
87  H2Matrix() {}
93  template <typename Derived>
94  void init_H2Matrix(const Derived& linOp,
95  const Bembel::AnsatzSpace<Derived>& ansatz_space,
96  int number_of_points = 9) {
97  // get transformation matrix from ansatz space
98  transformation_matrix_ = ansatz_space.get_transformation_matrix();
104  // initialize block-cluster-trees and get parameters
105  const int vector_dimension = Bembel::getFunctionSpaceVectorDimension<
107  block_cluster_tree_.resize(vector_dimension, vector_dimension);
108  {
109  Bembel::BlockClusterTree<Scalar> bt(linOp, ansatz_space);
110  for (int i = 0; i < vector_dimension; ++i)
111  for (int j = 0; j < vector_dimension; ++j)
112  block_cluster_tree_(i, j) =
113  bt; // .init_BlockClusterTree(linOp, ansatz_space);
114  }
115  auto parameters = block_cluster_tree_(0, 0).get_parameters();
116  // compute transfer and moment matrices for fmm
117  int cluster_level = parameters.max_level_ - parameters.min_cluster_level_;
118  if (cluster_level < 0) cluster_level = 0;
119  int cluster_refinement = parameters.min_cluster_level_;
120  if (cluster_refinement > parameters.max_level_)
121  cluster_refinement = parameters.max_level_;
122  fmm_transfer_matrices_ = Bembel::H2Multipole::computeTransferMatrices<
123  Bembel::H2Multipole::ChebychevRoots>(number_of_points);
124  fmm_moment_matrix_ = Bembel::H2Multipole::
125  Moment2D<Bembel::H2Multipole::ChebychevRoots, Derived>::compute2DMoment(
126  ansatz_space.get_superspace(), cluster_level, cluster_refinement,
127  number_of_points);
128  // compute interpolation points
129  Eigen::VectorXd interpolation_points1D =
130  Bembel::H2Multipole::ChebychevRoots(number_of_points).points_;
131  Eigen::MatrixXd interpolation_points2D =
132  Bembel::H2Multipole::interpolationPoints2D(interpolation_points1D);
133  // compute content of tree leafs
134  int polynomial_degree = ansatz_space.get_polynomial_degree();
135  int polynomial_degree_plus_one_squared =
136  (polynomial_degree + 1) * (polynomial_degree + 1);
138  auto super_space = ansatz_space.get_superspace();
139  auto ffield_deg = linOp.get_FarfieldQuadratureDegree(polynomial_degree);
140  std::vector<ElementSurfacePoints> ffield_qnodes =
141  Bembel::DuffyTrick::computeFfieldQnodes(super_space, GS[ffield_deg]);
142  const int NumberOfFMMComponents =
144 #pragma omp parallel
145  {
146 #pragma omp single
147  {
148  // build vector of iterators
149  std::vector<
150  typename std::vector<Bembel::BlockClusterTree<Scalar>*>::iterator>
151  leafs;
152  leafs.resize(vector_dimension * vector_dimension);
153  for (int i = 0; i < vector_dimension; ++i)
154  for (int j = 0; j < vector_dimension; ++j)
155  leafs[i * vector_dimension + j] =
156  block_cluster_tree_(j, i).lbegin();
157  // iterate over leafs
158  for (; leafs[0] != block_cluster_tree_(0, 0).lend();) {
159 #pragma omp task firstprivate(leafs)
160  {
161  switch ((*(leafs[0]))->get_cc()) {
162  // assemble dense matrix blocks
163  case Bembel::BlockClusterAdmissibility::Dense: {
164  const Bembel::ElementTreeNode* cluster1 =
165  (*(leafs[0]))->get_cluster1();
166  const Bembel::ElementTreeNode* cluster2 =
167  (*(leafs[0]))->get_cluster2();
168  int block_size =
169  std::distance(cluster2->begin(), cluster2->end()) *
170  polynomial_degree_plus_one_squared;
171  std::vector<
172  Eigen::Matrix<ScalarT, Eigen::Dynamic, Eigen::Dynamic>>
173  F;
174  for (int i = 0; i < vector_dimension * vector_dimension; ++i)
175  F.push_back(
176  Eigen::Matrix<ScalarT, Eigen::Dynamic, Eigen::Dynamic>(
177  block_size, block_size));
178  // iterate over elements in dense matrix block
179  unsigned int cl1index = 0;
180  unsigned int cl2index = 0;
181  for (const auto& element1 : *cluster1) {
182  cl2index = 0;
183  for (const auto& element2 : *cluster2) {
184  Eigen::Matrix<ScalarT, Eigen::Dynamic, Eigen::Dynamic>
185  intval(vector_dimension *
186  polynomial_degree_plus_one_squared,
187  vector_dimension *
188  polynomial_degree_plus_one_squared);
189  // do integration
191  linOp, super_space, element1, element2, GS,
192  ffield_qnodes[element1.id_],
193  ffield_qnodes[element2.id_], &intval);
194  // insert into dense matrices of all block cluster trees
195  for (int i = 0; i < vector_dimension; ++i)
196  for (int j = 0; j < vector_dimension; ++j)
197  F[i * vector_dimension + j].block(
198  polynomial_degree_plus_one_squared * cl1index,
199  polynomial_degree_plus_one_squared * cl2index,
200  polynomial_degree_plus_one_squared,
201  polynomial_degree_plus_one_squared) =
202  intval.block(j * polynomial_degree_plus_one_squared,
203  i * polynomial_degree_plus_one_squared,
204  polynomial_degree_plus_one_squared,
205  polynomial_degree_plus_one_squared);
206  ++cl2index;
207  }
208  ++cl1index;
209  }
210  for (int i = 0; i < vector_dimension * vector_dimension; ++i)
211  (*(leafs[i]))->get_leaf().set_F(F[i]);
212  } break;
213  // interpolation for low-rank blocks
214  case Bembel::BlockClusterAdmissibility::LowRank: {
215  auto F = Bembel::H2Multipole::interpolateKernel<Derived>(
216  linOp, super_space, interpolation_points2D,
217  *((*(leafs[0]))->get_cluster1()),
218  *((*(leafs[0]))->get_cluster2()));
219  for (int i = 0; i < vector_dimension; ++i) {
220  for (int j = 0; j < vector_dimension; ++j) {
221  (*(leafs[i * vector_dimension + j]))
222  ->get_leaf()
223  .set_F(F.block(j * interpolation_points2D.rows() *
224  NumberOfFMMComponents,
225  i * interpolation_points2D.rows() *
226  NumberOfFMMComponents,
227  interpolation_points2D.rows() *
228  NumberOfFMMComponents,
229  interpolation_points2D.rows() *
230  NumberOfFMMComponents));
231  (*(leafs[i * vector_dimension + j]))
232  ->get_leaf()
233  .set_low_rank_flag(true);
234  }
235  }
236  } break;
237  // this leaf is not a low-rank block and not a dense block,
238  // thus it is not a leaf -> error
239  default:
240  assert(0 && "This should never happen");
241  break;
242  }
243  }
244  // increment leafs of all block-cluster trees
245  for (auto leafsit = leafs.begin(); leafsit != leafs.end(); ++leafsit)
246  ++(*leafsit);
247  }
248  }
249  }
250  }
254  Eigen::Matrix<ScalarT, Eigen::Dynamic, Eigen::Dynamic> get_dense() const {
255  Eigen::Matrix<ScalarT, Eigen::Dynamic, Eigen::Dynamic> dense(rows(),
256  cols());
257  for (int i = 0; i < cols(); ++i) {
258  Eigen::VectorXd unit(cols());
259  unit.setZero();
260  unit(i) = 1.;
261  dense.col(i) = (*this) * unit;
262  }
263  return dense;
264  }
268  const Eigen::SparseMatrix<double> get_transformation_matrix() const {
269  return transformation_matrix_;
270  }
271  const Eigen::MatrixXd get_fmm_transfer_matrices() const {
272  return fmm_transfer_matrices_;
273  }
274  const std::vector<Eigen::MatrixXd> get_fmm_moment_matrix() const {
275  return fmm_moment_matrix_;
276  }
278  get_block_cluster_tree() const {
279  return block_cluster_tree_;
280  }
284  private:
285  // we declare functionality which has not been implemented (yet)
286  // to be private
287  H2Matrix(const H2Matrix<ScalarT>& H);
289  H2Matrix& operator=(const H2Matrix<ScalarT>& H);
290  H2Matrix& operator=(H2Matrix<ScalarT>&& H);
291 
292  Eigen::SparseMatrix<double> transformation_matrix_;
294  Eigen::MatrixXd fmm_transfer_matrices_;
295  std::vector<Eigen::MatrixXd> fmm_moment_matrix_;
296 };
297 
298 namespace internal {
299 
300 // adaption from SparseMatrix from Eigen
301 template <typename Scalar>
302 struct evaluator<H2Matrix<Scalar>> : evaluator<H2MatrixBase<H2Matrix<Scalar>>> {
303  typedef evaluator<H2MatrixBase<H2Matrix<Scalar>>> Base;
305  evaluator() : Base() {}
306  explicit evaluator(const H2MatrixType& mat) : Base(mat) {}
307 };
308 
309 } // namespace internal
310 } // namespace Eigen
311 
312 #endif // BEMBEL_SRC_H2MATRIX_H2MATRIX_HPP_
The AnsatzSpace is the class that handles the assembly of the discrete basis.
Definition: AnsatzSpace.hpp:25
int get_polynomial_degree() const
Retrieves the polynomial degree of this AnsatzSpace.
const Eigen::SparseMatrix< double > & get_transformation_matrix() const
Retrieves the transformation matrix associated with this AnsatzSpace.
const SuperSpace< Derived > & get_superspace() const
Retrieves the reference to the SuperSpace associated with this AnsatzSpace.
The ElementTreeNode corresponds to an element in the element tree.
const_iterator begin() const
Returns an iterator pointing to the element in the sequence before this ElementTreeNodes.
const_iterator end() const
Returns an iterator pointing to the element in the sequence after this ElementTreeNode.
forward definition of the H2Matrix Class in order to define traits
Definition: H2Matrix.hpp:60
Eigen::Matrix< ScalarT, Eigen::Dynamic, Eigen::Dynamic > get_dense() const
methods
Definition: H2Matrix.hpp:254
H2Matrix()
constructors
Definition: H2Matrix.hpp:87
ScalarT Scalar
Eigen related things.
Definition: H2Matrix.hpp:66
const Eigen::SparseMatrix< double > get_transformation_matrix() const
getter
Definition: H2Matrix.hpp:268
void init_H2Matrix(const Derived &linOp, const Bembel::AnsatzSpace< Derived > &ansatz_space, int number_of_points=9)
Assemble H2-Matrix for linear operator linOp and AnsatzSpace ansatz_space with number_of_points inter...
Definition: H2Matrix.hpp:94
Hierarchical Matrix class, which extends the EigenBase class.
void evaluateBilinearForm(const LinearOperatorBase< Derived > &linOp, const T &super_space, const ElementTreeNode &e1, const ElementTreeNode &e2, const CubatureVector &GS, const ElementSurfacePoints &ffield_qnodes1, const ElementSurfacePoints &ffield_qnodes2, Eigen::Matrix< typename LinearOperatorTraits< Derived >::Scalar, Eigen::Dynamic, Eigen::Dynamic > *intval)
This function wraps the quadrature routines for the DuffyTrick and returns all integrals for the give...
std::vector< ElementSurfacePoints > computeFfieldQnodes(const T &super_space, const Cubature &Q)
evaluates a given quadrature on all surface panels storage format is qNodes.col(k) = [xi,...
Eigen::MatrixXd interpolationPoints2D(const Eigen::VectorXd &x)
Compute tensor interpolation points on unit square from 1D interpolation points.
Eigen::MatrixXd computeTransferMatrices(int number_of_points)
Computes transfer matrices in required order to apply them all-at-once in a matrix-vector-product,...
Definition: H2Multipole.hpp:77
constexpr int getFunctionSpaceVectorDimension()
Computes the number_of_points Chebychev points.
Definition: H2Multipole.hpp:20
struct containing specifications on the linear operator has to be specialized or derived for any part...