Coverage Report

Created: 2026-04-09 06:30

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
0
  {
342
0
    if (res != nullptr && strlen(res) > 2)
343
0
      {
344
0
        int ch1 = toupper(res[0]);
345
0
        int ch2 = toupper(res[1]);
346
0
        int ch3 = toupper(res[2]);
347
348
0
        switch( ch1 )
349
0
          {
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
0
          }
734
735
0
      }
736
737
0
    return OBResidueIndex::UNK;
738
0
  }
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
0
  {
749
0
    reskey = GetResidueNumber(residue);
750
0
    switch(reskey)
751
0
      {
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
0
      default:
813
0
        aakey = 0;
814
0
        break;
815
0
      }
816
0
  }
817
818
  ///////////////////////////////////////////////////////////////////////////////
819
  // OBResidue: Constructors / Destructor
820
  ///////////////////////////////////////////////////////////////////////////////
821
822
  OBResidue::OBResidue()
823
0
  {
824
0
    _chain    = 'A';
825
0
    _idx      = 0;
826
0
    _aakey    = 0;
827
0
    _reskey   = OBResidueIndex::UNK;
828
0
    _resnum   = "";
829
0
    _resname  = "";
830
0
    _vdata.clear();
831
0
    _insertioncode=0;
832
0
  }
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
0
  {
851
0
    vector<OBAtom*>::iterator a;
852
0
    for ( a = _atoms.begin() ; a != _atoms.end() ; ++a )
853
0
      (*a)->SetResidue(nullptr);
854
0
    _atoms.clear();
855
856
0
  }
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
0
  {
888
0
    if (atom != nullptr)
889
0
      {
890
0
        atom->SetResidue(this);
891
892
0
        _atoms.push_back(atom);
893
0
        _atomid.push_back("");
894
0
        _hetatm.push_back(false);
895
0
        _sernum.push_back(0);
896
0
      }
897
0
  }
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.size())
907
0
      {
908
0
        for ( unsigned int i = 0 ; i < _atoms.size() ; ++i)
909
0
          {
910
0
            if (_atoms[i] != nullptr && _atoms[i] == atom)
911
0
              {
912
0
                atom->SetResidue(nullptr);
913
0
                _atoms.erase(_atoms.begin() + i);
914
0
                _atomid.erase(_atomid.begin() + i);
915
0
                _hetatm.erase(_hetatm.begin() + i);
916
0
                _sernum.erase(_sernum.begin() + i);
917
0
              }
918
0
          }
919
0
      }
920
0
  }
921
922
  bool OBResidue::Clear(void)
923
0
  {
924
0
    for (unsigned int i = 0 ; i < _atoms.size() ; ++i)
925
0
      _atoms[i]->SetResidue(nullptr);
926
927
0
    _chain   = 'A';
928
0
    _idx     = 0;
929
0
    _aakey   = 0;
930
0
    _reskey  = OBResidueIndex::UNK;
931
0
    _resnum  = "";
932
0
    _resname = "";
933
0
    _insertioncode=0;
934
935
0
    _atoms.clear();
936
0
    _atomid.clear();
937
0
    _hetatm.clear();
938
0
    _sernum.clear();
939
940
0
    return (OBBase::Clear());
941
0
  }
942
943
  void OBResidue::SetChain(char chain)
944
0
  {
945
0
    _chain = chain;
946
0
  }
947
948
  void OBResidue::SetChainNum(unsigned int chainnum)
949
0
  {
950
0
    _chain = (char) ('A' + chainnum - 1);
951
0
  }
952
953
  void OBResidue::SetIdx(unsigned int idx)
954
0
  {
955
0
    _idx = idx;
956
0
  }
957
958
  void OBResidue::SetName(const string &name)
959
0
  {
960
0
    _resname = name;
961
0
    SetResidueKeys(_resname.c_str(), _reskey, _aakey);
962
0
  }
963
964
  void OBResidue::SetSegName(const string &name)
965
0
  {
966
0
    _segname = name;
967
0
  }  
968
969
  void OBResidue::SetNum(const unsigned int resnum)
970
0
  {
971
0
    stringstream temp;
972
0
    temp << resnum;
973
0
    _resnum = temp.str();
974
0
  }
975
976
  void OBResidue::SetNum(const string resnum)
977
0
  {
978
0
    _resnum = resnum;
979
0
  }
980
981
  void OBResidue::SetAtomID(OBAtom *atom, const string &id)
982
0
  {
983
0
    for ( unsigned int i = 0 ; i < _atoms.size() ; ++i )
984
0
      if (_atoms[i] == atom)
985
0
        _atomid[i] = id;
986
0
  }
987
988
  void OBResidue::SetHetAtom(OBAtom *atom, bool hetatm)
989
0
  {
990
0
    for ( unsigned int i = 0 ; i < _atoms.size() ; ++i )
991
0
      if (_atoms[i] == atom)
992
0
        _hetatm[i] = hetatm;
993
0
  }
994
995
  void OBResidue::SetSerialNum(OBAtom *atom, unsigned int sernum)
996
0
  {
997
0
    for ( unsigned int i = 0 ; i < _atoms.size() ; ++i )
998
0
      if (_atoms[i] == atom)
999
0
        _sernum[i] = sernum;
1000
0
  }
1001
1002
  vector<OBAtom*> OBResidue::GetAtoms(void) const
1003
0
  {
1004
0
    return _atoms;
1005
0
  }
1006
1007
  vector<OBBond*> OBResidue::GetBonds(bool exterior) const
1008
0
  {
1009
0
    OBAtom         *atom;
1010
0
    vector<OBBond*> bonds;
1011
0
    OBBitVec        idxs;
1012
0
    unsigned int    sz;
1013
1014
0
    sz = (unsigned int) _atoms.size();
1015
0
    for ( unsigned int i = 0 ; i < sz ; ++i )
1016
0
      {
1017
0
        atom = _atoms[i];
1018
0
        OBBond *bond;
1019
0
        vector<OBBond*>::iterator b;
1020
0
        for (bond = atom->BeginBond(b) ; bond ; bond = atom->NextBond(b))
1021
0
          {
1022
0
            if (!idxs.BitIsSet(bond->GetIdx()))
1023
0
              {
1024
0
                if (!exterior)
1025
0
                  {
1026
0
                    if (bond->GetNbrAtom(atom)->GetResidue() == this)
1027
0
                      bonds.push_back(&(*bond));
1028
0
                  }
1029
0
                else
1030
0
                  bonds.push_back(&(*bond));
1031
1032
0
                idxs.SetBitOn(bond->GetIdx());
1033
0
              }
1034
0
          }
1035
0
      }
1036
1037
0
    return bonds;
1038
0
  }
1039
1040
  string OBResidue::GetName(void) const
1041
0
  {
1042
0
    return _resname;
1043
0
  }
1044
1045
  string OBResidue::GetSegName(void) const
1046
0
  {
1047
0
    return _segname;
1048
0
  }
1049
1050
  std::string OBResidue::GetNumString(void)
1051
0
  {
1052
0
    return _resnum;
1053
0
  }
1054
1055
  int OBResidue::GetNum(void)
1056
0
  {
1057
0
    return atoi(_resnum.c_str());
1058
0
  }
1059
1060
  unsigned int OBResidue::GetNumAtoms(void) const
1061
0
  {
1062
0
    return (unsigned int)_atoms.size();
1063
0
  }
1064
1065
  unsigned int OBResidue::GetNumHvyAtoms(void) const
1066
0
  {
1067
0
    unsigned int num_hvy_atoms = 0;
1068
1069
0
    for (auto atom = this->CBeginAtoms(); atom != this->CEndAtoms(); atom++)
1070
0
    {
1071
0
      if ((*atom)->GetAtomicNum() != OBElements::Hydrogen)
1072
0
      {
1073
0
        num_hvy_atoms++;
1074
0
      }
1075
0
    }
1076
1077
0
    return num_hvy_atoms;
1078
0
  }
1079
1080
  char OBResidue::GetChain(void) const
1081
0
  {
1082
0
    return _chain;
1083
0
  }
1084
1085
  unsigned int OBResidue::GetChainNum(void) const
1086
0
  {
1087
0
    if (isdigit(_chain))
1088
0
      return (_chain - '0');
1089
0
    else
1090
0
      return (_chain - 'A' + 1);
1091
0
  }
1092
1093
  unsigned int OBResidue::GetIdx(void) const
1094
0
  {
1095
0
    return(_idx);
1096
0
  }
1097
1098
  unsigned int OBResidue::GetResKey(void) const
1099
0
  {
1100
0
    return(_reskey);
1101
0
  }
1102
1103
  char OBResidue::GetInsertionCode(void) const
1104
0
  {
1105
0
    return(_insertioncode);
1106
0
  }
1107
1108
  string OBResidue::GetAtomID(OBAtom *atom) const
1109
0
  {
1110
0
    for ( unsigned int i = 0 ; i < _atoms.size() ; ++i )
1111
0
      if (_atoms[i] == atom)
1112
0
        return _atomid[i];
1113
0
    return "";
1114
0
  }
1115
1116
  unsigned int OBResidue::GetSerialNum(OBAtom *atom) const
1117
0
  {
1118
0
    for ( unsigned int i = 0 ; i < _atoms.size() ; ++i )
1119
0
      if (_atoms[i] == atom)
1120
0
        return _sernum[i];
1121
0
    return 0;
1122
0
  }
1123
1124
  bool OBResidue::IsHetAtom(OBAtom *atom) const
1125
0
  {
1126
0
    for ( unsigned int i = 0 ; i < _atoms.size() ; ++i )
1127
0
      if (_atoms[i] == atom)
1128
0
        return _hetatm[i];
1129
0
    return false;
1130
0
  }
1131
1132
  ///////////////////////////////////////////////////////////////////////////////
1133
  // OBResidue: Iteration Utilities
1134
  ///////////////////////////////////////////////////////////////////////////////
1135
1136
  OBAtom *OBResidue::BeginAtom(vector<OBAtom*>::iterator &i)
1137
0
  {
1138
0
    i = _atoms.begin();
1139
0
    return ((i == _atoms.end()) ? nullptr : *i);
1140
0
  }
1141
1142
  OBAtom *OBResidue::NextAtom(vector<OBAtom*>::iterator &i)
1143
0
  {
1144
0
    ++i;
1145
0
    return ((i == _atoms.end()) ? nullptr : *i);
1146
0
  }
1147
1148
  ///////////////////////////////////////////////////////////////////////////////
1149
  // OBResidue: Information Functions
1150
  ///////////////////////////////////////////////////////////////////////////////
1151
1152
  bool OBResidue::GetAminoAcidProperty(int property) const
1153
0
  {
1154
0
    switch(property)
1155
0
      {
1156
0
      case OBAminoAcidProperty::ACIDIC:
1157
0
        return IS_ACIDIC(_aakey)      != 0;
1158
0
      case OBAminoAcidProperty::ACYCLIC:
1159
0
        return IS_ACYCLIC(_aakey)     != 0;
1160
0
      case OBAminoAcidProperty::ALIPHATIC:
1161
0
        return IS_ALIPHATIC(_aakey)   != 0;
1162
0
      case OBAminoAcidProperty::AROMATIC:
1163
0
        return IS_AROMATIC(_aakey)    != 0;
1164
0
      case OBAminoAcidProperty::BASIC:
1165
0
        return IS_BASIC(_aakey)       != 0;
1166
0
      case OBAminoAcidProperty::BURIED:
1167
0
        return IS_BURIED(_aakey)      != 0;
1168
0
      case OBAminoAcidProperty::CHARGED:
1169
0
        return IS_CHARGED(_aakey)     != 0;
1170
0
      case OBAminoAcidProperty::CYCLIC:
1171
0
        return IS_CYCLIC(_aakey)      != 0;
1172
0
      case OBAminoAcidProperty::HYDROPHOBIC:
1173
0
        return IS_HYDROPHOBIC(_aakey) != 0;
1174
0
      case OBAminoAcidProperty::LARGE:
1175
0
        return IS_LARGE(_aakey)       != 0;
1176
0
      case OBAminoAcidProperty::MEDIUM:
1177
0
        return IS_MEDIUM(_aakey)      != 0;
1178
0
      case OBAminoAcidProperty::NEGATIVE:
1179
0
        return IS_NEGATIVE(_aakey)    != 0;
1180
0
      case OBAminoAcidProperty::NEUTRAL:
1181
0
        return IS_NEUTRAL(_aakey)     != 0;
1182
0
      case OBAminoAcidProperty::POLAR:
1183
0
        return IS_POLAR(_aakey)       != 0;
1184
0
      case OBAminoAcidProperty::POSITIVE:
1185
0
        return IS_POSITIVE(_aakey)    != 0;
1186
0
      case OBAminoAcidProperty::SMALL:
1187
0
        return IS_SMALL(_aakey)       != 0;
1188
0
      case OBAminoAcidProperty::SURFACE:
1189
0
        return IS_SURFACE(_aakey)     != 0;
1190
0
      default:
1191
0
        return false;
1192
0
      }
1193
0
  }
1194
1195
  bool OBResidue::GetAtomProperty(OBAtom *atom, int property) const
1196
0
  {
1197
0
    if (atom != nullptr)
1198
0
      {
1199
0
        unsigned int atomid = GetAtomIDNumber(GetAtomID(atom).c_str());
1200
1201
0
        switch(property)
1202
0
          {
1203
0
          case OBResidueAtomProperty::ALPHA_CARBON:
1204
0
            return (atomid == 1);
1205
1206
0
          case OBResidueAtomProperty::AMINO_BACKBONE:
1207
0
            return (atomid <= 3);
1208
1209
0
          case OBResidueAtomProperty::BACKBONE:
1210
0
            return (atomid <= 18);
1211
1212
0
          case OBResidueAtomProperty::CYSTEINE_SULPHUR:
1213
0
            return (atomid == 20);
1214
1215
0
          case OBResidueAtomProperty::LIGAND:
1216
0
            return IsHetAtom(atom) &&
1217
0
              !GetResidueProperty(OBResidueProperty::SOLVENT);
1218
1219
0
          case OBResidueAtomProperty::NUCLEIC_BACKBONE:
1220
0
            return ((atomid >= 7) && (atomid <= 18));
1221
1222
0
          case OBResidueAtomProperty::SHAPELY_BACKBONE:
1223
0
            return (atomid <= 7);
1224
1225
0
          case OBResidueAtomProperty::SHAPELY_SPECIAL:
1226
0
            return (atomid == 19);
1227
1228
0
          case OBResidueAtomProperty::SIDECHAIN:
1229
0
            return GetResidueProperty(OBResidueProperty::AMINO_NUCLEO) &&
1230
0
              (atomid > 18);
1231
1232
0
          case OBResidueAtomProperty::SUGAR_PHOSPHATE:
1233
0
            return (atomid == 7);
1234
0
          }
1235
0
      }
1236
1237
0
    return false;
1238
0
  }
1239
1240
  bool OBResidue::GetResidueProperty(int property) const
1241
0
  {
1242
0
    switch(property)
1243
0
      {
1244
0
      case OBResidueProperty::AMINO:
1245
0
        return (_reskey <= OBResidueIndex::HYP);
1246
1247
0
      case OBResidueProperty::AMINO_NUCLEO:
1248
0
        return (_reskey <= OBResidueIndex::PSU);
1249
1250
0
      case OBResidueProperty::COENZYME:
1251
0
        return (_reskey >= OBResidueIndex::NAD) &&
1252
0
          (_reskey <= OBResidueIndex::NDP);
1253
1254
0
      case OBResidueProperty::ION:
1255
0
        return (_reskey == OBResidueIndex::SO4) ||
1256
0
          (_reskey == OBResidueIndex::PO4);
1257
1258
0
      case OBResidueProperty::NUCLEO:
1259
0
        return (_reskey >= OBResidueIndex::A) &&
1260
0
          (_reskey <= OBResidueIndex::PSU);
1261
1262
0
      case OBResidueProperty::PROTEIN:
1263
0
        return (_reskey <= OBResidueIndex::HYP) ||
1264
0
          ((_reskey >= OBResidueIndex::UNK) &&
1265
0
           (_reskey <= OBResidueIndex::FOR));
1266
1267
0
      case OBResidueProperty::PURINE:
1268
0
        return (_reskey == OBResidueIndex::A) ||
1269
0
          (_reskey == OBResidueIndex::G);
1270
1271
0
      case OBResidueProperty::PYRIMIDINE:
1272
0
        return (_reskey == OBResidueIndex::C) ||
1273
0
          (_reskey == OBResidueIndex::T);
1274
1275
0
      case OBResidueProperty::SOLVENT:
1276
0
        return (_reskey >= OBResidueIndex::HOH) &&
1277
0
          (_reskey <= OBResidueIndex::PO4);
1278
1279
0
      case OBResidueProperty::WATER:
1280
0
        return (_reskey == OBResidueIndex::HOH) ||
1281
0
          (_reskey == OBResidueIndex::DOD);
1282
1283
0
      default:
1284
0
        return false;
1285
0
      }
1286
0
  }
1287
1288
  bool OBResidue::IsResidueType(int restype) const
1289
0
  {
1290
0
    return ((int)_reskey == restype);
1291
0
  }
1292
1293
} // end namespace OpenBabel
1294
1295
//! \file residue.cpp
1296
//! \brief Handle macromolecule residues.