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, 7 months ago) by chuckv
File size: 7068 byte(s)
Log Message:
Finished thermo and randomSPRNG classes.

File Contents

# User Rev Content
1 mmeineke 10 #include <cmath>
2 chuckv 218 #include <mpi++.h>
3 mmeineke 10
4     #include "Thermo.hpp"
5     #include "SRI.hpp"
6     #include "LRI.hpp"
7     #include "Integrator.hpp"
8    
9 chuckv 223 #define BASE_SEED 123456789
10 mmeineke 10
11 chuckv 223 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 mmeineke 10 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 chuckv 218 double kinetic_global;
33 mmeineke 10 Atom** atoms;
34 chuckv 218
35 mmeineke 10
36     n_atoms = entry_plug->n_atoms;
37     atoms = entry_plug->atoms;
38    
39     kinetic = 0.0;
40 chuckv 218 kinetic_global = 0.0;
41 mmeineke 10 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 chuckv 218 #ifdef IS_MPI
63     MPI_COMM_WORLD.Allreduce(&kinetic,&kinetic_global,1,MPI_DOUBLE,MPI_SUM);
64     kinetic = kinetic_global;
65     #endif
66    
67 mmeineke 10 kinetic = kinetic * 0.5 / e_convert;
68    
69     return kinetic;
70     }
71    
72     double Thermo::getPotential(){
73    
74     double potential;
75 chuckv 218 double potential_global;
76 mmeineke 10 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 chuckv 218 potential_global = 0.0;
84 mmeineke 10 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 chuckv 218 // 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 mmeineke 10 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 mmeineke 25 const double kb = 1.9872179E-3; // boltzman's constant in kcal/(mol K)
112 mmeineke 10 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 mmeineke 117 // 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 mmeineke 10
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 chuckv 221 #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 mmeineke 10 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 chuckv 221 #endif
198    
199     #ifdef USE_SPRNG
200 chuckv 223 vx = vbar * gaussStream->getGaussian();
201     vy = vbar * gaussStream->getGaussian();
202     vz = vbar * gaussStream->getGaussian();
203 chuckv 221 #endif
204    
205 mmeineke 10 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 chuckv 221 #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 mmeineke 10
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 chuckv 221 #endif
273     #ifdef USE_SPRNG
274     vbar = sqrt( 2.0 * kebar * dAtom->getIxx() );
275 chuckv 223 jx = vbar * gaussStream->getGaussian();
276 chuckv 221
277     vbar = sqrt( 2.0 * kebar * dAtom->getIyy() );
278 chuckv 223 jy = vbar * gaussStream->getGaussian();
279 chuckv 221
280     vbar = sqrt( 2.0 * kebar * dAtom->getIzz() );
281 chuckv 223 jz = vbar * gaussStream->getGaussian();
282 chuckv 221 #endif
283 mmeineke 10
284     dAtom->setJx( jx );
285     dAtom->setJy( jy );
286     dAtom->setJz( jz );
287     }
288     }
289     }
290     }