KinematicParcel.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-2015 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 "KinematicParcel.H"
27 #include "forceSuSp.H"
28 #include "IntegrationScheme.H"
29 #include "meshTools.H"
30 #include "cloudSolution.H"
31 
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 
34 template<class ParcelType>
36 
37 
38 // * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * * //
39 
40 template<class ParcelType>
41 template<class TrackData>
43 (
44  TrackData& td,
45  const scalar dt,
46  const label cellI
47 )
48 {
49  tetIndices tetIs = this->currentTetIndices();
50 
51  rhoc_ = td.rhoInterp().interpolate(this->position(), tetIs);
52 
53  if (rhoc_ < td.cloud().constProps().rhoMin())
54  {
55  if (debug)
56  {
58  << "Limiting observed density in cell " << cellI << " to "
59  << td.cloud().constProps().rhoMin() << nl << endl;
60  }
61 
62  rhoc_ = td.cloud().constProps().rhoMin();
63  }
64 
65  Uc_ = td.UInterp().interpolate(this->position(), tetIs);
66 
67  muc_ = td.muInterp().interpolate(this->position(), tetIs);
68 
69  // Apply dispersion components to carrier phase velocity
70  Uc_ = td.cloud().dispersion().update
71  (
72  dt,
73  cellI,
74  U_,
75  Uc_,
76  UTurb_,
77  tTurb_
78  );
79 }
80 
81 
82 template<class ParcelType>
83 template<class TrackData>
85 (
86  TrackData& td,
87  const scalar dt,
88  const label cellI
89 )
90 {
91  Uc_ += td.cloud().UTrans()[cellI]/massCell(cellI);
92 }
93 
94 
95 template<class ParcelType>
96 template<class TrackData>
98 (
99  TrackData& td,
100  const scalar dt,
101  const label cellI
102 )
103 {
104  // Define local properties at beginning of time step
105  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
106  const scalar np0 = nParticle_;
107  const scalar mass0 = mass();
108 
109  // Reynolds number
110  const scalar Re = this->Re(U_, d_, rhoc_, muc_);
111 
112 
113  // Sources
114  //~~~~~~~~
115 
116  // Explicit momentum source for particle
117  vector Su = vector::zero;
118 
119  // Linearised momentum source coefficient
120  scalar Spu = 0.0;
121 
122  // Momentum transfer from the particle to the carrier phase
123  vector dUTrans = vector::zero;
124 
125 
126  // Motion
127  // ~~~~~~
128 
129  // Calculate new particle velocity
130  this->U_ = calcVelocity(td, dt, cellI, Re, muc_, mass0, Su, dUTrans, Spu);
131 
132 
133  // Accumulate carrier phase source terms
134  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
135  if (td.cloud().solution().coupled())
136  {
137  // Update momentum transfer
138  td.cloud().UTrans()[cellI] += np0*dUTrans;
139 
140  // Update momentum transfer coefficient
141  td.cloud().UCoeff()[cellI] += np0*Spu;
142  }
143 }
144 
145 
146 template<class ParcelType>
147 template<class TrackData>
149 (
150  TrackData& td,
151  const scalar dt,
152  const label cellI,
153  const scalar Re,
154  const scalar mu,
155  const scalar mass,
156  const vector& Su,
157  vector& dUTrans,
158  scalar& Spu
159 ) const
160 {
161  typedef typename TrackData::cloudType cloudType;
162  typedef typename cloudType::parcelType parcelType;
163  typedef typename cloudType::forceType forceType;
164 
165  const forceType& forces = td.cloud().forces();
166 
167  // Momentum source due to particle forces
168  const parcelType& p = static_cast<const parcelType&>(*this);
169  const forceSuSp Fcp = forces.calcCoupled(p, dt, mass, Re, mu);
170  const forceSuSp Fncp = forces.calcNonCoupled(p, dt, mass, Re, mu);
171  const forceSuSp Feff = Fcp + Fncp;
172  const scalar massEff = forces.massEff(p, mass);
173 
174 
175  // New particle velocity
176  //~~~~~~~~~~~~~~~~~~~~~~
177 
178  // Update velocity - treat as 3-D
179  const vector abp = (Feff.Sp()*Uc_ + (Feff.Su() + Su))/massEff;
180  const scalar bp = Feff.Sp()/massEff;
181 
182  Spu = dt*Feff.Sp();
183 
185  td.cloud().UIntegrator().integrate(U_, dt, abp, bp);
186 
187  vector Unew = Ures.value();
188 
189  // note: Feff.Sp() and Fc.Sp() must be the same
190  dUTrans += dt*(Feff.Sp()*(Ures.average() - Uc_) - Fcp.Su());
191 
192  // Apply correction to velocity and dUTrans for reduced-D cases
193  const polyMesh& mesh = td.cloud().pMesh();
194  meshTools::constrainDirection(mesh, mesh.solutionD(), Unew);
195  meshTools::constrainDirection(mesh, mesh.solutionD(), dUTrans);
196 
197  return Unew;
198 }
199 
200 
201 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
202 
203 template<class ParcelType>
205 (
207 )
208 :
209  ParcelType(p),
210  active_(p.active_),
211  typeId_(p.typeId_),
212  nParticle_(p.nParticle_),
213  d_(p.d_),
214  dTarget_(p.dTarget_),
215  U_(p.U_),
216  rho_(p.rho_),
217  age_(p.age_),
218  tTurb_(p.tTurb_),
219  UTurb_(p.UTurb_),
220  rhoc_(p.rhoc_),
221  Uc_(p.Uc_),
222  muc_(p.muc_)
223 {}
224 
225 
226 template<class ParcelType>
228 (
229  const KinematicParcel<ParcelType>& p,
230  const polyMesh& mesh
231 )
232 :
233  ParcelType(p, mesh),
234  active_(p.active_),
235  typeId_(p.typeId_),
236  nParticle_(p.nParticle_),
237  d_(p.d_),
238  dTarget_(p.dTarget_),
239  U_(p.U_),
240  rho_(p.rho_),
241  age_(p.age_),
242  tTurb_(p.tTurb_),
243  UTurb_(p.UTurb_),
244  rhoc_(p.rhoc_),
245  Uc_(p.Uc_),
246  muc_(p.muc_)
247 {}
248 
249 
250 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
251 
252 template<class ParcelType>
253 template<class TrackData>
255 (
256  TrackData& td,
257  const scalar trackTime
258 )
259 {
260  typename TrackData::cloudType::parcelType& p =
261  static_cast<typename TrackData::cloudType::parcelType&>(*this);
262 
263  td.switchProcessor = false;
264  td.keepParticle = true;
265 
266  const polyMesh& mesh = td.cloud().pMesh();
267  const polyBoundaryMesh& pbMesh = mesh.boundaryMesh();
268  const cloudSolution& solution = td.cloud().solution();
269  const scalarField& cellLengthScale = td.cloud().cellLengthScale();
270 
271  scalar tEnd = (1.0 - p.stepFraction())*trackTime;
272  scalar dtMax = solution.deltaTMax(trackTime);
273 
274  bool tracking = true;
275  label nTrackingStalled = 0;
276 
277  while (td.keepParticle && !td.switchProcessor && tEnd > ROOTVSMALL)
278  {
279  // Apply correction to position for reduced-D cases
281 
282  const point start(p.position());
283 
284  // Set the Lagrangian time-step
285  scalar dt = min(dtMax, tEnd);
286 
287  // Cache the parcel current cell as this will change if a face is hit
288  const label cellI = p.cell();
289 
290  const scalar magU = mag(U_);
291  if (p.active() && tracking && (magU > ROOTVSMALL))
292  {
293  const scalar d = dt*magU;
294  const scalar deltaLMax = solution.deltaLMax(cellLengthScale[cellI]);
295  const scalar dCorr = min(d, deltaLMax);
296  dt *=
297  dCorr/d
298  *p.trackToFace(p.position() + dCorr*U_/magU, td);
299  }
300 
301  tEnd -= dt;
302 
303  const scalar newStepFraction = 1.0 - tEnd/trackTime;
304 
305  if (tracking)
306  {
307  if
308  (
309  mag(p.stepFraction() - newStepFraction)
311  )
312  {
313  nTrackingStalled++;
314 
315  if (nTrackingStalled > maxTrackAttempts)
316  {
317  tracking = false;
318  }
319  }
320  else
321  {
322  nTrackingStalled = 0;
323  }
324  }
325 
326  p.stepFraction() = newStepFraction;
327 
328  bool calcParcel = true;
329  if (!tracking && solution.steadyState())
330  {
331  calcParcel = false;
332  }
333 
334  // Avoid problems with extremely small timesteps
335  if ((dt > ROOTVSMALL) && calcParcel)
336  {
337  // Update cell based properties
338  p.setCellValues(td, dt, cellI);
339 
340  if (solution.cellValueSourceCorrection())
341  {
342  p.cellValueSourceCorrection(td, dt, cellI);
343  }
344 
345  p.calc(td, dt, cellI);
346  }
347 
348  if (p.onBoundary() && td.keepParticle)
349  {
350  if (isA<processorPolyPatch>(pbMesh[p.patch(p.face())]))
351  {
352  td.switchProcessor = true;
353  }
354  }
355 
356  p.age() += dt;
357 
358  td.cloud().functions().postMove(p, cellI, dt, start, td.keepParticle);
359  }
360 
361  return td.keepParticle;
362 }
363 
364 
365 template<class ParcelType>
366 template<class TrackData>
368 {
369  typename TrackData::cloudType::parcelType& p =
370  static_cast<typename TrackData::cloudType::parcelType&>(*this);
371 
372  td.cloud().functions().postFace(p, p.face(), td.keepParticle);
373 }
374 
375 
376 template<class ParcelType>
378 {}
379 
380 
381 template<class ParcelType>
382 template<class TrackData>
384 (
385  const polyPatch& pp,
386  TrackData& td,
387  const label patchI,
388  const scalar trackFraction,
389  const tetIndices& tetIs
390 )
391 {
392  typename TrackData::cloudType::parcelType& p =
393  static_cast<typename TrackData::cloudType::parcelType&>(*this);
394 
395  // Invoke post-processing model
396  td.cloud().functions().postPatch
397  (
398  p,
399  pp,
400  trackFraction,
401  tetIs,
402  td.keepParticle
403  );
404 
405  // Invoke surface film model
406  if (td.cloud().surfaceFilm().transferParcel(p, pp, td.keepParticle))
407  {
408  // All interactions done
409  return true;
410  }
411  else
412  {
413  // Invoke patch interaction model
414  return td.cloud().patchInteraction().correct
415  (
416  p,
417  pp,
418  td.keepParticle,
419  trackFraction,
420  tetIs
421  );
422  }
423 }
424 
425 
426 template<class ParcelType>
427 template<class TrackData>
429 (
430  const processorPolyPatch&,
431  TrackData& td
432 )
433 {
434  td.switchProcessor = true;
435 }
436 
437 
438 template<class ParcelType>
439 template<class TrackData>
441 (
442  const wallPolyPatch& wpp,
443  TrackData& td,
444  const tetIndices&
445 )
446 {
447  // Wall interactions handled by generic hitPatch function
448 }
449 
450 
451 template<class ParcelType>
452 template<class TrackData>
454 (
455  const polyPatch&,
456  TrackData& td
457 )
458 {
459  td.keepParticle = false;
460 
461  td.cloud().patchInteraction().addToEscapedParcels(nParticle_*mass());
462 }
463 
464 
465 template<class ParcelType>
467 {
468  ParcelType::transformProperties(T);
469 
470  U_ = transform(T, U_);
471 }
472 
473 
474 template<class ParcelType>
476 (
477  const vector& separation
478 )
479 {
480  ParcelType::transformProperties(separation);
481 }
482 
483 
484 template<class ParcelType>
486 (
487  const vector&
488 ) const
489 {
490  return 0.5*d_;
491 }
492 
493 
494 // * * * * * * * * * * * * * * IOStream operators * * * * * * * * * * * * * //
495 
496 #include "KinematicParcelIO.C"
497 
498 // ************************************************************************* //
Foam::meshTools::constrainDirection
void constrainDirection(const polyMesh &mesh, const Vector< label > &dirs, vector &d)
Set the constrained components of directions/velocity to zero.
Definition: meshTools.C:664
Foam::Tensor
Templated 3D tensor derived from VectorSpace adding construction from 9 components,...
Definition: complexI.H:224
meshTools.H
Foam::IntegrationScheme::integrationResult::value
Type value() const
Return const access to the value.
Definition: IntegrationScheme.H:81
Foam::forceSuSp::Sp
scalar Sp() const
Return const access to the implicit coefficient [kg/s].
Definition: forceSuSpI.H:62
Foam::solution
Selector class for relaxation factors, solver type and solution.
Definition: solution.H:48
p
p
Definition: pEqn.H:62
Foam::KinematicParcel::cellValueSourceCorrection
void cellValueSourceCorrection(TrackData &td, const scalar dt, const label cellI)
Correct cell values using latest transfer information.
Definition: KinematicParcel.C:85
Foam::polyBoundaryMesh
Foam::polyBoundaryMesh.
Definition: polyBoundaryMesh.H:60
Foam::particle::minStepFractionTol
static const scalar minStepFractionTol
Minimum stepFraction tolerance.
Definition: particle.H:329
Foam::constant::physicoChemical::mu
const dimensionedScalar mu
Atomic mass unit.
Definition: createFields.H:13
Foam::KinematicParcel::wallImpactDistance
virtual scalar wallImpactDistance(const vector &n) const
The nearest distance to a wall that the particle can be.
Definition: KinematicParcel.C:486
Foam::Re
scalarField Re(const UList< complex > &cf)
Definition: complexFields.C:97
Foam::solution::solution
solution(const solution &)
Disallow default bitwise copy construct and assignment.
forceSuSp.H
Foam::polyMesh::boundaryMesh
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:421
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
Foam::mag
dimensioned< scalar > mag(const dimensioned< Type > &)
Foam::KinematicParcel::calcVelocity
const vector calcVelocity(TrackData &td, const scalar dt, const label cellI, const scalar Re, const scalar mu, const scalar mass, const vector &Su, vector &dUTrans, scalar &Spu) const
Calculate new particle velocity.
Foam::KinematicParcel::move
bool move(TrackData &td, const scalar trackTime)
Move the parcel.
Definition: KinematicParcel.C:255
Foam::polyMesh
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
Foam::transform
dimensionSet transform(const dimensionSet &)
Definition: dimensionSet.C:465
KinematicParcel.H
Foam::label
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
Foam::Field
Pre-declare SubField and related Field type.
Definition: Field.H:57
Foam::fvc::Su
tmp< GeometricField< Type, fvPatchField, volMesh > > Su(const GeometricField< Type, fvPatchField, volMesh > &su, const GeometricField< Type, fvPatchField, volMesh > &vf)
Definition: fvcSup.C:44
Foam::nl
static const char nl
Definition: Ostream.H:260
Foam::polyPatch
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:66
Foam::cloudSolution
Stores all relevant solution info for cloud.
Definition: cloudSolution.H:51
Foam::forceSuSp
Helper container for force Su and Sp terms.
Definition: forceSuSp.H:58
Foam::T
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
Definition: FieldFieldFunctions.C:55
Foam::IntegrationScheme::integrationResult
Helper class to supply results of integration.
Definition: IntegrationScheme.H:57
Foam::KinematicParcel::hitProcessorPatch
void hitProcessorPatch(const processorPolyPatch &, TrackData &td)
Overridable function to handle the particle hitting a.
Definition: KinematicParcel.C:429
Foam::processorPolyPatch
Neighbour processor patch.
Definition: processorPolyPatch.H:55
Foam::IntegrationScheme::integrationResult::average
Type average() const
Return const access to the average.
Definition: IntegrationScheme.H:87
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:18
Foam::wallPolyPatch
Foam::wallPolyPatch.
Definition: wallPolyPatch.H:48
Foam::KinematicParcel::hitFace
void hitFace(int &td)
Overridable function to handle the particle hitting a face.
Foam::forces
This function object calculates the forces and moments by integrating the pressure and skin-friction ...
Definition: forces.H:234
Foam::KinematicParcel::hitPatch
bool hitPatch(const polyPatch &p, TrackData &td, const label patchI, const scalar trackFraction, const tetIndices &tetIs)
Overridable function to handle the particle hitting a patch.
Definition: KinematicParcel.C:384
Foam::tetIndices
Storage and named access for the indices of a tet which is part of the decomposition of a cell.
Definition: tetIndices.H:73
Foam::KinematicParcel::setCellValues
void setCellValues(TrackData &td, const scalar dt, const label cellI)
Set cell values.
Definition: KinematicParcel.C:43
cloudSolution.H
Foam::Vector< scalar >
Foam::KinematicParcel
Kinematic parcel class with rotational motion (as spherical particles only) and one/two-way coupling ...
Definition: KinematicParcel.H:60
Foam::meshTools::constrainToMeshCentre
void constrainToMeshCentre(const polyMesh &mesh, point &pt)
Set the constrained components of position to mesh centre.
Definition: meshTools.C:606
IntegrationScheme.H
Foam::KinematicParcel::transformProperties
virtual void transformProperties(const tensor &T)
Transform the physical properties of the particle.
Definition: KinematicParcel.C:466
Foam::KinematicParcel::KinematicParcel
KinematicParcel(const polyMesh &mesh, const vector &position, const label cellI, const label tetFaceI, const label tetPtI)
Construct from owner, position, and cloud owner.
Foam::KinematicParcel::calc
void calc(TrackData &td, const scalar dt, const label cellI)
Update parcel properties over the time interval.
Definition: KinematicParcel.C:98
Foam::min
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
Foam::forceSuSp::Su
const vector & Su() const
Return const access to the explicit contribution [kg.m/s2].
Definition: forceSuSpI.H:56
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:259
KinematicParcelIO.C
Foam::forces::forces
forces(const forces &)
Disallow default bitwise copy construct.
Foam::KinematicParcel::hitWallPatch
void hitWallPatch(const wallPolyPatch &, TrackData &td, const tetIndices &)
Overridable function to handle the particle hitting a wallPatch.
Definition: KinematicParcel.C:441