ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/NPTf.cpp
Revision: 600
Committed: Mon Jul 14 22:38:13 2003 UTC (20 years, 11 months ago) by gezelter
File size: 7406 byte(s)
Log Message:
Fixes for get and set routines in Atom and DirectionalAtom

File Contents

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