ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/Thermo.cpp
Revision: 708
Committed: Wed Aug 20 22:23:34 2003 UTC (20 years, 10 months ago) by tim
File size: 7589 byte(s)
Log Message:
user can setup seed in bass file now, if he does not specify any value for
seed, oopse will take the value of seconds of system time as seed

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