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.manybody;
39
40 import ffx.algorithms.AlgorithmListener;
41 import ffx.algorithms.optimize.RotamerOptimization;
42 import ffx.numerics.Potential;
43 import ffx.potential.MolecularAssembly;
44 import ffx.potential.bonded.Atom;
45 import ffx.potential.bonded.Residue;
46 import ffx.potential.bonded.Rotamer;
47 import ffx.potential.openmm.OpenMMEnergy;
48 import ffx.potential.utils.EnergyException;
49 import org.apache.commons.configuration2.CompositeConfiguration;
50
51 import java.io.File;
52 import java.io.IOException;
53 import java.nio.charset.StandardCharsets;
54 import java.nio.file.Files;
55 import java.nio.file.Path;
56 import java.nio.file.Paths;
57 import java.util.ArrayList;
58 import java.util.HashMap;
59 import java.util.List;
60 import java.util.Map;
61 import java.util.Set;
62 import java.util.logging.Level;
63 import java.util.logging.Logger;
64
65 import static ffx.potential.bonded.RotamerLibrary.applyRotamer;
66 import static java.lang.String.format;
67
68 public class EnergyExpansion {
69
70 private static final Logger logger = Logger.getLogger(EnergyExpansion.class.getName());
71
72
73
74 private static final double DEFAULT_OMM_RECALCULATE_THRESHOLD = -200;
75
76
77
78 private static final double DEFAULT_SINGULARITY_THRESHOLD = -1000;
79
80
81
82 private final Map<Integer, Integer[]> selfEnergyMap = new HashMap<>();
83
84
85
86 private final Map<Integer, Integer[]> twoBodyEnergyMap = new HashMap<>();
87
88
89
90 private final Map<Integer, Integer[]> threeBodyEnergyMap = new HashMap<>();
91
92
93
94 private final Map<Integer, Integer[]> fourBodyEnergyMap = new HashMap<>();
95
96
97
98 private final boolean master;
99
100
101
102
103 private final double ommRecalculateThreshold;
104
105
106
107
108
109
110 private final double singularityThreshold;
111
112
113
114 private final boolean potentialIsOpenMM;
115 private final RotamerOptimization rO;
116 private final DistanceMatrix dM;
117 private final EliminatedRotamers eR;
118
119
120
121 private final MolecularAssembly molecularAssembly;
122
123
124
125 private final AlgorithmListener algorithmListener;
126
127
128
129
130 private final List<Residue> allResiduesList;
131
132
133
134 private final int[][] resNeighbors;
135
136
137
138 private final boolean threeBodyTerm;
139
140
141
142 private final boolean decomposeOriginal;
143
144
145
146 private final boolean usingBoxOptimization;
147
148
149
150 private final boolean verbose;
151
152
153
154 private final boolean pruneClashes;
155
156
157
158 private final boolean prunePairClashes;
159
160
161
162 private final int max4BodyCount;
163
164
165
166 private double backboneEnergy;
167
168
169
170 private double[][] selfEnergy;
171
172
173
174
175 private double[][][][] twoBodyEnergy;
176
177
178
179
180 private double[][][][][][] threeBodyEnergy;
181
182 public EnergyExpansion(RotamerOptimization rO, DistanceMatrix dM, EliminatedRotamers eR,
183 MolecularAssembly molecularAssembly, Potential potential, AlgorithmListener algorithmListener,
184 List<Residue> allResiduesList, int[][] resNeighbors, boolean threeBodyTerm,
185 boolean decomposeOriginal, boolean usingBoxOptimization, boolean verbose,
186 boolean pruneClashes, boolean prunePairClashes, boolean master) {
187 this.rO = rO;
188 this.dM = dM;
189 this.eR = eR;
190 this.molecularAssembly = molecularAssembly;
191 this.algorithmListener = algorithmListener;
192 this.allResiduesList = allResiduesList;
193 this.resNeighbors = resNeighbors;
194 this.threeBodyTerm = threeBodyTerm;
195 this.decomposeOriginal = decomposeOriginal;
196 this.usingBoxOptimization = usingBoxOptimization;
197 this.verbose = verbose;
198 this.pruneClashes = pruneClashes;
199 this.prunePairClashes = prunePairClashes;
200 this.master = master;
201
202 CompositeConfiguration properties = molecularAssembly.getProperties();
203 max4BodyCount = properties.getInt("ro-max4BodyCount", Integer.MAX_VALUE);
204 if (max4BodyCount != Integer.MAX_VALUE) {
205 logger.info(format(" Max 4Body Count: %d", max4BodyCount));
206 }
207 singularityThreshold = properties.getDouble("ro-singularityThreshold", DEFAULT_SINGULARITY_THRESHOLD);
208 potentialIsOpenMM = potential instanceof OpenMMEnergy;
209 if (potentialIsOpenMM) {
210 ommRecalculateThreshold = properties.getDouble("ro-ommRecalculateThreshold", DEFAULT_OMM_RECALCULATE_THRESHOLD);
211 } else {
212 ommRecalculateThreshold = -1E200;
213 }
214 }
215
216
217
218
219
220
221 private static void turnOffAtoms(Residue residue) {
222 switch (residue.getResidueType()) {
223 case NA:
224 case AA:
225 List<Atom> atomList = residue.getVariableAtoms();
226 for (Atom atom : atomList) {
227 atom.setUse(false);
228 }
229 break;
230 default:
231 atomList = residue.getAtomList();
232 for (Atom atom : atomList) {
233 atom.setUse(false);
234 }
235 break;
236 }
237 }
238
239
240
241
242
243
244 private static void turnOnAtoms(Residue residue) {
245 switch (residue.getResidueType()) {
246 case NA:
247 case AA:
248 List<Atom> atomList = residue.getVariableAtoms();
249 for (Atom atom : atomList) {
250 atom.setUse(true);
251 }
252 break;
253 default:
254 atomList = residue.getAtomList();
255 for (Atom atom : atomList) {
256 atom.setUse(true);
257 }
258 break;
259 }
260 }
261
262 public HashMap<String, Integer> allocate2BodyJobMap(Residue[] residues, int nResidues,
263 boolean reverseMap) {
264 twoBodyEnergyMap.clear();
265
266 HashMap<String, Integer> reverseJobMapPairs = new HashMap<>();
267 int pairJobIndex = 0;
268 twoBodyEnergy = new double[nResidues][][][];
269 for (int i = 0; i < nResidues; i++) {
270 Residue resi = residues[i];
271 int indexI = allResiduesList.indexOf(resi);
272 Rotamer[] roti = resi.getRotamers();
273 int[] nI = resNeighbors[i];
274 int lenNI = nI.length;
275 twoBodyEnergy[i] = new double[roti.length][lenNI][];
276
277 for (int ri = 0; ri < roti.length; ri++) {
278 if (eR.check(i, ri)) {
279 continue;
280 }
281
282 for (int indJ = 0; indJ < lenNI; indJ++) {
283 int j = nI[indJ];
284 if (rO.checkNeighboringPair(i, j)) {
285 Residue resj = residues[j];
286 int indexJ = allResiduesList.indexOf(resj);
287 Rotamer[] rotj = resj.getRotamers();
288 twoBodyEnergy[i][ri][indJ] = new double[rotj.length];
289 for (int rj = 0; rj < rotj.length; rj++) {
290 if (eR.checkToJ(i, ri, j, rj)) {
291 continue;
292 }
293
294
295 if (dM.checkPairDistThreshold(indexI, ri, indexJ, rj)) {
296 continue;
297 }
298
299 Integer[] pairJob = {i, ri, j, rj};
300 if (decomposeOriginal && (ri != 0 || rj != 0)) {
301 continue;
302 }
303 twoBodyEnergyMap.put(pairJobIndex, pairJob);
304 if (reverseMap) {
305 String revKey = format("%d %d %d %d", i, ri, j, rj);
306 reverseJobMapPairs.put(revKey, pairJobIndex);
307 }
308 pairJobIndex++;
309 }
310 }
311 }
312 }
313 }
314 return reverseJobMapPairs;
315 }
316
317 public HashMap<String, Integer> allocate3BodyJobMap(Residue[] residues, int nResidues,
318 boolean reverseMap) {
319 HashMap<String, Integer> reverseJobMapTrimers = new HashMap<>();
320 threeBodyEnergyMap.clear();
321
322 threeBodyEnergy = new double[nResidues][][][][][];
323 int trimerJobIndex = 0;
324 for (int i = 0; i < nResidues; i++) {
325 Residue resi = residues[i];
326 int indexI = allResiduesList.indexOf(resi);
327 Rotamer[] roti = resi.getRotamers();
328 int lenri = roti.length;
329 int[] nI = resNeighbors[i];
330 int lenNI = nI.length;
331 threeBodyEnergy[i] = new double[lenri][lenNI][][][];
332
333 for (int ri = 0; ri < lenri; ri++) {
334 if (eR.check(i, ri)) {
335 continue;
336 }
337 for (int indJ = 0; indJ < lenNI; indJ++) {
338
339 int j = nI[indJ];
340 Residue resj = residues[j];
341 int indexJ = allResiduesList.indexOf(resj);
342 Rotamer[] rotj = resj.getRotamers();
343 int lenrj = rotj.length;
344 int[] nJ = resNeighbors[j];
345 int lenNJ = nJ.length;
346 threeBodyEnergy[i][ri][indJ] = new double[lenrj][lenNJ][];
347
348 for (int rj = 0; rj < lenrj; rj++) {
349 if (eR.checkToJ(i, ri, j, rj)) {
350 continue;
351 }
352
353 for (int indK = 0; indK < lenNJ; indK++) {
354 int k = nJ[indK];
355 Residue resk = residues[k];
356 int indexK = allResiduesList.indexOf(resk);
357 Rotamer[] rotk = resk.getRotamers();
358 int lenrk = rotk.length;
359 threeBodyEnergy[i][ri][indJ][rj][indK] = new double[lenrk];
360
361 for (int rk = 0; rk < lenrk; rk++) {
362 if (eR.checkToK(i, ri, j, rj, k, rk)) {
363 continue;
364 }
365 if (dM.checkTriDistThreshold(indexI, ri, indexJ, rj, indexK, rk)) {
366 continue;
367 }
368 Integer[] trimerJob = {i, ri, j, rj, k, rk};
369 if (decomposeOriginal && (ri != 0 || rj != 0 || rk != 0)) {
370 continue;
371 }
372 threeBodyEnergyMap.put(trimerJobIndex, trimerJob);
373 if (reverseMap) {
374 String revKey = format("%d %d %d %d %d %d", i, ri, j, rj, k, rk);
375 reverseJobMapTrimers.put(revKey, trimerJobIndex);
376 }
377 trimerJobIndex++;
378 }
379 }
380 }
381 }
382 }
383 }
384 return reverseJobMapTrimers;
385 }
386
387 public void allocate4BodyJobMap(Residue[] residues, int nResidues) {
388 logger.info(" Creating 4-Body jobs...");
389 fourBodyEnergyMap.clear();
390 boolean maxedOut = false;
391
392 int quadJobIndex = 0;
393 for (int i = 0; i < nResidues; i++) {
394 Residue resi = residues[i];
395 Rotamer[] roti = resi.getRotamers();
396 for (int ri = 0; ri < roti.length; ri++) {
397 if (eR.check(i, ri)) {
398 continue;
399 }
400 for (int j = i + 1; j < nResidues; j++) {
401 Residue resj = residues[j];
402 Rotamer[] rotj = resj.getRotamers();
403 for (int rj = 0; rj < rotj.length; rj++) {
404
405
406
407 if (eR.checkToJ(i, ri, j, rj)) {
408 continue;
409 }
410 for (int k = j + 1; k < nResidues; k++) {
411 Residue resk = residues[k];
412 Rotamer[] rotk = resk.getRotamers();
413 for (int rk = 0; rk < rotk.length; rk++) {
414
415
416
417 if (eR.checkToK(i, ri, j, rj, k, rk)) {
418 continue;
419 }
420 for (int l = k + 1; l < nResidues; l++) {
421 Residue resl = residues[l];
422 Rotamer[] rotl = resl.getRotamers();
423 for (int rl = 0; rl < rotl.length; rl++) {
424 if (eR.checkToL(i, ri, j, rj, k, rk, l, rl)) {
425 continue;
426 }
427 Integer[] quadJob = {i, ri, j, rj, k, rk, l, rl};
428 if (decomposeOriginal && (ri != 0 || rj != 0 || rk != 0 || rl != 0)) {
429 continue;
430 }
431 fourBodyEnergyMap.put(quadJobIndex++, quadJob);
432 if (fourBodyEnergyMap.size() > max4BodyCount) {
433 maxedOut = true;
434 break;
435 }
436 }
437 if (maxedOut) {
438 break;
439 }
440 }
441 if (maxedOut) {
442 break;
443 }
444 }
445 if (maxedOut) {
446 break;
447 }
448 }
449 if (maxedOut) {
450 break;
451 }
452 }
453 if (maxedOut) {
454 break;
455 }
456 }
457 if (maxedOut) {
458 break;
459 }
460 }
461 if (maxedOut) {
462 break;
463 }
464 }
465 }
466
467 public HashMap<String, Integer> allocateSelfJobMap(Residue[] residues, int nResidues,
468 boolean reverseMap) {
469 selfEnergyMap.clear();
470
471 HashMap<String, Integer> reverseJobMapSingles = new HashMap<>();
472 int singleJobIndex = 0;
473 selfEnergy = new double[nResidues][];
474 for (int i = 0; i < nResidues; i++) {
475 Residue resi = residues[i];
476 Rotamer[] roti = resi.getRotamers();
477 selfEnergy[i] = new double[roti.length];
478 for (int ri = 0; ri < roti.length; ri++) {
479 if (!eR.check(i, ri)) {
480 Integer[] selfJob = {i, ri};
481 if (decomposeOriginal && ri != 0) {
482 continue;
483 }
484 selfEnergyMap.put(singleJobIndex, selfJob);
485 if (reverseMap) {
486 String revKey = format("%d %d", i, ri);
487 reverseJobMapSingles.put(revKey, singleJobIndex);
488 }
489 singleJobIndex++;
490 }
491 }
492 }
493 return reverseJobMapSingles;
494 }
495
496
497
498
499
500
501
502
503
504
505
506
507 public double compute2BodyEnergy(Residue[] residues, int i, int ri, int j, int rj) {
508 rO.turnOffAllResidues(residues);
509 turnOnResidue(residues[i], ri);
510 turnOnResidue(residues[j], rj);
511 double energy;
512 try {
513 if (algorithmListener != null) {
514 algorithmListener.algorithmUpdate(molecularAssembly);
515 }
516 Rotamer[] rot_i = residues[i].getRotamers();
517 Rotamer[] rot_j = residues[j].getRotamers();
518 double subtract =
519 -backboneEnergy - getSelf(i, ri, rot_i[ri], true) - getSelf(j, rj, rot_j[rj], true);
520
521
522 energy = rO.currentEnergy(residues) + subtract;
523 if (logger.isLoggable(Level.FINE)) {
524 logger.fine(format(" %s Pair-Energy %16.8f = FF %16.8f - BB %16.8f + Self Ri %16.8f + Self Rj %16.8f ",
525 rot_i[ri].getName() + "-" + rot_j[rj].getName(), energy, energy + backboneEnergy, backboneEnergy,
526 getSelf(i, ri, rot_i[ri], true) , getSelf(j, rj, rot_j[rj], true)));
527 }
528 if (potentialIsOpenMM && energy < ommRecalculateThreshold) {
529 logger.warning(
530 format(" Experimental: re-computing pair energy %s-%d %s-%d using Force Field X",
531 residues[i], ri, residues[j], rj));
532 energy = rO.currentFFXPE() + subtract;
533 }
534 if (energy < singularityThreshold) {
535 String message = format(
536 " Rejecting pair energy for %s-%d %s-%d is %10.5g << %10f, " + "likely in error.",
537 residues[i], ri, residues[j], rj, energy, singularityThreshold);
538 logger.warning(message);
539 throw new EnergyException(message, false, energy);
540 }
541 } finally {
542
543 turnOffResidue(residues[i]);
544 turnOffResidue(residues[j]);
545 }
546 return energy;
547 }
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563 public double compute3BodyEnergy(Residue[] residues, int i, int ri, int j, int rj, int k, int rk) {
564 turnOffAllResidues(residues);
565 turnOnResidue(residues[i], ri);
566 turnOnResidue(residues[j], rj);
567 turnOnResidue(residues[k], rk);
568 Rotamer[] rot_i = residues[i].getRotamers();
569 Rotamer[] rot_j = residues[j].getRotamers();
570 Rotamer[] rot_k = residues[k].getRotamers();
571 double energy;
572 try {
573 if (algorithmListener != null) {
574 algorithmListener.algorithmUpdate(molecularAssembly);
575 }
576 double subtract =
577 -backboneEnergy - getSelf(i, ri, rot_i[ri], true) - getSelf(j, rj, rot_j[rj], true)
578 - getSelf(k, rk, rot_k[rk], true) - get2Body(i, ri, j, rj) - get2Body(i, ri, k, rk)
579 - get2Body(j, rj, k, rk);
580 energy = rO.currentEnergy(residues) + subtract;
581 if (potentialIsOpenMM && energy < ommRecalculateThreshold) {
582 logger.warning(
583 format(" Experimental: re-computing triple energy %s-%d %s-%d %s-%d using Force Field X",
584 residues[i], ri, residues[j], rj, residues[k], rk));
585 energy = rO.currentFFXPE() + subtract;
586 }
587 if (energy < singularityThreshold) {
588 String message = format(" Rejecting triple energy for %s-%d %s-%d %s-%d is %10.5g << %10f, "
589 + "likely in error.", residues[i], ri, residues[j], rj, residues[k], rk, energy,
590 singularityThreshold);
591 logger.warning(message);
592 throw new EnergyException(message);
593 }
594 } finally {
595
596 turnOffResidue(residues[i]);
597 turnOffResidue(residues[j]);
598 turnOffResidue(residues[k]);
599 }
600 return energy;
601 }
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618 public double compute4BodyEnergy(Residue[] residues, int i, int ri, int j, int rj, int k, int rk,
619 int l, int rl) {
620 turnOffAllResidues(residues);
621 turnOnResidue(residues[i], ri);
622 turnOnResidue(residues[j], rj);
623 turnOnResidue(residues[k], rk);
624 turnOnResidue(residues[l], rl);
625 double energy;
626 try {
627 if (algorithmListener != null) {
628 algorithmListener.algorithmUpdate(molecularAssembly);
629 }
630 double subtract =
631 -backboneEnergy - getSelf(i, ri) - getSelf(j, rj) - getSelf(k, rk) - getSelf(l, rl)
632 - get2Body(i, ri, j, rj) - get2Body(i, ri, k, rk) - get2Body(i, ri, l, rl)
633 - get2Body(j, rj, k, rk) - get2Body(j, rj, l, rl) - get2Body(k, rk, l, rl)
634 - get3Body(residues, i, ri, j, rj, k, rk) - get3Body(residues, i, ri, j, rj, l, rl)
635 - get3Body(residues, i, ri, k, rk, l, rl) - get3Body(residues, j, rj, k, rk, l, rl);
636 energy = rO.currentEnergy(residues) + subtract;
637
638 if (potentialIsOpenMM && energy < ommRecalculateThreshold) {
639 logger.warning(format(
640 " Experimental: re-computing quad energy %s-%d %s-%d %s-%d %s-%d using Force Field X",
641 residues[i], ri, residues[j], rj, residues[k], rk, residues[l], rl));
642 energy = rO.currentFFXPE() + subtract;
643 }
644 if (energy < singularityThreshold) {
645 String message = format(
646 " Rejecting quad energy for %s-%d %s-%d %s-%d %s-%d is %10.5g << %10f, "
647 + "likely in error.", residues[i], ri, residues[j], rj, residues[k], rk, residues[l],
648 rl, energy, singularityThreshold);
649 logger.warning(message);
650 throw new EnergyException(message);
651 }
652
653 } finally {
654
655 turnOffResidue(residues[i]);
656 turnOffResidue(residues[j]);
657 turnOffResidue(residues[k]);
658 turnOffResidue(residues[l]);
659 }
660 return energy;
661 }
662
663
664
665
666
667
668
669
670
671
672
673
674
675 public double computeSelfEnergy(Residue[] residues, int i, int ri) {
676 rO.turnOffAllResidues(residues);
677 rO.turnOnResidue(residues[i], ri);
678 double KpH = rO.getPHRestraint();
679 double energy;
680 try {
681 if (algorithmListener != null) {
682 algorithmListener.algorithmUpdate(molecularAssembly);
683 }
684 energy = rO.currentEnergy(residues) - backboneEnergy;
685 if (potentialIsOpenMM && energy < ommRecalculateThreshold) {
686 logger.warning(
687 format(" Experimental: re-computing self energy %s-%d using Force Field X", residues[i],
688 ri));
689 energy = rO.currentFFXPE() - backboneEnergy;
690 }
691 if (energy < singularityThreshold) {
692 String message = format(
693 " Rejecting self energy for %s-%d is %10.5g << %10f, " + "likely in error.", residues[i],
694 ri, energy, singularityThreshold);
695 logger.warning(message);
696 throw new EnergyException(message);
697 }
698 } finally {
699 rO.turnOffResidue(residues[i]);
700 }
701
702 Rotamer[] rotamers = residues[i].getRotamers();
703
704 if (rotamers[ri].isTitrating) {
705 double bias = rotamers[ri].getRotamerPhBias();
706
707 double pH = rO.getPH();
708 String name = rotamers[ri].getName();
709 double pHrestraint = 0;
710
711 switch (name) {
712 case "ASP":
713 if (pH <= 3.94) {
714 pHrestraint = 0.5 * KpH * Math.pow(pH - 3.94, 2);
715 }
716 break;
717 case "ASH":
718 if (pH >= 3.94) {
719 pHrestraint = 0.5 * KpH * Math.pow(pH - 3.94, 2);
720 }
721 break;
722 case "GLU":
723 if (pH <= 4.25) {
724 pHrestraint = 0.5 * KpH * Math.pow(pH - 4.25, 2);
725 }
726 break;
727 case "GLH":
728 if (pH >= 4.25) {
729 pHrestraint = 0.5 * KpH * Math.pow(pH - 4.25, 2);
730 }
731 break;
732 case "HIS":
733 if (pH >= 6.6) {
734 pHrestraint = 0.5 * KpH * Math.pow(pH - 6.6, 2);
735 }
736 break;
737 case "HID":
738 if (pH <= 7.0) {
739 pHrestraint = 0.5 * KpH * Math.pow(pH - 7.0, 2);
740 }
741 break;
742 case "HIE":
743 if(pH <= 6.6){
744 pHrestraint = 0.5 * KpH * Math.pow(pH - 6.6, 2);
745 }
746 break;
747 case "LYD":
748 if(pH <= 10.4){
749 pHrestraint = 0.5 * KpH * Math.pow(pH - 10.4, 2);
750 }
751 break;
752 case "LYS":
753 if(pH >= 10.4){
754 pHrestraint = 0.5 * KpH * Math.pow(pH - 10.4, 2);
755 }
756 break;
757 case "CYD":
758 if(pH - 8.55 <= 0){
759 pHrestraint = 0.5 * KpH * Math.pow(pH - 8.55,2);
760 }
761 break;
762 case "CYS":
763 if(pH - 8.55 >= 0){
764 pHrestraint = 0.5 * KpH * Math.pow(pH - 8.55,2);
765 }
766 break;
767 default:
768 break;
769 }
770
771 if (logger.isLoggable(Level.FINE)) {
772 logger.fine(format(" %s Self-Energy %16.8f = FF %16.8f - BB %16.8f + Ph Bias %16.8f + pHrestraint %16.8f ",
773 rotamers[ri].getName(), energy + bias + pHrestraint, energy + backboneEnergy, backboneEnergy, bias, pHrestraint));
774 }
775 energy += bias + pHrestraint;
776 }
777 return energy;
778 }
779
780
781
782
783
784
785
786
787
788 public double getTotalRotamerPhBias(List<Residue> residues, int[] rotamers, double pH, double KpH) {
789 double total = 0.0;
790 int n = residues.size();
791 for (int i = 0; i < n; i++) {
792 Rotamer[] rot = residues.get(i).getRotamers();
793 int ri = rotamers[i];
794 double pHrestraint = 0;
795 if (rot[ri].isTitrating) {
796 switch (rot[ri].getName()) {
797 case "ASP":
798 if (pH <= 3.94) {
799 pHrestraint = 0.5 * KpH * Math.pow(pH - 3.94, 2);
800 }
801 break;
802 case "ASH":
803 if (pH >= 3.94) {
804 pHrestraint = 0.5 * KpH * Math.pow(pH - 3.94, 2);
805 }
806 break;
807 case "GLU":
808 if (pH <= 4.25) {
809 pHrestraint = 0.5 * KpH * Math.pow(pH - 4.25, 2);
810 }
811 break;
812 case "GLH":
813 if (pH >= 4.25) {
814 pHrestraint = 0.5 * KpH * Math.pow(pH - 4.25, 2);
815 }
816 break;
817 case "HIS":
818 if (pH >= 6.6) {
819 pHrestraint = 0.5 * KpH * Math.pow(pH - 6.6, 2);
820 }
821 break;
822 case "HID":
823 if (pH <= 7.0) {
824 pHrestraint = 0.5 * KpH * Math.pow(pH - 7.0, 2);
825 }
826 break;
827 case "HIE":
828 if(pH <= 6.6){
829 pHrestraint = 0.5 * KpH * Math.pow(pH - 6.6, 2);
830 }
831 break;
832 case "LYD":
833 if(pH <= 10.4){
834 pHrestraint = 0.5 * KpH * Math.pow(pH - 10.4, 2);
835 }
836 break;
837 case "LYS":
838 if(pH >= 10.4){
839 pHrestraint = 0.5 * KpH * Math.pow(pH - 10.4, 2);
840 }
841 break;
842 case "CYD":
843 if(pH - 8.55 <= 0){
844 pHrestraint = 0.5 * KpH * Math.pow(pH - 8.55,2);
845 }
846 break;
847 case "CYS":
848 if(pH - 8.55 >= 0){
849 pHrestraint = 0.5 * KpH * Math.pow(pH - 8.55,2);
850 }
851 break;
852 default:
853 break;
854 }
855 total += rot[ri].getRotamerPhBias() + pHrestraint;
856 }
857 }
858 return total;
859 }
860
861
862
863
864
865
866
867
868
869
870
871 public double get2Body(int i, int ri, int j, int rj) {
872
873 if (j < i) {
874 int ii = i;
875 int iri = ri;
876 i = j;
877 ri = rj;
878 j = ii;
879 rj = iri;
880 }
881 try {
882
883 int[] nI = resNeighbors[i];
884 int indJ = -1;
885 for (int l = 0; l < nI.length; l++) {
886 if (nI[l] == j) {
887 indJ = l;
888 break;
889 }
890 }
891 if (indJ == -1) {
892 logger.fine(format(" Residue %d not found in neighbors of %d; assumed past cutoff.", j, i));
893 return 0;
894 } else {
895 return twoBodyEnergy[i][ri][indJ][rj];
896 }
897 } catch (NullPointerException npe) {
898 logger.info(format(" NPE for 2-body energy (%3d,%2d) (%3d,%2d).", i, ri, j, rj));
899 throw npe;
900 }
901 }
902
903
904
905
906
907
908
909
910
911
912
913
914
915 public double get3Body(Residue[] residues, int i, int ri, int j, int rj, int k, int rk) {
916 if (!threeBodyTerm) {
917 return 0.0;
918 }
919
920 if (j < i) {
921 int ii = i;
922 int iri = ri;
923 i = j;
924 ri = rj;
925 j = ii;
926 rj = iri;
927 }
928 if (k < i) {
929 int ii = i;
930 int iri = ri;
931 i = k;
932 ri = rk;
933 k = ii;
934 rk = iri;
935 }
936 if (k < j) {
937 int jj = j;
938 int jrj = rj;
939 j = k;
940 rj = rk;
941 k = jj;
942 rk = jrj;
943 }
944
945
946 int[] nI = resNeighbors[i];
947 int indJ = -1;
948 for (int l = 0; l < nI.length; l++) {
949 if (nI[l] == j) {
950 indJ = l;
951 break;
952 }
953 }
954
955 int[] nJ = resNeighbors[j];
956 int indK = -1;
957 for (int l = 0; l < nJ.length; l++) {
958 if (nJ[l] == k) {
959 indK = l;
960 break;
961 }
962 }
963
964
965
966
967 int indexI = allResiduesList.indexOf(residues[i]);
968 int indexJ = allResiduesList.indexOf(residues[j]);
969 int indexK = allResiduesList.indexOf(residues[k]);
970 if (dM.checkTriDistThreshold(indexI, ri, indexJ, rj, indexK, rk)) {
971 return 0;
972 } else {
973 try {
974 return threeBodyEnergy[i][ri][indJ][rj][indK][rk];
975 } catch (NullPointerException | ArrayIndexOutOfBoundsException ex) {
976 String message = format(
977 " Could not find an energy for 3-body energy (%3d,%2d) (%3d,%2d) (%3d,%2d)", i, ri, j,
978 rj, k, rk);
979 logger.warning(message);
980 throw ex;
981 }
982 }
983 }
984
985 public double getBackboneEnergy() {
986 return backboneEnergy;
987 }
988
989 public void setBackboneEnergy(double backboneEnergy) {
990 this.backboneEnergy = backboneEnergy;
991 }
992
993 public Map<Integer, Integer[]> getFourBodyEnergyMap() {
994 return fourBodyEnergyMap;
995 }
996
997
998
999
1000
1001
1002
1003
1004 public double getSelf(int i, int ri) {
1005 try {
1006 return selfEnergy[i][ri];
1007 } catch (NullPointerException npe) {
1008 logger.info(format(" NPE for self energy (%3d,%2d).", i, ri));
1009 throw npe;
1010 }
1011 }
1012
1013
1014
1015
1016
1017
1018
1019
1020 public double getSelf(int i, int ri, Rotamer rot, boolean excludeFMod) {
1021 try {
1022 double totalSelf;
1023 if (rot.isTitrating && excludeFMod) {
1024 String name = rot.getName();
1025 double pHRestraint = 0;
1026 switch (name) {
1027 case "ASP":
1028 if (rO.getPH() <= 3.94) {
1029 pHRestraint = 0.5 * rO.getPHRestraint() * Math.pow(rO.getPH() - 3.94, 2);
1030 }
1031 break;
1032 case "ASH":
1033 if (rO.getPH() >= 3.94) {
1034 pHRestraint = 0.5 * rO.getPHRestraint() * Math.pow(rO.getPH() - 3.94, 2);
1035 }
1036 break;
1037 case "GLU":
1038 if (rO.getPH() <= 4.25) {
1039 pHRestraint = 0.5 * rO.getPHRestraint() * Math.pow(rO.getPH() - 4.25, 2);
1040 }
1041 break;
1042 case "GLH":
1043 if (rO.getPH() >= 4.25) {
1044 pHRestraint = 0.5 * rO.getPHRestraint() * Math.pow(rO.getPH() - 4.25, 2);
1045 }
1046 break;
1047 case "HIS":
1048 if (rO.getPH() >= 6.6) {
1049 pHRestraint = 0.5 * rO.getPHRestraint() * Math.pow(rO.getPH() - 6.6, 2);
1050 }
1051 break;
1052 case "HID":
1053 if (rO.getPH() <= 7.0) {
1054 pHRestraint = 0.5 * rO.getPHRestraint() * Math.pow(rO.getPH() - 7.0, 2);
1055 }
1056 break;
1057 case "HIE":
1058 if(rO.getPH() <= 6.6){
1059 pHRestraint = 0.5 * rO.getPHRestraint() * Math.pow(rO.getPH() - 6.6, 2);
1060 }
1061 break;
1062 case "LYD":
1063 if(rO.getPH() <= 10.4){
1064 pHRestraint = 0.5*rO.getPHRestraint()*Math.pow(rO.getPH()- 10.4,2);
1065 }
1066 break;
1067 case "LYS":
1068 if(rO.getPH() >= 10.4){
1069 pHRestraint = 0.5*rO.getPHRestraint()*Math.pow(rO.getPH()- 10.4,2);
1070 }
1071 break;
1072 case "CYD":
1073 if(rO.getPH() - 8.55 <= 0){
1074 pHRestraint = 0.5*rO.getPHRestraint()*Math.pow(rO.getPH()- 8.55,2);
1075 }
1076 break;
1077 case "CYS":
1078 if(rO.getPH() - 8.55 >= 0){
1079 pHRestraint = 0.5*rO.getPHRestraint()*Math.pow(rO.getPH()- 8.55,2);
1080 }
1081 break;
1082 default:
1083 break;
1084 }
1085 totalSelf = selfEnergy[i][ri] - rot.getRotamerPhBias() - pHRestraint;
1086 } else {
1087 totalSelf = selfEnergy[i][ri];
1088 }
1089 return totalSelf;
1090 } catch (NullPointerException npe) {
1091 logger.info(format(" NPE for self energy (%3d,%2d).", i, ri));
1092 throw npe;
1093 }
1094 }
1095
1096
1097 public Map<Integer, Integer[]> getSelfEnergyMap() {
1098 return selfEnergyMap;
1099 }
1100
1101 public Map<Integer, Integer[]> getThreeBodyEnergyMap() {
1102 return threeBodyEnergyMap;
1103 }
1104
1105 public Map<Integer, Integer[]> getTwoBodyEnergyMap() {
1106 return twoBodyEnergyMap;
1107 }
1108
1109 public int loadEnergyRestart(File restartFile, Residue[] residues) {
1110 return loadEnergyRestart(restartFile, residues, -1, null);
1111 }
1112
1113 public int loadEnergyRestart(File restartFile, Residue[] residues, int boxIteration,
1114 int[] cellIndices) {
1115 try {
1116 int nResidues = residues.length;
1117 Path path = Paths.get(restartFile.getCanonicalPath());
1118 List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
1119 List<String> linesThisBox = new ArrayList<>();
1120
1121 try {
1122 backboneEnergy = rO.computeBackboneEnergy(residues);
1123 } catch (ArithmeticException ex) {
1124 logger.severe(
1125 format(" Exception %s in calculating backbone energy; FFX shutting down.", ex));
1126 }
1127 rO.logIfRank0(format("\n Backbone energy: %s\n", rO.formatEnergy(backboneEnergy)));
1128
1129 if (usingBoxOptimization && boxIteration >= 0) {
1130 boolean foundBox = false;
1131 for (int i = 0; i < lines.size(); i++) {
1132 String line = lines.get(i);
1133 if (line.startsWith("Box")) {
1134 String[] tok = line.replaceAll("Box", "").replaceAll(":", ",").replaceAll(" ", "")
1135 .split(",");
1136 int readIteration = Integer.parseInt(tok[0]);
1137 int readCellIndexX = Integer.parseInt(tok[1]);
1138 int readCellIndexY = Integer.parseInt(tok[2]);
1139 int readCellIndexZ = Integer.parseInt(tok[3]);
1140 if (readIteration == boxIteration && readCellIndexX == cellIndices[0]
1141 && readCellIndexY == cellIndices[1] && readCellIndexZ == cellIndices[2]) {
1142 foundBox = true;
1143 for (int j = i + 1; j < lines.size(); j++) {
1144 String l = lines.get(j);
1145 if (l.startsWith("Box")) {
1146 break;
1147 }
1148 linesThisBox.add(l);
1149 }
1150 break;
1151 }
1152 }
1153 }
1154 if (!foundBox) {
1155 rO.logIfRank0(format(" Didn't find restart energies for Box %d: %d,%d,%d", boxIteration,
1156 cellIndices[0], cellIndices[1], cellIndices[2]));
1157 return 0;
1158 } else if (linesThisBox.isEmpty()) {
1159 return 0;
1160 } else {
1161 lines = linesThisBox;
1162 }
1163 }
1164
1165 List<String> singleLines = new ArrayList<>();
1166 List<String> pairLines = new ArrayList<>();
1167 List<String> tripleLines = new ArrayList<>();
1168 for (String line : lines) {
1169 String[] tok = line.split("\\s");
1170 if (tok[0].startsWith("Self")) {
1171 singleLines.add(line);
1172 } else if (tok[0].startsWith("Pair")) {
1173 pairLines.add(line);
1174 } else if (tok[0].startsWith("Triple")) {
1175 tripleLines.add(line);
1176 }
1177 }
1178 int loaded = 0;
1179 if (!tripleLines.isEmpty()) {
1180 loaded = 3;
1181 } else if (!pairLines.isEmpty()) {
1182 loaded = 2;
1183 } else if (!singleLines.isEmpty()) {
1184 loaded = 1;
1185 } else {
1186 logger.warning(
1187 format(" Empty or unreadable energy restart file: %s.", restartFile.getCanonicalPath()));
1188 }
1189 if (loaded >= 1) {
1190 boolean reverseMap = true;
1191 HashMap<String, Integer> reverseJobMapSingles = allocateSelfJobMap(residues, nResidues,
1192 reverseMap);
1193
1194 for (String line : singleLines) {
1195 try {
1196 String[] tok = line.replace(",", "").replace(":", "").split("\\s+");
1197 int i;
1198 if (tok[1].contains("-")) {
1199 i = nameToNumber(tok[1], residues);
1200 } else {
1201 i = Integer.parseInt(tok[1]);
1202 }
1203 int ri = Integer.parseInt(tok[2]);
1204 double energy = Double.parseDouble(tok[3]);
1205 try {
1206 setSelf(i, ri, energy);
1207 if (verbose) {
1208 rO.logIfRank0(format(" From restart file: Self energy %3d (%8s,%2d): %s", i,
1209 residues[i].toFormattedString(false, true), ri, rO.formatEnergy(energy)));
1210 }
1211 } catch (Exception e) {
1212 if (verbose) {
1213 rO.logIfRank0(format(" Restart file out-of-bounds index: %s", line));
1214 }
1215 }
1216
1217 String revKey = format("%d %d", i, ri);
1218 selfEnergyMap.remove(reverseJobMapSingles.get(revKey));
1219 } catch (NumberFormatException ex) {
1220 logger.log(Level.WARNING, format(" Unparsable line in energy restart file: \n%s", line),
1221 ex);
1222 }
1223 }
1224 rO.logIfRank0(" Loaded self energies from restart file.");
1225
1226
1227 eR.prePruneSelves(residues);
1228
1229
1230 if (pruneClashes) {
1231 eR.pruneSingleClashes(residues);
1232 }
1233 }
1234
1235
1236 condenseEnergyMap(selfEnergyMap);
1237
1238 if (loaded >= 2) {
1239 if (!selfEnergyMap.isEmpty()) {
1240 rO.logIfRank0(
1241 " Double-check that parameters match original run due to missing self-energies.");
1242 }
1243 boolean reverseMap = true;
1244 HashMap<String, Integer> reverseJobMapPairs = allocate2BodyJobMap(residues, nResidues,
1245 reverseMap);
1246
1247
1248 for (String line : pairLines) {
1249 try {
1250 String[] tok = line.replace(",", "").replace(":", "").split("\\s+");
1251 int i;
1252 if (tok[1].contains("-")) {
1253 i = nameToNumber(tok[1], residues);
1254 } else {
1255 i = Integer.parseInt(tok[1]);
1256 }
1257 int ri = Integer.parseInt(tok[2]);
1258 int j;
1259 if (tok[3].contains("-")) {
1260 j = nameToNumber(tok[3], residues);
1261 } else {
1262 j = Integer.parseInt(tok[3]);
1263 }
1264 int rj = Integer.parseInt(tok[4]);
1265 double energy = Double.parseDouble(tok[5]);
1266 try {
1267
1268
1269
1270
1271 if (rO.checkNeighboringPair(i, j)) {
1272
1273
1274 Residue residueI = residues[i];
1275 Residue residueJ = residues[j];
1276 int indexI = allResiduesList.indexOf(residueI);
1277 int indexJ = allResiduesList.indexOf(residueJ);
1278 if (!dM.checkPairDistThreshold(indexI, ri, indexJ, rj)) {
1279 set2Body(i, ri, j, rj, energy);
1280
1281 double resDist = dM.getResidueDistance(indexI, ri, indexJ, rj);
1282 String resDistString = "large";
1283 if (resDist < Double.MAX_VALUE) {
1284 resDistString = format("%5.3f", resDist);
1285 }
1286
1287 double dist = dM.checkDistMatrix(indexI, ri, indexJ, rj);
1288 String distString = " large";
1289 if (dist < Double.MAX_VALUE) {
1290 distString = format("%10.3f", dist);
1291 }
1292
1293 logger.fine(format(" Pair %8s %-2d, %8s %-2d: %s at %s Ang (%s Ang by residue).",
1294 residueI.toFormattedString(false, true), ri,
1295 residueJ.toFormattedString(false, true), rj,
1296 rO.formatEnergy(get2Body(i, ri, j, rj)), distString, resDistString));
1297 }
1298 } else {
1299 logger.fine(format(
1300 "Ignoring a pair-energy from outside the cutoff: 2-energy [(%8s,%2d),(%8s,%2d)]: %12.4f",
1301 residues[i].toFormattedString(false, true), ri,
1302 residues[j].toFormattedString(false, true), rj, energy));
1303 }
1304
1305 if (verbose) {
1306 rO.logIfRank0(
1307 format(" From restart file: Pair energy [(%8s,%2d),(%8s,%2d)]: %12.4f",
1308 residues[i].toFormattedString(false, true), ri,
1309 residues[j].toFormattedString(false, true), rj, energy));
1310 }
1311 } catch (Exception e) {
1312 if (verbose) {
1313 rO.logIfRank0(format(" Restart file out-of-bounds index: %s", line));
1314 }
1315 }
1316
1317 String revKey = format("%d %d %d %d", i, ri, j, rj);
1318 twoBodyEnergyMap.remove(reverseJobMapPairs.get(revKey));
1319 } catch (NumberFormatException ex) {
1320 logger.log(Level.WARNING, format("Unparsable line in energy restart file: \n%s", line),
1321 ex);
1322 }
1323 }
1324 rO.logIfRank0(" Loaded 2-body energies from restart file.");
1325
1326
1327 eR.prePrunePairs(residues);
1328
1329
1330 if (prunePairClashes) {
1331 eR.prunePairClashes(residues);
1332 }
1333 }
1334
1335
1336 condenseEnergyMap(twoBodyEnergyMap);
1337
1338 if (loaded >= 3) {
1339 if (!twoBodyEnergyMap.isEmpty()) {
1340 if (master) {
1341 logger.warning(
1342 "Double-check that parameters match original run! Found trimers in restart file, but pairs job queue is non-empty.");
1343 }
1344 }
1345 boolean reverseMap = true;
1346 HashMap<String, Integer> reverseJobMapTrimers = allocate3BodyJobMap(residues, nResidues,
1347 reverseMap);
1348
1349
1350
1351 for (String line : tripleLines) {
1352 try {
1353 String[] tok = line.replace(",", "").replace(":", "").split("\\s+");
1354 int i;
1355 if (tok[1].contains("-")) {
1356 i = nameToNumber(tok[1], residues);
1357 } else {
1358 i = Integer.parseInt(tok[1]);
1359 }
1360 int ri = Integer.parseInt(tok[2]);
1361 int j;
1362 if (tok[3].contains("-")) {
1363 j = nameToNumber(tok[3], residues);
1364 } else {
1365 j = Integer.parseInt(tok[3]);
1366 }
1367 int rj = Integer.parseInt(tok[4]);
1368 int k;
1369 if (tok[5].contains("-")) {
1370 k = nameToNumber(tok[5], residues);
1371 } else {
1372 k = Integer.parseInt(tok[5]);
1373 }
1374 int rk = Integer.parseInt(tok[6]);
1375 double energy = Double.parseDouble(tok[7]);
1376
1377 try {
1378
1379
1380
1381
1382
1383
1384 if (rO.checkNeighboringTriple(i, j, k)) {
1385
1386
1387 Residue residueI = residues[i];
1388 Residue residueJ = residues[j];
1389 Residue residueK = residues[k];
1390 int indexI = allResiduesList.indexOf(residueI);
1391 int indexJ = allResiduesList.indexOf(residueJ);
1392 int indexK = allResiduesList.indexOf(residueK);
1393 if (!dM.checkTriDistThreshold(indexI, ri, indexJ, rj, indexK, rk)) {
1394 set3Body(residues, i, ri, j, rj, k, rk, energy);
1395
1396 double resDist = dM.get3BodyResidueDistance(indexI, ri, indexJ, rj, indexK, rk);
1397 String resDistString = " large";
1398 if (resDist < Double.MAX_VALUE) {
1399 resDistString = format("%5.3f", resDist);
1400 }
1401
1402 double rawDist = dM.getRawNBodyDistance(indexI, ri, indexJ, rj, indexK, rk);
1403 String distString = " large";
1404 if (rawDist < Double.MAX_VALUE) {
1405 distString = format("%10.3f", rawDist);
1406 }
1407
1408 logger.fine(format(
1409 " 3-Body %8s %-2d, %8s %-2d, %8s %-2d: %s at %s Ang (%s Ang by residue).",
1410 residueI.toFormattedString(false, true), ri,
1411 residueJ.toFormattedString(false, true), rj,
1412 residueK.toFormattedString(false, true), rk,
1413 rO.formatEnergy(get3Body(residues, i, ri, j, rj, k, rk)), distString,
1414 resDistString));
1415 }
1416 } else {
1417 logger.fine(format(
1418 "Ignoring a triple-energy from outside the cutoff: 3-Body %8s %-2d, %8s %-2d, %8s %-2d: %s",
1419 residues[i].toFormattedString(false, true), ri,
1420 residues[j].toFormattedString(false, true), rj,
1421 residues[k].toFormattedString(false, true), rk,
1422 rO.formatEnergy(get3Body(residues, i, ri, j, rj, k, rk))));
1423 }
1424 } catch (ArrayIndexOutOfBoundsException ex) {
1425 if (verbose) {
1426 rO.logIfRank0(format(" Restart file out-of-bounds index: %s", line));
1427 }
1428 } catch (NullPointerException npe) {
1429 if (verbose) {
1430 rO.logIfRank0(format(" NPE in loading 3-body energies: pruning "
1431 + "likely changed! 3-body %s-%d %s-%d %s-%d",
1432 residues[i].toFormattedString(false, true), ri, residues[j], rj, residues[k],
1433 rk));
1434 }
1435 }
1436 if (verbose) {
1437 rO.logIfRank0(
1438 format(" From restart file: Trimer energy %3d %-2d, %3d %-2d, %3d %-2d: %s", i, ri,
1439 j, rj, k, rk, rO.formatEnergy(energy)));
1440 }
1441
1442 String revKey = format("%d %d %d %d %d %d", i, ri, j, rj, k, rk);
1443 threeBodyEnergyMap.remove(reverseJobMapTrimers.get(revKey));
1444 } catch (NumberFormatException ex) {
1445 logger.log(Level.WARNING, format("Unparsable line in energy restart file: \n%s", line),
1446 ex);
1447 }
1448 }
1449 rO.logIfRank0(" Loaded trimer energies from restart file.");
1450 }
1451
1452
1453 condenseEnergyMap(threeBodyEnergyMap);
1454
1455 return loaded;
1456 } catch (IOException ex) {
1457 logger.log(Level.WARNING, "Exception while loading energy restart file.", ex);
1458 }
1459
1460 return 0;
1461 }
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472 public double lowestPairEnergy(Residue[] residues, int i, int ri, int j) {
1473 if (residues == null) {
1474 return 0.0;
1475 }
1476 int n = residues.length;
1477 if (i < 0 || i >= n) {
1478 return 0.0;
1479 }
1480 if (j < 0 || j >= n) {
1481 return 0.0;
1482 }
1483
1484 Rotamer[] rotamers = residues[j].getRotamers();
1485 int nr = rotamers.length;
1486 double energy = Double.MAX_VALUE;
1487 for (int jr = 0; jr < nr; jr++) {
1488 try {
1489 double e = get2Body(i, ri, j, jr);
1490 if (e < energy) {
1491 energy = e;
1492 }
1493 } catch (Exception e) {
1494
1495 }
1496 }
1497 return energy;
1498 }
1499
1500
1501
1502
1503
1504
1505
1506
1507 public double lowestSelfEnergy(Residue[] residues, int i) {
1508 if (residues == null) {
1509 return 0.0;
1510 }
1511 int n = residues.length;
1512 if (i < 0 || i >= n) {
1513 return 0.0;
1514 }
1515 Rotamer[] rotamers = residues[i].getRotamers();
1516 int nr = rotamers.length;
1517 double energy = Double.MAX_VALUE;
1518 for (int ni = 0; ni < nr; ni++) {
1519 try {
1520 double e = getSelf(i, ni);
1521 if (e < energy) {
1522 energy = e;
1523 }
1524 } catch (Exception e) {
1525
1526 }
1527 }
1528 return energy;
1529 }
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543 public boolean minMaxE2(Residue[] residues, double[] minMax, int i, int ri, int j, int rj)
1544 throws IllegalArgumentException {
1545 Residue resi = residues[i];
1546 Residue resj = residues[j];
1547 if (eR.check(i, ri) || eR.check(j, rj) || eR.check(i, ri, j, rj)) {
1548 throw new IllegalArgumentException(
1549 format(" Called for minMaxE2 on an eliminated pair %s-%d %s-%d",
1550 resi.toFormattedString(false, true), ri, resj.toFormattedString(false, true), rj));
1551 }
1552
1553
1554 minMax[0] = 0;
1555
1556 minMax[1] = 0;
1557
1558 int nRes = residues.length;
1559 for (int k = 0; k < nRes; k++) {
1560 if (k == i || k == j) {
1561 continue;
1562 }
1563 Residue resk = residues[k];
1564 Rotamer[] rotsk = resk.getRotamers();
1565 int lenrk = rotsk.length;
1566 double[] minMaxK = new double[2];
1567 minMaxK[0] = Double.MAX_VALUE;
1568 minMaxK[1] = Double.MIN_VALUE;
1569
1570 for (int rk = 0; rk < lenrk; rk++) {
1571 if (eR.check(k, rk)) {
1572
1573 continue;
1574 }
1575 if (eR.check(i, ri, k, rk) || eR.check(j, rj, k, rk)) {
1576
1577
1578
1579
1580 minMaxK[1] = Double.NaN;
1581 } else {
1582
1583
1584
1585 double currentMin = get2Body(i, ri, k, rk) + get2Body(j, rj, k, rk);
1586 double currentMax = currentMin;
1587 if (threeBodyTerm) {
1588
1589 currentMin += get3Body(residues, i, ri, j, rj, k, rk);
1590 currentMax = currentMin;
1591
1592
1593 double[] minMaxTriple = new double[2];
1594 if (minMaxE3(residues, minMaxTriple, i, ri, j, rj, k, rk)) {
1595
1596 assert (Double.isFinite(minMaxTriple[0]) && minMaxTriple[0] != Double.MAX_VALUE);
1597
1598
1599 currentMin += minMaxTriple[0];
1600
1601 if (Double.isFinite(currentMax) && Double.isFinite(minMaxTriple[1])) {
1602 currentMax += minMaxTriple[1];
1603 } else {
1604 currentMax = Double.NaN;
1605 }
1606 } else {
1607
1608 currentMin = Double.NaN;
1609 currentMax = Double.NaN;
1610 }
1611 }
1612
1613 assert (threeBodyTerm || currentMax == currentMin);
1614
1615
1616 if (Double.isFinite(currentMin) && currentMin < minMaxK[0]) {
1617
1618 minMaxK[0] = currentMin;
1619 }
1620
1621 if (Double.isFinite(currentMax) && Double.isFinite(minMaxK[1])) {
1622
1623 minMaxK[1] = Math.max(currentMax, minMaxK[1]);
1624 } else {
1625
1626 minMaxK[1] = Double.NaN;
1627 }
1628 }
1629 }
1630
1631 if (Double.isFinite(minMaxK[0])) {
1632
1633 minMax[0] += minMaxK[0];
1634 } else {
1635
1636 minMax[0] = Double.NaN;
1637 minMax[1] = Double.NaN;
1638 return false;
1639 }
1640 if (Double.isFinite(minMaxK[1]) && Double.isFinite(minMax[1])) {
1641
1642 minMax[1] += minMaxK[1];
1643 } else {
1644
1645 minMax[1] = Double.NaN;
1646 }
1647 }
1648
1649 return Double.isFinite(minMax[0]);
1650 }
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665 public boolean minMaxPairEnergy(Residue[] residues, double[] minMax, int i, int ri, int j) {
1666 Residue residuej = residues[j];
1667 Rotamer[] rotamersj = residuej.getRotamers();
1668 int lenrj = rotamersj.length;
1669 boolean valid = false;
1670 minMax[0] = Double.MAX_VALUE;
1671 minMax[1] = Double.MIN_VALUE;
1672
1673
1674 for (int rj = 0; rj < lenrj; rj++) {
1675
1676 if (eR.check(i, ri) || eR.check(j, rj) || eR.check(i, ri, j, rj)) {
1677 continue;
1678 }
1679
1680 double currMax = get2Body(i, ri, j, rj);
1681 double currMin = currMax;
1682
1683 if (threeBodyTerm) {
1684 double[] minMaxTriple = new double[2];
1685
1686 boolean validPair = minMax2BodySum(residues, minMaxTriple, i, ri, j, rj);
1687 if (!validPair) {
1688
1689 Residue residuei = residues[i];
1690 rO.logIfRank0(format(" Inconsistent Pair: %8s %2d, %8s %2d.",
1691 residuei.toFormattedString(false, true), ri, residuej.toFormattedString(false, true),
1692 rj), Level.INFO);
1693 continue;
1694 }
1695
1696 if (Double.isFinite(currMin) && Double.isFinite(minMaxTriple[0])) {
1697 currMin += minMaxTriple[0];
1698 } else {
1699 currMin = Double.NaN;
1700 }
1701
1702 if (Double.isFinite(currMax) && Double.isFinite(minMaxTriple[1])) {
1703 currMax += minMaxTriple[1];
1704 } else {
1705 currMax = Double.NaN;
1706 }
1707 }
1708
1709 valid = true;
1710 if (Double.isFinite(currMin) && currMin < minMax[0]) {
1711 minMax[0] = currMin;
1712 }
1713
1714 if (Double.isFinite(currMax) && Double.isFinite(minMax[1])) {
1715 if (currMax > minMax[1]) {
1716
1717 minMax[1] = currMax;
1718 }
1719 } else {
1720
1721 minMax[1] = Double.NaN;
1722 }
1723 }
1724
1725
1726
1727 minMax[0] = (minMax[0] == Double.MAX_VALUE) ? Double.NaN : minMax[0];
1728
1729 return valid;
1730 }
1731
1732 public void set2Body(int i, int ri, int j, int rj, double e) {
1733 set2Body(i, ri, j, rj, e, false);
1734 }
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746 public void set2Body(int i, int ri, int j, int rj, double e, boolean quiet) {
1747
1748 if (j < i) {
1749 int ii = i;
1750 int iri = ri;
1751 i = j;
1752 ri = rj;
1753 j = ii;
1754 rj = iri;
1755 }
1756 try {
1757
1758 int[] nI = resNeighbors[i];
1759 int indJ = -1;
1760 for (int l = 0; l < nI.length; l++) {
1761 if (nI[l] == j) {
1762 indJ = l;
1763 break;
1764 }
1765 }
1766 if (indJ == -1) {
1767 throw new IllegalArgumentException(
1768 format(" Residue %d not found in neighbors of %d; assumed past cutoff.", j, i));
1769 } else {
1770 twoBodyEnergy[i][ri][indJ][rj] = e;
1771 }
1772 } catch (NullPointerException npe) {
1773 if (!quiet) {
1774 logger.info(format(" NPE for 2-body energy (%3d,%2d) (%3d,%2d).", i, ri, j, rj));
1775 }
1776 throw npe;
1777 }
1778 }
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792 public void set3Body(Residue[] residues, int i, int ri, int j, int rj, int k, int rk, double e) {
1793 set3Body(residues, i, ri, j, rj, k, rk, e, false);
1794 }
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810 public void set3Body(Residue[] residues, int i, int ri, int j, int rj, int k, int rk, double e,
1811 boolean quiet) throws IllegalStateException {
1812 if (!threeBodyTerm) {
1813 throw new IllegalStateException(
1814 " Attempting to set a 3-body energy when threeBodyTerm is false!");
1815 }
1816
1817 if (j < i) {
1818 int ii = i;
1819 int iri = ri;
1820 i = j;
1821 ri = rj;
1822 j = ii;
1823 rj = iri;
1824 }
1825 if (k < i) {
1826 int ii = i;
1827 int iri = ri;
1828 i = k;
1829 ri = rk;
1830 k = ii;
1831 rk = iri;
1832 }
1833 if (k < j) {
1834 int jj = j;
1835 int jrj = rj;
1836 j = k;
1837 rj = rk;
1838 k = jj;
1839 rk = jrj;
1840 }
1841
1842
1843 int[] nI = resNeighbors[i];
1844 int indJ = -1;
1845 for (int l = 0; l < nI.length; l++) {
1846 if (nI[l] == j) {
1847 indJ = l;
1848 break;
1849 }
1850 }
1851
1852 int[] nJ = resNeighbors[j];
1853 int indK = -1;
1854 for (int l = 0; l < nJ.length; l++) {
1855 if (nJ[l] == k) {
1856 indK = l;
1857 break;
1858 }
1859 }
1860
1861
1862
1863
1864 int indexI = allResiduesList.indexOf(residues[i]);
1865 int indexJ = allResiduesList.indexOf(residues[j]);
1866 int indexK = allResiduesList.indexOf(residues[k]);
1867 if (dM.checkTriDistThreshold(indexI, ri, indexJ, rj, indexK, rk)) {
1868 throw new IllegalArgumentException(
1869 format(" Residue %d not found in neighbors of %d; assumed past cutoff.", j, i));
1870 } else {
1871 try {
1872 threeBodyEnergy[i][ri][indJ][rj][indK][rk] = e;
1873 } catch (NullPointerException | ArrayIndexOutOfBoundsException ex) {
1874 if (!quiet) {
1875 String message = format(
1876 " Could not access threeBodyEnergy array for 3-body energy (%3d,%2d) (%3d,%2d) (%3d,%2d)",
1877 i, ri, j, rj, k, rk);
1878 logger.warning(message);
1879 }
1880 throw ex;
1881 }
1882 }
1883 }
1884
1885 public void setSelf(int i, int ri, double e) {
1886 setSelf(i, ri, e, false);
1887 }
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897 public void setSelf(int i, int ri, double e, boolean quiet) {
1898 try {
1899 selfEnergy[i][ri] = e;
1900 } catch (NullPointerException | ArrayIndexOutOfBoundsException ex) {
1901 if (!quiet) {
1902 logger.warning(format(" NPE or array index error for (%3d,%2d)", i, ri));
1903 }
1904 throw ex;
1905 }
1906 }
1907
1908 public void turnOffAllResidues(Residue[] residues) {
1909 if (residues == null) {
1910 return;
1911 }
1912 for (Residue residue : residues) {
1913 turnOffResidue(residue);
1914 }
1915 }
1916
1917 public void turnOffResidue(Residue residue) {
1918 turnOffAtoms(residue);
1919 applyDefaultRotamer(residue);
1920 }
1921
1922 public void turnOnAllResidues(Residue[] residues) {
1923 if (residues == null) {
1924 return;
1925 }
1926 for (Residue residue : residues) {
1927 turnOnAtoms(residue);
1928 }
1929 }
1930
1931 public void turnOnResidue(Residue residue, int ri) {
1932 turnOnAtoms(residue);
1933 Rotamer[] rotamers = residue.getRotamers();
1934 applyRotamer(residue, rotamers[ri]);
1935 }
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948 private boolean minMax2BodySum(Residue[] residues, double[] minMax, int i, int ri, int j, int rj) {
1949 int nres = residues.length;
1950 double minSum = 0.0;
1951 double maxSum = 0.0;
1952 for (int k = 0; k < nres; k++) {
1953 if (k == i || k == j) {
1954 continue;
1955 }
1956 Residue residuek = residues[k];
1957 Rotamer[] romatersk = residuek.getRotamers();
1958 int lenrk = romatersk.length;
1959 double currentMin = Double.MAX_VALUE;
1960 double currentMax = Double.MIN_VALUE;
1961 for (int rk = 0; rk < lenrk; rk++) {
1962 if (eR.check(k, rk)) {
1963
1964 continue;
1965 }
1966 if (eR.check(i, ri, k, rk) || eR.check(j, rj, k, rk)) {
1967
1968
1969 currentMax = Double.NaN;
1970 } else {
1971 double current = get3Body(residues, i, ri, j, rj, k, rk);
1972 if (Double.isFinite(current) && current < currentMin) {
1973 currentMin = current;
1974 }
1975 if (Double.isFinite(current) && Double.isFinite(currentMax)) {
1976 if (current > currentMax) {
1977 currentMax = current;
1978 }
1979 } else {
1980
1981 currentMax = Double.NaN;
1982 }
1983 }
1984 }
1985 if (currentMin == Double.MAX_VALUE || !Double.isFinite(minSum)) {
1986
1987
1988 minMax[0] = Double.NaN;
1989 minMax[1] = Double.NaN;
1990 return false;
1991 } else {
1992
1993 minSum += currentMin;
1994 }
1995 if (Double.isFinite(maxSum) && Double.isFinite(currentMax)) {
1996 maxSum += currentMax;
1997 } else {
1998 maxSum = Double.NaN;
1999 }
2000 }
2001 minMax[0] = minSum;
2002 minMax[1] = maxSum;
2003 return true;
2004 }
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021 private boolean minMaxE3(Residue[] residues, double[] minMax, int i, int ri, int j, int rj, int k,
2022 int rk) throws IllegalArgumentException {
2023 Residue resi = residues[i];
2024 Residue resj = residues[j];
2025 Residue resk = residues[k];
2026 if (eR.check(i, ri) || eR.check(j, rj) || eR.check(k, rk) || eR.check(i, ri, j, rj)
2027 || eR.check(i, ri, k, rk) || eR.check(j, rj, k, rk)) {
2028
2029 throw new IllegalArgumentException(
2030 format(" Called for minMaxE2 on an eliminated triple %s-%d %s-%d %s-%d",
2031 resi.toFormattedString(false, true), ri, resj.toFormattedString(false, true), rj,
2032 resk.toFormattedString(false, true), rk));
2033 }
2034
2035
2036 minMax[0] = 0;
2037 minMax[1] = 0;
2038 int nRes = residues.length;
2039 for (int l = 0; l < nRes; l++) {
2040 if (l == i || l == j || l == k) {
2041 continue;
2042 }
2043 Residue resl = residues[l];
2044 Rotamer[] rotsl = resl.getRotamers();
2045 int lenrl = rotsl.length;
2046
2047
2048 double currentMax = Double.MIN_VALUE;
2049 double currentMin = Double.MAX_VALUE;
2050
2051 for (int rl = 0; rl < lenrl; rl++) {
2052 if (eR.check(l, rl) || eR.check(k, rk, l, rl)) {
2053
2054 continue;
2055 }
2056
2057 double current;
2058 if (eR.check(i, ri, l, rl) || eR.check(j, rj, l, rl)) {
2059
2060 current = Double.NaN;
2061 } else {
2062
2063 current =
2064 get3Body(residues, i, ri, k, rk, l, rl) + get3Body(residues, j, rj, k, rk, l, rl);
2065 }
2066
2067
2068
2069
2070
2071 if (Double.isFinite(current) && current < currentMin) {
2072
2073 currentMin = current;
2074 }
2075
2076 if (Double.isFinite(current) && Double.isFinite(currentMax)) {
2077 if (current > currentMax) {
2078 currentMax = current;
2079 }
2080 } else {
2081 currentMax = Double.NaN;
2082 }
2083 }
2084
2085 if (Double.isFinite(currentMin)) {
2086 minMax[0] += currentMin;
2087 } else {
2088
2089 minMax[0] = Double.NaN;
2090 minMax[1] = Double.NaN;
2091 return false;
2092 }
2093
2094 if (Double.isFinite(currentMax) && Double.isFinite(minMax[1])) {
2095 minMax[1] += currentMax;
2096 } else {
2097 minMax[1] = Double.NaN;
2098 }
2099
2100 }
2101 return Double.isFinite(minMax[0]);
2102 }
2103
2104
2105
2106
2107
2108
2109 private void applyDefaultRotamer(Residue residue) {
2110 applyRotamer(residue, residue.getRotamers()[0]);
2111 }
2112
2113 private int nameToNumber(String residueString, Residue[] residues) throws NumberFormatException {
2114 int ret = -1;
2115 for (int x = 0; x < residues.length; x++) {
2116 if (residueString.equals(residues[x].toString())) {
2117 ret = x;
2118 break;
2119 }
2120 }
2121 if (ret == -1) {
2122 throw new NumberFormatException();
2123 }
2124 return ret;
2125 }
2126
2127 private void condenseEnergyMap(Map<Integer, Integer[]> energyMap) {
2128 Set<Integer> keys = energyMap.keySet();
2129 HashMap<Integer, Integer[]> tempMap = new HashMap<>();
2130 int count = 0;
2131 for (int key : keys) {
2132 tempMap.put(count, energyMap.get(key));
2133 count++;
2134 }
2135 energyMap.clear();
2136 energyMap.putAll(tempMap);
2137 }
2138 }