Bioplib
Protein Structure C Library
 All Data Structures Files Functions Variables Typedefs Macros Pages
access.c
Go to the documentation of this file.
1 /************************************************************************/
2 /**
3 
4  \file access.c
5 
6  \version V1.2
7  \date 17.06.15
8  \brief Accessibility calculation code
9 
10  \copyright (c) UCL, Dr. Andrew C.R. Martin, 1999-2015
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  Calculation of solvent accessibility by the method of Lee and Richards.
40  Based loosely on PMCL code by Peter McLaughlin
41 
42 **************************************************************************
43 
44  Usage:
45  ======
46 \code
47  RESRAD *blSetAtomRadii(PDB *pdb, FILE *fpRad)
48 \endcode
49  Read the radius file and set the radii in the PDB linked list.
50  Also returns the data from the radius file for use by
51  blCalcResAccess()
52 
53 \code
54  BOOL blCalcAccess(PDB *pdb, int natoms,
55  REAL integrationAccuracy, REAL probeRadius,
56  BOOL doAccessibility)
57 \endcode
58  Does the accessibilty calculations. integrationAccuracy can be set
59  to zero to use the default value
60 
61 \code
62  RESACCESS *blCalcResAccess(PDB *pdb, RESRAD *resrad)
63 \endcode
64  Calculates residue accessibility and relative accessibility
65 
66 **************************************************************************
67 
68  Revision History:
69  =================
70 - V1.0 21.04.99 Original By: ACRM
71 - V1.1 17.07.14 Extracted from XMAS code
72 - V1.2 17.06.15 Added sidechain residues access
73 
74 *************************************************************************/
75 /* Doxygen
76  -------
77  #GROUP Handling PDB Data
78  #SUBGROUP Analyzing structures
79  #FUNCTION blSetAtomRadii()
80  Set atom radii from the radius file in the PDB linked list
81  Returns the radius lookup information since it also contains the
82  standard accessibilities
83 
84  #FUNCTION blCalcAccess()
85  Allocates arrays and calls routines to populate them, do the access
86  calculations and populate into the PDB linked list
87 
88  #FUNCTION blCalcResAccess()
89  Calculates and populates the residue totals and relative values
90  using standards stored in resrad
91 */
92 /************************************************************************/
93 /* Includes
94 */
95 #include <stdio.h>
96 #include <stdlib.h>
97 #include <math.h>
98 
99 #include "macros.h"
100 #include "SysDefs.h"
101 #include "pdb.h"
102 #include "access.h"
103 
104 /************************************************************************/
105 /* Defines and macros
106 */
107 #define MAXBUFF 160 /* I/O buffer */
108 #define MAX_INTERSECT 10000 /* Initial max no. of intersections of
109  neighbouring spheres - expands as
110  required */
111 #define MAX_INTERSECT_EXP 100 /* Amount to expand intersect array by */
112 #define MAX_ATOM_IN_CUBE 100 /* Initial max no. of atoms in a cube -
113  expands as required */
114 
115 #define FREE_ACCESS_STORAGE \
116 do { \
117  if(cube) free(cube); \
118  if(radii) free(radii); \
119  if(radiiSquared) free(radiiSquared); \
120  if(neighbours) free(neighbours); \
121  if(flag) free(flag); \
122  if(arci) free(arci); \
123  if(arcf) free(arcf); \
124  if(deltaX) free(deltaX); \
125  if(deltaY) free(deltaY); \
126  if(dist) free(dist); \
127  if(distSquared) free(distSquared); \
128  if(atomTable) free(atomTable); \
129  if(atomsInCube) { \
130  for(i=0;i<=maxAtomInCube;i++) \
131  { if(atomsInCube[i]) free(atomsInCube[i]); \
132  else break; \
133  } \
134  free(atomsInCube); \
135  } \
136 } while(0);
137 
138 
139 #define EXPAND_INTERSECT_ARRAYS \
140 do { int newMaxIntersect = (maxIntersect+MAX_INTERSECT_EXP), \
141  iexpand; \
142  neighbours = (int *)realloc(neighbours, \
143  (newMaxIntersect+1)*sizeof(int)); \
144  flag = (int *)realloc(flag, (newMaxIntersect+1)*sizeof(int)); \
145  arci = (REAL *)realloc(arci, (newMaxIntersect+1)*sizeof(REAL)); \
146  arcf = (REAL *)realloc(arcf, (newMaxIntersect+1)*sizeof(REAL)); \
147  deltaX = (REAL *)realloc(deltaX, (newMaxIntersect+1)*sizeof(REAL)); \
148  deltaY = (REAL *)realloc(deltaY, (newMaxIntersect+1)*sizeof(REAL)); \
149  dist = (REAL *)realloc(dist, (newMaxIntersect+1)*sizeof(REAL)); \
150  distSquared = (REAL *)realloc(distSquared, \
151  (newMaxIntersect+1)*sizeof(REAL)); \
152  if(neighbours==NULL || flag==NULL || arci==NULL || arcf==NULL || \
153  deltaX==NULL || deltaY==NULL || dist==NULL || \
154  distSquared==NULL) \
155  { FREE_ACCESS_STORAGE; \
156  return(FALSE); \
157  } \
158  for(iexpand=maxIntersect+1; iexpand<=newMaxIntersect; iexpand++) \
159  { neighbours[iexpand] = 0; \
160  flag[iexpand] = 0; \
161  arci[iexpand] = 0.0; \
162  arcf[iexpand] = 0.0; \
163  deltaX[iexpand] = 0.0; \
164  deltaY[iexpand] = 0.0; \
165  dist[iexpand] = 0.0; \
166  distSquared[iexpand] = 0.0; \
167  } \
168  maxIntersect = newMaxIntersect; \
169 } while(0)
170 
171 /************************************************************************/
172 /* Prototypes
173 */
174 static void SortArcEndpoints(REAL *a, int n, int *flag);
175 static BOOL doCalcAccess(int numAtoms, REAL integrationAccuracy,
176  REAL probeRadius, BOOL access,
177  REAL *AtomRadius,
178  REAL *x, REAL *y, REAL *z,
179  REAL *accessResults);
180 static void FillArrays(PDB *pdb, REAL *x, REAL *y, REAL *z, REAL *r);
181 static RESRAD *GetResidueRadii(RESRAD *resrad, char *resnam);
182 static RESRAD *ReadRadiusFile(FILE *fpRad);
183 static REAL GetStandardAccess(char *resnam, RESRAD *resrad);
184 static REAL DefaultRadius(char *element);
185 static void SetPDBAccess(PDB *pdb, REAL *accessArray);
186 static char *blGetElement(PDB *p);
187 static REAL GetStandardAccessSC(char *resnam, RESRAD *resrad);
188 
189 
190 /************************************************************************/
191 /*>static char *blGetElement(PDB *p)
192  ---------------------------------
193 *//**
194  \param[in] *p PDB structure pointer
195  \return Element assignment
196 
197  This will be replaced by Craig's routine in Bioplib
198  Note: Atomic symbol is not stored in PDB data structure.
199  Value set is based on columns 13-14 of pdb-formated text
200  file.
201 
202 - 17.07.14 Original By: ACRM
203  */
204 static char *blGetElement(PDB *p)
205 {
206  char buffer[8];
207  char *buffer_ptr;
208  char *rawAtomName = p->atnam_raw;
209 
210  strncpy(buffer,rawAtomName,2);
211  buffer[2] = '\0';
212 
213  KILLLEADSPACES(buffer_ptr,buffer);
214 
215  /* remove digits */
216  if(strlen(buffer_ptr) == 2 && isdigit(buffer[1]))
217  {
218  buffer[1] = '\0';
219  }
220  else if(strlen(buffer_ptr) == 2 && !isalpha(buffer[0]))
221  {
222  buffer_ptr += 1;
223  }
224 
225  /* fix hydrogens and carbons */
226  if(strlen(buffer_ptr) == 2 && rawAtomName[3] != ' ' &&
227  (rawAtomName[0] == 'H' || rawAtomName[0] == 'C' ||
228  rawAtomName[0] == 'N' || rawAtomName[0] == 'O' ||
229  rawAtomName[0] == 'P'))
230  {
231  if(!isalpha(rawAtomName[2]) || !isalpha(rawAtomName[3]))
232  {
233  buffer[1] = '\0';
234  }
235  }
236 
237  return(buffer_ptr);
238 }
239 
240 /************************************************************************/
241 /*>RESRAD *blSetAtomRadii(PDB *pdb, FILE *fpRad)
242  ---------------------------------------------
243 *//**
244  \param[in,out] *pdb PDB linked list
245  \param[in] *fpRad Radius file pointer
246  \return Linked list of radius information
247 
248  Set atom radii from the radius file in the PDB linked list
249  Returns the radius lookup information since it also contains the
250  standard accessibilities
251 
252 - 22.04.99 Original By: ACRM
253 - 16.06.99 Initialise radii to NULL
254 - 22.06.99 Changed to call DefaultRadius() with element type rather
255  than atom name
256 - 16.07.14 Rewritten to work outside XMAS format and now takes the
257  file pointer to the radii file rather than the filename
258 */
259 RESRAD *blSetAtomRadii(PDB *pdb, FILE *fpRad)
260 {
261  RESRAD *resrad,
262  *radii = NULL;
263  int i;
264  char currentResnam[8];
265  PDB *p;
266 
267 
268  resrad=ReadRadiusFile(fpRad);
269 
270  strcpy(currentResnam," ");
271  for(p=pdb; p!=NULL; NEXT(p))
272  {
273  /* If residue name has changed, find pointer to this residue in
274  the radius list
275  */
276  if(strncmp(p->resnam, currentResnam, 3))
277  {
278  strcpy(currentResnam, p->resnam);
279  radii = GetResidueRadii(resrad,p->resnam);
280  }
281 
282  if(radii == NULL)
283  {
284  /* Residue not found, use default for element */
285  p->radius = DefaultRadius(blGetElement(p));
286  }
287  else
288  {
289  for(i=0; i<radii->natoms; i++)
290  {
291  if(!strncmp(p->atnam_raw, radii->atnam[i], 4))
292  {
293  p->radius = radii->radius[i];
294  break;
295  }
296  }
297 
298  if(i==radii->natoms)
299  {
300  /* Didn't find this atom in the residue - use default atom
301  radius
302  */
303  p->radius = DefaultRadius(blGetElement(p));
304  }
305  }
306  }
307 
308  return(resrad);
309 }
310 
311 
312 /************************************************************************/
313 /*>BOOL blCalcAccess(PDB *pdb, int natoms,
314  REAL integrationAccuracy,
315  REAL probeRadius,
316  BOOL doAccessibility)
317  --------------------------------------------------------------
318 *//**
319  \param[in,out] *pdb PDB linked list
320  \param[in] natoms Number of atoms
321  \param[in] integrationAccuracy Integration accuracy
322  \param[in] probeRadius Probe radius
323  \param[in] doAccessibility Accessibility or contact area
324  \return Success
325 
326  Allocates arrays and calls routines to populate them, do the access
327  calculations and populate into the PDB linked list
328 
329 - 22.04.99 Original By: ACRM
330 */
331 BOOL blCalcAccess(PDB *pdb, int natoms,
332  REAL integrationAccuracy, REAL probeRadius,
333  BOOL doAccessibility)
334 {
335  REAL *x = NULL,
336  *y = NULL,
337  *z = NULL,
338  *radii = NULL,
339  *accessArray = NULL;
340  BOOL retval = FALSE;
341 
342  if(integrationAccuracy < VERY_SMALL)
343  integrationAccuracy = ACCESS_DEF_INTACC;
344 
345  /* Allocate arrays */
346  if((x=(REAL *)malloc(natoms * sizeof(REAL)))!=NULL)
347  {
348  if((y=(REAL *)malloc(natoms * sizeof(REAL)))!=NULL)
349  {
350  if((z=(REAL *)malloc(natoms * sizeof(REAL)))!=NULL)
351  {
352  if((radii=(REAL *)malloc(natoms * sizeof(REAL)))!=NULL)
353  {
354  if((accessArray=(REAL *)malloc(natoms * sizeof(REAL)))
355  !=NULL)
356  {
357  retval = TRUE;
358 
359  /* Populate arrays from PDB structure, do the
360  accessibility run and put the results back into the
361  PDB structure
362  */
363  FillArrays(pdb, x, y, z, radii);
364  doCalcAccess(natoms, integrationAccuracy, probeRadius,
365  doAccessibility,
366  radii, x, y, z,
367  accessArray);
368  SetPDBAccess(pdb, accessArray);
369  }
370  }
371  }
372  }
373  }
374 
375  /* Free the allocated memory */
376  if(x!=NULL) free(x);
377  if(y!=NULL) free(y);
378  if(z!=NULL) free(z);
379  if(radii!=NULL) free(radii);
380  if(accessArray!=NULL) free(accessArray);
381 
382  return(retval);
383 }
384 
385 
386 
387 /************************************************************************/
388 /*>static void FillArrays(PDB *pdb, REAL *x, REAL *y, REAL *z, REAL *r)
389  --------------------------------------------------------------------
390 *//**
391  \param[in] *pdb PDB linked list
392  \param[out] *x X coordinate array
393  \param[out] *y Y coordinate array
394  \param[out] *z Z coordinate array
395  \param[out] *r radius array
396 
397  Fills the coordinate and atom arrays from the PDB linked list
398 
399 - 22.04.99 Original By: ACRM
400 */
401 static void FillArrays(PDB *pdb, REAL *x, REAL *y, REAL *z, REAL *r)
402 {
403  PDB *p;
404  int count = 0;
405 
406 
407  for(p=pdb; p!=NULL; NEXT(p))
408  {
409  x[count] = p->x;
410  y[count] = p->y;
411  z[count] = p->z;
412  r[count] = p->radius;
413 
414  count++;
415  }
416 }
417 
418 
419 /************************************************************************/
420 /*>static RESRAD *GetResidueRadii(RESRAD *resrad, char *resnam)
421  --------------------------------------------------------------
422 *//**
423  \param[in] *resrad Linked list of atom radii information
424  \param[in] *resnam Residue name we are looking for
425  \return Pointer to information on this residue
426  (or NULL)
427 
428  Gets the radius information for the specified residue.
429 
430 - 22.04.99 Original By: ACRM
431 */
432 static RESRAD *GetResidueRadii(RESRAD *resrad, char *resnam)
433 {
434  RESRAD *r;
435 
436  /* Search through the residue types to find this residue */
437  for(r=resrad; r!=NULL; NEXT(r))
438  {
439  if(!strncmp(r->resnam, resnam, 3))
440  {
441  return(r);
442  break;
443  }
444  }
445 
446  return(NULL);
447 }
448 
449 /************************************************************************/
450 /*>static RESRAD *ReadRadiusFile(FILE *fpRad)
451  -----------------------------------------
452 *//**
453  \param[in] *fpRad Atom radius file pointer
454  \return Linked list of residue and atom radius
455  information
456 
457  Reads the specified file into the linked list of atom radii for each
458  residue type. The file also contains standard residue accessibility.
459 
460 - 22.04.99 Original By: ACRM
461 - 16.06.99 Initialise atomIndex to 0 and r to NULL
462 - 16.07.14 Changed to passing in file pointer
463 - 17.06.15 Reads stdAccessSc
464 */
465 static RESRAD *ReadRadiusFile(FILE *fpRad)
466 {
467  char buffer[MAXBUFF],
468  *chp,
469  junk[8];
470  RESRAD *resrad = NULL,
471  *r = NULL;
472  int atomCount = 0,
473  atomIndex = 0;
474 
475  while(fgets(buffer,MAXBUFF,fpRad))
476  {
477  if((chp=strchr(buffer,'#'))!=NULL) /* Strip comments */
478  *chp = '\0';
479 
480  KILLLEADSPACES(chp, buffer);
481  if(!strlen(chp)) /* Skip blank lines */
482  continue;
483 
484  /* Beginning of a new residue */
485  if(!atomCount)
486  {
487  if(resrad==NULL)
488  {
489  INIT(resrad, RESRAD);
490  r = resrad;
491  }
492  else
493  {
494  ALLOCNEXT(r, RESRAD);
495  }
496  if(r==NULL)
497  {
498  FREELIST(resrad, RESRAD);
499  return(NULL);
500  }
501 
502  sscanf(buffer,"%s %d %lf %lf",
503  r->resnam, &(r->natoms),
504  &(r->stdAccess), &(r->stdAccessSC));
505  atomCount = r->natoms;
506  atomIndex = 0;
507  }
508  else
509  {
510  strncpy(r->atnam[atomIndex],buffer,5);
511  r->atnam[atomIndex][5] = '\0';
512 #ifdef NO_LEAD_SPACE
513  if(r->atnam[atomIndex][0] == ' ')
514  {
515  for(i=0; i<4; i++)
516  r->atnam[atomIndex][i] = r->atnam[atomIndex][i+1];
517  }
518 #endif
519  /* Replace dots with spaces */
520  DEDOTIFY(r->atnam[atomIndex]);
521 
522  sscanf(buffer,"%s %lf",junk,&(r->radius[atomIndex]));
523  atomIndex++;
524  atomCount--;
525  }
526  }
527 
528  return(resrad);
529 }
530 
531 
532 /************************************************************************/
533 /*>static REAL GetStandardAccess(char *resnam, RESRAD *resrad)
534  ------------------------------------------------------------
535 *//**
536  \param[in] *resnam Residue name
537  \param[in] *resrad Residue/atom radii and standard
538  accessibilities
539  \return Standard accessibility for this residue
540 
541  Gets the standard accessibility for the specified residue type
542 
543 - 22.04.99 Original By: ACRM
544 */
545 static REAL GetStandardAccess(char *resnam, RESRAD *resrad)
546 {
547  RESRAD *r;
548 
549  /* Search through the residue types to find this residue */
550  for(r=resrad; r!=NULL; NEXT(r))
551  {
552  if(!strncmp(r->resnam, resnam, 3))
553  {
554  return(r->stdAccess);
555  }
556  }
557 
558  return((REAL)0.0);
559 }
560 
561 /************************************************************************/
562 /*>static REAL GetStandardAccessSC(char *resnam, RESRAD *resrad)
563  --------------------------------------------------------------
564 *//**
565  \param[in] *resnam Residue name
566  \param[in] *resrad Residue/atom radii and standard
567  accessibilities
568  \return Standard s/c accessibility for this residue
569 
570  Gets the standard sidechain accessibility for the specified residue
571  type
572 
573 - 17.06.15 Original By: ACRM
574 */
575 static REAL GetStandardAccessSC(char *resnam, RESRAD *resrad)
576 {
577  RESRAD *r;
578 
579  /* Search through the residue types to find this residue */
580  for(r=resrad; r!=NULL; NEXT(r))
581  {
582  if(!strncmp(r->resnam, resnam, 3))
583  {
584  return(r->stdAccessSC);
585  }
586  }
587 
588  return((REAL)0.0);
589 }
590 
591 /************************************************************************/
592 /*>static REAL DefaultRadius(char *element)
593  ----------------------------------------
594 *//**
595  \param[in] *element Element
596  \return Default radius
597 
598  Returns the default radius for a specified atom type
599 
600 - 22.04.99 Original By: ACRM
601 - 22.06.99 Modified to work with element rather than atom name
602 */
603 static REAL DefaultRadius(char *element)
604 {
605  if(!strcmp(element,"C"))
606  return((REAL)1.80);
607  else if(!strcmp(element,"N"))
608  return((REAL)1.60);
609  else if(!strcmp(element,"S"))
610  return((REAL)1.85);
611  else if(!strcmp(element,"O"))
612  return((REAL)1.40);
613  else if(!strcmp(element,"P"))
614  return((REAL)1.90);
615  else if(!strcmp(element,"CA"))
616  return((REAL)2.07);
617  else if(!strcmp(element,"FE"))
618  return((REAL)1.47);
619  else if(!strcmp(element,"CU"))
620  return((REAL)1.78);
621  else if(!strcmp(element,"ZN"))
622  return((REAL)1.39);
623  else if(!strcmp(element,"MG"))
624  return((REAL)1.73);
625  else
626  return((REAL)1.80);
627 }
628 
629 
630 /************************************************************************/
631 /*>static void SetPDBAccess(PDB *pdb, REAL *accessArray)
632  -----------------------------------------------------
633 *//**
634  \param *pdb PDB linked list
635  \param[in] *accessArray Accessibility information
636 
637  Puts accessibility information from the array into the PDB linked list.
638 
639 - 16.07.14 Original By: ACRM
640 */
641 static void SetPDBAccess(PDB *pdb, REAL *accessArray)
642 {
643  PDB *p;
644  int i = 0;
645 
646  for(p=pdb; p!=NULL; NEXT(p))
647  {
648  p->access = accessArray[i++];
649  }
650 }
651 
652 
653 
654 
655 /************************************************************************/
656 /*>RESACCESS *blCalcResAccess(PDB *pdb, RESRAD *resrad)
657  ----------------------------------------------
658 *//**
659  \param[in,out] *pdb PDB linked list
660  \param[in] *resrad Linked list of atom radius information
661  \return Linked list of residue accessibilities
662 
663  Calculates and populates the residue totals and relative values
664  using standards stored in resrad
665 
666 - 22.04.99 Original By: ACRM
667 - 04.08.99 Changed check on return from GetStandardAccess() to check
668  for < VERY_SMALL rather than ==0.0
669  Set relative access to -1 if the standard accessibility is
670  unknown rather than to 0.0
671 - 17.06.15 Added calculation of sidechain accessibility
672 */
674 {
675  PDB *start, *stop, *p;
676  REAL resAccess,
677  relAccess,
678  scAccess,
679  scRelAccess,
680  stdAccess,
681  stdAccessSC;
682 
683  RESACCESS *residues = NULL,
684  *r = NULL;
685 
686  for(start=pdb; start!=NULL; start=stop)
687  {
688  stop = blFindNextResidue(start);
689 
690  /* Add up accessibility for this residue */
691  resAccess = (REAL)0.0;
692  scAccess = (REAL)0.0;
693  for(p=start; p!=stop; NEXT(p))
694  {
695  resAccess += p->access;
696  if(strncmp(p->atnam, "N ", 4) &&
697  strncmp(p->atnam, "CA ", 4) &&
698  strncmp(p->atnam, "C ", 4) &&
699  strncmp(p->atnam, "O ", 4) &&
700  strncmp(p->atnam, "OXT ", 4))
701  {
702  scAccess += p->access;
703  }
704  }
705 
706  /* Get the standard accessibility for this amino acid and calculate
707  relative accessibility
708  */
709  stdAccess = GetStandardAccess(start->resnam, resrad);
710  stdAccessSC = GetStandardAccessSC(start->resnam, resrad);
711 
712  if(stdAccess<VERY_SMALL)
713  relAccess = -1.0;
714  else
715  relAccess = 100.0 * resAccess / stdAccess;
716 
717  if(stdAccessSC < VERY_SMALL)
718  scRelAccess = -1.0;
719  else
720  scRelAccess = 100.0 * scAccess / stdAccessSC;
721 
722  /* Create space to store the values */
723  if(residues == NULL)
724  {
725  INIT(residues, RESACCESS);
726  r = residues;
727  }
728  else
729  {
730  ALLOCNEXT(r, RESACCESS);
731  }
732  if(r==NULL)
733  {
734  FREELIST(residues, RESACCESS);
735  return(NULL);
736  }
737 
738  /* and store them */
739  strcpy(r->resnam, start->resnam);
740  strcpy(r->insert, start->insert);
741  strcpy(r->chain, start->chain);
742  r->resnum = start->resnum;
743  r->resAccess = resAccess;
744  r->relAccess = relAccess;
745  r->scAccess = scAccess;
746  r->scRelAccess = scRelAccess;
747  }
748 
749  return(residues);
750 }
751 
752 
753 /************************************************************************/
754 /*>static void SortArcEndpoints(REAL *endpoints, int nEndpoints,
755  int *flag)
756  -------------------------------------------------------------
757 *//**
758  \param[in,out] *endpoints Arc endpoints for sorting
759  \param[in] nEndpoints Number of endpoints
760  \param[out] *flag Flagged endpoints
761 
762  Sorts the arc endpoints
763 
764 - 21.04.99 Original By: ACRM
765 */
766 static void SortArcEndpoints(REAL *endpoints, int nEndpoints, int *flag)
767 {
768  int tmpFlagVal, midpoint,
769  il[16+1],
770  iu[16+1],
771  i, j, k, l, m;
772  REAL tmpEndpointVal, tmpEndpointVal2;
773 
774  for(i=1; i<=nEndpoints; i++)
775  flag[i]=i;
776 
777  m=1;
778  i=1;
779  j=nEndpoints;
780 
781 jump5:
782  if(i < j)
783  {
784 
785 jump10:
786  k=i;
787  midpoint=(j+i)/2;
788  tmpEndpointVal=endpoints[midpoint];
789 
790  if(endpoints[i] > tmpEndpointVal)
791  {
792  endpoints[midpoint]= endpoints[i];
793  endpoints[i]=tmpEndpointVal;
794  tmpEndpointVal=endpoints[midpoint];
795  tmpFlagVal=flag[midpoint];
796  flag[midpoint]=flag[i];
797  flag[i]=tmpFlagVal;
798  }
799 
800  l=j;
801 
802  if(endpoints[j] < tmpEndpointVal)
803  {
804  endpoints[midpoint]=endpoints[j];
805  endpoints[j]=tmpEndpointVal;
806  tmpEndpointVal=endpoints[midpoint];
807  tmpFlagVal=flag[midpoint];
808  flag[midpoint]=flag[j];
809  flag[j]=tmpFlagVal;
810 
811  if(endpoints[i] > tmpEndpointVal)
812  {
813  endpoints[midpoint]=endpoints[i];
814  endpoints[i]=tmpEndpointVal;
815  tmpEndpointVal=endpoints[midpoint];
816  tmpFlagVal=flag[midpoint];
817  flag[midpoint]=flag[i];
818  flag[i]=tmpFlagVal;
819 
820  goto exit40;
821 
822 jump30:
823  endpoints[l]=endpoints[k];
824  endpoints[k]=tmpEndpointVal2;
825  tmpFlagVal=flag[l];
826  flag[l]=flag[k];
827  flag[k]=tmpFlagVal;
828 exit40:
829  ;
830  }
831  }
832 
833  do
834  {
835  l--;
836  } while((l>0) && (endpoints[l] > tmpEndpointVal));
837  tmpEndpointVal2=endpoints[l];
838 
839  do
840  {
841  k++;
842  } while((k<=nEndpoints) && (endpoints[k] < tmpEndpointVal));
843 
844  if(k<=l) goto jump30;
845 
846  if((l-i) > (j-k))
847  {
848  il[m]=i;
849  iu[m]=l;
850  i=k;
851  m++;
852 
853  goto exit80;
854  }
855 
856  il[m]=k;
857  iu[m]=j;
858  j=l;
859  m++;
860 
861  goto exit80;
862  }
863 
864  do
865  {
866  m--;
867  if(m==0) return;
868  i=il[m];
869  j=iu[m];
870 
871 exit80:
872  if(j-i>=1) goto jump10;
873  if(i==1) goto jump5;
874 
875  i--;
876 
877 jump90:
878  i++;
879  } while(i==j);
880 
881  tmpEndpointVal=endpoints[i+1];
882  if(endpoints[i]<=tmpEndpointVal) goto jump90;
883 
884  tmpFlagVal=flag[i+1];
885  k=i;
886 
887  do
888  {
889  endpoints[k+1]=endpoints[k];
890  flag[k+1]=flag[k];
891  k--;
892  } while(tmpEndpointVal < endpoints[k]);
893 
894  endpoints[k+1]=tmpEndpointVal;
895  flag[k+1]=tmpFlagVal;
896 
897  goto jump90;
898 }
899 
900 
901 /************************************************************************/
902 /*>static BOOL doCalcAccess(int numAtoms, REAL integrationAccuracy,
903  REAL probeRadius,
904  BOOL access, REAL *atomRadii,
905  REAL *x, REAL *y, REAL *z,
906  REAL *accessResults)
907  --------------------------------------------------------------------
908 *//**
909  \param[in] numAtoms Number of atoms
910  \param[in] integrationAccuracy Integration accuracy
911  \param[in] probeRadius Radius of probe atom
912  \param[in] access Do solvent accessibility
913  rather than contact surface
914  \param[in] *atomRadii Array of atom radii
915  \param[in] *x Array of x coordinates
916  \param[in] *y Array of y coordinates
917  \param[in] *z Array of z coordinates
918  \param[out] *accessResults Array of accessibility results
919  \return Success?
920 
921  Does the real work of calculating accessibility
922 
923 - 21.04.99 Original By: ACRM
924 - 08.06.99 Fixed allocation of second dimension of atomsInCube[][]
925  to njidim rather than numAtoms
926 */
927 static BOOL doCalcAccess(int numAtoms, REAL integrationAccuracy,
928  REAL probeRadius,
929  BOOL access, REAL *atomRadii,
930  REAL *x, REAL *y, REAL *z,
931  REAL *accessResults)
932 {
933  int *cube = NULL,
934  *neighbours = NULL,
935  *flag = NULL,
936  *atomTable = NULL,
937  **atomsInCube = NULL;
938  REAL *radii = NULL, *radiiSquared=NULL,
939  *arci = NULL, *arcf=NULL,
940  *deltaX = NULL, *deltaY=NULL,
941  *dist = NULL, *distSquared=NULL;
942 
943  int i, j, k, l, m, n,
944  jj, kk,
945  cubeAtom, io, keyAtom,
946  cubeIndex,
947  nzp, karc, idim, jidim, kjidim,
948  mkji, nm,
949  maxIntersect = MAX_INTERSECT,
950  maxAtomInCube = MAX_ATOM_IN_CUBE;
951  REAL xmin = 999999.0,
952  ymin = 999999.0,
953  zmin = 999999.0,
954  xmax = -999999.0,
955  ymax = -999999.0,
956  zmax = -999999.0,
957  pi = acos(-1.0),
958  twoPi = 2.0*acos(-1.0),
959  maxRadius, totalArea, tmpArea,
960  intersect,
961  xr, yr, zr,
962  radius, radiusX2, radiusSquared,
963  zres, zgrid,
964  t, tf, ti, tt,
965  partialArea,
966  rsec2r, rsecr,
967  rsec2n, rsecn,
968  alpha, beta,
969  arcsum;
970  BOOL SkipAccess = FALSE;
971 
972 #ifdef DEBUG
973  int maxAtomsSeenInCube = 0,
974  maxIntersectsSeen = 0;
975 #endif
976 
977  /* Reset arrays to count from 1 instead of 0 */
978  atomRadii--;
979  x--; y--; z--;
980  accessResults--;
981 
982  /* Allocate memory for arrays based on number of atoms */
983  cube = (int *)malloc((numAtoms+1)*sizeof(int));
984  radii = (REAL *)malloc((numAtoms+1)*sizeof(REAL));
985  radiiSquared = (REAL *)malloc((numAtoms+1)*sizeof(REAL));
986 
987  /* Allocate memory for arrays based on number of intersects */
988  neighbours = (int *)malloc((MAX_INTERSECT+1)*sizeof(int));
989  flag = (int *)malloc((MAX_INTERSECT+1)*sizeof(int));
990  arci = (REAL *)malloc((MAX_INTERSECT+1)*sizeof(REAL));
991  arcf = (REAL *)malloc((MAX_INTERSECT+1)*sizeof(REAL));
992  deltaX = (REAL *)malloc((MAX_INTERSECT+1)*sizeof(REAL));
993  deltaY = (REAL *)malloc((MAX_INTERSECT+1)*sizeof(REAL));
994  dist = (REAL *)malloc((MAX_INTERSECT+1)*sizeof(REAL));
995  distSquared = (REAL *)malloc((MAX_INTERSECT+1)*sizeof(REAL));
996 
997  /* Check allocations */
998  if(cube == NULL ||
999  radii == NULL ||
1000  radiiSquared == NULL ||
1001  neighbours == NULL ||
1002  flag == NULL ||
1003  arci == NULL ||
1004  arcf == NULL ||
1005  deltaX == NULL ||
1006  deltaY == NULL ||
1007  dist == NULL ||
1008  distSquared == NULL)
1009  {
1011  return(FALSE);
1012  }
1013 
1014  /* Find the limits of the surrounding box */
1015  maxRadius = 0.0;
1016  for(i=1; i<=numAtoms; i++)
1017  {
1018  radii[i] = atomRadii[i] + probeRadius;
1019  radiiSquared[i] = radii[i] * radii[i];
1020  accessResults[i] = 0.0;
1021 
1022  if(radii[i] > maxRadius) maxRadius=radii[i];
1023  if(x[i] < xmin) xmin=x[i];
1024  if(y[i] < ymin) ymin=y[i];
1025  if(z[i] < zmin) zmin=z[i];
1026  if(x[i] > xmax) xmax=x[i];
1027  if(y[i] > ymax) ymax=y[i];
1028  if(z[i] > zmax) zmax=z[i];
1029  }
1030  maxRadius *= 2.0;
1031 
1032  /* Set up cubes containing the atoms. The dimension of a cube edge is
1033  equal to the radius of the largest atom sphere.
1034  */
1035  idim = (xmax-xmin)/maxRadius + 1.0;
1036  if(idim < 3) idim = 3;
1037 
1038  jidim = (ymax-ymin)/maxRadius + 1.0;
1039  if(jidim < 3) jidim = 3;
1040  jidim *= idim;
1041 
1042  kjidim = (zmax-zmin)/maxRadius + 1.0;
1043  if(kjidim < 3) kjidim = 3;
1044  kjidim *= jidim;
1045 
1046 #ifdef DEBUG
1047  fprintf(stderr,"Number of cubes: %d\n", kjidim);
1048 #endif
1049 
1050  /* Allocate memory for atomsInCube 2D array
1051  08.06.99 Corrected to inner dimension being kjidim rather than
1052  numAtom
1053  */
1054  if((atomsInCube = (int **)malloc((MAX_ATOM_IN_CUBE+1)*sizeof(int *)))
1055  ==NULL)
1056  {
1058  return(FALSE);
1059  }
1060 
1061  for(i=0; i<=MAX_ATOM_IN_CUBE; i++)
1062  {
1063  if((atomsInCube[i] = (int *)malloc((kjidim+1)*sizeof(int)))==NULL)
1064  {
1066  return(FALSE);
1067  }
1068  }
1069 
1070  /* Prepare the cubes
1071  -----------------
1072  Allocate memory for the cubes. Each cube may contain upto
1073  MAX_ATOM_IN_CUBE atoms. We count through the cubes with cubeIndex
1074  and store the atom indices in the atomTable[] array.
1075  */
1076  if((atomTable = (int *)malloc((kjidim+1)*sizeof(int)))==NULL)
1077  {
1079  return(FALSE);
1080  }
1081  for(l=1; l<=kjidim; l++)
1082  atomTable[l]=0;
1083 
1084  for(l=1; l<=numAtoms; l++)
1085  {
1086  i = (x[l]-xmin)/maxRadius + 1.0;
1087  j = (y[l]-ymin)/maxRadius;
1088  k = (z[l]-zmin)/maxRadius;
1089 
1090  cubeIndex = k*jidim + j*idim + i;
1091  n = atomTable[cubeIndex] + 1;
1092 
1093 #ifdef DEBUG
1094  if(n > maxAtomsSeenInCube)
1095  maxAtomsSeenInCube = n;
1096 #endif
1097 
1098  /* If we have too many atoms in the cube, expand the atomsInCube
1099  array
1100  */
1101  if(n > maxAtomInCube)
1102  {
1103  int newMaxAtomInCube = maxAtomInCube + MAX_ATOM_IN_CUBE,
1104  iexpand;
1105 
1106  if((atomsInCube = (int **)realloc(atomsInCube,
1107  (newMaxAtomInCube+1)*sizeof(int *)))
1108  ==NULL)
1109  {
1111  return(FALSE);
1112  }
1113 
1114  for(iexpand=maxAtomInCube+1;
1115  iexpand<=newMaxAtomInCube;
1116  iexpand++)
1117  {
1118  /* 08.06.99 Corrected numAtoms to kjidim */
1119  if((atomsInCube[iexpand] =
1120  (int *)malloc((kjidim+1) * sizeof(int)))
1121  ==NULL)
1122  {
1124  return(FALSE);
1125  }
1126  }
1127 
1128  maxAtomInCube = newMaxAtomInCube;
1129  }
1130 
1131  atomTable[cubeIndex] = n;
1132  atomsInCube[n][cubeIndex] = l;
1133  cube[l] = cubeIndex;
1134  }
1135 
1136 #ifdef DEBUG
1137  fprintf(stderr,"Max number of atoms in a cube: %d\n",
1138  maxAtomsSeenInCube);
1139 #endif
1140 
1141 
1142  /* Perform the actual accessibility calculations
1143  ---------------------------------------------
1144  We cycle through each atom in turn
1145  */
1146  for(keyAtom=1; keyAtom<=numAtoms; keyAtom++)
1147  {
1148  cubeIndex = cube[keyAtom];
1149  io = 0;
1150  totalArea = 0.0;
1151  xr = x[keyAtom];
1152  yr = y[keyAtom];
1153  zr = z[keyAtom];
1154  radius = radii[keyAtom];
1155  radiusX2 = radius*2.0;
1156  radiusSquared = radiiSquared[keyAtom];
1157 
1158  /* Find the 'mkji' cubes neighboring the cubeIndex cube */
1159  for(kk=1; kk<=3; kk++)
1160  {
1161  k=kk-2;
1162 
1163  for(jj=1; jj<=3; jj++)
1164  {
1165  j=jj-2;
1166 
1167  for(i=1; i<=3; i++)
1168  {
1169  mkji = cubeIndex + k*jidim + j*idim + i - 2;
1170  if(mkji >= 1)
1171  {
1172  if(mkji > kjidim)
1173  {
1174  jj=5; /* Force exit from for(jj) loop */
1175  kk=5; /* Force exit from for(kk) loop */
1176  break; /* out of for(i) loop */
1177  }
1178 
1179  nm = atomTable[mkji];
1180 
1181  if(nm >= 1)
1182  {
1183  /* Create neighbours[] which is a list of the atoms
1184  which are neighbours of atom keyAtom
1185  */
1186  for(m=1; m<=nm; m++)
1187  {
1188  cubeAtom = atomsInCube[m][mkji];
1189  if(cubeAtom != keyAtom)
1190  {
1191  io++;
1192 #ifdef DEBUG
1193  if(io > maxIntersectsSeen)
1194  maxIntersectsSeen = io;
1195 #endif
1196  if(io > maxIntersect)
1197  {
1199  }
1200 
1201  deltaX[io] = xr - x[cubeAtom];
1202  deltaY[io] = yr - y[cubeAtom];
1203 
1204  distSquared[io] = deltaX[io]*deltaX[io] +
1205  deltaY[io]*deltaY[io];
1206  dist[io] = sqrt(distSquared[io]);
1207  neighbours[io] = cubeAtom;
1208  }
1209  }
1210  }
1211  }
1212  }
1213  }
1214  }
1215 
1216  if(io == 0)
1217  {
1218  totalArea = twoPi * radiusX2;
1219  }
1220  else
1221  {
1222  /* Calculate the z resolution */
1223  nzp = 1.0/integrationAccuracy + 0.5;
1224  zres = radiusX2 / nzp;
1225  zgrid = z[keyAtom] - radius - zres/2.0;
1226 
1227  /* Take a section of atom spheres which is perpendicular to the
1228  z axis
1229  */
1230  for(i=1; i<=nzp; i++)
1231  {
1232  zgrid += zres;
1233 
1234  /* Calculate the radius of the circle of intersection of the
1235  keyAtom sphere on the current z-plane
1236  */
1237  rsec2r = radiusSquared - (zgrid-zr)*(zgrid-zr);
1238  rsecr = sqrt(rsec2r);
1239 
1240  for(k=1; k<=maxIntersect; k++)
1241  arci[k] = 0.0;
1242 
1243  karc=0;
1244 
1245  for(j=1; j<=io; j++)
1246  {
1247  cubeAtom = neighbours[j];
1248 
1249  /* Find the radius of the circle locus */
1250  rsec2n = radiiSquared[cubeAtom] -
1251  (zgrid-z[cubeAtom])*(zgrid-z[cubeAtom]);
1252 
1253  if(rsec2n > 0.0)
1254  {
1255  rsecn = sqrt(rsec2n);
1256 
1257  /* Find the intersections of the n circles with the
1258  keyAtom circles in this section
1259  */
1260  if(dist[j] < (rsecr+rsecn))
1261  {
1262  /* Test whether the the circles intersect, or
1263  whether one circle is completely inside the
1264  other in which case we don't calculate the
1265  accessibility!
1266  */
1267  intersect = rsecr - rsecn;
1268 
1269  SkipAccess = FALSE;
1270  if(dist[j] <= fabs(intersect))
1271  {
1272  if(intersect <= 0.0)
1273  {
1274  SkipAccess = TRUE;
1275  break; /* out of the j loop */
1276  }
1277  continue; /* the j loop */
1278  }
1279 
1280  /* Expand the intersect arrays if we have too many */
1281  if(++karc >= maxIntersect)
1282  {
1284  }
1285 #ifdef DEBUG
1286  if(karc > maxIntersectsSeen)
1287  maxIntersectsSeen = karc;
1288 #endif
1289 
1290  /* If the circles do intersect, then we find the
1291  points of intersection.
1292 
1293  The initial and final arc endpoints are found
1294  for the keyAtom circle intersected by a
1295  neighboring circle contained in the same plane.
1296  The initial endpoint of the enclosed arc is stored
1297  in arci, and the final arc in arcf. This uses
1298  the cosine law.
1299 
1300  Calculate alpha which is the angle between a
1301  line containing a point of intersection, the
1302  reference circle center and the line
1303  containing both circle centers.
1304  */
1305  alpha = acos((distSquared[j] + rsec2r - rsec2n) /
1306  (2.0 * dist[j] * rsecr));
1307 
1308  /* Calculate beta which is the angle between the
1309  line containing both circle centers and the
1310  x-axis
1311  */
1312  beta = atan2(deltaY[j], deltaX[j]) + pi;
1313 
1314  ti = beta - alpha;
1315  tf = beta + alpha;
1316  if(ti < 0.0)
1317  ti += twoPi;
1318 
1319  if(tf > twoPi)
1320  tf -= twoPi;
1321 
1322  arci[karc] = ti;
1323 
1324  /* If the arc crosses zero, then it is broken
1325  into two segments. The first ends at twoPi and
1326  the second begins at zero
1327  */
1328  if(tf < ti)
1329  {
1330  arcf[karc] = twoPi;
1331  karc++;
1332  }
1333 
1334  arcf[karc] = tf;
1335  }
1336  }
1337  }
1338 
1339  if(SkipAccess)
1340  {
1341  /* Accessibility skipped because circle was within another
1342  one
1343  */
1344  SkipAccess = FALSE;
1345  }
1346  else
1347  {
1348  /* Find the accessible contact surface area for the
1349  sphere keyAtom on this section
1350  */
1351  if(karc == 0)
1352  {
1353  arcsum = twoPi;
1354  }
1355  else
1356  {
1357  /* Sort the arc endpoints on the value of the
1358  initial arc endpoint
1359  */
1360  SortArcEndpoints(arci, karc, flag);
1361 
1362  /* Calculate the length of the accessible arc */
1363  arcsum = arci[1];
1364  t = arcf[flag[1]];
1365 
1366  if(karc != 1)
1367  {
1368  for(k=2; k<=karc; k++)
1369  {
1370  if(t < arci[k])
1371  {
1372  arcsum += (arci[k]-t);
1373  }
1374 
1375  tt = arcf[flag[k]];
1376  if(tt > t)
1377  {
1378  t = tt;
1379  }
1380  }
1381  }
1382 
1383  arcsum += (twoPi-t);
1384  }
1385 
1386  /* Calculate the partial accessible area for this atom
1387  on this section. The area/radius is equal to the
1388  accessible arc length x the section thickness.
1389  */
1390  partialArea = arcsum * zres;
1391 
1392  /* ...and add this to the total area for this atom */
1393  totalArea += partialArea;
1394  }
1395  }
1396  }
1397 
1398  /* Scale the area to Van der Waals shell */
1399  tmpArea = totalArea * (radius-probeRadius) * (radius-probeRadius) /
1400  radius;
1401 
1402  /* Convert from the contact area to the accessible surface area
1403  if required
1404  */
1405  if(access)
1406  {
1407  tmpArea *= (radius*radius) /
1408  ((radius-probeRadius) * (radius-probeRadius));
1409  }
1410 
1411  accessResults[keyAtom] = tmpArea;
1412  }
1413 
1414 #ifdef DEBUG
1415  fprintf(stderr,"Maximum intersects: %d\n",maxIntersectsSeen);
1416 #endif
1417 
1419 
1420  return(TRUE);
1421 }
1422 
#define ALLOCNEXT(x, y)
Definition: macros.h:251
Definition: access.h:65
Include file for PDB routines.
#define VERY_SMALL
Definition: access.h:61
int resnum
Definition: pdb.h:310
short BOOL
Definition: SysDefs.h:64
#define NULL
Definition: array2.c:99
BOOL blCalcAccess(PDB *pdb, int natoms, REAL integrationAccuracy, REAL probeRadius, BOOL doAccessibility)
Definition: access.c:331
char resnam[8]
Definition: access.h:72
Definition: pdb.h:298
#define MAXBUFF
Definition: access.c:107
#define FALSE
Definition: macros.h:223
#define NEXT(x)
Definition: macros.h:249
#define ACCESS_DEF_INTACC
Definition: access.h:58
BOOL flag
Definition: aalist.h:74
#define EXPAND_INTERSECT_ARRAYS
Definition: access.c:139
#define MAX_ATOM_IN_CUBE
Definition: access.c:112
Useful macros.
char atnam[8]
Definition: pdb.h:316
RESACCESS * blCalcResAccess(PDB *pdb, RESRAD *resrad)
Definition: access.c:673
REAL stdAccessSC
Definition: access.h:68
char resnam[8]
Definition: pdb.h:319
REAL ymin
Definition: plotting.c:146
double REAL
Definition: MathType.h:67
#define FREE_ACCESS_STORAGE
Definition: access.c:115
REAL z
Definition: pdb.h:300
REAL radius
Definition: pdb.h:300
REAL xmin
Definition: plotting.c:146
#define TRUE
Definition: macros.h:219
#define DEDOTIFY(str)
Definition: macros.h:512
REAL access
Definition: pdb.h:300
char atnam_raw[8]
Definition: pdb.h:317
REAL radius[ACCESS_MAX_ATOMS_PER_RESIDUE]
Definition: access.h:68
#define KILLLEADSPACES(y, x)
Definition: macros.h:408
#define FREELIST(y, z)
Definition: macros.h:264
#define INIT(x, y)
Definition: macros.h:244
System-type variable type definitions.
PDB * blFindNextResidue(PDB *pdb)
REAL stdAccess
Definition: access.h:68
int natoms
Definition: access.h:71
char chain[blMAXCHAINLABEL]
Definition: pdb.h:321
char atnam[ACCESS_MAX_ATOMS_PER_RESIDUE][8]
Definition: access.h:72
Accessibility calculation code.
REAL x
Definition: pdb.h:300
REAL y
Definition: pdb.h:300
#define MAX_INTERSECT
Definition: access.c:108
char insert[8]
Definition: pdb.h:320
RESRAD * blSetAtomRadii(PDB *pdb, FILE *fpRad)
Definition: access.c:259