snappyHexMeshConfig.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) 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  snappyHexMeshConfig
26 
27 Description
28  Preconfigures blockMeshDict, surfaceFeaturesDict and snappyHexMeshDict
29  files based on the case surface geometry files.
30 
31  Starting from a standard OpenFOAM case, this utility locates surface
32  geometry files, e.g. OBJ, STL format, in the constant/geometry directory.
33  It writes out the configuration files for mesh generation with
34  snappyHexMesh based on assumptions which can be overridden by options on
35  the command line.
36 
37  The utility processes the surface geometry files, attempting to anticipate
38  their intended purpose, trying in particular to recognise whether the
39  domain represents an external or internal flow. If there is a surface
40  which is closed, and is either single or surrounds all other surfaces,
41  then it is assumed that it forms the external boundary of an internal
42  flow. This assumption is overridden if the bounds of the background mesh
43  are specified using the '-bounds' option and they are more than 50% larger
44  than the surface bounds.
45 
46  Surfaces which form boundaries of the domain may contain named regions
47  that are intended to become patches in the final mesh. Any surface region
48  whose name begins with 'inlet' or 'outlet' will become a patch of the same
49  name in the final mesh. On an external surface (for an internal flow),
50  regions can be identified as inlets and outlets using the '-inletRegions'
51  and '-outletRegions' options, respectively. When either option specifies a
52  single region, the resulting patch name will be specifically 'inlet' or
53  'outlet', respectively. Surfaces which are contained within the domain,
54  which do not surround or intersect other surfaces, are assumed by default
55  to be wall patches. Any closed surface which surrounds another (but not an
56  external surface) is used to form a cellZone within the mesh. Any surface
57  can be specifically identified as a cellZone with the '-cellZones' option,
58  with the additional '-baffles' and '-rotatingZones' options available to
59  assign a surface to a more specific use.
60 
61  The background mesh for snappyHexMesh is a single block generated by
62  blockMesh, configured using a blockMeshDict file. The block bounds are
63  automatically calculated, but can be overridden by the '-bounds'
64  option. The number of cells is calculated to produce a fairly small
65  prototype mesh. The cell density can be overridden by the '-nCells' option
66  or can be scaled up by an integer factor using the '-refineBackground'
67  option. When the background mesh is required to form patches in the final
68  mesh, e.g. for an external flow, the user can specify the names and types
69  of the patches corresponding to the six block faces using options such as
70  '-xMinPatch', '-xMaxPatch', etc. The name and type of the default patch,
71  formed from block faces which are not configured, can also be specified
72  with the '-defaultPatch' option. The utility provides placeholder entries
73  for all block faces unless the '-clearBoundary' option is used. A special
74  '-cylindricalBackground' option generates a cylindrical background mesh,
75  oriented along the z-axis along x = y = 0.
76 
77  The snappyHexMesh configuration is generated automatically, applying a set
78  of defaults to the main configuration parameters. By default, explicit
79  feature capturing is configured, for which a surfaceFeaturesDict file is
80  written for the user to generate the features files with the
81  surfaceFeatures utility. Implicit feature capturing can alternatively be
82  selected with the '-implicitFeatures' option. Refinement levels can be
83  controlled with a range of options including: '-refinementLevel' for the
84  baseline refinement level; '-refinementSurfaces' for levels on specific
85  surfaces; '-refinementRegions' for levels inside specific surfaces;
86  '-refinementBoxes' for quick, box-shaped refinement regions specified by
87  min and max bounds; '-refinementDists' for distance-based refinement; and
88  '-nCellsBetweenLevels' to control the transition between refinement
89  levels. A '-layers' option specifies additional layers of cells at wall
90  boundaries. The insidePoint parameter is set to '(0 0 0)' by default but
91  can be overridden using the '-insidePoint' option.
92 
93 Usage
94  \b snappyHexMeshConfig [OPTIONS]
95 
96  Options:
97 
98  - \par -surface <file>
99  Single surface geometry file for meshing
100 
101  - \par -nCells <cells>
102  Number of cells in each direction, e.g. '(10 20 30)'
103 
104  - \par -bounds <box>
105  Bounding box of the mesh, e.g. '((-10 -5 0) (10 5 10))'
106 
107  - \par -cylindricalBackground
108  Generate a cylindrical background mesh aligned with the z-axis
109 
110  - \par -refineBackground <int>
111  Integer multiplier for the number of cells (>= 1)
112 
113  - \par -refinementLevel <int>
114  Refinement level used by snappyHexMesh, default 2
115 
116  - \par -surfaceLevels <entry>
117  Refinement level at specified surfaces, e.g. '((pipe 2) (baffles 1))'
118 
119  - \par -refinementRegions <entry>
120  Refinement regions specfied by '( (<surface> <level>) (...) )'
121 
122  - \par -refinementBoxes <entry>
123  Refinement boxes specfied by '( (<min> <max> <level>) (...) )'
124 
125  - \par -refinementDists <entry>
126  Refinement distance specified by '( (<surface> <dist> <level>) (...) )'
127 
128  - \par -defaultPatch <entry>
129  Name and type of default patch, '(<name> <type>)'
130 
131  - \par -xMinPatch (-xMaxPatch, -yMinPatch, etc...) <entry>
132  Name and type of the xMin (xMax, yMin, etc...) patch, '(<name> <type>)'
133 
134  - \par -clearBoundary,
135  Do not set default patch entries, i.e. xMin, xMax, yMin, etc...
136 
137  - \par -implicitFeatures,
138  Use implicit feature capturing
139 
140  - \par -layers <int>
141  Specify <int> surface layers at wall boundaries, default 0
142 
143  - \par -cellZones <list>
144  Surfaces that form cellZones, e.g. '(porousZone heatSource)'
145 
146  - \par -rotatingZones <list>
147  Surfaces that form rotatingZones, e.g. '(rotatingZone)'
148 
149  - \par -baffles <list>
150  Surfaces that form baffles, e.g. '(helical)'
151 
152  - \par -insidePoint <point>
153  Point location inside the region of geometry to be meshed
154 
155  - \par -nCellsBetweenLevels <int>
156  Number of cells at successive refinement levels, default 3
157 
158  - \par -inletRegions <list>
159  Inlet regions on an external surface, e.g. '(inletA inletB)'
160 
161  - \par -outletRegions <list>
162  Outlet regions on an external surface, e.g. '(outletA outletB)'
163 
164 \*---------------------------------------------------------------------------*/
165 
166 #include "argList.H"
167 #include "Time.H"
168 #include "meshingSurface.H"
173 #include "boundBox.H"
174 #include "searchableSurface.H"
175 #include "Tuple3.H"
176 
177 using namespace Foam;
178 
179 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
180 
181 void readPatchOption
182 (
183  const argList& args,
184  HashTable<Pair<word>>& opts,
185  const word& name
186 )
187 {
188  if (args.optionFound(name))
189  {
190  opts.insert(name, args.optionRead<Pair<word>>(name));
191  }
192 }
193 
194 
195 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
196 
197 int main(int argc, char *argv[])
198 {
199  argList::usageMin = 30;
200  argList::usageMax = 105;
201 
203  (
204  "Writes blockMeshDict, surfaceFeaturesDict and snappyHexMeshDict "
205  "files from surface geometry files.\n"
206  "For more information, see 'Description' in snappyHexMeshConfig.C "
207  "or run\n\n foamInfo snappyHexMeshConfig"
208  );
209 
210  #include "removeCaseOptions.H"
211 
213  (
214  "surface",
215  "file",
216  "single surface geometry file for meshing"
217  );
218 
220  (
221  "nCells",
222  "cells",
223  "number of cells in each direction, e.g. '(10 20 30)'"
224  );
225 
227  (
228  "bounds",
229  "box",
230  "bounding box of the mesh, e.g. '((-10 -5 0) (10 5 10))'"
231  );
232 
234  (
235  "cylindricalBackground",
236  "generate a cylindrical background mesh aligned with the z-axis"
237  );
238 
240  (
241  "refineBackground",
242  "int",
243  "integer multiplier for the number of cells (>= 1)"
244  );
245 
247  (
248  "refinementLevel",
249  "int",
250  "refinement level used by snappyHexMesh, default 2"
251  );
252 
254  (
255  "surfaceLevels",
256  "entry",
257  "refinement level at specified surfaces, e.g. '((pipe 2) (baffles 1))'"
258  );
259 
261  (
262  "refinementRegions",
263  "entry",
264  "refinement regions specfied by '( (<surface> <level>) (...) )'"
265  );
266 
268  (
269  "refinementBoxes",
270  "entry",
271  "refinement boxes specfied by '( (<min> <max> <level>) (...) )'"
272  );
273 
275  (
276  "refinementDists",
277  "entry",
278  "refinement distance specified by "
279  "'( (<surface> <dist> <level>) (...) )'"
280  );
281 
283  (
284  "defaultPatch",
285  "entry",
286  "name and type of default patch, '(<name> <type>)'"
287  );
288 
290 
291  forAll(patches, i)
292  {
294  (
295  patches[i] + "Patch",
296  "entry",
297  "patch in the "
298  + patches[i]
299  + " direction, format '(<name> <type>)'"
300  );
301  }
302 
304  (
305  "clearBoundary",
306  "do not set default patch entries, i.e. xMin, xMax, etc"
307  );
308 
310  (
311  "implicitFeatures",
312  "use implicit feature capturing"
313  );
314 
316  (
317  "layers",
318  "int",
319  "specify <int> surface layers at wall boundaries, default 0"
320  );
321 
323  (
324  "cellZones",
325  "list",
326  "surfaces that form cellZones, e.g. '(porousZone heatSource)'"
327  );
328 
330  (
331  "rotatingZones",
332  "list",
333  "surfaces that form rotatingZones, e.g. '(rotatingZone)'"
334  );
335 
337  (
338  "baffles",
339  "list",
340  "surfaces that form baffles, e.g. '(helical)'"
341  );
342 
344  (
345  "insidePoint",
346  "point",
347  "point location inside the region of geometry to be meshed"
348  );
349 
351  (
352  "nCellsBetweenLevels",
353  "int",
354  "number of cells at successive refinement levels, default 3"
355  );
356 
358  (
359  "inletRegions",
360  "list",
361  "inlet regions on an external surface, e.g. '(inletA inletB)'"
362  );
363 
365  (
366  "outletRegions",
367  "list",
368  "outlet regions on an external surface, e.g. '(outletA outletB)'"
369  );
370 
371  #include "setRootCase.H"
372  #include "createTime.H"
373 
374  fileNameList surfaceNames;
375 
376  if (args.optionFound("surface"))
377  {
378  surfaceNames.append(args.optionRead<fileName>("surface"));
379  }
380  else
381  {
382  const fileName surfDir
383  (
384  runTime.constant()/searchableSurface::geometryDir(runTime)
385  );
386 
387  // Reads files, removing "gz" extensions
388  fileNameList files(readDir(surfDir));
389 
390  // Check valid extensions and add the path to the names
391  forAll(files, i)
392  {
393  if (!meshingSurface::isSurfaceExt(files[i]))
394  {
395  continue;
396  }
397 
398  surfaceNames.append(surfDir/files[i]);
399  }
400 
401  // Need to exit if no surface geometry files found
402  if (surfaceNames.empty())
403  {
405  << "No surface geometry files found in "
406  << surfDir << nl
407  << "or provided using the '-surface' option"
408  << exit(FatalError);
409  }
410  }
411 
412  wordList cellZoneNames;
413  if (args.optionFound("cellZones"))
414  {
415  cellZoneNames.append(args.optionReadList<word>("cellZones"));
416  }
417 
418  wordList rotatingZoneNames;
419  if (args.optionFound("rotatingZones"))
420  {
421  rotatingZoneNames.append(args.optionReadList<word>("rotatingZones"));
422  }
423 
424  wordList baffleNames;
425  if (args.optionFound("baffles"))
426  {
427  baffleNames.append(args.optionReadList<word>("baffles"));
428  }
429 
430  boundBox bb;
431  if (args.optionFound("bounds"))
432  {
433  List<vector> bounds(args.optionReadList<vector>("bounds"));
434 
435  if (bounds.size() != 2)
436  {
438  << "Argument to '-bounds'"
439  << " should be of the form '(<min> <max>)'" << nl
440  << "with the <min> and <max> bounds of a bounding box"
441  << "\n\nFound instead the argument: "
442  << bounds
443  << exit(FatalError);
444  }
445 
446  bb = boundBox(bounds[0], bounds[1]);
447  Info<< "Bounding box specified by '-bounds' option: "
448  << bb << endl;
449  }
450 
451  wordList inletRegions;
452  if (args.optionFound("inletRegions"))
453  {
454  inletRegions.append(args.optionReadList<word>("inletRegions"));
455  }
456 
457  wordList outletRegions;
458  if (args.optionFound("outletRegions"))
459  {
460  outletRegions.append(args.optionReadList<word>("outletRegions"));
461  }
462 
463  meshingSurfaceList surfaces
464  (
465  runTime,
466  surfaceNames,
467  cellZoneNames,
468  rotatingZoneNames,
469  baffleNames,
470  bb,
471  inletRegions,
472  outletRegions
473  );
474 
475  const Vector<label> nCells
476  (
478  );
479  const label refineFactor
480  (
481  args.optionLookupOrDefault("refineBackground", 1)
482  );
483 
484  HashTable<Pair<word>> patchOpts(7);
485  patches.append("defaultPatch");
486  forAll(patches, i)
487  {
488  readPatchOption(args, patchOpts, patches[i] + "Patch");
489  }
490 
491  const bool clearBoundary(args.optionFound("clearBoundary"));
492 
493  if (args.optionFound("cylindricalBackground"))
494  {
495  blockMeshCylindricalConfiguration blockMeshConfig
496  (
497  "blockMeshDict",
498  runTime.system(),
499  runTime,
500  surfaces,
501  nCells,
502  refineFactor,
503  patchOpts,
504  clearBoundary
505  );
506 
507  blockMeshConfig.write();
508  }
509  else
510  {
511  blockMeshCartesianConfiguration blockMeshConfig
512  (
513  "blockMeshDict",
514  runTime.system(),
515  runTime,
516  surfaces,
517  nCells,
518  refineFactor,
519  patchOpts,
520  clearBoundary
521  );
522 
523  blockMeshConfig.write();
524  }
525 
526  // snappyHexMeshDict options
527  const label refinementLevel
528  (
529  args.optionLookupOrDefault<label>("refinementLevel", 2)
530  );
531 
532  List<Tuple2<word, label>> surfaceLevels;
533  if (args.optionFound("surfaceLevels"))
534  {
535  surfaceLevels.append
536  (
537  args.optionReadList<Tuple2<word, label>>("surfaceLevels")
538  );
539  }
540 
542  if (args.optionFound("refinementRegions"))
543  {
544  refinementRegions.append
545  (
546  args.optionReadList<Tuple2<word, label>>("refinementRegions")
547  );
548  }
549 
550  List<Tuple3<vector, vector, label>> refinementBoxes;
551  if (args.optionFound("refinementBoxes"))
552  {
553  refinementBoxes.append
554  (
556  (
557  "refinementBoxes"
558  )
559  );
560  }
561 
562  List<Tuple3<word, scalar, label>> refinementDists;
563  if (args.optionFound("refinementDists"))
564  {
565  refinementDists.append
566  (
568  );
569  }
570 
571  const bool implicitFeatures(args.optionFound("implicitFeatures"));
572 
573  const label layers(args.optionLookupOrDefault<label>("layers", 0));
574 
575  const point insidePoint
576  (
578  );
579 
580  const label nCellsBetweenLevels
581  (
582  args.optionLookupOrDefault<label>("nCellsBetweenLevels", 3)
583  );
584 
585  surfaceFeaturesConfiguration surfaceFeaturesConfig
586  (
587  "surfaceFeaturesDict",
588  runTime.system(),
589  runTime,
590  surfaces
591  );
592 
593  surfaceFeaturesConfig.write();
594 
595  snappyHexMeshConfiguration snappyConfig
596  (
597  "snappyHexMeshDict",
598  runTime.system(),
599  runTime,
600  surfaces,
601  refinementLevel,
602  surfaceLevels,
604  refinementBoxes,
605  refinementDists,
606  implicitFeatures,
607  layers,
608  insidePoint,
609  nCellsBetweenLevels
610  );
611 
612  snappyConfig.write();
613 
614  Info<< "\nEnd\n" << endl;
615 
616  return 0;
617 }
618 
619 
620 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
An STL-conforming hash table.
Definition: HashTable.H:127
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:178
void append(T *)
Append an element at the end of the list.
Definition: PtrListI.H:39
A 2-tuple for storing two objects of different types.
Definition: Tuple2.H:63
A 3-tuple for storing three objects of different types.
Definition: Tuple3.H:60
bool empty() const
Return true if the UList is empty (ie, size() is zero)
Definition: UListI.H:325
static const Form zero
Definition: VectorSpace.H:113
Extract command arguments and options from the supplied argc and argv parameters.
Definition: argList.H:103
static void addOption(const word &opt, const string &param="", const string &usage="")
Add to an option to validOptions with usage information.
Definition: argList.C:128
static void addNote(const string &)
Add extra notes for the usage information.
Definition: argList.C:159
T optionRead(const word &opt) const
Read a value from the named option.
Definition: argListI.H:193
static void addBoolOption(const word &opt, const string &usage="")
Add to a bool option to validOptions with usage information.
Definition: argList.C:118
bool optionFound(const word &opt) const
Return true if the named option is found.
Definition: argListI.H:114
static string::size_type usageMin
Min offset for displaying usage (default: 20)
Definition: argList.H:168
List< T > optionReadList(const word &opt) const
Read a List of values from the named option.
Definition: argList.H:316
static string::size_type usageMax
Max screen width for displaying usage (default: 80)
Definition: argList.H:171
T optionLookupOrDefault(const word &opt, const T &deflt) const
Read a value from the named option if present.
Definition: argListI.H:243
From a set of input surface geometry files and a set of configuration parameters, writes out a blockM...
static const List< word > patches
Default patch names for the background mesh.
From a set of input surface geometry files and a set of configuration parameters, writes out a blockM...
A bounding box defined in terms of the points at its extremities.
Definition: boundBox.H:59
A class for handling file names.
Definition: fileName.H:82
List of meshingSurfaces which stores the overall bounding box of all the meshingSurfaces.
static bool isSurfaceExt(const fileName &file)
Encapsulates queries for volume refinement ('refine all cells within shell').
static const word & geometryDir()
Return the geometry directory name.
From a set of input surface geometry files and some configuration parameters, writes out a snappyHexM...
From a set of input surface geometry files and some configuration parameters, writes out a surfacesFe...
A class for handling words, derived from string.
Definition: word.H:62
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
int main(int argc, char *argv[])
Definition: financialFoam.C:44
const fvPatchList & patches
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
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:251
word name(const bool)
Return a word representation of a bool.
Definition: boolIO.C:39
messageStream Info
error FatalError
static const char nl
Definition: Ostream.H:260
fileNameList readDir(const fileName &, const fileType=fileType::file, const bool filterVariants=true, const bool followLink=true)
Read a directory and return the entries as a string list.
Definition: POSIX.C:662
Foam::argList args(argc, argv)