Loading...
Searching...
No Matches
sixDoFRigidBodyMotionAxisConstraint.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-2015 OpenFOAM Foundation
9 Copyright (C) 2023 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
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
32#include "unitConversion.H"
34// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
36namespace Foam
37{
39{
41
43 (
45 axis,
47 );
48}
49}
50
51
52// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
53
54Foam::label Foam::sixDoFRigidBodyMotionConstraints::axis::rotationSector
55(
56 const vector& oldDir,
57 const vector& newDir
58) const
59{
60 const scalar thetaDir = (oldDir ^ newDir) & axis_;
61
62 if (equal(thetaDir, 0))
63 {
64 return 0;
65 }
66
67 return label(sign(thetaDir));
68}
69
70
71bool Foam::sixDoFRigidBodyMotionConstraints::axis::calcDir
72(
73 const vector& fm,
74 const bool rotationSector
75) const
76{
77 const scalar fmDir = axis_ & fm;
78
79 if (equal(fmDir, 0))
80 {
81 return rotationSector;
82 }
84 return (label(sign(fmDir)) == 1) ? true : false;
85}
86
87
88// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
89
91(
92 const word& name,
93 const dictionary& sDoFRBMCDict,
94 const sixDoFRigidBodyMotion& motion
95)
96:
97 sixDoFRigidBodyMotionConstraint(name, sDoFRBMCDict, motion),
98 refQ_(),
99 axis_(),
100 maxCWThetaPtr_(),
101 maxCCWThetaPtr_(),
102 degrees_(false)
104 read(sDoFRBMCDict);
105}
106
107
108// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
109
111(
113) const
114{}
115
116
118(
120) const
121{
122 if (!(maxCWThetaPtr_ && maxCCWThetaPtr_))
123 {
125 return;
126 }
127
128
129 // Calculate principal directions of the body
130 const vector refDir
131 (
132 rotationTensor(vector(1, 0 ,0), axis_) & vector(0, 1, 0)
133 );
134 const vector oldDir
135 (
136 (refQ_ & refDir).removeCollinear(axis_).normalise()
137 );
138 const vector newDir
139 (
140 (motion().orientation() & refDir).removeCollinear(axis_).normalise()
141 );
142
143
144 // Find the index of the rotation sector that the body resides
145 const label rotationSectorIndex = rotationSector(oldDir, newDir);
146
147 if (!rotationSectorIndex)
148 {
149 // The body resides at the reference orientation
151 return;
152 }
153
154 const bool rotationSector = (rotationSectorIndex == 1) ? true : false;
155
156
157 // Calculate the directions of total momentum and force acting on the body
158 const bool angularMomentumDir =
159 calcDir
160 (
161 motion().state().pi(),
162 rotationSector
163 );
164 const bool torqueDir = calcDir(motion().state().tau(), rotationSector);
165
166
167 // Calculate the rotation angle of the body wrt the reference orientation
168 const scalar theta = mag(acos(min(oldDir & newDir, scalar(1))));
169
170
171 // Calculate maximum clockwise and counterclockwise rotation angles
172 const scalar t = motion().time().timeOutputValue();
173 const scalar maxCWTheta =
174 degrees_
175 ? mag(degToRad(maxCWThetaPtr_->value(t)))
176 : mag(maxCWThetaPtr_->value(t));
177
178 const scalar maxCCWTheta =
179 degrees_
180 ? mag(degToRad(maxCCWThetaPtr_->value(t)))
181 : mag(maxCCWThetaPtr_->value(t));
182
183
184 // Apply the constraints according to various conditions
185 if
186 (
187 (rotationSector && (theta < maxCCWTheta))
188 || (!rotationSector && (theta < maxCWTheta))
189 )
190 {
191 pc.combine(pointConstraint(Tuple2<label, vector>(2, axis_)));
192 }
193 else
194 {
195 if (rotationSector == angularMomentumDir)
196 {
197 const scalar magPi = mag(motion().state().pi());
198
199 if (equal(magPi, scalar(0)) && rotationSector != torqueDir)
200 {
201 pc.combine(pointConstraint(Tuple2<label, vector>(2, axis_)));
202 }
203 else
204 {
205 // Constrain all rotational motions
206 pc.combine(pointConstraint(Tuple2<label, vector>(3, Zero)));
207 }
208 }
209 else
210 {
211 // If there is a difference between the directions of
212 // body rotation and of torque, release the body
213 pc.combine(pointConstraint(Tuple2<label, vector>(2, axis_)));
214 }
215 }
216
217
218 if (motion().report())
219 {
220 Info
221 << " old direction = " << oldDir << nl
222 << " new direction = " << newDir << nl
223 << " rotationSector = " << rotationSector << nl
224 << " theta = " << sign((oldDir ^ newDir) & axis_)*theta << nl
225 << " torque = " << motion().state().tau() << nl
226 << " torque dir = " << torqueDir << nl
227 << " angular momentum = " << motion().state().pi() << nl
228 << " angular momentum dir = " << angularMomentumDir << nl
229 << endl;
230 }
231}
232
233
235(
236 const dictionary& sDoFRBMCDict
237)
238{
239 if (!sixDoFRigidBodyMotionConstraint::read(sDoFRBMCDict))
240 {
241 return false;
242 }
243
244 sDoFRBMCCoeffs_.readEntry("axis", axis_);
245
246 axis_.normalise();
247
248 if (mag(axis_) < VSMALL)
249 {
250 FatalIOErrorInFunction(sDoFRBMCDict)
251 << "The entry 'axis' cannot have zero length: " << axis_
252 << exit(FatalIOError);
253 }
254
255
256 if (sDoFRBMCCoeffs_.found("thetaUnits"))
257 {
258 const word thetaUnits(sDoFRBMCCoeffs_.getWord("thetaUnits"));
259
260 if (thetaUnits == "degrees")
261 {
262 degrees_ = true;
263 }
264 else if (thetaUnits == "radians")
265 {
266 degrees_ = false;
267 }
268 else
269 {
270 FatalIOErrorInFunction(sDoFRBMCCoeffs_)
271 << "The units of thetaUnits can be either degrees or radians"
272 << exit(FatalIOError);
273 }
274
275
276 maxCWThetaPtr_.reset
277 (
278 Function1<scalar>::New
279 (
280 "maxClockwiseTheta",
281 sDoFRBMCCoeffs_,
282 &motion().time()
283 )
284 );
285
286 maxCCWThetaPtr_.reset
287 (
288 Function1<scalar>::New
289 (
290 "maxCounterclockwiseTheta",
291 sDoFRBMCCoeffs_,
292 &motion().time()
293 )
294 );
295
296
297 refQ_ =
298 sDoFRBMCCoeffs_.getOrDefault<tensor>("referenceOrientation", I);
299
300 if (mag(mag(refQ_) - sqrt(3.0)) > ROOTSMALL)
301 {
302 FatalIOErrorInFunction(sDoFRBMCCoeffs_)
303 << "The entry 'referenceOrientation' " << refQ_
304 << " is not a rotation tensor. "
305 << "mag(referenceOrientation) - sqrt(3) = "
306 << mag(refQ_) - sqrt(3.0) << nl
307 << exit(FatalIOError);
309 }
310
311 return true;
312}
313
314
316(
317 Ostream& os
318) const
319{
320 os.writeEntry("axis", axis_);
321
322
323 if (maxCWThetaPtr_ && maxCCWThetaPtr_)
324 {
325 if (degrees_)
326 {
327 os.writeEntry("thetaUnits", "degrees");
328 }
329 else
330 {
331 os.writeEntry("thetaUnits", "radians");
332 }
333
334 if (maxCWThetaPtr_)
335 {
336 maxCWThetaPtr_->writeData(os);
337 }
338
339 if (maxCCWThetaPtr_)
340 {
341 maxCCWThetaPtr_->writeData(os);
342 }
343
344 os.writeEntry("referenceOrientation", refQ_);
345 }
346}
347
348
349// ************************************************************************* //
constexpr scalar pi(M_PI)
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition Ostream.H:59
A 2-tuple for storing two objects of dissimilar types. The container is similar in purpose to std::pa...
Definition Tuple2.H:51
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
Accumulates point constraints through successive applications of the applyConstraint function.
void combine(const pointConstraint &)
Combine constraints.
Base class for defining constraints for sixDoF motions.
dictionary sDoFRBMCCoeffs_
Constraint model specific coefficient dictionary.
sixDoFRigidBodyMotionConstraint(const word &name, const dictionary &sDoFRBMCDict, const sixDoFRigidBodyMotion &motion)
Construct from the sDoFRBMCDict dictionary and Time.
const sixDoFRigidBodyMotion & motion() const noexcept
Return const access to motion.
virtual bool read(const dictionary &sDoFRBMCDict)
Update properties from given dictionary.
This constraint imposes an orientation limitation where bodies are restricted to rotate only around a...
virtual void constrainRotation(pointConstraint &) const
Apply and accumulate rotational constraints.
virtual bool read(const dictionary &sDoFRBMCCoeff)
Update properties from given dictionary.
axis(const word &name, const dictionary &sDoFRBMCDict, const sixDoFRigidBodyMotion &motion)
Construct from components.
virtual void constrainTranslation(pointConstraint &) const
Apply and accumulate translational constraints.
Six degree of freedom motion for a rigid body.
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
A class for handling words, derived from Foam::string.
Definition word.H:66
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition error.H:629
OBJstream os(runTime.globalPath()/outputName)
Namespace for six DoF motion constraints.
Namespace for OpenFOAM.
bool read(const char *buf, int32_t &val)
Same as readInt32.
Definition int32.H:127
dimensionedScalar sign(const dimensionedScalar &ds)
tensor rotationTensor(const vector &n1, const vector &n2)
Rotational transformation tensor from vector n1 to n2.
Definition transform.H:47
bool equal(const T &a, const T &b)
Compare two values for equality.
Definition label.H:180
messageStream Info
Information stream (stdout output on master, null elsewhere).
static const Identity< scalar > I
Definition Identity.H:100
Tensor< scalar > tensor
Definition symmTensor.H:57
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
constexpr scalar degToRad() noexcept
Multiplication factor for degrees to radians conversion.
dimensionedScalar sqrt(const dimensionedScalar &ds)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:26
IOerror FatalIOError
Error stream (stdout output on all processes), with additional 'FOAM FATAL IO ERROR' header text and ...
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition exprTraits.C:127
Vector< scalar > vector
Definition vector.H:57
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
dimensionedScalar acos(const dimensionedScalar &ds)
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
Unit conversion functions.