sixDoFRigidBodyMotion: Time integration now switches between symplectic and Crank-Nicolson

For explicit motion (and the first iteration of iterative motion
correction) the 2nd-order symplectic motion integrator is used.

For iterative correction a form of lagged Crank-Nicolson is used in
which the current time-step values correspond to the current iteration.
This converges to a 2nd-order implicit solution.
This commit is contained in:
Henry Weller
2015-10-12 21:27:42 +01:00
parent d3e5ea4914
commit 9427d134f9
6 changed files with 130 additions and 58 deletions

View File

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
\\ / A nd | Copyright (C) 2011-2014 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -204,18 +204,14 @@ void sixDoFRigidBodyDisplacementPointPatchVectorField::updateCoeffs()
const pointPatch& ptPatch = this->patch(); const pointPatch& ptPatch = this->patch();
// Store the motion state at the beginning of the time-step // Store the motion state at the beginning of the time-step
bool firstIter = false;
if (curTimeIndex_ != t.timeIndex()) if (curTimeIndex_ != t.timeIndex())
{ {
motion_.newTime(); motion_.newTime();
curTimeIndex_ = t.timeIndex(); curTimeIndex_ = t.timeIndex();
firstIter = true;
} }
// Patch force data is valid for the current positions, so
// calculate the forces on the motion object from this data, then
// update the positions
motion_.updatePosition(t.deltaTValue(), t.deltaT0Value());
dictionary forcesDict; dictionary forcesDict;
forcesDict.add("type", forces::typeName); forcesDict.add("type", forces::typeName);
@ -228,6 +224,11 @@ void sixDoFRigidBodyDisplacementPointPatchVectorField::updateCoeffs()
f.calcForcesMoment(); f.calcForcesMoment();
// Patch force data is valid for the current positions, so
// calculate the forces on the motion object from this data, then
// update the positions
motion_.updatePosition(firstIter, t.deltaTValue(), t.deltaT0Value());
// Get the forces on the patch faces at the current positions // Get the forces on the patch faces at the current positions
if (lookupGravity_ == 1) if (lookupGravity_ == 1)
@ -243,9 +244,11 @@ void sixDoFRigidBodyDisplacementPointPatchVectorField::updateCoeffs()
motion_.updateAcceleration motion_.updateAcceleration
( (
firstIter,
ramp*(f.forceEff() + motion_.mass()*g_), ramp*(f.forceEff() + motion_.mass()*g_),
ramp*(f.momentEff() + motion_.mass()*(motion_.momentArm() ^ g_)), ramp*(f.momentEff() + motion_.mass()*(motion_.momentArm() ^ g_)),
t.deltaTValue() t.deltaTValue(),
t.deltaT0Value()
); );
Field<vector>::operator= Field<vector>::operator=

View File

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
\\ / A nd | Copyright (C) 2011-2014 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -152,13 +152,15 @@ void uncoupledSixDoFRigidBodyDisplacementPointPatchVectorField::updateCoeffs()
const Time& t = mesh.time(); const Time& t = mesh.time();
// Store the motion state at the beginning of the time-step // Store the motion state at the beginning of the time-step
bool firstIter = false;
if (curTimeIndex_ != t.timeIndex()) if (curTimeIndex_ != t.timeIndex())
{ {
motion_.newTime(); motion_.newTime();
curTimeIndex_ = t.timeIndex(); curTimeIndex_ = t.timeIndex();
firstIter = true;
} }
motion_.updatePosition(t.deltaTValue(), t.deltaT0Value()); motion_.updatePosition(firstIter, t.deltaTValue(), t.deltaT0Value());
vector gravity = vector::zero; vector gravity = vector::zero;
@ -173,9 +175,11 @@ void uncoupledSixDoFRigidBodyDisplacementPointPatchVectorField::updateCoeffs()
// Do not modify the accelerations, except with gravity, where available // Do not modify the accelerations, except with gravity, where available
motion_.updateAcceleration motion_.updateAcceleration
( (
firstIter,
gravity*motion_.mass(), gravity*motion_.mass(),
vector::zero, vector::zero,
t.deltaTValue() t.deltaTValue(),
t.deltaT0Value()
); );
Field<vector>::operator= Field<vector>::operator=

View File

@ -259,22 +259,38 @@ void Foam::sixDoFRigidBodyMotion::addConstraints
void Foam::sixDoFRigidBodyMotion::updatePosition void Foam::sixDoFRigidBodyMotion::updatePosition
( (
bool firstIter,
scalar deltaT, scalar deltaT,
scalar deltaT0 scalar deltaT0
) )
{ {
// First leapfrog velocity adjust and motion part, required before
// force calculation
if (Pstream::master()) if (Pstream::master())
{ {
v() = tConstraints_ & (v0() + aDamp_*0.5*deltaT0*a()); if (firstIter)
pi() = rConstraints_ & (pi0() + aDamp_*0.5*deltaT0*tau()); {
// First simplectic step:
// Half-step for linear and angular velocities
// Update position and orientation
// Leapfrog move part v() = tConstraints_ & (v0() + aDamp_*0.5*deltaT0*a());
centreOfRotation() = centreOfRotation0() + deltaT*v(); pi() = rConstraints_ & (pi0() + aDamp_*0.5*deltaT0*tau());
// Leapfrog orientation adjustment centreOfRotation() = centreOfRotation0() + deltaT*v();
}
else
{
// For subsequent iterations use Crank-Nicolson
v() = tConstraints_
& (v0() + aDamp_*0.5*deltaT*(a() + motionState0_.a()));
pi() = rConstraints_
& (pi0() + aDamp_*0.5*deltaT*(tau() + motionState0_.tau()));
centreOfRotation() =
centreOfRotation0() + 0.5*deltaT*(v() + motionState0_.v());
}
// Correct orientation
Tuple2<tensor, vector> Qpi = rotate(Q0(), pi(), deltaT); Tuple2<tensor, vector> Qpi = rotate(Q0(), pi(), deltaT);
Q() = Qpi.first(); Q() = Qpi.first();
pi() = rConstraints_ & Qpi.second(); pi() = rConstraints_ & Qpi.second();
@ -286,16 +302,15 @@ void Foam::sixDoFRigidBodyMotion::updatePosition
void Foam::sixDoFRigidBodyMotion::updateAcceleration void Foam::sixDoFRigidBodyMotion::updateAcceleration
( (
bool firstIter,
const vector& fGlobal, const vector& fGlobal,
const vector& tauGlobal, const vector& tauGlobal,
scalar deltaT scalar deltaT,
scalar deltaT0
) )
{ {
static bool first = false; static bool first = false;
// Second leapfrog velocity adjust part, required after motion and
// acceleration calculation
if (Pstream::master()) if (Pstream::master())
{ {
// Save the previous iteration accelerations for relaxation // Save the previous iteration accelerations for relaxation
@ -315,9 +330,23 @@ void Foam::sixDoFRigidBodyMotion::updateAcceleration
} }
first = false; first = false;
// Correct velocities if (firstIter)
v() += tConstraints_ & aDamp_*0.5*deltaT*a(); {
pi() += rConstraints_ & aDamp_*0.5*deltaT*tau(); // Second simplectic step:
// Complete update of linear and angular velocities
v() += tConstraints_ & aDamp_*0.5*deltaT*a();
pi() += rConstraints_ & aDamp_*0.5*deltaT*tau();
}
else
{
// For subsequent iterations use Crank-Nicolson
v() = tConstraints_
& (v0() + aDamp_*0.5*deltaT*(a() + motionState0_.a()));
pi() = rConstraints_
& (pi0() + aDamp_*0.5*deltaT*(tau() + motionState0_.tau()));
}
if (report_) if (report_)
{ {
@ -329,6 +358,7 @@ void Foam::sixDoFRigidBodyMotion::updateAcceleration
} }
void Foam::sixDoFRigidBodyMotion::status() const void Foam::sixDoFRigidBodyMotion::status() const
{ {
Info<< "6-DoF rigid body motion" << nl Info<< "6-DoF rigid body motion" << nl

View File

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
\\ / A nd | Copyright (C) 2011-2014 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -42,6 +42,9 @@ Description
url = {http://link.aip.org/link/?JCP/107/5840/1}, url = {http://link.aip.org/link/?JCP/107/5840/1},
doi = {10.1063/1.474310} doi = {10.1063/1.474310}
Changes to Crank-Nicolson integration if subsequent iterations to handle
implicit coupling between pressure and motion.
Can add restraints (e.g. a spring) Can add restraints (e.g. a spring)
and constraints (e.g. motion may only be on a plane). and constraints (e.g. motion may only be on a plane).
@ -298,18 +301,22 @@ public:
// Update state // Update state
//- First leapfrog velocity adjust and motion part, required //- First symplectic velocity adjust and motion part, required
// before force calculation. Takes old timestep for variable // before force calculation. Takes old timestep for variable
// timestep cases. // timestep cases.
void updatePosition(scalar deltaT, scalar deltaT0); // Changes to Crank-Nicolson integration for subsequent iterations.
void updatePosition(bool firstIter, scalar deltaT, scalar deltaT0);
//- Second leapfrog velocity adjust part //- Second symplectic velocity adjust part
// required after motion and force calculation // required after motion and force calculation.
// Changes to Crank-Nicolson integration for subsequent iterations.
void updateAcceleration void updateAcceleration
( (
bool firstIter,
const vector& fGlobal, const vector& fGlobal,
const vector& tauGlobal, const vector& tauGlobal,
scalar deltaT scalar deltaT,
scalar deltaT0
); );
//- Report the status of the motion //- Report the status of the motion

View File

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
\\ / A nd | Copyright (C) 2013-2014 OpenFOAM Foundation \\ / A nd | Copyright (C) 2013-2015 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -85,6 +85,7 @@ Foam::sixDoFRigidBodyMotionSolver::sixDoFRigidBodyMotionSolver
patchSet_(mesh.boundaryMesh().patchSet(patches_)), patchSet_(mesh.boundaryMesh().patchSet(patches_)),
di_(readScalar(coeffDict().lookup("innerDistance"))), di_(readScalar(coeffDict().lookup("innerDistance"))),
do_(readScalar(coeffDict().lookup("outerDistance"))), do_(readScalar(coeffDict().lookup("outerDistance"))),
test_(coeffDict().lookupOrDefault<Switch>("test", false)),
rhoInf_(1.0), rhoInf_(1.0),
rhoName_(coeffDict().lookupOrDefault<word>("rhoName", "rho")), rhoName_(coeffDict().lookupOrDefault<word>("rhoName", "rho")),
scale_ scale_
@ -179,31 +180,15 @@ void Foam::sixDoFRigidBodyMotionSolver::solve()
<< " points." << exit(FatalError); << " points." << exit(FatalError);
} }
// Store the motion state at the beginning of the time-step // Store the motion state at the beginning of the time-stepbool
bool firstIter = false;
if (curTimeIndex_ != this->db().time().timeIndex()) if (curTimeIndex_ != this->db().time().timeIndex())
{ {
motion_.newTime(); motion_.newTime();
curTimeIndex_ = this->db().time().timeIndex(); curTimeIndex_ = this->db().time().timeIndex();
firstIter = true;
} }
// Patch force data is valid for the current positions, so
// calculate the forces on the motion object from this data, then
// update the positions
motion_.updatePosition(t.deltaTValue(), t.deltaT0Value());
dictionary forcesDict;
forcesDict.add("type", forces::typeName);
forcesDict.add("patches", patches_);
forcesDict.add("rhoInf", rhoInf_);
forcesDict.add("rhoName", rhoName_);
forcesDict.add("CofR", motion_.centreOfRotation());
forces f("forces", db(), forcesDict);
f.calcForcesMoment();
dimensionedVector g("g", dimAcceleration, vector::zero); dimensionedVector g("g", dimAcceleration, vector::zero);
if (db().foundObject<uniformDimensionedVectorField>("g")) if (db().foundObject<uniformDimensionedVectorField>("g"))
@ -218,12 +203,51 @@ void Foam::sixDoFRigidBodyMotionSolver::solve()
// scalar ramp = min(max((this->db().time().value() - 5)/10, 0), 1); // scalar ramp = min(max((this->db().time().value() - 5)/10, 0), 1);
scalar ramp = 1.0; scalar ramp = 1.0;
motion_.updateAcceleration if (test_)
( {
ramp*(f.forceEff() + motion_.mass()*g.value()), motion_.updatePosition(firstIter, t.deltaTValue(), t.deltaT0Value());
ramp*(f.momentEff() + motion_.mass()*(motion_.momentArm() ^ g.value())),
t.deltaTValue() motion_.updateAcceleration
); (
firstIter,
ramp*(motion_.mass()*g.value()),
ramp*(motion_.mass()*(motion_.momentArm() ^ g.value())),
t.deltaTValue(),
t.deltaT0Value()
);
}
else
{
dictionary forcesDict;
forcesDict.add("type", forces::typeName);
forcesDict.add("patches", patches_);
forcesDict.add("rhoInf", rhoInf_);
forcesDict.add("rhoName", rhoName_);
forcesDict.add("CofR", motion_.centreOfRotation());
forces f("forces", db(), forcesDict);
f.calcForcesMoment();
// Patch force data is valid for the current positions, so
// calculate the forces on the motion object from this data, then
// update the positions
motion_.updatePosition(firstIter, t.deltaTValue(), t.deltaT0Value());
motion_.updateAcceleration
(
firstIter,
ramp*(f.forceEff() + motion_.mass()*g.value()),
ramp
*(
f.momentEff()
+ motion_.mass()*(motion_.momentArm() ^ g.value())
),
t.deltaTValue(),
t.deltaT0Value()
);
}
// Update the displacements // Update the displacements
pointDisplacement_.internalField() = pointDisplacement_.internalField() =

View File

@ -70,6 +70,10 @@ class sixDoFRigidBodyMotionSolver
//- Outer morphing distance (limit of linear interpolation region) //- Outer morphing distance (limit of linear interpolation region)
const scalar do_; const scalar do_;
//- Switch for test-mode in which only the
// gravitational body-force is applied
Switch test_;
//- Reference density required by the forces object for //- Reference density required by the forces object for
// incompressible calculations, required if rhoName == rhoInf // incompressible calculations, required if rhoName == rhoInf
scalar rhoInf_; scalar rhoInf_;