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.algorithms.optimize;
39
40 import edu.rit.pj.Comm;
41 import edu.rit.pj.ParallelTeam;
42 import edu.rit.pj.WorkerTeam;
43 import ffx.algorithms.AlgorithmListener;
44 import ffx.algorithms.Terminatable;
45 import ffx.algorithms.mc.MCMove;
46 import ffx.algorithms.optimize.manybody.DistanceMatrix;
47 import ffx.algorithms.optimize.manybody.EliminatedRotamers;
48 import ffx.algorithms.optimize.manybody.EnergyExpansion;
49 import ffx.algorithms.optimize.manybody.EnergyRegion;
50 import ffx.algorithms.optimize.manybody.FourBodyEnergyRegion;
51 import ffx.algorithms.optimize.manybody.GoldsteinPairRegion;
52 import ffx.algorithms.optimize.manybody.ManyBodyCell;
53 import ffx.algorithms.optimize.manybody.RotamerMatrixMC;
54 import ffx.algorithms.optimize.manybody.RotamerMatrixMove;
55 import ffx.algorithms.optimize.manybody.SelfEnergyRegion;
56 import ffx.algorithms.optimize.manybody.ThreeBodyEnergyRegion;
57 import ffx.algorithms.optimize.manybody.TwoBodyEnergyRegion;
58 import ffx.crystal.Crystal;
59 import ffx.crystal.SymOp;
60 import ffx.numerics.Potential;
61 import ffx.potential.DualTopologyEnergy;
62 import ffx.potential.ForceFieldEnergy;
63 import ffx.potential.MolecularAssembly;
64 import ffx.potential.QuadTopologyEnergy;
65 import ffx.potential.bonded.Atom;
66 import ffx.potential.bonded.Polymer;
67 import ffx.potential.bonded.Residue;
68 import ffx.potential.bonded.ResidueState;
69 import ffx.potential.bonded.Rotamer;
70 import ffx.potential.bonded.RotamerLibrary;
71 import ffx.potential.nonbonded.NonbondedCutoff;
72 import ffx.potential.nonbonded.VanDerWaals;
73 import ffx.potential.openmm.OpenMMEnergy;
74 import ffx.potential.parameters.TitrationUtils;
75 import ffx.potential.parsers.PDBFilter;
76 import ffx.utilities.Constants;
77 import ffx.utilities.ObjectPair;
78 import ffx.utilities.Resources;
79 import org.apache.commons.configuration2.CompositeConfiguration;
80 import org.apache.commons.io.FilenameUtils;
81
82 import java.io.BufferedWriter;
83 import java.io.File;
84 import java.io.FileWriter;
85 import java.io.IOException;
86 import java.nio.file.Path;
87 import java.nio.file.Paths;
88 import java.util.ArrayList;
89 import java.util.Arrays;
90 import java.util.Collections;
91 import java.util.Comparator;
92 import java.util.HashSet;
93 import java.util.List;
94 import java.util.Objects;
95 import java.util.Random;
96 import java.util.Set;
97 import java.util.function.BiFunction;
98 import java.util.function.ToDoubleFunction;
99 import java.util.logging.Level;
100 import java.util.logging.Logger;
101 import java.util.stream.Collectors;
102 import java.util.stream.IntStream;
103
104 import static ffx.potential.bonded.Residue.ResidueType.NA;
105 import static ffx.potential.bonded.RotamerLibrary.applyRotamer;
106 import static java.lang.Boolean.parseBoolean;
107 import static java.lang.Double.parseDouble;
108 import static java.lang.Integer.parseInt;
109 import static java.lang.String.format;
110 import static java.lang.System.arraycopy;
111 import static java.util.Arrays.copyOf;
112 import static org.apache.commons.math3.util.FastMath.abs;
113 import static org.apache.commons.math3.util.FastMath.log;
114
115
116
117
118
119
120
121
122
123
124 public class RotamerOptimization implements Terminatable {
125
126
127
128
129 private static final Logger logger = Logger.getLogger(RotamerOptimization.class.getName());
130
131
132
133 private static final double FALLBACK_TWO_BODY_CUTOFF = 0;
134
135
136
137 protected MolecularAssembly molecularAssembly;
138
139
140
141 protected final Potential potential;
142
143
144
145 protected final AlgorithmListener algorithmListener;
146
147
148
149 private final Comm world;
150
151
152
153 private final int numProc;
154
155
156
157 private final int rank;
158
159
160
161 protected final boolean rank0;
162
163
164
165 private final boolean print = false;
166
167
168
169 private final boolean verboseEnergies = true;
170
171
172
173
174 protected boolean writeEnergyRestart = true;
175
176
177
178 BoxOptimization boxOpt;
179
180
181
182
183
184
185 private final BiFunction<List<Residue>, List<Rotamer>, File> dirSupplier;
186
187
188
189
190 private final ToDoubleFunction<File> eFunction;
191
192
193
194 private final boolean verbose;
195
196
197
198 private DistanceMatrix dM;
199
200
201
202 private EnergyExpansion eE;
203
204
205
206 private EliminatedRotamers eR;
207
208
209
210 protected RotamerLibrary library = RotamerLibrary.getDefaultLibrary();
211
212
213
214 private GoldsteinPairRegion goldsteinPairRegion;
215
216
217
218 private EnergyRegion energyRegion;
219
220
221
222 private boolean terminate = false;
223
224
225
226 private boolean done = true;
227
228
229
230 private double twoBodyCutoffDist;
231
232
233
234 private boolean threeBodyTerm = false;
235
236
237
238 private double threeBodyCutoffDist;
239
240
241
242 private int[][] resNeighbors;
243
244
245
246 private int[][] bidiResNeighbors;
247
248
249
250 private boolean pruneClashes = true;
251
252
253
254 private boolean prunePairClashes = true;
255
256
257
258 private int evaluatedPermutations = 0;
259
260
261
262 private int evaluatedPermutationsPrint = 0;
263
264
265
266 private double totalBoltzmann = 0;
267
268
269
270 private double refEnergy = 0;
271
272
273
274 private double[][] fraction;
275
276
277
278 private double[][] populationBoltzmann;
279
280
281
282 private double pH;
283
284
285
286 private double pHRestraint = 0;
287
288
289
290 private boolean recomputeSelf = false;
291
292
293
294 boolean genZ = false;
295
296
297
298 private List<Residue> residueList;
299
300
301
302 protected int[] optimum;
303
304
305
306
307 private int windowSize = 7;
308
309
310
311 private int increment = 3;
312
313
314
315 protected boolean revert;
316
317
318
319 protected Direction direction = Direction.FORWARD;
320
321
322
323
324 private double distance = 2.0;
325
326
327
328 private DistanceMethod distanceMethod = DistanceMethod.RESIDUE;
329
330
331
332 private Algorithm algorithm = null;
333
334
335
336
337
338 private boolean useGoldstein = true;
339
340
341
342 private int ensembleNumber = 1;
343
344
345
346 private double ensembleBuffer = 0.0;
347
348
349
350 private double ensembleBufferStep = 0.5;
351
352
353
354 private double ensembleEnergy = 0.0;
355
356
357
358 private File ensembleFile;
359
360
361
362 private PDBFilter ensembleFilter;
363
364
365
366 private double clashThreshold = 25.0;
367
368
369
370
371 private double multiResClashThreshold = 80.0;
372
373
374
375 private double pairClashThreshold = 25.0;
376
377
378
379 private double multiResPairClashAddn = 80.0;
380
381
382
383 private double[] x = null;
384
385
386
387
388 private boolean useForceFieldEnergy = false;
389
390
391
392
393 private double nucleicCorrectionThreshold = 0;
394
395
396
397 private double approximateEnergy = 0;
398
399
400
401
402 private int minNumberAcceptedNARotamers = 10;
403
404
405
406 private double nucleicPruningFactor = 10.0;
407
408
409
410 private double nucleicPairsPruningFactor = ((1.0 + nucleicPruningFactor) / 2);
411
412
413
414 private List<Residue> allResiduesList = null;
415
416
417
418 private Residue[] allResiduesArray = null;
419
420
421
422 private int nAllResidues = 0;
423
424
425
426
427 protected int[] optimumSubset;
428
429
430
431 protected boolean loadEnergyRestart = false;
432
433
434
435 private File energyRestartFile;
436
437
438
439 private ParallelTeam parallelTeam;
440
441
442
443
444 private boolean compute4BodyEnergy = false;
445
446
447
448 protected boolean usingBoxOptimization = false;
449
450
451
452
453 private double superpositionThreshold = 0.25;
454
455
456
457 private boolean decomposeOriginal = false;
458
459
460
461 private boolean monteCarlo = false;
462
463
464
465 private int nMCSteps = 1000000;
466
467
468
469 private double mcTemp = 298.15;
470
471
472
473 private boolean mcUseAll = false;
474
475
476
477 private boolean mcNoEnum = false;
478
479
480
481
482 protected boolean printFiles = true;
483
484
485
486 private List<ObjectPair<ResidueState[], Double>> ensembleStates;
487
488
489
490 private int maxRotCheckDepth;
491
492
493
494 protected BufferedWriter energyWriter;
495
496
497
498
499 private boolean testing = false;
500
501
502
503 private boolean monteCarloTesting = false;
504
505
506
507 private boolean testSelfEnergyEliminations = false;
508
509
510
511
512
513 private int testPairEnergyEliminations = -1;
514
515
516
517
518
519 private int testTripleEnergyEliminations1 = -1;
520
521
522
523
524
525 private int testTripleEnergyEliminations2 = -1;
526
527
528
529 private boolean selfEliminationOn = true;
530
531
532
533 private boolean pairEliminationOn = true;
534
535
536
537
538
539
540
541
542 public RotamerOptimization(MolecularAssembly molecularAssembly, Potential potential,
543 AlgorithmListener algorithmListener) {
544
545 this.molecularAssembly = molecularAssembly;
546 this.potential = potential;
547 if (potential instanceof ForceFieldEnergy) {
548 ((ForceFieldEnergy) potential).setPrintOnFailure(false, true);
549 } else if (potential instanceof DualTopologyEnergy) {
550 ((DualTopologyEnergy) potential).setPrintOnFailure(false, true);
551 } else if (potential instanceof QuadTopologyEnergy) {
552 ((QuadTopologyEnergy) potential).setPrintOnFailure(false, true);
553 }
554 this.algorithmListener = algorithmListener;
555
556 eFunction = this::currentPE;
557 dirSupplier = (List<Residue> resList, List<Rotamer> rotList) -> null;
558
559 world = Comm.world();
560 numProc = world.size();
561 rank = world.rank();
562
563 rank0 = rank == 0;
564
565 boxOpt = new BoxOptimization(this);
566
567 CompositeConfiguration properties = molecularAssembly.getProperties();
568 verbose = properties.getBoolean("verbose", false);
569
570
571 ForceFieldEnergy forceFieldEnergy = molecularAssembly.getPotentialEnergy();
572 VanDerWaals vdW = forceFieldEnergy.getVdwNode();
573 if (vdW != null) {
574 NonbondedCutoff nonBondedCutoff = vdW.getNonbondedCutoff();
575 twoBodyCutoffDist = nonBondedCutoff.off;
576 } else {
577 twoBodyCutoffDist = FALLBACK_TWO_BODY_CUTOFF;
578 }
579
580
581
582 boolean testing = properties.getBoolean("manybody-testing", false);
583 if (testing) {
584 turnRotamerSingleEliminationOff();
585 turnRotamerPairEliminationOff();
586 }
587 boolean monteCarloTesting = properties.getBoolean("manybody-testing-mc", false);
588 if (monteCarloTesting) {
589 setMonteCarloTesting(true);
590 }
591
592
593 String computeQuads = properties.getString("ro-compute4BodyEnergy");
594 if (computeQuads != null) {
595 this.compute4BodyEnergy = parseBoolean(computeQuads);
596 logger.info(format(" (KEY) compute4BodyEnergy: %b", this.compute4BodyEnergy));
597 }
598
599
600 String direction = properties.getString("ro-direction");
601 String boxDimensions = properties.getString("ro-boxDimensions");
602 if (direction != null) {
603 this.direction = Direction.valueOf(direction);
604 logger.info(format(" (KEY) direction: %s", this.direction));
605 }
606 if (boxDimensions != null) {
607 boxOpt.update(boxDimensions);
608 }
609
610
611 String ensembleNumber = properties.getString("ro-ensembleNumber");
612 String ensembleEnergy = properties.getString("ro-ensembleEnergy");
613 String ensembleBuffer = properties.getString("ro-ensembleBuffer");
614 if (ensembleNumber != null) {
615 this.ensembleNumber = parseInt(ensembleNumber);
616 this.ensembleBuffer = 5.0;
617 this.ensembleBufferStep = 0.1 * this.ensembleBuffer;
618 logger.info(format(" (KEY) ensembleNumber: %d", this.ensembleNumber));
619 }
620 if (ensembleBuffer != null) {
621 this.ensembleBuffer = parseDouble(ensembleBuffer);
622 this.ensembleBufferStep = 0.1 * this.ensembleBuffer;
623 logger.info(format(" (KEY) ensembleBuffer: %.2f", this.ensembleBuffer));
624 }
625 if (ensembleEnergy != null) {
626 this.ensembleEnergy = parseDouble(ensembleEnergy);
627 logger.info(format(" (KEY) ensembleEnergy: %.2f", this.ensembleEnergy));
628 }
629
630
631 String nucleicPruningFactor = properties.getString("ro-nucleicPruningFactor");
632 String nucleicCorrectionThreshold = properties.getString("ro-nucleicCorrectionThreshold");
633 String minimumNumberAcceptedNARotamers = properties.getString(
634 "ro-minimumNumberAcceptedNARotamers");
635 if (nucleicPruningFactor != null) {
636 double value = parseDouble(nucleicPruningFactor);
637 this.nucleicPruningFactor = (value >= 0 ? value : 1.0);
638 this.nucleicPairsPruningFactor = (1.0 + value) / 2;
639 logger.info(format(" (KEY) nucleicPruningFactor: %.2f", this.nucleicPruningFactor));
640 }
641 if (nucleicCorrectionThreshold != null) {
642 double value = parseDouble(nucleicCorrectionThreshold);
643 this.nucleicCorrectionThreshold = (value >= 0 ? value : 0);
644 logger.info(
645 format(" (KEY) nucleicCorrectionThreshold: %.2f", this.nucleicCorrectionThreshold));
646 }
647 if (minimumNumberAcceptedNARotamers != null) {
648 int value = parseInt(minimumNumberAcceptedNARotamers);
649 this.minNumberAcceptedNARotamers = (value > 0 ? value : 10);
650 logger.info(
651 format(" (KEY) minimumNumberAcceptedNARotamers: %d", this.minNumberAcceptedNARotamers));
652 }
653
654
655 String superpositionThreshold = properties.getString("ro-superpositionThreshold");
656 if (superpositionThreshold != null) {
657 this.superpositionThreshold = parseDouble(superpositionThreshold);
658 logger.info(format(" (KEY) superpositionThreshold: %.2f", this.superpositionThreshold));
659 }
660
661
662 String multiResClashThreshold = properties.getString("ro-multiResClashThreshold");
663 String multiResPairClashAddition = properties.getString("ro-multiResPairClashAddition");
664 if (multiResClashThreshold != null) {
665 this.multiResClashThreshold = parseDouble(multiResClashThreshold);
666 logger.info(format(" (KEY) multiResClashThreshold: %.2f", this.multiResClashThreshold));
667 }
668 if (multiResPairClashAddition != null) {
669 this.multiResPairClashAddn = parseDouble(multiResPairClashAddition);
670 logger.info(format(" (KEY) multiResPairClashAddition: %.2f", this.multiResPairClashAddn));
671 }
672
673
674 String mcTemp = properties.getString("ro-mcTemp");
675 String mcUseAll = properties.getString("ro-mcUseAll");
676 String mcNoEnum = properties.getString("ro-debug-mcNoEnum");
677 if (mcTemp != null) {
678 this.mcTemp = parseDouble(mcTemp);
679 logIfRank0(format(" (KEY) mcTemp: %10.6f", this.mcTemp));
680 }
681 if (mcUseAll != null) {
682 this.mcUseAll = parseBoolean(mcUseAll);
683 logIfRank0(format(" (KEY) mcUseAll: %b", this.mcUseAll));
684 }
685 if (mcNoEnum != null) {
686 this.mcNoEnum = parseBoolean(mcNoEnum);
687 logIfRank0(format(" (KEY) debug-mcNoEnum: %b", this.mcNoEnum));
688 }
689
690 String propStr = properties.getString("ro-maxRotCheckDepth");
691 int defaultMaxRotCheckDepth = 1;
692 if (propStr != null) {
693 try {
694 maxRotCheckDepth = parseInt(propStr);
695 if (maxRotCheckDepth > 3 || maxRotCheckDepth < 0) {
696 throw new IllegalArgumentException(" ro-maxRotCheckDepth must be between 0-3 inclusive!");
697 }
698 } catch (Exception ex) {
699 maxRotCheckDepth = defaultMaxRotCheckDepth;
700 logger.warning(format(" Could not parse %s value %s as valid integer; defaulting to %d",
701 "ro-maxRotCheckDepth", propStr, maxRotCheckDepth));
702 logger.warning(format(" Exception: %s", ex));
703 }
704 } else {
705 maxRotCheckDepth = defaultMaxRotCheckDepth;
706 }
707
708 setUpRestart();
709 }
710
711
712
713
714
715
716 public void setWriteEnergyRestart(boolean writeEnergyRestart) {
717 this.writeEnergyRestart = writeEnergyRestart;
718 }
719
720
721
722
723
724
725 private static void turnOffAtoms(Residue residue) {
726 switch (residue.getResidueType()) {
727 case NA:
728 case AA:
729 List<Atom> atomList = residue.getVariableAtoms();
730 for (Atom atom : atomList) {
731 atom.setUse(false);
732 }
733 break;
734 default:
735 atomList = residue.getAtomList();
736 for (Atom atom : atomList) {
737 atom.setUse(false);
738 }
739 break;
740 }
741 }
742
743
744
745
746
747
748 private static void turnOnAtoms(Residue residue) {
749 switch (residue.getResidueType()) {
750 case NA:
751 case AA:
752 List<Atom> atomList = residue.getVariableAtoms();
753 for (Atom atom : atomList) {
754 atom.setUse(true);
755 }
756 break;
757 default:
758 atomList = residue.getAtomList();
759 for (Atom atom : atomList) {
760 atom.setUse(true);
761 }
762 break;
763 }
764 }
765
766
767
768
769
770
771
772
773
774 public boolean checkNeighboringPair(int i, int j) {
775 assert i != j;
776 final int first;
777 final int second;
778 if (i > j) {
779 first = j;
780 second = i;
781 } else {
782 first = i;
783 second = j;
784 }
785 return Arrays.stream(resNeighbors[first]).anyMatch(l -> l == second);
786 }
787
788
789
790
791
792
793
794
795
796
797
798 public boolean checkNeighboringTriple(int i, int j, int k) {
799 assert i != j && i != k && j != k;
800 int[] vals = new int[]{i, j, k};
801 Arrays.sort(vals);
802 final int first = vals[0];
803 final int second = vals[1];
804 final int third = vals[2];
805 if (!checkNeighboringPair(first, second)) {
806 return false;
807 }
808 return (checkNeighboringPair(first, third) || checkNeighboringPair(second, third));
809 }
810
811
812
813
814
815
816
817
818
819 public boolean checkValidMove(int i, int ri, int[] currentRots) {
820 int nRes = currentRots.length;
821 for (int j = 0; j < nRes; j++) {
822 if (j == i) {
823 continue;
824 }
825 if (eR.check(j, currentRots[j], i, ri)) {
826 return false;
827 }
828 }
829 return true;
830 }
831
832
833
834
835
836
837
838
839
840 public double computeBackboneEnergy(Residue[] residues) throws ArithmeticException {
841
842 Atom[] atoms = molecularAssembly.getAtomArray();
843 for (Atom atom : atoms) {
844 atom.setUse(true);
845 }
846
847
848 turnOffAllResidues(residues);
849
850
851 return currentEnergy(residues);
852 }
853
854
855
856
857
858
859
860
861
862
863 public double computeEnergy(Residue[] residues, int[] rotamers, boolean print) {
864 double selfSum;
865 double pairSum;
866 double threeBodySum;
867 try {
868 if (parallelTeam == null) {
869 parallelTeam = new ParallelTeam();
870 }
871 if (energyRegion == null) {
872 energyRegion = new EnergyRegion(parallelTeam.getThreadCount());
873 }
874 energyRegion.init(eE, residues, rotamers, threeBodyTerm);
875 parallelTeam.execute(energyRegion);
876 selfSum = energyRegion.getSelf();
877 pairSum = energyRegion.getTwoBody();
878 threeBodySum = energyRegion.getThreeBody();
879 } catch (Exception e) {
880 throw new IllegalArgumentException(e);
881 }
882
883 approximateEnergy = eE.getBackboneEnergy() + selfSum + pairSum + threeBodySum;
884
885 if (print) {
886 logger.info(format(" Backbone %s", formatEnergy(eE.getBackboneEnergy())));
887 logger.info(format(" Self Energy %s", formatEnergy(selfSum)));
888 logger.info(format(" Pair Energy %s", formatEnergy(pairSum)));
889 if (!threeBodyTerm) {
890 logger.info(format(" Total Energy up to 2-Body %s", formatEnergy(approximateEnergy)));
891 } else {
892 logger.info(format(" 3-Body Energy %s", formatEnergy(threeBodySum)));
893 logger.info(format(" Total Energy up to 3-Body %s", formatEnergy(approximateEnergy)));
894 }
895 }
896 return approximateEnergy;
897 }
898
899
900
901
902
903
904
905 public double currentEnergy(Residue[] resArray) throws ArithmeticException {
906 return currentEnergy(Arrays.asList(resArray));
907 }
908
909
910
911
912
913
914
915
916
917 public double currentEnergyWrapper(List<Residue> resList) throws ArithmeticException {
918 return currentEnergy(resList);
919 }
920
921
922
923
924
925
926 public double currentFFXPE() {
927 if (x == null) {
928 int n = potential.getNumberOfVariables();
929 x = new double[n];
930 }
931 potential.getCoordinates(x);
932 return ((OpenMMEnergy) potential).energyFFX(x, false);
933 }
934
935
936
937
938
939
940
941 public String formatEnergy(double energy) {
942 if (abs(energy) < 1.0e6) {
943 return format("%16.8f", energy);
944 } else {
945 return format("*%15.4e", energy);
946 }
947 }
948
949 public double getApproximate() {
950 return approximateEnergy;
951 }
952
953 public double getBackboneEnergy() {
954 return eE.getBackboneEnergy();
955 }
956
957 public EliminatedRotamers getEliminatedRotamers() {
958 return eR;
959 }
960
961 public EnergyExpansion getEnergyExpansion() {
962 return eE;
963 }
964
965
966
967
968
969
970 public List<ResidueState[]> getEnsemble() {
971 if (ensembleStates == null) {
972 return null;
973 } else {
974 List<ResidueState[]> states = new ArrayList<>(ensembleStates.size());
975 ensembleStates.forEach((es) -> states.add(es.val()));
976 return states;
977 }
978 }
979
980
981
982
983
984
985 public void setEnsemble(int ensemble) {
986 setEnsemble(ensemble, 5.0);
987 }
988
989
990
991
992
993
994 public List<Residue> getResidues() {
995 return residueList;
996 }
997
998
999
1000
1001
1002
1003 public void setResidues(List<Residue> residueList) {
1004 this.residueList = residueList;
1005 }
1006
1007
1008
1009
1010
1011
1012 public void initFraction(List<Residue> residueList) {
1013 fraction = new double[residueList.size()][56];
1014 genZ = true;
1015 }
1016
1017
1018
1019
1020
1021
1022 public File getRestartFile() {
1023 return energyRestartFile;
1024 }
1025
1026 public double goldsteinPairSumOverK(Residue[] residues, int lb, int ub, int i, int riA, int riB,
1027 int j, int rjC, int rjD, List<Residue> blockedResidues, int[] possK) {
1028 double sumOverK = 0.0;
1029
1030 for (int indK = lb; indK <= ub; indK++) {
1031 int k = possK[indK];
1032 double minForResK = Double.MAX_VALUE;
1033 Residue resk = residues[k];
1034 Rotamer[] rotk = resk.getRotamers();
1035 int nrk = rotk.length;
1036 int rkEvals = 0;
1037
1038 for (int rk = 0; rk < nrk; rk++) {
1039 if (eR.check(k, rk)) {
1040 continue;
1041 }
1042
1043 if (eR.check(i, riA, k, rk) || eR.check(j, rjC, k, rk)) {
1044
1045 continue;
1046 }
1047
1048 if (eR.check(i, riB, k, rk) || eR.check(j, rjD, k, rk)) {
1049 blockedResidues.add(resk);
1050 return Double.NaN;
1051 }
1052
1053 rkEvals++;
1054 double currentResK =
1055 eE.get2Body(i, riA, k, rk) - eE.get2Body(i, riB, k, rk) + eE.get2Body(j, rjC, k, rk)
1056 - eE.get2Body(j, rjD, k, rk);
1057
1058 if (threeBodyTerm) {
1059 double sumOverL = (eE.get3Body(residues, i, riA, j, rjC, k, rk) - eE.get3Body(residues, i,
1060 riB, j, rjD, k, rk));
1061
1062 int[] nK = bidiResNeighbors[k];
1063 IntStream lStream = IntStream.concat(Arrays.stream(possK), Arrays.stream(nK));
1064 int[] possL = lStream.filter(l -> (l != i && l != j && l != k)).sorted().distinct()
1065 .toArray();
1066
1067 for (int l : possL) {
1068 if (l == k || l == i || l == j) {
1069 continue;
1070 }
1071 Residue residuel = residues[l];
1072 Rotamer[] rotamersl = residuel.getRotamers();
1073 int nrl = rotamersl.length;
1074 int rlEvaluations = 0;
1075 double minForResL = Double.MAX_VALUE;
1076
1077 for (int rl = 0; rl < nrl; rl++) {
1078
1079 if (eR.check(l, rl) || eR.check(k, rk, l, rl) || eR.check(i, riA, l, rl) || eR.check(j,
1080 rjC, l, rl)) {
1081
1082
1083 continue;
1084 }
1085 if (eR.check(i, riB, l, rl) || eR.check(j, rjD, l, rl)) {
1086
1087
1088 blockedResidues.add(residuel);
1089 return Double.NaN;
1090 }
1091 rlEvaluations++;
1092 double e =
1093 eE.get3Body(residues, i, riA, k, rk, l, rl) - eE.get3Body(residues, i, riB, k, rk,
1094 l, rl) + eE.get3Body(residues, j, rjC, k, rk, l, rl) - eE.get3Body(residues, j,
1095 rjD, k, rk, l, rl);
1096 if (e < minForResL) {
1097 minForResL = e;
1098 }
1099 }
1100 if (rlEvaluations == 0) {
1101 minForResL = 0.0;
1102 }
1103 sumOverL += minForResL;
1104 }
1105 currentResK += sumOverL;
1106 }
1107 if (currentResK < minForResK) {
1108 minForResK = currentResK;
1109 }
1110 }
1111 if (rkEvals == 0) {
1112 minForResK = 0.0;
1113 blockedResidues.add(resk);
1114 }
1115 sumOverK += minForResK;
1116 }
1117 return sumOverK;
1118 }
1119
1120 public void logIfRank0(String msg) {
1121 if (rank0) {
1122 logger.info(msg);
1123 }
1124 }
1125
1126 public void logIfRank0(String msg, Level level) {
1127 if (rank0) {
1128 logger.log(level, msg);
1129 }
1130 }
1131
1132
1133
1134
1135
1136
1137
1138 public double optimize(Algorithm algorithm) {
1139 this.algorithm = algorithm;
1140 return optimize();
1141 }
1142
1143
1144
1145
1146
1147
1148 public double optimize() {
1149 double e = 0;
1150 try {
1151
1152 CompositeConfiguration properties = molecularAssembly.getProperties();
1153 boolean ignoreNA = properties.getBoolean("ignoreNA", false);
1154 if (ignoreNA) {
1155 logger.info(" Ignoring nucleic acids.");
1156 }
1157
1158 logger.info(format("\n Rotamer Library: %s", library.getLibrary()));
1159 logger.info(format(" Algorithm: %s", algorithm));
1160 logger.info(format(" Goldstein Criteria: %b", useGoldstein));
1161 logger.info(format(" Three-Body Energies: %b\n", threeBodyTerm));
1162
1163
1164
1165
1166 allResiduesList = new ArrayList<>();
1167
1168 Polymer[] polymers = molecularAssembly.getChains();
1169 for (Polymer polymer : polymers) {
1170 List<Residue> current = polymer.getResidues();
1171 for (Residue residuej : current) {
1172 residuej.setRotamers(library);
1173 if (residuej.getRotamers() != null) {
1174 if (!(ignoreNA && residuej.getResidueType() == Residue.ResidueType.NA)) {
1175 allResiduesList.add(residuej);
1176 }
1177 }
1178 }
1179 }
1180
1181 sortResidues(allResiduesList);
1182 sortResidues(residueList);
1183
1184
1185 if (ignoreNA) {
1186 List<Residue> onlyAA = new ArrayList<>();
1187 for (Residue res : residueList) {
1188 if (res.getResidueType() != Residue.ResidueType.NA) {
1189 onlyAA.add(res);
1190 }
1191 }
1192 residueList = onlyAA;
1193 }
1194
1195 RotamerLibrary.initializeDefaultAtomicCoordinates(
1196 molecularAssembly.getChains());
1197
1198 nAllResidues = allResiduesList.size();
1199 allResiduesArray = allResiduesList.toArray(new Residue[nAllResidues]);
1200
1201
1202
1203
1204
1205
1206
1207 if (distance > 0) {
1208 dM = new DistanceMatrix(molecularAssembly, algorithmListener, allResiduesArray,
1209 allResiduesList, distanceMethod, distance, twoBodyCutoffDist, threeBodyCutoffDist);
1210 }
1211
1212 if (residueList != null) {
1213
1214
1215 optimum = new int[residueList.size()];
1216
1217 done = false;
1218 terminate = false;
1219
1220 switch (algorithm) {
1221 case INDEPENDENT -> e = independent(residueList);
1222 case BRUTE_FORCE -> e = bruteForce(residueList);
1223 case ALL -> {
1224 e = globalOptimization(residueList);
1225 arraycopy(optimumSubset, 0, optimum, 0, residueList.size());
1226 }
1227 case WINDOW -> {
1228 if(genZ) {
1229 e = slidingWindowCentered(residueList);
1230 } else {
1231 e = slidingWindowOptimization(residueList, windowSize, increment, revert, distance,
1232 direction, -1);
1233 }
1234 }
1235 case BOX -> e = boxOpt.boxOptimization(residueList);
1236 default -> {
1237 }
1238 }
1239 terminate = false;
1240 done = true;
1241 }
1242 } catch (Exception exception) {
1243 exception.printStackTrace();
1244 } finally {
1245 try {
1246 if (energyWriter != null) {
1247 energyWriter.close();
1248 }
1249 } catch (IOException ex) {
1250 logger.severe(" Exception in closing buffered energy writer.");
1251 }
1252 }
1253
1254 return e;
1255 }
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267 public double rotamerOptimization(MolecularAssembly molecularAssembly, Residue[] residues, int i,
1268 double lowEnergy, int[] optimum) {
1269
1270
1271 if (i == 0) {
1272 evaluatedPermutations = 0;
1273 }
1274
1275 int nResidues = residues.length;
1276 Residue current = residues[i];
1277 Rotamer[] rotamers = current.getRotamers();
1278 int lenri = rotamers.length;
1279 double currentEnergy = Double.MAX_VALUE;
1280 List<Residue> resList = Arrays.asList(residues);
1281 if (i < nResidues - 1) {
1282
1283
1284 int minRot = -1;
1285 for (int ri = 0; ri < lenri; ri++) {
1286 applyRotamer(current, rotamers[ri]);
1287 double rotEnergy = rotamerOptimization(molecularAssembly, residues, i + 1, lowEnergy,
1288 optimum);
1289 if (rotEnergy < currentEnergy) {
1290 currentEnergy = rotEnergy;
1291 }
1292 if (rotEnergy < lowEnergy) {
1293 minRot = ri;
1294 lowEnergy = rotEnergy;
1295 }
1296 }
1297 if (minRot > -1) {
1298 optimum[i] = minRot;
1299 }
1300 } else {
1301
1302
1303
1304
1305
1306 int[] rotArray = copyOf(optimum, nResidues);
1307 for (int ri = 0; ri < lenri; ri++) {
1308 applyRotamer(current, rotamers[ri]);
1309 double rotEnergy = Double.NaN;
1310 try {
1311 rotArray[nResidues - 1] = ri;
1312 rotEnergy = currentEnergy(resList) + eE.getTotalRotamerPhBias(resList, rotArray, pH, pHRestraint);
1313 logger.info(format(" %d Energy: %s", ++evaluatedPermutations, formatEnergy(rotEnergy)));
1314 } catch (ArithmeticException ex) {
1315 logger.info(
1316 format(" %d Energy set to NaN (unreasonable conformation)", ++evaluatedPermutations));
1317 }
1318 if (algorithmListener != null) {
1319 algorithmListener.algorithmUpdate(molecularAssembly);
1320 }
1321 if (rotEnergy < currentEnergy) {
1322 currentEnergy = rotEnergy;
1323 }
1324 if (rotEnergy < lowEnergy) {
1325 lowEnergy = rotEnergy;
1326 optimum[nResidues - 1] = ri;
1327 }
1328 }
1329 }
1330 return currentEnergy;
1331 }
1332
1333
1334
1335
1336
1337 public void setPHRestraint(double pHRestraint) {this.pHRestraint = pHRestraint;}
1338
1339
1340
1341
1342 public void setpH(double pH) {
1343 this.pH = pH;
1344 }
1345
1346
1347
1348
1349 public void setRecomputeSelf(boolean recomputeSelf) {
1350 this.recomputeSelf = recomputeSelf;
1351 }
1352
1353
1354
1355
1356
1357 public double getPHRestraint() {
1358 return pHRestraint;
1359 }
1360
1361
1362
1363
1364
1365 public double getPH() {
1366 return pH;
1367 }
1368
1369
1370
1371
1372
1373
1374 public void setApproxBoxLength(double approxBoxLength) {
1375 boxOpt.approxBoxLength = approxBoxLength;
1376 }
1377
1378
1379
1380
1381
1382
1383 public void setBoxBorderSize(double boxBorderSize) {
1384 boxOpt.cellBorderSize = boxBorderSize;
1385 }
1386
1387
1388
1389
1390
1391
1392 public void setBoxEnd(int boxEnd) {
1393
1394 boxOpt.cellEnd = boxEnd;
1395 }
1396
1397
1398
1399
1400
1401
1402
1403 public void setBoxInclusionCriterion(int boxInclusionCriterion) {
1404 boxOpt.boxInclusionCriterion = boxInclusionCriterion;
1405 }
1406
1407
1408
1409
1410
1411
1412 public void setBoxStart(int boxStart) {
1413 boxOpt.cellStart = boxStart;
1414 }
1415
1416
1417
1418
1419
1420
1421 public void setTitrationBoxes(boolean titrationBoxes) {boxOpt.titrationBoxes = titrationBoxes;}
1422
1423
1424
1425
1426
1427
1428 public void setTitrationBoxSize(double titrationBoxSize) {boxOpt.titrationBoxSize = titrationBoxSize;}
1429
1430
1431
1432
1433
1434
1435 public void setCoordinatesToEnsemble(int ensnum) {
1436 if (ensembleStates != null && !ensembleStates.isEmpty()) {
1437 ensnum %= ensembleStates.size();
1438 ResidueState.revertAllCoordinates(residueList, ensembleStates.get(ensnum).val());
1439 } else {
1440 throw new IllegalArgumentException(" Ensemble states not initialized!");
1441 }
1442 }
1443
1444
1445
1446
1447
1448
1449 public void setDecomposeOriginal(boolean decomposeOriginal) {
1450 this.decomposeOriginal = decomposeOriginal;
1451 }
1452
1453
1454
1455
1456
1457
1458 public void setDirection(Direction direction) {
1459 this.direction = direction;
1460 }
1461
1462
1463
1464
1465
1466
1467 public void setDistanceCutoff(double distance) {
1468 this.distance = distance;
1469 }
1470
1471
1472
1473
1474
1475
1476 public void setEnergyRestartFile(File file) {
1477 loadEnergyRestart = true;
1478 energyRestartFile = file;
1479 }
1480
1481
1482
1483
1484
1485
1486
1487 public void setEnsemble(int ensemble, double ensembleBuffer) {
1488 this.ensembleNumber = ensemble;
1489 this.ensembleBuffer = ensembleBuffer;
1490 this.ensembleBufferStep = 0.1 * ensembleBuffer;
1491 if (ensemble > 1) {
1492 setPruning(0);
1493 }
1494 }
1495
1496
1497
1498
1499
1500
1501 public void setIncrement(int increment) {
1502 this.increment = increment;
1503 }
1504
1505
1506
1507
1508
1509
1510 public void setMaxRotCheckDepth(int maxRotCheckDepth) {
1511 this.maxRotCheckDepth = maxRotCheckDepth;
1512 }
1513
1514
1515
1516
1517
1518
1519 public void setMinimumNumberAcceptedNARotamers(int minNumberAcceptedNARotamers) {
1520 if (minNumberAcceptedNARotamers > 0) {
1521 this.minNumberAcceptedNARotamers = minNumberAcceptedNARotamers;
1522 } else {
1523 logger.warning(
1524 "\n Minimum number of accepted NA rotamers must be a positive integer.\n Setting to default value 10.\n");
1525 this.minNumberAcceptedNARotamers = 10;
1526 }
1527 }
1528
1529
1530
1531
1532
1533
1534
1535 public void setMonteCarlo(boolean monteCarlo, int nMCsteps) {
1536 this.monteCarlo = monteCarlo;
1537 this.nMCSteps = nMCsteps;
1538 }
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548 public void setMonteCarloTesting(boolean bool) {
1549 this.monteCarloTesting = bool;
1550 }
1551
1552
1553
1554
1555
1556
1557 public void setNucleicCorrectionThreshold(double nucleicCorrectionThreshold) {
1558 if (nucleicCorrectionThreshold >= 0) {
1559 this.nucleicCorrectionThreshold = nucleicCorrectionThreshold;
1560 } else {
1561 logger.warning(
1562 "\n Correction threshold must be >= 0. Setting to default of 0 (threshold inactive).\n");
1563 this.nucleicCorrectionThreshold = 0;
1564 }
1565 }
1566
1567
1568
1569
1570
1571
1572 public void setNucleicPruningFactor(double nucleicPruningFactor) {
1573 this.nucleicPruningFactor = nucleicPruningFactor;
1574 this.nucleicPairsPruningFactor = ((1.0 + nucleicPruningFactor) / 2);
1575 }
1576
1577
1578
1579
1580
1581
1582 public void setNumXYZBoxes(int[] numXYZBoxes) {
1583 arraycopy(numXYZBoxes, 0, boxOpt.numXYZCells, 0, boxOpt.numXYZCells.length);
1584 }
1585
1586
1587
1588
1589
1590
1591 public void setPairClashThreshold(double pairClashThreshold) {
1592 this.pairClashThreshold = pairClashThreshold;
1593 }
1594
1595
1596
1597
1598
1599
1600
1601 public void setPrintFiles(boolean printFiles) {
1602 this.printFiles = printFiles;
1603 }
1604
1605
1606
1607
1608
1609
1610 public void setPruning(int set) {
1611 if (set == 0) {
1612 this.pruneClashes = false;
1613 this.prunePairClashes = false;
1614 } else if (set == 1) {
1615 this.pruneClashes = true;
1616 this.prunePairClashes = false;
1617 } else if (set == 2) {
1618 this.pruneClashes = true;
1619 this.prunePairClashes = true;
1620 }
1621 }
1622
1623
1624
1625
1626
1627
1628 public void setResiduesIgnoreNull(List<Residue> residues) {
1629 residueList = new ArrayList<>();
1630 logger.fine(" Optimizing these residues: ");
1631 for (Residue r : residues) {
1632 if (r.getRotamers() != null) {
1633 residueList.add(r);
1634 logger.fine(format("\t%s", r));
1635 } else {
1636 logger.fine(format(" not \t%s", r));
1637 }
1638 }
1639 }
1640
1641
1642
1643
1644
1645
1646 public void setRevert(boolean revert) {
1647 this.revert = revert;
1648 }
1649
1650 public void setRotamerLibrary(RotamerLibrary lib) {
1651 library = lib;
1652 }
1653
1654
1655
1656
1657
1658
1659 public void setSingletonClashThreshold(double singletonClashThreshold) {
1660 this.clashThreshold = singletonClashThreshold;
1661 }
1662
1663
1664
1665
1666
1667
1668 public void setSuperpositionThreshold(double superpositionThreshold) {
1669 this.superpositionThreshold = superpositionThreshold;
1670 }
1671
1672
1673
1674
1675
1676
1677
1678
1679 public void setThreeBodyCutoff(double threeBodyCutoffDist) {
1680 this.threeBodyCutoffDist = threeBodyCutoffDist;
1681 if (this.threeBodyCutoffDist < 0) {
1682 logger.info("Warning: threeBodyCutoffDist should not be less than 0.");
1683 }
1684 }
1685
1686
1687
1688
1689
1690
1691
1692 public void setThreeBodyEnergy(boolean threeBodyTerm) {
1693 this.threeBodyTerm = threeBodyTerm;
1694 }
1695
1696
1697
1698
1699
1700
1701
1702
1703 public void setTwoBodyCutoff(double twoBodyCutoffDist) {
1704 this.twoBodyCutoffDist = twoBodyCutoffDist;
1705 if (this.twoBodyCutoffDist < 0) {
1706 logger.info("Warning: threeBodyCutoffDist should not be less than 0.");
1707 }
1708 }
1709
1710
1711
1712
1713
1714
1715 public void setUseGoldstein(boolean useGoldstein) {
1716 this.useGoldstein = useGoldstein;
1717 }
1718
1719
1720
1721
1722
1723
1724 public void setWindowSize(int windowSize) {
1725 this.windowSize = windowSize;
1726 if (this.increment > windowSize) {
1727 logger.info(format(" Decreasing increment to match window size %d", windowSize));
1728 this.increment = windowSize;
1729 }
1730 }
1731
1732
1733
1734
1735 @Override
1736 public void terminate() {
1737 terminate = true;
1738 while (!done) {
1739 synchronized (this) {
1740 try {
1741 wait(1);
1742 } catch (InterruptedException e) {
1743 logger.log(Level.WARNING, " Exception terminating rotamer optimization.\n", e);
1744 }
1745 }
1746 }
1747 }
1748
1749
1750
1751
1752 @Override
1753 public String toString() {
1754 if (eR != null) {
1755 return eR.toString();
1756 } else {
1757 return null;
1758 }
1759 }
1760
1761 public void turnOffAllResidues(Residue[] residues) {
1762 if (residues == null) {
1763 return;
1764 }
1765 for (Residue residue : residues) {
1766 turnOffResidue(residue);
1767 }
1768 }
1769
1770 public void turnOffResidue(Residue residue) {
1771 turnOffAtoms(residue);
1772 applyDefaultRotamer(residue);
1773 }
1774
1775 public void turnOnAllResidues(Residue[] residues) {
1776 if (residues == null) {
1777 return;
1778 }
1779 for (Residue residue : residues) {
1780 turnOnAtoms(residue);
1781 }
1782 }
1783
1784 public void turnOnResidue(Residue residue, int ri) {
1785 turnOnAtoms(residue);
1786 Rotamer[] rotamers = residue.getRotamers();
1787 applyRotamer(residue, rotamers[ri]);
1788 }
1789
1790
1791
1792
1793 public void turnRotamerPairEliminationOff() {
1794 logger.info(" Turning off pair eliminations.");
1795 pairEliminationOn = false;
1796 }
1797
1798
1799
1800
1801 public void turnRotamerSingleEliminationOff() {
1802 logger.info(" Turning off single eliminations.");
1803 selfEliminationOn = false;
1804 }
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817 private double decomposedRotamerOptimization(Residue[] residues, int i, double lowEnergy,
1818 int[] optimum, int[] currentRotamers) {
1819
1820
1821 if (i == 0) {
1822 evaluatedPermutations = 0;
1823 }
1824
1825 int nResidues = residues.length;
1826 Residue current = residues[i];
1827 Rotamer[] rotamers = current.getRotamers();
1828 int lenri = rotamers.length;
1829 double currentEnergy = Double.MAX_VALUE;
1830 if (i < nResidues - 1) {
1831
1832
1833 for (int ri = 0; ri < lenri; ri++) {
1834 if (eR.check(i, ri)) {
1835 continue;
1836 }
1837 currentRotamers[i] = ri;
1838 double rotEnergy = decomposedRotamerOptimization(residues, i + 1, lowEnergy, optimum,
1839 currentRotamers);
1840 if (rotEnergy < lowEnergy) {
1841 lowEnergy = rotEnergy;
1842 }
1843 if (rotEnergy < currentEnergy) {
1844 currentEnergy = rotEnergy;
1845 }
1846 }
1847 } else {
1848
1849
1850 for (int ri = 0; ri < lenri; ri++) {
1851 if (eR.check(i, ri)) {
1852 continue;
1853 }
1854 currentRotamers[i] = ri;
1855 double rotEnergy = computeEnergy(residues, currentRotamers, false);
1856 ++evaluatedPermutations;
1857 if (rotEnergy < currentEnergy) {
1858 currentEnergy = rotEnergy;
1859 }
1860 if (rotEnergy < lowEnergy) {
1861
1862
1863
1864
1865
1866 arraycopy(currentRotamers, 0, optimum, 0, optimum.length);
1867 if (evaluatedPermutations > 1) {
1868 logger.info(
1869 format(" Minimum energy update: %f < %f, permutation %d", rotEnergy, lowEnergy,
1870 evaluatedPermutations));
1871 String permutation = " Rotamer permutation: " + optimum[0];
1872 for (int j = 1; j < nResidues; j++) {
1873 permutation = permutation.concat(", " + optimum[j]);
1874 }
1875 logger.info(permutation);
1876 } else {
1877 logger.info(format(" First minimum energy (permutation 1): %f", rotEnergy));
1878 }
1879 lowEnergy = rotEnergy;
1880 }
1881 }
1882 }
1883 return currentEnergy;
1884 }
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899 private double rotamerOptimizationMC(Residue[] residues, int[] optimum, int[] initialRots,
1900 int maxIters, boolean randomizeRots, boolean useAllElims) {
1901
1902 long initTime = -System.nanoTime();
1903 if (randomizeRots) {
1904 randomizeRotamers(initialRots, residues, true);
1905 }
1906
1907 int nRes = residues.length;
1908 arraycopy(initialRots, 0, optimum, 0, nRes);
1909 assert optimum.length == nRes;
1910 assert initialRots.length == nRes;
1911
1912 RotamerMatrixMC rmc = new RotamerMatrixMC(initialRots, residues, useForceFieldEnergy, this);
1913 rmc.setTemperature(mcTemp);
1914 RotamerMatrixMove rmove = new RotamerMatrixMove(useAllElims, initialRots, residues, this, eR,
1915 monteCarloTesting);
1916 List<MCMove> rmList = new ArrayList<>(1);
1917 rmList.add(rmove);
1918
1919 double initialEnergy = computeEnergy(residues, initialRots, false);
1920 double optimumEnergy = initialEnergy;
1921 double currentEnergy = initialEnergy;
1922
1923 int nAccept = 0;
1924 logIfRank0(
1925 format(" Beginning %d iterations of Monte Carlo search " + "starting from energy %10.6f",
1926 maxIters, initialEnergy));
1927
1928 for (int i = 0; i < maxIters; i++) {
1929 if (rmc.mcStep(rmList, currentEnergy)) {
1930 currentEnergy = rmc.lastEnergy();
1931 ++nAccept;
1932 if (currentEnergy < optimumEnergy) {
1933 optimumEnergy = currentEnergy;
1934 arraycopy(initialRots, 0, optimum, 0, nRes);
1935 }
1936 } else {
1937 currentEnergy = rmc.lastEnergy();
1938 }
1939 }
1940
1941 initTime += System.nanoTime();
1942 double fractAccept = ((double) nAccept) / ((double) maxIters);
1943 logIfRank0(
1944 format(" %d steps of DEE-MC completed in %10.6f seconds", maxIters, (initTime * 1.0E-9)));
1945 logIfRank0(format(" Number of steps accepted: %d for %10.6f of total", nAccept, fractAccept));
1946 logIfRank0(format(" Lowest energy found: %10.6f kcal/mol", optimumEnergy));
1947 logIfRank0(format(" Final energy found: %10.6f kcal/mol", currentEnergy));
1948
1949 return optimumEnergy;
1950 }
1951
1952
1953
1954
1955
1956
1957
1958
1959 private void randomizeRotamers(int[] rotamers, Residue[] residues, boolean useAllElims) {
1960 int nRes = rotamers.length;
1961 for (int i = 0; i < nRes; i++) {
1962 Rotamer[] rotsi = residues[i].getRotamers();
1963 int lenri = rotsi.length;
1964 List<Integer> allowedRots = new ArrayList<>(lenri);
1965
1966 for (int ri = 0; ri < lenri; ri++) {
1967 if (!eR.check(i, ri)) {
1968 allowedRots.add(ri);
1969 }
1970 }
1971
1972 Random rand = new Random();
1973 int nRots = allowedRots.size();
1974 if (monteCarloTesting) {
1975 rand.setSeed(nRots);
1976 }
1977 if (nRots > 1) {
1978 boolean validMove = !useAllElims;
1979 int indexRI;
1980 do {
1981 int ri = rand.nextInt(nRots);
1982 indexRI = allowedRots.get(ri);
1983 if (useAllElims) {
1984 validMove = checkValidMove(i, indexRI, rotamers);
1985 }
1986 } while (!validMove);
1987 rotamers[i] = indexRI;
1988 }
1989 }
1990 }
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005 private double rotamerOptimizationDEE(MolecularAssembly molecularAssembly, Residue[] residues,
2006 int i, int[] currentRotamers, double lowEnergy, int[] optimum, double[] permutationEnergies) {
2007
2008 if (i == 0) {
2009 evaluatedPermutations = 0;
2010 }
2011
2012 int nResidues = residues.length;
2013 Residue residuei = residues[i];
2014 Rotamer[] rotamersi = residuei.getRotamers();
2015 int lenri = rotamersi.length;
2016 double currentEnergy = Double.MAX_VALUE;
2017 List<Residue> resList = Arrays.asList(residues);
2018
2019
2020
2021 if (i < nResidues - 1) {
2022
2023 for (int ri = 0; ri < lenri; ri++) {
2024
2025 if (eR.check(i, ri)) {
2026 continue;
2027 }
2028
2029
2030 boolean deadEnd = false;
2031 for (int j = 0; j < i; j++) {
2032 int rj = currentRotamers[j];
2033 deadEnd = eR.check(j, rj, i, ri);
2034 if (deadEnd) {
2035 break;
2036 }
2037 }
2038 if (deadEnd) {
2039 continue;
2040 }
2041 applyRotamer(residuei, rotamersi[ri]);
2042 currentRotamers[i] = ri;
2043 double rotEnergy = rotamerOptimizationDEE(molecularAssembly, residues, i + 1,
2044 currentRotamers, lowEnergy, optimum, permutationEnergies);
2045 if (rotEnergy < currentEnergy) {
2046 currentEnergy = rotEnergy;
2047 }
2048 if (rotEnergy < lowEnergy) {
2049 optimum[i] = ri;
2050 lowEnergy = rotEnergy;
2051 }
2052 }
2053 } else {
2054 if (ensembleStates == null) {
2055 ensembleStates = new ArrayList<>();
2056 }
2057
2058
2059
2060
2061
2062
2063 for (int ri = 0; ri < lenri; ri++) {
2064
2065 if (eR.check(i, ri)) {
2066 continue;
2067 }
2068 currentRotamers[i] = ri;
2069
2070
2071 boolean deadEnd = false;
2072 for (int j = 0; j < i; j++) {
2073 int rj = currentRotamers[j];
2074 deadEnd = eR.check(j, rj, i, ri);
2075 if (deadEnd) {
2076 break;
2077 }
2078 }
2079 if (deadEnd) {
2080 continue;
2081 }
2082 applyRotamer(residuei, rotamersi[ri]);
2083
2084 approximateEnergy = computeEnergy(residues, currentRotamers, false);
2085 double comparisonEnergy = approximateEnergy;
2086 evaluatedPermutations++;
2087
2088 if (useForceFieldEnergy) {
2089 double amoebaEnergy = Double.NaN;
2090 try {
2091
2092 amoebaEnergy =
2093 currentEnergy(resList) + eE.getTotalRotamerPhBias(resList, currentRotamers, pH, pHRestraint);
2094 } catch (ArithmeticException ex) {
2095 logger.warning(
2096 format(" Exception %s in calculating full AMOEBA energy for permutation %d", ex,
2097 evaluatedPermutations));
2098 }
2099 comparisonEnergy = amoebaEnergy;
2100 }
2101 if (permutationEnergies != null) {
2102 permutationEnergies[evaluatedPermutations - 1] = comparisonEnergy;
2103 }
2104 if (algorithmListener != null) {
2105 algorithmListener.algorithmUpdate(molecularAssembly);
2106 }
2107 if (ensembleNumber > 1) {
2108 if (rank0 && printFiles) {
2109 try {
2110 FileWriter fw = new FileWriter(ensembleFile, true);
2111 BufferedWriter bw = new BufferedWriter(fw);
2112 bw.write(format("MODEL %d", evaluatedPermutations));
2113 for (int j = 0; j < 75; j++) {
2114 bw.write(" ");
2115 }
2116 bw.newLine();
2117 bw.flush();
2118 ensembleFilter.writeFile(ensembleFile, true);
2119 bw.write("ENDMDL");
2120 for (int j = 0; j < 64; j++) {
2121 bw.write(" ");
2122 }
2123 bw.newLine();
2124 bw.close();
2125 } catch (IOException e) {
2126 logger.warning(format("Exception writing to file: %s", ensembleFile.getName()));
2127 }
2128 }
2129 ResidueState[] states = ResidueState.storeAllCoordinates(residues);
2130 ensembleStates.add(new ObjectPair<>(states, comparisonEnergy));
2131 }
2132
2133 if (comparisonEnergy < currentEnergy) {
2134 currentEnergy = comparisonEnergy;
2135 }
2136
2137 if (comparisonEnergy < lowEnergy) {
2138 lowEnergy = comparisonEnergy;
2139 optimum[i] = ri;
2140 }
2141
2142 if (useForceFieldEnergy) {
2143
2144 logIfRank0(format(" %6e AMOEBA: %12.4f 3-Body: %12.4f Neglected: %12.4f (%12.4f)",
2145 (double) evaluatedPermutations, comparisonEnergy, approximateEnergy,
2146 comparisonEnergy - approximateEnergy, lowEnergy));
2147 } else {
2148 logIfRank0(
2149 format(" %12s %25f %25f", evaluatedPermutations, approximateEnergy, lowEnergy));
2150 }
2151 }
2152
2153 ensembleStates.sort(null);
2154 }
2155 return currentEnergy;
2156 }
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167 private double dryRun(Residue[] residues, int i, int[] currentRotamers) {
2168
2169 if (i == 0) {
2170 evaluatedPermutations = 0;
2171 evaluatedPermutationsPrint = 1000;
2172 }
2173
2174 if (evaluatedPermutations >= evaluatedPermutationsPrint) {
2175 if (evaluatedPermutations % evaluatedPermutationsPrint == 0) {
2176 logIfRank0(
2177 format(" The permutations have reached %10.4e.", (double) evaluatedPermutationsPrint));
2178 evaluatedPermutationsPrint *= 10;
2179 }
2180 }
2181
2182 int nResidues = residues.length;
2183 Residue residuei = residues[i];
2184 Rotamer[] rotamersi = residuei.getRotamers();
2185 int lenri = rotamersi.length;
2186 if (i < nResidues - 1) {
2187 for (int ri = 0; ri < lenri; ri++) {
2188 if (eR.check(i, ri)) {
2189 continue;
2190 }
2191 boolean deadEnd = false;
2192 for (int j = 0; j < i; j++) {
2193 int rj = currentRotamers[j];
2194 deadEnd = eR.check(j, rj, i, ri);
2195 if (deadEnd) {
2196 break;
2197 }
2198 }
2199 if (deadEnd) {
2200 continue;
2201 }
2202 currentRotamers[i] = ri;
2203 dryRun(residues, i + 1, currentRotamers);
2204 }
2205 } else {
2206
2207 for (int ri = 0; ri < lenri; ri++) {
2208 if (eR.check(i, ri)) {
2209 continue;
2210 }
2211 currentRotamers[i] = ri;
2212 boolean deadEnd = false;
2213 for (int j = 0; j < i; j++) {
2214 int rj = currentRotamers[j];
2215 deadEnd = eR.check(j, rj, i, ri);
2216 if (deadEnd) {
2217 break;
2218 }
2219 }
2220 if (!deadEnd) {
2221 evaluatedPermutations++;
2222 }
2223 }
2224 }
2225
2226 return 0.0;
2227 }
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240 private double dryRunForEnsemble(Residue[] residues, int i, int[] currentRotamers,
2241 double gmecEnergy, double[] permutationEnergies, int[][] permutations) {
2242
2243 if (i == 0) {
2244 evaluatedPermutations = 0;
2245 }
2246 int nResidues = residues.length;
2247 Residue residuei = residues[i];
2248 Rotamer[] rotamersi = residuei.getRotamers();
2249 int lenri = rotamersi.length;
2250 if (i < nResidues - 1) {
2251 for (int ri = 0; ri < lenri; ri++) {
2252 if (eR.check(i, ri)) {
2253 continue;
2254 }
2255 boolean deadEnd = false;
2256 for (int j = 0; j < i; j++) {
2257 int rj = currentRotamers[j];
2258 deadEnd = eR.check(j, rj, i, ri);
2259 if (deadEnd) {
2260 break;
2261 }
2262 }
2263 if (deadEnd) {
2264 continue;
2265 }
2266 currentRotamers[i] = ri;
2267 dryRunForEnsemble(residues, i + 1, currentRotamers, gmecEnergy, permutationEnergies,
2268 permutations);
2269 }
2270 } else {
2271
2272 for (int ri = 0; ri < lenri; ri++) {
2273 if (eR.check(i, ri)) {
2274 continue;
2275 }
2276 currentRotamers[i] = ri;
2277 boolean deadEnd = false;
2278 for (int j = 0; j < i; j++) {
2279 int rj = currentRotamers[j];
2280 deadEnd = eR.check(j, rj, i, ri);
2281 if (deadEnd) {
2282 break;
2283 }
2284 }
2285 if (deadEnd) {
2286 continue;
2287 }
2288 if (permutationEnergies[evaluatedPermutations] - gmecEnergy < ensembleEnergy) {
2289 permutations[evaluatedPermutations] = new int[nResidues];
2290 arraycopy(currentRotamers, 0, permutations[evaluatedPermutations], 0, nResidues);
2291 }
2292 evaluatedPermutations++;
2293 }
2294 }
2295 return 0.0;
2296 }
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306 public void partitionFunction(Residue[] residues, int i, int[] currentRotamers) throws Exception {
2307
2308 double LOG10 = log(10.0);
2309 double temperature = 298.15;
2310 if (i == 0) {
2311 totalBoltzmann = 0;
2312 evaluatedPermutations = 0;
2313 evaluatedPermutationsPrint = 1000;
2314 }
2315
2316 if (evaluatedPermutations >= evaluatedPermutationsPrint) {
2317 if (evaluatedPermutations % evaluatedPermutationsPrint == 0) {
2318 logIfRank0(
2319 format(" The permutations have reached %10.4e.", (double) evaluatedPermutationsPrint));
2320 evaluatedPermutationsPrint *= 10;
2321 }
2322 }
2323
2324 int nResidues = residues.length;
2325 Residue residuei = residues[i];
2326 Rotamer[] rotamersi = residuei.getRotamers();
2327 int lenri = rotamersi.length;
2328 if (i < nResidues - 1) {
2329 for (int ri = 0; ri < lenri; ri++) {
2330 if (eR.check(i, ri)) {
2331 continue;
2332 }
2333 boolean deadEnd = false;
2334 for (int j = 0; j < i; j++) {
2335 int rj = currentRotamers[j];
2336 deadEnd = eR.check(j, rj, i, ri);
2337 if (deadEnd) {
2338 break;
2339 }
2340 }
2341 if (deadEnd) {
2342 continue;
2343 }
2344 currentRotamers[i] = ri;
2345 partitionFunction(residues, i + 1, currentRotamers);
2346 }
2347 } else {
2348
2349 for (int ri = 0; ri < lenri; ri++) {
2350 if (eR.check(i, ri)) {
2351 continue;
2352 }
2353 currentRotamers[i] = ri;
2354 boolean deadEnd = false;
2355 for (int j = 0; j < i; j++) {
2356 int rj = currentRotamers[j];
2357 deadEnd = eR.check(j, rj, i, ri);
2358 if (deadEnd) {
2359 break;
2360 }
2361 }
2362 if (!deadEnd) {
2363 evaluatedPermutations++;
2364
2365 energyRegion.init(eE, residues, currentRotamers, threeBodyTerm);
2366 parallelTeam.execute(energyRegion);
2367 double selfEnergy = energyRegion.getSelf();
2368
2369 if (recomputeSelf) {
2370 int count = 0;
2371 for (Residue residue : residues) {
2372 double bias7 = 0;
2373 double biasCurrent = 0;
2374 Rotamer[] rotamers = residue.getRotamers();
2375 int currentRotamer = currentRotamers[count];
2376 switch (rotamers[currentRotamer].getName()) {
2377 case "HIE" -> {
2378 bias7 = (LOG10 * Constants.R * temperature * (TitrationUtils.Titration.HIStoHIE.pKa - 7)) -
2379 TitrationUtils.Titration.HIStoHIE.freeEnergyDiff;
2380 biasCurrent = (LOG10 * Constants.R * temperature * (TitrationUtils.Titration.HIStoHIE.pKa - pH)) -
2381 TitrationUtils.Titration.HIStoHIE.freeEnergyDiff;
2382 }
2383 case "HID" -> {
2384 bias7 = (LOG10 * Constants.R * temperature * (TitrationUtils.Titration.HIStoHID.pKa - 7)) -
2385 TitrationUtils.Titration.HIStoHID.freeEnergyDiff;
2386 biasCurrent = (LOG10 * Constants.R * temperature * (TitrationUtils.Titration.HIStoHID.pKa - pH)) -
2387 TitrationUtils.Titration.HIStoHID.freeEnergyDiff;
2388 }
2389 case "ASP" -> {
2390 bias7 = (LOG10 * Constants.R * temperature * (TitrationUtils.Titration.ASHtoASP.pKa - 7)) -
2391 TitrationUtils.Titration.ASHtoASP.freeEnergyDiff;
2392 biasCurrent = (LOG10 * Constants.R * temperature * (TitrationUtils.Titration.ASHtoASP.pKa - pH)) -
2393 TitrationUtils.Titration.ASHtoASP.freeEnergyDiff;
2394 }
2395 case "GLU" -> {
2396 bias7 = (LOG10 * Constants.R * temperature * (TitrationUtils.Titration.GLHtoGLU.pKa - 7)) -
2397 TitrationUtils.Titration.GLHtoGLU.freeEnergyDiff;
2398 biasCurrent = (LOG10 * Constants.R * temperature * (TitrationUtils.Titration.GLHtoGLU.pKa - pH)) -
2399 TitrationUtils.Titration.GLHtoGLU.freeEnergyDiff;
2400 }
2401 case "LYD" -> {
2402 bias7 = (LOG10 * Constants.R * temperature * (TitrationUtils.Titration.LYStoLYD.pKa - 7)) -
2403 TitrationUtils.Titration.LYStoLYD.freeEnergyDiff;
2404 biasCurrent = (LOG10 * Constants.R * temperature * (TitrationUtils.Titration.LYStoLYD.pKa - pH)) -
2405 TitrationUtils.Titration.LYStoLYD.freeEnergyDiff;
2406 }
2407 default -> {
2408 }
2409 }
2410 selfEnergy = selfEnergy - bias7 + biasCurrent;
2411 count += 1;
2412 }
2413 }
2414
2415
2416 double totalEnergy = eE.getBackboneEnergy() + selfEnergy +
2417 energyRegion.getTwoBody() + energyRegion.getThreeBody();
2418
2419
2420 if (evaluatedPermutations == 1) {
2421 refEnergy = totalEnergy;
2422 }
2423 double boltzmannWeight = Math.exp((-1.0 / (Constants.kB * 298.15)) * (totalEnergy - refEnergy));
2424
2425
2426 for (int res=0; res < residues.length; res++) {
2427 int currentRotamer = currentRotamers[res];
2428 populationBoltzmann[res][currentRotamer] += boltzmannWeight;
2429 }
2430
2431
2432 totalBoltzmann += boltzmannWeight;
2433 }
2434 }
2435 }
2436 }
2437
2438
2439
2440
2441
2442
2443 public double getRefEnergy() {
2444 return refEnergy;
2445 }
2446
2447
2448
2449
2450
2451
2452 public double getTotalBoltzmann() {
2453 return totalBoltzmann;
2454 }
2455
2456
2457
2458
2459
2460
2461 public double[][] getFraction() {
2462 return fraction;
2463 }
2464
2465
2466
2467
2468
2469
2470 public double[][] getPopulationBoltzmann() {
2471 return populationBoltzmann;
2472 }
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482 public void getFractions(Residue[] residues, int i, int[] currentRotamers) throws Exception {
2483 populationBoltzmann = new double[residues.length][56];
2484 if(!usingBoxOptimization){
2485 partitionFunction(residues, i, currentRotamers);
2486 optimum = new int[residues.length];
2487 for (int m = 0; m < fraction.length; m++) {
2488 for (int n = 0; n < 56; n++) {
2489 fraction[m][n] = populationBoltzmann[m][n] / totalBoltzmann;
2490 if(n > 0 && fraction[m][n] > fraction[m][n-1]){
2491 optimum[m] = n;
2492 } else if(n == 0){
2493 optimum[m] = n;
2494 }
2495 }
2496 Rotamer highestPopRot = residues[m].getRotamers()[optimum[m]];
2497 RotamerLibrary.applyRotamer(residues[m],highestPopRot);
2498 }
2499 }
2500 logger.info("\n Total permutations evaluated: " + evaluatedPermutations + "\n");
2501 }
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511 public void getFractions(Residue[] residues, int i, int[] currentRotamers, boolean usingBoxOptimization) throws Exception {
2512 double [][] fractionSubset = new double[residues.length][56];
2513 populationBoltzmann = new double[residues.length][56];
2514 partitionFunction(residues, i, currentRotamers);
2515 optimumSubset = new int[residues.length];
2516 for (int m = 0; m < fractionSubset.length; m++) {
2517 for (int n = 0; n < 56; n++) {
2518 fractionSubset[m][n] = populationBoltzmann[m][n] / totalBoltzmann;
2519 if(n > 0 && fractionSubset[m][n] > fractionSubset[m][n-1]){
2520 optimumSubset[m] = n;
2521 } else if(n == 0){
2522 optimumSubset[m] = n;
2523 }
2524 }
2525 Rotamer highestPopRot = residues[m].getRotamers()[optimumSubset[m]];
2526 RotamerLibrary.applyRotamer(residues[m],highestPopRot);
2527 Residue residue = residues[m];
2528 int index = residueList.indexOf(residue);
2529 fraction[index] = fractionSubset[m];
2530 optimum[index] = optimumSubset[m];
2531 }
2532 logger.info("\n Total permutations evaluated: " + evaluatedPermutations + "\n");
2533 }
2534
2535
2536
2537
2538
2539
2540 public double[][] getProtonationPopulations(Residue[] residues){
2541 double[][] populations = new double[residues.length][3];
2542 int residueIndex = 0;
2543 for (Residue residue : residues) {
2544 int index = residueList.indexOf(residue);
2545
2546 double protSum = 0;
2547 double deprotSum = 0;
2548 double tautomerSum = 0;
2549 Rotamer[] rotamers = residue.getRotamers();
2550 for (int rotIndex=0; rotIndex < rotamers.length; rotIndex++) {
2551 switch (rotamers[rotIndex].getName()) {
2552 case "HIS":
2553 case "LYS":
2554 case "GLH":
2555 case "ASH":
2556 case "CYS":
2557 protSum += fraction[index][rotIndex];
2558 populations[residueIndex][0] = protSum;
2559 break;
2560 case "HIE":
2561 case "LYD":
2562 case "GLU":
2563 case "ASP":
2564 case "CYD":
2565 deprotSum += fraction[index][rotIndex];
2566 populations[residueIndex][1] = deprotSum;
2567 break;
2568 case "HID":
2569 tautomerSum += fraction[index][rotIndex];
2570 populations[residueIndex][2] = tautomerSum;
2571 break;
2572 default:
2573 break;
2574 }
2575 }
2576 String formatedProtSum = format("%.6f", protSum);
2577 String formatedDeprotSum = format("%.6f", deprotSum);
2578 String formatedTautomerSum = format("%.6f", tautomerSum);
2579 switch (residue.getName()) {
2580 case "HIS":
2581 case "HIE":
2582 case "HID":
2583 logger.info(residue.getResidueNumber() + "\tHIS" + "\t" + formatedProtSum + "\t" +
2584 "HIE" + "\t" + formatedDeprotSum + "\t" +
2585 "HID" + "\t" + formatedTautomerSum);
2586 break;
2587 case "LYS":
2588 case "LYD":
2589 logger.info(residue.getResidueNumber() + "\tLYS" + "\t" + formatedProtSum + "\t" +
2590 "LYD" + "\t" + formatedDeprotSum);
2591 break;
2592 case "ASH":
2593 case "ASP":
2594 logger.info(residue.getResidueNumber() + "\tASP" + "\t" + formatedDeprotSum + "\t" +
2595 "ASH" + "\t" + formatedProtSum);
2596 break;
2597 case "GLH":
2598 case "GLU":
2599 logger.info(residue.getResidueNumber() + "\tGLU" + "\t" + formatedDeprotSum + "\t" +
2600 "GLH" + "\t" + formatedProtSum);
2601 break;
2602 case "CYS":
2603 case "CYD":
2604 logger.info(residue.getResidueNumber() + "\tCYS" + "\t" + formatedProtSum + "\t" +
2605 "CYD" + "\t" + formatedDeprotSum);
2606 break;
2607 default:
2608 break;
2609 }
2610 residueIndex++;
2611 }
2612
2613
2614 return populations;
2615 }
2616
2617 public double slidingWindowCentered(List<Residue> residueList) throws Exception {
2618 String[] titratableResidues = new String[]{"HIS", "HIE", "HID", "GLU", "GLH", "ASP", "ASH", "LYS", "LYD", "CYS", "CYD"};
2619 List<String> titratableResiudesList = Arrays.asList(titratableResidues);
2620
2621 double e = 0.0;
2622 for (Residue titrationResidue : residueList) {
2623 if (titratableResiudesList.contains(titrationResidue.getName())) {
2624 e = slidingWindowOptimization(residueList, windowSize, increment, revert, distance, Direction.FORWARD, residueList.indexOf(titrationResidue));
2625 }
2626 }
2627 return e;
2628 }
2629
2630
2631
2632
2633
2634
2635 public int[][] getConformers() throws Exception{
2636 int[][] conformers = new int[fraction.length][3];
2637 for(int i = 0; i < fraction.length; i++){
2638 double[] tempArray = new double[fraction[0].length];
2639 java.lang.System.arraycopy(fraction[i], 0, tempArray, 0, fraction[0].length);
2640 List<Double> elements = new ArrayList<Double>();
2641 for (int j = 0; j < tempArray.length; j++) {
2642 elements.add(tempArray[j]);
2643 }
2644 Arrays.sort(tempArray);
2645 int count = -1;
2646 for(int k = tempArray.length-3; k < tempArray.length; k++){
2647 count++;
2648 conformers[i][count] = elements.indexOf(tempArray[k]);
2649 }
2650 }
2651 return conformers;
2652 }
2653
2654
2655
2656
2657
2658
2659
2660 public int[] getOptimumRotamers() {
2661 return optimum;
2662 }
2663
2664
2665
2666
2667
2668
2669
2670 private double independent(List<Residue> residues) {
2671 double e = 0.0;
2672 List<Residue> singletonResidue = new ArrayList<>(Collections.nCopies(1, null));
2673 for (int i = 0; i < residues.size(); i++) {
2674 Residue residue = residues.get(i);
2675 singletonResidue.set(0, residue);
2676 logger.info(format(" Optimizing %s side-chain.", residue));
2677 Rotamer[] rotamers = residue.getRotamers();
2678 e = Double.MAX_VALUE;
2679 int bestRotamer = 0;
2680 double startingEnergy = 0.0;
2681 for (int j = 0; j < rotamers.length; j++) {
2682 Rotamer rotamer = rotamers[j];
2683 RotamerLibrary.applyRotamer(residue, rotamer);
2684 if (algorithmListener != null) {
2685 algorithmListener.algorithmUpdate(molecularAssembly);
2686 }
2687 double newE = Double.NaN;
2688 try {
2689 if (rotamer.isTitrating) {
2690 newE = currentEnergy(singletonResidue) + rotamer.getRotamerPhBias();
2691 } else {
2692 newE = currentEnergy(singletonResidue);
2693 }
2694
2695 if (j == 0) {
2696 startingEnergy = newE;
2697 newE = 0.0;
2698 } else {
2699 newE -= startingEnergy;
2700 }
2701 logger.info(format(" Energy %8s %-2d: %s", residue.toString(rotamers[j]), j, formatEnergy(newE)));
2702 double singularityThreshold = -100000;
2703 if (newE < singularityThreshold) {
2704 String message = format(" Rejecting as energy (%s << %s) is likely an error.", formatEnergy(newE), formatEnergy(singularityThreshold));
2705 logger.info(message);
2706 newE = Double.MAX_VALUE;
2707 }
2708 } catch (ArithmeticException ex) {
2709 logger.info(format(" Exception %s in energy calculations during independent for %s-%d", ex, residue, j));
2710 }
2711 if (newE < e) {
2712 e = newE;
2713 bestRotamer = j;
2714 }
2715 }
2716 Rotamer rotamer = rotamers[bestRotamer];
2717 RotamerLibrary.applyRotamer(residue, rotamer);
2718 optimum[i] = bestRotamer;
2719 logger.info(format(" Best Energy %8s %-2d: %s", residue.toString(rotamer), bestRotamer, formatEnergy(e)));
2720
2721 if (algorithmListener != null) {
2722 algorithmListener.algorithmUpdate(molecularAssembly);
2723 }
2724 if (terminate) {
2725 logger.info(format("\n Terminating after residue %s.\n", residue));
2726 break;
2727 }
2728 }
2729 return e;
2730 }
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740 private boolean firstValidPerm(Residue[] residues, int i, int[] currentRotamers) {
2741 int nResidues = residues.length;
2742 Residue residuei = residues[i];
2743 Rotamer[] rotamersi = residuei.getRotamers();
2744 int lenri = rotamersi.length;
2745 if (i < nResidues - 1) {
2746 for (int ri = 0; ri < lenri; ri++) {
2747 if (eR.check(i, ri)) {
2748 continue;
2749 }
2750 boolean deadEnd = false;
2751 for (int j = 0; j < i; j++) {
2752 int rj = currentRotamers[j];
2753 deadEnd = eR.check(j, rj, i, ri);
2754 if (deadEnd) {
2755 break;
2756 }
2757 }
2758 if (deadEnd) {
2759 continue;
2760 }
2761 currentRotamers[i] = ri;
2762 if (firstValidPerm(residues, i + 1, currentRotamers)) {
2763 return true;
2764 }
2765 }
2766 } else {
2767
2768 for (int ri = 0; ri < lenri; ri++) {
2769 if (eR.check(i, ri)) {
2770 continue;
2771 }
2772 currentRotamers[i] = ri;
2773 boolean deadEnd = false;
2774 for (int j = 0; j < i; j++) {
2775 int rj = currentRotamers[j];
2776 deadEnd = eR.check(j, rj, i, ri);
2777 if (deadEnd) {
2778 break;
2779 }
2780 }
2781 if (!deadEnd) {
2782 break;
2783 }
2784 }
2785 return true;
2786 }
2787 return false;
2788 }
2789
2790
2791
2792
2793
2794
2795
2796 protected double globalOptimization(List<Residue> residueList) {
2797 int currentEnsemble = Integer.MAX_VALUE;
2798 Residue[] residues = residueList.toArray(new Residue[0]);
2799 int nResidues = residues.length;
2800 int[] currentRotamers = new int[nResidues];
2801 optimumSubset = new int[nResidues];
2802
2803 int iterations = 0;
2804 boolean finalTry = false;
2805 int bestEnsembleTargetDiffThusFar = Integer.MAX_VALUE;
2806 double bestBufferThusFar = ensembleBuffer;
2807 double startingBuffer = ensembleBuffer;
2808
2809 if (ensembleEnergy > 0.0) {
2810 ensembleBuffer = ensembleEnergy;
2811 applyEliminationCriteria(residues, true, true);
2812
2813
2814 double permutations = 1;
2815 double singletonPermutations = 1;
2816 for (int i = 0; i < nResidues; i++) {
2817 Residue residue = residues[i];
2818 Rotamer[] rotamers = residue.getRotamers();
2819 int nr = rotamers.length;
2820 if (nr > 1) {
2821 int nrot = 0;
2822 for (int ri = 0; ri < nr; ri++) {
2823 if (!eR.eliminatedSingles[i][ri]) {
2824 nrot++;
2825 }
2826 }
2827 permutations *= rotamers.length;
2828 if (nrot > 1) {
2829 singletonPermutations *= nrot;
2830 }
2831 }
2832 }
2833 dryRun(residues, 0, currentRotamers);
2834 double pairTotalElimination = singletonPermutations - (double) evaluatedPermutations;
2835 double afterPairElim = singletonPermutations - pairTotalElimination;
2836 if (evaluatedPermutations == 0) {
2837 logger.severe(
2838 " No valid path through rotamer space found; try recomputing without pruning or using ensemble.");
2839 }
2840 if (rank0 && printFiles && ensembleFile == null) {
2841 File file = molecularAssembly.getFile();
2842 String filename = FilenameUtils.removeExtension(file.getAbsolutePath());
2843 ensembleFile = new File(filename + ".ens");
2844 if (ensembleFile.exists()) {
2845 for (int i = 2; i < 1000; i++) {
2846 ensembleFile = new File(filename + ".ens_" + i);
2847 if (!ensembleFile.exists()) {
2848 break;
2849 }
2850 }
2851 if (ensembleFile.exists()) {
2852 logger.warning(
2853 format(" Versioning failed: appending to end of file %s", ensembleFile.getName()));
2854 }
2855 }
2856 ensembleFilter = new PDBFilter(new File(ensembleFile.getName()), molecularAssembly, null,
2857 null);
2858 logger.info(format(" Ensemble file: %s", ensembleFile.getName()));
2859 }
2860 logIfRank0(format("%30s %35s %35s", "Condition", "Number of Permutations Left",
2861 "Number of Permutations Removed"));
2862 logIfRank0(format("%30s %35s %35s", "No Eliminations", permutations, ""));
2863 logIfRank0(format("%30s %35s %35s", "Single Eliminations", singletonPermutations,
2864 permutations - singletonPermutations));
2865 logIfRank0(
2866 format("%30s %35s %35s", "Pair Eliminations", afterPairElim, pairTotalElimination));
2867 logIfRank0(
2868 format("%30s %35s %35s", "Single and Pair Eliminations", (double) evaluatedPermutations,
2869 pairTotalElimination + (permutations - singletonPermutations)));
2870
2871 logIfRank0("\n Energy of permutations:");
2872 logIfRank0(format(" %12s %25s %25s", "Permutation", "Energy", "Lowest Possible Energy"));
2873
2874 double e;
2875 if (useMonteCarlo()) {
2876 firstValidPerm(residues, 0, currentRotamers);
2877 arraycopy(currentRotamers, 0, optimumSubset, 0, nResidues);
2878 rotamerOptimizationMC(residues, optimumSubset, currentRotamers, nMCSteps, false, mcUseAll);
2879
2880 logIfRank0(" Ensembles not currently compatible with Monte Carlo search");
2881
2882 } else {
2883 double[] permutationEnergies = new double[evaluatedPermutations];
2884 ensembleStates = new ArrayList<>();
2885
2886 e = rotamerOptimizationDEE(molecularAssembly, residues, 0, currentRotamers, Double.MAX_VALUE,
2887 optimumSubset, permutationEnergies);
2888 int[][] acceptedPermutations = new int[evaluatedPermutations][];
2889 logIfRank0(format(
2890 "\n Checking permutations for distance < %5.3f kcal/mol from GMEC energy %10.8f kcal/mol",
2891 ensembleEnergy, e));
2892 dryRunForEnsemble(residues, 0, currentRotamers, e, permutationEnergies,
2893 acceptedPermutations);
2894 int numAcceptedPermutations = 0;
2895
2896 for (int i = 0; i < acceptedPermutations.length; i++) {
2897 if (acceptedPermutations[i] != null) {
2898 ++numAcceptedPermutations;
2899 logIfRank0(
2900 format(" Accepting permutation %d at %8.6f < %8.6f", i, permutationEnergies[i] - e,
2901 ensembleEnergy));
2902 for (int j = 0; j < nResidues; j++) {
2903 Residue residuej = residues[j];
2904 Rotamer[] rotamersj = residuej.getRotamers();
2905 RotamerLibrary.applyRotamer(residuej, rotamersj[acceptedPermutations[i][j]]);
2906 }
2907
2908 ResidueState[] states = ResidueState.storeAllCoordinates(residues);
2909 ensembleStates.add(new ObjectPair<>(states, permutationEnergies[i]));
2910
2911 if (printFiles && rank0) {
2912 try {
2913 FileWriter fw = new FileWriter(ensembleFile, true);
2914 BufferedWriter bw = new BufferedWriter(fw);
2915 bw.write(format("MODEL %d", numAcceptedPermutations));
2916 for (int j = 0; j < 75; j++) {
2917 bw.write(" ");
2918 }
2919 bw.newLine();
2920 bw.flush();
2921 ensembleFilter.writeFile(ensembleFile, true);
2922 bw.write("ENDMDL");
2923 for (int j = 0; j < 64; j++) {
2924 bw.write(" ");
2925 }
2926 bw.newLine();
2927 bw.close();
2928 } catch (IOException ex) {
2929 logger.warning(format(" Exception writing to file: %s", ensembleFile.getName()));
2930 }
2931 }
2932 }
2933 }
2934 logIfRank0(format(" Number of permutations within %5.3f kcal/mol of GMEC energy: %6.4e",
2935 ensembleEnergy, (double) numAcceptedPermutations));
2936 ensembleStates.sort(null);
2937 }
2938
2939 logIfRank0(" Final rotamers:");
2940 logIfRank0(format("%17s %10s %11s %12s %11s", "Residue", "Chi 1", "Chi 2", "Chi 3", "Chi 4"));
2941 for (int i = 0; i < nResidues; i++) {
2942 Residue residue = residues[i];
2943 Rotamer[] rotamers = residue.getRotamers();
2944 int ri = optimumSubset[i];
2945 Rotamer rotamer = rotamers[ri];
2946 logIfRank0(format(" %c (%7s,%2d) %s", residue.getChainID(), residue.toString(rotamer), ri,
2947 rotamer.toAngleString()));
2948 RotamerLibrary.applyRotamer(residue, rotamer);
2949 }
2950 logIfRank0("\n");
2951
2952 double sumSelfEnergy = 0;
2953 double sumPairEnergy = 0;
2954 double sumTrimerEnergy = 0;
2955 for (int i = 0; i < nResidues; i++) {
2956 Residue residue = residues[i];
2957 Rotamer[] rotamers = residue.getRotamers();
2958 int ri = optimumSubset[i];
2959 sumSelfEnergy += eE.getSelf(i, ri);
2960 logIfRank0(
2961 format(" Final self Energy (%8s,%2d): %12.4f", residue.toString(rotamers[ri]), ri,
2962 eE.getSelf(i, ri)));
2963 }
2964 for (int i = 0; i < nResidues - 1; i++) {
2965 Residue residueI = residues[i];
2966 Rotamer[] rotI = residueI.getRotamers();
2967 int ri = optimumSubset[i];
2968 for (int j = i + 1; j < nResidues; j++) {
2969 Residue residueJ = residues[j];
2970 Rotamer[] rotJ = residueJ.getRotamers();
2971 int rj = optimumSubset[j];
2972 sumPairEnergy += eE.get2Body(i, ri, j, rj);
2973 if (eE.get2Body(i, ri, j, rj) > 10.0) {
2974 logIfRank0(format(" Large Final Pair Energy (%8s,%2d) (%8s,%2d): %12.4f",
2975 residueI.toString(rotI[ri]), ri, residueJ.toString(rotJ[rj]), rj,
2976 eE.get2Body(i, ri, j, rj)));
2977 }
2978 }
2979 }
2980
2981 try {
2982
2983 e = currentEnergy(residueList) + eE.getTotalRotamerPhBias(residueList, optimumSubset, pH, pHRestraint);
2984 } catch (ArithmeticException ex) {
2985 e = Double.NaN;
2986 logger.severe(
2987 format(" Exception %s in calculating current energy at the end of triples", ex));
2988 }
2989
2990 logIfRank0(format(" %12s %25s %25s", "Type", "Energy", "Lowest Possible Energy"));
2991 logIfRank0(format(" %12s %25f %25s", "Self:", sumSelfEnergy, ""));
2992 logIfRank0(format(" %12s %25f %25s", "Pair:", sumPairEnergy, ""));
2993
2994 approximateEnergy = eE.getBackboneEnergy() + sumSelfEnergy + sumPairEnergy;
2995
2996 if (threeBodyTerm) {
2997 for (int i = 0; i < nResidues - 2; i++) {
2998 int ri = optimumSubset[i];
2999 for (int j = i + 1; j < nResidues - 1; j++) {
3000 int rj = optimumSubset[j];
3001 for (int k = j + 1; k < nResidues; k++) {
3002 int rk = optimumSubset[k];
3003 try {
3004 sumTrimerEnergy += eE.get3Body(residues, i, ri, j, rj, k, rk);
3005 } catch (Exception ex) {
3006 logger.warning(ex.toString());
3007 }
3008 }
3009 }
3010 }
3011 approximateEnergy += sumTrimerEnergy;
3012 double higherOrderEnergy =
3013 e - sumSelfEnergy - sumPairEnergy - sumTrimerEnergy - eE.getBackboneEnergy();
3014 logIfRank0(format(" %12s %25f %25s", "Trimer:", sumTrimerEnergy, ""));
3015 logIfRank0(format(" %12s %25f %25s", "Neglected:", higherOrderEnergy, ""));
3016 } else {
3017 double higherOrderEnergy = e - sumSelfEnergy - sumPairEnergy - eE.getBackboneEnergy();
3018 logIfRank0(format(" %12s %25f %25s", "Neglected:", higherOrderEnergy, ""));
3019 }
3020 logIfRank0(format(" %12s %25f %25s", "Approximate:", approximateEnergy, ""));
3021 return e;
3022 }
3023
3024
3025
3026 int nPerms = 1;
3027 for (Residue residue : residues) {
3028 Rotamer[] rotamers = residue.getRotamers();
3029 int nr = rotamers.length;
3030 if (nr > 1) {
3031 nPerms *= rotamers.length;
3032 }
3033 if (nPerms > ensembleNumber) {
3034 break;
3035 }
3036 }
3037
3038 if (nPerms < ensembleNumber) {
3039 logger.info(format(
3040 " Requested an ensemble of %d, but only %d permutations exist; returning full ensemble",
3041 ensembleNumber, nPerms));
3042 ensembleNumber = nPerms;
3043 }
3044
3045 while (currentEnsemble != ensembleNumber) {
3046 if (monteCarlo) {
3047 logIfRank0(" Ensemble search not currently compatible with Monte Carlo");
3048 ensembleNumber = 1;
3049 }
3050
3051 if (iterations == 0) {
3052 applyEliminationCriteria(residues, true, true);
3053 } else {
3054 applyEliminationCriteria(residues, false, false);
3055 }
3056
3057
3058
3059 double permutations = 1;
3060 double singletonPermutations = 1;
3061 for (int i = 0; i < nResidues; i++) {
3062 Residue residue = residues[i];
3063 Rotamer[] rotamers = residue.getRotamers();
3064 int nr = rotamers.length;
3065 if (nr > 1) {
3066 int nrot = 0;
3067 for (int ri = 0; ri < nr; ri++) {
3068 if (!eR.eliminatedSingles[i][ri]) {
3069 nrot++;
3070 }
3071 }
3072 permutations *= rotamers.length;
3073 if (nrot > 1) {
3074 singletonPermutations *= nrot;
3075 }
3076 }
3077 }
3078
3079 logIfRank0(" Collecting Permutations:");
3080 dryRun(residues, 0, currentRotamers);
3081
3082 double pairTotalElimination = singletonPermutations - (double) evaluatedPermutations;
3083 double afterPairElim = singletonPermutations - pairTotalElimination;
3084 currentEnsemble = evaluatedPermutations;
3085 if (ensembleNumber == 1 && currentEnsemble == 0) {
3086 logger.severe(
3087 " No valid path through rotamer space found; try recomputing without pruning or using ensemble.");
3088 }
3089 if (ensembleNumber > 1) {
3090 if (rank0 && printFiles && ensembleFile == null) {
3091 File file = molecularAssembly.getFile();
3092 String filename = FilenameUtils.removeExtension(file.getAbsolutePath());
3093 ensembleFile = new File(filename + ".ens");
3094 if (ensembleFile.exists()) {
3095 for (int i = 2; i < 1000; i++) {
3096 ensembleFile = new File(filename + ".ens_" + i);
3097 if (!ensembleFile.exists()) {
3098 break;
3099 }
3100 }
3101 if (ensembleFile.exists()) {
3102 logger.warning(
3103 format(" Versioning failed: appending to end of file %s", ensembleFile.getName()));
3104 }
3105 }
3106 ensembleFilter = new PDBFilter(new File(ensembleFile.getName()), molecularAssembly, null,
3107 null);
3108 logger.info(format(" Ensemble file: %s", ensembleFile.getName()));
3109 }
3110 logIfRank0(format(" Ensemble Search Stats: (buffer: %5.3f, current: %d, target: %d)",
3111 ensembleBuffer, currentEnsemble, ensembleNumber));
3112 }
3113 if (ensembleNumber == 1 || finalTry) {
3114 logIfRank0(format("%30s %35s %35s", "Condition", "Number of Permutations Left",
3115 "Number of Permutations Removed"));
3116 logIfRank0(format("%30s %35s %35s", "No Eliminations", permutations, ""));
3117 logIfRank0(format("%30s %35s %35s", "Single Eliminations", singletonPermutations,
3118 permutations - singletonPermutations));
3119 logIfRank0(
3120 format("%30s %35s %35s", "Pair Eliminations", afterPairElim, pairTotalElimination));
3121 logIfRank0(
3122 format("%30s %35s %35s", "Single and Pair Eliminations", (double) evaluatedPermutations,
3123 pairTotalElimination + (permutations - singletonPermutations)));
3124
3125 logIfRank0("\n Energy of permutations:");
3126 logIfRank0(format(" %12s %25s %25s", "Permutation", "Energy", "Lowest Possible Energy"));
3127
3128 break;
3129 }
3130 if (abs(currentEnsemble - ensembleNumber) < bestEnsembleTargetDiffThusFar) {
3131 bestEnsembleTargetDiffThusFar = Math.abs(currentEnsemble - ensembleNumber);
3132 bestBufferThusFar = ensembleBuffer;
3133 }
3134 if (currentEnsemble > ensembleNumber) {
3135 ensembleBuffer -= ensembleBufferStep;
3136 ensembleBufferStep -= (ensembleBufferStep * 0.01);
3137 iterations++;
3138 } else if (currentEnsemble < ensembleNumber) {
3139 ensembleBuffer += ensembleBufferStep;
3140 ensembleBufferStep -= (ensembleBufferStep * 0.01);
3141 iterations++;
3142 }
3143 if (iterations > 100) {
3144 if (currentEnsemble == 0) {
3145
3146
3147 logIfRank0(" Ensemble still empty; increasing buffer energy.");
3148 startingBuffer = 3 * startingBuffer;
3149 setEnsemble(10, startingBuffer);
3150 iterations = 0;
3151 } else {
3152 ensembleBuffer = bestBufferThusFar;
3153 finalTry = true;
3154 }
3155 }
3156 }
3157
3158 if (currentEnsemble == 0) {
3159 logger.warning(
3160 " No valid rotamer permutations found; results will be unreliable. Try increasing the starting ensemble buffer.");
3161 }
3162 double[] permutationEnergyStub = null;
3163
3164 if (useMonteCarlo()) {
3165 firstValidPerm(residues, 0, currentRotamers);
3166 rotamerOptimizationMC(residues, optimumSubset, currentRotamers, nMCSteps, false, mcUseAll);
3167 } else {
3168 rotamerOptimizationDEE(molecularAssembly, residues, 0, currentRotamers, Double.MAX_VALUE,
3169 optimumSubset, permutationEnergyStub);
3170 }
3171
3172 double[] residueEnergy = new double[nResidues];
3173
3174 double sumSelfEnergy = 0;
3175 double sumLowSelfEnergy = 0;
3176
3177 logIfRank0("\n Energy contributions:");
3178 logIfRank0(format(" %15s %25s %25s", "Type", "Energy", "Lowest Possible Energy"));
3179
3180 for (int i = 0; i < nResidues; i++) {
3181 int ri = optimumSubset[i];
3182 Residue residue = residues[i];
3183 Rotamer[] rotamers = residue.getRotamers();
3184 turnOnAtoms(residue);
3185 RotamerLibrary.applyRotamer(residue, rotamers[ri]);
3186 double self = eE.getSelf(i, ri);
3187 residueEnergy[i] = self;
3188 sumSelfEnergy += self;
3189 double lowest = eE.lowestSelfEnergy(residues, i);
3190 sumLowSelfEnergy += lowest;
3191 if (self - lowest > 10.0) {
3192 logIfRank0(
3193 format(" %15s %25f %25f", "Self (" + residues[i] + "," + ri + "):", self, lowest));
3194 }
3195 }
3196
3197 double sumPairEnergy = 0.0;
3198 double sumLowPairEnergy = 0.0;
3199 double[] resPairEnergy = new double[nResidues];
3200 double[] lowPairEnergy = new double[nResidues];
3201 for (int i = 0; i < nResidues - 1; i++) {
3202 StringBuilder sb = new StringBuilder();
3203 int ri = optimumSubset[i];
3204 double sumPairEnergyI = 0;
3205 double sumLowPairEnergyI = 0;
3206 for (int j = i + 1; j < nResidues; j++) {
3207 int rj = optimumSubset[j];
3208 double pair = eE.get2Body(i, ri, j, rj);
3209 residueEnergy[i] += 0.5 * pair;
3210 residueEnergy[j] += 0.5 * pair;
3211 sumPairEnergy += pair;
3212 sumPairEnergyI += pair;
3213 double lowest = eE.lowestPairEnergy(residues, i, ri, j);
3214 sumLowPairEnergy += lowest;
3215 sumLowPairEnergyI += lowest;
3216 resPairEnergy[i] = 0.5 * pair;
3217 resPairEnergy[j] = 0.5 * pair;
3218 lowPairEnergy[i] = 0.5 * lowest;
3219 lowPairEnergy[j] = 0.5 * lowest;
3220 if (resPairEnergy[i] - lowPairEnergy[i] > 10.0) {
3221 sb.append(format(" Pair Energy (%8s,%2d) (%8s,%2d): %12.4f (Lowest: %12.4f).\n",
3222 residues[i].toFormattedString(false, true), ri,
3223 residues[j].toFormattedString(false, true), rj, pair, lowest));
3224 }
3225 }
3226 if (sumPairEnergyI - sumLowPairEnergyI > 10.0) {
3227 logIfRank0(
3228 format(" %15s %25f %25f", "Self (" + residues[i] + "," + ri + ")", sumPairEnergyI,
3229 sumLowPairEnergyI));
3230 sb.trimToSize();
3231 if (!sb.toString().isEmpty()) {
3232 logIfRank0(sb.toString());
3233 }
3234 }
3235 }
3236
3237 double e = Double.NaN;
3238 try {
3239
3240 e = currentEnergy(residueList) + eE.getTotalRotamerPhBias(residueList, optimumSubset, pH, pHRestraint);
3241 } catch (ArithmeticException ex) {
3242 logger.severe(
3243 format(" Exception %s in calculating current energy at the end of self and pairs", ex));
3244 }
3245 logIfRank0(format(" %15s %25f %25s", "Backbone:", eE.getBackboneEnergy(), ""));
3246 logIfRank0(format(" %15s %25f %25f", "Self:", sumSelfEnergy, sumLowSelfEnergy));
3247 logIfRank0(format(" %15s %25f %25f", "Pair:", sumPairEnergy, sumLowPairEnergy));
3248
3249 approximateEnergy = eE.getBackboneEnergy() + sumSelfEnergy + sumPairEnergy;
3250
3251 double sumTrimerEnergy = 0;
3252 if (threeBodyTerm) {
3253 for (int i = 0; i < nResidues - 2; i++) {
3254 int ri = optimumSubset[i];
3255 for (int j = i + 1; j < nResidues - 1; j++) {
3256 int rj = optimumSubset[j];
3257 for (int k = j + 1; k < nResidues; k++) {
3258 int rk = optimumSubset[k];
3259 try {
3260 double triple = eE.get3Body(residues, i, ri, j, rj, k, rk);
3261 double thirdTrip = triple / 3.0;
3262 residueEnergy[i] += thirdTrip;
3263 residueEnergy[j] += thirdTrip;
3264 residueEnergy[k] += thirdTrip;
3265 sumTrimerEnergy += triple;
3266 } catch (Exception ex) {
3267 logger.warning(ex.toString());
3268 }
3269 }
3270 }
3271 }
3272 approximateEnergy += sumTrimerEnergy;
3273 double higherOrderEnergy =
3274 e - sumSelfEnergy - sumPairEnergy - sumTrimerEnergy - eE.getBackboneEnergy();
3275 logIfRank0(format(" %15s %25f %25s", "Trimer:", sumTrimerEnergy, ""));
3276 logIfRank0(format(" %15s %25f %25s", "Neglected:", higherOrderEnergy, ""));
3277 } else {
3278 double higherOrderEnergy = e - sumSelfEnergy - sumPairEnergy - eE.getBackboneEnergy();
3279 logIfRank0(format(" %15s %25f %25s", "Neglected:", higherOrderEnergy, ""));
3280 }
3281
3282 logIfRank0(format(" %15s %25f %25s", "Approximate:", approximateEnergy, ""));
3283
3284 logIfRank0("\n Final rotamers:");
3285 logIfRank0(
3286 format("%17s %10s %11s %12s %11s %14s", "Residue", "Chi 1", "Chi 2", "Chi 3", "Chi 4",
3287 "Energy"));
3288 for (int i = 0; i < nResidues; i++) {
3289 Residue residue = residues[i];
3290 Rotamer[] rotamers = residue.getRotamers();
3291 int ri = optimumSubset[i];
3292 Rotamer rotamer = rotamers[ri];
3293 logIfRank0(format(" %3d %c (%7s,%2d) %s %12.4f ", i + 1, residue.getChainID(),
3294 residue.toString(rotamers[ri]), ri, rotamer.toAngleString(), residueEnergy[i]));
3295 RotamerLibrary.applyRotamer(residue, rotamer);
3296 }
3297 logIfRank0("\n");
3298 return e;
3299 }
3300
3301
3302
3303
3304
3305
3306
3307 private boolean useMonteCarlo() {
3308 return monteCarlo && (mcNoEnum || (nMCSteps < evaluatedPermutations));
3309 }
3310
3311
3312
3313
3314
3315
3316
3317 private double bruteForce(List<Residue> residueList) {
3318
3319 Residue[] residues = residueList.toArray(new Residue[0]);
3320 int nResidues = residues.length;
3321
3322
3323 double permutations = 1;
3324 for (Residue residue : residues) {
3325 Rotamer[] rotamers = residue.getRotamers();
3326 permutations *= rotamers.length;
3327 }
3328
3329 logger.info(format(" Number of permutations: %16.8e.", permutations));
3330
3331 double e;
3332 useForceFieldEnergy = molecularAssembly.getProperties()
3333 .getBoolean("ro-use-force-field-energy", false);
3334 if (!useForceFieldEnergy) {
3335
3336 setPruning(0);
3337 rotamerEnergies(residues);
3338 int[] currentRotamers = new int[nResidues];
3339 e = decomposedRotamerOptimization(residues, 0, Double.MAX_VALUE, optimum, currentRotamers);
3340
3341
3342 for (int i = 0; i < nResidues; i++) {
3343 Residue residue = residues[i];
3344 Rotamer[] rotamers = residue.getRotamers();
3345 RotamerLibrary.applyRotamer(residue, rotamers[optimum[i]]);
3346 turnOnAtoms(residue);
3347 }
3348
3349
3350 double fullEnergy = 0;
3351 try {
3352
3353 fullEnergy = currentEnergy(residueList) + eE.getTotalRotamerPhBias(residueList, optimum, pH, pHRestraint);
3354 } catch (Exception ex) {
3355 logger.severe(format(" Exception %s in calculating full energy; FFX shutting down", ex));
3356 }
3357
3358 logger.info(format(" Final summation of energies: %16.5f", e));
3359 logger.info(format(" Final energy of optimized structure: %16.5f", fullEnergy));
3360 logger.info(format(" Neglected: %16.5f", fullEnergy - e));
3361 } else {
3362 e = rotamerOptimization(molecularAssembly, residues, 0, Double.MAX_VALUE, optimum);
3363 }
3364
3365 for (int i = 0; i < nResidues; i++) {
3366 Residue residue = residues[i];
3367 Rotamer[] rotamers = residue.getRotamers();
3368 int ri = optimum[i];
3369 Rotamer rotamer = rotamers[ri];
3370 logger.info(format(" %s %s (%d)", residue.getResidueNumber(), rotamer.toString(), ri));
3371 RotamerLibrary.applyRotamer(residue, rotamer);
3372 if (useForceFieldEnergy) {
3373 try {
3374 e = currentEnergy(residueList) + eE.getTotalRotamerPhBias(residueList, optimum, pH, pHRestraint);
3375 } catch (ArithmeticException ex) {
3376 logger.fine(
3377 format(" Exception %s in calculating full AMOEBA energy at the end of brute force",
3378 ex));
3379 }
3380 }
3381 }
3382 return e;
3383 }
3384
3385 @SuppressWarnings("fallthrough")
3386 private double slidingWindowOptimization(List<Residue> residueList, int windowSize, int increment,
3387 boolean revert, double distance, Direction direction, int windowCenter) throws Exception {
3388
3389 long beginTime = -System.nanoTime();
3390 boolean incrementTruncated = false;
3391 boolean firstWindowSaved = false;
3392 int counter = 1;
3393 int windowEnd;
3394
3395 int nOptimize = residueList.size();
3396 if (nOptimize < windowSize) {
3397 windowSize = nOptimize;
3398 logger.info(" Window size too small for given residue range; truncating window size.");
3399 }
3400 switch (direction) {
3401 case BACKWARD:
3402 List<Residue> temp = new ArrayList<>();
3403 for (int i = nOptimize - 1; i >= 0; i--) {
3404 temp.add(residueList.get(i));
3405 }
3406 residueList = temp;
3407
3408 case FORWARD:
3409 for (int windowStart = 0; windowStart + (windowSize - 1) < nOptimize;
3410 windowStart += increment) {
3411 long windowTime = -System.nanoTime();
3412
3413 if(windowCenter > -1){
3414 windowStart = windowCenter - windowSize/2;
3415 if(windowStart < 0){
3416 windowStart = 0;
3417 }
3418 windowEnd = windowCenter + windowSize/2;
3419 if(windowEnd >= residueList.size()){
3420 windowEnd = residueList.size() - 1;
3421 }
3422 } else {
3423 windowEnd = windowStart + (windowSize - 1);
3424 }
3425
3426 if(windowCenter > -1){
3427 logIfRank0(format("\n Center window at residue %d.\n", residueList.get(windowCenter).getResidueNumber()));
3428 } else {
3429 logIfRank0(format("\n Iteration %d of the sliding window.\n", counter++));
3430 }
3431
3432 Residue firstResidue = residueList.get(windowStart);
3433 Residue lastResidue = residueList.get(windowEnd);
3434 if (firstResidue != lastResidue) {
3435 logIfRank0(
3436 format(" Residues %s ... %s", firstResidue.toString(), lastResidue.toString()));
3437 } else {
3438 logIfRank0(format(" Residue %s", firstResidue.toString()));
3439 }
3440 List<Residue> currentWindow = new ArrayList<>();
3441 for (int i = windowStart; i <= windowEnd; i++) {
3442 Residue residue = residueList.get(i);
3443 currentWindow.add(residue);
3444 }
3445
3446 if (distance > 0) {
3447 for (int i = windowStart; i <= windowEnd; i++) {
3448 if(windowCenter > -1){
3449 i = windowCenter;
3450 }
3451 Residue residuei = residueList.get(i);
3452 int indexI = allResiduesList.indexOf(residuei);
3453 int lengthRi;
3454 lengthRi = residuei.getRotamers().length;
3455 for (int ri = 0; ri < lengthRi; ri++) {
3456 for (int j = 0; j < nAllResidues; j++) {
3457 Residue residuej = allResiduesArray[j];
3458 Rotamer[] rotamersj = residuej.getRotamers();
3459 if (currentWindow.contains(residuej) || rotamersj == null) {
3460 continue;
3461 }
3462 int lengthRj = rotamersj.length;
3463 for (int rj = 0; rj < lengthRj; rj++) {
3464 double rotamerSeparation = dM.get2BodyDistance(indexI, ri, j, rj);
3465 if (rotamerSeparation <= distance) {
3466 if (!currentWindow.contains(residuej)) {
3467 logIfRank0(format(" Adding residue %s at distance %16.8f Ang from %s %d.",
3468 residuej.toFormattedString(false, true), rotamerSeparation,
3469 residuei.toFormattedString(false, true), ri));
3470 currentWindow.add(residuej);
3471 }
3472 break;
3473 }
3474 }
3475 }
3476 }
3477 if(windowCenter > -1){
3478 break;
3479 }
3480 }
3481 }
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503 if (counter > 2 && windowSize <= increment && firstResidue.getResidueType() == NA) {
3504 Residue prevResidue = firstResidue.getPreviousResidue();
3505 if (prevResidue != null && prevResidue.getResidueType() == NA
3506 && !currentWindow.contains(prevResidue) && prevResidue.getRotamers() != null) {
3507 logIfRank0(format(
3508 " Adding nucleic acid residue 5' of window start %s to give it flexibility about its sugar pucker.",
3509 prevResidue));
3510 currentWindow.add(prevResidue);
3511 }
3512 }
3513 sortResidues(currentWindow);
3514
3515 if (revert) {
3516 ResidueState[] coordinates = ResidueState.storeAllCoordinates(currentWindow);
3517 double startingEnergy = Double.NaN;
3518 try {
3519 startingEnergy = currentEnergy(currentWindow);
3520 } catch (ArithmeticException ex) {
3521 logger.severe(format(
3522 " Exception %s in calculating starting energy of a window; FFX shutting down",
3523 ex));
3524 }
3525 globalOptimization(currentWindow);
3526 double finalEnergy = Double.NaN;
3527 try {
3528 finalEnergy = currentEnergy(currentWindow);
3529 } catch (ArithmeticException ex) {
3530 logger.severe(
3531 format(" Exception %s in calculating final energy of a window; FFX shutting down",
3532 ex));
3533 }
3534 if (startingEnergy <= finalEnergy) {
3535 logger.info(
3536 "Optimization did not yield a better energy. Reverting to original coordinates.");
3537 ResidueState.revertAllCoordinates(currentWindow, coordinates);
3538 } else {
3539
3540 int i = 0;
3541 for (Residue residue : currentWindow) {
3542 int index = residueList.indexOf(residue);
3543 optimum[index] = optimumSubset[i++];
3544 }
3545 }
3546 } else {
3547 globalOptimization(currentWindow);
3548
3549 int i = 0;
3550 for (Residue residue : currentWindow) {
3551 int index = residueList.indexOf(residue);
3552 optimum[index] = optimumSubset[i++];
3553 }
3554 }
3555
3556 if (!incrementTruncated) {
3557 if (windowStart + (windowSize - 1) + increment > nOptimize - 1) {
3558 increment = nOptimize - windowStart - windowSize;
3559 if (increment == 0) {
3560 break;
3561 }
3562 logger.warning(" Increment truncated in order to optimize entire residue range.");
3563 incrementTruncated = true;
3564 }
3565 }
3566
3567 if (rank0 && printFiles) {
3568 File file = molecularAssembly.getFile();
3569 if (firstWindowSaved) {
3570 file.delete();
3571 }
3572
3573 if (windowStart + windowSize == nOptimize) {
3574 continue;
3575 }
3576 PDBFilter windowFilter = new PDBFilter(file, molecularAssembly, null, null);
3577
3578
3579 try {
3580 windowFilter.writeFile(file, false);
3581 if (firstResidue != lastResidue) {
3582 logger.info(
3583 format(" File with residues %s ... %s in window written to.", firstResidue,
3584 lastResidue));
3585 } else {
3586 logger.info(format(" File with residue %s in window written to.", firstResidue));
3587 }
3588 } catch (Exception e) {
3589 logger.warning(format("Exception writing to file: %s", file.getName()));
3590 }
3591 firstWindowSaved = true;
3592 }
3593 long currentTime = System.nanoTime();
3594 windowTime += currentTime;
3595 logIfRank0(format(" Time elapsed for this iteration: %11.3f sec", windowTime * 1.0E-9));
3596 logIfRank0(
3597 format(" Overall time elapsed: %11.3f sec", (currentTime + beginTime) * 1.0E-9));
3598 if(genZ){
3599 int[] currentRotamers = new int[optimumSubset.length];
3600 usingBoxOptimization = true;
3601 Residue[] residueSubsetArray = currentWindow.toArray(new Residue[currentWindow.size()]);
3602 getFractions(residueSubsetArray,0,currentRotamers, true);
3603 Residue[] titrationResidueArray = new Residue[]{residueList.get(windowCenter)};
3604 getProtonationPopulations(titrationResidueArray);
3605 }
3606 if(windowCenter > -1){
3607 break;
3608 }
3609 }
3610
3611
3612 break;
3613 default:
3614
3615 break;
3616 }
3617 return 0.0;
3618 }
3619
3620
3621
3622
3623
3624
3625 private void sortResidues(List<Residue> residues) {
3626 Comparator<Residue> comparator = Comparator.comparing(Residue::getChainID)
3627 .thenComparingInt(Residue::getResidueNumber);
3628 residues.sort(comparator);
3629 }
3630
3631
3632
3633
3634
3635
3636
3637
3638 private void applyEliminationCriteria(Residue[] residues, boolean getEnergies, boolean verbose) {
3639 Level prevLevel = logger.getLevel();
3640 if (!verbose) {
3641 logger.setLevel(Level.WARNING);
3642 }
3643 if (getEnergies) {
3644 applyEliminationCriteria(residues);
3645 } else {
3646 int i = 0;
3647 boolean pairEliminated;
3648 do {
3649 pairEliminated = false;
3650 if (useGoldstein) {
3651 if (selfEliminationOn) {
3652 i++;
3653 logIfRank0(format("\n Iteration %d: Applying Single Goldstein DEE conditions ", i));
3654
3655 while (goldsteinDriver(residues)) {
3656 i++;
3657 logIfRank0(this.toString());
3658 logIfRank0(
3659 format("\n Iteration %d: Applying Single Rotamer Goldstein DEE conditions ", i));
3660 }
3661 }
3662 if (pairEliminationOn) {
3663 i++;
3664 logIfRank0(
3665 format("\n Iteration %d: Applying Rotamer Pair Goldstein DEE conditions ", i));
3666
3667 pairEliminated = false;
3668 while (goldsteinPairDriver(residues)) {
3669 pairEliminated = true;
3670 i++;
3671 logIfRank0(this.toString());
3672 logIfRank0(
3673 format("\n Iteration %d: Applying Rotamer Pair Goldstein DEE conditions ", i));
3674 }
3675 }
3676 } else {
3677 if (selfEliminationOn) {
3678 i++;
3679 logIfRank0(format("\n Iteration %d: Applying Single DEE conditions ", i));
3680
3681 while (deeRotamerElimination(residues)) {
3682 i++;
3683 logIfRank0(toString());
3684 logIfRank0(format("\n Iteration %d: Applying Single Rotamer DEE conditions ", i));
3685 }
3686 }
3687 if (pairEliminationOn) {
3688 i++;
3689 logIfRank0(format("\n Iteration %d: Applying Rotamer Pair DEE conditions ", i));
3690
3691 pairEliminated = false;
3692 while (deeRotamerPairElimination(residues)) {
3693 pairEliminated = true;
3694 i++;
3695 logIfRank0(toString());
3696 logIfRank0(format("\n Iteration %d: Applying Rotamer Pair DEE conditions ", i));
3697 }
3698 }
3699 }
3700 eR.validateDEE(residues);
3701 logIfRank0(toString());
3702 } while (pairEliminated);
3703 logIfRank0(" Self-consistent DEE rotamer elimination achieved.\n");
3704 }
3705 if (!verbose) {
3706 logger.setLevel(prevLevel);
3707 }
3708 }
3709
3710 private void applyEliminationCriteria(Residue[] residues) {
3711 if (verboseEnergies) {
3712 try {
3713 logIfRank0(format("\n Beginning Energy %s", formatEnergy(currentEnergy(residues))));
3714 } catch (ArithmeticException ex) {
3715 logger.severe(format(" Exception %s in calculating beginning energy; FFX shutting down.", ex));
3716 }
3717 }
3718
3719 rotamerEnergies(residues);
3720
3721 if (testing) {
3722 int nres = residues.length;
3723 eR.onlyPrunedSingles = new boolean[nres][];
3724 eR.onlyPrunedPairs = new boolean[nres][][][];
3725 for (int i = 0; i < nres; i++) {
3726 Residue residuei = residues[i];
3727 Rotamer[] rotamersi = residuei.getRotamers();
3728 int lenri = rotamersi.length;
3729 eR.onlyPrunedSingles[i] = new boolean[lenri];
3730 eR.onlyPrunedSingles[i] = copyOf(eR.eliminatedSingles[i], eR.eliminatedSingles[i].length);
3731 eR.onlyPrunedPairs[i] = new boolean[lenri][][];
3732
3733 for (int ri = 0; ri < lenri; ri++) {
3734 eR.onlyPrunedPairs[i][ri] = new boolean[nres][];
3735 for (int j = i + 1; j < nres; j++) {
3736 Residue residuej = residues[j];
3737 Rotamer[] rotamersj = residuej.getRotamers();
3738 int lenrj = rotamersj.length;
3739 eR.onlyPrunedPairs[i][ri][j] = new boolean[lenrj];
3740 eR.onlyPrunedPairs[i][ri][j] = copyOf(eR.eliminatedPairs[i][ri][j],
3741 eR.eliminatedPairs[i][ri][j].length);
3742 }
3743 }
3744 }
3745 }
3746
3747 if (testSelfEnergyEliminations) {
3748 testSelfEnergyElimination(residues);
3749 } else if (testPairEnergyEliminations > -1) {
3750 testPairEnergyElimination(residues, testPairEnergyEliminations);
3751 } else if (testTripleEnergyEliminations1 > -1 && testTripleEnergyEliminations2 > -1) {
3752 testTripleEnergyElimination(residues, testTripleEnergyEliminations1,
3753 testTripleEnergyEliminations2);
3754 }
3755
3756 if (pruneClashes) {
3757 eR.validateDEE(residues);
3758 }
3759
3760 int i = 0;
3761 boolean pairEliminated;
3762 do {
3763 pairEliminated = false;
3764 if (useGoldstein) {
3765 if (selfEliminationOn) {
3766 i++;
3767 logIfRank0(format("\n Iteration %d: Applying Single Goldstein DEE conditions ", i));
3768
3769 while (goldsteinDriver(residues)) {
3770 i++;
3771 logIfRank0(this.toString());
3772 logIfRank0(
3773 format("\n Iteration %d: Applying Single Rotamer Goldstein DEE conditions ", i));
3774 }
3775 }
3776 if (pairEliminationOn) {
3777 i++;
3778 logIfRank0(format("\n Iteration %d: Applying Rotamer Pair Goldstein DEE conditions ", i));
3779
3780 while (goldsteinPairDriver(residues)) {
3781 pairEliminated = true;
3782 i++;
3783 logIfRank0(this.toString());
3784 logIfRank0(
3785 format("\n Iteration %d: Applying Rotamer Pair Goldstein DEE conditions ", i));
3786 }
3787 }
3788 } else {
3789 if (selfEliminationOn) {
3790 i++;
3791 logIfRank0(format("\n Iteration %d: Applying Single DEE conditions ", i));
3792
3793 while (deeRotamerElimination(residues)) {
3794 i++;
3795 logIfRank0(toString());
3796 logIfRank0(format("\n Iteration %d: Applying Single Rotamer DEE conditions ", i));
3797 }
3798 }
3799 if (pairEliminationOn) {
3800 i++;
3801 logIfRank0(format("\n Iteration %d: Applying Rotamer Pair DEE conditions ", i));
3802
3803 while (deeRotamerPairElimination(residues)) {
3804 pairEliminated = true;
3805 i++;
3806 logIfRank0(toString());
3807 logIfRank0(format("\n Iteration %d: Applying Rotamer Pair DEE conditions ", i));
3808 }
3809 }
3810 }
3811 eR.validateDEE(residues);
3812 logIfRank0(toString());
3813 } while (pairEliminated);
3814
3815 logIfRank0(" Self-consistent DEE rotamer elimination achieved.\n");
3816 }
3817
3818
3819
3820
3821
3822
3823
3824 private double currentEnergy(List<Residue> resList) throws ArithmeticException {
3825 List<Rotamer> rots = resList.stream().filter(Objects::nonNull).map(Residue::getRotamer)
3826 .collect(Collectors.toList());
3827 File energyDir = dirSupplier.apply(resList, rots);
3828 return eFunction.applyAsDouble(energyDir);
3829 }
3830
3831
3832
3833
3834
3835
3836
3837 private double currentPE(File dir) {
3838 if (x == null) {
3839 int nVar = potential.getNumberOfVariables();
3840 x = new double[nVar];
3841 }
3842 potential.getCoordinates(x);
3843 return potential.energy(x);
3844 }
3845
3846
3847
3848
3849
3850
3851 private void generateResidueNeighbors(Residue[] residues) {
3852 int nRes = residues.length;
3853 resNeighbors = new int[nRes][];
3854 bidiResNeighbors = new int[nRes][];
3855 for (int i = 0; i < nRes; i++) {
3856 Set<Integer> nearby = new HashSet<>();
3857 Residue resi = residues[i];
3858 Rotamer[] rotsi = resi.getRotamers();
3859 int lenri = rotsi.length;
3860 int indexI = allResiduesList.indexOf(resi);
3861
3862 for (int j = 0; j < nRes; j++) {
3863 if (i == j) {
3864 continue;
3865 }
3866 Residue resj = residues[j];
3867 Rotamer[] rotsj = resj.getRotamers();
3868 int lenrj = rotsj.length;
3869 int indexJ = allResiduesList.indexOf(resj);
3870
3871 boolean foundClose = false;
3872 for (int ri = 0; ri < lenri; ri++) {
3873 for (int rj = 0; rj < lenrj; rj++) {
3874 if (!dM.checkPairDistThreshold(indexI, ri, indexJ, rj)) {
3875 foundClose = true;
3876 break;
3877 }
3878 }
3879 if (foundClose) {
3880 break;
3881 }
3882 }
3883 if (foundClose) {
3884 nearby.add(j);
3885 }
3886 }
3887
3888
3889 int[] nI = nearby.stream().mapToInt(Integer::intValue).toArray();
3890 bidiResNeighbors[i] = nI;
3891
3892
3893 final int fi = i;
3894 nI = nearby.stream().mapToInt(Integer::intValue).filter(j -> j > fi).toArray();
3895 resNeighbors[i] = nI;
3896 }
3897 }
3898
3899 private void setUpRestart() {
3900 File restartFile;
3901 if (loadEnergyRestart) {
3902 restartFile = energyRestartFile;
3903 } else {
3904 File file = molecularAssembly.getFile();
3905 String filename = FilenameUtils.removeExtension(file.getAbsolutePath());
3906 Path restartPath = Paths.get(filename + ".restart");
3907 restartFile = restartPath.toFile();
3908 energyRestartFile = restartFile;
3909 }
3910 try {
3911 energyWriter = new BufferedWriter(new FileWriter(restartFile, true));
3912 } catch (IOException ex) {
3913 logger.log(Level.SEVERE, "Couldn't open energy restart file.", ex);
3914 }
3915 logger.info(format("\n Energy restart file: %s", restartFile.getName()));
3916 }
3917
3918
3919
3920
3921
3922
3923
3924
3925 private double rotamerEnergies(Residue[] residues) {
3926
3927 if (residues == null) {
3928 logger.warning(" Attempt to compute rotamer energies for an empty array of residues.");
3929 return 0.0;
3930 }
3931
3932 int nResidues = residues.length;
3933 Atom[] atoms = molecularAssembly.getAtomArray();
3934 generateResidueNeighbors(residues);
3935
3936 eR = new EliminatedRotamers(this, dM, allResiduesList, maxRotCheckDepth, clashThreshold,
3937 pairClashThreshold, multiResClashThreshold, nucleicPruningFactor, nucleicPairsPruningFactor,
3938 multiResPairClashAddn, pruneClashes, prunePairClashes, print, residues);
3939
3940 if (decomposeOriginal) {
3941 assert library.getUsingOrigCoordsRotamer();
3942 for (int i = 0; i < nResidues; i++) {
3943 Residue resi = residues[i];
3944 Rotamer[] rotsi = resi.getRotamers();
3945 int lenri = rotsi.length;
3946
3947
3948 for (int ri = 1; ri < lenri; ri++) {
3949 eR.eliminateRotamer(residues, i, ri, false);
3950 }
3951 }
3952 }
3953
3954
3955 for (Atom atom : atoms) {
3956 atom.setUse(true);
3957 }
3958
3959 eE = new EnergyExpansion(this, dM, eR, molecularAssembly, potential, algorithmListener,
3960 allResiduesList, resNeighbors, threeBodyTerm, decomposeOriginal, usingBoxOptimization,
3961 verbose, pruneClashes, prunePairClashes, rank0);
3962
3963
3964 eR.setEnergyExpansion(eE);
3965
3966 int loaded = 0;
3967 if (loadEnergyRestart) {
3968 if (usingBoxOptimization) {
3969 loaded = eE.loadEnergyRestart(energyRestartFile, residues, boxOpt.boxLoadIndex, boxOpt.boxLoadCellIndices);
3970 } else {
3971 loaded = eE.loadEnergyRestart(energyRestartFile, residues);
3972 }
3973 }
3974
3975 long energyStartTime = System.nanoTime();
3976 WorkerTeam energyWorkerTeam = new WorkerTeam(world);
3977
3978 try {
3979 if (loaded < 1) {
3980 eE.allocateSelfJobMap(residues, nResidues, false);
3981 }
3982
3983 SelfEnergyRegion selfEnergyRegion = new SelfEnergyRegion(this, eE, eR, residues, energyWriter,
3984 world, numProc, pruneClashes, rank0, rank, verbose, writeEnergyRestart, printFiles);
3985 energyWorkerTeam.execute(selfEnergyRegion);
3986 long singlesTime = System.nanoTime() - energyStartTime;
3987 logIfRank0(format(" Time for single energies: %12.4g", (singlesTime * 1.0E-9)));
3988 if (logger.isLoggable(Level.FINE)) {
3989 Resources.logResources();
3990 }
3991
3992 if (loaded < 2) {
3993 eE.allocate2BodyJobMap(residues, nResidues, false);
3994 }
3995
3996 TwoBodyEnergyRegion twoBodyEnergyRegion = new TwoBodyEnergyRegion(this, dM, eE, eR, residues,
3997 allResiduesList, energyWriter, world, numProc, prunePairClashes, superpositionThreshold,
3998 rank0, rank, verbose, writeEnergyRestart, printFiles);
3999 energyWorkerTeam.execute(twoBodyEnergyRegion);
4000 long pairsTime = System.nanoTime() - (singlesTime + energyStartTime);
4001
4002 long triplesTime = 0;
4003 long quadsTime = 0;
4004 logIfRank0(format(" Time for 2-body energies: %12.4g", (pairsTime * 1.0E-9)));
4005 if (logger.isLoggable(Level.FINE)) {
4006 Resources.logResources();
4007 }
4008
4009 if (threeBodyTerm) {
4010 if (loaded < 3) {
4011 eE.allocate3BodyJobMap(residues, nResidues, false);
4012 }
4013 ThreeBodyEnergyRegion threeBodyEnergyRegion = new ThreeBodyEnergyRegion(this, dM, eE, eR,
4014 residues, allResiduesList, energyWriter, world, numProc, superpositionThreshold, rank0,
4015 rank, verbose, writeEnergyRestart, printFiles);
4016 energyWorkerTeam.execute(threeBodyEnergyRegion);
4017 triplesTime = System.nanoTime() - (pairsTime + singlesTime + energyStartTime);
4018 logIfRank0(format(" Time for 3-Body energies: %12.4g", (triplesTime * 1.0E-9)));
4019 if (logger.isLoggable(Level.FINE)) {
4020 Resources.logResources();
4021 }
4022 }
4023
4024 if (compute4BodyEnergy) {
4025 eE.allocate4BodyJobMap(residues, nResidues);
4026
4027 FourBodyEnergyRegion fourBodyEnergyRegion = new FourBodyEnergyRegion(this, dM, eE, eR,
4028 residues, allResiduesList, superpositionThreshold);
4029 energyWorkerTeam.execute(fourBodyEnergyRegion);
4030 quadsTime = System.nanoTime() - (triplesTime + pairsTime + singlesTime + energyStartTime);
4031 logIfRank0(format(" Time for 4-Body energies: %12.4g", quadsTime * 1.0E-9));
4032 }
4033
4034 long allTime = singlesTime + pairsTime + triplesTime + quadsTime;
4035 logIfRank0(format(" Time for all energies: %12.4g", allTime * 1.0E-9));
4036 } catch (Exception ex) {
4037 String message = " Exception computing rotamer energies in parallel.";
4038 logger.log(Level.SEVERE, message, ex);
4039 }
4040
4041
4042 for (Atom atom : atoms) {
4043 atom.setUse(true);
4044 }
4045
4046 if (verboseEnergies && rank0) {
4047 try {
4048 double defaultEnergy = currentEnergy(residues);
4049 logger.info(format(" Energy of the system with rotamers in their default conformation: %s",
4050 formatEnergy(defaultEnergy)));
4051 } catch (ArithmeticException ex) {
4052 logger.severe(format(" Exception %s in calculating default energy; FFX shutting down", ex));
4053 }
4054 }
4055 return eE.getBackboneEnergy();
4056 }
4057
4058
4059
4060
4061
4062
4063 private void applyDefaultRotamer(Residue residue) {
4064 RotamerLibrary.applyRotamer(residue, residue.getRotamers()[0]);
4065 }
4066
4067
4068
4069
4070
4071
4072
4073 private boolean deeRotamerElimination(Residue[] residues) {
4074 int nres = residues.length;
4075
4076 boolean eliminated = false;
4077
4078 double[] minMax = new double[2];
4079 double[] minEnergySingles = null;
4080 double[] maxEnergySingles = null;
4081 for (int i = 0; i < nres; i++) {
4082 Residue residuei = residues[i];
4083 Rotamer[] rotamersi = residuei.getRotamers();
4084 int lenri = rotamersi.length;
4085 if (minEnergySingles == null || minEnergySingles.length < lenri) {
4086 minEnergySingles = new double[lenri];
4087 maxEnergySingles = new double[lenri];
4088 }
4089
4090 for (int ri = 0; ri < lenri; ri++) {
4091
4092 if (eR.check(i, ri)) {
4093 continue;
4094 }
4095
4096 minEnergySingles[ri] = eE.getSelf(i, ri);
4097 maxEnergySingles[ri] = minEnergySingles[ri];
4098 for (int j = 0; j < nres; j++) {
4099 if (j == i) {
4100 continue;
4101 }
4102 if (eE.minMaxPairEnergy(residues, minMax, i, ri, j)) {
4103 if (Double.isFinite(minMax[0]) && Double.isFinite(minEnergySingles[ri])) {
4104 minEnergySingles[ri] += minMax[0];
4105 } else {
4106
4107
4108
4109 minEnergySingles[ri] = Double.NaN;
4110 }
4111 if (Double.isFinite(minMax[0]) && Double.isFinite(maxEnergySingles[ri])) {
4112 maxEnergySingles[ri] += minMax[1];
4113 } else {
4114
4115
4116 maxEnergySingles[ri] = Double.NaN;
4117 }
4118 } else {
4119 Residue residuej = residues[j];
4120 logger.info(
4121 format(" Inconsistent Pair: %8s %2d, %8s.", residuei.toFormattedString(false, true),
4122 ri, residuej.toFormattedString(false, true)));
4123
4124 }
4125 }
4126 }
4127
4128
4129
4130
4131
4132 double eliminationEnergy = Double.MAX_VALUE;
4133 int eliminatingRotamer = 0;
4134 for (int ri = 0; ri < lenri; ri++) {
4135 if (eR.check(i, ri)) {
4136 continue;
4137 }
4138 if (Double.isFinite(maxEnergySingles[ri]) && maxEnergySingles[ri] < eliminationEnergy) {
4139 eliminationEnergy = maxEnergySingles[ri];
4140 eliminatingRotamer = ri;
4141 }
4142 }
4143
4144 if (eliminationEnergy == Double.MAX_VALUE) {
4145
4146
4147 logIfRank0(" Could not eliminate any i,ri because eliminationEnergy was never set!",
4148 Level.FINE);
4149 } else {
4150
4151
4152
4153
4154 for (int ri = 0; ri < lenri; ri++) {
4155 if (eR.check(i, ri)) {
4156 continue;
4157 }
4158
4159
4160 if (!Double.isFinite(minEnergySingles[ri])) {
4161 if (eR.eliminateRotamer(residues, i, ri, print)) {
4162 logIfRank0(format(" Rotamer elimination of (%8s,%2d) that always clashes.",
4163 residuei.toFormattedString(false, true), ri));
4164 eliminated = true;
4165 }
4166 }
4167
4168
4169 if (minEnergySingles[ri] > eliminationEnergy + ensembleBuffer) {
4170 if (eR.eliminateRotamer(residues, i, ri, print)) {
4171 logIfRank0(format(" Rotamer elimination of (%8s,%2d) by (%8s,%2d): %12.4f > %6.4f.",
4172 residuei.toFormattedString(false, true), ri,
4173 residuei.toFormattedString(false, true), eliminatingRotamer, minEnergySingles[ri],
4174 eliminationEnergy + ensembleBuffer));
4175 eliminated = true;
4176 }
4177 }
4178 }
4179 }
4180 }
4181 return eliminated;
4182 }
4183
4184
4185
4186
4187
4188
4189
4190
4191 private boolean deeRotamerPairElimination(Residue[] residues) {
4192 int nres = residues.length;
4193 boolean eliminated = false;
4194
4195 for (int i = 0; i < (nres - 1); i++) {
4196 Residue residuei = residues[i];
4197 Rotamer[] rotamersi = residuei.getRotamers();
4198 int lenri = rotamersi.length;
4199
4200
4201 double[][] minPairEnergies = new double[lenri][];
4202 double[][] maxPairEnergies = new double[lenri][];
4203
4204 for (int j = i + 1; j < nres; j++) {
4205 Residue residuej = residues[j];
4206 Rotamer[] rotamersj = residuej.getRotamers();
4207 int lenrj = rotamersj.length;
4208
4209 for (int ri = 0; ri < lenri; ri++) {
4210 if (eR.check(i, ri)) {
4211 continue;
4212 }
4213 minPairEnergies[ri] = new double[lenrj];
4214 maxPairEnergies[ri] = new double[lenrj];
4215
4216 for (int rj = 0; rj < lenrj; rj++) {
4217 if (eR.check(j, rj) || eR.check(i, ri, j, rj)) {
4218 continue;
4219 }
4220 minPairEnergies[ri][rj] =
4221 eE.getSelf(i, ri) + eE.getSelf(j, rj) + eE.get2Body(i, ri, j, rj);
4222 maxPairEnergies[ri][rj] = minPairEnergies[ri][rj];
4223
4224
4225 double[] minMax = new double[2];
4226
4227
4228 if (eE.minMaxE2(residues, minMax, i, ri, j, rj)) {
4229 if (Double.isFinite(minPairEnergies[ri][rj]) && Double.isFinite(minMax[0])) {
4230 minPairEnergies[ri][rj] += minMax[0];
4231 } else {
4232 logger.severe(
4233 format(" An ri-rj pair %s-%d %s-%d with NaN minimum was caught incorrectly!",
4234 residuei.toFormattedString(false, true), ri,
4235 residuej.toFormattedString(false, true), rj));
4236 }
4237 if (Double.isFinite(maxPairEnergies[ri][rj]) && Double.isFinite(minMax[1])) {
4238 maxPairEnergies[ri][rj] += minMax[1];
4239 } else {
4240
4241 maxPairEnergies[ri][rj] = Double.NaN;
4242 }
4243 } else {
4244
4245 minPairEnergies[ri][rj] = Double.NaN;
4246 logger.info(format(" Eliminating pair %s-%d %s-%d that always clashes.",
4247 residuei.toFormattedString(false, true), ri,
4248 residuej.toFormattedString(false, true), rj));
4249 eR.eliminateRotamerPair(residues, i, ri, j, rj, print);
4250 eliminated = true;
4251 }
4252 }
4253 }
4254
4255 double pairEliminationEnergy = Double.MAX_VALUE;
4256 for (int ri = 0; ri < lenri; ri++) {
4257 if (eR.check(i, ri)) {
4258 continue;
4259 }
4260 for (int rj = 0; rj < lenrj; rj++) {
4261 if (eR.check(j, rj) || eR.check(i, ri, j, rj)) {
4262 continue;
4263 }
4264 if (Double.isFinite(maxPairEnergies[ri][rj])
4265 && maxPairEnergies[ri][rj] < pairEliminationEnergy) {
4266 pairEliminationEnergy = maxPairEnergies[ri][rj];
4267 }
4268 }
4269 }
4270
4271 if (pairEliminationEnergy == Double.MAX_VALUE) {
4272 logIfRank0(format(
4273 " All rotamer pairs for residues %s and %s have possible conflicts; cannot perform any eliminations!",
4274 residuei.toFormattedString(false, true), residuej), Level.FINE);
4275 } else {
4276 double comparisonEnergy = pairEliminationEnergy + ensembleBuffer;
4277 for (int ri = 0; ri < lenri; ri++) {
4278 if (eR.check(i, ri)) {
4279 continue;
4280 }
4281 for (int rj = 0; rj < lenrj; rj++) {
4282 if (eR.check(j, rj) || eR.check(i, ri, j, rj)) {
4283 continue;
4284 }
4285 if (minPairEnergies[ri][rj] > comparisonEnergy) {
4286 if (eR.eliminateRotamerPair(residues, i, ri, j, rj, print)) {
4287 eliminated = true;
4288 logIfRank0(format(" Eliminating rotamer pair: %s %d, %s %d (%s > %s + %6.6f)",
4289 residuei.toFormattedString(false, true), ri,
4290 residuej.toFormattedString(false, true), rj,
4291 formatEnergy(minPairEnergies[ri][rj]), formatEnergy(pairEliminationEnergy),
4292 ensembleBuffer), Level.INFO);
4293 } else {
4294
4295 logIfRank0(
4296 format(" Already eliminated rotamer pair! %s %d, %s %d (%s > %1s + %6.6f)",
4297 residuei.toFormattedString(false, true), ri,
4298 residuej.toFormattedString(false, true), rj,
4299 formatEnergy(minPairEnergies[ri][rj]), formatEnergy(pairEliminationEnergy),
4300 ensembleBuffer), Level.WARNING);
4301 }
4302 }
4303 }
4304 }
4305 }
4306
4307 if (eR.pairsToSingleElimination(residues, i, j)) {
4308 eliminated = true;
4309 }
4310 }
4311 }
4312
4313 return eliminated;
4314 }
4315
4316 private boolean goldsteinDriver(Residue[] residues) {
4317 int nres = residues.length;
4318
4319 boolean eliminated = false;
4320
4321 for (int i = 0; i < nres; i++) {
4322 Residue resi = residues[i];
4323 Rotamer[] roti = resi.getRotamers();
4324 int nri = roti.length;
4325
4326 for (int riA = 0; riA < nri; riA++) {
4327
4328 if (eR.check(i, riA)) {
4329 continue;
4330 }
4331 for (int riB = 0; riB < nri; riB++) {
4332
4333 if (riA == riB || eR.check(i, riB)) {
4334 continue;
4335 }
4336 if (goldsteinElimination(residues, i, riA, riB)) {
4337 eliminated = true;
4338 break;
4339 }
4340 }
4341 }
4342 }
4343 if (!eliminated) {
4344 logIfRank0(" No more single rotamers to eliminate.");
4345 }
4346 return eliminated;
4347 }
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358 private boolean goldsteinElimination(Residue[] residues, int i, int riA, int riB) {
4359 Residue resi = residues[i];
4360
4361
4362 double selfDiff = eE.getSelf(i, riA) - eE.getSelf(i, riB);
4363 double goldsteinEnergy = selfDiff;
4364
4365 double sumPairDiff = 0.0;
4366 double sumTripleDiff = 0.0;
4367
4368
4369 for (int j : bidiResNeighbors[i]) {
4370 Residue resj = residues[j];
4371 Rotamer[] rotj = resj.getRotamers();
4372 int nrj = rotj.length;
4373 double minForResJ = Double.MAX_VALUE;
4374 double minPairDiff = 0.0;
4375 double minTripleDiff = 0.0;
4376 int rjEvals = 0;
4377
4378
4379 for (int rj = 0; rj < nrj; rj++) {
4380 if (eR.check(j, rj)) {
4381 continue;
4382 }
4383
4384 if (eR.check(i, riA, j, rj)) {
4385 continue;
4386 }
4387 if (eR.check(i, riB, j, rj)) {
4388
4389
4390
4391
4392
4393 return false;
4394 }
4395
4396 double pairI = eE.get2Body(i, riA, j, rj);
4397 double pairJ = eE.get2Body(i, riB, j, rj);
4398 double pairDiff = pairI - pairJ;
4399
4400 rjEvals++;
4401
4402
4403 double tripleDiff = 0.0;
4404 if (threeBodyTerm) {
4405 IntStream kStream = IntStream.concat(Arrays.stream(bidiResNeighbors[i]),
4406 Arrays.stream(bidiResNeighbors[j]));
4407 int[] possKs = kStream.distinct().sorted().toArray();
4408 for (int k : possKs) {
4409 if (k == i || k == j) {
4410 continue;
4411 }
4412 Residue resk = residues[k];
4413 Rotamer[] rotk = resk.getRotamers();
4414 int nrk = rotk.length;
4415 int rkEvals = 0;
4416 double minForResK = Double.MAX_VALUE;
4417 for (int rk = 0; rk < nrk; rk++) {
4418
4419
4420
4421
4422 if (eR.check(k, rk) || eR.check(j, rj, k, rk) || eR.check(i, riA, k, rk)) {
4423
4424
4425 continue;
4426 }
4427
4428
4429
4430
4431 if (eR.check(i, riB, k, rk)) {
4432
4433 return false;
4434 }
4435
4436 rkEvals++;
4437 double e =
4438 eE.get3Body(residues, i, riA, j, rj, k, rk) - eE.get3Body(residues, i, riB, j, rj,
4439 k, rk);
4440 if (e < minForResK) {
4441 minForResK = e;
4442 }
4443 }
4444
4445 if (rkEvals == 0) {
4446 minForResK = 0.0;
4447 }
4448 tripleDiff += minForResK;
4449 }
4450 }
4451
4452 double sumOverK = pairDiff + tripleDiff;
4453 if (sumOverK < minForResJ) {
4454 minForResJ = sumOverK;
4455 minPairDiff = pairDiff;
4456 minTripleDiff = tripleDiff;
4457 }
4458 }
4459
4460 if (rjEvals == 0) {
4461 minForResJ = 0.0;
4462 minPairDiff = 0.0;
4463 minTripleDiff = 0.0;
4464 }
4465 sumPairDiff += minPairDiff;
4466 sumTripleDiff += minTripleDiff;
4467 goldsteinEnergy += minForResJ;
4468 }
4469
4470 if (goldsteinEnergy > ensembleBuffer) {
4471 if (eR.eliminateRotamer(residues, i, riA, print)) {
4472 logIfRank0(format(" Rotamer elimination of (%8s,%2d) by (%8s,%2d): %12.4f > %6.4f.",
4473 resi.toFormattedString(false, true), riA, resi.toFormattedString(false, true), riB,
4474 goldsteinEnergy, ensembleBuffer));
4475 logIfRank0(format(" Self: %12.4f, Pairs: %12.4f, Triples: %12.4f.", selfDiff, sumPairDiff,
4476 sumTripleDiff));
4477 return true;
4478 }
4479 }
4480 return false;
4481 }
4482
4483
4484
4485
4486
4487
4488
4489 private boolean goldsteinPairDriver(Residue[] residues) {
4490 int nRes = residues.length;
4491 boolean eliminated = false;
4492
4493
4494 for (int i = 0; i < nRes; i++) {
4495 Residue resi = residues[i];
4496 Rotamer[] rotsi = resi.getRotamers();
4497 int lenri = rotsi.length;
4498
4499 for (int riA = 0; riA < lenri; riA++) {
4500
4501 if (eR.check(i, riA)) {
4502 continue;
4503 }
4504
4505
4506 for (int j = 0; j < nRes; j++) {
4507
4508 if (i == j) {
4509 continue;
4510 }
4511 Residue resj = residues[j];
4512 Rotamer[] rotsj = resj.getRotamers();
4513 int lenrj = rotsj.length;
4514 for (int rjC = 0; rjC < lenrj; rjC++) {
4515
4516 if (eR.check(j, rjC) || eR.check(i, riA, j, rjC)) {
4517 continue;
4518 }
4519 boolean breakOut = false;
4520
4521
4522
4523 for (int riB = 0; riB < lenri; riB++) {
4524 if (breakOut) {
4525 break;
4526 }
4527 if (eR.check(i, riB)) {
4528 continue;
4529 }
4530 for (int rjD = 0; rjD < lenrj; rjD++) {
4531 if (breakOut) {
4532 break;
4533 }
4534
4535 if (eR.check(j, rjD) || eR.check(i, riB, j, rjD)) {
4536 continue;
4537 }
4538
4539 if (riA == riB && rjC == rjD) {
4540 continue;
4541 }
4542 if (goldsteinPairElimination(residues, i, riA, riB, j, rjC, rjD)) {
4543 breakOut = true;
4544 eliminated = true;
4545 }
4546 }
4547 }
4548 }
4549 if (eR.pairsToSingleElimination(residues, i, j)) {
4550 eliminated = true;
4551 }
4552 }
4553 }
4554 }
4555 return eliminated;
4556 }
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568
4569
4570 private boolean goldsteinPairElimination(Residue[] residues, int i, int riA, int riB, int j,
4571 int rjC, int rjD) {
4572
4573 List<Residue> missedResidues = null;
4574
4575
4576 double goldsteinEnergy =
4577 eE.getSelf(i, riA) + eE.getSelf(j, rjC) + eE.get2Body(i, riA, j, rjC) - eE.getSelf(i, riB)
4578 - eE.getSelf(j, rjD) - eE.get2Body(i, riB, j, rjD);
4579
4580 try {
4581 if (parallelTeam == null) {
4582 parallelTeam = new ParallelTeam();
4583 }
4584 if (goldsteinPairRegion == null) {
4585 goldsteinPairRegion = new GoldsteinPairRegion(parallelTeam.getThreadCount());
4586 }
4587 goldsteinPairRegion.init(residues, i, riA, riB, j, rjC, rjD, bidiResNeighbors, this);
4588 parallelTeam.execute(goldsteinPairRegion);
4589 goldsteinEnergy += goldsteinPairRegion.getSumOverK();
4590 missedResidues = goldsteinPairRegion.getMissedResidues();
4591 } catch (Exception e) {
4592 logger.log(Level.WARNING, " Exception in GoldsteinPairRegion.", e);
4593 }
4594 if (missedResidues != null && !missedResidues.isEmpty()) {
4595 logIfRank0(format(
4596 " Skipping energy comparison due to a missed residue: i %d riA %d riB %d j %d rjC %d rjD %d",
4597 i, riA, riB, j, rjC, rjD), Level.FINE);
4598 return false;
4599 }
4600
4601 if (goldsteinEnergy > ensembleBuffer) {
4602 if (missedResidues.isEmpty()) {
4603 if (eR.eliminateRotamerPair(residues, i, riA, j, rjC, print)) {
4604 logIfRank0(format(
4605 " Pair elimination of [(%8s,%2d),(%8s,%2d)] by [(%8s,%2d),(%8s,%2d)]: %12.4f > %6.4f",
4606 residues[i].toFormattedString(false, true), riA,
4607 residues[j].toFormattedString(false, true), rjC,
4608 residues[i].toFormattedString(false, true), riB,
4609 residues[j].toFormattedString(false, true), rjD, goldsteinEnergy, ensembleBuffer));
4610 return true;
4611 }
4612 } else {
4613 logIfRank0(format(
4614 " No Pair elimination of [(%8s,%2d),(%8s,%2d)] by [(%8s,%2d),(%8s,%2d)]: %12.4f > %6.4f",
4615 residues[i].toFormattedString(false, true), riA,
4616 residues[j].toFormattedString(false, true), rjC,
4617 residues[i].toFormattedString(false, true), riB,
4618 residues[j].toFormattedString(false, true), rjD, goldsteinEnergy, ensembleBuffer));
4619 StringBuilder sb = new StringBuilder();
4620 for (Residue residueM : missedResidues) {
4621 sb.append(residueM);
4622 }
4623 logIfRank0(format(" due to %s.", sb));
4624 }
4625 }
4626 return false;
4627 }
4628
4629
4630
4631
4632
4633
4634 void setTestOverallOpt(boolean testing) {
4635 this.testing = testing;
4636 distanceMethod = DistanceMethod.ROTAMER;
4637 setTwoBodyCutoff(Double.MAX_VALUE);
4638 setThreeBodyCutoff(9.0);
4639 }
4640
4641
4642
4643
4644
4645
4646
4647
4648 void setTestSelfEnergyEliminations(boolean testSelfEnergyEliminations) {
4649 this.testing = true;
4650 this.testSelfEnergyEliminations = testSelfEnergyEliminations;
4651 testPairEnergyEliminations = -1;
4652 testTripleEnergyEliminations1 = -1;
4653 testTripleEnergyEliminations2 = -1;
4654 distanceMethod = DistanceMethod.ROTAMER;
4655 setTwoBodyCutoff(Double.MAX_VALUE);
4656 setThreeBodyCutoff(9.0);
4657 }
4658
4659
4660
4661
4662
4663
4664
4665
4666 void setTestPairEnergyEliminations(int testPairEnergyEliminations) {
4667 this.testing = true;
4668 this.testPairEnergyEliminations = testPairEnergyEliminations;
4669 testSelfEnergyEliminations = false;
4670 testTripleEnergyEliminations1 = -1;
4671 testTripleEnergyEliminations2 = -1;
4672 distanceMethod = DistanceMethod.ROTAMER;
4673 setTwoBodyCutoff(Double.MAX_VALUE);
4674 setThreeBodyCutoff(9.0);
4675 }
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686 void setTestTripleEnergyEliminations(int testTripleEnergyEliminations1,
4687 int testTripleEnergyEliminations2) {
4688 this.testing = true;
4689 this.testTripleEnergyEliminations1 = testTripleEnergyEliminations1;
4690 this.testTripleEnergyEliminations2 = testTripleEnergyEliminations2;
4691 testSelfEnergyEliminations = false;
4692 testPairEnergyEliminations = -1;
4693 distanceMethod = DistanceMethod.ROTAMER;
4694 setTwoBodyCutoff(Double.MAX_VALUE);
4695 setThreeBodyCutoff(9.0);
4696 }
4697
4698
4699
4700
4701
4702
4703 private void testSelfEnergyElimination(Residue[] residues) {
4704 int nRes = residues.length;
4705 for (int i = 0; i < nRes; i++) {
4706 Residue resI = residues[i];
4707 Rotamer[] rotI = resI.getRotamers();
4708 int nI = rotI.length;
4709 for (int ri = 0; ri < nI; ri++) {
4710 for (int j = i + 1; j < nRes; j++) {
4711 Residue resJ = residues[j];
4712 Rotamer[] rotJ = resJ.getRotamers();
4713 int nJ = rotJ.length;
4714 for (int rj = 0; rj < nJ; rj++) {
4715 try {
4716 eE.set2Body(i, ri, j, rj, 0, true);
4717 } catch (Exception e) {
4718
4719 }
4720 if (threeBodyTerm) {
4721 for (int k = j + 1; k < nRes; k++) {
4722 Residue resK = residues[k];
4723 Rotamer[] rotK = resK.getRotamers();
4724 int nK = rotK.length;
4725 for (int rk = 0; rk < nK; rk++) {
4726 try {
4727 eE.set3Body(residues, i, ri, j, rj, k, rk, 0, true);
4728 } catch (Exception e) {
4729
4730 }
4731 }
4732 }
4733 }
4734 }
4735 }
4736 }
4737 }
4738 }
4739
4740
4741
4742
4743
4744
4745
4746 private void testPairEnergyElimination(Residue[] residues, int resID) {
4747 int nRes = residues.length;
4748
4749 if (resID >= nRes) {
4750 return;
4751 }
4752
4753 for (int i = 0; i < nRes; i++) {
4754 Residue resI = residues[i];
4755 Rotamer[] rotI = resI.getRotamers();
4756 int nI = rotI.length;
4757 for (int ri = 0; ri < nI; ri++) {
4758 try {
4759 eE.setSelf(i, ri, 0, true);
4760 } catch (Exception e) {
4761
4762 }
4763 for (int j = i + 1; j < nRes; j++) {
4764 Residue resJ = residues[j];
4765 Rotamer[] rotJ = resJ.getRotamers();
4766 int nJ = rotJ.length;
4767 for (int rj = 0; rj < nJ; rj++) {
4768 if (i != resID && j != resID) {
4769 try {
4770 eE.set2Body(i, ri, j, rj, 0, true);
4771 } catch (Exception e) {
4772
4773 }
4774 }
4775 if (threeBodyTerm) {
4776 for (int k = j + 1; k < nRes; k++) {
4777 Residue resK = residues[k];
4778 Rotamer[] rotK = resK.getRotamers();
4779 int nK = rotK.length;
4780 for (int rk = 0; rk < nK; rk++) {
4781 try {
4782 eE.set3Body(residues, i, ri, j, rj, k, rk, 0, true);
4783 } catch (Exception e) {
4784
4785 }
4786 }
4787 }
4788 }
4789 }
4790 }
4791 }
4792 }
4793 }
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803 private void testTripleEnergyElimination(Residue[] residues, int resID1, int resID2) {
4804 int nRes = residues.length;
4805
4806 if (resID1 >= nRes) {
4807 return;
4808 }
4809 if (resID2 >= nRes) {
4810 return;
4811 }
4812 if (resID1 == resID2) {
4813 return;
4814 }
4815
4816 for (int i = 0; i < nRes; i++) {
4817 Residue resI = residues[i];
4818 Rotamer[] rotI = resI.getRotamers();
4819 int nI = rotI.length;
4820 for (int ri = 0; ri < nI; ri++) {
4821 try {
4822 eE.setSelf(i, ri, 0, true);
4823 } catch (Exception e) {
4824
4825 }
4826 for (int j = i + 1; j < nRes; j++) {
4827 Residue resJ = residues[j];
4828 Rotamer[] rotJ = resJ.getRotamers();
4829 int nJ = rotJ.length;
4830 for (int rj = 0; rj < nJ; rj++) {
4831
4832
4833
4834
4835 try {
4836 eE.set2Body(i, ri, j, rj, 0, true);
4837 } catch (Exception e) {
4838
4839 }
4840 if (threeBodyTerm) {
4841 for (int k = j + 1; k < nRes; k++) {
4842 Residue resK = residues[k];
4843 Rotamer[] rotK = resK.getRotamers();
4844 int nK = rotK.length;
4845 for (int rk = 0; rk < nK; rk++) {
4846
4847 if (i != resID1 && j != resID1 && k != resID1) {
4848 try {
4849 eE.set3Body(residues, i, ri, j, rj, k, rk, 0, true);
4850 } catch (Exception e) {
4851
4852 }
4853 }
4854 if (i != resID2 && j != resID2 && k != resID2) {
4855 try {
4856 eE.set3Body(residues, i, ri, j, rj, k, rk, 0, true);
4857 } catch (Exception e) {
4858
4859 }
4860 }
4861 }
4862 }
4863 }
4864 }
4865 }
4866 }
4867 }
4868 }
4869
4870
4871
4872
4873 public enum Algorithm {
4874 INDEPENDENT,
4875 ALL,
4876 BRUTE_FORCE,
4877 WINDOW,
4878 BOX;
4879
4880 public static Algorithm getAlgorithm(int algorithm) {
4881 switch (algorithm) {
4882 case 1:
4883 return INDEPENDENT;
4884 case 2:
4885 return ALL;
4886 case 3:
4887 return BRUTE_FORCE;
4888 case 4:
4889 return WINDOW;
4890 case 5:
4891 return BOX;
4892 default:
4893 throw new IllegalArgumentException(
4894 format(" Algorithm choice was %d, not in range 1-5!", algorithm));
4895 }
4896 }
4897 }
4898
4899
4900
4901
4902 public enum DistanceMethod {
4903 ROTAMER, RESIDUE
4904 }
4905
4906 public enum Direction {
4907 FORWARD, BACKWARD
4908 }
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
5047
5048
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071 }