ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/NPT.cpp
Revision: 857
Committed: Fri Nov 7 17:09:48 2003 UTC (20 years, 8 months ago) by mmeineke
File size: 8249 byte(s)
Log Message:
moved the velocity scale matrix calculation outside of the atom loop in the NPT family of integrators.

File Contents

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