Merge branch 'master' of ssh://git.code.sf.net/p/foam-extend/foam-extend-3.2
[foam-extend-3.2.git] / src / ODE / sixDOF / sixDOFqODE / sixDOFqODE.C
blob334b23d5f38aab4eeef78194e8a7f5ee88a92c84
1 /*---------------------------------------------------------------------------*\
2   =========                 |
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 -------------------------------------------------------------------------------
8 License
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/>.
24 Class
25     sixDOFqODE
27 Description
28     6-DOF solver using quaternions
30 Author
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();
50     // Linear velocity
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();
62     // Quaternions
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
75 ) const
77     // Fix the global force for global rotation constraints
78     dimensionedVector fAbs = force();
80     // Constrain translation
81     constrainTranslation(fAbs.value());
83     return
84     (
85        - (linSpringCoeffs_ & xR)    // spring
86        - (linDampingCoeffs_ & uR)   // damping
87        + fAbs
88          // To absolute
89        + (rotation.invR() & forceRelative())
90     )/mass_;
94 Foam::dimensionedVector Foam::sixDOFqODE::OmegaDot
96     const HamiltonRodriguezRot& rotation,
97     const dimensionedVector& omega
98 ) const
100     // Fix the global moment for global rotation constraints
101     dimensionedVector mAbs = moment();
103     // Constrain rotation
104     constrainRotation(mAbs.value());
106     return
107         inv(momentOfInertia_)
108       & (
109             E(omega)
110             // To relative
111           + (rotation.R() & mAbs)
112           + momentRelative()
113         );
117 Foam::dimensionedVector Foam::sixDOFqODE::E
119     const dimensionedVector& omega
120 ) const
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_)
132     {
133         consVec = referentRotation_.R() & vec;
135         if (fixedRoll_)
136         {
137             consVec.x() = 0;
138         }
139         if (fixedPitch_)
140         {
141             consVec.y() = 0;
142         }
143         if (fixedYaw_)
144         {
145             consVec.z() = 0;
146         }
148         vec = referentRotation_.invR() & consVec;
149     }
150     else
151     {
152         if (fixedRoll_)
153         {
154             vec.x() = 0;
155         }
156         if (fixedPitch_)
157         {
158             vec.y() = 0;
159         }
160         if (fixedYaw_)
161         {
162             vec.z() = 0;
163         }
164     }
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_)
174     {
175         consVec = referentRotation_.R() & vec;
177         if (fixedSurge_)
178         {
179             consVec.x() = 0;
180         }
181         if (fixedSway_)
182         {
183             consVec.y() = 0;
184         }
185         if (fixedHeave_)
186         {
187             consVec.z() = 0;
188         }
190         vec = referentRotation_.invR() & consVec;
191     }
192     else
193     {
194         if (fixedSurge_)
195         {
196             vec.x() = 0;
197         }
198         if (fixedSway_)
199         {
200             vec.y() = 0;
201         }
202         if (fixedHeave_)
203         {
204             vec.z() = 0;
205         }
206     }
210 void Foam::sixDOFqODE::aitkensRelaxation
212     const scalar min,
213     const scalar max
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)
221     {
222         relaxFactorT_ = saveOldRelFacT + (saveOldRelFacT - 1)*
223         (
224             (A_[1] - An_[2])
225           & (A_[0] - An_[1] - A_[1] - An_[2])
226         )/
227         magSqr(A_[0] - An_[1] - A_[1] - An_[2]);
228     }
229     else
230     {
231         relaxFactorT_ = min;
232     }
234     // Bound the relaxation factor for stability
235     if(relaxFactorT_ > max)
236     {
237         relaxFactorT_ = max;
238     }
239     else if(relaxFactorT_ < min)
240     {
241         relaxFactorT_ = min;
242     }
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)
249     {
250         relaxFactorR_ =
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]);
255     }
256     else
257     {
258         relaxFactorR_ = min;
259     }
261     // Bound the relaxation factor for stability
262     if(relaxFactorR_ > max)
263     {
264         relaxFactorR_ = max;
265     }
266     else if(relaxFactorR_ < min)
267     {
268         relaxFactorR_ = min;
269     }
273 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
275 // Construct from components
276 Foam::sixDOFqODE::sixDOFqODE(const IOobject& io)
278     IOdictionary(io),
280     mass_(lookup("mass")),
281     momentOfInertia_(lookup("momentOfInertia")),
283     Xequilibrium_(lookup("equilibriumPosition")),
284     linSpringCoeffs_(lookup("linearSpring")),
285     linDampingCoeffs_(lookup("linearDamping")),
286     relaxFactorT_(1.0),
287     relaxFactorR_(1.0),
288     oldRelaxFactorT_(1.0),
289     oldRelaxFactorR_(1.0),
291     Xrel_(lookup("Xrel")),
292     U_(lookup("U")),
293     Uaverage_(U_),
294     rotation_
295     (
296         vector(lookup("rotationVector")),
297         dimensionedScalar(lookup("rotationAngle")).value()
298     ),
299     omega_(lookup("omega")),
300     omegaAverage_(omega_),
301     omegaAverageAbsolute_(omega_),
303     A_(3, vector::zero),
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")),
312     coeffs_(13, 0.0),
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_
321     (
322         lookupOrDefault<Switch>
323         (
324             "referentMotionConstraints",
325             false
326         )
327     ),
328     referentRotation_(vector(1, 0, 0), 0)
330     setCoeffs();
334 // Construct as copy
335 Foam::sixDOFqODE::sixDOFqODE
337     const word& name,
338     const sixDOFqODE& sd
341     IOdictionary
342     (
343         IOobject
344         (
345             name,
346             sd.instance(),
347             sd.local(),
348             sd.db(),
349             IOobject::NO_READ,
350             IOobject::NO_WRITE
351         )
352     ),
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_
372     (
373         sd.omegaAverageAbsolute_.name(),
374         sd.omegaAverageAbsolute_
375     ),
377     A_(sd.A_),
378     OmegaDot_(sd.OmegaDot_),
379     An_(sd.An_),
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_),
386     coeffs_(sd.coeffs_),
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)
411     mass_ = sd.mass_;
412     momentOfInertia_ = sd.momentOfInertia_;
414     Xequilibrium_ = sd.Xequilibrium_;
415     linSpringCoeffs_ = sd.linSpringCoeffs_;
416     linDampingCoeffs_ = sd.linDampingCoeffs_;
418     Xrel_ = sd.Xrel_;
419     U_ = sd.U_;
420     Uaverage_ = sd.Uaverage_;
421     rotation_ = sd.rotation_;
422     omega_ = sd.omega_;
423     omegaAverage_ = sd.omegaAverage_;
424     omegaAverageAbsolute_ = sd.omegaAverageAbsolute_;
426     force_ = sd.force_;
427     moment_ = sd.moment_;
428     forceRelative_ = sd.forceRelative_;
429     momentRelative_ = sd.momentRelative_;
431     // Copy ODE coefficients: this carries actual ODE state
432     // HJ, 23/Mar/2015
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
446     const scalar x,
447     const scalarField& y,
448     scalarField& dydx
449 ) const
451     // Set the derivatives for displacement
452     dydx[0] = y[3];
453     dydx[1] = y[4];
454     dydx[2] = y[5];
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
459     (
460         y[9],
461         y[10],
462         y[11],
463         y[12]
464     );
466     const vector accel = A(curX, curU, curRotation).value();
468     dydx[3] = accel.x();
469     dydx[4] = accel.y();
470     dydx[5] = accel.z();
472     // Set the derivatives for rotation
473     dimensionedVector curOmega
474     (
475         "curOmega",
476         dimless/dimTime,
477         vector(y[6], y[7], y[8])
478     );
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
492     if (fixedRoll_)
493     {
494         dydx[10] = 0; // Roll axis (roll quaternion evolution RHS)
495     }
496     if (fixedPitch_)
497     {
498         dydx[11] = 0; // Pitch axis (pitch quaternion evolution RHS)
499     }
500     if (fixedYaw_)
501     {
502         dydx[12] = 0; // Yaw axis (yaw quaternion evolution RHS)
503     }
507 void Foam::sixDOFqODE::jacobian
509     const scalar x,
510     const scalarField& y,
511     scalarField& dfdx,
512     scalarSquareMatrix& dfdy
513 ) const
515     Info << "jacobian(...)" << endl;
516     notImplemented("sixDOFqODE::jacobian(...) const");
520 void Foam::sixDOFqODE::update(const scalar delta)
522     // Update position
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];
531     // Update velocity
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();
546     // Update omega
547     vector& omegaVal = omega_.value();
549     omegaVal.x() = coeffs_[6];
550     omegaVal.y() = coeffs_[7];
551     omegaVal.z() = coeffs_[8];
553     // Constrain omega
554     constrainRotation(omegaVal);
555     coeffs_[6] = omegaVal.x();
556     coeffs_[7] = omegaVal.y();
557     coeffs_[8] = omegaVal.z();
559     rotation_.updateRotation
560     (
561         HamiltonRodriguezRot
562         (
563             coeffs_[9],
564             coeffs_[10],
565             coeffs_[11],
566             coeffs_[12]
567         )
568     );
570     omegaAverage_.value() = rotation_.omegaAverage(delta);
572     // Calculate and constrain omegaAverageAbsolute appropriately
573     vector& omegaAverageAbsoluteValue = omegaAverageAbsolute_.value();
574     omegaAverageAbsoluteValue = rotation_.omegaAverageAbsolute(delta);
576     if (fixedRoll_)
577     {
578         omegaAverageAbsoluteValue.x() = 0;
579     }
580     if (fixedPitch_)
581     {
582         omegaAverageAbsoluteValue.y() = 0;
583     }
584     if (fixedYaw_)
585     {
586         omegaAverageAbsoluteValue.z() = 0;
587     }
591 void Foam::sixDOFqODE::relaxAcceleration
593     const scalar minRelFactor,
594     const scalar maxRelFactor
597     if (minRelFactor - maxRelFactor < SMALL)
598     {
599         // Fixed relaxation
600        relaxFactorT_ = minRelFactor;
601        relaxFactorR_ = minRelFactor;
602     }
603     else
604     {
605         // Use Aitkens relaxation
607         // Update Aitkens relaxation factor
608         aitkensRelaxation(minRelFactor, maxRelFactor);
610         // Update non relaxed accelerations
611         An_[1] = An_[2];
612         An_[2] = (force()/mass_).value();
613         OmegaDotn_[1] = OmegaDotn_[2];
614         OmegaDotn_[2] = (inv(momentOfInertia_) & moment()).value();
615     }
617     const dimensionedVector Aold
618     (
619         "",
620         dimensionSet(0, 1, -2, 0, 0, 0, 0),
621         A_[2]
622     );
624     const dimensionedVector OmegaDotold
625     (
626         "",
627         dimensionSet(0, 0, -2, 0, 0, 0, 0),
628         OmegaDot_[2]
629     );
631     force() =
632         Aold*mass_ + relaxFactorT_*(force() - Aold*mass_);
634     moment() =
635         (momentOfInertia_ & OmegaDotold)
636       + relaxFactorR_*(moment() - (momentOfInertia_ & OmegaDotold));
638     // Update relaxed old accelerations
639     A_[0] = A_[1];
640     A_[1] = A_[2];
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
652     os << *this;
653     return os.good();
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;
703     return os;
707 // ************************************************************************* //