ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/Thermo.cpp
Revision: 1113
Committed: Thu Apr 15 16:18:26 2004 UTC (20 years, 5 months ago) by tim
File size: 8842 byte(s)
Log Message:
fix whole bunch of bugs :-)

File Contents

# User Rev Content
1 gezelter 829 #include <math.h>
2 mmeineke 377 #include <iostream>
3     using namespace std;
4    
5     #ifdef IS_MPI
6     #include <mpi.h>
7     #endif //is_mpi
8    
9     #include "Thermo.hpp"
10     #include "SRI.hpp"
11     #include "Integrator.hpp"
12 chuckv 438 #include "simError.h"
13 mmeineke 402
14     #ifdef IS_MPI
15 chuckv 401 #define __C
16 mmeineke 402 #include "mpiSimulation.hpp"
17     #endif // is_mpi
18 mmeineke 377
19 mmeineke 614 Thermo::Thermo( SimInfo* the_info ) {
20     info = the_info;
21 tim 708 int baseSeed = the_info->getSeed();
22 mmeineke 377
23     gaussStream = new gaussianSPRNG( baseSeed );
24     }
25    
26     Thermo::~Thermo(){
27     delete gaussStream;
28     }
29    
30     double Thermo::getKinetic(){
31    
32     const double e_convert = 4.184E-4; // convert kcal/mol -> (amu A^2)/fs^2
33 gezelter 608 double kinetic;
34     double amass;
35     double aVel[3], aJ[3], I[3][3];
36     int j, kl;
37 mmeineke 377
38     double kinetic_global;
39 tim 1113 vector<StuntDouble *> integrableObjects = info->integrableObjects;
40 mmeineke 377
41     kinetic = 0.0;
42     kinetic_global = 0.0;
43    
44 tim 1113 for (kl=0; kl<integrableObjects.size(); kl++) {
45     integrableObjects[kl]->getVel(aVel);
46     amass = integrableObjects[kl]->getMass();
47 gezelter 608
48 tim 1113 for(j=0; j<3; j++)
49     kinetic += amass*aVel[j]*aVel[j];
50    
51     if (integrableObjects[kl]->isDirectional()){
52    
53     integrableObjects[kl]->getJ( aJ );
54     integrableObjects[kl]->getI( I );
55    
56 gezelter 608 for (j=0; j<3; j++)
57     kinetic += aJ[j]*aJ[j] / I[j][j];
58 mmeineke 377
59     }
60     }
61     #ifdef IS_MPI
62 mmeineke 447 MPI_Allreduce(&kinetic,&kinetic_global,1,MPI_DOUBLE,
63     MPI_SUM, MPI_COMM_WORLD);
64 mmeineke 377 kinetic = kinetic_global;
65     #endif //is_mpi
66    
67     kinetic = kinetic * 0.5 / e_convert;
68    
69     return kinetic;
70     }
71    
72     double Thermo::getPotential(){
73    
74 chuckv 401 double potential_local;
75 mmeineke 377 double potential;
76     int el, nSRI;
77 mmeineke 428 Molecule* molecules;
78 mmeineke 377
79 mmeineke 614 molecules = info->molecules;
80     nSRI = info->n_SRI;
81 mmeineke 377
82 chuckv 401 potential_local = 0.0;
83 chuckv 438 potential = 0.0;
84 mmeineke 614 potential_local += info->lrPot;
85 mmeineke 377
86 mmeineke 614 for( el=0; el<info->n_mol; el++ ){
87 mmeineke 428 potential_local += molecules[el].getPotential();
88 mmeineke 377 }
89    
90     // Get total potential for entire system from MPI.
91     #ifdef IS_MPI
92 mmeineke 447 MPI_Allreduce(&potential_local,&potential,1,MPI_DOUBLE,
93     MPI_SUM, MPI_COMM_WORLD);
94 chuckv 401 #else
95     potential = potential_local;
96 mmeineke 377 #endif // is_mpi
97    
98     return potential;
99     }
100    
101     double Thermo::getTotalE(){
102    
103     double total;
104    
105     total = this->getKinetic() + this->getPotential();
106     return total;
107     }
108    
109 gezelter 454 double Thermo::getTemperature(){
110    
111 tim 763 const double kb = 1.9872156E-3; // boltzman's constant in kcal/(mol K)
112 gezelter 454 double temperature;
113 tim 1113
114 mmeineke 614 temperature = ( 2.0 * this->getKinetic() ) / ((double)info->ndf * kb );
115 mmeineke 377 return temperature;
116     }
117    
118 gezelter 484 double Thermo::getVolume() {
119 gezelter 574
120 mmeineke 614 return info->boxVol;
121 gezelter 484 }
122    
123 gezelter 483 double Thermo::getPressure() {
124 gezelter 574
125 gezelter 483 // Relies on the calculation of the full molecular pressure tensor
126    
127     const double p_convert = 1.63882576e8;
128 gezelter 588 double press[3][3];
129 gezelter 483 double pressure;
130    
131     this->getPressureTensor(press);
132    
133 gezelter 588 pressure = p_convert * (press[0][0] + press[1][1] + press[2][2]) / 3.0;
134 gezelter 483
135     return pressure;
136     }
137    
138 mmeineke 755 double Thermo::getPressureX() {
139 gezelter 483
140 mmeineke 755 // Relies on the calculation of the full molecular pressure tensor
141    
142     const double p_convert = 1.63882576e8;
143     double press[3][3];
144     double pressureX;
145    
146     this->getPressureTensor(press);
147    
148     pressureX = p_convert * press[0][0];
149    
150     return pressureX;
151     }
152    
153     double Thermo::getPressureY() {
154    
155     // Relies on the calculation of the full molecular pressure tensor
156    
157     const double p_convert = 1.63882576e8;
158     double press[3][3];
159     double pressureY;
160    
161     this->getPressureTensor(press);
162    
163     pressureY = p_convert * press[1][1];
164    
165     return pressureY;
166     }
167    
168     double Thermo::getPressureZ() {
169    
170     // Relies on the calculation of the full molecular pressure tensor
171    
172     const double p_convert = 1.63882576e8;
173     double press[3][3];
174     double pressureZ;
175    
176     this->getPressureTensor(press);
177    
178     pressureZ = p_convert * press[2][2];
179    
180     return pressureZ;
181     }
182    
183    
184 gezelter 588 void Thermo::getPressureTensor(double press[3][3]){
185 gezelter 483 // returns pressure tensor in units amu*fs^-2*Ang^-1
186 gezelter 445 // routine derived via viral theorem description in:
187     // Paci, E. and Marchi, M. J.Phys.Chem. 1996, 100, 4314-4322
188 mmeineke 377
189 gezelter 477 const double e_convert = 4.184e-4;
190 gezelter 483
191     double molmass, volume;
192 gezelter 468 double vcom[3];
193 gezelter 483 double p_local[9], p_global[9];
194 mmeineke 614 int i, j, k, nMols;
195 gezelter 468 Molecule* molecules;
196    
197 mmeineke 614 nMols = info->n_mol;
198     molecules = info->molecules;
199     //tau = info->tau;
200 gezelter 468
201     // use velocities of molecular centers of mass and molecular masses:
202 gezelter 483 for (i=0; i < 9; i++) {
203     p_local[i] = 0.0;
204     p_global[i] = 0.0;
205     }
206 gezelter 475
207 gezelter 468 for (i=0; i < nMols; i++) {
208 gezelter 475 molmass = molecules[i].getCOMvel(vcom);
209 gezelter 483
210     p_local[0] += molmass * (vcom[0] * vcom[0]);
211     p_local[1] += molmass * (vcom[0] * vcom[1]);
212     p_local[2] += molmass * (vcom[0] * vcom[2]);
213     p_local[3] += molmass * (vcom[1] * vcom[0]);
214     p_local[4] += molmass * (vcom[1] * vcom[1]);
215     p_local[5] += molmass * (vcom[1] * vcom[2]);
216     p_local[6] += molmass * (vcom[2] * vcom[0]);
217     p_local[7] += molmass * (vcom[2] * vcom[1]);
218     p_local[8] += molmass * (vcom[2] * vcom[2]);
219 gezelter 468 }
220    
221     // Get total for entire system from MPI.
222 chuckv 479
223 gezelter 468 #ifdef IS_MPI
224 gezelter 483 MPI_Allreduce(p_local,p_global,9,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
225 gezelter 468 #else
226 gezelter 483 for (i=0; i<9; i++) {
227     p_global[i] = p_local[i];
228     }
229 gezelter 468 #endif // is_mpi
230    
231 gezelter 611 volume = this->getVolume();
232 gezelter 468
233 gezelter 588 for(i = 0; i < 3; i++) {
234     for (j = 0; j < 3; j++) {
235     k = 3*i + j;
236 mmeineke 614 press[i][j] = (p_global[k] + info->tau[k]*e_convert) / volume;
237    
238 gezelter 588 }
239 gezelter 483 }
240 mmeineke 377 }
241    
242     void Thermo::velocitize() {
243    
244 gezelter 608 double aVel[3], aJ[3], I[3][3];
245     int i, j, vr, vd; // velocity randomizer loop counters
246 chuckv 403 double vdrift[3];
247 mmeineke 377 double vbar;
248     const double kb = 8.31451e-7; // kb in amu, angstroms, fs, etc.
249     double av2;
250     double kebar;
251     int n_atoms;
252     Atom** atoms;
253     DirectionalAtom* dAtom;
254     double temperature;
255     int n_oriented;
256     int n_constraints;
257    
258 mmeineke 614 atoms = info->atoms;
259     n_atoms = info->n_atoms;
260     temperature = info->target_temp;
261     n_oriented = info->n_oriented;
262     n_constraints = info->n_constraints;
263 mmeineke 377
264 tim 763 kebar = kb * temperature * (double)info->ndfRaw /
265     ( 2.0 * (double)info->ndf );
266 chuckv 403
267 mmeineke 377 for(vr = 0; vr < n_atoms; vr++){
268    
269     // uses equipartition theory to solve for vbar in angstrom/fs
270    
271     av2 = 2.0 * kebar / atoms[vr]->getMass();
272     vbar = sqrt( av2 );
273 mmeineke 853
274 mmeineke 377 // picks random velocities from a gaussian distribution
275     // centered on vbar
276    
277 gezelter 608 for (j=0; j<3; j++)
278     aVel[j] = vbar * gaussStream->getGaussian();
279    
280     atoms[vr]->setVel( aVel );
281 mmeineke 377
282     }
283 chuckv 401
284     // Get the Center of Mass drift velocity.
285    
286 chuckv 403 getCOMVel(vdrift);
287 mmeineke 377
288     // Corrects for the center of mass drift.
289     // sums all the momentum and divides by total mass.
290    
291     for(vd = 0; vd < n_atoms; vd++){
292    
293 gezelter 608 atoms[vd]->getVel(aVel);
294    
295     for (j=0; j < 3; j++)
296     aVel[j] -= vdrift[j];
297 chuckv 401
298 gezelter 608 atoms[vd]->setVel( aVel );
299 mmeineke 377 }
300     if( n_oriented ){
301    
302     for( i=0; i<n_atoms; i++ ){
303    
304     if( atoms[i]->isDirectional() ){
305    
306     dAtom = (DirectionalAtom *)atoms[i];
307 gezelter 608 dAtom->getI( I );
308    
309     for (j = 0 ; j < 3; j++) {
310 mmeineke 377
311 gezelter 608 vbar = sqrt( 2.0 * kebar * I[j][j] );
312     aJ[j] = vbar * gaussStream->getGaussian();
313 mmeineke 377
314 gezelter 608 }
315    
316     dAtom->setJ( aJ );
317    
318 mmeineke 377 }
319     }
320     }
321     }
322 chuckv 401
323 chuckv 403 void Thermo::getCOMVel(double vdrift[3]){
324 chuckv 401
325     double mtot, mtot_local;
326 gezelter 608 double aVel[3], amass;
327 chuckv 401 double vdrift_local[3];
328 gezelter 608 int vd, n_atoms, j;
329 chuckv 401 Atom** atoms;
330    
331     // We are very careless here with the distinction between n_atoms and n_local
332     // We should really fix this before someone pokes an eye out.
333    
334 mmeineke 614 n_atoms = info->n_atoms;
335     atoms = info->atoms;
336 chuckv 401
337     mtot_local = 0.0;
338     vdrift_local[0] = 0.0;
339     vdrift_local[1] = 0.0;
340     vdrift_local[2] = 0.0;
341    
342     for(vd = 0; vd < n_atoms; vd++){
343    
344 gezelter 608 amass = atoms[vd]->getMass();
345     atoms[vd]->getVel( aVel );
346    
347     for(j = 0; j < 3; j++)
348     vdrift_local[j] += aVel[j] * amass;
349 chuckv 401
350 gezelter 608 mtot_local += amass;
351 chuckv 401 }
352    
353     #ifdef IS_MPI
354 mmeineke 447 MPI_Allreduce(&mtot_local,&mtot,1,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
355     MPI_Allreduce(vdrift_local,vdrift,3,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
356 chuckv 401 #else
357     mtot = mtot_local;
358     for(vd = 0; vd < 3; vd++) {
359     vdrift[vd] = vdrift_local[vd];
360     }
361     #endif
362    
363     for (vd = 0; vd < 3; vd++) {
364     vdrift[vd] = vdrift[vd] / mtot;
365     }
366    
367     }
368    
369 tim 763 void Thermo::getCOM(double COM[3]){
370    
371     double mtot, mtot_local;
372     double aPos[3], amass;
373     double COM_local[3];
374     int i, n_atoms, j;
375     Atom** atoms;
376    
377     // We are very careless here with the distinction between n_atoms and n_local
378     // We should really fix this before someone pokes an eye out.
379    
380     n_atoms = info->n_atoms;
381     atoms = info->atoms;
382    
383     mtot_local = 0.0;
384     COM_local[0] = 0.0;
385     COM_local[1] = 0.0;
386     COM_local[2] = 0.0;
387    
388     for(i = 0; i < n_atoms; i++){
389    
390     amass = atoms[i]->getMass();
391     atoms[i]->getPos( aPos );
392    
393     for(j = 0; j < 3; j++)
394     COM_local[j] += aPos[j] * amass;
395    
396     mtot_local += amass;
397     }
398    
399     #ifdef IS_MPI
400     MPI_Allreduce(&mtot_local,&mtot,1,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
401     MPI_Allreduce(COM_local,COM,3,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
402     #else
403     mtot = mtot_local;
404     for(i = 0; i < 3; i++) {
405     COM[i] = COM_local[i];
406     }
407     #endif
408    
409     for (i = 0; i < 3; i++) {
410     COM[i] = COM[i] / mtot;
411     }
412     }