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 "moleculeCloud.H"
00027 #include <finiteVolume/fvMesh.H>
00028
00029
00030
00031 namespace Foam
00032 {
00033 defineParticleTypeNameAndDebug(molecule, 0);
00034 defineTemplateTypeNameAndDebug(Cloud<molecule>, 0);
00035 };
00036
00037 Foam::scalar Foam::moleculeCloud::kb = 1.380650277e-23;
00038
00039 Foam::scalar Foam::moleculeCloud::elementaryCharge = 1.602176487e-19;
00040
00041 Foam::scalar Foam::moleculeCloud::vacuumPermittivity = 8.854187817e-12;
00042
00043
00044
00045
00046 void Foam::moleculeCloud::buildConstProps()
00047 {
00048 Info<< nl << "Reading moleculeProperties dictionary." << endl;
00049
00050 const List<word>& idList(pot_.idList());
00051
00052 constPropList_.setSize(idList.size());
00053
00054 const List<word>& siteIdList(pot_.siteIdList());
00055
00056 IOdictionary moleculePropertiesDict
00057 (
00058 IOobject
00059 (
00060 "moleculeProperties",
00061 mesh_.time().constant(),
00062 mesh_,
00063 IOobject::MUST_READ,
00064 IOobject::NO_WRITE,
00065 false
00066 )
00067 );
00068
00069 forAll(idList, i)
00070 {
00071 const word& id(idList[i]);
00072
00073 const dictionary& molDict(moleculePropertiesDict.subDict(id));
00074
00075 List<word> siteIdNames = molDict.lookup("siteIds");
00076
00077 List<label> siteIds(siteIdNames.size());
00078
00079 forAll(siteIdNames, sI)
00080 {
00081 const word& siteId = siteIdNames[sI];
00082
00083 siteIds[sI] = findIndex(siteIdList, siteId);
00084
00085 if (siteIds[sI] == -1)
00086 {
00087 FatalErrorIn("moleculeCloud.C") << nl
00088 << siteId << " site not found."
00089 << nl << abort(FatalError);
00090 }
00091 }
00092
00093 molecule::constantProperties& constProp = constPropList_[i];
00094
00095 constProp = molecule::constantProperties(molDict);
00096
00097 constProp.siteIds() = siteIds;
00098 }
00099 }
00100
00101
00102 void Foam::moleculeCloud::setSiteSizesAndPositions()
00103 {
00104 iterator mol(this->begin());
00105
00106 for (mol = this->begin(); mol != this->end(); ++mol)
00107 {
00108 const molecule::constantProperties& cP = constProps(mol().id());
00109
00110 mol().setSiteSizes(cP.nSites());
00111
00112 mol().setSitePositions(cP);
00113 }
00114 }
00115
00116
00117 void Foam::moleculeCloud::buildCellOccupancy()
00118 {
00119 forAll(cellOccupancy_, cO)
00120 {
00121 cellOccupancy_[cO].clear();
00122 }
00123
00124 iterator mol(this->begin());
00125
00126 for
00127 (
00128 mol = this->begin();
00129 mol != this->end();
00130 ++mol
00131 )
00132 {
00133 cellOccupancy_[mol().cell()].append(&mol());
00134 }
00135
00136 forAll(cellOccupancy_, cO)
00137 {
00138 cellOccupancy_[cO].shrink();
00139 }
00140
00141 il_.ril().referMolecules(cellOccupancy());
00142 }
00143
00144
00145 void Foam::moleculeCloud::calculatePairForce()
00146 {
00147 iterator mol(this->begin());
00148
00149 {
00150
00151
00152 molecule* molI = &mol();
00153
00154 molecule* molJ = &mol();
00155
00156 const directInteractionList& dil(il_.dil());
00157
00158 forAll(dil, d)
00159 {
00160 forAll(cellOccupancy_[d],cellIMols)
00161 {
00162 molI = cellOccupancy_[d][cellIMols];
00163
00164 forAll(dil[d], interactingCells)
00165 {
00166 List< molecule* > cellJ =
00167 cellOccupancy_[dil[d][interactingCells]];
00168
00169 forAll(cellJ, cellJMols)
00170 {
00171 molJ = cellJ[cellJMols];
00172
00173 evaluatePair(molI, molJ);
00174 }
00175 }
00176
00177 forAll(cellOccupancy_[d],cellIOtherMols)
00178 {
00179 molJ = cellOccupancy_[d][cellIOtherMols];
00180
00181 if (molJ > molI)
00182 {
00183 evaluatePair(molI, molJ);
00184 }
00185 }
00186 }
00187 }
00188 }
00189
00190 {
00191
00192
00193 molecule* molK = &mol();
00194
00195 referredCellList& ril(il_.ril());
00196
00197 forAll(ril, r)
00198 {
00199 const List<label>& realCells = ril[r].realCellsForInteraction();
00200
00201 forAll(ril[r], refMols)
00202 {
00203 referredMolecule* molL(&(ril[r][refMols]));
00204
00205 forAll(realCells, rC)
00206 {
00207 List<molecule*> cellK = cellOccupancy_[realCells[rC]];
00208
00209 forAll(cellK, cellKMols)
00210 {
00211 molK = cellK[cellKMols];
00212
00213 evaluatePair(molK, molL);
00214 }
00215 }
00216 }
00217 }
00218 }
00219 }
00220
00221
00222 void Foam::moleculeCloud::calculateTetherForce()
00223 {
00224 const tetherPotentialList& tetherPot(pot_.tetherPotentials());
00225
00226 iterator mol(this->begin());
00227
00228 for (mol = this->begin(); mol != this->end(); ++mol)
00229 {
00230 if (mol().tethered())
00231 {
00232 vector rIT = mol().position() - mol().specialPosition();
00233
00234 label idI = mol().id();
00235
00236 scalar massI = constProps(idI).mass();
00237
00238 vector fIT = tetherPot.force(idI, rIT);
00239
00240 mol().a() += fIT/massI;
00241
00242 mol().potentialEnergy() += tetherPot.energy(idI, rIT);
00243
00244
00245
00246 }
00247 }
00248 }
00249
00250
00251 void Foam::moleculeCloud::calculateExternalForce()
00252 {
00253 iterator mol(this->begin());
00254
00255 for (mol = this->begin(); mol != this->end(); ++mol)
00256 {
00257 mol().a() += pot_.gravity();
00258 }
00259 }
00260
00261
00262 void Foam::moleculeCloud::removeHighEnergyOverlaps()
00263 {
00264 Info<< nl << "Removing high energy overlaps, limit = "
00265 << pot_.potentialEnergyLimit()
00266 << nl << "Removal order:";
00267
00268 forAll(pot_.removalOrder(), rO)
00269 {
00270 Info<< ' ' << pot_.idList()[pot_.removalOrder()[rO]];
00271 }
00272
00273 Info<< nl ;
00274
00275 label initialSize = this->size();
00276
00277 buildCellOccupancy();
00278
00279
00280 iterator mol(this->begin());
00281
00282 {
00283 mol = this->begin();
00284
00285 molecule* molI = &mol();
00286
00287 molecule* molJ = &mol();
00288
00289 DynamicList<molecule*> molsToDelete;
00290
00291 const directInteractionList& dil(il_.dil());
00292
00293 forAll(dil, d)
00294 {
00295 forAll(cellOccupancy_[d],cellIMols)
00296 {
00297 molI = cellOccupancy_[d][cellIMols];
00298
00299 forAll(dil[d], interactingCells)
00300 {
00301 List< molecule* > cellJ =
00302 cellOccupancy_[dil[d][interactingCells]];
00303
00304 forAll(cellJ, cellJMols)
00305 {
00306 molJ = cellJ[cellJMols];
00307
00308 if (evaluatePotentialLimit(molI, molJ))
00309 {
00310 label idI = molI->id();
00311
00312 label idJ = molJ->id();
00313
00314 if
00315 (
00316 idI == idJ
00317 || findIndex(pot_.removalOrder(), idJ)
00318 < findIndex(pot_.removalOrder(), idI)
00319 )
00320 {
00321 if (findIndex(molsToDelete, molJ) == -1)
00322 {
00323 molsToDelete.append(molJ);
00324 }
00325 }
00326 else if (findIndex(molsToDelete, molI) == -1)
00327 {
00328 molsToDelete.append(molI);
00329 }
00330 }
00331 }
00332 }
00333 }
00334
00335 forAll(cellOccupancy_[d],cellIOtherMols)
00336 {
00337 molJ = cellOccupancy_[d][cellIOtherMols];
00338
00339 if (molJ > molI)
00340 {
00341 if (evaluatePotentialLimit(molI, molJ))
00342 {
00343 label idI = molI->id();
00344
00345 label idJ = molJ->id();
00346
00347 if
00348 (
00349 idI == idJ
00350 || findIndex(pot_.removalOrder(), idJ)
00351 < findIndex(pot_.removalOrder(), idI)
00352 )
00353 {
00354 if (findIndex(molsToDelete, molJ) == -1)
00355 {
00356 molsToDelete.append(molJ);
00357 }
00358 }
00359 else if (findIndex(molsToDelete, molI) == -1)
00360 {
00361 molsToDelete.append(molI);
00362 }
00363 }
00364 }
00365 }
00366 }
00367
00368 forAll (molsToDelete, mTD)
00369 {
00370 deleteParticle(*(molsToDelete[mTD]));
00371 }
00372 }
00373
00374 buildCellOccupancy();
00375
00376
00377
00378 {
00379 molecule* molK = &mol();
00380
00381 DynamicList<molecule*> molsToDelete;
00382
00383 referredCellList& ril(il_.ril());
00384
00385 forAll(ril, r)
00386 {
00387 referredCell& refCell = ril[r];
00388
00389 forAll(refCell, refMols)
00390 {
00391 referredMolecule* molL = &(refCell[refMols]);
00392
00393 List <label> realCells = refCell.realCellsForInteraction();
00394
00395 forAll(realCells, rC)
00396 {
00397 label cellK = realCells[rC];
00398
00399 List<molecule*> cellKMols = cellOccupancy_[cellK];
00400
00401 forAll(cellKMols, cKM)
00402 {
00403 molK = cellKMols[cKM];
00404
00405 if (evaluatePotentialLimit(molK, molL))
00406 {
00407 label idK = molK->id();
00408
00409 label idL = molL->id();
00410
00411 if
00412 (
00413 findIndex(pot_.removalOrder(), idK)
00414 < findIndex(pot_.removalOrder(), idL)
00415 )
00416 {
00417 if (findIndex(molsToDelete, molK) == -1)
00418 {
00419 molsToDelete.append(molK);
00420 }
00421 }
00422
00423 else if
00424 (
00425 findIndex(pot_.removalOrder(), idK)
00426 == findIndex(pot_.removalOrder(), idL)
00427 )
00428 {
00429 if
00430 (
00431 Pstream::myProcNo() == refCell.sourceProc()
00432 && cellK <= refCell.sourceCell()
00433 )
00434 {
00435 if (findIndex(molsToDelete, molK) == -1)
00436 {
00437 molsToDelete.append(molK);
00438 }
00439 }
00440
00441 else if
00442 (
00443 Pstream::myProcNo() < refCell.sourceProc()
00444 )
00445 {
00446 if (findIndex(molsToDelete, molK) == -1)
00447 {
00448 molsToDelete.append(molK);
00449 }
00450 }
00451 }
00452 }
00453 }
00454 }
00455 }
00456 }
00457
00458 forAll (molsToDelete, mTD)
00459 {
00460 deleteParticle(*(molsToDelete[mTD]));
00461 }
00462 }
00463
00464 buildCellOccupancy();
00465
00466 label molsRemoved = initialSize - this->size();
00467
00468 if (Pstream::parRun())
00469 {
00470 reduce(molsRemoved, sumOp<label>());
00471 }
00472
00473 Info<< tab << molsRemoved << " molecules removed" << endl;
00474 }
00475
00476
00477 void Foam::moleculeCloud::initialiseMolecules
00478 (
00479 const IOdictionary& mdInitialiseDict
00480 )
00481 {
00482 Info<< nl
00483 << "Initialising molecules in each zone specified in mdInitialiseDict."
00484 << endl;
00485
00486 const cellZoneMesh& cellZones = mesh_.cellZones();
00487
00488 if (!cellZones.size())
00489 {
00490 FatalErrorIn("void Foam::moleculeCloud::initialiseMolecules")
00491 << "No cellZones found in the mesh."
00492 << abort(FatalError);
00493 }
00494
00495 forAll (cellZones, z)
00496 {
00497 const cellZone& zone(cellZones[z]);
00498
00499 if (zone.size())
00500 {
00501 if (!mdInitialiseDict.found(zone.name()))
00502 {
00503 Info<< "No specification subDictionary for zone "
00504 << zone.name() << " found, skipping." << endl;
00505 }
00506 else
00507 {
00508 const dictionary& zoneDict =
00509 mdInitialiseDict.subDict(zone.name());
00510
00511 const scalar temperature
00512 (
00513 readScalar(zoneDict.lookup("temperature"))
00514 );
00515
00516 const vector bulkVelocity(zoneDict.lookup("bulkVelocity"));
00517
00518 List<word> latticeIds
00519 (
00520 zoneDict.lookup("latticeIds")
00521 );
00522
00523 List<vector> latticePositions
00524 (
00525 zoneDict.lookup("latticePositions")
00526 );
00527
00528 if(latticeIds.size() != latticePositions.size())
00529 {
00530 FatalErrorIn("Foam::moleculeCloud::initialiseMolecules")
00531 << "latticeIds and latticePositions must be the same "
00532 << " size." << nl
00533 << abort(FatalError);
00534 }
00535
00536 diagTensor latticeCellShape
00537 (
00538 zoneDict.lookup("latticeCellShape")
00539 );
00540
00541 scalar latticeCellScale = 0.0;
00542
00543 if (zoneDict.found("numberDensity"))
00544 {
00545 scalar numberDensity = readScalar
00546 (
00547 zoneDict.lookup("numberDensity")
00548 );
00549
00550 if (numberDensity < VSMALL)
00551 {
00552 WarningIn("moleculeCloud::initialiseMolecules")
00553 << "numberDensity too small, not filling zone "
00554 << zone.name() << endl;
00555
00556 continue;
00557 }
00558
00559 latticeCellScale = pow
00560 (
00561 latticeIds.size()/(det(latticeCellShape)*numberDensity),
00562 (1.0/3.0)
00563 );
00564 }
00565 else if (zoneDict.found("massDensity"))
00566 {
00567 scalar unitCellMass = 0.0;
00568
00569 forAll(latticeIds, i)
00570 {
00571 label id = findIndex(pot_.idList(), latticeIds[i]);
00572
00573 const molecule::constantProperties& cP(constProps(id));
00574
00575 unitCellMass += cP.mass();
00576 }
00577
00578 scalar massDensity = readScalar
00579 (
00580 zoneDict.lookup("massDensity")
00581 );
00582
00583 if (massDensity < VSMALL)
00584 {
00585 WarningIn("moleculeCloud::initialiseMolecules")
00586 << "massDensity too small, not filling zone "
00587 << zone.name() << endl;
00588
00589 continue;
00590 }
00591
00592
00593 latticeCellScale = pow
00594 (
00595 unitCellMass/(det(latticeCellShape)*massDensity),
00596 (1.0/3.0)
00597 );
00598 }
00599 else
00600 {
00601 FatalErrorIn("Foam::moleculeCloud::initialiseMolecules")
00602 << "massDensity or numberDensity not specified " << nl
00603 << abort(FatalError);
00604 }
00605
00606 latticeCellShape *= latticeCellScale;
00607
00608 vector anchor(zoneDict.lookup("anchor"));
00609
00610 bool tethered = false;
00611
00612 if (zoneDict.found("tetherSiteIds"))
00613 {
00614 tethered = bool
00615 (
00616 List<word>(zoneDict.lookup("tetherSiteIds")).size()
00617 );
00618 }
00619
00620 const vector orientationAngles
00621 (
00622 zoneDict.lookup("orientationAngles")
00623 );
00624
00625 scalar phi
00626 (
00627 orientationAngles.x()*mathematicalConstant::pi/180.0
00628 );
00629
00630 scalar theta
00631 (
00632 orientationAngles.y()*mathematicalConstant::pi/180.0
00633 );
00634
00635 scalar psi
00636 (
00637 orientationAngles.z()*mathematicalConstant::pi/180.0
00638 );
00639
00640 const tensor R
00641 (
00642 cos(psi)*cos(phi) - cos(theta)*sin(phi)*sin(psi),
00643 cos(psi)*sin(phi) + cos(theta)*cos(phi)*sin(psi),
00644 sin(psi)*sin(theta),
00645 - sin(psi)*cos(phi) - cos(theta)*sin(phi)*cos(psi),
00646 - sin(psi)*sin(phi) + cos(theta)*cos(phi)*cos(psi),
00647 cos(psi)*sin(theta),
00648 sin(theta)*sin(phi),
00649 - sin(theta)*cos(phi),
00650 cos(theta)
00651 );
00652
00653
00654
00655
00656
00657 vector zoneMin = VGREAT*vector::one;
00658
00659 vector zoneMax = -VGREAT*vector::one;
00660
00661 forAll (zone, cell)
00662 {
00663 const point cellCentre = mesh_.cellCentres()[zone[cell]];
00664
00665 if (cellCentre.x() > zoneMax.x())
00666 {
00667 zoneMax.x() = cellCentre.x();
00668 }
00669 if (cellCentre.x() < zoneMin.x())
00670 {
00671 zoneMin.x() = cellCentre.x();
00672 }
00673 if (cellCentre.y() > zoneMax.y())
00674 {
00675 zoneMax.y() = cellCentre.y();
00676 }
00677 if (cellCentre.y() < zoneMin.y())
00678 {
00679 zoneMin.y() = cellCentre.y();
00680 }
00681 if (cellCentre.z() > zoneMax.z())
00682 {
00683 zoneMax.z() = cellCentre.z();
00684 }
00685 if (cellCentre.z() < zoneMin.z())
00686 {
00687 zoneMin.z() = cellCentre.z();
00688 }
00689 }
00690
00691 point zoneMid = 0.5*(zoneMin + zoneMax);
00692
00693 point latticeMid = inv(latticeCellShape) & (R.T()
00694 & (zoneMid - anchor));
00695
00696 point latticeAnchor
00697 (
00698 label(latticeMid.x() + 0.5*sign(latticeMid.x())),
00699 label(latticeMid.y() + 0.5*sign(latticeMid.y())),
00700 label(latticeMid.z() + 0.5*sign(latticeMid.z()))
00701 );
00702
00703 anchor += (R & (latticeCellShape & latticeAnchor));
00704
00705
00706
00707
00708
00709
00710
00711 label n = 0;
00712
00713 label totalZoneMols = 0;
00714
00715 label molsPlacedThisIteration = 0;
00716
00717 while
00718 (
00719 molsPlacedThisIteration != 0
00720 || totalZoneMols == 0
00721 )
00722 {
00723 label sizeBeforeIteration = this->size();
00724
00725 bool partOfLayerInBounds = false;
00726
00727
00728
00729
00730
00731 if (n == 0)
00732 {
00733
00734
00735
00736 labelVector unitCellLatticePosition(0,0,0);
00737
00738 forAll(latticePositions, p)
00739 {
00740 label id = findIndex(pot_.idList(), latticeIds[p]);
00741
00742 const vector& latticePosition =
00743 vector
00744 (
00745 unitCellLatticePosition.x(),
00746 unitCellLatticePosition.y(),
00747 unitCellLatticePosition.z()
00748 )
00749 + latticePositions[p];
00750
00751 point globalPosition =
00752 anchor + (R & (latticeCellShape & latticePosition));
00753
00754 partOfLayerInBounds =
00755 mesh_.bounds().contains(globalPosition);
00756
00757 label cell = mesh_.findCell(globalPosition);
00758
00759 if (findIndex(zone, cell) != -1)
00760 {
00761 createMolecule
00762 (
00763 globalPosition,
00764 cell,
00765 id,
00766 tethered,
00767 temperature,
00768 bulkVelocity
00769 );
00770 }
00771 }
00772 }
00773 else
00774 {
00775
00776
00777 labelVector unitCellLatticePosition(0,0,0);
00778
00779 for
00780 (
00781 unitCellLatticePosition.z() = -n;
00782 unitCellLatticePosition.z() <= n;
00783 unitCellLatticePosition.z() += 2*n
00784 )
00785 {
00786 for
00787 (
00788 unitCellLatticePosition.y() = -n;
00789 unitCellLatticePosition.y() <= n;
00790 unitCellLatticePosition.y()++
00791 )
00792 {
00793 for
00794 (
00795 unitCellLatticePosition.x() = -n;
00796 unitCellLatticePosition.x() <= n;
00797 unitCellLatticePosition.x()++
00798 )
00799 {
00800 forAll(latticePositions, p)
00801 {
00802 label id = findIndex
00803 (
00804 pot_.idList(),
00805 latticeIds[p]
00806 );
00807
00808 const vector& latticePosition =
00809 vector
00810 (
00811 unitCellLatticePosition.x(),
00812 unitCellLatticePosition.y(),
00813 unitCellLatticePosition.z()
00814 )
00815 + latticePositions[p];
00816
00817 point globalPosition = anchor
00818 + (R
00819 &(latticeCellShape & latticePosition));
00820
00821 partOfLayerInBounds =
00822 mesh_.bounds().contains(globalPosition);
00823
00824 label cell = mesh_.findCell
00825 (
00826 globalPosition
00827 );
00828
00829 if (findIndex(zone, cell) != -1)
00830 {
00831 createMolecule
00832 (
00833 globalPosition,
00834 cell,
00835 id,
00836 tethered,
00837 temperature,
00838 bulkVelocity
00839 );
00840 }
00841 }
00842 }
00843 }
00844 }
00845
00846 for
00847 (
00848 unitCellLatticePosition.z() = -(n-1);
00849 unitCellLatticePosition.z() <= (n-1);
00850 unitCellLatticePosition.z()++
00851 )
00852 {
00853 for (label iR = 0; iR <= 2*n -1; iR++)
00854 {
00855 unitCellLatticePosition.x() = n;
00856
00857 unitCellLatticePosition.y() = -n + (iR + 1);
00858
00859 for (label iK = 0; iK < 4; iK++)
00860 {
00861 forAll(latticePositions, p)
00862 {
00863 label id = findIndex
00864 (
00865 pot_.idList(),
00866 latticeIds[p]
00867 );
00868
00869 const vector& latticePosition =
00870 vector
00871 (
00872 unitCellLatticePosition.x(),
00873 unitCellLatticePosition.y(),
00874 unitCellLatticePosition.z()
00875 )
00876 + latticePositions[p];
00877
00878 point globalPosition = anchor
00879 + (R
00880 &(latticeCellShape & latticePosition));
00881
00882 partOfLayerInBounds =
00883 mesh_.bounds().contains(globalPosition);
00884
00885 label cell = mesh_.findCell
00886 (
00887 globalPosition
00888 );
00889
00890 if (findIndex(zone, cell) != -1)
00891 {
00892 createMolecule
00893 (
00894 globalPosition,
00895 cell,
00896 id,
00897 tethered,
00898 temperature,
00899 bulkVelocity
00900 );
00901 }
00902 }
00903
00904 unitCellLatticePosition =
00905 labelVector
00906 (
00907 - unitCellLatticePosition.y(),
00908 unitCellLatticePosition.x(),
00909 unitCellLatticePosition.z()
00910 );
00911 }
00912 }
00913 }
00914 }
00915
00916
00917
00918
00919
00920 if
00921 (
00922 totalZoneMols == 0
00923 && !partOfLayerInBounds
00924 )
00925 {
00926 WarningIn("Foam::moleculeCloud::initialiseMolecules()")
00927 << "A whole layer of unit cells was placed "
00928 << "outside the bounds of the mesh, but no "
00929 << "molecules have been placed in zone '"
00930 << zone.name()
00931 << "'. This is likely to be because the zone "
00932 << "has few cells ("
00933 << zone.size()
00934 << " in this case) and no lattice position "
00935 << "fell inside them. "
00936 << "Aborting filling this zone."
00937 << endl;
00938
00939 break;
00940 }
00941
00942 molsPlacedThisIteration =
00943 this->size() - sizeBeforeIteration;
00944
00945 totalZoneMols += molsPlacedThisIteration;
00946
00947 n++;
00948 }
00949 }
00950 }
00951 }
00952 }
00953
00954
00955 void Foam::moleculeCloud::createMolecule
00956 (
00957 const point& position,
00958 label cell,
00959 label id,
00960 bool tethered,
00961 scalar temperature,
00962 const vector& bulkVelocity
00963 )
00964 {
00965 const Cloud<molecule>& cloud = *this;
00966
00967 if (cell == -1)
00968 {
00969 cell = mesh_.findCell(position);
00970 }
00971
00972 if (cell == -1)
00973 {
00974 FatalErrorIn("Foam::moleculeCloud::createMolecule")
00975 << "Position specified does not correspond to a mesh cell." << nl
00976 << abort(FatalError);
00977 }
00978
00979 point specialPosition(vector::zero);
00980
00981 label special = 0;
00982
00983 if (tethered)
00984 {
00985 specialPosition = position;
00986
00987 special = molecule::SPECIAL_TETHERED;
00988 }
00989
00990 const molecule::constantProperties& cP(constProps(id));
00991
00992 vector v = equipartitionLinearVelocity(temperature, cP.mass());
00993
00994 v += bulkVelocity;
00995
00996 vector pi = vector::zero;
00997
00998 tensor Q = I;
00999
01000 if (!cP.pointMolecule())
01001 {
01002 pi = equipartitionAngularMomentum(temperature, cP);
01003
01004 scalar phi(rndGen_.scalar01()*mathematicalConstant::twoPi);
01005
01006 scalar theta(rndGen_.scalar01()*mathematicalConstant::twoPi);
01007
01008 scalar psi(rndGen_.scalar01()*mathematicalConstant::twoPi);
01009
01010 Q = tensor
01011 (
01012 cos(psi)*cos(phi) - cos(theta)*sin(phi)*sin(psi),
01013 cos(psi)*sin(phi) + cos(theta)*cos(phi)*sin(psi),
01014 sin(psi)*sin(theta),
01015 - sin(psi)*cos(phi) - cos(theta)*sin(phi)*cos(psi),
01016 - sin(psi)*sin(phi) + cos(theta)*cos(phi)*cos(psi),
01017 cos(psi)*sin(theta),
01018 sin(theta)*sin(phi),
01019 - sin(theta)*cos(phi),
01020 cos(theta)
01021 );
01022 }
01023
01024 addParticle
01025 (
01026 new molecule
01027 (
01028 cloud,
01029 position,
01030 cell,
01031 Q,
01032 v,
01033 vector::zero,
01034 pi,
01035 vector::zero,
01036 specialPosition,
01037 constProps(id),
01038 special,
01039 id
01040 )
01041 );
01042 }
01043
01044
01045 Foam::label Foam::moleculeCloud::nSites() const
01046 {
01047 label n = 0;
01048
01049 const_iterator mol(this->begin());
01050
01051 for (mol = this->begin(); mol != this->end(); ++mol)
01052 {
01053 n += constProps(mol().id()).nSites();
01054 }
01055
01056 return n;
01057 }
01058
01059
01060
01061
01062 Foam::moleculeCloud::moleculeCloud
01063 (
01064 const polyMesh& mesh,
01065 const potential& pot,
01066 bool readFields
01067 )
01068 :
01069 Cloud<molecule>(mesh, "moleculeCloud", false),
01070 mesh_(mesh),
01071 pot_(pot),
01072 cellOccupancy_(mesh_.nCells()),
01073 il_(mesh_, pot_.pairPotentials().rCutMaxSqr(), false),
01074 constPropList_(),
01075 rndGen_(clock::getTime())
01076 {
01077 if (readFields)
01078 {
01079 molecule::readFields(*this);
01080 }
01081
01082 buildConstProps();
01083
01084 setSiteSizesAndPositions();
01085
01086 removeHighEnergyOverlaps();
01087
01088 calculateForce();
01089 }
01090
01091
01092 Foam::moleculeCloud::moleculeCloud
01093 (
01094 const polyMesh& mesh,
01095 const potential& pot,
01096 const IOdictionary& mdInitialiseDict,
01097 bool readFields
01098 )
01099 :
01100 Cloud<molecule>(mesh, "moleculeCloud", false),
01101 mesh_(mesh),
01102 pot_(pot),
01103 il_(mesh_),
01104 constPropList_(),
01105 rndGen_(clock::getTime())
01106 {
01107 if (readFields)
01108 {
01109 molecule::readFields(*this);
01110 }
01111
01112 clear();
01113
01114 buildConstProps();
01115
01116 initialiseMolecules(mdInitialiseDict);
01117 }
01118
01119
01120
01121
01122 void Foam::moleculeCloud::evolve()
01123 {
01124 molecule::trackData td0(*this, 0);
01125 Cloud<molecule>::move(td0);
01126
01127 molecule::trackData td1(*this, 1);
01128 Cloud<molecule>::move(td1);
01129
01130 molecule::trackData td2(*this, 2);
01131 Cloud<molecule>::move(td2);
01132
01133 calculateForce();
01134
01135 molecule::trackData td3(*this, 3);
01136 Cloud<molecule>::move(td3);
01137 }
01138
01139
01140 void Foam::moleculeCloud::calculateForce()
01141 {
01142 buildCellOccupancy();
01143
01144 iterator mol(this->begin());
01145
01146
01147 for (mol = this->begin(); mol != this->end(); ++mol)
01148 {
01149 mol().siteForces() = vector::zero;
01150
01151 mol().potentialEnergy() = 0.0;
01152
01153 mol().rf() = tensor::zero;
01154 }
01155
01156 calculatePairForce();
01157
01158 calculateTetherForce();
01159
01160 calculateExternalForce();
01161 }
01162
01163
01164 void Foam::moleculeCloud::applyConstraintsAndThermostats
01165 (
01166 const scalar targetTemperature,
01167 const scalar measuredTemperature
01168 )
01169 {
01170 scalar temperatureCorrectionFactor =
01171 sqrt(targetTemperature/measuredTemperature);
01172
01173 Info<< "----------------------------------------" << nl
01174 << "Temperature equilibration" << nl
01175 << "Target temperature = "
01176 << targetTemperature << nl
01177 << "Measured temperature = "
01178 << measuredTemperature << nl
01179 << "Temperature correction factor = "
01180 << temperatureCorrectionFactor << nl
01181 << "----------------------------------------"
01182 << endl;
01183
01184 iterator mol(this->begin());
01185
01186 for (mol = this->begin(); mol != this->end(); ++mol)
01187 {
01188 mol().v() *= temperatureCorrectionFactor;
01189
01190 mol().pi() *= temperatureCorrectionFactor;
01191 }
01192 }
01193
01194
01195 void Foam::moleculeCloud::writeXYZ(const fileName& fName) const
01196 {
01197 OFstream str(fName);
01198
01199 str << nSites() << nl << "moleculeCloud site positions in angstroms" << nl;
01200
01201 const_iterator mol(this->begin());
01202
01203 for (mol = this->begin(); mol != this->end(); ++mol)
01204 {
01205 const molecule::constantProperties& cP = constProps(mol().id());
01206
01207 forAll(mol().sitePositions(), i)
01208 {
01209 const point& sP = mol().sitePositions()[i];
01210
01211 str << pot_.siteIdList()[cP.siteIds()[i]]
01212 << ' ' << sP.x()*1e10
01213 << ' ' << sP.y()*1e10
01214 << ' ' << sP.z()*1e10
01215 << nl;
01216 }
01217 }
01218 }
01219
01220
01221