moleculeCloud.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2017 OpenFOAM Foundation
9  Copyright (C) 2019 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "moleculeCloud.H"
30 #include "fvMesh.H"
31 #include "unitConversion.H"
32 
33 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34 
35 namespace Foam
36 {
37  defineTemplateTypeNameAndDebug(Cloud<molecule>, 0);
38 }
39 
40 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
41 
42 void Foam::moleculeCloud::buildConstProps()
43 {
44  Info<< nl << "Reading moleculeProperties dictionary." << endl;
45 
46  const List<word>& idList(pot_.idList());
47 
48  constPropList_.setSize(idList.size());
49 
50  const List<word>& siteIdList(pot_.siteIdList());
51 
52  IOdictionary moleculePropertiesDict
53  (
54  IOobject
55  (
56  "moleculeProperties",
57  mesh_.time().constant(),
58  mesh_,
61  false
62  )
63  );
64 
65  forAll(idList, i)
66  {
67  const word& id = idList[i];
68  const dictionary& molDict = moleculePropertiesDict.subDict(id);
69 
70  List<word> siteIdNames = molDict.lookup("siteIds");
71 
72  List<label> siteIds(siteIdNames.size());
73 
74  forAll(siteIdNames, sI)
75  {
76  const word& siteId = siteIdNames[sI];
77 
78  siteIds[sI] = siteIdList.find(siteId);
79 
80  if (siteIds[sI] == -1)
81  {
83  << siteId << " site not found."
84  << nl << abort(FatalError);
85  }
86  }
87 
88  molecule::constantProperties& constProp = constPropList_[i];
89 
90  constProp = molecule::constantProperties(molDict);
91 
92  constProp.siteIds() = siteIds;
93  }
94 }
95 
96 
97 void Foam::moleculeCloud::setSiteSizesAndPositions()
98 {
99  for (molecule& mol : *this)
100  {
101  const molecule::constantProperties& cP = constProps(mol.id());
102 
103  mol.setSiteSizes(cP.nSites());
104 
105  mol.setSitePositions(cP);
106  }
107 }
108 
109 
110 void Foam::moleculeCloud::buildCellOccupancy()
111 {
112  for (auto& list : cellOccupancy_)
113  {
114  list.clear();
115  }
116 
117  for (molecule& mol : *this)
118  {
119  cellOccupancy_[mol.cell()].append(&mol);
120  }
121 
122  for (auto& list : cellOccupancy_)
123  {
124  list.shrink();
125  }
126 }
127 
128 
129 void Foam::moleculeCloud::calculatePairForce()
130 {
131  PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
132 
133  // Start sending referred data
134  label startOfRequests = Pstream::nRequests();
135  il_.sendReferredData(cellOccupancy(), pBufs);
136 
137  molecule* molI = nullptr;
138  molecule* molJ = nullptr;
139 
140  {
141  // Real-Real interactions
142 
143  const labelListList& dil = il_.dil();
144 
145  forAll(dil, d)
146  {
147  forAll(cellOccupancy_[d],cellIMols)
148  {
149  molI = cellOccupancy_[d][cellIMols];
150 
151  forAll(dil[d], interactingCells)
152  {
153  List<molecule*> cellJ =
154  cellOccupancy_[dil[d][interactingCells]];
155 
156  forAll(cellJ, cellJMols)
157  {
158  molJ = cellJ[cellJMols];
159 
160  evaluatePair(*molI, *molJ);
161  }
162  }
163 
164  forAll(cellOccupancy_[d], cellIOtherMols)
165  {
166  molJ = cellOccupancy_[d][cellIOtherMols];
167 
168  if (molJ > molI)
169  {
170  evaluatePair(*molI, *molJ);
171  }
172  }
173  }
174  }
175  }
176 
177  // Receive referred data
178  il_.receiveReferredData(pBufs, startOfRequests);
179 
180  {
181  // Real-Referred interactions
182 
183  const labelListList& ril = il_.ril();
184 
185  List<IDLList<molecule>>& referredMols = il_.referredParticles();
186 
187  forAll(ril, r)
188  {
189  const List<label>& realCells = ril[r];
190 
191  IDLList<molecule>& refMols = referredMols[r];
192 
193  for (molecule& refMol : refMols)
194  {
195  forAll(realCells, rC)
196  {
197  List<molecule*> celli = cellOccupancy_[realCells[rC]];
198 
199  forAll(celli, cellIMols)
200  {
201  molI = celli[cellIMols];
202 
203  evaluatePair(*molI, refMol);
204  }
205  }
206  }
207  }
208  }
209 }
210 
211 
212 void Foam::moleculeCloud::calculateTetherForce()
213 {
214  const tetherPotentialList& tetherPot(pot_.tetherPotentials());
215 
216  for (molecule& mol : *this)
217  {
218  if (mol.tethered())
219  {
220  vector rIT = mol.position() - mol.specialPosition();
221 
222  label idI = mol.id();
223 
224  scalar massI = constProps(idI).mass();
225 
226  vector fIT = tetherPot.force(idI, rIT);
227 
228  mol.a() += fIT/massI;
229 
230  mol.potentialEnergy() += tetherPot.energy(idI, rIT);
231 
232  // What to do here?
233  // mol.rf() += rIT*fIT;
234  }
235  }
236 }
237 
238 
239 void Foam::moleculeCloud::calculateExternalForce()
240 {
241  for (molecule& mol : *this)
242  {
243  mol.a() += pot_.gravity();
244  }
245 }
246 
247 
248 void Foam::moleculeCloud::removeHighEnergyOverlaps()
249 {
250  Info<< nl << "Removing high energy overlaps, limit = "
251  << pot_.potentialEnergyLimit()
252  << nl << "Removal order:";
253 
254  forAll(pot_.removalOrder(), rO)
255  {
256  Info<< ' ' << pot_.idList()[pot_.removalOrder()[rO]];
257  }
258 
259  Info<< nl ;
260 
261  label initialSize = this->size();
262 
263  buildCellOccupancy();
264 
265  // Real-Real interaction
266 
267  molecule* molI = nullptr;
268  molecule* molJ = nullptr;
269 
270  {
271  DynamicList<molecule*> molsToDelete;
272 
273  const labelListList& dil(il_.dil());
274 
275  forAll(dil, d)
276  {
277  forAll(cellOccupancy_[d],cellIMols)
278  {
279  molI = cellOccupancy_[d][cellIMols];
280 
281  forAll(dil[d], interactingCells)
282  {
283  List<molecule*> cellJ =
284  cellOccupancy_[dil[d][interactingCells]];
285 
286  forAll(cellJ, cellJMols)
287  {
288  molJ = cellJ[cellJMols];
289 
290  if (evaluatePotentialLimit(*molI, *molJ))
291  {
292  const label idI = molI->id();
293  const label idJ = molJ->id();
294 
295  if
296  (
297  idI == idJ
298  || pot_.removalOrder().find(idJ)
299  < pot_.removalOrder().find(idI)
300  )
301  {
302  if (!molsToDelete.found(molJ))
303  {
304  molsToDelete.append(molJ);
305  }
306  }
307  else if (!molsToDelete.found(molI))
308  {
309  molsToDelete.append(molI);
310  }
311  }
312  }
313  }
314  }
315 
316  forAll(cellOccupancy_[d], cellIOtherMols)
317  {
318  molJ = cellOccupancy_[d][cellIOtherMols];
319 
320  if (molJ > molI)
321  {
322  if (evaluatePotentialLimit(*molI, *molJ))
323  {
324  const label idI = molI->id();
325  const label idJ = molJ->id();
326 
327  if
328  (
329  idI == idJ
330  || pot_.removalOrder().find(idJ)
331  < pot_.removalOrder().find(idI)
332  )
333  {
334  if (!molsToDelete.found(molJ))
335  {
336  molsToDelete.append(molJ);
337  }
338  }
339  else if (!molsToDelete.found(molI))
340  {
341  molsToDelete.append(molI);
342  }
343  }
344  }
345  }
346  }
347 
348  forAll(molsToDelete, mTD)
349  {
350  deleteParticle(*(molsToDelete[mTD]));
351  }
352  }
353 
354  buildCellOccupancy();
355 
356  PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
357 
358  // Start sending referred data
359  label startOfRequests = Pstream::nRequests();
360 
361  il_.sendReferredData(cellOccupancy(), pBufs);
362 
363  // Receive referred data
364  il_.receiveReferredData(pBufs, startOfRequests);
365 
366  // Real-Referred interaction
367 
368  {
369  DynamicList<molecule*> molsToDelete;
370 
371  const labelListList& ril(il_.ril());
372 
373  List<IDLList<molecule>>& referredMols = il_.referredParticles();
374 
375  forAll(ril, r)
376  {
377  IDLList<molecule>& refMols = referredMols[r];
378 
379  for (molecule& refMol : refMols)
380  {
381  molJ = &refMol;
382 
383  const List<label>& realCells = ril[r];
384 
385  forAll(realCells, rC)
386  {
387  label celli = realCells[rC];
388 
389  List<molecule*> cellIMols = cellOccupancy_[celli];
390 
391  forAll(cellIMols, cIM)
392  {
393  molI = cellIMols[cIM];
394 
395  if (evaluatePotentialLimit(*molI, *molJ))
396  {
397  const label idI = molI->id();
398  const label idJ = molJ->id();
399 
400  if
401  (
402  pot_.removalOrder().find(idI)
403  < pot_.removalOrder().find(idJ)
404  )
405  {
406  if (!molsToDelete.found(molI))
407  {
408  molsToDelete.append(molI);
409  }
410  }
411  else if
412  (
413  pot_.removalOrder().find(idI)
414  == pot_.removalOrder().find(idJ)
415  )
416  {
417  // Remove one of the molecules
418  // arbitrarily, assuring that a
419  // consistent decision is made for
420  // both real-referred pairs.
421 
422  if (molI->origId() > molJ->origId())
423  {
424  if (!molsToDelete.found(molI))
425  {
426  molsToDelete.append(molI);
427  }
428  }
429  }
430  }
431  }
432  }
433  }
434  }
435 
436  forAll(molsToDelete, mTD)
437  {
438  deleteParticle(*(molsToDelete[mTD]));
439  }
440  }
441 
442  buildCellOccupancy();
443 
444  // Start sending referred data
445  startOfRequests = Pstream::nRequests();
446 
447  il_.sendReferredData(cellOccupancy(), pBufs);
448 
449  // Receive referred data
450  il_.receiveReferredData(pBufs, startOfRequests);
451 
452  label molsRemoved = initialSize - this->size();
453 
454  if (Pstream::parRun())
455  {
456  reduce(molsRemoved, sumOp<label>());
457  }
458 
459  Info<< tab << molsRemoved << " molecules removed" << endl;
460 }
461 
462 
463 void Foam::moleculeCloud::initialiseMolecules
464 (
465  const IOdictionary& mdInitialiseDict
466 )
467 {
468  Info<< nl
469  << "Initialising molecules in each zone specified in mdInitialiseDict."
470  << endl;
471 
472  const cellZoneMesh& cellZones = mesh_.cellZones();
473 
474  if (!cellZones.size())
475  {
477  << "No cellZones found in the mesh."
478  << abort(FatalError);
479  }
480 
481  for (const cellZone& zone : cellZones)
482  {
483  if (zone.size())
484  {
485  if (!mdInitialiseDict.found(zone.name()))
486  {
487  Info<< "No specification subDictionary for zone "
488  << zone.name() << " found, skipping." << endl;
489  }
490  else
491  {
492  const dictionary& zoneDict =
493  mdInitialiseDict.subDict(zone.name());
494 
495  const scalar temperature
496  (
497  zoneDict.get<scalar>("temperature")
498  );
499 
500  const vector bulkVelocity
501  (
502  zoneDict.get<vector>("bulkVelocity")
503  );
504 
505  List<word> latticeIds
506  (
507  zoneDict.lookup("latticeIds")
508  );
509 
510  List<vector> latticePositions
511  (
512  zoneDict.lookup("latticePositions")
513  );
514 
515  if (latticeIds.size() != latticePositions.size())
516  {
518  << "latticeIds and latticePositions must be the same "
519  << " size." << nl
520  << abort(FatalError);
521  }
522 
523  diagTensor latticeCellShape
524  (
525  zoneDict.lookup("latticeCellShape")
526  );
527 
528  scalar latticeCellScale = 0.0;
529 
530  if (zoneDict.found("numberDensity"))
531  {
532  const scalar numberDensity
533  (
534  zoneDict.get<scalar>("numberDensity")
535  );
536 
537  if (numberDensity < VSMALL)
538  {
540  << "numberDensity too small, not filling zone "
541  << zone.name() << endl;
542 
543  continue;
544  }
545 
546  latticeCellScale = pow
547  (
548  latticeIds.size()/(det(latticeCellShape)*numberDensity),
549  (1.0/3.0)
550  );
551  }
552  else if (zoneDict.found("massDensity"))
553  {
554  scalar unitCellMass = 0.0;
555 
556  forAll(latticeIds, i)
557  {
558  label id = pot_.idList().find(latticeIds[i]);
559 
560  const molecule::constantProperties& cP(constProps(id));
561 
562  unitCellMass += cP.mass();
563  }
564 
565  const scalar massDensity
566  (
567  zoneDict.get<scalar>("massDensity")
568  );
569 
570  if (massDensity < VSMALL)
571  {
573  << "massDensity too small, not filling zone "
574  << zone.name() << endl;
575 
576  continue;
577  }
578 
579 
580  latticeCellScale = pow
581  (
582  unitCellMass/(det(latticeCellShape)*massDensity),
583  (1.0/3.0)
584  );
585  }
586  else
587  {
589  << "massDensity or numberDensity not specified " << nl
590  << abort(FatalError);
591  }
592 
593  latticeCellShape *= latticeCellScale;
594 
595  vector anchor(zoneDict.get<vector>("anchor"));
596 
597  bool tethered = false;
598 
599  if (zoneDict.found("tetherSiteIds"))
600  {
601  tethered = bool
602  (
603  List<word>(zoneDict.lookup("tetherSiteIds")).size()
604  );
605  }
606 
607  const vector orientationAngles
608  (
609  zoneDict.get<vector>("orientationAngles")
610  );
611 
612  const scalar phi(degToRad(orientationAngles.x()));
613  const scalar theta(degToRad(orientationAngles.y()));
614  const scalar psi(degToRad(orientationAngles.z()));
615 
616  const tensor R
617  (
618  cos(psi)*cos(phi) - cos(theta)*sin(phi)*sin(psi),
619  cos(psi)*sin(phi) + cos(theta)*cos(phi)*sin(psi),
620  sin(psi)*sin(theta),
621  - sin(psi)*cos(phi) - cos(theta)*sin(phi)*cos(psi),
622  - sin(psi)*sin(phi) + cos(theta)*cos(phi)*cos(psi),
623  cos(psi)*sin(theta),
624  sin(theta)*sin(phi),
625  - sin(theta)*cos(phi),
626  cos(theta)
627  );
628 
629  // Find the optimal anchor position. Finding the approximate
630  // mid-point of the zone of cells and snapping to the nearest
631  // lattice location.
632 
633  vector zoneMin = VGREAT*vector::one;
634 
635  vector zoneMax = -VGREAT*vector::one;
636 
637  forAll(zone, cell)
638  {
639  const point cellCentre = mesh_.cellCentres()[zone[cell]];
640 
641  if (cellCentre.x() > zoneMax.x())
642  {
643  zoneMax.x() = cellCentre.x();
644  }
645  if (cellCentre.x() < zoneMin.x())
646  {
647  zoneMin.x() = cellCentre.x();
648  }
649  if (cellCentre.y() > zoneMax.y())
650  {
651  zoneMax.y() = cellCentre.y();
652  }
653  if (cellCentre.y() < zoneMin.y())
654  {
655  zoneMin.y() = cellCentre.y();
656  }
657  if (cellCentre.z() > zoneMax.z())
658  {
659  zoneMax.z() = cellCentre.z();
660  }
661  if (cellCentre.z() < zoneMin.z())
662  {
663  zoneMin.z() = cellCentre.z();
664  }
665  }
666 
667  point zoneMid = 0.5*(zoneMin + zoneMax);
668 
669  point latticeMid = inv(latticeCellShape) & (R.T()
670  & (zoneMid - anchor));
671 
672  point latticeAnchor
673  (
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()))
677  );
678 
679  anchor += (R & (latticeCellShape & latticeAnchor));
680 
681  // Continue trying to place molecules as long as at
682  // least one molecule is placed in each iteration.
683  // The "|| totalZoneMols == 0" condition means that the
684  // algorithm will continue if the origin is outside the
685  // zone.
686 
687  label n = 0;
688 
689  label totalZoneMols = 0;
690 
691  label molsPlacedThisIteration = 0;
692 
693  while
694  (
695  molsPlacedThisIteration != 0
696  || totalZoneMols == 0
697  )
698  {
699  label sizeBeforeIteration = this->size();
700 
701  bool partOfLayerInBounds = false;
702 
703  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
704  // start of placement of molecules
705  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
706 
707  if (n == 0)
708  {
709  // Special treatment is required for the first position,
710  // i.e. iteration zero.
711 
712  labelVector unitCellLatticePosition(0,0,0);
713 
714  forAll(latticePositions, p)
715  {
716  label id = pot_.idList().find(latticeIds[p]);
717 
718  const vector& latticePosition =
719  vector
720  (
721  unitCellLatticePosition.x(),
722  unitCellLatticePosition.y(),
723  unitCellLatticePosition.z()
724  )
725  + latticePositions[p];
726 
727  point globalPosition =
728  anchor
729  + (R & (latticeCellShape & latticePosition));
730 
731  partOfLayerInBounds = mesh_.bounds().contains
732  (
733  globalPosition
734  );
735 
736  const label cell =
737  mesh_.cellTree().findInside(globalPosition);
738 
739  if (zone.found(cell))
740  {
741  createMolecule
742  (
743  globalPosition,
744  cell,
745  id,
746  tethered,
747  temperature,
748  bulkVelocity
749  );
750  }
751  }
752  }
753  else
754  {
755  // Place top and bottom caps.
756 
757  labelVector unitCellLatticePosition(0,0,0);
758 
759  for
760  (
761  unitCellLatticePosition.z() = -n;
762  unitCellLatticePosition.z() <= n;
763  unitCellLatticePosition.z() += 2*n
764  )
765  {
766  for
767  (
768  unitCellLatticePosition.y() = -n;
769  unitCellLatticePosition.y() <= n;
770  unitCellLatticePosition.y()++
771  )
772  {
773  for
774  (
775  unitCellLatticePosition.x() = -n;
776  unitCellLatticePosition.x() <= n;
777  unitCellLatticePosition.x()++
778  )
779  {
780  forAll(latticePositions, p)
781  {
782  const label id =
783  pot_.idList().find(latticeIds[p]);
784 
785  const vector& latticePosition =
786  vector
787  (
788  unitCellLatticePosition.x(),
789  unitCellLatticePosition.y(),
790  unitCellLatticePosition.z()
791  )
792  + latticePositions[p];
793 
794  point globalPosition =
795  anchor
796  + (
797  R
798  & (
799  latticeCellShape
800  & latticePosition
801  )
802  );
803 
804  partOfLayerInBounds =
805  mesh_.bounds().contains
806  (
807  globalPosition
808  );
809 
810  const label cell =
811  mesh_.cellTree().findInside
812  (
813  globalPosition
814  );
815 
816  if (zone.found(cell))
817  {
818  createMolecule
819  (
820  globalPosition,
821  cell,
822  id,
823  tethered,
824  temperature,
825  bulkVelocity
826  );
827  }
828  }
829  }
830  }
831  }
832 
833  for
834  (
835  unitCellLatticePosition.z() = -(n-1);
836  unitCellLatticePosition.z() <= (n-1);
837  unitCellLatticePosition.z()++
838  )
839  {
840  for (label iR = 0; iR <= 2*n -1; iR++)
841  {
842  unitCellLatticePosition.x() = n;
843 
844  unitCellLatticePosition.y() = -n + (iR + 1);
845 
846  for (label iK = 0; iK < 4; iK++)
847  {
848  forAll(latticePositions, p)
849  {
850  const label id =
851  pot_.idList().find(latticeIds[p]);
852 
853  const vector& latticePosition =
854  vector
855  (
856  unitCellLatticePosition.x(),
857  unitCellLatticePosition.y(),
858  unitCellLatticePosition.z()
859  )
860  + latticePositions[p];
861 
862  point globalPosition =
863  anchor
864  + (
865  R
866  & (
867  latticeCellShape
868  & latticePosition
869  )
870  );
871 
872  partOfLayerInBounds =
873  mesh_.bounds().contains
874  (
875  globalPosition
876  );
877 
878  const label cell =
879  mesh_.cellTree().findInside
880  (
881  globalPosition
882  );
883 
884  if (zone.found(cell))
885  {
886  createMolecule
887  (
888  globalPosition,
889  cell,
890  id,
891  tethered,
892  temperature,
893  bulkVelocity
894  );
895  }
896  }
897 
898  unitCellLatticePosition =
900  (
901  - unitCellLatticePosition.y(),
902  unitCellLatticePosition.x(),
903  unitCellLatticePosition.z()
904  );
905  }
906  }
907  }
908  }
909 
910  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
911  // end of placement of molecules
912  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
913 
914  if
915  (
916  totalZoneMols == 0
917  && !partOfLayerInBounds
918  )
919  {
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 '"
924  << zone.name()
925  << "'. This is likely to be because the zone "
926  << "has few cells ("
927  << zone.size()
928  << " in this case) and no lattice position "
929  << "fell inside them. "
930  << "Aborting filling this zone."
931  << endl;
932 
933  break;
934  }
935 
936  molsPlacedThisIteration =
937  this->size() - sizeBeforeIteration;
938 
939  totalZoneMols += molsPlacedThisIteration;
940 
941  n++;
942  }
943  }
944  }
945  }
946 }
947 
948 
949 void Foam::moleculeCloud::createMolecule
950 (
951  const point& position,
952  label cell,
953  label id,
954  bool tethered,
955  scalar temperature,
956  const vector& bulkVelocity
957 )
958 {
959  point specialPosition(Zero);
960 
961  label special = 0;
962 
963  if (tethered)
964  {
965  specialPosition = position;
966 
967  special = molecule::SPECIAL_TETHERED;
968  }
969 
970  const molecule::constantProperties& cP(constProps(id));
971 
972  vector v = equipartitionLinearVelocity(temperature, cP.mass());
973 
974  v += bulkVelocity;
975 
976  vector pi = Zero;
977 
978  tensor Q = I;
979 
980  if (!cP.pointMolecule())
981  {
982  pi = equipartitionAngularMomentum(temperature, cP);
983 
984  const scalar phi(rndGen_.sample01<scalar>()*mathematical::twoPi);
985  const scalar theta(rndGen_.sample01<scalar>()*mathematical::twoPi);
986  const scalar psi(rndGen_.sample01<scalar>()*mathematical::twoPi);
987 
988  Q = tensor
989  (
990  cos(psi)*cos(phi) - cos(theta)*sin(phi)*sin(psi),
991  cos(psi)*sin(phi) + cos(theta)*cos(phi)*sin(psi),
992  sin(psi)*sin(theta),
993  - sin(psi)*cos(phi) - cos(theta)*sin(phi)*cos(psi),
994  - sin(psi)*sin(phi) + cos(theta)*cos(phi)*cos(psi),
995  cos(psi)*sin(theta),
996  sin(theta)*sin(phi),
997  - sin(theta)*cos(phi),
998  cos(theta)
999  );
1000  }
1001 
1002  addParticle
1003  (
1004  new molecule
1005  (
1006  mesh_,
1007  position,
1008  cell,
1009  Q,
1010  v,
1011  Zero,
1012  pi,
1013  Zero,
1014  specialPosition,
1015  constProps(id),
1016  special,
1017  id
1018  )
1019  );
1020 }
1021 
1022 
1023 Foam::label Foam::moleculeCloud::nSites() const
1024 {
1025  label n = 0;
1026 
1027  for (const molecule& mol : *this)
1028  {
1029  n += constProps(mol.id()).nSites();
1030  }
1031 
1032  return n;
1033 }
1034 
1035 
1036 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1037 
1038 Foam::moleculeCloud::moleculeCloud
1040  const polyMesh& mesh,
1041  const potential& pot,
1042  bool readFields
1043 )
1044 :
1045  Cloud<molecule>(mesh, "moleculeCloud", false),
1046  mesh_(mesh),
1047  pot_(pot),
1048  cellOccupancy_(mesh_.nCells()),
1049  il_(mesh_, pot_.pairPotentials().rCutMax(), false),
1050  constPropList_(),
1051  rndGen_(clock::getTime())
1052 {
1053  if (readFields)
1054  {
1055  molecule::readFields(*this);
1056  }
1057 
1058  buildConstProps();
1059 
1060  setSiteSizesAndPositions();
1061 
1062  removeHighEnergyOverlaps();
1063 
1064  calculateForce();
1065 }
1066 
1067 
1068 Foam::moleculeCloud::moleculeCloud
1070  const polyMesh& mesh,
1071  const potential& pot,
1072  const IOdictionary& mdInitialiseDict,
1073  bool readFields
1074 )
1075 :
1076  Cloud<molecule>(mesh, "moleculeCloud", false),
1077  mesh_(mesh),
1078  pot_(pot),
1079  il_(mesh_, 0.0, false),
1080  constPropList_(),
1081  rndGen_(clock::getTime())
1082 {
1083  if (readFields)
1084  {
1085  molecule::readFields(*this);
1086  }
1087 
1088  clear();
1089 
1090  buildConstProps();
1091 
1092  initialiseMolecules(mdInitialiseDict);
1093 }
1094 
1095 
1096 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1097 
1099 {
1100  molecule::trackingData td0(*this, 0);
1101  Cloud<molecule>::move(*this, td0, mesh_.time().deltaTValue());
1102 
1103  molecule::trackingData td1(*this, 1);
1104  Cloud<molecule>::move(*this, td1, mesh_.time().deltaTValue());
1105 
1106  molecule::trackingData td2(*this, 2);
1107  Cloud<molecule>::move(*this, td2, mesh_.time().deltaTValue());
1108 
1109  calculateForce();
1110 
1111  molecule::trackingData td3(*this, 3);
1112  Cloud<molecule>::move(*this, td3, mesh_.time().deltaTValue());
1113 }
1114 
1115 
1117 {
1118  buildCellOccupancy();
1119 
1120  // Set accumulated quantities to zero
1121  for (molecule& mol : *this)
1122  {
1123  mol.siteForces() = Zero;
1124 
1125  mol.potentialEnergy() = 0.0;
1126 
1127  mol.rf() = Zero;
1128  }
1129 
1130  calculatePairForce();
1131 
1132  calculateTetherForce();
1133 
1134  calculateExternalForce();
1135 }
1136 
1137 
1140  const scalar targetTemperature,
1141  const scalar measuredTemperature
1142 )
1143 {
1144  scalar temperatureCorrectionFactor =
1145  sqrt(targetTemperature/max(VSMALL, measuredTemperature));
1146 
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  << "----------------------------------------"
1156  << endl;
1157 
1158  for (molecule& mol : *this)
1159  {
1160  mol.v() *= temperatureCorrectionFactor;
1161 
1162  mol.pi() *= temperatureCorrectionFactor;
1163  }
1164 }
1165 
1166 
1167 void Foam::moleculeCloud::writeXYZ(const fileName& fName) const
1168 {
1169  OFstream os(fName);
1170 
1171  os << nSites() << nl << "moleculeCloud site positions in angstroms" << nl;
1172 
1173  for (const molecule& mol : *this)
1174  {
1175  const molecule::constantProperties& cP = constProps(mol.id());
1176 
1177  forAll(mol.sitePositions(), i)
1178  {
1179  const point& sP = mol.sitePositions()[i];
1180 
1181  os << pot_.siteIdList()[cP.siteIds()[i]]
1182  << ' ' << sP.x()*1e10
1183  << ' ' << sP.y()*1e10
1184  << ' ' << sP.z()*1e10
1185  << nl;
1186  }
1187  }
1188 }
1189 
1190 
1191 // ************************************************************************* //
Foam::IOobject::NO_WRITE
Definition: IOobject.H:130
Foam::molecule::constantProperties::siteIds
const List< label > & siteIds() const
Definition: moleculeI.H:394
Foam::IOdictionary
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:54
Foam::Vector::x
const Cmpt & x() const
Access to the vector x component.
Definition: VectorI.H:78
p
volScalarField & p
Definition: createFieldRefs.H:8
Foam::UPstream::commsTypes::nonBlocking
Foam::VectorSpace< Vector< scalar >, scalar, 3 >::one
static const Vector< scalar > one
Definition: VectorSpace.H:116
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
Foam::Zero
static constexpr const zero Zero
Global zero.
Definition: zero.H:128
Foam::sin
dimensionedScalar sin(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:264
Foam::tensor
Tensor< scalar > tensor
Tensor of scalars.
Definition: tensor.H:53
Foam::objectRegistry::time
const Time & time() const
Return time.
Definition: objectRegistry.H:186
Foam::UPstream::parRun
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:414
unitConversion.H
Unit conversion functions.
Foam::potential::siteIdList
const List< word > & siteIdList() const
Definition: potentialI.H:42
Foam::molecule::id
label id() const
Definition: moleculeI.H:640
Foam::defineTemplateTypeNameAndDebug
defineTemplateTypeNameAndDebug(faScalarMatrix, 0)
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:337
Foam::cellZoneMesh
ZoneMesh< cellZone, polyMesh > cellZoneMesh
A ZoneMesh with the type cellZone.
Definition: cellZoneMeshFwd.H:44
Foam::sign
dimensionedScalar sign(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:166
Foam::Vector::z
const Cmpt & z() const
Access to the vector z component.
Definition: VectorI.H:90
Foam::polyMesh
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:77
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:290
Foam::labelVector
Vector< label > labelVector
Vector of labels.
Definition: labelVector.H:51
n
label n
Definition: TABSMDCalcMethod2.H:31
Foam::reduce
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
Definition: PstreamReduceOps.H:51
moleculeCloud.H
R
#define R(A, B, C, D, E, F, K, M)
Foam::diagTensor
DiagTensor< scalar > diagTensor
A scalar version of the templated DiagTensor.
Definition: diagTensor.H:50
Foam::label
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:62
Foam::molecule
Foam::molecule.
Definition: molecule.H:67
cellOccupancy
const List< DynamicList< molecule * > > & cellOccupancy
Definition: calculateMDFields.H:1
Foam::molecule::sitePositions
const List< vector > & sitePositions() const
Definition: moleculeI.H:580
Foam::inv
dimensionedSphericalTensor inv(const dimensionedSphericalTensor &dt)
Definition: dimensionedSphericalTensor.C:73
Foam::Info
messageStream Info
Information stream (uses stdout - output is on the master only)
Foam::molecule::rf
const tensor & rf() const
Definition: moleculeI.H:616
Foam::clock::getTime
static time_t getTime()
Get the current clock time in seconds.
Definition: clock.C:46
Foam::molecule::siteForces
const List< vector > & siteForces() const
Definition: moleculeI.H:568
Foam::molecule::trackingData
Class used to pass tracking data to the trackToFace function.
Definition: molecule.H:167
Foam::moleculeCloud::evolve
void evolve()
Evolve the molecules (move, calculate forces, control state etc)
Definition: moleculeCloud.C:1098
phi
surfaceScalarField & phi
Definition: setRegionFluidFields.H:8
Foam::pow
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
Definition: dimensionedScalar.C:75
Foam::max
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
Foam::constant::mathematical::twoPi
constexpr scalar twoPi(2 *M_PI)
Foam::moleculeCloud::writeXYZ
void writeXYZ(const fileName &fName) const
Write molecule sites in XYZ format.
Definition: moleculeCloud.C:1167
Foam::Cloud::move
void move(TrackCloudType &cloud, typename ParticleType::trackingData &td, const scalar trackTime)
Move the particles.
Definition: Cloud.C:146
Foam::FatalError
error FatalError
Foam::potential
Definition: potential.H:55
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
fvMesh.H
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:137
Foam::vector
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:51
Foam::degToRad
constexpr scalar degToRad(const scalar deg) noexcept
Conversion from degrees to radians.
Definition: unitConversion.H:48
Foam::OFstream
Output to file stream, using an OSstream.
Definition: OFstream.H:99
Foam::molecule::potentialEnergy
scalar potentialEnergy() const
Definition: moleculeI.H:604
Foam::readFields
void readFields(const typename GeoFieldType::Mesh &mesh, const IOobjectList &objects, const wordHashSet &selectedFields, LIFOStack< regIOobject * > &storedObjects)
Read the selected GeometricFields of the templated type.
Definition: ReadFieldsTemplates.C:312
Foam::labelListList
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
Foam::molecule::readFields
static void readFields(Cloud< molecule > &mC)
Definition: moleculeIO.C:111
Foam::Vector::y
const Cmpt & y() const
Access to the vector y component.
Definition: VectorI.H:84
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:355
Foam::molecule::v
const vector & v() const
Definition: moleculeI.H:520
Foam::UPstream::nRequests
static label nRequests()
Get number of outstanding requests.
Definition: UPstream.C:152
Foam::tab
constexpr char tab
Definition: Ostream.H:371
Foam::constant::mathematical::pi
constexpr scalar pi(M_PI)
clear
patchWriters clear()
Foam::nl
constexpr char nl
Definition: Ostream.H:372
Foam::Vector< scalar >
Foam::moleculeCloud::applyConstraintsAndThermostats
void applyConstraintsAndThermostats(const scalar targetTemperature, const scalar measuredTemperature)
Definition: moleculeCloud.C:1139
Foam::sqrt
dimensionedScalar sqrt(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:144
Foam::Cloud< molecule >
bool
bool
Definition: EEqn.H:20
Foam::IOobject::MUST_READ_IF_MODIFIED
Definition: IOobject.H:121
Foam::molecule::constantProperties
Class to hold molecule constant properties.
Definition: molecule.H:91
constProp
word constProp(initialConditions.get< word >("constantProperty"))
Foam::moleculeCloud::calculateForce
void calculateForce()
Definition: moleculeCloud.C:1116
Foam::molecule::SPECIAL_TETHERED
Definition: molecule.H:83
Foam::det
dimensionedScalar det(const dimensionedSphericalTensor &dt)
Definition: dimensionedSphericalTensor.C:62
Foam::potential::idList
const List< word > & idList() const
Definition: potentialI.H:36
Foam::point
vector point
Point is a vector.
Definition: point.H:43
Foam::TimePaths::constant
const word & constant() const
Return constant name.
Definition: TimePathsI.H:88
psi
const volScalarField & psi
Definition: createFieldRefs.H:1
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:294
Foam::I
static const Identity< scalar > I
Definition: Identity.H:95
Foam::cos
dimensionedScalar cos(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:265
Foam::molecule::pi
const vector & pi() const
Definition: moleculeI.H:544