extrudeMesh.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-2026 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  extrudeMesh
26 
27 Description
28  Extrude mesh from existing patch or from patch read from file.
29 
30  Type of extrusion prescribed by run-time selectable model.
31 
32 \*---------------------------------------------------------------------------*/
33 
34 #include "argList.H"
35 #include "Time.H"
36 #include "polyTopoChange.H"
37 #include "edgeCollapser.H"
38 #include "perfectInterface.H"
39 #include "addPatchCellLayer.H"
40 #include "fvMesh.H"
41 #include "MeshedSurfaces.H"
42 #include "globalIndex.H"
43 #include "cellSet.H"
44 #include "systemDict.H"
45 
46 #include "extrudedMesh.H"
47 #include "extrudeModel.H"
48 
49 #include "wedge.H"
50 #include "wedgePolyPatch.H"
51 #include "planeExtrusion.H"
52 #include "emptyPolyPatch.H"
53 #include "processorPolyPatch.H"
54 
55 using namespace Foam;
56 
57 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
58 
59 enum class extrudeSurfaceType
60 {
61  mesh,
62  patch,
63  surface
64 };
65 
66 static const NamedEnum<extrudeSurfaceType, 3> extrudeSurfaceTypeNames
67 {
68  "mesh",
69  "patch",
70  "surface"
71 };
72 
73 
75 {
76  const label patchID = patches.findIndex(name);
77 
78  if (patchID == -1)
79  {
81  << "Cannot find patch " << name
82  << " in the source mesh.\n"
83  << "Valid patch names are " << patches.names()
84  << exit(FatalError);
85  }
86  return patchID;
87 }
88 
89 
90 labelList findPatchZones(polyMesh& mesh, const wordList& zoneNames)
91 {
92  labelList patchZones(zoneNames.size());
93 
94  // Add optional cellZone generation for the extrusion layer
95  forAll(zoneNames, i)
96  {
97  const label cellZonei = mesh.cellZones().findIndex(zoneNames[i]);
98  if (cellZonei >= 0)
99  {
100  patchZones[i] = cellZonei;
101  }
102  else
103  {
104  label nZones = mesh.cellZones().size();
105  mesh.cellZones().setSize(nZones + 1);
106  mesh.cellZones().set
107  (
108  nZones,
109  new cellZone
110  (
111  zoneNames[i],
112  labelList(),
113  mesh.cellZones()
114  )
115  );
116  patchZones[i] = nZones;
117  }
118  }
119 
120  return patchZones;
121 }
122 
123 
124 labelList findPatchFaces
125 (
126  polyMesh& mesh,
127  const polyBoundaryMesh& patches,
128  const wordList& patchNames,
129  const labelList& patchZones,
130  labelList& faceCellZones
131 )
132 {
133  // Count of the number of faces in the named patches
134  label n = 0;
135 
136  forAll(patchNames, i)
137  {
139  }
140 
141  labelList faceLabels(n);
142  faceCellZones.setSize(n);
143  n = 0;
144 
145  forAll(patchNames, i)
146  {
147  const polyPatch& pp = patches[findIndex(patches, patchNames[i])];
148 
149  forAll(pp, j)
150  {
151  faceLabels[n] = pp.start()+j;
152  faceCellZones[n] = patchZones[i];
153  n++;
154  }
155  }
156 
157  return faceLabels;
158 }
159 
160 
161 labelList findPatchFaces
162 (
163  const polyBoundaryMesh& patches,
164  const word& name
165 )
166 {
167  const polyPatch& pp = patches[findIndex(patches, name)];
168  labelList faceLabels(pp.size());
169 
170  forAll(pp, i)
171  {
172  faceLabels[i] = pp.start() + i;
173  }
174 
175  return faceLabels;
176 }
177 
178 
179 void updateFaceLabels(const polyTopoChangeMap& map, labelList& faceLabels)
180 {
181  const labelList& reverseMap = map.reverseFaceMap();
182 
183  labelList newFaceLabels(faceLabels.size());
184  label newI = 0;
185 
186  forAll(faceLabels, i)
187  {
188  label oldFacei = faceLabels[i];
189 
190  if (reverseMap[oldFacei] >= 0)
191  {
192  newFaceLabels[newI++] = reverseMap[oldFacei];
193  }
194  }
195  newFaceLabels.setSize(newI);
196  faceLabels.transfer(newFaceLabels);
197 }
198 
199 
200 void updateCellSet(const polyTopoChangeMap& map, labelHashSet& cellLabels)
201 {
202  const labelList& reverseMap = map.reverseCellMap();
203 
204  labelHashSet newCellLabels(2*cellLabels.size());
205 
206  forAll(cellLabels, i)
207  {
208  label oldCelli = cellLabels[i];
209 
210  if (reverseMap[oldCelli] >= 0)
211  {
212  newCellLabels.insert(reverseMap[oldCelli]);
213  }
214  }
215  cellLabels.transfer(newCellLabels);
216 }
217 
218 
219 template<class PatchType>
220 void changeFrontBackPatches
221 (
222  polyMesh& mesh,
223  const word& frontPatchName,
224  const word& backPatchName
225 )
226 {
228 
229  label frontPatchi = findIndex(patches, frontPatchName);
230  label backPatchi = findIndex(patches, backPatchName);
231 
232  DynamicList<polyPatch*> newPatches(patches.size());
233 
235  {
236  const polyPatch& pp(patches[patchi]);
237 
238  if (patchi == frontPatchi || patchi == backPatchi)
239  {
240  newPatches.append
241  (
242  new PatchType
243  (
244  pp.name(),
245  pp.size(),
246  pp.start(),
247  pp.index(),
248  mesh.boundary()
249  )
250  );
251  }
252  else
253  {
254  newPatches.append(pp.clone(mesh.boundary()).ptr());
255  }
256  }
257 
258  // Edit patches
260  mesh.addPatches(newPatches, true);
261 }
262 
263 
264 int main(int argc, char *argv[])
265 {
266  #include "addRegionOption.H"
267  #include "addMeshOption.H"
268  #include "addDictOption.H"
269  #include "addNoOverwriteOption.H"
270 
271  #include "setRootCase.H"
272  #include "createTimeExtruded.H"
273  #include "setNoOverwrite.H"
274 
275  const dictionary dict(systemDict("extrudeMeshDict", args, runTimeExtruded));
276 
277  // Point generator
279 
280  // Whether to flip normals
281  const Switch flipNormals(dict.lookup("flipNormals"));
282 
283  // What to extrude
284  const extrudeSurfaceType mode = extrudeSurfaceTypeNames.read
285  (
286  dict.lookup("constructFrom")
287  );
288 
289  // Any merging of small edges
290  const scalar mergeTol(dict.lookupOrDefault<scalar>("mergeTol", 1e-4));
291 
292  Info<< "Extruding from " << extrudeSurfaceTypeNames[mode]
293  << " using model " << model().type() << endl;
294  if (flipNormals)
295  {
296  Info<< "Flipping normals before extruding" << endl;
297  }
298  if (mergeTol > 0)
299  {
300  Info<< "Collapsing edges < " << mergeTol << " of bounding box" << endl;
301  }
302  else
303  {
304  Info<< "Not collapsing any edges after extrusion" << endl;
305  }
306  Info<< endl;
307 
308 
309  // Generated mesh (one of either)
310  autoPtr<fvMesh> meshFromMesh;
311  autoPtr<polyMesh> meshFromSurface;
312 
313  // Faces on front and back for stitching (in case of mergeFaces)
314  word frontPatchName;
315  labelList frontPatchFaces;
316  word backPatchName;
317  labelList backPatchFaces;
318 
319  // Optional added cells (get written to cellSet)
320  labelHashSet addedCellsSet;
321 
322  if (mode == extrudeSurfaceType::patch || mode == extrudeSurfaceType::mesh)
323  {
324  if (flipNormals && mode == extrudeSurfaceType::mesh)
325  {
327  << "Flipping normals not supported for extrusions from mesh."
328  << exit(FatalError);
329  }
330 
331  fileName sourceCasePath(dict.lookup("sourceCase"));
332  sourceCasePath.expand();
333  fileName sourceRootDir = sourceCasePath.path();
334  fileName sourceCaseDir = sourceCasePath.name();
335  if (Pstream::parRun())
336  {
337  sourceCaseDir =
338  sourceCaseDir
339  /"processor" + Foam::name(Pstream::myProcNo());
340  }
341  wordList sourcePatches(dict.lookup("sourcePatches"));
342 
343  if (sourcePatches.size() == 1)
344  {
345  frontPatchName = sourcePatches[0];
346  }
347 
348  wordList zoneNames(dict.lookupOrDefault("zoneNames", wordList::null()));
349  if (zoneNames.size() == 1)
350  {
351  if (zoneNames[0] == "patchNames")
352  {
353  zoneNames = sourcePatches;
354  }
355  else
356  {
357  zoneNames = wordList(sourcePatches.size(), zoneNames[0]);
358  }
359  }
360  else if (zoneNames.size() && zoneNames.size() != sourcePatches.size())
361  {
363  << "Number of zoneNames "
364  "does not equal the number of sourcePatches"
365  << exit(FatalError);
366  }
367 
368  Info<< "Extruding patches " << sourcePatches
369  << " on mesh " << sourceCasePath << nl
370  << endl;
371 
372  Time runTime
373  (
375  sourceRootDir,
376  sourceCaseDir
377  );
378 
380 
382 
383  const labelList patchZones
384  (
385  zoneNames.size()
386  ? findPatchZones(mesh, zoneNames)
387  : labelList(sourcePatches.size(), -1)
388  );
389 
390  labelList faceCellZones;
391  const labelList patchFaces
392  (
393  findPatchFaces
394  (
395  mesh,
396  patches,
397  sourcePatches,
398  patchZones,
399  faceCellZones
400  )
401  );
402 
403  // Extrusion engine. Either adding to existing mesh or
404  // creating separate mesh.
406 
407  if (mode == extrudeSurfaceType::patch && flipNormals)
408  {
409  // Cheat. Flip patch faces in mesh. This invalidates the
410  // mesh (open cells) but does produce the correct extrusion.
411  polyTopoChange meshMod(mesh);
412  forAll(patchFaces, i)
413  {
414  label patchFacei = patchFaces[i];
415 
416  label patchi = patches.whichPatch(patchFacei);
417  label own = mesh.faceOwner()[patchFacei];
418  label nei = -1;
419  if (patchi == -1)
420  {
421  nei = mesh.faceNeighbour()[patchFacei];
422  }
423 
424  meshMod.modifyFace
425  (
426  mesh.faces()[patchFacei].reverseFace(), // modified face
427  patchFacei, // label of face
428  own, // owner
429  nei, // neighbour
430  true, // face flip
431  patchi // patch for face
432  );
433  }
434 
435  // Change the mesh. without keeping old points.
436  autoPtr<polyTopoChangeMap> map = meshMod.changeMesh(mesh);
437 
438  // Update fields
439  mesh.topoChange(map);
440  }
441 
442 
443  indirectPrimitivePatch extrudePatch
444  (
446  (
447  mesh.faces(),
448  patchFaces
449  ),
450  mesh.points()
451  );
452 
453  // Determine extrudePatch normal
454  pointField extrudePatchPointNormals
455  (
456  PatchTools::pointNormals(mesh, extrudePatch)
457  );
458 
459 
460  // Precalculate mesh edges for pp.edges.
461  const labelList meshEdges
462  (
463  extrudePatch.meshEdges
464  (
465  mesh.edges(),
466  mesh.pointEdges()
467  )
468  );
469 
470  // Global face indices engine
471  const globalIndex globalFaces(mesh.nFaces());
472 
473  // Determine extrudePatch.edgeFaces in global numbering (so across
474  // coupled patches)
475  labelListList edgeGlobalFaces
476  (
478  (
479  mesh,
480  globalFaces,
481  extrudePatch
482  )
483  );
484 
485 
486  // Determine what patches boundary edges need to get extruded into.
487  // This might actually cause edge-connected processors to become
488  // face-connected so might need to introduce new processor boundaries.
489  // Calculates:
490  // - per pp.edge the patch to extrude into
491  // - any additional processor boundaries (patchToNbrProc = map from
492  // new patchID to neighbour processor)
493  // - number of new patches (nPatches)
494 
495  labelList sidePatchID;
496  label nPatches;
497  Map<label> nbrProcToPatch;
498  Map<label> patchToNbrProc;
500  (
501  mesh,
502  globalFaces,
503  edgeGlobalFaces,
504  extrudePatch,
505 
506  sidePatchID,
507  nPatches,
508  nbrProcToPatch,
509  patchToNbrProc
510  );
511 
512 
513  // Add any patches
514 
515  label nAdded = nPatches - mesh.poly().boundary().size();
516  reduce(nAdded, sumOp<label>());
517 
518  Info<< "Adding overall " << nAdded << " processor patches." << endl;
519 
520  if (nAdded > 0)
521  {
522  DynamicList<polyPatch*> newPatches(nPatches);
524  {
525  newPatches.append
526  (
528  (
529  mesh.poly().boundary()
530  ).ptr()
531  );
532  }
533  for
534  (
535  label patchi = mesh.poly().boundary().size();
536  patchi < nPatches;
537  patchi++
538  )
539  {
540  label nbrProci = patchToNbrProc[patchi];
541 
542  Pout<< "Adding patch " << patchi
543  << " between " << Pstream::myProcNo()
544  << " and " << nbrProci
545  << endl;
546 
547  newPatches.append
548  (
550  (
551  0, // size
552  mesh.nFaces(), // start
553  patchi, // index
554  mesh.poly().boundary(),// polyBoundaryMesh
555  Pstream::myProcNo(),// myProcNo
556  nbrProci // neighbProcNo
557  )
558  );
559  }
560 
561  // Add patches. Do no parallel updates.
563  mesh.addFvPatches(newPatches, true);
564  }
565 
566 
567 
568  // Only used for addPatchCellLayer into new mesh
569  labelList exposedPatchID;
570  if (mode == extrudeSurfaceType::patch)
571  {
572  dict.lookup("exposedPatchName") >> backPatchName;
573  exposedPatchID.setSize
574  (
575  extrudePatch.size(),
576  findIndex(patches, backPatchName)
577  );
578  }
579 
580  // Determine points and extrusion
581  pointField layer0Points(extrudePatch.nPoints());
582  pointField displacement(extrudePatch.nPoints());
583  forAll(displacement, pointi)
584  {
585  const vector& patchNormal = extrudePatchPointNormals[pointi];
586 
587  // layer0 point
588  layer0Points[pointi] = model()
589  (
590  extrudePatch.localPoints()[pointi],
591  patchNormal,
592  0
593  );
594  // layerN point
595  point extrudePt = model()
596  (
597  extrudePatch.localPoints()[pointi],
598  patchNormal,
599  model().nLayers()
600  );
601  displacement[pointi] = extrudePt - layer0Points[pointi];
602  }
603 
604 
605  // Check if wedge (has layer0 different from original patch points)
606  // If so move the mesh to starting position.
607  if (gMax(mag(layer0Points-extrudePatch.localPoints())) > small)
608  {
609  Info<< "Moving mesh to layer0 points since differ from original"
610  << " points - this can happen for wedge extrusions." << nl
611  << endl;
612 
613  pointField newPoints(mesh.points());
614  forAll(extrudePatch.meshPoints(), i)
615  {
616  newPoints[extrudePatch.meshPoints()[i]] = layer0Points[i];
617  }
618  mesh.setPoints(newPoints);
619  }
620 
621 
622  // Layers per face
623  labelList nFaceLayers(extrudePatch.size(), model().nLayers());
624 
625  // Layers per point
626  labelList nPointLayers(extrudePatch.nPoints(), model().nLayers());
627 
628  // Displacement for first layer
629  vectorField firstLayerDisp(displacement*model().sumThickness(1));
630 
631  // Expansion ratio not used.
632  scalarField ratio(extrudePatch.nPoints(), 1.0);
633 
634  // Topo change container. Either copy an existing mesh or start
635  // with empty storage (number of patches only needed for checking)
637  (
638  (
640  ? new polyTopoChange(mesh)
641  : new polyTopoChange(patches.size())
642  )
643  );
644 
645  layerExtrude.setRefinement
646  (
647  mesh,
648  globalFaces,
649  edgeGlobalFaces,
650 
651  ratio, // expansion ratio
652  extrudePatch, // patch faces to extrude
653  sidePatchID, // if boundary edge: patch to use
654  exposedPatchID, // if new mesh: patches for exposed faces
655  nFaceLayers,
656  nPointLayers,
657  firstLayerDisp,
658  faceCellZones,
659  meshMod()
660  );
661 
662  // Reset points according to extrusion model
663  forAll(layerExtrude.addedPoints(), pointi)
664  {
665  const labelList& pPoints = layerExtrude.addedPoints()[pointi];
666  forAll(pPoints, pPointi)
667  {
668  label meshPointi = pPoints[pPointi];
669 
670  point modelPt
671  (
672  model()
673  (
674  extrudePatch.localPoints()[pointi],
675  extrudePatchPointNormals[pointi],
676  pPointi+1 // layer
677  )
678  );
679 
680  const_cast<DynamicList<point>&>
681  (
682  meshMod().points()
683  )[meshPointi] = modelPt;
684  }
685  }
686 
687  // Store faces on front and exposed patch (if mode=patch there are
688  // only added faces so cannot used map to old faces)
689  const labelListList& layerFaces = layerExtrude.layerFaces();
690  backPatchFaces.setSize(layerFaces.size());
691  frontPatchFaces.setSize(layerFaces.size());
692  forAll(backPatchFaces, patchFacei)
693  {
694  backPatchFaces[patchFacei] = layerFaces[patchFacei].first();
695  frontPatchFaces[patchFacei] = layerFaces[patchFacei].last();
696  }
697 
698 
699  // Create actual mesh from polyTopoChange container
700  autoPtr<polyTopoChangeMap> map = meshMod().makeMesh
701  (
702  meshFromMesh,
703  IOobject
704  (
705  regionName,
706  runTimeExtruded.constant(),
707  runTimeExtruded,
710  false
711  ),
712  mesh
713  );
714 
715  layerExtrude.updateZones(meshFromMesh());
716 
717  meshFromMesh().topoChange(map);
718 
719  layerExtrude.topoChange
720  (
721  map(),
722  identityMap(extrudePatch.size()),
723  identityMap(extrudePatch.nPoints())
724  );
725 
726  // Calculate face labels for front and back.
727  frontPatchFaces = renumber
728  (
729  map().reverseFaceMap(),
730  frontPatchFaces
731  );
732  backPatchFaces = renumber
733  (
734  map().reverseFaceMap(),
735  backPatchFaces
736  );
737 
738  // Store added cells
740  {
741  const labelListList addedCells
742  (
743  layerExtrude.addedCells
744  (
745  meshFromMesh,
746  layerExtrude.layerFaces()
747  )
748  );
749  forAll(addedCells, facei)
750  {
751  const labelList& aCells = addedCells[facei];
752  forAll(aCells, i)
753  {
754  addedCellsSet.insert(aCells[i]);
755  }
756  }
757  }
758  }
759  else
760  {
761  // Read from surface
762  fileName surfName(dict.lookup("surface"));
763  surfName.expand();
764 
765  Info<< "Extruding surfaceMesh read from file " << surfName << nl
766  << endl;
767 
768  MeshedSurface<face> fMesh(surfName);
769 
770  if (flipNormals)
771  {
772  Info<< "Flipping faces." << nl << endl;
773  faceList& faces = const_cast<faceList&>(fMesh.faces());
774  forAll(faces, i)
775  {
776  faces[i] = fMesh[i].reverseFace();
777  }
778  }
779 
780  Info<< "Extruding surface with :" << nl
781  << " points : " << fMesh.points().size() << nl
782  << " faces : " << fMesh.size() << nl
783  << " normals[0] : " << fMesh.faceNormals()[0]
784  << nl
785  << endl;
786 
787  meshFromSurface.reset
788  (
789  new extrudedMesh
790  (
791  IOobject
792  (
794  runTimeExtruded.constant(),
795  runTimeExtruded
796  ),
797  fMesh,
798  model()
799  )
800  );
801 
802 
803  // Get the faces on front and back
804  frontPatchName = "originalPatch";
805  frontPatchFaces = findPatchFaces
806  (
807  meshFromSurface().boundary(),
808  frontPatchName
809  );
810  backPatchName = "otherSide";
811  backPatchFaces = findPatchFaces
812  (
813  meshFromSurface().boundary(),
814  backPatchName
815  );
816  }
817 
818 
819  polyMesh& mesh =
820  (
821  meshFromMesh.valid()
822  ? meshFromMesh()
823  : meshFromSurface()
824  );
825 
826 
827  const boundBox& bb = mesh.bounds();
828  const vector span = bb.span();
829  const scalar mergeDim = mergeTol * bb.minDim();
830 
831  Info<< "Mesh bounding box : " << bb << nl
832  << " with span : " << span << nl
833  << "Merge distance : " << mergeDim << nl
834  << endl;
835 
836 
837  // Collapse edges
838  // ~~~~~~~~~~~~~~
839 
840  if (mergeDim > 0)
841  {
842  Pout<< "Collapsing edges < " << mergeDim << " ..." << nl << endl;
843 
844  // Edge collapsing engine
845  edgeCollapser collapser(mesh);
846 
847  const edgeList& edges = mesh.edges();
848  const pointField& points = mesh.points();
849 
851  Map<point> collapsePointToLocation(mesh.nPoints());
852 
853  forAll(edges, edgeI)
854  {
855  const edge& e = edges[edgeI];
856 
857  scalar d = e.mag(points);
858 
859  if (d < mergeDim)
860  {
861  Pout<< "Merging edge " << e << " since length " << d
862  << " << " << mergeDim << nl;
863 
864  collapseEdge[edgeI] = true;
865  collapsePointToLocation.set(e[1], points[e[0]]);
866  }
867  }
868 
869  List<pointEdgeCollapse> allPointInfo;
871  labelList pointPriority(mesh.nPoints(), 0);
872 
873  collapser.consistentCollapse
874  (
875  globalPoints,
876  pointPriority,
877  collapsePointToLocation,
878  collapseEdge,
879  allPointInfo
880  );
881 
882  // Topo change container
883  polyTopoChange meshMod(mesh);
884 
885  // Put all modifications into meshMod
886  bool anyChange = collapser.setRefinement(allPointInfo, meshMod);
887  reduce(anyChange, orOp<bool>());
888 
889  if (anyChange)
890  {
891  // Construct new mesh from polyTopoChange.
892  autoPtr<polyTopoChangeMap> map = meshMod.changeMesh(mesh);
893 
894  // Update fields
895  mesh.topoChange(map);
896 
897  // Update stored data
898  updateFaceLabels(map(), frontPatchFaces);
899  updateFaceLabels(map(), backPatchFaces);
900  updateCellSet(map(), addedCellsSet);
901  }
902  }
903 
904 
905  // Change the front and back patch types as required
906  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
907 
908  word frontBackType(word::null);
909 
910  if (isType<extrudeModels::wedge>(model()))
911  {
912  changeFrontBackPatches<wedgePolyPatch>
913  (
914  mesh,
915  frontPatchName,
916  backPatchName
917  );
918  }
919  else if (isType<extrudeModels::plane>(model()))
920  {
921  changeFrontBackPatches<emptyPolyPatch>
922  (
923  mesh,
924  frontPatchName,
925  backPatchName
926  );
927  }
928 
929 
930  // Merging front and back patch faces
931  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
932 
933  Switch mergeFaces(dict.lookup("mergeFaces"));
934  if (mergeFaces)
935  {
937  {
939  << "Cannot stitch front and back of extrusion since"
940  << " in 'mesh' mode (extrusion appended to mesh)."
941  << exit(FatalError);
942  }
943 
944  Info<< "Assuming full 360 degree axisymmetric case;"
945  << " stitching faces on patches "
946  << frontPatchName << " and "
947  << backPatchName << " together ..." << nl << endl;
948 
949  if (frontPatchFaces.size() != backPatchFaces.size())
950  {
952  << "Differing number of faces on front ("
953  << frontPatchFaces.size() << ") and back ("
954  << backPatchFaces.size() << ")"
955  << exit(FatalError);
956  }
957 
958  // Add the perfect interface mesh modifier
959  perfectInterface perfectStitcher
960  (
961  "couple",
962  mesh,
963  word::null, // dummy patch name
964  word::null // dummy patch name
965  );
966 
967  // Topo change container
968  polyTopoChange meshMod(mesh);
969 
970  perfectStitcher.setRefinement
971  (
973  (
975  (
976  mesh.faces(),
977  frontPatchFaces
978  ),
979  mesh.points()
980  ),
982  (
984  (
985  mesh.faces(),
986  backPatchFaces
987  ),
988  mesh.points()
989  ),
990  meshMod
991  );
992 
993  // Construct new mesh from polyTopoChange.
994  autoPtr<polyTopoChangeMap> map = meshMod.changeMesh(mesh);
995 
996  // Update fields
997  mesh.topoChange(map);
998 
999  // Update local data
1000  updateCellSet(map(), addedCellsSet);
1001  }
1002 
1003  // Set the write instance based on the overwrite flag and whether or not a
1004  // mesh is already present
1005  const fileName meshInstanceExtruded =
1007  (
1008  IOobject
1009  (
1011  runTimeExtruded.name(),
1012  runTimeExtruded,
1014  )
1015  );
1016  if (meshInstanceExtruded != fileName::null)
1017  {
1018  if (!overwrite)
1019  {
1020  runTimeExtruded ++;
1021 
1022  mesh.setInstance(runTimeExtruded.name());
1023  }
1024  else
1025  {
1026  mesh.setInstance(meshInstanceExtruded);
1027  }
1028  }
1029  else
1030  {
1031  mesh.setInstance(runTimeExtruded.constant());
1032  }
1033 
1034  Info<< "Writing mesh to " << mesh.relativeObjectPath() << nl << endl;
1035 
1036  if (!mesh.write())
1037  {
1039  << "Failed writing " << mesh.name()
1040  << exit(FatalError);
1041  }
1042 
1043  // Need writing cellSet
1044  label nAdded = returnReduce(addedCellsSet.size(), sumOp<label>());
1045  if (nAdded > 0)
1046  {
1047  cellSet addedCells(mesh, "addedCells", addedCellsSet);
1048  Info<< "Writing added cells to cellSet " << addedCells.name()
1049  << nl << endl;
1050  if (!addedCells.write())
1051  {
1053  << "Failed writing " << addedCells.name()
1054  << exit(FatalError);
1055  }
1056  }
1057 
1058  Info<< "End\n" << endl;
1059 
1060  return 0;
1061 }
1062 
1063 
1064 // ************************************************************************* //
label n
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:78
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:109
void transfer(HashTable< T, Key, Hash > &)
Transfer the contents of the argument table into this table.
Definition: HashTable.C:587
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
fileName relativeObjectPath() const
Return complete relativePath + object name.
Definition: IOobject.H:420
autoPtr< IOobject > clone() const
Clone.
Definition: IOobject.H:280
A List with indirect addressing.
Definition: IndirectList.H:105
void transfer(List< T > &)
Transfer the contents of the argument List into this list.
Definition: List.C:342
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
static const List< word > & null()
Return a null List.
Definition: ListI.H:118
void setSize(const label)
Reset size of List.
Definition: List.C:281
Initialise the NamedEnum HashTable from the static list of names.
Definition: NamedEnum.H:55
A bit-packed bool list.
static tmp< pointField > pointNormals(const polyMesh &, const PrimitivePatch< FaceList, PointField > &)
Return parallel consistent point normals for patches using mesh points.
autoPtr< T > set(const label, const word &key, T *)
Set element to pointer provided and return old element.
label findIndex(const word &key) const
Return the index of the given the key or -1 if not found.
void setSize(const label)
Reset size of PtrList. If extending the PtrList, new entries are.
Definition: PtrList.C:131
A simple wrapper around bool so that it can be read as a word: true/false, on/off,...
Definition: Switch.H:61
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:76
static word controlDictName
The default control dictionary name (normally "controlDict")
Definition: Time.H:208
T & first()
Return the first element of the list.
Definition: UListI.H:114
label size() const
Return the number of elements in the UList.
Definition: UListI.H:311
T & last()
Return the last element of the list.
Definition: UListI.H:128
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:399
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
Adds layers of cells to outside of polyPatch. Can optionally create stand-alone extruded mesh (addToM...
static void calcSidePatch(const polyMesh &, const globalIndex &globalFaces, const labelListList &globalEdgeFaces, const indirectPrimitivePatch &pp, labelList &sidePatchID, label &nPatches, Map< label > &nbrProcToPatch, Map< label > &patchToNbrProc)
Boundary edges get extruded into boundary faces. Determine patch.
static labelListList globalEdgeFaces(const polyMesh &, const globalIndex &globalFaces, const indirectPrimitivePatch &pp)
Per patch edge the pp faces (in global indices) using it. Uses.
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: autoPtr.H:51
bool valid() const
Return true if the autoPtr valid (ie, the pointer is set)
Definition: autoPtrI.H:83
void reset(T *=nullptr)
If object pointer already set, delete object and set to given.
Definition: autoPtrI.H:114
A bounding box defined in terms of the points at its extremities.
Definition: boundBox.H:60
scalar minDim() const
Smallest length/height/width dimension.
Definition: boundBoxI.H:136
vector span() const
The bounding box span (from minimum to maximum)
Definition: boundBoxI.H:118
A collection of cell labels.
Definition: cellSet.H:51
Named list of cell indices representing a sub-set of the mesh.
Definition: cellZone.H:61
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
T lookupOrDefault(const word &, const T &) const
Find and return a T, if not found return the given default.
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:669
Does polyTopoChanges to remove edges. Can remove faces due to edge collapse but can not remove cells ...
Definition: edgeCollapser.H:67
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:61
static autoPtr< extrudeModel > New(const dictionary &)
Select null constructed.
A class for handling file names.
Definition: fileName.H:82
word name() const
Return file name (part beyond last /)
Definition: fileName.C:195
static const fileName null
An empty fileName.
Definition: fileName.H:97
fileName path() const
Return directory path name (part before last /)
Definition: fileName.C:284
const fvBoundaryMesh & boundary() const
Return reference to boundary mesh.
Definition: fvMesh.C:932
void addFvPatches(const List< polyPatch * > &, const bool validBoundary=true)
Add boundary patches. Constructor helper.
Definition: fvMesh.C:758
void removeFvBoundary()
Remove boundary patches. Warning: fvPatchFields hold ref to.
Definition: fvMesh.C:776
const word & name() const
Return reference to name.
Definition: fvMesh.H:447
virtual void topoChange(const polyTopoChangeMap &map)
Update mesh corresponding to the given map.
Definition: fvMesh.C:1335
virtual void setPoints(const pointField &)
Reset the points.
Definition: fvMesh.C:1194
const polyMesh & poly() const
Return reference to polyMesh.
Definition: fvMesh.H:456
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:64
Calculates points shared by more than two processor patches or cyclic patches.
Definition: globalPoints.H:101
label index() const
Return the index of this patch in the boundaryMesh.
const word & name() const
Return name.
Calculates zone number for every face of patch.
Definition: patchZones.H:56
Hack of attachDetach to couple patches when they perfectly align. Does not decouple....
Foam::polyBoundaryMesh.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:78
const cellZoneList & cellZones() const
Return cell zones.
Definition: polyMesh.H:438
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:260
const polyBoundaryMesh & boundary() const
Return boundary mesh.
Definition: polyMesh.H:393
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1308
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1321
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1327
void addPatches(const List< polyPatch * > &, const bool validBoundary=true)
Add boundary patches.
Definition: polyMesh.C:1091
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1295
void removeBoundary()
Remove boundary patches.
Definition: polyMeshClear.C:33
void setInstance(const fileName &)
Set the instance for mesh files.
Definition: polyMeshIO.C:102
static fileName meshDirInstance(const IOobject &io)
Return the instance of the polyMesh directory. Returns.
Definition: polyMesh.C:974
const boundBox & bounds() const
Return mesh bounding box.
Definition: polyMesh.H:399
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:71
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:277
virtual autoPtr< polyPatch > clone(const polyBoundaryMesh &bm) const
Construct and return a clone, resetting the boundary mesh.
Definition: polyPatch.H:212
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
const labelList & reverseCellMap() const
Reverse cell map.
const labelList & reverseFaceMap() const
Reverse face map.
Direct mesh changes based on v1.3 polyTopoChange syntax.
const labelListList & pointEdges() const
const edgeList & edges() const
Return mesh edges. Uses calcEdges.
label nPoints() const
label nEdges() const
label nFaces() const
Neighbour processor patch.
virtual bool write(const bool write=true) const
Write using setting from DB.
A class for handling words, derived from string.
Definition: word.H:63
static const word null
An empty word.
Definition: word.H:78
label collapseEdge(triSurface &surf, const scalar minLen)
Keep collapsing all edges < minLen.
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
int main(int argc, char *argv[])
Definition: financialFoam.C:44
label patchi
const pointField & points
const fvPatchList & patches
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
List< word > wordList
A List of words.
Definition: fileName.H:54
const doubleScalar e
Definition: doubleScalar.H:106
mode_t mode(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return the file mode.
Definition: POSIX.C:461
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
const word & regionName(const solver &region)
Definition: solver.H:218
ListType renumber(const labelUList &oldToNew, const ListType &)
Renumber the values (not the indices) of a list.
messageStream Info
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Type gMax(const UList< Type > &f, const label comm)
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
tmp< DimensionedField< scalar, GeoMesh, Field > > mag(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
error FatalError
labelList identityMap(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
IOdictionary systemDict(const word &dictName, const argList &args, const objectRegistry &ob, const word &regionName=polyMesh::defaultRegion, const fileName &path=fileName::null)
Definition: systemDict.C:93
static const char nl
Definition: Ostream.H:297
wordList patchNames(nPatches)
faceListList boundary(nPatches)
label nPatches
Definition: readKivaGrid.H:396
dictionary dict
const bool overwrite
Definition: setNoOverwrite.H:1
Foam::argList args(argc, argv)