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.crystal.Crystal;
41 import ffx.numerics.switching.UnivariateSwitchingFunction;
42 import ffx.potential.DualTopologyEnergy;
43 import ffx.potential.ForceFieldEnergy;
44 import ffx.potential.MolecularAssembly;
45 import ffx.potential.Platform;
46 import ffx.potential.bonded.Atom;
47 import ffx.potential.parameters.ForceField;
48 import ffx.potential.utils.EnergyException;
49
50 import javax.annotation.Nullable;
51 import java.util.logging.Level;
52 import java.util.logging.Logger;
53
54 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_State_DataType.OpenMM_State_Energy;
55 import static java.lang.Double.isFinite;
56 import static java.lang.String.format;
57
58 public class OpenMMDualTopologyEnergy extends DualTopologyEnergy implements OpenMMPotential {
59
60 private static final Logger logger = Logger.getLogger(OpenMMDualTopologyEnergy.class.getName());
61
62
63
64
65 private final OpenMMContext openMMContext;
66
67
68
69 private final OpenMMDualTopologySystem openMMDualTopologySystem;
70
71
72
73 private final Atom[] atoms;
74
75
76
77 private final MolecularAssembly molecularAssembly1;
78
79
80
81 private final MolecularAssembly molecularAssembly2;
82
83
84
85
86
87
88
89
90
91 public OpenMMDualTopologyEnergy(MolecularAssembly topology1, MolecularAssembly topology2,
92 UnivariateSwitchingFunction switchFunction, Platform requestedPlatform) {
93 super(topology1, topology2, switchFunction);
94
95 logger.info("\n Initializing an OpenMM Dual Topology System.");
96
97 molecularAssembly1 = topology1;
98 molecularAssembly2 = topology2;
99
100
101 Crystal crystal1 = molecularAssembly1.getCrystal();
102 int symOps1 = crystal1.spaceGroup.getNumberOfSymOps();
103 Crystal crystal2 = molecularAssembly2.getCrystal();
104 int symOps2 = crystal2.spaceGroup.getNumberOfSymOps();
105 if (symOps1 > 1 || symOps2 > 1) {
106 logger.severe(" OpenMM does not support symmetry operators.");
107 }
108
109
110 ForceField forceField = topology1.getForceField();
111 ffx.openmm.Platform openMMPlatform = OpenMMContext.loadPlatform(requestedPlatform, forceField);
112
113
114 openMMDualTopologySystem = new OpenMMDualTopologySystem(this);
115 openMMDualTopologySystem.addForces();
116
117 atoms = getDualTopologyAtoms(0);
118
119
120 openMMContext = new OpenMMContext(openMMPlatform, openMMDualTopologySystem, atoms);
121 }
122
123
124
125
126
127 @Override
128 public double energy(double[] x) {
129 return energy(x, false);
130 }
131
132
133
134
135 @Override
136 public double energy(double[] x, boolean verbose) {
137
138 openMMContext.update();
139
140 updateParameters(atoms);
141
142
143 unscaleCoordinates(x);
144 setCoordinates(x);
145
146 OpenMMState openMMState = openMMContext.getOpenMMState(OpenMM_State_Energy);
147 double e = openMMState.potentialEnergy;
148 openMMState.destroy();
149
150 if (!isFinite(e)) {
151 String message = format(" OpenMMDualTopologyEnergy was a non-finite %8g", e);
152 logger.warning(message);
153 throw new EnergyException(message);
154 }
155
156 if (verbose) {
157 logger.log(Level.INFO, format("\n OpenMM Energy: %14.10g", e));
158 }
159
160 return e;
161 }
162
163
164
165
166
167
168
169 public double energyFFX(double[] x) {
170 return super.energy(x, false);
171 }
172
173
174
175
176
177
178
179
180 public double energyFFX(double[] x, boolean verbose) {
181 return super.energy(x, verbose);
182 }
183
184
185
186
187
188
189
190 @Override
191 public void setCoordinates(double[] x) {
192
193 super.setCoordinates(x);
194
195 int n = atoms.length * 3;
196 double[] xall = new double[n];
197 int i = 0;
198 for (Atom atom : atoms) {
199 xall[i] = atom.getX();
200 xall[i + 1] = atom.getY();
201 xall[i + 2] = atom.getZ();
202 i += 3;
203 }
204
205
206 openMMContext.setPositions(xall);
207 }
208
209
210
211
212
213
214 @Override
215 public void setVelocity(double[] v) {
216
217 super.setVelocity(v);
218
219 int n = atoms.length * 3;
220 double[] vall = new double[n];
221 double[] v3 = new double[3];
222 int i = 0;
223 for (Atom atom : atoms) {
224 atom.getVelocity(v3);
225
226 if (!atom.isActive()) {
227 v3[0] = 0.0;
228 v3[1] = 0.0;
229 v3[2] = 0.0;
230 atom.setVelocity(v3);
231 }
232 vall[i] = v3[0];
233 vall[i + 1] = v3[1];
234 vall[i + 2] = v3[2];
235 i += 3;
236 }
237
238
239 openMMContext.setVelocities(vall);
240 }
241
242
243
244
245
246
247
248
249 public MolecularAssembly getMolecularAssembly(int topology) {
250 if (topology == 0) {
251 return molecularAssembly1;
252 } else if (topology == 1) {
253 return molecularAssembly2;
254 } else {
255 throw new IllegalArgumentException(" Invalid topology index: " + topology);
256 }
257 }
258
259
260
261
262
263
264
265 public ForceFieldEnergy getForceFieldEnergy(int topology) {
266 if (topology == 0) {
267 return getForceFieldEnergy1();
268 } else if (topology == 1) {
269 return getForceFieldEnergy2();
270 } else {
271 throw new IllegalArgumentException(" Invalid topology index: " + topology);
272 }
273 }
274
275
276
277
278
279
280 @Override
281 public void updateParameters(@Nullable Atom[] atoms) {
282 if (atoms == null) {
283 atoms = this.atoms;
284 }
285 if (openMMDualTopologySystem != null) {
286 openMMDualTopologySystem.updateParameters(atoms);
287 }
288 }
289
290
291
292
293
294
295 @Override
296 public OpenMMContext getContext() {
297 return openMMContext;
298 }
299
300
301
302
303
304
305
306
307
308
309
310
311 @Override
312 public void updateContext(String integratorName, double timeStep, double temperature, boolean forceCreation) {
313 openMMContext.update(integratorName, timeStep, temperature, forceCreation);
314 }
315
316
317
318
319
320
321
322
323
324 @Override
325 public OpenMMState getOpenMMState(int mask) {
326 return openMMContext.getOpenMMState(mask);
327 }
328
329
330
331
332
333
334 @Override
335 public OpenMMSystem getSystem() {
336 return openMMDualTopologySystem;
337 }
338
339
340
341
342 @Override
343 public boolean setActiveAtoms() {
344 return openMMDualTopologySystem.updateAtomMass();
345 }
346
347 }