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-2024 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, implicit
79  feature capturing is configured. Explicit feature capturing can
80  alternatively be selected with the '-explicitFeatures' option, when an
81  additional surfaceFeaturesDict file is written for the user to generate the
82  features files with the surfaceFeatures utility. 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 min
87  and max bounds; '-refinementDists' for distance-based refinement; and
88  '-nCellsBetweenLevels' to control the transition between refinement
89  levels. A '-layers' option controls additional layers of cells at specified
90  surfaces. The insidePoint parameter is set to '(0 0 0)' by default but can
91  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 specified by '( (<surface> <level>) (...) )'
121 
122  - \par -refinementBoxes <entry>
123  Refinement boxes specified by '( (<min> <max> <level>) (...) )'
124 
125  - \par -refinementDists <entry>
126  Refinement distance specified by
127  '( (<surface> <dist> <level>) (...) )'
128 
129  - \par -defaultPatch <entry>
130  Name and type of default patch, '(<name> <type>)'
131 
132  - \par -xMinPatch (-xMaxPatch, -yMinPatch, etc...) <entry>
133  Name and type of the xMin (xMax, yMin, etc...) patch,
134  '(<name> <type>)'
135 
136  - \par -clearBoundary,
137  Do not set default patch entries, i.e. xMin, xMax, yMin, etc...
138 
139  - \par -explicitFeatures,
140  Use explicit feature capturing, default is implicit
141 
142  - \par -layers <entry>
143  Number of layers on specified surfaces, e.g. '((car 3) (ground 4))'
144 
145  - \par -firstLayerThickness <value>
146  Specify the thickness of the near wall cells for layer addition
147 
148  - \par -layerExpansionRatio <value>
149  Specify the expansion ratio between layers, default 1.2
150 
151  - \par -cellZones <list>
152  Surfaces that form cellZones, e.g. '(porousZone heatSource)'
153 
154  - \par -rotatingZones <list>
155  Surfaces that form rotatingZones, e.g. '(rotatingZone)'
156 
157  - \par -baffles <list>
158  Surfaces that form baffles, e.g. '(helical)'
159 
160  - \par -insidePoint <point>
161  Point location inside the region of geometry to be meshed
162 
163  - \par -nCellsBetweenLevels <int>
164  Number of cells at successive refinement levels, default 3
165 
166  - \par -inletRegions <list>
167  Inlet regions on an external surface, e.g. '(inletA inletB)'
168 
169  - \par -outletRegions <list>
170  Outlet regions on an external surface, e.g. '(outletA outletB)'
171 
172 \*---------------------------------------------------------------------------*/
173 
174 #include "argList.H"
175 #include "Time.H"
176 #include "meshingSurface.H"
182 #include "boundBox.H"
183 #include "searchableSurface.H"
184 #include "Tuple3.H"
185 
186 using namespace Foam;
187 
188 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
189 
190 void readPatchOption
191 (
192  const argList& args,
193  HashTable<Pair<word>>& opts,
194  const word& name
195 )
196 {
197  if (args.optionFound(name))
198  {
199  opts.insert(name, args.optionRead<Pair<word>>(name));
200  }
201 }
202 
203 
204 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
205 
206 int main(int argc, char *argv[])
207 {
208  argList::usageMin = 32;
209  argList::usageMax = 105;
210 
212  (
213  "Writes blockMeshDict, surfaceFeaturesDict and snappyHexMeshDict "
214  "files from surface geometry files.\n"
215  "For more information, see 'Description' in snappyHexMeshConfig.C "
216  "or run\n\n foamInfo snappyHexMeshConfig"
217  );
218 
219  #include "removeCaseOptions.H"
220 
222  (
223  "surface",
224  "file",
225  "single surface geometry file for meshing"
226  );
227 
229  (
230  "nCells",
231  "cells",
232  "number of cells in each direction, e.g. '(10 20 30)'"
233  );
234 
236  (
237  "bounds",
238  "box",
239  "bounding box of the mesh, e.g. '((-10 -5 0) (10 5 10))'"
240  );
241 
243  (
244  "cylindricalBackground",
245  "generate a cylindrical background mesh aligned with the z-axis"
246  );
247 
249  (
250  "refineBackground",
251  "int",
252  "integer multiplier for the number of cells (>= 1)"
253  );
254 
256  (
257  "refinementLevel",
258  "int",
259  "refinement level used by snappyHexMesh, default 2"
260  );
261 
263  (
264  "surfaceLevels",
265  "entry",
266  "refinement level at specified surfaces, e.g. '((pipe 2) (baffles 1))'"
267  );
268 
270  (
271  "refinementRegions",
272  "entry",
273  "refinement regions specified by '( (<surface> <level>) (...) )'"
274  );
275 
277  (
278  "refinementBoxes",
279  "entry",
280  "refinement boxes specified by '( (<min> <max> <level>) (...) )'"
281  );
282 
284  (
285  "refinementDists",
286  "entry",
287  "refinement distance specified by "
288  "'( (<surface> <dist> <level>) (...) )'"
289  );
290 
292  (
293  "defaultPatch",
294  "entry",
295  "name and type of default patch, '(<name> <type>)'"
296  );
297 
299 
300  forAll(patches, i)
301  {
303  (
304  patches[i] + "Patch",
305  "entry",
306  "patch in the "
307  + patches[i]
308  + " direction, format '(<name> <type>)'"
309  );
310  }
311 
313  (
314  "clearBoundary",
315  "do not set default patch entries, i.e. xMin, xMax, etc"
316  );
317 
319  (
320  "explicitFeatures",
321  "use explicit feature capturing"
322  );
323 
325  (
326  "layers",
327  "entry",
328  "number of layers on specified surfaces, e.g. '((car 3) (ground 4))'"
329  );
330 
332  (
333  "firstLayerThickness",
334  "value",
335  "specify the thickness of the near wall cells for layer addition"
336  );
337 
339  (
340  "layerExpansionRatio",
341  "value",
342  "specify the expansion ratio between layers, default 1.2"
343  );
344 
346  (
347  "cellZones",
348  "list",
349  "surfaces that form cellZones, e.g. '(porousZone heatSource)'"
350  );
351 
353  (
354  "rotatingZones",
355  "list",
356  "surfaces that form rotatingZones, e.g. '(rotatingZone)'"
357  );
358 
360  (
361  "baffles",
362  "list",
363  "surfaces that form baffles, e.g. '(helical)'"
364  );
365 
367  (
368  "insidePoint",
369  "point",
370  "point location inside the region of geometry to be meshed"
371  );
372 
374  (
375  "nCellsBetweenLevels",
376  "int",
377  "number of cells at successive refinement levels, default 3"
378  );
379 
381  (
382  "inletRegions",
383  "list",
384  "inlet regions on an external surface, e.g. '(inletA inletB)'"
385  );
386 
388  (
389  "outletRegions",
390  "list",
391  "outlet regions on an external surface, e.g. '(outletA outletB)'"
392  );
393 
394  #include "setRootCase.H"
395  #include "createTime.H"
396 
397  fileNameList surfaceNames;
398 
399  if (args.optionFound("surface"))
400  {
401  surfaceNames.append(args.optionRead<fileName>("surface"));
402  }
403  else
404  {
405  const fileName surfDir
406  (
407  runTime.constant()/searchableSurface::geometryDir(runTime)
408  );
409 
410  // Reads files, removing "gz" extensions
411  fileNameList files(readDir(surfDir));
412 
413  // Check valid extensions and add the path to the names
414  forAll(files, i)
415  {
416  if (!meshingSurface::isSurfaceExt(files[i]))
417  {
418  continue;
419  }
420 
421  surfaceNames.append(surfDir/files[i]);
422  }
423 
424  // Need to exit if no surface geometry files found
425  if (surfaceNames.empty())
426  {
428  << "No surface geometry files found in "
429  << surfDir << nl
430  << "or provided using the '-surface' option"
431  << exit(FatalError);
432  }
433  }
434 
435  wordList cellZoneNames;
436  if (args.optionFound("cellZones"))
437  {
438  cellZoneNames.append(args.optionReadList<word>("cellZones"));
439  }
440 
441  wordList rotatingZoneNames;
442  if (args.optionFound("rotatingZones"))
443  {
444  rotatingZoneNames.append(args.optionReadList<word>("rotatingZones"));
445  }
446 
447  wordList baffleNames;
448  if (args.optionFound("baffles"))
449  {
450  baffleNames.append(args.optionReadList<word>("baffles"));
451  }
452 
453  boundBox bb;
454  if (args.optionFound("bounds"))
455  {
456  List<vector> bounds(args.optionReadList<vector>("bounds"));
457 
458  if (bounds.size() != 2)
459  {
461  << "Argument to '-bounds'"
462  << " should be of the form '(<min> <max>)'" << nl
463  << "with the <min> and <max> bounds of a bounding box"
464  << "\n\nFound instead the argument: "
465  << bounds
466  << exit(FatalError);
467  }
468 
469  bb = boundBox(bounds[0], bounds[1]);
470  Info<< "Bounding box specified by '-bounds' option: "
471  << bb << endl;
472  }
473 
474  wordList inletRegions;
475  if (args.optionFound("inletRegions"))
476  {
477  inletRegions.append(args.optionReadList<word>("inletRegions"));
478  }
479 
480  wordList outletRegions;
481  if (args.optionFound("outletRegions"))
482  {
483  outletRegions.append(args.optionReadList<word>("outletRegions"));
484  }
485 
486  meshingSurfaceList surfaces
487  (
488  runTime,
489  surfaceNames,
490  cellZoneNames,
491  rotatingZoneNames,
492  baffleNames,
493  bb,
494  inletRegions,
495  outletRegions
496  );
497 
498  const Vector<label> nCells
499  (
501  );
502  const label refineFactor
503  (
504  args.optionLookupOrDefault("refineBackground", 1)
505  );
506 
507  HashTable<Pair<word>> patchOpts(7);
508  patches.append("default");
509  forAll(patches, i)
510  {
511  readPatchOption(args, patchOpts, patches[i] + "Patch");
512  }
513 
514  const bool clearBoundary(args.optionFound("clearBoundary"));
515 
516  if (args.optionFound("cylindricalBackground"))
517  {
518  blockMeshCylindricalConfiguration blockMeshConfig
519  (
520  "blockMeshDict",
521  runTime.system(),
522  runTime,
523  surfaces,
524  nCells,
525  refineFactor,
526  patchOpts,
527  clearBoundary
528  );
529 
530  blockMeshConfig.write();
531  }
532  else
533  {
534  blockMeshCartesianConfiguration blockMeshConfig
535  (
536  "blockMeshDict",
537  runTime.system(),
538  runTime,
539  surfaces,
540  args.optionFound("bounds"),
541  nCells,
542  refineFactor,
543  patchOpts,
544  clearBoundary
545  );
546 
547  blockMeshConfig.write();
548  }
549 
550  // snappyHexMeshDict options
551  const label refinementLevel
552  (
553  args.optionLookupOrDefault<label>("refinementLevel", 2)
554  );
555 
556  List<Tuple2<word, label>> surfaceLevels;
557  if (args.optionFound("surfaceLevels"))
558  {
559  surfaceLevels.append
560  (
561  args.optionReadList<Tuple2<word, label>>("surfaceLevels")
562  );
563  }
564 
566  if (args.optionFound("refinementRegions"))
567  {
568  refinementRegions.append
569  (
570  args.optionReadList<Tuple2<word, label>>("refinementRegions")
571  );
572  }
573 
574  List<Tuple3<vector, vector, label>> refinementBoxes;
575  if (args.optionFound("refinementBoxes"))
576  {
577  refinementBoxes.append
578  (
580  (
581  "refinementBoxes"
582  )
583  );
584  }
585 
586  List<Tuple3<word, scalar, label>> refinementDists;
587  if (args.optionFound("refinementDists"))
588  {
589  refinementDists.append
590  (
592  );
593  }
594 
595  const bool explicitFeatures(args.optionFound("explicitFeatures"));
596 
597  List<Tuple2<word, label>> layers;
598  if (args.optionFound("layers"))
599  {
600  layers.append
601  (
603  );
604  }
605 
606  const scalar firstLayerThickness
607  (
608  args.optionLookupOrDefault<scalar>("firstLayerThickness", 0)
609  );
610 
611  const scalar layerExpansionRatio
612  (
613  args.optionLookupOrDefault<scalar>("layerExpansionRatio", 1.2)
614  );
615 
616  const point insidePoint
617  (
619  );
620 
621  const label nCellsBetweenLevels
622  (
623  args.optionLookupOrDefault<label>("nCellsBetweenLevels", 3)
624  );
625 
626  if (explicitFeatures)
627  {
628  surfaceFeaturesConfiguration surfaceFeaturesConfig
629  (
630  "surfaceFeaturesDict",
631  runTime.system(),
632  runTime,
633  surfaces
634  );
635 
636  surfaceFeaturesConfig.write();
637  }
638 
639  snappyHexMeshConfiguration snappyConfig
640  (
641  "snappyHexMeshDict",
642  runTime.system(),
643  runTime,
644  surfaces,
645  refinementLevel,
646  surfaceLevels,
648  refinementBoxes,
649  refinementDists,
650  explicitFeatures,
651  layers,
652  firstLayerThickness,
653  layerExpansionRatio,
654  insidePoint,
655  nCellsBetweenLevels
656  );
657 
658  snappyConfig.write();
659 
660  meshQualityConfiguration meshQualityConfig
661  (
662  "meshQualityDict",
663  runTime.system(),
664  runTime
665  );
666 
667  meshQualityConfig.write();
668 
669  Info<< "\nEnd\n" << endl;
670 
671  return 0;
672 }
673 
674 
675 // ************************************************************************* //
#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:66
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:118
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
Writes a meshQualityDict file which is included from the snappyHexMeshDict file.
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:334
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:257
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:266
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)