ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/integrators/NPA.cpp
Revision: 2011
Committed: Wed Aug 6 19:27:37 2014 UTC (10 years, 8 months ago) by gezelter
File size: 10229 byte(s)
Log Message:
Added NPA integrator

File Contents

# User Rev Content
1 gezelter 2011 /*
2     * Copyright (c) 2005 The University of Notre Dame. All Rights Reserved.
3     *
4     * The University of Notre Dame grants you ("Licensee") a
5     * non-exclusive, royalty free, license to use, modify and
6     * redistribute this software in source and binary code form, provided
7     * that the following conditions are met:
8     *
9     * 1. Redistributions of source code must retain the above copyright
10     * notice, this list of conditions and the following disclaimer.
11     *
12     * 2. Redistributions in binary form must reproduce the above copyright
13     * notice, this list of conditions and the following disclaimer in the
14     * documentation and/or other materials provided with the
15     * distribution.
16     *
17     * This software is provided "AS IS," without a warranty of any
18     * kind. All express or implied conditions, representations and
19     * warranties, including any implied warranty of merchantability,
20     * fitness for a particular purpose or non-infringement, are hereby
21     * excluded. The University of Notre Dame and its licensors shall not
22     * be liable for any damages suffered by licensee as a result of
23     * using, modifying or distributing the software or its
24     * derivatives. In no event will the University of Notre Dame or its
25     * licensors be liable for any lost revenue, profit or data, or for
26     * direct, indirect, special, consequential, incidental or punitive
27     * damages, however caused and regardless of the theory of liability,
28     * arising out of the use of or inability to use software, even if the
29     * University of Notre Dame has been advised of the possibility of
30     * such damages.
31     *
32     * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
33     * research, please cite the appropriate papers when you publish your
34     * work. Good starting points are:
35     *
36     * [1] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
37     * [2] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
38     * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 234107 (2008).
39     * [4] Kuang & Gezelter, J. Chem. Phys. 133, 164101 (2010).
40     * [5] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011).
41     */
42    
43     #include "brains/SimInfo.hpp"
44     #include "brains/Thermo.hpp"
45     #include "integrators/IntegratorCreator.hpp"
46     #include "integrators/NPA.hpp"
47     #include "primitives/Molecule.hpp"
48     #include "utils/PhysicalConstants.hpp"
49     #include "utils/simError.h"
50    
51     namespace OpenMD {
52    
53     void NPA::moveA() {
54     SimInfo::MoleculeIterator i;
55     Molecule::IntegrableObjectIterator j;
56     Molecule* mol;
57     StuntDouble* sd;
58     Vector3d Tb, ji;
59     RealType mass;
60     Vector3d vel;
61     Vector3d pos;
62     Vector3d frc;
63     Vector3d sc;
64     int index;
65    
66     loadEta();
67    
68     instaTemp =thermo.getTemperature();
69     press = thermo.getPressureTensor();
70     instaPress = PhysicalConstants::pressureConvert* (press(0, 0) +
71     press(1, 1) +
72     press(2, 2)) / 3.0;
73     instaVol =thermo.getVolume();
74    
75     Vector3d COM = thermo.getCom();
76    
77     //evolve velocity half step
78    
79     calcVelScale();
80    
81     for (mol = info_->beginMolecule(i); mol != NULL;
82     mol = info_->nextMolecule(i)) {
83    
84     for (sd = mol->beginIntegrableObject(j); sd != NULL;
85     sd = mol->nextIntegrableObject(j)) {
86    
87     vel = sd->getVel();
88     frc = sd->getFrc();
89    
90     mass = sd->getMass();
91    
92     getVelScaleA(sc, vel);
93    
94     // velocity half step (use chi from previous step here):
95    
96     vel += dt2*PhysicalConstants::energyConvert/mass* frc - dt2*sc;
97     sd->setVel(vel);
98    
99     if (sd->isDirectional()) {
100    
101     // get and convert the torque to body frame
102    
103     Tb = sd->lab2Body(sd->getTrq());
104    
105     // get the angular momentum, and propagate a half step
106    
107     ji = sd->getJ();
108    
109     ji += dt2*PhysicalConstants::energyConvert * Tb
110     - dt2*thermostat.first* ji;
111    
112     rotAlgo_->rotate(sd, ji, dt);
113    
114     sd->setJ(ji);
115     }
116     }
117     }
118     // evolve eta a half step
119    
120     evolveEtaA();
121     flucQ_->moveA();
122    
123     index = 0;
124     for (mol = info_->beginMolecule(i); mol != NULL;
125     mol = info_->nextMolecule(i)) {
126    
127     for (sd = mol->beginIntegrableObject(j); sd != NULL;
128     sd = mol->nextIntegrableObject(j)) {
129    
130     oldPos[index++] = sd->getPos();
131    
132     }
133     }
134    
135     //the first estimation of r(t+dt) is equal to r(t)
136    
137     for(int k = 0; k < maxIterNum_; k++) {
138     index = 0;
139     for (mol = info_->beginMolecule(i); mol != NULL;
140     mol = info_->nextMolecule(i)) {
141    
142     for (sd = mol->beginIntegrableObject(j); sd != NULL;
143     sd = mol->nextIntegrableObject(j)) {
144    
145     vel = sd->getVel();
146     pos = sd->getPos();
147    
148     this->getPosScale(pos, COM, index, sc);
149    
150     pos = oldPos[index] + dt * (vel + sc);
151     sd->setPos(pos);
152    
153     ++index;
154     }
155     }
156    
157     rattle_->constraintA();
158     }
159    
160     // Scale the box after all the positions have been moved:
161    
162     this->scaleSimBox();
163    
164     saveEta();
165     }
166    
167     void NPA::moveB(void) {
168     SimInfo::MoleculeIterator i;
169     Molecule::IntegrableObjectIterator j;
170     Molecule* mol;
171     StuntDouble* sd;
172     int index;
173     Vector3d Tb;
174     Vector3d ji;
175     Vector3d sc;
176     Vector3d vel;
177     Vector3d frc;
178     RealType mass;
179    
180     loadEta();
181    
182     //save velocity and angular momentum
183     index = 0;
184     for (mol = info_->beginMolecule(i); mol != NULL;
185     mol = info_->nextMolecule(i)) {
186    
187     for (sd = mol->beginIntegrableObject(j); sd != NULL;
188     sd = mol->nextIntegrableObject(j)) {
189    
190     oldVel[index] = sd->getVel();
191    
192     if (sd->isDirectional())
193     oldJi[index] = sd->getJ();
194    
195     ++index;
196     }
197     }
198    
199     instaVol = thermo.getVolume();
200     instaTemp = thermo.getTemperature();
201     instaPress = thermo.getPressure();
202    
203     //evolve eta
204     this->evolveEtaB();
205     this->calcVelScale();
206    
207     index = 0;
208     for (mol = info_->beginMolecule(i); mol != NULL;
209     mol = info_->nextMolecule(i)) {
210    
211     for (sd = mol->beginIntegrableObject(j); sd != NULL;
212     sd = mol->nextIntegrableObject(j)) {
213    
214     frc = sd->getFrc();
215     mass = sd->getMass();
216    
217     getVelScaleB(sc, index);
218    
219     // velocity half step
220     vel = oldVel[index]
221     + dt2*PhysicalConstants::energyConvert/mass* frc
222     - dt2*sc;
223    
224     sd->setVel(vel);
225    
226     if (sd->isDirectional()) {
227     // get and convert the torque to body frame
228     Tb = sd->lab2Body(sd->getTrq());
229    
230     ji = oldJi[index]
231     + dt2*PhysicalConstants::energyConvert*Tb
232     - dt2*thermostat.first*oldJi[index];
233    
234     sd->setJ(ji);
235     }
236    
237     ++index;
238     }
239     }
240    
241     rattle_->constraintB();
242    
243     flucQ_->moveB();
244     saveEta();
245     }
246    
247     void NPA::evolveEtaA() {
248    
249     eta(2,2) += dt2 * instaVol * (press(2, 2) - targetPressure/PhysicalConstants::pressureConvert) / (NkBT*tb2);
250     oldEta = eta;
251     }
252    
253     void NPA::evolveEtaB() {
254    
255     prevEta = eta;
256     eta(2,2) = oldEta(2, 2) + dt2 * instaVol *
257     (press(2, 2) - targetPressure/PhysicalConstants::pressureConvert) / (NkBT*tb2);
258     }
259    
260     void NPA::calcVelScale(){
261    
262     for (int i = 0; i < 3; i++ ) {
263     for (int j = 0; j < 3; j++ ) {
264     vScale(i, j) = eta(i, j);
265     }
266     }
267     }
268    
269     void NPA::getVelScaleA(Vector3d& sc, const Vector3d& vel){
270     sc = vScale * vel;
271     }
272    
273     void NPA::getVelScaleB(Vector3d& sc, int index ) {
274     sc = vScale * oldVel[index];
275     }
276    
277     void NPA::getPosScale(const Vector3d& pos, const Vector3d& COM, int index,
278     Vector3d& sc) {
279    
280     Vector3d rj = (oldPos[index] + pos)/(RealType)2.0 -COM;
281     sc = eta * rj;
282     }
283    
284     void NPA::scaleSimBox(){
285     Mat3x3d scaleMat;
286    
287     for(int i=0; i<3; i++){
288     for(int j=0; j<3; j++){
289     scaleMat(i, j) = 0.0;
290     if(i==j) {
291     scaleMat(i, j) = 1.0;
292     }
293     }
294     }
295    
296     scaleMat(2, 2) = exp(dt*eta(2, 2));
297     Mat3x3d hmat = snap->getHmat();
298     hmat = hmat *scaleMat;
299     snap->setHmat(hmat);
300     }
301    
302     bool NPA::etaConverged() {
303     int i;
304     RealType diffEta, sumEta;
305    
306     sumEta = 0;
307     for(i = 0; i < 3; i++) {
308     sumEta += pow(prevEta(i, i) - eta(i, i), 2);
309     }
310    
311     diffEta = sqrt( sumEta / 3.0 );
312    
313     return ( diffEta <= etaTolerance );
314     }
315    
316     RealType NPA::calcConservedQuantity(){
317    
318     thermostat = snap->getThermostat();
319     loadEta();
320    
321     // We need NkBT a lot, so just set it here: This is the RAW number
322     // of integrableObjects, so no subtraction or addition of constraints or
323     // orientational degrees of freedom:
324     NkBT = info_->getNGlobalIntegrableObjects()*PhysicalConstants::kB *targetTemp;
325    
326     // fkBT is used because the thermostat operates on more degrees of freedom
327     // than the barostat (when there are particles with orientational degrees
328     // of freedom).
329     fkBT = info_->getNdf()*PhysicalConstants::kB *targetTemp;
330    
331     RealType conservedQuantity;
332     RealType totalEnergy;
333     RealType thermostat_kinetic;
334     RealType thermostat_potential;
335     RealType barostat_kinetic;
336     RealType barostat_potential;
337     RealType trEta;
338    
339     totalEnergy = thermo.getTotalEnergy();
340    
341     thermostat_kinetic = 0.0;
342     thermostat_potential = 0.0;
343    
344     SquareMatrix<RealType, 3> tmp = eta.transpose() * eta;
345     trEta = tmp.trace();
346    
347     barostat_kinetic = NkBT * tb2 * trEta /(2.0 * PhysicalConstants::energyConvert);
348    
349     barostat_potential = (targetPressure * thermo.getVolume() / PhysicalConstants::pressureConvert) /PhysicalConstants::energyConvert;
350    
351     conservedQuantity = totalEnergy + thermostat_kinetic + thermostat_potential +
352     barostat_kinetic + barostat_potential;
353    
354     return conservedQuantity;
355    
356     }
357    
358     void NPA::loadEta() {
359     eta= snap->getBarostat();
360    
361     //if (!eta.isDiagonal()) {
362     // sprintf( painCave.errMsg,
363     // "NPA error: the diagonal elements of eta matrix are not the same or etaMat is not a diagonal matrix");
364     // painCave.isFatal = 1;
365     // simError();
366     //}
367     }
368    
369     void NPA::saveEta() {
370     snap->setBarostat(eta);
371     }
372    
373     }
374    

Properties

Name Value
svn:eol-style native