Flow123d
bih_tree.cc
Go to the documentation of this file.
1 /**!
2  *
3  * Copyright (C) 2007 Technical University of Liberec. All rights reserved.
4  *
5  * Please make a following refer to Flow123d on your project site if you use the program for any purpose,
6  * especially for academic research:
7  * Flow123d, Research Centre: Advanced Remedial Technologies, Technical University of Liberec, Czech Republic
8  *
9  * This program is free software; you can redistribute it and/or modify it under the terms
10  * of the GNU General Public License version 3 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along with this program; if not,
17  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 021110-1307, USA.
18  *
19  *
20  * $Id: bih_tree.cc 1567 2012-02-28 13:24:58Z jan.brezina $
21  * $Revision: 1567 $
22  * $LastChangedBy: jan.brezina $
23  * $LastChangedDate: 2012-02-28 14:24:58 +0100 (Tue, 28 Feb 2012) $
24  *
25  *
26  */
27 
28 #include "mesh/bih_tree.hh"
29 #include "mesh/bih_node.hh"
30 #include "system/global_defs.h"
31 #include <ctime>
32 #include <stack>
33 
34 /**
35  * Minimum reduction of box size to allow
36  * splitting of a node during tree creation.
37  */
38 const double BIHTree::size_reduce_factor = 0.8;
39 /**
40  * Maximum grow factor of total number of elements in childs compared to number of elements in
41  * the parent node during tree creation.
42  */
43 //const double BIHTree::max_grow_factor = 1.5;
44 
45 /*
46 BIHTree::BIHTree(Mesh* mesh, unsigned int soft_leaf_size_limit) {
47  xprintf(Msg, " - BIHTree->BIHTree(Mesh, unsigned int)\n");
48 
49  srand((unsigned)time(0));
50 
51  mesh_ = mesh;
52  nodes_.reserve(2 * mesh_->n_elements() / soft_leaf_size_limit);
53 
54  //START_TIMER("BIH Tree");
55 
56  element_boxes();
57  create_tree(soft_leaf_size_limit);
58 
59  free_memory();
60 
61  //END_TIMER("BIH Tree");
62 
63  xprintf(Msg, " - Tree created\n");
64 }
65 */
66 
67 BIHTree::BIHTree(Mesh* mesh, unsigned int soft_leaf_size_limit)
68 : r_gen(123), mesh_(mesh), leaf_size_limit(soft_leaf_size_limit)
69 {
70  ASSERT(mesh != nullptr, " ");
71  max_n_levels = 2*log(mesh->n_elements())/log(2);
72 
73  nodes_.reserve(2*mesh_->n_elements() / leaf_size_limit);
74  element_boxes();
75 
76  in_leaves_.resize(elements_.size());
77  for(unsigned int i=0; i<in_leaves_.size(); i++) in_leaves_[i] = i;
78 
79  // make root node
80  nodes_.push_back(BIHNode());
81  nodes_.back().set_leaf(0, in_leaves_.size(), 0, 0);
82  // make root box
83  Node* node = mesh_->node_vector.begin();
84  main_box_ = BoundingBox(node->point(), node->point());
85  FOR_NODES(mesh_, node ) {
86  main_box_.expand( node->point() );
87  }
88 
89  make_node(main_box_, 0);
90 }
91 
93 
94 }
95 
96 
97 
98 
99 /*
100 void BIHTree::create_tree(unsigned int soft_leaf_size_limit) {
101  create_root_node();
102 
103  // create tree
104  while (queue_.size()) {
105  BIHNode child[BIHNode::child_count];
106  BoundingBox child_box[BIHNode::child_count];
107 
108  ASSERT(queue_.front() < nodes_.size(), "Idx %d out of nodes_ of size %d.\n", queue_.front(), nodes_.size());
109 
110  BIHNode & actual_node = nodes_[queue_.front()];
111 
112  ASSERT(actual_node.is_leaf(), "Not leaf: %d\n",queue_.front() );
113  unsigned char depth = actual_node.depth();
114  unsigned int actual_node_leaf_size = actual_node.leaf_size();
115 
116  if (actual_node_leaf_size <= soft_leaf_size_limit) {
117  // mark node as definitive leaf
118  put_leaf_elements();
119  continue;
120  }
121 
122  unsigned char splitting_axis = box_queue_.front().longest_axis();
123  set_node_median(splitting_axis,actual_node);
124  actual_node.axis_ = splitting_axis; // actual_node is not leaf anymore
125 
126  //DBGMSG("node idx: %d median: %g axis: %d\n", queue_.front(), actual_node.median_, actual_node.axis_);
127 
128 
129  //calculate bounding boxes of subareas and create them
130  box_queue_.front().split(actual_node.axis(),actual_node.median(),child_box[0], child_box[1]);
131  child[0].set_depth(depth+1);
132  child[1].set_depth(depth+1);
133 
134  distribute_elements(child[0], child[1]);
135 
136  // test count of elements in subareas
137  if (child[0].leaf_size() > min_reduce_factor * actual_node_leaf_size ||
138  child[1].leaf_size() > min_reduce_factor * actual_node_leaf_size ||
139  child[0].leaf_size() + child[1].leaf_size() > max_grow_factor * actual_node_leaf_size) {
140 
141  list_element_index_next_.erase(list_element_index_next_.begin() + child[0].child_[0],
142  list_element_index_next_.begin() + child[1].child_[1]);
143  actual_node.set_depth(depth);
144  put_leaf_elements();
145  continue;
146  }
147 
148  // put nodes into vectors
149  test_new_level();
150  for (unsigned int i=0; i<BIHNode::child_count; i++) {
151  // can not use actual_node, since it can be invalid due to reallocation of nodes_
152 
153  nodes_[queue_.front()].child_[i] = nodes_.size();
154  queue_.push_back(nodes_.size());
155  box_queue_.push_back(child_box[i]);
156  nodes_.push_back(child[i]);
157  }
158 
159  // remove processed node from queue
160  queue_.pop_front();
161  box_queue_.pop_front();
162  }
163 
164 }*/
165 
166 
167 void BIHTree::split_node(const BoundingBox &node_box, unsigned int node_idx) {
168  BIHNode &node = nodes_[node_idx];
169  ASSERT(node.is_leaf(), " ");
170  unsigned int axis = node_box.longest_axis();
171  double median = estimate_median(axis, node);
172 
173  // split elements in node according to the median
174  auto left = in_leaves_.begin() + node.leaf_begin(); // first of unresolved elements in @p in_leaves_
175  auto right = in_leaves_.begin() + node.leaf_end()-1; // last of unresolved elements in @p in_leaves_
176 
177  double left_bound=node_box.min(axis); // max bound of the left group
178  double right_bound=node_box.max(axis); // min bound of the right group
179 
180  while (left != right) {
181  if ( elements_[ *left ].projection_center(axis) < median) {
182  left_bound = std::max( left_bound, elements_[ *left ].max(axis) );
183  //DBGMSG("left_bound: %g\n", left_bound);
184  ++left;
185  }
186  else {
187  while ( left != right
188  && elements_[ *right ].projection_center(axis) >= median ) {
189  right_bound = std::min( right_bound, elements_[ *right ].min(axis) );
190  //DBGMSG("right_bound: %g\n", right_bound);
191  --right;
192  }
193  std::swap( *left, *right);
194  }
195  }
196  // in any case left==right is now the first element of the right group
197 
198  unsigned int left_begin = node.leaf_begin();
199  unsigned int left_end = left - in_leaves_.begin();
200  unsigned int right_end = node.leaf_end();
201  unsigned int depth = node.depth()+1;
202  // create new leaf nodes and possibly call split_node on them
203  // can not use node reference anymore
204  nodes_.push_back(BIHNode());
205  nodes_.back().set_leaf(left_begin, left_end, left_bound, depth);
206  nodes_.push_back(BIHNode());
207  nodes_.back().set_leaf(left_end, right_end, right_bound, depth);
208 
209  nodes_[node_idx].set_non_leaf(nodes_.size()-2, nodes_.size()-1, axis);
210 }
211 
212 /*
213 void BIHTree::call_recursion(BoundingBox parent_box, BIHNode &parent, BoundingBox child_box, BIHNode &child) {
214 
215 }*/
216 
217 void BIHTree::make_node(const BoundingBox &box, unsigned int node_idx) {
218  // we must refer to the node by index to prevent seg. fault due to nodes_ reallocation
219 
220  split_node(box,node_idx);
221 
222 #ifdef DEBUG_MESSAGES
223 // cout << " branch node, axis: " << node.axis() << " bound: " << node.bound() << endl;
224 #endif
225  {
226  BIHNode &node = nodes_[node_idx];
227  BIHNode &child = nodes_[ node.child(0) ];
228 // DBGMSG("Node: %d\n",node.child(0));
229  BoundingBox node_box(box);
230  node_box.set_max(node.axis(), child.bound() );
231  if ( child.leaf_size() > leaf_size_limit
232  && child.depth() < max_n_levels
233  && ( node.axis() != node_box.longest_axis()
234  || node_box.size(node_box.longest_axis()) < box.size(node.axis()) * size_reduce_factor )
235  )
236  {
237  make_node(node_box, node.child(0) );
238  } else {
239 #ifdef DEBUG_MESSAGES
240 // cout << " leaf node, depth: " << child.depth() << " leaf range: " << child.leaf_begin() << " " << child.leaf_end() << endl;
241 // cout << " " << node_box << endl;
242 #endif
243  }
244  }
245 
246  {
247  BIHNode &node = nodes_[node_idx];
248  BIHNode &child = nodes_[ node.child(1) ];
249 // DBGMSG("Node: %d\n",node.child(1));
250  BoundingBox node_box(box);
251  node_box.set_min(node.axis(), child.bound() );
252  if ( child.leaf_size() > leaf_size_limit
253  && child.depth() < max_n_levels
254  && ( node.axis() != node_box.longest_axis()
255  || node_box.size(node_box.longest_axis()) < box.size(node.axis()) * size_reduce_factor )
256  )
257  {
258  make_node(node_box, node.child(1) );
259  } else {
260 #ifdef DEBUG_MESSAGES
261 // cout << " leaf node, depth: " << child.depth() << " leaf range: " << child.leaf_begin() << " " << child.leaf_end() <<endl;
262 // cout << " " <<node_box;
263 #endif
264  }
265  }
266 }
267 
268 /*
269 void BIHTree::create_root_node() {
270 
271  BIHNode bih_node(0);
272  bih_node.child_[0] = 0;
273  bih_node.child_[1] = mesh_->n_elements();
274  nodes_.push_back(bih_node);
275 
276  // put indexes of all elements to vector (for first level of tree)
277  list_element_index_.resize(mesh_->n_elements());
278  for (unsigned int i=0; i<mesh_->n_elements(); i++) {
279  list_element_index_[i] = i;
280  }
281 
282  // find minimal and maximal coordination of whole mesh
283  Node* node = mesh_->node_vector.begin();
284  main_box_ = BoundingBox(node->point(), node->point());
285 
286  FOR_NODES(mesh_, node ) {
287  main_box_.expand( node->point() );
288  }
289 
290  // put index of root node and its coordinations to vectors
291  queue_.clear();
292  queue_.push_back(0);
293  box_queue_.push_back(main_box_);
294 }
295 
296 */
297 
298 /*
299 void BIHTree::set_node_median(unsigned char axis, BIHNode &node)
300 {
301  unsigned int median_idx;
302  unsigned int n_elements = node.leaf_size();
303 
304  if (n_elements > max_median_sample_size) {
305  // random sample
306  coors_.resize(max_median_sample_size);
307  for (unsigned int i=0; i<coors_.size(); i++) {
308  median_idx = node.leaf_begin() + ( rand() << 15 | rand() ) % n_elements;
309  coors_[i] = elements_[ list_element_index_[ median_idx ] ].projection_center(axis);
310  }
311 
312  } else {
313  // all elements
314  coors_.resize(n_elements);
315  for (unsigned int i=0; i<coors_.size(); i++) {
316  median_idx = node.leaf_begin() + i;
317  coors_[i] = elements_[ list_element_index_[ median_idx ] ].projection_center(axis);
318  }
319 
320  }
321 
322  unsigned int median_position = (unsigned int)(coors_.size() / 2);
323  std::nth_element(coors_.begin(), coors_.begin()+median_position, coors_.end());
324 
325  node.median_ = coors_[median_position];
326 }*/
327 
328 double BIHTree::estimate_median(unsigned char axis, const BIHNode &node)
329 {
330  unsigned int median_idx;
331  unsigned int n_elements = node.leaf_size();
332 
333  if (n_elements > max_median_sample_size) {
334  // random sample
335  std::uniform_int_distribution<unsigned int> distribution(node.leaf_begin(), node.leaf_end()-1);
337  for (unsigned int i=0; i<coors_.size(); i++) {
338  median_idx = distribution(this->r_gen);
339 
340  coors_[i] = elements_[ in_leaves_[ median_idx ] ].projection_center(axis);
341  //DBGMSG(" random idx: %d, coor: %g\n", median_idx, coors_[i]);
342  }
343 
344  } else {
345  // all elements
346  coors_.resize(n_elements);
347  for (unsigned int i=0; i<coors_.size(); i++) {
348  median_idx = node.leaf_begin() + i;
349  coors_[i] = elements_[ in_leaves_[ median_idx ] ].projection_center(axis);
350  }
351 
352  }
353 
354  unsigned int median_position = (unsigned int)(coors_.size() / 2);
355  std::nth_element(coors_.begin(), coors_.begin()+median_position, coors_.end());
356 
357  //DBGMSG("median pos: %d %g\n", median_position, coors_[median_position]);
358  return coors_[median_position];
359 }
360 /*
361 void BIHTree::sort_elements(unsigned int &bound1, unsigned int &bound2) {
362  unsigned int bound3;
363  BIHNode & actual_node = nodes_[queue_.front()];
364 
365  // Four groups:
366  // <0, bound1) - left elements
367  // <bound1, bound2) - elements in both domains
368  // <bound2, bound3) - not yet processed elements
369  // <bound3, .. - right elements
370  bound1 = actual_node.child_[0];
371  bound2 = actual_node.child_[0];
372  bound3 = actual_node.child_[1];
373  while (bound2 != bound3) {
374  if (elements_[ list_element_index_[bound2] ].min()(actual_node.axis()) < actual_node.median_) {
375  if (elements_[ list_element_index_[bound2] ].max()(actual_node.axis()) > actual_node.median_) {
376  // median in bounding box (element in both ranges)
377  bound2++;
378  } else {
379  // median after bounding box (element in left range)
380  if (bound1 != bound2) {
381  std::swap(list_element_index_[bound1], list_element_index_[bound2]);
382  }
383  bound1++;
384  bound2++;
385  }
386  } else {
387  // median before bounding box (element in right range)
388  std::swap(list_element_index_[bound2], list_element_index_[bound3-1]);
389  bound3--;
390  }
391  }
392 }*/
393 
394 /*
395 void BIHTree::distribute_elements(BIHNode &left_child, BIHNode &right_child) {
396  unsigned int bound1, bound2;
397  BIHNode & actual_node = nodes_[queue_.front()];
398  sort_elements(bound1, bound2);
399 
400  // distribute elements into subareas
401  left_child.child_[0] = list_element_index_next_.size();
402  for (unsigned int i=actual_node.child_[0]; i<bound2; i++) {
403  list_element_index_next_.push_back(list_element_index_[i]);
404  }
405  left_child.child_[1] = list_element_index_next_.size();
406  right_child.child_[0] = list_element_index_next_.size();
407  for (unsigned int i=bound1; i<actual_node.child_[1]; i++) {
408  list_element_index_next_.push_back(list_element_index_[i]);
409  }
410  right_child.child_[1] = list_element_index_next_.size();
411 }
412 
413 
414 void BIHTree::put_leaf_elements() {
415  unsigned int lower_bound = in_leaves_.size();
416  BIHNode & actual_node = nodes_[queue_.front()];
417 
418  for (unsigned int i=actual_node.child_[0]; i<actual_node.child_[1]; i++) {
419  in_leaves_.push_back(list_element_index_[i]);
420  }
421 
422  test_new_level();
423  actual_node.child_[0] = lower_bound;
424  actual_node.child_[1] = in_leaves_.size();
425  queue_.pop_front();
426  box_queue_.pop_front();
427 }*/
428 
429 /*
430 void BIHTree::free_memory() {
431  std::deque<unsigned int>().swap(queue_);
432  std::deque<BoundingBox>().swap(box_queue_);
433  std::vector<unsigned int>().swap(list_element_index_);
434  std::vector<unsigned int>().swap(list_element_index_next_);
435  std::vector<double>().swap(coors_);
436 }
437 
438 
439 void BIHTree::test_new_level() {
440  if (nodes_[queue_.front()].child_[1] == list_element_index_.size()) {
441  //printf("test splnen\n");
442  list_element_index_.swap(list_element_index_next_);
443  list_element_index_next_.clear();
444  }
445 }
446 */
447 
448 
450  return elements_.size();
451 }
452 
453 
455  return main_box_;
456 }
457 
458 
460 {
461  std::stack<unsigned int, std::vector<unsigned int> > node_stack;
462  ASSERT_EQUAL(result_list.size() , 0);
463 
464  node_stack.push(0);
465  while (! node_stack.empty()) {
466  const BIHNode &node = nodes_[node_stack.top()];
467  //DBGMSG("node: %d\n", node_stack.top() );
468  node_stack.pop();
469 
470 
471  if (node.is_leaf()) {
472 
473  //DBGMSG( "leaf: %d size %d\n", queue_.front(), node.leaf_size() );
474  //START_TIMER("leaf");
475  for (unsigned int i=node.leaf_begin(); i<node.leaf_end(); i++) {
476  //DBGMSG("check i: %d i_ele: %d id: %d\n", i, in_leaves_[i], mesh_->element( in_leaves_[i] ).id());
477  //DBGCOUT( << "in leaf: " << elements_[ in_leaves_[i] ] <<endl );
478  if (elements_[ in_leaves_[i] ].intersect(box)) {
479 
480  //DBGMSG("el_id: %d\n" , mesh_->element(in_leaves_[i]).id() );
481  result_list.push_back(in_leaves_[i]);
482  }
483  }
484  //END_TIMER("leaf");
485  } else {
486  //DBGMSG("axis: %d bound left: %g right: %g\n",node.axis(),nodes_[node.child(0)].bound(), nodes_[node.child(1)].bound());
487  //START_TIMER("recursion");
488  if ( ! box.projection_gt( node.axis(), nodes_[node.child(0)].bound() ) ) {
489  //DBGMSG("push:%d\n", node.child(0));
490  // box intersects left group
491  node_stack.push( node.child(0) );
492  }
493  if ( ! box.projection_lt( node.axis(), nodes_[node.child(1)].bound() ) ) {
494  //DBGMSG("push:%d\n", node.child(1));
495  // box intersects right group
496  node_stack.push( node.child(1) );
497  }
498  //END_TIMER("recursion");
499  }
500  }
501 
502 
503 #ifdef DEBUG_ASSERT
504  // check uniqueness of element indexes
505  sort(result_list.begin(), result_list.end());
506  it = unique(result_list.begin(), result_list.end());
507  ASSERT_EQUAL(searsearchedElements.size() , it - result_list.begin());
508 #endif
509 }
510 
511 
513  find_bounding_box(BoundingBox(point), result_list);
514 }
515 
516 
517 
519  elements_.resize(mesh_->element.size());
520  unsigned int i=0;
521  FOR_ELEMENTS(mesh_, element) {
522  elements_[i] = element->bounding_box();
523 
524  i++;
525  }
526 }
527 
528 /*
529 
530 void BIHTree::get_tree_params(unsigned int &maxDepth, unsigned int &minDepth, double &avgDepth, unsigned int &leafNodesCount,
531  unsigned int &innerNodesCount, unsigned int &sumElements) {
532  unsigned int sumDepth = 0;
533  maxDepth = 0;
534  minDepth = 32767;
535  leafNodesCount = 0;
536  innerNodesCount = 1;
537 
538  for (unsigned int i=0; i<nodes_.size(); i++) {
539  if (nodes_[i].is_leaf()) {
540  if (nodes_[i].depth() > maxDepth) maxDepth = nodes_[i].depth();
541  if (nodes_[i].depth() < minDepth) minDepth = nodes_[i].depth();
542  sumDepth += nodes_[i].depth();
543  ++leafNodesCount;
544  } else {
545  ++innerNodesCount;
546  }
547  }
548 
549  avgDepth = (double) sumDepth / (double) leafNodesCount;
550  sumElements = in_leaves_.size();
551 }
552 */