ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/brains/Thermo.cpp
Revision: 1782
Committed: Wed Aug 22 02:28:28 2012 UTC (12 years, 8 months ago) by gezelter
File size: 27984 byte(s)
Log Message:
MERGE OpenMD development branch 1465:1781 into trunk

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 gezelter 1782 *
36     * [1] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
37     * [2] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
38     * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 24107 (2008).
39     * [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 gezelter 1782
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 1782 #include "types/FixedChargeAdapter.hpp"
55     #include "types/FluctuatingChargeAdapter.hpp"
56     #include "types/MultipoleAdapter.hpp"
57     #ifdef HAVE_QHULL
58     #include "math/ConvexHull.hpp"
59     #include "math/AlphaHull.hpp"
60     #endif
61 gezelter 2
62 gezelter 1782 using namespace std;
63 gezelter 1390 namespace OpenMD {
64 gezelter 2
65 gezelter 1782 RealType Thermo::getTranslationalKinetic() {
66     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
67 chuckv 1666
68 gezelter 1782 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    
80     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 gezelter 2
104 gezelter 1782 RealType Thermo::getRotationalKinetic() {
105     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
106 chuckv 1666
107 gezelter 1782 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    
120     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    
127     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     }
141    
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     }
151     return snap->getRotationalKineticEnergy();
152     }
153 chuckv 1666
154 gezelter 1782
155 chuckv 1666
156 gezelter 1782 RealType Thermo::getKinetic() {
157     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
158    
159     if (!snap->hasKineticEnergy) {
160     RealType ke = getTranslationalKinetic() + getRotationalKinetic();
161     snap->setKineticEnergy(ke);
162 chuckv 1666 }
163 gezelter 1782 return snap->getKineticEnergy();
164 chuckv 1666 }
165    
166 gezelter 1782 RealType Thermo::getPotential() {
167 chuckv 1666
168 gezelter 1782 // ForceManager computes the potential and stores it in the
169     // Snapshot. All we have to do is report it.
170 gezelter 2
171 gezelter 1782 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
172     return snap->getPotentialEnergy();
173     }
174 gezelter 2
175 gezelter 1782 RealType Thermo::getTotalEnergy() {
176 gezelter 2
177 gezelter 1782 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
178 gezelter 2
179 gezelter 1782 if (!snap->hasTotalEnergy) {
180     snap->setTotalEnergy(this->getKinetic() + this->getPotential());
181     }
182    
183     return snap->getTotalEnergy();
184 gezelter 507 }
185 gezelter 2
186 gezelter 1782 RealType Thermo::getTemperature() {
187 gezelter 2
188 gezelter 1782 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
189 gezelter 2
190 gezelter 1782 if (!snap->hasTemperature) {
191 gezelter 2
192 gezelter 1782 RealType temperature = ( 2.0 * this->getKinetic() )
193     / (info_->getNdf()* PhysicalConstants::kb );
194 gezelter 2
195 gezelter 1782 snap->setTemperature(temperature);
196     }
197    
198     return snap->getTemperature();
199     }
200 gezelter 2
201 gezelter 1782 RealType Thermo::getElectronicTemperature() {
202     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
203 gezelter 2
204 gezelter 1782 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    
218     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     }
228    
229     #ifdef IS_MPI
230     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &kinetic, 1, MPI::REALTYPE,
231     MPI::SUM);
232     #endif
233 gezelter 2
234 gezelter 1782 kinetic *= 0.5;
235     eTemp = (2.0 * kinetic) /
236     (info_->getNFluctuatingCharges() * PhysicalConstants::kb );
237    
238     snap->setElectronicTemperature(eTemp);
239     }
240    
241     return snap->getElectronicTemperature();
242 gezelter 507 }
243 gezelter 2
244    
245 gezelter 1782 RealType Thermo::getVolume() {
246     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
247     return snap->getVolume();
248 gezelter 507 }
249 gezelter 2
250 gezelter 1782 RealType Thermo::getPressure() {
251     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
252 chuckv 1666
253 gezelter 1782 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 1782 Mat3x3d Thermo::getPressureTensor() {
271     // 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     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
275    
276     if (!snap->hasPressureTensor) {
277    
278     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     }
298    
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     }
312     return snap->getPressureTensor();
313 gezelter 507 }
314 gezelter 2
315    
316    
317    
318 gezelter 1782 Vector3d Thermo::getSystemDipole() {
319     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
320 gezelter 2
321 gezelter 1782 if (!snap->hasSystemDipole) {
322     SimInfo::MoleculeIterator miter;
323     vector<Atom*>::iterator aiter;
324     Molecule* mol;
325     Atom* atom;
326     RealType charge;
327     RealType moment(0.0);
328     Vector3d ri(0.0);
329     Vector3d dipoleVector(0.0);
330     Vector3d nPos(0.0);
331     Vector3d pPos(0.0);
332     RealType nChg(0.0);
333     RealType pChg(0.0);
334     int nCount = 0;
335     int pCount = 0;
336    
337     RealType chargeToC = 1.60217733e-19;
338     RealType angstromToM = 1.0e-10;
339     RealType debyeToCm = 3.33564095198e-30;
340    
341     for (mol = info_->beginMolecule(miter); mol != NULL;
342     mol = info_->nextMolecule(miter)) {
343    
344     for (atom = mol->beginAtom(aiter); atom != NULL;
345     atom = mol->nextAtom(aiter)) {
346    
347     charge = 0.0;
348    
349     FixedChargeAdapter fca = FixedChargeAdapter(atom->getAtomType());
350     if ( fca.isFixedCharge() ) {
351     charge = fca.getCharge();
352     }
353    
354     FluctuatingChargeAdapter fqa = FluctuatingChargeAdapter(atom->getAtomType());
355     if ( fqa.isFluctuatingCharge() ) {
356     charge += atom->getFlucQPos();
357     }
358    
359     charge *= chargeToC;
360    
361     ri = atom->getPos();
362     snap->wrapVector(ri);
363     ri *= angstromToM;
364    
365     if (charge < 0.0) {
366     nPos += ri;
367     nChg -= charge;
368     nCount++;
369     } else if (charge > 0.0) {
370     pPos += ri;
371     pChg += charge;
372     pCount++;
373     }
374    
375     MultipoleAdapter ma = MultipoleAdapter(atom->getAtomType());
376     if (ma.isDipole() ) {
377     Vector3d u_i = atom->getElectroFrame().getColumn(2);
378     moment = ma.getDipoleMoment();
379     moment *= debyeToCm;
380     dipoleVector += u_i * moment;
381     }
382     }
383     }
384    
385    
386     #ifdef IS_MPI
387     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &pChg, 1, MPI::REALTYPE,
388     MPI::SUM);
389     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &nChg, 1, MPI::REALTYPE,
390     MPI::SUM);
391 gezelter 2
392 gezelter 1782 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &pCount, 1, MPI::INTEGER,
393     MPI::SUM);
394     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &nCount, 1, MPI::INTEGER,
395     MPI::SUM);
396 gezelter 2
397 gezelter 1782 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, pPos.getArrayPointer(), 3,
398     MPI::REALTYPE, MPI::SUM);
399     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, nPos.getArrayPointer(), 3,
400     MPI::REALTYPE, MPI::SUM);
401 gezelter 2
402 gezelter 1782 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, dipoleVector.getArrayPointer(),
403     3, MPI::REALTYPE, MPI::SUM);
404     #endif
405    
406     // first load the accumulated dipole moment (if dipoles were present)
407     Vector3d boxDipole = dipoleVector;
408     // now include the dipole moment due to charges
409     // use the lesser of the positive and negative charge totals
410     RealType chg_value = nChg <= pChg ? nChg : pChg;
411    
412     // find the average positions
413     if (pCount > 0 && nCount > 0 ) {
414     pPos /= pCount;
415     nPos /= nCount;
416     }
417    
418     // dipole is from the negative to the positive (physics notation)
419     boxDipole += (pPos - nPos) * chg_value;
420     snap->setSystemDipole(boxDipole);
421     }
422 tim 538
423 gezelter 1782 return snap->getSystemDipole();
424     }
425 tim 538
426 gezelter 1782 // Returns the Heat Flux Vector for the system
427     Vector3d Thermo::getHeatFlux(){
428     Snapshot* currSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
429     SimInfo::MoleculeIterator miter;
430     vector<StuntDouble*>::iterator iiter;
431     Molecule* mol;
432     StuntDouble* sd;
433     RigidBody::AtomIterator ai;
434     Atom* atom;
435     Vector3d vel;
436     Vector3d angMom;
437     Mat3x3d I;
438     int i;
439     int j;
440     int k;
441     RealType mass;
442 chuckv 1666
443 gezelter 1782 Vector3d x_a;
444     RealType kinetic;
445     RealType potential;
446     RealType eatom;
447     RealType AvgE_a_ = 0;
448     // Convective portion of the heat flux
449     Vector3d heatFluxJc = V3Zero;
450 tim 538
451 gezelter 1782 /* Calculate convective portion of the heat flux */
452     for (mol = info_->beginMolecule(miter); mol != NULL;
453     mol = info_->nextMolecule(miter)) {
454    
455     for (sd = mol->beginIntegrableObject(iiter);
456     sd != NULL;
457     sd = mol->nextIntegrableObject(iiter)) {
458    
459     mass = sd->getMass();
460     vel = sd->getVel();
461 tim 538
462 gezelter 1782 kinetic = mass * (vel[0]*vel[0] + vel[1]*vel[1] + vel[2]*vel[2]);
463    
464     if (sd->isDirectional()) {
465     angMom = sd->getJ();
466     I = sd->getI();
467 tim 538
468 gezelter 1782 if (sd->isLinear()) {
469     i = sd->linearAxis();
470     j = (i + 1) % 3;
471     k = (i + 2) % 3;
472     kinetic += angMom[j] * angMom[j] / I(j, j)
473     + angMom[k] * angMom[k] / I(k, k);
474     } else {
475     kinetic += angMom[0]*angMom[0]/I(0, 0)
476     + angMom[1]*angMom[1]/I(1, 1)
477     + angMom[2]*angMom[2]/I(2, 2);
478     }
479     }
480 tim 538
481 gezelter 1782 potential = 0.0;
482 gezelter 2
483 gezelter 1782 if (sd->isRigidBody()) {
484     RigidBody* rb = dynamic_cast<RigidBody*>(sd);
485     for (atom = rb->beginAtom(ai); atom != NULL;
486     atom = rb->nextAtom(ai)) {
487     potential += atom->getParticlePot();
488     }
489     } else {
490     potential = sd->getParticlePot();
491     }
492 gezelter 2
493 gezelter 1782 potential *= PhysicalConstants::energyConvert; // amu A^2/fs^2
494     // The potential may not be a 1/2 factor
495     eatom = (kinetic + potential)/2.0; // amu A^2/fs^2
496     heatFluxJc[0] += eatom*vel[0]; // amu A^3/fs^3
497     heatFluxJc[1] += eatom*vel[1]; // amu A^3/fs^3
498     heatFluxJc[2] += eatom*vel[2]; // amu A^3/fs^3
499 gezelter 507 }
500 gezelter 246 }
501 chuckv 1666
502 gezelter 1782 /* The J_v vector is reduced in the forceManager so everyone has
503     * the global Jv. Jc is computed over the local atoms and must be
504     * reduced among all processors.
505     */
506 gezelter 2 #ifdef IS_MPI
507 gezelter 1782 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &heatFluxJc[0], 3, MPI::REALTYPE,
508     MPI::SUM);
509     #endif
510    
511     // (kcal/mol * A/fs) * conversion => (amu A^3)/fs^3
512 gezelter 2
513 gezelter 1782 Vector3d heatFluxJv = currSnapshot->getConductiveHeatFlux() *
514     PhysicalConstants::energyConvert;
515    
516     // Correct for the fact the flux is 1/V (Jc + Jv)
517     return (heatFluxJv + heatFluxJc) / this->getVolume(); // amu / fs^3
518     }
519 gezelter 1126
520 chuckv 1666
521 gezelter 1782 Vector3d Thermo::getComVel(){
522     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
523    
524     if (!snap->hasCOMvel) {
525    
526     SimInfo::MoleculeIterator i;
527     Molecule* mol;
528    
529     Vector3d comVel(0.0);
530     RealType totalMass(0.0);
531    
532     for (mol = info_->beginMolecule(i); mol != NULL;
533     mol = info_->nextMolecule(i)) {
534     RealType mass = mol->getMass();
535     totalMass += mass;
536     comVel += mass * mol->getComVel();
537     }
538    
539     #ifdef IS_MPI
540     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &totalMass, 1, MPI::REALTYPE,
541     MPI::SUM);
542     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, comVel.getArrayPointer(), 3,
543     MPI::REALTYPE, MPI::SUM);
544     #endif
545    
546     comVel /= totalMass;
547     snap->setCOMvel(comVel);
548     }
549     return snap->getCOMvel();
550 gezelter 507 }
551 gezelter 2
552 gezelter 1782 Vector3d Thermo::getCom(){
553     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
554 chrisfen 998
555 gezelter 1782 if (!snap->hasCOM) {
556    
557     SimInfo::MoleculeIterator i;
558     Molecule* mol;
559    
560     Vector3d com(0.0);
561     RealType totalMass(0.0);
562    
563     for (mol = info_->beginMolecule(i); mol != NULL;
564     mol = info_->nextMolecule(i)) {
565     RealType mass = mol->getMass();
566     totalMass += mass;
567     com += mass * mol->getCom();
568     }
569    
570     #ifdef IS_MPI
571     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &totalMass, 1, MPI::REALTYPE,
572     MPI::SUM);
573     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, com.getArrayPointer(), 3,
574     MPI::REALTYPE, MPI::SUM);
575     #endif
576    
577     com /= totalMass;
578     snap->setCOM(com);
579     }
580     return snap->getCOM();
581     }
582 chuckv 1666
583 gezelter 1782 /**
584     * Returns center of mass and center of mass velocity in one
585     * function call.
586     */
587     void Thermo::getComAll(Vector3d &com, Vector3d &comVel){
588     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
589 gezelter 2
590 gezelter 1782 if (!(snap->hasCOM && snap->hasCOMvel)) {
591 tim 541
592 gezelter 1782 SimInfo::MoleculeIterator i;
593     Molecule* mol;
594    
595     RealType totalMass(0.0);
596    
597     com = 0.0;
598     comVel = 0.0;
599    
600     for (mol = info_->beginMolecule(i); mol != NULL;
601     mol = info_->nextMolecule(i)) {
602     RealType mass = mol->getMass();
603     totalMass += mass;
604     com += mass * mol->getCom();
605     comVel += mass * mol->getComVel();
606     }
607    
608     #ifdef IS_MPI
609     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &totalMass, 1, MPI::REALTYPE,
610     MPI::SUM);
611     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, com.getArrayPointer(), 3,
612     MPI::REALTYPE, MPI::SUM);
613     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, comVel.getArrayPointer(), 3,
614     MPI::REALTYPE, MPI::SUM);
615     #endif
616    
617     com /= totalMass;
618     comVel /= totalMass;
619     snap->setCOM(com);
620     snap->setCOMvel(comVel);
621     }
622     com = snap->getCOM();
623     comVel = snap->getCOMvel();
624     return;
625     }
626    
627     /**
628     * Return intertia tensor for entire system and angular momentum
629     * Vector.
630     *
631     *
632     *
633     * [ Ixx -Ixy -Ixz ]
634     * I =| -Iyx Iyy -Iyz |
635     * [ -Izx -Iyz Izz ]
636     */
637     void Thermo::getInertiaTensor(Mat3x3d &inertiaTensor,
638     Vector3d &angularMomentum){
639    
640     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
641    
642     if (!(snap->hasInertiaTensor && snap->hasCOMw)) {
643    
644     RealType xx = 0.0;
645     RealType yy = 0.0;
646     RealType zz = 0.0;
647     RealType xy = 0.0;
648     RealType xz = 0.0;
649     RealType yz = 0.0;
650     Vector3d com(0.0);
651     Vector3d comVel(0.0);
652    
653     getComAll(com, comVel);
654    
655     SimInfo::MoleculeIterator i;
656     Molecule* mol;
657    
658     Vector3d thisq(0.0);
659     Vector3d thisv(0.0);
660    
661     RealType thisMass = 0.0;
662    
663     for (mol = info_->beginMolecule(i); mol != NULL;
664     mol = info_->nextMolecule(i)) {
665    
666     thisq = mol->getCom()-com;
667     thisv = mol->getComVel()-comVel;
668     thisMass = mol->getMass();
669     // Compute moment of intertia coefficients.
670     xx += thisq[0]*thisq[0]*thisMass;
671     yy += thisq[1]*thisq[1]*thisMass;
672     zz += thisq[2]*thisq[2]*thisMass;
673    
674     // compute products of intertia
675     xy += thisq[0]*thisq[1]*thisMass;
676     xz += thisq[0]*thisq[2]*thisMass;
677     yz += thisq[1]*thisq[2]*thisMass;
678    
679     angularMomentum += cross( thisq, thisv ) * thisMass;
680     }
681    
682     inertiaTensor(0,0) = yy + zz;
683     inertiaTensor(0,1) = -xy;
684     inertiaTensor(0,2) = -xz;
685     inertiaTensor(1,0) = -xy;
686     inertiaTensor(1,1) = xx + zz;
687     inertiaTensor(1,2) = -yz;
688     inertiaTensor(2,0) = -xz;
689     inertiaTensor(2,1) = -yz;
690     inertiaTensor(2,2) = xx + yy;
691    
692     #ifdef IS_MPI
693     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, inertiaTensor.getArrayPointer(),
694     9, MPI::REALTYPE, MPI::SUM);
695     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE,
696     angularMomentum.getArrayPointer(), 3,
697     MPI::REALTYPE, MPI::SUM);
698     #endif
699    
700     snap->setCOMw(angularMomentum);
701     snap->setInertiaTensor(inertiaTensor);
702     }
703    
704     angularMomentum = snap->getCOMw();
705     inertiaTensor = snap->getInertiaTensor();
706    
707     return;
708     }
709    
710     // Returns the angular momentum of the system
711     Vector3d Thermo::getAngularMomentum(){
712     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
713    
714     if (!snap->hasCOMw) {
715    
716     Vector3d com(0.0);
717     Vector3d comVel(0.0);
718     Vector3d angularMomentum(0.0);
719    
720     getComAll(com, comVel);
721    
722     SimInfo::MoleculeIterator i;
723     Molecule* mol;
724    
725     Vector3d thisr(0.0);
726     Vector3d thisp(0.0);
727    
728     RealType thisMass;
729    
730     for (mol = info_->beginMolecule(i); mol != NULL;
731     mol = info_->nextMolecule(i)) {
732     thisMass = mol->getMass();
733     thisr = mol->getCom() - com;
734     thisp = (mol->getComVel() - comVel) * thisMass;
735    
736     angularMomentum += cross( thisr, thisp );
737     }
738    
739     #ifdef IS_MPI
740     MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE,
741     angularMomentum.getArrayPointer(), 3,
742     MPI::REALTYPE, MPI::SUM);
743     #endif
744    
745     snap->setCOMw(angularMomentum);
746     }
747    
748     return snap->getCOMw();
749     }
750    
751    
752     /**
753     * Returns the Volume of the system based on a ellipsoid with
754     * semi-axes based on the radius of gyration V=4/3*Pi*R_1*R_2*R_3
755     * where R_i are related to the principle inertia moments
756     * R_i = sqrt(C*I_i/N), this reduces to
757     * V = 4/3*Pi*(C/N)^3/2*sqrt(det(I)).
758     * See S.E. Baltazar et. al. Comp. Mat. Sci. 37 (2006) 526-536.
759     */
760     RealType Thermo::getGyrationalVolume(){
761     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
762    
763     if (!snap->hasGyrationalVolume) {
764    
765     Mat3x3d intTensor;
766     RealType det;
767     Vector3d dummyAngMom;
768     RealType sysconstants;
769     RealType geomCnst;
770     RealType volume;
771    
772     geomCnst = 3.0/2.0;
773     /* Get the inertial tensor and angular momentum for free*/
774     getInertiaTensor(intTensor, dummyAngMom);
775    
776     det = intTensor.determinant();
777     sysconstants = geomCnst / (RealType)(info_->getNGlobalIntegrableObjects());
778     volume = 4.0/3.0*NumericConstant::PI*pow(sysconstants,geomCnst)*sqrt(det);
779    
780     snap->setGyrationalVolume(volume);
781     }
782     return snap->getGyrationalVolume();
783     }
784    
785     void Thermo::getGyrationalVolume(RealType &volume, RealType &detI){
786     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
787    
788     if (!(snap->hasInertiaTensor && snap->hasGyrationalVolume)) {
789    
790     Mat3x3d intTensor;
791     Vector3d dummyAngMom;
792     RealType sysconstants;
793     RealType geomCnst;
794    
795     geomCnst = 3.0/2.0;
796     /* Get the inertia tensor and angular momentum for free*/
797     this->getInertiaTensor(intTensor, dummyAngMom);
798    
799     detI = intTensor.determinant();
800     sysconstants = geomCnst/(RealType)(info_->getNGlobalIntegrableObjects());
801     volume = 4.0/3.0*NumericConstant::PI*pow(sysconstants,geomCnst)*sqrt(detI);
802     snap->setGyrationalVolume(volume);
803     } else {
804     volume = snap->getGyrationalVolume();
805     detI = snap->getInertiaTensor().determinant();
806     }
807     return;
808     }
809    
810     RealType Thermo::getTaggedAtomPairDistance(){
811     Snapshot* currSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
812 gezelter 1291 Globals* simParams = info_->getSimParams();
813 gezelter 1782
814     if (simParams->haveTaggedAtomPair() &&
815 gezelter 1291 simParams->havePrintTaggedPairDistance()) {
816     if ( simParams->getPrintTaggedPairDistance()) {
817 gezelter 1782
818     pair<int, int> tap = simParams->getTaggedAtomPair();
819 gezelter 1291 Vector3d pos1, pos2, rab;
820 gezelter 1782
821     #ifdef IS_MPI
822     int mol1 = info_->getGlobalMolMembership(tap.first);
823     int mol2 = info_->getGlobalMolMembership(tap.second);
824 gezelter 1291
825     int proc1 = info_->getMolToProc(mol1);
826     int proc2 = info_->getMolToProc(mol2);
827    
828 gezelter 1782 RealType data[3];
829 gezelter 1291 if (proc1 == worldRank) {
830     StuntDouble* sd1 = info_->getIOIndexToIntegrableObject(tap.first);
831     pos1 = sd1->getPos();
832     data[0] = pos1.x();
833     data[1] = pos1.y();
834 gezelter 1782 data[2] = pos1.z();
835 gezelter 1291 MPI_Bcast(data, 3, MPI_REALTYPE, proc1, MPI_COMM_WORLD);
836     } else {
837     MPI_Bcast(data, 3, MPI_REALTYPE, proc1, MPI_COMM_WORLD);
838     pos1 = Vector3d(data);
839     }
840 chuckv 1292
841 gezelter 1291 if (proc2 == worldRank) {
842     StuntDouble* sd2 = info_->getIOIndexToIntegrableObject(tap.second);
843     pos2 = sd2->getPos();
844     data[0] = pos2.x();
845     data[1] = pos2.y();
846 gezelter 1782 data[2] = pos2.z();
847 gezelter 1291 MPI_Bcast(data, 3, MPI_REALTYPE, proc2, MPI_COMM_WORLD);
848     } else {
849     MPI_Bcast(data, 3, MPI_REALTYPE, proc2, MPI_COMM_WORLD);
850     pos2 = Vector3d(data);
851     }
852     #else
853     StuntDouble* at1 = info_->getIOIndexToIntegrableObject(tap.first);
854     StuntDouble* at2 = info_->getIOIndexToIntegrableObject(tap.second);
855     pos1 = at1->getPos();
856     pos2 = at2->getPos();
857 gezelter 1782 #endif
858 gezelter 1291 rab = pos2 - pos1;
859     currSnapshot->wrapVector(rab);
860 gezelter 1782 return rab.length();
861 gezelter 1291 }
862 gezelter 1782 return 0.0;
863 gezelter 1291 }
864 gezelter 1782 return 0.0;
865 gezelter 507 }
866 gezelter 2
867 gezelter 1782 RealType Thermo::getHullVolume(){
868     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
869 jmichalk 1604
870 gezelter 1782 #ifdef HAVE_QHULL
871     if (!snap->hasHullVolume) {
872     Hull* surfaceMesh_;
873 jmichalk 1604
874 gezelter 1782 Globals* simParams = info_->getSimParams();
875     const std::string ht = simParams->getHULL_Method();
876    
877     if (ht == "Convex") {
878     surfaceMesh_ = new ConvexHull();
879     } else if (ht == "AlphaShape") {
880     surfaceMesh_ = new AlphaHull(simParams->getAlpha());
881     } else {
882     return 0.0;
883     }
884    
885     // Build a vector of stunt doubles to determine if they are
886     // surface atoms
887     std::vector<StuntDouble*> localSites_;
888     Molecule* mol;
889     StuntDouble* sd;
890     SimInfo::MoleculeIterator i;
891     Molecule::IntegrableObjectIterator j;
892    
893     for (mol = info_->beginMolecule(i); mol != NULL;
894     mol = info_->nextMolecule(i)) {
895     for (sd = mol->beginIntegrableObject(j);
896     sd != NULL;
897     sd = mol->nextIntegrableObject(j)) {
898     localSites_.push_back(sd);
899 jmichalk 1604 }
900 gezelter 1782 }
901    
902     // Compute surface Mesh
903     surfaceMesh_->computeHull(localSites_);
904     snap->setHullVolume(surfaceMesh_->getVolume());
905 jmichalk 1604 }
906 gezelter 1782 return snap->getHullVolume();
907 chuckv 1666 #else
908 gezelter 1782 return 0.0;
909 chuckv 1638 #endif
910 gezelter 1782 }
911     }

Properties

Name Value
svn:keywords Author Id Revision Date