NiHu  2.0
cluster_tree.hpp
Go to the documentation of this file.
1 
7 #ifndef NIHU_CLUSTER_TREE_HPP_INCLUDED
8 #define NIHU_CLUSTER_TREE_HPP_INCLUDED
9 
10 #include "cluster.hpp"
11 #include "divide.hpp"
12 #include "util/misc.hpp"
13 
14 #include "Eigen/Dense"
15 #include "Eigen/StdVector"
16 
17 #include <algorithm> // std::min_element
18 #include <cstddef>
19 #include <iostream>
20 #include <numeric> // std::iota
21 #include <stdexcept> // std::logic_error
22 
23 namespace NiHu
24 {
25 namespace fmm
26 {
27 
32 template <class ClusterDerived>
34 {
35 public:
36  typedef ClusterDerived cluster_t;
37 
38  static size_t const dimension = cluster_t::dimension;
39  typedef typename cluster_t::bounding_box_t bounding_box_t;
40  typedef typename cluster_t::location_t location_t;
41  typedef typename cluster_t::idx_list_t idx_list_t;
42 
44  typedef std::vector<
45  cluster_t, Eigen::aligned_allocator<cluster_t>
47 
48  typedef typename cluster_vector_t::const_iterator iterator_t;
49 
50 public:
58  template <class It, class DivideDerived>
59  cluster_tree(It src_begin, It src_end, divide_base<DivideDerived> const& divide)
60  : cluster_tree(src_begin, src_end, src_begin, src_end, divide)
61  {
62  }
63 
74  template <class It1, class It2, class DivideDerived>
75  cluster_tree(It1 src_begin, It1 src_end, It2 rec_begin, It2 rec_end, divide_base<DivideDerived> const& divide)
76  : n_src(src_end - src_begin)
77  , n_rec(rec_end - rec_begin)
78  {
79  if (this->n_src + this->n_rec == 0)
80  throw std::logic_error("Cannot build cluster_tree from zero nodes");
81 
82  cluster_t root_cluster;
83  root_cluster.set_level(0);
84 
85  // compute bounding box of source and receiver nodes
86  typedef Eigen::Matrix<double, dimension, Eigen::Dynamic> nodes_t;
87  nodes_t nodes(dimension, n_src + n_rec);
88  for (size_t i = 0; i < n_src; ++i)
89  nodes.col(i) = src_begin[i];
90  for (size_t i = 0; i < n_rec; ++i)
91  nodes.col(n_src + i) = rec_begin[i];
92  bounding_box_t bb(nodes);
93  root_cluster.set_bounding_box(bb);
94 
95  // compute node index vectors of root cluster
96  idx_list_t src_node_idx(n_src);
97  std::iota(src_node_idx.begin(), src_node_idx.end(), 0);
98  root_cluster.set_src_node_idx(src_node_idx);
99 
100  idx_list_t rec_node_idx(n_rec);
101  std::iota(rec_node_idx.begin(), rec_node_idx.end(), 0);
102  root_cluster.set_rec_node_idx(rec_node_idx);
103 
104  this->clusters.push_back(root_cluster);
105 
106  // BFS traverse
107  for (size_t idx = 0; idx < clusters.size(); ++idx)
108  {
109  if (divide(clusters[idx]))
110  {
111  // get parent bounding box
112  auto par_bb = clusters[idx].get_bounding_box();
113 
114  // copy of parent source and receiver node indices
115  auto par_src = clusters[idx].get_src_node_idx();
116  auto par_rec = clusters[idx].get_rec_node_idx();
117 
118  // traverse possible children
119  for (size_t i = 0; i < (1 << dimension); ++i)
120  {
121  auto child_bb = par_bb.get_child(i);
122 
123  // move source indices to child if contained
124  idx_list_t child_src(par_src.size());
125  auto q_src = move_if(par_src.begin(), par_src.end(),
126  child_src.begin(), [&](size_t u) {
127  return bounding_box_t::dist2idx(src_begin[u], par_bb.get_center()) == i;
128  });
129  child_src.resize(std::distance(q_src, par_src.end()));
130  par_src.erase(q_src, par_src.end());
131 
132  // move receiver indices to child if contained
133  idx_list_t child_rec(par_rec.size());
134  auto q_rec = move_if(par_rec.begin(), par_rec.end(),
135  child_rec.begin(), [&](size_t u) {
136  return bounding_box_t::dist2idx(rec_begin[u], par_bb.get_center()) == i;
137  });
138  child_rec.resize(std::distance(q_rec, par_rec.end()));
139  par_rec.erase(q_rec, par_rec.end());
140 
141  // if child is empty, don't add to tree
142  if (child_src.empty() && child_rec.empty())
143  continue;
144 
145  cluster_t child;
146  child.set_parent(idx);
147  child.set_bounding_box(child_bb);
148  child.set_src_node_idx(child_src);
149  child.set_rec_node_idx(child_rec);
150  child.set_level(clusters[idx].get_level() + 1);
151  clusters[idx].add_child(clusters.size());
152  clusters.push_back(child);
153  }
154  if (!par_src.empty() || !par_rec.empty())
155  throw std::runtime_error("Remaining nodes in divided cluster");
156  }
157  else
158  {
159  this->leaf_indices.push_back(idx);
160  if (clusters[idx].is_source())
161  this->leaf_src_indices.push_back(idx);
162  if (clusters[idx].is_receiver())
163  this->leaf_rec_indices.push_back(idx);
164  }
165  }
166 
167  // build levels structure
168  this->levels.push_back(0);
169  for (size_t i = 0; i < this->clusters.size() - 1; ++i)
170  if (this->clusters[i].get_level() != this->clusters[i + 1].get_level())
171  this->levels.push_back(i + 1);
172  this->levels.push_back(this->clusters.size());
173 
174  }
175 
176  size_t get_n_src_nodes() const
177  {
178  return this->n_src;
179  }
180 
181  size_t get_n_rec_nodes() const
182  {
183  return this->n_rec;
184  }
185 
189  std::vector<size_t> const &get_leaf_indices() const
190  {
191  return this->leaf_indices;
192  }
193 
194  std::vector<size_t> const &get_leaf_src_indices() const
195  {
196  return this->leaf_src_indices;
197  }
198 
199  std::vector<size_t> const &get_leaf_rec_indices() const
200  {
201  return this->leaf_rec_indices;
202  }
203 
207  size_t get_n_leaves() const
208  {
209  return this->leaf_indices.size();
210  }
211 
215  std::vector<idx_list_t> get_leaf_src_index_vectors() const
216  {
217  std::vector<idx_list_t> indices(get_n_leaves());
218  auto v = get_leaf_indices();
219  for (size_t i = 0; i < v.size(); ++i)
220  indices[i] = this->clusters[v[i]].get_src_node_idx();
221  return indices;
222  }
223 
228  cluster_t const &operator[](size_t idx) const
229  {
230  return clusters[idx];
231  }
232 
237  cluster_t &operator[](size_t idx)
238  {
239  return clusters[idx];
240  }
241 
245  double get_root_diameter() const
246  {
247  return clusters[0].get_bounding_box().get_diameter();
248  }
249 
253  size_t get_n_levels() const
254  {
255  // note that levels is one element larger as it contains an end iterator
256  return this->levels.size() - 1;
257  }
258 
264  size_t level_begin(size_t idx) const
265  {
266  return this->levels[idx];
267  }
268 
274  size_t level_end(size_t idx) const
275  {
276  return this->levels[idx + 1];
277  }
278 
282  size_t get_n_clusters() const
283  {
284  return this->clusters.size();
285  }
286 
287  iterator_t begin() const
288  {
289  return clusters.begin();
290  }
291 
292  iterator_t end() const
293  {
294  return clusters.end();
295  }
296 
301  void print_debug(std::ostream &os = std::cout) const
302  {
303  os << "#Levels: " << this->get_n_levels() << std::endl;
304  for (size_t l = 0; l < this->get_n_levels(); ++l)
305  os << "Level #" << l << ": " << level_end(l) - level_begin(l) << " clusters" << std::endl;
306  os << "#Source Nodes: " << this->get_n_src_nodes() << std::endl;
307  os << "#Receiver Nodes: " << this->get_n_rec_nodes() << std::endl;
308  os << "Root diameter: " << this->get_root_diameter() << std::endl;
309  }
310 
311  idx_list_t get_src_ids() const
312  {
313  return this->src_node_ids;
314  }
315 
316  idx_list_t const &get_rec_ids() const
317  {
318  return this->rec_node_id;
319  }
320 
321 private:
322  size_t n_src, n_rec;
323 
324  cluster_vector_t clusters;
325 
326  std::vector<size_t> leaf_indices;
327  std::vector<size_t> leaf_src_indices;
328  std::vector<size_t> leaf_rec_indices;
329  std::vector<size_t> levels;
330 };
331 
332 template <class ClusterDerived>
333 size_t const cluster_tree<ClusterDerived>::dimension;
334 
335 
336 template <class C>
337 std::ostream &operator<<(std::ostream &os, cluster_tree<C> const &ct)
338 {
339  ct.print_debug(os);
340  return os;
341 }
342 
343 } // end of namespace fmm
344 } // end of namespace NiHu
345 
346 #endif /* NIHU_CLUSTER_TREE_HPP_INCLUDED */
NiHu::fmm::cluster_tree::operator[]
cluster_t & operator[](size_t idx)
index operator returning the idx-th cluster
Definition: cluster_tree.hpp:237
NiHu::move_if
InputIterator move_if(InputIterator first, InputIterator last, OutputIterator result, Predicate pred)
move selected elements from a range to an other
Definition: misc.hpp:20
NiHu::fmm::cluster_tree::get_n_leaves
size_t get_n_leaves() const
return number of leaf clusters
Definition: cluster_tree.hpp:207
NiHu::fmm::cluster_tree::get_n_clusters
size_t get_n_clusters() const
return number of clusters
Definition: cluster_tree.hpp:282
NiHu::operator<<
std::ostream & operator<<(std::ostream &os, const quadrature_base< Derived > &Q)
print a quadrature into an ouput stream
Definition: quadrature.hpp:317
NiHu::fmm::chebyshev_cluster::dimension
static const size_t dimension
the space's dimension
Definition: chebyshev_cluster.hpp:55
NiHu::fmm::cluster_tree::operator[]
const cluster_t & operator[](size_t idx) const
index operator returning the idx-th cluster
Definition: cluster_tree.hpp:228
NiHu::fmm::cluster_tree::cluster_tree
cluster_tree(It src_begin, It src_end, divide_base< DivideDerived > const &divide)
Create a cluster tree.
Definition: cluster_tree.hpp:59
NiHu::fmm::cluster_tree::get_root_diameter
double get_root_diameter() const
return root bounding box diameter
Definition: cluster_tree.hpp:245
NiHu::fmm::cluster_tree
Class representing a cluster tree.
Definition: cluster_tree.hpp:33
NiHu::fmm::cluster_tree::print_debug
void print_debug(std::ostream &os=std::cout) const
Print debug information to output strean.
Definition: cluster_tree.hpp:301
NiHu::fmm::cluster_tree::get_n_levels
size_t get_n_levels() const
return number of levels
Definition: cluster_tree.hpp:253
NiHu::fmm::divide_base
Base CRTP class for cluster division.
Definition: divide.hpp:28
NiHu::fmm::cluster_tree::cluster_tree
cluster_tree(It1 src_begin, It1 src_end, It2 rec_begin, It2 rec_end, divide_base< DivideDerived > const &divide)
Create a cluster tree.
Definition: cluster_tree.hpp:75
NiHu::fmm::cluster_tree::level_begin
size_t level_begin(size_t idx) const
Begin iterator to idx-th level clusters.
Definition: cluster_tree.hpp:264
divide.hpp
Cluster division strategies.
NiHu::fmm::cluster_tree::level_end
size_t level_end(size_t idx) const
End iterator to idx-th level clusters.
Definition: cluster_tree.hpp:274
NiHu::fmm::cluster_tree::cluster_vector_t
std::vector< cluster_t, Eigen::aligned_allocator< cluster_t > > cluster_vector_t
Type of the cluster vector.
Definition: cluster_tree.hpp:46
NiHu::fmm::cluster_tree::get_leaf_indices
const std::vector< size_t > & get_leaf_indices() const
return vector of leaf cluster indices
Definition: cluster_tree.hpp:189
NiHu::fmm::cluster_tree::get_leaf_src_index_vectors
std::vector< idx_list_t > get_leaf_src_index_vectors() const
assemble and return source leaf index vectors
Definition: cluster_tree.hpp:215
cluster.hpp
implementation of class NiHu::fmm::cluster_base
misc.hpp
miscellaneous functions and metafunctions