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, 2 months ago) by tim
File size: 8842 byte(s)
Log Message:
fix whole bunch of bugs :-)

File Contents

# Content
1 #include <math.h>
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 #include "simError.h"
13
14 #ifdef IS_MPI
15 #define __C
16 #include "mpiSimulation.hpp"
17 #endif // is_mpi
18
19 Thermo::Thermo( SimInfo* the_info ) {
20 info = the_info;
21 int baseSeed = the_info->getSeed();
22
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 double kinetic;
34 double amass;
35 double aVel[3], aJ[3], I[3][3];
36 int j, kl;
37
38 double kinetic_global;
39 vector<StuntDouble *> integrableObjects = info->integrableObjects;
40
41 kinetic = 0.0;
42 kinetic_global = 0.0;
43
44 for (kl=0; kl<integrableObjects.size(); kl++) {
45 integrableObjects[kl]->getVel(aVel);
46 amass = integrableObjects[kl]->getMass();
47
48 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 for (j=0; j<3; j++)
57 kinetic += aJ[j]*aJ[j] / I[j][j];
58
59 }
60 }
61 #ifdef IS_MPI
62 MPI_Allreduce(&kinetic,&kinetic_global,1,MPI_DOUBLE,
63 MPI_SUM, MPI_COMM_WORLD);
64 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 double potential_local;
75 double potential;
76 int el, nSRI;
77 Molecule* molecules;
78
79 molecules = info->molecules;
80 nSRI = info->n_SRI;
81
82 potential_local = 0.0;
83 potential = 0.0;
84 potential_local += info->lrPot;
85
86 for( el=0; el<info->n_mol; el++ ){
87 potential_local += molecules[el].getPotential();
88 }
89
90 // Get total potential for entire system from MPI.
91 #ifdef IS_MPI
92 MPI_Allreduce(&potential_local,&potential,1,MPI_DOUBLE,
93 MPI_SUM, MPI_COMM_WORLD);
94 #else
95 potential = potential_local;
96 #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 double Thermo::getTemperature(){
110
111 const double kb = 1.9872156E-3; // boltzman's constant in kcal/(mol K)
112 double temperature;
113
114 temperature = ( 2.0 * this->getKinetic() ) / ((double)info->ndf * kb );
115 return temperature;
116 }
117
118 double Thermo::getVolume() {
119
120 return info->boxVol;
121 }
122
123 double Thermo::getPressure() {
124
125 // Relies on the calculation of the full molecular pressure tensor
126
127 const double p_convert = 1.63882576e8;
128 double press[3][3];
129 double pressure;
130
131 this->getPressureTensor(press);
132
133 pressure = p_convert * (press[0][0] + press[1][1] + press[2][2]) / 3.0;
134
135 return pressure;
136 }
137
138 double Thermo::getPressureX() {
139
140 // 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 void Thermo::getPressureTensor(double press[3][3]){
185 // returns pressure tensor in units amu*fs^-2*Ang^-1
186 // routine derived via viral theorem description in:
187 // Paci, E. and Marchi, M. J.Phys.Chem. 1996, 100, 4314-4322
188
189 const double e_convert = 4.184e-4;
190
191 double molmass, volume;
192 double vcom[3];
193 double p_local[9], p_global[9];
194 int i, j, k, nMols;
195 Molecule* molecules;
196
197 nMols = info->n_mol;
198 molecules = info->molecules;
199 //tau = info->tau;
200
201 // use velocities of molecular centers of mass and molecular masses:
202 for (i=0; i < 9; i++) {
203 p_local[i] = 0.0;
204 p_global[i] = 0.0;
205 }
206
207 for (i=0; i < nMols; i++) {
208 molmass = molecules[i].getCOMvel(vcom);
209
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 }
220
221 // Get total for entire system from MPI.
222
223 #ifdef IS_MPI
224 MPI_Allreduce(p_local,p_global,9,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
225 #else
226 for (i=0; i<9; i++) {
227 p_global[i] = p_local[i];
228 }
229 #endif // is_mpi
230
231 volume = this->getVolume();
232
233 for(i = 0; i < 3; i++) {
234 for (j = 0; j < 3; j++) {
235 k = 3*i + j;
236 press[i][j] = (p_global[k] + info->tau[k]*e_convert) / volume;
237
238 }
239 }
240 }
241
242 void Thermo::velocitize() {
243
244 double aVel[3], aJ[3], I[3][3];
245 int i, j, vr, vd; // velocity randomizer loop counters
246 double vdrift[3];
247 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 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
264 kebar = kb * temperature * (double)info->ndfRaw /
265 ( 2.0 * (double)info->ndf );
266
267 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
274 // picks random velocities from a gaussian distribution
275 // centered on vbar
276
277 for (j=0; j<3; j++)
278 aVel[j] = vbar * gaussStream->getGaussian();
279
280 atoms[vr]->setVel( aVel );
281
282 }
283
284 // Get the Center of Mass drift velocity.
285
286 getCOMVel(vdrift);
287
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 atoms[vd]->getVel(aVel);
294
295 for (j=0; j < 3; j++)
296 aVel[j] -= vdrift[j];
297
298 atoms[vd]->setVel( aVel );
299 }
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 dAtom->getI( I );
308
309 for (j = 0 ; j < 3; j++) {
310
311 vbar = sqrt( 2.0 * kebar * I[j][j] );
312 aJ[j] = vbar * gaussStream->getGaussian();
313
314 }
315
316 dAtom->setJ( aJ );
317
318 }
319 }
320 }
321 }
322
323 void Thermo::getCOMVel(double vdrift[3]){
324
325 double mtot, mtot_local;
326 double aVel[3], amass;
327 double vdrift_local[3];
328 int vd, n_atoms, j;
329 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 n_atoms = info->n_atoms;
335 atoms = info->atoms;
336
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 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
350 mtot_local += amass;
351 }
352
353 #ifdef IS_MPI
354 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 #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 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 }