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