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

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