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.numerics.math.DoubleMath.dihedralAngle;
41 import static ffx.numerics.math.ScalarMath.modToRange;
42 import static ffx.potential.bonded.AminoAcidUtils.AminoAcid3;
43 import static ffx.potential.bonded.AminoAcidUtils.getAminoAcid;
44 import static ffx.potential.bonded.BondedUtils.findAtomsOfElement;
45 import static ffx.potential.bonded.BondedUtils.findBondedAtoms;
46 import static ffx.potential.bonded.BondedUtils.findNitrogenAtom;
47 import static ffx.potential.bonded.BondedUtils.findNucleotideO4s;
48 import static ffx.potential.bonded.BondedUtils.getAlphaCarbon;
49 import static ffx.potential.bonded.BondedUtils.hasAttachedAtom;
50 import static ffx.potential.bonded.BondedUtils.sortAtomsByDistance;
51 import static ffx.potential.bonded.NucleicAcidUtils.NucleicAcid3;
52 import static java.lang.Integer.parseInt;
53 import static java.lang.Math.PI;
54 import static java.lang.String.format;
55
56 import ffx.potential.MolecularAssembly;
57 import ffx.potential.parsers.PDBFilter.PDBFileStandard;
58 import java.util.ArrayList;
59 import java.util.Comparator;
60 import java.util.HashMap;
61 import java.util.List;
62 import java.util.Map;
63 import java.util.Optional;
64 import java.util.logging.Level;
65 import java.util.logging.Logger;
66
67
68
69
70
71
72
73
74 public class NamingUtils {
75
76 private static final Logger logger = Logger.getLogger(NamingUtils.class.getName());
77
78
79
80
81
82
83
84
85
86 public static void checkHydrogenAtomNames(Residue residue, PDBFileStandard fileStandard) {
87 switch (fileStandard) {
88 case VERSION3_3:
89 return;
90 case VERSION3_2:
91 default:
92 break;
93 }
94
95 String residueType = residue.getName().toUpperCase();
96 List<Atom> resAtoms = residue.getAtomList();
97 for (Atom atom : resAtoms) {
98 if (atom == null) {
99 continue;
100 }
101 String atomName = atom.getName().toUpperCase();
102
103 if (atomName.contains("H")) {
104 try {
105 String firstChar = atomName.substring(0, 1);
106 parseInt(firstChar);
107 atomName = atomName.substring(1);
108 atomName = atomName.concat(firstChar);
109 atom.setName(atomName);
110 } catch (NumberFormatException e) {
111
112 }
113 }
114 }
115
116
117 List<Atom> betas;
118 List<Atom> gammas;
119 List<Atom> deltas;
120 List<Atom> epsilons;
121 List<Atom> zetas;
122 String atomName;
123 Atom OH;
124 Atom HH;
125 Atom HG;
126 Atom HD2;
127 switch (getAminoAcid(residueType)) {
128 case GLY:
129 List<Atom> alphas = new ArrayList<>();
130 for (Atom atom : resAtoms) {
131 if (atom.getName().toUpperCase().contains("HA")) {
132 alphas.add(atom);
133 }
134 }
135 renameGlycineAlphaHydrogen(residue, alphas);
136 break;
137 case ALA:
138
139 break;
140 case VAL:
141
142 break;
143 case LEU:
144 case SER:
145 case CYD:
146 case ASP:
147 betas = new ArrayList<>();
148 for (Atom atom : resAtoms) {
149 if (atom.getName().toUpperCase().contains("HB")) {
150 betas.add(atom);
151 }
152 }
153 renameBetaHydrogen(residue, betas, 23);
154 break;
155 case ILE:
156 List<Atom> ileAtoms = new ArrayList<>();
157 for (Atom atom : resAtoms) {
158 if (atom.getName().toUpperCase().contains("HG1")) {
159 ileAtoms.add(atom);
160 }
161 }
162 renameIsoleucineHydrogen(residue, ileAtoms);
163 break;
164 case THR:
165 Atom HG1 = (Atom) residue.getAtomNode("HG1");
166 if (HG1 == null) {
167 for (Atom atom : resAtoms) {
168 atomName = atom.getName().toUpperCase();
169
170
171 if (atomName.length() < 4 && atomName.contains("HG")) {
172 atom.setName("HG1");
173 break;
174 }
175 }
176 }
177 break;
178 case CYS:
179 betas = new ArrayList<>();
180 HG = (Atom) residue.getAtomNode("HG");
181 for (Atom atom : resAtoms) {
182 atomName = atom.getName().toUpperCase();
183 if (atomName.contains("HB")) {
184 betas.add(atom);
185 } else if (HG == null && atomName.contains("HG")) {
186 HG = atom;
187 HG.setName("HG");
188 }
189 }
190 renameBetaHydrogen(residue, betas, 23);
191 break;
192 case CYX:
193
194 break;
195 case PRO:
196 betas = new ArrayList<>();
197 gammas = new ArrayList<>();
198 deltas = new ArrayList<>();
199 for (Atom atom : resAtoms) {
200 atomName = atom.getName().toUpperCase();
201 if (atomName.contains("HB")) {
202 betas.add(atom);
203 } else if (atomName.contains("HG")) {
204 gammas.add(atom);
205 } else if (atomName.contains("HD")) {
206 deltas.add(atom);
207 }
208 }
209 renameBetaHydrogen(residue, betas, 23);
210 renameGammaHydrogen(residue, gammas, 23);
211 renameDeltaHydrogen(residue, deltas, 23);
212 break;
213 case PHE:
214 betas = new ArrayList<>();
215 deltas = new ArrayList<>();
216 epsilons = new ArrayList<>();
217 Atom HZ = (Atom) residue.getAtomNode("HZ");
218 for (Atom atom : resAtoms) {
219 atomName = atom.getName().toUpperCase();
220 if (atomName.contains("HB")) {
221 betas.add(atom);
222 } else if (atomName.contains("HD")) {
223 deltas.add(atom);
224 } else if (atomName.contains("HE")) {
225 epsilons.add(atom);
226 } else if (HZ == null && atomName.contains("HZ")) {
227 HZ = atom;
228 HZ.setName("HZ");
229 }
230 }
231 renameBetaHydrogen(residue, betas, 23);
232 renameDeltaHydrogen(residue, deltas, 12);
233 renameEpsilonHydrogen(residue, epsilons, 12);
234 break;
235 case TYR:
236 betas = new ArrayList<>();
237 deltas = new ArrayList<>();
238 epsilons = new ArrayList<>();
239 HH = (Atom) residue.getAtomNode("HH");
240 OH = (Atom) residue.getAtomNode("OH");
241 for (Atom atom : resAtoms) {
242 atomName = atom.getName().toUpperCase();
243 if (atomName.contains("HB")) {
244 betas.add(atom);
245 } else if (atomName.contains("HD")) {
246 deltas.add(atom);
247 } else if (atomName.contains("HE")) {
248 epsilons.add(atom);
249 } else if (HH == null && atomName.contains("HH")) {
250 HH = atom;
251 HH.setName("HH");
252 } else if (OH == null && atomName.contains("O") && atomName.contains("H")) {
253 OH = atom;
254 OH.setName("OH");
255 }
256 }
257 renameBetaHydrogen(residue, betas, 23);
258 renameDeltaHydrogen(residue, deltas, 12);
259 renameEpsilonHydrogen(residue, epsilons, 12);
260 break;
261 case TYD:
262 betas = new ArrayList<>();
263 deltas = new ArrayList<>();
264 epsilons = new ArrayList<>();
265 OH = (Atom) residue.getAtomNode("OH");
266 for (Atom atom : resAtoms) {
267 atomName = atom.getName().toUpperCase();
268 if (atomName.contains("HB")) {
269 betas.add(atom);
270 } else if (atomName.contains("HD")) {
271 deltas.add(atom);
272 } else if (atomName.contains("HE")) {
273 epsilons.add(atom);
274 } else if (OH == null && atomName.contains("O") && atomName.contains("H")) {
275 OH = atom;
276 OH.setName("OH");
277 }
278 }
279 renameBetaHydrogen(residue, betas, 23);
280 renameDeltaHydrogen(residue, deltas, 12);
281 renameEpsilonHydrogen(residue, epsilons, 12);
282 break;
283 case TRP:
284 betas = new ArrayList<>();
285 epsilons = new ArrayList<>();
286 zetas = new ArrayList<>();
287 Atom HD1 = (Atom) residue.getAtomNode("HD1");
288 Atom HH2 = (Atom) residue.getAtomNode("HH2");
289 for (Atom atom : resAtoms) {
290 atomName = atom.getName().toUpperCase();
291 if (atomName.contains("HB")) {
292 betas.add(atom);
293 } else if (atomName.contains("HE")) {
294 epsilons.add(atom);
295 } else if (atomName.contains("HZ")) {
296 zetas.add(atom);
297 } else if (HD1 == null && atomName.contains("HD")) {
298 HD1 = atom;
299 HD1.setName("HD1");
300 } else if (HH2 == null && atomName.contains("HH")) {
301 HH2 = atom;
302 HH2.setName("HH2");
303 }
304 }
305 renameBetaHydrogen(residue, betas, 23);
306 renameEpsilonHydrogen(residue, epsilons, 13);
307 renameZetaHydrogen(residue, zetas, 23);
308 break;
309 case HIS:
310 betas = new ArrayList<>();
311 deltas = new ArrayList<>();
312 epsilons = new ArrayList<>();
313 for (Atom atom : resAtoms) {
314 atomName = atom.getName().toUpperCase();
315 if (atomName.contains("HB")) {
316 betas.add(atom);
317 } else if (atomName.contains("HD")) {
318 deltas.add(atom);
319 } else if (atomName.contains("HE")) {
320 epsilons.add(atom);
321 }
322 }
323 renameBetaHydrogen(residue, betas, 23);
324 renameDeltaHydrogen(residue, deltas, 12);
325 renameEpsilonHydrogen(residue, epsilons, 12);
326 break;
327 case HID:
328 betas = new ArrayList<>();
329 deltas = new ArrayList<>();
330 Atom HE1 = (Atom) residue.getAtomNode("HE1");
331 for (Atom atom : resAtoms) {
332 atomName = atom.getName().toUpperCase();
333 if (atomName.contains("HB")) {
334 betas.add(atom);
335 } else if (atomName.contains("HD")) {
336 deltas.add(atom);
337 } else if (HE1 == null && atomName.contains("HE")) {
338 HE1 = atom;
339 HE1.setName("HE1");
340 }
341 }
342 renameBetaHydrogen(residue, betas, 23);
343 renameDeltaHydrogen(residue, deltas, 12);
344 break;
345 case HIE:
346 betas = new ArrayList<>();
347 epsilons = new ArrayList<>();
348 HD2 = (Atom) residue.getAtomNode("HD2");
349 for (Atom atom : resAtoms) {
350 atomName = atom.getName().toUpperCase();
351 if (atomName.contains("HB")) {
352 betas.add(atom);
353 } else if (atomName.contains("HE")) {
354 epsilons.add(atom);
355 } else if (HD2 == null && atomName.contains("HD")) {
356 HD2 = atom;
357 HD2.setName("HD2");
358 }
359 }
360 renameBetaHydrogen(residue, betas, 23);
361 renameEpsilonHydrogen(residue, epsilons, 12);
362 break;
363 case ASH:
364 betas = new ArrayList<>();
365 HD2 = (Atom) residue.getAtomNode("HD2");
366 for (Atom atom : resAtoms) {
367 atomName = atom.getName().toUpperCase();
368 if (atomName.contains("HB")) {
369 betas.add(atom);
370 } else if (HD2 == null && atomName.contains("HD")) {
371 HD2 = atom;
372 HD2.setName("HD2");
373 }
374 }
375 renameBetaHydrogen(residue, betas, 23);
376 break;
377 case ASD:
378 betas = new ArrayList<>();
379 deltas = new ArrayList<>();
380 for (Atom atom : resAtoms) {
381 atomName = atom.getName().toUpperCase();
382 if (atomName.contains("HB")) {
383 betas.add(atom);
384 } else if (atomName.contains("HD")) {
385 deltas.add(atom);
386 }
387 }
388 renameBetaHydrogen(residue, betas, 23);
389 renameDeltaHydrogen(residue, deltas, 12);
390 break;
391 case ASN:
392 betas = new ArrayList<>();
393 List<Atom> HD2s = new ArrayList<>();
394 for (Atom atom : resAtoms) {
395 atomName = atom.getName().toUpperCase();
396 if (atomName.contains("HB")) {
397 betas.add(atom);
398 } else if (atomName.contains("HD")) {
399 HD2s.add(atom);
400 }
401 }
402 renameBetaHydrogen(residue, betas, 23);
403 renameAsparagineHydrogen(residue, HD2s);
404 break;
405 case GLU:
406 case MET:
407 betas = new ArrayList<>();
408 gammas = new ArrayList<>();
409 for (Atom atom : resAtoms) {
410 atomName = atom.getName().toUpperCase();
411 if (atomName.contains("HB")) {
412 betas.add(atom);
413 } else if (atomName.contains("HG")) {
414 gammas.add(atom);
415 }
416 }
417 renameBetaHydrogen(residue, betas, 23);
418 renameGammaHydrogen(residue, gammas, 23);
419 break;
420 case GLH:
421 betas = new ArrayList<>();
422 gammas = new ArrayList<>();
423 Atom HE2 = (Atom) residue.getAtomNode("HE2");
424 for (Atom atom : resAtoms) {
425 atomName = atom.getName().toUpperCase();
426 if (atomName.contains("HB")) {
427 betas.add(atom);
428 } else if (atomName.contains("HG")) {
429 gammas.add(atom);
430 } else if (HE2 == null && atomName.contains("HE")) {
431 HE2 = atom;
432 HE2.setName("HE2");
433 }
434 }
435 renameBetaHydrogen(residue, betas, 23);
436 renameGammaHydrogen(residue, gammas, 23);
437 break;
438 case GLD:
439 betas = new ArrayList<>();
440 gammas = new ArrayList<>();
441 epsilons = new ArrayList<>();
442 for (Atom atom : resAtoms) {
443 atomName = atom.getName().toUpperCase();
444 if (atomName.contains("HB")) {
445 betas.add(atom);
446 } else if (atomName.contains("HG")) {
447 gammas.add(atom);
448 } else if (atomName.contains("HE")) {
449 epsilons.add(atom);
450 }
451 }
452 renameBetaHydrogen(residue, betas, 23);
453 renameGammaHydrogen(residue, gammas, 23);
454 renameEpsilonHydrogen(residue, epsilons, 12);
455 break;
456 case GLN:
457 betas = new ArrayList<>();
458 gammas = new ArrayList<>();
459 epsilons = new ArrayList<>();
460 for (Atom atom : resAtoms) {
461 atomName = atom.getName().toUpperCase();
462 if (atomName.contains("HB")) {
463 betas.add(atom);
464 } else if (atomName.contains("HG")) {
465 gammas.add(atom);
466 } else if (atomName.contains("HE")) {
467 epsilons.add(atom);
468 }
469 }
470 renameBetaHydrogen(residue, betas, 23);
471 renameGammaHydrogen(residue, gammas, 23);
472 renameGlutamineHydrogen(residue, epsilons);
473 break;
474
475 case LYS:
476 betas = new ArrayList<>();
477 gammas = new ArrayList<>();
478 deltas = new ArrayList<>();
479 epsilons = new ArrayList<>();
480
481 for (Atom atom : resAtoms) {
482 atomName = atom.getName().toUpperCase();
483 if (atomName.contains("HB")) {
484 betas.add(atom);
485 } else if (atomName.contains("HG")) {
486 gammas.add(atom);
487 } else if (atomName.contains("HD")) {
488 deltas.add(atom);
489 } else if (atomName.contains("HE")) {
490 epsilons.add(atom);
491 }
492 }
493 renameBetaHydrogen(residue, betas, 23);
494 renameGammaHydrogen(residue, gammas, 23);
495 renameDeltaHydrogen(residue, deltas, 23);
496 renameEpsilonHydrogen(residue, epsilons, 23);
497 break;
498 case LYD:
499 betas = new ArrayList<>();
500 gammas = new ArrayList<>();
501 deltas = new ArrayList<>();
502 epsilons = new ArrayList<>();
503 zetas = new ArrayList<>();
504 for (Atom atom : resAtoms) {
505 atomName = atom.getName().toUpperCase();
506 if (atomName.contains("HB")) {
507 betas.add(atom);
508 } else if (atomName.contains("HG")) {
509 gammas.add(atom);
510 } else if (atomName.contains("HD")) {
511 deltas.add(atom);
512 } else if (atomName.contains("HE")) {
513 epsilons.add(atom);
514 } else if (atomName.contains("HZ")) {
515 zetas.add(atom);
516 }
517 }
518 renameBetaHydrogen(residue, betas, 23);
519 renameGammaHydrogen(residue, gammas, 23);
520 renameDeltaHydrogen(residue, deltas, 23);
521 renameEpsilonHydrogen(residue, epsilons, 23);
522 renameZetaHydrogen(residue, zetas, 12);
523 break;
524 case ARG:
525 betas = new ArrayList<>();
526 gammas = new ArrayList<>();
527 deltas = new ArrayList<>();
528 Atom HE = (Atom) residue.getAtomNode("HE");
529 List<Atom> HHn = new ArrayList<>();
530 for (Atom atom : resAtoms) {
531 atomName = atom.getName().toUpperCase();
532 if (atomName.contains("HB")) {
533 betas.add(atom);
534 } else if (atomName.contains("HG")) {
535 gammas.add(atom);
536 } else if (atomName.contains("HD")) {
537 deltas.add(atom);
538 } else if (HE == null && atomName.contains("HE")) {
539 HE = atom;
540 HE.setName("HE");
541 } else if (atomName.contains("HH")) {
542 HHn.add(atom);
543 }
544 }
545 renameBetaHydrogen(residue, betas, 23);
546 renameGammaHydrogen(residue, gammas, 23);
547 renameDeltaHydrogen(residue, deltas, 23);
548 renameArginineHydrogen(residue, HHn);
549 break;
550 case ORN:
551 case AIB:
552 case PCA:
553 case UNK:
554 default:
555
556
557 break;
558 }
559 }
560
561
562
563
564
565
566
567 public static void nameAcetylCap(Residue residue, Atom aceC) {
568 logger.fine(format(" Probable ACE cap attached to residue %s; duplicate atom names may result.",
569 residue));
570 aceC.setName("C");
571 findBondedAtoms(aceC, 8).get(0).setName("O");
572 Atom CH3 = findBondedAtoms(aceC, 6).get(0);
573 CH3.setName("CH3");
574 List<Atom> ntermHs = findBondedAtoms(CH3, 1);
575 for (int i = 0; i < 3; i++) {
576 ntermHs.get(i).setName(format("H%d", (i + 1)));
577 }
578 }
579
580
581
582
583
584
585
586
587
588
589
590
591
592 public static Optional<Atom> renameAlkyl(Atom carbon, Atom priorAtom, int protonOffset,
593 char posName) {
594 carbon.setName(format("C%c", posName));
595 List<Atom> hydrogen = findBondedAtoms(carbon, 1);
596 int numH = hydrogen.size();
597 if (numH == 1) {
598 hydrogen.get(0).setName(format("H%c", posName));
599 } else {
600 for (int i = 0; i < numH; i++) {
601 hydrogen.get(i).setName(format("H%c%d", posName, i + protonOffset));
602 }
603 }
604
605 return carbon.getBonds().stream()
606 .map((Bond b) -> b.get1_2(carbon))
607 .filter((Atom a) -> a != priorAtom)
608 .filter((Atom a) -> !hydrogen.contains(a))
609 .findAny();
610 }
611
612
613
614
615
616
617 public static boolean renameAminoAcidToPDBStandard(Residue residue) {
618 if (residue.getChainID() == null) {
619 if (logger.isLoggable(Level.FINE)) {
620 logger.fine(" Setting Chain ID to Z for " + residue);
621 }
622 residue.setChainID('Z');
623 }
624 AminoAcid3 aa3 = residue.getAminoAcid3();
625 final Atom N = findNitrogenAtom(residue);
626 if (N != null) {
627
628 N.setName("N");
629
630
631 Atom CA = getAlphaCarbon(residue, N);
632 CA.setName("CA");
633
634
635 List<Atom> hydrogenForCA = findBondedAtoms(CA, 1);
636 switch (aa3) {
637 case NME -> {
638
639 findBondedAtoms(N, 1).get(0).setName("H");
640 CA.setName("CH3");
641 for (int i = 1; i <= 3; i++) {
642 hydrogenForCA.get(i - 1).setName(format("H%d", i));
643 }
644 return true;
645 }
646 case GLY -> {
647 hydrogenForCA.get(0).setName("HA2");
648 hydrogenForCA.get(1).setName("HA3");
649 }
650 default -> hydrogenForCA.get(0).setName("HA");
651 }
652
653
654 Atom C = null;
655
656 Atom CB = null;
657 for (Atom carbon : findBondedAtoms(CA, 6)) {
658
659 if (hasAttachedAtom(carbon, 8) && !hasAttachedAtom(carbon, 1)) {
660 C = carbon;
661 C.setName("C");
662 } else {
663 CB = carbon;
664 CB.setName("CB");
665 }
666 }
667 if (C == null) {
668 throw new IllegalArgumentException(
669 format(" The carbonyl carbon for residue %s could not be found.", residue));
670 }
671 if (CB == null && aa3 != AminoAcidUtils.AminoAcid3.GLY) {
672 throw new IllegalArgumentException(
673 format(" The beta carbon for residue %s could not be found.", residue));
674 }
675
676
677 List<Atom> cTerminalOxygen = findBondedAtoms(C, 8);
678 switch (cTerminalOxygen.size()) {
679 case 1 ->
680
681 cTerminalOxygen.get(0).setName("O");
682 case 2 -> {
683 Atom O = null;
684 for (Atom oxygen : cTerminalOxygen) {
685 if (oxygen.getBonds().size() == 2) {
686 O = oxygen;
687 O.setName("OH");
688 findBondedAtoms(O, 1).get(0).setName("HO");
689 }
690 }
691 if (O == null) {
692 cTerminalOxygen.get(0).setName("O");
693 cTerminalOxygen.get(1).setName("OXT");
694 }
695 }
696 }
697
698
699 List<Atom> amideProtons = findBondedAtoms(N, 1);
700 if (amideProtons.size() == 1) {
701 amideProtons.get(0).setName("H");
702 } else {
703 for (int i = 1; i <= amideProtons.size(); i++) {
704 amideProtons.get(i - 1).setName(format("H%d", i));
705 }
706 }
707
708
709 renameCommonAminoAcids(residue, aa3, CA, CB);
710 } else if (aa3 == AminoAcid3.ACE) {
711 Atom O = findAtomsOfElement(residue, 8).get(0);
712 O.setName("O");
713 Atom C = findBondedAtoms(O, 6).get(0);
714 C.setName("C");
715 Atom CH3 = findBondedAtoms(C, 6).get(0);
716 CH3.setName("CH3");
717 List<Atom> hydrogen = findBondedAtoms(CH3, 1);
718 for (int i = 1; i <= 3; i++) {
719 hydrogen.get(i - 1).setName(format("H%d", i));
720 }
721 } else {
722 logger.fine(format(" Mapping of nitrogen to residue (%s) failed. Trying to remap to molecule.", residue));
723 return false;
724 }
725 return true;
726 }
727
728
729
730
731
732
733
734 public static void renameArginineHydrogen(Residue residue, List<Atom> resAtoms) {
735 Atom HH11 = (Atom) residue.getAtomNode("HH11");
736 Atom HH12 = (Atom) residue.getAtomNode("HH12");
737 Atom HH21 = (Atom) residue.getAtomNode("HH21");
738 Atom HH22 = (Atom) residue.getAtomNode("HH22");
739 if (HH11 != null) {
740 resAtoms.remove(HH11);
741 }
742 if (HH12 != null) {
743 resAtoms.remove(HH12);
744 }
745 if (HH21 != null) {
746 resAtoms.remove(HH21);
747 }
748 if (HH22 != null) {
749 resAtoms.remove(HH22);
750 }
751 if (!resAtoms.isEmpty() && HH11 == null) {
752 resAtoms.get(0).setName("HH11");
753 resAtoms.remove(0);
754 }
755 if (!resAtoms.isEmpty() && HH12 == null) {
756 resAtoms.get(0).setName("HH12");
757 resAtoms.remove(0);
758 }
759 if (!resAtoms.isEmpty() && HH21 == null) {
760 resAtoms.get(0).setName("HH21");
761 resAtoms.remove(0);
762 }
763 if (!resAtoms.isEmpty() && HH22 == null) {
764 resAtoms.get(0).setName("HH22");
765 resAtoms.remove(0);
766 }
767 }
768
769
770
771
772
773
774
775 public static void renameAsparagineHydrogen(Residue residue, List<Atom> resAtoms) {
776 Atom HD21 = (Atom) residue.getAtomNode("HD21");
777 Atom HD22 = (Atom) residue.getAtomNode("HD22");
778 if (HD21 != null) {
779 resAtoms.remove(HD21);
780 }
781 if (HD22 != null) {
782 resAtoms.remove(HD22);
783 }
784 if (!resAtoms.isEmpty() && HD21 == null) {
785 resAtoms.get(0).setName("HD21");
786 resAtoms.remove(0);
787 }
788 if (!resAtoms.isEmpty() && HD22 == null) {
789 resAtoms.get(0).setName("HD21");
790 }
791 }
792
793
794
795
796
797
798
799
800
801
802 public static void renameAtomsToPDBStandard(MolecularAssembly molecularAssembly) {
803 Polymer[] polymers = molecularAssembly.getChains();
804 if (polymers != null) {
805 for (Polymer polymer : polymers) {
806 for (Residue residue : polymer.getResidues()) {
807 switch (residue.getResidueType()) {
808 case AA -> renameAminoAcidToPDBStandard(residue);
809 case NA -> renameNucleicAcidToPDBStandard(residue);
810 case UNK -> {
811
812 }
813 }
814 }
815 }
816 }
817 }
818
819
820
821
822
823
824
825
826 public static void renameBetaHydrogen(Residue residue, List<Atom> resAtoms, int indexes) {
827 Atom[] HBn = new Atom[3];
828 switch (indexes) {
829 case 12 -> {
830 HBn[0] = (Atom) residue.getAtomNode("HB1");
831 HBn[1] = (Atom) residue.getAtomNode("HB2");
832 }
833 case 13 -> {
834 HBn[0] = (Atom) residue.getAtomNode("HB1");
835 HBn[2] = (Atom) residue.getAtomNode("HB3");
836 }
837 case 23 -> {
838 HBn[1] = (Atom) residue.getAtomNode("HB2");
839 HBn[2] = (Atom) residue.getAtomNode("HB3");
840 }
841 default -> {
842 return;
843 }
844 }
845 for (Atom HBatom : HBn) {
846 resAtoms.remove(HBatom);
847 }
848 if (!resAtoms.isEmpty() && HBn[0] == null && (indexes == 12 || indexes == 13)) {
849 resAtoms.get(0).setName("HB1");
850 resAtoms.remove(0);
851 }
852 if (!resAtoms.isEmpty() && HBn[1] == null && (indexes == 12 || indexes == 23)) {
853 resAtoms.get(0).setName("HB2");
854 resAtoms.remove(0);
855 }
856 if (!resAtoms.isEmpty() && HBn[2] == null && (indexes == 13 || indexes == 23)) {
857 resAtoms.get(0).setName("HB3");
858 resAtoms.remove(0);
859 }
860 }
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877 public static Optional<Atom> renameBranchedAlkyl(Atom carbon, Atom priorAtom, int protonOffset,
878 int branchNum, char posName) {
879 carbon.setName(format("C%c%d", posName, branchNum));
880 List<Atom> hydrogen = findBondedAtoms(carbon, 1);
881 int numH = hydrogen.size();
882 if (numH == 1) {
883 hydrogen.get(0).setName(format("H%c%d", posName, branchNum));
884 } else {
885 for (int i = 0; i < numH; i++) {
886 hydrogen.get(i).setName(format("H%c%d%d", posName, branchNum, i + protonOffset));
887 }
888 }
889
890 return carbon.getBonds().stream()
891 .map((Bond b) -> b.get1_2(carbon))
892 .filter((Atom a) -> a != priorAtom)
893 .filter((Atom a) -> !hydrogen.contains(a))
894 .findAny();
895 }
896
897
898
899
900
901
902
903
904
905 public static void renameCommonAminoAcids(Residue residue, AminoAcid3 aa3, Atom CA, Atom CB) {
906 switch (aa3) {
907 case ALA: {
908 renameAlkyl(CB, CA, 1, 'B');
909 }
910 break;
911 case CYS:
912 case CYD: {
913 Atom SG = renameAlkyl(CB, CA, 2, 'B').get();
914 SG.setName("SG");
915 if (hasAttachedAtom(SG, 1)) {
916 assert aa3 == AminoAcidUtils.AminoAcid3.CYS;
917 findBondedAtoms(SG, 1).get(0).setName("HG");
918 } else if (hasAttachedAtom(SG, 16)) {
919 logger.finer(format(" SG atom %s likely part of a disulfide bond.", SG));
920 } else {
921 residue.setName("CYD");
922 }
923 }
924 break;
925 case ASP:
926 case ASH:
927 case ASD: {
928 Atom CG = renameAlkyl(CB, CA, 2, 'B').get();
929 CG.setName("CG");
930 List<Atom> ODs = findBondedAtoms(CG, 8);
931
932 int protonatedOD = -1;
933 for (int i = 0; i < 2; i++) {
934 if (hasAttachedAtom(ODs.get(i), 1)) {
935 protonatedOD = i;
936 break;
937 }
938 }
939
940
941 if (hasAttachedAtom(ODs.get(0), 1) && hasAttachedAtom(ODs.get(1), 1)) {
942 protonatedOD = 2;
943 }
944
945 switch (protonatedOD) {
946 case -1 -> {
947 ODs.get(0).setName("OD1");
948 ODs.get(1).setName("OD2");
949 }
950 case 0 -> {
951 if (aa3 != AminoAcid3.ASH) {
952 residue.setName("ASH");
953 }
954 ODs.get(0).setName("OD2");
955 findBondedAtoms(ODs.get(0), 1).get(0).setName("HD2");
956 ODs.get(1).setName("OD1");
957 }
958 case 1 -> {
959 if (aa3 != AminoAcid3.ASH) {
960 residue.setName("ASH");
961 }
962 ODs.get(1).setName("OD2");
963 findBondedAtoms(ODs.get(1), 1).get(0).setName("HD2");
964 ODs.get(0).setName("OD1");
965 }
966 case 2 -> {
967 if (aa3 != AminoAcid3.ASD) {
968 residue.setName("ASD");
969 }
970 ODs.get(0).setName("OD1");
971 findBondedAtoms(ODs.get(0), 1).get(0).setName("HD1");
972 ODs.get(1).setName("OD2");
973 findBondedAtoms(ODs.get(1), 1).get(0).setName("HD2");
974 }
975 }
976 }
977 break;
978 case GLU:
979 case GLH:
980 case GLD: {
981 Atom CG = renameAlkyl(CB, CA, 2, 'B').get();
982 Atom CD = renameAlkyl(CG, CB, 2, 'G').get();
983 CD.setName("CD");
984 List<Atom> OEs = findBondedAtoms(CD, 8);
985
986 int protonatedOE = -1;
987 for (int i = 0; i < 2; i++) {
988 if (hasAttachedAtom(OEs.get(i), 1)) {
989 protonatedOE = i;
990 break;
991 }
992 }
993
994
995 if (hasAttachedAtom(OEs.get(0), 1) && hasAttachedAtom(OEs.get(1), 1)) {
996 protonatedOE = 2;
997 }
998
999 switch (protonatedOE) {
1000 case -1 -> {
1001 OEs.get(0).setName("OE1");
1002 OEs.get(1).setName("OE2");
1003 }
1004 case 0 -> {
1005 if (aa3 != AminoAcid3.GLH) {
1006 residue.setName("GLH");
1007 }
1008 OEs.get(0).setName("OE2");
1009 findBondedAtoms(OEs.get(0), 1).get(0).setName("HE2");
1010 OEs.get(1).setName("OE1");
1011 }
1012 case 1 -> {
1013 if (aa3 != AminoAcid3.GLH) {
1014 residue.setName("GLH");
1015 }
1016 OEs.get(1).setName("OE2");
1017 findBondedAtoms(OEs.get(1), 1).get(0).setName("HE2");
1018 OEs.get(0).setName("OE1");
1019 }
1020 case 2 -> {
1021 if (aa3 != AminoAcid3.GLD) {
1022 residue.setName("GLD");
1023 }
1024 OEs.get(0).setName("OE1");
1025 findBondedAtoms(OEs.get(0), 1).get(0).setName("HE1");
1026 OEs.get(1).setName("OE2");
1027 findBondedAtoms(OEs.get(1), 1).get(0).setName("HE2");
1028 }
1029 }
1030 }
1031 break;
1032 case PHE: {
1033 Atom CG = renameAlkyl(CB, CA, 2, 'B').get();
1034 CG.setName("CG");
1035 List<Atom> CDs = findBondedAtoms(CG, CB, 6);
1036
1037 Atom CZ = null;
1038 for (int i = 1; i <= 2; i++) {
1039 Atom CD = CDs.get(i - 1);
1040 Atom CE = renameBranchedAlkyl(CD, CG, 0, i, 'D').get();
1041 CZ = renameBranchedAlkyl(CE, CD, 0, i, 'E').get();
1042 }
1043 CZ.setName("CZ");
1044 findBondedAtoms(CZ, 1).get(0).setName("HZ");
1045 }
1046 break;
1047 case GLY:
1048 break;
1049 case HIS:
1050 case HIE:
1051 case HID: {
1052 Atom CG = renameAlkyl(CB, CA, 2, 'B').get();
1053 CG.setName("CG");
1054
1055 Atom CD2 = findBondedAtoms(CG, 6).stream().filter((Atom a) -> a != CB).findAny().get();
1056 CD2.setName("CD2");
1057 findBondedAtoms(CD2, 1).get(0).setName("HD2");
1058
1059 Atom NE2 = findBondedAtoms(CD2, 7).get(0);
1060 NE2.setName("NE2");
1061 List<Atom> HE2 = findBondedAtoms(NE2, 1);
1062 boolean epsProtonated = (HE2 != null && !HE2.isEmpty());
1063 if (epsProtonated) {
1064 HE2.get(0).setName("HE2");
1065 }
1066
1067 Atom CE1 = findBondedAtoms(NE2, CD2, 6).get(0);
1068 CE1.setName("CE1");
1069 findBondedAtoms(CE1, 1).get(0).setName("HE1");
1070
1071 Atom ND1 = findBondedAtoms(CG, 7).get(0);
1072 ND1.setName("ND1");
1073 List<Atom> HD1 = findBondedAtoms(ND1, 1);
1074 boolean deltaProtonated = (HD1 != null && !HD1.isEmpty());
1075 if (deltaProtonated) {
1076 HD1.get(0).setName("HD1");
1077 }
1078
1079
1080 if (epsProtonated && deltaProtonated) {
1081 assert aa3 == AminoAcidUtils.AminoAcid3.HIS;
1082 } else if (epsProtonated) {
1083 residue.setName("HIE");
1084 } else if (deltaProtonated) {
1085 residue.setName("HID");
1086 } else {
1087 throw new IllegalArgumentException(
1088 format(" Histidine residue %s is doubly deprotonated!", residue));
1089 }
1090 }
1091 break;
1092 case ILE: {
1093 findBondedAtoms(CB, 1).get(0).setName("HB");
1094 List<Atom> CGs = findBondedAtoms(CB, CA, 6);
1095
1096 for (Atom CG : CGs) {
1097 List<Atom> HGs = findBondedAtoms(CG, 1);
1098 int numHGs = HGs.size();
1099 if (numHGs == 3) {
1100 renameBranchedAlkyl(CG, CB, 1, 2, 'G');
1101 } else if (numHGs == 2) {
1102 Atom CD1 = renameBranchedAlkyl(CG, CB, 2, 1, 'G').get();
1103 renameBranchedAlkyl(CD1, CG, 1, 1, 'D');
1104 } else {
1105 throw new IllegalArgumentException(
1106 format(
1107 " Isoleucine residue %s had %d gamma hydrogen, expecting 2-3!",
1108 residue, numHGs));
1109 }
1110 }
1111 }
1112 break;
1113 case LYS:
1114 case LYD: {
1115 Atom CG = renameAlkyl(CB, CA, 2, 'B').get();
1116 Atom CD = renameAlkyl(CG, CB, 2, 'G').get();
1117 Atom CE = renameAlkyl(CD, CG, 2, 'D').get();
1118 Atom NZ = renameAlkyl(CE, CD, 2, 'E').get();
1119
1120 renameAlkyl(NZ, CE, 1, 'Z');
1121 NZ.setName("NZ");
1122 int numH = findBondedAtoms(NZ, 1).size();
1123 switch (numH) {
1124 case 2 -> residue.setName("LYD");
1125 case 3 -> {
1126 assert aa3 == AminoAcid3.LYS;
1127 }
1128 default -> throw new IllegalArgumentException(
1129 format(" Lysine residue %s had %d amine protons, expecting 2-3!", residue, numH));
1130 }
1131 }
1132 break;
1133 case LEU: {
1134 Atom CG = renameAlkyl(CB, CA, 2, 'B').get();
1135 CG.setName("CG");
1136 findBondedAtoms(CG, 1).get(0).setName("HG");
1137 List<Atom> CDs = findBondedAtoms(CG, CB, 6);
1138
1139 for (int i = 0; i < 2; i++) {
1140 renameBranchedAlkyl(CDs.get(i), CG, 1, (i + 1), 'D');
1141 }
1142 }
1143 break;
1144 case MET: {
1145 Atom CG = renameAlkyl(CB, CA, 2, 'B').get();
1146 Atom SD = renameAlkyl(CG, CB, 2, 'G').get();
1147 Atom CE = renameAlkyl(SD, CG, 0, 'D').get();
1148
1149 SD.setName("SD");
1150 renameAlkyl(CE, SD, 1, 'E');
1151 }
1152 break;
1153 case ASN: {
1154 Atom CG = renameAlkyl(CB, CA, 2, 'B').get();
1155 CG.setName("CG");
1156 findBondedAtoms(CG, 8).get(0).setName("OD1");
1157 Atom ND2 = findBondedAtoms(CG, 7).get(0);
1158 renameBranchedAlkyl(ND2, CG, 1, 2, 'D');
1159
1160 ND2.setName("ND2");
1161 }
1162 break;
1163 case PRO: {
1164 Atom CG = renameAlkyl(CB, CA, 2, 'B').get();
1165 Atom CD = renameAlkyl(CG, CB, 2, 'G').get();
1166 Atom N = renameAlkyl(CD, CG, 2, 'D').get();
1167 assert N.getName().equals("N");
1168 }
1169 break;
1170 case GLN: {
1171 Atom CG = renameAlkyl(CB, CA, 2, 'B').get();
1172 Atom CD = renameAlkyl(CG, CB, 2, 'G').get();
1173 CD.setName("CD");
1174
1175 findBondedAtoms(CD, 8).get(0).setName("OE1");
1176 Atom NE2 = findBondedAtoms(CD, 7).get(0);
1177 renameBranchedAlkyl(NE2, CD, 1, 2, 'E');
1178
1179 NE2.setName("NE2");
1180 }
1181 break;
1182 case ARG: {
1183 Atom CG = renameAlkyl(CB, CA, 2, 'B').get();
1184 Atom CD = renameAlkyl(CG, CB, 2, 'G').get();
1185 Atom NE = renameAlkyl(CD, CG, 2, 'D').get();
1186 Atom CZ = renameAlkyl(NE, CD, 0, 'E').get();
1187 NE.setName("NE");
1188 CZ.setName("CZ");
1189
1190 List<Atom> NHs = findBondedAtoms(CZ, NE, 7);
1191 assert NHs.size() == 2;
1192 for (int i = 0; i < 2; i++) {
1193 Atom NHx = NHs.get(i);
1194 renameBranchedAlkyl(NHx, CZ, 1, (i + 1), 'H');
1195 NHx.setName(format("NH%d", (i + 1)));
1196 }
1197 }
1198 break;
1199 case SER: {
1200 Atom OG = renameAlkyl(CB, CA, 2, 'B').get();
1201 renameAlkyl(OG, CB, 0, 'G');
1202 OG.setName("OG");
1203 }
1204 break;
1205 case THR: {
1206 CB.setName("CB");
1207 findBondedAtoms(CB, 1).get(0).setName("HB");
1208
1209 Atom OG1 = findBondedAtoms(CB, 8).get(0);
1210 OG1.setName("OG1");
1211 findBondedAtoms(OG1, 1).get(0).setName("HG1");
1212
1213 Atom CG2 = findBondedAtoms(CB, CA, 6).get(0);
1214 renameBranchedAlkyl(CG2, CB, 1, 2, 'G');
1215 }
1216 break;
1217 case VAL: {
1218 CB.setName("CB");
1219 findBondedAtoms(CB, 1).get(0).setName("HB");
1220
1221 List<Atom> CGs = findBondedAtoms(CB, CA, 6);
1222
1223 assert CGs.size() == 2;
1224 for (int i = 0; i < 2; i++) {
1225 Atom CGx = CGs.get(i);
1226 renameBranchedAlkyl(CGx, CB, 1, (i + 1), 'G');
1227 }
1228 }
1229 break;
1230 case TRP: {
1231 Atom CG = renameAlkyl(CB, CA, 2, 'B').get();
1232 CG.setName("CG");
1233 List<Atom> CDs = findBondedAtoms(CG, CB, 6);
1234 Atom CD1 = null;
1235 Atom CD2 = null;
1236
1237 for (Atom CDx : CDs) {
1238 if (hasAttachedAtom(CDx, 1)) {
1239 CD1 = CDx;
1240 } else {
1241 CD2 = CDx;
1242 CD2.setName("CD2");
1243 }
1244 }
1245 Atom NE1 = renameBranchedAlkyl(CD1, CG, 0, 1, 'D').get();
1246 Atom CE2 = renameBranchedAlkyl(NE1, CD1, 0, 1, 'E').get();
1247 NE1.setName("NE1");
1248 CE2.setName("CE2");
1249
1250 Atom CZ2 = findBondedAtoms(CE2, CD2, 6).get(0);
1251 Atom CH2 = renameBranchedAlkyl(CZ2, CE2, 0, 2, 'Z').get();
1252 Atom CZ3 = renameBranchedAlkyl(CH2, CZ2, 0, 2, 'H').get();
1253 Atom CE3 = renameBranchedAlkyl(CZ3, CH2, 0, 3, 'Z').get();
1254 if (CD2 != renameBranchedAlkyl(CE3, CZ3, 0, 3, 'E').get()) {
1255 throw new IllegalArgumentException(
1256 format(" Error in cyclizing tryptophan %s!", residue));
1257 }
1258 }
1259 break;
1260 case TYR:
1261 case TYD: {
1262 Atom CG = renameAlkyl(CB, CA, 2, 'B').get();
1263 CG.setName("CG");
1264 List<Atom> CDs = findBondedAtoms(CG, CB, 6);
1265 Atom CZ = null;
1266
1267 assert CDs.size() == 2;
1268 for (int i = 1; i <= 2; i++) {
1269 Atom CDx = CDs.get(i - 1);
1270 Atom CEx = renameBranchedAlkyl(CDx, CG, 0, i, 'D').get();
1271 CZ = renameBranchedAlkyl(CEx, CDx, 0, i, 'E').get();
1272 }
1273
1274 CZ.setName("CZ");
1275 Atom OH = findBondedAtoms(CZ, 8).get(0);
1276 OH.setName("OH");
1277 if (hasAttachedAtom(OH, 1)) {
1278 assert aa3 == AminoAcidUtils.AminoAcid3.TYR;
1279 findBondedAtoms(OH, 1).get(0).setName("HH");
1280 } else {
1281 residue.setName("TYD");
1282 }
1283 }
1284 break;
1285 default:
1286 throw new IllegalArgumentException(
1287 (format(" Amino acid %s (%s) not recognized!", residue, aa3)));
1288 }
1289 }
1290
1291
1292
1293
1294
1295
1296
1297 public static void renameCommonNucleicAcid(Residue residue, NucleicAcid3 na3) {
1298 Optional<Atom> optO4s = findNucleotideO4s(residue);
1299 if (optO4s.isPresent()) {
1300
1301 Atom O4s = optO4s.get();
1302 O4s.setName("O4'");
1303
1304
1305 List<Atom> bondedC = findBondedAtoms(O4s, 6);
1306 Atom C4s = null;
1307 Atom C1s = null;
1308
1309 Atom N19 = null;
1310 Atom H1s = null;
1311 for (Atom c : bondedC) {
1312 if (hasAttachedAtom(c, 7)) {
1313 C1s = c;
1314 C1s.setName("C1'");
1315 H1s = findBondedAtoms(C1s, 1).get(0);
1316 H1s.setName("H1'");
1317 N19 = findBondedAtoms(C1s, 7).get(0);
1318 } else {
1319 C4s = c;
1320 C4s.setName("C4'");
1321 findBondedAtoms(C4s, 1).get(0).setName("H4'");
1322 }
1323 }
1324 assert C4s != null && C1s != null;
1325
1326 Atom C2s = findBondedAtoms(C1s, 6).get(0);
1327 C2s.setName("C2'");
1328
1329 bondedC = findBondedAtoms(C4s, 6);
1330 Atom C5s = null;
1331 Atom C3s;
1332 Atom O3s;
1333 for (Atom c : bondedC) {
1334 if (c.getBonds().stream().anyMatch(b -> b.get1_2(c) == C2s)) {
1335 C3s = c;
1336 C3s.setName("C3'");
1337 O3s = findBondedAtoms(C3s, 8).get(0);
1338 O3s.setName("O3'");
1339 findBondedAtoms(C3s, 1).get(0).setName("H3'");
1340 if (hasAttachedAtom(O3s, 1)) {
1341 findBondedAtoms(O3s, 1).get(0).setName("HO3'");
1342 }
1343 } else {
1344 C5s = c;
1345 C5s.setName("C5'");
1346 List<Atom> allH5List = findBondedAtoms(C5s, 1);
1347 Atom[] allH5s = allH5List.toArray(new Atom[0]);
1348 sortAtomsByDistance(O4s, allH5s);
1349 allH5s[0].setName("H5'");
1350 allH5s[1].setName("H5''");
1351 }
1352 }
1353
1354 if (hasAttachedAtom(C2s, 8)) {
1355 Atom O2s = findBondedAtoms(C2s, 8).get(0);
1356 O2s.setName("O2'");
1357 findBondedAtoms(O2s, 1).get(0).setName("HO2'");
1358 findBondedAtoms(C2s, 1).get(0).setName("H2'");
1359 } else {
1360 List<Atom> bothH2List = findBondedAtoms(C2s, 1);
1361 Atom[] bothH2 = bothH2List.toArray(new Atom[0]);
1362 sortAtomsByDistance(H1s, bothH2);
1363
1364 bothH2[0].setName("H2''");
1365 bothH2[1].setName("H2'");
1366 }
1367
1368
1369 Atom O5s = findBondedAtoms(C5s, 8).get(0);
1370 O5s.setName("O5'");
1371
1372 if (hasAttachedAtom(O5s, 1)) {
1373 findBondedAtoms(O5s, 1).get(0).setName("HO5'");
1374 } else if (hasAttachedAtom(O5s, 15)) {
1375 Atom P = findBondedAtoms(O5s, 15).get(0);
1376 P.setName("P");
1377 List<Atom> bondedO = findBondedAtoms(P, O5s, 8);
1378 List<Atom> thisResO = bondedO.stream().filter(o -> residue.getAtomList().contains(o))
1379 .toList();
1380 int nBonded = bondedO.size();
1381 int nRes = thisResO.size();
1382 if (nBonded == 0) {
1383
1384 } else if (nBonded == nRes) {
1385 Atom OP1 = bondedO.get(0);
1386 OP1.setName("OP1");
1387
1388 final double[] xyzC5s = C5s.getXYZ(new double[3]);
1389 final double[] xyzO5s = O5s.getXYZ(new double[3]);
1390 final double[] xyzP = P.getXYZ(new double[3]);
1391 final double[] xyzOP1 = OP1.getXYZ(new double[3]);
1392 double dihedral = dihedralAngle(xyzC5s, xyzO5s, xyzP, xyzOP1);
1393 double twoPiOver3 = 2.0 * PI / 3.0;
1394 double target = modToRange(dihedral + twoPiOver3, -PI, PI);
1395 List<Atom> otherO = bondedO.stream().filter(o -> o != OP1).sorted(
1396 Comparator.comparingDouble((Atom o) -> {
1397 double[] xyzO = o.getXYZ(new double[3]);
1398 double dihedO = dihedralAngle(xyzC5s, xyzO5s, xyzP, xyzO);
1399 double diff = dihedO - target;
1400 double twoPi = 2 * PI;
1401 diff = modToRange(diff, 0, twoPi);
1402 diff = diff < PI ? diff : twoPi - diff;
1403 return diff;
1404 })).toList();
1405 for (int i = 0; i < otherO.size(); i++) {
1406 otherO.get(i).setName(format("OP%d", i + 2));
1407 }
1408 } else {
1409 Atom nextO3s =
1410 bondedO.stream().filter(o -> !residue.getAtomList().contains(o)).findAny().get();
1411
1412
1413 final double[] xyzC5s = C5s.getXYZ(new double[3]);
1414 final double[] xyzO5s = O5s.getXYZ(new double[3]);
1415 final double[] xyzP = P.getXYZ(new double[3]);
1416 final double[] xyzNextO3s = nextO3s.getXYZ(new double[3]);
1417 double dihedral = dihedralAngle(xyzC5s, xyzO5s, xyzP, xyzNextO3s);
1418 double twoPiOver3 = 2.0 * PI / 3.0;
1419 double target = modToRange(dihedral + twoPiOver3, -PI, PI);
1420 List<Atom> otherO = bondedO.stream().filter(o -> o != nextO3s).sorted(
1421 Comparator.comparingDouble((Atom o) -> {
1422 double[] xyzO = o.getXYZ(new double[3]);
1423 double dihedO = dihedralAngle(xyzC5s, xyzO5s, xyzP, xyzO);
1424 double diff = dihedO - target;
1425 double twoPi = 2 * PI;
1426 diff = modToRange(diff, 0, twoPi);
1427 diff = diff < PI ? diff : twoPi - diff;
1428 return diff;
1429 })).toList();
1430 for (int i = 0; i < otherO.size(); i++) {
1431 otherO.get(i).setName(format("OP%d", i + 1));
1432 }
1433 }
1434
1435 for (Atom op : bondedO) {
1436 if (hasAttachedAtom(op, 1)) {
1437 findBondedAtoms(op, 1).get(0).setName("H" + op.getName());
1438 }
1439 }
1440 }
1441 renameCommonNucleobase(N19, C1s, na3);
1442 } else {
1443 logger.warning(" Could not find O4' for residue " + residue);
1444 }
1445 }
1446
1447
1448
1449
1450
1451
1452
1453
1454 public static void renameCommonNucleobase(Atom N19, Atom C1s, NucleicAcid3 na3) {
1455 switch (na3) {
1456 case ADE, DAD -> {
1457 Map<String, Atom> purineBase = renameCommonPurine(N19, C1s);
1458
1459 findBondedAtoms(purineBase.get("C2"), 1).get(0).setName("H2");
1460 Atom C6 = purineBase.get("C6");
1461 Atom N1 = purineBase.get("N1");
1462 Atom N6 = findBondedAtoms(C6, N1, 7).get(0);
1463 N6.setName("N6");
1464 List<Atom> allH6List = findBondedAtoms(N6, 1);
1465 Atom[] allH6 = sortAtomsByDistance(N1, allH6List);
1466 allH6[0].setName("H61");
1467 allH6[1].setName("H62");
1468 }
1469 case CYT, DCY -> {
1470 Map<String, Atom> pyrimidineBase = renameCommonPyrimidine(N19, C1s);
1471
1472 Atom C4 = pyrimidineBase.get("C4");
1473 Atom N3 = pyrimidineBase.get("N3");
1474 Atom N4 = findBondedAtoms(C4, N3, 7).get(0);
1475 N4.setName("N4");
1476 Atom[] allH4 = sortAtomsByDistance(N3, findBondedAtoms(N4, 1));
1477 allH4[0].setName("H41");
1478 allH4[1].setName("H42");
1479 }
1480 case GUA, DGU -> {
1481 Map<String, Atom> purineBase = renameCommonPurine(N19, C1s);
1482
1483 Atom N1 = purineBase.get("N1");
1484 Atom C2 = purineBase.get("C2");
1485 Atom C6 = purineBase.get("C6");
1486 findBondedAtoms(N1, 1).get(0).setName("H1");
1487 Atom N2 =
1488 findBondedAtoms(C2, N1, 7).stream()
1489 .filter(n -> hasAttachedAtom(n, 1))
1490 .findAny()
1491 .get();
1492 N2.setName("N2");
1493 Atom[] allH2 = sortAtomsByDistance(N1, findBondedAtoms(N2, 1));
1494 allH2[0].setName("H21");
1495 allH2[1].setName("H22");
1496 findBondedAtoms(C6, 8).get(0).setName("O6");
1497 }
1498 case URI -> {
1499 Map<String, Atom> pyrimidineBase = renameCommonPyrimidine(N19, C1s);
1500
1501 findBondedAtoms(pyrimidineBase.get("N3"), 1).get(0).setName("H3");
1502 findBondedAtoms(pyrimidineBase.get("C4"), 8).get(0).setName("O4");
1503 }
1504 case THY, DTY -> {
1505 Map<String, Atom> pyrimidineBase = renameCommonPyrimidine(N19, C1s);
1506
1507 findBondedAtoms(pyrimidineBase.get("N3"), 1).get(0).setName("H3");
1508 findBondedAtoms(pyrimidineBase.get("C4"), 8).get(0).setName("O4");
1509 Atom C5 = pyrimidineBase.get("C5");
1510 for (Atom c : findBondedAtoms(C5, 6)) {
1511 List<Atom> bondedH = findBondedAtoms(c, 1);
1512 if (bondedH != null && bondedH.size() == 3) {
1513 c.setName("C7");
1514 for (int i = 0; i < 3; i++) {
1515 bondedH.get(i).setName(format("H7%d", i + 1));
1516 }
1517 break;
1518 }
1519 }
1520 }
1521 }
1522 }
1523
1524
1525
1526
1527
1528
1529
1530
1531 public static Map<String, Atom> renameCommonPurine(Atom N9, Atom C1s) {
1532 Map<String, Atom> keyAtoms = new HashMap<>(10);
1533 N9.setName("N9");
1534 for (Atom c : findBondedAtoms(N9, C1s, 6)) {
1535 if (hasAttachedAtom(c, 1)) {
1536 Atom C8 = c;
1537 C8.setName("C8");
1538 findBondedAtoms(C8, 1).get(0).setName("H8");
1539 Atom N7 = findBondedAtoms(C8, N9, 7).get(0);
1540 N7.setName("N7");
1541 Atom C5 = findBondedAtoms(N7, C8, 6).get(0);
1542 C5.setName("C5");
1543 } else {
1544 Atom C4 = c;
1545 C4.setName("C4");
1546 Atom N3 = findBondedAtoms(C4, N9, 7).get(0);
1547 N3.setName("N3");
1548 Atom C2 = findBondedAtoms(N3, C4, 6).get(0);
1549 C2.setName("C2");
1550 keyAtoms.put("C2", C2);
1551 Atom N1 = findBondedAtoms(C2, N3, 7).get(0);
1552 N1.setName("N1");
1553 keyAtoms.put("N1", N1);
1554 Atom C6 = findBondedAtoms(N1, C2, 6).get(0);
1555 C6.setName("C6");
1556 keyAtoms.put("C6", C6);
1557 }
1558 }
1559
1560 return keyAtoms;
1561 }
1562
1563
1564
1565
1566
1567
1568
1569
1570 public static Map<String, Atom> renameCommonPyrimidine(Atom N1, Atom C1s) {
1571 Map<String, Atom> keyAtoms = new HashMap<>();
1572 N1.setName("N1");
1573 for (Atom c : findBondedAtoms(N1, C1s, 6)) {
1574 if (hasAttachedAtom(c, 8)) {
1575 Atom C2 = c;
1576 C2.setName("C2");
1577 findBondedAtoms(C2, 8).get(0).setName("O2");
1578 Atom N3 = findBondedAtoms(C2, N1, 7).get(0);
1579 N3.setName("N3");
1580 keyAtoms.put("N3", N3);
1581 Atom C4 = findBondedAtoms(N3, C2, 6).get(0);
1582 C4.setName("C4");
1583 keyAtoms.put("C4", C4);
1584 Atom C5 = findBondedAtoms(C4, 6).get(0);
1585 C5.setName("C5");
1586 keyAtoms.put("C5", C5);
1587 if (hasAttachedAtom(C5, 1)) {
1588 findBondedAtoms(C5, 1).get(0).setName("H5");
1589 }
1590 } else {
1591 Atom C6 = c;
1592 C6.setName("C6");
1593 findBondedAtoms(C6, 1).get(0).setName("H6");
1594 }
1595 }
1596
1597
1598 return keyAtoms;
1599 }
1600
1601
1602
1603
1604
1605
1606
1607
1608 public static void renameDeltaHydrogen(Residue residue, List<Atom> resAtoms, int indexes) {
1609 Atom[] HDn = new Atom[3];
1610 switch (indexes) {
1611 case 12 -> {
1612 HDn[0] = (Atom) residue.getAtomNode("HD1");
1613 HDn[1] = (Atom) residue.getAtomNode("HD2");
1614 }
1615 case 13 -> {
1616 HDn[0] = (Atom) residue.getAtomNode("HD1");
1617 HDn[2] = (Atom) residue.getAtomNode("HD3");
1618 }
1619 case 23 -> {
1620 HDn[1] = (Atom) residue.getAtomNode("HD2");
1621 HDn[2] = (Atom) residue.getAtomNode("HD3");
1622 }
1623 default -> {
1624 return;
1625 }
1626 }
1627 for (Atom HDatom : HDn) {
1628 resAtoms.remove(HDatom);
1629 }
1630 if (!resAtoms.isEmpty() && HDn[0] == null && (indexes == 12 || indexes == 13)) {
1631 resAtoms.get(0).setName("HD1");
1632 resAtoms.remove(0);
1633 }
1634 if (!resAtoms.isEmpty() && HDn[1] == null && (indexes == 12 || indexes == 23)) {
1635 resAtoms.get(0).setName("HD2");
1636 resAtoms.remove(0);
1637 }
1638 if (!resAtoms.isEmpty() && HDn[2] == null && (indexes == 13 || indexes == 23)) {
1639 resAtoms.get(0).setName("HD3");
1640 resAtoms.remove(0);
1641 }
1642 }
1643
1644
1645
1646
1647
1648
1649
1650
1651 public static void renameEpsilonHydrogen(Residue residue, List<Atom> resAtoms, int indexes) {
1652 Atom[] HEn = new Atom[3];
1653 switch (indexes) {
1654 case 12 -> {
1655 HEn[0] = (Atom) residue.getAtomNode("HE1");
1656 HEn[1] = (Atom) residue.getAtomNode("HE2");
1657 }
1658 case 13 -> {
1659 HEn[0] = (Atom) residue.getAtomNode("HE1");
1660 HEn[2] = (Atom) residue.getAtomNode("HE3");
1661 }
1662 case 23 -> {
1663 HEn[1] = (Atom) residue.getAtomNode("HE2");
1664 HEn[2] = (Atom) residue.getAtomNode("HE3");
1665 }
1666 default -> {
1667 return;
1668 }
1669 }
1670 for (Atom HEatom : HEn) {
1671 resAtoms.remove(HEatom);
1672 }
1673 if (!resAtoms.isEmpty() && HEn[0] == null && (indexes == 12 || indexes == 13)) {
1674 resAtoms.get(0).setName("HE1");
1675 resAtoms.remove(0);
1676 }
1677 if (!resAtoms.isEmpty() && HEn[1] == null && (indexes == 12 || indexes == 23)) {
1678 resAtoms.get(0).setName("HE2");
1679 resAtoms.remove(0);
1680 }
1681 if (!resAtoms.isEmpty() && HEn[2] == null && (indexes == 13 || indexes == 23)) {
1682 resAtoms.get(0).setName("HE3");
1683 resAtoms.remove(0);
1684 }
1685 }
1686
1687
1688
1689
1690
1691
1692
1693
1694 public static void renameGammaHydrogen(Residue residue, List<Atom> resAtoms, int indexes) {
1695 Atom[] HGn = new Atom[3];
1696 switch (indexes) {
1697 case 12 -> {
1698 HGn[0] = (Atom) residue.getAtomNode("HG1");
1699 HGn[1] = (Atom) residue.getAtomNode("HG2");
1700 }
1701 case 13 -> {
1702 HGn[0] = (Atom) residue.getAtomNode("HG1");
1703 HGn[2] = (Atom) residue.getAtomNode("HG3");
1704 }
1705 case 23 -> {
1706 HGn[1] = (Atom) residue.getAtomNode("HG2");
1707 HGn[2] = (Atom) residue.getAtomNode("HG3");
1708 }
1709 default -> {
1710 return;
1711 }
1712 }
1713 for (Atom HGatom : HGn) {
1714 resAtoms.remove(HGatom);
1715 }
1716 if (!resAtoms.isEmpty() && HGn[0] == null && (indexes == 12 || indexes == 13)) {
1717 resAtoms.get(0).setName("HG1");
1718 resAtoms.remove(0);
1719 }
1720 if (!resAtoms.isEmpty() && HGn[1] == null && (indexes == 12 || indexes == 23)) {
1721 resAtoms.get(0).setName("HG2");
1722 resAtoms.remove(0);
1723 }
1724 if (!resAtoms.isEmpty() && HGn[2] == null && (indexes == 13 || indexes == 23)) {
1725 resAtoms.get(0).setName("HG3");
1726 resAtoms.remove(0);
1727 }
1728 }
1729
1730
1731
1732
1733
1734
1735
1736 public static void renameGlutamineHydrogen(Residue residue, List<Atom> resAtoms) {
1737 Atom HE21 = (Atom) residue.getAtomNode("HE21");
1738 Atom HE22 = (Atom) residue.getAtomNode("HE22");
1739 if (HE21 != null) {
1740 resAtoms.remove(HE21);
1741 }
1742 if (HE22 != null) {
1743 resAtoms.remove(HE22);
1744 }
1745 if (!resAtoms.isEmpty() && HE21 == null) {
1746 resAtoms.get(0).setName("HE21");
1747 resAtoms.remove(0);
1748 }
1749 if (!resAtoms.isEmpty() && HE22 == null) {
1750 resAtoms.get(0).setName("HE21");
1751 }
1752 }
1753
1754
1755
1756
1757
1758
1759
1760 public static void renameGlycineAlphaHydrogen(Residue residue, List<Atom> resAtoms) {
1761 Atom HA2 = (Atom) residue.getAtomNode("HA2");
1762 Atom HA3 = (Atom) residue.getAtomNode("HA3");
1763 if (HA2 != null) {
1764 resAtoms.remove(HA2);
1765 }
1766 if (HA3 != null) {
1767 resAtoms.remove(HA3);
1768 }
1769 if (HA2 == null && !resAtoms.isEmpty()) {
1770 resAtoms.get(0).setName("HA2");
1771 resAtoms.remove(0);
1772 }
1773 if (HA3 == null && !resAtoms.isEmpty()) {
1774 resAtoms.get(0).setName("HA3");
1775 }
1776 }
1777
1778
1779
1780
1781
1782
1783
1784 public static void renameIsoleucineHydrogen(Residue residue, List<Atom> resAtoms) {
1785 Atom HG12 = (Atom) residue.getAtomNode("HG12");
1786 Atom HG13 = (Atom) residue.getAtomNode("HG13");
1787 if (HG12 != null) {
1788 resAtoms.remove(HG12);
1789 }
1790 if (HG13 != null) {
1791 resAtoms.remove(HG13);
1792 }
1793 if (HG12 == null && !resAtoms.isEmpty()) {
1794 resAtoms.get(0).setName("HG12");
1795 resAtoms.remove(0);
1796 }
1797 if (HG13 == null && !resAtoms.isEmpty()) {
1798 resAtoms.get(0).setName("HG13");
1799 }
1800 }
1801
1802
1803
1804
1805
1806
1807 public static void renameNTerminusHydrogen(Residue residue) {
1808 Atom[] h = new Atom[3];
1809 h[0] = (Atom) residue.getAtomNode("H1");
1810 h[1] = (Atom) residue.getAtomNode("H2");
1811 h[2] = (Atom) residue.getAtomNode("H3");
1812 int numAtoms = 0;
1813 for (Atom atom : h) {
1814 numAtoms += (atom == null ? 0 : 1);
1815 }
1816 if (numAtoms == 3) {
1817 return;
1818 }
1819 List<Atom> resAtoms = residue.getAtomList();
1820 for (Atom resAtom : resAtoms) {
1821
1822 boolean doContinue = false;
1823 for (Atom hAtom : h) {
1824 if (resAtom.equals(hAtom)) {
1825 doContinue = true;
1826 break;
1827 }
1828 }
1829 if (doContinue) {
1830 continue;
1831 }
1832
1833
1834 String atomName = resAtom.getName().toUpperCase();
1835 if (atomName.equals("H") || atomName.matches("H[1-3]") || atomName.matches("[1-3]H")) {
1836 ++numAtoms;
1837 for (int i = 0; i < h.length; i++) {
1838 if (h[i] == null) {
1839 resAtom.setName("H" + (i + 1));
1840 h[i] = resAtom;
1841 break;
1842 }
1843 }
1844 if (numAtoms == 3) {
1845 return;
1846 }
1847 }
1848 }
1849 }
1850
1851
1852
1853
1854
1855
1856 public static void renameNucleicAcidToPDBStandard(Residue residue) {
1857 if (residue.getChainID() == null) {
1858 logger.info(" Setting Chain ID to Z for " + residue);
1859 residue.setChainID('Z');
1860 }
1861 assert residue.getResidueType() == Residue.ResidueType.NA;
1862 NucleicAcid3 na3 = residue.getNucleicAcid3(true);
1863 residue.setName(na3.toString());
1864 switch (na3) {
1865 case ADE, DAD, CYT, DCY, GUA, DGU, THY, DTY, URI -> renameCommonNucleicAcid(residue, na3);
1866 default -> logger.info(" Could not rename atoms for nonstandard nucleic acid " + na3);
1867 }
1868 }
1869
1870
1871
1872
1873
1874
1875
1876
1877 public static void renameZetaHydrogen(Residue residue, List<Atom> resAtoms, int indexes) {
1878 Atom[] HZn = new Atom[3];
1879 switch (indexes) {
1880 case 12 -> {
1881 HZn[0] = (Atom) residue.getAtomNode("HZ1");
1882 HZn[1] = (Atom) residue.getAtomNode("HZ2");
1883 }
1884 case 13 -> {
1885 HZn[0] = (Atom) residue.getAtomNode("HZ1");
1886 HZn[2] = (Atom) residue.getAtomNode("HZ3");
1887 }
1888 case 23 -> {
1889 HZn[1] = (Atom) residue.getAtomNode("HZ2");
1890 HZn[2] = (Atom) residue.getAtomNode("HZ3");
1891 }
1892 default -> {
1893 return;
1894 }
1895 }
1896 for (Atom HZatom : HZn) {
1897 resAtoms.remove(HZatom);
1898 }
1899 if (!resAtoms.isEmpty() && HZn[0] == null && (indexes == 12 || indexes == 13)) {
1900 resAtoms.get(0).setName("HZ1");
1901 resAtoms.remove(0);
1902 }
1903 if (!resAtoms.isEmpty() && HZn[1] == null && (indexes == 12 || indexes == 23)) {
1904 resAtoms.get(0).setName("HZ2");
1905 resAtoms.remove(0);
1906 }
1907 if (!resAtoms.isEmpty() && HZn[2] == null && (indexes == 13 || indexes == 23)) {
1908 resAtoms.get(0).setName("HZ3");
1909 resAtoms.remove(0);
1910 }
1911 }
1912
1913
1914 public enum HetAtoms {
1915 BR,
1916 CA,
1917 CA2,
1918 CL,
1919 K,
1920 MG,
1921 MG2,
1922 NA,
1923 HOH,
1924 H2O,
1925 WAT,
1926 ZN,
1927 ZN2;
1928
1929
1930
1931
1932
1933
1934
1935 public static HetAtoms parse(String str) {
1936 String hName = str.toUpperCase().replaceFirst("[0-9+\\-]+$", "");
1937 return valueOf(hName);
1938 }
1939 }
1940 }