checkGeometry.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2 
3  DAFoam : Discrete Adjoint with OpenFOAM
4  Version : v3
5 
6  This file is modified from OpenFOAM's source code
7  applications/utilities/mesh/manipulation/checkMesh/checkMeshGeometry.C
8 
9  OpenFOAM: The Open Source CFD Toolbox
10 
11  Copyright (C): 2011-2016 OpenFOAM Foundation
12 
13  OpenFOAM License:
14 
15  OpenFOAM is free software: you can redistribute it and/or modify it
16  under the terms of the GNU General Public License as published by
17  the Free Software Foundation, either version 3 of the License, or
18  (at your option) any later version.
19 
20  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
21  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
22  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23  for more details.
24 
25  You should have received a copy of the GNU General Public License
26  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
27 
28 \*---------------------------------------------------------------------------*/
29 
30 #include "checkGeometry.H"
31 
32 namespace Foam
33 {
34 //- Default transformation behaviour for position
36 {
37 public:
38  //- Transform patch-based field
39  void operator()(
40  const coupledPolyPatch& cpp,
41  List<pointField>& pts) const
42  {
43  // Each element of pts is all the points in the face. Convert into
44  // lists of size cpp to transform.
45 
46  List<pointField> newPts(pts.size());
47  forAll(pts, facei)
48  {
49  newPts[facei].setSize(pts[facei].size());
50  }
51 
52  label index = 0;
53  while (true)
54  {
55  label n = 0;
56 
57  // Extract for every face the i'th position
58  pointField ptsAtIndex(pts.size(), Zero);
59  forAll(cpp, facei)
60  {
61  const pointField& facePts = pts[facei];
62  if (facePts.size() > index)
63  {
64  ptsAtIndex[facei] = facePts[index];
65  n++;
66  }
67  }
68 
69  if (n == 0)
70  {
71  break;
72  }
73 
74  // Now ptsAtIndex will have for every face either zero or
75  // the position of the i'th vertex. Transform.
76  cpp.transformPosition(ptsAtIndex);
77 
78  // Extract back from ptsAtIndex into newPts
79  forAll(cpp, facei)
80  {
81  pointField& facePts = newPts[facei];
82  if (facePts.size() > index)
83  {
84  facePts[index] = ptsAtIndex[facei];
85  }
86  }
87 
88  index++;
89  }
90 
91  pts.transfer(newPts);
92  }
93 };
94 }
95 
97  const polyMesh& mesh,
98  const bool report,
99  labelHashSet* setPtr)
100 {
101  const pointField& p = mesh.points();
102  const faceList& fcs = mesh.faces();
103  const polyBoundaryMesh& patches = mesh.boundaryMesh();
104 
105  // Zero'th point on coupled faces
106  //pointField nbrZeroPoint(fcs.size()-mesh.nInternalFaces(), vector::max);
107  List<pointField> nbrPoints(fcs.size() - mesh.nInternalFaces());
108 
109  // Exchange zero point
110  forAll(patches, patchi)
111  {
112  if (patches[patchi].coupled())
113  {
114  const coupledPolyPatch& cpp = refCast<const coupledPolyPatch>(
115  patches[patchi]);
116 
117  forAll(cpp, i)
118  {
119  label bFacei = cpp.start() + i - mesh.nInternalFaces();
120  const face& f = cpp[i];
121  nbrPoints[bFacei].setSize(f.size());
122  forAll(f, fp)
123  {
124  const point& p0 = p[f[fp]];
125  nbrPoints[bFacei][fp] = p0;
126  }
127  }
128  }
129  }
130  syncTools::syncBoundaryFaceList(
131  mesh,
132  nbrPoints,
133  eqOp<pointField>(),
135 
136  // Compare to local ones. Use same tolerance as for matching
137  label nErrorFaces = 0;
138  scalar avgMismatch = 0;
139  label nCoupledPoints = 0;
140 
141  forAll(patches, patchi)
142  {
143  if (patches[patchi].coupled())
144  {
145  const coupledPolyPatch& cpp =
146  refCast<const coupledPolyPatch>(patches[patchi]);
147 
148  if (cpp.owner())
149  {
150  scalarField smallDist(
151  cpp.calcFaceTol(
152  //cpp.matchTolerance(),
153  cpp,
154  cpp.points(),
155  cpp.faceCentres()));
156 
157  forAll(cpp, i)
158  {
159  label bFacei = cpp.start() + i - mesh.nInternalFaces();
160  const face& f = cpp[i];
161 
162  if (f.size() != nbrPoints[bFacei].size())
163  {
164  FatalErrorInFunction
165  << "Local face size : " << f.size()
166  << " does not equal neighbour face size : "
167  << nbrPoints[bFacei].size()
168  << abort(FatalError);
169  }
170 
171  label fp = 0;
172  forAll(f, j)
173  {
174  const point& p0 = p[f[fp]];
175  scalar d = mag(p0 - nbrPoints[bFacei][j]);
176 
177  if (d > smallDist[i])
178  {
179  if (setPtr)
180  {
181  setPtr->insert(cpp.start() + i);
182  }
183  nErrorFaces++;
184 
185  break;
186  }
187 
188  avgMismatch += d;
189  nCoupledPoints++;
190 
191  fp = f.rcIndex(fp);
192  }
193  }
194  }
195  }
196  }
197 
198  reduce(nErrorFaces, sumOp<label>());
199  reduce(avgMismatch, maxOp<scalar>());
200  reduce(nCoupledPoints, sumOp<label>());
201 
202  if (nCoupledPoints > 0)
203  {
204  avgMismatch /= nCoupledPoints;
205  }
206 
207  if (nErrorFaces > 0)
208  {
209  if (report)
210  {
211  Info << " **Error in coupled point location: "
212  << nErrorFaces
213  << " faces have their 0th or consecutive vertex not opposite"
214  << " their coupled equivalent. Average mismatch "
215  << avgMismatch << "."
216  << endl;
217  }
218 
219  return true;
220  }
221  else
222  {
223  if (report)
224  {
225  Info << " Coupled point location match (average "
226  << avgMismatch << ") OK." << endl;
227  }
228 
229  return false;
230  }
231 }
232 
234  const polyMesh& mesh,
235  const autoPtr<surfaceWriter>& surfWriter,
236  const autoPtr<writer<scalar>>& setWriter,
237  const label maxIncorrectlyOrientedFaces)
238 {
239  label noFailedChecks = 0;
240 
241  //Info << "\nChecking geometry..." << endl;
242 
243  // Get a small relative length from the bounding box
244  const boundBox& globalBb = mesh.bounds();
245 
246  Info << " Overall domain bounding box "
247  << globalBb.min() << " " << globalBb.max() << endl;
248 
249  // Geometric directions
250  const Vector<label> validDirs = (mesh.geometricD() + Vector<label>::one);
251  labelList tmpList(3);
252  forAll(tmpList, idxI) tmpList[idxI] = validDirs[idxI] / 2;
253  Info << " Mesh has " << mesh.nGeometricD()
254  << " geometric (non-empty/wedge) directions " << tmpList << endl;
255 
256  // Solution directions
257  const Vector<label> solDirs = (mesh.solutionD() + Vector<label>::one);
258  forAll(tmpList, idxI) tmpList[idxI] = solDirs[idxI] / 2;
259  Info << " Mesh has " << mesh.nSolutionD()
260  << " solution (non-empty) directions " << tmpList << endl;
261 
262  if (mesh.nGeometricD() < 3)
263  {
264  FatalErrorInFunction
265  << "Mesh geometric directions is less than 3 and not supported!"
266  << abort(FatalError);
267  }
268 
269  if (mesh.checkClosedBoundary(true))
270  {
271  noFailedChecks++;
272  }
273 
274  {
275  cellSet cells(mesh, "nonClosedCells", mesh.nCells() / 100 + 1);
276  cellSet aspectCells(mesh, "highAspectRatioCells", mesh.nCells() / 100 + 1);
277  if (
278  mesh.checkClosedCells(
279  true,
280  &cells,
281  &aspectCells,
282  mesh.geometricD()))
283  {
284  noFailedChecks++;
285 
286  label nNonClosed = returnReduce(cells.size(), sumOp<label>());
287 
288  if (nNonClosed > 0)
289  {
290  Info << " <<Writing " << nNonClosed
291  << " non closed cells to set " << cells.name() << endl;
292  cells.instance() = mesh.pointsInstance();
293  cells.write();
294  if (surfWriter.valid())
295  {
296  mergeAndWrite(surfWriter(), cells);
297  }
298  }
299  }
300 
301  label nHighAspect = returnReduce(aspectCells.size(), sumOp<label>());
302 
303  if (nHighAspect > 0)
304  {
305  Info << " <<Writing " << nHighAspect
306  << " cells with high aspect ratio to set "
307  << aspectCells.name() << endl;
308  aspectCells.instance() = mesh.pointsInstance();
309  aspectCells.write();
310  if (surfWriter.valid())
311  {
312  mergeAndWrite(surfWriter(), aspectCells);
313  }
314  }
315  }
316 
317  {
318  faceSet faces(mesh, "zeroAreaFaces", mesh.nFaces() / 100 + 1);
319  if (mesh.checkFaceAreas(true, &faces))
320  {
321  noFailedChecks++;
322 
323  label nFaces = returnReduce(faces.size(), sumOp<label>());
324 
325  if (nFaces > 0)
326  {
327  Info << " <<Writing " << nFaces
328  << " zero area faces to set " << faces.name() << endl;
329  faces.instance() = mesh.pointsInstance();
330  faces.write();
331  if (surfWriter.valid())
332  {
333  mergeAndWrite(surfWriter(), faces);
334  }
335  }
336  }
337  }
338 
339  {
340  cellSet cells(mesh, "zeroVolumeCells", mesh.nCells() / 100 + 1);
341  if (mesh.checkCellVolumes(true, &cells))
342  {
343  noFailedChecks++;
344 
345  label nCells = returnReduce(cells.size(), sumOp<label>());
346 
347  if (nCells > 0)
348  {
349  Info << " <<Writing " << nCells
350  << " zero volume cells to set " << cells.name() << endl;
351  cells.instance() = mesh.pointsInstance();
352  cells.write();
353  if (surfWriter.valid())
354  {
355  mergeAndWrite(surfWriter(), cells);
356  }
357  }
358  }
359  }
360 
361  {
362  faceSet faces(mesh, "nonOrthoFaces", mesh.nFaces() / 100 + 1);
363  if (mesh.checkFaceOrthogonality(true, &faces))
364  {
365  noFailedChecks++;
366  }
367 
368  label nFaces = returnReduce(faces.size(), sumOp<label>());
369 
370  if (nFaces > 0)
371  {
372  Info << " <<Writing " << nFaces
373  << " non-orthogonal faces to set " << faces.name() << endl;
374  faces.instance() = mesh.pointsInstance();
375  faces.write();
376  if (surfWriter.valid())
377  {
378  mergeAndWrite(surfWriter(), faces);
379  }
380  }
381  }
382 
383  {
384  faceSet faces(mesh, "wrongOrientedFaces", mesh.nFaces() / 100 + 1);
385  if (mesh.checkFacePyramids(true, -SMALL, &faces))
386  {
387  if (maxIncorrectlyOrientedFaces > 0)
388  {
389  Info << "maxIncorrectlyOrientedFaces threshold is set to " << maxIncorrectlyOrientedFaces << endl;
390  }
391 
392  label nFaces = returnReduce(faces.size(), sumOp<label>());
393 
394  // if nFaces is less than maxIncorrectlyOrientedFaces
395  // we do not consider it is a failed mesh. This allows
396  // users to relax the mesh check for incorrectly oriented
397  // mesh faces
398  if (nFaces > maxIncorrectlyOrientedFaces)
399  {
400  noFailedChecks++;
401  }
402 
403  if (nFaces > 0)
404  {
405  Info << " <<Writing " << nFaces
406  << " faces with incorrect orientation to set "
407  << faces.name() << endl;
408  faces.instance() = mesh.pointsInstance();
409  faces.write();
410  if (surfWriter.valid())
411  {
412  mergeAndWrite(surfWriter(), faces);
413  }
414  }
415  }
416  }
417 
418  {
419  faceSet faces(mesh, "skewFaces", mesh.nFaces() / 100 + 1);
420  if (mesh.checkFaceSkewness(true, &faces))
421  {
422  noFailedChecks++;
423 
424  label nFaces = returnReduce(faces.size(), sumOp<label>());
425 
426  if (nFaces > 0)
427  {
428  Info << " <<Writing " << nFaces
429  << " skew faces to set " << faces.name() << endl;
430  faces.instance() = mesh.pointsInstance();
431  faces.write();
432  if (surfWriter.valid())
433  {
434  mergeAndWrite(surfWriter(), faces);
435  }
436  }
437  }
438  }
439 
440  {
441  faceSet faces(mesh, "coupledFaces", mesh.nFaces() / 100 + 1);
442  if (checkCoupledPoints(mesh, true, &faces))
443  {
444  noFailedChecks++;
445 
446  label nFaces = returnReduce(faces.size(), sumOp<label>());
447 
448  if (nFaces > 0)
449  {
450  Info << " <<Writing " << nFaces
451  << " faces with incorrectly matched 0th (or consecutive)"
452  << " vertex to set "
453  << faces.name() << endl;
454  faces.instance() = mesh.pointsInstance();
455  faces.write();
456  if (surfWriter.valid())
457  {
458  mergeAndWrite(surfWriter(), faces);
459  }
460  }
461  }
462  }
463 
464  return noFailedChecks;
465 }
forAll
forAll(pseudoP.boundaryField(), patchI)
Definition: solvePseudoPEqn.H:10
checkGeometry.H
Foam::checkCoupledPoints
bool checkCoupledPoints(const polyMesh &, const bool report, labelHashSet *)
Check 0th vertex on coupled faces.
Definition: checkGeometry.C:96
p0
volScalarField p0(p)
p
volScalarField & p
Definition: createRefsPimple.H:6
Foam::mergeAndWrite
void mergeAndWrite(const polyMesh &mesh, const surfaceWriter &writer, const word &name, const indirectPrimitivePatch &setPatch, const fileName &outputDir)
Definition: checkTools.C:52
mesh
fvMesh & mesh
Definition: createRefsHeatTransfer.H:4
Foam::transformPositionList
Definition: checkGeometry.C:35
Foam
Definition: multiFreqScalarFvPatchField.C:144
Foam::checkGeometry
label checkGeometry(const polyMesh &mesh, const autoPtr< surfaceWriter > &surfWriter, const autoPtr< writer< scalar >> &setWriter, const label maxIncorrectlyOrientedFaces)
check mesh quality
Definition: checkGeometry.C:233
Foam::transformPositionList::operator()
void operator()(const coupledPolyPatch &cpp, List< pointField > &pts) const
Definition: checkGeometry.C:39