polyMeshTetDecomposition.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2019 OpenFOAM Foundation
9  Copyright (C) 2019-2021 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
30 
31 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
32 
33 // Note: the use of this tolerance is ad-hoc, there may be extreme
34 // cases where the resulting tetrahedra still have particle tracking
35 // problems, or tets with lower quality may track OK.
36 const Foam::scalar Foam::polyMeshTetDecomposition::minTetQuality = sqr(SMALL);
37 
38 
39 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
40 
42 (
43  const polyMesh& mesh,
44  const point& cC,
45  const label fI,
46  const bool isOwner,
47  const label faceBasePtI
48 )
49 {
50  // Does fan decomposition of face (starting at faceBasePti) and determines
51  // min quality over all resulting tets.
52 
53  const pointField& pPts = mesh.points();
54  const face& f = mesh.faces()[fI];
55  const point& tetBasePt = pPts[f[faceBasePtI]];
56 
57  scalar thisBaseMinTetQuality = VGREAT;
58 
59  for (label tetPtI = 1; tetPtI < f.size() - 1; tetPtI++)
60  {
61  label facePtI = (tetPtI + faceBasePtI) % f.size();
62  label otherFacePtI = f.fcIndex(facePtI);
63 
64  label ptAI = -1;
65  label ptBI = -1;
66 
67  if (isOwner)
68  {
69  ptAI = f[facePtI];
70  ptBI = f[otherFacePtI];
71  }
72  else
73  {
74  ptAI = f[otherFacePtI];
75  ptBI = f[facePtI];
76  }
77 
78  const point& pA = pPts[ptAI];
79  const point& pB = pPts[ptBI];
80 
81  tetPointRef tet(cC, tetBasePt, pA, pB);
82 
83  scalar tetQuality = tet.quality();
84 
85  if (tetQuality < thisBaseMinTetQuality)
86  {
87  thisBaseMinTetQuality = tetQuality;
88  }
89  }
90  return thisBaseMinTetQuality;
91 }
92 
93 
95 (
96  const polyMesh& mesh,
97  const label facei,
98  const label faceBasePtI
99 )
100 {
101  const scalar ownQuality =
102  minQuality
103  (
104  mesh,
105  mesh.cellCentres()[mesh.faceOwner()[facei]],
106  facei,
107  true,
108  faceBasePtI
109  );
110 
111  if (mesh.isInternalFace(facei))
112  {
113  const scalar neiQuality =
114  minQuality
115  (
116  mesh,
117  mesh.cellCentres()[mesh.faceNeighbour()[facei]],
118  facei,
119  false,
120  faceBasePtI
121  );
122 
123  if (neiQuality < ownQuality)
124  {
125  return neiQuality;
126  }
127  }
128 
129  return ownQuality;
130 }
131 
132 
134 (
135  const polyMesh& mesh,
136  label fI,
137  const point& nCc,
138  scalar tol,
139  bool report
140 )
141 {
142  const faceList& pFaces = mesh.faces();
143  const vectorField& pC = mesh.cellCentres();
144  const labelList& pOwner = mesh.faceOwner();
145 
146  const face& f = pFaces[fI];
147 
148  label oCI = pOwner[fI];
149 
150  const point& oCc = pC[oCI];
151 
152  forAll(f, faceBasePtI)
153  {
154  scalar ownQuality = minQuality(mesh, oCc, fI, true, faceBasePtI);
155  scalar neiQuality = minQuality(mesh, nCc, fI, false, faceBasePtI);
156 
157  if (min(ownQuality, neiQuality) > tol)
158  {
159  return faceBasePtI;
160  }
161  }
162 
163  // If a base point hasn't triggered a return by now, then there is
164  // none that can produce a good decomposition
165  return -1;
166 }
167 
168 
170 (
171  const polyMesh& mesh,
172  label fI,
173  scalar tol,
174  bool report
175 )
176 {
177  return findSharedBasePoint
178  (
179  mesh,
180  fI,
181  mesh.cellCentres()[mesh.faceNeighbour()[fI]],
182  tol,
183  report
184  );
185 }
186 
187 
189 (
190  const polyMesh& mesh,
191  label fI,
192  scalar tol,
193  bool report
194 )
195 {
196  const faceList& pFaces = mesh.faces();
197  const vectorField& pC = mesh.cellCentres();
198  const labelList& pOwner = mesh.faceOwner();
199 
200  const face& f = pFaces[fI];
201 
202  label cI = pOwner[fI];
203 
204  bool own = (pOwner[fI] == cI);
205 
206  const point& cC = pC[cI];
207 
208  forAll(f, faceBasePtI)
209  {
210  scalar quality = minQuality(mesh, cC, fI, own, faceBasePtI);
211 
212  if (quality > tol)
213  {
214  return faceBasePtI;
215  }
216  }
217 
218  // If a base point hasn't triggered a return by now, then there is
219  // none that can produce a good decomposition
220  return -1;
221 }
222 
223 
225 (
226  const polyMesh& mesh,
227  scalar tol,
228  bool report
229 )
230 {
231  const labelList& pOwner = mesh.faceOwner();
232  const vectorField& pC = mesh.cellCentres();
233 
234  // Find a suitable base point for each face, considering both
235  // cells for interface faces or those on coupled patches
236 
237  labelList tetBasePtIs(mesh.nFaces(), -1);
238 
239  label nInternalFaces = mesh.nInternalFaces();
240 
241  for (label fI = 0; fI < nInternalFaces; ++fI)
242  {
243  tetBasePtIs[fI] = findSharedBasePoint(mesh, fI, tol, report);
244  }
245 
246  pointField neighbourCellCentres(mesh.nFaces() - nInternalFaces);
247 
248  for (label facei = nInternalFaces; facei < mesh.nFaces(); ++facei)
249  {
250  neighbourCellCentres[facei - nInternalFaces] = pC[pOwner[facei]];
251  }
252 
253  syncTools::swapBoundaryFacePositions(mesh, neighbourCellCentres);
254 
255  const polyBoundaryMesh& patches = mesh.boundaryMesh();
256 
257  SubList<label> boundaryFaceTetBasePtIs
258  (
259  tetBasePtIs,
260  mesh.nFaces() - nInternalFaces,
261  nInternalFaces
262  );
263 
264  for
265  (
266  label fI = nInternalFaces, bFI = 0;
267  fI < mesh.nFaces();
268  fI++, bFI++
269  )
270  {
271  label patchi = mesh.boundaryMesh().patchID()[bFI];
272 
273  if (patches[patchi].coupled())
274  {
275  const coupledPolyPatch& pp =
276  refCast<const coupledPolyPatch>(patches[patchi]);
277 
278  if (pp.owner())
279  {
280  boundaryFaceTetBasePtIs[bFI] = findSharedBasePoint
281  (
282  mesh,
283  fI,
284  neighbourCellCentres[bFI],
285  tol,
286  report
287  );
288  }
289  else
290  {
291  // Assign -2, to distinguish from a failed base point
292  // find, which returns -1.
293  boundaryFaceTetBasePtIs[bFI] = -2;
294  }
295  }
296  else
297  {
298  boundaryFaceTetBasePtIs[bFI] = findBasePoint
299  (
300  mesh,
301  fI,
302  tol,
303  report
304  );
305  }
306  }
307 
308  // maxEqOp will replace the -2 values on the neighbour patches
309  // with the result from the owner base point find.
310 
311  syncTools::syncBoundaryFaceList
312  (
313  mesh,
314  boundaryFaceTetBasePtIs,
316  );
317 
318  for
319  (
320  label fI = nInternalFaces, bFI = 0;
321  fI < mesh.nFaces();
322  fI++, bFI++
323  )
324  {
325  label& bFTetBasePtI = boundaryFaceTetBasePtIs[bFI];
326 
327  if (bFTetBasePtI == -2)
328  {
330  << "Coupled face base point exchange failure for face "
331  << fI << " at " << mesh.faceCentres()[fI]
332  << abort(FatalError);
333  }
334 
335  if (bFTetBasePtI < 1)
336  {
337  // If the base point is -1, it should be left as such to
338  // indicate a problem, if it is 0, then no action is required.
339 
340  continue;
341  }
342 
343  label patchi = mesh.boundaryMesh().patchID()[bFI];
344 
345  if (patches[patchi].coupled())
346  {
347  const coupledPolyPatch& pp =
348  refCast<const coupledPolyPatch>(patches[patchi]);
349 
350  // Calculated base points on coupled faces are those of
351  // the owner patch face. They need to be reindexed to for
352  // the non-owner face, which has the opposite order.
353 
354  // So, for fPtI_o != 0, fPtI_n = f.size() - fPtI_o
355 
356  // i.e.:
357 
358  // owner coupledPolyPatch face
359  // face (a b c d e f)
360  // fPtI 0 1 2 3 4 5
361  // +
362  // #
363 
364  // neighbour coupledPolyPatch face
365  // face (a f e d c b)
366  // fPtI 0 1 2 3 4 5
367  // +
368  // #
369  // +: 6 - 1 = 5
370  // #: 6 - 2 = 4
371 
372  if (!pp.owner())
373  {
374  bFTetBasePtI = mesh.faces()[fI].size() - bFTetBasePtI;
375  }
376  }
377  }
378 
379  return tetBasePtIs;
380 }
381 
382 
384 (
385  const polyMesh& mesh,
386  scalar tol,
387  const bool report,
388  labelHashSet* setPtr
389 )
390 {
391  const labelList& own = mesh.faceOwner();
392  const labelList& nei = mesh.faceNeighbour();
393  const polyBoundaryMesh& patches = mesh.boundaryMesh();
394 
395  const vectorField& cc = mesh.cellCentres();
396  const vectorField& fc = mesh.faceCentres();
397 
398  // Calculate coupled cell centre
399  pointField neiCc(mesh.nBoundaryFaces());
400 
401  for (label facei = mesh.nInternalFaces(); facei < mesh.nFaces(); ++facei)
402  {
403  neiCc[facei - mesh.nInternalFaces()] = cc[own[facei]];
404  }
405 
406  syncTools::swapBoundaryFacePositions(mesh, neiCc);
407 
408  const faceList& fcs = mesh.faces();
409 
410  const pointField& p = mesh.points();
411 
412  label nErrorTets = 0;
413 
414  forAll(fcs, facei)
415  {
416  const face& f = fcs[facei];
417 
418  forAll(f, fPtI)
419  {
420  scalar tetQual = tetPointRef
421  (
422  p[f[fPtI]],
423  p[f.nextLabel(fPtI)],
424  fc[facei],
425  cc[own[facei]]
426  ).quality();
427 
428  if (tetQual > -tol)
429  {
430  if (setPtr)
431  {
432  setPtr->insert(facei);
433  }
434 
435  nErrorTets++;
436  break; // no need to check other tets
437  }
438  }
439 
440  if (mesh.isInternalFace(facei))
441  {
442  // Create the neighbour tet - it will have positive volume
443  const face& f = fcs[facei];
444 
445  forAll(f, fPtI)
446  {
447  scalar tetQual = tetPointRef
448  (
449  p[f[fPtI]],
450  p[f.nextLabel(fPtI)],
451  fc[facei],
452  cc[nei[facei]]
453  ).quality();
454 
455  if (tetQual < tol)
456  {
457  if (setPtr)
458  {
459  setPtr->insert(facei);
460  }
461 
462  nErrorTets++;
463  break;
464  }
465  }
466 
467  if (findSharedBasePoint(mesh, facei, tol, report) == -1)
468  {
469  if (setPtr)
470  {
471  setPtr->insert(facei);
472  }
473 
474  nErrorTets++;
475  }
476  }
477  else
478  {
479  label patchi = patches.patchID()[facei - mesh.nInternalFaces()];
480 
481  if (patches[patchi].coupled())
482  {
483  if
484  (
485  findSharedBasePoint
486  (
487  mesh,
488  facei,
489  neiCc[facei - mesh.nInternalFaces()],
490  tol,
491  report
492  ) == -1
493  )
494  {
495  if (setPtr)
496  {
497  setPtr->insert(facei);
498  }
499 
500  nErrorTets++;
501  }
502  }
503  else
504  {
505  if (findBasePoint(mesh, facei, tol, report) == -1)
506  {
507  if (setPtr)
508  {
509  setPtr->insert(facei);
510  }
511 
512  nErrorTets++;
513  }
514  }
515  }
516  }
517 
518  reduce(nErrorTets, sumOp<label>());
519 
520  if (nErrorTets > 0)
521  {
522  if (report)
523  {
524  Info<< " ***Error in face tets: "
525  << nErrorTets << " faces with low quality or negative volume "
526  << "decomposition tets." << endl;
527  }
528 
529  return true;
530  }
531 
532  if (report)
533  {
534  Info<< " Face tets OK." << endl;
535  }
536 
537  return false;
538 }
539 
540 
542 (
543  const polyMesh& mesh,
544  label facei,
545  label celli
546 )
547 {
548  const faceList& pFaces = mesh.faces();
549 
550  const face& f = pFaces[facei];
551 
552  label nTets = f.size() - 2;
553 
554  List<tetIndices> faceTets(nTets);
555 
556  for (label tetPti = 1; tetPti < f.size() - 1; ++tetPti)
557  {
558  faceTets[tetPti - 1] = tetIndices(celli, facei, tetPti);
559  }
560 
561  return faceTets;
562 }
563 
564 
566 (
567  const polyMesh& mesh,
568  label celli
569 )
570 {
571  const faceList& pFaces = mesh.faces();
572  const cellList& pCells = mesh.cells();
573 
574  const cell& thisCell = pCells[celli];
575 
576  label nTets = 0;
577 
578  for (const label facei : thisCell)
579  {
580  nTets += pFaces[facei].size() - 2;
581  }
582 
583  DynamicList<tetIndices> cellTets(nTets);
584 
585  for (const label facei : thisCell)
586  {
587  cellTets.append(faceTetIndices(mesh, facei, celli));
588  }
589 
590  return cellTets;
591 }
592 
593 
595 (
596  const polyMesh& mesh,
597  label celli,
598  const point& pt
599 )
600 {
601  const faceList& pFaces = mesh.faces();
602  const cellList& pCells = mesh.cells();
603 
604  const cell& thisCell = pCells[celli];
605 
606  tetIndices tetContainingPt;
607 
608 
609  for (const label facei : thisCell)
610  {
611  const face& f = pFaces[facei];
612 
613  for (label tetPti = 1; tetPti < f.size() - 1; ++tetPti)
614  {
615  // Get tetIndices of face triangle
616  tetIndices faceTetIs(celli, facei, tetPti);
617 
618  // Check if inside
619  if (faceTetIs.tet(mesh).inside(pt))
620  {
621  tetContainingPt = faceTetIs;
622  break;
623  }
624  }
625 
626  if (tetContainingPt.cell() != -1)
627  {
628  break;
629  }
630  }
631 
632  return tetContainingPt;
633 }
634 
635 
637 (
638  const polyMesh& mesh,
639  const bool report
640 )
641 {
642  // Determine points used by two faces on the same cell
643  const cellList& cells = mesh.cells();
644  const faceList& faces = mesh.faces();
645  const labelList& faceOwn = mesh.faceOwner();
646  const labelList& faceNei = mesh.faceNeighbour();
647 
648 
649  // Get face triangulation base point
650  labelList tetBasePtIs(mesh.tetBasePtIs());
651 
652 
653  // Pre-filter: mark all cells with illegal base points
654  bitSet problemCells(cells.size());
655 
656  forAll(tetBasePtIs, facei)
657  {
658  if (tetBasePtIs[facei] == -1)
659  {
660  problemCells.set(faceOwn[facei]);
661 
662  if (mesh.isInternalFace(facei))
663  {
664  problemCells.set(faceNei[facei]);
665  }
666  }
667  }
668 
669 
670  // Mark all points that are shared by just two faces within an adjacent
671  // problem cell as problematic
672  bitSet problemPoints(mesh.points().size());
673 
674  {
675  // Number of times a point occurs in a cell.
676  // Used to detect dangling vertices (count = 2)
677  Map<label> pointCount;
678 
679  // Analyse problem cells for points shared by two faces only
680  for (const label celli : problemCells)
681  {
682  pointCount.clear();
683 
684  for (const label facei : cells[celli])
685  {
686  for (const label pointi : faces[facei])
687  {
688  ++pointCount(pointi);
689  }
690  }
691 
692  forAllConstIters(pointCount, iter)
693  {
694  if (iter.val() == 1)
695  {
697  << "point:" << iter.key()
698  << " at:" << mesh.points()[iter.key()]
699  << " only used by one face" << nl
700  << exit(FatalError);
701  }
702  else if (iter.val() == 2)
703  {
704  problemPoints.set(iter.key());
705  }
706  }
707  }
708  }
709 
710 
711  // For all faces which form a part of a problem-cell, check if the base
712  // point is adjacent to any problem points. If it is, re-calculate the base
713  // point so that it is not.
714  label nAdapted = 0;
715  forAll(tetBasePtIs, facei)
716  {
717  if
718  (
719  problemCells.test(faceOwn[facei])
720  || (mesh.isInternalFace(facei) && problemCells.test(faceNei[facei]))
721  )
722  {
723  const face& f = faces[facei];
724 
725  // Check if either of the points adjacent to the base point is a
726  // problem point. If not, the existing base point can be retained.
727  const label fp0 = tetBasePtIs[facei] < 0 ? 0 : tetBasePtIs[facei];
728 
729  if
730  (
731  !problemPoints.test(f.rcValue(fp0))
732  && !problemPoints.test(f.fcValue(fp0))
733  )
734  {
735  continue;
736  }
737 
738  // A new base point is required. Pick the point that results in the
739  // least-worst tet and which is not adjacent to any problem points.
740  scalar maxQ = -GREAT;
741  label maxFp = -1;
742  forAll(f, fp)
743  {
744  if
745  (
746  !problemPoints.test(f.rcValue(fp))
747  && !problemPoints.test(f.fcValue(fp))
748  )
749  {
750  const scalar q = minQuality(mesh, facei, fp);
751  if (q > maxQ)
752  {
753  maxQ = q;
754  maxFp = fp;
755  }
756  }
757  }
758 
759  if (maxFp != -1)
760  {
761  // Success! Set the new base point
762  tetBasePtIs[facei] = maxFp;
763  }
764  else
765  {
766  // No point was found on face that would not result in some
767  // duplicate triangle. Do what? Continue and hope? Spit an
768  // error? Silently or noisily reduce the filtering level?
769 
770  tetBasePtIs[facei] = 0;
771  }
772 
773  ++nAdapted;
774  }
775  }
776 
777  syncTools::syncFaceList(mesh, tetBasePtIs, maxEqOp<label>());
778 
779  if (report && returnReduce(nAdapted, sumOp<label>()))
780  {
781  Pout<< "Adapted starting point of triangulation on "
782  << nAdapted << " faces." << endl;
783  }
784 
785  return tetBasePtIs;
786 }
787 
788 
789 // ************************************************************************* //
Foam::polyMeshTetDecomposition::checkFaceTets
static bool checkFaceTets(const polyMesh &mesh, scalar tol=minTetQuality, const bool report=false, labelHashSet *setPtr=nullptr)
Check face-decomposition tet volume.
Definition: polyMeshTetDecomposition.C:384
Foam::tetrahedron::inside
bool inside(const point &pt) const
Return true if point is inside tetrahedron.
Definition: tetrahedronI.H:415
Foam::polyMeshTetDecomposition::minTetQuality
static const scalar minTetQuality
Minimum tetrahedron quality.
Definition: polyMeshTetDecomposition.H:66
p
volScalarField & p
Definition: createFieldRefs.H:8
Foam::tetIndices::tet
tetPointRef tet(const polyMesh &mesh) const
Return the geometry corresponding to this tet.
Definition: tetIndicesI.H:155
Foam::returnReduce
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Definition: PstreamReduceOps.H:94
Foam::bitSet
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:63
Foam::tetIndices::cell
label cell() const
Return the cell.
Definition: tetIndicesI.H:31
Foam::polyBoundaryMesh
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO.
Definition: polyBoundaryMesh.H:63
Foam::DynamicList
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:55
Foam::polyMeshTetDecomposition::findFaceBasePts
static labelList findFaceBasePts(const polyMesh &mesh, scalar tol=minTetQuality, bool report=false)
Definition: polyMeshTetDecomposition.C:225
Foam::SubList
A List obtained as a section of another List.
Definition: SubList.H:54
Foam::Map< label >
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::coupledPolyPatch
The coupledPolyPatch is an abstract base class for patches that couple regions of the computational d...
Definition: coupledPolyPatch.H:54
Foam::Pout
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Foam::coupledPolyPatch::owner
virtual bool owner() const =0
Does this side own the patch ?
Foam::HashSet< label, Hash< label > >
Foam::min
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
Foam::polyMesh
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:77
polyMeshTetDecomposition.H
Foam::sumOp
Definition: ops.H:213
Foam::tetPointRef
tetrahedron< point, const point & > tetPointRef
A tetrahedron using referred points.
Definition: tetPointRef.H:47
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::polyMeshTetDecomposition::findSharedBasePoint
static label findSharedBasePoint(const polyMesh &mesh, label fI, const point &nCc, scalar tol, bool report=false)
Find the first suitable base point to use for a minimum.
Definition: polyMeshTetDecomposition.C:134
Foam::polyMeshTetDecomposition::findBasePoint
static label findBasePoint(const polyMesh &mesh, label fI, scalar tol, bool report=false)
Find the base point to use for a minimum triangle.
Definition: polyMeshTetDecomposition.C:189
Foam::Field< vector >
Foam::Info
messageStream Info
Information stream (stdout output on master, null elsewhere)
Foam::DynamicList::append
DynamicList< T, SizeMin > & append(const T &val)
Append an element to the end of this list.
Definition: DynamicListI.H:511
Foam::tetrahedron::quality
scalar quality() const
Return quality: Ratio of tetrahedron and circum-sphere.
Definition: tetrahedronI.H:232
Foam::FatalError
error FatalError
reduce
reduce(hasMovingMesh, orOp< bool >())
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
Foam::polyMeshTetDecomposition::findTet
static tetIndices findTet(const polyMesh &mesh, label cI, const point &pt)
Find the tet decomposition of the cell containing the given point.
Definition: polyMeshTetDecomposition.C:595
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Foam::maxEqOp
Definition: ops.H:80
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::polyMeshTetDecomposition::adjustTetBasePtIs
static labelList adjustTetBasePtIs(const polyMesh &mesh, const bool report=false)
Return an adjusted list of tet base points.
Definition: polyMeshTetDecomposition.C:637
Foam::tetIndices
Storage and named access for the indices of a tet which is part of the decomposition of a cell.
Definition: tetIndices.H:83
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:51
Foam::nl
constexpr char nl
Definition: Ostream.H:404
forAllConstIters
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
f
labelList f(nPoints)
Foam::Vector< scalar >
Foam::List< face >
Foam::HashSet::insert
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:191
patches
const polyBoundaryMesh & patches
Definition: convertProcessorPatches.H:65
Foam::polyMeshTetDecomposition::cellTetIndices
static List< tetIndices > cellTetIndices(const polyMesh &mesh, label cI)
Return the tet decomposition of the given cell, see.
Definition: polyMeshTetDecomposition.C:566
Foam::face
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:72
cells
const cellShapeList & cells
Definition: gmvOutputHeader.H:3
coupled
bool coupled(solutionDict.getOrDefault("coupledEnergyField", false))
Foam::polyMeshTetDecomposition::minQuality
static scalar minQuality(const polyMesh &mesh, const point &cC, const label fI, const bool isOwner, const label faceBasePtI)
Definition: polyMeshTetDecomposition.C:42
Foam::cell
A cell is defined as a list of faces with extra functionality.
Definition: cell.H:54
pFaces
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=cellModel::ref(cellModel::HEX);labelList hexLabels(8);label activeCells=0;labelList pointMap(nPoints);forAll(pointMap, i){ pointMap[i]=i;}for(label i=0;i< nPoints;i++){ if(f[i] > 0.0) { hexLabels[0]=i;hexLabels[1]=i1tab[i];hexLabels[2]=i3tab[i1tab[i]];hexLabels[3]=i3tab[i];hexLabels[4]=i8tab[i];hexLabels[5]=i1tab[i8tab[i]];hexLabels[6]=i3tab[i1tab[i8tab[i]]];hexLabels[7]=i3tab[i8tab[i]];cellShapes[activeCells].reset(hex, hexLabels);edgeList edges=cellShapes[activeCells].edges();forAll(edges, ei) { if(edges[ei].mag(points)< SMALL) { label start=pointMap[edges[ei].start()];while(start !=pointMap[start]) { start=pointMap[start];} label end=pointMap[edges[ei].end()];while(end !=pointMap[end]) { end=pointMap[end];} label minLabel=min(start, end);pointMap[start]=pointMap[end]=minLabel;} } cellZoning[activeCells]=idreg[i];activeCells++;}}cellShapes.setSize(activeCells);cellZoning.setSize(activeCells);forAll(cellShapes, celli){ cellShape &cs=cellShapes[celli];forAll(cs, i) { cs[i]=pointMap[cs[i]];} cs.collapse();}label bcIDs[11]={-1, 0, 2, 4, -1, 5, -1, 6, 7, 8, 9};const label nBCs=12;const word *kivaPatchTypes[nBCs]={ &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &symmetryPolyPatch::typeName, &wedgePolyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &symmetryPolyPatch::typeName, &oldCyclicPolyPatch::typeName};enum patchTypeNames{ PISTON, VALVE, LINER, CYLINDERHEAD, AXIS, WEDGE, INFLOW, OUTFLOW, PRESIN, PRESOUT, SYMMETRYPLANE, CYCLIC};const char *kivaPatchNames[nBCs]={ "piston", "valve", "liner", "cylinderHead", "axis", "wedge", "inflow", "outflow", "presin", "presout", "symmetryPlane", "cyclic"};List< SLList< face > > pFaces[nBCs]
Definition: readKivaGrid.H:235
Foam::tetrahedron
A tetrahedron primitive.
Definition: tetrahedron.H:63
Foam::polyMeshTetDecomposition::faceTetIndices
static List< tetIndices > faceTetIndices(const polyMesh &mesh, label fI, label cI)
Return the tet decomposition of the given face, with.
Definition: polyMeshTetDecomposition.C:542