OpenFOAM® v3.0+: New Meshing Functionality
snappyHexMesh: close-proximity feature detection
An important feature of snappyHexMesh is to be able to specify regions of higher refinement in small gaps and between close features. Identifying these regions manually for highly complex surfaces with large length scale variations this might involve a lot of painstaking interaction.
This release adds the ability to detect and refine regions with close features automatically, e.g. for small pipes and gaps.
The detection algorithm works in two passes: it is a surface-only based algorithm when the mesh resolution is too low and switches to a mesh based one once there is enough mesh resolution. The surface-only algorithm works on a triangulated surface only (triSurfaceMesh) and detects triangle centres close to opposing surfaces. This detection pass enables starting snappyHexMesh from a single cell.
Usage is as follows:
planarAngle 30;
refinementRegions
{
ref1
{
mode inside;
levels ((10000 0)); // Dummy base-level refinement
// If cells
// - are inside geometry ref1
// - have level 0..9
// - and are in a gap < 4 cell sizes across
// refine them
gapLevel (4 0 10);
// Optional limiting of gap detection based on the
// local surface normal (of the nearest surface).
// The default is mixed, i.e.
// ignore the normal and detect gaps irrespective
// whether they are inside or outside of the geomtry.
// - options: inside, mixed, outside
gapMode inside;
}
}
The specification is enabled by using the gapLevel keyword in a refinementRegion (in the refinementRegions section in the snappyHexMeshDict dictionary) and consists of three integers:
- the number of cells in the gap
- minimum cell level at which to apply the detection and refinement, and
- maximum cell level at which to apply the detection and refinement
The minimum and maximum cell levels select the set of cells to operate on, the number of cells in the gap determines for this set of cells how large a gap is detected. Optionally the gapLevel can be overridden on a per-surface basis in the refinementSurfaces section. This will override all three settings but can never extend the set of cells, only limit it.
snappyHexMesh: limited region-based refinement
The refinement, i.e. edge-based, surface-based or volume-based, can now be limited to geometric regions using the limitRegions section. This syntax is equivalent to the refinementRegions level specification and gives an upper limit for the refinement level inside any region.
Usage:
{
...
}
limitRegions
{
wake.stl
{
// Limit refinement outside the geometry to max level 4
mode outside;
levels ((1e10 4));
}
}
- Example
- $FOAM_TUTORIALS/mesh/snappyHexMesh/gap_detection
snappyHexMesh: face zone layer insertion
snappyHexMesh can add layers to any existing patch, irrespective of whether the patch was present in the initial mesh or added during meshing.
This functionality has been extended to allow layer addition to face zones by internally converting the face zone into baffles on two separate patches, named <faceZone> and <faceZone>_slave.
snappyHexMesh: location(s) in mesh
The process to define faceZones and cellZones in cases with bordering geometries has been extended. Firstly cellZones can now be assigned purely by walking across connected regions and are no longer related to a particular geometry. In other words they behave similar to locationInMesh, which is determined by walking all visible parts of the mesh. Secondly, faceZones are now automatically generated from each combination of cellZones. Faces that have neighbours in different cellZones will be allocated into a generated faceZone. The new behaviour is controlled through the locationsInMesh, locationsOutsideMesh and faceZoneControls entries:
{
// (Optional) points that should not be reachable from the
// location(s)InMesh. Meshing will abort if with an error message.
locationsOutsideMesh ((100 100 100));
// Points, one per region, and an optional name of a cellZone. "none" is
// the special name for the unzoned mesh region. Any face between different
// regions get added to a faceZone with name
// <cellZoneA>_to_<cellZoneB> where A is the lowest numbered
// cellZone.
locationsInMesh
(
((-0.09 0.001 -0.049) leftSolid)
((0.01 0.0299 0.01) none)
);
// (Optional) per synthesised faceZone, the type of baffles
faceZoneControls
{
leftSolid_to_none
{
// (Optional) specification of patch type (default is wall). No
// constraint types (cyclic, symmetry) etc. are allowed.
patchInfo
{
type patch;
inGroups (patchPatches);
}
faceType baffle;
}
}
}
snappyHexMesh: refinement region updates
In earlier releases of OpenFOAM the refinementRegions operated on a per-surface basis. This has been extended to include a per-region basis, enabled by the new subTriSurfaceMesh geometry type. The new type performs an on-the-fly subsetting (based on a set of regions) of a previously defined triSurfaceMesh. This new geometry can now be used as any other geometry, i.e. both as a refinement-surface or -region.
Usage is as follows:
{
complex_surface.stl
{
type triSurfaceMesh;
}
new_region
{
type subTriSurfaceMesh;
patches ("solid1");
}
}
- Source code
- $FOAM_SRC/meshTools/searchableSurface/subTriSurfaceMesh.H
snappyHexMesh: new analytical shapes
The set of analytical shapes to define primitive parts has been extended to include a new searchableCone: an optionally hollow, truncated cone. The specification is similar to the existing searchableCylinder:
{
cone
{
type searchableCone;
point1 (0 0 0);
radius1 1.0;
innerRadius1 0.5;
point2 (10 0 0);
radius1 2.0;
innerRadius1 1.5;
}
}
Setting both radii equal produces a cylinder shape.
The second new shape is a searchableRotatedBox: a box defined via minimum and maximum co-ordinates, rotated by co-ordinate system at the box centroid:
{
boxRotated
{
type searchableRotatedBox;
span (1 1 1);
origin (0.5 0.5 0.5);
e1 (1 1 0);
e3 (0 0 1);
}
}
- Source code
- $FOAM_SRC/meshTools/searchableSurface
snappyHexMesh: refinement at coarse/fine intersections
The surface refinement level is currently cached by snappyHexMesh on a per-input-triangle basis by looking at the refinement level that each triangle centre would receive. This results in all cells that intersect the same surface triangle being assigned the same refinement level. For large triangles spanning multiple volume refinement shells, e.g. outside box of a wind tunnel simulation, this can result in sub-optimal performance.
In this version the logic has been updated to
- detect triangles where points and triangle centre would get a different refinement level.
- specifically handle these triangles during actual refinement and look up the needed refinement level from the actual intersection position.
This combines the performance of caching of the wanted refinement level for most of the triangles with the accurate refinement from using the actual intersection. On most surfaces the number of triangles which gets tested will be a small fraction of the overall number of triangles. snappyHexMesh will now display during startup the number of uncached triangles.
The same logic applies to non-triangle refinement surfaces, e.g.searchableBox, searchableSphere etc.. These will be refined according to actual intersection location. This means that the surface refinement level phase will already refine the surface up to the wanted shell level whereas before the wanted refinement level was only reached in the follow-on shell refinement phase. The effect is that now on curved surfaces, e.g.searchableSphere, the mesh that is kept better represents the actual geometry (if the refinement was due to refinement shells).
snappyHexMesh: volume smoothing
The snappyHexMesh procedure introduces uses a cell-splitting method to create finer cells. At the interface between coarse and fine cells this produces a non-orthogonality of around 30 degrees for an initial hex cell. This non-orthogonality can be improved by smoothing the mesh at these interfaces.
In this version, the points on faces where the refinement level changes can be smoothed. This new behaviour is switched off by default but can be enabled with the new nSmoothInternal setting in the snapControls section.
Usage:
{
..
// Number of patch smoothing iterations before finding correspondence
// to surface
nSmoothPatch 3;
// Number of smoothing of internal points on refinement interfaces
nSmoothInternal $nSmoothPatch;
}
In the current implementation the value of nSmoothInternal can never be larger than the number of patch smoothing iterations nSmoothPatch.
snappyHexMesh: splitting of boundary faces
The default behaviour of snappyHexMesh is to try to align existing mesh edges to features. This sometimes causes faces which are concave, which usually appear as non-orthogonality of the extruded mesh. This will limit the amount of layer coverage.
To avoid this scenario, new optional settings enable splitting of faces along a diagonal if the operation results in a mesh edge which better conforms to the feature.
The behaviour is controlled by the settings:
{
// When to run face splitting (never at first iteration, always
// at last iteration). Is interval. Default -1 (disabled)
// Recommendation: set to half the number of feature snap iterations
nFaceSplitInterval 5;
}
addLayersControls
{
// Do not extrude around sharp edge if not both faces are extruded.
// Default is 0.5*featureAngle. Set to -180 always attempt extrusion
layerTerminationAngle -180;
// Optional: do not extrude any point where
// (false) : all surrounding faces are not fully extruded
// (true) : all surrounding points are not extruded
// Default is false.
detectExtrusionIsland true;
}
snappyHexMesh: mesh motion for layer addition
The main phase of the layer addition process is the shrinking of the existing mesh to make space for the layers. This process is now run-time selectable, using the optional meshShrinker parameter. The default is a medial-axis algorithm, but any of the existing displacement motion solvers can be used:
{
// Select the solver-based mesh shrinking method
meshShrinker displacementMotionSolver;
// Select the Laplacian method
solver displacementLaplacian;
// Settings for the Laplacian method
displacementLaplacianCoeffs
{
//- Increase diffusivity close to all walls
diffusivity quadratic inverseDistance 1(wall);
}
}
Note that most displacement motion solvers might require additional entries in fvSchemes, fvSolution.
- Example
- $FOAM_TUTORIALS/heatTransfer/buoyantBoussinesqSimpleFoam/iglooWithFridges
subsetMesh: extended functionality
The subsetMesh utility can be used to extract cellSets from an existing mesh. This extraction can cause internal faces to be exposed, which are subsequently assigned to a new faceSet called ‘oldInternalFaces’, or to an existing patch by the -patch option.
This functionality has been extended to assign the exposed faces to the topologically nearest patch from a supplied set, including wildcards, with the new option -patches. A typical use might be to remove some borderline cells that checkMesh has picked up.
Usage:
- Source code
- $FOAM_APP/utilities/mesh/manipulation/subsetMesh
checkMesh: export bad quality cells
In order to visualise problematic regions, the checkMesh application has been extended with a -writeSets option which will parallel reconstruct and write all faceSets and cellSets in any of the surface formats (currently dx, ensight, nastran, raw, starcd, vtk). In case of a cellSet, the faces on the outside of the cellSet are reconstructed.
Sample use:
New files will be created under postProcessing/<time>
- Source code
- $FOAM_UTILITIES/mesh/manipulation/checkMesh
Patching of surfaces
The existing surfaceAutoPatch utility could split a surface into patches based on a feature angle. In this release the functionality has been generalised and renamed to surfacePatch.
It performs a set of operations on triangulated surfaces, e.g. geometric feature angle splitting, and the new regioning based on intersections with another surface. The input is provided by a surfacePatchDict dictionary consisting of the description of the geometry in snappyHexMesh familiar notation and a set of operations to perform on a surface.
Usage:
{
box
{
type searchableBox;
min (0 0 0);
max (1 1 1);
}
singleTri.obj
{
type triSurfaceMesh;
}
unitCube.stl
{
type triSurfaceMesh;
}
};
surfaces
{
unitCube.stl
{
regions
{
maxZ
{
type autoPatch;
featureAngle 60;
}
}
}
singleTri.obj
{
type cut;
cutters (box);
}
}
The example shows how to re-patch region maxZ of the unitCube surface based on a 60 degree feature angle (i.e. the old surfaceAutoPatch functionality), and will cut (all regions of) the singleTri surface with a box of size 1, putting all triangles in a separate region.
The utility accepts a -dict argument to change the location of the surfacePatchDict dictionary.
- Source code
- $FOAM_UTILITIES/surface/surfacePatch
surfaceBooleanFeatures: trim surfaces
The existing surfaceBooleanFeatures utility has been extended with a -trim option to enable the manipulation of feature edges:
where the new feature edges will be clipped based on the exterior of plane.obj.
- Source code
- $FOAM_UTILITIES/surface/surfaceBooleanFeatures