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