# | Line 1 | Line 1 | |
---|---|---|
1 | < | #include <cmath> |
1 | > | #include <math.h> |
2 | #include <iostream> | |
3 | using namespace std; | |
4 | ||
# | Line 10 | Line 10 | using namespace std; | |
10 | #include "SRI.hpp" | |
11 | #include "Integrator.hpp" | |
12 | #include "simError.h" | |
13 | + | #include "MatVec3.h" |
14 | ||
15 | #ifdef IS_MPI | |
16 | #define __C | |
17 | #include "mpiSimulation.hpp" | |
18 | #endif // is_mpi | |
19 | ||
20 | + | inline double roundMe( double x ){ |
21 | + | return ( x >= 0 ) ? floor( x + 0.5 ) : ceil( x - 0.5 ); |
22 | + | } |
23 | ||
24 | < | #define BASE_SEED 123456789 |
25 | < | |
26 | < | Thermo::Thermo( SimInfo* the_entry_plug ) { |
23 | < | entry_plug = the_entry_plug; |
24 | < | int baseSeed = BASE_SEED; |
24 | > | Thermo::Thermo( SimInfo* the_info ) { |
25 | > | info = the_info; |
26 | > | int baseSeed = the_info->getSeed(); |
27 | ||
28 | gaussStream = new gaussianSPRNG( baseSeed ); | |
29 | } | |
# | Line 36 | Line 38 | double Thermo::getKinetic(){ | |
38 | double kinetic; | |
39 | double amass; | |
40 | double aVel[3], aJ[3], I[3][3]; | |
41 | < | int j, kl; |
41 | > | int i, j, k, kl; |
42 | ||
41 | – | DirectionalAtom *dAtom; |
42 | – | |
43 | – | int n_atoms; |
43 | double kinetic_global; | |
44 | < | Atom** atoms; |
46 | < | |
44 | > | vector<StuntDouble *> integrableObjects = info->integrableObjects; |
45 | ||
48 | – | n_atoms = entry_plug->n_atoms; |
49 | – | atoms = entry_plug->atoms; |
50 | – | |
46 | kinetic = 0.0; | |
47 | kinetic_global = 0.0; | |
53 | – | for( kl=0; kl < n_atoms; kl++ ){ |
54 | – | |
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]; |
48 | ||
49 | < | if( atoms[kl]->isDirectional() ){ |
50 | < | |
51 | < | dAtom = (DirectionalAtom *)atoms[kl]; |
49 | > | for (kl=0; kl<integrableObjects.size(); kl++) { |
50 | > | integrableObjects[kl]->getVel(aVel); |
51 | > | amass = integrableObjects[kl]->getMass(); |
52 | ||
53 | < | dAtom->getJ( aJ ); |
54 | < | dAtom->getI( I ); |
55 | < | |
56 | < | for (j=0; j<3; j++) |
57 | < | kinetic += aJ[j]*aJ[j] / I[j][j]; |
58 | < | |
59 | < | } |
53 | > | for(j=0; j<3; j++) |
54 | > | kinetic += amass*aVel[j]*aVel[j]; |
55 | > | |
56 | > | if (integrableObjects[kl]->isDirectional()){ |
57 | > | |
58 | > | integrableObjects[kl]->getJ( aJ ); |
59 | > | integrableObjects[kl]->getI( I ); |
60 | > | |
61 | > | if (integrableObjects[kl]->isLinear()) { |
62 | > | i = integrableObjects[kl]->linearAxis(); |
63 | > | j = (i+1)%3; |
64 | > | k = (i+2)%3; |
65 | > | kinetic += aJ[j]*aJ[j]/I[j][j] + aJ[k]*aJ[k]/I[k][k]; |
66 | > | } else { |
67 | > | for (j=0; j<3; j++) |
68 | > | kinetic += aJ[j]*aJ[j] / I[j][j]; |
69 | > | } |
70 | > | } |
71 | } | |
72 | #ifdef IS_MPI | |
73 | MPI_Allreduce(&kinetic,&kinetic_global,1,MPI_DOUBLE, | |
74 | MPI_SUM, MPI_COMM_WORLD); | |
75 | kinetic = kinetic_global; | |
76 | #endif //is_mpi | |
77 | < | |
77 | > | |
78 | kinetic = kinetic * 0.5 / e_convert; | |
79 | ||
80 | return kinetic; | |
# | Line 88 | Line 87 | double Thermo::getPotential(){ | |
87 | int el, nSRI; | |
88 | Molecule* molecules; | |
89 | ||
90 | < | molecules = entry_plug->molecules; |
91 | < | nSRI = entry_plug->n_SRI; |
90 | > | molecules = info->molecules; |
91 | > | nSRI = info->n_SRI; |
92 | ||
93 | potential_local = 0.0; | |
94 | potential = 0.0; | |
95 | < | potential_local += entry_plug->lrPot; |
95 | > | potential_local += info->lrPot; |
96 | ||
97 | < | for( el=0; el<entry_plug->n_mol; el++ ){ |
97 | > | for( el=0; el<info->n_mol; el++ ){ |
98 | potential_local += molecules[el].getPotential(); | |
99 | } | |
100 | ||
# | Line 107 | Line 106 | double Thermo::getPotential(){ | |
106 | potential = potential_local; | |
107 | #endif // is_mpi | |
108 | ||
110 | – | #ifdef IS_MPI |
111 | – | /* |
112 | – | std::cerr << "node " << worldRank << ": after pot = " << potential << "\n"; |
113 | – | */ |
114 | – | #endif |
115 | – | |
109 | return potential; | |
110 | } | |
111 | ||
# | Line 126 | Line 119 | double Thermo::getTemperature(){ | |
119 | ||
120 | double Thermo::getTemperature(){ | |
121 | ||
122 | < | const double kb = 1.9872179E-3; // boltzman's constant in kcal/(mol K) |
122 | > | const double kb = 1.9872156E-3; // boltzman's constant in kcal/(mol K) |
123 | double temperature; | |
131 | – | |
132 | – | temperature = ( 2.0 * this->getKinetic() ) / ((double)entry_plug->ndf * kb ); |
133 | – | return temperature; |
134 | – | } |
135 | – | |
136 | – | 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 | – | double press[3][3]; |
141 | – | |
142 | – | u = this->getTotalE(); |
143 | – | |
144 | – | this->getPressureTensor(press); |
145 | – | p = (press[0][0] + press[1][1] + press[2][2]) / 3.0; |
124 | ||
125 | < | v = this->getVolume(); |
126 | < | |
149 | < | return (u + (p*v)/e_convert); |
125 | > | temperature = ( 2.0 * this->getKinetic() ) / ((double)info->ndf * kb ); |
126 | > | return temperature; |
127 | } | |
128 | ||
129 | double Thermo::getVolume() { | |
130 | ||
131 | < | return entry_plug->boxVol; |
131 | > | return info->boxVol; |
132 | } | |
133 | ||
134 | double Thermo::getPressure() { | |
# | Line 169 | Line 146 | double Thermo::getPressure() { | |
146 | return pressure; | |
147 | } | |
148 | ||
149 | + | double Thermo::getPressureX() { |
150 | ||
151 | + | // Relies on the calculation of the full molecular pressure tensor |
152 | + | |
153 | + | const double p_convert = 1.63882576e8; |
154 | + | double press[3][3]; |
155 | + | double pressureX; |
156 | + | |
157 | + | this->getPressureTensor(press); |
158 | + | |
159 | + | pressureX = p_convert * press[0][0]; |
160 | + | |
161 | + | return pressureX; |
162 | + | } |
163 | + | |
164 | + | double Thermo::getPressureY() { |
165 | + | |
166 | + | // Relies on the calculation of the full molecular pressure tensor |
167 | + | |
168 | + | const double p_convert = 1.63882576e8; |
169 | + | double press[3][3]; |
170 | + | double pressureY; |
171 | + | |
172 | + | this->getPressureTensor(press); |
173 | + | |
174 | + | pressureY = p_convert * press[1][1]; |
175 | + | |
176 | + | return pressureY; |
177 | + | } |
178 | + | |
179 | + | double Thermo::getPressureZ() { |
180 | + | |
181 | + | // Relies on the calculation of the full molecular pressure tensor |
182 | + | |
183 | + | const double p_convert = 1.63882576e8; |
184 | + | double press[3][3]; |
185 | + | double pressureZ; |
186 | + | |
187 | + | this->getPressureTensor(press); |
188 | + | |
189 | + | pressureZ = p_convert * press[2][2]; |
190 | + | |
191 | + | return pressureZ; |
192 | + | } |
193 | + | |
194 | + | |
195 | void Thermo::getPressureTensor(double press[3][3]){ | |
196 | // returns pressure tensor in units amu*fs^-2*Ang^-1 | |
197 | // routine derived via viral theorem description in: | |
# | Line 178 | Line 200 | void Thermo::getPressureTensor(double press[3][3]){ | |
200 | const double e_convert = 4.184e-4; | |
201 | ||
202 | double molmass, volume; | |
203 | < | double vcom[3]; |
203 | > | double vcom[3], pcom[3], fcom[3], scaled[3]; |
204 | double p_local[9], p_global[9]; | |
205 | < | int i, j, k, l, nMols; |
205 | > | int i, j, k, nMols; |
206 | Molecule* molecules; | |
207 | ||
208 | < | nMols = entry_plug->n_mol; |
209 | < | molecules = entry_plug->molecules; |
210 | < | //tau = entry_plug->tau; |
208 | > | nMols = info->n_mol; |
209 | > | molecules = info->molecules; |
210 | > | //tau = info->tau; |
211 | ||
212 | // use velocities of molecular centers of mass and molecular masses: | |
213 | for (i=0; i < 9; i++) { | |
# | Line 193 | Line 215 | void Thermo::getPressureTensor(double press[3][3]){ | |
215 | p_global[i] = 0.0; | |
216 | } | |
217 | ||
218 | < | for (i=0; i < nMols; i++) { |
197 | < | molmass = molecules[i].getCOMvel(vcom); |
218 | > | for (i=0; i < info->integrableObjects.size(); i++) { |
219 | ||
220 | + | molmass = info->integrableObjects[i]->getMass(); |
221 | + | |
222 | + | info->integrableObjects[i]->getVel(vcom); |
223 | + | info->integrableObjects[i]->getPos(pcom); |
224 | + | info->integrableObjects[i]->getFrc(fcom); |
225 | + | |
226 | + | matVecMul3(info->HmatInv, pcom, scaled); |
227 | + | |
228 | + | for(j=0; j<3; j++) |
229 | + | scaled[j] -= roundMe(scaled[j]); |
230 | + | |
231 | + | // calc the wrapped real coordinates from the wrapped scaled coordinates |
232 | + | |
233 | + | matVecMul3(info->Hmat, scaled, pcom); |
234 | + | |
235 | p_local[0] += molmass * (vcom[0] * vcom[0]); | |
236 | p_local[1] += molmass * (vcom[0] * vcom[1]); | |
237 | p_local[2] += molmass * (vcom[0] * vcom[2]); | |
# | Line 205 | Line 241 | void Thermo::getPressureTensor(double press[3][3]){ | |
241 | p_local[6] += molmass * (vcom[2] * vcom[0]); | |
242 | p_local[7] += molmass * (vcom[2] * vcom[1]); | |
243 | p_local[8] += molmass * (vcom[2] * vcom[2]); | |
244 | + | |
245 | } | |
246 | ||
247 | // Get total for entire system from MPI. | |
# | Line 217 | Line 254 | void Thermo::getPressureTensor(double press[3][3]){ | |
254 | } | |
255 | #endif // is_mpi | |
256 | ||
257 | < | volume = entry_plug->boxVol; |
257 | > | volume = this->getVolume(); |
258 | ||
259 | for(i = 0; i < 3; i++) { | |
260 | for (j = 0; j < 3; j++) { | |
261 | k = 3*i + j; | |
262 | < | l = 3*j + i; |
226 | < | press[i][j] = (p_global[k] - entry_plug->tau[l]*e_convert) / volume; |
262 | > | press[i][j] = (p_global[k] + info->tau[k]*e_convert) / volume; |
263 | } | |
264 | } | |
265 | } | |
266 | ||
267 | void Thermo::velocitize() { | |
268 | ||
233 | – | double x,y; |
269 | double aVel[3], aJ[3], I[3][3]; | |
270 | < | int i, j, vr, vd; // velocity randomizer loop counters |
270 | > | int i, j, l, m, n, vr, vd; // velocity randomizer loop counters |
271 | double vdrift[3]; | |
272 | double vbar; | |
273 | const double kb = 8.31451e-7; // kb in amu, angstroms, fs, etc. | |
274 | double av2; | |
275 | double kebar; | |
241 | – | int n_atoms; |
242 | – | Atom** atoms; |
243 | – | DirectionalAtom* dAtom; |
276 | double temperature; | |
277 | < | int n_oriented; |
246 | < | int n_constraints; |
277 | > | int nobj; |
278 | ||
279 | < | atoms = entry_plug->atoms; |
249 | < | n_atoms = entry_plug->n_atoms; |
250 | < | temperature = entry_plug->target_temp; |
251 | < | n_oriented = entry_plug->n_oriented; |
252 | < | n_constraints = entry_plug->n_constraints; |
279 | > | nobj = info->integrableObjects.size(); |
280 | ||
281 | < | kebar = kb * temperature * (double)entry_plug->ndf / |
255 | < | ( 2.0 * (double)entry_plug->ndfRaw ); |
281 | > | temperature = info->target_temp; |
282 | ||
283 | < | for(vr = 0; vr < n_atoms; vr++){ |
283 | > | kebar = kb * temperature * (double)info->ndfRaw / |
284 | > | ( 2.0 * (double)info->ndf ); |
285 | > | |
286 | > | for(vr = 0; vr < nobj; vr++){ |
287 | ||
288 | // uses equipartition theory to solve for vbar in angstrom/fs | |
289 | ||
290 | < | av2 = 2.0 * kebar / atoms[vr]->getMass(); |
290 | > | av2 = 2.0 * kebar / info->integrableObjects[vr]->getMass(); |
291 | vbar = sqrt( av2 ); | |
292 | < | |
264 | < | // vbar = sqrt( 8.31451e-7 * temperature / atoms[vr]->getMass() ); |
265 | < | |
292 | > | |
293 | // picks random velocities from a gaussian distribution | |
294 | // centered on vbar | |
295 | ||
296 | for (j=0; j<3; j++) | |
297 | aVel[j] = vbar * gaussStream->getGaussian(); | |
298 | ||
299 | < | atoms[vr]->setVel( aVel ); |
299 | > | info->integrableObjects[vr]->setVel( aVel ); |
300 | > | |
301 | > | if(info->integrableObjects[vr]->isDirectional()){ |
302 | ||
303 | + | info->integrableObjects[vr]->getI( I ); |
304 | + | |
305 | + | if (info->integrableObjects[vr]->isLinear()) { |
306 | + | |
307 | + | l= info->integrableObjects[vr]->linearAxis(); |
308 | + | m = (l+1)%3; |
309 | + | n = (l+2)%3; |
310 | + | |
311 | + | aJ[l] = 0.0; |
312 | + | vbar = sqrt( 2.0 * kebar * I[m][m] ); |
313 | + | aJ[m] = vbar * gaussStream->getGaussian(); |
314 | + | vbar = sqrt( 2.0 * kebar * I[n][n] ); |
315 | + | aJ[n] = vbar * gaussStream->getGaussian(); |
316 | + | |
317 | + | } else { |
318 | + | for (j = 0 ; j < 3; j++) { |
319 | + | vbar = sqrt( 2.0 * kebar * I[j][j] ); |
320 | + | aJ[j] = vbar * gaussStream->getGaussian(); |
321 | + | } |
322 | + | } // else isLinear |
323 | + | |
324 | + | info->integrableObjects[vr]->setJ( aJ ); |
325 | + | |
326 | + | }//isDirectional |
327 | + | |
328 | } | |
329 | ||
330 | // Get the Center of Mass drift velocity. | |
# | Line 280 | Line 334 | void Thermo::velocitize() { | |
334 | // Corrects for the center of mass drift. | |
335 | // sums all the momentum and divides by total mass. | |
336 | ||
337 | < | for(vd = 0; vd < n_atoms; vd++){ |
337 | > | for(vd = 0; vd < nobj; vd++){ |
338 | ||
339 | < | atoms[vd]->getVel(aVel); |
339 | > | info->integrableObjects[vd]->getVel(aVel); |
340 | ||
341 | for (j=0; j < 3; j++) | |
342 | aVel[j] -= vdrift[j]; | |
343 | ||
344 | < | atoms[vd]->setVel( aVel ); |
344 | > | info->integrableObjects[vd]->setVel( aVel ); |
345 | } | |
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 | – | dAtom->getI( I ); |
300 | – | |
301 | – | for (j = 0 ; j < 3; j++) { |
346 | ||
303 | – | vbar = sqrt( 2.0 * kebar * I[j][j] ); |
304 | – | aJ[j] = vbar * gaussStream->getGaussian(); |
305 | – | |
306 | – | } |
307 | – | |
308 | – | dAtom->setJ( aJ ); |
309 | – | |
310 | – | } |
311 | – | } |
312 | – | } |
347 | } | |
348 | ||
349 | void Thermo::getCOMVel(double vdrift[3]){ | |
# | Line 317 | Line 351 | void Thermo::getCOMVel(double vdrift[3]){ | |
351 | double mtot, mtot_local; | |
352 | double aVel[3], amass; | |
353 | double vdrift_local[3]; | |
354 | < | int vd, n_atoms, j; |
355 | < | Atom** atoms; |
354 | > | int vd, j; |
355 | > | int nobj; |
356 | ||
357 | < | // 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. |
357 | > | nobj = info->integrableObjects.size(); |
358 | ||
326 | – | n_atoms = entry_plug->n_atoms; |
327 | – | atoms = entry_plug->atoms; |
328 | – | |
359 | mtot_local = 0.0; | |
360 | vdrift_local[0] = 0.0; | |
361 | vdrift_local[1] = 0.0; | |
362 | vdrift_local[2] = 0.0; | |
363 | ||
364 | < | for(vd = 0; vd < n_atoms; vd++){ |
364 | > | for(vd = 0; vd < nobj; vd++){ |
365 | ||
366 | < | amass = atoms[vd]->getMass(); |
367 | < | atoms[vd]->getVel( aVel ); |
366 | > | amass = info->integrableObjects[vd]->getMass(); |
367 | > | info->integrableObjects[vd]->getVel( aVel ); |
368 | ||
369 | for(j = 0; j < 3; j++) | |
370 | vdrift_local[j] += aVel[j] * amass; | |
# | Line 358 | Line 388 | void Thermo::getCOMVel(double vdrift[3]){ | |
388 | ||
389 | } | |
390 | ||
391 | + | void Thermo::getCOM(double COM[3]){ |
392 | + | |
393 | + | double mtot, mtot_local; |
394 | + | double aPos[3], amass; |
395 | + | double COM_local[3]; |
396 | + | int i, j; |
397 | + | int nobj; |
398 | + | |
399 | + | mtot_local = 0.0; |
400 | + | COM_local[0] = 0.0; |
401 | + | COM_local[1] = 0.0; |
402 | + | COM_local[2] = 0.0; |
403 | + | |
404 | + | nobj = info->integrableObjects.size(); |
405 | + | for(i = 0; i < nobj; i++){ |
406 | + | |
407 | + | amass = info->integrableObjects[i]->getMass(); |
408 | + | info->integrableObjects[i]->getPos( aPos ); |
409 | + | |
410 | + | for(j = 0; j < 3; j++) |
411 | + | COM_local[j] += aPos[j] * amass; |
412 | + | |
413 | + | mtot_local += amass; |
414 | + | } |
415 | + | |
416 | + | #ifdef IS_MPI |
417 | + | MPI_Allreduce(&mtot_local,&mtot,1,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD); |
418 | + | MPI_Allreduce(COM_local,COM,3,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD); |
419 | + | #else |
420 | + | mtot = mtot_local; |
421 | + | for(i = 0; i < 3; i++) { |
422 | + | COM[i] = COM_local[i]; |
423 | + | } |
424 | + | #endif |
425 | + | |
426 | + | for (i = 0; i < 3; i++) { |
427 | + | COM[i] = COM[i] / mtot; |
428 | + | } |
429 | + | } |
430 | + | |
431 | + | void Thermo::removeCOMdrift() { |
432 | + | double vdrift[3], aVel[3]; |
433 | + | int vd, j, nobj; |
434 | + | |
435 | + | nobj = info->integrableObjects.size(); |
436 | + | |
437 | + | // Get the Center of Mass drift velocity. |
438 | + | |
439 | + | getCOMVel(vdrift); |
440 | + | |
441 | + | // Corrects for the center of mass drift. |
442 | + | // sums all the momentum and divides by total mass. |
443 | + | |
444 | + | for(vd = 0; vd < nobj; vd++){ |
445 | + | |
446 | + | info->integrableObjects[vd]->getVel(aVel); |
447 | + | |
448 | + | for (j=0; j < 3; j++) |
449 | + | aVel[j] -= vdrift[j]; |
450 | + | |
451 | + | info->integrableObjects[vd]->setVel( aVel ); |
452 | + | } |
453 | + | } |
– | Removed lines |
+ | Added lines |
< | Changed lines |
> | Changed lines |