Loading...
Searching...
No Matches
checkGeometry.C
Go to the documentation of this file.
1#include "PatchTools.H"
2#include "checkGeometry.H"
3#include "polyMesh.H"
4#include "cellSet.H"
5#include "faceSet.H"
6#include "pointSet.H"
7#include "edgeHashes.H"
8#include "wedgePolyPatch.H"
9#include "unitConversion.H"
11#include "checkTools.H"
12#include "functionObject.H"
13
14#include "vtkCoordSetWriter.H"
15#include "vtkSurfaceWriter.H"
16
17#include "cyclicACMIPolyPatch.H"
18#include "mappedPatchBase.H"
19#include "Time.H"
20
21// Find wedge with opposite orientation. Note: does not actually check that
22// it is opposite, only that it has opposite normal and same axis
24(
25 const polyMesh& mesh,
26 const wedgePolyPatch& wpp
27)
28{
29 const polyBoundaryMesh& patches = mesh.boundaryMesh();
30
31 scalar wppCosAngle = wpp.cosAngle();
32
33 forAll(patches, patchi)
34 {
35 if
36 (
37 patchi != wpp.index()
38 && patches[patchi].size()
39 && isA<wedgePolyPatch>(patches[patchi])
40 )
41 {
42 const auto& pp = refCast<const wedgePolyPatch>(patches[patchi]);
43
44 // Calculate (cos of) angle to wpp (not pp!) centre normal
45 scalar ppCosAngle = wpp.centreNormal() & pp.n();
46
47 if
48 (
49 pp.size() == wpp.size()
50 && mag(pp.axis() & wpp.axis()) >= (1-1e-3)
51 && mag(ppCosAngle - wppCosAngle) >= 1e-3
52 )
53 {
54 return patchi;
55 }
56 }
57 }
58 return -1;
59}
60
61
63(
64 const polyMesh& mesh,
65 const bool report,
66 const Vector<label>& directions,
67 labelHashSet* setPtr
68)
69{
70 // To mark edges without calculating edge addressing
71 EdgeMap<label> edgesInError;
72
73 const pointField& p = mesh.points();
74 const faceList& fcs = mesh.faces();
75
76
77 const polyBoundaryMesh& patches = mesh.boundaryMesh();
78 forAll(patches, patchi)
79 {
80 if (patches[patchi].size() && isA<wedgePolyPatch>(patches[patchi]))
81 {
82 const auto& pp = refCast<const wedgePolyPatch>(patches[patchi]);
83
84 scalar wedgeAngle = acos(pp.cosAngle());
85
86 if (report)
87 {
88 Info<< " Wedge " << pp.name() << " with angle "
89 << radToDeg(wedgeAngle) << " degrees"
90 << endl;
91 }
92
93 // Find opposite
94 label oppositePatchi = findOppositeWedge(mesh, pp);
95
96 if (oppositePatchi == -1)
97 {
98 if (report)
99 {
100 Info<< " ***Cannot find opposite wedge for wedge "
101 << pp.name() << endl;
102 }
103 return true;
104 }
105
106 const auto& opp =
107 refCast<const wedgePolyPatch>(patches[oppositePatchi]);
108
109
110 if (mag(opp.axis() & pp.axis()) < (1-1e-3))
111 {
112 if (report)
113 {
114 Info<< " ***Wedges do not have the same axis."
115 << " Encountered " << pp.axis()
116 << " on patch " << pp.name()
117 << " which differs from " << opp.axis()
118 << " on opposite wedge patch" << opp.axis()
119 << endl;
120 }
121 return true;
122 }
123
124
125
126 // Mark edges on wedgePatches
127 forAll(pp, i)
128 {
129 const face& f = pp[i];
130 forAll(f, fp)
131 {
132 label p0 = f[fp];
133 label p1 = f.nextLabel(fp);
134 edgesInError.insert(edge(p0, p1), -1); // non-error value
135 }
136 }
137
138
139 // Check that wedge patch is flat
140 const point& p0 = p[pp.meshPoints()[0]];
141 forAll(pp.meshPoints(), i)
142 {
143 const point& pt = p[pp.meshPoints()[i]];
144 scalar d = mag((pt - p0) & pp.n());
145
146 if (d > ROOTSMALL)
147 {
148 if (report)
149 {
150 Info<< " ***Wedge patch " << pp.name() << " not planar."
151 << " Point " << pt << " is not in patch plane by "
152 << d << " metre."
153 << endl;
154 }
155 return true;
156 }
157 }
158 }
159 }
160
161
162
163 // Check all non-wedge faces
164 label nEdgesInError = 0;
165
166 forAll(fcs, facei)
167 {
168 const face& f = fcs[facei];
169
170 forAll(f, fp)
171 {
172 label p0 = f[fp];
173 label p1 = f.nextLabel(fp);
174 if (p0 < p1)
175 {
176 vector d(p[p1]-p[p0]);
177 scalar magD = mag(d);
178
179 if (magD > ROOTVSMALL)
180 {
181 d /= magD;
182
183 // Check how many empty directions are used by the edge.
184 label nEmptyDirs = 0;
185 label nNonEmptyDirs = 0;
186 for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
187 {
188 if (mag(d[cmpt]) > 1e-6)
189 {
190 if (directions[cmpt] == 0)
191 {
192 nEmptyDirs++;
193 }
194 else
195 {
196 nNonEmptyDirs++;
197 }
198 }
199 }
200
201 if (nEmptyDirs == 0)
202 {
203 // Purely in ok directions.
204 }
205 else if (nEmptyDirs == 1)
206 {
207 // Ok if purely in empty directions.
208 if (nNonEmptyDirs > 0)
209 {
210 if (edgesInError.insert(edge(p0, p1), facei))
211 {
212 nEdgesInError++;
213 }
214 }
215 }
216 else if (nEmptyDirs > 1)
217 {
218 // Always an error
219 if (edgesInError.insert(edge(p0, p1), facei))
220 {
221 nEdgesInError++;
222 }
223 }
224 }
225 }
226 }
227 }
228
229 label nErrorEdges = returnReduce(nEdgesInError, sumOp<label>());
230
231 if (nErrorEdges > 0)
232 {
233 if (report)
234 {
235 Info<< " ***Number of edges not aligned with or perpendicular to "
236 << "non-empty directions: " << nErrorEdges << endl;
237 }
238
239 if (setPtr)
240 {
241 setPtr->reserve(2*nEdgesInError);
242 forAllConstIters(edgesInError, iter)
243 {
244 if (iter.val() >= 0)
245 {
246 setPtr->insert(iter.key().first());
247 setPtr->insert(iter.key().second());
248 }
249 }
250 }
251
252 return true;
253 }
254
255 if (report)
256 {
257 Info<< " All edges aligned with or perpendicular to "
258 << "non-empty directions." << endl;
259 }
260
261 return false;
262}
263
264
265namespace Foam
266{
267 //- Default transformation behaviour for position
268 class transformPositionList
269 {
270 public:
271
272 //- Transform patch-based field
273 void operator()
274 (
275 const coupledPolyPatch& cpp,
276 UList<pointField>& pts
277 ) const
278 {
279 // Each element of pts is all the points in the face.
280 // Convert into lists of size cpp to transform.
281
282 List<pointField> newPts(pts.size());
283 forAll(pts, facei)
284 {
285 newPts[facei].resize(pts[facei].size());
286 }
287
288 pointField ptsAtIndex(pts.size());
289
290 label index = 0;
291 while (true)
292 {
293 label n = 0;
294
295 // Extract for every face the i'th position
296 ptsAtIndex = Zero;
297 forAll(cpp, facei)
298 {
299 const pointField& facePts = pts[facei];
300 if (facePts.size() > index)
301 {
302 ptsAtIndex[facei] = facePts[index];
303 n++;
304 }
305 }
306
307 if (n == 0)
308 {
309 break;
310 }
311
312 // Now ptsAtIndex will have for every face either zero or
313 // the position of the i'th vertex. Transform.
314 cpp.transformPosition(ptsAtIndex);
315
316 // Extract back from ptsAtIndex into newPts
317 forAll(cpp, facei)
318 {
319 pointField& facePts = newPts[facei];
320 if (facePts.size() > index)
321 {
322 facePts[index] = ptsAtIndex[facei];
323 }
324 }
325
326 index++;
327 }
328
329 // Transfer newPts -> pts
330 std::move(newPts.begin(), newPts.end(), pts.begin());
331 }
332 };
333}
334
335
337(
338 const polyMesh& mesh,
339 const bool report,
340 labelHashSet* setPtr
341)
342{
343 const pointField& p = mesh.points();
344 const faceList& fcs = mesh.faces();
345 const polyBoundaryMesh& patches = mesh.boundaryMesh();
346
347 // Zero'th point on coupled faces
348 //pointField nbrZeroPoint(fcs.size()-mesh.nInternalFaces(), vector::max);
349 List<pointField> nbrPoints(fcs.size() - mesh.nInternalFaces());
350
351 // Exchange zero point
352 forAll(patches, patchi)
353 {
354 if (patches[patchi].coupled())
355 {
356 const auto& cpp = refCast<const coupledPolyPatch>(patches[patchi]);
357
358 forAll(cpp, i)
359 {
360 label bFacei = cpp.start() + i - mesh.nInternalFaces();
361 const face& f = cpp[i];
362 nbrPoints[bFacei].setSize(f.size());
363 forAll(f, fp)
364 {
365 const point& p0 = p[f[fp]];
366 nbrPoints[bFacei][fp] = p0;
367 }
368 }
369 }
370 }
371 syncTools::syncBoundaryFaceList
372 (
373 mesh,
374 nbrPoints,
375 eqOp<pointField>(),
376 transformPositionList()
377 );
378
379 // Compare to local ones. Use same tolerance as for matching
380 label nErrorFaces = 0;
381 scalar avgMismatch = 0;
382 label nCoupledPoints = 0;
383
384 forAll(patches, patchi)
385 {
386 if (patches[patchi].coupled())
387 {
388 const auto& cpp = refCast<const coupledPolyPatch>(patches[patchi]);
389
390 if (cpp.owner())
391 {
392 scalarField smallDist
393 (
394 cpp.calcFaceTol
395 (
396 //cpp.matchTolerance(),
397 cpp,
398 cpp.points(),
399 cpp.faceCentres()
400 )
401 );
402
403 forAll(cpp, i)
404 {
405 label bFacei = cpp.start() + i - mesh.nInternalFaces();
406 const face& f = cpp[i];
407
408 if (f.size() != nbrPoints[bFacei].size())
409 {
411 << "Local face size : " << f.size()
412 << " does not equal neighbour face size : "
413 << nbrPoints[bFacei].size()
414 << abort(FatalError);
415 }
416
417 label fp = 0;
418 forAll(f, j)
419 {
420 const point& p0 = p[f[fp]];
421 scalar d = mag(p0 - nbrPoints[bFacei][j]);
422
423 if (d > smallDist[i])
424 {
425 if (setPtr)
426 {
427 setPtr->insert(cpp.start()+i);
428 }
429 nErrorFaces++;
430
431 break;
432 }
433
434 avgMismatch += d;
435 nCoupledPoints++;
436
437 fp = f.rcIndex(fp);
438 }
439 }
440 }
441 }
442 }
443
444 reduce(nErrorFaces, sumOp<label>());
445 reduce(avgMismatch, maxOp<scalar>());
446 reduce(nCoupledPoints, sumOp<label>());
447
448 if (nCoupledPoints > 0)
449 {
450 avgMismatch /= nCoupledPoints;
451 }
452
453 if (nErrorFaces > 0)
454 {
455 if (report)
456 {
457 Info<< " **Error in coupled point location: "
458 << nErrorFaces
459 << " faces have their 0th or consecutive vertex not opposite"
460 << " their coupled equivalent. Average mismatch "
461 << avgMismatch << "."
462 << endl;
463 }
464
465 return true;
466 }
467
468 if (report)
469 {
470 Info<< " Coupled point location match (average "
471 << avgMismatch << ") OK." << endl;
472 }
473
474 return false;
475}
476
477
479(
480 const polyMesh& mesh,
481 surfaceWriter& wr,
482 const fileName& fName,
483 const scalarField& weights,
484 const faceList& localFaces,
485 const labelList& meshPoints,
486 const Map<label>& meshPointMap,
487
488 // Collect geometry
489 faceList& mergedFaces,
490 pointField& mergedPoints,
491 autoPtr<globalIndex>& globalFaces,
492 autoPtr<globalIndex>& globalPoints
493)
494{
495 labelList pointToGlobal;
496 labelList uniqueMeshPointLabels;
498 (
499 mesh,
500 localFaces,
501 meshPoints,
502 meshPointMap,
503
504 pointToGlobal,
505 uniqueMeshPointLabels,
506 globalPoints,
507 globalFaces,
508
509 mergedFaces,
510 mergedPoints
511 );
512 // Collect field
513 scalarField mergedWeights;
514 globalFaces().gather(weights, mergedWeights);
515
516 if (Pstream::master())
517 {
518 wr.open
519 (
520 mergedPoints,
521 mergedFaces,
522 fName,
523 false // serial - already merged
524 );
525
526 wr.write("weightsSum", mergedWeights);
527 wr.clear();
528 }
529}
530
531
532Foam::label Foam::checkGeometry
533(
534 const polyMesh& mesh,
535 const bool allGeometry,
536 autoPtr<surfaceWriter>& surfWriter,
537 autoPtr<coordSetWriter>& setWriter
538)
539{
540 label noFailedChecks = 0;
541
542 Info<< "\nChecking geometry..." << endl;
543
544 // Get a small relative length from the bounding box
545 const boundBox& globalBb = mesh.bounds();
546
547 Info<< " Overall domain bounding box "
548 << globalBb.min() << " " << globalBb.max() << endl;
549
550
551 // Min length
552 scalar minDistSqr = magSqr(1e-6 * globalBb.span());
553
554 // Geometric directions
555 const Vector<label> validDirs = (mesh.geometricD() + Vector<label>::one)/2;
556 Info<< " Mesh has " << mesh.nGeometricD()
557 << " geometric (non-empty/wedge) directions " << validDirs << endl;
558
559 // Solution directions
560 const Vector<label> solDirs = (mesh.solutionD() + Vector<label>::one)/2;
561 Info<< " Mesh has " << mesh.nSolutionD()
562 << " solution (non-empty) directions " << solDirs << endl;
563
564 if (mesh.nGeometricD() < 3)
565 {
566 pointSet nonAlignedPoints(mesh, "nonAlignedEdges", mesh.nPoints()/100);
567
568 if
569 (
570 (
571 validDirs != solDirs
572 && checkWedges(mesh, true, validDirs, &nonAlignedPoints)
573 )
574 || (
575 validDirs == solDirs
576 && mesh.checkEdgeAlignment(true, validDirs, &nonAlignedPoints)
577 )
578 )
579 {
580 noFailedChecks++;
581 label nNonAligned = returnReduce
582 (
583 nonAlignedPoints.size(),
584 sumOp<label>()
585 );
586
587 if (nNonAligned > 0)
588 {
589 Info<< " <<Writing " << nNonAligned
590 << " points on non-aligned edges to set "
591 << nonAlignedPoints.name() << endl;
592 nonAlignedPoints.instance() = mesh.pointsInstance();
593 nonAlignedPoints.write();
594 if (setWriter && setWriter->enabled())
595 {
596 mergeAndWrite(*setWriter, nonAlignedPoints);
597 }
598 }
599 }
600 }
601
602 if (mesh.checkClosedBoundary(true)) noFailedChecks++;
603
604 {
605 cellSet cells(mesh, "nonClosedCells", mesh.nCells()/100+1);
606 cellSet aspectCells(mesh, "highAspectRatioCells", mesh.nCells()/100+1);
607 if
608 (
609 mesh.checkClosedCells
610 (
611 true,
612 &cells,
613 &aspectCells,
614 mesh.geometricD()
615 )
616 )
617 {
618 noFailedChecks++;
619
620 label nNonClosed = returnReduce(cells.size(), sumOp<label>());
621
622 if (nNonClosed > 0)
623 {
624 Info<< " <<Writing " << nNonClosed
625 << " non closed cells to set " << cells.name() << endl;
626 cells.instance() = mesh.pointsInstance();
627 cells.write();
628 if (surfWriter && surfWriter->enabled())
629 {
630 mergeAndWrite(*surfWriter, cells);
631 }
632 }
633 }
634
635 label nHighAspect = returnReduce(aspectCells.size(), sumOp<label>());
636
637 if (nHighAspect > 0)
638 {
639 Info<< " <<Writing " << nHighAspect
640 << " cells with high aspect ratio to set "
641 << aspectCells.name() << endl;
642 aspectCells.instance() = mesh.pointsInstance();
643 aspectCells.write();
644 if (surfWriter && surfWriter->enabled())
645 {
646 mergeAndWrite(*surfWriter, aspectCells);
647 }
648 }
649 }
650
651 {
652 faceSet faces(mesh, "zeroAreaFaces", mesh.nFaces()/100+1);
653 if (mesh.checkFaceAreas(true, &faces))
654 {
655 noFailedChecks++;
656
657 label nFaces = returnReduce(faces.size(), sumOp<label>());
658
659 if (nFaces > 0)
660 {
661 Info<< " <<Writing " << nFaces
662 << " zero area faces to set " << faces.name() << endl;
663 faces.instance() = mesh.pointsInstance();
664 faces.write();
665 if (surfWriter && surfWriter->enabled())
666 {
667 mergeAndWrite(*surfWriter, faces);
668 }
669 }
670 }
671 }
672
673 {
674 cellSet cells(mesh, "zeroVolumeCells", mesh.nCells()/100+1);
675 if (mesh.checkCellVolumes(true, &cells))
676 {
677 noFailedChecks++;
678
679 label nCells = returnReduce(cells.size(), sumOp<label>());
680
681 if (nCells > 0)
682 {
683 Info<< " <<Writing " << nCells
684 << " zero volume cells to set " << cells.name() << endl;
685 cells.instance() = mesh.pointsInstance();
686 cells.write();
687 if (surfWriter && surfWriter->enabled())
688 {
689 mergeAndWrite(*surfWriter, cells);
690 }
691 }
692 }
693 }
694
695 {
696 faceSet faces(mesh, "nonOrthoFaces", mesh.nFaces()/100+1);
697 if (mesh.checkFaceOrthogonality(true, &faces))
698 {
699 noFailedChecks++;
700 }
701
702 label nFaces = returnReduce(faces.size(), sumOp<label>());
703
704 if (nFaces > 0)
705 {
706 Info<< " <<Writing " << nFaces
707 << " non-orthogonal faces to set " << faces.name() << endl;
708 faces.instance() = mesh.pointsInstance();
709 faces.write();
710 if (surfWriter && surfWriter->enabled())
711 {
712 mergeAndWrite(*surfWriter, faces);
713 }
714 }
715 }
716
717 {
718 faceSet faces(mesh, "wrongOrientedFaces", mesh.nFaces()/100 + 1);
719 if (mesh.checkFacePyramids(true, -SMALL, &faces))
720 {
721 noFailedChecks++;
722
723 label nFaces = returnReduce(faces.size(), sumOp<label>());
724
725 if (nFaces > 0)
726 {
727 Info<< " <<Writing " << nFaces
728 << " faces with incorrect orientation to set "
729 << faces.name() << endl;
730 faces.instance() = mesh.pointsInstance();
731 faces.write();
732 if (surfWriter && surfWriter->enabled())
733 {
734 mergeAndWrite(*surfWriter, faces);
735 }
736 }
737 }
738 }
739
740 {
741 faceSet faces(mesh, "skewFaces", mesh.nFaces()/100+1);
742 if (mesh.checkFaceSkewness(true, &faces))
743 {
744 noFailedChecks++;
745
746 label nFaces = returnReduce(faces.size(), sumOp<label>());
747
748 if (nFaces > 0)
749 {
750 Info<< " <<Writing " << nFaces
751 << " skew faces to set " << faces.name() << endl;
752 faces.instance() = mesh.pointsInstance();
753 faces.write();
754 if (surfWriter && surfWriter->enabled())
755 {
756 mergeAndWrite(*surfWriter, faces);
757 }
758 }
759 }
760 }
761
762 {
763 faceSet faces(mesh, "coupledFaces", mesh.nFaces()/100 + 1);
764 if (checkCoupledPoints(mesh, true, &faces))
765 {
766 noFailedChecks++;
767
768 label nFaces = returnReduce(faces.size(), sumOp<label>());
769
770 if (nFaces > 0)
771 {
772 Info<< " <<Writing " << nFaces
773 << " faces with incorrectly matched 0th (or consecutive)"
774 << " vertex to set "
775 << faces.name() << endl;
776 faces.instance() = mesh.pointsInstance();
777 faces.write();
778 if (surfWriter && surfWriter->enabled())
779 {
780 mergeAndWrite(*surfWriter, faces);
781 }
782 }
783 }
784 }
785
786 if (allGeometry)
787 {
788 faceSet faces(mesh, "lowQualityTetFaces", mesh.nFaces()/100+1);
789 if
790 (
791 polyMeshTetDecomposition::checkFaceTets
792 (
793 mesh,
794 polyMeshTetDecomposition::minTetQuality,
795 true,
796 &faces
797 )
798 )
799 {
800 noFailedChecks++;
801
802 label nFaces = returnReduce(faces.size(), sumOp<label>());
803
804 if (nFaces > 0)
805 {
806 Info<< " <<Writing " << nFaces
807 << " faces with low quality or negative volume "
808 << "decomposition tets to set " << faces.name() << endl;
809 faces.instance() = mesh.pointsInstance();
810 faces.write();
811 if (surfWriter && surfWriter->enabled())
812 {
813 mergeAndWrite(*surfWriter, faces);
814 }
815 }
816 }
817 }
818
819 if (allGeometry)
820 {
821 // Note use of nPoints since don't want edge construction.
822 pointSet points(mesh, "shortEdges", mesh.nPoints()/1000 + 1);
823 if (mesh.checkEdgeLength(true, minDistSqr, &points))
824 {
825 //noFailedChecks++;
826
827 label nPoints = returnReduce(points.size(), sumOp<label>());
828
829 if (nPoints > 0)
830 {
831 Info<< " <<Writing " << nPoints
832 << " points on short edges to set " << points.name()
833 << endl;
834 points.instance() = mesh.pointsInstance();
835 points.write();
836 if (setWriter && setWriter->enabled())
837 {
838 mergeAndWrite(*setWriter, points);
839 }
840 }
841 }
842
843 label nEdgeClose = returnReduce(points.size(), sumOp<label>());
844
845 if (mesh.checkPointNearness(false, minDistSqr, &points))
846 {
847 //noFailedChecks++;
848
849 label nPoints = returnReduce(points.size(), sumOp<label>());
850
851 if (nPoints > nEdgeClose)
852 {
853 pointSet nearPoints(mesh, "nearPoints", points);
854 Info<< " <<Writing " << nPoints
855 << " near (closer than " << Foam::sqrt(minDistSqr)
856 << " apart) points to set " << nearPoints.name() << endl;
857 nearPoints.instance() = mesh.pointsInstance();
858 nearPoints.write();
859 if (setWriter && setWriter->enabled())
860 {
861 mergeAndWrite(*setWriter, nearPoints);
862 }
863 }
864 }
865 }
866
867 if (allGeometry)
868 {
869 faceSet faces(mesh, "concaveFaces", mesh.nFaces()/100 + 1);
870 if (mesh.checkFaceAngles(true, 10, &faces))
871 {
872 //noFailedChecks++;
873
874 label nFaces = returnReduce(faces.size(), sumOp<label>());
875
876 if (nFaces > 0)
877 {
878 Info<< " <<Writing " << nFaces
879 << " faces with concave angles to set " << faces.name()
880 << endl;
881 faces.instance() = mesh.pointsInstance();
882 faces.write();
883 if (surfWriter && surfWriter->enabled())
884 {
885 mergeAndWrite(*surfWriter, faces);
886 }
887 }
888 }
889 }
890
891 if (allGeometry)
892 {
893 faceSet faces(mesh, "warpedFaces", mesh.nFaces()/100 + 1);
894 if (mesh.checkFaceFlatness(true, 0.8, &faces))
895 {
896 //noFailedChecks++;
897
898 label nFaces = returnReduce(faces.size(), sumOp<label>());
899
900 if (nFaces > 0)
901 {
902 Info<< " <<Writing " << nFaces
903 << " warped faces to set " << faces.name() << endl;
904 faces.instance() = mesh.pointsInstance();
905 faces.write();
906 if (surfWriter && surfWriter->enabled())
907 {
908 mergeAndWrite(*surfWriter, faces);
909 }
910 }
911 }
912 }
913
914 if (allGeometry)
915 {
916 cellSet cells(mesh, "underdeterminedCells", mesh.nCells()/100);
917 if (mesh.checkCellDeterminant(true, &cells))
918 {
919 noFailedChecks++;
920
921 label nCells = returnReduce(cells.size(), sumOp<label>());
922
923 Info<< " <<Writing " << nCells
924 << " under-determined cells to set " << cells.name() << endl;
925 cells.instance() = mesh.pointsInstance();
926 cells.write();
927 if (surfWriter && surfWriter->enabled())
928 {
929 mergeAndWrite(*surfWriter, cells);
930 }
931 }
932 }
933
934 if (allGeometry)
935 {
936 cellSet cells(mesh, "concaveCells", mesh.nCells()/100);
937 if (mesh.checkConcaveCells(true, &cells))
938 {
939 noFailedChecks++;
940
941 label nCells = returnReduce(cells.size(), sumOp<label>());
942
943 Info<< " <<Writing " << nCells
944 << " concave cells to set " << cells.name() << endl;
945 cells.instance() = mesh.pointsInstance();
946 cells.write();
947 if (surfWriter && surfWriter->enabled())
948 {
949 mergeAndWrite(*surfWriter, cells);
950 }
951 }
952 }
953
954 if (allGeometry)
955 {
956 faceSet faces(mesh, "lowWeightFaces", mesh.nFaces()/100);
957 if (mesh.checkFaceWeight(true, 0.05, &faces))
958 {
959 noFailedChecks++;
960
961 label nFaces = returnReduce(faces.size(), sumOp<label>());
962
963 Info<< " <<Writing " << nFaces
964 << " faces with low interpolation weights to set "
965 << faces.name() << endl;
966 faces.instance() = mesh.pointsInstance();
967 faces.write();
968 if (surfWriter && surfWriter->enabled())
969 {
970 mergeAndWrite(*surfWriter, faces);
971 }
972 }
973 }
974
975 if (allGeometry)
976 {
977 faceSet faces(mesh, "lowVolRatioFaces", mesh.nFaces()/100);
978 if (mesh.checkVolRatio(true, 0.01, &faces))
979 {
980 noFailedChecks++;
981
982 label nFaces = returnReduce(faces.size(), sumOp<label>());
983
984 Info<< " <<Writing " << nFaces
985 << " faces with low volume ratio cells to set "
986 << faces.name() << endl;
987 faces.instance() = mesh.pointsInstance();
988 faces.write();
989 if (surfWriter && surfWriter->enabled())
990 {
991 mergeAndWrite(*surfWriter, faces);
992 }
993 }
994 }
995
996 if (allGeometry)
997 {
998 const polyBoundaryMesh& pbm = mesh.boundaryMesh();
999
1000 const word tmName(mesh.time().timeName());
1001 const word procAndTime(Foam::name(Pstream::myProcNo()) + "_" + tmName);
1002
1003 autoPtr<surfaceWriter> patchWriter;
1004 if (!surfWriter)
1005 {
1006 patchWriter.reset(new surfaceWriters::vtkWriter());
1007 }
1008
1009 surfaceWriter& wr = (surfWriter ? *surfWriter : *patchWriter);
1010
1011 // Currently only do AMI checks
1012
1013 const fileName outputDir
1014 (
1015 mesh.time().globalPath()/functionObject::outputPrefix
1016 / mesh.regionName()/"checkMesh"
1017 );
1018
1019 forAll(pbm, patchi)
1020 {
1021 if (isA<cyclicAMIPolyPatch>(pbm[patchi]))
1022 {
1023 const auto& cpp =
1024 refCast<const cyclicAMIPolyPatch>(pbm[patchi]);
1025
1026 if (cpp.owner())
1027 {
1028 Info<< "Calculating AMI weights between owner patch: "
1029 << cpp.name() << " and neighbour patch: "
1030 << cpp.neighbPatch().name() << endl;
1031
1032 const AMIPatchToPatchInterpolation& ami = cpp.AMI();
1033
1034 {
1035 // Collect geometry
1036 faceList mergedFaces;
1037 pointField mergedPoints;
1038 autoPtr<globalIndex> globalFaces;
1039 autoPtr<globalIndex> globalPoints;
1041 (
1042 mesh,
1043 wr,
1044 outputDir / cpp.name() + "-src_" + tmName,
1045 ami.srcWeightsSum(),
1046 cpp.localFaces(),
1047 cpp.meshPoints(),
1048 cpp.meshPointMap(),
1049
1050 mergedFaces,
1051 mergedPoints,
1052 globalFaces,
1053 globalPoints
1054 );
1055
1056 if (isA<cyclicACMIPolyPatch>(pbm[patchi]))
1057 {
1058 const auto& pp =
1059 refCast<const cyclicACMIPolyPatch>(pbm[patchi]);
1060
1061 scalarField mergedMask;
1062 globalFaces().gather(pp.mask(), mergedMask);
1063
1064 if (Pstream::master())
1065 {
1066 wr.open
1067 (
1068 mergedPoints,
1069 mergedFaces,
1070 (outputDir / cpp.name() + "-src_" + tmName),
1071 false // serial - already merged
1072 );
1073
1074 wr.write("mask", mergedMask);
1075 wr.clear();
1076 }
1077 }
1078 }
1079 {
1080 const auto& nbrPp = cpp.neighbPatch();
1081
1082 // Collect geometry
1083 faceList mergedFaces;
1084 pointField mergedPoints;
1085 autoPtr<globalIndex> globalFaces;
1086 autoPtr<globalIndex> globalPoints;
1088 (
1089 mesh,
1090 wr,
1091 (
1092 outputDir
1093 / nbrPp.name() + "-tgt_" + tmName
1094 ),
1095 ami.tgtWeightsSum(),
1096 nbrPp.localFaces(),
1097 nbrPp.meshPoints(),
1098 nbrPp.meshPointMap(),
1099
1100 mergedFaces,
1101 mergedPoints,
1102 globalFaces,
1103 globalPoints
1104 );
1105
1106 if (isA<cyclicACMIPolyPatch>(pbm[patchi]))
1107 {
1108 const auto& pp =
1109 refCast<const cyclicACMIPolyPatch>(pbm[patchi]);
1110
1111 scalarField mergedMask;
1112 globalFaces().gather
1113 (
1114 pp.neighbPatch().mask(),
1115 mergedMask
1116 );
1117
1118 if (Pstream::master())
1119 {
1120 wr.open
1121 (
1122 mergedPoints,
1123 mergedFaces,
1124 (
1125 outputDir
1126 / nbrPp.name() + "-tgt_" + tmName
1127 ),
1128 false // serial - already merged
1129 );
1130
1131 wr.write("mask", mergedMask);
1132 wr.clear();
1133 }
1134 }
1135 }
1136 }
1137 }
1138 else if (isA<mappedPatchBase>(pbm[patchi]))
1139 {
1140 const auto& pp = pbm[patchi];
1141 const auto& cpp = refCast<const mappedPatchBase>(pp);
1142 const AMIPatchToPatchInterpolation& ami = cpp.AMI();
1143
1144 // Collect geometry
1145 faceList mergedFaces;
1146 pointField mergedPoints;
1147 autoPtr<globalIndex> globalFaces;
1148 autoPtr<globalIndex> globalPoints;
1150 (
1151 mesh,
1152 wr,
1153 outputDir / pp.name() + "-src_" + tmName,
1154 ami.srcWeightsSum(),
1155 pp.localFaces(),
1156 pp.meshPoints(),
1157 pp.meshPointMap(),
1158
1159 mergedFaces,
1160 mergedPoints,
1161 globalFaces,
1162 globalPoints
1163 );
1164
1165 if (cpp.sameWorld())
1166 {
1167 //- Get the patch on the region
1168 const polyPatch& nbrPp = cpp.samplePolyPatch();
1169
1170 // Collect neighbour geometry
1171 faceList mergedFaces;
1172 pointField mergedPoints;
1173 autoPtr<globalIndex> globalFaces;
1174 autoPtr<globalIndex> globalPoints;
1175
1177 (
1178 cpp.sampleMesh(),
1179 wr,
1180 outputDir / nbrPp.name() + "-tgt_" + tmName,
1181 ami.tgtWeightsSum(),
1182 nbrPp.localFaces(),
1183 nbrPp.meshPoints(),
1184 nbrPp.meshPointMap(),
1185
1186 mergedFaces,
1187 mergedPoints,
1188 globalFaces,
1189 globalPoints
1190 );
1191 }
1192 }
1193 }
1194 }
1195
1196 return noFailedChecks;
1197}
label n
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
const polyBoundaryMesh & pbm
static void gatherAndMerge(const scalar mergeDist, const PrimitivePatch< FaceList, PointField > &pp, Field< typename PrimitivePatch< FaceList, PointField >::point_type > &mergedPoints, List< typename PrimitivePatch< FaceList, PointField >::face_type > &mergedFaces, globalIndex &pointAddr, globalIndex &faceAddr, labelList &pointMergeMap=const_cast< labelList & >(labelList::null()), const bool useLocal=false)
Gather points and faces onto master and merge into single patch.
const word & name() const noexcept
Return const reference to name.
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
volScalarField & p
const volScalarField & p0
Definition EEqn.H:36
const polyBoundaryMesh & patches
bool coupled
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
const pointField & points
label nPoints
const cellShapeList & cells
return returnReduce(nRefine-oldNRefine, sumOp< label >())
Namespace for OpenFOAM.
List< label > labelList
A List of labels.
Definition List.H:62
label checkGeometry(const polyMesh &mesh, const bool allGeometry, autoPtr< surfaceWriter > &surfWriter, autoPtr< coordSetWriter > &setWriter)
bool checkCoupledPoints(const polyMesh &, const bool report, labelHashSet *)
Check 0th vertex on coupled faces.
messageStream Info
Information stream (stdout output on master, null elsewhere).
List< face > faceList
List of faces.
Definition faceListFwd.H:41
bool checkWedges(const polyMesh &, const bool report, const Vector< label > &, labelHashSet *)
Check wedge orientation.
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
dimensionedScalar sqrt(const dimensionedScalar &ds)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
void reduce(T &value, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce).
void mergeAndWrite(const polyMesh &mesh, surfaceWriter &writer, const word &name, const indirectPrimitivePatch &setPatch, const fileName &outputDir)
Generate merged surface on master and write. Needs input patch.
AMIInterpolation AMIPatchToPatchInterpolation
Patch-to-patch interpolation == Foam::AMIInterpolation.
errorManip< error > abort(error &err)
Definition errorManip.H:139
vector point
Point is a vector.
Definition point.H:37
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition exprTraits.C:127
void collectAndWriteAMIWeights(const polyMesh &mesh, surfaceWriter &wr, const fileName &fName, const scalarField &weights, const faceList &localFaces, const labelList &meshPoints, const Map< label > &meshPointMap, faceList &mergedFaces, pointField &mergedPoints, autoPtr< globalIndex > &globalFaces, autoPtr< globalIndex > &globalPoints)
Collect AMI weights to master and write.
label findOppositeWedge(const polyMesh &, const wedgePolyPatch &)
vectorField pointField
pointField is a vectorField.
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
dimensionedScalar acos(const dimensionedScalar &ds)
constexpr scalar radToDeg(const scalar rad) noexcept
Conversion from radians to degrees.
labelList f(nPoints)
const pointField & pts
volScalarField & e
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
#define forAllConstIters(container, iter)
Iterate across all elements of the container object with const access.
Definition stdFoam.H:235
Unit conversion functions.