ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/NPTfm.cpp
Revision: 763
Committed: Mon Sep 15 16:52:02 2003 UTC (21 years ago) by tim
File size: 10662 byte(s)
Log Message:
add conserved quantity to statWriter
fix bug of vector wrapping at NPTi

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