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 \*----------------------------------------------------------------------------*/
26 #include "meshRefinement.H"
28 #include "syncTools.H"
30 #include "refinementSurfaces.H"
33 #include "indirectPrimitivePatch.H"
34 #include "polyTopoChange.H"
35 #include "meshTools.H"
36 #include "polyModifyFace.H"
37 #include "polyModifyCell.H"
38 #include "polyAddFace.H"
39 #include "polyRemoveFace.H"
40 #include "polyAddPoint.H"
41 #include "localPointRegion.H"
42 #include "duplicatePoints.H"
44 #include "regionSplit.H"
45 #include "removeCells.H"
47 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
49 // Repatches external face or creates baffle for internal face
50 // with user specified patches (might be different for both sides).
51 // Returns label of added face.
52 Foam::label Foam::meshRefinement::createBaffle
57 polyTopoChange& meshMod
60 const face& f = mesh_.faces()[faceI];
61 label zoneID = mesh_.faceZones().whichZone(faceI);
62 bool zoneFlip = false;
66 const faceZone& fZone = mesh_.faceZones()[zoneID];
67 zoneFlip = fZone.flipMap()[fZone.whichFace(faceI)];
75 faceI, // label of face
76 mesh_.faceOwner()[faceI], // owner
79 ownPatch, // patch for face
80 false, // remove from zone
81 zoneID, // zone for face
82 zoneFlip // face flip in zone
89 if (mesh_.isInternalFace(faceI))
95 "meshRefinement::createBaffle"
96 "(const label, const label, const label, polyTopoChange&)"
97 ) << "No neighbour patch for internal face " << faceI
98 << " fc:" << mesh_.faceCentres()[faceI]
99 << " ownPatch:" << ownPatch << abort(FatalError);
102 bool reverseFlip = false;
105 reverseFlip = !zoneFlip;
108 dupFaceI = meshMod.setAction
112 f.reverseFace(), // modified face
113 mesh_.faceNeighbour()[faceI],// owner
117 faceI, // masterFaceID,
119 neiPatch, // patch for face
120 zoneID, // zone for face
121 reverseFlip // face flip in zone
129 // Get an estimate for the patch the internal face should get. Bit heuristic.
130 Foam::label Foam::meshRefinement::getBafflePatch
132 const labelList& facePatch,
136 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
138 // Loop over face points
139 // for each point check all faces patch IDs
140 // as soon as an ID >= 0 is found, break and assign that ID
141 // to the current face.
142 // Check first for real patch (so proper surface intersection and then
143 // in facePatch array for patches to block off faces
145 forAll(mesh_.faces()[faceI], fp)
147 label pointI = mesh_.faces()[faceI][fp];
149 forAll(mesh_.pointFaces()[pointI], pf)
151 label pFaceI = mesh_.pointFaces()[pointI][pf];
153 label patchI = patches.whichPatch(pFaceI);
155 if (patchI != -1 && !patches[patchI].coupled())
159 else if (facePatch[pFaceI] != -1)
161 return facePatch[pFaceI];
166 // Loop over owner and neighbour cells, looking for the first face with a
167 // valid patch number
168 const cell& ownFaces = mesh_.cells()[mesh_.faceOwner()[faceI]];
172 label cFaceI = ownFaces[i];
174 label patchI = patches.whichPatch(cFaceI);
176 if (patchI != -1 && !patches[patchI].coupled())
180 else if (facePatch[cFaceI] != -1)
182 return facePatch[cFaceI];
186 if (mesh_.isInternalFace(faceI))
188 const cell& neiFaces = mesh_.cells()[mesh_.faceNeighbour()[faceI]];
192 label cFaceI = neiFaces[i];
194 label patchI = patches.whichPatch(cFaceI);
196 if (patchI != -1 && !patches[patchI].coupled())
200 else if (facePatch[cFaceI] != -1)
202 return facePatch[cFaceI];
209 "meshRefinement::getBafflePatch(const labelList&, const label)"
210 ) << "Could not find boundary face neighbouring internal face "
211 << faceI << " with face centre " << mesh_.faceCentres()[faceI]
213 << "Using arbitrary patch " << 0 << " instead." << endl;
219 // Determine patches for baffles on all intersected unnamed faces
220 void Foam::meshRefinement::getBafflePatches
222 const labelList& globalToPatch,
223 const labelList& neiLevel,
224 const pointField& neiCc,
230 autoPtr<OFstream> str;
232 if (debug&OBJINTERSECTIONS)
238 mesh_.time().path()/timeName()/"intersections.obj"
242 Pout<< "getBafflePatches : Writing surface intersections to file "
243 << str().name() << nl << endl;
246 const pointField& cellCentres = mesh_.cellCentres();
248 // Surfaces that need to be baffled
249 const labelList surfacesToBaffle(surfaces_.getUnnamedSurfaces());
251 ownPatch.setSize(mesh_.nFaces());
253 neiPatch.setSize(mesh_.nFaces());
257 // Collect candidate faces
258 // ~~~~~~~~~~~~~~~~~~~~~~~
260 labelList testFaces(intersectedFaces());
265 pointField start(testFaces.size());
266 pointField end(testFaces.size());
270 label faceI = testFaces[i];
272 label own = mesh_.faceOwner()[faceI];
274 if (mesh_.isInternalFace(faceI))
276 start[i] = cellCentres[own];
277 end[i] = cellCentres[mesh_.faceNeighbour()[faceI]];
281 start[i] = cellCentres[own];
282 end[i] = neiCc[faceI-mesh_.nInternalFaces()];
286 // Extend segments a bit
288 const vectorField smallVec(Foam::sqrt(SMALL)*(end-start));
294 // Do test for intersections
295 // ~~~~~~~~~~~~~~~~~~~~~~~~~
297 List<pointIndexHit> hit1;
300 List<pointIndexHit> hit2;
302 surfaces_.findNearestIntersection
319 label faceI = testFaces[i];
321 if (hit1[i].hit() && hit2[i].hit())
325 meshTools::writeOBJ(str(), start[i]);
327 meshTools::writeOBJ(str(), hit1[i].rawPoint());
329 meshTools::writeOBJ(str(), hit2[i].rawPoint());
331 meshTools::writeOBJ(str(), end[i]);
333 str()<< "l " << vertI-3 << ' ' << vertI-2 << nl;
334 str()<< "l " << vertI-2 << ' ' << vertI-1 << nl;
335 str()<< "l " << vertI-1 << ' ' << vertI << nl;
338 // Pick up the patches
339 ownPatch[faceI] = globalToPatch
341 surfaces_.globalRegion(surface1[i], region1[i])
343 neiPatch[faceI] = globalToPatch
345 surfaces_.globalRegion(surface2[i], region2[i])
348 if (ownPatch[faceI] == -1 || neiPatch[faceI] == -1)
350 FatalErrorIn("getBafflePatches(..)")
351 << "problem." << abort(FatalError);
356 // No need to parallel sync since intersection data (surfaceIndex_ etc.)
357 // already guaranteed to be synced...
359 // - owncc and neicc are reversed on different procs so might pick
360 // up different regions reversed? No problem. Neighbour on one processor
361 // might not be owner on the other processor but the neighbour is
362 // not used when creating baffles from proc faces.
363 // - tolerances issues occasionally crop up.
364 syncTools::syncFaceList(mesh_, ownPatch, maxEqOp<label>());
365 syncTools::syncFaceList(mesh_, neiPatch, maxEqOp<label>());
369 // Get faces to repatch. Returns map from face to patch.
370 Foam::Map<Foam::label> Foam::meshRefinement::getZoneBafflePatches
372 const bool allowBoundary,
373 const labelList& globalToPatch
376 Map<label> bafflePatch(mesh_.nFaces()/1000);
378 const wordList& faceZoneNames = surfaces_.faceZoneNames();
379 const faceZoneMesh& fZones = mesh_.faceZones();
381 forAll(faceZoneNames, surfI)
383 if (faceZoneNames[surfI].size())
386 label zoneI = fZones.findZoneID(faceZoneNames[surfI]);
388 const faceZone& fZone = fZones[zoneI];
390 //// Get patch allocated for zone
391 //label patchI = surfaceToCyclicPatch_[surfI];
392 // Get patch of (first region) of surface
393 label patchI = globalToPatch[surfaces_.globalRegion(surfI, 0)];
395 Info<< "For surface "
396 << surfaces_.names()[surfI]
397 << " found faceZone " << fZone.name()
398 << " and patch " << mesh_.boundaryMesh()[patchI].name()
404 label faceI = fZone[i];
406 if (allowBoundary || mesh_.isInternalFace(faceI))
408 if (!bafflePatch.insert(faceI, patchI))
410 label oldPatchI = bafflePatch[faceI];
412 if (oldPatchI != patchI)
414 FatalErrorIn("getZoneBafflePatches(const bool)")
416 << " fc:" << mesh_.faceCentres()[faceI]
417 << " in zone " << fZone.name()
419 << mesh_.boundaryMesh()[oldPatchI].name()
421 << mesh_.boundaryMesh()[patchI].name()
422 << abort(FatalError);
433 // Create baffle for every face where ownPatch != -1
434 Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::createBaffles
436 const labelList& ownPatch,
437 const labelList& neiPatch
442 ownPatch.size() != mesh_.nFaces()
443 || neiPatch.size() != mesh_.nFaces()
448 "meshRefinement::createBaffles"
449 "(const labelList&, const labelList&)"
450 ) << "Illegal size :"
451 << " ownPatch:" << ownPatch.size()
452 << " neiPatch:" << neiPatch.size()
453 << ". Should be number of faces:" << mesh_.nFaces()
454 << abort(FatalError);
459 labelList syncedOwnPatch(ownPatch);
460 syncTools::syncFaceList(mesh_, syncedOwnPatch, maxEqOp<label>());
461 labelList syncedNeiPatch(neiPatch);
462 syncTools::syncFaceList(mesh_, syncedNeiPatch, maxEqOp<label>());
464 forAll(syncedOwnPatch, faceI)
468 (ownPatch[faceI] == -1 && syncedOwnPatch[faceI] != -1)
469 || (neiPatch[faceI] == -1 && syncedNeiPatch[faceI] != -1)
474 "meshRefinement::createBaffles"
475 "(const labelList&, const labelList&)"
476 ) << "Non synchronised at face:" << faceI
477 << " on patch:" << mesh_.boundaryMesh().whichPatch(faceI)
478 << " fc:" << mesh_.faceCentres()[faceI] << endl
479 << "ownPatch:" << ownPatch[faceI]
480 << " syncedOwnPatch:" << syncedOwnPatch[faceI]
481 << " neiPatch:" << neiPatch[faceI]
482 << " syncedNeiPatch:" << syncedNeiPatch[faceI]
483 << abort(FatalError);
488 // Topochange container
489 polyTopoChange meshMod(mesh_);
493 forAll(ownPatch, faceI)
495 if (ownPatch[faceI] != -1)
497 // Create baffle or repatch face. Return label of inserted baffle
502 ownPatch[faceI], // owner side patch
503 neiPatch[faceI], // neighbour side patch
510 // Change the mesh (no inflation, parallel sync)
511 autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true);
514 mesh_.updateMesh(map);
516 // Move mesh if in inflation mode
517 if (map().hasMotionPoints())
519 mesh_.movePoints(map().preMotionPoints());
523 // Delete mesh volumes.
528 // Reset the instance for if in overwrite mode
529 mesh_.setInstance(timeName());
531 //- Redo the intersections on the newly create baffle faces. Note that
532 // this changes also the cell centre positions.
533 faceSet baffledFacesSet(mesh_, "baffledFacesSet", 2*nBaffles);
535 const labelList& reverseFaceMap = map().reverseFaceMap();
536 const labelList& faceMap = map().faceMap();
538 // Pick up owner side of baffle
539 forAll(ownPatch, oldFaceI)
541 label faceI = reverseFaceMap[oldFaceI];
543 if (ownPatch[oldFaceI] != -1 && faceI >= 0)
545 const cell& ownFaces = mesh_.cells()[mesh_.faceOwner()[faceI]];
549 baffledFacesSet.insert(ownFaces[i]);
553 // Pick up neighbour side of baffle (added faces)
554 forAll(faceMap, faceI)
556 label oldFaceI = faceMap[faceI];
558 if (oldFaceI >= 0 && reverseFaceMap[oldFaceI] != faceI)
560 const cell& ownFaces = mesh_.cells()[mesh_.faceOwner()[faceI]];
564 baffledFacesSet.insert(ownFaces[i]);
568 baffledFacesSet.sync(mesh_);
570 updateMesh(map, baffledFacesSet.toc());
576 // Return a list of coupled face pairs, i.e. faces that use the same vertices.
577 // (this information is recalculated instead of maintained since would be too
578 // hard across splitMeshRegions).
579 Foam::List<Foam::labelPair> Foam::meshRefinement::getDuplicateFaces
581 const labelList& testFaces
584 labelList duplicateFace
586 localPointRegion::findDuplicateFaces
593 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
595 // Convert into list of coupled face pairs (mesh face labels).
596 List<labelPair> duplicateFaces(testFaces.size());
599 forAll(duplicateFace, i)
601 label otherFaceI = duplicateFace[i];
603 if (otherFaceI != -1 && i < otherFaceI)
605 label meshFace0 = testFaces[i];
606 label patch0 = patches.whichPatch(meshFace0);
607 label meshFace1 = testFaces[otherFaceI];
608 label patch1 = patches.whichPatch(meshFace1);
612 (patch0 != -1 && isA<processorPolyPatch>(patches[patch0]))
613 || (patch1 != -1 && isA<processorPolyPatch>(patches[patch1]))
618 "meshRefinement::getDuplicateFaces"
619 "(const bool, const labelList&)"
620 ) << "One of two duplicate faces is on"
621 << " processorPolyPatch."
622 << "This is not allowed." << nl
623 << "Face:" << meshFace0
624 << " is on patch:" << patches[patch0].name()
626 << "Face:" << meshFace1
627 << " is on patch:" << patches[patch1].name()
628 << abort(FatalError);
631 duplicateFaces[dupI++] = labelPair(meshFace0, meshFace1);
634 duplicateFaces.setSize(dupI);
636 Info<< "getDuplicateFaces : found " << returnReduce(dupI, sumOp<label>())
637 << " pairs of duplicate faces." << nl << endl;
642 faceSet duplicateFaceSet(mesh_, "duplicateFaces", 2*dupI);
644 forAll(duplicateFaces, i)
646 duplicateFaceSet.insert(duplicateFaces[i][0]);
647 duplicateFaceSet.insert(duplicateFaces[i][1]);
649 Pout<< "Writing duplicate faces (baffles) to faceSet "
650 << duplicateFaceSet.name() << nl << endl;
651 duplicateFaceSet.instance() = timeName();
652 duplicateFaceSet.write();
655 return duplicateFaces;
659 Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::createZoneBaffles
661 const labelList& globalToPatch,
662 List<labelPair>& baffles
665 labelList zonedSurfaces = surfaces_.getNamedSurfaces();
667 autoPtr<mapPolyMesh> map;
669 // No need to sync; all processors will have all same zonedSurfaces.
670 if (zonedSurfaces.size())
672 // Split internal faces on interface surfaces
673 Info<< "Converting zoned faces into baffles ..." << endl;
675 // Get faces (internal only) to be baffled. Map from face to patch
677 Map<label> faceToPatch(getZoneBafflePatches(false, globalToPatch));
679 label nZoneFaces = returnReduce(faceToPatch.size(), sumOp<label>());
682 // Convert into labelLists
683 labelList ownPatch(mesh_.nFaces(), -1);
684 forAllConstIter(Map<label>, faceToPatch, iter)
686 ownPatch[iter.key()] = iter();
689 // Create baffles. both sides same patch.
690 map = createBaffles(ownPatch, ownPatch);
692 // Get pairs of faces created.
693 // Just loop over faceMap and store baffle if we encounter a slave
696 baffles.setSize(faceToPatch.size());
699 const labelList& faceMap = map().faceMap();
700 const labelList& reverseFaceMap = map().reverseFaceMap();
702 forAll(faceMap, faceI)
704 label oldFaceI = faceMap[faceI];
706 // Does face originate from face-to-patch
707 Map<label>::const_iterator iter = faceToPatch.find(oldFaceI);
709 if (iter != faceToPatch.end())
711 label masterFaceI = reverseFaceMap[oldFaceI];
712 if (faceI != masterFaceI)
714 baffles[baffleI++] = labelPair(masterFaceI, faceI);
719 if (baffleI != faceToPatch.size())
721 FatalErrorIn("meshRefinement::createZoneBaffles(..)")
722 << "Had " << faceToPatch.size() << " patches to create "
723 << " but encountered " << baffleI
724 << " slave faces originating from patcheable faces."
725 << abort(FatalError);
730 const_cast<Time&>(mesh_.time())++;
731 Pout<< "Writing zone-baffled mesh to time " << timeName()
733 write(debug, mesh_.time().path()/"baffles");
736 Info<< "Created " << nZoneFaces << " baffles in = "
737 << mesh_.time().cpuTimeIncrement() << " s\n" << nl << endl;
743 // Extract those baffles (duplicate) faces that are on the edge of a baffle
744 // region. These are candidates for merging.
745 // Done by counting the number of baffles faces per mesh edge. If edge
746 // has 2 boundary faces and both are baffle faces it is the edge of a baffle
748 Foam::List<Foam::labelPair> Foam::meshRefinement::filterDuplicateFaces
750 const List<labelPair>& couples
753 // All duplicate faces on edge of the patch are to be merged.
754 // So we count for all edges of duplicate faces how many duplicate
756 labelList nBafflesPerEdge(mesh_.nEdges(), 0);
760 // Count number of boundary faces per edge
761 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
763 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
765 forAll(patches, patchI)
767 const polyPatch& pp = patches[patchI];
769 // Count number of boundary faces. Discard coupled boundary faces.
772 label faceI = pp.start();
776 const labelList& fEdges = mesh_.faceEdges(faceI);
778 forAll(fEdges, fEdgeI)
780 nBafflesPerEdge[fEdges[fEdgeI]]++;
788 DynamicList<label> fe0;
789 DynamicList<label> fe1;
792 // Count number of duplicate boundary faces per edge
793 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
797 const labelList& fEdges0 = mesh_.faceEdges(couples[i].first(), fe0);
799 forAll(fEdges0, fEdgeI)
801 nBafflesPerEdge[fEdges0[fEdgeI]] += 1000000;
804 const labelList& fEdges1 = mesh_.faceEdges(couples[i].second(), fe1);
806 forAll(fEdges1, fEdgeI)
808 nBafflesPerEdge[fEdges1[fEdgeI]] += 1000000;
812 // Add nBaffles on shared edges
813 syncTools::syncEdgeList
817 plusEqOp<label>(), // in-place add
822 // Baffles which are not next to other boundaries and baffles will have
823 // nBafflesPerEdge value 2*1000000+2*1 (from 2 boundary faces which are
824 // both baffle faces)
826 List<labelPair> filteredCouples(couples.size());
831 const labelPair& couple = couples[i];
835 patches.whichPatch(couple.first())
836 == patches.whichPatch(couple.second())
839 const labelList& fEdges = mesh_.faceEdges(couples[i].first());
841 forAll(fEdges, fEdgeI)
843 label edgeI = fEdges[fEdgeI];
845 if (nBafflesPerEdge[edgeI] == 2*1000000+2*1)
847 filteredCouples[filterI++] = couples[i];
853 filteredCouples.setSize(filterI);
855 //Info<< "filterDuplicateFaces : from "
856 // << returnReduce(couples.size(), sumOp<label>())
858 // << returnReduce(filteredCouples.size(), sumOp<label>())
859 // << " baffles." << nl << endl;
861 return filteredCouples;
865 // Merge baffles. Gets pairs of faces.
866 Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::mergeBaffles
868 const List<labelPair>& couples
871 // Mesh change engine
872 polyTopoChange meshMod(mesh_);
874 const faceList& faces = mesh_.faces();
875 const labelList& faceOwner = mesh_.faceOwner();
876 const faceZoneMesh& faceZones = mesh_.faceZones();
880 label face0 = couples[i].first();
881 label face1 = couples[i].second();
883 // face1 < 0 signals a coupled face that has been converted to baffle.
885 label own0 = faceOwner[face0];
886 label own1 = faceOwner[face1];
888 if (face1 < 0 || own0 < own1)
890 // Use face0 as the new internal face.
891 label zoneID = faceZones.whichZone(face0);
892 bool zoneFlip = false;
896 const faceZone& fZone = faceZones[zoneID];
897 zoneFlip = fZone.flipMap()[fZone.whichFace(face0)];
900 label nei = (face1 < 0 ? -1 : own1);
902 meshMod.setAction(polyRemoveFace(face1));
907 faces[face0], // modified face
908 face0, // label of face being modified
912 -1, // patch for face
913 false, // remove from zone
914 zoneID, // zone for face
915 zoneFlip // face flip in zone
921 // Use face1 as the new internal face.
922 label zoneID = faceZones.whichZone(face1);
923 bool zoneFlip = false;
927 const faceZone& fZone = faceZones[zoneID];
928 zoneFlip = fZone.flipMap()[fZone.whichFace(face1)];
931 meshMod.setAction(polyRemoveFace(face0));
936 faces[face1], // modified face
937 face1, // label of face being modified
941 -1, // patch for face
942 false, // remove from zone
943 zoneID, // zone for face
944 zoneFlip // face flip in zone
950 // Change the mesh (no inflation)
951 autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true);
954 mesh_.updateMesh(map);
956 // Move mesh (since morphing does not do this)
957 if (map().hasMotionPoints())
959 mesh_.movePoints(map().preMotionPoints());
963 // Delete mesh volumes.
967 // Reset the instance for if in overwrite mode
968 mesh_.setInstance(timeName());
970 // Update intersections. Recalculate intersections on merged faces since
971 // this seems to give problems? Note: should not be nessecary since
972 // baffles preserve intersections from when they were created.
973 labelList newExposedFaces(2*couples.size());
978 label newFace0 = map().reverseFaceMap()[couples[i].first()];
981 newExposedFaces[newI++] = newFace0;
984 label newFace1 = map().reverseFaceMap()[couples[i].second()];
987 newExposedFaces[newI++] = newFace1;
990 newExposedFaces.setSize(newI);
991 updateMesh(map, newExposedFaces);
997 // Finds region per cell for cells inside closed named surfaces
998 void Foam::meshRefinement::findCellZoneGeometric
1000 const labelList& closedNamedSurfaces, // indices of closed surfaces
1001 labelList& namedSurfaceIndex, // per face index of named surface
1002 const labelList& surfaceToCellZone, // cell zone index per surface
1004 labelList& cellToZone
1007 const pointField& cellCentres = mesh_.cellCentres();
1008 const labelList& faceOwner = mesh_.faceOwner();
1009 const labelList& faceNeighbour = mesh_.faceNeighbour();
1011 // Check if cell centre is inside
1012 labelList insideSurfaces;
1013 surfaces_.findInside
1015 closedNamedSurfaces,
1020 forAll(insideSurfaces, cellI)
1022 if (cellToZone[cellI] == -2)
1024 label surfI = insideSurfaces[cellI];
1028 cellToZone[cellI] = surfaceToCellZone[surfI];
1034 // Some cells with cell centres close to surface might have
1035 // had been put into wrong surface. Recheck with perturbed cell centre.
1038 // 1. Collect points
1040 // Count points to test.
1041 label nCandidates = 0;
1042 forAll(namedSurfaceIndex, faceI)
1044 label surfI = namedSurfaceIndex[faceI];
1048 if (mesh_.isInternalFace(faceI))
1060 pointField candidatePoints(nCandidates);
1062 forAll(namedSurfaceIndex, faceI)
1064 label surfI = namedSurfaceIndex[faceI];
1068 label own = faceOwner[faceI];
1069 const point& ownCc = cellCentres[own];
1071 if (mesh_.isInternalFace(faceI))
1073 label nei = faceNeighbour[faceI];
1074 const point& neiCc = cellCentres[nei];
1076 const vector d = 1E-4*(neiCc - ownCc);
1077 candidatePoints[nCandidates++] = ownCc-d;
1078 candidatePoints[nCandidates++] = neiCc+d;
1082 const point& neiFc = mesh_.faceCentres()[faceI];
1084 const vector d = 1E-4*(neiFc - ownCc);
1085 candidatePoints[nCandidates++] = ownCc-d;
1091 // 2. Test points for inside
1093 surfaces_.findInside
1095 closedNamedSurfaces,
1101 // 3. Update zone information
1104 forAll(namedSurfaceIndex, faceI)
1106 label surfI = namedSurfaceIndex[faceI];
1110 label own = faceOwner[faceI];
1112 if (mesh_.isInternalFace(faceI))
1114 label ownSurfI = insideSurfaces[nCandidates++];
1117 cellToZone[own] = surfaceToCellZone[ownSurfI];
1120 label neiSurfI = insideSurfaces[nCandidates++];
1123 label nei = faceNeighbour[faceI];
1125 cellToZone[nei] = surfaceToCellZone[neiSurfI];
1130 label ownSurfI = insideSurfaces[nCandidates++];
1133 cellToZone[own] = surfaceToCellZone[ownSurfI];
1140 // Adapt the namedSurfaceIndex
1141 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
1142 // for if any cells were not completely covered.
1144 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
1146 label ownZone = cellToZone[mesh_.faceOwner()[faceI]];
1147 label neiZone = cellToZone[mesh_.faceNeighbour()[faceI]];
1149 if (namedSurfaceIndex[faceI] == -1 && (ownZone != neiZone))
1151 // Give face the zone of max cell zone
1152 namedSurfaceIndex[faceI] = findIndex
1155 max(ownZone, neiZone)
1160 labelList neiCellZone(mesh_.nFaces()-mesh_.nInternalFaces());
1161 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
1163 forAll(patches, patchI)
1165 const polyPatch& pp = patches[patchI];
1171 label faceI = pp.start()+i;
1172 label ownZone = cellToZone[mesh_.faceOwner()[faceI]];
1173 neiCellZone[faceI-mesh_.nInternalFaces()] = ownZone;
1177 syncTools::swapBoundaryFaceList(mesh_, neiCellZone);
1179 forAll(patches, patchI)
1181 const polyPatch& pp = patches[patchI];
1187 label faceI = pp.start()+i;
1188 label ownZone = cellToZone[mesh_.faceOwner()[faceI]];
1189 label neiZone = neiCellZone[faceI-mesh_.nInternalFaces()];
1191 if (namedSurfaceIndex[faceI] == -1 && (ownZone != neiZone))
1193 // Give face the max cell zone
1194 namedSurfaceIndex[faceI] = findIndex
1197 max(ownZone, neiZone)
1205 syncTools::syncFaceList(mesh_, namedSurfaceIndex, maxEqOp<label>());
1208 void Foam::meshRefinement::findCellZoneInsideWalk
1210 const labelList& locationSurfaces, // indices of surfaces with inside point
1211 const labelList& namedSurfaceIndex, // per face index of named surface
1212 const labelList& surfaceToCellZone, // cell zone index per surface
1214 labelList& cellToZone
1217 // Analyse regions. Reuse regionsplit
1218 boolList blockedFace(mesh_.nFaces());
1220 forAll(namedSurfaceIndex, faceI)
1222 if (namedSurfaceIndex[faceI] == -1)
1224 blockedFace[faceI] = false;
1228 blockedFace[faceI] = true;
1231 // No need to sync since namedSurfaceIndex already is synced
1233 // Set region per cell based on walking
1234 regionSplit cellRegion(mesh_, blockedFace);
1235 blockedFace.clear();
1238 // For all locationSurface find the cell
1239 forAll(locationSurfaces, i)
1241 label surfI = locationSurfaces[i];
1242 const point& insidePoint = surfaces_.zoneInsidePoints()[surfI];
1244 Info<< "For surface " << surfaces_.names()[surfI]
1245 << " finding inside point " << insidePoint
1248 // Find the region containing the insidePoint
1249 label keepRegionI = -1;
1251 label cellI = mesh_.findCell(insidePoint);
1255 keepRegionI = cellRegion[cellI];
1257 reduce(keepRegionI, maxOp<label>());
1259 Info<< "For surface " << surfaces_.names()[surfI]
1260 << " found point " << insidePoint << " in cell " << cellI
1261 << " in global region " << keepRegionI
1262 << " out of " << cellRegion.nRegions() << " regions." << endl;
1264 if (keepRegionI == -1)
1268 "meshRefinement::findCellZoneInsideWalk"
1269 "(const labelList&, const labelList&"
1270 ", const labelList&, const labelList&)"
1271 ) << "Point " << insidePoint
1272 << " is not inside the mesh." << nl
1273 << "Bounding box of the mesh:" << mesh_.bounds()
1274 << exit(FatalError);
1277 // Set all cells with this region
1278 forAll(cellRegion, cellI)
1280 if (cellRegion[cellI] == keepRegionI)
1282 if (cellToZone[cellI] == -2)
1284 cellToZone[cellI] = surfaceToCellZone[surfI];
1286 else if (cellToZone[cellI] != surfaceToCellZone[surfI])
1290 "meshRefinement::findCellZoneInsideWalk"
1291 "(const labelList&, const labelList&"
1292 ", const labelList&, const labelList&)"
1293 ) << "Cell " << cellI
1294 << " at " << mesh_.cellCentres()[cellI]
1295 << " is inside surface " << surfaces_.names()[surfI]
1296 << " but already marked as being in zone "
1297 << cellToZone[cellI] << endl
1298 << "This can happen if your surfaces are not"
1299 << " (sufficiently) closed."
1309 bool Foam::meshRefinement::calcRegionToZone
1311 const label surfZoneI,
1312 const label ownRegion,
1313 const label neiRegion,
1315 labelList& regionToCellZone
1318 bool changed = false;
1320 // Check whether inbetween different regions
1321 if (ownRegion != neiRegion)
1323 // Jump. Change one of the sides to my type.
1325 // 1. Interface between my type and unset region.
1326 // Set region to keepRegion
1328 if (regionToCellZone[ownRegion] == -2)
1330 if (regionToCellZone[neiRegion] == surfZoneI)
1332 // Face between unset and my region. Put unset
1333 // region into keepRegion
1334 regionToCellZone[ownRegion] = -1;
1337 else if (regionToCellZone[neiRegion] != -2)
1339 // Face between unset and other region.
1340 // Put unset region into my region
1341 regionToCellZone[ownRegion] = surfZoneI;
1345 else if (regionToCellZone[neiRegion] == -2)
1347 if (regionToCellZone[ownRegion] == surfZoneI)
1349 // Face between unset and my region. Put unset
1350 // region into keepRegion
1351 regionToCellZone[neiRegion] = -1;
1354 else if (regionToCellZone[ownRegion] != -2)
1356 // Face between unset and other region.
1357 // Put unset region into my region
1358 regionToCellZone[neiRegion] = surfZoneI;
1367 // Finds region per cell. Assumes:
1368 // - region containing keepPoint does not go into a cellZone
1369 // - all other regions can be found by crossing faces marked in
1370 // namedSurfaceIndex.
1371 void Foam::meshRefinement::findCellZoneTopo
1373 const point& keepPoint,
1374 const labelList& namedSurfaceIndex,
1375 const labelList& surfaceToCellZone,
1376 labelList& cellToZone
1379 // Analyse regions. Reuse regionsplit
1380 boolList blockedFace(mesh_.nFaces());
1382 forAll(namedSurfaceIndex, faceI)
1384 if (namedSurfaceIndex[faceI] == -1)
1386 blockedFace[faceI] = false;
1390 blockedFace[faceI] = true;
1393 // No need to sync since namedSurfaceIndex already is synced
1395 // Set region per cell based on walking
1396 regionSplit cellRegion(mesh_, blockedFace);
1397 blockedFace.clear();
1399 // Per mesh region the zone the cell should be put in.
1400 // -2 : not analysed yet
1401 // -1 : keepPoint region. Not put into any cellzone.
1402 // >= 0 : index of cellZone
1403 labelList regionToCellZone(cellRegion.nRegions(), -2);
1405 // See which cells already are set in the cellToZone (from geometric
1406 // searching) and use these to take over their zones.
1407 // Note: could be improved to count number of cells per region.
1408 forAll(cellToZone, cellI)
1410 if (cellToZone[cellI] != -2)
1412 regionToCellZone[cellRegion[cellI]] = cellToZone[cellI];
1418 // Find the region containing the keepPoint
1419 label keepRegionI = -1;
1421 label cellI = mesh_.findCell(keepPoint);
1425 keepRegionI = cellRegion[cellI];
1427 reduce(keepRegionI, maxOp<label>());
1429 Info<< "Found point " << keepPoint << " in cell " << cellI
1430 << " in global region " << keepRegionI
1431 << " out of " << cellRegion.nRegions() << " regions." << endl;
1433 if (keepRegionI == -1)
1437 "meshRefinement::findCellZoneTopo"
1438 "(const point&, const labelList&, const labelList&, labelList&)"
1439 ) << "Point " << keepPoint
1440 << " is not inside the mesh." << nl
1441 << "Bounding box of the mesh:" << mesh_.bounds()
1442 << exit(FatalError);
1445 // Mark default region with zone -1.
1446 if (regionToCellZone[keepRegionI] == -2)
1448 regionToCellZone[keepRegionI] = -1;
1452 // Find correspondence between cell zone and surface
1453 // by changing cell zone every time we cross a surface.
1456 // Synchronise regionToCellZone.
1458 // - region numbers are identical on all processors
1459 // - keepRegion is identical ,,
1460 // - cellZones are identical ,,
1461 // This done at top of loop to account for geometric matching
1462 // not being synchronised.
1463 Pstream::listCombineGather(regionToCellZone, maxEqOp<label>());
1464 Pstream::listCombineScatter(regionToCellZone);
1467 bool changed = false;
1471 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
1473 label surfI = namedSurfaceIndex[faceI];
1475 // Connected even if no cellZone defined for surface
1478 // Calculate region to zone from cellRegions on either side
1479 // of internal face.
1480 bool changedCell = calcRegionToZone
1482 surfaceToCellZone[surfI],
1483 cellRegion[mesh_.faceOwner()[faceI]],
1484 cellRegion[mesh_.faceNeighbour()[faceI]],
1488 changed = changed | changedCell;
1494 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
1496 // Get coupled neighbour cellRegion
1497 labelList neiCellRegion(mesh_.nFaces()-mesh_.nInternalFaces());
1498 forAll(patches, patchI)
1500 const polyPatch& pp = patches[patchI];
1506 label faceI = pp.start()+i;
1507 neiCellRegion[faceI-mesh_.nInternalFaces()] =
1508 cellRegion[mesh_.faceOwner()[faceI]];
1512 syncTools::swapBoundaryFaceList(mesh_, neiCellRegion);
1514 // Calculate region to zone from cellRegions on either side of coupled
1516 forAll(patches, patchI)
1518 const polyPatch& pp = patches[patchI];
1524 label faceI = pp.start()+i;
1526 label surfI = namedSurfaceIndex[faceI];
1528 // Connected even if no cellZone defined for surface
1531 bool changedCell = calcRegionToZone
1533 surfaceToCellZone[surfI],
1534 cellRegion[mesh_.faceOwner()[faceI]],
1535 neiCellRegion[faceI-mesh_.nInternalFaces()],
1539 changed = changed | changedCell;
1545 if (!returnReduce(changed, orOp<bool>()))
1552 forAll(regionToCellZone, regionI)
1554 label zoneI = regionToCellZone[regionI];
1560 "meshRefinement::findCellZoneTopo"
1561 "(const point&, const labelList&, const labelList&, labelList&)"
1562 ) << "For region " << regionI << " haven't set cell zone."
1563 << exit(FatalError);
1569 forAll(regionToCellZone, regionI)
1571 Pout<< "Region " << regionI
1572 << " becomes cellZone:" << regionToCellZone[regionI]
1577 // Rework into cellToZone
1578 forAll(cellToZone, cellI)
1580 cellToZone[cellI] = regionToCellZone[cellRegion[cellI]];
1585 // Make namedSurfaceIndex consistent with cellToZone - clear out any blocked
1586 // faces inbetween same cell zone.
1587 void Foam::meshRefinement::makeConsistentFaceIndex
1589 const labelList& cellToZone,
1590 labelList& namedSurfaceIndex
1593 const labelList& faceOwner = mesh_.faceOwner();
1594 const labelList& faceNeighbour = mesh_.faceNeighbour();
1596 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
1598 label ownZone = cellToZone[faceOwner[faceI]];
1599 label neiZone = cellToZone[faceNeighbour[faceI]];
1601 if (ownZone == neiZone && namedSurfaceIndex[faceI] != -1)
1603 namedSurfaceIndex[faceI] = -1;
1605 else if (ownZone != neiZone && namedSurfaceIndex[faceI] == -1)
1607 FatalErrorIn("meshRefinement::zonify()")
1608 << "Different cell zones on either side of face " << faceI
1609 << " at " << mesh_.faceCentres()[faceI]
1610 << " but face not marked with a surface."
1611 << abort(FatalError);
1615 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
1617 // Get coupled neighbour cellZone
1618 labelList neiCellZone(mesh_.nFaces()-mesh_.nInternalFaces());
1619 forAll(patches, patchI)
1621 const polyPatch& pp = patches[patchI];
1627 label faceI = pp.start()+i;
1628 neiCellZone[faceI-mesh_.nInternalFaces()] =
1629 cellToZone[mesh_.faceOwner()[faceI]];
1633 syncTools::swapBoundaryFaceList(mesh_, neiCellZone);
1635 // Use coupled cellZone to do check
1636 forAll(patches, patchI)
1638 const polyPatch& pp = patches[patchI];
1644 label faceI = pp.start()+i;
1646 label ownZone = cellToZone[faceOwner[faceI]];
1647 label neiZone = neiCellZone[faceI-mesh_.nInternalFaces()];
1649 if (ownZone == neiZone && namedSurfaceIndex[faceI] != -1)
1651 namedSurfaceIndex[faceI] = -1;
1653 else if (ownZone != neiZone && namedSurfaceIndex[faceI] == -1)
1655 FatalErrorIn("meshRefinement::zonify()")
1656 << "Different cell zones on either side of face "
1657 << faceI << " at " << mesh_.faceCentres()[faceI]
1658 << " but face not marked with a surface."
1659 << abort(FatalError);
1665 // Unzonify boundary faces
1668 label faceI = pp.start()+i;
1669 namedSurfaceIndex[faceI] = -1;
1676 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1678 // Split off unreachable areas of mesh.
1679 void Foam::meshRefinement::baffleAndSplitMesh
1681 const bool handleSnapProblems,
1682 const bool removeEdgeConnectedCells,
1683 const scalarField& perpendicularAngle,
1684 const bool mergeFreeStanding,
1685 const dictionary& motionDict,
1687 const labelList& globalToPatch,
1688 const point& keepPoint
1691 // Introduce baffles
1692 // ~~~~~~~~~~~~~~~~~
1694 // Split the mesh along internal faces wherever there is a pierce between
1695 // two cell centres.
1697 Info<< "Introducing baffles for "
1698 << returnReduce(countHits(), sumOp<label>())
1699 << " faces that are intersected by the surface." << nl << endl;
1701 // Swap neighbouring cell centres and cell level
1702 labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
1703 pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
1704 calcNeighbourData(neiLevel, neiCc);
1706 labelList ownPatch, neiPatch;
1722 createBaffles(ownPatch, neiPatch);
1726 // Debug:test all is still synced across proc patches
1730 Info<< "Created baffles in = "
1731 << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
1733 printMeshInfo(debug, "After introducing baffles");
1737 Pout<< "Writing baffled mesh to time " << timeName()
1739 write(debug, runTime.path()/"baffles");
1740 Pout<< "Dumped debug data in = "
1741 << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
1745 // Introduce baffles to delete problem cells
1746 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1748 // Create some additional baffles where we want surface cells removed.
1750 if (handleSnapProblems)
1753 << "Introducing baffles to block off problem cells" << nl
1754 << "----------------------------------------------" << nl
1759 markFacesOnProblemCells
1762 removeEdgeConnectedCells,
1766 //markFacesOnProblemCellsGeometric(motionDict)
1768 Info<< "Analyzed problem cells in = "
1769 << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
1773 faceSet problemTopo(mesh_, "problemFacesTopo", 100);
1775 const labelList facePatchTopo
1777 markFacesOnProblemCells
1780 removeEdgeConnectedCells,
1785 forAll(facePatchTopo, faceI)
1787 if (facePatchTopo[faceI] != -1)
1789 problemTopo.insert(faceI);
1792 problemTopo.instance() = timeName();
1793 Pout<< "Dumping " << problemTopo.size()
1794 << " problem faces to " << problemTopo.objectPath() << endl;
1795 problemTopo.write();
1798 Info<< "Introducing baffles to delete problem cells." << nl << endl;
1805 // Create baffles with same owner and neighbour for now.
1806 createBaffles(facePatch, facePatch);
1810 // Debug:test all is still synced across proc patches
1813 Info<< "Created baffles in = "
1814 << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
1816 printMeshInfo(debug, "After introducing baffles");
1820 Pout<< "Writing extra baffled mesh to time "
1821 << timeName() << endl;
1822 write(debug, runTime.path()/"extraBaffles");
1823 Pout<< "Dumped debug data in = "
1824 << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
1829 // Select part of mesh
1830 // ~~~~~~~~~~~~~~~~~~~
1833 << "Remove unreachable sections of mesh" << nl
1834 << "-----------------------------------" << nl
1842 splitMeshRegions(keepPoint);
1846 // Debug:test all is still synced across proc patches
1849 Info<< "Split mesh in = "
1850 << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
1852 printMeshInfo(debug, "After subsetting");
1856 Pout<< "Writing subsetted mesh to time " << timeName()
1858 write(debug, runTime.path()/timeName());
1859 Pout<< "Dumped debug data in = "
1860 << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
1867 if (mergeFreeStanding)
1870 << "Merge free-standing baffles" << nl
1871 << "---------------------------" << nl
1879 // List of pairs of freestanding baffle faces.
1880 List<labelPair> couples
1882 filterDuplicateFaces // filter out freestanding baffles
1884 getDuplicateFaces // get all baffles
1886 identity(mesh_.nFaces()-mesh_.nInternalFaces())
1887 +mesh_.nInternalFaces()
1892 label nCouples = couples.size();
1893 reduce(nCouples, sumOp<label>());
1895 Info<< "Detected free-standing baffles : " << nCouples << endl;
1899 // Actually merge baffles. Note: not exactly parallellized. Should
1900 // convert baffle faces into processor faces if they resulted
1902 mergeBaffles(couples);
1906 // Debug:test all is still synced across proc patches
1910 Info<< "Merged free-standing baffles in = "
1911 << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
1916 // Split off (with optional buffer layers) unreachable areas of mesh.
1917 Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::splitMesh
1919 const label nBufferLayers,
1920 const labelList& globalToPatch,
1921 const point& keepPoint
1924 // Determine patches to put intersections into
1925 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1927 // Swap neighbouring cell centres and cell level
1928 labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
1929 pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
1930 calcNeighbourData(neiLevel, neiCc);
1932 labelList ownPatch, neiPatch;
1943 // Analyse regions. Reuse regionsplit
1944 boolList blockedFace(mesh_.nFaces(), false);
1946 forAll(ownPatch, faceI)
1948 if (ownPatch[faceI] != -1 || neiPatch[faceI] != -1)
1950 blockedFace[faceI] = true;
1953 syncTools::syncFaceList(mesh_, blockedFace, orEqOp<bool>());
1955 // Set region per cell based on walking
1956 regionSplit cellRegion(mesh_, blockedFace);
1957 blockedFace.clear();
1959 // Find the region containing the keepPoint
1960 label keepRegionI = -1;
1962 label cellI = mesh_.findCell(keepPoint);
1966 keepRegionI = cellRegion[cellI];
1968 reduce(keepRegionI, maxOp<label>());
1970 Info<< "Found point " << keepPoint << " in cell " << cellI
1971 << " in global region " << keepRegionI
1972 << " out of " << cellRegion.nRegions() << " regions." << endl;
1974 if (keepRegionI == -1)
1978 "meshRefinement::splitMesh"
1979 "(const label, const labelList&, const point&)"
1980 ) << "Point " << keepPoint
1981 << " is not inside the mesh." << nl
1982 << "Bounding box of the mesh:" << mesh_.bounds()
1983 << exit(FatalError);
1987 // Walk out nBufferlayers from region split
1988 // (modifies cellRegion, ownPatch)
1989 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1990 // Takes over face patch onto points and then back to faces and cells
1991 // (so cell-face-point walk)
1993 const labelList& faceOwner = mesh_.faceOwner();
1994 const labelList& faceNeighbour = mesh_.faceNeighbour();
1996 // Patch for exposed faces for lack of anything sensible.
1997 label defaultPatch = 0;
1998 if (globalToPatch.size())
2000 defaultPatch = globalToPatch[0];
2003 for (label i = 0; i < nBufferLayers; i++)
2005 // 1. From cells (via faces) to points
2007 labelList pointBaffle(mesh_.nPoints(), -1);
2009 forAll(faceNeighbour, faceI)
2011 const face& f = mesh_.faces()[faceI];
2013 label ownRegion = cellRegion[faceOwner[faceI]];
2014 label neiRegion = cellRegion[faceNeighbour[faceI]];
2016 if (ownRegion == keepRegionI && neiRegion != keepRegionI)
2018 // Note max(..) since possibly regionSplit might have split
2019 // off extra unreachable parts of mesh. Note: or can this only
2020 // happen for boundary faces?
2023 pointBaffle[f[fp]] = max(defaultPatch, ownPatch[faceI]);
2026 else if (ownRegion != keepRegionI && neiRegion == keepRegionI)
2028 label newPatchI = neiPatch[faceI];
2029 if (newPatchI == -1)
2031 newPatchI = max(defaultPatch, ownPatch[faceI]);
2035 pointBaffle[f[fp]] = newPatchI;
2041 label faceI = mesh_.nInternalFaces();
2042 faceI < mesh_.nFaces();
2046 const face& f = mesh_.faces()[faceI];
2048 label ownRegion = cellRegion[faceOwner[faceI]];
2050 if (ownRegion == keepRegionI)
2054 pointBaffle[f[fp]] = max(defaultPatch, ownPatch[faceI]);
2060 syncTools::syncPointList
2069 // 2. From points back to faces
2071 const labelListList& pointFaces = mesh_.pointFaces();
2073 forAll(pointFaces, pointI)
2075 if (pointBaffle[pointI] != -1)
2077 const labelList& pFaces = pointFaces[pointI];
2079 forAll(pFaces, pFaceI)
2081 label faceI = pFaces[pFaceI];
2083 if (ownPatch[faceI] == -1)
2085 ownPatch[faceI] = pointBaffle[pointI];
2090 syncTools::syncFaceList(mesh_, ownPatch, maxEqOp<label>());
2093 // 3. From faces to cells (cellRegion) and back to faces (ownPatch)
2095 labelList newOwnPatch(ownPatch);
2097 forAll(ownPatch, faceI)
2099 if (ownPatch[faceI] != -1)
2101 label own = faceOwner[faceI];
2103 if (cellRegion[own] != keepRegionI)
2105 cellRegion[own] = keepRegionI;
2107 const cell& ownFaces = mesh_.cells()[own];
2110 if (ownPatch[ownFaces[j]] == -1)
2112 newOwnPatch[ownFaces[j]] = ownPatch[faceI];
2116 if (mesh_.isInternalFace(faceI))
2118 label nei = faceNeighbour[faceI];
2120 if (cellRegion[nei] != keepRegionI)
2122 cellRegion[nei] = keepRegionI;
2124 const cell& neiFaces = mesh_.cells()[nei];
2127 if (ownPatch[neiFaces[j]] == -1)
2129 newOwnPatch[neiFaces[j]] = ownPatch[faceI];
2137 ownPatch.transfer(newOwnPatch);
2139 syncTools::syncFaceList(mesh_, ownPatch, maxEqOp<label>());
2147 // Get cells to remove
2148 DynamicList<label> cellsToRemove(mesh_.nCells());
2149 forAll(cellRegion, cellI)
2151 if (cellRegion[cellI] != keepRegionI)
2153 cellsToRemove.append(cellI);
2156 cellsToRemove.shrink();
2158 label nCellsToKeep = mesh_.nCells() - cellsToRemove.size();
2159 reduce(nCellsToKeep, sumOp<label>());
2161 Info<< "Keeping all cells in region " << keepRegionI
2162 << " containing point " << keepPoint << endl
2163 << "Selected for keeping : " << nCellsToKeep
2164 << " cells." << endl;
2168 removeCells cellRemover(mesh_);
2170 // Pick up patches for exposed faces
2171 labelList exposedFaces(cellRemover.getExposedFaces(cellsToRemove));
2172 labelList exposedPatches(exposedFaces.size());
2174 forAll(exposedFaces, i)
2176 label faceI = exposedFaces[i];
2178 if (ownPatch[faceI] != -1)
2180 exposedPatches[i] = ownPatch[faceI];
2184 WarningIn("meshRefinement::splitMesh(..)")
2185 << "For exposed face " << faceI
2186 << " fc:" << mesh_.faceCentres()[faceI]
2187 << " found no patch." << endl
2188 << " Taking patch " << defaultPatch
2189 << " instead." << endl;
2190 exposedPatches[i] = defaultPatch;
2194 return doRemoveCells
2204 // Find boundary points that connect to more than one cell region and
2206 Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::dupNonManifoldPoints()
2208 // Topochange container
2209 polyTopoChange meshMod(mesh_);
2212 // Analyse which points need to be duplicated
2213 localPointRegion regionSide(mesh_);
2215 label nNonManifPoints = returnReduce
2217 regionSide.meshPointMap().size(),
2221 Info<< "dupNonManifoldPoints : Found : " << nNonManifPoints
2222 << " non-manifold points (out of "
2223 << mesh_.globalData().nTotalPoints()
2226 // Topo change engine
2227 duplicatePoints pointDuplicator(mesh_);
2229 // Insert changes into meshMod
2230 pointDuplicator.setRefinement(regionSide, meshMod);
2232 // Change the mesh (no inflation, parallel sync)
2233 autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true);
2236 mesh_.updateMesh(map);
2238 // Move mesh if in inflation mode
2239 if (map().hasMotionPoints())
2241 mesh_.movePoints(map().preMotionPoints());
2245 // Delete mesh volumes.
2249 // Reset the instance for if in overwrite mode
2250 mesh_.setInstance(timeName());
2252 // Update intersections. Is mapping only (no faces created, positions stay
2253 // same) so no need to recalculate intersections.
2254 updateMesh(map, labelList(0));
2261 Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify
2263 const point& keepPoint,
2264 const bool allowFreeStandingZoneFaces
2267 const wordList& cellZoneNames = surfaces_.cellZoneNames();
2268 const wordList& faceZoneNames = surfaces_.faceZoneNames();
2270 labelList namedSurfaces(surfaces_.getNamedSurfaces());
2272 forAll(namedSurfaces, i)
2274 label surfI = namedSurfaces[i];
2276 Info<< "Surface : " << surfaces_.names()[surfI] << nl
2277 << " faceZone : " << faceZoneNames[surfI] << nl
2278 << " cellZone : " << cellZoneNames[surfI] << endl;
2282 // Add zones to mesh
2284 labelList surfaceToFaceZone(faceZoneNames.size(), -1);
2286 faceZoneMesh& faceZones = mesh_.faceZones();
2288 forAll(namedSurfaces, i)
2290 label surfI = namedSurfaces[i];
2292 label zoneI = faceZones.findZoneID(faceZoneNames[surfI]);
2296 zoneI = faceZones.size();
2297 faceZones.setSize(zoneI+1);
2303 faceZoneNames[surfI], //name
2304 labelList(0), //addressing
2305 boolList(0), //flipmap
2307 faceZones //faceZoneMesh
2314 Pout<< "Faces on " << surfaces_.names()[surfI]
2315 << " will go into faceZone " << zoneI << endl;
2317 surfaceToFaceZone[surfI] = zoneI;
2320 // Check they are synced
2321 List<wordList> allFaceZones(Pstream::nProcs());
2322 allFaceZones[Pstream::myProcNo()] = faceZones.names();
2323 Pstream::gatherList(allFaceZones);
2324 Pstream::scatterList(allFaceZones);
2326 for (label procI = 1; procI < allFaceZones.size(); procI++)
2328 if (allFaceZones[procI] != allFaceZones[0])
2332 "meshRefinement::zonify"
2333 "(const label, const point&)"
2334 ) << "Zones not synchronised among processors." << nl
2335 << " Processor0 has faceZones:" << allFaceZones[0]
2336 << " , processor" << procI
2337 << " has faceZones:" << allFaceZones[procI]
2338 << exit(FatalError);
2343 labelList surfaceToCellZone(cellZoneNames.size(), -1);
2345 cellZoneMesh& cellZones = mesh_.cellZones();
2347 forAll(namedSurfaces, i)
2349 label surfI = namedSurfaces[i];
2351 if (cellZoneNames[surfI] != word::null)
2353 label zoneI = cellZones.findZoneID(cellZoneNames[surfI]);
2357 zoneI = cellZones.size();
2358 cellZones.setSize(zoneI+1);
2364 cellZoneNames[surfI], //name
2365 labelList(0), //addressing
2367 cellZones //cellZoneMesh
2374 Pout<< "Cells inside " << surfaces_.names()[surfI]
2375 << " will go into cellZone " << zoneI << endl;
2377 surfaceToCellZone[surfI] = zoneI;
2381 // Check they are synced
2382 List<wordList> allCellZones(Pstream::nProcs());
2383 allCellZones[Pstream::myProcNo()] = cellZones.names();
2384 Pstream::gatherList(allCellZones);
2385 Pstream::scatterList(allCellZones);
2387 for (label procI = 1; procI < allCellZones.size(); procI++)
2389 if (allCellZones[procI] != allCellZones[0])
2393 "meshRefinement::zonify"
2394 "(const label, const point&)"
2395 ) << "Zones not synchronised among processors." << nl
2396 << " Processor0 has cellZones:" << allCellZones[0]
2397 << " , processor" << procI
2398 << " has cellZones:" << allCellZones[procI]
2399 << exit(FatalError);
2406 const pointField& cellCentres = mesh_.cellCentres();
2407 const labelList& faceOwner = mesh_.faceOwner();
2408 const labelList& faceNeighbour = mesh_.faceNeighbour();
2409 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
2412 // Mark faces intersecting zoned surfaces
2413 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2416 // Like surfaceIndex_ but only for named surfaces.
2417 labelList namedSurfaceIndex(mesh_.nFaces(), -1);
2420 // Statistics: number of faces per faceZone
2421 labelList nSurfFaces(faceZoneNames.size(), 0);
2423 // Swap neighbouring cell centres and cell level
2424 labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
2425 pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
2426 calcNeighbourData(neiLevel, neiCc);
2428 // Note: for all internal faces? internal + coupled?
2429 // Since zonify is run after baffling the surfaceIndex_ on baffles is
2430 // not synchronised across both baffle faces. Fortunately we don't
2431 // do zonify baffle faces anyway (they are normal boundary faces).
2433 // Collect candidate faces
2434 // ~~~~~~~~~~~~~~~~~~~~~~~
2436 labelList testFaces(intersectedFaces());
2441 pointField start(testFaces.size());
2442 pointField end(testFaces.size());
2444 forAll(testFaces, i)
2446 label faceI = testFaces[i];
2448 if (mesh_.isInternalFace(faceI))
2450 start[i] = cellCentres[faceOwner[faceI]];
2451 end[i] = cellCentres[faceNeighbour[faceI]];
2455 start[i] = cellCentres[faceOwner[faceI]];
2456 end[i] = neiCc[faceI-mesh_.nInternalFaces()];
2460 // Extend segments a bit
2462 const vectorField smallVec(Foam::sqrt(SMALL)*(end-start));
2468 // Do test for intersections
2469 // ~~~~~~~~~~~~~~~~~~~~~~~~~
2470 // Note that we intersect all intersected faces again. Could reuse
2471 // the information already in surfaceIndex_.
2476 List<pointIndexHit> hit1;
2478 List<pointIndexHit> hit2;
2480 surfaces_.findNearestIntersection
2495 forAll(testFaces, i)
2497 label faceI = testFaces[i];
2499 if (surface1[i] != -1)
2501 // If both hit should probably choose nearest. For later.
2502 namedSurfaceIndex[faceI] = surface1[i];
2503 nSurfFaces[surface1[i]]++;
2505 else if (surface2[i] != -1)
2507 namedSurfaceIndex[faceI] = surface2[i];
2508 nSurfFaces[surface2[i]]++;
2513 // surfaceIndex migh have different surfaces on both sides if
2514 // there happen to be a (obviously thin) surface with different
2515 // regions between the cell centres. If one is on a named surface
2516 // and the other is not this might give problems so sync.
2517 syncTools::syncFaceList
2527 forAll(nSurfFaces, surfI)
2530 << surfaces_.names()[surfI]
2531 << " nZoneFaces:" << nSurfFaces[surfI] << nl;
2538 // Put the cells into the correct zone
2539 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2543 // -1 : not in any zone
2545 labelList cellToZone(mesh_.nCells(), -2);
2548 // Set using geometric test
2549 // ~~~~~~~~~~~~~~~~~~~~~~~~
2551 // Closed surfaces with cellZone specified.
2552 labelList closedNamedSurfaces(surfaces_.getClosedNamedSurfaces());
2554 if (closedNamedSurfaces.size())
2556 Info<< "Found " << closedNamedSurfaces.size()
2557 << " closed, named surfaces. Assigning cells in/outside"
2558 << " these surfaces to the corresponding cellZone."
2561 findCellZoneGeometric
2563 closedNamedSurfaces, // indices of closed surfaces
2564 namedSurfaceIndex, // per face index of named surface
2565 surfaceToCellZone, // cell zone index per surface
2572 // Set using provided locations
2573 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2575 labelList locationSurfaces(surfaces_.getInsidePointNamedSurfaces());
2576 if (locationSurfaces.size())
2578 Info<< "Found " << locationSurfaces.size()
2579 << " named surfaces with a provided inside point."
2580 << " Assigning cells inside these surfaces"
2581 << " to the corresponding cellZone."
2584 findCellZoneInsideWalk
2586 locationSurfaces, // indices of closed surfaces
2587 namedSurfaceIndex, // per face index of named surface
2588 surfaceToCellZone, // cell zone index per surface
2595 // Set using walking
2596 // ~~~~~~~~~~~~~~~~~
2599 Info<< "Walking from location-in-mesh " << keepPoint
2600 << " to assign cellZones "
2601 << "- crossing a faceZone face changes cellZone" << nl << endl;
2615 // Make sure namedSurfaceIndex is unset inbetween same cell cell zones.
2616 if (!allowFreeStandingZoneFaces)
2618 Info<< "Only keeping zone faces inbetween different cellZones."
2621 makeConsistentFaceIndex(cellToZone, namedSurfaceIndex);
2624 // Topochange container
2625 polyTopoChange meshMod(mesh_);
2628 // Put the faces into the correct zone
2629 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2631 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
2633 label surfI = namedSurfaceIndex[faceI];
2637 // Orient face zone to have slave cells in max cell zone.
2638 label ownZone = cellToZone[faceOwner[faceI]];
2639 label neiZone = cellToZone[faceNeighbour[faceI]];
2642 if (ownZone == max(ownZone, neiZone))
2655 mesh_.faces()[faceI], // modified face
2656 faceI, // label of face
2657 faceOwner[faceI], // owner
2658 faceNeighbour[faceI], // neighbour
2660 -1, // patch for face
2661 false, // remove from zone
2662 surfaceToFaceZone[surfI], // zone for face
2663 flip // face flip in zone
2669 // Get coupled neighbour cellZone. Set to -1 on non-coupled patches.
2670 labelList neiCellZone(mesh_.nFaces()-mesh_.nInternalFaces(), -1);
2671 forAll(patches, patchI)
2673 const polyPatch& pp = patches[patchI];
2679 label faceI = pp.start()+i;
2680 neiCellZone[faceI-mesh_.nInternalFaces()] =
2681 cellToZone[mesh_.faceOwner()[faceI]];
2685 syncTools::swapBoundaryFaceList(mesh_, neiCellZone);
2687 // Get per face whether is it master (of a coupled set of faces)
2688 PackedBoolList isMasterFace(syncTools::getMasterFaces(mesh_));
2690 // Set owner as no-flip
2691 forAll(patches, patchI)
2693 const polyPatch& pp = patches[patchI];
2695 label faceI = pp.start();
2699 label surfI = namedSurfaceIndex[faceI];
2703 label ownZone = cellToZone[faceOwner[faceI]];
2704 label neiZone = neiCellZone[faceI-mesh_.nInternalFaces()];
2708 label maxZone = max(ownZone, neiZone);
2714 else if (ownZone == neiZone)
2716 // Free-standing zone face or coupled boundary. Keep master
2718 flip = !isMasterFace[faceI];
2720 else if (neiZone == maxZone)
2733 mesh_.faces()[faceI], // modified face
2734 faceI, // label of face
2735 faceOwner[faceI], // owner
2738 patchI, // patch for face
2739 false, // remove from zone
2740 surfaceToFaceZone[surfI], // zone for face
2741 flip // face flip in zone
2750 // Put the cells into the correct zone
2751 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2753 forAll(cellToZone, cellI)
2755 label zoneI = cellToZone[cellI];
2764 false, // removeFromZone
2771 // Change the mesh (no inflation, parallel sync)
2772 autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true);
2775 mesh_.updateMesh(map);
2777 // Move mesh if in inflation mode
2778 if (map().hasMotionPoints())
2780 mesh_.movePoints(map().preMotionPoints());
2784 // Delete mesh volumes.
2788 // Reset the instance for if in overwrite mode
2789 mesh_.setInstance(timeName());
2791 // Print some stats (note: zones are synchronised)
2792 if (mesh_.cellZones().size() > 0)
2794 Info<< "CellZones:" << endl;
2795 forAll(mesh_.cellZones(), zoneI)
2797 const cellZone& cz = mesh_.cellZones()[zoneI];
2798 Info<< " " << cz.name()
2799 << "\tsize:" << returnReduce(cz.size(), sumOp<label>())
2804 if (mesh_.faceZones().size() > 0)
2806 Info<< "FaceZones:" << endl;
2807 forAll(mesh_.faceZones(), zoneI)
2809 const faceZone& fz = mesh_.faceZones()[zoneI];
2810 Info<< " " << fz.name()
2811 << "\tsize:" << returnReduce(fz.size(), sumOp<label>())
2817 // None of the faces has changed, only the zones. Still...
2818 updateMesh(map, labelList());
2824 // ************************************************************************* //