forceCoeffs.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-2016 OpenFOAM Foundation
9  Copyright (C) 2015-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 "forceCoeffs.H"
30 #include "dictionary.H"
31 #include "Time.H"
32 #include "Pstream.H"
33 #include "IOmanip.H"
34 #include "fvMesh.H"
35 #include "dimensionedTypes.H"
36 #include "volFields.H"
38 
39 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
40 
41 namespace Foam
42 {
43 namespace functionObjects
44 {
45  defineTypeNameAndDebug(forceCoeffs, 0);
47 }
48 }
49 
50 
51 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
52 
54 {
55  if (initialised_)
56  {
57  return;
58  }
59 
60  initialised_ = true;
61 }
62 
63 
65 {
66  auto* coeffPtr =
67  mesh_.getObjectPtr<volVectorField>(scopedName("forceCoeff"));
68 
69  if (!coeffPtr)
70  {
71  coeffPtr = new volVectorField
72  (
73  IOobject
74  (
75  scopedName("forceCoeff"),
76  time_.timeName(),
77  mesh_,
81  ),
82  mesh_,
84  );
85 
86  mesh_.objectRegistry::store(coeffPtr);
87  }
88 
89  return *coeffPtr;
90 }
91 
92 
94 {
95  auto* coeffPtr =
96  mesh_.getObjectPtr<volVectorField>(scopedName("momentCoeff"));
97 
98  if (!coeffPtr)
99  {
100  coeffPtr = new volVectorField
101  (
102  IOobject
103  (
104  scopedName("momentCoeff"),
105  time_.timeName(),
106  mesh_,
110  ),
111  mesh_,
113  );
114 
115  mesh_.objectRegistry::store(coeffPtr);
116  }
117 
118  return *coeffPtr;
119 }
120 
121 
123 {
124  Cf_.reset();
125  Cm_.reset();
127  forceCoeff() == dimensionedVector(dimless, Zero);
128  momentCoeff() == dimensionedVector(dimless, Zero);
129 }
130 
131 
134 {
135  HashTable<coeffDesc> coeffs(16);
136 
137  coeffs.insert("Cd", coeffDesc("Drag force", "Cd", 0, 0));
138  coeffs.insert("Cs", coeffDesc("Side force", "Cs", 1, 2));
139  coeffs.insert("Cl", coeffDesc("Lift force", "Cl", 2, 1));
140 
141  // Add front/rear options
142  const auto frontRearCoeffs(coeffs);
143  forAllConstIters(frontRearCoeffs, iter)
144  {
145  const auto& fr = iter.val();
146  coeffs.insert(fr.frontName(), fr.front());
147  coeffs.insert(fr.rearName(), fr.rear());
148  }
149 
150  // Add moments
151  coeffs.insert("CmRoll", coeffDesc("Roll moment", "CmRoll", 0, -1));
152  coeffs.insert("CmPitch", coeffDesc("Pitch moment", "CmPitch", 1, -1));
153  coeffs.insert("CmYaw", coeffDesc("Yaw moment", "CmYaw", 2, -1));
154 
155  return coeffs;
156 }
157 
158 
160 {
161  // Calculate scaling factors
162  const scalar pDyn = 0.5*rhoRef_*sqr(magUInf_);
163  const dimensionedScalar forceScaling
164  (
166  scalar(1)/(Aref_*pDyn + SMALL)
167  );
168 
169  const auto& coordSys = coordSysPtr_();
170 
171  // Calculate force coefficients
172  forceCoeff() = forceScaling*force();
173 
174  Cf_.reset
175  (
176  forceScaling.value()*coordSys.localVector(sumPatchForcesP_),
177  forceScaling.value()*coordSys.localVector(sumPatchForcesV_),
178  forceScaling.value()*coordSys.localVector(sumInternalForces_)
179  );
180 }
181 
182 
184 {
185  // Calculate scaling factors
186  const scalar pDyn = 0.5*rhoRef_*sqr(magUInf_);
187  const dimensionedScalar momentScaling
188  (
190  scalar(1)/(Aref_*pDyn*lRef_ + SMALL)
191  );
192 
193  const auto& coordSys = coordSysPtr_();
194 
195  // Calculate moment coefficients
196  momentCoeff() = momentScaling*moment();
197 
198  Cm_.reset
199  (
200  momentScaling.value()*coordSys.localVector(sumPatchMomentsP_),
201  momentScaling.value()*coordSys.localVector(sumPatchMomentsV_),
202  momentScaling.value()*coordSys.localVector(sumInternalMoments_)
203  );
204 }
205 
206 
208 {
209  if (!coeffFilePtr_)
210  {
211  coeffFilePtr_ = newFileAtStartTime("coefficient");
212  writeIntegratedDataFileHeader("Coefficients", coeffFilePtr_());
213  }
214 }
215 
216 
218 (
219  const word& header,
220  OFstream& os
221 ) const
222 {
223  const auto& coordSys = coordSysPtr_();
224 
225  writeHeader(os, "Force and moment coefficients");
226  writeHeaderValue(os, "dragDir", coordSys.e1());
227  writeHeaderValue(os, "sideDir", coordSys.e2());
228  writeHeaderValue(os, "liftDir", coordSys.e3());
229  writeHeaderValue(os, "rollAxis", coordSys.e1());
230  writeHeaderValue(os, "pitchAxis", coordSys.e2());
231  writeHeaderValue(os, "yawAxis", coordSys.e3());
232  writeHeaderValue(os, "magUInf", magUInf_);
233  writeHeaderValue(os, "lRef", lRef_);
234  writeHeaderValue(os, "Aref", Aref_);
235  writeHeaderValue(os, "CofR", coordSys.origin());
236  writeHeader(os, "");
237  writeCommented(os, "Time");
238 
239  for (const auto& iter : coeffs_.csorted())
240  {
241  const auto& coeff = iter.val();
242 
243  if (!coeff.active_) continue;
244 
245  writeTabbed(os, coeff.name_);
246  }
247 
248  os << endl;
249 }
250 
251 
253 {
254  OFstream& os = coeffFilePtr_();
255 
256  writeCurrentTime(os);
257 
258  for (const auto& iter : coeffs_.csorted())
259  {
260  const auto& coeff = iter.val();
261 
262  if (!coeff.active_) continue;
263 
264  const vector coeffValue = coeff.value(Cf_, Cm_);
265 
266  os << tab << (coeffValue.x() + coeffValue.y() + coeffValue.z());
267  }
268 
269  coeffFilePtr_() << endl;
270 }
271 
272 
273 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
274 
276 (
277  const word& name,
278  const Time& runTime,
279  const dictionary& dict,
280  const bool readFields
281 )
282 :
283  forces(name, runTime, dict, false),
284  Cf_(),
285  Cm_(),
286  coeffFilePtr_(),
287  magUInf_(Zero),
288  lRef_(Zero),
289  Aref_(Zero),
290  initialised_(false)
291 {
292  if (readFields)
293  {
294  read(dict);
295  setCoordinateSystem(dict, "liftDir", "dragDir");
297  }
298 }
299 
300 
301 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
302 
304 {
305  if (!forces::read(dict))
306  {
307  return false;
308  }
309 
310  initialised_ = false;
311 
312  // Reference scales
313  dict.readEntry("magUInf", magUInf_);
314  dict.readEntry("lRef", lRef_);
315  dict.readEntry("Aref", Aref_);
316 
317  // If case is compressible we must read rhoInf
318  // (stored in rhoRef_) to calculate the reference dynamic pressure
319  // Note: for incompressible, rhoRef_ is already initialised to 1
320  if (rhoName_ != "rhoInf")
321  {
322  dict.readEntry("rhoInf", rhoRef_);
323  }
324 
325  Info<< " magUInf: " << magUInf_ << nl
326  << " lRef : " << lRef_ << nl
327  << " Aref : " << Aref_ << nl
328  << " rhoInf : " << rhoRef_ << endl;
329 
330  if (min(magUInf_, rhoRef_) < SMALL || min(lRef_, Aref_) < SMALL)
331  {
333  << "Non-zero values are required for reference scales"
334  << exit(FatalIOError);
335 
336  return false;
337  }
338 
339  if (!dict.found("coefficients"))
340  {
341  Info<< " Selecting all coefficients" << nl;
342 
343  coeffs_ = selectCoeffs();
344 
345  for (auto& iter : coeffs_.sorted())
346  {
347  auto& coeff = iter.val();
348  coeff.active_ = true;
349  Info<< " - " << coeff << nl;
350  }
351  }
352  else
353  {
354  const wordHashSet coeffs(dict.get<wordHashSet>("coefficients"));
355 
356  coeffs_ = selectCoeffs();
357 
358  Info<< " Selecting coefficients:" << nl;
359 
360  for (const word& key : coeffs)
361  {
362  auto iter = coeffs_.find(key);
363 
364  if (!iter.good())
365  {
367  << "Unknown coefficient type " << key
368  << " . Valid entries are : " << coeffs_.sortedToc()
369  << exit(FatalIOError);
370  }
371  auto& coeff = iter.val();
372  coeff.active_ = true;
373  Info<< " - " << coeff << nl;
374  }
375  }
376 
378 
379  return true;
380 }
381 
382 
383 
385 {
387 
388  initialise();
389 
390  reset();
391 
392  Log << type() << " " << name() << " write:" << nl
393  << " " << "Coefficient"
394  << tab << "Total"
395  << tab << "Pressure"
396  << tab << "Viscous"
397  << tab << "Internal"
398  << nl;
399 
400  calcForceCoeffs();
401 
402  calcMomentCoeffs();
403 
404  auto logValues = [](const word& name, const vector& coeff, Ostream& os)
405  {
406  os << " " << name << ":"
407  << tab << coeff.x() + coeff.y() + coeff.z()
408  << tab << coeff.x()
409  << tab << coeff.y()
410  << tab << coeff.z()
411  << nl;
412  };
413 
414  // Always setting all results
415  for (const auto& iter : coeffs_.csorted())
416  {
417  const word& coeffName = iter.key();
418  const auto& coeff = iter.val();
419 
420  // Vectors for x:pressure, y:viscous, z:internal
421  const vector coeffValue = coeff.value(Cf_, Cm_);
422 
423  if (log && coeff.active_)
424  {
425  logValues(coeffName, coeffValue, Info);
426  }
427 
428  setResult(coeffName, coeffValue.x() + coeffValue.y() + coeffValue.z());
429  setResult(coeffName & "pressure", coeffValue.x());
430  setResult(coeffName & "viscous", coeffValue.y());
431  setResult(coeffName & "internal", coeffValue.z());
432  }
434  Log << endl;
435 
436  return true;
437 }
438 
439 
441 {
442  if (writeToFile())
443  {
444  Log << " writing force and moment coefficient files." << endl;
445 
446  createIntegratedDataFile();
447 
448  writeIntegratedDataFile();
449  }
450 
451  if (writeFields_)
452  {
453  forceCoeff().write();
454  momentCoeff().write();
455  }
456 
457  Log << endl;
458 
459  return true;
460 }
461 
462 
463 // ************************************************************************* //
const Type & value() const noexcept
Return const reference to value.
dictionary dict
defineTypeNameAndDebug(ObukhovLength, 0)
void calcForceCoeffs()
Calculate force coefficients.
Definition: forceCoeffs.C:152
static bool initialised_(false)
virtual bool write()
Write to data files/fields and to streams.
Definition: forceCoeffs.C:433
static void writeHeader(Ostream &os, const word &fieldName)
dimensionedScalar log(const dimensionedScalar &ds)
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Output to file stream, using an OSstream.
Definition: OFstream.H:49
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
dimensioned< vector > dimensionedVector
Dimensioned vector obtained from generic dimensioned type.
engineTime & runTime
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
constexpr char tab
The tab &#39;\t&#39; character(0x09)
Definition: Ostream.H:49
void writeIntegratedDataFile()
Write integrated coefficients to the integrated-coefficient file.
Definition: forceCoeffs.C:245
Ignore writing from objectRegistry::writeObject()
const dimensionSet dimless
Dimensionless.
volVectorField & momentCoeff()
Return access to the moment coefficients field.
Definition: forceCoeffs.C:86
Abstract base-class for Time/database function objects.
GeometricField< vector, fvPatchField, volMesh > volVectorField
Definition: volFieldsFwd.H:82
HashTable< coeffDesc > selectCoeffs() const
Return the operand coefficients.
Definition: forceCoeffs.C:126
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:69
forceCoeffs(const word &name, const Time &runTime, const dictionary &dict, const bool readFields=true)
Construct from Time and dictionary.
Definition: forceCoeffs.C:269
virtual bool read(const dictionary &dict)
Read the dictionary.
Definition: forces.C:602
Macros for easy insertion into run-time selection tables.
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: POSIX.C:799
virtual void calcForcesMoments()
Calculate forces and moments.
Definition: forces.C:678
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
A class for handling words, derived from Foam::string.
Definition: word.H:63
volScalarField pDyn(IOobject("pDyn", runTime.timeName(), mesh, IOobject::NO_READ, IOobject::AUTO_WRITE), mesh, dimensionedScalar(dimPressure, Zero))
HashSet< word, Hash< word > > wordHashSet
A HashSet of words, uses string hasher.
Definition: HashSet.H:73
void initialise()
Initialise containers and fields.
Definition: forceCoeffs.C:46
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
void reset()
Reset containers and fields.
Definition: forceCoeffs.C:115
void calcMomentCoeffs()
Calculate moment coefficients.
Definition: forceCoeffs.C:176
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
virtual bool read(const dictionary &dict)
Read the dictionary.
Definition: forceCoeffs.C:296
Istream and Ostream manipulators taking arguments.
const dimensionSet dimForce
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
Reads fields from the time directories and adds them to the mesh database for further post-processing...
Definition: readFields.H:151
OBJstream os(runTime.globalPath()/outputName)
volVectorField & forceCoeff()
Return access to the force coefficients field.
Definition: forceCoeffs.C:57
addToRunTimeSelectionTable(functionObject, ObukhovLength, dictionary)
void setCoordinateSystem(const dictionary &dict, const word &e3Name=word::null, const word &e1Name=word::null)
Set the co-ordinate system from dictionary and axes names.
Definition: forces.C:45
Computes force and moment coefficients over a given list of patches, and optionally over given porous...
Definition: forceCoeffs.H:433
void writeIntegratedDataFileHeader(const word &header, OFstream &os) const
Write header to the integrated-coefficient file.
Definition: forceCoeffs.C:211
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:50
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:627
auto key(const Type &t) -> typename std::enable_if< std::is_enum< Type >::value, typename std::underlying_type< Type >::type >::type
Definition: foamGltfBase.H:103
Nothing to be read.
#define Log
Definition: PDRblock.C:28
messageStream Info
Information stream (stdout output on master, null elsewhere)
Computes forces and moments over a given list of patches by integrating pressure and viscous forces a...
Definition: forces.H:317
void createIntegratedDataFile()
Create the integrated-coefficient file.
Definition: forceCoeffs.C:200
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:172
Request registration (bool: true)
virtual bool execute()
Execute the function object.
Definition: forceCoeffs.C:377
Namespace for OpenFOAM.
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
IOerror FatalIOError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL IO ERROR&#39; header text and ...
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127