primitiveMeshCheckMotion.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | foam-extend: Open Source CFD
4  \\ / O peration | Version: 3.2
5  \\ / A nd | Web: http://www.foam-extend.org
6  \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
8 License
9  This file is part of foam-extend.
10 
11  foam-extend is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by the
13  Free Software Foundation, either version 3 of the License, or (at your
14  option) any later version.
15 
16  foam-extend is distributed in the hope that it will be useful, but
17  WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  General Public License for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
23 
24 Description
25  Given a set of points, find out if the mesh resulting from point motion
26  will be valid without actually changing the mesh.
27 
28 \*---------------------------------------------------------------------------*/
29 
30 #include "primitiveMesh.H"
31 #include "pyramidPointFaceRef.H"
32 #include "cell.H"
33 #include "mathematicalConstants.H"
34 
35 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
36 
38 (
39  const pointField& newPoints,
40  const bool report
41 ) const
42 {
43  if (debug || report)
44  {
45  Pout<< "bool primitiveMesh::checkMeshMotion("
46  << "const pointField& newPoints, const bool report) const: "
47  << "checking mesh motion" << endl;
48  }
49 
50  bool error = false;
51 
52  const faceList& f = faces();
53 
54  const labelList& own = faceOwner();
55  const labelList& nei = faceNeighbour();
56 
57  vectorField fCtrs(nFaces());
58  vectorField fAreas(nFaces());
59 
60  makeFaceCentresAndAreas(newPoints, fCtrs, fAreas);
61 
62  // Check cell volumes and calculate new cell centres
63  vectorField cellCtrs(nCells());
64  scalarField cellVols(nCells());
65 
66  makeCellCentresAndVols(fCtrs, fAreas, cellCtrs, cellVols);
67 
68  scalar minVolume = GREAT;
69  label nNegVols = 0;
70 
71  forAll (cellVols, cellI)
72  {
73  if (cellVols[cellI] < VSMALL)
74  {
75  if (debug || report)
76  {
77  Pout<< "Zero or negative cell volume detected for cell "
78  << cellI << ". Volume = " << cellVols[cellI] << endl;
79  }
80 
81  nNegVols++;
82  }
83 
84  minVolume = min(minVolume, cellVols[cellI]);
85  }
86 
87  if (nNegVols > 0)
88  {
89  error = true;
90 
91  Pout<< "Zero or negative cell volume in mesh motion in " << nNegVols
92  << " cells. Min volume: " << minVolume << endl;
93  }
94  else
95  {
96  if (debug || report)
97  {
98  Pout<< "Min volume = " << minVolume
99  << ". Total volume = " << sum(cellVols)
100  << ". Cell volumes OK." << endl;
101  }
102  }
103 
104  // Check face areas
105 
106  scalar minArea = GREAT;
107  label nNegAreas = 0;
108  label nPyrErrors = 0;
109  label nDotProductErrors = 0;
110 
111  forAll (f, faceI)
112  {
113  const scalar a = Foam::mag(fAreas[faceI]);
114 
115  if (a < VSMALL)
116  {
117  if (debug || report)
118  {
119  if (isInternalFace(faceI))
120  {
121  Pout<< "Zero or negative face area detected for "
122  << "internal face "<< faceI << " between cells "
123  << own[faceI] << " and " << nei[faceI]
124  << ". Face area magnitude = " << a << endl;
125  }
126  else
127  {
128  Pout<< "Zero or negative face area detected for "
129  << "boundary face " << faceI << " next to cell "
130  << own[faceI] << ". Face area magnitude = "
131  << a << endl;
132  }
133  }
134 
135  nNegAreas++;
136  }
137 
138  minArea = min(minArea, a);
139 
140  // Create the owner pyramid - it will have negative volume
141  scalar pyrVol =
142  pyramidPointFaceRef(f[faceI], cellCtrs[own[faceI]]).mag(newPoints);
143 
144  if (pyrVol > SMALL)
145  {
146  if (debug || report)
147  {
148  Pout<< "Negative pyramid volume: " << -pyrVol
149  << " for face " << faceI << " " << f[faceI]
150  << " and owner cell: " << own[faceI] << endl
151  << "Owner cell vertex labels: "
152  << cells()[own[faceI]].labels(f)
153  << endl;
154  }
155 
156  nPyrErrors++;
157  }
158 
159  if (isInternalFace(faceI))
160  {
161  // Create the neighbour pyramid - it will have positive volume
162  scalar pyrVol =
164  (
165  f[faceI],
166  cellCtrs[nei[faceI]]
167  ).mag(newPoints);
168 
169  if (pyrVol < -SMALL)
170  {
171  if (debug || report)
172  {
173  Pout<< "Negative pyramid volume: " << pyrVol
174  << " for face " << faceI << " " << f[faceI]
175  << " and neighbour cell: " << nei[faceI] << nl
176  << "Neighbour cell vertex labels: "
177  << cells()[nei[faceI]].labels(f)
178  << endl;
179  }
180 
181  nPyrErrors++;
182  }
183 
184  const vector d = cellCtrs[nei[faceI]] - cellCtrs[own[faceI]];
185  const vector& s = fAreas[faceI];
186  scalar dDotS = (d & s)/(mag(d)*mag(s) + VSMALL);
187 
188  // Only write full message the first time
189  if (dDotS < SMALL && nDotProductErrors == 0)
190  {
191  // Non-orthogonality greater than 90 deg
192  WarningIn
193  (
194  "primitiveMesh::checkMeshMotion"
195  "(const pointField& newPoints, const bool report) const"
196  ) << "Severe non-orthogonality in mesh motion for face "
197  << faceI
198  << " between cells " << own[faceI] << " and " << nei[faceI]
199  << ": Angle = "
200  << Foam::acos(dDotS)/mathematicalConstant::pi*180.0
201  << " deg." << endl;
202 
203  nDotProductErrors++;
204  }
205  }
206  }
207 
208  if (nNegAreas > 0)
209  {
210  error = true;
211 
212  WarningIn
213  (
214  "primitiveMesh::checkMeshMotion"
215  "(const pointField& newPoints, const bool report) const"
216  ) << "Zero or negative face area in mesh motion in " << nNegAreas
217  << " faces. Min area: " << minArea << endl;
218  }
219  else
220  {
221  if (debug || report)
222  {
223  Pout<< "Min area = " << minArea
224  << ". Face areas OK." << endl;
225  }
226  }
227 
228  if (nPyrErrors > 0)
229  {
230  Pout<< "Detected " << nPyrErrors
231  << " negative pyramid volume in mesh motion" << endl;
232 
233  error = true;
234  }
235  else
236  {
237  if (debug || report)
238  {
239  Pout<< "Pyramid volumes OK." << endl;
240  }
241  }
242 
243  if (nDotProductErrors > 0)
244  {
245  Pout<< "Detected " << nDotProductErrors
246  << " in non-orthogonality in mesh motion." << endl;
247 
248  error = true;
249  }
250  else
251  {
252  if (debug || report)
253  {
254  Pout<< "Non-orthogonality check OK." << endl;
255  }
256  }
257 
258  if (!error && (debug || report))
259  {
260  Pout << "Mesh motion check OK." << endl;
261  }
262 
263  return error;
264 }
265 
266 
267 // ************************************************************************* //
mathematicalConstants.H
cell.H
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:406
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
Foam::mag
dimensioned< scalar > mag(const dimensioned< Type > &)
Foam::label
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
Foam::Field
Pre-declare SubField and related Field type.
Definition: Field.H:57
Foam::nl
static const char nl
Definition: Ostream.H:260
cellVols
const scalarField & cellVols
Definition: temperatureAndPressureVariables.H:49
s
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))
Foam::Pout
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
f
labelList f(nPoints)
Foam::Vector< scalar >
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:59
Foam::acos
dimensionedScalar acos(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:259
Foam::sum
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
Definition: DimensionedFieldFunctions.C:333
Foam::constant::mathematical::pi
const scalar pi(M_PI)
cells
const cellShapeList & cells
Definition: gmvOutputHeader.H:3
WarningIn
#define WarningIn(functionName)
Report a warning using Foam::Warning.
Definition: messageStream.H:254
Foam::primitiveMesh::checkMeshMotion
bool checkMeshMotion(const pointField &newPoints, const bool report=false) const
Check mesh motion for correctness given motion points.
Definition: primitiveMeshCheckMotion.C:38
Foam::min
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
Foam::pyramidPointFaceRef
pyramid< point, const point &, const face & > pyramidPointFaceRef
Definition: pyramidPointFaceRef.H:45
pyramidPointFaceRef.H
Foam::error
Class to handle errors and exceptions in a simple, consistent stream-based manner.
Definition: error.H:66