Bembel
BlockClusterTree.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_BLOCKCLUSTERTREE_HPP_
12 #define BEMBEL_SRC_H2MATRIX_BLOCKCLUSTERTREE_HPP_
13 
14 namespace Bembel {
15 
16 template <typename Scalar>
17 class BlockClusterTree;
18 
20  enum { Refine = 0, LowRank = 1, Dense = 2 };
21 };
22 
23 template <typename Scalar>
26  : eta_(-1), min_cluster_level_(-1), max_level_(-1) {}
28  Eigen::Matrix<double, 12, Eigen::Dynamic> ffield_qnodes_;
29  double eta_; // eta from admissibility condition
30  int ffield_deg_; // todo @Michael comment this
31  int min_cluster_level_; // a tree leaf has 4^min_cluster_level_ elements
32  int max_level_; // depth of block cluster tree
33  int polynomial_degree_; // todo @Michael comment this
34  int polynomial_degree_plus_one_squared_; // todo @Michael comment this
35  const ElementTreeNode *et_root_;
36 };
37 
38 template <typename Scalar>
40  public:
45  : parameters_(nullptr),
47  leaf_(nullptr),
48  leaf_pointers_(nullptr),
49  cluster1_(nullptr),
50  cluster2_(nullptr),
51  rows_(0),
52  cols_(0),
53  cc_(-1) {}
54 
55  BlockClusterTree(BlockClusterTree &&other) noexcept {
56  parameters_ = other.parameters_;
57  sons_ = std::move(other.sons_);
58  leaf_ = other.leaf_;
59  leaf_pointers_ = other.leaf_pointers_;
60  cluster1_ = other.cluster1_;
61  cluster2_ = other.cluster2_;
62  rows_ = other.rows_;
63  cols_ = other.cols_;
64  cc_ = other.cc_;
65  updateLeafPointers();
66  }
67 
68  BlockClusterTree(const BlockClusterTree &other) noexcept {
69  parameters_ = other.parameters_;
70  sons_ = other.sons_;
71  // tree leaf is deep copied for const copy constructor! This has to be
72  // taken care of in some sense when going for Hmatrix arithmetics...
73  if (other.leaf_) {
74  leaf_ = std::make_shared<
75  TreeLeaf<Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>>>();
76  *leaf_ = static_cast<const TreeLeaf<
77  Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>> &>(
78  *(other.leaf_));
79  }
80  leaf_pointers_ = std::make_shared<std::vector<BlockClusterTree *>>();
81  cluster1_ = other.cluster1_;
82  cluster2_ = other.cluster2_;
83  rows_ = other.rows_;
84  cols_ = other.cols_;
85  cc_ = other.cc_;
86  updateLeafPointers();
87  }
88 
89  template <typename LinOp, typename AnsatzSpace>
90  BlockClusterTree(const LinOp &linear_operator,
91  const AnsatzSpace &ansatz_space) {
92  init_BlockClusterTree(linear_operator, ansatz_space);
93  }
98  std::swap(parameters_, other.parameters_);
99  std::swap(sons_, other.sons_);
100  std::swap(leaf_, other.leaf_);
101  std::swap(leaf_pointers_, other.leaf_pointers_);
102  std::swap(cluster1_, other.cluster1_);
103  std::swap(cluster2_, other.cluster2_);
104  std::swap(rows_, other.rows_);
105  std::swap(cols_, other.cols_);
106  std::swap(cc_, other.cc_);
107  updateLeafPointers();
108  return *this;
109  }
113  void set_parameters(double eta = 1.6, int min_cluster_level = 1) {
114  parameters_ = std::make_shared<BlockClusterTreeParameters<Scalar>>();
115  parameters_->eta_ = eta;
116  parameters_->min_cluster_level_ = min_cluster_level;
117  return;
118  }
119 
120  template <typename LinOp, typename AnsatzSpace>
121  void init_BlockClusterTree(const LinOp &linOp,
122  const AnsatzSpace &ansatz_space) {
123  if (parameters_ == nullptr) set_parameters();
124  // get element tree from ansatz space
125  const ElementTree &element_tree =
126  ansatz_space.get_superspace().get_mesh().get_element_tree();
127  parameters_->et_root_ = std::addressof(element_tree.root());
128  cluster1_ = std::addressof(element_tree.root());
129  cluster2_ = std::addressof(element_tree.root());
130  // set parameters for matrix assembly
131  parameters_->max_level_ = element_tree.get_max_level();
132  parameters_->polynomial_degree_ =
133  ansatz_space.get_superspace().get_polynomial_degree();
134  parameters_->polynomial_degree_plus_one_squared_ =
135  (parameters_->polynomial_degree_ + 1) *
136  (parameters_->polynomial_degree_ + 1);
137  parameters_->ffield_deg_ =
138  linOp.get_FarfieldQuadratureDegree(parameters_->polynomial_degree_);
139  // set up leaf_pointers
140  leaf_pointers_ = std::make_shared<std::vector<BlockClusterTree *>>();
141  leaf_pointers_->clear();
142  // block cluster tree assembly
143  rows_ = element_tree.get_number_of_elements();
144  cols_ = element_tree.get_number_of_elements();
145  // we let appendSubtree handle everything, since the root always
146  // returns 0 in compare cluster
147  appendSubtree(linOp, ansatz_space, cluster1_, cluster2_);
148  updateLeafPointers();
149  return;
150  }
154  template <typename LinOp, typename AnsatzSpace>
155  void appendSubtree(const LinOp &linear_operator,
156  const AnsatzSpace &ansatz_space,
157  const ElementTreeNode *cluster1,
158  const ElementTreeNode *cluster2) {
159  cc_ = compareCluster(*cluster1, *cluster2);
160  // there are children to handle
161  if (cc_ == BlockClusterAdmissibility::Refine) {
162  // reserve memory for sons_
163  sons_.resize(cluster1->sons_.size(), cluster2->sons_.size());
164  for (auto j = 0; j < sons_.cols(); ++j)
165  for (auto i = 0; i < sons_.rows(); ++i) {
166  const ElementTreeNode &son1 = cluster1->sons_[i];
167  const ElementTreeNode &son2 = cluster2->sons_[j];
168  sons_(i, j).parameters_ = parameters_;
169  sons_(i, j).cluster1_ = std::addressof(son1);
170  sons_(i, j).cluster2_ = std::addressof(son2);
171  sons_(i, j).rows_ = std::distance(son1.begin(), son1.end());
172  sons_(i, j).cols_ = std::distance(son2.begin(), son2.end());
173  // let recursion handle the rest
174  sons_(i, j).appendSubtree(linear_operator, ansatz_space,
175  std::addressof(son1), std::addressof(son2));
176  }
177  } else {
178  leaf_ = std::make_shared<
180  }
181  return;
182  }
183 
184  void printNode() const {
185  std::cout << "{" << std::endl;
186  std::cout << "cluster: " << cluster1_ << " & " << cluster2_ << std::endl;
187  std::cout << "rows: " << rows_ << " cols: " << cols_ << std::endl;
188  std::cout << "format: " << cc_ << std::endl;
189  std::cout << "children: " << sons_.rows() << " x " << sons_.cols()
190  << std::endl;
191  std::cout << "leaf: " << leaf_ << std::endl;
192  std::cout << "parameters: " << parameters_ << std::endl;
193 
194  std::cout << "}" << std::endl;
195  return;
196  }
200  int get_cc() const { return cc_; }
201  int rows() const { return rows_; }
202  int cols() const { return cols_; }
203  const ElementTreeNode *get_cluster1() const { return cluster1_; }
204  const ElementTreeNode *get_cluster2() const { return cluster2_; }
205  int get_level() const { return get_cluster1()->get_level(); }
206  typename std::vector<BlockClusterTree *>::iterator lbegin() {
207  return leaf_pointers_->begin();
208  }
209  typename std::vector<BlockClusterTree *>::iterator lend() {
210  return leaf_pointers_->end();
211  }
212  typename std::vector<BlockClusterTree *>::const_iterator clbegin() const {
213  return leaf_pointers_->begin();
214  }
215  typename std::vector<BlockClusterTree *>::const_iterator clend() const {
216  return leaf_pointers_->end();
217  }
218  int get_row_start_index() {
219  return get_parameters().polynomial_degree_plus_one_squared_ *
220  std::distance(get_parameters().et_root_->begin(),
221  cluster1_->begin());
222  }
223  int get_row_end_index() {
224  return get_parameters().polynomial_degree_plus_one_squared_ *
225  std::distance(get_parameters().et_root_->begin(), cluster1_->end());
226  }
227  int get_col_start_index() {
228  return get_parameters().polynomial_degree_plus_one_squared_ *
229  std::distance(get_parameters().et_root_->begin(),
230  cluster2_->begin());
231  }
232  int get_col_end_index() {
233  return get_parameters().polynomial_degree_plus_one_squared_ *
234  std::distance(get_parameters().et_root_->begin(), cluster2_->end());
235  }
236  const BlockClusterTreeParameters<Scalar> &get_parameters() const {
237  return *parameters_;
238  }
239  BlockClusterTreeParameters<Scalar> &get_parameters() { return *parameters_; }
240 
241  const TreeLeaf<Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>>
242  &get_leaf() const {
243  return *leaf_;
244  }
245  TreeLeaf<Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>> &get_leaf() {
246  return *leaf_;
247  }
251  private:
255  int compareCluster(const ElementTreeNode &cluster1,
256  const ElementTreeNode &cluster2) {
257  int r;
258  double dist = (cluster1.midpoint_ - cluster2.midpoint_).norm() -
259  cluster1.radius_ - cluster2.radius_;
260  dist = dist > 0 ? dist : 0;
261  double max_radius = cluster1.radius_ > cluster2.radius_ ? cluster1.radius_
262  : cluster2.radius_;
263 
267  if (dist < 0 || max_radius >= parameters_->eta_ * dist)
268  r = BlockClusterAdmissibility::Refine;
269  else
270  r = BlockClusterAdmissibility::LowRank;
271 
272  if (r == BlockClusterAdmissibility::Refine &&
273  parameters_->max_level_ - cluster1.level_ <=
274  parameters_->min_cluster_level_)
275  r = BlockClusterAdmissibility::Dense;
276 
277  return r;
278  }
279  void updateLeafPointers() {
280  // make sure we have the root of the block cluster tree calling this method
281  if (cluster1_->id_ != -1 || cluster1_ != cluster2_) {
282  return;
283  } else {
284  leaf_pointers_->clear();
285  updateLeafPointers_recursion(*this);
286  }
287  }
288  void updateLeafPointers_recursion(BlockClusterTree &child) {
289  if (child.cc_ == BlockClusterAdmissibility::Refine) {
290  for (auto j = 0; j < child.sons_.cols(); ++j)
291  for (auto i = 0; i < child.sons_.rows(); ++i)
292  updateLeafPointers_recursion(child.sons_(i, j));
293  } else {
294  leaf_pointers_->push_back(std::addressof(child));
295  }
296  return;
297  }
301  std::shared_ptr<BlockClusterTreeParameters<Scalar>> parameters_;
302  GenericMatrix<BlockClusterTree> sons_;
303  std::shared_ptr<
304  TreeLeaf<Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>>>
305  leaf_;
306  std::shared_ptr<std::vector<BlockClusterTree *>> leaf_pointers_;
307  const ElementTreeNode *cluster1_;
308  const ElementTreeNode *cluster2_;
309  int rows_;
310  int cols_;
311  int cc_;
312 };
313 
314 } // namespace Bembel
315 #endif // BEMBEL_SRC_H2MATRIX_BLOCKCLUSTERTREE_HPP_
The AnsatzSpace is the class that handles the assembly of the discrete basis.
Definition: AnsatzSpace.hpp:25
const SuperSpace< Derived > & get_superspace() const
Retrieves the reference to the SuperSpace associated with this AnsatzSpace.
BlockClusterTree & operator=(BlockClusterTree other) noexcept
assignment operator
void appendSubtree(const LinOp &linear_operator, const AnsatzSpace &ansatz_space, const ElementTreeNode *cluster1, const ElementTreeNode *cluster2)
methods
void set_parameters(double eta=1.6, int min_cluster_level=1)
init
This class organizes an element structure on a Geometry object and handles refinement.
Definition: ElementTree.hpp:32
int get_number_of_elements() const
Return number of elements in the ElementTree.
int get_max_level() const
Return maximum level of refinement.
ElementTreeNode & root()
Return reference to the root ElementTreeNode.
The ElementTreeNode corresponds to an element in the element tree.
int id_
radius of the element
const_iterator begin() const
Returns an iterator pointing to the element in the sequence before this ElementTreeNodes.
int get_level() const
Get the level of refinement of the element.
std::vector< ElementTreeNode > sons_
member variables
const_iterator end() const
Returns an iterator pointing to the element in the sequence after this ElementTreeNode.
This class is managing the leafs of the H2Matrix BlockClusterTree.
Definition: TreeLeaf.hpp:20
Routines for the evalutation of pointwise errors.
Definition: AnsatzSpace.hpp:14