OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
MolecularRestraint.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 "restraints/MolecularRestraint.hpp"
49
50#include <utility>
51
52#include "math/SVD.hpp"
54
55// using namespace JAMA;
56
57namespace OpenMD {
58
59 void MolecularRestraint::calcForce(std::vector<Vector3d> struc,
60 Vector3d molCom) {
61 assert(struc.size() == ref_.size());
62
63 std::vector<Vector3d>::iterator it;
64
65 // clear out initial values:
66 pot_ = 0.0;
67 for (it = forces_.begin(); it != forces_.end(); ++it)
68 (*it) = 0.0;
69
70 if (restType_ & rtDisplacement) {
71 Vector3d del = molCom - refCom_;
72
73 RealType r = del.length();
74 RealType p = 0.5 * kDisp_ * r * r;
75
76 pot_ += p;
77
78 if (printRest_) restInfo_[rtDisplacement] = std::make_pair(r, p);
79
80 for (it = forces_.begin(); it != forces_.end(); ++it)
81 (*it) += -kDisp_ * del * scaleFactor_;
82 }
83
84 if (restType_ & rtDisplacementX) {
85 Vector3d del = molCom - refCom_;
86
87 RealType r = del.x();
88 RealType p = 0.5 * kDispX_ * r * r;
89
90 pot_ += p;
91
92 if (printRest_) restInfo_[rtDisplacementX] = std::make_pair(r, p);
93
94 for (it = forces_.begin(); it != forces_.end(); ++it)
95 (*it) += -kDispX_ * r * V3X * scaleFactor_;
96 }
97
98 if (restType_ & rtDisplacementY) {
99 Vector3d del = molCom - refCom_;
100
101 RealType r = del.y();
102 RealType p = 0.5 * kDispY_ * r * r;
103
104 pot_ += p;
105
106 if (printRest_) restInfo_[rtDisplacementY] = std::make_pair(r, p);
107
108 for (it = forces_.begin(); it != forces_.end(); ++it)
109 (*it) += -kDispY_ * r * V3Y * scaleFactor_;
110 }
111
112 if (restType_ & rtDisplacementZ) {
113 Vector3d del = molCom - refCom_;
114
115 RealType r = del.z();
116 RealType p = 0.5 * kDispZ_ * r * r;
117
118 pot_ += p;
119
120 if (printRest_) restInfo_[rtDisplacementZ] = std::make_pair(r, p);
121
122 for (it = forces_.begin(); it != forces_.end(); ++it)
123 (*it) += -kDispZ_ * r * V3Z * scaleFactor_;
124 }
125
126 if (restType_ & rtAbsoluteZ) {
127 RealType r = molCom(2) - posZ0_;
128 RealType p = 0.5 * kAbs_ * r * r;
129 Vector3d frc = Vector3d(0.0, 0.0, -kAbs_ * r);
130
131 pot_ += p;
132
133 if (printRest_) restInfo_[rtAbsoluteZ] = std::make_pair(r, p);
134
135 for (it = forces_.begin(); it != forces_.end(); ++it)
136 (*it) += frc * scaleFactor_;
137 }
138
139 // Anything higher than 32 requires orientations:
140
141 if (restType_ >= 32) {
142 Vector3d tBody(0.0);
143
144 Mat3x3d R(0.0);
145
146 for (unsigned int n = 0; n < struc.size(); n++) {
147 /*
148 * First migrate the center of mass:
149 */
150 struc[n] -= molCom;
151
152 /*
153 * correlation matrix R:
154 * R(i,j) = sum(over n): y(n,i) * x(n,j)
155 * where x(n) and y(n) are two vector sets
156 */
157
158 R += outProduct(struc[n], ref_[n]);
159 }
160
161 // SVD class uses dynamic matrices, so we must wrap the correlation
162 // matrix before calling SVD and then unwrap the results into Mat3x3d
163 // and Vector3d before we use them.
164
165 DynamicRectMatrix<RealType> Rtmp(3, 3, 0.0);
169
170 Rtmp.setSubMatrix(0, 0, R);
171
172 // Heavy lifting goes here:
173
174 JAMA::SVD<RealType> svd(Rtmp);
175
176 svd.getU(vtmp);
177 svd.getSingularValues(stmp);
178 svd.getV(wtmp);
179
180 Mat3x3d v;
181 Vector3d s;
182 Mat3x3d w_tr;
183
184 vtmp.getSubMatrix(0, 0, v);
185 stmp.getSubVector(0, s);
186 wtmp.getSubMatrix(0, 0, w_tr);
187
188 bool is_reflection = (v.determinant() * w_tr.determinant()) < 0.0;
189
190 if (is_reflection) {
191 v(2, 0) = -v(2, 0);
192 v(2, 1) = -v(2, 1);
193 v(2, 2) = -v(2, 2);
194 }
195
196 RotMat3x3d Atrans = v * w_tr.transpose();
197 RotMat3x3d A = Atrans.transpose();
198
199 Quat4d quat = A.toQuaternion();
200
201 RealType twistAngle;
202 RealType swingX, swingY;
203
204 quat.toTwistSwing(twistAngle, swingX, swingY);
205
206 RealType dVdtwist, dVdswingX, dVdswingY;
207 RealType dTwist, dSwingX, dSwingY;
208 RealType p;
209
210 if (restType_ & rtTwist) {
211 dTwist = twistAngle - twist0_;
212 /// dVdtwist = kTwist_ * sin(dTwist) ;
213 /// p = kTwist_ * (1.0 - cos(dTwist) ) ;
214 dVdtwist = kTwist_ * dTwist;
215 p = 0.5 * kTwist_ * dTwist * dTwist;
216 pot_ += p;
217 tBody -= dVdtwist * V3Z;
218 if (printRest_) restInfo_[rtTwist] = std::make_pair(twistAngle, p);
219 }
220
221 if (restType_ & rtSwingX) {
222 dSwingX = swingX - swingX0_;
223 /// dVdswingX = kSwingX_ * 2.0 * sin(2.0 * dSwingX);
224 /// p = kSwingX_ * (1.0 - cos(2.0 * dSwingX));
225 dVdswingX = kSwingX_ * dSwingX;
226 p = 0.5 * kSwingX_ * dSwingX * dSwingX;
227 pot_ += p;
228 tBody -= dVdswingX * V3X;
229 if (printRest_) restInfo_[rtSwingX] = std::make_pair(swingX, p);
230 }
231 if (restType_ & rtSwingY) {
232 dSwingY = swingY - swingY0_;
233 /// dVdswingY = kSwingY_ * 2.0 * sin(2.0 * dSwingY);
234 /// p = kSwingY_ * (1.0 - cos(2.0 * dSwingY));
235 dVdswingY = kSwingY_ * dSwingY;
236 p = 0.5 * kSwingX_ * dSwingY * dSwingY;
237 pot_ += p;
238 tBody -= dVdswingY * V3Y;
239 if (printRest_) restInfo_[rtSwingY] = std::make_pair(swingY, p);
240 }
241
242 RealType t2 = dot(tBody, tBody);
243
244 Vector3d rLab, rBody, txr, fBody, fLab;
245
246 for (unsigned int i = 0; i < struc.size(); i++) {
247 rLab = struc[i];
248 rBody = A * rLab;
249
250 txr = cross(tBody, rBody);
251 fBody = txr * t2;
252 fLab = Atrans * fBody;
253 fLab *= scaleFactor_;
254
255 forces_[i] += fLab;
256 }
257
258 // test the force vectors and see if it is the right orientation
259 // std::cout << struc.size() << std::endl << std::endl;
260 // for (int i = 0; i != struc.size(); ++i){
261 // std::cout << "H\t" << struc[i].x() << "\t" << struc[i].y() <<
262 // "\t" << struc[i].z() << "\t"; std::cout << forces_[i].x() <<
263 // "\t"
264 // << forces_[i].y()
265 // << "\t" << forces_[i].z() << std::endl;
266 // }
267 }
268 }
269} // namespace OpenMD
Singular Value Decomposition.
Definition SVD.hpp:34
void getSingularValues(DynamicVector< Real > &x)
Return the one-dimensional array of singular values.
Definition SVD.hpp:443
Rectangular matrix class with contiguous flat storage.
Dynamically-sized vector class.
void calcForce(std::vector< Vector3d > struc, Vector3d molCom)
Real determinant() const
Returns the determinant of this matrix.
Quaternion< Real > toQuaternion()
Returns the quaternion from this rotation matrix.
Real & z()
Returns reference of the third element of Vector3.
Definition Vector3.hpp:123
Real & x()
Returns reference of the first element of Vector3.
Definition Vector3.hpp:99
Real & y()
Returns reference of the second element of Vector3.
Definition Vector3.hpp:111
Real length() const
Returns the length of this vector.
Definition Vector.hpp:397
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
Vector3< Real > cross(const Vector3< Real > &v1, const Vector3< Real > &v2)
Returns the cross product of two Vectors.
Definition Vector3.hpp:139
Real dot(const DynamicVector< Real > &v1, const DynamicVector< Real > &v2)
Returns the dot product of two DynamicVectors.