# | Line 1 | Line 1 | |
---|---|---|
1 | < | #include <cmath> |
1 | > | #include <math.h> |
2 | #include <iostream> | |
3 | using namespace std; | |
4 | ||
5 | #ifdef IS_MPI | |
6 | #include <mpi.h> | |
7 | – | #include <mpi++.h> |
7 | #endif //is_mpi | |
8 | ||
9 | #include "Thermo.hpp" | |
# | Line 17 | Line 16 | using namespace std; | |
16 | #include "mpiSimulation.hpp" | |
17 | #endif // is_mpi | |
18 | ||
19 | < | |
20 | < | #define BASE_SEED 123456789 |
21 | < | |
23 | < | Thermo::Thermo( SimInfo* the_entry_plug ) { |
24 | < | entry_plug = the_entry_plug; |
25 | < | int baseSeed = BASE_SEED; |
19 | > | Thermo::Thermo( SimInfo* the_info ) { |
20 | > | info = the_info; |
21 | > | int baseSeed = the_info->getSeed(); |
22 | ||
23 | gaussStream = new gaussianSPRNG( baseSeed ); | |
24 | } | |
# | Line 34 | Line 30 | double Thermo::getKinetic(){ | |
30 | double Thermo::getKinetic(){ | |
31 | ||
32 | const double e_convert = 4.184E-4; // convert kcal/mol -> (amu A^2)/fs^2 | |
33 | < | double vx2, vy2, vz2; |
34 | < | double kinetic, v_sqr; |
35 | < | int kl; |
36 | < | double jx2, jy2, jz2; // the square of the angular momentums |
33 | > | double kinetic; |
34 | > | double amass; |
35 | > | double aVel[3], aJ[3], I[3][3]; |
36 | > | int j, kl; |
37 | ||
38 | DirectionalAtom *dAtom; | |
39 | ||
# | Line 46 | Line 42 | double Thermo::getKinetic(){ | |
42 | Atom** atoms; | |
43 | ||
44 | ||
45 | < | n_atoms = entry_plug->n_atoms; |
46 | < | atoms = entry_plug->atoms; |
45 | > | n_atoms = info->n_atoms; |
46 | > | atoms = info->atoms; |
47 | ||
48 | kinetic = 0.0; | |
49 | kinetic_global = 0.0; | |
50 | for( kl=0; kl < n_atoms; kl++ ){ | |
51 | + | |
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 | ||
56 | – | vx2 = atoms[kl]->get_vx() * atoms[kl]->get_vx(); |
57 | – | vy2 = atoms[kl]->get_vy() * atoms[kl]->get_vy(); |
58 | – | vz2 = atoms[kl]->get_vz() * atoms[kl]->get_vz(); |
59 | – | |
60 | – | v_sqr = vx2 + vy2 + vz2; |
61 | – | kinetic += atoms[kl]->getMass() * v_sqr; |
62 | – | |
58 | if( atoms[kl]->isDirectional() ){ | |
59 | ||
60 | dAtom = (DirectionalAtom *)atoms[kl]; | |
61 | + | |
62 | + | dAtom->getJ( aJ ); |
63 | + | dAtom->getI( I ); |
64 | ||
65 | < | jx2 = dAtom->getJx() * dAtom->getJx(); |
66 | < | jy2 = dAtom->getJy() * dAtom->getJy(); |
69 | < | jz2 = dAtom->getJz() * dAtom->getJz(); |
65 | > | for (j=0; j<3; j++) |
66 | > | kinetic += aJ[j]*aJ[j] / I[j][j]; |
67 | ||
71 | – | kinetic += (jx2 / dAtom->getIxx()) + (jy2 / dAtom->getIyy()) |
72 | – | + (jz2 / dAtom->getIzz()); |
68 | } | |
69 | } | |
70 | #ifdef IS_MPI | |
71 | < | MPI::COMM_WORLD.Allreduce(&kinetic,&kinetic_global,1,MPI_DOUBLE,MPI_SUM); |
71 | > | MPI_Allreduce(&kinetic,&kinetic_global,1,MPI_DOUBLE, |
72 | > | MPI_SUM, MPI_COMM_WORLD); |
73 | kinetic = kinetic_global; | |
74 | #endif //is_mpi | |
75 | ||
# | Line 89 | Line 85 | double Thermo::getPotential(){ | |
85 | int el, nSRI; | |
86 | Molecule* molecules; | |
87 | ||
88 | < | molecules = entry_plug->molecules; |
89 | < | nSRI = entry_plug->n_SRI; |
88 | > | molecules = info->molecules; |
89 | > | nSRI = info->n_SRI; |
90 | ||
91 | potential_local = 0.0; | |
92 | potential = 0.0; | |
93 | < | potential_local += entry_plug->lrPot; |
93 | > | potential_local += info->lrPot; |
94 | ||
95 | < | for( el=0; el<entry_plug->n_mol; el++ ){ |
95 | > | for( el=0; el<info->n_mol; el++ ){ |
96 | potential_local += molecules[el].getPotential(); | |
97 | } | |
98 | ||
103 | – | #ifdef IS_MPI |
104 | – | /* |
105 | – | std::cerr << "node " << worldRank << ": before LONG RANGE pot = " << entry_plug->lrPot |
106 | – | << "; pot_local = " << potential_local |
107 | – | << "; pot = " << potential << "\n"; |
108 | – | */ |
109 | – | #endif |
110 | – | |
99 | // Get total potential for entire system from MPI. | |
100 | #ifdef IS_MPI | |
101 | < | MPI::COMM_WORLD.Allreduce(&potential_local,&potential,1,MPI_DOUBLE,MPI_SUM); |
101 | > | MPI_Allreduce(&potential_local,&potential,1,MPI_DOUBLE, |
102 | > | MPI_SUM, MPI_COMM_WORLD); |
103 | #else | |
104 | potential = potential_local; | |
105 | #endif // is_mpi | |
# | Line 134 | Line 123 | double Thermo::getTemperature(){ | |
123 | ||
124 | double Thermo::getTemperature(){ | |
125 | ||
126 | < | const double kb = 1.9872179E-3; // boltzman's constant in kcal/(mol K) |
126 | > | const double kb = 1.9872156E-3; // boltzman's constant in kcal/(mol K) |
127 | double temperature; | |
139 | – | int ndf_local, ndf; |
128 | ||
129 | < | ndf_local = 3 * entry_plug->n_atoms + 3 * entry_plug->n_oriented |
130 | < | - entry_plug->n_constraints; |
129 | > | temperature = ( 2.0 * this->getKinetic() ) / ((double)info->ndf * kb ); |
130 | > | return temperature; |
131 | > | } |
132 | ||
133 | < | #ifdef IS_MPI |
145 | < | MPI::COMM_WORLD.Allreduce(&ndf_local,&ndf,1,MPI_INT,MPI_SUM); |
146 | < | #else |
147 | < | ndf = ndf_local; |
148 | < | #endif |
133 | > | double Thermo::getVolume() { |
134 | ||
135 | < | ndf = ndf - 3; |
135 | > | return info->boxVol; |
136 | > | } |
137 | > | |
138 | > | double Thermo::getPressure() { |
139 | > | |
140 | > | // Relies on the calculation of the full molecular pressure tensor |
141 | ||
142 | < | temperature = ( 2.0 * this->getKinetic() ) / ( ndf * kb ); |
143 | < | return temperature; |
142 | > | const double p_convert = 1.63882576e8; |
143 | > | double press[3][3]; |
144 | > | double pressure; |
145 | > | |
146 | > | this->getPressureTensor(press); |
147 | > | |
148 | > | pressure = p_convert * (press[0][0] + press[1][1] + press[2][2]) / 3.0; |
149 | > | |
150 | > | return pressure; |
151 | } | |
152 | ||
153 | < | double Thermo::getPressure(){ |
153 | > | double Thermo::getPressureX() { |
154 | ||
155 | < | // const double conv_Pa_atm = 9.901E-6; // convert Pa -> atm |
156 | < | // const double conv_internal_Pa = 1.661E-7; //convert amu/(fs^2 A) -> Pa |
157 | < | // const double conv_A_m = 1.0E-10; //convert A -> m |
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 pressureX; |
160 | ||
161 | < | return 0.0; |
161 | > | this->getPressureTensor(press); |
162 | > | |
163 | > | pressureX = p_convert * press[0][0]; |
164 | > | |
165 | > | return pressureX; |
166 | } | |
167 | ||
168 | + | double Thermo::getPressureY() { |
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 pressureY; |
175 | + | |
176 | + | this->getPressureTensor(press); |
177 | + | |
178 | + | pressureY = p_convert * press[1][1]; |
179 | + | |
180 | + | return pressureY; |
181 | + | } |
182 | + | |
183 | + | double Thermo::getPressureZ() { |
184 | + | |
185 | + | // Relies on the calculation of the full molecular pressure tensor |
186 | + | |
187 | + | const double p_convert = 1.63882576e8; |
188 | + | double press[3][3]; |
189 | + | double pressureZ; |
190 | + | |
191 | + | this->getPressureTensor(press); |
192 | + | |
193 | + | pressureZ = p_convert * press[2][2]; |
194 | + | |
195 | + | return pressureZ; |
196 | + | } |
197 | + | |
198 | + | |
199 | + | void Thermo::getPressureTensor(double press[3][3]){ |
200 | + | // returns pressure tensor in units amu*fs^-2*Ang^-1 |
201 | + | // routine derived via viral theorem description in: |
202 | + | // Paci, E. and Marchi, M. J.Phys.Chem. 1996, 100, 4314-4322 |
203 | + | |
204 | + | const double e_convert = 4.184e-4; |
205 | + | |
206 | + | double molmass, volume; |
207 | + | double vcom[3]; |
208 | + | double p_local[9], p_global[9]; |
209 | + | int i, j, k, nMols; |
210 | + | Molecule* molecules; |
211 | + | |
212 | + | nMols = info->n_mol; |
213 | + | molecules = info->molecules; |
214 | + | //tau = info->tau; |
215 | + | |
216 | + | // use velocities of molecular centers of mass and molecular masses: |
217 | + | for (i=0; i < 9; i++) { |
218 | + | p_local[i] = 0.0; |
219 | + | p_global[i] = 0.0; |
220 | + | } |
221 | + | |
222 | + | for (i=0; i < nMols; i++) { |
223 | + | molmass = molecules[i].getCOMvel(vcom); |
224 | + | |
225 | + | p_local[0] += molmass * (vcom[0] * vcom[0]); |
226 | + | p_local[1] += molmass * (vcom[0] * vcom[1]); |
227 | + | p_local[2] += molmass * (vcom[0] * vcom[2]); |
228 | + | p_local[3] += molmass * (vcom[1] * vcom[0]); |
229 | + | p_local[4] += molmass * (vcom[1] * vcom[1]); |
230 | + | p_local[5] += molmass * (vcom[1] * vcom[2]); |
231 | + | p_local[6] += molmass * (vcom[2] * vcom[0]); |
232 | + | p_local[7] += molmass * (vcom[2] * vcom[1]); |
233 | + | p_local[8] += molmass * (vcom[2] * vcom[2]); |
234 | + | } |
235 | + | |
236 | + | // Get total for entire system from MPI. |
237 | + | |
238 | + | #ifdef IS_MPI |
239 | + | MPI_Allreduce(p_local,p_global,9,MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); |
240 | + | #else |
241 | + | for (i=0; i<9; i++) { |
242 | + | p_global[i] = p_local[i]; |
243 | + | } |
244 | + | #endif // is_mpi |
245 | + | |
246 | + | volume = this->getVolume(); |
247 | + | |
248 | + | for(i = 0; i < 3; i++) { |
249 | + | for (j = 0; j < 3; j++) { |
250 | + | k = 3*i + j; |
251 | + | press[i][j] = (p_global[k] + info->tau[k]*e_convert) / volume; |
252 | + | |
253 | + | } |
254 | + | } |
255 | + | } |
256 | + | |
257 | void Thermo::velocitize() { | |
258 | ||
259 | < | double x,y; |
260 | < | double vx, vy, vz; |
169 | < | double jx, jy, jz; |
170 | < | int i, vr, vd; // velocity randomizer loop counters |
259 | > | double aVel[3], aJ[3], I[3][3]; |
260 | > | int i, j, vr, vd; // velocity randomizer loop counters |
261 | double vdrift[3]; | |
262 | double vbar; | |
263 | const double kb = 8.31451e-7; // kb in amu, angstroms, fs, etc. | |
264 | double av2; | |
265 | double kebar; | |
176 | – | int ndf, ndf_local; // number of degrees of freedom |
177 | – | int ndfRaw, ndfRaw_local; // the raw number of degrees of freedom |
266 | int n_atoms; | |
267 | Atom** atoms; | |
268 | DirectionalAtom* dAtom; | |
# | Line 182 | Line 270 | void Thermo::velocitize() { | |
270 | int n_oriented; | |
271 | int n_constraints; | |
272 | ||
273 | < | atoms = entry_plug->atoms; |
274 | < | n_atoms = entry_plug->n_atoms; |
275 | < | temperature = entry_plug->target_temp; |
276 | < | n_oriented = entry_plug->n_oriented; |
277 | < | n_constraints = entry_plug->n_constraints; |
273 | > | atoms = info->atoms; |
274 | > | n_atoms = info->n_atoms; |
275 | > | temperature = info->target_temp; |
276 | > | n_oriented = info->n_oriented; |
277 | > | n_constraints = info->n_constraints; |
278 | ||
279 | < | // Raw degrees of freedom that we have to set |
280 | < | ndfRaw_local = 3 * entry_plug->n_atoms + 3 * entry_plug->n_oriented; |
193 | < | |
194 | < | // Degrees of freedom that can contain kinetic energy |
195 | < | ndf_local = 3 * entry_plug->n_atoms + 3 * entry_plug->n_oriented |
196 | < | - entry_plug->n_constraints; |
279 | > | kebar = kb * temperature * (double)info->ndfRaw / |
280 | > | ( 2.0 * (double)info->ndf ); |
281 | ||
198 | – | #ifdef IS_MPI |
199 | – | MPI::COMM_WORLD.Allreduce(&ndf_local,&ndf,1,MPI_INT,MPI_SUM); |
200 | – | MPI::COMM_WORLD.Allreduce(&ndfRaw_local,&ndfRaw,1,MPI_INT,MPI_SUM); |
201 | – | #else |
202 | – | ndfRaw = ndfRaw_local; |
203 | – | ndf = ndf_local; |
204 | – | #endif |
205 | – | ndf = ndf - 3; |
206 | – | |
207 | – | kebar = kb * temperature * (double)ndf / ( 2.0 * (double)ndfRaw ); |
208 | – | |
282 | for(vr = 0; vr < n_atoms; vr++){ | |
283 | ||
284 | // uses equipartition theory to solve for vbar in angstrom/fs | |
# | Line 218 | Line 291 | void Thermo::velocitize() { | |
291 | // picks random velocities from a gaussian distribution | |
292 | // centered on vbar | |
293 | ||
294 | < | vx = vbar * gaussStream->getGaussian(); |
295 | < | vy = vbar * gaussStream->getGaussian(); |
296 | < | vz = vbar * gaussStream->getGaussian(); |
294 | > | for (j=0; j<3; j++) |
295 | > | aVel[j] = vbar * gaussStream->getGaussian(); |
296 | > | |
297 | > | atoms[vr]->setVel( aVel ); |
298 | ||
225 | – | atoms[vr]->set_vx( vx ); |
226 | – | atoms[vr]->set_vy( vy ); |
227 | – | atoms[vr]->set_vz( vz ); |
299 | } | |
300 | ||
301 | // Get the Center of Mass drift velocity. | |
# | Line 236 | Line 307 | void Thermo::velocitize() { | |
307 | ||
308 | for(vd = 0; vd < n_atoms; vd++){ | |
309 | ||
310 | < | vx = atoms[vd]->get_vx(); |
240 | < | vy = atoms[vd]->get_vy(); |
241 | < | vz = atoms[vd]->get_vz(); |
242 | < | |
243 | < | vx -= vdrift[0]; |
244 | < | vy -= vdrift[1]; |
245 | < | vz -= vdrift[2]; |
310 | > | atoms[vd]->getVel(aVel); |
311 | ||
312 | < | atoms[vd]->set_vx(vx); |
313 | < | atoms[vd]->set_vy(vy); |
314 | < | atoms[vd]->set_vz(vz); |
312 | > | for (j=0; j < 3; j++) |
313 | > | aVel[j] -= vdrift[j]; |
314 | > | |
315 | > | atoms[vd]->setVel( aVel ); |
316 | } | |
317 | if( n_oriented ){ | |
318 | ||
# | Line 255 | Line 321 | void Thermo::velocitize() { | |
321 | if( atoms[i]->isDirectional() ){ | |
322 | ||
323 | dAtom = (DirectionalAtom *)atoms[i]; | |
324 | + | dAtom->getI( I ); |
325 | + | |
326 | + | for (j = 0 ; j < 3; j++) { |
327 | ||
328 | < | vbar = sqrt( 2.0 * kebar * dAtom->getIxx() ); |
329 | < | jx = vbar * gaussStream->getGaussian(); |
328 | > | vbar = sqrt( 2.0 * kebar * I[j][j] ); |
329 | > | aJ[j] = vbar * gaussStream->getGaussian(); |
330 | ||
331 | < | vbar = sqrt( 2.0 * kebar * dAtom->getIyy() ); |
263 | < | jy = vbar * gaussStream->getGaussian(); |
331 | > | } |
332 | ||
333 | < | vbar = sqrt( 2.0 * kebar * dAtom->getIzz() ); |
334 | < | jz = vbar * gaussStream->getGaussian(); |
267 | < | |
268 | < | dAtom->setJx( jx ); |
269 | < | dAtom->setJy( jy ); |
270 | < | dAtom->setJz( jz ); |
333 | > | dAtom->setJ( aJ ); |
334 | > | |
335 | } | |
336 | } | |
337 | } | |
# | Line 276 | Line 340 | void Thermo::getCOMVel(double vdrift[3]){ | |
340 | void Thermo::getCOMVel(double vdrift[3]){ | |
341 | ||
342 | double mtot, mtot_local; | |
343 | + | double aVel[3], amass; |
344 | double vdrift_local[3]; | |
345 | < | int vd, n_atoms; |
345 | > | int vd, n_atoms, j; |
346 | Atom** atoms; | |
347 | ||
348 | // We are very careless here with the distinction between n_atoms and n_local | |
349 | // We should really fix this before someone pokes an eye out. | |
350 | ||
351 | < | n_atoms = entry_plug->n_atoms; |
352 | < | atoms = entry_plug->atoms; |
351 | > | n_atoms = info->n_atoms; |
352 | > | atoms = info->atoms; |
353 | ||
354 | mtot_local = 0.0; | |
355 | vdrift_local[0] = 0.0; | |
# | Line 293 | Line 358 | void Thermo::getCOMVel(double vdrift[3]){ | |
358 | ||
359 | for(vd = 0; vd < n_atoms; vd++){ | |
360 | ||
361 | < | vdrift_local[0] += atoms[vd]->get_vx() * atoms[vd]->getMass(); |
362 | < | vdrift_local[1] += atoms[vd]->get_vy() * atoms[vd]->getMass(); |
363 | < | vdrift_local[2] += atoms[vd]->get_vz() * atoms[vd]->getMass(); |
361 | > | amass = atoms[vd]->getMass(); |
362 | > | atoms[vd]->getVel( aVel ); |
363 | > | |
364 | > | for(j = 0; j < 3; j++) |
365 | > | vdrift_local[j] += aVel[j] * amass; |
366 | ||
367 | < | mtot_local += atoms[vd]->getMass(); |
367 | > | mtot_local += amass; |
368 | } | |
369 | ||
370 | #ifdef IS_MPI | |
371 | < | MPI::COMM_WORLD.Allreduce(&mtot_local,&mtot,1,MPI_DOUBLE,MPI_SUM); |
372 | < | MPI::COMM_WORLD.Allreduce(vdrift_local,vdrift,3,MPI_DOUBLE,MPI_SUM); |
371 | > | MPI_Allreduce(&mtot_local,&mtot,1,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD); |
372 | > | MPI_Allreduce(vdrift_local,vdrift,3,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD); |
373 | #else | |
374 | mtot = mtot_local; | |
375 | for(vd = 0; vd < 3; vd++) { | |
# | Line 316 | Line 383 | void Thermo::getCOMVel(double vdrift[3]){ | |
383 | ||
384 | } | |
385 | ||
386 | + | void Thermo::getCOM(double COM[3]){ |
387 | + | |
388 | + | double mtot, mtot_local; |
389 | + | double aPos[3], amass; |
390 | + | double COM_local[3]; |
391 | + | int i, n_atoms, j; |
392 | + | Atom** atoms; |
393 | + | |
394 | + | // We are very careless here with the distinction between n_atoms and n_local |
395 | + | // We should really fix this before someone pokes an eye out. |
396 | + | |
397 | + | n_atoms = info->n_atoms; |
398 | + | atoms = info->atoms; |
399 | + | |
400 | + | mtot_local = 0.0; |
401 | + | COM_local[0] = 0.0; |
402 | + | COM_local[1] = 0.0; |
403 | + | COM_local[2] = 0.0; |
404 | + | |
405 | + | for(i = 0; i < n_atoms; i++){ |
406 | + | |
407 | + | amass = atoms[i]->getMass(); |
408 | + | atoms[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 | + | } |
– | Removed lines |
+ | Added lines |
< | Changed lines |
> | Changed lines |