ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/NPTfm.cpp
Revision: 606
Committed: Tue Jul 15 03:28:05 2003 UTC (20 years, 11 months ago) by gezelter
File size: 8152 byte(s)
Log Message:
Added NPTfm

File Contents

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