00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "DsmcCloud_.H"
00027 #include <dsmc/BinaryCollisionModel.H>
00028 #include <dsmc/WallInteractionModel.H>
00029 #include <dsmc/InflowBoundaryModel.H>
00030 #include <finiteVolume/zeroGradientFvPatchFields.H>
00031
00032
00033
00034 template<class ParcelType>
00035 Foam::scalar Foam::DsmcCloud<ParcelType>::kb = 1.380650277e-23;
00036
00037
00038
00039
00040 template<class ParcelType>
00041 void Foam::DsmcCloud<ParcelType>::buildConstProps()
00042 {
00043 Info<< nl << "Constructing constant properties for" << endl;
00044 constProps_.setSize(typeIdList_.size());
00045
00046 dictionary moleculeProperties
00047 (
00048 particleProperties_.subDict("moleculeProperties")
00049 );
00050
00051 forAll(typeIdList_, i)
00052 {
00053 const word& id(typeIdList_[i]);
00054
00055 Info<< " " << id << endl;
00056
00057 const dictionary& molDict(moleculeProperties.subDict(id));
00058
00059 constProps_[i] =
00060 typename ParcelType::constantProperties::constantProperties(molDict);
00061 }
00062 }
00063
00064
00065 template<class ParcelType>
00066 void Foam::DsmcCloud<ParcelType>::buildCellOccupancy()
00067 {
00068 forAll(cellOccupancy_, cO)
00069 {
00070 cellOccupancy_[cO].clear();
00071 }
00072
00073 forAllIter(typename DsmcCloud<ParcelType>, *this, iter)
00074 {
00075 cellOccupancy_[iter().cell()].append(&iter());
00076 }
00077 }
00078
00079
00080 template<class ParcelType>
00081 void Foam::DsmcCloud<ParcelType>::initialise
00082 (
00083 const IOdictionary& dsmcInitialiseDict
00084 )
00085 {
00086 Info<< nl << "Initialising particles" << endl;
00087
00088 const scalar temperature
00089 (
00090 readScalar(dsmcInitialiseDict.lookup("temperature"))
00091 );
00092
00093 const vector velocity(dsmcInitialiseDict.lookup("velocity"));
00094
00095 const dictionary& numberDensitiesDict
00096 (
00097 dsmcInitialiseDict.subDict("numberDensities")
00098 );
00099
00100 List<word> molecules(numberDensitiesDict.toc());
00101
00102 Field<scalar> numberDensities(molecules.size());
00103
00104 forAll(molecules, i)
00105 {
00106 numberDensities[i] = readScalar
00107 (
00108 numberDensitiesDict.lookup(molecules[i])
00109 );
00110 }
00111
00112 numberDensities /= nParticle_;
00113
00114 forAll(mesh_.cells(), cell)
00115 {
00116 const vector& cC = mesh_.cellCentres()[cell];
00117 const labelList& cellFaces = mesh_.cells()[cell];
00118 const scalar cV = mesh_.cellVolumes()[cell];
00119
00120 label nTets = 0;
00121
00122
00123 forAll(cellFaces, face)
00124 {
00125 nTets += mesh_.faces()[cellFaces[face]].size() - 2;
00126 }
00127
00128
00129
00130 scalarList cTetVFracs(nTets, 0.0);
00131
00132 List<labelList> tetPtIs(nTets, labelList(3,-1));
00133
00134
00135 label tet = 0;
00136
00137 forAll(cellFaces, face)
00138 {
00139 const labelList& facePoints = mesh_.faces()[cellFaces[face]];
00140
00141 label pointI = 1;
00142 while ((pointI + 1) < facePoints.size())
00143 {
00144
00145 const vector& pA = mesh_.points()[facePoints[0]];
00146 const vector& pB = mesh_.points()[facePoints[pointI]];
00147 const vector& pC = mesh_.points()[facePoints[pointI + 1]];
00148
00149 cTetVFracs[tet] =
00150 mag(((pA - cC) ^ (pB - cC)) & (pC - cC))/(cV*6.0)
00151 + cTetVFracs[max((tet - 1),0)];
00152
00153 tetPtIs[tet][0] = facePoints[0];
00154 tetPtIs[tet][1] = facePoints[pointI];
00155 tetPtIs[tet][2] = facePoints[pointI + 1];
00156
00157 pointI++;
00158 tet++;
00159 }
00160 }
00161
00162
00163
00164 cTetVFracs[nTets - 1] = 1.0;
00165
00166 forAll(molecules, i)
00167 {
00168 const word& moleculeName(molecules[i]);
00169
00170 label typeId(findIndex(typeIdList_, moleculeName));
00171
00172 if (typeId == -1)
00173 {
00174 FatalErrorIn("Foam::DsmcCloud<ParcelType>::initialise")
00175 << "typeId " << moleculeName << "not defined." << nl
00176 << abort(FatalError);
00177 }
00178
00179 const typename ParcelType::constantProperties& cP =
00180 constProps(typeId);
00181
00182 scalar numberDensity = numberDensities[i];
00183
00184
00185 scalar particlesRequired = numberDensity*mesh_.cellVolumes()[cell];
00186
00187
00188 label nParticlesToInsert = label(particlesRequired);
00189
00190
00191
00192 if ((particlesRequired - nParticlesToInsert) > rndGen_.scalar01())
00193 {
00194 nParticlesToInsert++;
00195 }
00196
00197 for (label pI = 0; pI < nParticlesToInsert; pI++)
00198 {
00199
00200
00201 scalar s = rndGen_.scalar01();
00202 scalar t = rndGen_.scalar01();
00203 scalar u = rndGen_.scalar01();
00204
00205 if (s + t > 1.0)
00206 {
00207 s = 1.0 - s;
00208 t = 1.0 - t;
00209 }
00210
00211 if (t + u > 1.0)
00212 {
00213 scalar tmp = u;
00214 u = 1.0 - s - t;
00215 t = 1.0 - tmp;
00216 }
00217 else if (s + t + u > 1.0)
00218 {
00219 scalar tmp = u;
00220 u = s + t + u - 1.0;
00221 s = 1.0 - t - tmp;
00222 }
00223
00224
00225
00226 scalar tetSelection = rndGen_.scalar01();
00227
00228
00229 label sTet = -1;
00230
00231 forAll(cTetVFracs, tet)
00232 {
00233 sTet = tet;
00234
00235 if (cTetVFracs[tet] >= tetSelection)
00236 {
00237 break;
00238 }
00239 }
00240
00241 vector p =
00242 (1 - s - t - u)*cC
00243 + s*mesh_.points()[tetPtIs[sTet][0]]
00244 + t*mesh_.points()[tetPtIs[sTet][1]]
00245 + u*mesh_.points()[tetPtIs[sTet][2]];
00246
00247 vector U = equipartitionLinearVelocity
00248 (
00249 temperature,
00250 cP.mass()
00251 );
00252
00253 scalar Ei = equipartitionInternalEnergy
00254 (
00255 temperature,
00256 cP.internalDegreesOfFreedom()
00257 );
00258
00259 U += velocity;
00260
00261 addNewParcel
00262 (
00263 p,
00264 U,
00265 Ei,
00266 cell,
00267 typeId
00268 );
00269 }
00270 }
00271 }
00272
00273
00274
00275
00276
00277 label mostAbundantType(findMax(numberDensities));
00278
00279 const typename ParcelType::constantProperties& cP = constProps
00280 (
00281 mostAbundantType
00282 );
00283
00284 sigmaTcRMax_.internalField() = cP.sigmaT()*maxwellianMostProbableSpeed
00285 (
00286 temperature,
00287 cP.mass()
00288 );
00289
00290 sigmaTcRMax_.correctBoundaryConditions();
00291 }
00292
00293
00294 template<class ParcelType>
00295 void Foam::DsmcCloud<ParcelType>::collisions()
00296 {
00297 buildCellOccupancy();
00298
00299
00300 List<DynamicList<label> > subCells(8);
00301
00302 scalar deltaT = mesh().time().deltaTValue();
00303
00304 label collisionCandidates = 0;
00305
00306 label collisions = 0;
00307
00308 forAll(cellOccupancy_, celli)
00309 {
00310 const DynamicList<ParcelType*>& cellParcels(cellOccupancy_[celli]);
00311
00312 label nC(cellParcels.size());
00313
00314 if (nC > 1)
00315 {
00316
00317
00318
00319
00320
00321 forAll(subCells, i)
00322 {
00323 subCells[i].clear();
00324 }
00325
00326
00327 List<label> whichSubCell(cellParcels.size());
00328
00329 const point& cC = mesh_.cellCentres()[celli];
00330
00331 forAll(cellParcels, i)
00332 {
00333 ParcelType* p = cellParcels[i];
00334
00335 vector relPos = p->position() - cC;
00336
00337 label subCell =
00338 pos(relPos.x()) + 2*pos(relPos.y()) + 4*pos(relPos.z());
00339
00340 subCells[subCell].append(i);
00341
00342 whichSubCell[i] = subCell;
00343 }
00344
00345
00346
00347 scalar sigmaTcRMax = sigmaTcRMax_[celli];
00348
00349 scalar selectedPairs =
00350 collisionSelectionRemainder_[celli]
00351 + 0.5*nC*(nC - 1)*nParticle_*sigmaTcRMax*deltaT
00352 /mesh_.cellVolumes()[celli];
00353
00354 label nCandidates(selectedPairs);
00355
00356 collisionSelectionRemainder_[celli] = selectedPairs - nCandidates;
00357
00358 collisionCandidates += nCandidates;
00359
00360 for (label c = 0; c < nCandidates; c++)
00361 {
00362
00363
00364
00365
00366 label candidateP = rndGen_.integer(0, nC - 1);
00367
00368
00369 label candidateQ = -1;
00370
00371 List<label> subCellPs = subCells[whichSubCell[candidateP]];
00372
00373 label nSC = subCellPs.size();
00374
00375 if (nSC > 1)
00376 {
00377
00378
00379
00380
00381 do
00382 {
00383 candidateQ = subCellPs[rndGen_.integer(0, nSC - 1)];
00384
00385 } while(candidateP == candidateQ);
00386 }
00387 else
00388 {
00389
00390
00391
00392
00393 do
00394 {
00395 candidateQ = rndGen_.integer(0, nC - 1);
00396
00397 } while(candidateP == candidateQ);
00398 }
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417 ParcelType* parcelP = cellParcels[candidateP];
00418 ParcelType* parcelQ = cellParcels[candidateQ];
00419
00420 label typeIdP = parcelP->typeId();
00421 label typeIdQ = parcelQ->typeId();
00422
00423 scalar sigmaTcR = binaryCollision().sigmaTcR
00424 (
00425 typeIdP,
00426 typeIdQ,
00427 parcelP->U(),
00428 parcelQ->U()
00429 );
00430
00431
00432
00433
00434
00435 if (sigmaTcR > sigmaTcRMax_[celli])
00436 {
00437 sigmaTcRMax_[celli] = sigmaTcR;
00438 }
00439
00440 if ((sigmaTcR/sigmaTcRMax) > rndGen_.scalar01())
00441 {
00442 binaryCollision().collide
00443 (
00444 typeIdP,
00445 typeIdQ,
00446 parcelP->U(),
00447 parcelQ->U(),
00448 parcelP->Ei(),
00449 parcelQ->Ei()
00450 );
00451
00452 collisions++;
00453 }
00454 }
00455 }
00456 }
00457
00458 reduce(collisions, sumOp<label>());
00459
00460 reduce(collisionCandidates, sumOp<label>());
00461
00462 sigmaTcRMax_.correctBoundaryConditions();
00463
00464 if (collisionCandidates)
00465 {
00466 Info<< " Collisions = "
00467 << collisions << nl
00468 << " Acceptance rate = "
00469 << scalar(collisions)/scalar(collisionCandidates) << nl
00470 << endl;
00471 }
00472 else
00473 {
00474 Info<< " No collisions" << endl;
00475 }
00476 }
00477
00478
00479 template<class ParcelType>
00480 void Foam::DsmcCloud<ParcelType>::resetFields()
00481 {
00482 q_ = dimensionedScalar("zero", dimensionSet(1, 0, -3, 0, 0), 0.0);
00483
00484 fD_ = dimensionedVector
00485 (
00486 "zero",
00487 dimensionSet(1, -1, -2, 0, 0),
00488 vector::zero
00489 );
00490
00491 rhoN_ = dimensionedScalar("zero", dimensionSet(0, -3, 0, 0, 0), VSMALL);
00492
00493 rhoM_ = dimensionedScalar("zero", dimensionSet(1, -3, 0, 0, 0), VSMALL);
00494
00495 dsmcRhoN_ = dimensionedScalar("zero", dimensionSet(0, -3, 0, 0, 0), 0.0);
00496
00497 linearKE_ = dimensionedScalar("zero", dimensionSet(1, -1, -2, 0, 0), 0.0);
00498
00499 internalE_ = dimensionedScalar("zero", dimensionSet(1, -1, -2, 0, 0), 0.0);
00500
00501 iDof_ = dimensionedScalar("zero", dimensionSet(0, -3, 0, 0, 0), VSMALL);
00502
00503 momentum_ = dimensionedVector
00504 (
00505 "zero",
00506 dimensionSet(1, -2, -1, 0, 0),
00507 vector::zero
00508 );
00509 }
00510
00511
00512 template<class ParcelType>
00513 void Foam::DsmcCloud<ParcelType>::calculateFields()
00514 {
00515 scalarField& rhoN = rhoN_.internalField();
00516
00517 scalarField& rhoM = rhoM_.internalField();
00518
00519 scalarField& dsmcRhoN = dsmcRhoN_.internalField();
00520
00521 scalarField& linearKE = linearKE_.internalField();
00522
00523 scalarField& internalE = internalE_.internalField();
00524
00525 scalarField& iDof = iDof_.internalField();
00526
00527 vectorField& momentum = momentum_.internalField();
00528
00529 forAllConstIter(typename DsmcCloud<ParcelType>, *this, iter)
00530 {
00531 const ParcelType& p = iter();
00532 const label cellI = p.cell();
00533
00534 rhoN[cellI]++;
00535
00536 rhoM[cellI] += constProps(p.typeId()).mass();
00537
00538 dsmcRhoN[cellI]++;
00539
00540 linearKE[cellI] += 0.5*constProps(p.typeId()).mass()*(p.U() & p.U());
00541
00542 internalE[cellI] += p.Ei();
00543
00544 iDof[cellI] += constProps(p.typeId()).internalDegreesOfFreedom();
00545
00546 momentum[cellI] += constProps(p.typeId()).mass()*p.U();
00547 }
00548
00549 rhoN *= nParticle_/mesh().cellVolumes();
00550 rhoN_.correctBoundaryConditions();
00551
00552 rhoM *= nParticle_/mesh().cellVolumes();
00553 rhoM_.correctBoundaryConditions();
00554
00555 dsmcRhoN_.correctBoundaryConditions();
00556
00557 linearKE *= nParticle_/mesh().cellVolumes();
00558 linearKE_.correctBoundaryConditions();
00559
00560 internalE *= nParticle_/mesh().cellVolumes();
00561 internalE_.correctBoundaryConditions();
00562
00563 iDof *= nParticle_/mesh().cellVolumes();
00564 iDof_.correctBoundaryConditions();
00565
00566 momentum *= nParticle_/mesh().cellVolumes();
00567 momentum_.correctBoundaryConditions();
00568 }
00569
00570
00571
00572
00573 template<class ParcelType>
00574 void Foam::DsmcCloud<ParcelType>::addNewParcel
00575 (
00576 const vector& position,
00577 const vector& U,
00578 const scalar Ei,
00579 const label cellId,
00580 const label typeId
00581 )
00582 {
00583 ParcelType* pPtr = new ParcelType
00584 (
00585 *this,
00586 position,
00587 U,
00588 Ei,
00589 cellId,
00590 typeId
00591 );
00592
00593 this->addParticle(pPtr);
00594 }
00595
00596
00597
00598
00599 template<class ParcelType>
00600 Foam::DsmcCloud<ParcelType>::DsmcCloud
00601 (
00602 const word& cloudName,
00603 const fvMesh& mesh,
00604 bool readFields
00605 )
00606 :
00607 Cloud<ParcelType>(mesh, cloudName, false),
00608 DsmcBaseCloud(),
00609 cloudName_(cloudName),
00610 mesh_(mesh),
00611 particleProperties_
00612 (
00613 IOobject
00614 (
00615 cloudName + "Properties",
00616 mesh_.time().constant(),
00617 mesh_,
00618 IOobject::MUST_READ,
00619 IOobject::NO_WRITE
00620 )
00621 ),
00622 typeIdList_(particleProperties_.lookup("typeIdList")),
00623 nParticle_(readScalar(particleProperties_.lookup("nEquivalentParticles"))),
00624 cellOccupancy_(mesh_.nCells()),
00625 sigmaTcRMax_
00626 (
00627 IOobject
00628 (
00629 this->name() + "SigmaTcRMax",
00630 mesh_.time().timeName(),
00631 mesh_,
00632 IOobject::MUST_READ,
00633 IOobject::AUTO_WRITE
00634 ),
00635 mesh_
00636 ),
00637 collisionSelectionRemainder_(mesh_.nCells(), 0),
00638 q_
00639 (
00640 IOobject
00641 (
00642 "q",
00643 mesh_.time().timeName(),
00644 mesh_,
00645 IOobject::MUST_READ,
00646 IOobject::AUTO_WRITE
00647 ),
00648 mesh_
00649 ),
00650 fD_
00651 (
00652 IOobject
00653 (
00654 "fD",
00655 mesh_.time().timeName(),
00656 mesh_,
00657 IOobject::MUST_READ,
00658 IOobject::AUTO_WRITE
00659 ),
00660 mesh_
00661 ),
00662 rhoN_
00663 (
00664 IOobject
00665 (
00666 "rhoN",
00667 mesh_.time().timeName(),
00668 mesh_,
00669 IOobject::MUST_READ,
00670 IOobject::AUTO_WRITE
00671 ),
00672 mesh_
00673 ),
00674 rhoM_
00675 (
00676 IOobject
00677 (
00678 "rhoM",
00679 mesh_.time().timeName(),
00680 mesh_,
00681 IOobject::MUST_READ,
00682 IOobject::AUTO_WRITE
00683 ),
00684 mesh_
00685 ),
00686 dsmcRhoN_
00687 (
00688 IOobject
00689 (
00690 "dsmcRhoN",
00691 mesh_.time().timeName(),
00692 mesh_,
00693 IOobject::MUST_READ,
00694 IOobject::AUTO_WRITE
00695 ),
00696 mesh_
00697 ),
00698 linearKE_
00699 (
00700 IOobject
00701 (
00702 "linearKE",
00703 mesh_.time().timeName(),
00704 mesh_,
00705 IOobject::MUST_READ,
00706 IOobject::AUTO_WRITE
00707 ),
00708 mesh_
00709 ),
00710 internalE_
00711 (
00712 IOobject
00713 (
00714 "internalE",
00715 mesh_.time().timeName(),
00716 mesh_,
00717 IOobject::MUST_READ,
00718 IOobject::AUTO_WRITE
00719 ),
00720 mesh_
00721 ),
00722 iDof_
00723 (
00724 IOobject
00725 (
00726 "iDof",
00727 mesh_.time().timeName(),
00728 mesh_,
00729 IOobject::MUST_READ,
00730 IOobject::AUTO_WRITE
00731 ),
00732 mesh_
00733 ),
00734 momentum_
00735 (
00736 IOobject
00737 (
00738 "momentum",
00739 mesh_.time().timeName(),
00740 mesh_,
00741 IOobject::MUST_READ,
00742 IOobject::AUTO_WRITE
00743 ),
00744 mesh_
00745 ),
00746 constProps_(),
00747 rndGen_(label(149382906) + 7183*Pstream::myProcNo()),
00748 boundaryT_
00749 (
00750 volScalarField
00751 (
00752 IOobject
00753 (
00754 "boundaryT",
00755 mesh_.time().timeName(),
00756 mesh_,
00757 IOobject::MUST_READ,
00758 IOobject::AUTO_WRITE
00759 ),
00760 mesh_
00761 )
00762 ),
00763 boundaryU_
00764 (
00765 volVectorField
00766 (
00767 IOobject
00768 (
00769 "boundaryU",
00770 mesh_.time().timeName(),
00771 mesh_,
00772 IOobject::MUST_READ,
00773 IOobject::AUTO_WRITE
00774 ),
00775 mesh_
00776 )
00777 ),
00778 binaryCollisionModel_
00779 (
00780 BinaryCollisionModel<DsmcCloud<ParcelType> >::New
00781 (
00782 particleProperties_,
00783 *this
00784 )
00785 ),
00786 wallInteractionModel_
00787 (
00788 WallInteractionModel<DsmcCloud<ParcelType> >::New
00789 (
00790 particleProperties_,
00791 *this
00792 )
00793 ),
00794 inflowBoundaryModel_
00795 (
00796 InflowBoundaryModel<DsmcCloud<ParcelType> >::New
00797 (
00798 particleProperties_,
00799 *this
00800 )
00801 )
00802 {
00803 buildConstProps();
00804
00805 buildCellOccupancy();
00806
00807
00808
00809 forAll(collisionSelectionRemainder_, i)
00810 {
00811 collisionSelectionRemainder_[i] = rndGen_.scalar01();
00812 }
00813
00814 if (readFields)
00815 {
00816 ParcelType::readFields(*this);
00817 }
00818 }
00819
00820
00821 template<class ParcelType>
00822 Foam::DsmcCloud<ParcelType>::DsmcCloud
00823 (
00824 const word& cloudName,
00825 const fvMesh& mesh,
00826 const IOdictionary& dsmcInitialiseDict
00827 )
00828 :
00829 Cloud<ParcelType>(mesh, cloudName, false),
00830 DsmcBaseCloud(),
00831 cloudName_(cloudName),
00832 mesh_(mesh),
00833 particleProperties_
00834 (
00835 IOobject
00836 (
00837 cloudName + "Properties",
00838 mesh_.time().constant(),
00839 mesh_,
00840 IOobject::MUST_READ,
00841 IOobject::NO_WRITE
00842 )
00843 ),
00844 typeIdList_(particleProperties_.lookup("typeIdList")),
00845 nParticle_(readScalar(particleProperties_.lookup("nEquivalentParticles"))),
00846 cellOccupancy_(),
00847 sigmaTcRMax_
00848 (
00849 IOobject
00850 (
00851 this->name() + "SigmaTcRMax",
00852 mesh_.time().timeName(),
00853 mesh_,
00854 IOobject::NO_READ,
00855 IOobject::AUTO_WRITE
00856 ),
00857 mesh_,
00858 dimensionedScalar("zero", dimensionSet(0, 3, -1, 0, 0), 0.0),
00859 zeroGradientFvPatchScalarField::typeName
00860 ),
00861 collisionSelectionRemainder_(),
00862 q_
00863 (
00864 IOobject
00865 (
00866 this->name() + "q_",
00867 mesh_.time().timeName(),
00868 mesh_,
00869 IOobject::NO_READ,
00870 IOobject::NO_WRITE
00871 ),
00872 mesh_,
00873 dimensionedScalar("zero", dimensionSet(1, 0, -3, 0, 0), 0.0)
00874 ),
00875 fD_
00876 (
00877 IOobject
00878 (
00879 this->name() + "fD_",
00880 mesh_.time().timeName(),
00881 mesh_,
00882 IOobject::NO_READ,
00883 IOobject::NO_WRITE
00884 ),
00885 mesh_,
00886 dimensionedVector
00887 (
00888 "zero",
00889 dimensionSet(1, -1, -2, 0, 0),
00890 vector::zero
00891 )
00892 ),
00893 rhoN_
00894 (
00895 IOobject
00896 (
00897 this->name() + "rhoN_",
00898 mesh_.time().timeName(),
00899 mesh_,
00900 IOobject::NO_READ,
00901 IOobject::NO_WRITE
00902 ),
00903 mesh_,
00904 dimensionedScalar("zero", dimensionSet(0, -3, 0, 0, 0), VSMALL)
00905 ),
00906 rhoM_
00907 (
00908 IOobject
00909 (
00910 this->name() + "rhoM_",
00911 mesh_.time().timeName(),
00912 mesh_,
00913 IOobject::NO_READ,
00914 IOobject::NO_WRITE
00915 ),
00916 mesh_,
00917 dimensionedScalar("zero", dimensionSet(1, -3, 0, 0, 0), VSMALL)
00918 ),
00919 dsmcRhoN_
00920 (
00921 IOobject
00922 (
00923 this->name() + "dsmcRhoN_",
00924 mesh_.time().timeName(),
00925 mesh_,
00926 IOobject::NO_READ,
00927 IOobject::NO_WRITE
00928 ),
00929 mesh_,
00930 dimensionedScalar("zero", dimensionSet(0, -3, 0, 0, 0), 0.0)
00931 ),
00932 linearKE_
00933 (
00934 IOobject
00935 (
00936 this->name() + "linearKE_",
00937 mesh_.time().timeName(),
00938 mesh_,
00939 IOobject::NO_READ,
00940 IOobject::NO_WRITE
00941 ),
00942 mesh_,
00943 dimensionedScalar("zero", dimensionSet(1, -1, -2, 0, 0), 0.0)
00944 ),
00945 internalE_
00946 (
00947 IOobject
00948 (
00949 this->name() + "internalE_",
00950 mesh_.time().timeName(),
00951 mesh_,
00952 IOobject::NO_READ,
00953 IOobject::NO_WRITE
00954 ),
00955 mesh_,
00956 dimensionedScalar("zero", dimensionSet(1, -1, -2, 0, 0), 0.0)
00957 ),
00958 iDof_
00959 (
00960 IOobject
00961 (
00962 this->name() + "iDof_",
00963 mesh_.time().timeName(),
00964 mesh_,
00965 IOobject::NO_READ,
00966 IOobject::NO_WRITE
00967 ),
00968 mesh_,
00969 dimensionedScalar("zero", dimensionSet(0, -3, 0, 0, 0), VSMALL)
00970 ),
00971 momentum_
00972 (
00973 IOobject
00974 (
00975 this->name() + "momentum_",
00976 mesh_.time().timeName(),
00977 mesh_,
00978 IOobject::NO_READ,
00979 IOobject::NO_WRITE
00980 ),
00981 mesh_,
00982 dimensionedVector
00983 (
00984 "zero",
00985 dimensionSet(1, -2, -1, 0, 0),
00986 vector::zero
00987 )
00988 ),
00989 constProps_(),
00990 rndGen_(label(971501) + 1526*Pstream::myProcNo()),
00991 boundaryT_
00992 (
00993 volScalarField
00994 (
00995 IOobject
00996 (
00997 "boundaryT",
00998 mesh_.time().timeName(),
00999 mesh_,
01000 IOobject::NO_READ,
01001 IOobject::NO_WRITE
01002 ),
01003 mesh_,
01004 dimensionedScalar("zero", dimensionSet(0, 0, 0, 1, 0), 0.0)
01005 )
01006 ),
01007 boundaryU_
01008 (
01009 volVectorField
01010 (
01011 IOobject
01012 (
01013 "boundaryU",
01014 mesh_.time().timeName(),
01015 mesh_,
01016 IOobject::NO_READ,
01017 IOobject::NO_WRITE
01018 ),
01019 mesh_,
01020 dimensionedVector
01021 (
01022 "zero",
01023 dimensionSet(0, 1, -1, 0, 0),
01024 vector::zero
01025 )
01026 )
01027 ),
01028 binaryCollisionModel_(),
01029 wallInteractionModel_(),
01030 inflowBoundaryModel_()
01031 {
01032 clear();
01033
01034 buildConstProps();
01035
01036 initialise(dsmcInitialiseDict);
01037 }
01038
01039
01040
01041
01042 template<class ParcelType>
01043 Foam::DsmcCloud<ParcelType>::~DsmcCloud()
01044 {}
01045
01046
01047
01048
01049 template<class ParcelType>
01050 void Foam::DsmcCloud<ParcelType>::evolve()
01051 {
01052 typename ParcelType::trackData td(*this);
01053
01054
01055 resetFields();
01056
01057 if (debug)
01058 {
01059 this->dumpParticlePositions();
01060 }
01061
01062
01063 this->inflowBoundary().inflow();
01064
01065
01066 Cloud<ParcelType>::move(td);
01067
01068
01069 collisions();
01070
01071
01072 calculateFields();
01073 }
01074
01075
01076 template<class ParcelType>
01077 void Foam::DsmcCloud<ParcelType>::info() const
01078 {
01079 label nDsmcParticles = this->size();
01080 reduce(nDsmcParticles, sumOp<label>());
01081
01082 scalar nMol = nDsmcParticles*nParticle_;
01083
01084 vector linearMomentum = linearMomentumOfSystem();
01085 reduce(linearMomentum, sumOp<vector>());
01086
01087 scalar linearKineticEnergy = linearKineticEnergyOfSystem();
01088 reduce(linearKineticEnergy, sumOp<scalar>());
01089
01090 scalar internalEnergy = internalEnergyOfSystem();
01091 reduce(internalEnergy, sumOp<scalar>());
01092
01093 Info<< "Cloud name: " << this->name() << nl
01094 << " Number of dsmc particles = "
01095 << nDsmcParticles
01096 << endl;
01097
01098 if (nDsmcParticles)
01099 {
01100 Info<< " Number of molecules = "
01101 << nMol << nl
01102 << " Mass in system = "
01103 << returnReduce(massInSystem(), sumOp<scalar>()) << nl
01104 << " Average linear momentum = "
01105 << linearMomentum/nMol << nl
01106 << " |Average linear momentum| = "
01107 << mag(linearMomentum)/nMol << nl
01108 << " Average linear kinetic energy = "
01109 << linearKineticEnergy/nMol << nl
01110 << " Average internal energy = "
01111 << internalEnergy/nMol << nl
01112 << " Average total energy = "
01113 << (internalEnergy + linearKineticEnergy)/nMol
01114 << endl;
01115 }
01116 }
01117
01118
01119 template<class ParcelType>
01120 Foam::vector Foam::DsmcCloud<ParcelType>::equipartitionLinearVelocity
01121 (
01122 scalar temperature,
01123 scalar mass
01124 )
01125 {
01126 return
01127 sqrt(kb*temperature/mass)
01128 *vector
01129 (
01130 rndGen_.GaussNormal(),
01131 rndGen_.GaussNormal(),
01132 rndGen_.GaussNormal()
01133 );
01134 }
01135
01136
01137 template<class ParcelType>
01138 Foam::scalar Foam::DsmcCloud<ParcelType>::equipartitionInternalEnergy
01139 (
01140 scalar temperature,
01141 scalar iDof
01142 )
01143 {
01144 scalar Ei = 0.0;
01145
01146 if (iDof < SMALL)
01147 {
01148 return Ei;
01149 }
01150 else if (iDof < 2.0 + SMALL && iDof > 2.0 - SMALL)
01151 {
01152
01153 Ei = -log(rndGen_.scalar01())*kb*temperature;
01154 }
01155 else
01156 {
01157 scalar a = 0.5*iDof - 1;
01158
01159 scalar energyRatio;
01160
01161 scalar P = -1;
01162
01163 do
01164 {
01165 energyRatio = 10*rndGen_.scalar01();
01166
01167 P = pow((energyRatio/a), a)*exp(a - energyRatio);
01168
01169 } while (P < rndGen_.scalar01());
01170
01171 Ei = energyRatio*kb*temperature;
01172 }
01173
01174 return Ei;
01175 }
01176
01177
01178 template<class ParcelType>
01179 void Foam::DsmcCloud<ParcelType>::dumpParticlePositions() const
01180 {
01181 OFstream pObj
01182 (
01183 this->db().time().path()/"parcelPositions_"
01184 + this->name() + "_"
01185 + this->db().time().timeName() + ".obj"
01186 );
01187
01188 forAllConstIter(typename DsmcCloud<ParcelType>, *this, iter)
01189 {
01190 const ParcelType& p = iter();
01191
01192 pObj<< "v " << p.position().x()
01193 << " " << p.position().y()
01194 << " " << p.position().z()
01195 << nl;
01196 }
01197
01198 pObj.flush();
01199 }
01200
01201
01202