WallLocalSpringSliderDashpot.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 
27 
28 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
29 
30 template<class CloudType>
32 (
33  scalar& rMin,
34  scalar& rhoMax,
35  scalar& UMagMax
36 ) const
37 {
38  rMin = VGREAT;
39  rhoMax = -VGREAT;
40  UMagMax = -VGREAT;
41 
42  forAllConstIter(typename CloudType, this->owner(), iter)
43  {
44  const typename CloudType::parcelType& p = iter();
45 
46  // Finding minimum diameter to avoid excessive arithmetic
47 
48  scalar dEff = p.d();
49 
50  if (useEquivalentSize_)
51  {
52  dEff *= cbrt(p.nParticle()*volumeFactor_);
53  }
54 
55  rMin = min(dEff, rMin);
56 
57  rhoMax = max(p.rho(), rhoMax);
58 
59  UMagMax = max
60  (
61  mag(p.U()) + mag(p.omega())*dEff/2,
62  UMagMax
63  );
64  }
65 
66  // Transform the minimum diameter into minimum radius
67  // rMin = dMin/2
68 
69  rMin /= 2.0;
70 }
71 
72 
73 template<class CloudType>
75 (
76  typename CloudType::parcelType& p,
77  const point& site,
78  const WallSiteData<vector>& data,
79  scalar pREff,
80  bool cohesion
81 ) const
82 {
83  // wall patch index
84  label wPI = patchMap_[data.patchIndex()];
85 
86  // data for this patch
87  scalar Estar = Estar_[wPI];
88  scalar Gstar = Gstar_[wPI];
89  scalar alpha = alpha_[wPI];
90  scalar b = b_[wPI];
91  scalar mu = mu_[wPI];
92  scalar cohesionEnergyDensity = cohesionEnergyDensity_[wPI];
93  cohesion = cohesion && cohesion_[wPI];
94 
95  vector r_PW = p.position() - site;
96 
97  vector U_PW = p.U() - data.wallData();
98 
99  scalar r_PW_mag = mag(r_PW);
100 
101  scalar normalOverlapMag = max(pREff - r_PW_mag, 0.0);
102 
103  vector rHat_PW = r_PW/(r_PW_mag + VSMALL);
104 
105  scalar kN = (4.0/3.0)*sqrt(pREff)*Estar;
106 
107  scalar etaN = alpha*sqrt(p.mass()*kN)*pow025(normalOverlapMag);
108 
109  vector fN_PW =
110  rHat_PW
111  *(kN*pow(normalOverlapMag, b) - etaN*(U_PW & rHat_PW));
112 
113  // Cohesion force, energy density multiplied by the area of wall/particle
114  // overlap
115  if (cohesion)
116  {
117  fN_PW +=
118  -cohesionEnergyDensity
119  *mathematical::pi*(sqr(pREff) - sqr(r_PW_mag))
120  *rHat_PW;
121  }
122 
123  p.f() += fN_PW;
124 
125  vector USlip_PW =
126  U_PW - (U_PW & rHat_PW)*rHat_PW
127  + (p.omega() ^ (pREff*-rHat_PW));
128 
129  scalar deltaT = this->owner().mesh().time().deltaTValue();
130 
131  vector& tangentialOverlap_PW =
132  p.collisionRecords().matchWallRecord(-r_PW, pREff).collisionData();
133 
134  tangentialOverlap_PW += USlip_PW*deltaT;
135 
136  scalar tangentialOverlapMag = mag(tangentialOverlap_PW);
137 
138  if (tangentialOverlapMag > VSMALL)
139  {
140  scalar kT = 8.0*sqrt(pREff*normalOverlapMag)*Gstar;
141 
142  scalar etaT = etaN;
143 
144  // Tangential force
145  vector fT_PW;
146 
147  if (kT*tangentialOverlapMag > mu*mag(fN_PW))
148  {
149  // Tangential force greater than sliding friction,
150  // particle slips
151 
152  fT_PW = -mu*mag(fN_PW)*USlip_PW/mag(USlip_PW);
153 
154  tangentialOverlap_PW = Zero;
155  }
156  else
157  {
158  fT_PW =
159  -kT*tangentialOverlapMag
160  *tangentialOverlap_PW/tangentialOverlapMag
161  - etaT*USlip_PW;
162  }
163 
164  p.f() += fT_PW;
165 
166  p.torque() += (pREff*-rHat_PW) ^ fT_PW;
167  }
168 }
169 
170 
171 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
172 
173 template<class CloudType>
175 (
176  const dictionary& dict,
177  CloudType& cloud
178 )
179 :
180  WallModel<CloudType>(dict, cloud, typeName),
181  Estar_(),
182  Gstar_(),
183  alpha_(),
184  b_(),
185  mu_(),
186  cohesionEnergyDensity_(),
187  cohesion_(),
188  patchMap_(),
189  maxEstarIndex_(-1),
190  collisionResolutionSteps_
191  (
192  readScalar
193  (
194  this->coeffDict().lookup("collisionResolutionSteps")
195  )
196  ),
197  volumeFactor_(1.0),
198  useEquivalentSize_(Switch(this->coeffDict().lookup("useEquivalentSize")))
199 {
200  if (useEquivalentSize_)
201  {
202  volumeFactor_ = readScalar(this->coeffDict().lookup("volumeFactor"));
203  }
204 
205  scalar pNu = this->owner().constProps().poissonsRatio();
206 
207  scalar pE = this->owner().constProps().youngsModulus();
208 
209  const polyMesh& mesh = cloud.mesh();
210 
211  const polyBoundaryMesh& bMesh = mesh.boundaryMesh();
212 
213  patchMap_.setSize(bMesh.size(), -1);
214 
215  DynamicList<label> wallPatchIndices;
216 
217  forAll(bMesh, patchi)
218  {
219  if (isA<wallPolyPatch>(bMesh[patchi]))
220  {
221  wallPatchIndices.append(bMesh[patchi].index());
222  }
223  }
224 
225  label nWallPatches = wallPatchIndices.size();
226 
227  Estar_.setSize(nWallPatches);
228  Gstar_.setSize(nWallPatches);
229  alpha_.setSize(nWallPatches);
230  b_.setSize(nWallPatches);
231  mu_.setSize(nWallPatches);
232  cohesionEnergyDensity_.setSize(nWallPatches);
233  cohesion_.setSize(nWallPatches);
234 
235  scalar maxEstar = -GREAT;
236 
237  forAll(wallPatchIndices, wPI)
238  {
239  const dictionary& patchCoeffDict
240  (
241  this->coeffDict().subDict(bMesh[wallPatchIndices[wPI]].name())
242  );
243 
244  patchMap_[wallPatchIndices[wPI]] = wPI;
245 
246  scalar nu = readScalar(patchCoeffDict.lookup("poissonsRatio"));
247 
248  scalar E = readScalar(patchCoeffDict.lookup("youngsModulus"));
249 
250  Estar_[wPI] = 1/((1 - sqr(pNu))/pE + (1 - sqr(nu))/E);
251 
252  Gstar_[wPI] = 1/(2*((2 + pNu - sqr(pNu))/pE + (2 + nu - sqr(nu))/E));
253 
254  alpha_[wPI] = readScalar(patchCoeffDict.lookup("alpha"));
255 
256  b_[wPI] = readScalar(patchCoeffDict.lookup("b"));
257 
258  mu_[wPI] = readScalar(patchCoeffDict.lookup("mu"));
259 
260  cohesionEnergyDensity_[wPI] = readScalar
261  (
262  patchCoeffDict.lookup("cohesionEnergyDensity")
263  );
264 
265  cohesion_[wPI] = (mag(cohesionEnergyDensity_[wPI]) > VSMALL);
266 
267  if (Estar_[wPI] > maxEstar)
268  {
269  maxEstarIndex_ = wPI;
270 
271  maxEstar = Estar_[wPI];
272  }
273  }
274 }
275 
276 
277 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
278 
279 template<class CloudType>
281 {}
282 
283 
284 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
285 
286 template<class CloudType>
288 (
289  const typename CloudType::parcelType& p
290 ) const
291 {
292  if (useEquivalentSize_)
293  {
294  return p.d()/2*cbrt(p.nParticle()*volumeFactor_);
295  }
296  else
297  {
298  return p.d()/2;
299  }
300 }
301 
302 
303 template<class CloudType>
305 {
306  return true;
307 }
308 
309 
310 template<class CloudType>
312 {
313  if (!(this->owner().size()))
314  {
315  return 1;
316  }
317 
318  scalar rMin;
319  scalar rhoMax;
320  scalar UMagMax;
321 
322  findMinMaxProperties(rMin, rhoMax, UMagMax);
323 
324  // Note: pi^(7/5)*(5/4)^(2/5) = 5.429675
325  scalar minCollisionDeltaT =
326  5.429675
327  *rMin
328  *pow(rhoMax/(Estar_[maxEstarIndex_]*sqrt(UMagMax) + VSMALL), 0.4)
329  /collisionResolutionSteps_;
330 
331  return ceil(this->owner().time().deltaTValue()/minCollisionDeltaT);
332 }
333 
334 
335 template<class CloudType>
337 (
338  typename CloudType::parcelType& p,
339  const List<point>& flatSitePoints,
340  const List<WallSiteData<vector>>& flatSiteData,
341  const List<point>& sharpSitePoints,
342  const List<WallSiteData<vector>>& sharpSiteData
343 ) const
344 {
345  scalar pREff = this->pREff(p);
346 
347  forAll(flatSitePoints, siteI)
348  {
349  evaluateWall
350  (
351  p,
352  flatSitePoints[siteI],
353  flatSiteData[siteI],
354  pREff,
355  true
356  );
357  }
358 
359  forAll(sharpSitePoints, siteI)
360  {
361  // Treating sharp sites like flat sites, except suppress cohesion
362 
363  evaluateWall
364  (
365  p,
366  sharpSitePoints[siteI],
367  sharpSiteData[siteI],
368  pREff,
369  false
370  );
371  }
372 }
373 
374 
375 // ************************************************************************* //
#define readScalar
Definition: doubleScalar.C:38
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:424
PtrList< dimensionedScalar > rhoMax(fluidRegions.size())
WallLocalSpringSliderDashpot(const dictionary &dict, CloudType &cloud)
Construct from dictionary.
dictionary dict
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:428
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
DSMCCloud< dsmcParcel > CloudType
virtual label nSubCycles() const
For WallModels that control the timestep, calculate the.
virtual scalar pREff(const typename CloudType::parcelType &p) const
Return the effective radius for a particle for the model.
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:137
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:60
dimensionedSymmTensor sqr(const dimensionedVector &dv)
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:163
dimensionedScalar sqrt(const dimensionedScalar &ds)
Forces between particles and walls, interacting with a spring, slider, damper model.
dimensionedScalar pow025(const dimensionedScalar &ds)
A simple wrapper around bool so that it can be read as a word: true/false, on/off, yes/no, y/n, t/f, or none.
Definition: Switch.H:60
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:49
virtual bool controlsTimestep() const
Whether the WallModel has a timestep limit that will.
A list of faces which address into the list of points.
stressControl lookup("compactNormalStress") >> compactNormalStress
dynamicFvMesh & mesh
dimensionedScalar cbrt(const dimensionedScalar &ds)
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:292
static const zero Zero
Definition: zero.H:91
Templated wall interaction class.
Definition: PairCollision.H:51
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:29
Stores the patch ID and templated data to represent a collision with a wall to be passed to the wall ...
Definition: WallSiteData.H:50
void setSize(const label)
Reset size of PtrList. If extending the PtrList, new entries are.
Definition: PtrList.C:131
Foam::polyBoundaryMesh.
ParcelType parcelType
Type of parcel the cloud was instantiated for.
Definition: DSMCCloud.H:218
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
label patchi
vector point
Point is a vector.
Definition: point.H:41
dimensioned< scalar > mag(const dimensioned< Type > &)
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
Templated base class for dsmc cloud.
Definition: DSMCCloud.H:69
volScalarField & nu
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:576