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