Coverage Report

Created: 2026-10-17 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openbabel/src/residue.cpp
Line
Count
Source
1
/**********************************************************************
2
residue.cpp - Handle macromolecule residues.
3
4
Copyright (C) 2001, 2002  OpenEye Scientific Software, Inc.
5
Some portions Copyright (C) 2001-2006 by Geoffrey R. Hutchison
6
7
This file is part of the Open Babel project.
8
For more information, see <http://openbabel.org/>
9
10
This program is free software; you can redistribute it and/or modify
11
it under the terms of the GNU General Public License as published by
12
the Free Software Foundation version 2 of the License.
13
14
This program is distributed in the hope that it will be useful,
15
but WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
GNU General Public License for more details.
18
***********************************************************************/
19
20
/**********************************************************************
21
Global arrays Residue, ElemDesc and function GetResidueNumber were
22
obtained in part or whole from RasMol2 by Roger Sayle.
23
***********************************************************************/
24
25
///////////////////////////////////////////////////////////////////////////////
26
// File Includes
27
///////////////////////////////////////////////////////////////////////////////
28
29
#include <cstring>
30
31
#include <openbabel/babelconfig.h>
32
33
#include <openbabel/residue.h>
34
#include <openbabel/atom.h>
35
#include <openbabel/oberror.h>
36
#include <openbabel/bitvec.h>
37
#include <openbabel/bond.h>
38
#include <openbabel/elements.h>
39
#include <cstring>
40
#include <cstdlib>
41
42
using namespace std;
43
44
namespace OpenBabel
45
{
46
   ////////////////////////////////////////////////////////////////////////////////
47
  // Global Variables
48
  ////////////////////////////////////////////////////////////////////////////////
49
50
  char Residue[MAXRES][4] = {
51
    /*===============*/
52
    /*  Amino Acids  */
53
    /*===============*/
54
55
    /* Ordered by Cumulative Frequency in Brookhaven *
56
     * Protein Databank, December 1991               */
57
58
    "ALA", /* 8.4% */     "GLY", /* 8.3% */
59
    "LEU", /* 8.0% */     "SER", /* 7.5% */
60
    "VAL", /* 7.1% */     "THR", /* 6.4% */
61
    "LYS", /* 5.8% */     "ASP", /* 5.5% */
62
    "ILE", /* 5.2% */     "ASN", /* 4.9% */
63
    "GLU", /* 4.9% */     "PRO", /* 4.4% */
64
    "ARG", /* 3.8% */     "PHE", /* 3.7% */
65
    "GLN", /* 3.5% */     "TYR", /* 3.5% */
66
    "HIS", /* 2.3% */     "CYS", /* 2.0% */
67
    "MET", /* 1.8% */     "TRP", /* 1.4% */
68
69
    "ASX", "GLX", "PCA", "HYP",
70
71
    /*===================*/
72
    /*  DNA Nucleotides  */
73
    /*===================*/
74
    "  A", "  C", "  G", "  T",
75
76
    /*===================*/
77
    /*  RNA Nucleotides  */
78
    /*===================*/
79
    "  U", " +U", "  I", "1MA",
80
    "5MC", "OMC", "1MG", "2MG",
81
    "M2G", "7MG", "OMG", " YG",
82
    "H2U", "5MU", "PSU",
83
84
    /*=================*/
85
    /*  Miscellaneous  */
86
    /*=================*/
87
    "UNK", "ACE", "FOR", "HOH",
88
    "DOD", "SO4", "PO4", "NAD",
89
    "COA", "NAP", "NDP"
90
  };
91
92
  /* Avoid SGI Compiler Warnings! */
93
    char ElemDesc[MAXELEM][4] = {
94
    { ' ', 'N', ' ', ' ' },  /* 0*/
95
    { ' ', 'C', 'A', ' ' },  /* 1*/
96
    { ' ', 'C', ' ', ' ' },  /* 2*/
97
    { ' ', 'O', ' ', ' ' },  /* 3*/   /* 0-3   Amino Acid Backbone    */
98
    { ' ', 'C', '\'', ' ' }, /* 4*/
99
    { ' ', 'O', 'T', ' ' },  /* 5*/
100
    { ' ', 'S', ' ', ' ' },  /* 6*/
101
    { ' ', 'P', ' ', ' ' },  /* 7*/   /* 4-7   Shapely Amino Backbone */
102
    { ' ', 'O', '1', 'P' },  /* 8*/
103
    { ' ', 'O', '2', 'P' },  /* 9*/
104
    { ' ', 'O', '5', '*' },  /*10*/
105
    { ' ', 'C', '5', '*' },  /*11*/
106
    { ' ', 'C', '4', '*' },  /*12*/
107
    { ' ', 'O', '4', '*' },  /*13*/
108
    { ' ', 'C', '3', '*' },  /*14*/
109
    { ' ', 'O', '3', '*' },  /*15*/
110
    { ' ', 'C', '2', '*' },  /*16*/
111
    { ' ', 'O', '2', '*' },  /*17*/
112
    { ' ', 'C', '1', '*' },  /*18*/   /* 7-18  Nucleic Acid Backbone  */
113
    { ' ', 'C', 'A', '2' },  /*19*/   /* 19    Shapely Special        */
114
    { ' ', 'S', 'G', ' ' },  /*20*/   /* 20    Cysteine Sulphur       */
115
    { ' ', 'N', '1', ' ' },  /*21*/
116
    { ' ', 'N', '2', ' ' },  /*22*/
117
    { ' ', 'N', '3', ' ' },  /*23*/
118
    { ' ', 'N', '4', ' ' },  /*24*/
119
    { ' ', 'N', '6', ' ' },  /*25*/
120
    { ' ', 'O', '2', ' ' },  /*26*/
121
    { ' ', 'O', '4', ' ' },  /*27*/
122
    { ' ', 'O', '6', ' ' }   /*28*/   /* 21-28 Nucleic Acid H-Bonding */
123
  };
124
125
 /** \class OBResidue residue.h <openbabel/residue.h>
126
      \brief Residue information
127
128
      The residue information is drawn from PDB or MOL2 files (or similar), which
129
      track biomolecule information,
130
      and are stored in the OBResidue class. OBResidues are stored inside the
131
      OBAtom class and OBMol classes.
132
      The residue information for an atom can be requested in
133
      the following way:
134
      \code
135
      OBAtom *atom;
136
      OBResidue *r;
137
      atom = mol.GetAtom(1);
138
      r = atom->GetResidue();
139
      \endcode
140
      The residue information for a molecule can be manipulated too:
141
      \code
142
      cout << "This molecule has " << mol.NumResidues() << " residues." << endl;
143
      OBResidue *r;
144
      r = mol.GetResidue(1);
145
      \endcode
146
  */
147
148
  ///////////////////////////////////////////////////////////////////////////////
149
  // Residue Functions
150
  ///////////////////////////////////////////////////////////////////////////////
151
152
  static unsigned int GetAtomIDNumber(const char *atomid)
153
0
  {
154
0
    if (atomid != nullptr)
155
0
      {
156
0
        int ch1 = toupper(atomid[0]);
157
0
        int ch2 = toupper(atomid[1]);
158
0
        int ch3 = toupper(atomid[2]);
159
0
        int ch4 = toupper(atomid[3]);
160
161
0
        if (ch1 == ' ')
162
0
          {
163
0
            switch(ch2)
164
0
              {
165
0
              case 'C':
166
167
0
                switch(ch3)
168
0
                  {
169
0
                  case 'A':
170
171
0
                    if (ch4 == ' ')
172
0
                      return 1;
173
0
                    else if (ch4 == '2')
174
0
                      return 19;
175
176
0
                    break;
177
178
0
                  case ' ':
179
0
                    if (ch4 == ' ')
180
0
                      return 2;
181
0
                    break;
182
183
0
                  case '\'':
184
0
                    if (ch4 == ' ')
185
0
                      return 4;
186
0
                    break;
187
188
0
                  case '1':
189
0
                    if (ch4 == '*')
190
0
                      return 18;
191
0
                    break;
192
193
0
                  case '2':
194
0
                    if (ch4 == '*')
195
0
                      return 16;
196
0
                    break;
197
198
0
                  case '3':
199
0
                    if (ch4 == '*')
200
0
                      return 14;
201
0
                    break;
202
203
0
                  case '4':
204
0
                    if (ch4 == '*')
205
0
                      return 12;
206
0
                    break;
207
208
0
                  case '5':
209
0
                    if (ch4 == '*')
210
0
                      return 11;
211
0
                    break;
212
213
0
                  }
214
215
0
                break;
216
217
0
              case 'N':
218
219
0
                if (ch4 == ' ')
220
0
                  {
221
0
                    switch (ch3)
222
0
                      {
223
0
                      case ' ':
224
0
                        return 0;
225
0
                      case '1':
226
0
                        return 21;
227
0
                      case '2':
228
0
                        return 22;
229
0
                      case '3':
230
0
                        return 23;
231
0
                      case '4':
232
0
                        return 24;
233
0
                      case '6':
234
0
                        return 25;
235
0
                      }
236
0
                  }
237
238
0
                break;
239
240
0
              case 'O':
241
242
0
                switch(ch3)
243
0
                  {
244
0
                  case ' ':
245
246
0
                    if (ch4 == ' ')
247
0
                      return 3;
248
249
0
                    break;
250
251
0
                  case 'T':
252
253
0
                    if (ch4 == ' ')
254
0
                      return 5;
255
256
0
                    break;
257
258
0
                  case '1':
259
260
0
                    if (ch4 == 'P')
261
0
                      return 8;
262
263
0
                    break;
264
265
0
                  case '2':
266
267
0
                    if (ch4 == 'P')
268
0
                      return 9;
269
0
                    else if (ch4 == '*')
270
0
                      return 17;
271
0
                    else if (ch4 == ' ')
272
0
                      return 26;
273
274
0
                    break;
275
276
0
                  case '3':
277
278
0
                    if (ch4 == '*')
279
0
                      return 15;
280
281
0
                    break;
282
283
0
                  case '4':
284
285
0
                    if (ch4 == '*')
286
0
                      return 13;
287
0
                    else if (ch4 == ' ')
288
0
                      return 27;
289
290
0
                    break;
291
292
0
                  case '5':
293
294
0
                    if (ch4 == '*')
295
0
                      return 10;
296
297
0
                    break;
298
299
0
                  case '6':
300
301
0
                    if (ch4 == ' ')
302
0
                      return 28;
303
304
0
                    break;
305
0
                  }
306
307
0
                break;
308
309
0
              case 'P':
310
311
0
                if ((ch3 == ' ') && (ch4 == ' '))
312
0
                  return 7;
313
314
0
                break;
315
316
0
              case 'S':
317
318
0
                if (ch4 == ' ')
319
0
                  {
320
0
                    if (ch3 == ' ')
321
0
                      return 6;
322
0
                    else if (ch3 == 'G')
323
0
                      return 20;
324
0
                  }
325
326
0
                break;
327
0
              }
328
0
          }
329
330
0
        return MAXELEM;
331
0
      }
332
333
0
    else
334
0
      {
335
0
        obErrorLog.ThrowError(__FUNCTION__, "NULL Atom IDs specified", obWarning);
336
0
        return MAXELEM;
337
0
      }
338
0
  }
339
340
  static unsigned int GetResidueNumber(const char *res)
341
2
  {
342
2
    if (res != nullptr && strlen(res) > 2)
343
2
      {
344
2
        int ch1 = toupper(res[0]);
345
2
        int ch2 = toupper(res[1]);
346
2
        int ch3 = toupper(res[2]);
347
348
2
        switch( ch1 )
349
2
          {
350
0
          case(' '):
351
352
0
            if( ch2 == ' ' )
353
0
              {
354
0
                switch( ch3 )
355
0
                  {
356
0
                  case('A'):  return( 24 );
357
0
                  case('C'):  return( 25 );
358
0
                  case('G'):  return( 26 );
359
0
                  case('T'):  return( 27 );
360
0
                  case('U'):  return( 28 );
361
0
                  case('I'):  return( 30 );
362
0
                  }
363
0
              }
364
0
            else if( ch2 == '+' )
365
0
              {
366
0
                if( ch3 == 'U' )
367
0
                  return( 29 );
368
0
              }
369
0
            else if( ch2 == 'Y' )
370
0
              {
371
0
                if( ch3 == 'G' )
372
0
                  return( 39 );
373
0
              }
374
375
0
            break;
376
377
0
          case('0'):
378
379
0
            if( ch2 == 'M' )
380
0
              {
381
0
                if( ch3 == 'C' )
382
0
                  return( 33 );
383
0
                else if( ch3 == 'G' )
384
0
                  return( 38 );
385
0
              }
386
387
0
            break;
388
389
0
          case('1'):
390
391
0
            if( ch2 == 'M' )
392
0
              {
393
0
                if( ch3 == 'A' )
394
0
                  return( 31 );
395
0
                else if( ch3 == 'G' )
396
0
                  return( 34 );
397
0
              }
398
399
0
            break;
400
401
0
          case('2'):
402
403
0
            if( ch2 == 'M' )
404
0
              if( ch3 == 'G' )
405
0
                return( 35 );
406
407
0
            break;
408
409
0
          case('5'):
410
411
0
            if( ch2 == 'M' )
412
0
              {
413
0
                if( ch3 == 'C' )
414
0
                  return( 32 );
415
0
                else if( ch3 == 'U' )
416
0
                  return( 41 );
417
0
              }
418
419
0
            break;
420
421
0
          case('7'):
422
423
0
            if( ch2 == 'M' )
424
0
              if( ch3 == 'G' )
425
0
                return( 37 );
426
427
0
            break;
428
429
0
          case('A'):
430
431
0
            if( ch2 == 'L' )
432
0
              {
433
0
                if( ch3 == 'A' )
434
0
                  return(  0 );
435
0
              }
436
0
            else if( ch2 == 'S' )
437
0
              {
438
0
                if( ch3 == 'P' )
439
0
                  return(  7 );
440
0
                else if( ch3 == 'N' )
441
0
                  return(  9 );
442
0
                else if( ch3 == 'X' )
443
0
                  return( 20 );
444
0
              }
445
0
            else if( ch2 == 'R' )
446
0
              {
447
0
                if( ch3 == 'G' )
448
0
                  return( 12 );
449
0
              }
450
0
            else if( ch2 == 'C' )
451
0
              {
452
0
                if( ch3 == 'E' )
453
0
                  return( 44 );
454
0
              }
455
0
            else if( ch2 == 'D' )
456
0
              {
457
0
                if( ch3 == 'E' )
458
0
                  return( 24 );    /* "ADE" -> "  A" */
459
0
              }
460
461
0
            break;
462
463
0
          case('C'):
464
465
0
            if( ch2 == 'Y' )
466
0
              {
467
0
                if( ch3 == 'S' )
468
0
                  return( 17 );
469
0
                else if( ch3 == 'H' )
470
0
                  return( 17 );    /* "CYH" -> "CYS" */
471
0
                else if( ch3 == 'T' )
472
0
                  return( 25 );    /* "CYT" -> "  C" */
473
0
              }
474
0
            else if( ch2 == 'O' )
475
0
              {
476
0
                if( ch3 == 'A' )
477
0
                  return( 51 );
478
0
              }
479
0
            else if( ch2 == 'P' )
480
0
              {
481
0
                if( ch3 == 'R' )
482
0
                  return( 11 );    /* "CPR" -> "PRO" */
483
0
              }
484
0
            else if( ch2 == 'S' )
485
0
              {
486
0
                if( ch3 == 'H' )
487
0
                  return( 17 );    /* "CSH" -> "CYS" */
488
0
                else if( ch3 == 'M' )
489
0
                  return( 17 );    /* "CSM" -> "CYS" */
490
0
              }
491
492
0
            break;
493
494
0
          case('D'):
495
496
0
            if( ch2 == 'O' )
497
0
              {
498
0
                if( ch3 == 'D' )
499
0
                  return( 47 );
500
0
              }
501
0
            else if( ch2 == '2' )
502
0
              {
503
0
                if( ch3 == 'O' )
504
0
                  return( 47 );    /* "D2O" -> "DOD" */
505
0
              }
506
507
0
            break;
508
509
0
          case('F'):
510
511
0
            if( ch2 == 'O' )
512
0
              if( ch3 == 'R' )
513
0
                return( 45 );
514
515
0
            break;
516
517
0
          case('G'):
518
519
0
            if( ch2 == 'L' )
520
0
              {
521
0
                if( ch3 == 'Y' )
522
0
                  return(  1 );
523
0
                else if( ch3 == 'U' )
524
0
                  return( 10 );
525
0
                else if( ch3 == 'N' )
526
0
                  return( 14 );
527
0
                else if( ch3 == 'X' )
528
0
                  return( 21 );
529
0
              }
530
0
            else if( ch2 == 'U' )
531
0
              {
532
0
                if( ch3 == 'A' )
533
0
                  return( 26 );    /* "GUA" -> "  G" */
534
0
              }
535
536
0
            break;
537
538
0
          case('H'):
539
540
0
            if( ch2 == 'I' )
541
0
              {
542
0
                if( ch3 == 'S' )
543
0
                  return( 16 );
544
0
              }
545
0
            else if( ch2 == 'O' )
546
0
              {
547
0
                if( ch3 == 'H' )
548
0
                  return( 46 );
549
0
              }
550
0
            else if( ch2 == 'Y' )
551
0
              {
552
0
                if( ch3 == 'P' )
553
0
                  return( 23 );
554
0
              }
555
0
            else if( ch2 == '2' )
556
0
              {
557
0
                if( ch3 == 'O' )
558
0
                  return( 46 );    /* "H20" -> "HOH" */
559
0
                else if( ch3 == 'U' )
560
0
                  return( 40 );
561
0
              }
562
563
0
            break;
564
565
0
          case('I'):
566
567
0
            if( ch2 == 'L' )
568
0
              if( ch3 == 'E' )
569
0
                return(  8 );
570
571
0
            break;
572
573
0
          case('L'):
574
575
0
            if( ch2 == 'E' )
576
0
              {
577
0
                if( ch3 == 'U' )
578
0
                  return(  2 );
579
0
              }
580
0
            else if( ch2 == 'Y' )
581
0
              {
582
0
                if( ch3 == 'S' )
583
0
                  return(  6 );
584
0
              }
585
586
0
            break;
587
588
0
          case('M'):
589
590
0
            if( ch2 == 'E' )
591
0
              {
592
0
                if( ch3 == 'T' )
593
0
                  return( 18 );
594
0
              }
595
0
            else if( ch2 == '2' )
596
0
              {
597
0
                if( ch3 == 'G' )
598
0
                  return( 36 );
599
0
              }
600
601
0
            break;
602
603
0
          case('N'):
604
605
0
            if( ch2 == 'A' )
606
0
              {
607
0
                if( ch3 == 'D' )
608
0
                  return( 50 );
609
0
                else if( ch3 == 'P' )
610
0
                  return( 52 );
611
0
              }
612
0
            else if( ch2 == 'D' )
613
0
              {
614
0
                if( ch3 == 'P' )
615
0
                  return( 53 );
616
0
              }
617
618
0
            break;
619
620
0
          case('P'):
621
622
0
            if( ch2 == 'R' )
623
0
              {
624
0
                if( ch3 == 'O' )
625
0
                  return( 11 );
626
0
              }
627
0
            else if( ch2 == 'H' )
628
0
              {
629
0
                if( ch3 == 'E' )
630
0
                  return( 13 );
631
0
              }
632
0
            else if( ch2 == 'C' )
633
0
              {
634
0
                if( ch3 == 'A' )
635
0
                  return( 22 );
636
0
              }
637
0
            else if( ch2 == 'O' )
638
0
              {
639
0
                if( ch3 == '4' )
640
0
                  return( 49 );
641
0
              }
642
0
            else if( ch2 == 'S' )
643
0
              {
644
0
                if( ch3 == 'U' )
645
0
                  return( 42 );
646
0
              }
647
648
0
            break;
649
650
0
          case('S'):
651
652
0
            if( ch2 == 'E' )
653
0
              {
654
0
                if( ch3 == 'R' )
655
0
                  return(  3 );
656
0
              }
657
0
            else if( ch2 == 'O' )
658
0
              {
659
0
                if( ch3 == '4' )
660
0
                  return( 48 );
661
0
                else if( ch3 == 'L' )
662
0
                  return( 46 );    /* "SOL" -> "HOH" */
663
0
              }
664
0
            else if( ch2 == 'U' )
665
0
              {
666
0
                if( ch3 == 'L' )
667
0
                  return( 48 );    /* "SUL" -> "SO4" */
668
0
              }
669
670
0
            break;
671
672
0
          case('T'):
673
674
0
            if( ch2 == 'H' )
675
0
              {
676
0
                if( ch3 == 'R' )
677
0
                  return(  5 );
678
0
                else if( ch3 == 'Y' )
679
0
                  return( 27 );    /* "THY" -> "  T" */
680
0
              }
681
0
            else if( ch2 == 'Y' )
682
0
              {
683
0
                if( ch3 == 'R' )
684
0
                  return( 15 );
685
0
              }
686
0
            else if( ch2 == 'R' )
687
0
              {
688
0
                if( ch3 == 'P' )
689
0
                  return( 19 );
690
0
                else if( ch3 == 'Y' )
691
0
                  return( 19 );    /* "TRY" -> "TRP" */
692
0
              }
693
0
            else if( ch2 == 'I' )
694
0
              {
695
0
                if( ch3 == 'P' )
696
0
                  return( 46 );    /* "TIP" -> "HOH" */
697
0
              }
698
699
0
            break;
700
701
0
          case('U'):
702
703
0
            if( ch2 == 'N' )
704
0
              {
705
0
                if( ch3 == 'K' )
706
0
                  return( 43 );
707
0
              }
708
0
            else if( ch2 == 'R' )
709
0
              {
710
0
                if( ch3 == 'A' )
711
0
                  return( 28 );    /* "URA" -> "  U" */
712
0
                else if( ch3 == 'I' )
713
0
                  return( 28 );    /* "URI" -> "  U" */
714
0
              }
715
716
0
            break;
717
718
0
          case('V'):
719
720
0
            if( ch2 == 'A' )
721
0
              if( ch3 == 'L' )
722
0
                return(  4 );
723
724
0
            break;
725
726
0
          case('W'):
727
728
0
            if( ch2 == 'A' )
729
0
              if( ch3 == 'T' )
730
0
                return( 46 );    /* "WAT" -> "HOH" */
731
732
0
            break;
733
2
          }
734
735
2
      }
736
737
2
    return OBResidueIndex::UNK;
738
2
  }
739
740
0
  void    OBResidue::SetInsertionCode(const char insertioncode) {
741
0
  _insertioncode=insertioncode;
742
0
  }
743
744
745
  static void SetResidueKeys(const char   *residue,
746
                             unsigned int &reskey,
747
                             unsigned int &aakey)
748
2
  {
749
2
    reskey = GetResidueNumber(residue);
750
2
    switch(reskey)
751
2
      {
752
0
      case OBResidueIndex::ALA:
753
0
        aakey = AA_ALA;
754
0
        break;
755
0
      case OBResidueIndex::GLY:
756
0
        aakey = AA_GLY;
757
0
        break;
758
0
      case OBResidueIndex::LEU:
759
0
        aakey = AA_LEU;
760
0
        break;
761
0
      case OBResidueIndex::SER:
762
0
        aakey = AA_SER;
763
0
        break;
764
0
      case OBResidueIndex::VAL:
765
0
        aakey = AA_VAL;
766
0
        break;
767
0
      case OBResidueIndex::THR:
768
0
        aakey = AA_THR;
769
0
        break;
770
0
      case OBResidueIndex::LYS:
771
0
        aakey = AA_LYS;
772
0
        break;
773
0
      case OBResidueIndex::ASP:
774
0
        aakey = AA_ASP;
775
0
        break;
776
0
      case OBResidueIndex::ILE:
777
0
        aakey = AA_ILE;
778
0
        break;
779
0
      case OBResidueIndex::ASN:
780
0
        aakey = AA_ASN;
781
0
        break;
782
0
      case OBResidueIndex::GLU:
783
0
        aakey = AA_GLU;
784
0
        break;
785
0
      case OBResidueIndex::PRO:
786
0
        aakey = AA_PRO;
787
0
        break;
788
0
      case OBResidueIndex::ARG:
789
0
        aakey = AA_ARG;
790
0
        break;
791
0
      case OBResidueIndex::PHE:
792
0
        aakey = AA_PHE;
793
0
        break;
794
0
      case OBResidueIndex::GLN:
795
0
        aakey = AA_GLN;
796
0
        break;
797
0
      case OBResidueIndex::TYR:
798
0
        aakey = AA_TYR;
799
0
        break;
800
0
      case OBResidueIndex::HIS:
801
0
        aakey = AA_HIS;
802
0
        break;
803
0
      case OBResidueIndex::CYS:
804
0
        aakey = AA_CYS;
805
0
        break;
806
0
      case OBResidueIndex::MET:
807
0
        aakey = AA_MET;
808
0
        break;
809
0
      case OBResidueIndex::TRP:
810
0
        aakey = AA_TRP;
811
0
        break;
812
2
      default:
813
2
        aakey = 0;
814
2
        break;
815
2
      }
816
2
  }
817
818
  ///////////////////////////////////////////////////////////////////////////////
819
  // OBResidue: Constructors / Destructor
820
  ///////////////////////////////////////////////////////////////////////////////
821
822
  OBResidue::OBResidue()
823
2
  {
824
2
    _chain    = 'A';
825
2
    _idx      = 0;
826
2
    _aakey    = 0;
827
2
    _reskey   = OBResidueIndex::UNK;
828
2
    _resnum   = "";
829
2
    _resname  = "";
830
2
    _vdata.clear();
831
2
    _insertioncode=0;
832
2
  }
833
834
  OBResidue::OBResidue(const OBResidue &src) :
835
0
    OBBase()
836
0
  {
837
0
    _chain    = src._chain;
838
0
    _aakey    = src._aakey;
839
0
    _reskey   = src._reskey;
840
0
    _resnum   = src._resnum;
841
0
    _resname  = src._resname;
842
0
    _atomid   = src._atomid;
843
0
    _hetatm   = src._hetatm;
844
0
    _sernum   = src._sernum;
845
0
    _insertioncode=src._insertioncode;
846
847
0
  }
848
849
  OBResidue::~OBResidue()
850
2
  {
851
2
    vector<OBAtom*>::iterator a;
852
13
    for ( a = _atoms.begin() ; a != _atoms.end() ; ++a )
853
11
      (*a)->SetResidue(nullptr);
854
2
    _atoms.clear();
855
856
2
  }
857
858
  ///////////////////////////////////////////////////////////////////////////////
859
  // OBResidue: Operator Overloads
860
  ///////////////////////////////////////////////////////////////////////////////
861
862
  OBResidue &OBResidue::operator = (const OBResidue &src)
863
    //copy residue information
864
    // Currently does not copy vdata informtion
865
0
  {
866
0
    if (this != &src)
867
0
      {
868
0
        _chain    = src._chain;
869
0
        _aakey    = src._aakey;
870
0
        _reskey   = src._reskey;
871
0
        _resnum   = src._resnum;
872
0
        _resname  = src._resname;
873
0
        _atomid   = src._atomid;
874
0
        _hetatm   = src._hetatm;
875
0
        _sernum   = src._sernum;
876
0
        _insertioncode = src._insertioncode;
877
0
      }
878
879
0
    return(*this);
880
0
  }
881
882
  ///////////////////////////////////////////////////////////////////////////////
883
  // OBResidue: Data Access / Manipulation
884
  ///////////////////////////////////////////////////////////////////////////////
885
886
  void OBResidue::AddAtom(OBAtom *atom)
887
11
  {
888
11
    if (atom != nullptr)
889
11
      {
890
11
        atom->SetResidue(this);
891
892
11
        _atoms.push_back(atom);
893
11
        _atomid.push_back("");
894
11
        _hetatm.push_back(false);
895
11
        _sernum.push_back(0);
896
11
      }
897
11
  }
898
899
  void OBResidue::InsertAtom(OBAtom *atom)
900
0
  {
901
0
    AddAtom(atom);
902
0
  }
903
904
  void OBResidue::RemoveAtom(OBAtom *atom)
905
0
  {
906
0
    if (atom == nullptr || _atoms.empty())
907
0
      return;
908
    // Iterate from the back so that erase doesn't shift elements past
909
    // the cursor: an atom may have been AddAtom'd more than once, and
910
    // every occurrence needs to go (otherwise ~OBResidue() later walks
911
    // a stale pointer to the now-destroyed atom).
912
0
    for (size_t i = _atoms.size(); i > 0; )
913
0
      {
914
0
        --i;
915
0
        if (_atoms[i] == atom)
916
0
          {
917
0
            atom->SetResidue(nullptr);
918
0
            _atoms.erase(_atoms.begin() + i);
919
0
            _atomid.erase(_atomid.begin() + i);
920
0
            _hetatm.erase(_hetatm.begin() + i);
921
0
            _sernum.erase(_sernum.begin() + i);
922
0
          }
923
0
      }
924
0
  }
925
926
  bool OBResidue::Clear(void)
927
0
  {
928
0
    for (unsigned int i = 0 ; i < _atoms.size() ; ++i)
929
0
      _atoms[i]->SetResidue(nullptr);
930
931
0
    _chain   = 'A';
932
0
    _idx     = 0;
933
0
    _aakey   = 0;
934
0
    _reskey  = OBResidueIndex::UNK;
935
0
    _resnum  = "";
936
0
    _resname = "";
937
0
    _insertioncode=0;
938
939
0
    _atoms.clear();
940
0
    _atomid.clear();
941
0
    _hetatm.clear();
942
0
    _sernum.clear();
943
944
0
    return (OBBase::Clear());
945
0
  }
946
947
  void OBResidue::SetChain(char chain)
948
0
  {
949
0
    _chain = chain;
950
0
  }
951
952
  void OBResidue::SetChainNum(unsigned int chainnum)
953
2
  {
954
2
    _chain = (char) ('A' + chainnum - 1);
955
2
  }
956
957
  void OBResidue::SetIdx(unsigned int idx)
958
2
  {
959
2
    _idx = idx;
960
2
  }
961
962
  void OBResidue::SetName(const string &name)
963
2
  {
964
2
    _resname = name;
965
2
    SetResidueKeys(_resname.c_str(), _reskey, _aakey);
966
2
  }
967
968
  void OBResidue::SetSegName(const string &name)
969
0
  {
970
0
    _segname = name;
971
0
  }  
972
973
  void OBResidue::SetNum(const unsigned int resnum)
974
2
  {
975
2
    stringstream temp;
976
2
    temp << resnum;
977
2
    _resnum = temp.str();
978
2
  }
979
980
  void OBResidue::SetNum(const string resnum)
981
0
  {
982
0
    _resnum = resnum;
983
0
  }
984
985
  void OBResidue::SetAtomID(OBAtom *atom, const string &id)
986
11
  {
987
47
    for ( unsigned int i = 0 ; i < _atoms.size() ; ++i )
988
36
      if (_atoms[i] == atom)
989
11
        _atomid[i] = id;
990
11
  }
991
992
  void OBResidue::SetHetAtom(OBAtom *atom, bool hetatm)
993
0
  {
994
0
    for ( unsigned int i = 0 ; i < _atoms.size() ; ++i )
995
0
      if (_atoms[i] == atom)
996
0
        _hetatm[i] = hetatm;
997
0
  }
998
999
  void OBResidue::SetSerialNum(OBAtom *atom, unsigned int sernum)
1000
11
  {
1001
47
    for ( unsigned int i = 0 ; i < _atoms.size() ; ++i )
1002
36
      if (_atoms[i] == atom)
1003
11
        _sernum[i] = sernum;
1004
11
  }
1005
1006
  vector<OBAtom*> OBResidue::GetAtoms(void) const
1007
0
  {
1008
0
    return _atoms;
1009
0
  }
1010
1011
  vector<OBBond*> OBResidue::GetBonds(bool exterior) const
1012
0
  {
1013
0
    OBAtom         *atom;
1014
0
    vector<OBBond*> bonds;
1015
0
    OBBitVec        idxs;
1016
0
    unsigned int    sz;
1017
1018
0
    sz = (unsigned int) _atoms.size();
1019
0
    for ( unsigned int i = 0 ; i < sz ; ++i )
1020
0
      {
1021
0
        atom = _atoms[i];
1022
0
        OBBond *bond;
1023
0
        vector<OBBond*>::iterator b;
1024
0
        for (bond = atom->BeginBond(b) ; bond ; bond = atom->NextBond(b))
1025
0
          {
1026
0
            if (!idxs.BitIsSet(bond->GetIdx()))
1027
0
              {
1028
0
                if (!exterior)
1029
0
                  {
1030
0
                    if (bond->GetNbrAtom(atom)->GetResidue() == this)
1031
0
                      bonds.push_back(&(*bond));
1032
0
                  }
1033
0
                else
1034
0
                  bonds.push_back(&(*bond));
1035
1036
0
                idxs.SetBitOn(bond->GetIdx());
1037
0
              }
1038
0
          }
1039
0
      }
1040
1041
0
    return bonds;
1042
0
  }
1043
1044
  string OBResidue::GetName(void) const
1045
0
  {
1046
0
    return _resname;
1047
0
  }
1048
1049
  string OBResidue::GetSegName(void) const
1050
0
  {
1051
0
    return _segname;
1052
0
  }
1053
1054
  std::string OBResidue::GetNumString(void)
1055
0
  {
1056
0
    return _resnum;
1057
0
  }
1058
1059
  int OBResidue::GetNum(void)
1060
0
  {
1061
0
    return atoi(_resnum.c_str());
1062
0
  }
1063
1064
  unsigned int OBResidue::GetNumAtoms(void) const
1065
0
  {
1066
0
    return (unsigned int)_atoms.size();
1067
0
  }
1068
1069
  unsigned int OBResidue::GetNumHvyAtoms(void) const
1070
0
  {
1071
0
    unsigned int num_hvy_atoms = 0;
1072
1073
0
    for (auto atom = this->CBeginAtoms(); atom != this->CEndAtoms(); atom++)
1074
0
    {
1075
0
      if ((*atom)->GetAtomicNum() != OBElements::Hydrogen)
1076
0
      {
1077
0
        num_hvy_atoms++;
1078
0
      }
1079
0
    }
1080
1081
0
    return num_hvy_atoms;
1082
0
  }
1083
1084
  char OBResidue::GetChain(void) const
1085
0
  {
1086
0
    return _chain;
1087
0
  }
1088
1089
  unsigned int OBResidue::GetChainNum(void) const
1090
0
  {
1091
0
    if (isdigit(_chain))
1092
0
      return (_chain - '0');
1093
0
    else
1094
0
      return (_chain - 'A' + 1);
1095
0
  }
1096
1097
  unsigned int OBResidue::GetIdx(void) const
1098
0
  {
1099
0
    return(_idx);
1100
0
  }
1101
1102
  unsigned int OBResidue::GetResKey(void) const
1103
0
  {
1104
0
    return(_reskey);
1105
0
  }
1106
1107
  char OBResidue::GetInsertionCode(void) const
1108
0
  {
1109
0
    return(_insertioncode);
1110
0
  }
1111
1112
  string OBResidue::GetAtomID(OBAtom *atom) const
1113
0
  {
1114
0
    for ( unsigned int i = 0 ; i < _atoms.size() ; ++i )
1115
0
      if (_atoms[i] == atom)
1116
0
        return _atomid[i];
1117
0
    return "";
1118
0
  }
1119
1120
  unsigned int OBResidue::GetSerialNum(OBAtom *atom) const
1121
0
  {
1122
0
    for ( unsigned int i = 0 ; i < _atoms.size() ; ++i )
1123
0
      if (_atoms[i] == atom)
1124
0
        return _sernum[i];
1125
0
    return 0;
1126
0
  }
1127
1128
  bool OBResidue::IsHetAtom(OBAtom *atom) const
1129
0
  {
1130
0
    for ( unsigned int i = 0 ; i < _atoms.size() ; ++i )
1131
0
      if (_atoms[i] == atom)
1132
0
        return _hetatm[i];
1133
0
    return false;
1134
0
  }
1135
1136
  ///////////////////////////////////////////////////////////////////////////////
1137
  // OBResidue: Iteration Utilities
1138
  ///////////////////////////////////////////////////////////////////////////////
1139
1140
  OBAtom *OBResidue::BeginAtom(vector<OBAtom*>::iterator &i)
1141
0
  {
1142
0
    i = _atoms.begin();
1143
0
    return ((i == _atoms.end()) ? nullptr : *i);
1144
0
  }
1145
1146
  OBAtom *OBResidue::NextAtom(vector<OBAtom*>::iterator &i)
1147
0
  {
1148
0
    ++i;
1149
0
    return ((i == _atoms.end()) ? nullptr : *i);
1150
0
  }
1151
1152
  ///////////////////////////////////////////////////////////////////////////////
1153
  // OBResidue: Information Functions
1154
  ///////////////////////////////////////////////////////////////////////////////
1155
1156
  bool OBResidue::GetAminoAcidProperty(int property) const
1157
0
  {
1158
0
    switch(property)
1159
0
      {
1160
0
      case OBAminoAcidProperty::ACIDIC:
1161
0
        return IS_ACIDIC(_aakey)      != 0;
1162
0
      case OBAminoAcidProperty::ACYCLIC:
1163
0
        return IS_ACYCLIC(_aakey)     != 0;
1164
0
      case OBAminoAcidProperty::ALIPHATIC:
1165
0
        return IS_ALIPHATIC(_aakey)   != 0;
1166
0
      case OBAminoAcidProperty::AROMATIC:
1167
0
        return IS_AROMATIC(_aakey)    != 0;
1168
0
      case OBAminoAcidProperty::BASIC:
1169
0
        return IS_BASIC(_aakey)       != 0;
1170
0
      case OBAminoAcidProperty::BURIED:
1171
0
        return IS_BURIED(_aakey)      != 0;
1172
0
      case OBAminoAcidProperty::CHARGED:
1173
0
        return IS_CHARGED(_aakey)     != 0;
1174
0
      case OBAminoAcidProperty::CYCLIC:
1175
0
        return IS_CYCLIC(_aakey)      != 0;
1176
0
      case OBAminoAcidProperty::HYDROPHOBIC:
1177
0
        return IS_HYDROPHOBIC(_aakey) != 0;
1178
0
      case OBAminoAcidProperty::LARGE:
1179
0
        return IS_LARGE(_aakey)       != 0;
1180
0
      case OBAminoAcidProperty::MEDIUM:
1181
0
        return IS_MEDIUM(_aakey)      != 0;
1182
0
      case OBAminoAcidProperty::NEGATIVE:
1183
0
        return IS_NEGATIVE(_aakey)    != 0;
1184
0
      case OBAminoAcidProperty::NEUTRAL:
1185
0
        return IS_NEUTRAL(_aakey)     != 0;
1186
0
      case OBAminoAcidProperty::POLAR:
1187
0
        return IS_POLAR(_aakey)       != 0;
1188
0
      case OBAminoAcidProperty::POSITIVE:
1189
0
        return IS_POSITIVE(_aakey)    != 0;
1190
0
      case OBAminoAcidProperty::SMALL:
1191
0
        return IS_SMALL(_aakey)       != 0;
1192
0
      case OBAminoAcidProperty::SURFACE:
1193
0
        return IS_SURFACE(_aakey)     != 0;
1194
0
      default:
1195
0
        return false;
1196
0
      }
1197
0
  }
1198
1199
  bool OBResidue::GetAtomProperty(OBAtom *atom, int property) const
1200
0
  {
1201
0
    if (atom != nullptr)
1202
0
      {
1203
0
        unsigned int atomid = GetAtomIDNumber(GetAtomID(atom).c_str());
1204
1205
0
        switch(property)
1206
0
          {
1207
0
          case OBResidueAtomProperty::ALPHA_CARBON:
1208
0
            return (atomid == 1);
1209
1210
0
          case OBResidueAtomProperty::AMINO_BACKBONE:
1211
0
            return (atomid <= 3);
1212
1213
0
          case OBResidueAtomProperty::BACKBONE:
1214
0
            return (atomid <= 18);
1215
1216
0
          case OBResidueAtomProperty::CYSTEINE_SULPHUR:
1217
0
            return (atomid == 20);
1218
1219
0
          case OBResidueAtomProperty::LIGAND:
1220
0
            return IsHetAtom(atom) &&
1221
0
              !GetResidueProperty(OBResidueProperty::SOLVENT);
1222
1223
0
          case OBResidueAtomProperty::NUCLEIC_BACKBONE:
1224
0
            return ((atomid >= 7) && (atomid <= 18));
1225
1226
0
          case OBResidueAtomProperty::SHAPELY_BACKBONE:
1227
0
            return (atomid <= 7);
1228
1229
0
          case OBResidueAtomProperty::SHAPELY_SPECIAL:
1230
0
            return (atomid == 19);
1231
1232
0
          case OBResidueAtomProperty::SIDECHAIN:
1233
0
            return GetResidueProperty(OBResidueProperty::AMINO_NUCLEO) &&
1234
0
              (atomid > 18);
1235
1236
0
          case OBResidueAtomProperty::SUGAR_PHOSPHATE:
1237
0
            return (atomid == 7);
1238
0
          }
1239
0
      }
1240
1241
0
    return false;
1242
0
  }
1243
1244
  bool OBResidue::GetResidueProperty(int property) const
1245
0
  {
1246
0
    switch(property)
1247
0
      {
1248
0
      case OBResidueProperty::AMINO:
1249
0
        return (_reskey <= OBResidueIndex::HYP);
1250
1251
0
      case OBResidueProperty::AMINO_NUCLEO:
1252
0
        return (_reskey <= OBResidueIndex::PSU);
1253
1254
0
      case OBResidueProperty::COENZYME:
1255
0
        return (_reskey >= OBResidueIndex::NAD) &&
1256
0
          (_reskey <= OBResidueIndex::NDP);
1257
1258
0
      case OBResidueProperty::ION:
1259
0
        return (_reskey == OBResidueIndex::SO4) ||
1260
0
          (_reskey == OBResidueIndex::PO4);
1261
1262
0
      case OBResidueProperty::NUCLEO:
1263
0
        return (_reskey >= OBResidueIndex::A) &&
1264
0
          (_reskey <= OBResidueIndex::PSU);
1265
1266
0
      case OBResidueProperty::PROTEIN:
1267
0
        return (_reskey <= OBResidueIndex::HYP) ||
1268
0
          ((_reskey >= OBResidueIndex::UNK) &&
1269
0
           (_reskey <= OBResidueIndex::FOR));
1270
1271
0
      case OBResidueProperty::PURINE:
1272
0
        return (_reskey == OBResidueIndex::A) ||
1273
0
          (_reskey == OBResidueIndex::G);
1274
1275
0
      case OBResidueProperty::PYRIMIDINE:
1276
0
        return (_reskey == OBResidueIndex::C) ||
1277
0
          (_reskey == OBResidueIndex::T);
1278
1279
0
      case OBResidueProperty::SOLVENT:
1280
0
        return (_reskey >= OBResidueIndex::HOH) &&
1281
0
          (_reskey <= OBResidueIndex::PO4);
1282
1283
0
      case OBResidueProperty::WATER:
1284
0
        return (_reskey == OBResidueIndex::HOH) ||
1285
0
          (_reskey == OBResidueIndex::DOD);
1286
1287
0
      default:
1288
0
        return false;
1289
0
      }
1290
0
  }
1291
1292
  bool OBResidue::IsResidueType(int restype) const
1293
0
  {
1294
0
    return ((int)_reskey == restype);
1295
0
  }
1296
1297
} // end namespace OpenBabel
1298
1299
//! \file residue.cpp
1300
//! \brief Handle macromolecule residues.