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