ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/branches/new-templateless/OOPSE/libmdtools/NPT.cpp
Revision: 852
Committed: Thu Nov 6 18:20:47 2003 UTC (21 years, 8 months ago) by mmeineke
File size: 7804 byte(s)
Log Message:
fixed the "Sudden Death" bug.
	The box was not switching between orthorhombic and non-orthorhombic wrapping correctly.
	we added a fabs() to the check.which should fix it.

File Contents

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