1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation, either version 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
28 6-DOF solver using quaternions
31 Dubravko Matijasevic, FSB Zagreb. All rights reserved.
33 \*---------------------------------------------------------------------------*/
35 #include "objectRegistry.H"
36 #include "sixDOFqODE.H"
38 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
40 void Foam::sixDOFqODE::setCoeffs()
42 // Set ODE coefficients from position and rotation
44 // Linear displacement relative to spring equilibrium
45 const vector& Xval = Xrel_.value();
46 coeffs_[0] = Xval.x();
47 coeffs_[1] = Xval.y();
48 coeffs_[2] = Xval.z();
51 const vector& Uval = U_.value();
52 coeffs_[3] = Uval.x();
53 coeffs_[4] = Uval.y();
54 coeffs_[5] = Uval.z();
56 // Rotational velocity in non - inertial coordinate system
57 const vector& omegaVal = omega_.value();
58 coeffs_[6] = omegaVal.x();
59 coeffs_[7] = omegaVal.y();
60 coeffs_[8] = omegaVal.z();
63 coeffs_[9] = rotation_.eInitial().e0();
64 coeffs_[10] = rotation_.eInitial().e1();
65 coeffs_[11] = rotation_.eInitial().e2();
66 coeffs_[12] = rotation_.eInitial().e3();
70 Foam::dimensionedVector Foam::sixDOFqODE::A
72 const dimensionedVector& xR,
73 const dimensionedVector& uR,
74 const HamiltonRodriguezRot& rotation
77 // Fix the global force for global rotation constraints
78 dimensionedVector fAbs = force();
80 // Constrain translation
81 constrainTranslation(fAbs.value());
85 - (linSpringCoeffs_ & xR) // spring
86 - (linDampingCoeffs_ & uR) // damping
89 + (rotation.invR() & forceRelative())
94 Foam::dimensionedVector Foam::sixDOFqODE::OmegaDot
96 const HamiltonRodriguezRot& rotation,
97 const dimensionedVector& omega
100 // Fix the global moment for global rotation constraints
101 dimensionedVector mAbs = moment();
103 // Constrain rotation
104 constrainRotation(mAbs.value());
107 inv(momentOfInertia_)
111 + (rotation.R() & mAbs)
117 Foam::dimensionedVector Foam::sixDOFqODE::E
119 const dimensionedVector& omega
122 return (*(momentOfInertia_ & omega) & omega);
126 void Foam::sixDOFqODE::constrainRotation(vector& vec) const
128 vector consVec(vector::zero);
130 // Constrain the vector in respect to referent or global coordinate system
131 if (referentMotionConstraints_)
133 consVec = referentRotation_.R() & vec;
148 vec = referentRotation_.invR() & consVec;
168 void Foam::sixDOFqODE::constrainTranslation(vector& vec) const
170 vector consVec(vector::zero);
172 // Constrain the vector in respect to referent or global coordinate system
173 if (referentMotionConstraints_)
175 consVec = referentRotation_.R() & vec;
190 vec = referentRotation_.invR() & consVec;
210 void Foam::sixDOFqODE::aitkensRelaxation
216 // Calculate translational relax factor
217 const scalar saveOldRelFacT = oldRelaxFactorT_;
218 oldRelaxFactorT_ = relaxFactorT_;
220 if(magSqr(A_[0] - An_[1] - A_[1] - An_[2]) > SMALL)
222 relaxFactorT_ = saveOldRelFacT + (saveOldRelFacT - 1)*
225 & (A_[0] - An_[1] - A_[1] - An_[2])
227 magSqr(A_[0] - An_[1] - A_[1] - An_[2]);
234 // Bound the relaxation factor for stability
235 if(relaxFactorT_ > max)
239 else if(relaxFactorT_ < min)
244 // Calculate rotational relax factor
245 const scalar saveOldRelFacR = oldRelaxFactorR_;
246 oldRelaxFactorR_ = relaxFactorR_;
248 if(magSqr(OmegaDot_[0] - OmegaDotn_[1] - OmegaDot_[1] - OmegaDotn_[2]) > SMALL)
251 saveOldRelFacR + (saveOldRelFacR - 1)*
252 ((OmegaDot_[1] - OmegaDotn_[2]) &
253 (OmegaDot_[0] - OmegaDotn_[1] - OmegaDot_[1] - OmegaDotn_[2]))/
254 magSqr(OmegaDot_[0] - OmegaDotn_[1] - OmegaDot_[1] - OmegaDotn_[2]);
261 // Bound the relaxation factor for stability
262 if(relaxFactorR_ > max)
266 else if(relaxFactorR_ < min)
273 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
275 // Construct from components
276 Foam::sixDOFqODE::sixDOFqODE(const IOobject& io)
280 mass_(lookup("mass")),
281 momentOfInertia_(lookup("momentOfInertia")),
283 Xequilibrium_(lookup("equilibriumPosition")),
284 linSpringCoeffs_(lookup("linearSpring")),
285 linDampingCoeffs_(lookup("linearDamping")),
288 oldRelaxFactorT_(1.0),
289 oldRelaxFactorR_(1.0),
291 Xrel_(lookup("Xrel")),
296 vector(lookup("rotationVector")),
297 dimensionedScalar(lookup("rotationAngle")).value()
299 omega_(lookup("omega")),
300 omegaAverage_(omega_),
301 omegaAverageAbsolute_(omega_),
304 OmegaDot_(3, vector::zero),
305 An_(3, vector::zero),
306 OmegaDotn_(3, vector::zero),
307 force_(lookup("force")),
308 moment_(lookup("moment")),
309 forceRelative_(lookup("forceRelative")),
310 momentRelative_(lookup("momentRelative")),
314 fixedSurge_(lookup("fixedSurge")),
315 fixedSway_(lookup("fixedSway")),
316 fixedHeave_(lookup("fixedHeave")),
317 fixedRoll_(lookup("fixedRoll")),
318 fixedPitch_(lookup("fixedPitch")),
319 fixedYaw_(lookup("fixedYaw")),
320 referentMotionConstraints_
322 lookupOrDefault<Switch>
324 "referentMotionConstraints",
328 referentRotation_(vector(1, 0, 0), 0)
335 Foam::sixDOFqODE::sixDOFqODE
354 mass_(sd.mass_.name(), sd.mass_),
355 momentOfInertia_(sd.momentOfInertia_.name(), sd.momentOfInertia_),
357 Xequilibrium_(sd.Xequilibrium_.name(), sd.Xequilibrium_),
358 linSpringCoeffs_(sd.linSpringCoeffs_.name(), sd.linSpringCoeffs_),
359 linDampingCoeffs_(sd.linDampingCoeffs_.name(), sd.linDampingCoeffs_),
360 relaxFactorT_(sd.relaxFactorT_),
361 relaxFactorR_(sd.relaxFactorR_),
362 oldRelaxFactorT_(sd.oldRelaxFactorT_),
363 oldRelaxFactorR_(sd.oldRelaxFactorR_),
365 Xrel_(sd.Xrel_.name(), sd.Xrel_),
366 U_(sd.U_.name(), sd.U_),
367 Uaverage_(sd.Uaverage_.name(), sd.Uaverage_),
368 rotation_(sd.rotation_),
369 omega_(sd.omega_.name(), sd.omega_),
370 omegaAverage_(sd.omegaAverage_.name(), sd.omegaAverage_),
371 omegaAverageAbsolute_
373 sd.omegaAverageAbsolute_.name(),
374 sd.omegaAverageAbsolute_
378 OmegaDot_(sd.OmegaDot_),
380 OmegaDotn_(sd.OmegaDotn_),
381 force_(sd.force_.name(), sd.force_),
382 moment_(sd.moment_.name(), sd.moment_),
383 forceRelative_(sd.forceRelative_.name(), sd.forceRelative_),
384 momentRelative_(sd.momentRelative_.name(), sd.momentRelative_),
388 fixedSurge_(sd.fixedSurge_),
389 fixedSway_(sd.fixedSway_),
390 fixedHeave_(sd.fixedHeave_),
391 fixedRoll_(sd.fixedRoll_),
392 fixedPitch_(sd.fixedPitch_),
393 fixedYaw_(sd.fixedYaw_),
394 referentMotionConstraints_(sd.referentMotionConstraints_),
395 referentRotation_(sd.referentRotation_)
399 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
401 Foam::sixDOFqODE::~sixDOFqODE()
405 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
407 void Foam::sixDOFqODE::setState(const sixDOFqODE& sd)
409 // Set state does not copy AList_, AOld_, relaxFactor_ and relaxFactorOld_ to
410 // allow Aitkens relaxation (IG 5/May/2016)
412 momentOfInertia_ = sd.momentOfInertia_;
414 Xequilibrium_ = sd.Xequilibrium_;
415 linSpringCoeffs_ = sd.linSpringCoeffs_;
416 linDampingCoeffs_ = sd.linDampingCoeffs_;
420 Uaverage_ = sd.Uaverage_;
421 rotation_ = sd.rotation_;
423 omegaAverage_ = sd.omegaAverage_;
424 omegaAverageAbsolute_ = sd.omegaAverageAbsolute_;
427 moment_ = sd.moment_;
428 forceRelative_ = sd.forceRelative_;
429 momentRelative_ = sd.momentRelative_;
431 // Copy ODE coefficients: this carries actual ODE state
433 coeffs_ = sd.coeffs_;
435 fixedSurge_ = sd.fixedSurge_;
436 fixedSway_ = sd.fixedSway_;
437 fixedHeave_ = sd.fixedHeave_;
438 fixedRoll_ = sd.fixedRoll_;
439 fixedPitch_ = sd.fixedPitch_;
440 fixedYaw_ = sd.fixedYaw_;
444 void Foam::sixDOFqODE::derivatives
447 const scalarField& y,
451 // Set the derivatives for displacement
456 dimensionedVector curX("curX", dimLength, vector(y[0], y[1], y[2]));
457 dimensionedVector curU("curU", dimVelocity, vector(y[3], y[4], y[5]));
458 const HamiltonRodriguezRot curRotation
466 const vector accel = A(curX, curU, curRotation).value();
472 // Set the derivatives for rotation
473 dimensionedVector curOmega
477 vector(y[6], y[7], y[8])
480 const vector omegaDot = OmegaDot(curRotation, curOmega).value();
482 dydx[6] = omegaDot.x();
483 dydx[7] = omegaDot.y();
484 dydx[8] = omegaDot.z();
486 dydx[9] = curRotation.eDot(curOmega.value(), 0);
487 dydx[10] = curRotation.eDot(curOmega.value(), 1);
488 dydx[11] = curRotation.eDot(curOmega.value(), 2);
489 dydx[12] = curRotation.eDot(curOmega.value(), 3);
491 // Add rotational constraints by setting RHS of given components to zero
494 dydx[10] = 0; // Roll axis (roll quaternion evolution RHS)
498 dydx[11] = 0; // Pitch axis (pitch quaternion evolution RHS)
502 dydx[12] = 0; // Yaw axis (yaw quaternion evolution RHS)
507 void Foam::sixDOFqODE::jacobian
510 const scalarField& y,
512 scalarSquareMatrix& dfdy
515 Info << "jacobian(...)" << endl;
516 notImplemented("sixDOFqODE::jacobian(...) const");
520 void Foam::sixDOFqODE::update(const scalar delta)
523 vector Xold = Xrel_.value();
525 vector& Xval = Xrel_.value();
527 Xval.x() = coeffs_[0];
528 Xval.y() = coeffs_[1];
529 Xval.z() = coeffs_[2];
532 Uaverage_.value() = (Xval - Xold)/delta;
534 vector& Uval = U_.value();
536 Uval.x() = coeffs_[3];
537 Uval.y() = coeffs_[4];
538 Uval.z() = coeffs_[5];
540 // Constrain velocity
541 constrainTranslation(Uval);
542 coeffs_[3] = Uval.x();
543 coeffs_[4] = Uval.y();
544 coeffs_[5] = Uval.z();
547 vector& omegaVal = omega_.value();
549 omegaVal.x() = coeffs_[6];
550 omegaVal.y() = coeffs_[7];
551 omegaVal.z() = coeffs_[8];
554 constrainRotation(omegaVal);
555 coeffs_[6] = omegaVal.x();
556 coeffs_[7] = omegaVal.y();
557 coeffs_[8] = omegaVal.z();
559 rotation_.updateRotation
570 omegaAverage_.value() = rotation_.omegaAverage(delta);
572 // Calculate and constrain omegaAverageAbsolute appropriately
573 vector& omegaAverageAbsoluteValue = omegaAverageAbsolute_.value();
574 omegaAverageAbsoluteValue = rotation_.omegaAverageAbsolute(delta);
578 omegaAverageAbsoluteValue.x() = 0;
582 omegaAverageAbsoluteValue.y() = 0;
586 omegaAverageAbsoluteValue.z() = 0;
591 void Foam::sixDOFqODE::relaxAcceleration
593 const scalar minRelFactor,
594 const scalar maxRelFactor
597 if (minRelFactor - maxRelFactor < SMALL)
600 relaxFactorT_ = minRelFactor;
601 relaxFactorR_ = minRelFactor;
605 // Use Aitkens relaxation
607 // Update Aitkens relaxation factor
608 aitkensRelaxation(minRelFactor, maxRelFactor);
610 // Update non relaxed accelerations
612 An_[2] = (force()/mass_).value();
613 OmegaDotn_[1] = OmegaDotn_[2];
614 OmegaDotn_[2] = (inv(momentOfInertia_) & moment()).value();
617 const dimensionedVector Aold
620 dimensionSet(0, 1, -2, 0, 0, 0, 0),
624 const dimensionedVector OmegaDotold
627 dimensionSet(0, 0, -2, 0, 0, 0, 0),
632 Aold*mass_ + relaxFactorT_*(force() - Aold*mass_);
635 (momentOfInertia_ & OmegaDotold)
636 + relaxFactorR_*(moment() - (momentOfInertia_ & OmegaDotold));
638 // Update relaxed old accelerations
641 A_[2] = (force()/mass_).value();
642 OmegaDot_[0] = OmegaDot_[1];
643 OmegaDot_[1] = OmegaDot_[2];
644 OmegaDot_[2] = (inv(momentOfInertia_) & moment()).value();
648 // * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
650 bool Foam::sixDOFqODE::writeData(Ostream& os) const
657 // * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * * //
659 Foam::Ostream& Foam::operator<<(Ostream& os, const sixDOFqODE& sds)
661 os.writeKeyword("mass") << tab << sds.mass_ << token::END_STATEMENT << nl;
662 os.writeKeyword("momentOfInertia") << tab << sds.momentOfInertia_
663 << token::END_STATEMENT << nl << nl;
665 os.writeKeyword("equilibriumPosition") << tab << sds.Xequilibrium_
666 << token::END_STATEMENT << nl;
667 os.writeKeyword("linearSpring") << tab << sds.linSpringCoeffs_
668 << token::END_STATEMENT << nl;
669 os.writeKeyword("linearDamping") << tab << sds.linDampingCoeffs_
670 << token::END_STATEMENT << nl << nl;
672 os.writeKeyword("Xrel") << tab << sds.Xrel() << token::END_STATEMENT << nl;
673 os.writeKeyword("U") << tab << sds.U() << token::END_STATEMENT << nl;
674 os.writeKeyword("rotationVector") << tab << sds.rotVector()
675 << token::END_STATEMENT << nl;
676 os.writeKeyword("rotationAngle") << tab << sds.rotAngle()
677 << token::END_STATEMENT << nl;
678 os.writeKeyword("omega") << tab << sds.omega()
679 << token::END_STATEMENT << nl << nl;
681 os.writeKeyword("force") << tab << sds.force()
682 << token::END_STATEMENT << nl;
683 os.writeKeyword("moment") << tab << sds.moment()
684 << token::END_STATEMENT << nl;
685 os.writeKeyword("forceRelative") << tab << sds.forceRelative()
686 << token::END_STATEMENT << nl;
687 os.writeKeyword("momentRelative") << tab << sds.momentRelative()
688 << token::END_STATEMENT << endl;
690 os.writeKeyword("fixedSurge") << tab << sds.fixedSurge_ <<
691 token::END_STATEMENT << endl;
692 os.writeKeyword("fixedSway") << tab << sds.fixedSway_ <<
693 token::END_STATEMENT << endl;
694 os.writeKeyword("fixedHeave") << tab << sds.fixedHeave_ <<
695 token::END_STATEMENT << endl;
696 os.writeKeyword("fixedRoll") << tab << sds.fixedRoll_ <<
697 token::END_STATEMENT << endl;
698 os.writeKeyword("fixedPitch") << tab << sds.fixedPitch_ <<
699 token::END_STATEMENT << endl;
700 os.writeKeyword("fixedYaw") << tab << sds.fixedYaw_ <<
701 token::END_STATEMENT << endl;
707 // ************************************************************************* //