snappySnapDriver.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2015 OpenFOAM Foundation
9  Copyright (C) 2015-2019 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 Description
28  All to do with snapping to the surface
29 
30 \*----------------------------------------------------------------------------*/
31 
32 #include "snappySnapDriver.H"
33 #include "motionSmoother.H"
34 #include "polyTopoChange.H"
35 #include "syncTools.H"
36 #include "fvMesh.H"
37 #include "Time.H"
38 #include "OFstream.H"
39 #include "OBJstream.H"
40 #include "mapPolyMesh.H"
41 #include "pointEdgePoint.H"
42 #include "PointEdgeWave.H"
43 #include "mergePoints.H"
44 #include "snapParameters.H"
45 #include "refinementSurfaces.H"
46 #include "searchableSurfaces.H"
47 #include "unitConversion.H"
48 #include "localPointRegion.H"
49 #include "PatchTools.H"
50 #include "refinementFeatures.H"
51 #include "profiling.H"
52 
53 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
54 
55 namespace Foam
56 {
57 
58 defineTypeNameAndDebug(snappySnapDriver, 0);
59 
60 } // End namespace Foam
61 
62 
63 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
64 
65 // Calculate geometrically collocated points, Requires bitSet to be
66 // sized and initialised!
67 Foam::label Foam::snappySnapDriver::getCollocatedPoints
68 (
69  const scalar tol,
70  const pointField& points,
71  bitSet& isCollocatedPoint
72 )
73 {
74  labelList pointMap;
75  label nUnique = mergePoints
76  (
77  points, // points
78  tol, // mergeTol
79  false, // verbose
80  pointMap
81  );
82  bool hasMerged = (nUnique < points.size());
83 
84  if (!returnReduce(hasMerged, orOp<bool>()))
85  {
86  return 0;
87  }
88 
89  // Determine which merged points are referenced more than once
90  label nCollocated = 0;
91 
92  // Per old point the newPoint. Or -1 (not set yet) or -2 (already seen
93  // twice)
94  labelList firstOldPoint(nUnique, -1);
95  forAll(pointMap, oldPointi)
96  {
97  label newPointi = pointMap[oldPointi];
98 
99  if (firstOldPoint[newPointi] == -1)
100  {
101  // First use of oldPointi. Store.
102  firstOldPoint[newPointi] = oldPointi;
103  }
104  else if (firstOldPoint[newPointi] == -2)
105  {
106  // Third or more reference of oldPointi -> non-manifold
107  isCollocatedPoint.set(oldPointi);
108  nCollocated++;
109  }
110  else
111  {
112  // Second reference of oldPointi -> non-manifold
113  isCollocatedPoint.set(firstOldPoint[newPointi]);
114  nCollocated++;
115 
116  isCollocatedPoint.set(oldPointi);
117  nCollocated++;
118 
119  // Mark with special value to save checking next time round
120  firstOldPoint[newPointi] = -2;
121  }
122  }
123  return returnReduce(nCollocated, sumOp<label>());
124 }
125 
126 
127 Foam::tmp<Foam::pointField> Foam::snappySnapDriver::smoothInternalDisplacement
128 (
129  const meshRefinement& meshRefiner,
130  const motionSmoother& meshMover
131 )
132 {
133  const indirectPrimitivePatch& pp = meshMover.patch();
134  const polyMesh& mesh = meshMover.mesh();
135 
136  // Get neighbour refinement
137  const hexRef8& cutter = meshRefiner.meshCutter();
138  const labelList& cellLevel = cutter.cellLevel();
139 
140 
141  // Get the faces on the boundary
142  bitSet isFront(mesh.nFaces(), pp.addressing());
143 
144  // Walk out from the surface a bit. Poor man's FaceCellWave.
145  // Commented out for now - not sure if needed and if so how much
146  //for (label iter = 0; iter < 2; iter++)
147  //{
148  // bitSet newIsFront(mesh.nFaces());
149  //
150  // forAll(isFront, facei)
151  // {
152  // if (isFront.test(facei))
153  // {
154  // label own = mesh.faceOwner()[facei];
155  // const cell& ownFaces = mesh.cells()[own];
156  // newIsFront.set(ownFaces);
157  //
158  // if (mesh.isInternalFace(facei))
159  // {
160  // label nei = mesh.faceNeighbour()[facei];
161  // const cell& neiFaces = mesh.cells()[nei];
162  // newIsFront.set(neiFaces);
163  // }
164  // }
165  // }
166  //
167  // syncTools::syncFaceList
168  // (
169  // mesh,
170  // newIsFront,
171  // orEqOp<unsigned int>()
172  // );
173  //
174  // isFront = newIsFront;
175  //}
176 
177  // Mark all points on faces
178  // - not on the boundary
179  // - inbetween differing refinement levels
180  bitSet isMovingPoint(mesh.nPoints());
181 
182  label nInterface = 0;
183 
184  for (label facei = 0; facei < mesh.nInternalFaces(); facei++)
185  {
186  label ownLevel = cellLevel[mesh.faceOwner()[facei]];
187  label neiLevel = cellLevel[mesh.faceNeighbour()[facei]];
188 
189  if (!isFront.test(facei) && ownLevel != neiLevel)
190  {
191  const face& f = mesh.faces()[facei];
192  isMovingPoint.set(f);
193 
194  ++nInterface;
195  }
196  }
197 
198  labelList neiCellLevel;
199  syncTools::swapBoundaryCellList(mesh, cellLevel, neiCellLevel);
200 
201  for (label facei = mesh.nInternalFaces(); facei < mesh.nFaces(); facei++)
202  {
203  label ownLevel = cellLevel[mesh.faceOwner()[facei]];
204  label neiLevel = neiCellLevel[facei-mesh.nInternalFaces()];
205 
206  if (!isFront.test(facei) && ownLevel != neiLevel)
207  {
208  const face& f = mesh.faces()[facei];
209  isMovingPoint.set(f);
210 
211  ++nInterface;
212  }
213  }
214 
215  if (debug)
216  {
217  reduce(nInterface, sumOp<label>());
218  Info<< "Found " << nInterface << " faces out of "
220  << " inbetween refinement regions." << endl;
221  }
222 
223  // Make sure that points that are coupled to a moving point are marked
224  // as well
225  syncTools::syncPointList(mesh, isMovingPoint, maxEqOp<unsigned int>(), 0);
226 
227  // Unmark any point on the boundary. If we're doing zero iterations of
228  // face-cell wave we might have coupled points not being unmarked.
229  isMovingPoint.unset(pp.meshPoints());
230 
231  // Make sure that points that are coupled to meshPoints but not on a patch
232  // are unmarked as well
233  syncTools::syncPointList(mesh, isMovingPoint, minEqOp<unsigned int>(), 1);
234 
235 
236  // Calculate average of connected cells
237  labelList nCells(mesh.nPoints(), Zero);
238  pointField sumLocation(mesh.nPoints(), Zero);
239 
240  forAll(isMovingPoint, pointi)
241  {
242  if (isMovingPoint.test(pointi))
243  {
244  const labelList& pCells = mesh.pointCells(pointi);
245 
246  forAll(pCells, i)
247  {
248  sumLocation[pointi] += mesh.cellCentres()[pCells[i]];
249  nCells[pointi]++;
250  }
251  }
252  }
253 
254  // Sum
255  syncTools::syncPointList(mesh, nCells, plusEqOp<label>(), label(0));
257  (
258  mesh,
259  sumLocation,
260  plusEqOp<point>(),
262  );
263 
264  tmp<pointField> tdisplacement(new pointField(mesh.nPoints(), Zero));
265  pointField& displacement = tdisplacement.ref();
266 
267  label nAdapted = 0;
268 
269  forAll(displacement, pointi)
270  {
271  if (nCells[pointi] > 0)
272  {
273  displacement[pointi] =
274  sumLocation[pointi]/nCells[pointi]-mesh.points()[pointi];
275  nAdapted++;
276  }
277  }
278 
279  reduce(nAdapted, sumOp<label>());
280  Info<< "Smoothing " << nAdapted << " points inbetween refinement regions."
281  << endl;
282 
283  return tdisplacement;
284 }
285 
286 
287 // Calculate displacement as average of patch points.
288 Foam::tmp<Foam::pointField> Foam::snappySnapDriver::smoothPatchDisplacement
289 (
290  const motionSmoother& meshMover,
291  const List<labelPair>& baffles
292 )
293 {
294  const indirectPrimitivePatch& pp = meshMover.patch();
295 
296  // Calculate geometrically non-manifold points on the patch to be moved.
297  bitSet nonManifoldPoint(pp.nPoints());
298  label nNonManifoldPoints = getCollocatedPoints
299  (
300  SMALL,
301  pp.localPoints(),
302  nonManifoldPoint
303  );
304  Info<< "Found " << nNonManifoldPoints << " non-manifold point(s)."
305  << endl;
306 
307 
308  // Average points
309  // ~~~~~~~~~~~~~~
310 
311  // We determine three points:
312  // - average of (centres of) connected patch faces
313  // - average of (centres of) connected internal mesh faces
314  // - as fallback: centre of any connected cell
315  // so we can do something moderately sensible for non/manifold points.
316 
317  // Note: the averages are calculated properly parallel. This is
318  // necessary to get the points shared by processors correct.
319 
320 
321  const labelListList& pointFaces = pp.pointFaces();
322  const labelList& meshPoints = pp.meshPoints();
323  const pointField& points = pp.points();
324  const polyMesh& mesh = meshMover.mesh();
325 
326  // Get labels of faces to count (master of coupled faces and baffle pairs)
327  bitSet isMasterFace(syncTools::getMasterFaces(mesh));
328 
329  {
330  forAll(baffles, i)
331  {
332  label f0 = baffles[i].first();
333  label f1 = baffles[i].second();
334 
335  if (isMasterFace.test(f0))
336  {
337  // Make f1 a slave
338  isMasterFace.unset(f1);
339  }
340  else if (isMasterFace.test(f1))
341  {
342  isMasterFace.unset(f0);
343  }
344  else
345  {
347  << "Both sides of baffle consisting of faces " << f0
348  << " and " << f1 << " are already slave faces."
349  << abort(FatalError);
350  }
351  }
352  }
353 
354 
355  // Get average position of boundary face centres
356  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
357 
358  vectorField avgBoundary(pointFaces.size(), Zero);
359  labelList nBoundary(pointFaces.size(), Zero);
360 
361  forAll(pointFaces, patchPointi)
362  {
363  const labelList& pFaces = pointFaces[patchPointi];
364 
365  forAll(pFaces, pfi)
366  {
367  label facei = pFaces[pfi];
368 
369  if (isMasterFace.test(pp.addressing()[facei]))
370  {
371  avgBoundary[patchPointi] += pp[facei].centre(points);
372  nBoundary[patchPointi]++;
373  }
374  }
375  }
376 
378  (
379  mesh,
380  pp.meshPoints(),
381  avgBoundary,
382  plusEqOp<point>(), // combine op
383  vector::zero // null value
384  );
386  (
387  mesh,
388  pp.meshPoints(),
389  nBoundary,
390  plusEqOp<label>(), // combine op
391  label(0) // null value
392  );
393 
394  forAll(avgBoundary, i)
395  {
396  avgBoundary[i] /= nBoundary[i];
397  }
398 
399 
400  // Get average position of internal face centres
401  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
402 
403  vectorField avgInternal;
404  labelList nInternal;
405  {
406  vectorField globalSum(mesh.nPoints(), Zero);
407  labelList globalNum(mesh.nPoints(), Zero);
408 
409  // Note: no use of pointFaces
410  const faceList& faces = mesh.faces();
411 
412  for (label facei = 0; facei < mesh.nInternalFaces(); facei++)
413  {
414  const face& f = faces[facei];
415  const point& fc = mesh.faceCentres()[facei];
416 
417  forAll(f, fp)
418  {
419  globalSum[f[fp]] += fc;
420  globalNum[f[fp]]++;
421  }
422  }
423 
424  // Count coupled faces as internal ones (but only once)
425  const polyBoundaryMesh& patches = mesh.boundaryMesh();
426 
427  forAll(patches, patchi)
428  {
429  if
430  (
431  patches[patchi].coupled()
432  && refCast<const coupledPolyPatch>(patches[patchi]).owner()
433  )
434  {
435  const coupledPolyPatch& pp =
436  refCast<const coupledPolyPatch>(patches[patchi]);
437 
438  const vectorField::subField faceCentres = pp.faceCentres();
439 
440  forAll(pp, i)
441  {
442  const face& f = pp[i];
443  const point& fc = faceCentres[i];
444 
445  forAll(f, fp)
446  {
447  globalSum[f[fp]] += fc;
448  globalNum[f[fp]]++;
449  }
450  }
451  }
452  }
453 
455  (
456  mesh,
457  globalSum,
458  plusEqOp<vector>(), // combine op
459  vector::zero // null value
460  );
462  (
463  mesh,
464  globalNum,
465  plusEqOp<label>(), // combine op
466  label(0) // null value
467  );
468 
469  avgInternal.setSize(meshPoints.size());
470  nInternal.setSize(meshPoints.size());
471 
472  forAll(avgInternal, patchPointi)
473  {
474  label meshPointi = meshPoints[patchPointi];
475 
476  nInternal[patchPointi] = globalNum[meshPointi];
477 
478  if (nInternal[patchPointi] == 0)
479  {
480  avgInternal[patchPointi] = globalSum[meshPointi];
481  }
482  else
483  {
484  avgInternal[patchPointi] =
485  globalSum[meshPointi]
486  / nInternal[patchPointi];
487  }
488  }
489  }
490 
491 
492  // Precalculate any cell using mesh point (replacement of pointCells()[])
493  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
494 
495  labelList anyCell(mesh.nPoints(), -1);
496  forAll(mesh.faceOwner(), facei)
497  {
498  label own = mesh.faceOwner()[facei];
499  const face& f = mesh.faces()[facei];
500 
501  forAll(f, fp)
502  {
503  anyCell[f[fp]] = own;
504  }
505  }
506 
507 
508  // Displacement to calculate.
509  tmp<pointField> tpatchDisp(new pointField(meshPoints.size(), Zero));
510  pointField& patchDisp = tpatchDisp.ref();
511 
512  forAll(pointFaces, i)
513  {
514  label meshPointi = meshPoints[i];
515  const point& currentPos = pp.points()[meshPointi];
516 
517  // Now we have the two average points: avgBoundary and avgInternal
518  // and how many boundary/internal faces connect to the point
519  // (nBoundary, nInternal)
520  // Do some blending between the two.
521  // Note: the following section has some reasoning behind it but the
522  // blending factors can be experimented with.
523 
524  point newPos;
525 
526  if (!nonManifoldPoint.test(i))
527  {
528  // Points that are manifold. Weight the internal and boundary
529  // by their number of faces and blend with
530  scalar internalBlend = 0.1;
531  scalar blend = 0.1;
532 
533  point avgPos =
534  (
535  internalBlend*nInternal[i]*avgInternal[i]
536  +(1-internalBlend)*nBoundary[i]*avgBoundary[i]
537  )
538  / (internalBlend*nInternal[i]+(1-internalBlend)*nBoundary[i]);
539 
540  newPos = (1-blend)*avgPos + blend*currentPos;
541  }
542  else if (nInternal[i] == 0)
543  {
544  // Non-manifold without internal faces. Use any connected cell
545  // as internal point instead. Use precalculated any cell to avoid
546  // e.g. pointCells()[meshPointi][0]
547 
548  const point& cc = mesh.cellCentres()[anyCell[meshPointi]];
549 
550  scalar cellCBlend = 0.8;
551  scalar blend = 0.1;
552 
553  point avgPos = (1-cellCBlend)*avgBoundary[i] + cellCBlend*cc;
554 
555  newPos = (1-blend)*avgPos + blend*currentPos;
556  }
557  else
558  {
559  // Non-manifold point with internal faces connected to them
560  scalar internalBlend = 0.9;
561  scalar blend = 0.1;
562 
563  point avgPos =
564  internalBlend*avgInternal[i]
565  + (1-internalBlend)*avgBoundary[i];
566 
567  newPos = (1-blend)*avgPos + blend*currentPos;
568  }
569 
570  patchDisp[i] = newPos - currentPos;
571  }
572 
573  return tpatchDisp;
574 }
575 //XXXXXXX
576 //Foam::tmp<Foam::pointField> Foam::snappySnapDriver::avg
577 //(
578 // const indirectPrimitivePatch& pp,
579 // const pointField& localPoints
580 //)
581 //{
582 // const labelListList& pointEdges = pp.pointEdges();
583 // const edgeList& edges = pp.edges();
584 //
585 // tmp<pointField> tavg(new pointField(pointEdges.size(), Zero));
586 // pointField& avg = tavg();
587 //
588 // forAll(pointEdges, verti)
589 // {
590 // vector& avgPos = avg[verti];
591 //
592 // const labelList& pEdges = pointEdges[verti];
593 //
594 // forAll(pEdges, myEdgei)
595 // {
596 // const edge& e = edges[pEdges[myEdgei]];
597 //
598 // label otherVerti = e.otherVertex(verti);
599 //
600 // avgPos += localPoints[otherVerti];
601 // }
602 //
603 // avgPos /= pEdges.size();
604 // }
605 // return tavg;
606 //}
607 //Foam::tmp<Foam::pointField>
608 //Foam::snappySnapDriver::smoothLambdaMuPatchDisplacement
609 //(
610 // const motionSmoother& meshMover,
611 // const List<labelPair>& baffles
612 //)
613 //{
614 // const indirectPrimitivePatch& pp = meshMover.patch();
615 // pointField newLocalPoints(pp.localPoints());
616 //
617 // const label iters = 90;
618 // const scalar lambda = 0.33;
619 // const scalar mu = 0.34;
620 //
621 // for (label iter = 0; iter < iters; iter++)
622 // {
623 // // Lambda
624 // newLocalPoints =
625 // (1 - lambda)*newLocalPoints
626 // + lambda*avg(pp, newLocalPoints);
627 //
628 // // Mu
629 // newLocalPoints =
630 // (1 + mu)*newLocalPoints
631 // - mu*avg(pp, newLocalPoints);
632 // }
633 // return newLocalPoints-pp.localPoints();
634 //}
635 //XXXXXXX
636 
637 
638 Foam::tmp<Foam::scalarField> Foam::snappySnapDriver::edgePatchDist
639 (
640  const pointMesh& pMesh,
641  const indirectPrimitivePatch& pp
642 )
643 {
644  const polyMesh& mesh = pMesh();
645 
646  // Set initial changed points to all the patch points
647  List<pointEdgePoint> wallInfo(pp.nPoints());
648 
649  forAll(pp.localPoints(), ppi)
650  {
651  wallInfo[ppi] = pointEdgePoint(pp.localPoints()[ppi], 0.0);
652  }
653 
654  // Current info on points
655  List<pointEdgePoint> allPointInfo(mesh.nPoints());
656 
657  // Current info on edges
658  List<pointEdgePoint> allEdgeInfo(mesh.nEdges());
659 
660  PointEdgeWave<pointEdgePoint> wallCalc
661  (
662  mesh,
663  pp.meshPoints(),
664  wallInfo,
665 
666  allPointInfo,
667  allEdgeInfo,
668  mesh.globalData().nTotalPoints() // max iterations
669  );
670 
671  // Copy edge values into scalarField
672  tmp<scalarField> tedgeDist(new scalarField(mesh.nEdges()));
673  scalarField& edgeDist = tedgeDist.ref();
674 
675  forAll(allEdgeInfo, edgei)
676  {
677  edgeDist[edgei] = Foam::sqrt(allEdgeInfo[edgei].distSqr());
678  }
679 
680  return tedgeDist;
681 }
682 
683 
684 void Foam::snappySnapDriver::dumpMove
685 (
686  const fileName& fName,
687  const pointField& meshPts,
688  const pointField& surfPts
689 )
690 {
691  // Dump direction of growth into file
692  Info<< "Dumping move direction to " << fName << endl;
693 
694  OFstream nearestStream(fName);
695 
696  label verti = 0;
697 
698  forAll(meshPts, pti)
699  {
700  meshTools::writeOBJ(nearestStream, meshPts[pti]);
701  verti++;
702 
703  meshTools::writeOBJ(nearestStream, surfPts[pti]);
704  verti++;
705 
706  nearestStream<< "l " << verti-1 << ' ' << verti << nl;
707  }
708 }
709 
710 
711 // Check whether all displacement vectors point outwards of patch. Return true
712 // if so.
713 bool Foam::snappySnapDriver::outwardsDisplacement
714 (
715  const indirectPrimitivePatch& pp,
716  const vectorField& patchDisp
717 )
718 {
719  const vectorField& faceNormals = pp.faceNormals();
720  const labelListList& pointFaces = pp.pointFaces();
721 
722  forAll(pointFaces, pointi)
723  {
724  const labelList& pFaces = pointFaces[pointi];
725 
726  vector disp(patchDisp[pointi]);
727 
728  scalar magDisp = mag(disp);
729 
730  if (magDisp > SMALL)
731  {
732  disp /= magDisp;
733 
734  bool outwards = meshTools::visNormal(disp, faceNormals, pFaces);
735 
736  if (!outwards)
737  {
738  Warning<< "Displacement " << patchDisp[pointi]
739  << " at mesh point " << pp.meshPoints()[pointi]
740  << " coord " << pp.points()[pp.meshPoints()[pointi]]
741  << " points through the surrounding patch faces" << endl;
742  return false;
743  }
744  }
745  else
746  {
747  //? Displacement small but in wrong direction. Would probably be ok.
748  }
749  }
750  return true;
751 }
752 
753 
754 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
755 
756 Foam::snappySnapDriver::snappySnapDriver
757 (
758  meshRefinement& meshRefiner,
759  const labelList& globalToMasterPatch,
760  const labelList& globalToSlavePatch,
761  const bool dryRun
762 )
763 :
764  meshRefiner_(meshRefiner),
765  globalToMasterPatch_(globalToMasterPatch),
766  globalToSlavePatch_(globalToSlavePatch),
767  dryRun_(dryRun)
768 {}
769 
770 
771 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
772 
774 (
775  const fvMesh& mesh,
776  const snapParameters& snapParams,
777  const indirectPrimitivePatch& pp
778 )
779 {
780  const edgeList& edges = pp.edges();
781  const labelListList& pointEdges = pp.pointEdges();
782  const pointField& localPoints = pp.localPoints();
783 
784  scalarField maxEdgeLen(localPoints.size(), -GREAT);
785 
786  forAll(pointEdges, pointi)
787  {
788  const labelList& pEdges = pointEdges[pointi];
789 
790  forAll(pEdges, pEdgei)
791  {
792  const edge& e = edges[pEdges[pEdgei]];
793 
794  scalar len = e.mag(localPoints);
795 
796  maxEdgeLen[pointi] = max(maxEdgeLen[pointi], len);
797  }
798  }
799 
801  (
802  mesh,
803  pp.meshPoints(),
804  maxEdgeLen,
805  maxEqOp<scalar>(), // combine op
806  -GREAT // null value
807  );
808 
809  return scalarField(snapParams.snapTol()*maxEdgeLen);
810 }
811 
812 
814 (
815  const meshRefinement& meshRefiner,
816  const snapParameters& snapParams,
817  const label nInitErrors,
818  const List<labelPair>& baffles,
819  motionSmoother& meshMover
820 )
821 {
822  addProfiling(smooth, "snappyHexMesh::snap::smoothing");
823  const fvMesh& mesh = meshRefiner.mesh();
824 
825  labelList checkFaces;
826 
827  if (snapParams.nSmoothInternal() > 0)
828  {
829  Info<< "Smoothing patch and internal points ..." << endl;
830  }
831  else
832  {
833  Info<< "Smoothing patch points ..." << endl;
834  }
835 
836  vectorField& pointDisp = meshMover.pointDisplacement().primitiveFieldRef();
837 
838  for
839  (
840  label smoothIter = 0;
841  smoothIter < snapParams.nSmoothPatch();
842  smoothIter++
843  )
844  {
845  Info<< "Smoothing iteration " << smoothIter << endl;
846  checkFaces.setSize(mesh.nFaces());
847  forAll(checkFaces, facei)
848  {
849  checkFaces[facei] = facei;
850  }
851 
852  // If enabled smooth the internal points
853  if (snapParams.nSmoothInternal() > smoothIter)
854  {
855  // Override values on internal points on refinement interfaces
856  pointDisp = smoothInternalDisplacement(meshRefiner, meshMover);
857  }
858 
859  // Smooth the patch points
860  pointField patchDisp(smoothPatchDisplacement(meshMover, baffles));
861  //pointField patchDisp
862  //(
863  // smoothLambdaMuPatchDisplacement(meshMover, baffles)
864  //);
865 
866  // Take over patch displacement as boundary condition on
867  // pointDisplacement
868  meshMover.setDisplacement(patchDisp);
869 
870  // Start off from current mesh.points()
871  meshMover.correct();
872 
873  scalar oldErrorReduction = -1;
874 
875  for (label snapIter = 0; snapIter < 2*snapParams.nSnap(); snapIter++)
876  {
877  Info<< nl << "Scaling iteration " << snapIter << endl;
878 
879  if (snapIter == snapParams.nSnap())
880  {
881  Info<< "Displacement scaling for error reduction set to 0."
882  << endl;
883  oldErrorReduction = meshMover.setErrorReduction(0.0);
884  }
885 
886  // Try to adapt mesh to obtain displacement by smoothly
887  // decreasing displacement at error locations.
888  if (meshMover.scaleMesh(checkFaces, baffles, true, nInitErrors))
889  {
890  Info<< "Successfully moved mesh" << endl;
891  break;
892  }
893  }
894 
895  if (oldErrorReduction >= 0)
896  {
897  meshMover.setErrorReduction(oldErrorReduction);
898  }
899  Info<< endl;
900  }
901 
902 
903  // The current mesh is the starting mesh to smooth from.
904  meshMover.correct();
905 
907  {
908  const_cast<Time&>(mesh.time())++;
909  Info<< "Writing patch smoothed mesh to time "
910  << meshRefiner.timeName() << '.' << endl;
911  meshRefiner.write
912  (
915  (
918  ),
919  mesh.time().path()/meshRefiner.timeName()
920  );
921  Info<< "Dumped mesh in = "
922  << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl;
923  }
924 
925  Info<< "Patch points smoothed in = "
926  << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl;
927 }
928 
929 
930 // Get (pp-local) indices of points that are both on zone and on patched surface
931 Foam::labelList Foam::snappySnapDriver::getZoneSurfacePoints
932 (
933  const fvMesh& mesh,
934  const indirectPrimitivePatch& pp,
935  const word& zoneName
936 )
937 {
938  label zonei = mesh.faceZones().findZoneID(zoneName);
939 
940  if (zonei == -1)
941  {
943  << "Cannot find zone " << zoneName
944  << exit(FatalError);
945  }
946 
947  const faceZone& fZone = mesh.faceZones()[zonei];
948 
949 
950  // Could use PrimitivePatch & localFaces to extract points but might just
951  // as well do it ourselves.
952 
953  boolList pointOnZone(pp.nPoints(), false);
954 
955  forAll(fZone, i)
956  {
957  const face& f = mesh.faces()[fZone[i]];
958 
959  forAll(f, fp)
960  {
961  label meshPointi = f[fp];
962 
963  const auto iter = pp.meshPointMap().cfind(meshPointi);
964 
965  if (iter.found())
966  {
967  const label pointi = iter.val();
968  pointOnZone[pointi] = true;
969  }
970  }
971  }
972 
973  return findIndices(pointOnZone, true);
974 }
975 
976 
978 (
979  const fvMesh& mesh,
980  const indirectPrimitivePatch& pp
981 )
982 {
983  const labelListList& pointFaces = pp.pointFaces();
984 
985 
986  tmp<pointField> tavgBoundary
987  (
988  new pointField(pointFaces.size(), Zero)
989  );
990  pointField& avgBoundary = tavgBoundary.ref();
991  labelList nBoundary(pointFaces.size(), Zero);
992 
993  forAll(pointFaces, pointi)
994  {
995  const labelList& pFaces = pointFaces[pointi];
996 
997  forAll(pFaces, pfi)
998  {
999  label facei = pFaces[pfi];
1000  label meshFacei = pp.addressing()[facei];
1001 
1002  label own = mesh.faceOwner()[meshFacei];
1003  avgBoundary[pointi] += mesh.cellCentres()[own];
1004  nBoundary[pointi]++;
1005  }
1006  }
1007 
1009  (
1010  mesh,
1011  pp.meshPoints(),
1012  avgBoundary,
1013  plusEqOp<point>(), // combine op
1014  vector::zero // null value
1015  );
1017  (
1018  mesh,
1019  pp.meshPoints(),
1020  nBoundary,
1021  plusEqOp<label>(), // combine op
1022  label(0) // null value
1023  );
1024 
1025  forAll(avgBoundary, i)
1026  {
1027  avgBoundary[i] /= nBoundary[i];
1028  }
1029  return tavgBoundary;
1030 }
1031 
1032 
1033 //Foam::tmp<Foam::scalarField> Foam::snappySnapDriver::calcEdgeLen
1034 //(
1035 // const indirectPrimitivePatch& pp
1036 //) const
1037 //{
1038 // // Get local edge length based on refinement level
1039 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1040 // // (Ripped from snappyLayerDriver)
1041 //
1042 // tmp<scalarField> tedgeLen(new scalarField(pp.nPoints()));
1043 // scalarField& edgeLen = tedgeLen();
1044 // {
1045 // const fvMesh& mesh = meshRefiner_.mesh();
1046 // const scalar edge0Len = meshRefiner_.meshCutter().level0EdgeLength();
1047 // const labelList& cellLevel = meshRefiner_.meshCutter().cellLevel();
1048 //
1049 // labelList maxPointLevel(pp.nPoints(), labelMin);
1050 //
1051 // forAll(pp, i)
1052 // {
1053 // label ownLevel = cellLevel[mesh.faceOwner()[pp.addressing()[i]]];
1054 // const face& f = pp.localFaces()[i];
1055 // forAll(f, fp)
1056 // {
1057 // maxPointLevel[f[fp]] = max(maxPointLevel[f[fp]], ownLevel);
1058 // }
1059 // }
1060 //
1061 // syncTools::syncPointList
1062 // (
1063 // mesh,
1064 // pp.meshPoints(),
1065 // maxPointLevel,
1066 // maxEqOp<label>(),
1067 // labelMin // null value
1068 // );
1069 //
1070 //
1071 // forAll(maxPointLevel, pointi)
1072 // {
1073 // // Find undistorted edge size for this level.
1074 // edgeLen[pointi] = edge0Len/(1<<maxPointLevel[pointi]);
1075 // }
1076 // }
1077 // return tedgeLen;
1078 //}
1079 
1080 
1083  const scalar planarCos,
1084  const indirectPrimitivePatch& pp,
1085  const pointField& nearestPoint,
1086  const vectorField& nearestNormal,
1087 
1088  vectorField& disp
1089 ) const
1090 {
1091  Info<< "Detecting near surfaces ..." << endl;
1092 
1093  const pointField& localPoints = pp.localPoints();
1094  const labelList& meshPoints = pp.meshPoints();
1095  const refinementSurfaces& surfaces = meshRefiner_.surfaces();
1096  const fvMesh& mesh = meshRefiner_.mesh();
1097 
1099  //const scalarField edgeLen(calcEdgeLen(pp));
1100  //
1103  //
1104  //{
1105  // const vector n = normalised(vector::one);
1106  //
1107  // pointField start(14*pp.nPoints());
1108  // pointField end(start.size());
1109  //
1110  // label rayi = 0;
1111  // forAll(localPoints, pointi)
1112  // {
1113  // const point& pt = localPoints[pointi];
1114  //
1115  // // Along coordinate axes
1116  //
1117  // {
1118  // start[rayi] = pt;
1119  // point& endPt = end[rayi++];
1120  // endPt = pt;
1121  // endPt.x() -= edgeLen[pointi];
1122  // }
1123  // {
1124  // start[rayi] = pt;
1125  // point& endPt = end[rayi++];
1126  // endPt = pt;
1127  // endPt.x() += edgeLen[pointi];
1128  // }
1129  // {
1130  // start[rayi] = pt;
1131  // point& endPt = end[rayi++];
1132  // endPt = pt;
1133  // endPt.y() -= edgeLen[pointi];
1134  // }
1135  // {
1136  // start[rayi] = pt;
1137  // point& endPt = end[rayi++];
1138  // endPt = pt;
1139  // endPt.y() += edgeLen[pointi];
1140  // }
1141  // {
1142  // start[rayi] = pt;
1143  // point& endPt = end[rayi++];
1144  // endPt = pt;
1145  // endPt.z() -= edgeLen[pointi];
1146  // }
1147  // {
1148  // start[rayi] = pt;
1149  // point& endPt = end[rayi++];
1150  // endPt = pt;
1151  // endPt.z() += edgeLen[pointi];
1152  // }
1153  //
1154  // // At 45 degrees
1155  //
1156  // const vector vec(edgeLen[pointi]*n);
1157  //
1158  // {
1159  // start[rayi] = pt;
1160  // point& endPt = end[rayi++];
1161  // endPt = pt;
1162  // endPt.x() += vec.x();
1163  // endPt.y() += vec.y();
1164  // endPt.z() += vec.z();
1165  // }
1166  // {
1167  // start[rayi] = pt;
1168  // point& endPt = end[rayi++];
1169  // endPt = pt;
1170  // endPt.x() -= vec.x();
1171  // endPt.y() += vec.y();
1172  // endPt.z() += vec.z();
1173  // }
1174  // {
1175  // start[rayi] = pt;
1176  // point& endPt = end[rayi++];
1177  // endPt = pt;
1178  // endPt.x() += vec.x();
1179  // endPt.y() -= vec.y();
1180  // endPt.z() += vec.z();
1181  // }
1182  // {
1183  // start[rayi] = pt;
1184  // point& endPt = end[rayi++];
1185  // endPt = pt;
1186  // endPt.x() -= vec.x();
1187  // endPt.y() -= vec.y();
1188  // endPt.z() += vec.z();
1189  // }
1190  // {
1191  // start[rayi] = pt;
1192  // point& endPt = end[rayi++];
1193  // endPt = pt;
1194  // endPt.x() += vec.x();
1195  // endPt.y() += vec.y();
1196  // endPt.z() -= vec.z();
1197  // }
1198  // {
1199  // start[rayi] = pt;
1200  // point& endPt = end[rayi++];
1201  // endPt = pt;
1202  // endPt.x() -= vec.x();
1203  // endPt.y() += vec.y();
1204  // endPt.z() -= vec.z();
1205  // }
1206  // {
1207  // start[rayi] = pt;
1208  // point& endPt = end[rayi++];
1209  // endPt = pt;
1210  // endPt.x() += vec.x();
1211  // endPt.y() -= vec.y();
1212  // endPt.z() -= vec.z();
1213  // }
1214  // {
1215  // start[rayi] = pt;
1216  // point& endPt = end[rayi++];
1217  // endPt = pt;
1218  // endPt.x() -= vec.x();
1219  // endPt.y() -= vec.y();
1220  // endPt.z() -= vec.z();
1221  // }
1222  // }
1223  //
1224  // labelList surface1;
1225  // List<pointIndexHit> hit1;
1226  // labelList region1;
1227  // vectorField normal1;
1228  //
1229  // labelList surface2;
1230  // List<pointIndexHit> hit2;
1231  // labelList region2;
1232  // vectorField normal2;
1233  // surfaces.findNearestIntersection
1234  // (
1235  // unzonedSurfaces, // surfacesToTest,
1236  // start,
1237  // end,
1238  //
1239  // surface1,
1240  // hit1,
1241  // region1,
1242  // normal1,
1243  //
1244  // surface2,
1245  // hit2,
1246  // region2,
1247  // normal2
1248  // );
1249  //
1250  // // All intersections
1251  // {
1252  // OBJstream str
1253  // (
1254  // mesh.time().path()
1255  // / "surfaceHits_" + meshRefiner_.timeName() + ".obj"
1256  // );
1257  //
1258  // Info<< "Dumping intersections with rays to " << str.name()
1259  // << endl;
1260  //
1261  // forAll(hit1, i)
1262  // {
1263  // if (hit1[i].hit())
1264  // {
1265  // str.write(linePointRef(start[i], hit1[i].hitPoint()));
1266  // }
1267  // if (hit2[i].hit())
1268  // {
1269  // str.write(linePointRef(start[i], hit2[i].hitPoint()));
1270  // }
1271  // }
1272  // }
1273  //
1274  // // Co-planar intersections
1275  // {
1276  // OBJstream str
1277  // (
1278  // mesh.time().path()
1279  // / "coplanarHits_" + meshRefiner_.timeName() + ".obj"
1280  // );
1281  //
1282  // Info<< "Dumping intersections with co-planar surfaces to "
1283  // << str.name() << endl;
1284  //
1285  // forAll(localPoints, pointi)
1286  // {
1287  // bool hasNormal = false;
1288  // point surfPointA;
1289  // vector surfNormalA;
1290  // point surfPointB;
1291  // vector surfNormalB;
1292  //
1293  // bool isCoplanar = false;
1294  //
1295  // label rayi = 14*pointi;
1296  // for (label i = 0; i < 14; i++)
1297  // {
1298  // if (hit1[rayi].hit())
1299  // {
1300  // const point& pt = hit1[rayi].hitPoint();
1301  // const vector& n = normal1[rayi];
1302  //
1303  // if (!hasNormal)
1304  // {
1305  // hasNormal = true;
1306  // surfPointA = pt;
1307  // surfNormalA = n;
1308  // }
1309  // else
1310  // {
1311  // if
1312  // (
1313  // meshRefiner_.isGap
1314  // (
1315  // planarCos,
1316  // surfPointA,
1317  // surfNormalA,
1318  // pt,
1319  // n
1320  // )
1321  // )
1322  // {
1323  // isCoplanar = true;
1324  // surfPointB = pt;
1325  // surfNormalB = n;
1326  // break;
1327  // }
1328  // }
1329  // }
1330  // if (hit2[rayi].hit())
1331  // {
1332  // const point& pt = hit2[rayi].hitPoint();
1333  // const vector& n = normal2[rayi];
1334  //
1335  // if (!hasNormal)
1336  // {
1337  // hasNormal = true;
1338  // surfPointA = pt;
1339  // surfNormalA = n;
1340  // }
1341  // else
1342  // {
1343  // if
1344  // (
1345  // meshRefiner_.isGap
1346  // (
1347  // planarCos,
1348  // surfPointA,
1349  // surfNormalA,
1350  // pt,
1351  // n
1352  // )
1353  // )
1354  // {
1355  // isCoplanar = true;
1356  // surfPointB = pt;
1357  // surfNormalB = n;
1358  // break;
1359  // }
1360  // }
1361  // }
1362  //
1363  // rayi++;
1364  // }
1365  //
1366  // if (isCoplanar)
1367  // {
1368  // str.write(linePointRef(surfPointA, surfPointB));
1369  // }
1370  // }
1371  // }
1372  //}
1373 
1374 
1375  const pointField avgCc(avgCellCentres(mesh, pp));
1376 
1377  // Construct rays through localPoints to beyond cell centre
1378  pointField start(pp.nPoints());
1379  pointField end(pp.nPoints());
1380  forAll(localPoints, pointi)
1381  {
1382  const point& pt = localPoints[pointi];
1383  const vector d = 2*(avgCc[pointi]-pt);
1384  start[pointi] = pt - d;
1385  end[pointi] = pt + d;
1386  }
1387 
1388 
1389  autoPtr<OBJstream> gapStr;
1391  {
1392  gapStr.reset
1393  (
1394  new OBJstream
1395  (
1396  mesh.time().path()
1397  / "detectNearSurfaces_" + meshRefiner_.timeName() + ".obj"
1398  )
1399  );
1400  }
1401 
1402 
1403  const bitSet isPatchMasterPoint
1404  (
1406  (
1407  mesh,
1408  meshPoints
1409  )
1410  );
1411 
1412  label nOverride = 0;
1413 
1414  // 1. All points to non-interface surfaces
1415  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1416  {
1417  const labelList unzonedSurfaces =
1419  (
1420  meshRefiner_.surfaces().surfZones()
1421  );
1422 
1423  // Do intersection test
1424  labelList surface1;
1425  List<pointIndexHit> hit1;
1426  labelList region1;
1427  vectorField normal1;
1428 
1429  labelList surface2;
1430  List<pointIndexHit> hit2;
1431  labelList region2;
1432  vectorField normal2;
1433  surfaces.findNearestIntersection
1434  (
1435  unzonedSurfaces,
1436  start,
1437  end,
1438 
1439  surface1,
1440  hit1,
1441  region1,
1442  normal1,
1443 
1444  surface2,
1445  hit2,
1446  region2,
1447  normal2
1448  );
1449 
1450 
1451  forAll(localPoints, pointi)
1452  {
1453  // Current location
1454  const point& pt = localPoints[pointi];
1455 
1456  bool override = false;
1457 
1458  //if (hit1[pointi].hit())
1459  //{
1460  // if
1461  // (
1462  // meshRefiner_.isGap
1463  // (
1464  // planarCos,
1465  // nearestPoint[pointi],
1466  // nearestNormal[pointi],
1467  // hit1[pointi].hitPoint(),
1468  // normal1[pointi]
1469  // )
1470  // )
1471  // {
1472  // disp[pointi] = hit1[pointi].hitPoint()-pt;
1473  // override = true;
1474  // }
1475  //}
1476  //if (hit2[pointi].hit())
1477  //{
1478  // if
1479  // (
1480  // meshRefiner_.isGap
1481  // (
1482  // planarCos,
1483  // nearestPoint[pointi],
1484  // nearestNormal[pointi],
1485  // hit2[pointi].hitPoint(),
1486  // normal2[pointi]
1487  // )
1488  // )
1489  // {
1490  // disp[pointi] = hit2[pointi].hitPoint()-pt;
1491  // override = true;
1492  // }
1493  //}
1494 
1495  if (hit1[pointi].hit() && hit2[pointi].hit())
1496  {
1497  if
1498  (
1499  meshRefiner_.isGap
1500  (
1501  planarCos,
1502  hit1[pointi].hitPoint(),
1503  normal1[pointi],
1504  hit2[pointi].hitPoint(),
1505  normal2[pointi]
1506  )
1507  )
1508  {
1509  // TBD: check if the attraction (to nearest) would attract
1510  // good enough and not override attraction
1511 
1512  if (gapStr.valid())
1513  {
1514  const point& intPt = hit2[pointi].hitPoint();
1515  gapStr().write(linePointRef(pt, intPt));
1516  }
1517 
1518  // Choose hit2 : nearest to end point (so inside the domain)
1519  disp[pointi] = hit2[pointi].hitPoint()-pt;
1520  override = true;
1521  }
1522  }
1523 
1524  if (override && isPatchMasterPoint[pointi])
1525  {
1526  nOverride++;
1527  }
1528  }
1529  }
1530 
1531 
1532  // 2. All points on zones to their respective surface
1533  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1534 
1535  {
1536  // Surfaces with zone information
1537  const PtrList<surfaceZonesInfo>& surfZones = surfaces.surfZones();
1538 
1539  const labelList zonedSurfaces = surfaceZonesInfo::getNamedSurfaces
1540  (
1541  surfZones
1542  );
1543 
1544  forAll(zonedSurfaces, i)
1545  {
1546  label zoneSurfi = zonedSurfaces[i];
1547 
1548  const word& faceZoneName = surfZones[zoneSurfi].faceZoneName();
1549 
1550  const labelList surfacesToTest(1, zoneSurfi);
1551 
1552  // Get indices of points both on faceZone and on pp.
1553  labelList zonePointIndices
1554  (
1555  getZoneSurfacePoints
1556  (
1557  mesh,
1558  pp,
1559  faceZoneName
1560  )
1561  );
1562 
1563  // Do intersection test
1564  labelList surface1;
1565  List<pointIndexHit> hit1;
1566  labelList region1;
1567  vectorField normal1;
1568 
1569  labelList surface2;
1570  List<pointIndexHit> hit2;
1571  labelList region2;
1572  vectorField normal2;
1573  surfaces.findNearestIntersection
1574  (
1575  surfacesToTest,
1576  pointField(start, zonePointIndices),
1577  pointField(end, zonePointIndices),
1578 
1579  surface1,
1580  hit1,
1581  region1,
1582  normal1,
1583 
1584  surface2,
1585  hit2,
1586  region2,
1587  normal2
1588  );
1589 
1590 
1591  forAll(hit1, i)
1592  {
1593  label pointi = zonePointIndices[i];
1594 
1595  // Current location
1596  const point& pt = localPoints[pointi];
1597 
1598  bool override = false;
1599 
1600  //if (hit1[i].hit())
1601  //{
1602  // if
1603  // (
1604  // meshRefiner_.isGap
1605  // (
1606  // planarCos,
1607  // nearestPoint[pointi],
1608  // nearestNormal[pointi],
1609  // hit1[i].hitPoint(),
1610  // normal1[i]
1611  // )
1612  // )
1613  // {
1614  // disp[pointi] = hit1[i].hitPoint()-pt;
1615  // override = true;
1616  // }
1617  //}
1618  //if (hit2[i].hit())
1619  //{
1620  // if
1621  // (
1622  // meshRefiner_.isGap
1623  // (
1624  // planarCos,
1625  // nearestPoint[pointi],
1626  // nearestNormal[pointi],
1627  // hit2[i].hitPoint(),
1628  // normal2[i]
1629  // )
1630  // )
1631  // {
1632  // disp[pointi] = hit2[i].hitPoint()-pt;
1633  // override = true;
1634  // }
1635  //}
1636 
1637  if (hit1[i].hit() && hit2[i].hit())
1638  {
1639  if
1640  (
1641  meshRefiner_.isGap
1642  (
1643  planarCos,
1644  hit1[i].hitPoint(),
1645  normal1[i],
1646  hit2[i].hitPoint(),
1647  normal2[i]
1648  )
1649  )
1650  {
1651  if (gapStr.valid())
1652  {
1653  const point& intPt = hit2[i].hitPoint();
1654  gapStr().write(linePointRef(pt, intPt));
1655  }
1656 
1657  disp[pointi] = hit2[i].hitPoint()-pt;
1658  override = true;
1659  }
1660  }
1661 
1662  if (override && isPatchMasterPoint[pointi])
1663  {
1664  nOverride++;
1665  }
1666  }
1667  }
1668  }
1669 
1670  Info<< "Overriding nearest with intersection of close gaps at "
1671  << returnReduce(nOverride, sumOp<label>())
1672  << " out of " << returnReduce(pp.nPoints(), sumOp<label>())
1673  << " points." << endl;
1674 }
1675 
1676 
1677 void Foam::snappySnapDriver::calcNearestSurface
1678 (
1679  const refinementSurfaces& surfaces,
1680 
1681  const labelList& surfacesToTest,
1682  const labelListList& regionsToTest,
1683 
1684  const pointField& localPoints,
1685  const labelList& zonePointIndices,
1686 
1687  scalarField& minSnapDist,
1688  labelList& snapSurf,
1689  vectorField& patchDisp,
1690 
1691  // Optional: nearest point, normal
1692  pointField& nearestPoint,
1693  vectorField& nearestNormal
1694 )
1695 {
1696  // Find nearest for points both on faceZone and pp.
1697  List<pointIndexHit> hitInfo;
1698  labelList hitSurface;
1699 
1700  if (nearestNormal.size() == localPoints.size())
1701  {
1702  labelList hitRegion;
1703  vectorField hitNormal;
1704  surfaces.findNearestRegion
1705  (
1706  surfacesToTest,
1707  regionsToTest,
1708 
1709  pointField(localPoints, zonePointIndices),
1710  sqr(scalarField(minSnapDist, zonePointIndices)),
1711 
1712  hitSurface,
1713  hitInfo,
1714  hitRegion,
1715  hitNormal
1716  );
1717 
1718  forAll(hitInfo, i)
1719  {
1720  if (hitInfo[i].hit())
1721  {
1722  label pointi = zonePointIndices[i];
1723  nearestPoint[pointi] = hitInfo[i].hitPoint();
1724  nearestNormal[pointi] = hitNormal[i];
1725  }
1726  }
1727  }
1728  else
1729  {
1730  surfaces.findNearest
1731  (
1732  surfacesToTest,
1733  regionsToTest,
1734 
1735  pointField(localPoints, zonePointIndices),
1736  sqr(scalarField(minSnapDist, zonePointIndices)),
1737 
1738  hitSurface,
1739  hitInfo
1740  );
1741  }
1742 
1743  forAll(hitInfo, i)
1744  {
1745  if (hitInfo[i].hit())
1746  {
1747  label pointi = zonePointIndices[i];
1748 
1749  patchDisp[pointi] = hitInfo[i].hitPoint() - localPoints[pointi];
1750  minSnapDist[pointi] = mag(patchDisp[pointi]);
1751  snapSurf[pointi] = hitSurface[i];
1752  }
1753  }
1754 }
1755 
1756 
1757 Foam::vectorField Foam::snappySnapDriver::calcNearestSurface
1759  const bool strictRegionSnap,
1760  const meshRefinement& meshRefiner,
1761  const labelList& globalToMasterPatch,
1762  const labelList& globalToSlavePatch,
1763  const scalarField& snapDist,
1764  const indirectPrimitivePatch& pp,
1765  pointField& nearestPoint,
1766  vectorField& nearestNormal
1767 )
1768 {
1769  Info<< "Calculating patchDisplacement as distance to nearest surface"
1770  << " point ..." << endl;
1771  if (strictRegionSnap)
1772  {
1773  Info<< " non-zone points : attract to local region on surface only"
1774  << nl
1775  << " zone points : attract to local region on surface only"
1776  << nl
1777  << endl;
1778  }
1779  else
1780  {
1781  Info<< " non-zone points :"
1782  << " attract to nearest of all non-zone surfaces"
1783  << nl
1784  << " zone points : attract to zone surface only" << nl
1785  << endl;
1786  }
1787 
1788 
1789  const pointField& localPoints = pp.localPoints();
1790  const refinementSurfaces& surfaces = meshRefiner.surfaces();
1791  const fvMesh& mesh = meshRefiner.mesh();
1792 
1793  // Displacement per patch point
1794  vectorField patchDisp(localPoints.size(), Zero);
1795 
1796  if (returnReduce(localPoints.size(), sumOp<label>()) > 0)
1797  {
1798  // Current surface snapped to. Used to check whether points have been
1799  // snapped at all
1800  labelList snapSurf(localPoints.size(), -1);
1801 
1802  // Current best snap distance (since point might be on multiple
1803  // regions)
1804  scalarField minSnapDist(snapDist);
1805 
1806 
1807  if (strictRegionSnap)
1808  {
1809  // Attract patch points to same region only
1810 
1811  forAll(surfaces.surfaces(), surfi)
1812  {
1813  label geomi = surfaces.surfaces()[surfi];
1814  label nRegions = surfaces.geometry()[geomi].regions().size();
1815 
1816  const labelList surfacesToTest(1, surfi);
1817 
1818  for (label regioni = 0; regioni < nRegions; regioni++)
1819  {
1820  label globali = surfaces.globalRegion(surfi, regioni);
1821  label masterPatchi = globalToMasterPatch[globali];
1822 
1823  // Get indices of points both on patch and on pp
1824  labelList zonePointIndices
1825  (
1826  getFacePoints
1827  (
1828  pp,
1829  mesh.boundaryMesh()[masterPatchi]
1830  )
1831  );
1832 
1833  calcNearestSurface
1834  (
1835  surfaces,
1836 
1837  surfacesToTest,
1838  labelListList(1, labelList(1, regioni)), //regionsToTest
1839 
1840  localPoints,
1841  zonePointIndices,
1842 
1843  minSnapDist,
1844  snapSurf,
1845  patchDisp,
1846 
1847  // Optional: nearest point, normal
1848  nearestPoint,
1849  nearestNormal
1850  );
1851 
1852  if (globalToSlavePatch[globali] != masterPatchi)
1853  {
1854  label slavePatchi = globalToSlavePatch[globali];
1855 
1856  // Get indices of points both on patch and on pp
1857  labelList zonePointIndices
1858  (
1859  getFacePoints
1860  (
1861  pp,
1862  mesh.boundaryMesh()[slavePatchi]
1863  )
1864  );
1865 
1866  calcNearestSurface
1867  (
1868  surfaces,
1869 
1870  surfacesToTest,
1871  labelListList(1, labelList(1, regioni)),
1872 
1873  localPoints,
1874  zonePointIndices,
1875 
1876  minSnapDist,
1877  snapSurf,
1878  patchDisp,
1879 
1880  // Optional: nearest point, normal
1881  nearestPoint,
1882  nearestNormal
1883  );
1884  }
1885  }
1886  }
1887  }
1888  else
1889  {
1890  // Divide surfaces into zoned and unzoned
1891  const labelList unzonedSurfaces =
1893  (
1894  meshRefiner.surfaces().surfZones()
1895  );
1896 
1897 
1898  // 1. All points to non-interface surfaces
1899  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1900 
1901  List<pointIndexHit> hitInfo;
1902  labelList hitSurface;
1903 
1904  if (nearestNormal.size() == localPoints.size())
1905  {
1906  labelList hitRegion;
1907  vectorField hitNormal;
1908  surfaces.findNearestRegion
1909  (
1910  unzonedSurfaces,
1911  localPoints,
1912  sqr(snapDist),
1913  hitSurface,
1914  hitInfo,
1915  hitRegion,
1916  hitNormal
1917  );
1918 
1919  forAll(hitInfo, pointi)
1920  {
1921  if (hitInfo[pointi].hit())
1922  {
1923  nearestPoint[pointi] = hitInfo[pointi].hitPoint();
1924  nearestNormal[pointi] = hitNormal[pointi];
1925  }
1926  }
1927  }
1928  else
1929  {
1930  surfaces.findNearest
1931  (
1932  unzonedSurfaces,
1933  localPoints,
1934  sqr(snapDist), // sqr of attract distance
1935  hitSurface,
1936  hitInfo
1937  );
1938  }
1939 
1940  forAll(hitInfo, pointi)
1941  {
1942  if (hitInfo[pointi].hit())
1943  {
1944  patchDisp[pointi] =
1945  hitInfo[pointi].hitPoint()
1946  - localPoints[pointi];
1947 
1948  snapSurf[pointi] = hitSurface[pointi];
1949  }
1950  }
1951 
1952 
1953  const labelList zonedSurfaces =
1955  (
1956  meshRefiner.surfaces().surfZones()
1957  );
1958 
1959 
1960  // 2. All points on zones to their respective surface
1961  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1962 
1963  // Surfaces with zone information
1964  const PtrList<surfaceZonesInfo>& surfZones = surfaces.surfZones();
1965 
1966  forAll(zonedSurfaces, i)
1967  {
1968  label surfi = zonedSurfaces[i];
1969 
1970  const word& faceZoneName = surfZones[surfi].faceZoneName();
1971 
1972  const labelList surfacesToTest(1, surfi);
1973 
1974  label geomi = surfaces.surfaces()[surfi];
1975  label nRegions = surfaces.geometry()[geomi].regions().size();
1976 
1977 
1978  // Get indices of points both on faceZone and on pp.
1979  labelList zonePointIndices
1980  (
1981  getZoneSurfacePoints
1982  (
1983  mesh,
1984  pp,
1985  faceZoneName
1986  )
1987  );
1988 
1989 
1990  calcNearestSurface
1991  (
1992  surfaces,
1993 
1994  surfacesToTest,
1995  labelListList(1, identity(nRegions)),
1996 
1997  localPoints,
1998  zonePointIndices,
1999 
2000  minSnapDist,
2001  snapSurf,
2002  patchDisp,
2003 
2004  // Optional: nearest point, normal
2005  nearestPoint,
2006  nearestNormal
2007  );
2008  }
2009  }
2010 
2011 
2012  // Check if all points are being snapped
2013  forAll(snapSurf, pointi)
2014  {
2015  if (snapSurf[pointi] == -1)
2016  {
2017  static label nWarn = 0;
2018 
2019  if (nWarn < 100)
2020  {
2022  << "For point:" << pointi
2023  << " coordinate:" << localPoints[pointi]
2024  << " did not find any surface within:"
2025  << minSnapDist[pointi] << " metre." << endl;
2026  nWarn++;
2027  if (nWarn == 100)
2028  {
2030  << "Reached warning limit " << nWarn
2031  << ". Suppressing further warnings." << endl;
2032  }
2033  }
2034  }
2035  }
2036 
2037  {
2038  const bitSet isPatchMasterPoint
2039  (
2041  (
2042  mesh,
2043  pp.meshPoints()
2044  )
2045  );
2046 
2047  scalarField magDisp(mag(patchDisp));
2048 
2049  Info<< "Wanted displacement : average:"
2050  << meshRefinement::gAverage(isPatchMasterPoint, magDisp)
2051  << " min:" << gMin(magDisp)
2052  << " max:" << gMax(magDisp) << endl;
2053  }
2054  }
2055 
2056  Info<< "Calculated surface displacement in = "
2057  << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl;
2058 
2059 
2060  // Limit amount of movement. Can not happen for triSurfaceMesh but
2061  // can happen for some analytical shapes?
2062  forAll(patchDisp, patchPointi)
2063  {
2064  scalar magDisp = mag(patchDisp[patchPointi]);
2065 
2066  if (magDisp > snapDist[patchPointi])
2067  {
2068  patchDisp[patchPointi] *= snapDist[patchPointi] / magDisp;
2069 
2070  Pout<< "Limiting displacement for " << patchPointi
2071  << " from " << magDisp << " to " << snapDist[patchPointi]
2072  << endl;
2073  }
2074  }
2075 
2076  // Points on zones in one domain but only present as point on other
2077  // will not do condition 2 on all. Sync explicitly.
2079  (
2080  mesh,
2081  pp.meshPoints(),
2082  patchDisp,
2083  minMagSqrEqOp<point>(), // combine op
2084  vector(GREAT, GREAT, GREAT) // null value (note: cannot use VGREAT)
2085  );
2086 
2087  return patchDisp;
2088 }
2089 
2090 
2093  const snapParameters& snapParams,
2094  motionSmoother& meshMover
2095 ) const
2096 {
2097  if (dryRun_)
2098  {
2099  return;
2100  }
2101 
2102  const fvMesh& mesh = meshRefiner_.mesh();
2103  const indirectPrimitivePatch& pp = meshMover.patch();
2104 
2105  Info<< "Smoothing displacement ..." << endl;
2106 
2107  // Set edge diffusivity as inverse of distance to patch
2108  scalarField edgeGamma(1.0/(edgePatchDist(meshMover.pMesh(), pp) + SMALL));
2109  //scalarField edgeGamma(mesh.nEdges(), 1.0);
2110  //scalarField edgeGamma(wallGamma(mesh, pp, 10, 1));
2111 
2112  // Get displacement field
2113  pointVectorField& disp = meshMover.displacement();
2114 
2115  for (label iter = 0; iter < snapParams.nSmoothDispl(); iter++)
2116  {
2117  if ((iter % 10) == 0)
2118  {
2119  Info<< "Iteration " << iter << endl;
2120  }
2121  pointVectorField oldDisp(disp);
2122  meshMover.smooth(oldDisp, edgeGamma, disp);
2123  }
2124  Info<< "Displacement smoothed in = "
2125  << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl;
2126 
2128  {
2129  const_cast<Time&>(mesh.time())++;
2130  Info<< "Writing smoothed mesh to time " << meshRefiner_.timeName()
2131  << endl;
2132 
2133  // Moving mesh creates meshPhi. Can be cleared out by a mesh.clearOut
2134  // but this will also delete all pointMesh but not pointFields which
2135  // gives an illegal situation.
2136 
2137  meshRefiner_.write
2138  (
2141  (
2144  ),
2145  mesh.time().path()/meshRefiner_.timeName()
2146  );
2147  Info<< "Writing displacement field ..." << endl;
2148  disp.write();
2149  tmp<pointScalarField> magDisp(mag(disp));
2150  magDisp().write();
2151 
2152  Info<< "Writing actual patch displacement ..." << endl;
2153  vectorField actualPatchDisp(disp, pp.meshPoints());
2154  dumpMove
2155  (
2156  mesh.time().path()
2157  / "actualPatchDisplacement_" + meshRefiner_.timeName() + ".obj",
2158  pp.localPoints(),
2159  pp.localPoints() + actualPatchDisp
2160  );
2161  }
2162 }
2163 
2164 
2167  const snapParameters& snapParams,
2168  const label nInitErrors,
2169  const List<labelPair>& baffles,
2170  motionSmoother& meshMover
2171 )
2172 {
2173  addProfiling(scale, "snappyHexMesh::snap::scale");
2174  const fvMesh& mesh = meshRefiner_.mesh();
2175 
2176  // Relax displacement until correct mesh
2177  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2178  labelList checkFaces(identity(mesh.nFaces()));
2179 
2180  scalar oldErrorReduction = -1;
2181 
2182  bool meshOk = false;
2183 
2184  Info<< "Moving mesh ..." << endl;
2185  for (label iter = 0; iter < 2*snapParams.nSnap(); iter++)
2186  {
2187  Info<< nl << "Iteration " << iter << endl;
2188 
2189  if (iter == snapParams.nSnap())
2190  {
2191  Info<< "Displacement scaling for error reduction set to 0." << endl;
2192  oldErrorReduction = meshMover.setErrorReduction(0.0);
2193  }
2194 
2195  meshOk = meshMover.scaleMesh(checkFaces, baffles, true, nInitErrors);
2196 
2197  if (meshOk)
2198  {
2199  Info<< "Successfully moved mesh" << endl;
2200  break;
2201  }
2203  {
2204  const_cast<Time&>(mesh.time())++;
2205  Info<< "Writing scaled mesh to time " << meshRefiner_.timeName()
2206  << endl;
2207  mesh.write();
2208 
2209  Info<< "Writing displacement field ..." << endl;
2210  meshMover.displacement().write();
2211  tmp<pointScalarField> magDisp(mag(meshMover.displacement()));
2212  magDisp().write();
2213  }
2214  }
2215 
2216  if (oldErrorReduction >= 0)
2217  {
2218  meshMover.setErrorReduction(oldErrorReduction);
2219  }
2220  Info<< "Moved mesh in = "
2221  << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl;
2222 
2223  return meshOk;
2224 }
2225 
2226 
2227 // After snapping: correct patching according to nearest surface.
2228 // Code is very similar to calcNearestSurface.
2229 // - calculate face-wise snap distance as max of point-wise
2230 // - calculate face-wise nearest surface point
2231 // - repatch face according to patch for surface point.
2234  const snapParameters& snapParams,
2235  const labelList& adaptPatchIDs,
2236  const labelList& preserveFaces
2237 )
2238 {
2239  const fvMesh& mesh = meshRefiner_.mesh();
2240  const refinementSurfaces& surfaces = meshRefiner_.surfaces();
2241 
2242  Info<< "Repatching faces according to nearest surface ..." << endl;
2243 
2244  // Get the labels of added patches.
2246  (
2248  (
2249  mesh,
2250  adaptPatchIDs
2251  )
2252  );
2253  indirectPrimitivePatch& pp = ppPtr();
2254 
2255  // Divide surfaces into zoned and unzoned
2256  labelList zonedSurfaces =
2258  labelList unzonedSurfaces =
2260 
2261 
2262  // Faces that do not move
2263  bitSet isZonedFace(mesh.nFaces());
2264  {
2265  // 1. Preserve faces in preserveFaces list
2266  forAll(preserveFaces, facei)
2267  {
2268  if (preserveFaces[facei] != -1)
2269  {
2270  isZonedFace.set(facei);
2271  }
2272  }
2273 
2274  // 2. All faces on zoned surfaces
2275  const PtrList<surfaceZonesInfo>& surfZones = surfaces.surfZones();
2276  const faceZoneMesh& fZones = mesh.faceZones();
2277 
2278  forAll(zonedSurfaces, i)
2279  {
2280  const label zoneSurfi = zonedSurfaces[i];
2281  const faceZone& fZone = fZones[surfZones[zoneSurfi].faceZoneName()];
2282 
2283  isZonedFace.set(fZone);
2284  }
2285  }
2286 
2287 
2288  // Determine per pp face which patch it should be in
2289  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2290 
2291  // Patch that face should be in
2292  labelList closestPatch(pp.size(), -1);
2293  {
2294  // face snap distance as max of point snap distance
2295  scalarField faceSnapDist(pp.size(), -GREAT);
2296  {
2297  // Distance to attract to nearest feature on surface
2298  const scalarField snapDist
2299  (
2300  calcSnapDistance
2301  (
2302  mesh,
2303  snapParams,
2304  pp
2305  )
2306  );
2307 
2308  const faceList& localFaces = pp.localFaces();
2309 
2310  forAll(localFaces, facei)
2311  {
2312  const face& f = localFaces[facei];
2313 
2314  forAll(f, fp)
2315  {
2316  faceSnapDist[facei] = max
2317  (
2318  faceSnapDist[facei],
2319  snapDist[f[fp]]
2320  );
2321  }
2322  }
2323  }
2324 
2325  pointField localFaceCentres(mesh.faceCentres(), pp.addressing());
2326 
2327  // Get nearest surface and region
2328  labelList hitSurface;
2329  labelList hitRegion;
2330  surfaces.findNearestRegion
2331  (
2332  unzonedSurfaces,
2333  localFaceCentres,
2334  sqr(faceSnapDist), // sqr of attract distance
2335  hitSurface,
2336  hitRegion
2337  );
2338 
2339  // Get patch
2340  forAll(pp, i)
2341  {
2342  label facei = pp.addressing()[i];
2343 
2344  if (hitSurface[i] != -1 && !isZonedFace.test(facei))
2345  {
2346  closestPatch[i] = globalToMasterPatch_
2347  [
2348  surfaces.globalRegion
2349  (
2350  hitSurface[i],
2351  hitRegion[i]
2352  )
2353  ];
2354  }
2355  }
2356  }
2357 
2358 
2359  // Change those faces for which there is a different closest patch
2360  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2361 
2362  labelList ownPatch(mesh.nFaces(), -1);
2363  labelList neiPatch(mesh.nFaces(), -1);
2364 
2366 
2367  forAll(patches, patchi)
2368  {
2369  const polyPatch& pp = patches[patchi];
2370 
2371  forAll(pp, i)
2372  {
2373  ownPatch[pp.start()+i] = patchi;
2374  neiPatch[pp.start()+i] = patchi;
2375  }
2376  }
2377 
2378  label nChanged = 0;
2379  forAll(closestPatch, i)
2380  {
2381  label facei = pp.addressing()[i];
2382 
2383  if (closestPatch[i] != -1 && closestPatch[i] != ownPatch[facei])
2384  {
2385  ownPatch[facei] = closestPatch[i];
2386  neiPatch[facei] = closestPatch[i];
2387  nChanged++;
2388  }
2389  }
2390 
2391  Info<< "Repatched " << returnReduce(nChanged, sumOp<label>())
2392  << " faces in = " << mesh.time().cpuTimeIncrement() << " s\n" << nl
2393  << endl;
2394 
2395  return meshRefiner_.createBaffles(ownPatch, neiPatch);
2396 }
2397 
2398 
2399 void Foam::snappySnapDriver::detectWarpedFaces
2400 (
2401  const scalar featureCos,
2402  const indirectPrimitivePatch& pp,
2403 
2404  DynamicList<label>& splitFaces,
2405  DynamicList<labelPair>& splits
2406 ) const
2407 {
2408  const fvMesh& mesh = meshRefiner_.mesh();
2409  const faceList& localFaces = pp.localFaces();
2410  const pointField& localPoints = pp.localPoints();
2411  const labelList& bFaces = pp.addressing();
2412 
2413  splitFaces.clear();
2414  splitFaces.setCapacity(bFaces.size());
2415  splits.clear();
2416  splits.setCapacity(bFaces.size());
2417 
2418  // Determine parallel consistent normals on points
2419  const vectorField pointNormals(PatchTools::pointNormals(mesh, pp));
2420 
2421  face f0(4);
2422  face f1(4);
2423 
2424  forAll(localFaces, facei)
2425  {
2426  const face& f = localFaces[facei];
2427 
2428  if (f.size() >= 4)
2429  {
2430  // See if splitting face across diagonal would make two faces with
2431  // biggish normal angle
2432 
2433  labelPair minDiag(-1, -1);
2434  scalar minCos(GREAT);
2435 
2436  for (label startFp = 0; startFp < f.size()-2; startFp++)
2437  {
2438  label minFp = f.rcIndex(startFp);
2439 
2440  for
2441  (
2442  label endFp = f.fcIndex(f.fcIndex(startFp));
2443  endFp < f.size() && endFp != minFp;
2444  endFp++
2445  )
2446  {
2447  // Form two faces
2448  f0.setSize(endFp-startFp+1);
2449  label i0 = 0;
2450  for (label fp = startFp; fp <= endFp; fp++)
2451  {
2452  f0[i0++] = f[fp];
2453  }
2454  f1.setSize(f.size()+2-f0.size());
2455  label i1 = 0;
2456  for (label fp = endFp; fp != startFp; fp = f.fcIndex(fp))
2457  {
2458  f1[i1++] = f[fp];
2459  }
2460  f1[i1++] = f[startFp];
2461 
2462  //Info<< "Splitting face:" << f << " into f0:" << f0
2463  // << " f1:" << f1 << endl;
2464 
2465  const vector n0 = f0.areaNormal(localPoints);
2466  const scalar n0Mag = mag(n0);
2467 
2468  const vector n1 = f1.areaNormal(localPoints);
2469  const scalar n1Mag = mag(n1);
2470 
2471  if (n0Mag > ROOTVSMALL && n1Mag > ROOTVSMALL)
2472  {
2473  scalar cosAngle = (n0/n0Mag) & (n1/n1Mag);
2474  if (cosAngle < minCos)
2475  {
2476  minCos = cosAngle;
2477  minDiag = labelPair(startFp, endFp);
2478  }
2479  }
2480  }
2481  }
2482 
2483 
2484  if (minCos < featureCos)
2485  {
2486  splitFaces.append(bFaces[facei]);
2487  splits.append(minDiag);
2488  }
2489  }
2490  }
2491 }
2492 
2493 
2494 Foam::labelList Foam::snappySnapDriver::getInternalOrBaffleDuplicateFace() const
2495 {
2496  const fvMesh& mesh = meshRefiner_.mesh();
2497 
2498  labelList internalOrBaffleFaceZones;
2499  {
2500  List<surfaceZonesInfo::faceZoneType> fzTypes(2);
2501  fzTypes[0] = surfaceZonesInfo::INTERNAL;
2502  fzTypes[1] = surfaceZonesInfo::BAFFLE;
2503  internalOrBaffleFaceZones = meshRefiner_.getZones(fzTypes);
2504  }
2505 
2506  List<labelPair> baffles
2507  (
2508  meshRefiner_.subsetBaffles
2509  (
2510  mesh,
2511  internalOrBaffleFaceZones,
2513  )
2514  );
2515 
2516  labelList faceToDuplicate(mesh.nFaces(), -1);
2517  forAll(baffles, i)
2518  {
2519  const labelPair& p = baffles[i];
2520  faceToDuplicate[p[0]] = p[1];
2521  faceToDuplicate[p[1]] = p[0];
2522  }
2523 
2524  return faceToDuplicate;
2525 }
2526 
2527 
2530  const dictionary& snapDict,
2531  const dictionary& motionDict,
2532  const meshRefinement::FaceMergeType mergeType,
2533  const scalar featureCos,
2534  const scalar planarAngle,
2535  const snapParameters& snapParams
2536 )
2537 {
2538  addProfiling(snap, "snappyHexMesh::snap");
2539  fvMesh& mesh = meshRefiner_.mesh();
2540 
2541  Info<< nl
2542  << "Morphing phase" << nl
2543  << "--------------" << nl
2544  << endl;
2545 
2546  // faceZone handling
2547  // ~~~~~~~~~~~~~~~~~
2548  //
2549  // We convert all faceZones into baffles during snapping so we can use
2550  // a standard mesh motion (except for the mesh checking which for baffles
2551  // created from internal faces should check across the baffles). The state
2552  // is stored in two variables:
2553  // baffles : pairs of boundary faces
2554  // duplicateFace : from mesh face to its baffle colleague (or -1 for
2555  // normal faces)
2556  // There are three types of faceZones according to the faceType property:
2557  //
2558  // internal
2559  // --------
2560  // - baffles: need to be checked across
2561  // - duplicateFace: from face to duplicate face. Contains
2562  // all faces on faceZone to prevents merging patch faces.
2563  //
2564  // baffle
2565  // ------
2566  // - baffles: no need to be checked across
2567  // - duplicateFace: contains all faces on faceZone to prevent
2568  // merging patch faces.
2569  //
2570  // boundary
2571  // --------
2572  // - baffles: no need to be checked across. Also points get duplicated
2573  // so will no longer be baffles
2574  // - duplicateFace: contains no faces on faceZone since both sides can
2575  // merge faces independently.
2576 
2577 
2578 
2579  // faceZones of type internal
2580  const labelList internalFaceZones
2581  (
2582  meshRefiner_.getZones
2583  (
2585  (
2586  1,
2588  )
2589  )
2590  );
2591 
2592 
2593  // Create baffles (pairs of faces that share the same points)
2594  // Baffles stored as owner and neighbour face that have been created.
2595  {
2596  List<labelPair> baffles;
2597  labelList originatingFaceZone;
2598  meshRefiner_.createZoneBaffles
2599  (
2600  identity(mesh.faceZones().size()),
2601  baffles,
2602  originatingFaceZone
2603  );
2604  }
2605 
2606  // Duplicate points on faceZones of type boundary
2607  meshRefiner_.dupNonManifoldBoundaryPoints();
2608 
2609 
2610  bool doFeatures = false;
2611  label nFeatIter = 1;
2612  if (snapParams.nFeatureSnap() > 0)
2613  {
2614  doFeatures = true;
2615 
2616  if (!dryRun_)
2617  {
2618  nFeatIter = snapParams.nFeatureSnap();
2619  }
2620 
2621  Info<< "Snapping to features in " << nFeatIter
2622  << " iterations ..." << endl;
2623  }
2624 
2625 
2626  bool meshOk = false;
2627 
2628 
2629  // Get the labels of added patches.
2630  labelList adaptPatchIDs(meshRefiner_.meshedPatches());
2631 
2632 
2633 
2634  {
2636  (
2638  (
2639  mesh,
2640  adaptPatchIDs
2641  )
2642  );
2643 
2644 
2645  // Distance to attract to nearest feature on surface
2646  scalarField snapDist(calcSnapDistance(mesh, snapParams, ppPtr()));
2647 
2648 
2649  // Construct iterative mesh mover.
2650  Info<< "Constructing mesh displacer ..." << endl;
2651  Info<< "Using mesh parameters " << motionDict << nl << endl;
2652 
2653  autoPtr<motionSmoother> meshMoverPtr
2654  (
2655  new motionSmoother
2656  (
2657  mesh,
2658  ppPtr(),
2659  adaptPatchIDs,
2661  (
2663  adaptPatchIDs
2664  ),
2665  motionDict,
2666  dryRun_
2667  )
2668  );
2669 
2670 
2671  // Check initial mesh
2672  Info<< "Checking initial mesh ..." << endl;
2673  labelHashSet wrongFaces(mesh.nFaces()/100);
2674  motionSmoother::checkMesh(false, mesh, motionDict, wrongFaces, dryRun_);
2675  const label nInitErrors = returnReduce
2676  (
2677  wrongFaces.size(),
2678  sumOp<label>()
2679  );
2680 
2681  Info<< "Detected " << nInitErrors << " illegal faces"
2682  << " (concave, zero area or negative cell pyramid volume)"
2683  << endl;
2684 
2685 
2686  Info<< "Checked initial mesh in = "
2687  << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl;
2688 
2689  // Extract baffles across internal faceZones (for checking mesh quality
2690  // across
2691  labelPairList internalBaffles
2692  (
2693  meshRefiner_.subsetBaffles
2694  (
2695  mesh,
2696  internalFaceZones,
2698  )
2699  );
2700 
2701 
2702 
2703  // Pre-smooth patch vertices (so before determining nearest)
2704  preSmoothPatch
2705  (
2706  meshRefiner_,
2707  snapParams,
2708  nInitErrors,
2709  internalBaffles,
2710  meshMoverPtr()
2711  );
2712 
2713  // TBD. Include re-patching?
2714 
2715 
2716  //- Only if in feature attraction mode:
2717  // Nearest feature
2718  vectorField patchAttraction;
2719  // Constraints at feature
2720  List<pointConstraint> patchConstraints;
2721 
2722 
2723  //- Any faces to split
2724  DynamicList<label> splitFaces;
2725  //- Indices in face to split across
2726  DynamicList<labelPair> splits;
2727 
2728 
2729  for (label iter = 0; iter < nFeatIter; iter++)
2730  {
2731  Info<< nl
2732  << "Morph iteration " << iter << nl
2733  << "-----------------" << endl;
2734 
2735  // Splitting iteration?
2736  bool doSplit = false;
2737  if
2738  (
2739  doFeatures
2740  && snapParams.nFaceSplitInterval() > 0
2741  && (
2742  (iter == nFeatIter-1)
2743  || (iter > 0 && (iter%snapParams.nFaceSplitInterval()) == 0)
2744  )
2745  )
2746  {
2747  doSplit = true;
2748  }
2749 
2750 
2751 
2752  indirectPrimitivePatch& pp = ppPtr();
2753  motionSmoother& meshMover = meshMoverPtr();
2754 
2755 
2756  // Calculate displacement at every patch point if we need it:
2757  // - if automatic near-surface detection
2758  // - if face splitting active
2759  pointField nearestPoint;
2760  vectorField nearestNormal;
2761 
2762  if (snapParams.detectNearSurfacesSnap() || doSplit)
2763  {
2764  nearestPoint.setSize(pp.nPoints(), vector::max);
2765  nearestNormal.setSize(pp.nPoints(), Zero);
2766  }
2767 
2768  vectorField disp = calcNearestSurface
2769  (
2770  snapParams.strictRegionSnap(), // attract points to region only
2771  meshRefiner_,
2772  globalToMasterPatch_, // for if strictRegionSnap
2773  globalToSlavePatch_, // for if strictRegionSnap
2774  snapDist,
2775  pp,
2776 
2777  nearestPoint,
2778  nearestNormal
2779  );
2780 
2781 
2782  // Override displacement at thin gaps
2783  if (snapParams.detectNearSurfacesSnap())
2784  {
2785  detectNearSurfaces
2786  (
2787  Foam::cos(degToRad(planarAngle)),// planar cos for gaps
2788  pp,
2789  nearestPoint, // surfacepoint from nearest test
2790  nearestNormal, // surfacenormal from nearest test
2791 
2792  disp
2793  );
2794  }
2795 
2796  // Override displacement with feature edge attempt
2797  if (doFeatures)
2798  {
2799  splitFaces.clear();
2800  splits.clear();
2801  disp = calcNearestSurfaceFeature
2802  (
2803  snapParams,
2804  !doSplit, // alignMeshEdges
2805  iter,
2806  featureCos,
2807  scalar(iter+1)/nFeatIter,
2808 
2809  snapDist,
2810  disp,
2811  nearestNormal,
2812  meshMover,
2813 
2814  patchAttraction,
2815  patchConstraints,
2816 
2817  splitFaces,
2818  splits
2819  );
2820  }
2821 
2822  // Check for displacement being outwards.
2823  outwardsDisplacement(pp, disp);
2824 
2825  // Set initial distribution of displacement field (on patches)
2826  // from patchDisp and make displacement consistent with b.c.
2827  // on displacement pointVectorField.
2828  meshMover.setDisplacement(disp);
2829 
2830 
2832  {
2833  dumpMove
2834  (
2835  mesh.time().path()
2836  / "patchDisplacement_" + name(iter) + ".obj",
2837  pp.localPoints(),
2838  pp.localPoints() + disp
2839  );
2840  }
2841 
2842  // Get smoothly varying internal displacement field.
2843  smoothDisplacement(snapParams, meshMover);
2844 
2845  // Apply internal displacement to mesh.
2846  meshOk = scaleMesh
2847  (
2848  snapParams,
2849  nInitErrors,
2850  internalBaffles,
2851  meshMover
2852  );
2853 
2854  if (!meshOk)
2855  {
2857  << "Did not successfully snap mesh."
2858  << " Continuing to snap to resolve easy" << nl
2859  << " surfaces but the"
2860  << " resulting mesh will not satisfy your quality"
2861  << " constraints" << nl << endl;
2862  }
2863 
2865  {
2866  const_cast<Time&>(mesh.time())++;
2867  Info<< "Writing scaled mesh to time "
2868  << meshRefiner_.timeName() << endl;
2869  meshRefiner_.write
2870  (
2873  (
2876  ),
2877  mesh.time().path()/meshRefiner_.timeName()
2878  );
2879  Info<< "Writing displacement field ..." << endl;
2880  meshMover.displacement().write();
2881  tmp<pointScalarField> magDisp
2882  (
2883  mag(meshMover.displacement())
2884  );
2885  magDisp().write();
2886  }
2887 
2888  // Use current mesh as base mesh
2889  meshMover.correct();
2890 
2891 
2892 
2893  // See if any faces need splitting
2894  label nTotalSplit = returnReduce(splitFaces.size(), sumOp<label>());
2895  if (nTotalSplit && doSplit)
2896  {
2897  // Filter out baffle faces from faceZones of type
2898  // internal/baffle
2899 
2900  labelList duplicateFace(getInternalOrBaffleDuplicateFace());
2901 
2902  {
2903  labelList oldSplitFaces(std::move(splitFaces));
2904  List<labelPair> oldSplits(std::move(splits));
2905  forAll(oldSplitFaces, i)
2906  {
2907  if (duplicateFace[oldSplitFaces[i]] == -1)
2908  {
2909  splitFaces.append(oldSplitFaces[i]);
2910  splits.append(oldSplits[i]);
2911  }
2912  }
2913  nTotalSplit = returnReduce
2914  (
2915  splitFaces.size(),
2916  sumOp<label>()
2917  );
2918  }
2919 
2920  // Update mesh
2921  meshRefiner_.splitFacesUndo
2922  (
2923  splitFaces,
2924  splits,
2925  motionDict,
2926 
2927  duplicateFace,
2928  internalBaffles
2929  );
2930 
2931  // Redo meshMover
2932  meshMoverPtr.clear();
2933  ppPtr.clear();
2934 
2935  // Update mesh mover
2936  ppPtr = meshRefinement::makePatch(mesh, adaptPatchIDs);
2937  meshMoverPtr.reset
2938  (
2939  new motionSmoother
2940  (
2941  mesh,
2942  ppPtr(),
2943  adaptPatchIDs,
2945  (
2947  adaptPatchIDs
2948  ),
2949  motionDict,
2950  dryRun_
2951  )
2952  );
2953 
2954  // Update snapping distance
2955  snapDist = calcSnapDistance(mesh, snapParams, ppPtr());
2956 
2957 
2959  {
2960  const_cast<Time&>(mesh.time())++;
2961  Info<< "Writing split-faces mesh to time "
2962  << meshRefiner_.timeName() << endl;
2963  meshRefiner_.write
2964  (
2967  (
2970  ),
2971  mesh.time().path()/meshRefiner_.timeName()
2972  );
2973  }
2974  }
2975 
2976 
2978  {
2979  forAll(internalBaffles, i)
2980  {
2981  const labelPair& p = internalBaffles[i];
2982  const point& fc0 = mesh.faceCentres()[p[0]];
2983  const point& fc1 = mesh.faceCentres()[p[1]];
2984 
2985  if (mag(fc0-fc1) > meshRefiner_.mergeDistance())
2986  {
2988  << "Separated baffles : f0:" << p[0]
2989  << " centre:" << fc0
2990  << " f1:" << p[1] << " centre:" << fc1
2991  << " distance:" << mag(fc0-fc1)
2992  << exit(FatalError);
2993  }
2994  }
2995  }
2996  }
2997  }
2998 
2999 
3000  // Merge any introduced baffles (from faceZones of faceType 'internal')
3001  {
3002  autoPtr<mapPolyMesh> mapPtr = meshRefiner_.mergeZoneBaffles
3003  (
3004  true, // internal zones
3005  false // baffle zones
3006  );
3007 
3008  if (mapPtr.valid())
3009  {
3011  {
3012  const_cast<Time&>(mesh.time())++;
3013  Info<< "Writing baffle-merged mesh to time "
3014  << meshRefiner_.timeName() << endl;
3015  meshRefiner_.write
3016  (
3019  (
3022  ),
3023  meshRefiner_.timeName()
3024  );
3025  }
3026  }
3027  }
3028 
3029  // Repatch faces according to nearest. Do not repatch baffle faces.
3030  {
3031  labelList duplicateFace(getInternalOrBaffleDuplicateFace());
3032 
3033  repatchToSurface(snapParams, adaptPatchIDs, duplicateFace);
3034  }
3035 
3036  if
3037  (
3038  mergeType == meshRefinement::FaceMergeType::GEOMETRIC
3039  || mergeType == meshRefinement::FaceMergeType::IGNOREPATCH
3040  )
3041  {
3042  labelList duplicateFace(getInternalOrBaffleDuplicateFace());
3043 
3044  // Repatching might have caused faces to be on same patch and hence
3045  // mergeable so try again to merge coplanar faces. Do not merge baffle
3046  // faces to ensure they both stay the same.
3047  label nChanged = meshRefiner_.mergePatchFacesUndo
3048  (
3049  featureCos, // minCos
3050  featureCos, // concaveCos
3051  meshRefiner_.meshedPatches(),
3052  motionDict,
3053  duplicateFace, // faces not to merge
3054  mergeType
3055  );
3056 
3057  nChanged += meshRefiner_.mergeEdgesUndo(featureCos, motionDict);
3058 
3059  if (nChanged > 0 && debug & meshRefinement::MESH)
3060  {
3061  const_cast<Time&>(mesh.time())++;
3062  Info<< "Writing patchFace merged mesh to time "
3063  << meshRefiner_.timeName() << endl;
3064  meshRefiner_.write
3065  (
3068  (
3071  ),
3072  meshRefiner_.timeName()
3073  );
3074  }
3075  }
3076 
3078  {
3079  const_cast<Time&>(mesh.time())++;
3080  }
3081 }
3082 
3083 
3084 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:74
profiling.H
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
Foam::autoPtr::reset
void reset(T *p=nullptr) noexcept
Delete managed object and set to new given pointer.
Definition: autoPtrI.H:158
Foam::snappySnapDriver::smoothDisplacement
void smoothDisplacement(const snapParameters &snapParams, motionSmoother &) const
Smooth the displacement field to the internal.
Definition: snappySnapDriver.C:2092
Foam::polyMesh::points
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1038
Foam::scalarField
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Definition: primitiveFieldsFwd.H:52
Foam::PrimitivePatch::pointFaces
const labelListList & pointFaces() const
Return point-face addressing.
Definition: PrimitivePatch.C:378
p
volScalarField & p
Definition: createFieldRefs.H:8
Foam::motionSmootherAlgo::setErrorReduction
scalar setErrorReduction(const scalar)
Set the errorReduction (by how much to scale the displacement.
Definition: motionSmootherAlgo.C:698
Foam::Time
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:73
Foam::meshRefinement::gAverage
static T gAverage(const bitSet &isMasterElem, const UList< T > &values)
Helper: calculate average.
Definition: meshRefinementTemplates.C:62
Foam::meshRefinement::WRITEMESH
Definition: meshRefinement.H:115
Foam::snappySnapDriver::calcSnapDistance
static scalarField calcSnapDistance(const fvMesh &mesh, const snapParameters &snapParams, const indirectPrimitivePatch &)
Calculate edge length per patch point.
Definition: snappySnapDriver.C:774
snappySnapDriver.H
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:62
Foam::fvMesh::write
virtual bool write(const bool valid=true) const
Write mesh using IO settings from time.
Definition: fvMesh.C:939
Foam::returnReduce
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Definition: PstreamReduceOps.H:94
Foam::bitSet
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:64
Foam::OBJstream
OFstream that keeps track of vertices.
Definition: OBJstream.H:56
Foam::polyBoundaryMesh
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO.
Definition: polyBoundaryMesh.H:62
Foam::PrimitivePatch::edges
const edgeList & edges() const
Return list of edges, address into LOCAL point list.
Definition: PrimitivePatch.C:238
Foam::tmp
A class for managing temporary objects.
Definition: PtrList.H:59
Foam::Zero
static constexpr const zero Zero
Global zero.
Definition: zero.H:128
PatchTools.H
Foam::refinementSurfaces::findNearest
void findNearest(const labelList &surfacesToTest, const pointField &samples, const scalarField &nearestDistSqr, labelList &surfaces, List< pointIndexHit > &) const
Find nearest point on surfaces.
Definition: refinementSurfaces.C:1489
Foam::DynamicList< label >
Foam::meshTools::writeOBJ
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of a point.
Definition: meshTools.C:203
Foam::primitiveMesh::nInternalFaces
label nInternalFaces() const
Number of internal faces.
Definition: primitiveMeshI.H:78
Foam::motionSmootherAlgo::correct
void correct()
Take over existing mesh position.
Definition: motionSmootherAlgo.C:391
Foam::refinementSurfaces::surfaces
const labelList & surfaces() const
Definition: refinementSurfaces.H:169
Foam::PrimitivePatch::localPoints
const Field< PointType > & localPoints() const
Return pointField of points in patch.
Definition: PrimitivePatch.C:458
Foam::motionSmootherAlgo::patch
const indirectPrimitivePatch & patch() const
Reference to patch.
Definition: motionSmootherAlgo.C:373
Foam::primitiveMesh::nFaces
label nFaces() const
Number of mesh faces.
Definition: primitiveMeshI.H:90
mapPolyMesh.H
Foam::Warning
messageStream Warning
Foam::meshRefinement::writeLevel
static writeType writeLevel()
Get/set write level.
Definition: meshRefinement.C:3395
Foam::globalMeshData::nTotalPoints
label nTotalPoints() const
Return total number of points in decomposed mesh. Not.
Definition: globalMeshData.H:381
polyTopoChange.H
motionSmoother.H
Foam::MeshObject< polyMesh, UpdateableMeshObject, pointMesh >::New
static const pointMesh & New(const polyMesh &mesh, Args &&... args)
Get existing or create a new MeshObject.
Definition: MeshObject.C:48
localPointRegion.H
Foam::meshRefinement::ATTRACTION
Definition: meshRefinement.H:98
Foam::edge
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:63
Foam::primitiveMesh::nEdges
label nEdges() const
Number of mesh edges.
Definition: primitiveMeshI.H:67
Foam::motionSmootherAlgo::scaleMesh
bool scaleMesh(labelList &checkFaces, const bool smoothMesh=true, const label nAllow=0)
Move mesh with given scale. Return true if mesh ok or has.
Definition: motionSmootherAlgo.C:712
unitConversion.H
Unit conversion functions.
Foam::boolList
List< bool > boolList
A List of bools.
Definition: List.H:72
Foam::surfaceZonesInfo::getNamedSurfaces
static labelList getNamedSurfaces(const PtrList< surfaceZonesInfo > &surfList)
Get indices of named surfaces (surfaces with faceZoneName)
Definition: surfaceZonesInfo.C:192
Foam::autoPtr::valid
bool valid() const noexcept
True if the managed pointer is non-null.
Definition: autoPtrI.H:107
Foam::polyMesh::boundaryMesh
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:435
Foam::motionSmootherAlgo::checkMesh
static bool checkMesh(const bool report, const polyMesh &mesh, const dictionary &dict, labelHashSet &wrongFaces, const bool dryRun=false)
Check mesh with mesh settings in dict. Collects incorrect faces.
Definition: motionSmootherAlgoCheck.C:461
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:337
Foam::globalMeshData::nTotalFaces
label nTotalFaces() const
Return total number of faces in decomposed mesh. Not.
Definition: globalMeshData.H:388
Foam::syncTools::getMasterFaces
static bitSet getMasterFaces(const polyMesh &mesh)
Definition: syncTools.C:126
refinementFeatures.H
Foam::Pout
prefixOSstream Pout
An Ostream wrapper for parallel output to std::cout.
Foam::HashSet< label, Hash< label > >
Foam::meshRefinement::mesh
const fvMesh & mesh() const
Reference to mesh.
Definition: meshRefinement.H:940
syncTools.H
Foam::refinementSurfaces::geometry
const searchableSurfaces & geometry() const
Definition: refinementSurfaces.H:164
Foam::syncTools::syncPointList
static void syncPointList(const polyMesh &mesh, List< T > &pointValues, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh points.
Definition: syncToolsTemplates.C:747
Foam::sumOp
Definition: ops.H:213
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:290
OFstream.H
Foam::vectorField
Field< vector > vectorField
Specialisation of Field<T> for vector.
Definition: primitiveFieldsFwd.H:54
Foam::polyMesh::faceZones
const faceZoneMesh & faceZones() const
Return face zone mesh.
Definition: polyMesh.H:477
Foam::meshRefinement::FaceMergeType
FaceMergeType
Enumeration for what to do with co-planar patch faces on a single.
Definition: meshRefinement.H:134
Foam::labelPair
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:54
searchableSurfaces.H
Foam::snapParameters
Simple container to keep together snap specific information.
Definition: snapParameters.H:52
Foam::refinementSurfaces::surfZones
const PtrList< surfaceZonesInfo > & surfZones() const
Definition: refinementSurfaces.H:180
Foam::reduce
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
Definition: PstreamReduceOps.H:51
pointEdgePoint.H
Foam::snapParameters::nFeatureSnap
label nFeatureSnap() const
Definition: snapParameters.H:178
Foam::tmp::ref
T & ref() const
Definition: tmpI.H:258
Foam::meshRefinement::timeName
word timeName() const
Definition: meshRefinement.C:3197
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:62
pFaces
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=cellModel::ref(cellModel::HEX);labelList hexLabels(8);label activeCells=0;labelList pointMap(nPoints);forAll(pointMap, i){ pointMap[i]=i;}for(label i=0;i< nPoints;i++){ if(f[i] > 0.0) { hexLabels[0]=i;hexLabels[1]=i1tab[i];hexLabels[2]=i3tab[i1tab[i]];hexLabels[3]=i3tab[i];hexLabels[4]=i8tab[i];hexLabels[5]=i1tab[i8tab[i]];hexLabels[6]=i3tab[i1tab[i8tab[i]]];hexLabels[7]=i3tab[i8tab[i]];cellShapes[activeCells]=cellShape(hex, hexLabels);edgeList edges=cellShapes[activeCells].edges();forAll(edges, ei) { if(edges[ei].mag(points)< SMALL) { label start=pointMap[edges[ei].start()];while(start !=pointMap[start]) { start=pointMap[start];} label end=pointMap[edges[ei].end()];while(end !=pointMap[end]) { end=pointMap[end];} label minLabel=min(start, end);pointMap[start]=pointMap[end]=minLabel;} } cellZoning[activeCells]=idreg[i];activeCells++;}}cellShapes.setSize(activeCells);cellZoning.setSize(activeCells);forAll(cellShapes, celli){ cellShape &cs=cellShapes[celli];forAll(cs, i) { cs[i]=pointMap[cs[i]];} cs.collapse();}label bcIDs[11]={-1, 0, 2, 4, -1, 5, -1, 6, 7, 8, 9};const label nBCs=12;const word *kivaPatchTypes[nBCs]={ &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &symmetryPolyPatch::typeName, &wedgePolyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &symmetryPolyPatch::typeName, &oldCyclicPolyPatch::typeName};enum patchTypeNames{ PISTON, VALVE, LINER, CYLINDERHEAD, AXIS, WEDGE, INFLOW, OUTFLOW, PRESIN, PRESOUT, SYMMETRYPLANE, CYCLIC};const char *kivaPatchNames[nBCs]={ "piston", "valve", "liner", "cylinderHead", "axis", "wedge", "inflow", "outflow", "presin", "presout", "symmetryPlane", "cyclic"};List< SLList< face > > pFaces[nBCs]
Definition: readKivaGrid.H:235
faceNormals
surfaceVectorField faceNormals(mesh.Sf()/mesh.magSf())
Foam::snappySnapDriver::detectNearSurfaces
void detectNearSurfaces(const scalar planarCos, const indirectPrimitivePatch &, const pointField &nearestPoint, const vectorField &nearestNormal, vectorField &disp) const
Per patch point override displacement if in gap situation.
Definition: snappySnapDriver.C:1082
Foam::Field< scalar >
Foam::faceZone
A subset of mesh faces organised as a primitive patch.
Definition: faceZone.H:65
Foam::Info
messageStream Info
Information stream (uses stdout - output is on the master only)
Foam::polyPatch
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:66
refinementSurfaces.H
Foam::name
word name(const complex &c)
Return string representation of complex.
Definition: complex.C:76
PointEdgeWave.H
Foam::DynamicList::append
DynamicList< T, SizeMin > & append(const T &val)
Append an element to the end of this list.
Definition: DynamicListI.H:472
Foam::PrimitivePatch::pointEdges
const labelListList & pointEdges() const
Return point-edge addressing.
Definition: PrimitivePatch.C:358
Foam::DynamicList::clear
void clear()
Clear the addressed list, i.e. set the size to zero.
Definition: DynamicListI.H:348
Foam::polyMesh::faceOwner
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1076
Foam::snapParameters::strictRegionSnap
Switch strictRegionSnap() const
Attract point to corresponding surface region only.
Definition: snapParameters.H:170
Foam::ZoneMesh< faceZone, polyMesh >
Foam::PtrList
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers....
Definition: List.H:65
Foam::motionSmoother
Given a displacement moves the mesh by scaling the displacement back until there are no more mesh err...
Definition: motionSmoother.H:91
Foam::max
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
Foam::syncTools::swapBoundaryCellList
static void swapBoundaryCellList(const polyMesh &mesh, const UList< T > &cellData, List< T > &neighbourCellData)
Swap to obtain neighbour cell values for all boundary faces.
Definition: syncToolsTemplates.C:1175
newPointi
label newPointi
Definition: readKivaGrid.H:496
Foam::PrimitivePatch::nPoints
label nPoints() const
Return number of points supporting patch faces.
Definition: PrimitivePatch.H:311
Foam::snapParameters::nSnap
label nSnap() const
Maximum number of snapping relaxation iterations. Should stop.
Definition: snapParameters.H:154
addProfiling
#define addProfiling(name, descr)
Define profiling trigger with specified name and description string.
Definition: profilingTrigger.H:114
Foam::FatalError
error FatalError
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:121
Foam::meshRefinement::makePatch
static autoPtr< indirectPrimitivePatch > makePatch(const polyMesh &, const labelList &)
Create patch from set of patches.
Definition: meshRefinement.C:1874
Foam::refinementSurfaces::globalRegion
label globalRegion(const label surfI, const label regionI) const
From surface and region on surface to global region.
Definition: refinementSurfaces.H:249
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
stdFoam::end
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:115
Foam::Ostream::write
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
Foam::fvMesh
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:84
fvMesh.H
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:137
Foam::ZoneMesh::findZoneID
label findZoneID(const word &zoneName) const
Find zone index given a name, return -1 if not found.
Definition: ZoneMesh.C:484
Foam::vector
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:51
Foam::polyPatch::start
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:311
Foam::maxEqOp
Definition: ops.H:80
Foam::degToRad
constexpr scalar degToRad(const scalar deg) noexcept
Conversion from degrees to radians.
Definition: unitConversion.H:48
Foam::mergePoints
label mergePoints(const PointList &points, const scalar mergeTol, const bool verbose, labelList &pointMap, typename PointList::const_reference origin=PointList::value_type::zero)
Sorts and merges points. All points closer than/equal mergeTol get merged.
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::DynamicList::setCapacity
void setCapacity(const label nElem)
Alter the size of the underlying storage.
Definition: DynamicListI.H:232
Foam::GeometricField::primitiveFieldRef
Internal::FieldType & primitiveFieldRef(const bool updateAccessTime=true)
Return a reference to the internal field.
Definition: GeometricField.C:735
Foam::snappySnapDriver::repatchToSurface
autoPtr< mapPolyMesh > repatchToSurface(const snapParameters &snapParams, const labelList &adaptPatchIDs, const labelList &preserveFaces)
Repatch faces according to surface nearest the face centre.
Definition: snappySnapDriver.C:2233
Foam::surfaceZonesInfo::getUnnamedSurfaces
static labelList getUnnamedSurfaces(const PtrList< surfaceZonesInfo > &surfList)
Get indices of unnamed surfaces (surfaces without faceZoneName)
Definition: surfaceZonesInfo.C:171
Foam::refinementSurfaces::findNearestRegion
void findNearestRegion(const labelList &surfacesToTest, const pointField &samples, const scalarField &nearestDistSqr, labelList &hitSurface, labelList &hitRegion) const
Find nearest point on surfaces. Return surface and region on.
Definition: refinementSurfaces.C:1522
Foam::indirectPrimitivePatch
PrimitivePatch< face, IndirectList, const pointField & > indirectPrimitivePatch
A PrimitivePatch using an IndirectList for the faces.
Definition: indirectPrimitivePatch.H:47
Foam::snappySnapDriver::scaleMesh
bool scaleMesh(const snapParameters &snapParams, const label nInitErrors, const List< labelPair > &baffles, motionSmoother &)
Do the hard work: move the mesh according to displacement,.
Definition: snappySnapDriver.C:2166
Foam::surfaceZonesInfo::BAFFLE
Definition: surfaceZonesInfo.H:79
Time.H
Foam::autoPtr
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: HashPtrTable.H:53
Foam::labelListList
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
Foam::primitiveMesh::cellCentres
const vectorField & cellCentres() const
Definition: primitiveMeshCellCentresAndVols.C:176
Foam::linePointRef
line< point, const point & > linePointRef
Line using referred points.
Definition: linePointRef.H:47
Foam::polyMesh::faces
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1063
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:355
Foam::refinementSurfaces::findNearestIntersection
void findNearestIntersection(const labelList &surfacesToTest, const pointField &start, const pointField &end, labelList &surface1, List< pointIndexHit > &hit1, labelList &region1, labelList &surface2, List< pointIndexHit > &hit2, labelList &region2) const
Find intersection nearest to the endpoints. surface1,2 are.
Definition: refinementSurfaces.C:1122
Foam::snapParameters::snapTol
scalar snapTol() const
Relative distance for points to be attracted by surface.
Definition: snapParameters.H:141
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:51
Foam::nl
constexpr char nl
Definition: Ostream.H:372
Foam::Pair
An ordered pair of two objects of type <T> with first() and second() elements.
Definition: Pair.H:54
Foam::Time::path
fileName path() const
Return path.
Definition: Time.H:303
Foam::snapParameters::nFaceSplitInterval
label nFaceSplitInterval() const
Definition: snapParameters.H:226
Foam::snapParameters::nSmoothInternal
label nSmoothInternal() const
Number of internal point smoothing iterations (combined with.
Definition: snapParameters.H:132
Foam::VectorSpace< Vector< scalar >, scalar, 3 >::max
static const Vector< scalar > max
Definition: VectorSpace.H:117
f
labelList f(nPoints)
Foam::snappySnapDriver::doSnap
void doSnap(const dictionary &snapDict, const dictionary &motionDict, const meshRefinement::FaceMergeType mergeType, const scalar featureCos, const scalar planarAngle, const snapParameters &snapParams)
Definition: snappySnapDriver.C:2529
Foam::faceList
List< face > faceList
A List of faces.
Definition: faceListFwd.H:47
Foam::PatchTools::pointNormals
static tmp< pointField > pointNormals(const polyMesh &, const PrimitivePatch< Face, FaceList, PointField, PointType > &)
Return parallel consistent point normals for patches using mesh points.
Foam::Vector< scalar >
Foam::meshRefinement::writeType
writeType
Enumeration for what to write. Used as a bit-pattern.
Definition: meshRefinement.H:113
Foam::List< label >
Foam::sqrt
dimensionedScalar sqrt(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:144
Foam::snapParameters::detectNearSurfacesSnap
Switch detectNearSurfacesSnap() const
Override attraction to nearest with intersection location.
Definition: snapParameters.H:164
Foam::motionSmootherAlgo::pointDisplacement
pointVectorField & pointDisplacement()
Return reference to the point motion displacement field.
Definition: motionSmootherAlgo.H:339
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::start
label ListType::const_reference const label start
Definition: ListOps.H:408
Foam::primitiveMesh::faceCentres
const vectorField & faceCentres() const
Definition: primitiveMeshFaceCentresAndAreas.C:145
Foam::meshRefinement
Helper class which maintains intersections of (changing) mesh with (static) surfaces.
Definition: meshRefinement.H:86
Foam::motionSmootherAlgo::setDisplacement
static void setDisplacement(const labelList &patchIDs, const indirectPrimitivePatch &pp, pointField &patchDisp, pointVectorField &displacement)
Set displacement field from displacement on patch points.
Definition: motionSmootherAlgo.C:468
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
Foam::meshRefinement::write
bool write() const
Write mesh and all data.
Definition: meshRefinement.C:3037
Foam::primitiveMesh::nPoints
label nPoints() const
Number of mesh points.
Definition: primitiveMeshI.H:37
Foam::identity
labelList identity(const label len, label start=0)
Create identity map of the given length with (map[i] == i)
Definition: labelList.C:38
Foam::motionSmootherAlgo::smooth
void smooth(const GeometricField< Type, pointPatchField, pointMesh > &fld, const scalarField &edgeWeight, GeometricField< Type, pointPatchField, pointMesh > &newFld) const
Fully explicit smoothing of fields (not positions)
Definition: motionSmootherAlgoTemplates.C:233
Foam::primitiveMesh::pointCells
const labelListList & pointCells() const
Definition: primitiveMeshPointCells.C:110
patches
const polyBoundaryMesh & patches
Definition: convertProcessorPatches.H:65
snapParameters.H
Foam::List::set
std::enable_if< std::is_same< bool, TypeT >::value, bool >::type set(const label i, bool val=true)
A bitSet::set() method for a list of bool.
Definition: List.H:320
Foam::autoPtr::clear
void clear() noexcept
Delete managed object and set pointer to nullptr.
Definition: autoPtrI.H:151
mergePoints.H
Merge points. See below.
Foam::motionSmootherAlgo::pMesh
const pointMesh & pMesh() const
Reference to pointMesh.
Definition: motionSmootherAlgo.C:367
Foam::cpuTimeCxx::cpuTimeIncrement
double cpuTimeIncrement() const
Return CPU time (in seconds) since last call to cpuTimeIncrement()
Definition: cpuTimeCxx.C:75
Foam::fvMesh::time
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:246
Foam::VectorSpace< Vector< scalar >, scalar, 3 >::zero
static const Vector< scalar > zero
Definition: VectorSpace.H:115
Foam::PrimitivePatch::localFaces
const List< Face > & localFaces() const
Return patch faces addressing into local point list.
Definition: PrimitivePatch.C:398
Foam::Field< vector >::subField
SubField< vector > subField
Declare type of subField.
Definition: Field.H:90
Foam::face
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:74
Foam::plusEqOp
Definition: ops.H:72
Foam::gMin
Type gMin(const FieldField< Field, Type > &f)
Definition: FieldFieldFunctions.C:593
Foam::polyMesh::globalData
const globalMeshData & globalData() const
Return parallel info.
Definition: polyMesh.C:1241
Foam::point
vector point
Point is a vector.
Definition: point.H:43
Foam::PrimitivePatch::meshPointMap
const Map< label > & meshPointMap() const
Mesh point map.
Definition: PrimitivePatch.C:438
Foam::meshTools::visNormal
bool visNormal(const vector &n, const vectorField &faceNormals, const labelList &faceLabels)
Check if n is in same direction as normals of all faceLabels.
Definition: meshTools.C:37
Foam::PrimitivePatch::meshPoints
const labelList & meshPoints() const
Return labelList of mesh points in patch.
Definition: PrimitivePatch.C:418
Foam::List::setSize
void setSize(const label newSize)
Alias for resize(const label)
Definition: ListI.H:146
Foam::GeometricField< vector, pointPatchField, pointMesh >
Foam::minMagSqrEqOp
Definition: ops.H:82
Foam::refinementSurfaces
Container for data on surfaces used for surface-driven refinement. Contains all the data about the le...
Definition: refinementSurfaces.H:63
Foam::snapParameters::nSmoothDispl
label nSmoothDispl() const
Number of mesh displacement smoothing iterations.
Definition: snapParameters.H:147
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::snappySnapDriver::preSmoothPatch
static void preSmoothPatch(const meshRefinement &meshRefiner, const snapParameters &snapParams, const label nInitErrors, const List< labelPair > &baffles, motionSmoother &)
Smooth the mesh (patch and internal) to increase visibility.
Definition: snappySnapDriver.C:814
Foam::meshRefinement::makeDisplacementField
static tmp< pointVectorField > makeDisplacementField(const pointMesh &pMesh, const labelList &adaptPatchIDs)
Helper function to make a pointVectorField with correct.
Definition: meshRefinement.C:1916
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:294
Foam::snappySnapDriver::avgCellCentres
static tmp< pointField > avgCellCentres(const fvMesh &mesh, const indirectPrimitivePatch &)
Helper: calculate average cell centre per point.
Definition: snappySnapDriver.C:978
Foam::gMax
Type gMax(const FieldField< Field, Type > &f)
Definition: FieldFieldFunctions.C:592
OBJstream.H
Foam::polyMesh::faceNeighbour
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1082
Foam::meshRefinement::MESH
Definition: meshRefinement.H:95
Foam::snapParameters::nSmoothPatch
label nSmoothPatch() const
Number of patch smoothing iterations before finding.
Definition: snapParameters.H:125
Foam::meshRefinement::getMasterPoints
static bitSet getMasterPoints(const polyMesh &mesh, const labelList &meshPoints)
Determine master point for subset of points. If coupled.
Definition: meshRefinement.C:3073
Foam::localPointRegion::findDuplicateFacePairs
static labelPairList findDuplicateFacePairs(const polyMesh &)
Helper routine to find all baffles (two boundary faces.
Definition: localPointRegion.C:625
Foam::motionSmootherData::displacement
pointVectorField & displacement()
Reference to displacement field.
Definition: motionSmootherData.C:102
Foam::PrimitivePatch
A list of faces which address into the list of points.
Definition: PrimitivePatch.H:90
Foam::fvc::smooth
void smooth(volScalarField &field, const scalar coeff)
Definition: fvcSmooth.C:37
Foam::cos
dimensionedScalar cos(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:265
Foam::meshRefinement::surfaces
const refinementSurfaces & surfaces() const
Reference to surface search engines.
Definition: meshRefinement.H:967
Foam::meshRefinement::debugType
debugType
Enumeration for what to debug. Used as a bit-pattern.
Definition: meshRefinement.H:93
Foam::surfaceZonesInfo::INTERNAL
Definition: surfaceZonesInfo.H:78