1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend 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 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
26 \*---------------------------------------------------------------------------*/
28 #include "cellClassification.H"
29 #include "triSurfaceSearch.H"
30 #include "indexedOctree.H"
31 #include "treeDataFace.H"
32 #include "meshSearch.H"
37 #include "meshTools.H"
39 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
43 defineTypeNameAndDebug(cellClassification, 0);
47 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
49 Foam::label Foam::cellClassification::count
51 const labelList& elems,
59 if (elems[elemI] == elem)
68 // Mark all faces that are cut by the surface. Two pass:
69 // Pass1: mark all mesh edges that intersect surface (quick since triangle
71 // Pass2: Check for all point neighbours of these faces whether any of their
73 Foam::boolList Foam::cellClassification::markFaces
75 const triSurfaceSearch& search
80 boolList cutFace(mesh_.nFaces(), false);
84 // Intersect mesh edges with surface (is fast) and mark all faces that
87 forAll(mesh_.edges(), edgeI)
89 if (debug && (edgeI % 10000 == 0))
91 Pout<< "Intersecting mesh edge " << edgeI << " with surface"
95 const edge& e = mesh_.edges()[edgeI];
97 const point& p0 = mesh_.points()[e.start()];
98 const point& p1 = mesh_.points()[e.end()];
100 pointIndexHit pHit(search.tree().findLineAny(p0, p1));
104 const labelList& myFaces = mesh_.edgeFaces()[edgeI];
106 forAll(myFaces, myFaceI)
108 label faceI = myFaces[myFaceI];
112 cutFace[faceI] = true;
122 Pout<< "Intersected edges of mesh with surface in = "
123 << timer.cpuTimeIncrement() << " s\n" << endl << endl;
127 // Construct octree on faces that have not yet been marked as cut
130 labelList allFaces(mesh_.nFaces() - nCutFaces);
134 forAll(cutFace, faceI)
138 allFaces[allFaceI++] = faceI;
144 Pout<< "Testing " << allFaceI << " faces for piercing by surface"
148 treeBoundBox allBb(mesh_.points());
150 // Extend domain slightly (also makes it 3D if was 2D)
151 scalar tol = 1e-6*allBb.avgDim();
153 point& bbMin = allBb.min();
158 point& bbMax = allBb.max();
163 indexedOctree<treeDataFace> faceTree
165 treeDataFace(false, mesh_, allFaces),
166 allBb, // overall search domain
172 const triSurface& surf = search.surface();
173 const edgeList& edges = surf.edges();
174 const pointField& localPoints = surf.localPoints();
180 if (debug && (edgeI % 10000 == 0))
182 Pout<< "Intersecting surface edge " << edgeI
183 << " with mesh faces" << endl;
185 const edge& e = edges[edgeI];
187 const point& start = localPoints[e.start()];
188 const point& end = localPoints[e.end()];
190 vector edgeNormal(end - start);
191 const scalar edgeMag = mag(edgeNormal);
192 const vector smallVec = 1E-9*edgeNormal;
194 edgeNormal /= edgeMag+VSMALL;
196 // Current start of pierce test
201 pointIndexHit pHit(faceTree.findLine(pt, end));
209 label faceI = faceTree.shapes().faceLabels()[pHit.index()];
213 cutFace[faceI] = true;
218 // Restart from previous endpoint
219 pt = pHit.hitPoint() + smallVec;
221 if (((pt-start) & edgeNormal) >= edgeMag)
231 Pout<< "Detected an additional " << nAddFaces << " faces cut"
234 Pout<< "Intersected edges of surface with mesh faces in = "
235 << timer.cpuTimeIncrement() << " s\n" << endl << endl;
242 // Determine faces cut by surface and use to divide cells into types. See
243 // cellInfo. All cells reachable from outsidePts are considered to be of type
245 void Foam::cellClassification::markCells
247 const meshSearch& queryMesh,
248 const boolList& piercedFace,
249 const pointField& outsidePts
252 // Use meshwave to partition mesh, starting from outsidePt
255 // Construct null; sets type to NOTSET
256 List<cellInfo> cellInfoList(mesh_.nCells());
258 // Mark cut cells first
259 forAll(piercedFace, faceI)
261 if (piercedFace[faceI])
263 cellInfoList[mesh_.faceOwner()[faceI]] =
264 cellInfo(cellClassification::CUT);
266 if (mesh_.isInternalFace(faceI))
268 cellInfoList[mesh_.faceNeighbour()[faceI]] =
269 cellInfo(cellClassification::CUT);
275 // Mark cells containing outside points as being outside
278 // Coarse guess number of faces
279 labelHashSet outsideFacesMap(outsidePts.size() * 6 * 2);
281 forAll(outsidePts, outsidePtI)
283 // Use linear search for points.
284 label cellI = queryMesh.findCell(outsidePts[outsidePtI], -1, false);
290 "List<cellClassification::cType> markCells"
291 "(const meshSearch&, const boolList&, const pointField&)"
292 ) << "outsidePoint " << outsidePts[outsidePtI]
293 << " is not inside any cell"
294 << nl << "It might be on a face or outside the geometry"
298 cellInfoList[cellI] = cellInfo(cellClassification::OUTSIDE);
300 // Mark faces of cellI
301 const labelList& myFaces = mesh_.cells()[cellI];
302 forAll(myFaces, myFaceI)
304 outsideFacesMap.insert(myFaces[myFaceI]);
310 // Mark faces to start wave from
313 labelList changedFaces(outsideFacesMap.toc());
315 List<cellInfo> changedFacesInfo
318 cellInfo(cellClassification::OUTSIDE)
321 MeshWave<cellInfo> cellInfoCalc
324 changedFaces, // Labels of changed faces
325 changedFacesInfo, // Information on changed faces
326 cellInfoList, // Information on all cells
327 mesh_.globalData().nTotalCells() // max iterations
330 // Get information out of cellInfoList
331 const List<cellInfo>& allInfo = cellInfoCalc.allCellInfo();
333 forAll(allInfo, cellI)
335 label t = allInfo[cellI].type();
337 if (t == cellClassification::NOTSET)
339 t = cellClassification::INSIDE;
341 operator[](cellI) = t;
346 void Foam::cellClassification::classifyPoints
348 const label meshType,
349 const labelList& cellType,
350 List<pointStatus>& pointSide
353 pointSide.setSize(mesh_.nPoints());
355 forAll(mesh_.pointCells(), pointI)
357 const labelList& pCells = mesh_.pointCells()[pointI];
359 pointSide[pointI] = UNSET;
363 label type = cellType[pCells[i]];
365 if (type == meshType)
367 if (pointSide[pointI] == UNSET)
369 pointSide[pointI] = MESH;
371 else if (pointSide[pointI] == NONMESH)
373 pointSide[pointI] = MIXED;
380 if (pointSide[pointI] == UNSET)
382 pointSide[pointI] = NONMESH;
384 else if (pointSide[pointI] == MESH)
386 pointSide[pointI] = MIXED;
396 bool Foam::cellClassification::usesMixedPointsOnly
398 const List<pointStatus>& pointSide,
402 const faceList& faces = mesh_.faces();
404 const cell& cFaces = mesh_.cells()[cellI];
406 forAll(cFaces, cFaceI)
408 const face& f = faces[cFaces[cFaceI]];
412 if (pointSide[f[fp]] != MIXED)
419 // All points are mixed.
424 void Foam::cellClassification::getMeshOutside
426 const label meshType,
427 faceList& outsideFaces,
428 labelList& outsideOwner
431 const labelList& own = mesh_.faceOwner();
432 const labelList& nbr = mesh_.faceNeighbour();
433 const faceList& faces = mesh_.faces();
435 outsideFaces.setSize(mesh_.nFaces());
436 outsideOwner.setSize(mesh_.nFaces());
439 // Get faces on interface between meshType and non-meshType
441 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
443 label ownType = operator[](own[faceI]);
444 label nbrType = operator[](nbr[faceI]);
446 if (ownType == meshType && nbrType != meshType)
448 outsideFaces[outsideI] = faces[faceI];
449 outsideOwner[outsideI] = own[faceI]; // meshType cell
452 else if (ownType != meshType && nbrType == meshType)
454 outsideFaces[outsideI] = faces[faceI];
455 outsideOwner[outsideI] = nbr[faceI]; // meshType cell
460 // Get faces on outside of real mesh with cells of meshType.
462 for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++)
464 if (operator[](own[faceI]) == meshType)
466 outsideFaces[outsideI] = faces[faceI];
467 outsideOwner[outsideI] = own[faceI]; // meshType cell
471 outsideFaces.setSize(outsideI);
472 outsideOwner.setSize(outsideI);
476 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
478 // Construct from mesh and surface and point(s) on outside
479 Foam::cellClassification::cellClassification
481 const polyMesh& mesh,
482 const meshSearch& meshQuery,
483 const triSurfaceSearch& surfQuery,
484 const pointField& outsidePoints
487 labelList(mesh.nCells(), cellClassification::NOTSET),
493 markFaces(surfQuery),
499 // Construct from mesh and meshType.
500 Foam::cellClassification::cellClassification
502 const polyMesh& mesh,
503 const labelList& cellType
509 if (mesh_.nCells() != size())
513 "cellClassification::cellClassification"
514 "(const polyMesh&, const labelList&)"
515 ) << "Number of elements of cellType argument is not equal to the"
516 << " number of cells" << abort(FatalError);
522 Foam::cellClassification::cellClassification(const cellClassification& cType)
529 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
532 // Makes cutCells further than nLayers away from meshType to
533 // fillType. Returns number of cells changed.
534 Foam::label Foam::cellClassification::trimCutCells
537 const label meshType,
541 // Temporary cell type for growing.
542 labelList newCellType(*this);
544 // // Split types into outside and rest
545 // forAll(*this, cellI)
547 // label type = operator[](cellI);
549 // if (type == meshType)
551 // newCellType[cellI] = type;
555 // newCellType[cellI] = fillType;
562 // Do point-cell-point walk on newCellType out from meshType cells
563 for (label iter = 0; iter < nLayers; iter++)
565 // Get status of points: visible from meshType (pointSide == MESH)
566 // or fillType/cutCells cells (pointSide == NONMESH) or
567 // both (pointSide == MIXED)
568 List<pointStatus> pointSide(mesh_.nPoints());
569 classifyPoints(meshType, newCellType, pointSide);
571 // Grow layer of outside cells
572 forAll(pointSide, pointI)
574 if (pointSide[pointI] == MIXED)
577 const labelList& pCells = mesh_.pointCells()[pointI];
581 label type = newCellType[pCells[i]];
583 if (type == cellClassification::CUT)
585 // Found cut cell sharing point with
586 // mesh type cell. Grow.
587 newCellType[pCells[i]] = meshType;
594 // Merge newCellType into *this:
595 // - leave meshType cells intact
596 // - leave nonMesh cells intact
597 // - make cutcells fillType if they were not marked in newCellType
601 forAll(newCellType, cellI)
603 if (operator[](cellI) == cellClassification::CUT)
605 if (newCellType[cellI] != meshType)
607 // Cell was cutCell but further than nLayers away from
608 // meshType. Convert to fillType.
609 operator[](cellI) = fillType;
619 // Grow surface by pointNeighbours of type meshType
620 Foam::label Foam::cellClassification::growSurface
622 const label meshType,
626 boolList hasMeshType(mesh_.nPoints(), false);
628 // Mark points used by meshType cells
630 forAll(mesh_.pointCells(), pointI)
632 const labelList& myCells = mesh_.pointCells()[pointI];
634 // Check if one of cells has meshType
635 forAll(myCells, myCellI)
637 label type = operator[](myCells[myCellI]);
639 if (type == meshType)
641 hasMeshType[pointI] = true;
648 // Change neighbours of marked points
652 forAll(hasMeshType, pointI)
654 if (hasMeshType[pointI])
656 const labelList& myCells = mesh_.pointCells()[pointI];
658 forAll(myCells, myCellI)
660 if (operator[](myCells[myCellI]) != meshType)
662 operator[](myCells[myCellI]) = fillType;
673 // Check all points used by cells of meshType for use of at least one point
674 // which is not on the outside. If all points are on the outside of the mesh
675 // this would probably result in a flattened cell when projecting the cell
677 Foam::label Foam::cellClassification::fillHangingCells
679 const label meshType,
680 const label fillType,
684 label nTotChanged = 0;
686 for(label iter = 0; iter < maxIter; iter++)
690 // Get status of points: visible from meshType or non-meshType cells
691 List<pointStatus> pointSide(mesh_.nPoints());
692 classifyPoints(meshType, *this, pointSide);
694 // Check all cells using mixed point type for whether they use mixed
695 // points only. Note: could probably speed this up by counting number
696 // of mixed verts per face and mixed faces per cell or something?
697 forAll(pointSide, pointI)
699 if (pointSide[pointI] == MIXED)
701 const labelList& pCells = mesh_.pointCells()[pointI];
705 label cellI = pCells[i];
707 if (operator[](cellI) == meshType)
709 if (usesMixedPointsOnly(pointSide, cellI))
711 operator[](cellI) = fillType;
719 nTotChanged += nChanged;
721 Pout<< "removeHangingCells : changed " << nChanged
722 << " hanging cells" << endl;
734 Foam::label Foam::cellClassification::fillRegionEdges
736 const label meshType,
737 const label fillType,
741 label nTotChanged = 0;
743 for(label iter = 0; iter < maxIter; iter++)
745 // Get interface between meshType cells and non-meshType cells as a list
746 // of faces and for each face the cell which is the meshType.
747 faceList outsideFaces;
748 labelList outsideOwner;
750 getMeshOutside(meshType, outsideFaces, outsideOwner);
752 // Build primitivePatch out of it and check it for problems.
753 primitiveFacePatch fp(outsideFaces, mesh_.points());
755 const labelListList& edgeFaces = fp.edgeFaces();
759 // Check all edgeFaces for non-manifoldness
761 forAll(edgeFaces, edgeI)
763 const labelList& eFaces = edgeFaces[edgeI];
765 if (eFaces.size() > 2)
767 // patch connected through pinched edge. Remove first face using
768 // edge (and not yet changed)
772 label patchFaceI = eFaces[i];
774 label ownerCell = outsideOwner[patchFaceI];
776 if (operator[](ownerCell) == meshType)
778 operator[](ownerCell) = fillType;
788 nTotChanged += nChanged;
790 Pout<< "fillRegionEdges : changed " << nChanged
791 << " cells using multiply connected edges" << endl;
803 Foam::label Foam::cellClassification::fillRegionPoints
805 const label meshType,
806 const label fillType,
810 label nTotChanged = 0;
812 for(label iter = 0; iter < maxIter; iter++)
814 // Get interface between meshType cells and non-meshType cells as a list
815 // of faces and for each face the cell which is the meshType.
816 faceList outsideFaces;
817 labelList outsideOwner;
819 getMeshOutside(meshType, outsideFaces, outsideOwner);
821 // Build primitivePatch out of it and check it for problems.
822 primitiveFacePatch fp(outsideFaces, mesh_.points());
824 labelHashSet nonManifoldPoints;
826 // Check for non-manifold points.
827 fp.checkPointManifold(false, &nonManifoldPoints);
829 const Map<label>& meshPointMap = fp.meshPointMap();
835 labelHashSet::const_iterator iter = nonManifoldPoints.begin();
836 iter != nonManifoldPoints.end();
840 // Find a face on fp using point and remove it.
841 label patchPointI = meshPointMap[iter.key()];
843 const labelList& pFaces = fp.pointFaces()[patchPointI];
845 // Remove any face using conflicting point. Does first face which
846 // has not yet been done. Could be more intelligent and decide which
847 // one would be best to remove.
850 label patchFaceI = pFaces[i];
852 label ownerCell = outsideOwner[patchFaceI];
854 if (operator[](ownerCell) == meshType)
856 operator[](ownerCell) = fillType;
865 nTotChanged += nChanged;
867 Pout<< "fillRegionPoints : changed " << nChanged
868 << " cells using multiply connected points" << endl;
880 void Foam::cellClassification::writeStats(Ostream& os) const
882 os << "Cells:" << size() << endl
883 << " notset : " << count(*this, NOTSET) << endl
884 << " cut : " << count(*this, CUT) << endl
885 << " inside : " << count(*this, INSIDE) << endl
886 << " outside : " << count(*this, OUTSIDE) << endl;
890 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
892 void Foam::cellClassification::operator=(const Foam::cellClassification& rhs)
894 labelList::operator=(rhs);
898 // ************************************************************************* //