Computational fluid dynamics (CFD) with OpenFOAM uses a mesh of small volumes (or cells) to describe the solution domain. In many cases the mesh does not change during a CFD simulation.  The term “dynamic mesh” describes situations where the mesh does change, either topologically by adding or removing cells, or by capturing the motion of the solution domain. When a domain is decomposed for parallel simulation, the mesh for an individual sub-domain can also be dynamic due to changes in the distribution of cells during a simulation.

This article describes the redesign of dynamic mesh functionality, released in OpenFOAM v10 and the development version of OpenFOAM (OpenFOAM-dev). The redesign was motivated by the development of non-conformal coupling (NCC) to replace the unreliable arbitrary mesh interface functionality. It specifically overcame a limitation of the previous dynamic mesh functionality which permitted only a single form of mesh motion or topological change within a simulation.

Background to Dynamic Mesh

Solver applications with dynamic mesh capability have existed in OpenFOAM since v1.3 in 2006. Each one began by replacing the fvMesh in a solver with a static mesh with a dynamicFvMesh. The resulting solver included “DyM” in its name, with solvers like interFoam having an equivalent interDyMFoam solver with dynamic mesh capability.  In OpenFOAM v7 in 2019, CFD Direct made dynamic mesh capability available in all solvers as standard, deprecating the DyM versions to reduce the number of solver applications.

 The types of dynamic mesh included automatic mesh refinement/unrefinement and various forms of mesh motion due to:

  • solid body motion of the entire mesh, for sloshing in a tank of  liquid, rotation of a region of mesh, e.g. for a propeller, etc.;
  • a prescribed boundary motion, with deformation of the mesh;
  • rigid body motion of an object described by a boundary surface, e.g. a ship.

A solver reads the dynamic mesh configuration from an optional dynamicMeshDict file.  Prior to OpenFOAM v10, users would select the type of dynamic mesh functionality through a dynamicFvMesh entry in that file. Their choice was limited to a single preconfigured form of mesh motion or refinement.  They could select one of the motions — solid body, prescribed boundary or rigid body — or automatic refinement, but not two or more items in combination.

Mesh Movers and Topology Changers

NCC was introduced to OpenFOAM-dev in 2022 and released in OpenFOAM v10 later that year. Its primary use is for cases when one or more regions are moving, e.g. to simulate rotating geometry.  As well as moving the mesh, there are additional mesh changes caused by the introduction of new faces in the finite volume mesh (fvMesh) at intersections between coupled patches. The need for at least two forms of mesh change with NCC motivated the redesign of dynamic mesh.

The initial redesign separated topological change and mesh motion into fvMeshTopoChanger and fvMeshMover classes respectively. These classes are part of the standard fvMesh class, simplifying the code and allowing the removal of the dynamicFvMesh class. Topology is changed within the update() function which can add and remove points as required and maps data for fields from the previous mesh to the updated mesh. Mesh motion is performed by the move() function which moves points and subsequently calculates new cell volumes and mesh-fluxes for conservative transport.

Users enable motion and topology change through separate sub-dictionaries in the dynamicMeshDict file as shown in the sample below.

mover
{
    type          motionSolver;
    libs          ("libfvMeshMovers.so" "librigidBodyMeshMotion.so");
    motionSolver  solidBody;
    ...
}

topoChanger
{
    type          refiner;
    libs          ("libfvMeshTopoChangers.so");
    ...
}

It shows a combination of dynamic mesh functionality in which a liquid filled tank undergoes solid body motion with mesh refinement around the liquid-air interface.  Multiple motions can be applied using the motionSolverList type of motionSolver.

Parallel Decomposition and Distribution

For a parallel simulation, the mesh is decomposed into sub-domains. Parallel efficiency dictates that each sub-domain has a similar computing time, and thus number of cells (all other things being equal). Changes in mesh topology during the simulation, such as mesh refinement, can introduce an imbalance in the number of cells per sub-domain.

In December 2021, CFD Direct added a general framework for mesh redistribution within the new fvMeshDistributor class in OpenFOAM.  Distribution is provided by an update() function, executed after the update() function from fvMeshTopoChanger. The mesh distributor is selected through an optional distributor sub-dictionary in the dynamicMeshDict file, as illustrated below.

distributor
{
    type          decomposer;
    libs          ("libfvMeshDistributors.so");
    redistributionInterval 10;
    maxImbalance  0.1;
}

redistributionInterval specifies the number of time steps between redistributions; maxImbalance specifies the difference between the largest and smallest numbers of cells on the sub-domains, beyond which the mesh is redistributed.  The distribution method is specified in the decomposeParDict file. The user can specify different methods for decomposition and redistribution through separate keywords as shown in the following example.

decomposer      hierarchical;
distributor     ptscotch;

Mesh-to-Mesh Mapping

As mentioned above, topology change requires mapping of field data from the previous mesh to the updated mesh. Since the release of OpenFOAM v10, CFD Direct have extensively refactored and rationalised the mesh-to-mesh mapping functionality. It has been extended to process particles and supports changes in decomposition between meshes when running in parallel.

There is also a meshToMesh topology changer which maps the solution to a specified sequence of pre-generated meshes during a simulation. The mesh can move between the sequence of meshes for applications such as piston and valve motion in engines. The movingCone example case shown below demonstrates this functionality. The case is axisymmetric with a cone that moves from an open boundary on the left towards a wall on the right. The first (left) image below shows a mesh which has moved and deformed under the prescribed cone motion. In the next time step, the simulation switches to a new pre-generated mesh, mapping data from the previous mesh. The velocity field maps smoothly between the meshes.

General Algorithm

The redesign splits dynamic mesh into topology change, distribution and motion. NCC also includes “unstitching” and “stitching” of the fvMesh at the couple interface. It enabled the creation of a general algorithm for modular solvers, with the topology change and distribution being executed in the solver.preSolve() function by mesh.update() which includes:

bool updated = topoChanger_->update();
updated = distributor_->update() || updated;

Mesh motion occurs separately in the solver.moveMesh() function by mesh.move() which includes:

const bool moved = mover_->update();

As the inventor of the C++ programming language, Bjarne Stroustrup, once said: “My best tool for efficiency and performance is abstraction.”

Dynamic Meshes in OpenFOAM