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 "meshOctreeInsideOutside.H"
31 #include "labelLongList.H"
37 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
42 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
44 meshOctreeInsideOutside::meshOctreeInsideOutside
49 octreeModifier_(octree),
50 cubeGroup_(octree.numberOfLeaves(), -1),
54 hasOutsideNeighbour_(octree.numberOfLeaves(), false),
55 communicationCubes_(),
68 label nInternal(0), nUnknown(0), nData(0), nOutside(0);
70 const label nLeaves = octree.numberOfLeaves();
71 for(label leafI=0;leafI<nLeaves;++leafI)
73 const meshOctreeCubeBasic& oc = octree.returnLeaf(leafI);
75 if( oc.cubeType() & meshOctreeCube::INSIDE )
79 else if( oc.cubeType() & meshOctreeCube::UNKNOWN )
83 else if( oc.cubeType() & meshOctreeCube::DATA )
87 else if( oc.cubeType() & meshOctreeCube::OUTSIDE )
93 if( octree.neiProcs().size() )
95 reduce(nInternal, sumOp<label>());
96 reduce(nUnknown, sumOp<label>());
97 reduce(nData, sumOp<label>());
98 reduce(nOutside, sumOp<label>());
101 Info << "Number of internal boxes is " << nInternal << endl;
102 Info << "Number of outside boxes is " << nOutside << endl;
103 Info << "Number of data boxes is " << nData << endl;
104 Info << "Number of unknown boxes is " << nUnknown << endl;
107 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
109 meshOctreeInsideOutside::~meshOctreeInsideOutside()
113 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
115 void meshOctreeInsideOutside::initialiseBoxes()
117 const LongList<meshOctreeCube*>& leaves = octreeModifier_.leavesAccess();
120 # pragma omp parallel for if( leaves.size() > 1000 )
122 forAll(leaves, leafI)
124 if( leaves[leafI]->hasContainedElements() )
126 leaves[leafI]->setCubeType(meshOctreeCubeBasic::DATA);
130 leaves[leafI]->setCubeType(meshOctreeCubeBasic::UNKNOWN);
135 void meshOctreeInsideOutside::frontalMarking()
137 communicationCubes_.clear();
138 neighbouringGroups_.clear();
140 labelLongList frontCubes;
141 DynList<label> neighbours;
143 label nGroup(0), nThreads(1);
145 const LongList<meshOctreeCube*>& leaves = octreeModifier_.leavesAccess();
146 const meshOctree& octree = octreeModifier_.octree();
148 boolList commCubes(leaves.size(), false);
151 if( leaves.size() > 1000 )
152 nThreads = 3 * omp_get_num_procs();
154 # pragma omp parallel num_threads(nThreads) \
155 private(frontCubes, neighbours)
158 LongList<std::pair<label, label> > threadCommPairs;
161 const label threadI = omp_get_thread_num();
163 const label threadI(0);
166 const label chunkSize = leaves.size() / nThreads + 1;
168 const label minLeaf = threadI * chunkSize;
170 const label maxLeaf = Foam::min(leaves.size(), minLeaf + chunkSize);
172 for(label leafI=minLeaf;leafI<maxLeaf;++leafI)
174 if( leaves[leafI]->hasContainedElements() )
176 if( cubeGroup_[leafI] != -1 )
181 # pragma omp critical
185 direction cType(meshOctreeCubeBasic::UNKNOWN);
187 frontCubes.append(leafI);
188 cubeGroup_[leafI] = groupI;
190 labelLongList neiDATACubes;
192 while( frontCubes.size() )
194 const label fLabel = frontCubes.removeLastElement();
195 octree.findNeighboursForLeaf(fLabel, neighbours);
197 forAll(neighbours, neiI)
199 const label nei = neighbours[neiI];
200 if( (nei >= minLeaf) && (nei < maxLeaf) )
202 if( cubeGroup_[nei] != -1 )
205 if( leaves[nei]->hasContainedElements() )
207 neiDATACubes.append(nei);
211 frontCubes.append(nei);
212 cubeGroup_[nei] = groupI;
217 cType = meshOctreeCubeBasic::OUTSIDE;
219 else if( nei == meshOctreeCubeBasic::OTHERPROC )
221 commCubes[fLabel] = true;
225 if( leaves[nei]->hasContainedElements() )
227 neiDATACubes.append(nei);
231 threadCommPairs.append
233 std::make_pair(fLabel, nei)
241 # pragma omp critical
244 if( groupI >= boundaryDATACubes_.size() )
245 boundaryDATACubes_.setSize(groupI+1);
247 boundaryDATACubes_.setRow(groupI, neiDATACubes);
248 groupType_[groupI] = cType;
256 //- find group to neighbouring groups addressing
257 List<DynList<label> > localNeiGroups(nGroup);
258 forAll(threadCommPairs, cfI)
260 const std::pair<label, label>& lp = threadCommPairs[cfI];
261 const label groupI = cubeGroup_[lp.first];
262 const label neiGroup = cubeGroup_[lp.second];
264 if( (neiGroup >= nGroup) || (groupI >= nGroup) )
265 FatalError << "neiGroup " << neiGroup
266 << " groupI " << groupI << " are >= than "
267 << "nGroups " << nGroup << abort(FatalError);
271 localNeiGroups[groupI].appendIfNotIn(neiGroup);
272 localNeiGroups[neiGroup].appendIfNotIn(groupI);
277 # pragma omp critical
280 neighbouringGroups_.setSize(nGroup);
282 forAll(localNeiGroups, groupI)
284 const DynList<label>& lGroups = localNeiGroups[groupI];
286 neighbouringGroups_.appendIfNotIn(groupI, groupI);
290 neighbouringGroups_.append(groupI, lGroups[i]);
296 //- create cubesInGroup_ addressing
297 labelList nCubesInGroup(nGroup, 0);
298 forAll(cubeGroup_, leafI)
300 if( cubeGroup_[leafI] < 0 )
303 ++nCubesInGroup[cubeGroup_[leafI]];
306 cubesInGroup_.setSizeAndRowSize(nCubesInGroup);
308 forAllReverse(cubeGroup_, leafI)
310 const label groupI = cubeGroup_[leafI];
315 cubesInGroup_(groupI, --nCubesInGroup[groupI]) = leafI;
318 //- mark cubes at inter-processor boundaries
319 forAll(commCubes, leafI)
321 if( commCubes[leafI] )
322 communicationCubes_.append(leafI);
327 forAll(cubeGroup_, leafI)
329 if( cubeGroup_[leafI] != -1 )
332 reduce(nMarked, sumOp<label>());
333 const label totalLeaves = returnReduce(leaves_.size(), sumOp<label>());
334 Info << "Total number of leaves " << totalLeaves << endl;
335 Info << "Number of marked leaves " << nMarked << endl;
339 void meshOctreeInsideOutside::markOutsideCubes()
341 const LongList<meshOctreeCube*>& leaves = octreeModifier_.leavesAccess();
342 const meshOctree& octree = octreeModifier_.octree();
344 DynList<label> neighbours;
350 keepUpdating = false;
356 //- make sure that groups created by different threads
357 //- have the same information
358 forAll(neighbouringGroups_, groupI)
360 if( groupType_[groupI] & meshOctreeCubeBasic::OUTSIDE )
362 forAllRow(neighbouringGroups_, groupI, i)
364 const label neiGroup = neighbouringGroups_(groupI, i);
365 if( groupType_[neiGroup] & meshOctreeCube::UNKNOWN )
368 groupType_[neiGroup] = meshOctreeCube::OUTSIDE;
377 } while( nChanged != 0 );
382 LongList<meshOctreeCubeCoordinates> dataToSend;
384 //- go through the list of communicationCubes and send the ones
385 //- which are marked as outside
386 forAll(communicationCubes_, i)
388 const label groupI = cubeGroup_[communicationCubes_[i]];
393 if( groupType_[groupI] & meshOctreeCube::OUTSIDE )
394 dataToSend.append(*leaves[communicationCubes_[i]]);
397 LongList<meshOctreeCubeCoordinates> receivedCoords;
398 octree.exchangeRequestsWithNeighbourProcessors
404 //- go through the list of received coordinates and check if any
405 //- local boxes are their neighbours. If a local neighbour is
406 //- a DATA box set the hasOutsideNeighbour_ flag to true. If the
407 //- local neighbour is of UNKNOWN type set it to OUTSIDE.
409 # pragma omp parallel for if( receivedCoords.size() > 100 ) \
410 private(neighbours) schedule(dynamic, 20)
412 forAll(receivedCoords, i)
414 octree.findNeighboursForLeaf(receivedCoords[i], neighbours);
416 forAll(neighbours, neiI)
418 const label nei = neighbours[neiI];
423 if( leaves[nei]->hasContainedElements() )
425 hasOutsideNeighbour_[nei] = true;
428 if( groupType_[cubeGroup_[nei]] & meshOctreeCube::UNKNOWN )
430 groupType_[cubeGroup_[nei]] = meshOctreeCube::OUTSIDE;
439 reduce(nChanged, sumOp<label>());
440 } while( nChanged != 0 );
442 reduce(keepUpdating, maxOp<bool>());
444 } while( keepUpdating );
446 //- set OUTSIDE type to the cubes in OUTSIDE groups
449 std::map<label, direction>::const_iterator it=groupType_.begin();
450 it!=groupType_.end();
457 if( it->second & meshOctreeCubeBasic::OUTSIDE )
459 const label groupI = it->first;
461 //- set the cube type to OUTSIDE
462 forAllRow(cubesInGroup_, groupI, i)
463 leaves[cubesInGroup_(groupI, i)]->setCubeType
465 meshOctreeCube::OUTSIDE
468 //- set true to the collected DATA boxes
469 forAllRow(boundaryDATACubes_, groupI, neiI)
470 hasOutsideNeighbour_[boundaryDATACubes_(groupI, neiI)] = true;
475 void meshOctreeInsideOutside::reviseDataBoxes()
477 //- remove DATA flag from boxes which do not have an OUTSIDE neighbour
478 //- and are not surrounded with DATA boxes containing different surface
479 //- triangles in different patches
480 const LongList<meshOctreeCube*>& leaves = octreeModifier_.leavesAccess();
481 const meshOctree& octree = octreeModifier_.octree();
482 const triSurf& surface = octree.surface();
483 DynList<label> neighbours;
485 boolList checkedPatches(leaves.size(), false);
493 LongList<meshOctreeCubeCoordinates> checkCoordinates;
494 labelHashSet transferCoordinates;
497 # pragma omp parallel for if( leaves.size() > 1000 ) \
498 private(neighbours) schedule(dynamic, 20) reduction(+ : nMarked)
500 forAll(leaves, leafI)
501 if( Pstream::parRun() && hasOutsideNeighbour_[leafI] )
503 octree.findAllLeafNeighbours(leafI, neighbours);
504 forAll(neighbours, neiI)
505 if( neighbours[neiI] == meshOctreeCubeBasic::OTHERPROC )
508 # pragma omp critical
511 if( !transferCoordinates.found(leafI) )
513 checkCoordinates.append
515 leaves[leafI]->coordinates()
517 transferCoordinates.insert(leafI);
525 (leaves[leafI]->cubeType() & meshOctreeCube::DATA) &&
526 !hasOutsideNeighbour_[leafI]
529 meshOctreeCube* oc = leaves[leafI];
532 Info << "Box " << leafI << " may not be a DATA box" << endl;
535 DynList<label> patches;
537 oc->slotPtr()->containedTriangles_;
538 const constRow el = ct[oc->containedElements()];
540 patches.appendIfNotIn(surface[el[elI]].region());
542 if( patches.size() > 1 )
545 checkedPatches[leafI] = true;
547 //- check if there exist neighbours
548 //- which have some DATA neighbours
549 octree.findAllLeafNeighbours(leafI, neighbours);
550 forAll(neighbours, neiI)
552 const label nei = neighbours[neiI];
557 if( hasOutsideNeighbour_[nei] )
559 oc->setCubeType(meshOctreeCube::INSIDE);
567 if( octree.neiProcs().size() )
569 LongList<meshOctreeCubeCoordinates> receivedCoords;
570 octree.exchangeRequestsWithNeighbourProcessors
576 //- check if any of the local neighbours is a data box with
577 //- no OUTSIDE neighbours
579 # pragma omp parallel for if( receivedCoords.size() > 100 ) \
580 private(neighbours) schedule(dynamic, 20) reduction(+ : nMarked)
582 forAll(receivedCoords, i)
584 octree.findAllLeafNeighbours(receivedCoords[i], neighbours);
586 forAll(neighbours, neiI)
588 const label nei = neighbours[neiI];
595 (leaves[nei]->cubeType() & meshOctreeCube::DATA) &&
596 !hasOutsideNeighbour_[nei] && checkedPatches[nei]
599 leaves[nei]->setCubeType(meshOctreeCube::INSIDE);
606 reduce(nMarked, sumOp<label>());
608 } while( nMarked != 0 );
611 label nOutside(0), nData(0), hasOutNei(0);
612 forAll(leaves, leafI)
614 const direction cType = leaves[leafI]->cubeType();
615 if( cType & meshOctreeCubeBasic::OUTSIDE )
617 else if( cType & meshOctreeCubeBasic::DATA )
620 if( hasOutsideNeighbour_[leafI] )
624 reduce(hasOutNei, sumOp<label>());
625 reduce(nData, sumOp<label>());
626 reduce(nOutside, sumOp<label>());
627 Info << "Number of outside boxes " << nOutside << endl;
628 Info << "Number of data boxes " << nData << " real data "
629 << hasOutNei << endl;
630 returnReduce(1, sumOp<label>());
635 void meshOctreeInsideOutside::markInsideCubes()
637 const LongList<meshOctreeCube*>& leaves = octreeModifier_.leavesAccess();
638 const meshOctree& octree = octreeModifier_.octree();
641 DynList<label> neighbours;
643 //- make INSIDE groups for which it is possible
646 std::map<label, direction>::iterator it=groupType_.begin();
647 it!=groupType_.end();
651 const label groupI = it->first;
656 if( it->second & meshOctreeCubeBasic::UNKNOWN )
658 forAllRow(boundaryDATACubes_, groupI, neiI)
660 const label cLabel = boundaryDATACubes_(groupI, neiI);
662 hasOutsideNeighbour_[cLabel] ||
664 leaves[cLabel]->cubeType() & meshOctreeCube::INSIDE
668 it->second = meshOctreeCube::INSIDE;
677 keepUpdating = false;
679 //- mark INSIDE groups created by different threads
684 forAll(neighbouringGroups_, groupI)
686 if( groupType_[groupI] & meshOctreeCube::INSIDE )
688 forAllRow(neighbouringGroups_, groupI, i)
690 const label neiGroup = neighbouringGroups_(groupI, i);
692 if( groupType_[neiGroup] & meshOctreeCube::UNKNOWN )
695 groupType_[neiGroup] = meshOctreeCube::INSIDE;
704 } while( nChanged != 0 );
706 if( octree.neiProcs().size() == 0 )
709 //- the code for exchanging data between different processes
710 LongList<meshOctreeCubeCoordinates> dataToSend, receivedCoords;
712 //- send coordinates of boxes with hasOutsideNeighbour_ flag and
713 //- the boxes which have been marked as INSIDE to the neighbouring procs
714 forAll(hasOutsideNeighbour_, leafI)
717 hasOutsideNeighbour_[leafI] ||
718 (leaves[leafI]->cubeType() & meshOctreeCubeBasic::INSIDE)
721 octree.findNeighboursForLeaf(leafI, neighbours);
723 forAll(neighbours, neiI)
724 if( neighbours[neiI] == meshOctreeCube::OTHERPROC )
726 dataToSend.append(leaves[leafI]->coordinates());
732 octree.exchangeRequestsWithNeighbourProcessors
739 # pragma omp parallel for if( receivedCoords.size() > 100 ) \
740 private(neighbours) schedule(dynamic, 20)
742 forAll(receivedCoords, i)
744 octree.findNeighboursForLeaf(receivedCoords[i], neighbours);
746 forAll(neighbours, neiI)
748 const label nei = neighbours[neiI];
753 const label groupI = cubeGroup_[nei];
758 if( groupType_[groupI] & meshOctreeCube::UNKNOWN )
759 groupType_[groupI] = meshOctreeCubeBasic::INSIDE;
768 //- go through the list of communicationCubes and send the ones
769 //- which are marked as outside
770 forAll(communicationCubes_, i)
773 groupType_[cubeGroup_[communicationCubes_[i]]] &
774 meshOctreeCubeBasic::INSIDE
778 leaves[communicationCubes_[i]]->coordinates()
782 receivedCoords.clear();
783 octree.exchangeRequestsWithNeighbourProcessors
789 //- go through the list of received coordinates and check if any
790 //- local boxes are their neighbours. If a local neighbour is
791 //- a DATA box set the hasOutsideNeighbour_ flag to true. If the
792 //- local neighbour is of UNKNOWN type set it to OUTSIDE.
794 # pragma omp parallel for if( receivedCoords.size() > 100 ) \
795 private(neighbours) schedule(dynamic, 20) reduction(+ : nChanged)
797 forAll(receivedCoords, i)
799 octree.findNeighboursForLeaf(receivedCoords[i], neighbours);
801 forAll(neighbours, neiI)
803 const label nei = neighbours[neiI];
808 const label groupI = cubeGroup_[nei];
813 if( groupType_[groupI] & meshOctreeCube::UNKNOWN )
815 groupType_[groupI] = meshOctreeCube::INSIDE;
821 reduce(nChanged, sumOp<label>());
826 } while( nChanged != 0 );
828 reduce(keepUpdating, maxOp<bool>());
830 } while( keepUpdating );
832 //- set INSIDE type to the cubes in INSIDE groups
835 std::map<label, direction>::const_iterator it=groupType_.begin();
836 it!=groupType_.end();
843 if( it->second & meshOctreeCubeBasic::INSIDE )
845 const label groupI = it->first;
847 //- set the cube type to OUTSIDE
848 forAllRow(cubesInGroup_, groupI, i)
849 leaves[cubesInGroup_(groupI, i)]->setCubeType
851 meshOctreeCube::INSIDE
857 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
859 } // End namespace Foam
861 // ************************************************************************* //