primitiveMeshGeometry.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 | Copyright (C) 2011-2012 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 "primitiveMeshGeometry.H"
27 #include "pyramidPointFaceRef.H"
28 #include "unitConversion.H"
29 #include "triPointRef.H"
30 
31 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
32 
33 namespace Foam
34 {
35  defineTypeNameAndDebug(primitiveMeshGeometry, 0);
36 }
37 
38 
39 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
40 
41 void Foam::primitiveMeshGeometry::updateFaceCentresAndAreas
42 (
43  const pointField& p,
44  const labelList& changedFaces
45 )
46 {
47  const faceList& fs = mesh_.faces();
48 
49  forAll(changedFaces, i)
50  {
51  label facei = changedFaces[i];
52 
53  const labelList& f = fs[facei];
54  label nPoints = f.size();
55 
56  // If the face is a triangle, do a direct calculation for efficiency
57  // and to avoid round-off error-related problems
58  if (nPoints == 3)
59  {
60  faceCentres_[facei] = (1.0/3.0)*(p[f[0]] + p[f[1]] + p[f[2]]);
61  faceAreas_[facei] = 0.5*((p[f[1]] - p[f[0]])^(p[f[2]] - p[f[0]]));
62  }
63  else
64  {
65  vector sumN = vector::zero;
66  scalar sumA = 0.0;
67  vector sumAc = vector::zero;
68 
69  point fCentre = p[f[0]];
70  for (label pi = 1; pi < nPoints; pi++)
71  {
72  fCentre += p[f[pi]];
73  }
74 
75  fCentre /= nPoints;
76 
77  for (label pi = 0; pi < nPoints; pi++)
78  {
79  const point& nextPoint = p[f[(pi + 1) % nPoints]];
80 
81  vector c = p[f[pi]] + nextPoint + fCentre;
82  vector n = (nextPoint - p[f[pi]])^(fCentre - p[f[pi]]);
83  scalar a = mag(n);
84 
85  sumN += n;
86  sumA += a;
87  sumAc += a*c;
88  }
89 
90  faceCentres_[facei] = (1.0/3.0)*sumAc/(sumA + VSMALL);
91  faceAreas_[facei] = 0.5*sumN;
92  }
93  }
94 }
95 
96 
97 void Foam::primitiveMeshGeometry::updateCellCentresAndVols
98 (
99  const labelList& changedCells,
100  const labelList& changedFaces
101 )
102 {
103  // Clear the fields for accumulation
104  UIndirectList<vector>(cellCentres_, changedCells) = vector::zero;
105  UIndirectList<scalar>(cellVolumes_, changedCells) = 0.0;
106 
107  const labelList& own = mesh_.faceOwner();
108  const labelList& nei = mesh_.faceNeighbour();
109 
110  // first estimate the approximate cell centre as the average of face centres
111 
112  vectorField cEst(mesh_.nCells());
113  UIndirectList<vector>(cEst, changedCells) = vector::zero;
114  scalarField nCellFaces(mesh_.nCells());
115  UIndirectList<scalar>(nCellFaces, changedCells) = 0.0;
116 
117  forAll(changedFaces, i)
118  {
119  label faceI = changedFaces[i];
120  cEst[own[faceI]] += faceCentres_[faceI];
121  nCellFaces[own[faceI]] += 1;
122 
123  if (mesh_.isInternalFace(faceI))
124  {
125  cEst[nei[faceI]] += faceCentres_[faceI];
126  nCellFaces[nei[faceI]] += 1;
127  }
128  }
129 
130  forAll(changedCells, i)
131  {
132  label cellI = changedCells[i];
133  cEst[cellI] /= nCellFaces[cellI];
134  }
135 
136  forAll(changedFaces, i)
137  {
138  label faceI = changedFaces[i];
139 
140  // Calculate 3*face-pyramid volume
141  scalar pyr3Vol = max
142  (
143  faceAreas_[faceI] & (faceCentres_[faceI] - cEst[own[faceI]]),
144  VSMALL
145  );
146 
147  // Calculate face-pyramid centre
148  vector pc = (3.0/4.0)*faceCentres_[faceI] + (1.0/4.0)*cEst[own[faceI]];
149 
150  // Accumulate volume-weighted face-pyramid centre
151  cellCentres_[own[faceI]] += pyr3Vol*pc;
152 
153  // Accumulate face-pyramid volume
154  cellVolumes_[own[faceI]] += pyr3Vol;
155 
156  if (mesh_.isInternalFace(faceI))
157  {
158  // Calculate 3*face-pyramid volume
159  scalar pyr3Vol = max
160  (
161  faceAreas_[faceI] & (cEst[nei[faceI]] - faceCentres_[faceI]),
162  VSMALL
163  );
164 
165  // Calculate face-pyramid centre
166  vector pc =
167  (3.0/4.0)*faceCentres_[faceI]
168  + (1.0/4.0)*cEst[nei[faceI]];
169 
170  // Accumulate volume-weighted face-pyramid centre
171  cellCentres_[nei[faceI]] += pyr3Vol*pc;
172 
173  // Accumulate face-pyramid volume
174  cellVolumes_[nei[faceI]] += pyr3Vol;
175  }
176  }
177 
178  forAll(changedCells, i)
179  {
180  label cellI = changedCells[i];
181 
182  cellCentres_[cellI] /= cellVolumes_[cellI];
183  cellVolumes_[cellI] *= (1.0/3.0);
184  }
185 }
186 
187 
189 (
190  const labelList& changedFaces
191 ) const
192 {
193  const labelList& own = mesh_.faceOwner();
194  const labelList& nei = mesh_.faceNeighbour();
195 
196  labelHashSet affectedCells(2*changedFaces.size());
197 
198  forAll(changedFaces, i)
199  {
200  label faceI = changedFaces[i];
201 
202  affectedCells.insert(own[faceI]);
203 
204  if (mesh_.isInternalFace(faceI))
205  {
206  affectedCells.insert(nei[faceI]);
207  }
208  }
209  return affectedCells.toc();
210 }
211 
212 
213 
214 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
215 
216 // Construct from components
218 (
219  const primitiveMesh& mesh
220 )
221 :
222  mesh_(mesh)
223 {
224  correct();
225 }
226 
227 
228 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
229 
230 
231 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
232 
233 //- Take over properties from mesh
235 {
236  faceAreas_ = mesh_.faceAreas();
237  faceCentres_ = mesh_.faceCentres();
238  cellCentres_ = mesh_.cellCentres();
239  cellVolumes_ = mesh_.cellVolumes();
240 }
241 
242 
243 //- Recalculate on selected faces
245 (
246  const pointField& p,
247  const labelList& changedFaces
248 )
249 {
250  // Update face quantities
251  updateFaceCentresAndAreas(p, changedFaces);
252  // Update cell quantities from face quantities
253  updateCellCentresAndVols(affectedCells(changedFaces), changedFaces);
254 }
255 
256 
258 (
259  const bool report,
260  const scalar orthWarn,
261  const primitiveMesh& mesh,
262  const vectorField& cellCentres,
263  const vectorField& faceAreas,
264  const labelList& checkFaces,
265  labelHashSet* setPtr
266 )
267 {
268  // for all internal faces check theat the d dot S product is positive
269 
270  const labelList& own = mesh.faceOwner();
271  const labelList& nei = mesh.faceNeighbour();
272 
273  // Severe nonorthogonality threshold
274  const scalar severeNonorthogonalityThreshold = ::cos(degToRad(orthWarn));
275 
276  scalar minDDotS = GREAT;
277 
278  scalar sumDDotS = 0;
279 
280  label severeNonOrth = 0;
281 
282  label errorNonOrth = 0;
283 
284  forAll(checkFaces, i)
285  {
286  label faceI = checkFaces[i];
287 
288  if (mesh.isInternalFace(faceI))
289  {
290  vector d = cellCentres[nei[faceI]] - cellCentres[own[faceI]];
291  const vector& s = faceAreas[faceI];
292 
293  scalar dDotS = (d & s)/(mag(d)*mag(s) + VSMALL);
294 
295  if (dDotS < severeNonorthogonalityThreshold)
296  {
297  if (dDotS > SMALL)
298  {
299  if (report)
300  {
301  // Severe non-orthogonality but mesh still OK
302  Pout<< "Severe non-orthogonality for face " << faceI
303  << " between cells " << own[faceI]
304  << " and " << nei[faceI]
305  << ": Angle = " << radToDeg(::acos(dDotS))
306  << " deg." << endl;
307  }
308 
309  if (setPtr)
310  {
311  setPtr->insert(faceI);
312  }
313 
314  severeNonOrth++;
315  }
316  else
317  {
318  // Non-orthogonality greater than 90 deg
319  if (report)
320  {
321  WarningIn
322  (
323  "primitiveMeshGeometry::checkFaceDotProduct"
324  "(const bool, const scalar, const labelList&"
325  ", labelHashSet*)"
326  ) << "Severe non-orthogonality detected for face "
327  << faceI
328  << " between cells " << own[faceI] << " and "
329  << nei[faceI]
330  << ": Angle = " << radToDeg(::acos(dDotS))
331  << " deg." << endl;
332  }
333 
334  errorNonOrth++;
335 
336  if (setPtr)
337  {
338  setPtr->insert(faceI);
339  }
340  }
341  }
342 
343  if (dDotS < minDDotS)
344  {
345  minDDotS = dDotS;
346  }
347 
348  sumDDotS += dDotS;
349  }
350  }
351 
352  reduce(minDDotS, minOp<scalar>());
353  reduce(sumDDotS, sumOp<scalar>());
354  reduce(severeNonOrth, sumOp<label>());
355  reduce(errorNonOrth, sumOp<label>());
356 
357  label neiSize = nei.size();
358  reduce(neiSize, sumOp<label>());
359 
360  // Only report if there are some internal faces
361  if (neiSize > 0)
362  {
363  if (report && minDDotS < severeNonorthogonalityThreshold)
364  {
365  Info<< "Number of non-orthogonality errors: " << errorNonOrth
366  << ". Number of severely non-orthogonal faces: "
367  << severeNonOrth << "." << endl;
368  }
369  }
370 
371  if (report)
372  {
373  if (neiSize > 0)
374  {
375  Info<< "Mesh non-orthogonality Max: "
376  << radToDeg(::acos(minDDotS))
377  << " average: " << radToDeg(::acos(sumDDotS/neiSize))
378  << endl;
379  }
380  }
381 
382  if (errorNonOrth > 0)
383  {
384  if (report)
385  {
387  (
388  "primitiveMeshGeometry::checkFaceDotProduct"
389  "(const bool, const scalar, const labelList&, labelHashSet*)"
390  ) << "Error in non-orthogonality detected" << endl;
391  }
392 
393  return true;
394  }
395  else
396  {
397  if (report)
398  {
399  Info<< "Non-orthogonality check OK.\n" << endl;
400  }
401 
402  return false;
403  }
404 }
405 
406 
408 (
409  const bool report,
410  const scalar minPyrVol,
411  const primitiveMesh& mesh,
412  const vectorField& cellCentres,
413  const pointField& p,
414  const labelList& checkFaces,
415  labelHashSet* setPtr
416 )
417 {
418  // check whether face area vector points to the cell with higher label
419  const labelList& own = mesh.faceOwner();
420  const labelList& nei = mesh.faceNeighbour();
421 
422  const faceList& f = mesh.faces();
423 
424  label nErrorPyrs = 0;
425 
426  forAll(checkFaces, i)
427  {
428  label faceI = checkFaces[i];
429 
430  // Create the owner pyramid - it will have negative volume
431  scalar pyrVol = pyramidPointFaceRef
432  (
433  f[faceI],
434  cellCentres[own[faceI]]
435  ).mag(p);
436 
437  if (pyrVol > -minPyrVol)
438  {
439  if (report)
440  {
441  Pout<< "bool primitiveMeshGeometry::checkFacePyramids("
442  << "const bool, const scalar, const pointField&"
443  << ", const labelList&, labelHashSet*): "
444  << "face " << faceI << " points the wrong way. " << endl
445  << "Pyramid volume: " << -pyrVol
446  << " Face " << f[faceI] << " area: " << f[faceI].mag(p)
447  << " Owner cell: " << own[faceI] << endl
448  << "Owner cell vertex labels: "
449  << mesh.cells()[own[faceI]].labels(f)
450  << endl;
451  }
452 
453 
454  if (setPtr)
455  {
456  setPtr->insert(faceI);
457  }
458 
459  nErrorPyrs++;
460  }
461 
462  if (mesh.isInternalFace(faceI))
463  {
464  // Create the neighbour pyramid - it will have positive volume
465  scalar pyrVol =
466  pyramidPointFaceRef(f[faceI], cellCentres[nei[faceI]]).mag(p);
467 
468  if (pyrVol < minPyrVol)
469  {
470  if (report)
471  {
472  Pout<< "bool primitiveMeshGeometry::checkFacePyramids("
473  << "const bool, const scalar, const pointField&"
474  << ", const labelList&, labelHashSet*): "
475  << "face " << faceI << " points the wrong way. " << endl
476  << "Pyramid volume: " << -pyrVol
477  << " Face " << f[faceI] << " area: " << f[faceI].mag(p)
478  << " Neighbour cell: " << nei[faceI] << endl
479  << "Neighbour cell vertex labels: "
480  << mesh.cells()[nei[faceI]].labels(f)
481  << endl;
482  }
483 
484  if (setPtr)
485  {
486  setPtr->insert(faceI);
487  }
488 
489  nErrorPyrs++;
490  }
491  }
492  }
493 
494  reduce(nErrorPyrs, sumOp<label>());
495 
496  if (nErrorPyrs > 0)
497  {
498  if (report)
499  {
501  (
502  "primitiveMeshGeometry::checkFacePyramids("
503  "const bool, const scalar, const pointField&"
504  ", const labelList&, labelHashSet*)"
505  ) << "Error in face pyramids: faces pointing the wrong way!"
506  << endl;
507  }
508 
509  return true;
510  }
511  else
512  {
513  if (report)
514  {
515  Info<< "Face pyramids OK.\n" << endl;
516  }
517 
518  return false;
519  }
520 }
521 
522 
524 (
525  const bool report,
526  const scalar internalSkew,
527  const scalar boundarySkew,
528  const primitiveMesh& mesh,
529  const vectorField& cellCentres,
530  const vectorField& faceCentres,
531  const vectorField& faceAreas,
532  const labelList& checkFaces,
533  labelHashSet* setPtr
534 )
535 {
536  // Warn if the skew correction vector is more than skew times
537  // larger than the face area vector
538 
539  const labelList& own = mesh.faceOwner();
540  const labelList& nei = mesh.faceNeighbour();
541 
542  scalar maxSkew = 0;
543 
544  label nWarnSkew = 0;
545 
546  forAll(checkFaces, i)
547  {
548  label faceI = checkFaces[i];
549 
550  if (mesh.isInternalFace(faceI))
551  {
552  scalar dOwn = mag(faceCentres[faceI] - cellCentres[own[faceI]]);
553  scalar dNei = mag(faceCentres[faceI] - cellCentres[nei[faceI]]);
554 
555  point faceIntersection =
556  cellCentres[own[faceI]]*dNei/(dOwn+dNei)
557  + cellCentres[nei[faceI]]*dOwn/(dOwn+dNei);
558 
559  scalar skewness =
560  mag(faceCentres[faceI] - faceIntersection)
561  / (
562  mag(cellCentres[nei[faceI]]-cellCentres[own[faceI]])
563  + VSMALL
564  );
565 
566  // Check if the skewness vector is greater than the PN vector.
567  // This does not cause trouble but is a good indication of a poor
568  // mesh.
569  if (skewness > internalSkew)
570  {
571  if (report)
572  {
573  Pout<< "Severe skewness for face " << faceI
574  << " skewness = " << skewness << endl;
575  }
576 
577  if (setPtr)
578  {
579  setPtr->insert(faceI);
580  }
581 
582  nWarnSkew++;
583  }
584 
585  if (skewness > maxSkew)
586  {
587  maxSkew = skewness;
588  }
589  }
590  else
591  {
592  // Boundary faces: consider them to have only skewness error.
593  // (i.e. treat as if mirror cell on other side)
594 
595  vector faceNormal = faceAreas[faceI];
596  faceNormal /= mag(faceNormal) + VSMALL;
597 
598  vector dOwn = faceCentres[faceI] - cellCentres[own[faceI]];
599 
600  vector dWall = faceNormal*(faceNormal & dOwn);
601 
602  point faceIntersection = cellCentres[own[faceI]] + dWall;
603 
604  scalar skewness =
605  mag(faceCentres[faceI] - faceIntersection)
606  /(2*mag(dWall) + VSMALL);
607 
608  // Check if the skewness vector is greater than the PN vector.
609  // This does not cause trouble but is a good indication of a poor
610  // mesh.
611  if (skewness > boundarySkew)
612  {
613  if (report)
614  {
615  Pout<< "Severe skewness for boundary face " << faceI
616  << " skewness = " << skewness << endl;
617  }
618 
619  if (setPtr)
620  {
621  setPtr->insert(faceI);
622  }
623 
624  nWarnSkew++;
625  }
626 
627  if (skewness > maxSkew)
628  {
629  maxSkew = skewness;
630  }
631  }
632  }
633 
634  reduce(maxSkew, maxOp<scalar>());
635  reduce(nWarnSkew, sumOp<label>());
636 
637  if (nWarnSkew > 0)
638  {
639  if (report)
640  {
641  WarningIn
642  (
643  "primitiveMeshGeometry::checkFaceSkewness"
644  "(const bool, const scalar, const labelList&, labelHashSet*)"
645  ) << "Large face skewness detected. Max skewness = "
646  << 100*maxSkew
647  << " percent.\nThis may impair the quality of the result." << nl
648  << nWarnSkew << " highly skew faces detected."
649  << endl;
650  }
651 
652  return true;
653  }
654  else
655  {
656  if (report)
657  {
658  Info<< "Max skewness = " << 100*maxSkew
659  << " percent. Face skewness OK.\n" << endl;
660  }
661 
662  return false;
663  }
664 }
665 
666 
668 (
669  const bool report,
670  const scalar warnWeight,
671  const primitiveMesh& mesh,
672  const vectorField& cellCentres,
673  const vectorField& faceCentres,
674  const vectorField& faceAreas,
675  const labelList& checkFaces,
676  labelHashSet* setPtr
677 )
678 {
679  // Warn if the delta factor (0..1) is too large.
680 
681  const labelList& own = mesh.faceOwner();
682  const labelList& nei = mesh.faceNeighbour();
683 
684  scalar minWeight = GREAT;
685 
686  label nWarnWeight = 0;
687 
688  forAll(checkFaces, i)
689  {
690  label faceI = checkFaces[i];
691 
692  if (mesh.isInternalFace(faceI))
693  {
694  const point& fc = faceCentres[faceI];
695 
696  scalar dOwn = mag(faceAreas[faceI] & (fc-cellCentres[own[faceI]]));
697  scalar dNei = mag(faceAreas[faceI] & (cellCentres[nei[faceI]]-fc));
698 
699  scalar weight = min(dNei,dOwn)/(dNei+dOwn);
700 
701  if (weight < warnWeight)
702  {
703  if (report)
704  {
705  Pout<< "Small weighting factor for face " << faceI
706  << " weight = " << weight << endl;
707  }
708 
709  if (setPtr)
710  {
711  setPtr->insert(faceI);
712  }
713 
714  nWarnWeight++;
715  }
716 
717  minWeight = min(minWeight, weight);
718  }
719  }
720 
721  reduce(minWeight, minOp<scalar>());
722  reduce(nWarnWeight, sumOp<label>());
723 
724  if (minWeight < warnWeight)
725  {
726  if (report)
727  {
728  WarningIn
729  (
730  "primitiveMeshGeometry::checkFaceWeights"
731  "(const bool, const scalar, const labelList&, labelHashSet*)"
732  ) << "Small interpolation weight detected. Min weight = "
733  << minWeight << '.' << nl
734  << nWarnWeight << " faces with small weights detected."
735  << endl;
736  }
737 
738  return true;
739  }
740  else
741  {
742  if (report)
743  {
744  Info<< "Min weight = " << minWeight
745  << " percent. Weights OK.\n" << endl;
746  }
747 
748  return false;
749  }
750 }
751 
752 
753 // Check convexity of angles in a face. Allow a slight non-convexity.
754 // E.g. maxDeg = 10 allows for angles < 190 (or 10 degrees concavity)
755 // (if truly concave and points not visible from face centre the face-pyramid
756 // check in checkMesh will fail)
758 (
759  const bool report,
760  const scalar maxDeg,
761  const primitiveMesh& mesh,
762  const vectorField& faceAreas,
763  const pointField& p,
764  const labelList& checkFaces,
765  labelHashSet* setPtr
766 )
767 {
768  if (maxDeg < -SMALL || maxDeg > 180+SMALL)
769  {
771  (
772  "primitiveMeshGeometry::checkFaceAngles"
773  "(const bool, const scalar, const pointField&, const labelList&"
774  ", labelHashSet*)"
775  ) << "maxDeg should be [0..180] but is now " << maxDeg
776  << abort(FatalError);
777  }
778 
779  const scalar maxSin = Foam::sin(degToRad(maxDeg));
780 
781  const faceList& fcs = mesh.faces();
782 
783  scalar maxEdgeSin = 0.0;
784 
785  label nConcave = 0;
786 
787  label errorFaceI = -1;
788 
789  forAll(checkFaces, i)
790  {
791  label faceI = checkFaces[i];
792 
793  const face& f = fcs[faceI];
794 
795  vector faceNormal = faceAreas[faceI];
796  faceNormal /= mag(faceNormal) + VSMALL;
797 
798  // Get edge from f[0] to f[size-1];
799  vector ePrev(p[f.first()] - p[f.last()]);
800  scalar magEPrev = mag(ePrev);
801  ePrev /= magEPrev + VSMALL;
802 
803  forAll(f, fp0)
804  {
805  // Get vertex after fp
806  label fp1 = f.fcIndex(fp0);
807 
808  // Normalized vector between two consecutive points
809  vector e10(p[f[fp1]] - p[f[fp0]]);
810  scalar magE10 = mag(e10);
811  e10 /= magE10 + VSMALL;
812 
813  if (magEPrev > SMALL && magE10 > SMALL)
814  {
815  vector edgeNormal = ePrev ^ e10;
816  scalar magEdgeNormal = mag(edgeNormal);
817 
818  if (magEdgeNormal < maxSin)
819  {
820  // Edges (almost) aligned -> face is ok.
821  }
822  else
823  {
824  // Check normal
825  edgeNormal /= magEdgeNormal;
826 
827  if ((edgeNormal & faceNormal) < SMALL)
828  {
829  if (faceI != errorFaceI)
830  {
831  // Count only one error per face.
832  errorFaceI = faceI;
833  nConcave++;
834  }
835 
836  if (setPtr)
837  {
838  setPtr->insert(faceI);
839  }
840 
841  maxEdgeSin = max(maxEdgeSin, magEdgeNormal);
842  }
843  }
844  }
845 
846  ePrev = e10;
847  magEPrev = magE10;
848  }
849  }
850 
851  reduce(nConcave, sumOp<label>());
852  reduce(maxEdgeSin, maxOp<scalar>());
853 
854  if (report)
855  {
856  if (maxEdgeSin > SMALL)
857  {
858  scalar maxConcaveDegr =
859  radToDeg(Foam::asin(Foam::min(1.0, maxEdgeSin)));
860 
861  Info<< "There are " << nConcave
862  << " faces with concave angles between consecutive"
863  << " edges. Max concave angle = " << maxConcaveDegr
864  << " degrees.\n" << endl;
865  }
866  else
867  {
868  Info<< "All angles in faces are convex or less than " << maxDeg
869  << " degrees concave.\n" << endl;
870  }
871  }
872 
873  if (nConcave > 0)
874  {
875  if (report)
876  {
877  WarningIn
878  (
879  "primitiveMeshGeometry::checkFaceAngles"
880  "(const bool, const scalar, const pointField&"
881  ", const labelList&, labelHashSet*)"
882  ) << nConcave << " face points with severe concave angle (> "
883  << maxDeg << " deg) found.\n"
884  << endl;
885  }
886 
887  return true;
888  }
889  else
890  {
891  return false;
892  }
893 }
894 
895 
899 //bool Foam::primitiveMeshGeometry::checkFaceFlatness
900 //(
901 // const bool report,
902 // const scalar warnFlatness,
903 // const primitiveMesh& mesh,
904 // const vectorField& faceAreas,
905 // const vectorField& faceCentres,
906 // const pointField& p,
907 // const labelList& checkFaces,
908 // labelHashSet* setPtr
909 //)
910 //{
911 // if (warnFlatness < 0 || warnFlatness > 1)
912 // {
913 // FatalErrorIn
914 // (
915 // "primitiveMeshGeometry::checkFaceFlatness"
916 // "(const bool, const scalar, const pointField&"
917 // ", const labelList&, labelHashSet*)"
918 // ) << "warnFlatness should be [0..1] but is now " << warnFlatness
919 // << abort(FatalError);
920 // }
921 //
922 //
923 // const faceList& fcs = mesh.faces();
924 //
925 // // Areas are calculated as the sum of areas. (see
926 // // primitiveMeshFaceCentresAndAreas.C)
927 //
928 // label nWarped = 0;
929 //
930 // scalar minFlatness = GREAT;
931 // scalar sumFlatness = 0;
932 // label nSummed = 0;
933 //
934 // forAll(checkFaces, i)
935 // {
936 // label faceI = checkFaces[i];
937 //
938 // const face& f = fcs[faceI];
939 //
940 // scalar magArea = mag(faceAreas[faceI]);
941 //
942 // if (f.size() > 3 && magArea > VSMALL)
943 // {
944 // const point& fc = faceCentres[faceI];
945 //
946 // // Calculate the sum of magnitude of areas and compare to
947 // // magnitude of sum of areas.
948 //
949 // scalar sumA = 0.0;
950 //
951 // forAll(f, fp)
952 // {
953 // const point& thisPoint = p[f[fp]];
954 // const point& nextPoint = p[f.nextLabel(fp)];
955 //
956 // // Triangle around fc.
957 // vector n = 0.5*((nextPoint - thisPoint)^(fc - thisPoint));
958 // sumA += mag(n);
959 // }
960 //
961 // scalar flatness = magArea / (sumA+VSMALL);
962 //
963 // sumFlatness += flatness;
964 // nSummed++;
965 //
966 // minFlatness = min(minFlatness, flatness);
967 //
968 // if (flatness < warnFlatness)
969 // {
970 // nWarped++;
971 //
972 // if (setPtr)
973 // {
974 // setPtr->insert(faceI);
975 // }
976 // }
977 // }
978 // }
979 //
980 //
981 // reduce(nWarped, sumOp<label>());
982 // reduce(minFlatness, minOp<scalar>());
983 //
984 // reduce(nSummed, sumOp<label>());
985 // reduce(sumFlatness, sumOp<scalar>());
986 //
987 // if (report)
988 // {
989 // if (nSummed > 0)
990 // {
991 // Info<< "Face flatness (1 = flat, 0 = butterfly) : average = "
992 // << sumFlatness / nSummed << " min = " << minFlatness << endl;
993 // }
994 //
995 // if (nWarped> 0)
996 // {
997 // Info<< "There are " << nWarped
998 // << " faces with ratio between projected and actual area < "
999 // << warnFlatness
1000 // << ".\nMinimum ratio (minimum flatness, maximum warpage) = "
1001 // << minFlatness << nl << endl;
1002 // }
1003 // else
1004 // {
1005 // Info<< "All faces are flat in that the ratio between projected"
1006 // << " and actual area is > " << warnFlatness << nl << endl;
1007 // }
1008 // }
1009 //
1010 // if (nWarped > 0)
1011 // {
1012 // if (report)
1013 // {
1014 // WarningIn
1015 // (
1016 // "primitiveMeshGeometry::checkFaceFlatness"
1017 // "(const bool, const scalar, const pointField&"
1018 // ", const labelList&, labelHashSet*)"
1019 // ) << nWarped << " faces with severe warpage (flatness < "
1020 // << warnFlatness << ") found.\n"
1021 // << endl;
1022 // }
1023 //
1024 // return true;
1025 // }
1026 // else
1027 // {
1028 // return false;
1029 // }
1030 //}
1031 
1032 
1033 // Check twist of faces. Is calculated as the difference between areas of
1034 // individual triangles and the overall area of the face (which ifself is
1035 // is the average of the areas of the individual triangles).
1038  const bool report,
1039  const scalar minTwist,
1040  const primitiveMesh& mesh,
1041  const vectorField& faceAreas,
1042  const vectorField& faceCentres,
1043  const pointField& p,
1044  const labelList& checkFaces,
1045  labelHashSet* setPtr
1046 )
1047 {
1048  if (minTwist < -1-SMALL || minTwist > 1+SMALL)
1049  {
1050  FatalErrorIn
1051  (
1052  "primitiveMeshGeometry::checkFaceTwist"
1053  "(const bool, const scalar, const primitiveMesh&, const pointField&"
1054  ", const labelList&, labelHashSet*)"
1055  ) << "minTwist should be [-1..1] but is now " << minTwist
1056  << abort(FatalError);
1057  }
1058 
1059 
1060  const faceList& fcs = mesh.faces();
1061 
1062  // Areas are calculated as the sum of areas. (see
1063  // primitiveMeshFaceCentresAndAreas.C)
1064 
1065  label nWarped = 0;
1066 
1067  forAll(checkFaces, i)
1068  {
1069  label faceI = checkFaces[i];
1070 
1071  const face& f = fcs[faceI];
1072 
1073  scalar magArea = mag(faceAreas[faceI]);
1074 
1075  if (f.size() > 3 && magArea > VSMALL)
1076  {
1077  const vector nf = faceAreas[faceI] / magArea;
1078 
1079  const point& fc = faceCentres[faceI];
1080 
1081  forAll(f, fpI)
1082  {
1083  vector triArea
1084  (
1085  triPointRef
1086  (
1087  p[f[fpI]],
1088  p[f.nextLabel(fpI)],
1089  fc
1090  ).normal()
1091  );
1092 
1093  scalar magTri = mag(triArea);
1094 
1095  if (magTri > VSMALL && ((nf & triArea/magTri) < minTwist))
1096  {
1097  nWarped++;
1098 
1099  if (setPtr)
1100  {
1101  setPtr->insert(faceI);
1102  }
1103  }
1104  }
1105  }
1106  }
1107 
1108 
1109  reduce(nWarped, sumOp<label>());
1110 
1111  if (report)
1112  {
1113  if (nWarped> 0)
1114  {
1115  Info<< "There are " << nWarped
1116  << " faces with cosine of the angle"
1117  << " between triangle normal and face normal less than "
1118  << minTwist << nl << endl;
1119  }
1120  else
1121  {
1122  Info<< "All faces are flat in that the cosine of the angle"
1123  << " between triangle normal and face normal less than "
1124  << minTwist << nl << endl;
1125  }
1126  }
1127 
1128  if (nWarped > 0)
1129  {
1130  if (report)
1131  {
1132  WarningIn
1133  (
1134  "primitiveMeshGeometry::checkFaceTwist"
1135  "(const bool, const scalar, const primitiveMesh&"
1136  ", const pointField&, const labelList&, labelHashSet*)"
1137  ) << nWarped << " faces with severe warpage "
1138  << "(cosine of the angle between triangle normal and "
1139  << "face normal < " << minTwist << ") found.\n"
1140  << endl;
1141  }
1142 
1143  return true;
1144  }
1145  else
1146  {
1147  return false;
1148  }
1149 }
1150 
1151 
1154  const bool report,
1155  const scalar minArea,
1156  const primitiveMesh& mesh,
1157  const vectorField& faceAreas,
1158  const labelList& checkFaces,
1159  labelHashSet* setPtr
1160 )
1161 {
1162  label nZeroArea = 0;
1163 
1164  forAll(checkFaces, i)
1165  {
1166  label faceI = checkFaces[i];
1167 
1168  if (mag(faceAreas[faceI]) < minArea)
1169  {
1170  if (setPtr)
1171  {
1172  setPtr->insert(faceI);
1173  }
1174  nZeroArea++;
1175  }
1176  }
1177 
1178 
1179  reduce(nZeroArea, sumOp<label>());
1180 
1181  if (report)
1182  {
1183  if (nZeroArea > 0)
1184  {
1185  Info<< "There are " << nZeroArea
1186  << " faces with area < " << minArea << '.' << nl << endl;
1187  }
1188  else
1189  {
1190  Info<< "All faces have area > " << minArea << '.' << nl << endl;
1191  }
1192  }
1193 
1194  if (nZeroArea > 0)
1195  {
1196  if (report)
1197  {
1198  WarningIn
1199  (
1200  "primitiveMeshGeometry::checkFaceArea"
1201  "(const bool, const scalar, const primitiveMesh&"
1202  ", const pointField&, const labelList&, labelHashSet*)"
1203  ) << nZeroArea << " faces with area < " << minArea
1204  << " found.\n"
1205  << endl;
1206  }
1207 
1208  return true;
1209  }
1210  else
1211  {
1212  return false;
1213  }
1214 }
1215 
1216 
1219  const bool report,
1220  const scalar warnDet,
1221  const primitiveMesh& mesh,
1222  const vectorField& faceAreas,
1223  const labelList& checkFaces,
1224  const labelList& affectedCells,
1225  labelHashSet* setPtr
1226 )
1227 {
1228  const cellList& cells = mesh.cells();
1229 
1230  scalar minDet = GREAT;
1231  scalar sumDet = 0.0;
1232  label nSumDet = 0;
1233  label nWarnDet = 0;
1234 
1235  forAll(affectedCells, i)
1236  {
1237  const cell& cFaces = cells[affectedCells[i]];
1238 
1239  tensor areaSum(tensor::zero);
1240  scalar magAreaSum = 0;
1241 
1242  forAll(cFaces, cFaceI)
1243  {
1244  label faceI = cFaces[cFaceI];
1245 
1246  scalar magArea = mag(faceAreas[faceI]);
1247 
1248  magAreaSum += magArea;
1249  areaSum += faceAreas[faceI]*(faceAreas[faceI]/magArea);
1250  }
1251 
1252  scalar scaledDet = det(areaSum/magAreaSum)/0.037037037037037;
1253 
1254  minDet = min(minDet, scaledDet);
1255  sumDet += scaledDet;
1256  nSumDet++;
1257 
1258  if (scaledDet < warnDet)
1259  {
1260  if (setPtr)
1261  {
1262  // Insert all faces of the cell.
1263  forAll(cFaces, cFaceI)
1264  {
1265  label faceI = cFaces[cFaceI];
1266  setPtr->insert(faceI);
1267  }
1268  }
1269  nWarnDet++;
1270  }
1271  }
1272 
1273  reduce(minDet, minOp<scalar>());
1274  reduce(sumDet, sumOp<scalar>());
1275  reduce(nSumDet, sumOp<label>());
1276  reduce(nWarnDet, sumOp<label>());
1277 
1278  if (report)
1279  {
1280  if (nSumDet > 0)
1281  {
1282  Info<< "Cell determinant (1 = uniform cube) : average = "
1283  << sumDet / nSumDet << " min = " << minDet << endl;
1284  }
1285 
1286  if (nWarnDet > 0)
1287  {
1288  Info<< "There are " << nWarnDet
1289  << " cells with determinant < " << warnDet << '.' << nl
1290  << endl;
1291  }
1292  else
1293  {
1294  Info<< "All faces have determinant > " << warnDet << '.' << nl
1295  << endl;
1296  }
1297  }
1298 
1299  if (nWarnDet > 0)
1300  {
1301  if (report)
1302  {
1303  WarningIn
1304  (
1305  "primitiveMeshGeometry::checkCellDeterminant"
1306  "(const bool, const scalar, const primitiveMesh&"
1307  ", const pointField&, const labelList&, const labelList&"
1308  ", labelHashSet*)"
1309  ) << nWarnDet << " cells with determinant < " << warnDet
1310  << " found.\n"
1311  << endl;
1312  }
1313 
1314  return true;
1315  }
1316  else
1317  {
1318  return false;
1319  }
1320 }
1321 
1322 
1325  const bool report,
1326  const scalar orthWarn,
1327  const labelList& checkFaces,
1328  labelHashSet* setPtr
1329 ) const
1330 {
1331  return checkFaceDotProduct
1332  (
1333  report,
1334  orthWarn,
1335  mesh_,
1336  cellCentres_,
1337  faceAreas_,
1338  checkFaces,
1339  setPtr
1340  );
1341 }
1342 
1343 
1346  const bool report,
1347  const scalar minPyrVol,
1348  const pointField& p,
1349  const labelList& checkFaces,
1350  labelHashSet* setPtr
1351 ) const
1352 {
1353  return checkFacePyramids
1354  (
1355  report,
1356  minPyrVol,
1357  mesh_,
1358  cellCentres_,
1359  p,
1360  checkFaces,
1361  setPtr
1362  );
1363 }
1364 
1365 
1368  const bool report,
1369  const scalar internalSkew,
1370  const scalar boundarySkew,
1371  const labelList& checkFaces,
1372  labelHashSet* setPtr
1373 ) const
1374 {
1375  return checkFaceSkewness
1376  (
1377  report,
1378  internalSkew,
1379  boundarySkew,
1380  mesh_,
1381  cellCentres_,
1382  faceCentres_,
1383  faceAreas_,
1384  checkFaces,
1385  setPtr
1386  );
1387 }
1388 
1389 
1392  const bool report,
1393  const scalar warnWeight,
1394  const labelList& checkFaces,
1395  labelHashSet* setPtr
1396 ) const
1397 {
1398  return checkFaceWeights
1399  (
1400  report,
1401  warnWeight,
1402  mesh_,
1403  cellCentres_,
1404  faceCentres_,
1405  faceAreas_,
1406  checkFaces,
1407  setPtr
1408  );
1409 }
1410 
1411 
1414  const bool report,
1415  const scalar maxDeg,
1416  const pointField& p,
1417  const labelList& checkFaces,
1418  labelHashSet* setPtr
1419 ) const
1420 {
1421  return checkFaceAngles
1422  (
1423  report,
1424  maxDeg,
1425  mesh_,
1426  faceAreas_,
1427  p,
1428  checkFaces,
1429  setPtr
1430  );
1431 }
1432 
1433 
1434 //bool Foam::primitiveMeshGeometry::checkFaceFlatness
1435 //(
1436 // const bool report,
1437 // const scalar warnFlatness,
1438 // const pointField& p,
1439 // const labelList& checkFaces,
1440 // labelHashSet* setPtr
1441 //) const
1442 //{
1443 // return checkFaceFlatness
1444 // (
1445 // report,
1446 // warnFlatness,
1447 // mesh_,
1448 // faceAreas_,
1449 // faceCentres_,
1450 // p,
1451 // checkFaces,
1452 // setPtr
1453 // );
1454 //}
1455 
1456 
1459  const bool report,
1460  const scalar minTwist,
1461  const pointField& p,
1462  const labelList& checkFaces,
1463  labelHashSet* setPtr
1464 ) const
1465 {
1466  return checkFaceTwist
1467  (
1468  report,
1469  minTwist,
1470  mesh_,
1471  faceAreas_,
1472  faceCentres_,
1473  p,
1474  checkFaces,
1475  setPtr
1476  );
1477 }
1478 
1479 
1482  const bool report,
1483  const scalar minArea,
1484  const labelList& checkFaces,
1485  labelHashSet* setPtr
1486 ) const
1487 {
1488  return checkFaceArea
1489  (
1490  report,
1491  minArea,
1492  mesh_,
1493  faceAreas_,
1494  checkFaces,
1495  setPtr
1496  );
1497 }
1498 
1499 
1502  const bool report,
1503  const scalar warnDet,
1504  const labelList& checkFaces,
1505  const labelList& affectedCells,
1506  labelHashSet* setPtr
1507 ) const
1508 {
1509  return checkCellDeterminant
1510  (
1511  report,
1512  warnDet,
1513  mesh_,
1514  faceAreas_,
1515  checkFaces,
1516  affectedCells,
1517  setPtr
1518  );
1519 }
1520 
1521 
1522 // ************************************************************************* //
#define SeriousErrorIn(functionName)
Report an error message using Foam::SeriousError.
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
vector point
Point is a vector.
Definition: point.H:41
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){gmvFile<< iter().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 ))
dimensioned< scalar > mag(const dimensioned< Type > &)
A cell is defined as a list of faces with extra functionality.
Definition: cell.H:56
static const Tensor zero
Definition: Tensor.H:80
T & last()
Return the last element of the list.
Definition: UListI.H:131
primitiveMeshGeometry(const primitiveMesh &)
Construct from mesh.
static bool checkFaceArea(const bool report, const scalar minArea, const primitiveMesh &, const vectorField &faceAreas, const labelList &checkFaces, labelHashSet *setPtr)
Info<< "Predicted p max-min : "<< max(p).value()<< " "<< min(p).value()<< endl;rho==max(psi *p+alphal *rhol0+((alphav *psiv+alphal *psil)-psi)*pSat, rhoMin);#1"/home/dm2/henry/OpenFOAM/OpenFOAM-3.0.x/applications/solvers/multiphase/cavitatingFoam/alphavPsi.H"1{alphav=max(min((rho-rholSat)/(rhovSat-rholSat), scalar(1)), scalar(0));alphal=1.0-alphav;Info<< "max-min alphav: "<< max(alphav).value()<< " "<< min(alphav).value()<< endl;psiModel-> correct()
Definition: pEqn.H:74
static bool checkFaceDotProduct(const bool report, const scalar orthWarn, const primitiveMesh &, const vectorField &cellCentres, const vectorField &faceAreas, const labelList &checkFaces, labelHashSet *setPtr)
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
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:76
label fcIndex(const label i) const
Return the forward circular index, i.e. the next index.
Definition: UListI.H:58
const cellList & cells() const
void correct()
Take over properties from mesh.
messageStream Info
List< face > faceList
Definition: faceListFwd.H:43
virtual const faceList & faces() const =0
Return faces.
label nextLabel(const label i) const
Next vertex on face.
Definition: faceI.H:117
T & first()
Return the first element of the list.
Definition: UListI.H:117
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
A triangle primitive used to calculate face normals and swept volumes.
Definition: triangle.H:57
Namespace for OpenFOAM.
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
static bool checkFaceWeights(const bool report, const scalar warnWeight, const primitiveMesh &mesh, const vectorField &cellCentres, const vectorField &faceCentres, const vectorField &faceAreas, const labelList &checkFaces, labelHashSet *setPtr)
label n
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
static bool checkFacePyramids(const bool report, const scalar minPyrVol, const primitiveMesh &, const vectorField &cellCentres, const pointField &p, const labelList &checkFaces, labelHashSet *)
Cell-face mesh analysis engine.
Definition: primitiveMesh.H:74
static const char nl
Definition: Ostream.H:260
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
#define WarningIn(functionName)
Report a warning using Foam::Warning.
dimensionedScalar det(const dimensionedSphericalTensor &dt)
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
Field< vector > vectorField
Specialisation of Field<T> for vector.
#define forAll(list, i)
Definition: UList.H:421
static bool checkCellDeterminant(const bool report, const scalar minDet, const primitiveMesh &, const vectorField &faceAreas, const labelList &checkFaces, const labelList &affectedCells, labelHashSet *setPtr)
dimensionedScalar cos(const dimensionedScalar &ds)
static bool checkFaceTwist(const bool report, const scalar minTwist, const primitiveMesh &, const vectorField &faceAreas, const vectorField &faceCentres, const pointField &p, const labelList &checkFaces, labelHashSet *setPtr)
scalar radToDeg(const scalar rad)
Conversion from radians to degrees.
Unit conversion functions.
dimensionedScalar acos(const dimensionedScalar &ds)
errorManip< error > abort(error &err)
Definition: errorManip.H:131
#define FatalErrorIn(functionName)
Report an error message using Foam::FatalError.
Definition: error.H:314
const cellShapeList & cells
pyramid< point, const point &, const face & > pyramidPointFaceRef
error FatalError
labelList affectedCells(const labelList &changedFaces) const
Helper function: get affected cells from faces.
List< label > labelList
A List of labels.
Definition: labelList.H:56
static const Vector zero
Definition: Vector.H:80
scalar degToRad(const scalar deg)
Conversion from degrees to radians.
A normal distribution model.
const dimensionedScalar c
Speed of light in a vacuum.
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:49
static bool checkFaceAngles(const bool report, const scalar maxDeg, const primitiveMesh &mesh, const vectorField &faceAreas, const pointField &p, const labelList &checkFaces, labelHashSet *setPtr)
static bool checkFaceSkewness(const bool report, const scalar internalSkew, const scalar boundarySkew, const primitiveMesh &mesh, const vectorField &cellCentres, const vectorField &faceCentres, const vectorField &faceAreas, const labelList &checkFaces, labelHashSet *setPtr)
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
label nPoints
virtual const labelList & faceOwner() const =0
Face face-owner addresing.
dimensionedScalar asin(const dimensionedScalar &ds)
virtual const labelList & faceNeighbour() const =0
Face face-neighbour addressing.
defineTypeNameAndDebug(combustionModel, 0)
prefixOSstream Pout(cout,"Pout")
Definition: IOstreams.H:53
bool isInternalFace(const label faceIndex) const
Return true if given face label is internal to the mesh.
dimensionedScalar sin(const dimensionedScalar &ds)
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:116