binary_tree.cc
Go to the documentation of this file.
1 // LIC// ====================================================================
2 // LIC// This file forms part of oomph-lib, the object-oriented,
3 // LIC// multi-physics finite-element library, available
4 // LIC// at http://www.oomph-lib.org.
5 // LIC//
6 // LIC// Copyright (C) 2006-2023 Matthias Heil and Andrew Hazel
7 // LIC//
8 // LIC// This library is free software; you can redistribute it and/or
9 // LIC// modify it under the terms of the GNU Lesser General Public
10 // LIC// License as published by the Free Software Foundation; either
11 // LIC// version 2.1 of the License, or (at your option) any later version.
12 // LIC//
13 // LIC// This library is distributed in the hope that it will be useful,
14 // LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // LIC// Lesser General Public License for more details.
17 // LIC//
18 // LIC// You should have received a copy of the GNU Lesser General Public
19 // LIC// License along with this library; if not, write to the Free Software
20 // LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 // LIC// 02110-1301 USA.
22 // LIC//
23 // LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24 // LIC//
25 // LIC//====================================================================
26 // Non-inline and non-templated functions for BinaryTree and BinaryTreeForest
27 // classes
28 
29 // Config header generated by autoconfig
30 #ifdef HAVE_CONFIG_H
31 #include <oomph-lib-config.h>
32 #endif
33 
34 #include <set>
35 
36 // oomph-lib headers
37 #include "binary_tree.h"
39 
40 namespace oomph
41 {
42  //========================================================================
43  /// Boolean indicating that static member data has been setup.
44  //========================================================================
46 
47  //========================================================================
48  /// Colours for neighbours in various directions (static data).
49  //========================================================================
50  Vector<std::string> BinaryTree::Colour;
51 
52  //========================================================================
53  /// S_base(direction): Initial value for coordinate s on the edge
54  /// indicated by direction (L/R) (static data).
55  //========================================================================
56  Vector<double> BinaryTree::S_base;
57 
58  //========================================================================
59  /// Translate (enumerated) directions into strings (static data).
60  //========================================================================
61  Vector<std::string> BinaryTree::Direct_string;
62 
63  //========================================================================
64  /// Get opposite edge, e.g. Reflect_edge[N]=S (static data)
65  //========================================================================
66  Vector<int> BinaryTree::Reflect_edge;
67 
68  //========================================================================
69  /// Array of direction/segment adjacency scheme:
70  /// Is_adjacent(i_vertex,j_segment): Is vertex adjacent to segment?
71  /// (static data)
72  //========================================================================
73  DenseMatrix<bool> BinaryTree::Is_adjacent;
74 
75  //========================================================================
76  /// Reflection scheme: Reflect(direction,segment): Get mirror of segment
77  /// in specified direction. E.g. Reflect(L,L)=R (static data)
78  //========================================================================
79  DenseMatrix<int> BinaryTree::Reflect;
80 
81  //========================================================================
82  /// Set up the static data stored in the BinaryTree -- this needs to be
83  /// called before BinaryTrees can be used. Automatically called by
84  /// RefineableLineMesh constructor.
85  //========================================================================
87  {
88  using namespace BinaryTreeNames;
89 
90 #ifdef PARANOID
92  {
93  std::ostringstream error_stream;
94  error_stream << "Inconsistent enumeration! \n Tree::OMEGA="
95  << Tree::OMEGA << "\nBinaryTree::OMEGA=" << BinaryTree::OMEGA
96  << std::endl;
97  throw OomphLibError(
98  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
99  }
100 #endif
101 
102  // Set flag to indicate that static data has been setup
104 
105  // Tecplot colours for neighbours in various directions
106  Colour.resize(27);
107 
108  Colour[L] = "RED";
109  Colour[R] = "CYAN";
110  Colour[OMEGA] = "YELLOW";
111 
112  // S_base(direction): Initial value for coordinate s on the
113  // edge indicated by direction (L/R)
114  S_base.resize(27);
115 
116  S_base[L] = -1.0;
117  S_base[R] = 1.0;
118 
119  // Translate (enumerated) directions into strings
120  Direct_string.resize(27);
121 
122  Direct_string[L] = "L";
123  Direct_string[R] = "R";
124  Direct_string[OMEGA] = "OMEGA";
125 
126  // Build direction/segment adjacency scheme:
127  // Is_adjacent(i_vertex,j_segment): Is vertex adjacent to segment?
128  Is_adjacent.resize(27, 27);
129 
130  Is_adjacent(L, L) = true;
131  Is_adjacent(R, L) = false;
132  Is_adjacent(L, R) = false;
133  Is_adjacent(R, R) = true;
134 
135  // Build reflection scheme: Reflect(direction,segment):
136  // Get mirror of segment in direction
137  Reflect.resize(27, 27);
138 
139  Reflect(L, L) = R;
140  Reflect(R, L) = R;
141  Reflect(L, R) = L;
142  Reflect(R, R) = L;
143 
144  // Get opposite edge, e.g. Reflect_edge(L)=R
145  Reflect_edge.resize(27);
146 
147  Reflect_edge[L] = R;
148  Reflect_edge[R] = L;
149  }
150 
151  //========================================================================
152  /// Return pointer to greater or equal-sized edge neighbour in specified
153  /// \c direction; also provide info regarding the relative size of the
154  /// neighbour:
155  /// - In the present binary tree, the left vertex is located at the local
156  /// coordinate s = -1. This point is located at the local coordinate
157  /// s = \c s_in_neighbour[0] in the neighbouring binary tree.
158  /// - We're looking for a neighbour in the specified \c direction. When
159  /// viewed from the neighbouring binary tree, the edge that separates
160  /// the present binary tree from its neighbour is the neighbour's
161  /// \c edge edge. Since in 1D there can be no rotation between the two
162  /// binary trees, this is a simple reflection. For instance, if we're
163  /// looking for a neighhbour in the \c L [eft] \c direction, \c edge
164  /// will be \c R [ight].
165  /// - \c diff_level <= 0 indicates the difference in refinement levels
166  /// between the two neighbours. If \c diff_level==0, the neighbour has
167  /// the same size as the current binary tree.
168  /// - \c in_neighbouring_tree returns true if we have had to flip to a
169  /// different root, even if that root is actually the same (as it can
170  /// be in periodic problems).
171  //========================================================================
173  Vector<double>& s_in_neighbour,
174  int& edge,
175  int& diff_level,
176  bool& in_neighbouring_tree) const
177  {
178  using namespace BinaryTreeNames;
179 
180 #ifdef PARANOID
181  if ((direction != L) && (direction != R))
182  {
183  std::ostringstream error_stream;
184  error_stream << "Direction " << direction << " is not L or R"
185  << std::endl;
186 
187  throw OomphLibError(
188  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
189  }
190 #endif
191 
192  // Initialise in_neighbouring tree to false. It will be set to true
193  // during the recursion if we do actually hop over into the neighbour
194  in_neighbouring_tree = false;
195 
196  // Maximum level to which we're allowed to descend (we only want
197  // greater-or-equal-sized neighbours)
198  int max_level = Level;
199 
200  // Current element has the following root:
201  BinaryTreeRoot* orig_root_pt = dynamic_cast<BinaryTreeRoot*>(Root_pt);
202 
203  // Initialise offset in local coordinate
204  double s_diff = 0;
205 
206  // Initialise difference in level
207  diff_level = 0;
208 
209  // Find neighbour
210  BinaryTree* return_pt = gteq_edge_neighbour(direction,
211  s_diff,
212  diff_level,
213  in_neighbouring_tree,
214  max_level,
215  orig_root_pt);
216 
217  BinaryTree* neighb_pt = return_pt;
218 
219  // If neighbour exists...
220  if (neighb_pt != 0)
221  {
222  // What's the direction of the interfacial edge when viewed from within
223  // the neighbour element?
224  edge = Reflect_edge[direction];
225 
226  // What's the local coordinate s at which this edge is located in the
227  // neighbouring element?
228  s_in_neighbour[0] = S_base[edge];
229  }
230  return return_pt;
231  }
232 
233  //========================================================================
234  /// Find `greater-or-equal-sized edge neighbour' in given direction (L/R).
235  ///
236  /// This is an auxiliary routine which allows neighbour finding in
237  /// adjacent binary trees. Needs to keep track of previous son types
238  /// and the maximum level to which search is performed.
239  ///
240  /// Parameters:
241  /// - direction (L/R): Direction in which neighbour has to be found.
242  /// - s_diff: Offset of left vertex from corresponding vertex in
243  /// neighbour. Note that this is input/output as it needs to be
244  /// incremented/decremented during the recursive calls to this function.
245  /// - edge: We're looking for the neighbour across our edge 'direction'
246  /// (L/R). When viewed from the neighbour, this edge is `edge' (L/R).
247  /// Since there is no relative rotation between neighbours this is a
248  /// mere reflection, e.g. direction=L --> edge=R etc.
249  /// - diff_level <= 0 indicates the difference in binary tree levels
250  /// between the current element and its neighbour.
251  /// - max_level is the maximum level to which the neighbour search is
252  /// allowed to proceed. This is again necessary because in a forest,
253  /// the neighbour search isn't based on pure recursion.
254  /// - orig_root_pt identifies the root node of the element whose
255  /// neighbour we're really trying to find by all these recursive calls.
256  //========================================================================
258  const int& direction,
259  double& s_diff,
260  int& diff_level,
261  bool& in_neighbouring_tree,
262  int max_level,
263  BinaryTreeRoot* const& orig_root_pt) const
264  {
265  using namespace BinaryTreeNames;
266 
267 #ifdef PARANOID
268  if ((direction != L) && (direction != R))
269  {
270  std::ostringstream error_stream;
271  error_stream << "Direction " << direction << " is not L or R"
272  << std::endl;
273 
274  throw OomphLibError(
275  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
276  }
277 #endif
278 
279  BinaryTree* next_el_pt;
280  BinaryTree* return_el_pt;
281 
282  // STEP 1: Find the neighbour's father
283  // -------
284 
285  // Does the element have a father?
286  if (Father_pt != 0)
287  {
288  // If the present segment (whose location inside its father element
289  // is specified by Son_type) is adjacent to the father's edge in the
290  // required direction, then its neighbour has a different father
291  // ---> we need to climb up the tree to the father and find his
292  // neighbour in the required direction. Note that this is the cunning
293  // recursive part. The returning may not stop until we hit the very
294  // top of the tree, when the element does NOT have a father.
295  if (Is_adjacent(direction, Son_type))
296  {
297  next_el_pt = dynamic_cast<BinaryTree*>(Father_pt)->gteq_edge_neighbour(
298  direction,
299  s_diff,
300  diff_level,
301  in_neighbouring_tree,
302  max_level,
303  orig_root_pt);
304  }
305  // If the present segment is not adjacent to the father's edge in the
306  // required direction, then the neighbour has the same father and is
307  // obtained by the appropriate reflection inside the father element.
308  // This will only be called if we have not left the original tree.
309  else
310  {
311  next_el_pt = dynamic_cast<BinaryTree*>(Father_pt);
312  }
313 
314  // We're about to ascend one level
315  diff_level -= 1;
316 
317  // Work out position of left corner of present edge in its father element
318  s_diff += pow(0.5, -diff_level);
319 
320  // STEP 2: We have now located the neighbour's father and need to
321  // ------- find the appropriate son.
322 
323  // Buffer cases where the neighbour (and hence its father) lie outside
324  // the boundary
325  if (next_el_pt != 0)
326  {
327  // If the father is a leaf then we can't descend to the same
328  // level as the present node ---> simply return the father himself
329  // as the (greater) neighbour. Same applies if we are about to
330  // descend lower than the max_level (in a neighbouring tree).
331  if ((next_el_pt->Son_pt.size() == 0) ||
332  (next_el_pt->Level > max_level - 1))
333  {
334  return_el_pt = next_el_pt;
335  }
336  // We have located the neighbour's father: The position of the
337  // neighbour is obtained by `reflecting' the position of the
338  // node itself. We know exactly how to reflect because we know which
339  // son type we are and we have the pointer to the neighbour's father.
340  else
341  {
342  int son_segment = Reflect(direction, Son_type);
343 
344  // The next element in the tree is the appropriate son of the
345  // neighbour's father
346  return_el_pt =
347  dynamic_cast<BinaryTree*>(next_el_pt->Son_pt[son_segment]);
348 
349  // Work out position of left corner of present edge in next
350  // higher element
351  s_diff -= pow(0.5, -diff_level);
352 
353  // We have just descended one level
354  diff_level += 1;
355  }
356  }
357  // The neighbour's father lies outside the boundary --> the neighbour
358  // itself does too --> return NULL
359  else
360  {
361  return_el_pt = 0;
362  }
363  }
364  // Element does not have a father --> check if it has a neighbouring
365  // tree in the appropriate direction
366  else
367  {
368  // Find neighbouring root
369  if (Root_pt->neighbour_pt(direction) != 0)
370  {
371  // In this case we have moved to a neighbour, so set the flag
372  in_neighbouring_tree = true;
373  return_el_pt =
374  dynamic_cast<BinaryTreeRoot*>(Root_pt->neighbour_pt(direction));
375  }
376  // No neighbouring tree, so there really is no neighbour --> return NULL
377  else
378  {
379  return_el_pt = 0;
380  }
381  }
382 
383  return return_el_pt;
384  }
385 
386  //========================================================================
387  /// Self-test: Check neighbour finding routine. For each element in the
388  /// tree and for each vertex, determine the distance between the vertex
389  /// and its position in the neighbour. If the difference is less than
390  /// Tree::Max_neighbour_finding_tolerance return success (0), otherwise
391  /// failure (1).
392  //========================================================================
394  {
395  // Stick pointers to all nodes into Vector and number elements
396  // in the process
397  Vector<Tree*> all_nodes_pt;
398  stick_all_tree_nodes_into_vector(all_nodes_pt);
399  long int count = 0;
400  unsigned long num_nodes = all_nodes_pt.size();
401  for (unsigned long i = 0; i < num_nodes; i++)
402  {
403  all_nodes_pt[i]->object_pt()->set_number(++count);
404  }
405 
406  // Check neighbours (distance between hanging nodes) -- don't print
407  // (keep output streams closed)
408  double max_error = 0.0;
409  std::ofstream neighbours_file;
410  std::ofstream neighbours_txt_file;
412  all_nodes_pt, neighbours_file, neighbours_txt_file, max_error);
413 
414  if (max_error > Max_neighbour_finding_tolerance)
415  {
416  oomph_info << "\n \n Failed self_test() for BinaryTree: Max. error "
417  << max_error << std::endl
418  << std::endl;
419  return 1;
420  }
421  else
422  {
423  oomph_info << "\n \n Passed self_test() for BinaryTree: Max. error "
424  << max_error << std::endl
425  << std::endl;
426  return 0;
427  }
428  }
429 
430 
431  //========================================================================
432  /// Constructor for BinaryTreeForest:
433  ///
434  /// Pass:
435  /// - trees_pt[], the Vector of pointers to the constituent trees
436  /// (BinaryTreeRoot objects)
437  //========================================================================
439  : TreeForest(trees_pt)
440  {
441 #ifdef LEAK_CHECK
442  LeakCheckNames::BinaryTreeForest_build += 1;
443 #endif
444 
445  using namespace BinaryTreeNames;
446 
447  // Set up the neighbours
448  find_neighbours();
449  }
450 
451  //========================================================================
452  /// Set up the neighbour lookup schemes for all constituent binary trees.
453  //========================================================================
455  {
456  using namespace BinaryTreeNames;
457 
458  unsigned numtrees = ntree();
459  unsigned n = 0; // to store nnode1d
460  if (numtrees > 0)
461  {
462  n = Trees_pt[0]->object_pt()->nnode_1d();
463  }
464  else
465  {
466  throw OomphLibError(
467  "Trying to setup the neighbour scheme for an empty forest\n",
468  OOMPH_CURRENT_FUNCTION,
469  OOMPH_EXCEPTION_LOCATION);
470  }
471 
472  // Number of vertex nodes: 2
473  unsigned n_vertex_node = 2;
474 
475  // Find connected trees by identifying those whose associated elements
476  // share a common vertex node
477  std::map<Node*, std::set<unsigned>> tree_assoc_with_vertex_node;
478 
479  // Loop over all trees
480  for (unsigned i = 0; i < numtrees; i++)
481  {
482  // Loop over the vertex nodes of the associated element
483  for (unsigned j = 0; j < n_vertex_node; j++)
484  {
485  Node* nod_pt = dynamic_cast<LineElementBase*>(Trees_pt[i]->object_pt())
486  ->vertex_node_pt(j);
487  tree_assoc_with_vertex_node[nod_pt].insert(i);
488  }
489  }
490 
491  // For each tree we store a set of neighbouring trees
492  // i.e. trees that share a node
493  Vector<std::set<unsigned>> neighb_tree(numtrees);
494 
495  // Loop over vertex nodes
496  for (std::map<Node*, std::set<unsigned>>::iterator it =
497  tree_assoc_with_vertex_node.begin();
498  it != tree_assoc_with_vertex_node.end();
499  it++)
500  {
501  // Loop over connected elements twice
502  for (std::set<unsigned>::iterator it_el1 = it->second.begin();
503  it_el1 != it->second.end();
504  it_el1++)
505  {
506  unsigned i = (*it_el1);
507  for (std::set<unsigned>::iterator it_el2 = it->second.begin();
508  it_el2 != it->second.end();
509  it_el2++)
510  {
511  unsigned j = (*it_el2);
512  // These two elements are connected
513  if (i != j)
514  {
515  neighb_tree[i].insert(j);
516  }
517  }
518  }
519  }
520 
521  // Loop over all trees
522  for (unsigned i = 0; i < numtrees; i++)
523  {
524  // Loop over their neighbours
525  for (std::set<unsigned>::iterator it = neighb_tree[i].begin();
526  it != neighb_tree[i].end();
527  it++)
528  {
529  unsigned j = (*it);
530 
531  // is it the left-hand neighbour?
532  bool is_L_neighbour = Trees_pt[j]->object_pt()->get_node_number(
533  Trees_pt[i]->object_pt()->node_pt(0)) != -1;
534 
535  // is it the right-hand neighbour?
536  bool is_R_neighbour = Trees_pt[j]->object_pt()->get_node_number(
537  Trees_pt[i]->object_pt()->node_pt(n - 1)) != -1;
538 
539  if (is_L_neighbour) Trees_pt[i]->neighbour_pt(L) = Trees_pt[j];
540  if (is_R_neighbour) Trees_pt[i]->neighbour_pt(R) = Trees_pt[j];
541  }
542  } // End of loop over all trees
543  }
544 
545  //========================================================================
546  /// Document and check all the neighbours in all the nodes in the forest.
547  //========================================================================
549  {
550  // Create Vector of elements
551  Vector<Tree*> all_tree_nodes_pt;
552  this->stick_all_tree_nodes_into_vector(all_tree_nodes_pt);
553 
554  // Create storage for information files
555  std::ofstream neigh_file;
556  std::ofstream neigh_txt_file;
557 
558  // If we are documenting the results, then open the files
559  if (doc_info.is_doc_enabled())
560  {
561  std::ostringstream fullname;
562  fullname << doc_info.directory() << "/neighbours" << doc_info.number()
563  << ".dat";
564  oomph_info << "opened " << fullname.str() << " to doc neighbours"
565  << std::endl;
566  neigh_file.open(fullname.str().c_str());
567  fullname.str("");
568  fullname << doc_info.directory() << "/neighbours" << doc_info.number()
569  << ".txt";
570  oomph_info << "opened " << fullname.str() << " to doc neighbours"
571  << std::endl;
572  neigh_txt_file.open(fullname.str().c_str());
573  }
574 
575  // Call the standard documentation function
576  double max_error = 0.0;
578  all_tree_nodes_pt, neigh_file, neigh_txt_file, max_error);
579 
580  // If the error is too large, complain
581  if (max_error > Tree::max_neighbour_finding_tolerance())
582  {
583  std::ostringstream error_stream;
584  error_stream << "Max. error in binary tree neighbour finding: "
585  << max_error << " is too big" << std::endl;
586  error_stream
587  << "i.e. bigger than Tree::max_neighbour_finding_tolerance()="
588  << Tree::max_neighbour_finding_tolerance() << std::endl;
589 
590  // Close the files if they were opened
591  if (doc_info.is_doc_enabled())
592  {
593  neigh_file.close();
594  neigh_txt_file.close();
595  }
596 
597  throw OomphLibError(
598  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
599  }
600  else
601  {
602  oomph_info << "Max. error in binary tree neighbour finding: " << max_error
603  << " is OK" << std::endl;
604  oomph_info
605  << "i.e. less than BinaryTree::max_neighbour_finding_tolerance()="
607  }
608 
609  // Close the files if they were opened
610  if (doc_info.is_doc_enabled())
611  {
612  neigh_file.close();
613  neigh_txt_file.close();
614  }
615  }
616 
617  //========================================================================
618  /// Self test: Check neighbour finding routine. For each element in the
619  /// tree and for each vertex, determine the distance between the vertex
620  /// and its position in the neighbour. If the difference is less than
621  /// Tree::Max_neighbour_finding_tolerance return success (0), otherwise
622  /// failure (1).
623  //========================================================================
625  {
626  // Stick pointers to all nodes into Vector and number elements
627  // in the process
628  Vector<Tree*> all_forest_nodes_pt;
629  stick_all_tree_nodes_into_vector(all_forest_nodes_pt);
630  long int count = 0;
631  unsigned long num_nodes = all_forest_nodes_pt.size();
632  for (unsigned long i = 0; i < num_nodes; i++)
633  {
634  all_forest_nodes_pt[i]->object_pt()->set_number(++count);
635  }
636 
637  // Check neighbours (distance between hanging nodes) -- don't print
638  // (keep output streams closed)
639  double max_error = 0.0;
640  std::ofstream neighbours_file;
641  std::ofstream neighbours_txt_file;
643  all_forest_nodes_pt, neighbours_file, neighbours_txt_file, max_error);
645  {
646  oomph_info << "\n \n Failed self_test() for BinaryTree: Max. error "
647  << max_error << std::endl
648  << std::endl;
649  return 1;
650  }
651  else
652  {
653  oomph_info << "\n \n Passed self_test() for BinaryTree: Max. error "
654  << max_error << std::endl
655  << std::endl;
656  return 0;
657  }
658  }
659 
660  //========================================================================
661  /// Doc/check all neighbours of binary tree ("nodes") contained in the
662  /// Vector forest_node_pt. Output into neighbours_file which can be viewed
663  /// from tecplot with BinaryTreeNeighbours.mcr. Neighbour info and errors
664  /// are displayed on neighbours_txt_file. Finally, compute the maximum
665  /// error between vertices when viewed from neighbouring element. Output
666  /// is suppressed if the output streams are closed.
667  //========================================================================
669  std::ofstream& neighbours_file,
670  std::ofstream& neighbours_txt_file,
671  double& max_error)
672  {
673  using namespace BinaryTreeNames;
674 
675  int diff_level;
676  double s_diff;
677  bool in_neighbouring_tree;
678  int edge = OMEGA;
679 
680  Vector<double> s(1);
681  Vector<double> x(1);
682  Vector<int> prev_son_type;
683 
684  Vector<double> s_in_neighbour(1);
685 
686  Vector<double> x_small(1);
687  Vector<double> x_large(1);
688 
689  // Initialise error in vertex positions
690  max_error = 0.0;
691 
692  // Loop over all elements to assign numbers for plotting
693  // -----------------------------------------------------
694  unsigned long num_nodes = forest_nodes_pt.size();
695  for (unsigned long i = 0; i < num_nodes; i++)
696  {
697  // Set number
698  forest_nodes_pt[i]->object_pt()->set_number(i);
699  }
700 
701  // Loop over all elements for checks
702  // ---------------------------------
703  for (unsigned long i = 0; i < num_nodes; i++)
704  {
705  // Doc the element itself
706  BinaryTree* el_pt = dynamic_cast<BinaryTree*>(forest_nodes_pt[i]);
707 
708  // If the object is incomplete, complain
709  if (el_pt->object_pt()->nodes_built())
710  {
711  // Print it
712  if (neighbours_file.is_open())
713  {
714  dynamic_cast<RefineableQElement<1>*>(el_pt->object_pt())
715  ->output_corners(neighbours_file, "BLACK");
716  }
717 
718  // Loop over directions to find neighbours
719  // ---------------------------------------
720  for (int direction = L; direction <= R; direction++)
721  {
722  // Initialise difference in levels and coordinate offset
723  diff_level = 0;
724  s_diff = 0.0;
725 
726  // Find greater-or-equal-sized neighbour...
727  BinaryTree* neighb_pt = el_pt->gteq_edge_neighbour(
728  direction, s_in_neighbour, edge, diff_level, in_neighbouring_tree);
729 
730  // If neighbour exist and nodes are created: Doc it
731  if ((neighb_pt != 0) && (neighb_pt->object_pt()->nodes_built()))
732  {
733  // Doc neighbour stats
734  if (neighbours_txt_file.is_open())
735  {
736  neighbours_txt_file
737  << Direct_string[direction] << " neighbour of "
738  << el_pt->object_pt()->number() << " is "
739  << neighb_pt->object_pt()->number() << " diff_level "
740  << diff_level << " s_diff " << s_diff
741  << " inside neighbour the edge is " << Direct_string[edge]
742  << std::endl
743  << std::endl;
744  }
745 
746  // Plot neighbour in the appropriate colour
747  if (neighbours_file.is_open())
748  {
749  dynamic_cast<RefineableQElement<1>*>(neighb_pt->object_pt())
750  ->output_corners(neighbours_file, Colour[direction]);
751  }
752 
753  // Check that local coordinates in the larger element (obtained
754  // via s_diff) lead to the same spatial point as the node vertices
755  // in the current element
756  {
757  if (neighbours_file.is_open())
758  {
759  neighbours_file << "ZONE I=1 \n";
760  }
761 
762  // Left vertex:
763  // ------------
764 
765  // Get coordinates in large (neighbour) element
766  s[0] = s_in_neighbour[0];
767  neighb_pt->object_pt()->get_x(s, x_large);
768 
769  // Get coordinates in small element
770  Vector<double> s(1);
771  s[0] = S_base[direction];
772  el_pt->object_pt()->get_x(s, x_small);
773 
774  // Need to exclude periodic nodes from this check. There can
775  // only be periodic nodes if we have moved into the neighbour
776  bool is_periodic = false;
777  if (in_neighbouring_tree)
778  {
779  // Is the node periodic?
780  is_periodic =
781  el_pt->root_pt()->is_neighbour_periodic(direction);
782  }
783 
784  double error = 0.0;
785  // Only bother to calculate the error if the node is NOT periodic
786  if (is_periodic == false)
787  {
788  error += pow(x_small[0] - x_large[0], 2);
789  }
790 
791  // Take the root of the square error
792  error = sqrt(error);
793  if (neighbours_txt_file.is_open())
794  {
795  neighbours_txt_file << "Error (1) " << error << std::endl;
796  }
797 
798  if (std::fabs(error) > max_error)
799  {
800  max_error = std::fabs(error);
801  }
802 
803  if (neighbours_file.is_open())
804  {
805  neighbours_file << x_large[0] << " 0 \n";
806  }
807 
808  // Right vertex:
809  // -------------
810 
811  // Get coordinates in large (neighbour) element
812  s[0] = s_in_neighbour[0];
813  neighb_pt->object_pt()->get_x(s, x_large);
814 
815  // Get coordinates in small element
816  s[0] = S_base[direction];
817  el_pt->object_pt()->get_x(s, x_small);
818 
819  error = 0.0;
820  // Only do this if we are NOT periodic
821  if (is_periodic == false)
822  {
823  error += pow(x_small[0] - x_large[0], 2);
824  }
825  // Take the root of the square error
826  error = sqrt(error);
827 
828  // error =
829  // sqrt(pow(x_small[0]-x_large[0],2)+pow(x_small[1]-x_large[1],2));
830  if (neighbours_txt_file.is_open())
831  {
832  neighbours_txt_file << "Error (2) " << error << std::endl;
833  }
834 
835  if (std::fabs(error) > max_error)
836  {
837  max_error = std::fabs(error);
838  }
839 
840  if (neighbours_file.is_open())
841  {
842  neighbours_file << x_large[0] << " 0 \n";
843  }
844  }
845  // else
846  // {
847  // // No neighbour: write dummy zone so tecplot can find
848  // four
849  // // neighbours for every element
850  // if (neighbours_file.is_open())
851  // {
852  // neighbours_file << "ZONE I=1 \n";
853  // neighbours_file << "-0.05 -0.05 0 \n";
854  // neighbours_file << "-0.05 -0.05 0 \n";
855  // }
856  // }
857  }
858  // If neighbour does not exist: Insert blank zones into file
859  // so that tecplot can find four neighbours for every element
860  else
861  {
862  if (neighbours_file.is_open())
863  {
864  neighbours_file << "ZONE \n 0.00 0 \n";
865  neighbours_file << "ZONE I=1 \n";
866  neighbours_file << "-0.05 0 \n";
867  neighbours_file << "-0.05 0 \n";
868  }
869  }
870  }
871  } // End of case when element can be documented
872  }
873  }
874 
875 } // namespace oomph
static char t char * s
Definition: cfortran.h:568
cstr elem_len * i
Definition: cfortran.h:603
void find_neighbours()
Construct the neighbour lookup scheme.
Definition: binary_tree.cc:454
BinaryTreeForest()
Default constructor (empty and broken)
Definition: binary_tree.h:289
void check_all_neighbours(DocInfo &doc_info)
Document and check all the neighbours of all the nodes in the forest. DocInfo object specifies the ou...
Definition: binary_tree.cc:548
unsigned self_test()
Self-test: Check all neighbours. Return success (0) if the maximum distance between corresponding poi...
Definition: binary_tree.cc:624
BinaryTreeRoot is a BinaryTree that forms the root of a (recursive) binary tree. The "root node" is s...
Definition: binary_tree.h:231
BinaryTree class: Recursively defined, generalised binary tree.
Definition: binary_tree.h:92
static Vector< double > S_base
S_base(direction): Initial value for coordinate s on the edge indicated by direction (L/R)
Definition: binary_tree.h:210
static Vector< std::string > Colour
Colours for neighbours in various directions.
Definition: binary_tree.h:206
static Vector< std::string > Direct_string
Translate (enumerated) directions into strings.
Definition: binary_tree.h:162
static void setup_static_data()
Set up the static data, reflection schemes, etc.
Definition: binary_tree.cc:86
static void doc_neighbours(Vector< Tree * > forest_nodes_pt, std::ofstream &neighbours_file, std::ofstream &neighbours_txt_file, double &max_error)
Doc/check all neighbours of binary tree (nodes) contained in the Vector forest_node_pt....
Definition: binary_tree.cc:668
static bool Static_data_has_been_setup
Boolean indicating that static member data has been setup.
Definition: binary_tree.h:193
static DenseMatrix< int > Reflect
Reflection scheme: Reflect(direction,segment): Get mirror of segment in specified direction....
Definition: binary_tree.h:221
BinaryTree * gteq_edge_neighbour(const int &direction, Vector< double > &s_in_neighbour, int &edge, int &diff_level, bool &in_neighbouring_tree) const
Return pointer to greater or equal-sized edge neighbour in specified direction; also provide info reg...
Definition: binary_tree.cc:172
unsigned self_test()
Self-test: Check all neighbours. Return success (0) if the maximum distance between corresponding poi...
Definition: binary_tree.cc:393
static DenseMatrix< bool > Is_adjacent
Array of direction/segment adjacency scheme: Is_adjacent(i_vertex,j_segment): Is vertex adjacent to s...
Definition: binary_tree.h:217
static Vector< int > Reflect_edge
Get opposite edge, e.g. Reflect_edge[L]=R.
Definition: binary_tree.h:213
void resize(const unsigned long &n)
Resize to a square nxn matrix; any values already present will be transfered.
Definition: matrices.h:498
Information for documentation of results: Directory and file number to enable output in the form RESL...
bool is_doc_enabled() const
Are we documenting?
std::string directory() const
Output directory.
unsigned & number()
Number used (e.g.) for labeling output files.
void get_x(const Vector< double > &s, Vector< double > &x) const
Global coordinates as function of local coordinates. Either via FE representation or via macro-elemen...
Definition: elements.h:1885
Base class for all line elements.
Definition: Qelements.h:466
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition: nodes.h:906
An OomphLibError object which should be thrown when an run-time error is encountered....
long number() const
Element number (for debugging/plotting)
virtual bool nodes_built()
Return true if all the nodes have been built, false if not.
Refineable version of QElement<1,NNODE_1D>.
A TreeForest consists of a collection of TreeRoots. Each member tree can have neighbours in various e...
Definition: tree.h:409
void stick_all_tree_nodes_into_vector(Vector< Tree * > &all_forest_nodes)
Traverse forest and stick pointers to all "nodes" into Vector.
Definition: tree.cc:405
unsigned ntree()
Number of trees in forest.
Definition: tree.h:460
Vector< TreeRoot * > Trees_pt
Vector containing the pointers to the trees.
Definition: tree.h:480
bool is_neighbour_periodic(const int &direction)
Return whether the neighbour in the particular direction is periodic.
Definition: tree.h:364
TreeRoot *& neighbour_pt(const int &direction)
Return the pointer to the neighbouring TreeRoots in specified direction. Returns NULL if there's no n...
Definition: tree.h:357
Tree * Father_pt
Pointer to the Father of the Tree.
Definition: tree.h:296
void stick_all_tree_nodes_into_vector(Vector< Tree * > &)
Traverse and stick pointers to all "nodes" into Vector.
Definition: tree.cc:277
RefineableElement * object_pt() const
Return the pointer to the object (RefineableElement) represented by the tree.
Definition: tree.h:88
TreeRoot * Root_pt
Pointer to the root of the tree.
Definition: tree.h:292
int Son_type
Son type (e.g. SW/SE/NW/NE in a quadtree)
Definition: tree.h:305
int Level
Level of the Tree (level 0 = root)
Definition: tree.h:302
static const int OMEGA
Default value for an unassigned neighbour.
Definition: tree.h:262
Vector< Tree * > Son_pt
Vector of pointers to the sons of the Tree.
Definition: tree.h:299
TreeRoot *& root_pt()
Return pointer to root of the tree.
Definition: tree.h:141
static double Max_neighbour_finding_tolerance
Max. allowed discrepancy in neighbour finding routine (distance between points when identified from t...
Definition: tree.h:313
static double & max_neighbour_finding_tolerance()
Max. allowed discrepancy in neighbour finding routine (distance between points when identified from t...
Definition: tree.h:255
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
OomphInfo oomph_info
Single (global) instantiation of the OomphInfo object – this is used throughout the library as a "rep...