mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
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:
@ -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=
|
||||||
|
|||||||
@ -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=
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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() =
|
||||||
|
|||||||
@ -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_;
|
||||||
|
|||||||
Reference in New Issue
Block a user