ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/Thermo.cpp
Revision: 614
Committed: Tue Jul 15 17:57:04 2003 UTC (20 years, 11 months ago) by mmeineke
File size: 7609 byte(s)
Log Message:
fixed some bugs, Changed entry_plug to info where appropriate

File Contents

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