42 void Foam::moleculeCloud::buildConstProps()
44 Info<<
nl <<
"Reading moleculeProperties dictionary." <<
endl;
46 const List<word>& idList(pot_.
idList());
48 constPropList_.setSize(idList.size());
50 const List<word>& siteIdList(pot_.
siteIdList());
52 IOdictionary moleculePropertiesDict
67 const word&
id = idList[i];
68 const dictionary& molDict = moleculePropertiesDict.subDict(
id);
70 List<word> siteIdNames = molDict.lookup(
"siteIds");
72 List<label> siteIds(siteIdNames.size());
76 const word& siteId = siteIdNames[sI];
78 siteIds[sI] = siteIdList.find(siteId);
80 if (siteIds[sI] == -1)
83 << siteId <<
" site not found."
88 molecule::constantProperties&
constProp = constPropList_[i];
90 constProp = molecule::constantProperties(molDict);
97 void Foam::moleculeCloud::setSiteSizesAndPositions()
99 for (molecule& mol : *
this)
101 const molecule::constantProperties& cP = constProps(mol.id());
103 mol.setSiteSizes(cP.nSites());
105 mol.setSitePositions(cP);
110 void Foam::moleculeCloud::buildCellOccupancy()
112 for (
auto& list : cellOccupancy_)
117 for (molecule& mol : *
this)
119 cellOccupancy_[mol.cell()].append(&mol);
122 for (
auto& list : cellOccupancy_)
129 void Foam::moleculeCloud::calculatePairForce()
137 molecule* molI =
nullptr;
138 molecule* molJ =
nullptr;
147 forAll(cellOccupancy_[d],cellIMols)
149 molI = cellOccupancy_[d][cellIMols];
151 forAll(dil[d], interactingCells)
153 List<molecule*> cellJ =
154 cellOccupancy_[dil[d][interactingCells]];
158 molJ = cellJ[cellJMols];
160 evaluatePair(*molI, *molJ);
164 forAll(cellOccupancy_[d], cellIOtherMols)
166 molJ = cellOccupancy_[d][cellIOtherMols];
170 evaluatePair(*molI, *molJ);
178 il_.receiveReferredData(pBufs, startOfRequests);
185 List<IDLList<molecule>>& referredMols = il_.referredParticles();
189 const List<label>& realCells = ril[r];
191 IDLList<molecule>& refMols = referredMols[r];
193 for (molecule& refMol : refMols)
197 List<molecule*> celli = cellOccupancy_[realCells[rC]];
201 molI = celli[cellIMols];
203 evaluatePair(*molI, refMol);
212 void Foam::moleculeCloud::calculateTetherForce()
214 const tetherPotentialList& tetherPot(pot_.tetherPotentials());
216 for (molecule& mol : *
this)
220 vector rIT = mol.position() - mol.specialPosition();
222 label idI = mol.id();
224 scalar massI = constProps(idI).mass();
226 vector fIT = tetherPot.force(idI, rIT);
228 mol.a() += fIT/massI;
230 mol.potentialEnergy() += tetherPot.energy(idI, rIT);
239 void Foam::moleculeCloud::calculateExternalForce()
241 for (molecule& mol : *
this)
243 mol.a() += pot_.gravity();
248 void Foam::moleculeCloud::removeHighEnergyOverlaps()
250 Info<<
nl <<
"Removing high energy overlaps, limit = "
251 << pot_.potentialEnergyLimit()
252 <<
nl <<
"Removal order:";
254 forAll(pot_.removalOrder(), rO)
256 Info<<
' ' << pot_.idList()[pot_.removalOrder()[rO]];
261 label initialSize = this->size();
263 buildCellOccupancy();
267 molecule* molI =
nullptr;
268 molecule* molJ =
nullptr;
271 DynamicList<molecule*> molsToDelete;
277 forAll(cellOccupancy_[d],cellIMols)
279 molI = cellOccupancy_[d][cellIMols];
281 forAll(dil[d], interactingCells)
283 List<molecule*> cellJ =
284 cellOccupancy_[dil[d][interactingCells]];
288 molJ = cellJ[cellJMols];
290 if (evaluatePotentialLimit(*molI, *molJ))
292 const label idI = molI->id();
293 const label idJ = molJ->id();
298 || pot_.removalOrder().find(idJ)
299 < pot_.removalOrder().find(idI)
302 if (!molsToDelete.found(molJ))
304 molsToDelete.append(molJ);
307 else if (!molsToDelete.found(molI))
309 molsToDelete.append(molI);
316 forAll(cellOccupancy_[d], cellIOtherMols)
318 molJ = cellOccupancy_[d][cellIOtherMols];
322 if (evaluatePotentialLimit(*molI, *molJ))
324 const label idI = molI->id();
325 const label idJ = molJ->id();
330 || pot_.removalOrder().find(idJ)
331 < pot_.removalOrder().find(idI)
334 if (!molsToDelete.found(molJ))
336 molsToDelete.append(molJ);
339 else if (!molsToDelete.found(molI))
341 molsToDelete.append(molI);
350 deleteParticle(*(molsToDelete[mTD]));
354 buildCellOccupancy();
364 il_.receiveReferredData(pBufs, startOfRequests);
369 DynamicList<molecule*> molsToDelete;
373 List<IDLList<molecule>>& referredMols = il_.referredParticles();
377 IDLList<molecule>& refMols = referredMols[r];
379 for (molecule& refMol : refMols)
383 const List<label>& realCells = ril[r];
387 label celli = realCells[rC];
389 List<molecule*> cellIMols = cellOccupancy_[celli];
393 molI = cellIMols[cIM];
395 if (evaluatePotentialLimit(*molI, *molJ))
397 const label idI = molI->id();
398 const label idJ = molJ->id();
402 pot_.removalOrder().find(idI)
403 < pot_.removalOrder().find(idJ)
406 if (!molsToDelete.found(molI))
408 molsToDelete.append(molI);
413 pot_.removalOrder().find(idI)
414 == pot_.removalOrder().find(idJ)
422 if (molI->origId() > molJ->origId())
424 if (!molsToDelete.found(molI))
426 molsToDelete.append(molI);
438 deleteParticle(*(molsToDelete[mTD]));
442 buildCellOccupancy();
450 il_.receiveReferredData(pBufs, startOfRequests);
452 label molsRemoved = initialSize - this->size();
456 reduce(molsRemoved, sumOp<label>());
459 Info<<
tab << molsRemoved <<
" molecules removed" <<
endl;
463 void Foam::moleculeCloud::initialiseMolecules
465 const IOdictionary& mdInitialiseDict
469 <<
"Initialising molecules in each zone specified in mdInitialiseDict."
474 if (!cellZones.size())
477 <<
"No cellZones found in the mesh."
481 for (
const cellZone& zone : cellZones)
485 if (!mdInitialiseDict.found(zone.name()))
487 Info<<
"No specification subDictionary for zone "
488 << zone.name() <<
" found, skipping." <<
endl;
492 const dictionary& zoneDict =
493 mdInitialiseDict.subDict(zone.name());
495 const scalar temperature
497 zoneDict.get<scalar>(
"temperature")
502 zoneDict.get<
vector>(
"bulkVelocity")
505 List<word> latticeIds
507 zoneDict.lookup(
"latticeIds")
510 List<vector> latticePositions
512 zoneDict.lookup(
"latticePositions")
515 if (latticeIds.size() != latticePositions.size())
518 <<
"latticeIds and latticePositions must be the same "
525 zoneDict.lookup(
"latticeCellShape")
528 scalar latticeCellScale = 0.0;
530 if (zoneDict.found(
"numberDensity"))
532 const scalar numberDensity
534 zoneDict.get<scalar>(
"numberDensity")
537 if (numberDensity < VSMALL)
540 <<
"numberDensity too small, not filling zone "
541 << zone.name() <<
endl;
546 latticeCellScale =
pow
548 latticeIds.size()/(
det(latticeCellShape)*numberDensity),
552 else if (zoneDict.found(
"massDensity"))
554 scalar unitCellMass = 0.0;
558 label id = pot_.idList().find(latticeIds[i]);
560 const molecule::constantProperties& cP(constProps(
id));
562 unitCellMass += cP.mass();
565 const scalar massDensity
567 zoneDict.get<scalar>(
"massDensity")
570 if (massDensity < VSMALL)
573 <<
"massDensity too small, not filling zone "
574 << zone.name() <<
endl;
580 latticeCellScale =
pow
582 unitCellMass/(
det(latticeCellShape)*massDensity),
589 <<
"massDensity or numberDensity not specified " <<
nl
593 latticeCellShape *= latticeCellScale;
597 bool tethered =
false;
599 if (zoneDict.found(
"tetherSiteIds"))
603 List<word>(zoneDict.lookup(
"tetherSiteIds")).size()
607 const vector orientationAngles
609 zoneDict.get<
vector>(
"orientationAngles")
613 const scalar theta(
degToRad(orientationAngles.y()));
639 const point cellCentre = mesh_.cellCentres()[zone[cell]];
641 if (cellCentre.x() > zoneMax.x())
643 zoneMax.
x() = cellCentre.x();
645 if (cellCentre.x() < zoneMin.x())
647 zoneMin.x() = cellCentre.x();
649 if (cellCentre.y() > zoneMax.y())
651 zoneMax.y() = cellCentre.y();
653 if (cellCentre.y() < zoneMin.y())
655 zoneMin.y() = cellCentre.y();
657 if (cellCentre.z() > zoneMax.z())
659 zoneMax.z() = cellCentre.z();
661 if (cellCentre.z() < zoneMin.z())
663 zoneMin.z() = cellCentre.z();
667 point zoneMid = 0.5*(zoneMin + zoneMax);
669 point latticeMid =
inv(latticeCellShape) & (
R.T()
670 & (zoneMid - anchor));
674 label(latticeMid.x() + 0.5*
sign(latticeMid.x())),
675 label(latticeMid.y() + 0.5*
sign(latticeMid.y())),
676 label(latticeMid.z() + 0.5*
sign(latticeMid.z()))
679 anchor += (
R & (latticeCellShape & latticeAnchor));
689 label totalZoneMols = 0;
691 label molsPlacedThisIteration = 0;
695 molsPlacedThisIteration != 0
696 || totalZoneMols == 0
699 label sizeBeforeIteration = this->size();
701 bool partOfLayerInBounds =
false;
716 label id = pot_.idList().find(latticeIds[
p]);
718 const vector& latticePosition =
721 unitCellLatticePosition.x(),
722 unitCellLatticePosition.y(),
723 unitCellLatticePosition.z()
725 + latticePositions[
p];
727 point globalPosition =
729 + (
R & (latticeCellShape & latticePosition));
731 partOfLayerInBounds = mesh_.bounds().contains
737 mesh_.cellTree().findInside(globalPosition);
739 if (zone.found(cell))
761 unitCellLatticePosition.z() = -
n;
762 unitCellLatticePosition.z() <=
n;
763 unitCellLatticePosition.z() += 2*
n
768 unitCellLatticePosition.y() = -
n;
769 unitCellLatticePosition.y() <=
n;
770 unitCellLatticePosition.y()++
775 unitCellLatticePosition.x() = -
n;
776 unitCellLatticePosition.x() <=
n;
777 unitCellLatticePosition.x()++
783 pot_.idList().find(latticeIds[
p]);
785 const vector& latticePosition =
788 unitCellLatticePosition.x(),
789 unitCellLatticePosition.y(),
790 unitCellLatticePosition.z()
792 + latticePositions[
p];
794 point globalPosition =
804 partOfLayerInBounds =
805 mesh_.bounds().contains
811 mesh_.cellTree().findInside
816 if (zone.found(cell))
835 unitCellLatticePosition.z() = -(
n-1);
836 unitCellLatticePosition.z() <= (
n-1);
837 unitCellLatticePosition.z()++
840 for (
label iR = 0; iR <= 2*
n -1; iR++)
842 unitCellLatticePosition.x() =
n;
844 unitCellLatticePosition.y() = -
n + (iR + 1);
846 for (
label iK = 0; iK < 4; iK++)
851 pot_.idList().find(latticeIds[
p]);
853 const vector& latticePosition =
856 unitCellLatticePosition.x(),
857 unitCellLatticePosition.y(),
858 unitCellLatticePosition.z()
860 + latticePositions[
p];
862 point globalPosition =
872 partOfLayerInBounds =
873 mesh_.bounds().contains
879 mesh_.cellTree().findInside
884 if (zone.found(cell))
898 unitCellLatticePosition =
901 - unitCellLatticePosition.y(),
902 unitCellLatticePosition.x(),
903 unitCellLatticePosition.z()
917 && !partOfLayerInBounds
921 <<
"A whole layer of unit cells was placed "
922 <<
"outside the bounds of the mesh, but no "
923 <<
"molecules have been placed in zone '"
925 <<
"'. This is likely to be because the zone "
928 <<
" in this case) and no lattice position "
929 <<
"fell inside them. "
930 <<
"Aborting filling this zone."
936 molsPlacedThisIteration =
937 this->size() - sizeBeforeIteration;
939 totalZoneMols += molsPlacedThisIteration;
949 void Foam::moleculeCloud::createMolecule
951 const point& position,
956 const vector& bulkVelocity
965 specialPosition = position;
970 const molecule::constantProperties& cP(constProps(
id));
972 vector v = equipartitionLinearVelocity(temperature, cP.mass());
980 if (!cP.pointMolecule())
982 pi = equipartitionAngularMomentum(temperature, cP);
1027 for (
const molecule& mol : *
this)
1029 n += constProps(mol.id()).nSites();
1038 Foam::moleculeCloud::moleculeCloud
1048 cellOccupancy_(mesh_.nCells()),
1049 il_(mesh_, pot_.pairPotentials().rCutMax(),
false),
1060 setSiteSizesAndPositions();
1062 removeHighEnergyOverlaps();
1068 Foam::moleculeCloud::moleculeCloud
1079 il_(mesh_, 0.0,
false),
1092 initialiseMolecules(mdInitialiseDict);
1118 buildCellOccupancy();
1130 calculatePairForce();
1132 calculateTetherForce();
1134 calculateExternalForce();
1140 const scalar targetTemperature,
1141 const scalar measuredTemperature
1144 scalar temperatureCorrectionFactor =
1145 sqrt(targetTemperature/
max(VSMALL, measuredTemperature));
1147 Info<<
"----------------------------------------" <<
nl
1148 <<
"Temperature equilibration" <<
nl
1149 <<
"Target temperature = "
1150 << targetTemperature <<
nl
1151 <<
"Measured temperature = "
1152 << measuredTemperature <<
nl
1153 <<
"Temperature correction factor = "
1154 << temperatureCorrectionFactor <<
nl
1155 <<
"----------------------------------------"
1160 mol.
v() *= temperatureCorrectionFactor;
1162 mol.
pi() *= temperatureCorrectionFactor;
1171 os << nSites() <<
nl <<
"moleculeCloud site positions in angstroms" <<
nl;
1181 os << pot_.siteIdList()[cP.
siteIds()[i]]
1182 <<
' ' << sP.
x()*1e10
1183 <<
' ' << sP.
y()*1e10
1184 <<
' ' << sP.
z()*1e10