Merge branch 'master' of /home/noisy3/OpenFOAM/OpenFOAM-dev

This commit is contained in:
mattijs
2009-04-28 12:15:14 +01:00
8 changed files with 494 additions and 233 deletions

View File

@ -91,7 +91,7 @@ int main(int argc, char *argv[])
runTime.write(); runTime.write();
Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s" Info<< nl << "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
<< " ClockTime = " << runTime.elapsedClockTime() << " s" << " ClockTime = " << runTime.elapsedClockTime() << " s"
<< nl << endl; << nl << endl;
} }

View File

@ -390,7 +390,7 @@ Foam::scalar Foam::Particle<ParticleType>::trackToFace
// slightly towards the cell-centre. // slightly towards the cell-centre.
if (trackFraction < SMALL) if (trackFraction < SMALL)
{ {
position_ += 1.0e-6*(mesh.cellCentres()[celli_] - position_); position_ += 1.0e-3*(mesh.cellCentres()[celli_] - position_);
} }
return trackFraction; return trackFraction;

View File

@ -37,6 +37,7 @@ Foam::scalar Foam::DsmcCloud<ParcelType>::kb = 1.380650277e-23;
template<class ParcelType> template<class ParcelType>
Foam::scalar Foam::DsmcCloud<ParcelType>::Tref = 273; Foam::scalar Foam::DsmcCloud<ParcelType>::Tref = 273;
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class ParcelType> template<class ParcelType>
@ -113,87 +114,161 @@ void Foam::DsmcCloud<ParcelType>::initialise
numberDensities /= nParticle_; numberDensities /= nParticle_;
scalar x0 = mesh_.bounds().min().x(); forAll(mesh_.cells(), cell)
scalar xR = mesh_.bounds().max().x() - x0;
scalar y0 = mesh_.bounds().min().y();
scalar yR = mesh_.bounds().max().y() - y0;
scalar z0 = mesh_.bounds().min().z();
scalar zR = mesh_.bounds().max().z() - z0;
forAll(molecules, i)
{ {
const word& moleculeName(molecules[i]); const vector& cC = mesh_.cellCentres()[cell];
const labelList& cellFaces = mesh_.cells()[cell];
const scalar cV = mesh_.cellVolumes()[cell];
label typeId(findIndex(typeIdList_, moleculeName)); label nTets = 0;
if (typeId == -1) // Each face is split into nEdges (or nVertices) - 2 tets.
forAll(cellFaces, face)
{ {
FatalErrorIn("Foam::DsmcCloud<ParcelType>::initialise") nTets += mesh_.faces()[cellFaces[face]].size() - 2;
<< "typeId " << moleculeName << "not defined." << nl
<< abort(FatalError);
} }
const typename ParcelType::constantProperties& cP = constProps(typeId); // Calculate the cumulative tet volumes circulating around the cell and
// record the vertex labels of each.
scalarList cTetVFracs(nTets, 0.0);
scalar numberDensity = numberDensities[i]; List<labelList> tetPtIs(nTets, labelList(3,-1));
scalar spacing = pow(numberDensity,-(1.0/3.0)); // Keep track of which tet this is.
label tet = 0;
int ni = label(xR/spacing) + 1; forAll(cellFaces, face)
int nj = label(yR/spacing) + 1;
int nk = label(zR/spacing) + 1;
vector delta(xR/ni, yR/nj, zR/nk);
scalar pert = spacing;
for (int i = 0; i < ni; i++)
{ {
for (int j = 0; j < nj; j++) const labelList& facePoints = mesh_.faces()[cellFaces[face]];
label pointI = 1;
while ((pointI + 1) < facePoints.size())
{ {
for (int k = 0; k < nk; k++)
const vector& pA = mesh_.points()[facePoints[0]];
const vector& pB = mesh_.points()[facePoints[pointI]];
const vector& pC = mesh_.points()[facePoints[pointI + 1]];
cTetVFracs[tet] =
mag(((pA - cC) ^ (pB - cC)) & (pC - cC))/(cV*6.0)
+ cTetVFracs[max((tet - 1),0)];
tetPtIs[tet][0] = facePoints[0];
tetPtIs[tet][1] = facePoints[pointI];
tetPtIs[tet][2] = facePoints[pointI + 1];
pointI++;
tet++;
}
}
// Force the last volume fraction value to 1.0 to avoid any
// rounding/non-flat face errors giving a value < 1.0
cTetVFracs[nTets - 1] = 1.0;
forAll(molecules, i)
{
const word& moleculeName(molecules[i]);
label typeId(findIndex(typeIdList_, moleculeName));
if (typeId == -1)
{
FatalErrorIn("Foam::DsmcCloud<ParcelType>::initialise")
<< "typeId " << moleculeName << "not defined." << nl
<< abort(FatalError);
}
const typename ParcelType::constantProperties& cP =
constProps(typeId);
scalar numberDensity = numberDensities[i];
// Calculate the number of particles required
scalar particlesRequired = numberDensity*mesh_.cellVolumes()[cell];
// Only integer numbers of particles can be inserted
label nParticlesToInsert = label(particlesRequired);
// Add another particle with a probability proportional to the
// remainder of taking the integer part of particlesRequired
if ((particlesRequired - nParticlesToInsert) > rndGen_.scalar01())
{
nParticlesToInsert++;
}
for (label pI = 0; pI < nParticlesToInsert; pI++)
{
// Choose a random point in a generic tetrahedron
scalar s = rndGen_.scalar01();
scalar t = rndGen_.scalar01();
scalar u = rndGen_.scalar01();
if (s + t > 1.0)
{ {
point p s = 1.0 - s;
( t = 1.0 - t;
x0 + (i + 0.5)*delta.x(), }
y0 + (j + 0.5)*delta.y(),
z0 + (k + 0.5)*delta.z()
);
p.x() += pert*(rndGen_.scalar01() - 0.5); if (t + u > 1.0)
p.y() += pert*(rndGen_.scalar01() - 0.5); {
p.z() += pert*(rndGen_.scalar01() - 0.5); scalar tmp = u;
u = 1.0 - s - t;
t = 1.0 - tmp;
}
else if (s + t + u > 1.0)
{
scalar tmp = u;
u = s + t + u - 1.0;
s = 1.0 - t - tmp;
}
label cell = mesh_.findCell(p); // Choose a tetrahedron to insert in, based on their relative
// volumes
scalar tetSelection = rndGen_.scalar01();
vector U = equipartitionLinearVelocity // Selected tetrahedron
( label sTet = -1;
temperature,
cP.mass()
);
scalar Ei = equipartitionInternalEnergy forAll(cTetVFracs, tet)
( {
temperature, sTet = tet;
cP.internalDegreesOfFreedom()
);
U += velocity; if (cTetVFracs[tet] >= tetSelection)
if (cell >= 0)
{ {
addNewParcel break;
(
p,
U,
Ei,
cell,
typeId
);
} }
} }
vector p =
(1 - s - t - u)*cC
+ s*mesh_.points()[tetPtIs[sTet][0]]
+ t*mesh_.points()[tetPtIs[sTet][1]]
+ u*mesh_.points()[tetPtIs[sTet][2]];
vector U = equipartitionLinearVelocity
(
temperature,
cP.mass()
);
scalar Ei = equipartitionInternalEnergy
(
temperature,
cP.internalDegreesOfFreedom()
);
U += velocity;
addNewParcel
(
p,
U,
Ei,
cell,
typeId
);
} }
} }
} }
@ -276,7 +351,7 @@ void Foam::DsmcCloud<ParcelType>::collisions()
scalar selectedPairs = scalar selectedPairs =
collisionSelectionRemainder_[celli] collisionSelectionRemainder_[celli]
+ 0.5*nC*(nC-1)*nParticle_*sigmaTcRMax*deltaT + 0.5*nC*(nC - 1)*nParticle_*sigmaTcRMax*deltaT
/mesh_.cellVolumes()[celli]; /mesh_.cellVolumes()[celli];
label nCandidates(selectedPairs); label nCandidates(selectedPairs);
@ -551,6 +626,13 @@ Foam::DsmcCloud<ParcelType>::DsmcCloud
buildConstProps(); buildConstProps();
buildCellOccupancy(); buildCellOccupancy();
// Initialise the collision selection remainder to a random value between 0
// and 1.
forAll(collisionSelectionRemainder_, i)
{
collisionSelectionRemainder_[i] = rndGen_.scalar01();
}
} }
@ -739,22 +821,27 @@ void Foam::DsmcCloud<ParcelType>::info() const
Info<< "Cloud name: " << this->name() << nl Info<< "Cloud name: " << this->name() << nl
<< " Number of dsmc particles = " << " Number of dsmc particles = "
<< nDsmcParticles << nl << nDsmcParticles
<< " Number of molecules = "
<< nMol << nl
<< " Mass in system = "
<< returnReduce(massInSystem(), sumOp<scalar>()) << nl
<< " Average linear momentum = "
<< linearMomentum/nMol << nl
<< " |Average linear momentum| = "
<< mag(linearMomentum)/nMol << nl
<< " Average linear kinetic energy = "
<< linearKineticEnergy/nMol << nl
<< " Average internal energy = "
<< internalEnergy/nMol << nl
<< " Average total energy = "
<< (internalEnergy + linearKineticEnergy)/nMol << nl
<< endl; << endl;
if (nDsmcParticles)
{
Info<< " Number of molecules = "
<< nMol << nl
<< " Mass in system = "
<< returnReduce(massInSystem(), sumOp<scalar>()) << nl
<< " Average linear momentum = "
<< linearMomentum/nMol << nl
<< " |Average linear momentum| = "
<< mag(linearMomentum)/nMol << nl
<< " Average linear kinetic energy = "
<< linearKineticEnergy/nMol << nl
<< " Average internal energy = "
<< internalEnergy/nMol << nl
<< " Average total energy = "
<< (internalEnergy + linearKineticEnergy)/nMol
<< endl;
}
} }
@ -785,7 +872,11 @@ Foam::scalar Foam::DsmcCloud<ParcelType>::equipartitionInternalEnergy
{ {
scalar Ei = 0.0; scalar Ei = 0.0;
if (iDof < 2.0 + SMALL && iDof > 2.0 - SMALL) if (iDof < SMALL)
{
return Ei;
}
else if (iDof < 2.0 + SMALL && iDof > 2.0 - SMALL)
{ {
// Special case for iDof = 2, i.e. diatomics; // Special case for iDof = 2, i.e. diatomics;
Ei = -log(rndGen_.scalar01())*kb*temperature; Ei = -log(rndGen_.scalar01())*kb*temperature;
@ -796,7 +887,7 @@ Foam::scalar Foam::DsmcCloud<ParcelType>::equipartitionInternalEnergy
scalar energyRatio; scalar energyRatio;
scalar P; scalar P = -1;
do do
{ {

View File

@ -299,6 +299,12 @@ public:
scalar mass scalar mass
) const; ) const;
inline scalarField maxwellianAverageSpeed
(
scalarField temperature,
scalar mass
) const;
//- RMS particle speed //- RMS particle speed
inline scalar maxwellianRMSSpeed inline scalar maxwellianRMSSpeed
( (
@ -306,6 +312,12 @@ public:
scalar mass scalar mass
) const; ) const;
inline scalarField maxwellianRMSSpeed
(
scalarField temperature,
scalar mass
) const;
//- Most probable speed //- Most probable speed
inline scalar maxwellianMostProbableSpeed inline scalar maxwellianMostProbableSpeed
( (
@ -313,6 +325,11 @@ public:
scalar mass scalar mass
) const; ) const;
inline scalarField maxwellianMostProbableSpeed
(
scalarField temperature,
scalar mass
) const;
// Sub-models // Sub-models

View File

@ -302,6 +302,17 @@ inline Foam::scalar Foam::DsmcCloud<ParcelType>::maxwellianAverageSpeed
} }
template<class ParcelType>
inline Foam::scalarField Foam::DsmcCloud<ParcelType>::maxwellianAverageSpeed
(
scalarField temperature,
scalar mass
) const
{
return 2.0*sqrt(2.0*kb*temperature/(mathematicalConstant::pi*mass));
}
template<class ParcelType> template<class ParcelType>
inline Foam::scalar Foam::DsmcCloud<ParcelType>::maxwellianRMSSpeed inline Foam::scalar Foam::DsmcCloud<ParcelType>::maxwellianRMSSpeed
( (
@ -313,6 +324,17 @@ inline Foam::scalar Foam::DsmcCloud<ParcelType>::maxwellianRMSSpeed
} }
template<class ParcelType>
inline Foam::scalarField Foam::DsmcCloud<ParcelType>::maxwellianRMSSpeed
(
scalarField temperature,
scalar mass
) const
{
return sqrt(3.0*kb*temperature/mass);
}
template<class ParcelType> template<class ParcelType>
inline Foam::scalar inline Foam::scalar
Foam::DsmcCloud<ParcelType>::maxwellianMostProbableSpeed Foam::DsmcCloud<ParcelType>::maxwellianMostProbableSpeed
@ -325,6 +347,18 @@ Foam::DsmcCloud<ParcelType>::maxwellianMostProbableSpeed
} }
template<class ParcelType>
inline Foam::scalarField
Foam::DsmcCloud<ParcelType>::maxwellianMostProbableSpeed
(
scalarField temperature,
scalar mass
) const
{
return sqrt(2.0*kb*temperature/mass);
}
template<class ParcelType> template<class ParcelType>
inline const Foam::tmp<Foam::volScalarField> inline const Foam::tmp<Foam::volScalarField>
Foam::DsmcCloud<ParcelType>::rhoN() const Foam::DsmcCloud<ParcelType>::rhoN() const
@ -343,7 +377,7 @@ Foam::DsmcCloud<ParcelType>::rhoN() const
false false
), ),
mesh_, mesh_,
dimensionedScalar("zero", dimensionSet(0, -3, 0, 0, 0), 0.0) dimensionedScalar("zero", dimensionSet(0, -3, 0, 0, 0), VSMALL)
) )
); );
@ -380,7 +414,7 @@ Foam::DsmcCloud<ParcelType>::rhoM() const
false false
), ),
mesh_, mesh_,
dimensionedScalar("zero", dimensionSet(1, -3, 0, 0, 0), 0.0) dimensionedScalar("zero", dimensionSet(1, -3, 0, 0, 0), VSMALL)
) )
); );
@ -568,7 +602,7 @@ Foam::DsmcCloud<ParcelType>::iDof() const
false false
), ),
mesh_, mesh_,
dimensionedScalar("zero", dimensionSet(0, -3, 0, 0, 0), 0.0) dimensionedScalar("zero", dimensionSet(0, -3, 0, 0, 0), VSMALL)
) )
); );

View File

@ -36,32 +36,27 @@ Foam::FreeStream<CloudType>::FreeStream
) )
: :
InflowBoundaryModel<CloudType>(dict, cloud, typeName), InflowBoundaryModel<CloudType>(dict, cloud, typeName),
patchIndex_(), patches_(),
temperature_(readScalar(this->coeffDict().lookup("temperature"))),
velocity_(this->coeffDict().lookup("velocity")),
moleculeTypeIds_(), moleculeTypeIds_(),
numberDensities_(), numberDensities_(),
particleFluxAccumulators_() particleFluxAccumulators_()
{ {
word patchName = this->coeffDict().lookup("patch"); // Identify which patches to use
patchIndex_ = cloud.mesh().boundaryMesh().findPatchID(patchName); DynamicList<label> patches;
const polyPatch& patch = cloud.mesh().boundaryMesh()[patchIndex_]; forAll(cloud.mesh().boundaryMesh(), p)
if (patchIndex_ == -1)
{ {
FatalErrorIn const polyPatch& patch = cloud.mesh().boundaryMesh()[p];
(
"Foam::FreeStream<CloudType>::FreeStream" if (patch.type() == polyPatch::typeName)
"(" {
"const dictionary&, " patches.append(p);
"CloudType&" }
")"
) << "patch " << patchName << " not found." << nl
<< abort(FatalError);
} }
patches_.transfer(patches);
const dictionary& numberDensitiesDict const dictionary& numberDensitiesDict
( (
this->coeffDict().subDict("numberDensities") this->coeffDict().subDict("numberDensities")
@ -69,10 +64,24 @@ Foam::FreeStream<CloudType>::FreeStream
List<word> molecules(numberDensitiesDict.toc()); List<word> molecules(numberDensitiesDict.toc());
numberDensities_.setSize(molecules.size()); // Initialise the particleFluxAccumulators_
particleFluxAccumulators_.setSize(patches_.size());
forAll(patches_, p)
{
const polyPatch& patch = cloud.mesh().boundaryMesh()[patches_[p]];
particleFluxAccumulators_[p] = List<Field<scalar> >
(
molecules.size(),
Field<scalar>(patch.size(), 0.0)
);
}
moleculeTypeIds_.setSize(molecules.size()); moleculeTypeIds_.setSize(molecules.size());
numberDensities_.setSize(molecules.size());
forAll(molecules, i) forAll(molecules, i)
{ {
numberDensities_[i] = readScalar numberDensities_[i] = readScalar
@ -97,12 +106,6 @@ Foam::FreeStream<CloudType>::FreeStream
} }
numberDensities_ /= cloud.nParticle(); numberDensities_ /= cloud.nParticle();
particleFluxAccumulators_.setSize
(
molecules.size(),
Field<scalar>(patch.size(), 0)
);
} }
@ -127,144 +130,262 @@ void Foam::FreeStream<CloudType>::inflow()
Random& rndGen(cloud.rndGen()); Random& rndGen(cloud.rndGen());
const polyPatch& patch = mesh.boundaryMesh()[patchIndex_]; scalar sqrtPi = sqrt(mathematicalConstant::pi);
label particlesInserted = 0; label particlesInserted = 0;
// Add mass to the accumulators. negative face area dotted with the const volScalarField::GeometricBoundaryField& boundaryT
// velocity to point flux into the domain. (
cloud.T().boundaryField()
);
forAll(particleFluxAccumulators_, i) const volVectorField::GeometricBoundaryField& boundaryU
(
cloud.U().boundaryField()
);
forAll(patches_, p)
{ {
particleFluxAccumulators_[i] += label patchI = patches_[p];
-patch.faceAreas() & (velocity_*numberDensities_[i]*deltaT);
}
forAll(patch, f) const polyPatch& patch = mesh.boundaryMesh()[patchI];
{
// Loop over all faces as the outer loop to avoid calculating
// geometrical properties multiple times.
labelList faceVertices = patch[f]; // Add mass to the accumulators. negative face area dotted with the
// velocity to point flux into the domain.
label nVertices = faceVertices.size(); // Take a reference to the particleFluxAccumulator for this patch
List<Field<scalar> >& pFA = particleFluxAccumulators_[p];
label globalFaceIndex = f + patch.start(); forAll(pFA, i)
label cell = mesh.faceOwner()[globalFaceIndex];
const vector& fC = patch.faceCentres()[f];
scalar fA = mag(patch.faceAreas()[f]);
// Cummulative triangle area fractions
List<scalar> cTriAFracs(nVertices);
for (label v = 0; v < nVertices - 1; v++)
{ {
const point& vA = mesh.points()[faceVertices[v]];
const point& vB = mesh.points()[faceVertices[(v + 1)]];
cTriAFracs[v] =
0.5*mag((vA - fC)^(vB - fC))/fA
+ cTriAFracs[max((v - 1), 0)];
}
// Force the last area fraction value to 1.0 to avoid any
// rounding/non-flat face errors giving a value < 1.0
cTriAFracs[nVertices - 1] = 1.0;
// Normal unit vector *negative* so normal is pointing into the
// domain
vector nw = patch.faceAreas()[f];
nw /= -mag(nw);
// Wall tangential unit vector. Use the direction between the
// face centre and the first vertex in the list
vector tw1 = fC - (mesh.points()[faceVertices[0]]);
tw1 /= mag(tw1);
// Other tangential unit vector. Rescaling in case face is not
// flat and nw and tw1 aren't perfectly orthogonal
vector tw2 = nw^tw1;
tw2 /= mag(tw2);
forAll(particleFluxAccumulators_, i)
{
scalar& faceAccumulator = particleFluxAccumulators_[i][f];
// Number of particles to insert
label nI = max(label(faceAccumulator), 0);
faceAccumulator -= nI;
label typeId = moleculeTypeIds_[i]; label typeId = moleculeTypeIds_[i];
scalar mass = cloud.constProps(typeId).mass(); scalar mass = cloud.constProps(typeId).mass();
for (label n = 0; n < nI; n++) scalarField mostProbableSpeed
(
cloud.maxwellianMostProbableSpeed
(
boundaryT[patchI],
mass
)
);
// Dotting boundary velocity with the face unit normal (which points
// out of the domain, so it must be negated), dividing by the most
// probable speed to form molecularSpeedRatio * cosTheta
scalarField sCosTheta =
boundaryU[patchI]
& -patch.faceAreas()/mag(patch.faceAreas())
/mostProbableSpeed;
// From Bird eqn 4.22
pFA[i] +=
mag(patch.faceAreas())*numberDensities_[i]*deltaT
*mostProbableSpeed
*(
exp(-sqr(sCosTheta)) + sqrtPi*sCosTheta*(1 + erf(sCosTheta))
)
/(2.0*sqrtPi);
}
forAll(patch, f)
{
// Loop over all faces as the outer loop to avoid calculating
// geometrical properties multiple times.
labelList faceVertices = patch[f];
label nVertices = faceVertices.size();
label globalFaceIndex = f + patch.start();
label cell = mesh.faceOwner()[globalFaceIndex];
const vector& fC = patch.faceCentres()[f];
scalar fA = mag(patch.faceAreas()[f]);
// Cumulative triangle area fractions
List<scalar> cTriAFracs(nVertices);
for (label v = 0; v < nVertices - 1; v++)
{ {
// Choose a triangle to insert on, based on their relative area const point& vA = mesh.points()[faceVertices[v]];
scalar triSelection = rndGen.scalar01(); const point& vB = mesh.points()[faceVertices[(v + 1)]];
// Selected triangle cTriAFracs[v] =
label sTri = -1; 0.5*mag((vA - fC)^(vB - fC))/fA
+ cTriAFracs[max((v - 1), 0)];
}
forAll(cTriAFracs, tri) // Force the last area fraction value to 1.0 to avoid any
// rounding/non-flat face errors giving a value < 1.0
cTriAFracs[nVertices - 1] = 1.0;
// Normal unit vector *negative* so normal is pointing into the
// domain
vector n = patch.faceAreas()[f];
n /= -mag(n);
// Wall tangential unit vector. Use the direction between the
// face centre and the first vertex in the list
vector t1 = fC - (mesh.points()[faceVertices[0]]);
t1 /= mag(t1);
// Other tangential unit vector. Rescaling in case face is not
// flat and n and t1 aren't perfectly orthogonal
vector t2 = n^t1;
t2 /= mag(t2);
scalar faceTemperature = boundaryT[patchI][f];
const vector& faceVelocity = boundaryU[patchI][f];
forAll(pFA, i)
{
scalar& faceAccumulator = pFA[i][f];
// Number of whole particles to insert
label nI = max(label(faceAccumulator), 0);
// Add another particle with a probability proportional to the
// remainder of taking the integer part of faceAccumulator
if ((faceAccumulator - nI) > rndGen.scalar01())
{ {
sTri = tri; nI++;
if (cTriAFracs[tri] >= triSelection)
{
break;
}
} }
// Randomly distribute the points on the triangle, using the faceAccumulator -= nI;
// method from:
// Generating Random Points in Triangles
// by Greg Turk
// from "Graphics Gems", Academic Press, 1990
// http://tog.acm.org/GraphicsGems/gems/TriPoints.c
const point& A = fC; label typeId = moleculeTypeIds_[i];
const point& B = mesh.points()[faceVertices[sTri]];
const point& C = scalar mass = cloud.constProps(typeId).mass();
for (label i = 0; i < nI; i++)
{
// Choose a triangle to insert on, based on their relative
// area
scalar triSelection = rndGen.scalar01();
// Selected triangle
label sTri = -1;
forAll(cTriAFracs, tri)
{
sTri = tri;
if (cTriAFracs[tri] >= triSelection)
{
break;
}
}
// Randomly distribute the points on the triangle, using the
// method from:
// Generating Random Points in Triangles
// by Greg Turk
// from "Graphics Gems", Academic Press, 1990
// http://tog.acm.org/GraphicsGems/gems/TriPoints.c
const point& A = fC;
const point& B = mesh.points()[faceVertices[sTri]];
const point& C =
mesh.points()[faceVertices[(sTri + 1) % nVertices]]; mesh.points()[faceVertices[(sTri + 1) % nVertices]];
scalar s = rndGen.scalar01(); scalar s = rndGen.scalar01();
scalar t = sqrt(rndGen.scalar01()); scalar t = sqrt(rndGen.scalar01());
point p = (1 - t)*A + (1 - s)*t*B + s*t*C; point p = (1 - t)*A + (1 - s)*t*B + s*t*C;
vector U = // Velocity generation
sqrt(CloudType::kb*temperature_/mass)
*( scalar mostProbableSpeed
rndGen.GaussNormal()*tw1 (
+ rndGen.GaussNormal()*tw2 cloud.maxwellianMostProbableSpeed
- sqrt(-2.0*log(max(1 - rndGen.scalar01(), VSMALL)))*nw (
faceTemperature,
mass
)
); );
U += velocity_; scalar sCosTheta = (faceVelocity & n)/mostProbableSpeed;
scalar Ei = cloud.equipartitionInternalEnergy // Coefficients required for Bird eqn 12.5
( scalar uNormProbCoeffA =
temperature_, sCosTheta + sqrt(sqr(sCosTheta) + 2.0);
cloud.constProps(typeId).internalDegreesOfFreedom()
);
cloud.addNewParcel scalar uNormProbCoeffB =
( 0.5*
p, (
U, 1.0
Ei, + sCosTheta*(sCosTheta - sqrt(sqr(sCosTheta) + 2.0))
cell, );
typeId
);
particlesInserted++; // Equivalent to the QA value in Bird's DSMC3.FOR
scalar randomScaling = 3.0;
if (sCosTheta < -3)
{
randomScaling = mag(sCosTheta) + 1;
}
scalar P = -1;
// Normalised candidates for the normal direction velocity
// component
scalar uNormal;
scalar uNormalThermal;
// Select a velocity using Bird eqn 12.5
do
{
uNormalThermal =
randomScaling*(2.0*rndGen.scalar01() - 1);
uNormal = uNormalThermal + sCosTheta;
if (uNormal < 0.0)
{
P = -1;
}
else
{
P = 2.0*uNormal/uNormProbCoeffA
*exp(uNormProbCoeffB - sqr(uNormalThermal));
}
} while (P < rndGen.scalar01());
vector U =
sqrt(CloudType::kb*faceTemperature/mass)
*(
rndGen.GaussNormal()*t1
+ rndGen.GaussNormal()*t2
)
+ mostProbableSpeed*uNormal*n;
scalar Ei = cloud.equipartitionInternalEnergy
(
faceTemperature,
cloud.constProps(typeId).internalDegreesOfFreedom()
);
cloud.addNewParcel
(
p,
U,
Ei,
cell,
typeId
);
particlesInserted++;
}
} }
} }
} }

View File

@ -26,8 +26,10 @@ Class
Foam::FreeStream Foam::FreeStream
Description Description
Inserting new particles across the faces of a specified patch for a free Inserting new particles across the faces of a all patched of type
stream. Uniform values of temperature, velocity and number densities "patch" for a free stream. Uniform values number density, temperature
and velocity sourced face-by-face from the boundaryT and boundaryU fields
of the cloud.
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
@ -52,14 +54,8 @@ class FreeStream
{ {
// Private data // Private data
//- Index of patch to introduce particles across //- The indices of patches to introduce molecules across
label patchIndex_; labelList patches_;
//- Temperature of the free stream
scalar temperature_;
//- Velocity of the free stream
vector velocity_;
//- The molecule types to be introduced //- The molecule types to be introduced
List<label> moleculeTypeIds_; List<label> moleculeTypeIds_;
@ -67,10 +63,13 @@ class FreeStream
//- The number density of the species in the inflow //- The number density of the species in the inflow
Field<scalar> numberDensities_; Field<scalar> numberDensities_;
//- A List of Fields, one Field for every species to be introduced, each //- A List of Lists of Fields specifying carry-over of mass flux from
// field entry corresponding to a face on the patch to be injected // one timestep to the next
// across. // + Outer List - one inner List for each patch
List<Field<scalar> > particleFluxAccumulators_; // + Inner List - one Field for every species to be introduced
// + Each field entry corresponding to a face to be injected across
// with a particular species
List<List<Field<scalar> > > particleFluxAccumulators_;
public: public:

View File

@ -137,7 +137,7 @@ void Foam::dsmcFields::write()
iDofMeanName iDofMeanName
); );
if (min(rhoNMean).value() > VSMALL) if (min(mag(rhoNMean)).value() > VSMALL)
{ {
Info<< "Calculating dsmcFields." << endl; Info<< "Calculating dsmcFields." << endl;
@ -223,10 +223,9 @@ void Foam::dsmcFields::write()
} }
else else
{ {
Info<< "Small or negative value (" << min(rhoNMean) Info<< "Small value (" << min(mag(rhoNMean))
<< ") found in rhoNMean field. " << ") found in rhoNMean field. "
<< "Not calculating dsmcFields to avoid division by zero " << "Not calculating dsmcFields to avoid division by zero."
<< "or invalid results."
<< endl; << endl;
} }
} }