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