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.Atom;
46 import ffx.potential.bonded.StretchTorsion;
47 import ffx.potential.terms.StretchTorsionPotentialEnergy;
48
49 import java.util.logging.Logger;
50
51 import static edu.uiowa.jopenmm.OpenMMAmoebaLibrary.OpenMM_KJPerKcal;
52 import static edu.uiowa.jopenmm.OpenMMAmoebaLibrary.OpenMM_NmPerAngstrom;
53 import static java.lang.String.format;
54
55
56
57
58 public class StretchTorsionForce extends CustomCompoundBondForce {
59
60 private static final Logger logger = Logger.getLogger(StretchTorsionForce.class.getName());
61
62
63
64
65
66
67 public StretchTorsionForce(StretchTorsionPotentialEnergy stretchTorsionPotentialEnergy) {
68 super(4, StretchTorsion.stretchTorsionForm());
69 StretchTorsion[] stretchTorsions = stretchTorsionPotentialEnergy.getStretchTorsionArray();
70 addGlobalParameter("phi1", 0);
71 addGlobalParameter("phi2", Math.PI);
72 addGlobalParameter("phi3", 0);
73 for (int m = 1; m < 4; m++) {
74 for (int n = 1; n < 4; n++) {
75 addPerBondParameter(format("k%d%d", m, n));
76 }
77 }
78 for (int m = 1; m < 4; m++) {
79 addPerBondParameter(format("b%d", m));
80 }
81
82 final double unitConv = OpenMM_KJPerKcal / OpenMM_NmPerAngstrom;
83
84 for (StretchTorsion stretchTorsion : stretchTorsions) {
85 double[] constants = stretchTorsion.getConstants();
86 DoubleArray parameters = new DoubleArray(0);
87 for (int m = 0; m < 3; m++) {
88 for (int n = 0; n < 3; n++) {
89 int index = (3 * m) + n;
90 parameters.append(constants[index] * unitConv);
91 }
92 }
93 parameters.append(stretchTorsion.bondType1.distance * OpenMM_NmPerAngstrom);
94 parameters.append(stretchTorsion.bondType2.distance * OpenMM_NmPerAngstrom);
95 parameters.append(stretchTorsion.bondType3.distance * OpenMM_NmPerAngstrom);
96
97 IntArray particles = new IntArray(0);
98 Atom[] atoms = stretchTorsion.getAtomArray(true);
99 for (int i = 0; i < 4; i++) {
100 particles.append(atoms[i].getArrayIndex());
101 }
102
103 addBond(particles, parameters);
104 parameters.destroy();
105 particles.destroy();
106 }
107
108 int forceGroup = stretchTorsionPotentialEnergy.getForceGroup();
109 setForceGroup(forceGroup);
110 logger.info(format(" Stretch-Torsions: %10d", stretchTorsions.length));
111 logger.fine(format(" Force Group: %10d", forceGroup));
112 }
113
114
115
116
117
118
119
120
121 public StretchTorsionForce(StretchTorsionPotentialEnergy stretchPotentialEnergy,
122 int topology, OpenMMDualTopologyEnergy openMMDualTopologyEnergy) {
123 super(4, StretchTorsion.stretchTorsionForm());
124 StretchTorsion[] stretchTorsions = stretchPotentialEnergy.getStretchTorsionArray();
125 addGlobalParameter("phi1", 0);
126 addGlobalParameter("phi2", Math.PI);
127 addGlobalParameter("phi3", 0);
128 for (int m = 1; m < 4; m++) {
129 for (int n = 1; n < 4; n++) {
130 addPerBondParameter(format("k%d%d", m, n));
131 }
132 }
133 for (int m = 1; m < 4; m++) {
134 addPerBondParameter(format("b%d", m));
135 }
136
137 final double unitConv = OpenMM_KJPerKcal / OpenMM_NmPerAngstrom;
138 double scaleDT = openMMDualTopologyEnergy.getTopologyScale(topology);
139
140 for (StretchTorsion stretchTorsion : stretchTorsions) {
141 double scale = 1.0;
142
143 if (!stretchTorsion.applyLambda()) {
144 scale = scaleDT;
145 }
146 double[] constants = stretchTorsion.getConstants();
147 DoubleArray parameters = new DoubleArray(0);
148 for (int m = 0; m < 3; m++) {
149 for (int n = 0; n < 3; n++) {
150 int index = (3 * m) + n;
151 parameters.append(constants[index] * unitConv * scale);
152 }
153 }
154 parameters.append(stretchTorsion.bondType1.distance * OpenMM_NmPerAngstrom);
155 parameters.append(stretchTorsion.bondType2.distance * OpenMM_NmPerAngstrom);
156 parameters.append(stretchTorsion.bondType3.distance * OpenMM_NmPerAngstrom);
157
158 IntArray particles = new IntArray(0);
159 Atom[] atoms = stretchTorsion.getAtomArray(true);
160 for (int i = 0; i < 4; i++) {
161 int atomIndex = atoms[i].getArrayIndex();
162 atomIndex = openMMDualTopologyEnergy.mapToDualTopologyIndex(topology, atomIndex);
163 particles.append(atomIndex);
164 }
165
166 addBond(particles, parameters);
167 parameters.destroy();
168 particles.destroy();
169 }
170
171 int forceGroup = stretchPotentialEnergy.getForceGroup();
172 setForceGroup(forceGroup);
173 logger.info(format(" Stretch-Torsions: %10d", stretchTorsions.length));
174 logger.fine(format(" Force Group: %10d", forceGroup));
175 }
176
177
178
179
180
181
182
183 public static Force constructForce(OpenMMEnergy openMMEnergy) {
184 StretchTorsionPotentialEnergy stretchTorsionPotentialEnergy =
185 openMMEnergy.getStretchTorsionPotentialEnergy();
186 if (stretchTorsionPotentialEnergy == null) {
187 return null;
188 }
189 return new StretchTorsionForce(stretchTorsionPotentialEnergy);
190 }
191
192
193
194
195
196
197
198
199 public static Force constructForce(int topology, OpenMMDualTopologyEnergy openMMDualTopologyEnergy) {
200 ForceFieldEnergy forceFieldEnergy = openMMDualTopologyEnergy.getForceFieldEnergy(topology);
201 StretchTorsionPotentialEnergy stretchTorsionPotentialEnergy =
202 forceFieldEnergy.getStretchTorsionPotentialEnergy();
203 if (stretchTorsionPotentialEnergy == null) {
204 return null;
205 }
206 return new StretchTorsionForce(stretchTorsionPotentialEnergy, topology, openMMDualTopologyEnergy);
207 }
208
209
210
211
212
213
214
215 public void updateForce(int topology, OpenMMDualTopologyEnergy openMMDualTopologyEnergy) {
216 ForceFieldEnergy forceFieldEnergy = openMMDualTopologyEnergy.getForceFieldEnergy(topology);
217 StretchTorsionPotentialEnergy stretchTorsionPotentialEnergy =
218 forceFieldEnergy.getStretchTorsionPotentialEnergy();
219 if (stretchTorsionPotentialEnergy == null) {
220 return;
221 }
222 StretchTorsion[] stretchTorsions = stretchTorsionPotentialEnergy.getStretchTorsionArray();
223 final double unitConv = OpenMM_KJPerKcal / OpenMM_NmPerAngstrom;
224 double scaleDT = openMMDualTopologyEnergy.getTopologyScale(topology);
225
226 int stIndex = 0;
227 for (StretchTorsion stretchTorsion : stretchTorsions) {
228 double scale = 1.0;
229
230 if (!stretchTorsion.applyLambda()) {
231 scale = scaleDT;
232 }
233 double[] constants = stretchTorsion.getConstants();
234 DoubleArray parameters = new DoubleArray(0);
235 for (int m = 0; m < 3; m++) {
236 for (int n = 0; n < 3; n++) {
237 int index = (3 * m) + n;
238 parameters.append(constants[index] * unitConv * scale);
239 }
240 }
241 parameters.append(stretchTorsion.bondType1.distance * OpenMM_NmPerAngstrom);
242 parameters.append(stretchTorsion.bondType2.distance * OpenMM_NmPerAngstrom);
243 parameters.append(stretchTorsion.bondType3.distance * OpenMM_NmPerAngstrom);
244
245 IntArray particles = new IntArray(0);
246 Atom[] atoms = stretchTorsion.getAtomArray(true);
247 for (int i = 0; i < 4; i++) {
248 int atomIndex = atoms[i].getArrayIndex();
249 atomIndex = openMMDualTopologyEnergy.mapToDualTopologyIndex(topology, atomIndex);
250 particles.append(atomIndex);
251 }
252
253 setBondParameters(stIndex++, particles, parameters);
254 parameters.destroy();
255 particles.destroy();
256 }
257
258 updateParametersInContext(openMMDualTopologyEnergy.getContext());
259 }
260 }