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-2024 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 "weightedPosition.H"
52 #include "profiling.H"
53 #include "addPatchCellLayer.H"
55 #include "snappyLayerDriver.H"
56 #include "IOmanip.H"
57 
58 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
59 
60 namespace Foam
61 {
62 
63 defineTypeNameAndDebug(snappySnapDriver, 0);
64 
65 } // End namespace Foam
66 
67 
68 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
69 
70 // Calculate geometrically collocated points, Requires bitSet to be
71 // sized and initialised!
72 Foam::label Foam::snappySnapDriver::getCollocatedPoints
73 (
74  const scalar tol,
75  const pointField& points,
76  bitSet& isCollocatedPoint
77 )
78 {
79  labelList pointMap;
80  label nUnique = Foam::mergePoints
81  (
82  points, // points
83  tol, // mergeTol
84  false, // verbose
85  pointMap
86  );
87  bool hasMerged = (nUnique < points.size());
88 
89  if (!returnReduceOr(hasMerged))
90  {
91  return 0;
92  }
93 
94  // Determine which merged points are referenced more than once
95  label nCollocated = 0;
96 
97  // Per old point the newPoint. Or -1 (not set yet) or -2 (already seen
98  // twice)
99  labelList firstOldPoint(nUnique, -1);
100  forAll(pointMap, oldPointi)
101  {
102  label newPointi = pointMap[oldPointi];
103 
104  if (firstOldPoint[newPointi] == -1)
105  {
106  // First use of oldPointi. Store.
107  firstOldPoint[newPointi] = oldPointi;
108  }
109  else if (firstOldPoint[newPointi] == -2)
110  {
111  // Third or more reference of oldPointi -> non-manifold
112  isCollocatedPoint.set(oldPointi);
113  nCollocated++;
114  }
115  else
116  {
117  // Second reference of oldPointi -> non-manifold
118  isCollocatedPoint.set(firstOldPoint[newPointi]);
119  nCollocated++;
120 
121  isCollocatedPoint.set(oldPointi);
122  nCollocated++;
123 
124  // Mark with special value to save checking next time round
125  firstOldPoint[newPointi] = -2;
126  }
127  }
128  return returnReduce(nCollocated, sumOp<label>());
129 }
130 
131 
132 Foam::tmp<Foam::pointField> Foam::snappySnapDriver::smoothInternalDisplacement
133 (
134  const meshRefinement& meshRefiner,
135  const motionSmoother& meshMover
136 )
137 {
138  const indirectPrimitivePatch& pp = meshMover.patch();
139  const polyMesh& mesh = meshMover.mesh();
140 
141  // Get neighbour refinement
142  const hexRef8& cutter = meshRefiner.meshCutter();
143  const labelList& cellLevel = cutter.cellLevel();
144 
145 
146  // Get the faces on the boundary
147  bitSet isFront(mesh.nFaces(), pp.addressing());
148 
149  // Walk out from the surface a bit. Poor man's FaceCellWave.
150  // Commented out for now - not sure if needed and if so how much
151  //for (label iter = 0; iter < 2; iter++)
152  //{
153  // bitSet newIsFront(mesh.nFaces());
154  //
155  // forAll(isFront, facei)
156  // {
157  // if (isFront.test(facei))
158  // {
159  // label own = mesh.faceOwner()[facei];
160  // const cell& ownFaces = mesh.cells()[own];
161  // newIsFront.set(ownFaces);
162  //
163  // if (mesh.isInternalFace(facei))
164  // {
165  // label nei = mesh.faceNeighbour()[facei];
166  // const cell& neiFaces = mesh.cells()[nei];
167  // newIsFront.set(neiFaces);
168  // }
169  // }
170  // }
171  //
172  // syncTools::syncFaceList
173  // (
174  // mesh,
175  // newIsFront,
176  // orEqOp<unsigned int>()
177  // );
178  //
179  // isFront = newIsFront;
180  //}
181 
182  // Mark all points on faces
183  // - not on the boundary
184  // - inbetween differing refinement levels
185  bitSet isMovingPoint(mesh.nPoints());
186 
187  label nInterface = 0;
188 
189  for (label facei = 0; facei < mesh.nInternalFaces(); facei++)
190  {
191  label ownLevel = cellLevel[mesh.faceOwner()[facei]];
192  label neiLevel = cellLevel[mesh.faceNeighbour()[facei]];
193 
194  if (!isFront.test(facei) && ownLevel != neiLevel)
195  {
196  const face& f = mesh.faces()[facei];
197  isMovingPoint.set(f);
198 
199  ++nInterface;
200  }
201  }
202 
203  labelList neiCellLevel;
204  syncTools::swapBoundaryCellList(mesh, cellLevel, neiCellLevel);
205 
206  for (label facei = mesh.nInternalFaces(); facei < mesh.nFaces(); facei++)
207  {
208  label ownLevel = cellLevel[mesh.faceOwner()[facei]];
209  label neiLevel = neiCellLevel[facei-mesh.nInternalFaces()];
210 
211  if (!isFront.test(facei) && ownLevel != neiLevel)
212  {
213  const face& f = mesh.faces()[facei];
214  isMovingPoint.set(f);
215 
216  ++nInterface;
217  }
218  }
219 
220  if (debug)
221  {
222  Info<< "Found " << returnReduce(nInterface, sumOp<label>())
223  << " faces out of " << mesh.globalData().nTotalFaces()
224  << " inbetween refinement regions." << endl;
225  }
226 
227  // Make sure that points that are coupled to a moving point are marked
228  // as well
229  syncTools::syncPointList(mesh, isMovingPoint, maxEqOp<unsigned int>(), 0);
230 
231  // Unmark any point on the boundary. If we're doing zero iterations of
232  // face-cell wave we might have coupled points not being unmarked.
233  isMovingPoint.unset(pp.meshPoints());
234 
235  // Make sure that points that are coupled to meshPoints but not on a patch
236  // are unmarked as well
237  syncTools::syncPointList(mesh, isMovingPoint, minEqOp<unsigned int>(), 1);
238 
239 
240  // Calculate average of connected cells
241  Field<weightedPosition> sumLocation
242  (
243  mesh.nPoints(),
245  );
246 
247  forAll(isMovingPoint, pointi)
248  {
249  if (isMovingPoint.test(pointi))
250  {
251  const labelList& pCells = mesh.pointCells(pointi);
252 
253  sumLocation[pointi].first() = pCells.size();
254  for (const label celli : pCells)
255  {
256  sumLocation[pointi].second() += mesh.cellCentres()[celli];
257  }
258  }
259  }
260 
261  // Add coupled contributions
262  weightedPosition::syncPoints(mesh, sumLocation);
263 
264  auto tdisplacement = tmp<pointField>::New(mesh.nPoints(), Zero);
265  auto& displacement = tdisplacement.ref();
266 
267  label nAdapted = 0;
268 
269  forAll(displacement, pointi)
270  {
271  const weightedPosition& wp = sumLocation[pointi];
272  if (mag(wp.first()) > VSMALL)
273  {
274  displacement[pointi] =
275  wp.second()/wp.first()
276  - mesh.points()[pointi];
277  nAdapted++;
278  }
279  }
280 
281  Info<< "Smoothing " << returnReduce(nAdapted, sumOp<label>())
282  << " points inbetween refinement regions."
283  << endl;
284 
285  return tdisplacement;
286 }
287 
288 
289 // Calculate displacement as average of patch points.
290 Foam::tmp<Foam::pointField> Foam::snappySnapDriver::smoothPatchDisplacement
291 (
292  const motionSmoother& meshMover,
293  const List<labelPair>& baffles
294 )
295 {
296  const indirectPrimitivePatch& pp = meshMover.patch();
297 
298  // Calculate geometrically non-manifold points on the patch to be moved.
299  bitSet nonManifoldPoint(pp.nPoints());
300  label nNonManifoldPoints = getCollocatedPoints
301  (
302  SMALL,
303  pp.localPoints(),
304  nonManifoldPoint
305  );
306  Info<< "Found " << nNonManifoldPoints << " non-manifold point(s)."
307  << endl;
308 
309 
310  // Average points
311  // ~~~~~~~~~~~~~~
312 
313  // We determine three points:
314  // - average of (centres of) connected patch faces
315  // - average of (centres of) connected internal mesh faces
316  // - as fallback: centre of any connected cell
317  // so we can do something moderately sensible for non/manifold points.
318 
319  // Note: the averages are calculated properly parallel. This is
320  // necessary to get the points shared by processors correct.
321 
322 
323  const labelListList& pointFaces = pp.pointFaces();
324  const labelList& meshPoints = pp.meshPoints();
325  const pointField& points = pp.points();
326  const polyMesh& mesh = meshMover.mesh();
327 
328  // Get labels of faces to count (master of coupled faces and baffle pairs)
329  bitSet isMasterFace(syncTools::getMasterFaces(mesh));
330 
331  {
332  forAll(baffles, i)
333  {
334  label f0 = baffles[i].first();
335  label f1 = baffles[i].second();
336 
337  if (isMasterFace.test(f0))
338  {
339  // Make f1 a slave
340  isMasterFace.unset(f1);
341  }
342  else if (isMasterFace.test(f1))
343  {
344  isMasterFace.unset(f0);
345  }
346  else
347  {
349  << "Both sides of baffle consisting of faces " << f0
350  << " and " << f1 << " are already slave faces."
351  << abort(FatalError);
352  }
353  }
354  }
355 
356 
357  // Get average position of boundary face centres
358  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
359 
360  Field<weightedPosition> avgBoundary
361  (
362  pointFaces.size(),
364  );
365  {
366  forAll(pointFaces, patchPointi)
367  {
368  const labelList& pFaces = pointFaces[patchPointi];
369 
370  forAll(pFaces, pfi)
371  {
372  label facei = pFaces[pfi];
373 
374  if (isMasterFace.test(pp.addressing()[facei]))
375  {
376  avgBoundary[patchPointi].first() += 1.0;
377  avgBoundary[patchPointi].second() +=
378  pp[facei].centre(points);
379  }
380  }
381  }
382 
383  // Add coupled contributions
385 
386  // Normalise
387  forAll(avgBoundary, i)
388  {
389  // Note: what if there is no master boundary face?
390  if (mag(avgBoundary[i].first()) > VSMALL)
391  {
392  avgBoundary[i].second() /= avgBoundary[i].first();
393  }
394  }
395  }
396 
397 
398  // Get average position of internal face centres
399  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
400 
401  Field<weightedPosition> avgInternal;
402  {
403  Field<weightedPosition> globalSum
404  (
405  mesh.nPoints(),
407  );
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  weightedPosition& wp = globalSum[f[fp]];
420  wp.first() += 1.0;
421  wp.second() += fc;
422  }
423  }
424 
425  // Count coupled faces as internal ones (but only once)
426  const polyBoundaryMesh& patches = mesh.boundaryMesh();
427 
428  forAll(patches, patchi)
429  {
430  if
431  (
432  patches[patchi].coupled()
433  && refCast<const coupledPolyPatch>(patches[patchi]).owner()
434  )
435  {
436  const coupledPolyPatch& pp =
437  refCast<const coupledPolyPatch>(patches[patchi]);
438 
439  const vectorField::subField faceCentres = pp.faceCentres();
440 
441  forAll(pp, i)
442  {
443  const face& f = pp[i];
444  const point& fc = faceCentres[i];
445 
446  forAll(f, fp)
447  {
448  weightedPosition& wp = globalSum[f[fp]];
449  wp.first() += 1.0;
450  wp.second() += fc;
451  }
452  }
453  }
454  }
455 
456  // Add coupled contributions
458 
459  avgInternal.setSize(meshPoints.size());
460 
461  forAll(avgInternal, patchPointi)
462  {
463  label meshPointi = meshPoints[patchPointi];
464  const weightedPosition& wp = globalSum[meshPointi];
465 
466  avgInternal[patchPointi].first() = wp.first();
467  if (mag(wp.first()) < VSMALL)
468  {
469  // Set to zero?
470  avgInternal[patchPointi].second() = wp.second();
471  }
472  else
473  {
474  avgInternal[patchPointi].second() = wp.second()/wp.first();
475  }
476  }
477  }
478 
479 
480  // Precalculate any cell using mesh point (replacement of pointCells()[])
481  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
482 
483  labelList anyCell(mesh.nPoints(), -1);
484  forAll(mesh.faceOwner(), facei)
485  {
486  label own = mesh.faceOwner()[facei];
487  const face& f = mesh.faces()[facei];
488 
489  forAll(f, fp)
490  {
491  anyCell[f[fp]] = own;
492  }
493  }
494 
495 
496  // Displacement to calculate.
497  auto tpatchDisp = tmp<pointField>::New(meshPoints.size(), Zero);
498  auto& patchDisp = tpatchDisp.ref();
499 
500  forAll(pointFaces, i)
501  {
502  label meshPointi = meshPoints[i];
503  const point& currentPos = pp.points()[meshPointi];
504 
505  // Now we have the two average points and their counts:
506  // avgBoundary and avgInternal
507  // Do some blending between the two.
508  // Note: the following section has some reasoning behind it but the
509  // blending factors can be experimented with.
510 
511  const weightedPosition& internal = avgInternal[i];
512  const weightedPosition& boundary = avgBoundary[i];
513 
514  point newPos;
515 
516  if (!nonManifoldPoint.test(i))
517  {
518  // Points that are manifold. Weight the internal and boundary
519  // by their number of faces and blend with
520  scalar internalBlend = 0.1;
521  scalar blend = 0.1;
522 
523  point avgPos =
524  (
525  internalBlend*internal.first()*internal.second()
526  +(1-internalBlend)*boundary.first()*boundary.second()
527  )
528  / (
529  internalBlend*internal.first()
530  +(1-internalBlend)*boundary.first()
531  );
532 
533  newPos = (1-blend)*avgPos + blend*currentPos;
534  }
535  else if (internal.first() == 0)
536  {
537  // Non-manifold without internal faces. Use any connected cell
538  // as internal point instead. Use precalculated any cell to avoid
539  // e.g. pointCells()[meshPointi][0]
540 
541  const point& cc = mesh.cellCentres()[anyCell[meshPointi]];
542 
543  scalar cellCBlend = 0.8;
544  scalar blend = 0.1;
545 
546  point avgPos = (1-cellCBlend)*boundary.second() + cellCBlend*cc;
547 
548  newPos = (1-blend)*avgPos + blend*currentPos;
549  }
550  else
551  {
552  // Non-manifold point with internal faces connected to them
553  scalar internalBlend = 0.9;
554  scalar blend = 0.1;
555 
556  point avgPos =
557  internalBlend*internal.second()
558  + (1-internalBlend)*boundary.second();
559 
560  newPos = (1-blend)*avgPos + blend*currentPos;
561  }
562 
563  patchDisp[i] = newPos - currentPos;
564  }
565 
566  return tpatchDisp;
567 }
568 //XXXXXXX
569 //Foam::tmp<Foam::pointField> Foam::snappySnapDriver::avg
570 //(
571 // const indirectPrimitivePatch& pp,
572 // const pointField& localPoints
573 //)
574 //{
575 // const labelListList& pointEdges = pp.pointEdges();
576 // const edgeList& edges = pp.edges();
577 //
578 // auto tavg = tmp<pointField>::New(pointEdges.size(), Zero);
579 // auto& avg = tavg.ref();
580 //
581 // forAll(pointEdges, verti)
582 // {
583 // vector& avgPos = avg[verti];
584 //
585 // const labelList& pEdges = pointEdges[verti];
586 //
587 // forAll(pEdges, myEdgei)
588 // {
589 // const edge& e = edges[pEdges[myEdgei]];
590 //
591 // label otherVerti = e.otherVertex(verti);
592 //
593 // avgPos += localPoints[otherVerti];
594 // }
595 //
596 // avgPos /= pEdges.size();
597 // }
598 // return tavg;
599 //}
600 //Foam::tmp<Foam::pointField>
601 //Foam::snappySnapDriver::smoothLambdaMuPatchDisplacement
602 //(
603 // const motionSmoother& meshMover,
604 // const List<labelPair>& baffles
605 //)
606 //{
607 // const indirectPrimitivePatch& pp = meshMover.patch();
608 // pointField newLocalPoints(pp.localPoints());
609 //
610 // const label iters = 90;
611 // const scalar lambda = 0.33;
612 // const scalar mu = 0.34;
613 //
614 // for (label iter = 0; iter < iters; iter++)
615 // {
616 // // Lambda
617 // newLocalPoints =
618 // (1 - lambda)*newLocalPoints
619 // + lambda*avg(pp, newLocalPoints);
620 //
621 // // Mu
622 // newLocalPoints =
623 // (1 + mu)*newLocalPoints
624 // - mu*avg(pp, newLocalPoints);
625 // }
626 // return newLocalPoints-pp.localPoints();
627 //}
628 //XXXXXXX
629 
630 
631 Foam::tmp<Foam::scalarField> Foam::snappySnapDriver::edgePatchDist
632 (
633  const pointMesh& pMesh,
635 )
636 {
637  const polyMesh& mesh = pMesh();
638 
639  // Set initial changed points to all the patch points
640  List<pointEdgePoint> wallInfo(pp.nPoints());
641 
642  forAll(pp.localPoints(), ppi)
643  {
644  wallInfo[ppi] = pointEdgePoint(pp.localPoints()[ppi], 0.0);
645  }
646 
647  // Current info on points
648  List<pointEdgePoint> allPointInfo(mesh.nPoints());
649 
650  // Current info on edges
651  List<pointEdgePoint> allEdgeInfo(mesh.nEdges());
652 
653  PointEdgeWave<pointEdgePoint> wallCalc
654  (
655  mesh,
656  pp.meshPoints(),
657  wallInfo,
658 
659  allPointInfo,
660  allEdgeInfo,
661  mesh.globalData().nTotalPoints() // max iterations
662  );
663 
664  // Copy edge values into scalarField
665  auto tedgeDist = tmp<scalarField>::New(mesh.nEdges());
666  auto& edgeDist = tedgeDist.ref();
667 
668  forAll(allEdgeInfo, edgei)
669  {
670  edgeDist[edgei] = Foam::sqrt(allEdgeInfo[edgei].distSqr());
671  }
672 
673  return tedgeDist;
674 }
675 
676 
677 void Foam::snappySnapDriver::dumpMove
678 (
679  const fileName& fName,
680  const pointField& meshPts,
681  const pointField& surfPts
682 )
683 {
684  // Dump direction of growth into file
685  Info<< "Dumping move direction to " << fName << endl;
686 
687  OFstream nearestStream(fName);
688 
689  label verti = 0;
690 
691  forAll(meshPts, pti)
692  {
693  meshTools::writeOBJ(nearestStream, meshPts[pti]);
694  verti++;
695 
696  meshTools::writeOBJ(nearestStream, surfPts[pti]);
697  verti++;
698 
699  nearestStream<< "l " << verti-1 << ' ' << verti << nl;
700  }
701 }
702 
703 
704 // Check whether all displacement vectors point outwards of patch. Return true
705 // if so.
706 bool Foam::snappySnapDriver::outwardsDisplacement
707 (
708  const indirectPrimitivePatch& pp,
709  const vectorField& patchDisp
710 )
711 {
712  const vectorField& faceNormals = pp.faceNormals();
713  const labelListList& pointFaces = pp.pointFaces();
714 
715  forAll(pointFaces, pointi)
716  {
717  const labelList& pFaces = pointFaces[pointi];
718 
719  vector disp(patchDisp[pointi]);
720 
721  scalar magDisp = mag(disp);
722 
723  if (magDisp > SMALL)
724  {
725  disp /= magDisp;
726 
727  bool outwards = meshTools::visNormal(disp, faceNormals, pFaces);
728 
729  if (!outwards)
730  {
731  Warning<< "Displacement " << patchDisp[pointi]
732  << " at mesh point " << pp.meshPoints()[pointi]
733  << " coord " << pp.points()[pp.meshPoints()[pointi]]
734  << " points through the surrounding patch faces" << endl;
735  return false;
736  }
737  }
738  else
739  {
740  //? Displacement small but in wrong direction. Would probably be ok.
741  }
742  }
743  return true;
744 }
745 
746 
747 void Foam::snappySnapDriver::freezeExposedPoints
748 (
749  const meshRefinement& meshRefiner,
750  const word& fzName, // faceZone name
751  const word& pzName, // pointZone name
752  const indirectPrimitivePatch& outside,
753  vectorField& outsideDisp
754 )
755 {
756  const fvMesh& mesh = meshRefiner.mesh();
757  const pointZoneMesh& pointZones = mesh.pointZones();
758 
759  bitSet isFrozenPoint(mesh.nPoints());
760 
761  // Add frozen points
762  const label pointZonei = pointZones.findZoneID(pzName);
763  if (pointZonei != -1)
764  {
765  isFrozenPoint.set(pointZones[pointZonei]);
766  }
767 
768  // Add (inside) points of frozen faces
769  const faceZoneMesh& faceZones = mesh.faceZones();
770  const label faceZonei = faceZones.findZoneID(fzName);
771  if (faceZonei != -1)
772  {
774  (
775  UIndirectList<face>(mesh.faces(), faceZones[faceZonei]),
776  mesh.points()
777  );
778 
779  // Count number of faces per edge
780  const labelList nEdgeFaces(meshRefiner.countEdgeFaces(pp));
781 
782  // Freeze all internal points
783  forAll(nEdgeFaces, edgei)
784  {
785  if (nEdgeFaces[edgei] != 1)
786  {
787  const edge& e = pp.edges()[edgei];
788  isFrozenPoint.set(pp.meshPoints()[e[0]]);
789  isFrozenPoint.set(pp.meshPoints()[e[1]]);
790  }
791  }
792  }
793 
795  (
796  mesh,
797  isFrozenPoint,
798  orEqOp<unsigned int>(),
799  0u
800  );
801 
802  for (const label pointi : isFrozenPoint)
803  {
804  const auto iter = outside.meshPointMap().find(pointi);
805  if (iter.good())
806  {
807  outsideDisp[iter.val()] = Zero;
808  }
809  }
810 }
811 
812 
813 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
814 
815 Foam::snappySnapDriver::snappySnapDriver
816 (
817  meshRefinement& meshRefiner,
818  const labelList& globalToMasterPatch,
819  const labelList& globalToSlavePatch,
820  const bool dryRun
821 )
822 :
823  meshRefiner_(meshRefiner),
824  globalToMasterPatch_(globalToMasterPatch),
825  globalToSlavePatch_(globalToSlavePatch),
826  dryRun_(dryRun)
827 {}
828 
829 
830 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
831 
833 (
834  const fvMesh& mesh,
835  const snapParameters& snapParams,
837 )
838 {
839  const edgeList& edges = pp.edges();
840  const labelListList& pointEdges = pp.pointEdges();
841  const pointField& localPoints = pp.localPoints();
842 
843  scalarField maxEdgeLen(localPoints.size(), -GREAT);
844 
845  forAll(pointEdges, pointi)
846  {
847  const labelList& pEdges = pointEdges[pointi];
848 
849  forAll(pEdges, pEdgei)
850  {
851  const edge& e = edges[pEdges[pEdgei]];
852 
853  scalar len = e.mag(localPoints);
854 
855  maxEdgeLen[pointi] = max(maxEdgeLen[pointi], len);
856  }
857  }
858 
860  (
861  mesh,
862  pp.meshPoints(),
863  maxEdgeLen,
864  maxEqOp<scalar>(), // combine op
865  -GREAT // null value
866  );
868  return scalarField(snapParams.snapTol()*maxEdgeLen);
869 }
870 
871 
873 (
874  const meshRefinement& meshRefiner,
875  const snapParameters& snapParams,
876  const label nInitErrors,
877  const List<labelPair>& baffles,
878  motionSmoother& meshMover
879 )
880 {
881  addProfiling(smooth, "snappyHexMesh::snap::smoothing");
882  const fvMesh& mesh = meshRefiner.mesh();
883 
884  labelList checkFaces;
885 
886  if (snapParams.nSmoothInternal() > 0)
887  {
888  Info<< "Smoothing patch and internal points ..." << endl;
889  }
890  else
891  {
892  Info<< "Smoothing patch points ..." << endl;
893  }
894 
895  vectorField& pointDisp = meshMover.pointDisplacement().primitiveFieldRef();
896 
897  for
898  (
899  label smoothIter = 0;
900  smoothIter < snapParams.nSmoothPatch();
901  smoothIter++
902  )
903  {
904  Info<< "Smoothing iteration " << smoothIter << endl;
905  checkFaces.setSize(mesh.nFaces());
906  forAll(checkFaces, facei)
907  {
908  checkFaces[facei] = facei;
909  }
910 
911  // If enabled smooth the internal points
912  if (snapParams.nSmoothInternal() > smoothIter)
913  {
914  // Override values on internal points on refinement interfaces
915  pointDisp = smoothInternalDisplacement(meshRefiner, meshMover);
916  }
917 
918  // Smooth the patch points
919  pointField patchDisp(smoothPatchDisplacement(meshMover, baffles));
920  //pointField patchDisp
921  //(
922  // smoothLambdaMuPatchDisplacement(meshMover, baffles)
923  //);
924 
925  // Take over patch displacement as boundary condition on
926  // pointDisplacement
927  meshMover.setDisplacement(patchDisp);
928 
929  // Start off from current mesh.points()
930  meshMover.correct();
931 
932  scalar oldErrorReduction = -1;
933 
934  for (label snapIter = 0; snapIter < 2*snapParams.nSnap(); snapIter++)
935  {
936  Info<< nl << "Scaling iteration " << snapIter << endl;
937 
938  if (snapIter == snapParams.nSnap())
939  {
940  Info<< "Displacement scaling for error reduction set to 0."
941  << endl;
942  oldErrorReduction = meshMover.setErrorReduction(0.0);
943  }
944 
945  // Try to adapt mesh to obtain displacement by smoothly
946  // decreasing displacement at error locations.
947  if (meshMover.scaleMesh(checkFaces, baffles, true, nInitErrors))
948  {
949  Info<< "Successfully moved mesh" << endl;
950  break;
951  }
952  }
953 
954  if (oldErrorReduction >= 0)
955  {
956  meshMover.setErrorReduction(oldErrorReduction);
957  }
958  Info<< endl;
959  }
960 
961 
962  // The current mesh is the starting mesh to smooth from.
963  meshMover.correct();
964 
966  {
967  const_cast<Time&>(mesh.time())++;
968  Info<< "Writing patch smoothed mesh to time "
969  << meshRefiner.timeName() << '.' << endl;
970  meshRefiner.write
971  (
974  (
977  ),
978  mesh.time().path()/meshRefiner.timeName()
979  );
980  Info<< "Dumped mesh in = "
981  << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl;
982  }
983 
984  Info<< "Patch points smoothed in = "
985  << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl;
986 }
987 
988 
989 // Get (pp-local) indices of points that are both on zone and on patched surface
990 void Foam::snappySnapDriver::getZoneSurfacePoints
991 (
992  const fvMesh& mesh,
993  const indirectPrimitivePatch& pp,
994  const word& zoneName,
995 
996  bitSet& pointOnZone
997 )
998 {
999  label zonei = mesh.faceZones().findZoneID(zoneName);
1000 
1001  if (zonei == -1)
1002  {
1004  << "Cannot find zone " << zoneName
1005  << exit(FatalError);
1006  }
1007 
1008  const faceZone& fZone = mesh.faceZones()[zonei];
1009 
1010 
1011  // Could use PrimitivePatch & localFaces to extract points but might just
1012  // as well do it ourselves.
1013 
1014  forAll(fZone, i)
1015  {
1016  const face& f = mesh.faces()[fZone[i]];
1017 
1018  forAll(f, fp)
1019  {
1020  label meshPointi = f[fp];
1021 
1022  const auto iter = pp.meshPointMap().cfind(meshPointi);
1023 
1024  if (iter.good())
1025  {
1026  const label pointi = iter.val();
1027  pointOnZone[pointi] = true;
1028  }
1029  }
1030  }
1031 }
1032 
1033 
1035 (
1036  const fvMesh& mesh,
1037  const indirectPrimitivePatch& pp
1038 )
1039 {
1040  const labelListList& pointFaces = pp.pointFaces();
1041 
1042  Field<weightedPosition> avgBoundary
1043  (
1044  pointFaces.size(),
1046  );
1047 
1048  forAll(pointFaces, pointi)
1049  {
1050  const labelList& pFaces = pointFaces[pointi];
1051 
1052  avgBoundary[pointi].first() = pFaces.size();
1053  forAll(pFaces, pfi)
1054  {
1055  label facei = pFaces[pfi];
1056  label own = mesh.faceOwner()[pp.addressing()[facei]];
1057  avgBoundary[pointi].second() += mesh.cellCentres()[own];
1058  }
1059  }
1060 
1061  // Add coupled contributions
1063 
1064  auto tavgBoundary = tmp<pointField>::New(avgBoundary.size());
1065  weightedPosition::getPoints(avgBoundary, tavgBoundary.ref());
1066 
1067  return tavgBoundary;
1068 }
1069 
1070 
1071 //Foam::tmp<Foam::scalarField> Foam::snappySnapDriver::calcEdgeLen
1072 //(
1073 // const indirectPrimitivePatch& pp
1074 //) const
1075 //{
1076 // // Get local edge length based on refinement level
1077 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1078 // // (Ripped from snappyLayerDriver)
1079 //
1080 // auto tedgeLen = tmp<scalarField>::New(pp.nPoints());
1081 // auto& edgeLen = tedgeLen.ref();
1082 // {
1083 // const fvMesh& mesh = meshRefiner_.mesh();
1084 // const scalar edge0Len = meshRefiner_.meshCutter().level0EdgeLength();
1085 // const labelList& cellLevel = meshRefiner_.meshCutter().cellLevel();
1086 //
1087 // labelList maxPointLevel(pp.nPoints(), labelMin);
1088 //
1089 // forAll(pp, i)
1090 // {
1091 // label ownLevel = cellLevel[mesh.faceOwner()[pp.addressing()[i]]];
1092 // const face& f = pp.localFaces()[i];
1093 // forAll(f, fp)
1094 // {
1095 // maxPointLevel[f[fp]] = max(maxPointLevel[f[fp]], ownLevel);
1096 // }
1097 // }
1098 //
1099 // syncTools::syncPointList
1100 // (
1101 // mesh,
1102 // pp.meshPoints(),
1103 // maxPointLevel,
1104 // maxEqOp<label>(),
1105 // labelMin // null value
1106 // );
1107 //
1108 //
1109 // forAll(maxPointLevel, pointi)
1110 // {
1111 // // Find undistorted edge size for this level.
1112 // edgeLen[pointi] = edge0Len/(1<<maxPointLevel[pointi]);
1113 // }
1114 // }
1115 // return tedgeLen;
1116 //}
1117 
1118 
1120 (
1121  const scalar planarCos,
1122  const indirectPrimitivePatch& pp,
1123  const pointField& localPoints,
1124  const pointField& nearestPoint,
1125  const vectorField& nearestNormal,
1126 
1127  vectorField& disp
1128 ) const
1129 {
1130  Info<< "Detecting near surfaces ..." << endl;
1131 
1132  const labelList& meshPoints = pp.meshPoints();
1133  const refinementSurfaces& surfaces = meshRefiner_.surfaces();
1134  const fvMesh& mesh = meshRefiner_.mesh();
1135 
1137  //const scalarField edgeLen(calcEdgeLen(pp));
1138  //
1141  //
1142  //{
1143  // const vector n = normalised(vector::one);
1144  //
1145  // pointField start(14*pp.nPoints());
1146  // pointField end(start.size());
1147  //
1148  // label rayi = 0;
1149  // forAll(localPoints, pointi)
1150  // {
1151  // const point& pt = localPoints[pointi];
1152  //
1153  // // Along coordinate axes
1154  //
1155  // {
1156  // start[rayi] = pt;
1157  // point& endPt = end[rayi++];
1158  // endPt = pt;
1159  // endPt.x() -= edgeLen[pointi];
1160  // }
1161  // {
1162  // start[rayi] = pt;
1163  // point& endPt = end[rayi++];
1164  // endPt = pt;
1165  // endPt.x() += edgeLen[pointi];
1166  // }
1167  // {
1168  // start[rayi] = pt;
1169  // point& endPt = end[rayi++];
1170  // endPt = pt;
1171  // endPt.y() -= edgeLen[pointi];
1172  // }
1173  // {
1174  // start[rayi] = pt;
1175  // point& endPt = end[rayi++];
1176  // endPt = pt;
1177  // endPt.y() += edgeLen[pointi];
1178  // }
1179  // {
1180  // start[rayi] = pt;
1181  // point& endPt = end[rayi++];
1182  // endPt = pt;
1183  // endPt.z() -= edgeLen[pointi];
1184  // }
1185  // {
1186  // start[rayi] = pt;
1187  // point& endPt = end[rayi++];
1188  // endPt = pt;
1189  // endPt.z() += edgeLen[pointi];
1190  // }
1191  //
1192  // // At 45 degrees
1193  //
1194  // const vector vec(edgeLen[pointi]*n);
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  // start[rayi] = pt;
1222  // point& endPt = end[rayi++];
1223  // endPt = pt;
1224  // endPt.x() -= vec.x();
1225  // endPt.y() -= vec.y();
1226  // endPt.z() += vec.z();
1227  // }
1228  // {
1229  // start[rayi] = pt;
1230  // point& endPt = end[rayi++];
1231  // endPt = pt;
1232  // endPt.x() += vec.x();
1233  // endPt.y() += vec.y();
1234  // endPt.z() -= vec.z();
1235  // }
1236  // {
1237  // start[rayi] = pt;
1238  // point& endPt = end[rayi++];
1239  // endPt = pt;
1240  // endPt.x() -= vec.x();
1241  // endPt.y() += vec.y();
1242  // endPt.z() -= vec.z();
1243  // }
1244  // {
1245  // start[rayi] = pt;
1246  // point& endPt = end[rayi++];
1247  // endPt = pt;
1248  // endPt.x() += vec.x();
1249  // endPt.y() -= vec.y();
1250  // endPt.z() -= vec.z();
1251  // }
1252  // {
1253  // start[rayi] = pt;
1254  // point& endPt = end[rayi++];
1255  // endPt = pt;
1256  // endPt.x() -= vec.x();
1257  // endPt.y() -= vec.y();
1258  // endPt.z() -= vec.z();
1259  // }
1260  // }
1261  //
1262  // labelList surface1;
1263  // List<pointIndexHit> hit1;
1264  // labelList region1;
1265  // vectorField normal1;
1266  //
1267  // labelList surface2;
1268  // List<pointIndexHit> hit2;
1269  // labelList region2;
1270  // vectorField normal2;
1271  // surfaces.findNearestIntersection
1272  // (
1273  // unzonedSurfaces, // surfacesToTest,
1274  // start,
1275  // end,
1276  //
1277  // surface1,
1278  // hit1,
1279  // region1,
1280  // normal1,
1281  //
1282  // surface2,
1283  // hit2,
1284  // region2,
1285  // normal2
1286  // );
1287  //
1288  // // All intersections
1289  // {
1290  // OBJstream str
1291  // (
1292  // mesh.time().path()
1293  // / "surfaceHits_" + meshRefiner_.timeName() + ".obj"
1294  // );
1295  //
1296  // Info<< "Dumping intersections with rays to " << str.name()
1297  // << endl;
1298  //
1299  // forAll(hit1, i)
1300  // {
1301  // if (hit1[i].hit())
1302  // {
1303  // str.writeLine(start[i], hit1[i].point());
1304  // }
1305  // if (hit2[i].hit())
1306  // {
1307  // str.writeLine(start[i], hit2[i].point());
1308  // }
1309  // }
1310  // }
1311  //
1312  // // Co-planar intersections
1313  // {
1314  // OBJstream str
1315  // (
1316  // mesh.time().path()
1317  // / "coplanarHits_" + meshRefiner_.timeName() + ".obj"
1318  // );
1319  //
1320  // Info<< "Dumping intersections with co-planar surfaces to "
1321  // << str.name() << endl;
1322  //
1323  // forAll(localPoints, pointi)
1324  // {
1325  // bool hasNormal = false;
1326  // point surfPointA;
1327  // vector surfNormalA;
1328  // point surfPointB;
1329  // vector surfNormalB;
1330  //
1331  // bool isCoplanar = false;
1332  //
1333  // label rayi = 14*pointi;
1334  // for (label i = 0; i < 14; i++)
1335  // {
1336  // if (hit1[rayi].hit())
1337  // {
1338  // const point& pt = hit1[rayi].point();
1339  // const vector& n = normal1[rayi];
1340  //
1341  // if (!hasNormal)
1342  // {
1343  // hasNormal = true;
1344  // surfPointA = pt;
1345  // surfNormalA = n;
1346  // }
1347  // else
1348  // {
1349  // if
1350  // (
1351  // meshRefiner_.isGap
1352  // (
1353  // planarCos,
1354  // surfPointA,
1355  // surfNormalA,
1356  // pt,
1357  // n
1358  // )
1359  // )
1360  // {
1361  // isCoplanar = true;
1362  // surfPointB = pt;
1363  // surfNormalB = n;
1364  // break;
1365  // }
1366  // }
1367  // }
1368  // if (hit2[rayi].hit())
1369  // {
1370  // const point& pt = hit2[rayi].point();
1371  // const vector& n = normal2[rayi];
1372  //
1373  // if (!hasNormal)
1374  // {
1375  // hasNormal = true;
1376  // surfPointA = pt;
1377  // surfNormalA = n;
1378  // }
1379  // else
1380  // {
1381  // if
1382  // (
1383  // meshRefiner_.isGap
1384  // (
1385  // planarCos,
1386  // surfPointA,
1387  // surfNormalA,
1388  // pt,
1389  // n
1390  // )
1391  // )
1392  // {
1393  // isCoplanar = true;
1394  // surfPointB = pt;
1395  // surfNormalB = n;
1396  // break;
1397  // }
1398  // }
1399  // }
1400  //
1401  // rayi++;
1402  // }
1403  //
1404  // if (isCoplanar)
1405  // {
1406  // str.writeLine(surfPointA, surfPointB);
1407  // }
1408  // }
1409  // }
1410  //}
1411 
1412 
1413  const pointField avgCc(avgCellCentres(mesh, pp));
1414 
1415  // Construct rays through localPoints to beyond cell centre
1416  pointField start(pp.nPoints());
1417  pointField end(pp.nPoints());
1418  forAll(localPoints, pointi)
1419  {
1420  const point& pt = localPoints[pointi];
1421  const vector d = 2*(avgCc[pointi]-pt);
1422  start[pointi] = pt - d;
1423  end[pointi] = pt + d;
1424  }
1425 
1426 
1427  autoPtr<OBJstream> gapStr;
1429  {
1430  gapStr.reset
1431  (
1432  new OBJstream
1433  (
1434  mesh.time().path()
1435  / "detectNearSurfaces_" + meshRefiner_.timeName() + ".obj"
1436  )
1437  );
1438  }
1439 
1440 
1441  const bitSet isPatchMasterPoint
1442  (
1444  (
1445  mesh,
1446  meshPoints
1447  )
1448  );
1449 
1450  label nOverride = 0;
1451 
1452  // 1. All points to non-interface surfaces
1453  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1454  {
1455  const labelList unzonedSurfaces =
1457  (
1458  meshRefiner_.surfaces().surfZones()
1459  );
1460 
1461  // Do intersection test
1462  labelList surface1;
1463  List<pointIndexHit> hit1;
1464  labelList region1;
1465  vectorField normal1;
1466 
1467  labelList surface2;
1468  List<pointIndexHit> hit2;
1469  labelList region2;
1470  vectorField normal2;
1471  surfaces.findNearestIntersection
1472  (
1473  unzonedSurfaces,
1474  start,
1475  end,
1476 
1477  surface1,
1478  hit1,
1479  region1,
1480  normal1,
1481 
1482  surface2,
1483  hit2,
1484  region2,
1485  normal2
1486  );
1487 
1488 
1489  forAll(localPoints, pointi)
1490  {
1491  // Current location
1492  const point& pt = localPoints[pointi];
1493 
1494  bool override = false;
1495 
1496  //if (hit1[pointi].hit())
1497  //{
1498  // if
1499  // (
1500  // meshRefiner_.isGap
1501  // (
1502  // planarCos,
1503  // nearestPoint[pointi],
1504  // nearestNormal[pointi],
1505  // hit1[pointi].point(),
1506  // normal1[pointi]
1507  // )
1508  // )
1509  // {
1510  // disp[pointi] = hit1[pointi].point()-pt;
1511  // override = true;
1512  // }
1513  //}
1514  //if (hit2[pointi].hit())
1515  //{
1516  // if
1517  // (
1518  // meshRefiner_.isGap
1519  // (
1520  // planarCos,
1521  // nearestPoint[pointi],
1522  // nearestNormal[pointi],
1523  // hit2[pointi].point(),
1524  // normal2[pointi]
1525  // )
1526  // )
1527  // {
1528  // disp[pointi] = hit2[pointi].point()-pt;
1529  // override = true;
1530  // }
1531  //}
1532 
1533  if (hit1[pointi].hit() && hit2[pointi].hit())
1534  {
1535  if
1536  (
1537  meshRefiner_.isGap
1538  (
1539  planarCos,
1540  hit1[pointi].point(),
1541  normal1[pointi],
1542  hit2[pointi].point(),
1543  normal2[pointi]
1544  )
1545  )
1546  {
1547  // TBD: check if the attraction (to nearest) would attract
1548  // good enough and not override attraction
1549 
1550  if (gapStr)
1551  {
1552  gapStr().writeLine(pt, hit2[pointi].point());
1553  }
1554 
1555  // Choose hit2 : nearest to end point (so inside the domain)
1556  disp[pointi] = hit2[pointi].point()-pt;
1557  override = true;
1558  }
1559  }
1560 
1561  if (override && isPatchMasterPoint[pointi])
1562  {
1563  nOverride++;
1564  }
1565  }
1566  }
1567 
1568 
1569  // 2. All points on zones to their respective surface
1570  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1571 
1572  {
1573  // Surfaces with zone information
1574  const PtrList<surfaceZonesInfo>& surfZones = surfaces.surfZones();
1575 
1576  const labelList zonedSurfaces = surfaceZonesInfo::getNamedSurfaces
1577  (
1578  surfZones
1579  );
1580 
1581  forAll(zonedSurfaces, i)
1582  {
1583  label zoneSurfi = zonedSurfaces[i];
1584  const labelList surfacesToTest(1, zoneSurfi);
1585 
1586  const wordList& faceZoneNames =
1587  surfZones[zoneSurfi].faceZoneNames();
1588  forAll(faceZoneNames, namei)
1589  {
1590  const word& faceZoneName = faceZoneNames[namei];
1591 
1592  // Get indices of points both on faceZone and on pp.
1593  bitSet pointOnZone(pp.nPoints());
1594  getZoneSurfacePoints
1595  (
1596  mesh,
1597  pp,
1598  faceZoneName,
1599  pointOnZone
1600  );
1601  const labelList zonePointIndices(pointOnZone.toc());
1602 
1603  // Do intersection test
1604  labelList surface1;
1605  List<pointIndexHit> hit1;
1606  labelList region1;
1607  vectorField normal1;
1608 
1609  labelList surface2;
1610  List<pointIndexHit> hit2;
1611  labelList region2;
1612  vectorField normal2;
1613  surfaces.findNearestIntersection
1614  (
1615  surfacesToTest,
1616  pointField(start, zonePointIndices),
1617  pointField(end, zonePointIndices),
1618 
1619  surface1,
1620  hit1,
1621  region1,
1622  normal1,
1623 
1624  surface2,
1625  hit2,
1626  region2,
1627  normal2
1628  );
1629 
1630 
1631  forAll(hit1, i)
1632  {
1633  label pointi = zonePointIndices[i];
1634 
1635  // Current location
1636  const point& pt = localPoints[pointi];
1637 
1638  bool override = false;
1639 
1640  //if (hit1[i].hit())
1641  //{
1642  // if
1643  // (
1644  // meshRefiner_.isGap
1645  // (
1646  // planarCos,
1647  // nearestPoint[pointi],
1648  // nearestNormal[pointi],
1649  // hit1[i].point(),
1650  // normal1[i]
1651  // )
1652  // )
1653  // {
1654  // disp[pointi] = hit1[i].point()-pt;
1655  // override = true;
1656  // }
1657  //}
1658  //if (hit2[i].hit())
1659  //{
1660  // if
1661  // (
1662  // meshRefiner_.isGap
1663  // (
1664  // planarCos,
1665  // nearestPoint[pointi],
1666  // nearestNormal[pointi],
1667  // hit2[i].point(),
1668  // normal2[i]
1669  // )
1670  // )
1671  // {
1672  // disp[pointi] = hit2[i].point()-pt;
1673  // override = true;
1674  // }
1675  //}
1676 
1677  if (hit1[i].hit() && hit2[i].hit())
1678  {
1679  if
1680  (
1681  meshRefiner_.isGap
1682  (
1683  planarCos,
1684  hit1[i].point(),
1685  normal1[i],
1686  hit2[i].point(),
1687  normal2[i]
1688  )
1689  )
1690  {
1691  if (gapStr)
1692  {
1693  gapStr().writeLine(pt, hit2[i].point());
1694  }
1695 
1696  disp[pointi] = hit2[i].point()-pt;
1697  override = true;
1698  }
1699  }
1700 
1701  if (override && isPatchMasterPoint[pointi])
1702  {
1703  nOverride++;
1704  }
1705  }
1706  }
1707  }
1708  }
1709 
1710  Info<< "Overriding nearest with intersection of close gaps at "
1711  << returnReduce(nOverride, sumOp<label>())
1712  << " out of " << returnReduce(pp.nPoints(), sumOp<label>())
1713  << " points." << endl;
1714 }
1715 
1716 
1717 void Foam::snappySnapDriver::calcNearestSurface
1718 (
1719  const refinementSurfaces& surfaces,
1720 
1721  const labelList& surfacesToTest,
1722  const labelListList& regionsToTest,
1723 
1724  const pointField& localPoints,
1725  const labelList& zonePointIndices,
1726 
1727  scalarField& minSnapDist,
1728  labelList& snapSurf,
1729  vectorField& patchDisp,
1730 
1731  // Optional: nearest point, normal
1732  pointField& nearestPoint,
1733  vectorField& nearestNormal
1734 )
1735 {
1736  // Find nearest for points both on faceZone and pp.
1737  List<pointIndexHit> hitInfo;
1738  labelList hitSurface;
1739 
1740  if (nearestNormal.size() == localPoints.size())
1741  {
1742  labelList hitRegion;
1743  vectorField hitNormal;
1744  surfaces.findNearestRegion
1745  (
1746  surfacesToTest,
1747  regionsToTest,
1748 
1749  pointField(localPoints, zonePointIndices),
1750  sqr(scalarField(minSnapDist, zonePointIndices)),
1751 
1752  hitSurface,
1753  hitInfo,
1754  hitRegion,
1755  hitNormal
1756  );
1757 
1758  forAll(hitInfo, i)
1759  {
1760  if (hitInfo[i].hit())
1761  {
1762  label pointi = zonePointIndices[i];
1763  nearestPoint[pointi] = hitInfo[i].point();
1764  nearestNormal[pointi] = hitNormal[i];
1765  }
1766  }
1767  }
1768  else
1769  {
1770  surfaces.findNearest
1771  (
1772  surfacesToTest,
1773  regionsToTest,
1774 
1775  pointField(localPoints, zonePointIndices),
1776  sqr(scalarField(minSnapDist, zonePointIndices)),
1777 
1778  hitSurface,
1779  hitInfo
1780  );
1781  }
1782 
1783  forAll(hitInfo, i)
1784  {
1785  if (hitInfo[i].hit())
1786  {
1787  label pointi = zonePointIndices[i];
1788 
1789  patchDisp[pointi] = hitInfo[i].point() - localPoints[pointi];
1790  minSnapDist[pointi] = mag(patchDisp[pointi]);
1791  snapSurf[pointi] = hitSurface[i];
1792  }
1793  }
1794 }
1795 
1796 
1797 Foam::vectorField Foam::snappySnapDriver::calcNearestSurface
1798 (
1799  const bool strictRegionSnap,
1800  const meshRefinement& meshRefiner,
1801  const labelList& globalToMasterPatch,
1802  const labelList& globalToSlavePatch,
1803  const indirectPrimitivePatch& pp,
1804  const pointField& localPoints,
1805  const scalarField& snapDist,
1806  pointField& nearestPoint,
1807  vectorField& nearestNormal
1808 )
1809 {
1810  Info<< "Calculating patchDisplacement as distance to nearest surface"
1811  << " point ..." << endl;
1812  if (strictRegionSnap)
1813  {
1814  Info<< " non-zone points : attract to local region on surface only"
1815  << nl
1816  << " zone points : attract to local region on surface only"
1817  << nl
1818  << endl;
1819  }
1820  else
1821  {
1822  Info<< " non-zone points :"
1823  << " attract to nearest of all non-zone surfaces"
1824  << nl
1825  << " zone points : attract to zone surface only" << nl
1826  << endl;
1827  }
1828 
1829 
1830  const refinementSurfaces& surfaces = meshRefiner.surfaces();
1831  const fvMesh& mesh = meshRefiner.mesh();
1832 
1833  // Displacement per patch point
1834  vectorField patchDisp(localPoints.size(), Zero);
1835 
1836  if (returnReduceOr(localPoints.size()))
1837  {
1838  // Current surface snapped to. Used to check whether points have been
1839  // snapped at all
1840  labelList snapSurf(localPoints.size(), -1);
1841 
1842  // Current best snap distance (since point might be on multiple
1843  // regions)
1844  scalarField minSnapDist(snapDist);
1845 
1846 
1847  if (strictRegionSnap)
1848  {
1849  // Attract patch points to same region only
1850 
1851  forAll(surfaces.surfaces(), surfi)
1852  {
1853  label geomi = surfaces.surfaces()[surfi];
1854  label nRegions = surfaces.geometry()[geomi].regions().size();
1855 
1856  const labelList surfacesToTest(1, surfi);
1857 
1858  for (label regioni = 0; regioni < nRegions; regioni++)
1859  {
1860  label globali = surfaces.globalRegion(surfi, regioni);
1861  label masterPatchi = globalToMasterPatch[globali];
1862 
1863  // Get indices of points both on patch and on pp
1864  labelList zonePointIndices
1865  (
1866  getFacePoints
1867  (
1868  pp,
1869  mesh.boundaryMesh()[masterPatchi]
1870  )
1871  );
1872 
1873  calcNearestSurface
1874  (
1875  surfaces,
1876 
1877  surfacesToTest,
1878  labelListList(1, labelList(1, regioni)), //regionsToTest
1879 
1880  localPoints,
1881  zonePointIndices,
1882 
1883  minSnapDist,
1884  snapSurf,
1885  patchDisp,
1886 
1887  // Optional: nearest point, normal
1888  nearestPoint,
1889  nearestNormal
1890  );
1891 
1892  if (globalToSlavePatch[globali] != masterPatchi)
1893  {
1894  label slavePatchi = globalToSlavePatch[globali];
1895 
1896  // Get indices of points both on patch and on pp
1897  labelList zonePointIndices
1898  (
1899  getFacePoints
1900  (
1901  pp,
1902  mesh.boundaryMesh()[slavePatchi]
1903  )
1904  );
1905 
1906  calcNearestSurface
1907  (
1908  surfaces,
1909 
1910  surfacesToTest,
1911  labelListList(1, labelList(1, regioni)),
1912 
1913  localPoints,
1914  zonePointIndices,
1915 
1916  minSnapDist,
1917  snapSurf,
1918  patchDisp,
1919 
1920  // Optional: nearest point, normal
1921  nearestPoint,
1922  nearestNormal
1923  );
1924  }
1925  }
1926  }
1927  }
1928  else
1929  {
1930  // Divide surfaces into zoned and unzoned
1931  const labelList unzonedSurfaces =
1933  (
1934  meshRefiner.surfaces().surfZones()
1935  );
1936 
1937 
1938  // 1. All points to non-interface surfaces
1939  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1940 
1941  List<pointIndexHit> hitInfo;
1942  labelList hitSurface;
1943 
1944  if (nearestNormal.size() == localPoints.size())
1945  {
1946  labelList hitRegion;
1947  vectorField hitNormal;
1948  surfaces.findNearestRegion
1949  (
1950  unzonedSurfaces,
1951  localPoints,
1952  sqr(snapDist),
1953  hitSurface,
1954  hitInfo,
1955  hitRegion,
1956  hitNormal
1957  );
1958 
1959  forAll(hitInfo, pointi)
1960  {
1961  if (hitInfo[pointi].hit())
1962  {
1963  nearestPoint[pointi] = hitInfo[pointi].point();
1964  nearestNormal[pointi] = hitNormal[pointi];
1965  }
1966  }
1967  }
1968  else
1969  {
1970  surfaces.findNearest
1971  (
1972  unzonedSurfaces,
1973  localPoints,
1974  sqr(snapDist), // sqr of attract distance
1975  hitSurface,
1976  hitInfo
1977  );
1978  }
1979 
1980  forAll(hitInfo, pointi)
1981  {
1982  if (hitInfo[pointi].hit())
1983  {
1984  patchDisp[pointi] =
1985  hitInfo[pointi].point()
1986  - localPoints[pointi];
1987 
1988  snapSurf[pointi] = hitSurface[pointi];
1989  }
1990  }
1991 
1992 
1993  const labelList zonedSurfaces = surfaceZonesInfo::getNamedSurfaces
1994  (
1995  meshRefiner.surfaces().surfZones()
1996  );
1997 
1998 
1999  // 2. All points on zones to their respective surface
2000  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2001  // (ignoring faceZone subdivision)
2002 
2003  // Surfaces with zone information
2004  const PtrList<surfaceZonesInfo>& surfZones = surfaces.surfZones();
2005 
2006  forAll(zonedSurfaces, i)
2007  {
2008  label surfi = zonedSurfaces[i];
2009  const labelList surfacesToTest(1, surfi);
2010  const label geomi = surfaces.surfaces()[surfi];
2011  const label nRegions =
2012  surfaces.geometry()[geomi].regions().size();
2013 
2014  const wordList& faceZoneNames =
2015  surfZones[surfi].faceZoneNames();
2016 
2017  // Get indices of points both on any faceZone and on pp.
2018  bitSet pointOnZone(pp.nPoints());
2019  forAll(faceZoneNames, locali)
2020  {
2021  getZoneSurfacePoints
2022  (
2023  mesh,
2024  pp,
2025  faceZoneNames[locali],
2026  pointOnZone
2027  );
2028  }
2029  const labelList zonePointIndices(pointOnZone.toc());
2030 
2031  calcNearestSurface
2032  (
2033  surfaces,
2034 
2035  surfacesToTest,
2036  labelListList(1, identity(nRegions)),
2037 
2038  localPoints,
2039  zonePointIndices,
2040 
2041  minSnapDist,
2042  snapSurf,
2043  patchDisp,
2044 
2045  // Optional: nearest point, normal
2046  nearestPoint,
2047  nearestNormal
2048  );
2049  }
2050  }
2051 
2052 
2053  // Check if all points are being snapped
2054  forAll(snapSurf, pointi)
2055  {
2056  if (snapSurf[pointi] == -1)
2057  {
2058  static label nWarn = 0;
2059 
2060  if (nWarn < 100)
2061  {
2063  << "For point:" << pointi
2064  << " coordinate:" << localPoints[pointi]
2065  << " did not find any surface within:"
2066  << minSnapDist[pointi] << " metre." << endl;
2067  nWarn++;
2068  if (nWarn == 100)
2069  {
2071  << "Reached warning limit " << nWarn
2072  << ". Suppressing further warnings." << endl;
2073  }
2074  }
2075  }
2076  }
2077 
2078  {
2079  const bitSet isPatchMasterPoint
2080  (
2082  (
2083  mesh,
2084  pp.meshPoints()
2085  )
2086  );
2087 
2088  scalarField magDisp(mag(patchDisp));
2089 
2090  Info<< "Wanted displacement : average:"
2091  << meshRefinement::gAverage(isPatchMasterPoint, magDisp)
2092  << " min:" << gMin(magDisp)
2093  << " max:" << gMax(magDisp) << endl;
2094  }
2095  }
2096 
2097  Info<< "Calculated surface displacement in = "
2098  << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl;
2099 
2100 
2101  // Limit amount of movement. Can not happen for triSurfaceMesh but
2102  // can happen for some analytical shapes?
2103  forAll(patchDisp, patchPointi)
2104  {
2105  scalar magDisp = mag(patchDisp[patchPointi]);
2106 
2107  if (magDisp > snapDist[patchPointi])
2108  {
2109  patchDisp[patchPointi] *= snapDist[patchPointi] / magDisp;
2110 
2111  Pout<< "Limiting displacement for " << patchPointi
2112  << " from " << magDisp << " to " << snapDist[patchPointi]
2113  << endl;
2114  }
2115  }
2116 
2117  // Points on zones in one domain but only present as point on other
2118  // will not do condition 2 on all. Sync explicitly.
2120  (
2121  mesh,
2122  pp.meshPoints(),
2123  patchDisp,
2124  minMagSqrEqOp<point>(), // combine op
2125  vector(GREAT, GREAT, GREAT) // null value (note: cannot use VGREAT)
2126  );
2128  return patchDisp;
2129 }
2130 
2131 
2133 (
2134  const snapParameters& snapParams,
2135  motionSmoother& meshMover
2136 ) const
2137 {
2138  if (dryRun_)
2139  {
2140  return;
2141  }
2142 
2143  const fvMesh& mesh = meshRefiner_.mesh();
2144  const indirectPrimitivePatch& pp = meshMover.patch();
2145 
2146  Info<< "Smoothing displacement ..." << endl;
2147 
2148  // Set edge diffusivity as inverse of distance to patch
2149  scalarField edgeGamma(1.0/(edgePatchDist(meshMover.pMesh(), pp) + SMALL));
2150  //scalarField edgeGamma(mesh.nEdges(), 1.0);
2151  //scalarField edgeGamma(wallGamma(mesh, pp, 10, 1));
2152 
2153  // Get displacement field
2154  pointVectorField& disp = meshMover.displacement();
2155 
2156  for (label iter = 0; iter < snapParams.nSmoothDispl(); iter++)
2157  {
2158  if ((iter % 10) == 0)
2159  {
2160  Info<< "Iteration " << iter << endl;
2161  }
2162  pointVectorField oldDisp(disp);
2163  meshMover.smooth(oldDisp, edgeGamma, disp);
2164  }
2165  Info<< "Displacement smoothed in = "
2166  << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl;
2167 
2169  {
2170  const_cast<Time&>(mesh.time())++;
2171  Info<< "Writing smoothed mesh to time " << meshRefiner_.timeName()
2172  << endl;
2173 
2174  // Moving mesh creates meshPhi. Can be cleared out by a mesh.clearOut
2175  // but this will also delete all pointMesh but not pointFields which
2176  // gives an illegal situation.
2177 
2178  meshRefiner_.write
2179  (
2182  (
2185  ),
2186  mesh.time().path()/meshRefiner_.timeName()
2187  );
2188  Info<< "Writing displacement field ..." << endl;
2189  disp.write();
2190  tmp<pointScalarField> magDisp(mag(disp));
2191  magDisp().write();
2192 
2193  Info<< "Writing actual patch displacement ..." << endl;
2194  vectorField actualPatchDisp(disp, pp.meshPoints());
2195  dumpMove
2196  (
2197  mesh.time().path()
2198  / "actualPatchDisplacement_" + meshRefiner_.timeName() + ".obj",
2199  pp.localPoints(),
2200  pp.localPoints() + actualPatchDisp
2201  );
2202  }
2203 }
2204 
2205 
2207 (
2208  const snapParameters& snapParams,
2209  const label nInitErrors,
2210  const List<labelPair>& baffles,
2211  motionSmoother& meshMover
2212 )
2213 {
2214  addProfiling(scale, "snappyHexMesh::snap::scale");
2215  const fvMesh& mesh = meshRefiner_.mesh();
2216 
2217  // Relax displacement until correct mesh
2218  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2219  labelList checkFaces(identity(mesh.nFaces()));
2220 
2221  scalar oldErrorReduction = -1;
2222 
2223  bool meshOk = false;
2224 
2225  Info<< "Moving mesh ..." << endl;
2226  for (label iter = 0; iter < 2*snapParams.nSnap(); iter++)
2227  {
2228  Info<< nl << "Iteration " << iter << endl;
2229 
2230  if (iter == snapParams.nSnap())
2231  {
2232  Info<< "Displacement scaling for error reduction set to 0." << endl;
2233  oldErrorReduction = meshMover.setErrorReduction(0.0);
2234  }
2235 
2236  meshOk = meshMover.scaleMesh(checkFaces, baffles, true, nInitErrors);
2237 
2238  if (meshOk)
2239  {
2240  Info<< "Successfully moved mesh" << endl;
2241  break;
2242  }
2244  {
2245  const_cast<Time&>(mesh.time())++;
2246  Info<< "Writing scaled mesh to time " << meshRefiner_.timeName()
2247  << endl;
2248  mesh.write();
2249 
2250  Info<< "Writing displacement field ..." << endl;
2251  meshMover.displacement().write();
2252  tmp<pointScalarField> magDisp(mag(meshMover.displacement()));
2253  magDisp().write();
2254  }
2255  }
2256 
2257  if (oldErrorReduction >= 0)
2258  {
2259  meshMover.setErrorReduction(oldErrorReduction);
2260  }
2261  Info<< "Moved mesh in = "
2262  << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl;
2263 
2264  return meshOk;
2265 }
2266 
2267 
2268 // After snapping: correct patching according to nearest surface.
2269 // Code is very similar to calcNearestSurface.
2270 // - calculate face-wise snap distance as max of point-wise
2271 // - calculate face-wise nearest surface point
2272 // - repatch face according to patch for surface point.
2274 (
2275  const snapParameters& snapParams,
2276  const labelList& adaptPatchIDs,
2277  const labelList& preserveFaces
2278 )
2279 {
2280  const fvMesh& mesh = meshRefiner_.mesh();
2281  const refinementSurfaces& surfaces = meshRefiner_.surfaces();
2282 
2283  Info<< "Repatching faces according to nearest surface ..." << endl;
2284 
2285  // Get the labels of added patches.
2287  (
2289  (
2290  mesh,
2291  adaptPatchIDs
2292  )
2293  );
2294  indirectPrimitivePatch& pp = ppPtr();
2295 
2296  // Divide surfaces into zoned and unzoned
2297  labelList zonedSurfaces =
2299  labelList unzonedSurfaces =
2301 
2302 
2303  // Faces that do not move
2304  bitSet isZonedFace(mesh.nFaces());
2305  {
2306  // 1. Preserve faces in preserveFaces list
2307  forAll(preserveFaces, facei)
2308  {
2309  if (preserveFaces[facei] != -1)
2310  {
2311  isZonedFace.set(facei);
2312  }
2313  }
2314 
2315  // 2. All faces on zoned surfaces
2316  const PtrList<surfaceZonesInfo>& surfZones = surfaces.surfZones();
2317  const faceZoneMesh& fZones = mesh.faceZones();
2318 
2319  forAll(zonedSurfaces, i)
2320  {
2321  const label zoneSurfi = zonedSurfaces[i];
2322  const wordList& fZoneNames = surfZones[zoneSurfi].faceZoneNames();
2323  forAll(fZoneNames, i)
2324  {
2325  const faceZone& fZone = fZones[fZoneNames[i]];
2326  isZonedFace.set(fZone);
2327  }
2328  }
2329  }
2330 
2331 
2332  // Determine per pp face which patch it should be in
2333  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2334 
2335  // Patch that face should be in
2336  labelList closestPatch(pp.size(), -1);
2337  {
2338  // face snap distance as max of point snap distance
2339  scalarField faceSnapDist(pp.size(), -GREAT);
2340  {
2341  // Distance to attract to nearest feature on surface
2342  const scalarField snapDist
2343  (
2344  calcSnapDistance
2345  (
2346  mesh,
2347  snapParams,
2348  pp
2349  )
2350  );
2351 
2352  const faceList& localFaces = pp.localFaces();
2353 
2354  forAll(localFaces, facei)
2355  {
2356  const face& f = localFaces[facei];
2357 
2358  forAll(f, fp)
2359  {
2360  faceSnapDist[facei] = max
2361  (
2362  faceSnapDist[facei],
2363  snapDist[f[fp]]
2364  );
2365  }
2366  }
2367  }
2368 
2369  pointField localFaceCentres(mesh.faceCentres(), pp.addressing());
2370 
2371  // Get nearest surface and region
2372  labelList hitSurface;
2373  labelList hitRegion;
2374  surfaces.findNearestRegion
2375  (
2376  unzonedSurfaces,
2377  localFaceCentres,
2378  sqr(faceSnapDist), // sqr of attract distance
2379  hitSurface,
2380  hitRegion
2381  );
2382 
2383  // Get patch
2384  forAll(pp, i)
2385  {
2386  label facei = pp.addressing()[i];
2387 
2388  if (hitSurface[i] != -1 && !isZonedFace.test(facei))
2389  {
2390  closestPatch[i] = globalToMasterPatch_
2391  [
2392  surfaces.globalRegion
2393  (
2394  hitSurface[i],
2395  hitRegion[i]
2396  )
2397  ];
2398  }
2399  }
2400  }
2401 
2402 
2403  // Change those faces for which there is a different closest patch
2404  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2405 
2406  labelList ownPatch(mesh.nFaces(), -1);
2407  labelList neiPatch(mesh.nFaces(), -1);
2408 
2410 
2411  forAll(patches, patchi)
2412  {
2413  const polyPatch& pp = patches[patchi];
2414 
2415  forAll(pp, i)
2416  {
2417  ownPatch[pp.start()+i] = patchi;
2418  neiPatch[pp.start()+i] = patchi;
2419  }
2420  }
2421 
2422  label nChanged = 0;
2423  forAll(closestPatch, i)
2424  {
2425  label facei = pp.addressing()[i];
2426 
2427  if (closestPatch[i] != -1 && closestPatch[i] != ownPatch[facei])
2428  {
2429  ownPatch[facei] = closestPatch[i];
2430  neiPatch[facei] = closestPatch[i];
2431  nChanged++;
2432  }
2433  }
2434 
2435  Info<< "Repatched " << returnReduce(nChanged, sumOp<label>())
2436  << " faces in = " << mesh.time().cpuTimeIncrement() << " s\n" << nl
2437  << endl;
2438 
2439  return meshRefiner_.createBaffles(ownPatch, neiPatch);
2440 }
2441 
2442 
2443 void Foam::snappySnapDriver::detectWarpedFaces
2444 (
2445  const scalar featureCos,
2446  const indirectPrimitivePatch& pp,
2447 
2448  DynamicList<label>& splitFaces,
2449  DynamicList<labelPair>& splits
2450 ) const
2451 {
2452  const fvMesh& mesh = meshRefiner_.mesh();
2453  const faceList& localFaces = pp.localFaces();
2454  const pointField& localPoints = pp.localPoints();
2455  const labelList& bFaces = pp.addressing();
2456 
2457  splitFaces.clear();
2458  splitFaces.setCapacity(bFaces.size());
2459  splits.clear();
2460  splits.setCapacity(bFaces.size());
2461 
2462  // Determine parallel consistent normals on points
2463  const vectorField pointNormals(PatchTools::pointNormals(mesh, pp));
2464 
2465  face f0(4);
2466  face f1(4);
2467 
2468  forAll(localFaces, facei)
2469  {
2470  const face& f = localFaces[facei];
2471 
2472  if (f.size() >= 4)
2473  {
2474  // See if splitting face across diagonal would make two faces with
2475  // biggish normal angle
2476 
2477  labelPair minDiag(-1, -1);
2478  scalar minCos(GREAT);
2479 
2480  for (label startFp = 0; startFp < f.size()-2; startFp++)
2481  {
2482  label minFp = f.rcIndex(startFp);
2483 
2484  for
2485  (
2486  label endFp = f.fcIndex(f.fcIndex(startFp));
2487  endFp < f.size() && endFp != minFp;
2488  endFp++
2489  )
2490  {
2491  // Form two faces
2492  f0.setSize(endFp-startFp+1);
2493  label i0 = 0;
2494  for (label fp = startFp; fp <= endFp; fp++)
2495  {
2496  f0[i0++] = f[fp];
2497  }
2498  f1.setSize(f.size()+2-f0.size());
2499  label i1 = 0;
2500  for (label fp = endFp; fp != startFp; fp = f.fcIndex(fp))
2501  {
2502  f1[i1++] = f[fp];
2503  }
2504  f1[i1++] = f[startFp];
2505 
2506  //Info<< "Splitting face:" << f << " into f0:" << f0
2507  // << " f1:" << f1 << endl;
2508 
2509  const vector n0 = f0.areaNormal(localPoints);
2510  const scalar n0Mag = mag(n0);
2511 
2512  const vector n1 = f1.areaNormal(localPoints);
2513  const scalar n1Mag = mag(n1);
2514 
2515  if (n0Mag > ROOTVSMALL && n1Mag > ROOTVSMALL)
2516  {
2517  scalar cosAngle = (n0/n0Mag) & (n1/n1Mag);
2518  if (cosAngle < minCos)
2519  {
2520  minCos = cosAngle;
2521  minDiag = labelPair(startFp, endFp);
2522  }
2523  }
2524  }
2525  }
2526 
2527 
2528  if (minCos < featureCos)
2529  {
2530  splitFaces.append(bFaces[facei]);
2531  splits.append(minDiag);
2532  }
2533  }
2534  }
2535 }
2536 
2537 
2538 Foam::labelList Foam::snappySnapDriver::getInternalOrBaffleDuplicateFace() const
2539 {
2540  const fvMesh& mesh = meshRefiner_.mesh();
2541 
2542  labelList internalOrBaffleFaceZones;
2543  {
2544  List<surfaceZonesInfo::faceZoneType> fzTypes(2);
2545  fzTypes[0] = surfaceZonesInfo::INTERNAL;
2546  fzTypes[1] = surfaceZonesInfo::BAFFLE;
2547  internalOrBaffleFaceZones = meshRefiner_.getZones(fzTypes);
2548  }
2549 
2550  List<labelPair> baffles
2551  (
2552  meshRefiner_.subsetBaffles
2553  (
2554  mesh,
2555  internalOrBaffleFaceZones,
2557  )
2558  );
2559 
2560  labelList faceToDuplicate(mesh.nFaces(), -1);
2561  forAll(baffles, i)
2562  {
2563  const labelPair& p = baffles[i];
2564  faceToDuplicate[p[0]] = p[1];
2565  faceToDuplicate[p[1]] = p[0];
2566  }
2568  return faceToDuplicate;
2569 }
2570 
2571 
2573 (
2574  const dictionary& snapDict,
2575  const dictionary& motionDict,
2576  const meshRefinement::FaceMergeType mergeType,
2577  const scalar featureCos,
2578  const scalar planarAngle,
2579  const snapParameters& snapParams
2580 )
2581 {
2582  if (meshRefiner_.meshType() == meshRefinement::CASTELLATEDBUFFERLAYER2)
2583  {
2584  // Buffer-layer replacement for this routine
2585 
2586  doSnapBufferLayers
2587  (
2588  snapDict,
2589  motionDict,
2590  mergeType,
2591  featureCos,
2592  planarAngle,
2593  snapParams
2594  );
2595  return;
2596  }
2597 
2598  addProfiling(snap, "snappyHexMesh::snap");
2599  fvMesh& mesh = meshRefiner_.mesh();
2600 
2601  Info<< nl
2602  << "Morphing phase" << nl
2603  << "--------------" << nl
2604  << endl;
2605 
2606  // faceZone handling
2607  // ~~~~~~~~~~~~~~~~~
2608  //
2609  // We convert all faceZones into baffles during snapping so we can use
2610  // a standard mesh motion (except for the mesh checking which for baffles
2611  // created from internal faces should check across the baffles). The state
2612  // is stored in two variables:
2613  // baffles : pairs of boundary faces
2614  // duplicateFace : from mesh face to its baffle colleague (or -1 for
2615  // normal faces)
2616  // There are three types of faceZones according to the faceType property:
2617  //
2618  // internal
2619  // --------
2620  // - baffles: need to be checked across
2621  // - duplicateFace: from face to duplicate face. Contains
2622  // all faces on faceZone to prevents merging patch faces.
2623  //
2624  // baffle
2625  // ------
2626  // - baffles: no need to be checked across
2627  // - duplicateFace: contains all faces on faceZone to prevent
2628  // merging patch faces.
2629  //
2630  // boundary
2631  // --------
2632  // - baffles: no need to be checked across. Also points get duplicated
2633  // so will no longer be baffles
2634  // - duplicateFace: contains no faces on faceZone since both sides can
2635  // merge faces independently.
2636 
2637 
2638 
2639  // Get labels of patches where optional buffer layers are added
2640  DynamicList<label> bufPatchIDs;
2641  if (meshRefiner_.meshType() == meshRefinement::CASTELLATEDBUFFERLAYER)
2642  {
2643  bufPatchIDs.setCapacity(globalToMasterPatch_.size());
2644 
2645  const auto& addLayers =
2646  meshRefiner_.surfaces().addBufferLayers();
2647 
2648  // Normal patches
2649  forAll(globalToMasterPatch_, globalRegioni)
2650  {
2651  if (addLayers[globalRegioni])
2652  {
2653  const label masterP =
2654  globalToMasterPatch_[globalRegioni];
2655  const label slaveP =
2656  globalToSlavePatch_[globalRegioni];
2657 
2658  bufPatchIDs.append(masterP);
2659  if (slaveP != masterP)
2660  {
2661  bufPatchIDs.append(slaveP);
2662  }
2663  }
2664  }
2665 
2666  // Temporary patches from faceZones
2667  for (const auto& fz : mesh.faceZones())
2668  {
2669  label mpI, spI;
2671  if (meshRefiner_.getFaceZoneInfo(fz.name(), mpI, spI, type))
2672  {
2673  bufPatchIDs.appendUniq(mpI);
2674  bufPatchIDs.appendUniq(spI);
2675  }
2676  }
2677  }
2678 
2679 
2680 
2681  // faceZones of type internal
2682  const labelList internalFaceZones
2683  (
2684  meshRefiner_.getZones
2685  (
2686  List<surfaceZonesInfo::faceZoneType>
2687  (
2688  1,
2690  )
2691  )
2692  );
2693 
2694  // Create baffles (pairs of faces that share the same points)
2695  // Baffles stored as owner and neighbour face that have been created.
2696  List<labelPair> baffles;
2697  {
2698  labelList originatingFaceZone;
2699  meshRefiner_.createZoneBaffles
2700  (
2701  identity(mesh.faceZones().size()),
2702  baffles,
2703  originatingFaceZone
2704  );
2705  }
2706 
2707  // Duplicate points on faceZones of type boundary. Renumber baffles
2708  // (probably not necessary - faceIDs should not change)
2709  {
2710  autoPtr<mapPolyMesh> map = meshRefiner_.dupNonManifoldBoundaryPoints();
2711  if (map)
2712  {
2713  const labelList& reverseFaceMap = map->reverseFaceMap();
2714  forAll(baffles, i)
2715  {
2716  label f0 = reverseFaceMap[baffles[i].first()];
2717  label f1 = reverseFaceMap[baffles[i].second()];
2718  baffles[i] = labelPair(f0, f1);
2719  }
2720  }
2721  }
2722 
2723 
2724  bool doFeatures = false;
2725  label nFeatIter = 1;
2726  if (snapParams.nFeatureSnap() > 0)
2727  {
2728  doFeatures = true;
2729 
2730  if (!dryRun_)
2731  {
2732  nFeatIter = snapParams.nFeatureSnap();
2733  }
2734 
2735  Info<< "Snapping to features in " << nFeatIter
2736  << " iterations ..." << endl;
2737  }
2738 
2739 
2740  bool meshOk = false;
2741 
2742 
2743  // Get the labels of added patches.
2744  const labelList adaptPatchIDs(meshRefiner_.meshedPatches());
2745 
2746 
2747 
2748  {
2749  autoPtr<indirectPrimitivePatch> ppPtr
2750  (
2752  (
2753  mesh,
2754  adaptPatchIDs
2755  )
2756  );
2757 
2758  // Distance to attract to nearest feature on surface
2759  scalarField snapDist(calcSnapDistance(mesh, snapParams, ppPtr()));
2760 
2761 
2762  // Construct iterative mesh mover.
2763  Info<< "Constructing mesh displacer ..." << endl;
2764  Info<< "Using mesh parameters " << motionDict << nl << endl;
2765 
2766  autoPtr<motionSmoother> meshMoverPtr
2767  (
2768  new motionSmoother
2769  (
2770  mesh,
2771  ppPtr(),
2772  adaptPatchIDs,
2774  (
2776  adaptPatchIDs
2777  ),
2778  motionDict,
2779  dryRun_
2780  )
2781  );
2782 
2783 
2784  // Check initial mesh
2785  Info<< "Checking initial mesh ..." << endl;
2786  labelHashSet wrongFaces(mesh.nFaces()/100);
2787  motionSmoother::checkMesh(false, mesh, motionDict, wrongFaces, dryRun_);
2788  const label nInitErrors = returnReduce
2789  (
2790  wrongFaces.size(),
2791  sumOp<label>()
2792  );
2793 
2794  Info<< "Detected " << nInitErrors << " illegal faces"
2795  << " (concave, zero area or negative cell pyramid volume)"
2796  << endl;
2797 
2798 
2799  Info<< "Checked initial mesh in = "
2800  << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl;
2801 
2802  // Extract baffles across internal faceZones (for checking mesh quality
2803  // across)
2804  labelPairList internalBaffles
2805  (
2806  meshRefiner_.subsetBaffles
2807  (
2808  mesh,
2809  internalFaceZones,
2811  )
2812  );
2813 
2814 
2815 
2816  // Pre-smooth patch vertices (so before determining nearest)
2817  preSmoothPatch
2818  (
2819  meshRefiner_,
2820  snapParams,
2821  nInitErrors,
2822  internalBaffles,
2823  meshMoverPtr()
2824  );
2825 
2826  // Reset moving flag in case we do any topo changes
2827  mesh.moving(false);
2828 
2829 
2830  // Optionally add buffer layers
2831  if (meshRefiner_.meshType() == meshRefinement::CASTELLATEDBUFFERLAYER)
2832  {
2835  //autoPtr<mapPolyMesh> mapPtr = meshRefiner_.mergeZoneBaffles
2836  //(
2837  // true, // internal zones
2838  // false // baffle zones
2839  //);
2840  //
2841  //if (mapPtr)
2842  //{
2843  // if (debug & meshRefinement::MESH)
2844  // {
2845  // const_cast<Time&>(mesh.time())++;
2846  // Info<< "Writing baffle-merged mesh to time "
2847  // << meshRefiner_.timeName() << endl;
2848  // meshRefiner_.write
2849  // (
2850  // meshRefinement::debugType(debug),
2851  // meshRefinement::writeType
2852  // (
2853  // meshRefinement::writeLevel()
2854  // | meshRefinement::WRITEMESH
2855  // ),
2856  // meshRefiner_.timeName()
2857  // );
2858  // }
2859  //}
2860 
2862  //Info<< "Adding buffer layers ..." << endl;
2863  //
2864  //{
2865  // // Remove references to pp
2866  // meshMoverPtr.clear();
2867  //
2868  // const labelList meshFaces
2869  // (
2870  // mesh.faceZones().selection
2871  // (
2872  // internalFaceZones
2873  // ).sortedToc()
2874  // );
2875  // ppPtr.reset
2876  // (
2877  // new indirectPrimitivePatch
2878  // (
2879  // IndirectList<face>
2880  // (
2881  // mesh.faces(),
2882  // meshFaces
2883  // ),
2884  // mesh.points()
2885  // )
2886  // );
2887  // const pointField thickness
2888  // (
2889  // wantedThickness(ppPtr(), 1e-1) //cellSizeFraction
2890  // * PatchTools::pointNormals(mesh, ppPtr())
2891  // );
2892  //
2893  // // Layer mesh modifier
2894  // // - use intrusion, not extrusion
2895  // addPatchCellLayer addLayer(mesh, true, false);
2896  //
2897  // // Do mesh changes : introduce point, faces, cells
2898  // autoPtr<mapPolyMesh> mapPtr = addBufferLayers
2899  // (
2900  // ppPtr(),
2901  // -thickness, //1e-3, //cellSizeFraction,
2902  // addLayer
2903  // );
2904  //
2905  // // Update numbering on baffles, pointToMaster. Note: uses
2906  // // geometric tolerance - could be avoided since now we have
2907  // // addPatchCellLayer still intact. However would like to avoid
2908  // // use of addPatchCellLayer altogether.
2909  // if (mapPtr)
2910  // {
2911  // // Invalidate extrusion (face numbering might have changed)
2912  // ppPtr.clear();
2913  //
2914  // labelList dummyPointToMaster;
2915  // snappyLayerDriver::mapFaceZonePoints
2916  // (
2917  // meshRefiner_,
2918  // mapPtr(),
2919  // internalBaffles,
2920  // dummyPointToMaster
2921  // );
2922  //
2923  // if (debug & meshRefinement::MESH)
2924  // {
2925  // const_cast<Time&>(mesh.time())++;
2926  // Info<< "Writing INTERNAL ZONE buffer layer mesh"
2927  // << " to time " << meshRefiner_.timeName() << endl;
2928  // meshRefiner_.write
2929  // (
2930  // meshRefinement::debugType(debug),
2931  // meshRefinement::writeType
2932  // (
2933  // meshRefinement::writeLevel()
2934  // | meshRefinement::WRITEMESH
2935  // ),
2936  // meshRefiner_.timeName()
2937  // );
2938  // }
2939  // }
2940  //}
2941 
2943  //{
2944  // labelList originatingFaceZone;
2945  // meshRefiner_.createZoneBaffles
2946  // (
2947  // internalFaceZones,
2948  // baffles,
2949  // originatingFaceZone
2950  // );
2951  //}
2952 
2953 
2954  Info<< "Adding buffer layers ..." << endl;
2955 
2956  // Remove references to pp
2957  meshMoverPtr.clear();
2958  // Invalidate extrusion (face numbering might have changed)
2959  ppPtr.clear();
2960 
2961  // Note: all the way up to addBufferLayers can probably be replaced
2962  // once addPatchCellLayer can add to both sides of faceZone ...
2963 
2964  // Duplicate points on faceZones that layers are added to
2965  labelList pointToMaster;
2966  {
2967  labelList numLayers(mesh.boundaryMesh().size(), 0);
2968  UIndirectList<label>(numLayers, bufPatchIDs) = 1;
2969 
2970  autoPtr<mapPolyMesh> mapPtr =
2972  (
2973  meshRefiner_,
2974  bufPatchIDs, // patch indices
2975  numLayers, // num layers per patch
2976  baffles,
2977  pointToMaster
2978  );
2979  if (mapPtr)
2980  {
2981  // Update numbering on any baffles
2983  (
2984  mesh,
2985  mapPtr().faceMap(),
2986  internalBaffles
2987  );
2988 
2989 
2992  //if (debug & meshRefinement::MESH)
2993  //{
2994  // pointField newPoints(mesh.nPoints());
2995  // forAll(newPoints, pointi)
2996  // {
2997  // const auto& pCells = mesh.pointCells()[pointi];
2998  //
2999  // point avg(Zero);
3000  // for (const label celli : pCells)
3001  // {
3002  // avg += mesh.cellCentres()[celli];
3003  // }
3004  // avg /= pCells.size();
3005  //
3006  // newPoints[pointi] =
3007  // 0.5*mesh.points()[pointi]
3008  // + 0.5*avg;
3009  // }
3010  // mesh.movePoints(newPoints);
3011  //
3012  // const_cast<Time&>(mesh.time())++;
3013  // Info<< "Writing DEBUG-shrunk layer mesh to time "
3014  // << meshRefiner_.timeName() << endl;
3015  // meshRefiner_.write
3016  // (
3017  // meshRefinement::debugType(debug),
3018  // meshRefinement::writeType
3019  // (
3020  // meshRefinement::writeLevel()
3021  // | meshRefinement::WRITEMESH
3022  // ),
3023  // meshRefiner_.timeName()
3024  // );
3025  //}
3026  }
3027  }
3028 
3029  //- Not needed: shrinking of mesh since now using intrusion ...
3030  // // Move mesh back with thickness. Two purposes:
3031  // // - avoid mapFaceZonePoints below merging points extraneously
3032  // // (does not use addPatchCellLayer structure; uses geometric
3033  // // tolerance)
3034  // // - see what is happening
3035  // {
3036  // pointField newPoints(mesh.points());
3037  // const auto& mp = ppPtr().meshPoints();
3038  // forAll(mp, i)
3039  // {
3040  // newPoints[mp[i]] -= thickness[i];
3041  // }
3042  // mesh.movePoints(newPoints);
3043  // ppPtr().movePoints(mesh.points());
3044  //
3045  // if (debug & meshRefinement::MESH)
3046  // {
3047  // const_cast<Time&>(mesh.time())++;
3048  // Info<< "Writing shrunk buffer layer mesh to time "
3049  // << meshRefiner_.timeName() << endl;
3050  // meshRefiner_.write
3051  // (
3052  // meshRefinement::debugType(debug),
3053  // meshRefinement::writeType
3054  // (
3055  // meshRefinement::writeLevel()
3056  // | meshRefinement::WRITEMESH
3057  // ),
3058  // meshRefiner_.timeName()
3059  // );
3060  // }
3061  // }
3062 
3063 
3064  {
3065  // Layer mesh modifier
3066  // - use intrusion, not extrusion
3067  addPatchCellLayer addLayer(mesh, true, false);
3068 
3069  // Redo pp
3070  autoPtr<indirectPrimitivePatch> bufPatchPtr
3071  (
3072  meshRefinement::makePatch(mesh, bufPatchIDs)
3073  );
3074 
3075  pointField thickness
3076  (
3077  wantedThickness(bufPatchPtr(), 1e-1) //cellSizeFraction
3078  * PatchTools::pointNormals(mesh, bufPatchPtr())
3079  );
3080 
3081  // Make sure to adhere to constraints
3082  {
3083 
3084  const pointMesh& pMesh = pointMesh::New(mesh);
3085  const labelList& mp = bufPatchPtr().meshPoints();
3086 
3087  tmp<pointVectorField> tdisp
3088  (
3090  (
3091  pMesh,
3092  adaptPatchIDs
3093  )
3094  );
3095  // Set internal field
3096  UIndirectList<point>(tdisp.ref(), mp) = thickness;
3097  // Take over onto boundary field. Needed since constraint
3098  // patch might be before the fixedValue patches so its
3099  // value gets overwritten
3100  for (auto& ppf : tdisp.ref().boundaryFieldRef())
3101  {
3102  ppf == ppf.patchInternalField();
3103  }
3104 
3105  // Adhere to multi-point constraints
3106  const pointConstraints& pcs = pointConstraints::New(pMesh);
3107  pcs.constrainDisplacement(tdisp.ref(), false);
3108 
3109  thickness = UIndirectList<point>(tdisp(), mp);
3110  }
3111 
3112 
3113 
3114  // Print a bit
3115  {
3116  // See snappyLayerDriver::calculateLayerThickness.
3117  const auto& pbm = mesh.boundaryMesh();
3118  label maxLen = 0;
3119  for (const label patchi : bufPatchIDs)
3120  {
3121  maxLen = max(maxLen, label(pbm[patchi].name().size()));
3122  }
3123 
3124  const int oldPrecision = Info.stream().precision();
3125 
3126  Info<< nl
3127  << setf(ios_base::left) << setw(maxLen) << "patch"
3128  << setw(0) << " faces layers thickness[m]" << nl
3129  << setf(ios_base::left) << setw(maxLen) << "-----"
3130  << setw(0) << " ----- ------ ------------" << endl;
3131 
3132  for (const label patchi : bufPatchIDs)
3133  {
3134  Info<< setf(ios_base::left) << setw(maxLen)
3135  << pbm[patchi].name() << setprecision(3)
3136  << " " << setw(8)
3137  << returnReduce(pbm[patchi].size(), sumOp<scalar>())
3138  << " " << setw(6) << 1
3139  << " " << setw(8) << gAverage(mag(thickness))
3140  << endl;
3141  }
3142  Info<< setprecision(oldPrecision) << endl;
3143  }
3144 
3145 
3146  // Do mesh changes : introduce point, faces, cells
3147  autoPtr<mapPolyMesh> mapPtr = addBufferLayers
3148  (
3149  bufPatchPtr(),
3150  -thickness, //1e-3, //cellSizeFraction,
3151  addLayer
3152  );
3153 
3154  // Update numbering on baffles, pointToMaster. Note: uses
3155  // geometric tolerance - could be avoided since now we have
3156  // addPatchCellLayer still intact. However would like to avoid
3157  // use of addPatchCellLayer altogether.
3158  if (mapPtr)
3159  {
3160  // Invalidate extrusion (face numbering might have changed)
3161  ppPtr.clear();
3162 
3164  (
3165  meshRefiner_,
3166  mapPtr(),
3167  internalBaffles,
3168  pointToMaster
3169  );
3170  }
3171  }
3172 
3173 
3174 
3175  {
3176  // Merge duplicated points (this creates illegal cells -
3177  // hopefully they will be smoothed out)
3178  autoPtr<mapPolyMesh> mapPtr =
3179  meshRefiner_.mergePoints(pointToMaster);
3180  if (mapPtr)
3181  {
3182  // Invalidate extrusion (point numbering might have changed)
3183  ppPtr.clear();
3184 
3185  // Update numbering on any baffles
3187  (
3188  mesh,
3189  mapPtr().faceMap(),
3190  internalBaffles
3191  );
3192  // Extract baffles across internal faceZones
3193  internalBaffles = meshRefinement::subsetBaffles
3194  (
3195  mesh,
3196  internalFaceZones,
3197  internalBaffles
3198  );
3199 
3201  {
3202  const_cast<Time&>(mesh.time())++;
3203  Info<< "Writing merged points buffer layer mesh"
3204  << " to time " << meshRefiner_.timeName() << endl;
3205  meshRefiner_.write
3206  (
3209  (
3212  ),
3213  meshRefiner_.timeName()
3214  );
3215  }
3216  }
3217  }
3218 
3219 
3220  Info<< "Inflating buffer layers ..." << endl;
3221 
3222  const pointMesh& pMesh = pointMesh::New(mesh);
3223 
3224  {
3225  autoPtr<displacementMotionSolver> motionPtr
3226  (
3227  makeMotionSolver
3228  (
3229  pMesh,
3230  snapDict,
3231  bufPatchIDs
3232  //patchConstraints
3233  )
3234  );
3235 
3236  // Solve internal displacement
3237  tmp<pointField> tnewPoints(motionPtr->newPoints());
3238 
3239  // Move points
3240  mesh.movePoints(tnewPoints);
3241 
3242  // Reset moving flag to avoid problems with topo changes
3243  mesh.moving(false);
3244 
3246  {
3247  const_cast<Time&>(mesh.time())++;
3248  Info<< "Writing smoothed buffer layer mesh to time "
3249  << meshRefiner_.timeName() << endl;
3250  meshRefiner_.write
3251  (
3254  (
3257  ),
3258  meshRefiner_.timeName()
3259  );
3260  }
3261  }
3262 
3263  // Update mesh mover
3264  ppPtr = meshRefinement::makePatch(mesh, adaptPatchIDs);
3265  meshMoverPtr.reset
3266  (
3267  new motionSmoother
3268  (
3269  mesh,
3270  ppPtr(),
3271  adaptPatchIDs,
3273  (
3275  adaptPatchIDs
3276  ),
3277  motionDict,
3278  dryRun_
3279  )
3280  );
3281  }
3282 
3283 
3284  //- Only if in feature attraction mode:
3285  // Nearest feature
3286  vectorField patchAttraction;
3287  // Constraints at feature
3288  List<pointConstraint> patchConstraints;
3289 
3290 
3291  //- Any faces to split
3292  DynamicList<label> splitFaces;
3293  //- Indices in face to split across
3294  DynamicList<labelPair> splits;
3295  //- Patch for both sides of the face
3296  DynamicList<labelPair> splitPatches;
3297 
3298 
3299  for (label iter = 0; iter < nFeatIter; iter++)
3300  {
3301  Info<< nl
3302  << "Morph iteration " << iter << nl
3303  << "-----------------" << endl;
3304 
3305  // Splitting iteration?
3306  bool doSplit = false;
3307  if
3308  (
3309  doFeatures
3310  && snapParams.nFaceSplitInterval() > 0
3311  && (
3312  (iter == nFeatIter-1)
3313  || (iter > 0 && (iter%snapParams.nFaceSplitInterval()) == 0)
3314  )
3315  )
3316  {
3317  doSplit = true;
3318  }
3319 
3320 
3321 
3322  indirectPrimitivePatch& pp = ppPtr();
3323  motionSmoother& meshMover = meshMoverPtr();
3324 
3325 
3326  // Calculate displacement at every patch point if we need it:
3327  // - if automatic near-surface detection
3328  // - if face splitting active
3329  pointField nearestPoint;
3330  vectorField nearestNormal;
3331 
3332  if (snapParams.detectNearSurfacesSnap() || doSplit)
3333  {
3334  nearestPoint.setSize(pp.nPoints(), vector::max);
3335  nearestNormal.setSize(pp.nPoints(), Zero);
3336  }
3337 
3338  vectorField disp = calcNearestSurface
3339  (
3340  snapParams.strictRegionSnap(), // attract points to region only
3341  meshRefiner_,
3342  globalToMasterPatch_, // for if strictRegionSnap
3343  globalToSlavePatch_, // for if strictRegionSnap
3344  pp,
3345  pp.localPoints(),
3346  snapDist,
3347 
3348  nearestPoint,
3349  nearestNormal
3350  );
3351 
3352 
3353  // Override displacement at thin gaps
3354  if (snapParams.detectNearSurfacesSnap())
3355  {
3356  detectNearSurfaces
3357  (
3358  Foam::cos(degToRad(planarAngle)),// planar cos for gaps
3359  pp,
3360  pp.localPoints(),
3361  nearestPoint, // surfacepoint from nearest test
3362  nearestNormal, // surfacenormal from nearest test
3363 
3364  disp
3365  );
3366  }
3367 
3368  // Override displacement with feature edge attempt
3369  if (doFeatures)
3370  {
3371  splitFaces.clear();
3372  splits.clear();
3373  splitPatches.clear();
3374  disp = calcNearestSurfaceFeature
3375  (
3376  snapParams,
3377  !doSplit, // alignMeshEdges
3378  false, // no special handling for >=3 patch points
3379  iter,
3380  featureCos,
3381  scalar(iter+1)/nFeatIter,
3382 
3383  snapDist,
3384  disp,
3385  nearestNormal,
3386  pp,
3387  pp.localPoints(),
3388 
3389  patchAttraction,
3390  patchConstraints,
3391 
3392  splitFaces,
3393  splits,
3394  splitPatches
3395  );
3396  }
3397 
3398  // Check for displacement being outwards.
3399  outwardsDisplacement(pp, disp);
3400 
3401  // Freeze points on exposed points/faces
3402  freezeExposedPoints
3403  (
3404  meshRefiner_,
3405  "frozenFaces", // faceZone name
3406  "frozenPoints", // pointZone name
3407  pp,
3408  disp
3409  );
3410 
3411  // Set initial distribution of displacement field (on patches)
3412  // from patchDisp and make displacement consistent with b.c.
3413  // on displacement pointVectorField.
3414  meshMover.setDisplacement(disp);
3415 
3416 
3418  {
3419  dumpMove
3420  (
3421  mesh.time().path()
3422  / "patchDisplacement_" + name(iter) + ".obj",
3423  pp.localPoints(),
3424  pp.localPoints() + disp
3425  );
3426  }
3427 
3428  // Get smoothly varying internal displacement field.
3429  smoothDisplacement(snapParams, meshMover);
3430 
3431  // Apply internal displacement to mesh.
3432  meshOk = scaleMesh
3433  (
3434  snapParams,
3435  nInitErrors,
3436  internalBaffles,
3437  meshMover
3438  );
3439 
3440  if (!meshOk)
3441  {
3443  << "Did not successfully snap mesh."
3444  << " Continuing to snap to resolve easy" << nl
3445  << " surfaces but the"
3446  << " resulting mesh will not satisfy your quality"
3447  << " constraints" << nl << endl;
3448  }
3449 
3451  {
3452  const_cast<Time&>(mesh.time())++;
3453  Info<< "Writing scaled mesh to time "
3454  << meshRefiner_.timeName() << endl;
3455  meshRefiner_.write
3456  (
3459  (
3462  ),
3463  mesh.time().path()/meshRefiner_.timeName()
3464  );
3465  Info<< "Writing displacement field ..." << endl;
3466  meshMover.displacement().write();
3467  tmp<pointScalarField> magDisp
3468  (
3469  mag(meshMover.displacement())
3470  );
3471  magDisp().write();
3472  }
3473 
3474  // Use current mesh as base mesh
3475  meshMover.correct();
3476 
3477 
3478 
3479  // See if any faces need splitting
3480  label nTotalSplit = returnReduce(splitFaces.size(), sumOp<label>());
3481  if (nTotalSplit && doSplit)
3482  {
3483  // Filter out baffle faces from faceZones of type
3484  // internal/baffle
3485 
3486  labelList duplicateFace(getInternalOrBaffleDuplicateFace());
3487 
3488  {
3489  labelList oldSplitFaces(std::move(splitFaces));
3490  List<labelPair> oldSplits(std::move(splits));
3491  List<labelPair> oldSplitPatches(std::move(splitPatches));
3492  forAll(oldSplitFaces, i)
3493  {
3494  if (duplicateFace[oldSplitFaces[i]] == -1)
3495  {
3496  splitFaces.append(oldSplitFaces[i]);
3497  splits.append(oldSplits[i]);
3498  splitPatches.append(oldSplitPatches[i]);
3499  }
3500  }
3501  nTotalSplit = returnReduce
3502  (
3503  splitFaces.size(),
3504  sumOp<label>()
3505  );
3506  }
3507 
3508  // Update mesh
3509 
3510  // Reset moving flag to avoid meshPhi problems with topo changes
3511  mesh.moving(false);
3512 
3513  meshRefiner_.splitFacesUndo
3514  (
3515  splitFaces,
3516  splits,
3517  splitPatches,
3518  motionDict,
3519 
3520  duplicateFace,
3521  internalBaffles
3522  );
3523 
3524  // Redo meshMover
3525  meshMoverPtr.clear();
3526  ppPtr.clear();
3527 
3528  // Update mesh mover
3529  ppPtr = meshRefinement::makePatch(mesh, adaptPatchIDs);
3530  meshMoverPtr.reset
3531  (
3532  new motionSmoother
3533  (
3534  mesh,
3535  ppPtr(),
3536  adaptPatchIDs,
3538  (
3540  adaptPatchIDs
3541  ),
3542  motionDict,
3543  dryRun_
3544  )
3545  );
3546 
3547  // Update snapping distance
3548  snapDist = calcSnapDistance(mesh, snapParams, ppPtr());
3549 
3550 
3552  {
3553  const_cast<Time&>(mesh.time())++;
3554  Info<< "Writing split-faces mesh to time "
3555  << meshRefiner_.timeName() << endl;
3556  meshRefiner_.write
3557  (
3560  (
3563  ),
3564  mesh.time().path()/meshRefiner_.timeName()
3565  );
3566  }
3567  }
3568 
3569 
3571  {
3572  forAll(internalBaffles, i)
3573  {
3574  const labelPair& p = internalBaffles[i];
3575  const point& fc0 = mesh.faceCentres()[p[0]];
3576  const point& fc1 = mesh.faceCentres()[p[1]];
3577 
3578  if (mag(fc0-fc1) > meshRefiner_.mergeDistance())
3579  {
3581  << "Separated baffles : f0:" << p[0]
3582  << " centre:" << fc0
3583  << " f1:" << p[1] << " centre:" << fc1
3584  << " distance:" << mag(fc0-fc1)
3585  << exit(FatalError);
3586  }
3587  }
3588  }
3589  }
3590  }
3591 
3592 
3593  // Reset moving flag to avoid any meshPhi mapping problems
3594  mesh.moving(false);
3595 
3596 
3597  // Merge any introduced baffles (from faceZones of faceType 'internal')
3598  {
3599  autoPtr<mapPolyMesh> mapPtr = meshRefiner_.mergeZoneBaffles
3600  (
3601  true, // internal zones
3602  false // baffle zones
3603  );
3604 
3605  if (mapPtr)
3606  {
3608  {
3609  const_cast<Time&>(mesh.time())++;
3610  Info<< "Writing baffle-merged mesh to time "
3611  << meshRefiner_.timeName() << endl;
3612  meshRefiner_.write
3613  (
3616  (
3619  ),
3620  meshRefiner_.timeName()
3621  );
3622  }
3623  }
3624  }
3625 
3626  // Repatch faces according to nearest. Do not repatch baffle faces.
3627  {
3628  labelList duplicateFace(getInternalOrBaffleDuplicateFace());
3629 
3630  repatchToSurface(snapParams, adaptPatchIDs, duplicateFace);
3631  }
3632 
3633  if
3634  (
3635  mergeType == meshRefinement::FaceMergeType::GEOMETRIC
3636  || mergeType == meshRefinement::FaceMergeType::IGNOREPATCH
3637  )
3638  {
3639  labelList duplicateFace(getInternalOrBaffleDuplicateFace());
3640 
3641  // Repatching might have caused faces to be on same patch and hence
3642  // mergeable so try again to merge coplanar faces. Do not merge baffle
3643  // faces to ensure they both stay the same.
3644  label nChanged = meshRefiner_.mergePatchFacesUndo
3645  (
3646  featureCos, // minCos
3647  featureCos, // concaveCos
3648  meshRefiner_.meshedPatches(),
3649  motionDict,
3650  duplicateFace, // faces not to merge
3651  mergeType
3652  );
3653 
3654  nChanged += meshRefiner_.mergeEdgesUndo(featureCos, motionDict);
3655 
3656  if (nChanged > 0 && debug & meshRefinement::MESH)
3657  {
3658  const_cast<Time&>(mesh.time())++;
3659  Info<< "Writing patchFace merged mesh to time "
3660  << meshRefiner_.timeName() << endl;
3661  meshRefiner_.write
3662  (
3665  (
3668  ),
3669  meshRefiner_.timeName()
3670  );
3671  }
3672  }
3673 
3675  {
3676  const_cast<Time&>(mesh.time())++;
3677  }
3678 }
3679 
3680 
3681 // ************************************************************************* //
Given a displacement moves the mesh by scaling the displacement back until there are no more mesh err...
faceListList boundary
const labelListList & pointEdges() const
Return point-edge addressing.
Switch detectNearSurfacesSnap() const
Override attraction to nearest with intersection location.
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.
const polyBoundaryMesh & pbm
label nPoints() const
Number of points supporting patch faces.
const List< face_type > & localFaces() const
Return patch faces addressing into local point list.
reference val() const
Const access to referenced object (value)
Definition: HashTable.H:1201
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
ZoneMesh< faceZone, polyMesh > faceZoneMesh
A ZoneMesh with the type faceZone.
fileName path() const
Return path = rootPath/caseName. Same as TimePaths::path()
Definition: Time.H:503
label nSmoothDispl() const
Number of mesh displacement smoothing iterations.
const labelList & surfaces() const
static void mapBaffles(const polyMesh &mesh, const labelList &faceMap, List< labelPair > &baffles)
Map baffles after layer addition. Gets new-to-old face map.
bool scaleMesh(const snapParameters &snapParams, const label nInitErrors, const List< labelPair > &baffles, motionSmoother &)
Do the hard work: move the mesh according to displacement,.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:68
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
const Field< point_type > & localPoints() const
Return pointField of points in patch.
static bitSet getMasterFaces(const polyMesh &mesh)
Get per face whether it is uncoupled or a master of a coupled set of faces.
Definition: syncTools.C:119
label nPoints() const noexcept
Number of mesh points.
void doSnap(const dictionary &snapDict, const dictionary &motionDict, const meshRefinement::FaceMergeType mergeType, const scalar featureCos, const scalar planarAngle, const snapParameters &snapParams)
Snap onto surface & features.
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:608
Type gMin(const FieldField< Field, Type > &f)
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1122
static const weightedPosition zero
static void swapBoundaryCellList(const polyMesh &mesh, const UList< T > &cellData, List< T > &neighbourCellData, const bool parRun=UPstream::parRun())
Extract and swap to obtain neighbour cell values for all boundary faces.
const word & name() const noexcept
Return the object name.
Definition: IOobjectI.H:195
static const pointMesh & New(const polyMesh &mesh, Args &&... args)
Get existing or create MeshObject registered with typeName.
Definition: MeshObject.C:53
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
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:493
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Unit conversion functions.
bool scaleMesh(labelList &checkFaces, const bool smoothMesh=true, const label nAllow=0)
Move mesh with given scale. Return true if mesh ok or has.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
const pointMesh & pMesh() const
Reference to pointMesh.
label nSmoothPatch() const
Number of patch smoothing iterations before finding.
T & first()
Access first element of the list, position [0].
Definition: UList.H:862
dimensionedScalar sqrt(const dimensionedScalar &ds)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
virtual void movePoints(const pointField &)
Move points, returns volumes swept by faces in motion.
Definition: fvMesh.C:929
static writeType writeLevel()
Get/set write level.
#define addProfiling(Name,...)
Define profiling trigger with specified name and description string. The description is generated by ...
GeometricField< vector, pointPatchField, pointMesh > pointVectorField
void setCapacity(const label len)
Alter the size of the underlying storage.
Definition: DynamicListI.H:303
List< labelPair > labelPairList
List of labelPair.
Definition: labelPair.H:33
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of a point.
Definition: meshTools.C:196
static void getPoints(const UList< weightedPosition > &in, List< point > &out)
Get points.
static List< labelPair > subsetBaffles(const polyMesh &mesh, const labelList &zoneIDs, const List< labelPair > &baffles)
Subset baffles according to zones.
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:360
label nFaces() const noexcept
Number of mesh faces.
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
A PrimitivePatch with an IndirectList for the faces, const reference for the point field...
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Perform reduction on a copy, using specified binary operation.
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
void findNearest(const labelList &surfacesToTest, const pointField &samples, const scalarField &nearestDistSqr, labelList &surfaces, List< pointIndexHit > &) const
Find nearest point on surfaces.
label nFeatureSnap() const
const labelList & meshPoints() const
Return labelList of mesh points in patch.
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
void smooth(volScalarField &field, const scalar coeff)
Definition: fvcSmooth.C:37
const fvMesh & mesh() const
Reference to mesh.
static labelPairList findDuplicateFacePairs(const polyMesh &)
Helper routine to find all baffles (two boundary faces.
label nTotalPoints() const noexcept
Total global number of mesh points. Not compensated for duplicate points!
Container for data on surfaces used for surface-driven refinement. Contains all the data about the le...
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1078
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
void correct()
Take over existing mesh position.
label fcIndex(const label i) const noexcept
The forward circular index. The next index in the list which returns to the first at the end of the l...
Definition: UListI.H:90
label mergePoints(const PointList &points, labelList &pointToUnique, labelList &uniquePoints, const scalar mergeTol=SMALL, const bool verbose=false)
Calculate merge mapping, preserving the original point order. All points closer/equal mergeTol are to...
void reset(T *p=nullptr) noexcept
Delete managed object and set to new given pointer.
Definition: autoPtrI.H:37
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
const Field< point_type > & faceNormals() const
Return face unit normals for patch.
List< face > faceList
List of faces.
Definition: faceListFwd.H:39
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: POSIX.C:799
A list of faces which address into the list of points.
Omanip< int > setprecision(const int i)
Definition: IOmanip.H:205
const Map< label > & meshPointMap() const
Mesh point map.
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
void setSize(const label n)
Alias for resize()
Definition: List.H:320
scalar setErrorReduction(const scalar)
Set the errorReduction (by how much to scale the displacement.
FaceMergeType
Enumeration for what to do with co-planar patch faces on a single.
dynamicFvMesh & mesh
dimensionedScalar cos(const dimensionedScalar &ds)
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
const pointField & points
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.
label nFaceSplitInterval() const
label findZoneID(const word &zoneName) const
Find zone index by name, return -1 if not found.
Definition: ZoneMesh.C:718
const_iterator cfind(const Key &key) const
Find and return an const_iterator set at the hashed entry.
Definition: HashTableI.H:113
An edge is a list of two vertex labels. This can correspond to a directed graph edge or an edge on a ...
Definition: edge.H:59
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i), works like std::iota() but returning a...
Definition: labelLists.C:44
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:130
virtual int precision() const override
Get precision of output field.
Definition: OSstream.C:334
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:609
A class for handling words, derived from Foam::string.
Definition: word.H:63
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Simple container to keep together snap specific information.
autoPtr< mapPolyMesh > repatchToSurface(const snapParameters &snapParams, const labelList &adaptPatchIDs, const labelList &preserveFaces)
Repatch faces according to surface nearest the face centre.
label size() const noexcept
The number of entries in the list.
Definition: UPtrListI.H:106
const Field< point_type > & faceCentres() const
Return face centres for patch.
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1116
static void setDisplacement(const labelList &patchIDs, const indirectPrimitivePatch &pp, pointField &patchDisp, pointVectorField &displacement)
Set displacement field from displacement on patch points.
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:206
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
void smoothDisplacement(const snapParameters &snapParams, motionSmoother &) const
Smooth the displacement field to the internal.
const globalMeshData & globalData() const
Return parallel info (demand-driven)
Definition: polyMesh.C:1311
const edgeList & edges() const
Return list of edges, address into LOCAL point list.
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.
label nInternalFaces() const noexcept
Number of internal faces.
Vector< scalar > vector
Definition: vector.H:57
ZoneMesh< pointZone, polyMesh > pointZoneMesh
A ZoneMesh with the type pointZone.
const Field< point_type > & points() const noexcept
Return reference to global points.
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicList.H:584
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1103
const PtrList< surfaceZonesInfo > & surfZones() const
const vectorField & cellCentres() const
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:30
static labelList getUnnamedSurfaces(const PtrList< surfaceZonesInfo > &surfList)
Get indices of unnamed surfaces (surfaces without faceZoneName)
errorManip< error > abort(error &err)
Definition: errorManip.H:139
const T * set(const label i) const
Return const pointer to element (can be nullptr), or nullptr for out-of-range access (ie...
Definition: PtrList.H:159
label nEdges() const
Number of mesh edges.
static void syncPointList(const polyMesh &mesh, List< T > &pointValues, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh points.
const labelListList & pointCells() const
virtual bool write(const bool writeOnProc=true) const
Write mesh using IO settings from time.
Definition: fvMesh.C:1113
void smooth(const GeometricField< Type, pointPatchField, pointMesh > &fld, const scalarField &edgeWeight, GeometricField< Type, pointPatchField, pointMesh > &newFld) const
Fully explicit smoothing of fields (not positions)
word timeName() const
Replacement for Time::timeName() that returns oldInstance (if overwrite_)
static scalarField calcSnapDistance(const fvMesh &mesh, const snapParameters &snapParams, const indirectPrimitivePatch &)
Calculate edge length per patch point.
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO...
OSstream & stream(OSstream *alternative=nullptr)
Return OSstream for output operations.
Definition: messageStream.C:79
const labelListList & pointFaces() const
Return point-face addressing.
Istream and Ostream manipulators taking arguments.
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
An OFstream that keeps track of vertices and provides convenience output methods for OBJ files...
Definition: OBJstream.H:55
Smanip< std::ios_base::fmtflags > setf(std::ios_base::fmtflags flags)
Definition: IOmanip.H:169
int debug
Static debugging option.
static void mapFaceZonePoints(meshRefinement &meshRefiner, const mapPolyMesh &map, labelPairList &baffles, labelList &pointToMaster)
Map numbering after adding cell layers.
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:51
Type gMax(const FieldField< Field, Type > &f)
const faceZoneMesh & faceZones() const noexcept
Return face zone mesh.
Definition: polyMesh.H:671
defineTypeNameAndDebug(combustionModel, 0)
const indirectPrimitivePatch & patch() const
Reference to patch.
static tmp< pointField > avgCellCentres(const fvMesh &mesh, const indirectPrimitivePatch &)
Helper: calculate average cell centre per point.
void clear() noexcept
Clear the addressed list, i.e. set the size to zero.
Definition: DynamicListI.H:405
Geometric merging of points. See below.
labelList f(nPoints)
static autoPtr< indirectPrimitivePatch > makePatch(const polyMesh &, const labelList &)
Create patch from set of patches.
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].reset(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
double cpuTimeIncrement() const
Return CPU time [seconds] since last call to cpuTimeIncrement(), resetCpuTimeIncrement().
Definition: cpuTimePosix.C:86
messageStream Warning
Warning stream (stdout output on master, null elsewhere), with additional &#39;FOAM Warning&#39; header text...
Helper class which maintains intersections of (changing) mesh with (static) surfaces.
pointVectorField & pointDisplacement()
Return reference to the point motion displacement field.
bool moving() const noexcept
Is mesh moving.
Definition: polyMesh.H:732
const vectorField & faceCentres() const
const pointZoneMesh & pointZones() const noexcept
Return point zone mesh.
Definition: polyMesh.H:663
List< word > wordList
List of word.
Definition: fileName.H:59
label nSnap() const
Maximum number of snapping relaxation iterations. Should stop.
PrimitivePatch< UIndirectList< face >, const pointField & > uindirectPrimitivePatch
A PrimitivePatch with UIndirectList for the faces, const reference for the point field.
Internal::FieldType & primitiveFieldRef(const bool updateAccessTime=true)
Return a reference to the internal field values.
scalar snapTol() const
Relative distance for points to be attracted by surface.
vector point
Point is a vector.
Definition: point.H:37
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:59
#define WarningInFunction
Report a warning using Foam::Warning.
Switch strictRegionSnap() const
Attract point to corresponding surface region only.
label newPointi
Definition: readKivaGrid.H:496
Type gAverage(const FieldField< Field, Type > &f)
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers...
Definition: List.H:55
void detectNearSurfaces(const scalar planarCos, const indirectPrimitivePatch &pp, const pointField &ppLocalPoints, const pointField &nearestPoint, const vectorField &nearestNormal, vectorField &disp) const
Per patch point override displacement if in gap situation.
static bitSet getMasterPoints(const polyMesh &mesh, const labelList &meshPoints)
Determine master point for subset of points. If coupled.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
const char * end
Definition: SVGTools.H:223
const polyBoundaryMesh & patches
label globalRegion(const label surfI, const label regionI) const
From surface and region on surface to global region.
static labelList getNamedSurfaces(const PtrList< surfaceZonesInfo > &surfList)
Get indices of named surfaces (surfaces with faceZoneName)
messageStream Info
Information stream (stdout output on master, null elsewhere)
label nTotalFaces() const noexcept
Total global number of mesh faces. Not compensated for duplicate faces!
SubField< vector > subField
Declare type of subField.
Definition: Field.H:128
writeType
Enumeration for what to write. Used as a bit-pattern.
Field< vector > vectorField
Specialisation of Field<T> for vector.
faceZoneType
What to do with faceZone faces.
debugType
Enumeration for what to debug. Used as a bit-pattern.
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
A subset of mesh faces organised as a primitive patch.
Definition: faceZone.H:60
static void syncPoints(const polyMesh &mesh, List< weightedPosition > &)
Synchronisation for mesh point positions.
bool write() const
Write mesh and all data.
List< label > labelList
A List of labels.
Definition: List.H:62
static tmp< pointVectorField > makeDisplacementField(const pointMesh &pMesh, const labelList &adaptPatchIDs)
Helper function to make a pointVectorField with correct.
volScalarField & p
A class for managing temporary objects.
Definition: HashPtrTable.H:50
label nSmoothInternal() const
Number of internal point smoothing iterations (combined with.
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:69
bool coupled
static T gAverage(const bitSet &isMasterElem, const UList< T > &values)
Helper: calculate average.
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.
label rcIndex(const label i) const noexcept
The reverse circular index. The previous index in the list which returns to the last at the beginning...
Definition: UListI.H:97
static tmp< pointField > pointNormals(const polyMesh &, const PrimitivePatch< FaceList, PointField > &, const bitSet &flipMap=bitSet::null())
Return parallel consistent point normals for patches using mesh points.
static autoPtr< mapPolyMesh > dupFaceZonePoints(meshRefinement &meshRefiner, const labelList &patchIDs, const labelList &numLayers, List< labelPair > baffles, labelList &pointToMaster)
Duplicate points on faceZones with layers. Re-used when adding buffer layers. Can be made private aga...
bool returnReduceOr(const bool value, const label comm=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
constexpr scalar degToRad(const scalar deg) noexcept
Conversion from degrees to radians.
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
const dimensionedScalar mp
Proton mass.
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
Namespace for OpenFOAM.
pointVectorField & displacement()
Reference to displacement field.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127