snappyLayerDriver.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2015 OpenFOAM Foundation
9  Copyright (C) 2015-2020 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 Description
28  All to do with adding cell layers
29 
30 \*----------------------------------------------------------------------------*/
31 
32 #include "snappyLayerDriver.H"
33 #include "fvMesh.H"
34 #include "Time.H"
35 #include "meshRefinement.H"
36 #include "removePoints.H"
37 #include "pointFields.H"
38 #include "motionSmoother.H"
39 #include "unitConversion.H"
40 #include "pointSet.H"
41 #include "faceSet.H"
42 #include "cellSet.H"
43 #include "polyTopoChange.H"
44 #include "mapPolyMesh.H"
45 #include "addPatchCellLayer.H"
46 #include "mapDistributePolyMesh.H"
47 #include "OBJstream.H"
48 #include "layerParameters.H"
49 #include "combineFaces.H"
50 #include "IOmanip.H"
51 #include "globalIndex.H"
52 #include "DynamicField.H"
53 #include "PatchTools.H"
54 #include "slipPointPatchFields.H"
60 #include "localPointRegion.H"
62 #include "scalarIOField.H"
63 #include "profiling.H"
64 
65 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
66 
67 namespace Foam
68 {
69 
70 defineTypeNameAndDebug(snappyLayerDriver, 0);
71 
72 } // End namespace Foam
73 
74 
75 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
76 
77 // For debugging: Dump displacement to .obj files
78 void Foam::snappyLayerDriver::dumpDisplacement
79 (
80  const fileName& prefix,
81  const indirectPrimitivePatch& pp,
82  const vectorField& patchDisp,
83  const List<extrudeMode>& extrudeStatus
84 )
85 {
86  OBJstream dispStr(prefix + "_disp.obj");
87  Info<< "Writing all displacements to " << dispStr.name() << endl;
88 
89  forAll(patchDisp, patchPointi)
90  {
91  const point& pt = pp.localPoints()[patchPointi];
92  dispStr.write(linePointRef(pt, pt + patchDisp[patchPointi]));
93  }
94 
95 
96  OBJstream illStr(prefix + "_illegal.obj");
97  Info<< "Writing invalid displacements to " << illStr.name() << endl;
98 
99  forAll(patchDisp, patchPointi)
100  {
101  if (extrudeStatus[patchPointi] != EXTRUDE)
102  {
103  const point& pt = pp.localPoints()[patchPointi];
104  illStr.write(linePointRef(pt, pt + patchDisp[patchPointi]));
105  }
106  }
107 }
108 
109 
110 Foam::tmp<Foam::scalarField> Foam::snappyLayerDriver::avgPointData
111 (
112  const indirectPrimitivePatch& pp,
113  const scalarField& pointFld
114 )
115 {
116  tmp<scalarField> tfaceFld(new scalarField(pp.size(), Zero));
117  scalarField& faceFld = tfaceFld.ref();
118 
119  forAll(pp.localFaces(), facei)
120  {
121  const face& f = pp.localFaces()[facei];
122  if (f.size())
123  {
124  forAll(f, fp)
125  {
126  faceFld[facei] += pointFld[f[fp]];
127  }
128  faceFld[facei] /= f.size();
129  }
130  }
131  return tfaceFld;
132 }
133 
134 
135 // Check that primitivePatch is not multiply connected. Collect non-manifold
136 // points in pointSet.
137 void Foam::snappyLayerDriver::checkManifold
138 (
139  const indirectPrimitivePatch& fp,
140  pointSet& nonManifoldPoints
141 )
142 {
143  // Check for non-manifold points (surface pinched at point)
144  fp.checkPointManifold(false, &nonManifoldPoints);
145 
146  // Check for edge-faces (surface pinched at edge)
147  const labelListList& edgeFaces = fp.edgeFaces();
148 
149  forAll(edgeFaces, edgei)
150  {
151  const labelList& eFaces = edgeFaces[edgei];
152 
153  if (eFaces.size() > 2)
154  {
155  const edge& e = fp.edges()[edgei];
156 
157  nonManifoldPoints.insert(fp.meshPoints()[e[0]]);
158  nonManifoldPoints.insert(fp.meshPoints()[e[1]]);
159  }
160  }
161 }
162 
163 
164 void Foam::snappyLayerDriver::checkMeshManifold() const
165 {
166  const fvMesh& mesh = meshRefiner_.mesh();
167 
168  Info<< nl << "Checking mesh manifoldness ..." << endl;
169 
170  pointSet nonManifoldPoints
171  (
172  mesh,
173  "nonManifoldPoints",
174  mesh.nPoints() / 100
175  );
176 
177  // Build primitivePatch out of faces and check it for problems.
178  checkManifold
179  (
181  (
182  IndirectList<face>
183  (
184  mesh.faces(),
185  identity(mesh.boundaryMesh().range()) // All outside faces
186  ),
187  mesh.points()
188  ),
189  nonManifoldPoints
190  );
191 
192  label nNonManif = returnReduce(nonManifoldPoints.size(), sumOp<label>());
193 
194  if (nNonManif > 0)
195  {
196  Info<< "Outside of mesh is multiply connected across edges or"
197  << " points." << nl
198  << "This is not a fatal error but might cause some unexpected"
199  << " behaviour." << nl
200  //<< "Writing " << nNonManif
201  //<< " points where this happens to pointSet "
202  //<< nonManifoldPoints.name()
203  << endl;
204 
205  //nonManifoldPoints.instance() = meshRefiner_.timeName();
206  //nonManifoldPoints.write();
207  }
208  Info<< endl;
209 }
210 
211 
212 
213 // Unset extrusion on point. Returns true if anything unset.
214 bool Foam::snappyLayerDriver::unmarkExtrusion
215 (
216  const label patchPointi,
217  pointField& patchDisp,
218  labelList& patchNLayers,
219  List<extrudeMode>& extrudeStatus
220 )
221 {
222  if (extrudeStatus[patchPointi] == EXTRUDE)
223  {
224  extrudeStatus[patchPointi] = NOEXTRUDE;
225  patchNLayers[patchPointi] = 0;
226  patchDisp[patchPointi] = Zero;
227  return true;
228  }
229  else if (extrudeStatus[patchPointi] == EXTRUDEREMOVE)
230  {
231  extrudeStatus[patchPointi] = NOEXTRUDE;
232  patchNLayers[patchPointi] = 0;
233  patchDisp[patchPointi] = Zero;
234  return true;
235  }
236 
237  return false;
238 }
239 
240 
241 // Unset extrusion on face. Returns true if anything unset.
242 bool Foam::snappyLayerDriver::unmarkExtrusion
243 (
244  const face& localFace,
245  pointField& patchDisp,
246  labelList& patchNLayers,
247  List<extrudeMode>& extrudeStatus
248 )
249 {
250  bool unextruded = false;
251 
252  forAll(localFace, fp)
253  {
254  if
255  (
256  unmarkExtrusion
257  (
258  localFace[fp],
259  patchDisp,
260  patchNLayers,
261  extrudeStatus
262  )
263  )
264  {
265  unextruded = true;
266  }
267  }
268  return unextruded;
269 }
270 
271 
272 Foam::label Foam::snappyLayerDriver::constrainFp(const label sz, const label fp)
273 {
274  if (fp >= sz)
275  {
276  return 0;
277  }
278  else if (fp < 0)
279  {
280  return sz-1;
281  }
282  else
283  {
284  return fp;
285  }
286 }
287 
288 
289 void Foam::snappyLayerDriver::countCommonPoints
290 (
291  const indirectPrimitivePatch& pp,
292  const label facei,
293 
294  Map<label>& nCommonPoints
295 ) const
296 {
297  const faceList& localFaces = pp.localFaces();
298  const labelListList& pointFaces = pp.pointFaces();
299 
300  const face& f = localFaces[facei];
301 
302  nCommonPoints.clear();
303 
304  forAll(f, fp)
305  {
306  label pointi = f[fp];
307  const labelList& pFaces = pointFaces[pointi];
308 
309  forAll(pFaces, pFacei)
310  {
311  label nbFacei = pFaces[pFacei];
312 
313  if (facei < nbFacei)
314  {
315  // Only check once for each combination of two faces.
316  ++(nCommonPoints(nbFacei, 0));
317  }
318  }
319  }
320 }
321 
322 
323 bool Foam::snappyLayerDriver::checkCommonOrder
324 (
325  const label nCommon,
326  const face& curFace,
327  const face& nbFace
328 ) const
329 {
330  forAll(curFace, fp)
331  {
332  // Get the index in the neighbouring face shared with curFace
333  const label nb = nbFace.find(curFace[fp]);
334 
335  if (nb != -1)
336  {
337 
338  // Check the whole face from nb onwards for shared vertices
339  // with neighbouring face. Rule is that any shared vertices
340  // should be consecutive on both faces i.e. if they are
341  // vertices fp,fp+1,fp+2 on one face they should be
342  // vertices nb, nb+1, nb+2 (or nb+2, nb+1, nb) on the
343  // other face.
344 
345 
346  // Vertices before and after on curFace
347  label fpPlus1 = curFace.fcIndex(fp);
348  label fpMin1 = curFace.rcIndex(fp);
349 
350  // Vertices before and after on nbFace
351  label nbPlus1 = nbFace.fcIndex(nb);
352  label nbMin1 = nbFace.rcIndex(nb);
353 
354  // Find order of walking by comparing next points on both
355  // faces.
356  label curInc = labelMax;
357  label nbInc = labelMax;
358 
359  if (nbFace[nbPlus1] == curFace[fpPlus1])
360  {
361  curInc = 1;
362  nbInc = 1;
363  }
364  else if (nbFace[nbPlus1] == curFace[fpMin1])
365  {
366  curInc = -1;
367  nbInc = 1;
368  }
369  else if (nbFace[nbMin1] == curFace[fpMin1])
370  {
371  curInc = -1;
372  nbInc = -1;
373  }
374  else
375  {
376  curInc = 1;
377  nbInc = -1;
378  }
379 
380 
381  // Pass1: loop until start of common vertices found.
382  label curNb = nb;
383  label curFp = fp;
384 
385  do
386  {
387  curFp = constrainFp(curFace.size(), curFp+curInc);
388  curNb = constrainFp(nbFace.size(), curNb+nbInc);
389  } while (curFace[curFp] == nbFace[curNb]);
390 
391  // Pass2: check equality walking from curFp, curNb
392  // in opposite order.
393 
394  curInc = -curInc;
395  nbInc = -nbInc;
396 
397  for (label commonI = 0; commonI < nCommon; commonI++)
398  {
399  curFp = constrainFp(curFace.size(), curFp+curInc);
400  curNb = constrainFp(nbFace.size(), curNb+nbInc);
401 
402  if (curFace[curFp] != nbFace[curNb])
403  {
404  // Error: gap in string of connected vertices
405  return false;
406  }
407  }
408 
409  // Done the curFace - nbFace combination.
410  break;
411  }
412  }
413 
414  return true;
415 }
416 
417 
418 void Foam::snappyLayerDriver::checkCommonOrder
419 (
420  const indirectPrimitivePatch& pp,
421  const label facei,
422  const Map<label>& nCommonPoints,
423  pointField& patchDisp,
424  labelList& patchNLayers,
425  List<extrudeMode>& extrudeStatus
426 ) const
427 {
428  forAllConstIters(nCommonPoints, iter)
429  {
430  const label nbFacei = iter.key();
431  const label nCommon = iter.val();
432 
433  const face& curFace = pp[facei];
434  const face& nbFace = pp[nbFacei];
435 
436  if
437  (
438  nCommon >= 2
439  && nCommon != nbFace.size()
440  && nCommon != curFace.size()
441  )
442  {
443  bool stringOk = checkCommonOrder(nCommon, curFace, nbFace);
444 
445  if (!stringOk)
446  {
447  // Note: unmark whole face or just the common points?
448  // For now unmark the whole face
449  unmarkExtrusion
450  (
451  pp.localFaces()[facei],
452  patchDisp,
453  patchNLayers,
454  extrudeStatus
455  );
456  unmarkExtrusion
457  (
458  pp.localFaces()[nbFacei],
459  patchDisp,
460  patchNLayers,
461  extrudeStatus
462  );
463  }
464  }
465  }
466 }
467 
468 
469 void Foam::snappyLayerDriver::handleNonStringConnected
470 (
471  const indirectPrimitivePatch& pp,
472  pointField& patchDisp,
473  labelList& patchNLayers,
474  List<extrudeMode>& extrudeStatus
475 ) const
476 {
477  // Detect faces which are connected on non-consecutive vertices.
478  // This is the "<<Number of faces with non-consecutive shared points"
479  // warning from checkMesh. These faces cannot be extruded so
480  // there is no need to even attempt it.
481 
482  List<extrudeMode> oldExtrudeStatus;
483  autoPtr<OBJstream> str;
485  {
486  oldExtrudeStatus = extrudeStatus;
487  str.reset
488  (
489  new OBJstream
490  (
491  meshRefiner_.mesh().time().path()
492  /"nonStringConnected.obj"
493  )
494  );
495  Pout<< "Dumping string edges to " << str().name();
496  }
497 
498 
499  // 1) Local
500  Map<label> nCommonPoints(128);
501 
502  forAll(pp, facei)
503  {
504  countCommonPoints(pp, facei, nCommonPoints);
505 
506  // Faces share pointi. Find any more shared points
507  // and if not in single string unmark all. See
508  // primitiveMesh::checkCommonOrder
509  checkCommonOrder
510  (
511  pp,
512  facei,
513  nCommonPoints,
514 
515  patchDisp,
516  patchNLayers,
517  extrudeStatus
518  );
519  }
520 
521  // 2) TDB. Other face remote
522 
523 
524 
526  {
527  forAll(extrudeStatus, pointi)
528  {
529  if (extrudeStatus[pointi] != oldExtrudeStatus[pointi])
530  {
531  str().write
532  (
533  meshRefiner_.mesh().points()[pp.meshPoints()[pointi]]
534  );
535  }
536  }
537  }
538 }
539 
540 
541 // No extrusion at non-manifold points.
542 void Foam::snappyLayerDriver::handleNonManifolds
543 (
544  const indirectPrimitivePatch& pp,
545  const labelList& meshEdges,
546  const labelListList& edgeGlobalFaces,
547  pointField& patchDisp,
548  labelList& patchNLayers,
549  List<extrudeMode>& extrudeStatus
550 ) const
551 {
552  const fvMesh& mesh = meshRefiner_.mesh();
553 
554  Info<< nl << "Handling non-manifold points ..." << endl;
555 
556  // Detect non-manifold points
557  Info<< nl << "Checking patch manifoldness ..." << endl;
558 
559  pointSet nonManifoldPoints(mesh, "nonManifoldPoints", pp.nPoints());
560 
561  // 1. Local check. Note that we do not check for e.g. two patch faces
562  // being connected via a point since their connection might be ok
563  // through a coupled patch. The ultimate is to do a proper point-face
564  // walk which is done when actually duplicating the points. Here we just
565  // do the obvious problems.
566  {
567  // Check for edge-faces (surface pinched at edge)
568  const labelListList& edgeFaces = pp.edgeFaces();
569 
570  forAll(edgeFaces, edgei)
571  {
572  const labelList& eFaces = edgeFaces[edgei];
573  if (eFaces.size() > 2)
574  {
575  const edge& e = pp.edges()[edgei];
576  nonManifoldPoints.insert(pp.meshPoints()[e[0]]);
577  nonManifoldPoints.insert(pp.meshPoints()[e[1]]);
578  }
579  }
580  }
581 
582  // 2. Remote check for boundary edges on coupled boundaries
583  forAll(edgeGlobalFaces, edgei)
584  {
585  if (edgeGlobalFaces[edgei].size() > 2)
586  {
587  // So boundary edges that are connected to more than 2 processors
588  // i.e. a non-manifold edge which is exactly on a processor
589  // boundary.
590  const edge& e = pp.edges()[edgei];
591  nonManifoldPoints.insert(pp.meshPoints()[e[0]]);
592  nonManifoldPoints.insert(pp.meshPoints()[e[1]]);
593  }
594  }
595 
596 
597  label nNonManif = returnReduce(nonManifoldPoints.size(), sumOp<label>());
598 
599  Info<< "Outside of local patch is multiply connected across edges or"
600  << " points at " << nNonManif << " points." << endl;
601 
602  if (nNonManif > 0)
603  {
604  // Make sure all processors use the same information. The edge might
605  // not exist locally but remotely there might be a problem with this
606  // edge.
607  nonManifoldPoints.sync(mesh);
608 
609  const labelList& meshPoints = pp.meshPoints();
610 
611  forAll(meshPoints, patchPointi)
612  {
613  if (nonManifoldPoints.found(meshPoints[patchPointi]))
614  {
615  unmarkExtrusion
616  (
617  patchPointi,
618  patchDisp,
619  patchNLayers,
620  extrudeStatus
621  );
622  }
623  }
624  }
625 
626  Info<< "Set displacement to zero for all " << nNonManif
627  << " non-manifold points" << endl;
628 
629 
630 
631  // 4. Check for extrusion of baffles i.e. all edges of a face having the
632  // same two neighbouring faces (one of which is the current face).
633  // Note: this is detected locally already before - this test is for the
634  // extremely rare occurrence where the baffle faces are on
635  // different processors.
636  {
637  label nBaffleFaces = 0;
638 
639  const labelListList& faceEdges = pp.faceEdges();
640  forAll(pp, facei)
641  {
642  const labelList& fEdges = faceEdges[facei];
643 
644  const labelList& globFaces0 = edgeGlobalFaces[fEdges[0]];
645  if (globFaces0.size() == 2)
646  {
647  const edge e0(globFaces0[0], globFaces0[1]);
648  bool isBaffle = true;
649  for (label fp = 1; fp < fEdges.size(); fp++)
650  {
651  const labelList& globFaces = edgeGlobalFaces[fEdges[fp]];
652  if
653  (
654  (globFaces.size() != 2)
655  || (edge(globFaces[0], globFaces[1]) != e0)
656  )
657  {
658  isBaffle = false;
659  break;
660  }
661  }
662 
663  if (isBaffle)
664  {
665  bool unextrude = unmarkExtrusion
666  (
667  pp.localFaces()[facei],
668  patchDisp,
669  patchNLayers,
670  extrudeStatus
671  );
672  if (unextrude)
673  {
674  //Pout<< "Detected extrusion of baffle face "
675  // << pp.faceCentres()[facei]
676  // << " since all edges have the same neighbours "
677  // << e0 << endl;
678 
679  nBaffleFaces++;
680  }
681  }
682  }
683  }
684 
685  reduce(nBaffleFaces, sumOp<label>());
686 
687  if (nBaffleFaces)
688  {
689  Info<< "Set displacement to zero for all points on " << nBaffleFaces
690  << " baffle faces" << endl;
691  }
692  }
693 }
694 
695 
696 // Parallel feature edge detection. Assumes non-manifold edges already handled.
697 void Foam::snappyLayerDriver::handleFeatureAngle
698 (
699  const indirectPrimitivePatch& pp,
700  const labelList& meshEdges,
701  const scalar minAngle,
702  pointField& patchDisp,
703  labelList& patchNLayers,
704  List<extrudeMode>& extrudeStatus
705 ) const
706 {
707  const fvMesh& mesh = meshRefiner_.mesh();
708 
709  const scalar minCos = Foam::cos(degToRad(minAngle));
710 
711  Info<< nl << "Handling feature edges (angle < " << minAngle
712  << ") ..." << endl;
713 
714  if (minCos < 1-SMALL && minCos > -1+SMALL)
715  {
716  // Normal component of normals of connected faces.
717  vectorField edgeNormal(mesh.nEdges(), point::max);
718 
719  const labelListList& edgeFaces = pp.edgeFaces();
720 
721  forAll(edgeFaces, edgei)
722  {
723  const labelList& eFaces = pp.edgeFaces()[edgei];
724 
725  label meshEdgei = meshEdges[edgei];
726 
727  forAll(eFaces, i)
728  {
729  nomalsCombine()
730  (
731  edgeNormal[meshEdgei],
732  pp.faceNormals()[eFaces[i]]
733  );
734  }
735  }
736 
738  (
739  mesh,
740  edgeNormal,
741  nomalsCombine(),
742  point::max // null value
743  );
744 
745  autoPtr<OBJstream> str;
747  {
748  str.reset
749  (
750  new OBJstream
751  (
752  mesh.time().path()
753  / "featureEdges_"
754  + meshRefiner_.timeName()
755  + ".obj"
756  )
757  );
758  Info<< "Writing feature edges to " << str().name() << endl;
759  }
760 
761  label nFeats = 0;
762 
763  // Now on coupled edges the edgeNormal will have been truncated and
764  // only be still be the old value where two faces have the same normal
765  forAll(edgeFaces, edgei)
766  {
767  const labelList& eFaces = pp.edgeFaces()[edgei];
768 
769  label meshEdgei = meshEdges[edgei];
770 
771  const vector& n = edgeNormal[meshEdgei];
772 
773  if (n != point::max)
774  {
775  scalar cos = n & pp.faceNormals()[eFaces[0]];
776 
777  if (cos < minCos)
778  {
779  const edge& e = pp.edges()[edgei];
780 
781  unmarkExtrusion
782  (
783  e[0],
784  patchDisp,
785  patchNLayers,
786  extrudeStatus
787  );
788  unmarkExtrusion
789  (
790  e[1],
791  patchDisp,
792  patchNLayers,
793  extrudeStatus
794  );
795 
796  nFeats++;
797 
798  if (str)
799  {
800  const point& p0 = pp.localPoints()[e[0]];
801  const point& p1 = pp.localPoints()[e[1]];
802  str().write(linePointRef(p0, p1));
803  }
804  }
805  }
806  }
807 
808  Info<< "Set displacement to zero for points on "
809  << returnReduce(nFeats, sumOp<label>())
810  << " feature edges" << endl;
811  }
812 }
813 
814 
815 // No extrusion on cells with warped faces. Calculates the thickness of the
816 // layer and compares it to the space the warped face takes up. Disables
817 // extrusion if layer thickness is more than faceRatio of the thickness of
818 // the face.
819 void Foam::snappyLayerDriver::handleWarpedFaces
820 (
821  const indirectPrimitivePatch& pp,
822  const scalar faceRatio,
823  const boolList& relativeSizes,
824  const scalar edge0Len,
825  const labelList& cellLevel,
826  pointField& patchDisp,
827  labelList& patchNLayers,
828  List<extrudeMode>& extrudeStatus
829 ) const
830 {
831  const fvMesh& mesh = meshRefiner_.mesh();
832  const polyBoundaryMesh& patches = mesh.boundaryMesh();
833 
834  Info<< nl << "Handling cells with warped patch faces ..." << nl;
835 
836  const pointField& points = mesh.points();
837 
838  // Local reference to face centres also used to trigger consistent
839  // [re-]building of demand-driven face centres and areas
840  const vectorField& faceCentres = mesh.faceCentres();
841 
842  label nWarpedFaces = 0;
843 
844  forAll(pp, i)
845  {
846  const face& f = pp[i];
847  label faceI = pp.addressing()[i];
848  label patchI = patches.patchID()[faceI-mesh.nInternalFaces()];
849 
850  // It is hard to calculate some length scale if not in relative
851  // mode so disable this check.
852 
853  if (relativeSizes[patchI] && f.size() > 3)
854  {
855  label ownLevel = cellLevel[mesh.faceOwner()[faceI]];
856  scalar edgeLen = edge0Len/(1<<ownLevel);
857 
858  // Normal distance to face centre plane
859  const point& fc = faceCentres[faceI];
860  const vector& fn = pp.faceNormals()[i];
861 
862  scalarField vProj(f.size());
863 
864  forAll(f, fp)
865  {
866  vector n = points[f[fp]] - fc;
867  vProj[fp] = (n & fn);
868  }
869 
870  // Get normal 'span' of face
871  scalar minVal = min(vProj);
872  scalar maxVal = max(vProj);
873 
874  if ((maxVal - minVal) > faceRatio * edgeLen)
875  {
876  if
877  (
878  unmarkExtrusion
879  (
880  pp.localFaces()[i],
881  patchDisp,
882  patchNLayers,
883  extrudeStatus
884  )
885  )
886  {
887  nWarpedFaces++;
888  }
889  }
890  }
891  }
892 
893  Info<< "Set displacement to zero on "
894  << returnReduce(nWarpedFaces, sumOp<label>())
895  << " warped faces since layer would be > " << faceRatio
896  << " of the size of the bounding box." << endl;
897 }
898 
899 
902 //void Foam::snappyLayerDriver::handleMultiplePatchFaces
903 //(
904 // const indirectPrimitivePatch& pp,
905 // pointField& patchDisp,
906 // labelList& patchNLayers,
907 // List<extrudeMode>& extrudeStatus
908 //) const
909 //{
910 // const fvMesh& mesh = meshRefiner_.mesh();
911 //
912 // Info<< nl << "Handling cells with multiple patch faces ..." << nl;
913 //
914 // const labelListList& pointFaces = pp.pointFaces();
915 //
916 // // Cells that should not get an extrusion layer
917 // cellSet multiPatchCells(mesh, "multiPatchCells", pp.size());
918 //
919 // // Detect points that use multiple faces on same cell.
920 // forAll(pointFaces, patchPointi)
921 // {
922 // const labelList& pFaces = pointFaces[patchPointi];
923 //
924 // labelHashSet pointCells(pFaces.size());
925 //
926 // forAll(pFaces, i)
927 // {
928 // label celli = mesh.faceOwner()[pp.addressing()[pFaces[i]]];
929 //
930 // if (!pointCells.insert(celli))
931 // {
932 // // Second or more occurrence of cell so cell has two or more
933 // // pp faces connected to this point.
934 // multiPatchCells.insert(celli);
935 // }
936 // }
937 // }
938 //
939 // label nMultiPatchCells = returnReduce
940 // (
941 // multiPatchCells.size(),
942 // sumOp<label>()
943 // );
944 //
945 // Info<< "Detected " << nMultiPatchCells
946 // << " cells with multiple (connected) patch faces." << endl;
947 //
948 // label nChanged = 0;
949 //
950 // if (nMultiPatchCells > 0)
951 // {
952 // multiPatchCells.instance() = meshRefiner_.timeName();
953 // Info<< "Writing " << nMultiPatchCells
954 // << " cells with multiple (connected) patch faces to cellSet "
955 // << multiPatchCells.objectPath() << endl;
956 // multiPatchCells.write();
957 //
958 //
959 // // Go through all points and remove extrusion on any cell in
960 // // multiPatchCells
961 // // (has to be done in separate loop since having one point on
962 // // multipatches has to reset extrusion on all points of cell)
963 //
964 // forAll(pointFaces, patchPointi)
965 // {
966 // if (extrudeStatus[patchPointi] != NOEXTRUDE)
967 // {
968 // const labelList& pFaces = pointFaces[patchPointi];
969 //
970 // forAll(pFaces, i)
971 // {
972 // label celli =
973 // mesh.faceOwner()[pp.addressing()[pFaces[i]]];
974 //
975 // if (multiPatchCells.found(celli))
976 // {
977 // if
978 // (
979 // unmarkExtrusion
980 // (
981 // patchPointi,
982 // patchDisp,
983 // patchNLayers,
984 // extrudeStatus
985 // )
986 // )
987 // {
988 // nChanged++;
989 // }
990 // }
991 // }
992 // }
993 // }
994 //
995 // reduce(nChanged, sumOp<label>());
996 // }
997 //
998 // Info<< "Prevented extrusion on " << nChanged
999 // << " points due to multiple patch faces." << nl << endl;
1000 //}
1001 
1002 
1003 void Foam::snappyLayerDriver::setNumLayers
1004 (
1005  const labelList& patchToNLayers,
1006  const labelList& patchIDs,
1007  const indirectPrimitivePatch& pp,
1008  pointField& patchDisp,
1009  labelList& patchNLayers,
1010  List<extrudeMode>& extrudeStatus,
1011  label& nAddedCells
1012 ) const
1013 {
1014  const fvMesh& mesh = meshRefiner_.mesh();
1015 
1016  Info<< nl << "Handling points with inconsistent layer specification ..."
1017  << endl;
1018 
1019  // Get for every point (really only necessary on patch external points)
1020  // the max and min of any patch faces using it.
1021  labelList maxLayers(patchNLayers.size(), labelMin);
1022  labelList minLayers(patchNLayers.size(), labelMax);
1023 
1024  forAll(patchIDs, i)
1025  {
1026  label patchi = patchIDs[i];
1027 
1028  const labelList& meshPoints = mesh.boundaryMesh()[patchi].meshPoints();
1029 
1030  label wantedLayers = patchToNLayers[patchi];
1031 
1032  forAll(meshPoints, patchPointi)
1033  {
1034  label ppPointi = pp.meshPointMap()[meshPoints[patchPointi]];
1035 
1036  maxLayers[ppPointi] = max(wantedLayers, maxLayers[ppPointi]);
1037  minLayers[ppPointi] = min(wantedLayers, minLayers[ppPointi]);
1038  }
1039  }
1040 
1042  (
1043  mesh,
1044  pp.meshPoints(),
1045  maxLayers,
1046  maxEqOp<label>(),
1047  labelMin // null value
1048  );
1050  (
1051  mesh,
1052  pp.meshPoints(),
1053  minLayers,
1054  minEqOp<label>(),
1055  labelMax // null value
1056  );
1057 
1058  // Unmark any point with different min and max
1059  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1060 
1061  //label nConflicts = 0;
1062 
1063  forAll(maxLayers, i)
1064  {
1065  if (maxLayers[i] == labelMin || minLayers[i] == labelMax)
1066  {
1068  << "Patchpoint:" << i << " coord:" << pp.localPoints()[i]
1069  << " maxLayers:" << maxLayers
1070  << " minLayers:" << minLayers
1071  << abort(FatalError);
1072  }
1073  else if (maxLayers[i] == minLayers[i])
1074  {
1075  // Ok setting.
1076  patchNLayers[i] = maxLayers[i];
1077  }
1078  else
1079  {
1080  // Inconsistent num layers between patch faces using point
1081  //if
1082  //(
1083  // unmarkExtrusion
1084  // (
1085  // i,
1086  // patchDisp,
1087  // patchNLayers,
1088  // extrudeStatus
1089  // )
1090  //)
1091  //{
1092  // nConflicts++;
1093  //}
1094  patchNLayers[i] = maxLayers[i];
1095  }
1096  }
1097 
1098 
1099  // Calculate number of cells to create
1100  nAddedCells = 0;
1101  forAll(pp.localFaces(), facei)
1102  {
1103  const face& f = pp.localFaces()[facei];
1104 
1105  // Get max of extrusion per point
1106  label nCells = 0;
1107  forAll(f, fp)
1108  {
1109  nCells = max(nCells, patchNLayers[f[fp]]);
1110  }
1111 
1112  nAddedCells += nCells;
1113  }
1114  reduce(nAddedCells, sumOp<label>());
1115 
1116  //reduce(nConflicts, sumOp<label>());
1117  //
1118  //Info<< "Set displacement to zero for " << nConflicts
1119  // << " points due to points being on multiple regions"
1120  // << " with inconsistent nLayers specification." << endl;
1121 }
1122 
1123 
1124 // Construct pointVectorField with correct boundary conditions for adding
1125 // layers
1127 Foam::snappyLayerDriver::makeLayerDisplacementField
1128 (
1129  const pointMesh& pMesh,
1130  const labelList& numLayers
1131 )
1132 {
1133  // Construct displacement field.
1134  const pointBoundaryMesh& pointPatches = pMesh.boundary();
1135 
1136  wordList patchFieldTypes
1137  (
1138  pointPatches.size(),
1139  slipPointPatchVectorField::typeName
1140  );
1141  wordList actualPatchTypes(patchFieldTypes.size());
1142  forAll(pointPatches, patchi)
1143  {
1144  actualPatchTypes[patchi] = pointPatches[patchi].type();
1145  }
1146 
1147  forAll(numLayers, patchi)
1148  {
1149  // 0 layers: do not allow slip so fixedValue 0
1150  // >0 layers: fixedValue which gets adapted
1151  if (numLayers[patchi] == 0)
1152  {
1153  patchFieldTypes[patchi] =
1154  zeroFixedValuePointPatchVectorField::typeName;
1155  }
1156  else if (numLayers[patchi] > 0)
1157  {
1158  patchFieldTypes[patchi] = fixedValuePointPatchVectorField::typeName;
1159  }
1160  }
1161 
1162  forAll(pointPatches, patchi)
1163  {
1164  if (isA<processorPointPatch>(pointPatches[patchi]))
1165  {
1166  patchFieldTypes[patchi] = calculatedPointPatchVectorField::typeName;
1167  }
1168  else if (isA<cyclicPointPatch>(pointPatches[patchi]))
1169  {
1170  patchFieldTypes[patchi] = cyclicSlipPointPatchVectorField::typeName;
1171  }
1172  }
1173 
1174 
1175  const polyMesh& mesh = pMesh();
1176 
1177  // Note: time().timeName() instead of meshRefinement::timeName() since
1178  // postprocessable field.
1179 
1181  (
1182  IOobject
1183  (
1184  "pointDisplacement",
1185  mesh.time().timeName(),
1186  mesh,
1189  ),
1190  pMesh,
1192  patchFieldTypes,
1193  actualPatchTypes
1194  );
1195 }
1196 
1197 
1198 void Foam::snappyLayerDriver::growNoExtrusion
1199 (
1200  const indirectPrimitivePatch& pp,
1201  pointField& patchDisp,
1202  labelList& patchNLayers,
1203  List<extrudeMode>& extrudeStatus
1204 ) const
1205 {
1206  Info<< nl << "Growing non-extrusion points by one layer ..." << endl;
1207 
1208  List<extrudeMode> grownExtrudeStatus(extrudeStatus);
1209 
1210  const faceList& localFaces = pp.localFaces();
1211 
1212  label nGrown = 0;
1213 
1214  forAll(localFaces, facei)
1215  {
1216  const face& f = localFaces[facei];
1217 
1218  bool hasSqueeze = false;
1219  forAll(f, fp)
1220  {
1221  if (extrudeStatus[f[fp]] == NOEXTRUDE)
1222  {
1223  hasSqueeze = true;
1224  break;
1225  }
1226  }
1227 
1228  if (hasSqueeze)
1229  {
1230  // Squeeze all points of face
1231  forAll(f, fp)
1232  {
1233  if
1234  (
1235  extrudeStatus[f[fp]] == EXTRUDE
1236  && grownExtrudeStatus[f[fp]] != NOEXTRUDE
1237  )
1238  {
1239  grownExtrudeStatus[f[fp]] = NOEXTRUDE;
1240  nGrown++;
1241  }
1242  }
1243  }
1244  }
1245 
1246  extrudeStatus.transfer(grownExtrudeStatus);
1247 
1248 
1249  // Synchronise since might get called multiple times.
1250  // Use the fact that NOEXTRUDE is the minimum value.
1251  {
1252  labelList status(extrudeStatus.size());
1253  forAll(status, i)
1254  {
1255  status[i] = extrudeStatus[i];
1256  }
1258  (
1259  meshRefiner_.mesh(),
1260  pp.meshPoints(),
1261  status,
1262  minEqOp<label>(),
1263  labelMax // null value
1264  );
1265  forAll(status, i)
1266  {
1267  extrudeStatus[i] = extrudeMode(status[i]);
1268  }
1269  }
1270 
1271 
1272  forAll(extrudeStatus, patchPointi)
1273  {
1274  if (extrudeStatus[patchPointi] == NOEXTRUDE)
1275  {
1276  patchDisp[patchPointi] = Zero;
1277  patchNLayers[patchPointi] = 0;
1278  }
1279  }
1280 
1281  reduce(nGrown, sumOp<label>());
1282 
1283  Info<< "Set displacement to zero for an additional " << nGrown
1284  << " points." << endl;
1285 }
1286 
1287 
1288 void Foam::snappyLayerDriver::determineSidePatches
1289 (
1290  const globalIndex& globalFaces,
1291  const labelListList& edgeGlobalFaces,
1292  const indirectPrimitivePatch& pp,
1293 
1294  labelList& edgePatchID,
1295  labelList& edgeZoneID,
1296  boolList& edgeFlip,
1297  labelList& inflateFaceID
1298 )
1299 {
1300  // Sometimes edges-to-be-extruded are on more than 2 processors.
1301  // Work out which 2 hold the faces to be extruded and thus which procpatch
1302  // the edge-face should be in. As an additional complication this might
1303  // mean that 2 procesors that were only edge-connected now suddenly need
1304  // to become face-connected i.e. have a processor patch between them.
1305 
1306  fvMesh& mesh = meshRefiner_.mesh();
1307 
1308  // Determine edgePatchID. Any additional processor boundary gets added to
1309  // patchToNbrProc,nbrProcToPatch and nPatches gets set to the new number
1310  // of patches.
1311  // Note: faceZones are at this point split into baffles so any zone
1312  // information might also come from boundary faces (hence
1313  // zoneFromAnyFace set in call to calcExtrudeInfo)
1314  label nPatches;
1315  Map<label> nbrProcToPatch;
1316  Map<label> patchToNbrProc;
1318  (
1319  true, // zoneFromAnyFace
1320 
1321  mesh,
1322  globalFaces,
1323  edgeGlobalFaces,
1324  pp,
1325 
1326  edgePatchID,
1327  nPatches,
1328  nbrProcToPatch,
1329  patchToNbrProc,
1330  edgeZoneID,
1331  edgeFlip,
1332  inflateFaceID
1333  );
1334 
1335  label nOldPatches = mesh.boundaryMesh().size();
1336  label nAdded = returnReduce(nPatches-nOldPatches, sumOp<label>());
1337  Info<< nl << "Adding in total " << nAdded/2 << " inter-processor patches to"
1338  << " handle extrusion of non-manifold processor boundaries."
1339  << endl;
1340 
1341  if (nAdded > 0)
1342  {
1343  // We might not add patches in same order as in patchToNbrProc
1344  // so prepare to renumber edgePatchID
1345  Map<label> wantedToAddedPatch;
1346 
1347  for (label patchi = nOldPatches; patchi < nPatches; patchi++)
1348  {
1349  label nbrProci = patchToNbrProc[patchi];
1350  word name
1351  (
1353  );
1354 
1355  dictionary patchDict;
1356  patchDict.add("type", processorPolyPatch::typeName);
1357  patchDict.add("myProcNo", Pstream::myProcNo());
1358  patchDict.add("neighbProcNo", nbrProci);
1359  patchDict.add("nFaces", 0);
1360  patchDict.add("startFace", mesh.nFaces());
1361 
1362  //Pout<< "Adding patch " << patchi
1363  // << " name:" << name
1364  // << " between " << Pstream::myProcNo()
1365  // << " and " << nbrProci << endl;
1366 
1367  label procPatchi = meshRefiner_.appendPatch
1368  (
1369  mesh,
1370  mesh.boundaryMesh().size(), // new patch index
1371  name,
1372  patchDict
1373  );
1374  wantedToAddedPatch.insert(patchi, procPatchi);
1375  }
1376 
1377  // Renumber edgePatchID
1378  forAll(edgePatchID, i)
1379  {
1380  label patchi = edgePatchID[i];
1381  const auto fnd = wantedToAddedPatch.cfind(patchi);
1382  if (fnd.found())
1383  {
1384  edgePatchID[i] = fnd.val();
1385  }
1386  }
1387 
1388  mesh.clearOut();
1389  const_cast<polyBoundaryMesh&>(mesh.boundaryMesh()).updateMesh();
1390  }
1391 }
1392 
1393 
1394 void Foam::snappyLayerDriver::calculateLayerThickness
1395 (
1396  const indirectPrimitivePatch& pp,
1397  const labelList& patchIDs,
1398  const layerParameters& layerParams,
1399  const labelList& cellLevel,
1400  const labelList& patchNLayers,
1401  const scalar edge0Len,
1402 
1403  scalarField& thickness,
1404  scalarField& minThickness,
1405  scalarField& expansionRatio
1406 ) const
1407 {
1408  const fvMesh& mesh = meshRefiner_.mesh();
1409  const polyBoundaryMesh& patches = mesh.boundaryMesh();
1410 
1411 
1412  // Rework patch-wise layer parameters into minimum per point
1413  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1414  // Note: only layer parameters consistent with layer specification
1415  // method (see layerParameters) will be correct.
1416  scalarField firstLayerThickness(pp.nPoints(), GREAT);
1417  scalarField finalLayerThickness(pp.nPoints(), GREAT);
1418  scalarField totalThickness(pp.nPoints(), GREAT);
1419  scalarField expRatio(pp.nPoints(), GREAT);
1420 
1421  minThickness.setSize(pp.nPoints());
1422  minThickness = GREAT;
1423 
1424  thickness.setSize(pp.nPoints());
1425  thickness = GREAT;
1426 
1427  expansionRatio.setSize(pp.nPoints());
1428  expansionRatio = GREAT;
1429 
1430  for (const label patchi : patchIDs)
1431  {
1432  const labelList& meshPoints = patches[patchi].meshPoints();
1433 
1434  forAll(meshPoints, patchPointi)
1435  {
1436  label ppPointi = pp.meshPointMap()[meshPoints[patchPointi]];
1437 
1438  firstLayerThickness[ppPointi] = min
1439  (
1440  firstLayerThickness[ppPointi],
1441  layerParams.firstLayerThickness()[patchi]
1442  );
1443  finalLayerThickness[ppPointi] = min
1444  (
1445  finalLayerThickness[ppPointi],
1446  layerParams.finalLayerThickness()[patchi]
1447  );
1448  totalThickness[ppPointi] = min
1449  (
1450  totalThickness[ppPointi],
1451  layerParams.thickness()[patchi]
1452  );
1453  expRatio[ppPointi] = min
1454  (
1455  expRatio[ppPointi],
1456  layerParams.expansionRatio()[patchi]
1457  );
1458  minThickness[ppPointi] = min
1459  (
1460  minThickness[ppPointi],
1461  layerParams.minThickness()[patchi]
1462  );
1463  }
1464  }
1465 
1467  (
1468  mesh,
1469  pp.meshPoints(),
1470  firstLayerThickness,
1471  minEqOp<scalar>(),
1472  GREAT // null value
1473  );
1475  (
1476  mesh,
1477  pp.meshPoints(),
1478  finalLayerThickness,
1479  minEqOp<scalar>(),
1480  GREAT // null value
1481  );
1483  (
1484  mesh,
1485  pp.meshPoints(),
1486  totalThickness,
1487  minEqOp<scalar>(),
1488  GREAT // null value
1489  );
1491  (
1492  mesh,
1493  pp.meshPoints(),
1494  expRatio,
1495  minEqOp<scalar>(),
1496  GREAT // null value
1497  );
1499  (
1500  mesh,
1501  pp.meshPoints(),
1502  minThickness,
1503  minEqOp<scalar>(),
1504  GREAT // null value
1505  );
1506 
1507 
1508  // Now the thicknesses are set according to the minimum of connected
1509  // patches.
1510 
1511  // Determine per point the max cell level of connected cells
1512  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1513 
1514  labelList maxPointLevel(pp.nPoints(), labelMin);
1515  {
1516  forAll(pp, i)
1517  {
1518  label ownLevel = cellLevel[mesh.faceOwner()[pp.addressing()[i]]];
1519 
1520  const face& f = pp.localFaces()[i];
1521 
1522  forAll(f, fp)
1523  {
1524  maxPointLevel[f[fp]] = max(maxPointLevel[f[fp]], ownLevel);
1525  }
1526  }
1527 
1529  (
1530  mesh,
1531  pp.meshPoints(),
1532  maxPointLevel,
1533  maxEqOp<label>(),
1534  labelMin // null value
1535  );
1536  }
1537 
1538 
1539  // Rework relative thickness into absolute
1540  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1541  // by multiplying with the internal cell size.
1542  // Note that we cannot loop over the patches since then points on
1543  // multiple patches would get multiplied with edgeLen twice ..
1544  {
1545  // Multiplication factor for relative sizes
1546  scalarField edgeLen(pp.nPoints(), GREAT);
1547 
1548  labelList spec(pp.nPoints(), layerParameters::FIRST_AND_TOTAL);
1549 
1550  bitSet isRelativePoint(mesh.nPoints());
1551 
1552  for (const label patchi : patchIDs)
1553  {
1554  const labelList& meshPoints = patches[patchi].meshPoints();
1555  const layerParameters::thicknessModelType patchSpec =
1556  layerParams.layerModels()[patchi];
1557  const bool relSize = layerParams.relativeSizes()[patchi];
1558 
1559  for (const label meshPointi : meshPoints)
1560  {
1561  const label ppPointi = pp.meshPointMap()[meshPointi];
1562 
1563  // Note: who wins if different specs?
1564 
1565  // Calculate undistorted edge size for this level.
1566  edgeLen[ppPointi] = min
1567  (
1568  edgeLen[ppPointi],
1569  edge0Len/(1<<maxPointLevel[ppPointi])
1570  );
1571  spec[ppPointi] = max(spec[ppPointi], patchSpec);
1572  isRelativePoint[meshPointi] =
1573  isRelativePoint[meshPointi]
1574  || relSize;
1575  }
1576  }
1577 
1579  (
1580  mesh,
1581  pp.meshPoints(),
1582  edgeLen,
1583  minEqOp<scalar>(),
1584  GREAT // null value
1585  );
1587  (
1588  mesh,
1589  pp.meshPoints(),
1590  spec,
1591  maxEqOp<label>(),
1592  label(layerParameters::FIRST_AND_TOTAL) // null value
1593  );
1595  (
1596  mesh,
1597  isRelativePoint,
1598  orEqOp<unsigned int>(),
1599  0
1600  );
1601 
1602 
1603 
1604 
1605  forAll(pp.meshPoints(), pointi)
1606  {
1607  const label meshPointi = pp.meshPoints()[pointi];
1608  const layerParameters::thicknessModelType pointSpec =
1609  static_cast<layerParameters::thicknessModelType>(spec[pointi]);
1610 
1612  {
1613  // This overrules the relative sizes flag for
1614  // first (always absolute) and final (always relative)
1615  finalLayerThickness[pointi] *= edgeLen[pointi];
1616  if (isRelativePoint[meshPointi])
1617  {
1618  totalThickness[pointi] *= edgeLen[pointi];
1619  minThickness[pointi] *= edgeLen[pointi];
1620  }
1621  }
1622  else if (isRelativePoint[meshPointi])
1623  {
1624  firstLayerThickness[pointi] *= edgeLen[pointi];
1625  finalLayerThickness[pointi] *= edgeLen[pointi];
1626  totalThickness[pointi] *= edgeLen[pointi];
1627  minThickness[pointi] *= edgeLen[pointi];
1628  }
1629 
1630  thickness[pointi] = min
1631  (
1632  thickness[pointi],
1634  (
1635  pointSpec,
1636  patchNLayers[pointi],
1637  firstLayerThickness[pointi],
1638  finalLayerThickness[pointi],
1639  totalThickness[pointi],
1640  expRatio[pointi]
1641  )
1642  );
1643  expansionRatio[pointi] = min
1644  (
1645  expansionRatio[pointi],
1646  layerParameters::layerExpansionRatio
1647  (
1648  pointSpec,
1649  patchNLayers[pointi],
1650  firstLayerThickness[pointi],
1651  finalLayerThickness[pointi],
1652  totalThickness[pointi],
1653  expRatio[pointi]
1654  )
1655  );
1656  }
1657  }
1658 
1659  // Synchronise the determined thicknes. Note that this should not be
1660  // necessary since the inputs to the calls to layerThickness,
1661  // layerExpansionRatio above are already parallel consistent
1662 
1664  (
1665  mesh,
1666  pp.meshPoints(),
1667  thickness,
1668  minEqOp<scalar>(),
1669  GREAT // null value
1670  );
1672  (
1673  mesh,
1674  pp.meshPoints(),
1675  expansionRatio,
1676  minEqOp<scalar>(),
1677  GREAT // null value
1678  );
1679 
1680  //Info<< "calculateLayerThickness : min:" << gMin(thickness)
1681  // << " max:" << gMax(thickness) << endl;
1682 
1683  // Print a bit
1684  {
1685  const polyBoundaryMesh& patches = mesh.boundaryMesh();
1686 
1687  int oldPrecision = Info().precision();
1688 
1689  // Find maximum length of a patch name, for a nicer output
1690  label maxPatchNameLen = 0;
1691  forAll(patchIDs, i)
1692  {
1693  label patchi = patchIDs[i];
1694  word patchName = patches[patchi].name();
1695  maxPatchNameLen = max(maxPatchNameLen, label(patchName.size()));
1696  }
1697 
1698  Info<< nl
1699  << setf(ios_base::left) << setw(maxPatchNameLen) << "patch"
1700  << setw(0) << " faces layers avg thickness[m]" << nl
1701  << setf(ios_base::left) << setw(maxPatchNameLen) << " "
1702  << setw(0) << " near-wall overall" << nl
1703  << setf(ios_base::left) << setw(maxPatchNameLen) << "-----"
1704  << setw(0) << " ----- ------ --------- -------" << endl;
1705 
1706 
1707  const bitSet isMasterPoint(syncTools::getMasterPoints(mesh));
1708 
1709  forAll(patchIDs, i)
1710  {
1711  label patchi = patchIDs[i];
1712 
1713  const labelList& meshPoints = patches[patchi].meshPoints();
1715  layerParams.layerModels()[patchi];
1716 
1717  scalar sumThickness = 0;
1718  scalar sumNearWallThickness = 0;
1719  label nMasterPoints = 0;
1720 
1721  forAll(meshPoints, patchPointi)
1722  {
1723  label meshPointi = meshPoints[patchPointi];
1724  if (isMasterPoint[meshPointi])
1725  {
1726  label ppPointi = pp.meshPointMap()[meshPointi];
1727 
1728  sumThickness += thickness[ppPointi];
1729  sumNearWallThickness += layerParams.firstLayerThickness
1730  (
1731  spec,
1732  patchNLayers[ppPointi],
1733  firstLayerThickness[ppPointi],
1734  finalLayerThickness[ppPointi],
1735  thickness[ppPointi],
1736  expansionRatio[ppPointi]
1737  );
1738  nMasterPoints++;
1739  }
1740  }
1741 
1742  label totNPoints = returnReduce(nMasterPoints, sumOp<label>());
1743 
1744  // For empty patches, totNPoints is 0.
1745  scalar avgThickness = 0;
1746  scalar avgNearWallThickness = 0;
1747 
1748  if (totNPoints > 0)
1749  {
1750  avgThickness =
1751  returnReduce(sumThickness, sumOp<scalar>())
1752  / totNPoints;
1753  avgNearWallThickness =
1754  returnReduce(sumNearWallThickness, sumOp<scalar>())
1755  / totNPoints;
1756  }
1757 
1758  Info<< setf(ios_base::left) << setw(maxPatchNameLen)
1759  << patches[patchi].name() << setprecision(3)
1760  << " " << setw(8)
1761  << returnReduce(patches[patchi].size(), sumOp<scalar>())
1762  << " " << setw(6) << layerParams.numLayers()[patchi]
1763  << " " << setw(8) << avgNearWallThickness
1764  << " " << setw(8) << avgThickness
1765  << endl;
1766  }
1767  Info<< setprecision(oldPrecision) << endl;
1768  }
1769 }
1770 
1771 
1772 // Synchronize displacement among coupled patches.
1773 void Foam::snappyLayerDriver::syncPatchDisplacement
1774 (
1775  const indirectPrimitivePatch& pp,
1776  const scalarField& minThickness,
1777  pointField& patchDisp,
1778  labelList& patchNLayers,
1779  List<extrudeMode>& extrudeStatus
1780 ) const
1781 {
1782  const fvMesh& mesh = meshRefiner_.mesh();
1783  const labelList& meshPoints = pp.meshPoints();
1784 
1785  label nChangedTotal = 0;
1786 
1787  while (true)
1788  {
1789  label nChanged = 0;
1790 
1791  // Sync displacement (by taking min)
1793  (
1794  mesh,
1795  meshPoints,
1796  patchDisp,
1797  minMagSqrEqOp<vector>(),
1798  point::rootMax // null value
1799  );
1800 
1801  // Unmark if displacement too small
1802  forAll(patchDisp, i)
1803  {
1804  if (mag(patchDisp[i]) < minThickness[i])
1805  {
1806  if
1807  (
1808  unmarkExtrusion
1809  (
1810  i,
1811  patchDisp,
1812  patchNLayers,
1813  extrudeStatus
1814  )
1815  )
1816  {
1817  nChanged++;
1818  }
1819  }
1820  }
1821 
1822  labelList syncPatchNLayers(patchNLayers);
1823 
1825  (
1826  mesh,
1827  meshPoints,
1828  syncPatchNLayers,
1829  minEqOp<label>(),
1830  labelMax // null value
1831  );
1832 
1833  // Reset if differs
1834  // 1. take max
1835  forAll(syncPatchNLayers, i)
1836  {
1837  if (syncPatchNLayers[i] != patchNLayers[i])
1838  {
1839  if
1840  (
1841  unmarkExtrusion
1842  (
1843  i,
1844  patchDisp,
1845  patchNLayers,
1846  extrudeStatus
1847  )
1848  )
1849  {
1850  nChanged++;
1851  }
1852  }
1853  }
1854 
1856  (
1857  mesh,
1858  meshPoints,
1859  syncPatchNLayers,
1860  maxEqOp<label>(),
1861  labelMin // null value
1862  );
1863 
1864  // Reset if differs
1865  // 2. take min
1866  forAll(syncPatchNLayers, i)
1867  {
1868  if (syncPatchNLayers[i] != patchNLayers[i])
1869  {
1870  if
1871  (
1872  unmarkExtrusion
1873  (
1874  i,
1875  patchDisp,
1876  patchNLayers,
1877  extrudeStatus
1878  )
1879  )
1880  {
1881  nChanged++;
1882  }
1883  }
1884  }
1885  nChangedTotal += nChanged;
1886 
1887  if (!returnReduce(nChanged, sumOp<label>()))
1888  {
1889  break;
1890  }
1891  }
1892 
1893  //Info<< "Prevented extrusion on "
1894  // << returnReduce(nChangedTotal, sumOp<label>())
1895  // << " coupled patch points during syncPatchDisplacement." << endl;
1896 }
1897 
1898 
1899 // Calculate displacement vector for all patch points. Uses pointNormal.
1900 // Checks that displaced patch point would be visible from all centres
1901 // of the faces using it.
1902 // extrudeStatus is both input and output and gives the status of each
1903 // patch point.
1904 void Foam::snappyLayerDriver::getPatchDisplacement
1905 (
1906  const indirectPrimitivePatch& pp,
1907  const scalarField& thickness,
1908  const scalarField& minThickness,
1909  const scalarField& expansionRatio,
1910 
1911  pointField& patchDisp,
1912  labelList& patchNLayers,
1913  List<extrudeMode>& extrudeStatus
1914 ) const
1915 {
1916  Info<< nl << "Determining displacement for added points"
1917  << " according to pointNormal ..." << endl;
1918 
1919  const fvMesh& mesh = meshRefiner_.mesh();
1920  const vectorField& faceNormals = pp.faceNormals();
1921  const labelListList& pointFaces = pp.pointFaces();
1922  const pointField& localPoints = pp.localPoints();
1923 
1924  // Determine pointNormal
1925  // ~~~~~~~~~~~~~~~~~~~~~
1926 
1927  pointField pointNormals(PatchTools::pointNormals(mesh, pp));
1928 
1929 
1930  // Determine local length scale on patch
1931  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1932 
1933  // Start off from same thickness everywhere (except where no extrusion)
1934  patchDisp = thickness*pointNormals;
1935 
1936 
1937  label nNoVisNormal = 0;
1938  label nExtrudeRemove = 0;
1939 
1940 
1942 // {
1943 // OBJstream twoStr
1944 // (
1945 // mesh.time().path()
1946 // / "twoFacePoints_"
1947 // + meshRefiner_.timeName()
1948 // + ".obj"
1949 // );
1950 // OBJstream multiStr
1951 // (
1952 // mesh.time().path()
1953 // / "multiFacePoints_"
1954 // + meshRefiner_.timeName()
1955 // + ".obj"
1956 // );
1957 // Pout<< "Writing points inbetween two faces on same cell to "
1958 // << twoStr.name() << endl;
1959 // Pout<< "Writing points inbetween three or more faces on same cell to "
1960 // << multiStr.name() << endl;
1961 // // Check whether inbetween patch faces on same cell
1962 // Map<labelList> cellToFaces;
1963 // forAll(pointNormals, patchPointi)
1964 // {
1965 // const labelList& pFaces = pointFaces[patchPointi];
1966 //
1967 // cellToFaces.clear();
1968 // forAll(pFaces, pFacei)
1969 // {
1970 // const label patchFacei = pFaces[pFacei];
1971 // const label meshFacei = pp.addressing()[patchFacei];
1972 // const label celli = mesh.faceOwner()[meshFacei];
1973 // Map<labelList>::iterator faceFnd = cellToFaces.find(celli);
1974 // if (faceFnd.found())
1975 // {
1976 // labelList& faces = faceFnd();
1977 // if (!faces.found(patchFacei))
1978 // {
1979 // faces.append(patchFacei);
1980 // }
1981 // }
1982 // else
1983 // {
1984 // cellToFaces.insert(celli, labelList(1, patchFacei));
1985 // }
1986 // }
1987 //
1988 // forAllConstIter(Map<labelList>, cellToFaces, iter)
1989 // {
1990 // if (iter().size() == 2)
1991 // {
1992 // twoStr.write(pp.localPoints()[patchPointi]);
1993 // }
1994 // else if (iter().size() > 2)
1995 // {
1996 // multiStr.write(pp.localPoints()[patchPointi]);
1997 //
1998 // const scalar ratio =
1999 // layerParameters::finalLayerThicknessRatio
2000 // (
2001 // patchNLayers[patchPointi],
2002 // expansionRatio[patchPointi]
2003 // );
2004 // // Get thickness of cell next to bulk
2005 // const vector finalDisp
2006 // (
2007 // ratio*patchDisp[patchPointi]
2008 // );
2009 //
2010 // //Pout<< "** point:" << pp.localPoints()[patchPointi]
2011 // // << " on cell:" << iter.key()
2012 // // << " faces:" << iter()
2013 // // << " displacement was:" << patchDisp[patchPointi]
2014 // // << " ratio:" << ratio
2015 // // << " finalDispl:" << finalDisp;
2016 //
2017 // // Half this thickness
2018 // patchDisp[patchPointi] -= 0.8*finalDisp;
2019 //
2020 // //Pout<< " new displacement:"
2021 // // << patchDisp[patchPointi] << endl;
2022 // }
2023 // }
2024 // }
2025 //
2026 // Pout<< "Written " << multiStr.nVertices()
2027 // << " points inbetween three or more faces on same cell to "
2028 // << multiStr.name() << endl;
2029 // }
2031 
2032 
2033  // Check if no extrude possible.
2034  forAll(pointNormals, patchPointi)
2035  {
2036  label meshPointi = pp.meshPoints()[patchPointi];
2037 
2038  if (extrudeStatus[patchPointi] == NOEXTRUDE)
2039  {
2040  // Do not use unmarkExtrusion; forcibly set to zero extrusion.
2041  patchNLayers[patchPointi] = 0;
2042  patchDisp[patchPointi] = Zero;
2043  }
2044  else
2045  {
2046  // Get normal
2047  const vector& n = pointNormals[patchPointi];
2048 
2049  if (!meshTools::visNormal(n, faceNormals, pointFaces[patchPointi]))
2050  {
2052  {
2053  Pout<< "No valid normal for point " << meshPointi
2054  << ' ' << pp.points()[meshPointi]
2055  << "; setting displacement to "
2056  << patchDisp[patchPointi]
2057  << endl;
2058  }
2059 
2060  extrudeStatus[patchPointi] = EXTRUDEREMOVE;
2061  nNoVisNormal++;
2062  }
2063  }
2064  }
2065 
2066  // At illegal points make displacement average of new neighbour positions
2067  forAll(extrudeStatus, patchPointi)
2068  {
2069  if (extrudeStatus[patchPointi] == EXTRUDEREMOVE)
2070  {
2071  point avg(Zero);
2072  label nPoints = 0;
2073 
2074  const labelList& pEdges = pp.pointEdges()[patchPointi];
2075 
2076  forAll(pEdges, i)
2077  {
2078  label edgei = pEdges[i];
2079 
2080  label otherPointi = pp.edges()[edgei].otherVertex(patchPointi);
2081 
2082  if (extrudeStatus[otherPointi] != NOEXTRUDE)
2083  {
2084  avg += localPoints[otherPointi] + patchDisp[otherPointi];
2085  nPoints++;
2086  }
2087  }
2088 
2089  if (nPoints > 0)
2090  {
2092  {
2093  Pout<< "Displacement at illegal point "
2094  << localPoints[patchPointi]
2095  << " set to "
2096  << (avg / nPoints - localPoints[patchPointi])
2097  << endl;
2098  }
2099 
2100  patchDisp[patchPointi] =
2101  avg / nPoints
2102  - localPoints[patchPointi];
2103 
2104  nExtrudeRemove++;
2105  }
2106  else
2107  {
2108  // All surrounding points are not extruded. Leave patchDisp
2109  // intact.
2110  }
2111  }
2112  }
2113 
2114  Info<< "Detected " << returnReduce(nNoVisNormal, sumOp<label>())
2115  << " points with point normal pointing through faces." << nl
2116  << "Reset displacement at "
2117  << returnReduce(nExtrudeRemove, sumOp<label>())
2118  << " points to average of surrounding points." << endl;
2119 
2120  // Make sure displacement is equal on both sides of coupled patches.
2121  syncPatchDisplacement
2122  (
2123  pp,
2124  minThickness,
2125  patchDisp,
2126  patchNLayers,
2127  extrudeStatus
2128  );
2129 
2130  Info<< endl;
2131 }
2132 
2133 
2134 bool Foam::snappyLayerDriver::sameEdgeNeighbour
2135 (
2136  const labelListList& globalEdgeFaces,
2137  const label myGlobalFacei,
2138  const label nbrGlobFacei,
2139  const label edgei
2140 ) const
2141 {
2142  const labelList& eFaces = globalEdgeFaces[edgei];
2143  if (eFaces.size() == 2)
2144  {
2145  return edge(myGlobalFacei, nbrGlobFacei) == edge(eFaces[0], eFaces[1]);
2146  }
2147 
2148  return false;
2149 }
2150 
2151 
2152 void Foam::snappyLayerDriver::getVertexString
2153 (
2154  const indirectPrimitivePatch& pp,
2155  const labelListList& globalEdgeFaces,
2156  const label facei,
2157  const label edgei,
2158  const label myGlobFacei,
2159  const label nbrGlobFacei,
2160  DynamicList<label>& vertices
2161 ) const
2162 {
2163  const labelList& fEdges = pp.faceEdges()[facei];
2164  label fp = fEdges.find(edgei);
2165 
2166  if (fp == -1)
2167  {
2169  << "problem." << abort(FatalError);
2170  }
2171 
2172  // Search back
2173  label startFp = fp;
2174 
2175  forAll(fEdges, i)
2176  {
2177  label prevFp = fEdges.rcIndex(startFp);
2178  if
2179  (
2180  !sameEdgeNeighbour
2181  (
2182  globalEdgeFaces,
2183  myGlobFacei,
2184  nbrGlobFacei,
2185  fEdges[prevFp]
2186  )
2187  )
2188  {
2189  break;
2190  }
2191  startFp = prevFp;
2192  }
2193 
2194  label endFp = fp;
2195  forAll(fEdges, i)
2196  {
2197  label nextFp = fEdges.fcIndex(endFp);
2198  if
2199  (
2200  !sameEdgeNeighbour
2201  (
2202  globalEdgeFaces,
2203  myGlobFacei,
2204  nbrGlobFacei,
2205  fEdges[nextFp]
2206  )
2207  )
2208  {
2209  break;
2210  }
2211  endFp = nextFp;
2212  }
2213 
2214  const face& f = pp.localFaces()[facei];
2215  vertices.clear();
2216  fp = startFp;
2217  while (fp != endFp)
2218  {
2219  vertices.append(f[fp]);
2220  fp = f.fcIndex(fp);
2221  }
2222  vertices.append(f[fp]);
2223  fp = f.fcIndex(fp);
2224  vertices.append(f[fp]);
2225 }
2226 
2227 
2228 // Truncates displacement
2229 // - for all patchFaces in the faceset displacement gets set to zero
2230 // - all displacement < minThickness gets set to zero
2231 Foam::label Foam::snappyLayerDriver::truncateDisplacement
2232 (
2233  const globalIndex& globalFaces,
2234  const labelListList& edgeGlobalFaces,
2235  const indirectPrimitivePatch& pp,
2236  const scalarField& minThickness,
2237  const faceSet& illegalPatchFaces,
2238  pointField& patchDisp,
2239  labelList& patchNLayers,
2240  List<extrudeMode>& extrudeStatus
2241 ) const
2242 {
2243  const fvMesh& mesh = meshRefiner_.mesh();
2244 
2245  label nChanged = 0;
2246 
2247  const Map<label>& meshPointMap = pp.meshPointMap();
2248 
2249  for (const label facei : illegalPatchFaces)
2250  {
2251  if (mesh.isInternalFace(facei))
2252  {
2254  << "Faceset " << illegalPatchFaces.name()
2255  << " contains internal face " << facei << nl
2256  << "It should only contain patch faces" << abort(FatalError);
2257  }
2258 
2259  const face& f = mesh.faces()[facei];
2260 
2261 
2262  forAll(f, fp)
2263  {
2264  const auto fnd = meshPointMap.cfind(f[fp]);
2265  if (fnd.found())
2266  {
2267  const label patchPointi = fnd.val();
2268 
2269  if (extrudeStatus[patchPointi] != NOEXTRUDE)
2270  {
2271  unmarkExtrusion
2272  (
2273  patchPointi,
2274  patchDisp,
2275  patchNLayers,
2276  extrudeStatus
2277  );
2278  nChanged++;
2279  }
2280  }
2281  }
2282  }
2283 
2284  forAll(patchDisp, patchPointi)
2285  {
2286  if (mag(patchDisp[patchPointi]) < minThickness[patchPointi])
2287  {
2288  if
2289  (
2290  unmarkExtrusion
2291  (
2292  patchPointi,
2293  patchDisp,
2294  patchNLayers,
2295  extrudeStatus
2296  )
2297  )
2298  {
2299  nChanged++;
2300  }
2301  }
2302  else if (extrudeStatus[patchPointi] == NOEXTRUDE)
2303  {
2304  // Make sure displacement is 0. Should already be so but ...
2305  patchDisp[patchPointi] = Zero;
2306  patchNLayers[patchPointi] = 0;
2307  }
2308  }
2309 
2310 
2311  const faceList& localFaces = pp.localFaces();
2312 
2313  while (true)
2314  {
2315  syncPatchDisplacement
2316  (
2317  pp,
2318  minThickness,
2319  patchDisp,
2320  patchNLayers,
2321  extrudeStatus
2322  );
2323 
2324 
2325  // Pinch
2326  // ~~~~~
2327 
2328  // Make sure that a face doesn't have two non-consecutive areas
2329  // not extruded (e.g. quad where vertex 0 and 2 are not extruded
2330  // but 1 and 3 are) since this gives topological errors.
2331 
2332  label nPinched = 0;
2333 
2334  forAll(localFaces, i)
2335  {
2336  const face& localF = localFaces[i];
2337 
2338  // Count number of transitions from unsnapped to snapped.
2339  label nTrans = 0;
2340 
2341  extrudeMode prevMode = extrudeStatus[localF.prevLabel(0)];
2342 
2343  forAll(localF, fp)
2344  {
2345  extrudeMode fpMode = extrudeStatus[localF[fp]];
2346 
2347  if (prevMode == NOEXTRUDE && fpMode != NOEXTRUDE)
2348  {
2349  nTrans++;
2350  }
2351  prevMode = fpMode;
2352  }
2353 
2354  if (nTrans > 1)
2355  {
2356  // Multiple pinches. Reset whole face as unextruded.
2357  if
2358  (
2359  unmarkExtrusion
2360  (
2361  localF,
2362  patchDisp,
2363  patchNLayers,
2364  extrudeStatus
2365  )
2366  )
2367  {
2368  nPinched++;
2369  nChanged++;
2370  }
2371  }
2372  }
2373 
2374  reduce(nPinched, sumOp<label>());
2375 
2376  Info<< "truncateDisplacement : Unextruded " << nPinched
2377  << " faces due to non-consecutive vertices being extruded." << endl;
2378 
2379 
2380  // Butterfly
2381  // ~~~~~~~~~
2382 
2383  // Make sure that a string of edges becomes a single face so
2384  // not a butterfly. Occasionally an 'edge' will have a single dangling
2385  // vertex due to face combining. These get extruded as a single face
2386  // (with a dangling vertex) so make sure this extrusion forms a single
2387  // shape.
2388  // - continuous i.e. no butterfly:
2389  // + +
2390  // |\ /|
2391  // | \ / |
2392  // +--+--+
2393  // - extrudes from all but the endpoints i.e. no partial
2394  // extrude
2395  // +
2396  // /|
2397  // / |
2398  // +--+--+
2399  // The common error topology is a pinch somewhere in the middle
2400  label nButterFly = 0;
2401  {
2402  DynamicList<label> stringedVerts;
2403  forAll(pp.edges(), edgei)
2404  {
2405  const labelList& globFaces = edgeGlobalFaces[edgei];
2406 
2407  if (globFaces.size() == 2)
2408  {
2409  label myFacei = pp.edgeFaces()[edgei][0];
2410  label myGlobalFacei = globalFaces.toGlobal
2411  (
2412  pp.addressing()[myFacei]
2413  );
2414  label nbrGlobalFacei =
2415  (
2416  globFaces[0] != myGlobalFacei
2417  ? globFaces[0]
2418  : globFaces[1]
2419  );
2420  getVertexString
2421  (
2422  pp,
2423  edgeGlobalFaces,
2424  myFacei,
2425  edgei,
2426  myGlobalFacei,
2427  nbrGlobalFacei,
2428  stringedVerts
2429  );
2430 
2431  if
2432  (
2433  extrudeStatus[stringedVerts[0]] != NOEXTRUDE
2434  || extrudeStatus[stringedVerts.last()] != NOEXTRUDE
2435  )
2436  {
2437  // Any pinch in the middle
2438  bool pinch = false;
2439  for (label i = 1; i < stringedVerts.size()-1; i++)
2440  {
2441  if (extrudeStatus[stringedVerts[i]] == NOEXTRUDE)
2442  {
2443  pinch = true;
2444  break;
2445  }
2446  }
2447  if (pinch)
2448  {
2449  forAll(stringedVerts, i)
2450  {
2451  if
2452  (
2453  unmarkExtrusion
2454  (
2455  stringedVerts[i],
2456  patchDisp,
2457  patchNLayers,
2458  extrudeStatus
2459  )
2460  )
2461  {
2462  nButterFly++;
2463  nChanged++;
2464  }
2465  }
2466  }
2467  }
2468  }
2469  }
2470  }
2471 
2472  reduce(nButterFly, sumOp<label>());
2473 
2474  Info<< "truncateDisplacement : Unextruded " << nButterFly
2475  << " faces due to stringed edges with inconsistent extrusion."
2476  << endl;
2477 
2478 
2479 
2480  // Consistent number of layers
2481  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
2482 
2483  // Make sure that a face has consistent number of layers for all
2484  // its vertices.
2485 
2486  label nDiffering = 0;
2487 
2488  //forAll(localFaces, i)
2489  //{
2490  // const face& localF = localFaces[i];
2491  //
2492  // label numLayers = -1;
2493  //
2494  // forAll(localF, fp)
2495  // {
2496  // if (patchNLayers[localF[fp]] > 0)
2497  // {
2498  // if (numLayers == -1)
2499  // {
2500  // numLayers = patchNLayers[localF[fp]];
2501  // }
2502  // else if (numLayers != patchNLayers[localF[fp]])
2503  // {
2504  // // Differing number of layers
2505  // if
2506  // (
2507  // unmarkExtrusion
2508  // (
2509  // localF,
2510  // patchDisp,
2511  // patchNLayers,
2512  // extrudeStatus
2513  // )
2514  // )
2515  // {
2516  // nDiffering++;
2517  // nChanged++;
2518  // }
2519  // break;
2520  // }
2521  // }
2522  // }
2523  //}
2524  //
2525  //reduce(nDiffering, sumOp<label>());
2526  //
2527  //Info<< "truncateDisplacement : Unextruded " << nDiffering
2528  // << " faces due to having differing number of layers." << endl;
2529 
2530  if (nPinched+nButterFly+nDiffering == 0)
2531  {
2532  break;
2533  }
2534  }
2535 
2536  return nChanged;
2537 }
2538 
2539 
2540 // Setup layer information (at points and faces) to modify mesh topology in
2541 // regions where layer mesh terminates.
2542 void Foam::snappyLayerDriver::setupLayerInfoTruncation
2543 (
2544  const indirectPrimitivePatch& pp,
2545  const labelList& patchNLayers,
2546  const List<extrudeMode>& extrudeStatus,
2547  const label nBufferCellsNoExtrude,
2548  labelList& nPatchPointLayers,
2549  labelList& nPatchFaceLayers
2550 ) const
2551 {
2552  Info<< nl << "Setting up information for layer truncation ..." << endl;
2553 
2554  const fvMesh& mesh = meshRefiner_.mesh();
2555 
2556  if (nBufferCellsNoExtrude < 0)
2557  {
2558  Info<< nl << "Performing no layer truncation."
2559  << " nBufferCellsNoExtrude set to less than 0 ..." << endl;
2560 
2561  // Face layers if any point gets extruded
2562  forAll(pp.localFaces(), patchFacei)
2563  {
2564  const face& f = pp.localFaces()[patchFacei];
2565 
2566  forAll(f, fp)
2567  {
2568  const label nPointLayers = patchNLayers[f[fp]];
2569  if (nPointLayers > 0)
2570  {
2571  if (nPatchFaceLayers[patchFacei] == -1)
2572  {
2573  nPatchFaceLayers[patchFacei] = nPointLayers;
2574  }
2575  else
2576  {
2577  nPatchFaceLayers[patchFacei] = min
2578  (
2579  nPatchFaceLayers[patchFacei],
2580  nPointLayers
2581  );
2582  }
2583  }
2584  }
2585  }
2586  nPatchPointLayers = patchNLayers;
2587 
2588  // Set any unset patch face layers
2589  forAll(nPatchFaceLayers, patchFacei)
2590  {
2591  if (nPatchFaceLayers[patchFacei] == -1)
2592  {
2593  nPatchFaceLayers[patchFacei] = 0;
2594  }
2595  }
2596  }
2597  else
2598  {
2599  // Determine max point layers per face.
2600  labelList maxLevel(pp.size(), Zero);
2601 
2602  forAll(pp.localFaces(), patchFacei)
2603  {
2604  const face& f = pp.localFaces()[patchFacei];
2605 
2606  // find patch faces where layer terminates (i.e contains extrude
2607  // and noextrude points).
2608 
2609  bool noExtrude = false;
2610  label mLevel = 0;
2611 
2612  forAll(f, fp)
2613  {
2614  if (extrudeStatus[f[fp]] == NOEXTRUDE)
2615  {
2616  noExtrude = true;
2617  }
2618  mLevel = max(mLevel, patchNLayers[f[fp]]);
2619  }
2620 
2621  if (mLevel > 0)
2622  {
2623  // So one of the points is extruded. Check if all are extruded
2624  // or is a mix.
2625 
2626  if (noExtrude)
2627  {
2628  nPatchFaceLayers[patchFacei] = 1;
2629  maxLevel[patchFacei] = mLevel;
2630  }
2631  else
2632  {
2633  maxLevel[patchFacei] = mLevel;
2634  }
2635  }
2636  }
2637 
2638  // We have the seed faces (faces with nPatchFaceLayers != maxLevel)
2639  // Now do a meshwave across the patch where we pick up neighbours
2640  // of seed faces.
2641  // Note: quite inefficient. Could probably be coded better.
2642 
2643  const labelListList& pointFaces = pp.pointFaces();
2644 
2645  label nLevels = gMax(patchNLayers);
2646 
2647  // flag neighbouring patch faces with number of layers to grow
2648  for (label ilevel = 1; ilevel < nLevels; ilevel++)
2649  {
2650  label nBuffer;
2651 
2652  if (ilevel == 1)
2653  {
2654  nBuffer = nBufferCellsNoExtrude - 1;
2655  }
2656  else
2657  {
2658  nBuffer = nBufferCellsNoExtrude;
2659  }
2660 
2661  for (label ibuffer = 0; ibuffer < nBuffer + 1; ibuffer++)
2662  {
2663  labelList tempCounter(nPatchFaceLayers);
2664 
2665  boolList foundNeighbour(pp.nPoints(), false);
2666 
2667  forAll(pp.meshPoints(), patchPointi)
2668  {
2669  forAll(pointFaces[patchPointi], pointFacei)
2670  {
2671  label facei = pointFaces[patchPointi][pointFacei];
2672 
2673  if
2674  (
2675  nPatchFaceLayers[facei] != -1
2676  && maxLevel[facei] > 0
2677  )
2678  {
2679  foundNeighbour[patchPointi] = true;
2680  break;
2681  }
2682  }
2683  }
2684 
2686  (
2687  mesh,
2688  pp.meshPoints(),
2689  foundNeighbour,
2690  orEqOp<bool>(),
2691  false // null value
2692  );
2693 
2694  forAll(pp.meshPoints(), patchPointi)
2695  {
2696  if (foundNeighbour[patchPointi])
2697  {
2698  forAll(pointFaces[patchPointi], pointFacei)
2699  {
2700  label facei = pointFaces[patchPointi][pointFacei];
2701  if
2702  (
2703  nPatchFaceLayers[facei] == -1
2704  && maxLevel[facei] > 0
2705  && ilevel < maxLevel[facei]
2706  )
2707  {
2708  tempCounter[facei] = ilevel;
2709  }
2710  }
2711  }
2712  }
2713  nPatchFaceLayers = tempCounter;
2714  }
2715  }
2716 
2717  forAll(pp.localFaces(), patchFacei)
2718  {
2719  if (nPatchFaceLayers[patchFacei] == -1)
2720  {
2721  nPatchFaceLayers[patchFacei] = maxLevel[patchFacei];
2722  }
2723  }
2724 
2725  forAll(pp.meshPoints(), patchPointi)
2726  {
2727  if (extrudeStatus[patchPointi] != NOEXTRUDE)
2728  {
2729  forAll(pointFaces[patchPointi], pointFacei)
2730  {
2731  label face = pointFaces[patchPointi][pointFacei];
2732  nPatchPointLayers[patchPointi] = max
2733  (
2734  nPatchPointLayers[patchPointi],
2735  nPatchFaceLayers[face]
2736  );
2737  }
2738  }
2739  else
2740  {
2741  nPatchPointLayers[patchPointi] = 0;
2742  }
2743  }
2745  (
2746  mesh,
2747  pp.meshPoints(),
2748  nPatchPointLayers,
2749  maxEqOp<label>(),
2750  label(0) // null value
2751  );
2752  }
2753 }
2754 
2755 
2756 // Does any of the cells use a face from faces?
2757 bool Foam::snappyLayerDriver::cellsUseFace
2758 (
2759  const polyMesh& mesh,
2760  const labelList& cellLabels,
2761  const labelHashSet& faces
2762 )
2763 {
2764  forAll(cellLabels, i)
2765  {
2766  const cell& cFaces = mesh.cells()[cellLabels[i]];
2767 
2768  forAll(cFaces, cFacei)
2769  {
2770  if (faces.found(cFaces[cFacei]))
2771  {
2772  return true;
2773  }
2774  }
2775  }
2776 
2777  return false;
2778 }
2779 
2780 
2781 // Checks the newly added cells and locally unmarks points so they
2782 // will not get extruded next time round. Returns global number of unmarked
2783 // points (0 if all was fine)
2784 Foam::label Foam::snappyLayerDriver::checkAndUnmark
2785 (
2786  const addPatchCellLayer& addLayer,
2787  const dictionary& meshQualityDict,
2788  const bool additionalReporting,
2789  const List<labelPair>& baffles,
2790  const indirectPrimitivePatch& pp,
2791  const fvMesh& newMesh,
2792 
2793  pointField& patchDisp,
2794  labelList& patchNLayers,
2795  List<extrudeMode>& extrudeStatus
2796 )
2797 {
2798  // Check the resulting mesh for errors
2799  Info<< nl << "Checking mesh with layer ..." << endl;
2800  faceSet wrongFaces(newMesh, "wrongFaces", newMesh.nFaces()/1000);
2802  (
2803  false,
2804  newMesh,
2805  meshQualityDict,
2806  identity(newMesh.nFaces()),
2807  baffles,
2808  wrongFaces,
2809  false // dryRun_
2810  );
2811  Info<< "Detected " << returnReduce(wrongFaces.size(), sumOp<label>())
2812  << " illegal faces"
2813  << " (concave, zero area or negative cell pyramid volume)"
2814  << endl;
2815 
2816  // Undo local extrusion if
2817  // - any of the added cells in error
2818 
2819  label nChanged = 0;
2820 
2821  // Get all cells in the layer.
2822  labelListList addedCells
2823  (
2825  (
2826  newMesh,
2827  addLayer.layerFaces()
2828  )
2829  );
2830 
2831  // Check if any of the faces in error uses any face of an added cell
2832  // - if additionalReporting print the few remaining areas for ease of
2833  // finding out where the problems are.
2834 
2835  const label nReportMax = 10;
2836  DynamicField<point> disabledFaceCentres(nReportMax);
2837 
2838  forAll(addedCells, oldPatchFacei)
2839  {
2840  // Get the cells (in newMesh labels) per old patch face (in mesh
2841  // labels)
2842  const labelList& fCells = addedCells[oldPatchFacei];
2843 
2844  if (cellsUseFace(newMesh, fCells, wrongFaces))
2845  {
2846  // Unmark points on old mesh
2847  if
2848  (
2849  unmarkExtrusion
2850  (
2851  pp.localFaces()[oldPatchFacei],
2852  patchDisp,
2853  patchNLayers,
2854  extrudeStatus
2855  )
2856  )
2857  {
2858  if (additionalReporting && (nChanged < nReportMax))
2859  {
2860  disabledFaceCentres.append
2861  (
2862  pp.faceCentres()[oldPatchFacei]
2863  );
2864  }
2865 
2866  nChanged++;
2867  }
2868  }
2869  }
2870 
2871 
2872  label nChangedTotal = returnReduce(nChanged, sumOp<label>());
2873 
2874  if (additionalReporting)
2875  {
2876  // Limit the number of points to be printed so that
2877  // not too many points are reported when running in parallel
2878  // Not accurate, i.e. not always nReportMax points are written,
2879  // but this estimation avoid some communication here.
2880  // The important thing, however, is that when only a few faces
2881  // are disabled, their coordinates are printed, and this should be
2882  // the case
2883  label nReportLocal = nChanged;
2884  if (nChangedTotal > nReportMax)
2885  {
2886  nReportLocal = min
2887  (
2888  max(nChangedTotal / Pstream::nProcs(), 1),
2889  min
2890  (
2891  nChanged,
2892  max(nReportMax / Pstream::nProcs(), 1)
2893  )
2894  );
2895  }
2896 
2897  if (nReportLocal)
2898  {
2899  Pout<< "Checked mesh with layers. Disabled extrusion at " << endl;
2900  for (label i=0; i < nReportLocal; i++)
2901  {
2902  Pout<< " " << disabledFaceCentres[i] << endl;
2903  }
2904  }
2905 
2906  label nReportTotal = returnReduce(nReportLocal, sumOp<label>());
2907 
2908  if (nReportTotal < nChangedTotal)
2909  {
2910  Info<< "Suppressed disabled extrusion message for other "
2911  << nChangedTotal - nReportTotal << " faces." << endl;
2912  }
2913  }
2914 
2915  return nChangedTotal;
2916 }
2917 
2918 
2919 //- Count global number of extruded faces
2920 Foam::label Foam::snappyLayerDriver::countExtrusion
2921 (
2922  const indirectPrimitivePatch& pp,
2923  const List<extrudeMode>& extrudeStatus
2924 )
2925 {
2926  // Count number of extruded patch faces
2927  label nExtruded = 0;
2928  {
2929  const faceList& localFaces = pp.localFaces();
2930 
2931  forAll(localFaces, i)
2932  {
2933  const face& localFace = localFaces[i];
2934 
2935  forAll(localFace, fp)
2936  {
2937  if (extrudeStatus[localFace[fp]] != NOEXTRUDE)
2938  {
2939  nExtruded++;
2940  break;
2941  }
2942  }
2943  }
2944  }
2945 
2946  return returnReduce(nExtruded, sumOp<label>());
2947 }
2948 
2949 
2950 Foam::List<Foam::labelPair> Foam::snappyLayerDriver::getBafflesOnAddedMesh
2951 (
2952  const polyMesh& mesh,
2953  const labelList& newToOldFaces,
2954  const List<labelPair>& baffles
2955 )
2956 {
2957  // The problem is that the baffle faces are now inside the
2958  // mesh (addPatchCellLayer modifies original boundary faces and
2959  // adds new ones. So 2 pass:
2960  // - find the boundary face for all faces originating from baffle
2961  // - use the boundary face for the new baffles
2962 
2963  Map<label> baffleSet(4*baffles.size());
2964  forAll(baffles, bafflei)
2965  {
2966  baffleSet.insert(baffles[bafflei][0], bafflei);
2967  baffleSet.insert(baffles[bafflei][1], bafflei);
2968  }
2969 
2970 
2971  List<labelPair> newBaffles(baffles.size(), labelPair(-1, -1));
2972  for
2973  (
2974  label facei = mesh.nInternalFaces();
2975  facei < mesh.nFaces();
2976  facei++
2977  )
2978  {
2979  label oldFacei = newToOldFaces[facei];
2980 
2981  const auto faceFnd = baffleSet.find(oldFacei);
2982  if (faceFnd.found())
2983  {
2984  label bafflei = faceFnd();
2985  labelPair& p = newBaffles[bafflei];
2986  if (p[0] == -1)
2987  {
2988  p[0] = facei;
2989  }
2990  else if (p[1] == -1)
2991  {
2992  p[1] = facei;
2993  }
2994  else
2995  {
2997  << "Problem:" << facei << " at:"
2998  << mesh.faceCentres()[facei]
2999  << " is on same baffle as " << p[0]
3000  << " at:" << mesh.faceCentres()[p[0]]
3001  << " and " << p[1]
3002  << " at:" << mesh.faceCentres()[p[1]]
3003  << exit(FatalError);
3004  }
3005  }
3006  }
3007  return newBaffles;
3008 }
3009 
3010 
3011 // Collect layer faces and layer cells into mesh fields for ease of handling
3012 void Foam::snappyLayerDriver::getLayerCellsFaces
3013 (
3014  const polyMesh& mesh,
3015  const addPatchCellLayer& addLayer,
3016  const scalarField& oldRealThickness,
3017 
3018  labelList& cellNLayers,
3019  scalarField& faceRealThickness
3020 )
3021 {
3022  cellNLayers.setSize(mesh.nCells());
3023  cellNLayers = 0;
3024  faceRealThickness.setSize(mesh.nFaces());
3025  faceRealThickness = 0;
3026 
3027  // Mark all faces in the layer
3028  const labelListList& layerFaces = addLayer.layerFaces();
3029 
3030  // Mark all cells in the layer.
3031  labelListList addedCells(addPatchCellLayer::addedCells(mesh, layerFaces));
3032 
3033  forAll(addedCells, oldPatchFacei)
3034  {
3035  const labelList& added = addedCells[oldPatchFacei];
3036 
3037  const labelList& layer = layerFaces[oldPatchFacei];
3038 
3039  if (layer.size())
3040  {
3041  // Leave out original internal face
3042  forAll(added, i)
3043  {
3044  cellNLayers[added[i]] = layer.size()-1;
3045  }
3046  }
3047  }
3048 
3049  forAll(layerFaces, oldPatchFacei)
3050  {
3051  const labelList& layer = layerFaces[oldPatchFacei];
3052  const scalar realThickness = oldRealThickness[oldPatchFacei];
3053 
3054  if (layer.size())
3055  {
3056  // Layer contains both original boundary face and new boundary
3057  // face so is nLayers+1. Leave out old internal face.
3058  for (label i = 1; i < layer.size(); i++)
3059  {
3060  faceRealThickness[layer[i]] = realThickness;
3061  }
3062  }
3063  }
3064 }
3065 
3066 
3067 void Foam::snappyLayerDriver::printLayerData
3068 (
3069  const fvMesh& mesh,
3070  const labelList& patchIDs,
3071  const labelList& cellNLayers,
3072  const scalarField& faceWantedThickness,
3073  const scalarField& faceRealThickness
3074 ) const
3075 {
3076  const polyBoundaryMesh& pbm = mesh.boundaryMesh();
3077 
3078  int oldPrecision = Info().precision();
3079 
3080  // Find maximum length of a patch name, for a nicer output
3081  label maxPatchNameLen = 0;
3082  forAll(patchIDs, i)
3083  {
3084  label patchi = patchIDs[i];
3085  word patchName = pbm[patchi].name();
3086  maxPatchNameLen = max(maxPatchNameLen, label(patchName.size()));
3087  }
3088 
3089  Info<< nl
3090  << setf(ios_base::left) << setw(maxPatchNameLen) << "patch"
3091  << setw(0) << " faces layers overall thickness" << nl
3092  << setf(ios_base::left) << setw(maxPatchNameLen) << " "
3093  << setw(0) << " [m] [%]" << nl
3094  << setf(ios_base::left) << setw(maxPatchNameLen) << "-----"
3095  << setw(0) << " ----- ------ --- ---" << endl;
3096 
3097 
3098  forAll(patchIDs, i)
3099  {
3100  label patchi = patchIDs[i];
3101  const polyPatch& pp = pbm[patchi];
3102 
3103  label sumSize = pp.size();
3104 
3105  // Number of layers
3106  const labelList& faceCells = pp.faceCells();
3107  label sumNLayers = 0;
3108  forAll(faceCells, i)
3109  {
3110  sumNLayers += cellNLayers[faceCells[i]];
3111  }
3112 
3113  // Thickness
3114  scalarField::subField patchWanted = pbm[patchi].patchSlice
3115  (
3116  faceWantedThickness
3117  );
3118  scalarField::subField patchReal = pbm[patchi].patchSlice
3119  (
3120  faceRealThickness
3121  );
3122 
3123  scalar sumRealThickness = sum(patchReal);
3124  scalar sumFraction = 0;
3125  forAll(patchReal, i)
3126  {
3127  if (patchWanted[i] > VSMALL)
3128  {
3129  sumFraction += (patchReal[i]/patchWanted[i]);
3130  }
3131  }
3132 
3133 
3134  reduce(sumSize, sumOp<label>());
3135  reduce(sumNLayers, sumOp<label>());
3136  reduce(sumRealThickness, sumOp<scalar>());
3137  reduce(sumFraction, sumOp<scalar>());
3138 
3139 
3140  scalar avgLayers = 0;
3141  scalar avgReal = 0;
3142  scalar avgFraction = 0;
3143  if (sumSize > 0)
3144  {
3145  avgLayers = scalar(sumNLayers)/sumSize;
3146  avgReal = sumRealThickness/sumSize;
3147  avgFraction = sumFraction/sumSize;
3148  }
3149 
3150  Info<< setf(ios_base::left) << setw(maxPatchNameLen)
3151  << pbm[patchi].name() << setprecision(3)
3152  << " " << setw(8) << sumSize
3153  << " " << setw(8) << avgLayers
3154  << " " << setw(8) << avgReal
3155  << " " << setw(8) << 100*avgFraction
3156  << endl;
3157  }
3158  Info<< setprecision(oldPrecision) << endl;
3159 }
3160 
3161 
3162 bool Foam::snappyLayerDriver::writeLayerSets
3163 (
3164  const fvMesh& mesh,
3165  const labelList& cellNLayers,
3166  const scalarField& faceRealThickness
3167 ) const
3168 {
3169  bool allOk = true;
3170  {
3171  label nAdded = 0;
3172  forAll(cellNLayers, celli)
3173  {
3174  if (cellNLayers[celli] > 0)
3175  {
3176  nAdded++;
3177  }
3178  }
3179  cellSet addedCellSet(mesh, "addedCells", nAdded);
3180  forAll(cellNLayers, celli)
3181  {
3182  if (cellNLayers[celli] > 0)
3183  {
3184  addedCellSet.insert(celli);
3185  }
3186  }
3187  addedCellSet.instance() = meshRefiner_.timeName();
3188  Info<< "Writing "
3189  << returnReduce(addedCellSet.size(), sumOp<label>())
3190  << " added cells to cellSet "
3191  << addedCellSet.name() << endl;
3192  bool ok = addedCellSet.write();
3193  allOk = allOk && ok;
3194  }
3195  {
3196  label nAdded = 0;
3197  for (label facei = 0; facei < mesh.nInternalFaces(); facei++)
3198  {
3199  if (faceRealThickness[facei] > 0)
3200  {
3201  nAdded++;
3202  }
3203  }
3204 
3205  faceSet layerFacesSet(mesh, "layerFaces", nAdded);
3206  for (label facei = 0; facei < mesh.nInternalFaces(); facei++)
3207  {
3208  if (faceRealThickness[facei] > 0)
3209  {
3210  layerFacesSet.insert(facei);
3211  }
3212  }
3213  layerFacesSet.instance() = meshRefiner_.timeName();
3214  Info<< "Writing "
3215  << returnReduce(layerFacesSet.size(), sumOp<label>())
3216  << " faces inside added layer to faceSet "
3217  << layerFacesSet.name() << endl;
3218  bool ok = layerFacesSet.write();
3219  allOk = allOk && ok;
3220  }
3221  return allOk;
3222 }
3223 
3224 
3225 bool Foam::snappyLayerDriver::writeLayerData
3226 (
3227  const fvMesh& mesh,
3228  const labelList& patchIDs,
3229  const labelList& cellNLayers,
3230  const scalarField& faceWantedThickness,
3231  const scalarField& faceRealThickness
3232 ) const
3233 {
3234  bool allOk = true;
3235 
3237  {
3238  bool ok = writeLayerSets(mesh, cellNLayers, faceRealThickness);
3239  allOk = allOk && ok;
3240  }
3241 
3243  {
3244  Info<< nl << "Writing fields with layer information:" << incrIndent
3245  << endl;
3246  {
3248  (
3249  IOobject
3250  (
3251  "nSurfaceLayers",
3252  mesh.time().timeName(),
3253  mesh,
3256  false
3257  ),
3258  mesh,
3260  fixedValueFvPatchScalarField::typeName
3261  );
3262  forAll(fld, celli)
3263  {
3264  fld[celli] = cellNLayers[celli];
3265  }
3266  volScalarField::Boundary& fldBf = fld.boundaryFieldRef();
3267 
3268  const polyBoundaryMesh& pbm = mesh.boundaryMesh();
3269  forAll(patchIDs, i)
3270  {
3271  label patchi = patchIDs[i];
3272  const polyPatch& pp = pbm[patchi];
3273  const labelList& faceCells = pp.faceCells();
3274  scalarField pfld(faceCells.size());
3275  forAll(faceCells, i)
3276  {
3277  pfld[i] = cellNLayers[faceCells[i]];
3278  }
3279  fldBf[patchi] == pfld;
3280  }
3281  Info<< indent << fld.name() << " : actual number of layers"
3282  << endl;
3283  bool ok = fld.write();
3284  allOk = allOk && ok;
3285  }
3286  {
3288  (
3289  IOobject
3290  (
3291  "thickness",
3292  mesh.time().timeName(),
3293  mesh,
3296  false
3297  ),
3298  mesh,
3300  fixedValueFvPatchScalarField::typeName
3301  );
3302  volScalarField::Boundary& fldBf = fld.boundaryFieldRef();
3303  const polyBoundaryMesh& pbm = mesh.boundaryMesh();
3304  forAll(patchIDs, i)
3305  {
3306  label patchi = patchIDs[i];
3307  fldBf[patchi] == pbm[patchi].patchSlice(faceRealThickness);
3308  }
3309  Info<< indent << fld.name() << " : overall layer thickness"
3310  << endl;
3311  bool ok = fld.write();
3312  allOk = allOk && ok;
3313  }
3314  {
3316  (
3317  IOobject
3318  (
3319  "thicknessFraction",
3320  mesh.time().timeName(),
3321  mesh,
3324  false
3325  ),
3326  mesh,
3328  fixedValueFvPatchScalarField::typeName
3329  );
3330  volScalarField::Boundary& fldBf = fld.boundaryFieldRef();
3331  const polyBoundaryMesh& pbm = mesh.boundaryMesh();
3332  forAll(patchIDs, i)
3333  {
3334  label patchi = patchIDs[i];
3335 
3336  scalarField::subField patchWanted = pbm[patchi].patchSlice
3337  (
3338  faceWantedThickness
3339  );
3340  scalarField::subField patchReal = pbm[patchi].patchSlice
3341  (
3342  faceRealThickness
3343  );
3344 
3345  // Convert patchReal to relative thickness
3346  scalarField pfld(patchReal.size(), Zero);
3347  forAll(patchReal, i)
3348  {
3349  if (patchWanted[i] > VSMALL)
3350  {
3351  pfld[i] = patchReal[i]/patchWanted[i];
3352  }
3353  }
3354 
3355  fldBf[patchi] == pfld;
3356  }
3357  Info<< indent << fld.name()
3358  << " : overall layer thickness (fraction"
3359  << " of desired thickness)" << endl;
3360  bool ok = fld.write();
3361  allOk = allOk && ok;
3362  }
3363  Info<< decrIndent<< endl;
3364  }
3365 
3366  return allOk;
3367 }
3368 
3369 
3370 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
3371 
3372 Foam::snappyLayerDriver::snappyLayerDriver
3374  meshRefinement& meshRefiner,
3375  const labelList& globalToMasterPatch,
3376  const labelList& globalToSlavePatch,
3377  const bool dryRun
3378 )
3379 :
3380  meshRefiner_(meshRefiner),
3381  globalToMasterPatch_(globalToMasterPatch),
3382  globalToSlavePatch_(globalToSlavePatch),
3383  dryRun_(dryRun)
3384 {}
3385 
3386 
3387 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
3388 
3391  const layerParameters& layerParams,
3392  const dictionary& motionDict,
3393  const meshRefinement::FaceMergeType mergeType
3394 )
3395 {
3396  // Clip to 30 degrees. Not helpful!
3397  //scalar planarAngle = min(30.0, layerParams.featureAngle());
3398  scalar planarAngle = layerParams.mergePatchFacesAngle();
3399  scalar minCos = Foam::cos(degToRad(planarAngle));
3400 
3401  scalar concaveCos = Foam::cos(degToRad(layerParams.concaveAngle()));
3402 
3403  Info<< nl
3404  << "Merging all faces of a cell" << nl
3405  << "---------------------------" << nl
3406  << " - which are on the same patch" << nl
3407  << " - which make an angle < " << planarAngle
3408  << " degrees"
3409  << " (cos:" << minCos << ')' << nl
3410  << " - as long as the resulting face doesn't become concave"
3411  << " by more than "
3412  << layerParams.concaveAngle() << " degrees" << nl
3413  << " (0=straight, 180=fully concave)" << nl
3414  << endl;
3415 
3416  const fvMesh& mesh = meshRefiner_.mesh();
3417 
3419 
3420  labelList duplicateFace(mesh.nFaces(), -1);
3421  forAll(couples, i)
3422  {
3423  const labelPair& cpl = couples[i];
3424  duplicateFace[cpl[0]] = cpl[1];
3425  duplicateFace[cpl[1]] = cpl[0];
3426  }
3427 
3428  label nChanged = meshRefiner_.mergePatchFacesUndo
3429  (
3430  minCos,
3431  concaveCos,
3432  meshRefiner_.meshedPatches(),
3433  motionDict,
3434  duplicateFace,
3435  mergeType // How to merge co-planar patch faces
3436  );
3437 
3438  nChanged += meshRefiner_.mergeEdgesUndo(minCos, motionDict);
3439 }
3440 
3441 
3444  const layerParameters& layerParams,
3445  const dictionary& motionDict,
3446  const labelList& patchIDs,
3447  const label nAllowableErrors,
3448  decompositionMethod& decomposer,
3449  fvMeshDistribute& distributor
3450 )
3451 {
3452  fvMesh& mesh = meshRefiner_.mesh();
3453 
3454 
3455  // faceZones of type internal or baffle (for merging points across)
3456  labelList internalOrBaffleFaceZones;
3457  {
3459  fzTypes[0] = surfaceZonesInfo::INTERNAL;
3460  fzTypes[1] = surfaceZonesInfo::BAFFLE;
3461  internalOrBaffleFaceZones = meshRefiner_.getZones(fzTypes);
3462  }
3463 
3464  // faceZones of type internal (for checking mesh quality across and
3465  // merging baffles)
3466  const labelList internalFaceZones
3467  (
3468  meshRefiner_.getZones
3469  (
3471  (
3472  1,
3474  )
3475  )
3476  );
3477 
3478  // Create baffles (pairs of faces that share the same points)
3479  // Baffles stored as owner and neighbour face that have been created.
3480  List<labelPair> baffles;
3481  {
3482  labelList originatingFaceZone;
3483  meshRefiner_.createZoneBaffles
3484  (
3485  identity(mesh.faceZones().size()),
3486  baffles,
3487  originatingFaceZone
3488  );
3489 
3491  {
3492  const_cast<Time&>(mesh.time())++;
3493  Info<< "Writing baffled mesh to time "
3494  << meshRefiner_.timeName() << endl;
3495  meshRefiner_.write
3496  (
3499  (
3502  ),
3503  mesh.time().path()/meshRefiner_.timeName()
3504  );
3505  }
3506  }
3507 
3508 
3509  // Duplicate points on faceZones of type boundary. Should normally already
3510  // be done by snapping phase
3511  {
3512  autoPtr<mapPolyMesh> map = meshRefiner_.dupNonManifoldBoundaryPoints();
3513  if (map)
3514  {
3515  const labelList& reverseFaceMap = map->reverseFaceMap();
3516  forAll(baffles, i)
3517  {
3518  label f0 = reverseFaceMap[baffles[i].first()];
3519  label f1 = reverseFaceMap[baffles[i].second()];
3520  baffles[i] = labelPair(f0, f1);
3521  }
3522  }
3523  }
3524 
3525 
3526 
3527  // Now we have all patches determine the number of layer per patch
3528  // This will be layerParams.numLayers() except for faceZones where one
3529  // side does get layers and the other not in which case we want to
3530  // suppress movement by explicitly setting numLayers 0
3531  labelList numLayers(layerParams.numLayers());
3532  {
3533  labelHashSet layerIDs(patchIDs);
3534  forAll(mesh.faceZones(), zonei)
3535  {
3536  label mpi, spi;
3538  bool hasInfo = meshRefiner_.getFaceZoneInfo
3539  (
3540  mesh.faceZones()[zonei].name(),
3541  mpi,
3542  spi,
3543  fzType
3544  );
3545  if (hasInfo)
3546  {
3547  const polyBoundaryMesh& pbm = mesh.boundaryMesh();
3548  if (layerIDs.found(mpi) && !layerIDs.found(spi))
3549  {
3550  // Only layers on master side. Fix points on slave side
3551  Info<< "On faceZone " << mesh.faceZones()[zonei].name()
3552  << " adding layers to master patch " << pbm[mpi].name()
3553  << " only. Freezing points on slave patch "
3554  << pbm[spi].name() << endl;
3555  numLayers[spi] = 0;
3556  }
3557  else if (!layerIDs.found(mpi) && layerIDs.found(spi))
3558  {
3559  // Only layers on slave side. Fix points on master side
3560  Info<< "On faceZone " << mesh.faceZones()[zonei].name()
3561  << " adding layers to slave patch " << pbm[spi].name()
3562  << " only. Freezing points on master patch "
3563  << pbm[mpi].name() << endl;
3564  numLayers[mpi] = 0;
3565  }
3566  }
3567  }
3568  }
3569 
3570 
3571 
3572  // Duplicate points on faceZones that layers are added to
3573  labelList pointToMaster;
3574 
3575  {
3576  // Check outside of baffles for non-manifoldness
3577 
3578  // Points that are candidates for duplication
3579  labelList candidatePoints;
3580  {
3581  // Do full analysis to see if we need to extrude points
3582  // so have to duplicate them
3584  (
3586  (
3587  mesh,
3588  patchIDs
3589  )
3590  );
3591 
3592  // Displacement for all pp.localPoints. Set to large value to
3593  // avoid truncation in syncPatchDisplacement because of
3594  // minThickness.
3595  vectorField patchDisp(pp().nPoints(), vector(GREAT, GREAT, GREAT));
3596  labelList patchNLayers(pp().nPoints(), Zero);
3597  label nIdealTotAddedCells = 0;
3598  List<extrudeMode> extrudeStatus(pp().nPoints(), EXTRUDE);
3599  // Get number of layers per point from number of layers per patch
3600  setNumLayers
3601  (
3602  numLayers, // per patch the num layers
3603  patchIDs, // patches that are being moved
3604  *pp, // indirectpatch for all faces moving
3605 
3606  patchDisp,
3607  patchNLayers,
3608  extrudeStatus,
3609  nIdealTotAddedCells
3610  );
3611  // Make sure displacement is equal on both sides of coupled patches.
3612  // Note that we explicitly disable the minThickness truncation
3613  // of the patchDisp here.
3614  syncPatchDisplacement
3615  (
3616  *pp,
3617  scalarField(patchDisp.size(), Zero), //minThickness,
3618  patchDisp,
3619  patchNLayers,
3620  extrudeStatus
3621  );
3622 
3623 
3624  // Do duplication only if all patch points decide to extrude. Ignore
3625  // contribution from non-patch points. Note that we need to
3626  // apply this to all mesh points
3627  labelList minPatchState(mesh.nPoints(), labelMax);
3628  forAll(extrudeStatus, patchPointi)
3629  {
3630  label pointi = pp().meshPoints()[patchPointi];
3631  minPatchState[pointi] = extrudeStatus[patchPointi];
3632  }
3633 
3635  (
3636  mesh,
3637  minPatchState,
3638  minEqOp<label>(), // combine op
3639  labelMax // null value
3640  );
3641 
3642  // So now minPatchState:
3643  // - labelMax on non-patch points
3644  // - NOEXTRUDE if any patch point was not extruded
3645  // - EXTRUDE or EXTRUDEREMOVE if all patch points are extruded/
3646  // extrudeRemove.
3647 
3648  label n = 0;
3649  forAll(minPatchState, pointi)
3650  {
3651  label state = minPatchState[pointi];
3652  if (state == EXTRUDE || state == EXTRUDEREMOVE)
3653  {
3654  n++;
3655  }
3656  }
3657  candidatePoints.setSize(n);
3658  n = 0;
3659  forAll(minPatchState, pointi)
3660  {
3661  label state = minPatchState[pointi];
3662  if (state == EXTRUDE || state == EXTRUDEREMOVE)
3663  {
3664  candidatePoints[n++] = pointi;
3665  }
3666  }
3667  }
3668 
3669  // Not duplicate points on either side of baffles that don't get any
3670  // layers
3671  labelPairList nonDupBaffles;
3672 
3673  {
3674  // faceZones that are not being duplicated
3675  DynamicList<label> nonDupZones(mesh.faceZones().size());
3676 
3677  labelHashSet layerIDs(patchIDs);
3678  forAll(mesh.faceZones(), zonei)
3679  {
3680  label mpi, spi;
3682  bool hasInfo = meshRefiner_.getFaceZoneInfo
3683  (
3684  mesh.faceZones()[zonei].name(),
3685  mpi,
3686  spi,
3687  fzType
3688  );
3689  if (hasInfo && !layerIDs.found(mpi) && !layerIDs.found(spi))
3690  {
3691  nonDupZones.append(zonei);
3692  }
3693  }
3694  nonDupBaffles = meshRefinement::subsetBaffles
3695  (
3696  mesh,
3697  nonDupZones,
3699  );
3700  }
3701 
3702 
3703  const localPointRegion regionSide(mesh, nonDupBaffles, candidatePoints);
3704 
3705  autoPtr<mapPolyMesh> map = meshRefiner_.dupNonManifoldPoints
3706  (
3707  regionSide
3708  );
3709 
3710  if (map)
3711  {
3712  // Store point duplication
3713  pointToMaster.setSize(mesh.nPoints(), -1);
3714 
3715  const labelList& pointMap = map().pointMap();
3716  const labelList& reversePointMap = map().reversePointMap();
3717 
3718  forAll(pointMap, pointi)
3719  {
3720  label oldPointi = pointMap[pointi];
3721  label newMasterPointi = reversePointMap[oldPointi];
3722 
3723  if (newMasterPointi != pointi)
3724  {
3725  // Found slave. Mark both master and slave
3726  pointToMaster[pointi] = newMasterPointi;
3727  pointToMaster[newMasterPointi] = newMasterPointi;
3728  }
3729  }
3730 
3731  // Update baffle numbering
3732  {
3733  const labelList& reverseFaceMap = map().reverseFaceMap();
3734  forAll(baffles, i)
3735  {
3736  label f0 = reverseFaceMap[baffles[i].first()];
3737  label f1 = reverseFaceMap[baffles[i].second()];
3738  baffles[i] = labelPair(f0, f1);
3739  }
3740  }
3741 
3742 
3744  {
3745  const_cast<Time&>(mesh.time())++;
3746  Info<< "Writing point-duplicate mesh to time "
3747  << meshRefiner_.timeName() << endl;
3748 
3749  meshRefiner_.write
3750  (
3753  (
3756  ),
3757  mesh.time().path()/meshRefiner_.timeName()
3758  );
3759 
3760  OBJstream str
3761  (
3762  mesh.time().path()
3763  / "duplicatePoints_"
3764  + meshRefiner_.timeName()
3765  + ".obj"
3766  );
3767  Info<< "Writing point-duplicates to " << str.name() << endl;
3768  const pointField& p = mesh.points();
3769  forAll(pointMap, pointi)
3770  {
3771  label newMasteri = reversePointMap[pointMap[pointi]];
3772 
3773  if (newMasteri != pointi)
3774  {
3775  str.write(linePointRef(p[pointi], p[newMasteri]));
3776  }
3777  }
3778  }
3779  }
3780  }
3781 
3782 
3783  // Add layers to patches
3784  // ~~~~~~~~~~~~~~~~~~~~~
3785 
3786  // Now we have
3787  // - mesh with optional baffles and duplicated points for faceZones
3788  // where layers are to be added
3789  // - pointToMaster : correspondence for duplicated points
3790  // - baffles : list of pairs of faces
3791 
3792 
3794  (
3796  (
3797  mesh,
3798  patchIDs
3799  )
3800  );
3801 
3802 
3803  // Global face indices engine
3804  const globalIndex globalFaces(mesh.nFaces());
3805 
3806  // Determine extrudePatch.edgeFaces in global numbering (so across
3807  // coupled patches). This is used only to string up edges between coupled
3808  // faces (all edges between same (global)face indices get extruded).
3809  labelListList edgeGlobalFaces
3810  (
3812  (
3813  mesh,
3814  globalFaces,
3815  *pp
3816  )
3817  );
3818 
3819  // Determine patches for extruded boundary edges. Calculates if any
3820  // additional processor patches need to be constructed.
3821 
3822  labelList edgePatchID;
3823  labelList edgeZoneID;
3824  boolList edgeFlip;
3825  labelList inflateFaceID;
3826  determineSidePatches
3827  (
3828  globalFaces,
3829  edgeGlobalFaces,
3830  *pp,
3831 
3832  edgePatchID,
3833  edgeZoneID,
3834  edgeFlip,
3835  inflateFaceID
3836  );
3837 
3838 
3839  // Point-wise extrusion data
3840  // ~~~~~~~~~~~~~~~~~~~~~~~~~
3841 
3842  // Displacement for all pp.localPoints. Set to large value so does
3843  // not trigger the minThickness truncation (see syncPatchDisplacement below)
3844  vectorField patchDisp(pp().nPoints(), vector(GREAT, GREAT, GREAT));
3845 
3846  // Number of layers for all pp.localPoints. Note: only valid if
3847  // extrudeStatus = EXTRUDE.
3848  labelList patchNLayers(pp().nPoints(), Zero);
3849 
3850  // Ideal number of cells added
3851  label nIdealTotAddedCells = 0;
3852 
3853  // Whether to add edge for all pp.localPoints.
3854  List<extrudeMode> extrudeStatus(pp().nPoints(), EXTRUDE);
3855 
3856 
3857  {
3858  // Get number of layers per point from number of layers per patch
3859  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3860 
3861  setNumLayers
3862  (
3863  numLayers, // per patch the num layers
3864  patchIDs, // patches that are being moved
3865  *pp, // indirectpatch for all faces moving
3866 
3867  patchDisp,
3868  patchNLayers,
3869  extrudeStatus,
3870  nIdealTotAddedCells
3871  );
3872 
3873  // Precalculate mesh edge labels for patch edges
3874  labelList meshEdges(pp().meshEdges(mesh.edges(), mesh.pointEdges()));
3875 
3876 
3877  // Disable extrusion on split strings of common points
3878  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3879 
3880  handleNonStringConnected
3881  (
3882  *pp,
3883  patchDisp,
3884  patchNLayers,
3885  extrudeStatus
3886  );
3887 
3888 
3889  // Disable extrusion on non-manifold points
3890  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3891 
3892  handleNonManifolds
3893  (
3894  *pp,
3895  meshEdges,
3896  edgeGlobalFaces,
3897 
3898  patchDisp,
3899  patchNLayers,
3900  extrudeStatus
3901  );
3902 
3903  // Disable extrusion on feature angles
3904  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3905 
3906  handleFeatureAngle
3907  (
3908  *pp,
3909  meshEdges,
3910  layerParams.featureAngle(),
3911 
3912  patchDisp,
3913  patchNLayers,
3914  extrudeStatus
3915  );
3916 
3917  // Disable extrusion on warped faces
3918  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3919  // It is hard to calculate some length scale if not in relative
3920  // mode so disable this check.
3921  if (!layerParams.relativeSizes().found(false))
3922  {
3923  // Undistorted edge length
3924  const scalar edge0Len =
3925  meshRefiner_.meshCutter().level0EdgeLength();
3926  const labelList& cellLevel = meshRefiner_.meshCutter().cellLevel();
3927 
3928  handleWarpedFaces
3929  (
3930  *pp,
3931  layerParams.maxFaceThicknessRatio(),
3932  layerParams.relativeSizes(),
3933  edge0Len,
3934  cellLevel,
3935 
3936  patchDisp,
3937  patchNLayers,
3938  extrudeStatus
3939  );
3940  }
3941 
3944  //
3945  //handleMultiplePatchFaces
3946  //(
3947  // *pp,
3948  //
3949  // patchDisp,
3950  // patchNLayers,
3951  // extrudeStatus
3952  //);
3953 
3954  addProfiling(grow, "snappyHexMesh::layers::grow");
3955 
3956  // Grow out region of non-extrusion
3957  for (label i = 0; i < layerParams.nGrow(); i++)
3958  {
3959  growNoExtrusion
3960  (
3961  *pp,
3962  patchDisp,
3963  patchNLayers,
3964  extrudeStatus
3965  );
3966  }
3967  }
3968 
3969 
3970  // Undistorted edge length
3971  const scalar edge0Len = meshRefiner_.meshCutter().level0EdgeLength();
3972  const labelList& cellLevel = meshRefiner_.meshCutter().cellLevel();
3973 
3974  // Determine (wanted) point-wise overall layer thickness and expansion
3975  // ratio
3976  scalarField thickness(pp().nPoints());
3977  scalarIOField minThickness
3978  (
3979  IOobject
3980  (
3981  "minThickness",
3982  meshRefiner_.timeName(),
3983  mesh,
3985  ),
3986  pp().nPoints()
3987  );
3988  scalarField expansionRatio(pp().nPoints());
3989  calculateLayerThickness
3990  (
3991  *pp,
3992  patchIDs,
3993  layerParams,
3994  cellLevel,
3995  patchNLayers,
3996  edge0Len,
3997 
3998  thickness,
3999  minThickness,
4000  expansionRatio
4001  );
4002 
4003 
4004 
4005  // Current set of topology changes. (changing mesh clears out
4006  // polyTopoChange)
4007  polyTopoChange savedMeshMod(mesh.boundaryMesh().size());
4008  // Per cell 0 or number of layers in the cell column it is part of
4009  labelList cellNLayers;
4010  // Per face actual overall layer thickness
4011  scalarField faceRealThickness;
4012  // Per face wanted overall layer thickness
4013  scalarField faceWantedThickness(mesh.nFaces(), Zero);
4014  {
4015  UIndirectList<scalar>(faceWantedThickness, pp->addressing()) =
4016  avgPointData(*pp, thickness);
4017  }
4018 
4019 
4020  {
4021  // Overall displacement field
4022  pointVectorField displacement
4023  (
4024  makeLayerDisplacementField
4025  (
4027  numLayers
4028  )
4029  );
4030 
4031  // Allocate run-time selectable mesh mover
4032  autoPtr<externalDisplacementMeshMover> medialAxisMoverPtr;
4033  {
4034  // Set up controls for meshMover
4035  dictionary combinedDict(layerParams.dict());
4036  // Add mesh quality constraints
4037  combinedDict.merge(motionDict);
4038  // Where to get minThickness from
4039  combinedDict.add("minThicknessName", minThickness.name());
4040 
4041  const List<labelPair> internalBaffles
4042  (
4044  (
4045  mesh,
4046  internalFaceZones,
4048  )
4049  );
4050 
4051  // Take over patchDisp as boundary conditions on displacement
4052  // pointVectorField
4053  medialAxisMoverPtr = externalDisplacementMeshMover::New
4054  (
4055  layerParams.meshShrinker(),
4056  combinedDict,
4057  internalBaffles,
4058  displacement
4059  );
4060 
4061 
4062  if (dryRun_)
4063  {
4064  string errorMsg(FatalError.message());
4065  string IOerrorMsg(FatalIOError.message());
4066 
4067  if (errorMsg.size() || IOerrorMsg.size())
4068  {
4069  //errorMsg = "[dryRun] " + errorMsg;
4070  //errorMsg.replaceAll("\n", "\n[dryRun] ");
4071  //IOerrorMsg = "[dryRun] " + IOerrorMsg;
4072  //IOerrorMsg.replaceAll("\n", "\n[dryRun] ");
4073 
4074  IOWarningInFunction(combinedDict)
4075  << nl
4076  << "Missing/incorrect required dictionary entries:"
4077  << nl << nl
4078  << IOerrorMsg.c_str() << nl
4079  << errorMsg.c_str() << nl << nl
4080  << "Exiting dry-run" << nl << endl;
4081 
4082  if (Pstream::parRun())
4083  {
4084  Perr<< "\nFOAM parallel run exiting\n" << endl;
4085  Pstream::exit(0);
4086  }
4087  else
4088  {
4089  Perr<< "\nFOAM exiting\n" << endl;
4090  std::exit(0);
4091  }
4092  }
4093  }
4094  }
4095 
4096 
4097  // Saved old points
4098  const pointField oldPoints(mesh.points());
4099 
4100  for
4101  (
4102  label iteration = 0;
4103  iteration < layerParams.nLayerIter();
4104  iteration++
4105  )
4106  {
4107  Info<< nl
4108  << "Layer addition iteration " << iteration << nl
4109  << "--------------------------" << endl;
4110 
4111 
4112  // Unset the extrusion at the pp.
4113  const dictionary& meshQualityDict =
4114  (
4115  iteration < layerParams.nRelaxedIter()
4116  ? motionDict
4117  : motionDict.subDict("relaxed")
4118  );
4119 
4120  if (iteration >= layerParams.nRelaxedIter())
4121  {
4122  Info<< "Switched to relaxed meshQuality constraints." << endl;
4123  }
4124 
4125 
4126 
4127  // Make sure displacement is equal on both sides of coupled patches.
4128  // Note that this also does the patchDisp < minThickness truncation
4129  // so for the first pass make sure the patchDisp is larger than
4130  // that.
4131  syncPatchDisplacement
4132  (
4133  *pp,
4134  minThickness,
4135  patchDisp,
4136  patchNLayers,
4137  extrudeStatus
4138  );
4139 
4140  // Displacement acc. to pointnormals
4141  getPatchDisplacement
4142  (
4143  *pp,
4144  thickness,
4145  minThickness,
4146  expansionRatio,
4147 
4148  patchDisp,
4149  patchNLayers,
4150  extrudeStatus
4151  );
4152 
4153  // Shrink mesh by displacement value first.
4154  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4155 
4156  {
4157  const pointField oldPatchPos(pp().localPoints());
4158 
4159  // We have patchDisp which is the outwards pointing
4160  // extrusion distance. Convert into an inwards pointing
4161  // shrink distance
4162  patchDisp = -patchDisp;
4163 
4164  // Take over patchDisp into pointDisplacement field and
4165  // adjust both for multi-patch constraints
4167  (
4168  patchIDs,
4169  *pp,
4170  patchDisp,
4171  displacement
4172  );
4173 
4174 
4175  // Move mesh
4176  // ~~~~~~~~~
4177 
4178  // Set up controls for meshMover
4179  dictionary combinedDict(layerParams.dict());
4180  // Add standard quality constraints
4181  combinedDict.merge(motionDict);
4182  // Add relaxed constraints (overrides standard ones)
4183  combinedDict.merge(meshQualityDict);
4184  // Where to get minThickness from
4185  combinedDict.add("minThicknessName", minThickness.name());
4186 
4187  labelList checkFaces(identity(mesh.nFaces()));
4188  medialAxisMoverPtr().move
4189  (
4190  combinedDict,
4191  nAllowableErrors,
4192  checkFaces
4193  );
4194 
4195  pp().movePoints(mesh.points());
4196 
4197  // Update patchDisp (since not all might have been honoured)
4198  patchDisp = oldPatchPos - pp().localPoints();
4199  }
4200 
4201  // Truncate displacements that are too small (this will do internal
4202  // ones, coupled ones have already been truncated by
4203  // syncPatchDisplacement)
4204  faceSet dummySet(mesh, "wrongPatchFaces", 0);
4205  truncateDisplacement
4206  (
4207  globalFaces,
4208  edgeGlobalFaces,
4209  *pp,
4210  minThickness,
4211  dummySet,
4212  patchDisp,
4213  patchNLayers,
4214  extrudeStatus
4215  );
4216 
4217 
4218  // Dump to .obj file for debugging.
4220  {
4221  dumpDisplacement
4222  (
4223  mesh.time().path()/"layer_" + meshRefiner_.timeName(),
4224  pp(),
4225  patchDisp,
4226  extrudeStatus
4227  );
4228 
4229  const_cast<Time&>(mesh.time())++;
4230  Info<< "Writing shrunk mesh to time "
4231  << meshRefiner_.timeName() << endl;
4232 
4233  // See comment in snappySnapDriver why we should not remove
4234  // meshPhi using mesh.clearOut().
4235 
4236  meshRefiner_.write
4237  (
4240  (
4243  ),
4244  mesh.time().path()/meshRefiner_.timeName()
4245  );
4246  }
4247 
4248 
4249  // Mesh topo change engine. Insert current mesh.
4250  polyTopoChange meshMod(mesh);
4251 
4252  // Grow layer of cells on to patch. Handles zero sized displacement.
4253  addPatchCellLayer addLayer(mesh);
4254 
4255  // Determine per point/per face number of layers to extrude. Also
4256  // handles the slow termination of layers when going switching
4257  // layers
4258 
4259  labelList nPatchPointLayers(pp().nPoints(), -1);
4260  labelList nPatchFaceLayers(pp().size(), -1);
4261  setupLayerInfoTruncation
4262  (
4263  *pp,
4264  patchNLayers,
4265  extrudeStatus,
4266  layerParams.nBufferCellsNoExtrude(),
4267  nPatchPointLayers,
4268  nPatchFaceLayers
4269  );
4270 
4271  // Calculate displacement for final layer for addPatchLayer.
4272  // (layer of cells next to the original mesh)
4273  vectorField finalDisp(patchNLayers.size(), Zero);
4274 
4275  forAll(nPatchPointLayers, i)
4276  {
4278  (
4279  nPatchPointLayers[i],
4280  expansionRatio[i]
4281  );
4282  finalDisp[i] = ratio*patchDisp[i];
4283  }
4284 
4285 
4286  const scalarField invExpansionRatio(1.0/expansionRatio);
4287 
4288  // Add topo regardless of whether extrudeStatus is extruderemove.
4289  // Not add layer if patchDisp is zero.
4290  addLayer.setRefinement
4291  (
4292  globalFaces,
4293  edgeGlobalFaces,
4294 
4295  invExpansionRatio,
4296  pp(),
4297 
4298  edgePatchID, // boundary patch for extruded boundary edges
4299  edgeZoneID, // zone for extruded edges
4300  edgeFlip,
4301  inflateFaceID,
4302 
4303 
4304  labelList(0), // exposed patchIDs, not used for adding layers
4305  nPatchFaceLayers, // layers per face
4306  nPatchPointLayers, // layers per point
4307  finalDisp, // thickness of layer nearest internal mesh
4308  meshMod
4309  );
4310 
4311  if (debug)
4312  {
4313  const_cast<Time&>(mesh.time())++;
4314  }
4315 
4316  // Store mesh changes for if mesh is correct.
4317  savedMeshMod = meshMod;
4318 
4319 
4320  // With the stored topo changes we create a new mesh so we can
4321  // undo if necessary.
4322 
4323  autoPtr<fvMesh> newMeshPtr;
4324  autoPtr<mapPolyMesh> mapPtr = meshMod.makeMesh
4325  (
4326  newMeshPtr,
4327  IOobject
4328  (
4329  //mesh.name()+"_layer",
4330  mesh.name(),
4331  static_cast<polyMesh&>(mesh).instance(),
4332  mesh.time(), // register with runTime
4333  IOobject::READ_IF_PRESENT, // read fv* if present
4334  static_cast<polyMesh&>(mesh).writeOpt()
4335  ), // io params from original mesh but new name
4336  mesh, // original mesh
4337  true // parallel sync
4338  );
4339  fvMesh& newMesh = *newMeshPtr;
4340  mapPolyMesh& map = *mapPtr;
4341 
4342  // Get timing, but more importantly get memory information
4343  addProfiling(grow, "snappyHexMesh::layers::updateMesh");
4344 
4345  //?necessary? Update fields
4346  newMesh.updateMesh(map);
4347 
4348  newMesh.setInstance(meshRefiner_.timeName());
4349 
4350  // Update numbering on addLayer:
4351  // - cell/point labels to be newMesh.
4352  // - patchFaces to remain in oldMesh order.
4353  addLayer.updateMesh
4354  (
4355  map,
4356  identity(pp().size()),
4357  identity(pp().nPoints())
4358  );
4359 
4360  // Collect layer faces and cells for outside loop.
4361  getLayerCellsFaces
4362  (
4363  newMesh,
4364  addLayer,
4365  avgPointData(*pp, mag(patchDisp))(), // current thickness
4366 
4367  cellNLayers,
4368  faceRealThickness
4369  );
4370 
4371 
4372  // Count number of added cells
4373  label nAddedCells = 0;
4374  forAll(cellNLayers, celli)
4375  {
4376  if (cellNLayers[celli] > 0)
4377  {
4378  nAddedCells++;
4379  }
4380  }
4381 
4382 
4384  {
4385  Info<< "Writing layer mesh to time " << meshRefiner_.timeName()
4386  << endl;
4387  newMesh.write();
4388  writeLayerSets(newMesh, cellNLayers, faceRealThickness);
4389 
4390  // Reset the instance of the original mesh so next iteration
4391  // it dumps a complete mesh. This is just so that the inbetween
4392  // newMesh does not upset e.g. paraFoam cycling through the
4393  // times.
4394  mesh.setInstance(meshRefiner_.timeName());
4395  }
4396 
4397 
4398  //- Get baffles in newMesh numbering. Note that we cannot detect
4399  // baffles here since the points are duplicated
4400  List<labelPair> internalBaffles;
4401  {
4402  // From old mesh face to corresponding newMesh boundary face
4403  labelList meshToNewMesh(mesh.nFaces(), -1);
4404  for
4405  (
4406  label facei = newMesh.nInternalFaces();
4407  facei < newMesh.nFaces();
4408  facei++
4409  )
4410  {
4411  label newMeshFacei = map.faceMap()[facei];
4412  if (newMeshFacei != -1)
4413  {
4414  meshToNewMesh[newMeshFacei] = facei;
4415  }
4416  }
4417 
4418  List<labelPair> newMeshBaffles(baffles.size());
4419  label newi = 0;
4420  forAll(baffles, i)
4421  {
4422  const labelPair& p = baffles[i];
4423  labelPair newMeshBaffle
4424  (
4425  meshToNewMesh[p[0]],
4426  meshToNewMesh[p[1]]
4427  );
4428  if (newMeshBaffle[0] != -1 && newMeshBaffle[1] != -1)
4429  {
4430  newMeshBaffles[newi++] = newMeshBaffle;
4431  }
4432  }
4433  newMeshBaffles.setSize(newi);
4434 
4435  internalBaffles = meshRefinement::subsetBaffles
4436  (
4437  newMesh,
4438  internalFaceZones,
4439  newMeshBaffles
4440  );
4441 
4442  Info<< "Detected "
4443  << returnReduce(internalBaffles.size(), sumOp<label>())
4444  << " baffles across faceZones of type internal" << nl
4445  << endl;
4446  }
4447 
4448  label nTotChanged = checkAndUnmark
4449  (
4450  addLayer,
4451  meshQualityDict,
4452  layerParams.additionalReporting(),
4453  internalBaffles,
4454  pp(),
4455  newMesh,
4456 
4457  patchDisp,
4458  patchNLayers,
4459  extrudeStatus
4460  );
4461 
4462  label nTotExtruded = countExtrusion(*pp, extrudeStatus);
4463  label nTotFaces = returnReduce(pp().size(), sumOp<label>());
4464  label nTotAddedCells = returnReduce(nAddedCells, sumOp<label>());
4465 
4466  Info<< "Extruding " << nTotExtruded
4467  << " out of " << nTotFaces
4468  << " faces (" << 100.0*nTotExtruded/nTotFaces << "%)."
4469  << " Removed extrusion at " << nTotChanged << " faces."
4470  << endl
4471  << "Added " << nTotAddedCells << " out of "
4472  << nIdealTotAddedCells
4473  << " cells (" << 100.0*nTotAddedCells/nIdealTotAddedCells
4474  << "%)." << endl;
4475 
4476  if (nTotChanged == 0)
4477  {
4478  break;
4479  }
4480 
4481  // Reset mesh points and start again
4482  mesh.movePoints(oldPoints);
4483  pp().movePoints(mesh.points());
4484  medialAxisMoverPtr().movePoints(mesh.points());
4485 
4486  // Grow out region of non-extrusion
4487  for (label i = 0; i < layerParams.nGrow(); i++)
4488  {
4489  growNoExtrusion
4490  (
4491  *pp,
4492  patchDisp,
4493  patchNLayers,
4494  extrudeStatus
4495  );
4496  }
4497 
4498  Info<< endl;
4499  }
4500  }
4501 
4502 
4503  // At this point we have a (shrunk) mesh and a set of topology changes
4504  // which will make a valid mesh with layer. Apply these changes to the
4505  // current mesh.
4506 
4507  {
4508  // Apply the stored topo changes to the current mesh.
4509  autoPtr<mapPolyMesh> mapPtr = savedMeshMod.changeMesh(mesh, false);
4510  mapPolyMesh& map = *mapPtr;
4511 
4512  // Hack to remove meshPhi - mapped incorrectly. TBD.
4513  mesh.clearOut();
4514 
4515  // Update fields
4516  mesh.updateMesh(map);
4517 
4518  // Move mesh (since morphing does not do this)
4519  if (map.hasMotionPoints())
4520  {
4522  }
4523  else
4524  {
4525  // Delete mesh volumes.
4526  mesh.clearOut();
4527  }
4528 
4529  // Reset the instance for if in overwrite mode
4530  mesh.setInstance(meshRefiner_.timeName());
4531 
4532  meshRefiner_.updateMesh(map, labelList(0));
4533 
4534  // Update numbering of faceWantedThickness
4536  (
4537  map.faceMap(),
4538  scalar(0),
4539  faceWantedThickness
4540  );
4541 
4542  // Print data now that we still have patches for the zones
4543  //if (meshRefinement::outputLevel() & meshRefinement::OUTPUTLAYERINFO)
4544  printLayerData
4545  (
4546  mesh,
4547  patchIDs,
4548  cellNLayers,
4549  faceWantedThickness,
4550  faceRealThickness
4551  );
4552 
4553 
4554  // Dump for debugging
4556  {
4557  const_cast<Time&>(mesh.time())++;
4558  Info<< "Writing mesh with layers but disconnected to time "
4559  << meshRefiner_.timeName() << endl;
4560  meshRefiner_.write
4561  (
4564  (
4567  ),
4568  mesh.time().path()/meshRefiner_.timeName()
4569  );
4570  }
4571 
4572 
4573  // Use geometric detection of points-to-be-merged
4574  // - detect any boundary face created from a duplicated face (=baffle)
4575  // - on these mark any point created from a duplicated point
4576  if (returnReduce(pointToMaster.size(), sumOp<label>()))
4577  {
4578  // Estimate number of points-to-be-merged
4579  DynamicList<label> candidates(baffles.size()*4);
4580 
4581  // Mark whether old face was on baffle
4582  bitSet oldBaffleFace(map.nOldFaces());
4583  forAll(baffles, i)
4584  {
4585  const labelPair& baffle = baffles[i];
4586  oldBaffleFace.set(baffle[0]);
4587  oldBaffleFace.set(baffle[1]);
4588  }
4589 
4590  // Collect candidate if
4591  // - point on boundary face originating from baffle
4592  // - and point originating from duplicate
4593  for
4594  (
4595  label facei = mesh.nInternalFaces();
4596  facei < mesh.nFaces();
4597  facei++
4598  )
4599  {
4600  label oldFacei = map.faceMap()[facei];
4601  if (oldFacei != -1 && oldBaffleFace.test(oldFacei))
4602  {
4603  const face& f = mesh.faces()[facei];
4604  forAll(f, fp)
4605  {
4606  label pointi = f[fp];
4607  label oldPointi = map.pointMap()[pointi];
4608 
4609  if (pointToMaster[oldPointi] != -1)
4610  {
4611  candidates.append(pointi);
4612  }
4613  }
4614  }
4615  }
4616 
4617 
4618  // Do geometric merge. Ideally we'd like to use a topological
4619  // merge but we've thrown away all layer-wise addressing when
4620  // throwing away addPatchCellLayer engine. Also the addressing
4621  // is extremely complicated. There is no problem with merging
4622  // too many points; the problem would be if merging baffles.
4623  // Trust mergeZoneBaffles to do sufficient checks.
4624  labelList oldToNew;
4625  label nNew = mergePoints
4626  (
4627  pointField(mesh.points(), candidates),
4628  meshRefiner_.mergeDistance(),
4629  false,
4630  oldToNew
4631  );
4632 
4633  // Extract points to be merged (i.e. multiple points originating
4634  // from a single one)
4635 
4636  labelListList newToOld(invertOneToMany(nNew, oldToNew));
4637 
4638  // Extract points with more than one old one
4639  pointToMaster.setSize(mesh.nPoints());
4640  pointToMaster = -1;
4641 
4642  forAll(newToOld, newi)
4643  {
4644  const labelList& oldPoints = newToOld[newi];
4645  if (oldPoints.size() > 1)
4646  {
4647  labelList meshPoints
4648  (
4649  labelUIndList(candidates, oldPoints)
4650  );
4651  label masteri = min(meshPoints);
4652  forAll(meshPoints, i)
4653  {
4654  pointToMaster[meshPoints[i]] = masteri;
4655  }
4656  }
4657  }
4658  }
4659  }
4660 
4661 
4662 
4663 
4664 
4665  // Count duplicate points
4666  label nPointPairs = 0;
4667  forAll(pointToMaster, pointi)
4668  {
4669  label otherPointi = pointToMaster[pointi];
4670  if (otherPointi != -1)
4671  {
4672  nPointPairs++;
4673  }
4674  }
4675  reduce(nPointPairs, sumOp<label>());
4676  if (nPointPairs > 0)
4677  {
4678  // Merge any duplicated points
4679  Info<< "Merging " << nPointPairs << " duplicated points ..." << endl;
4680 
4682  {
4683  OBJstream str
4684  (
4685  mesh.time().path()
4686  / "mergePoints_"
4687  + meshRefiner_.timeName()
4688  + ".obj"
4689  );
4690  Info<< "Points to be merged to " << str.name() << endl;
4691  forAll(pointToMaster, pointi)
4692  {
4693  label otherPointi = pointToMaster[pointi];
4694  if (otherPointi != -1)
4695  {
4696  const point& pt = mesh.points()[pointi];
4697  const point& otherPt = mesh.points()[otherPointi];
4698  str.write(linePointRef(pt, otherPt));
4699  }
4700  }
4701  }
4702 
4703 
4704  autoPtr<mapPolyMesh> map = meshRefiner_.mergePoints(pointToMaster);
4705  if (map)
4706  {
4707  inplaceReorder(map().reverseCellMap(), cellNLayers);
4708 
4709  const labelList& reverseFaceMap = map().reverseFaceMap();
4710  inplaceReorder(reverseFaceMap, faceWantedThickness);
4711  inplaceReorder(reverseFaceMap, faceRealThickness);
4712 
4713  Info<< "Merged points in = "
4714  << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl;
4715  }
4716  }
4717 
4718  if (mesh.faceZones().size() > 0)
4719  {
4720  // Merge any baffles
4721  Info<< "Converting baffles back into zoned faces ..."
4722  << endl;
4723 
4724  autoPtr<mapPolyMesh> map = meshRefiner_.mergeZoneBaffles
4725  (
4726  true, // internal zones
4727  false // baffle zones
4728  );
4729  if (map)
4730  {
4731  inplaceReorder(map().reverseCellMap(), cellNLayers);
4732 
4733  const labelList& faceMap = map().faceMap();
4734 
4735  // Make sure to keep the max since on two patches only one has
4736  // layers.
4737  scalarField newFaceRealThickness(mesh.nFaces(), Zero);
4738  scalarField newFaceWantedThickness(mesh.nFaces(), Zero);
4739  forAll(newFaceRealThickness, facei)
4740  {
4741  label oldFacei = faceMap[facei];
4742  if (oldFacei >= 0)
4743  {
4744  scalar& realThick = newFaceRealThickness[facei];
4745  realThick = max(realThick, faceRealThickness[oldFacei]);
4746  scalar& wanted = newFaceWantedThickness[facei];
4747  wanted = max(wanted, faceWantedThickness[oldFacei]);
4748  }
4749  }
4750  faceRealThickness.transfer(newFaceRealThickness);
4751  faceWantedThickness.transfer(newFaceWantedThickness);
4752  }
4753 
4754  Info<< "Converted baffles in = "
4755  << meshRefiner_.mesh().time().cpuTimeIncrement()
4756  << " s\n" << nl << endl;
4757  }
4758 
4759  // Do final balancing
4760  // ~~~~~~~~~~~~~~~~~~
4761 
4762  if (Pstream::parRun())
4763  {
4764  Info<< nl
4765  << "Doing final balancing" << nl
4766  << "---------------------" << nl
4767  << endl;
4768 
4769  if (debug)
4770  {
4771  const_cast<Time&>(mesh.time())++;
4772  }
4773 
4774  // Balance. No restriction on face zones and baffles.
4775  autoPtr<mapDistributePolyMesh> map = meshRefiner_.balance
4776  (
4777  false,
4778  false,
4779  scalarField(mesh.nCells(), 1.0),
4780  decomposer,
4781  distributor
4782  );
4783 
4784  // Re-distribute flag of layer faces and cells
4785  map().distributeCellData(cellNLayers);
4786  map().distributeFaceData(faceWantedThickness);
4787  map().distributeFaceData(faceRealThickness);
4788  }
4789 
4790 
4791  // Write mesh data
4792  // ~~~~~~~~~~~~~~~
4793 
4794  if (!dryRun_)
4795  {
4796  writeLayerData
4797  (
4798  mesh,
4799  patchIDs,
4800  cellNLayers,
4801  faceWantedThickness,
4802  faceRealThickness
4803  );
4804  }
4805 }
4806 
4807 
4810  const dictionary& shrinkDict,
4811  const dictionary& motionDict,
4812  const layerParameters& layerParams,
4813  const meshRefinement::FaceMergeType mergeType,
4814  const bool preBalance,
4815  decompositionMethod& decomposer,
4816  fvMeshDistribute& distributor
4817 )
4818 {
4819  addProfiling(layers, "snappyHexMesh::layers");
4820  const fvMesh& mesh = meshRefiner_.mesh();
4821 
4822  Info<< nl
4823  << "Shrinking and layer addition phase" << nl
4824  << "----------------------------------" << nl
4825  << endl;
4826 
4827 
4828  Info<< "Using mesh parameters " << motionDict << nl << endl;
4829 
4830  // Merge coplanar boundary faces
4831  if
4832  (
4833  mergeType == meshRefinement::FaceMergeType::GEOMETRIC
4834  || mergeType == meshRefinement::FaceMergeType::IGNOREPATCH
4835  )
4836  {
4837  mergePatchFacesUndo(layerParams, motionDict, mergeType);
4838  }
4839 
4840 
4841  // Per patch the number of layers (-1 or 0 if no layer)
4842  const labelList& numLayers = layerParams.numLayers();
4843 
4844  // Patches that need to get a layer
4845  DynamicList<label> patchIDs(numLayers.size());
4846  label nFacesWithLayers = 0;
4847  forAll(numLayers, patchi)
4848  {
4849  if (numLayers[patchi] > 0)
4850  {
4851  const polyPatch& pp = mesh.boundaryMesh()[patchi];
4852 
4853  if (!pp.coupled())
4854  {
4855  patchIDs.append(patchi);
4856  nFacesWithLayers += mesh.boundaryMesh()[patchi].size();
4857  }
4858  else
4859  {
4861  << "Ignoring layers on coupled patch " << pp.name()
4862  << endl;
4863  }
4864  }
4865  }
4866 
4867  // Add contributions from faceZones that get layers
4868  const faceZoneMesh& fZones = mesh.faceZones();
4869  forAll(fZones, zonei)
4870  {
4871  label mpi, spi;
4873  meshRefiner_.getFaceZoneInfo(fZones[zonei].name(), mpi, spi, fzType);
4874 
4875  if (numLayers[mpi] > 0)
4876  {
4877  nFacesWithLayers += fZones[zonei].size();
4878  }
4879  if (numLayers[spi] > 0)
4880  {
4881  nFacesWithLayers += fZones[zonei].size();
4882  }
4883  }
4884 
4885 
4886  patchIDs.shrink();
4887 
4888  if (returnReduce(nFacesWithLayers, sumOp<label>()) == 0)
4889  {
4890  Info<< nl << "No layers to generate ..." << endl;
4891  }
4892  else
4893  {
4894  // Check that outside of mesh is not multiply connected.
4895  checkMeshManifold();
4896 
4897  // Check initial mesh
4898  Info<< "Checking initial mesh ..." << endl;
4899  labelHashSet wrongFaces(mesh.nFaces()/100);
4900  motionSmoother::checkMesh(false, mesh, motionDict, wrongFaces, dryRun_);
4901  const label nInitErrors = returnReduce
4902  (
4903  wrongFaces.size(),
4904  sumOp<label>()
4905  );
4906 
4907  Info<< "Detected " << nInitErrors << " illegal faces"
4908  << " (concave, zero area or negative cell pyramid volume)"
4909  << endl;
4910 
4911 
4912  bool faceZoneOnCoupledFace = false;
4913 
4914  if (!preBalance)
4915  {
4916  // Check if there are faceZones on processor boundaries. This
4917  // requires balancing to move them off the processor boundaries.
4918 
4919  // Is face on a faceZone
4920  bitSet isExtrudedZoneFace(mesh.nFaces());
4921  {
4922  // Add contributions from faceZones that get layers
4923  const faceZoneMesh& fZones = mesh.faceZones();
4924  forAll(fZones, zonei)
4925  {
4926  const faceZone& fZone = fZones[zonei];
4927  const word& fzName = fZone.name();
4928 
4929  label mpi, spi;
4931  meshRefiner_.getFaceZoneInfo(fzName, mpi, spi, fzType);
4932 
4933  if (numLayers[mpi] > 0 || numLayers[spi])
4934  {
4935  isExtrudedZoneFace.set(fZone);
4936  }
4937  }
4938  }
4939 
4940  bitSet intOrCoupled
4941  (
4943  );
4944 
4945  for
4946  (
4947  label facei = mesh.nInternalFaces();
4948  facei < mesh.nFaces();
4949  facei++
4950  )
4951  {
4952  if (intOrCoupled[facei] && isExtrudedZoneFace.test(facei))
4953  {
4954  faceZoneOnCoupledFace = true;
4955  break;
4956  }
4957  }
4958 
4959  reduce(faceZoneOnCoupledFace, orOp<bool>());
4960  }
4961 
4962 
4963 
4964 
4965  // Balance
4966  if (Pstream::parRun() && (preBalance || faceZoneOnCoupledFace))
4967  {
4968  Info<< nl
4969  << "Doing initial balancing" << nl
4970  << "-----------------------" << nl
4971  << endl;
4972 
4973  scalarField cellWeights(mesh.nCells(), 1);
4974  forAll(numLayers, patchi)
4975  {
4976  if (numLayers[patchi] > 0)
4977  {
4978  const polyPatch& pp = mesh.boundaryMesh()[patchi];
4979  forAll(pp.faceCells(), i)
4980  {
4981  cellWeights[pp.faceCells()[i]] += numLayers[patchi];
4982  }
4983  }
4984  }
4985 
4986  // Add contributions from faceZones that get layers
4987  const faceZoneMesh& fZones = mesh.faceZones();
4988  forAll(fZones, zonei)
4989  {
4990  const faceZone& fZone = fZones[zonei];
4991  const word& fzName = fZone.name();
4992 
4993  label mpi, spi;
4995  meshRefiner_.getFaceZoneInfo(fzName, mpi, spi, fzType);
4996 
4997  if (numLayers[mpi] > 0)
4998  {
4999  // Get the owner side for unflipped faces, neighbour side
5000  // for flipped ones
5001  const labelList& cellIDs = fZone.slaveCells();
5002  forAll(cellIDs, i)
5003  {
5004  if (cellIDs[i] >= 0)
5005  {
5006  cellWeights[cellIDs[i]] += numLayers[mpi];
5007  }
5008  }
5009  }
5010  if (numLayers[spi] > 0)
5011  {
5012  const labelList& cellIDs = fZone.masterCells();
5013  forAll(cellIDs, i)
5014  {
5015  if (cellIDs[i] >= 0)
5016  {
5017  cellWeights[cellIDs[i]] += numLayers[mpi];
5018  }
5019  }
5020  }
5021  }
5022 
5023  // Balance mesh (and meshRefinement). Restrict faceZones to
5024  // be on internal faces only since they will be converted into
5025  // baffles.
5026  autoPtr<mapDistributePolyMesh> map = meshRefiner_.balance
5027  (
5028  true, // keepZoneFaces
5029  false,
5030  cellWeights,
5031  decomposer,
5032  distributor
5033  );
5034  }
5035 
5036 
5037  // Do all topo changes
5038  addLayers
5039  (
5040  layerParams,
5041  motionDict,
5042  patchIDs,
5043  nInitErrors,
5044  decomposer,
5045  distributor
5046  );
5047  }
5048 }
5049 
5050 
5051 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::VectorSpace< Vector< Cmpt >, Cmpt, 3 >::rootMax
static const Vector< Cmpt > rootMax
Definition: VectorSpace.H:119
Foam::layerParameters::nGrow
label nGrow() const
If points get not extruded do nGrow layers of connected faces.
Definition: layerParameters.H:307
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:71
Foam::setf
Smanip< ios_base::fmtflags > setf(const ios_base::fmtflags flags)
Definition: IOmanip.H:169
profiling.H
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
addPatchCellLayer.H
Foam::polyMesh::points
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1069
Foam::scalarField
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Definition: primitiveFieldsFwd.H:52
Foam::IOobject
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition: IOobject.H:104
p
volScalarField & p
Definition: createFieldRefs.H:8
Foam::PatchTools::pointNormals
static tmp< pointField > pointNormals(const polyMesh &, const PrimitivePatch< FaceList, PointField > &)
Return parallel consistent point normals for patches using mesh points.
Foam::IOobject::AUTO_WRITE
Definition: IOobject.H:129
Foam::localPointRegion
Takes mesh with 'baffles' (= boundary faces sharing points). Determines for selected points on bounda...
Definition: localPointRegion.H:69
Foam::dimless
const dimensionSet dimless(0, 0, 0, 0, 0, 0, 0)
Dimensionless.
Definition: dimensionSets.H:50
Foam::layerParameters::layerThickness
static scalar layerThickness(const thicknessModelType, const label nLayers, const scalar firstLayerThickness, const scalar finalLayerThickness, const scalar totalThickness, const scalar expansionRatio)
Determine overall thickness. Uses two of the four parameters.
Definition: layerParameters.C:720
Foam::Time
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:73
Foam::syncTools::getInternalOrCoupledFaces
static bitSet getInternalOrCoupledFaces(const polyMesh &mesh)
Get per face whether it is internal or coupled.
Definition: syncTools.C:176
Foam::meshRefinement::WRITEMESH
Definition: meshRefinement.H:114
Foam::surfaceZonesInfo::faceZoneType
faceZoneType
What to do with faceZone faces.
Definition: surfaceZonesInfo.H:86
Foam::faceMap
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
Definition: blockMeshMergeTopological.C:94
Foam::IOobject::name
const word & name() const
Return name.
Definition: IOobjectI.H:70
Foam::labelMax
constexpr label labelMax
Definition: label.H:61
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:62
Foam::IOField
A primitive field of type <T> with automated input and output.
Definition: foamVtkLagrangianWriter.H:61
Foam::fvMesh::write
virtual bool write(const bool valid=true) const
Write mesh using IO settings from time.
Definition: fvMesh.C:1027
Foam::returnReduce
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Definition: PstreamReduceOps.H:94
Foam::externalDisplacementMeshMover::New
static autoPtr< externalDisplacementMeshMover > New(const word &type, const dictionary &dict, const List< labelPair > &baffles, pointVectorField &pointDisplacement, const bool dryRun=false)
Return a reference to the selected meshMover model.
Definition: externalDisplacementMeshMover.C:137
Foam::bitSet
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:63
Foam::OBJstream
OFstream that keeps track of vertices.
Definition: OBJstream.H:58
Foam::polyBoundaryMesh
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO.
Definition: polyBoundaryMesh.H:62
cyclicSlipPointPatchFields.H
Foam::dimLength
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:53
nPatches
label nPatches
Definition: readKivaGrid.H:396
Foam::layerParameters::dict
const dictionary & dict() const
Definition: layerParameters.H:199
Foam::tmp
A class for managing temporary objects.
Definition: PtrList.H:61
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
PatchTools.H
Foam::addPatchCellLayer::globalEdgeFaces
static labelListList globalEdgeFaces(const polyMesh &, const globalIndex &globalFaces, const indirectPrimitivePatch &pp)
Per patch edge the pp faces (in global indices) using it.
Definition: addPatchCellLayer.C:647
Foam::DynamicList< label >
calculatedPointPatchFields.H
Foam::primitiveMesh::nInternalFaces
label nInternalFaces() const
Number of internal faces.
Definition: primitiveMeshI.H:78
Foam::layerParameters::maxFaceThicknessRatio
scalar maxFaceThicknessRatio() const
Stop layer growth on highly warped cells.
Definition: layerParameters.H:313
Foam::primitiveMesh::nFaces
label nFaces() const
Number of mesh faces.
Definition: primitiveMeshI.H:90
mapPolyMesh.H
globalIndex.H
Foam::layerParameters::additionalReporting
bool additionalReporting() const
Any additional reporting requested?
Definition: layerParameters.H:325
Foam::meshRefinement::writeLevel
static writeType writeLevel()
Get/set write level.
Definition: meshRefinement.C:3440
Foam::polyPatch::coupled
virtual bool coupled() const
Return true if this patch is geometrically coupled (i.e. faces and.
Definition: polyPatch.H:329
polyTopoChange.H
motionSmoother.H
combineFaces.H
Foam::UPstream::parRun
static bool & parRun()
Test if this a parallel run, or allow modify access.
Definition: UPstream.H:434
Foam::MeshObject< polyMesh, UpdateableMeshObject, pointMesh >::New
static const pointMesh & New(const polyMesh &mesh, Args &&... args)
Get existing or create a new MeshObject.
Definition: MeshObject.C:48
Foam::Time::timeName
static word timeName(const scalar t, const int precision=precision_)
Definition: Time.C:780
zeroFixedValuePointPatchFields.H
localPointRegion.H
Foam::meshRefinement::ATTRACTION
Definition: meshRefinement.H:97
Foam::primitiveMesh::cells
const cellList & cells() const
Definition: primitiveMeshCells.C:138
Foam::polyTopoChange
Direct mesh changes based on v1.3 polyTopoChange syntax.
Definition: polyTopoChange.H:99
Foam::layerParameters::nRelaxedIter
label nRelaxedIter() const
Number of iterations after which relaxed motion rules.
Definition: layerParameters.H:281
Foam::primitiveMesh::nEdges
label nEdges() const
Number of mesh edges.
Definition: primitiveMeshI.H:67
Foam::syncTools::getMasterPoints
static bitSet getMasterPoints(const polyMesh &mesh)
Definition: syncTools.C:68
unitConversion.H
Unit conversion functions.
Foam::mapPolyMesh::nOldFaces
label nOldFaces() const
Number of old faces.
Definition: mapPolyMesh.H:381
Foam::faceSet
A list of face labels.
Definition: faceSet.H:51
Foam::boolList
List< bool > boolList
A List of bools.
Definition: List.H:69
Foam::List::append
void append(const T &val)
Append an element at the end of the list.
Definition: ListI.H:182
Foam::FatalIOError
IOerror FatalIOError
Foam::fvMesh::movePoints
virtual tmp< scalarField > movePoints(const pointField &)
Move points, returns volumes swept by faces in motion.
Definition: fvMesh.C:851
Foam::polyMesh::boundaryMesh
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:444
Foam::motionSmootherAlgo::checkMesh
static bool checkMesh(const bool report, const polyMesh &mesh, const dictionary &dict, labelHashSet &wrongFaces, const bool dryRun=false)
Check mesh with mesh settings in dict. Collects incorrect faces.
Definition: motionSmootherAlgoCheck.C:462
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
scalarIOField.H
Foam::mapPolyMesh::preMotionPoints
const pointField & preMotionPoints() const
Pre-motion point positions.
Definition: mapPolyMesh.H:613
Foam::primitiveMesh::edges
const edgeList & edges() const
Return mesh edges. Uses calcEdges.
Definition: primitiveMeshEdges.C:505
Foam::Pout
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Foam::primitiveMesh::pointEdges
const labelListList & pointEdges() const
Definition: primitiveMeshEdges.C:516
Foam::bitSet::test
bool test(const label pos) const
Test value at specified position, never auto-vivify entries.
Definition: bitSetI.H:520
Foam::HashSet< label, Hash< label > >
Foam::incrIndent
Ostream & incrIndent(Ostream &os)
Increment the indent level.
Definition: Ostream.H:327
Foam::min
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
Foam::polyMesh
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:77
Foam::meshRefinement::updateList
static void updateList(const labelList &newToOld, const T &nullValue, List< T > &elems)
Helper: reorder list according to map.
Definition: meshRefinementTemplates.C:38
Foam::snappyLayerDriver::mergePatchFacesUndo
void mergePatchFacesUndo(const layerParameters &layerParams, const dictionary &motionDict, const meshRefinement::FaceMergeType mergeType)
Merge patch faces on same cell.
Definition: snappyLayerDriver.C:3390
Foam::polyBoundaryMesh::range
labelRange range() const
The face range for all boundary faces.
Definition: polyBoundaryMesh.C:650
Foam::syncTools::syncPointList
static void syncPointList(const polyMesh &mesh, List< T > &pointValues, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh points.
Definition: syncToolsTemplates.C:724
Foam::layerParameters::nLayerIter
label nLayerIter() const
Number of overall layer addition iterations.
Definition: layerParameters.H:274
Foam::sumOp
Definition: ops.H:213
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::meshRefinement::subsetBaffles
static List< labelPair > subsetBaffles(const polyMesh &mesh, const labelList &zoneIDs, const List< labelPair > &baffles)
Subset baffles according to zones.
Definition: meshRefinementBaffles.C:686
Foam::minEqOp
Definition: ops.H:81
Foam::vectorField
Field< vector > vectorField
Specialisation of Field<T> for vector.
Definition: primitiveFieldsFwd.H:54
Foam::dimensionedVector
dimensioned< vector > dimensionedVector
Dimensioned vector obtained from generic dimensioned type.
Definition: dimensionedVector.H:50
Foam::polyMesh::faceZones
const faceZoneMesh & faceZones() const
Return face zone mesh.
Definition: polyMesh.H:486
Foam::meshRefinement::FaceMergeType
FaceMergeType
Enumeration for what to do with co-planar patch faces on a single.
Definition: meshRefinement.H:133
Foam::layerParameters::finalLayerThicknessRatio
static scalar finalLayerThicknessRatio(const label nLayers, const scalar expansionRatio)
Determine ratio of final layer thickness to.
Definition: layerParameters.C:970
nPoints
label nPoints
Definition: gmvOutputHeader.H:2
Foam::labelPair
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:54
Foam::wordList
List< word > wordList
A List of words.
Definition: fileName.H:59
mapDistributePolyMesh.H
n
label n
Definition: TABSMDCalcMethod2.H:31
Foam::polyBoundaryMesh::patchID
const labelList & patchID() const
Per boundary face label the patch index.
Definition: polyBoundaryMesh.C:452
Foam::dictionary::merge
bool merge(const dictionary &dict)
Merge entries from the given dictionary.
Definition: dictionary.C:879
Foam::regionSide
Determines the 'side' for every face and connected to a singly-connected (through edges) region of fa...
Definition: regionSide.H:63
Foam::snappyLayerDriver::addLayers
void addLayers(const layerParameters &layerParams, const dictionary &motionDict, const labelList &patchIDs, const label nAllowableErrors, decompositionMethod &decomposer, fvMeshDistribute &distributor)
Add cell layers.
Definition: snappyLayerDriver.C:3443
Foam::reduce
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
Definition: PstreamReduceOps.H:51
removePoints.H
Foam::layerParameters::nBufferCellsNoExtrude
label nBufferCellsNoExtrude() const
Create buffer region for new layer terminations.
Definition: layerParameters.H:319
Foam::primitiveMesh::nCells
label nCells() const
Number of mesh cells.
Definition: primitiveMeshI.H:96
pFaces
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=cellModel::ref(cellModel::HEX);labelList hexLabels(8);label activeCells=0;labelList pointMap(nPoints);forAll(pointMap, i){ pointMap[i]=i;}for(label i=0;i< nPoints;i++){ if(f[i] > 0.0) { hexLabels[0]=i;hexLabels[1]=i1tab[i];hexLabels[2]=i3tab[i1tab[i]];hexLabels[3]=i3tab[i];hexLabels[4]=i8tab[i];hexLabels[5]=i1tab[i8tab[i]];hexLabels[6]=i3tab[i1tab[i8tab[i]]];hexLabels[7]=i3tab[i8tab[i]];cellShapes[activeCells]=cellShape(hex, hexLabels);edgeList edges=cellShapes[activeCells].edges();forAll(edges, ei) { if(edges[ei].mag(points)< SMALL) { label start=pointMap[edges[ei].start()];while(start !=pointMap[start]) { start=pointMap[start];} label end=pointMap[edges[ei].end()];while(end !=pointMap[end]) { end=pointMap[end];} label minLabel=min(start, end);pointMap[start]=pointMap[end]=minLabel;} } cellZoning[activeCells]=idreg[i];activeCells++;}}cellShapes.setSize(activeCells);cellZoning.setSize(activeCells);forAll(cellShapes, celli){ cellShape &cs=cellShapes[celli];forAll(cs, i) { cs[i]=pointMap[cs[i]];} cs.collapse();}label bcIDs[11]={-1, 0, 2, 4, -1, 5, -1, 6, 7, 8, 9};const label nBCs=12;const word *kivaPatchTypes[nBCs]={ &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &symmetryPolyPatch::typeName, &wedgePolyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &symmetryPolyPatch::typeName, &oldCyclicPolyPatch::typeName};enum patchTypeNames{ PISTON, VALVE, LINER, CYLINDERHEAD, AXIS, WEDGE, INFLOW, OUTFLOW, PRESIN, PRESOUT, SYMMETRYPLANE, CYCLIC};const char *kivaPatchNames[nBCs]={ "piston", "valve", "liner", "cylinderHead", "axis", "wedge", "inflow", "outflow", "presin", "presout", "symmetryPlane", "cyclic"};List< SLList< face > > pFaces[nBCs]
Definition: readKivaGrid.H:235
faceNormals
surfaceVectorField faceNormals(mesh.Sf()/mesh.magSf())
Foam::Field< vector >
externalDisplacementMeshMover.H
Foam::meshRefinement::LAYERINFO
Definition: meshRefinement.H:98
Foam::faceZone
A subset of mesh faces organised as a primitive patch.
Definition: faceZone.H:65
Foam::Info
messageStream Info
Information stream (uses stdout - output is on the master only)
Foam::polyPatch
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:68
Foam::name
word name(const complex &c)
Return string representation of complex.
Definition: complex.C:76
Foam::layerParameters::FIRST_AND_TOTAL
Definition: layerParameters.H:72
Foam::OSstream::name
virtual const fileName & name() const
Return the name of the stream.
Definition: OSstream.H:107
Foam::syncTools::syncEdgeList
static void syncEdgeList(const polyMesh &mesh, List< T > &edgeValues, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh edges.
Definition: syncToolsTemplates.C:803
Foam::polyMesh::faceOwner
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1107
faceSet.H
Foam::dictionary::subDict
const dictionary & subDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary.
Definition: dictionary.C:528
Foam::IOobject::READ_IF_PRESENT
Definition: IOobject.H:122
Foam::layerParameters::mergePatchFacesAngle
scalar mergePatchFacesAngle() const
Definition: layerParameters.H:294
Foam::fvMesh::updateMesh
virtual void updateMesh(const mapPolyMesh &mpm)
Update mesh corresponding to the given map.
Definition: fvMesh.C:939
Foam::faceZone::slaveCells
const labelList & slaveCells() const
Return labels of slave cells.
Definition: faceZone.C:407
Foam::ZoneMesh< faceZone, polyMesh >
IOmanip.H
Istream and Ostream manipulators taking arguments.
Foam::layerParameters::relativeSizes
const boolList & relativeSizes() const
Are size parameters relative to inner cell size or.
Definition: layerParameters.H:219
Foam::layerParameters::FIRST_AND_RELATIVE_FINAL
Definition: layerParameters.H:77
Foam::dimensionedScalar
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
Definition: dimensionedScalarFwd.H:43
Foam::volScalarField
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:57
slipPointPatchFields.H
Foam::max
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
fld
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< ' ';}gmvFile<< nl;for(const word &name :lagrangianScalarNames){ IOField< scalar > fld(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
Definition: gmvOutputLagrangian.H:23
Foam::layerParameters
Simple container to keep together layer specific information.
Definition: layerParameters.H:58
addProfiling
#define addProfiling(name, descr)
Define profiling trigger with specified name and description string.
Definition: profilingTrigger.H:113
Foam::FatalError
error FatalError
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:121
Foam::snappyLayerDriver::EXTRUDE
Extrude.
Definition: snappyLayerDriver.H:69
Foam::vertices
pointField vertices(const blockVertexList &bvl)
Definition: blockVertexList.H:49
Foam::meshRefinement::makePatch
static autoPtr< indirectPrimitivePatch > makePatch(const polyMesh &, const labelList &)
Create patch from set of patches.
Definition: meshRefinement.C:1904
Foam::addPatchCellLayer
Adds layers of cells to outside of polyPatch. Can optionally create stand-alone extruded mesh (addToM...
Definition: addPatchCellLayer.H:128
Foam::layerParameters::numLayers
const labelList & numLayers() const
How many layers to add.
Definition: layerParameters.H:212
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
meshRefinement.H
Foam::decompositionMethod
Abstract base class for domain decomposition.
Definition: decompositionMethod.H:51
Foam::Ostream::write
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
Foam::error::message
string message() const
The accumulated error message.
Definition: error.C:277
Foam::fvMesh
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:83
fvMesh.H
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::decrIndent
Ostream & decrIndent(Ostream &os)
Decrement the indent level.
Definition: Ostream.H:334
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Foam::polyPatch::faceCells
const labelUList & faceCells() const
Return face-cell addressing.
Definition: polyPatch.C:363
Foam::zone::name
const word & name() const
Return name.
Definition: zone.H:158
Foam::setw
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
Foam::globalIndex
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:68
Foam::indent
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:320
Foam::vector
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:51
Foam::degToRad
constexpr scalar degToRad(const scalar deg) noexcept
Conversion from degrees to radians.
Definition: unitConversion.H:48
Foam::addPatchCellLayer::updateMesh
void updateMesh(const mapPolyMesh &, const labelList &faceMap, const labelList &pointMap)
Update any locally stored mesh information. Gets additional.
Definition: addPatchCellLayer.C:2382
Foam::mergePoints
label mergePoints(const PointList &points, const scalar mergeTol, const bool verbose, labelList &pointMap, typename PointList::const_reference origin=PointList::value_type::zero)
Sorts and merges points. All points closer than/equal mergeTol get merged.
fixedValuePointPatchFields.H
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::mapPolyMesh::reverseFaceMap
const labelList & reverseFaceMap() const
Reverse face map.
Definition: mapPolyMesh.H:501
Foam::indirectPrimitivePatch
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
A PrimitivePatch with an IndirectList for the faces, const reference for the point field.
Definition: indirectPrimitivePatch.H:49
Foam::meshRefinement::WRITELAYERFIELDS
Definition: meshRefinement.H:118
Foam::Perr
prefixOSstream Perr
OSstream wrapped stderr (std::cerr) with parallel prefix.
Foam::surfaceZonesInfo::BAFFLE
Definition: surfaceZonesInfo.H:89
Foam::setprecision
Omanip< int > setprecision(const int i)
Definition: IOmanip.H:205
Time.H
Foam::autoPtr
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: HashPtrTable.H:53
Foam::labelListList
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
Foam::faceZone::masterCells
const labelList & masterCells() const
Definition: faceZone.C:396
Foam::linePointRef
line< point, const point & > linePointRef
A line using referred points.
Definition: linePointRef.H:47
Foam::polyMesh::faces
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1094
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:381
DynamicField.H
Foam::layerParameters::featureAngle
scalar featureAngle() const
Definition: layerParameters.H:289
Foam::UPstream::myProcNo
static int myProcNo(const label communicator=worldComm)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:464
Foam::nl
constexpr char nl
Definition: Ostream.H:385
Foam::Pair< label >
Foam::Time::path
fileName path() const
Return path.
Definition: Time.H:358
forAllConstIters
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
Foam::VectorSpace< Vector< Cmpt >, Cmpt, 3 >::max
static const Vector< Cmpt > max
Definition: VectorSpace.H:117
f
labelList f(nPoints)
layerParameters.H
Foam::faceList
List< face > faceList
A List of faces.
Definition: faceListFwd.H:47
Foam::Vector< scalar >
Foam::meshRefinement::writeType
writeType
Enumeration for what to write. Used as a bit-pattern.
Definition: meshRefinement.H:112
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:63
Foam::addPatchCellLayer::calcExtrudeInfo
static void calcExtrudeInfo(const bool zoneFromAnyFace, const polyMesh &, const globalIndex &globalFaces, const labelListList &globalEdgeFaces, const indirectPrimitivePatch &pp, labelList &edgePatchID, label &nPatches, Map< label > &nbrProcToPatch, Map< label > &patchToNbrProc, labelList &edgeZoneID, boolList &edgeFlip, labelList &inflateFaceID)
Determine extrude information per patch edge:
Definition: addPatchCellLayer.C:1090
Foam::processorPolyPatch::newName
static word newName(const label myProcNo, const label neighbProcNo)
Return the name of a processorPolyPatch.
Definition: processorPolyPatch.C:186
Foam::mapPolyMesh::pointMap
const labelList & pointMap() const
Old point map.
Definition: mapPolyMesh.H:396
Foam::primitiveMesh::isInternalFace
bool isInternalFace(const label faceIndex) const
Return true if given face label is internal to the mesh.
Definition: primitiveMeshI.H:102
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::primitiveMesh::faceCentres
const vectorField & faceCentres() const
Definition: primitiveMeshFaceCentresAndAreas.C:77
fixedValueFvPatchFields.H
Foam::meshRefinement
Helper class which maintains intersections of (changing) mesh with (static) surfaces.
Definition: meshRefinement.H:85
Foam::motionSmootherAlgo::setDisplacement
static void setDisplacement(const labelList &patchIDs, const indirectPrimitivePatch &pp, pointField &patchDisp, pointVectorField &displacement)
Set displacement field from displacement on patch points.
Definition: motionSmootherAlgo.C:468
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
Foam::primitiveMesh::nPoints
label nPoints() const
Number of mesh points.
Definition: primitiveMeshI.H:37
Foam::identity
labelList identity(const label len, label start=0)
Create identity map of the given length with (map[i] == i)
Definition: labelList.C:38
Foam::List::clear
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:115
Foam::tmp::New
static tmp< T > New(Args &&... args)
Construct tmp of T with forwarding arguments.
Foam::sum
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
Definition: DimensionedFieldFunctions.C:327
patches
const polyBoundaryMesh & patches
Definition: convertProcessorPatches.H:65
Foam::mapPolyMesh::faceMap
const labelList & faceMap() const
Old face map.
Definition: mapPolyMesh.H:410
Foam::labelMin
constexpr label labelMin
Definition: label.H:60
Foam::mapPolyMesh
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Definition: mapPolyMesh.H:161
Foam::mapPolyMesh::hasMotionPoints
bool hasMotionPoints() const
Has valid preMotionPoints?
Definition: mapPolyMesh.H:619
Foam::cpuTimeCxx::cpuTimeIncrement
double cpuTimeIncrement() const
Return CPU time (in seconds) since last call to cpuTimeIncrement()
Definition: cpuTimeCxx.C:75
Foam::fvMesh::time
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:275
Foam::UIndirectList
A List with indirect addressing.
Definition: faMatrix.H:60
Foam::inplaceReorder
void inplaceReorder(const labelUList &oldToNew, ListType &input, const bool prune=false)
Inplace reorder the elements of a list.
Definition: ListOpsTemplates.C:124
Foam::Field< scalar >::subField
SubField< scalar > subField
Declare type of subField.
Definition: Field.H:89
Foam::face
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:72
Foam::layerParameters::thicknessModelType
thicknessModelType
Enumeration defining the layer specification:
Definition: layerParameters.H:70
Foam::snappyLayerDriver::doLayers
void doLayers(const dictionary &shrinkDict, const dictionary &motionDict, const layerParameters &layerParams, const meshRefinement::FaceMergeType mergeType, const bool preBalance, decompositionMethod &decomposer, fvMeshDistribute &distributor)
Add layers according to the dictionary settings.
Definition: snappyLayerDriver.C:4809
cellSet.H
p0
const volScalarField & p0
Definition: EEqn.H:36
IOWarningInFunction
#define IOWarningInFunction(ios)
Report an IO warning using Foam::Warning.
Definition: messageStream.H:315
Foam::point
vector point
Point is a vector.
Definition: point.H:43
Foam::HashTable::found
bool found(const Key &key) const
Return true if hashed entry is found in table.
Definition: HashTableI.H:100
Foam::labelHashSet
HashSet< label, Hash< label > > labelHashSet
A HashSet with label keys and label hasher.
Definition: HashSet.H:409
Foam::meshTools::visNormal
bool visNormal(const vector &n, const vectorField &faceNormals, const labelList &faceLabels)
Check if n is in same direction as normals of all faceLabels.
Definition: meshTools.C:37
Foam::List::setSize
void setSize(const label newSize)
Alias for resize(const label)
Definition: ListI.H:146
Foam::GeometricField< vector, pointPatchField, pointMesh >
Foam::IOobject::NO_READ
Definition: IOobject.H:123
Foam::invertOneToMany
labelListList invertOneToMany(const label len, const labelUList &map)
Invert one-to-many map. Unmapped elements will be size 0.
Definition: ListOps.C:114
Foam::meshRefinement::WRITELAYERSETS
Definition: meshRefinement.H:117
Foam::orOp
Definition: ops.H:234
Foam::layerParameters::meshShrinker
const word & meshShrinker() const
Type of mesh shrinker.
Definition: layerParameters.H:331
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::polyTopoChange::makeMesh
autoPtr< mapPolyMesh > makeMesh(autoPtr< Type > &newMesh, const IOobject &io, const polyMesh &mesh, const bool syncParallel=true, const bool orderCells=false, const bool orderPoints=false)
Create new mesh with old mesh patches. Additional dictionaries.
Foam::patchIdentifier::name
const word & name() const
The patch name.
Definition: patchIdentifier.H:134
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:303
Foam::fvMeshDistribute
Sends/receives parts of mesh+fvfields to neighbouring processors. Used in load balancing.
Definition: fvMeshDistribute.H:73
pointFields.H
Foam::gMax
Type gMax(const FieldField< Field, Type > &f)
Definition: FieldFieldFunctions.C:592
OBJstream.H
Foam::polyMesh::setInstance
void setInstance(const fileName &instance, const IOobject::writeOption wOpt=IOobject::AUTO_WRITE)
Set the instance for mesh files.
Definition: polyMeshIO.C:36
Foam::meshRefinement::MESH
Definition: meshRefinement.H:94
Foam::UPstream::nProcs
static label nProcs(const label communicator=worldComm)
Number of processes in parallel run, and 1 for serial run.
Definition: UPstream.H:446
Foam::localPointRegion::findDuplicateFacePairs
static labelPairList findDuplicateFacePairs(const polyMesh &)
Helper routine to find all baffles (two boundary faces.
Definition: localPointRegion.C:625
Foam::fvMesh::clearOut
void clearOut()
Clear all geometry and addressing.
Definition: fvMesh.C:227
Foam::layerParameters::concaveAngle
scalar concaveAngle() const
Definition: layerParameters.H:299
Foam::fvMesh::name
const word & name() const
Return reference to name.
Definition: fvMesh.H:295
snappyLayerDriver.H
Foam::addPatchCellLayer::setRefinement
void setRefinement(const globalIndex &globalFaces, const labelListList &globalEdgeFaces, const scalarField &expansionRatio, const indirectPrimitivePatch &pp, const labelList &sidePatchID, const labelList &sideZoneID, const boolList &sideFlip, const labelList &inflateFaceID, const labelList &exposedPatchID, const labelList &nFaceLayers, const labelList &nPointLayers, const vectorField &firstLayerDisp, polyTopoChange &meshMod)
Play commands into polyTopoChange to create layers on top.
Definition: addPatchCellLayer.C:1418
Foam::labelUIndList
UIndirectList< label > labelUIndList
UIndirectList of labels.
Definition: UIndirectList.H:58
Foam::cos
dimensionedScalar cos(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:265
Foam::addPatchCellLayer::addedCells
labelListList addedCells() const
Added cells given current mesh & layerfaces.
Definition: addPatchCellLayer.C:640
pointSet.H
Foam::meshRefinement::debugType
debugType
Enumeration for what to debug. Used as a bit-pattern.
Definition: meshRefinement.H:92
Foam::UPstream::exit
static void exit(int errNo=1)
Shutdown (finalize) MPI as required and exit program with errNo.
Definition: UPstream.C:63
Foam::surfaceZonesInfo::INTERNAL
Definition: surfaceZonesInfo.H:88