sixDoFRigidBodyMotion.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2017 OpenFOAM Foundation
9  Copyright (C) 2016-2023 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "sixDoFRigidBodyMotion.H"
30 #include "sixDoFSolver.H"
31 #include "septernion.H"
32 
33 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
34 
35 void Foam::sixDoFRigidBodyMotion::applyRestraints()
36 {
37  if (restraints_.empty())
38  {
39  return;
40  }
41 
42  if (Pstream::master())
43  {
44  forAll(restraints_, rI)
45  {
46  if (report_)
47  {
48  Info<< "Restraint " << restraints_[rI].name() << ": ";
49  }
50 
51  // Restraint position
52  point rP = Zero;
53 
54  // Restraint force
55  vector rF = Zero;
56 
57  // Restraint moment
58  vector rM = Zero;
59 
60  // Accumulate the restraints
61  restraints_[rI].restrain(*this, rP, rF, rM);
62 
63  // Update the acceleration
64  a() += rF/mass_;
65 
66  // Moments are returned in global axes, transforming to
67  // body local to add to torque.
68  tau() += Q().T() & (rM + ((rP - centreOfRotation()) ^ rF));
69  }
70  }
71 }
72 
73 
74 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
75 
77 :
78  time_(time),
79  motionState_(),
80  motionState0_(),
81  restraints_(),
82  constraints_(),
83  tConstraints_(tensor::I),
84  rConstraints_(tensor::I),
85  initialCentreOfMass_(Zero),
86  initialCentreOfRotation_(Zero),
87  initialQ_(I),
88  mass_(VSMALL),
89  momentOfInertia_(diagTensor::one*VSMALL),
90  aRelax_(1.0),
91  aDamp_(1.0),
92  report_(false),
93  updateConstraints_(false),
94  solver_(nullptr)
95 {}
96 
97 
99 (
100  const dictionary& dict,
101  const dictionary& stateDict,
102  const Time& time
103 )
104 :
105  time_(time),
106  motionState_(stateDict),
107  motionState0_(),
108  restraints_(),
109  constraints_(),
110  tConstraints_(tensor::I),
111  rConstraints_(tensor::I),
112  initialCentreOfMass_
113  (
114  dict.getOrDefault
115  (
116  "initialCentreOfMass",
117  dict.get<vector>("centreOfMass")
118  )
119  ),
120  initialCentreOfRotation_(initialCentreOfMass_),
121  initialQ_
122  (
123  dict.getOrDefault
124  (
125  "initialOrientation",
126  dict.getOrDefault("orientation", tensor::I)
127  )
128  ),
129  mass_(dict.get<scalar>("mass")),
130  momentOfInertia_(dict.get<diagTensor>("momentOfInertia")),
131  aRelax_(dict.getOrDefault<scalar>("accelerationRelaxation", 1)),
132  aDamp_(dict.getOrDefault<scalar>("accelerationDamping", 1)),
133  report_(dict.getOrDefault("report", false)),
134  updateConstraints_(dict.getOrDefault("updateConstraints", false)),
135  solver_(sixDoFSolver::New(dict.subDict("solver"), *this))
136 {
138 
139  // Set constraints and initial centre of rotation
140  // if different to the centre of mass
142 
143  // If the centres of mass and rotation are different ...
144  vector R(initialCentreOfMass_ - initialCentreOfRotation_);
145  if (magSqr(R) > VSMALL)
146  {
147  // ... correct the moment of inertia tensor using parallel axes theorem
148  momentOfInertia_ += mass_*diag(I*magSqr(R) - sqr(R));
149 
150  // ... and if the centre of rotation is not specified for motion state
151  // update it
152  if (!stateDict.found("centreOfRotation"))
153  {
154  motionState_.centreOfRotation() = initialCentreOfRotation_;
155  }
156  }
158  // Save the old-time motion state
159  motionState0_ = motionState_;
160 }
161 
162 
164 (
165  const sixDoFRigidBodyMotion& sDoFRBM
166 )
167 :
168  time_(sDoFRBM.time_),
169  motionState_(sDoFRBM.motionState_),
170  motionState0_(sDoFRBM.motionState0_),
171  restraints_(sDoFRBM.restraints_),
172  constraints_(sDoFRBM.constraints_),
173  tConstraints_(sDoFRBM.tConstraints_),
174  rConstraints_(sDoFRBM.rConstraints_),
175  initialCentreOfMass_(sDoFRBM.initialCentreOfMass_),
176  initialCentreOfRotation_(sDoFRBM.initialCentreOfRotation_),
177  initialQ_(sDoFRBM.initialQ_),
178  mass_(sDoFRBM.mass_),
179  momentOfInertia_(sDoFRBM.momentOfInertia_),
180  aRelax_(sDoFRBM.aRelax_),
181  aDamp_(sDoFRBM.aDamp_),
182  report_(sDoFRBM.report_),
183  updateConstraints_(sDoFRBM.updateConstraints_),
184  solver_(sDoFRBM.solver_.clone())
185 {}
186 
187 
188 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
189 
191 {} // Define here (incomplete type in header)
192 
193 
194 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
195 
197 (
198  const dictionary& dict
199 )
200 {
201  if (dict.found("restraints"))
202  {
203  const dictionary& restraintDict = dict.subDict("restraints");
204 
205  label i = 0;
206 
207  restraints_.setSize(restraintDict.size());
208 
209  for (const entry& dEntry : restraintDict)
210  {
211  if (dEntry.isDict())
212  {
213  restraints_.set
214  (
215  i++,
217  (
218  dEntry.keyword(),
219  dEntry.dict()
220  )
221  );
222  }
223  }
225  restraints_.setSize(i);
226  }
227 }
228 
229 
231 (
232  const dictionary& dict
233 )
234 {
235  if (dict.found("constraints"))
236  {
237  const dictionary& constraintDict = dict.subDict("constraints");
238 
239  label i = 0;
240 
241  constraints_.setSize(constraintDict.size());
242 
243  pointConstraint pct;
244  pointConstraint pcr;
245 
246  for (const entry& dEntry : constraintDict)
247  {
248  if (dEntry.isDict())
249  {
250  constraints_.set
251  (
252  i,
254  (
255  dEntry.keyword(),
256  dEntry.dict(),
257  *this
258  )
259  );
260 
261  constraints_[i].setCentreOfRotation(initialCentreOfRotation_);
262  constraints_[i].constrainTranslation(pct);
263  constraints_[i].constrainRotation(pcr);
264 
265  i++;
266  }
267  }
268 
269  constraints_.setSize(i);
270 
271  tConstraints_ = pct.constraintTransformation();
272  rConstraints_ = pcr.constraintTransformation();
273 
274  Info<< "Translational constraint tensor " << tConstraints_ << nl
275  << "Rotational constraint tensor " << rConstraints_ << endl;
276  }
277 }
278 
279 
280 void Foam::sixDoFRigidBodyMotion::updateAcceleration
281 (
282  const vector& fGlobal,
283  const vector& tauGlobal
284 )
285 {
286  static bool first = true;
287 
288  // Save the previous iteration accelerations for relaxation
289  vector aPrevIter = a();
290  vector tauPrevIter = tau();
291 
292  // Calculate new accelerations
293  a() = fGlobal/mass_;
294  tau() = (Q().T() & tauGlobal);
295  applyRestraints();
296 
297  // Relax accelerations on all but first iteration
298  if (!first)
299  {
300  a() = aRelax_*a() + (1 - aRelax_)*aPrevIter;
301  tau() = aRelax_*tau() + (1 - aRelax_)*tauPrevIter;
302  }
303  else
304  {
305  first = false;
306  }
307 }
308 
309 
310 void Foam::sixDoFRigidBodyMotion::updateConstraints()
311 {
312  if (!updateConstraints_)
313  {
314  return;
315  }
316 
317  pointConstraint pct;
318  pointConstraint pcr;
319 
320  forAll(constraints_, i)
321  {
322  constraints_[i].setCentreOfRotation(initialCentreOfRotation_);
323  constraints_[i].constrainTranslation(pct);
324  constraints_[i].constrainRotation(pcr);
325  }
326 
327  tConstraints_ = pct.constraintTransformation();
328  rConstraints_ = pcr.constraintTransformation();
330  Info<< "Translational constraint tensor " << tConstraints_ << nl
331  << "Rotational constraint tensor " << rConstraints_ << endl;
332 }
333 
334 
336 (
337  bool firstIter,
338  const vector& fGlobal,
339  const vector& tauGlobal,
340  scalar deltaT,
341  scalar deltaT0
342 )
343 {
344  if (Pstream::master())
345  {
346  solver_->solve(firstIter, fGlobal, tauGlobal, deltaT, deltaT0);
347 
348  if (report_)
349  {
350  status();
351  }
352  }
353 
354  Pstream::broadcast(motionState_);
355 }
356 
357 
359 {
360  Info<< "6-DoF rigid body motion" << nl
361  << " Centre of rotation: " << centreOfRotation() << nl
362  << " Centre of mass: " << centreOfMass() << nl
363  << " Orientation: " << orientation() << nl
364  << " Linear velocity: " << v() << nl
365  << " Angular velocity: " << omega()
366  << endl;
367 }
368 
369 
371 (
372  const pointField& initialPoints
373 ) const
374 {
375  return
376  (
377  centreOfRotation()
378  + (Q() & initialQ_.T() & (initialPoints - initialCentreOfRotation_))
379  );
380 }
381 
382 
384 (
385  const pointField& initialPoints,
386  const scalarField& scale
387 ) const
388 {
389  // Calculate the transformation septerion from the initial state
390  septernion s
391  (
392  centreOfRotation() - initialCentreOfRotation(),
393  quaternion(Q().T() & initialQ())
394  );
395 
396  tmp<pointField> tpoints(new pointField(initialPoints));
397  pointField& points = tpoints.ref();
398 
399  forAll(points, pointi)
400  {
401  // Move non-stationary points
402  if (scale[pointi] > SMALL)
403  {
404  // Use solid-body motion where scale = 1
405  if (scale[pointi] > 1 - SMALL)
406  {
407  points[pointi] = transform(initialPoints[pointi]);
408  }
409  // Slerp septernion interpolation
410  else
411  {
412  septernion ss(slerp(septernion::I, s, scale[pointi]));
413 
414  points[pointi] =
415  initialCentreOfRotation()
416  + ss.invTransformPoint
417  (
418  initialPoints[pointi]
419  - initialCentreOfRotation()
420  );
421  }
422  }
423  }
424 
425  return tpoints;
426 }
427 
428 
429 // ************************************************************************* //
Six degree of freedom motion for a rigid body.
List< ReturnType > get(const UPtrList< T > &list, const AccessOp &aop)
List of values generated by applying the access operation to each list item.
void addConstraints(const dictionary &dict)
Add restraints to the motion, public to allow external.
dictionary dict
DiagTensor< scalar > diagTensor
DiagTensor of scalars, i.e. DiagTensor<scalar>.
Definition: diagTensor.H:49
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
const point & centreOfRotation() const
Return the current centre of rotation.
T & ref() const
Return non-const reference to the contents of a non-null managed pointer.
Definition: tmpI.H:235
dimensionedSymmTensor sqr(const dimensionedVector &dv)
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
Tensor< scalar > tensor
Definition: symmTensor.H:57
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tf1, const word &name, const dimensionSet &dimensions, const bool initCopy=false)
Global function forwards to reuseTmpDimensionedField::New.
point transform(const point &initialPoints) const
Transform the given initial state point by the current motion.
Septernion class used to perform translations and rotations in 3D space.
Definition: septernion.H:62
const dictionary & subDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary.
Definition: dictionary.C:441
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:69
static void broadcast(Type &value, const label comm=UPstream::worldComm)
Broadcast content (contiguous or non-contiguous) to all communicator ranks. Does nothing in non-paral...
bool found(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry (const access) with the given keyword.
Definition: dictionaryI.H:104
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
void diag(pointPatchField< vector > &, const pointPatchField< tensor > &)
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
const point & centreOfRotation() const
Return access to the centre of mass.
const pointField & points
static const Identity< scalar > I
Definition: Identity.H:100
Quaternion class used to perform rotations in 3D space.
Definition: quaternion.H:53
Vector< scalar > vector
Definition: vector.H:57
static const septernion I
Definition: septernion.H:84
void status() const
Report the status of the motion.
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
vector invTransformPoint(const vector &v) const
Inverse Transform the given coordinate point.
Definition: septernionI.H:91
static autoPtr< sixDoFRigidBodyMotionRestraint > New(const word &name, const dictionary &sDoFRBMRDict)
Select constructed from the sDoFRBMRDict dictionary and Time.
vector point
Point is a vector.
Definition: point.H:37
#define R(A, B, C, D, E, F, K, M)
quaternion slerp(const quaternion &qa, const quaternion &qb, const scalar t)
Spherical linear interpolation of quaternions.
Definition: quaternion.C:75
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1082
messageStream Info
Information stream (stdout output on master, null elsewhere)
static autoPtr< sixDoFRigidBodyMotionConstraint > New(const word &name, const dictionary &sDoFRBMCDict, const sixDoFRigidBodyMotion &motion)
Select constructed from the sDoFRBMCDict dictionary and Time.
entry * set(entry *entryPtr)
Assign a new entry, overwriting any existing entry.
Definition: dictionary.C:765
sixDoFRigidBodyMotion(const Time &)
Construct null.
A class for managing temporary objects.
Definition: HashPtrTable.H:50
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
dimensionSet transform(const dimensionSet &ds)
Return the argument; transformations do not change the dimensions.
Definition: dimensionSet.C:521
Tensor of scalars, i.e. Tensor<scalar>.
void update(bool firstIter, const vector &fGlobal, const vector &tauGlobal, scalar deltaT, scalar deltaT0)
Symplectic integration of velocities, orientation and position.
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
void addRestraints(const dictionary &dict)
Add restraints to the motion, public to allow external.
A keyword and a list of tokens is an &#39;entry&#39;.
Definition: entry.H:63
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127