33template<
class CloudType>
34void Foam::PairSpringSliderDashpot<CloudType>::findMinMaxProperties
45 for (
const typename CloudType::parcelType&
p : this->owner())
51 if (useEquivalentSize_)
53 dEff *=
cbrt(
p.nParticle()*volumeFactor_);
56 RMin =
min(dEff, RMin);
83template<
class CloudType>
93 alpha_(this->coeffDict().getScalar(
"alpha")),
94 b_(this->coeffDict().getScalar(
"b")),
95 mu_(this->coeffDict().getScalar(
"mu")),
96 cohesionEnergyDensity_
98 this->coeffDict().getScalar(
"cohesionEnergyDensity")
101 collisionResolutionSteps_
103 this->coeffDict().getScalar(
"collisionResolutionSteps")
106 useEquivalentSize_(
Switch(this->coeffDict().
lookup(
"useEquivalentSize")))
108 if (useEquivalentSize_)
117 Estar_ = E/(2.0*(1.0 -
sqr(
nu)));
119 scalar G = E/(2.0*(1.0 +
nu));
121 Gstar_ = G/(2.0*(2.0 -
nu));
123 cohesion_ = (
mag(cohesionEnergyDensity_) > VSMALL);
129template<
class CloudType>
136template<
class CloudType>
139 if (!(this->owner().size()))
148 findMinMaxProperties(RMin,
rhoMax, UMagMax);
151 scalar minCollisionDeltaT =
155 /collisionResolutionSteps_;
157 return ceil(this->
owner().time().deltaTValue()/minCollisionDeltaT);
161template<
class CloudType>
170 scalar dAEff = pA.d();
172 if (useEquivalentSize_)
174 dAEff *=
cbrt(pA.nParticle()*volumeFactor_);
177 scalar dBEff = pB.d();
179 if (useEquivalentSize_)
181 dBEff *=
cbrt(pB.nParticle()*volumeFactor_);
184 scalar r_AB_mag =
mag(r_AB);
186 scalar normalOverlapMag = 0.5*(dAEff + dBEff) - r_AB_mag;
188 if (normalOverlapMag > 0)
193 scalar forceCoeff = this->forceCoeff(pA, pB);
195 vector rHat_AB = r_AB/(r_AB_mag + VSMALL);
200 scalar
R = 0.5*dAEff*dBEff/(dAEff + dBEff);
203 scalar
M = pA.mass()*pB.mass()/(pA.mass() + pB.mass());
205 scalar kN = (4.0/3.0)*
sqrt(
R)*Estar_;
207 scalar etaN = alpha_*
sqrt(
M*kN)*
pow025(normalOverlapMag);
212 *(kN*
pow(normalOverlapMag, b_) - etaN*(U_AB & rHat_AB));
219 -cohesionEnergyDensity_
220 *overlapArea(dAEff/2.0, dBEff/2.0, r_AB_mag)
230 U_AB - (U_AB & rHat_AB)*rHat_AB
231 - ((dAEff/2*pA.omega() + dBEff/2*pB.omega()) ^ rHat_AB);
233 scalar deltaT = this->owner().mesh().time().deltaTValue();
235 vector& tangentialOverlap_AB =
236 pA.collisionRecords().matchPairRecord
242 vector& tangentialOverlap_BA =
243 pB.collisionRecords().matchPairRecord
249 vector deltaTangentialOverlap_AB = USlip_AB*deltaT;
251 tangentialOverlap_AB += deltaTangentialOverlap_AB;
252 tangentialOverlap_BA += -deltaTangentialOverlap_AB;
254 scalar tangentialOverlapMag =
mag(tangentialOverlap_AB);
256 if (tangentialOverlapMag > VSMALL)
258 scalar kT = 8.0*
sqrt(
R*normalOverlapMag)*Gstar_;
265 if (kT*tangentialOverlapMag > mu_*
mag(fN_AB))
270 fT_AB = -mu_*
mag(fN_AB)*USlip_AB/
mag(USlip_AB);
272 tangentialOverlap_AB =
Zero;
273 tangentialOverlap_BA =
Zero;
277 fT_AB = - kT*tangentialOverlap_AB - etaT*USlip_AB;
285 pA.torque() += (dAEff/2*-rHat_AB) ^ fT_AB;
286 pB.torque() += (dBEff/2*rHat_AB) ^ -fT_AB;
#define R(A, B, C, D, E, F, K, M)
const List< typename ParcelType::constantProperties > & constProps() const
Return all of the constant properties.
const vector & U() const
Return const access to velocity.
Templated pair interaction class.
const dictionary & coeffDict() const
Return the coefficients dictionary.
const dictionary & dict() const
Return the dictionary.
scalar forceCoeff(typename CloudType::parcelType &pA, typename CloudType::parcelType &pB) const
Return the force coefficient based on the forceRampTime_.
const CloudType & owner() const
Return the owner cloud object.
PairModel(CloudType &owner)
Construct null from cloud owner.
virtual label nSubCycles() const
For PairModels that control the timestep, calculate the.
scalar overlapArea(scalar rA, scalar rB, scalar rAB) const
Return the area of overlap between two spheres of radii rA and rB,.
PairSpringSliderDashpot(const dictionary &dict, CloudType &cloud)
Construct from dictionary.
virtual void evaluatePair(typename CloudType::parcelType &pA, typename CloudType::parcelType &pB) const
Calculate the pair interaction between parcels.
virtual bool controlsTimestep() const
Whether the PairModel has a timestep limit that will.
A simple wrapper around bool so that it can be read as a word: true/false, on/off,...
A cloud is a registry collection of lagrangian particles.
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
bool readEntry(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX, IOobjectOption::readOption readOpt=IOobjectOption::MUST_READ) const
Find entry and assign to T val. FatalIOError if it is found and the number of tokens is incorrect,...
vector position() const
Return current particle position.
label origId() const noexcept
Return the particle ID on the originating processor.
label origProc() const noexcept
Return the originating processor ID.
Lookup type of boundary radiation properties.
const dimensionedScalar rhoMax
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
DSMCCloud< dsmcParcel > CloudType
dimensionedSymmTensor sqr(const dimensionedVector &dv)
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
const word GlobalIOList< Tuple2< scalar, vector > >::typeName("scalarVectorTable")
dimensionedScalar sqrt(const dimensionedScalar &ds)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
static constexpr const zero Zero
Global zero (0).
dimensionedScalar cbrt(const dimensionedScalar &ds)
dimensionedScalar pow025(const dimensionedScalar &ds)