ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/NPTf.cpp
Revision: 578
Committed: Wed Jul 9 02:15:29 2003 UTC (21 years ago) by gezelter
File size: 9485 byte(s)
Log Message:
Fixes for both NPTf and NPTi

File Contents

# User Rev Content
1 gezelter 576 #include "Atom.hpp"
2     #include "SRI.hpp"
3     #include "AbstractClasses.hpp"
4     #include "SimInfo.hpp"
5     #include "ForceFields.hpp"
6     #include "Thermo.hpp"
7     #include "ReadWrite.hpp"
8     #include "Integrator.hpp"
9     #include "simError.h"
10    
11    
12 gezelter 578 // Basic non-isotropic thermostating and barostating via the Melchionna
13 gezelter 576 // modification of the Hoover algorithm:
14     //
15     // Melchionna, S., Ciccotti, G., and Holian, B. L., 1993,
16     // Molec. Phys., 78, 533.
17     //
18     // and
19     //
20     // Hoover, W. G., 1986, Phys. Rev. A, 34, 2499.
21    
22 gezelter 577 NPTf::NPTf ( SimInfo *theInfo, ForceFields* the_ff):
23 gezelter 576 Integrator( theInfo, the_ff )
24     {
25     int i;
26     chi = 0.0;
27     for(i = 0; i < 9; i++) eta[i] = 0.0;
28     have_tau_thermostat = 0;
29     have_tau_barostat = 0;
30     have_target_temp = 0;
31     have_target_pressure = 0;
32     }
33    
34 gezelter 577 void NPTf::moveA() {
35 gezelter 576
36     int i,j,k;
37     int atomIndex, aMatIndex;
38     DirectionalAtom* dAtom;
39     double Tb[3];
40     double ji[3];
41     double rj[3];
42 gezelter 578 double ident[3][3], eta1[3][3], eta2[3][3], hmnew[3][3];
43     double hm[9];
44     double vx, vy, vz;
45     double scx, scy, scz;
46 gezelter 576 double instaTemp, instaPress, instaVol;
47     double tt2, tb2;
48     double angle;
49 gezelter 577 double press[9];
50     const double p_convert = 1.63882576e8;
51 gezelter 576
52     tt2 = tauThermostat * tauThermostat;
53     tb2 = tauBarostat * tauBarostat;
54    
55     instaTemp = tStats->getTemperature();
56 gezelter 577 tStats->getPressureTensor(press);
57    
58     for (i=0; i < 9; i++) press[i] *= p_convert;
59    
60 gezelter 576 instaVol = tStats->getVolume();
61    
62     // first evolve chi a half step
63    
64     chi += dt2 * ( instaTemp / targetTemp - 1.0) / tt2;
65    
66 gezelter 577 eta[0] += dt2 * instaVol * (press[0] - targetPressure) / (NkBT*tb2);
67     eta[1] += dt2 * instaVol * press[1] / (NkBT*tb2);
68     eta[2] += dt2 * instaVol * press[2] / (NkBT*tb2);
69     eta[3] += dt2 * instaVol * press[3] / (NkBT*tb2);
70     eta[4] += dt2 * instaVol * (press[4] - targetPressure) / (NkBT*tb2);
71     eta[5] += dt2 * instaVol * press[5] / (NkBT*tb2);
72     eta[6] += dt2 * instaVol * press[6] / (NkBT*tb2);
73     eta[7] += dt2 * instaVol * press[7] / (NkBT*tb2);
74     eta[8] += dt2 * instaVol * (press[8] - targetPressure) / (NkBT*tb2);
75    
76 gezelter 576 for( i=0; i<nAtoms; i++ ){
77     atomIndex = i * 3;
78     aMatIndex = i * 9;
79    
80     // velocity half step
81 gezelter 577
82     vx = vel[atomIndex];
83     vy = vel[atomIndex+1];
84     vz = vel[atomIndex+2];
85    
86     scx = (chi + eta[0])*vx + eta[1]*vy + eta[2]*vz;
87     scy = eta[3]*vx + (chi + eta[4])*vy + eta[5]*vz;
88     scz = eta[6]*vx + eta[7]*vy + (chi + eta[8])*vz;
89    
90     vx += dt2 * ((frc[atomIndex] /atoms[i]->getMass())*eConvert - scx);
91     vy += dt2 * ((frc[atomIndex+1]/atoms[i]->getMass())*eConvert - scy);
92     vz += dt2 * ((frc[atomIndex+2]/atoms[i]->getMass())*eConvert - scz);
93 gezelter 576
94 gezelter 577 vel[atomIndex] = vx;
95     vel[atomIndex+1] = vy;
96     vel[atomIndex+2] = vz;
97    
98 gezelter 576 // position whole step
99    
100 gezelter 577 rj[0] = pos[atomIndex];
101     rj[1] = pos[atomIndex+1];
102     rj[2] = pos[atomIndex+2];
103 gezelter 576
104 gezelter 577 info->wrapVector(rj);
105 gezelter 576
106 gezelter 577 scx = eta[0]*rj[0] + eta[1]*rj[1] + eta[2]*rj[2];
107     scy = eta[3]*rj[0] + eta[4]*rj[1] + eta[5]*rj[2];
108     scz = eta[6]*rj[0] + eta[7]*rj[1] + eta[8]*rj[2];
109 gezelter 576
110 gezelter 577 pos[atomIndex] += dt * (vel[atomIndex] + scx);
111     pos[atomIndex+1] += dt * (vel[atomIndex+1] + scy);
112     pos[atomIndex+2] += dt * (vel[atomIndex+2] + scz);
113 gezelter 576
114     if( atoms[i]->isDirectional() ){
115    
116     dAtom = (DirectionalAtom *)atoms[i];
117    
118     // get and convert the torque to body frame
119    
120     Tb[0] = dAtom->getTx();
121     Tb[1] = dAtom->getTy();
122     Tb[2] = dAtom->getTz();
123    
124     dAtom->lab2Body( Tb );
125    
126     // get the angular momentum, and propagate a half step
127    
128     ji[0] = dAtom->getJx();
129     ji[1] = dAtom->getJy();
130     ji[2] = dAtom->getJz();
131    
132     ji[0] += dt2 * (Tb[0] * eConvert - ji[0]*chi);
133     ji[1] += dt2 * (Tb[1] * eConvert - ji[1]*chi);
134     ji[2] += dt2 * (Tb[2] * eConvert - ji[2]*chi);
135    
136     // use the angular velocities to propagate the rotation matrix a
137     // full time step
138    
139     // rotate about the x-axis
140     angle = dt2 * ji[0] / dAtom->getIxx();
141     this->rotate( 1, 2, angle, ji, &Amat[aMatIndex] );
142    
143     // rotate about the y-axis
144     angle = dt2 * ji[1] / dAtom->getIyy();
145     this->rotate( 2, 0, angle, ji, &Amat[aMatIndex] );
146    
147     // rotate about the z-axis
148     angle = dt * ji[2] / dAtom->getIzz();
149     this->rotate( 0, 1, angle, ji, &Amat[aMatIndex] );
150    
151     // rotate about the y-axis
152     angle = dt2 * ji[1] / dAtom->getIyy();
153     this->rotate( 2, 0, angle, ji, &Amat[aMatIndex] );
154    
155     // rotate about the x-axis
156     angle = dt2 * ji[0] / dAtom->getIxx();
157     this->rotate( 1, 2, angle, ji, &Amat[aMatIndex] );
158    
159     dAtom->setJx( ji[0] );
160     dAtom->setJy( ji[1] );
161     dAtom->setJz( ji[2] );
162     }
163    
164     }
165 gezelter 577
166     // Scale the box after all the positions have been moved:
167    
168 gezelter 578 // Use a taylor expansion for eta products: Hmat = Hmat . exp(dt * etaMat)
169     // Hmat = Hmat . ( Ident + dt * etaMat + dt^2 * etaMat*etaMat / 2)
170 gezelter 577
171 gezelter 578
172     for(i=0; i<3; i++){
173     for(j=0; j<3; j++){
174     ident[i][j] = 0.0;
175     eta1[i][j] = eta[3*i+j];
176     eta2[i][j] = 0.0;
177     for(k=0; k<3; k++){
178     eta2[i][j] += eta[3*i+k] * eta[3*k+j];
179     }
180     }
181     ident[i][i] = 1.0;
182     }
183    
184 gezelter 577
185     info->getBoxM(hm);
186 gezelter 578
187     for(i=0; i<3; i++){
188     for(j=0; j<3; j++){
189     hmnew[i][j] = 0.0;
190     for(k=0; k<3; k++){
191     // remember that hmat has transpose ordering for Fortran compat:
192     hmnew[i][j] += hm[3*k+i] * (ident[k][j]
193     + dt * eta1[k][j]
194     + 0.5 * dt * dt * eta2[k][j]);
195     }
196     }
197     }
198 gezelter 577
199 gezelter 578 for (i = 0; i < 3; i++) {
200     for (j = 0; j < 3; j++) {
201     // remember that hmat has transpose ordering for Fortran compat:
202     hm[3*j + 1] = hmnew[i][j];
203     }
204     }
205 gezelter 577
206 gezelter 578 info->setBoxM(hm);
207    
208 gezelter 576 }
209    
210 gezelter 578 void NPTf::moveB( void ){
211 gezelter 576 int i,j,k;
212     int atomIndex;
213     DirectionalAtom* dAtom;
214     double Tb[3];
215     double ji[3];
216 gezelter 578 double press[9];
217     double instaTemp, instaVol;
218 gezelter 576 double tt2, tb2;
219 gezelter 578 double vx, vy, vz;
220     double scx, scy, scz;
221     const double p_convert = 1.63882576e8;
222 gezelter 576
223     tt2 = tauThermostat * tauThermostat;
224     tb2 = tauBarostat * tauBarostat;
225    
226     instaTemp = tStats->getTemperature();
227 gezelter 578 tStats->getPressureTensor(press);
228    
229     for (i=0; i < 9; i++) press[i] *= p_convert;
230    
231 gezelter 576 instaVol = tStats->getVolume();
232 gezelter 578
233     // first evolve chi a half step
234    
235 gezelter 576 chi += dt2 * ( instaTemp / targetTemp - 1.0) / tt2;
236    
237 gezelter 578 eta[0] += dt2 * instaVol * (press[0] - targetPressure) / (NkBT*tb2);
238     eta[1] += dt2 * instaVol * press[1] / (NkBT*tb2);
239     eta[2] += dt2 * instaVol * press[2] / (NkBT*tb2);
240     eta[3] += dt2 * instaVol * press[3] / (NkBT*tb2);
241     eta[4] += dt2 * instaVol * (press[4] - targetPressure) / (NkBT*tb2);
242     eta[5] += dt2 * instaVol * press[5] / (NkBT*tb2);
243     eta[6] += dt2 * instaVol * press[6] / (NkBT*tb2);
244     eta[7] += dt2 * instaVol * press[7] / (NkBT*tb2);
245     eta[8] += dt2 * instaVol * (press[8] - targetPressure) / (NkBT*tb2);
246    
247 gezelter 576 for( i=0; i<nAtoms; i++ ){
248     atomIndex = i * 3;
249 gezelter 578
250 gezelter 576 // velocity half step
251    
252 gezelter 578 vx = vel[atomIndex];
253     vy = vel[atomIndex+1];
254     vz = vel[atomIndex+2];
255    
256     scx = (chi + eta[0])*vx + eta[1]*vy + eta[2]*vz;
257     scy = eta[3]*vx + (chi + eta[4])*vy + eta[5]*vz;
258     scz = eta[6]*vx + eta[7]*vy + (chi + eta[8])*vz;
259    
260     vx += dt2 * ((frc[atomIndex] /atoms[i]->getMass())*eConvert - scx);
261     vy += dt2 * ((frc[atomIndex+1]/atoms[i]->getMass())*eConvert - scy);
262     vz += dt2 * ((frc[atomIndex+2]/atoms[i]->getMass())*eConvert - scz);
263    
264     vel[atomIndex] = vx;
265     vel[atomIndex+1] = vy;
266     vel[atomIndex+2] = vz;
267    
268 gezelter 576 if( atoms[i]->isDirectional() ){
269    
270     dAtom = (DirectionalAtom *)atoms[i];
271    
272     // get and convert the torque to body frame
273    
274     Tb[0] = dAtom->getTx();
275     Tb[1] = dAtom->getTy();
276     Tb[2] = dAtom->getTz();
277    
278     dAtom->lab2Body( Tb );
279    
280     // get the angular momentum, and complete the angular momentum
281     // half step
282    
283     ji[0] = dAtom->getJx();
284     ji[1] = dAtom->getJy();
285     ji[2] = dAtom->getJz();
286    
287     ji[0] += dt2 * (Tb[0] * eConvert - ji[0]*chi);
288     ji[1] += dt2 * (Tb[1] * eConvert - ji[1]*chi);
289     ji[2] += dt2 * (Tb[2] * eConvert - ji[2]*chi);
290    
291     dAtom->setJx( ji[0] );
292     dAtom->setJy( ji[1] );
293     dAtom->setJz( ji[2] );
294     }
295     }
296     }
297    
298     int NPTi::readyCheck() {
299    
300     // First check to see if we have a target temperature.
301     // Not having one is fatal.
302    
303     if (!have_target_temp) {
304     sprintf( painCave.errMsg,
305     "NPTi error: You can't use the NPTi integrator\n"
306     " without a targetTemp!\n"
307     );
308     painCave.isFatal = 1;
309     simError();
310     return -1;
311     }
312    
313     if (!have_target_pressure) {
314     sprintf( painCave.errMsg,
315     "NPTi error: You can't use the NPTi integrator\n"
316     " without a targetPressure!\n"
317     );
318     painCave.isFatal = 1;
319     simError();
320     return -1;
321     }
322    
323     // We must set tauThermostat.
324    
325     if (!have_tau_thermostat) {
326     sprintf( painCave.errMsg,
327     "NPTi error: If you use the NPTi\n"
328     " integrator, you must set tauThermostat.\n");
329     painCave.isFatal = 1;
330     simError();
331     return -1;
332     }
333    
334     // We must set tauBarostat.
335    
336     if (!have_tau_barostat) {
337     sprintf( painCave.errMsg,
338     "NPTi error: If you use the NPTi\n"
339     " integrator, you must set tauBarostat.\n");
340     painCave.isFatal = 1;
341     simError();
342     return -1;
343     }
344    
345     // We need NkBT a lot, so just set it here:
346    
347     NkBT = (double)info->ndf * kB * targetTemp;
348    
349     return 1;
350     }