Foam::scalar Foam::VirtualMassForce<CloudType>::massAdd ( const typename CloudType::parcelType& p, const scalar mass ) const { return mass*p.rhoc()/p.rho()*Cvm_; }
Foam::scalar Foam::WallLocalSpringSliderDashpot<CloudType>::pREff ( const typename CloudType::parcelType& p ) const { if (useEquivalentSize_) { return p.d()/2*cbrt(p.nParticle()*volumeFactor_); } else { return p.d()/2; } }
Foam::scalar Foam::LambertWall<CloudType>::pREff ( const typename CloudType::parcelType& p ) const { if (useEquivalentSize_) { return p.d()/2*cbrt(p.nParticle()*volumeFactor_); } else { return p.d()/2; } }
void Foam::PatchInjection<CloudType>::setProperties ( const label, const label, const scalar, typename CloudType::parcelType& parcel ) { // set particle velocity parcel.U() = U0_; // set particle diameter parcel.d() = parcelPDF_->sample(); }
void Foam::NoInjection<CloudType>::setProperties ( const label, const label, const scalar, typename CloudType::parcelType& parcel ) { // set particle velocity parcel.U() = vector::zero; // set particle diameter parcel.d() = 0.0; }
void Foam::ManualInjection<CloudType>::setProperties ( const label parcelI, const label, const scalar, typename CloudType::parcelType& parcel ) { // set particle velocity parcel.U() = U0_; // set particle diameter parcel.d() = diameters_[parcelI]; }
Foam::forceSuSp Foam::GravityForce<CloudType>::calcNonCoupled ( const typename CloudType::parcelType& p, const scalar dt, const scalar mass, const scalar Re, const scalar muc ) const { forceSuSp value(vector::zero, 0.0); value.Su() = mass*g_*(1.0 - p.rhoc()/p.rho()); return value; }
Foam::forceSuSp Foam::SphereDragForce<CloudType>::calcCoupled ( const typename CloudType::parcelType& p, const scalar dt, const scalar mass, const scalar Re, const scalar muc ) const { forceSuSp value(vector::zero, 0.0); value.Sp() = mass*0.75*muc*CdRe(Re)/(p.rho()*sqr(p.d())); return value; }
Foam::scalar Foam::NoPendularWall<CloudType>::pREff ( const typename CloudType::parcelType& p ) const { return p.d()/2; }
Foam::forceSuSp Foam::BrownianMotionForce<CloudType>::calcCoupled ( const typename CloudType::parcelType& p, const scalar dt, const scalar mass, const scalar Re, const scalar muc ) const { forceSuSp value(vector::zero, 0.0); const scalar dp = p.d(); const scalar Tc = p.Tc(); const scalar eta = rndGen_.sample01<scalar>(); const scalar alpha = 2.0*lambda_/dp; const scalar cc = 1.0 + alpha*(1.257 + 0.4*exp(-1.1/alpha)); const scalar sigma = physicoChemical::sigma.value(); scalar f = 0.0; if (turbulence_) { const label cellI = p.cell(); const volScalarField& k = *kPtr_; const scalar kc = k[cellI]; const scalar Dp = sigma*Tc*cc/(3*mathematical::pi*muc*dp); f = eta/mass*sqrt(2.0*sqr(kc)*sqr(Tc)/(Dp*dt)); } else { const scalar rhoRatio = p.rho()/p.rhoc(); const scalar s0 = 216*muc*sigma*Tc/(sqr(mathematical::pi)*pow5(dp)*(rhoRatio)*cc); f = eta*sqrt(mathematical::pi*s0/dt); } const scalar sqrt2 = sqrt(2.0); for (label i = 0; i < 3; i++) { const scalar x = rndGen_.sample01<scalar>(); const scalar eta = sqrt2*erfInv(2*x - 1.0); value.Su()[i] = mass*f*eta; } return value; }
Foam::scalar Foam::VariableHardSphere<CloudType>::sigmaTcR ( const typename CloudType::parcelType& pP, const typename CloudType::parcelType& pQ ) const { const CloudType& cloud(this->owner()); label typeIdP = pP.typeId(); label typeIdQ = pQ.typeId(); scalar dPQ = 0.5 *( cloud.constProps(typeIdP).d() + cloud.constProps(typeIdQ).d() ); scalar omegaPQ = 0.5 *( cloud.constProps(typeIdP).omega() + cloud.constProps(typeIdQ).omega() ); scalar cR = mag(pP.U() - pQ.U()); if (cR < VSMALL) { return 0; } scalar mP = cloud.constProps(typeIdP).mass(); scalar mQ = cloud.constProps(typeIdQ).mass(); scalar mR = mP*mQ/(mP + mQ); // calculating cross section = pi*dPQ^2, where dPQ is from Bird, eq. 4.79 scalar sigmaTPQ = pi*dPQ*dPQ *pow(2.0*physicoChemical::k.value()*Tref_/(mR*cR*cR), omegaPQ - 0.5) /exp(Foam::lgamma(2.5 - omegaPQ)); return sigmaTPQ*cR; }
void Foam::ManualInjectionWet<CloudType>::setProperties ( const label parcelI, const label, const scalar, typename CloudType::parcelType& parcel ) { // set particle velocity parcel.U() = U0_; // set particle diameter parcel.d() = diameters_[parcelI]; // set initial liquid volume parcel.Vliq() = iniVliq_; }
Foam::forceSuSp Foam::WenYuDragForce<CloudType>::calcCoupled ( const typename CloudType::parcelType& p, const scalar dt, const scalar mass, const scalar Re, const scalar muc ) const { scalar alphac(alphac_[p.cell()]); return forceSuSp ( vector::zero, (mass/p.rho()) *0.75*CdRe(alphac*Re)*muc*pow(alphac, -2.65)/(alphac*sqr(p.d())) ); }
Foam::forceSuSp Foam::PressureGradientForce<CloudType>::calcCoupled ( const typename CloudType::parcelType& p, const scalar dt, const scalar mass, const scalar Re, const scalar muc ) const { forceSuSp value(Zero, 0.0); vector DUcDt = DUcDtInterp().interpolate(p.position(), p.currentTetIndices()); value.Su() = mass*p.rhoc()/p.rho()*DUcDt; return value; }
void Foam::LambertWall<CloudType>::evaluatePendularWall ( typename CloudType::parcelType& p, const point& site, const WallSiteData<vector>& data, scalar pREff ) const { const scalar& st = this->surfaceTension(); const scalar& ca = this->contactAngle(); const scalar& lf = this->liqFrac(); const scalar& vis = this->viscosity(); const scalar& ms = this->minSep(); scalar Vtot = lf*(p.Vliq()); vector r_PW = p.position() - site; vector U_PW = p.U() - data.wallData(); scalar r_PW_mag = mag(r_PW); scalar normalOverlapMag = pREff - r_PW_mag; scalar S = -normalOverlapMag; vector rHat_PW = r_PW/(r_PW_mag + VSMALL); // Normal force scalar capMag = 4*mathematical::pi*pREff*st*cos(ca)/ (1+max(S, 0)*sqrt(mathematical::pi*pREff/Vtot)); //Info << "the value of capMag is " << capMag << endl; //Info << " the value of overlapMag S is " << S << endl; //Info << " the volume of Vtot is " << Vtot << endl; scalar Svis = max(pREff*ms, S); scalar etaN = 6*mathematical::pi*vis*pREff*pREff/Svis; vector fN_PW = (-capMag - etaN*(U_PW & rHat_PW)) * rHat_PW; p.f() += fN_PW; vector UT_PW = U_PW - (U_PW & rHat_PW)*rHat_PW - ((pREff*p.omega()) ^ rHat_PW); scalar etaT = 6*mathematical::pi*vis*pREff*(8./15.*log(pREff/Svis) + 0.9588); vector fT_PW = -etaT * UT_PW; p.f() += fT_PW; p.torque() += (pREff*-rHat_PW) ^ fT_PW; }
void Foam::VariableHardSphere<CloudType>::collide ( typename CloudType::parcelType& pP, typename CloudType::parcelType& pQ ) { CloudType& cloud(this->owner()); label typeIdP = pP.typeId(); label typeIdQ = pQ.typeId(); vector& UP = pP.U(); vector& UQ = pQ.U(); Random& rndGen(cloud.rndGen()); scalar mP = cloud.constProps(typeIdP).mass(); scalar mQ = cloud.constProps(typeIdQ).mass(); vector Ucm = (mP*UP + mQ*UQ)/(mP + mQ); scalar cR = mag(UP - UQ); scalar cosTheta = 2.0*rndGen.scalar01() - 1.0; scalar sinTheta = sqrt(1.0 - cosTheta*cosTheta); scalar phi = twoPi*rndGen.scalar01(); vector postCollisionRelU = cR *vector ( cosTheta, sinTheta*cos(phi), sinTheta*sin(phi) ); UP = Ucm + postCollisionRelU*mQ/(mP + mQ); UQ = Ucm - postCollisionRelU*mP/(mP + mQ); }
Foam::forceSuSp Foam::ParamagneticForce<CloudType>::calcNonCoupled ( const typename CloudType::parcelType& p, const typename CloudType::parcelType::trackingData& td, const scalar dt, const scalar mass, const scalar Re, const scalar muc ) const { forceSuSp value(Zero, 0.0); const interpolation<vector>& HdotGradHInterp = *HdotGradHInterpPtr_; value.Su()= mass*3.0*constant::electromagnetic::mu0.value()/p.rho() *magneticSusceptibility_/(magneticSusceptibility_ + 3) *HdotGradHInterp.interpolate(p.coordinates(), p.currentTetIndices()); return value; }
Foam::forceSuSp Foam::LiftForce<CloudType>::calcCoupled ( const typename CloudType::parcelType& p, const typename CloudType::parcelType::trackingData& td, const scalar dt, const scalar mass, const scalar Re, const scalar muc ) const { forceSuSp value(Zero, 0.0); vector curlUc = curlUcInterp().interpolate(p.coordinates(), p.currentTetIndices()); scalar Cl = this->Cl(p, td, curlUc, Re, muc); value.Su() = mass/p.rho()*td.rhoc()*Cl*((td.Uc() - p.U())^curlUc); return value; }
void Foam::SwakScriptableInjection<CloudType>::setProperties ( const label parcelI, const label, const scalar, typename CloudType::parcelType& parcel ) { // set particle velocity scalarField U0Vals(particleData_["U0"]); if(U0Vals.size()<3) { FatalErrorIn("void Foam::SwakScriptableInjection<CloudType>::setPositionAndCell") << "Expected a list with at least 3 values. Got " << U0Vals << endl << exit(FatalError); } parcel.U() = vector(U0Vals[0],U0Vals[1],U0Vals[2]); // set particle diameter parcel.d() = readScalar(particleData_["diameter"]); // Info << parcel << endl; }
Foam::forceSuSp Foam::SRFForce<CloudType>::calcNonCoupled ( const typename CloudType::parcelType& p, const scalar dt, const scalar mass, const scalar Re, const scalar muc ) const { forceSuSp value(Zero, 0.0); const typename SRF::SRFModel& srf = *srfPtr_; const vector& omega = srf.omega().value(); const vector& r = p.position(); // Coriolis and centrifugal acceleration terms value.Su() = mass*(1.0 - p.rhoc()/p.rho()) *(2.0*(p.U() ^ omega) + (omega ^ (r ^ omega))); return value; }
Foam::forceSuSp Foam::NonInertialFrameForce<CloudType>::calcNonCoupled ( const typename CloudType::parcelType& p, const scalar dt, const scalar mass, const scalar Re, const scalar muc ) const { forceSuSp value(vector::zero, 0.0); const vector r = p.position() - centreOfRotation_; value.Su() = mass *( -W_ + (r ^ omegaDot_) + 2.0*(p.U() ^ omega_) + (omega_ ^ (r ^ omega_)) ); return value; }
Foam::vector Foam::DampingModels::Relaxation<CloudType>::velocityCorrection ( typename CloudType::parcelType& p, const scalar deltaT ) const { const tetIndices tetIs(p.cell(), p.tetFace(), p.tetPt(), this->owner().mesh()); const scalar x = deltaT*oneByTimeScaleAverage_->interpolate(p.position(), tetIs); const vector u = uAverage_->interpolate(p.position(), tetIs); return (u - p.U())*x/(x + 2.0); }
Foam::forceSuSp Foam::LiftForce<CloudType>::calcCoupled ( const typename CloudType::parcelType& p, const scalar dt, const scalar mass, const scalar Re, const scalar muc ) const { forceSuSp value(vector::zero, 0.0); vector curlUc = curlUcInterp().interpolate(p.position(), p.currentTetIndices()); scalar Cl = this->Cl(p, curlUc, Re, muc); value.Su() = mass/p.rho()*p.d()/2.0*p.rhoc()*Cl*((p.Uc() - p.U())^curlUc); return value; }
void Foam::MaxwellianThermal<CloudType>::correct ( typename CloudType::parcelType& p, const wallPolyPatch& wpp ) { vector& U = p.U(); scalar& Ei = p.Ei(); label typeId = p.typeId(); label wppIndex = wpp.index(); label wppLocalFace = wpp.whichFace(p.face()); vector nw = p.normal(); nw /= mag(nw); // Normal velocity magnitude scalar U_dot_nw = U & nw; // Wall tangential velocity (flow direction) vector Ut = U - U_dot_nw*nw; CloudType& cloud(this->owner()); Random& rndGen(cloud.rndGen()); while (mag(Ut) < SMALL) { // If the incident velocity is parallel to the face normal, no // tangential direction can be chosen. Add a perturbation to the // incoming velocity and recalculate. U = vector ( U.x()*(0.8 + 0.2*rndGen.scalar01()), U.y()*(0.8 + 0.2*rndGen.scalar01()), U.z()*(0.8 + 0.2*rndGen.scalar01()) ); U_dot_nw = U & nw; Ut = U - U_dot_nw*nw; } // Wall tangential unit vector vector tw1 = Ut/mag(Ut); // Other tangential unit vector vector tw2 = nw^tw1; scalar T = cloud.boundaryT().boundaryField()[wppIndex][wppLocalFace]; scalar mass = cloud.constProps(typeId).mass(); scalar iDof = cloud.constProps(typeId).internalDegreesOfFreedom(); U = sqrt(physicoChemical::k.value()*T/mass) *( rndGen.GaussNormal()*tw1 + rndGen.GaussNormal()*tw2 - sqrt(-2.0*log(max(1 - rndGen.scalar01(), VSMALL)))*nw ); U += cloud.boundaryU().boundaryField()[wppIndex][wppLocalFace]; Ei = cloud.equipartitionInternalEnergy(T, iDof); }
void Foam::PairSpringSliderDashpot<CloudType>::evaluatePair ( typename CloudType::parcelType& pA, typename CloudType::parcelType& pB ) const { vector r_AB = (pA.position() - pB.position()); scalar dAEff = pA.d(); if (useEquivalentSize_) { dAEff *= cbrt(pA.nParticle()*volumeFactor_); } scalar dBEff = pB.d(); if (useEquivalentSize_) { dBEff *= cbrt(pB.nParticle()*volumeFactor_); } scalar r_AB_mag = mag(r_AB); scalar normalOverlapMag = 0.5*(dAEff + dBEff) - r_AB_mag; if (normalOverlapMag > 0) { //Particles in collision vector rHat_AB = r_AB/(r_AB_mag + VSMALL); vector U_AB = pA.U() - pB.U(); // Effective radius scalar R = 0.5*dAEff*dBEff/(dAEff + dBEff); // Effective mass scalar M = pA.mass()*pB.mass()/(pA.mass() + pB.mass()); scalar kN = (4.0/3.0)*sqrt(R)*Estar_; scalar etaN = alpha_*sqrt(M*kN)*pow025(normalOverlapMag); // Normal force vector fN_AB = rHat_AB *(kN*pow(normalOverlapMag, b_) - etaN*(U_AB & rHat_AB)); // Cohesion force if (cohesion_) { fN_AB += -cohesionEnergyDensity_ *overlapArea(dAEff/2.0, dBEff/2.0, r_AB_mag) *rHat_AB; } pA.f() += fN_AB; pB.f() += -fN_AB; vector USlip_AB = U_AB - (U_AB & rHat_AB)*rHat_AB + (pA.omega() ^ (dAEff/2*-rHat_AB)) - (pB.omega() ^ (dBEff/2*rHat_AB)); scalar deltaT = this->owner().mesh().time().deltaTValue(); vector& tangentialOverlap_AB = pA.collisionRecords().matchPairRecord ( pB.origProc(), pB.origId() ).collisionData(); vector& tangentialOverlap_BA = pB.collisionRecords().matchPairRecord ( pA.origProc(), pA.origId() ).collisionData(); vector deltaTangentialOverlap_AB = USlip_AB*deltaT; tangentialOverlap_AB += deltaTangentialOverlap_AB; tangentialOverlap_BA += -deltaTangentialOverlap_AB; scalar tangentialOverlapMag = mag(tangentialOverlap_AB); if (tangentialOverlapMag > VSMALL) { scalar kT = 8.0*sqrt(R*normalOverlapMag)*Gstar_; scalar etaT = etaN; // Tangential force vector fT_AB; if (kT*tangentialOverlapMag > mu_*mag(fN_AB)) { // Tangential force greater than sliding friction, // particle slips fT_AB = -mu_*mag(fN_AB)*USlip_AB/mag(USlip_AB); tangentialOverlap_AB = vector::zero; tangentialOverlap_BA = vector::zero; } else { fT_AB = -kT*tangentialOverlapMag *tangentialOverlap_AB/tangentialOverlapMag - etaT*USlip_AB; } pA.f() += fT_AB; pB.f() += -fT_AB; pA.torque() += (dAEff/2*-rHat_AB) ^ fT_AB; pB.torque() += (dBEff/2*rHat_AB) ^ -fT_AB; } } }
void Foam::MixedDiffuseSpecular<CloudType>::correct ( typename CloudType::parcelType& p ) { vector& U = p.U(); scalar& Ei = p.Ei(); label typeId = p.typeId(); const label wppIndex = p.patch(); const polyPatch& wpp = p.mesh().boundaryMesh()[wppIndex]; label wppLocalFace = wpp.whichFace(p.face()); const vector nw = p.normal(); // Normal velocity magnitude scalar U_dot_nw = U & nw; CloudType& cloud(this->owner()); Random& rndGen(cloud.rndGen()); if (diffuseFraction_ > rndGen.scalar01()) { // Diffuse reflection // Wall tangential velocity (flow direction) vector Ut = U - U_dot_nw*nw; while (mag(Ut) < small) { // If the incident velocity is parallel to the face normal, no // tangential direction can be chosen. Add a perturbation to the // incoming velocity and recalculate. U = vector ( U.x()*(0.8 + 0.2*rndGen.scalar01()), U.y()*(0.8 + 0.2*rndGen.scalar01()), U.z()*(0.8 + 0.2*rndGen.scalar01()) ); U_dot_nw = U & nw; Ut = U - U_dot_nw*nw; } // Wall tangential unit vector vector tw1 = Ut/mag(Ut); // Other tangential unit vector vector tw2 = nw^tw1; scalar T = cloud.boundaryT().boundaryField()[wppIndex][wppLocalFace]; scalar mass = cloud.constProps(typeId).mass(); direction iDof = cloud.constProps(typeId).internalDegreesOfFreedom(); U = sqrt(physicoChemical::k.value()*T/mass) *( rndGen.scalarNormal()*tw1 + rndGen.scalarNormal()*tw2 - sqrt(-2.0*log(max(1 - rndGen.scalar01(), vSmall)))*nw ); U += cloud.boundaryU().boundaryField()[wppIndex][wppLocalFace]; Ei = cloud.equipartitionInternalEnergy(T, iDof); } else { // Specular reflection if (U_dot_nw > 0.0) { U -= 2.0*U_dot_nw*nw; } } }
Foam::forceSuSp Foam::BrownianMotionForce<CloudType>::calcCoupled ( const typename CloudType::parcelType& p, const typename CloudType::parcelType::trackingData& td, const scalar dt, const scalar mass, const scalar Re, const scalar muc ) const { forceSuSp value(Zero, 0.0); const scalar dp = p.d(); const scalar Tc = td.Tc(); const scalar alpha = 2.0*lambda_/dp; const scalar cc = 1.0 + alpha*(1.257 + 0.4*exp(-1.1/alpha)); // Boltzmann constant const scalar kb = physicoChemical::k.value(); scalar f = 0; if (turbulence_) { const label celli = p.cell(); const volScalarField& k = *kPtr_; const scalar kc = k[celli]; const scalar Dp = kb*Tc*cc/(3*mathematical::pi*muc*dp); f = sqrt(2.0*sqr(kc)*sqr(Tc)/(Dp*dt)); } else { const scalar s0 = 216*muc*kb*Tc/(sqr(mathematical::pi)*pow5(dp)*sqr(p.rho())*cc); f = mass*sqrt(mathematical::pi*s0/dt); } // To generate a cubic distribution (3 independent directions) : // const scalar sqrt2 = sqrt(2.0); // for (direction dir = 0; dir < vector::nComponents; dir++) // { // const scalar x = rndGen_.sample01<scalar>(); // const scalar eta = sqrt2*erfInv(2*x - 1.0); // value.Su()[dir] = f*eta; // } // To generate a spherical distribution: Random& rnd = this->owner().rndGen(); const scalar theta = rnd.scalar01()*twoPi; const scalar u = 2*rnd.scalar01() - 1; const scalar a = sqrt(1 - sqr(u)); const vector dir(a*cos(theta), a*sin(theta), u); value.Su() = f*mag(rnd.scalarNormal())*dir; return value; }
void Foam::PatchInteractionModel<CloudType>::patchData ( typename CloudType::parcelType& p, const polyPatch& pp, const scalar trackFraction, const tetIndices& tetIs, vector& nw, vector& Up ) const { const fvMesh& mesh = this->owner().mesh(); const volVectorField& Ufield = mesh.objectRegistry::lookupObject<volVectorField>(UName_); label patchI = pp.index(); label patchFaceI = pp.whichFace(p.face()); vector n = tetIs.faceTri(mesh).normal(); n /= mag(n); vector U = Ufield.boundaryField()[patchI][patchFaceI]; // Unless the face is rotating, the required normal is n; nw = n; if (!mesh.moving()) { // Only wall patches may have a non-zero wall velocity from // the velocity field when the mesh is not moving. if (isA<wallPolyPatch>(pp)) { Up = U; } else { Up = vector::zero; } } else { vector U00 = Ufield.oldTime().boundaryField()[patchI][patchFaceI]; vector n00 = tetIs.oldFaceTri(mesh).normal(); // Difference in normal over timestep vector dn = vector::zero; if (mag(n00) > SMALL) { // If the old normal is zero (for example in layer // addition) then use the current normal, meaning that the // motion can only be translational, and dn remains zero, // otherwise, calculate dn: n00 /= mag(n00); dn = n - n00; } // Total fraction thought the timestep of the motion, // including stepFraction before the current tracking step // and the current trackFraction // i.e. // let s = stepFraction, t = trackFraction // Motion of x in time: // |-----------------|---------|---------| // x00 x0 xi x // // where xi is the correct value of x at the required // tracking instant. // // x0 = x00 + s*(x - x00) = s*x + (1 - s)*x00 // // i.e. the motion covered by previous tracking portions // within this timestep, and // // xi = x0 + t*(x - x0) // = t*x + (1 - t)*x0 // = t*x + (1 - t)*(s*x + (1 - s)*x00) // = (s + t - s*t)*x + (1 - (s + t - s*t))*x00 // // let m = (s + t - s*t) // // xi = m*x + (1 - m)*x00 = x00 + m*(x - x00); // // In the same form as before. scalar m = p.stepFraction() + trackFraction - (p.stepFraction()*trackFraction); // When the mesh is moving, the velocity field on wall patches // will contain the velocity associated with the motion of the // mesh, in which case it is interpolated in time using m. // For other patches the face velocity will need to be // reconstructed from the face centre motion. const vector& Cf = mesh.faceCentres()[p.face()]; vector Cf00 = mesh.faces()[p.face()].centre(mesh.oldPoints()); if (isA<wallPolyPatch>(pp)) { Up = U00 + m*(U - U00); } else { Up = (Cf - Cf00)/this->owner().time().deltaTValue(); } if (mag(dn) > SMALL) { // Rotational motion, nw requires interpolation and a // rotational velocity around face centre correction to Up // is required. nw = n00 + m*dn; // Cf at tracking instant vector Cfi = Cf00 + m*(Cf - Cf00); // Normal vector cross product vector omega = (n00 ^ n); scalar magOmega = mag(omega); // magOmega = sin(angle between unit normals) // Normalise omega vector by magOmega, then multiply by // angle/dt to give the correct angular velocity vector. omega *= Foam::asin(magOmega) /(magOmega*this->owner().time().deltaTValue()); // Project position onto face and calculate this position // relative to the face centre. vector facePos = p.position() - ((p.position() - Cfi) & nw)*nw - Cfi; Up += (omega ^ facePos); } // No further action is required if the motion is // translational only, nw and Up have already been set. } }
void Foam::LarsenBorgnakkeVariableHardSphere<CloudType>::collide ( typename CloudType::parcelType& pP, typename CloudType::parcelType& pQ ) { CloudType& cloud(this->owner()); label typeIdP = pP.typeId(); label typeIdQ = pQ.typeId(); vector& UP = pP.U(); vector& UQ = pQ.U(); scalar& EiP = pP.Ei(); scalar& EiQ = pQ.Ei(); Random& rndGen(cloud.rndGen()); scalar inverseCollisionNumber = 1/relaxationCollisionNumber_; // Larsen Borgnakke internal energy redistribution part. Using the serial // application of the LB method, as per the INELRS subroutine in Bird's // DSMC0R.FOR scalar preCollisionEiP = EiP; scalar preCollisionEiQ = EiQ; direction iDofP = cloud.constProps(typeIdP).internalDegreesOfFreedom(); direction iDofQ = cloud.constProps(typeIdQ).internalDegreesOfFreedom(); scalar omegaPQ = 0.5 *( cloud.constProps(typeIdP).omega() + cloud.constProps(typeIdQ).omega() ); scalar mP = cloud.constProps(typeIdP).mass(); scalar mQ = cloud.constProps(typeIdQ).mass(); scalar mR = mP*mQ/(mP + mQ); vector Ucm = (mP*UP + mQ*UQ)/(mP + mQ); scalar cRsqr = magSqr(UP - UQ); scalar availableEnergy = 0.5*mR*cRsqr; scalar ChiB = 2.5 - omegaPQ; if (iDofP > 0) { if (inverseCollisionNumber > rndGen.scalar01()) { availableEnergy += preCollisionEiP; if (iDofP == 2) { scalar energyRatio = 1.0 - pow(rndGen.scalar01(), (1.0/ChiB)); EiP = energyRatio*availableEnergy; } else { scalar ChiA = 0.5*iDofP; EiP = energyRatio(ChiA, ChiB)*availableEnergy; } availableEnergy -= EiP; } } if (iDofQ > 0) { if (inverseCollisionNumber > rndGen.scalar01()) { availableEnergy += preCollisionEiQ; if (iDofQ == 2) { scalar energyRatio = 1.0 - pow(rndGen.scalar01(), (1.0/ChiB)); EiQ = energyRatio*availableEnergy; } else { scalar ChiA = 0.5*iDofQ; EiQ = energyRatio(ChiA, ChiB)*availableEnergy; } availableEnergy -= EiQ; } } // Rescale the translational energy scalar cR = sqrt(2.0*availableEnergy/mR); // Variable Hard Sphere collision part scalar cosTheta = 2.0*rndGen.scalar01() - 1.0; scalar sinTheta = sqrt(1.0 - cosTheta*cosTheta); scalar phi = twoPi*rndGen.scalar01(); vector postCollisionRelU = cR *vector ( cosTheta, sinTheta*cos(phi), sinTheta*sin(phi) ); UP = Ucm + postCollisionRelU*mQ/(mP + mQ); UQ = Ucm - postCollisionRelU*mP/(mP + mQ); }
void Foam::WallLocalSpringSliderDashpot<CloudType>::evaluateWall ( typename CloudType::parcelType& p, const point& site, const WallSiteData<vector>& data, scalar pREff ) const { // wall patch index label wPI = patchMap_[data.patchIndex()]; // data for this patch scalar Estar = Estar_[wPI]; scalar Gstar = Gstar_[wPI]; scalar alpha = alpha_[wPI]; scalar b = b_[wPI]; scalar mu = mu_[wPI]; vector r_PW = p.position() - site; vector U_PW = p.U() - data.wallData(); scalar normalOverlapMag = max(pREff - mag(r_PW), 0.0); vector rHat_PW = r_PW/(mag(r_PW) + VSMALL); scalar kN = (4.0/3.0)*sqrt(pREff)*Estar; scalar etaN = alpha*sqrt(p.mass()*kN)*pow025(normalOverlapMag); vector fN_PW = rHat_PW *(kN*pow(normalOverlapMag, b) - etaN*(U_PW & rHat_PW)); p.f() += fN_PW; vector USlip_PW = U_PW - (U_PW & rHat_PW)*rHat_PW + (p.omega() ^ (pREff*-rHat_PW)); scalar deltaT = this->owner().mesh().time().deltaTValue(); vector& tangentialOverlap_PW = p.collisionRecords().matchWallRecord(-r_PW, pREff).collisionData(); tangentialOverlap_PW += USlip_PW*deltaT; scalar tangentialOverlapMag = mag(tangentialOverlap_PW); if (tangentialOverlapMag > VSMALL) { scalar kT = 8.0*sqrt(pREff*normalOverlapMag)*Gstar; scalar etaT = etaN; // Tangential force vector fT_PW; if (kT*tangentialOverlapMag > mu*mag(fN_PW)) { // Tangential force greater than sliding friction, // particle slips fT_PW = -mu*mag(fN_PW)*USlip_PW/mag(USlip_PW); tangentialOverlap_PW = vector::zero; } else { fT_PW = -kT*tangentialOverlapMag *tangentialOverlap_PW/tangentialOverlapMag - etaT*USlip_PW; } p.f() += fT_PW; p.torque() += (pREff*-rHat_PW) ^ fT_PW; } }