ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/NPTi.cpp
Revision: 578
Committed: Wed Jul 9 02:15:29 2003 UTC (20 years, 11 months ago) by gezelter
File size: 6299 byte(s)
Log Message:
Fixes for both NPTf and NPTi

File Contents

# User Rev Content
1 gezelter 578 #include <cmath>
2 gezelter 574 #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     NPTi::NPTi ( SimInfo *theInfo, ForceFields* the_ff):
24     Integrator( theInfo, the_ff )
25     {
26     chi = 0.0;
27     eta = 0.0;
28     have_tau_thermostat = 0;
29     have_tau_barostat = 0;
30     have_target_temp = 0;
31     have_target_pressure = 0;
32     }
33    
34     void NPTi::moveA() {
35    
36     int i,j,k;
37     int atomIndex, aMatIndex;
38     DirectionalAtom* dAtom;
39     double Tb[3];
40     double ji[3];
41     double rj[3];
42     double instaTemp, instaPress, instaVol;
43     double tt2, tb2;
44     double angle;
45    
46     tt2 = tauThermostat * tauThermostat;
47     tb2 = tauBarostat * tauBarostat;
48    
49     instaTemp = tStats->getTemperature();
50     instaPress = tStats->getPressure();
51     instaVol = tStats->getVolume();
52    
53     // first evolve chi a half step
54    
55     chi += dt2 * ( instaTemp / targetTemp - 1.0) / tt2;
56     eta += dt2 * ( instaVol * (instaPress - targetPressure) / (NkBT*tb2));
57    
58     for( i=0; i<nAtoms; i++ ){
59     atomIndex = i * 3;
60     aMatIndex = i * 9;
61    
62     // velocity half step
63     for( j=atomIndex; j<(atomIndex+3); j++ )
64     vel[j] += dt2 * ((frc[j]/atoms[i]->getMass())*eConvert
65     - vel[j]*(chi+eta));
66    
67     // position whole step
68    
69 gezelter 577 rj[0] = pos[atomIndex];
70     rj[1] = pos[atomIndex+1];
71     rj[2] = pos[atomIndex+2];
72    
73     info->wrapVector(rj);
74 gezelter 574
75 gezelter 577 pos[atomIndex] += dt * (vel[atomIndex] + eta*rj[0]);
76     pos[atomIndex+1] += dt * (vel[atomIndex+1] + eta*rj[1]);
77     pos[atomIndex+2] += dt * (vel[atomIndex+2] + eta*rj[2]);
78 gezelter 574
79     if( atoms[i]->isDirectional() ){
80    
81     dAtom = (DirectionalAtom *)atoms[i];
82    
83     // get and convert the torque to body frame
84    
85     Tb[0] = dAtom->getTx();
86     Tb[1] = dAtom->getTy();
87     Tb[2] = dAtom->getTz();
88    
89     dAtom->lab2Body( Tb );
90    
91     // get the angular momentum, and propagate a half step
92    
93     ji[0] = dAtom->getJx();
94     ji[1] = dAtom->getJy();
95     ji[2] = dAtom->getJz();
96    
97     ji[0] += dt2 * (Tb[0] * eConvert - ji[0]*chi);
98     ji[1] += dt2 * (Tb[1] * eConvert - ji[1]*chi);
99     ji[2] += dt2 * (Tb[2] * eConvert - ji[2]*chi);
100    
101     // use the angular velocities to propagate the rotation matrix a
102     // full time step
103    
104     // rotate about the x-axis
105     angle = dt2 * ji[0] / dAtom->getIxx();
106     this->rotate( 1, 2, angle, ji, &Amat[aMatIndex] );
107    
108     // rotate about the y-axis
109     angle = dt2 * ji[1] / dAtom->getIyy();
110     this->rotate( 2, 0, angle, ji, &Amat[aMatIndex] );
111    
112     // rotate about the z-axis
113     angle = dt * ji[2] / dAtom->getIzz();
114     this->rotate( 0, 1, angle, ji, &Amat[aMatIndex] );
115    
116     // rotate about the y-axis
117     angle = dt2 * ji[1] / dAtom->getIyy();
118     this->rotate( 2, 0, angle, ji, &Amat[aMatIndex] );
119    
120     // rotate about the x-axis
121     angle = dt2 * ji[0] / dAtom->getIxx();
122     this->rotate( 1, 2, angle, ji, &Amat[aMatIndex] );
123    
124     dAtom->setJx( ji[0] );
125     dAtom->setJy( ji[1] );
126     dAtom->setJz( ji[2] );
127     }
128    
129     }
130 gezelter 577 // Scale the box after all the positions have been moved:
131    
132     info->scaleBox(exp(dt*eta));
133    
134 gezelter 574 }
135    
136     void NPTi::moveB( void ){
137     int i,j,k;
138     int atomIndex;
139     DirectionalAtom* dAtom;
140     double Tb[3];
141     double ji[3];
142     double instaTemp, instaPress, instaVol;
143     double tt2, tb2;
144    
145     tt2 = tauThermostat * tauThermostat;
146     tb2 = tauBarostat * tauBarostat;
147    
148     instaTemp = tStats->getTemperature();
149     instaPress = tStats->getPressure();
150     instaVol = tStats->getVolume();
151    
152     chi += dt2 * ( instaTemp / targetTemp - 1.0) / tt2;
153     eta += dt2 * ( instaVol * (instaPress - targetPressure) / (NkBT*tb2));
154    
155     for( i=0; i<nAtoms; i++ ){
156     atomIndex = i * 3;
157    
158     // velocity half step
159     for( j=atomIndex; j<(atomIndex+3); j++ )
160     for( j=atomIndex; j<(atomIndex+3); j++ )
161     vel[j] += dt2 * ((frc[j]/atoms[i]->getMass())*eConvert
162     - vel[j]*(chi+eta));
163    
164     if( atoms[i]->isDirectional() ){
165    
166     dAtom = (DirectionalAtom *)atoms[i];
167    
168     // get and convert the torque to body frame
169    
170     Tb[0] = dAtom->getTx();
171     Tb[1] = dAtom->getTy();
172     Tb[2] = dAtom->getTz();
173    
174     dAtom->lab2Body( Tb );
175    
176     // get the angular momentum, and complete the angular momentum
177     // half step
178    
179     ji[0] = dAtom->getJx();
180     ji[1] = dAtom->getJy();
181     ji[2] = dAtom->getJz();
182    
183     ji[0] += dt2 * (Tb[0] * eConvert - ji[0]*chi);
184     ji[1] += dt2 * (Tb[1] * eConvert - ji[1]*chi);
185     ji[2] += dt2 * (Tb[2] * eConvert - ji[2]*chi);
186    
187     dAtom->setJx( ji[0] );
188     dAtom->setJy( ji[1] );
189     dAtom->setJz( ji[2] );
190     }
191     }
192     }
193    
194     int NPTi::readyCheck() {
195    
196     // First check to see if we have a target temperature.
197     // Not having one is fatal.
198    
199     if (!have_target_temp) {
200     sprintf( painCave.errMsg,
201     "NPTi error: You can't use the NPTi integrator\n"
202     " without a targetTemp!\n"
203     );
204     painCave.isFatal = 1;
205     simError();
206     return -1;
207     }
208    
209     if (!have_target_pressure) {
210     sprintf( painCave.errMsg,
211     "NPTi error: You can't use the NPTi integrator\n"
212     " without a targetPressure!\n"
213     );
214     painCave.isFatal = 1;
215     simError();
216     return -1;
217     }
218    
219     // We must set tauThermostat.
220    
221     if (!have_tau_thermostat) {
222     sprintf( painCave.errMsg,
223     "NPTi error: If you use the NPTi\n"
224     " integrator, you must set tauThermostat.\n");
225     painCave.isFatal = 1;
226     simError();
227     return -1;
228     }
229    
230     // We must set tauBarostat.
231    
232     if (!have_tau_barostat) {
233     sprintf( painCave.errMsg,
234     "NPTi error: If you use the NPTi\n"
235     " integrator, you must set tauBarostat.\n");
236     painCave.isFatal = 1;
237     simError();
238     return -1;
239     }
240    
241     // We need NkBT a lot, so just set it here:
242    
243     NkBT = (double)info->ndf * kB * targetTemp;
244    
245     return 1;
246     }