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; } } }
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::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); }