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