1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM 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 2 of the License, or (at your
14 option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 Hrvoje Jasak, Wikki Ltd. All rights reserved.
28 \*---------------------------------------------------------------------------*/
30 #include "volFields.H"
31 #include "surfaceFields.H"
32 #include "floatingBody.H"
33 #include "transform.H"
34 #include "transformField.H"
35 #include "fixedValueTetPolyPatchFields.H"
37 #include "incompressible/incompressibleTwoPhaseMixture/twoPhaseMixture.H"
38 #include "incompressible/RAS/RASModel/RASModel.H"
39 #include "incompressible/LES/LESModel/LESModel.H"
41 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
43 void Foam::floatingBody::check() const
45 forAll (hullPatches_, patchI)
47 if (!hullPatches_[patchI].active())
49 FatalErrorIn("void floatingBody::check() const")
50 << "Hull patch named " << hullPatches_[patchI].name()
51 << " not found. Available patches: "
52 << mesh_.boundaryMesh().names()
59 Foam::tmp<Foam::volSymmTensorField> Foam::floatingBody::devRhoReff() const
61 if (mesh_.foundObject<incompressible::RASModel>("RASProperties"))
63 const incompressible::RASModel& ras =
64 mesh_.lookupObject<incompressible::RASModel>("RASProperties");
68 else if (mesh_.foundObject<incompressible::LESModel>("LESProperties"))
70 const incompressible::LESModel& les =
71 mesh_.lookupObject<incompressible::LESModel>("LESProperties");
75 else if (mesh_.foundObject<twoPhaseMixture>("transportProperties"))
77 const twoPhaseMixture& twoPhaseProperties =
78 mesh_.lookupObject<twoPhaseMixture>("transportProperties");
80 const volVectorField& U = mesh_.lookupObject<volVectorField>("U");
82 return twoPhaseProperties.nu()*dev(twoSymm(fvc::grad(U)));
86 FatalErrorIn("floatingBody::devRhoReff()")
87 << "No valid model for viscous stress calculation."
90 return volSymmTensorField::null();
95 Foam::vector Foam::floatingBody::dragForce() const
97 // Note: Return zero if there is no flow solution
101 !mesh_.foundObject<volVectorField>("U")
102 || !mesh_.foundObject<volScalarField>("p")
107 "floatingBody::dragForce() const"
108 ) << "No flow solution found. Returning zero."
114 const volScalarField& alpha = mesh_.lookupObject<volScalarField>("alpha1");
115 const volScalarField& p = mesh_.lookupObject<volScalarField>("p");
116 const volVectorField& U = mesh_.lookupObject<volVectorField>("U");
118 const surfaceVectorField::GeometricBoundaryField& Sfb =
119 mesh_.Sf().boundaryField();
121 tmp<volSymmTensorField> tdevRhoReff = devRhoReff();
122 const volSymmTensorField::GeometricBoundaryField& devRhoReffb
123 = tdevRhoReff().boundaryField();
125 vector pressureForce = vector::zero;
126 vector viscousForce = vector::zero;
128 forAll (hullPatches_, patchI)
130 const label curPatch = hullPatches_[patchI].index();
132 // Note: calculating forces on the wetted surface only
138 alpha.boundaryField()[curPatch]*
139 p.boundaryField()[curPatch]*Sfb[curPatch]
145 alpha.boundaryField()[curPatch]*
146 (Sfb[curPatch] & devRhoReffb[curPatch])
150 vector totalForce = pressureForce + viscousForce;
152 Info<< "Pressure force = " << pressureForce << nl
153 << "Viscous force = " << viscousForce << nl
154 << "Total force = " << totalForce << endl;
160 Foam::vector Foam::floatingBody::dragMoment() const
162 // Note: Return zero if there is no flow solution
166 !mesh_.foundObject<volVectorField>("U")
167 || !mesh_.foundObject<volScalarField>("p")
172 "floatingBody::dragForce() const"
173 ) << "No flow solution found. Returning zero."
179 const volScalarField& alpha = mesh_.lookupObject<volScalarField>("alpha1");
180 const volScalarField& p = mesh_.lookupObject<volScalarField>("p");
181 const volVectorField& U = mesh_.lookupObject<volVectorField>("U");
183 const surfaceVectorField::GeometricBoundaryField& Sfb =
184 mesh_.Sf().boundaryField();
186 tmp<volSymmTensorField> tdevRhoReff = devRhoReff();
187 const volSymmTensorField::GeometricBoundaryField& devRhoReffb
188 = tdevRhoReff().boundaryField();
190 vector pressureMoment = vector::zero;
191 vector viscousMoment = vector::zero;
193 forAll (hullPatches_, patchI)
195 // Get index of current patch
196 const label curPatch = hullPatches_[patchI].index();
198 // Note: calculating forces on the wetted surface only
204 (mesh_.Cf().boundaryField()[curPatch] - sixDOF_.X().value())
206 alpha.boundaryField()[curPatch]*
207 p.boundaryField()[curPatch]*Sfb[curPatch]
214 (mesh_.Cf().boundaryField()[curPatch] - sixDOF_.X().value())
216 alpha.boundaryField()[curPatch]*
217 (Sfb[curPatch] & devRhoReffb[curPatch])
222 vector totalMoment = pressureMoment + viscousMoment;
224 Info<< "Pressure moment = " << pressureMoment << nl
225 << "Viscous moment = " << viscousMoment << nl
226 << "Total moment = " << totalMoment << endl;
232 void Foam::floatingBody::fixTranslation(vector& v) const
251 void Foam::floatingBody::fixRotation(vector& rot) const
271 Foam::vector Foam::floatingBody::rotCentreVelocity() const
275 // New position of rotation centroid in absolute coordinate system
276 transform(sixDOF_.toAbsolute(), centreOfSlider_)
277 // Motion of centre of gravity
278 + sixDOF_.X().value()
279 // Old position of rotation centroid
281 )/mesh_.time().deltaT().value();
285 Foam::tmp<Foam::vectorField> Foam::floatingBody::boundaryVelocity
287 const vectorField& boundaryPoints
291 // Translation of centroid
293 // Rotation around centroid
295 // New points,scaled around centroid
298 sixDOF_.rotIncrementTensor().T(),
299 boundaryPoints - rotCentre_
301 // Old points, scaled around centroid
302 - (boundaryPoints - rotCentre_)
303 )/mesh_.time().deltaT().value();
307 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
309 Foam::floatingBody::floatingBody
313 const dictionary& dict
320 hullSlider_(word(dict.lookup("hullSlider")), mesh_.boundaryMesh()),
321 hullSliderZone_(word(dict.lookup("hullSliderZone")), mesh_.faceZones()),
322 fixedSlider_(word(dict.lookup("fixedSlider")), mesh_.boundaryMesh()),
323 fixedSliderZone_(word(dict.lookup("fixedSliderZone")), mesh_.faceZones()),
324 centreOfSlider_(dict.lookup("centreOfSlider")),
326 addPropulsionForce_(dict.lookup("addPropulsionForce")),
327 propulsionDirection_(dict.lookup("propulsionDirection")),
328 propulsionForceCentroid_(dict.lookup("propulsionForceCentroid")),
335 mesh_.time().timeName(),
346 dict.lookup("odeSolver"),
350 epsilon_(readScalar(dict.lookup("epsilon"))),
352 fixedSurge_(dict.lookup("fixedSurge")),
353 fixedSway_(dict.lookup("fixedSway")),
354 fixedHeave_(dict.lookup("fixedHeave")),
355 fixedRoll_(dict.lookup("fixedRoll")),
356 fixedPitch_(dict.lookup("fixedPitch")),
357 fixedYaw_(dict.lookup("fixedYaw")),
359 steadyState_(dict.lookup("steadyState")),
361 rotCentre_(sixDOF_.X().value()),
362 oldForce_(vector::zero),
363 oldMoment_(vector::zero),
364 // Dealing with writing a motion file in parallel. HJ, 14/Aug/2008
365 of_(mesh_.time().caseConstant()/".."/name_ + ".dat")
367 // Read hull patch names
368 wordList hullPatchNames(dict.lookup("hullPatches"));
370 hullPatches_.setSize(hullPatchNames.size());
372 forAll (hullPatchNames, patchI)
379 hullPatchNames[patchI],
385 // Rescale propulsion direction vector
386 if (mag(propulsionDirection_) < SMALL)
390 "floatingBody::floatingBody(const word& name, const fvMesh& mesh,"
391 "const dictionary& dict)"
392 ) << " Incorrect propulsion direction: " << propulsionDirection_
393 << abort(FatalError);
397 propulsionDirection_ /= mag(propulsionDirection_);
400 // Block (initial) motion components as requested
403 fixTranslation(sixDOF_.U().value());
406 fixRotation(sixDOF_.omega().value());
412 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
414 void Foam::floatingBody::setMotion(tetPointVectorField& motionU)
416 // Calculate forces and moments
417 vector curForce = dragForce();
418 vector curMoment = dragMoment();
420 if (addPropulsionForce_)
422 // Here, curForce = drag. HJ, 11/Mar/2009
424 const vector propulsionForce =
425 - propulsionDirection_*(propulsionDirection_ & curForce);
427 const vector propulsionMoment =
429 (propulsionForceCentroid_ - sixDOF_.X().value())
433 Info<< "Propulsion force = " << propulsionForce
434 << " Propulsion moment = " << propulsionMoment << endl;
436 curForce += propulsionForce;
437 curMoment += propulsionMoment;
440 const uniformDimensionedVectorField& g =
441 mesh_.lookupObject<uniformDimensionedVectorField>("g");
443 // Grab initial force for the first time-step
444 if (curTimeIndex_ == -1)
446 oldForce_ = curForce;
447 oldMoment_ = curMoment;
448 curTimeIndex_ = mesh_.time().timeIndex();
451 // Set force and moment
452 sixDOF_.force().value() =
453 0.5*(curForce + oldForce_)
454 + sixDOF_.mass().value()*g.value();
456 sixDOF_.moment().value() =
457 0.5*(curMoment + oldMoment_);
459 // Manage multiple calls to mesh motion within a single time-step
460 if (curTimeIndex_ < mesh_.time().timeIndex())
462 oldForce_ = curForce;
463 oldMoment_ = curMoment;
464 curTimeIndex_ = mesh_.time().timeIndex();
467 // Manage steady-state: reset velocities to zero
470 sixDOF_.U().value() = vector::zero;
471 sixDOF_.omega().value() = vector::zero;
475 // Block motion components as requested
478 fixTranslation(sixDOF_.force().value());
481 fixRotation(sixDOF_.moment().value());
484 // Grab centre of rotation before the ODE solution
485 rotCentre_ = sixDOF_.X().value()
486 + transform(sixDOF_.toAbsolute(), centreOfSlider_);
491 mesh_.time().value(),
492 mesh_.time().value() + mesh_.time().deltaT().value(),
494 mesh_.time().deltaT().value()
497 Info<< "body: " << name() << nl
498 << "f = " << sixDOF_.force().value() << tab
499 << "mg = " << sixDOF_.mass().value()*g.value() << tab
500 << "M = " << sixDOF_.moment().value() << nl
501 << "x = " << sixDOF_.X().value() << tab
502 << "u = " << sixDOF_.Uaverage().value() << nl
503 << "rot vector = " << sixDOF_.rotVector() << tab
504 << "rot angle = " << sixDOF_.rotAngle().value() << tab
505 << "omega = " << sixDOF_.omegaAverageAbsolute().value() << endl;
507 // Set boundary motion on the hull patches
508 forAll (hullPatches_, patchI)
510 fixedValueTetPolyPatchVectorField& motionUHull =
511 refCast<fixedValueTetPolyPatchVectorField>
513 motionU.boundaryField()[hullPatches_[patchI].index()]
516 // Set motion based on current hull geometry
520 motionUHull.patch().localPoints()
524 // Set motion on slider surfaces
525 if (hullSlider_.active())
527 fixedValueTetPolyPatchVectorField& motionUHullSlider =
528 refCast<fixedValueTetPolyPatchVectorField>
530 motionU.boundaryField()[hullSlider_.index()]
536 motionUHullSlider.patch().localPoints()
540 if (fixedSlider_.active())
542 fixedValueTetPolyPatchVectorField& motionUFixedSlider =
543 refCast<fixedValueTetPolyPatchVectorField>
545 motionU.boundaryField()[fixedSlider_.index()]
548 motionUFixedSlider == rotCentreVelocity();
552 // Report position and rotation. Write only if master
553 if (Pstream::master())
555 of_ << mesh_.time().value() << tab;
560 of_ << sixDOF_.X().value().x() << tab;
565 of_ << sixDOF_.X().value().y() << tab;
570 of_ << sixDOF_.X().value().z() << tab;
574 if (!fixedRoll_ || !fixedPitch_ || !fixedYaw_)
576 of_ << sixDOF_.rotAngle().value() << tab;
584 void Foam::floatingBody::correctMotion(vectorField& newAllPoints) const
586 // Adjust motion of slider zone points
587 if (hullSliderZone_.active())
589 // Hull slider zone takes translation and rotation
590 const pointField newP =
593 mesh_.faceZones()[hullSliderZone_.index()]().localPoints()
596 const labelList& addr =
597 mesh_.faceZones()[hullSliderZone_.index()]().meshPoints();
601 if (addr[i] >= mesh_.nPoints())
603 newAllPoints[addr[i]] += newP[i]*mesh_.time().deltaT().value();
608 if (fixedSliderZone_.active())
610 // Fixed slider zone takes translation only
611 const vector rcv = rotCentreVelocity();
613 const labelList& addr =
614 mesh_.faceZones()[fixedSliderZone_.index()]().meshPoints();
618 if (addr[i] >= mesh_.nPoints())
620 newAllPoints[addr[i]] += rcv*mesh_.time().deltaT().value();
627 // ************************************************************************* //