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 "topoCellLooper.H"
27 #include "cellFeatures.H"
29 #include "unitConversion.H"
30 #include "DynamicList.H"
32 #include "meshTools.H"
33 #include "hexMatcher.H"
35 #include "addToRunTimeSelectionTable.H"
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
41 defineTypeNameAndDebug(topoCellLooper, 0);
42 addToRunTimeSelectionTable(cellLooper, topoCellLooper, word);
45 // Angle for polys to be considered splitHexes.
46 const Foam::scalar Foam::topoCellLooper::featureCos = Foam::cos(degToRad(10.0));
49 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
51 // In-memory truncate a list
53 void Foam::topoCellLooper::subsetList
62 // Truncate (setSize decides itself not to do anything if nothing
66 FatalErrorIn("topoCellLooper::subsetList")
67 << "startI:" << startI << " freeI:" << freeI
68 << " lst:" << lst << abort(FatalError);
70 lst.setCapacity(freeI);
74 // Shift elements down
76 for (label elemI = startI; elemI < freeI; elemI++)
78 lst[newI++] = lst[elemI];
81 if ((freeI - startI) < 0)
83 FatalErrorIn("topoCellLooper::subsetList")
84 << "startI:" << startI << " freeI:" << freeI
85 << " lst:" << lst << abort(FatalError);
88 lst.setCapacity(freeI - startI);
93 // Returns label of edge nFeaturePts away from startEdge (in the direction of
94 // startVertI) and not counting non-featurePoints.
96 // When stepping to this face it can happen in 3 different ways:
106 // A: jumping from face0 to face1 across edge A.
118 // B: jumping from face0 to face1 across (non-feature) point B
130 // C: jumping from face0 to face1 across (feature) point C on edge.
134 void Foam::topoCellLooper::walkFace
136 const cellFeatures& features,
138 const label startEdgeI,
139 const label startVertI,
140 const label nFeaturePts,
146 const labelList& fEdges = mesh().faceEdges()[faceI];
152 // Number of feature points crossed so far
157 // Started on edge. Go to one of its endpoints.
158 vertI = mesh().edges()[edgeI].start();
160 if (features.isFeatureVertex(faceI, vertI))
166 if ((edgeI == -1) || !meshTools::edgeOnFace(mesh(), faceI, edgeI))
168 // Either edge is not set or not on current face. Just take one of
169 // the edges on this face as starting edge.
170 edgeI = getFirstVertEdge(faceI, vertI);
173 // Now we should have starting edge on face and a vertex on that edge.
178 edgeI = meshTools::otherEdge(mesh(), fEdges, edgeI, vertI);
180 if (nVisited == nFeaturePts)
185 vertI = mesh().edges()[edgeI].otherVertex(vertI);
187 if (features.isFeatureVertex(faceI, vertI))
196 // Returns list of vertices on 'superEdge' i.e. list of edges connected by
197 // non-feature points. First and last are feature points, ones inbetween are
199 Foam::labelList Foam::topoCellLooper::getSuperEdge
201 const cellFeatures& features,
203 const label startEdgeI,
204 const label startVertI
207 const labelList& fEdges = mesh().faceEdges()[faceI];
209 labelList superVerts(fEdges.size());
210 label superVertI = 0;
213 label edgeI = startEdgeI;
215 label vertI = startVertI;
217 superVerts[superVertI++] = vertI;
219 label prevEdgeI = -1;
223 vertI = mesh().edges()[edgeI].otherVertex(vertI);
225 superVerts[superVertI++] = vertI;
229 edgeI = meshTools::otherEdge(mesh(), fEdges, edgeI, vertI);
231 while (!features.isFeaturePoint(prevEdgeI, edgeI));
233 superVerts.setSize(superVertI);
239 // Return non-feature edge from cells' edges that is most perpendicular
240 // to refinement direction.
241 Foam::label Foam::topoCellLooper::getAlignedNonFeatureEdge
243 const vector& refDir,
245 const cellFeatures& features
248 const labelList& cEdges = mesh().cellEdges()[cellI];
250 const point& ctr = mesh().cellCentres()[cellI];
253 scalar maxCos = -GREAT;
255 forAll(cEdges, cEdgeI)
257 label edgeI = cEdges[cEdgeI];
259 if (!features.isFeatureEdge(edgeI))
261 const edge& e = mesh().edges()[edgeI];
263 // Get plane spanned by e.start, e.end and cell centre.
264 vector e0 = mesh().points()[e.start()] - ctr;
265 vector e1 = mesh().points()[e.end()] - ctr;
270 scalar cosAngle = mag(refDir & n);
272 if (cosAngle > maxCos)
285 // Starts from edge and vertex on edge on face (or neighbouring face)
286 // and steps either to existing vertex (vertI != -1) or to edge (vertI == -1)
287 // by walking point-edge and crossing nFeats featurePoints.
288 void Foam::topoCellLooper::walkAcrossFace
290 const cellFeatures& features,
292 const label startEdgeI,
293 const label startVertI,
300 label oppositeVertI = -1;
301 label oppositeEdgeI = -1;
303 // Go to oppositeEdge and a vertex on that.
316 // Loop over super edge to find internal points if there are any.
318 labelList superEdge =
327 label sz = superEdge.size();
331 // No non-feature point inbetween feature points.
335 edgeI = oppositeEdgeI;
339 vertI = superEdge[1];
344 //Should choose acc. to geometry!
349 Pout<< " Don't know what to do. Stepped to non-feature point "
350 << "at index " << index << " in superEdge:" << superEdge
354 vertI = superEdge[index];
360 // Walks cell circumference. Updates face, edge, vertex.
362 // Position on face is given by:
364 // vertI == -1, faceI != -1, edgeI != -1
365 // on edge of face. Cross edge to neighbouring face.
367 // vertI != -1, edgeI != -1, faceI == -1
368 // coming from edge onto vertex vertI. Need to step to one
369 // of the faces not using edgeI.
371 // vertI != -1, edgeI == -1, faceI != -1
372 // coming from vertex on side of face. Step to one of the faces
373 // using vertI but not faceI
374 void Foam::topoCellLooper::walkSplitHex
377 const cellFeatures& features,
378 const label fromFaceI,
379 const label fromEdgeI,
380 const label fromVertI,
382 DynamicList<label>& loop,
383 DynamicList<scalar>& loopWeights
386 // Work vars giving position on cell
387 label faceI = fromFaceI;
388 label edgeI = fromEdgeI;
389 label vertI = fromVertI;
395 Pout<< "Entering walk with : cell:" << cellI << " face:" << faceI;
398 Pout<< " verts:" << mesh().faces()[faceI];
400 Pout<< " edge:" << edgeI;
403 Pout<< " verts:" << mesh().edges()[edgeI];
405 Pout<< " vert:" << vertI << endl;
408 label startLoop = -1;
425 // Breaking walk since vertI already cut
426 label firstFree = loop.size();
428 subsetList(startLoop, firstFree, loop);
429 subsetList(startLoop, firstFree, loopWeights);
448 // Breaking walk since edgeI already cut
449 label firstFree = loop.size();
451 subsetList(startLoop, firstFree, loop);
452 subsetList(startLoop, firstFree, loopWeights);
463 FatalErrorIn("walkSplitHex") << "Illegal edge and vert"
464 << abort(FatalError);
467 loop.append(edgeToEVert(edgeI));
468 loopWeights.append(0.5);
470 // Cross edge to next face
471 faceI = meshTools::otherFace(mesh(), cellI, faceI, edgeI);
475 Pout<< " stepped across edge " << mesh().edges()[edgeI]
476 << " to face " << faceI << " verts:"
477 << mesh().faces()[faceI] << endl;
480 label nextEdgeI = -1;
481 label nextVertI = -1;
483 // Walk face along its edges
503 loop.append(vertToEVert(vertI));
504 loopWeights.append(-GREAT);
508 // Normal vertex on edge of face. Get edges connected to it
509 // which are not on faceI.
510 labelList nextEdges = getVertEdgesNonFace
517 if (nextEdges.empty())
519 // Cross to other face (there is only one since no edges)
520 const labelList& pFaces = mesh().pointFaces()[vertI];
522 forAll(pFaces, pFaceI)
524 label thisFaceI = pFaces[pFaceI];
529 && meshTools::faceOnCell(mesh(), cellI, thisFaceI)
539 Pout<< " stepped from non-edge vertex " << vertI
540 << " to face " << faceI << " verts:"
541 << mesh().faces()[faceI]
542 << " since candidate edges:" << nextEdges << endl;
545 label nextEdgeI = -1;
546 label nextVertI = -1;
554 2, // 2 vertices to cross
563 else if (nextEdges.size() == 1)
565 // One edge. Go along this one.
566 edgeI = nextEdges[0];
570 Pout<< " stepped from non-edge vertex " << vertI
571 << " along edge " << edgeI << " verts:"
572 << mesh().edges()[edgeI]
573 << " out of candidate edges:"
574 << nextEdges << endl;
577 vertI = mesh().edges()[edgeI].otherVertex(vertI);
583 // Multiple edges to choose from. Pick any one.
584 // (ideally should be geometric)
586 label index = nextEdges.size()/2;
588 edgeI = nextEdges[index];
592 Pout<< " stepped from non-edge vertex " << vertI
593 << " along edge " << edgeI << " verts:"
594 << mesh().edges()[edgeI]
595 << " out of candidate edges:" << nextEdges << endl;
598 vertI = mesh().edges()[edgeI].otherVertex(vertI);
605 // Get faces connected to startVertI but not startEdgeI
606 labelList nextFaces =
614 if (nextFaces.size() == 1)
616 // Only one face to cross.
617 faceI = nextFaces[0];
619 label nextEdgeI = -1;
620 label nextVertI = -1;
628 2, // 2 vertices to cross
637 else if (nextFaces.size() == 2)
639 // Split face. Get edge inbetween.
643 meshTools::getSharedEdge
650 vertI = mesh().edges()[edgeI].otherVertex(vertI);
654 FatalErrorIn("walkFromVert") << "Not yet implemented"
655 << "Choosing from more than "
656 << "two candidates:" << nextFaces
657 << " when coming from vertex " << vertI << " on cell "
658 << cellI << abort(FatalError);
665 Pout<< "Walked to : face:" << faceI;
668 Pout<< " verts:" << mesh().faces()[faceI];
670 Pout<< " edge:" << edgeI;
673 Pout<< " verts:" << mesh().edges()[edgeI];
675 Pout<< " vert:" << vertI << endl;
682 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
684 // Construct from components
685 Foam::topoCellLooper::topoCellLooper(const polyMesh& mesh)
691 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
693 Foam::topoCellLooper::~topoCellLooper()
697 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
699 bool Foam::topoCellLooper::cut
701 const vector& refDir,
703 const boolList& vertIsCut,
704 const boolList& edgeIsCut,
705 const scalarField& edgeWeight,
708 scalarField& loopWeights
711 if (mesh().cellShapes()[cellI].model() == hex_)
713 // Let parent handle hex case.
728 cellFeatures superCell(mesh(), featureCos, cellI);
730 if (hexMatcher().isA(superCell.faces()))
733 getAlignedNonFeatureEdge
746 // Found non-feature edge. Start walking from vertex on edge.
747 vertI = mesh().edges()[edgeI].start();
751 // No 'matching' non-feature edge found on cell. Get starting
752 // normal i.e. feature edge.
753 edgeI = getMisAlignedEdge(refDir, cellI);
755 // Get any face using edge
758 meshTools::getEdgeFaces(mesh(), cellI, edgeI, face0, face1);
763 label nEstCuts = 2*mesh().cells()[cellI].size();
765 DynamicList<label> localLoop(nEstCuts);
766 DynamicList<scalar> localLoopWeights(nEstCuts);
780 if (localLoop.size() <=2)
786 loop.transfer(localLoop);
787 loopWeights.transfer(localLoopWeights);
794 // Let parent handle poly case.
795 return hexCellLooper::cut
810 bool Foam::topoCellLooper::cut
812 const plane& cutPlane,
814 const boolList& vertIsCut,
815 const boolList& edgeIsCut,
816 const scalarField& edgeWeight,
819 scalarField& loopWeights
822 // Let parent handle cut with plane.
838 // ************************************************************************* //