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