Loading [MathJax]/extensions/tex2jax.js
ug4
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
ntree_impl.hpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2013-2015: G-CSC, Goethe University Frankfurt
3 * Author: Sebastian Reiter
4 *
5 * This file is part of UG4.
6 *
7 * UG4 is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License version 3 (as published by the
9 * Free Software Foundation) with the following additional attribution
10 * requirements (according to LGPL/GPL v3 §7):
11 *
12 * (1) The following notice must be displayed in the Appropriate Legal Notices
13 * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
14 *
15 * (2) The following notice must be displayed at a prominent place in the
16 * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
17 *
18 * (3) The following bibliography is recommended for citation and must be
19 * preserved in all covered files:
20 * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
21 * parallel geometric multigrid solver on hierarchically distributed grids.
22 * Computing and visualization in science 16, 4 (2013), 151-164"
23 * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
24 * flexible software system for simulating pde based models on high performance
25 * computers. Computing and visualization in science 16, 4 (2013), 165-179"
26 *
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU Lesser General Public License for more details.
31 */
32
33#ifndef __H__UG__ntree_impl__
34#define __H__UG__ntree_impl__
35
36#include <cassert>
37#include "ntree.h"
38
39namespace ug{
40
41template <int tree_dim, int world_dim, class elem_t, class common_data_t>
43ntree() :
44 m_warningsEnabled (true)
45{
46 m_nodes.resize(1);
47}
48
49
50template <int tree_dim, int world_dim, class elem_t, class common_data_t>
53{
54 m_nodes.clear();
55 m_nodes.resize(1);
56 m_nodes[0].level = 0;
57}
58
59
60template <int tree_dim, int world_dim, class elem_t, class common_data_t>
62clear()
63{
64 clear_nodes();
65 m_entries.clear();
66 m_numDelayedElements = 0;
67}
68
69
70template <int tree_dim, int world_dim, class elem_t, class common_data_t>
72set_desc(const NTreeDesc& desc)
73{
74 m_desc = desc;
75}
76
77template <int tree_dim, int world_dim, class elem_t, class common_data_t>
79desc() const
80{
81 return m_desc;
82}
83
84template <int tree_dim, int world_dim, class elem_t, class common_data_t>
86set_common_data(const common_data_t& commonData)
87{
88 m_commonData = commonData;
89}
90
91template <int tree_dim, int world_dim, class elem_t, class common_data_t>
93common_data() const
94{
95 return m_commonData;
96}
97
98template <int tree_dim, int world_dim, class elem_t, class common_data_t>
100empty() const
101{
102 return size() == 0;
103}
104
105
106template <int tree_dim, int world_dim, class elem_t, class common_data_t>
108size() const
109{
110 return m_entries.size() - m_numDelayedElements;
111}
112
113
114template <int tree_dim, int world_dim, class elem_t, class common_data_t>
117{
118 return m_numDelayedElements;
119}
120
121
122template <int tree_dim, int world_dim, class elem_t, class common_data_t>
124add_element(const elem_t& elem)
125{
126// size_t entryInd = m_entries.size();
127 m_entries.push_back(Entry(elem));
128
129 ++m_numDelayedElements;
130
131//todo If we allowed for immediate on-the-fly insertion of elements, the following
132// code could serve as an implementation base. Note, that it is not yet complete.
133// One would have to update parent boxes if a child box changes etc.
134// It would make sense to also allow for the specification of a
135// minimum root-bounding-box, since else most insertions would trigger a rebalance.
136// {
137// vector_t center;
138// traits::calculate_center(center, elem, m_commonData);
139// size_t nodeInd = find_leaf_node(center);
140// if(nodeInd == s_invalidIndex){
141// ++m_numDelayedElements;
142// rebalance();
143// }
144// else{
145// Node& node = m_nodes[nodeInd];
146// add_entry_to_node(node, entryInd);
147// if(node.numEntries >= m_desc.splitThreshold)
148// split_leaf_node(nodeInd);
149// else{
150// //todo the update could be much more efficient (simply unite the
151// // old bounding box with the new element's bounding box.
152// update_loose_bounding_box(node);
153// }
154// }
155// }
156}
157
158
159template <int tree_dim, int world_dim, class elem_t, class common_data_t>
161rebalance()
162{
163// push all elements into the root node, calculate its bounding box
164// and call split_leaf_node if the element threshold is surpassed.
165 clear_nodes();
166 Node& root = m_nodes.back();
167 if(!m_entries.empty()){
168 root.firstEntryInd = 0;
169 root.lastEntryInd = m_entries.size() - 1;
170 root.numEntries = m_entries.size();
171 for(size_t i = 0; i < m_entries.size(); ++i)
172 m_entries[i].nextEntryInd = i+1;
173 m_entries.back().nextEntryInd = s_invalidIndex;
174
175 // the tight bounding box and the loose bounding box of the root node
176 // should be the same.
177 update_loose_bounding_box(root);
178 root.tightBox = root.looseBox;
179
180 if(root.numEntries >= m_desc.splitThreshold)
181 split_leaf_node(0);
182 }
183}
184
185
186template <int tree_dim, int world_dim, class elem_t, class common_data_t>
188split_leaf_node(size_t nodeIndex)
189{
191 if(m_nodes[nodeIndex].numEntries <= 1)
192 return;
194 if(m_nodes[nodeIndex].level >= m_desc.maxDepth){
195 if(m_warningsEnabled){
196 UG_LOG("WARNING in ntree::split_leaf_node(): maximum tree depth "
197 << m_desc.maxDepth << " reached. No further splits are performed for "
198 " this node. Note that too many elements per node may lead to performance issues.\n"
199 << " Number of elements in this node: " << m_nodes[nodeIndex].numEntries << std::endl
200 << " Corner coordinates of this node: " << m_nodes[nodeIndex].tightBox << std::endl);
201 }
202 return;
203 }
204
205 if(m_nodes[nodeIndex].childNodeInd[0] != s_invalidIndex)
206 return;
207
208 const size_t firstChild = m_nodes.size();
209 m_nodes.resize(firstChild + s_numChildren);
210
211// ATTENTION: Be careful not to resize m_nodes while using node, since this would invalidate the reference!
212 Node& node = m_nodes[nodeIndex];
213
214// calculate center of mass and use the traits class to split the box of
215// the current node into 's_numChildren' child boxes. Each child box thereby
216// spanned by one of the corners of the original box and 'centerOfMass'.
217 vector_t centerOfMass = calculate_center_of_mass(node);
218 box_t childBoxes[s_numChildren];
219 traits::split_box(childBoxes, node.tightBox, centerOfMass);
220
221// iterate over all entries in the current node and assign them to child nodes.
222 size_t numEntriesAssigned = 0;
223 for(size_t entryInd = node.firstEntryInd; entryInd != s_invalidIndex;){
224 Entry& entry = m_entries[entryInd];
225 size_t nextEntryInd = entry.nextEntryInd;
226
227 size_t i_child;
228 vector_t center;
229 traits::calculate_center(center, entry.elem, m_commonData);
230 for(i_child = 0; i_child < s_numChildren; ++i_child){
231 if(traits::box_contains_point(childBoxes[i_child], center)){
232 add_entry_to_node(m_nodes[firstChild + i_child], entryInd);
233 ++numEntriesAssigned;
234 break;
235 }
237 /*-- For debugging only: --*
238 if(i_child == s_numChildren){
239 UG_LOG ("ERROR in ntree::split_leaf_node(): Element with center @ " << center
240 << " does not belong to any child of the box " << node.tightBox << std::endl);
241 }
242 *--*/
243
244 entryInd = nextEntryInd;
246
247// all elements of the current box now should be assigned to child boxes.
248// we thus clear element lists and entry-count from the current node.
249 UG_COND_THROW(numEntriesAssigned != node.numEntries, "Couldn't find a matching "
250 "child node for some elements during split_leaf_node in "
251 "ntree::split_leaf_node");
252
253 node.firstEntryInd = node.lastEntryInd = s_invalidIndex;
254 node.numEntries = 0;
255
256 for(size_t i_child = 0; i_child < s_numChildren; ++i_child){
257 node.childNodeInd[i_child] = firstChild + i_child;
258 Node& childNode = m_nodes[firstChild + i_child];
259 childNode.level = node.level + 1;
260 childNode.tightBox = childBoxes[i_child];
261 update_loose_bounding_box(childNode);
262 }
263
264// since split_leaf_node resizes m_nodes and since this invalidates any references
265// to m_nodes, we perform the recursion in a last step
266 for(size_t i_child = 0; i_child < s_numChildren; ++i_child){
267 size_t childNodeInd = firstChild + i_child;
268 if(m_nodes[childNodeInd].numEntries >= m_desc.splitThreshold)
269 split_leaf_node(childNodeInd);
270 }
271}
272
273
274template <int tree_dim, int world_dim, class elem_t, class common_data_t>
276find_leaf_node(const vector_t& point, size_t curNode)
277{
278 Node& n = m_nodes[curNode];
279 if(traits::box_contains_point(n.tightBox, point)){
280 if(n.childNodeInd[0] != s_invalidIndex){
281 for(size_t i = 0; i < s_numChildren; ++i){
282 size_t result = find_leaf_node(point, n.childNodeInd[i]);
283 if(result != s_invalidIndex)
284 return result;
285 }
286 }
287 else{
288 return curNode;
289 }
290 }
291 return s_invalidIndex;
292}
293
294
295template <int tree_dim, int world_dim, class elem_t, class common_data_t>
297add_entry_to_node(Node& node, size_t entryInd)
298{
299 if(node.firstEntryInd == s_invalidIndex){
300 assert(node.numEntries == 0);
301 node.firstEntryInd = node.lastEntryInd = entryInd;
302 }
303 else{
304 m_entries[node.lastEntryInd].nextEntryInd = entryInd;
305 node.lastEntryInd = entryInd;
306 }
307
308 m_entries[entryInd].nextEntryInd = s_invalidIndex;
309 ++node.numEntries;
310}
311
312
313template <int tree_dim, int world_dim, class elem_t, class common_data_t>
317 size_t entryInd = node.firstEntryInd;
318 if(entryInd == s_invalidIndex){
319 node.looseBox = node.tightBox;
320 return;
322
323 Entry& entry = m_entries[entryInd];
324 traits::calculate_bounding_box(node.looseBox, entry.elem, m_commonData);
325
326 entryInd = entry.nextEntryInd;
327 while(entryInd != s_invalidIndex){
328 Entry& entry = m_entries[entryInd];
329 box_t nbox;
330 traits::calculate_bounding_box(nbox, entry.elem, m_commonData);
331 traits::merge_boxes(node.looseBox, node.looseBox, nbox);
332 entryInd = entry.nextEntryInd;
333 }
334
335//todo: Solve box-growing in a more portable way!
336 typename traits::vector_t offset;
337 offset = SMALL;
338 traits::grow_box(node.looseBox, node.looseBox, offset);
339}
340
341
342template <int tree_dim, int world_dim, class elem_t, class common_data_t>
346{
347 vector_t centerOfMass;
348 VecSet(centerOfMass, 0);
349
350 for(size_t entryInd = node.firstEntryInd; entryInd != s_invalidIndex;){
351 Entry& entry = m_entries[entryInd];
352
353 vector_t center;
354 traits::calculate_center(center, entry.elem, m_commonData);
355 VecAdd(centerOfMass, centerOfMass, center);
356 entryInd = entry.nextEntryInd;
357 }
358
359 if(node.numEntries > 0)
360 VecScale(centerOfMass, centerOfMass, (real_t)1 / (real_t)node.numEntries);
361
362 return centerOfMass;
363}
364
365
366template <int tree_dim, int world_dim, class elem_t, class common_data_t>
368num_nodes() const
369{
370 return m_nodes.size();
371}
372
373
374template <int tree_dim, int world_dim, class elem_t, class common_data_t>
376num_child_nodes(size_t nodeId) const
377{
378 assert(nodeId < m_nodes.size());
379 if(m_nodes[nodeId].childNodeInd[0] == s_invalidIndex)
380 return 0;
381 return s_numChildren;
382}
383
384
385template <int tree_dim, int world_dim, class elem_t, class common_data_t>
387child_node_ids(size_t nodeId) const
388{
389 assert(nodeId < m_nodes.size());
390 return m_nodes[nodeId].childNodeInd;
391}
392
393
394template <int tree_dim, int world_dim, class elem_t, class common_data_t>
397elems_begin(size_t nodeId) const
398{
399 assert(nodeId < m_nodes.size());
400 if(m_entries.empty())
401 return elem_iterator_t(NULL, s_invalidIndex);
402 return elem_iterator_t(&m_entries.front(), m_nodes[nodeId].firstEntryInd);
403}
404
405
406template <int tree_dim, int world_dim, class elem_t, class common_data_t>
409elems_end(size_t nodeId) const
410{
411 return elem_iterator_t(NULL, s_invalidIndex);
412}
413
414
415template <int tree_dim, int world_dim, class elem_t, class common_data_t>
417num_elements(size_t nodeId) const
418{
419 assert(nodeId < m_nodes.size());
420 return m_nodes[nodeId].numEntries;
421}
422
423template <int tree_dim, int world_dim, class elem_t, class common_data_t>
425level(size_t nodeId) const
426{
427 assert(nodeId < m_nodes.size());
428 return m_nodes[nodeId].level;
429}
430
431template <int tree_dim, int world_dim, class elem_t, class common_data_t>
434bounding_box(size_t nodeId) const
435{
436 assert(nodeId < m_nodes.size());
437 return m_nodes[nodeId].looseBox;
438}
439
440}// end of namespace
441
442#endif
void add_entry_to_node(Node &node, size_t entryInd)
adds an entry to the given node
Definition ntree_impl.hpp:297
size_t num_elements(size_t nodeId) const
returns the number of elements that the given node contains
Definition ntree_impl.hpp:417
size_t num_delayed_elements() const
returns the number of elements which have been added but are not yet accessible in the tree.
Definition ntree_impl.hpp:116
void add_element(const elem_t &elem)
adds an element to the tree.
Definition ntree_impl.hpp:124
elem_iterator_t elems_end(size_t nodeId) const
returns an iterator to the end of the element-sequence of a given node
Definition ntree_impl.hpp:409
void clear()
Definition ntree_impl.hpp:62
const NTreeDesc & desc() const
returns the balancing-parameters of the tree.
Definition ntree_impl.hpp:79
void split_leaf_node(size_t nodeIndex)
splits a node into 2^tree_dim child nodes and assigns entries to those children.
Definition ntree_impl.hpp:188
size_t num_child_nodes(size_t nodeId) const
returns the number of children of a node
Definition ntree_impl.hpp:376
size_t num_nodes() const
returns the total number of nodes in the tree
Definition ntree_impl.hpp:368
size_t size() const
returns the number of entries in the tree (delayed entries excluded)
Definition ntree_impl.hpp:108
void clear_nodes()
clear only the nodes
Definition ntree_impl.hpp:52
TCommonData common_data_t
Definition ntree.h:169
TElem elem_t
Definition ntree.h:168
bool empty() const
returns true if the tree is empty
Definition ntree_impl.hpp:100
ntree()
Definition ntree_impl.hpp:43
vector_t calculate_center_of_mass(Node &node)
calculates the center of mass of a given node
Definition ntree_impl.hpp:345
const box_t & bounding_box(size_t nodeId) const
returns the smallest box which contains all elements of the given node
Definition ntree_impl.hpp:434
void rebalance()
rebalances the whole tree
Definition ntree_impl.hpp:161
const common_data_t & common_data() const
returns the common-data stored in the tree
Definition ntree_impl.hpp:93
size_t level(size_t nodeId) const
returns the number tree-level in which the node is located
Definition ntree_impl.hpp:425
size_t find_leaf_node(const vector_t &point, size_t curNode=0)
returns an index to the leaf-node which contains the given point
Definition ntree_impl.hpp:276
void update_loose_bounding_box(Node &node)
updates the loose bounding box of the given node
Definition ntree_impl.hpp:315
const_ntree_element_iterator< elem_t, Entry > elem_iterator_t
Definition ntree.h:174
void set_desc(const NTreeDesc &desc)
sets the balancing-parameters of the tree.
Definition ntree_impl.hpp:72
elem_iterator_t elems_begin(size_t nodeId) const
returns an iterator to the first element of a given node
Definition ntree_impl.hpp:397
void set_common_data(const common_data_t &commonData)
sets the common-data which the tree passes on to callback methods
Definition ntree_impl.hpp:86
const size_t * child_node_ids(size_t nodeId) const
returns an array of child-id's for the given node
Definition ntree_impl.hpp:387
traits::real_t real_t
Definition ntree.h:171
std::vector< Node > m_nodes
m_nodes[0] is always considered to be the root node.
Definition ntree.h:334
#define UG_LOG(msg)
Definition log.h:367
#define UG_COND_THROW(cond, msg)
UG_COND_THROW(cond, msg) : performs a UG_THROW(msg) if cond == true.
Definition error.h:61
void VecSet(vector_t &vInOut, typename vector_t::value_type s)
Set each vector component to scalar (componentwise)
Definition math_vector_functions_common_impl.hpp:539
void VecAdd(vector_t &vOut, const vector_t &v1, const vector_t &v2)
adds two MathVector<N>s and stores the result in a third one
Definition math_vector_functions_common_impl.hpp:185
void VecScale(vector_t &vOut, const vector_t &v, typename vector_t::value_type s)
scales a MathVector<N>
Definition math_vector_functions_common_impl.hpp:252
the ug namespace
const number SMALL
Definition math_constants.h:41
Definition ntree.h:100
An Entry combines an element with the index to the next entry in a leaf-node's entry list.
Definition ntree.h:273
elem_t elem
Definition ntree.h:274
size_t nextEntryInd
Definition ntree.h:277
Definition ntree.h:286
size_t numEntries
number of entries in the node
Definition ntree.h:290
size_t lastEntryInd
index into m_entries. s_invalidIndex: no entry
Definition ntree.h:289
box_t tightBox
tight bounding box - disjunct partition of the root box
Definition ntree.h:292
box_t looseBox
loose bounding box - contains all bounding boxes of its entries
Definition ntree.h:293
size_t firstEntryInd
< index into m_nodes. s_invalidIndex: no child node.
Definition ntree.h:288
size_t childNodeInd[s_numChildren]
Definition ntree.h:287