OpenFOAM® v3.0+: New Meshing Functionality

13/01/2016

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:

// Angle used to detect opposite surfaces
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.

Gap refinement

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:

refinementRegions
{
    ...
}


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.

Layer generation on face zones

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:

castellatedMeshControls
{
    // (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;
        }
    }
}

Headlamp section

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:

geometry
{
    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:

geometry
{
    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.

Hollow 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:

geometry
{
    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).

Refinement at coarse-fine interfaces

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:

snapControls
{
    ..
    // 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.

Volume smoothing

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:

snapControls
{
    // 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;
}

Effect on layer coverage of splitting boundary faces

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:

addLayersControls
{
    // 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

Layers with medial axis (left) and Laplacian (right)

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:

subsetMesh c0 -patches '(".*Wall")'

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:

mpirun -np 2 checkMesh -writeSets ensight -parallel

New files will be created under postProcessing/<time>

Visualisation of non-orthogonal faces (red)

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:

geometry
{
    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.

Cutting triangle with box to generate new 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:

surfaceBooleanFeatures difference vehicle.obj windtunnel.obj -trim '((plane.obj outside))'

where the new feature edges will be clipped based on the exterior of plane.obj.

Source code
$FOAM_UTILITIES/surface/surfaceBooleanFeatures