OpenMD 3.1
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
NPA.cpp
1/*
2 * Copyright (c) 2004-present, The University of Notre Dame. All rights
3 * reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
32 * research, please cite the appropriate papers when you publish your
33 * work. Good starting points are:
34 *
35 * [1] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
36 * [2] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
37 * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 234107 (2008).
38 * [4] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011).
39 * [5] Kuang & Gezelter, Mol. Phys., 110, 691-701 (2012).
40 * [6] Lamichhane, Gezelter & Newman, J. Chem. Phys. 141, 134109 (2014).
41 * [7] Lamichhane, Newman & Gezelter, J. Chem. Phys. 141, 134110 (2014).
42 * [8] Bhattarai, Newman & Gezelter, Phys. Rev. B 99, 094106 (2019).
43 */
44
45#include "integrators/NPA.hpp"
46
47#include "brains/SimInfo.hpp"
48#include "brains/Thermo.hpp"
49#include "integrators/IntegratorCreator.hpp"
51#include "utils/Constants.hpp"
52#include "utils/simError.h"
53
54namespace OpenMD {
55
56 void NPA::moveA() {
57 SimInfo::MoleculeIterator i;
58 Molecule::IntegrableObjectIterator j;
59 Molecule* mol;
60 StuntDouble* sd;
61 Vector3d Tb, ji;
62 RealType mass;
63 Vector3d vel;
64 Vector3d pos;
65 Vector3d frc;
66 Vector3d sc;
67 int index;
68
69 loadEta();
70
71 instaTemp = thermo.getTemperature();
72 press = thermo.getPressureTensor();
73 instaPress = Constants::pressureConvert *
74 (press(0, 0) + press(1, 1) + press(2, 2)) / 3.0;
75 instaVol = thermo.getVolume();
76
77 Vector3d COM = thermo.getCom();
78
79 // evolve velocity half step
80
81 calcVelScale();
82
83 for (mol = info_->beginMolecule(i); mol != NULL;
84 mol = info_->nextMolecule(i)) {
85 for (sd = mol->beginIntegrableObject(j); sd != NULL;
86 sd = mol->nextIntegrableObject(j)) {
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 * Constants::energyConvert / mass * frc - dt2 * sc;
97 sd->setVel(vel);
98
99 if (sd->isDirectional()) {
100 // get and convert the torque to body frame
101
102 Tb = sd->lab2Body(sd->getTrq());
103
104 // get the angular momentum, and propagate a half step
105
106 ji = sd->getJ();
107
108 ji += dt2 * Constants::energyConvert * Tb;
109
110 rotAlgo_->rotate(sd, ji, dt);
111
112 sd->setJ(ji);
113 }
114 }
115 }
116 // evolve eta a half step
117
118 evolveEtaA();
119 flucQ_->moveA();
120
121 index = 0;
122 for (mol = info_->beginMolecule(i); mol != NULL;
123 mol = info_->nextMolecule(i)) {
124 for (sd = mol->beginIntegrableObject(j); sd != NULL;
125 sd = mol->nextIntegrableObject(j)) {
126 oldPos[index++] = sd->getPos();
127 }
128 }
129
130 // the first estimation of r(t+dt) is equal to r(t)
131
132 for (int k = 0; k < maxIterNum_; k++) {
133 index = 0;
134 for (mol = info_->beginMolecule(i); mol != NULL;
135 mol = info_->nextMolecule(i)) {
136 for (sd = mol->beginIntegrableObject(j); sd != NULL;
137 sd = mol->nextIntegrableObject(j)) {
138 vel = sd->getVel();
139 pos = sd->getPos();
140
141 this->getPosScale(pos, COM, index, sc);
142
143 pos = oldPos[index] + dt * (vel + sc);
144 sd->setPos(pos);
145
146 ++index;
147 }
148 }
149
150 rattle_->constraintA();
151 }
152
153 // Scale the box after all the positions have been moved:
154
155 this->scaleSimBox();
156
157 saveEta();
158 }
159
160 void NPA::moveB(void) {
161 SimInfo::MoleculeIterator i;
162 Molecule::IntegrableObjectIterator j;
163 Molecule* mol;
164 StuntDouble* sd;
165 int index;
166 Vector3d Tb;
167 Vector3d ji;
168 Vector3d sc;
169 Vector3d vel;
170 Vector3d frc;
171 RealType mass;
172
173 loadEta();
174
175 // save velocity and angular momentum
176 index = 0;
177 for (mol = info_->beginMolecule(i); mol != NULL;
178 mol = info_->nextMolecule(i)) {
179 for (sd = mol->beginIntegrableObject(j); sd != NULL;
180 sd = mol->nextIntegrableObject(j)) {
181 oldVel[index] = sd->getVel();
182
183 if (sd->isDirectional()) oldJi[index] = sd->getJ();
184
185 ++index;
186 }
187 }
188
189 instaVol = thermo.getVolume();
190 for (int k = 0; k < maxIterNum_; k++) {
191 instaTemp = thermo.getTemperature();
192 instaPress = thermo.getPressure();
193
194 // evolve eta
195 this->evolveEtaB();
196 this->calcVelScale();
197
198 index = 0;
199 for (mol = info_->beginMolecule(i); mol != NULL;
200 mol = info_->nextMolecule(i)) {
201 for (sd = mol->beginIntegrableObject(j); sd != NULL;
202 sd = mol->nextIntegrableObject(j)) {
203 frc = sd->getFrc();
204 mass = sd->getMass();
205
206 getVelScaleB(sc, index);
207
208 // velocity half step
209 vel = oldVel[index] + dt2 * Constants::energyConvert / mass * frc -
210 dt2 * sc;
211
212 sd->setVel(vel);
213
214 if (sd->isDirectional()) {
215 // get and convert the torque to body frame
216 Tb = sd->lab2Body(sd->getTrq());
217
218 ji = oldJi[index] + dt2 * Constants::energyConvert * Tb;
219
220 sd->setJ(ji);
221 }
222
223 ++index;
224 }
225 }
226
227 rattle_->constraintB();
228
229 if (this->etaConverged()) break;
230 }
231
232 flucQ_->moveB();
233 saveEta();
234 }
235
236 void NPA::evolveEtaA() {
237 eta(2, 2) += dt2 * instaVol *
238 (press(2, 2) - targetPressure / Constants::pressureConvert) /
239 (NkBT * tb2);
240 oldEta = eta;
241 }
242
243 void NPA::evolveEtaB() {
244 prevEta = eta;
245 eta(2, 2) =
246 oldEta(2, 2) +
247 dt2 * instaVol *
248 (press(2, 2) - targetPressure / Constants::pressureConvert) /
249 (NkBT * tb2);
250 }
251
252 void NPA::calcVelScale() {
253 for (int i = 0; i < 3; i++) {
254 for (int j = 0; j < 3; j++) {
255 vScale(i, j) = eta(i, j);
256 }
257 }
258 }
259
260 void NPA::getVelScaleA(Vector3d& sc, const Vector3d& vel) {
261 sc = vScale * vel;
262 }
263
264 void NPA::getVelScaleB(Vector3d& sc, int index) {
265 sc = vScale * oldVel[index];
266 }
267
268 void NPA::getPosScale(const Vector3d& pos, const Vector3d& COM, int index,
269 Vector3d& sc) {
270 Vector3d rj = (oldPos[index] + pos) / (RealType)2.0 - COM;
271 sc = eta * rj;
272 }
273
274 void NPA::scaleSimBox() {
275 Mat3x3d scaleMat;
276
277 for (int i = 0; i < 3; i++) {
278 for (int j = 0; j < 3; j++) {
279 scaleMat(i, j) = 0.0;
280 if (i == j) { scaleMat(i, j) = 1.0; }
281 }
282 }
283
284 scaleMat(2, 2) = exp(dt * eta(2, 2));
285 Mat3x3d hmat = snap->getHmat();
286 hmat = hmat * scaleMat;
287 snap->setHmat(hmat);
288 }
289
290 bool NPA::etaConverged() {
291 int i;
292 RealType diffEta, sumEta;
293
294 sumEta = 0;
295 for (i = 0; i < 3; i++) {
296 sumEta += pow(prevEta(i, i) - eta(i, i), 2);
297 }
298
299 diffEta = sqrt(sumEta / 3.0);
300
301 return (diffEta <= etaTolerance);
302 }
303
304 RealType NPA::calcConservedQuantity() {
305 loadEta();
306
307 // We need NkBT a lot, so just set it here: This is the RAW number
308 // of integrableObjects, so no subtraction or addition of constraints or
309 // orientational degrees of freedom:
310 NkBT = info_->getNGlobalIntegrableObjects() * Constants::kB * targetTemp;
311
312 RealType conservedQuantity;
313 RealType totalEnergy;
314 RealType barostat_kinetic;
315 RealType barostat_potential;
316 RealType trEta;
317
318 totalEnergy = thermo.getTotalEnergy();
319
320 SquareMatrix<RealType, 3> tmp = eta.transpose() * eta;
321 trEta = tmp.trace();
322
323 barostat_kinetic = NkBT * tb2 * trEta / (2.0 * Constants::energyConvert);
324
325 barostat_potential =
326 (targetPressure * thermo.getVolume() / Constants::pressureConvert) /
327 Constants::energyConvert;
328
329 conservedQuantity = totalEnergy + barostat_kinetic + barostat_potential;
330
331 return conservedQuantity;
332 }
333
334 void NPA::loadEta() { eta = snap->getBarostat(); }
335
336 void NPA::saveEta() { snap->setBarostat(eta); }
337} // namespace OpenMD
int getNGlobalIntegrableObjects()
Returns the total number of integrable objects (total number of rigid bodies plus the total number of...
Definition SimInfo.hpp:139
Molecule * beginMolecule(MoleculeIterator &i)
Returns the first molecule in this SimInfo and intialize the iterator.
Definition SimInfo.cpp:240
Molecule * nextMolecule(MoleculeIterator &i)
Returns the next avaliable Molecule based on the iterator.
Definition SimInfo.cpp:245
Mat3x3d getHmat()
Returns the H-Matrix.
Definition Snapshot.cpp:214
void setHmat(const Mat3x3d &m)
Sets the H-Matrix.
Definition Snapshot.cpp:217
A square matrix class.
Real trace() const
Returns the trace of this matrix.
"Don't move, or you're dead! Stand up! Captain, we've got them!"
Vector3d getTrq()
Returns the current torque of this stuntDouble.
Vector3d lab2Body(const Vector3d &v)
Converts a lab fixed vector to a body fixed vector.
Vector3d getVel()
Returns the current velocity of this stuntDouble.
RealType getMass()
Returns the mass of this stuntDouble.
Vector3d getPos()
Returns the current position of this stuntDouble.
void setPos(const Vector3d &pos)
Sets the current position of this stuntDouble.
void setVel(const Vector3d &vel)
Sets the current velocity of this stuntDouble.
Vector3d getJ()
Returns the current angular momentum of this stuntDouble (body -fixed).
bool isDirectional()
Tests if this stuntDouble is a directional one.
Vector3d getFrc()
Returns the current force of this stuntDouble.
void setJ(const Vector3d &angMom)
Sets the current angular momentum of this stuntDouble (body-fixed).
Mat3x3d getPressureTensor()
gives the pressure tensor in amu*fs^-2*Ang^-1
Definition Thermo.cpp:450
Vector3d getCom()
Returns the center of the mass of the whole system.
Definition Thermo.cpp:812
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.