OpenMD 3.0
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
Rattle.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 "constraints/Rattle.hpp"
46
47#include <cmath>
48
49#ifdef IS_MPI
50#include <mpi.h>
51#endif
52
54#include "utils/simError.h"
55
56namespace OpenMD {
57
58 Rattle::Rattle(SimInfo* info) :
59 info_(info), maxConsIteration_(10), consTolerance_(1.0e-6),
60 doRattle_(false), currConstraintTime_(0.0) {
61 if (info_->getNGlobalConstraints() > 0) doRattle_ = true;
62
63 if (!doRattle_) return;
64
65 Globals* simParams = info_->getSimParams();
66
67 if (simParams->haveDt()) {
68 dt_ = simParams->getDt();
69 } else {
70 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
71 "Rattle Error: dt is not set\n");
72 painCave.isFatal = 1;
73 simError();
74 }
75
76 currentSnapshot_ = info_->getSnapshotManager()->getCurrentSnapshot();
77 if (simParams->haveConstraintTime()) {
78 constraintTime_ = simParams->getConstraintTime();
79 } else {
80 constraintTime_ = simParams->getStatusTime();
81 }
82
83 constraintOutputFile_ =
84 getPrefix(info_->getFinalConfigFileName()) + ".constraintForces";
85
86 // create ConstraintWriter
87 constraintWriter_ =
88 new ConstraintWriter(info_, constraintOutputFile_.c_str());
89
90 if (!constraintWriter_) {
91 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
92 "Failed to create ConstraintWriter\n");
93 painCave.isFatal = 1;
94 simError();
95 }
96 }
97
98 Rattle::~Rattle() { delete constraintWriter_; }
99
100 void Rattle::constraintA() {
101 if (!doRattle_) return;
102 doConstraint(&Rattle::constraintPairA);
103 }
104 void Rattle::constraintB() {
105 if (!doRattle_) return;
106 doConstraint(&Rattle::constraintPairB);
107
108 if (currentSnapshot_->getTime() >= currConstraintTime_) {
109 Molecule* mol;
110 SimInfo::MoleculeIterator mi;
111 ConstraintPair* consPair;
112 Molecule::ConstraintPairIterator cpi;
113 std::list<ConstraintPair*> constraints;
114 for (mol = info_->beginMolecule(mi); mol != NULL;
115 mol = info_->nextMolecule(mi)) {
116 for (consPair = mol->beginConstraintPair(cpi); consPair != NULL;
117 consPair = mol->nextConstraintPair(cpi)) {
118 constraints.push_back(consPair);
119 }
120 }
121 constraintWriter_->writeConstraintForces(constraints);
122 currConstraintTime_ += constraintTime_;
123 }
124 }
125
126 void Rattle::doConstraint(ConstraintPairFuncPtr func) {
127 if (!doRattle_) return;
128
129 Molecule* mol;
130 SimInfo::MoleculeIterator mi;
131 ConstraintElem* consElem;
132 Molecule::ConstraintElemIterator cei;
133 ConstraintPair* consPair;
134 Molecule::ConstraintPairIterator cpi;
135
136 for (mol = info_->beginMolecule(mi); mol != NULL;
137 mol = info_->nextMolecule(mi)) {
138 for (consElem = mol->beginConstraintElem(cei); consElem != NULL;
139 consElem = mol->nextConstraintElem(cei)) {
140 consElem->setMoved(true);
141 consElem->setMoving(false);
142 }
143 for (consPair = mol->beginConstraintPair(cpi); consPair != NULL;
144 consPair = mol->nextConstraintPair(cpi)) {
145 consPair->resetConstraintForce();
146 }
147 }
148
149 // main loop of constraint algorithm
150 int done = 0;
151 int iteration = 0;
152 while (!done && iteration < maxConsIteration_) {
153 done = 1;
154
155 // loop over every constraint pair
156
157 for (mol = info_->beginMolecule(mi); mol != NULL;
158 mol = info_->nextMolecule(mi)) {
159 for (consPair = mol->beginConstraintPair(cpi); consPair != NULL;
160 consPair = mol->nextConstraintPair(cpi)) {
161 // dispatch constraint algorithm
162 if (consPair->isMoved()) {
163 int exeStatus = (this->*func)(consPair);
164
165 switch (exeStatus) {
166 case consFail:
167 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
168 "Constraint failure in Rattle::constrainA, "
169 "Constraint Fail\n");
170 painCave.isFatal = 1;
171 simError();
172
173 break;
174 case consSuccess:
175 // constrain the pair by moving two elements
176 done = 0;
177 consPair->getConsElem1()->setMoving(true);
178 consPair->getConsElem2()->setMoving(true);
179 break;
180 case consAlready:
181 // current pair is already constrained, do not need to
182 // move the elements
183 break;
184 default:
185 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
186 "ConstraintAlgorithm::doConstraint() "
187 "Error: unrecognized status");
188 painCave.isFatal = 1;
189 simError();
190 break;
191 }
192 }
193 }
194 } // end for(iter->first())
195
196#ifdef IS_MPI
197 MPI_Allreduce(MPI_IN_PLACE, &done, 1, MPI_INT, MPI_LAND, MPI_COMM_WORLD);
198#endif
199
200 errorCheckPoint();
201
202 for (mol = info_->beginMolecule(mi); mol != NULL;
203 mol = info_->nextMolecule(mi)) {
204 for (consElem = mol->beginConstraintElem(cei); consElem != NULL;
205 consElem = mol->nextConstraintElem(cei)) {
206 consElem->setMoved(consElem->getMoving());
207 consElem->setMoving(false);
208 }
209 }
210 iteration++;
211 } // end while
212
213 if (!done) {
214 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
215 "Constraint failure in Rattle::constrainA, "
216 "too many iterations: %d\n",
217 iteration);
218 painCave.isFatal = 1;
219 simError();
220 }
221
222 errorCheckPoint();
223 }
224
225 int Rattle::constraintPairA(ConstraintPair* consPair) {
226 ConstraintElem* consElem1 = consPair->getConsElem1();
227 ConstraintElem* consElem2 = consPair->getConsElem2();
228
229 Vector3d posA = consElem1->getPos();
230 Vector3d posB = consElem2->getPos();
231
232 Vector3d pab = posA - posB;
233
234 // periodic boundary condition
235
236 currentSnapshot_->wrapVector(pab);
237
238 RealType pabsq = pab.lengthSquare();
239
240 RealType rabsq = consPair->getConsDistSquare();
241 RealType diffsq = rabsq - pabsq;
242
243 // the original rattle code from alan tidesley
244 if (fabs(diffsq) > (consTolerance_ * rabsq * 2.0)) {
245 Vector3d oldPosA = consElem1->getPrevPos();
246 Vector3d oldPosB = consElem2->getPrevPos();
247
248 Vector3d rab = oldPosA - oldPosB;
249
250 currentSnapshot_->wrapVector(rab);
251
252 RealType rpab = dot(rab, pab);
253 RealType rpabsq = rpab * rpab;
254
255 if (rpabsq < (rabsq * -diffsq)) { return consFail; }
256
257 RealType rma = 1.0 / consElem1->getMass();
258 RealType rmb = 1.0 / consElem2->getMass();
259
260 RealType gab = diffsq / (2.0 * (rma + rmb) * rpab);
261
262 Vector3d delta = rab * gab;
263
264 // set atom1's position
265 posA += rma * delta;
266 consElem1->setPos(posA);
267
268 // set atom2's position
269 posB -= rmb * delta;
270 consElem2->setPos(posB);
271
272 delta /= dt_;
273
274 // set atom1's velocity
275 Vector3d velA = consElem1->getVel();
276 velA += rma * delta;
277 consElem1->setVel(velA);
278
279 // set atom2's velocity
280 Vector3d velB = consElem2->getVel();
281 velB -= rmb * delta;
282 consElem2->setVel(velB);
283
284 // report the constraint force back to the constraint pair:
285 Vector3d fcons = 2.0 * delta / dt_;
286 RealType proj = copysign(fcons.length(), dot(fcons, rab));
287
288 consPair->addConstraintForce(proj);
289 return consSuccess;
290 } else {
291 return consAlready;
292 }
293 }
294
295 int Rattle::constraintPairB(ConstraintPair* consPair) {
296 ConstraintElem* consElem1 = consPair->getConsElem1();
297 ConstraintElem* consElem2 = consPair->getConsElem2();
298
299 Vector3d velA = consElem1->getVel();
300 Vector3d velB = consElem2->getVel();
301
302 Vector3d dv = velA - velB;
303
304 Vector3d posA = consElem1->getPos();
305 Vector3d posB = consElem2->getPos();
306
307 Vector3d rab = posA - posB;
308
309 currentSnapshot_->wrapVector(rab);
310
311 RealType rma = 1.0 / consElem1->getMass();
312 RealType rmb = 1.0 / consElem2->getMass();
313
314 RealType rvab = dot(rab, dv);
315
316 RealType gab = -rvab / ((rma + rmb) * consPair->getConsDistSquare());
317
318 if (fabs(gab) > consTolerance_) {
319 Vector3d delta = rab * gab;
320 velA += rma * delta;
321 consElem1->setVel(velA);
322
323 velB -= rmb * delta;
324 consElem2->setVel(velB);
325
326 // report the constraint force back to the constraint pair:
327
328 Vector3d fcons = 2.0 * delta / dt_;
329 RealType proj = copysign(fcons.length(), dot(fcons, rab));
330
331 consPair->addConstraintForce(proj);
332 return consSuccess;
333 } else {
334 return consAlready;
335 }
336 }
337
338} // namespace OpenMD
Real lengthSquare()
Returns the squared length of this vector.
Definition Vector.hpp:399
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
Real dot(const DynamicVector< Real > &v1, const DynamicVector< Real > &v2)
Returns the dot product of two DynamicVectors.
std::string getPrefix(const std::string &str)