dynamicMotionSolverFvMeshAMI restart implementation
Summary
AMI with topological changes does not support restarting from a later time as stated in the OpenFOAM-v2006 release notes. The algorithm duplicates faces to achieve a 1-to-1 face match between AMI's. When attempting to restart, the AMI patches are initialized with the original number of faces and the initialization of their field values fail because the number of field values on the patch is not the original anymore, but larger. A fix is to call the update()
function during the initialization of dynamicMotionSolverFvMeshAMI so the field values of the patch map to the correct number of faces.
Steps to reproduce
Run $FOAM_TUTORIALS/incompressible/pimpleFoam/laminar/mixerVesselAMI2D/mixerVesselAMI2D-topologyChange
, stop and try to restart from the latest time.
Environment information
- OpenFOAM version : from v2006 to v2406
Proposed fix
Call the update()
function during initialization. This way the AMI patches go through the process of resetting, removing and adding new faces given the current rotation position. Do this only if the time where the restarting takes place has performed duplication of faces. If not, performing the topological changes during initialization ends up in the same error as before, but inverted (less number of field values than faces on the patch).
To reproduce the fix it is important to change the precision of mixerVesselAMI2D-topologyChange
to binary. This is because the points that are not being rotated are taken from the points file at the restarting time. If there is a mismatch between both the precision of the rotating and non-rotating patch, the addressing of intersecting faces between AMI patches (srcToTgtAddr
) is wrong and a different number of faces, instead of the supposed ones, are added.
Here is the modified .C file: dynamicMotionSolverFvMeshAMI.C
Changes in that file:
...
#include "cyclicACMIPolyPatch.H"
...
bool Foam::dynamicMotionSolverFvMeshAMI::init(const bool doInit)
{
if (doInit)
{
dynamicFvMesh::init(doInit);
}
motionPtr_ = motionSolver::New(*this);
// allow restarts during initialization to match patch field values if required
polyBoundaryMesh& pbm = const_cast<polyBoundaryMesh&>(boundaryMesh());
bool changeRequired = false;
for (label patchi = 0; patchi < pbm.nNonProcessor(); ++patchi)
{
if (isA<cyclicAMIPolyPatch>(pbm[patchi]))
{
const cyclicAMIPolyPatch& cpp = refCast<const cyclicAMIPolyPatch>(pbm[patchi]);
changeRequired = cpp.createAMIFaces() || changeRequired;
}
else if (isA<cyclicACMIPolyPatch>(pbm[patchi]))
{
const cyclicACMIPolyPatch& cpp = refCast<const cyclicACMIPolyPatch>(pbm[patchi]);
changeRequired = cpp.cyclicAMIPolyPatch::createAMIFaces() || changeRequired;
}
}
if (returnReduceOr(changeRequired))
{
update();
}
return true;
}
At time 0, createAMIFaces
is false, unless explicitly required not to (e.g: using the fields in 0 and mesh in constant from a saved time with topology changes)