Curvature-based refinement in snappyHexMesh

On appealing feature of snappyHexMesh is the auto-refinement option depending on surface curvature. It is possible to define a minimal and a maximal refinement level per surface or region, and SHM will decide based on the set ‘resolveFeatureAngle’ whether to further refine that surface (up to the maximum refinement level, of course).

In my experience, however, this feature can create some grid problems. Especially at the interface between multiple refinement levels, snappyHexMesh seems to have troubles snapping the mesh correctly to the ship surface. What happens, is that if the surface locally has higher curvature, snappyHexMesh will refine the cells there. This may be limited to a single cell. Depending on the ‘nCellsBetweenLevels’ setting, more cells will be refined. However, SHM still generates an ‘island’ with an interface between larger and smaller cells around the perimeter. The initially snapped mesh may still look fine, but if the cells at the border between refinement levels have distorted shapes, adding layers is becoming more and more of a problem.

Example ship

To sketch an example, I’m trying to get a good mesh around an inland ship hull. For speed of meshing, I am currently focusing on the most complex part, the stern (an example is given in the next figure). An inland ship stern is far from smooth, due to propeller tunnels. The skirts of these tunnels have to prevent the propeller from ventilating (sucking in air from the water surface) in case the ship has to operate at low draft. One may imagine that fitting a mesh around this is not easy, but with some practice it will work out.

Stern of an inland ship. Note the tunnel skirts making meshing pretty complex.

Fitting the grid around the propeller tunnel: locally refined zones

A propeller tunnel like this is a nice candidate for using the auto-refinement function. Namely, upstream the deform smoothly into the parallel midbody of the ship, hence reducing curvature and requiring less small grid cells. The result, however, is not exactly nice:

A close-up of the mesh in the region where the tunnel blends into the parallel midbody of the ship

There are multiple small islands at places where the curvature of the surface exceeds a certain threshold locally. Again, at interfaces between different refinement levels, snappyHexMesh has problems – in my experience – fitting a nicely snapped grid to the STL surface.

Snapping artifacts at interfaces between refinement levels

In the figure above, such problems are not immediately obvious, but the following two pictures may clearify the problem.

Close-up of the snapped surface of the tunnel skirt, from the inside of the ship. Snapping problems are clearly visible.

The first picture shows the surface snapped to the STL file by snappyHexMesh. Multiple badly snapped cells can be observed. Such artifacts prevent layers from being grown at the surface.The next picture shows the mesh at the tunnel skirt. Comparing both pictures, we can see that artifacts in the snapped surface seem to occur at the interface between multiple refinement levels.

Close-up of the snapped mesh at the tunnel skirt.

My solution to get a better snapped mesh

My solution to this was to not allow snappyHexMesh to automatically refine the surface based on curvature. This means that you have to sub-divide your STL in multiple parts (the original surface on which the STL was based is in Rhino, so that was not a big problem in my case) and have the minimum and maximum refinement levels equal per surface (between surfaces, they can vary). When sub-dividing the STL, it is a good idea to ensure that the edge between separate patches is in an area of limited curvature; otherwise SHM will still have problems in those areas!

A small relieve, however, is that the problem mostly seems to occur if the interface between multiple refinement levels does not resemble a straight or smooth line. At the parallel midbody of the ship used in this post, for example, the distribution of curvature is constant: flat at the bottom, curved with radius R at the bilge, and flat at the side again (and that for 70 meters in length). In such a case, the interface between refinement levels will end up to be a straight line. SnappyHexMesh handles this without problems. But specifically for areas with a lot of curvature changes, using fixed refinement levels per surface patch seems a good idea.

A mesh check before layer addition

A nice way to check this if layers can be fitted after snapping is through the snappyHexMesh log: at the starting point of a feature snapping iteration (Morph iteration xxx), snappyHexMesh prints the minimal and maximal distance from the mesh to the STL surface. A a rule of thumb, I assume maximal distance here should be (considerably) less than the thickness of the first layer.

This applies when ‘relativeSizes’ is false. If you’re using relative layer sizing (based on the local grid cell size), note that the maximum snapping distance is a global value and if layers locally are larger due to relative layer sizing, layers may still be fitted nicely. I am using absolute layer sizing since I do not want layers to suddenly become smaller if my local patch has been refined to smaller cells (namely, the boundary layer thickness does not suddenly become different if the underlying patch is finer or coarser).