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.potential.bonded;
39
40 import static ffx.potential.bonded.AminoAcidUtils.assignAminoAcidAtomTypes;
41 import static java.lang.String.format;
42 import static java.lang.System.arraycopy;
43
44 import ffx.potential.bonded.AminoAcidUtils.AminoAcid3;
45 import ffx.potential.bonded.BondedUtils.MissingAtomTypeException;
46 import ffx.potential.bonded.BondedUtils.MissingHeavyAtomException;
47 import ffx.potential.bonded.NucleicAcidUtils.NucleicAcid3;
48 import ffx.potential.parameters.ForceField;
49
50 import java.io.Serial;
51 import java.util.ArrayList;
52 import java.util.List;
53 import java.util.Objects;
54 import java.util.logging.Logger;
55 import org.jogamp.java3d.BranchGroup;
56 import org.jogamp.java3d.Material;
57 import org.jogamp.vecmath.Color3f;
58
59
60
61
62
63
64
65
66 public class MultiResidue extends Residue {
67
68 @Serial
69 private static final long serialVersionUID = 1L;
70
71 private static final Logger logger = Logger.getLogger(MultiResidue.class.getName());
72
73
74 ForceField forceField;
75
76 private Residue activeResidue;
77
78 private final List<Residue> consideredResidues;
79
80 private Rotamer[] rotamers;
81
82 private Rotamer originalRotamer;
83
84
85
86
87
88
89
90 public MultiResidue(Residue residue, ForceField forceField) {
91 super(residue.getResidueNumber() + "-" + "MultiResidue", residue.getResidueNumber(),
92 residue.residueType, residue.getChainID(), residue.getChainID().toString());
93 this.forceField = forceField;
94 activeResidue = residue;
95
96 consideredResidues = new ArrayList<>();
97 consideredResidues.add(residue);
98 removeLeaves();
99 }
100
101
102 @Override
103 public MSNode addMSNode(MSNode o) {
104 if (o instanceof Residue) {
105 add(o);
106 return o;
107 } else {
108 return null;
109 }
110 }
111
112
113
114
115
116
117 public void addResidue(Residue newResidue) {
118
119 consideredResidues.add(newResidue);
120
121
122 Residue prevResidue = activeResidue.getPreviousResidue();
123 Residue nextResidue = activeResidue.getNextResidue();
124 Residue prev2Residue = null;
125 if (prevResidue != null) {
126 prev2Residue = prevResidue.getPreviousResidue();
127 }
128 Residue next2Residue = null;
129 if (nextResidue != null) {
130 next2Residue = nextResidue.getNextResidue();
131 }
132
133 moveBackBoneAtoms(activeResidue, newResidue);
134
135
136 List<Joint> joints = activeResidue.getJoints();
137 for (Joint joint : joints) {
138 newResidue.addJoint(joint);
139 }
140
141
142 activeResidue.removeFromParent();
143 add(newResidue);
144 activeResidue = newResidue;
145
146
147 try {
148 assignAminoAcidAtomTypes(newResidue, prevResidue, nextResidue, forceField, null);
149 if (nextResidue != null) {
150 Atom C = (Atom) newResidue.getAtomNode("C");
151 Atom nextN = (Atom) nextResidue.getAtomNode("N");
152 for (Joint joint : joints) {
153 Bond bond = joint.getBondList().get(0);
154 if (bond.containsAtom(C) && bond.containsAtom(nextN)) {
155 C.setBond(bond);
156 }
157 }
158 }
159 } catch (MissingHeavyAtomException | MissingAtomTypeException exception) {
160 logger.severe(exception.toString());
161 }
162 newResidue.finalize(true, forceField);
163
164 updateGeometry(newResidue, prevResidue, nextResidue, prev2Residue, next2Residue);
165 }
166
167
168 @Override
169 public void assignBondedTerms(ForceField forceField) {
170 activeResidue.assignBondedTerms(forceField);
171 }
172
173
174 @Override
175 public Joint createJoint(Bond bond, MSGroup group1, MSGroup group2, ForceField forceField) {
176 return activeResidue.createJoint(bond, group1, group2, forceField);
177 }
178
179
180 @Override
181 public Joint createJoint(MSGroup group1, MSGroup group2, ForceField forceField) {
182 return activeResidue.createJoint(group1, group2, forceField);
183 }
184
185
186
187
188
189
190
191
192 @Override
193 public boolean equals(Object o) {
194 if (this == o) {
195 return true;
196 }
197 if (o == null || getClass() != o.getClass()) {
198 return false;
199 }
200 MultiResidue multiResidue = (MultiResidue) o;
201 return Objects.equals(getSegID(), multiResidue.getSegID())
202 && Objects.equals(getResidueNumber(), multiResidue.getResidueNumber())
203 && Objects.equals(getName(), multiResidue.getName());
204 }
205
206
207 @Override
208 public void finalize(boolean finalizeGeometry, ForceField forceField) {
209 activeResidue.finalize(finalizeGeometry, forceField);
210 }
211
212
213 @Override
214 public void findDangelingAtoms() {
215 activeResidue.findDangelingAtoms();
216 }
217
218
219
220
221
222
223 public Residue getActive() {
224 return activeResidue;
225 }
226
227
228
229
230
231
232 @Override
233 public AminoAcid3 getAminoAcid3() {
234 return activeResidue.getAminoAcid3();
235 }
236
237
238 @Override
239 public MSNode getAngles() {
240 return activeResidue.getAngles();
241 }
242
243
244 @Override
245 public void setAngles(MSNode t) {
246 activeResidue.setAngles(t);
247 }
248
249
250 @Override
251 public MSNode getAtomNode() {
252 return activeResidue.getAtomNode();
253 }
254
255
256 @Override
257 public void setAtomNode(MSNode t) {
258 activeResidue.setAtomNode(t);
259 }
260
261
262 @Override
263 public MSNode getAtomNode(int index) {
264 return activeResidue.getAtomNode(index);
265 }
266
267
268 @Override
269 public MSNode getAtomNode(String n) {
270 return activeResidue.getAtomNode(n);
271 }
272
273
274 @Override
275 public List<MSNode> getAtomNodeList() {
276 return activeResidue.getAtomNodeList();
277 }
278
279
280 @Override
281 public Bond getBond(String id) {
282 return activeResidue.getBond(id);
283 }
284
285
286 @Override
287 public Bond getBond(int index) {
288 return activeResidue.getBond(index);
289 }
290
291
292 @Override
293 public MSNode getBonds() {
294 return activeResidue.getBonds();
295 }
296
297
298 @Override
299 public void setBonds(MSNode t) {
300 activeResidue.setBonds(t);
301 }
302
303
304 @Override
305 public double[] getCenter() {
306 return activeResidue.getCenter();
307 }
308
309
310 @Override
311 public void setCenter(double[] d) {
312 activeResidue.setCenter(d);
313 }
314
315
316
317
318
319
320 public List<Residue> getConsideredResidues() {
321 return new ArrayList<>(consideredResidues);
322 }
323
324
325 @Override
326 public List<Atom> getDanglingAtoms() {
327 return activeResidue.getDanglingAtoms();
328 }
329
330
331 @Override
332 public void setDanglingAtoms(List<Atom> a) {
333 activeResidue.setDanglingAtoms(a);
334 }
335
336
337
338
339
340
341
342 public List<Residue> getInactive() {
343 List<Residue> ret = new ArrayList<>();
344 for (Residue res : consideredResidues) {
345 if (res != activeResidue) {
346 ret.add(res);
347 }
348 }
349 return ret;
350 }
351
352
353 @Override
354 public double[] getMultiScaleCenter(boolean w) {
355 return activeResidue.getMultiScaleCenter(w);
356 }
357
358
359 @Override
360 public String getName() {
361 if (activeResidue != null) {
362 return activeResidue.getName();
363 }
364 return super.getName();
365 }
366
367
368
369
370
371
372 public int getResidueCount() {
373 if (consideredResidues == null) {
374 return 0;
375 }
376 return consideredResidues.size();
377 }
378
379
380 @Override
381 public Rotamer[] getRotamers() {
382 return rotamers;
383 }
384
385
386 @Override
387 public Rotamer[] setRotamers(RotamerLibrary library) {
388 List<Rotamer[]> usual = new ArrayList<>();
389 int nRots = 0;
390
391 for (Residue residue : consideredResidues) {
392 Rotamer[] rotamers = library.getRotamers(residue);
393 if (rotamers != null && rotamers.length > 0) {
394 usual.add(rotamers);
395 nRots += rotamers.length;
396 }
397 }
398
399 if (library.getUsingOrigCoordsRotamer()) {
400 if (originalRotamer == null
401 && (residueType == Residue.ResidueType.AA || residueType == Residue.ResidueType.NA)) {
402 ResidueState origState = storeState();
403 double[] chi = RotamerLibrary.measureRotamer(activeResidue, false);
404 if (residueType == Residue.ResidueType.AA) {
405 AminoAcid3 aa3 = this.getAminoAcid3();
406 originalRotamer = new Rotamer(aa3, origState, chi);
407 } else if (residueType == Residue.ResidueType.NA) {
408 NucleicAcid3 na3 = this.getNucleicAcid3();
409 originalRotamer = new Rotamer(na3, origState, chi);
410 }
411 }
412 Rotamer[] allRotamers;
413 if (originalRotamer != null) {
414 allRotamers = new Rotamer[nRots + 1];
415 int index = 1;
416 allRotamers[0] = originalRotamer;
417 for (Rotamer[] rotamersI : usual) {
418 int nRotamers = rotamersI.length;
419 arraycopy(rotamersI, 0, allRotamers, index, nRotamers);
420 index += nRotamers;
421 }
422 } else {
423 allRotamers = addAllDefaultRotamers(usual, nRots);
424 }
425 rotamers = allRotamers;
426 } else {
427 rotamers = addAllDefaultRotamers(usual, nRots);
428 }
429 return rotamers;
430 }
431
432
433 @Override
434 public List<Atom> getSideChainAtoms() {
435 return activeResidue.getSideChainAtoms();
436 }
437
438
439 @Override
440 public MSNode getTermNode() {
441 return activeResidue.getTermNode();
442 }
443
444
445 @Override
446 public MSNode getTorsions() {
447 return activeResidue.getTorsions();
448 }
449
450
451 @Override
452 public void setTorsions(MSNode t) {
453 activeResidue.setTorsions(t);
454 }
455
456
457
458
459
460
461 @Override
462 public List<Atom> getVariableAtoms() {
463 return activeResidue.getAtomList();
464 }
465
466
467 @Override
468 public int hashCode() {
469 return Objects.hash(getSegID(), getResidueNumber(), getName());
470 }
471
472
473 @Override
474 public boolean isFinalized() {
475 return activeResidue.isFinalized();
476 }
477
478
479 @Override
480 public void setFinalized(boolean t) {
481 activeResidue.setFinalized(t);
482 }
483
484
485 @Override
486 public void reOrderAtoms() {
487 activeResidue.reOrderAtoms();
488 }
489
490
491
492
493
494
495
496 public boolean setActiveResidue(int i) {
497 if (consideredResidues == null) {
498 return false;
499 }
500 if (i >= consideredResidues.size()) {
501 return false;
502 }
503 return setActiveResidue(consideredResidues.get(i));
504 }
505
506
507
508
509
510
511
512 public boolean setActiveResidue(Residue residue) {
513 if (!consideredResidues.contains(residue)) {
514 return false;
515 }
516 if (residue == activeResidue) {
517 return true;
518 }
519 Residue prevResidue = activeResidue.getPreviousResidue();
520 Residue nextResidue = activeResidue.getNextResidue();
521 Residue prev2Residue = null;
522 if (prevResidue != null) {
523 prev2Residue = prevResidue.getPreviousResidue();
524 }
525 Residue next2Residue = null;
526 if (nextResidue != null) {
527 next2Residue = nextResidue.getNextResidue();
528 }
529
530 activeResidue.removeFromParent();
531
532
533 moveBackBoneAtoms(activeResidue, residue);
534 updateGeometry(residue, prevResidue, nextResidue, prev2Residue, next2Residue);
535 activeResidue = residue;
536
537 setName(toString());
538 add(activeResidue);
539
540 return true;
541 }
542
543
544
545
546
547
548
549
550 public boolean setActiveResidue(AminoAcid3 aa) {
551 Residue residue = null;
552 for (Residue res : consideredResidues) {
553 if (res.getAminoAcid3() == aa) {
554 residue = res;
555 break;
556 }
557 }
558 if (residue == null) {
559 return false;
560 }
561 return setActiveResidue(residue);
562 }
563
564
565 @Override
566 public void setColor(RendererCache.ColorModel newColorModel, Color3f color, Material mat) {
567 activeResidue.setColor(newColorModel, color, mat);
568 }
569
570
571 @Override
572 public void setOutOfPlaneBends(MSNode t) {
573 activeResidue.setOutOfPlaneBends(t);
574 }
575
576
577 @Override
578 public void setPiOrbitalTorsions(MSNode t) {
579 activeResidue.setPiOrbitalTorsions(t);
580 }
581
582
583 @Override
584 public void setStretchBends(MSNode t) {
585 activeResidue.setStretchBends(t);
586 }
587
588
589 @Override
590 public void setTerms(MSNode t) {
591 activeResidue.setTerms(t);
592 }
593
594
595 @Override
596 public void setTorsionTorsions(MSNode t) {
597 activeResidue.setTorsionTorsions(t);
598 }
599
600
601 @Override
602 public void setUreyBradleys(MSNode t) {
603 activeResidue.setUreyBradleys(t);
604 }
605
606
607 @Override
608 public void setView(RendererCache.ViewModel newViewModel, List<BranchGroup> newShapes) {
609 activeResidue.setView(newViewModel, newShapes);
610 }
611
612
613
614
615
616
617 @Override
618 public ResidueState storeState() {
619 return storeMultiResState();
620 }
621
622
623 @Override
624 public String toString() {
625 int resNum = consideredResidues.get(0).getResidueNumber();
626 StringBuilder sb = new StringBuilder();
627 sb.append(resNum).append("-");
628 for (Residue res : consideredResidues) {
629 int num = AminoAcidUtils.getAminoAcidNumber(res.getName());
630 String aa1 = AminoAcidUtils.AminoAcid1.values()[num].toString();
631 if (res == activeResidue) {
632 sb.append("[").append(aa1).append("]");
633 } else {
634 sb.append(aa1);
635 }
636 }
637 return sb.toString();
638 }
639
640
641 @Override
642 public void update() {
643 activeResidue.update();
644 }
645
646
647 @Override
648 public void updateAtoms() {
649 activeResidue.updateAtoms();
650 }
651
652
653 @Override
654 public void updateBonds() {
655 activeResidue.updateBonds();
656 }
657
658
659
660
661
662
663
664 private ResidueState storeMultiResState() {
665 return new ResidueState(this, activeResidue);
666 }
667
668
669
670
671
672
673
674
675 private Rotamer[] addAllDefaultRotamers(List<Rotamer[]> rotamerList, int nRots) {
676 Rotamer[] allRotamers = new Rotamer[nRots];
677 int index = 0;
678 for (Rotamer[] rotamers : rotamerList) {
679 int nRotamers = rotamers.length;
680 arraycopy(rotamers, 0, allRotamers, index, nRotamers);
681 index += nRotamers;
682 }
683 return allRotamers;
684 }
685
686 @Override
687 public void revertState(ResidueState state) {
688 Residue res = state.getStateResidue();
689 if (!setActiveResidue(res)) {
690 throw new IllegalArgumentException(
691 format(
692 " Could not revert " + "multi-residue %s to residue identity %s",
693 this, state.getStateResidue().toString()));
694 }
695 for (Atom atom : getAtomList()) {
696 atom.moveTo(state.getAtomCoords(atom));
697 }
698 }
699
700 private void moveBackBoneAtoms(Residue fromResidue, Residue toResidue) {
701 Residue prevRes = this.getPreviousResidue();
702 Residue nextRes = this.getNextResidue();
703
704
705
706
707 Atom CA = (Atom) fromResidue.getAtomNode("CA");
708 Atom C = (Atom) fromResidue.getAtomNode("C");
709 Atom HA = (Atom) fromResidue.getAtomNode("HA");
710 Atom N = (Atom) fromResidue.getAtomNode("N");
711 Atom O = (Atom) fromResidue.getAtomNode("O");
712
713 CA.removeFromParent();
714 HA.removeFromParent();
715 C.removeFromParent();
716 O.removeFromParent();
717 N.removeFromParent();
718
719
720 CA.clearGeometry();
721 HA.clearGeometry();
722 C.clearGeometry();
723 O.clearGeometry();
724 N.clearGeometry();
725
726
727 String resName = toResidue.getName();
728 CA.setResName(resName);
729 HA.setResName(resName);
730 C.setResName(resName);
731 O.setResName(resName);
732 N.setResName(resName);
733
734
735 toResidue.addMSNode(CA);
736 toResidue.addMSNode(HA);
737 toResidue.addMSNode(C);
738 toResidue.addMSNode(O);
739 toResidue.addMSNode(N);
740
741 if (prevRes == null) {
742 Atom H1 = (Atom) fromResidue.getAtomNode("H1");
743 Atom H2 = (Atom) fromResidue.getAtomNode("H2");
744 Atom H3 = (Atom) fromResidue.getAtomNode("H3");
745
746 H1.removeFromParent();
747 H2.removeFromParent();
748
749 H1.clearGeometry();
750 H2.clearGeometry();
751 H1.setResName(resName);
752 H2.setResName(resName);
753 toResidue.addMSNode(H1);
754 toResidue.addMSNode(H2);
755
756 if (H3 != null) {
757 H3.removeFromParent();
758 H3.clearGeometry();
759 H3.setResName(resName);
760 toResidue.addMSNode(H3);
761 }
762 } else {
763 Atom H = (Atom) fromResidue.getAtomNode("H");
764 H.removeFromParent();
765 H.clearGeometry();
766 H.setResName(resName);
767 toResidue.addMSNode(H);
768 }
769
770 if (nextRes == null) {
771 Atom OXT = (Atom) fromResidue.getAtomNode("OXT");
772 if (OXT != null) {
773 OXT.removeFromParent();
774 OXT.clearGeometry();
775 OXT.setResName(resName);
776 toResidue.addMSNode(OXT);
777 } else {
778 Atom OH = (Atom) fromResidue.getAtomNode("OH");
779 Atom HO = (Atom) fromResidue.getAtomNode("HO");
780 OH.removeFromParent();
781 HO.removeFromParent();
782 OH.clearGeometry();
783 HO.clearGeometry();
784 OH.setResName(resName);
785 HO.setResName(resName);
786 toResidue.addMSNode(OH);
787 toResidue.addMSNode(HO);
788 }
789 }
790 }
791
792
793
794
795
796
797
798
799
800
801 private void updateGeometry(
802 Residue residue, Residue prev, Residue next, Residue prev2, Residue next2) {
803 if (residue == null) {
804 return;
805 }
806
807
808 List<Atom> atoms = residue.getAtomList();
809 List<Bond> bonds = residue.getBondList();
810 List<Angle> angles = residue.getAngleList();
811 List<Torsion> torsions = residue.getTorsionList();
812 if (prev != null) {
813 atoms.addAll(prev.getAtomList());
814 bonds.addAll(prev.getBondList());
815 angles.addAll(prev.getAngleList());
816 torsions.addAll(prev.getTorsionList());
817 List<Joint> joints = prev.getJoints();
818 for (Joint joint : joints) {
819 bonds.addAll(joint.getBondList());
820 angles.addAll(joint.getAngleList());
821 torsions.addAll(joint.getTorsionList());
822 }
823 }
824 if (prev2 != null) {
825 bonds.addAll(prev2.getBondList());
826 angles.addAll(prev2.getAngleList());
827 torsions.addAll(prev2.getTorsionList());
828 }
829 if (next != null) {
830 atoms.addAll(next.getAtomList());
831 bonds.addAll(next.getBondList());
832 angles.addAll(next.getAngleList());
833 torsions.addAll(next.getTorsionList());
834 List<Joint> joints = next.getJoints();
835 for (Joint joint : joints) {
836 bonds.addAll(joint.getBondList());
837 angles.addAll(joint.getAngleList());
838 torsions.addAll(joint.getTorsionList());
839 }
840 }
841 if (next2 != null) {
842 bonds.addAll(next2.getBondList());
843 angles.addAll(next2.getAngleList());
844 torsions.addAll(next2.getTorsionList());
845 }
846
847 for (Atom atom : atoms) {
848 atom.clearGeometry();
849 }
850 for (Atom atom : atoms) {
851 for (Bond b : bonds) {
852 if (b.containsAtom(atom)) {
853 atom.setBond(b);
854 }
855 }
856 }
857 for (Atom atom : atoms) {
858 for (Angle a : angles) {
859 if (a.containsAtom(atom)) {
860 atom.setAngle(a);
861 }
862 }
863 }
864 for (Atom atom : atoms) {
865 for (Torsion t : torsions) {
866 if (t.containsAtom(atom)) {
867 atom.setTorsion(t);
868 }
869 }
870 }
871 }
872
873 }