propellerDisk.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2024-2025 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
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
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
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
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "propellerDisk.H"
29 
30 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
31 
32 namespace Foam
33 {
34 namespace fv
35 {
38  (
39  fvModel,
42  );
43 }
44 }
45 
46 
47 // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
48 
50 {
51  phaseName_ = dict.lookupOrDefault<word>("phase", word::null);
52 
53  UName_ = dict.lookupOrDefault<word>
54  (
55  "U",
57  );
58 
59  if (dict.found("centre"))
60  {
61  centre_ = dict.lookup<vector>("centre");
62  }
63  else
64  {
65  const Field<vector> zoneCellCentres(mesh().cellCentres(), zone_.zone());
66  const Field<scalar> zoneCellVolumes(mesh().cellVolumes(), zone_.zone());
67  centre_ = gSum(zoneCellVolumes*zoneCellCentres)/zone_.V();
68  }
69 
70  normal_ = normalised(dict.lookup<vector>("normal"));
71 
72  n_ = dict.lookup<scalar>("n");
73  rotationDir_ = sign(n_);
74  n_ = mag(n_);
75 
76  dProp_ = dict.lookup<scalar>("dPropeller");
77  dHub_ = dict.lookup<scalar>("dHub");
78 
80  Function1<vector2D>::New("propellerCurve", dimless, dimless, dict);
81 
82  log_ = dict.lookupOrDefault<Switch>("log", false);
83 
84  if (log_ && Pstream::master())
85  {
87  logFile_->writeTimeColumnHeaders
88  (
89  {
90  "n",
91  "J",
92  "Jcorr",
93  "Udisk",
94  "Ucorr",
95  "Kt",
96  "Kq",
97  "T/rho",
98  "Q/rho",
99  "force",
100  "moment"
101  }
102  );
103  }
104 
105  bool adjustment(dict.lookupOrDefault<Switch>("adjustment", false));
106 
107  if (adjustment)
108  {
109  if (adjustment_.valid())
110  {
111  adjustment_->readCoeffs(dict);
112  }
113  else
114  {
116  }
117  }
118  else
119  {
120  adjustment_.clear();
121  }
122 }
123 
124 
125 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
126 
127 Foam::scalar Foam::fv::propellerDisk::diskThickness(const vector& centre) const
128 {
129  const Field<vector> zoneCellCentres(mesh().cellCentres(), zone_.zone());
130  const scalar r2 = gMax(magSqr(zoneCellCentres - centre));
131 
132  return zone_.V()/(constant::mathematical::pi*r2);
133 }
134 
135 
137 (
138  const vectorField& U,
139  const vector& nHat
140 ) const
141 {
142  const labelList& cells = zone_.zone();
143  const scalarField& V = mesh().V();
144 
145  scalar VUn = 0;
146  forAll(cells, i)
147  {
148  VUn += V[cells[i]]*(nHat & U[cells[i]]);
149  }
150  reduce(VUn, sumOp<scalar>());
151 
152  const scalar Uref = VUn/zone_.V();
153 
154  return mag(Uref/(n_*dProp_));
155 }
156 
157 
158 Foam::scalar Foam::fv::propellerDisk::n() const
159 {
160  if (adjustment_.valid())
161  {
162  return adjustment_->n();
163  }
164  else
165  {
166  return n_;
167  }
168 }
169 
170 
171 void Foam::fv::propellerDisk::correctn(const scalar T) const
172 {
173  if (adjustment_.valid())
174  {
175  adjustment_->correctn(T);
176  }
177 }
178 
179 
180 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
181 
183 (
184  const word& name,
185  const word& modelType,
186  const fvMesh& mesh,
187  const dictionary& dict
188 )
189 :
190  fvModel(name, modelType, mesh, dict),
191  zone_(mesh, dict),
192  phaseName_(word::null),
193  UName_(word::null),
194  force_(Zero),
195  moment_(Zero),
196  log_(false)
197 {
199 }
200 
201 
202 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
203 
205 {}
206 
207 
208 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
209 
211 {
212  if (fvModel::read(dict))
213  {
214  zone_.read(coeffs(dict));
215  readCoeffs(coeffs(dict));
216  return true;
217  }
218  else
219  {
220  return false;
221  }
222 }
223 
224 
226 {
227  return wordList(1, UName_);
228 }
229 
230 
232 (
233  const volScalarField& alpha,
234  const volScalarField& rho,
235  const volVectorField& U,
236  fvMatrix<vector>& eqn
237 ) const
238 {
239  addActuationDiskAxialInertialResistance
240  (
241  eqn.source(),
242  alpha,
243  rho,
244  U
245  );
246 }
247 
248 
250 (
251  const volVectorField& U,
252  fvMatrix<vector>& eqn
253 ) const
254 {
255  addActuationDiskAxialInertialResistance
256  (
257  eqn.source(),
260  U
261  );
262 }
263 
264 
266 (
267  const volScalarField& rho,
268  const volVectorField& U,
269  fvMatrix<vector>& eqn
270 ) const
271 {
272  addActuationDiskAxialInertialResistance
273  (
274  eqn.source(),
276  rho,
277  U
278  );
279 }
280 
281 
283 {
284  zone_.movePoints();
285  return true;
286 }
287 
288 
290 {
291  zone_.topoChange(map);
292 }
293 
294 
296 {
297  zone_.mapMesh(map);
298 }
299 
300 
302 (
303  const polyDistributionMap& map
304 )
305 {
306  zone_.distribute(map);
307 }
308 
309 
310 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
Macros for easy insertion into run-time selection tables.
static autoPtr< Function1< Type > > New(const word &name, const Function1s::unitSets &units, const dictionary &dict)
Select from dictionary.
Definition: Function1New.C:32
Generic GeometricField class.
static word groupName(Name name, const word &group)
A simple wrapper around bool so that it can be read as a word: true/false, on/off,...
Definition: Switch.H:61
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:423
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
functionObject support for writing log files
Definition: logFile.H:60
scalar V() const
Return const access to the total cell volume.
Definition: fvCellZoneI.H:34
A special matrix type and solver, designed for finite volume solutions of scalar equations....
Definition: fvMatrix.H:118
Field< Type > & source()
Definition: fvMatrix.H:307
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:98
const DimensionedField< scalar, fvMesh > & V() const
Return cell volumes.
Finite volume model abstract base class.
Definition: fvModel.H:60
static const dictionary & coeffs(const word &modelType, const dictionary &)
Return the coefficients sub-dictionary for a given model type.
Definition: fvModelI.H:31
virtual bool read(const dictionary &dict)
Read source dictionary.
Definition: fvModel.C:196
const fvMesh & mesh() const
Return const access to the mesh database.
Definition: fvModelI.H:69
const word & name() const
Return const access to the source name.
Definition: fvModelI.H:57
Disk momentum source which approximates a propeller based on a given propeller curve.
scalar dProp_
Propeller diameter.
virtual bool movePoints()
Update for mesh motion.
virtual ~propellerDisk()
Destructor.
virtual void addSup(const volVectorField &U, fvMatrix< vector > &eqn) const
Source term to momentum equation.
virtual wordList addSupFields() const
Return the list of fields for which the fvModel adds source term.
vector centre_
Propeller disk centre.
word UName_
Name of the velocity field.
virtual void readCoeffs(const dictionary &dict)
Read the model coefficients.
Definition: propellerDisk.C:49
word phaseName_
The name of the phase to which this fvModel applies.
fvCellZone zone_
The cellZone the fvConstraint applies to.
friend class propellerDiskAdjustment
virtual void topoChange(const polyTopoChangeMap &)
Update topology using the given map.
virtual void distribute(const polyDistributionMap &)
Redistribute or update using the given distribution map.
vector normal_
Propeller disk normal direction.
scalar dHub_
Hub diameter.
virtual bool read(const dictionary &dict)
Read dictionary.
scalar diskThickness(const vector &centre) const
Computes the thickness of the disk in streamwise direction.
virtual void mapMesh(const polyMeshMap &)
Update from another mesh using the given map.
autoPtr< propellerDiskAdjustment > adjustment_
autoPtr< Function1< vector2D > > propellerFunction_
Propeller function.
scalar rotationDir_
Rotation direction (obtained from the sign of n_)
scalar n() const
Return the rotation speed.
scalar J(const vectorField &U, const vector &nHat) const
Return the normalised flow-rate through the disk.
propellerDisk(const word &name, const word &modelType, const fvMesh &mesh, const dictionary &dict)
Construct from components.
autoPtr< functionObjects::logFile > logFile_
Optional log file.
void correctn(const scalar T) const
Rotation speed correction.
scalar n_
Rotation speed [1/s].
Switch log_
Optional switch to enable logging of integral properties.
const cellZone & zone() const
Return const access to the cell set.
A class representing the concept of a GeometricField of 1 used to avoid unnecessary manipulations for...
Class containing mesh-to-mesh mapping information after a mesh distribution where we send parts of me...
Class containing mesh-to-mesh mapping information.
Definition: polyMeshMap.H:51
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Template function which returns the un-mangled name of a given type. Useful for types which do not ha...
A class for handling words, derived from string.
Definition: word.H:63
static const word null
An empty word.
Definition: word.H:78
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
const cellShapeList & cells
U
Definition: pEqn.H:72
rho
Definition: pEqn.H:1
volScalarField alpha(IOobject("alpha", runTime.name(), mesh, IOobject::READ_IF_PRESENT, IOobject::AUTO_WRITE), lambda *max(Ua &U, zeroSensitivity))
addToRunTimeSelectionTable(fvConstraint, bound, dictionary)
defineTypeNameAndDebug(bound, 0)
Namespace for OpenFOAM.
static const zero Zero
Definition: zero.H:97
List< word > wordList
A List of words.
Definition: fileName.H:54
const dimensionSet & dimless
Definition: dimensions.C:138
dimensionedScalar sign(const dimensionedScalar &ds)
Type gSum(const UList< Type > &f, const label comm)
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
dimensionSet normalised(const dimensionSet &)
Definition: dimensionSet.C:509
Type gMax(const UList< Type > &f, const label comm)
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
tmp< DimensionedField< scalar, GeoMesh, Field > > mag(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
tmp< DimensionedField< scalar, GeoMesh, Field > > magSqr(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
void T(GeometricField< Type, GeoMesh, PrimitiveField1 > &gf, const GeometricField< Type, GeoMesh, PrimitiveField2 > &gf1)
labelList fv(nPoints)
dictionary dict