ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/NPTf.cpp
Revision: 617
Committed: Tue Jul 15 19:56:08 2003 UTC (20 years, 11 months ago) by gezelter
File size: 8987 byte(s)
Log Message:
Fixes for the NPT ensembles

File Contents

# Content
1 #include <cmath>
2 #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 // Basic non-isotropic thermostating and barostating via the Melchionna
14 // 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 NPTf::NPTf ( SimInfo *theInfo, ForceFields* the_ff):
24 Integrator( theInfo, the_ff )
25 {
26 int i, j;
27 chi = 0.0;
28
29 for(i = 0; i < 3; i++)
30 for (j = 0; j < 3; j++)
31 eta[i][j] = 0.0;
32
33 have_tau_thermostat = 0;
34 have_tau_barostat = 0;
35 have_target_temp = 0;
36 have_target_pressure = 0;
37 }
38
39 void NPTf::moveA() {
40
41 int i, j, k;
42 DirectionalAtom* dAtom;
43 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 double press[3][3], vScale[3][3], hm[3][3], hmnew[3][3], scaleMat[3][3];
54 double bigScale, smallScale, offDiagMax;
55
56 tt2 = tauThermostat * tauThermostat;
57 tb2 = tauBarostat * tauBarostat;
58
59 instaTemp = tStats->getTemperature();
60 tStats->getPressureTensor(press);
61 instaVol = tStats->getVolume();
62
63 // first evolve chi a half step
64
65 chi += dt2 * ( instaTemp / targetTemp - 1.0) / tt2;
66
67 for (i = 0; i < 3; i++ ) {
68 for (j = 0; j < 3; j++ ) {
69 if (i == j) {
70
71 eta[i][j] += dt2 * instaVol *
72 (press[i][j] - targetPressure/p_convert) / (NkBT*tb2);
73
74 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 for( i=0; i<nAtoms; i++ ){
87
88 atoms[i]->getVel( vel );
89 atoms[i]->getPos( pos );
90 atoms[i]->getFrc( frc );
91
92 mass = atoms[i]->getMass();
93
94 // velocity half step
95
96 info->matVecMul3( vScale, vel, sc );
97
98 for (j = 0; j < 3; j++) {
99 vel[j] += dt2 * ((frc[j] / mass) * eConvert - sc[j]);
100 rj[j] = pos[j];
101 }
102
103 atoms[i]->setVel( vel );
104
105 // position whole step
106
107 info->wrapVector(rj);
108
109 info->matVecMul3( eta, rj, sc );
110
111 for (j = 0; j < 3; j++ )
112 pos[j] += dt * (vel[j] + sc[j]);
113
114 atoms[i]->setPos( pos );
115
116 if( atoms[i]->isDirectional() ){
117
118 dAtom = (DirectionalAtom *)atoms[i];
119
120 // get and convert the torque to body frame
121
122 dAtom->getTrq( Tb );
123 dAtom->lab2Body( Tb );
124
125 // get the angular momentum, and propagate a half step
126
127 dAtom->getJ( ji );
128
129 for (j=0; j < 3; j++)
130 ji[j] += dt2 * (Tb[j] * eConvert - ji[j]*chi);
131
132 // use the angular velocities to propagate the rotation matrix a
133 // full time step
134
135 dAtom->getA(A);
136 dAtom->getI(I);
137
138 // rotate about the x-axis
139 angle = dt2 * ji[0] / I[0][0];
140 this->rotate( 1, 2, angle, ji, A );
141
142 // rotate about the y-axis
143 angle = dt2 * ji[1] / I[1][1];
144 this->rotate( 2, 0, angle, ji, A );
145
146 // rotate about the z-axis
147 angle = dt * ji[2] / I[2][2];
148 this->rotate( 0, 1, angle, ji, A);
149
150 // rotate about the y-axis
151 angle = dt2 * ji[1] / I[1][1];
152 this->rotate( 2, 0, angle, ji, A );
153
154 // rotate about the x-axis
155 angle = dt2 * ji[0] / I[0][0];
156 this->rotate( 1, 2, angle, ji, A );
157
158 dAtom->setJ( ji );
159 dAtom->setA( A );
160 }
161 }
162
163 // Scale the box after all the positions have been moved:
164
165 // Use a taylor expansion for eta products: Hmat = Hmat . exp(dt * etaMat)
166 // Hmat = Hmat . ( Ident + dt * etaMat + dt^2 * etaMat*etaMat / 2)
167
168 bigScale = 1.0;
169 smallScale = 1.0;
170 offDiagMax = 0.0;
171
172 for(i=0; i<3; i++){
173 for(j=0; j<3; j++){
174
175 // Calculate the matrix Product of the eta array (we only need
176 // the ij element right now):
177
178 eta2ij = 0.0;
179 for(k=0; k<3; k++){
180 eta2ij += eta[i][k] * eta[k][j];
181 }
182
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
189 if (i != j)
190 if (fabs(scaleMat[i][j]) > offDiagMax)
191 offDiagMax = fabs(scaleMat[i][j]);
192
193 }
194
195 if (scaleMat[i][i] > bigScale) bigScale = scaleMat[i][i];
196 if (scaleMat[i][i] < smallScale) smallScale = scaleMat[i][i];
197 }
198
199 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
229 }
230
231 void NPTf::moveB( void ){
232
233 int i, j;
234 DirectionalAtom* dAtom;
235 double Tb[3], ji[3];
236 double vel[3], frc[3];
237 double mass;
238
239 double instaTemp, instaPress, instaVol;
240 double tt2, tb2;
241 double sc[3];
242 double press[3][3], vScale[3][3];
243
244 tt2 = tauThermostat * tauThermostat;
245 tb2 = tauBarostat * tauBarostat;
246
247 instaTemp = tStats->getTemperature();
248 tStats->getPressureTensor(press);
249 instaVol = tStats->getVolume();
250
251 // first evolve chi a half step
252
253 chi += dt2 * ( instaTemp / targetTemp - 1.0) / tt2;
254
255 for (i = 0; i < 3; i++ ) {
256 for (j = 0; j < 3; j++ ) {
257 if (i == j) {
258
259 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 for( i=0; i<nAtoms; i++ ){
275
276 atoms[i]->getVel( vel );
277 atoms[i]->getFrc( frc );
278
279 mass = atoms[i]->getMass();
280
281 // velocity half step
282
283 info->matVecMul3( vScale, vel, sc );
284
285 for (j = 0; j < 3; j++) {
286 vel[j] += dt2 * ((frc[j] / mass) * eConvert - sc[j]);
287 }
288
289 atoms[i]->setVel( vel );
290
291 if( atoms[i]->isDirectional() ){
292
293 dAtom = (DirectionalAtom *)atoms[i];
294
295 // get and convert the torque to body frame
296
297 dAtom->getTrq( Tb );
298 dAtom->lab2Body( Tb );
299
300 // get the angular momentum, and propagate a half step
301
302 dAtom->getJ( ji );
303
304 for (j=0; j < 3; j++)
305 ji[j] += dt2 * (Tb[j] * eConvert - ji[j]*chi);
306
307 dAtom->setJ( ji );
308
309 }
310 }
311 }
312
313 int NPTf::readyCheck() {
314
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 "NPTf error: You can't use the NPTf integrator\n"
321 " 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 "NPTf error: You can't use the NPTf integrator\n"
331 " 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 "NPTf error: If you use the NPTf\n"
343 " 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 "NPTf error: If you use the NPTf\n"
354 " 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 }