ConeNozzleInjection.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 | Copyright (C) 2011-2016 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 "ConeNozzleInjection.H"
27 #include "TimeDataEntry.H"
28 #include "mathematicalConstants.H"
29 #include "distributionModel.H"
30 
31 using namespace Foam::constant;
32 
33 // * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * * //
34 
35 template<class CloudType>
37 {
38  word injectionMethodType = this->coeffDict().lookup("injectionMethod");
39  if (injectionMethodType == "disc")
40  {
41  injectionMethod_ = imDisc;
42  }
43  else if (injectionMethodType == "point")
44  {
45  injectionMethod_ = imPoint;
46 
47  // Set/cache the injector cell
48  this->findCellAtPosition
49  (
50  injectorCell_,
51  tetFaceI_,
52  tetPtI_,
53  position_,
54  false
55  );
56  }
57  else
58  {
59  FatalErrorIn("Foam::InjectionModel<CloudType>::setInjectionMethod()")
60  << "injectionMethod must be either 'point' or 'disc'"
61  << exit(FatalError);
62  }
63 }
64 
65 
66 template<class CloudType>
68 {
69  word flowType = this->coeffDict().lookup("flowType");
70  if (flowType == "constantVelocity")
71  {
72  this->coeffDict().lookup("UMag") >> UMag_;
73  flowType_ = ftConstantVelocity;
74  }
75  else if (flowType == "pressureDrivenVelocity")
76  {
77  Pinj_.reset(this->coeffDict());
78  flowType_ = ftPressureDrivenVelocity;
79  }
80  else if (flowType == "flowRateAndDischarge")
81  {
82  Cd_.reset(this->coeffDict());
83  flowType_ = ftFlowRateAndDischarge;
84  }
85  else
86  {
87  FatalErrorIn("Foam::InjectionModel<CloudType>::setFlowType()")
88  << "flowType must be either 'constantVelocity', "
89  <<"'pressureDrivenVelocity' or 'flowRateAndDischarge'"
90  << exit(FatalError);
91  }
92 }
93 
94 
95 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
96 
97 template<class CloudType>
99 (
100  const dictionary& dict,
101  CloudType& owner,
102  const word& modelName
103 )
104 :
105  InjectionModel<CloudType>(dict, owner, modelName, typeName),
106  injectionMethod_(imPoint),
107  flowType_(ftConstantVelocity),
108  outerDiameter_(readScalar(this->coeffDict().lookup("outerDiameter"))),
109  innerDiameter_(readScalar(this->coeffDict().lookup("innerDiameter"))),
110  duration_(readScalar(this->coeffDict().lookup("duration"))),
111  position_(this->coeffDict().lookup("position")),
112  injectorCell_(-1),
113  tetFaceI_(-1),
114  tetPtI_(-1),
115  direction_(this->coeffDict().lookup("direction")),
116  parcelsPerSecond_
117  (
118  readScalar(this->coeffDict().lookup("parcelsPerSecond"))
119  ),
120  flowRateProfile_
121  (
123  (
124  owner.db().time(),
125  "flowRateProfile",
126  this->coeffDict()
127  )
128  ),
129  thetaInner_
130  (
132  (
133  owner.db().time(),
134  "thetaInner",
135  this->coeffDict()
136  )
137  ),
138  thetaOuter_
139  (
141  (
142  owner.db().time(),
143  "thetaOuter",
144  this->coeffDict()
145  )
146  ),
147  sizeDistribution_
148  (
150  (
151  this->coeffDict().subDict("sizeDistribution"),
152  owner.rndGen()
153  )
154  ),
155  tanVec1_(vector::zero),
156  tanVec2_(vector::zero),
157  normal_(vector::zero),
158 
159  UMag_(0.0),
160  Cd_(owner.db().time(), "Cd"),
161  Pinj_(owner.db().time(), "Pinj")
162 {
163  if (innerDiameter_ >= outerDiameter_)
164  {
166  (
167  "Foam::ConeNozzleInjection<CloudType>::ConeNozzleInjection"
168  "("
169  "const dictionary&, "
170  "CloudType&, "
171  "const word&"
172  ")"
173  )<< "innerNozzleDiameter >= outerNozzleDiameter" << nl
174  << exit(FatalError);
175  }
176 
177  duration_ = owner.db().time().userTimeToTime(duration_);
178 
179  setInjectionMethod();
180 
181  setFlowType();
182 
183  cachedRandom& rndGen = this->owner().rndGen();
184 
185  // Normalise direction vector
186  direction_ /= mag(direction_);
187 
188  // Determine direction vectors tangential to direction
189  vector tangent = vector::zero;
190  scalar magTangent = 0.0;
191 
192  while(magTangent < SMALL)
193  {
194  vector v = rndGen.sample01<vector>();
195 
196  tangent = v - (v & direction_)*direction_;
197  magTangent = mag(tangent);
198  }
199 
200  tanVec1_ = tangent/magTangent;
201  tanVec2_ = direction_^tanVec1_;
202 
203  // Set total volume to inject
204  this->volumeTotal_ = flowRateProfile_.integrate(0.0, duration_);
205 
206  updateMesh();
207 }
208 
209 
210 template<class CloudType>
212 (
214 )
215 :
217  injectionMethod_(im.injectionMethod_),
218  flowType_(im.flowType_),
219  outerDiameter_(im.outerDiameter_),
220  innerDiameter_(im.innerDiameter_),
221  duration_(im.duration_),
222  position_(im.position_),
223  injectorCell_(im.injectorCell_),
224  tetFaceI_(im.tetFaceI_),
225  tetPtI_(im.tetPtI_),
226  direction_(im.direction_),
227  parcelsPerSecond_(im.parcelsPerSecond_),
228  flowRateProfile_(im.flowRateProfile_),
229  thetaInner_(im.thetaInner_),
230  thetaOuter_(im.thetaOuter_),
231  sizeDistribution_(im.sizeDistribution_().clone().ptr()),
232  tanVec1_(im.tanVec1_),
233  tanVec2_(im.tanVec2_),
234  normal_(im.normal_),
235  UMag_(im.UMag_),
236  Cd_(im.Cd_),
237  Pinj_(im.Pinj_)
238 {}
239 
240 
241 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
242 
243 template<class CloudType>
245 {}
246 
247 
248 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
249 
250 template<class CloudType>
252 {
253  // Set/cache the injector cells
254  switch (injectionMethod_)
255  {
256  case imPoint:
257  {
258  this->findCellAtPosition
259  (
260  injectorCell_,
261  tetFaceI_,
262  tetPtI_,
263  position_
264  );
265  }
266  default:
267  {
268  // do nothing
269  }
270  }
271 }
272 
273 
274 template<class CloudType>
276 {
277  return this->SOI_ + duration_;
278 }
279 
280 
281 template<class CloudType>
283 (
284  const scalar time0,
285  const scalar time1
286 )
287 {
288  if ((time0 >= 0.0) && (time0 < duration_))
289  {
290  return floor((time1 - time0)*parcelsPerSecond_);
291  }
292  else
293  {
294  return 0;
295  }
296 }
297 
298 
299 template<class CloudType>
301 (
302  const scalar time0,
303  const scalar time1
304 )
305 {
306  if ((time0 >= 0.0) && (time0 < duration_))
307  {
308  return flowRateProfile_.integrate(time0, time1);
309  }
310  else
311  {
312  return 0.0;
313  }
314 }
315 
316 
317 template<class CloudType>
319 (
320  const label,
321  const label,
322  const scalar,
323  vector& position,
324  label& cellOwner,
325  label& tetFaceI,
326  label& tetPtI
327 )
328 {
329  cachedRandom& rndGen = this->owner().rndGen();
330 
331  scalar beta = mathematical::twoPi*rndGen.sample01<scalar>();
332  normal_ = tanVec1_*cos(beta) + tanVec2_*sin(beta);
333 
334  switch (injectionMethod_)
335  {
336  case imPoint:
337  {
338  position = position_;
339  cellOwner = injectorCell_;
340  tetFaceI = tetFaceI_;
341  tetPtI = tetPtI_;
342 
343  break;
344  }
345  case imDisc:
346  {
347  scalar frac = rndGen.sample01<scalar>();
348  scalar dr = outerDiameter_ - innerDiameter_;
349  scalar r = 0.5*(innerDiameter_ + frac*dr);
350  position = position_ + r*normal_;
351 
352  this->findCellAtPosition
353  (
354  cellOwner,
355  tetFaceI,
356  tetPtI,
357  position,
358  false
359  );
360  break;
361  }
362  default:
363  {
365  (
366  "void Foam::ConeNozzleInjection<CloudType>::setPositionAndCell"
367  "("
368  "const label, "
369  "const label, "
370  "const scalar, "
371  "vector&, "
372  "label&, "
373  "label&, "
374  "label&"
375  ")"
376  )<< "Unknown injectionMethod type" << nl
377  << exit(FatalError);
378  }
379  }
380 }
381 
382 
383 template<class CloudType>
385 (
386  const label parcelI,
387  const label,
388  const scalar time,
389  typename CloudType::parcelType& parcel
390 )
391 {
392  cachedRandom& rndGen = this->owner().rndGen();
393 
394  // set particle velocity
395  const scalar deg2Rad = mathematical::pi/180.0;
396 
397  scalar t = time - this->SOI_;
398  scalar ti = thetaInner_.value(t);
399  scalar to = thetaOuter_.value(t);
400  scalar coneAngle = rndGen.sample01<scalar>()*(to - ti) + ti;
401 
402  coneAngle *= deg2Rad;
403  scalar alpha = sin(coneAngle);
404  scalar dcorr = cos(coneAngle);
405 
406  vector normal = alpha*normal_;
407  vector dirVec = dcorr*direction_;
408  dirVec += normal;
409  dirVec /= mag(dirVec);
410 
411  switch (flowType_)
412  {
413  case ftConstantVelocity:
414  {
415  parcel.U() = UMag_*dirVec;
416  break;
417  }
418  case ftPressureDrivenVelocity:
419  {
420  scalar pAmbient = this->owner().pAmbient();
421  scalar rho = parcel.rho();
422  scalar UMag = ::sqrt(2.0*(Pinj_.value(t) - pAmbient)/rho);
423  parcel.U() = UMag*dirVec;
424  break;
425  }
426  case ftFlowRateAndDischarge:
427  {
428  scalar Ao = 0.25*mathematical::pi*outerDiameter_*outerDiameter_;
429  scalar Ai = 0.25*mathematical::pi*innerDiameter_*innerDiameter_;
430  scalar massFlowRate =
431  this->massTotal()
432  *flowRateProfile_.value(t)
433  /this->volumeTotal();
434 
435  scalar Umag = massFlowRate/(parcel.rho()*Cd_.value(t)*(Ao - Ai));
436  parcel.U() = Umag*dirVec;
437  break;
438  }
439  default:
440  {
441  }
442  }
443 
444  // set particle diameter
445  parcel.d() = sizeDistribution_->sample();
446 }
447 
448 
449 template<class CloudType>
451 {
452  return false;
453 }
454 
455 
456 template<class CloudType>
458 {
459  return true;
460 }
461 
462 
463 // ************************************************************************* //
dimensionedScalar sqrt(const dimensionedScalar &ds)
cachedRandom rndGen(label(0),-1)
virtual bool validInjection(const label parcelI)
Return flag to identify whether or not injection of parcelI is.
virtual ~ConeNozzleInjection()
Destructor.
dimensioned< scalar > mag(const dimensioned< Type > &)
Collection of constants.
dimensionedScalar beta("beta", dimless/dimTemperature, laminarTransport)
virtual void updateMesh()
Set injector locations when mesh is updated.
A class for handling words, derived from string.
Definition: word.H:59
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
virtual bool fullyDescribed() const
Flag to identify whether model fully describes the parcel.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:137
virtual void setPositionAndCell(const label parcelI, const label nParcels, const scalar time, vector &position, label &cellOwner, label &tetFaceI, label &tetPtI)
Set the injection position and owner cell.
virtual void setProperties(const label parcelI, const label nParcels, const scalar time, typename CloudType::parcelType &parcel)
Set the parcel properties.
ParcelType parcelType
Type of parcel the cloud was instantiated for.
Definition: DSMCCloud.H:217
dictionary dict
static const char nl
Definition: Ostream.H:260
stressControl lookup("compactNormalStress") >> compactNormalStress
const dimensionedScalar alpha
Fine-structure constant: default SI units: [].
bool readScalar(const char *buf, doubleScalar &s)
Read whole of buf as a scalar. Return true if succesful.
Definition: doubleScalar.H:63
Templated injection model class.
dimensionedScalar cos(const dimensionedScalar &ds)
ConeNozzleInjection(const dictionary &dict, CloudType &owner, const word &modelName)
Construct from dictionary.
static autoPtr< distributionModel > New(const dictionary &dict, cachedRandom &rndGen)
Selector.
#define FatalErrorIn(functionName)
Report an error message using Foam::FatalError.
Definition: error.H:314
scalar timeEnd() const
Return the end-of-injection time.
error FatalError
Random number generator.
Definition: cachedRandom.H:63
virtual scalar volumeToInject(const scalar time0, const scalar time1)
Volume of parcels to introduce relative to SOI.
static const Vector zero
Definition: Vector.H:80
A normal distribution model.
Type sample01()
Return a sample whose components lie in the range 0-1.
virtual label parcelsToInject(const scalar time0, const scalar time1)
Number of parcels to introduce relative to SOI.
Templated base class for dsmc cloud.
Definition: DSMCCloud.H:68
const scalar twoPi(2 *pi)
dimensionedScalar sin(const dimensionedScalar &ds)