blockMesh.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  blockMesh
26 
27 Description
28  A multi-block mesh generator.
29 
30  Uses the block mesh description found in
31  - \c system/blockMeshDict
32  - \c system/<region>/blockMeshDict
33  - \c constant/polyMesh/blockMeshDict
34  - \c constant/<region>/polyMesh/blockMeshDict
35 
36 Usage
37  \b blockMesh [OPTION]
38 
39  Options:
40  - \par -blockTopology
41  Write the topology as a set of edges in OBJ format.
42 
43  - \par -region <name>
44  Specify an alternative mesh region.
45 
46  - \par -dict <filename>
47  Specify alternative dictionary for the block mesh description.
48 
49 \*---------------------------------------------------------------------------*/
50 
51 #include "argList.H"
52 #include "Time.H"
53 #include "systemDict.H"
54 #include "blockMesh.H"
55 #include "mergePatchPairs.H"
56 #include "polyTopoChange.H"
57 #include "emptyPolyPatch.H"
58 #include "cyclicPolyPatch.H"
59 #include "OFstream.H"
60 
61 using namespace Foam;
62 
63 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
64 
65 int main(int argc, char *argv[])
66 {
68  #include "addDictOption.H"
70  (
71  "blockTopology",
72  "write block edges and centres as .obj files"
73  );
75  (
76  "noClean",
77  "keep the existing files in the polyMesh"
78  );
79 
81  (
82  "Block description\n"
83  "\n"
84  " For a given block, the correspondence between the ordering of\n"
85  " vertex labels and face labels is shown below.\n"
86  " For vertex numbering in the sequence 0 to 7 (block, centre):\n"
87  " faces 0 (f0) and 1 are left and right, respectively;\n"
88  " faces 2 and 3 are front and back; \n"
89  " and faces 4 and 5 are bottom and top::\n"
90  "\n"
91  " 7 ---- 6\n"
92  " f5 |\\ |\\ f3\n"
93  " | | 4 ---- 5 \\\n"
94  " | 3 |--- 2 | \\\n"
95  " | \\| \\| f2\n"
96  " f4 0 ---- 1\n"
97  "\n"
98  " Z f0 ----- f1\n"
99  " | Y\n"
100  " | /\n"
101  " O --- X\n"
102  );
103 
104  #include "addMeshOption.H"
105  #include "addRegionOption.H"
107  #include "setMeshPath.H"
109 
110  const word dictName("blockMeshDict");
111 
112 
113  // Check if the mesh is specified otherwise mesh the default mesh
114  if (!meshPath.empty())
115  {
116  Info<< nl << "Generating mesh " << meshPath << endl;
117  }
118 
120  word regionPath;
121 
122  // Check if the region is specified otherwise mesh the default region
124  {
125  Info<< nl << "Generating mesh for region " << regionName << endl;
126  regionPath = regionName;
127  }
128 
129  if (!args.optionFound("noClean"))
130  {
131  const fileName polyMeshPath
132  (
133  runTime.path()/runTime.constant()
134  /meshPath/regionPath/polyMesh::meshSubDir
135  );
136 
137  if (exists(polyMeshPath))
138  {
139  if (exists(polyMeshPath/dictName))
140  {
141  Info<< "Not deleting polyMesh directory " << nl
142  << " " << polyMeshPath << nl
143  << " because it contains " << dictName << endl;
144  }
145  else
146  {
147  Info<< "Deleting polyMesh directory" << nl
148  << " " << polyMeshPath << endl;
149  rmDir(polyMeshPath);
150  }
151  }
152  }
153 
154  typeIOobject<IOdictionary> meshDictIO
155  (
156  systemDictIO(dictName, args, runTime, regionName, meshPath)
157  );
158 
159  if (!meshDictIO.headerOk())
160  {
162  << "Cannot find file " << meshDictIO.relativeObjectPath()
163  << nl
164  << exit(FatalError);
165  }
166 
167  Info<< "Creating block mesh from\n "
168  << meshDictIO.relativeObjectPath() << endl;
169 
170  IOdictionary meshDict(meshDictIO);
171  blockMesh blocks(meshDict, runTime.constant()/meshPath, regionName);
172 
173 
174  if (args.optionFound("blockTopology"))
175  {
176  // Write mesh as edges.
177  {
178  fileName objMeshFile("blockTopology.obj");
179 
180  OFstream str(runTime.path()/objMeshFile);
181 
182  Info<< nl << "Dumping block structure as Lightwave obj format"
183  << " to " << objMeshFile << endl;
184 
185  blocks.writeTopology(str);
186  }
187 
188  // Write centres of blocks
189  {
190  fileName objCcFile("blockCentres.obj");
191 
192  OFstream str(runTime.path()/objCcFile);
193 
194  Info<< nl << "Dumping block centres as Lightwave obj format"
195  << " to " << objCcFile << endl;
196 
197  const polyMesh& topo = blocks.topology();
198 
199  const pointField& cellCentres = topo.cellCentres();
200 
201  forAll(cellCentres, celli)
202  {
203  // point cc = b.blockShape().centre(b.points());
204  const point& cc = cellCentres[celli];
205 
206  str << "v " << cc.x() << ' ' << cc.y() << ' ' << cc.z() << nl;
207  }
208  }
209 
210  Info<< nl << "end" << endl;
211 
212  return 0;
213  }
214 
215 
216  Info<< nl << "Creating polyMesh from blockMesh" << endl;
217 
218  units::setLength(blocks.scaleFactor());
219 
220  word defaultFacesName = "defaultFaces";
222  polyMesh mesh
223  (
224  IOobject
225  (
226  regionName,
227  runTime.constant(),
228  meshPath,
229  runTime
230  ),
231  clone(blocks.points()), // could we reuse space?
232  blocks.cells(),
233  blocks.patches(),
234  blocks.patchNames(),
235  blocks.patchDicts(),
238  );
239 
240 
241  // Read in a list of dictionaries for the merge patch pairs
242  if (meshDict.found("mergePatchPairs"))
243  {
244  const List<Pair<word>> patchPairNames
245  (
246  meshDict.lookup("mergePatchPairs")
247  );
248 
249  const scalar mergeTolerance =
250  meshDict.lookupOrDefault<scalar>("mergeTolerance", 1e-4);
251 
252  if (patchPairNames.size())
253  {
254  const word oldInstance = mesh.pointsInstance();
255  mergePatchPairs(mesh, patchPairNames, mergeTolerance);
256  mesh.setInstance(oldInstance);
257  }
258  }
259  else
260  {
261  Info<< nl << "No patch pairs to merge" << endl;
262  }
263 
264  label nZones = blocks.numZonedBlocks();
265 
266  if (nZones > 0)
267  {
268  Info<< nl << "Adding cell zones" << endl;
269 
270  // Map from zoneName to cellZone index
271  HashTable<label> zoneMap(nZones);
272 
273  // Cells per zone.
274  List<DynamicList<label>> zoneCells(nZones);
275 
276  // Running cell counter
277  label celli = 0;
278 
279  // Largest zone so far
280  label freeZoneI = 0;
281 
282  forAll(blocks, blockI)
283  {
284  const block& b = blocks[blockI];
285  const List<FixedList<label, 8>> blockCells = b.cells();
286  const word& zoneName = b.zoneName();
287 
288  if (zoneName.size())
289  {
290  HashTable<label>::const_iterator iter = zoneMap.find(zoneName);
291 
292  label zoneI;
293 
294  if (iter == zoneMap.end())
295  {
296  zoneI = freeZoneI++;
297 
298  Info<< " " << zoneI << '\t' << zoneName << endl;
299 
300  zoneMap.insert(zoneName, zoneI);
301  }
302  else
303  {
304  zoneI = iter();
305  }
306 
307  forAll(blockCells, i)
308  {
309  zoneCells[zoneI].append(celli++);
310  }
311  }
312  else
313  {
314  celli += blockCells.size();
315  }
316  }
317 
318 
319  List<cellZone*> cz(zoneMap.size());
320 
321  forAllConstIter(HashTable<label>, zoneMap, iter)
322  {
323  label zoneI = iter();
324 
325  cz[zoneI] = new cellZone
326  (
327  iter.key(),
328  zoneCells[zoneI].shrink(),
329  mesh.cellZones()
330  );
331  }
332 
333  mesh.pointZones().setSize(0);
334  mesh.faceZones().setSize(0);
335  mesh.cellZones().setSize(0);
337  }
338 
339 
340  // Detect any cyclic patches and force re-ordering of the faces
341  {
342  const polyPatchList& patches = mesh.boundary();
343  bool hasCyclic = false;
345  {
346  if (isA<cyclicPolyPatch>(patches[patchi]))
347  {
348  hasCyclic = true;
349  break;
350  }
351  }
352 
353  if (hasCyclic)
354  {
355  Info<< nl << "Detected cyclic patches; ordering boundary faces"
356  << endl;
357  const word oldInstance = mesh.instance();
358  polyTopoChange meshMod(mesh);
359  meshMod.changeMesh(mesh);
360  mesh.setInstance(oldInstance);
361  }
362  }
363 
364 
365  // Ensure the points are written to a sufficient precision
367 
368  Info<< nl << "Writing polyMesh" << endl;
369  mesh.removeFiles();
370  if (!mesh.write())
371  {
373  << "Failed writing polyMesh."
374  << exit(FatalError);
375  }
376 
377 
378  // Write summary
379  {
380  const polyPatchList& patches = mesh.boundary();
381 
382  Info<< "----------------" << nl
383  << "Mesh Information" << nl
384  << "----------------" << nl
385  << " " << "boundingBox: " << boundBox(mesh.points()) << nl
386  << " " << "nPoints: " << mesh.nPoints() << nl
387  << " " << "nCells: " << mesh.nCells() << nl
388  << " " << "nFaces: " << mesh.nFaces() << nl
389  << " " << "nInternalFaces: " << mesh.nInternalFaces() << nl;
390 
391  Info<< "----------------" << nl
392  << "Patches" << nl
393  << "----------------" << nl;
394 
396  {
397  const polyPatch& p = patches[patchi];
398 
399  Info<< " " << "patch " << patchi
400  << " (start: " << p.start()
401  << " size: " << p.size()
402  << ") name: " << p.name()
403  << nl;
404  }
405  }
406 
407  Info<< "\nEnd\n" << endl;
408 
409  return 0;
410 }
411 
412 
413 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:492
void shrink()
Shrink the allocated table to approx. twice number of elements.
Definition: HashTable.C:574
iterator find(const Key &)
Find and return an iterator set at the hashedEntry.
Definition: HashTable.C:167
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:57
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
fileName & instance() const
Return the instance directory, constant, system, <time> etc.
Definition: IOobject.C:352
const word & name() const
Return name.
Definition: IOobject.H:307
static unsigned int defaultPrecision()
Return the default precision.
Definition: IOstream.H:473
static unsigned int highPrecision()
Return a high precision for writing data that is.
Definition: IOstream.C:90
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 size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
Output to file stream.
Definition: OFstream.H:87
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
void setSize(const label)
Reset size of PtrList. If extending the PtrList, new entries are.
Definition: PtrList.C:131
const Cmpt & z() const
Definition: VectorI.H:87
const Cmpt & y() const
Definition: VectorI.H:81
const Cmpt & x() const
Definition: VectorI.H:75
static void addNote(const string &)
Add extra notes for the usage information.
Definition: argList.C:152
static void addBoolOption(const word &opt, const string &usage="")
Add to a bool option to validOptions with usage information.
Definition: argList.C:111
bool optionFound(const word &opt) const
Return true if the named option is found.
Definition: argListI.H:114
bool optionReadIfPresent(const word &opt, T &) const
Read a value from the named option if present.
Definition: argListI.H:255
static void noParallel()
Remove the parallel options.
Definition: argList.C:168
A multi-block mesh generator.
Definition: blockMesh.H:65
Creates a single block of cells from point coordinates, numbers of cells in each direction and an exp...
Definition: block.H:66
A bounding box defined in terms of the points at its extremities.
Definition: boundBox.H:60
Named list of cell indices representing a sub-set of the mesh.
Definition: cellZone.H:61
A class for handling file names.
Definition: fileName.H:82
const fvBoundaryMesh & boundary() const
Return reference to boundary mesh.
Definition: fvMesh.C:932
Class to stitch mesh by merging patch-pairs.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:78
const pointZoneList & pointZones() const
Return point zones.
Definition: polyMesh.H:426
const cellZoneList & cellZones() const
Return cell zones.
Definition: polyMesh.H:438
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:260
const fileName & pointsInstance() const
Return the current instance directory for points.
Definition: polyMesh.C:1006
const faceZoneList & faceZones() const
Return face zones.
Definition: polyMesh.H:432
void removeFiles(const fileName &instanceDir) const
Remove all files from mesh instance.
Definition: polyMesh.C:1502
void addZones(const List< pointZone * > &pz, const List< faceZone * > &fz, const List< cellZone * > &cz)
Add mesh zones.
Definition: polyMesh.C:1129
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1295
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:263
void setInstance(const fileName &)
Set the instance for mesh files.
Definition: polyMeshIO.C:102
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:71
Direct mesh changes based on v1.3 polyTopoChange syntax.
label nInternalFaces() const
const vectorField & cellCentres() const
label nCells() const
label nPoints() const
label nFaces() const
virtual bool write(const bool write=true) const
Write using setting from DB.
Templated form of IOobject providing type information for file reading and header type checking.
Definition: IOobject.H:545
A class for handling words, derived from string.
Definition: word.H:63
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 fvPatchList & patches
volScalarField & b
Definition: createFields.H:27
void setLength(const unitSet &length)
Set the length scale to the given unit set.
Definition: units.C:352
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
const doubleScalar e
Definition: doubleScalar.H:106
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
String typeName(const std::type_info &info)
Return the un-mangled name given the standard type info.
const word & regionName(const solver &region)
Definition: solver.H:218
IOobject systemDictIO(const word &dictName, const argList &args, const objectRegistry &ob, const word &regionName=polyMesh::defaultRegion, const fileName &path=fileName::null)
Definition: systemDict.C:33
bool exists(const fileName &, const bool checkVariants=true, const bool followLink=true)
Does the name exist (as directory or file) in the file system?
Definition: POSIX.C:520
messageStream Info
bool rmDir(const fileName &)
Remove a directory and its contents.
Definition: POSIX.C:1047
T clone(const T &t)
Definition: List.H:55
error FatalError
static const char nl
Definition: Ostream.H:297
word defaultFacesName
Definition: readKivaGrid.H:454
word defaultFacesType
Definition: readKivaGrid.H:455
word meshPath
Definition: setMeshPath.H:1
Foam::argList args(argc, argv)
volScalarField & p