1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 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, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "topoCellLooper.H"
28 #include "cellFeatures.H"
30 #include "mathematicalConstants.H"
31 #include "DynamicList.H"
33 #include "meshTools.H"
34 #include "hexMatcher.H"
36 #include "addToRunTimeSelectionTable.H"
38 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
40 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
43 defineTypeNameAndDebug(topoCellLooper, 0);
44 addToRunTimeSelectionTable(cellLooper, topoCellLooper, word);
47 // Angle for polys to be considered splitHexes.
48 const Foam::scalar Foam::topoCellLooper::featureCos =
49 Foam::cos(10.0 * mathematicalConstant::pi/180.0);
52 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
54 // In-memory truncate a list
56 void Foam::topoCellLooper::subsetList
65 // Truncate (setSize decides itself not to do anything if nothing
69 FatalErrorIn("topoCellLooper::subsetList")
70 << "startI:" << startI << " freeI:" << freeI
71 << " lst:" << lst << abort(FatalError);
73 lst.setCapacity(freeI);
77 // Shift elements down
79 for (label elemI = startI; elemI < freeI; elemI++)
81 lst[newI++] = lst[elemI];
84 if ((freeI - startI) < 0)
86 FatalErrorIn("topoCellLooper::subsetList")
87 << "startI:" << startI << " freeI:" << freeI
88 << " lst:" << lst << abort(FatalError);
91 lst.setCapacity(freeI - startI);
96 // Returns label of edge nFeaturePts away from startEdge (in the direction of
97 // startVertI) and not counting non-featurePoints.
99 // When stepping to this face it can happen in 3 different ways:
109 // A: jumping from face0 to face1 across edge A.
121 // B: jumping from face0 to face1 across (non-feature) point B
133 // C: jumping from face0 to face1 across (feature) point C on edge.
137 void Foam::topoCellLooper::walkFace
139 const cellFeatures& features,
141 const label startEdgeI,
142 const label startVertI,
143 const label nFeaturePts,
149 const labelList& fEdges = mesh().faceEdges()[faceI];
155 // Number of feature points crossed so far
160 // Started on edge. Go to one of its endpoints.
161 vertI = mesh().edges()[edgeI].start();
163 if (features.isFeatureVertex(faceI, vertI))
169 if ((edgeI == -1) || !meshTools::edgeOnFace(mesh(), faceI, edgeI))
171 // Either edge is not set or not on current face. Just take one of
172 // the edges on this face as starting edge.
173 edgeI = getFirstVertEdge(faceI, vertI);
176 // Now we should have starting edge on face and a vertex on that edge.
181 edgeI = meshTools::otherEdge(mesh(), fEdges, edgeI, vertI);
183 if (nVisited == nFeaturePts)
188 vertI = mesh().edges()[edgeI].otherVertex(vertI);
190 if (features.isFeatureVertex(faceI, vertI))
199 // Returns list of vertices on 'superEdge' i.e. list of edges connected by
200 // non-feature points. First and last are feature points, ones inbetween are
202 Foam::labelList Foam::topoCellLooper::getSuperEdge
204 const cellFeatures& features,
206 const label startEdgeI,
207 const label startVertI
210 const labelList& fEdges = mesh().faceEdges()[faceI];
212 labelList superVerts(fEdges.size());
213 label superVertI = 0;
216 label edgeI = startEdgeI;
218 label vertI = startVertI;
220 superVerts[superVertI++] = vertI;
222 label prevEdgeI = -1;
226 vertI = mesh().edges()[edgeI].otherVertex(vertI);
228 superVerts[superVertI++] = vertI;
232 edgeI = meshTools::otherEdge(mesh(), fEdges, edgeI, vertI);
234 while (!features.isFeaturePoint(prevEdgeI, edgeI));
236 superVerts.setSize(superVertI);
242 // Return non-feature edge from cells' edges that is most perpendicular
243 // to refinement direction.
244 Foam::label Foam::topoCellLooper::getAlignedNonFeatureEdge
246 const vector& refDir,
248 const cellFeatures& features
251 const labelList& cEdges = mesh().cellEdges()[cellI];
253 const point& ctr = mesh().cellCentres()[cellI];
256 scalar maxCos = -GREAT;
258 forAll(cEdges, cEdgeI)
260 label edgeI = cEdges[cEdgeI];
262 if (!features.isFeatureEdge(edgeI))
264 const edge& e = mesh().edges()[edgeI];
266 // Get plane spanned by e.start, e.end and cell centre.
267 vector e0 = mesh().points()[e.start()] - ctr;
268 vector e1 = mesh().points()[e.end()] - ctr;
273 scalar cosAngle = mag(refDir & n);
275 if (cosAngle > maxCos)
288 // Starts from edge and vertex on edge on face (or neighbouring face)
289 // and steps either to existing vertex (vertI != -1) or to edge (vertI == -1)
290 // by walking point-edge and crossing nFeats featurePoints.
291 void Foam::topoCellLooper::walkAcrossFace
293 const cellFeatures& features,
295 const label startEdgeI,
296 const label startVertI,
303 label oppositeVertI = -1;
304 label oppositeEdgeI = -1;
306 // Go to oppositeEdge and a vertex on that.
319 // Loop over super edge to find internal points if there are any.
321 labelList superEdge =
330 label sz = superEdge.size();
334 // No non-feature point inbetween feature points.
338 edgeI = oppositeEdgeI;
342 vertI = superEdge[1];
347 //Should choose acc. to geometry!
352 Pout<< " Don't know what to do. Stepped to non-feature point "
353 << "at index " << index << " in superEdge:" << superEdge
357 vertI = superEdge[index];
363 // Walks cell circumference. Updates face, edge, vertex.
365 // Position on face is given by:
367 // vertI == -1, faceI != -1, edgeI != -1
368 // on edge of face. Cross edge to neighbouring face.
370 // vertI != -1, edgeI != -1, faceI == -1
371 // coming from edge onto vertex vertI. Need to step to one
372 // of the faces not using edgeI.
374 // vertI != -1, edgeI == -1, faceI != -1
375 // coming from vertex on side of face. Step to one of the faces
376 // using vertI but not faceI
377 void Foam::topoCellLooper::walkSplitHex
380 const cellFeatures& features,
381 const label fromFaceI,
382 const label fromEdgeI,
383 const label fromVertI,
385 DynamicList<label>& loop,
386 DynamicList<scalar>& loopWeights
389 // Work vars giving position on cell
390 label faceI = fromFaceI;
391 label edgeI = fromEdgeI;
392 label vertI = fromVertI;
398 Pout<< "Entering walk with : cell:" << cellI << " face:" << faceI;
401 Pout<< " verts:" << mesh().faces()[faceI];
403 Pout<< " edge:" << edgeI;
406 Pout<< " verts:" << mesh().edges()[edgeI];
408 Pout<< " vert:" << vertI << endl;
411 label startLoop = -1;
428 // Breaking walk since vertI already cut
429 label firstFree = loop.size();
431 subsetList(startLoop, firstFree, loop);
432 subsetList(startLoop, firstFree, loopWeights);
451 // Breaking walk since edgeI already cut
452 label firstFree = loop.size();
454 subsetList(startLoop, firstFree, loop);
455 subsetList(startLoop, firstFree, loopWeights);
466 FatalErrorIn("walkSplitHex") << "Illegal edge and vert"
467 << abort(FatalError);
470 loop.append(edgeToEVert(edgeI));
471 loopWeights.append(0.5);
473 // Cross edge to next face
474 faceI = meshTools::otherFace(mesh(), cellI, faceI, edgeI);
478 Pout<< " stepped across edge " << mesh().edges()[edgeI]
479 << " to face " << faceI << " verts:"
480 << mesh().faces()[faceI] << endl;
483 label nextEdgeI = -1;
484 label nextVertI = -1;
486 // Walk face along its edges
506 loop.append(vertToEVert(vertI));
507 loopWeights.append(-GREAT);
511 // Normal vertex on edge of face. Get edges connected to it
512 // which are not on faceI.
513 labelList nextEdges = getVertEdgesNonFace
520 if (nextEdges.empty())
522 // Cross to other face (there is only one since no edges)
523 const labelList& pFaces = mesh().pointFaces()[vertI];
525 forAll(pFaces, pFaceI)
527 label thisFaceI = pFaces[pFaceI];
532 && meshTools::faceOnCell(mesh(), cellI, thisFaceI)
542 Pout<< " stepped from non-edge vertex " << vertI
543 << " to face " << faceI << " verts:"
544 << mesh().faces()[faceI]
545 << " since candidate edges:" << nextEdges << endl;
548 label nextEdgeI = -1;
549 label nextVertI = -1;
557 2, // 2 vertices to cross
566 else if (nextEdges.size() == 1)
568 // One edge. Go along this one.
569 edgeI = nextEdges[0];
573 Pout<< " stepped from non-edge vertex " << vertI
574 << " along edge " << edgeI << " verts:"
575 << mesh().edges()[edgeI]
576 << " out of candidate edges:"
577 << nextEdges << endl;
580 vertI = mesh().edges()[edgeI].otherVertex(vertI);
586 // Multiple edges to choose from. Pick any one.
587 // (ideally should be geometric)
589 label index = nextEdges.size()/2;
591 edgeI = nextEdges[index];
595 Pout<< " stepped from non-edge vertex " << vertI
596 << " along edge " << edgeI << " verts:"
597 << mesh().edges()[edgeI]
598 << " out of candidate edges:" << nextEdges << endl;
601 vertI = mesh().edges()[edgeI].otherVertex(vertI);
608 // Get faces connected to startVertI but not startEdgeI
609 labelList nextFaces =
617 if (nextFaces.size() == 1)
619 // Only one face to cross.
620 faceI = nextFaces[0];
622 label nextEdgeI = -1;
623 label nextVertI = -1;
631 2, // 2 vertices to cross
640 else if (nextFaces.size() == 2)
642 // Split face. Get edge inbetween.
646 meshTools::getSharedEdge
653 vertI = mesh().edges()[edgeI].otherVertex(vertI);
657 FatalErrorIn("walkFromVert") << "Not yet implemented"
658 << "Choosing from more than "
659 << "two candidates:" << nextFaces
660 << " when coming from vertex " << vertI << " on cell "
661 << cellI << abort(FatalError);
668 Pout<< "Walked to : face:" << faceI;
671 Pout<< " verts:" << mesh().faces()[faceI];
673 Pout<< " edge:" << edgeI;
676 Pout<< " verts:" << mesh().edges()[edgeI];
678 Pout<< " vert:" << vertI << endl;
685 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
687 // Construct from components
688 Foam::topoCellLooper::topoCellLooper(const polyMesh& mesh)
694 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
696 Foam::topoCellLooper::~topoCellLooper()
700 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
702 bool Foam::topoCellLooper::cut
704 const vector& refDir,
706 const boolList& vertIsCut,
707 const boolList& edgeIsCut,
708 const scalarField& edgeWeight,
711 scalarField& loopWeights
714 if (mesh().cellShapes()[cellI].model() == hex_)
716 // Let parent handle hex case.
731 cellFeatures superCell(mesh(), featureCos, cellI);
733 if (hexMatcher().isA(superCell.faces()))
736 getAlignedNonFeatureEdge
749 // Found non-feature edge. Start walking from vertex on edge.
750 vertI = mesh().edges()[edgeI].start();
754 // No 'matching' non-feature edge found on cell. Get starting
755 // normal i.e. feature edge.
756 edgeI = getMisAlignedEdge(refDir, cellI);
758 // Get any face using edge
761 meshTools::getEdgeFaces(mesh(), cellI, edgeI, face0, face1);
766 label nEstCuts = 2*mesh().cells()[cellI].size();
768 DynamicList<label> localLoop(nEstCuts);
769 DynamicList<scalar> localLoopWeights(nEstCuts);
783 if (localLoop.size() <=2)
789 loop.transfer(localLoop);
790 loopWeights.transfer(localLoopWeights);
797 // Let parent handle poly case.
798 return hexCellLooper::cut
813 bool Foam::topoCellLooper::cut
815 const plane& cutPlane,
817 const boolList& vertIsCut,
818 const boolList& edgeIsCut,
819 const scalarField& edgeWeight,
822 scalarField& loopWeights
825 // Let parent handle cut with plane.
841 // ************************************************************************* //