ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/mdtools/md_code/Thermo.cpp
Revision: 223
Committed: Fri Jan 3 22:04:50 2003 UTC (21 years, 6 months ago) by chuckv
File size: 7068 byte(s)
Log Message:
Finished thermo and randomSPRNG classes.

File Contents

# Content
1 #include <cmath>
2 #include <mpi++.h>
3
4 #include "Thermo.hpp"
5 #include "SRI.hpp"
6 #include "LRI.hpp"
7 #include "Integrator.hpp"
8
9 #define BASE_SEED 123456789
10
11 Thermo::Thermo( SimInfo* the_entry_plug ) {
12 entry_plug = the_entry_plug;
13 baseSeed = BASE_SEED;
14 gaussStream = new gaussianSPRNG( baseSeed );
15 }
16
17 Thermo::~Thermo(){
18 delete gaussStream;
19 }
20
21 double Thermo::getKinetic(){
22
23 const double e_convert = 4.184E-4; // convert kcal/mol -> (amu A^2)/fs^2
24 double vx2, vy2, vz2;
25 double kinetic, v_sqr;
26 int kl;
27 double jx2, jy2, jz2; // the square of the angular momentums
28
29 DirectionalAtom *dAtom;
30
31 int n_atoms;
32 double kinetic_global;
33 Atom** atoms;
34
35
36 n_atoms = entry_plug->n_atoms;
37 atoms = entry_plug->atoms;
38
39 kinetic = 0.0;
40 kinetic_global = 0.0;
41 for( kl=0; kl < n_atoms; kl++ ){
42
43 vx2 = atoms[kl]->get_vx() * atoms[kl]->get_vx();
44 vy2 = atoms[kl]->get_vy() * atoms[kl]->get_vy();
45 vz2 = atoms[kl]->get_vz() * atoms[kl]->get_vz();
46
47 v_sqr = vx2 + vy2 + vz2;
48 kinetic += atoms[kl]->getMass() * v_sqr;
49
50 if( atoms[kl]->isDirectional() ){
51
52 dAtom = (DirectionalAtom *)atoms[kl];
53
54 jx2 = dAtom->getJx() * dAtom->getJx();
55 jy2 = dAtom->getJy() * dAtom->getJy();
56 jz2 = dAtom->getJz() * dAtom->getJz();
57
58 kinetic += (jx2 / dAtom->getIxx()) + (jy2 / dAtom->getIyy())
59 + (jz2 / dAtom->getIzz());
60 }
61 }
62 #ifdef IS_MPI
63 MPI_COMM_WORLD.Allreduce(&kinetic,&kinetic_global,1,MPI_DOUBLE,MPI_SUM);
64 kinetic = kinetic_global;
65 #endif
66
67 kinetic = kinetic * 0.5 / e_convert;
68
69 return kinetic;
70 }
71
72 double Thermo::getPotential(){
73
74 double potential;
75 double potential_global;
76 int el, nSRI;
77 SRI** sris;
78
79 sris = entry_plug->sr_interactions;
80 nSRI = entry_plug->n_SRI;
81
82 potential = 0.0;
83 potential_global = 0.0;
84 potential += entry_plug->longRange->get_potential();;
85
86 // std::cerr << "long range potential: " << potential << "\n";
87 for( el=0; el<nSRI; el++ ){
88
89 potential += sris[el]->get_potential();
90 }
91
92 // Get total potential for entire system from MPI.
93 #ifdef IS_MPI
94 MPI_COMM_WORLD.Allreduce(&potential,&potential_global,1,MPI_DOUBLE,MPI_SUM);
95 potential = potential_global;
96 #endif
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.9872179E-3; // boltzman's constant in kcal/(mol K)
112 double temperature;
113
114 int ndf = 3 * entry_plug->n_atoms + 3 * entry_plug->n_oriented
115 - entry_plug->n_constraints - 3;
116
117 temperature = ( 2.0 * this->getKinetic() ) / ( ndf * kb );
118 return temperature;
119 }
120
121 double Thermo::getPressure(){
122
123 // const double conv_Pa_atm = 9.901E-6; // convert Pa -> atm
124 // const double conv_internal_Pa = 1.661E-7; //convert amu/(fs^2 A) -> Pa
125 // const double conv_A_m = 1.0E-10; //convert A -> m
126
127 return 0.0;
128 }
129
130 void Thermo::velocitize() {
131
132 double x,y;
133 double vx, vy, vz;
134 double jx, jy, jz;
135 int i, vr, vd; // velocity randomizer loop counters
136 double vdrift[3];
137 double mtot = 0.0;
138 double vbar;
139 const double kb = 8.31451e-7; // kb in amu, angstroms, fs, etc.
140 double av2;
141 double kebar;
142 int ndf; // number of degrees of freedom
143 int ndfRaw; // the raw number of degrees of freedom
144 int n_atoms;
145 Atom** atoms;
146 DirectionalAtom* dAtom;
147 double temperature;
148 int n_oriented;
149 int n_constraints;
150
151 atoms = entry_plug->atoms;
152 n_atoms = entry_plug->n_atoms;
153 temperature = entry_plug->target_temp;
154 n_oriented = entry_plug->n_oriented;
155 n_constraints = entry_plug->n_constraints;
156
157
158 ndfRaw = 3 * n_atoms + 3 * n_oriented;
159 ndf = ndfRaw - n_constraints - 3;
160 kebar = kb * temperature * (double)ndf / ( 2.0 * (double)ndfRaw );
161
162 for(vr = 0; vr < n_atoms; vr++){
163
164 // uses equipartition theory to solve for vbar in angstrom/fs
165
166 av2 = 2.0 * kebar / atoms[vr]->getMass();
167 vbar = sqrt( av2 );
168
169 // vbar = sqrt( 8.31451e-7 * temperature / atoms[vr]->getMass() );
170
171 // picks random velocities from a gaussian distribution
172 // centered on vbar
173 #ifndef USE_SPRNG
174 /* If we are using mpi, we need to use the SPRNG random
175 generator. The non drand48 generator will just repeat
176 the same numbers for every node creating a non-gaussian
177 distribution for the simulation. drand48 is fine for the
178 single processor version of the code, but SPRNG should
179 still be preferred for consistency.
180 */
181 #ifdef IS_MPI
182 #error "SPRNG random number generator must be used for MPI"
183 #else
184 #warning "Using drand48 for random number generation"
185 #endif
186 x = drand48();
187 y = drand48();
188 vx = vbar * sqrt( -2.0 * log(x)) * cos(2 * M_PI * y);
189
190 x = drand48();
191 y = drand48();
192 vy = vbar * sqrt( -2.0 * log(x)) * cos(2 * M_PI * y);
193
194 x = drand48();
195 y = drand48();
196 vz = vbar * sqrt( -2.0 * log(x)) * cos(2 * M_PI * y);
197 #endif
198
199 #ifdef USE_SPRNG
200 vx = vbar * gaussStream->getGaussian();
201 vy = vbar * gaussStream->getGaussian();
202 vz = vbar * gaussStream->getGaussian();
203 #endif
204
205 atoms[vr]->set_vx( vx );
206 atoms[vr]->set_vy( vy );
207 atoms[vr]->set_vz( vz );
208 }
209
210 // Corrects for the center of mass drift.
211 // sums all the momentum and divides by total mass.
212
213 mtot = 0.0;
214 vdrift[0] = 0.0;
215 vdrift[1] = 0.0;
216 vdrift[2] = 0.0;
217 for(vd = 0; vd < n_atoms; vd++){
218
219 vdrift[0] += atoms[vd]->get_vx() * atoms[vd]->getMass();
220 vdrift[1] += atoms[vd]->get_vy() * atoms[vd]->getMass();
221 vdrift[2] += atoms[vd]->get_vz() * atoms[vd]->getMass();
222
223 mtot = mtot + atoms[vd]->getMass();
224 }
225
226 for (vd = 0; vd < 3; vd++) {
227 vdrift[vd] = vdrift[vd] / mtot;
228 }
229
230 for(vd = 0; vd < n_atoms; vd++){
231
232 vx = atoms[vd]->get_vx();
233 vy = atoms[vd]->get_vy();
234 vz = atoms[vd]->get_vz();
235
236
237 vx -= vdrift[0];
238 vy -= vdrift[1];
239 vz -= vdrift[2];
240
241 atoms[vd]->set_vx(vx);
242 atoms[vd]->set_vy(vy);
243 atoms[vd]->set_vz(vz);
244 }
245 if( n_oriented ){
246
247 for( i=0; i<n_atoms; i++ ){
248
249 if( atoms[i]->isDirectional() ){
250
251 dAtom = (DirectionalAtom *)atoms[i];
252 #ifdef IS_MPI
253 #error "SPRNG random number generator must be used for MPI"
254 #else
255 #warning "Using drand48 for random number generation"
256 #endif
257
258 vbar = sqrt( 2.0 * kebar * dAtom->getIxx() );
259 x = drand48();
260 y = drand48();
261 jx = vbar * sqrt( -2.0 * log(x)) * cos(2 * M_PI * y);
262
263 vbar = sqrt( 2.0 * kebar * dAtom->getIyy() );
264 x = drand48();
265 y = drand48();
266 jy = vbar * sqrt( -2.0 * log(x)) * cos(2 * M_PI * y);
267
268 vbar = sqrt( 2.0 * kebar * dAtom->getIzz() );
269 x = drand48();
270 y = drand48();
271 jz = vbar * sqrt( -2.0 * log(x)) * cos(2 * M_PI * y);
272 #endif
273 #ifdef USE_SPRNG
274 vbar = sqrt( 2.0 * kebar * dAtom->getIxx() );
275 jx = vbar * gaussStream->getGaussian();
276
277 vbar = sqrt( 2.0 * kebar * dAtom->getIyy() );
278 jy = vbar * gaussStream->getGaussian();
279
280 vbar = sqrt( 2.0 * kebar * dAtom->getIzz() );
281 jz = vbar * gaussStream->getGaussian();
282 #endif
283
284 dAtom->setJx( jx );
285 dAtom->setJy( jy );
286 dAtom->setJz( jz );
287 }
288 }
289 }
290 }