ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/NPTfm.cpp
Revision: 746
Committed: Thu Sep 4 21:48:35 2003 UTC (21 years ago) by mmeineke
File size: 10065 byte(s)
Log Message:
added resetTime to the Global namespace.

added ability to reset the integrators in the NVT and NPT family.

File Contents

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