ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/brains/Thermo.cpp
Revision: 1874
Committed: Wed May 15 15:09:35 2013 UTC (11 years, 11 months ago) by gezelter
File size: 29427 byte(s)
Log Message:
Fixed a bunch of cppcheck warnings.

File Contents

# User Rev Content
1 gezelter 507 /*
2 gezelter 246 * Copyright (c) 2005 The University of Notre Dame. All Rights Reserved.
3     *
4     * The University of Notre Dame grants you ("Licensee") a
5     * non-exclusive, royalty free, license to use, modify and
6     * redistribute this software in source and binary code form, provided
7     * that the following conditions are met:
8     *
9 gezelter 1390 * 1. Redistributions of source code must retain the above copyright
10 gezelter 246 * notice, this list of conditions and the following disclaimer.
11     *
12 gezelter 1390 * 2. Redistributions in binary form must reproduce the above copyright
13 gezelter 246 * notice, this list of conditions and the following disclaimer in the
14     * documentation and/or other materials provided with the
15     * distribution.
16     *
17     * This software is provided "AS IS," without a warranty of any
18     * kind. All express or implied conditions, representations and
19     * warranties, including any implied warranty of merchantability,
20     * fitness for a particular purpose or non-infringement, are hereby
21     * excluded. The University of Notre Dame and its licensors shall not
22     * be liable for any damages suffered by licensee as a result of
23     * using, modifying or distributing the software or its
24     * derivatives. In no event will the University of Notre Dame or its
25     * licensors be liable for any lost revenue, profit or data, or for
26     * direct, indirect, special, consequential, incidental or punitive
27     * damages, however caused and regardless of the theory of liability,
28     * arising out of the use of or inability to use software, even if the
29     * University of Notre Dame has been advised of the possibility of
30     * such damages.
31 gezelter 1390 *
32     * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
33     * research, please cite the appropriate papers when you publish your
34     * work. Good starting points are:
35     *
36     * [1] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
37     * [2] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
38 gezelter 1850 * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 234107 (2008).
39 gezelter 1665 * [4] Kuang & Gezelter, J. Chem. Phys. 133, 164101 (2010).
40     * [5] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011).
41 gezelter 246 */
42    
43 gezelter 2 #include <math.h>
44     #include <iostream>
45    
46     #ifdef IS_MPI
47     #include <mpi.h>
48     #endif //is_mpi
49    
50 tim 3 #include "brains/Thermo.hpp"
51 gezelter 246 #include "primitives/Molecule.hpp"
52 tim 3 #include "utils/simError.h"
53 gezelter 1390 #include "utils/PhysicalConstants.hpp"
54 gezelter 1764 #include "types/FixedChargeAdapter.hpp"
55     #include "types/FluctuatingChargeAdapter.hpp"
56 gezelter 1710 #include "types/MultipoleAdapter.hpp"
57 gezelter 1767 #ifdef HAVE_QHULL
58 gezelter 1764 #include "math/ConvexHull.hpp"
59     #include "math/AlphaHull.hpp"
60 gezelter 1767 #endif
61 gezelter 2
62 gezelter 1764 using namespace std;
63 gezelter 1390 namespace OpenMD {
64 gezelter 2
65 gezelter 1764 RealType Thermo::getTranslationalKinetic() {
66     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
67    
68     if (!snap->hasTranslationalKineticEnergy) {
69     SimInfo::MoleculeIterator miter;
70     vector<StuntDouble*>::iterator iiter;
71     Molecule* mol;
72     StuntDouble* sd;
73     Vector3d vel;
74     RealType mass;
75     RealType kinetic(0.0);
76    
77     for (mol = info_->beginMolecule(miter); mol != NULL;
78     mol = info_->nextMolecule(miter)) {
79 gezelter 945
80 gezelter 1764 for (sd = mol->beginIntegrableObject(iiter); sd != NULL;
81     sd = mol->nextIntegrableObject(iiter)) {
82    
83     mass = sd->getMass();
84     vel = sd->getVel();
85    
86     kinetic += mass * (vel[0]*vel[0] + vel[1]*vel[1] + vel[2]*vel[2]);
87    
88     }
89     }
90    
91     #ifdef IS_MPI
92     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &kinetic, 1, MPI::REALTYPE,
93     MPI::SUM);
94     #endif
95    
96     kinetic = kinetic * 0.5 / PhysicalConstants::energyConvert;
97    
98    
99     snap->setTranslationalKineticEnergy(kinetic);
100     }
101     return snap->getTranslationalKineticEnergy();
102     }
103    
104     RealType Thermo::getRotationalKinetic() {
105     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
106    
107     if (!snap->hasRotationalKineticEnergy) {
108     SimInfo::MoleculeIterator miter;
109     vector<StuntDouble*>::iterator iiter;
110     Molecule* mol;
111     StuntDouble* sd;
112     Vector3d angMom;
113     Mat3x3d I;
114     int i, j, k;
115     RealType kinetic(0.0);
116    
117     for (mol = info_->beginMolecule(miter); mol != NULL;
118     mol = info_->nextMolecule(miter)) {
119 gezelter 945
120 gezelter 1764 for (sd = mol->beginIntegrableObject(iiter); sd != NULL;
121     sd = mol->nextIntegrableObject(iiter)) {
122    
123     if (sd->isDirectional()) {
124     angMom = sd->getJ();
125     I = sd->getI();
126 gezelter 246
127 gezelter 1764 if (sd->isLinear()) {
128     i = sd->linearAxis();
129     j = (i + 1) % 3;
130     k = (i + 2) % 3;
131     kinetic += angMom[j] * angMom[j] / I(j, j)
132     + angMom[k] * angMom[k] / I(k, k);
133     } else {
134     kinetic += angMom[0]*angMom[0]/I(0, 0)
135     + angMom[1]*angMom[1]/I(1, 1)
136     + angMom[2]*angMom[2]/I(2, 2);
137     }
138     }
139     }
140 gezelter 507 }
141 gezelter 1764
142     #ifdef IS_MPI
143     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &kinetic, 1, MPI::REALTYPE,
144     MPI::SUM);
145     #endif
146    
147     kinetic = kinetic * 0.5 / PhysicalConstants::energyConvert;
148    
149     snap->setRotationalKineticEnergy(kinetic);
150 gezelter 246 }
151 gezelter 1764 return snap->getRotationalKineticEnergy();
152     }
153 gezelter 2
154 gezelter 1764
155 gezelter 2
156 gezelter 1764 RealType Thermo::getKinetic() {
157     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
158 gezelter 2
159 gezelter 1764 if (!snap->hasKineticEnergy) {
160     RealType ke = getTranslationalKinetic() + getRotationalKinetic();
161     snap->setKineticEnergy(ke);
162     }
163     return snap->getKineticEnergy();
164 gezelter 507 }
165 gezelter 2
166 tim 963 RealType Thermo::getPotential() {
167 gezelter 1760
168 gezelter 1764 // ForceManager computes the potential and stores it in the
169     // Snapshot. All we have to do is report it.
170    
171     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
172     return snap->getPotentialEnergy();
173 gezelter 507 }
174 gezelter 2
175 gezelter 1764 RealType Thermo::getTotalEnergy() {
176 gezelter 2
177 gezelter 1764 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
178    
179     if (!snap->hasTotalEnergy) {
180     snap->setTotalEnergy(this->getKinetic() + this->getPotential());
181     }
182    
183     return snap->getTotalEnergy();
184 gezelter 507 }
185 gezelter 2
186 tim 963 RealType Thermo::getTemperature() {
187 gezelter 1764
188     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
189    
190     if (!snap->hasTemperature) {
191    
192     RealType temperature = ( 2.0 * this->getKinetic() )
193     / (info_->getNdf()* PhysicalConstants::kb );
194    
195     snap->setTemperature(temperature);
196     }
197 gezelter 246
198 gezelter 1764 return snap->getTemperature();
199 gezelter 507 }
200 gezelter 2
201 gezelter 1715 RealType Thermo::getElectronicTemperature() {
202 gezelter 1764 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
203    
204     if (!snap->hasElectronicTemperature) {
205    
206     SimInfo::MoleculeIterator miter;
207     vector<Atom*>::iterator iiter;
208     Molecule* mol;
209     Atom* atom;
210     RealType cvel;
211     RealType cmass;
212     RealType kinetic(0.0);
213     RealType eTemp;
214    
215     for (mol = info_->beginMolecule(miter); mol != NULL;
216     mol = info_->nextMolecule(miter)) {
217 gezelter 1715
218 gezelter 1764 for (atom = mol->beginFluctuatingCharge(iiter); atom != NULL;
219     atom = mol->nextFluctuatingCharge(iiter)) {
220    
221     cmass = atom->getChargeMass();
222     cvel = atom->getFlucQVel();
223    
224     kinetic += cmass * cvel * cvel;
225    
226     }
227 gezelter 1715 }
228    
229     #ifdef IS_MPI
230 gezelter 1764 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &kinetic, 1, MPI::REALTYPE,
231     MPI::SUM);
232     #endif
233 gezelter 1715
234 gezelter 1764 kinetic *= 0.5;
235     eTemp = (2.0 * kinetic) /
236 gezelter 1870 (info_->getNFluctuatingCharges() * PhysicalConstants::kb );
237 gezelter 1764
238     snap->setElectronicTemperature(eTemp);
239     }
240 gezelter 1715
241 gezelter 1764 return snap->getElectronicTemperature();
242 gezelter 1715 }
243    
244    
245 tim 963 RealType Thermo::getVolume() {
246 gezelter 1764 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
247     return snap->getVolume();
248 gezelter 507 }
249 gezelter 2
250 tim 963 RealType Thermo::getPressure() {
251 gezelter 1764 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
252 gezelter 2
253 gezelter 1764 if (!snap->hasPressure) {
254     // Relies on the calculation of the full molecular pressure tensor
255    
256     Mat3x3d tensor;
257     RealType pressure;
258    
259     tensor = getPressureTensor();
260    
261     pressure = PhysicalConstants::pressureConvert *
262     (tensor(0, 0) + tensor(1, 1) + tensor(2, 2)) / 3.0;
263    
264     snap->setPressure(pressure);
265     }
266    
267     return snap->getPressure();
268 gezelter 507 }
269 gezelter 2
270 gezelter 507 Mat3x3d Thermo::getPressureTensor() {
271 gezelter 246 // returns pressure tensor in units amu*fs^-2*Ang^-1
272     // routine derived via viral theorem description in:
273     // Paci, E. and Marchi, M. J.Phys.Chem. 1996, 100, 4314-4322
274 gezelter 1764 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
275 gezelter 2
276 gezelter 1764 if (!snap->hasPressureTensor) {
277 gezelter 2
278 gezelter 1764 Mat3x3d pressureTensor;
279     Mat3x3d p_tens(0.0);
280     RealType mass;
281     Vector3d vcom;
282    
283     SimInfo::MoleculeIterator i;
284     vector<StuntDouble*>::iterator j;
285     Molecule* mol;
286     StuntDouble* sd;
287     for (mol = info_->beginMolecule(i); mol != NULL;
288     mol = info_->nextMolecule(i)) {
289    
290     for (sd = mol->beginIntegrableObject(j); sd != NULL;
291     sd = mol->nextIntegrableObject(j)) {
292    
293     mass = sd->getMass();
294     vcom = sd->getVel();
295     p_tens += mass * outProduct(vcom, vcom);
296     }
297 gezelter 507 }
298 gezelter 1764
299     #ifdef IS_MPI
300     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, p_tens.getArrayPointer(), 9,
301     MPI::REALTYPE, MPI::SUM);
302     #endif
303    
304     RealType volume = this->getVolume();
305     Mat3x3d stressTensor = snap->getStressTensor();
306    
307     pressureTensor = (p_tens +
308     PhysicalConstants::energyConvert * stressTensor)/volume;
309    
310     snap->setPressureTensor(pressureTensor);
311 gezelter 246 }
312 gezelter 1764 return snap->getPressureTensor();
313 gezelter 507 }
314 gezelter 2
315 chrisfen 998
316 gezelter 2
317 tim 541
318 gezelter 1764 Vector3d Thermo::getSystemDipole() {
319     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
320 tim 541
321 gezelter 1764 if (!snap->hasSystemDipole) {
322     SimInfo::MoleculeIterator miter;
323     vector<Atom*>::iterator aiter;
324     Molecule* mol;
325     Atom* atom;
326     RealType charge;
327     Vector3d ri(0.0);
328     Vector3d dipoleVector(0.0);
329     Vector3d nPos(0.0);
330     Vector3d pPos(0.0);
331     RealType nChg(0.0);
332     RealType pChg(0.0);
333     int nCount = 0;
334     int pCount = 0;
335 gezelter 1291
336 gezelter 1764 RealType chargeToC = 1.60217733e-19;
337     RealType angstromToM = 1.0e-10;
338     RealType debyeToCm = 3.33564095198e-30;
339    
340     for (mol = info_->beginMolecule(miter); mol != NULL;
341     mol = info_->nextMolecule(miter)) {
342 gezelter 1503
343 gezelter 1764 for (atom = mol->beginAtom(aiter); atom != NULL;
344     atom = mol->nextAtom(aiter)) {
345    
346 gezelter 1503 charge = 0.0;
347 gezelter 1764
348     FixedChargeAdapter fca = FixedChargeAdapter(atom->getAtomType());
349     if ( fca.isFixedCharge() ) {
350     charge = fca.getCharge();
351 gezelter 1503 }
352 gezelter 1764
353     FluctuatingChargeAdapter fqa = FluctuatingChargeAdapter(atom->getAtomType());
354     if ( fqa.isFluctuatingCharge() ) {
355     charge += atom->getFlucQPos();
356     }
357    
358     charge *= chargeToC;
359    
360     ri = atom->getPos();
361     snap->wrapVector(ri);
362     ri *= angstromToM;
363    
364     if (charge < 0.0) {
365     nPos += ri;
366     nChg -= charge;
367     nCount++;
368     } else if (charge > 0.0) {
369     pPos += ri;
370     pChg += charge;
371     pCount++;
372     }
373    
374 gezelter 1787 if (atom->isDipole()) {
375     dipoleVector += atom->getDipole() * debyeToCm;
376 gezelter 1764 }
377 gezelter 1503 }
378     }
379 gezelter 1764
380    
381 gezelter 1503 #ifdef IS_MPI
382 gezelter 1764 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &pChg, 1, MPI::REALTYPE,
383     MPI::SUM);
384     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &nChg, 1, MPI::REALTYPE,
385     MPI::SUM);
386 gezelter 1503
387 gezelter 1764 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &pCount, 1, MPI::INTEGER,
388     MPI::SUM);
389     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &nCount, 1, MPI::INTEGER,
390     MPI::SUM);
391 gezelter 1503
392 gezelter 1764 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, pPos.getArrayPointer(), 3,
393     MPI::REALTYPE, MPI::SUM);
394     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, nPos.getArrayPointer(), 3,
395     MPI::REALTYPE, MPI::SUM);
396    
397     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, dipoleVector.getArrayPointer(),
398     3, MPI::REALTYPE, MPI::SUM);
399     #endif
400    
401     // first load the accumulated dipole moment (if dipoles were present)
402     Vector3d boxDipole = dipoleVector;
403     // now include the dipole moment due to charges
404     // use the lesser of the positive and negative charge totals
405     RealType chg_value = nChg <= pChg ? nChg : pChg;
406    
407     // find the average positions
408     if (pCount > 0 && nCount > 0 ) {
409     pPos /= pCount;
410     nPos /= nCount;
411     }
412    
413     // dipole is from the negative to the positive (physics notation)
414     boxDipole += (pPos - nPos) * chg_value;
415     snap->setSystemDipole(boxDipole);
416 gezelter 1503 }
417    
418 gezelter 1764 return snap->getSystemDipole();
419 gezelter 1503 }
420 gezelter 1723
421     // Returns the Heat Flux Vector for the system
422     Vector3d Thermo::getHeatFlux(){
423     Snapshot* currSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
424     SimInfo::MoleculeIterator miter;
425 gezelter 1764 vector<StuntDouble*>::iterator iiter;
426 gezelter 1723 Molecule* mol;
427 gezelter 1764 StuntDouble* sd;
428 gezelter 1723 RigidBody::AtomIterator ai;
429     Atom* atom;
430     Vector3d vel;
431     Vector3d angMom;
432     Mat3x3d I;
433     int i;
434     int j;
435     int k;
436     RealType mass;
437    
438     Vector3d x_a;
439     RealType kinetic;
440     RealType potential;
441     RealType eatom;
442     // Convective portion of the heat flux
443     Vector3d heatFluxJc = V3Zero;
444    
445     /* Calculate convective portion of the heat flux */
446     for (mol = info_->beginMolecule(miter); mol != NULL;
447     mol = info_->nextMolecule(miter)) {
448    
449 gezelter 1764 for (sd = mol->beginIntegrableObject(iiter);
450     sd != NULL;
451     sd = mol->nextIntegrableObject(iiter)) {
452 gezelter 1723
453 gezelter 1764 mass = sd->getMass();
454     vel = sd->getVel();
455 gezelter 1723
456     kinetic = mass * (vel[0]*vel[0] + vel[1]*vel[1] + vel[2]*vel[2]);
457    
458 gezelter 1764 if (sd->isDirectional()) {
459     angMom = sd->getJ();
460     I = sd->getI();
461 gezelter 1723
462 gezelter 1764 if (sd->isLinear()) {
463     i = sd->linearAxis();
464 gezelter 1723 j = (i + 1) % 3;
465     k = (i + 2) % 3;
466 gezelter 1764 kinetic += angMom[j] * angMom[j] / I(j, j)
467     + angMom[k] * angMom[k] / I(k, k);
468 gezelter 1723 } else {
469 gezelter 1764 kinetic += angMom[0]*angMom[0]/I(0, 0)
470     + angMom[1]*angMom[1]/I(1, 1)
471 gezelter 1723 + angMom[2]*angMom[2]/I(2, 2);
472     }
473     }
474    
475     potential = 0.0;
476    
477 gezelter 1764 if (sd->isRigidBody()) {
478     RigidBody* rb = dynamic_cast<RigidBody*>(sd);
479 gezelter 1723 for (atom = rb->beginAtom(ai); atom != NULL;
480     atom = rb->nextAtom(ai)) {
481     potential += atom->getParticlePot();
482     }
483     } else {
484 gezelter 1764 potential = sd->getParticlePot();
485 gezelter 1723 }
486    
487     potential *= PhysicalConstants::energyConvert; // amu A^2/fs^2
488     // The potential may not be a 1/2 factor
489     eatom = (kinetic + potential)/2.0; // amu A^2/fs^2
490     heatFluxJc[0] += eatom*vel[0]; // amu A^3/fs^3
491     heatFluxJc[1] += eatom*vel[1]; // amu A^3/fs^3
492     heatFluxJc[2] += eatom*vel[2]; // amu A^3/fs^3
493     }
494     }
495    
496 gezelter 1764 /* The J_v vector is reduced in the forceManager so everyone has
497     * the global Jv. Jc is computed over the local atoms and must be
498     * reduced among all processors.
499 gezelter 1723 */
500     #ifdef IS_MPI
501     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &heatFluxJc[0], 3, MPI::REALTYPE,
502     MPI::SUM);
503     #endif
504    
505     // (kcal/mol * A/fs) * conversion => (amu A^3)/fs^3
506    
507     Vector3d heatFluxJv = currSnapshot->getConductiveHeatFlux() *
508     PhysicalConstants::energyConvert;
509 gezelter 1764
510 gezelter 1723 // Correct for the fact the flux is 1/V (Jc + Jv)
511     return (heatFluxJv + heatFluxJc) / this->getVolume(); // amu / fs^3
512     }
513 gezelter 1764
514    
515     Vector3d Thermo::getComVel(){
516     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
517    
518     if (!snap->hasCOMvel) {
519    
520     SimInfo::MoleculeIterator i;
521     Molecule* mol;
522    
523     Vector3d comVel(0.0);
524     RealType totalMass(0.0);
525    
526     for (mol = info_->beginMolecule(i); mol != NULL;
527     mol = info_->nextMolecule(i)) {
528     RealType mass = mol->getMass();
529     totalMass += mass;
530     comVel += mass * mol->getComVel();
531     }
532    
533     #ifdef IS_MPI
534     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &totalMass, 1, MPI::REALTYPE,
535     MPI::SUM);
536     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, comVel.getArrayPointer(), 3,
537     MPI::REALTYPE, MPI::SUM);
538     #endif
539    
540     comVel /= totalMass;
541     snap->setCOMvel(comVel);
542     }
543     return snap->getCOMvel();
544     }
545    
546     Vector3d Thermo::getCom(){
547     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
548    
549     if (!snap->hasCOM) {
550    
551     SimInfo::MoleculeIterator i;
552     Molecule* mol;
553    
554     Vector3d com(0.0);
555     RealType totalMass(0.0);
556    
557     for (mol = info_->beginMolecule(i); mol != NULL;
558     mol = info_->nextMolecule(i)) {
559     RealType mass = mol->getMass();
560     totalMass += mass;
561     com += mass * mol->getCom();
562     }
563    
564     #ifdef IS_MPI
565     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &totalMass, 1, MPI::REALTYPE,
566     MPI::SUM);
567     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, com.getArrayPointer(), 3,
568     MPI::REALTYPE, MPI::SUM);
569     #endif
570    
571     com /= totalMass;
572     snap->setCOM(com);
573     }
574     return snap->getCOM();
575     }
576    
577     /**
578     * Returns center of mass and center of mass velocity in one
579     * function call.
580     */
581     void Thermo::getComAll(Vector3d &com, Vector3d &comVel){
582     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
583    
584     if (!(snap->hasCOM && snap->hasCOMvel)) {
585    
586     SimInfo::MoleculeIterator i;
587     Molecule* mol;
588    
589     RealType totalMass(0.0);
590    
591     com = 0.0;
592     comVel = 0.0;
593    
594     for (mol = info_->beginMolecule(i); mol != NULL;
595     mol = info_->nextMolecule(i)) {
596     RealType mass = mol->getMass();
597     totalMass += mass;
598     com += mass * mol->getCom();
599     comVel += mass * mol->getComVel();
600     }
601    
602     #ifdef IS_MPI
603     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &totalMass, 1, MPI::REALTYPE,
604     MPI::SUM);
605     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, com.getArrayPointer(), 3,
606     MPI::REALTYPE, MPI::SUM);
607     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, comVel.getArrayPointer(), 3,
608     MPI::REALTYPE, MPI::SUM);
609     #endif
610    
611     com /= totalMass;
612     comVel /= totalMass;
613     snap->setCOM(com);
614     snap->setCOMvel(comVel);
615     }
616     com = snap->getCOM();
617     comVel = snap->getCOMvel();
618     return;
619     }
620    
621     /**
622 gezelter 1866 * \brief Return inertia tensor for entire system and angular momentum
623     * Vector.
624 gezelter 1764 *
625     *
626     *
627     * [ Ixx -Ixy -Ixz ]
628     * I =| -Iyx Iyy -Iyz |
629     * [ -Izx -Iyz Izz ]
630     */
631     void Thermo::getInertiaTensor(Mat3x3d &inertiaTensor,
632     Vector3d &angularMomentum){
633    
634     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
635    
636     if (!(snap->hasInertiaTensor && snap->hasCOMw)) {
637    
638     RealType xx = 0.0;
639     RealType yy = 0.0;
640     RealType zz = 0.0;
641     RealType xy = 0.0;
642     RealType xz = 0.0;
643     RealType yz = 0.0;
644     Vector3d com(0.0);
645     Vector3d comVel(0.0);
646    
647     getComAll(com, comVel);
648    
649     SimInfo::MoleculeIterator i;
650     Molecule* mol;
651    
652     Vector3d thisq(0.0);
653     Vector3d thisv(0.0);
654    
655     RealType thisMass = 0.0;
656    
657     for (mol = info_->beginMolecule(i); mol != NULL;
658     mol = info_->nextMolecule(i)) {
659    
660     thisq = mol->getCom()-com;
661     thisv = mol->getComVel()-comVel;
662     thisMass = mol->getMass();
663     // Compute moment of intertia coefficients.
664     xx += thisq[0]*thisq[0]*thisMass;
665     yy += thisq[1]*thisq[1]*thisMass;
666     zz += thisq[2]*thisq[2]*thisMass;
667    
668     // compute products of intertia
669     xy += thisq[0]*thisq[1]*thisMass;
670     xz += thisq[0]*thisq[2]*thisMass;
671     yz += thisq[1]*thisq[2]*thisMass;
672    
673     angularMomentum += cross( thisq, thisv ) * thisMass;
674     }
675    
676     inertiaTensor(0,0) = yy + zz;
677     inertiaTensor(0,1) = -xy;
678     inertiaTensor(0,2) = -xz;
679     inertiaTensor(1,0) = -xy;
680     inertiaTensor(1,1) = xx + zz;
681     inertiaTensor(1,2) = -yz;
682     inertiaTensor(2,0) = -xz;
683     inertiaTensor(2,1) = -yz;
684     inertiaTensor(2,2) = xx + yy;
685    
686     #ifdef IS_MPI
687     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, inertiaTensor.getArrayPointer(),
688     9, MPI::REALTYPE, MPI::SUM);
689     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE,
690     angularMomentum.getArrayPointer(), 3,
691     MPI::REALTYPE, MPI::SUM);
692     #endif
693    
694     snap->setCOMw(angularMomentum);
695     snap->setInertiaTensor(inertiaTensor);
696     }
697    
698     angularMomentum = snap->getCOMw();
699     inertiaTensor = snap->getInertiaTensor();
700    
701     return;
702     }
703    
704 gezelter 1866
705     Mat3x3d Thermo::getBoundingBox(){
706    
707     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
708    
709     if (!(snap->hasBoundingBox)) {
710    
711     SimInfo::MoleculeIterator i;
712     Molecule::RigidBodyIterator ri;
713     Molecule::AtomIterator ai;
714     Molecule* mol;
715     RigidBody* rb;
716     Atom* atom;
717     Vector3d pos, bMax, bMin;
718     int index = 0;
719    
720     for (mol = info_->beginMolecule(i); mol != NULL;
721     mol = info_->nextMolecule(i)) {
722    
723     //change the positions of atoms which belong to the rigidbodies
724     for (rb = mol->beginRigidBody(ri); rb != NULL;
725     rb = mol->nextRigidBody(ri)) {
726     rb->updateAtoms();
727     }
728    
729     for(atom = mol->beginAtom(ai); atom != NULL;
730     atom = mol->nextAtom(ai)) {
731    
732     pos = atom->getPos();
733    
734     if (index == 0) {
735     bMax = pos;
736     bMin = pos;
737     } else {
738     for (int i = 0; i < 3; i++) {
739     bMax[i] = max(bMax[i], pos[i]);
740     bMin[i] = min(bMin[i], pos[i]);
741     }
742     }
743     index++;
744     }
745     }
746    
747     #ifdef IS_MPI
748     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &bMax[0], 3, MPI::REALTYPE,
749     MPI::MAX);
750    
751     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &bMin[0], 3, MPI::REALTYPE,
752     MPI::MIN);
753     #endif
754     Mat3x3d bBox = Mat3x3d(0.0);
755     for (int i = 0; i < 3; i++) {
756     bBox(i,i) = bMax[i] - bMin[i];
757     }
758     snap->setBoundingBox(bBox);
759     }
760    
761     return snap->getBoundingBox();
762     }
763    
764    
765 gezelter 1764 // Returns the angular momentum of the system
766     Vector3d Thermo::getAngularMomentum(){
767     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
768    
769     if (!snap->hasCOMw) {
770    
771     Vector3d com(0.0);
772     Vector3d comVel(0.0);
773     Vector3d angularMomentum(0.0);
774    
775     getComAll(com, comVel);
776    
777     SimInfo::MoleculeIterator i;
778     Molecule* mol;
779    
780     Vector3d thisr(0.0);
781     Vector3d thisp(0.0);
782    
783     RealType thisMass;
784    
785     for (mol = info_->beginMolecule(i); mol != NULL;
786     mol = info_->nextMolecule(i)) {
787     thisMass = mol->getMass();
788     thisr = mol->getCom() - com;
789     thisp = (mol->getComVel() - comVel) * thisMass;
790    
791     angularMomentum += cross( thisr, thisp );
792     }
793    
794     #ifdef IS_MPI
795     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE,
796     angularMomentum.getArrayPointer(), 3,
797     MPI::REALTYPE, MPI::SUM);
798     #endif
799    
800     snap->setCOMw(angularMomentum);
801     }
802    
803     return snap->getCOMw();
804     }
805    
806    
807     /**
808     * Returns the Volume of the system based on a ellipsoid with
809     * semi-axes based on the radius of gyration V=4/3*Pi*R_1*R_2*R_3
810     * where R_i are related to the principle inertia moments
811     * R_i = sqrt(C*I_i/N), this reduces to
812     * V = 4/3*Pi*(C/N)^3/2*sqrt(det(I)).
813     * See S.E. Baltazar et. al. Comp. Mat. Sci. 37 (2006) 526-536.
814     */
815     RealType Thermo::getGyrationalVolume(){
816     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
817    
818     if (!snap->hasGyrationalVolume) {
819    
820     Mat3x3d intTensor;
821     RealType det;
822     Vector3d dummyAngMom;
823     RealType sysconstants;
824     RealType geomCnst;
825     RealType volume;
826    
827     geomCnst = 3.0/2.0;
828     /* Get the inertial tensor and angular momentum for free*/
829     getInertiaTensor(intTensor, dummyAngMom);
830    
831     det = intTensor.determinant();
832     sysconstants = geomCnst / (RealType)(info_->getNGlobalIntegrableObjects());
833     volume = 4.0/3.0*NumericConstant::PI*pow(sysconstants,geomCnst)*sqrt(det);
834    
835     snap->setGyrationalVolume(volume);
836     }
837     return snap->getGyrationalVolume();
838     }
839    
840     void Thermo::getGyrationalVolume(RealType &volume, RealType &detI){
841     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
842    
843     if (!(snap->hasInertiaTensor && snap->hasGyrationalVolume)) {
844    
845     Mat3x3d intTensor;
846     Vector3d dummyAngMom;
847     RealType sysconstants;
848     RealType geomCnst;
849    
850     geomCnst = 3.0/2.0;
851     /* Get the inertia tensor and angular momentum for free*/
852     this->getInertiaTensor(intTensor, dummyAngMom);
853    
854     detI = intTensor.determinant();
855     sysconstants = geomCnst/(RealType)(info_->getNGlobalIntegrableObjects());
856     volume = 4.0/3.0*NumericConstant::PI*pow(sysconstants,geomCnst)*sqrt(detI);
857     snap->setGyrationalVolume(volume);
858     } else {
859     volume = snap->getGyrationalVolume();
860     detI = snap->getInertiaTensor().determinant();
861     }
862     return;
863     }
864    
865     RealType Thermo::getTaggedAtomPairDistance(){
866     Snapshot* currSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
867     Globals* simParams = info_->getSimParams();
868    
869     if (simParams->haveTaggedAtomPair() &&
870     simParams->havePrintTaggedPairDistance()) {
871     if ( simParams->getPrintTaggedPairDistance()) {
872    
873     pair<int, int> tap = simParams->getTaggedAtomPair();
874     Vector3d pos1, pos2, rab;
875    
876     #ifdef IS_MPI
877     int mol1 = info_->getGlobalMolMembership(tap.first);
878     int mol2 = info_->getGlobalMolMembership(tap.second);
879    
880     int proc1 = info_->getMolToProc(mol1);
881     int proc2 = info_->getMolToProc(mol2);
882    
883     RealType data[3];
884     if (proc1 == worldRank) {
885     StuntDouble* sd1 = info_->getIOIndexToIntegrableObject(tap.first);
886     pos1 = sd1->getPos();
887     data[0] = pos1.x();
888     data[1] = pos1.y();
889     data[2] = pos1.z();
890 gezelter 1798 MPI::COMM_WORLD.Bcast(data, 3, MPI::REALTYPE, proc1);
891 gezelter 1764 } else {
892 gezelter 1798 MPI::COMM_WORLD.Bcast(data, 3, MPI::REALTYPE, proc1);
893 gezelter 1764 pos1 = Vector3d(data);
894     }
895    
896     if (proc2 == worldRank) {
897     StuntDouble* sd2 = info_->getIOIndexToIntegrableObject(tap.second);
898     pos2 = sd2->getPos();
899     data[0] = pos2.x();
900     data[1] = pos2.y();
901 gezelter 1798 data[2] = pos2.z();
902     MPI::COMM_WORLD.Bcast(data, 3, MPI::REALTYPE, proc2);
903 gezelter 1764 } else {
904 gezelter 1798 MPI::COMM_WORLD.Bcast(data, 3, MPI::REALTYPE, proc2);
905 gezelter 1764 pos2 = Vector3d(data);
906     }
907     #else
908     StuntDouble* at1 = info_->getIOIndexToIntegrableObject(tap.first);
909     StuntDouble* at2 = info_->getIOIndexToIntegrableObject(tap.second);
910     pos1 = at1->getPos();
911     pos2 = at2->getPos();
912     #endif
913     rab = pos2 - pos1;
914     currSnapshot->wrapVector(rab);
915     return rab.length();
916     }
917     return 0.0;
918     }
919     return 0.0;
920     }
921    
922     RealType Thermo::getHullVolume(){
923 gezelter 1874 #ifdef HAVE_QHULL
924 gezelter 1764 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
925     if (!snap->hasHullVolume) {
926     Hull* surfaceMesh_;
927 gezelter 1874
928 gezelter 1764 Globals* simParams = info_->getSimParams();
929     const std::string ht = simParams->getHULL_Method();
930    
931     if (ht == "Convex") {
932     surfaceMesh_ = new ConvexHull();
933     } else if (ht == "AlphaShape") {
934     surfaceMesh_ = new AlphaHull(simParams->getAlpha());
935     } else {
936     return 0.0;
937     }
938    
939     // Build a vector of stunt doubles to determine if they are
940     // surface atoms
941     std::vector<StuntDouble*> localSites_;
942     Molecule* mol;
943     StuntDouble* sd;
944     SimInfo::MoleculeIterator i;
945     Molecule::IntegrableObjectIterator j;
946    
947     for (mol = info_->beginMolecule(i); mol != NULL;
948     mol = info_->nextMolecule(i)) {
949     for (sd = mol->beginIntegrableObject(j);
950     sd != NULL;
951     sd = mol->nextIntegrableObject(j)) {
952     localSites_.push_back(sd);
953     }
954     }
955    
956     // Compute surface Mesh
957     surfaceMesh_->computeHull(localSites_);
958     snap->setHullVolume(surfaceMesh_->getVolume());
959 gezelter 1874
960 gezelter 1867 delete surfaceMesh_;
961 gezelter 1764 }
962 gezelter 1874
963 gezelter 1764 return snap->getHullVolume();
964 gezelter 1767 #else
965     return 0.0;
966     #endif
967     }
968 gezelter 1866
969    
970 gezelter 1764 }

Properties

Name Value
svn:keywords Author Id Revision Date