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 com.sun.jna.ptr.PointerByReference;
41 import ffx.openmm.State;
42 import ffx.potential.bonded.Atom;
43 import ffx.potential.utils.EnergyException;
44
45 import javax.annotation.Nullable;
46
47 import static edu.uiowa.jopenmm.OpenMMAmoebaLibrary.OpenMM_AngstromsPerNm;
48 import static edu.uiowa.jopenmm.OpenMMAmoebaLibrary.OpenMM_KcalPerKJ;
49 import static edu.uiowa.jopenmm.OpenMMAmoebaLibrary.OpenMM_NmPerAngstrom;
50 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_State_DataType.OpenMM_State_Energy;
51 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_State_DataType.OpenMM_State_Forces;
52 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_State_DataType.OpenMM_State_Positions;
53 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_State_DataType.OpenMM_State_Velocities;
54 import static java.lang.Double.isInfinite;
55 import static java.lang.Double.isNaN;
56 import static java.lang.String.format;
57
58
59
60
61 public class OpenMMState extends State {
62
63
64
65
66 public final double potentialEnergy;
67
68
69
70 public final double kineticEnergy;
71
72
73
74 public final double totalEnergy;
75
76
77
78 private final int dataTypes;
79
80
81
82 private final Atom[] atoms;
83
84
85
86 private final int n;
87
88
89
90 private final int nAtoms;
91
92
93
94
95
96
97
98
99 protected OpenMMState(PointerByReference pointer, Atom[] atoms, int dof) {
100 super(pointer);
101
102 this.dataTypes = super.getDataTypes();
103 this.atoms = atoms;
104 this.n = dof;
105 nAtoms = atoms.length;
106 if (stateContains(OpenMM_State_Energy)) {
107
108 potentialEnergy = super.getPotentialEnergy() * OpenMM_KcalPerKJ;
109 kineticEnergy = super.getKineticEnergy() * OpenMM_KcalPerKJ;
110 totalEnergy = potentialEnergy + kineticEnergy;
111 } else {
112 potentialEnergy = 0.0;
113 kineticEnergy = 0.0;
114 totalEnergy = 0.0;
115 }
116 }
117
118
119
120
121
122
123
124
125 public double[] getAccelerations(@Nullable double[] a) {
126 if (!stateContains(OpenMM_State_Forces)) {
127 return a;
128 }
129
130 if (a == null || a.length != n) {
131 a = new double[n];
132 }
133
134 double[] forces = getForces();
135 for (int i = 0, index = 0; i < nAtoms; i++, index += 3) {
136 Atom atom = atoms[i];
137 if (atom.isActive()) {
138 double mass = atom.getMass();
139 double xx = forces[index] * OpenMM_AngstromsPerNm / mass;
140 double yy = forces[index + 1] * OpenMM_AngstromsPerNm / mass;
141 double zz = forces[index + 2] * OpenMM_AngstromsPerNm / mass;
142 a[index] = xx;
143 a[index + 1] = yy;
144 a[index + 2] = zz;
145 atom.setAcceleration(xx, yy, zz);
146 }
147 }
148 return a;
149 }
150
151
152
153
154
155
156
157
158 public double[] getGradient(@Nullable double[] g) {
159 if (!stateContains(OpenMM_State_Forces)) {
160 return g;
161 }
162
163 if (g == null || g.length != n) {
164 g = new double[n];
165 }
166
167 double[] forces = getForces();
168 for (int i = 0, index = 0; i < nAtoms; i++, index += 3) {
169 Atom atom = atoms[i];
170 if (atom.isActive()) {
171 double xx = -forces[index] * OpenMM_NmPerAngstrom * OpenMM_KcalPerKJ;
172 double yy = -forces[index + 1] * OpenMM_NmPerAngstrom * OpenMM_KcalPerKJ;
173 double zz = -forces[index + 2] * OpenMM_NmPerAngstrom * OpenMM_KcalPerKJ;
174 if (isNaN(xx) || isInfinite(xx) || isNaN(yy) || isInfinite(yy) || isNaN(zz) || isInfinite(zz)) {
175 StringBuilder sb = new StringBuilder(
176 format(" The gradient of atom %s is (%8.3f,%8.3f,%8.3f).", atom, xx, yy, zz));
177 double[] vals = new double[3];
178 atom.getVelocity(vals);
179 sb.append(format("\n Velocities: %8.3g %8.3g %8.3g", vals[0], vals[1], vals[2]));
180 atom.getAcceleration(vals);
181 sb.append(format("\n Accelerations: %8.3g %8.3g %8.3g", vals[0], vals[1], vals[2]));
182 atom.getPreviousAcceleration(vals);
183 sb.append(
184 format("\n Previous accelerations: %8.3g %8.3g %8.3g", vals[0], vals[1], vals[2]));
185 throw new EnergyException(sb.toString());
186 }
187 g[index] = xx;
188 g[index + 1] = yy;
189 g[index + 2] = zz;
190 atom.setXYZGradient(xx, yy, zz);
191 }
192 }
193 return g;
194 }
195
196
197
198
199
200
201 public double[][] getPeriodicBoxVectors() {
202 if (!stateContains(OpenMM_State_Positions)) {
203 return null;
204 }
205
206 double[][] latticeVectors = super.getPeriodicBoxVectors();
207 latticeVectors[0][0] *= OpenMM_AngstromsPerNm;
208 latticeVectors[0][1] *= OpenMM_AngstromsPerNm;
209 latticeVectors[0][2] *= OpenMM_AngstromsPerNm;
210 latticeVectors[1][0] *= OpenMM_AngstromsPerNm;
211 latticeVectors[1][1] *= OpenMM_AngstromsPerNm;
212 latticeVectors[1][2] *= OpenMM_AngstromsPerNm;
213 latticeVectors[2][0] *= OpenMM_AngstromsPerNm;
214 latticeVectors[2][1] *= OpenMM_AngstromsPerNm;
215 latticeVectors[2][2] *= OpenMM_AngstromsPerNm;
216 return latticeVectors;
217 }
218
219
220
221
222
223
224
225
226 public double[] getPositions(@Nullable double[] x) {
227 if (!stateContains(OpenMM_State_Positions)) {
228 return x;
229 }
230
231 if (x == null || x.length != n) {
232 x = new double[n];
233 }
234
235 double[] pos = getPositions();
236 for (int i = 0, index = 0; i < nAtoms; i++, index += 3) {
237 Atom atom = atoms[i];
238 if (atom.isActive()) {
239 double xx = pos[index] * OpenMM_AngstromsPerNm;
240 double yy = pos[index + 1] * OpenMM_AngstromsPerNm;
241 double zz = pos[index + 2] * OpenMM_AngstromsPerNm;
242 x[index] = xx;
243 x[index + 1] = yy;
244 x[index + 2] = zz;
245 atom.moveTo(xx, yy, zz);
246 }
247 }
248 return x;
249 }
250
251
252
253
254
255
256
257
258 public double[] getVelocities(@Nullable double[] v) {
259 if (!stateContains(OpenMM_State_Velocities)) {
260 return v;
261 }
262
263 if (v == null || v.length != n) {
264 v = new double[n];
265 }
266
267 double[] vel = getVelocities();
268 for (int i = 0, index = 0; i < nAtoms; i++, index += 3) {
269 Atom atom = atoms[i];
270 if (atom.isActive()) {
271 double xx = vel[index] * OpenMM_AngstromsPerNm;
272 double yy = vel[index + 1] * OpenMM_AngstromsPerNm;
273 double zz = vel[index + 2] * OpenMM_AngstromsPerNm;
274 v[index] = xx;
275 v[index + 1] = yy;
276 v[index + 2] = zz;
277 atom.setVelocity(xx, yy, zz);
278 }
279 }
280 return v;
281 }
282
283
284
285
286
287
288 @Override
289 public double getPeriodicBoxVolume() {
290 return super.getPeriodicBoxVolume()
291 * OpenMM_AngstromsPerNm * OpenMM_AngstromsPerNm * OpenMM_AngstromsPerNm;
292 }
293
294
295
296
297
298
299 @Override
300 public double getPotentialEnergy() {
301 return potentialEnergy;
302 }
303
304
305
306
307
308
309 @Override
310 public double getKineticEnergy() {
311 return kineticEnergy;
312 }
313
314
315
316
317
318
319 public double getTotalEnergy() {
320 return totalEnergy;
321 }
322
323
324
325
326
327
328 @Override
329 public int getDataTypes() {
330 return dataTypes;
331 }
332
333
334
335
336
337
338
339 private boolean stateContains(int dataType) {
340 return (dataTypes & dataType) == dataType;
341 }
342 }