OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
Thermo.cpp
1/*
2 * Copyright (c) 2004-present, The University of Notre Dame. All rights
3 * reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
32 * research, please cite the following paper when you publish your work:
33 *
34 * [1] Drisko et al., J. Open Source Softw. 9, 7004 (2024).
35 *
36 * Good starting points for code and simulation methodology are:
37 *
38 * [2] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
39 * [3] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
40 * [4] Sun, Lin & Gezelter, J. Chem. Phys. 128, 234107 (2008).
41 * [5] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011).
42 * [6] Kuang & Gezelter, Mol. Phys., 110, 691-701 (2012).
43 * [7] Lamichhane, Gezelter & Newman, J. Chem. Phys. 141, 134109 (2014).
44 * [8] Bhattarai, Newman & Gezelter, Phys. Rev. B 99, 094106 (2019).
45 * [9] Drisko & Gezelter, J. Chem. Theory Comput. 20, 4986-4997 (2024).
46 */
47
48#include "brains/Thermo.hpp"
49
50#include <cmath>
51#include <iostream>
52
53#ifdef IS_MPI
54#include <mpi.h>
55#endif
56
58#include "types/FixedChargeAdapter.hpp"
59#include "types/FluctuatingChargeAdapter.hpp"
60#include "types/MultipoleAdapter.hpp"
61#include "utils/Constants.hpp"
62#include "utils/simError.h"
63#ifdef HAVE_QHULL
64#include "math/AlphaHull.hpp"
65#include "math/ConvexHull.hpp"
66#endif
67
68using namespace std;
69namespace OpenMD {
70
71 Thermo::Thermo(SimInfo* info) : info_(info) {
72 velField_ = std::make_unique<VelocityField>(info);
73 bool usePeculiarVelocities_ = velField_->isActive();
74 }
75
76 RealType Thermo::getTranslationalKinetic() {
77 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
78
79 if (!snap->hasTranslationalKineticEnergy) {
80 SimInfo::MoleculeIterator miter;
81 vector<StuntDouble*>::iterator iiter;
82 Molecule* mol;
83 StuntDouble* sd;
84 Vector3d vel;
85 Vector3d ambient;
86 RealType mass;
87 RealType kinetic(0.0);
88
89 for (mol = info_->beginMolecule(miter); mol != NULL;
90 mol = info_->nextMolecule(miter)) {
91 for (sd = mol->beginIntegrableObject(iiter); sd != NULL;
92 sd = mol->nextIntegrableObject(iiter)) {
93 mass = sd->getMass();
94 vel = sd->getVel();
95
96 if (usePeculiarVelocities_) {
97 ambient = velField_->getVelocity(sd->getPos());
98 vel -= ambient;
99 }
100
101 kinetic +=
102 mass * (vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2]);
103 }
104 }
105
106#ifdef IS_MPI
107 MPI_Allreduce(MPI_IN_PLACE, &kinetic, 1, MPI_REALTYPE, MPI_SUM,
108 MPI_COMM_WORLD);
109#endif
110
111 kinetic = kinetic * 0.5 / Constants::energyConvert;
112
113 snap->setTranslationalKineticEnergy(kinetic);
114 }
115 return snap->getTranslationalKineticEnergy();
116 }
117
118 RealType Thermo::getRotationalKinetic() {
119 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
120
121 if (!snap->hasRotationalKineticEnergy) {
122 SimInfo::MoleculeIterator miter;
123 vector<StuntDouble*>::iterator iiter;
124 Molecule* mol;
125 StuntDouble* sd;
126 Vector3d vorticity(0.0);
127 Vector3d J, omegaB, omegaL;
128 Mat3x3d I, A, Atrans;
129 int i, j, k;
130 RealType kinetic(0.0);
131
132 if (usePeculiarVelocities_) {
133 vorticity = velField_->getVorticity();
134 }
135
136 for (mol = info_->beginMolecule(miter); mol != NULL;
137 mol = info_->nextMolecule(miter)) {
138 for (sd = mol->beginIntegrableObject(iiter); sd != NULL;
139 sd = mol->nextIntegrableObject(iiter)) {
140 if (sd->isDirectional()) {
141 J = sd->getJ();
142 I = sd->getI();
143 A = sd->getA();
144 Atrans = A.transpose();
145
146 if (sd->isLinear()) {
147 i = sd->linearAxis();
148 j = (i + 1) % 3;
149 k = (i + 2) % 3;
150 omegaB[i] = 0.0;
151 omegaB[j] = J[j] / I(j,j);
152 omegaB[k] = J[k] / I(k,k);
153 } else {
154 omegaB[0] = J[0] / I(0,0);
155 omegaB[1] = J[1] / I(1,1);
156 omegaB[2] = J[2] / I(2,2);
157 }
158 omegaL = Atrans * omegaB - vorticity;
159 omegaB = A * omegaL;
160
161 kinetic += dot(omegaB, I * omegaB);
162
163 }
164 }
165 }
166
167#ifdef IS_MPI
168 MPI_Allreduce(MPI_IN_PLACE, &kinetic, 1, MPI_REALTYPE, MPI_SUM,
169 MPI_COMM_WORLD);
170#endif
171
172 kinetic = kinetic * 0.5 / Constants::energyConvert ;
173
174 snap->setRotationalKineticEnergy(kinetic);
175 }
176 return snap->getRotationalKineticEnergy();
177 }
178
179 RealType Thermo::getKinetic() {
180 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
181
182 if (!snap->hasKineticEnergy) {
183 RealType ke = getTranslationalKinetic() + getRotationalKinetic() +
184 getElectronicKinetic();
185
186 snap->setKineticEnergy(ke);
187 }
188 return snap->getKineticEnergy();
189 }
190
191 RealType Thermo::getPotential() {
192 // ForceManager computes the potential and stores it in the
193 // Snapshot. All we have to do is report it.
194
195 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
196 return snap->getPotentialEnergy();
197 }
198
199 potVec Thermo::getSelectionPotentials() {
200 // ForceManager computes the selection potentials and stores them
201 // in the Snapshot. All we have to do is report them.
202
203 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
204 return snap->getSelectionPotentials();
205 }
206
207 RealType Thermo::getTotalEnergy() {
208 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
209
210 if (!snap->hasTotalEnergy) {
211 snap->setTotalEnergy(this->getKinetic() + this->getPotential());
212 }
213
214 return snap->getTotalEnergy();
215 }
216
217 /*
218 * Returns only the nuclear portion of the temperature - see
219 * getElectronicTemperature for the electronic portion */
220 RealType Thermo::getTemperature() {
221 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
222
223 if (!snap->hasTemperature) {
224 RealType nuclearKE =
225 this->getTranslationalKinetic() + this->getRotationalKinetic();
226
227 RealType temperature {};
228
229 // With no degrees of freedom, T is not well defined, but we'll
230 // set to zero.
231
232 if (info_->getNdf() > 0)
233 temperature = (2.0 * nuclearKE) / (info_->getNdf() * Constants::kb);
234 else
235 temperature = 0.0;
236
237 snap->setTemperature(temperature);
238 }
239
240 return snap->getTemperature();
241 }
242
243 RealType Thermo::getElectronicKinetic() {
244 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
245
246 if (!snap->hasElectronicKineticEnergy) {
247 SimInfo::MoleculeIterator miter;
248 vector<Atom*>::iterator iiter;
249 Molecule* mol;
250 Atom* atom;
251 RealType cvel;
252 RealType cmass;
253 RealType kinetic(0.0);
254
255 for (mol = info_->beginMolecule(miter); mol != NULL;
256 mol = info_->nextMolecule(miter)) {
257 for (atom = mol->beginFluctuatingCharge(iiter); atom != NULL;
258 atom = mol->nextFluctuatingCharge(iiter)) {
259 cmass = atom->getChargeMass();
260 cvel = atom->getFlucQVel();
261 kinetic += cmass * cvel * cvel;
262 }
263 }
264
265#ifdef IS_MPI
266 MPI_Allreduce(MPI_IN_PLACE, &kinetic, 1, MPI_REALTYPE, MPI_SUM,
267 MPI_COMM_WORLD);
268#endif
269
270 kinetic *= 0.5;
271 snap->setElectronicKineticEnergy(kinetic);
272 }
273
274 return snap->getElectronicKineticEnergy();
275 }
276
277 RealType Thermo::getElectronicTemperature() {
278 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
279
280 if (!snap->hasElectronicTemperature) {
281 RealType eTemp = (2.0 * this->getElectronicKinetic()) /
282 (info_->getNFluctuatingCharges() * Constants::kb);
283
284 snap->setElectronicTemperature(eTemp);
285 }
286
287 return snap->getElectronicTemperature();
288 }
289
290 RealType Thermo::getNetCharge() {
291 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
292
293 if (!snap->hasNetCharge) {
294 SimInfo::MoleculeIterator miter;
295 vector<Atom*>::iterator aiter;
296 Molecule* mol;
297 Atom* atom;
298 RealType charge;
299 RealType netCharge(0.0);
300
301 for (mol = info_->beginMolecule(miter); mol != NULL;
302 mol = info_->nextMolecule(miter)) {
303 for (atom = mol->beginAtom(aiter); atom != NULL;
304 atom = mol->nextAtom(aiter)) {
305 charge = 0.0;
306
307 FixedChargeAdapter fca = FixedChargeAdapter(atom->getAtomType());
308 if (fca.isFixedCharge()) { charge = fca.getCharge(); }
309
310 FluctuatingChargeAdapter fqa =
311 FluctuatingChargeAdapter(atom->getAtomType());
312 if (fqa.isFluctuatingCharge()) { charge += atom->getFlucQPos(); }
313
314 netCharge += charge;
315 }
316 }
317
318#ifdef IS_MPI
319 MPI_Allreduce(MPI_IN_PLACE, &netCharge, 1, MPI_REALTYPE, MPI_SUM,
320 MPI_COMM_WORLD);
321#endif
322
323 snap->setNetCharge(netCharge);
324 }
325
326 return snap->getNetCharge();
327 }
328
329 RealType Thermo::getChargeMomentum() {
330 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
331
332 if (!snap->hasChargeMomentum) {
333 SimInfo::MoleculeIterator miter;
334 vector<Atom*>::iterator iiter;
335 Molecule* mol;
336 Atom* atom;
337 RealType cvel;
338 RealType cmass;
339 RealType momentum(0.0);
340
341 for (mol = info_->beginMolecule(miter); mol != NULL;
342 mol = info_->nextMolecule(miter)) {
343 for (atom = mol->beginFluctuatingCharge(iiter); atom != NULL;
344 atom = mol->nextFluctuatingCharge(iiter)) {
345 cmass = atom->getChargeMass();
346 cvel = atom->getFlucQVel();
347
348 momentum += cmass * cvel;
349 }
350 }
351
352#ifdef IS_MPI
353 MPI_Allreduce(MPI_IN_PLACE, &momentum, 1, MPI_REALTYPE, MPI_SUM,
354 MPI_COMM_WORLD);
355#endif
356
357 snap->setChargeMomentum(momentum);
358 }
359
360 return snap->getChargeMomentum();
361 }
362
363 std::vector<Vector3d> Thermo::getCurrentDensity() {
364 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
365 AtomTypeSet simTypes = info_->getSimulatedAtomTypes();
366
367 SimInfo::MoleculeIterator miter;
368 std::vector<Atom*>::iterator iiter;
369 std::vector<RigidBody*>::iterator ri;
370 Molecule* mol;
371 RigidBody* rb;
372 Atom* atom;
373 AtomType* atype;
374 AtomTypeSet::iterator at;
375 Vector3d Jc(0.0);
376 Vector3d ambient;
377 std::vector<Vector3d> typeJc(simTypes.size(), V3Zero);
378
379 for (mol = info_->beginMolecule(miter); mol != NULL;
380 mol = info_->nextMolecule(miter)) {
381 // change the velocities of atoms which belong to the rigidbodies
382 for (rb = mol->beginRigidBody(ri); rb != NULL;
383 rb = mol->nextRigidBody(ri)) {
384 rb->updateAtomVel();
385 }
386
387 for (atom = mol->beginAtom(iiter); atom != NULL;
388 atom = mol->nextAtom(iiter)) {
389 Vector3d v = atom->getVel();
390 if (usePeculiarVelocities_) {
391 ambient = velField_->getVelocity(atom->getPos());
392 v -= ambient;
393 }
394
395 RealType q = 0.0;
396 int typeIndex(-1);
397
398 atype = atom->getAtomType();
399 FixedChargeAdapter fca = FixedChargeAdapter(atype);
400 if (fca.isFixedCharge()) q = fca.getCharge();
401 FluctuatingChargeAdapter fqa = FluctuatingChargeAdapter(atype);
402 if (fqa.isFluctuatingCharge()) q += atom->getFlucQPos();
403
404 typeIndex = -1;
405 at = std::find(simTypes.begin(), simTypes.end(), atype);
406 if (at != simTypes.end()) {
407 typeIndex = std::distance(simTypes.begin(), at);
408 }
409
410 if (typeIndex != -1) { typeJc[typeIndex] += q * v; }
411 Jc += q * v;
412 }
413 }
414
415#ifdef IS_MPI
416 MPI_Allreduce(MPI_IN_PLACE, &Jc[0], 3, MPI_REALTYPE, MPI_SUM,
417 MPI_COMM_WORLD);
418 for (unsigned int j = 0; j < simTypes.size(); j++) {
419 MPI_Allreduce(MPI_IN_PLACE, &typeJc[j][0], 3, MPI_REALTYPE, MPI_SUM,
420 MPI_COMM_WORLD);
421 }
422#endif
423
424 RealType vol = snap->getVolume();
425
426 Jc /= (vol * Constants::currentDensityConvert);
427 for (unsigned int j = 0; j < simTypes.size(); j++) {
428 typeJc[j] /= (vol * Constants::currentDensityConvert);
429 }
430
431 std::vector<Vector3d> result;
432 result.clear();
433
434 result.push_back(Jc);
435 for (unsigned int j = 0; j < simTypes.size(); j++)
436 result.push_back(typeJc[j]);
437
438 return result;
439 }
440
441 RealType Thermo::getVolume() {
442 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
443 return snap->getVolume();
444 }
445
446 RealType Thermo::getPressure() {
447 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
448
449 if (!snap->hasPressure) {
450 // Relies on the calculation of the full molecular pressure tensor
451
452 Mat3x3d tensor;
453 RealType pressure;
454
455 tensor = getPressureTensor();
456
457 pressure = Constants::pressureConvert *
458 (tensor(0, 0) + tensor(1, 1) + tensor(2, 2)) / 3.0;
459
460 snap->setPressure(pressure);
461 }
462
463 return snap->getPressure();
464 }
465
466 RealType Thermo::getPressure(Snapshot* snap) {
467 if (!snap->hasPressure) {
468 // Relies on the calculation of the full molecular pressure tensor
469 Mat3x3d tensor;
470 RealType pressure;
471
472 tensor = getPressureTensor(snap);
473
474 pressure = Constants::pressureConvert *
475 (tensor(0, 0) + tensor(1, 1) + tensor(2, 2)) / 3.0;
476
477 snap->setPressure(pressure);
478 }
479
480 return snap->getPressure();
481 }
482
484 // returns pressure tensor in units amu*fs^-2*Ang^-1
485 // routine derived via viral theorem description in:
486 // Paci, E. and Marchi, M. J.Phys.Chem. 1996, 100, 4314-4322
487 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
488
489 if (!snap->hasPressureTensor) {
490 Mat3x3d pressureTensor;
491 Mat3x3d p_tens(0.0);
492 RealType mass;
493 Vector3d vcom;
494 Vector3d ambient;
495
496 SimInfo::MoleculeIterator i;
497 vector<StuntDouble*>::iterator j;
498 Molecule* mol;
499 StuntDouble* sd;
500 for (mol = info_->beginMolecule(i); mol != NULL;
501 mol = info_->nextMolecule(i)) {
502 for (sd = mol->beginIntegrableObject(j); sd != NULL;
503 sd = mol->nextIntegrableObject(j)) {
504 mass = sd->getMass();
505 vcom = sd->getVel();
506 if (usePeculiarVelocities_) {
507 ambient = velField_->getVelocity(sd->getPos());
508 vcom -= ambient;
509 }
510 p_tens += mass * outProduct(vcom, vcom);
511 }
512 }
513
514#ifdef IS_MPI
515 MPI_Allreduce(MPI_IN_PLACE, p_tens.getArrayPointer(), 9, MPI_REALTYPE,
516 MPI_SUM, MPI_COMM_WORLD);
517#endif
518
519 RealType volume = this->getVolume();
520 Mat3x3d virialTensor = snap->getVirialTensor();
521
522 pressureTensor =
523 (p_tens + Constants::energyConvert * virialTensor) / volume;
524
525 snap->setPressureTensor(pressureTensor);
526 }
527 return snap->getPressureTensor();
528 }
529
531 // returns pressure tensor in units amu*fs^-2*Ang^-1
532 // routine derived via viral theorem description in:
533 // Paci, E. and Marchi, M. J.Phys.Chem. 1996, 100, 4314-4322
534 if (!snap->hasPressureTensor) {
535 Mat3x3d pressureTensor;
536 Mat3x3d p_tens(0.0);
537 RealType mass;
538 Vector3d vcom;
539 Vector3d ambient;
540
541 SimInfo::MoleculeIterator i;
542 vector<StuntDouble*>::iterator j;
543 Molecule* mol;
544 StuntDouble* sd;
545 for (mol = info_->beginMolecule(i); mol != NULL;
546 mol = info_->nextMolecule(i)) {
547 for (sd = mol->beginIntegrableObject(j); sd != NULL;
548 sd = mol->nextIntegrableObject(j)) {
549 mass = sd->getMass();
550 vcom = sd->getVel(snap);
551 if (usePeculiarVelocities_) {
552 ambient = velField_->getVelocity(sd->getPos());
553 vcom -= ambient;
554 }
555 p_tens += mass * outProduct(vcom, vcom);
556 }
557 }
558
559#ifdef IS_MPI
560 MPI_Allreduce(MPI_IN_PLACE, p_tens.getArrayPointer(), 9, MPI_REALTYPE,
561 MPI_SUM, MPI_COMM_WORLD);
562#endif
563
564 RealType volume = this->getVolume();
565 Mat3x3d virialTensor = snap->getVirialTensor();
566
567 pressureTensor =
568 (p_tens + Constants::energyConvert * virialTensor) / volume;
569
570 snap->setPressureTensor(pressureTensor);
571 }
572 return snap->getPressureTensor();
573 }
574
576 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
577
578 if (!snap->hasSystemDipole) {
579 SimInfo::MoleculeIterator miter;
580 vector<Atom*>::iterator aiter;
581 Molecule* mol;
582 Atom* atom;
583 RealType charge;
584 Vector3d ri(0.0);
585 Vector3d dipoleVector(0.0);
586 Vector3d nPos(0.0);
587 Vector3d pPos(0.0);
588 RealType nChg(0.0);
589 RealType pChg(0.0);
590 int nCount = 0;
591 int pCount = 0;
592
593 RealType chargeToC = 1.60217733e-19;
594 RealType angstromToM = 1.0e-10;
595 RealType debyeToCm = 3.33564095198e-30;
596
597 for (mol = info_->beginMolecule(miter); mol != NULL;
598 mol = info_->nextMolecule(miter)) {
599 for (atom = mol->beginAtom(aiter); atom != NULL;
600 atom = mol->nextAtom(aiter)) {
601 charge = 0.0;
602
604 if (fca.isFixedCharge()) { charge = fca.getCharge(); }
605
608 if (fqa.isFluctuatingCharge()) { charge += atom->getFlucQPos(); }
609
610 charge *= chargeToC;
611
612 ri = atom->getPos();
613 snap->wrapVector(ri);
614 ri *= angstromToM;
615
616 if (charge < 0.0) {
617 nPos += ri;
618 nChg -= charge;
619 nCount++;
620 } else if (charge > 0.0) {
621 pPos += ri;
622 pChg += charge;
623 pCount++;
624 }
625
626 if (atom->isDipole()) {
627 dipoleVector += atom->getDipole() * debyeToCm;
628 }
629 }
630 }
631
632#ifdef IS_MPI
633 MPI_Allreduce(MPI_IN_PLACE, &pChg, 1, MPI_REALTYPE, MPI_SUM,
634 MPI_COMM_WORLD);
635 MPI_Allreduce(MPI_IN_PLACE, &nChg, 1, MPI_REALTYPE, MPI_SUM,
636 MPI_COMM_WORLD);
637
638 MPI_Allreduce(MPI_IN_PLACE, &pCount, 1, MPI_INTEGER, MPI_SUM,
639 MPI_COMM_WORLD);
640 MPI_Allreduce(MPI_IN_PLACE, &nCount, 1, MPI_INTEGER, MPI_SUM,
641 MPI_COMM_WORLD);
642
643 MPI_Allreduce(MPI_IN_PLACE, pPos.getArrayPointer(), 3, MPI_REALTYPE,
644 MPI_SUM, MPI_COMM_WORLD);
645 MPI_Allreduce(MPI_IN_PLACE, nPos.getArrayPointer(), 3, MPI_REALTYPE,
646 MPI_SUM, MPI_COMM_WORLD);
647
648 MPI_Allreduce(MPI_IN_PLACE, dipoleVector.getArrayPointer(), 3,
649 MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
650#endif
651
652 // first load the accumulated dipole moment (if dipoles were present)
653 Vector3d boxDipole = dipoleVector;
654 // now include the dipole moment due to charges
655 // use the lesser of the positive and negative charge totals
656 RealType chg_value = nChg <= pChg ? nChg : pChg;
657
658 // find the average positions
659 if (pCount > 0 && nCount > 0) {
660 pPos /= pCount;
661 nPos /= nCount;
662 }
663
664 // dipole is from the negative to the positive (physics notation)
665 boxDipole += (pPos - nPos) * chg_value;
666 snap->setSystemDipole(boxDipole);
667 }
668
669 return snap->getSystemDipole();
670 }
671
673 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
674
675 if (!snap->hasSystemQuadrupole) {
676 SimInfo::MoleculeIterator miter;
677 vector<Atom*>::iterator aiter;
678 Molecule* mol;
679 Atom* atom;
680 RealType charge;
681 Vector3d ri(0.0);
682 Vector3d dipole(0.0);
683 Mat3x3d qpole(0.0);
684
685 RealType chargeToC = 1.60217733e-19;
686 RealType angstromToM = 1.0e-10;
687 RealType debyeToCm = 3.33564095198e-30;
688
689 for (mol = info_->beginMolecule(miter); mol != NULL;
690 mol = info_->nextMolecule(miter)) {
691 for (atom = mol->beginAtom(aiter); atom != NULL;
692 atom = mol->nextAtom(aiter)) {
693 ri = atom->getPos();
694 snap->wrapVector(ri);
695 ri *= angstromToM;
696
697 charge = 0.0;
698
700 if (fca.isFixedCharge()) { charge = fca.getCharge(); }
701
704 if (fqa.isFluctuatingCharge()) { charge += atom->getFlucQPos(); }
705
706 charge *= chargeToC;
707
708 qpole += 0.5 * charge * outProduct(ri, ri);
709
711
712 if (ma.isDipole()) {
713 dipole = atom->getDipole() * debyeToCm;
714 qpole += 0.5 * outProduct(dipole, ri);
715 qpole += 0.5 * outProduct(ri, dipole);
716 }
717
718 if (ma.isQuadrupole()) {
719 qpole += atom->getQuadrupole() * debyeToCm * angstromToM;
720 }
721 }
722 }
723
724#ifdef IS_MPI
725 MPI_Allreduce(MPI_IN_PLACE, qpole.getArrayPointer(), 9, MPI_REALTYPE,
726 MPI_SUM, MPI_COMM_WORLD);
727#endif
728
729 snap->setSystemQuadrupole(qpole);
730 }
731
732 return snap->getSystemQuadrupole();
733 }
734
735 // Returns the Heat Flux Vector for the system
736 Vector3d Thermo::getHeatFlux() {
737 Snapshot* currSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
738 SimInfo::MoleculeIterator miter;
739 vector<StuntDouble*>::iterator iiter;
740 Molecule* mol;
741 StuntDouble* sd;
742 RigidBody::AtomIterator ai;
743 Atom* atom;
744 Vector3d vel, omegaB, omegaL;
745 Vector3d ambient, vorticity;
746 Vector3d J;
747 Mat3x3d I, A, Atrans;
748 int i;
749 int j;
750 int k;
751 RealType mass;
752
753 Vector3d x_a;
754 RealType kinetic;
755 RealType potential;
756 RealType eatom;
757 // Convective portion of the heat flux
758 Vector3d heatFluxJc = V3Zero;
759
760 if (usePeculiarVelocities_) {
761 vorticity = velField_->getVorticity();
762 }
763
764 /* Calculate convective portion of the heat flux */
765 for (mol = info_->beginMolecule(miter); mol != NULL;
766 mol = info_->nextMolecule(miter)) {
767 for (sd = mol->beginIntegrableObject(iiter); sd != NULL;
768 sd = mol->nextIntegrableObject(iiter)) {
769 mass = sd->getMass();
770 vel = sd->getVel();
771 if (usePeculiarVelocities_) {
772 ambient = velField_->getVelocity(sd->getPos());
773 vel -= ambient;
774 }
775
776 kinetic = mass * (vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2]);
777
778 if (sd->isDirectional()) {
779 J = sd->getJ();
780 I = sd->getI();
781 A = sd->getA();
782 Atrans = A.transpose();
783
784 if (sd->isLinear()) {
785 i = sd->linearAxis();
786 j = (i + 1) % 3;
787 k = (i + 2) % 3;
788 omegaB[i] = 0.0;
789 omegaB[j] = J[j] / I(j,j);
790 omegaB[k] = J[k] / I(k,k);
791 } else {
792 omegaB[0] = J[0] / I(0,0);
793 omegaB[1] = J[1] / I(1,1);
794 omegaB[2] = J[2] / I(2,2);
795 }
796 omegaL = Atrans * omegaB - vorticity;
797 omegaB = A * omegaL;
798
799 kinetic += dot(omegaB, I * omegaB);
800 }
801
802 potential = 0.0;
803
804 if (sd->isRigidBody()) {
805 RigidBody* rb = dynamic_cast<RigidBody*>(sd);
806 for (atom = rb->beginAtom(ai); atom != NULL;
807 atom = rb->nextAtom(ai)) {
808 potential += atom->getParticlePot();
809 }
810 } else {
811 potential = sd->getParticlePot();
812 }
813
814 potential *= Constants::energyConvert; // amu A^2/fs^2
815 // The potential may not be a 1/2 factor
816 eatom = (kinetic + potential) / 2.0; // amu A^2/fs^2
817 heatFluxJc[0] += eatom * vel[0]; // amu A^3/fs^3
818 heatFluxJc[1] += eatom * vel[1]; // amu A^3/fs^3
819 heatFluxJc[2] += eatom * vel[2]; // amu A^3/fs^3
820 }
821 }
822
823 /* The J_v vector is reduced in the forceManager so everyone has
824 * the global Jv. Jc is computed over the local atoms and must be
825 * reduced among all processors.
826 */
827#ifdef IS_MPI
828 MPI_Allreduce(MPI_IN_PLACE, &heatFluxJc[0], 3, MPI_REALTYPE, MPI_SUM,
829 MPI_COMM_WORLD);
830#endif
831
832 // (kcal/mol * A/fs) * conversion => (amu A^3)/fs^3
833
834 Vector3d heatFluxJv =
835 currSnapshot->getConductiveHeatFlux() * Constants::energyConvert;
836
837 // Correct for the fact the flux is 1/V (Jc + Jv)
838 return (heatFluxJv + heatFluxJc) / this->getVolume(); // amu / fs^3
839 }
840
841 Vector3d Thermo::getComVel() {
842 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
843
844 if (!snap->hasCOMvel) {
845 SimInfo::MoleculeIterator i;
846 Molecule* mol;
847
848 Vector3d vel;
849 Vector3d ambient;
850 Vector3d comVel(0.0);
851 RealType totalMass(0.0);
852
853 for (mol = info_->beginMolecule(i); mol != NULL;
854 mol = info_->nextMolecule(i)) {
855 RealType mass = mol->getMass();
856 totalMass += mass;
857 vel = mol->getComVel();
858 if (usePeculiarVelocities_) {
859 ambient = velField_->getVelocity(mol->getCom());
860 vel -= ambient;
861 }
862
863 comVel += mass * vel;
864 }
865
866#ifdef IS_MPI
867 MPI_Allreduce(MPI_IN_PLACE, &totalMass, 1, MPI_REALTYPE, MPI_SUM,
868 MPI_COMM_WORLD);
869 MPI_Allreduce(MPI_IN_PLACE, comVel.getArrayPointer(), 3, MPI_REALTYPE,
870 MPI_SUM, MPI_COMM_WORLD);
871#endif
872
873 comVel /= totalMass;
874 snap->setCOMvel(comVel);
875 }
876 return snap->getCOMvel();
877 }
878
879 Vector3d Thermo::getCom() {
880 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
881
882 if (!snap->hasCOM) {
883 SimInfo::MoleculeIterator i;
884 Molecule* mol;
885
886 Vector3d com(0.0);
887 RealType totalMass(0.0);
888
889 for (mol = info_->beginMolecule(i); mol != NULL;
890 mol = info_->nextMolecule(i)) {
891 RealType mass = mol->getMass();
892 totalMass += mass;
893 com += mass * mol->getCom();
894 }
895
896#ifdef IS_MPI
897 MPI_Allreduce(MPI_IN_PLACE, &totalMass, 1, MPI_REALTYPE, MPI_SUM,
898 MPI_COMM_WORLD);
899 MPI_Allreduce(MPI_IN_PLACE, com.getArrayPointer(), 3, MPI_REALTYPE,
900 MPI_SUM, MPI_COMM_WORLD);
901#endif
902
903 com /= totalMass;
904 snap->setCOM(com);
905 }
906 return snap->getCOM();
907 }
908
909 /**
910 * Returns center of mass and center of mass velocity in one
911 * function call.
912 */
913 void Thermo::getComAll(Vector3d& com, Vector3d& comVel) {
914 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
915
916 if (!(snap->hasCOM && snap->hasCOMvel)) {
917 SimInfo::MoleculeIterator i;
918 Molecule* mol;
919
920 RealType totalMass(0.0);
921 Vector3d vel;
922 Vector3d ambient;
923
924 com = 0.0;
925 comVel = 0.0;
926
927 for (mol = info_->beginMolecule(i); mol != NULL;
928 mol = info_->nextMolecule(i)) {
929 RealType mass = mol->getMass();
930 totalMass += mass;
931 com += mass * mol->getCom();
932
933 vel = mol->getComVel();
934 if (usePeculiarVelocities_) {
935 ambient = velField_->getVelocity(mol->getCom());
936 vel -= ambient;
937 }
938
939 comVel += mass * vel;
940
941 }
942
943#ifdef IS_MPI
944 MPI_Allreduce(MPI_IN_PLACE, &totalMass, 1, MPI_REALTYPE, MPI_SUM,
945 MPI_COMM_WORLD);
946 MPI_Allreduce(MPI_IN_PLACE, com.getArrayPointer(), 3, MPI_REALTYPE,
947 MPI_SUM, MPI_COMM_WORLD);
948 MPI_Allreduce(MPI_IN_PLACE, comVel.getArrayPointer(), 3, MPI_REALTYPE,
949 MPI_SUM, MPI_COMM_WORLD);
950#endif
951
952 com /= totalMass;
953 comVel /= totalMass;
954 snap->setCOM(com);
955 snap->setCOMvel(comVel);
956 }
957 com = snap->getCOM();
958 comVel = snap->getCOMvel();
959 return;
960 }
961
962 /**
963 * \brief Return inertia tensor for entire system and angular momentum
964 * Vector.
965 *
966 *
967 *
968 * [ Ixx -Ixy -Ixz ]
969 * I =| -Iyx Iyy -Iyz |
970 * [ -Izx -Iyz Izz ]
971 */
972 void Thermo::getInertiaTensor(Mat3x3d& inertiaTensor,
973 Vector3d& angularMomentum) {
974 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
975 Molecule::IntegrableObjectIterator j;
976 StuntDouble* sd;
977
978 if (!(snap->hasInertiaTensor && snap->hasCOMw)) {
979 RealType xx = 0.0;
980 RealType yy = 0.0;
981 RealType zz = 0.0;
982 RealType xy = 0.0;
983 RealType xz = 0.0;
984 RealType yz = 0.0;
985 Vector3d com(0.0);
986 Vector3d comVel(0.0);
987
988 getComAll(com, comVel);
989
990 SimInfo::MoleculeIterator i;
991 Molecule* mol;
992
993 Vector3d r(0.0);
994 Vector3d v(0.0);
995 Mat3x3d Itmp {};
996
997 RealType m = 0.0;
998
999 for (mol = info_->beginMolecule(i); mol != NULL;
1000 mol = info_->nextMolecule(i)) {
1001 for (sd = mol->beginIntegrableObject(j); sd != NULL;
1002 sd = mol->nextIntegrableObject(j)) {
1003 r = sd->getPos() - com;
1004 v = sd->getVel() - comVel;
1005
1006 m = sd->getMass();
1007
1008 // Compute moment of intertia coefficients.
1009 xx += r[0] * r[0] * m;
1010 yy += r[1] * r[1] * m;
1011 zz += r[2] * r[2] * m;
1012
1013 // compute products of intertia
1014 xy += r[0] * r[1] * m;
1015 xz += r[0] * r[2] * m;
1016 yz += r[1] * r[2] * m;
1017
1018 angularMomentum += cross(r, v) * m;
1019
1020 if (sd->isDirectional()) {
1021 RotMat3x3d A = sd->getA();
1022 Itmp += A.transpose() * sd->getI() * A;
1023 angularMomentum += sd->getJ();
1024 }
1025 }
1026 }
1027
1028 inertiaTensor(0, 0) = yy + zz;
1029 inertiaTensor(0, 1) = -xy;
1030 inertiaTensor(0, 2) = -xz;
1031 inertiaTensor(1, 0) = -xy;
1032 inertiaTensor(1, 1) = xx + zz;
1033 inertiaTensor(1, 2) = -yz;
1034 inertiaTensor(2, 0) = -xz;
1035 inertiaTensor(2, 1) = -yz;
1036 inertiaTensor(2, 2) = xx + yy;
1037
1038 inertiaTensor += Itmp;
1039
1040#ifdef IS_MPI
1041 MPI_Allreduce(MPI_IN_PLACE, inertiaTensor.getArrayPointer(), 9,
1042 MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1043 MPI_Allreduce(MPI_IN_PLACE, angularMomentum.getArrayPointer(), 3,
1044 MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1045#endif
1046
1047 snap->setCOMw(angularMomentum);
1048 snap->setInertiaTensor(inertiaTensor);
1049 }
1050
1051 angularMomentum = snap->getCOMw();
1052 inertiaTensor = snap->getInertiaTensor();
1053
1054 return;
1055 }
1056
1058 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
1059
1060 if (!(snap->hasBoundingBox)) {
1061 SimInfo::MoleculeIterator i;
1062 Molecule::RigidBodyIterator ri;
1063 Molecule::AtomIterator ai;
1064 Molecule* mol;
1065 RigidBody* rb;
1066 Atom* atom;
1067 Vector3d pos, bMax, bMin;
1068 int index = 0;
1069
1070 for (mol = info_->beginMolecule(i); mol != NULL;
1071 mol = info_->nextMolecule(i)) {
1072 // change the positions of atoms which belong to the rigidbodies
1073 for (rb = mol->beginRigidBody(ri); rb != NULL;
1074 rb = mol->nextRigidBody(ri)) {
1075 rb->updateAtoms();
1076 }
1077
1078 for (atom = mol->beginAtom(ai); atom != NULL;
1079 atom = mol->nextAtom(ai)) {
1080 pos = atom->getPos();
1081
1082 if (index == 0) {
1083 bMax = pos;
1084 bMin = pos;
1085 } else {
1086 for (int i = 0; i < 3; i++) {
1087 bMax[i] = max(bMax[i], pos[i]);
1088 bMin[i] = min(bMin[i], pos[i]);
1089 }
1090 }
1091 index++;
1092 }
1093 }
1094
1095#ifdef IS_MPI
1096 MPI_Allreduce(MPI_IN_PLACE, &bMax[0], 3, MPI_REALTYPE, MPI_MAX,
1097 MPI_COMM_WORLD);
1098
1099 MPI_Allreduce(MPI_IN_PLACE, &bMin[0], 3, MPI_REALTYPE, MPI_MIN,
1100 MPI_COMM_WORLD);
1101#endif
1102 Mat3x3d bBox = Mat3x3d(0.0);
1103 for (int i = 0; i < 3; i++) {
1104 bBox(i, i) = bMax[i] - bMin[i];
1105 }
1106 snap->setBoundingBox(bBox);
1107 }
1108
1109 return snap->getBoundingBox();
1110 }
1111
1112 // Returns the angular momentum of the system
1114 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
1115
1116 if (!snap->hasCOMw) {
1117 Vector3d com(0.0);
1118 Vector3d comVel(0.0);
1119 Vector3d angularMomentum(0.0);
1120
1121 getComAll(com, comVel);
1122
1123 SimInfo::MoleculeIterator i;
1124 Molecule* mol;
1125
1126 Vector3d thisr(0.0);
1127 Vector3d thisp(0.0);
1128
1129 RealType thisMass;
1130
1131 for (mol = info_->beginMolecule(i); mol != NULL;
1132 mol = info_->nextMolecule(i)) {
1133 thisMass = mol->getMass();
1134 thisr = mol->getCom() - com;
1135 thisp = (mol->getComVel() - comVel) * thisMass;
1136
1137 angularMomentum += cross(thisr, thisp);
1138 }
1139
1140#ifdef IS_MPI
1141 MPI_Allreduce(MPI_IN_PLACE, angularMomentum.getArrayPointer(), 3,
1142 MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1143#endif
1144
1145 snap->setCOMw(angularMomentum);
1146 }
1147
1148 return snap->getCOMw();
1149 }
1150
1151 /**
1152 * Returns the Volume of the system based on a ellipsoid with
1153 * semi-axes based on the radius of gyration V=4/3*Pi*R_1*R_2*R_3
1154 * where R_i are related to the principle inertia moments
1155 * R_i = sqrt(C*I_i/N), this reduces to
1156 * V = 4/3*Pi*(C/N)^3/2*sqrt(det(I)).
1157 * See S.E. Baltazar et. al. Comp. Mat. Sci. 37 (2006) 526-536.
1158 */
1160 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
1161
1162 if (!snap->hasGyrationalVolume) {
1163 Mat3x3d intTensor;
1164 RealType det;
1165 Vector3d dummyAngMom;
1166 RealType sysconstants;
1167 RealType geomCnst;
1168 RealType volume;
1169
1170 geomCnst = 3.0 / 2.0;
1171 /* Get the inertial tensor and angular momentum for free*/
1172 getInertiaTensor(intTensor, dummyAngMom);
1173
1174 det = intTensor.determinant();
1175 sysconstants =
1176 geomCnst / (RealType)(info_->getNGlobalIntegrableObjects());
1177 volume =
1178 4.0 / 3.0 * Constants::PI * pow(sysconstants, geomCnst) * sqrt(det);
1179
1180 snap->setGyrationalVolume(volume);
1181 }
1182 return snap->getGyrationalVolume();
1183 }
1184
1185 void Thermo::getGyrationalVolume(RealType& volume, RealType& detI) {
1186 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
1187
1188 if (!(snap->hasInertiaTensor && snap->hasGyrationalVolume)) {
1189 Mat3x3d intTensor;
1190 Vector3d dummyAngMom;
1191 RealType sysconstants;
1192 RealType geomCnst;
1193
1194 geomCnst = 3.0 / 2.0;
1195 /* Get the inertia tensor and angular momentum for free*/
1196 this->getInertiaTensor(intTensor, dummyAngMom);
1197
1198 detI = intTensor.determinant();
1199 sysconstants =
1200 geomCnst / (RealType)(info_->getNGlobalIntegrableObjects());
1201 volume =
1202 4.0 / 3.0 * Constants::PI * pow(sysconstants, geomCnst) * sqrt(detI);
1203 snap->setGyrationalVolume(volume);
1204 } else {
1205 volume = snap->getGyrationalVolume();
1206 detI = snap->getInertiaTensor().determinant();
1207 }
1208 return;
1209 }
1210
1211 RealType Thermo::getTaggedAtomPairDistance() {
1212 Snapshot* currSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
1213 Globals* simParams = info_->getSimParams();
1214
1215 if (simParams->haveTaggedAtomPair() &&
1216 simParams->havePrintTaggedPairDistance()) {
1217 if (simParams->getPrintTaggedPairDistance()) {
1218 pair<int, int> tap = simParams->getTaggedAtomPair();
1219 Vector3d pos1, pos2, rab;
1220
1221#ifdef IS_MPI
1222 int mol1 = info_->getGlobalMolMembership(tap.first);
1223 int mol2 = info_->getGlobalMolMembership(tap.second);
1224
1225 int proc1 = info_->getMolToProc(mol1);
1226 int proc2 = info_->getMolToProc(mol2);
1227
1228 RealType data[3];
1229 if (proc1 == worldRank) {
1230 StuntDouble* sd1 = info_->getIOIndexToIntegrableObject(tap.first);
1231 pos1 = sd1->getPos();
1232 data[0] = pos1.x();
1233 data[1] = pos1.y();
1234 data[2] = pos1.z();
1235 MPI_Bcast(data, 3, MPI_REALTYPE, proc1, MPI_COMM_WORLD);
1236 } else {
1237 MPI_Bcast(data, 3, MPI_REALTYPE, proc1, MPI_COMM_WORLD);
1238 pos1 = Vector3d(data);
1239 }
1240
1241 if (proc2 == worldRank) {
1242 StuntDouble* sd2 = info_->getIOIndexToIntegrableObject(tap.second);
1243 pos2 = sd2->getPos();
1244 data[0] = pos2.x();
1245 data[1] = pos2.y();
1246 data[2] = pos2.z();
1247 MPI_Bcast(data, 3, MPI_REALTYPE, proc2, MPI_COMM_WORLD);
1248 } else {
1249 MPI_Bcast(data, 3, MPI_REALTYPE, proc2, MPI_COMM_WORLD);
1250 pos2 = Vector3d(data);
1251 }
1252#else
1253 StuntDouble* at1 = info_->getIOIndexToIntegrableObject(tap.first);
1254 StuntDouble* at2 = info_->getIOIndexToIntegrableObject(tap.second);
1255 pos1 = at1->getPos();
1256 pos2 = at2->getPos();
1257#endif
1258 rab = pos2 - pos1;
1259 currSnapshot->wrapVector(rab);
1260 return rab.length();
1261 }
1262 return 0.0;
1263 }
1264 return 0.0;
1265 }
1266
1267 RealType Thermo::getHullVolume() {
1268#ifdef HAVE_QHULL
1269 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
1270 if (!snap->hasHullVolume) {
1271 Hull* surfaceMesh_;
1272
1273 Globals* simParams = info_->getSimParams();
1274 const std::string ht = simParams->getHULL_Method();
1275
1276 if (ht == "Convex") {
1277 surfaceMesh_ = new ConvexHull();
1278 } else if (ht == "AlphaShape") {
1279 surfaceMesh_ = new AlphaHull(simParams->getAlpha());
1280 } else {
1281 return 0.0;
1282 }
1283
1284 // Build a vector of stunt doubles to determine if they are
1285 // surface atoms
1286 std::vector<StuntDouble*> localSites_;
1287 Molecule* mol;
1288 StuntDouble* sd;
1289 SimInfo::MoleculeIterator i;
1290 Molecule::IntegrableObjectIterator j;
1291
1292 for (mol = info_->beginMolecule(i); mol != NULL;
1293 mol = info_->nextMolecule(i)) {
1294 for (sd = mol->beginIntegrableObject(j); sd != NULL;
1295 sd = mol->nextIntegrableObject(j)) {
1296 localSites_.push_back(sd);
1297 }
1298 }
1299
1300 // Compute surface Mesh
1301 surfaceMesh_->computeHull(localSites_);
1302 snap->setHullVolume(surfaceMesh_->getVolume());
1303
1304 delete surfaceMesh_;
1305 }
1306
1307 return snap->getHullVolume();
1308#else
1309 return 0.0;
1310#endif
1311 }
1312
1313} // namespace OpenMD
AtomType * getAtomType()
Returns the AtomType of this Atom.
Definition Atom.hpp:86
RealType getMass()
get total mass of this molecule
Definition Molecule.cpp:268
Vector3d getComVel()
Returns the velocity of center of mass of this molecule.
Definition Molecule.cpp:368
Vector3d getCom()
Returns the current center of mass position of this molecule.
Definition Molecule.cpp:315
Real * getArrayPointer()
Returns the pointer of internal array.
void updateAtoms()
update the positions of atoms belong to this rigidbody
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
Definition SimInfo.hpp:96
The Snapshot class is a repository storing dynamic data during a Simulation.
Definition Snapshot.hpp:166
Mat3x3d getBoundingBox()
Returns the Bounding Box.
Definition Snapshot.cpp:284
void setBoundingBox(const Mat3x3d &m)
Sets the Bounding Box.
Definition Snapshot.cpp:287
void wrapVector(Vector3d &v)
Wrapping the vector according to periodic boundary condition.
Definition Snapshot.cpp:340
Real determinant() const
Returns the determinant of this matrix.
"Don't move, or you're dead! Stand up! Captain, we've got them!"
RotMat3x3d getA()
Returns the current rotation matrix of this stuntDouble.
Vector3d getVel()
Returns the current velocity of this stuntDouble.
int linearAxis()
Returns the linear axis of the rigidbody, atom and directional atom will always return -1.
RealType getMass()
Returns the mass of this stuntDouble.
Mat3x3d getQuadrupole()
Returns the current quadrupole tensor of this stuntDouble.
virtual Mat3x3d getI()=0
Returns the inertia tensor of this stuntDouble.
bool isLinear()
Tests the if this stuntDouble is a linear rigidbody.
Vector3d getPos()
Returns the current position of this stuntDouble.
RealType getFlucQPos()
Returns the current fluctuating charge of this stuntDouble.
Vector3d getDipole()
Returns the current dipole vector of this stuntDouble.
RealType getParticlePot()
Returns the current particlePot of this stuntDouble.
bool isRigidBody()
Tests if this stuntDouble is a rigid body.
Vector3d getJ()
Returns the current angular momentum of this stuntDouble (body -fixed).
bool isDirectional()
Tests if this stuntDouble is a directional one.
Mat3x3d getPressureTensor()
gives the pressure tensor in amu*fs^-2*Ang^-1
Definition Thermo.cpp:483
Vector3d getSystemDipole()
accumulate and return the simulation box dipole moment in C*m
Definition Thermo.cpp:575
void getComAll(Vector3d &com, Vector3d &comVel)
Returns the center of the mass and Center of Mass velocity of the whole system.
Definition Thermo.cpp:913
void getInertiaTensor(Mat3x3d &inertiaTensor, Vector3d &angularMomentum)
Returns the inertia tensor and the total angular momentum for for the entire system.
Definition Thermo.cpp:972
RealType getGyrationalVolume()
Returns volume of system as estimated by an ellipsoid defined by the radii of gyration.
Definition Thermo.cpp:1159
Vector3d getCom()
Returns the center of the mass of the whole system.
Definition Thermo.cpp:879
Mat3x3d getSystemQuadrupole()
accumulate and return the simulation box dipole moment in debye Angstroms
Definition Thermo.cpp:672
Vector3d getAngularMomentum()
Returns system angular momentum.
Definition Thermo.cpp:1113
Vector3d getComVel()
Returns the velocity of center of mass of the whole system.
Definition Thermo.cpp:841
Mat3x3d getBoundingBox()
Returns the Axis-aligned bounding box for the current system.
Definition Thermo.cpp:1057
Real & z()
Returns reference of the third element of Vector3.
Definition Vector3.hpp:123
Real & x()
Returns reference of the first element of Vector3.
Definition Vector3.hpp:99
Real & y()
Returns reference of the second element of Vector3.
Definition Vector3.hpp:111
const Real * getArrayPointer() const
Returns the pointer of internal array.
Definition Vector.hpp:174
Real length() const
Returns the length of this vector.
Definition Vector.hpp:397
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
Vector3< Real > cross(const Vector3< Real > &v1, const Vector3< Real > &v2)
Returns the cross product of two Vectors.
Definition Vector3.hpp:139
Real dot(const DynamicVector< Real > &v1, const DynamicVector< Real > &v2)
Returns the dot product of two DynamicVectors.