GCC Code Coverage Report


Directory: Bembel/src/
File: Bembel/src/H2Matrix/BlockClusterTree.hpp
Date: 2024-09-30 07:01:38
Exec Total Coverage
Lines: 140 152 92.1%
Functions: 56 58 96.6%
Branches: 37 44 84.1%

Line Branch Exec Source
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
19 struct BlockClusterAdmissibility {
20 enum { Refine = 0, LowRank = 1, Dense = 2 };
21 };
22
23 template <typename Scalar>
24 struct BlockClusterTreeParameters {
25 5 BlockClusterTreeParameters()
26
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 : eta_(-1), min_cluster_level_(-1), max_level_(-1) {}
27 GaussSquare<Constants::maximum_quadrature_degree> GS_;
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>
39 class BlockClusterTree {
40 public:
41 //////////////////////////////////////////////////////////////////////////////
42 /// constructors
43 //////////////////////////////////////////////////////////////////////////////
44 3068 BlockClusterTree()
45 3068 : parameters_(nullptr),
46 3068 sons_(GenericMatrix<BlockClusterTree>()),
47 3068 leaf_(nullptr),
48 3068 leaf_pointers_(nullptr),
49 3068 cluster1_(nullptr),
50 3068 cluster2_(nullptr),
51 3068 rows_(0),
52 3068 cols_(0),
53 3068 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 4904 BlockClusterTree(const BlockClusterTree &other) noexcept {
69 4904 parameters_ = other.parameters_;
70 4904 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
2/2
✓ Branch 1 taken 4608 times.
✓ Branch 2 taken 296 times.
4904 if (other.leaf_) {
74 4608 leaf_ = std::make_shared<
75 TreeLeaf<Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>>>();
76 4608 *leaf_ = static_cast<const TreeLeaf<
77 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>> &>(
78 4608 *(other.leaf_));
79 }
80 4904 leaf_pointers_ = std::make_shared<std::vector<BlockClusterTree *>>();
81 4904 cluster1_ = other.cluster1_;
82 4904 cluster2_ = other.cluster2_;
83 4904 rows_ = other.rows_;
84 4904 cols_ = other.cols_;
85 4904 cc_ = other.cc_;
86 4904 updateLeafPointers();
87 4904 }
88
89 template <typename LinOp, typename AnsatzSpace>
90 5 BlockClusterTree(const LinOp &linear_operator,
91 5 const AnsatzSpace &ansatz_space) {
92
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 init_BlockClusterTree(linear_operator, ansatz_space);
93 5 }
94 //////////////////////////////////////////////////////////////////////////////
95 /// assignment operator
96 //////////////////////////////////////////////////////////////////////////////
97 8 BlockClusterTree &operator=(BlockClusterTree other) noexcept {
98 8 std::swap(parameters_, other.parameters_);
99 8 std::swap(sons_, other.sons_);
100 8 std::swap(leaf_, other.leaf_);
101 8 std::swap(leaf_pointers_, other.leaf_pointers_);
102 8 std::swap(cluster1_, other.cluster1_);
103 8 std::swap(cluster2_, other.cluster2_);
104 8 std::swap(rows_, other.rows_);
105 8 std::swap(cols_, other.cols_);
106 8 std::swap(cc_, other.cc_);
107 8 updateLeafPointers();
108 8 return *this;
109 }
110 //////////////////////////////////////////////////////////////////////////////
111 /// init
112 //////////////////////////////////////////////////////////////////////////////
113 5 void set_parameters(double eta = 1.6, int min_cluster_level = 1) {
114 5 parameters_ = std::make_shared<BlockClusterTreeParameters<Scalar>>();
115 5 parameters_->eta_ = eta;
116 5 parameters_->min_cluster_level_ = min_cluster_level;
117 5 return;
118 }
119
120 template <typename LinOp, typename AnsatzSpace>
121 5 void init_BlockClusterTree(const LinOp &linOp,
122 const AnsatzSpace &ansatz_space) {
123
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 if (parameters_ == nullptr) set_parameters();
124 // get element tree from ansatz space
125 const ElementTree &element_tree =
126 5 ansatz_space.get_superspace().get_mesh().get_element_tree();
127 5 parameters_->et_root_ = std::addressof(element_tree.root());
128 5 cluster1_ = std::addressof(element_tree.root());
129 5 cluster2_ = std::addressof(element_tree.root());
130 // set parameters for matrix assembly
131 5 parameters_->max_level_ = element_tree.get_max_level();
132 5 parameters_->polynomial_degree_ =
133 10 ansatz_space.get_superspace().get_polynomial_degree();
134 10 parameters_->polynomial_degree_plus_one_squared_ =
135 5 (parameters_->polynomial_degree_ + 1) *
136 5 (parameters_->polynomial_degree_ + 1);
137 10 parameters_->ffield_deg_ =
138 5 linOp.get_FarfieldQuadratureDegree(parameters_->polynomial_degree_);
139 // set up leaf_pointers
140 5 leaf_pointers_ = std::make_shared<std::vector<BlockClusterTree *>>();
141 5 leaf_pointers_->clear();
142 // block cluster tree assembly
143 5 rows_ = element_tree.get_number_of_elements();
144 5 cols_ = element_tree.get_number_of_elements();
145 // we let appendSubtree handle everything, since the root always
146 // returns 0 in compare cluster
147 5 appendSubtree(linOp, ansatz_space, cluster1_, cluster2_);
148 5 updateLeafPointers();
149 5 return;
150 }
151 //////////////////////////////////////////////////////////////////////////////
152 /// methods
153 //////////////////////////////////////////////////////////////////////////////
154 template <typename LinOp, typename AnsatzSpace>
155 3065 void appendSubtree(const LinOp &linear_operator,
156 const AnsatzSpace &ansatz_space,
157 const ElementTreeNode *cluster1,
158 const ElementTreeNode *cluster2) {
159 3065 cc_ = compareCluster(*cluster1, *cluster2);
160 // there are children to handle
161
2/2
✓ Branch 0 taken 185 times.
✓ Branch 1 taken 2880 times.
3065 if (cc_ == BlockClusterAdmissibility::Refine) {
162 // reserve memory for sons_
163 185 sons_.resize(cluster1->sons_.size(), cluster2->sons_.size());
164
2/2
✓ Branch 1 taken 750 times.
✓ Branch 2 taken 185 times.
935 for (auto j = 0; j < sons_.cols(); ++j)
165
2/2
✓ Branch 1 taken 3060 times.
✓ Branch 2 taken 750 times.
3810 for (auto i = 0; i < sons_.rows(); ++i) {
166 3060 const ElementTreeNode &son1 = cluster1->sons_[i];
167 3060 const ElementTreeNode &son2 = cluster2->sons_[j];
168 3060 sons_(i, j).parameters_ = parameters_;
169 3060 sons_(i, j).cluster1_ = std::addressof(son1);
170 3060 sons_(i, j).cluster2_ = std::addressof(son2);
171 3060 sons_(i, j).rows_ = std::distance(son1.begin(), son1.end());
172 3060 sons_(i, j).cols_ = std::distance(son2.begin(), son2.end());
173 // let recursion handle the rest
174 3060 sons_(i, j).appendSubtree(linear_operator, ansatz_space,
175 std::addressof(son1), std::addressof(son2));
176 }
177 } else {
178 2880 leaf_ = std::make_shared<
179 TreeLeaf<Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>>>();
180 }
181 3065 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 }
197 //////////////////////////////////////////////////////////////////////////////
198 /// getter
199 //////////////////////////////////////////////////////////////////////////////
200 448704 int get_cc() const { return cc_; }
201 int rows() const { return rows_; }
202 int cols() const { return cols_; }
203 302976 const ElementTreeNode *get_cluster1() const { return cluster1_; }
204 152928 const ElementTreeNode *get_cluster2() const { return cluster2_; }
205 int get_level() const { return get_cluster1()->get_level(); }
206 8 typename std::vector<BlockClusterTree *>::iterator lbegin() {
207 8 return leaf_pointers_->begin();
208 }
209 2885 typename std::vector<BlockClusterTree *>::iterator lend() {
210 2885 return leaf_pointers_->end();
211 }
212 774 typename std::vector<BlockClusterTree *>::const_iterator clbegin() const {
213 774 return leaf_pointers_->begin();
214 }
215 446598 typename std::vector<BlockClusterTree *>::const_iterator clend() const {
216 446598 return leaf_pointers_->end();
217 }
218 591552 int get_row_start_index() {
219 591552 return get_parameters().polynomial_degree_plus_one_squared_ *
220 591552 std::distance(get_parameters().et_root_->begin(),
221 1183104 cluster1_->begin());
222 }
223 295776 int get_row_end_index() {
224 295776 return get_parameters().polynomial_degree_plus_one_squared_ *
225 295776 std::distance(get_parameters().et_root_->begin(), cluster1_->end());
226 }
227 591552 int get_col_start_index() {
228 591552 return get_parameters().polynomial_degree_plus_one_squared_ *
229 591552 std::distance(get_parameters().et_root_->begin(),
230 1183104 cluster2_->begin());
231 }
232 295776 int get_col_end_index() {
233 295776 return get_parameters().polynomial_degree_plus_one_squared_ *
234 295776 std::distance(get_parameters().et_root_->begin(), cluster2_->end());
235 }
236 300702 const BlockClusterTreeParameters<Scalar> &get_parameters() const {
237 300702 return *parameters_;
238 }
239 3549317 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 452064 TreeLeaf<Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>> &get_leaf() {
246 452064 return *leaf_;
247 }
248 //////////////////////////////////////////////////////////////////////////////
249 /// private members
250 //////////////////////////////////////////////////////////////////////////////
251 private:
252 /**
253 * \brief determines admissible clusters
254 **/
255 3065 int compareCluster(const ElementTreeNode &cluster1,
256 const ElementTreeNode &cluster2) {
257 int r;
258
1/2
✓ Branch 2 taken 3065 times.
✗ Branch 3 not taken.
3065 double dist = (cluster1.midpoint_ - cluster2.midpoint_).norm() -
259 3065 cluster1.radius_ - cluster2.radius_;
260
2/2
✓ Branch 0 taken 1920 times.
✓ Branch 1 taken 1145 times.
3065 dist = dist > 0 ? dist : 0;
261
2/2
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 2889 times.
3065 double max_radius = cluster1.radius_ > cluster2.radius_ ? cluster1.radius_
262 : cluster2.radius_;
263
264 /**
265 * \todo replace by 2*max_radius
266 */
267
5/6
✓ Branch 0 taken 3065 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 2009 times.
✓ Branch 4 taken 1056 times.
✓ Branch 5 taken 2009 times.
✓ Branch 6 taken 1056 times.
3065 if (dist < 0 || max_radius >= parameters_->eta_ * dist)
268 2009 r = BlockClusterAdmissibility::Refine;
269 else
270 1056 r = BlockClusterAdmissibility::LowRank;
271
272
4/4
✓ Branch 0 taken 2009 times.
✓ Branch 1 taken 1056 times.
✓ Branch 2 taken 1824 times.
✓ Branch 3 taken 1241 times.
5074 if (r == BlockClusterAdmissibility::Refine &&
273 2009 parameters_->max_level_ - cluster1.level_ <=
274
2/2
✓ Branch 1 taken 1824 times.
✓ Branch 2 taken 185 times.
2009 parameters_->min_cluster_level_)
275 1824 r = BlockClusterAdmissibility::Dense;
276
277 3065 return r;
278 }
279 4917 void updateLeafPointers() {
280 // make sure we have the root of the block cluster tree calling this method
281
3/4
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 4896 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 21 times.
4917 if (cluster1_->id_ != -1 || cluster1_ != cluster2_) {
282 4896 return;
283 } else {
284 21 leaf_pointers_->clear();
285 21 updateLeafPointers_recursion(*this);
286 }
287 }
288 12873 void updateLeafPointers_recursion(BlockClusterTree &child) {
289
2/2
✓ Branch 0 taken 777 times.
✓ Branch 1 taken 12096 times.
12873 if (child.cc_ == BlockClusterAdmissibility::Refine) {
290
2/2
✓ Branch 1 taken 3150 times.
✓ Branch 2 taken 777 times.
3927 for (auto j = 0; j < child.sons_.cols(); ++j)
291
2/2
✓ Branch 1 taken 12852 times.
✓ Branch 2 taken 3150 times.
16002 for (auto i = 0; i < child.sons_.rows(); ++i)
292 12852 updateLeafPointers_recursion(child.sons_(i, j));
293 } else {
294
1/2
✓ Branch 3 taken 12096 times.
✗ Branch 4 not taken.
12096 leaf_pointers_->push_back(std::addressof(child));
295 }
296 12873 return;
297 }
298 //////////////////////////////////////////////////////////////////////////////
299 /// member variables
300 //////////////////////////////////////////////////////////////////////////////
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_
316