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