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