1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2008-2011 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
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.
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
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/>.
24 \*---------------------------------------------------------------------------*/
26 #include "PairSpringSliderDashpot.H"
28 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
30 template<class CloudType>
31 void Foam::PairSpringSliderDashpot<CloudType>::findMinMaxProperties
42 forAllConstIter(typename CloudType, this->owner(), iter)
44 const typename CloudType::parcelType& p = iter();
46 // Finding minimum diameter to avoid excessive arithmetic
50 if (useEquivalentSize_)
52 dEff *= cbrt(p.nParticle()*volumeFactor_);
55 RMin = min(dEff, RMin);
57 rhoMax = max(p.rho(), rhoMax);
61 mag(p.U()) + mag(p.omega())*dEff/2,
66 // Transform the minimum diameter into minimum radius
68 // then rMin into minimum R,
69 // 1/RMin = 1/rMin + 1/rMin,
70 // RMin = rMin/2 = dMin/4
74 // Multiply by two to create the worst-case relative velocity
80 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
82 template<class CloudType>
83 Foam::PairSpringSliderDashpot<CloudType>::PairSpringSliderDashpot
85 const dictionary& dict,
89 PairModel<CloudType>(dict, cloud, typeName),
92 alpha_(readScalar(this->coeffDict().lookup("alpha"))),
93 b_(readScalar(this->coeffDict().lookup("b"))),
94 mu_(readScalar(this->coeffDict().lookup("mu"))),
95 cohesionEnergyDensity_
97 readScalar(this->coeffDict().lookup("cohesionEnergyDensity"))
100 collisionResolutionSteps_
102 readScalar(this->coeffDict().lookup("collisionResolutionSteps"))
105 useEquivalentSize_(Switch(this->coeffDict().lookup("useEquivalentSize")))
107 if (useEquivalentSize_)
109 volumeFactor_ = readScalar(this->coeffDict().lookup("volumeFactor"));
112 scalar nu = this->owner().constProps().poissonsRatio();
114 scalar E = this->owner().constProps().youngsModulus();
116 Estar_ = E/(2.0*(1.0 - sqr(nu)));
118 scalar G = E/(2.0*(1.0 + nu));
120 Gstar_ = G/(2.0*(2.0 - nu));
122 cohesion_ = (mag(cohesionEnergyDensity_) > VSMALL);
126 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
128 template<class CloudType>
129 Foam::PairSpringSliderDashpot<CloudType>::~PairSpringSliderDashpot()
133 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
135 template<class CloudType>
136 bool Foam::PairSpringSliderDashpot<CloudType>::controlsTimestep() const
142 template<class CloudType>
143 Foam::label Foam::PairSpringSliderDashpot<CloudType>::nSubCycles() const
145 if (!(this->owner().size()))
154 findMinMaxProperties(RMin, rhoMax, UMagMax);
156 // Note: pi^(7/5)*(5/4)^(2/5) = 5.429675
157 scalar minCollisionDeltaT =
160 *pow(rhoMax/(Estar_*sqrt(UMagMax) + VSMALL), 0.4)
161 /collisionResolutionSteps_;
163 return ceil(this->owner().time().deltaTValue()/minCollisionDeltaT);
167 template<class CloudType>
168 void Foam::PairSpringSliderDashpot<CloudType>::evaluatePair
170 typename CloudType::parcelType& pA,
171 typename CloudType::parcelType& pB
174 vector r_AB = (pA.position() - pB.position());
176 scalar dAEff = pA.d();
178 if (useEquivalentSize_)
180 dAEff *= cbrt(pA.nParticle()*volumeFactor_);
183 scalar dBEff = pB.d();
185 if (useEquivalentSize_)
187 dBEff *= cbrt(pB.nParticle()*volumeFactor_);
190 scalar r_AB_mag = mag(r_AB);
192 scalar normalOverlapMag = 0.5*(dAEff + dBEff) - r_AB_mag;
194 if (normalOverlapMag > 0)
196 //Particles in collision
198 vector rHat_AB = r_AB/(r_AB_mag + VSMALL);
200 vector U_AB = pA.U() - pB.U();
203 scalar R = 0.5*dAEff*dBEff/(dAEff + dBEff);
206 scalar M = pA.mass()*pB.mass()/(pA.mass() + pB.mass());
208 scalar kN = (4.0/3.0)*sqrt(R)*Estar_;
210 scalar etaN = alpha_*sqrt(M*kN)*pow025(normalOverlapMag);
215 *(kN*pow(normalOverlapMag, b_) - etaN*(U_AB & rHat_AB));
221 -cohesionEnergyDensity_
222 *overlapArea(dAEff/2.0, dBEff/2.0, r_AB_mag)
230 U_AB - (U_AB & rHat_AB)*rHat_AB
231 + (pA.omega() ^ (dAEff/2*-rHat_AB))
232 - (pB.omega() ^ (dBEff/2*rHat_AB));
234 scalar deltaT = this->owner().mesh().time().deltaTValue();
236 vector& tangentialOverlap_AB =
237 pA.collisionRecords().matchPairRecord
243 vector& tangentialOverlap_BA =
244 pB.collisionRecords().matchPairRecord
250 vector deltaTangentialOverlap_AB = USlip_AB*deltaT;
252 tangentialOverlap_AB += deltaTangentialOverlap_AB;
253 tangentialOverlap_BA += -deltaTangentialOverlap_AB;
255 scalar tangentialOverlapMag = mag(tangentialOverlap_AB);
257 if (tangentialOverlapMag > VSMALL)
259 scalar kT = 8.0*sqrt(R*normalOverlapMag)*Gstar_;
266 if (kT*tangentialOverlapMag > mu_*mag(fN_AB))
268 // Tangential force greater than sliding friction,
271 fT_AB = -mu_*mag(fN_AB)*USlip_AB/mag(USlip_AB);
273 tangentialOverlap_AB = vector::zero;
274 tangentialOverlap_BA = vector::zero;
279 -kT*tangentialOverlapMag
280 *tangentialOverlap_AB/tangentialOverlapMag
287 pA.torque() += (dAEff/2*-rHat_AB) ^ fT_AB;
288 pB.torque() += (dBEff/2*rHat_AB) ^ -fT_AB;
294 // ************************************************************************* //