extrudeToRegionMesh.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2023 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 Application
25  extrudeToRegionMesh
26 
27 Description
28  Extrude faceZones (internal or boundary faces) or faceSets (boundary faces
29  only) into a separate mesh (as a different region).
30 
31  - used to e.g. extrude baffles (extrude internal faces) or create
32  liquid film regions.
33  - if extruding internal faces:
34  - create baffles in original mesh with mappedWall patches
35  - if extruding boundary faces:
36  - convert boundary faces to mappedWall patches
37  - extrude edges of faceZone as a <zone>_sidePatch
38  - extrudes into master direction (i.e. away from the owner cell
39  if flipMap is false)
40 
41 \verbatim
42 
43 Internal face extrusion
44 -----------------------
45 
46  +-------------+
47  | |
48  | |
49  +---AAAAAAA---+
50  | |
51  | |
52  +-------------+
53 
54  AAA=faceZone to extrude.
55 
56 
57 For the case of no flipMap the extrusion starts at owner and extrudes
58 into the space of the neighbour:
59 
60  +CCCCCCC+
61  | | <= extruded mesh
62  +BBBBBBB+
63 
64  +-------------+
65  | |
66  | (neighbour) |
67  |___CCCCCCC___| <= original mesh (with 'baffles' added)
68  | BBBBBBB |
69  |(owner side) |
70  | |
71  +-------------+
72 
73  BBB=mapped between owner on original mesh and new extrusion.
74  (zero offset)
75  CCC=mapped between neighbour on original mesh and new extrusion
76  (offset due to the thickness of the extruded mesh)
77 
78 For the case of flipMap the extrusion is the other way around: from the
79 neighbour side into the owner side.
80 
81 
82 Boundary face extrusion
83 -----------------------
84 
85  +--AAAAAAA--+
86  | |
87  | |
88  +-----------+
89 
90  AAA=faceZone to extrude. E.g. slave side is owner side (no flipmap)
91 
92 becomes
93 
94  +CCCCCCC+
95  | | <= extruded mesh
96  +BBBBBBB+
97 
98  +--BBBBBBB--+
99  | | <= original mesh
100  | |
101  +-----------+
102 
103  BBB=mapped between original mesh and new extrusion
104  CCC=polypatch
105 
106 
107  Notes:
108  - when extruding cyclics with only one cell in between it does not
109  detect this as a cyclic since the face is the same face. It will
110  only work if the coupled edge extrudes a different face so if there
111  are more than 1 cell in between.
112 
113 \endverbatim
114 
115 \*---------------------------------------------------------------------------*/
116 
117 #include "argList.H"
118 #include "polyTopoChange.H"
119 #include "mappedWallPolyPatch.H"
121 #include "createShellMesh.H"
122 #include "syncTools.H"
123 #include "cyclicPolyPatch.H"
124 #include "wedgePolyPatch.H"
125 #include "extrudeModel.H"
126 #include "faceSet.H"
127 #include "fvMeshTools.H"
128 #include "OBJstream.H"
129 #include "PatchTools.H"
130 #include "systemDict.H"
131 
132 using namespace Foam;
133 
134 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
135 
136 label findPatchID(const List<polyPatch*>& newPatches, const word& name)
137 {
138  forAll(newPatches, i)
139  {
140  if (newPatches[i]->name() == name)
141  {
142  return i;
143  }
144  }
145  return -1;
146 }
147 
148 
149 label addPatch
150 (
151  const polyBoundaryMesh& patches,
152  const word& patchName,
153  const word& patchType,
154  const dictionary& dict,
155  DynamicList<polyPatch*>& newPatches
156 )
157 {
158  label patchi = findPatchID(newPatches, patchName);
159 
160  if (patchi != -1)
161  {
162  if (newPatches[patchi]->type() == patchType)
163  {
164  return patchi;
165  }
166  else
167  {
169  << "Already have patch " << patchName
170  << " but of type " << newPatches[patchi]->type()
171  << exit(FatalError);
172  }
173  }
174 
175  patchi = newPatches.size();
176 
177  label startFacei = 0;
178  if (patchi > 0)
179  {
180  const polyPatch& pp = *newPatches.last();
181  startFacei = pp.start()+pp.size();
182  }
183 
184  dictionary patchDict(dict);
185  patchDict.set("type", patchType);
186  patchDict.set("nFaces", 0);
187  patchDict.set("startFace", startFacei);
188 
189  newPatches.append
190  (
192  (
193  patchName,
194  patchDict,
195  patchi,
196  patches
197  ).ptr()
198  );
199 
200  return patchi;
201 }
202 
203 
204 // Remove zero-sized patches
205 void deleteEmptyPatches(fvMesh& mesh)
206 {
207  const polyBoundaryMesh& patches = mesh.boundaryMesh();
208 
209  wordList masterNames;
210  if (Pstream::master())
211  {
212  masterNames = patches.names();
213  }
214  Pstream::scatter(masterNames);
215 
216 
217  labelList oldToNew(patches.size(), -1);
218  label usedI = 0;
219  label notUsedI = patches.size();
220 
221  // Add all the non-empty, non-processor patches
222  forAll(masterNames, masterI)
223  {
224  label patchi = patches.findPatchID(masterNames[masterI]);
225 
226  if (patchi != -1)
227  {
228  if (isA<processorPolyPatch>(patches[patchi]))
229  {
230  // Similar named processor patch? Not 'possible'.
231  if (patches[patchi].size() == 0)
232  {
233  Pout<< "Deleting processor patch " << patchi
234  << " name:" << patches[patchi].name()
235  << endl;
236  oldToNew[patchi] = --notUsedI;
237  }
238  else
239  {
240  oldToNew[patchi] = usedI++;
241  }
242  }
243  else
244  {
245  // Common patch.
246  if (returnReduce(patches[patchi].size(), sumOp<label>()) == 0)
247  {
248  Pout<< "Deleting patch " << patchi
249  << " name:" << patches[patchi].name()
250  << endl;
251  oldToNew[patchi] = --notUsedI;
252  }
253  else
254  {
255  oldToNew[patchi] = usedI++;
256  }
257  }
258  }
259  }
260 
261  // Add remaining patches at the end
263  {
264  if (oldToNew[patchi] == -1)
265  {
266  // Unique to this processor. Note: could check that these are
267  // only processor patches.
268  if (patches[patchi].size() == 0)
269  {
270  Pout<< "Deleting processor patch " << patchi
271  << " name:" << patches[patchi].name()
272  << endl;
273  oldToNew[patchi] = --notUsedI;
274  }
275  else
276  {
277  oldToNew[patchi] = usedI++;
278  }
279  }
280  }
281 
282  fvMeshTools::reorderPatches(mesh, oldToNew, usedI, true);
283 }
284 
285 
286 enum class connectivity
287 {
288  unset,
289  boundary,
290  internal,
291  error
292 };
293 
294 
295 struct isInternalEqOp
296 {
297  void operator()(connectivity& x, const connectivity& y) const
298  {
299  if (x == connectivity::unset)
300  {
301  // Set x if not yet set
302  x = y;
303  }
304  else if (y == connectivity::unset)
305  {
306  // Do not set x if y is not yet set
307  }
308  else if (x == y)
309  {
310  // Do nothing if x and y are equal
311  }
312  else
313  {
314  // Set an error value if x and y are both set and unequal
315  x = connectivity::error;
316  }
317  }
318 };
319 
320 
321 Ostream& operator<<(Ostream& os, const connectivity& p)
322 {
323  return os << static_cast<label>(p);
324 }
325 
326 
327 Istream& operator>>(Istream& is, connectivity& p)
328 {
329  label l;
330  is >> l;
331  p = static_cast<connectivity>(l);
332  return is;
333 }
334 
335 
336 // Return a bool list indicating whether or not the zone contains internal or
337 // boundary faces
338 boolList calcZoneIsInternal
339 (
340  const polyMesh& mesh,
341  const wordList& zoneNames,
342  const labelList& extrudeFaces,
343  const labelList& extrudeFaceZoneIDs
344 )
345 {
346  List<connectivity> zoneConnectivity(zoneNames.size(), connectivity::unset);
347 
348  forAll(extrudeFaces, i)
349  {
350  const label facei = extrudeFaces[i];
351  const label zonei = extrudeFaceZoneIDs[i];
352  isInternalEqOp()
353  (
354  zoneConnectivity[zonei],
355  mesh.isInternalFace(facei)
356  ? connectivity::internal
358  );
359  }
360 
361  Pstream::listCombineGather(zoneConnectivity, isInternalEqOp());
362  Pstream::listCombineScatter(zoneConnectivity);
363 
364  boolList zoneIsInternal(zoneNames.size());
365  forAll(zoneConnectivity, zonei)
366  {
367  switch (zoneConnectivity[zonei])
368  {
369  case connectivity::unset:
370  // This zone doesn't contain any faces, so it doesn't matter
371  // what we do here
372  zoneIsInternal[zonei] = false;
373  break;
375  zoneIsInternal[zonei] = false;
376  break;
377  case connectivity::internal:
378  zoneIsInternal[zonei] = true;
379  break;
380  case connectivity::error:
382  << "Zone " << zoneNames[zonei]
383  << " contains both internal and boundary faces."
384  << " This is not allowed." << exit(FatalError);
385  break;
386  }
387  }
388 
389  return zoneIsInternal;
390 }
391 
392 
393 // To combineReduce a labelList. Filters out duplicates.
394 struct uniqueEqOp
395 {
396  void operator()(labelList& x, const labelList& y) const
397  {
398  if (x.empty())
399  {
400  if (y.size())
401  {
402  x = y;
403  }
404  }
405  else
406  {
407  forAll(y, yi)
408  {
409  if (findIndex(x, y[yi]) == -1)
410  {
411  label sz = x.size();
412  x.setSize(sz+1);
413  x[sz] = y[yi];
414  }
415  }
416  }
417  }
418 };
419 
420 
421 // Calculate global pp faces per pp edge.
422 labelListList globalEdgeFaces
423 (
424  const polyMesh& mesh,
425  const globalIndex& globalFaces,
426  const primitiveFacePatch& pp,
427  const labelList& ppMeshEdges
428 )
429 {
430  // From mesh edge to global pp face labels.
431  labelListList globalEdgeFaces(ppMeshEdges.size());
432 
433  const labelListList& edgeFaces = pp.edgeFaces();
434 
435  forAll(edgeFaces, edgeI)
436  {
437  const labelList& eFaces = edgeFaces[edgeI];
438 
439  // Store pp face and processor as unique tag.
440  labelList& globalEFaces = globalEdgeFaces[edgeI];
441  globalEFaces.setSize(eFaces.size());
442  forAll(eFaces, i)
443  {
444  globalEFaces[i] = globalFaces.toGlobal(eFaces[i]);
445  }
446  }
447 
448  // Synchronise across coupled edges.
450  (
451  mesh,
452  ppMeshEdges,
453  globalEdgeFaces,
454  uniqueEqOp(),
455  labelList() // null value
456  );
457 
458  return globalEdgeFaces;
459 }
460 
461 
462 // Find a patch face that is not extruded. Return -1 if not found.
463 label findUncoveredPatchFace
464 (
465  const fvMesh& mesh,
466  const UIndirectList<label>& extrudeFaces, // mesh faces that are extruded
467  const label meshEdgeI // mesh edge
468 )
469 {
470  // Make set of extruded faces.
471  labelHashSet extrudeFaceSet(extrudeFaces.size());
472  forAll(extrudeFaces, i)
473  {
474  extrudeFaceSet.insert(extrudeFaces[i]);
475  }
476 
477  const polyBoundaryMesh& pbm = mesh.boundaryMesh();
478  const labelList& eFaces = mesh.edgeFaces()[meshEdgeI];
479  forAll(eFaces, i)
480  {
481  label facei = eFaces[i];
482  label patchi = pbm.whichPatch(facei);
483 
484  if
485  (
486  patchi != -1
487  && !pbm[patchi].coupled()
488  && !extrudeFaceSet.found(facei)
489  )
490  {
491  return facei;
492  }
493  }
494  return -1;
495 }
496 
497 
498 // Same as findUncoveredPatchFace, except explicitly checks for cyclic faces
499 label findUncoveredCyclicPatchFace
500 (
501  const fvMesh& mesh,
502  const UIndirectList<label>& extrudeFaces, // mesh faces that are extruded
503  const label meshEdgeI // mesh edge
504 )
505 {
506  // Make set of extruded faces.
507  labelHashSet extrudeFaceSet(extrudeFaces.size());
508  forAll(extrudeFaces, i)
509  {
510  extrudeFaceSet.insert(extrudeFaces[i]);
511  }
512 
513  const polyBoundaryMesh& pbm = mesh.boundaryMesh();
514  const labelList& eFaces = mesh.edgeFaces()[meshEdgeI];
515  forAll(eFaces, i)
516  {
517  label facei = eFaces[i];
518  label patchi = pbm.whichPatch(facei);
519 
520  if
521  (
522  patchi != -1
523  && isA<cyclicPolyPatch>(pbm[patchi])
524  && !extrudeFaceSet.found(facei)
525  )
526  {
527  return facei;
528  }
529  }
530  return -1;
531 }
532 
533 
534 // Add coupled patches into the mesh
535 void addCouplingPatches
536 (
537  const fvMesh& mesh,
538  const bool isShellMesh,
539  const bool intrude,
540  const word& regionName,
541  const word& nbrRegionName,
542  const wordList& zoneNames,
543  const wordList& oppositeZoneNames,
544  const boolList& zoneIsInternal,
545  const dictionary& dict,
546  DynamicList<polyPatch*>& newPatches,
547  labelList& zoneTopPatch,
548  labelList& zoneBottomPatch
549 )
550 {
551  Pout<< "Adding coupling patches:" << nl << nl
552  << "patchID\tpatch\ttype" << nl
553  << "-------\t-----\t----"
554  << endl;
555 
557  (
558  dict.lookupOrDefault("patchNames", wordList())
559  );
560  wordList regionPatchNames
561  (
562  dict.lookupOrDefault("regionPatchNames", wordList())
563  );
564  if (isShellMesh)
565  {
566  patchNames.swap(regionPatchNames);
567  }
568 
569  const wordList patchTypes
570  (
571  isShellMesh
572  ? dict.lookupOrDefault("regionPatchTypes", wordList())
573  : dict.lookupOrDefault("patchTypes", wordList())
574  );
575 
576  wordList oppositePatchNames
577  (
578  dict.lookupOrDefault("oppositePatchNames", wordList())
579  );
580  wordList regionOppositePatchNames
581  (
582  dict.lookupOrDefault("regionOppositePatchNames", wordList())
583  );
584  if (isShellMesh)
585  {
586  oppositePatchNames.swap(regionOppositePatchNames);
587  }
588 
589  const wordList oppositePatchTypes
590  (
591  isShellMesh
592  ? dict.lookupOrDefault("regionOppositePatchTypes", wordList())
593  : dict.lookupOrDefault("oppositePatchType", wordList())
594  );
595 
596  zoneTopPatch.setSize(zoneNames.size(), -1);
597  zoneBottomPatch.setSize(zoneNames.size(), -1);
598 
599  dictionary patchDict;
600  patchDict.add("neighbourRegion", nbrRegionName);
601 
602  label nOldPatches = newPatches.size();
603  forAll(zoneNames, zonei)
604  {
605  const word patchNamePrefix =
606  regionName + "_to_" + nbrRegionName + '_';
607 
608  const word nbrPatchNamePrefix =
609  nbrRegionName + "_to_" + regionName + '_';
610 
611  word bottomPatchName;
612  word bottomNbrPatchName;
613  word topPatchName;
614  word topNbrPatchName;
615 
616  if (zoneIsInternal[zonei])
617  {
618  bottomPatchName =
619  patchNamePrefix + zoneNames[zonei] + "_bottom";
620  bottomNbrPatchName =
621  nbrPatchNamePrefix + zoneNames[zonei] + "_bottom";
622  topPatchName =
623  patchNamePrefix + zoneNames[zonei] + "_top";
624  topNbrPatchName =
625  nbrPatchNamePrefix + zoneNames[zonei] + "_top";
626  }
627  else if (!oppositeZoneNames[zonei].empty())
628  {
629  bottomPatchName = patchNamePrefix + zoneNames[zonei];
630  bottomNbrPatchName = nbrPatchNamePrefix + zoneNames[zonei];
631  topPatchName = patchNamePrefix + oppositeZoneNames[zonei];
632  topNbrPatchName = nbrPatchNamePrefix + oppositeZoneNames[zonei];
633  }
634  else
635  {
636  bottomPatchName = patchNamePrefix + zoneNames[zonei];
637  bottomNbrPatchName = nbrPatchNamePrefix + zoneNames[zonei];
638  topPatchName = zoneNames[zonei] + "_top";
639  topNbrPatchName = word::null;
640  }
641 
642  if (patchNames.size())
643  {
644  bottomPatchName = patchNames[zonei];
645  }
646  if (regionPatchNames.size())
647  {
648  bottomNbrPatchName = regionPatchNames[zonei];
649  }
650  if (oppositePatchNames.size())
651  {
652  topPatchName = oppositePatchNames[zonei];
653  }
654  if (regionOppositePatchNames.size())
655  {
656  topNbrPatchName = regionOppositePatchNames[zonei];
657  }
658 
659  const bool bothMapped =
660  zoneIsInternal[zonei] || !oppositeZoneNames[zonei].empty();
661 
662  const bool bottomMapped = bothMapped || !(intrude && isShellMesh);
663  const bool topMapped = bothMapped || intrude;
664 
665  const bool bottomExtruded = !isShellMesh && intrude;
666  const bool topExtruded = !bottomExtruded;
667 
668  dictionary bottomPatchDict;
669  if (bottomMapped)
670  {
671  bottomPatchDict = patchDict;
672  bottomPatchDict.add
673  (
674  "neighbourPatch",
675  !intrude ? bottomNbrPatchName : topNbrPatchName
676  );
677  if (bottomExtruded)
678  {
679  bottomPatchDict.add("isExtrudedRegion", isShellMesh);
680  }
681  }
682 
683  zoneBottomPatch[zonei] = addPatch
684  (
685  mesh.boundaryMesh(),
686  bottomPatchName,
687  patchTypes.size() ? patchTypes[zonei]
688  : !bottomMapped ? polyPatch::typeName
689  : !bottomExtruded
690  ? mappedWallPolyPatch::typeName
691  : mappedExtrudedWallPolyPatch::typeName,
692  bottomPatchDict,
693  newPatches
694  );
695 
696  Pout<< zoneBottomPatch[zonei]
697  << '\t' << newPatches[zoneBottomPatch[zonei]]->name()
698  << '\t' << newPatches[zoneBottomPatch[zonei]]->type()
699  << nl;
700 
701  if (!isShellMesh && !bothMapped) continue;
702 
703  dictionary topPatchDict;
704  if (topMapped)
705  {
706  topPatchDict = patchDict;
707  topPatchDict.add
708  (
709  "neighbourPatch",
710  !intrude ? topNbrPatchName : bottomNbrPatchName
711  );
712  if (topExtruded)
713  {
714  topPatchDict.add("isExtrudedRegion", isShellMesh);
715  }
716  }
717 
718  zoneTopPatch[zonei] = addPatch
719  (
720  mesh.boundaryMesh(),
721  topPatchName,
722  oppositePatchTypes.size() ? oppositePatchTypes[zonei]
723  : !topMapped ? polyPatch::typeName
724  : !topExtruded
725  ? mappedWallPolyPatch::typeName
726  : mappedExtrudedWallPolyPatch::typeName,
727  topPatchDict,
728  newPatches
729  );
730 
731  Pout<< zoneTopPatch[zonei]
732  << '\t' << newPatches[zoneTopPatch[zonei]]->name()
733  << '\t' << newPatches[zoneTopPatch[zonei]]->type()
734  << nl;
735  }
736 
737  Pout<< "Added " << newPatches.size()-nOldPatches
738  << " inter-region patches." << nl
739  << endl;
740 }
741 
742 
743 // Count the number of faces in patches that need to be created
744 labelList countExtrudePatches
745 (
746  const fvMesh& mesh,
747  const label nZones,
748  const primitiveFacePatch& extrudePatch,
749  const labelList& extrudeFaces,
750  const labelList& extrudeFaceZoneIDs,
751  const labelList& extrudeEdgeMeshEdges,
752  const labelListList& extrudeEdgeGlobalFaces
753 )
754 {
755  labelList zoneSideNFaces(nZones, 0);
756 
757  forAll(extrudePatch.edgeFaces(), edgeI)
758  {
759  const labelList& eFaces = extrudePatch.edgeFaces()[edgeI];
760 
761  if (eFaces.size() == 2)
762  {
763  // Internal edge
764  }
765  else if
766  (
767  eFaces.size() == 1
768  && extrudeEdgeGlobalFaces[edgeI].size() == 2
769  )
770  {
771  // Coupled edge
772  }
773  else
774  {
775  // Perimeter edge. Check whether we are on a mesh edge with
776  // external patches. If so choose any uncovered one. If none found
777  // put face in undetermined zone 'side' patch.
778  const label facei = findUncoveredPatchFace
779  (
780  mesh,
781  UIndirectList<label>(extrudeFaces, eFaces),
782  extrudeEdgeMeshEdges[edgeI]
783  );
784 
785  if (facei == -1)
786  {
787  forAll(extrudePatch.edgeFaces()[edgeI], i)
788  {
789  const label facei = extrudePatch.edgeFaces()[edgeI][i];
790  zoneSideNFaces[extrudeFaceZoneIDs[facei]] ++;
791  }
792  }
793  }
794  }
795 
796  Pstream::listCombineGather(zoneSideNFaces, plusEqOp<label>());
797  Pstream::listCombineScatter(zoneSideNFaces);
798 
799  return zoneSideNFaces;
800 }
801 
802 
803 // Add side patches into the mesh
804 labelList addZoneSidePatches
805 (
806  const fvMesh& mesh,
807  const wordList& zoneNames,
808  const labelList& zoneSideNFaces,
809  const word& oneDPolyPatchType,
810  DynamicList<polyPatch*>& newPatches
811 )
812 {
813  Pout<< "Adding patches for sides on zones:" << nl << nl
814  << "patchID\tpatch" << nl << "-------\t-----" << endl;
815 
816  labelList zoneSidePatches(zoneNames.size(), -labelMax);
817 
818  const label nOldPatches = newPatches.size();
819 
820  if (oneDPolyPatchType != word::null)
821  {
822  forAll(zoneSideNFaces, zoneI)
823  {
824  word patchName;
825 
826  if (oneDPolyPatchType == "empty")
827  {
828  patchName = "oneDEmptyPatch";
829  zoneSidePatches[zoneI] = addPatch
830  (
831  mesh.boundaryMesh(),
832  patchName,
833  emptyPolyPatch::typeName,
834  dictionary(),
835  newPatches
836  );
837  }
838  else if (oneDPolyPatchType == "wedge")
839  {
840  patchName = "oneDWedgePatch";
841  zoneSidePatches[zoneI] = addPatch
842  (
843  mesh.boundaryMesh(),
844  patchName,
845  wedgePolyPatch::typeName,
846  dictionary(),
847  newPatches
848  );
849  }
850  else
851  {
853  << "Type " << oneDPolyPatchType << " does not exist "
854  << exit(FatalError);
855  }
856 
857  Pout<< zoneSidePatches[zoneI] << '\t' << patchName << nl;
858  }
859  }
860  else
861  {
862  forAll(zoneSideNFaces, zoneI)
863  {
864  if (zoneSideNFaces[zoneI] > 0)
865  {
866  word patchName = zoneNames[zoneI] + "_" + "side";
867 
868  zoneSidePatches[zoneI] = addPatch
869  (
870  mesh.boundaryMesh(),
871  patchName,
872  polyPatch::typeName,
873  dictionary(),
874  newPatches
875  );
876 
877  Pout<< zoneSidePatches[zoneI] << '\t' << patchName << nl;
878  }
879  }
880  }
881 
882  Pout<< "Added " << newPatches.size() - nOldPatches << " zone-side patches."
883  << nl << endl;
884 
885  return zoneSidePatches;
886 }
887 
888 
889 // Add any additional coupled side patches that might be necessary. Return
890 // correspondence between extruded edges and their side patches.
891 labelList addExtrudeEdgeSidePatches
892 (
893  const fvMesh& mesh,
894  const primitiveFacePatch& extrudePatch,
895  const labelList& extrudeFaces,
896  const labelList& extrudeEdgeMeshEdges,
897  const distributionMap& extrudeEdgeFacesMap,
898  const labelListList& extrudeEdgeGlobalFaces,
899  DynamicList<polyPatch*>& newPatches
900 )
901 {
902  // Get procID in extrudeEdgeGlobalFaces order
903  labelList procID(extrudeEdgeGlobalFaces.size(), Pstream::myProcNo());
904  extrudeEdgeFacesMap.distribute(procID);
905 
906  // Calculate opposite processor for coupled edges (only if shared by
907  // two procs). Note: Could have saved original globalEdgeFaces structure.
908  labelList minProcID(extrudeEdgeGlobalFaces.size(), labelMax);
909  labelList maxProcID(extrudeEdgeGlobalFaces.size(), labelMin);
910  forAll(extrudeEdgeGlobalFaces, edgeI)
911  {
912  const labelList& eFaces = extrudeEdgeGlobalFaces[edgeI];
913  if (eFaces.size())
914  {
915  forAll(eFaces, i)
916  {
917  label proci = procID[eFaces[i]];
918  minProcID[edgeI] = min(minProcID[edgeI], proci);
919  maxProcID[edgeI] = max(maxProcID[edgeI], proci);
920  }
921  }
922  }
924  (
925  mesh,
926  extrudeEdgeMeshEdges,
927  minProcID,
928  minEqOp<label>(),
929  labelMax // null value
930  );
932  (
933  mesh,
934  extrudeEdgeMeshEdges,
935  maxProcID,
936  maxEqOp<label>(),
937  labelMin // null value
938  );
939 
940  Pout<< "Adding processor or cyclic patches:" << nl << nl
941  << "patchID\tpatch" << nl << "-------\t-----" << endl;
942 
943  const label nOldPatches = newPatches.size();
944 
945  labelList extrudeEdgeSidePatches(extrudePatch.edgeFaces().size(), -1);
946  forAll(extrudePatch.edgeFaces(), edgeI)
947  {
948  const labelList& eFaces = extrudePatch.edgeFaces()[edgeI];
949 
950  if
951  (
952  eFaces.size() == 1
953  && extrudeEdgeGlobalFaces[edgeI].size() == 2
954  )
955  {
956  // Coupled boundary edge. Find matching patch.
957  label nbrProci = minProcID[edgeI];
958  if (nbrProci == Pstream::myProcNo())
959  {
960  nbrProci = maxProcID[edgeI];
961  }
962 
963  if (nbrProci == Pstream::myProcNo())
964  {
965  // Cyclic patch since both procs the same. This cyclic should
966  // already exist in newPatches so no adding necessary.
967 
968  const label facei = findUncoveredCyclicPatchFace
969  (
970  mesh,
971  UIndirectList<label>(extrudeFaces, eFaces),
972  extrudeEdgeMeshEdges[edgeI]
973  );
974 
975  if (facei != -1)
976  {
977  const polyBoundaryMesh& patches = mesh.boundaryMesh();
978 
979  const label newPatchi = findPatchID
980  (
981  newPatches,
982  patches[patches.whichPatch(facei)].name()
983  );
984 
985  extrudeEdgeSidePatches[edgeI] = newPatchi;
986  }
987  else
988  {
990  << "Unable to determine coupled patch addressing"
991  << abort(FatalError);
992  }
993  }
994  else
995  {
996  // Processor patch
997  const word name =
999 
1000  extrudeEdgeSidePatches[edgeI] = findPatchID(newPatches, name);
1001 
1002  if (extrudeEdgeSidePatches[edgeI] == -1)
1003  {
1004  dictionary patchDict;
1005  patchDict.add("myProcNo", Pstream::myProcNo());
1006  patchDict.add("neighbProcNo", nbrProci);
1007 
1008  extrudeEdgeSidePatches[edgeI] = addPatch
1009  (
1010  mesh.boundaryMesh(),
1011  name,
1012  processorPolyPatch::typeName,
1013  patchDict,
1014  newPatches
1015  );
1016 
1017  Pout<< extrudeEdgeSidePatches[edgeI] << '\t' << name << nl;
1018  }
1019  }
1020  }
1021  }
1022 
1023  Pout<< "Added " << newPatches.size() - nOldPatches
1024  << " coupled patches." << nl << endl;
1025 
1026  return extrudeEdgeSidePatches;
1027 }
1028 
1029 
1030 int main(int argc, char *argv[])
1031 {
1032  argList::addNote("Create region mesh by extruding a faceZone or faceSet");
1033 
1034  #include "addRegionOption.H"
1035  #include "addOverwriteOption.H"
1036  #include "addDictOption.H"
1037  #include "setRootCase.H"
1038  #include "createTime.H"
1039  #include "createNamedMesh.H"
1040 
1041  if (mesh.boundaryMesh().checkParallelSync(true))
1042  {
1043  List<wordList> allNames(Pstream::nProcs());
1044  allNames[Pstream::myProcNo()] = mesh.boundaryMesh().names();
1045  Pstream::gatherList(allNames);
1046  Pstream::scatterList(allNames);
1047 
1049  << "Patches are not synchronised on all processors."
1050  << " Per processor patches " << allNames
1051  << exit(FatalError);
1052  }
1053 
1054  bool overwrite = args.optionFound("overwrite");
1055 
1056  const dictionary dict(systemDict("extrudeToRegionMeshDict", args, mesh));
1057 
1058  // Region to create by extrusion
1059  const word shellRegionName(dict.lookup("region"));
1060 
1061  // Should the extruded region overlap the existing region, i.e. "intrude"?
1062  const Switch intrude(dict.lookupOrDefault("intrude", false));
1063 
1064  if (shellRegionName == regionName)
1065  {
1066  FatalIOErrorIn(args.executable().c_str(), dict)
1067  << "Cannot extrude into same region as mesh." << endl
1068  << "Mesh region : " << regionName << endl
1069  << "Shell region : " << shellRegionName
1070  << exit(FatalIOError);
1071  }
1072 
1073  // Select faces to extrude
1074  enum class zoneSourceType
1075  {
1076  zone,
1077  set,
1078  patch
1079  };
1080 
1081  static const wordList zoneSourceTypeNames
1082  {
1083  "faceZone",
1084  "faceSet",
1085  "patch"
1086  };
1087 
1088  static const wordList zoneSourcesTypeNames
1089  {
1090  "faceZones",
1091  "faceSets",
1092  "patches"
1093  };
1094 
1095  wordList zoneNames;
1096  wordList oppositeZoneNames;
1097  List<zoneSourceType> zoneSourceTypes;
1098 
1099  auto lookupZones = [&](const zoneSourceType& type)
1100  {
1101  const word& keyword = zoneSourcesTypeNames[unsigned(type)];
1102 
1103  if (dict.found(keyword))
1104  {
1105  zoneNames.append(dict.lookup<wordList>(keyword));
1106 
1107  oppositeZoneNames.append
1108  (
1110  (
1111  {
1112  "opposite" + keyword.capitalise(),
1113  keyword + "Shadow"
1114  },
1115  wordList
1116  (
1117  zoneNames.size() - oppositeZoneNames.size(),
1118  word::null
1119  )
1120  )
1121  );
1122 
1123  zoneSourceTypes.setSize(zoneNames.size(), type);
1124  }
1125  };
1126  lookupZones(zoneSourceType::zone);
1127  lookupZones(zoneSourceType::set);
1128  lookupZones(zoneSourceType::patch);
1129 
1130  Info<< nl << "Extruding:" << nl << incrIndent;
1131  forAll(zoneNames, zonei)
1132  {
1133  const unsigned typei = unsigned(zoneSourceTypes[zonei]);
1134 
1135  if (oppositeZoneNames[zonei].empty())
1136  {
1137  Info<< indent << "From " << zoneSourceTypeNames[typei] << " \""
1138  << zoneNames[zonei] << "\"" << nl;
1139  }
1140  else
1141  {
1142  Info<< indent << "Between " << zoneSourcesTypeNames[typei] << " \""
1143  << zoneNames[zonei] << "\" and \"" << oppositeZoneNames[zonei]
1144  << "\"" << nl;
1145  }
1146  }
1147  Info<< endl << decrIndent;
1148 
1149  // One-dimensional extrusion settings
1150  const Switch oneD(dict.lookupOrDefault("oneD", false));
1151  Switch oneDNonManifoldEdges(false);
1152  word oneDPatchType(emptyPolyPatch::typeName);
1153  if (oneD)
1154  {
1155  oneDNonManifoldEdges = dict.lookupOrDefault("nonManifold", false);
1156  dict.lookup("oneDPolyPatchType") >> oneDPatchType;
1157  }
1158 
1159  if (oneD)
1160  {
1161  if (oneDNonManifoldEdges)
1162  {
1163  Info<< "Extruding as 1D columns with sides in patch type "
1164  << oneDPatchType
1165  << " and connected points (except on non-manifold areas)."
1166  << endl;
1167  }
1168  else
1169  {
1170  Info<< "Extruding as 1D columns with sides in patch type "
1171  << oneDPatchType
1172  << " and duplicated points (overlapping volumes)."
1173  << endl;
1174  }
1175  }
1176 
1177  // Construct the point generator
1179 
1180  // Change the primary mesh?
1181  const Switch adaptMesh(dict.lookup("adaptMesh"));
1182 
1183 
1184  // Determine output instance
1185  word meshInstance;
1186  if (!overwrite)
1187  {
1188  runTime++;
1189  meshInstance = runTime.name();
1190  }
1191  else
1192  {
1193  meshInstance = mesh.pointsInstance();
1194  }
1195  Info<< "Writing meshes to " << meshInstance << nl << endl;
1196 
1197 
1198  // Map from extrude zone to mesh zone, or -1 if not a mesh zone
1199  labelList zoneMeshZoneID(zoneNames.size(), -1);
1200  labelList oppositeZoneMeshZoneID(zoneNames.size(), -1);
1201  forAll(zoneNames, zonei)
1202  {
1203  if (zoneSourceTypes[zonei] != zoneSourceType::zone) continue;
1204 
1205  zoneMeshZoneID[zonei] =
1206  mesh.faceZones().findZoneID(zoneNames[zonei]);
1207 
1208  if (zoneMeshZoneID[zonei] == -1)
1209  {
1210  FatalIOErrorIn(args.executable().c_str(), dict)
1211  << "Cannot find zone " << zoneNames[zonei]
1212  << endl << "Valid zones are " << mesh.faceZones().names()
1213  << exit(FatalIOError);
1214  }
1215 
1216  if (!oppositeZoneNames[zonei].empty())
1217  {
1218  oppositeZoneMeshZoneID[zonei] =
1219  mesh.faceZones().findZoneID(oppositeZoneNames[zonei]);
1220 
1221  if (oppositeZoneMeshZoneID[zonei] == -1)
1222  {
1223  FatalIOErrorIn(args.executable().c_str(), dict)
1224  << "Cannot find opposite zone " << oppositeZoneNames[zonei]
1225  << endl << "Valid zones are " << mesh.faceZones().names()
1226  << exit(FatalIOError);
1227  }
1228  }
1229  }
1230 
1231 
1232  // Extract faces to extrude
1233  labelList extrudeFaces, oppositeExtrudeFaces;
1234  labelList extrudeFaceZoneIDs, oppositeExtrudeFaceZoneIDs;
1235  boolList extrudeFaceFlips, oppositeExtrudeFaceFlips;
1236  {
1237  // Load any faceSets that we need
1238  PtrList<faceSet> zoneSets(zoneNames.size());
1239  PtrList<faceSet> oppositeZoneSets(zoneNames.size());
1240  forAll(zoneNames, zonei)
1241  {
1242  if (zoneSourceTypes[zonei] == zoneSourceType::set)
1243  {
1244  zoneSets.set(zonei, new faceSet(mesh, zoneNames[zonei]));
1245  if (!oppositeZoneNames.empty())
1246  {
1247  oppositeZoneSets.set
1248  (
1249  zonei,
1250  new faceSet(mesh, oppositeZoneNames[zonei])
1251  );
1252  }
1253  }
1254  }
1255 
1256  // Create dynamic face lists
1257  DynamicList<label> facesDyn, oppositeFacesDyn;
1258  DynamicList<label> zoneIDsDyn, oppositeZoneIDsDyn;
1259  DynamicList<bool> flipsDyn, oppositeFlipsDyn;
1260  forAll(zoneNames, zonei)
1261  {
1262  switch (zoneSourceTypes[zonei])
1263  {
1264  case zoneSourceType::zone:
1265  {
1266  const faceZone& fz =
1267  mesh.faceZones()[zoneMeshZoneID[zonei]];
1268  facesDyn.append(fz);
1269  zoneIDsDyn.append(labelList(fz.size(), zonei));
1270  flipsDyn.append(fz.flipMap());
1271 
1272  if (!oppositeZoneNames[zonei].empty())
1273  {
1274  const faceZone& sfz =
1275  mesh.faceZones()[oppositeZoneMeshZoneID[zonei]];
1276  if (sfz.size() != fz.size())
1277  {
1278  FatalIOErrorIn(args.executable().c_str(), dict)
1279  << "Opposite zone " << oppositeZoneNames[zonei]
1280  << "is a different size from it's "
1281  << "corresponding zone " << zoneNames[zonei]
1282  << exit(FatalIOError);
1283  }
1284  oppositeFacesDyn.append(sfz);
1285  oppositeZoneIDsDyn.append(labelList(sfz.size(), zonei));
1286  oppositeFlipsDyn.append(sfz.flipMap());
1287  }
1288  else
1289  {
1290  oppositeFacesDyn.append(labelList(fz.size(), -1));
1291  oppositeZoneIDsDyn.append(labelList(fz.size(), -1));
1292  oppositeFlipsDyn.append(boolList(fz.size(), false));
1293  }
1294  break;
1295  }
1296  case zoneSourceType::set:
1297  {
1298  const faceSet& fs = zoneSets[zonei];
1299  facesDyn.append(fs.toc());
1300  zoneIDsDyn.append(labelList(fs.size(), zonei));
1301  flipsDyn.append(boolList(fs.size(), false));
1302 
1303  if (!oppositeZoneNames[zonei].empty())
1304  {
1305  const faceSet& sfs = oppositeZoneSets[zonei];
1306  if (sfs.size() != fs.size())
1307  {
1308  FatalIOErrorIn(args.executable().c_str(), dict)
1309  << "Opposite set " << oppositeZoneNames[zonei]
1310  << "is a different size from it's "
1311  << "corresponding zone " << zoneNames[zonei]
1312  << exit(FatalIOError);
1313  }
1314  oppositeFacesDyn.append(sfs.toc());
1315  oppositeZoneIDsDyn.append(labelList(sfs.size(), zonei));
1316  oppositeFlipsDyn.append(boolList(sfs.size(), false));
1317  }
1318  else
1319  {
1320  oppositeFacesDyn.append(labelList(fs.size(), -1));
1321  oppositeZoneIDsDyn.append(labelList(fs.size(), -1));
1322  oppositeFlipsDyn.append(boolList(fs.size(), false));
1323  }
1324  break;
1325  }
1326  case zoneSourceType::patch:
1327  {
1328  const polyPatch& pp =
1329  mesh.boundaryMesh()[zoneNames[zonei]];
1330  facesDyn.append(pp.start() + identityMap(pp.size()));
1331  zoneIDsDyn.append(labelList(pp.size(), zonei));
1332  flipsDyn.append(boolList(pp.size(), false));
1333 
1334  if (!oppositeZoneNames[zonei].empty())
1335  {
1336  const polyPatch& spp =
1337  mesh.boundaryMesh()[oppositeZoneNames[zonei]];
1338  if (spp.size() != pp.size())
1339  {
1340  FatalIOErrorIn(args.executable().c_str(), dict)
1341  << "Opposite patch " << oppositeZoneNames[zonei]
1342  << "is a different size from it's "
1343  << "corresponding zone " << zoneNames[zonei]
1344  << exit(FatalIOError);
1345  }
1346  oppositeFacesDyn.append
1347  (
1348  spp.start() + identityMap(spp.size())
1349  );
1350  oppositeZoneIDsDyn.append(labelList(spp.size(), zonei));
1351  oppositeFlipsDyn.append(boolList(spp.size(), false));
1352  }
1353  else
1354  {
1355  oppositeFacesDyn.append(labelList(pp.size(), -1));
1356  oppositeZoneIDsDyn.append(labelList(pp.size(), -1));
1357  oppositeFlipsDyn.append(boolList(pp.size(), false));
1358  }
1359  break;
1360  }
1361  }
1362  }
1363 
1364  // Transfer to non-dynamic storage
1365  extrudeFaces.transfer(facesDyn);
1366  extrudeFaceZoneIDs.transfer(zoneIDsDyn);
1367  extrudeFaceFlips.transfer(flipsDyn);
1368  oppositeExtrudeFaces.transfer(oppositeFacesDyn);
1369  oppositeExtrudeFaceZoneIDs.transfer(oppositeZoneIDsDyn);
1370  oppositeExtrudeFaceFlips.transfer(oppositeFlipsDyn);
1371  }
1372 
1373  faceList extrudeFaceList(UIndirectList<face>(mesh.faces(), extrudeFaces));
1374 
1375  forAll(extrudeFaceList, facei)
1376  {
1377  if (intrude != extrudeFaceFlips[facei])
1378  {
1379  extrudeFaceList[facei].flip();
1380  }
1381  }
1382 
1383  // Create a primitive patch of the extruded faces
1384  const primitiveFacePatch extrudePatch
1385  (
1386  extrudeFaceList,
1387  mesh.points()
1388  );
1389 
1390  // Check zone either all internal or all external faces
1391  const boolList zoneIsInternal
1392  (
1393  calcZoneIsInternal(mesh, zoneNames, extrudeFaces, extrudeFaceZoneIDs)
1394  );
1395 
1396 
1397  Info<< "extrudePatch :"
1398  << " faces:" << returnReduce(extrudePatch.size(), sumOp<label>())
1399  << " points:" << returnReduce(extrudePatch.nPoints(), sumOp<label>())
1400  << " edges:" << returnReduce(extrudePatch.nEdges(), sumOp<label>())
1401  << nl << endl;
1402 
1403 
1404  // Determine per-extrude-edge info
1405  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1406 
1407  // Corresponding mesh edges
1408  const labelList extrudeEdgeMeshEdges
1409  (
1410  extrudePatch.meshEdges
1411  (
1412  mesh.edges(),
1413  mesh.pointEdges()
1414  )
1415  );
1416 
1417  const globalIndex globalExtrudeFaces(extrudePatch.size());
1418 
1419  // Global pp faces per pp edge.
1420  labelListList extrudeEdgeGlobalFaces
1421  (
1422  globalEdgeFaces
1423  (
1424  mesh,
1425  globalExtrudeFaces,
1426  extrudePatch,
1427  extrudeEdgeMeshEdges
1428  )
1429  );
1430  List<Map<label>> compactMap;
1431  const distributionMap extrudeEdgeFacesMap
1432  (
1433  globalExtrudeFaces,
1434  extrudeEdgeGlobalFaces,
1435  compactMap
1436  );
1437 
1438 
1439  // Copy all non-local patches since these are used on boundary edges of
1440  // the extrusion
1441  DynamicList<polyPatch*> regionPatches(mesh.boundaryMesh().size());
1442  forAll(mesh.boundaryMesh(), patchi)
1443  {
1444  if (!isA<processorPolyPatch>(mesh.boundaryMesh()[patchi]))
1445  {
1446  regionPatches.append
1447  (
1448  mesh.boundaryMesh()[patchi].clone
1449  (
1450  mesh.boundaryMesh(),
1451  regionPatches.size(),
1452  0, // size
1453  0 // start
1454  ).ptr()
1455  );
1456  }
1457  }
1458 
1459 
1460  // Add interface patches
1461  // ~~~~~~~~~~~~~~~~~~~~~
1462 
1463  // From zone to interface patch (region side)
1464  labelList zoneTopPatch, zoneBottomPatch;
1465  addCouplingPatches
1466  (
1467  mesh,
1468  true,
1469  intrude,
1470  shellRegionName,
1471  regionName,
1472  zoneNames,
1473  oppositeZoneNames,
1474  zoneIsInternal,
1475  dict,
1476  regionPatches,
1477  zoneTopPatch,
1478  zoneBottomPatch
1479  );
1480 
1481  // From zone to interface patch (mesh side)
1482  labelList interMeshTopPatch;
1483  labelList interMeshBottomPatch;
1484  if (adaptMesh)
1485  {
1486  const polyBoundaryMesh& patches = mesh.boundaryMesh();
1487 
1488  // Clone existing non-processor patches
1489  DynamicList<polyPatch*> newPatches(patches.size());
1491  {
1492  if (!isA<processorPolyPatch>(patches[patchi]))
1493  {
1494  newPatches.append(patches[patchi].clone(patches).ptr());
1495  }
1496  }
1497 
1498  // Add new patches
1499  addCouplingPatches
1500  (
1501  mesh,
1502  false,
1503  intrude,
1504  regionName,
1505  shellRegionName,
1506  zoneNames,
1507  oppositeZoneNames,
1508  zoneIsInternal,
1509  dict,
1510  newPatches,
1511  interMeshTopPatch,
1512  interMeshBottomPatch
1513  );
1514 
1515  // Clone existing processor patches
1517  {
1518  if (isA<processorPolyPatch>(patches[patchi]))
1519  {
1520  newPatches.append
1521  (
1523  (
1524  patches,
1525  newPatches.size(),
1526  patches[patchi].size(),
1527  patches[patchi].start()
1528  ).ptr()
1529  );
1530  }
1531  }
1532 
1533  // Add to mesh
1534  mesh.clearOut();
1535  mesh.removeFvBoundary();
1536  mesh.addFvPatches(newPatches, true);
1537 
1538  // Note: from this point on mesh patches differs from regionPatches
1539  }
1540 
1541 
1542  // Patch per extruded face
1543  labelList extrudeFaceTopPatchID(extrudePatch.size());
1544  labelList extrudeFaceBottomPatchID(extrudePatch.size());
1545  forAll(extrudeFaceZoneIDs, facei)
1546  {
1547  extrudeFaceTopPatchID[facei] =
1548  zoneTopPatch[extrudeFaceZoneIDs[facei]];
1549  extrudeFaceBottomPatchID[facei] =
1550  zoneBottomPatch[extrudeFaceZoneIDs[facei]];
1551  }
1552 
1553 
1554  // Count how many patches on special edges of extrudePatch are necessary
1555  const labelList zoneSideNFaces
1556  (
1557  countExtrudePatches
1558  (
1559  mesh,
1560  zoneNames.size(),
1561  extrudePatch, // patch
1562  extrudeFaces, // mesh face per patch face
1563  extrudeFaceZoneIDs, // ...
1564  extrudeEdgeMeshEdges, // mesh edge per patch edge
1565  extrudeEdgeGlobalFaces // global indexing per patch edge
1566  )
1567  );
1568 
1569 
1570  // Add the zone-side patches.
1571  const labelList zoneSidePatches
1572  (
1573  addZoneSidePatches
1574  (
1575  mesh,
1576  zoneNames,
1577  zoneSideNFaces,
1578  (oneD ? oneDPatchType : word::null),
1579  regionPatches
1580  )
1581  );
1582 
1583 
1584  // Sets extrudeEdgeSidePatches[edgei] to interprocessor patch. Adds any
1585  // interprocessor or cyclic patches if necessary.
1586  const labelList extrudeEdgeSidePatches
1587  (
1588  addExtrudeEdgeSidePatches
1589  (
1590  mesh,
1591  extrudePatch,
1592  extrudeFaces,
1593  extrudeEdgeMeshEdges,
1594  extrudeEdgeFacesMap,
1595  extrudeEdgeGlobalFaces,
1596  regionPatches
1597  )
1598  );
1599 
1600 
1601  // Set patches to use for edges to be extruded into boundary faces
1602  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1603  // In order of edgeFaces: per edge, per originating face the
1604  // patch to use for the side face (from the extruded edge).
1605  // If empty size create an internal face.
1606  labelListList extrudeEdgePatches(extrudePatch.nEdges());
1607 
1608  // Is edge a non-manifold edge
1609  PackedBoolList nonManifoldEdge(extrudePatch.nEdges(), false);
1610 
1611  // Note: logic has to be same as in countExtrudePatches.
1612  forAll(extrudePatch.edgeFaces(), edgeI)
1613  {
1614  const labelList& eFaces = extrudePatch.edgeFaces()[edgeI];
1615  labelList& ePatches = extrudeEdgePatches[edgeI];
1616 
1617  if (oneD)
1618  {
1619  ePatches.setSize(eFaces.size());
1620  forAll(eFaces, i)
1621  {
1622  ePatches[i] =
1623  zoneSidePatches[extrudeFaceZoneIDs[eFaces[i]]];
1624  }
1625 
1626  if (oneDNonManifoldEdges)
1627  {
1628  if (eFaces.size() != 2)
1629  {
1630  nonManifoldEdge[edgeI] = true;
1631  }
1632  }
1633  else
1634  {
1635  nonManifoldEdge[edgeI] = true;
1636  }
1637  }
1638  else if (eFaces.size() == 2)
1639  {
1640  // Internal edge
1641  }
1642  else if (extrudeEdgeSidePatches[edgeI] != -1)
1643  {
1644  // Coupled edge
1645  ePatches.setSize(eFaces.size());
1646  forAll(eFaces, i)
1647  {
1648  ePatches[i] = extrudeEdgeSidePatches[edgeI];
1649  }
1650  }
1651  else
1652  {
1653  // Perimeter edge
1654  const label facei = findUncoveredPatchFace
1655  (
1656  mesh,
1657  UIndirectList<label>(extrudeFaces, eFaces),
1658  extrudeEdgeMeshEdges[edgeI]
1659  );
1660 
1661  if (facei != -1)
1662  {
1663  const label newPatchi =
1664  findPatchID
1665  (
1666  regionPatches,
1667  mesh.boundaryMesh()
1668  [
1669  mesh.boundaryMesh().whichPatch(facei)
1670  ].name()
1671  );
1672  ePatches.setSize(eFaces.size(), newPatchi);
1673  }
1674  else
1675  {
1676  ePatches.setSize(eFaces.size());
1677  forAll(eFaces, i)
1678  {
1679  ePatches[i] =
1680  zoneSidePatches[extrudeFaceZoneIDs[eFaces[i]]];
1681  }
1682  }
1683 
1684  nonManifoldEdge[edgeI] = true;
1685  }
1686  }
1687 
1688 
1689 
1690  // Assign point regions
1691  // ~~~~~~~~~~~~~~~~~~~~
1692 
1693  // Per face, per point the region number.
1694  faceList pointGlobalRegions;
1695  faceList pointLocalRegions;
1696  labelList localToGlobalRegion;
1697 
1699  (
1700  mesh.globalData(),
1701  extrudePatch,
1702  nonManifoldEdge,
1703  false, // keep cyclic separated regions apart
1704  pointGlobalRegions,
1705  pointLocalRegions,
1706  localToGlobalRegion
1707  );
1708 
1709  // Per local region an originating point
1710  labelList localRegionPoints(localToGlobalRegion.size());
1711  forAll(pointLocalRegions, facei)
1712  {
1713  const face& f = extrudePatch.localFaces()[facei];
1714  const face& pRegions = pointLocalRegions[facei];
1715  forAll(pRegions, fp)
1716  {
1717  localRegionPoints[pRegions[fp]] = f[fp];
1718  }
1719  }
1720 
1721  // Calculate region normals by reducing local region normals
1722  pointField localRegionNormals(localToGlobalRegion.size());
1723  {
1724  pointField localSum(localToGlobalRegion.size(), Zero);
1725 
1726  forAll(pointLocalRegions, facei)
1727  {
1728  const face& pRegions = pointLocalRegions[facei];
1729  forAll(pRegions, fp)
1730  {
1731  const label localRegionI = pRegions[fp];
1732 
1733  // Add a small amount of the face-centre-to-point vector in
1734  // order to stabilise the computation of normals on the edges
1735  // of baffles
1736  localSum[localRegionI] +=
1737  rootSmall
1738  *(
1739  extrudePatch.points()[extrudePatch[facei][fp]]
1740  - extrudePatch.faceCentres()[facei]
1741  )
1742  + (1 - rootSmall)
1743  *(
1744  extrudePatch.faceNormals()[facei]
1745  );
1746  }
1747  }
1748 
1749  Map<point> globalSum(2*localToGlobalRegion.size());
1750 
1751  forAll(localSum, localRegionI)
1752  {
1753  label globalRegionI = localToGlobalRegion[localRegionI];
1754  globalSum.insert(globalRegionI, localSum[localRegionI]);
1755  }
1756 
1757  // Reduce
1759  Pstream::mapCombineScatter(globalSum);
1760 
1761  forAll(localToGlobalRegion, localRegionI)
1762  {
1763  label globalRegionI = localToGlobalRegion[localRegionI];
1764  localRegionNormals[localRegionI] = globalSum[globalRegionI];
1765  }
1766  localRegionNormals /= mag(localRegionNormals) ;
1767  }
1768 
1769 
1770  // Use model to create displacements of first layer
1771  vectorField firstDisp(localRegionNormals.size());
1772  forAll(firstDisp, regionI)
1773  {
1774  const point& regionPt = extrudePatch.points()
1775  [
1776  extrudePatch.meshPoints()
1777  [
1778  localRegionPoints[regionI]
1779  ]
1780  ];
1781  const vector& n = localRegionNormals[regionI];
1782  firstDisp[regionI] = model()(regionPt, n, 1) - regionPt;
1783  }
1784 
1785 
1786  // Create a new mesh
1787  // ~~~~~~~~~~~~~~~~~
1788 
1789  fvMesh regionMesh
1790  (
1791  IOobject
1792  (
1793  shellRegionName,
1794  meshInstance,
1795  runTime,
1798  false
1799  ),
1800  pointField(),
1801  faceList(),
1802  labelList(),
1803  labelList(),
1804  false
1805  );
1806 
1807  // Add the new patches
1808  forAll(regionPatches, patchi)
1809  {
1810  polyPatch* ppPtr = regionPatches[patchi];
1811  regionPatches[patchi] = ppPtr->clone(regionMesh.boundaryMesh()).ptr();
1812  delete ppPtr;
1813  }
1814  regionMesh.clearOut();
1815  regionMesh.removeFvBoundary();
1816  regionMesh.addFvPatches(regionPatches, true);
1817 
1818  // Extrude
1819  {
1820  polyTopoChange meshMod(regionPatches.size());
1821 
1822  createShellMesh extruder
1823  (
1824  extrudePatch,
1825  pointLocalRegions,
1826  localRegionPoints
1827  );
1828 
1829  extruder.setRefinement
1830  (
1831  firstDisp, // first displacement
1832  model().expansionRatio(),
1833  model().nLayers(), // nLayers
1834  extrudeFaceTopPatchID,
1835  extrudeFaceBottomPatchID,
1836  extrudeEdgePatches,
1837  meshMod
1838  );
1839 
1840  // Enforce actual point positions according to extrudeModel (model), as
1841  // the extruder only does a fixed expansionRatio. The regionPoints and
1842  // nLayers are looped in the same way as in createShellMesh.
1843  DynamicList<point>& newPoints =
1844  const_cast<DynamicList<point>&>(meshMod.points());
1845  label meshPointi = extrudePatch.localPoints().size();
1846  forAll(localRegionPoints, regioni)
1847  {
1848  const label pointi = localRegionPoints[regioni];
1849  const point& pt = extrudePatch.localPoints()[pointi];
1850  const vector& n = localRegionNormals[regioni];
1851 
1852  for (label layeri = 1; layeri <= model().nLayers(); layeri++)
1853  {
1854  newPoints[meshPointi++] = model()(pt, n, layeri);
1855  }
1856  }
1857 
1858  meshMod.changeMesh(regionMesh, false);
1859  }
1860 
1861  // Set region mesh instance and write options
1862  regionMesh.setInstance(meshInstance);
1863 
1864  // Remove any unused patches
1865  deleteEmptyPatches(regionMesh);
1866 
1867 
1868  Info<< "Writing mesh " << regionMesh.name() << " to "
1869  << regionMesh.facesInstance() << nl << endl;
1870  regionMesh.write();
1871 
1872 
1873  // Insert baffles into original mesh
1874  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1875 
1876  autoPtr<polyTopoChangeMap> addBafflesMap;
1877 
1878  if (adaptMesh)
1879  {
1880  polyTopoChange meshMod(mesh);
1881 
1882  // Modify faces to be in bottom (= always coupled) patch
1883  forAll(extrudeFaces, facei)
1884  {
1885  const label meshFacei = extrudeFaces[facei];
1886  const label zonei = extrudeFaceZoneIDs[facei];
1887  const bool flip = extrudeFaceFlips[facei];
1888  const face& f = mesh.faces()[meshFacei];
1889 
1890  if (!flip)
1891  {
1892  meshMod.modifyFace
1893  (
1894  f, // modified face
1895  meshFacei, // label of face being modified
1896  mesh.faceOwner()[meshFacei],// owner
1897  -1, // neighbour
1898  false, // face flip
1899  interMeshBottomPatch[zonei],// patch for face
1900  zoneMeshZoneID[zonei], // zone for face
1901  false // face flip in zone
1902  );
1903  }
1904  else if (mesh.isInternalFace(meshFacei))
1905  {
1906  meshMod.modifyFace
1907  (
1908  f.reverseFace(), // modified face
1909  meshFacei, // label of modified face
1910  mesh.faceNeighbour()[meshFacei],// owner
1911  -1, // neighbour
1912  true, // face flip
1913  interMeshBottomPatch[zonei], // patch for face
1914  zoneMeshZoneID[zonei], // zone for face
1915  true // face flip in zone
1916  );
1917  }
1918  }
1919 
1920  forAll(extrudeFaces, facei)
1921  {
1922  if (oppositeExtrudeFaces[facei] != -1)
1923  {
1924  const label meshFacei = oppositeExtrudeFaces[facei];
1925  const label zonei = oppositeExtrudeFaceZoneIDs[facei];
1926  const bool flip = oppositeExtrudeFaceFlips[facei];
1927  const face& f = mesh.faces()[meshFacei];
1928 
1929  if (!flip)
1930  {
1931  meshMod.modifyFace
1932  (
1933  f, // modified face
1934  meshFacei, // face being modified
1935  mesh.faceOwner()[meshFacei],// owner
1936  -1, // neighbour
1937  false, // face flip
1938  interMeshTopPatch[zonei], // patch for face
1939  zoneMeshZoneID[zonei], // zone for face
1940  false // face flip in zone
1941  );
1942  }
1943  else if (mesh.isInternalFace(meshFacei))
1944  {
1945  meshMod.modifyFace
1946  (
1947  f.reverseFace(), // modified face
1948  meshFacei, // label modified face
1949  mesh.faceNeighbour()[meshFacei],// owner
1950  -1, // neighbour
1951  true, // face flip
1952  interMeshTopPatch[zonei], // patch for face
1953  zoneMeshZoneID[zonei], // zone for face
1954  true // face flip in zone
1955  );
1956  }
1957  }
1958  else
1959  {
1960  const label meshFacei = extrudeFaces[facei];
1961  const label zonei = extrudeFaceZoneIDs[facei];
1962  const bool flip = extrudeFaceFlips[facei];
1963  const face& f = mesh.faces()[meshFacei];
1964 
1965  if (!flip)
1966  {
1967  if (mesh.isInternalFace(meshFacei))
1968  {
1969  meshMod.addFace
1970  (
1971  f.reverseFace(), // modified face
1972  mesh.faceNeighbour()[meshFacei],// owner
1973  -1, // neighbour
1974  -1, // master point
1975  -1, // master edge
1976  meshFacei, // master face
1977  true, // flip flux
1978  interMeshTopPatch[zonei], // patch for face
1979  -1, // zone for face
1980  false // face flip in zone
1981  );
1982  }
1983  }
1984  else
1985  {
1986  meshMod.addFace
1987  (
1988  f, // face
1989  mesh.faceOwner()[meshFacei], // owner
1990  -1, // neighbour
1991  -1, // master point
1992  -1, // master edge
1993  meshFacei, // master face
1994  false, // flip flux
1995  interMeshTopPatch[zonei], // patch for face
1996  -1, // zone for face
1997  false // zone flip
1998  );
1999  }
2000  }
2001  }
2002 
2003  // Change the mesh. Change points directly (no inflation).
2004  addBafflesMap = meshMod.changeMesh(mesh, false);
2005 
2006  // Update fields
2007  mesh.topoChange(addBafflesMap);
2008 
2009  // Move mesh (since morphing might not do this)
2010  if (addBafflesMap().hasMotionPoints())
2011  {
2012  mesh.setPoints(addBafflesMap().preMotionPoints());
2013  }
2014 
2015  mesh.setInstance(meshInstance);
2016 
2017  // Remove any unused patches
2018  deleteEmptyPatches(mesh);
2019 
2020  Info<< "Writing mesh " << mesh.name() << " to "
2021  << mesh.facesInstance() << nl << endl;
2022  mesh.write();
2023  }
2024 
2025  Info << "End\n" << endl;
2026 
2027  return 0;
2028 }
2029 
2030 
2031 // ************************************************************************* //
scalar y
label n
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:78
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:296
List< Key > toc() const
Return the table of contents.
Definition: HashTable.C:202
label size() const
Return number of elements in table.
Definition: HashTableI.H:65
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
autoPtr< IOobject > clone() const
Clone.
Definition: IOobject.H:283
const word & name() const
Return name.
Definition: IOobject.H:310
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:60
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:91
void transfer(List< T > &)
Transfer the contents of the argument List into this list.
Definition: List.C:342
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:178
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
void setSize(const label)
Reset size of List.
Definition: List.C:281
A HashTable to objects of type <T> with a label key.
Definition: Map.H:52
label findZoneID(const word &zoneName) const
Find zone index given a name.
Definition: MeshZones.C:341
wordList names() const
Return a list of zone names.
Definition: MeshZones.C:256
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:57
virtual Ostream & write(const char)=0
Write character.
A bit-packed bool list.
A list of faces which address into the list of points.
label nEdges() const
Return number of edges in patch.
label nPoints() const
Return number of points supporting patch faces.
labelList meshEdges(const edgeList &allEdges, const labelListList &cellEdges, const labelList &faceCells) const
Return labels of patch edges in the global edge list using.
const labelList & meshPoints() const
Return labelList of mesh points in patch. They are constructed.
const Field< PointType > & points() const
Return reference to global points.
const List< FaceType > & localFaces() const
Return patch faces addressing into local point list.
const labelListList & edgeFaces() const
Return edge-face addressing.
const Field< PointType > & localPoints() const
Return pointField of points in patch.
const Field< PointType > & faceNormals() const
Return face normals for patch.
const Field< PointType > & faceCentres() const
Return face centres for patch.
static void scatter(const List< commsStruct > &comms, T &Value, const int tag, const label comm)
Scatter data. Distribute without modification. Reverse of gather.
static void scatterList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Scatter data. Reverse of gatherList.
static void mapCombineScatter(const List< commsStruct > &comms, Container &Values, const int tag, const label comm)
Scatter data. Reverse of combineGather.
static void listCombineGather(const List< commsStruct > &comms, List< T > &Value, const CombineOp &cop, const int tag, const label comm)
static void mapCombineGather(const List< commsStruct > &comms, Container &Values, const CombineOp &cop, const int tag, const label comm)
static void listCombineScatter(const List< commsStruct > &comms, List< T > &Value, const int tag, const label comm)
Scatter data. Reverse of combineGather.
static void gatherList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Gather data but keep individual values separate.
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: PtrList.H:75
A simple wrapper around bool so that it can be read as a word: true/false, on/off,...
Definition: Switch.H:61
A List with indirect addressing.
Definition: UIndirectList.H:60
label size() const
Return the number of elements in the list.
bool empty() const
Return true if the UList is empty (ie, size() is zero)
Definition: UListI.H:325
void swap(UList< T > &)
Swap two ULists of the same type in constant time.
Definition: UList.C:90
T & last()
Return the last element of the list.
Definition: UListI.H:128
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:423
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:411
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
static void addNote(const string &)
Add extra notes for the usage information.
Definition: argList.C:159
bool optionFound(const word &opt) const
Return true if the named option is found.
Definition: argListI.H:114
const word & executable() const
Name of executable without the path.
Definition: argListI.H:36
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: autoPtr.H:51
Creates mesh by extruding a patch.
static void calcPointRegions(const globalMeshData &globalData, const primitiveFacePatch &patch, const PackedBoolList &nonManifoldEdge, const bool syncNonCollocated, faceList &pointGlobalRegions, faceList &pointLocalRegions, labelList &localToGlobalRegion)
Helper: calculate point regions. The point region is the.
A list of keyword definitions, which are a keyword followed by any number of values (e....
Definition: dictionary.H:160
T lookupOrDefaultBackwardsCompatible(const wordList &, const T &, bool recursive=false, bool patternMatch=true) const
Find and return a T, trying a list of keywords in sequence.
T lookupOrDefault(const word &, const T &, bool recursive=false, bool patternMatch=true) const
Find and return a T,.
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:860
void set(entry *)
Assign a new entry, overwrite any existing entry.
Definition: dictionary.C:1307
bool add(entry *, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:1169
bool found(const word &, bool recursive=false, bool patternMatch=true) const
Search dictionary for given keyword.
Definition: dictionary.C:659
Class containing processor-to-processor mapping information.
void distribute(List< T > &fld, const bool dummyTransform=true, const int tag=UPstream::msgType()) const
Distribute data using default commsType.
Class to handle errors and exceptions in a simple, consistent stream-based manner.
Definition: error.H:71
static autoPtr< extrudeModel > New(const dictionary &)
Select null constructed.
A list of face labels.
Definition: faceSet.H:51
A subset of mesh faces organised as a primitive patch.
Definition: faceZone.H:68
const boolList & flipMap() const
Return face flip map.
Definition: faceZone.H:249
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:76
static void reorderPatches(fvMesh &, const labelList &oldToNew, const label nPatches, const bool validBoundary)
Reorder and remove trailing patches. If validBoundary call is parallel.
Definition: fvMeshTools.C:141
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:101
void addFvPatches(const List< polyPatch * > &, const bool validBoundary=true)
Add boundary patches. Constructor helper.
Definition: fvMesh.C:727
virtual bool write(const bool write=true) const
Write mesh using IO settings from time.
Definition: fvMesh.C:1736
void removeFvBoundary()
Remove boundary patches. Warning: fvPatchFields hold ref to.
Definition: fvMesh.C:745
const word & name() const
Return reference to name.
Definition: fvMesh.H:416
virtual void topoChange(const polyTopoChangeMap &map)
Update mesh corresponding to the given map.
Definition: fvMesh.C:1236
void clearOut()
Clear all geometry and addressing.
Definition: fvMesh.C:286
virtual void setPoints(const pointField &)
Reset the points.
Definition: fvMesh.C:1133
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:64
label toGlobal(const label i) const
From local to global.
Definition: globalIndexI.H:82
Foam::polyBoundaryMesh.
label whichPatch(const label faceIndex) const
Return patch index for a given face label.
wordList names() const
Return a list of patch names.
bool checkParallelSync(const bool report=false) const
Check whether all procs have all patches and in same order. Return.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:80
const fileName & facesInstance() const
Return the current instance directory for faces.
Definition: polyMesh.C:1025
const meshFaceZones & faceZones() const
Return face zones.
Definition: polyMesh.H:447
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1373
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1386
const globalMeshData & globalData() const
Return parallel info.
Definition: polyMesh.C:1562
const fileName & pointsInstance() const
Return the current instance directory for points.
Definition: polyMesh.C:1019
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:405
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1392
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1360
void setInstance(const fileName &)
Set the instance for mesh files.
Definition: polyMeshIO.C:78
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:70
static autoPtr< polyPatch > New(const word &patchType, const word &name, const label size, const label start, const label index, const polyBoundaryMesh &bm)
Return a pointer to a new patch created on freestore from.
Definition: polyPatchNew.C:32
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:280
virtual autoPtr< polyPatch > clone(const polyBoundaryMesh &bm) const
Construct and return a clone, resetting the boundary mesh.
Definition: polyPatch.H:215
Direct mesh changes based on v1.3 polyTopoChange syntax.
const labelListList & pointEdges() const
const edgeList & edges() const
Return mesh edges. Uses calcEdges.
const labelListList & edgeFaces() const
bool isInternalFace(const label faceIndex) const
Return true if given face label is internal to the mesh.
static word newName(const label myProcNo, const label neighbProcNo)
Return the name of a processorPolyPatch.
static void syncEdgeList(const polyMesh &, List< T > &, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronise values on all mesh edges.
A class for handling words, derived from string.
Definition: word.H:62
static const word null
An empty word.
Definition: word.H:77
Base class for zones.
Definition: zone.H:60
Foam::word regionName
#define FatalIOErrorIn(functionName, ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:312
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
int main(int argc, char *argv[])
Definition: financialFoam.C:44
label patchi
const fvPatchList & patches
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
static const zero Zero
Definition: zero.H:97
Ostream & decrIndent(Ostream &os)
Decrement the indent level.
Definition: Ostream.H:235
List< label > labelList
A List of labels.
Definition: labelList.H:56
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
IOdictionary systemDict(const word &dictName, const argList &args, const objectRegistry &ob, const word &regionName=polyMesh::defaultRegion)
Definition: systemDict.C:92
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
word name(const bool)
Return a word representation of a bool.
Definition: boolIO.C:39
errorManip< error > abort(error &err)
Definition: errorManip.H:131
messageStream Info
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
Ostream & incrIndent(Ostream &os)
Increment the indent level.
Definition: Ostream.H:228
List< bool > boolList
Bool container classes.
Definition: boolList.H:50
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Istream & operator>>(Istream &, directionInfo &)
dimensioned< scalar > mag(const dimensioned< Type > &)
T clone(const T &t)
Definition: List.H:55
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
IOerror FatalIOError
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
error FatalError
static const label labelMax
Definition: label.H:62
labelList identityMap(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
Ostream & operator<<(Ostream &, const ensightPart &)
List< face > faceList
Definition: faceListFwd.H:43
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:221
static const char nl
Definition: Ostream.H:260
static const label labelMin
Definition: label.H:61
fileType type(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return the file type: directory or file.
Definition: POSIX.C:488
wordList patchTypes(nPatches)
wordList patchNames(nPatches)
faceListList boundary(nPatches)
labelList f(nPoints)
dictionary dict
Foam::argList args(argc, argv)
volScalarField & p