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;
39
40 import edu.rit.pj.IntegerForLoop;
41 import edu.rit.pj.IntegerSchedule;
42 import edu.rit.pj.ParallelRegion;
43 import edu.rit.pj.ParallelTeam;
44 import edu.rit.pj.reduction.SharedDouble;
45 import ffx.crystal.Crystal;
46 import ffx.crystal.CrystalPotential;
47 import ffx.crystal.LatticeSystem;
48 import ffx.crystal.NCSCrystal;
49 import ffx.crystal.ReplicatesCrystal;
50 import ffx.crystal.SpaceGroup;
51 import ffx.crystal.SpaceGroupDefinitions;
52 import ffx.crystal.SymOp;
53 import ffx.numerics.Constraint;
54 import ffx.numerics.atomic.AtomicDoubleArray.AtomicDoubleArrayImpl;
55 import ffx.numerics.atomic.AtomicDoubleArray3D;
56 import ffx.numerics.math.Double3;
57 import ffx.numerics.switching.ConstantSwitch;
58 import ffx.numerics.switching.UnivariateFunctionFactory;
59 import ffx.numerics.switching.UnivariateSwitchingFunction;
60 import ffx.potential.bonded.Angle;
61 import ffx.potential.bonded.AngleTorsion;
62 import ffx.potential.bonded.Atom;
63 import ffx.potential.bonded.Bond;
64 import ffx.potential.bonded.BondedTerm;
65 import ffx.potential.bonded.ImproperTorsion;
66 import ffx.potential.bonded.LambdaInterface;
67 import ffx.potential.bonded.MSNode;
68 import ffx.potential.bonded.MultiResidue;
69 import ffx.potential.bonded.OutOfPlaneBend;
70 import ffx.potential.bonded.PiOrbitalTorsion;
71 import ffx.potential.bonded.RelativeSolvation;
72 import ffx.potential.bonded.RelativeSolvation.SolvationLibrary;
73 import ffx.potential.bonded.Residue;
74 import ffx.potential.bonded.RestrainDistance;
75 import ffx.potential.bonded.StretchBend;
76 import ffx.potential.bonded.StretchTorsion;
77 import ffx.potential.bonded.Torsion;
78 import ffx.potential.bonded.TorsionTorsion;
79 import ffx.potential.bonded.UreyBradley;
80 import ffx.potential.constraint.CcmaConstraint;
81 import ffx.potential.constraint.SettleConstraint;
82 import ffx.potential.extended.ExtendedSystem;
83 import ffx.potential.nonbonded.COMRestraint;
84 import ffx.potential.nonbonded.GeneralizedKirkwood;
85 import ffx.potential.nonbonded.NCSRestraint;
86 import ffx.potential.nonbonded.ParticleMeshEwald;
87 import ffx.potential.nonbonded.RestrainGroups;
88 import ffx.potential.bonded.RestrainPosition;
89 import ffx.potential.nonbonded.VanDerWaals;
90 import ffx.potential.nonbonded.VanDerWaalsTornado;
91 import ffx.potential.openmm.OpenMMEnergy;
92 import ffx.potential.parameters.AngleType;
93 import ffx.potential.parameters.AngleType.AngleMode;
94 import ffx.potential.parameters.BondType;
95 import ffx.potential.parameters.ForceField;
96 import ffx.potential.parameters.ForceField.ELEC_FORM;
97 import ffx.potential.parameters.OutOfPlaneBendType;
98 import ffx.potential.parameters.TorsionType;
99 import ffx.potential.utils.ConvexHullOps;
100 import ffx.potential.utils.EnergyException;
101 import ffx.potential.utils.PotentialsFunctions;
102 import ffx.potential.utils.PotentialsUtils;
103 import ffx.utilities.FFXProperty;
104 import org.apache.commons.configuration2.CompositeConfiguration;
105
106 import javax.annotation.Nullable;
107 import java.io.File;
108 import java.time.LocalDateTime;
109 import java.time.format.DateTimeFormatter;
110 import java.util.ArrayList;
111 import java.util.Arrays;
112 import java.util.Collections;
113 import java.util.HashSet;
114 import java.util.List;
115 import java.util.Set;
116 import java.util.logging.Level;
117 import java.util.logging.Logger;
118 import java.util.stream.Collectors;
119 import java.util.stream.Stream;
120
121 import static edu.uiowa.jopenmm.OpenMMAmoebaLibrary.OpenMM_NmPerAngstrom;
122 import static ffx.potential.bonded.BondedTerm.removeNeuralNetworkTerms;
123 import static ffx.potential.bonded.RestrainPosition.parseRestrainPositions;
124 import static ffx.potential.nonbonded.VanDerWaalsForm.DEFAULT_VDW_CUTOFF;
125 import static ffx.potential.nonbonded.pme.EwaldParameters.DEFAULT_EWALD_CUTOFF;
126 import static ffx.potential.parameters.ForceField.toEnumForm;
127 import static ffx.potential.parsers.XYZFileFilter.isXYZ;
128 import static ffx.utilities.PropertyGroup.NonBondedCutoff;
129 import static ffx.utilities.PropertyGroup.PotentialFunctionSelection;
130 import static java.lang.Double.isInfinite;
131 import static java.lang.Double.isNaN;
132 import static java.lang.String.format;
133 import static java.lang.System.arraycopy;
134 import static java.util.Arrays.sort;
135 import static org.apache.commons.io.FilenameUtils.removeExtension;
136 import static org.apache.commons.math3.util.FastMath.PI;
137 import static org.apache.commons.math3.util.FastMath.max;
138 import static org.apache.commons.math3.util.FastMath.min;
139 import static org.apache.commons.math3.util.FastMath.sqrt;
140
141
142
143
144
145
146
147 public class ForceFieldEnergy implements CrystalPotential, LambdaInterface {
148
149
150
151
152 public static final double DEFAULT_CONSTRAINT_TOLERANCE = 1E-4;
153
154
155
156 private static final Logger logger = Logger.getLogger(ForceFieldEnergy.class.getName());
157
158
159
160 private static final double toSeconds = 1.0e-9;
161
162
163
164 protected final MolecularAssembly molecularAssembly;
165
166
167
168
169 public final double maxDebugGradient;
170
171
172
173 private final ParallelTeam parallelTeam;
174
175
176
177 private final NCSRestraint ncsRestraint;
178
179
180
181 private final COMRestraint comRestraint;
182
183
184
185 private final VanDerWaals vanderWaals;
186
187
188
189 private final ANIEnergy aniEnergy;
190 private final List<Constraint> constraints;
191
192
193
194
195 public enum RestrainMode {
196
197
198
199 ENERGY,
200
201
202
203 ALCHEMICAL
204 }
205
206 @FFXProperty(name = "vdw-cutoff", propertyGroup = NonBondedCutoff, defaultValue = "12.0", description = """
207 Sets the cutoff distance value in Angstroms for van der Waals potential energy interactions.
208 The energy for any pair of van der Waals sites beyond the cutoff distance will be set to zero.
209 Other properties can be used to define the smoothing scheme near the cutoff distance.
210 The default cutoff distance in the absence of the vdw-cutoff keyword is infinite for nonperiodic
211 systems and 12.0 for periodic systems.
212 """)
213 private double vdwCutoff;
214
215 @FFXProperty(name = "ewald-cutoff", propertyGroup = NonBondedCutoff, defaultValue = "7.0", description = """
216 Sets the value in Angstroms of the real-space distance cutoff for use during Ewald summation.
217 By default, in the absence of the ewald-cutoff property, a value of 7.0 is used.
218 """)
219 private double ewaldCutoff;
220
221 @FFXProperty(name = "gk-cutoff", propertyGroup = NonBondedCutoff, defaultValue = "12.0", description = """
222 Sets the value in Angstroms of the generalized Kirkwood distance cutoff for use
223 during implicit solvent simulations. By default, in the absence of the gk-cutoff property,
224 no cutoff is used under aperiodic boundary conditions and the vdw-cutoff is used under PBC.
225 """)
226 private double gkCutoff;
227
228 private static final double DEFAULT_LIST_BUFFER = 2.0;
229
230 @FFXProperty(name = "list-buffer", propertyGroup = NonBondedCutoff, defaultValue = "2.0", description = """
231 Sets the size of the neighbor list buffer in Angstroms for potential energy functions.
232 This value is added to the actual cutoff distance to determine which pairs will be kept on the neighbor list.
233 This buffer value is used for all potential function neighbor lists.
234 The default value in the absence of the list-buffer keyword is 2.0 Angstroms.
235 """)
236 private double listBuffer;
237
238
239
240
241 private final double cutOff2;
242
243
244
245 private final double cutoffPlusBuffer;
246
247
248
249 private final ParticleMeshEwald particleMeshEwald;
250
251
252
253 private final ELEC_FORM elecForm;
254
255
256
257 private final boolean nnTermOrig;
258
259
260
261 private final boolean bondTermOrig;
262
263
264
265 private final boolean angleTermOrig;
266
267
268
269 private final boolean stretchBendTermOrig;
270
271
272
273 private final boolean ureyBradleyTermOrig;
274
275
276
277 private final boolean outOfPlaneBendTermOrig;
278
279
280
281 private final boolean torsionTermOrig;
282
283
284
285 private final boolean stretchTorsionTermOrig;
286
287
288
289 private final boolean angleTorsionTermOrig;
290
291
292
293 private final boolean improperTorsionTermOrig;
294
295
296
297 private final boolean piOrbitalTorsionTermOrig;
298
299
300
301 private final boolean torsionTorsionTermOrig;
302
303
304
305 private final boolean restrainPositionTermOrig;
306
307
308
309 private final boolean restrainGroupTermOrig;
310
311
312
313 private final boolean restrainDistanceTermOrig;
314
315
316
317 private final boolean restrainTorsionTermOrig;
318
319
320
321
322 private final boolean vanderWaalsTermOrig;
323
324
325
326 private final boolean multipoleTermOrig;
327
328
329
330 private final boolean polarizationTermOrig;
331
332
333
334 private final boolean generalizedKirkwoodTermOrig;
335
336 private boolean esvTermOrig;
337
338
339
340 private final boolean rigidHydrogens;
341
342
343
344 private final boolean lambdaTorsions;
345
346
347
348 private final RelativeSolvation relativeSolvation;
349 private final boolean relativeSolvationTerm;
350 private final Platform platform = Platform.FFX;
351
352
353
354
355 @FFXProperty(name = "lambdaterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
356 defaultValue = "false", description = "Specifies use of the Lambda state variable.")
357 protected boolean lambdaTerm;
358
359
360
361 private double lambda = 1.0;
362
363
364
365 protected double[] optimizationScaling = null;
366
367
368
369 public boolean lambdaBondedTerms = false;
370
371
372
373 boolean lambdaAllBondedTerms = false;
374
375
376
377
378 boolean destroyed = false;
379
380
381
382
383 private STATE state = STATE.BOTH;
384
385
386
387 private final Atom[] atoms;
388
389
390
391 private final Bond[] bonds;
392
393
394
395 private final Angle[] angles;
396
397
398
399 private final StretchBend[] stretchBends;
400
401
402
403 private final UreyBradley[] ureyBradleys;
404
405
406
407 private final OutOfPlaneBend[] outOfPlaneBends;
408
409
410
411 private final Torsion[] torsions;
412
413
414
415 private final ImproperTorsion[] improperTorsions;
416
417
418
419 private final PiOrbitalTorsion[] piOrbitalTorsions;
420
421
422
423 private final TorsionTorsion[] torsionTorsions;
424
425
426
427 private final StretchTorsion[] stretchTorsions;
428
429
430
431 private final AngleTorsion[] angleTorsions;
432
433
434
435
436 private RestrainDistance[] restrainDistances;
437
438
439
440 private Torsion[] restrainTorsions;
441
442
443
444 private final RestrainPosition[] restrainPositions;
445
446
447
448 private final RestrainGroups restrainGroups;
449
450
451
452 private final RestrainMode restrainMode;
453
454
455
456
457 private final int nAtoms;
458
459
460
461 private final int nBonds;
462
463
464
465 private final int nAngles;
466
467
468
469 private final int nStretchBends;
470
471
472
473 private final int nUreyBradleys;
474
475
476
477 private final int nOutOfPlaneBends;
478
479
480
481 private final int nTorsions;
482
483
484
485 private final int nImproperTorsions;
486
487
488
489 private final int nPiOrbitalTorsions;
490
491
492
493 private final int nTorsionTorsions;
494
495
496
497 private final int nAngleTorsions;
498
499
500
501 private final int nStretchTorsions;
502
503
504
505
506 private int nRestrainDistances;
507
508
509
510 private int nRestrainTorsions;
511
512
513
514 private int nRestrainPositions;
515
516
517
518 private int nRestrainGroups;
519
520
521
522
523 private int nVanDerWaalInteractions;
524
525
526
527 private int nPermanentInteractions;
528
529
530
531 private int nGKInteractions;
532
533
534
535
536 private Crystal crystal;
537
538
539
540 private final BondedRegion bondedRegion;
541
542
543
544
545 private boolean nnTerm;
546
547
548
549
550 @FFXProperty(name = "bondterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
551 defaultValue = "true", description = "Specifies use of the bond stretch potential.")
552 private boolean bondTerm;
553
554
555
556
557 @FFXProperty(name = "angleterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
558 defaultValue = "true", description = "Specifies use of the angle bend potential.")
559 private boolean angleTerm;
560
561
562
563
564 @FFXProperty(name = "strbndterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
565 defaultValue = "true", description = "Specifies use of the stretch-bend potential.")
566 private boolean stretchBendTerm;
567
568
569
570
571 @FFXProperty(name = "ureyterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
572 defaultValue = "true", description = "Specifies use of the Urey-Bradley potential.")
573 private boolean ureyBradleyTerm;
574
575
576
577
578 @FFXProperty(name = "opbendterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
579 defaultValue = "true", description = "Specifies use of the out-of-plane potential.")
580 private boolean outOfPlaneBendTerm;
581
582
583
584
585 @FFXProperty(name = "torsionterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
586 defaultValue = "true", description = "Specifies use of the torsional potential.")
587 private boolean torsionTerm;
588
589
590
591
592 @FFXProperty(name = "strtorterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
593 defaultValue = "true", description = "Specifies use of the stretch-torsion potential.")
594 private boolean stretchTorsionTerm;
595
596
597
598
599 @FFXProperty(name = "angtorterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
600 defaultValue = "true", description = "Specifies use of the angle-torsion potential.")
601 private boolean angleTorsionTerm;
602
603
604
605
606 @FFXProperty(name = "imptorterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
607 defaultValue = "true", description = "Specifies use of the improper torsion potential.")
608 private boolean improperTorsionTerm;
609
610
611
612
613 @FFXProperty(name = "pitorsterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
614 defaultValue = "true", description = "Specifies use of the pi-system torsion potential.")
615 private boolean piOrbitalTorsionTerm;
616
617
618
619
620 @FFXProperty(name = "tortorterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
621 defaultValue = "true", description = "Specifies use of the pi-system torsion potential.")
622 private boolean torsionTorsionTerm;
623
624
625
626
627 @FFXProperty(name = "vdwterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
628 defaultValue = "true", description = """
629 Specifies use of the vdw der Waals potential.
630 If set to false, all non-bonded terms are turned off.
631 """)
632 private boolean vanderWaalsTerm;
633
634
635
636
637 @FFXProperty(name = "mpoleterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
638 defaultValue = "true", description = """
639 Specifies use of the fixed charge electrostatic potential.
640 Setting mpoleterm to false also turns off polarization and generalized Kirkwood,
641 overriding the polarizeterm and gkterm properties.
642 """)
643 private boolean multipoleTerm;
644
645
646
647
648 @FFXProperty(name = "polarizeterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
649 defaultValue = "true", description = """
650 Specifies use of the polarizable electrostatic potential.
651 Setting polarizeterm to false overrides the polarization property.
652 """)
653 private boolean polarizationTerm;
654
655
656
657
658 @FFXProperty(name = "gkterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
659 defaultValue = "false", description = "Specifies use of generalized Kirkwood electrostatics.")
660 private boolean generalizedKirkwoodTerm;
661
662
663
664
665 private boolean comTerm;
666
667
668
669 private boolean comTermOrig;
670
671
672
673 private boolean ncsTerm;
674
675
676
677 private boolean ncsTermOrig;
678
679
680
681 private boolean restrainDistanceTerm;
682
683
684
685 private boolean restrainTorsionTerm;
686
687
688
689 private boolean restrainPositionTerm;
690
691
692
693 private boolean restrainGroupTerm;
694
695
696
697
698 private double rigidScale;
699
700
701
702
703 private double nnEnergy;
704
705
706
707 private double bondEnergy;
708
709
710
711 private double bondRMSD;
712
713
714
715 private double angleEnergy;
716
717
718
719 private double angleRMSD;
720
721
722
723 private double stretchBendEnergy;
724
725
726
727 private double ureyBradleyEnergy;
728
729
730
731 private double outOfPlaneBendEnergy;
732
733
734
735 private double torsionEnergy;
736
737
738
739 private double stretchTorsionEnergy;
740
741
742
743 private double angleTorsionEnergy;
744
745
746
747 private double improperTorsionEnergy;
748
749
750
751 private double piOrbitalTorsionEnergy;
752
753
754
755 private double torsionTorsionEnergy;
756
757
758
759
760 private double restrainDistanceEnergy;
761
762
763
764 private double restrainPositionEnergy;
765
766
767
768 private double restrainGroupEnergy;
769
770
771
772 private double restrainTorsionEnergy;
773
774
775
776
777 private double totalBondedEnergy;
778
779
780
781 private double vanDerWaalsEnergy;
782
783
784
785 private double permanentMultipoleEnergy;
786
787
788
789 private double permanentRealSpaceEnergy;
790
791
792
793 private double polarizationEnergy;
794
795
796
797 private double totalMultipoleEnergy;
798
799
800
801 private double totalNonBondedEnergy;
802
803
804
805 private double solvationEnergy;
806
807
808
809 private double ncsEnergy;
810
811
812
813
814 private double comRestraintEnergy;
815
816
817
818 private double totalEnergy;
819
820
821
822
823 private long nnTime;
824
825
826
827 private long bondTime;
828
829
830
831 private long angleTime;
832
833
834
835 private long stretchBendTime;
836
837
838
839 private long ureyBradleyTime;
840
841
842
843 private long outOfPlaneBendTime;
844
845
846
847 private long torsionTime;
848
849
850
851 private long angleTorsionTime;
852
853
854
855 private long stretchTorsionTime;
856
857
858
859 private long piOrbitalTorsionTime;
860
861
862
863 private long improperTorsionTime;
864
865
866
867 private long torsionTorsionTime;
868
869
870
871 private long vanDerWaalsTime;
872
873
874
875 private long electrostaticTime;
876
877
878
879 private long restrainDistanceTime;
880
881
882
883 private long restrainTorsionTime;
884
885
886
887
888 private long comRestraintTime;
889
890
891
892 private long restrainGroupTime;
893
894
895
896 private long totalTime;
897
898
899
900
901 private ExtendedSystem esvSystem = null;
902
903 private boolean esvTerm;
904 private double esvBias;
905
906
907
908 private long ncsTime;
909 private int nRelativeSolvations;
910
911
912
913 private long restrainPositionTime;
914
915 private double relativeSolvationEnergy;
916
917
918
919 private boolean printOnFailure;
920
921
922
923
924
925
926 protected ForceFieldEnergy(MolecularAssembly molecularAssembly) {
927 this(molecularAssembly, ParallelTeam.getDefaultThreadCount());
928 }
929
930
931
932
933
934
935
936 protected ForceFieldEnergy(MolecularAssembly molecularAssembly, int numThreads) {
937
938 this.molecularAssembly = molecularAssembly;
939 atoms = molecularAssembly.getAtomArray();
940 nAtoms = atoms.length;
941
942
943 for (int i = 0; i < nAtoms; i++) {
944 int index = atoms[i].getXyzIndex() - 1;
945 assert (i == index);
946 }
947
948
949 int nThreads = min(nAtoms, numThreads);
950 parallelTeam = new ParallelTeam(nThreads);
951
952 ForceField forceField = molecularAssembly.getForceField();
953 CompositeConfiguration properties = forceField.getProperties();
954 String name = forceField.toString().toUpperCase();
955
956 logger.info(format(" Constructing Force Field %s", name));
957 logger.info(format("\n SMP threads: %10d", nThreads));
958
959
960 boolean standardizeAtomNames = properties.getBoolean("standardizeAtomNames", true);
961 if (standardizeAtomNames) {
962 molecularAssembly.renameWaterProtons();
963 }
964
965 nnTerm = forceField.getBoolean("NNTERM", false);
966
967 if (nnTerm) {
968 for (Atom atom : atoms) {
969 atom.setNeuralNetwork(true);
970 }
971 }
972 bondTerm = forceField.getBoolean("BONDTERM", true);
973 angleTerm = forceField.getBoolean("ANGLETERM", true);
974 stretchBendTerm = forceField.getBoolean("STRBNDTERM", true);
975 ureyBradleyTerm = forceField.getBoolean("UREYTERM", true);
976 outOfPlaneBendTerm = forceField.getBoolean("OPBENDTERM", true);
977 torsionTerm = forceField.getBoolean("TORSIONTERM", true);
978 stretchTorsionTerm = forceField.getBoolean("STRTORTERM", true);
979 angleTorsionTerm = forceField.getBoolean("ANGTORTERM", true);
980 piOrbitalTorsionTerm = forceField.getBoolean("PITORSTERM", true);
981 torsionTorsionTerm = forceField.getBoolean("TORTORTERM", true);
982 improperTorsionTerm = forceField.getBoolean("IMPROPERTERM", true);
983 vanderWaalsTerm = forceField.getBoolean("VDWTERM", true);
984
985 boolean tornadoVM = forceField.getBoolean("tornado", false);
986 if (vanderWaalsTerm && !tornadoVM) {
987 multipoleTerm = forceField.getBoolean("MPOLETERM", true);
988 if (multipoleTerm) {
989 String polarizeString = forceField.getString("POLARIZATION", "NONE");
990 boolean defaultPolarizeTerm = !polarizeString.equalsIgnoreCase("NONE");
991 polarizationTerm = forceField.getBoolean("POLARIZETERM", defaultPolarizeTerm);
992 generalizedKirkwoodTerm = forceField.getBoolean("GKTERM", false);
993 } else {
994
995 polarizationTerm = false;
996 generalizedKirkwoodTerm = false;
997 }
998 } else {
999
1000 multipoleTerm = false;
1001 polarizationTerm = false;
1002 generalizedKirkwoodTerm = false;
1003 }
1004
1005
1006 lambdaTerm = forceField.getBoolean("LAMBDATERM", false);
1007 comTerm = forceField.getBoolean("COMRESTRAINTERM", false);
1008 lambdaTorsions = forceField.getBoolean("TORSION_LAMBDATERM", false);
1009 printOnFailure = forceField.getBoolean("PRINT_ON_FAILURE", false);
1010
1011
1012 if (properties.containsKey("restrain-distance")) {
1013 restrainDistanceTerm = true;
1014 } else {
1015 restrainDistanceTerm = false;
1016 }
1017
1018
1019 if (properties.containsKey("restrain-torsion")) {
1020 restrainTorsionTerm = true;
1021 } else {
1022 restrainTorsionTerm = false;
1023 }
1024
1025 String mode = forceField.getString("RESTRAIN_MODE", "ENERGY");
1026 if (mode.equalsIgnoreCase("ALCHEMICAL")) {
1027 restrainMode = RestrainMode.ALCHEMICAL;
1028 } else {
1029 restrainMode = RestrainMode.ENERGY;
1030 }
1031 if (restrainTorsionTerm) {
1032 logger.info(" Restrain Torsion Mode: " + restrainMode);
1033 }
1034
1035
1036 if (properties.containsKey("restrain-groups")) {
1037 restrainGroupTerm = true;
1038 } else {
1039 restrainGroupTerm = false;
1040 }
1041
1042
1043 if (properties.containsKey("restrain-position") || properties.containsKey("restrain-position-lambda")) {
1044 restrainPositionTerm = true;
1045 } else {
1046 restrainPositionTerm = false;
1047 }
1048
1049
1050
1051 nnTermOrig = nnTerm;
1052 bondTermOrig = bondTerm;
1053 angleTermOrig = angleTerm;
1054 stretchBendTermOrig = stretchBendTerm;
1055 ureyBradleyTermOrig = ureyBradleyTerm;
1056 outOfPlaneBendTermOrig = outOfPlaneBendTerm;
1057 torsionTermOrig = torsionTerm;
1058 angleTorsionTermOrig = angleTorsionTerm;
1059 stretchTorsionTermOrig = stretchTorsionTerm;
1060 improperTorsionTermOrig = improperTorsionTerm;
1061 piOrbitalTorsionTermOrig = piOrbitalTorsionTerm;
1062 torsionTorsionTermOrig = torsionTorsionTerm;
1063 vanderWaalsTermOrig = vanderWaalsTerm;
1064 multipoleTermOrig = multipoleTerm;
1065 polarizationTermOrig = polarizationTerm;
1066 generalizedKirkwoodTermOrig = generalizedKirkwoodTerm;
1067 ncsTermOrig = ncsTerm;
1068 comTermOrig = comTerm;
1069 restrainDistanceTermOrig = restrainDistanceTerm;
1070 restrainTorsionTermOrig = restrainTorsionTerm;
1071 restrainPositionTermOrig = restrainPositionTerm;
1072 restrainGroupTermOrig = restrainGroupTerm;
1073
1074
1075 String spacegroup;
1076 double a, b, c, alpha, beta, gamma;
1077 boolean aperiodic;
1078 try {
1079 spacegroup = forceField.getString("SPACEGROUP", "P 1");
1080 SpaceGroup sg = SpaceGroupDefinitions.spaceGroupFactory(spacegroup);
1081 LatticeSystem latticeSystem = sg.latticeSystem;
1082 a = forceField.getDouble("A_AXIS");
1083 aperiodic = false;
1084 b = forceField.getDouble("B_AXIS", latticeSystem.getDefaultBAxis(a));
1085 c = forceField.getDouble("C_AXIS", latticeSystem.getDefaultCAxis(a, b));
1086 alpha = forceField.getDouble("ALPHA", latticeSystem.getDefaultAlpha());
1087 beta = forceField.getDouble("BETA", latticeSystem.getDefaultBeta());
1088 gamma = forceField.getDouble("GAMMA", latticeSystem.getDefaultGamma());
1089 if (!sg.latticeSystem.validParameters(a, b, c, alpha, beta, gamma)) {
1090 logger.severe(" Check lattice parameters.");
1091 }
1092 if (a == 1.0 && b == 1.0 && c == 1.0) {
1093 String message = " A-, B-, and C-axis values equal to 1.0.";
1094 logger.info(message);
1095 throw new Exception(message);
1096 }
1097 if (a <= 0.0 || b <= 0.0 || c <= 0.0 || alpha <= 0.0 || beta <= 0.0 || gamma <= 0.0) {
1098
1099 String message = " Crystal parameters are not valid due to negative or zero value.";
1100 logger.warning(message);
1101 throw new Exception(message);
1102 }
1103 } catch (Exception e) {
1104 aperiodic = true;
1105
1106
1107 double maxR = 0.0;
1108 if (nAtoms < 10) {
1109 for (int i = 0; i < nAtoms - 1; i++) {
1110 Double3 xi = atoms[i].getXYZ();
1111 for (int j = 1; j < nAtoms; j++) {
1112 double r = atoms[j].getXYZ().dist(xi);
1113 maxR = max(r, maxR);
1114 }
1115 }
1116 } else {
1117 try {
1118 maxR = ConvexHullOps.maxDist(ConvexHullOps.constructHull(atoms));
1119 } catch (Exception ex) {
1120
1121 logger.info(" Convex Hull operation failed with message " + ex + "\n Trying brute force approach...");
1122 if (logger.isLoggable(Level.FINE)) {
1123 logger.fine(Utilities.stackTraceToString(ex));
1124 }
1125 for (int i = 0; i < nAtoms - 1; i++) {
1126 Double3 xi = atoms[i].getXYZ();
1127 for (int j = 1; j < nAtoms; j++) {
1128 double r = atoms[j].getXYZ().dist(xi);
1129 maxR = max(r, maxR);
1130 }
1131 }
1132 }
1133 }
1134 maxR = max(10.0, maxR);
1135
1136 logger.info(format(" The system will be treated as aperiodic (max separation = %6.1f A).", maxR));
1137
1138
1139 forceField.addProperty("EWALD_ALPHA", "0.0");
1140
1141
1142 spacegroup = "P1";
1143 a = 2.0 * maxR;
1144 b = 2.0 * maxR;
1145 c = 2.0 * maxR;
1146 alpha = 90.0;
1147 beta = 90.0;
1148 gamma = 90.0;
1149 }
1150 Crystal unitCell = new Crystal(a, b, c, alpha, beta, gamma, spacegroup);
1151 unitCell.setAperiodic(aperiodic);
1152
1153
1154 vdwCutoff = DEFAULT_VDW_CUTOFF;
1155 ewaldCutoff = DEFAULT_EWALD_CUTOFF;
1156 gkCutoff = vdwCutoff;
1157 if (unitCell.aperiodic()) {
1158
1159 vdwCutoff = Double.POSITIVE_INFINITY;
1160 ewaldCutoff = Double.POSITIVE_INFINITY;
1161 gkCutoff = Double.POSITIVE_INFINITY;
1162 }
1163
1164 vdwCutoff = forceField.getDouble("VDW_CUTOFF", vdwCutoff);
1165 ewaldCutoff = forceField.getDouble("EWALD_CUTOFF", ewaldCutoff);
1166 gkCutoff = forceField.getDouble("GK_CUTOFF", gkCutoff);
1167
1168
1169 double nlistCutoff = vdwCutoff;
1170 if (multipoleTerm) {
1171 nlistCutoff = max(vdwCutoff, ewaldCutoff);
1172 }
1173 if (generalizedKirkwoodTerm) {
1174 nlistCutoff = max(nlistCutoff, gkCutoff);
1175 }
1176
1177
1178 boolean disabledNeighborUpdates = forceField.getBoolean("DISABLE_NEIGHBOR_UPDATES", false);
1179 if (disabledNeighborUpdates) {
1180 logger.info(format(" Neighbor list updates disabled; interactions will "
1181 + "only be calculated between atoms that started the simulation "
1182 + "within a radius of %9.3g Angstroms of each other.", nlistCutoff));
1183
1184 vdwCutoff = Double.POSITIVE_INFINITY;
1185 ewaldCutoff = Double.POSITIVE_INFINITY;
1186 gkCutoff = Double.POSITIVE_INFINITY;
1187 }
1188
1189 listBuffer = forceField.getDouble("LIST_BUFFER", DEFAULT_LIST_BUFFER);
1190 cutoffPlusBuffer = nlistCutoff + listBuffer;
1191 cutOff2 = 2.0 * cutoffPlusBuffer;
1192 unitCell = configureNCS(forceField, unitCell);
1193
1194
1195 if (!aperiodic) {
1196 this.crystal = ReplicatesCrystal.replicatesCrystalFactory(unitCell, cutOff2);
1197 logger.info(format("\n Density: %6.3f (g/cc)",
1198 crystal.getDensity(molecularAssembly.getMass())));
1199 logger.info(crystal.toString());
1200 } else {
1201 this.crystal = unitCell;
1202 }
1203
1204 if (!unitCell.aperiodic() && unitCell.spaceGroup.number == 1) {
1205 ncsTerm = forceField.getBoolean("NCSTERM", false);
1206 ncsTermOrig = ncsTerm;
1207 } else {
1208 ncsTerm = false;
1209 ncsTermOrig = false;
1210 }
1211
1212
1213 int nSpecial = checkForSpecialPositions(forceField);
1214
1215 rigidHydrogens = forceField.getBoolean("RIGID_HYDROGENS", false);
1216 rigidScale = forceField.getDouble("RIGID_SCALE", 10.0);
1217
1218 nRelativeSolvations = 0;
1219 String relSolvLibrary = forceField.getString("RELATIVE_SOLVATION", "NONE").toUpperCase();
1220 SolvationLibrary library = SolvationLibrary.valueOf(relSolvLibrary);
1221 if (library == SolvationLibrary.AUTO) {
1222 if (generalizedKirkwoodTerm && name.toUpperCase().contains("OPLS")) {
1223 library = SolvationLibrary.MACCALLUM_TIP4P;
1224
1225 } else if (generalizedKirkwoodTerm) {
1226 library = SolvationLibrary.GK;
1227 } else {
1228 library = SolvationLibrary.NONE;
1229 }
1230 }
1231 if (library != SolvationLibrary.NONE) {
1232 relativeSolvationTerm = true;
1233 relativeSolvation = new RelativeSolvation(library, forceField);
1234 } else {
1235 relativeSolvationTerm = false;
1236 relativeSolvation = null;
1237 }
1238
1239 boolean checkAllNodeCharges = forceField.getBoolean("CHECK_ALL_NODE_CHARGES", false);
1240
1241 if (rigidScale <= 1.0) {
1242 rigidScale = 1.0;
1243 }
1244
1245 logger.info("\n Bonded Terms");
1246 if (rigidHydrogens && rigidScale > 1.0) {
1247 logger.info(format(" Rigid hydrogens: %10.2f", rigidScale));
1248 }
1249
1250
1251 if (bondTerm) {
1252 List<Bond> bondList = molecularAssembly.getBondList();
1253 if (nnTerm) {
1254 removeNeuralNetworkTerms(bondList);
1255 }
1256 nBonds = bondList.size();
1257 bonds = bondList.toArray(new Bond[0]);
1258 sort(bonds);
1259 if (nBonds > 0) {
1260 logger.info(format(" Bonds: %10d", nBonds));
1261 }
1262 } else {
1263 nBonds = 0;
1264 bonds = null;
1265 }
1266
1267
1268 if (angleTerm) {
1269 List<Angle> angleList = molecularAssembly.getAngleList();
1270 if (nnTerm) {
1271 removeNeuralNetworkTerms(angleList);
1272 }
1273 nAngles = angleList.size();
1274 angles = angleList.toArray(new Angle[0]);
1275 sort(angles);
1276 if (nAngles > 0) {
1277 logger.info(format(" Angles: %10d", nAngles));
1278 }
1279 } else {
1280 nAngles = 0;
1281 angles = null;
1282 }
1283
1284
1285 if (stretchBendTerm) {
1286 List<StretchBend> stretchBendList = molecularAssembly.getStretchBendList();
1287 if (nnTerm) {
1288 removeNeuralNetworkTerms(stretchBendList);
1289 }
1290 nStretchBends = stretchBendList.size();
1291 stretchBends = stretchBendList.toArray(new StretchBend[0]);
1292 sort(stretchBends);
1293 if (nStretchBends > 0) {
1294 logger.info(format(" Stretch-Bends: %10d", nStretchBends));
1295 }
1296 } else {
1297 nStretchBends = 0;
1298 stretchBends = null;
1299 }
1300
1301
1302 if (ureyBradleyTerm) {
1303 List<UreyBradley> ureyBradleyList = molecularAssembly.getUreyBradleyList();
1304 if (nnTerm) {
1305 removeNeuralNetworkTerms(ureyBradleyList);
1306 }
1307 nUreyBradleys = ureyBradleyList.size();
1308 ureyBradleys = ureyBradleyList.toArray(new UreyBradley[0]);
1309 sort(ureyBradleys);
1310 if (nUreyBradleys > 0) {
1311 logger.info(format(" Urey-Bradleys: %10d", nUreyBradleys));
1312 }
1313 } else {
1314 nUreyBradleys = 0;
1315 ureyBradleys = null;
1316 }
1317
1318
1319 if (rigidHydrogens) {
1320 if (bonds != null) {
1321 for (Bond bond : bonds) {
1322 if (bond.containsHydrogen()) {
1323 bond.setRigidScale(rigidScale);
1324 }
1325 }
1326 }
1327 if (angles != null) {
1328 for (Angle angle : angles) {
1329 if (angle.containsHydrogen()) {
1330 angle.setRigidScale(rigidScale);
1331 }
1332 }
1333 }
1334 if (stretchBends != null) {
1335 for (StretchBend stretchBend : stretchBends) {
1336 if (stretchBend.containsHydrogen()) {
1337 stretchBend.setRigidScale(rigidScale);
1338 }
1339 }
1340 }
1341 if (ureyBradleys != null) {
1342 for (UreyBradley ureyBradley : ureyBradleys) {
1343 if (ureyBradley.containsHydrogen()) {
1344 ureyBradley.setRigidScale(rigidScale);
1345 }
1346 }
1347 }
1348 }
1349
1350
1351 if (outOfPlaneBendTerm) {
1352 List<OutOfPlaneBend> outOfPlaneBendList = molecularAssembly.getOutOfPlaneBendList();
1353 if (nnTerm) {
1354 removeNeuralNetworkTerms(outOfPlaneBendList);
1355 }
1356 nOutOfPlaneBends = outOfPlaneBendList.size();
1357 outOfPlaneBends = outOfPlaneBendList.toArray(new OutOfPlaneBend[0]);
1358 sort(outOfPlaneBends);
1359 if (nOutOfPlaneBends > 0) {
1360 logger.info(format(" Out-of-Plane Bends: %10d", nOutOfPlaneBends));
1361 }
1362 } else {
1363 nOutOfPlaneBends = 0;
1364 outOfPlaneBends = null;
1365 }
1366
1367
1368 if (torsionTerm) {
1369 List<Torsion> torsionList = molecularAssembly.getTorsionList();
1370 if (nnTerm) {
1371 removeNeuralNetworkTerms(torsionList);
1372 }
1373 nTorsions = torsionList.size();
1374 torsions = torsionList.toArray(new Torsion[0]);
1375 if (nTorsions > 0) {
1376 logger.info(format(" Torsions: %10d", nTorsions));
1377 }
1378 } else {
1379 nTorsions = 0;
1380 torsions = null;
1381 }
1382
1383
1384 if (stretchTorsionTerm) {
1385 List<StretchTorsion> stretchTorsionList = molecularAssembly.getStretchTorsionList();
1386 if (nnTerm) {
1387 removeNeuralNetworkTerms(stretchTorsionList);
1388 }
1389 nStretchTorsions = stretchTorsionList.size();
1390 stretchTorsions = stretchTorsionList.toArray(new StretchTorsion[0]);
1391 if (nStretchTorsions > 0) {
1392 logger.info(format(" Stretch-Torsions: %10d", nStretchTorsions));
1393 }
1394 } else {
1395 nStretchTorsions = 0;
1396 stretchTorsions = null;
1397 }
1398
1399
1400 if (angleTorsionTerm) {
1401 List<AngleTorsion> angleTorsionList = molecularAssembly.getAngleTorsionList();
1402 if (nnTerm) {
1403 removeNeuralNetworkTerms(angleTorsionList);
1404 }
1405 nAngleTorsions = angleTorsionList.size();
1406 angleTorsions = angleTorsionList.toArray(new AngleTorsion[0]);
1407 if (nAngleTorsions > 0) {
1408 logger.info(format(" Angle-Torsions: %10d", nAngleTorsions));
1409 }
1410 } else {
1411 nAngleTorsions = 0;
1412 angleTorsions = null;
1413 }
1414
1415
1416 if (piOrbitalTorsionTerm) {
1417 List<PiOrbitalTorsion> piOrbitalTorsionList = molecularAssembly.getPiOrbitalTorsionList();
1418 if (nnTerm) {
1419 removeNeuralNetworkTerms(piOrbitalTorsionList);
1420 }
1421 nPiOrbitalTorsions = piOrbitalTorsionList.size();
1422 piOrbitalTorsions = piOrbitalTorsionList.toArray(new PiOrbitalTorsion[0]);
1423 if (nPiOrbitalTorsions > 0) {
1424 logger.info(format(" Pi-Orbital Torsions: %10d", nPiOrbitalTorsions));
1425 }
1426 } else {
1427 nPiOrbitalTorsions = 0;
1428 piOrbitalTorsions = null;
1429 }
1430
1431
1432 if (torsionTorsionTerm) {
1433 List<TorsionTorsion> torsionTorsionList = molecularAssembly.getTorsionTorsionList();
1434 if (nnTerm) {
1435 removeNeuralNetworkTerms(torsionTorsionList);
1436 }
1437 nTorsionTorsions = torsionTorsionList.size();
1438 torsionTorsions = torsionTorsionList.toArray(new TorsionTorsion[0]);
1439 if (nTorsionTorsions > 0) {
1440 logger.info(format(" Torsion-Torsions: %10d", nTorsionTorsions));
1441 }
1442 } else {
1443 nTorsionTorsions = 0;
1444 torsionTorsions = null;
1445 }
1446
1447
1448 if (improperTorsionTerm) {
1449 List<ImproperTorsion> improperTorsionList = molecularAssembly.getImproperTorsionList();
1450 if (nnTerm) {
1451 removeNeuralNetworkTerms(improperTorsionList);
1452 }
1453 nImproperTorsions = improperTorsionList.size();
1454 improperTorsions = improperTorsionList.toArray(new ImproperTorsion[0]);
1455 if (nImproperTorsions > 0) {
1456 logger.info(format(" Improper Torsions: %10d", nImproperTorsions));
1457 }
1458 } else {
1459 nImproperTorsions = 0;
1460 improperTorsions = null;
1461 }
1462
1463 int[] molecule = molecularAssembly.getMoleculeNumbers();
1464 if (vanderWaalsTerm) {
1465 logger.info("\n Non-Bonded Terms");
1466 boolean[] nn = null;
1467 if (nnTerm) {
1468 nn = molecularAssembly.getNeuralNetworkIdentity();
1469 } else {
1470 nn = new boolean[nAtoms];
1471 Arrays.fill(nn, false);
1472 }
1473
1474 if (!tornadoVM) {
1475 vanderWaals = new VanDerWaals(atoms, molecule, nn, crystal, forceField, parallelTeam,
1476 vdwCutoff, nlistCutoff);
1477 } else {
1478 vanderWaals = new VanDerWaalsTornado(atoms, crystal, forceField, vdwCutoff);
1479 }
1480 } else {
1481 vanderWaals = null;
1482 }
1483
1484 if (nnTerm) {
1485 aniEnergy = new ANIEnergy(molecularAssembly);
1486 } else {
1487 aniEnergy = null;
1488 }
1489
1490 if (multipoleTerm) {
1491 if (name.contains("OPLS") || name.contains("AMBER") || name.contains("CHARMM")) {
1492 elecForm = ELEC_FORM.FIXED_CHARGE;
1493 } else {
1494 elecForm = ELEC_FORM.PAM;
1495 }
1496 particleMeshEwald = new ParticleMeshEwald(atoms, molecule, forceField, crystal,
1497 vanderWaals.getNeighborList(), elecForm, ewaldCutoff, gkCutoff, parallelTeam);
1498 double charge = molecularAssembly.getCharge(checkAllNodeCharges);
1499 logger.info(format("\n Overall system charge: %10.3f", charge));
1500 } else {
1501 elecForm = null;
1502 particleMeshEwald = null;
1503 }
1504
1505 if (ncsTerm) {
1506 String sg = forceField.getString("NCSGROUP", "P 1");
1507 Crystal ncsCrystal = new Crystal(a, b, c, alpha, beta, gamma, sg);
1508 ncsRestraint = new NCSRestraint(atoms, forceField, ncsCrystal);
1509 } else {
1510 ncsRestraint = null;
1511 }
1512
1513 if (restrainPositionTerm) {
1514 restrainPositions = parseRestrainPositions(molecularAssembly);
1515 if (restrainPositions != null) {
1516 nRestrainPositions = restrainPositions.length;
1517 } else {
1518 nRestrainPositions = 0;
1519 }
1520 } else {
1521 restrainPositions = null;
1522 }
1523
1524 if (restrainGroupTerm) {
1525 restrainGroups = new RestrainGroups(molecularAssembly);
1526 nRestrainGroups = restrainGroups.getNumberOfRestraints();
1527 } else {
1528 restrainGroups = null;
1529 }
1530
1531 if (comTerm) {
1532 comRestraint = new COMRestraint(molecularAssembly);
1533 } else {
1534 comRestraint = null;
1535 }
1536
1537 if (restrainDistanceTerm) {
1538
1539 configureRestrainDistances(properties);
1540 }
1541
1542 if (restrainTorsionTerm) {
1543 nRestrainTorsions = configureRestrainTorsions(properties, forceField);
1544 }
1545
1546 bondedRegion = new BondedRegion();
1547 maxDebugGradient = forceField.getDouble("MAX_DEBUG_GRADIENT", Double.POSITIVE_INFINITY);
1548
1549 molecularAssembly.setPotential(this);
1550
1551
1552 constraints = configureConstraints(forceField);
1553
1554 if (lambdaTerm) {
1555 this.setLambda(1.0);
1556 if (nSpecial == 0) {
1557
1558
1559 crystal.setSpecialPositionCutoff(0.0);
1560 } else {
1561
1562 logger.info(" Special positions checking will be performed during a lambda simulation.");
1563 }
1564 }
1565 }
1566
1567 private int checkForSpecialPositions(ForceField forceField) {
1568
1569 boolean specialPositionsInactive = forceField.getBoolean("SPECIAL_POSITIONS_INACTIVE", true);
1570 int nSpecial = 0;
1571 if (specialPositionsInactive) {
1572 int nSymm = crystal.getNumSymOps();
1573 if (nSymm > 1) {
1574 SpaceGroup spaceGroup = crystal.spaceGroup;
1575 double sp2 = crystal.getSpecialPositionCutoff2();
1576 double[] mate = new double[3];
1577 StringBuilder sb = new StringBuilder("\n Atoms at Special Positions set to Inactive:\n");
1578 for (int i = 0; i < nAtoms; i++) {
1579 Atom atom = atoms[i];
1580 double[] xyz = atom.getXYZ(null);
1581 for (int iSymm = 1; iSymm < nSymm; iSymm++) {
1582 SymOp symOp = spaceGroup.getSymOp(iSymm);
1583 crystal.applySymOp(xyz, mate, symOp);
1584 double dr2 = crystal.image(xyz, mate);
1585 if (dr2 < sp2) {
1586 sb.append(
1587 format(" %s separation with SymOp %d at %8.6f A.\n", atoms[i], iSymm, sqrt(dr2)));
1588 atom.setActive(false);
1589 nSpecial++;
1590 break;
1591 }
1592 }
1593 }
1594 if (nSpecial > 0) {
1595 logger.info(sb.toString());
1596 }
1597 }
1598 }
1599 return nSpecial;
1600 }
1601
1602
1603
1604
1605
1606
1607
1608
1609 private int configureRestrainTorsions(CompositeConfiguration properties, ForceField forceField) {
1610 StringBuilder restrainLog = new StringBuilder("\n Restrain-Torsions");
1611
1612 String[] restrainTorsions = properties.getStringArray("restrain-torsion");
1613 double torsionUnits = forceField.getDouble("TORSIONUNIT", TorsionType.DEFAULT_TORSION_UNIT);
1614 List<Torsion> restrainTorsionList = new ArrayList<>(restrainTorsions.length);
1615 for (String restrainString : restrainTorsions) {
1616
1617 restrainString = "restrain-torsion " + restrainString;
1618
1619 String input = restrainString.split("#+")[0];
1620
1621 String[] tokens = input.trim().split(" +");
1622
1623
1624 TorsionType torsionType = TorsionType.parse(input, tokens);
1625 torsionType.torsionUnit = torsionUnits;
1626
1627
1628 int[] atomIndices = torsionType.atomClasses;
1629 int ai1 = atomIndices[0] - 1;
1630 int ai2 = atomIndices[1] - 1;
1631 int ai3 = atomIndices[2] - 1;
1632 int ai4 = atomIndices[3] - 1;
1633 Atom a1 = atoms[ai1];
1634 Atom a2 = atoms[ai2];
1635 Atom a3 = atoms[ai3];
1636 Atom a4 = atoms[ai4];
1637
1638
1639 Bond firstBond = a1.getBond(a2);
1640 Bond middleBond = a2.getBond(a3);
1641 Bond lastBond = a3.getBond(a4);
1642 Torsion torsion = new Torsion(firstBond, middleBond, lastBond);
1643 torsion.setTorsionType(torsionType);
1644 restrainTorsionList.add(torsion);
1645 restrainLog.append("\n ").append(torsion);
1646 }
1647
1648 if (!restrainTorsionList.isEmpty()) {
1649 nRestrainTorsions = restrainTorsionList.size();
1650 logger.info(restrainLog.toString());
1651 logger.info(format(" Added %4d torsion restraints.", nRestrainTorsions));
1652 restrainTorsionTerm = true;
1653 this.restrainTorsions = restrainTorsionList.toArray(new Torsion[0]);
1654 restrainTorsionEnergy = 0;
1655 restrainTorsionTime = 0;
1656 return restrainTorsionList.size();
1657 }
1658
1659 return 0;
1660 }
1661
1662
1663
1664
1665
1666
1667 private void configureRestrainDistances(CompositeConfiguration properties) {
1668
1669 String[] bondRestraints = properties.getStringArray("restrain-distance");
1670 for (String bondRest : bondRestraints) {
1671 try {
1672 String[] toks = bondRest.split("\\s+");
1673 if (toks.length < 2) {
1674 throw new IllegalArgumentException(
1675 format(" restrain-distance value %s could not be parsed!", bondRest));
1676 }
1677
1678
1679 int at1 = Integer.parseInt(toks[0]) - 1;
1680 int at2 = Integer.parseInt(toks[1]) - 1;
1681
1682 double forceConst = 100.0;
1683 double flatBottomRadius = 0;
1684 Atom a1 = atoms[at1];
1685 Atom a2 = atoms[at2];
1686
1687 if (toks.length > 2) {
1688 forceConst = Double.parseDouble(toks[2]);
1689 }
1690 double dist;
1691 switch (toks.length) {
1692 case 2:
1693 case 3:
1694 double[] xyz1 = new double[3];
1695 xyz1 = a1.getXYZ(xyz1);
1696 double[] xyz2 = new double[3];
1697 xyz2 = a2.getXYZ(xyz2);
1698
1699 dist = crystal.minDistOverSymOps(xyz1, xyz2);
1700 break;
1701 case 4:
1702 dist = Double.parseDouble(toks[3]);
1703 break;
1704 case 5:
1705 default:
1706 double minDist = Double.parseDouble(toks[3]);
1707 double maxDist = Double.parseDouble(toks[4]);
1708 dist = 0.5 * (minDist + maxDist);
1709 flatBottomRadius = 0.5 * Math.abs(maxDist - minDist);
1710 break;
1711 }
1712
1713 UnivariateSwitchingFunction switchF;
1714 double lamStart = RestrainDistance.DEFAULT_RB_LAM_START;
1715 double lamEnd = RestrainDistance.DEFAULT_RB_LAM_END;
1716 if (toks.length > 5) {
1717 int offset = 5;
1718 if (toks[5].matches("^[01](?:\\.[0-9]*)?")) {
1719 offset = 6;
1720 lamStart = Double.parseDouble(toks[5]);
1721 if (toks[6].matches("^[01](?:\\.[0-9]*)?")) {
1722 offset = 7;
1723 lamEnd = Double.parseDouble(toks[6]);
1724 }
1725 }
1726 switchF = UnivariateFunctionFactory.parseUSF(toks, offset);
1727 } else {
1728 switchF = new ConstantSwitch();
1729 }
1730
1731 setRestrainDistance(a1, a2, dist, forceConst, flatBottomRadius, lamStart, lamEnd, switchF);
1732 } catch (Exception ex) {
1733 logger.info(format(" Exception in parsing restrain-distance: %s", ex));
1734 }
1735 }
1736 }
1737
1738
1739
1740
1741
1742
1743
1744 private List<Constraint> configureConstraints(ForceField forceField) {
1745 String constraintStrings = forceField.getString("CONSTRAIN", forceField.getString("RATTLE", null));
1746 if (constraintStrings == null) {
1747 return Collections.emptyList();
1748 }
1749
1750 ArrayList<Constraint> constraints = new ArrayList<>();
1751 logger.info(format(" Experimental: parsing constraints option %s", constraintStrings));
1752
1753 Set<Bond> numericBonds = new HashSet<>(1);
1754 Set<Angle> numericAngles = new HashSet<>(1);
1755
1756
1757 if (constraintStrings.isEmpty() || constraintStrings.matches("^\\s*$")) {
1758
1759 logger.info(" Constraining X-H bonds.");
1760 numericBonds = Arrays.stream(bonds).filter(
1761 (Bond bond) -> bond.getAtom(0).getAtomicNumber() == 1
1762 || bond.getAtom(1).getAtomicNumber() == 1).collect(Collectors.toSet());
1763 } else {
1764 String[] constraintToks = constraintStrings.split("\\s+");
1765
1766
1767 for (String tok : constraintToks) {
1768 if (tok.equalsIgnoreCase("WATER")) {
1769 logger.info(" Constraining waters to be rigid based on angle & bonds.");
1770
1771
1772 Stream<MSNode> settleStream = molecularAssembly.getMolecules().stream()
1773 .filter((MSNode m) -> m.getAtomList().size() == 3).filter((MSNode m) -> {
1774 List<Atom> atoms = m.getAtomList();
1775 Atom O = null;
1776 List<Atom> H = new ArrayList<>(2);
1777 for (Atom at : atoms) {
1778 int atN = at.getAtomicNumber();
1779 if (atN == 8) {
1780 O = at;
1781 } else if (atN == 1) {
1782 H.add(at);
1783 }
1784 }
1785 return O != null && H.size() == 2;
1786 });
1787
1788 settleStream = Stream.concat(settleStream, molecularAssembly.getWater().stream());
1789
1790 List<SettleConstraint> settleConstraints = settleStream.map(
1791 (MSNode m) -> m.getAngleList().getFirst()).map(SettleConstraint::settleFactory).toList();
1792 constraints.addAll(settleConstraints);
1793
1794 } else if (tok.equalsIgnoreCase("DIATOMIC")) {
1795 logger.severe(" Diatomic distance constraints not yet implemented properly.");
1796 } else if (tok.equalsIgnoreCase("TRIATOMIC")) {
1797 logger.severe(
1798 " Triatomic SETTLE constraints for non-water molecules not yet implemented properly.");
1799 }
1800 }
1801
1802
1803 for (String tok : constraintToks) {
1804 if (tok.equalsIgnoreCase("BONDS")) {
1805 numericBonds = new HashSet<>(Arrays.asList(bonds));
1806 } else if (tok.equalsIgnoreCase("ANGLES")) {
1807 numericAngles = new HashSet<>(Arrays.asList(angles));
1808 }
1809 }
1810 }
1811
1812
1813 for (Angle angle : numericAngles) {
1814 angle.getBondList().forEach(numericBonds::remove);
1815 }
1816
1817
1818 List<Angle> ccmaAngles = numericAngles.stream().filter((Angle ang) -> !ang.isConstrained())
1819 .collect(Collectors.toList());
1820 List<Bond> ccmaBonds = numericBonds.stream().filter((Bond bond) -> !bond.isConstrained())
1821 .collect(Collectors.toList());
1822
1823 CcmaConstraint ccmaConstraint = CcmaConstraint.ccmaFactory(ccmaBonds, ccmaAngles, atoms,
1824 getMass(), CcmaConstraint.DEFAULT_CCMA_NONZERO_CUTOFF);
1825 constraints.add(ccmaConstraint);
1826 logger.info(format(" Added %d constraints.", constraints.size()));
1827
1828 return constraints;
1829 }
1830
1831
1832
1833
1834
1835
1836
1837 public static ForceFieldEnergy energyFactory(MolecularAssembly assembly) {
1838 return energyFactory(assembly, ParallelTeam.getDefaultThreadCount());
1839 }
1840
1841
1842
1843
1844
1845
1846
1847
1848 @SuppressWarnings("fallthrough")
1849 public static ForceFieldEnergy energyFactory(MolecularAssembly assembly, int numThreads) {
1850 ForceField forceField = assembly.getForceField();
1851 String platformString = toEnumForm(forceField.getString("PLATFORM", "FFX"));
1852 try {
1853 Platform platform = Platform.valueOf(platformString);
1854 switch (platform) {
1855 case OMM, OMM_REF, OMM_CUDA, OMM_OPENCL:
1856 try {
1857 return new OpenMMEnergy(assembly, platform, numThreads);
1858 } catch (Exception ex) {
1859 logger.warning(format(" Exception creating OpenMMEnergy: %s", ex));
1860 ForceFieldEnergy ffxEnergy = assembly.getPotentialEnergy();
1861 if (ffxEnergy == null) {
1862 ffxEnergy = new ForceFieldEnergy(assembly, numThreads);
1863 assembly.setPotential(ffxEnergy);
1864 }
1865 return ffxEnergy;
1866 }
1867 case OMM_CPU:
1868 logger.warning(format(" Platform %s not supported; defaulting to FFX", platform));
1869 default:
1870 ForceFieldEnergy ffxEnergy = assembly.getPotentialEnergy();
1871 if (ffxEnergy == null) {
1872 ffxEnergy = new ForceFieldEnergy(assembly, numThreads);
1873 assembly.setPotential(ffxEnergy);
1874 }
1875 return ffxEnergy;
1876 }
1877 } catch (IllegalArgumentException | NullPointerException ex) {
1878 logger.warning(
1879 format(" String %s did not match a known energy implementation", platformString));
1880 ForceFieldEnergy ffxEnergy = assembly.getPotentialEnergy();
1881 if (ffxEnergy == null) {
1882 ffxEnergy = new ForceFieldEnergy(assembly, numThreads);
1883 assembly.setPotential(ffxEnergy);
1884 }
1885 return ffxEnergy;
1886 }
1887 }
1888
1889
1890
1891
1892
1893
1894
1895 public void applyAllConstraintPositions(double[] xPrior, double[] xNew) {
1896 applyAllConstraintPositions(xPrior, xNew, DEFAULT_CONSTRAINT_TOLERANCE);
1897 }
1898
1899
1900
1901
1902
1903
1904
1905
1906 public void applyAllConstraintPositions(double[] xPrior, double[] xNew, double tol) {
1907 if (xPrior == null) {
1908 xPrior = Arrays.copyOf(xNew, xNew.length);
1909 }
1910 for (Constraint constraint : constraints) {
1911 constraint.applyConstraintToStep(xPrior, xNew, getMass(), tol);
1912 }
1913 }
1914
1915
1916
1917
1918
1919
1920
1921 public void attachExtendedSystem(ExtendedSystem system) {
1922 if (system == null) {
1923 throw new IllegalArgumentException();
1924 }
1925 esvTerm = true;
1926 esvTermOrig = esvTerm;
1927 esvSystem = system;
1928 if (vanderWaalsTerm) {
1929 if (vanderWaals == null) {
1930 logger.warning("Null VdW during ESV setup.");
1931 } else {
1932 vanderWaals.attachExtendedSystem(system);
1933 }
1934 }
1935 if (multipoleTerm) {
1936 if (particleMeshEwald == null) {
1937 logger.warning("Null PME during ESV setup.");
1938 } else {
1939 particleMeshEwald.attachExtendedSystem(system);
1940 }
1941 }
1942 }
1943
1944
1945
1946
1947
1948
1949 @Override
1950 public boolean dEdLZeroAtEnds() {
1951
1952
1953 return !lambdaTerm;
1954 }
1955
1956
1957
1958
1959
1960
1961 public boolean destroy() {
1962 if (destroyed) {
1963
1964
1965 logger.fine(format(" This ForceFieldEnergy is already destroyed: %s", this));
1966 return true;
1967 } else {
1968 try {
1969 if (parallelTeam != null) {
1970 parallelTeam.shutdown();
1971 }
1972 if (vanderWaals != null) {
1973 vanderWaals.destroy();
1974 }
1975 if (particleMeshEwald != null) {
1976 particleMeshEwald.destroy();
1977 }
1978 molecularAssembly.finishDestruction();
1979 destroyed = true;
1980 return true;
1981 } catch (Exception ex) {
1982 logger.warning(format(" Exception in shutting down a ForceFieldEnergy: %s", ex));
1983 logger.info(Utilities.stackTraceToString(ex));
1984 return false;
1985 }
1986 }
1987 }
1988
1989
1990
1991
1992
1993
1994 public double energy() {
1995 return energy(false, false);
1996 }
1997
1998
1999
2000
2001
2002
2003 public double energy(boolean gradient, boolean print) {
2004 try {
2005 totalTime = System.nanoTime();
2006 nnTime = 0;
2007 bondTime = 0;
2008 angleTime = 0;
2009 stretchBendTime = 0;
2010 ureyBradleyTime = 0;
2011 outOfPlaneBendTime = 0;
2012 torsionTime = 0;
2013 stretchTorsionTime = 0;
2014 angleTorsionTime = 0;
2015 piOrbitalTorsionTime = 0;
2016 torsionTorsionTime = 0;
2017 improperTorsionTime = 0;
2018 vanDerWaalsTime = 0;
2019 electrostaticTime = 0;
2020 restrainDistanceTime = 0;
2021 restrainTorsionTime = 0;
2022 restrainPositionTime = 0;
2023 restrainGroupTime = 0;
2024 ncsTime = 0;
2025
2026
2027 nnEnergy = 0.0;
2028 bondEnergy = 0.0;
2029 angleEnergy = 0.0;
2030 stretchBendEnergy = 0.0;
2031 ureyBradleyEnergy = 0.0;
2032 outOfPlaneBendEnergy = 0.0;
2033 torsionEnergy = 0.0;
2034 angleTorsionEnergy = 0.0;
2035 stretchTorsionEnergy = 0.0;
2036 piOrbitalTorsionEnergy = 0.0;
2037 torsionTorsionEnergy = 0.0;
2038 improperTorsionEnergy = 0.0;
2039 totalBondedEnergy = 0.0;
2040
2041
2042 restrainDistanceEnergy = 0.0;
2043 restrainTorsionEnergy = 0.0;
2044 restrainPositionEnergy = 0.0;
2045 restrainGroupEnergy = 0.0;
2046 ncsEnergy = 0.0;
2047
2048
2049 bondRMSD = 0.0;
2050 angleRMSD = 0.0;
2051
2052
2053 vanDerWaalsEnergy = 0.0;
2054 permanentMultipoleEnergy = 0.0;
2055 permanentRealSpaceEnergy = 0.0;
2056 polarizationEnergy = 0.0;
2057 totalMultipoleEnergy = 0.0;
2058 totalNonBondedEnergy = 0.0;
2059
2060
2061 solvationEnergy = 0.0;
2062
2063
2064 relativeSolvationEnergy = 0.0;
2065 nRelativeSolvations = 0;
2066
2067 esvBias = 0.0;
2068
2069
2070 totalEnergy = 0.0;
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081 try {
2082 bondedRegion.setGradient(gradient);
2083 parallelTeam.execute(bondedRegion);
2084 } catch (RuntimeException ex) {
2085 logger.warning("Runtime exception during bonded term calculation.");
2086 throw ex;
2087 } catch (Exception ex) {
2088 logger.info(Utilities.stackTraceToString(ex));
2089 logger.severe(ex.toString());
2090 }
2091
2092 if (!lambdaBondedTerms) {
2093
2094 if (ncsTerm) {
2095 ncsTime = -System.nanoTime();
2096 ncsEnergy = ncsRestraint.residual(gradient, print);
2097 ncsTime += System.nanoTime();
2098 }
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110 if (restrainGroupTerm) {
2111 restrainGroupTime = -System.nanoTime();
2112 restrainGroupEnergy = restrainGroups.energy(gradient);
2113 restrainGroupTime += System.nanoTime();
2114 }
2115
2116 if (comTerm) {
2117 comRestraintTime = -System.nanoTime();
2118 comRestraintEnergy = comRestraint.residual(gradient, print);
2119 comRestraintTime += System.nanoTime();
2120 }
2121
2122
2123
2124 if (nnTerm) {
2125 nnTime = -System.nanoTime();
2126 nnEnergy = aniEnergy.energy(gradient, print);
2127 nnTime += System.nanoTime();
2128 }
2129
2130
2131 if (vanderWaalsTerm) {
2132 vanDerWaalsTime = -System.nanoTime();
2133 vanDerWaalsEnergy = vanderWaals.energy(gradient, print);
2134 nVanDerWaalInteractions = this.vanderWaals.getInteractions();
2135 vanDerWaalsTime += System.nanoTime();
2136 }
2137
2138 if (multipoleTerm) {
2139 electrostaticTime = -System.nanoTime();
2140 totalMultipoleEnergy = particleMeshEwald.energy(gradient, print);
2141 permanentMultipoleEnergy = particleMeshEwald.getPermanentEnergy();
2142 permanentRealSpaceEnergy = particleMeshEwald.getPermRealEnergy();
2143 polarizationEnergy = particleMeshEwald.getPolarizationEnergy();
2144 nPermanentInteractions = particleMeshEwald.getInteractions();
2145 solvationEnergy = particleMeshEwald.getSolvationEnergy();
2146 nGKInteractions = particleMeshEwald.getGKInteractions();
2147 electrostaticTime += System.nanoTime();
2148 }
2149 }
2150
2151 if (relativeSolvationTerm) {
2152 List<Residue> residuesList = molecularAssembly.getResidueList();
2153 for (Residue residue : residuesList) {
2154 if (residue instanceof MultiResidue) {
2155 Atom refAtom = residue.getSideChainAtoms().get(0);
2156 if (refAtom != null && refAtom.getUse()) {
2157
2158
2159 double thisSolvation = relativeSolvation.getSolvationEnergy(residue, false);
2160 relativeSolvationEnergy -= thisSolvation;
2161 if (thisSolvation != 0) {
2162 nRelativeSolvations++;
2163 }
2164 }
2165 }
2166 }
2167 }
2168
2169 totalTime = System.nanoTime() - totalTime;
2170
2171 totalBondedEnergy = nnEnergy + bondEnergy + angleEnergy + stretchBendEnergy + ureyBradleyEnergy
2172 + outOfPlaneBendEnergy + torsionEnergy + angleTorsionEnergy + stretchTorsionEnergy
2173 + piOrbitalTorsionEnergy + improperTorsionEnergy + torsionTorsionEnergy
2174 + ncsEnergy + comRestraintEnergy
2175 + restrainDistanceEnergy + restrainPositionEnergy + restrainGroupEnergy + restrainTorsionEnergy;
2176
2177 totalNonBondedEnergy = vanDerWaalsEnergy + totalMultipoleEnergy + relativeSolvationEnergy;
2178 totalEnergy = totalBondedEnergy + totalNonBondedEnergy + solvationEnergy;
2179 if (esvTerm) {
2180 esvBias = esvSystem.getBiasEnergy();
2181 totalEnergy += esvBias;
2182 }
2183
2184 if (print) {
2185 StringBuilder sb = new StringBuilder();
2186 if (gradient) {
2187 sb.append("\n Computed Potential Energy and Atomic Coordinate Gradients\n");
2188 } else {
2189 sb.append("\n Computed Potential Energy\n");
2190 }
2191 sb.append(this);
2192 logger.info(sb.toString());
2193 }
2194 return totalEnergy;
2195 } catch (EnergyException ex) {
2196 if (printOnFailure) {
2197 printFailure();
2198 }
2199 if (ex.doCauseSevere()) {
2200 logger.info(Utilities.stackTraceToString(ex));
2201 logger.log(Level.SEVERE, " Error in calculating energies or gradients", ex);
2202 } else {
2203 logger.log(Level.INFO, format(" Exception in energy calculation:\n %s", ex));
2204 }
2205 throw ex;
2206 }
2207 }
2208
2209
2210
2211
2212 @Override
2213 public double energy(double[] x) {
2214 return energy(x, false);
2215 }
2216
2217
2218
2219
2220 @Override
2221 public double energy(double[] x, boolean verbose) {
2222 assert Arrays.stream(x).allMatch(Double::isFinite);
2223
2224
2225 unscaleCoordinates(x);
2226
2227
2228 setCoordinates(x);
2229
2230 double e = this.energy(false, verbose);
2231
2232
2233 scaleCoordinates(x);
2234
2235 return e;
2236 }
2237
2238
2239
2240
2241 @Override
2242 public double energyAndGradient(double[] x, double[] g) {
2243 return energyAndGradient(x, g, false);
2244 }
2245
2246
2247
2248
2249 @Override
2250 public double energyAndGradient(double[] x, double[] g, boolean verbose) {
2251 assert Arrays.stream(x).allMatch(Double::isFinite);
2252
2253 unscaleCoordinates(x);
2254
2255 setCoordinates(x);
2256 double e = energy(true, verbose);
2257
2258
2259
2260 try {
2261 fillGradient(g);
2262
2263
2264 scaleCoordinatesAndGradient(x, g);
2265
2266 if (maxDebugGradient < Double.MAX_VALUE) {
2267 boolean extremeGrad = Arrays.stream(g)
2268 .anyMatch((double gi) -> (gi > maxDebugGradient || gi < -maxDebugGradient));
2269 if (extremeGrad) {
2270 File origFile = molecularAssembly.getFile();
2271 String timeString = LocalDateTime.now()
2272 .format(DateTimeFormatter.ofPattern("yyyy_MM_dd-HH_mm_ss"));
2273
2274 String filename = format("%s-LARGEGRAD-%s.pdb",
2275 removeExtension(molecularAssembly.getFile().getName()), timeString);
2276 PotentialsFunctions ef = new PotentialsUtils();
2277 filename = ef.versionFile(filename);
2278
2279 logger.warning(format(" Excessively large gradient detected; printing snapshot to file %s",
2280 filename));
2281 ef.saveAsPDB(molecularAssembly, new File(filename));
2282 molecularAssembly.setFile(origFile);
2283 }
2284 }
2285 return e;
2286 } catch (EnergyException ex) {
2287 if (printOnFailure) {
2288 printFailure();
2289 }
2290 if (ex.doCauseSevere()) {
2291 logger.info(Utilities.stackTraceToString(ex));
2292 logger.log(Level.SEVERE, " Error in calculating energies or gradients", ex);
2293 } else {
2294 logger.log(Level.INFO, format(" Exception in energy calculation:\n %s", ex));
2295 }
2296 throw ex;
2297 }
2298 }
2299
2300
2301
2302
2303 private void printFailure() {
2304 String timeString = LocalDateTime.now()
2305 .format(DateTimeFormatter.ofPattern("yyyy_MM_dd-HH_mm_ss"));
2306 File file = molecularAssembly.getFile();
2307 String ext = "pdb";
2308 if (isXYZ(file)) {
2309 ext = "xyz";
2310 }
2311 String filename = format("%s-ERROR-%s.%s", removeExtension(file.getName()), timeString, ext);
2312 PotentialsFunctions ef = new PotentialsUtils();
2313 filename = ef.versionFile(filename);
2314 logger.info(format(" Writing on-error snapshot to file %s", filename));
2315 ef.save(molecularAssembly, new File(filename));
2316 }
2317
2318
2319
2320
2321
2322
2323 @Override
2324 public double[] getAcceleration(double[] acceleration) {
2325 int n = getNumberOfVariables();
2326 if (acceleration == null || acceleration.length < n) {
2327 acceleration = new double[n];
2328 }
2329 int index = 0;
2330 double[] a = new double[3];
2331 for (int i = 0; i < nAtoms; i++) {
2332 if (atoms[i].isActive()) {
2333 atoms[i].getAcceleration(a);
2334 acceleration[index++] = a[0];
2335 acceleration[index++] = a[1];
2336 acceleration[index++] = a[2];
2337 }
2338 }
2339 return acceleration;
2340 }
2341
2342
2343
2344
2345
2346
2347 public double getAngleEnergy() {
2348 return angleEnergy;
2349 }
2350
2351
2352
2353
2354
2355
2356 public double getAngleTorsionEnergy() {
2357 return angleTorsionEnergy;
2358 }
2359
2360
2361
2362
2363
2364
2365 public AngleTorsion[] getAngleTorsions() {
2366 return angleTorsions;
2367 }
2368
2369
2370
2371
2372
2373
2374 public Angle[] getAngles() {
2375 return angles;
2376 }
2377
2378 public String getAngleEnergyString() {
2379 AngleType angleType = angles[0].angleType;
2380 String energy;
2381 if (angleType.angleFunction == AngleType.AngleFunction.SEXTIC) {
2382 energy = format("""
2383 k*(d^2 + %.15g*d^3 + %.15g*d^4 + %.15g*d^5 + %.15g*d^6);
2384 d=%.15g*theta-theta0;
2385 """,
2386 angleType.cubic, angleType.quartic, angleType.pentic, angleType.sextic, 180.0 / PI);
2387 } else {
2388 energy = format("""
2389 k*(d^2);
2390 d=%.15g*theta-theta0;
2391 """,
2392 180.0 / PI);
2393 }
2394 return energy;
2395 }
2396
2397 public String getInPlaneAngleEnergyString() {
2398 AngleType angleType = angles[0].angleType;
2399 String energy = format("""
2400 k*(d^2 + %.15g*d^3 + %.15g*d^4 + %.15g*d^5 + %.15g*d^6);
2401 d=theta-theta0;
2402 theta = %.15g*pointangle(x1, y1, z1, projx, projy, projz, x3, y3, z3);
2403 projx = x2-nx*dot;
2404 projy = y2-ny*dot;
2405 projz = z2-nz*dot;
2406 dot = nx*(x2-x3) + ny*(y2-y3) + nz*(z2-z3);
2407 nx = px/norm;
2408 ny = py/norm;
2409 nz = pz/norm;
2410 norm = sqrt(px*px + py*py + pz*pz);
2411 px = (d1y*d2z-d1z*d2y);
2412 py = (d1z*d2x-d1x*d2z);
2413 pz = (d1x*d2y-d1y*d2x);
2414 d1x = x1-x4;
2415 d1y = y1-y4;
2416 d1z = z1-z4;
2417 d2x = x3-x4;
2418 d2y = y3-y4;
2419 d2z = z3-z4;
2420 """,
2421 angleType.cubic, angleType.quartic, angleType.pentic, angleType.sextic, 180.0 / PI);
2422 return energy;
2423 }
2424
2425
2426
2427
2428
2429
2430
2431 public Angle[] getAngles(AngleMode angleMode) {
2432 if (angles == null || angles.length < 1) {
2433 return null;
2434 }
2435 int nAngles = angles.length;
2436 List<Angle> angleList = new ArrayList<>();
2437
2438 for (int i = 0; i < nAngles; i++) {
2439 if (angles[i].getAngleMode() == angleMode) {
2440 angleList.add(angles[i]);
2441 }
2442 }
2443 nAngles = angleList.size();
2444 if (nAngles < 1) {
2445 return null;
2446 }
2447 return angleList.toArray(new Angle[0]);
2448 }
2449
2450
2451
2452
2453
2454
2455
2456 public double getNeutralNetworkEnergy() {
2457 return nnEnergy;
2458 }
2459
2460
2461
2462
2463
2464
2465 public double getBondEnergy() {
2466 return bondEnergy;
2467 }
2468
2469
2470
2471
2472
2473
2474 public Bond[] getBonds() {
2475 return bonds;
2476 }
2477
2478 public String getBondEnergyString() {
2479 BondType bondType = bonds[0].getBondType();
2480 String energy;
2481 if (bondType.bondFunction == BondType.BondFunction.QUARTIC) {
2482 energy = format("""
2483 k*(d^2 + %.15g*d^3 + %.15g*d^4);
2484 d=r-r0;
2485 """,
2486 bondType.cubic / OpenMM_NmPerAngstrom,
2487 bondType.quartic / (OpenMM_NmPerAngstrom * OpenMM_NmPerAngstrom));
2488 } else {
2489 energy = """
2490 k*(d^2);
2491 d=r-r0;
2492 """;
2493 }
2494 return energy;
2495 }
2496
2497
2498
2499
2500
2501
2502 public double getCavitationEnergy() {
2503 return particleMeshEwald.getCavitationEnergy();
2504 }
2505
2506
2507
2508
2509
2510
2511 @Override
2512 public List<Constraint> getConstraints() {
2513 return constraints.isEmpty() ? Collections.emptyList() : new ArrayList<>(constraints);
2514 }
2515
2516
2517
2518
2519
2520
2521 public List<RestrainPosition> getRestrainPositions() {
2522 if (restrainPositions == null) {
2523 return Collections.emptyList();
2524 }
2525 return List.of(restrainPositions);
2526 }
2527
2528
2529
2530
2531 @Override
2532 public double[] getCoordinates(double[] x) {
2533 int n = getNumberOfVariables();
2534 if (x == null || x.length < n) {
2535 x = new double[n];
2536 }
2537 int index = 0;
2538 for (int i = 0; i < nAtoms; i++) {
2539 Atom a = atoms[i];
2540 if (a.isActive()) {
2541 x[index++] = a.getX();
2542 x[index++] = a.getY();
2543 x[index++] = a.getZ();
2544 }
2545 }
2546 return x;
2547 }
2548
2549
2550
2551
2552
2553
2554 @Override
2555 public Crystal getCrystal() {
2556 return crystal;
2557 }
2558
2559
2560
2561
2562
2563
2564 @Override
2565 public void setCrystal(Crystal crystal) {
2566 setCrystal(crystal, false);
2567 }
2568
2569
2570
2571
2572
2573
2574 public double getCutoffPlusBuffer() {
2575 return cutoffPlusBuffer;
2576 }
2577
2578
2579
2580
2581
2582
2583 public double getDispersionEnergy() {
2584 return particleMeshEwald.getDispersionEnergy();
2585 }
2586
2587
2588
2589
2590
2591
2592 public double getElectrostaticEnergy() {
2593 return totalMultipoleEnergy;
2594 }
2595
2596
2597
2598
2599 @Override
2600 public STATE getEnergyTermState() {
2601 return state;
2602 }
2603
2604
2605
2606
2607
2608
2609 @Override
2610 public void setEnergyTermState(STATE state) {
2611 this.state = state;
2612 switch (state) {
2613 case FAST:
2614 nnTerm = nnTermOrig;
2615 bondTerm = bondTermOrig;
2616 angleTerm = angleTermOrig;
2617 stretchBendTerm = stretchBendTermOrig;
2618 ureyBradleyTerm = ureyBradleyTermOrig;
2619 outOfPlaneBendTerm = outOfPlaneBendTermOrig;
2620 torsionTerm = torsionTermOrig;
2621 stretchTorsionTerm = stretchTorsionTermOrig;
2622 angleTorsionTerm = angleTorsionTermOrig;
2623 piOrbitalTorsionTerm = piOrbitalTorsionTermOrig;
2624 torsionTorsionTerm = torsionTorsionTermOrig;
2625 improperTorsionTerm = improperTorsionTermOrig;
2626 restrainDistanceTerm = restrainDistanceTermOrig;
2627 restrainTorsionTerm = restrainTorsionTermOrig;
2628 restrainPositionTerm = restrainPositionTermOrig;
2629 restrainGroupTerm = restrainGroupTermOrig;
2630 ncsTerm = ncsTermOrig;
2631 comTerm = comTermOrig;
2632 vanderWaalsTerm = false;
2633 multipoleTerm = false;
2634 polarizationTerm = false;
2635 generalizedKirkwoodTerm = false;
2636 esvTerm = false;
2637 break;
2638 case SLOW:
2639 vanderWaalsTerm = vanderWaalsTermOrig;
2640 multipoleTerm = multipoleTermOrig;
2641 polarizationTerm = polarizationTermOrig;
2642 generalizedKirkwoodTerm = generalizedKirkwoodTermOrig;
2643 esvTerm = esvTermOrig;
2644 nnTerm = false;
2645 bondTerm = false;
2646 angleTerm = false;
2647 stretchBendTerm = false;
2648 ureyBradleyTerm = false;
2649 outOfPlaneBendTerm = false;
2650 torsionTerm = false;
2651 stretchTorsionTerm = false;
2652 angleTorsionTerm = false;
2653 piOrbitalTorsionTerm = false;
2654 torsionTorsionTerm = false;
2655 improperTorsionTerm = false;
2656 restrainDistanceTerm = false;
2657 restrainPositionTerm = false;
2658 restrainGroupTerm = false;
2659 ncsTerm = false;
2660 comTerm = false;
2661 break;
2662 default:
2663 nnTerm = nnTermOrig;
2664 bondTerm = bondTermOrig;
2665 angleTerm = angleTermOrig;
2666 stretchBendTerm = stretchBendTermOrig;
2667 ureyBradleyTerm = ureyBradleyTermOrig;
2668 outOfPlaneBendTerm = outOfPlaneBendTermOrig;
2669 torsionTerm = torsionTermOrig;
2670 stretchTorsionTerm = stretchTorsionTermOrig;
2671 angleTorsionTerm = angleTorsionTermOrig;
2672 piOrbitalTorsionTerm = piOrbitalTorsionTermOrig;
2673 torsionTorsionTerm = torsionTorsionTermOrig;
2674 improperTorsionTerm = improperTorsionTermOrig;
2675 restrainDistanceTerm = restrainDistanceTermOrig;
2676 restrainTorsionTerm = restrainTorsionTermOrig;
2677 restrainPositionTerm = restrainPositionTermOrig;
2678 restrainGroupTerm = restrainGroupTermOrig;
2679 ncsTerm = ncsTermOrig;
2680 comTermOrig = comTerm;
2681 vanderWaalsTerm = vanderWaalsTermOrig;
2682 multipoleTerm = multipoleTermOrig;
2683 polarizationTerm = polarizationTermOrig;
2684 generalizedKirkwoodTerm = generalizedKirkwoodTermOrig;
2685 }
2686 }
2687
2688
2689
2690
2691
2692
2693 public double getEsvBiasEnergy() {
2694 return esvBias;
2695 }
2696
2697
2698
2699
2700
2701
2702 public ExtendedSystem getExtendedSystem() {
2703 return esvSystem;
2704 }
2705
2706
2707
2708
2709
2710
2711 public GeneralizedKirkwood getGK() {
2712 if (particleMeshEwald != null) {
2713 return particleMeshEwald.getGK();
2714 } else {
2715 return null;
2716 }
2717 }
2718
2719
2720
2721
2722
2723
2724 public double getGKEnergy() {
2725 return particleMeshEwald.getGKEnergy();
2726 }
2727
2728
2729
2730
2731
2732
2733
2734 public double[] getGradient(double[] g) {
2735 return fillGradient(g);
2736 }
2737
2738
2739
2740
2741
2742
2743 public double getImproperTorsionEnergy() {
2744 return improperTorsionEnergy;
2745 }
2746
2747
2748
2749
2750
2751
2752 public ImproperTorsion[] getImproperTorsions() {
2753 return improperTorsions;
2754 }
2755
2756
2757
2758
2759 @Override
2760 public double getLambda() {
2761 return lambda;
2762 }
2763
2764
2765
2766
2767 @Override
2768 public void setLambda(double lambda) {
2769 if (lambdaTerm) {
2770 if (lambda <= 1.0 && lambda >= 0.0) {
2771 this.lambda = lambda;
2772 if (vanderWaalsTerm) {
2773 vanderWaals.setLambda(lambda);
2774 }
2775 if (multipoleTerm) {
2776 particleMeshEwald.setLambda(lambda);
2777 }
2778
2779
2780
2781
2782
2783
2784
2785
2786 if (restrainDistanceTerm && nRestrainDistances > 0) {
2787 for (RestrainDistance restrainDistance : restrainDistances) {
2788 restrainDistance.setLambda(lambda);
2789 }
2790 }
2791 if (restrainTorsionTerm && nRestrainTorsions > 0) {
2792 for (Torsion restrainTorsion : restrainTorsions) {
2793 restrainTorsion.setLambda(lambda);
2794 }
2795 }
2796
2797 if (ncsTerm && ncsRestraint != null) {
2798 ncsRestraint.setLambda(lambda);
2799 }
2800 if (comTerm && comRestraint != null) {
2801 comRestraint.setLambda(lambda);
2802 }
2803 if (lambdaTorsions) {
2804 for (int i = 0; i < nTorsions; i++) {
2805 torsions[i].setLambda(lambda);
2806 }
2807 for (int i = 0; i < nPiOrbitalTorsions; i++) {
2808 piOrbitalTorsions[i].setLambda(lambda);
2809 }
2810 for (int i = 0; i < nTorsionTorsions; i++) {
2811 torsionTorsions[i].setLambda(lambda);
2812 }
2813 }
2814 } else {
2815 String message = format("Lambda value %8.3f is not in the range [0..1].", lambda);
2816 logger.warning(message);
2817 }
2818 } else {
2819 logger.fine(" Attempting to set a lambda value on a ForceFieldEnergy with lambdaterm false.");
2820 }
2821 }
2822
2823
2824
2825
2826 @Override
2827 public double[] getMass() {
2828 int n = getNumberOfVariables();
2829 double[] mass = new double[n];
2830 int index = 0;
2831 for (int i = 0; i < nAtoms; i++) {
2832 Atom a = atoms[i];
2833 if (a.isActive()) {
2834 double m = a.getMass();
2835 mass[index++] = m;
2836 mass[index++] = m;
2837 mass[index++] = m;
2838 }
2839 }
2840 return mass;
2841 }
2842
2843
2844
2845
2846 @Override
2847 public int getNumberOfVariables() {
2848 int nActive = 0;
2849 for (int i = 0; i < nAtoms; i++) {
2850 if (atoms[i].isActive()) {
2851 nActive++;
2852 }
2853 }
2854 return nActive * 3;
2855 }
2856
2857
2858
2859
2860
2861
2862 public int getNumberofAngleTorsions() {
2863 return nAngleTorsions;
2864 }
2865
2866
2867
2868
2869
2870
2871 public int getNumberofAngles() {
2872 return nAngles;
2873 }
2874
2875
2876
2877
2878
2879
2880 public int getNumberofBonds() {
2881 return nBonds;
2882 }
2883
2884
2885
2886
2887
2888
2889 public int getNumberofImproperTorsions() {
2890 return nImproperTorsions;
2891 }
2892
2893
2894
2895
2896
2897
2898 public int getNumberofOutOfPlaneBends() {
2899 return nOutOfPlaneBends;
2900 }
2901
2902
2903
2904
2905
2906
2907 public int getNumberofPiOrbitalTorsions() {
2908 return nPiOrbitalTorsions;
2909 }
2910
2911
2912
2913
2914
2915
2916 public int getNumberofStretchBends() {
2917 return nStretchBends;
2918 }
2919
2920
2921
2922
2923
2924
2925 public int getNumberofStretchTorsions() {
2926 return nStretchTorsions;
2927 }
2928
2929
2930
2931
2932
2933
2934 public int getNumberofTorsionTorsions() {
2935 return nTorsionTorsions;
2936 }
2937
2938
2939
2940
2941
2942
2943 public int getNumberofTorsions() {
2944 return nTorsions;
2945 }
2946
2947
2948
2949
2950
2951
2952 public int getNumberofUreyBradleys() {
2953 return nUreyBradleys;
2954 }
2955
2956
2957
2958
2959
2960
2961 public double getOutOfPlaneBendEnergy() {
2962 return outOfPlaneBendEnergy;
2963 }
2964
2965
2966
2967
2968
2969
2970 public OutOfPlaneBend[] getOutOfPlaneBends() {
2971 return outOfPlaneBends;
2972 }
2973
2974 public String getOutOfPlaneEnergyString() {
2975 OutOfPlaneBendType outOfPlaneBendType = outOfPlaneBends[0].outOfPlaneBendType;
2976 String energy = format("""
2977 k*(theta^2 + %.15g*theta^3 + %.15g*theta^4 + %.15g*theta^5 + %.15g*theta^6);
2978 theta = %.15g*pointangle(x2, y2, z2, x4, y4, z4, projx, projy, projz);
2979 projx = x2-nx*dot;
2980 projy = y2-ny*dot;
2981 projz = z2-nz*dot;
2982 dot = nx*(x2-x3) + ny*(y2-y3) + nz*(z2-z3);
2983 nx = px/norm;
2984 ny = py/norm;
2985 nz = pz/norm;
2986 norm = sqrt(px*px + py*py + pz*pz);
2987 px = (d1y*d2z-d1z*d2y);
2988 py = (d1z*d2x-d1x*d2z);
2989 pz = (d1x*d2y-d1y*d2x);
2990 d1x = x1-x4;
2991 d1y = y1-y4;
2992 d1z = z1-z4;
2993 d2x = x3-x4;
2994 d2y = y3-y4;
2995 d2z = z3-z4
2996 """,
2997 outOfPlaneBendType.cubic, outOfPlaneBendType.quartic,
2998 outOfPlaneBendType.pentic, outOfPlaneBendType.sextic, 180.0 / PI);
2999 return energy;
3000 }
3001
3002
3003
3004
3005
3006
3007 public String getPDBHeaderString() {
3008 energy(false, false);
3009 StringBuilder sb = new StringBuilder();
3010 sb.append("REMARK 3 CALCULATED POTENTIAL ENERGY\n");
3011 if (nnTerm) {
3012 sb.append(
3013 format("REMARK 3 %s %g (%d)\n", "NEUTRAL NETWORK : ", nnEnergy, nAtoms));
3014 }
3015 if (bondTerm) {
3016 sb.append(
3017 format("REMARK 3 %s %g (%d)\n", "BOND STRETCHING : ", bondEnergy, nBonds));
3018 sb.append(format("REMARK 3 %s %g\n", "BOND RMSD : ", bondRMSD));
3019 }
3020 if (angleTerm) {
3021 sb.append(format("REMARK 3 %s %g (%d)\n", "ANGLE BENDING : ", angleEnergy,
3022 nAngles));
3023 sb.append(format("REMARK 3 %s %g\n", "ANGLE RMSD : ", angleRMSD));
3024 }
3025 if (stretchBendTerm) {
3026 sb.append(
3027 format("REMARK 3 %s %g (%d)\n", "STRETCH-BEND : ", stretchBendEnergy,
3028 nStretchBends));
3029 }
3030 if (ureyBradleyTerm) {
3031 sb.append(
3032 format("REMARK 3 %s %g (%d)\n", "UREY-BRADLEY : ", ureyBradleyEnergy,
3033 nUreyBradleys));
3034 }
3035 if (outOfPlaneBendTerm) {
3036 sb.append(
3037 format("REMARK 3 %s %g (%d)\n", "OUT-OF-PLANE BEND : ", outOfPlaneBendEnergy,
3038 nOutOfPlaneBends));
3039 }
3040 if (torsionTerm) {
3041 sb.append(format("REMARK 3 %s %g (%d)\n", "TORSIONAL ANGLE : ", torsionEnergy,
3042 nTorsions));
3043 }
3044 if (piOrbitalTorsionTerm) {
3045 sb.append(format("REMARK 3 %s %g (%d)\n", "PI-ORBITAL TORSION : ",
3046 piOrbitalTorsionEnergy, nPiOrbitalTorsions));
3047 }
3048 if (torsionTorsionTerm) {
3049 sb.append(
3050 format("REMARK 3 %s %g (%d)\n", "TORSION-TORSION : ", torsionTorsionEnergy,
3051 nTorsionTorsions));
3052 }
3053 if (improperTorsionTerm) {
3054 sb.append(
3055 format("REMARK 3 %s %g (%d)\n", "IMPROPER TORSION : ", improperTorsionEnergy,
3056 nImproperTorsions));
3057 }
3058 if (restrainDistanceTerm) {
3059 sb.append(format("REMARK 3 %s %g (%d)\n", "RESTRAINT BOND STRETCHING : ",
3060 restrainDistanceEnergy, nRestrainDistances));
3061 }
3062
3063 if (ncsTerm) {
3064 sb.append(
3065 format("REMARK 3 %s %g (%d)\n", "NCS RESTRAINT : ", ncsEnergy, nAtoms));
3066 }
3067
3068 if (restrainPositionTerm && nRestrainPositions > 0) {
3069 int nRests = 0;
3070 for (RestrainPosition restrainPosition : restrainPositions) {
3071 nRests += restrainPosition.getNumAtoms();
3072 }
3073 sb.append(format("REMARK 3 %s %g (%d)\n", "COORDINATE RESTRAINTS : ", restrainPositionEnergy,
3074 nRests));
3075 }
3076
3077 if (comTerm) {
3078 sb.append(
3079 format("REMARK 3 %s %g (%d)\n", "COM RESTRAINT : ", comRestraintEnergy,
3080 nAtoms));
3081 }
3082
3083 if (vanderWaalsTerm) {
3084 sb.append(
3085 format("REMARK 3 %s %g (%d)\n", "VAN DER WAALS : ", vanDerWaalsEnergy,
3086 nVanDerWaalInteractions));
3087 }
3088 if (multipoleTerm) {
3089 sb.append(format("REMARK 3 %s %g (%d)\n", "ATOMIC MULTIPOLES : ",
3090 permanentMultipoleEnergy, nPermanentInteractions));
3091 }
3092 if (polarizationTerm) {
3093 sb.append(format("REMARK 3 %s %g (%d)\n", "POLARIZATION : ",
3094 polarizationEnergy, nPermanentInteractions));
3095 }
3096 sb.append(format("REMARK 3 %s %g\n", "TOTAL POTENTIAL (KCAL/MOL) : ", totalEnergy));
3097 int nsymm = crystal.getUnitCell().spaceGroup.getNumberOfSymOps();
3098 if (nsymm > 1) {
3099 sb.append(format("REMARK 3 %s %g\n", "UNIT CELL POTENTIAL : ", totalEnergy * nsymm));
3100 }
3101 if (crystal.getUnitCell() != crystal) {
3102 nsymm = crystal.spaceGroup.getNumberOfSymOps();
3103 if (nsymm > 1) {
3104 sb.append(format("REMARK 3 %s %g\n", "REPLICATES CELL POTENTIAL : ", totalEnergy * nsymm));
3105 }
3106 }
3107 sb.append("REMARK 3\n");
3108
3109 return sb.toString();
3110 }
3111
3112
3113
3114
3115
3116
3117 public ParallelTeam getParallelTeam() {
3118 return parallelTeam;
3119 }
3120
3121
3122
3123
3124
3125
3126 public int getPermanentInteractions() {
3127 return nPermanentInteractions;
3128 }
3129
3130
3131
3132
3133
3134
3135 public double getPermanentMultipoleEnergy() {
3136 return permanentMultipoleEnergy;
3137 }
3138
3139
3140
3141
3142
3143
3144 public double getPermanentRealSpaceEnergy() {
3145 return permanentRealSpaceEnergy;
3146 }
3147
3148
3149
3150
3151
3152
3153 public double getPermanentReciprocalMpoleEnergy() {
3154 return particleMeshEwald.getPermRecipEnergy();
3155 }
3156
3157
3158
3159
3160
3161
3162 public double getPermanentReciprocalSelfEnergy() {
3163 return particleMeshEwald.getPermSelfEnergy();
3164 }
3165
3166
3167
3168
3169
3170
3171 public double getPiOrbitalTorsionEnergy() {
3172 return piOrbitalTorsionEnergy;
3173 }
3174
3175
3176
3177
3178
3179
3180 public PiOrbitalTorsion[] getPiOrbitalTorsions() {
3181 return piOrbitalTorsions;
3182 }
3183
3184 public String getPiOrbitalTorsionEnergyString() {
3185 String energy = """
3186 2*k*sin(phi)^2;
3187 phi = pointdihedral(x3+c1x, y3+c1y, z3+c1z, x3, y3, z3, x4, y4, z4, x4+c2x, y4+c2y, z4+c2z);
3188 c1x = (d14y*d24z-d14z*d24y);
3189 c1y = (d14z*d24x-d14x*d24z);
3190 c1z = (d14x*d24y-d14y*d24x);
3191 c2x = (d53y*d63z-d53z*d63y);
3192 c2y = (d53z*d63x-d53x*d63z);
3193 c2z = (d53x*d63y-d53y*d63x);
3194 d14x = x1-x4;
3195 d14y = y1-y4;
3196 d14z = z1-z4;
3197 d24x = x2-x4;
3198 d24y = y2-y4;
3199 d24z = z2-z4;
3200 d53x = x5-x3;
3201 d53y = y5-y3;
3202 d53z = z5-z3;
3203 d63x = x6-x3;
3204 d63y = y6-y3;
3205 d63z = z6-z3;
3206 """;
3207 return energy;
3208 }
3209
3210
3211
3212
3213
3214
3215
3216 public Platform getPlatform() {
3217 return platform;
3218 }
3219
3220
3221
3222
3223
3224
3225 public ParticleMeshEwald getPmeNode() {
3226 return particleMeshEwald;
3227 }
3228
3229
3230
3231
3232
3233
3234 public double getPolarizationEnergy() {
3235 return polarizationEnergy;
3236 }
3237
3238
3239
3240
3241
3242
3243
3244 @Override
3245 public double[] getPreviousAcceleration(double[] previousAcceleration) {
3246 int n = getNumberOfVariables();
3247 if (previousAcceleration == null || previousAcceleration.length < n) {
3248 previousAcceleration = new double[n];
3249 }
3250 int index = 0;
3251 double[] a = new double[3];
3252 for (int i = 0; i < nAtoms; i++) {
3253 if (atoms[i].isActive()) {
3254 atoms[i].getPreviousAcceleration(a);
3255 previousAcceleration[index++] = a[0];
3256 previousAcceleration[index++] = a[1];
3257 previousAcceleration[index++] = a[2];
3258 }
3259 }
3260 return previousAcceleration;
3261 }
3262
3263
3264
3265
3266
3267
3268 public double getRelativeSolvationEnergy() {
3269 return relativeSolvationEnergy;
3270 }
3271
3272
3273
3274
3275 @Override
3276 public double[] getScaling() {
3277 return optimizationScaling;
3278 }
3279
3280
3281
3282
3283 @Override
3284 public void setScaling(double[] scaling) {
3285 optimizationScaling = scaling;
3286 }
3287
3288
3289
3290
3291
3292
3293 public double getSolvationEnergy() {
3294 return solvationEnergy;
3295 }
3296
3297
3298
3299
3300
3301
3302 public int getSolvationInteractions() {
3303 return nGKInteractions;
3304 }
3305
3306
3307
3308
3309
3310
3311 public double getStrenchBendEnergy() {
3312 return stretchBendEnergy;
3313 }
3314
3315
3316
3317
3318
3319
3320 public StretchBend[] getStretchBends() {
3321 return stretchBends;
3322 }
3323
3324 public String getStretchBendEnergyString() {
3325 String energy = format("(k1*(distance(p1,p2)-r12) + k2*(distance(p2,p3)-r23))*(%.15g*(angle(p1,p2,p3)-theta0))", 180.0 / PI);
3326 return energy;
3327 }
3328
3329
3330
3331
3332
3333
3334 public double getStretchTorsionEnergy() {
3335 return stretchTorsionEnergy;
3336 }
3337
3338
3339
3340
3341
3342
3343 public StretchTorsion[] getStretchTorsions() {
3344 return stretchTorsions;
3345 }
3346
3347
3348
3349
3350
3351
3352 public double getTorsionEnergy() {
3353 return torsionEnergy;
3354 }
3355
3356
3357
3358
3359
3360
3361 public double getTorsionTorsionEnergy() {
3362 return torsionTorsionEnergy;
3363 }
3364
3365
3366
3367
3368
3369
3370 public TorsionTorsion[] getTorsionTorsions() {
3371 return torsionTorsions;
3372 }
3373
3374
3375
3376
3377
3378
3379 public Torsion[] getTorsions() {
3380 return torsions;
3381 }
3382
3383
3384
3385
3386
3387
3388 public double getTotalElectrostaticEnergy() {
3389 return totalMultipoleEnergy + solvationEnergy;
3390 }
3391
3392
3393
3394
3395 @Override
3396 public double getTotalEnergy() {
3397 return totalEnergy;
3398 }
3399
3400
3401
3402
3403
3404
3405 public double getUreyBradleyEnergy() {
3406 return ureyBradleyEnergy;
3407 }
3408
3409
3410
3411
3412
3413
3414 public UreyBradley[] getUreyBradleys() {
3415 return ureyBradleys;
3416 }
3417
3418
3419
3420
3421
3422
3423 public double getVanDerWaalsEnergy() {
3424 return vanDerWaalsEnergy;
3425 }
3426
3427
3428
3429
3430
3431
3432 public int getVanDerWaalsInteractions() {
3433 return nVanDerWaalInteractions;
3434 }
3435
3436
3437
3438
3439
3440
3441 @Override
3442 public VARIABLE_TYPE[] getVariableTypes() {
3443 int n = getNumberOfVariables();
3444 VARIABLE_TYPE[] type = new VARIABLE_TYPE[n];
3445 int i = 0;
3446 for (int j = 0; j < nAtoms; j++) {
3447 if (atoms[j].isActive()) {
3448 type[i++] = VARIABLE_TYPE.X;
3449 type[i++] = VARIABLE_TYPE.Y;
3450 type[i++] = VARIABLE_TYPE.Z;
3451 }
3452 }
3453 return type;
3454 }
3455
3456
3457
3458
3459
3460
3461 public VanDerWaals getVdwNode() {
3462 return vanderWaals;
3463 }
3464
3465
3466
3467
3468
3469
3470 @Override
3471 public double[] getVelocity(double[] velocity) {
3472 int n = getNumberOfVariables();
3473 if (velocity == null || velocity.length < n) {
3474 velocity = new double[n];
3475 }
3476 int index = 0;
3477 double[] v = new double[3];
3478 for (int i = 0; i < nAtoms; i++) {
3479 Atom a = atoms[i];
3480 if (a.isActive()) {
3481 a.getVelocity(v);
3482 velocity[index++] = v[0];
3483 velocity[index++] = v[1];
3484 velocity[index++] = v[2];
3485 }
3486 }
3487 return velocity;
3488 }
3489
3490
3491
3492
3493 @Override
3494 public double getd2EdL2() {
3495 double d2EdLambda2 = 0.0;
3496 if (!lambdaBondedTerms) {
3497 if (vanderWaalsTerm) {
3498 d2EdLambda2 = vanderWaals.getd2EdL2();
3499 }
3500 if (multipoleTerm) {
3501 d2EdLambda2 += particleMeshEwald.getd2EdL2();
3502 }
3503
3504
3505
3506
3507
3508
3509
3510 if (restrainDistanceTerm && nRestrainDistances > 0) {
3511 for (int i = 0; i < nRestrainDistances; i++) {
3512 d2EdLambda2 += restrainDistances[i].getd2EdL2();
3513 }
3514 }
3515 if (ncsTerm && ncsRestraint != null) {
3516 d2EdLambda2 += ncsRestraint.getd2EdL2();
3517 }
3518 if (comTerm && comRestraint != null) {
3519 d2EdLambda2 += comRestraint.getd2EdL2();
3520 }
3521 if (lambdaTorsions) {
3522 for (int i = 0; i < nTorsions; i++) {
3523 d2EdLambda2 += torsions[i].getd2EdL2();
3524 }
3525 for (int i = 0; i < nPiOrbitalTorsions; i++) {
3526 d2EdLambda2 += piOrbitalTorsions[i].getd2EdL2();
3527 }
3528 for (int i = 0; i < nTorsionTorsions; i++) {
3529 d2EdLambda2 += torsionTorsions[i].getd2EdL2();
3530 }
3531 }
3532 }
3533 return d2EdLambda2;
3534 }
3535
3536
3537
3538
3539 @Override
3540 public double getdEdL() {
3541 double dEdLambda = 0.0;
3542 if (!lambdaBondedTerms) {
3543 if (vanderWaalsTerm) {
3544 dEdLambda = vanderWaals.getdEdL();
3545 }
3546 if (multipoleTerm) {
3547 dEdLambda += particleMeshEwald.getdEdL();
3548 }
3549 if (restrainDistanceTerm && nRestrainDistances > 0) {
3550 for (int i = 0; i < nRestrainDistances; i++) {
3551 dEdLambda += restrainDistances[i].getdEdL();
3552 }
3553 }
3554
3555
3556
3557
3558
3559
3560
3561 if (ncsTerm && ncsRestraint != null) {
3562 dEdLambda += ncsRestraint.getdEdL();
3563 }
3564 if (comTerm && comRestraint != null) {
3565 dEdLambda += comRestraint.getdEdL();
3566 }
3567 if (lambdaTorsions) {
3568 for (int i = 0; i < nTorsions; i++) {
3569 dEdLambda += torsions[i].getdEdL();
3570 }
3571 for (int i = 0; i < nPiOrbitalTorsions; i++) {
3572 dEdLambda += piOrbitalTorsions[i].getdEdL();
3573 }
3574 for (int i = 0; i < nTorsionTorsions; i++) {
3575 dEdLambda += torsionTorsions[i].getdEdL();
3576 }
3577 }
3578 }
3579 return dEdLambda;
3580 }
3581
3582
3583
3584
3585 @Override
3586 public void getdEdXdL(double[] gradients) {
3587 if (!lambdaBondedTerms) {
3588 if (vanderWaalsTerm) {
3589 vanderWaals.getdEdXdL(gradients);
3590 }
3591 if (multipoleTerm) {
3592 particleMeshEwald.getdEdXdL(gradients);
3593 }
3594 if (restrainDistanceTerm && nRestrainDistances > 0) {
3595 for (int i = 0; i < nRestrainDistances; i++) {
3596 restrainDistances[i].getdEdXdL(gradients);
3597 }
3598 }
3599
3600
3601
3602
3603
3604
3605
3606 if (ncsTerm && ncsRestraint != null) {
3607 ncsRestraint.getdEdXdL(gradients);
3608 }
3609 if (comTerm && comRestraint != null) {
3610 comRestraint.getdEdXdL(gradients);
3611 }
3612 if (lambdaTorsions) {
3613 double[] grad = new double[3];
3614 int index = 0;
3615 for (int i = 0; i < nAtoms; i++) {
3616 Atom a = atoms[i];
3617 if (a.isActive()) {
3618 a.getLambdaXYZGradient(grad);
3619 gradients[index++] += grad[0];
3620 gradients[index++] += grad[1];
3621 gradients[index++] += grad[2];
3622 }
3623 }
3624 }
3625 }
3626 }
3627
3628
3629
3630
3631
3632
3633 @Override
3634 public void setAcceleration(double[] acceleration) {
3635 if (acceleration == null) {
3636 return;
3637 }
3638 int index = 0;
3639 double[] accel = new double[3];
3640 for (int i = 0; i < nAtoms; i++) {
3641 if (atoms[i].isActive()) {
3642 accel[0] = acceleration[index++];
3643 accel[1] = acceleration[index++];
3644 accel[2] = acceleration[index++];
3645 atoms[i].setAcceleration(accel);
3646 }
3647 }
3648 }
3649
3650
3651
3652
3653
3654
3655 public void setCoordinates(double[] coords) {
3656 if (coords == null) {
3657 return;
3658 }
3659 int index = 0;
3660 for (int i = 0; i < nAtoms; i++) {
3661 Atom a = atoms[i];
3662 if (a.isActive()) {
3663 double x = coords[index++];
3664 double y = coords[index++];
3665 double z = coords[index++];
3666 a.moveTo(x, y, z);
3667 }
3668 }
3669 }
3670
3671
3672
3673
3674
3675
3676
3677 public void setCrystal(Crystal crystal, boolean checkReplicatesCell) {
3678 if (checkReplicatesCell) {
3679 this.crystal = ReplicatesCrystal.replicatesCrystalFactory(crystal.getUnitCell(), cutOff2);
3680 } else {
3681 this.crystal = crystal;
3682 }
3683
3684
3685
3686
3687 if (vanderWaalsTerm) {
3688 vanderWaals.setCrystal(this.crystal);
3689 }
3690 if (multipoleTerm) {
3691 particleMeshEwald.setCrystal(this.crystal);
3692 }
3693 }
3694
3695
3696
3697
3698
3699
3700
3701 @Override
3702 public void setPreviousAcceleration(double[] previousAcceleration) {
3703 if (previousAcceleration == null) {
3704 return;
3705 }
3706 int index = 0;
3707 double[] prev = new double[3];
3708 for (int i = 0; i < nAtoms; i++) {
3709 if (atoms[i].isActive()) {
3710 prev[0] = previousAcceleration[index++];
3711 prev[1] = previousAcceleration[index++];
3712 prev[2] = previousAcceleration[index++];
3713 atoms[i].setPreviousAcceleration(prev);
3714 }
3715 }
3716 }
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728 public void setPrintOnFailure(boolean onFail, boolean override) {
3729 if (override) {
3730
3731 printOnFailure = onFail;
3732 } else {
3733 try {
3734 molecularAssembly.getForceField().getBoolean("PRINT_ON_FAILURE");
3735
3736
3737
3738
3739
3740 } catch (Exception ex) {
3741 printOnFailure = onFail;
3742 }
3743 }
3744 }
3745
3746
3747
3748
3749
3750
3751 @Override
3752 public void setVelocity(double[] velocity) {
3753 if (velocity == null) {
3754 return;
3755 }
3756 int index = 0;
3757 double[] vel = new double[3];
3758 for (int i = 0; i < nAtoms; i++) {
3759 if (atoms[i].isActive()) {
3760 vel[0] = velocity[index++];
3761 vel[1] = velocity[index++];
3762 vel[2] = velocity[index++];
3763 atoms[i].setVelocity(vel);
3764 }
3765 }
3766 }
3767
3768
3769
3770
3771 @Override
3772 public String toString() {
3773 StringBuilder sb = new StringBuilder();
3774 if (bondTerm && nBonds > 0) {
3775 sb.append(format(" %s %20.8f %12d %12.3f (%8.5f)\n", "Bond Stretching ", bondEnergy, nBonds,
3776 bondTime * toSeconds, bondRMSD));
3777 }
3778 if (angleTerm && nAngles > 0) {
3779 sb.append(
3780 format(" %s %20.8f %12d %12.3f (%8.5f)\n", "Angle Bending ", angleEnergy, nAngles,
3781 angleTime * toSeconds, angleRMSD));
3782 }
3783 if (stretchBendTerm && nStretchBends > 0) {
3784 sb.append(
3785 format(" %s %20.8f %12d %12.3f\n", "Stretch-Bend ", stretchBendEnergy, nStretchBends,
3786 stretchBendTime * toSeconds));
3787 }
3788 if (ureyBradleyTerm && nUreyBradleys > 0) {
3789 sb.append(
3790 format(" %s %20.8f %12d %12.3f\n", "Urey-Bradley ", ureyBradleyEnergy, nUreyBradleys,
3791 ureyBradleyTime * toSeconds));
3792 }
3793 if (outOfPlaneBendTerm && nOutOfPlaneBends > 0) {
3794 sb.append(format(" %s %20.8f %12d %12.3f\n", "Out-of-Plane Bend ", outOfPlaneBendEnergy,
3795 nOutOfPlaneBends, outOfPlaneBendTime * toSeconds));
3796 }
3797 if (torsionTerm && nTorsions > 0) {
3798 sb.append(format(" %s %20.8f %12d %12.3f\n", "Torsional Angle ", torsionEnergy, nTorsions,
3799 torsionTime * toSeconds));
3800 }
3801 if (piOrbitalTorsionTerm && nPiOrbitalTorsions > 0) {
3802 sb.append(format(" %s %20.8f %12d %12.3f\n", "Pi-Orbital Torsion", piOrbitalTorsionEnergy,
3803 nPiOrbitalTorsions, piOrbitalTorsionTime * toSeconds));
3804 }
3805 if (stretchTorsionTerm && nStretchTorsions > 0) {
3806 sb.append(format(" %s %20.8f %12d %12.3f\n", "Stretch-Torsion ", stretchTorsionEnergy,
3807 nStretchTorsions, stretchTorsionTime * toSeconds));
3808 }
3809 if (angleTorsionTerm && nAngleTorsions > 0) {
3810 sb.append(format(" %s %20.8f %12d %12.3f\n", "Angle-Torsion ", angleTorsionEnergy,
3811 nAngleTorsions, angleTorsionTime * toSeconds));
3812 }
3813 if (torsionTorsionTerm && nTorsionTorsions > 0) {
3814 sb.append(format(" %s %20.8f %12d %12.3f\n", "Torsion-Torsion ", torsionTorsionEnergy,
3815 nTorsionTorsions, torsionTorsionTime * toSeconds));
3816 }
3817 if (improperTorsionTerm && nImproperTorsions > 0) {
3818 sb.append(format(" %s %20.8f %12d %12.3f\n", "Improper Torsion ", improperTorsionEnergy,
3819 nImproperTorsions, improperTorsionTime * toSeconds));
3820 }
3821 if (restrainDistanceTerm && nRestrainDistances > 0) {
3822 sb.append(format(" %s %20.8f %12d %12.3f\n", "Restrain Distance ", restrainDistanceEnergy,
3823 nRestrainDistances, restrainDistanceTime * toSeconds));
3824 }
3825 if (restrainTorsionTerm && nRestrainTorsions > 0) {
3826 sb.append(format(" %s %20.8f %12d %12.3f\n", "Restrain Torsion ", restrainTorsionEnergy, nRestrainTorsions,
3827 restrainTorsionTime * toSeconds));
3828 }
3829 if (restrainPositionTerm && nRestrainPositions > 0) {
3830 int nRestrainPositionAtoms = 0;
3831 for (RestrainPosition restrainPosition : restrainPositions) {
3832 nRestrainPositionAtoms += restrainPosition.getNumAtoms();
3833 }
3834 sb.append(format(" %s %20.8f %12d %12.3f\n", "Restrain Position ", restrainPositionEnergy, nRestrainPositionAtoms,
3835 restrainPositionTime * toSeconds));
3836 }
3837 if (restrainGroupTerm && nRestrainGroups > 0) {
3838 sb.append(format(" %s %20.8f %12d %12.3f\n", "Restrain Groups ", restrainGroupEnergy,
3839 nRestrainGroups, restrainGroupTime * toSeconds));
3840 }
3841 if (ncsTerm) {
3842 sb.append(format(" %s %20.8f %12d %12.3f\n", "NCS Restraint ", ncsEnergy, nAtoms,
3843 ncsTime * toSeconds));
3844 }
3845 if (comTerm) {
3846 sb.append(format(" %s %20.8f %12d %12.3f\n", "COM Restraint ", comRestraintEnergy, nAtoms,
3847 comRestraintTime * toSeconds));
3848 }
3849 if (vanderWaalsTerm && nVanDerWaalInteractions > 0) {
3850 sb.append(format(" %s %20.8f %12d %12.3f\n", "Van der Waals ", vanDerWaalsEnergy,
3851 nVanDerWaalInteractions, vanDerWaalsTime * toSeconds));
3852 }
3853 if (multipoleTerm && nPermanentInteractions > 0) {
3854 if (polarizationTerm) {
3855 sb.append(format(" %s %20.8f %12d\n", "Atomic Multipoles ", permanentMultipoleEnergy,
3856 nPermanentInteractions));
3857 } else {
3858 if (elecForm == ELEC_FORM.FIXED_CHARGE) {
3859 sb.append(format(" %s %20.8f %12d %12.3f\n", "Atomic Charges ", permanentMultipoleEnergy,
3860 nPermanentInteractions, electrostaticTime * toSeconds));
3861 } else
3862 sb.append(format(" %s %20.8f %12d %12.3f\n", "Atomic Multipoles ", permanentMultipoleEnergy,
3863 nPermanentInteractions, electrostaticTime * toSeconds));
3864 }
3865 }
3866 if (polarizationTerm && nPermanentInteractions > 0) {
3867 sb.append(format(" %s %20.8f %12d %12.3f\n", "Polarization ", polarizationEnergy,
3868 nPermanentInteractions, electrostaticTime * toSeconds));
3869 }
3870 if (generalizedKirkwoodTerm && nGKInteractions > 0) {
3871 sb.append(
3872 format(" %s %20.8f %12d\n", "Solvation ", solvationEnergy, nGKInteractions));
3873 }
3874 if (relativeSolvationTerm) {
3875 sb.append(format(" %s %20.8f %12d\n", "Relative Solvation", relativeSolvationEnergy,
3876 nRelativeSolvations));
3877 }
3878 if (esvTerm) {
3879 sb.append(
3880 format(" %s %20.8f %s\n", "ExtendedSystemBias", esvBias, esvSystem.getLambdaList()));
3881 sb.append(esvSystem.getBiasDecomposition());
3882 }
3883 if (nnTerm) {
3884 sb.append(format(" %s %20.8f %12d %12.3f\n", "Neural Network ", nnEnergy, nAtoms,
3885 nnTime * toSeconds));
3886 }
3887 sb.append(
3888 format(" %s %20.8f %s %12.3f (sec)", "Total Potential ", totalEnergy, "(Kcal/mole)",
3889 totalTime * toSeconds));
3890 int nsymm = crystal.getUnitCell().spaceGroup.getNumberOfSymOps();
3891 if (nsymm > 1) {
3892 sb.append(format("\n %s %20.8f", "Unit Cell ", totalEnergy * nsymm));
3893 }
3894 if (crystal.getUnitCell() != crystal) {
3895 nsymm = crystal.spaceGroup.getNumberOfSymOps();
3896 sb.append(format("\n %s %20.8f", "Replicates Cell ", totalEnergy * nsymm));
3897 }
3898
3899 return sb.toString();
3900 }
3901
3902
3903
3904
3905
3906 public void logBondedTerms() {
3907 if (bondTerm && nBonds > 0) {
3908 logger.info("\n Bond Stretching Interactions:");
3909 Bond[] bonds = getBonds();
3910 for (Bond bond : bonds) {
3911 logger.info(" Bond \t" + bond.toString());
3912 }
3913 }
3914 if (angleTerm && nAngles > 0) {
3915 logger.info("\n Angle Bending Interactions:");
3916 Angle[] angles = getAngles();
3917 for (Angle angle : angles) {
3918 logger.info(" Angle \t" + angle.toString());
3919 }
3920 }
3921 if (stretchBendTerm && nStretchBends > 0) {
3922 logger.info("\n Stretch-Bend Interactions:");
3923 StretchBend[] stretchBends = getStretchBends();
3924 for (StretchBend stretchBend : stretchBends) {
3925 logger.info(" Stretch-Bend \t" + stretchBend.toString());
3926 }
3927 }
3928 if (ureyBradleyTerm && nUreyBradleys > 0) {
3929 logger.info("\n Urey-Bradley Interactions:");
3930 UreyBradley[] ureyBradleys = getUreyBradleys();
3931 for (UreyBradley ureyBradley : ureyBradleys) {
3932 logger.info("Urey-Bradley \t" + ureyBradley.toString());
3933 }
3934 }
3935 if (outOfPlaneBendTerm && nOutOfPlaneBends > 0) {
3936 logger.info("\n Out-of-Plane Bend Interactions:");
3937 OutOfPlaneBend[] outOfPlaneBends = getOutOfPlaneBends();
3938 for (OutOfPlaneBend outOfPlaneBend : outOfPlaneBends) {
3939 logger.info(" Out-of-Plane Bend \t" + outOfPlaneBend.toString());
3940 }
3941 }
3942 if (torsionTerm && nTorsions > 0) {
3943 logger.info("\n Torsion Angle Interactions:");
3944 Torsion[] torsions = getTorsions();
3945 for (Torsion torsion : torsions) {
3946 logger.info(" Torsion \t" + torsion.toString());
3947 }
3948 }
3949 if (piOrbitalTorsionTerm && nPiOrbitalTorsions > 0) {
3950 logger.info("\n Pi-Orbital Torsion Interactions:");
3951 PiOrbitalTorsion[] piOrbitalTorsions = getPiOrbitalTorsions();
3952 for (PiOrbitalTorsion piOrbitalTorsion : piOrbitalTorsions) {
3953 logger.info(" Pi-Torsion \t" + piOrbitalTorsion.toString());
3954 }
3955 }
3956 if (stretchTorsionTerm && nStretchTorsions > 0) {
3957 logger.info("\n Stretch-Torsion Interactions:");
3958 StretchTorsion[] stretchTorsions = getStretchTorsions();
3959 for (StretchTorsion stretchTorsion : stretchTorsions) {
3960 logger.info(" Stretch-Torsion \t" + stretchTorsion.toString());
3961 }
3962 }
3963 if (angleTorsionTerm && nAngleTorsions > 0) {
3964 logger.info("\n Angle-Torsion Interactions:");
3965 AngleTorsion[] angleTorsions = getAngleTorsions();
3966 for (AngleTorsion angleTorsion : angleTorsions) {
3967 logger.info(" Angle-Torsion \t" + angleTorsion.toString());
3968 }
3969 }
3970 if (torsionTorsionTerm && nTorsionTorsions > 0) {
3971 logger.info("\n Torsion-Torsion Interactions:");
3972 TorsionTorsion[] torsionTorsions = getTorsionTorsions();
3973 for (TorsionTorsion torsionTorsion : torsionTorsions) {
3974 logger.info(" Torsion-Torsion \t" + torsionTorsion.toString());
3975 }
3976 }
3977 if (improperTorsionTerm && nImproperTorsions > 0) {
3978 logger.info("\n Improper Interactions:");
3979 ImproperTorsion[] improperTorsions = getImproperTorsions();
3980 for (ImproperTorsion improperTorsion : improperTorsions) {
3981 logger.info(" Improper \t" + improperTorsion.toString());
3982 }
3983 }
3984 if (restrainDistanceTerm && nRestrainDistances > 0) {
3985 logger.info("\n Restrain Distance Interactions:");
3986 List<RestrainDistance> restrainDistances = getRestrainDistances(null);
3987 for (RestrainDistance restrainDistance : restrainDistances) {
3988 logger.info(" Restrain Distance \t" + restrainDistance.toString());
3989 }
3990 }
3991 if (restrainTorsionTerm && nRestrainTorsions > 0) {
3992 logger.info("\n Restrain Torsion Interactions:");
3993 for (Torsion restrainTorsion : restrainTorsions) {
3994 logger.info(" Restrain Torsion \t" + restrainTorsion.toString());
3995 }
3996 }
3997 if (restrainPositionTerm && nRestrainPositions > 0) {
3998 logger.info("\n Restrain Position Interactions:");
3999 for (RestrainPosition restrainPosition : restrainPositions) {
4000 logger.info(" Restrain Position \t" + restrainPosition.toString());
4001 }
4002 }
4003 if (restrainGroupTerm && nRestrainGroups > 0) {
4004 logger.info("\n Restrain Group Interactions:");
4005 logger.info(restrainGroups.toString());
4006 }
4007 }
4008
4009
4010
4011
4012
4013
4014
4015 void setLambdaBondedTerms(boolean lambdaBondedTerms, boolean lambdaAllBondedTerms) {
4016 this.lambdaBondedTerms = lambdaBondedTerms;
4017 this.lambdaAllBondedTerms = lambdaAllBondedTerms;
4018 }
4019
4020
4021
4022
4023
4024
4025
4026 private double getNonbondedEnergy(boolean includeSolv) {
4027 return (includeSolv ? (totalNonBondedEnergy + solvationEnergy) : totalNonBondedEnergy);
4028 }
4029
4030
4031
4032
4033
4034
4035
4036
4037 private double[] fillGradient(double[] g) {
4038 assert (g != null);
4039 double[] grad = new double[3];
4040 int n = getNumberOfVariables();
4041 if (g == null || g.length < n) {
4042 g = new double[n];
4043 }
4044 int index = 0;
4045 for (int i = 0; i < nAtoms; i++) {
4046 Atom a = atoms[i];
4047 if (a.isActive()) {
4048 a.getXYZGradient(grad);
4049 double gx = grad[0];
4050 double gy = grad[1];
4051 double gz = grad[2];
4052 if (isNaN(gx) || isInfinite(gx) || isNaN(gy) || isInfinite(gy) || isNaN(gz) || isInfinite(
4053 gz)) {
4054 StringBuilder sb = new StringBuilder(
4055 format("The gradient of atom %s is (%8.3f,%8.3f,%8.3f).", a, gx, gy, gz));
4056 double[] vals = new double[3];
4057 a.getVelocity(vals);
4058 sb.append(format("\n Velocities: %8.3g %8.3g %8.3g", vals[0], vals[1], vals[2]));
4059 a.getAcceleration(vals);
4060 sb.append(format("\n Accelerations: %8.3g %8.3g %8.3g", vals[0], vals[1], vals[2]));
4061 a.getPreviousAcceleration(vals);
4062 sb.append(
4063 format("\n Previous accelerations: %8.3g %8.3g %8.3g", vals[0], vals[1], vals[2]));
4064
4065 throw new EnergyException(sb.toString());
4066 }
4067 g[index++] = gx;
4068 g[index++] = gy;
4069 g[index++] = gz;
4070 }
4071 }
4072 return g;
4073 }
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087 private void setRestrainDistance(Atom a1, Atom a2, double distance, double forceConstant,
4088 double flatBottom, double lamStart, double lamEnd,
4089 UnivariateSwitchingFunction switchingFunction) {
4090 restrainDistanceTerm = true;
4091 boolean rbLambda = !(switchingFunction instanceof ConstantSwitch) && lambdaTerm;
4092 RestrainDistance restrainDistance = new RestrainDistance(a1, a2, crystal, rbLambda, lamStart, lamEnd, switchingFunction);
4093 int[] classes = {a1.getAtomType().atomClass, a2.getAtomType().atomClass};
4094 if (flatBottom != 0) {
4095 BondType bondType = new BondType(classes, forceConstant, distance,
4096 BondType.BondFunction.FLAT_BOTTOM_HARMONIC, flatBottom);
4097 restrainDistance.setBondType(bondType);
4098 } else {
4099 BondType bondType = new BondType(classes, forceConstant, distance,
4100 BondType.BondFunction.HARMONIC);
4101 restrainDistance.setBondType(bondType);
4102 }
4103
4104 if (restrainDistances == null) {
4105 nRestrainDistances = 0;
4106 }
4107
4108 RestrainDistance[] restrainDistances1 = new RestrainDistance[++nRestrainDistances];
4109 if (restrainDistances != null && restrainDistances.length != 0) {
4110 arraycopy(restrainDistances, 0, restrainDistances1, 0, (nRestrainDistances - 1));
4111 }
4112 restrainDistances1[nRestrainDistances - 1] = restrainDistance;
4113 restrainDistances = restrainDistances1;
4114 restrainDistance.energy(false);
4115 restrainDistance.log();
4116 }
4117
4118 private Crystal configureNCS(ForceField forceField, Crystal unitCell) {
4119
4120
4121 if (forceField.getProperties().containsKey("MTRIX1")
4122 && forceField.getProperties().containsKey("MTRIX2") && forceField.getProperties()
4123 .containsKey("MTRIX3")) {
4124 Crystal unitCell2 = new Crystal(unitCell.a, unitCell.b, unitCell.c, unitCell.alpha,
4125 unitCell.beta, unitCell.gamma, unitCell.spaceGroup.pdbName);
4126 SpaceGroup spaceGroup = unitCell2.spaceGroup;
4127
4128 CompositeConfiguration properties = forceField.getProperties();
4129 String[] MTRX1List = properties.getStringArray("MTRIX1");
4130 String[] MTRX2List = properties.getStringArray("MTRIX2");
4131 String[] MTRX3List = properties.getStringArray("MTRIX3");
4132 spaceGroup.symOps.clear();
4133 double number1;
4134 double number2;
4135 double number3;
4136 for (int i = 0; i < MTRX1List.length; i++) {
4137 double[][] Rot_MTRX = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
4138 double[] Tr_MTRX = {0, 0, 0};
4139 String[] tokens1 = MTRX1List[i].trim().split(" +");
4140 String[] tokens2 = MTRX2List[i].trim().split(" +");
4141 String[] tokens3 = MTRX3List[i].trim().split(" +");
4142 for (int k = 0; k < 4; k++) {
4143 number1 = Double.parseDouble(tokens1[k]);
4144 number2 = Double.parseDouble(tokens2[k]);
4145 number3 = Double.parseDouble(tokens3[k]);
4146 if (k != 3) {
4147 Rot_MTRX[0][k] = number1;
4148 Rot_MTRX[1][k] = number2;
4149 Rot_MTRX[2][k] = number3;
4150 } else {
4151 Tr_MTRX[0] = number1;
4152 Tr_MTRX[1] = number2;
4153 Tr_MTRX[2] = number3;
4154 }
4155 }
4156 SymOp symOp = new SymOp(Rot_MTRX, Tr_MTRX);
4157 if (logger.isLoggable(Level.FINEST)) {
4158 logger.info(
4159 format(" MTRIXn SymOp: %d of %d\n" + symOp, i + 1, MTRX1List.length));
4160 }
4161 spaceGroup.symOps.add(symOp);
4162 }
4163 unitCell = NCSCrystal.NCSCrystalFactory(unitCell, spaceGroup.symOps);
4164 unitCell.updateCrystal();
4165 }
4166 return unitCell;
4167 }
4168
4169
4170
4171
4172
4173
4174
4175 public List<RestrainDistance> getRestrainDistances(@Nullable BondType.BondFunction bondFunction) {
4176 List<RestrainDistance> list = new ArrayList<>();
4177 if (restrainDistances != null && restrainDistances.length > 0) {
4178
4179 if (bondFunction == null) {
4180 return Arrays.asList(restrainDistances);
4181 }
4182
4183 for (RestrainDistance restrainDistance : restrainDistances) {
4184 if (restrainDistance.getBondType().bondFunction == bondFunction) {
4185 list.add(restrainDistance);
4186 }
4187 }
4188 if (!list.isEmpty()) {
4189 return list;
4190 }
4191 }
4192 return null;
4193 }
4194
4195 public RestrainMode getRestrainMode() {
4196 return restrainMode;
4197 }
4198
4199
4200
4201
4202
4203
4204 public Torsion[] getRestrainTorsions() {
4205 if (restrainTorsions != null && restrainTorsions.length > 0) {
4206 return restrainTorsions;
4207 } else {
4208 return null;
4209 }
4210 }
4211
4212
4213
4214
4215
4216
4217 public RestrainGroups getRestrainGroups() {
4218 return restrainGroups;
4219 }
4220
4221 private class BondedRegion extends ParallelRegion {
4222
4223
4224 private final SharedDouble sharedBondRMSD;
4225 private final SharedDouble sharedAngleRMSD;
4226
4227 private final SharedDouble sharedBondEnergy;
4228 private final SharedDouble sharedAngleEnergy;
4229 private final SharedDouble sharedOutOfPlaneBendEnergy;
4230 private final SharedDouble sharedPiOrbitalTorsionEnergy;
4231 private final SharedDouble sharedStretchBendEnergy;
4232 private final SharedDouble sharedUreyBradleyEnergy;
4233 private final SharedDouble sharedImproperTorsionEnergy;
4234 private final SharedDouble sharedTorsionEnergy;
4235 private final SharedDouble sharedStretchTorsionEnergy;
4236 private final SharedDouble sharedAngleTorsionEnergy;
4237 private final SharedDouble sharedTorsionTorsionEnergy;
4238 private final SharedDouble sharedRestrainPositionEnergy;
4239 private final SharedDouble sharedRestrainDistanceEnergy;
4240 private final SharedDouble sharedRestrainTorsionEnergy;
4241
4242 private final int nThreads;
4243
4244 private final GradInitLoop[] gradInitLoops;
4245 private final GradReduceLoop[] gradReduceLoops;
4246
4247 private final BondedTermLoop[] bondLoops;
4248 private final BondedTermLoop[] angleLoops;
4249 private final BondedTermLoop[] outOfPlaneBendLoops;
4250 private final BondedTermLoop[] improperTorsionLoops;
4251 private final BondedTermLoop[] piOrbitalTorsionLoops;
4252 private final BondedTermLoop[] stretchBendLoops;
4253 private final BondedTermLoop[] torsionLoops;
4254 private final BondedTermLoop[] stretchTorsionLoops;
4255 private final BondedTermLoop[] angleTorsionLoops;
4256 private final BondedTermLoop[] torsionTorsionLoops;
4257 private final BondedTermLoop[] ureyBradleyLoops;
4258 private final BondedTermLoop[] restrainPositionLoops;
4259 private final BondedTermLoop[] restrainDistanceLoops;
4260 private final BondedTermLoop[] restrainTorsionLoops;
4261 private final AtomicDoubleArray3D grad;
4262
4263 private boolean gradient = false;
4264 private AtomicDoubleArrayImpl atomicDoubleArrayImpl;
4265 private AtomicDoubleArray3D lambdaGrad;
4266
4267 BondedRegion() {
4268
4269
4270 sharedAngleRMSD = new SharedDouble();
4271 sharedBondRMSD = new SharedDouble();
4272
4273
4274 sharedBondEnergy = new SharedDouble();
4275 sharedAngleEnergy = new SharedDouble();
4276 sharedImproperTorsionEnergy = new SharedDouble();
4277 sharedOutOfPlaneBendEnergy = new SharedDouble();
4278 sharedPiOrbitalTorsionEnergy = new SharedDouble();
4279 sharedStretchBendEnergy = new SharedDouble();
4280 sharedTorsionEnergy = new SharedDouble();
4281 sharedStretchTorsionEnergy = new SharedDouble();
4282 sharedAngleTorsionEnergy = new SharedDouble();
4283 sharedTorsionTorsionEnergy = new SharedDouble();
4284 sharedUreyBradleyEnergy = new SharedDouble();
4285
4286
4287 sharedRestrainPositionEnergy = new SharedDouble();
4288 sharedRestrainDistanceEnergy = new SharedDouble();
4289 sharedRestrainTorsionEnergy = new SharedDouble();
4290
4291 nThreads = parallelTeam.getThreadCount();
4292
4293
4294 gradInitLoops = new GradInitLoop[nThreads];
4295 gradReduceLoops = new GradReduceLoop[nThreads];
4296
4297
4298 angleLoops = new BondedTermLoop[nThreads];
4299 bondLoops = new BondedTermLoop[nThreads];
4300 improperTorsionLoops = new BondedTermLoop[nThreads];
4301 outOfPlaneBendLoops = new BondedTermLoop[nThreads];
4302 piOrbitalTorsionLoops = new BondedTermLoop[nThreads];
4303 stretchBendLoops = new BondedTermLoop[nThreads];
4304 torsionLoops = new BondedTermLoop[nThreads];
4305 stretchTorsionLoops = new BondedTermLoop[nThreads];
4306 angleTorsionLoops = new BondedTermLoop[nThreads];
4307 torsionTorsionLoops = new BondedTermLoop[nThreads];
4308 ureyBradleyLoops = new BondedTermLoop[nThreads];
4309 restrainPositionLoops = new BondedTermLoop[nThreads];
4310 restrainTorsionLoops = new BondedTermLoop[nThreads];
4311 restrainDistanceLoops = new BondedTermLoop[nThreads];
4312
4313
4314 atomicDoubleArrayImpl = AtomicDoubleArrayImpl.MULTI;
4315 ForceField forceField = molecularAssembly.getForceField();
4316
4317 String value = forceField.getString("ARRAY_REDUCTION", "MULTI");
4318 try {
4319 atomicDoubleArrayImpl = AtomicDoubleArrayImpl.valueOf(toEnumForm(value));
4320 } catch (Exception e) {
4321 logger.info(format(" Unrecognized ARRAY-REDUCTION %s; defaulting to %s", value,
4322 atomicDoubleArrayImpl));
4323 }
4324 logger.fine(format(" Bonded using %s arrays.", atomicDoubleArrayImpl.toString()));
4325
4326 grad = new AtomicDoubleArray3D(atomicDoubleArrayImpl, nAtoms, nThreads);
4327 if (lambdaTerm) {
4328 lambdaGrad = new AtomicDoubleArray3D(atomicDoubleArrayImpl, nAtoms, nThreads);
4329 }
4330 }
4331
4332 @Override
4333 public void finish() {
4334
4335 if (bondTerm) {
4336 bondRMSD = sqrt(sharedBondRMSD.get() / bonds.length);
4337 }
4338 if (angleTerm) {
4339 angleRMSD = sqrt(sharedAngleRMSD.get() / angles.length);
4340 }
4341
4342
4343 angleEnergy = sharedAngleEnergy.get();
4344 bondEnergy = sharedBondEnergy.get();
4345 improperTorsionEnergy = sharedImproperTorsionEnergy.get();
4346 outOfPlaneBendEnergy = sharedOutOfPlaneBendEnergy.get();
4347 piOrbitalTorsionEnergy = sharedPiOrbitalTorsionEnergy.get();
4348 stretchBendEnergy = sharedStretchBendEnergy.get();
4349 ureyBradleyEnergy = sharedUreyBradleyEnergy.get();
4350 torsionEnergy = sharedTorsionEnergy.get();
4351 stretchTorsionEnergy = sharedStretchTorsionEnergy.get();
4352 angleTorsionEnergy = sharedAngleTorsionEnergy.get();
4353 torsionTorsionEnergy = sharedTorsionTorsionEnergy.get();
4354 ureyBradleyEnergy = sharedUreyBradleyEnergy.get();
4355
4356
4357 restrainPositionEnergy = sharedRestrainPositionEnergy.get();
4358 restrainDistanceEnergy = sharedRestrainDistanceEnergy.get();
4359 restrainTorsionEnergy = sharedRestrainTorsionEnergy.get();
4360 }
4361
4362 @Override
4363 public void run() throws Exception {
4364 int threadID = getThreadIndex();
4365
4366
4367 if (gradient) {
4368 if (gradInitLoops[threadID] == null) {
4369 gradInitLoops[threadID] = new GradInitLoop();
4370 }
4371 execute(0, nAtoms - 1, gradInitLoops[threadID]);
4372 }
4373
4374
4375 if (angleTerm) {
4376 if (angleLoops[threadID] == null) {
4377 angleLoops[threadID] = new BondedTermLoop(angles, sharedAngleEnergy, sharedAngleRMSD);
4378 }
4379 if (threadID == 0) {
4380 angleTime = -System.nanoTime();
4381 }
4382 execute(0, nAngles - 1, angleLoops[threadID]);
4383 if (threadID == 0) {
4384 angleTime += System.nanoTime();
4385 }
4386 }
4387
4388 if (bondTerm) {
4389 if (bondLoops[threadID] == null) {
4390 bondLoops[threadID] = new BondedTermLoop(bonds, sharedBondEnergy, sharedBondRMSD);
4391 }
4392 if (threadID == 0) {
4393 bondTime = -System.nanoTime();
4394 }
4395 execute(0, nBonds - 1, bondLoops[threadID]);
4396 if (threadID == 0) {
4397 bondTime += System.nanoTime();
4398 }
4399 }
4400
4401 if (improperTorsionTerm) {
4402 if (improperTorsionLoops[threadID] == null) {
4403 improperTorsionLoops[threadID] = new BondedTermLoop(improperTorsions,
4404 sharedImproperTorsionEnergy);
4405 }
4406 if (threadID == 0) {
4407 improperTorsionTime = -System.nanoTime();
4408 }
4409 execute(0, nImproperTorsions - 1, improperTorsionLoops[threadID]);
4410 if (threadID == 0) {
4411 improperTorsionTime += System.nanoTime();
4412 }
4413 }
4414
4415 if (outOfPlaneBendTerm) {
4416 if (outOfPlaneBendLoops[threadID] == null) {
4417 outOfPlaneBendLoops[threadID] = new BondedTermLoop(outOfPlaneBends,
4418 sharedOutOfPlaneBendEnergy);
4419 }
4420 if (threadID == 0) {
4421 outOfPlaneBendTime = -System.nanoTime();
4422 }
4423 execute(0, nOutOfPlaneBends - 1, outOfPlaneBendLoops[threadID]);
4424 if (threadID == 0) {
4425 outOfPlaneBendTime += System.nanoTime();
4426 }
4427 }
4428
4429 if (piOrbitalTorsionTerm) {
4430 if (piOrbitalTorsionLoops[threadID] == null) {
4431 piOrbitalTorsionLoops[threadID] = new BondedTermLoop(piOrbitalTorsions,
4432 sharedPiOrbitalTorsionEnergy);
4433 }
4434 if (threadID == 0) {
4435 piOrbitalTorsionTime = -System.nanoTime();
4436 }
4437 execute(0, nPiOrbitalTorsions - 1, piOrbitalTorsionLoops[threadID]);
4438 if (threadID == 0) {
4439 piOrbitalTorsionTime += System.nanoTime();
4440 }
4441 }
4442
4443 if (stretchBendTerm) {
4444 if (stretchBendLoops[threadID] == null) {
4445 stretchBendLoops[threadID] = new BondedTermLoop(stretchBends, sharedStretchBendEnergy);
4446 }
4447 if (threadID == 0) {
4448 stretchBendTime = -System.nanoTime();
4449 }
4450 execute(0, nStretchBends - 1, stretchBendLoops[threadID]);
4451 if (threadID == 0) {
4452 stretchBendTime += System.nanoTime();
4453 }
4454 }
4455
4456 if (torsionTerm) {
4457 if (torsionLoops[threadID] == null) {
4458 torsionLoops[threadID] = new BondedTermLoop(torsions, sharedTorsionEnergy);
4459 }
4460 if (threadID == 0) {
4461 torsionTime = -System.nanoTime();
4462 }
4463 execute(0, nTorsions - 1, torsionLoops[threadID]);
4464 if (threadID == 0) {
4465 torsionTime += System.nanoTime();
4466 }
4467 }
4468
4469 if (stretchTorsionTerm) {
4470 if (stretchTorsionLoops[threadID] == null) {
4471 stretchTorsionLoops[threadID] = new BondedTermLoop(stretchTorsions,
4472 sharedStretchTorsionEnergy);
4473 }
4474 if (threadID == 0) {
4475 stretchTorsionTime = -System.nanoTime();
4476 }
4477 execute(0, nStretchTorsions - 1, stretchTorsionLoops[threadID]);
4478 if (threadID == 0) {
4479 stretchTorsionTime += System.nanoTime();
4480 }
4481 }
4482
4483 if (angleTorsionTerm) {
4484 if (angleTorsionLoops[threadID] == null) {
4485 angleTorsionLoops[threadID] = new BondedTermLoop(angleTorsions, sharedAngleTorsionEnergy);
4486 }
4487 if (threadID == 0) {
4488 angleTorsionTime = -System.nanoTime();
4489 }
4490 execute(0, nAngleTorsions - 1, angleTorsionLoops[threadID]);
4491 if (threadID == 0) {
4492 angleTorsionTime += System.nanoTime();
4493 }
4494 }
4495
4496 if (torsionTorsionTerm) {
4497 if (torsionTorsionLoops[threadID] == null) {
4498 torsionTorsionLoops[threadID] = new BondedTermLoop(torsionTorsions,
4499 sharedTorsionTorsionEnergy);
4500 }
4501 if (threadID == 0) {
4502 torsionTorsionTime = -System.nanoTime();
4503 }
4504 execute(0, nTorsionTorsions - 1, torsionTorsionLoops[threadID]);
4505 if (threadID == 0) {
4506 torsionTorsionTime += System.nanoTime();
4507 }
4508 }
4509
4510 if (ureyBradleyTerm) {
4511 if (ureyBradleyLoops[threadID] == null) {
4512 ureyBradleyLoops[threadID] = new BondedTermLoop(ureyBradleys, sharedUreyBradleyEnergy);
4513 }
4514 if (threadID == 0) {
4515 ureyBradleyTime = -System.nanoTime();
4516 }
4517 execute(0, nUreyBradleys - 1, ureyBradleyLoops[threadID]);
4518 if (threadID == 0) {
4519 ureyBradleyTime += System.nanoTime();
4520 }
4521 }
4522
4523
4524 if ((restrainMode == RestrainMode.ENERGY) ||
4525 (restrainMode == RestrainMode.ALCHEMICAL && lambdaBondedTerms)) {
4526 boolean checkAlchemicalAtoms = (restrainMode == RestrainMode.ENERGY);
4527 if (restrainPositionTerm && nRestrainPositions > 0) {
4528 if (restrainPositionLoops[threadID] == null) {
4529 restrainPositionLoops[threadID] = new BondedTermLoop(restrainPositions, sharedRestrainPositionEnergy, null, checkAlchemicalAtoms);
4530 }
4531 if (threadID == 0) {
4532 restrainPositionTime = -System.nanoTime();
4533 }
4534 execute(0, nRestrainPositions - 1, restrainPositionLoops[threadID]);
4535 if (threadID == 0) {
4536 restrainPositionTime += System.nanoTime();
4537 }
4538 }
4539
4540
4541 if (restrainDistanceTerm && nRestrainDistances > 0) {
4542 if (restrainDistanceLoops[threadID] == null) {
4543 restrainDistanceLoops[threadID] = new BondedTermLoop(restrainDistances, sharedRestrainDistanceEnergy, null, checkAlchemicalAtoms);
4544 }
4545 if (threadID == 0) {
4546 restrainDistanceTime = -System.nanoTime();
4547 }
4548 execute(0, nRestrainDistances - 1, restrainDistanceLoops[threadID]);
4549 if (threadID == 0) {
4550 restrainDistanceTime += System.nanoTime();
4551 }
4552 }
4553
4554
4555 if (restrainTorsionTerm && nRestrainTorsions > 0) {
4556 if (restrainTorsionLoops[threadID] == null) {
4557 restrainTorsionLoops[threadID] = new BondedTermLoop(restrainTorsions, sharedRestrainTorsionEnergy, null, checkAlchemicalAtoms);
4558 }
4559 if (threadID == 0) {
4560 restrainTorsionTime = -System.nanoTime();
4561 }
4562 execute(0, nRestrainTorsions - 1, restrainTorsionLoops[threadID]);
4563 if (threadID == 0) {
4564 restrainTorsionTime += System.nanoTime();
4565 }
4566 }
4567 }
4568
4569
4570 if (gradient) {
4571 if (gradReduceLoops[threadID] == null) {
4572 gradReduceLoops[threadID] = new GradReduceLoop();
4573 }
4574 execute(0, nAtoms - 1, gradReduceLoops[threadID]);
4575 }
4576 }
4577
4578 public void setGradient(boolean gradient) {
4579 this.gradient = gradient;
4580 }
4581
4582 @Override
4583 public void start() {
4584
4585 sharedAngleRMSD.set(0.0);
4586 sharedBondRMSD.set(0.0);
4587
4588
4589 sharedAngleEnergy.set(0.0);
4590 sharedBondEnergy.set(0.0);
4591 sharedImproperTorsionEnergy.set(0.0);
4592 sharedOutOfPlaneBendEnergy.set(0.0);
4593 sharedPiOrbitalTorsionEnergy.set(0.0);
4594 sharedStretchBendEnergy.set(0.0);
4595 sharedTorsionEnergy.set(0.0);
4596 sharedStretchTorsionEnergy.set(0.0);
4597 sharedAngleTorsionEnergy.set(0.0);
4598 sharedTorsionTorsionEnergy.set(0.0);
4599 sharedUreyBradleyEnergy.set(0.0);
4600
4601
4602 sharedRestrainPositionEnergy.set(0.0);
4603 sharedRestrainDistanceEnergy.set(0.0);
4604 sharedRestrainTorsionEnergy.set(0.0);
4605
4606
4607 if (gradient) {
4608 grad.alloc(nAtoms);
4609 }
4610 if (lambdaTerm) {
4611 lambdaGrad.alloc(nAtoms);
4612 }
4613 }
4614
4615 private class GradInitLoop extends IntegerForLoop {
4616
4617 @Override
4618 public void run(int first, int last) {
4619 int threadID = getThreadIndex();
4620 if (gradient) {
4621 grad.reset(threadID, first, last);
4622 for (int i = first; i <= last; i++) {
4623 atoms[i].setXYZGradient(0.0, 0.0, 0.0);
4624 }
4625 }
4626 if (lambdaTerm) {
4627 lambdaGrad.reset(threadID, first, last);
4628 for (int i = first; i <= last; i++) {
4629 atoms[i].setLambdaXYZGradient(0.0, 0.0, 0.0);
4630 }
4631 }
4632 }
4633
4634 @Override
4635 public IntegerSchedule schedule() {
4636 return IntegerSchedule.fixed();
4637 }
4638 }
4639
4640 private class GradReduceLoop extends IntegerForLoop {
4641
4642 @Override
4643 public void run(int first, int last) {
4644 if (gradient) {
4645 grad.reduce(first, last);
4646 for (int i = first; i <= last; i++) {
4647 Atom a = atoms[i];
4648 a.setXYZGradient(grad.getX(i), grad.getY(i), grad.getZ(i));
4649 }
4650 }
4651 if (lambdaTerm) {
4652 lambdaGrad.reduce(first, last);
4653 for (int i = first; i <= last; i++) {
4654 Atom a = atoms[i];
4655 a.setLambdaXYZGradient(lambdaGrad.getX(i), lambdaGrad.getY(i), lambdaGrad.getZ(i));
4656 }
4657 }
4658 }
4659
4660 @Override
4661 public IntegerSchedule schedule() {
4662 return IntegerSchedule.fixed();
4663 }
4664 }
4665
4666 private class BondedTermLoop extends IntegerForLoop {
4667
4668 private final BondedTerm[] terms;
4669 private final SharedDouble sharedEnergy;
4670 private final SharedDouble sharedRMSD;
4671 private final boolean checkAlchemicalAtoms;
4672 private final boolean computeRMSD;
4673 private double localEnergy;
4674 private double localRMSD;
4675 private int threadID;
4676
4677 BondedTermLoop(BondedTerm[] terms, SharedDouble sharedEnergy) {
4678 this(terms, sharedEnergy, null);
4679 }
4680
4681 BondedTermLoop(BondedTerm[] terms, SharedDouble sharedEnergy, SharedDouble sharedRMSD) {
4682 this(terms, sharedEnergy, sharedRMSD, true);
4683 }
4684
4685 BondedTermLoop(BondedTerm[] terms, SharedDouble sharedEnergy, SharedDouble sharedRMSD, boolean checkAlchemicalAtoms) {
4686 this.terms = terms;
4687 this.sharedEnergy = sharedEnergy;
4688 this.sharedRMSD = sharedRMSD;
4689 computeRMSD = (sharedRMSD != null);
4690 this.checkAlchemicalAtoms = checkAlchemicalAtoms;
4691 }
4692
4693 @Override
4694 public void finish() {
4695 sharedEnergy.addAndGet(localEnergy);
4696 if (computeRMSD) {
4697 sharedRMSD.addAndGet(localRMSD);
4698 }
4699 }
4700
4701 @Override
4702 public void run(int first, int last) {
4703 for (int i = first; i <= last; i++) {
4704 BondedTerm term = terms[i];
4705 boolean used = true;
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722 if (checkAlchemicalAtoms) {
4723 used = !lambdaBondedTerms || lambdaAllBondedTerms || (term.applyLambda() && !term.isLambdaScaled());
4724 }
4725 if (used) {
4726 localEnergy += term.energy(gradient, threadID, grad, lambdaGrad);
4727 if (computeRMSD) {
4728 double value = term.getValue();
4729 localRMSD += value * value;
4730 }
4731 }
4732 }
4733 }
4734
4735 @Override
4736 public void start() {
4737 localEnergy = 0.0;
4738 localRMSD = 0.0;
4739 threadID = getThreadIndex();
4740 }
4741 }
4742 }
4743 }