1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd.
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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 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, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 \*---------------------------------------------------------------------------*/
32 #include "treeBoundBox.H"
34 #include "linePointRef.H"
36 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
41 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
44 const label treeNode<Type>::leafOffset = 100;
47 const labelList treeNode<Type>::dummy(1);
50 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
53 void treeNode<Type>::setAsNode(const label octant)
55 subNodeTypes_ |= (0x1 << octant);
60 void treeNode<Type>::setAsLeaf(const label octant)
62 subNodeTypes_ &= ~(0x1 << octant);
66 // Set pointer to sub node
68 void treeNode<Type>::setNodePtr(const label octant, treeElem<Type>* treeNodePtr)
71 subNodes_[octant] = treeNodePtr;
75 // Set pointer to sub leaf
77 void treeNode<Type>::setLeafPtr(const label octant, treeElem<Type>* treeLeafPtr)
80 subNodes_[octant] = treeLeafPtr;
85 void treeNode<Type>::setVolType(const label octant, const label type)
87 if ((type < 0) || (type > 3))
89 FatalErrorIn("treeNode<Type>::setVolType(const label, const label)")
90 << "Type " << type << " not within range 0..3" << endl;
93 // Clear out two bits at position 2*octant
94 volType_ &= ~(0x3 << 2*octant);
96 // Add the two bits of type
97 volType_ |= (type << 2*octant);
101 template <class Type>
102 void treeNode<Type>::space(Ostream& os, const label n)
104 for(label i=0; i<n; i++)
111 // look in single octant starting from <start>
112 template <class Type>
113 const treeLeaf<Type>* treeNode<Type>::findLeafLineOctant
118 const vector& direction,
123 static const char* functionName =
124 "treeNode<Type>::findLeafLineOctant"
125 "(const int, const Type&, const label, const vector&,"
126 " point&, const point&)";
130 space(Pout, 2*level);
131 Pout<< "findLeafLineOctant : bb:" << this->bb()
132 << " start:" << start
135 << " Searching octant:" << octant
139 if (subNodes()[octant])
143 // Node: recurse into subnodes
144 const treeNode<Type>* subNodePtr = getNodePtr(octant);
146 if (subNodePtr->bb().contains(direction, start))
148 // Search on lower level
149 const treeLeaf<Type>* subLeafPtr =
150 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(mid(), 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 treeNode<Type>::treeNode(const treeBoundBox& bb)
304 for(label octant=0; octant<8; octant++)
306 subNodes_[octant] = NULL;
307 setVolType(octant, octree<Type>::UNKNOWN);
312 // Construct from Istream
313 template <class Type>
314 treeNode<Type>::treeNode
323 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
325 template <class Type>
326 treeNode<Type>::~treeNode()
328 for(int octant=0; octant<8; octant++)
330 if (subNodes()[octant])
334 delete getNodePtr(octant);
338 delete getLeafPtr(octant);
345 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
347 // Distributes cells to subLeaves
348 template <class Type>
349 void treeNode<Type>::distribute
354 const labelList& indices
360 Pout<< "treeNode::distributing " << indices.size() << endl;
363 // Create subLeaves if nessecary
364 for(label octant=0; octant<8; octant++)
366 if (subNodes()[octant])
368 printNode(Pout, level);
371 "treeNode<Type>::distribute(const label, octree<Type>&, "
372 "const Type&, const labelList&)"
373 ) << "subNode already available at octant:" << octant
374 << abort(FatalError);
378 treeLeaf<Type>* subLeafPtr =
381 this->bb().subBbox(mid(), octant),
385 top.setLeaves(top.nLeaves() + 1);
386 setLeafPtr(octant, subLeafPtr);
391 // add cells to correct sub leaf
394 const label shapei = indices[i];
396 for(label octant=0; octant<8; octant++)
398 treeLeaf<Type>* leafPtr = getLeafPtr(octant);
400 if (shapes.overlaps(shapei, leafPtr->bb()))
405 Pout<< "inserting " << shapei;
406 shapes.write(Pout, shapei);
407 Pout<< " into " << leafPtr->bb() << endl;
409 leafPtr->insert(shapei);
410 top.setEntries(top.nEntries() + 1);
415 // Trim size of subLeaves
416 for(label octant=0; octant<8; octant++)
418 treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
420 if (subLeafPtr->size() == 0)
422 // Contains no data. Delete.
423 setLeafPtr(octant, NULL);
425 top.setLeaves(top.nLeaves() - 1);
429 // Trim to actual size.
437 Pout<< "end of treeNode::distribute" << endl;
442 // Descends to refineLevel and checks the subLeaves for redistribution
443 template <class Type>
444 void treeNode<Type>::redistribute
449 const label refineLevel
455 Pout<< "treeNode::redistribute with level:" << level
456 << " refineLevel:" << refineLevel << endl;
459 // Descend to correct level
460 if (level < refineLevel)
462 for(label octant=0; octant<8; octant++)
464 if (subNodes()[octant])
468 getNodePtr(octant)->redistribute
481 // Reached correct (should also be deepest) level of treeNode
485 Pout<< "treeNode::redistribute : now at correct level" << endl;
488 // handle redistribution of sub leaves
489 for(label octant=0; octant<8; octant++)
491 if (subNodes()[octant])
497 "treeNode<Type>::redistribute(const int, octree& top,"
498 "const int, const treeBoundBox&)"
499 ) << "found treeNode instead of treeLeaf" << endl
500 << abort(FatalError);
504 treeLeaf<Type>* leafPtr = getLeafPtr(octant);
506 treeLeaf<Type>* newSubPtr = leafPtr->redistribute
513 if (newSubPtr && (newSubPtr != leafPtr))
515 // redistribute has created nodePtr
516 // so delete no longer used subPtr and update info
520 << top.nEntries() - leafPtr->size()
521 << " entries" << endl;
523 top.setEntries(top.nEntries() - leafPtr->size());
527 top.setLeaves(top.nLeaves() - 1);
529 setNodePtr(octant, newSubPtr);
537 Pout<< "end of treeNode::redistribute for correct level" << endl;
544 Pout<< "return from treeNode::redistribute with bb:" << this->bb()
551 template <class Type>
552 label treeNode<Type>::setSubNodeType
562 Pout<< "treeNode::setSubNodeType with level:" << level
563 << " bb:" << this->bb() << endl;
568 for(label octant=0; octant<8; octant++)
572 if (subNodes()[octant])
576 subType = getNodePtr(octant)->setSubNodeType
585 subType = getLeafPtr(octant)->setSubNodeType
595 // No data in this one. Set type for octant acc. to its bounding
597 const treeBoundBox subBb = this->bb().subBbox(mid(), octant);
599 subType = shapes.getSampleType(top, subBb.mid());
605 Pout<< "treeNode::setSubNodeType : setting octant with bb:"
606 << this->bb().subBbox(mid(), octant)
607 << " to type:" << octree<Type>::volType(subType) << endl;
609 setVolType(octant, subType);
611 // Combine sub node types into type for treeNode. Result is 'mixed' if
612 // types differ among subnodes.
617 else if (subType != myType)
619 myType = octree<Type>::MIXED;
626 Pout<< "return from treeNode::setSubNodeType with type:"
627 << octree<Type>::volType(myType)
628 << " bb:" << this->bb() << endl;
636 template <class Type>
637 label treeNode<Type>::getSampleType
640 const octree<Type>& top,
648 Pout<< "treeNode::getSampleType with level:" << level
649 << " bb:" << this->bb() << " sample:" << sample << endl;
652 // Determine octant of bb. If on edge just use whichever octant.
655 label octant = this->bb().subOctant(mid(), sample, onEdge);
657 label type = getVolType(octant);
659 if (type == octree<Type>::MIXED)
661 // At this level multiple sub types. Recurse to resolve.
662 if (subNodes()[octant])
666 // Node: recurse into subnodes
667 type = getNodePtr(octant)->getSampleType
678 type = getLeafPtr(octant)->getSampleType
689 // Problem: empty subnode should have a type
692 "treeNode<Type>::getSampleType"
693 "(const label, octree<Type>&, const Type&, const point&)"
694 ) << "Empty node bb:" << this->bb().subBbox(mid(), octant)
695 << " has non-mixed type:"
696 << octree<Type>::volType(type)
697 << abort(FatalError);
701 if (type == octree<Type>::MIXED)
705 "treeNode<Type>::getSampleType"
706 "(const label, octree<Type>&, const Type&, const point&)"
707 ) << "Type is MIXED when searching for " << sample
708 << " at level " << this->bb() << endl
709 << "This probably is because the octree has not been constructed"
710 << " with search facility." << exit(FatalError);
716 Pout<< "return from treeNode::getSampleType with type:"
717 << octree<Type>::volType(type)
718 << " bb:" << this->bb()
719 << " sample:" << sample << endl;
725 template <class Type>
726 label treeNode<Type>::find
732 // Find octant of sample. Don't care if on edge (since any item on edge
733 // will have been inserted in both subcubes)
736 label octant = this->bb().subOctant(mid(), sample, onEdge);
738 if (subNodes()[octant])
742 // Node: recurse into subnodes
743 return getNodePtr(octant)->find
751 // Leaf: let leaf::find handle this
752 return getLeafPtr(octant)->find(shapes, sample);
759 template <class Type>
760 bool treeNode<Type>::findTightest
764 treeBoundBox& tightest
767 bool changed = false;
769 // Get best guess for starting octant
772 label sampleOctant = this->bb().subOctant(mid(), sample, onEdge);
774 // Go into all suboctants (one containing sample first) and update tightest.
775 // Order of visiting is if e.g. sampleOctant = 5:
777 for(label octanti=0; octanti<8; octanti++)
782 // Use sampleOctant first
783 octant = sampleOctant;
785 else if (octanti == sampleOctant)
794 if (subNodes()[octant])
798 // Node: recurse into subnodes
799 const treeNode<Type>* subNodePtr = getNodePtr(octant);
801 if (subNodePtr->bb().intersects(tightest))
803 // there might be a better fit inside this subNode
805 subNodePtr->findTightest
815 // Leaf: let leaf::find handle this
816 const treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
818 if (subLeafPtr->bb().intersects(tightest))
820 // there might be a better fit inside this subLeaf
822 subLeafPtr->findTightest
837 template <class Type>
838 bool treeNode<Type>::findNearest
842 treeBoundBox& tightest,
847 bool changed = false;
852 Pout<< "In findNearest with sample:" << sample << " cube:"
853 << this->bb() << " tightest:" << tightest << endl;
858 label sampleOctant = this->bb().subOctant(mid(), sample, onEdge);
860 // Go into all suboctants (one containing sample first) and update tightest.
861 // Order of visiting is if e.g. sampleOctant = 5:
863 for(label octanti=0; octanti<8; octanti++)
868 // Use sampleOctant first
869 octant = sampleOctant;
871 else if (octanti == sampleOctant)
880 if (subNodes()[octant])
885 const treeNode<Type>* subNodePtr = getNodePtr(octant);
887 if (subNodePtr->bb().intersects(tightest))
889 // there might be a better fit inside this subNode
891 subNodePtr->findNearest
903 // Leaf: let leaf::find handle this
904 const treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
906 if (subLeafPtr->bb().intersects(tightest))
908 // there might be a better fit inside this subNode
910 subLeafPtr->findNearest
925 Pout<< "Exiting findNearest for sample:" << sample << " cube:"
926 << this->bb() << " tightesti:" << tightesti << endl;
933 template <class Type>
934 bool treeNode<Type>::findNearest
937 const linePointRef& ln,
938 treeBoundBox& tightest,
940 point& linePoint, // nearest point on line
941 point& shapePoint // nearest point on shape
944 bool changed = false;
948 // Estimate for where best to start searching
949 label sampleOctant = this->bb().subOctant(mid(), ln.centre(), onEdge);
951 // Go into all suboctants (one containing sample first) and update tightest.
952 // Order of visiting is if e.g. sampleOctant = 5:
954 for(label octanti=0; octanti<8; octanti++)
959 // Use sampleOctant first
960 octant = sampleOctant;
962 else if (octanti == sampleOctant)
971 if (subNodes()[octant])
976 const treeNode<Type>* subNodePtr = getNodePtr(octant);
978 if (subNodePtr->bb().intersects(tightest))
980 // there might be a better fit inside this subNode
982 subNodePtr->findNearest
995 // Leaf: let leaf::find handle this
996 const treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
998 if (subLeafPtr->bb().intersects(tightest))
1000 // there might be a better fit inside this subNode
1002 subLeafPtr->findNearest
1020 template <class Type>
1021 bool treeNode<Type>::findBox
1024 const boundBox& box,
1025 labelHashSet& elements
1028 bool changed = false;
1030 bool onEdge = false;
1032 // Estimate for where best to start searching
1033 point boxMid(0.5*(box.min() + box.max()));
1034 label sampleOctant = this->bb().subOctant(mid(), boxMid, onEdge);
1036 // Go into all suboctants (one containing sample first) and update tightest.
1037 // Order of visiting is if e.g. sampleOctant = 5:
1039 for(label octanti=0; octanti<8; octanti++)
1044 // Use sampleOctant first
1045 octant = sampleOctant;
1047 else if (octanti == sampleOctant)
1056 if (subNodes()[octant])
1061 const treeNode<Type>* subNodePtr = getNodePtr(octant);
1063 if (subNodePtr->bb().intersects(box))
1066 changed |= subNodePtr->findBox(shapes, box, elements);
1071 // Leaf: let leaf::find handle this
1072 const treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
1074 if (subLeafPtr->bb().intersects(box))
1077 changed |= subLeafPtr->findBox(shapes, box, elements);
1087 // look from <start> in current cube (given by this->bb()).
1088 template <class Type>
1089 const treeLeaf<Type>* treeNode<Type>::findLeafLine
1099 space(Pout, 2*level);
1100 Pout<< "findLeafLine : bb:" << this->bb() << " mid:" << mid()
1101 << " start:" << start << endl;
1104 scalar typDim = this->bb().avgDim();
1106 const vector direction = end - start;
1108 // Loop on current level until start has been updated to be outside
1109 // of this->bb(). Note that max only four subcubes can be crossed so this is
1110 // check on whether there are any truncation error problems.
1116 if (!this->bb().contains(direction, start))
1120 space(Pout, 2*level);
1121 Pout<< "findLeafLine : Start not inside bb " << this->bb()
1122 << ". Returning with start:" << start << " subLeaf:"
1128 // Check if start and <end> equal
1129 if ((mag(start - end)/typDim) < SMALL)
1133 space(Pout, 2*level);
1134 Pout<< "findLeafLine : start equals end"
1135 << ". Returning with start:" << start << " subLeaf:"
1143 // Too many iterations. Is hanging. Handle outside of loop.
1147 bool onEdge = false;
1148 label octant = this->bb().subOctant(mid(), direction, start, onEdge);
1150 // Try finding non-empty treeleaf in octant
1151 const treeLeaf<Type>* leafPtr =
1164 // Found treeLeaf -> return
1167 space(Pout, 2*level);
1168 Pout<< "findLeafLine : Found treeLeaf"
1169 << ". Returning with start:" << start << " subLeaf:"
1170 << long(leafPtr) << endl;
1179 // Check if is hanging. Max 4 octants can be crossed by a straight line
1182 "treeNode<Type>::findLeafLine"
1183 "(const label, octree<Type>&, point&,"
1185 ) << "Did not leave bb " << this->bb()
1186 << " after " << iter
1187 << " iterations of updating starting point."
1188 << "start:" << start << " end:" << end
1189 << abort(FatalError);
1195 template <class Type>
1196 void treeNode<Type>::findLeaves
1198 List<treeLeaf<Type>*>& leafArray,
1202 // Go into all sub boxes
1203 for(label octant=0; octant<8; octant++)
1205 if (subNodes()[octant])
1209 // Node: recurse into subnodes
1210 const treeNode<Type>* subNodePtr = getNodePtr(octant);
1211 subNodePtr->findLeaves(leafArray, leafIndex);
1216 treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
1217 leafArray[leafIndex++] = subLeafPtr;
1224 template <class Type>
1225 void treeNode<Type>::findLeaves
1227 List<const treeLeaf<Type>*>& leafArray,
1231 // Go into all sub boxes
1232 for(label octant=0; octant<8; octant++)
1234 if (subNodes()[octant])
1238 // Node: recurse into subnodes
1239 const treeNode<Type>* subNodePtr = getNodePtr(octant);
1240 subNodePtr->findLeaves(leafArray, leafIndex);
1245 treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
1246 leafArray[leafIndex++] = subLeafPtr;
1253 template <class Type>
1254 void treeNode<Type>::printNode
1262 os << "node:" << this->bb() << endl;
1264 for(label octant=0; octant<8; octant++)
1266 label type = getVolType(octant);
1268 string typeString = octree<Type>::volType(type);
1270 if (!subNodes_[octant])
1273 os << octant << ":" << typeString << " : null" << endl;
1275 else if (isNode(octant))
1278 os << octant << ":" << typeString << " : node" << endl;
1279 getNodePtr(octant)->printNode(os, level+1);
1284 os << octant << ":" << typeString << " : leaf" << endl;
1286 treeLeaf<Type>* leafPtr = getLeafPtr(octant);
1287 leafPtr->printLeaf(os, level+1);
1293 template <class Type>
1294 void treeNode<Type>::writeOBJ
1301 point midPoint(this->bb().mid());
1303 label midVertNo = vertNo;
1304 os << "v " << midPoint.x() << " " << midPoint.y() << " "
1305 << midPoint.z() << endl;
1308 for(label octant=0; octant<8; octant++)
1310 if (subNodes_[octant])
1314 treeNode<Type>* nodePtr = getNodePtr(octant);
1316 point subMidPoint(nodePtr->bb().mid());
1317 os << "v " << subMidPoint.x() << " " << subMidPoint.y() << " "
1318 << subMidPoint.z() << endl;
1319 os << "l " << midVertNo + 1<< " " << vertNo + 1 << endl;
1322 nodePtr->writeOBJ(os, level+1, vertNo);
1326 treeLeaf<Type>* leafPtr = getLeafPtr(octant);
1328 point subMidPoint(leafPtr->bb().mid());
1329 os << "v " << subMidPoint.x() << " " << subMidPoint.y() << " "
1330 << subMidPoint.z() << endl;
1331 os << "l " << midVertNo + 1<< " " << vertNo + 1 << endl;
1334 //leafPtr->writeOBJ(os, level+1, vertNo);
1341 // * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
1343 template <class Type>
1344 Istream& operator>>(Istream& is, treeNode<Type>& oc)
1346 for(label octant = 0; octant < 8; octant++)
1348 oc.subNodes_[octant] = NULL;
1355 // Read number of entries folllowing
1358 is.readBegin("treeNode");
1359 for (label octant = 0; octant < nPtrs; octant++)
1364 if (index >= treeNode<Type>::leafOffset)
1366 // Leaf recognized by out of range index
1367 treeLeaf<Type>* leafPtr = new treeLeaf<Type>(is);
1368 oc.setLeafPtr(index - treeNode<Type>::leafOffset, leafPtr);
1372 oc.setNodePtr(index, new treeNode<Type>(is));
1376 // Read end of treeNode list
1377 is.readEnd("treeNode");
1379 // Check state of Istream
1380 is.check("Istream& operator>>(Istream&, treeNode&)");
1386 template <class Type>
1387 Ostream& operator<<(Ostream& os, const treeNode<Type>& tn)
1389 // Count valid subnodes:
1391 // - treeLeafs with non-zero cell list.
1393 for (label octant = 0; octant < 8; octant++)
1395 if (tn.subNodes_[octant])
1400 || (tn.getLeafPtr(octant)->indices().size() != 0)
1409 // output subnodes as list of length nPtrs
1410 os << token::SPACE << tn.bb() << token::SPACE << nPtrs
1411 << token::SPACE << token::BEGIN_LIST;
1413 for (label octant = 0; octant < 8; octant++)
1415 if (tn.subNodes_[octant])
1417 if (tn.isNode(octant))
1419 const treeNode<Type>* subNodePtr = tn.getNodePtr(octant);
1421 // Node: output index, value
1422 os << token::SPACE << octant << token::SPACE << *subNodePtr
1425 else if (tn.getLeafPtr(octant)->indices().size() != 0)
1427 // treeLeaf: mark by putting index invalid
1428 const treeLeaf<Type>* subLeafPtr = tn.getLeafPtr(octant);
1430 os << token::SPACE << octant + treeNode<Type>::leafOffset
1431 << token::SPACE << *subLeafPtr
1437 os << token::SPACE << token::END_LIST;
1443 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1445 } // End namespace Foam
1447 // ************************************************************************* //