octree.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-2025 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#include <algorithm>
27
28#include "octree.h"
30
31namespace oomph
32{
33 //========================================================================
34 /// Bool indicating that static member data has been setup
35 //========================================================================
37
38
39 // Public static member data:
40 //---------------------------
41
42 //====================================================================
43 /// Translate (enumerated) directions into strings
44 //====================================================================
45 Vector<std::string> OcTree::Direct_string;
46
47 //====================================================================
48 /// Get opposite face, e.g. Reflect_face[L]=R
49 //====================================================================
50 Vector<int> OcTree::Reflect_face;
51
52 //====================================================================
53 /// Get opposite edge, e.g. Reflect_edge[DB]=UF
54 //====================================================================
55 Vector<int> OcTree::Reflect_edge;
56
57 //====================================================================
58 /// Get opposite vertex, e.g. Reflect_vertex[LDB]=RUF
59 //====================================================================
60 Vector<int> OcTree::Reflect_vertex;
61
62 //====================================================================
63 /// Map of vectors containing the two vertices for each edge
64 //====================================================================
65 Vector<Vector<int>> OcTree::Vertex_at_end_of_edge;
66
67 //====================================================================
68 /// Map storing the information to translate a vector of directions
69 /// (in the three coordinate directions) into a direction
70 //====================================================================
71 std::map<Vector<int>, int> OcTree::Vector_to_direction;
72
73 //====================================================================
74 /// Vector storing the information to translate a direction into a
75 /// vector of directions (in the three coordinate directions)
76 //====================================================================
77 Vector<Vector<int>> OcTree::Direction_to_vector;
78
79 //====================================================================
80 /// Storage for the up/right-equivalents corresponding to two
81 /// pairs of vertices along an element edge:
82 /// - The first pair contains
83 /// -# the vertex in the reference element
84 /// -# the corresponding vertex in the edge neighbour (i.e. the
85 /// vertex in the edge neighbour that is located at the same
86 /// position as that first vertex).
87 /// .
88 /// - The second pair contains
89 /// -# the vertex at the other end of the edge in the reference element
90 /// -# the corresponding vertex in the edge neighbour.
91 /// .
92 /// .
93 /// These two pairs completely define the relative rotation
94 /// between the reference element and its edge neighbour. The map
95 /// returns a pair which contains the up_equivalent and the
96 /// right_equivalent of the edge neighbour, i.e. it tells us
97 /// which direction in the edge neighbour coincides with the
98 /// up (or right) direction in the reference element.
99 //====================================================================
100 std::map<std::pair<std::pair<int, int>, std::pair<int, int>>,
101 std::pair<int, int>>
103
104
105 // Protected static member data:
106 //------------------------------
107
108
109 //====================================================================
110 /// Entry in rotation matrix: cos(i*90)
111 //====================================================================
112 Vector<int> OcTree::Cosi;
113
114
115 //====================================================================
116 /// Entry in rotation matrix: sin(i*90)
117 //====================================================================
118 Vector<int> OcTree::Sini;
119
120 //====================================================================
121 /// Array of direction/octant adjacency scheme:
122 /// Is_adjacent(direction,octant): Is face/edge \c direction
123 /// adjacent to octant \c octant ? Table in Samet's book.
124 //====================================================================
125 DenseMatrix<bool> OcTree::Is_adjacent;
126
127 //====================================================================
128 /// Reflection scheme: Reflect(direction,octant): Get mirror
129 /// of octant/edge in specified direction. E.g. Reflect(LDF,L)=RDF
130 //====================================================================
131 DenseMatrix<int> OcTree::Reflect;
132
133 //====================================================================
134 /// Determine common face of edges or octants.
135 /// Slightly bizarre lookup scheme from Samet's book.
136 //====================================================================
137 DenseMatrix<int> OcTree::Common_face;
138
139 //====================================================================
140 /// Colours for neighbours in various directions
141 //====================================================================
142 Vector<std::string> OcTree::Colour;
143
144 //====================================================================
145 /// s_base(i,direction): Initial value for coordinate s[i] on
146 /// the face indicated by direction (L/R/U/D/F/B)
147 //====================================================================
148 DenseMatrix<double> OcTree::S_base;
149
150 //====================================================================
151 /// Each face of the RefineableQElement<3> that is represented
152 /// by the octree is parametrised by two (of the three)
153 /// local coordinates that parametrise the entire 3D element. E.g.
154 /// the B[ack] face is parametrised by (s[0], s[1]); the D[own] face
155 /// is parametrised by (s[0],s[2]); etc. We always identify the
156 /// in-face coordinate with the lower (3D) index with the subscript
157 /// \c _lo and the one with the larger (3D) index with the subscript \c _hi.
158 /// Here we set up the translation scheme between the 2D in-face
159 /// coordinates (s_lo,s_hi) and the corresponding 3D coordinates:
160 /// If we're located on face \c face [L/R/F/B/U/D], then
161 /// an increase in s_lo from -1 to +1 corresponds to a change
162 /// of \c S_steplo(i,face) in the 3D coordinate \c s[i]. S_steplo(i,direction)
163 //====================================================================
164 DenseMatrix<double> OcTree::S_steplo;
165
166
167 //====================================================================
168 /// If we're located on face \c face [L/R/F/B/U/D], then
169 /// an increase in s_hi from -1 to +1 corresponds to a change
170 /// of \c S_stephi(i,face) in the 3D coordinate \ s[i].
171 /// [Read the discussion of \c S_steplo for an explanation of
172 /// the subscripts \c _hi and \c _lo.]
173 //====================================================================
174 DenseMatrix<double> OcTree::S_stephi;
175
176 //====================================================================
177 /// Relative to the left/down/back vertex in any (father) octree, the
178 /// corresponding vertex in the son specified by \c son_octant has an offset.
179 /// If we project the son_octant's left/down/back vertex onto the
180 /// father's face \c face, it is located at the in-face coordinate
181 /// \c s_lo = h/2 \c S_directlo(face,son_octant). [See discussion of
182 /// \c S_steplo for an explanation of the subscripts \c _hi and \c _lo.]
183 //====================================================================
184 DenseMatrix<double> OcTree::S_directlo;
185
186 //====================================================================
187 /// Relative to the left/down/back vertex in any (father) octree, the
188 /// corresponding vertex in the son specified by \c son_octant has an offset.
189 /// If we project the son_octant's left/down/back vertex onto the
190 /// father's face \c face, it is located at the in-face coordinate
191 /// \c s_hi = h/2 \c S_directlhi(face,son_octant). [See discussion of
192 /// \c S_steplo for an explanation of the subscripts \c _hi and \c _lo.]
193 //====================================================================
194 DenseMatrix<double> OcTree::S_directhi;
195
196 //====================================================================
197 /// S_base_edge(i,edge): Initial value for coordinate s[i] on
198 /// the specified edge (LF/RF/...).
199 //====================================================================
200 DenseMatrix<double> OcTree::S_base_edge;
201
202 //====================================================================
203 /// Each edge of the RefineableQElement<3> that is represented
204 /// by the octree is parametrised by one (of the three)
205 /// local coordinates that parametrise the entire 3D element.
206 /// If we're located on edge \c edge [DB,UB,...], then
207 /// an increase in s from -1 to +1 corresponds to a change
208 /// of \c s_step_edge(i,edge) in the 3D coordinates \c s[i].
209 //====================================================================
210 DenseMatrix<double> OcTree::S_step_edge;
211
212 //====================================================================
213 /// Relative to the left/down/back vertex in any (father) octree, the
214 /// corresponding vertex in the son specified by \c son_octant has an offset.
215 /// If we project the son_octant's left/down/back vertex onto the
216 /// father's edge \c edge, it is located at the in-face coordinate
217 /// \c s_lo = h/2 \c S_direct_edge(edge,son_octant).
218 //====================================================================
219 DenseMatrix<double> OcTree::S_direct_edge;
220
221
222 // End static data
223 //----------------
224
225
226 //===================================================================
227 /// This function is used to translate the position of a vertex node
228 /// (given by his local number n into a vector giving the position of
229 /// this node in the local coordinates system.
230 /// It also needs the value of nnode1d to work.
231 //===================================================================
233 const unsigned& nnode1d)
234 {
235#ifdef PARANOID
236 if ((n != 0) && (n != nnode1d - 1) && (n != (nnode1d - 1) * nnode1d) &&
237 (n != nnode1d * nnode1d - 1) &&
238 (n != (nnode1d * nnode1d) * (nnode1d - 1) + 0) &&
239 (n != (nnode1d * nnode1d) * (nnode1d - 1) + nnode1d - 1) &&
240 (n != (nnode1d * nnode1d) * (nnode1d - 1) + (nnode1d - 1) * nnode1d) &&
241 (n != (nnode1d * nnode1d) * (nnode1d - 1) + nnode1d * nnode1d - 1))
242 {
243 std::ostringstream error_stream;
244 error_stream << "Node " << n
245 << " is not a vertex node in a brick element with "
246 << nnode1d << " nodes along each edge!";
247
248 throw OomphLibError(
250 }
251#endif
252 int a, b, c;
254 a = n / (nnode1d * nnode1d);
255 b = (n - a * nnode1d * nnode1d) / nnode1d;
256 c = n - a * nnode1d * nnode1d - b * nnode1d;
257
258 result_vect[0] = 2 * c / (nnode1d - 1) - 1;
259 result_vect[1] = 2 * b / (nnode1d - 1) - 1;
260 result_vect[2] = 2 * a / (nnode1d - 1) - 1;
261
262 return result_vect;
263 }
264
265 //==================================================================
266 /// Given an edge, this function returns the faces on which it lies.
267 //==================================================================
269 {
270 using namespace OcTreeNames;
271
272#ifdef PARANOID
273 if ((edge != LB) && (edge != RB) && (edge != DB) && (edge != UB) &&
274 (edge != LD) && (edge != RD) && (edge != LU) && (edge != RU) &&
275 (edge != LF) && (edge != RF) && (edge != DF) && (edge != UF))
276 {
277 std::ostringstream error_stream;
278 error_stream << "Edge " << Direct_string[edge] << "is not valid!";
279 throw OomphLibError(
281 }
282#endif
283
284 // Allocate space for the result
285 Vector<int> faces(2, 0);
286
287 // Which faces does this edge lie on?
288 switch (edge)
289 {
290 case LB:
291 // First entry
292 faces[0] = L;
293
294 // Second entry
295 faces[1] = B;
296
297 // Break
298 break;
299 case RB:
300 // First entry
301 faces[0] = R;
302
303 // Second entry
304 faces[1] = B;
305
306 // Break
307 break;
308 case DB:
309 // First entry
310 faces[0] = D;
311
312 // Second entry
313 faces[1] = B;
314
315 // Break
316 break;
317 case UB:
318 // First entry
319 faces[0] = U;
320
321 // Second entry
322 faces[1] = B;
323
324 // Break
325 break;
326 case LD:
327 // First entry
328 faces[0] = L;
329
330 // Second entry
331 faces[1] = D;
332
333 // Break
334 break;
335 case RD:
336 // First entry
337 faces[0] = R;
338
339 // Second entry
340 faces[1] = D;
341
342 // Break
343 break;
344 case LU:
345 // First entry
346 faces[0] = L;
347
348 // Second entry
349 faces[1] = U;
350
351 // Break
352 break;
353 case RU:
354 // First entry
355 faces[0] = R;
356
357 // Second entry
358 faces[1] = U;
359
360 // Break
361 break;
362 case LF:
363 // First entry
364 faces[0] = L;
365
366 // Second entry
367 faces[1] = F;
368
369 // Break
370 break;
371 case RF:
372 // First entry
373 faces[0] = R;
374
375 // Second entry
376 faces[1] = F;
377
378 // Break
379 break;
380 case DF:
381 // First entry
382 faces[0] = D;
383
384 // Second entry
385 faces[1] = F;
386
387 // Break
388 break;
389 case UF:
390 // First entry
391 faces[0] = U;
392
393 // Second entry
394 faces[1] = F;
395
396 // Break
397 break;
398 default:
399 // Throw an error
400 throw OomphLibError("Incorrect edge input!",
403 }
404
405 // Return the faces
406 return faces;
407 } // End of faces_of_common_edge
408
409
410 //==================================================================
411 /// Return the local node number of given vertex
412 /// in an element with nnode1d nodes in each coordinate direction.
413 //==================================================================
415 const unsigned& nnode1d)
416 {
417 using namespace OcTreeNames;
418
419#ifdef PARANOID
420 if ((vertex != LDB) && (vertex != RDB) && (vertex != LUB) &&
421 (vertex != RUB) && (vertex != LDF) && (vertex != RDF) &&
422 (vertex != LUF) && (vertex != RUF))
423 {
424 std::ostringstream error_stream;
425 error_stream << "Wrong vertex: " << Direct_string[vertex] << std::endl;
426 throw OomphLibError(
428 }
429#endif
430
431 switch (vertex)
432 {
433 case LDB:
434 return 0;
435 break;
436
437 case RDB:
438 return nnode1d - 1;
439 break;
440
441
442 case LUB:
443 return nnode1d * (nnode1d - 1);
444 break;
445
446 case RUB:
447 return nnode1d * nnode1d - 1;
448 break;
449
450
451 case LDF:
452 return nnode1d * nnode1d * (nnode1d - 1);
453 break;
454
455
456 case RDF:
457 return (nnode1d * nnode1d + 1) * (nnode1d - 1);
458 break;
459
460 case LUF:
461 return nnode1d * nnode1d * nnode1d - nnode1d;
462 break;
463
464 case RUF:
465 return nnode1d * nnode1d * nnode1d - 1;
466 break;
467
468 default:
469
470 std::ostringstream error_stream;
471 error_stream << "Never get here. vertex: " << Direct_string[vertex]
472 << std::endl;
473 throw OomphLibError(
475 break;
476 }
477
478
479 std::ostringstream error_stream;
480 error_stream << "Never get here. vertex: " << Direct_string[vertex]
481 << std::endl;
482 throw OomphLibError(
484 }
485
486
487 //==================================================================
488 /// Return the vertex of local (vertex) node n
489 /// in an element with nnode1d nodes in each coordinate direction.
490 //==================================================================
491 int OcTree::node_number_to_vertex(const unsigned& n, const unsigned& nnode1d)
492 {
493 using namespace OcTreeNames;
494
495#ifdef PARANOID
496 if ((n != 0) && (n != nnode1d - 1) && (n != (nnode1d - 1) * nnode1d) &&
497 (n != nnode1d * nnode1d - 1) &&
498 (n != (nnode1d * nnode1d) * (nnode1d - 1) + 0) &&
499 (n != (nnode1d * nnode1d) * (nnode1d - 1) + nnode1d - 1) &&
500 (n != (nnode1d * nnode1d) * (nnode1d - 1) + (nnode1d - 1) * nnode1d) &&
501 (n != (nnode1d * nnode1d) * (nnode1d - 1) + nnode1d * nnode1d - 1))
502 {
503 std::ostringstream error_stream;
504 error_stream << "Node " << n
505 << " is not a vertex node in a brick element with "
506 << nnode1d << " nodes along each edge!";
507
508 throw OomphLibError(
510 }
511#endif
512
513 if (n == 0)
514 {
515 return LDB;
516 }
517 else if (n == nnode1d - 1)
518 {
519 return RDB;
520 }
521 else if (n == nnode1d * (nnode1d - 1))
522 {
523 return LUB;
524 }
525 else if (n == nnode1d * nnode1d - 1)
526 {
527 return RUB;
528 }
529 else if (n == nnode1d * nnode1d * (nnode1d - 1))
530 {
531 return LDF;
532 }
533 else if (n == (nnode1d * nnode1d + 1) * (nnode1d - 1))
534 {
535 return RDF;
536 }
537 else if (n == nnode1d * nnode1d * nnode1d - nnode1d)
538 {
539 return LUF;
540 }
541 else if (n == nnode1d * nnode1d * nnode1d - 1)
542 {
543 return RUF;
544 }
545 else
546 {
547 std::ostringstream error_stream;
548 error_stream << "Never get here. local node number: " << n
549 << " is not a vertex node in a brick element with "
550 << nnode1d << " nodes along each edge!" << std::endl;
551 throw OomphLibError(
553 }
554 }
555
556
557 //==================================================================
558 /// This function takes as argument two node numbers of two nodes
559 /// delimiting an edge, and one face of this edge and returns the
560 /// other face that is sharing this edge. The node numbers given to
561 /// this function MUST be vertices nodes to work.
562 /// it also need the value of nnode1d to work.
563 /// (\c face is a direction in the set U,D,F,B,L,R).
564 //==================================================================
565 int OcTree::get_the_other_face(const unsigned& n1,
566 const unsigned& n2,
567 const unsigned& nnode1d,
568 const int& face)
569 {
574
575 // Translate the nodes to vectors
578
579 // Translate the face to a vector
581
582 // Compute the vector to the other face -- magic, courtesy of Renaud
583 // Schleck!
584 for (unsigned i = 0; i < 3; i++)
585 {
586 // Calculate the i-th entry
588
589#ifdef PARANOID
590 if ((vect_other_face[i] != 1) && (vect_other_face[i] != -1) &&
591 (vect_other_face[i] != 0))
592 {
593 throw OomphLibError("The nodes given are not vertices",
596 }
597#endif
598 }
599
600 // return the corresponding face
602 }
603
604
605 //====================================================================
606 /// Build the rotation matrix for a rotation around the axis \c axis of
607 /// an angle \c angle*90
608 //====================================================================
610 int& angle,
612 {
613 using namespace OcTreeNames;
614 int a = 0, b = 0, c = 0, i, j;
615
616 switch (axis)
617 {
618 case R:
619 a = 1;
620 b = 2;
621 c = 0;
622 break;
623 case U:
624 a = 2;
625 b = 0;
626 c = 1;
627 break;
628 case F:
629 a = 0;
630 b = 1;
631 c = 2;
632 break;
633 default:
634 // Object to create error message
635 std::ostringstream error_message_stream;
636
637 // Create the error message
638 error_message_stream << "Bad axis (" << axis << "). Expected "
639 << OcTreeNames::R << ", " << OcTreeNames::U
640 << " or " << OcTreeNames::F << "." << std::endl;
641
642 // Throw the error message
646 }
647 for (i = 0; i < 3; i++)
648 {
649 for (j = 0; j < 3; j++)
650 {
651 mat(i, j) = 0;
652 }
653 }
654 mat(a, a) = Cosi[angle];
655 mat(b, b) = Cosi[angle];
656 mat(a, b) = -Sini[angle];
657 mat(b, a) = Sini[angle];
658 mat(c, c) = 1;
659 }
660
661 //===================================================================
662 /// Helper: Performs the operation Mat3=Mat1*Mat2
663 //===================================================================
665 const DenseMatrix<int>& mat2,
667 {
668 int Sum, i, j, k;
669 for (i = 0; i < 3; i++)
670 {
671 for (j = 0; j < 3; j++)
672 {
673 Sum = 0;
674 for (k = 0; k < 3; k++)
675 {
676 Sum += mat1(i, k) * mat2(k, j);
677 }
678 mat3(i, j) = Sum;
679 }
680 }
681 }
682
683
684 //===================================================================
685 /// Helper: Performs the operation Vect2=Mat*Vect1
686 //===================================================================
688 const Vector<int>& vect1,
690 {
691 int i, k, sum;
692 for (i = 0; i < 3; i++)
693 {
694 sum = 0;
695 for (k = 0; k < 3; k++)
696 {
697 sum += mat(i, k) * vect1[k];
698 }
699 vect2[i] = sum;
700 }
701 }
702
703
704 //===================================================================
705 /// A rotation is defined by the newUp and newRight
706 /// directions; so if Up becomes newUp and Right becomes newRight
707 /// then dir becomes rotate(newUp,newRight,dir);
708 //===================================================================
709 int OcTree::rotate(const int& new_up, const int& new_right, const int& dir)
710 {
711 using namespace OcTreeNames;
712
713#ifdef PARANOID
714 if ((new_up != L) && (new_up != R) && (new_up != F) && (new_up != B) &&
715 (new_up != U) && (new_up != D))
716 {
717 std::ostringstream error_stream;
718 error_stream << "Wrong new_up: " << Direct_string[new_up] << std::endl;
719 throw OomphLibError(
721 }
722 if ((new_right != L) && (new_right != R) && (new_right != F) &&
723 (new_right != B) && (new_right != U) && (new_right != D))
724 {
725 std::ostringstream error_stream;
726 error_stream << "Wrong new_right: " << Direct_string[new_right]
727 << std::endl;
728 throw OomphLibError(
730 }
731#endif
732
735 // translate the direction to a vector
737
738 // rotate it
740
741 // translate the vector back to a direction
743 }
744
745
746 //==================================================================
747 /// This function rotates a vector according to a rotation of
748 /// the axes that changes up to new_up and right to new_right.
749 //==================================================================
751 const int& new_right,
752 const Vector<int>& dir)
753 {
754 using namespace OcTreeNames;
755
756#ifdef PARANOID
757 if ((new_up != L) && (new_up != R) && (new_up != F) && (new_up != B) &&
758 (new_up != U) && (new_up != D))
759 {
760 std::ostringstream error_stream;
761 error_stream << "Wrong new_up: " << Direct_string[new_up] << std::endl;
762 throw OomphLibError(
764 }
765 if ((new_right != L) && (new_right != R) && (new_right != F) &&
766 (new_right != B) && (new_right != U) && (new_right != D))
767 {
768 std::ostringstream error_stream;
769 error_stream << "Wrong new_right: " << Direct_string[new_right]
770 << std::endl;
771 throw OomphLibError(
773 }
774#endif
775
776 // Every possible rotation of an element can be produced by the
777 // compostition of two (or one) rotations about one of the main
778 // axes of the element (R, U, F). So for each (newRight,newUp)
779 // we define the (angle1,axis1) of the first rotation and the
780 // (angle2, axis2) of the second one (if needed)
781
782 int axis1, axis2, angle1, angle2, nrot;
783 nrot = 2;
784 if (new_up == U)
785 {
786 nrot = 1;
787 axis1 = U;
788 switch (new_right)
789 {
790 case R:
791 angle1 = 0;
792 break;
793 case B:
794 angle1 = 1;
795 break;
796 case L:
797 angle1 = 2;
798 break;
799 case F:
800 angle1 = 3;
801 break;
802 default:
803 std::ostringstream error_stream;
804 error_stream << "New_right is " << new_right << " ("
805 << Direct_string[new_right] << "). "
806 << "It should be R, B, L, or F" << std::endl;
807 throw OomphLibError(error_stream.str(),
810 }
811 }
812
813 if (new_up == D)
814 {
815 switch (new_right)
816 {
817 case R:
818 nrot = 1;
819 axis1 = R;
820 angle1 = 2;
821 break;
822 case B:
823 axis1 = R;
824 angle1 = 2;
825 axis2 = U;
826 angle2 = 1;
827 break;
828 case L:
829 nrot = 1;
830 axis1 = F;
831 angle1 = 2;
832 break;
833 case F:
834 axis1 = R;
835 angle1 = 2;
836 axis2 = U;
837 angle2 = 3;
838 break;
839 default:
840 std::ostringstream error_stream;
841 error_stream << "New_right is " << new_right << " ("
842 << Direct_string[new_right] << "). "
843 << "It should be R, B, L, or F" << std::endl;
844 throw OomphLibError(error_stream.str(),
847 }
848 }
849
850 if (new_up == R)
851 {
852 switch (new_right)
853 {
854 case D:
855 nrot = 1;
856 axis1 = F;
857 angle1 = 3;
858 break;
859 case B:
860 axis1 = F;
861 angle1 = 3;
862 axis2 = R;
863 angle2 = 1;
864 break;
865 case U:
866 axis1 = F;
867 angle1 = 1;
868 axis2 = U;
869 angle2 = 2;
870 break;
871 case F:
872 axis1 = F;
873 angle1 = 3;
874 axis2 = R;
875 angle2 = 3;
876 break;
877 default:
878 std::ostringstream error_stream;
879 error_stream << "New_right is " << new_right << " ("
880 << Direct_string[new_right] << "). "
881 << "It should be D, B, U, or F" << std::endl;
882 throw OomphLibError(error_stream.str(),
885 }
886 }
887
888 if (new_up == L)
889 {
890 switch (new_right)
891 {
892 case D:
893 axis1 = F;
894 angle1 = 1;
895 axis2 = R;
896 angle2 = 2;
897 break;
898 case B:
899 axis1 = F;
900 angle1 = 1;
901 axis2 = R;
902 angle2 = 3;
903 break;
904 case U:
905 nrot = 1;
906 axis1 = F;
907 angle1 = 1;
908 break;
909 case F:
910 axis1 = F;
911 angle1 = 1;
912 axis2 = R;
913 angle2 = 1;
914 break;
915 default:
916 std::ostringstream error_stream;
917 error_stream << "New_right is " << new_right << " ("
918 << Direct_string[new_right] << "). "
919 << "It should be D, B, U, or F" << std::endl;
920 throw OomphLibError(error_stream.str(),
923 }
924 }
925
926 if (new_up == F)
927 {
928 switch (new_right)
929 {
930 case R:
931 nrot = 1;
932 axis1 = R;
933 angle1 = 1;
934 break;
935 case L:
936 axis1 = R;
937 angle1 = 1;
938 axis2 = F;
939 angle2 = 2;
940 break;
941 case U:
942 axis1 = R;
943 angle1 = 1;
944 axis2 = F;
945 angle2 = 1;
946 break;
947 case D:
948 axis1 = R;
949 angle1 = 1;
950 axis2 = F;
951 angle2 = 3;
952 break;
953 default:
954 std::ostringstream error_stream;
955 error_stream << "New_right is " << new_right << " ("
956 << Direct_string[new_right] << "). "
957 << "It should be R, L, U, or D" << std::endl;
958 throw OomphLibError(error_stream.str(),
961 }
962 }
963 if (new_up == B)
964 {
965 switch (new_right)
966 {
967 case R:
968 nrot = 1;
969 axis1 = R;
970 angle1 = 3;
971 break;
972 case L:
973 axis1 = R;
974 angle1 = 3;
975 axis2 = F;
976 angle2 = 2;
977 break;
978 case U:
979 axis1 = R;
980 angle1 = 3;
981 axis2 = F;
982 angle2 = 1;
983 break;
984 case D:
985 axis1 = R;
986 angle1 = 3;
987 axis2 = F;
988 angle2 = 3;
989 break;
990 default:
991 std::ostringstream error_stream;
992 error_stream << "New_right is " << new_right << " ("
993 << Direct_string[new_right] << "). "
994 << "It should be R, L, U, or D" << std::endl;
995 throw OomphLibError(error_stream.str(),
998 }
999 }
1000
1005
1006 // Then we build the first rotation matrix
1008
1009 // If needed we build the second one
1010 if (nrot == 2)
1011 {
1012 // And we make the composition of the two rotations
1013 // which is stored in Mat3
1016 }
1017 else
1018 {
1019 // Else we just copy Mat1 into Mat3
1020 for (int i = 0; i < 3; i++)
1021 {
1022 for (int j = 0; j < 3; j++)
1023 {
1024 mat3(i, j) = mat1(i, j);
1025 }
1026 }
1027 }
1028
1029 // Rotate
1031
1032 // Return the corresponding vector
1033 return vect_new_dir;
1034 }
1035
1036
1037 //====================================================================
1038 /// Setup static data for OcTree
1039 //====================================================================
1041 {
1042 using namespace OcTreeNames;
1043
1044
1045#ifdef PARANOID
1047 {
1048 std::ostringstream error_stream;
1049 error_stream << "Inconsistent enumeration! \n Tree::OMEGA="
1050 << Tree::OMEGA << "\nOcTree::OMEGA=" << OcTree::OMEGA
1051 << std::endl;
1052 throw OomphLibError(
1054 }
1055#endif
1056
1057 // Private static data
1058 //--------------------
1059
1060 // Set flag to indicate that static data has been setup
1062
1063 // Initialisation of cosi and sini used in rotation matrix
1064 Cosi.resize(4);
1065 Sini.resize(4);
1066
1067 Cosi[0] = 1;
1068 Cosi[1] = 0;
1069 Cosi[2] = -1;
1070 Cosi[3] = 0;
1071
1072 Sini[0] = 0;
1073 Sini[1] = 1;
1074 Sini[2] = 0;
1075 Sini[3] = -1;
1076
1077
1078 // Build direction/octant adjacency scheme
1079 // Is_adjacent(i_face,j_octant):
1080 // Is face adjacent to octant?
1081 // See the table in Samet book
1082 Is_adjacent.resize(27, 27);
1083 Is_adjacent(L, LDB) = true;
1084 Is_adjacent(R, LDB) = false;
1085 Is_adjacent(D, LDB) = true;
1086 Is_adjacent(U, LDB) = false;
1087 Is_adjacent(B, LDB) = true;
1088 Is_adjacent(F, LDB) = false;
1089
1090 Is_adjacent(L, LDF) = true;
1091 Is_adjacent(R, LDF) = false;
1092 Is_adjacent(D, LDF) = true;
1093 Is_adjacent(U, LDF) = false;
1094 Is_adjacent(B, LDF) = false;
1095 Is_adjacent(F, LDF) = true;
1096
1097 Is_adjacent(L, LUB) = true;
1098 Is_adjacent(R, LUB) = false;
1099 Is_adjacent(D, LUB) = false;
1100 Is_adjacent(U, LUB) = true;
1101 Is_adjacent(B, LUB) = true;
1102 Is_adjacent(F, LUB) = false;
1103
1104 Is_adjacent(L, LUF) = true;
1105 Is_adjacent(R, LUF) = false;
1106 Is_adjacent(D, LUF) = false;
1107 Is_adjacent(U, LUF) = true;
1108 Is_adjacent(B, LUF) = false;
1109 Is_adjacent(F, LUF) = true;
1110
1111 Is_adjacent(L, RDB) = false;
1112 Is_adjacent(R, RDB) = true;
1113 Is_adjacent(D, RDB) = true;
1114 Is_adjacent(U, RDB) = false;
1115 Is_adjacent(B, RDB) = true;
1116 Is_adjacent(F, RDB) = false;
1117
1118 Is_adjacent(L, RDF) = false;
1119 Is_adjacent(R, RDF) = true;
1120 Is_adjacent(D, RDF) = true;
1121 Is_adjacent(U, RDF) = false;
1122 Is_adjacent(B, RDF) = false;
1123 Is_adjacent(F, RDF) = true;
1124
1125 Is_adjacent(L, RUB) = false;
1126 Is_adjacent(R, RUB) = true;
1127 Is_adjacent(D, RUB) = false;
1128 Is_adjacent(U, RUB) = true;
1129 Is_adjacent(B, RUB) = true;
1130 Is_adjacent(F, RUB) = false;
1131
1132 Is_adjacent(L, RUF) = false;
1133 Is_adjacent(R, RUF) = true;
1134 Is_adjacent(D, RUF) = false;
1135 Is_adjacent(U, RUF) = true;
1136 Is_adjacent(B, RUF) = false;
1137 Is_adjacent(F, RUF) = true;
1138
1139
1140 // Build direction/octant adjacency scheme
1141 // Is_adjacent(i_edge,j_octant):
1142 // Is edge adjacent to octant?
1143 // See the table in Samet book
1144 Is_adjacent(LD, LDB) = true;
1145 Is_adjacent(LD, LDF) = true;
1146 Is_adjacent(LD, LUB) = false;
1147 Is_adjacent(LD, LUF) = false;
1148 Is_adjacent(LD, RDB) = false;
1149 Is_adjacent(LD, RDF) = false;
1150 Is_adjacent(LD, RUB) = false;
1151 Is_adjacent(LD, RUF) = false;
1152
1153 Is_adjacent(LU, LDB) = false;
1154 Is_adjacent(LU, LDF) = false;
1155 Is_adjacent(LU, LUB) = true;
1156 Is_adjacent(LU, LUF) = true;
1157 Is_adjacent(LU, RDB) = false;
1158 Is_adjacent(LU, RDF) = false;
1159 Is_adjacent(LU, RUB) = false;
1160 Is_adjacent(LU, RUF) = false;
1161
1162
1163 Is_adjacent(LB, LDB) = true;
1164 Is_adjacent(LB, LDF) = false;
1165 Is_adjacent(LB, LUB) = true;
1166 Is_adjacent(LB, LUF) = false;
1167 Is_adjacent(LB, RDB) = false;
1168 Is_adjacent(LB, RDF) = false;
1169 Is_adjacent(LB, RUB) = false;
1170 Is_adjacent(LB, RUF) = false;
1171
1172
1173 Is_adjacent(LF, LDB) = false;
1174 Is_adjacent(LF, LDF) = true;
1175 Is_adjacent(LF, LUB) = false;
1176 Is_adjacent(LF, LUF) = true;
1177 Is_adjacent(LF, RDB) = false;
1178 Is_adjacent(LF, RDF) = false;
1179 Is_adjacent(LF, RUB) = false;
1180 Is_adjacent(LF, RUF) = false;
1181
1182
1183 Is_adjacent(RD, LDB) = false;
1184 Is_adjacent(RD, LDF) = false;
1185 Is_adjacent(RD, LUB) = false;
1186 Is_adjacent(RD, LUF) = false;
1187 Is_adjacent(RD, RDB) = true;
1188 Is_adjacent(RD, RDF) = true;
1189 Is_adjacent(RD, RUB) = false;
1190 Is_adjacent(RD, RUF) = false;
1191
1192
1193 Is_adjacent(RU, LDB) = false;
1194 Is_adjacent(RU, LDF) = false;
1195 Is_adjacent(RU, LUB) = false;
1196 Is_adjacent(RU, LUF) = false;
1197 Is_adjacent(RU, RDB) = false;
1198 Is_adjacent(RU, RDF) = false;
1199 Is_adjacent(RU, RUB) = true;
1200 Is_adjacent(RU, RUF) = true;
1201
1202 Is_adjacent(RB, LDB) = false;
1203 Is_adjacent(RB, LDF) = false;
1204 Is_adjacent(RB, LUB) = false;
1205 Is_adjacent(RB, LUF) = false;
1206 Is_adjacent(RB, RDB) = true;
1207 Is_adjacent(RB, RDF) = false;
1208 Is_adjacent(RB, RUB) = true;
1209 Is_adjacent(RB, RUF) = false;
1210
1211 Is_adjacent(RF, LDB) = false;
1212 Is_adjacent(RF, LDF) = false;
1213 Is_adjacent(RF, LUB) = false;
1214 Is_adjacent(RF, LUF) = false;
1215 Is_adjacent(RF, RDB) = false;
1216 Is_adjacent(RF, RDF) = true;
1217 Is_adjacent(RF, RUB) = false;
1218 Is_adjacent(RF, RUF) = true;
1219
1220
1221 Is_adjacent(DB, LDB) = true;
1222 Is_adjacent(DB, LDF) = false;
1223 Is_adjacent(DB, LUB) = false;
1224 Is_adjacent(DB, LUF) = false;
1225 Is_adjacent(DB, RDB) = true;
1226 Is_adjacent(DB, RDF) = false;
1227 Is_adjacent(DB, RUB) = false;
1228 Is_adjacent(DB, RUF) = false;
1229
1230
1231 Is_adjacent(DF, LDB) = false;
1232 Is_adjacent(DF, LDF) = true;
1233 Is_adjacent(DF, LUB) = false;
1234 Is_adjacent(DF, LUF) = false;
1235 Is_adjacent(DF, RDB) = false;
1236 Is_adjacent(DF, RDF) = true;
1237 Is_adjacent(DF, RUB) = false;
1238 Is_adjacent(DF, RUF) = false;
1239
1240 Is_adjacent(UB, LDB) = false;
1241 Is_adjacent(UB, LDF) = false;
1242 Is_adjacent(UB, LUB) = true;
1243 Is_adjacent(UB, LUF) = false;
1244 Is_adjacent(UB, RDB) = false;
1245 Is_adjacent(UB, RDF) = false;
1246 Is_adjacent(UB, RUB) = true;
1247 Is_adjacent(UB, RUF) = false;
1248
1249 Is_adjacent(UF, LDB) = false;
1250 Is_adjacent(UF, LDF) = false;
1251 Is_adjacent(UF, LUB) = false;
1252 Is_adjacent(UF, LUF) = true;
1253 Is_adjacent(UF, RDB) = false;
1254 Is_adjacent(UF, RDF) = false;
1255 Is_adjacent(UF, RUB) = false;
1256 Is_adjacent(UF, RUF) = true;
1257
1258
1259 // Common face of various octants from Samet's book
1260 Common_face.resize(27, 27);
1261 Common_face(LDB, LDB) = OMEGA;
1262 Common_face(LDB, LDF) = OMEGA;
1263 Common_face(LDB, LUB) = OMEGA;
1264 Common_face(LDB, LUF) = L;
1265 Common_face(LDB, RDB) = OMEGA;
1266 Common_face(LDB, RDF) = D;
1267 Common_face(LDB, RUB) = B;
1268 Common_face(LDB, RUF) = OMEGA;
1269
1270 Common_face(LDF, LDB) = OMEGA;
1271 Common_face(LDF, LDF) = OMEGA;
1272 Common_face(LDF, LUB) = L;
1273 Common_face(LDF, LUF) = OMEGA;
1274 Common_face(LDF, RDB) = D;
1275 Common_face(LDF, RDF) = OMEGA;
1276 Common_face(LDF, RUB) = OMEGA;
1277 Common_face(LDF, RUF) = F;
1278
1279 Common_face(LUB, LDB) = OMEGA;
1280 Common_face(LUB, LDF) = L;
1281 Common_face(LUB, LUB) = OMEGA;
1282 Common_face(LUB, LUF) = OMEGA;
1283 Common_face(LUB, RDB) = B;
1284 Common_face(LUB, RDF) = OMEGA;
1285 Common_face(LUB, RUB) = OMEGA;
1286 Common_face(LUB, RUF) = U;
1287
1288 Common_face(LUF, LDB) = L;
1289 Common_face(LUF, LDF) = OMEGA;
1290 Common_face(LUF, LUB) = OMEGA;
1291 Common_face(LUF, LUF) = OMEGA;
1292 Common_face(LUF, RDB) = OMEGA;
1293 Common_face(LUF, RDF) = F;
1294 Common_face(LUF, RUB) = U;
1295 Common_face(LUF, RUF) = OMEGA;
1296
1297 Common_face(RDB, LDB) = OMEGA;
1298 Common_face(RDB, LDF) = D;
1299 Common_face(RDB, LUB) = B;
1300 Common_face(RDB, LUF) = OMEGA;
1301 Common_face(RDB, RDB) = OMEGA;
1302 Common_face(RDB, RDF) = OMEGA;
1303 Common_face(RDB, RUB) = OMEGA;
1304 Common_face(RDB, RUF) = R;
1305
1306 Common_face(RDF, LDB) = D;
1307 Common_face(RDF, LDF) = OMEGA;
1308 Common_face(RDF, LUB) = OMEGA;
1309 Common_face(RDF, LUF) = F;
1310 Common_face(RDF, RDB) = OMEGA;
1311 Common_face(RDF, RDF) = OMEGA;
1312 Common_face(RDF, RUB) = R;
1313 Common_face(RDF, RUF) = OMEGA;
1314
1315 Common_face(RUB, LDB) = B;
1316 Common_face(RUB, LDF) = OMEGA;
1317 Common_face(RUB, LUB) = OMEGA;
1318 Common_face(RUB, LUF) = U;
1319 Common_face(RUB, RDB) = OMEGA;
1320 Common_face(RUB, RDF) = R;
1321 Common_face(RUB, RUB) = OMEGA;
1322 Common_face(RUB, RUF) = OMEGA;
1323
1324 Common_face(RUF, LDB) = OMEGA;
1325 Common_face(RUF, LDF) = F;
1326 Common_face(RUF, LUB) = U;
1327 Common_face(RUF, LUF) = OMEGA;
1328 Common_face(RUF, RDB) = R;
1329 Common_face(RUF, RDF) = OMEGA;
1330 Common_face(RUF, RUB) = OMEGA;
1331 Common_face(RUF, RUF) = OMEGA;
1332
1333
1334 // Common face of various edges/octants from Samet's book
1335 Common_face(LD, LDB) = OMEGA;
1336 Common_face(LD, LDF) = OMEGA;
1337 Common_face(LD, LUB) = L;
1338 Common_face(LD, LUF) = L;
1339 Common_face(LD, RDB) = D;
1340 Common_face(LD, RDF) = D;
1341 Common_face(LD, RUB) = OMEGA;
1342 Common_face(LD, RUF) = OMEGA;
1343
1344 Common_face(LU, LDB) = L;
1345 Common_face(LU, LDF) = L;
1346 Common_face(LU, LUB) = OMEGA;
1347 Common_face(LU, LUF) = OMEGA;
1348 Common_face(LU, RDB) = OMEGA;
1349 Common_face(LU, RDF) = OMEGA;
1350 Common_face(LU, RUB) = U;
1351 Common_face(LU, RUF) = U;
1352
1353 Common_face(LB, LDB) = OMEGA;
1354 Common_face(LB, LDF) = L;
1355 Common_face(LB, LUB) = OMEGA;
1356 Common_face(LB, LUF) = L;
1357 Common_face(LB, RDB) = B;
1358 Common_face(LB, RDF) = OMEGA;
1359 Common_face(LB, RUB) = B;
1360 Common_face(LB, RUF) = OMEGA;
1361
1362 Common_face(LF, LDB) = L;
1363 Common_face(LF, LDF) = OMEGA;
1364 Common_face(LF, LUB) = L;
1365 Common_face(LF, LUF) = OMEGA;
1366 Common_face(LF, RDB) = OMEGA;
1367 Common_face(LF, RDF) = F;
1368 Common_face(LF, RUB) = OMEGA;
1369 Common_face(LF, RUF) = F;
1370
1371 Common_face(RD, LDB) = D;
1372 Common_face(RD, LDF) = D;
1373 Common_face(RD, LUB) = OMEGA;
1374 Common_face(RD, LUF) = OMEGA;
1375 Common_face(RD, RDB) = OMEGA;
1376 Common_face(RD, RDF) = OMEGA;
1377 Common_face(RD, RUB) = R;
1378 Common_face(RD, RUF) = R;
1379
1380 Common_face(RU, LDB) = OMEGA;
1381 Common_face(RU, LDF) = OMEGA;
1382 Common_face(RU, LUB) = U;
1383 Common_face(RU, LUF) = U;
1384 Common_face(RU, RDB) = R;
1385 Common_face(RU, RDF) = R;
1386 Common_face(RU, RUB) = OMEGA;
1387 Common_face(RU, RUF) = OMEGA;
1388
1389 Common_face(RB, LDB) = B;
1390 Common_face(RB, LDF) = OMEGA;
1391 Common_face(RB, LUB) = B;
1392 Common_face(RB, LUF) = OMEGA;
1393 Common_face(RB, RDB) = OMEGA;
1394 Common_face(RB, RDF) = R;
1395 Common_face(RB, RUB) = OMEGA;
1396 Common_face(RB, RUF) = R;
1397
1398 Common_face(RF, LDB) = OMEGA;
1399 Common_face(RF, LDF) = F;
1400 Common_face(RF, LUB) = OMEGA;
1401 Common_face(RF, LUF) = F;
1402 Common_face(RF, RDB) = R;
1403 Common_face(RF, RDF) = OMEGA;
1404 Common_face(RF, RUB) = R;
1405 Common_face(RF, RUF) = OMEGA;
1406
1407
1408 Common_face(DB, LDB) = OMEGA;
1409 Common_face(DB, LDF) = D;
1410 Common_face(DB, LUB) = B;
1411 Common_face(DB, LUF) = OMEGA;
1412 Common_face(DB, RDB) = OMEGA;
1413 Common_face(DB, RDF) = D;
1414 Common_face(DB, RUB) = B;
1415 Common_face(DB, RUF) = OMEGA;
1416
1417 Common_face(DF, LDB) = D;
1418 Common_face(DF, LDF) = OMEGA;
1419 Common_face(DF, LUB) = OMEGA;
1420 Common_face(DF, LUF) = F;
1421 Common_face(DF, RDB) = D;
1422 Common_face(DF, RDF) = OMEGA;
1423 Common_face(DF, RUB) = OMEGA;
1424 Common_face(DF, RUF) = F;
1425
1426 Common_face(UB, LDB) = B;
1427 Common_face(UB, LDF) = OMEGA;
1428 Common_face(UB, LUB) = OMEGA;
1429 Common_face(UB, LUF) = U;
1430 Common_face(UB, RDB) = B;
1431 Common_face(UB, RDF) = OMEGA;
1432 Common_face(UB, RUB) = OMEGA;
1433 Common_face(UB, RUF) = U;
1434
1435 Common_face(UF, LDB) = OMEGA;
1436 Common_face(UF, LDF) = F;
1437 Common_face(UF, LUB) = U;
1438 Common_face(UF, LUF) = OMEGA;
1439 Common_face(UF, RDB) = OMEGA;
1440 Common_face(UF, RDF) = F;
1441 Common_face(UF, RUB) = U;
1442 Common_face(UF, RUF) = OMEGA;
1443
1444
1445 // Tecplot colours for neighbours in various directions
1446 Colour.resize(27);
1447 Colour[R] = "CYAN";
1448 Colour[L] = "RED";
1449 Colour[U] = "GREEN";
1450 Colour[D] = "BLUE";
1451 Colour[F] = "CUSTOM3";
1452 Colour[B] = "PURPLE";
1453 Colour[OMEGA] = "YELLOW";
1454
1455 Colour[LB] = "BLUE";
1456 Colour[RB] = "BLUE";
1457 Colour[DB] = "BLUE";
1458 Colour[UB] = "BLUE";
1459
1460 Colour[LD] = "GREEN";
1461 Colour[RD] = "GREEN";
1462 Colour[LU] = "GREEN";
1463 Colour[RU] = "GREEN";
1464
1465
1466 Colour[LF] = "RED";
1467 Colour[RF] = "RED";
1468 Colour[DF] = "RED";
1469 Colour[UF] = "RED";
1470
1471 Colour[OMEGA] = "YELLOW";
1472
1473
1474 // Reflection scheme:
1475 // Reflect(direction,octant): Get mirror of octant in direction
1476 // Table in Samet book as well
1477 Reflect.resize(27, 27);
1478
1479 Reflect(L, LDB) = RDB;
1480 Reflect(R, LDB) = RDB;
1481 Reflect(D, LDB) = LUB;
1482 Reflect(U, LDB) = LUB;
1483 Reflect(B, LDB) = LDF;
1484 Reflect(F, LDB) = LDF;
1485
1486 Reflect(L, LDF) = RDF;
1487 Reflect(R, LDF) = RDF;
1488 Reflect(D, LDF) = LUF;
1489 Reflect(U, LDF) = LUF;
1490 Reflect(B, LDF) = LDB;
1491 Reflect(F, LDF) = LDB;
1492
1493 Reflect(L, LUB) = RUB;
1494 Reflect(R, LUB) = RUB;
1495 Reflect(D, LUB) = LDB;
1496 Reflect(U, LUB) = LDB;
1497 Reflect(B, LUB) = LUF;
1498 Reflect(F, LUB) = LUF;
1499
1500 Reflect(L, LUF) = RUF;
1501 Reflect(R, LUF) = RUF;
1502 Reflect(D, LUF) = LDF;
1503 Reflect(U, LUF) = LDF;
1504 Reflect(B, LUF) = LUB;
1505 Reflect(F, LUF) = LUB;
1506
1507 Reflect(L, RDB) = LDB;
1508 Reflect(R, RDB) = LDB;
1509 Reflect(D, RDB) = RUB;
1510 Reflect(U, RDB) = RUB;
1511 Reflect(B, RDB) = RDF;
1512 Reflect(F, RDB) = RDF;
1513
1514 Reflect(L, RDF) = LDF;
1515 Reflect(R, RDF) = LDF;
1516 Reflect(D, RDF) = RUF;
1517 Reflect(U, RDF) = RUF;
1518 Reflect(B, RDF) = RDB;
1519 Reflect(F, RDF) = RDB;
1520
1521 Reflect(L, RUB) = LUB;
1522 Reflect(R, RUB) = LUB;
1523 Reflect(D, RUB) = RDB;
1524 Reflect(U, RUB) = RDB;
1525 Reflect(B, RUB) = RUF;
1526 Reflect(F, RUB) = RUF;
1527
1528 Reflect(L, RUF) = LUF;
1529 Reflect(R, RUF) = LUF;
1530 Reflect(D, RUF) = RDF;
1531 Reflect(U, RUF) = RDF;
1532 Reflect(B, RUF) = RUB;
1533 Reflect(F, RUF) = RUB;
1534
1535
1536 // Reflection scheme:
1537 // Reflect(direction (edge) ,octant): Get mirror of edge in direction
1538 // Table in Samet book as well
1539
1540 Reflect(LD, LDB) = RUB;
1541 Reflect(LU, LDB) = RUB;
1542 Reflect(RD, LDB) = RUB;
1543 Reflect(RU, LDB) = RUB;
1544
1545 Reflect(LD, LDF) = RUF;
1546 Reflect(LU, LDF) = RUF;
1547 Reflect(RD, LDF) = RUF;
1548 Reflect(RU, LDF) = RUF;
1549
1550 Reflect(LD, LUB) = RDB;
1551 Reflect(LU, LUB) = RDB;
1552 Reflect(RD, LUB) = RDB;
1553 Reflect(RU, LUB) = RDB;
1554
1555 Reflect(LD, LUF) = RDF;
1556 Reflect(LU, LUF) = RDF;
1557 Reflect(RD, LUF) = RDF;
1558 Reflect(RU, LUF) = RDF;
1559
1560
1561 Reflect(LD, RDB) = LUB;
1562 Reflect(LU, RDB) = LUB;
1563 Reflect(RD, RDB) = LUB;
1564 Reflect(RU, RDB) = LUB;
1565
1566 Reflect(LD, RDF) = LUF;
1567 Reflect(LU, RDF) = LUF;
1568 Reflect(RD, RDF) = LUF;
1569 Reflect(RU, RDF) = LUF;
1570
1571 Reflect(LD, RUB) = LDB;
1572 Reflect(LU, RUB) = LDB;
1573 Reflect(RD, RUB) = LDB;
1574 Reflect(RU, RUB) = LDB;
1575
1576 Reflect(LD, RUF) = LDF;
1577 Reflect(LU, RUF) = LDF;
1578 Reflect(RD, RUF) = LDF;
1579 Reflect(RU, RUF) = LDF;
1580
1581
1582 Reflect(LB, LDB) = RDF;
1583 Reflect(LF, LDB) = RDF;
1584 Reflect(RB, LDB) = RDF;
1585 Reflect(RF, LDB) = RDF;
1586
1587 Reflect(LB, LDF) = RDB;
1588 Reflect(LF, LDF) = RDB;
1589 Reflect(RB, LDF) = RDB;
1590 Reflect(RF, LDF) = RDB;
1591
1592 Reflect(LB, LUB) = RUF;
1593 Reflect(LF, LUB) = RUF;
1594 Reflect(RB, LUB) = RUF;
1595 Reflect(RF, LUB) = RUF;
1596
1597 Reflect(LB, LUF) = RUB;
1598 Reflect(LF, LUF) = RUB;
1599 Reflect(RB, LUF) = RUB;
1600 Reflect(RF, LUF) = RUB;
1601
1602 Reflect(LB, RDB) = LDF;
1603 Reflect(LF, RDB) = LDF;
1604 Reflect(RB, RDB) = LDF;
1605 Reflect(RF, RDB) = LDF;
1606
1607 Reflect(LB, RDF) = LDB;
1608 Reflect(LF, RDF) = LDB;
1609 Reflect(RB, RDF) = LDB;
1610 Reflect(RF, RDF) = LDB;
1611
1612 Reflect(LB, RUB) = LUF;
1613 Reflect(LF, RUB) = LUF;
1614 Reflect(RB, RUB) = LUF;
1615 Reflect(RF, RUB) = LUF;
1616
1617 Reflect(LB, RUF) = LUB;
1618 Reflect(LF, RUF) = LUB;
1619 Reflect(RB, RUF) = LUB;
1620 Reflect(RF, RUF) = LUB;
1621
1622
1623 Reflect(DB, LDB) = LUF;
1624 Reflect(DF, LDB) = LUF;
1625 Reflect(UB, LDB) = LUF;
1626 Reflect(UF, LDB) = LUF;
1627
1628 Reflect(DB, LDF) = LUB;
1629 Reflect(DF, LDF) = LUB;
1630 Reflect(UB, LDF) = LUB;
1631 Reflect(UF, LDF) = LUB;
1632
1633 Reflect(DB, LUB) = LDF;
1634 Reflect(DF, LUB) = LDF;
1635 Reflect(UB, LUB) = LDF;
1636 Reflect(UF, LUB) = LDF;
1637
1638 Reflect(DB, LUF) = LDB;
1639 Reflect(DF, LUF) = LDB;
1640 Reflect(UB, LUF) = LDB;
1641 Reflect(UF, LUF) = LDB;
1642
1643 Reflect(DB, RDB) = RUF;
1644 Reflect(DF, RDB) = RUF;
1645 Reflect(UB, RDB) = RUF;
1646 Reflect(UF, RDB) = RUF;
1647
1648 Reflect(DB, RDF) = RUB;
1649 Reflect(DF, RDF) = RUB;
1650 Reflect(UB, RDF) = RUB;
1651 Reflect(UF, RDF) = RUB;
1652
1653 Reflect(DB, RUB) = RDF;
1654 Reflect(DF, RUB) = RDF;
1655 Reflect(UB, RUB) = RDF;
1656 Reflect(UF, RUB) = RDF;
1657
1658 Reflect(DB, RUF) = RDB;
1659 Reflect(DF, RUF) = RDB;
1660 Reflect(UB, RUF) = RDB;
1661 Reflect(UF, RUF) = RDB;
1662
1663
1664 // S_base(i,direction) etc.: Initial value/increment for coordinate s[i] on
1665 // the face indicated by direction (L/R/U/D/F/B)
1666 S_base.resize(3, 27);
1667 S_steplo.resize(3, 27);
1668 S_stephi.resize(3, 27);
1669
1670 S_base(0, L) = -1.0;
1671 S_base(1, L) = -1.0;
1672 S_base(2, L) = -1.0;
1673 S_steplo(0, L) = 0.0;
1674 S_steplo(1, L) = 2.0;
1675 S_steplo(2, L) = 0.0;
1676 S_stephi(0, L) = 0.0;
1677 S_stephi(1, L) = 0.0;
1678 S_stephi(2, L) = 2.0;
1679
1680 S_base(0, R) = 1.0;
1681 S_base(1, R) = -1.0;
1682 S_base(2, R) = -1.0;
1683 S_steplo(0, R) = 0.0;
1684 S_steplo(1, R) = 2.0;
1685 S_steplo(2, R) = 0.0;
1686 S_stephi(0, R) = 0.0;
1687 S_stephi(1, R) = 0.0;
1688 S_stephi(2, R) = 2.0;
1689
1690 S_base(0, U) = -1.0;
1691 S_base(1, U) = 1.0;
1692 S_base(2, U) = -1.0;
1693 S_steplo(0, U) = 2.0;
1694 S_steplo(1, U) = 0.0;
1695 S_steplo(2, U) = 0.0;
1696 S_stephi(0, U) = 0.0;
1697 S_stephi(1, U) = 0.0;
1698 S_stephi(2, U) = 2.0;
1699
1700 S_base(0, D) = -1.0;
1701 S_base(1, D) = -1.0;
1702 S_base(2, D) = -1.0;
1703 S_steplo(0, D) = 2.0;
1704 S_steplo(1, D) = 0.0;
1705 S_steplo(2, D) = 0.0;
1706 S_stephi(0, D) = 0.0;
1707 S_stephi(1, D) = 0.0;
1708 S_stephi(2, D) = 2.0;
1709
1710 S_base(0, F) = -1.0;
1711 S_base(1, F) = -1.0;
1712 S_base(2, F) = 1.0;
1713 S_steplo(0, F) = 2.0;
1714 S_steplo(1, F) = 0.0;
1715 S_steplo(2, F) = 0.0;
1716 S_stephi(0, F) = 0.0;
1717 S_stephi(1, F) = 2.0;
1718 S_stephi(2, F) = 0.0;
1719
1720 S_base(0, B) = -1.0;
1721 S_base(1, B) = -1.0;
1722 S_base(2, B) = -1.0;
1723 S_steplo(0, B) = 2.0;
1724 S_steplo(1, B) = 0.0;
1725 S_steplo(2, B) = 0.0;
1726 S_stephi(0, B) = 0.0;
1727 S_stephi(1, B) = 2.0;
1728 S_stephi(2, B) = 0.0;
1729
1730
1731 // Relative to the left/down/back vertex in any (father) octree, the
1732 // corresponding vertex in the son specified by \c son_octant has an offset.
1733 // If we project the son_octant's left/down/back vertex onto the
1734 // father's face \c face, it is located at the in-face coordinate
1735 // \c s_lo = h/2 \c S_directlo(face,son_octant). [See discussion of
1736 // \c S_steplo for an explanation of the subscripts \c _hi and \c _lo.]
1737 S_directlo.resize(27, 27);
1738 S_directhi.resize(27, 27);
1739
1740 S_directlo(L, LDB) = 0.0;
1741 S_directlo(R, LDB) = 0.0;
1742 S_directlo(U, LDB) = 0.0;
1743 S_directlo(D, LDB) = 0.0;
1744 S_directlo(F, LDB) = 0.0;
1745 S_directlo(B, LDB) = 0.0;
1746
1747 S_directlo(L, LDF) = 0.0;
1748 S_directlo(R, LDF) = 0.0;
1749 S_directlo(U, LDF) = 0.0;
1750 S_directlo(D, LDF) = 0.0;
1751 S_directlo(F, LDF) = 0.0;
1752 S_directlo(B, LDF) = 0.0;
1753
1754 S_directlo(L, LUB) = 1.0;
1755 S_directlo(R, LUB) = 1.0;
1756 S_directlo(U, LUB) = 0.0;
1757 S_directlo(D, LUB) = 0.0;
1758 S_directlo(F, LUB) = 0.0;
1759 S_directlo(B, LUB) = 0.0;
1760
1761 S_directlo(L, LUF) = 1.0;
1762 S_directlo(R, LUF) = 1.0;
1763 S_directlo(U, LUF) = 0.0;
1764 S_directlo(D, LUF) = 0.0;
1765 S_directlo(F, LUF) = 0.0;
1766 S_directlo(B, LUF) = 0.0;
1767
1768 S_directlo(L, RDB) = 0.0;
1769 S_directlo(R, RDB) = 0.0;
1770 S_directlo(U, RDB) = 1.0;
1771 S_directlo(D, RDB) = 1.0;
1772 S_directlo(F, RDB) = 1.0;
1773 S_directlo(B, RDB) = 1.0;
1774
1775 S_directlo(L, RDF) = 0.0;
1776 S_directlo(R, RDF) = 0.0;
1777 S_directlo(U, RDF) = 1.0;
1778 S_directlo(D, RDF) = 1.0;
1779 S_directlo(F, RDF) = 1.0;
1780 S_directlo(B, RDF) = 1.0;
1781
1782 S_directlo(L, RUB) = 1.0;
1783 S_directlo(R, RUB) = 1.0;
1784 S_directlo(U, RUB) = 1.0;
1785 S_directlo(D, RUB) = 1.0;
1786 S_directlo(F, RUB) = 1.0;
1787 S_directlo(B, RUB) = 1.0;
1788
1789 S_directlo(L, RUF) = 1.0;
1790 S_directlo(R, RUF) = 1.0;
1791 S_directlo(U, RUF) = 1.0;
1792 S_directlo(D, RUF) = 1.0;
1793 S_directlo(F, RUF) = 1.0;
1794 S_directlo(B, RUF) = 1.0;
1795
1796
1797 S_directhi(L, LDB) = 0.0;
1798 S_directhi(R, LDB) = 0.0;
1799 S_directhi(U, LDB) = 0.0;
1800 S_directhi(D, LDB) = 0.0;
1801 S_directhi(F, LDB) = 0.0;
1802 S_directhi(B, LDB) = 0.0;
1803
1804 S_directhi(L, LDF) = 1.0;
1805 S_directhi(R, LDF) = 1.0;
1806 S_directhi(U, LDF) = 1.0;
1807 S_directhi(D, LDF) = 1.0;
1808 S_directhi(F, LDF) = 0.0;
1809 S_directhi(B, LDF) = 0.0;
1810
1811 S_directhi(L, LUB) = 0.0;
1812 S_directhi(R, LUB) = 0.0;
1813 S_directhi(U, LUB) = 0.0;
1814 S_directhi(D, LUB) = 0.0;
1815 S_directhi(F, LUB) = 1.0;
1816 S_directhi(B, LUB) = 1.0;
1817
1818 S_directhi(L, LUF) = 1.0;
1819 S_directhi(R, LUF) = 1.0;
1820 S_directhi(U, LUF) = 1.0;
1821 S_directhi(D, LUF) = 1.0;
1822 S_directhi(F, LUF) = 1.0;
1823 S_directhi(B, LUF) = 1.0;
1824
1825 S_directhi(L, RDB) = 0.0;
1826 S_directhi(R, RDB) = 0.0;
1827 S_directhi(U, RDB) = 0.0;
1828 S_directhi(D, RDB) = 0.0;
1829 S_directhi(F, RDB) = 0.0;
1830 S_directhi(B, RDB) = 0.0;
1831
1832 S_directhi(L, RDF) = 1.0;
1833 S_directhi(R, RDF) = 1.0;
1834 S_directhi(U, RDF) = 1.0;
1835 S_directhi(D, RDF) = 1.0;
1836 S_directhi(F, RDF) = 0.0;
1837 S_directhi(B, RDF) = 0.0;
1838
1839 S_directhi(L, RUB) = 0.0;
1840 S_directhi(R, RUB) = 0.0;
1841 S_directhi(U, RUB) = 0.0;
1842 S_directhi(D, RUB) = 0.0;
1843 S_directhi(F, RUB) = 1.0;
1844 S_directhi(B, RUB) = 1.0;
1845
1846 S_directhi(L, RUF) = 1.0;
1847 S_directhi(R, RUF) = 1.0;
1848 S_directhi(U, RUF) = 1.0;
1849 S_directhi(D, RUF) = 1.0;
1850 S_directhi(F, RUF) = 1.0;
1851 S_directhi(B, RUF) = 1.0;
1852
1853
1854 // S_base_edge(i,direction): Initial value/increment for coordinate s[i] on
1855 // the edge indicated by direction (LB,RB,...)
1856 S_base_edge.resize(3, 27);
1857 S_step_edge.resize(3, 27);
1858
1859 S_base_edge(0, LB) = -1.0;
1860 S_base_edge(1, LB) = -1.0;
1861 S_base_edge(2, LB) = -1.0;
1862 S_step_edge(0, LB) = 0.0;
1863 S_step_edge(1, LB) = 2.0;
1864 S_step_edge(2, LB) = 0.0;
1865
1866 S_base_edge(0, RB) = 1.0;
1867 S_base_edge(1, RB) = -1.0;
1868 S_base_edge(2, RB) = -1.0;
1869 S_step_edge(0, RB) = 0.0;
1870 S_step_edge(1, RB) = 2.0;
1871 S_step_edge(2, RB) = 0.0;
1872
1873 S_base_edge(0, DB) = -1.0;
1874 S_base_edge(1, DB) = -1.0;
1875 S_base_edge(2, DB) = -1.0;
1876 S_step_edge(0, DB) = 2.0;
1877 S_step_edge(1, DB) = 0.0;
1878 S_step_edge(2, DB) = 0.0;
1879
1880 S_base_edge(0, UB) = -1.0;
1881 S_base_edge(1, UB) = 1.0;
1882 S_base_edge(2, UB) = -1.0;
1883 S_step_edge(0, UB) = 2.0;
1884 S_step_edge(1, UB) = 0.0;
1885 S_step_edge(2, UB) = 0.0;
1886
1887 S_base_edge(0, LD) = -1.0;
1888 S_base_edge(1, LD) = -1.0;
1889 S_base_edge(2, LD) = -1.0;
1890 S_step_edge(0, LD) = 0.0;
1891 S_step_edge(1, LD) = 0.0;
1892 S_step_edge(2, LD) = 2.0;
1893
1894 S_base_edge(0, RD) = 1.0;
1895 S_base_edge(1, RD) = -1.0;
1896 S_base_edge(2, RD) = -1.0;
1897 S_step_edge(0, RD) = 0.0;
1898 S_step_edge(1, RD) = 0.0;
1899 S_step_edge(2, RD) = 2.0;
1900
1901 S_base_edge(0, LU) = -1.0;
1902 S_base_edge(1, LU) = 1.0;
1903 S_base_edge(2, LU) = -1.0;
1904 S_step_edge(0, LU) = 0.0;
1905 S_step_edge(1, LU) = 0.0;
1906 S_step_edge(2, LU) = 2.0;
1907
1908 S_base_edge(0, RU) = 1.0;
1909 S_base_edge(1, RU) = 1.0;
1910 S_base_edge(2, RU) = -1.0;
1911 S_step_edge(0, RU) = 0.0;
1912 S_step_edge(1, RU) = 0.0;
1913 S_step_edge(2, RU) = 2.0;
1914
1915
1916 S_base_edge(0, LF) = -1.0;
1917 S_base_edge(1, LF) = -1.0;
1918 S_base_edge(2, LF) = 1.0;
1919 S_step_edge(0, LF) = 0.0;
1920 S_step_edge(1, LF) = 2.0;
1921 S_step_edge(2, LF) = 0.0;
1922
1923 S_base_edge(0, RF) = 1.0;
1924 S_base_edge(1, RF) = -1.0;
1925 S_base_edge(2, RF) = 1.0;
1926 S_step_edge(0, RF) = 0.0;
1927 S_step_edge(1, RF) = 2.0;
1928 S_step_edge(2, RF) = 0.0;
1929
1930 S_base_edge(0, DF) = -1.0;
1931 S_base_edge(1, DF) = -1.0;
1932 S_base_edge(2, DF) = 1.0;
1933 S_step_edge(0, DF) = 2.0;
1934 S_step_edge(1, DF) = 0.0;
1935 S_step_edge(2, DF) = 0.0;
1936
1937 S_base_edge(0, UF) = -1.0;
1938 S_base_edge(1, UF) = 1.0;
1939 S_base_edge(2, UF) = 1.0;
1940 S_step_edge(0, UF) = 2.0;
1941 S_step_edge(1, UF) = 0.0;
1942 S_step_edge(2, UF) = 0.0;
1943
1944
1945 // Relative to the left/down/back vertex in any (father) octree, the
1946 // corresponding vertex in the son specified by \c son_octant has an offset.
1947 // If we project the son_octant's left/down/back vertex onto the
1948 // father's edge \c edge, it is located at the in-face coordinate
1949 // \c s_lo = h/2 \c S_direct_edge(edge,son_octant).
1950 S_direct_edge.resize(27, 27);
1951 S_direct_edge(LB, LDB) = 0.0;
1952 S_direct_edge(RB, LDB) = 0.0;
1953 S_direct_edge(DB, LDB) = 0.0;
1954 S_direct_edge(UB, LDB) = 0.0;
1955 S_direct_edge(LD, LDB) = 0.0;
1956 S_direct_edge(RD, LDB) = 0.0;
1957 S_direct_edge(LU, LDB) = 0.0;
1958 S_direct_edge(RU, LDB) = 0.0;
1959 S_direct_edge(LF, LDB) = 0.0;
1960 S_direct_edge(RF, LDB) = 0.0;
1961 S_direct_edge(DF, LDB) = 0.0;
1962 S_direct_edge(UF, LDB) = 0.0;
1963
1964 S_direct_edge(LB, RDB) = 0.0;
1965 S_direct_edge(RB, RDB) = 0.0;
1966 S_direct_edge(DB, RDB) = 1.0;
1967 S_direct_edge(UB, RDB) = 1.0;
1968 S_direct_edge(LD, RDB) = 0.0;
1969 S_direct_edge(RD, RDB) = 0.0;
1970 S_direct_edge(LU, RDB) = 0.0;
1971 S_direct_edge(RU, RDB) = 0.0;
1972 S_direct_edge(LF, RDB) = 0.0;
1973 S_direct_edge(RF, RDB) = 0.0;
1974 S_direct_edge(DF, RDB) = 1.0;
1975 S_direct_edge(UF, RDB) = 1.0;
1976
1977 S_direct_edge(LB, LUB) = 1.0;
1978 S_direct_edge(RB, LUB) = 1.0;
1979 S_direct_edge(DB, LUB) = 0.0;
1980 S_direct_edge(UB, LUB) = 0.0;
1981 S_direct_edge(LD, LUB) = 0.0;
1982 S_direct_edge(RD, LUB) = 0.0;
1983 S_direct_edge(LU, LUB) = 0.0;
1984 S_direct_edge(RU, LUB) = 0.0;
1985 S_direct_edge(LF, LUB) = 1.0;
1986 S_direct_edge(RF, LUB) = 1.0;
1987 S_direct_edge(DF, LUB) = 0.0;
1988 S_direct_edge(UF, LUB) = 0.0;
1989
1990 S_direct_edge(LB, RUB) = 1.0;
1991 S_direct_edge(RB, RUB) = 1.0;
1992 S_direct_edge(DB, RUB) = 1.0;
1993 S_direct_edge(UB, RUB) = 1.0;
1994 S_direct_edge(LD, RUB) = 0.0;
1995 S_direct_edge(RD, RUB) = 0.0;
1996 S_direct_edge(LU, RUB) = 0.0;
1997 S_direct_edge(RU, RUB) = 0.0;
1998 S_direct_edge(LF, RUB) = 1.0;
1999 S_direct_edge(RF, RUB) = 1.0;
2000 S_direct_edge(DF, RUB) = 1.0;
2001 S_direct_edge(UF, RUB) = 1.0;
2002
2003
2004 S_direct_edge(LB, LDF) = 0.0;
2005 S_direct_edge(RB, LDF) = 0.0;
2006 S_direct_edge(DB, LDF) = 0.0;
2007 S_direct_edge(UB, LDF) = 0.0;
2008 S_direct_edge(LD, LDF) = 1.0;
2009 S_direct_edge(RD, LDF) = 1.0;
2010 S_direct_edge(LU, LDF) = 1.0;
2011 S_direct_edge(RU, LDF) = 1.0;
2012 S_direct_edge(LF, LDF) = 0.0;
2013 S_direct_edge(RF, LDF) = 0.0;
2014 S_direct_edge(DF, LDF) = 0.0;
2015 S_direct_edge(UF, LDF) = 0.0;
2016
2017 S_direct_edge(LB, RDF) = 0.0;
2018 S_direct_edge(RB, RDF) = 0.0;
2019 S_direct_edge(DB, RDF) = 1.0;
2020 S_direct_edge(UB, RDF) = 1.0;
2021 S_direct_edge(LD, RDF) = 1.0;
2022 S_direct_edge(RD, RDF) = 1.0;
2023 S_direct_edge(LU, RDF) = 1.0;
2024 S_direct_edge(RU, RDF) = 1.0;
2025 S_direct_edge(LF, RDF) = 0.0;
2026 S_direct_edge(RF, RDF) = 0.0;
2027 S_direct_edge(DF, RDF) = 1.0;
2028 S_direct_edge(UF, RDF) = 1.0;
2029
2030 S_direct_edge(LB, LUF) = 1.0;
2031 S_direct_edge(RB, LUF) = 1.0;
2032 S_direct_edge(DB, LUF) = 0.0;
2033 S_direct_edge(UB, LUF) = 0.0;
2034 S_direct_edge(LD, LUF) = 1.0;
2035 S_direct_edge(RD, LUF) = 1.0;
2036 S_direct_edge(LU, LUF) = 1.0;
2037 S_direct_edge(RU, LUF) = 1.0;
2038 S_direct_edge(LF, LUF) = 1.0;
2039 S_direct_edge(RF, LUF) = 1.0;
2040 S_direct_edge(DF, LUF) = 0.0;
2041 S_direct_edge(UF, LUF) = 0.0;
2042
2043 S_direct_edge(LB, RUF) = 1.0;
2044 S_direct_edge(RB, RUF) = 1.0;
2045 S_direct_edge(DB, RUF) = 1.0;
2046 S_direct_edge(UB, RUF) = 1.0;
2047 S_direct_edge(LD, RUF) = 1.0;
2048 S_direct_edge(RD, RUF) = 1.0;
2049 S_direct_edge(LU, RUF) = 1.0;
2050 S_direct_edge(RU, RUF) = 1.0;
2051 S_direct_edge(LF, RUF) = 1.0;
2052 S_direct_edge(RF, RUF) = 1.0;
2053 S_direct_edge(DF, RUF) = 1.0;
2054 S_direct_edge(UF, RUF) = 1.0;
2055
2056
2057 // Public static data:
2058 //-------------------
2059
2060 // Translate (enumerated) directions into strings
2061 Direct_string.resize(27);
2062 Direct_string[LDB] = "LDB";
2063 Direct_string[LDF] = "LDF";
2064 Direct_string[LUB] = "LUB";
2065 Direct_string[LUF] = "LUF";
2066 Direct_string[RDB] = "RDB";
2067 Direct_string[RDF] = "RDF";
2068 Direct_string[RUB] = "RUB";
2069 Direct_string[RUF] = "RUF";
2070
2071
2072 Direct_string[L] = "L";
2073 Direct_string[R] = "R";
2074 Direct_string[U] = "U";
2075 Direct_string[D] = "D";
2076 Direct_string[F] = "F";
2077 Direct_string[B] = "B";
2078
2079 Direct_string[LU] = "LU";
2080 Direct_string[LD] = "LD";
2081 Direct_string[LF] = "LF";
2082 Direct_string[LB] = "LB";
2083 Direct_string[RU] = "RU";
2084 Direct_string[RD] = "RD";
2085 Direct_string[RF] = "RF";
2086 Direct_string[RB] = "RB";
2087 Direct_string[UF] = "UF";
2088 Direct_string[UB] = "UB";
2089 Direct_string[DF] = "DF";
2090 Direct_string[DB] = "DB";
2091
2092 Direct_string[OMEGA] = "OMEGA";
2093
2094
2095 // Get opposite face, e.g. Reflect_face(L)=R
2096 Reflect_face.resize(27);
2097 Reflect_face[L] = R;
2098 Reflect_face[R] = L;
2099 Reflect_face[U] = D;
2100 Reflect_face[D] = U;
2101 Reflect_face[B] = F;
2102 Reflect_face[F] = B;
2103
2104 // Get opposite edge, e.g. Reflect_edge(DB)=UF
2105 Reflect_edge.resize(27);
2106 Reflect_edge[LB] = RF;
2107 Reflect_edge[RB] = LF;
2108 Reflect_edge[DB] = UF;
2109 Reflect_edge[UB] = DF;
2110
2111 Reflect_edge[LD] = RU;
2112 Reflect_edge[RD] = LU;
2113 Reflect_edge[LU] = RD;
2114 Reflect_edge[RU] = LD;
2115
2116 Reflect_edge[LF] = RB;
2117 Reflect_edge[RF] = LB;
2118 Reflect_edge[DF] = UB;
2119 Reflect_edge[UF] = DB;
2120
2121 // Get opposite vertex, e.g. Reflect_vertex(LDB)=RUF
2122 Reflect_vertex.resize(27);
2123 Reflect_vertex[LDB] = RUF;
2124 Reflect_vertex[RUF] = LDB;
2125 Reflect_vertex[RDB] = LUF;
2126 Reflect_vertex[LUF] = RDB;
2127 Reflect_vertex[LUB] = RDF;
2128 Reflect_vertex[RDF] = LUB;
2129 Reflect_vertex[RUB] = LDF;
2130 Reflect_vertex[LDF] = RUB;
2131
2132
2133 // Vertices at ends of edges
2134 Vertex_at_end_of_edge.resize(27);
2135
2136 Vertex_at_end_of_edge[DB].resize(2);
2137 Vertex_at_end_of_edge[DB][0] = LDB; // Pattern: both other indices
2138 Vertex_at_end_of_edge[DB][1] = RDB;
2139
2140 Vertex_at_end_of_edge[UB].resize(2);
2141 Vertex_at_end_of_edge[UB][0] = LUB; // Pattern: both other indices
2142 Vertex_at_end_of_edge[UB][1] = RUB;
2143
2144
2145 Vertex_at_end_of_edge[LB].resize(2);
2146 Vertex_at_end_of_edge[LB][0] = LUB; // Pattern: both other indices
2147 Vertex_at_end_of_edge[LB][1] = LDB;
2148
2149 Vertex_at_end_of_edge[RB].resize(2);
2150 Vertex_at_end_of_edge[RB][0] = RUB; // Pattern: both other indices
2151 Vertex_at_end_of_edge[RB][1] = RDB;
2152
2153
2154 Vertex_at_end_of_edge[LD].resize(2);
2155 Vertex_at_end_of_edge[LD][0] = LDF; // Pattern: both other indices
2156 Vertex_at_end_of_edge[LD][1] = LDB;
2157
2158 Vertex_at_end_of_edge[RD].resize(2);
2159 Vertex_at_end_of_edge[RD][0] = RDF; // Pattern: both other indices
2160 Vertex_at_end_of_edge[RD][1] = RDB;
2161
2162 Vertex_at_end_of_edge[LU].resize(2);
2163 Vertex_at_end_of_edge[LU][0] = LUF; // Pattern: both other indices
2164 Vertex_at_end_of_edge[LU][1] = LUB;
2165
2166 Vertex_at_end_of_edge[RU].resize(2);
2167 Vertex_at_end_of_edge[RU][0] = RUF; // Pattern: both other indices
2168 Vertex_at_end_of_edge[RU][1] = RUB;
2169
2170
2171 Vertex_at_end_of_edge[DF].resize(2);
2172 Vertex_at_end_of_edge[DF][0] = LDF; // Pattern: both other indices
2173 Vertex_at_end_of_edge[DF][1] = RDF;
2174
2175 Vertex_at_end_of_edge[UF].resize(2);
2176 Vertex_at_end_of_edge[UF][0] = LUF; // Pattern: both other indices
2177 Vertex_at_end_of_edge[UF][1] = RUF;
2178
2179 Vertex_at_end_of_edge[LF].resize(2);
2180 Vertex_at_end_of_edge[LF][0] = LUF; // Pattern: both other indices
2181 Vertex_at_end_of_edge[LF][1] = LDF;
2182
2183 Vertex_at_end_of_edge[RF].resize(2);
2184 Vertex_at_end_of_edge[RF][0] = RUF; // Pattern: both other indices
2185 Vertex_at_end_of_edge[RF][1] = RDF;
2186
2187
2188 // Initialisation of the values of Vector_to_direction
2189 Vector<int> vect(3);
2190 int elem;
2191
2192 for (int i = -1; i < 2; i++)
2193 {
2194 for (int j = -1; j < 2; j++)
2195 {
2196 for (int k = -1; k < 2; k++)
2197 {
2198 vect[0] = i;
2199 vect[1] = j;
2200 vect[2] = k;
2201 int num_elem = 0;
2202
2203 // To put a number on the vector (i,j,k), we assume that that
2204 // the vector (i+1,j+1,k+1) represents the decomposition
2205 // of the number of the corresponding direction in base 3.
2206 num_elem = (i + 1) * 9 + (j + 1) * 3 + (k + 1);
2207
2208 // for each number we have the corresponding element
2209 switch (num_elem)
2210 {
2211 case 6:
2212 elem = LUB;
2213 break;
2214 case 24:
2215 elem = RUB;
2216 break;
2217 case 26:
2218 elem = RUF;
2219 break;
2220 case 8:
2221 elem = LUF;
2222 break;
2223 case 0:
2224 elem = LDB;
2225 break;
2226 case 18:
2227 elem = RDB;
2228 break;
2229 case 20:
2230 elem = RDF;
2231 break;
2232 case 2:
2233 elem = LDF;
2234 break;
2235 case 25:
2236 elem = RU;
2237 break;
2238 case 23:
2239 elem = RF;
2240 break;
2241 case 19:
2242 elem = RD;
2243 break;
2244 case 21:
2245 elem = RB;
2246 break;
2247 case 7:
2248 elem = LU;
2249 break;
2250 case 5:
2251 elem = LF;
2252 break;
2253 case 1:
2254 elem = LD;
2255 break;
2256 case 3:
2257 elem = LB;
2258 break;
2259 case 17:
2260 elem = UF;
2261 break;
2262 case 15:
2263 elem = UB;
2264 break;
2265 case 11:
2266 elem = DF;
2267 break;
2268 case 9:
2269 elem = DB;
2270 break;
2271 case 16:
2272 elem = U;
2273 break;
2274 case 10:
2275 elem = D;
2276 break;
2277 case 22:
2278 elem = R;
2279 break;
2280 case 4:
2281 elem = L;
2282 break;
2283 case 14:
2284 elem = F;
2285 break;
2286 case 12:
2287 elem = B;
2288 break;
2289 case 13:
2290 elem = OMEGA;
2291 break;
2292 default:
2293 elem = OMEGA;
2294 oomph_info << "there might be a problem with Vector_to_direction"
2295 << std::endl;
2296 break;
2297 }
2299 }
2300 }
2301 }
2302
2303
2304 // Initialisation of Direction_to_vector:
2305 // Translate Octant, face, edge into direction vector using the
2306 // value of Direct_string; Direction_to_vector[U]={0,1,0};
2307 Direction_to_vector.resize(27);
2308 for (int i = LDB; i <= F; i++)
2309 {
2310 Direction_to_vector[i].resize(3);
2311 // Initialisation to 0;
2312 for (int j = 0; j < 3; j++)
2313 {
2314 Direction_to_vector[i][j] = 0;
2315 }
2316
2317 // Use +1 or -1 to indicate the relevant components of
2318 // the vector Direction
2319 for (unsigned j = 0; j < 3; j++)
2320 {
2321 if (Direct_string[i].length() > j)
2322 {
2323 switch (Direct_string[i][j])
2324 {
2325 case 'R':
2326 Direction_to_vector[i][0] = 1;
2327 break;
2328 case 'L':
2329 Direction_to_vector[i][0] = -1;
2330 break;
2331 case 'U':
2332 Direction_to_vector[i][1] = 1;
2333 break;
2334 case 'D':
2335 Direction_to_vector[i][1] = -1;
2336 break;
2337 case 'F':
2338 Direction_to_vector[i][2] = 1;
2339 break;
2340 case 'B':
2341 Direction_to_vector[i][2] = -1;
2342 break;
2343 default:
2344 oomph_info << "Direction Error !!" << std::endl;
2345 }
2346 }
2347 }
2348 }
2349
2350
2351 // Setup map that works out required rotations based on
2352 //-----------------------------------------------------
2353 // adjacent edge vertices
2354 //-----------------------
2355
2356 int new_up, new_right;
2357 int new_vertex;
2358
2359
2360 // Map that stores the set of rotations (as a pairs consisting of
2361 // the up_equivalent and the right_equivalent) that move the vertex
2362 // specified by the first entry in key pair to the position of the second
2363 // one:
2364 std::map<std::pair<int, int>, std::set<std::pair<int, int>>>
2366
2367 // Loop over all vertices
2368 for (int vertex = LDB; vertex <= RUF; vertex++)
2369 {
2370 new_up = U;
2371 new_right = R;
2373 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2374 std::make_pair(new_up, new_right));
2375
2376 new_up = U;
2377 new_right = B;
2379 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2380 std::make_pair(new_up, new_right));
2381
2382 new_up = U;
2383 new_right = L;
2385 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2386 std::make_pair(new_up, new_right));
2387
2388 new_up = U;
2389 new_right = F;
2391 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2392 std::make_pair(new_up, new_right));
2393
2394
2395 new_up = D;
2396 new_right = R;
2398 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2399 std::make_pair(new_up, new_right));
2400
2401 new_up = D;
2402 new_right = B;
2404 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2405 std::make_pair(new_up, new_right));
2406
2407 new_up = D;
2408 new_right = L;
2410 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2411 std::make_pair(new_up, new_right));
2412
2413 new_up = D;
2414 new_right = F;
2416 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2417 std::make_pair(new_up, new_right));
2418
2419
2420 new_up = R;
2421 new_right = D;
2423 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2424 std::make_pair(new_up, new_right));
2425
2426 new_up = R;
2427 new_right = B;
2429 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2430 std::make_pair(new_up, new_right));
2431
2432 new_up = R;
2433 new_right = U;
2435 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2436 std::make_pair(new_up, new_right));
2437
2438 new_up = R;
2439 new_right = F;
2441 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2442 std::make_pair(new_up, new_right));
2443
2444
2445 new_up = L;
2446 new_right = D;
2448 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2449 std::make_pair(new_up, new_right));
2450
2451 new_up = L;
2452 new_right = B;
2454 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2455 std::make_pair(new_up, new_right));
2456
2457 new_up = L;
2458 new_right = U;
2460 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2461 std::make_pair(new_up, new_right));
2462
2463 new_up = L;
2464 new_right = F;
2466 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2467 std::make_pair(new_up, new_right));
2468
2469
2470 new_up = F;
2471 new_right = R;
2473 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2474 std::make_pair(new_up, new_right));
2475
2476 new_up = F;
2477 new_right = L;
2479 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2480 std::make_pair(new_up, new_right));
2481
2482 new_up = F;
2483 new_right = U;
2485 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2486 std::make_pair(new_up, new_right));
2487
2488 new_up = F;
2489 new_right = D;
2491 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2492 std::make_pair(new_up, new_right));
2493
2494
2495 new_up = B;
2496 new_right = R;
2498 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2499 std::make_pair(new_up, new_right));
2500
2501 new_up = B;
2502 new_right = L;
2504 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2505 std::make_pair(new_up, new_right));
2506
2507 new_up = B;
2508 new_right = U;
2510 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2511 std::make_pair(new_up, new_right));
2512
2513 new_up = B;
2514 new_right = D;
2516 required_rotation[std::make_pair(vertex, new_vertex)].insert(
2517 std::make_pair(new_up, new_right));
2518 }
2519
2520
2521 // Each vertex is part of three edges. This container stores the
2522 // vertices in each of the three edge neighbours that are
2523 // adjacent to this node if there's no relative rotation between
2524 // the elements.
2525 std::map<int, Vector<int>> vertex_in_edge_neighbour;
2526
2527
2528 // Each vertex is part of three edges. This container stores the
2529 // vertices at the other end of the edge
2530 std::map<int, Vector<int>> other_vertex_on_edge;
2531
2532 // Each vertex is part of three edges. This container stores the
2533 // vertices in the adjacent element at the other end of the edge
2534 // assuming there are no rotations between the elements.
2535 std::map<int, Vector<int>> other_vertex_in_edge_neighbour;
2536
2537
2538 vertex_in_edge_neighbour[LDB].resize(3);
2539 vertex_in_edge_neighbour[LDB][0] =
2540 LUF; // Pattern: exactly one letter matches
2541 vertex_in_edge_neighbour[LDB][1] = RDF;
2542 vertex_in_edge_neighbour[LDB][2] = RUB;
2543
2544 other_vertex_on_edge[LDB].resize(3);
2545 other_vertex_on_edge[LDB][0] =
2546 RDB; // Pattern: opposite of the matching letter
2547 other_vertex_on_edge[LDB][1] = LUB;
2548 other_vertex_on_edge[LDB][2] = LDF;
2549
2550 other_vertex_in_edge_neighbour[LDB].resize(3);
2551 other_vertex_in_edge_neighbour[LDB][0] = RUF; // Pattern: full reflection
2552 other_vertex_in_edge_neighbour[LDB][1] = RUF;
2553 other_vertex_in_edge_neighbour[LDB][2] = RUF;
2554
2555
2556 vertex_in_edge_neighbour[RDB].resize(3);
2557 vertex_in_edge_neighbour[RDB][0] =
2558 RUF; // Pattern: exactly one letter matches
2559 vertex_in_edge_neighbour[RDB][1] = LDF;
2560 vertex_in_edge_neighbour[RDB][2] = LUB;
2561
2562 other_vertex_on_edge[RDB].resize(3);
2563 other_vertex_on_edge[RDB][0] =
2564 LDB; // Pattern: opposite of the matching letter
2565 other_vertex_on_edge[RDB][1] = RUB;
2566 other_vertex_on_edge[RDB][2] = RDF;
2567
2568 other_vertex_in_edge_neighbour[RDB].resize(3);
2569 other_vertex_in_edge_neighbour[RDB][0] = LUF; // Pattern: full reflection
2570 other_vertex_in_edge_neighbour[RDB][1] = LUF;
2571 other_vertex_in_edge_neighbour[RDB][2] = LUF;
2572
2573
2574 vertex_in_edge_neighbour[LUB].resize(3);
2575 vertex_in_edge_neighbour[LUB][0] =
2576 LDF; // Pattern: exactly one letter matches
2577 vertex_in_edge_neighbour[LUB][1] = RUF;
2578 vertex_in_edge_neighbour[LUB][2] = RDB;
2579
2580 other_vertex_on_edge[LUB].resize(3);
2581 other_vertex_on_edge[LUB][0] =
2582 RUB; // Pattern: opposite of the matching letter
2583 other_vertex_on_edge[LUB][1] = LDB;
2584 other_vertex_on_edge[LUB][2] = LUF;
2585
2586 other_vertex_in_edge_neighbour[LUB].resize(3);
2587 other_vertex_in_edge_neighbour[LUB][0] = RDF; // Pattern: full reflection
2588 other_vertex_in_edge_neighbour[LUB][1] = RDF;
2589 other_vertex_in_edge_neighbour[LUB][2] = RDF;
2590
2591
2592 vertex_in_edge_neighbour[RUB].resize(3);
2593 vertex_in_edge_neighbour[RUB][0] =
2594 RDF; // Pattern: exactly one letter matches
2595 vertex_in_edge_neighbour[RUB][1] = LUF;
2596 vertex_in_edge_neighbour[RUB][2] = LDB;
2597
2598 other_vertex_on_edge[RUB].resize(3);
2599 other_vertex_on_edge[RUB][0] =
2600 LUB; // Pattern: opposite of the matching letter
2601 other_vertex_on_edge[RUB][1] = RDB;
2602 other_vertex_on_edge[RUB][2] = RUF;
2603
2604 other_vertex_in_edge_neighbour[RUB].resize(3);
2605 other_vertex_in_edge_neighbour[RUB][0] = LDF; // Pattern: full reflection
2606 other_vertex_in_edge_neighbour[RUB][1] = LDF;
2607 other_vertex_in_edge_neighbour[RUB][2] = LDF;
2608
2609
2610 vertex_in_edge_neighbour[LDF].resize(3);
2611 vertex_in_edge_neighbour[LDF][0] =
2612 LUB; // Pattern: exactly one letter matches
2613 vertex_in_edge_neighbour[LDF][1] = RDB;
2614 vertex_in_edge_neighbour[LDF][2] = RUF;
2615
2616 other_vertex_on_edge[LDF].resize(3);
2617 other_vertex_on_edge[LDF][0] =
2618 RDF; // Pattern: opposite of the matching letter
2619 other_vertex_on_edge[LDF][1] = LUF;
2620 other_vertex_on_edge[LDF][2] = LDB;
2621
2622 other_vertex_in_edge_neighbour[LDF].resize(3);
2623 other_vertex_in_edge_neighbour[LDF][0] = RUB; // Pattern: full reflection
2624 other_vertex_in_edge_neighbour[LDF][1] = RUB;
2625 other_vertex_in_edge_neighbour[LDF][2] = RUB;
2626
2627
2628 vertex_in_edge_neighbour[RDF].resize(3);
2629 vertex_in_edge_neighbour[RDF][0] =
2630 RUB; // Pattern: exactly one letter matches
2631 vertex_in_edge_neighbour[RDF][1] = LDB;
2632 vertex_in_edge_neighbour[RDF][2] = LUF;
2633
2634 other_vertex_on_edge[RDF].resize(3);
2635 other_vertex_on_edge[RDF][0] =
2636 LDF; // Pattern: opposite of the matching letter
2637 other_vertex_on_edge[RDF][1] = RUF;
2638 other_vertex_on_edge[RDF][2] = RDB;
2639
2640 other_vertex_in_edge_neighbour[RDF].resize(3);
2641 other_vertex_in_edge_neighbour[RDF][0] = LUB; // Pattern: full reflection
2642 other_vertex_in_edge_neighbour[RDF][1] = LUB;
2643 other_vertex_in_edge_neighbour[RDF][2] = LUB;
2644
2645
2646 vertex_in_edge_neighbour[LUF].resize(3);
2647 vertex_in_edge_neighbour[LUF][0] =
2648 LDB; // Pattern: exactly one letter matches
2649 vertex_in_edge_neighbour[LUF][1] = RUB;
2650 vertex_in_edge_neighbour[LUF][2] = RDF;
2651
2652 other_vertex_on_edge[LUF].resize(3);
2653 other_vertex_on_edge[LUF][0] =
2654 RUF; // Pattern: opposite of the matching letter
2655 other_vertex_on_edge[LUF][1] = LDF;
2656 other_vertex_on_edge[LUF][2] = LUB;
2657
2658 other_vertex_in_edge_neighbour[LUF].resize(3);
2659 other_vertex_in_edge_neighbour[LUF][0] = RDB; // Pattern: full reflection
2660 other_vertex_in_edge_neighbour[LUF][1] = RDB;
2661 other_vertex_in_edge_neighbour[LUF][2] = RDB;
2662
2663
2664 vertex_in_edge_neighbour[RUF].resize(3);
2665 vertex_in_edge_neighbour[RUF][0] =
2666 RDB; // Pattern: exactly one letter matches
2667 vertex_in_edge_neighbour[RUF][1] = LUB;
2668 vertex_in_edge_neighbour[RUF][2] = LDF;
2669
2670 other_vertex_on_edge[RUF].resize(3);
2671 other_vertex_on_edge[RUF][0] =
2672 LUF; // Pattern: opposite of the matching letter
2673 other_vertex_on_edge[RUF][1] = RDF;
2674 other_vertex_on_edge[RUF][2] = RUB;
2675
2676 other_vertex_in_edge_neighbour[RUF].resize(3);
2677 other_vertex_in_edge_neighbour[RUF][0] = LDB; // Pattern: full reflection
2678 other_vertex_in_edge_neighbour[RUF][1] = LDB;
2679 other_vertex_in_edge_neighbour[RUF][2] = LDB;
2680
2681
2682 // Loop over all vertices in the reference element
2683 for (int vertex = LDB; vertex <= RUF; vertex++)
2684 {
2685 // Loop over the three edges that are connected to this vertex
2686 for (unsigned i = 0; i < 3; i++)
2687 {
2688 // This is the other vertex along this edge
2690
2691 // This is the vertex in the edge neighbour that corresponds
2692 // to the present vertex in the reference element (in
2693 // the absence of rotations)
2695
2696 // This is the vertex in the edge neighbour that corresponds
2697 // to the other vertex in the reference element (in
2698 // the absence of rotations)
2701
2702 // Loop over all vertices in the neighbour element
2703 for (int neigh_vertex = LDB; neigh_vertex <= RUF; neigh_vertex++)
2704 {
2705 // What rotations would turn the neigh_vertex
2706 // into the unrotated_neigh_vertex?
2707 std::set<std::pair<int, int>> vertex_rot =
2708 required_rotation[std::make_pair(neigh_vertex,
2710
2711
2712 // Loop over all "other" vertices in the neighbour element
2713 for (int neigh_other_vertex = LDB; neigh_other_vertex <= RUF;
2715 {
2716 // What rotations would turn the other_neigh_vertex
2717 // into the unrotated_other_neigh_vertex?
2718 std::set<std::pair<int, int>> other_vertex_rot =
2721
2722 // What are the common rotations?
2723 std::set<std::pair<int, int>> common_rotations;
2724
2725 // Get the intersection of the two sets
2726 std::set_intersection(
2727 vertex_rot.begin(),
2728 vertex_rot.end(),
2729 other_vertex_rot.begin(),
2730 other_vertex_rot.end(),
2732
2733
2734 if (common_rotations.size() > 0)
2735 {
2736 for (std::set<std::pair<int, int>>::iterator it =
2737 common_rotations.begin();
2738 it != common_rotations.end();
2739 it++)
2740 {
2741 // Copy into container
2742
2743 // First: up equivalent:
2745 [std::make_pair(
2746 std::make_pair(vertex, neigh_vertex),
2747 std::make_pair(other_vertex, neigh_other_vertex))]
2748 .first = it->first;
2749
2750 // Second: Right equivalent
2752 [std::make_pair(
2753 std::make_pair(vertex, neigh_vertex),
2754 std::make_pair(other_vertex, neigh_other_vertex))]
2755 .second = it->second;
2756 }
2757 }
2758 }
2759 }
2760 }
2761 }
2762 }
2763
2764
2765 //================================================================
2766 /// Is the edge neighbour (for edge "edge") specified via the pointer
2767 /// also a face neighbour for one of the two adjacent faces?
2768 //================================================================
2770 OcTree* edge_neigh_pt) const
2771 {
2772#ifdef PARANOID
2773 // No paranoid check needed -- the default for the switch statement
2774 // catches illegal values for edge
2775#endif
2776
2777
2778 // Catch stupid case: Null doesn't have a face neighbour...
2779 if (edge_neigh_pt == 0)
2780 {
2781 return false;
2782 }
2783
2784 using namespace OcTreeNames;
2785
2786 // Auxiliary variables
2787 int face;
2791 int reflected_face;
2792 int diff_level;
2793 bool in_neighbouring_tree = false;
2794
2795 OcTree* face_neigh_pt = 0;
2796
2797 switch (edge)
2798 {
2799 case LB:
2800
2801 // Get first face neighbour
2802 face = L;
2805 s_sw,
2806 s_ne,
2808 diff_level,
2810
2811 // Check if they agree...
2812 if (face_neigh_pt != 0)
2813 {
2815 {
2816 return true;
2817 }
2818 }
2819
2820 // Get second face neighbour
2821 face = B;
2824 s_sw,
2825 s_ne,
2827 diff_level,
2829
2830 // Check if they agree...
2831 if (face_neigh_pt != 0)
2832 {
2834 {
2835 return true;
2836 }
2837 }
2838
2839 break;
2840
2841
2842 case RB:
2843
2844
2845 // Get first face neighbour
2846 face = R;
2849 s_sw,
2850 s_ne,
2852 diff_level,
2854
2855 // Check if they agree...
2856 if (face_neigh_pt != 0)
2857 {
2859 {
2860 return true;
2861 }
2862 }
2863
2864 // Get second face neighbour
2865 face = B;
2868 s_sw,
2869 s_ne,
2871 diff_level,
2873 // Check if they agree...
2874 if (face_neigh_pt != 0)
2875 {
2877 {
2878 return true;
2879 }
2880 }
2881
2882 break;
2883
2884
2885 case DB:
2886
2887 // Get first face neighbour
2888 face = D;
2891 s_sw,
2892 s_ne,
2894 diff_level,
2896
2897 // Check if they agree...
2898 if (face_neigh_pt != 0)
2899 {
2901 {
2902 return true;
2903 }
2904 }
2905
2906 // Get second face neighbour
2907 face = B;
2910 s_sw,
2911 s_ne,
2913 diff_level,
2915 // Check if they agree...
2916 if (face_neigh_pt != 0)
2917 {
2919 {
2920 return true;
2921 }
2922 }
2923
2924 break;
2925
2926
2927 case UB:
2928
2929 // Get first face neighbour
2930 face = U;
2933 s_sw,
2934 s_ne,
2936 diff_level,
2938
2939 // Check if they agree...
2940 if (face_neigh_pt != 0)
2941 {
2943 {
2944 return true;
2945 }
2946 }
2947
2948 // Get second face neighbour
2949 face = B;
2952 s_sw,
2953 s_ne,
2955 diff_level,
2957
2958 // Check if they agree...
2959 if (face_neigh_pt != 0)
2960 {
2962 {
2963 return true;
2964 }
2965 }
2966
2967 break;
2968
2969 case LD:
2970
2971
2972 // Get first face neighbour
2973 face = L;
2976 s_sw,
2977 s_ne,
2979 diff_level,
2981
2982 // Check if they agree...
2983 if (face_neigh_pt != 0)
2984 {
2986 {
2987 return true;
2988 }
2989 }
2990
2991 // Get second face neighbour
2992 face = D;
2995 s_sw,
2996 s_ne,
2998 diff_level,
3000 // Check if they agree...
3001 if (face_neigh_pt != 0)
3002 {
3004 {
3005 return true;
3006 }
3007 }
3008
3009 break;
3010
3011 case RD:
3012
3013
3014 // Get first face neighbour
3015 face = R;
3018 s_sw,
3019 s_ne,
3021 diff_level,
3023
3024 // Check if they agree...
3025 if (face_neigh_pt != 0)
3026 {
3028 {
3029 return true;
3030 }
3031 }
3032
3033 // Get second face neighbour
3034 face = D;
3037 s_sw,
3038 s_ne,
3040 diff_level,
3042 // Check if they agree...
3043 if (face_neigh_pt != 0)
3044 {
3046 {
3047 return true;
3048 }
3049 }
3050
3051 break;
3052
3053 case LU:
3054
3055 // Get first face neighbour
3056 face = L;
3059 s_sw,
3060 s_ne,
3062 diff_level,
3064
3065 // Check if they agree...
3066 if (face_neigh_pt != 0)
3067 {
3069 {
3070 return true;
3071 }
3072 }
3073
3074 // Get second face neighbour
3075 face = U;
3078 s_sw,
3079 s_ne,
3081 diff_level,
3083
3084 // Check if they agree...
3085 if (face_neigh_pt != 0)
3086 {
3088 {
3089 return true;
3090 }
3091 }
3092
3093 break;
3094
3095
3096 case RU:
3097
3098 // Get first face neighbour
3099 face = R;
3102 s_sw,
3103 s_ne,
3105 diff_level,
3107
3108 // Check if they agree...
3109 if (face_neigh_pt != 0)
3110 {
3112 {
3113 return true;
3114 }
3115 }
3116
3117 // Get second face neighbour
3118 face = U;
3121 s_sw,
3122 s_ne,
3124 diff_level,
3126
3127 // Check if they agree...
3128 if (face_neigh_pt != 0)
3129 {
3131 {
3132 return true;
3133 }
3134 }
3135
3136 break;
3137
3138
3139 case LF:
3140
3141
3142 // Get first face neighbour
3143 face = L;
3146 s_sw,
3147 s_ne,
3149 diff_level,
3151
3152 // Check if they agree...
3153 if (face_neigh_pt != 0)
3154 {
3156 {
3157 return true;
3158 }
3159 }
3160
3161 // Get second face neighbour
3162 face = F;
3165 s_sw,
3166 s_ne,
3168 diff_level,
3170
3171 // Check if they agree...
3172 if (face_neigh_pt != 0)
3173 {
3175 {
3176 return true;
3177 }
3178 }
3179
3180 break;
3181
3182 case RF:
3183
3184 // Get first face neighbour
3185 face = R;
3188 s_sw,
3189 s_ne,
3191 diff_level,
3193
3194 // Check if they agree...
3195 if (face_neigh_pt != 0)
3196 {
3198 {
3199 return true;
3200 }
3201 }
3202
3203 // Get second face neighbour
3204 face = F;
3207 s_sw,
3208 s_ne,
3210 diff_level,
3212
3213 // Check if they agree...
3214 if (face_neigh_pt != 0)
3215 {
3217 {
3218 return true;
3219 }
3220 }
3221
3222 break;
3223
3224
3225 case DF:
3226
3227 // Get first face neighbour
3228 face = D;
3231 s_sw,
3232 s_ne,
3234 diff_level,
3236
3237 // Check if they agree...
3238 if (face_neigh_pt != 0)
3239 {
3241 {
3242 return true;
3243 }
3244 }
3245
3246
3247 // Get second face neighbour
3248 face = F;
3251 s_sw,
3252 s_ne,
3254 diff_level,
3256
3257 // Check if they agree...
3258 if (face_neigh_pt != 0)
3259 {
3261 {
3262 return true;
3263 }
3264 }
3265
3266 break;
3267
3268
3269 case UF:
3270
3271 // Get first face neighbour
3272 face = U;
3275 s_sw,
3276 s_ne,
3278 diff_level,
3280
3281 // Check if they agree...
3282 if (face_neigh_pt != 0)
3283 {
3285 {
3286 return true;
3287 }
3288 }
3289
3290
3291 // Get second face neighbour
3292 face = F;
3295 s_sw,
3296 s_ne,
3298 diff_level,
3300
3301 // Check if they agree...
3302 if (face_neigh_pt != 0)
3303 {
3305 {
3306 return true;
3307 }
3308 }
3309
3310 break;
3311
3312 default:
3313
3314 // There is no face neighbour in this direction so they can't
3315 // agree:
3316 std::ostringstream error_stream;
3317 error_stream << "Never get here! Edge:" << Direct_string[edge] << " "
3318 << edge << std::endl;
3319 throw OomphLibError(
3321 }
3322
3323 // If we've made it to here then we've located the requested edge
3324 // but found that none of its two face neighbours match the specified
3325 // edge neighbour:
3326 return false;
3327 }
3328
3329
3330 //================================================================
3331 /// Find (pointer to) `greater-or-equal-sized face neighbour' in
3332 /// given direction (L/R/U/D/F/B).
3333 /// Another way of interpreting this is that we're looking for
3334 /// the neighbour across the present element's face 'direction'.
3335 /// The various arguments return additional information about the
3336 /// size and relative orientation of the neighbouring octree.
3337 /// To interpret these we use the following
3338 /// <B>General convention:</B>
3339 /// - Each face of the element that is represented by the octree
3340 /// is parametrised by two (of the three)
3341 /// local coordinates that parametrise the entire 3D element. E.g.
3342 /// the B[ack] face is parametrised by (s[0], s[1]); the D[own] face
3343 /// is parametrised by (s[0],s[2]); etc. We always identify the
3344 /// in-face coordinate with the lower (3D) index with the subscript
3345 /// _lo and the one with the larger (3D) index with the subscript _hi.
3346 /// .
3347 /// With this convention, the interpretation of the arguments is
3348 /// as follows:
3349 /// - The vector \c translate_s turns the index of the local coordinate
3350 /// in the present octree into that of the neighbour. If there are no
3351 /// rotations then \c translate_s[i] = i.
3352 /// - In the present octree, the "south west" vertex of the face
3353 /// between the present octree and its neighbour is located at
3354 /// S_lo=-1, S_hi=-1. This point is located at the (3D) local
3355 /// coordinates (\c s_sw[0], \c s_sw[1], \c s_sw[2])
3356 /// in the neighbouring octree.
3357 /// - ditto with s_ne: In the present octree, the "north east" vertex
3358 /// of the face between the present octree and its neighbour is located at
3359 /// S_lo=+1, S_hi=+1. This point is located
3360 /// at the (3D) local coordinates (\c s_ne[0], \c s_ne[1], \c s_ne[2])
3361 /// in the neighbouring octree.
3362 /// - We're looking for a neighbour in the specified \c direction. When
3363 /// viewed from the neighbouring octree, the face that separates
3364 /// the present octree from its neighbour is the neighbour's face
3365 /// \c face. If there's no rotation between the two octrees, this is a
3366 /// simple reflection: For instance, if we're looking
3367 /// for a neighhbour in the \c R [ight] \c direction, \c face will
3368 /// be \c L [eft]
3369 /// - \c diff_level <= 0 indicates the difference in refinement levels between
3370 /// the two neighbours. If \c diff_level==0, the neighbour has the
3371 /// same size as the current octree.
3372 //=================================================================
3377 int& face,
3378 int& diff_level,
3379 bool& in_neighbouring_tree) const
3380 {
3381 using namespace OcTreeNames;
3382
3383#ifdef PARANOID
3384 if ((direction != L) && (direction != R) && (direction != F) &&
3385 (direction != B) && (direction != U) && (direction != D))
3386 {
3387 std::ostringstream error_stream;
3388 error_stream << "Wrong direction: " << Direct_string[direction]
3389 << std::endl;
3390 throw OomphLibError(
3392 }
3393#endif
3394
3395 // Initialise in_neighbouring tree to false. It will be set to true
3396 // during the recursion if we do actually hop over in to the neighbour
3397 in_neighbouring_tree = false;
3398
3399 // Maximum level to which we're allowed to descend (we only want
3400 // greater-or-equal-sized neighbours)
3401 int max_level = Level;
3402
3403 // Current element has the following root:
3404 OcTreeRoot* orig_root_pt = dynamic_cast<OcTreeRoot*>(Root_pt);
3405
3406 // Initialise offset in local coordinate
3407 double s_difflo = 0;
3408 double s_diffhi = 0;
3409
3410 // Initialise difference in level
3411 diff_level = 0;
3412
3413 // Find neighbour
3415 s_difflo,
3416 s_diffhi,
3417 diff_level,
3419 max_level,
3420 orig_root_pt);
3421
3423
3424 // Initialise the translation scheme
3425 for (unsigned i = 0; i < 3; i++)
3426 {
3427 translate_s[i] = i;
3428 }
3429
3430 // If neighbour exists: What's the direction of the interfacial
3431 // face when viewed from within the neighbour element?
3432 if (neighb_pt != 0)
3433 {
3434 // Find the reflection of the original direction, which will be the
3435 // direction to the face in the neighbour, if there are no rotations.
3437
3438 // These coordinates are the coordinates of the ne and sw points
3439 // in the neighbour (provided there are no rotations -- we'll correct
3440 // for these below)
3441 s_sw[0] = S_base(0, reflected_dir) +
3444
3445 s_sw[1] = S_base(1, reflected_dir) +
3448
3449 s_sw[2] = S_base(2, reflected_dir) +
3452
3453 s_ne[0] = S_base(0, reflected_dir) +
3454 S_steplo(0, reflected_dir) * pow(2.0, diff_level) +
3456 S_stephi(0, reflected_dir) * pow(2.0, diff_level) +
3458
3459 s_ne[1] = S_base(1, reflected_dir) +
3460 S_steplo(1, reflected_dir) * pow(2.0, diff_level) +
3462 S_stephi(1, reflected_dir) * pow(2.0, diff_level) +
3464
3465 s_ne[2] = S_base(2, reflected_dir) +
3466 S_steplo(2, reflected_dir) * pow(2.0, diff_level) +
3468 S_stephi(2, reflected_dir) * pow(2.0, diff_level) +
3470
3471 // If there is no rotation then the new direction is the same as the
3472 // old direction
3473 int new_dir = direction;
3474
3475 // If necessary, rotate things around (the orientation of Up in the
3476 // neighbour might be be different from that in the present element)
3477 // If the root of the neighbour is the not same as the one of the present
3478 // element then their orientations may not be the same and the new
3479 // direction is given by :
3480 if (neighb_pt->Root_pt != Root_pt)
3481 {
3482 new_dir = rotate(orig_root_pt->up_equivalent(neighb_pt->Root_pt),
3483 orig_root_pt->right_equivalent(neighb_pt->Root_pt),
3484 direction);
3485 }
3486
3487 // What's the direction of the interfacial face when viewed from within
3488 // the neighbour element?
3490
3492
3493 // If the root of the present element is different from the root
3494 // of his neighbour, we have to rotate the RUF and LDB coordinates
3495 // to have their equivalents in the neighbour's point of view.
3496 if (neighb_pt->Root_pt != Root_pt)
3497 {
3498 int tmp_dir;
3499 Vector<int> vect1(3);
3500 Vector<int> vect2(3);
3501 Vector<int> vect3(3);
3503
3504 // All this is just to compute the rotation matrix
3505 tmp_dir = rotate(orig_root_pt->up_equivalent(neighb_pt->Root_pt),
3506 orig_root_pt->right_equivalent(neighb_pt->Root_pt),
3507 R);
3509
3510 // All this is just to compute the rotation matrix
3511 tmp_dir = rotate(orig_root_pt->up_equivalent(neighb_pt->Root_pt),
3512 orig_root_pt->right_equivalent(neighb_pt->Root_pt),
3513 U);
3515
3516 // All this is just to compute the rotation matrix
3517 tmp_dir = rotate(orig_root_pt->up_equivalent(neighb_pt->Root_pt),
3518 orig_root_pt->right_equivalent(neighb_pt->Root_pt),
3519 F);
3521
3522 // Setup the inverse rotation matrix
3523 for (int i = 0; i < 3; i++)
3524 {
3525 Mat_rot(i, 0) = vect1[i];
3526 Mat_rot(i, 1) = vect2[i];
3527 Mat_rot(i, 2) = vect3[i];
3528 }
3529
3530 // Initialise the translation scheme
3532
3533 // Then the rotation of the coordinates
3534 for (unsigned i = 0; i < 3; i++)
3535 {
3536 s_ne_new[i] = 0.0;
3537 s_sw_new[i] = 0.0;
3538 translate_s_new[i] = 0;
3539 for (unsigned k = 0; k < 3; k++)
3540 {
3541 s_ne_new[i] += Mat_rot(i, k) * s_ne[k];
3542 s_sw_new[i] += Mat_rot(i, k) * s_sw[k];
3544 }
3545 }
3546
3547 s_ne = s_ne_new;
3548 s_sw = s_sw_new;
3549
3550 // Set the translation scheme
3551 for (unsigned i = 0; i < 3; i++)
3552 {
3553 // abs is ok here; not fabs!
3554 translate_s[i] = std::abs(translate_s_new[i]);
3555 }
3556 }
3557
3558 } // end of if(neighb_pt!=0)
3559
3560 return return_pt;
3561 }
3562
3563 //================================================================
3564 /// Find (pointer to) `greater-or-equal-sized true edge neighbour' in
3565 /// the given direction (LB,RB,DB,UB [the back edges],
3566 /// LD,RD,LU,RU [the side edges], LF,RF,DF,UF [the front edges]).
3567 /// Another way of interpreting this is that we're looking for
3568 /// the neighbour across the present element's edge 'direction'.
3569 /// The various arguments return additional information about the
3570 /// size and relative orientation of the neighbouring octree.
3571 /// Each edge of the element that is represented by the octree
3572 /// is parametrised by one (of the three) local coordinates that
3573 /// parametrise the entire 3D element. E.g. the L[eft]B[ack] edge
3574 /// is parametrised by s[1]; the "low" vertex of this edge
3575 /// (located at the low value of this coordinate, i.e. at s[1]=-1)
3576 /// is L[eft]D[own]B[ack]. The "high" vertex of this edge (located
3577 /// at the high value of this coordinate, i.e. at s[1]=1) is
3578 /// L[eft]U[p]B[ack]; etc
3579 /// The interpretation of the arguments is as follows:
3580 /// - In a forest, an OcTree can have multiple edge neighbours
3581 /// (across an edge where multiple trees meet). \c i_root_edge_neighbour
3582 /// specifies which of these is used. Use this as "reverse communication":
3583 /// First call with \c i_root_edge_neighbour=0 and \c n_root_edge_neighour
3584 /// initialised to anything you want (zero, ideally). On return from
3585 /// the fct, \c n_root_edge_neighour contains the total number of true
3586 /// edge neighbours, so additional calls to the fct with
3587 /// \c i_root_edge_neighbour>0 can be made until they've all been visited.
3588 /// - The vector \c translate_s turns the index of the local coordinate
3589 /// in the present octree into that of the neighbour. If there are no
3590 /// rotations then \c translate_s[i] = i.
3591 /// - The "low" vertex of the edge in the present octree
3592 /// coincides with a certain vertex in the edge neighbour.
3593 /// In terms of the neighbour's local coordinates, this point is
3594 /// located at the (3D) local coordinates (\c s_lo[0], \c s_lo[1],
3595 /// \c s_lo[2])
3596 /// - ditto with s_hi: The "high" vertex of the edge in the present octree
3597 /// coincides with a certain vertex in the edge neighbour.
3598 /// In terms of the neighbour's local coordinates, this point is
3599 /// located at the (3D) local coordinates (\c s_hi[0], \c s_hi[1],
3600 /// \c s_hi[2])
3601 /// - We're looking for a neighbour in the specified \c direction. When
3602 /// viewed from the neighbouring octree, the edge that separates
3603 /// the present octree from its neighbour is the neighbour's edge
3604 /// \c edge. If there's no rotation between the two octrees, this is a
3605 /// simple reflection: For instance, if we're looking
3606 /// for a neighhbour in the \c DB \c direction, \c edge will
3607 /// be \c UF.
3608 /// - \c diff_level <= 0 indicates the difference in refinement levels between
3609 /// the two neighbours. If \c diff_level==0, the neighbour has the
3610 /// same size as the current octree.
3611 /// .
3612 /// \b Important: We're only looking for \b true edge neighbours
3613 /// i.e. edge neigbours that are not also face neighbours. This is an
3614 /// important difference to Samet's terminology. If the neighbour
3615 /// in a certain direction is not a true edge neighbour, or if there
3616 /// is no neighbour, then this function returns NULL.
3617 //=================================================================
3619 const int& direction,
3620 const unsigned& i_root_edge_neighbour,
3621 unsigned& nroot_edge_neighbour,
3625 int& edge,
3626 int& diff_level) const
3627 {
3628 using namespace OcTreeNames;
3629
3630#ifdef PARANOID
3631 if ((direction != LB) && (direction != RB) && (direction != DB) &&
3632 (direction != UB) && (direction != LD) && (direction != RD) &&
3633 (direction != LU) && (direction != RU) && (direction != LF) &&
3634 (direction != RF) && (direction != DF) && (direction != UF))
3635 {
3636 std::ostringstream error_stream;
3637 error_stream << "Wrong direction: " << Direct_string[direction]
3638 << std::endl;
3639 throw OomphLibError(
3641 }
3642#endif
3643
3644 // Maximum level to which we're allowed to descend (we only want
3645 // greater-or-equal-sized neighbours)
3646 int max_level = Level;
3647
3648 // Current element has the following root:
3649 OcTreeRoot* orig_root_pt = dynamic_cast<OcTreeRoot*>(Root_pt);
3650
3651 // Initialise offset in local coordinate along edge
3652 double s_diff = 0;
3653
3654 // Initialise difference in level
3655 diff_level = 0;
3656
3657 // Find edge neighbour
3661 s_diff,
3662 diff_level,
3663 max_level,
3664 orig_root_pt);
3665
3666 // Only use "true" edge neighbours
3668 {
3669 return_pt = 0;
3670 }
3671
3672 // By default, we return what was returned as the true edge neighbour.
3674
3675 // Initialise the translation scheme
3676 for (unsigned i = 0; i < 3; i++)
3677 {
3678 translate_s[i] = i;
3679 }
3680
3681 // If neighbour exists: What's the direction of the interfacial
3682 // edge when viewed from within the neighbour element?
3683 if (neighb_pt != 0)
3684 {
3685 // Find the reflection of the original direction, which will be the
3686 // direction to the edge in the neighbour, if there are no rotations.
3688
3689 // These coordinates are the coordinates of the "low" and "high" points
3690 // in the neighbour (provided there are no rotations -- we'll correct
3691 // for these below)
3692 s_lo[0] =
3694
3695 s_lo[1] =
3697
3698 s_lo[2] =
3700
3701 s_hi[0] = S_base_edge(0, reflected_dir) +
3704
3705 s_hi[1] = S_base_edge(1, reflected_dir) +
3708
3709 s_hi[2] = S_base_edge(2, reflected_dir) +
3712
3713 // If there is no rotation then the new direction is the same as the
3714 // old direction
3715 int new_dir = direction;
3716
3717
3718 // If necessary, rotate things around (the orientation of Up in the
3719 // neighbour might be be different from that in the present element)
3720 // If the root of the neighbour is the not same as the one of the present
3721 // element then their orientations may not be the same and the new
3722 // direction is given by :
3723 if (neighb_pt->Root_pt != Root_pt)
3724 {
3725 int new_up = orig_root_pt->up_equivalent(neighb_pt->Root_pt);
3726
3727 int new_right = orig_root_pt->right_equivalent(neighb_pt->Root_pt);
3728
3730 }
3731
3732 // What's the direction of the interfacial edge when viewed from within
3733 // the neighbour element (including rotations!)
3735
3736 // Get ready to rotate the local coordinates
3738
3739 // If the root of the present element is different from the root
3740 // of his neighbour, we have to rotate the lo and hi coordinates
3741 // to have their equivalents from the neighbour's point of view.
3742 if ((neighb_pt->Root_pt != Root_pt))
3743 {
3744 int tmp_dir;
3745 Vector<int> vect1(3);
3746 Vector<int> vect2(3);
3747 Vector<int> vect3(3);
3749
3750 // All this is just to compute the rotation matrix
3751 tmp_dir = rotate(orig_root_pt->up_equivalent(neighb_pt->Root_pt),
3752 orig_root_pt->right_equivalent(neighb_pt->Root_pt),
3753 R);
3755
3756
3757 tmp_dir = rotate(orig_root_pt->up_equivalent(neighb_pt->Root_pt),
3758 orig_root_pt->right_equivalent(neighb_pt->Root_pt),
3759 U);
3761
3762
3763 tmp_dir = rotate(orig_root_pt->up_equivalent(neighb_pt->Root_pt),
3764 orig_root_pt->right_equivalent(neighb_pt->Root_pt),
3765 F);
3767
3768
3769 // Setup the inverse rotation matrix
3770 for (int i = 0; i < 3; i++)
3771 {
3772 Mat_rot(i, 0) = vect1[i];
3773 Mat_rot(i, 1) = vect2[i];
3774 Mat_rot(i, 2) = vect3[i];
3775 }
3776
3777 // Initialise the translation scheme
3779
3780 // Then the rotation of the coordinates
3781 for (unsigned i = 0; i < 3; i++)
3782 {
3783 s_hi_new[i] = 0.0;
3784 s_lo_new[i] = 0.0;
3785 translate_s_new[i] = 0;
3786 for (unsigned k = 0; k < 3; k++)
3787 {
3788 s_hi_new[i] += Mat_rot(i, k) * s_hi[k];
3789 s_lo_new[i] += Mat_rot(i, k) * s_lo[k];
3791 }
3792 }
3793
3794 s_lo = s_lo_new;
3795 s_hi = s_hi_new;
3796
3797 // Set the translation scheme
3798 for (unsigned i = 0; i < 3; i++)
3799 {
3800 // abs is ok here; not fabs!
3801 translate_s[i] = std::abs(translate_s_new[i]);
3802 }
3803 }
3804
3805 } // end if for (neighb_pt!=0)
3806
3807 return return_pt;
3808 }
3809
3810
3811 //==========================================================================
3812 /// Find `greater-or-equal-sized face neighbour' in given direction
3813 /// (L/R/U/D/B/F).
3814 ///
3815 /// This is an auxiliary routine which allows neighbour finding in adjacent
3816 /// octrees. Needs to keep track of previous son types and
3817 /// the maximum level to which search is performed.
3818 ///
3819 /// Parameters:
3820 ///
3821 /// - direction: (L/R/U/D/B/F) Direction in which neighbour has to be found.
3822 /// - s_difflo/s_diffhi: Offset of left/down/back vertex from
3823 /// corresponding vertex in neighbour. Note that this is input/output
3824 /// as it needs to be incremented/decremented during the recursive calls
3825 /// to this function.
3826 /// - face: We're looking for the neighbour across our face 'direction'
3827 /// (L/R/U/D/B/F). When viewed from the neighbour, this face is
3828 /// `face' (L/R/U/D/B/F). [If there's no relative rotation between
3829 /// neighbours then this is a mere reflection, e.g. direction=F --> face=B
3830 /// etc.]
3831 /// - diff_level <= 0 indicates the difference in octree levels
3832 /// between the current element and its neighbour.
3833 /// - max_level is the maximum level to which the neighbour search is
3834 /// allowed to proceed. This is necessary because in a forest,
3835 /// the neighbour search isn't based on pure recursion.
3836 /// - orig_root_pt identifies the root node of the element whose
3837 /// neighbour we're really trying to find by all these recursive calls.
3838 //===========================================================================
3840 double& s_difflo,
3841 double& s_diffhi,
3842 int& diff_level,
3844 int max_level,
3845 OcTreeRoot* orig_root_pt) const
3846 {
3847 using namespace OcTreeNames;
3848
3849#ifdef PARANOID
3850 if ((direction != L) && (direction != R) && (direction != F) &&
3851 (direction != B) && (direction != U) && (direction != D))
3852 {
3853 std::ostringstream error_stream;
3854 error_stream << "Direction " << Direct_string[direction]
3855 << " is not L, R, B, F, D or U." << std::endl;
3856 throw OomphLibError(
3858 }
3859#endif
3860
3863
3864 // Initialise in_neighbouring tree to false. It will be set to true
3865 // during the recursion if we do actually hop over in to the neighbour
3866 in_neighbouring_tree = false;
3867
3868 // STEP 1: Find the neighbour's father
3869 //--------
3870 // Does the element have a father?
3871 if (Father_pt != 0)
3872 {
3873 // If the present octant (whose location inside its
3874 // father element is specified by Son_type) is adjacent to the
3875 // father's face in the required direction, then its neighbour has
3876 // a different father ---> we need to climb up the tree to
3877 // the father and find his neighbour in the required direction
3879 {
3881 direction,
3882 s_difflo,
3883 s_diffhi,
3884 diff_level,
3886 max_level,
3887 orig_root_pt);
3888 }
3889 // If the present octant is not adjacent to the
3890 // father's face in the required direction, then the
3891 // neighbour has the same father and will be obtained
3892 // by the appropriate reflection inside the father element
3893 else
3894 {
3895 next_el_pt = dynamic_cast<OcTree*>(Father_pt);
3896 }
3897
3898 // We're about to ascend one level:
3899 diff_level -= 1;
3900
3901 // Work out position of lower-left corner of present face
3902 // in its father element
3905
3906 // STEP 2: We have now located the neighbour's father and need to
3907 // ------- find the appropriate son.
3908 // Buffer cases where the neighbour (and hence its father) lie outside
3909 // the boundary
3910 if (next_el_pt != 0)
3911 {
3912 // If the father is a leaf then we can't descend to the same
3913 // level as the present node ---> simply return the father himself
3914 // as the (greater) neighbour. Same applies if we are about
3915 // to descend lower than the max_level (in a neighbouring tree)
3916 if ((next_el_pt->Son_pt.size() == 0) ||
3917 (next_el_pt->Level > max_level - 1))
3918 {
3920 }
3921 // We have located the neighbour's father: The position of the
3922 // neighbour is obtained by `reflecting' the position of the
3923 // node itself.
3924 else
3925 {
3926 // By default (in the absence of rotations) we obtain the
3927 // son octant by reflecting
3929
3930 // If there is a rotation, we rotate the son octant
3931 if (orig_root_pt != next_el_pt->Root_pt)
3932 {
3933 int my_up = dynamic_cast<OcTreeRoot*>(Root_pt)->up_equivalent(
3934 next_el_pt->Root_pt);
3935 int my_right = dynamic_cast<OcTreeRoot*>(Root_pt)->right_equivalent(
3936 next_el_pt->Root_pt);
3938 }
3939
3940 return_el_pt = dynamic_cast<OcTree*>(next_el_pt->Son_pt[son_octant]);
3941
3942 // Work out position of lower-left corner of present face
3943 // in next higher element
3946
3947 // We have just descended one level
3948 diff_level += 1;
3949 }
3950 }
3951 // The neighbour's father lies outside the boundary --> the neighbour
3952 // itself does too --> return NULL.
3953 else
3954 {
3955 return_el_pt = 0;
3956 }
3957 }
3958 // Element does not have a father --> check if it has a neighbouring
3959 // tree in the appropriate direction
3960 else
3961 {
3962 // Find neighbouring root
3963 if (Root_pt->neighbour_pt(direction) != 0)
3964 {
3965 // If we're in the neighbouring tree
3966 in_neighbouring_tree = true;
3967
3968 // Return
3969 return_el_pt = dynamic_cast<OcTree*>(Root_pt->neighbour_pt(direction));
3970 }
3971 // No neighbouring tree, so there really is no neighbour --> return NULL
3972 else
3973 {
3974 return_el_pt = 0;
3975 }
3976 }
3977
3978 // Return the appropriate OcTree pointer
3979 return return_el_pt;
3980 } // End of gteq_face_neighbour
3981
3982
3983 //==========================================================================
3984 /// Find `greater-or-equal-sized edge neighbour' in given direction
3985 /// (LB,RB,DB,UB [the back edges],
3986 /// LD,RD,LU,RU [the side edges], LF,RF,DF,UF [the front edges]).
3987 ///
3988 /// This is an auxiliary routine which allows neighbour finding in adjacent
3989 /// octrees. Needs to keep track of previous son types and
3990 /// the maximum level to which search is performed.
3991 ///
3992 /// Parameters:
3993 ///
3994 /// - direction: (LB,RB/...) Direction in which neighbour has to be found.
3995 /// - In a forest, an OcTree can have multiple edge neighbours
3996 /// (across an edge where multiple trees meet). \c i_root_edge_neighbour
3997 /// specifies which of these is used. Use this as "reverse communication":
3998 /// First call with \c i_root_edge_neighbour=0 and \c n_root_edge_neighour
3999 /// initialised to anything you want (zero, ideally). On return from
4000 /// the fct, \c n_root_edge_neighour contains the total number of true
4001 /// edge neighbours, so additional calls to the fct with
4002 /// \c i_root_edge_neighbour>0 can be made until they've all been visited.
4003 /// - s_diff: Offset of left/down/back vertex from
4004 /// corresponding vertex in
4005 /// neighbour. Note that this is input/output as it needs to be incremented/
4006 /// decremented during the recursive calls to this function.
4007 /// - diff_level <= 0 indicates the difference in octree levels
4008 /// between the current element and its neighbour.
4009 /// - max_level is the maximum level to which the neighbour search is
4010 /// allowed to proceed. This is necessary because in a forest,
4011 /// the neighbour search isn't based on pure recursion.
4012 /// - orig_root_pt identifies the root node of the element whose
4013 /// neighbour we're really trying to find by all these recursive calls.
4014 //===========================================================================
4016 const unsigned& i_root_edge_neighbour,
4017 unsigned& nroot_edge_neighbour,
4018 double& s_diff,
4019 int& diff_level,
4020 int max_level,
4021 OcTreeRoot* orig_root_pt) const
4022 {
4023 using namespace OcTreeNames;
4024
4025
4026#ifdef PARANOID
4027 if ((direction != LB) && (direction != RB) && (direction != DB) &&
4028 (direction != UB) && (direction != LD) && (direction != RD) &&
4029 (direction != LU) && (direction != RU) && (direction != LF) &&
4030 (direction != RF) && (direction != DF) && (direction != UF))
4031 {
4032 std::ostringstream error_stream;
4033 error_stream << "Wrong direction: " << Direct_string[direction]
4034 << std::endl;
4035 throw OomphLibError(
4037 }
4038#endif
4039
4040 // Initialise total number of edge neighbours available across
4041 // edges of octree roots
4043
4044 OcTree* next_el_pt = 0;
4045 OcTree* return_el_pt = 0;
4046
4047 // STEP 1: Find the common ancestor
4048 //--------
4049 // Does the element have a father?
4050 if (Father_pt != 0)
4051 {
4052 // If the present octant (whose location inside its
4053 // father element is specified by Son_type) is adjacent to the
4054 // father's edge in the required direction, then its neighbour has
4055 // a different father ---> we need to climb up the tree to
4056 // the father and find his neighbour in the required direction
4058 {
4060 direction,
4063 s_diff,
4064 diff_level,
4065 max_level,
4066 orig_root_pt);
4067 }
4068 // If the present octant (whose location inside its
4069 // father element is specified by Son_type) is adjacent to the
4070 // father's face in the required direction, then its neighbour has
4071 // a different father ---> we need to climb up the tree to
4072 // the father and find his neighbour in the required direction,
4073 // crossing the face as we do so.
4074 else if (Common_face(direction, Son_type) != OMEGA)
4075 {
4076 // Initialise bool
4077 bool in_neighbouring_tree = false;
4078
4079 // We're going across a face:
4080 double s_difflo = 0.0;
4081 double s_diffhi = 0.0;
4082 int diff_level_edge = 0;
4083
4086 s_difflo,
4087 s_diffhi,
4090 max_level,
4091 orig_root_pt);
4092 }
4093 // If the present octant is not adjacent to the
4094 // father's face/edge in the required direction, then the
4095 // neighbour has the same father and will be obtained
4096 // by the appropriate reflection inside the father element
4097 else
4098 {
4099 next_el_pt = dynamic_cast<OcTree*>(Father_pt);
4100 }
4101
4102 // We're about to ascend one level:
4103 diff_level -= 1;
4104
4105 // Work out position of "low" vertex of present edge
4106 // in its father element
4108
4109 // STEP 2: We have now located the neighbour's father and need to
4110 // ------- find the appropriate son.
4111 // Buffer cases where ...
4112 if (next_el_pt != 0)
4113 {
4114 // If the father is a leaf then we can't descend to the same
4115 // level as the present node ---> simply return the father himself
4116 // as the (greater) neighbour. Same applies if we are about
4117 // to descend lower than the max_level (in a neighbouring tree)
4118 if ((next_el_pt->Son_pt.size() == 0) ||
4119 (next_el_pt->Level > max_level - 1))
4120 {
4122 }
4123 // We have located the neighbour's father: The position of the
4124 // neighbour is obtained by `reflecting' the position of the
4125 // node itself.
4126 else
4127 {
4128 // By default (in the absence of rotations) we obtain the
4129 // son octant by reflecting
4131
4132 // If there is a rotation, we rotate the son octant
4133 if (orig_root_pt != next_el_pt->Root_pt)
4134 {
4135 int my_up = dynamic_cast<OcTreeRoot*>(Root_pt)->up_equivalent(
4136 next_el_pt->Root_pt);
4137 int my_right = dynamic_cast<OcTreeRoot*>(Root_pt)->right_equivalent(
4138 next_el_pt->Root_pt);
4140 }
4141
4142 return_el_pt = dynamic_cast<OcTree*>(next_el_pt->Son_pt[son_octant]);
4143
4144 // Work out position of "low" vertex of present edge
4145 // in next higher element
4147
4148 // We have just descended one level
4149 diff_level += 1;
4150 }
4151 }
4152 // The neighbour's father lies outside the boundary --> the neighbour
4153 // itself does too --> return NULL.
4154 else
4155 {
4156 return_el_pt = 0;
4157 }
4158 }
4159 // Element does not have a father --> check if it has a neighbouring
4160 // tree in the appropriate direction
4161 else
4162 {
4163 // Get total number of edge neighbours available across
4164 // edges of octree roots for return
4166 dynamic_cast<OcTreeRoot*>(Root_pt)->nedge_neighbour(direction);
4167
4168 // Get vector of edge neighbours (if any) in appropriate direction
4169 Vector<TreeRoot*> edge_neighbour_pt =
4170 dynamic_cast<OcTreeRoot*>(Root_pt)->edge_neighbour_pt(direction);
4171
4172 // Get the number of edge neighbours
4173 unsigned n_neigh = edge_neighbour_pt.size();
4174
4175 // If there are any edge neighbours
4176 if (n_neigh > 0)
4177 {
4178 // Return the appropriate edge neighbour
4179 return_el_pt =
4180 dynamic_cast<OcTree*>(edge_neighbour_pt[i_root_edge_neighbour]);
4181 }
4182 else
4183 {
4184 return_el_pt = 0;
4185 }
4186 }
4187
4188 return return_el_pt;
4189 } // End of gteq_edge_neighbour
4190
4191
4192 //================================================================
4193 /// Self-test: Check neighbour finding routine. For each element
4194 /// in the tree and for each vertex, determine the
4195 /// distance between the vertex and its position in the
4196 /// neigbour. . If the difference is less than
4197 /// Tree::Max_neighbour_finding_tolerance.
4198 /// return success (0), otherwise failure (1)
4199 //=================================================================
4201 {
4202 // Stick pointers to all nodes into Vector and number elements
4203 // in the process
4206
4207 long int count = 0;
4208 unsigned long num_nodes = all_nodes_pt.size();
4209
4210 for (unsigned long i = 0; i < num_nodes; i++)
4211 {
4212 all_nodes_pt[i]->object_pt()->set_number(++count);
4213 }
4214
4215 // Check neighbours vertices and their opposite points
4216 std::ofstream neighbours_file;
4217 std::ofstream no_true_edge_file;
4218 std::ofstream neighbours_txt_file;
4219
4220 double max_error_face = 0.0;
4223
4224 double max_error_edge = 0.0;
4230 bool failed = false;
4232 {
4234 << "\n \n Failed self_test() for OcTree because of faces: Max. error "
4235 << max_error_face << std::endl
4236 << std::endl;
4237 failed = true;
4238 }
4239
4241 {
4243 << "\n \n Failed self_test() for OcTree because of edges: Max. error "
4244 << max_error_edge << std::endl
4245 << std::endl;
4246 failed = true;
4247 }
4248
4249 double max_error = max_error_face;
4250 if (max_error_edge > max_error) max_error = max_error_edge;
4251
4252 if (failed)
4253 {
4254 return 1;
4255 }
4256 else
4257 {
4258 oomph_info << "Passed self_test() for OcTree: Max. error " << max_error
4259 << std::endl;
4260 return 0;
4261 }
4262 }
4263
4264
4265 //=================================================================
4266 /// Doc/check all face neighbours of octree (nodes) contained in the
4267 /// Vector forest_node_pt. Output into neighbours_file which can
4268 /// be viewed from tecplot with OcTreeNeighbours.mcr
4269 /// Neighbour info and errors are displayed on
4270 /// neighbours_txt_file. Finally, compute the max. error between
4271 /// vertices when viewed from neighbouring element.
4272 /// If the two filestreams are closed, output is suppressed.
4273 /// (Static function.)
4274 //=================================================================
4276 std::ofstream& neighbours_file,
4277 std::ofstream& neighbours_txt_file,
4278 double& max_error)
4279 {
4280 using namespace OcTreeNames;
4281
4282 int diff_level;
4283 int face = OMEGA;
4285
4286 Vector<double> s(3);
4287 Vector<double> x(3);
4288
4292
4295
4296
4297 // Initialise error in vertex positions
4298 max_error = 0.0;
4299
4300 // Loop over all elements
4301 // ----------------------
4302 unsigned long num_nodes = forest_nodes_pt.size();
4303
4304 for (unsigned long i = 0; i < num_nodes; i++)
4305 {
4306 // Doc the element itself
4307 OcTree* el_pt = dynamic_cast<OcTree*>(forest_nodes_pt[i]);
4308
4309 // If the object is incomplete omit
4310 if (el_pt->object_pt()->nodes_built())
4311 {
4312 // Print it
4313 if (neighbours_file.is_open())
4314 {
4315 neighbours_file << "#---------------------------------" << std::endl;
4316 neighbours_file << "#The element itself: " << i << std::endl;
4317 neighbours_file << "#---------------------------------" << std::endl;
4318 dynamic_cast<RefineableQElement<3>*>(el_pt->object_pt())
4319 ->output_corners(neighbours_file, "BLACK");
4320 }
4321
4322 // Loop over directions to find neighbours
4323 // ----------------------------------------
4324 for (int direction = L; direction <= F; direction++)
4325 {
4326 // Initialise difference in levels and coordinate offset
4327 diff_level = 0;
4328
4329 // Find greater-or-equal-sized neighbour...
4330 OcTree* neighb_pt = el_pt->gteq_face_neighbour(direction,
4332 s_sw,
4333 s_ne,
4334 face,
4335 diff_level,
4337
4338 // If neighbour exists and nodes are created
4339 if ((neighb_pt != 0) && (neighb_pt->object_pt()->nodes_built()))
4340 {
4341 // Doc neighbour stats
4342 if (neighbours_txt_file.is_open())
4343 {
4345 << Direct_string[direction] << " neighbour of "
4346 << el_pt->object_pt()->number() << " is "
4347 << neighb_pt->object_pt()->number() << " diff_level "
4348 << diff_level << ". Inside the neighbour the face is "
4349 << Direct_string[face] << std::endl;
4350 }
4351
4352 // Plot neighbour in the appropriate colour
4353 if (neighbours_file.is_open())
4354 {
4355 neighbours_file << "#---------------------------------"
4356 << std::endl;
4358 << "#Neighbour element: " << Direct_string[direction]
4359 << "\n#---------------------------------" << std::endl;
4360 dynamic_cast<RefineableQElement<3>*>(neighb_pt->object_pt())
4361 ->output_corners(neighbours_file, Colour[direction]);
4362 }
4363
4364 // Check that local coordinates in the larger element
4365 // lead to the same spatial point as the node vertices
4366 // in the current element
4367 if (neighbours_file.is_open())
4368 {
4369 neighbours_file << "ZONE I=2 C=" << Colour[direction]
4370 << std::endl;
4371 }
4372
4373 // "South west" vertex in the interfacial face
4374 //--------------------------------------------
4375
4376 // Get coordinates in large (neighbour) element
4377 s[0] = s_sw[0];
4378 s[1] = s_sw[1];
4379 s[2] = s_sw[2];
4380 neighb_pt->object_pt()->get_x(s, x_large);
4381
4382 // Get coordinates in small element
4383 Vector<double> s(3);
4384 s[0] = S_base(0, direction);
4385 s[1] = S_base(1, direction);
4386 s[2] = S_base(2, direction);
4387 el_pt->object_pt()->get_x(s, x_small);
4388
4389 // Need to exclude periodic nodes from this check
4390 // There can only be periodic nodes if we have moved into the
4391 // neighbour
4392 bool is_periodic = false;
4394 {
4395 // is the node periodic
4396 is_periodic = el_pt->root_pt()->is_neighbour_periodic(direction);
4397 }
4398
4399 double error = 0.0;
4400 // Only bother to calculate the error if the node is NOT periodic
4401 if (is_periodic == false)
4402 {
4403 error = sqrt(pow(x_small[0] - x_large[0], 2) +
4404 pow(x_small[1] - x_large[1], 2) +
4405 pow(x_small[2] - x_large[2], 2));
4406 }
4407
4408 if (neighbours_txt_file.is_open())
4409 {
4410 neighbours_txt_file << "Error (1) " << error << std::endl;
4411 }
4412
4413 if (std::fabs(error) > max_error)
4414 {
4415 max_error = std::fabs(error);
4416 }
4417
4418 // Check error and doc mismatch if required
4419 bool stop = false;
4420 std::ofstream mismatch_file;
4421 if (std::fabs(error) > Max_neighbour_finding_tolerance)
4422 {
4423 stop = true;
4424 mismatch_file.open("mismatch.dat");
4425 mismatch_file << "ZONE" << std::endl;
4426 mismatch_file << x_large[0] << " " << x_large[1] << " "
4427 << x_large[2] << " 2 \n";
4428 mismatch_file << x_small[0] << " " << x_small[1] << " "
4429 << x_small[2] << " 3 \n";
4430 }
4431
4432 if (neighbours_file.is_open())
4433 {
4434 neighbours_file << "#SOUTH WEST: " << std::endl;
4435 neighbours_file << x_large[0] << " " << x_large[1] << " "
4436 << x_large[2] << " 40 \n";
4437 }
4438
4439
4440 // "North east" vertex in the interfacial face
4441 //--------------------------------------------
4442
4443 // Get coordinates in large (neighbour) element
4444 s[0] = s_ne[0];
4445 s[1] = s_ne[1];
4446 s[2] = s_ne[2];
4447 neighb_pt->object_pt()->get_x(s, x_large);
4448
4449 // Get coordinates in small element
4450 s[0] = S_base(0, direction) + S_steplo(0, direction) +
4451 S_stephi(0, direction);
4452 s[1] = S_base(1, direction) + S_steplo(1, direction) +
4453 S_stephi(1, direction);
4454 s[2] = S_base(2, direction) + S_steplo(2, direction) +
4455 S_stephi(2, direction);
4456 el_pt->object_pt()->get_x(s, x_small);
4457
4458 error = 0.0;
4459 // Only do this if we are NOT periodic
4460 if (is_periodic == false)
4461 {
4462 error = sqrt(pow(x_small[0] - x_large[0], 2) +
4463 pow(x_small[1] - x_large[1], 2) +
4464 pow(x_small[2] - x_large[2], 2));
4465 }
4466
4467 // Output
4468 if (neighbours_file.is_open())
4469 {
4470 neighbours_file << "#NORTH EAST: " << std::endl;
4471 neighbours_file << x_large[0] << " " << x_large[1] << " "
4472 << x_large[2] << " 80 \n";
4473 }
4474
4475 if (neighbours_txt_file.is_open())
4476 {
4477 neighbours_txt_file << "Error (2) " << error << std::endl;
4478 }
4479
4480 if (std::fabs(error) > max_error)
4481 {
4482 max_error = std::fabs(error);
4483 }
4484
4485 // Check error and doc mismatch if required
4486 if (std::fabs(error) > Max_neighbour_finding_tolerance)
4487 {
4488 stop = true;
4489 }
4490 if (stop)
4491 {
4492 if (!mismatch_file.is_open())
4493 {
4494 mismatch_file.open("mismatch.dat");
4495 }
4496 mismatch_file << "ZONE" << std::endl;
4497 mismatch_file << x_large[0] << " " << x_large[1] << " "
4498 << x_large[2] << " 2 " << std::fabs(error)
4499 << " \n";
4500 mismatch_file << x_small[0] << " " << x_small[1] << " "
4501 << x_small[2] << " 3 " << std::fabs(error)
4502 << " \n";
4503 mismatch_file.close();
4504 pause("Error");
4505 }
4506 }
4507
4508 // If neighbour does not exist: Insert blank zones into file
4509 // so that tecplot can find six neighbours for every element
4510 else
4511 {
4512 if (neighbours_file.is_open())
4513 {
4515 << "#---------------------------------\n"
4516 << "# No neighbour in direction: " << Direct_string[direction]
4517 << "\n"
4518 << "#---------------------------------" << std::endl;
4519
4520 dynamic_cast<RefineableQElement<3>*>(el_pt->object_pt())
4521 ->output_corners(neighbours_file, "WHITE");
4522 neighbours_file << "ZONE I=2 \n";
4523 neighbours_file << "-0.05 -0.05 -0.05 0 \n";
4524 neighbours_file << "-0.05 -0.05 -0.05 0 \n";
4525 }
4526 }
4527
4528 if (neighbours_file.is_open())
4529 {
4530 neighbours_file << std::endl << std::endl << std::endl;
4531 }
4532 }
4533 } // End of case when element can be documented
4534 }
4535 }
4536
4537
4538 //////////////////////////////////////////////////////////////////////
4539 //////////////////////////////////////////////////////////////////////
4540
4541
4542 //=================================================================
4543 /// Doc/check all true edge neighbours of octree (nodes) contained
4544 /// in the Vector forest_node_pt. Output into neighbours_file which can
4545 /// be viewed from tecplot with OcTreeNeighbours.mcr
4546 /// Neighbour info and errors are displayed on
4547 /// neighbours_txt_file. Finally, compute the max. error between
4548 /// vertices when viewed from neighbouring element.
4549 /// If the two filestreams are closed, output is suppressed.
4550 /// (Static function).
4551 //=================================================================
4553 std::ofstream& neighbours_file,
4554 std::ofstream& no_true_edge_file,
4555 std::ofstream& neighbours_txt_file,
4556 double& max_error)
4557 {
4558 using namespace OcTreeNames;
4559
4560 int diff_level;
4561 int edge = OMEGA;
4562
4563 Vector<double> s(3);
4564 Vector<double> x(3);
4565
4569
4572
4573
4574 // Initialise error in vertex positions
4575 max_error = 0.0;
4576
4577 // Loop over all elements
4578 // ----------------------
4579 unsigned long num_nodes = forest_nodes_pt.size();
4580
4581 for (unsigned long i = 0; i < num_nodes; i++)
4582 {
4583 // Doc the element itself
4584 OcTree* el_pt = dynamic_cast<OcTree*>(forest_nodes_pt[i]);
4585
4586 // If the object is incomplete omit
4587 if (el_pt->object_pt()->nodes_built())
4588 {
4589 // Print it
4590 if (neighbours_file.is_open())
4591 {
4592 neighbours_file << "#---------------------------------" << std::endl;
4593 neighbours_file << "# The element itself: " << i << std::endl;
4594 neighbours_file << "#---------------------------------" << std::endl;
4595 dynamic_cast<RefineableQElement<3>*>(el_pt->object_pt())
4596 ->output_corners(neighbours_file, "BLACK");
4597 }
4598
4599 // Loop over directions to find edge neighbours
4600 // --------------------------------------------
4601 for (int direction = LB; direction <= UF; direction++)
4602 {
4603 // Initialise difference in levels
4604 diff_level = 0;
4605
4606 // For now simply doc the zero-th edge neighbour (if any)
4607 unsigned i_root_edge_neighbour = 0;
4608 unsigned nroot_edge_neighbour = 0;
4609
4610 // Find greater-or-equal-sized edge neighbour...
4611 OcTree* neighb_pt =
4612 el_pt->gteq_true_edge_neighbour(direction,
4616 s_lo,
4617 s_hi,
4618 edge,
4619 diff_level);
4620
4621 // If neighbour exists and nodes are created
4622 if ((neighb_pt != 0) && (neighb_pt->object_pt()->nodes_built()))
4623 {
4624 // Doc neighbour stats
4625 if (neighbours_txt_file.is_open())
4626 {
4628 << Direct_string[direction] << " neighbour of "
4629 << el_pt->object_pt()->number() << " is "
4630 << neighb_pt->object_pt()->number() << " diff_level "
4631 << diff_level << ". Inside the neighbour the edge is "
4632 << Direct_string[edge] << std::endl;
4633 }
4634
4635 // Plot neighbour in the appropriate colour
4636 if (neighbours_file.is_open())
4637 {
4639 << "#---------------------------------"
4640 << "\n# Neighbour element: " << Direct_string[direction]
4641 << "\n#---------------------------------" << std::endl;
4642 dynamic_cast<RefineableQElement<3>*>(neighb_pt->object_pt())
4643 ->output_corners(neighbours_file, Colour[direction]);
4644 }
4645
4646 // Check that local coordinates in the larger element
4647 // lead to the same spatial point as the node vertices
4648 // in the current element
4649 if (neighbours_file.is_open())
4650 {
4651 neighbours_file << "ZONE I=2 C=" << Colour[direction]
4652 << std::endl;
4653 }
4654
4655 // "Low" vertex in the edge
4656 //-------------------------
4657 // Get coordinates in large (neighbour) element
4658 s[0] = s_lo[0];
4659 s[1] = s_lo[1];
4660 s[2] = s_lo[2];
4661 neighb_pt->object_pt()->get_x(s, x_large);
4662
4663 // Get coordinates in small element
4664 Vector<double> s(3);
4665 s[0] = S_base_edge(0, direction);
4666 s[1] = S_base_edge(1, direction);
4667 s[2] = S_base_edge(2, direction);
4668 el_pt->object_pt()->get_x(s, x_small);
4669
4670 // Need to exclude periodic nodes from this check
4671 // There can only be periodic nodes if we have moved into the
4672 // neighbour
4673 bool is_periodic = false;
4674
4675 // Get the faces on which the edge lies
4678
4679 // Get the number of entries in the vector
4681
4682 // Loop over the faces
4683 for (unsigned i_face = 0; i_face < n_faces_attached_to_edge;
4684 i_face++)
4685 {
4686 // Is the node periodic in the face direction?
4687 is_periodic = el_pt->root_pt()->is_neighbour_periodic(
4689
4690 // Check if the edge is periodic in the i_face-th face direction
4691 if (is_periodic)
4692 {
4693 // We're done!
4694 break;
4695 }
4696 } // for (unsigned
4697 // i_face=0;i_face<n_faces_attached_to_edge;i_face++)
4698
4699 double error = 0.0;
4700 // Only bother to calculate the error if the node is NOT periodic
4701 if (is_periodic == false)
4702 {
4703 error = sqrt(pow(x_small[0] - x_large[0], 2) +
4704 pow(x_small[1] - x_large[1], 2) +
4705 pow(x_small[2] - x_large[2], 2));
4706 }
4707
4708 if (std::fabs(error) > max_error)
4709 {
4710 max_error = std::fabs(error);
4711 }
4712
4713 if (neighbours_txt_file.is_open())
4714 {
4715 neighbours_txt_file << "Error (1) " << error << std::endl;
4716 }
4717
4718 // Check error and doc mismatch if required
4719 bool stop = false;
4720 std::ofstream mismatch_file;
4721 if (std::fabs(error) > Max_neighbour_finding_tolerance)
4722 {
4723 stop = true;
4724 mismatch_file.open("mismatch.dat");
4725 mismatch_file << "ZONE" << std::endl;
4726 mismatch_file << x_large[0] << " " << x_large[1] << " "
4727 << x_large[2] << " 2 \n";
4728 mismatch_file << x_small[0] << " " << x_small[1] << " "
4729 << x_small[2] << " 3 \n";
4730 }
4731
4732 if (neighbours_file.is_open())
4733 {
4734 neighbours_file << "# LOW VERTEX: " << std::endl;
4735 neighbours_file << x_large[0] << " " << x_large[1] << " "
4736 << x_large[2] << " 40 \n";
4737 }
4738
4739
4740 // "High" vertex in the edge
4741 //--------------------------
4742 // Get coordinates in large (neighbour) element
4743 s[0] = s_hi[0];
4744 s[1] = s_hi[1];
4745 s[2] = s_hi[2];
4746 neighb_pt->object_pt()->get_x(s, x_large);
4747
4748 // Get coordinates in small element
4752 el_pt->object_pt()->get_x(s, x_small);
4753
4754 // Output
4755 if (neighbours_file.is_open())
4756 {
4757 neighbours_file << "# HI VERTEX: " << std::endl;
4758 neighbours_file << x_large[0] << " " << x_large[1] << " "
4759 << x_large[2] << " 80 \n";
4760 }
4761
4762 // Reset the error value
4763 error = 0.0;
4764
4765 // Only do this if we are NOT periodic
4766 if (is_periodic == false)
4767 {
4768 error = sqrt(pow(x_small[0] - x_large[0], 2) +
4769 pow(x_small[1] - x_large[1], 2) +
4770 pow(x_small[2] - x_large[2], 2));
4771 }
4772
4773 if (neighbours_txt_file.is_open())
4774 {
4775 neighbours_txt_file << "Error (2) " << error << std::endl;
4776 }
4777
4778 if (std::fabs(error) > max_error)
4779 {
4780 max_error = std::fabs(error);
4781 }
4782
4783 // Check error and doc mismatch if required
4784 if (std::fabs(error) > Max_neighbour_finding_tolerance)
4785 {
4786 stop = true;
4787 }
4788 if (stop)
4789 {
4790 if (!mismatch_file.is_open())
4791 {
4792 mismatch_file.open("mismatch.dat");
4793 }
4794 mismatch_file << "ZONE" << std::endl;
4795 mismatch_file << x_large[0] << " " << x_large[1] << " "
4796 << x_large[2] << " 2 \n";
4797 mismatch_file << x_small[0] << " " << x_small[1] << " "
4798 << x_small[2] << " 3 \n";
4799 mismatch_file.close();
4800 pause("Error");
4801 }
4802 }
4803
4804 // If neighbour does not exist: Insert blank zones into file
4805 // so that tecplot can find twelve neighbours for every element
4806 else
4807 {
4808 if (neighbours_file.is_open())
4809 {
4810 neighbours_file << "#---------------------------------"
4811 << std::endl;
4813 << "# No neighbour in direction: " << Direct_string[direction]
4814 << std::endl;
4815 neighbours_file << "#---------------------------------"
4816 << std::endl;
4817
4818 dynamic_cast<RefineableQElement<3>*>(el_pt->object_pt())
4819 ->output_corners(neighbours_file, "WHITE");
4820 neighbours_file << "ZONE I=2 \n";
4821 neighbours_file << "-0.05 -0.05 -0.05 0 \n";
4822 neighbours_file << "-0.05 -0.05 -0.05 0 \n";
4823
4824
4825 // Doc edge for which no neighbour exists but only
4826 // for the smallest elements
4827 if (el_pt->is_leaf())
4828 {
4829 // Get start coordinates in small element
4830 Vector<double> s(3), x_start(3), x_end(3);
4831 s[0] = S_base_edge(0, direction);
4832 s[1] = S_base_edge(1, direction);
4833 s[2] = S_base_edge(2, direction);
4834 el_pt->object_pt()->get_x(s, x_start);
4835
4836
4837 // Get coordinates in small element
4841 el_pt->object_pt()->get_x(s, x_end);
4842
4843 no_true_edge_file << "ZONE I=2" << std::endl;
4844 no_true_edge_file << x_start[0] << " " << x_start[1] << " "
4845 << x_start[2] << " " << std::endl;
4846 no_true_edge_file << x_end[0] << " " << x_end[1] << " "
4847 << x_end[2] << " " << std::endl;
4848 }
4849 }
4850
4851 if (neighbours_file.is_open())
4852 {
4853 neighbours_file << std::endl << std::endl << std::endl;
4854 }
4855 }
4856 } // End of case when element can be documented
4857 }
4858 }
4859 }
4860
4861
4862 //////////////////////////////////////////////////////////////////////
4863 //////////////////////////////////////////////////////////////////////
4864 //////////////////////////////////////////////////////////////////////
4865
4866
4867 //================================================================
4868 /// Constructor for OcTreeForest:
4869 ///
4870 /// Pass:
4871 /// - trees_pt[], the Vector of pointers to the constituent trees
4872 /// (OcTreeRoot objects)
4873 ///
4874 //=================================================================
4876 {
4877#ifdef LEAK_CHECK
4879#endif
4880
4881 // Don't setup neighbours etc. if forest is empty
4882 if (trees_pt.size() == 0)
4883 {
4884 return;
4885 }
4886
4887 using namespace OcTreeNames;
4888
4889 // Construct the neighbour and rotation scheme, note that all neighbour
4890 // pointers must be set before the constructor is called
4891
4892 // MemoryUsage::doc_memory_usage(
4893 // "before find_neighbours in octree forest constr");
4894
4895 // setup the neighbour scheme
4897
4898 // MemoryUsage::doc_memory_usage(
4899 // "after find_neighbours in octree forest constr");
4900
4901 // setup the rotation scheme
4903
4904 // MemoryUsage::doc_memory_usage(
4905 // "after construct_up_right_equivalents in octree forest constr");
4906 }
4907
4908 //================================================================
4909 /// setup the neighbour scheme : tells to each element in the
4910 /// forest which (if any) element is its {R,L,U,D,B,F} face neighbour
4911 /// and which is its {LB,RB,...,UF} edge neighbour.
4912 //================================================================
4914 {
4915 using namespace OcTreeNames;
4916 unsigned numtrees = ntree();
4917 int n = 0; // to store nnode1d
4918 if (numtrees > 0)
4919 {
4920 n = Trees_pt[0]->object_pt()->nnode_1d();
4921 }
4922 else
4923 {
4924 throw OomphLibError(
4925 "Trying to setup the neighbour scheme for an empty forest",
4928 }
4929
4930
4931 // Number of vertex nodes: 8
4932 unsigned n_vertex_node = 8;
4933
4934 // Find potentially connected trees by identifying
4935 // those whose associated elements share a common vertex node
4936 std::map<Node*, std::set<unsigned>> tree_assoc_with_vertex_node;
4937
4938 // Loop over all trees
4939 for (unsigned i = 0; i < numtrees; i++)
4940 {
4941 // Loop over the vertex nodes of the associated element
4942 for (unsigned j = 0; j < n_vertex_node; j++)
4943 {
4944 Node* nod_pt = dynamic_cast<BrickElementBase*>(Trees_pt[i]->object_pt())
4945 ->vertex_node_pt(j);
4947 }
4948 }
4949
4950
4951 // For each tree we store a set of potentially neighbouring trees
4952 // i.e. trees that share at least one node
4954
4955 // Loop over vertex nodes
4956 for (std::map<Node*, std::set<unsigned>>::iterator it =
4959 it++)
4960 {
4961 // Loop over connected elements twice
4962 for (std::set<unsigned>::iterator it_el1 = it->second.begin();
4963 it_el1 != it->second.end();
4964 it_el1++)
4965 {
4966 unsigned i = (*it_el1);
4967 for (std::set<unsigned>::iterator it_el2 = it->second.begin();
4968 it_el2 != it->second.end();
4969 it_el2++)
4970 {
4971 unsigned j = (*it_el2);
4972 // These two elements are potentially connected
4973 if (i != j)
4974 {
4975 potentially_neighb_tree[i].insert(j);
4976 }
4977 }
4978 }
4979 }
4980
4981
4982 // Loop over all trees
4983 for (unsigned i = 0; i < numtrees; i++)
4984 {
4985 // Cast to OcTreeRoot
4986 OcTreeRoot* octree_root_i_pt = dynamic_cast<OcTreeRoot*>(Trees_pt[i]);
4987
4988 // Loop over their potential neighbours
4989 for (std::set<unsigned>::iterator it = potentially_neighb_tree[i].begin();
4990 it != potentially_neighb_tree[i].end();
4991 it++)
4992 {
4993 unsigned j = (*it);
4994
4995 // So far, we haven't identified the candidate element as a face
4996 // neighbour of element/tree i
4997 bool is_face_neighbour = false;
4998
4999 // is it the Up neighbour ?
5000 bool is_Up_neighbour =
5001 ((Trees_pt[j]->object_pt()->get_node_number(
5002 Trees_pt[i]->object_pt()->node_pt(n * (n * n - 1))) != -1) &&
5003 (Trees_pt[j]->object_pt()->get_node_number(
5004 Trees_pt[i]->object_pt()->node_pt(n * n - 1)) != -1));
5005
5006 // is it the Down neighbour ?
5007 bool is_Down_neighbour =
5008 ((Trees_pt[j]->object_pt()->get_node_number(
5009 Trees_pt[i]->object_pt()->node_pt(n * n * (n - 1))) != -1) &&
5010 (Trees_pt[j]->object_pt()->get_node_number(
5011 Trees_pt[i]->object_pt()->node_pt(n - 1)) != -1));
5012
5013 // is it the Right neighbour ?
5014 bool is_Right_neighbour =
5015 ((Trees_pt[j]->object_pt()->get_node_number(
5016 Trees_pt[i]->object_pt()->node_pt(n * n * n - 1)) != -1) &&
5017 (Trees_pt[j]->object_pt()->get_node_number(
5018 Trees_pt[i]->object_pt()->node_pt(n - 1)) != -1));
5019
5020 // is it the Left neighbour ?
5021 bool is_Left_neighbour =
5022 ((Trees_pt[j]->object_pt()->get_node_number(
5023 Trees_pt[i]->object_pt()->node_pt(n * (n * n - 1))) != -1) &&
5024 (Trees_pt[j]->object_pt()->get_node_number(
5025 Trees_pt[i]->object_pt()->node_pt(0)) != -1));
5026
5027 // is it the Back neighbour ?
5028 bool is_Back_neighbour =
5029 ((Trees_pt[j]->object_pt()->get_node_number(
5030 Trees_pt[i]->object_pt()->node_pt(n * n - 1)) != -1) &&
5031 (Trees_pt[j]->object_pt()->get_node_number(
5032 Trees_pt[i]->object_pt()->node_pt(0)) != -1));
5033
5034 // is it the Front neighbour ?
5035 bool is_Front_neighbour =
5036 ((Trees_pt[j]->object_pt()->get_node_number(
5037 Trees_pt[i]->object_pt()->node_pt(n * n * n - 1)) != -1) &&
5038 (Trees_pt[j]->object_pt()->get_node_number(
5039 Trees_pt[i]->object_pt()->node_pt(n * n * (n - 1))) != -1));
5040
5041
5043 {
5044 is_face_neighbour = true;
5045 Trees_pt[i]->neighbour_pt(D) = Trees_pt[j];
5046 }
5047 if (is_Up_neighbour)
5048 {
5049 is_face_neighbour = true;
5050 Trees_pt[i]->neighbour_pt(U) = Trees_pt[j];
5051 }
5053 {
5054 is_face_neighbour = true;
5055 Trees_pt[i]->neighbour_pt(R) = Trees_pt[j];
5056 }
5058 {
5059 is_face_neighbour = true;
5060 Trees_pt[i]->neighbour_pt(L) = Trees_pt[j];
5061 }
5063 {
5064 is_face_neighbour = true;
5065 Trees_pt[i]->neighbour_pt(B) = Trees_pt[j];
5066 }
5068 {
5069 is_face_neighbour = true;
5070 Trees_pt[i]->neighbour_pt(F) = Trees_pt[j];
5071 }
5072
5073
5074 // If it's not a face neighbour, it may still be an edge
5075 // neighbour. We check this by checking if the
5076 // vertex nodes coincide. Note: This test would also
5077 // evaluate to true for face neighbours but we've already
5078 // determined that the element is not a face neighbour!
5079 if (!is_face_neighbour)
5080 {
5081 // is it the left back neighbour ?
5083 ((Trees_pt[j]->object_pt()->get_node_number(
5084 Trees_pt[i]->object_pt()->node_pt(0)) != -1) &&
5085 (Trees_pt[j]->object_pt()->get_node_number(
5086 Trees_pt[i]->object_pt()->node_pt(n * (n - 1))) != -1));
5087
5088 // is it the right back neighbour ?
5090 ((Trees_pt[j]->object_pt()->get_node_number(
5091 Trees_pt[i]->object_pt()->node_pt(n - 1)) != -1) &&
5092 (Trees_pt[j]->object_pt()->get_node_number(
5093 Trees_pt[i]->object_pt()->node_pt(n * n - 1)) != -1));
5094
5095
5096 // is it the down back neighbour ?
5098 ((Trees_pt[j]->object_pt()->get_node_number(
5099 Trees_pt[i]->object_pt()->node_pt(n - 1)) != -1) &&
5100 (Trees_pt[j]->object_pt()->get_node_number(
5101 Trees_pt[i]->object_pt()->node_pt(0)) != -1));
5102
5103 // is it the up back neighbour ?
5105 ((Trees_pt[j]->object_pt()->get_node_number(
5106 Trees_pt[i]->object_pt()->node_pt(n * (n - 1))) != -1) &&
5107 (Trees_pt[j]->object_pt()->get_node_number(
5108 Trees_pt[i]->object_pt()->node_pt(n * n - 1)) != -1));
5109
5110
5111 // is it the left down neighbour ?
5113 ((Trees_pt[j]->object_pt()->get_node_number(
5114 Trees_pt[i]->object_pt()->node_pt(n * n * (n - 1))) != -1) &&
5115 (Trees_pt[j]->object_pt()->get_node_number(
5116 Trees_pt[i]->object_pt()->node_pt(0)) != -1));
5117
5118
5119 // is it the right down neighbour ?
5121 ((Trees_pt[j]->object_pt()->get_node_number(
5122 Trees_pt[i]->object_pt()->node_pt((n * n + 1) * (n - 1))) !=
5123 -1) &&
5124 (Trees_pt[j]->object_pt()->get_node_number(
5125 Trees_pt[i]->object_pt()->node_pt(n - 1)) != -1));
5126
5127
5128 // is it the left up neighbour ?
5130 ((Trees_pt[j]->object_pt()->get_node_number(
5131 Trees_pt[i]->object_pt()->node_pt((n * n * n - n))) != -1) &&
5132 (Trees_pt[j]->object_pt()->get_node_number(
5133 Trees_pt[i]->object_pt()->node_pt(n * (n - 1))) != -1));
5134
5135
5136 // is it the right up neighbour ?
5138 ((Trees_pt[j]->object_pt()->get_node_number(
5139 Trees_pt[i]->object_pt()->node_pt((n * n * n - 1))) != -1) &&
5140 (Trees_pt[j]->object_pt()->get_node_number(
5141 Trees_pt[i]->object_pt()->node_pt(n * n - 1)) != -1));
5142
5143
5144 // is it the left front neighbour ?
5146 ((Trees_pt[j]->object_pt()->get_node_number(
5147 Trees_pt[i]->object_pt()->node_pt((n * n * n - n))) != -1) &&
5148 (Trees_pt[j]->object_pt()->get_node_number(
5149 Trees_pt[i]->object_pt()->node_pt(n * n * (n - 1))) != -1));
5150
5151
5152 // is it the right front neighbour ?
5154 ((Trees_pt[j]->object_pt()->get_node_number(
5155 Trees_pt[i]->object_pt()->node_pt((n * n * n - 1))) != -1) &&
5156 (Trees_pt[j]->object_pt()->get_node_number(
5157 Trees_pt[i]->object_pt()->node_pt((n * n + 1) * (n - 1))) !=
5158 -1));
5159
5160
5161 // is it the down front neighbour ?
5163 ((Trees_pt[j]->object_pt()->get_node_number(
5164 Trees_pt[i]->object_pt()->node_pt(n * n * (n - 1))) != -1) &&
5165 (Trees_pt[j]->object_pt()->get_node_number(
5166 Trees_pt[i]->object_pt()->node_pt((n * n + 1) * (n - 1))) !=
5167 -1));
5168
5169
5170 // is it the up front neighbour ?
5172 ((Trees_pt[j]->object_pt()->get_node_number(
5173 Trees_pt[i]->object_pt()->node_pt((n * n * n - n))) != -1) &&
5174 (Trees_pt[j]->object_pt()->get_node_number(
5175 Trees_pt[i]->object_pt()->node_pt((n * n * n - 1))) != -1));
5176
5177
5178 // Add to storage scheme for edge neighbours (only!)
5179
5181 {
5182 // Trees_pt[i]->neighbour_pt(LB)=Trees_pt[j];
5183 octree_root_i_pt->add_edge_neighbour_pt(Trees_pt[j], LB);
5184 }
5186 {
5187 // Trees_pt[i]->neighbour_pt(RB)=Trees_pt[j];
5188 octree_root_i_pt->add_edge_neighbour_pt(Trees_pt[j], RB);
5189 }
5191 {
5192 // Trees_pt[i]->neighbour_pt(DB)=Trees_pt[j];
5193 octree_root_i_pt->add_edge_neighbour_pt(Trees_pt[j], DB);
5194 }
5196 {
5197 // Trees_pt[i]->neighbour_pt(UB)=Trees_pt[j];
5198 octree_root_i_pt->add_edge_neighbour_pt(Trees_pt[j], UB);
5199 }
5200
5201
5203 {
5204 // Trees_pt[i]->neighbour_pt(LD)=Trees_pt[j];
5205 octree_root_i_pt->add_edge_neighbour_pt(Trees_pt[j], LD);
5206 }
5208 {
5209 // Trees_pt[i]->neighbour_pt(RD)=Trees_pt[j];
5210 octree_root_i_pt->add_edge_neighbour_pt(Trees_pt[j], RD);
5211 }
5213 {
5214 // Trees_pt[i]->neighbour_pt(LU)=Trees_pt[j];
5215 octree_root_i_pt->add_edge_neighbour_pt(Trees_pt[j], LU);
5216 }
5218 {
5219 // Trees_pt[i]->neighbour_pt(RU)=Trees_pt[j];
5220 octree_root_i_pt->add_edge_neighbour_pt(Trees_pt[j], RU);
5221 }
5222
5223
5225 {
5226 // Trees_pt[i]->neighbour_pt(LF)=Trees_pt[j];
5227 octree_root_i_pt->add_edge_neighbour_pt(Trees_pt[j], LF);
5228 }
5230 {
5231 // Trees_pt[i]->neighbour_pt(RF)=Trees_pt[j];
5232 octree_root_i_pt->add_edge_neighbour_pt(Trees_pt[j], RF);
5233 }
5235 {
5236 // Trees_pt[i]->neighbour_pt(DF)=Trees_pt[j];
5237 octree_root_i_pt->add_edge_neighbour_pt(Trees_pt[j], DF);
5238 }
5240 {
5241 // Trees_pt[i]->neighbour_pt(UF)=Trees_pt[j];
5242 octree_root_i_pt->add_edge_neighbour_pt(Trees_pt[j], UF);
5243 }
5244 }
5245 }
5246 }
5247 }
5248
5249
5250 //================================================================
5251 /// Construct the rotation scheme for the octree forest.
5252 /// Note that all pointers to neighbours must have been allocated
5253 /// for this to work.
5254 //================================================================
5256 {
5257 using namespace OcTreeNames;
5258
5259 // Number of trees in forest
5260 unsigned numtrees = ntree();
5261
5262 // nnode1d from first element (if it exists!)
5263 int nnode1d = 0;
5264 if (numtrees > 0)
5265 {
5266 nnode1d = Trees_pt[0]->object_pt()->nnode_1d();
5267 }
5268
5269 OcTreeRoot* neigh_pt = 0;
5270
5271 // Loop over all the trees
5272 //------------------------
5273 for (unsigned i = 0; i < numtrees; i++)
5274 {
5275 // Find the pointer to the Up neighbour
5276 //------------------------------------
5278
5279 // If there is a neighbour?
5280 if (neigh_pt != 0)
5281 {
5282 // Find the direction of the present tree, as viewed from the neighbour
5283 int direction = neigh_pt->direction_of_neighbour(octree_pt(i));
5284
5285 // If up neighbour has a pointer to this tree
5286 if (direction != Tree::OMEGA)
5287 {
5288 // The direction to the element in the neighbour
5289 // must be equivalent to the down direction in this element
5290 // Hence, the up equivalent is the reflection of that direction
5293
5294 // The right equivalent is the direction to the equivalent of
5295 // the right face in the present element, which will
5296 // be connected to the UR edge of the present element,
5297 // but will not be the face adjacent to the U boundary
5298 // i.e. the "direction" face.
5299 // We find the local node numbers, in the neighbour, of
5300 // the UR edge of the present element
5301 int nod1 = neigh_pt->object_pt()->get_node_number(
5302 octree_pt(i)->object_pt()->node_pt(nnode1d * nnode1d * nnode1d -
5303 1));
5304 int nod2 = neigh_pt->object_pt()->get_node_number(
5305 octree_pt(i)->object_pt()->node_pt(nnode1d * nnode1d - 1));
5306
5307 // Now get the other face connected to that edge in the
5308 // neighbour. It is the right equivalent
5310 neigh_pt,
5312 }
5313 else
5314 // If U neighbour does not have pointer to this tree, die
5315 {
5316 std::ostringstream error_stream;
5317 error_stream << "Tree " << i
5318 << "'s Up neighbour has no neighbour pointer to Tree "
5319 << i << std::endl;
5320
5321 throw OomphLibError(error_stream.str(),
5324 }
5325 }
5326
5327
5328 // Find the pointer to the Right neighbour
5329 //---------------------------------------
5331
5332 // If there is a neighbour?
5333 if (neigh_pt != 0)
5334 {
5335 // Find the direction of the present tree, as viewed from the neighbour
5336 int direction = neigh_pt->direction_of_neighbour(octree_pt(i));
5337
5338 // If the neighbour has a pointer to this tree
5339 if (direction != Tree::OMEGA)
5340 {
5341 // The direction to the element in the neighbour
5342 // must be equivalent to the left direction in this element
5343 // Hence, the right equivalent is the reflection of that direction
5346
5347 // The up equivalent will be the direction to the equivalent of
5348 // the up face in the neighbour, which will be connected to the
5349 // UR edge of the present element, but will not be the face
5350 // adjacent to the R boundary, i.e. the "direction" face
5351 // We find the local node numbers, in the neighbour, of the
5352 // UR edge of the present element
5353 int nod1 = neigh_pt->object_pt()->get_node_number(
5354 octree_pt(i)->object_pt()->node_pt(nnode1d * nnode1d * nnode1d -
5355 1));
5356 int nod2 = neigh_pt->object_pt()->get_node_number(
5357 octree_pt(i)->object_pt()->node_pt(nnode1d * nnode1d - 1));
5358
5359 // Now get the other face connected to that edge in the
5360 // neighbour. It is the up equivalent
5362 neigh_pt,
5364 }
5365 else
5366 {
5367 // If R neighbour does not have pointer to this tree, die
5368 std::ostringstream error_stream;
5369 error_stream << "Tree " << i
5370 << "'s Right neighbour has no neighbour pointer to Tree "
5371 << i << std::endl;
5372
5373 throw OomphLibError(error_stream.str(),
5376 }
5377 }
5378
5379
5380 // Find the pointer to the Down neighbour
5381 //--------------------------------------
5383
5384 // If there is a neighbour?
5385 if (neigh_pt != 0)
5386 {
5387 // Find the direction of the present tree, as viewed from the neighbour
5388 int direction = neigh_pt->direction_of_neighbour(octree_pt(i));
5389
5390 // If the neighbour has a pointer to this element
5391 if (direction != Tree::OMEGA)
5392 {
5393 // The direction to the element in the neighbour must be
5394 // equivalent to the up direction
5396
5397 // The right equivalent is the direction to the equivalent of
5398 // the right face in the present element, which will be
5399 // connected to the DR edge of the present element, but will
5400 // not be the face adjacent to the D boundary,
5401 // i.e. the "direction" face.
5402 // We find the local node numbers, in the neighbour, of
5403 // the RD edge of the present element
5404 int nod1 = neigh_pt->object_pt()->get_node_number(
5405 octree_pt(i)->object_pt()->node_pt(nnode1d - 1));
5406 int nod2 = neigh_pt->object_pt()->get_node_number(
5407 octree_pt(i)->object_pt()->node_pt((nnode1d * nnode1d + 1) *
5408 (nnode1d - 1)));
5409
5410 // Now get the other face connected to that edge in the neighbour.
5411 // It is the right equivalent
5413 neigh_pt,
5415 }
5416 else
5417 {
5418 // If D neighbour does not have pointer to this tree, die
5419 std::ostringstream error_stream;
5420 error_stream << "Tree " << i
5421 << "'s Down neighbour has no neighbour pointer to Tree "
5422 << i << std::endl;
5423
5424 throw OomphLibError(error_stream.str(),
5427 }
5428 }
5429
5430
5431 // Find the pointer to the Left neighbour
5432 //--------------------------------------
5434
5435 // If there is a neighbour
5436 if (neigh_pt != 0)
5437 {
5438 // Find the direction of the present tree, as viewed from the neighbour
5439 int direction = neigh_pt->direction_of_neighbour(octree_pt(i));
5440
5441 // If the neighbour has a pointer to the present element
5442 if (direction != Tree::OMEGA)
5443 {
5444 // The direction to the element in the neighbour is
5445 // must be equivalent to the right direction
5447
5448 // The up equivalent is the direction to the equivalent of the
5449 // up face in the present element, which will be connected to
5450 // the UL edge of the present element, but will not
5451 // be the face adjacent to the L boundary, i.e. the "direction"
5452 // face.
5453 // We find the local node numbers, in the neighbour, of the UL
5454 // edge
5455 int nod1 = neigh_pt->object_pt()->get_node_number(
5456 octree_pt(i)->object_pt()->node_pt((nnode1d - 1) * nnode1d));
5457 int nod2 = neigh_pt->object_pt()->get_node_number(
5458 octree_pt(i)->object_pt()->node_pt((nnode1d * nnode1d - 1) *
5459 nnode1d));
5460
5461 // Now get the other face connected to that edge in the
5462 // neighbour.It is the up equivalent
5464 neigh_pt,
5466 }
5467 else
5468 {
5469 // If L neighbour does not have pointer to this tree, die
5470 std::ostringstream error_stream;
5471 error_stream << "Tree " << i
5472 << "'s Left neighbour has no neighbour pointer to Tree "
5473 << i << std::endl;
5474
5475 throw OomphLibError(error_stream.str(),
5478 }
5479 }
5480
5481
5482 // Find the pointer to the Front neighbour
5483 //---------------------------------------
5485
5486 // If there is a neighbour?
5487 if (neigh_pt != 0)
5488 {
5489 // Find the direction of the present tree, as viewed from the neighbour
5490 int direction = neigh_pt->direction_of_neighbour(octree_pt(i));
5491
5492 // If the neighbour has a pointer to the present element
5493 if (direction != Tree::OMEGA)
5494 {
5495 // The direction to the up face will be given by the
5496 // other face connected to the UF edge in the neighbour
5497 // i.e. the face that is not given by direction
5498 // We obtain the local node numbers, in the neighbour,
5499 // of the UF edge in the present element
5500 int nod1 = neigh_pt->object_pt()->get_node_number(
5501 octree_pt(i)->object_pt()->node_pt(nnode1d * nnode1d * nnode1d -
5502 1));
5503 int nod2 = neigh_pt->object_pt()->get_node_number(
5504 octree_pt(i)->object_pt()->node_pt((nnode1d * nnode1d - 1) *
5505 nnode1d));
5506
5507 // We now get the other face connected to that edge
5508 // It is the up equivalent.
5510 neigh_pt,
5512
5513 // The direction to the right face will be given by the
5514 // other face connected to the RF edge in the neighbour
5515 // i.e. the face that is not given by the direction
5516 // We get the local node numbers, in the neighbour,
5517 // of the RF edge in the present element
5518 nod1 = neigh_pt->object_pt()->get_node_number(
5519 octree_pt(i)->object_pt()->node_pt(nnode1d * nnode1d * nnode1d -
5520 1));
5521 nod2 = neigh_pt->object_pt()->get_node_number(
5522 octree_pt(i)->object_pt()->node_pt((nnode1d * nnode1d + 1) *
5523 (nnode1d - 1)));
5524
5525 // We now get the other face connected to that edge
5526 // It is the right equivalent
5528 neigh_pt,
5530 }
5531 else
5532 {
5533 // If F neighbour does not have pointer to this tree, die
5534 std::ostringstream error_stream;
5535 error_stream << "Tree " << i
5536 << "'s Front neighbour has no neighbour pointer to Tree "
5537 << i << std::endl;
5538
5539 throw OomphLibError(error_stream.str(),
5542 }
5543 }
5544
5545
5546 // Find the pointer to the Back neighbour
5547 //--------------------------------------
5549
5550 // If there is a neighbour?
5551 if (neigh_pt != 0)
5552 {
5553 // Find the direction of the present tree, as viewed from the neighbour
5554 int direction = neigh_pt->direction_of_neighbour(octree_pt(i));
5555
5556 // If the neighbour has a pointer to the present element
5557 if (direction != Tree::OMEGA)
5558 {
5559 // The direction to the up face will be given by the
5560 // other face connected to the UB edge of the present element
5561 // i.e. not the "direction" face
5562 // We obtain the local node numbers, in the neighbour,
5563 // of the UB edge in the present element
5564 int nod1 = neigh_pt->object_pt()->get_node_number(
5565 octree_pt(i)->object_pt()->node_pt((nnode1d - 1) * nnode1d));
5566 int nod2 = neigh_pt->object_pt()->get_node_number(
5567 octree_pt(i)->object_pt()->node_pt(nnode1d * nnode1d - 1));
5568
5569 // We now get the other face connected to that edge
5570 // It is the up equivalent
5572 neigh_pt,
5574
5575 // The direction to the right face will be given by
5576 // the other face connected to the RB edge of the present
5577 // element, i.e. not the direction face.
5578 // We obtain local node numbers, in the neighbour,
5579 // of the RB edge in the present element
5580 nod1 = neigh_pt->object_pt()->get_node_number(
5581 octree_pt(i)->object_pt()->node_pt(nnode1d * nnode1d - 1));
5582 nod2 = neigh_pt->object_pt()->get_node_number(
5583 octree_pt(i)->object_pt()->node_pt(nnode1d - 1));
5584
5585 // We now get the other face connected to that edge
5586 // It is the right equivalent
5588 neigh_pt,
5590 }
5591 else
5592 {
5593 // If B neighbour does not have pointer to this tree, die
5594 std::ostringstream error_stream;
5595 error_stream << "Tree " << i
5596 << "'s Back neighbour has no neighbour pointer to Tree "
5597 << i << std::endl;
5598
5599 throw OomphLibError(error_stream.str(),
5602 }
5603 }
5604
5605
5606 // EDGE NEIGHBOURS
5607 //----------------
5608
5609 // Loop over all edges:
5610 for (int edge = LB; edge <= UF; edge++)
5611 {
5612 // Get vector to pointers of edge neighbours
5614
5615 // Loop over all edge neighbours
5616 unsigned n_neigh = edge_neigh_pt.size();
5617 for (unsigned e = 0; e < n_neigh; e++)
5618 {
5619 // If there is a neighbour
5620 if (edge_neigh_pt[e] != 0)
5621 {
5622 // Here are the two vertices at the two ends of the edge
5623 // in the present element
5626
5627 // Get node numbers of the two vertices on edge
5629 unsigned nod2 =
5631
5632
5633 // Here are the local node numbers (in the neighbouring element)
5634 // of the start/end nodes of present element's edge:
5635 unsigned neighb_nod1 =
5636 edge_neigh_pt[e]->object_pt()->get_node_number(
5637 octree_pt(i)->object_pt()->node_pt(nod1));
5638
5639 unsigned neighb_nod2 =
5640 edge_neigh_pt[e]->object_pt()->get_node_number(
5641 octree_pt(i)->object_pt()->node_pt(nod2));
5642
5643 // Convert to vertices
5644 int neighb_vertex =
5648
5649 // Up equivalent is stored first in the pair that's returned
5650 // by the lookup table
5654 [std::make_pair(
5655 std::make_pair(neighb_vertex, vertex),
5656 std::make_pair(neighb_other_vertex, other_vertex))]
5657 .first);
5658
5659 // Right equivalent is stored second in the pair that's returned
5660 // by the lookup table
5664 [std::make_pair(
5665 std::make_pair(neighb_vertex, vertex),
5666 std::make_pair(neighb_other_vertex, other_vertex))]
5667 .second);
5668 }
5669 }
5670 }
5671 } // end of loop over all trees.
5672 }
5673
5674
5675 //================================================================
5676 /// Self test: Check neighbour finding routine
5677 //=================================================================
5679 {
5680 // Stick pointers to all nodes into Vector and number elements
5681 // in the process
5684 long int count = 0;
5685 unsigned long num_nodes = all_nodes_pt.size();
5686 for (unsigned long i = 0; i < num_nodes; i++)
5687 {
5688 all_nodes_pt[i]->object_pt()->set_number(++count);
5689 }
5690
5691 // Check neighbours vertices and their opposite points
5692 std::ofstream neighbours_file;
5693 std::ofstream no_true_edge_file;
5694 std::ofstream neighbours_txt_file;
5695
5696 double max_error_face = 0.0;
5699
5700 double max_error_edge = 0.0;
5706
5707 bool failed = false;
5709 {
5710 oomph_info << "\n\n Failed self_test() for OcTreeForest because of "
5711 "faces: Max. error "
5712 << max_error_face << std::endl
5713 << std::endl;
5714 failed = true;
5715 }
5716
5718 {
5719 oomph_info << "\n\n Failed self_test() for OcTreeForest because of "
5720 "edges: Max. error "
5721 << max_error_edge << std::endl
5722 << std::endl;
5723 failed = true;
5724 }
5725
5726 double max_error = max_error_face;
5727 if (max_error_edge > max_error) max_error = max_error_edge;
5728
5729 if (failed)
5730 {
5731 return 1;
5732 }
5733 else
5734 {
5735 oomph_info << "\nPassed self_test() for OcTreeForest: Max. error "
5736 << max_error << std::endl;
5737 return 0;
5738 }
5739 }
5740
5741
5742 //================================================================
5743 /// Document and check all the neighbours of all the nodes
5744 /// in the forest. DocInfo object specifies the output directory
5745 /// and file numbers for the various files. If
5746 /// \c doc_info.is_doc_enabled()=false
5747 /// no output is created.
5748 //================================================================
5750 {
5751 // Create vector of all elements in the tree
5753 this->stick_all_tree_nodes_into_vector(all_tree_nodes_pt);
5754
5755 // Face neighbours
5756 //----------------
5757 {
5758 // Create storage for the files
5759 std::ofstream neigh_file;
5760 std::ofstream neigh_txt_file;
5761 // If we are documenting, then do so
5762 if (doc_info.is_doc_enabled())
5763 {
5764 std::ostringstream fullname;
5765 fullname << doc_info.directory() << "/neighbours" << doc_info.number()
5766 << ".dat";
5767 oomph_info << "opened " << fullname.str() << " to doc neighbours"
5768 << std::endl;
5769 neigh_file.open(fullname.str().c_str());
5770 fullname.str("");
5771 fullname << doc_info.directory() << "/neighbours" << doc_info.number()
5772 << ".txt";
5773 oomph_info << "opened " << fullname.str() << " to doc neighbours"
5774 << std::endl;
5775 neigh_txt_file.open(fullname.str().c_str());
5776 }
5777
5778 // Call the static member of OcTree function
5779 double max_error = 0.0;
5782 if (max_error > Tree::max_neighbour_finding_tolerance())
5783 {
5784 std::ostringstream error_stream;
5785 error_stream << "\nMax. error in octree neighbour finding: "
5786 << max_error << " is too big" << std::endl;
5788 << "i.e. bigger than Tree::max_neighbour_finding_tolerance()="
5789 << Tree::max_neighbour_finding_tolerance() << std::endl;
5790
5791 // Close the files if they were opened
5792 if (doc_info.is_doc_enabled())
5793 {
5794 neigh_file.close();
5795 neigh_txt_file.close();
5796 }
5797
5798 throw OomphLibError(
5800 }
5801 else
5802 {
5803 oomph_info << "\nMax. error in octree neighbour finding: " << max_error
5804 << " is OK" << std::endl;
5806 << "i.e. less than OcTree::max_neighbour_finding_tolerance()="
5808 }
5809
5810 // Close the documentation files if they were opened
5811 if (doc_info.is_doc_enabled())
5812 {
5813 neigh_file.close();
5814 neigh_txt_file.close();
5815 }
5816 }
5817
5818 // Edge neighbours
5819 //----------------
5820 {
5821 // Create storage for the files
5822 std::ofstream neigh_file;
5823 std::ofstream no_true_edge_file;
5824 std::ofstream neigh_txt_file;
5825 // If we are documenting, then do so
5826 if (doc_info.is_doc_enabled())
5827 {
5828 std::ostringstream fullname;
5829 fullname << doc_info.directory() << "/edge_neighbours"
5830 << doc_info.number() << ".dat";
5831 neigh_file.open(fullname.str().c_str());
5832 fullname.str("");
5833 fullname << doc_info.directory() << "/no_true_edge" << doc_info.number()
5834 << ".dat";
5835 no_true_edge_file.open(fullname.str().c_str());
5836 fullname.str("");
5837 fullname << doc_info.directory() << "/edge_neighbours"
5838 << doc_info.number() << ".txt";
5839 neigh_txt_file.open(fullname.str().c_str());
5840 }
5841
5842 // Call the static member of OcTree function
5843 double max_error = 0.0;
5844 // Get the maximum error between edge neighbours
5846 neigh_file,
5849 max_error);
5850 if (max_error > Tree::max_neighbour_finding_tolerance())
5851 {
5852 std::ostringstream error_stream;
5853 error_stream << "Max. error in octree edge neighbour finding: "
5854 << max_error << " is too big" << std::endl;
5856 << "i.e. bigger than Tree::max_neighbour_finding_tolerance()="
5857 << Tree::max_neighbour_finding_tolerance() << std::endl;
5858
5859 // Close the files if they were opened
5860 if (doc_info.is_doc_enabled())
5861 {
5862 neigh_file.close();
5863 no_true_edge_file.close();
5864 neigh_txt_file.close();
5865 }
5866
5867 throw OomphLibError(
5869 }
5870 else
5871 {
5872 oomph_info << "Max. error in octree edge neighbour finding: "
5873 << max_error << " is OK" << std::endl;
5875 << "i.e. less than OcTree::max_neighbour_finding_tolerance()="
5877 }
5878
5879 // Close the documentation files if they were opened
5880 if (doc_info.is_doc_enabled())
5881 {
5882 neigh_file.close();
5883 no_true_edge_file.close();
5884 neigh_txt_file.close();
5885 }
5886 }
5887 }
5888
5889
5890 //================================================================
5891 /// Open output files that will stored any hanging nodes that are
5892 /// created in the mesh refinement process.
5893 /// ===============================================================
5896 {
5897 // In 3D, there will be six output files
5898 for (unsigned i = 0; i < 6; i++)
5899 {
5900 output_stream.push_back(new std::ofstream);
5901 }
5902
5903 // If we are documenting the output, open the files
5904 if (doc_info.is_doc_enabled())
5905 {
5906 std::ostringstream fullname;
5907 fullname << doc_info.directory() << "/hang_nodes_u" << doc_info.number()
5908 << ".dat";
5909 output_stream[0]->open(fullname.str().c_str());
5910 fullname.str("");
5911 fullname << doc_info.directory() << "/hang_nodes_d" << doc_info.number()
5912 << ".dat";
5913 output_stream[1]->open(fullname.str().c_str());
5914 fullname.str("");
5915 fullname << doc_info.directory() << "/hang_nodes_l" << doc_info.number()
5916 << ".dat";
5917 output_stream[2]->open(fullname.str().c_str());
5918 fullname.str("");
5919 fullname << doc_info.directory() << "/hang_nodes_r" << doc_info.number()
5920 << ".dat";
5921 output_stream[3]->open(fullname.str().c_str());
5922 fullname.str("");
5923 fullname << doc_info.directory() << "/hang_nodes_b" << doc_info.number()
5924 << ".dat";
5925 output_stream[4]->open(fullname.str().c_str());
5926 fullname.str("");
5927 fullname << doc_info.directory() << "/hang_nodes_f" << doc_info.number()
5928 << ".dat";
5929 output_stream[5]->open(fullname.str().c_str());
5930 }
5931 }
5932
5933
5934} // namespace oomph
e
Definition cfortran.h:571
static char t char * s
Definition cfortran.h:568
static int num_elem(char *strv, unsigned elem_len, int term_char, int num_term) static int num_elem(strv
cstr elem_len * i
Definition cfortran.h:603
Base class for all brick elements.
Definition Qelements.h:1233
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.
double size() const
Calculate the size of the element (length, area, volume,...) in Eulerian computational coordinates....
Definition elements.cc:4320
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:1889
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition elements.h:2179
virtual unsigned nnode_1d() const
Return the number of nodes along one edge of the element Default is to return zero — must be overload...
Definition elements.h:2222
int get_node_number(Node *const &node_pt) const
Return the number of the node *node_pt if this node is in the element, else return -1;.
Definition elements.cc:3844
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition nodes.h:906
OcTreeForest()
Default constructor (empty and broken)
Definition octree.h:935
OcTreeRoot * octree_pt(const unsigned &i) const
Return pointer to i-th OcTree in forest (Performs a dynamic cast from the TreeRoot to a OcTreeRoot).
Definition octree.h:973
OcTreeRoot * oc_face_neigh_pt(const unsigned &i, const int &direction)
Given the number i of the root octree in this forest, return pointer to its face neighbour in the spe...
Definition octree.h:982
Vector< TreeRoot * > oc_edge_neigh_pt(const unsigned &i, const int &direction)
Given the number i of the root octree in this forest, return the vector of pointers to the true edge ...
Definition octree.h:1002
void find_neighbours()
Construct the neighbour scheme.
Definition octree.cc:4913
void open_hanging_node_files(DocInfo &doc_info, Vector< std::ofstream * > &output_stream)
Open output files that will store any hanging nodes in the forest and return a vector of the streams.
Definition octree.cc:5894
void construct_up_right_equivalents()
Construct the rotation schemes.
Definition octree.cc:5255
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 octree.cc:5749
unsigned self_test()
Self-test: Check all neighbours. Return success (0) if the max. distance between corresponding points...
Definition octree.cc:5678
OcTreeRoot is a OcTree that forms the root of a (recursive) octree. The "root node" is special as it ...
Definition octree.h:611
void set_up_equivalent(TreeRoot *tree_root_pt, const int &dir)
Set up equivalent of the neighbours specified by pointer: When viewed from the current octree's neigh...
Definition octree.h:779
void set_right_equivalent(TreeRoot *tree_root_pt, const int &dir)
The same thing as up_equivalent, but for the right direction: When viewed from the current octree nei...
Definition octree.h:806
OcTree class: Recursively defined, generalised octree.
Definition octree.h:114
static DenseMatrix< double > S_step_edge
Each edge of the RefineableQElement<3> that is represented by the octree is parametrised by one (of t...
Definition octree.h:593
static Vector< std::string > Colour
Colours for neighbours in various directions.
Definition octree.h:540
static DenseMatrix< double > S_base
s_base(i,direction): Initial value for coordinate s[i] on the face indicated by direction (L/R/U/D/F/...
Definition octree.h:544
static DenseMatrix< double > S_directhi
Relative to the left/down/back vertex in any (father) octree, the corresponding vertex in the son spe...
Definition octree.h:581
static DenseMatrix< bool > Is_adjacent
Array of direction/octant adjacency scheme: Is_adjacent(direction,octant): Is face/edge direction adj...
Definition octree.h:529
static Vector< int > rotate(const int &new_up, const int &new_right, const Vector< int > &dir)
If U[p] becomes new_up and R[ight] becomes new_right then the direction vector dir becomes rotate(new...
Definition octree.cc:750
static Vector< int > faces_of_common_edge(const int &edge)
Function that, given an edge, returns the two faces on which it.
Definition octree.cc:268
static Vector< std::string > Direct_string
Translate (enumerated) directions into strings.
Definition octree.h:329
static DenseMatrix< double > S_directlo
Relative to the left/down/back vertex in any (father) octree, the corresponding vertex in the son spe...
Definition octree.h:573
static int node_number_to_vertex(const unsigned &n, const unsigned &nnode1d)
Return the vertex [LDB,RDB,...] of local (vertex) node n in an element with nnode1d nodes in each coo...
Definition octree.cc:491
static void mult_mat_vect(const DenseMatrix< int > &mat, const Vector< int > &vect1, Vector< int > &vect2)
Helper function: Performs the operation : vect2 = mat*vect1.
Definition octree.cc:687
static DenseMatrix< int > Common_face
Determine common face of edges or octants. Slightly bizarre lookup scheme from Samet's book.
Definition octree.h:537
static Vector< int > Reflect_face
Get opposite face, e.g. Reflect_face[L]=R.
Definition octree.h:332
static Vector< int > Sini
Entry in rotation matrix sin(i*90)
Definition octree.h:523
static void setup_static_data()
Setup the static data, rotation and reflection schemes, etc.
Definition octree.cc:1040
unsigned self_test()
Self-test: Check all neighbours. Return success (0) if the max. distance between corresponding points...
Definition octree.cc:4200
OcTree * gteq_face_neighbour(const int &direction, Vector< unsigned > &translate_s, Vector< double > &s_sw, Vector< double > &s_ne, int &face, int &diff_level, bool &in_neighbouring_tree) const
Find (pointer to) ‘greater-or-equal-sized face neighbour’ in given direction (L/R/U/D/F/B)....
Definition octree.cc:3373
static Vector< int > vertex_node_to_vector(const unsigned &n, const unsigned &nnode1d)
Returns the vector of the coordinate directions of vertex node number n in an element with nnode1d el...
Definition octree.cc:232
static void doc_true_edge_neighbours(Vector< Tree * > forest_nodes_pt, std::ofstream &neighbours_file, std::ofstream &no_true_edge_file, std::ofstream &neighbours_txt_file, double &max_error)
Doc/check all true edge neighbours of octree (nodes) contained in the Vector forest_node_pt....
Definition octree.cc:4552
static std::map< std::pair< std::pair< int, int >, std::pair< int, int > >, std::pair< int, int > > Up_and_right_equivalent_for_pairs_of_vertices
Storage for the up/right-equivalents corresponding to two pairs of vertices along an element edge:
Definition octree.h:377
static DenseMatrix< double > S_base_edge
S_base_edge(i,edge): Initial value for coordinate s[i] on the specified edge (LF/RF/....
Definition octree.h:585
static Vector< int > Cosi
Entry in rotation matrix: cos(i*90)
Definition octree.h:520
static DenseMatrix< int > Reflect
Reflection scheme: Reflect(direction,octant): Get mirror of octant/edge in specified direction....
Definition octree.h:533
static int get_the_other_face(const unsigned &n1, const unsigned &n2, const unsigned &nnode1d, const int &face)
If an edge is bordered by the nodes whose local numbers are n1 and n2 in an element with nnode1d node...
Definition octree.cc:565
OcTree * gteq_true_edge_neighbour(const int &direction, const unsigned &i_root_edge_neighbour, unsigned &nroot_edge_neighbour, Vector< unsigned > &translate_s, Vector< double > &s_lo, Vector< double > &s_hi, int &edge, int &diff_level) const
Find (pointer to) ‘greater-or-equal-sized true edge neighbour’ in the given direction (LB,...
Definition octree.cc:3618
bool edge_neighbour_is_face_neighbour(const int &edge, OcTree *edge_neighb_pt) const
Is the edge neighbour (for edge "edge") specified via the pointer also a face neighbour for one of th...
Definition octree.cc:2769
OcTree * gteq_edge_neighbour(const int &direction, const unsigned &i_root_edge_neighbour, unsigned &nroot_edge_neighbour, double &s_diff, int &diff_level, int max_level, OcTreeRoot *orig_root_pt) const
Find ‘greater-or-equal-sized edge neighbour’ in given direction (LB,RB,DB,UB [the back edges],...
Definition octree.cc:4015
static DenseMatrix< double > S_direct_edge
Relative to the left/down/back vertex in any (father) octree, the corresponding vertex in the son spe...
Definition octree.h:600
static Vector< int > Reflect_vertex
Get opposite vertex, e.g. Reflect_vertex[LDB]=RUF.
Definition octree.h:338
static Vector< Vector< int > > Vertex_at_end_of_edge
Vector of vectors containing the two vertices for each edge, e.g. Vertex_at_end_of_edge[LU][0]=LUB an...
Definition octree.h:343
static void construct_rotation_matrix(int &axis, int &angle, DenseMatrix< int > &mat)
This constructs the rotation matrix of the rotation around the axis axis with an angle of angle*90.
Definition octree.cc:609
static void mult_mat_mat(const DenseMatrix< int > &mat1, const DenseMatrix< int > &mat2, DenseMatrix< int > &mat3)
Helper function: Performs the operation : mat3=mat1*mat2.
Definition octree.cc:664
static bool Static_data_has_been_setup
Bool indicating that static member data has been setup.
Definition octree.h:412
static DenseMatrix< double > S_stephi
If we're located on face face [L/R/F/B/U/D], then an increase in s_hi from -1 to +1 corresponds to a ...
Definition octree.h:565
static Vector< Vector< int > > Direction_to_vector
For each direction, i.e. a son_type (vertex), a face or an edge, this defines a vector that indicates...
Definition octree.h:353
static Vector< int > Reflect_edge
Get opposite edge, e.g. Reflect_edge[DB]=UF.
Definition octree.h:335
static std::map< Vector< int >, int > Vector_to_direction
Each vector representing a direction can be translated into a direction, either a son type (vertex),...
Definition octree.h:348
static DenseMatrix< double > S_steplo
Each face of the RefineableQElement<3> that is represented by the octree is parametrised by two (of t...
Definition octree.h:558
static unsigned vertex_to_node_number(const int &vertex, const unsigned &nnode1d)
Return the local node number of given vertex [LDB,RDB,...] in an element with nnode1d nodes in each c...
Definition octree.cc:414
static void doc_face_neighbours(Vector< Tree * > forest_nodes_pt, std::ofstream &neighbours_file, std::ofstream &neighbours_txt_file, double &max_error)
Doc/check all face neighbours of octree (nodes) contained in the Vector forest_node_pt....
Definition octree.cc:4275
An OomphLibError object which should be thrown when an run-time error is encountered....
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
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
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
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
static double & max_neighbour_finding_tolerance()
Max. allowed discrepancy in neighbour finding routine (distance between points when identified from t...
Definition tree.h:255
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
static double Max_neighbour_finding_tolerance
Max. allowed discrepancy in neighbour finding routine (distance between points when identified from t...
Definition tree.h:313
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
void pause(std::string message)
Pause and display message.
OomphInfo oomph_info
Single (global) instantiation of the OomphInfo object – this is used throughout the library as a "rep...