1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | cfMesh: A library for mesh generation
5 \\ / A nd | Author: Franjo Juretic (franjo.juretic@c-fields.com)
6 \\/ M anipulation | Copyright (C) Creative Fields, Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of cfMesh.
11 cfMesh 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 3 of the License, or (at your
14 option) any later version.
16 cfMesh 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 cfMesh. If not, see <http://www.gnu.org/licenses/>.
26 \*---------------------------------------------------------------------------*/
28 #include "meshOctreeAddressing.H"
29 #include "helperFunctions.H"
30 #include "VRWGraphSMPModifier.H"
31 #include "demandDrivenData.H"
32 #include "meshOctree.H"
33 #include "labelLongList.H"
46 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
51 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
56 const fileName& fName,
57 const meshOctree& octree,
58 const List<direction>& boxTypes,
65 file << "# vtk DataFile Version 3.0\n";
66 file << "vtk output\n";
68 file << "DATASET UNSTRUCTURED_GRID\n";
71 forAll(boxTypes, leafI)
72 if( boxTypes[leafI] & bType )
76 file << "POINTS " << 8*nBoxes << " float\n";
77 forAll(boxTypes, leafI)
79 if( boxTypes[leafI] & bType )
81 FixedList<point, 8> vertices;
82 octree.returnLeaf(leafI).vertices(octree.rootBox(), vertices);
86 const point& p = vertices[vI];
88 file << p.x() << ' ' << p.y() << ' ' << p.z() << nl;
94 file << "\nCELLS " << nBoxes
95 << " " << 9 * nBoxes << nl;
98 forAll(boxTypes, leafI)
100 if( boxTypes[leafI] & bType )
102 const label start = 8 * nBoxes;
103 file << 8 << " " << start << " " << start+1
104 << " " << start+3 << " " << start+2
105 << " " << start+4 << " " << start+5
106 << " " << start+7 << " " << start+6 << nl;
115 file << "CELL_TYPES " << nBoxes << nl;
116 for(label i=0;i<nBoxes;++i)
123 void meshOctreeAddressing::createOctreePoints() const
125 const VRWGraph& nodeLabels = this->nodeLabels();
126 const boundBox& rootBox = octree_.rootBox();
128 octreePointsPtr_ = new pointField(nNodes_);
129 pointField& octreePoints = *octreePointsPtr_;
131 const label nLeaves = nodeLabels.size();
133 # pragma omp parallel for schedule(guided, 100)
135 for(label cubeI=0;cubeI<nLeaves;++cubeI)
137 if( nodeLabels.sizeOfRow(cubeI) == 0 )
140 FixedList<point, 8> vertices;
141 const meshOctreeCubeBasic& oc = octree_.returnLeaf(cubeI);
142 oc.vertices(rootBox, vertices);
144 forAllRow(nodeLabels, cubeI, nI)
146 const label nodeI = nodeLabels(cubeI, nI);
148 octreePoints[nodeI] = vertices[nI];
153 void meshOctreeAddressing::createNodeLabels() const
155 const List<direction>& boxType = this->boxType();
157 nodeLabelsPtr_ = new VRWGraph(octree_.numberOfLeaves());
158 VRWGraph& nodeLabels = *nodeLabelsPtr_;
160 //- allocate storage for node labels
161 forAll(nodeLabels, leafI)
165 nodeLabels.setRowSize(leafI, 8);
167 forAllRow(nodeLabels, leafI, i)
168 nodeLabels(leafI, i) = -1;
172 //- start creating node labels
174 DynList<label> numLocalNodes;
176 # pragma omp parallel
180 const label nThreads = omp_get_num_threads();
181 const label threadI = omp_get_thread_num();
183 const label nThreads = 1;
184 const label threadI = 0;
190 numLocalNodes.setSize(nThreads);
196 //- count the number of nodes local to each process
197 label& nLocalNodes = numLocalNodes[threadI];
201 # pragma omp for schedule(static, 100)
203 forAll(nodeLabels, leafI)
205 forAllRow(nodeLabels, leafI, nI)
207 if( nodeLabels(leafI, nI) != -1 )
210 FixedList<label, 8> pLeaves;
211 octree_.findLeavesForCubeVertex(leafI, nI, pLeaves);
213 FixedList<bool, 8> validLeaf(true);
214 label minLeaf(leafI);
217 if( pLeaves[plI] > -1 )
219 for(label i=plI+1;i<8;++i)
220 if( pLeaves[plI] == pLeaves[i] )
222 validLeaf[plI] = false;
223 validLeaf[i] = false;
226 if( !boxType[pLeaves[plI]] )
228 validLeaf[plI] = false;
233 minLeaf = Foam::min(minLeaf, pLeaves[plI]);
237 validLeaf[plI] = false;
241 if( (minLeaf == leafI) && validLeaf[7-nI] )
246 //- set node labels to -2 not to repeat searches
247 nodeLabels(pLeaves[plI], (7-plI)) = -2;
255 //- set start node for each process
261 for(label i=0;i<threadI;++i)
262 startNode += numLocalNodes[i];
264 //- start creating node labels
266 # pragma omp for schedule(static, 100)
268 forAll(nodeLabels, leafI)
270 forAllRow(nodeLabels, leafI, nI)
272 if( nodeLabels(leafI, nI) >= 0 )
275 FixedList<label, 8> pLeaves;
276 octree_.findLeavesForCubeVertex(leafI, nI, pLeaves);
278 FixedList<bool, 8> validLeaf(true);
279 label minLeaf(leafI);
282 if( pLeaves[plI] > -1 )
284 for(label i=plI+1;i<8;++i)
285 if( pLeaves[plI] == pLeaves[i] )
287 validLeaf[plI] = false;
288 validLeaf[i] = false;
291 if( !boxType[pLeaves[plI]] )
293 validLeaf[plI] = false;
298 minLeaf = Foam::min(minLeaf, pLeaves[plI]);
302 validLeaf[plI] = false;
306 if( (minLeaf == leafI) && validLeaf[7-nI] )
311 //- store the vertex at the corresponding
312 //- location in the cube
313 nodeLabels(pLeaves[plI], (7-plI)) = startNode;
316 //- store vertex label
322 //- set the number of nodes
324 # pragma omp critical
327 nNodes_ = Foam::max(nNodes_, startNode);
332 List<direction> badLeaves(nodeLabels.size(), direction(0));
333 forAll(nodeLabels, leafI)
334 forAllRow(nodeLabels, leafI, i)
335 if( nodeLabels(leafI, i) < 0 )
336 badLeaves[leafI] |= 1;
337 writeOctreeToVTK("badLeaves.vtk", octree_, badLeaves, 1);
339 writeOctreeToVTK("meshCells.vtk", octree_, boxType, MESHCELL);
340 writeOctreeToVTK("boundaryCells.vtk", octree_, boxType, BOUNDARY);
342 Info << "Checking for existence of negative node labels" << endl;
343 forAll(nodeLabels, leafI)
345 forAllRow(nodeLabels, leafI, nI)
347 if( nodeLabels(leafI, nI) < 0 )
349 FixedList<label, 8> pLeaves;
350 octree_.findLeavesForCubeVertex(leafI, nI, pLeaves);
352 FixedList<bool, 8> validLeaf(true);
353 label minLeaf(leafI);
356 if( pLeaves[plI] > -1 )
358 for(label i=plI+1;i<8;++i)
359 if( pLeaves[plI] == pLeaves[i] )
361 validLeaf[plI] = false;
362 validLeaf[i] = false;
365 if( !boxType[pLeaves[plI]] )
367 validLeaf[plI] = false;
372 minLeaf = Foam::min(minLeaf, pLeaves[plI]);
376 validLeaf[plI] = false;
380 Info << "Min leaf " << minLeaf << endl;
381 Info << "Valid leaf " << validLeaf << endl;
382 Info << "pLeaves " << pLeaves << endl;
383 Info << "Node position " << nI << endl;
385 Info << "1.Leaf " << leafI << " node labels "
386 << nodeLabels[leafI] << endl;
390 Info << "Leaf at position " << i << " has node labels "
391 << nodeLabels[pLeaves[i]]
393 << octree_.returnLeaf(pLeaves[i]).level() << endl;
400 void meshOctreeAddressing::createNodeLeaves() const
402 const List<direction>& boxType = this->boxType();
403 const VRWGraph& nodeLabels = this->nodeLabels();
405 //- allocate nodeLeavesPtr_
406 nodeLeavesPtr_ = new FRWGraph<label, 8>(nNodes_);
407 FRWGraph<label, 8>& nodeLeaves = *nodeLeavesPtr_;
409 boolList storedNode(nNodes_, false);
411 # pragma omp parallel for schedule(dynamic, 100)
413 forAll(nodeLabels, leafI)
415 forAllRow(nodeLabels, leafI, nI)
417 const label nodeI = nodeLabels(leafI, nI);
419 if( storedNode[nodeI] )
422 storedNode[nodeI] = true;
424 FixedList<label, 8> pLeaves;
425 octree_.findLeavesForCubeVertex(leafI, nI, pLeaves);
429 if( pLeaves[plI] < 0 )
432 if( !boxType[pLeaves[plI]] )
436 nodeLeaves.setRow(nodeI, pLeaves);
441 void meshOctreeAddressing::findUsedBoxes() const
443 boxTypePtr_ = new List<direction>(octree_.numberOfLeaves(), NONE);
444 List<direction>& boxType = *boxTypePtr_;
447 # pragma omp parallel for schedule(dynamic, 40)
449 forAll(boxType, leafI)
451 const meshOctreeCubeBasic& leaf = octree_.returnLeaf(leafI);
454 !octree_.hasContainedTriangles(leafI) &&
455 !octree_.hasContainedEdges(leafI) &&
456 (leaf.cubeType() & meshOctreeCubeBasic::INSIDE)
458 boxType[leafI] |= MESHCELL;
461 if( meshDict_.found("nonManifoldMeshing") )
463 const bool nonManifoldMesh
465 readBool(meshDict_.lookup("nonManifoldMeshing"))
468 if( nonManifoldMesh )
471 # pragma omp parallel for schedule(dynamic, 40)
473 forAll(boxType, leafI)
475 const meshOctreeCubeBasic& leaf = octree_.returnLeaf(leafI);
476 if( leaf.cubeType() & meshOctreeCubeBasic::UNKNOWN )
477 boxType[leafI] |= MESHCELL;
484 Info << "Using DATA boxes" << endl;
486 forAll(boxType, leafI)
489 octree_.hasContainedTriangles(leafI) ||
490 octree_.hasContainedEdges(leafI)
492 boxType[leafI] |= MESHCELL;
495 //- do not use boxes intersecting given patches
496 if( meshDict_.found("removeCellsIntersectingPatches") )
498 wordHashSet patchesToRemove;
500 if( meshDict_.isDict("removeCellsIntersectingPatches") )
502 const dictionary& dict =
503 meshDict_.subDict("removeCellsIntersectingPatches");
504 const wordList patchNames = dict.toc();
505 forAll(patchNames, patchI)
506 patchesToRemove.insert(patchNames[patchI]);
510 wordHashSet patchesToRemoveCopy
512 meshDict_.lookup("removeCellsIntersectingPatches")
514 patchesToRemove.transfer(patchesToRemoveCopy);
517 const triSurf& ts = octree_.surface();
518 boolList removeFacets(ts.size(), false);
520 //- remove facets in patches
521 forAllConstIter(HashSet<word>, patchesToRemove, it)
523 const labelList matchedPatches = ts.findPatches(it.key());
524 boolList activePatch(ts.patches().size(), false);
525 forAll(matchedPatches, ptchI)
526 activePatch[matchedPatches[ptchI]] = true;
530 if( activePatch[ts[triI].region()] )
531 removeFacets[triI] = true;
535 //- remove facets in subsets
536 forAllConstIter(HashSet<word>, patchesToRemove, it)
538 const label subsetID = ts.facetSubsetIndex(it.key());
541 labelLongList facets;
542 ts.facetsInSubset(subsetID, facets);
545 removeFacets[facets[i]] = true;
549 //- set BOUNDARY flag to boxes intersected by the given facets
550 DynList<label> containedTriangles;
551 forAll(boxType, leafI)
553 octree_.containedTriangles(leafI, containedTriangles);
555 forAll(containedTriangles, i)
557 if( removeFacets[containedTriangles[i]] )
559 boxType[leafI] = NONE;
565 else if( meshDict_.found("keepCellsIntersectingPatches") )
567 wordHashSet patchesToKeep;
569 if( meshDict_.isDict("keepCellsIntersectingPatches") )
571 const dictionary& dict =
572 meshDict_.subDict("keepCellsIntersectingPatches");
573 const wordList patchNames = dict.toc();
575 forAll(patchNames, patchI)
576 patchesToKeep.insert(patchNames[patchI]);
580 wordHashSet patchesToKeepCopy
582 meshDict_.lookup("keepCellsIntersectingPatches")
584 patchesToKeep.transfer(patchesToKeepCopy);
587 const triSurf& ts = octree_.surface();
588 boolList keepFacets(ts.size(), false);
590 //- keep facets in patches
591 forAllConstIter(HashSet<word>, patchesToKeep, it)
593 const labelList matchedPatches = ts.findPatches(it.key());
594 boolList activePatch(ts.patches().size(), false);
595 forAll(matchedPatches, ptchI)
596 activePatch[matchedPatches[ptchI]] = true;
600 if( activePatch[ts[triI].region()] )
601 keepFacets[triI] = true;
605 //- keep facets in subsets
606 forAllConstIter(wordHashSet, patchesToKeep, it)
608 const label subsetID = ts.facetSubsetIndex(it.key());
612 labelLongList facets;
613 ts.facetsInSubset(subsetID, facets);
616 keepFacets[facets[i]] = true;
620 //- set MESHCELL flag to boxes intersected by the given facets
621 DynList<label> containedTriangles;
622 forAll(boxType, leafI)
624 octree_.containedTriangles(leafI, containedTriangles);
626 forAll(containedTriangles, i)
628 if( keepFacets[containedTriangles[i]] )
630 boxType[leafI] = MESHCELL;
636 //- set BOUNDARY flag to boxes which do not have a MESHCELL flag
637 DynList<label> neighs;
639 # pragma omp parallel for if( boxType.size() > 1000 ) \
640 private(neighs) schedule(dynamic, 20)
642 forAll(boxType, leafI)
644 if( boxType[leafI] & MESHCELL )
646 for(label i=0;i<6;++i)
649 octree_.findNeighboursInDirection(leafI, i, neighs);
653 const label neiLabel = neighs[neiI];
658 if( !(boxType[neiLabel] & MESHCELL) )
659 boxType[neiLabel] = BOUNDARY;
665 if( Pstream::parRun() )
667 //- make sure that all processors have the same information
668 //- about BOUNDARY boxes
669 const labelLongList& globalLeafLabel = this->globalLeafLabel();
670 const VRWGraph& leafAtProcs = this->leafAtProcs();
671 const Map<label>& globalLeafToLocal =
672 this->globalToLocalLeafAddressing();
674 std::map<label, labelLongList> exchangeData;
675 forAll(octree_.neiProcs(), procI)
680 octree_.neiProcs()[procI],
685 forAllConstIter(Map<label>, globalLeafToLocal, iter)
687 const label leafI = iter();
689 if( boxType[leafI] & BOUNDARY )
691 forAllRow(leafAtProcs, leafI, procI)
693 const label neiProc = leafAtProcs(leafI, procI);
695 if( neiProc == Pstream::myProcNo() )
698 exchangeData[neiProc].append(globalLeafLabel[leafI]);
703 labelLongList receivedData;
704 help::exchangeMap(exchangeData, receivedData);
706 forAll(receivedData, i)
707 boxType[globalLeafToLocal[receivedData[i]]] = BOUNDARY;
711 void meshOctreeAddressing::calculateNodeType() const
713 const FRWGraph<label, 8>& nodeLeaves = this->nodeLeaves();
715 nodeTypePtr_ = new List<direction>(nNodes_, NONE);
716 List<direction>& nodeType = *nodeTypePtr_;
719 # pragma omp parallel for schedule(static, 1)
721 forAll(nodeLeaves, nodeI)
723 forAllRow(nodeLeaves, nodeI, nlI)
725 const label leafI = nodeLeaves(nodeI, nlI);
730 const meshOctreeCubeBasic& oc = octree_.returnLeaf(leafI);
733 (oc.cubeType() & meshOctreeCubeBasic::OUTSIDE) ||
734 (oc.cubeType() & meshOctreeCubeBasic::UNKNOWN)
737 nodeType[nodeI] |= OUTERNODE;
741 !octree_.hasContainedTriangles(leafI) &&
742 (oc.cubeType() & meshOctreeCubeBasic::INSIDE)
745 nodeType[nodeI] |= INNERNODE;
752 void meshOctreeAddressing::createOctreeFaces() const
754 octreeFacesPtr_ = new VRWGraph();
755 octreeFacesOwnersPtr_ = new labelLongList();
756 octreeFacesNeighboursPtr_ = new labelLongList();
758 const VRWGraph& nodeLabels = this->nodeLabels();
759 const List<direction>& boxType = this->boxType();
763 labelList rowSizes, chunkSizes;
766 # pragma omp parallel
769 //- faces are created and stored into helper arrays, and each thread
770 //- allocates its own graph for storing faces. The faces are generated
771 //- by dividing the octree leaves into chunks, and distributing these
772 //- chunks over the threads. There are four chunks per each thread to
773 //- improve load balancing. The number of faces generated in each chunk
774 //- is stored and later in used to store the faces into the octree faces
775 //- graph in the correct order
776 VRWGraph helperFaces;
777 labelLongList helperOwner, helperNeighbour;
780 const label nThreads = omp_get_num_threads();
781 const label threadI = omp_get_thread_num();
782 const label nChunks = 4 * omp_get_num_threads();
783 const label chunkSize = boxType.size() / nChunks + 1;
785 const label nThreads(1);
786 const label threadI(0);
787 const label nChunks(1);
788 const label chunkSize = boxType.size();
795 chunkSizes.setSize(nChunks);
805 label chunkI=threadI;
810 const label start = chunkSize * chunkI;
811 const label end = Foam::min(start+chunkSize, boxType.size());
813 const label nBefore = helperFaces.size();
815 for(label leafI=start;leafI<end;++leafI)
817 const meshOctreeCubeBasic& oc = octree_.returnLeaf(leafI);
819 if( boxType[leafI] & MESHCELL )
821 FixedList<label, 12> edgeCentreLabel(-1);
822 for(label i=0;i<12;++i)
823 edgeCentreLabel[i] = findEdgeCentre(leafI, i);
825 for(label fI=0;fI<6;++fI)
827 DynList<label> neighbours;
828 octree_.findNeighboursInDirection
835 if( neighbours.size() != 1 )
838 const label nei = neighbours[0];
840 //- stop if the neighbour is on other processor
841 if( nei == meshOctreeCubeBasic::OTHERPROC )
846 for(label pI=0;pI<4;++pI)
849 meshOctreeCubeCoordinates::faceNodes_[fI][pI];
851 meshOctreeCubeCoordinates::faceEdges_[fI][pI];
853 f.append(nodeLabels(leafI, nI));
855 if( edgeCentreLabel[feI] != -1 )
856 f.append(edgeCentreLabel[feI]);
861 //- face is at the boundary of the octree
862 helperFaces.appendList(f);
863 helperOwner.append(leafI);
864 helperNeighbour.append(-1);
866 else if( boxType[nei] & MESHCELL )
868 //- face is an internal face
871 helperFaces.appendList(f);
872 helperOwner.append(leafI);
873 helperNeighbour.append(nei);
877 octree_.returnLeaf(nei).level() < oc.level()
880 //- append a reversed face
882 for(label j=f.size()-1;j>i;--j)
884 const label add = f[j];
890 helperFaces.appendList(f);
891 helperOwner.append(nei);
892 helperNeighbour.append(leafI);
895 else if( boxType[nei] & BOUNDARY )
897 //- face is at the boundary of the mesh cells
898 helperFaces.appendList(f);
899 helperOwner.append(leafI);
900 helperNeighbour.append(nei);
904 else if( boxType[leafI] & BOUNDARY )
906 for(label fI=0;fI<6;++fI)
908 DynList<label> neighbours;
909 octree_.findNeighboursInDirection
916 if( neighbours.size() != 1 )
918 const label nei = neighbours[0];
922 (boxType[nei] & MESHCELL) &&
923 (octree_.returnLeaf(nei).level() < oc.level())
926 //- add a boundary face
927 const label* fNodes =
928 meshOctreeCubeCoordinates::faceNodes_[fI];
930 for(label i=0;i<4;++i)
932 cf[i] = nodeLabels(leafI, fNodes[i]);
935 helperFaces.appendList(cf.reverseFace());
936 helperOwner.append(nei);
937 helperNeighbour.append(leafI);
943 //- store the size of this chunk
944 chunkSizes[chunkI] = helperFaces.size() - nBefore;
947 //- set the sizes of faces graph
949 # pragma omp critical
951 nFaces += helperFaces.size();
959 rowSizes.setSize(nFaces);
960 octreeFacesPtr_->setSize(nFaces);
961 octreeFacesOwnersPtr_->setSize(nFaces);
962 octreeFacesNeighboursPtr_->setSize(nFaces);
969 //- set the size of face graph rows and copy owners and neighbours
972 label chunkI=threadI;
977 label start(0), localStart(0);
978 for(label i=0;i<chunkI;++i)
979 start += chunkSizes[i];
980 for(label i=threadI;i<chunkI;i+=nThreads)
981 localStart += chunkSizes[i];
983 for(label faceI=0;faceI<chunkSizes[chunkI];++faceI)
985 octreeFacesOwnersPtr_->operator[](start) =
986 helperOwner[localStart];
987 octreeFacesNeighboursPtr_->operator[](start) =
988 helperNeighbour[localStart];
989 rowSizes[start++] = helperFaces.sizeOfRow(localStart++);
996 //- set the size of octree faces
999 VRWGraphSMPModifier(*octreeFacesPtr_).setSizeAndRowSize(rowSizes);
1002 # pragma omp barrier
1005 //- copy the data into octree faces
1008 label chunkI=threadI;
1013 label start(0), localStart(0);
1015 for(label i=0;i<chunkI;++i)
1016 start += chunkSizes[i];
1017 for(label i=threadI;i<chunkI;i+=nThreads)
1018 localStart += chunkSizes[i];
1020 for(label faceI=0;faceI<chunkSizes[chunkI];++faceI)
1022 for(label i=0;i<helperFaces.sizeOfRow(localStart);++i)
1023 octreeFacesPtr_->operator()(start, i) =
1024 helperFaces(localStart, i);
1033 List<vector> sum(octree_.numberOfLeaves(), vector::zero);
1034 for(label faceI=0;faceI<octreeFacesPtr_->size();++faceI)
1036 face f(octreeFacesPtr_->sizeOfRow(faceI));
1038 f[pI] = octreeFacesPtr_->operator()(faceI, pI);
1039 const vector n = f.normal(this->octreePoints());
1041 sum[(*octreeFacesOwnersPtr_)[faceI]] += n;
1042 const label nei = (*octreeFacesNeighboursPtr_)[faceI];
1053 Pstream::parRun() &&
1054 octree_.returnLeaf(lfI).procNo() != Pstream::myProcNo()
1057 if( (boxType[lfI] & MESHCELL) && (mag(sum[lfI]) > SMALL) )
1058 Info << "Leaf " << lfI << " is not closed " << sum[lfI] << endl;
1063 void meshOctreeAddressing::calculateLeafFaces() const
1065 const labelLongList& owner = octreeFaceOwner();
1066 const labelLongList& neighbour = octreeFaceNeighbour();
1068 leafFacesPtr_ = new VRWGraph(octree_.numberOfLeaves());
1069 VRWGraph& leafFaces = *leafFacesPtr_;
1071 labelList nlf(leafFaces.size(), 0);
1075 if( neighbour[fI] < 0 )
1077 ++nlf[neighbour[fI]];
1081 leafFaces.setRowSize(leafI, nlf[leafI]);
1086 leafFaces(owner[fI], nlf[owner[fI]]++) = fI;
1087 if( neighbour[fI] < 0 )
1089 leafFaces(neighbour[fI], nlf[neighbour[fI]]++) = fI;
1093 void meshOctreeAddressing::calculateNodeFaces() const
1095 const VRWGraph& octreeFaces = this->octreeFaces();
1096 nodeFacesPtr_ = new VRWGraph(numberOfNodes());
1097 VRWGraph& nodeFaces = *nodeFacesPtr_;
1099 VRWGraphSMPModifier(nodeFaces).reverseAddressing(octreeFaces);
1100 nodeFaces.setSize(numberOfNodes());
1103 void meshOctreeAddressing::calculateLeafLeaves() const
1105 const labelLongList& owner = octreeFaceOwner();
1106 const labelLongList& neighbour = octreeFaceNeighbour();
1108 leafLeavesPtr_ = new VRWGraph(octree_.numberOfLeaves());
1109 VRWGraph& leafLeaves = *leafLeavesPtr_;
1111 labelList nNei(leafLeaves.size(), 0);
1112 forAll(owner, faceI)
1114 if( owner[faceI] < 0 )
1116 if( neighbour[faceI] < 0 )
1119 ++nNei[owner[faceI]];
1120 ++nNei[neighbour[faceI]];
1124 leafLeaves.setRowSize(leafI, nNei[leafI]);
1128 forAll(owner, faceI)
1130 if( owner[faceI] < 0 )
1132 if( neighbour[faceI] < 0 )
1135 leafLeaves(owner[faceI], nNei[owner[faceI]]++) = neighbour[faceI];
1136 leafLeaves(neighbour[faceI], nNei[neighbour[faceI]]++) = owner[faceI];
1140 void meshOctreeAddressing::createOctreeEdges() const
1142 const VRWGraph& faces = this->octreeFaces();
1144 //- allocate memory for edges, face-edges addressing
1145 //- and node-edges addressing
1146 octreeEdgesPtr_ = new LongList<edge>();
1147 LongList<edge>& edges = *octreeEdgesPtr_;
1148 faceEdgesPtr_ = new VRWGraph(faces.size());
1149 VRWGraph& faceEdges = *faceEdgesPtr_;
1150 nodeEdgesPtr_ = new VRWGraph();
1151 VRWGraph& nodeEdges = *nodeEdgesPtr_;
1152 nodeEdges.setSizeAndColumnWidth(nNodes_, 6);
1154 forAll(faces, faceI)
1156 faceEdges.setRowSize(faceI, faces[faceI].size());
1157 forAllRow(faceEdges, faceI, feI)
1158 faceEdges(faceI, feI) = -1;
1161 forAll(faces, faceI)
1163 const label nEdges = faces.sizeOfRow(faceI);
1165 for(label eI=0;eI<nEdges;++eI)
1170 faces(faceI, (eI+1)%nEdges)
1174 forAllRow(nodeEdges, e.start(), neI)
1176 if( edges[nodeEdges(e.start(), neI)] == e )
1178 eLabel = nodeEdges(e.start(), neI);
1186 faceEdges(faceI, eI) = edges.size();
1187 nodeEdges.append(e.start(), edges.size());
1188 nodeEdges.append(e.end(), edges.size());
1194 faceEdges(faceI, eI) = eLabel;
1200 void meshOctreeAddressing::calculateLeafEdges() const
1202 const VRWGraph& edgeLeaves = this->edgeLeaves();
1204 leafEdgesPtr_ = new VRWGraph();
1205 VRWGraph& leafEdges = *leafEdgesPtr_;
1207 VRWGraphSMPModifier(leafEdges).reverseAddressing(edgeLeaves);
1208 leafEdges.setSize(octree_.numberOfLeaves());
1211 void meshOctreeAddressing::calculateEdgeLeaves() const
1213 const VRWGraph& edgeFaces = this->edgeFaces();
1214 const labelLongList& owner = this->octreeFaceOwner();
1215 const labelLongList& neighbour = this->octreeFaceNeighbour();
1217 edgeLeavesPtr_ = new VRWGraph();
1218 VRWGraph& edgeLeaves = *edgeLeavesPtr_;
1219 edgeLeaves.setSizeAndColumnWidth(edgeFaces.size(), 4);
1221 forAll(edgeFaces, edgeI)
1223 forAllRow(edgeFaces, edgeI, efI)
1225 const label fI = edgeFaces(edgeI, efI);
1226 const label own = owner[fI];
1227 const label nei = neighbour[fI];
1229 edgeLeaves.appendIfNotIn(edgeI, own);
1233 edgeLeaves.appendIfNotIn(edgeI, nei);
1238 void meshOctreeAddressing::calculateEdgeFaces() const
1240 const VRWGraph& faceEdges = this->faceEdges();
1241 edgeFacesPtr_ = new VRWGraph(octreeEdges().size());
1242 VRWGraph& edgeFaces = *edgeFacesPtr_;
1244 VRWGraphSMPModifier(edgeFaces).reverseAddressing(faceEdges);
1245 edgeFaces.setSize(octreeEdges().size());
1248 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1250 } // End namespace Foam
1252 // ************************************************************************* //