OpenMD 3.1
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
UFF.cpp
1/*
2 * Copyright (c) 2020 The University of Notre Dame. All Rights Reserved.
3 *
4 * The University of Notre Dame grants you ("Licensee") a
5 * non-exclusive, royalty free, license to use, modify and
6 * redistribute this software in source and binary code form, provided
7 * that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the
15 * distribution.
16 *
17 * This software is provided "AS IS," without a warranty of any
18 * kind. All express or implied conditions, representations and
19 * warranties, including any implied warranty of merchantability,
20 * fitness for a particular purpose or non-infringement, are hereby
21 * excluded. The University of Notre Dame and its licensors shall not
22 * be liable for any damages suffered by licensee as a result of
23 * using, modifying or distributing the software or its
24 * derivatives. In no event will the University of Notre Dame or its
25 * licensors be liable for any lost revenue, profit or data, or for
26 * direct, indirect, special, consequential, incidental or punitive
27 * damages, however caused and regardless of the theory of liability,
28 * arising out of the use of or inability to use software, even if the
29 * University of Notre Dame has been advised of the possibility of
30 * such damages.
31 *
32 * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
33 * research, please cite the appropriate papers when you publish your
34 * work. Good starting points are:
35 *
36 * [1] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
37 * [2] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
38 * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 234107 (2008).
39 * [4] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011).
40 * [5] Kuang & Gezelter, Mol. Phys., 110, 691-701 (2012).
41 * [6] Lamichhane, Gezelter & Newman, J. Chem. Phys. 141, 134109 (2014).
42 * [7] Lamichhane, Newman & Gezelter, J. Chem. Phys. 141, 134110 (2014).
43 * [8] Bhattarai, Newman & Gezelter, Phys. Rev. B 99, 094106 (2019).
44 */
45
46#include "forceFields/UFF.hpp"
47
48namespace OpenMD {
49 namespace UFF {
50
51 RealType fastPower(RealType x, int y) {
52 RealType temp;
53 if( y == 0)
54 return 1;
55 temp = fastPower(x, y/2);
56 if (y%2 == 0)
57 return temp*temp;
58 else {
59 if(y > 0)
60 return x*temp*temp;
61 else
62 return (temp*temp)/x;
63 }
64 }
65
66 RealType calcBondRestLength(RealType bondOrder, const AtomType *at1,
67 const AtomType *at2) {
68 assert(bondOrder > 0);
69 assert(at1);
70 assert(at2);
71
72 UFFAdapter uff1 = UFFAdapter(at1);
73 UFFAdapter uff2 = UFFAdapter(at2);
74
75 RealType ri = uff1->getR1();
76 RealType rj = uff2->getR1();
77 // Precompute the equilibrium bond distance
78 // From equation 3
79 // this is the pauling correction:
80 RealType rBO = -Params::lambda * (ri + rj) * log(bondOrder);
81
82 // O'Keefe and Breese electronegativity correction:
83 RealType Xi = uff1->getXi();
84 RealType Xj = uff2->getXi();
85 RealType rEN = ri * rj * (sqrt(Xi) - sqrt(Xj)) * (sqrt(Xi) - sqrt(Xj)) /
86 (Xi * ri + Xj * rj);
87 // NOTE: See http://towhee.sourceforge.net/forcefields/uff.html
88 // There is a typo in the published paper
89 RealType r0 = ri + rj + rBO - rEN;
90 return r0;
91 }
92
93 RealType calcBondForceConstant(RealType restLength, const AtomType *at1,
94 const AtomType *at2) {
95 UFFAdapter uff1 = UFFAdapter(at1);
96 UFFAdapter uff2 = UFFAdapter(at2);
97
98 RealType kb = 2.0 * Params::G * uff1->getZ1() * uff2->getZ1() /
99 (restLength * restLength * restLength);
100 return kb;
101 }
102
103 RealType calcAngleForceConstant(RealType theta0, RealType bondOrder12,
104 RealType bondOrder23, const AtomType *at1,
105 const AtomType *at2,
106 const AtomType *at3) {
107 UFFAdapter uff1 = UFFAdapter(at1);
108 UFFAdapter uff2 = UFFAdapter(at2);
109 UFFAdapter uff3 = UFFAdapter(at3);
110
111 RealType cosTheta0 = cos(theta0);
112 RealType r12 = calcBondRestLength(bondOrder12, at1, at2);
113 RealType r23 = calcBondRestLength(bondOrder23, at2, at3);
114 RealType r13 = sqrt(r12 * r12 + r23 * r23 - 2. * r12 * r23 * cosTheta0);
115 RealType beta = 2. * Params::G / (r12 * r23);
116
117 RealType preFactor = beta * uff1->getZ1() * uff3->getZ1() /
118 fastPower(r13,5);
119 RealType rTerm = r12 * r23;
120 RealType innerBit =
121 3. * rTerm * (1. - cosTheta0 * cosTheta0) - r13 * r13 * cosTheta0;
122 RealType res = preFactor * rTerm * innerBit;
123 return res;
124 }
125
126 void calcTorsionParams(RealType bondOrder23, int atNum2,
127 int atNum3,
128 RDKit::Atom::HybridizationType hyb2,
129 RDKit::Atom::HybridizationType hyb3,
130 const AtomType *at2,
131 const AtomType *at3,
132 bool endAtomIsSP2) {
133 assert((hyb2 == RDKit::Atom::SP2 || hyb2 == RDKit::Atom::SP3) &&
134 (hyb3 == RDKit::Atom::SP2 || hyb3 == RDKit::Atom::SP3));
135
136 UFFAdapter uff2 = UFFAdapter(at2);
137 UFFAdapter uff3 = UFFAdapter(at3);
138
139
140 if (hyb2 == RDKit::Atom::SP3 && hyb3 == RDKit::Atom::SP3) {
141 // general case:
142 d_forceConstant = sqrt(uff2->getV1() * uff3->getV1());
143 d_order = 3;
144 d_cosTerm = -1; // phi0=60
145
146 // special case for single bonds between group 6 elements:
147 if (bondOrder23 == 1.0 && isInGroup6(atNum2) &&
148 isInGroup6(atNum3)) {
149 RealType V2 = 6.8, V3 = 6.8;
150 if (atNum2 == 8) {
151 V2 = 2.0;
152 }
153 if (atNum3 == 8) {
154 V3 = 2.0;
155 }
156 d_forceConstant = sqrt(V2 * V3);
157 d_order = 2;
158 d_cosTerm = -1; // phi0=90
159 }
160 } else if (hyb2 == RDKit::Atom::SP2 && hyb3 == RDKit::Atom::SP2) {
161 d_forceConstant = equation17(bondOrder23, at2, at3);
162 d_order = 2;
163 // FIX: is this angle term right?
164 d_cosTerm = 1.0; // phi0= 180
165 } else {
166 // SP2 - SP3, this is, by default, independent of atom type in UFF:
167 d_forceConstant = 1.0;
168 d_order = 6;
169 d_cosTerm = 1.0; // phi0 = 0
170 if (bondOrder23 == 1.0) {
171 // special case between group 6 sp3 and non-group 6 sp2:
172 if ((hyb2 == RDKit::Atom::SP3 && isInGroup6(atNum2) &&
173 !isInGroup6(atNum3)) ||
174 (hyb3 == RDKit::Atom::SP3 && isInGroup6(atNum3) &&
175 !isInGroup6(atNum2))) {
176 d_forceConstant = equation17(bondOrder23, at2, at3);
177 d_order = 2;
178 d_cosTerm = -1; // phi0 = 90;
179 }
180
181 // special case for sp3 - sp2 - sp2
182 // (i.e. the sp2 has another sp2 neighbor, like propene)
183 else if (endAtomIsSP2) {
184 d_forceConstant = 2.0;
185 d_order = 3;
186 d_cosTerm = -1; // phi0 = 180;
187 }
188 }
189 }
190 }
191
192 bool isInGroup6(int num) {
193 return (num == 8 || num == 16 || num == 34 || num == 52 || num == 84);
194 }
195
196 // implements equation 17 of the UFF paper.
197 RealType equation17(RealType bondOrder23, const AtomType *at2,
198 const AtomType *at3) {
199 UFFAdapter uff2 = UFFAdapter(at2);
200 UFFAdapter uff3 = UFFAdapter(at3);
201
202 return 5. * sqrt(uff2->getU1() * uff3->getU1()) *
203 (1. + 4.18 * log(bondOrder23));
204 }
205
206 RealType calculateCosY(const Vector3d &iPoint,
207 const Vector3d &jPoint,
208 const Vector3d &kPoint,
209 const Vector3d &lPoint) {
210 Vector3d rJI = iPoint - jPoint;
211 Vector3d rJK = kPoint - jPoint;
212 Vector3d rJL = lPoint - jPoint;
213 rJI /= rJI.length();
214 rJK /= rJK.length();
215 rJL /= rJL.length();
216
217 Vector3d n = rJI.crossProduct(rJK);
218 n /= n.length();
219
220 return n.dotProduct(rJL);
221 }
222
223 calcInversionCoefficientsAndForceConstant(int at2AtomicNum,
224 bool isCBoundToO) {
225 RealType res = 0.0;
226 RealType C0 = 0.0;
227 RealType C1 = 0.0;
228 RealType C2 = 0.0;
229 // if the central atom is sp2 carbon, nitrogen or oxygen
230 if ((at2AtomicNum == 6) || (at2AtomicNum == 7) || (at2AtomicNum == 8)) {
231 C0 = 1.0;
232 C1 = -1.0;
233 C2 = 0.0;
234 res = (isCBoundToO ? 50.0 : 6.0);
235 } else {
236 // group 5 elements are not clearly explained in the UFF paper
237 // the following code was inspired by MCCCS Towhee's ffuff.F
238 RealType w0 = M_PI / 180.0;
239 switch (at2AtomicNum) {
240 // if the central atom is phosphorous
241 case 15:
242 w0 *= 84.4339;
243 break;
244
245 // if the central atom is arsenic
246 case 33:
247 w0 *= 86.9735;
248 break;
249
250 // if the central atom is antimonium
251 case 51:
252 w0 *= 87.7047;
253 break;
254
255 // if the central atom is bismuth
256 case 83:
257 w0 *= 90.0;
258 break;
259 }
260 C2 = 1.0;
261 C1 = -4.0 * cos(w0);
262 C0 = -(C1 * cos(w0) + C2 * cos(2.0 * w0));
263 res = 22.0 / (C0 + C1 + C2);
264 }
265 res /= 3.0;
266
267 return boost::make_tuple(res, C0, C1, C2);
268 }
269
270 RealType calcNonbondedMinimum(const AtomType *at1,
271 const AtomType *at2) {
272 UFFAdapter uff1 = UFFAdapter(at1);
273 UFFAdapter uff2 = UFFAdapter(at2);
274
275 return sqrt(uff1->getX1() * uff2->getX1());
276 }
277
278 RealType calcNonbondedDepth(const AtomType *at1,
279 const AtomType *at2) {
280 UFFAdapter uff1 = UFFAdapter(at1);
281 UFFAdapter uff2 = UFFAdapter(at2);
282
283 return sqrt(uff1->getD1() * uff2->getD1());
284 }
285 }
286}
Real length()
Returns the length of this vector.
Definition Vector.hpp:393
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.