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.openmm.AndersenThermostat;
43 import ffx.openmm.CMMotionRemover;
44 import ffx.openmm.Force;
45 import ffx.openmm.MonteCarloBarostat;
46 import ffx.potential.MolecularAssembly;
47 import ffx.potential.bonded.Angle;
48 import ffx.potential.bonded.Atom;
49 import ffx.potential.bonded.Bond;
50 import ffx.potential.nonbonded.GeneralizedKirkwood;
51 import ffx.potential.nonbonded.VanDerWaals;
52 import ffx.potential.nonbonded.VanDerWaalsForm;
53 import ffx.potential.nonbonded.implicit.ChandlerCavitation;
54 import ffx.potential.nonbonded.implicit.DispersionRegion;
55 import ffx.potential.parameters.BondType;
56 import ffx.potential.parameters.ForceField;
57 import ffx.utilities.Constants;
58 import org.apache.commons.configuration2.CompositeConfiguration;
59
60 import javax.annotation.Nullable;
61 import java.util.logging.Level;
62 import java.util.logging.Logger;
63
64 import static edu.uiowa.jopenmm.OpenMMAmoebaLibrary.OpenMM_NmPerAngstrom;
65 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_Boolean.OpenMM_True;
66 import static ffx.potential.nonbonded.VanDerWaalsForm.VDW_TYPE.LENNARD_JONES;
67 import static ffx.utilities.Constants.KCAL_TO_GRAM_ANG2_PER_PS2;
68 import static ffx.utilities.Constants.kB;
69 import static java.lang.String.format;
70 import static org.apache.commons.math3.util.FastMath.cos;
71 import static org.apache.commons.math3.util.FastMath.pow;
72 import static org.apache.commons.math3.util.FastMath.sqrt;
73 import static org.apache.commons.math3.util.FastMath.toRadians;
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89 public class OpenMMSystem extends ffx.openmm.System {
90
91 private static final Logger logger = Logger.getLogger(OpenMMSystem.class.getName());
92
93 private static final double DEFAULT_MELD_SCALE_FACTOR = -1.0;
94
95
96
97 private final OpenMMEnergy openMMEnergy;
98
99
100
101 private final OpenMMContext openMMContext;
102 private final double meldScaleFactor;
103
104
105
106
107 private final boolean useMeld;
108
109
110
111 private final ForceField forceField;
112
113
114
115 private final Atom[] atoms;
116
117
118
119
120 private boolean updateBondedTerms = false;
121
122
123
124 private BondForce bondForce = null;
125
126
127
128 private AngleForce angleForce = null;
129
130
131
132 private InPlaneAngleForce inPlaneAngleForce = null;
133
134
135
136 private StretchBendForce stretchBendForce = null;
137
138
139
140 private UreyBradleyForce ureyBradleyForce = null;
141
142
143
144 private OutOfPlaneBendForce outOfPlaneBendForce = null;
145
146
147
148 private PiOrbitalTorsionForce piOrbitalTorsionForce = null;
149
150
151
152 private TorsionForce torsionForce = null;
153
154
155
156 private ImproperTorsionForce improperTorsionForce = null;
157
158
159
160 private AmoebaTorsionTorsionForce amoebaTorsionTorsionForce = null;
161
162
163
164 private StretchTorsionForce stretchTorsionForce = null;
165
166
167
168 private AngleTorsionForce angleTorsionForce = null;
169
170
171
172 private RestrainTorsionsForce restrainTorsionsForce = null;
173
174
175
176 private RestrainPositionsForce restrainPositionsForce = null;
177
178
179
180 private RestrainGroupsForce restrainGroupsForce = null;
181
182
183
184 private AmoebaVdwForce amoebaVDWForce = null;
185
186
187
188 private AmoebaMultipoleForce amoebaMultipoleForce = null;
189
190
191
192 private AmoebaGeneralizedKirkwoodForce amoebaGeneralizedKirkwoodForce = null;
193
194
195
196 private AmoebaWcaDispersionForce amoebaWcaDispersionForce = null;
197
198
199
200 private AmoebaGKCavitationForce amoebaGKCavitationForce = null;
201
202
203
204 private FixedChargeGBForce fixedChargeGBForce = null;
205
206
207
208 private FixedChargeNonbondedForce fixedChargeNonBondedForce = null;
209
210
211
212 private FixedChargeAlchemicalForces fixedChargeAlchemicalForces = null;
213
214
215
216 private AndersenThermostat andersenThermostat = null;
217
218
219
220 private MonteCarloBarostat monteCarloBarostat = null;
221
222
223
224 private CMMotionRemover cmMotionRemover = null;
225
226
227
228 private boolean softcoreCreated = false;
229
230
231
232
233 private boolean elecLambdaTerm;
234
235
236
237
238 private boolean vdwLambdaTerm;
239
240
241
242
243 private boolean torsionLambdaTerm;
244
245
246
247 private double lambdaVDW = 1.0;
248
249
250
251 private double lambdaElec = 1.0;
252
253
254
255 private double lambdaTorsion = 1.0;
256
257
258
259
260
261
262
263 private double electrostaticStart = 0.6;
264
265
266
267 private double electrostaticLambdaPower;
268
269
270
271 private double vdWSoftcoreAlpha = 0.25;
272
273
274
275 private double vdwSoftcorePower = 3.0;
276
277
278
279 private double torsionalLambdaPower = 2.0;
280
281
282
283
284
285
286 public OpenMMSystem(OpenMMEnergy openMMEnergy) {
287 this.openMMEnergy = openMMEnergy;
288 this.openMMContext = openMMEnergy.getContext();
289
290 logger.info("\n System created");
291
292 MolecularAssembly molecularAssembly = openMMEnergy.getMolecularAssembly();
293 forceField = molecularAssembly.getForceField();
294 atoms = molecularAssembly.getAtomArray();
295
296
297 try {
298 addAtoms();
299 } catch (Exception e) {
300 logger.severe(" Atom without mass encountered.");
301 }
302
303
304 meldScaleFactor = forceField.getDouble("MELD_SCALE_FACTOR", DEFAULT_MELD_SCALE_FACTOR);
305 if (meldScaleFactor <= 1.0 && meldScaleFactor > 0.0) {
306 useMeld = true;
307 elecLambdaTerm = true;
308 vdwLambdaTerm = true;
309 torsionLambdaTerm = true;
310 } else {
311 useMeld = false;
312 elecLambdaTerm = false;
313 vdwLambdaTerm = false;
314 torsionLambdaTerm = false;
315 }
316
317
318 elecLambdaTerm = forceField.getBoolean("ELEC_LAMBDATERM", elecLambdaTerm);
319 vdwLambdaTerm = forceField.getBoolean("VDW_LAMBDATERM", vdwLambdaTerm);
320 torsionLambdaTerm = forceField.getBoolean("TORSION_LAMBDATERM", torsionLambdaTerm);
321
322 if (!forceField.getBoolean("LAMBDATERM", false)) {
323 openMMEnergy.setLambdaTerm(elecLambdaTerm || vdwLambdaTerm || torsionLambdaTerm);
324 } else {
325 openMMEnergy.setLambdaTerm(true);
326 }
327
328 VanDerWaals vdW = openMMEnergy.getVdwNode();
329 if (vdW != null) {
330 vdWSoftcoreAlpha = vdW.getAlpha();
331 vdwSoftcorePower = (int) vdW.getBeta();
332 }
333
334 electrostaticStart = forceField.getDouble("PERMANENT_LAMBDA_START", electrostaticStart);
335 if (electrostaticStart > 1.0) {
336 electrostaticStart = 1.0;
337 } else if (electrostaticStart < 0.0) {
338 electrostaticStart = 0.0;
339 }
340 electrostaticLambdaPower = forceField.getDouble("PERMANENT_LAMBDA_EXPONENT", 2.0);
341
342 if (useMeld) {
343
344 openMMEnergy.setLambdaStart(0.0);
345
346 electrostaticStart = 0.0;
347
348 electrostaticLambdaPower = 1.0;
349
350 vdwSoftcorePower = 1;
351
352 vdWSoftcoreAlpha = 0.0;
353
354 torsionalLambdaPower = 1.0;
355
356 openMMEnergy.setTwoSidedFiniteDifference(false);
357 }
358 }
359
360
361
362
363 public void addForces() {
364
365
366
367 boolean rigidHydrogen = forceField.getBoolean("RIGID_HYDROGEN", false);
368 boolean rigidBonds = forceField.getBoolean("RIGID_BONDS", false);
369 boolean rigidHydrogenAngles = forceField.getBoolean("RIGID_HYDROGEN_ANGLES", false);
370 if (rigidHydrogen) {
371 addHydrogenConstraints();
372 }
373 if (rigidBonds) {
374 addUpBondConstraints();
375 }
376 if (rigidHydrogenAngles) {
377 setUpHydrogenAngleConstraints();
378 }
379
380 logger.info("\n Bonded Terms\n");
381
382
383 if (rigidBonds) {
384 logger.info(" Not creating AmoebaBondForce because bonds are constrained.");
385 } else {
386 bondForce = (BondForce) BondForce.constructForce(openMMEnergy);
387 addForce(bondForce);
388 }
389
390
391 angleForce = (AngleForce) AngleForce.constructForce(openMMEnergy);
392 addForce(angleForce);
393
394
395 inPlaneAngleForce = (InPlaneAngleForce) InPlaneAngleForce.constructForce(openMMEnergy);
396 addForce(inPlaneAngleForce);
397
398
399 stretchBendForce = (StretchBendForce) StretchBendForce.constructForce(openMMEnergy);
400 addForce(stretchBendForce);
401
402
403 ureyBradleyForce = (UreyBradleyForce) UreyBradleyForce.constructForce(openMMEnergy);
404 addForce(ureyBradleyForce);
405
406
407 outOfPlaneBendForce = (OutOfPlaneBendForce) OutOfPlaneBendForce.constructForce(openMMEnergy);
408 addForce(outOfPlaneBendForce);
409
410
411 piOrbitalTorsionForce = (PiOrbitalTorsionForce) PiOrbitalTorsionForce.constructForce(openMMEnergy);
412 addForce(piOrbitalTorsionForce);
413
414
415 torsionForce = (TorsionForce) TorsionForce.constructForce(openMMEnergy);
416 addForce(torsionForce);
417
418
419 improperTorsionForce = (ImproperTorsionForce) ImproperTorsionForce.constructForce(openMMEnergy);
420 addForce(improperTorsionForce);
421
422
423 stretchTorsionForce = (StretchTorsionForce) StretchTorsionForce.constructForce(openMMEnergy);
424 addForce(stretchTorsionForce);
425
426
427 angleTorsionForce = (AngleTorsionForce) AngleTorsionForce.constructForce(openMMEnergy);
428 addForce(angleTorsionForce);
429
430
431 amoebaTorsionTorsionForce = (AmoebaTorsionTorsionForce) AmoebaTorsionTorsionForce.constructForce(openMMEnergy);
432 addForce(amoebaTorsionTorsionForce);
433
434
435 restrainPositionsForce = (RestrainPositionsForce) RestrainPositionsForce.constructForce(openMMEnergy);
436 addForce(restrainPositionsForce);
437
438
439 for (BondType.BondFunction function : BondType.BondFunction.values()) {
440 RestrainBondsForce restrainBondsForce = (RestrainBondsForce) RestrainBondsForce.constructForce(function, openMMEnergy);
441 addForce(restrainBondsForce);
442 }
443
444
445 restrainTorsionsForce = (RestrainTorsionsForce) RestrainTorsionsForce.constructForce(openMMEnergy);
446 addForce(restrainTorsionsForce);
447
448
449 restrainGroupsForce = (RestrainGroupsForce) RestrainGroupsForce.constructForce(openMMEnergy);
450 addForce(restrainGroupsForce);
451
452 setDefaultPeriodicBoxVectors();
453
454 VanDerWaals vdW = openMMEnergy.getVdwNode();
455 if (vdW != null) {
456 logger.info("\n Non-Bonded Terms\n");
457 VanDerWaalsForm vdwForm = vdW.getVDWForm();
458 if (vdwForm.vdwType == LENNARD_JONES) {
459 fixedChargeNonBondedForce = (FixedChargeNonbondedForce) FixedChargeNonbondedForce.constructForce(openMMEnergy);
460 addForce(fixedChargeNonBondedForce);
461 if (fixedChargeNonBondedForce != null) {
462 GeneralizedKirkwood gk = openMMEnergy.getGK();
463 if (gk != null) {
464 fixedChargeGBForce = (FixedChargeGBForce) FixedChargeGBForce.constructForce(openMMEnergy);
465 addForce(fixedChargeGBForce);
466 }
467 }
468 } else {
469
470 amoebaVDWForce = (AmoebaVdwForce) AmoebaVdwForce.constructForce(openMMEnergy);
471 addForce(amoebaVDWForce);
472
473
474 amoebaMultipoleForce = (AmoebaMultipoleForce) AmoebaMultipoleForce.constructForce(openMMEnergy);
475 addForce(amoebaMultipoleForce);
476
477
478 GeneralizedKirkwood gk = openMMEnergy.getGK();
479 if (gk != null) {
480 amoebaGeneralizedKirkwoodForce = (AmoebaGeneralizedKirkwoodForce) AmoebaGeneralizedKirkwoodForce.constructForce(openMMEnergy);
481 addForce(amoebaGeneralizedKirkwoodForce);
482
483
484 DispersionRegion dispersionRegion = gk.getDispersionRegion();
485 if (dispersionRegion != null) {
486 amoebaWcaDispersionForce = (AmoebaWcaDispersionForce) AmoebaWcaDispersionForce.constructForce(openMMEnergy);
487 addForce(amoebaWcaDispersionForce);
488 }
489
490
491 ChandlerCavitation chandlerCavitation = gk.getChandlerCavitation();
492 if (chandlerCavitation != null && chandlerCavitation.getGaussVol() != null) {
493 amoebaGKCavitationForce = (AmoebaGKCavitationForce) AmoebaGKCavitationForce.constructForce(openMMEnergy);
494 addForce(amoebaGKCavitationForce);
495 }
496 }
497 }
498 }
499
500 if (openMMEnergy.getLambdaTerm()) {
501 logger.info(format("\n Lambda path start: %6.3f", openMMEnergy.getLambdaStart()));
502 logger.info(format(" Lambda scales torsions: %s", torsionLambdaTerm));
503 if (torsionLambdaTerm) {
504 logger.info(format(" torsion lambda power: %6.3f", torsionalLambdaPower));
505 }
506 logger.info(format(" Lambda scales vdW interactions: %s", vdwLambdaTerm));
507 if (vdwLambdaTerm) {
508 logger.info(format(" van Der Waals alpha: %6.3f", vdWSoftcoreAlpha));
509 logger.info(format(" van Der Waals lambda power: %6.3f", vdwSoftcorePower));
510 }
511 logger.info(format(" Lambda scales electrostatics: %s", elecLambdaTerm));
512
513 if (elecLambdaTerm) {
514 logger.info(format(" Electrostatics start: %6.3f", electrostaticStart));
515 logger.info(format(" Electrostatics lambda power: %6.3f", electrostaticLambdaPower));
516 }
517 logger.info(format(" Using Meld: %s", useMeld));
518 if (useMeld) {
519 logger.info(format(" Meld scale factor: %6.3f", meldScaleFactor));
520 }
521 }
522 }
523
524
525
526
527
528 public void removeForce(Force force) {
529 if (force != null) {
530 removeForce(force.getForceIndex());
531 }
532 }
533
534
535
536
537
538
539 public void addAndersenThermostatForce(double targetTemp) {
540 double collisionFreq = forceField.getDouble("COLLISION_FREQ", 0.1);
541 addAndersenThermostatForce(targetTemp, collisionFreq);
542 }
543
544
545
546
547
548
549
550 public void addAndersenThermostatForce(double targetTemp, double collisionFreq) {
551 if (andersenThermostat != null) {
552 removeForce(andersenThermostat);
553 andersenThermostat = null;
554 }
555 andersenThermostat = new AndersenThermostat(targetTemp, collisionFreq);
556 addForce(andersenThermostat);
557 logger.info("\n Adding an Andersen thermostat");
558 logger.info(format(" Target Temperature: %6.2f (K)", targetTemp));
559 logger.info(format(" Collision Frequency: %6.2f (1/psec)", collisionFreq));
560 }
561
562
563
564
565 public void addCOMMRemoverForce() {
566 if (cmMotionRemover != null) {
567 removeForce(cmMotionRemover);
568 cmMotionRemover = null;
569 }
570 int frequency = 100;
571 cmMotionRemover = new CMMotionRemover(frequency);
572 addForce(cmMotionRemover);
573 logger.info("\n Added a Center of Mass Motion Remover");
574 logger.info(format(" Frequency: %6d", frequency));
575 }
576
577
578
579
580
581
582
583
584 public void addMonteCarloBarostatForce(double targetPressure, double targetTemp, int frequency) {
585 if (monteCarloBarostat != null) {
586 removeForce(monteCarloBarostat);
587 monteCarloBarostat = null;
588 }
589 double pressureInBar = targetPressure * Constants.ATM_TO_BAR;
590 monteCarloBarostat = new MonteCarloBarostat(pressureInBar, targetTemp, frequency);
591 CompositeConfiguration properties = openMMEnergy.getMolecularAssembly().getProperties();
592 if (properties.containsKey("barostat-seed")) {
593 int randomSeed = properties.getInt("barostat-seed", 0);
594 logger.info(format(" Setting random seed %d for Monte Carlo Barostat", randomSeed));
595 monteCarloBarostat.setRandomNumberSeed(randomSeed);
596 }
597 addForce(monteCarloBarostat);
598 logger.info("\n Added a Monte Carlo Barostat");
599 logger.info(format(" Target Pressure: %6.2f (atm)", targetPressure));
600 logger.info(format(" Target Temperature: %6.2f (K)", targetTemp));
601 logger.info(format(" MC Move Frequency: %6d", frequency));
602 }
603
604
605
606
607
608
609 public int calculateDegreesOfFreedom() {
610
611 int dof = openMMEnergy.getNumberOfVariables();
612
613 dof = dof - getNumConstraints();
614
615 if (cmMotionRemover != null) {
616 dof -= 3;
617 }
618 return dof;
619 }
620
621 public double getTemperature(double kineticEnergy) {
622 double dof = calculateDegreesOfFreedom();
623 return 2.0 * kineticEnergy * KCAL_TO_GRAM_ANG2_PER_PS2 / (kB * dof);
624 }
625
626
627
628
629
630
631 public ForceField getForceField() {
632 return forceField;
633 }
634
635
636
637
638 public void free() {
639 if (getPointer() != null) {
640 logger.fine(" Free OpenMM system.");
641 destroy();
642 logger.fine(" Free OpenMM system completed.");
643 }
644 }
645
646
647
648
649 public void printLambdaValues() {
650 logger.info(format("\n Lambda Values\n Torsion: %6.3f vdW: %6.3f Elec: %6.3f ", lambdaTorsion,
651 lambdaVDW, lambdaElec));
652 }
653
654
655
656
657
658
659 public void setLambda(double lambda) {
660
661
662 lambdaTorsion = 1.0;
663
664
665 lambdaVDW = 1.0;
666
667
668 lambdaElec = 1.0;
669
670 if (torsionLambdaTerm) {
671
672 lambdaTorsion = pow(lambda, torsionalLambdaPower);
673 if (useMeld) {
674 lambdaTorsion = meldScaleFactor + lambda * (1.0 - meldScaleFactor);
675 }
676 }
677
678 if (elecLambdaTerm && vdwLambdaTerm) {
679
680 if (lambda < electrostaticStart) {
681
682 lambdaElec = 0.0;
683 } else {
684
685 double elecWindow = 1.0 - electrostaticStart;
686 lambdaElec = (lambda - electrostaticStart) / elecWindow;
687 lambdaElec = pow(lambdaElec, electrostaticLambdaPower);
688 }
689 lambdaVDW = lambda;
690 if (useMeld) {
691 lambdaElec = sqrt(meldScaleFactor + lambda * (1.0 - meldScaleFactor));
692 lambdaVDW = meldScaleFactor + lambda * (1.0 - meldScaleFactor);
693 }
694 } else if (vdwLambdaTerm) {
695
696 lambdaElec = 0.0;
697 lambdaVDW = lambda;
698 if (useMeld) {
699 lambdaVDW = meldScaleFactor + lambda * (1.0 - meldScaleFactor);
700 }
701
702 } else if (elecLambdaTerm) {
703
704 lambdaElec = lambda;
705 if (useMeld) {
706 lambdaElec = sqrt(meldScaleFactor + lambda * (1.0 - meldScaleFactor));
707 }
708 }
709 }
710
711
712
713
714
715
716 public boolean getVdwLambdaTerm() {
717 return vdwLambdaTerm;
718 }
719
720
721
722
723
724
725 public double getVdWSoftcoreAlpha() {
726 return vdWSoftcoreAlpha;
727 }
728
729
730
731
732
733
734 public double getVdwSoftcorePower() {
735 return vdwSoftcorePower;
736 }
737
738 public void setUpdateBondedTerms(boolean updateBondedTerms) {
739 this.updateBondedTerms = updateBondedTerms;
740 }
741
742
743
744
745
746
747
748
749
750
751
752 private void setDefaultPeriodicBoxVectors() {
753 Crystal crystal = openMMEnergy.getCrystal();
754 if (!crystal.aperiodic()) {
755 OpenMM_Vec3 a = new OpenMM_Vec3();
756 OpenMM_Vec3 b = new OpenMM_Vec3();
757 OpenMM_Vec3 c = new OpenMM_Vec3();
758 double[][] Ai = crystal.Ai;
759 a.x = Ai[0][0] * OpenMM_NmPerAngstrom;
760 a.y = Ai[0][1] * OpenMM_NmPerAngstrom;
761 a.z = Ai[0][2] * OpenMM_NmPerAngstrom;
762 b.x = Ai[1][0] * OpenMM_NmPerAngstrom;
763 b.y = Ai[1][1] * OpenMM_NmPerAngstrom;
764 b.z = Ai[1][2] * OpenMM_NmPerAngstrom;
765 c.x = Ai[2][0] * OpenMM_NmPerAngstrom;
766 c.y = Ai[2][1] * OpenMM_NmPerAngstrom;
767 c.z = Ai[2][2] * OpenMM_NmPerAngstrom;
768 setDefaultPeriodicBoxVectors(a, b, c);
769 }
770 }
771
772 public double getLambdaElec() {
773 return lambdaElec;
774 }
775
776
777
778
779
780
781 public void updateParameters(@Nullable Atom[] atoms) {
782 if (vdwLambdaTerm) {
783 if (fixedChargeNonBondedForce != null) {
784 if (!softcoreCreated) {
785 fixedChargeAlchemicalForces = new FixedChargeAlchemicalForces(openMMEnergy, fixedChargeNonBondedForce);
786 addForce(fixedChargeAlchemicalForces.getFixedChargeSoftcoreForce());
787 addForce(fixedChargeAlchemicalForces.getAlchemicalAlchemicalStericsForce());
788 addForce(fixedChargeAlchemicalForces.getNonAlchemicalAlchemicalStericsForce());
789
790 openMMContext.reinitialize(OpenMM_True);
791 softcoreCreated = true;
792 }
793 openMMContext.setParameter("vdw_lambda", lambdaVDW);
794 } else if (amoebaVDWForce != null) {
795 openMMContext.setParameter("AmoebaVdwLambda", lambdaVDW);
796 if (softcoreCreated) {
797
798 if (!torsionLambdaTerm && !elecLambdaTerm) {
799 return;
800 }
801 } else {
802 softcoreCreated = true;
803 }
804 }
805 }
806
807
808
809 if (updateBondedTerms) {
810 if (bondForce != null) {
811 bondForce.updateForce(openMMEnergy);
812 }
813 if (angleForce != null) {
814 angleForce.updateForce(openMMEnergy);
815 }
816 if (inPlaneAngleForce != null) {
817 inPlaneAngleForce.updateForce(openMMEnergy);
818 }
819 if (stretchBendForce != null) {
820 stretchBendForce.updateForce(openMMEnergy);
821 }
822 if (ureyBradleyForce != null) {
823 ureyBradleyForce.updateForce(openMMEnergy);
824 }
825 if (outOfPlaneBendForce != null) {
826 outOfPlaneBendForce.updateForce(openMMEnergy);
827 }
828 if (piOrbitalTorsionForce != null) {
829 piOrbitalTorsionForce.updateForce(openMMEnergy);
830 }
831 }
832
833 if (torsionLambdaTerm || updateBondedTerms) {
834 if (torsionForce != null) {
835 torsionForce.setLambdaTorsion(lambdaTorsion);
836 torsionForce.updateForce(openMMEnergy);
837 }
838 if (improperTorsionForce != null) {
839 improperTorsionForce.setLambdaTorsion(lambdaTorsion);
840 improperTorsionForce.updateForce(openMMEnergy);
841 }
842 }
843
844 if (restrainTorsionsForce != null) {
845 restrainTorsionsForce.updateForce(openMMEnergy);
846 }
847
848 if (atoms == null || atoms.length == 0) {
849 return;
850 }
851
852
853 if (fixedChargeNonBondedForce != null) {
854 fixedChargeNonBondedForce.updateForce(atoms, openMMEnergy);
855 }
856
857
858 if (fixedChargeGBForce != null) {
859 fixedChargeGBForce.updateForce(atoms, openMMEnergy);
860 }
861
862
863 if (amoebaVDWForce != null) {
864 amoebaVDWForce.updateForce(atoms, openMMEnergy);
865 }
866
867
868 if (amoebaMultipoleForce != null) {
869 amoebaMultipoleForce.updateForce(atoms, openMMEnergy);
870 }
871
872
873 if (amoebaGeneralizedKirkwoodForce != null) {
874 amoebaGeneralizedKirkwoodForce.updateForce(atoms, openMMEnergy);
875 }
876
877
878 if (amoebaWcaDispersionForce != null) {
879 amoebaWcaDispersionForce.updateForce(atoms, openMMEnergy);
880 }
881
882
883 if (amoebaGKCavitationForce != null) {
884 amoebaGKCavitationForce.updateForce(atoms, openMMEnergy);
885 }
886 }
887
888
889
890
891
892 private void addAtoms() throws Exception {
893 double totalMass = 0.0;
894 for (Atom atom : atoms) {
895 double mass = atom.getMass();
896 totalMass += mass;
897 if (mass < 0.0) {
898 throw new Exception(" Atom with mass less than 0.");
899 }
900 if (mass == 0.0) {
901 logger.info(format(" Atom %s has zero mass.", atom));
902 }
903 addParticle(mass);
904 }
905 logger.log(Level.INFO, format(" Atoms \t\t%6d", atoms.length));
906 logger.log(Level.INFO, format(" Mass \t\t%12.3f", totalMass));
907 }
908
909
910
911
912 public void updateAtomMass() {
913 int index = 0;
914 for (Atom atom : atoms) {
915 double mass = 0.0;
916 if (atom.isActive()) {
917 mass = atom.getMass();
918 }
919 setParticleMass(index++, mass);
920 }
921 }
922
923 public boolean hasAmoebaCavitationForce() {
924 return amoebaGKCavitationForce != null;
925 }
926
927
928
929
930 private void addUpBondConstraints() {
931 Bond[] bonds = openMMEnergy.getBonds();
932 if (bonds == null || bonds.length < 1) {
933 return;
934 }
935
936 logger.info(" Adding constraints for all bonds.");
937 for (Bond bond : bonds) {
938 Atom atom1 = bond.getAtom(0);
939 Atom atom2 = bond.getAtom(1);
940 int iAtom1 = atom1.getXyzIndex() - 1;
941 int iAtom2 = atom2.getXyzIndex() - 1;
942 addConstraint(iAtom1, iAtom2, bond.bondType.distance * OpenMM_NmPerAngstrom);
943 }
944 }
945
946
947
948
949 private void addHydrogenConstraints() {
950 Bond[] bonds = openMMEnergy.getBonds();
951 if (bonds == null || bonds.length < 1) {
952 return;
953 }
954
955 logger.info(" Adding constraints for hydrogen bonds.");
956 for (Bond bond : bonds) {
957 Atom atom1 = bond.getAtom(0);
958 Atom atom2 = bond.getAtom(1);
959 if (atom1.isHydrogen() || atom2.isHydrogen()) {
960 BondType bondType = bond.bondType;
961 int iAtom1 = atom1.getXyzIndex() - 1;
962 int iAtom2 = atom2.getXyzIndex() - 1;
963 addConstraint(iAtom1, iAtom2, bondType.distance * OpenMM_NmPerAngstrom);
964 }
965 }
966 }
967
968
969
970
971 private void setUpHydrogenAngleConstraints() {
972 Angle[] angles = openMMEnergy.getAngles();
973 if (angles == null || angles.length < 1) {
974 return;
975 }
976
977 logger.info(" Adding hydrogen angle constraints.");
978
979 for (Angle angle : angles) {
980 if (isHydrogenAngle(angle)) {
981 Atom atom1 = angle.getAtom(0);
982 Atom atom3 = angle.getAtom(2);
983
984
985
986 Bond bond1 = angle.getBond(0);
987 double distance1 = bond1.bondType.distance;
988
989 Bond bond2 = angle.getBond(1);
990 double distance2 = bond2.bondType.distance;
991
992
993 double angleVal = angle.angleType.angle[angle.nh];
994
995
996 double falseBondLength = sqrt(
997 distance1 * distance1 + distance2 * distance2 - 2.0 * distance1 * distance2 * cos(
998 toRadians(angleVal)));
999
1000 int iAtom1 = atom1.getXyzIndex() - 1;
1001 int iAtom3 = atom3.getXyzIndex() - 1;
1002 addConstraint(iAtom1, iAtom3, falseBondLength * OpenMM_NmPerAngstrom);
1003 }
1004 }
1005 }
1006
1007
1008
1009
1010
1011
1012
1013
1014 private boolean isHydrogenAngle(Angle angle) {
1015 if (angle.containsHydrogen()) {
1016
1017 double angleVal = angle.angleType.angle[angle.nh];
1018
1019
1020
1021 if (angleVal < 160.0) {
1022 Atom atom1 = angle.getAtom(0);
1023 Atom atom2 = angle.getAtom(1);
1024 Atom atom3 = angle.getAtom(2);
1025
1026
1027 return atom1.isHydrogen() && atom3.isHydrogen() && !atom2.isHydrogen();
1028 }
1029 }
1030 return false;
1031 }
1032
1033 }