primitiveMeshTools.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) 2012-2016 OpenFOAM Foundation
9  Copyright (C) 2017-2022 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 
29 #include "primitiveMeshTools.H"
30 #include "primitiveMesh.H"
31 #include "syncTools.H"
32 #include "pyramid.H"
33 #include "tetrahedron.H"
34 #include "PrecisionAdaptor.H"
35 
36 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
37 
39 (
40  const primitiveMesh& mesh,
41  const UList<label>& faceIDs,
42  const pointField& p,
43  vectorField& fCtrs,
44  vectorField& fAreas
45 )
46 {
47  const faceList& fs = mesh.faces();
48 
49  for (const label facei : faceIDs)
50  {
51  const labelList& f = fs[facei];
52  const label nPoints = f.size();
53 
54  // If the face is a triangle, do a direct calculation for efficiency
55  // and to avoid round-off error-related problems
56  if (nPoints == 3)
57  {
58  fCtrs[facei] = triPointRef::centre(p[f[0]], p[f[1]], p[f[2]]);
59  fAreas[facei] = triPointRef::areaNormal(p[f[0]], p[f[1]], p[f[2]]);
60  }
61  else
62  {
64 
65  solveVector sumN = Zero;
66  solveScalar sumA = 0.0;
67  solveVector sumAc = Zero;
68 
69  solveVector fCentre = p[f[0]];
70  for (label pi = 1; pi < nPoints; ++pi)
71  {
72  fCentre += solveVector(p[f[pi]]);
73  }
74 
75  fCentre /= nPoints;
76 
77  for (label pi = 0; pi < nPoints; ++pi)
78  {
79  const label nextPi(pi == nPoints-1 ? 0 : pi+1);
80  const solveVector nextPoint(p[f[nextPi]]);
81  const solveVector thisPoint(p[f[pi]]);
82 
83  solveVector c = thisPoint + nextPoint + fCentre;
84  solveVector n = (nextPoint - thisPoint)^(fCentre - thisPoint);
85  solveScalar a = mag(n);
86  sumN += n;
87  sumA += a;
88  sumAc += a*c;
89  }
90 
91  // This is to deal with zero-area faces. Mark very small faces
92  // to be detected in e.g., processorPolyPatch.
93  if (sumA < ROOTVSMALL)
94  {
95  fCtrs[facei] = fCentre;
96  fAreas[facei] = Zero;
97  }
98  else
99  {
100  fCtrs[facei] = (1.0/3.0)*sumAc/sumA;
101  fAreas[facei] = 0.5*sumN;
102  }
103  }
104  }
105 }
106 
107 
109 (
110  const primitiveMesh& mesh,
111  const vectorField& fCtrs,
112  const vectorField& fAreas,
113  const List<label>& cellIDs,
114  const List<cell>& cells,
115  vectorField& cellCtrs_s,
116  scalarField& cellVols_s
117 )
118 {
119  typedef Vector<solveScalar> solveVector;
120 
121  PrecisionAdaptor<solveVector, vector> tcellCtrs(cellCtrs_s, false);
122  PrecisionAdaptor<solveScalar, scalar> tcellVols(cellVols_s, false);
123  Field<solveVector>& cellCtrs = tcellCtrs.ref();
124  Field<solveScalar>& cellVols = tcellVols.ref();
125 
126 
127  // Use current cell centres as estimates for the new cell centres
128  // Note - not currently used
129  // - Introduces a small difference (seen when write precision extended to
130  // 16) to the cell centre and volume values, typically last 4 digits
131  //const vectorField Cc0(cellCtrs, cellIDs);
132 
133  // Estimate cell centres using current face centres
134  // - Same method as used by makeCellCentresAndVols()
135  vectorField Cc0(cellIDs.size(), Zero);
136  {
137  labelField nCellFaces(cellIDs.size(), Zero);
138  const auto& cells = mesh.cells();
139 
140  forAll(cellIDs, i)
141  {
142  const label celli = cellIDs[i];
143  const cell& c = cells[celli];
144  for (const auto facei : c)
145  {
146  Cc0[i] += fCtrs[facei];
147  ++nCellFaces[i];
148  }
149  }
150 
151  forAll(Cc0, i)
152  {
153  Cc0[i] /= nCellFaces[i];
154  }
155  }
156 
157  // Clear the fields for accumulation
158  for (const label celli : cellIDs)
159  {
160  cellCtrs[celli] = Zero;
161  cellVols[celli] = Zero;
162  }
163 
164  const auto& own = mesh.faceOwner();
165 
166  forAll(cellIDs, i)
167  {
168  const label celli = cellIDs[i];
169  const auto& c = cells[celli];
170  const solveVector cc(Cc0[i]);
171 
172  for (const label facei : c)
173  {
174  const solveVector fc(fCtrs[facei]);
175  const solveVector fA(fAreas[facei]);
176 
177  const solveScalar pyr3Vol = own[facei] == celli
178  ? fA & (fc - cc)
179  : fA & (cc - fc);
180 
181  // Calculate face-pyramid centre
182  const solveVector pc = (3.0/4.0)*fc + (1.0/4.0)*cc;
183 
184  // Accumulate volume-weighted face-pyramid centre
185  cellCtrs[celli] += pyr3Vol*pc;
186 
187  // Accumulate face-pyramid volume
188  cellVols[celli] += pyr3Vol;
189  }
190 
191  if (mag(cellVols[celli]) > VSMALL)
192  {
193  cellCtrs[celli] /= cellVols[celli];
194  cellVols[celli] *= (1.0/3.0);
195  }
196  else
197  {
198  cellCtrs[celli] = Cc0[i];
199  }
200  }
201 }
202 
203 
205 (
206  const UList<face>& fcs,
207  const pointField& p,
208  vectorField& fCtrs,
209  vectorField& fAreas
210 )
211 {
212  // Safety first - ensure properly sized
213  fCtrs.resize_nocopy(fcs.size());
214  fAreas.resize_nocopy(fcs.size());
215 
216  forAll(fcs, facei)
217  {
218  const face& f = fcs[facei];
219  const label nPoints = f.size();
220 
221  // If the face is a triangle, do a direct calculation for efficiency
222  // and to avoid round-off error-related problems
223  if (nPoints == 3)
224  {
225  fCtrs[facei] = triPointRef::centre(p[f[0]], p[f[1]], p[f[2]]);
226  fAreas[facei] = triPointRef::areaNormal(p[f[0]], p[f[1]], p[f[2]]);
227  }
228  else
229  {
230  solveVector sumN = Zero;
231  solveScalar sumA = Zero;
232  solveVector sumAc = Zero;
233 
234  solveVector fCentre = p[f[0]];
235  for (label pi = 1; pi < nPoints; ++pi)
236  {
237  fCentre += solveVector(p[f[pi]]);
238  }
239  fCentre /= nPoints;
240 
241  for (label pi = 0; pi < nPoints; ++pi)
242  {
243  const solveVector thisPoint(p[f.thisLabel(pi)]);
244  const solveVector nextPoint(p[f.nextLabel(pi)]);
245 
246  solveVector c = thisPoint + nextPoint + fCentre;
247  solveVector n = (nextPoint - thisPoint)^(fCentre - thisPoint);
248  solveScalar a = mag(n);
249 
250  sumN += n;
251  sumA += a;
252  sumAc += a*c;
253  }
254 
255  // This is to deal with zero-area faces. Mark very small faces
256  // to be detected in e.g., processorPolyPatch.
257  if (sumA < ROOTVSMALL)
258  {
259  fCtrs[facei] = fCentre;
260  fAreas[facei] = Zero;
261  }
262  else
263  {
264  fCtrs[facei] = (1.0/3.0)*sumAc/sumA;
265  fAreas[facei] = 0.5*sumN;
266  }
267  }
268  }
269 }
270 
271 
273 (
274  const primitiveMesh& mesh,
275  const pointField& p,
276  vectorField& fCtrs,
277  vectorField& fAreas
278 )
279 {
280  makeFaceCentresAndAreas(mesh.faces(), p, fCtrs, fAreas);
281 }
282 
283 
285 (
286  const primitiveMesh& mesh,
287  const vectorField& fCtrs,
288  const vectorField& fAreas,
289  vectorField& cellCtrs_s,
290  scalarField& cellVols_s
291 )
292 {
293  PrecisionAdaptor<solveVector, vector> tcellCtrs(cellCtrs_s, false);
294  PrecisionAdaptor<solveScalar, scalar> tcellVols(cellVols_s, false);
295  Field<solveVector>& cellCtrs = tcellCtrs.ref();
296  Field<solveScalar>& cellVols = tcellVols.ref();
297 
298  // Clear the fields for accumulation
299  cellCtrs = Zero;
300  cellVols = Zero;
301 
302  const labelList& own = mesh.faceOwner();
303  const labelList& nei = mesh.faceNeighbour();
304 
305  // first estimate the approximate cell centre as the average of
306  // face centres
307 
309  labelField nCellFaces(mesh.nCells(), Zero);
310 
311  forAll(own, facei)
312  {
313  cEst[own[facei]] += solveVector(fCtrs[facei]);
314  ++nCellFaces[own[facei]];
315  }
316 
317  forAll(nei, facei)
318  {
319  cEst[nei[facei]] += solveVector(fCtrs[facei]);
320  ++nCellFaces[nei[facei]];
321  }
322 
323  forAll(cEst, celli)
324  {
325  cEst[celli] /= nCellFaces[celli];
326  }
327 
328  forAll(own, facei)
329  {
330  const solveVector fc(fCtrs[facei]);
331  const solveVector fA(fAreas[facei]);
332 
333  // Calculate 3*face-pyramid volume
334  solveScalar pyr3Vol = fA & (fc - cEst[own[facei]]);
335 
336  // Calculate face-pyramid centre
337  solveVector pc = (3.0/4.0)*fc + (1.0/4.0)*cEst[own[facei]];
338 
339  // Accumulate volume-weighted face-pyramid centre
340  cellCtrs[own[facei]] += pyr3Vol*pc;
341 
342  // Accumulate face-pyramid volume
343  cellVols[own[facei]] += pyr3Vol;
344  }
345 
346  forAll(nei, facei)
347  {
348  const solveVector fc(fCtrs[facei]);
349  const solveVector fA(fAreas[facei]);
350 
351  // Calculate 3*face-pyramid volume
352  solveScalar pyr3Vol = fA & (cEst[nei[facei]] - fc);
353 
354  // Calculate face-pyramid centre
355  solveVector pc = (3.0/4.0)*fc + (1.0/4.0)*cEst[nei[facei]];
356 
357  // Accumulate volume-weighted face-pyramid centre
358  cellCtrs[nei[facei]] += pyr3Vol*pc;
359 
360  // Accumulate face-pyramid volume
361  cellVols[nei[facei]] += pyr3Vol;
362  }
363 
364  forAll(cellCtrs, celli)
365  {
366  if (mag(cellVols[celli]) > VSMALL)
367  {
368  cellCtrs[celli] /= cellVols[celli];
369  }
370  else
371  {
372  cellCtrs[celli] = cEst[celli];
373  }
374  }
375 
376  cellVols *= (1.0/3.0);
377 }
378 
379 
381 (
382  const UList<face>& fcs,
383  const pointField& p,
384  const vectorField& fCtrs,
385  const vectorField& fAreas,
386 
387  const label facei,
388  const point& ownCc,
389  const point& neiCc
390 )
391 {
392  const face& f = fcs[facei];
393 
394  vector Cpf = fCtrs[facei] - ownCc;
395  vector d = neiCc - ownCc;
396 
397  // Skewness vector
398  vector sv =
399  Cpf
400  - ((fAreas[facei] & Cpf)/((fAreas[facei] & d) + ROOTVSMALL))*d;
401  vector svHat = sv/(mag(sv) + ROOTVSMALL);
402 
403  // Normalisation distance calculated as the approximate distance
404  // from the face centre to the edge of the face in the direction
405  // of the skewness
406  scalar fd = 0.2*mag(d) + ROOTVSMALL;
407  forAll(f, pi)
408  {
409  fd = max(fd, mag(svHat & (p[f[pi]] - fCtrs[facei])));
410  }
412  // Normalised skewness
413  return mag(sv)/fd;
414 }
415 
416 
418 (
419  const UList<face>& fcs,
420  const pointField& p,
421  const vectorField& fCtrs,
422  const vectorField& fAreas,
423 
424  const label facei,
425  const point& ownCc
426 )
427 {
428  const face& f = fcs[facei];
429 
430  vector Cpf = fCtrs[facei] - ownCc;
431 
432  vector normal = normalised(fAreas[facei]);
433  vector d = normal*(normal & Cpf);
434 
435  // Skewness vector
436  vector sv =
437  Cpf
438  - ((fAreas[facei] & Cpf)/((fAreas[facei] & d) + ROOTVSMALL))*d;
439  vector svHat = sv/(mag(sv) + ROOTVSMALL);
440 
441  // Normalisation distance calculated as the approximate distance
442  // from the face centre to the edge of the face in the direction
443  // of the skewness
444  scalar fd = 0.4*mag(d) + ROOTVSMALL;
445  forAll(f, pi)
446  {
447  fd = max(fd, mag(svHat & (p[f[pi]] - fCtrs[facei])));
448  }
450  // Normalised skewness
451  return mag(sv)/fd;
452 }
453 
454 
456 (
457  const primitiveMesh& mesh,
458  const pointField& p,
459  const vectorField& fCtrs,
460  const vectorField& fAreas,
461 
462  const label facei,
463  const point& ownCc,
464  const point& neiCc
465 )
466 {
467  return faceSkewness(mesh.faces(), p, fCtrs, fAreas, facei, ownCc, neiCc);
468 }
469 
470 
472 (
473  const primitiveMesh& mesh,
474  const pointField& p,
475  const vectorField& fCtrs,
476  const vectorField& fAreas,
477 
478  const label facei,
479  const point& ownCc
480 )
481 {
482  return boundaryFaceSkewness(mesh.faces(), p, fCtrs, fAreas, facei, ownCc);
483 }
484 
485 
487 (
488  const point& ownCc,
489  const point& neiCc,
490  const vector& s
491 )
492 {
493  vector d = neiCc - ownCc;
494 
495  return (d & s)/(mag(d)*mag(s) + ROOTVSMALL);
496 }
497 
498 
499 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
500 
502 (
503  const primitiveMesh& mesh,
504  const vectorField& areas,
505  const vectorField& cc
506 )
507 {
508  const labelList& own = mesh.faceOwner();
509  const labelList& nei = mesh.faceNeighbour();
510 
511  auto tortho = tmp<scalarField>::New(mesh.nInternalFaces());
512  auto& ortho = tortho.ref();
513 
514  // Internal faces
515  forAll(nei, facei)
516  {
517  ortho[facei] = faceOrthogonality
518  (
519  cc[own[facei]],
520  cc[nei[facei]],
521  areas[facei]
522  );
523  }
524 
525  return tortho;
526 }
527 
528 
530 (
531  const primitiveMesh& mesh,
532  const pointField& p,
533  const vectorField& fCtrs,
534  const vectorField& fAreas,
535  const vectorField& cellCtrs
536 )
537 {
538  const labelList& own = mesh.faceOwner();
539  const labelList& nei = mesh.faceNeighbour();
540  const faceList& faces = mesh.faces();
541 
542  auto tskew = tmp<scalarField>::New(mesh.nFaces());
543  auto& skew = tskew.ref();
544 
545  // Internal faces
546  for (label facei = 0; facei < mesh.nInternalFaces(); ++facei)
547  {
548  skew[facei] = faceSkewness
549  (
550  faces,
551  p,
552  fCtrs,
553  fAreas,
554 
555  facei,
556  cellCtrs[own[facei]],
557  cellCtrs[nei[facei]]
558  );
559  }
560 
561 
562  // Boundary faces: consider them to have only skewness error.
563  // (i.e. treat as if mirror cell on other side)
564 
565  for (label facei = mesh.nInternalFaces(); facei < mesh.nFaces(); ++facei)
566  {
567  skew[facei] = boundaryFaceSkewness
568  (
569  faces,
570  p,
571  fCtrs,
572  fAreas,
573  facei,
574  cellCtrs[own[facei]]
575  );
576  }
577 
578  return tskew;
579 }
580 
581 
583 (
584  const primitiveMesh& mesh,
585  const pointField& points,
586  const vectorField& ctrs,
587 
588  scalarField& ownPyrVol,
589  scalarField& neiPyrVol
590 )
591 {
592  const labelList& own = mesh.faceOwner();
593  const labelList& nei = mesh.faceNeighbour();
594  const faceList& f = mesh.faces();
595 
596  ownPyrVol.setSize(mesh.nFaces());
597  neiPyrVol.setSize(mesh.nInternalFaces());
598 
599  forAll(f, facei)
600  {
601  // Create the owner pyramid
602  ownPyrVol[facei] = -pyramidPointFaceRef
603  (
604  f[facei],
605  ctrs[own[facei]]
606  ).mag(points);
607 
608  if (mesh.isInternalFace(facei))
609  {
610  // Create the neighbour pyramid - it will have positive volume
611  neiPyrVol[facei] = pyramidPointFaceRef
612  (
613  f[facei],
614  ctrs[nei[facei]]
615  ).mag(points);
616  }
617  }
618 }
619 
620 
622 (
623  const primitiveMesh& mesh,
624  const Vector<label>& meshD,
625  const vectorField& areas,
626  const scalarField& vols,
627 
628  scalarField& openness,
629  scalarField& aratio
630 )
631 {
632  const labelList& own = mesh.faceOwner();
633  const labelList& nei = mesh.faceNeighbour();
634 
635  // Loop through cell faces and sum up the face area vectors for each cell.
636  // This should be zero in all vector components
637 
638  vectorField sumClosed(mesh.nCells(), Zero);
639  vectorField sumMagClosed(mesh.nCells(), Zero);
640 
641  forAll(own, facei)
642  {
643  // Add to owner
644  sumClosed[own[facei]] += areas[facei];
645  sumMagClosed[own[facei]] += cmptMag(areas[facei]);
646  }
647 
648  forAll(nei, facei)
649  {
650  // Subtract from neighbour
651  sumClosed[nei[facei]] -= areas[facei];
652  sumMagClosed[nei[facei]] += cmptMag(areas[facei]);
653  }
654 
655 
656  label nDims = 0;
657  for (direction dir = 0; dir < vector::nComponents; dir++)
658  {
659  if (meshD[dir] == 1)
660  {
661  nDims++;
662  }
663  }
664 
665 
666  // Check the sums
667  openness.setSize(mesh.nCells());
668  aratio.setSize(mesh.nCells());
669 
670  forAll(sumClosed, celli)
671  {
672  scalar maxOpenness = 0;
673 
674  for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
675  {
676  maxOpenness = max
677  (
678  maxOpenness,
679  mag(sumClosed[celli][cmpt])
680  /(sumMagClosed[celli][cmpt] + ROOTVSMALL)
681  );
682  }
683  openness[celli] = maxOpenness;
684 
685  // Calculate the aspect ration as the maximum of Cartesian component
686  // aspect ratio to the total area hydraulic area aspect ratio
687  scalar minCmpt = VGREAT;
688  scalar maxCmpt = -VGREAT;
689  for (direction dir = 0; dir < vector::nComponents; dir++)
690  {
691  if (meshD[dir] == 1)
692  {
693  minCmpt = min(minCmpt, sumMagClosed[celli][dir]);
694  maxCmpt = max(maxCmpt, sumMagClosed[celli][dir]);
695  }
696  }
697 
698  scalar aspectRatio = maxCmpt/(minCmpt + ROOTVSMALL);
699  if (nDims == 3)
700  {
701  scalar v = max(ROOTVSMALL, vols[celli]);
702 
703  aspectRatio = max
704  (
705  aspectRatio,
706  1.0/6.0*cmptSum(sumMagClosed[celli])/pow(v, 2.0/3.0)
707  );
708  }
710  aratio[celli] = aspectRatio;
711  }
712 }
713 
714 
716 (
717  const scalar maxSin,
718  const primitiveMesh& mesh,
719  const pointField& p,
720  const vectorField& faceAreas
721 )
722 {
723  const faceList& fcs = mesh.faces();
724 
725  vectorField faceNormals(faceAreas);
726  faceNormals /= mag(faceNormals) + ROOTVSMALL;
727 
728  auto tfaceAngles = tmp<scalarField>::New(mesh.nFaces());
729  auto&& faceAngles = tfaceAngles.ref();
730 
731  forAll(fcs, facei)
732  {
733  const face& f = fcs[facei];
734 
735  // Normalized vector from f[size-1] to f[0];
736  vector ePrev(p[f.first()] - p[f.last()]);
737  scalar magEPrev = mag(ePrev);
738  ePrev /= magEPrev + ROOTVSMALL;
739 
740  scalar maxEdgeSin = 0.0;
741 
742  forAll(f, fp0)
743  {
744  // Normalized vector between two consecutive points
745  vector e10(p[f.nextLabel(fp0)] - p[f.thisLabel(fp0)]);
746  scalar magE10 = mag(e10);
747  e10 /= magE10 + ROOTVSMALL;
748 
749  if (magEPrev > SMALL && magE10 > SMALL)
750  {
751  vector edgeNormal = ePrev ^ e10;
752  scalar magEdgeNormal = mag(edgeNormal);
753 
754  if (magEdgeNormal < maxSin)
755  {
756  // Edges (almost) aligned -> face is ok.
757  }
758  else
759  {
760  // Check normal
761  edgeNormal /= magEdgeNormal;
762 
763  if ((edgeNormal & faceNormals[facei]) < SMALL)
764  {
765  maxEdgeSin = max(maxEdgeSin, magEdgeNormal);
766  }
767  }
768  }
769 
770  ePrev = e10;
771  magEPrev = magE10;
772  }
773 
774  faceAngles[facei] = maxEdgeSin;
775  }
776 
777  return tfaceAngles;
778 }
779 
780 
782 (
783  const primitiveMesh& mesh,
784  const pointField& p,
785  const vectorField& fCtrs,
786  const vectorField& faceAreas
787 )
788 {
789  const faceList& fcs = mesh.faces();
790 
791  // Areas are calculated as the sum of areas. (see
792  // primitiveMeshFaceCentresAndAreas.C)
793  scalarField magAreas(mag(faceAreas));
794 
795  auto tfaceFlatness = tmp<scalarField>::New(mesh.nFaces(), scalar(1));
796  auto& faceFlatness = tfaceFlatness.ref();
797 
798  forAll(fcs, facei)
799  {
800  const face& f = fcs[facei];
801 
802  if (f.size() > 3 && magAreas[facei] > ROOTVSMALL)
803  {
804  const solveVector fc = fCtrs[facei];
805 
806  // Calculate the sum of magnitude of areas and compare to magnitude
807  // of sum of areas.
808 
809  solveScalar sumA = 0.0;
810 
811  forAll(f, fp)
812  {
813  const solveVector thisPoint = p[f[fp]];
814  const solveVector nextPoint = p[f.nextLabel(fp)];
815 
816  // Triangle around fc.
817  solveVector n = 0.5*((nextPoint - thisPoint)^(fc - thisPoint));
818  sumA += mag(n);
819  }
820 
821  faceFlatness[facei] = magAreas[facei]/(sumA + ROOTVSMALL);
822  }
823  }
824 
825  return tfaceFlatness;
826 }
827 
828 
830 (
831  const primitiveMesh& mesh,
832  const Vector<label>& meshD,
833  const vectorField& faceAreas,
834  const bitSet& internalOrCoupledFace
835 )
836 {
837  // Determine number of dimensions and (for 2D) missing dimension
838  label nDims = 0;
839  label twoD = -1;
840  for (direction dir = 0; dir < vector::nComponents; dir++)
841  {
842  if (meshD[dir] == 1)
843  {
844  nDims++;
845  }
846  else
847  {
848  twoD = dir;
849  }
850  }
851 
852  auto tcellDeterminant = tmp<scalarField>::New(mesh.nCells());
853  auto& cellDeterminant = tcellDeterminant.ref();
854 
855  const cellList& c = mesh.cells();
856 
857  if (nDims == 1)
858  {
859  cellDeterminant = 1.0;
860  }
861  else
862  {
863  forAll(c, celli)
864  {
865  const labelList& curFaces = c[celli];
866 
867  // Calculate local normalization factor
868  scalar avgArea = 0;
869 
870  label nInternalFaces = 0;
871 
872  forAll(curFaces, i)
873  {
874  if (internalOrCoupledFace.test(curFaces[i]))
875  {
876  avgArea += mag(faceAreas[curFaces[i]]);
877 
878  nInternalFaces++;
879  }
880  }
881 
882  if (nInternalFaces == 0 || avgArea < ROOTVSMALL)
883  {
884  cellDeterminant[celli] = 0;
885  }
886  else
887  {
888  avgArea /= nInternalFaces;
889 
890  symmTensor areaTensor(Zero);
891 
892  forAll(curFaces, i)
893  {
894  if (internalOrCoupledFace.test(curFaces[i]))
895  {
896  areaTensor += sqr(faceAreas[curFaces[i]]/avgArea);
897  }
898  }
899 
900  if (nDims == 2)
901  {
902  // Add the missing eigenvector (such that it does not
903  // affect the determinant)
904  if (twoD == 0)
905  {
906  areaTensor.xx() = 1;
907  }
908  else if (twoD == 1)
909  {
910  areaTensor.yy() = 1;
911  }
912  else
913  {
914  areaTensor.zz() = 1;
915  }
916  }
917 
918  // Note:
919  // - normalise to be 0..1 (since cube has eigenvalues 2 2 2)
920  // - we use the determinant (i.e. 3rd invariant) and not e.g.
921  // condition number (= max ev / min ev) since we are
922  // interested in the minimum connectivity and not the
923  // uniformity. Using the condition number on corner cells
924  // leads to uniformity 1 i.e. equally bad in all three
925  // directions which is not what we want.
926  cellDeterminant[celli] = mag(det(areaTensor))/8.0;
927  }
928  }
929  }
930 
931  return tcellDeterminant;
932 }
933 
934 
935 // ************************************************************************* //
Field< label > labelField
Specialisation of Field<T> for label.
Definition: labelField.H:48
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
uint8_t direction
Definition: direction.H:46
static void updateCellCentresAndVols(const primitiveMesh &mesh, const vectorField &fCtrs, const vectorField &fAreas, const List< label > &cellIDs, const List< cell > &cells, vectorField &cellCtrs_s, scalarField &cellVols_s)
Update cell centres and volumes for the cells in the set cellIDs.
List< cell > cellList
List of cell.
Definition: cellListFwd.H:39
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:68
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Cmpt cmptSum(const SphericalTensor< Cmpt > &st)
Return the sum of components of a SphericalTensor.
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1122
dimensionedTensor skew(const dimensionedTensor &dt)
Cell-face mesh analysis engine.
Definition: primitiveMesh.H:75
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
dimensionedSymmTensor sqr(const dimensionedVector &dv)
T & first()
Access first element of the list, position [0].
Definition: UList.H:853
const cellList & cells() const
::Foam::direction nComponents(const expressions::valueTypeCode) noexcept
The number of components associated with given valueTypeCode.
Definition: exprTraits.C:40
dimensionedScalar det(const dimensionedSphericalTensor &dt)
quaternion normalised(const quaternion &q)
Return the normalised (unit) quaternion of the given quaternion.
Definition: quaternionI.H:674
A non-const Field/List wrapper with possible data conversion.
label nFaces() const noexcept
Number of mesh faces.
static tmp< scalarField > faceConcavity(const scalar maxSin, const primitiveMesh &mesh, const pointField &p, const vectorField &faceAreas)
Generate face concavity field. Returns per face the (sin of the) most concave angle between two conse...
bool isInternalFace(const label faceIndex) const noexcept
Return true if given face label is internal to the mesh.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
pyramid< point, const point &, const face & > pyramidPointFaceRef
A pyramid using referred point and face.
Definition: pyramid.H:70
Vector< solveScalar > solveVector
Definition: vector.H:60
List< face > faceList
List of faces.
Definition: faceListFwd.H:39
static tmp< scalarField > faceSkewness(const primitiveMesh &mesh, const pointField &points, const vectorField &fCtrs, const vectorField &fAreas, const vectorField &cellCtrs)
Generate skewness field.
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
void setSize(const label n)
Alias for resize()
Definition: List.H:316
dynamicFvMesh & mesh
const cellShapeList & cells
const pointField & points
SymmTensor< scalar > symmTensor
SymmTensor of scalars, i.e. SymmTensor<scalar>.
Definition: symmTensor.H:55
label nPoints
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1116
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:206
Point centre() const
Return centre (centroid)
Definition: triangleI.H:126
constexpr scalar pi(M_PI)
label nInternalFaces() const noexcept
Number of internal faces.
Vector< scalar > vector
Definition: vector.H:57
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1103
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
Templated 3D Vector derived from VectorSpace adding construction from 3 components, element access using x(), y() and z() member functions and the inner-product (dot-product) and cross-product operators.
Definition: Vector.H:58
void cmptMag(FieldField< Field, Type > &cf, const FieldField< Field, Type > &f)
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
static void facePyramidVolume(const primitiveMesh &mesh, const pointField &points, const vectorField &cellCtrs, scalarField &ownPyrVol, scalarField &neiPyrVol)
Generate face pyramid volume fields.
static tmp< scalarField > cellDeterminant(const primitiveMesh &mesh, const Vector< label > &directions, const vectorField &faceAreas, const bitSet &internalOrCoupledFace)
Generate cell determinant field. Normalised to 1 for an internal cube.
labelList f(nPoints)
const scalarField & cellVols
T & last()
Access last element of the list, position [size()-1].
Definition: UList.H:867
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
static scalar boundaryFaceSkewness(const UList< face > &faces, const pointField &p, const vectorField &fCtrs, const vectorField &fAreas, const label facei, const point &ownCc)
Skewness of single boundary face.
vector point
Point is a vector.
Definition: point.H:37
static void makeFaceCentresAndAreas(const UList< face > &faces, const pointField &p, vectorField &fCtrs, vectorField &fAreas)
Calculate face centres and areas for specified faces.
label nCells() const noexcept
Number of mesh cells.
const dimensionedScalar c
Speed of light in a vacuum.
label n
Field< vector > vectorField
Specialisation of Field<T> for vector.
static void makeCellCentresAndVols(const primitiveMesh &mesh, const vectorField &fCtrs, const vectorField &fAreas, vectorField &cellCtrs, scalarField &cellVols)
Calculate cell centres and volumes from face properties.
static tmp< scalarField > faceOrthogonality(const primitiveMesh &mesh, const vectorField &fAreas, const vectorField &cellCtrs)
Generate non-orthogonality field (internal faces only)
List< label > labelList
A List of labels.
Definition: List.H:62
volScalarField & p
A class for managing temporary objects.
Definition: HashPtrTable.H:50
static void cellClosedness(const primitiveMesh &mesh, const Vector< label > &meshD, const vectorField &areas, const scalarField &vols, scalarField &openness, scalarField &aratio)
Generate cell openness and cell aspect ratio field.
static tmp< scalarField > faceFlatness(const primitiveMesh &mesh, const pointField &p, const vectorField &fCtrs, const vectorField &faceAreas)
Generate face flatness field. Compares the individual triangles&#39; normals against the face average nor...
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
labelList cellIDs
static void updateFaceCentresAndAreas(const primitiveMesh &mesh, const UList< label > &faceIDs, const pointField &p, vectorField &fCtrs, vectorField &fAreas)
Update face centres and areas for the faces in the set faceIDs.
vector areaNormal() const
The area normal - with magnitude equal to area of triangle.
Definition: triangleI.H:151
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127