ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/NPTf.cpp
Revision: 645
Committed: Tue Jul 22 19:54:52 2003 UTC (20 years, 11 months ago) by tim
File size: 9074 byte(s)
Log Message:
*** empty log message ***

File Contents

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