1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
29 #include "treeBoundBox.H"
31 #include "linePointRef.H"
33 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
36 const Foam::label Foam::treeNode<Type>::leafOffset(100);
39 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
42 void Foam::treeNode<Type>::setAsNode(const label octant)
44 subNodeTypes_ |= (0x1 << octant);
49 void Foam::treeNode<Type>::setAsLeaf(const label octant)
51 subNodeTypes_ &= ~(0x1 << octant);
55 // Set pointer to sub node
57 void Foam::treeNode<Type>::setNodePtr
60 treeElem<Type>* treeNodePtr
64 subNodes_[octant] = treeNodePtr;
68 // Set pointer to sub leaf
70 void Foam::treeNode<Type>::setLeafPtr
73 treeElem<Type>* treeLeafPtr
77 subNodes_[octant] = treeLeafPtr;
82 void Foam::treeNode<Type>::setVolType
88 if ((type < 0) || (type > 3))
90 FatalErrorIn("treeNode<Type>::setVolType(const label, const label)")
91 << "Type " << type << " not within range 0..3" << endl;
94 // Clear out two bits at position 2*octant
95 volType_ &= ~(0x3 << 2*octant);
97 // Add the two bits of type
98 volType_ |= (type << 2*octant);
102 template <class Type>
103 void Foam::treeNode<Type>::space(Ostream& os, const label n)
105 for (label i=0; i<n; i++)
112 // look in single octant starting from <start>
113 template <class Type>
114 const Foam::treeLeaf<Type>* Foam::treeNode<Type>::findLeafLineOctant
119 const vector& direction,
124 static const char* functionName =
125 "treeNode<Type>::findLeafLineOctant"
126 "(const int, const Type&, const label, const vector&,"
127 " point&, const point&)";
131 space(Pout, 2*level);
132 Pout<< "findLeafLineOctant : bb:" << this->bb()
133 << " start:" << start
135 << " mid:" << midpoint()
136 << " Searching octant:" << octant
140 if (subNodes()[octant])
144 // Node: recurse into subnodes
145 const treeNode<Type>* subNodePtr = getNodePtr(octant);
147 if (subNodePtr->bb().contains(direction, start))
149 // Search on lower level
150 const treeLeaf<Type>* subLeafPtr = subNodePtr->findLeafLine
160 space(Pout, 2*level);
161 Pout<< "findLeafLineOctant : bb:" << this->bb()
162 << " returning from sub treeNode"
163 << " with start:" << start << " subLeaf:"
164 << long(subLeafPtr) << endl;
171 FatalErrorIn(functionName)
172 << "Sub node " << subNodePtr->bb()
173 << " at octant " << octant
174 << " does not contain start " << start
175 << abort(FatalError);
181 const treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
183 if (subLeafPtr->bb().contains(direction, start))
185 // Step to end of subleaf bb
189 !subLeafPtr->bb().intersects
197 FatalErrorIn(functionName)
198 << "Sub leaf contains start " << start
199 << " but line does not intersect its bb "
201 << abort(FatalError);
207 space(Pout, 2*level);
208 Pout<< "findLeafLineOctant : returning from intersecting"
209 << " treeLeaf " << subLeafPtr->bb()
210 << " with start:" << start << " subLeaf:"
211 << long(subLeafPtr) << endl;
218 FatalErrorIn(functionName)
219 << "Sub leaf " << subLeafPtr->bb()
220 << " at octant " << octant
221 << " does not contain start " << start
222 << abort(FatalError);
228 // Empty subNode. Transfer across.
229 const treeBoundBox emptyBb = this->bb().subBbox(midpoint(), octant);
231 if (emptyBb.contains(direction, start))
235 space(Pout, 2*level);
236 Pout<< "findLeafLineOctant : Empty node. Octant:" << octant
237 << " start:" << start
238 << " bb:" << this->bb()
239 << " emptyBb:" << emptyBb << endl;
242 // Update start by clipping to emptyBb
254 FatalErrorIn(functionName)
255 << "Empty node contains start " << start
256 << " but line does not intersect its (calculated)"
258 << endl << "This might be due to truncation error"
259 << abort(FatalError);
265 space(Pout, 2*level);
266 Pout<< "findLeafLineOctant : returning from intersecting with"
267 << " empty " << emptyBb
268 << " with start:" << start << " subLeaf:" << 0 << endl;
275 FatalErrorIn(functionName)
276 << "Empty node " << emptyBb
277 << " at octant " << octant
278 << " does not contain start " << start
279 << abort(FatalError);
283 FatalErrorIn(functionName)
284 << "Octant " << octant << " of cube " << this->bb()
285 << " does not contain start " << start
286 << abort(FatalError);
292 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
294 // Construct from components
295 template <class Type>
296 Foam::treeNode<Type>::treeNode(const treeBoundBox& bb)
304 for (label octantI=0; octantI<8; octantI++)
306 subNodes_[octantI] = NULL;
307 setVolType(octantI, octree<Type>::UNKNOWN);
312 // Construct from Istream
313 template <class Type>
314 Foam::treeNode<Type>::treeNode(Istream& is)
320 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
322 template <class Type>
323 Foam::treeNode<Type>::~treeNode()
325 for (int octant=0; octant<8; octant++)
327 if (subNodes()[octant])
331 delete getNodePtr(octant);
335 delete getLeafPtr(octant);
342 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
344 // Distributes cells to subLeaves
345 template <class Type>
346 void Foam::treeNode<Type>::distribute
351 const labelList& indices
357 Pout<< "treeNode::distributing " << indices.size() << endl;
360 // Create subLeaves if necessary
361 for (label octant=0; octant<8; octant++)
363 if (subNodes()[octant])
365 printNode(Pout, level);
368 "treeNode<Type>::distribute(const label, octree<Type>&, "
369 "const Type&, const labelList&)"
370 ) << "subNode already available at octant:" << octant
371 << abort(FatalError);
375 treeLeaf<Type>* subLeafPtr = new treeLeaf<Type>
377 this->bb().subBbox(midpoint(), octant),
381 top.setLeaves(top.nLeaves() + 1);
382 setLeafPtr(octant, subLeafPtr);
387 // add cells to correct sub leaf
390 const label shapei = indices[i];
392 for (label octant=0; octant<8; octant++)
394 treeLeaf<Type>* leafPtr = getLeafPtr(octant);
396 if (shapes.overlaps(shapei, leafPtr->bb()))
401 Pout<< "inserting " << shapei;
402 shapes.write(Pout, shapei);
403 Pout<< " into " << leafPtr->bb() << endl;
405 leafPtr->insert(shapei);
406 top.setEntries(top.nEntries() + 1);
411 // Trim size of subLeaves
412 for (label octant=0; octant<8; octant++)
414 treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
416 if (subLeafPtr->size() == 0)
418 // Contains no data. Delete.
419 setLeafPtr(octant, NULL);
421 top.setLeaves(top.nLeaves() - 1);
425 // Trim to actual size.
433 Pout<< "end of treeNode::distribute" << endl;
438 // Descends to refineLevel and checks the subLeaves for redistribution
439 template <class Type>
440 void Foam::treeNode<Type>::redistribute
445 const label refineLevel
451 Pout<< "treeNode::redistribute with level:" << level
452 << " refineLevel:" << refineLevel << endl;
455 // Descend to correct level
456 if (level < refineLevel)
458 for (label octant=0; octant<8; octant++)
460 if (subNodes()[octant])
464 getNodePtr(octant)->redistribute
477 // Reached correct (should also be deepest) level of treeNode
481 Pout<< "treeNode::redistribute : now at correct level" << endl;
484 // handle redistribution of sub leaves
485 for (label octant=0; octant<8; octant++)
487 if (subNodes()[octant])
493 "treeNode<Type>::redistribute(const int, octree& top,"
494 "const int, const treeBoundBox&)"
495 ) << "found treeNode instead of treeLeaf" << endl
496 << abort(FatalError);
500 treeLeaf<Type>* leafPtr = getLeafPtr(octant);
502 treeLeaf<Type>* newSubPtr = leafPtr->redistribute
509 if (newSubPtr && (newSubPtr != leafPtr))
511 // redistribute has created nodePtr
512 // so delete no longer used subPtr and update info
516 << top.nEntries() - leafPtr->size()
517 << " entries" << endl;
519 top.setEntries(top.nEntries() - leafPtr->size());
523 top.setLeaves(top.nLeaves() - 1);
525 setNodePtr(octant, newSubPtr);
533 Pout<< "end of treeNode::redistribute for correct level" << endl;
540 Pout<< "return from treeNode::redistribute with bb:" << this->bb()
547 template <class Type>
548 Foam::label Foam::treeNode<Type>::setSubNodeType
558 Pout<< "treeNode::setSubNodeType with level:" << level
559 << " bb:" << this->bb() << endl;
564 for (label octant=0; octant<8; octant++)
568 if (subNodes()[octant])
572 subType = getNodePtr(octant)->setSubNodeType
581 subType = getLeafPtr(octant)->setSubNodeType
591 // No data in this one. Set type for octant acc. to its bounding
593 const treeBoundBox subBb = this->bb().subBbox(midpoint(), octant);
595 subType = shapes.getSampleType(top, subBb.midpoint());
601 Pout<< "treeNode::setSubNodeType : setting octant with bb:"
602 << this->bb().subBbox(midpoint(), octant)
603 << " to type:" << octree<Type>::volType(subType) << endl;
605 setVolType(octant, subType);
607 // Combine sub node types into type for treeNode. Result is 'mixed' if
608 // types differ among subnodes.
613 else if (subType != myType)
615 myType = octree<Type>::MIXED;
622 Pout<< "return from treeNode::setSubNodeType with type:"
623 << octree<Type>::volType(myType)
624 << " bb:" << this->bb() << endl;
632 template <class Type>
633 Foam::label Foam::treeNode<Type>::getSampleType
636 const octree<Type>& top,
644 Pout<< "treeNode::getSampleType with level:" << level
645 << " bb:" << this->bb() << " sample:" << sample << endl;
648 // Determine octant of bb. If on edge just use whichever octant.
651 label octant = this->bb().subOctant(midpoint(), sample, onEdge);
653 label type = getVolType(octant);
655 if (type == octree<Type>::MIXED)
657 // At this level multiple sub types. Recurse to resolve.
658 if (subNodes()[octant])
662 // Node: recurse into subnodes
663 type = getNodePtr(octant)->getSampleType
674 type = getLeafPtr(octant)->getSampleType
685 // Problem: empty subnode should have a type
688 "treeNode<Type>::getSampleType"
689 "(const label, octree<Type>&, const Type&, const point&)"
690 ) << "Empty node bb:" << this->bb().subBbox(midpoint(), octant)
691 << " has non-mixed type:"
692 << octree<Type>::volType(type)
693 << abort(FatalError);
697 if (type == octree<Type>::MIXED)
701 "treeNode<Type>::getSampleType"
702 "(const label, octree<Type>&, const Type&, const point&)"
703 ) << "Type is MIXED when searching for " << sample
704 << " at level " << this->bb() << endl
705 << "This probably is because the octree has not been constructed"
706 << " with search facility." << exit(FatalError);
712 Pout<< "return from treeNode::getSampleType with type:"
713 << octree<Type>::volType(type)
714 << " bb:" << this->bb()
715 << " sample:" << sample << endl;
721 template <class Type>
722 Foam::label Foam::treeNode<Type>::find
728 // Find octant of sample. Don't care if on edge (since any item on edge
729 // will have been inserted in both subcubes)
732 label octant = this->bb().subOctant(midpoint(), sample, onEdge);
734 if (subNodes()[octant])
738 // Node: recurse into subnodes
739 return getNodePtr(octant)->find(shapes, sample);
743 // Leaf: let leaf::find handle this
744 return getLeafPtr(octant)->find(shapes, sample);
751 template <class Type>
752 bool Foam::treeNode<Type>::findTightest
756 treeBoundBox& tightest
759 bool changed = false;
761 // Estimate for best place to start searching
762 label sampleOctant = this->bb().subOctant(midpoint(), sample, onEdge);
764 // Go into all suboctants (one containing sample first) and update tightest.
765 // Order of visiting is if e.g. sampleOctant = 5:
767 for (label octantI=0; octantI<8; octantI++)
772 // Use sampleOctant first
773 octant = sampleOctant;
775 else if (octantI == sampleOctant)
784 if (subNodes()[octant])
788 // Node: recurse into subnodes
789 const treeNode<Type>* subNodePtr = getNodePtr(octant);
791 if (subNodePtr->bb().overlaps(tightest))
793 // there might be a better fit inside this subNode
794 changed |= subNodePtr->findTightest
804 // Leaf: let leaf::find handle this
805 const treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
807 if (subLeafPtr->bb().overlaps(tightest))
809 // there might be a better fit inside this subLeaf
810 changed |= subLeafPtr->findTightest
825 template <class Type>
826 bool Foam::treeNode<Type>::findNearest
830 treeBoundBox& tightest,
837 Pout<< "In findNearest with sample:" << sample << " cube:"
838 << this->bb() << " tightest:" << tightest << endl;
841 bool changed = false;
843 // Estimate for best place to start searching
844 label sampleOctant = this->bb().subOctant(midpoint(), sample, onEdge);
846 // Go into all suboctants (one containing sample first) and update tightest.
847 // Order of visiting is if e.g. sampleOctant = 5:
849 for (label octantI=0; octantI<8; octantI++)
854 // Use sampleOctant first
855 octant = sampleOctant;
857 else if (octantI == sampleOctant)
866 if (subNodes()[octant])
871 const treeNode<Type>* subNodePtr = getNodePtr(octant);
873 if (subNodePtr->bb().overlaps(tightest))
875 // there might be a better fit inside this subNode
876 changed |= subNodePtr->findNearest
888 // Leaf: let leaf::find handle this
889 const treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
891 if (subLeafPtr->bb().overlaps(tightest))
893 // there might be a better fit inside this subNode
894 changed |= subLeafPtr->findNearest
909 Pout<< "Exiting findNearest for sample:" << sample << " cube:"
910 << this->bb() << " tightestI:" << tightestI << endl;
917 template <class Type>
918 bool Foam::treeNode<Type>::findNearest
921 const linePointRef& ln,
922 treeBoundBox& tightest,
924 point& linePoint, // nearest point on line
925 point& shapePoint // nearest point on shape
928 bool changed = false;
930 // Estimate for best place to start searching
931 label sampleOctant = this->bb().subOctant(midpoint(), ln.centre(), onEdge);
933 // Go into all suboctants (one containing sample first) and update tightest.
934 // Order of visiting is if e.g. sampleOctant = 5:
936 for (label octantI=0; octantI<8; octantI++)
941 // Use sampleOctant first
942 octant = sampleOctant;
944 else if (octantI == sampleOctant)
953 if (subNodes()[octant])
958 const treeNode<Type>* subNodePtr = getNodePtr(octant);
960 if (subNodePtr->bb().overlaps(tightest))
962 // there might be a better fit inside this subNode
963 changed |= subNodePtr->findNearest
976 // Leaf: let leaf::find handle this
977 const treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
979 if (subLeafPtr->bb().overlaps(tightest))
981 // there might be a better fit inside this subNode
982 changed |= subLeafPtr->findNearest
1000 template <class Type>
1001 bool Foam::treeNode<Type>::findBox
1004 const boundBox& box,
1005 labelHashSet& elements
1008 bool changed = false;
1009 bool onEdge = false;
1010 // Estimate for best place to start searching
1011 label sampleOctant = this->bb().subOctant
1018 // Go into all suboctants (one containing sample first) and update tightest.
1019 // Order of visiting is if e.g. sampleOctant = 5:
1021 for (label octantI=0; octantI<8; octantI++)
1026 // Use sampleOctant first
1027 octant = sampleOctant;
1029 else if (octantI == sampleOctant)
1038 if (subNodes()[octant])
1043 const treeNode<Type>* subNodePtr = getNodePtr(octant);
1045 if (subNodePtr->bb().overlaps(box))
1048 changed |= subNodePtr->findBox(shapes, box, elements);
1053 // Leaf: let leaf::find handle this
1054 const treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
1056 if (subLeafPtr->bb().overlaps(box))
1059 changed |= subLeafPtr->findBox(shapes, box, elements);
1069 // look from <start> in current cube (given by this->bb()).
1070 template <class Type>
1071 const Foam::treeLeaf<Type>* Foam::treeNode<Type>::findLeafLine
1081 space(Pout, 2*level);
1082 Pout<< "findLeafLine : bb:" << this->bb() << " mid:" << midpoint()
1083 << " start:" << start << endl;
1086 scalar typDim = this->bb().avgDim();
1088 const vector direction = end - start;
1090 // Loop on current level until start has been updated to be outside
1091 // of this->bb(). Note that max only four subcubes can be crossed so this is
1092 // check on whether there are any truncation error problems.
1098 if (!this->bb().contains(direction, start))
1102 space(Pout, 2*level);
1103 Pout<< "findLeafLine : Start not inside bb " << this->bb()
1104 << ". Returning with start:" << start << " subLeaf:"
1110 // Check if start and <end> equal
1111 if ((mag(start - end)/typDim) < SMALL)
1115 space(Pout, 2*level);
1116 Pout<< "findLeafLine : start equals end"
1117 << ". Returning with start:" << start << " subLeaf:"
1125 // Too many iterations. Is hanging. Handle outside of loop.
1129 bool onEdge = false;
1130 label octant = this->bb().subOctant
1132 midpoint(), direction, start, onEdge
1135 // Try finding non-empty treeleaf in octant
1136 const treeLeaf<Type>* leafPtr = findLeafLineOctant
1148 // Found treeLeaf -> return
1151 space(Pout, 2*level);
1152 Pout<< "findLeafLine : Found treeLeaf"
1153 << ". Returning with start:" << start << " subLeaf:"
1154 << long(leafPtr) << endl;
1163 // Check if is hanging. Max 4 octants can be crossed by a straight line
1166 "treeNode<Type>::findLeafLine"
1167 "(const label, octree<Type>&, point&,"
1169 ) << "Did not leave bb " << this->bb()
1170 << " after " << iter
1171 << " iterations of updating starting point."
1172 << "start:" << start << " end:" << end
1173 << abort(FatalError);
1179 template <class Type>
1180 void Foam::treeNode<Type>::findLeaves
1182 List<treeLeaf<Type>*>& leafArray,
1186 // Go into all sub boxes
1187 for (label octant=0; octant<8; octant++)
1189 if (subNodes()[octant])
1193 // Node: recurse into subnodes
1194 const treeNode<Type>* subNodePtr = getNodePtr(octant);
1195 subNodePtr->findLeaves(leafArray, leafIndex);
1200 treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
1201 leafArray[leafIndex++] = subLeafPtr;
1208 template <class Type>
1209 void Foam::treeNode<Type>::findLeaves
1211 List<const treeLeaf<Type>*>& leafArray,
1215 // Go into all sub boxes
1216 for (label octant=0; octant<8; octant++)
1218 if (subNodes()[octant])
1222 // Node: recurse into subnodes
1223 const treeNode<Type>* subNodePtr = getNodePtr(octant);
1224 subNodePtr->findLeaves(leafArray, leafIndex);
1229 treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
1230 leafArray[leafIndex++] = subLeafPtr;
1237 template <class Type>
1238 void Foam::treeNode<Type>::printNode
1246 os << "node:" << this->bb() << endl;
1248 for (label octant=0; octant<8; octant++)
1250 label type = getVolType(octant);
1252 string typeString = octree<Type>::volType(type);
1254 if (!subNodes_[octant])
1257 os << octant << ":" << typeString << " : null" << endl;
1259 else if (isNode(octant))
1262 os << octant << ":" << typeString << " : node" << endl;
1263 getNodePtr(octant)->printNode(os, level+1);
1268 os << octant << ":" << typeString << " : leaf" << endl;
1270 treeLeaf<Type>* leafPtr = getLeafPtr(octant);
1271 leafPtr->printLeaf(os, level+1);
1277 template <class Type>
1278 void Foam::treeNode<Type>::writeOBJ
1285 point midPoint(this->bb().midpoint());
1287 label midVertNo = vertNo;
1288 os << "v " << midPoint.x() << " " << midPoint.y() << " "
1289 << midPoint.z() << endl;
1292 for (label octant=0; octant<8; octant++)
1294 if (subNodes_[octant])
1298 treeNode<Type>* nodePtr = getNodePtr(octant);
1300 point subMidPoint(nodePtr->bb().midpoint());
1301 os << "v " << subMidPoint.x() << " " << subMidPoint.y() << " "
1302 << subMidPoint.z() << endl;
1303 os << "l " << midVertNo + 1<< " " << vertNo + 1 << endl;
1306 nodePtr->writeOBJ(os, level+1, vertNo);
1310 treeLeaf<Type>* leafPtr = getLeafPtr(octant);
1312 point subMidPoint(leafPtr->bb().midpoint());
1313 os << "v " << subMidPoint.x() << " " << subMidPoint.y() << " "
1314 << subMidPoint.z() << endl;
1315 os << "l " << midVertNo + 1<< " " << vertNo + 1 << endl;
1318 //leafPtr->writeOBJ(os, level+1, vertNo);
1325 // * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
1327 template <class Type>
1328 Foam::Istream& Foam::operator>>(Istream& is, treeNode<Type>& oc)
1330 for (label octant = 0; octant < 8; octant++)
1332 oc.subNodes_[octant] = NULL;
1339 // Read number of entries folllowing
1342 is.readBegin("treeNode");
1343 for (label octant = 0; octant < nPtrs; octant++)
1348 if (index >= treeNode<Type>::leafOffset)
1350 // Leaf recognized by out of range index
1351 treeLeaf<Type>* leafPtr = new treeLeaf<Type>(is);
1352 oc.setLeafPtr(index - treeNode<Type>::leafOffset, leafPtr);
1356 oc.setNodePtr(index, new treeNode<Type>(is));
1360 // Read end of treeNode list
1361 is.readEnd("treeNode");
1363 // Check state of Istream
1364 is.check("Istream& operator>>(Istream&, treeNode&)");
1370 template <class Type>
1371 Foam::Ostream& Foam::operator<<(Ostream& os, const treeNode<Type>& tn)
1373 // Count valid subnodes:
1375 // - treeLeafs with non-zero cell list.
1377 for (label octant = 0; octant < 8; octant++)
1379 if (tn.subNodes_[octant])
1381 if (tn.isNode(octant) || tn.getLeafPtr(octant)->indices().size())
1389 // output subnodes as list of length nPtrs
1390 os << token::SPACE << tn.bb() << token::SPACE << nPtrs
1391 << token::SPACE << token::BEGIN_LIST;
1393 for (label octant = 0; octant < 8; octant++)
1395 if (tn.subNodes_[octant])
1397 if (tn.isNode(octant))
1399 const treeNode<Type>* subNodePtr = tn.getNodePtr(octant);
1401 // Node: output index, value
1402 os << token::SPACE << octant << token::SPACE << *subNodePtr
1405 else if (tn.getLeafPtr(octant)->indices().size())
1407 // treeLeaf: mark by putting index invalid
1408 const treeLeaf<Type>* subLeafPtr = tn.getLeafPtr(octant);
1410 os << token::SPACE << octant + treeNode<Type>::leafOffset
1411 << token::SPACE << *subLeafPtr
1417 os << token::SPACE << token::END_LIST;
1423 // ************************************************************************* //