topoCellLooper.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
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.
15 
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
19  for more details.
20 
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/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "topoCellLooper.H"
27 #include "cellFeatures.H"
28 #include "polyMesh.H"
29 #include "unitConversion.H"
30 #include "DynamicList.H"
31 #include "ListOps.H"
32 #include "meshTools.H"
33 #include "hexMatcher.H"
34 
36 
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
38 
39 namespace Foam
40 {
41  defineTypeNameAndDebug(topoCellLooper, 0);
42  addToRunTimeSelectionTable(cellLooper, topoCellLooper, word);
43 }
44 
45 // Angle for polys to be considered splitHexes.
46 const Foam::scalar Foam::topoCellLooper::featureCos = Foam::cos(degToRad(10.0));
47 
48 
49 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
50 
51 // In-memory truncate a list
52 template<class T>
53 void Foam::topoCellLooper::subsetList
54 (
55  const label startI,
56  const label freeI,
57  DynamicList<T>& lst
58 )
59 {
60  if (startI == 0)
61  {
62  // Truncate (setSize decides itself not to do anything if nothing
63  // changed)
64  if (freeI < 0)
65  {
67  << " lst:" << lst << abort(FatalError);
68  }
69  lst.setCapacity(freeI);
70  }
71  else
72  {
73  // Shift elements down
74  label newI = 0;
75  for (label elemI = startI; elemI < freeI; elemI++)
76  {
77  lst[newI++] = lst[elemI];
78  }
79 
80  if ((freeI - startI) < 0)
81  {
83  << " lst:" << lst << abort(FatalError);
84  }
85 
86  lst.setCapacity(freeI - startI);
87  }
88 }
89 
90 
91 // Returns label of edge nFeaturePts away from startEdge (in the direction of
92 // startVertI) and not counting non-featurePoints.
93 //
94 // When stepping to this face it can happen in 3 different ways:
95 //
96 // --|------
97 // |
98 // 1 | 0
99 // |A
100 // |
101 // |
102 // --|------
103 //
104 // A: jumping from face0 to face1 across edge A.
105 // startEdge != -1
106 // startVert == -1
107 //
108 // --|------
109 // |
110 // 1 | 0
111 // +B
112 // |
113 // |
114 // --|------
115 //
116 // B: jumping from face0 to face1 across (non-feature) point B
117 // startEdge == -1
118 // startVert != -1
119 //
120 // --|------
121 // 0 | 1
122 // |C
123 // --+
124 // |
125 // |
126 // --|------
127 //
128 // C: jumping from face0 to face1 across (feature) point C on edge.
129 // startEdge != -1
130 // startVert != -1
131 //
132 void Foam::topoCellLooper::walkFace
133 (
134  const cellFeatures& features,
135  const label facei,
136  const label startEdgeI,
137  const label startVertI,
138  const label nFeaturePts,
139 
140  label& edgeI,
141  label& vertI
142 ) const
143 {
144  const labelList& fEdges = mesh().faceEdges()[facei];
145 
146  edgeI = startEdgeI;
147 
148  vertI = startVertI;
149 
150  // Number of feature points crossed so far
151  label nVisited = 0;
152 
153  if (vertI == -1)
154  {
155  // Started on edge. Go to one of its endpoints.
156  vertI = mesh().edges()[edgeI].start();
157 
158  if (features.isFeatureVertex(facei, vertI))
159  {
160  nVisited++;
161  }
162  }
163 
164  if ((edgeI == -1) || !meshTools::edgeOnFace(mesh(), facei, edgeI))
165  {
166  // Either edge is not set or not on current face. Just take one of
167  // the edges on this face as starting edge.
168  edgeI = getFirstVertEdge(facei, vertI);
169  }
170 
171  // Now we should have starting edge on face and a vertex on that edge.
172 
173  do
174  {
175 
176  edgeI = meshTools::otherEdge(mesh(), fEdges, edgeI, vertI);
177 
178  if (nVisited == nFeaturePts)
179  {
180  break;
181  }
182 
183  vertI = mesh().edges()[edgeI].otherVertex(vertI);
184 
185  if (features.isFeatureVertex(facei, vertI))
186  {
187  nVisited++;
188  }
189  }
190  while (true);
191 }
192 
193 
194 // Returns list of vertices on 'superEdge' i.e. list of edges connected by
195 // non-feature points. First and last are feature points, ones in between are
196 // not.
197 Foam::labelList Foam::topoCellLooper::getSuperEdge
198 (
199  const cellFeatures& features,
200  const label facei,
201  const label startEdgeI,
202  const label startVertI
203 ) const
204 {
205  const labelList& fEdges = mesh().faceEdges()[facei];
206 
207  labelList superVerts(fEdges.size());
208  label superVertI = 0;
209 
210 
211  label edgeI = startEdgeI;
212 
213  label vertI = startVertI;
214 
215  superVerts[superVertI++] = vertI;
216 
217  label prevEdgeI = -1;
218 
219  do
220  {
221  vertI = mesh().edges()[edgeI].otherVertex(vertI);
222 
223  superVerts[superVertI++] = vertI;
224 
225  prevEdgeI = edgeI;
226 
227  edgeI = meshTools::otherEdge(mesh(), fEdges, edgeI, vertI);
228  }
229  while (!features.isFeaturePoint(prevEdgeI, edgeI));
230 
231  superVerts.setSize(superVertI);
232 
233  return superVerts;
234 }
235 
236 
237 // Return non-feature edge from cells' edges that is most perpendicular
238 // to refinement direction.
239 Foam::label Foam::topoCellLooper::getAlignedNonFeatureEdge
240 (
241  const vector& refDir,
242  const label celli,
243  const cellFeatures& features
244 ) const
245 {
246  const labelList& cEdges = mesh().cellEdges()[celli];
247 
248  const point& ctr = mesh().cellCentres()[celli];
249 
250  label cutEdgeI = -1;
251  scalar maxCos = -great;
252 
253  forAll(cEdges, cEdgeI)
254  {
255  label edgeI = cEdges[cEdgeI];
256 
257  if (!features.isFeatureEdge(edgeI))
258  {
259  const edge& e = mesh().edges()[edgeI];
260 
261  // Get plane spanned by e.start, e.end and cell centre.
262  vector e0 = mesh().points()[e.start()] - ctr;
263  vector e1 = mesh().points()[e.end()] - ctr;
264 
265  vector n = e0 ^ e1;
266  n /= mag(n);
267 
268  scalar cosAngle = mag(refDir & n);
269 
270  if (cosAngle > maxCos)
271  {
272  maxCos = cosAngle;
273 
274  cutEdgeI = edgeI;
275  }
276  }
277  }
278 
279  return cutEdgeI;
280 }
281 
282 
283 // Starts from edge and vertex on edge on face (or neighbouring face)
284 // and steps either to existing vertex (vertI != -1) or to edge (vertI == -1)
285 // by walking point-edge and crossing nFeats featurePoints.
286 void Foam::topoCellLooper::walkAcrossFace
287 (
288  const cellFeatures& features,
289  const label facei,
290  const label startEdgeI,
291  const label startVertI,
292  const label nFeats,
293 
294  label& edgeI,
295  label& vertI
296 ) const
297 {
298  label oppositeVertI = -1;
299  label oppositeEdgeI = -1;
300 
301  // Go to oppositeEdge and a vertex on that.
302  walkFace
303  (
304  features,
305  facei,
306  startEdgeI,
307  startVertI,
308  nFeats,
309 
310  oppositeEdgeI,
311  oppositeVertI
312  );
313 
314  // Loop over super edge to find internal points if there are any.
315 
316  labelList superEdge =
317  getSuperEdge
318  (
319  features,
320  facei,
321  oppositeEdgeI,
322  oppositeVertI
323  );
324 
325  label sz = superEdge.size();
326 
327  if (sz == 2)
328  {
329  // No non-feature point in between feature points.
330  // Mark edge.
331 
332  vertI = -1;
333  edgeI = oppositeEdgeI;
334  }
335  else if (sz == 3)
336  {
337  vertI = superEdge[1];
338  edgeI = -1;
339  }
340  else
341  {
342  // Should choose acc. to geometry!
343  label index = sz/2;
344 
345  if (debug)
346  {
347  Pout<< " Don't know what to do. Stepped to non-feature point "
348  << "at index " << index << " in superEdge:" << superEdge
349  << endl;
350  }
351 
352  vertI = superEdge[index];
353  edgeI = -1;
354  }
355 }
356 
357 
358 // Walks cell circumference. Updates face, edge, vertex.
359 //
360 // Position on face is given by:
361 //
362 // vertI == -1, facei != -1, edgeI != -1
363 // on edge of face. Cross edge to neighbouring face.
364 //
365 // vertI != -1, edgeI != -1, facei == -1
366 // coming from edge onto vertex vertI. Need to step to one
367 // of the faces not using edgeI.
368 //
369 // vertI != -1, edgeI == -1, facei != -1
370 // coming from vertex on side of face. Step to one of the faces
371 // using vertI but not facei
372 void Foam::topoCellLooper::walkSplitHex
373 (
374  const label celli,
375  const cellFeatures& features,
376  const label fromFacei,
377  const label fromEdgeI,
378  const label fromVertI,
379 
380  DynamicList<label>& loop,
381  DynamicList<scalar>& loopWeights
382 ) const
383 {
384  // Work vars giving position on cell
385  label facei = fromFacei;
386  label edgeI = fromEdgeI;
387  label vertI = fromVertI;
388 
389  do
390  {
391  if (debug)
392  {
393  Pout<< "Entering walk with : cell:" << celli << " face:" << facei;
394  if (facei != -1)
395  {
396  Pout<< " verts:" << mesh().faces()[facei];
397  }
398  Pout<< " edge:" << edgeI;
399  if (edgeI != -1)
400  {
401  Pout<< " verts:" << mesh().edges()[edgeI];
402  }
403  Pout<< " vert:" << vertI << endl;
404  }
405 
406  label startLoop = -1;
407 
408  if
409  (
410  (vertI != -1)
411  && (
412  (startLoop =
413  findIndex
414  (
415  loop,
416  vertToEVert(vertI)
417  )
418  )
419  != -1
420  )
421  )
422  {
423  // Breaking walk since vertI already cut
424  label firstFree = loop.size();
425 
426  subsetList(startLoop, firstFree, loop);
427  subsetList(startLoop, firstFree, loopWeights);
428 
429  break;
430  }
431  if
432  (
433  (edgeI != -1)
434  && (
435  (startLoop =
436  findIndex
437  (
438  loop,
439  edgeToEVert(edgeI)
440  )
441  )
442  != -1
443  )
444  )
445  {
446  // Breaking walk since edgeI already cut
447  label firstFree = loop.size();
448 
449  subsetList(startLoop, firstFree, loop);
450  subsetList(startLoop, firstFree, loopWeights);
451 
452  break;
453  }
454 
455 
456  if (vertI == -1)
457  {
458  // On edge
459  if (edgeI == -1)
460  {
462  << abort(FatalError);
463  }
464 
465  loop.append(edgeToEVert(edgeI));
466  loopWeights.append(0.5);
467 
468  // Cross edge to next face
469  facei = meshTools::otherFace(mesh(), celli, facei, edgeI);
470 
471  if (debug)
472  {
473  Pout<< " stepped across edge " << mesh().edges()[edgeI]
474  << " to face " << facei << " verts:"
475  << mesh().faces()[facei] << endl;
476  }
477 
478  label nextEdgeI = -1;
479  label nextVertI = -1;
480 
481  // Walk face along its edges
482  walkAcrossFace
483  (
484  features,
485  facei,
486  edgeI,
487  vertI,
488  2,
489 
490  nextEdgeI,
491  nextVertI
492  );
493 
494  edgeI = nextEdgeI;
495  vertI = nextVertI;
496  }
497  else
498  {
499  // On vertex.
500 
501  loop.append(vertToEVert(vertI));
502  loopWeights.append(-great);
503 
504  if (edgeI == -1)
505  {
506  // Normal vertex on edge of face. Get edges connected to it
507  // which are not on facei.
508  labelList nextEdges = getVertEdgesNonFace
509  (
510  celli,
511  facei,
512  vertI
513  );
514 
515  if (nextEdges.empty())
516  {
517  // Cross to other face (there is only one since no edges)
518  const labelList& pFaces = mesh().pointFaces()[vertI];
519 
520  forAll(pFaces, pFacei)
521  {
522  label thisFacei = pFaces[pFacei];
523 
524  if
525  (
526  (thisFacei != facei)
527  && meshTools::faceOnCell(mesh(), celli, thisFacei)
528  )
529  {
530  facei = thisFacei;
531  break;
532  }
533  }
534 
535  if (debug)
536  {
537  Pout<< " stepped from non-edge vertex " << vertI
538  << " to face " << facei << " verts:"
539  << mesh().faces()[facei]
540  << " since candidate edges:" << nextEdges << endl;
541  }
542 
543  label nextEdgeI = -1;
544  label nextVertI = -1;
545 
546  walkAcrossFace
547  (
548  features,
549  facei,
550  edgeI,
551  vertI,
552  2, // 2 vertices to cross
553 
554  nextEdgeI,
555  nextVertI
556  );
557 
558  edgeI = nextEdgeI;
559  vertI = nextVertI;
560  }
561  else if (nextEdges.size() == 1)
562  {
563  // One edge. Go along this one.
564  edgeI = nextEdges[0];
565 
566  if (debug)
567  {
568  Pout<< " stepped from non-edge vertex " << vertI
569  << " along edge " << edgeI << " verts:"
570  << mesh().edges()[edgeI]
571  << " out of candidate edges:"
572  << nextEdges << endl;
573  }
574 
575  vertI = mesh().edges()[edgeI].otherVertex(vertI);
576 
577  facei = -1;
578  }
579  else
580  {
581  // Multiple edges to choose from. Pick any one.
582  // (ideally should be geometric)
583 
584  label index = nextEdges.size()/2;
585 
586  edgeI = nextEdges[index];
587 
588  if (debug)
589  {
590  Pout<< " stepped from non-edge vertex " << vertI
591  << " along edge " << edgeI << " verts:"
592  << mesh().edges()[edgeI]
593  << " out of candidate edges:" << nextEdges << endl;
594  }
595 
596  vertI = mesh().edges()[edgeI].otherVertex(vertI);
597 
598  facei = -1;
599  }
600  }
601  else
602  {
603  // Get faces connected to startVertI but not startEdgeI
604  labelList nextFaces =
605  getVertFacesNonEdge
606  (
607  celli,
608  edgeI,
609  vertI
610  );
611 
612  if (nextFaces.size() == 1)
613  {
614  // Only one face to cross.
615  facei = nextFaces[0];
616 
617  label nextEdgeI = -1;
618  label nextVertI = -1;
619 
620  walkAcrossFace
621  (
622  features,
623  facei,
624  edgeI,
625  vertI,
626  2, // 2 vertices to cross
627 
628  nextEdgeI,
629  nextVertI
630  );
631 
632  edgeI = nextEdgeI;
633  vertI = nextVertI;
634  }
635  else if (nextFaces.size() == 2)
636  {
637  // Split face. Get edge in between.
638  facei = -1;
639 
640  edgeI =
642  (
643  mesh(),
644  nextFaces[0],
645  nextFaces[1]
646  );
647 
648  vertI = mesh().edges()[edgeI].otherVertex(vertI);
649  }
650  else
651  {
653  << "Choosing from more than "
654  << "two candidates:" << nextFaces
655  << " when coming from vertex " << vertI << " on cell "
656  << celli << abort(FatalError);
657  }
658  }
659  }
660 
661  if (debug)
662  {
663  Pout<< "Walked to : face:" << facei;
664  if (facei != -1)
665  {
666  Pout<< " verts:" << mesh().faces()[facei];
667  }
668  Pout<< " edge:" << edgeI;
669  if (edgeI != -1)
670  {
671  Pout<< " verts:" << mesh().edges()[edgeI];
672  }
673  Pout<< " vert:" << vertI << endl;
674  }
675  }
676  while (true);
677 }
678 
679 
680 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
681 
682 // Construct from components
684 :
685  hexCellLooper(mesh)
686 {}
687 
688 
689 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
690 
692 {}
693 
694 
695 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
696 
698 (
699  const vector& refDir,
700  const label celli,
701  const boolList& vertIsCut,
702  const boolList& edgeIsCut,
703  const scalarField& edgeWeight,
704 
705  labelList& loop,
706  scalarField& loopWeights
707 ) const
708 {
709  if (mesh().cellShapes()[celli].model() == hex_)
710  {
711  // Let parent handle hex case.
712  return
714  (
715  refDir,
716  celli,
717  vertIsCut,
718  edgeIsCut,
719  edgeWeight,
720  loop,
721  loopWeights
722  );
723  }
724  else
725  {
726  cellFeatures superCell(mesh(), featureCos, celli);
727 
728  if (hexMatcher().isA(superCell.faces()))
729  {
730  label edgeI =
731  getAlignedNonFeatureEdge
732  (
733  refDir,
734  celli,
735  superCell
736  );
737 
738  label vertI = -1;
739 
740  label facei = -1;
741 
742  if (edgeI != -1)
743  {
744  // Found non-feature edge. Start walking from vertex on edge.
745  vertI = mesh().edges()[edgeI].start();
746  }
747  else
748  {
749  // No 'matching' non-feature edge found on cell. Get starting
750  // normal i.e. feature edge.
751  edgeI = getMisAlignedEdge(refDir, celli);
752 
753  // Get any face using edge
754  label face0;
755  label face1;
756  meshTools::getEdgeFaces(mesh(), celli, edgeI, face0, face1);
757 
758  facei = face0;
759  }
760 
761  label nEstCuts = 2*mesh().cells()[celli].size();
762 
763  DynamicList<label> localLoop(nEstCuts);
764  DynamicList<scalar> localLoopWeights(nEstCuts);
765 
766  walkSplitHex
767  (
768  celli,
769  superCell,
770  facei,
771  edgeI,
772  vertI,
773 
774  localLoop,
775  localLoopWeights
776  );
777 
778  if (localLoop.size() <=2)
779  {
780  return false;
781  }
782  else
783  {
784  loop.transfer(localLoop);
785  loopWeights.transfer(localLoopWeights);
786 
787  return true;
788  }
789  }
790  else
791  {
792  // Let parent handle poly case.
793  return hexCellLooper::cut
794  (
795  refDir,
796  celli,
797  vertIsCut,
798  edgeIsCut,
799  edgeWeight,
800  loop,
801  loopWeights
802  );
803  }
804  }
805 }
806 
807 
809 (
810  const plane& cutPlane,
811  const label celli,
812  const boolList& vertIsCut,
813  const boolList& edgeIsCut,
814  const scalarField& edgeWeight,
815 
816  labelList& loop,
817  scalarField& loopWeights
818 ) const
819 {
820  // Let parent handle cut with plane.
821  return
823  (
824  cutPlane,
825  celli,
826  vertIsCut,
827  edgeIsCut,
828  edgeWeight,
829 
830  loop,
831  loopWeights
832  );
833 }
834 
835 
836 // ************************************************************************* //
bool isA(const Type &t)
Check if a dynamic_cast to typeid is possible.
Definition: typeInfo.H:134
const labelListList & cellEdges() const
bool edgeOnFace(const primitiveMesh &, const label facei, const label edgeI)
Is edge used by face.
Definition: meshTools.C:296
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
virtual bool cut(const vector &refDir, const label celli, const boolList &vertIsCut, const boolList &edgeIsCut, const scalarField &edgeWeight, labelList &loop, scalarField &loopWeights) const
Create cut along circumference of celli. Gets current mesh cuts.
label otherEdge(const primitiveMesh &, const labelList &edgeLabels, const label edgeI, const label vertI)
Return label of other edge (out of candidates edgeLabels)
Definition: meshTools.C:501
error FatalError
const labelListList & faceEdges() const
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:323
Unit conversion functions.
virtual ~topoCellLooper()
Destructor.
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
topoCellLooper(const polyMesh &mesh)
Construct from components.
label getSharedEdge(const primitiveMesh &, const label f0, const label f1)
Return edge shared by two faces. Throws error if no edge found.
Definition: meshTools.C:386
A cellMatcher for hex cells.
Definition: hexMatcher.H:51
const cellList & cells() const
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:49
Geometric class that creates a 2D plane and can return the intersection point between a line and the ...
Definition: plane.H:60
const cellModel & hex_
Reference to hex cell shape.
Definition: hexCellLooper.H:70
bool faceOnCell(const primitiveMesh &, const label celli, const label facei)
Is face used by cell.
Definition: meshTools.C:308
Macros for easy insertion into run-time selection tables.
scalar degToRad(const scalar deg)
Conversion from degrees to radians.
Various functions to operate on Lists.
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1131
label getMisAlignedEdge(const vector &refDir, const label celli) const
Return edge from cellEdges that is most perpendicular.
Definition: cellLooper.C:167
dynamicFvMesh & mesh
dimensionedScalar cos(const dimensionedScalar &ds)
const cellShapeList & cellShapes
static const scalar featureCos
Cos of angle for feature recognition (of splitHexes)
List< label > labelList
A List of labels.
Definition: labelList.H:56
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1156
const vectorField & cellCentres() const
const faceList & faces() const
Definition: cellFeatures.H:136
errorManip< error > abort(error &err)
Definition: errorManip.H:131
const polyMesh & mesh() const
Definition: edgeVertex.H:93
addToRunTimeSelectionTable(ensightPart, ensightPartCells, istream)
defineTypeNameAndDebug(combustionModel, 0)
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
const edgeList & edges() const
Return mesh edges. Uses calcEdges.
vector point
Point is a vector.
Definition: point.H:41
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
Implementation of cellLooper.
Definition: hexCellLooper.H:60
const labelListList & pointFaces() const
dimensioned< scalar > mag(const dimensioned< Type > &)
label n
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
Cell analysis class.
Definition: cellFeatures.H:61
label walkFace(const primitiveMesh &, const label facei, const label startEdgeI, const label startVertI, const label nEdges)
Returns label of edge nEdges away from startEdge (in the direction.
Definition: meshTools.C:587
void transfer(List< T > &)
Transfer the contents of the argument List into this list.
Definition: List.C:342
void getEdgeFaces(const primitiveMesh &, const label celli, const label edgeI, label &face0, label &face1)
Get faces on cell using edgeI. Throws error if no two found.
Definition: meshTools.C:458
virtual bool cut(const vector &refDir, const label celli, const boolList &vertIsCut, const boolList &edgeIsCut, const scalarField &edgeWeight, labelList &loop, scalarField &loopWeights) const
Create cut along circumference of celli. Gets current mesh cuts.
label otherFace(const primitiveMesh &, const label celli, const label facei, const label edgeI)
Return face on cell using edgeI but not facei. Throws error.
Definition: meshTools.C:536
Namespace for OpenFOAM.