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 void Foam::snappySnapDriver::getZoneSurfacePoints
932 (
933  const fvMesh& mesh,
934  const indirectPrimitivePatch& pp,
935  const word& zoneName,
936 
937  bitSet& pointOnZone
938 )
939 {
940  label zonei = mesh.faceZones().findZoneID(zoneName);
941 
942  if (zonei == -1)
943  {
945  << "Cannot find zone " << zoneName
946  << exit(FatalError);
947  }
948 
949  const faceZone& fZone = mesh.faceZones()[zonei];
950 
951 
952  // Could use PrimitivePatch & localFaces to extract points but might just
953  // as well do it ourselves.
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 
974 
976 (
977  const fvMesh& mesh,
978  const indirectPrimitivePatch& pp
979 )
980 {
981  const labelListList& pointFaces = pp.pointFaces();
982 
983 
984  tmp<pointField> tavgBoundary
985  (
986  new pointField(pointFaces.size(), Zero)
987  );
988  pointField& avgBoundary = tavgBoundary.ref();
989  labelList nBoundary(pointFaces.size(), Zero);
990 
991  forAll(pointFaces, pointi)
992  {
993  const labelList& pFaces = pointFaces[pointi];
994 
995  forAll(pFaces, pfi)
996  {
997  label facei = pFaces[pfi];
998  label meshFacei = pp.addressing()[facei];
999 
1000  label own = mesh.faceOwner()[meshFacei];
1001  avgBoundary[pointi] += mesh.cellCentres()[own];
1002  nBoundary[pointi]++;
1003  }
1004  }
1005 
1007  (
1008  mesh,
1009  pp.meshPoints(),
1010  avgBoundary,
1011  plusEqOp<point>(), // combine op
1012  vector::zero // null value
1013  );
1015  (
1016  mesh,
1017  pp.meshPoints(),
1018  nBoundary,
1019  plusEqOp<label>(), // combine op
1020  label(0) // null value
1021  );
1022 
1023  forAll(avgBoundary, i)
1024  {
1025  avgBoundary[i] /= nBoundary[i];
1026  }
1027  return tavgBoundary;
1028 }
1029 
1030 
1031 //Foam::tmp<Foam::scalarField> Foam::snappySnapDriver::calcEdgeLen
1032 //(
1033 // const indirectPrimitivePatch& pp
1034 //) const
1035 //{
1036 // // Get local edge length based on refinement level
1037 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1038 // // (Ripped from snappyLayerDriver)
1039 //
1040 // tmp<scalarField> tedgeLen(new scalarField(pp.nPoints()));
1041 // scalarField& edgeLen = tedgeLen();
1042 // {
1043 // const fvMesh& mesh = meshRefiner_.mesh();
1044 // const scalar edge0Len = meshRefiner_.meshCutter().level0EdgeLength();
1045 // const labelList& cellLevel = meshRefiner_.meshCutter().cellLevel();
1046 //
1047 // labelList maxPointLevel(pp.nPoints(), labelMin);
1048 //
1049 // forAll(pp, i)
1050 // {
1051 // label ownLevel = cellLevel[mesh.faceOwner()[pp.addressing()[i]]];
1052 // const face& f = pp.localFaces()[i];
1053 // forAll(f, fp)
1054 // {
1055 // maxPointLevel[f[fp]] = max(maxPointLevel[f[fp]], ownLevel);
1056 // }
1057 // }
1058 //
1059 // syncTools::syncPointList
1060 // (
1061 // mesh,
1062 // pp.meshPoints(),
1063 // maxPointLevel,
1064 // maxEqOp<label>(),
1065 // labelMin // null value
1066 // );
1067 //
1068 //
1069 // forAll(maxPointLevel, pointi)
1070 // {
1071 // // Find undistorted edge size for this level.
1072 // edgeLen[pointi] = edge0Len/(1<<maxPointLevel[pointi]);
1073 // }
1074 // }
1075 // return tedgeLen;
1076 //}
1077 
1078 
1081  const scalar planarCos,
1082  const indirectPrimitivePatch& pp,
1083  const pointField& nearestPoint,
1084  const vectorField& nearestNormal,
1085 
1086  vectorField& disp
1087 ) const
1088 {
1089  Info<< "Detecting near surfaces ..." << endl;
1090 
1091  const pointField& localPoints = pp.localPoints();
1092  const labelList& meshPoints = pp.meshPoints();
1093  const refinementSurfaces& surfaces = meshRefiner_.surfaces();
1094  const fvMesh& mesh = meshRefiner_.mesh();
1095 
1097  //const scalarField edgeLen(calcEdgeLen(pp));
1098  //
1101  //
1102  //{
1103  // const vector n = normalised(vector::one);
1104  //
1105  // pointField start(14*pp.nPoints());
1106  // pointField end(start.size());
1107  //
1108  // label rayi = 0;
1109  // forAll(localPoints, pointi)
1110  // {
1111  // const point& pt = localPoints[pointi];
1112  //
1113  // // Along coordinate axes
1114  //
1115  // {
1116  // start[rayi] = pt;
1117  // point& endPt = end[rayi++];
1118  // endPt = pt;
1119  // endPt.x() -= edgeLen[pointi];
1120  // }
1121  // {
1122  // start[rayi] = pt;
1123  // point& endPt = end[rayi++];
1124  // endPt = pt;
1125  // endPt.x() += edgeLen[pointi];
1126  // }
1127  // {
1128  // start[rayi] = pt;
1129  // point& endPt = end[rayi++];
1130  // endPt = pt;
1131  // endPt.y() -= edgeLen[pointi];
1132  // }
1133  // {
1134  // start[rayi] = pt;
1135  // point& endPt = end[rayi++];
1136  // endPt = pt;
1137  // endPt.y() += edgeLen[pointi];
1138  // }
1139  // {
1140  // start[rayi] = pt;
1141  // point& endPt = end[rayi++];
1142  // endPt = pt;
1143  // endPt.z() -= edgeLen[pointi];
1144  // }
1145  // {
1146  // start[rayi] = pt;
1147  // point& endPt = end[rayi++];
1148  // endPt = pt;
1149  // endPt.z() += edgeLen[pointi];
1150  // }
1151  //
1152  // // At 45 degrees
1153  //
1154  // const vector vec(edgeLen[pointi]*n);
1155  //
1156  // {
1157  // start[rayi] = pt;
1158  // point& endPt = end[rayi++];
1159  // endPt = pt;
1160  // endPt.x() += vec.x();
1161  // endPt.y() += vec.y();
1162  // endPt.z() += vec.z();
1163  // }
1164  // {
1165  // start[rayi] = pt;
1166  // point& endPt = end[rayi++];
1167  // endPt = pt;
1168  // endPt.x() -= vec.x();
1169  // endPt.y() += vec.y();
1170  // endPt.z() += vec.z();
1171  // }
1172  // {
1173  // start[rayi] = pt;
1174  // point& endPt = end[rayi++];
1175  // endPt = pt;
1176  // endPt.x() += vec.x();
1177  // endPt.y() -= vec.y();
1178  // endPt.z() += vec.z();
1179  // }
1180  // {
1181  // start[rayi] = pt;
1182  // point& endPt = end[rayi++];
1183  // endPt = pt;
1184  // endPt.x() -= vec.x();
1185  // endPt.y() -= vec.y();
1186  // endPt.z() += vec.z();
1187  // }
1188  // {
1189  // start[rayi] = pt;
1190  // point& endPt = end[rayi++];
1191  // endPt = pt;
1192  // endPt.x() += vec.x();
1193  // endPt.y() += vec.y();
1194  // endPt.z() -= vec.z();
1195  // }
1196  // {
1197  // start[rayi] = pt;
1198  // point& endPt = end[rayi++];
1199  // endPt = pt;
1200  // endPt.x() -= vec.x();
1201  // endPt.y() += vec.y();
1202  // endPt.z() -= vec.z();
1203  // }
1204  // {
1205  // start[rayi] = pt;
1206  // point& endPt = end[rayi++];
1207  // endPt = pt;
1208  // endPt.x() += vec.x();
1209  // endPt.y() -= vec.y();
1210  // endPt.z() -= vec.z();
1211  // }
1212  // {
1213  // start[rayi] = pt;
1214  // point& endPt = end[rayi++];
1215  // endPt = pt;
1216  // endPt.x() -= vec.x();
1217  // endPt.y() -= vec.y();
1218  // endPt.z() -= vec.z();
1219  // }
1220  // }
1221  //
1222  // labelList surface1;
1223  // List<pointIndexHit> hit1;
1224  // labelList region1;
1225  // vectorField normal1;
1226  //
1227  // labelList surface2;
1228  // List<pointIndexHit> hit2;
1229  // labelList region2;
1230  // vectorField normal2;
1231  // surfaces.findNearestIntersection
1232  // (
1233  // unzonedSurfaces, // surfacesToTest,
1234  // start,
1235  // end,
1236  //
1237  // surface1,
1238  // hit1,
1239  // region1,
1240  // normal1,
1241  //
1242  // surface2,
1243  // hit2,
1244  // region2,
1245  // normal2
1246  // );
1247  //
1248  // // All intersections
1249  // {
1250  // OBJstream str
1251  // (
1252  // mesh.time().path()
1253  // / "surfaceHits_" + meshRefiner_.timeName() + ".obj"
1254  // );
1255  //
1256  // Info<< "Dumping intersections with rays to " << str.name()
1257  // << endl;
1258  //
1259  // forAll(hit1, i)
1260  // {
1261  // if (hit1[i].hit())
1262  // {
1263  // str.write(linePointRef(start[i], hit1[i].hitPoint()));
1264  // }
1265  // if (hit2[i].hit())
1266  // {
1267  // str.write(linePointRef(start[i], hit2[i].hitPoint()));
1268  // }
1269  // }
1270  // }
1271  //
1272  // // Co-planar intersections
1273  // {
1274  // OBJstream str
1275  // (
1276  // mesh.time().path()
1277  // / "coplanarHits_" + meshRefiner_.timeName() + ".obj"
1278  // );
1279  //
1280  // Info<< "Dumping intersections with co-planar surfaces to "
1281  // << str.name() << endl;
1282  //
1283  // forAll(localPoints, pointi)
1284  // {
1285  // bool hasNormal = false;
1286  // point surfPointA;
1287  // vector surfNormalA;
1288  // point surfPointB;
1289  // vector surfNormalB;
1290  //
1291  // bool isCoplanar = false;
1292  //
1293  // label rayi = 14*pointi;
1294  // for (label i = 0; i < 14; i++)
1295  // {
1296  // if (hit1[rayi].hit())
1297  // {
1298  // const point& pt = hit1[rayi].hitPoint();
1299  // const vector& n = normal1[rayi];
1300  //
1301  // if (!hasNormal)
1302  // {
1303  // hasNormal = true;
1304  // surfPointA = pt;
1305  // surfNormalA = n;
1306  // }
1307  // else
1308  // {
1309  // if
1310  // (
1311  // meshRefiner_.isGap
1312  // (
1313  // planarCos,
1314  // surfPointA,
1315  // surfNormalA,
1316  // pt,
1317  // n
1318  // )
1319  // )
1320  // {
1321  // isCoplanar = true;
1322  // surfPointB = pt;
1323  // surfNormalB = n;
1324  // break;
1325  // }
1326  // }
1327  // }
1328  // if (hit2[rayi].hit())
1329  // {
1330  // const point& pt = hit2[rayi].hitPoint();
1331  // const vector& n = normal2[rayi];
1332  //
1333  // if (!hasNormal)
1334  // {
1335  // hasNormal = true;
1336  // surfPointA = pt;
1337  // surfNormalA = n;
1338  // }
1339  // else
1340  // {
1341  // if
1342  // (
1343  // meshRefiner_.isGap
1344  // (
1345  // planarCos,
1346  // surfPointA,
1347  // surfNormalA,
1348  // pt,
1349  // n
1350  // )
1351  // )
1352  // {
1353  // isCoplanar = true;
1354  // surfPointB = pt;
1355  // surfNormalB = n;
1356  // break;
1357  // }
1358  // }
1359  // }
1360  //
1361  // rayi++;
1362  // }
1363  //
1364  // if (isCoplanar)
1365  // {
1366  // str.write(linePointRef(surfPointA, surfPointB));
1367  // }
1368  // }
1369  // }
1370  //}
1371 
1372 
1373  const pointField avgCc(avgCellCentres(mesh, pp));
1374 
1375  // Construct rays through localPoints to beyond cell centre
1376  pointField start(pp.nPoints());
1377  pointField end(pp.nPoints());
1378  forAll(localPoints, pointi)
1379  {
1380  const point& pt = localPoints[pointi];
1381  const vector d = 2*(avgCc[pointi]-pt);
1382  start[pointi] = pt - d;
1383  end[pointi] = pt + d;
1384  }
1385 
1386 
1387  autoPtr<OBJstream> gapStr;
1389  {
1390  gapStr.reset
1391  (
1392  new OBJstream
1393  (
1394  mesh.time().path()
1395  / "detectNearSurfaces_" + meshRefiner_.timeName() + ".obj"
1396  )
1397  );
1398  }
1399 
1400 
1401  const bitSet isPatchMasterPoint
1402  (
1404  (
1405  mesh,
1406  meshPoints
1407  )
1408  );
1409 
1410  label nOverride = 0;
1411 
1412  // 1. All points to non-interface surfaces
1413  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1414  {
1415  const labelList unzonedSurfaces =
1417  (
1418  meshRefiner_.surfaces().surfZones()
1419  );
1420 
1421  // Do intersection test
1422  labelList surface1;
1423  List<pointIndexHit> hit1;
1424  labelList region1;
1425  vectorField normal1;
1426 
1427  labelList surface2;
1428  List<pointIndexHit> hit2;
1429  labelList region2;
1430  vectorField normal2;
1431  surfaces.findNearestIntersection
1432  (
1433  unzonedSurfaces,
1434  start,
1435  end,
1436 
1437  surface1,
1438  hit1,
1439  region1,
1440  normal1,
1441 
1442  surface2,
1443  hit2,
1444  region2,
1445  normal2
1446  );
1447 
1448 
1449  forAll(localPoints, pointi)
1450  {
1451  // Current location
1452  const point& pt = localPoints[pointi];
1453 
1454  bool override = false;
1455 
1456  //if (hit1[pointi].hit())
1457  //{
1458  // if
1459  // (
1460  // meshRefiner_.isGap
1461  // (
1462  // planarCos,
1463  // nearestPoint[pointi],
1464  // nearestNormal[pointi],
1465  // hit1[pointi].hitPoint(),
1466  // normal1[pointi]
1467  // )
1468  // )
1469  // {
1470  // disp[pointi] = hit1[pointi].hitPoint()-pt;
1471  // override = true;
1472  // }
1473  //}
1474  //if (hit2[pointi].hit())
1475  //{
1476  // if
1477  // (
1478  // meshRefiner_.isGap
1479  // (
1480  // planarCos,
1481  // nearestPoint[pointi],
1482  // nearestNormal[pointi],
1483  // hit2[pointi].hitPoint(),
1484  // normal2[pointi]
1485  // )
1486  // )
1487  // {
1488  // disp[pointi] = hit2[pointi].hitPoint()-pt;
1489  // override = true;
1490  // }
1491  //}
1492 
1493  if (hit1[pointi].hit() && hit2[pointi].hit())
1494  {
1495  if
1496  (
1497  meshRefiner_.isGap
1498  (
1499  planarCos,
1500  hit1[pointi].hitPoint(),
1501  normal1[pointi],
1502  hit2[pointi].hitPoint(),
1503  normal2[pointi]
1504  )
1505  )
1506  {
1507  // TBD: check if the attraction (to nearest) would attract
1508  // good enough and not override attraction
1509 
1510  if (gapStr.valid())
1511  {
1512  const point& intPt = hit2[pointi].hitPoint();
1513  gapStr().write(linePointRef(pt, intPt));
1514  }
1515 
1516  // Choose hit2 : nearest to end point (so inside the domain)
1517  disp[pointi] = hit2[pointi].hitPoint()-pt;
1518  override = true;
1519  }
1520  }
1521 
1522  if (override && isPatchMasterPoint[pointi])
1523  {
1524  nOverride++;
1525  }
1526  }
1527  }
1528 
1529 
1530  // 2. All points on zones to their respective surface
1531  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1532 
1533  {
1534  // Surfaces with zone information
1535  const PtrList<surfaceZonesInfo>& surfZones = surfaces.surfZones();
1536 
1537  const labelList zonedSurfaces = surfaceZonesInfo::getNamedSurfaces
1538  (
1539  surfZones
1540  );
1541 
1542  forAll(zonedSurfaces, i)
1543  {
1544  label zoneSurfi = zonedSurfaces[i];
1545  const labelList surfacesToTest(1, zoneSurfi);
1546 
1547  const wordList& faceZoneNames =
1548  surfZones[zoneSurfi].faceZoneNames();
1549  forAll(faceZoneNames, namei)
1550  {
1551  const word& faceZoneName = faceZoneNames[namei];
1552 
1553  // Get indices of points both on faceZone and on pp.
1554  bitSet pointOnZone(pp.nPoints());
1555  getZoneSurfacePoints
1556  (
1557  mesh,
1558  pp,
1559  faceZoneName,
1560  pointOnZone
1561  );
1562  const labelList zonePointIndices(pointOnZone.toc());
1563 
1564  // Do intersection test
1565  labelList surface1;
1566  List<pointIndexHit> hit1;
1567  labelList region1;
1568  vectorField normal1;
1569 
1570  labelList surface2;
1571  List<pointIndexHit> hit2;
1572  labelList region2;
1573  vectorField normal2;
1574  surfaces.findNearestIntersection
1575  (
1576  surfacesToTest,
1577  pointField(start, zonePointIndices),
1578  pointField(end, zonePointIndices),
1579 
1580  surface1,
1581  hit1,
1582  region1,
1583  normal1,
1584 
1585  surface2,
1586  hit2,
1587  region2,
1588  normal2
1589  );
1590 
1591 
1592  forAll(hit1, i)
1593  {
1594  label pointi = zonePointIndices[i];
1595 
1596  // Current location
1597  const point& pt = localPoints[pointi];
1598 
1599  bool override = false;
1600 
1601  //if (hit1[i].hit())
1602  //{
1603  // if
1604  // (
1605  // meshRefiner_.isGap
1606  // (
1607  // planarCos,
1608  // nearestPoint[pointi],
1609  // nearestNormal[pointi],
1610  // hit1[i].hitPoint(),
1611  // normal1[i]
1612  // )
1613  // )
1614  // {
1615  // disp[pointi] = hit1[i].hitPoint()-pt;
1616  // override = true;
1617  // }
1618  //}
1619  //if (hit2[i].hit())
1620  //{
1621  // if
1622  // (
1623  // meshRefiner_.isGap
1624  // (
1625  // planarCos,
1626  // nearestPoint[pointi],
1627  // nearestNormal[pointi],
1628  // hit2[i].hitPoint(),
1629  // normal2[i]
1630  // )
1631  // )
1632  // {
1633  // disp[pointi] = hit2[i].hitPoint()-pt;
1634  // override = true;
1635  // }
1636  //}
1637 
1638  if (hit1[i].hit() && hit2[i].hit())
1639  {
1640  if
1641  (
1642  meshRefiner_.isGap
1643  (
1644  planarCos,
1645  hit1[i].hitPoint(),
1646  normal1[i],
1647  hit2[i].hitPoint(),
1648  normal2[i]
1649  )
1650  )
1651  {
1652  if (gapStr.valid())
1653  {
1654  const point& intPt = hit2[i].hitPoint();
1655  gapStr().write(linePointRef(pt, intPt));
1656  }
1657 
1658  disp[pointi] = hit2[i].hitPoint()-pt;
1659  override = true;
1660  }
1661  }
1662 
1663  if (override && isPatchMasterPoint[pointi])
1664  {
1665  nOverride++;
1666  }
1667  }
1668  }
1669  }
1670  }
1671 
1672  Info<< "Overriding nearest with intersection of close gaps at "
1673  << returnReduce(nOverride, sumOp<label>())
1674  << " out of " << returnReduce(pp.nPoints(), sumOp<label>())
1675  << " points." << endl;
1676 }
1677 
1678 
1679 void Foam::snappySnapDriver::calcNearestSurface
1680 (
1681  const refinementSurfaces& surfaces,
1682 
1683  const labelList& surfacesToTest,
1684  const labelListList& regionsToTest,
1685 
1686  const pointField& localPoints,
1687  const labelList& zonePointIndices,
1688 
1689  scalarField& minSnapDist,
1690  labelList& snapSurf,
1691  vectorField& patchDisp,
1692 
1693  // Optional: nearest point, normal
1694  pointField& nearestPoint,
1695  vectorField& nearestNormal
1696 )
1697 {
1698  // Find nearest for points both on faceZone and pp.
1699  List<pointIndexHit> hitInfo;
1700  labelList hitSurface;
1701 
1702  if (nearestNormal.size() == localPoints.size())
1703  {
1704  labelList hitRegion;
1705  vectorField hitNormal;
1706  surfaces.findNearestRegion
1707  (
1708  surfacesToTest,
1709  regionsToTest,
1710 
1711  pointField(localPoints, zonePointIndices),
1712  sqr(scalarField(minSnapDist, zonePointIndices)),
1713 
1714  hitSurface,
1715  hitInfo,
1716  hitRegion,
1717  hitNormal
1718  );
1719 
1720  forAll(hitInfo, i)
1721  {
1722  if (hitInfo[i].hit())
1723  {
1724  label pointi = zonePointIndices[i];
1725  nearestPoint[pointi] = hitInfo[i].hitPoint();
1726  nearestNormal[pointi] = hitNormal[i];
1727  }
1728  }
1729  }
1730  else
1731  {
1732  surfaces.findNearest
1733  (
1734  surfacesToTest,
1735  regionsToTest,
1736 
1737  pointField(localPoints, zonePointIndices),
1738  sqr(scalarField(minSnapDist, zonePointIndices)),
1739 
1740  hitSurface,
1741  hitInfo
1742  );
1743  }
1744 
1745  forAll(hitInfo, i)
1746  {
1747  if (hitInfo[i].hit())
1748  {
1749  label pointi = zonePointIndices[i];
1750 
1751  patchDisp[pointi] = hitInfo[i].hitPoint() - localPoints[pointi];
1752  minSnapDist[pointi] = mag(patchDisp[pointi]);
1753  snapSurf[pointi] = hitSurface[i];
1754  }
1755  }
1756 }
1757 
1758 
1759 Foam::vectorField Foam::snappySnapDriver::calcNearestSurface
1761  const bool strictRegionSnap,
1762  const meshRefinement& meshRefiner,
1763  const labelList& globalToMasterPatch,
1764  const labelList& globalToSlavePatch,
1765  const scalarField& snapDist,
1766  const indirectPrimitivePatch& pp,
1767  pointField& nearestPoint,
1768  vectorField& nearestNormal
1769 )
1770 {
1771  Info<< "Calculating patchDisplacement as distance to nearest surface"
1772  << " point ..." << endl;
1773  if (strictRegionSnap)
1774  {
1775  Info<< " non-zone points : attract to local region on surface only"
1776  << nl
1777  << " zone points : attract to local region on surface only"
1778  << nl
1779  << endl;
1780  }
1781  else
1782  {
1783  Info<< " non-zone points :"
1784  << " attract to nearest of all non-zone surfaces"
1785  << nl
1786  << " zone points : attract to zone surface only" << nl
1787  << endl;
1788  }
1789 
1790 
1791  const pointField& localPoints = pp.localPoints();
1792  const refinementSurfaces& surfaces = meshRefiner.surfaces();
1793  const fvMesh& mesh = meshRefiner.mesh();
1794 
1795  // Displacement per patch point
1796  vectorField patchDisp(localPoints.size(), Zero);
1797 
1798  if (returnReduce(localPoints.size(), sumOp<label>()) > 0)
1799  {
1800  // Current surface snapped to. Used to check whether points have been
1801  // snapped at all
1802  labelList snapSurf(localPoints.size(), -1);
1803 
1804  // Current best snap distance (since point might be on multiple
1805  // regions)
1806  scalarField minSnapDist(snapDist);
1807 
1808 
1809  if (strictRegionSnap)
1810  {
1811  // Attract patch points to same region only
1812 
1813  forAll(surfaces.surfaces(), surfi)
1814  {
1815  label geomi = surfaces.surfaces()[surfi];
1816  label nRegions = surfaces.geometry()[geomi].regions().size();
1817 
1818  const labelList surfacesToTest(1, surfi);
1819 
1820  for (label regioni = 0; regioni < nRegions; regioni++)
1821  {
1822  label globali = surfaces.globalRegion(surfi, regioni);
1823  label masterPatchi = globalToMasterPatch[globali];
1824 
1825  // Get indices of points both on patch and on pp
1826  labelList zonePointIndices
1827  (
1828  getFacePoints
1829  (
1830  pp,
1831  mesh.boundaryMesh()[masterPatchi]
1832  )
1833  );
1834 
1835  calcNearestSurface
1836  (
1837  surfaces,
1838 
1839  surfacesToTest,
1840  labelListList(1, labelList(1, regioni)), //regionsToTest
1841 
1842  localPoints,
1843  zonePointIndices,
1844 
1845  minSnapDist,
1846  snapSurf,
1847  patchDisp,
1848 
1849  // Optional: nearest point, normal
1850  nearestPoint,
1851  nearestNormal
1852  );
1853 
1854  if (globalToSlavePatch[globali] != masterPatchi)
1855  {
1856  label slavePatchi = globalToSlavePatch[globali];
1857 
1858  // Get indices of points both on patch and on pp
1859  labelList zonePointIndices
1860  (
1861  getFacePoints
1862  (
1863  pp,
1864  mesh.boundaryMesh()[slavePatchi]
1865  )
1866  );
1867 
1868  calcNearestSurface
1869  (
1870  surfaces,
1871 
1872  surfacesToTest,
1873  labelListList(1, labelList(1, regioni)),
1874 
1875  localPoints,
1876  zonePointIndices,
1877 
1878  minSnapDist,
1879  snapSurf,
1880  patchDisp,
1881 
1882  // Optional: nearest point, normal
1883  nearestPoint,
1884  nearestNormal
1885  );
1886  }
1887  }
1888  }
1889  }
1890  else
1891  {
1892  // Divide surfaces into zoned and unzoned
1893  const labelList unzonedSurfaces =
1895  (
1896  meshRefiner.surfaces().surfZones()
1897  );
1898 
1899 
1900  // 1. All points to non-interface surfaces
1901  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1902 
1903  List<pointIndexHit> hitInfo;
1904  labelList hitSurface;
1905 
1906  if (nearestNormal.size() == localPoints.size())
1907  {
1908  labelList hitRegion;
1909  vectorField hitNormal;
1910  surfaces.findNearestRegion
1911  (
1912  unzonedSurfaces,
1913  localPoints,
1914  sqr(snapDist),
1915  hitSurface,
1916  hitInfo,
1917  hitRegion,
1918  hitNormal
1919  );
1920 
1921  forAll(hitInfo, pointi)
1922  {
1923  if (hitInfo[pointi].hit())
1924  {
1925  nearestPoint[pointi] = hitInfo[pointi].hitPoint();
1926  nearestNormal[pointi] = hitNormal[pointi];
1927  }
1928  }
1929  }
1930  else
1931  {
1932  surfaces.findNearest
1933  (
1934  unzonedSurfaces,
1935  localPoints,
1936  sqr(snapDist), // sqr of attract distance
1937  hitSurface,
1938  hitInfo
1939  );
1940  }
1941 
1942  forAll(hitInfo, pointi)
1943  {
1944  if (hitInfo[pointi].hit())
1945  {
1946  patchDisp[pointi] =
1947  hitInfo[pointi].hitPoint()
1948  - localPoints[pointi];
1949 
1950  snapSurf[pointi] = hitSurface[pointi];
1951  }
1952  }
1953 
1954 
1955  const labelList zonedSurfaces = surfaceZonesInfo::getNamedSurfaces
1956  (
1957  meshRefiner.surfaces().surfZones()
1958  );
1959 
1960 
1961  // 2. All points on zones to their respective surface
1962  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1963  // (ignoring faceZone subdivision)
1964 
1965  // Surfaces with zone information
1966  const PtrList<surfaceZonesInfo>& surfZones = surfaces.surfZones();
1967 
1968  forAll(zonedSurfaces, i)
1969  {
1970  label surfi = zonedSurfaces[i];
1971  const labelList surfacesToTest(1, surfi);
1972  const label geomi = surfaces.surfaces()[surfi];
1973  const label nRegions =
1974  surfaces.geometry()[geomi].regions().size();
1975 
1976  const wordList& faceZoneNames =
1977  surfZones[surfi].faceZoneNames();
1978 
1979  // Get indices of points both on any faceZone and on pp.
1980  bitSet pointOnZone(pp.nPoints());
1981  forAll(faceZoneNames, locali)
1982  {
1983  getZoneSurfacePoints
1984  (
1985  mesh,
1986  pp,
1987  faceZoneNames[locali],
1988  pointOnZone
1989  );
1990  }
1991  const labelList zonePointIndices(pointOnZone.toc());
1992 
1993  calcNearestSurface
1994  (
1995  surfaces,
1996 
1997  surfacesToTest,
1998  labelListList(1, identity(nRegions)),
1999 
2000  localPoints,
2001  zonePointIndices,
2002 
2003  minSnapDist,
2004  snapSurf,
2005  patchDisp,
2006 
2007  // Optional: nearest point, normal
2008  nearestPoint,
2009  nearestNormal
2010  );
2011  }
2012  }
2013 
2014 
2015  // Check if all points are being snapped
2016  forAll(snapSurf, pointi)
2017  {
2018  if (snapSurf[pointi] == -1)
2019  {
2020  static label nWarn = 0;
2021 
2022  if (nWarn < 100)
2023  {
2025  << "For point:" << pointi
2026  << " coordinate:" << localPoints[pointi]
2027  << " did not find any surface within:"
2028  << minSnapDist[pointi] << " metre." << endl;
2029  nWarn++;
2030  if (nWarn == 100)
2031  {
2033  << "Reached warning limit " << nWarn
2034  << ". Suppressing further warnings." << endl;
2035  }
2036  }
2037  }
2038  }
2039 
2040  {
2041  const bitSet isPatchMasterPoint
2042  (
2044  (
2045  mesh,
2046  pp.meshPoints()
2047  )
2048  );
2049 
2050  scalarField magDisp(mag(patchDisp));
2051 
2052  Info<< "Wanted displacement : average:"
2053  << meshRefinement::gAverage(isPatchMasterPoint, magDisp)
2054  << " min:" << gMin(magDisp)
2055  << " max:" << gMax(magDisp) << endl;
2056  }
2057  }
2058 
2059  Info<< "Calculated surface displacement in = "
2060  << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl;
2061 
2062 
2063  // Limit amount of movement. Can not happen for triSurfaceMesh but
2064  // can happen for some analytical shapes?
2065  forAll(patchDisp, patchPointi)
2066  {
2067  scalar magDisp = mag(patchDisp[patchPointi]);
2068 
2069  if (magDisp > snapDist[patchPointi])
2070  {
2071  patchDisp[patchPointi] *= snapDist[patchPointi] / magDisp;
2072 
2073  Pout<< "Limiting displacement for " << patchPointi
2074  << " from " << magDisp << " to " << snapDist[patchPointi]
2075  << endl;
2076  }
2077  }
2078 
2079  // Points on zones in one domain but only present as point on other
2080  // will not do condition 2 on all. Sync explicitly.
2082  (
2083  mesh,
2084  pp.meshPoints(),
2085  patchDisp,
2086  minMagSqrEqOp<point>(), // combine op
2087  vector(GREAT, GREAT, GREAT) // null value (note: cannot use VGREAT)
2088  );
2089 
2090  return patchDisp;
2091 }
2092 
2093 
2096  const snapParameters& snapParams,
2097  motionSmoother& meshMover
2098 ) const
2099 {
2100  if (dryRun_)
2101  {
2102  return;
2103  }
2104 
2105  const fvMesh& mesh = meshRefiner_.mesh();
2106  const indirectPrimitivePatch& pp = meshMover.patch();
2107 
2108  Info<< "Smoothing displacement ..." << endl;
2109 
2110  // Set edge diffusivity as inverse of distance to patch
2111  scalarField edgeGamma(1.0/(edgePatchDist(meshMover.pMesh(), pp) + SMALL));
2112  //scalarField edgeGamma(mesh.nEdges(), 1.0);
2113  //scalarField edgeGamma(wallGamma(mesh, pp, 10, 1));
2114 
2115  // Get displacement field
2116  pointVectorField& disp = meshMover.displacement();
2117 
2118  for (label iter = 0; iter < snapParams.nSmoothDispl(); iter++)
2119  {
2120  if ((iter % 10) == 0)
2121  {
2122  Info<< "Iteration " << iter << endl;
2123  }
2124  pointVectorField oldDisp(disp);
2125  meshMover.smooth(oldDisp, edgeGamma, disp);
2126  }
2127  Info<< "Displacement smoothed in = "
2128  << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl;
2129 
2131  {
2132  const_cast<Time&>(mesh.time())++;
2133  Info<< "Writing smoothed mesh to time " << meshRefiner_.timeName()
2134  << endl;
2135 
2136  // Moving mesh creates meshPhi. Can be cleared out by a mesh.clearOut
2137  // but this will also delete all pointMesh but not pointFields which
2138  // gives an illegal situation.
2139 
2140  meshRefiner_.write
2141  (
2144  (
2147  ),
2148  mesh.time().path()/meshRefiner_.timeName()
2149  );
2150  Info<< "Writing displacement field ..." << endl;
2151  disp.write();
2152  tmp<pointScalarField> magDisp(mag(disp));
2153  magDisp().write();
2154 
2155  Info<< "Writing actual patch displacement ..." << endl;
2156  vectorField actualPatchDisp(disp, pp.meshPoints());
2157  dumpMove
2158  (
2159  mesh.time().path()
2160  / "actualPatchDisplacement_" + meshRefiner_.timeName() + ".obj",
2161  pp.localPoints(),
2162  pp.localPoints() + actualPatchDisp
2163  );
2164  }
2165 }
2166 
2167 
2170  const snapParameters& snapParams,
2171  const label nInitErrors,
2172  const List<labelPair>& baffles,
2173  motionSmoother& meshMover
2174 )
2175 {
2176  addProfiling(scale, "snappyHexMesh::snap::scale");
2177  const fvMesh& mesh = meshRefiner_.mesh();
2178 
2179  // Relax displacement until correct mesh
2180  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2181  labelList checkFaces(identity(mesh.nFaces()));
2182 
2183  scalar oldErrorReduction = -1;
2184 
2185  bool meshOk = false;
2186 
2187  Info<< "Moving mesh ..." << endl;
2188  for (label iter = 0; iter < 2*snapParams.nSnap(); iter++)
2189  {
2190  Info<< nl << "Iteration " << iter << endl;
2191 
2192  if (iter == snapParams.nSnap())
2193  {
2194  Info<< "Displacement scaling for error reduction set to 0." << endl;
2195  oldErrorReduction = meshMover.setErrorReduction(0.0);
2196  }
2197 
2198  meshOk = meshMover.scaleMesh(checkFaces, baffles, true, nInitErrors);
2199 
2200  if (meshOk)
2201  {
2202  Info<< "Successfully moved mesh" << endl;
2203  break;
2204  }
2206  {
2207  const_cast<Time&>(mesh.time())++;
2208  Info<< "Writing scaled mesh to time " << meshRefiner_.timeName()
2209  << endl;
2210  mesh.write();
2211 
2212  Info<< "Writing displacement field ..." << endl;
2213  meshMover.displacement().write();
2214  tmp<pointScalarField> magDisp(mag(meshMover.displacement()));
2215  magDisp().write();
2216  }
2217  }
2218 
2219  if (oldErrorReduction >= 0)
2220  {
2221  meshMover.setErrorReduction(oldErrorReduction);
2222  }
2223  Info<< "Moved mesh in = "
2224  << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl;
2225 
2226  return meshOk;
2227 }
2228 
2229 
2230 // After snapping: correct patching according to nearest surface.
2231 // Code is very similar to calcNearestSurface.
2232 // - calculate face-wise snap distance as max of point-wise
2233 // - calculate face-wise nearest surface point
2234 // - repatch face according to patch for surface point.
2237  const snapParameters& snapParams,
2238  const labelList& adaptPatchIDs,
2239  const labelList& preserveFaces
2240 )
2241 {
2242  const fvMesh& mesh = meshRefiner_.mesh();
2243  const refinementSurfaces& surfaces = meshRefiner_.surfaces();
2244 
2245  Info<< "Repatching faces according to nearest surface ..." << endl;
2246 
2247  // Get the labels of added patches.
2249  (
2251  (
2252  mesh,
2253  adaptPatchIDs
2254  )
2255  );
2256  indirectPrimitivePatch& pp = ppPtr();
2257 
2258  // Divide surfaces into zoned and unzoned
2259  labelList zonedSurfaces =
2261  labelList unzonedSurfaces =
2263 
2264 
2265  // Faces that do not move
2266  bitSet isZonedFace(mesh.nFaces());
2267  {
2268  // 1. Preserve faces in preserveFaces list
2269  forAll(preserveFaces, facei)
2270  {
2271  if (preserveFaces[facei] != -1)
2272  {
2273  isZonedFace.set(facei);
2274  }
2275  }
2276 
2277  // 2. All faces on zoned surfaces
2278  const PtrList<surfaceZonesInfo>& surfZones = surfaces.surfZones();
2279  const faceZoneMesh& fZones = mesh.faceZones();
2280 
2281  forAll(zonedSurfaces, i)
2282  {
2283  const label zoneSurfi = zonedSurfaces[i];
2284  const wordList& fZoneNames = surfZones[zoneSurfi].faceZoneNames();
2285  forAll(fZoneNames, i)
2286  {
2287  const faceZone& fZone = fZones[fZoneNames[i]];
2288  isZonedFace.set(fZone);
2289  }
2290  }
2291  }
2292 
2293 
2294  // Determine per pp face which patch it should be in
2295  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2296 
2297  // Patch that face should be in
2298  labelList closestPatch(pp.size(), -1);
2299  {
2300  // face snap distance as max of point snap distance
2301  scalarField faceSnapDist(pp.size(), -GREAT);
2302  {
2303  // Distance to attract to nearest feature on surface
2304  const scalarField snapDist
2305  (
2306  calcSnapDistance
2307  (
2308  mesh,
2309  snapParams,
2310  pp
2311  )
2312  );
2313 
2314  const faceList& localFaces = pp.localFaces();
2315 
2316  forAll(localFaces, facei)
2317  {
2318  const face& f = localFaces[facei];
2319 
2320  forAll(f, fp)
2321  {
2322  faceSnapDist[facei] = max
2323  (
2324  faceSnapDist[facei],
2325  snapDist[f[fp]]
2326  );
2327  }
2328  }
2329  }
2330 
2331  pointField localFaceCentres(mesh.faceCentres(), pp.addressing());
2332 
2333  // Get nearest surface and region
2334  labelList hitSurface;
2335  labelList hitRegion;
2336  surfaces.findNearestRegion
2337  (
2338  unzonedSurfaces,
2339  localFaceCentres,
2340  sqr(faceSnapDist), // sqr of attract distance
2341  hitSurface,
2342  hitRegion
2343  );
2344 
2345  // Get patch
2346  forAll(pp, i)
2347  {
2348  label facei = pp.addressing()[i];
2349 
2350  if (hitSurface[i] != -1 && !isZonedFace.test(facei))
2351  {
2352  closestPatch[i] = globalToMasterPatch_
2353  [
2354  surfaces.globalRegion
2355  (
2356  hitSurface[i],
2357  hitRegion[i]
2358  )
2359  ];
2360  }
2361  }
2362  }
2363 
2364 
2365  // Change those faces for which there is a different closest patch
2366  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2367 
2368  labelList ownPatch(mesh.nFaces(), -1);
2369  labelList neiPatch(mesh.nFaces(), -1);
2370 
2372 
2373  forAll(patches, patchi)
2374  {
2375  const polyPatch& pp = patches[patchi];
2376 
2377  forAll(pp, i)
2378  {
2379  ownPatch[pp.start()+i] = patchi;
2380  neiPatch[pp.start()+i] = patchi;
2381  }
2382  }
2383 
2384  label nChanged = 0;
2385  forAll(closestPatch, i)
2386  {
2387  label facei = pp.addressing()[i];
2388 
2389  if (closestPatch[i] != -1 && closestPatch[i] != ownPatch[facei])
2390  {
2391  ownPatch[facei] = closestPatch[i];
2392  neiPatch[facei] = closestPatch[i];
2393  nChanged++;
2394  }
2395  }
2396 
2397  Info<< "Repatched " << returnReduce(nChanged, sumOp<label>())
2398  << " faces in = " << mesh.time().cpuTimeIncrement() << " s\n" << nl
2399  << endl;
2400 
2401  return meshRefiner_.createBaffles(ownPatch, neiPatch);
2402 }
2403 
2404 
2405 void Foam::snappySnapDriver::detectWarpedFaces
2406 (
2407  const scalar featureCos,
2408  const indirectPrimitivePatch& pp,
2409 
2410  DynamicList<label>& splitFaces,
2411  DynamicList<labelPair>& splits
2412 ) const
2413 {
2414  const fvMesh& mesh = meshRefiner_.mesh();
2415  const faceList& localFaces = pp.localFaces();
2416  const pointField& localPoints = pp.localPoints();
2417  const labelList& bFaces = pp.addressing();
2418 
2419  splitFaces.clear();
2420  splitFaces.setCapacity(bFaces.size());
2421  splits.clear();
2422  splits.setCapacity(bFaces.size());
2423 
2424  // Determine parallel consistent normals on points
2425  const vectorField pointNormals(PatchTools::pointNormals(mesh, pp));
2426 
2427  face f0(4);
2428  face f1(4);
2429 
2430  forAll(localFaces, facei)
2431  {
2432  const face& f = localFaces[facei];
2433 
2434  if (f.size() >= 4)
2435  {
2436  // See if splitting face across diagonal would make two faces with
2437  // biggish normal angle
2438 
2439  labelPair minDiag(-1, -1);
2440  scalar minCos(GREAT);
2441 
2442  for (label startFp = 0; startFp < f.size()-2; startFp++)
2443  {
2444  label minFp = f.rcIndex(startFp);
2445 
2446  for
2447  (
2448  label endFp = f.fcIndex(f.fcIndex(startFp));
2449  endFp < f.size() && endFp != minFp;
2450  endFp++
2451  )
2452  {
2453  // Form two faces
2454  f0.setSize(endFp-startFp+1);
2455  label i0 = 0;
2456  for (label fp = startFp; fp <= endFp; fp++)
2457  {
2458  f0[i0++] = f[fp];
2459  }
2460  f1.setSize(f.size()+2-f0.size());
2461  label i1 = 0;
2462  for (label fp = endFp; fp != startFp; fp = f.fcIndex(fp))
2463  {
2464  f1[i1++] = f[fp];
2465  }
2466  f1[i1++] = f[startFp];
2467 
2468  //Info<< "Splitting face:" << f << " into f0:" << f0
2469  // << " f1:" << f1 << endl;
2470 
2471  const vector n0 = f0.areaNormal(localPoints);
2472  const scalar n0Mag = mag(n0);
2473 
2474  const vector n1 = f1.areaNormal(localPoints);
2475  const scalar n1Mag = mag(n1);
2476 
2477  if (n0Mag > ROOTVSMALL && n1Mag > ROOTVSMALL)
2478  {
2479  scalar cosAngle = (n0/n0Mag) & (n1/n1Mag);
2480  if (cosAngle < minCos)
2481  {
2482  minCos = cosAngle;
2483  minDiag = labelPair(startFp, endFp);
2484  }
2485  }
2486  }
2487  }
2488 
2489 
2490  if (minCos < featureCos)
2491  {
2492  splitFaces.append(bFaces[facei]);
2493  splits.append(minDiag);
2494  }
2495  }
2496  }
2497 }
2498 
2499 
2500 Foam::labelList Foam::snappySnapDriver::getInternalOrBaffleDuplicateFace() const
2501 {
2502  const fvMesh& mesh = meshRefiner_.mesh();
2503 
2504  labelList internalOrBaffleFaceZones;
2505  {
2506  List<surfaceZonesInfo::faceZoneType> fzTypes(2);
2507  fzTypes[0] = surfaceZonesInfo::INTERNAL;
2508  fzTypes[1] = surfaceZonesInfo::BAFFLE;
2509  internalOrBaffleFaceZones = meshRefiner_.getZones(fzTypes);
2510  }
2511 
2512  List<labelPair> baffles
2513  (
2514  meshRefiner_.subsetBaffles
2515  (
2516  mesh,
2517  internalOrBaffleFaceZones,
2519  )
2520  );
2521 
2522  labelList faceToDuplicate(mesh.nFaces(), -1);
2523  forAll(baffles, i)
2524  {
2525  const labelPair& p = baffles[i];
2526  faceToDuplicate[p[0]] = p[1];
2527  faceToDuplicate[p[1]] = p[0];
2528  }
2529 
2530  return faceToDuplicate;
2531 }
2532 
2533 
2536  const dictionary& snapDict,
2537  const dictionary& motionDict,
2538  const meshRefinement::FaceMergeType mergeType,
2539  const scalar featureCos,
2540  const scalar planarAngle,
2541  const snapParameters& snapParams
2542 )
2543 {
2544  addProfiling(snap, "snappyHexMesh::snap");
2545  fvMesh& mesh = meshRefiner_.mesh();
2546 
2547  Info<< nl
2548  << "Morphing phase" << nl
2549  << "--------------" << nl
2550  << endl;
2551 
2552  // faceZone handling
2553  // ~~~~~~~~~~~~~~~~~
2554  //
2555  // We convert all faceZones into baffles during snapping so we can use
2556  // a standard mesh motion (except for the mesh checking which for baffles
2557  // created from internal faces should check across the baffles). The state
2558  // is stored in two variables:
2559  // baffles : pairs of boundary faces
2560  // duplicateFace : from mesh face to its baffle colleague (or -1 for
2561  // normal faces)
2562  // There are three types of faceZones according to the faceType property:
2563  //
2564  // internal
2565  // --------
2566  // - baffles: need to be checked across
2567  // - duplicateFace: from face to duplicate face. Contains
2568  // all faces on faceZone to prevents merging patch faces.
2569  //
2570  // baffle
2571  // ------
2572  // - baffles: no need to be checked across
2573  // - duplicateFace: contains all faces on faceZone to prevent
2574  // merging patch faces.
2575  //
2576  // boundary
2577  // --------
2578  // - baffles: no need to be checked across. Also points get duplicated
2579  // so will no longer be baffles
2580  // - duplicateFace: contains no faces on faceZone since both sides can
2581  // merge faces independently.
2582 
2583 
2584 
2585  // faceZones of type internal
2586  const labelList internalFaceZones
2587  (
2588  meshRefiner_.getZones
2589  (
2591  (
2592  1,
2594  )
2595  )
2596  );
2597 
2598 
2599  // Create baffles (pairs of faces that share the same points)
2600  // Baffles stored as owner and neighbour face that have been created.
2601  {
2602  List<labelPair> baffles;
2603  labelList originatingFaceZone;
2604  meshRefiner_.createZoneBaffles
2605  (
2606  identity(mesh.faceZones().size()),
2607  baffles,
2608  originatingFaceZone
2609  );
2610  }
2611 
2612  // Duplicate points on faceZones of type boundary
2613  meshRefiner_.dupNonManifoldBoundaryPoints();
2614 
2615 
2616  bool doFeatures = false;
2617  label nFeatIter = 1;
2618  if (snapParams.nFeatureSnap() > 0)
2619  {
2620  doFeatures = true;
2621 
2622  if (!dryRun_)
2623  {
2624  nFeatIter = snapParams.nFeatureSnap();
2625  }
2626 
2627  Info<< "Snapping to features in " << nFeatIter
2628  << " iterations ..." << endl;
2629  }
2630 
2631 
2632  bool meshOk = false;
2633 
2634 
2635  // Get the labels of added patches.
2636  labelList adaptPatchIDs(meshRefiner_.meshedPatches());
2637 
2638 
2639 
2640  {
2642  (
2644  (
2645  mesh,
2646  adaptPatchIDs
2647  )
2648  );
2649 
2650 
2651  // Distance to attract to nearest feature on surface
2652  scalarField snapDist(calcSnapDistance(mesh, snapParams, ppPtr()));
2653 
2654 
2655  // Construct iterative mesh mover.
2656  Info<< "Constructing mesh displacer ..." << endl;
2657  Info<< "Using mesh parameters " << motionDict << nl << endl;
2658 
2659  autoPtr<motionSmoother> meshMoverPtr
2660  (
2661  new motionSmoother
2662  (
2663  mesh,
2664  ppPtr(),
2665  adaptPatchIDs,
2667  (
2669  adaptPatchIDs
2670  ),
2671  motionDict,
2672  dryRun_
2673  )
2674  );
2675 
2676 
2677  // Check initial mesh
2678  Info<< "Checking initial mesh ..." << endl;
2679  labelHashSet wrongFaces(mesh.nFaces()/100);
2680  motionSmoother::checkMesh(false, mesh, motionDict, wrongFaces, dryRun_);
2681  const label nInitErrors = returnReduce
2682  (
2683  wrongFaces.size(),
2684  sumOp<label>()
2685  );
2686 
2687  Info<< "Detected " << nInitErrors << " illegal faces"
2688  << " (concave, zero area or negative cell pyramid volume)"
2689  << endl;
2690 
2691 
2692  Info<< "Checked initial mesh in = "
2693  << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl;
2694 
2695  // Extract baffles across internal faceZones (for checking mesh quality
2696  // across
2697  labelPairList internalBaffles
2698  (
2699  meshRefiner_.subsetBaffles
2700  (
2701  mesh,
2702  internalFaceZones,
2704  )
2705  );
2706 
2707 
2708 
2709  // Pre-smooth patch vertices (so before determining nearest)
2710  preSmoothPatch
2711  (
2712  meshRefiner_,
2713  snapParams,
2714  nInitErrors,
2715  internalBaffles,
2716  meshMoverPtr()
2717  );
2718 
2719  // TBD. Include re-patching?
2720 
2721 
2722  //- Only if in feature attraction mode:
2723  // Nearest feature
2724  vectorField patchAttraction;
2725  // Constraints at feature
2726  List<pointConstraint> patchConstraints;
2727 
2728 
2729  //- Any faces to split
2730  DynamicList<label> splitFaces;
2731  //- Indices in face to split across
2732  DynamicList<labelPair> splits;
2733 
2734 
2735  for (label iter = 0; iter < nFeatIter; iter++)
2736  {
2737  Info<< nl
2738  << "Morph iteration " << iter << nl
2739  << "-----------------" << endl;
2740 
2741  // Splitting iteration?
2742  bool doSplit = false;
2743  if
2744  (
2745  doFeatures
2746  && snapParams.nFaceSplitInterval() > 0
2747  && (
2748  (iter == nFeatIter-1)
2749  || (iter > 0 && (iter%snapParams.nFaceSplitInterval()) == 0)
2750  )
2751  )
2752  {
2753  doSplit = true;
2754  }
2755 
2756 
2757 
2758  indirectPrimitivePatch& pp = ppPtr();
2759  motionSmoother& meshMover = meshMoverPtr();
2760 
2761 
2762  // Calculate displacement at every patch point if we need it:
2763  // - if automatic near-surface detection
2764  // - if face splitting active
2765  pointField nearestPoint;
2766  vectorField nearestNormal;
2767 
2768  if (snapParams.detectNearSurfacesSnap() || doSplit)
2769  {
2770  nearestPoint.setSize(pp.nPoints(), vector::max);
2771  nearestNormal.setSize(pp.nPoints(), Zero);
2772  }
2773 
2774  vectorField disp = calcNearestSurface
2775  (
2776  snapParams.strictRegionSnap(), // attract points to region only
2777  meshRefiner_,
2778  globalToMasterPatch_, // for if strictRegionSnap
2779  globalToSlavePatch_, // for if strictRegionSnap
2780  snapDist,
2781  pp,
2782 
2783  nearestPoint,
2784  nearestNormal
2785  );
2786 
2787 
2788  // Override displacement at thin gaps
2789  if (snapParams.detectNearSurfacesSnap())
2790  {
2791  detectNearSurfaces
2792  (
2793  Foam::cos(degToRad(planarAngle)),// planar cos for gaps
2794  pp,
2795  nearestPoint, // surfacepoint from nearest test
2796  nearestNormal, // surfacenormal from nearest test
2797 
2798  disp
2799  );
2800  }
2801 
2802  // Override displacement with feature edge attempt
2803  if (doFeatures)
2804  {
2805  splitFaces.clear();
2806  splits.clear();
2807  disp = calcNearestSurfaceFeature
2808  (
2809  snapParams,
2810  !doSplit, // alignMeshEdges
2811  iter,
2812  featureCos,
2813  scalar(iter+1)/nFeatIter,
2814 
2815  snapDist,
2816  disp,
2817  nearestNormal,
2818  meshMover,
2819 
2820  patchAttraction,
2821  patchConstraints,
2822 
2823  splitFaces,
2824  splits
2825  );
2826  }
2827 
2828  // Check for displacement being outwards.
2829  outwardsDisplacement(pp, disp);
2830 
2831  // Set initial distribution of displacement field (on patches)
2832  // from patchDisp and make displacement consistent with b.c.
2833  // on displacement pointVectorField.
2834  meshMover.setDisplacement(disp);
2835 
2836 
2838  {
2839  dumpMove
2840  (
2841  mesh.time().path()
2842  / "patchDisplacement_" + name(iter) + ".obj",
2843  pp.localPoints(),
2844  pp.localPoints() + disp
2845  );
2846  }
2847 
2848  // Get smoothly varying internal displacement field.
2849  smoothDisplacement(snapParams, meshMover);
2850 
2851  // Apply internal displacement to mesh.
2852  meshOk = scaleMesh
2853  (
2854  snapParams,
2855  nInitErrors,
2856  internalBaffles,
2857  meshMover
2858  );
2859 
2860  if (!meshOk)
2861  {
2863  << "Did not successfully snap mesh."
2864  << " Continuing to snap to resolve easy" << nl
2865  << " surfaces but the"
2866  << " resulting mesh will not satisfy your quality"
2867  << " constraints" << nl << endl;
2868  }
2869 
2871  {
2872  const_cast<Time&>(mesh.time())++;
2873  Info<< "Writing scaled mesh to time "
2874  << meshRefiner_.timeName() << endl;
2875  meshRefiner_.write
2876  (
2879  (
2882  ),
2883  mesh.time().path()/meshRefiner_.timeName()
2884  );
2885  Info<< "Writing displacement field ..." << endl;
2886  meshMover.displacement().write();
2887  tmp<pointScalarField> magDisp
2888  (
2889  mag(meshMover.displacement())
2890  );
2891  magDisp().write();
2892  }
2893 
2894  // Use current mesh as base mesh
2895  meshMover.correct();
2896 
2897 
2898 
2899  // See if any faces need splitting
2900  label nTotalSplit = returnReduce(splitFaces.size(), sumOp<label>());
2901  if (nTotalSplit && doSplit)
2902  {
2903  // Filter out baffle faces from faceZones of type
2904  // internal/baffle
2905 
2906  labelList duplicateFace(getInternalOrBaffleDuplicateFace());
2907 
2908  {
2909  labelList oldSplitFaces(std::move(splitFaces));
2910  List<labelPair> oldSplits(std::move(splits));
2911  forAll(oldSplitFaces, i)
2912  {
2913  if (duplicateFace[oldSplitFaces[i]] == -1)
2914  {
2915  splitFaces.append(oldSplitFaces[i]);
2916  splits.append(oldSplits[i]);
2917  }
2918  }
2919  nTotalSplit = returnReduce
2920  (
2921  splitFaces.size(),
2922  sumOp<label>()
2923  );
2924  }
2925 
2926  // Update mesh
2927  meshRefiner_.splitFacesUndo
2928  (
2929  splitFaces,
2930  splits,
2931  motionDict,
2932 
2933  duplicateFace,
2934  internalBaffles
2935  );
2936 
2937  // Redo meshMover
2938  meshMoverPtr.clear();
2939  ppPtr.clear();
2940 
2941  // Update mesh mover
2942  ppPtr = meshRefinement::makePatch(mesh, adaptPatchIDs);
2943  meshMoverPtr.reset
2944  (
2945  new motionSmoother
2946  (
2947  mesh,
2948  ppPtr(),
2949  adaptPatchIDs,
2951  (
2953  adaptPatchIDs
2954  ),
2955  motionDict,
2956  dryRun_
2957  )
2958  );
2959 
2960  // Update snapping distance
2961  snapDist = calcSnapDistance(mesh, snapParams, ppPtr());
2962 
2963 
2965  {
2966  const_cast<Time&>(mesh.time())++;
2967  Info<< "Writing split-faces mesh to time "
2968  << meshRefiner_.timeName() << endl;
2969  meshRefiner_.write
2970  (
2973  (
2976  ),
2977  mesh.time().path()/meshRefiner_.timeName()
2978  );
2979  }
2980  }
2981 
2982 
2984  {
2985  forAll(internalBaffles, i)
2986  {
2987  const labelPair& p = internalBaffles[i];
2988  const point& fc0 = mesh.faceCentres()[p[0]];
2989  const point& fc1 = mesh.faceCentres()[p[1]];
2990 
2991  if (mag(fc0-fc1) > meshRefiner_.mergeDistance())
2992  {
2994  << "Separated baffles : f0:" << p[0]
2995  << " centre:" << fc0
2996  << " f1:" << p[1] << " centre:" << fc1
2997  << " distance:" << mag(fc0-fc1)
2998  << exit(FatalError);
2999  }
3000  }
3001  }
3002  }
3003  }
3004 
3005 
3006  // Merge any introduced baffles (from faceZones of faceType 'internal')
3007  {
3008  autoPtr<mapPolyMesh> mapPtr = meshRefiner_.mergeZoneBaffles
3009  (
3010  true, // internal zones
3011  false // baffle zones
3012  );
3013 
3014  if (mapPtr.valid())
3015  {
3017  {
3018  const_cast<Time&>(mesh.time())++;
3019  Info<< "Writing baffle-merged mesh to time "
3020  << meshRefiner_.timeName() << endl;
3021  meshRefiner_.write
3022  (
3025  (
3028  ),
3029  meshRefiner_.timeName()
3030  );
3031  }
3032  }
3033  }
3034 
3035  // Repatch faces according to nearest. Do not repatch baffle faces.
3036  {
3037  labelList duplicateFace(getInternalOrBaffleDuplicateFace());
3038 
3039  repatchToSurface(snapParams, adaptPatchIDs, duplicateFace);
3040  }
3041 
3042  if
3043  (
3044  mergeType == meshRefinement::FaceMergeType::GEOMETRIC
3045  || mergeType == meshRefinement::FaceMergeType::IGNOREPATCH
3046  )
3047  {
3048  labelList duplicateFace(getInternalOrBaffleDuplicateFace());
3049 
3050  // Repatching might have caused faces to be on same patch and hence
3051  // mergeable so try again to merge coplanar faces. Do not merge baffle
3052  // faces to ensure they both stay the same.
3053  label nChanged = meshRefiner_.mergePatchFacesUndo
3054  (
3055  featureCos, // minCos
3056  featureCos, // concaveCos
3057  meshRefiner_.meshedPatches(),
3058  motionDict,
3059  duplicateFace, // faces not to merge
3060  mergeType
3061  );
3062 
3063  nChanged += meshRefiner_.mergeEdgesUndo(featureCos, motionDict);
3064 
3065  if (nChanged > 0 && debug & meshRefinement::MESH)
3066  {
3067  const_cast<Time&>(mesh.time())++;
3068  Info<< "Writing patchFace merged mesh to time "
3069  << meshRefiner_.timeName() << endl;
3070  meshRefiner_.write
3071  (
3074  (
3077  ),
3078  meshRefiner_.timeName()
3079  );
3080  }
3081  }
3082 
3084  {
3085  const_cast<Time&>(mesh.time())++;
3086  }
3087 }
3088 
3089 
3090 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:71
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:109
Foam::snappySnapDriver::smoothDisplacement
void smoothDisplacement(const snapParameters &snapParams, motionSmoother &) const
Smooth the displacement field to the internal.
Definition: snappySnapDriver.C:2095
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:281
p
volScalarField & p
Definition: createFieldRefs.H:8
Foam::PatchTools::pointNormals
static tmp< pointField > pointNormals(const polyMesh &, const PrimitivePatch< FaceList, PointField > &)
Return parallel consistent point normals for patches using mesh points.
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:114
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:895
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:58
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:190
Foam::tmp
A class for managing temporary objects.
Definition: PtrList.H:59
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
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:1559
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:183
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:3440
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:97
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::surfaceZonesInfo::getNamedSurfaces
static labelList getNamedSurfaces(const PtrList< surfaceZonesInfo > &surfList)
Get indices of named surfaces (surfaces with faceZoneName)
Definition: surfaceZonesInfo.C:263
Foam::autoPtr::valid
bool valid() const noexcept
True if the managed pointer is non-null.
Definition: autoPtr.H:148
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:462
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
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:953
syncTools.H
Foam::refinementSurfaces::geometry
const searchableSurfaces & geometry() const
Definition: refinementSurfaces.H:178
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:296
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:133
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:194
Foam::reduce
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
Definition: PstreamReduceOps.H:51
Foam::bitSet::toc
labelList toc() const
The indices of the on bits as a sorted labelList.
Definition: bitSet.C:527
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:3242
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:1080
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:67
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:268
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:62
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:316
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:1904
Foam::refinementSurfaces::globalRegion
label globalRegion(const label surfI, const label regionI) const
From surface and region on surface to global region.
Definition: refinementSurfaces.H:270
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:121
Foam::PrimitivePatch::localFaces
const List< face_type > & localFaces() const
Return patch faces addressing into local point list.
Definition: PrimitivePatch.C:297
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:312
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::PrimitivePatch::localPoints
const Field< point_type > & localPoints() const
Return pointField of points in patch.
Definition: PrimitivePatch.C:339
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:766
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:2236
Foam::surfaceZonesInfo::getUnnamedSurfaces
static labelList getUnnamedSurfaces(const PtrList< surfaceZonesInfo > &surfList)
Get indices of unnamed surfaces (surfaces without faceZoneName)
Definition: surfaceZonesInfo.C:242
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:1592
Foam::indirectPrimitivePatch
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
A PrimitivePatch with an IndirectList for the faces, const reference for the point field.
Definition: indirectPrimitivePatch.H:49
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:2169
Foam::surfaceZonesInfo::BAFFLE
Definition: surfaceZonesInfo.H:89
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:175
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:372
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:1192
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:385
Foam::Pair< label >
Foam::Time::path
fileName path() const
Return path.
Definition: Time.H:358
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:2535
Foam::faceList
List< face > faceList
A List of faces.
Definition: faceListFwd.H:47
Foam::Vector< scalar >
Foam::meshRefinement::writeType
writeType
Enumeration for what to write. Used as a bit-pattern.
Definition: meshRefinement.H:112
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::primitiveMesh::faceCentres
const vectorField & faceCentres() const
Definition: primitiveMeshFaceCentresAndAreas.C:144
Foam::meshRefinement
Helper class which maintains intersections of (changing) mesh with (static) surfaces.
Definition: meshRefinement.H:85
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:3082
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:325
Foam::autoPtr::clear
void clear() noexcept
Same as reset(nullptr)
Definition: autoPtr.H:178
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:248
Foam::VectorSpace< Vector< scalar >, scalar, 3 >::zero
static const Vector< scalar > zero
Definition: VectorSpace.H:115
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:72
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:1234
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:323
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:310
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:1946
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:298
Foam::snappySnapDriver::avgCellCentres
static tmp< pointField > avgCellCentres(const fvMesh &mesh, const indirectPrimitivePatch &)
Helper: calculate average cell centre per point.
Definition: snappySnapDriver.C:976
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:94
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:3118
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:85
Foam::fvc::smooth
void smooth(volScalarField &field, const scalar coeff)
Definition: fvcSmooth.C:44
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:980
Foam::meshRefinement::debugType
debugType
Enumeration for what to debug. Used as a bit-pattern.
Definition: meshRefinement.H:92
Foam::surfaceZonesInfo::INTERNAL
Definition: surfaceZonesInfo.H:88