1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2008 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 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
43 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
45 defineTypeNameAndDebug(topoCellLooper, 0);
47 addToRunTimeSelectionTable(cellLooper, topoCellLooper, word);
52 // Angle for polys to be considered splitHexes.
53 const Foam::scalar Foam::topoCellLooper::featureCos =
54 Foam::cos(10.0 * mathematicalConstant::pi/180.0);
57 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
59 // In-memory truncate a list
61 void Foam::topoCellLooper::subsetList
70 // Truncate (setsize decides itself not to do anything if nothing
74 FatalErrorIn("topoCellLooper::subsetList")
75 << "startI:" << startI << " freeI:" << freeI
76 << " lst:" << lst << abort(FatalError);
82 // Shift elements down
84 for (label elemI = startI; elemI < freeI; elemI++)
86 lst[newI++] = lst[elemI];
89 if ((freeI - startI) < 0)
91 FatalErrorIn("topoCellLooper::subsetList")
92 << "startI:" << startI << " freeI:" << freeI
93 << " lst:" << lst << abort(FatalError);
96 lst.setSize(freeI - startI);
101 // Returns label of edge nFeaturePts away from startEdge (in the direction of
102 // startVertI) and not counting non-featurePoints.
104 // When stepping to this face it can happen in 3 different ways:
114 // A: jumping from face0 to face1 across edge A.
126 // B: jumping from face0 to face1 across (non-feature) point B
138 // C: jumping from face0 to face1 across (feature) point C on edge.
142 void Foam::topoCellLooper::walkFace
144 const cellFeatures& features,
146 const label startEdgeI,
147 const label startVertI,
148 const label nFeaturePts,
154 const labelList& fEdges = mesh().faceEdges()[faceI];
160 // Number of feature points crossed so far
165 // Started on edge. Go to one of its endpoints.
166 vertI = mesh().edges()[edgeI].start();
168 if (features.isFeatureVertex(faceI, vertI))
174 if ((edgeI == -1) || !meshTools::edgeOnFace(mesh(), faceI, edgeI))
176 // Either edge is not set or not on current face. Just take one of
177 // the edges on this face as starting edge.
178 edgeI = getFirstVertEdge(faceI, vertI);
181 // Now we should have starting edge on face and a vertex on that edge.
186 edgeI = meshTools::otherEdge(mesh(), fEdges, edgeI, vertI);
188 if (nVisited == nFeaturePts)
193 vertI = mesh().edges()[edgeI].otherVertex(vertI);
195 if (features.isFeatureVertex(faceI, vertI))
204 // Returns list of vertices on 'superEdge' i.e. list of edges connected by
205 // non-feature points. First and last are feature points, ones inbetween are
207 Foam::labelList Foam::topoCellLooper::getSuperEdge
209 const cellFeatures& features,
211 const label startEdgeI,
212 const label startVertI
215 const labelList& fEdges = mesh().faceEdges()[faceI];
217 labelList superVerts(fEdges.size());
218 label superVertI = 0;
221 label edgeI = startEdgeI;
223 label vertI = startVertI;
225 superVerts[superVertI++] = vertI;
227 label prevEdgeI = -1;
231 vertI = mesh().edges()[edgeI].otherVertex(vertI);
233 superVerts[superVertI++] = vertI;
237 edgeI = meshTools::otherEdge(mesh(), fEdges, edgeI, vertI);
239 while (!features.isFeaturePoint(prevEdgeI, edgeI));
241 superVerts.setSize(superVertI);
247 // Return non-feature edge from cells' edges that is most perpendicular
248 // to refinement direction.
249 Foam::label Foam::topoCellLooper::getAlignedNonFeatureEdge
251 const vector& refDir,
253 const cellFeatures& features
256 const labelList& cEdges = mesh().cellEdges()[cellI];
258 const point& ctr = mesh().cellCentres()[cellI];
261 scalar maxCos = -GREAT;
263 forAll(cEdges, cEdgeI)
265 label edgeI = cEdges[cEdgeI];
267 if (!features.isFeatureEdge(edgeI))
269 const edge& e = mesh().edges()[edgeI];
271 // Get plane spanned by e.start, e.end and cell centre.
272 vector e0 = mesh().points()[e.start()] - ctr;
273 vector e1 = mesh().points()[e.end()] - ctr;
278 scalar cosAngle = mag(refDir & n);
280 if (cosAngle > maxCos)
293 // Starts from edge and vertex on edge on face (or neighbouring face)
294 // and steps either to existing vertex (vertI != -1) or to edge (vertI == -1)
295 // by walking point-edge and crossing nFeats featurePoints.
296 void Foam::topoCellLooper::walkAcrossFace
298 const cellFeatures& features,
300 const label startEdgeI,
301 const label startVertI,
308 label oppositeVertI = -1;
309 label oppositeEdgeI = -1;
311 // Go to oppositeEdge and a vertex on that.
324 // Loop over super edge to find internal points if there are any.
326 labelList superEdge =
335 label sz = superEdge.size();
339 // No non-feature point inbetween feature points.
343 edgeI = oppositeEdgeI;
347 vertI = superEdge[1];
352 //Should choose acc. to geometry!
357 Pout<< " Don't know what to do. Stepped to non-feature point "
358 << "at index " << index << " in superEdge:" << superEdge
362 vertI = superEdge[index];
368 // Walks cell circumference. Updates face, edge, vertex.
370 // Position on face is given by:
372 // vertI == -1, faceI != -1, edgeI != -1
373 // on edge of face. Cross edge to neighbouring face.
375 // vertI != -1, edgeI != -1, faceI == -1
376 // coming from edge onto vertex vertI. Need to step to one
377 // of the faces not using edgeI.
379 // vertI != -1, edgeI == -1, faceI != -1
380 // coming from vertex on side of face. Step to one of the faces
381 // using vertI but not faceI
382 void Foam::topoCellLooper::walkSplitHex
385 const cellFeatures& features,
386 const label fromFaceI,
387 const label fromEdgeI,
388 const label fromVertI,
390 DynamicList<label>& loop,
391 DynamicList<scalar>& loopWeights
394 // Work vars giving position on cell
395 label faceI = fromFaceI;
396 label edgeI = fromEdgeI;
397 label vertI = fromVertI;
403 Pout<< "Entering walk with : cell:" << cellI << " face:" << faceI;
406 Pout<< " verts:" << mesh().faces()[faceI];
408 Pout<< " edge:" << edgeI;
411 Pout<< " verts:" << mesh().edges()[edgeI];
413 Pout<< " vert:" << vertI << endl;
416 label startLoop = -1;
433 // Breaking walk since vertI already cut
434 label firstFree = loop.size();
436 subsetList(startLoop, firstFree, loop);
437 subsetList(startLoop, firstFree, loopWeights);
456 // Breaking walk since edgeI already cut
457 label firstFree = loop.size();
459 subsetList(startLoop, firstFree, loop);
460 subsetList(startLoop, firstFree, loopWeights);
471 FatalErrorIn("walkSplitHex") << "Illegal edge and vert"
472 << abort(FatalError);
475 loop.append(edgeToEVert(edgeI));
476 loopWeights.append(0.5);
478 // Cross edge to next face
479 faceI = meshTools::otherFace(mesh(), cellI, faceI, edgeI);
483 Pout<< " stepped across edge " << mesh().edges()[edgeI]
484 << " to face " << faceI << " verts:"
485 << mesh().faces()[faceI] << endl;
488 label nextEdgeI = -1;
489 label nextVertI = -1;
491 // Walk face along its edges
511 loop.append(vertToEVert(vertI));
512 loopWeights.append(-GREAT);
516 // Normal vertex on edge of face. Get edges connected to it
517 // which are not on faceI.
518 labelList nextEdges =
526 if (nextEdges.size() == 0)
528 // Cross to other face (there is only one since no edges)
529 const labelList& pFaces = mesh().pointFaces()[vertI];
531 forAll(pFaces, pFaceI)
533 label thisFaceI = pFaces[pFaceI];
538 && meshTools::faceOnCell(mesh(), cellI, thisFaceI)
548 Pout<< " stepped from non-edge vertex " << vertI
549 << " to face " << faceI << " verts:"
550 << mesh().faces()[faceI]
551 << " since candidate edges:" << nextEdges << endl;
554 label nextEdgeI = -1;
555 label nextVertI = -1;
563 2, // 2 vertices to cross
572 else if (nextEdges.size() == 1)
574 // One edge. Go along this one.
575 edgeI = nextEdges[0];
579 Pout<< " stepped from non-edge vertex " << vertI
580 << " along edge " << edgeI << " verts:"
581 << mesh().edges()[edgeI]
582 << " out of candidate edges:"
583 << nextEdges << endl;
586 vertI = mesh().edges()[edgeI].otherVertex(vertI);
592 // Multiple edges to choose from. Pick any one.
593 // (ideally should be geometric)
595 label index = nextEdges.size()/2;
597 edgeI = nextEdges[index];
601 Pout<< " stepped from non-edge vertex " << vertI
602 << " along edge " << edgeI << " verts:"
603 << mesh().edges()[edgeI]
604 << " out of candidate edges:" << nextEdges << endl;
607 vertI = mesh().edges()[edgeI].otherVertex(vertI);
614 // Get faces connected to startVertI but not startEdgeI
615 labelList nextFaces =
623 if (nextFaces.size() == 1)
625 // Only one face to cross.
626 faceI = nextFaces[0];
628 label nextEdgeI = -1;
629 label nextVertI = -1;
637 2, // 2 vertices to cross
646 else if (nextFaces.size() == 2)
648 // Split face. Get edge inbetween.
652 meshTools::getSharedEdge
659 vertI = mesh().edges()[edgeI].otherVertex(vertI);
663 FatalErrorIn("walkFromVert") << "Not yet implemented"
664 << "Choosing from more than "
665 << "two candidates:" << nextFaces
666 << " when coming from vertex " << vertI << " on cell "
667 << cellI << abort(FatalError);
674 Pout<< "Walked to : face:" << faceI;
677 Pout<< " verts:" << mesh().faces()[faceI];
679 Pout<< " edge:" << edgeI;
682 Pout<< " verts:" << mesh().edges()[edgeI];
684 Pout<< " vert:" << vertI << endl;
691 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
693 // Construct from components
694 Foam::topoCellLooper::topoCellLooper(const polyMesh& mesh)
700 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
702 Foam::topoCellLooper::~topoCellLooper()
706 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
708 bool Foam::topoCellLooper::cut
710 const vector& refDir,
712 const boolList& vertIsCut,
713 const boolList& edgeIsCut,
714 const scalarField& edgeWeight,
717 scalarField& loopWeights
720 if (mesh().cellShapes()[cellI].model() == hex_)
722 // Let parent handle hex case.
737 cellFeatures superCell(mesh(), featureCos, cellI);
739 if (hexMatcher().isA(superCell.faces()))
742 getAlignedNonFeatureEdge
755 // Found non-feature edge. Start walking from vertex on edge.
756 vertI = mesh().edges()[edgeI].start();
760 // No 'matching' non-feature edge found on cell. Get starting
761 // normal i.e. feature edge.
762 edgeI = getMisAlignedEdge(refDir, cellI);
764 // Get any face using edge
767 meshTools::getEdgeFaces(mesh(), cellI, edgeI, face0, face1);
772 label nEstCuts = 2*mesh().cells()[cellI].size();
774 DynamicList<label> localLoop(nEstCuts);
775 DynamicList<scalar> localLoopWeights(nEstCuts);
789 if (localLoop.size() <=2)
796 localLoopWeights.shrink();
798 loop.transfer(localLoop);
799 loopWeights.transfer(localLoopWeights);
806 // Let parent handle poly case.
823 bool Foam::topoCellLooper::cut
825 const plane& cutPlane,
827 const boolList& vertIsCut,
828 const boolList& edgeIsCut,
829 const scalarField& edgeWeight,
832 scalarField& loopWeights
835 // Let parent handle cut with plane.
851 // ************************************************************************* //