1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 package ffx.potential.openmm;
39
40 import ffx.openmm.CustomCompoundBondForce;
41 import ffx.openmm.DoubleArray;
42 import ffx.openmm.Force;
43 import ffx.openmm.IntArray;
44 import ffx.potential.ForceFieldEnergy;
45 import ffx.potential.bonded.Angle;
46 import ffx.potential.bonded.Atom;
47 import ffx.potential.parameters.AngleType;
48 import ffx.potential.parameters.ForceField;
49 import ffx.potential.terms.AnglePotentialEnergy;
50
51 import java.util.logging.Logger;
52
53 import static edu.uiowa.jopenmm.OpenMMAmoebaLibrary.OpenMM_KJPerKcal;
54 import static java.lang.String.format;
55
56
57
58
59 public class InPlaneAngleForce extends CustomCompoundBondForce {
60
61 private static final Logger logger = Logger.getLogger(InPlaneAngleForce.class.getName());
62
63 private int nAngles = 0;
64 private final boolean manyBodyTitration;
65
66
67
68
69
70
71
72 public InPlaneAngleForce(AnglePotentialEnergy anglePotentialEnergy, OpenMMEnergy openMMEnergy) {
73 super(4, anglePotentialEnergy.getInPlaneAngleEnergyString());
74 Angle[] angles = anglePotentialEnergy.getAngleArray();
75 addPerBondParameter("theta0");
76 addPerBondParameter("k");
77 setName("InPlaneAngle");
78
79 ForceField forceField = openMMEnergy.getMolecularAssembly().getForceField();
80 manyBodyTitration = forceField.getBoolean("MANYBODY_TITRATION", false);
81
82 IntArray particles = new IntArray(0);
83 DoubleArray parameters = new DoubleArray(0);
84 for (Angle angle : angles) {
85 AngleType.AngleMode angleMode = angle.angleType.angleMode;
86
87 if (!manyBodyTitration && angleMode == AngleType.AngleMode.NORMAL) {
88
89 } else {
90 double theta0 = angle.angleType.angle[angle.nh];
91 double k = OpenMM_KJPerKcal * angle.angleType.angleUnit * angle.angleType.forceConstant;
92 int i1 = angle.getAtom(0).getArrayIndex();
93 int i2 = angle.getAtom(1).getArrayIndex();
94 int i3 = angle.getAtom(2).getArrayIndex();
95 int i4 = 0;
96 if (angleMode == AngleType.AngleMode.NORMAL) {
97
98
99 k = 0.0;
100 Atom fourthAtom = angle.getFourthAtomOfTrigonalCenter();
101 if (fourthAtom != null) {
102 i4 = fourthAtom.getArrayIndex();
103 } else {
104 while (i1 == i4 || i2 == i4 || i3 == i4) {
105 i4++;
106 }
107 }
108 } else {
109 i4 = angle.getAtom4().getArrayIndex();
110 }
111 particles.append(i1);
112 particles.append(i2);
113 particles.append(i3);
114 particles.append(i4);
115 parameters.append(theta0);
116 parameters.append(k);
117 addBond(particles, parameters);
118 nAngles++;
119 particles.resize(0);
120 parameters.resize(0);
121 }
122 }
123 particles.destroy();
124 parameters.destroy();
125
126 if (nAngles > 0) {
127 int forceGroup = anglePotentialEnergy.getForceGroup();
128 setForceGroup(forceGroup);
129 logger.info(format(" In-Plane Angles: %10d", nAngles));
130 logger.fine(format(" Force Group: %10d", forceGroup));
131 }
132 }
133
134
135
136
137
138
139
140
141 public InPlaneAngleForce(AnglePotentialEnergy anglePotentialEnergy, int topology, OpenMMDualTopologyEnergy openMMDualTopologyEnergy) {
142 super(4, anglePotentialEnergy.getInPlaneAngleEnergyString());
143
144 ForceFieldEnergy forceFieldEnergy = openMMDualTopologyEnergy.getForceFieldEnergy(topology);
145 ForceField forceField = forceFieldEnergy.getMolecularAssembly().getForceField();
146 manyBodyTitration = forceField.getBoolean("MANYBODY_TITRATION", false);
147 if (manyBodyTitration) {
148 logger.severe("Dual Topology does not support many body titration.");
149 }
150
151 Angle[] angles = anglePotentialEnergy.getAngleArray();
152 addPerBondParameter("theta0");
153 addPerBondParameter("k");
154 setName("InPlaneAngle");
155
156 double scale = openMMDualTopologyEnergy.getTopologyScale(topology);
157
158 IntArray particles = new IntArray(0);
159 DoubleArray parameters = new DoubleArray(0);
160 for (Angle angle : angles) {
161 AngleType.AngleMode angleMode = angle.angleType.angleMode;
162
163 if (angleMode == AngleType.AngleMode.NORMAL) {
164
165 } else {
166 double theta0 = angle.angleType.angle[angle.nh];
167 double k = OpenMM_KJPerKcal * angle.angleType.angleUnit * angle.angleType.forceConstant;
168
169 if (!angle.applyLambda()) {
170 k *= scale;
171 }
172 int i1 = angle.getAtom(0).getArrayIndex();
173 int i2 = angle.getAtom(1).getArrayIndex();
174 int i3 = angle.getAtom(2).getArrayIndex();
175 int i4 = angle.getAtom4().getArrayIndex();
176 i1 = openMMDualTopologyEnergy.mapToDualTopologyIndex(topology, i1);
177 i2 = openMMDualTopologyEnergy.mapToDualTopologyIndex(topology, i2);
178 i3 = openMMDualTopologyEnergy.mapToDualTopologyIndex(topology, i3);
179 i4 = openMMDualTopologyEnergy.mapToDualTopologyIndex(topology, i4);
180 particles.append(i1);
181 particles.append(i2);
182 particles.append(i3);
183 particles.append(i4);
184 parameters.append(theta0);
185 parameters.append(k);
186 addBond(particles, parameters);
187 nAngles++;
188 particles.resize(0);
189 parameters.resize(0);
190 }
191 }
192 particles.destroy();
193 parameters.destroy();
194
195 if (nAngles > 0) {
196 int forceGroup = anglePotentialEnergy.getForceGroup();
197 setForceGroup(forceGroup);
198 logger.info(format(" In-Plane Angles: %10d", nAngles));
199 logger.fine(format(" Force Group: %10d", forceGroup));
200 }
201 }
202
203
204
205
206
207
208
209 public static Force constructForce(OpenMMEnergy openMMEnergy) {
210 AnglePotentialEnergy anglePotentialEnergy = openMMEnergy.getAnglePotentialEnergy();
211 if (anglePotentialEnergy == null) {
212 return null;
213 }
214 InPlaneAngleForce angleForce = new InPlaneAngleForce(anglePotentialEnergy, openMMEnergy);
215 if (angleForce.nAngles > 0) {
216 return angleForce;
217 }
218 return null;
219 }
220
221
222
223
224
225
226
227
228 public static Force constructForce(int topology, OpenMMDualTopologyEnergy openMMDualTopologyEnergy) {
229 ForceFieldEnergy forceFieldEnergy = openMMDualTopologyEnergy.getForceFieldEnergy(topology);
230 AnglePotentialEnergy anglePotentialEnergy = forceFieldEnergy.getAnglePotentialEnergy();
231 if (anglePotentialEnergy == null) {
232 return null;
233 }
234 InPlaneAngleForce angleForce = new InPlaneAngleForce(anglePotentialEnergy, topology, openMMDualTopologyEnergy);
235 if (angleForce.nAngles > 0) {
236 return angleForce;
237 }
238 return null;
239 }
240
241
242
243
244
245
246 public void updateForce(OpenMMEnergy openMMEnergy) {
247 AnglePotentialEnergy anglePotentialEnergy = openMMEnergy.getAnglePotentialEnergy();
248 if (anglePotentialEnergy == null) {
249 return;
250 }
251 Angle[] angles = anglePotentialEnergy.getAngleArray();
252 IntArray particles = new IntArray(0);
253 DoubleArray parameters = new DoubleArray(0);
254 int index = 0;
255 for (Angle angle : angles) {
256 AngleType.AngleMode angleMode = angle.angleType.angleMode;
257 if (!manyBodyTitration && angleMode == AngleType.AngleMode.NORMAL) {
258
259 } else {
260 double theta0 = angle.angleType.angle[angle.nh];
261 double k = OpenMM_KJPerKcal * angle.angleType.angleUnit * angle.angleType.forceConstant;
262 int i1 = angle.getAtom(0).getArrayIndex();
263 int i2 = angle.getAtom(1).getArrayIndex();
264 int i3 = angle.getAtom(2).getArrayIndex();
265
266 int i4 = 0;
267 if (angleMode == AngleType.AngleMode.NORMAL) {
268
269 k = 0.0;
270 Atom fourthAtom = angle.getFourthAtomOfTrigonalCenter();
271 if (fourthAtom != null) {
272 i4 = fourthAtom.getArrayIndex();
273 } else {
274 while (i1 == i4 || i2 == i4 || i3 == i4) {
275 i4++;
276 }
277 }
278 } else {
279 i4 = angle.getAtom4().getArrayIndex();
280 }
281 particles.append(i1);
282 particles.append(i2);
283 particles.append(i3);
284 particles.append(i4);
285 parameters.append(theta0);
286 parameters.append(k);
287 setBondParameters(index++, particles, parameters);
288 particles.resize(0);
289 parameters.resize(0);
290 }
291 }
292 particles.destroy();
293 parameters.destroy();
294 updateParametersInContext(openMMEnergy.getContext());
295 }
296
297
298
299
300
301
302
303 public void updateForce(int topology, OpenMMDualTopologyEnergy openMMDualTopologyEnergy) {
304 ForceFieldEnergy forceFieldEnergy = openMMDualTopologyEnergy.getForceFieldEnergy(topology);
305 AnglePotentialEnergy anglePotentialEnergy = forceFieldEnergy.getAnglePotentialEnergy();
306 if (anglePotentialEnergy == null) {
307 return;
308 }
309 Angle[] angles = anglePotentialEnergy.getAngleArray();
310 double scale = openMMDualTopologyEnergy.getTopologyScale(topology);
311 IntArray particles = new IntArray(0);
312 DoubleArray parameters = new DoubleArray(0);
313 int index = 0;
314 for (Angle angle : angles) {
315 AngleType.AngleMode angleMode = angle.angleType.angleMode;
316 if (angleMode == AngleType.AngleMode.NORMAL) {
317
318 } else {
319 double theta0 = angle.angleType.angle[angle.nh];
320 double k = OpenMM_KJPerKcal * angle.angleType.angleUnit * angle.angleType.forceConstant;
321
322 if (!angle.applyLambda()) {
323 k *= scale;
324 }
325 int i1 = angle.getAtom(0).getArrayIndex();
326 int i2 = angle.getAtom(1).getArrayIndex();
327 int i3 = angle.getAtom(2).getArrayIndex();
328 int i4 = angle.getAtom4().getArrayIndex();
329 i1 = openMMDualTopologyEnergy.mapToDualTopologyIndex(topology, i1);
330 i2 = openMMDualTopologyEnergy.mapToDualTopologyIndex(topology, i2);
331 i3 = openMMDualTopologyEnergy.mapToDualTopologyIndex(topology, i3);
332 i4 = openMMDualTopologyEnergy.mapToDualTopologyIndex(topology, i4);
333 particles.append(i1);
334 particles.append(i2);
335 particles.append(i3);
336 particles.append(i4);
337 parameters.append(theta0);
338 parameters.append(k);
339 setBondParameters(index++, particles, parameters);
340 particles.resize(0);
341 parameters.resize(0);
342 }
343 }
344 particles.destroy();
345 parameters.destroy();
346 updateParametersInContext(openMMDualTopologyEnergy.getContext());
347 }
348 }