ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/NPT.cpp
Revision: 778
Committed: Fri Sep 19 20:00:27 2003 UTC (20 years, 9 months ago) by mmeineke
File size: 7719 byte(s)
Log Message:
added NPT base class. NPTi is up to date. NPTf is not.

File Contents

# Content
1 #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 #ifdef IS_MPI
13 #include "mpiSimulation.hpp"
14 #endif
15
16
17 // Basic isotropic thermostating and barostating via the Melchionna
18 // modification of the Hoover algorithm:
19 //
20 // Melchionna, S., Ciccotti, G., and Holian, B. L., 1993,
21 // Molec. Phys., 78, 533.
22 //
23 // and
24 //
25 // Hoover, W. G., 1986, Phys. Rev. A, 34, 2499.
26
27 template<typename T> NPT<T>::NPT ( SimInfo *theInfo, ForceFields* the_ff):
28 T( theInfo, the_ff )
29 {
30 chi = 0.0;
31 integralOfChidt = 0.0;
32 have_tau_thermostat = 0;
33 have_tau_barostat = 0;
34 have_target_temp = 0;
35 have_target_pressure = 0;
36 have_chi_tolerance = 0;
37 have_eta_tolerance = 0;
38 have_pos_iter_tolerance = 0;
39
40 oldPos = new double[3*nAtoms];
41 oldVel = new double[3*nAtoms];
42 oldJi = new double[3*nAtoms];
43 #ifdef IS_MPI
44 Nparticles = mpiSim->getTotAtoms();
45 #else
46 Nparticles = theInfo->n_atoms;
47 #endif
48
49 }
50
51 template<typename T> NPT<T>::~NPT() {
52 delete[] oldPos;
53 delete[] oldVel;
54 delete[] oldJi;
55 }
56
57 template<typename T> void NPT<T>::moveA() {
58
59 //new version of NPT
60 int i, j, k;
61 DirectionalAtom* dAtom;
62 double Tb[3], ji[3];
63 double mass;
64 double vel[3], pos[3], frc[3];
65 double sc[3];
66 double COM[3];
67
68 instaTemp = tStats->getTemperature();
69 instaPress = tStats->getPressure();
70 instaVol = tStats->getVolume();
71
72 tStats->getCOM(COM);
73
74 //evolve velocity half step
75 for( i=0; i<nAtoms; i++ ){
76
77 atoms[i]->getVel( vel );
78 atoms[i]->getFrc( frc );
79
80 mass = atoms[i]->getMass();
81
82 getVelScaleA( sc, vel );
83
84 for (j=0; j < 3; j++) {
85
86 // velocity half step (use chi from previous step here):
87 vel[j] += dt2 * ((frc[j] / mass ) * eConvert - sc[j]);
88
89 }
90
91 atoms[i]->setVel( vel );
92
93 if( atoms[i]->isDirectional() ){
94
95 dAtom = (DirectionalAtom *)atoms[i];
96
97 // get and convert the torque to body frame
98
99 dAtom->getTrq( Tb );
100 dAtom->lab2Body( Tb );
101
102 // get the angular momentum, and propagate a half step
103
104 dAtom->getJ( ji );
105
106 for (j=0; j < 3; j++)
107 ji[j] += dt2 * (Tb[j] * eConvert - ji[j]*chi);
108
109 this->rotationPropagation( dAtom, ji );
110
111 dAtom->setJ( ji );
112 }
113 }
114
115 // evolve chi and eta half step
116
117 evolveChiA();
118 evolveEtaA();
119
120 //calculate the integral of chidt
121 integralOfChidt += dt2*chi;
122
123 //save the old positions
124 for(i = 0; i < nAtoms; i++){
125 atoms[i]->getPos(pos);
126 for(j = 0; j < 3; j++)
127 oldPos[i*3 + j] = pos[j];
128 }
129
130 //the first estimation of r(t+dt) is equal to r(t)
131
132 for(k = 0; k < 5; k ++){
133
134 for(i =0 ; i < nAtoms; i++){
135
136 atoms[i]->getVel(vel);
137 atoms[i]->getPos(pos);
138
139 this->getPosScale( pos, COM, i, sc );
140
141 for(j = 0; j < 3; j++)
142 pos[j] = oldPos[i*3 + j] + dt*(vel[j] + sc[j]);
143
144 atoms[i]->setPos( pos );
145 }
146
147 if (nConstrained){
148 constrainA();
149 }
150 }
151
152
153 // Scale the box after all the positions have been moved:
154
155 this->scaleSimBox();
156 }
157
158 template<typename T> void NPT<T>::moveB( void ){
159
160 //new version of NPT
161 int i, j, k;
162 DirectionalAtom* dAtom;
163 double Tb[3], ji[3], sc[3];
164 double vel[3], frc[3];
165 double mass;
166
167 // Set things up for the iteration:
168
169 for( i=0; i<nAtoms; i++ ){
170
171 atoms[i]->getVel( vel );
172
173 for (j=0; j < 3; j++)
174 oldVel[3*i + j] = vel[j];
175
176 if( atoms[i]->isDirectional() ){
177
178 dAtom = (DirectionalAtom *)atoms[i];
179
180 dAtom->getJ( ji );
181
182 for (j=0; j < 3; j++)
183 oldJi[3*i + j] = ji[j];
184
185 }
186 }
187
188 // do the iteration:
189
190 instaVol = tStats->getVolume();
191
192 for (k=0; k < 4; k++) {
193
194 instaTemp = tStats->getTemperature();
195 instaPress = tStats->getPressure();
196
197 // evolve chi another half step using the temperature at t + dt/2
198
199 this->evolveChiB();
200 this->evolveEtaB();
201
202 for( i=0; i<nAtoms; i++ ){
203
204 atoms[i]->getFrc( frc );
205 atoms[i]->getVel(vel);
206
207 mass = atoms[i]->getMass();
208
209 getVelScaleB( sc, i );
210
211 // velocity half step
212 for (j=0; j < 3; j++)
213 vel[j] = oldVel[3*i+j] + dt2 * ((frc[j] / mass ) * eConvert - sc[j]);
214
215 atoms[i]->setVel( vel );
216
217 if( atoms[i]->isDirectional() ){
218
219 dAtom = (DirectionalAtom *)atoms[i];
220
221 // get and convert the torque to body frame
222
223 dAtom->getTrq( Tb );
224 dAtom->lab2Body( Tb );
225
226 for (j=0; j < 3; j++)
227 ji[j] = oldJi[3*i + j] + dt2 * (Tb[j] * eConvert - oldJi[3*i+j]*chi);
228
229 dAtom->setJ( ji );
230 }
231 }
232
233 if (nConstrained){
234 constrainB();
235 }
236
237 if ( this->chiConverged() && this->etaConverged() ) break;
238 }
239
240 //calculate integral of chida
241 integralOfChidt += dt2*chi;
242
243
244 }
245
246 template<typename T> void NPT<T>::resetIntegrator() {
247 chi = 0.0;
248 T::resetIntegrator();
249 }
250
251 template<typename T> void NPT<T>::evolveChiA() {
252 chi += dt2 * ( instaTemp / targetTemp - 1.0) / tt2;
253 oldChi = chi;
254 }
255
256 template<typename T> void NPT<T>::evolveChiB() {
257
258 prevChi = chi;
259 chi = oldChi + dt2 * ( instaTemp / targetTemp - 1.0) / tt2;
260 }
261
262 template<typename T> bool NPT<T>::chiConverged() {
263
264 return ( fabs( prevChi - chi ) <= chiTolerance );
265 }
266
267 template<typename T> int NPT<T>::readyCheck() {
268
269 //check parent's readyCheck() first
270 if (T::readyCheck() == -1)
271 return -1;
272
273 // First check to see if we have a target temperature.
274 // Not having one is fatal.
275
276 if (!have_target_temp) {
277 sprintf( painCave.errMsg,
278 "NPT error: You can't use the NPT integrator\n"
279 " without a targetTemp!\n"
280 );
281 painCave.isFatal = 1;
282 simError();
283 return -1;
284 }
285
286 if (!have_target_pressure) {
287 sprintf( painCave.errMsg,
288 "NPT error: You can't use the NPT integrator\n"
289 " without a targetPressure!\n"
290 );
291 painCave.isFatal = 1;
292 simError();
293 return -1;
294 }
295
296 // We must set tauThermostat.
297
298 if (!have_tau_thermostat) {
299 sprintf( painCave.errMsg,
300 "NPT error: If you use the NPT\n"
301 " integrator, you must set tauThermostat.\n");
302 painCave.isFatal = 1;
303 simError();
304 return -1;
305 }
306
307 // We must set tauBarostat.
308
309 if (!have_tau_barostat) {
310 sprintf( painCave.errMsg,
311 "NPT error: If you use the NPT\n"
312 " integrator, you must set tauBarostat.\n");
313 painCave.isFatal = 1;
314 simError();
315 return -1;
316 }
317
318 if (!have_chi_tolerance) {
319 sprintf( painCave.errMsg,
320 "NPT warning: setting chi tolerance to 1e-6\n");
321 chiTolerance = 1e-6;
322 have_chi_tolerance = 1;
323 painCave.isFatal = 0;
324 simError();
325 }
326
327 if (!have_eta_tolerance) {
328 sprintf( painCave.errMsg,
329 "NPT warning: setting eta tolerance to 1e-6\n");
330 etaTolerance = 1e-6;
331 have_eta_tolerance = 1;
332 painCave.isFatal = 0;
333 simError();
334 }
335
336 // We need NkBT a lot, so just set it here: This is the RAW number
337 // of particles, so no subtraction or addition of constraints or
338 // orientational degrees of freedom:
339
340 NkBT = (double)Nparticles * kB * targetTemp;
341
342 // fkBT is used because the thermostat operates on more degrees of freedom
343 // than the barostat (when there are particles with orientational degrees
344 // of freedom). ndf = 3 * (n_atoms + n_oriented -1) - n_constraint - nZcons
345
346 fkBT = (double)info->ndf * kB * targetTemp;
347
348 tt2 = tauThermostat * tauThermostat;
349 tb2 = tauBarostat * tauBarostat;
350
351 return 1;
352 }