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 edu.uiowa.jopenmm.OpenMM_Vec3;
41 import ffx.crystal.Crystal;
42 import ffx.numerics.Potential;
43 import ffx.potential.ForceFieldEnergy;
44 import ffx.potential.bonded.Atom;
45 import ffx.potential.bonded.TorsionTorsion;
46 import ffx.potential.nonbonded.ParticleMeshEwald;
47 import ffx.potential.nonbonded.VanDerWaals;
48 import ffx.potential.terms.TorsionTorsionPotentialEnergy;
49
50 import javax.annotation.Nullable;
51 import java.util.logging.Logger;
52
53 import static edu.uiowa.jopenmm.OpenMMAmoebaLibrary.OpenMM_NmPerAngstrom;
54 import static java.lang.String.format;
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 public class OpenMMDualTopologySystem extends OpenMMSystem {
71
72 private static final Logger logger = Logger.getLogger(OpenMMDualTopologySystem.class.getName());
73
74
75
76
77 private final OpenMMDualTopologyEnergy openMMDualTopologyEnergy;
78
79
80
81
82 protected ForceFieldEnergy forceFieldEnergy;
83
84
85
86 protected ForceFieldEnergy forceFieldEnergy2;
87
88
89
90 protected BondForce bondForce2 = null;
91
92
93
94 protected AngleForce angleForce2 = null;
95
96
97
98 protected InPlaneAngleForce inPlaneAngleForce2 = null;
99
100
101
102 protected StretchBendForce stretchBendForce2 = null;
103
104
105
106 protected UreyBradleyForce ureyBradleyForce2 = null;
107
108
109
110 protected OutOfPlaneBendForce outOfPlaneBendForce2 = null;
111
112
113
114 protected PiOrbitalTorsionForce piOrbitalTorsionForce2 = null;
115
116
117
118 protected TorsionForce torsionForce2 = null;
119
120
121
122 protected ImproperTorsionForce improperTorsionForce2 = null;
123
124
125
126 protected StretchTorsionForce stretchTorsionForce2 = null;
127
128
129
130 protected AngleTorsionForce angleTorsionForce2 = null;
131
132
133
134 protected RestrainTorsionsForce restrainTorsionsForce2 = null;
135
136
137
138
139
140 protected AmoebaTorsionTorsionForce amoebaTorsionTorsionForce2 = null;
141
142
143
144 private AmoebaVdwForce amoebaVDWForce2 = null;
145
146
147
148 private AmoebaMultipoleForce amoebaMultipoleForce2 = null;
149
150
151
152
153
154
155 public OpenMMDualTopologySystem(OpenMMDualTopologyEnergy openMMDualTopologyEnergy) {
156 this.openMMDualTopologyEnergy = openMMDualTopologyEnergy;
157
158 forceFieldEnergy = openMMDualTopologyEnergy.getForceFieldEnergy(0);
159 forceFieldEnergy2 = openMMDualTopologyEnergy.getForceFieldEnergy(1);
160 forceField = openMMDualTopologyEnergy.getMolecularAssembly(0).getForceField();
161
162
163 atoms = openMMDualTopologyEnergy.getDualTopologyAtoms(0);
164
165
166 try {
167 addAtoms();
168 } catch (Exception e) {
169 logger.severe(" Atom without mass encountered.");
170 }
171
172 logger.info(format("\n OpenMM dual-topology system created with %d atoms.", atoms.length));
173 }
174
175
176
177
178
179
180 public Potential getPotential() {
181 return openMMDualTopologyEnergy;
182 }
183
184
185
186
187
188
189 @Override
190 public Crystal getCrystal() {
191 return forceFieldEnergy.getCrystal();
192 }
193
194
195
196
197
198
199
200
201
202
203
204 @Override
205 protected void setDefaultPeriodicBoxVectors() {
206 Crystal crystal = forceFieldEnergy.getCrystal();
207 if (!crystal.aperiodic()) {
208 OpenMM_Vec3 a = new OpenMM_Vec3();
209 OpenMM_Vec3 b = new OpenMM_Vec3();
210 OpenMM_Vec3 c = new OpenMM_Vec3();
211 double[][] Ai = crystal.Ai;
212 a.x = Ai[0][0] * OpenMM_NmPerAngstrom;
213 a.y = Ai[0][1] * OpenMM_NmPerAngstrom;
214 a.z = Ai[0][2] * OpenMM_NmPerAngstrom;
215 b.x = Ai[1][0] * OpenMM_NmPerAngstrom;
216 b.y = Ai[1][1] * OpenMM_NmPerAngstrom;
217 b.z = Ai[1][2] * OpenMM_NmPerAngstrom;
218 c.x = Ai[2][0] * OpenMM_NmPerAngstrom;
219 c.y = Ai[2][1] * OpenMM_NmPerAngstrom;
220 c.z = Ai[2][2] * OpenMM_NmPerAngstrom;
221 setDefaultPeriodicBoxVectors(a, b, c);
222 }
223 }
224
225
226
227
228 @Override
229 public void addForces() {
230 setDefaultPeriodicBoxVectors();
231
232
233
234 boolean rigidHydrogen = forceField.getBoolean("RIGID_HYDROGEN", false);
235 boolean rigidBonds = forceField.getBoolean("RIGID_BONDS", false);
236 boolean rigidHydrogenAngles = forceField.getBoolean("RIGID_HYDROGEN_ANGLES", false);
237 if (rigidHydrogen || rigidBonds || rigidHydrogenAngles) {
238 logger.severe(" Dual Topology does not support rigid hydrogen atoms.");
239 }
240
241 logger.info("\n Bonded Terms\n");
242
243
244 bondForce = (BondForce) BondForce.constructForce(0, openMMDualTopologyEnergy);
245 bondForce2 = (BondForce) BondForce.constructForce(1, openMMDualTopologyEnergy);
246 addForce(bondForce);
247 addForce(bondForce2);
248
249
250 angleForce = (AngleForce) AngleForce.constructForce(0, openMMDualTopologyEnergy);
251 angleForce2 = (AngleForce) AngleForce.constructForce(1, openMMDualTopologyEnergy);
252 addForce(angleForce);
253 addForce(angleForce2);
254
255
256 inPlaneAngleForce = (InPlaneAngleForce) InPlaneAngleForce.constructForce(0, openMMDualTopologyEnergy);
257 inPlaneAngleForce2 = (InPlaneAngleForce) InPlaneAngleForce.constructForce(1, openMMDualTopologyEnergy);
258 addForce(inPlaneAngleForce);
259 addForce(inPlaneAngleForce2);
260
261
262 stretchBendForce = (StretchBendForce) StretchBendForce.constructForce(0, openMMDualTopologyEnergy);
263 stretchBendForce2 = (StretchBendForce) StretchBendForce.constructForce(1, openMMDualTopologyEnergy);
264 addForce(stretchBendForce);
265 addForce(stretchBendForce2);
266
267
268 ureyBradleyForce = (UreyBradleyForce) UreyBradleyForce.constructForce(0, openMMDualTopologyEnergy);
269 ureyBradleyForce2 = (UreyBradleyForce) UreyBradleyForce.constructForce(1, openMMDualTopologyEnergy);
270 addForce(ureyBradleyForce);
271 addForce(ureyBradleyForce2);
272
273
274 outOfPlaneBendForce = (OutOfPlaneBendForce) OutOfPlaneBendForce.constructForce(0, openMMDualTopologyEnergy);
275 outOfPlaneBendForce2 = (OutOfPlaneBendForce) OutOfPlaneBendForce.constructForce(1, openMMDualTopologyEnergy);
276 addForce(outOfPlaneBendForce);
277 addForce(outOfPlaneBendForce2);
278
279
280 piOrbitalTorsionForce = (PiOrbitalTorsionForce) PiOrbitalTorsionForce.constructForce(0, openMMDualTopologyEnergy);
281 piOrbitalTorsionForce2 = (PiOrbitalTorsionForce) PiOrbitalTorsionForce.constructForce(1, openMMDualTopologyEnergy);
282 addForce(piOrbitalTorsionForce);
283 addForce(piOrbitalTorsionForce2);
284
285
286 torsionForce = (TorsionForce) TorsionForce.constructForce(0, openMMDualTopologyEnergy);
287 torsionForce2 = (TorsionForce) TorsionForce.constructForce(1, openMMDualTopologyEnergy);
288 addForce(torsionForce);
289 addForce(torsionForce2);
290
291
292 improperTorsionForce = (ImproperTorsionForce) ImproperTorsionForce.constructForce(0, openMMDualTopologyEnergy);
293 improperTorsionForce2 = (ImproperTorsionForce) ImproperTorsionForce.constructForce(1, openMMDualTopologyEnergy);
294 addForce(improperTorsionForce);
295 addForce(improperTorsionForce2);
296
297
298 stretchTorsionForce = (StretchTorsionForce) StretchTorsionForce.constructForce(0, openMMDualTopologyEnergy);
299 stretchTorsionForce2 = (StretchTorsionForce) StretchTorsionForce.constructForce(1, openMMDualTopologyEnergy);
300 addForce(stretchTorsionForce);
301 addForce(stretchTorsionForce2);
302
303
304 angleTorsionForce = (AngleTorsionForce) AngleTorsionForce.constructForce(0, openMMDualTopologyEnergy);
305 angleTorsionForce2 = (AngleTorsionForce) AngleTorsionForce.constructForce(1, openMMDualTopologyEnergy);
306 addForce(angleTorsionForce);
307 addForce(angleTorsionForce2);
308
309 if (openMMDualTopologyEnergy.getForceFieldEnergy(0).getRestrainMode() == ForceFieldEnergy.RestrainMode.ALCHEMICAL) {
310
311 restrainTorsionsForce = (RestrainTorsionsForce) RestrainTorsionsForce.constructForce(0, openMMDualTopologyEnergy);
312 restrainTorsionsForce2 = (RestrainTorsionsForce) RestrainTorsionsForce.constructForce(1, openMMDualTopologyEnergy);
313 addForce(restrainTorsionsForce);
314 addForce(restrainTorsionsForce2);
315 }
316
317
318
319 amoebaTorsionTorsionForce = (AmoebaTorsionTorsionForce) AmoebaTorsionTorsionForce.constructForce(0, openMMDualTopologyEnergy);
320 addForce(amoebaTorsionTorsionForce);
321
322
323
324
325 TorsionTorsionPotentialEnergy torsionTorsionPotentialEnergy = openMMDualTopologyEnergy.getForceFieldEnergy(0).getTorsionTorsionPotentialEnergy();
326 TorsionTorsionPotentialEnergy torsionTorsionPotentialEnergy2 = openMMDualTopologyEnergy.getForceFieldEnergy(0).getTorsionTorsionPotentialEnergy();
327 int numTorsionTorsions = 0;
328 int numTorsionTorsions2 = 0;
329 if (torsionTorsionPotentialEnergy != null) {
330 numTorsionTorsions = torsionTorsionPotentialEnergy.getNumberOfTorsionTorsions();
331 }
332 if (torsionTorsionPotentialEnergy2 != null) {
333 numTorsionTorsions2 = torsionTorsionPotentialEnergy2.getNumberOfTorsionTorsions();
334 }
335 if (numTorsionTorsions != numTorsionTorsions2) {
336 logger.severe(" The number of Torsion-Torsion forces in the two topologies do not match: "
337 + numTorsionTorsions + " vs. " + numTorsionTorsions2);
338 } else if (numTorsionTorsions != 0) {
339 TorsionTorsion[] torsionTorsion = torsionTorsionPotentialEnergy.getTorsionTorsionArray();
340 TorsionTorsion[] torsionTorsion2 = torsionTorsionPotentialEnergy2.getTorsionTorsionArray();
341
342 for (int i = 0; i < numTorsionTorsions; i++) {
343 TorsionTorsion tt1 = torsionTorsion[i];
344 TorsionTorsion tt2 = torsionTorsion2[i];
345 if (!tt1.equals(tt2)) {
346 logger.severe(" The Torsion-Torsion terms in the two topologies do not match: " + tt1 + " vs. " + tt2);
347 }
348 }
349 }
350
351 VanDerWaals vdW1 = forceFieldEnergy.getVdwNode();
352 VanDerWaals vdW2 = forceFieldEnergy2.getVdwNode();
353 if (vdW1 != null || vdW2 != null) {
354 logger.info("\n Non-Bonded Terms");
355
356 if (vdW1 != null) {
357
358 amoebaVDWForce = (AmoebaVdwForce) AmoebaVdwForce.constructForce(0, openMMDualTopologyEnergy);
359 addForce(amoebaVDWForce);
360 }
361 if (vdW2 != null) {
362
363 amoebaVDWForce2 = (AmoebaVdwForce) AmoebaVdwForce.constructForce(1, openMMDualTopologyEnergy);
364 amoebaVDWForce2.setLambdaName("AmoebaVdwLambda2");
365 addForce(amoebaVDWForce2);
366 }
367
368 ParticleMeshEwald pme = forceFieldEnergy.getPmeNode();
369 ParticleMeshEwald pme2 = forceFieldEnergy2.getPmeNode();
370 if (pme != null) {
371 amoebaMultipoleForce = (AmoebaMultipoleForce) AmoebaMultipoleForce.constructForce(0, openMMDualTopologyEnergy);
372 addForce(amoebaMultipoleForce);
373 }
374 if (pme2 != null) {
375 amoebaMultipoleForce2 = (AmoebaMultipoleForce) AmoebaMultipoleForce.constructForce(1, openMMDualTopologyEnergy);
376 addForce(amoebaMultipoleForce2);
377 }
378
379 }
380 }
381
382
383
384
385
386
387 @Override
388 public int getNumberOfVariables() {
389 int nActive = 0;
390 int nAtoms = atoms.length;
391 for (int i = 0; i < nAtoms; i++) {
392 if (atoms[i].isActive()) {
393 nActive++;
394 }
395 }
396 int ret = nActive * 3;
397 return ret;
398 }
399
400
401
402
403
404
405 @Override
406 public int calculateDegreesOfFreedom() {
407 int dof = getNumberOfVariables();
408
409
410 dof = dof - getNumConstraints();
411
412
413 if (cmMotionRemover != null) {
414 dof -= 3;
415 }
416
417 return dof;
418 }
419
420
421
422
423 @Override
424 public void free() {
425 if (getPointer() != null) {
426 logger.fine(" Free OpenMM dual-topology system.");
427 destroy();
428 logger.fine(" Free OpenMM dual-topology system completed.");
429 }
430 }
431
432
433
434
435
436
437 @Override
438 public void updateParameters(@Nullable Atom[] atoms) {
439
440
441 if (bondForce != null) {
442 bondForce.updateForce(0, openMMDualTopologyEnergy);
443 }
444 if (bondForce2 != null) {
445 bondForce2.updateForce(1, openMMDualTopologyEnergy);
446 }
447 if (angleForce != null) {
448 angleForce.updateForce(0, openMMDualTopologyEnergy);
449 }
450 if (angleForce2 != null) {
451 angleForce2.updateForce(1, openMMDualTopologyEnergy);
452 }
453 if (inPlaneAngleForce != null) {
454 inPlaneAngleForce.updateForce(0, openMMDualTopologyEnergy);
455 }
456 if (inPlaneAngleForce2 != null) {
457 inPlaneAngleForce2.updateForce(1, openMMDualTopologyEnergy);
458 }
459 if (stretchBendForce != null) {
460 stretchBendForce.updateForce(0, openMMDualTopologyEnergy);
461 }
462 if (stretchBendForce2 != null) {
463 stretchBendForce2.updateForce(1, openMMDualTopologyEnergy);
464 }
465 if (ureyBradleyForce != null) {
466 ureyBradleyForce.updateForce(0, openMMDualTopologyEnergy);
467 }
468 if (ureyBradleyForce2 != null) {
469 ureyBradleyForce2.updateForce(1, openMMDualTopologyEnergy);
470 }
471 if (outOfPlaneBendForce != null) {
472 outOfPlaneBendForce.updateForce(0, openMMDualTopologyEnergy);
473 }
474 if (outOfPlaneBendForce2 != null) {
475 outOfPlaneBendForce2.updateForce(1, openMMDualTopologyEnergy);
476 }
477 if (piOrbitalTorsionForce != null) {
478 piOrbitalTorsionForce.updateForce(0, openMMDualTopologyEnergy);
479 }
480 if (piOrbitalTorsionForce2 != null) {
481 piOrbitalTorsionForce2.updateForce(1, openMMDualTopologyEnergy);
482 }
483 if (torsionForce != null) {
484 torsionForce.updateForce(0, openMMDualTopologyEnergy);
485 }
486 if (torsionForce2 != null) {
487 torsionForce2.updateForce(1, openMMDualTopologyEnergy);
488 }
489 if (improperTorsionForce != null) {
490 improperTorsionForce.updateForce(0, openMMDualTopologyEnergy);
491 }
492 if (improperTorsionForce2 != null) {
493 improperTorsionForce2.updateForce(1, openMMDualTopologyEnergy);
494 }
495 if (stretchTorsionForce != null) {
496 stretchTorsionForce.updateForce(0, openMMDualTopologyEnergy);
497 }
498 if (stretchTorsionForce2 != null) {
499 stretchTorsionForce2.updateForce(1, openMMDualTopologyEnergy);
500 }
501 if (angleTorsionForce != null) {
502 angleTorsionForce.updateForce(0, openMMDualTopologyEnergy);
503 }
504 if (angleTorsionForce2 != null) {
505 angleTorsionForce2.updateForce(1, openMMDualTopologyEnergy);
506 }
507 if (restrainTorsionsForce != null) {
508 restrainTorsionsForce.updateForce(0, openMMDualTopologyEnergy);
509 }
510 if (restrainTorsionsForce2 != null) {
511 restrainTorsionsForce2.updateForce(1, openMMDualTopologyEnergy);
512 }
513
514
515
516 if (amoebaVDWForce != null) {
517 VanDerWaals vanDerWaals = forceFieldEnergy.getVdwNode();
518 if (vanDerWaals.getLambdaTerm()) {
519 double lambdaVDW = vanDerWaals.getLambda();
520 openMMDualTopologyEnergy.getContext().setParameter("AmoebaVdwLambda", lambdaVDW);
521 }
522 atoms = forceFieldEnergy.getAtomArray();
523 amoebaVDWForce.updateForce(atoms, 0, openMMDualTopologyEnergy);
524 }
525 if (amoebaVDWForce2 != null) {
526 VanDerWaals vanDerWaals = forceFieldEnergy2.getVdwNode();
527 if (vanDerWaals.getLambdaTerm()) {
528 double lambdaVDW = vanDerWaals.getLambda();
529 openMMDualTopologyEnergy.getContext().setParameter("AmoebaVdwLambda2", lambdaVDW);
530 }
531 atoms = forceFieldEnergy2.getAtomArray();
532 amoebaVDWForce2.updateForce(atoms, 1, openMMDualTopologyEnergy);
533 }
534 if (amoebaMultipoleForce != null) {
535 atoms = forceFieldEnergy.getAtomArray();
536 amoebaMultipoleForce.updateForce(atoms, 0, openMMDualTopologyEnergy);
537 }
538 if (amoebaMultipoleForce2 != null) {
539 atoms = forceFieldEnergy2.getAtomArray();
540 amoebaMultipoleForce2.updateForce(atoms, 1, openMMDualTopologyEnergy);
541 }
542 }
543 }