OpenMD 3.0
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
NVT.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/NVT.hpp"
46
48#include "utils/Constants.hpp"
49#include "utils/simError.h"
50
51namespace OpenMD {
52
53 NVT::NVT(SimInfo* info) :
54 VelocityVerletIntegrator(info), maxIterNum_(4), chiTolerance_(1e-6) {
55 Globals* simParams = info_->getSimParams();
56
57 if (!simParams->getUseIntialExtendedSystemState()) {
58 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
59 snap->setThermostat(make_pair(0.0, 0.0));
60 }
61
62 if (!simParams->haveTargetTemp()) {
63 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
64 "You can't use the NVT integrator without a targetTemp_!\n");
65 painCave.isFatal = 1;
66 painCave.severity = OPENMD_ERROR;
67 simError();
68 } else {
69 targetTemp_ = simParams->getTargetTemp();
70 }
71
72 // We must set tauThermostat.
73
74 if (!simParams->haveTauThermostat()) {
75 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
76 "If you use the constant temperature\n"
77 "\tintegrator, you must set tauThermostat.\n");
78
79 painCave.severity = OPENMD_ERROR;
80 painCave.isFatal = 1;
81 simError();
82 } else {
83 tauThermostat_ = simParams->getTauThermostat();
84 }
85
86 updateSizes();
87 }
88
89 void NVT::doUpdateSizes() {
90 oldVel_.resize(info_->getNIntegrableObjects());
91 oldJi_.resize(info_->getNIntegrableObjects());
92 }
93
94 void NVT::moveA() {
95 SimInfo::MoleculeIterator i;
96 Molecule::IntegrableObjectIterator j;
97 Molecule* mol;
98 StuntDouble* sd;
99 Vector3d Tb;
100 Vector3d ji;
101 RealType mass;
102 Vector3d vel;
103 Vector3d pos;
104 Vector3d frc;
105
106 pair<RealType, RealType> thermostat = snap->getThermostat();
107
108 // We need the temperature at time = t for the chi update below:
109
110 RealType instTemp = thermo.getTemperature();
111
112 for (mol = info_->beginMolecule(i); mol != NULL;
113 mol = info_->nextMolecule(i)) {
114 for (sd = mol->beginIntegrableObject(j); sd != NULL;
115 sd = mol->nextIntegrableObject(j)) {
116 vel = sd->getVel();
117 pos = sd->getPos();
118 frc = sd->getFrc();
119
120 mass = sd->getMass();
121
122 // velocity half step (use chi from previous step here):
123 vel += dt2 * Constants::energyConvert / mass * frc -
124 dt2 * thermostat.first * vel;
125
126 // position whole step
127 pos += dt * vel;
128
129 sd->setVel(vel);
130 sd->setPos(pos);
131
132 if (sd->isDirectional()) {
133 // convert the torque to body frame
134 Tb = sd->lab2Body(sd->getTrq());
135
136 // get the angular momentum, and propagate a half step
137
138 ji = sd->getJ();
139
140 ji +=
141 dt2 * Constants::energyConvert * Tb - dt2 * thermostat.first * ji;
142
143 rotAlgo_->rotate(sd, ji, dt);
144
145 sd->setJ(ji);
146 }
147 }
148 }
149
150 flucQ_->moveA();
151 rattle_->constraintA();
152
153 // Finally, evolve chi a half step (just like a velocity) using
154 // temperature at time t, not time t+dt/2
155
156 thermostat.first += dt2 * (instTemp / targetTemp_ - 1.0) /
157 (tauThermostat_ * tauThermostat_);
158 thermostat.second += thermostat.first * dt2;
159
160 snap->setThermostat(thermostat);
161 }
162
163 void NVT::moveB() {
164 SimInfo::MoleculeIterator i;
165 Molecule::IntegrableObjectIterator j;
166 Molecule* mol;
167 StuntDouble* sd;
168
169 Vector3d Tb;
170 Vector3d ji;
171 Vector3d vel;
172 Vector3d frc;
173 RealType mass;
174 RealType instTemp;
175 int index;
176 // Set things up for the iteration:
177
178 pair<RealType, RealType> thermostat = snap->getThermostat();
179 RealType oldChi = thermostat.first;
180 RealType prevChi;
181
182 index = 0;
183 for (mol = info_->beginMolecule(i); mol != NULL;
184 mol = info_->nextMolecule(i)) {
185 for (sd = mol->beginIntegrableObject(j); sd != NULL;
186 sd = mol->nextIntegrableObject(j)) {
187 oldVel_[index] = sd->getVel();
188
189 if (sd->isDirectional()) oldJi_[index] = sd->getJ();
190
191 ++index;
192 }
193 }
194
195 // do the iteration:
196
197 for (int k = 0; k < maxIterNum_; k++) {
198 index = 0;
199 instTemp = thermo.getTemperature();
200
201 // evolve chi another half step using the temperature at t + dt/2
202
203 prevChi = thermostat.first;
204 thermostat.first = oldChi + dt2 * (instTemp / targetTemp_ - 1.0) /
205 (tauThermostat_ * tauThermostat_);
206
207 for (mol = info_->beginMolecule(i); mol != NULL;
208 mol = info_->nextMolecule(i)) {
209 for (sd = mol->beginIntegrableObject(j); sd != NULL;
210 sd = mol->nextIntegrableObject(j)) {
211 frc = sd->getFrc();
212 mass = sd->getMass();
213
214 // velocity half step
215
216 vel = oldVel_[index] + dt2 / mass * Constants::energyConvert * frc -
217 dt2 * thermostat.first * oldVel_[index];
218
219 sd->setVel(vel);
220
221 if (sd->isDirectional()) {
222 // get and convert the torque to body frame
223
224 Tb = sd->lab2Body(sd->getTrq());
225
226 ji = oldJi_[index] + dt2 * Constants::energyConvert * Tb -
227 dt2 * thermostat.first * oldJi_[index];
228
229 sd->setJ(ji);
230 }
231
232 ++index;
233 }
234 }
235
236 rattle_->constraintB();
237
238 if (fabs(prevChi - thermostat.first) <= chiTolerance_) break;
239 }
240
241 flucQ_->moveB();
242
243 thermostat.second += dt2 * thermostat.first;
244 snap->setThermostat(thermostat);
245 }
246
247 void NVT::resetIntegrator() { snap->setThermostat(make_pair(0.0, 0.0)); }
248
249 RealType NVT::calcConservedQuantity() {
250 pair<RealType, RealType> thermostat = snap->getThermostat();
251 RealType conservedQuantity;
252 RealType fkBT;
253 RealType Energy;
254 RealType thermostat_kinetic;
255 RealType thermostat_potential;
256
257 fkBT = info_->getNdf() * Constants::kB * targetTemp_;
258
259 Energy = thermo.getTotalEnergy();
260
261 thermostat_kinetic = fkBT * tauThermostat_ * tauThermostat_ *
262 thermostat.first * thermostat.first /
263 (2.0 * Constants::energyConvert);
264
265 thermostat_potential = fkBT * thermostat.second / Constants::energyConvert;
266
267 conservedQuantity = Energy + thermostat_kinetic + thermostat_potential;
268
269 return conservedQuantity;
270 }
271
272} // namespace OpenMD
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
Definition SimInfo.hpp:93
int getNdf()
Returns the number of degrees of freedom.
Definition SimInfo.hpp:220
Molecule * beginMolecule(MoleculeIterator &i)
Returns the first molecule in this SimInfo and intialize the iterator.
Definition SimInfo.cpp:240
unsigned int getNIntegrableObjects()
Returns the number of local integrable objects.
Definition SimInfo.hpp:192
Molecule * nextMolecule(MoleculeIterator &i)
Returns the next avaliable Molecule based on the iterator.
Definition SimInfo.cpp:245
The Snapshot class is a repository storing dynamic data during a Simulation.
Definition Snapshot.hpp:147
"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).
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.