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.ParallelTeam;
41 import ffx.crystal.Crystal;
42 import ffx.crystal.CrystalPotential;
43 import ffx.crystal.LatticeSystem;
44 import ffx.crystal.NCSCrystal;
45 import ffx.crystal.ReplicatesCrystal;
46 import ffx.crystal.SpaceGroup;
47 import ffx.crystal.SpaceGroupDefinitions;
48 import ffx.crystal.SymOp;
49 import ffx.numerics.Constraint;
50 import ffx.numerics.math.Double3;
51 import ffx.numerics.switching.ConstantSwitch;
52 import ffx.numerics.switching.UnivariateFunctionFactory;
53 import ffx.numerics.switching.UnivariateSwitchingFunction;
54 import ffx.potential.bonded.Angle;
55 import ffx.potential.bonded.AngleTorsion;
56 import ffx.potential.bonded.Atom;
57 import ffx.potential.bonded.Bond;
58 import ffx.potential.bonded.ImproperTorsion;
59 import ffx.potential.bonded.LambdaInterface;
60 import ffx.potential.bonded.MSNode;
61 import ffx.potential.bonded.OutOfPlaneBend;
62 import ffx.potential.bonded.PiOrbitalTorsion;
63 import ffx.potential.bonded.RestrainDistance;
64 import ffx.potential.bonded.RestrainPosition;
65 import ffx.potential.bonded.StretchBend;
66 import ffx.potential.bonded.StretchTorsion;
67 import ffx.potential.bonded.Torsion;
68 import ffx.potential.bonded.TorsionTorsion;
69 import ffx.potential.bonded.UreyBradley;
70 import ffx.potential.constraint.CcmaConstraint;
71 import ffx.potential.constraint.SettleConstraint;
72 import ffx.potential.extended.ExtendedSystem;
73 import ffx.potential.nonbonded.COMRestraint;
74 import ffx.potential.nonbonded.GeneralizedKirkwood;
75 import ffx.potential.nonbonded.NCSRestraint;
76 import ffx.potential.nonbonded.ParticleMeshEwald;
77 import ffx.potential.nonbonded.RestrainGroups;
78 import ffx.potential.nonbonded.VanDerWaals;
79 import ffx.potential.nonbonded.VanDerWaalsTornado;
80 import ffx.potential.openmm.OpenMMEnergy;
81 import ffx.potential.parameters.AngleType.AngleMode;
82 import ffx.potential.parameters.BondType;
83 import ffx.potential.parameters.ForceField;
84 import ffx.potential.parameters.ForceField.ELEC_FORM;
85 import ffx.potential.parameters.TorsionType;
86 import ffx.potential.terms.AnglePotentialEnergy;
87 import ffx.potential.terms.AngleTorsionPotentialEnergy;
88 import ffx.potential.terms.BondPotentialEnergy;
89 import ffx.potential.terms.EnergyTermRegion;
90 import ffx.potential.terms.ImproperTorsionPotentialEnergy;
91 import ffx.potential.terms.OutOfPlaneBendPotentialEnergy;
92 import ffx.potential.terms.PiOrbitalTorsionPotentialEnergy;
93 import ffx.potential.terms.RestrainDistancePotentialEnergy;
94 import ffx.potential.terms.RestrainPositionPotentialEnergy;
95 import ffx.potential.terms.RestrainTorsionPotentialEnergy;
96 import ffx.potential.terms.StretchBendPotentialEnergy;
97 import ffx.potential.terms.StretchTorsionPotentialEnergy;
98 import ffx.potential.terms.TorsionPotentialEnergy;
99 import ffx.potential.terms.TorsionTorsionPotentialEnergy;
100 import ffx.potential.terms.UreyBradleyPotentialEnergy;
101 import ffx.potential.utils.ConvexHullOps;
102 import ffx.potential.utils.EnergyException;
103 import ffx.potential.utils.PotentialsFunctions;
104 import ffx.potential.utils.PotentialsUtils;
105 import ffx.utilities.FFXProperty;
106 import org.apache.commons.configuration2.CompositeConfiguration;
107
108 import javax.annotation.Nullable;
109 import java.io.File;
110 import java.time.LocalDateTime;
111 import java.time.format.DateTimeFormatter;
112 import java.util.ArrayList;
113 import java.util.Arrays;
114 import java.util.Collections;
115 import java.util.HashSet;
116 import java.util.List;
117 import java.util.Set;
118 import java.util.logging.Level;
119 import java.util.logging.Logger;
120 import java.util.stream.Collectors;
121 import java.util.stream.Stream;
122
123 import static ffx.potential.bonded.BondedTerm.removeNeuralNetworkTerms;
124 import static ffx.potential.bonded.RestrainPosition.parseRestrainPositions;
125 import static ffx.potential.nonbonded.VanDerWaalsForm.DEFAULT_VDW_CUTOFF;
126 import static ffx.potential.nonbonded.pme.EwaldParameters.DEFAULT_EWALD_CUTOFF;
127 import static ffx.potential.parameters.ForceField.toEnumForm;
128 import static ffx.potential.parsers.XYZFileFilter.isXYZ;
129 import static ffx.utilities.PropertyGroup.NonBondedCutoff;
130 import static ffx.utilities.PropertyGroup.PotentialFunctionSelection;
131 import static java.lang.Double.isInfinite;
132 import static java.lang.Double.isNaN;
133 import static java.lang.String.format;
134 import static org.apache.commons.io.FilenameUtils.removeExtension;
135 import static org.apache.commons.math3.util.FastMath.max;
136 import static org.apache.commons.math3.util.FastMath.min;
137 import static org.apache.commons.math3.util.FastMath.sqrt;
138
139
140
141
142
143
144
145 public class ForceFieldEnergy implements CrystalPotential, LambdaInterface {
146
147
148
149
150 private static final Logger logger = Logger.getLogger(ForceFieldEnergy.class.getName());
151
152
153
154
155 private static final double toSeconds = 1.0e-9;
156
157
158
159
160 public enum RestrainMode {
161
162
163
164 ENERGY,
165
166
167
168 ALCHEMICAL
169 }
170
171
172
173
174 private final Platform platform = Platform.FFX;
175
176
177
178
179 protected final MolecularAssembly molecularAssembly;
180
181
182
183 private final Atom[] atoms;
184
185
186
187 private Crystal crystal;
188
189
190
191 private final ParallelTeam parallelTeam;
192
193
194
195 private final NCSRestraint ncsRestraint;
196
197
198
199 private final COMRestraint comRestraint;
200
201
202
203 private final VanDerWaals vanderWaals;
204
205
206
207 private final ParticleMeshEwald particleMeshEwald;
208
209
210
211 private final ANIEnergy aniEnergy;
212
213
214
215
216 private final List<Constraint> constraints;
217
218
219
220 public static final double DEFAULT_CONSTRAINT_TOLERANCE = 1E-4;
221
222 @FFXProperty(name = "vdw-cutoff", propertyGroup = NonBondedCutoff, defaultValue = "12.0", description = """
223 Sets the cutoff distance value in Angstroms for van der Waals potential energy interactions.
224 The energy for any pair of van der Waals sites beyond the cutoff distance will be set to zero.
225 Other properties can be used to define the smoothing scheme near the cutoff distance.
226 The default cutoff distance in the absence of the vdw-cutoff keyword is infinite for nonperiodic
227 systems and 12.0 for periodic systems.
228 """)
229 private double vdwCutoff;
230
231 @FFXProperty(name = "ewald-cutoff", propertyGroup = NonBondedCutoff, defaultValue = "7.0", description = """
232 Sets the value in Angstroms of the real-space distance cutoff for use during Ewald summation.
233 By default, in the absence of the ewald-cutoff property, a value of 7.0 is used.
234 """)
235 private double ewaldCutoff;
236
237 @FFXProperty(name = "gk-cutoff", propertyGroup = NonBondedCutoff, defaultValue = "12.0", description = """
238 Sets the value in Angstroms of the generalized Kirkwood distance cutoff for use
239 during implicit solvent simulations. By default, in the absence of the gk-cutoff property,
240 no cutoff is used under aperiodic boundary conditions and the vdw-cutoff is used under PBC.
241 """)
242 private double gkCutoff;
243
244 private static final double DEFAULT_LIST_BUFFER = 2.0;
245
246 @FFXProperty(name = "list-buffer", propertyGroup = NonBondedCutoff, defaultValue = "2.0", description = """
247 Sets the size of the neighbor list buffer in Angstroms for potential energy functions.
248 This value is added to the actual cutoff distance to determine which pairs will be kept on the neighbor list.
249 This buffer value is used for all potential function neighbor lists.
250 The default value in the absence of the list-buffer keyword is 2.0 Angstroms.
251 """)
252 private double listBuffer;
253
254
255
256
257 private final double cutOff2;
258
259
260
261 private final double cutoffPlusBuffer;
262
263
264
265 private final ELEC_FORM elecForm;
266
267
268
269
270 @FFXProperty(name = "lambdaterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
271 defaultValue = "false", description = "Specifies use of the Lambda state variable.")
272 protected boolean lambdaTerm;
273
274
275
276 private double lambda = 1.0;
277
278
279
280 public boolean lambdaBondedTerms = false;
281
282
283
284 boolean lambdaAllBondedTerms = false;
285
286
287
288 private final boolean lambdaTorsions;
289
290
291
292
293
294 private STATE state = STATE.BOTH;
295
296
297
298 protected double[] optimizationScaling = null;
299
300
301
302
303 private final EnergyTermRegion forceFieldBondedEnergyRegion;
304
305
306
307 private final BondPotentialEnergy bondPotentialEnergy;
308
309
310
311 private final AnglePotentialEnergy anglePotentialEnergy;
312
313
314
315 private final StretchBendPotentialEnergy stretchBendPotentialEnergy;
316
317
318
319 private final UreyBradleyPotentialEnergy ureyBradleyPotentialEnergy;
320
321
322
323 private final OutOfPlaneBendPotentialEnergy outOfPlaneBendPotentialEnergy;
324
325
326
327 private final TorsionPotentialEnergy torsionPotentialEnergy;
328
329
330
331 private final StretchTorsionPotentialEnergy stretchTorsionPotentialEnergy;
332
333
334
335 private final AngleTorsionPotentialEnergy angleTorsionPotentialEnergy;
336
337
338
339 private final ImproperTorsionPotentialEnergy improperTorsionPotentialEnergy;
340
341
342
343 private final PiOrbitalTorsionPotentialEnergy piOrbitalTorsionPotentialEnergy;
344
345
346
347 private final TorsionTorsionPotentialEnergy torsionTorsionPotentialEnergy;
348
349
350
351
352 private final EnergyTermRegion restrainEnergyRegion;
353
354
355
356 private final RestrainMode restrainMode;
357
358
359
360 private final RestrainPositionPotentialEnergy restrainPositionPotentialEnergy;
361
362
363
364 private final RestrainDistancePotentialEnergy restrainDistancePotentialEnergy;
365
366
367
368 private final RestrainTorsionPotentialEnergy restrainTorsionPotentialEnergy;
369
370
371
372 private final RestrainGroups restrainGroups;
373
374
375
376
377 private final int nAtoms;
378
379
380
381 private int nRestrainGroups;
382
383
384
385 private int nVanDerWaalInteractions;
386
387
388
389 private int nPermanentInteractions;
390
391
392
393 private int nGKInteractions;
394
395
396
397
398 private boolean nnTerm;
399
400
401
402
403 @FFXProperty(name = "bondterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
404 defaultValue = "true", description = "Specifies use of the bond stretch potential.")
405 private final boolean bondTerm;
406
407
408
409
410 @FFXProperty(name = "angleterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
411 defaultValue = "true", description = "Specifies use of the angle bend potential.")
412 private final boolean angleTerm;
413
414
415
416
417 @FFXProperty(name = "strbndterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
418 defaultValue = "true", description = "Specifies use of the stretch-bend potential.")
419 private final boolean stretchBendTerm;
420
421
422
423
424 @FFXProperty(name = "ureyterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
425 defaultValue = "true", description = "Specifies use of the Urey-Bradley potential.")
426 private final boolean ureyBradleyTerm;
427
428
429
430
431 @FFXProperty(name = "opbendterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
432 defaultValue = "true", description = "Specifies use of the out-of-plane potential.")
433 private final boolean outOfPlaneBendTerm;
434
435
436
437
438 @FFXProperty(name = "torsionterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
439 defaultValue = "true", description = "Specifies use of the torsional potential.")
440 private final boolean torsionTerm;
441
442
443
444
445 @FFXProperty(name = "strtorterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
446 defaultValue = "true", description = "Specifies use of the stretch-torsion potential.")
447 private final boolean stretchTorsionTerm;
448
449
450
451
452 @FFXProperty(name = "angtorterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
453 defaultValue = "true", description = "Specifies use of the angle-torsion potential.")
454 private final boolean angleTorsionTerm;
455
456
457
458
459 @FFXProperty(name = "imptorterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
460 defaultValue = "true", description = "Specifies use of the improper torsion potential.")
461 private final boolean improperTorsionTerm;
462
463
464
465
466 @FFXProperty(name = "pitorsterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
467 defaultValue = "true", description = "Specifies use of the pi-system torsion potential.")
468 private final boolean piOrbitalTorsionTerm;
469
470
471
472
473 @FFXProperty(name = "tortorterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
474 defaultValue = "true", description = "Specifies use of the pi-system torsion potential.")
475 private final boolean torsionTorsionTerm;
476
477
478
479
480 private final boolean restrainPositionTerm;
481
482
483
484 private final boolean restrainDistanceTerm;
485
486
487
488 private final boolean restrainTorsionTerm;
489
490
491
492 private boolean restrainGroupTerm;
493
494
495
496
497 @FFXProperty(name = "vdwterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
498 defaultValue = "true", description = """
499 Specifies use of the vdw der Waals potential.
500 If set to false, all non-bonded terms are turned off.
501 """)
502 private boolean vanderWaalsTerm;
503
504
505
506
507 @FFXProperty(name = "mpoleterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
508 defaultValue = "true", description = """
509 Specifies use of the fixed charge electrostatic potential.
510 Setting mpoleterm to false also turns off polarization and generalized Kirkwood,
511 overriding the polarizeterm and gkterm properties.
512 """)
513 private boolean multipoleTerm;
514
515
516
517
518 @FFXProperty(name = "polarizeterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
519 defaultValue = "true", description = """
520 Specifies use of the polarizable electrostatic potential.
521 Setting polarizeterm to false overrides the polarization property.
522 """)
523 private boolean polarizationTerm;
524
525
526
527
528 @FFXProperty(name = "gkterm", clazz = Boolean.class, propertyGroup = PotentialFunctionSelection,
529 defaultValue = "false", description = "Specifies use of generalized Kirkwood electrostatics.")
530 private boolean generalizedKirkwoodTerm;
531
532
533
534
535 private boolean comTerm;
536
537
538
539 private boolean ncsTerm;
540
541
542
543
544 private final boolean nnTermOrig;
545
546
547
548 private final boolean restrainGroupTermOrig;
549
550
551
552 private final boolean vanderWaalsTermOrig;
553
554
555
556 private final boolean multipoleTermOrig;
557
558
559
560 private final boolean polarizationTermOrig;
561
562
563
564 private final boolean generalizedKirkwoodTermOrig;
565
566
567
568 private boolean esvTermOrig;
569
570
571
572 private boolean ncsTermOrig;
573
574
575
576 private boolean comTermOrig;
577
578
579
580
581 private double nnEnergy;
582
583
584
585 private double restrainGroupEnergy;
586
587
588
589 private double vanDerWaalsEnergy;
590
591
592
593 private double permanentMultipoleEnergy;
594
595
596
597 private double polarizationEnergy;
598
599
600
601 private double solvationEnergy;
602
603
604
605 private double ncsEnergy;
606
607
608
609 private double comRestraintEnergy;
610
611
612
613 private double totalEnergy;
614
615
616
617
618 private long ncsTime;
619
620
621
622 private long nnTime;
623
624
625
626 private long restrainGroupTime;
627
628
629
630 private long comRestraintTime;
631
632
633
634 private long vanDerWaalsTime;
635
636
637
638 private long electrostaticTime;
639
640
641
642 private long totalTime;
643
644
645
646
647 private ExtendedSystem esvSystem = null;
648 private boolean esvTerm;
649 private double esvBias;
650
651
652
653
654 boolean destroyed = false;
655
656
657
658
659 public final double maxDebugGradient;
660
661
662
663 private boolean printOnFailure;
664
665
666
667
668
669
670 protected ForceFieldEnergy(MolecularAssembly molecularAssembly) {
671 this(molecularAssembly, ParallelTeam.getDefaultThreadCount());
672 }
673
674
675
676
677
678
679
680 protected ForceFieldEnergy(MolecularAssembly molecularAssembly, int numThreads) {
681
682 this.molecularAssembly = molecularAssembly;
683 atoms = molecularAssembly.getAtomArray();
684 nAtoms = atoms.length;
685
686
687 for (int i = 0; i < nAtoms; i++) {
688 int index = atoms[i].getXyzIndex() - 1;
689 assert (i == index);
690 }
691
692
693 int nThreads = min(nAtoms, numThreads);
694 parallelTeam = new ParallelTeam(nThreads);
695
696 ForceField forceField = molecularAssembly.getForceField();
697 CompositeConfiguration properties = forceField.getProperties();
698 String name = forceField.toString().toUpperCase();
699
700 logger.info(format(" Constructing Force Field %s", name));
701 logger.info(format("\n SMP threads: %10d", nThreads));
702
703
704 boolean standardizeAtomNames = properties.getBoolean("standardizeAtomNames", true);
705 if (standardizeAtomNames) {
706 molecularAssembly.renameWaterProtons();
707 }
708
709 nnTerm = forceField.getBoolean("NNTERM", false);
710
711 if (nnTerm) {
712 for (Atom atom : atoms) {
713 atom.setNeuralNetwork(true);
714 }
715 }
716 bondTerm = forceField.getBoolean("BONDTERM", true);
717 angleTerm = forceField.getBoolean("ANGLETERM", true);
718 stretchBendTerm = forceField.getBoolean("STRBNDTERM", true);
719 ureyBradleyTerm = forceField.getBoolean("UREYTERM", true);
720 outOfPlaneBendTerm = forceField.getBoolean("OPBENDTERM", true);
721 torsionTerm = forceField.getBoolean("TORSIONTERM", true);
722 stretchTorsionTerm = forceField.getBoolean("STRTORTERM", true);
723 angleTorsionTerm = forceField.getBoolean("ANGTORTERM", true);
724 piOrbitalTorsionTerm = forceField.getBoolean("PITORSTERM", true);
725 torsionTorsionTerm = forceField.getBoolean("TORTORTERM", true);
726 improperTorsionTerm = forceField.getBoolean("IMPROPERTERM", true);
727 vanderWaalsTerm = forceField.getBoolean("VDWTERM", true);
728
729 boolean tornadoVM = forceField.getBoolean("tornado", false);
730 if (vanderWaalsTerm && !tornadoVM) {
731 multipoleTerm = forceField.getBoolean("MPOLETERM", true);
732 if (multipoleTerm) {
733 String polarizeString = forceField.getString("POLARIZATION", "NONE");
734 boolean defaultPolarizeTerm = !polarizeString.equalsIgnoreCase("NONE");
735 polarizationTerm = forceField.getBoolean("POLARIZETERM", defaultPolarizeTerm);
736 generalizedKirkwoodTerm = forceField.getBoolean("GKTERM", false);
737 } else {
738
739 polarizationTerm = false;
740 generalizedKirkwoodTerm = false;
741 }
742 } else {
743
744 multipoleTerm = false;
745 polarizationTerm = false;
746 generalizedKirkwoodTerm = false;
747 }
748
749 lambdaTerm = forceField.getBoolean("LAMBDATERM", false);
750 comTerm = forceField.getBoolean("COMRESTRAINTERM", false);
751 lambdaTorsions = forceField.getBoolean("TORSION_LAMBDATERM", false);
752 printOnFailure = forceField.getBoolean("PRINT_ON_FAILURE", false);
753
754 String mode = forceField.getString("RESTRAIN_MODE", "ENERGY");
755 if (mode.equalsIgnoreCase("ALCHEMICAL")) {
756 restrainMode = RestrainMode.ALCHEMICAL;
757 } else {
758 restrainMode = RestrainMode.ENERGY;
759 }
760
761
762 if (properties.containsKey("restrain-groups")) {
763 restrainGroupTerm = true;
764 } else {
765 restrainGroupTerm = false;
766 }
767
768
769 nnTermOrig = nnTerm;
770 restrainGroupTermOrig = restrainGroupTerm;
771 vanderWaalsTermOrig = vanderWaalsTerm;
772 multipoleTermOrig = multipoleTerm;
773 polarizationTermOrig = polarizationTerm;
774 generalizedKirkwoodTermOrig = generalizedKirkwoodTerm;
775 ncsTermOrig = ncsTerm;
776 comTermOrig = comTerm;
777
778
779 String spacegroup;
780 double a, b, c, alpha, beta, gamma;
781 boolean aperiodic;
782 try {
783 spacegroup = forceField.getString("SPACEGROUP", "P 1");
784 SpaceGroup sg = SpaceGroupDefinitions.spaceGroupFactory(spacegroup);
785 LatticeSystem latticeSystem = sg.latticeSystem;
786 a = forceField.getDouble("A_AXIS");
787 aperiodic = false;
788 b = forceField.getDouble("B_AXIS", latticeSystem.getDefaultBAxis(a));
789 c = forceField.getDouble("C_AXIS", latticeSystem.getDefaultCAxis(a, b));
790 alpha = forceField.getDouble("ALPHA", latticeSystem.getDefaultAlpha());
791 beta = forceField.getDouble("BETA", latticeSystem.getDefaultBeta());
792 gamma = forceField.getDouble("GAMMA", latticeSystem.getDefaultGamma());
793 if (!sg.latticeSystem.validParameters(a, b, c, alpha, beta, gamma)) {
794 logger.severe(" Check lattice parameters.");
795 }
796 if (a == 1.0 && b == 1.0 && c == 1.0) {
797 String message = " A-, B-, and C-axis values equal to 1.0.";
798 logger.info(message);
799 throw new Exception(message);
800 }
801 if (a <= 0.0 || b <= 0.0 || c <= 0.0 || alpha <= 0.0 || beta <= 0.0 || gamma <= 0.0) {
802
803 String message = " Crystal parameters are not valid due to negative or zero value.";
804 logger.warning(message);
805 throw new Exception(message);
806 }
807 } catch (Exception e) {
808 aperiodic = true;
809
810
811 double maxR = 0.0;
812 if (nAtoms < 10) {
813 for (int i = 0; i < nAtoms - 1; i++) {
814 Double3 xi = atoms[i].getXYZ();
815 for (int j = 1; j < nAtoms; j++) {
816 double r = atoms[j].getXYZ().dist(xi);
817 maxR = max(r, maxR);
818 }
819 }
820 } else {
821 try {
822 maxR = ConvexHullOps.maxDist(ConvexHullOps.constructHull(atoms));
823 } catch (Exception ex) {
824
825 logger.info(" Convex Hull operation failed with message " + ex + "\n Trying brute force approach...");
826 if (logger.isLoggable(Level.FINE)) {
827 logger.fine(Utilities.stackTraceToString(ex));
828 }
829 for (int i = 0; i < nAtoms - 1; i++) {
830 Double3 xi = atoms[i].getXYZ();
831 for (int j = 1; j < nAtoms; j++) {
832 double r = atoms[j].getXYZ().dist(xi);
833 maxR = max(r, maxR);
834 }
835 }
836 }
837 }
838 maxR = max(10.0, maxR);
839
840 logger.info(format(" The system will be treated as aperiodic (max separation = %6.1f A).", maxR));
841
842
843 forceField.addProperty("EWALD_ALPHA", "0.0");
844
845
846 spacegroup = "P1";
847 a = 2.0 * maxR;
848 b = 2.0 * maxR;
849 c = 2.0 * maxR;
850 alpha = 90.0;
851 beta = 90.0;
852 gamma = 90.0;
853 }
854 Crystal unitCell = new Crystal(a, b, c, alpha, beta, gamma, spacegroup);
855 unitCell.setAperiodic(aperiodic);
856
857
858 vdwCutoff = DEFAULT_VDW_CUTOFF;
859 ewaldCutoff = DEFAULT_EWALD_CUTOFF;
860 gkCutoff = vdwCutoff;
861 if (unitCell.aperiodic()) {
862
863 vdwCutoff = Double.POSITIVE_INFINITY;
864 ewaldCutoff = Double.POSITIVE_INFINITY;
865 gkCutoff = Double.POSITIVE_INFINITY;
866 }
867
868 vdwCutoff = forceField.getDouble("VDW_CUTOFF", vdwCutoff);
869 ewaldCutoff = forceField.getDouble("EWALD_CUTOFF", ewaldCutoff);
870 gkCutoff = forceField.getDouble("GK_CUTOFF", gkCutoff);
871
872
873 double nlistCutoff = vdwCutoff;
874 if (multipoleTerm) {
875 nlistCutoff = max(vdwCutoff, ewaldCutoff);
876 }
877 if (generalizedKirkwoodTerm) {
878 nlistCutoff = max(nlistCutoff, gkCutoff);
879 }
880
881
882 boolean disabledNeighborUpdates = forceField.getBoolean("DISABLE_NEIGHBOR_UPDATES", false);
883 if (disabledNeighborUpdates) {
884 logger.info(format(" Neighbor list updates disabled; interactions will "
885 + "only be calculated between atoms that started the simulation "
886 + "within a radius of %9.3g Angstroms of each other.", nlistCutoff));
887
888 vdwCutoff = Double.POSITIVE_INFINITY;
889 ewaldCutoff = Double.POSITIVE_INFINITY;
890 gkCutoff = Double.POSITIVE_INFINITY;
891 }
892
893 listBuffer = forceField.getDouble("LIST_BUFFER", DEFAULT_LIST_BUFFER);
894 cutoffPlusBuffer = nlistCutoff + listBuffer;
895 cutOff2 = 2.0 * cutoffPlusBuffer;
896 unitCell = configureNCS(forceField, unitCell);
897
898
899 if (!aperiodic) {
900 this.crystal = ReplicatesCrystal.replicatesCrystalFactory(unitCell, cutOff2);
901 logger.info(format("\n Density: %6.3f (g/cc)",
902 crystal.getDensity(molecularAssembly.getMass())));
903 logger.info(crystal.toString());
904 } else {
905 this.crystal = unitCell;
906 }
907
908 if (!unitCell.aperiodic() && unitCell.spaceGroup.number == 1) {
909 ncsTerm = forceField.getBoolean("NCSTERM", false);
910 ncsTermOrig = ncsTerm;
911 } else {
912 ncsTerm = false;
913 ncsTermOrig = false;
914 }
915
916
917 int nSpecial = checkForSpecialPositions(forceField);
918
919
920 boolean rigidHydrogens = forceField.getBoolean("RIGID_HYDROGENS", false);
921
922 double rigidScale = forceField.getDouble("RIGID_SCALE", 10.0);
923
924 boolean checkAllNodeCharges = forceField.getBoolean("CHECK_ALL_NODE_CHARGES", false);
925
926 if (rigidScale <= 1.0) {
927 rigidScale = 1.0;
928 }
929
930 logger.info("\n Bonded Terms");
931 if (rigidHydrogens && rigidScale > 1.0) {
932 logger.info(format(" Rigid hydrogens: %10.2f", rigidScale));
933 }
934
935 forceFieldBondedEnergyRegion = new EnergyTermRegion(parallelTeam, molecularAssembly, lambdaTerm);
936 restrainEnergyRegion = new EnergyTermRegion(parallelTeam, molecularAssembly, lambdaTerm);
937
938
939 if (bondTerm) {
940 List<Bond> bondList = molecularAssembly.getBondList();
941 if (nnTerm) {
942 removeNeuralNetworkTerms(bondList);
943 }
944 if (!bondList.isEmpty()) {
945 int forceGroup = forceField.getInteger("BOND_FORCE_GROUP", 0);
946 bondPotentialEnergy = new BondPotentialEnergy("Bonds", forceGroup, bondList);
947 forceFieldBondedEnergyRegion.addEnergyTerm(bondPotentialEnergy);
948 } else {
949 bondPotentialEnergy = null;
950 }
951 } else {
952 bondPotentialEnergy = null;
953 }
954
955
956 if (angleTerm) {
957 List<Angle> angleList = molecularAssembly.getAngleList();
958 if (nnTerm) {
959 removeNeuralNetworkTerms(angleList);
960 }
961 if (!angleList.isEmpty()) {
962 int forceGroup = forceField.getInteger("ANGLE_FORCE_GROUP", 0);
963 anglePotentialEnergy = new AnglePotentialEnergy("Angles", forceGroup, angleList);
964 forceFieldBondedEnergyRegion.addEnergyTerm(anglePotentialEnergy);
965 } else {
966 anglePotentialEnergy = null;
967 }
968 } else {
969 anglePotentialEnergy = null;
970 }
971
972
973 if (stretchBendTerm) {
974 List<StretchBend> stretchBendList = molecularAssembly.getStretchBendList();
975 if (nnTerm) {
976 removeNeuralNetworkTerms(stretchBendList);
977 }
978 if (!stretchBendList.isEmpty()) {
979 int forceGroup = forceField.getInteger("STRETCH_BEND_FORCE_GROUP", 0);
980 stretchBendPotentialEnergy = new StretchBendPotentialEnergy("Stretch-Bends", forceGroup, stretchBendList);
981 forceFieldBondedEnergyRegion.addEnergyTerm(stretchBendPotentialEnergy);
982 } else {
983 stretchBendPotentialEnergy = null;
984 }
985 } else {
986 stretchBendPotentialEnergy = null;
987 }
988
989
990 if (ureyBradleyTerm) {
991 List<UreyBradley> ureyBradleyList = molecularAssembly.getUreyBradleyList();
992 if (nnTerm) {
993 removeNeuralNetworkTerms(ureyBradleyList);
994 }
995 if (!ureyBradleyList.isEmpty()) {
996 int forceGroup = forceField.getInteger("UREY_BRADLEY_FORCE_GROUP", 0);
997 ureyBradleyPotentialEnergy = new UreyBradleyPotentialEnergy("Urey-Bradleys", forceGroup, ureyBradleyList);
998 forceFieldBondedEnergyRegion.addEnergyTerm(ureyBradleyPotentialEnergy);
999 } else {
1000 ureyBradleyPotentialEnergy = null;
1001 }
1002 } else {
1003 ureyBradleyPotentialEnergy = null;
1004 }
1005
1006
1007 if (rigidHydrogens) {
1008 if (bondPotentialEnergy != null) {
1009 for (Bond bond : bondPotentialEnergy.getBonds()) {
1010 if (bond.containsHydrogen()) {
1011 bond.setRigidScale(rigidScale);
1012 }
1013 }
1014 }
1015 if (anglePotentialEnergy != null) {
1016 for (Angle angle : anglePotentialEnergy.getAngles()) {
1017 if (angle.containsHydrogen()) {
1018 angle.setRigidScale(rigidScale);
1019 }
1020 }
1021 }
1022 if (stretchBendPotentialEnergy != null) {
1023 for (StretchBend stretchBend : stretchBendPotentialEnergy.getStretchBends()) {
1024 if (stretchBend.containsHydrogen()) {
1025 stretchBend.setRigidScale(rigidScale);
1026 }
1027 }
1028 }
1029 if (ureyBradleyPotentialEnergy != null) {
1030 for (UreyBradley ureyBradley : ureyBradleyPotentialEnergy.getUreyBradleys()) {
1031 if (ureyBradley.containsHydrogen()) {
1032 ureyBradley.setRigidScale(rigidScale);
1033 }
1034 }
1035 }
1036 }
1037
1038
1039 if (outOfPlaneBendTerm) {
1040 List<OutOfPlaneBend> outOfPlaneBendList = molecularAssembly.getOutOfPlaneBendList();
1041 if (nnTerm) {
1042 removeNeuralNetworkTerms(outOfPlaneBendList);
1043 }
1044 if (!outOfPlaneBendList.isEmpty()) {
1045 int forceGroup = forceField.getInteger("OUT_OF_PLANE_BEND_FORCE_GROUP", 0);
1046 outOfPlaneBendPotentialEnergy = new OutOfPlaneBendPotentialEnergy("Out-0f-Plane Bends", forceGroup, outOfPlaneBendList);
1047 forceFieldBondedEnergyRegion.addEnergyTerm(outOfPlaneBendPotentialEnergy);
1048 } else {
1049 outOfPlaneBendPotentialEnergy = null;
1050 }
1051 } else {
1052 outOfPlaneBendPotentialEnergy = null;
1053 }
1054
1055
1056 if (torsionTerm) {
1057 List<Torsion> torsionList = molecularAssembly.getTorsionList();
1058 if (nnTerm) {
1059 removeNeuralNetworkTerms(torsionList);
1060 }
1061 if (!torsionList.isEmpty()) {
1062 int forceGroup = forceField.getInteger("TORSION_FORCE_GROUP", 0);
1063 torsionPotentialEnergy = new TorsionPotentialEnergy("Torsions", forceGroup, torsionList);
1064 forceFieldBondedEnergyRegion.addEnergyTerm(torsionPotentialEnergy);
1065 } else
1066 torsionPotentialEnergy = null;
1067 } else {
1068 torsionPotentialEnergy = null;
1069 }
1070
1071
1072 if (stretchTorsionTerm) {
1073 List<StretchTorsion> stretchTorsionList = molecularAssembly.getStretchTorsionList();
1074 if (nnTerm) {
1075 removeNeuralNetworkTerms(stretchTorsionList);
1076 }
1077 if (!stretchTorsionList.isEmpty()) {
1078 int forceGroup = forceField.getInteger("STRETCH_TORSION_FORCE_GROUP", 0);
1079 stretchTorsionPotentialEnergy = new StretchTorsionPotentialEnergy("Stretch-Torsions", forceGroup, stretchTorsionList);
1080 forceFieldBondedEnergyRegion.addEnergyTerm(stretchTorsionPotentialEnergy);
1081 } else {
1082 stretchTorsionPotentialEnergy = null;
1083 }
1084 } else {
1085 stretchTorsionPotentialEnergy = null;
1086 }
1087
1088
1089 if (angleTorsionTerm) {
1090 List<AngleTorsion> angleTorsionList = molecularAssembly.getAngleTorsionList();
1091 if (nnTerm) {
1092 removeNeuralNetworkTerms(angleTorsionList);
1093 }
1094 if (!angleTorsionList.isEmpty()) {
1095 int forceGroup = forceField.getInteger("ANGLE_TORSION_FORCE_GROUP", 0);
1096 angleTorsionPotentialEnergy = new AngleTorsionPotentialEnergy("Angle-Torsions", forceGroup, angleTorsionList);
1097 forceFieldBondedEnergyRegion.addEnergyTerm(angleTorsionPotentialEnergy);
1098 } else {
1099 angleTorsionPotentialEnergy = null;
1100 }
1101 } else {
1102 angleTorsionPotentialEnergy = null;
1103 }
1104
1105
1106 if (improperTorsionTerm) {
1107 List<ImproperTorsion> improperTorsionList = molecularAssembly.getImproperTorsionList();
1108 if (nnTerm) {
1109 removeNeuralNetworkTerms(improperTorsionList);
1110 }
1111 if (!improperTorsionList.isEmpty()) {
1112 int forceGroup = forceField.getInteger("IMPROPER_TORSION_FORCE_GROUP", 0);
1113 improperTorsionPotentialEnergy = new ImproperTorsionPotentialEnergy("Improper Torsions", forceGroup, improperTorsionList);
1114 forceFieldBondedEnergyRegion.addEnergyTerm(improperTorsionPotentialEnergy);
1115 } else {
1116 improperTorsionPotentialEnergy = null;
1117 }
1118 } else {
1119 improperTorsionPotentialEnergy = null;
1120 }
1121
1122
1123 if (piOrbitalTorsionTerm) {
1124 List<PiOrbitalTorsion> piOrbitalTorsionList = molecularAssembly.getPiOrbitalTorsionList();
1125 if (nnTerm) {
1126 removeNeuralNetworkTerms(piOrbitalTorsionList);
1127 }
1128 if (!piOrbitalTorsionList.isEmpty()) {
1129 int forceGroup = forceField.getInteger("PI_ORBITAL_TORSION_FORCE_GROUP", 0);
1130 piOrbitalTorsionPotentialEnergy = new PiOrbitalTorsionPotentialEnergy("Pi-Orbital Torsions", forceGroup, piOrbitalTorsionList);
1131 forceFieldBondedEnergyRegion.addEnergyTerm(piOrbitalTorsionPotentialEnergy);
1132 } else {
1133 piOrbitalTorsionPotentialEnergy = null;
1134 }
1135 } else {
1136 piOrbitalTorsionPotentialEnergy = null;
1137 }
1138
1139
1140 if (torsionTorsionTerm) {
1141 List<TorsionTorsion> torsionTorsionList = molecularAssembly.getTorsionTorsionList();
1142 if (nnTerm) {
1143 removeNeuralNetworkTerms(torsionTorsionList);
1144 }
1145 if (!torsionTorsionList.isEmpty()) {
1146 int forceGroup = forceField.getInteger("TORSION_TORSION_FORCE_GROUP", 0);
1147 torsionTorsionPotentialEnergy = new TorsionTorsionPotentialEnergy("Torsion-Torsions", forceGroup, torsionTorsionList);
1148 forceFieldBondedEnergyRegion.addEnergyTerm(torsionTorsionPotentialEnergy);
1149 } else {
1150 torsionTorsionPotentialEnergy = null;
1151 }
1152 } else {
1153 torsionTorsionPotentialEnergy = null;
1154 }
1155
1156
1157 RestrainPosition[] restrainPositions = parseRestrainPositions(molecularAssembly);
1158 if (restrainPositions != null && restrainPositions.length > 0) {
1159 restrainPositionTerm = true;
1160 } else {
1161 restrainPositionTerm = false;
1162 }
1163 if (restrainPositionTerm) {
1164 int forceGroup = forceField.getInteger("RESTRAIN_POSITION_FORCE_GROUP", 0);
1165 restrainPositionPotentialEnergy = new RestrainPositionPotentialEnergy("Restrain Positions", forceGroup, java.util.Arrays.asList(restrainPositions));
1166 restrainEnergyRegion.addEnergyTerm(restrainPositionPotentialEnergy);
1167 } else {
1168 restrainPositionPotentialEnergy = null;
1169 }
1170
1171
1172 RestrainDistance[] restrainDistances = configureRestrainDistances(properties);
1173 if (restrainDistances != null && restrainDistances.length > 0) {
1174 restrainDistanceTerm = true;
1175 } else {
1176 restrainDistanceTerm = false;
1177 }
1178 if (restrainDistanceTerm) {
1179 int forceGroup = forceField.getInteger("RESTRAIN_DISTANCE_FORCE_GROUP", 0);
1180 restrainDistancePotentialEnergy = new RestrainDistancePotentialEnergy("Restrain Distances", forceGroup, java.util.Arrays.asList(restrainDistances));
1181 restrainEnergyRegion.addEnergyTerm(restrainDistancePotentialEnergy);
1182 } else {
1183 restrainDistancePotentialEnergy = null;
1184 }
1185
1186
1187 Torsion[] restrainTorsions = configureRestrainTorsions(properties, forceField);
1188 if (restrainTorsions != null && restrainTorsions.length > 0) {
1189 restrainTorsionTerm = true;
1190 } else {
1191 restrainTorsionTerm = false;
1192 }
1193 if (restrainTorsionTerm) {
1194 logger.info(" Restrain Torsion Mode: " + restrainMode);
1195 int forceGroup = forceField.getInteger("RESTRAIN_TORSION_FORCE_GROUP", 0);
1196 restrainTorsionPotentialEnergy = new RestrainTorsionPotentialEnergy("Restrain Torsions", forceGroup, java.util.Arrays.asList(restrainTorsions));
1197 restrainEnergyRegion.addEnergyTerm(restrainTorsionPotentialEnergy);
1198 } else {
1199 restrainTorsionPotentialEnergy = null;
1200 }
1201
1202 int[] molecule = molecularAssembly.getMoleculeNumbers();
1203 if (vanderWaalsTerm) {
1204 logger.info("\n Non-Bonded Terms");
1205 boolean[] nn = null;
1206 if (nnTerm) {
1207 nn = molecularAssembly.getNeuralNetworkIdentity();
1208 } else {
1209 nn = new boolean[nAtoms];
1210 Arrays.fill(nn, false);
1211 }
1212
1213 if (!tornadoVM) {
1214 vanderWaals = new VanDerWaals(atoms, molecule, nn, crystal, forceField, parallelTeam,
1215 vdwCutoff, nlistCutoff);
1216 } else {
1217 vanderWaals = new VanDerWaalsTornado(atoms, crystal, forceField, vdwCutoff);
1218 }
1219 } else {
1220 vanderWaals = null;
1221 }
1222
1223 if (nnTerm) {
1224 aniEnergy = new ANIEnergy(molecularAssembly);
1225 } else {
1226 aniEnergy = null;
1227 }
1228
1229 if (multipoleTerm) {
1230 if (name.contains("OPLS") || name.contains("AMBER") || name.contains("CHARMM")) {
1231 elecForm = ELEC_FORM.FIXED_CHARGE;
1232 } else {
1233 elecForm = ELEC_FORM.PAM;
1234 }
1235 particleMeshEwald = new ParticleMeshEwald(atoms, molecule, forceField, crystal,
1236 vanderWaals.getNeighborList(), elecForm, ewaldCutoff, gkCutoff, parallelTeam);
1237 double charge = molecularAssembly.getCharge(checkAllNodeCharges);
1238 logger.info(format("\n Overall system charge: %10.3f", charge));
1239 } else {
1240 elecForm = null;
1241 particleMeshEwald = null;
1242 }
1243
1244 if (ncsTerm) {
1245 String sg = forceField.getString("NCSGROUP", "P 1");
1246 Crystal ncsCrystal = new Crystal(a, b, c, alpha, beta, gamma, sg);
1247 ncsRestraint = new NCSRestraint(atoms, forceField, ncsCrystal);
1248 } else {
1249 ncsRestraint = null;
1250 }
1251
1252 if (restrainGroupTerm) {
1253 restrainGroups = new RestrainGroups(molecularAssembly);
1254 nRestrainGroups = restrainGroups.getNumberOfRestraints();
1255 } else {
1256 restrainGroups = null;
1257 }
1258
1259 if (comTerm) {
1260 comRestraint = new COMRestraint(molecularAssembly);
1261 } else {
1262 comRestraint = null;
1263 }
1264
1265
1266 maxDebugGradient = forceField.getDouble("MAX_DEBUG_GRADIENT", Double.POSITIVE_INFINITY);
1267
1268 molecularAssembly.setPotential(this);
1269
1270
1271 constraints = configureConstraints(forceField);
1272
1273 if (lambdaTerm) {
1274 this.setLambda(1.0);
1275 if (nSpecial == 0) {
1276
1277
1278 crystal.setSpecialPositionCutoff(0.0);
1279 } else {
1280
1281 logger.info(" Special positions checking will be performed during a lambda simulation.");
1282 }
1283 }
1284 }
1285
1286
1287
1288
1289
1290
1291 public MolecularAssembly getMolecularAssembly() {
1292 return molecularAssembly;
1293 }
1294
1295
1296
1297
1298
1299
1300 public void setLambdaTerm(boolean lambdaTerm) {
1301 this.lambdaTerm = lambdaTerm;
1302 }
1303
1304
1305
1306
1307
1308
1309 public boolean getLambdaTerm() {
1310 return lambdaTerm;
1311 }
1312
1313 private int checkForSpecialPositions(ForceField forceField) {
1314
1315 boolean specialPositionsInactive = forceField.getBoolean("SPECIAL_POSITIONS_INACTIVE", true);
1316 int nSpecial = 0;
1317 if (specialPositionsInactive) {
1318 int nSymm = crystal.getNumSymOps();
1319 if (nSymm > 1) {
1320 SpaceGroup spaceGroup = crystal.spaceGroup;
1321 double sp2 = crystal.getSpecialPositionCutoff2();
1322 double[] mate = new double[3];
1323 StringBuilder sb = new StringBuilder("\n Atoms at Special Positions set to Inactive:\n");
1324 for (int i = 0; i < nAtoms; i++) {
1325 Atom atom = atoms[i];
1326 double[] xyz = atom.getXYZ(null);
1327 for (int iSymm = 1; iSymm < nSymm; iSymm++) {
1328 SymOp symOp = spaceGroup.getSymOp(iSymm);
1329 crystal.applySymOp(xyz, mate, symOp);
1330 double dr2 = crystal.image(xyz, mate);
1331 if (dr2 < sp2) {
1332 sb.append(
1333 format(" %s separation with SymOp %d at %8.6f A.\n", atoms[i], iSymm, sqrt(dr2)));
1334 atom.setActive(false);
1335 nSpecial++;
1336 break;
1337 }
1338 }
1339 }
1340 if (nSpecial > 0) {
1341 logger.info(sb.toString());
1342 }
1343 }
1344 }
1345 return nSpecial;
1346 }
1347
1348
1349
1350
1351
1352
1353
1354
1355 private Torsion[] configureRestrainTorsions(CompositeConfiguration properties, ForceField forceField) {
1356 StringBuilder restrainLog = new StringBuilder("\n Restrain-Torsions");
1357
1358 String[] restrainTorsions = properties.getStringArray("restrain-torsion");
1359 double torsionUnits = forceField.getDouble("TORSIONUNIT", TorsionType.DEFAULT_TORSION_UNIT);
1360 List<Torsion> restrainTorsionList = new ArrayList<>(restrainTorsions.length);
1361 for (String restrainString : restrainTorsions) {
1362
1363 restrainString = "restrain-torsion " + restrainString;
1364
1365 String input = restrainString.split("#+")[0];
1366
1367 String[] tokens = input.trim().split(" +");
1368
1369
1370 TorsionType torsionType = TorsionType.parse(input, tokens);
1371 torsionType.torsionUnit = torsionUnits;
1372
1373
1374 int[] atomIndices = torsionType.atomClasses;
1375 int ai1 = atomIndices[0] - 1;
1376 int ai2 = atomIndices[1] - 1;
1377 int ai3 = atomIndices[2] - 1;
1378 int ai4 = atomIndices[3] - 1;
1379 Atom a1 = atoms[ai1];
1380 Atom a2 = atoms[ai2];
1381 Atom a3 = atoms[ai3];
1382 Atom a4 = atoms[ai4];
1383
1384
1385 Bond firstBond = a1.getBond(a2);
1386 Bond middleBond = a2.getBond(a3);
1387 Bond lastBond = a3.getBond(a4);
1388 Torsion torsion = new Torsion(firstBond, middleBond, lastBond);
1389 torsion.setTorsionType(torsionType);
1390 restrainTorsionList.add(torsion);
1391 restrainLog.append("\n ").append(torsion);
1392 }
1393
1394 if (!restrainTorsionList.isEmpty()) {
1395 logger.info(restrainLog.toString());
1396 return restrainTorsionList.toArray(new Torsion[0]);
1397 } else {
1398 return null;
1399 }
1400 }
1401
1402
1403
1404
1405
1406
1407 private RestrainDistance[] configureRestrainDistances(CompositeConfiguration properties) {
1408 List<RestrainDistance> restrainDistanceList = new ArrayList<>();
1409 String[] bondRestraints = properties.getStringArray("restrain-distance");
1410 for (String bondRest : bondRestraints) {
1411 try {
1412 String[] toks = bondRest.split("\\s+");
1413 if (toks.length < 2) {
1414 throw new IllegalArgumentException(
1415 format(" restrain-distance value %s could not be parsed!", bondRest));
1416 }
1417
1418
1419 int at1 = Integer.parseInt(toks[0]) - 1;
1420 int at2 = Integer.parseInt(toks[1]) - 1;
1421
1422 double forceConst = 100.0;
1423 double flatBottomRadius = 0;
1424 Atom a1 = atoms[at1];
1425 Atom a2 = atoms[at2];
1426
1427 if (toks.length > 2) {
1428 forceConst = Double.parseDouble(toks[2]);
1429 }
1430 double dist;
1431 switch (toks.length) {
1432 case 2:
1433 case 3:
1434 double[] xyz1 = new double[3];
1435 xyz1 = a1.getXYZ(xyz1);
1436 double[] xyz2 = new double[3];
1437 xyz2 = a2.getXYZ(xyz2);
1438
1439 dist = crystal.minDistOverSymOps(xyz1, xyz2);
1440 break;
1441 case 4:
1442 dist = Double.parseDouble(toks[3]);
1443 break;
1444 case 5:
1445 default:
1446 double minDist = Double.parseDouble(toks[3]);
1447 double maxDist = Double.parseDouble(toks[4]);
1448 dist = 0.5 * (minDist + maxDist);
1449 flatBottomRadius = 0.5 * Math.abs(maxDist - minDist);
1450 break;
1451 }
1452
1453 UnivariateSwitchingFunction switchF;
1454 double lamStart = RestrainDistance.DEFAULT_RB_LAM_START;
1455 double lamEnd = RestrainDistance.DEFAULT_RB_LAM_END;
1456 if (toks.length > 5) {
1457 int offset = 5;
1458 if (toks[5].matches("^[01](?:\\.[0-9]*)?")) {
1459 offset = 6;
1460 lamStart = Double.parseDouble(toks[5]);
1461 if (toks[6].matches("^[01](?:\\.[0-9]*)?")) {
1462 offset = 7;
1463 lamEnd = Double.parseDouble(toks[6]);
1464 }
1465 }
1466 switchF = UnivariateFunctionFactory.parseUSF(toks, offset);
1467 } else {
1468 switchF = new ConstantSwitch();
1469 }
1470
1471 RestrainDistance restrainDistance = createRestrainDistance(a1, a2, dist,
1472 forceConst, flatBottomRadius, lamStart, lamEnd, switchF);
1473 restrainDistanceList.add(restrainDistance);
1474 } catch (Exception ex) {
1475 logger.info(format(" Exception in parsing restrain-distance: %s", ex));
1476 }
1477 }
1478 if (!restrainDistanceList.isEmpty()) {
1479 return restrainDistanceList.toArray(new RestrainDistance[0]);
1480 } else {
1481 return null;
1482 }
1483 }
1484
1485
1486
1487
1488
1489
1490
1491 private List<Constraint> configureConstraints(ForceField forceField) {
1492 String constraintStrings = forceField.getString("CONSTRAIN", forceField.getString("RATTLE", null));
1493 if (constraintStrings == null) {
1494 return Collections.emptyList();
1495 }
1496
1497 ArrayList<Constraint> constraints = new ArrayList<>();
1498 logger.info(format(" Experimental: parsing constraints option %s", constraintStrings));
1499
1500 Set<Bond> numericBonds = new HashSet<>(1);
1501 Set<Angle> numericAngles = new HashSet<>(1);
1502
1503
1504 if (constraintStrings.isEmpty() || constraintStrings.matches("^\\s*$")) {
1505
1506 logger.info(" Constraining X-H bonds.");
1507 Bond[] bonds = bondPotentialEnergy.getBondArray();
1508 numericBonds = Arrays.stream(bonds).filter(
1509 (Bond bond) -> bond.getAtom(0).getAtomicNumber() == 1
1510 || bond.getAtom(1).getAtomicNumber() == 1).collect(Collectors.toSet());
1511 } else {
1512 String[] constraintToks = constraintStrings.split("\\s+");
1513
1514
1515 for (String tok : constraintToks) {
1516 if (tok.equalsIgnoreCase("WATER")) {
1517 logger.info(" Constraining waters to be rigid based on angle & bonds.");
1518
1519
1520 Stream<MSNode> settleStream = molecularAssembly.getMolecules().stream()
1521 .filter((MSNode m) -> m.getAtomList().size() == 3).filter((MSNode m) -> {
1522 List<Atom> atoms = m.getAtomList();
1523 Atom O = null;
1524 List<Atom> H = new ArrayList<>(2);
1525 for (Atom at : atoms) {
1526 int atN = at.getAtomicNumber();
1527 if (atN == 8) {
1528 O = at;
1529 } else if (atN == 1) {
1530 H.add(at);
1531 }
1532 }
1533 return O != null && H.size() == 2;
1534 });
1535
1536 settleStream = Stream.concat(settleStream, molecularAssembly.getWater().stream());
1537
1538 List<SettleConstraint> settleConstraints = settleStream.map(
1539 (MSNode m) -> m.getAngleList().getFirst()).map(SettleConstraint::settleFactory).toList();
1540 constraints.addAll(settleConstraints);
1541
1542 } else if (tok.equalsIgnoreCase("DIATOMIC")) {
1543 logger.severe(" Diatomic distance constraints not yet implemented properly.");
1544 } else if (tok.equalsIgnoreCase("TRIATOMIC")) {
1545 logger.severe(
1546 " Triatomic SETTLE constraints for non-water molecules not yet implemented properly.");
1547 }
1548 }
1549
1550
1551 for (String tok : constraintToks) {
1552 if (tok.equalsIgnoreCase("BONDS") && bondPotentialEnergy != null) {
1553 Bond[] bonds = bondPotentialEnergy.getBondArray();
1554 numericBonds = new HashSet<>(Arrays.asList(bonds));
1555 } else if (tok.equalsIgnoreCase("ANGLES") && anglePotentialEnergy != null) {
1556 Angle[] angles = anglePotentialEnergy.getAngleArray();
1557 numericAngles = new HashSet<>(Arrays.asList(angles));
1558 }
1559 }
1560 }
1561
1562
1563 for (Angle angle : numericAngles) {
1564 angle.getBondList().forEach(numericBonds::remove);
1565 }
1566
1567
1568 List<Angle> ccmaAngles = numericAngles.stream().filter((Angle ang) -> !ang.isConstrained()).collect(Collectors.toList());
1569 List<Bond> ccmaBonds = numericBonds.stream().filter((Bond bond) -> !bond.isConstrained()).collect(Collectors.toList());
1570
1571 CcmaConstraint ccmaConstraint = CcmaConstraint.ccmaFactory(ccmaBonds, ccmaAngles, atoms,
1572 getMass(), CcmaConstraint.DEFAULT_CCMA_NONZERO_CUTOFF);
1573 constraints.add(ccmaConstraint);
1574 logger.info(format(" Added %d constraints.", constraints.size()));
1575
1576 return constraints;
1577 }
1578
1579
1580
1581
1582
1583
1584
1585 public static ForceFieldEnergy energyFactory(MolecularAssembly assembly) {
1586 return energyFactory(assembly, ParallelTeam.getDefaultThreadCount());
1587 }
1588
1589
1590
1591
1592
1593
1594
1595
1596 @SuppressWarnings("fallthrough")
1597 public static ForceFieldEnergy energyFactory(MolecularAssembly assembly, int numThreads) {
1598 ForceField forceField = assembly.getForceField();
1599 String platformString = toEnumForm(forceField.getString("PLATFORM", "FFX"));
1600 Platform platform;
1601 try {
1602 platform = Platform.valueOf(platformString);
1603 } catch (IllegalArgumentException e) {
1604 logger.warning(format(" String %s did not match a known energy implementation", platformString));
1605 platform = Platform.FFX;
1606 }
1607
1608
1609 String dtPlatformString = toEnumForm(forceField.getString("PLATFORM_DT", "FFX"));
1610 try {
1611 Platform dtPlatform = Platform.valueOf(dtPlatformString);
1612
1613 if (dtPlatform != Platform.FFX) {
1614
1615 platform = Platform.FFX;
1616 }
1617 } catch (IllegalArgumentException e) {
1618
1619 }
1620
1621 switch (platform) {
1622 case OMM, OMM_REF, OMM_CUDA, OMM_OPENCL:
1623 try {
1624 return new OpenMMEnergy(assembly, platform, numThreads);
1625 } catch (Exception ex) {
1626 logger.warning(format(" Exception creating OpenMMEnergy: %s", ex));
1627 ForceFieldEnergy ffxEnergy = assembly.getPotentialEnergy();
1628 if (ffxEnergy == null) {
1629 ffxEnergy = new ForceFieldEnergy(assembly, numThreads);
1630 assembly.setPotential(ffxEnergy);
1631 }
1632 return ffxEnergy;
1633 }
1634 case OMM_CPU:
1635 logger.warning(format(" Platform %s not supported; defaulting to FFX", platform));
1636 default:
1637 ForceFieldEnergy ffxEnergy = assembly.getPotentialEnergy();
1638 if (ffxEnergy == null) {
1639 ffxEnergy = new ForceFieldEnergy(assembly, numThreads);
1640 assembly.setPotential(ffxEnergy);
1641 }
1642 return ffxEnergy;
1643 }
1644 }
1645
1646
1647
1648
1649
1650
1651 public Atom[] getAtomArray() {
1652 return atoms;
1653 }
1654
1655
1656
1657
1658
1659
1660
1661 public void applyAllConstraintPositions(double[] xPrior, double[] xNew) {
1662 applyAllConstraintPositions(xPrior, xNew, DEFAULT_CONSTRAINT_TOLERANCE);
1663 }
1664
1665
1666
1667
1668
1669
1670
1671
1672 public void applyAllConstraintPositions(double[] xPrior, double[] xNew, double tol) {
1673 if (xPrior == null) {
1674 xPrior = Arrays.copyOf(xNew, xNew.length);
1675 }
1676 for (Constraint constraint : constraints) {
1677 constraint.applyConstraintToStep(xPrior, xNew, getMass(), tol);
1678 }
1679 }
1680
1681
1682
1683
1684
1685
1686
1687 public void attachExtendedSystem(ExtendedSystem system) {
1688 if (system == null) {
1689 throw new IllegalArgumentException();
1690 }
1691 esvTerm = true;
1692 esvTermOrig = esvTerm;
1693 esvSystem = system;
1694 if (vanderWaalsTerm) {
1695 if (vanderWaals == null) {
1696 logger.warning("Null VdW during ESV setup.");
1697 } else {
1698 vanderWaals.attachExtendedSystem(system);
1699 }
1700 }
1701 if (multipoleTerm) {
1702 if (particleMeshEwald == null) {
1703 logger.warning("Null PME during ESV setup.");
1704 } else {
1705 particleMeshEwald.attachExtendedSystem(system);
1706 }
1707 }
1708 }
1709
1710
1711
1712
1713
1714
1715 @Override
1716 public boolean dEdLZeroAtEnds() {
1717
1718
1719 return !lambdaTerm;
1720 }
1721
1722
1723
1724
1725
1726
1727 public boolean destroy() {
1728 if (destroyed) {
1729
1730
1731 logger.fine(format(" This ForceFieldEnergy is already destroyed: %s", this));
1732 return true;
1733 } else {
1734 try {
1735 if (parallelTeam != null) {
1736 parallelTeam.shutdown();
1737 }
1738 if (vanderWaals != null) {
1739 vanderWaals.destroy();
1740 }
1741 if (particleMeshEwald != null) {
1742 particleMeshEwald.destroy();
1743 }
1744 molecularAssembly.finishDestruction();
1745 destroyed = true;
1746 return true;
1747 } catch (Exception ex) {
1748 logger.warning(format(" Exception in shutting down a ForceFieldEnergy: %s", ex));
1749 logger.info(Utilities.stackTraceToString(ex));
1750 return false;
1751 }
1752 }
1753 }
1754
1755
1756
1757
1758
1759
1760 public double energy() {
1761 return energy(false, false);
1762 }
1763
1764
1765
1766
1767
1768
1769
1770
1771 public double energy(boolean gradient, boolean print) {
1772 try {
1773 totalTime = System.nanoTime();
1774 nnTime = 0;
1775 restrainGroupTime = 0;
1776 vanDerWaalsTime = 0;
1777 electrostaticTime = 0;
1778 ncsTime = 0;
1779
1780
1781 double forceFieldBondedEnergy = 0.0;
1782 nnEnergy = 0.0;
1783
1784
1785 double restrainEnergy = 0.0;
1786 restrainGroupEnergy = 0.0;
1787 ncsEnergy = 0.0;
1788
1789
1790 double totalNonBondedEnergy = 0.0;
1791 double totalMultipoleEnergy = 0.0;
1792 vanDerWaalsEnergy = 0.0;
1793 permanentMultipoleEnergy = 0.0;
1794 polarizationEnergy = 0.0;
1795
1796
1797 solvationEnergy = 0.0;
1798 esvBias = 0.0;
1799
1800
1801 totalEnergy = 0.0;
1802
1803
1804 try {
1805 forceFieldBondedEnergyRegion.setGradient(gradient);
1806 forceFieldBondedEnergyRegion.setLambdaBondedTerms(lambdaBondedTerms);
1807 forceFieldBondedEnergyRegion.setLambdaAllBondedTerms(lambdaAllBondedTerms);
1808 forceFieldBondedEnergyRegion.setInitAtomGradients(true);
1809 parallelTeam.execute(forceFieldBondedEnergyRegion);
1810 forceFieldBondedEnergy = forceFieldBondedEnergyRegion.getEnergy();
1811 } catch (RuntimeException ex) {
1812 logger.warning("Runtime exception during bonded term calculation.");
1813 throw ex;
1814 } catch (Exception ex) {
1815 logger.info(Utilities.stackTraceToString(ex));
1816 logger.severe(ex.toString());
1817 }
1818
1819
1820 try {
1821 if ((restrainMode == RestrainMode.ENERGY) ||
1822 (restrainMode == RestrainMode.ALCHEMICAL && lambdaBondedTerms)) {
1823 boolean checkAlchemicalAtoms = (restrainMode == RestrainMode.ENERGY);
1824 restrainEnergyRegion.setGradient(gradient);
1825 restrainEnergyRegion.setLambdaBondedTerms(lambdaBondedTerms);
1826 restrainEnergyRegion.setLambdaAllBondedTerms(lambdaAllBondedTerms);
1827 restrainEnergyRegion.setCheckAlchemicalAtoms(checkAlchemicalAtoms);
1828 restrainEnergyRegion.setInitAtomGradients(false);
1829 parallelTeam.execute(restrainEnergyRegion);
1830 restrainEnergy = restrainEnergyRegion.getEnergy();
1831 }
1832 } catch (RuntimeException ex) {
1833 logger.warning("Runtime exception during restrain term calculation.");
1834 throw ex;
1835 } catch (Exception ex) {
1836 logger.info(Utilities.stackTraceToString(ex));
1837 logger.severe(ex.toString());
1838 }
1839
1840 if (!lambdaBondedTerms) {
1841
1842 if (ncsTerm) {
1843 ncsTime = -System.nanoTime();
1844 ncsEnergy = ncsRestraint.residual(gradient, print);
1845 ncsTime += System.nanoTime();
1846 }
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858 if (restrainGroupTerm) {
1859 restrainGroupTime = -System.nanoTime();
1860 restrainGroupEnergy = restrainGroups.energy(gradient);
1861 restrainGroupTime += System.nanoTime();
1862 }
1863
1864 if (comTerm) {
1865 comRestraintTime = -System.nanoTime();
1866 comRestraintEnergy = comRestraint.residual(gradient, print);
1867 comRestraintTime += System.nanoTime();
1868 }
1869
1870
1871
1872 if (nnTerm) {
1873 nnTime = -System.nanoTime();
1874 nnEnergy = aniEnergy.energy(gradient, print);
1875 nnTime += System.nanoTime();
1876 }
1877
1878
1879 if (vanderWaalsTerm) {
1880 vanDerWaalsTime = -System.nanoTime();
1881 vanDerWaalsEnergy = vanderWaals.energy(gradient, print);
1882 nVanDerWaalInteractions = this.vanderWaals.getInteractions();
1883 vanDerWaalsTime += System.nanoTime();
1884 }
1885
1886 if (multipoleTerm) {
1887 electrostaticTime = -System.nanoTime();
1888 totalMultipoleEnergy = particleMeshEwald.energy(gradient, print);
1889 permanentMultipoleEnergy = particleMeshEwald.getPermanentEnergy();
1890 polarizationEnergy = particleMeshEwald.getPolarizationEnergy();
1891 nPermanentInteractions = particleMeshEwald.getInteractions();
1892 solvationEnergy = particleMeshEwald.getSolvationEnergy();
1893 nGKInteractions = particleMeshEwald.getGKInteractions();
1894 electrostaticTime += System.nanoTime();
1895 }
1896 }
1897
1898 totalTime = System.nanoTime() - totalTime;
1899
1900 double totalBondedEnergy = forceFieldBondedEnergy + restrainEnergy
1901 + nnEnergy + ncsEnergy + comRestraintEnergy + restrainGroupEnergy;
1902
1903 totalNonBondedEnergy = vanDerWaalsEnergy + totalMultipoleEnergy;
1904 totalEnergy = totalBondedEnergy + totalNonBondedEnergy + solvationEnergy;
1905 if (esvTerm) {
1906 esvBias = esvSystem.getBiasEnergy();
1907 totalEnergy += esvBias;
1908 }
1909
1910 if (print) {
1911 StringBuilder sb = new StringBuilder();
1912 if (gradient) {
1913 sb.append("\n Computed Potential Energy and Atomic Coordinate Gradients\n");
1914 } else {
1915 sb.append("\n Computed Potential Energy\n");
1916 }
1917 sb.append(this);
1918 logger.info(sb.toString());
1919 }
1920 return totalEnergy;
1921 } catch (EnergyException ex) {
1922 if (printOnFailure) {
1923 printFailure();
1924 }
1925 if (ex.doCauseSevere()) {
1926 logger.info(Utilities.stackTraceToString(ex));
1927 logger.log(Level.SEVERE, " Error in calculating energies or gradients", ex);
1928 } else {
1929 logger.log(Level.INFO, format(" Exception in energy calculation:\n %s", ex));
1930 }
1931 throw ex;
1932 }
1933 }
1934
1935
1936
1937
1938 @Override
1939 public double energy(double[] x) {
1940 return energy(x, false);
1941 }
1942
1943
1944
1945
1946 @Override
1947 public double energy(double[] x, boolean verbose) {
1948 assert Arrays.stream(x).allMatch(Double::isFinite);
1949
1950
1951 unscaleCoordinates(x);
1952
1953
1954 setCoordinates(x);
1955
1956 double e = this.energy(false, verbose);
1957
1958
1959 scaleCoordinates(x);
1960
1961 return e;
1962 }
1963
1964
1965
1966
1967 @Override
1968 public double energyAndGradient(double[] x, double[] g) {
1969 return energyAndGradient(x, g, false);
1970 }
1971
1972
1973
1974
1975 @Override
1976 public double energyAndGradient(double[] x, double[] g, boolean verbose) {
1977 assert Arrays.stream(x).allMatch(Double::isFinite);
1978
1979 unscaleCoordinates(x);
1980
1981 setCoordinates(x);
1982 double e = energy(true, verbose);
1983
1984
1985
1986 try {
1987 fillGradient(g);
1988
1989
1990 scaleCoordinatesAndGradient(x, g);
1991
1992 if (maxDebugGradient < Double.MAX_VALUE) {
1993 boolean extremeGrad = Arrays.stream(g)
1994 .anyMatch((double gi) -> (gi > maxDebugGradient || gi < -maxDebugGradient));
1995 if (extremeGrad) {
1996 File origFile = molecularAssembly.getFile();
1997 String timeString = LocalDateTime.now()
1998 .format(DateTimeFormatter.ofPattern("yyyy_MM_dd-HH_mm_ss"));
1999
2000 String filename = format("%s-LARGEGRAD-%s.pdb",
2001 removeExtension(molecularAssembly.getFile().getName()), timeString);
2002 PotentialsFunctions ef = new PotentialsUtils();
2003 filename = ef.versionFile(filename);
2004
2005 logger.warning(format(" Excessively large gradient detected; printing snapshot to file %s",
2006 filename));
2007 ef.saveAsPDB(molecularAssembly, new File(filename));
2008 molecularAssembly.setFile(origFile);
2009 }
2010 }
2011 return e;
2012 } catch (EnergyException ex) {
2013 if (printOnFailure) {
2014 printFailure();
2015 }
2016 if (ex.doCauseSevere()) {
2017 logger.info(Utilities.stackTraceToString(ex));
2018 logger.log(Level.SEVERE, " Error in calculating energies or gradients", ex);
2019 } else {
2020 logger.log(Level.INFO, format(" Exception in energy calculation:\n %s", ex));
2021 }
2022 throw ex;
2023 }
2024 }
2025
2026
2027
2028
2029 private void printFailure() {
2030 String timeString = LocalDateTime.now()
2031 .format(DateTimeFormatter.ofPattern("yyyy_MM_dd-HH_mm_ss"));
2032 File file = molecularAssembly.getFile();
2033 String ext = "pdb";
2034 if (isXYZ(file)) {
2035 ext = "xyz";
2036 }
2037 String filename = format("%s-ERROR-%s.%s", removeExtension(file.getName()), timeString, ext);
2038 PotentialsFunctions ef = new PotentialsUtils();
2039 filename = ef.versionFile(filename);
2040 logger.info(format(" Writing on-error snapshot to file %s", filename));
2041 ef.save(molecularAssembly, new File(filename));
2042 }
2043
2044
2045
2046
2047
2048
2049 @Override
2050 public double[] getAcceleration(double[] acceleration) {
2051 int n = getNumberOfVariables();
2052 if (acceleration == null || acceleration.length < n) {
2053 acceleration = new double[n];
2054 }
2055 int index = 0;
2056 double[] a = new double[3];
2057 for (int i = 0; i < nAtoms; i++) {
2058 if (atoms[i].isActive()) {
2059 atoms[i].getAcceleration(a);
2060 acceleration[index++] = a[0];
2061 acceleration[index++] = a[1];
2062 acceleration[index++] = a[2];
2063 }
2064 }
2065 return acceleration;
2066 }
2067
2068
2069
2070
2071
2072
2073
2074 public Angle[] getAngles(AngleMode angleMode) {
2075 if (anglePotentialEnergy == null) {
2076 return null;
2077 }
2078 Angle[] angles = anglePotentialEnergy.getAngleArray();
2079 int nAngles = angles.length;
2080 List<Angle> angleList = new ArrayList<>();
2081
2082 for (int i = 0; i < nAngles; i++) {
2083 if (angles[i].getAngleMode() == angleMode) {
2084 angleList.add(angles[i]);
2085 }
2086 }
2087 nAngles = angleList.size();
2088 if (nAngles < 1) {
2089 return null;
2090 }
2091 return angleList.toArray(new Angle[0]);
2092 }
2093
2094
2095
2096
2097
2098
2099 @Override
2100 public List<Constraint> getConstraints() {
2101 return constraints.isEmpty() ? Collections.emptyList() : new ArrayList<>(constraints);
2102 }
2103
2104
2105
2106
2107 @Override
2108 public double[] getCoordinates(double[] x) {
2109 int n = getNumberOfVariables();
2110 if (x == null || x.length < n) {
2111 x = new double[n];
2112 }
2113 int index = 0;
2114 for (int i = 0; i < nAtoms; i++) {
2115 Atom a = atoms[i];
2116 if (a.isActive()) {
2117 x[index++] = a.getX();
2118 x[index++] = a.getY();
2119 x[index++] = a.getZ();
2120 }
2121 }
2122 return x;
2123 }
2124
2125
2126
2127
2128
2129
2130 @Override
2131 public Crystal getCrystal() {
2132 return crystal;
2133 }
2134
2135
2136
2137
2138
2139
2140 @Override
2141 public void setCrystal(Crystal crystal) {
2142 setCrystal(crystal, false);
2143 }
2144
2145
2146
2147
2148
2149
2150 public double getCutoffPlusBuffer() {
2151 return cutoffPlusBuffer;
2152 }
2153
2154
2155
2156
2157 @Override
2158 public STATE getEnergyTermState() {
2159 return state;
2160 }
2161
2162
2163
2164
2165
2166
2167 @Override
2168 public void setEnergyTermState(STATE state) {
2169 this.state = state;
2170 if (forceFieldBondedEnergyRegion != null) {
2171 forceFieldBondedEnergyRegion.setState(state);
2172 }
2173 if (restrainEnergyRegion != null) {
2174 restrainEnergyRegion.setState(state);
2175 }
2176 switch (state) {
2177 case FAST:
2178 nnTerm = nnTermOrig;
2179 restrainGroupTerm = restrainGroupTermOrig;
2180 ncsTerm = ncsTermOrig;
2181 comTerm = comTermOrig;
2182 vanderWaalsTerm = false;
2183 multipoleTerm = false;
2184 polarizationTerm = false;
2185 generalizedKirkwoodTerm = false;
2186 esvTerm = false;
2187 break;
2188 case SLOW:
2189 vanderWaalsTerm = vanderWaalsTermOrig;
2190 multipoleTerm = multipoleTermOrig;
2191 polarizationTerm = polarizationTermOrig;
2192 generalizedKirkwoodTerm = generalizedKirkwoodTermOrig;
2193 esvTerm = esvTermOrig;
2194 nnTerm = false;
2195 restrainGroupTerm = false;
2196 ncsTerm = false;
2197 comTerm = false;
2198 break;
2199 default:
2200 nnTerm = nnTermOrig;
2201 restrainGroupTerm = restrainGroupTermOrig;
2202 ncsTerm = ncsTermOrig;
2203 comTermOrig = comTerm;
2204 vanderWaalsTerm = vanderWaalsTermOrig;
2205 multipoleTerm = multipoleTermOrig;
2206 polarizationTerm = polarizationTermOrig;
2207 generalizedKirkwoodTerm = generalizedKirkwoodTermOrig;
2208 }
2209 }
2210
2211
2212
2213
2214
2215
2216 public double getEsvBiasEnergy() {
2217 return esvBias;
2218 }
2219
2220
2221
2222
2223
2224
2225 public ExtendedSystem getExtendedSystem() {
2226 return esvSystem;
2227 }
2228
2229
2230
2231
2232
2233
2234 public GeneralizedKirkwood getGK() {
2235 if (particleMeshEwald != null) {
2236 return particleMeshEwald.getGK();
2237 } else {
2238 return null;
2239 }
2240 }
2241
2242
2243
2244
2245
2246
2247
2248 public double[] getGradient(double[] g) {
2249 return fillGradient(g);
2250 }
2251
2252
2253
2254
2255 @Override
2256 public double getLambda() {
2257 return lambda;
2258 }
2259
2260
2261
2262
2263 @Override
2264 public void setLambda(double lambda) {
2265 if (lambdaTerm) {
2266 if (lambda <= 1.0 && lambda >= 0.0) {
2267 this.lambda = lambda;
2268 if (vanderWaalsTerm) {
2269 vanderWaals.setLambda(lambda);
2270 }
2271 if (multipoleTerm) {
2272 particleMeshEwald.setLambda(lambda);
2273 }
2274
2275
2276
2277
2278
2279
2280
2281
2282 if (restrainDistanceTerm && restrainDistancePotentialEnergy != null) {
2283 for (RestrainDistance restrainDistance : restrainDistancePotentialEnergy.getRestrainDistances()) {
2284 restrainDistance.setLambda(lambda);
2285 }
2286 }
2287 if (restrainTorsionTerm && restrainTorsionPotentialEnergy != null) {
2288 for (Torsion restrainTorsion : restrainTorsionPotentialEnergy.getRestrainTorsions()) {
2289 restrainTorsion.setLambda(lambda);
2290 }
2291 }
2292 if (ncsTerm && ncsRestraint != null) {
2293 ncsRestraint.setLambda(lambda);
2294 }
2295 if (comTerm && comRestraint != null) {
2296 comRestraint.setLambda(lambda);
2297 }
2298 if (lambdaTorsions) {
2299 if (torsionPotentialEnergy != null) {
2300 torsionPotentialEnergy.setLambda(lambda);
2301 }
2302 if (piOrbitalTorsionPotentialEnergy != null) {
2303 piOrbitalTorsionPotentialEnergy.setLambda(lambda);
2304 }
2305 if (torsionTorsionPotentialEnergy != null) {
2306 torsionTorsionPotentialEnergy.setLambda(lambda);
2307 }
2308 }
2309 } else {
2310 String message = format("Lambda value %8.3f is not in the range [0..1].", lambda);
2311 logger.warning(message);
2312 }
2313 } else {
2314 logger.fine(" Attempting to set a lambda value on a ForceFieldEnergy with lambdaterm false.");
2315 }
2316 }
2317
2318
2319
2320
2321 @Override
2322 public double[] getMass() {
2323 int n = getNumberOfVariables();
2324 double[] mass = new double[n];
2325 int index = 0;
2326 for (int i = 0; i < nAtoms; i++) {
2327 Atom a = atoms[i];
2328 if (a.isActive()) {
2329 double m = a.getMass();
2330 mass[index++] = m;
2331 mass[index++] = m;
2332 mass[index++] = m;
2333 }
2334 }
2335 return mass;
2336 }
2337
2338
2339
2340
2341 @Override
2342 public int getNumberOfVariables() {
2343 int nActive = 0;
2344 for (int i = 0; i < nAtoms; i++) {
2345 if (atoms[i].isActive()) {
2346 nActive++;
2347 }
2348 }
2349 return nActive * 3;
2350 }
2351
2352
2353
2354
2355
2356
2357 public String getPDBHeaderString() {
2358 energy(false, false);
2359 StringBuilder sb = new StringBuilder();
2360 sb.append("REMARK 3 CALCULATED POTENTIAL ENERGY\n");
2361 sb.append(forceFieldBondedEnergyRegion.toPDBString());
2362 sb.append(restrainEnergyRegion.toPDBString());
2363 if (nnTerm) {
2364 sb.append(
2365 format("REMARK 3 %s %g (%d)\n", "NEUTRAL NETWORK : ", nnEnergy, nAtoms));
2366 }
2367 if (ncsTerm) {
2368 sb.append(
2369 format("REMARK 3 %s %g (%d)\n", "NCS RESTRAINT : ", ncsEnergy, nAtoms));
2370 }
2371 if (comTerm) {
2372 sb.append(
2373 format("REMARK 3 %s %g (%d)\n", "COM RESTRAINT : ", comRestraintEnergy,
2374 nAtoms));
2375 }
2376 if (vanderWaalsTerm) {
2377 sb.append(
2378 format("REMARK 3 %s %g (%d)\n", "VAN DER WAALS : ", vanDerWaalsEnergy,
2379 nVanDerWaalInteractions));
2380 }
2381 if (multipoleTerm) {
2382 sb.append(format("REMARK 3 %s %g (%d)\n", "ATOMIC MULTIPOLES : ",
2383 permanentMultipoleEnergy, nPermanentInteractions));
2384 }
2385 if (polarizationTerm) {
2386 sb.append(format("REMARK 3 %s %g (%d)\n", "POLARIZATION : ",
2387 polarizationEnergy, nPermanentInteractions));
2388 }
2389 sb.append(format("REMARK 3 %s %g\n", "TOTAL POTENTIAL (KCAL/MOL) : ", totalEnergy));
2390 int nsymm = crystal.getUnitCell().spaceGroup.getNumberOfSymOps();
2391 if (nsymm > 1) {
2392 sb.append(format("REMARK 3 %s %g\n", "UNIT CELL POTENTIAL : ", totalEnergy * nsymm));
2393 }
2394 if (crystal.getUnitCell() != crystal) {
2395 nsymm = crystal.spaceGroup.getNumberOfSymOps();
2396 if (nsymm > 1) {
2397 sb.append(format("REMARK 3 %s %g\n", "REPLICATES CELL POTENTIAL : ", totalEnergy * nsymm));
2398 }
2399 }
2400 sb.append("REMARK 3\n");
2401
2402 return sb.toString();
2403 }
2404
2405
2406
2407
2408
2409
2410 public ParallelTeam getParallelTeam() {
2411 return parallelTeam;
2412 }
2413
2414
2415
2416
2417
2418
2419 public int getPermanentInteractions() {
2420 return nPermanentInteractions;
2421 }
2422
2423
2424
2425
2426
2427
2428 public double getPermanentMultipoleEnergy() {
2429 return permanentMultipoleEnergy;
2430 }
2431
2432
2433
2434
2435
2436
2437
2438 public Platform getPlatform() {
2439 return platform;
2440 }
2441
2442
2443
2444
2445
2446
2447 public ParticleMeshEwald getPmeNode() {
2448 return particleMeshEwald;
2449 }
2450
2451
2452
2453
2454
2455
2456 public double getPolarizationEnergy() {
2457 return polarizationEnergy;
2458 }
2459
2460
2461
2462
2463
2464
2465 @Override
2466 public double[] getPreviousAcceleration(double[] previousAcceleration) {
2467 int n = getNumberOfVariables();
2468 if (previousAcceleration == null || previousAcceleration.length < n) {
2469 previousAcceleration = new double[n];
2470 }
2471 int index = 0;
2472 double[] a = new double[3];
2473 for (int i = 0; i < nAtoms; i++) {
2474 if (atoms[i].isActive()) {
2475 atoms[i].getPreviousAcceleration(a);
2476 previousAcceleration[index++] = a[0];
2477 previousAcceleration[index++] = a[1];
2478 previousAcceleration[index++] = a[2];
2479 }
2480 }
2481 return previousAcceleration;
2482 }
2483
2484
2485
2486
2487 @Override
2488 public double[] getScaling() {
2489 return optimizationScaling;
2490 }
2491
2492
2493
2494
2495 @Override
2496 public void setScaling(double[] scaling) {
2497 optimizationScaling = scaling;
2498 }
2499
2500
2501
2502
2503
2504
2505 public double getSolvationEnergy() {
2506 return solvationEnergy;
2507 }
2508
2509
2510
2511
2512
2513
2514 public int getSolvationInteractions() {
2515 return nGKInteractions;
2516 }
2517
2518
2519
2520
2521 @Override
2522 public double getTotalEnergy() {
2523 return totalEnergy;
2524 }
2525
2526
2527
2528
2529
2530
2531 public double getVanDerWaalsEnergy() {
2532 return vanDerWaalsEnergy;
2533 }
2534
2535
2536
2537
2538
2539
2540 public int getVanDerWaalsInteractions() {
2541 return nVanDerWaalInteractions;
2542 }
2543
2544
2545
2546
2547
2548
2549 @Override
2550 public VARIABLE_TYPE[] getVariableTypes() {
2551 int n = getNumberOfVariables();
2552 VARIABLE_TYPE[] type = new VARIABLE_TYPE[n];
2553 int i = 0;
2554 for (int j = 0; j < nAtoms; j++) {
2555 if (atoms[j].isActive()) {
2556 type[i++] = VARIABLE_TYPE.X;
2557 type[i++] = VARIABLE_TYPE.Y;
2558 type[i++] = VARIABLE_TYPE.Z;
2559 }
2560 }
2561 return type;
2562 }
2563
2564
2565
2566
2567
2568
2569 public VanDerWaals getVdwNode() {
2570 return vanderWaals;
2571 }
2572
2573
2574
2575
2576
2577
2578 @Override
2579 public double[] getVelocity(double[] velocity) {
2580 int n = getNumberOfVariables();
2581 if (velocity == null || velocity.length < n) {
2582 velocity = new double[n];
2583 }
2584 int index = 0;
2585 double[] v = new double[3];
2586 for (int i = 0; i < nAtoms; i++) {
2587 Atom a = atoms[i];
2588 if (a.isActive()) {
2589 a.getVelocity(v);
2590 velocity[index++] = v[0];
2591 velocity[index++] = v[1];
2592 velocity[index++] = v[2];
2593 }
2594 }
2595 return velocity;
2596 }
2597
2598
2599
2600
2601 @Override
2602 public double getd2EdL2() {
2603 double d2EdLambda2 = 0.0;
2604 if (!lambdaBondedTerms) {
2605 if (vanderWaalsTerm) {
2606 d2EdLambda2 = vanderWaals.getd2EdL2();
2607 }
2608 if (multipoleTerm) {
2609 d2EdLambda2 += particleMeshEwald.getd2EdL2();
2610 }
2611
2612
2613
2614
2615
2616
2617
2618 if (restrainDistanceTerm && restrainDistancePotentialEnergy != null) {
2619 for (RestrainDistance restrainDistance : restrainDistancePotentialEnergy.getRestrainDistanceArray()) {
2620 d2EdLambda2 += restrainDistance.getd2EdL2();
2621 }
2622 }
2623 if (ncsTerm && ncsRestraint != null) {
2624 d2EdLambda2 += ncsRestraint.getd2EdL2();
2625 }
2626 if (comTerm && comRestraint != null) {
2627 d2EdLambda2 += comRestraint.getd2EdL2();
2628 }
2629 if (lambdaTorsions) {
2630 if (torsionPotentialEnergy != null) {
2631 d2EdLambda2 += torsionPotentialEnergy.getd2EdL2();
2632 }
2633 if (piOrbitalTorsionPotentialEnergy != null) {
2634 d2EdLambda2 += piOrbitalTorsionPotentialEnergy.getd2EdL2();
2635 }
2636 if (torsionTorsionPotentialEnergy != null) {
2637 d2EdLambda2 += torsionTorsionPotentialEnergy.getd2EdL2();
2638 }
2639 }
2640 }
2641 return d2EdLambda2;
2642 }
2643
2644
2645
2646
2647 @Override
2648 public double getdEdL() {
2649 double dEdLambda = 0.0;
2650 if (!lambdaBondedTerms) {
2651 if (vanderWaalsTerm) {
2652 dEdLambda = vanderWaals.getdEdL();
2653 }
2654 if (multipoleTerm) {
2655 dEdLambda += particleMeshEwald.getdEdL();
2656 }
2657 if (restrainDistanceTerm && restrainDistancePotentialEnergy != null) {
2658 for (RestrainDistance restrainDistance : restrainDistancePotentialEnergy.getRestrainDistanceArray()) {
2659 dEdLambda += restrainDistance.getdEdL();
2660 }
2661 }
2662
2663
2664
2665
2666
2667
2668
2669 if (ncsTerm && ncsRestraint != null) {
2670 dEdLambda += ncsRestraint.getdEdL();
2671 }
2672 if (comTerm && comRestraint != null) {
2673 dEdLambda += comRestraint.getdEdL();
2674 }
2675 if (lambdaTorsions) {
2676 if (torsionPotentialEnergy != null) {
2677 dEdLambda += torsionPotentialEnergy.getdEdL();
2678 }
2679 if (piOrbitalTorsionPotentialEnergy != null) {
2680 dEdLambda += piOrbitalTorsionPotentialEnergy.getdEdL();
2681 }
2682 if (torsionTorsionPotentialEnergy != null) {
2683 dEdLambda += torsionTorsionPotentialEnergy.getdEdL();
2684 }
2685 }
2686 }
2687 return dEdLambda;
2688 }
2689
2690
2691
2692
2693 @Override
2694 public void getdEdXdL(double[] gradients) {
2695 if (!lambdaBondedTerms) {
2696 if (vanderWaalsTerm) {
2697 vanderWaals.getdEdXdL(gradients);
2698 }
2699 if (multipoleTerm) {
2700 particleMeshEwald.getdEdXdL(gradients);
2701 }
2702 if (restrainDistanceTerm && restrainDistancePotentialEnergy != null) {
2703 for (RestrainDistance restrainDistance : restrainDistancePotentialEnergy.getRestrainDistanceArray()) {
2704 restrainDistance.getdEdXdL(gradients);
2705 }
2706 }
2707
2708
2709
2710
2711
2712
2713
2714 if (ncsTerm && ncsRestraint != null) {
2715 ncsRestraint.getdEdXdL(gradients);
2716 }
2717 if (comTerm && comRestraint != null) {
2718 comRestraint.getdEdXdL(gradients);
2719 }
2720 if (lambdaTorsions) {
2721 double[] grad = new double[3];
2722 int index = 0;
2723 for (int i = 0; i < nAtoms; i++) {
2724 Atom a = atoms[i];
2725 if (a.isActive()) {
2726 a.getLambdaXYZGradient(grad);
2727 gradients[index++] += grad[0];
2728 gradients[index++] += grad[1];
2729 gradients[index++] += grad[2];
2730 }
2731 }
2732 }
2733 }
2734 }
2735
2736
2737
2738
2739
2740
2741 @Override
2742 public void setAcceleration(double[] acceleration) {
2743 if (acceleration == null) {
2744 return;
2745 }
2746 int index = 0;
2747 double[] accel = new double[3];
2748 for (int i = 0; i < nAtoms; i++) {
2749 if (atoms[i].isActive()) {
2750 accel[0] = acceleration[index++];
2751 accel[1] = acceleration[index++];
2752 accel[2] = acceleration[index++];
2753 atoms[i].setAcceleration(accel);
2754 }
2755 }
2756 }
2757
2758
2759
2760
2761
2762
2763 public void setCoordinates(@Nullable double[] coords) {
2764 if (coords == null) {
2765 return;
2766 }
2767 int index = 0;
2768 for (Atom a : atoms) {
2769 if (a.isActive()) {
2770 double x = coords[index++];
2771 double y = coords[index++];
2772 double z = coords[index++];
2773 a.moveTo(x, y, z);
2774 }
2775 }
2776 }
2777
2778
2779
2780
2781
2782
2783
2784 public void setCrystal(Crystal crystal, boolean checkReplicatesCell) {
2785 if (checkReplicatesCell) {
2786 this.crystal = ReplicatesCrystal.replicatesCrystalFactory(crystal.getUnitCell(), cutOff2);
2787 } else {
2788 this.crystal = crystal;
2789 }
2790
2791
2792
2793
2794 if (vanderWaalsTerm) {
2795 vanderWaals.setCrystal(this.crystal);
2796 }
2797 if (multipoleTerm) {
2798 particleMeshEwald.setCrystal(this.crystal);
2799 }
2800 }
2801
2802
2803
2804
2805
2806
2807
2808 @Override
2809 public void setPreviousAcceleration(double[] previousAcceleration) {
2810 if (previousAcceleration == null) {
2811 return;
2812 }
2813 int index = 0;
2814 double[] prev = new double[3];
2815 for (int i = 0; i < nAtoms; i++) {
2816 if (atoms[i].isActive()) {
2817 prev[0] = previousAcceleration[index++];
2818 prev[1] = previousAcceleration[index++];
2819 prev[2] = previousAcceleration[index++];
2820 atoms[i].setPreviousAcceleration(prev);
2821 }
2822 }
2823 }
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835 public void setPrintOnFailure(boolean onFail, boolean override) {
2836 if (override) {
2837
2838 printOnFailure = onFail;
2839 } else {
2840 try {
2841 molecularAssembly.getForceField().getBoolean("PRINT_ON_FAILURE");
2842
2843
2844
2845
2846
2847 } catch (Exception ex) {
2848 printOnFailure = onFail;
2849 }
2850 }
2851 }
2852
2853
2854
2855
2856
2857
2858 @Override
2859 public void setVelocity(double[] velocity) {
2860 if (velocity == null) {
2861 return;
2862 }
2863 int index = 0;
2864 double[] vel = new double[3];
2865 for (Atom a : atoms) {
2866 if (a.isActive()) {
2867 vel[0] = velocity[index++];
2868 vel[1] = velocity[index++];
2869 vel[2] = velocity[index++];
2870 } else {
2871
2872 vel[0] = 0.0;
2873 vel[1] = 0.0;
2874 vel[2] = 0.0;
2875 }
2876 a.setVelocity(vel);
2877 }
2878 }
2879
2880
2881
2882
2883 @Override
2884 public String toString() {
2885 StringBuilder sb = new StringBuilder();
2886 sb.append(forceFieldBondedEnergyRegion.toString());
2887 sb.append(restrainEnergyRegion.toString());
2888 if (restrainGroupTerm && nRestrainGroups > 0) {
2889 sb.append(format(" %s %20.8f %12d %12.3f\n", "Restrain Groups ", restrainGroupEnergy,
2890 nRestrainGroups, restrainGroupTime * toSeconds));
2891 }
2892 if (ncsTerm) {
2893 sb.append(format(" %s %20.8f %12d %12.3f\n", "NCS Restraint ", ncsEnergy, nAtoms,
2894 ncsTime * toSeconds));
2895 }
2896 if (comTerm) {
2897 sb.append(format(" %s %20.8f %12d %12.3f\n", "COM Restraint ", comRestraintEnergy, nAtoms,
2898 comRestraintTime * toSeconds));
2899 }
2900 if (vanderWaalsTerm && nVanDerWaalInteractions > 0) {
2901 sb.append(format(" %s %20.8f %12d %12.3f\n", "Van der Waals ", vanDerWaalsEnergy,
2902 nVanDerWaalInteractions, vanDerWaalsTime * toSeconds));
2903 }
2904 if (multipoleTerm && nPermanentInteractions > 0) {
2905 if (polarizationTerm) {
2906 sb.append(format(" %s %20.8f %12d\n", "Atomic Multipoles ", permanentMultipoleEnergy,
2907 nPermanentInteractions));
2908 } else {
2909 if (elecForm == ELEC_FORM.FIXED_CHARGE) {
2910 sb.append(format(" %s %20.8f %12d %12.3f\n", "Atomic Charges ", permanentMultipoleEnergy,
2911 nPermanentInteractions, electrostaticTime * toSeconds));
2912 } else
2913 sb.append(format(" %s %20.8f %12d %12.3f\n", "Atomic Multipoles ", permanentMultipoleEnergy,
2914 nPermanentInteractions, electrostaticTime * toSeconds));
2915 }
2916 }
2917 if (polarizationTerm && nPermanentInteractions > 0) {
2918 sb.append(format(" %s %20.8f %12d %12.3f\n", "Polarization ", polarizationEnergy,
2919 nPermanentInteractions, electrostaticTime * toSeconds));
2920 }
2921 if (generalizedKirkwoodTerm && nGKInteractions > 0) {
2922 sb.append(
2923 format(" %s %20.8f %12d\n", "Solvation ", solvationEnergy, nGKInteractions));
2924 }
2925 if (esvTerm) {
2926 sb.append(
2927 format(" %s %20.8f %s\n", "ExtendedSystemBias", esvBias, esvSystem.getLambdaList()));
2928 sb.append(esvSystem.getBiasDecomposition());
2929 }
2930 if (nnTerm) {
2931 sb.append(format(" %s %20.8f %12d %12.3f\n", "Neural Network ", nnEnergy, nAtoms,
2932 nnTime * toSeconds));
2933 }
2934 sb.append(format(" %s %20.8f %s %12.3f (sec)",
2935 "Total Potential ", totalEnergy, "(Kcal/mole)", totalTime * toSeconds));
2936 int nsymm = crystal.getUnitCell().spaceGroup.getNumberOfSymOps();
2937 if (nsymm > 1) {
2938 sb.append(format("\n %s %20.8f", "Unit Cell ", totalEnergy * nsymm));
2939 }
2940 if (crystal.getUnitCell() != crystal) {
2941 nsymm = crystal.spaceGroup.getNumberOfSymOps();
2942 sb.append(format("\n %s %20.8f", "Replicates Cell ", totalEnergy * nsymm));
2943 }
2944
2945 return sb.toString();
2946 }
2947
2948
2949
2950
2951 public void logBondedTermsAndRestraints() {
2952 if (forceFieldBondedEnergyRegion != null) {
2953 forceFieldBondedEnergyRegion.log();
2954 }
2955 if (restrainEnergyRegion != null) {
2956 restrainEnergyRegion.log();
2957 }
2958 if (restrainGroupTerm && nRestrainGroups > 0) {
2959 logger.info("\n Restrain Group Interactions:");
2960 logger.info(restrainGroups.toString());
2961 }
2962 }
2963
2964
2965
2966
2967
2968
2969
2970 void setLambdaBondedTerms(boolean lambdaBondedTerms, boolean lambdaAllBondedTerms) {
2971 this.lambdaBondedTerms = lambdaBondedTerms;
2972 this.lambdaAllBondedTerms = lambdaAllBondedTerms;
2973 }
2974
2975
2976
2977
2978
2979
2980
2981
2982 private double[] fillGradient(double[] g) {
2983 assert (g != null);
2984 double[] grad = new double[3];
2985 int n = getNumberOfVariables();
2986 if (g == null || g.length < n) {
2987 g = new double[n];
2988 }
2989 int index = 0;
2990 for (int i = 0; i < nAtoms; i++) {
2991 Atom a = atoms[i];
2992 if (a.isActive()) {
2993 a.getXYZGradient(grad);
2994 double gx = grad[0];
2995 double gy = grad[1];
2996 double gz = grad[2];
2997 if (isNaN(gx) || isInfinite(gx) || isNaN(gy) || isInfinite(gy) || isNaN(gz) || isInfinite(
2998 gz)) {
2999 StringBuilder sb = new StringBuilder(
3000 format("The gradient of atom %s is (%8.3f,%8.3f,%8.3f).", a, gx, gy, gz));
3001 double[] vals = new double[3];
3002 a.getVelocity(vals);
3003 sb.append(format("\n Velocities: %8.3g %8.3g %8.3g", vals[0], vals[1], vals[2]));
3004 a.getAcceleration(vals);
3005 sb.append(format("\n Accelerations: %8.3g %8.3g %8.3g", vals[0], vals[1], vals[2]));
3006 a.getPreviousAcceleration(vals);
3007 sb.append(
3008 format("\n Previous accelerations: %8.3g %8.3g %8.3g", vals[0], vals[1], vals[2]));
3009
3010 throw new EnergyException(sb.toString());
3011 }
3012 g[index++] = gx;
3013 g[index++] = gy;
3014 g[index++] = gz;
3015 }
3016 }
3017 return g;
3018 }
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032 private RestrainDistance createRestrainDistance(Atom a1, Atom a2, double distance, double forceConstant,
3033 double flatBottom, double lamStart, double lamEnd,
3034 UnivariateSwitchingFunction switchingFunction) {
3035 boolean rbLambda = !(switchingFunction instanceof ConstantSwitch) && lambdaTerm;
3036 RestrainDistance restrainDistance = new RestrainDistance(a1, a2, crystal, rbLambda, lamStart, lamEnd, switchingFunction);
3037 int[] classes = {a1.getAtomType().atomClass, a2.getAtomType().atomClass};
3038 if (flatBottom != 0) {
3039 BondType bondType = new BondType(classes, forceConstant, distance,
3040 BondType.BondFunction.FLAT_BOTTOM_HARMONIC, flatBottom);
3041 restrainDistance.setBondType(bondType);
3042 } else {
3043 BondType bondType = new BondType(classes, forceConstant, distance,
3044 BondType.BondFunction.HARMONIC);
3045 restrainDistance.setBondType(bondType);
3046 }
3047 return restrainDistance;
3048 }
3049
3050 private Crystal configureNCS(ForceField forceField, Crystal unitCell) {
3051
3052
3053 if (forceField.getProperties().containsKey("MTRIX1")
3054 && forceField.getProperties().containsKey("MTRIX2") && forceField.getProperties()
3055 .containsKey("MTRIX3")) {
3056 Crystal unitCell2 = new Crystal(unitCell.a, unitCell.b, unitCell.c, unitCell.alpha,
3057 unitCell.beta, unitCell.gamma, unitCell.spaceGroup.pdbName);
3058 SpaceGroup spaceGroup = unitCell2.spaceGroup;
3059
3060 CompositeConfiguration properties = forceField.getProperties();
3061 String[] MTRX1List = properties.getStringArray("MTRIX1");
3062 String[] MTRX2List = properties.getStringArray("MTRIX2");
3063 String[] MTRX3List = properties.getStringArray("MTRIX3");
3064 spaceGroup.symOps.clear();
3065 double number1;
3066 double number2;
3067 double number3;
3068 for (int i = 0; i < MTRX1List.length; i++) {
3069 double[][] Rot_MTRX = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
3070 double[] Tr_MTRX = {0, 0, 0};
3071 String[] tokens1 = MTRX1List[i].trim().split(" +");
3072 String[] tokens2 = MTRX2List[i].trim().split(" +");
3073 String[] tokens3 = MTRX3List[i].trim().split(" +");
3074 for (int k = 0; k < 4; k++) {
3075 number1 = Double.parseDouble(tokens1[k]);
3076 number2 = Double.parseDouble(tokens2[k]);
3077 number3 = Double.parseDouble(tokens3[k]);
3078 if (k != 3) {
3079 Rot_MTRX[0][k] = number1;
3080 Rot_MTRX[1][k] = number2;
3081 Rot_MTRX[2][k] = number3;
3082 } else {
3083 Tr_MTRX[0] = number1;
3084 Tr_MTRX[1] = number2;
3085 Tr_MTRX[2] = number3;
3086 }
3087 }
3088 SymOp symOp = new SymOp(Rot_MTRX, Tr_MTRX);
3089 if (logger.isLoggable(Level.FINEST)) {
3090 logger.info(
3091 format(" MTRIXn SymOp: %d of %d\n" + symOp, i + 1, MTRX1List.length));
3092 }
3093 spaceGroup.symOps.add(symOp);
3094 }
3095 unitCell = NCSCrystal.NCSCrystalFactory(unitCell, spaceGroup.symOps);
3096 unitCell.updateCrystal();
3097 }
3098 return unitCell;
3099 }
3100
3101 public RestrainMode getRestrainMode() {
3102 return restrainMode;
3103 }
3104
3105
3106
3107
3108
3109
3110 public RestrainGroups getRestrainGroups() {
3111 return restrainGroups;
3112 }
3113
3114
3115
3116
3117
3118
3119 public TorsionTorsionPotentialEnergy getTorsionTorsionPotentialEnergy() {
3120 return torsionTorsionPotentialEnergy;
3121 }
3122
3123
3124
3125
3126
3127
3128 public AnglePotentialEnergy getAnglePotentialEnergy() {
3129 return anglePotentialEnergy;
3130 }
3131
3132
3133
3134
3135
3136
3137 public BondPotentialEnergy getBondPotentialEnergy() {
3138 return bondPotentialEnergy;
3139 }
3140
3141
3142
3143
3144
3145
3146 public StretchBendPotentialEnergy getStretchBendPotentialEnergy() {
3147 return stretchBendPotentialEnergy;
3148 }
3149
3150
3151
3152
3153
3154
3155 public UreyBradleyPotentialEnergy getUreyBradleyPotentialEnergy() {
3156 return ureyBradleyPotentialEnergy;
3157 }
3158
3159
3160
3161
3162
3163
3164 public OutOfPlaneBendPotentialEnergy getOutOfPlaneBendPotentialEnergy() {
3165 return outOfPlaneBendPotentialEnergy;
3166 }
3167
3168
3169
3170
3171
3172
3173 public TorsionPotentialEnergy getTorsionPotentialEnergy() {
3174 return torsionPotentialEnergy;
3175 }
3176
3177
3178
3179
3180
3181
3182 public StretchTorsionPotentialEnergy getStretchTorsionPotentialEnergy() {
3183 return stretchTorsionPotentialEnergy;
3184 }
3185
3186
3187
3188
3189
3190
3191 public AngleTorsionPotentialEnergy getAngleTorsionPotentialEnergy() {
3192 return angleTorsionPotentialEnergy;
3193 }
3194
3195
3196
3197
3198
3199
3200 public ImproperTorsionPotentialEnergy getImproperTorsionPotentialEnergy() {
3201 return improperTorsionPotentialEnergy;
3202 }
3203
3204
3205
3206
3207
3208
3209 public PiOrbitalTorsionPotentialEnergy getPiOrbitalTorsionPotentialEnergy() {
3210 return piOrbitalTorsionPotentialEnergy;
3211 }
3212
3213
3214
3215
3216
3217
3218 public RestrainPositionPotentialEnergy getRestrainPositionPotentialEnergy() {
3219 return restrainPositionPotentialEnergy;
3220 }
3221
3222
3223
3224
3225
3226
3227 public RestrainDistancePotentialEnergy getRestrainDistancePotentialEnergy() {
3228 return restrainDistancePotentialEnergy;
3229 }
3230
3231
3232
3233
3234
3235
3236 public RestrainTorsionPotentialEnergy getRestrainTorsionPotentialEnergy() {
3237 return restrainTorsionPotentialEnergy;
3238 }
3239
3240 }