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