Bioplib
Protein Structure C Library
 All Data Structures Files Functions Variables Typedefs Macros Pages
BuildConect.c
Go to the documentation of this file.
1 /************************************************************************/
2 /**
3 
4  \file BuildConect.c
5 
6  \version V1.5
7  \date 03.10.16
8  \brief Build connectivity information in PDB linked list
9 
10  \copyright (c) UCL / Dr. Andrew C. R. Martin 2002-2016
11  \author Dr. Andrew C. R. Martin
12  \par
13  Institute of Structural & Molecular Biology,
14  University College London,
15  Gower Street,
16  London.
17  WC1E 6BT.
18  \par
19  andrew@bioinf.org.uk
20  andrew.martin@ucl.ac.uk
21 
22 **************************************************************************
23 
24  This code is NOT IN THE PUBLIC DOMAIN, but it may be copied
25  according to the conditions laid out in the accompanying file
26  COPYING.DOC.
27 
28  The code may be modified as required, but any modifications must be
29  documented so that the person responsible can be identified.
30 
31  The code may not be sold commercially or included as part of a
32  commercial product except as described in the file COPYING.DOC.
33 
34 **************************************************************************
35 
36  Description:
37  ============
38 
39 
40 **************************************************************************
41 
42  Usage:
43  ======
44 
45 **************************************************************************
46 
47  Revision History:
48  =================
49 - V1.0 19.02.15 Original
50 - V1.1 16.03.15 Added blDeleteAConect() and blDeleteAConectByNum()
51 - V1.2 12.05.15 Fixed to add conects between C and N if either is
52  a HETATM
53 - V1.3 23.06.15 Added blAreResiduesBonded() and
54  blAreResiduePointersBonded()
55 - V1.4 22.07.15 Added blIsConnected()
56 - V1.5 03.10.16 Added <stdlib.h>
57 
58 *************************************************************************/
59 /* Doxygen
60  -------
61  #GROUP Handling PDB Data
62  #SUBGROUP Miscellaneous functions
63 
64  #FUNCTION blBuildConectData()
65  Rebuild all CONECT data using covalent radii of the atoms
66 
67  #FUNCTION blAddConect()
68  Adds a CONECT in both directions between two specified atoms
69 
70  #FUNCTION blAddOneDirectionConect()
71  Adds a CONECT in one direction between two specified atoms
72 
73  #FUNCTION blDeleteAConect()
74  Deletes a CONECT between two specified atoms
75 
76  #FUNCTION blDeleteAConectByNum()
77  Deletes a specified CONECT from an atom
78 
79  #FUNCTION blDeleteAtomConects()
80  Deletes all CONECT information associated with a PDB pointer. Also
81  deletes the relevant CONECTs (back to this atom) from the partner
82  atoms
83 
84  #FUNCTION blCopyConects()
85  Updates the CONECT information in the out PDB linked list based on
86  those in the in linked list. This is used when we have copied a PDB
87  linked list (e.g. in the bl...AsCopy() routines) to make sure the
88  CONECT data points to records in the new linked list instead of the
89  old one.
90 
91  #FUNCTION blAreResiduesBonded()
92  Tests whether residues specified by chain, number and insert are
93  bonded
94 
95  #FUNCTION blAreResiduePointersBonded()
96  Tests whether residues specified by pointers to the start of the
97  residues
98 
99  #FUNCTION blIsBonded()
100  Test whether two atoms are bonded
101 
102  #FUNCTION blIsConected()
103  Tests whether two atoms are listed as connected in the CONECT records
104 */
105 /************************************************************************/
106 /* Includes
107 */
108 #include <math.h>
109 #include <stdlib.h>
110 #include "macros.h"
111 #include "pdb.h"
112 
113 /************************************************************************/
114 /* Defines and macros
115 */
117 {
118  char element[8];
120 };
121 
122 /************************************************************************/
123 /* Globals
124 */
125 static struct _covalentradii covalentRadii[] =
126 {
127  {"C", 0.76}, {"O", 0.66}, {"N", 0.71}, {"S", 1.05}, {"P", 1.11},
128  {"H", 0.31}, {"CL", 1.02}, {"K", 2.03}, {"NA", 1.66}, {"MN", 1.61},
129  {"CO", 1.50}, {"NI", 1.24}, {"CU", 1.32}, {"ZN", 1.22}, {"SE", 1.20},
130  {"BR", 1.20}, {"MG", 1.41}, {"CA", 1.76}, {"FE", 1.52}, {"LI", 1.33},
131  {"BE", 1.02}, {"B", 0.85}, {"F", 0.64}, {"NE", 0.67}, {"AL", 1.26},
132  {"SI", 1.16}, {"AR", 1.07}, {"SC", 1.70}, {"TI", 1.60}, {"V", 1.53},
133  {"CR", 1.39}, {"GA", 1.24}, {"GE", 1.21}, {"AS", 1.21}, {"KR", 1.21},
134  {"RB", 2.20}, {"SR", 1.95}, {"Y", 1.90}, {"ZR", 1.75}, {"NB", 1.64},
135  {"MO", 1.54}, {"TC", 1.47}, {"RU", 1.46}, {"RH", 1.42}, {"PD", 1.39},
136  {"AG", 1.45}, {"CD", 1.44}, {"IN", 1.46}, {"SN", 1.40}, {"SB", 1.40},
137  {"TE", 1.38}, {"I", 1.39}, {"XE", 1.40}, {"CS", 2.44}, {"BA", 2.15},
138  {"LU", 1.75}, {"HF", 1.70}, {"TA", 1.62}, {"W", 1.51}, {"RE", 1.44},
139  {"OS", 1.41}, {"IR", 1.36}, {"PT", 1.36}, {"AU", 1.32}, {"HG", 1.45},
140  {"TL", 1.46}, {"PB", 1.48}, {"BI", 1.51}, {"PO", 1.50}, {"AT", 1.50},
141  {"RN", 1.50}, {"FR", 2.60}, {"RA", 2.21}, {"LR", 1.61}, {"RF", 1.57},
142  {"DB", 1.49}, {"SG", 1.43}, {"BH", 1.41}, {"HS", 1.34}, {"MT", 1.29},
143  {"DS", 1.28}, {"RG", 1.21}, {"CN", 1.37}, {"FL", 1.43}, {"LV", 1.75},
144  {"LA", 2.07}, {"CE", 2.04}, {"PR", 2.03}, {"ND", 2.01}, {"PM", 1.99},
145  {"SM", 1.98}, {"EU", 1.98}, {"GD", 1.96}, {"TB", 1.94}, {"DY", 1.92},
146  {"HO", 1.92}, {"ER", 1.89}, {"TM", 1.90}, {"YB", 1.87}, {"AC", 2.15},
147  {"TH", 2.06}, {"PA", 2.00}, {"U", 1.96}, {"NP", 1.90}, {"PU", 1.87},
148  {"AM", 1.80}, {"CM", 1.69}, {"BK", 1.68}, {"CF", 1.68}, {"ES", 1.65},
149  {"FM", 1.67}, {"MD", 1.73}, {"NO", 1.76}, {"HE", 0.46}, {"\0", 0.00}
150 };
151 
152 
153 /************************************************************************/
154 /* Prototypes
155 */
156 static REAL findCovalentRadius(char *element);
157 
158 
159 /************************************************************************/
160 /*>BOOL blAddConect(PDB *p, PDB *q)
161  --------------------------------
162 *//**
163 
164  \param[in,out] *p First PDB item
165  \param[in,out] *q Second PDB item
166  \return Success?
167 
168  Adds a conect bteween p and q (i.e. in both directions)
169  Fails if there are too many CONECTs
170 
171 - 19.02.15 Original By: ACRM
172 */
174 {
175  BOOL retval = TRUE;
176 
177  if(!blAddOneDirectionConect(p,q))
178  retval=FALSE;
179  if(!blAddOneDirectionConect(q,p))
180  retval=FALSE;
181 
182  return(retval);
183 }
184 
185 
186 /************************************************************************/
187 /*>BOOL blAddOneDirectionConect(PDB *p, PDB *q)
188  --------------------------------------------
189 *//**
190 
191  \param[in,out] *p First PDB item
192  \param[in,out] *q Second PDB item
193  \return Success?
194 
195  Adds a conect from p to q (i.e. one direction only)
196  Fails if there are too many CONECTs
197 
198 - 19.02.15 Original By: ACRM
199 */
201 {
202  int i;
203  BOOL gotConect;
204 
205  /* See if we have the conect already */
206  gotConect=FALSE;
207  for(i=0; i<p->nConect; i++)
208  {
209  if(p->conect[i] == q)
210  {
211  gotConect = TRUE;
212  break;
213  }
214  }
215 
216  /* If we haven't got it already store it */
217  if(!gotConect)
218  {
219  if(p->nConect < MAXCONECT)
220  {
221  p->conect[p->nConect] = q;
222  (p->nConect)++;
223  }
224  else
225  {
226  return(FALSE);
227  }
228  }
229  return(TRUE);
230 }
231 
232 
233 /************************************************************************/
234 /*>BOOL blBuildConectData(PDB *pdb, REAL tol)
235  ------------------------------------------
236 *//**
237  \param[in,out] *pdb PDB linked list
238  \param[in] tol Tolerence for distance between atoms
239  \return Were all CONECTs added OK
240 
241  Deletes all current connectivity data and rebuilds it using covalent
242  radii data. A return of FALSE indicates that there were too many
243  connections for an atom. If this happens, MAXCONECT needs to be
244  increased in pdb.h
245 
246 - 19.02.15 Original By: ACRM
247 - 26.02.15 Added tol paramater
248 - 12.05.15 Conects are built involving backbone C and N if either atom
249  is a HETATM
250 */
252 {
253  PDB *p,
254  *q,
255  *res,
256  *nextRes;
257  BOOL retval=TRUE;
258 
259  /* Clear all current connect data */
260  for(p=pdb; p!=NULL; NEXT(p))
261  {
262  p->nConect = 0;
263  }
264 
265  for(res=pdb; res!=NULL; res=nextRes)
266  {
267  nextRes = blFindNextResidue(res);
268 
269  /* Check for any HETATM connections within this residue */
270  for(p=res; p!=nextRes; NEXT(p))
271  {
272  for(q=p->next; q!=nextRes; NEXT(q))
273  {
274  if(!strncmp(p->record_type, "HETATM", 6) ||
275  !strncmp(q->record_type, "HETATM", 6))
276  {
277  if(blIsBonded(p, q, tol))
278  {
279  if(!blAddConect(p,q))
280  retval=FALSE;
281  }
282  }
283  }
284  }
285 
286  /* Check for connections between residues which don't involve backbone
287  C or N, or do involve HETATMS
288  */
289  for(p=res; p!=nextRes; NEXT(p))
290  {
291  for(q=nextRes; q!=NULL; NEXT(q))
292  {
293  if(strncmp(p->atnam, "C ", 4) ||
294  strncmp(q->atnam, "N ", 4) ||
295  !strncmp(p->record_type, "HETATM", 6) ||
296  !strncmp(q->record_type, "HETATM", 6))
297  {
298  if(blIsBonded(p, q, tol))
299  {
300  if(!blAddConect(p,q))
301  retval=FALSE;
302  }
303  }
304  }
305  }
306  }
307 
308  return(retval);
309 }
310 
311 
312 /************************************************************************/
313 /*>BOOL blIsBonded(PDB *p, PDB *q, REAL tol)
314  -----------------------------------------
315 *//**
316  \param[in] *p First PDB atom
317  \param[in] *q Second PDB atom
318  \param[in] tol Telerance for separation between atoms
319  \return Bonded?
320 
321  Test whether two atoms are bonded
322 
323 - 19.02.15 Original By: ACRM
324 - 26.02.15 Added tol parameter. Changed to used squared distances
325 */
326 BOOL blIsBonded(PDB *p, PDB *q, REAL tol)
327 {
328  REAL r1, r2, bondDist;
329  r1 = findCovalentRadius(p->element);
330  r2 = findCovalentRadius(q->element);
331  bondDist = (r1+r2+tol);
332 
333  if(DISTSQ(p,q) <= bondDist*bondDist)
334  return(TRUE);
335  return(FALSE);
336 }
337 
338 
339 /************************************************************************/
340 /*>BOOL blAreResiduesBonded(PDB *pdb,
341  char *chain1, int resnum1, char *insert1,
342  char *chain2, int resnum2, char *insert2,
343  REAL tol)
344  ------------------------------------------------------------------
345 *//**
346  \param[in] *pdb PDB linked list
347  \param[in] *chain1 First chain label
348  \param[in] resnum1 First residue number
349  \param[in] *insert1 First insert code
350  \param[in] *chain2 Second chain label
351  \param[in] resnum2 Second residue number
352  \param[in] *insert2 Second insert code
353  \param[in] tol Tolerance for distances
354  \return Are they bonded
355 
356  Tests whether two residue are bonded
357 
358 - 23.06.15 Original By: ACRM
359 */
361  char *chain1, int resnum1, char *insert1,
362  char *chain2, int resnum2, char *insert2,
363  REAL tol)
364 {
365  PDB *res1,
366  *res2;
367 
368  /* Find the residues */
369  if((res1 = blFindResidue(pdb, chain1, resnum1, insert1))!=NULL)
370  {
371  if((res2 = blFindResidue(pdb, chain2, resnum2, insert2))!=NULL)
372  {
373  return(blAreResiduePointersBonded(res1, res2, tol));
374  }
375  }
376  return(FALSE);
377 }
378 
379 
380 /************************************************************************/
381 /*>BOOL blAreResiduePointersBonded(PDB *res1, PDB *res2, REAL tol)
382  ---------------------------------------------------------------
383 *//**
384  \param[in] *res1 Start of first residue
385  \param[in] *res2 Start of second residue
386  \param[in] tol Tolerance for distances
387  \return Are they bonded
388 
389  Tests whether two residue are bonded using pointers to start of
390  residues
391 
392 - 23.06.15 Original By: ACRM
393 */
395 {
396  PDB *res1next,
397  *res2next,
398  *p,
399  *q;
400 
401  if((res1 != NULL) && (res2 != NULL))
402  {
403  /* Find the following residues */
404  res1next = blFindNextResidue(res1);
405  res2next = blFindNextResidue(res2);
406 
407  /* Step through the atoms in each residue and see if they are
408  bonded
409  */
410  for(p=res1; p!=res1next; NEXT(p))
411  {
412  for(q=res2; q!=res2next; NEXT(q))
413  {
414  if(blIsBonded(p, q, tol))
415  return(TRUE);
416  }
417  }
418  }
419  return(FALSE);
420 }
421 
422 /************************************************************************/
423 /*>static REAL findCovalentRadius(char *element)
424  ---------------------------------------------
425 *//**
426  \param[in] *element The element type
427  \return The covalent bonding radius of the atom
428 
429 - 19.02.15 Original By: ACRM
430 */
431 static REAL findCovalentRadius(char *element)
432 {
433  int i;
434 
435  for(i=0; covalentRadii[i].element[0] != '\0'; i++)
436  {
437  if(!strcmp(element, covalentRadii[i].element))
438  {
439  return(covalentRadii[i].radius);
440  }
441  }
442  return((REAL)1.0);
443 }
444 
445 
446 /************************************************************************/
447 /*>BOOL blDeleteAConect(PDB *p, PDB *q)
448  -----------------------------------
449 *//**
450  \param[in] *p First PDB pointer
451  \param[in] *q Second PDB pointer
452  \return Success
453 
454  Deletes the CONECT information between the two specified atoms
455 
456 - 16.03.15 Original By: ACRM
457 */
459 {
460  int cNum;
461  BOOL retval = TRUE;
462 
463  for(cNum=0; cNum < p->nConect; cNum++)
464  {
465  if(p->conect[cNum] == q)
466  {
467  if(!blDeleteAConectByNum(p, cNum))
468  retval = FALSE;
469  break;
470  }
471  }
472 
473  for(cNum=0; cNum < q->nConect; cNum++)
474  {
475  if(q->conect[cNum] == p)
476  {
477  if(!blDeleteAConectByNum(q, cNum))
478  retval = FALSE;
479  break;
480  }
481  }
482 
483  return(retval);
484 }
485 
486 /************************************************************************/
487 /*>BOOL blDeleteAConectByNum(PDB *pdb, int cNum)
488  ------------------------------------------
489 *//**
490  \param[in] *pdb PDB pointer
491  \param[in] cNum Index into the ->conect[] array for the CONECT
492  to be deleted
493  \return Success
494 
495  Deletes the link for the specified CONECT. Other CONECTs are shuffled
496  down.
497 
498 - 16.03.15 Original By: ACRM
499 */
501 {
502  int i;
503 
504  /* Check that the CONECT exists */
505  if((cNum >= pdb->nConect) || (pdb->nConect == 0))
506  return(FALSE);
507 
508  /* Shuffle the CONECTs down */
509  for(i=cNum; i<pdb->nConect; i++)
510  {
511  PDB *next = NULL;
512  if((i+1) < pdb->nConect)
513  next = pdb->conect[i+1];
514 
515  pdb->conect[i] = next;
516  }
517 
518  /* Decrement the number of CONECTs and return */
519  pdb->nConect--;
520  return(TRUE);
521 }
522 
523 
524 /************************************************************************/
525 /*>void blDeleteAtomConects(PDB *pdb)
526  ----------------------------------
527 *//**
528  \param[in] *pdb PDB pointer
529 
530  Deletes all CONECT information associated with a PDB pointer. Also
531  deletes the relevant CONECTs (back to this atom) from the partner
532  atoms
533 
534 - 17.03.15 Original By: ACRM
535 */
537 {
538  int i;
539 
540  if(pdb!=NULL)
541  {
542  /* For each CONECT (if there are any) */
543  for(i=0; i<pdb->nConect; i++)
544  {
545  /* Find the partner */
546  PDB *conect = pdb->conect[i];
547 
548  if(conect!=NULL)
549  {
550  blDeleteAConect(pdb, conect);
551  }
552  pdb->conect[i] = NULL;
553  }
554  pdb->nConect = 0;
555  }
556 }
557 
558 /************************************************************************/
559 /*>BOOL blCopyConects(PDB *out, PDB *in)
560  -------------------------------------
561 *//**
562  \param[out] *out PDB linked list containing new CONECT records
563  \param[in] *in PDB linked list containing original CONECT records
564  \return Success
565 
566  Updates the CONECT information in the out PDB linked list based on
567  those in the in linked list. This is used when we have copied a PDB
568  linked list (e.g. in the bl...AsCopy() routines) to make sure the
569  CONECT data points to records in the new linked list instead of the
570  old one.
571 
572 - 17.04.15 Original By: ACRM
573 */
575 {
576  PDB **idxOut = NULL,
577  *p;
578  int indexSize = 0;
579 
580  /* Create an indices by atom number */
581  if((idxOut = blIndexAtomNumbersPDB(out, &indexSize))==NULL)
582  return(FALSE);
583 
584  /* Step through the output linked list */
585  for(p=out; p!=NULL; NEXT(p))
586  {
587  int i;
588 
589  /* Step through the CONECT data for this atom - which will be
590  from the OLD linked list
591  */
592  for(i=0; i<p->nConect; i++)
593  {
594  if(p->conect[i] != NULL)
595  {
596  int atomNum;
597  PDB *newPtr = NULL;
598 
599  /* Find the atom number from old linked list */
600  atomNum = (p->conect[i])->atnum;
601 
602  /* Look up the pointer for this in the new linked list index*/
603  if(atomNum < indexSize)
604  newPtr = idxOut[atomNum];
605 
606  /* Reset pointer */
607  p->conect[i] = newPtr;
608  }
609  }
610  }
611 
612  free(idxOut);
613  return(TRUE);
614 }
615 
616 /************************************************************************/
617 /*>BOOL blIsConected(PDB *p, PDB *q)
618  ---------------------------------
619 *//**
620  \param[in] *p First atom
621  \param[in] *q Second atom
622  \return Connected?
623 
624  Tests whether there is a link between the specified atoms in the
625  CONECT list
626 
627 - 07.06.99 Original By: ACRM
628 */
630 { int i;
631  for(i=0; i<p->nConect; i++)
632  {
633  if(p->conect[i] == q)
634  return(TRUE);
635  }
636 
637  for(i=0; i<q->nConect; i++)
638  {
639  if(q->conect[i] == p)
640  return(TRUE);
641  }
642 
643  return(FALSE);
644 }
645 
646 
647 /************************************************************************/
648 #ifdef TEST
649 #include <stdio.h>
650 
651 int main(int argc, char **argv)
652 {
653  char *filename = "test.pdb";
654  WHOLEPDB *wpdb;
655  FILE *fp;
656  PDB *pdb1, *pdb2, *p;
657  int natoms;
658 
659  if((fp=fopen(filename, "r"))==NULL)
660  {
661  fprintf(stderr,"Can't open %s\n", filename);
662  return(1);
663  }
664 
665  if(((wpdb=blReadWholePDB(fp))==NULL)||(wpdb->pdb == NULL))
666  {
667  fprintf(stderr,"Can't read atoms from %s\n", filename);
668  return(1);
669  }
670  fclose(fp);
671 
672  pdb1 = wpdb->pdb;
673  if((pdb2 = blStripHPDBAsCopy(pdb1, &natoms))==NULL)
674  {
675  fprintf(stderr,"Stripping hydrogens failed\n");
676  return(1);
677  }
678 
679  if(!blCopyConects(pdb2, pdb1))
680  {
681  fprintf(stderr,"Failed to copy CONECT data\n");
682  return(1);
683  }
684 
685  printf(">>> Original CONECT data\n");
686  wpdb->pdb = pdb1;
687  blWriteWholePDBTrailer(stdout, wpdb, 1);
688 
689  /* Reset atom numbers in original list to prove we aren't picking up
690  the old atoms
691  */
692  for(p=pdb1; p!=NULL; NEXT(p))
693  p->atnum = 0;
694 
695  printf(">>> New CONECT data\n");
696  wpdb->pdb = pdb2;
697  blWriteWholePDBTrailer(stdout, wpdb, 1);
698 
699  return(0);
700 }
701 #endif
702 
BOOL blAddConect(PDB *p, PDB *q)
Definition: BuildConect.c:173
BOOL blIsBonded(PDB *p, PDB *q, REAL tol)
Definition: BuildConect.c:326
int main(int argc, char **argv)
Definition: test.c:4
Include file for PDB routines.
BOOL blBuildConectData(PDB *pdb, REAL tol)
Definition: BuildConect.c:251
short BOOL
Definition: SysDefs.h:64
#define NULL
Definition: array2.c:99
Definition: pdb.h:298
#define FALSE
Definition: macros.h:223
Definition: pdb.h:372
#define NEXT(x)
Definition: macros.h:249
int atnum
Definition: pdb.h:309
char record_type[8]
Definition: pdb.h:315
Useful macros.
int nConect
Definition: pdb.h:312
WHOLEPDB * blReadWholePDB(FILE *fpin)
Definition: ReadPDB.c:2328
char atnam[8]
Definition: pdb.h:316
void blWriteWholePDBTrailer(FILE *fp, WHOLEPDB *wpdb, int numTer)
Definition: WritePDB.c:1643
BOOL blAddOneDirectionConect(PDB *p, PDB *q)
Definition: BuildConect.c:200
double REAL
Definition: MathType.h:67
PDB * pdb
Definition: pdb.h:374
char element[8]
Definition: pdb.h:322
BOOL blIsConected(PDB *p, PDB *q)
Definition: BuildConect.c:629
#define TRUE
Definition: macros.h:219
BOOL blCopyConects(PDB *out, PDB *in)
Definition: BuildConect.c:574
void blDeleteAtomConects(PDB *pdb)
Definition: BuildConect.c:536
BOOL blDeleteAConectByNum(PDB *pdb, int cNum)
Definition: BuildConect.c:500
BOOL blAreResiduePointersBonded(PDB *res1, PDB *res2, REAL tol)
Definition: BuildConect.c:394
PDB * blFindResidue(PDB *pdb, char *chain, int resnum, char *insert)
Definition: FindResidue.c:117
#define MAXCONECT
Definition: pdb.h:243
PDB ** blIndexAtomNumbersPDB(PDB *pdb, int *indexSize)
Definition: IndexPDB.c:156
PDB * blFindNextResidue(PDB *pdb)
PDB * blStripHPDBAsCopy(PDB *pdbin, int *natom)
Definition: StripHPDB.c:115
struct pdb_entry * next
Definition: pdb.h:307
#define DISTSQ(a, b)
Definition: macros.h:228
struct pdb_entry * conect[MAXCONECT]
Definition: pdb.h:308
BOOL blAreResiduesBonded(PDB *pdb, char *chain1, int resnum1, char *insert1, char *chain2, int resnum2, char *insert2, REAL tol)
Definition: BuildConect.c:360
char element[8]
Definition: BuildConect.c:118
BOOL blDeleteAConect(PDB *p, PDB *q)
Definition: BuildConect.c:458