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.mc;
39
40 import ffx.numerics.Potential;
41 import ffx.potential.ForceFieldEnergy;
42 import ffx.potential.MolecularAssembly;
43 import ffx.potential.bonded.AminoAcidUtils;
44 import ffx.potential.bonded.AminoAcidUtils.AminoAcid3;
45 import ffx.potential.bonded.Angle;
46 import ffx.potential.bonded.Atom;
47 import ffx.potential.bonded.Bond;
48 import ffx.potential.bonded.Residue;
49 import ffx.potential.bonded.ResidueState;
50 import ffx.potential.bonded.Rotamer;
51 import ffx.potential.bonded.RotamerLibrary;
52 import ffx.potential.bonded.Torsion;
53 import ffx.potential.parameters.AtomType;
54 import ffx.potential.parsers.PDBFilter;
55 import org.apache.commons.configuration2.CompositeConfiguration;
56 import org.apache.commons.io.FilenameUtils;
57 import org.apache.commons.math3.util.FastMath;
58
59 import java.io.BufferedWriter;
60 import java.io.File;
61 import java.io.FileWriter;
62 import java.io.IOException;
63 import java.util.ArrayList;
64 import java.util.HashMap;
65 import java.util.List;
66 import java.util.concurrent.ThreadLocalRandom;
67 import java.util.logging.Logger;
68
69 import static ffx.utilities.Constants.R;
70 import static java.lang.String.format;
71 import static java.lang.System.arraycopy;
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89 public class RosenbluthChiAllMove implements MCMove {
90
91 private static final Logger logger = Logger.getLogger(RosenbluthChiAllMove.class.getName());
92 private static int numAccepted = 0;
93
94 private final MolecularAssembly molecularAssembly;
95
96 private final Residue target;
97
98 private final ResidueState origState;
99
100 private final ForceFieldEnergy forceFieldEnergy;
101
102 private final double beta;
103 private final int testSetSize;
104 private final ThreadLocalRandom rand = ThreadLocalRandom.current();
105 private final StringBuilder report = new StringBuilder();
106 private final boolean[] doChi = new boolean[4];
107 private final MODE mode;
108 private final boolean torsionSampling;
109 private final double CATASTROPHE_THRESHOLD = -10000;
110
111 private final double NS_TO_MS = 0.000001;
112
113 double finalEnergy = 0.0;
114
115 private Rotamer proposedMove;
116
117 private PDBFilter writer;
118
119 private SnapshotWriter snapshotWriter = null;
120
121 private double Wn = 0.0;
122 private double Wo = 0.0;
123 private final int moveNumber;
124 private double[] proposedChis = new double[4];
125 private boolean accepted = false;
126
127 private final double origEnergy;
128
129 private final long startTime;
130
131 private long endTime;
132
133 private final boolean verbose;
134 private final boolean randInts;
135 private final boolean noSnaps;
136 private final boolean printTestSets;
137 private final boolean logTimings;
138 private final boolean verboseEnergies;
139
140
141
142
143
144
145
146
147
148
149
150
151
152 RosenbluthChiAllMove(MolecularAssembly molecularAssembly, Residue target, int testSetSize,
153 ForceFieldEnergy forceFieldEnergy, double temperature, boolean writeSnapshots, int moveNumber,
154 boolean verbose) {
155
156 CompositeConfiguration properties = molecularAssembly.getProperties();
157 if (properties.containsKey("cbmc-type")) {
158 mode = MODE.valueOf(properties.getString("cbmc-type"));
159 } else {
160 logger.severe("CBMC: must specify a bias type.");
161 mode = MODE.CHEAP;
162 }
163
164 this.startTime = System.nanoTime();
165 this.molecularAssembly = molecularAssembly;
166 this.target = target;
167 this.testSetSize = testSetSize;
168 this.forceFieldEnergy = forceFieldEnergy;
169 this.beta = 1 / (R * temperature);
170 this.moveNumber = moveNumber;
171 this.verbose = verbose;
172 origState = target.storeState();
173
174 randInts = properties.getBoolean("cbmc-randInts", false);
175 noSnaps = properties.getBoolean("cbmc-noSnaps", false);
176 printTestSets = properties.getBoolean("cbmc-printTestSets", false);
177 logTimings = properties.getBoolean("cbmc-logTimings", false);
178 verboseEnergies = properties.getBoolean("cbmc-verboseEnergies", false);
179
180 if (writeSnapshots) {
181 snapshotWriter = new SnapshotWriter(molecularAssembly, false);
182 }
183
184 doChi[0] = properties.getBoolean("cbmc-doChi0", false);
185 doChi[1] = properties.getBoolean("cbmc-doChi1", false);
186 doChi[2] = properties.getBoolean("cbmc-doChi2", false);
187 doChi[3] = properties.getBoolean("cbmc-doChi3", false);
188 if (!doChi[0] && !doChi[1] && !doChi[2] && !doChi[3]) {
189 doChi[0] = true;
190 doChi[1] = true;
191 doChi[2] = true;
192 doChi[3] = true;
193 }
194 updateAll();
195 origEnergy = totalEnergy();
196
197 torsionSampling = properties.getBoolean("cbmc-torsionSampler", false);
198 if (torsionSampling) {
199 logger.info(" Torsion Sampler engaged!");
200 HashMap<Integer, BackBondedList> map = createBackBondedMap(
201 AminoAcidUtils.AminoAcid3.valueOf(target.getName()));
202 List<Torsion> allTors = new ArrayList<>();
203 for (int i = 0; i < map.size(); i++) {
204 Torsion tors = map.get(i).torsion;
205 allTors.add(tors);
206 }
207 torsionSampler(allTors);
208 System.exit(0);
209 }
210 try {
211 switch (mode) {
212 case EXPENSIVE -> engageExpensive();
213 case CHEAP -> engageCheap();
214 case CTRL_ALL -> engageControlAll();
215 default -> logger.severe("CBMC: Unknown biasing type requested.");
216 }
217 } catch (ArithmeticException ex) {
218 target.revertState(origState);
219 accepted = false;
220 }
221 }
222
223
224
225
226
227
228 public MODE getMode() {
229 return mode;
230 }
231
232
233
234
235
236
237 public double getWn() {
238 return Wn;
239 }
240
241
242
243
244
245
246
247 @Override
248 public void move() {
249 RotamerLibrary.applyRotamer(target, proposedMove);
250 updateAll();
251 }
252
253
254
255
256
257
258 @Override
259 public void revertMove() {
260 target.revertState(origState);
261 updateAll();
262 }
263
264
265 @Override
266 public String toString() {
267 return format("Rosenbluth Rotamer Move:\n Res: %s\n Rota: %s", target.toString(),
268 proposedMove.toString());
269 }
270
271 private void write() {
272 if (noSnaps) {
273 return;
274 }
275 if (writer == null) {
276 writer = new PDBFilter(molecularAssembly.getFile(), molecularAssembly, null, null);
277 }
278 String filename = molecularAssembly.getFile().getAbsolutePath();
279 if (!filename.contains("_mc")) {
280 filename = FilenameUtils.removeExtension(filename) + "_mc.pdb";
281 }
282 File file = new File(filename);
283 writer.writeFile(file, false);
284 }
285
286
287
288
289
290
291 double getWo() {
292 return Wo;
293 }
294
295
296
297
298
299
300 private TrialSet cheapTorsionSet(List<Torsion> allTors, int setSize, String snapSuffix) {
301 if (printTestSets) {
302 report.append(" TrialSet_Cheap (uDep uExt)\n");
303 }
304 TrialSet trialSet = new TrialSet(setSize);
305 double[] origChi = RotamerLibrary.measureRotamer(target, false);
306 int i = 0;
307 while (i < setSize) {
308 double[] newChi = new double[origChi.length];
309 arraycopy(origChi, 0, newChi, 0, origChi.length);
310 for (int k = 0; k < origChi.length; k++) {
311 if (doChi[k]) {
312 if (randInts) {
313 newChi[k] = rand.nextInt(360) - 180;
314 } else {
315 newChi[k] = rand.nextDouble(360.0) - 180;
316 }
317 }
318 }
319 Rotamer newState = createRotamer(target, newChi);
320 RotamerLibrary.applyRotamer(target, newState);
321 double uTors = 0;
322 for (int j = 0; j < allTors.size(); j++) {
323 if (doChi[j]) {
324 uTors += allTors.get(j).energy(false);
325 double offset = 0;
326 try {
327 offset = TORSION_OFFSET_AMPRO13.valueOf(target.getName() + j).offset;
328 } catch (IllegalArgumentException ex) {
329 logger.warning(ex.getMessage());
330 }
331 uTors += offset;
332 }
333 }
334 double criterion = FastMath.exp(-beta * uTors);
335 double rng = rand.nextDouble();
336 if (rng < criterion) {
337 trialSet.theta[i] = 0.0;
338 trialSet.rotamer[i] = newState;
339 trialSet.uDep[i] = uTors;
340 trialSet.uExt[i] = totalEnergy() - uTors;
341 i++;
342 writeSnapshot(snapSuffix, true);
343 if (printTestSets) {
344 if (i < 5 || i > setSize - 1) {
345 report.append(
346 format(" %3s %d: %5.2f\t%5.2f\n", snapSuffix, i, trialSet.uDep[i - 1],
347 trialSet.uExt[i - 1]));
348 } else if (i == 5) {
349 report.append(" ...\n");
350 }
351 }
352 }
353 }
354 target.revertState(origState);
355 updateAll();
356 return trialSet;
357 }
358
359
360
361
362 private TrialSet expensiveTorsionSet(Torsion tors, int chiIndex, int setSize, String snapSuffix) {
363 report.append(format(" TrialSet for Chi%d\t\t(Theta uDep uExt)\n", chiIndex));
364 TrialSet trialSet = new TrialSet(setSize);
365 double[] origChi = RotamerLibrary.measureRotamer(target, false);
366 int i = 0;
367 while (i < setSize) {
368 double theta = rand.nextDouble(360.0) - 180;
369 double[] newChi = new double[origChi.length];
370 arraycopy(origChi, 0, newChi, 0, origChi.length);
371 newChi[chiIndex] = theta;
372 Rotamer newState = createRotamer(target, newChi);
373 RotamerLibrary.applyRotamer(target, newState);
374 double uTors = tors.energy(false);
375 double offset = 0;
376 try {
377 offset = TORSION_OFFSET_AMPRO13.valueOf(target.getName() + chiIndex).offset;
378 } catch (IllegalArgumentException ex) {
379 logger.warning(ex.getMessage());
380 }
381 uTors += offset;
382 double criterion = FastMath.exp(-beta * uTors);
383 double rng = rand.nextDouble();
384 report.append(format(" prop: %5.1f %.2g %.2g %.2g\n", theta, uTors, criterion, rng));
385 if (rng < criterion) {
386 report.append(" ^ Accepted!\n");
387 writeSnapshot(snapSuffix, false);
388 trialSet.theta[i] = theta;
389 trialSet.rotamer[i] = newState;
390 trialSet.uDep[i] = uTors;
391 trialSet.uExt[i] = totalEnergy() - uTors;
392 i++;
393 writeSnapshot(snapSuffix, true);
394 if (i < 4 || i > setSize - 1) {
395 report.append(format(" %3s %d: %5.2f\t%5.2f\t%5.2f\n", snapSuffix, i, theta,
396 trialSet.uDep[i - 1], trialSet.uExt[i - 1]));
397 } else if (i == 4) {
398 report.append(" ...\n");
399 }
400 }
401 }
402 target.revertState(origState);
403 updateAll();
404 return trialSet;
405 }
406
407
408
409
410
411
412
413
414
415 private void engageCheap() {
416 report.append(format(" Rosenbluth CBMC Move: %4d (%s)\n", moveNumber, target));
417
418 AminoAcid3 name = AminoAcidUtils.AminoAcid3.valueOf(target.getName());
419 double[] chi = RotamerLibrary.measureRotamer(target, false);
420 HashMap<Integer, BackBondedList> map = createBackBondedMap(name);
421
422
423
424
425
426
427
428 List<Torsion> allTors = new ArrayList<>();
429 for (int i = 0; i < chi.length; i++) {
430 Torsion tors = map.get(i).torsion;
431 allTors.add(tors);
432 }
433 TrialSet newTrialSet = cheapTorsionSet(allTors, testSetSize, "bkn");
434 Wn = newTrialSet.sumExtBolt();
435 if (Wn <= 0) {
436 report.append("WARNING: Numerical instability in CMBC.");
437 report.append(" Test set uExt values: ");
438 for (int i = 0; i < newTrialSet.uExt.length; i++) {
439 report.append(format("%5.2f, ", newTrialSet.uExt[i]));
440 }
441 report.append(" Discarding move.\n");
442 target.revertState(origState);
443 Wn = -1.0;
444 Wo = 1000;
445 logger.info(report.toString());
446 }
447
448
449 double rng = rand.nextDouble(Wn);
450 double running = 0.0;
451 for (int j = 0; j < newTrialSet.uExt.length; j++) {
452 double uExtBolt = FastMath.exp(-beta * newTrialSet.uExt[j]);
453 running += uExtBolt;
454 if (rng < running) {
455 proposedMove = newTrialSet.rotamer[j];
456 proposedChis = newTrialSet.theta;
457 double prob = uExtBolt / Wn * 100;
458 if (printTestSets) {
459 report.append(
460 format(" Chose %d %7.4f\t %4.1f%%\n", j + 1, newTrialSet.uExt[j], prob));
461 }
462 break;
463 }
464 }
465 report.append(format(" Wn Total: %g\n", Wn));
466
467
468
469 double ouDep = 0.0;
470 for (Torsion tors : allTors) {
471 ouDep += tors.energy(false);
472 }
473 double ouExt = totalEnergy() - ouDep;
474 double ouExtBolt = FastMath.exp(-beta * ouExt);
475 if (printTestSets) {
476 report.append(
477 format(" %3s %d: %9.5g %9.5g %9.5g\n", "bko", 0, ouDep, ouExt, ouExtBolt));
478 }
479 writeSnapshot("bko", true);
480 TrialSet oldTrialSet = cheapTorsionSet(allTors, testSetSize - 1, "bko");
481 Wo = ouExtBolt + oldTrialSet.sumExtBolt();
482
483 report.append(format(" Wo Total: %11.4g\n", Wo));
484 report.append(format(" Wn/Wo: %11.4g", Wn / Wo));
485
486 RotamerLibrary.applyRotamer(target, proposedMove);
487 proposedChis = RotamerLibrary.measureRotamer(target, false);
488 finalEnergy = totalEnergy();
489 if (finalEnergy < CATASTROPHE_THRESHOLD) {
490 report.append("\nWARNING: Multipole catastrophe in CMBC.\n");
491 report.append(" Discarding move.\n");
492 target.revertState(origState);
493 updateAll();
494 Wn = -1.0;
495 Wo = 1000;
496 logger.info(report.toString());
497 }
498
499 double criterion = Math.min(1, Wn / Wo);
500 rng = ThreadLocalRandom.current().nextDouble();
501 report.append(format(" rng: %5.2f\n", rng));
502 if (rng < criterion) {
503 accepted = true;
504 numAccepted++;
505 updateAll();
506 write();
507 report.append(format(" Accepted! %5d NewEnergy: %.4f Chi:", numAccepted, finalEnergy));
508 for (double proposedChi : proposedChis) {
509 report.append(format(" %7.2f", proposedChi));
510 }
511 report.append("\n");
512 } else {
513 accepted = false;
514 target.revertState(origState);
515 updateAll();
516 report.append(format(" Denied. %5d OldEnergy: %.4f Chi:", numAccepted, origEnergy));
517 for (double v : chi) {
518 report.append(format(" %7.2f", v));
519 }
520 report.append("\n");
521 }
522
523 endTime = System.nanoTime();
524 double took = (endTime - startTime) * NS_TO_MS;
525 if (logTimings) {
526 report.append(format(" Timing (ms): %.2f", took));
527 }
528 logger.info(report.toString());
529 }
530
531
532
533
534
535 private void engageExpensive() {
536 report.append(format(" Rosenbluth CBMC Move: %4d %s\n", moveNumber, target));
537
538 AminoAcid3 name = AminoAcidUtils.AminoAcid3.valueOf(target.getName());
539 double[] chi = RotamerLibrary.measureRotamer(target, false);
540 HashMap<Integer, BackBondedList> map = createBackBondedMap(name);
541
542
543
544
545
546 double[] wn = new double[chi.length];
547 double[] finalChi = new double[chi.length];
548 for (int i = 0; i < chi.length; i++) {
549 Torsion tors = map.get(i).torsion;
550
551 TrialSet trialSet = expensiveTorsionSet(tors, i, testSetSize, "bkn");
552 wn[i] = trialSet.sumExtBolt();
553 if (i == 0) {
554 Wn = wn[i];
555 } else {
556 Wn *= wn[i];
557 }
558 report.append(format(" wn,W running: %.2g %.2g", wn[i], Wn));
559 logger.info(report.toString());
560
561
562 double rng = rand.nextDouble(wn[i]);
563 double running = 0.0;
564 for (int j = 0; j < trialSet.uExt.length; j++) {
565 double uExtBolt = FastMath.exp(-beta * trialSet.uExt[j]);
566 running += uExtBolt;
567 if (rng < running) {
568 finalChi[i] = trialSet.theta[j];
569 double prob = uExtBolt / wn[i] * 100;
570 report.append(
571 format(" Chose %d %7.4f\t%7.4f\t %4.1f%%\n", j, trialSet.uExt[j], uExtBolt,
572 prob));
573 break;
574 }
575 }
576 }
577 report.append(format(" Wn Total: %g\n", Wn));
578 proposedMove = createRotamer(name, finalChi);
579
580
581
582
583 double[] wo = new double[chi.length];
584 for (int i = 0; i < chi.length; i++) {
585 Torsion tors = map.get(i).torsion;
586 double ouDep = tors.energy(false);
587 double ouExt = totalEnergy() - ouDep;
588 double ouExtBolt = FastMath.exp(-beta * ouExt);
589 TrialSet trialSet = expensiveTorsionSet(tors, i, testSetSize - 1, "bko");
590 wo[i] = ouExtBolt + trialSet.sumExtBolt();
591 if (i == 0) {
592 Wo = wo[i];
593 } else {
594 Wo *= wo[i];
595 }
596 }
597 report.append(format(" Wo Total: %g\n", Wo));
598 report.append(format(" Wn/Wo: %g\n", Wn / Wo));
599
600 target.revertState(origState);
601 updateAll();
602 if (verbose) {
603 logger.info(report.toString());
604 }
605 }
606
607
608
609
610
611 private void engageControlAll() {
612 report.append(format(" Rosenbluth Control Move: %4d %s\n", moveNumber, target));
613 double origEnergy = totalEnergy();
614 double[] origChi = RotamerLibrary.measureRotamer(target, false);
615 double[] newChi = new double[origChi.length];
616 arraycopy(origChi, 0, newChi, 0, origChi.length);
617 for (int i = 0; i < origChi.length; i++) {
618 if (doChi[i]) {
619 double theta = rand.nextDouble(360.0) - 180;
620 newChi[i] = theta;
621 }
622 }
623 proposedChis = newChi;
624 Rotamer newState = createRotamer(target, newChi);
625 RotamerLibrary.applyRotamer(target, newState);
626
627 finalEnergy = totalEnergy();
628 if (this.finalEnergy < CATASTROPHE_THRESHOLD) {
629 report.append("\nWARNING: Multipole catastrophe in CBMC.\n");
630 report.append(" Discarding move.\n");
631 target.revertState(origState);
632 updateAll();
633 Wn = -1.0;
634 Wo = 1000;
635 logger.info(report.toString());
636 }
637
638 double dU = finalEnergy - origEnergy;
639 double criterion = FastMath.exp(-beta * dU);
640 double rng = rand.nextDouble();
641 report.append(" move (thetas): ");
642 for (double value : newChi) {
643 report.append(format("%7.2f ", value));
644 }
645 report.append("\n");
646 report.append(format(" orig, final, dU: %.2g %.2g %.2g\n", origEnergy, finalEnergy, dU));
647 report.append(format(" crit, rng: %.2g %.2g\n", criterion, rng));
648 if (rng < criterion) {
649 accepted = true;
650 numAccepted++;
651 report.append(format(" Accepted! %5d NewEnergy: %.4f Chi:", numAccepted, finalEnergy));
652 for (double proposedChi : proposedChis) {
653 report.append(format(" %7.2f", proposedChi));
654 }
655 report.append("\n");
656 updateAll();
657 if (!noSnaps) {
658 PDBFilter writer = new PDBFilter(molecularAssembly.getFile(), molecularAssembly, null, null);
659 String filename = molecularAssembly.getFile().getAbsolutePath();
660 if (!filename.contains("_mc")) {
661 filename = FilenameUtils.removeExtension(filename) + "_mc.pdb";
662 }
663 File file = new File(filename);
664 writer.writeFile(file, false);
665 }
666 } else {
667 accepted = false;
668 report.append(format(" Denied. %5d NewEnergy: %.4f Chi:", numAccepted, origEnergy));
669 for (double v : origChi) {
670 report.append(format(" %7.2f", v));
671 }
672 report.append("\n");
673 target.revertState(origState);
674 }
675
676 updateAll();
677 endTime = System.nanoTime();
678 double took = (endTime - startTime) * NS_TO_MS;
679 if (logTimings) {
680 report.append(format(" Timing (ms): %.2f", took));
681 }
682 logger.info(report.toString());
683 }
684
685
686
687
688
689
690 boolean wasAccepted() {
691 return accepted;
692 }
693
694 private Rotamer createRotamer(AminoAcid3 name, double[] chi) {
695
696 double[] values = new double[chi.length * 2];
697 for (int k = 0; k < chi.length; k++) {
698 int kk = 2 * k;
699 values[kk] = chi[k];
700 values[kk + 1] = 0.0;
701 }
702 return new Rotamer(name, values);
703 }
704
705 private Rotamer createRotamer(Residue res, double[] chi) {
706 return createRotamer(AminoAcidUtils.AminoAcid3.valueOf(res.getName()), chi);
707 }
708
709 private void updateAll() {
710 updateBonds();
711 updateAngles();
712 updateTorsions();
713 }
714
715 private void updateBonds() {
716 for (Bond bond : target.getBondList()) {
717 bond.update();
718 }
719 }
720
721 private void updateAngles() {
722 for (Angle angle : target.getAngleList()) {
723 angle.update();
724 }
725 }
726
727 private void updateTorsions() {
728 for (Torsion torsion : target.getTorsionList()) {
729 torsion.update();
730 }
731 }
732
733 private double totalEnergy() {
734 double[] x = new double[forceFieldEnergy.getNumberOfVariables() * 3];
735 forceFieldEnergy.setEnergyTermState(Potential.STATE.BOTH);
736 forceFieldEnergy.getCoordinates(x);
737 return forceFieldEnergy.energy(false, verboseEnergies);
738 }
739
740
741
742
743
744
745 private HashMap<Integer, BackBondedList> createBackBondedMap(AminoAcid3 name) {
746 HashMap<Integer, BackBondedList> map = new HashMap<>();
747 List<Atom> chain = new ArrayList<>();
748 Atom N = (Atom) target.getAtomNode("N");
749 Atom CA = (Atom) target.getAtomNode("CA");
750 Atom CB = (Atom) target.getAtomNode("CB");
751 List<Atom> keyAtoms = new ArrayList<>();
752 switch (name) {
753 case VAL -> {
754 Atom CG1 = (Atom) target.getAtomNode("CG1");
755 keyAtoms.add(CG1);
756 keyAtoms.add(CB);
757 }
758 case LEU -> {
759 Atom CG = (Atom) target.getAtomNode("CG");
760 Atom CD1 = (Atom) target.getAtomNode("CD1");
761 keyAtoms.add(CG);
762 keyAtoms.add(CD1);
763 }
764 case ILE -> {
765 Atom CD1 = (Atom) target.getAtomNode("CD1");
766 Atom CG1 = (Atom) target.getAtomNode("CG1");
767 keyAtoms.add(CD1);
768 keyAtoms.add(CG1);
769 }
770 case SER -> {
771 Atom OG = (Atom) target.getAtomNode("OG");
772 Atom HG = (Atom) target.getAtomNode("HG");
773 keyAtoms.add(OG);
774 keyAtoms.add(HG);
775 }
776 case THR -> {
777 Atom OG1 = (Atom) target.getAtomNode("OG1");
778 Atom HG1 = (Atom) target.getAtomNode("HG1");
779 keyAtoms.add(OG1);
780 keyAtoms.add(HG1);
781 }
782 case CYX, CYD -> {
783 Atom SG = (Atom) target.getAtomNode("SG");
784 keyAtoms.add(SG);
785 }
786 case PHE -> {
787 Atom CD1 = (Atom) target.getAtomNode("CD1");
788 Atom CG = (Atom) target.getAtomNode("CG");
789 keyAtoms.add(CG);
790 }
791 case PRO -> {
792
793 Atom CD = (Atom) target.getAtomNode("CD");
794 Atom CG = (Atom) target.getAtomNode("CG");
795 keyAtoms.add(CG);
796 keyAtoms.add(CD);
797 }
798 case TYR -> {
799 Atom CD1 = (Atom) target.getAtomNode("CD1");
800 Atom CE2 = (Atom) target.getAtomNode("CE2");
801 Atom CG = (Atom) target.getAtomNode("CG");
802 Atom CZ = (Atom) target.getAtomNode("CZ");
803 Atom OH = (Atom) target.getAtomNode("OH");
804 Atom HH = (Atom) target.getAtomNode("HH");
805
806 Bond b1 = CG.getBond(CB);
807 Angle a1 = CG.getAngle(CB, CA);
808 Torsion t1 = CG.getTorsion(CB, CA, N);
809 Bond b2 = CD1.getBond(CG);
810 Angle a2 = CD1.getAngle(CG, CB);
811 Torsion t2 = CD1.getTorsion(CG, CB, CA);
812 Bond b3 = HH.getBond(OH);
813 Angle a3 = HH.getAngle(OH, CZ);
814 Torsion t3 = HH.getTorsion(OH, CZ, CE2);
815 BackBondedList bbl1 = new BackBondedList(b1, a1, t1);
816 BackBondedList bbl2 = new BackBondedList(b2, a2, t2);
817 BackBondedList bbl3 = new BackBondedList(b3, a3, t3);
818 map.put(0, bbl1);
819 map.put(1, bbl2);
820 map.put(2, bbl3);
821 return map;
822 }
823 case TYD, TRP -> {
824 Atom CD1 = (Atom) target.getAtomNode("CD1");
825 Atom CG = (Atom) target.getAtomNode("CG");
826 keyAtoms.add(CG);
827 keyAtoms.add(CD1);
828 }
829 case HIS, HID, HIE -> {
830 Atom CG = (Atom) target.getAtomNode("CG");
831 Atom ND1 = (Atom) target.getAtomNode("ND1");
832 keyAtoms.add(CG);
833 keyAtoms.add(ND1);
834 }
835 case ASP -> {
836 Atom CG = (Atom) target.getAtomNode("CG");
837 keyAtoms.add(CG);
838 }
839 case ASH, ASN -> {
840 Atom CG = (Atom) target.getAtomNode("CG");
841 Atom OD1 = (Atom) target.getAtomNode("OD1");
842 keyAtoms.add(CG);
843 keyAtoms.add(OD1);
844 }
845 case GLU, GLH, GLN -> {
846 Atom CG = (Atom) target.getAtomNode("CG");
847 Atom CD = (Atom) target.getAtomNode("CD");
848 Atom OE1 = (Atom) target.getAtomNode("OE1");
849 keyAtoms.add(CG);
850 keyAtoms.add(CD);
851 keyAtoms.add(OE1);
852 }
853 case MET -> {
854 Atom CG = (Atom) target.getAtomNode("CG");
855 Atom CE = (Atom) target.getAtomNode("CE");
856 Atom SD = (Atom) target.getAtomNode("SD");
857 keyAtoms.add(CG);
858 keyAtoms.add(SD);
859 keyAtoms.add(CE);
860 }
861 case LYS, LYD -> {
862 Atom CD = (Atom) target.getAtomNode("CD");
863 Atom CE = (Atom) target.getAtomNode("CE");
864 Atom CG = (Atom) target.getAtomNode("CG");
865 Atom NZ = (Atom) target.getAtomNode("NZ");
866 keyAtoms.add(CG);
867 keyAtoms.add(CD);
868 keyAtoms.add(CE);
869 keyAtoms.add(NZ);
870 }
871 case ARG -> {
872 Atom CD = (Atom) target.getAtomNode("CD");
873 Atom CG = (Atom) target.getAtomNode("CG");
874 Atom CZ = (Atom) target.getAtomNode("CZ");
875 Atom NE = (Atom) target.getAtomNode("NE");
876 keyAtoms.add(CG);
877 keyAtoms.add(CD);
878 keyAtoms.add(NE);
879 keyAtoms.add(CZ);
880 }
881 default -> logger.severe(format("CBMC called on unsupported residue: %s", name));
882 }
883
884 chain.add(N);
885 chain.add(CA);
886 chain.add(CB);
887 chain.addAll(keyAtoms);
888 for (int i = 3; i < chain.size(); i++) {
889 Atom key = chain.get(i);
890 Bond bond = key.getBond(chain.get(i - 1));
891 Angle angle = key.getAngle(chain.get(i - 1), chain.get(i - 2));
892 Torsion torsion = key.getTorsion(chain.get(i - 1), chain.get(i - 2), chain.get(i - 3));
893 BackBondedList bbl = new BackBondedList(bond, angle, torsion);
894 map.put(i - 3, bbl);
895
896 }
897 return map;
898 }
899
900 private void writeSnapshot(String suffix, boolean append) {
901 if (snapshotWriter != null && !noSnaps) {
902 snapshotWriter.write(suffix, append);
903 }
904 }
905
906
907
908
909
910
911
912 private void torsionSampler(List<Torsion> allTors) {
913 updateAll();
914 double[] origChi = measureLysine(target, false);
915 StringBuilder sb = new StringBuilder();
916 sb.append(format(" Torsion Sampling for %s\n", target.getName()));
917 sb.append(" origChi:");
918 for (double value : origChi) {
919 sb.append(format(" %6.2f", value));
920 }
921 sb.append("\n");
922 for (int k = 0; k < origChi.length; k++) {
923 Torsion tors = allTors.get(k);
924 AtomType type1 = tors.getAtomArray()[0].getAtomType();
925 AtomType type2 = tors.getAtomArray()[1].getAtomType();
926 AtomType type3 = tors.getAtomArray()[2].getAtomType();
927 AtomType type4 = tors.getAtomArray()[3].getAtomType();
928 sb.append(
929 format(" %d: \"(%3d %3d %3s) (%3d %3d %3s) (%3d %3d %3s) (%3d %3d %3s)\"\n", k,
930 type1.type, type1.atomClass, type1.name, type2.type, type2.atomClass, type2.name,
931 type3.type, type3.atomClass, type3.name, type4.type, type4.atomClass, type4.name));
932 }
933 logger.info(sb.toString());
934 sb = new StringBuilder();
935 sb.append(" Resi chi0 chi1 chi2 chi3 List<uTors> uTorsSum uTotal\n");
936 logger.info(sb.toString());
937 sb = new StringBuilder();
938 boolean doChi0 = false, doChi1 = false;
939 boolean doChi2 = true, doChi3 = true;
940 double increment = 1.0;
941 for (double chi0 = -180.0; chi0 < 180.0; chi0 += increment) {
942 for (double chi1 = -180.0; chi1 <= 180.0; chi1 += increment) {
943 for (double chi2 = -180.0; chi2 <= 180.0; chi2 += increment) {
944 for (double chi3 = -180.0; chi3 <= 180.0; chi3 += increment) {
945 sb.append(format(" %3s", target.getName()));
946 double[] newChi = new double[4];
947 if (doChi0) {
948 newChi[0] = chi0;
949 } else {
950 newChi[0] = origChi[0];
951 }
952 if (doChi1) {
953 newChi[1] = chi1;
954 } else {
955 newChi[1] = origChi[1];
956 }
957 if (doChi2) {
958 newChi[2] = chi2;
959 } else {
960 newChi[2] = origChi[2];
961 }
962 if (doChi3) {
963 newChi[3] = chi3;
964 } else {
965 newChi[3] = origChi[3];
966 }
967 Rotamer newState = createRotamer(target, newChi);
968 RotamerLibrary.applyRotamer(target, newState);
969 for (int wut = 0; wut < origChi.length; wut++) {
970 sb.append(format(" %3.0f", newChi[wut]));
971 }
972 writeSnapshot(format("%.0f", chi1), false);
973 double uTorsSum = 0.0;
974 for (Torsion allTor : allTors) {
975 double uTors = allTor.energy(false);
976 sb.append(format(" %5.2f", uTors));
977 uTorsSum += uTors;
978 }
979 sb.append(format(" %5.2f", uTorsSum));
980 double totalE = 1000.0;
981 try {
982 totalE = totalEnergy();
983 } catch (Exception ex) {
984
985 }
986 if (totalE > 1000.0) {
987 totalE = 1000.0;
988 }
989 sb.append(format(" %10.4f", totalE));
990 sb.append("\n");
991 logger.info(sb.toString());
992 sb = new StringBuilder();
993 if (!doChi3) {
994 break;
995 }
996 }
997 if (!doChi2) {
998 break;
999 }
1000 }
1001 if (!doChi1) {
1002 break;
1003 }
1004 }
1005 if (!doChi0) {
1006 break;
1007 }
1008 }
1009
1010 if (torsionSampling) {
1011 try {
1012 File output = new File("torsionSampler.log");
1013 BufferedWriter bw = new BufferedWriter(new FileWriter(output));
1014 bw.write(sb.toString());
1015 bw.close();
1016 } catch (IOException ex) {
1017
1018 }
1019 }
1020 System.exit(0);
1021 }
1022
1023
1024
1025
1026
1027
1028
1029
1030 private double[] measureLysine(Residue residue, boolean print) {
1031 if (!residue.getName().contains("LY") || (
1032 residue.getAminoAcid3() != AminoAcidUtils.AminoAcid3.LYS
1033 && residue.getAminoAcid3() != AminoAcidUtils.AminoAcid3.LYD)) {
1034 logger.severe("Yeah that ain't a lysine.");
1035 }
1036 double[] chi = new double[4];
1037 List<Torsion> torsions = residue.getTorsionList();
1038 Atom N = (Atom) residue.getAtomNode("N");
1039 Atom CA = (Atom) residue.getAtomNode("CA");
1040 Atom CB = (Atom) residue.getAtomNode("CB");
1041 Atom CD = (Atom) residue.getAtomNode("CD");
1042 Atom CE = (Atom) residue.getAtomNode("CE");
1043 Atom CG = (Atom) residue.getAtomNode("CG");
1044 Atom NZ = (Atom) residue.getAtomNode("NZ");
1045 logger.info(
1046 format(" Here's the atoms I found: \n%s\n%s\n%s\n%s\n%s\n%s\n%s", N, CA, CB, CD, CE, CG,
1047 NZ));
1048 logger.info(format(" Num torsions: %d", torsions.size()));
1049 int count = 0;
1050 for (Torsion torsion : torsions) {
1051 torsion.energy(false);
1052 logger.info(format(" Torsion numba %d: %s", count++, torsion));
1053 if (torsion.compare(N, CA, CB, CG)) {
1054 chi[0] = torsion.getValue();
1055 if (print) {
1056 logger.info(torsion.toString());
1057 }
1058 }
1059 if (torsion.compare(CA, CB, CG, CD)) {
1060 chi[1] = torsion.getValue();
1061 if (print) {
1062 logger.info(torsion.toString());
1063 }
1064 }
1065 if (torsion.compare(CB, CG, CD, CE)) {
1066 chi[2] = torsion.getValue();
1067 if (print) {
1068 logger.info(torsion.toString());
1069 }
1070 }
1071 if (torsion.compare(CG, CD, CE, NZ)) {
1072 chi[3] = torsion.getValue();
1073 if (print) {
1074 logger.info(torsion.toString());
1075 }
1076 }
1077 }
1078 return chi;
1079 }
1080
1081
1082 public enum MODE {
1083 EXPENSIVE, CHEAP, CTRL_ALL
1084 }
1085
1086
1087 private enum TORSION_OFFSET_AMPRO13 {
1088 LYS0(1.610000), LYD0(1.610000), LYS1(0.939033), LYD1(0.939033), LYS2(1.000000), LYD2(
1089 1.000000), LYS3(0.800000), LYD3(0.800000);
1090
1091 public final double offset;
1092
1093 TORSION_OFFSET_AMPRO13(double offset) {
1094 this.offset = offset;
1095 }
1096 }
1097
1098 private static class BackBondedList {
1099
1100 public final Bond bond;
1101 public final Angle angle;
1102 public final Torsion torsion;
1103
1104 public BackBondedList(Bond bond, Angle angle, Torsion tors) {
1105 this.bond = bond;
1106 this.angle = angle;
1107 this.torsion = tors;
1108 }
1109 }
1110
1111 private class TrialSet {
1112
1113 public final Rotamer[] rotamer;
1114 public final double[] uDep;
1115 public final double[] uExt;
1116 public final double[] theta;
1117
1118 public TrialSet(int setSize) {
1119 rotamer = new Rotamer[setSize];
1120 uDep = new double[setSize];
1121 uExt = new double[setSize];
1122 theta = new double[setSize];
1123 }
1124
1125 public double prodExtBolt() {
1126 double prod = 0.0;
1127 for (double v : uExt) {
1128 prod *= FastMath.exp(-beta * v);
1129 }
1130 return prod;
1131 }
1132
1133
1134
1135
1136
1137 public double sumExtBolt() {
1138 double sum = 0.0;
1139 for (double v : uExt) {
1140 sum += FastMath.exp(-beta * v);
1141 }
1142 return sum;
1143 }
1144 }
1145
1146 private class SnapshotWriter {
1147
1148 private final MolecularAssembly mola;
1149 private final PDBFilter filter;
1150 private final boolean interleaving;
1151
1152 private SnapshotWriter(MolecularAssembly mola, boolean interleaving) {
1153 this.mola = mola;
1154 this.interleaving = interleaving;
1155 this.filter = new PDBFilter(mola.getFile(), mola, null, null);
1156 this.filter.setLogWrites(false);
1157 }
1158
1159 private void write(String suffix, boolean append) {
1160 String filename =
1161 FilenameUtils.removeExtension(mola.getFile().toString()) + "." + suffix + "-" + moveNumber;
1162 if (interleaving) {
1163 filename = mola.getFile().getAbsolutePath();
1164 if (!filename.contains("dyn")) {
1165 filename = FilenameUtils.removeExtension(filename) + "_dyn.pdb";
1166 }
1167 }
1168 File file = new File(filename);
1169 filter.setLogWrites(false);
1170 filter.writeFile(file, append);
1171 }
1172 }
1173 }