ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/NPTim.cpp
Revision: 604
Committed: Tue Jul 15 03:08:00 2003 UTC (20 years, 11 months ago) by gezelter
File size: 6435 byte(s)
Log Message:
Checking in changes for NPTim

File Contents

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