ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/NPTim.cpp
Revision: 596
Committed: Mon Jul 14 15:04:55 2003 UTC (20 years, 11 months ago) by gezelter
File size: 7610 byte(s)
Log Message:
Working on NPTim

File Contents

# User Rev Content
1 gezelter 596 #include <cmath>
2     #include "Atom.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    
13     // Basic 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 NPTim variant scales the molecular center-of-mass coordinates
24     // instead of the atomic coordinates
25    
26     NPTim::NPTim ( SimInfo *theInfo, ForceFields* the_ff):
27     Integrator( theInfo, the_ff )
28     {
29     chi = 0.0;
30     eta = 0.0;
31     have_tau_thermostat = 0;
32     have_tau_barostat = 0;
33     have_target_temp = 0;
34     have_target_pressure = 0;
35     }
36    
37     void NPTim::moveA() {
38    
39     int i,j,k;
40     int nInMol, aMatIndex;
41     DirectionalAtom* dAtom;
42     Atom** theAtoms;
43     Molecule** myMols;
44     double Tb[3];
45     double ji[3];
46     double rc[3];
47     double mass;
48     double rx, ry, rz, vx, vy, vz, fx, fy, fz;
49     double instaTemp, instaPress, instaVol;
50     double tt2, tb2;
51     double angle;
52    
53     nMols = info->n_mol;
54     myMols = info->molecules;
55    
56     tt2 = tauThermostat * tauThermostat;
57     tb2 = tauBarostat * tauBarostat;
58    
59     instaTemp = tStats->getTemperature();
60     instaPress = tStats->getPressure();
61     instaVol = tStats->getVolume();
62    
63     // first evolve chi a half step
64    
65     chi += dt2 * ( instaTemp / targetTemp - 1.0) / tt2;
66     eta += dt2 * ( instaVol * (instaPress - targetPressure) /
67     (p_convert*NkBT*tb2));
68    
69     for( i = 0; i < nMols; i++) {
70    
71     myMols[i].getCOM(rc);
72    
73     nInMol = myMols[i]->getNAtoms();
74     theAtoms = myMols[i]->getMyAtoms();
75    
76     // find the minimum image coordinates of the molecular centers of mass:
77    
78     info->wrapVector(rc);
79    
80     for (j = 0; j < nInMol; j++) {
81    
82     if(theAtoms[j] != NULL) {
83    
84     aMatIndex = 9 * theAtoms[j]->getIndex();
85    
86     mass = theAtoms[j]->getMass();
87    
88     vx = theAtoms[j]->get_vx();
89     vy = theAtoms[j]->get_vy();
90     vz = theAtoms[j]->get_vz();
91    
92     fx = theAtoms[j]->getFx();
93     fy = theAtoms[j]->getFy();
94     fz = theAtoms[j]->getFz();
95    
96     rx = theAtoms[j]->getX();
97     ry = theAtoms[j]->getY();
98     rz = theAtoms[j]->getZ();
99    
100     // velocity half step
101    
102     vx += dt2 * ((fx / mass)*eConvert - vx*(chi+eta));
103     vy += dt2 * ((fy / mass)*eConvert - vy*(chi+eta));
104     vz += dt2 * ((fz / mass)*eConvert - vz*(chi+eta));
105    
106     // position whole step
107    
108     rx += dt*(vx + eta*rc[0]);
109     ry += dt*(vy + eta*rc[1]);
110     rz += dt*(vz + eta*rc[2]);
111    
112     theAtoms[j]->set_vx(vx);
113     theAtoms[j]->set_vy(vy);
114     theAtoms[j]->set_vz(vz);
115    
116     theAtoms[j]->setX(rx);
117     theAtoms[j]->setY(ry);
118     theAtoms[j]->setZ(rz);
119    
120     if( theAtoms[j]->isDirectional() ){
121    
122     dAtom = (DirectionalAtom *)theAtoms[j];
123    
124     // get and convert the torque to body frame
125    
126     Tb[0] = dAtom->getTx();
127     Tb[1] = dAtom->getTy();
128     Tb[2] = dAtom->getTz();
129    
130     dAtom->lab2Body( Tb );
131    
132     // get the angular momentum, and propagate a half step
133    
134     ji[0] = dAtom->getJx();
135     ji[1] = dAtom->getJy();
136     ji[2] = dAtom->getJz();
137    
138     ji[0] += dt2 * (Tb[0] * eConvert - ji[0]*chi);
139     ji[1] += dt2 * (Tb[1] * eConvert - ji[1]*chi);
140     ji[2] += dt2 * (Tb[2] * eConvert - ji[2]*chi);
141    
142     // use the angular velocities to propagate the rotation matrix a
143     // full time step
144    
145     // rotate about the x-axis
146     angle = dt2 * ji[0] / dAtom->getIxx();
147     this->rotate( 1, 2, angle, ji, &Amat[aMatIndex] );
148    
149     // rotate about the y-axis
150     angle = dt2 * ji[1] / dAtom->getIyy();
151     this->rotate( 2, 0, angle, ji, &Amat[aMatIndex] );
152    
153     // rotate about the z-axis
154     angle = dt * ji[2] / dAtom->getIzz();
155     this->rotate( 0, 1, angle, ji, &Amat[aMatIndex] );
156    
157     // rotate about the y-axis
158     angle = dt2 * ji[1] / dAtom->getIyy();
159     this->rotate( 2, 0, angle, ji, &Amat[aMatIndex] );
160    
161     // rotate about the x-axis
162     angle = dt2 * ji[0] / dAtom->getIxx();
163     this->rotate( 1, 2, angle, ji, &Amat[aMatIndex] );
164    
165     dAtom->setJx( ji[0] );
166     dAtom->setJy( ji[1] );
167     dAtom->setJz( ji[2] );
168     }
169    
170     }
171     }
172     }
173     // Scale the box after all the positions have been moved:
174    
175     cerr << "eta = " << eta
176     << "; exp(dt*eta) = " << exp(eta*dt) << "\n";
177    
178     info->scaleBox(exp(dt*eta));
179     }
180    
181     void NPTi::moveB( void ){
182     int i,j,k;
183     int atomIndex;
184     DirectionalAtom* dAtom;
185     double Tb[3];
186     double ji[3];
187     double instaTemp, instaPress, instaVol;
188     double tt2, tb2;
189    
190     tt2 = tauThermostat * tauThermostat;
191     tb2 = tauBarostat * tauBarostat;
192    
193     instaTemp = tStats->getTemperature();
194     instaPress = tStats->getPressure();
195     instaVol = tStats->getVolume();
196    
197     chi += dt2 * ( instaTemp / targetTemp - 1.0) / tt2;
198     eta += dt2 * ( instaVol * (instaPress - targetPressure) /
199     (p_convert*NkBT*tb2));
200    
201     for( i=0; i<nAtoms; i++ ){
202     atomIndex = i * 3;
203    
204     // velocity half step
205     for( j=atomIndex; j<(atomIndex+3); j++ )
206     for( j=atomIndex; j<(atomIndex+3); j++ )
207     vel[j] += dt2 * ((frc[j]/atoms[i]->getMass())*eConvert
208     - vel[j]*(chi+eta));
209    
210     if( atoms[i]->isDirectional() ){
211    
212     dAtom = (DirectionalAtom *)atoms[i];
213    
214     // get and convert the torque to body frame
215    
216     Tb[0] = dAtom->getTx();
217     Tb[1] = dAtom->getTy();
218     Tb[2] = dAtom->getTz();
219    
220     dAtom->lab2Body( Tb );
221    
222     // get the angular momentum, and complete the angular momentum
223     // half step
224    
225     ji[0] = dAtom->getJx();
226     ji[1] = dAtom->getJy();
227     ji[2] = dAtom->getJz();
228    
229     ji[0] += dt2 * (Tb[0] * eConvert - ji[0]*chi);
230     ji[1] += dt2 * (Tb[1] * eConvert - ji[1]*chi);
231     ji[2] += dt2 * (Tb[2] * eConvert - ji[2]*chi);
232    
233     dAtom->setJx( ji[0] );
234     dAtom->setJy( ji[1] );
235     dAtom->setJz( ji[2] );
236     }
237     }
238     }
239    
240     int NPTi::readyCheck() {
241    
242     // First check to see if we have a target temperature.
243     // Not having one is fatal.
244    
245     if (!have_target_temp) {
246     sprintf( painCave.errMsg,
247     "NPTi error: You can't use the NPTi integrator\n"
248     " without a targetTemp!\n"
249     );
250     painCave.isFatal = 1;
251     simError();
252     return -1;
253     }
254    
255     if (!have_target_pressure) {
256     sprintf( painCave.errMsg,
257     "NPTi error: You can't use the NPTi integrator\n"
258     " without a targetPressure!\n"
259     );
260     painCave.isFatal = 1;
261     simError();
262     return -1;
263     }
264    
265     // We must set tauThermostat.
266    
267     if (!have_tau_thermostat) {
268     sprintf( painCave.errMsg,
269     "NPTi error: If you use the NPTi\n"
270     " integrator, you must set tauThermostat.\n");
271     painCave.isFatal = 1;
272     simError();
273     return -1;
274     }
275    
276     // We must set tauBarostat.
277    
278     if (!have_tau_barostat) {
279     sprintf( painCave.errMsg,
280     "NPTi error: If you use the NPTi\n"
281     " integrator, you must set tauBarostat.\n");
282     painCave.isFatal = 1;
283     simError();
284     return -1;
285     }
286    
287     // We need NkBT a lot, so just set it here:
288    
289     NkBT = (double)info->ndf * kB * targetTemp;
290    
291     return 1;
292     }