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