Interface Documentation
Version: invalid
interface.hh
Go to the documentation of this file.
1 /*
2  @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@
3  /@@///// /@@ @@////@@ @@////// /@@
4  /@@ /@@ @@@@@ @@ // /@@ /@@
5  /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@
6  /@@//// /@@/@@@@@@@/@@ ////////@@/@@
7  /@@ /@@/@@//// //@@ @@ /@@/@@
8  /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@
9  // /// ////// ////// //////// //
10 
11  Copyright (c) 2016, Triad National Security, LLC
12  All rights reserved.
13  */
14 #pragma once
15 
18 #if !defined(__FLECSI_PRIVATE__)
19 #error Do not include this file directly!
20 #endif
21 #include "flecsi/data/privilege.hh"
22 #include "flecsi/topo/core.hh" // base
24 #include "flecsi/topo/ntree/geometry.hh"
27 
28 #include <fstream>
29 #include <iostream>
30 #include <stack>
31 #include <type_traits>
32 #include <unordered_map>
33 
34 namespace flecsi {
35 namespace topo {
36 
37 //----------------------------------------------------------------------------//
38 // NTree topology.
39 //----------------------------------------------------------------------------//
40 
45 //-----------------------------------------------------------------//
48 //-----------------------------------------------------------------//
49 template<typename POLICY_TYPE>
50 struct ntree : ntree_base {
51  template<std::size_t>
52  struct access;
53 
54  ntree(const coloring &) {}
55 };
56 
57 template<class Policy>
58 template<std::size_t Priv>
59 struct ntree<Policy>::access {
60  static constexpr bool Write = privilege_write(Priv);
61 
62  // tree storage type definition
64  // entity ID type
65  using id_t = util::id_t;
66  // offset type use by connectivities to give offsets and counts
67  using offset_t = util::offset_t;
68 
69  // ------- Basic declarations: types and subtypes
70  static constexpr size_t dimension = Policy::dimension;
71  using element_t = typename Policy::element_t;
73  using range_t = std::array<point_t, 2>;
74  // ------- Space filling curve
75  using key_t = typename Policy::key_t;
76  // ------- Tree topology
77  using node_t = typename Policy::node_t;
78  using tree_entity_t = typename Policy::tree_entity_t;
79  using entity_t = typename Policy::entity_t;
80  using entity_id_t = typename entity_base<0>::id_t;
82 
83  storage_t nts_;
84 
89  access() {
90  max_depth_ = 0;
91  // Init the new storage, for now without handler
92  // Add the root in the node_map_
93  node_map_.emplace(key_t::root(), key_t::root());
94  root_ = node_map_.find(key_t::root());
95  assert(root_ != node_map_.end());
96  }
97 
103  void set_range(const range_t & range) {
104  range_ = range;
105  }
106 
111  template<class... S, class = std::enable_if_t<Write>>
112  entity_t * make_entity(S &&... args) {
113  return nts_.template make_entity(std::forward<S>(args)...);
114  }
115 
119  void generate_keys() {
120  for(auto & ent : *(nts_.entity_index_space.storage())) {
121  ent.set_key(key_t(range_, ent.coordinates()));
122  }
123  }
124 
128  void sort_entities() {
129  // See how
130  }
131 
135  node_t * root() {
136  return root_; // base_t::nts_->node_index_space.storage()->begin() +
137  // root_id_;
138  }
139 
144  template<class... S, class = std::enable_if_t<Write>>
145  entity_t * make_tree_entity(S &&... args) {
146  return nts_.template make_tree_entity(std::forward<S>(args)...);
147  }
148 
153  void build_tree() {
154  for(auto & ent : *(nts_.entity_index_space.storage())) {
155  insert(ent);
156  }
157  }
158 
163  void insert(entity_t & ent) {
164  // Find parent closest of the entity
165  key_t node_key = ent.key();
166  node_t * parent = find_parent(node_key);
167  assert(parent != nullptr);
168 
169  // It is not a leaf, need to insert intermediate node
170  if(!parent->is_leaf()) {
171  // Create the missing node
172  int depth = parent->key().depth() + 1;
173  node_key.truncate(depth);
174  int bit = node_key.last_value();
175  parent->add_bit_child(bit);
176 
177  // Insert this node and reinsert
178  node_map_.emplace_back(node_key, node_key);
179  auto * new_parent = &(node_map_.find(node_key)->second);
180  new_parent->set_leaf(true);
181  new_parent->insert(ent.global_id());
182  }
183  else {
184  // Conflict with a children
185  if(parent->size() == (1 << dimension)) {
186  refine_(parent);
187  insert(ent);
188  }
189  else {
190  parent->insert(ent.global_id());
191  }
192  }
193  parent = find_parent(node_key);
194  }
195 
199  entity_t & get(const entity_id_t & id) {
200  return *(nts_.entity_index_space.storage()->begin() + id.entity());
201  }
202 
206  node_t * find_parent(key_t key) {
207  key.truncate(max_depth_);
208  while(key != root()->key()) {
209  auto br = &(node_map_.find(key)->second);
210  if(br != nullptr) {
211  return br;
212  }
213  key.pop();
214  }
215  return root();
216  }
217 
221  void cofm(node_t * b = nullptr, bool local = false) {
222  if(b == nullptr)
223  b = root();
224  // Find the sub particles on which we want to work
225  std::vector<node_t *> working_branches;
226  std::stack<node_t *> stk_remaining;
227  int level = 5;
228  std::stack<node_t *> stk;
229  stk.push(b);
230  while(!stk.empty()) {
231  node_t * c = stk.top();
232  int cur_level = c->key().depth();
233  stk.pop();
234  if(c->is_leaf()) {
235  working_branches.push_back(c);
236  }
237  else {
238  if(cur_level == level) {
239  working_branches.push_back(c);
240  }
241  else {
242  stk_remaining.push(c);
243  for(int i = (1 << dimension) - 1; i >= 0; --i) {
244  if(!c->as_child(i))
245  continue;
246  auto next = child_(c, i);
247  assert(next != nullptr);
248  stk.push(next);
249  }
250  }
251  }
252  }
253 
254  // Work in parallel on the sub branches
255  const int nwork = working_branches.size();
256 
257 #ifdef _OPENMP
258 #pragma omp parallel for
259 #endif
260  for(int b = 0; b < nwork; ++b) {
261  // Find the leave in order in these sub branches
262  std::stack<node_t *> stk1;
263  std::stack<node_t *> stk2;
264  stk1.push(working_branches[b]);
265  while(!stk1.empty()) {
266  node_t * cur = stk1.top();
267  stk1.pop();
268  stk2.push(cur);
269  // Push children to stk1
270  if(!cur->is_leaf()) {
271  for(int i = 0; i < (1 << dimension); ++i) {
272  if(!cur->as_child(i))
273  continue;
274  node_t * next = child_(cur, i);
275  stk1.push(next);
276  }
277  }
278  }
279  // Finish the highest part of the tree in serial
280  while(!stk2.empty()) {
281  node_t * cur = stk2.top();
282  stk2.pop();
283  update_COM(cur, local);
284  }
285  }
286  // Finish the high part of the tree on one thread
287  while(!stk_remaining.empty()) {
288  node_t * cur = stk_remaining.top();
289  stk_remaining.pop();
290  update_COM(cur, local);
291  }
292  }
293 
297  void update_COM(node_t * b, bool /*local_only*/ = false) {
298  // Starting branch
299  element_t mass = 0;
300  point_t bmax{}, bmin{};
301  point_t coordinates{};
302  uint64_t nchildren = 0;
303  int owner = b->owner();
304  for(size_t d = 0; d < dimension; ++d) {
305  bmax[d] = -DBL_MAX;
306  bmin[d] = DBL_MAX;
307  }
308  if(b->is_leaf()) {
309  // For local branches, compute the radius
310  for(auto child : *b) {
311  auto ent = get(child);
312  owner = ent.owner();
313  ++nchildren;
314  element_t childmass = ent.mass();
315  for(size_t d = 0; d < dimension; ++d) {
316  bmax[d] = std::max(bmax[d], ent.coordinates()[d] + ent.radius() / 2.);
317  bmin[d] = std::min(bmin[d], ent.coordinates()[d] - ent.radius() / 2.);
318  }
319  coordinates += childmass * ent.coordinates();
320  mass += childmass;
321  }
322  if(mass > element_t(0))
323  coordinates /= mass;
324  }
325  else {
326  for(int i = 0; i < (1 << dimension); ++i) {
327  auto node = child_(b, i);
328  if(node == nullptr)
329  continue;
330  nchildren += node->sub_entities();
331  mass += node->mass();
332  if(node->mass() > 0) {
333  for(size_t d = 0; d < dimension; ++d) {
334  bmax[d] = std::max(bmax[d], node->bmax()[d]);
335  bmin[d] = std::min(bmin[d], node->bmin()[d]);
336  }
337  }
338  coordinates += node->mass() * node->coordinates();
339  }
340  if(mass > element_t(0))
341  coordinates /= mass;
342  }
343  b->set_sub_entities(nchildren);
344  b->set_coordinates(coordinates);
345  b->set_mass(mass);
346  b->set_bmin(bmin);
347  b->set_bmax(bmax);
348  assert(nchildren != 0);
349  }
350 
356  void graphviz(int num) {
357  flog(trace) << " outputing tree file #" << num << std::endl;
358 
359  char fname[64];
360  sprintf(fname, "output_graphviz_%02d.gv", num);
361  std::ofstream output;
362  output.open(fname);
363  output << "digraph G {" << std::endl << "forcelabels=true;" << std::endl;
364 
365  // Add the legend
366  output << "node [label=\"node\" xlabel=\"sub_entities,owner,requested,"
367  "ghosts_local\"]"
368  << std::endl;
369 
370  std::stack<node_t *> stk;
371  // Get root
372  auto rt = root();
373  stk.push(rt);
374 
375  while(!stk.empty()) {
376  node_t * cur = stk.top();
377  stk.pop();
378  if(!cur->is_leaf()) {
379  output << cur->key() << " [label=\"" << cur->key() << "\", xlabel=\""
380  << cur->sub_entities() << " - " << cur->owner() << " - "
381  << cur->requested() << " - " << cur->ghosts_local() << "\"];"
382  << std::endl;
383  switch(cur->locality()) {
384  case 1:
385  output << cur->key() << " [shape=circle,color=blue]" << std::endl;
386  break;
387  case 2:
388  output << cur->key() << " [shape=circle,color=red]" << std::endl;
389  break;
390  case 3:
391  output << cur->key() << " [shape=circle,color=green]" << std::endl;
392  break;
393  default:
394  output << cur->key() << " [shape=circle,color=black]" << std::endl;
395  break;
396  }
397 
398  // Add the child to the stack and add for display
399  for(size_t i = 0; i < (1 << dimension); ++i) {
400  auto br = child_(cur, i);
401  if(br == nullptr)
402  continue;
403  stk.push(br);
404  output << std::oct << cur->key() << "->" << br->key() << std::dec
405  << std::endl;
406  }
407  }
408  else {
409  output << cur->key() << " [label=\"" << cur->key() << "\", xlabel=\""
410  << cur->sub_entities() << " - " << cur->owner() << " - "
411  << cur->requested() << " - " << cur->ghosts_local() << "\"];"
412  << std::endl;
413  switch(cur->locality()) {
414  case 1:
415  output << cur->key() << " [shape=circle,color=blue]" << std::endl;
416  break;
417  case 2:
418  output << cur->key() << " [shape=circle,color=red]" << std::endl;
419  break;
420  case 3:
421  output << cur->key() << " [shape=circle,color=green]" << std::endl;
422  break;
423  default:
424  output << cur->key() << " [shape=circle,color=black]" << std::endl;
425  break;
426  }
427  for(auto ent : *cur) {
428  auto e = get(ent);
429  key_t key = e.key();
430  key.truncate(max_depth_ + 2);
431  output << key << " [label=\"" << key << "\", xlabel=\"" << e.owner()
432  << " - " << e.global_id().entity() << "\"];" << std::endl;
433 
434  output << cur->key() << "->" << key << std::endl;
435  switch(e.locality()) {
436  case 0:
437  output << key << " [shape=box,color=black]" << std::endl;
438  break;
439  case 1:
440  output << key << " [shape=box,color=red]" << std::endl;
441  break;
442  case 2:
443  output << key << " [shape=box,color=green]" << std::endl;
444  break;
445  default:
446  output << key << " [shape=circle,color=black]" << std::endl;
447  break;
448  }
449  output << std::dec;
450  }
451  }
452  }
453  output << "}" << std::endl;
454  output.close();
455  }
456 
457 private:
461  node_t * child_(node_t * b, const int & i) {
462  key_t key = b->key();
463  key.push(i);
464  return &(node_map_.find(key)->second);
465  }
466 
470  void refine_(node_t * b) {
471  key_t pid = b->key();
472  size_t depth = pid.depth() + 1;
473  // For every children
474  char bit_child = 0;
475  for(auto ent : *b) {
476  key_t k = get(ent).key();
477  k.truncate(depth);
478  bit_child |= 1 << k.last_value();
479  node_map_.emplace_back(k, k);
480  }
481  max_depth_ = std::max(max_depth_, depth);
482  for(auto ent : *b) {
483  insert(get(ent));
484  }
485  b->set_leaf(false);
486  b->clear();
487  b->set_bit_child(bit_child);
488  }
489 
490  size_t max_depth_;
491  range_t range_;
492 
493  // Hasher for the node id used in the unordered_map data structure
494  template<class K>
495  struct node_key_hasher__ {
496  size_t operator()(const K & k) const noexcept {
497  return k.value() & ((1 << 22) - 1);
498  }
499  };
500  std::unordered_map<key_t, node_t, node_key_hasher__<key_t>> node_map_;
501  typename std::unordered_map<key_t, node_t, node_key_hasher__<key_t>>::iterator
502  root_;
503 
504  friend std::ostream & operator<<(std::ostream & os, const access & t) {
505  os << "Tree: range: " << t.range_[0] << "-" << t.range_[1];
506  return os;
507  }
508 };
509 
510 template<>
512  using type = ntree_base;
513 };
514 
515 } // namespace topo
516 } // namespace flecsi
node_t * root()
Definition: interface.hh:135
entity_t * make_tree_entity(S &&... args)
Construct a new tree entity. The tree entity&#39;s constructor should not be called directly.
Definition: interface.hh:145
void sort_entities()
Sort the entities present in the tree.
Definition: interface.hh:128
Definition: id.hh:36
void insert(entity_t &ent)
Insert a particle in the tree. Search for the nearest parent and refine if necessary.
Definition: interface.hh:163
void generate_keys()
Make the keys for all the enities present in the tree.
Definition: interface.hh:119
#define flog(severity)
Definition: flog.hh:136
offset represents an offset range (a start index plus a count of elements) in a single uint64_t...
Definition: offset.hh:34
entity_t * make_entity(S &&... args)
Construct a new entity. The entity&#39;s constructor should not be called directly.
Definition: interface.hh:112
Definition: coloring.hh:33
Definition: coloring.hh:31
std::ostream & operator<<(std::ostream &ostr, const filling_curve< D, T, DER > &k)
output for filling_curve using output_ function defined in the class
Definition: filling_curve.hh:206
Definition: core.hh:40
Definition: interface.hh:52
node_t * find_parent(key_t key)
Find the closest parent of a key.
Definition: interface.hh:206
void set_range(const range_t &range)
Set the range of the current domain. This range is the same among all the processes and is used to co...
Definition: interface.hh:103
storage_t * storage()
Return the storage object.
Definition: index_space.hh:627
Definition: dimensioned_array.hh:58
Definition: interface.hh:50
access()
Definition: interface.hh:89
void graphviz(int num)
Output the tree topology in a file The format is graphviz and can be converted to PDF with dot dot -T...
Definition: interface.hh:356
void build_tree()
Build the tree topology in the node_map_, insert all the local particles of the tree in a serial way...
Definition: interface.hh:153
Definition: geometry.hh:45
void cofm(node_t *b=nullptr, bool local=false)
Compute the cofm data for the tree using double stack.
Definition: interface.hh:221
Definition: control.hh:31
void update_COM(node_t *b, bool=false)
Compute the COFM information for a dedicated branch.
Definition: interface.hh:297