Bioplib
Protein Structure C Library
 All Data Structures Files Functions Variables Typedefs Macros Pages
WritePDB.c
Go to the documentation of this file.
1 /************************************************************************/
2 /**
3 
4  \file WritePDB.c
5 
6  \version V1.29
7  \date 29.07.15
8  \brief Write a PDB file from a linked list
9 
10  \copyright (c) UCL / Dr. Andrew C. R. Martin 1993-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  This routine will write a .PDB file of any size from a linked list of
40  the protein structure. This list is contained in a linked set of
41  structures of type pdb_entry. The structure is set up by including the
42  file "pdb.h". For details of the structure, see this file.
43 
44 **************************************************************************
45 
46  Usage:
47  ======
48 
49 \code
50  blWritePDB(fp, pdb)
51 \endcode
52 
53  \param[in] *fp A pointer to the file to write
54  \param[in] *pdb The start of the PDB linked list.
55 
56 **************************************************************************
57 
58  Revision History:
59  =================
60 - V1.0 08.03.89 Original
61 - V1.2 28.03.90 Modified to match the correct column definition of
62  ReadPDB V1.2 (N.B. There was no V1.1)
63 - V1.3 01.06.92 Corrected header, to match standard. Autodoc'd,
64  ANSIed. Added FPU check.
65 - V1.4 10.06.93 Changed to use NEXT() macro. void types
66 - V1.5 22.02.94 Added TER card at end of file
67 - V1.6 15.02.01 Writes using atnam_raw so atom name is unchanged from
68  input
69 - V1.7 30.05.02 Changed PDB field from 'junk' to 'record_type'
70 - V1.8 03.06.05 'atnam_raw' no longer includes the alternate indicator
71  which is now in 'altpos'
72 - V1.9 22.09.06 Added WritePDBRecordAtnam()
73 - V1.10 04.02.14 Use CHAINMATCH macro. By: CTP
74 - V1.11 01.06.14 Added WritePDBML() By: CTP
75 - V1.12 21.06.14 Added blWritePDB(), blFormatCheckWritePDB() and
76  blWriteAsPDB(). Renamed WritePDBML() to blWriteAsPDBML()
77  and deprecated WritePDB(). Defined WRITEPDB_MAIN.
78  By: CTP
79 - V1.13 07.07.14 Renamed functions to use bl prefix. Moved WritePDB() to
80  deprecated.h By: CTP
81 - V1.14 17.07.14 Added blSetElementSymbolFromAtomName() By: CTP
82 - V1.15 16.08.14 Added writing element and charge. By: CTP
83 - V1.16 18.08.14 Added XML_SUPPORT option allowing compilation without
84  support for PDBML format. By: CTP
85 - V1.17 17.02.15 Handles segid and the element and formal charge in
86  blWritePDBRecordAtnam() By: ACRM
87 - V1.18 23.02.15 Modified blWriteAsPDB() to do proper TER cards - now
88  returns an int - the number of TER cards written
89 - V1.19 24.02.15 Renamed blWriteAsPDB() to blWritePDBAsPDBorGromos()
90  and integrated Gromos support into this routine.
91  Now takes a new BOOL flag
92 - V1.20 25.02.15 blWritePDBAsPDBML() now returns BOOL and checks all
93  memory allocations
94 - V1.21 02.03.15 Corrected counting of ORIGX, SCALE and MTRIX records
95  in WriteMaster().
96  Added blWriteWholePDBHeaderNoRes()
97  Added space padding to TER in blWriteTerCard()
98  Added space padding to END and to CONECT in
99  blWriteWholePDBTrailer()
100 - V1.22 09.03.15 blWriteWholePDBHeaderNoRes() now skips more header lines
101 - V1.23 10.03.15 blWriteWholePDBHeaderNoRes() now skips more header lines
102 - V1.24 02.04.15 WriteMaster() Padded MASTER record to 80 cols. By: CTP
103 - V1.25 13.05.15 Updated blWritePDBAsPDBML() to write CONECT records,
104  Added output of COMPND and SOURCE records. By: CTP
105 - V1.26 08.06.15 Updated XML check for output format. By: CTP
106 - V1.27 21.06.15 Added blMapChainsToEntity(). blDoWritePDBAsPDBML() sets
107  entity_id based on COMPND records if entty_id not
108  already set. By: CTP
109 - V1.28 10.07.15 Added return value for blWritePDBAsPDBML() and
110  blDoWritePDBAsPDBML() when XML_SUPPORT not defined
111  By: ACRM
112 - V1.29 29.07.15 Added output of PDBML seqres records from wpdb->header.
113  Added ReadSeqresChainLabelWholePDB() and
114  ReadSeqresResidueListWholePDB(). By: CTP
115 
116 *************************************************************************/
117 /* Doxygen
118  -------
119  #GROUP Handling PDB Data
120  #SUBGROUP File IO
121 
122  #KEYFUNCTION blWritePDB()
123  Main entry point to write a PDB linked list to a file
124 
125  #KEYFUNCTION blWritePDBRecord()
126  Writes a single PDB record in PDB format
127 
128  #KEYFUNCTION blWriteWholePDB()
129  Writes a PDB file including header and trailer information.
130  Output in PDBML-format if flags set.
131 
132  #FUNCTION blWriteWholePDBHeader()
133  Writes the header of a PDB file
134 
135  #FUNCTION blWriteWholePDBHeaderNoRes()
136  Writes the header of a PDB file, but skips any records associated
137  with residue numbers
138 
139  #FUNCTION blWriteWholePDBTrailer()
140  Writes the trailer of a PDB file
141 
142  #FUNCTION blFormatCheckWritePDB()
143  Checks that a PDB linked list can be written as a standard PDB file
144  (i.e. chain labels are no more than one character)
145 
146  #FUNCTION blWritePDBAsPDBorGromos()
147  Writes a PDB linked list to a file in PDB format or the modified
148  GROMOS version
149 
150  #FUNCTION blWritePDBRecordAtnam()
151  Writes a single PDB record in PDB format using atom data from the
152  atnam field rather than the atnam_raw field
153 
154  #FUNCTION blWritePDBAsPDBML()
155  Write a PDB linked list to a file in PDBML XML format
156 
157  #FUNCTION blSetElementSymbolFromAtomName()
158  Sets the element field based on the content of the atom name stored
159  in atnam_raw
160 
161  #FUNCTION blWriteGromosPDB()
162  Write a PDB linked list by calling blWritePDBAsPDBorGromos()
163 
164  #FUNCTION blWriteGromosPDBRecord()
165  Write a GROMOS PDB record
166 
167  #FUNCTION blWriteTerCard()
168  Prints a complete new PDB format TER card
169 */
170 /************************************************************************/
171 /* Defines required for includes
172 */
173 #define WRITEPDB_MAIN
174 
175 /************************************************************************/
176 #include <stdio.h>
177 #include <string.h>
178 #include <math.h>
179 #include <stdlib.h>
180 
181 #ifdef XML_SUPPORT /* Required to read PDBML files */
182 #include <libxml/tree.h>
183 #include <ctype.h>
184 #define XMLDIE(x) do {if((x)!=NULL) { xmlFreeDoc((x)); \
185  xmlCleanupParser(); } \
186  return(FALSE);} while(FALSE)
187 #endif
188 
189 #include "MathType.h"
190 #include "pdb.h"
191 #include "macros.h"
192 #include "hash.h"
193 #include "fsscanf.h"
194 
195 /************************************************************************/
196 /* Prototypes
197 */
198 static void WriteMaster(FILE *fp, WHOLEPDB *wpdb, int numConect,
199  int numTer);
200 static BOOL blDoWritePDBAsPDBML(FILE *fp, WHOLEPDB *wpdb, BOOL doWhole);
201 static BOOL blSetPDBMLDateField(char *pdbml_date, char *pdb_date);
202 static HASHTABLE *blMapChainsToEntity(WHOLEPDB *wpdb);
203 static char **ReadSeqresChainLabelWholePDB(WHOLEPDB *wpdb, int *nchains);
204 static STRINGLIST **ReadSeqresResidueListWholePDB(WHOLEPDB *wpdb,
205  int *nchains);
206 /************************************************************************/
207 /*>int blWritePDB(FILE *fp, PDB *pdb)
208  ----------------------------------
209 *//**
210 
211  \param[in] *fp PDB file pointer to be written
212  \param[in] *pdb PDB linked list to write
213  \return int Number of TER cards written (0 indicates error)
214 
215  Write a PDB linked list...
216 
217 - 21.06.14 Original By: CTP
218 - 18.08.14 Added XML_SUPPORT option. Return error if attempting to write
219  PDBML format. By: CTP
220 - 23.02.15 Now returns an int
221 - 24.02.15 Changed to call blWritePDBAsPDBorGromos() and blWritePDBAsPDBML()
222 */
223 int blWritePDB(FILE *fp,
224  PDB *pdb)
225 {
226  int numTer;
227 
228  if((gPDBXMLForce == FORCEXML_XML) ||
230  {
231 
232 #ifdef XML_SUPPORT
233  /* Write PDBML file */
234  blWritePDBAsPDBML(fp, pdb);
235  return(1);
236 #else
237  /* PDBML not supported */
238  return FALSE;
239 #endif
240 
241  }
242  else
243  {
244  /* Check format */
245  if(blFormatCheckWritePDB(pdb) == FALSE)
246  {
247  return(0);
248  }
249 
250  /* Write whole PDB File */
251  numTer = blWritePDBAsPDBorGromos(fp, pdb, FALSE);
252  }
253 
254  return(numTer);
255 }
256 
257 
258 /************************************************************************/
259 /*>BOOL blFormatCheckWritePDB(PDB *pdb)
260  ------------------------------------
261 *//**
262 
263  \param[in] *pdb PDB linked list to write
264 
265  Checks PDB linked list is compatible with PDB-formatted text file.
266 
267 - 21.06.14 Original By: CTP
268 */
270 {
271  PDB *p;
272  for(p = pdb ; p ; NEXT(p))
273  {
274  /* Check chain id is single letter */
275  if(strlen(p->chain) > 1)
276  {
277  return FALSE;
278  }
279  }
280  return TRUE;
281 }
282 
283 
284 /************************************************************************/
285 /*>int blWritePDBAsPDBorGromos(FILE *fp, PDB *pdb, BOOL doGromos)
286  --------------------------------------------------------------
287 *//**
288 
289  \param[in] *fp PDB file pointer to be written
290  \param[in] *pdb PDB linked list to write
291  \return Number of TER cards written (0=error)
292 
293  Write a PDB linked list by calls to WritePDBRecord()
294 
295 - 08.03.89 Original
296 - 01.06.92 ANSIed and autodoc'd
297 - 10.06.93 Uses NEXT macro; void type
298 - 08.07.93 Added insertion of TER cards
299 - 22.02.94 And a TER card at the end of the file
300 - 04.02.14 Use CHAINMATCH macro. By: CTP
301 - 17.06.14 Renamed to blWriteAsPDB() By: CTP
302 - 07.07.14 Use blWritePDBRecord() By: CTP
303 - 23.02.15 Write correct format TER cards. Now returns int By: ACRM
304 - 24.02.15 Renamed to blWritePDBAsPDBorGromos() and added doGromos
305  flag
306 
307 */
308 int blWritePDBAsPDBorGromos(FILE *fp, PDB *pdb, BOOL doGromos)
309 {
310  PDB *p,
311  *prev = NULL;
312  int numTer = 0;
313  BOOL doneTer = FALSE;
314 
315  for(p=pdb; p!=NULL; NEXT(p))
316  {
317  /* If previous was non-null and was an ATOM */
318  if((prev!=NULL) && !strncmp(prev->record_type, "ATOM ", 6))
319  {
320  /* If the chain has changed write a TER card */
321  if(!doneTer && !CHAINMATCH(p->chain, prev->chain))
322  {
323  blWriteTerCard(fp, prev);
324  numTer++;
325  doneTer = TRUE;
326  }
327  /* If we've moved into a HETATM, then see if this HETATOM group
328  is bonded to the previous residue. If it isn't, print a TER
329  card
330  */
331  if(!doneTer && !strncmp(p->record_type, "HETATM", 6))
332  {
333  PDB *prevStart = blFindResidue(pdb, prev->chain, prev->resnum,
334  prev->insert);
335  if(!blAreResiduePointersBonded(prevStart, p, (REAL)0.2))
336  {
337  blWriteTerCard(fp, prev);
338  numTer++;
339  doneTer = TRUE;
340  }
341  }
342  }
343 
344  if(doGromos)
345  {
347  doneTer = FALSE;
348  }
349  else
350  {
351  blWritePDBRecord(fp,p);
352  doneTer = FALSE;
353  }
354  prev=p;
355  }
356 
357  if((!doneTer) &&
358  (prev!=NULL) &&
359  !strncmp(prev->record_type, "ATOM ", 6))
360  {
361  blWriteTerCard(fp, prev);
362  numTer++;
363  }
364  return(numTer);
365 }
366 
367 
368 /************************************************************************/
369 /*>void blWriteTerCard(FILE *fp, PDB *p)
370  -------------------------------------
371 *//**
372  \param[in] *fp File pointer
373  \param[in] *p PDB record pointer
374 
375  Prints a TER card in the new PDB format - i.e. with the residue
376  information for the previous ATOM/HETATM, rather than just printing
377  TER
378 
379 - 23.02.15 Original By: ACRM
380 - 02.03.15 Added space padding
381 */
382 void blWriteTerCard(FILE *fp, PDB *p)
383 {
384  if(p!=NULL)
385  {
386  fprintf(fp,"TER %5d %-4s%1s%4d%1s%s\n",
387  p->atnum+1, p->resnam, p->chain, p->resnum, p->insert,
388  " ");
389  }
390 }
391 
392 
393 /************************************************************************/
394 /*>void blWritePDBRecord(FILE *fp, PDB *pdb)
395  -----------------------------------------
396 *//**
397 
398  \param[in] *fp PDB file pointer to be written
399  \param[in] *pdb PDB linked list record to write
400 
401  Write a PDB record
402 
403 - 08.03.89 Original
404 - 28.03.90 Changed to match ReadPDB() V1.2 for column widths
405 - 01.06.92 ANSIed and autodoc'd
406 - 10.06.93 void type
407 - 22.06.93 Changed to %lf. Ljust strings
408 - 11.03.94 %lf back to %f (!)
409 - 15.02.01 Modified to use atnam_raw
410 - 03.06.05 Modified to use altpos
411 - 07.07.14 Renamed to blWritePDBRecord() By: CTP
412 - 16.08.14 Write element and formal charge. By: CTP
413 - 17.02.15 Added segid support By: ACRM
414 */
415 void blWritePDBRecord(FILE *fp,
416  PDB *pdb)
417 {
418  char charge = ' ',
419  sign = ' ';
420 
421  if(pdb->formal_charge && ABS(pdb->formal_charge <= 8))
422  {
423  charge = (char)('0' + ABS(pdb->formal_charge));
424  sign = pdb->formal_charge > 0 ? '+':'-';
425  }
426 
427  fprintf(fp,"%-6s%5d %-4s%c%-4s%1s%4d%1s %8.3f%8.3f%8.3f%6.2f%6.2f %4s%2s%c%c\n",
428  pdb->record_type,
429  pdb->atnum,
430  pdb->atnam_raw,
431  pdb->altpos,
432  pdb->resnam,
433  pdb->chain,
434  pdb->resnum,
435  pdb->insert,
436  pdb->x,
437  pdb->y,
438  pdb->z,
439  pdb->occ,
440  pdb->bval,
441  pdb->segid,
442  pdb->element,
443  charge,
444  sign);
445 }
446 
447 
448 /************************************************************************/
449 /*>void blWritePDBRecordAtnam(FILE *fp, PDB *pdb)
450  ----------------------------------------------
451 *//**
452 
453  \param[in] *fp PDB file pointer to be written
454  \param[in] *pdb PDB linked list record to write
455 
456  Write a PDB record using the data in atnam rather than atnam_raw
457 
458 - 08.03.89 Original
459 - 28.03.90 Changed to match ReadPDB() V1.2 for column widths
460 - 01.06.92 ANSIed and autodoc'd
461 - 10.06.93 void type
462 - 22.06.93 Changed to %lf. Ljust strings
463 - 11.03.94 %lf back to %f (!)
464 - 15.02.01 Modified to use atnam_raw
465 - 03.06.05 Modified to use altpos
466 - 22.09.05 This is like the old version which used atnam rather
467  than atnam_raw
468 - 07.07.14 Renamed to blWritePDBRecordAtnam() By: CTP
469 - 17.02.15 Added element, formalcharge and segid support By: ACRM
470 */
471 void blWritePDBRecordAtnam(FILE *fp,
472  PDB *pdb)
473 {
474  char charge = ' ',
475  sign = ' ';
476 
477  if(pdb->formal_charge && ABS(pdb->formal_charge <= 8))
478  {
479  charge = (char)('0' + ABS(pdb->formal_charge));
480  sign = pdb->formal_charge > 0 ? '+':'-';
481  }
482 
483  fprintf(fp,"%-6s%5d %-4s%-4s%1s%4d%1s %8.3f%8.3f%8.3f%6.2f%6.2f %4s%2s%c%c\n",
484  pdb->record_type,
485  pdb->atnum,
486  pdb->atnam,
487  pdb->resnam,
488  pdb->chain,
489  pdb->resnum,
490  pdb->insert,
491  pdb->x,
492  pdb->y,
493  pdb->z,
494  pdb->occ,
495  pdb->bval,
496  pdb->segid,
497  pdb->element,
498  charge,
499  sign);
500 }
501 
502 /************************************************************************/
503 /*>BOOL blWritePDBAsPDBML(FILE *fp, PDB *pdb)
504  ------------------------------------------
505 *//**
506 
507  \param[in] *fp PDB file pointer to be written
508  \param[in] *pdb PDB linked list to write
509  \return Success
510 
511  Write a PDB linked list in PDBML format.
512 
513 - 02.06.14 Original. By: CTP
514 - 21.06.14 Renamed blWriteAsPDBML() and updated symbol handling. By: CTP
515 - 17.07.14 Use blSetElementSymbolFromAtomName() By: CTP
516 - 16.08.14 Use element and charge data. By: CTP
517 - 17.02.15 Added segid support By: ACRM
518 - 24.02.15 Changed name to blWritePDBAsPDBML()
519 - 25.02.15 Changed to type BOOL and checks all memory allocations
520 - 29.04.15 Updated to write CONECT records. By: CTP
521 - 11.05.15 Made function into wrapper for blDoWritePDBAsPDBML(). By: CTP
522 - 10.07.15 Added return value for no XML_SUPPORT By: ACRM
523 
524 */
525 BOOL blWritePDBAsPDBML(FILE *fp, PDB *pdb)
526 {
527 #ifndef XML_SUPPORT
528 
529  /* PDBML format not supported. */
530  return(FALSE); /* 10.07.15 */
531 
532 #else
533 
534  /* PDBML format supported. */
535  WHOLEPDB wpdb;
536  wpdb.header = NULL;
537  wpdb.trailer = NULL;
538  wpdb.natoms = 0;
539  wpdb.pdb = pdb;
540  return(blDoWritePDBAsPDBML(fp, &wpdb, FALSE));
541 
542 #endif
543 }
544 
545 /************************************************************************/
546 /*>BOOL blDoWritePDBAsPDBML(FILE *fp, WHOLEPDB *wpdb, BOOL doWhole)
547  -----------------------------------------------------------------
548 *//**
549 
550  \param[in] *fp PDB file pointer to be written
551  \param[in] *wpdb WHOLEPDB to write
552  \param[in] doWhole Write whole pdb including header and conect
553  records or just coordinate records.
554  \return Success
555 
556  Write a PDB linked list in PDBML format.
557 
558 - 02.06.14 Original. By: CTP
559 - 21.06.14 Renamed blWriteAsPDBML() and updated symbol handling. By: CTP
560 - 17.07.14 Use blSetElementSymbolFromAtomName() By: CTP
561 - 16.08.14 Use element and charge data. By: CTP
562 - 17.02.15 Added segid support By: ACRM
563 - 24.02.15 Changed name to blWritePDBAsPDBML()
564 - 25.02.15 Changed to type BOOL and checks all memory allocations
565 - 29.04.15 Updated to write CONECT records. By: CTP
566 - 11.05.15 Renamed from blWritePDBAsPDBML() to blDoWritePDBAsPDBML().
567  Changed to a static function.
568  blWritePDBAsPDBML() is now a wrapper for this function.
569  This function takes WHOLEPDB as input instead of PDB and
570  writes wpdb->header and wpdb->trailer info if doWhole param is
571  TRUE. By: CTP
572 - 21.06.15 Write entity_id. Use COMPND record to set entity_id if not set
573  in PDB. Set compound type to polymer. By: CTP
574 - 10.07.15 Added return value for no XML_SUPPORT By: ACRM
575 - 29.07.15 Added output of SEQRES records from wpdb->header. By: CTP
576 */
577 static BOOL blDoWritePDBAsPDBML(FILE *fp, WHOLEPDB *wpdb, BOOL doWhole)
578 {
579 #ifndef XML_SUPPORT
580 
581  /* PDBML format not supported. */
582  return(FALSE); /* 10.07.15 */
583 
584 #else
585 
586  /* PDBML format supported */
587  PDB *p,
588  *q;
589  xmlDocPtr doc = NULL;
590  xmlNodePtr root_node = NULL,
591  sites_node = NULL,
592  atom_node = NULL,
593  node = NULL;
594  xmlNsPtr pdbx = NULL,
595  xsi = NULL;
596  char buffer[16],
597  *buffer_ptr;
598  int conect_id = 0,
599  i, j;
600 
601  char header[82] = "",
602  date[82] = "",
603  pdbcode[82] = "",
604  pdbml_date[11] = "",
605  *title = NULL;
606 
607  COMPND compound;
608  PDBSOURCE species;
609  int molid = 0;
610  HASHTABLE *chain_to_entity = NULL;
611  int seqres_nchains = 0;
612  char **seqres_chain = NULL;
613  STRINGLIST **seqres_residues = NULL,
614  *s = NULL;
615 
616  /* Create document */
617  if((doc = xmlNewDoc((xmlChar *)"1.0"))==NULL)
618  XMLDIE(doc); /* 25.02.15 */
619  if((doc->encoding = xmlStrdup((xmlChar *) "UTF-8"))==NULL)
620  XMLDIE(doc); /* 25.02.15 */
621 
622  /* Root node */
623  if((root_node=xmlNewNode(NULL, (xmlChar *)"datablock"))==NULL)
624  XMLDIE(doc); /* 25.02.15 */
625  xmlDocSetRootElement(doc, root_node);
626  if((pdbx=xmlNewNs(root_node, (xmlChar *)"null",
627  (xmlChar *)"PDBx"))==NULL)
628  XMLDIE(doc); /* 25.02.15 */
629  if((xsi =xmlNewNs(root_node, (xmlChar *)"null",
630  (xmlChar *)"xsi"))==NULL)
631  XMLDIE(doc); /* 25.02.15 */
632  xmlSetNs(root_node,pdbx);
633 
634  /* Write Coordinate Data */
635 
636  /* map chain to entity from compnd records */
637  chain_to_entity = blMapChainsToEntity(wpdb);
638 
639  /* Atom_sites node */
640  if((sites_node = xmlNewChild(root_node, NULL,
641  (xmlChar *)"atom_siteCategory",
642  NULL))==NULL)
643  XMLDIE(doc); /* 25.02.15 */
644 
645 
646  /* Atom nodes */
647  for(p=wpdb->pdb; p!=NULL; NEXT(p))
648  {
649  /* skip TER */
650  if(!strncmp("TER",p->resnam,3))
651  {
652  continue;
653  }
654 
655  /* Add atom node */
656  if((atom_node = xmlNewChild(sites_node, NULL,
657  (xmlChar *)"atom_site", NULL))==NULL)
658  XMLDIE(doc); /* 25.02.15 */
659 
660  sprintf(buffer, "%d", p->atnum);
661  xmlNewProp(atom_node, (xmlChar *)"id", (xmlChar *)buffer);
662 
663  /*** Add atom data nodes ***/
664 
665  /* B value */
666  sprintf(buffer,"%.2f", p->bval);
667  if((node = xmlNewChild(atom_node, NULL,
668  (xmlChar *)"B_iso_or_equiv",
669  (xmlChar *)buffer))==NULL)
670  XMLDIE(doc); /* 25.02.15 */
671 
672  /* coordinates */
673  sprintf(buffer,"%.3f", p->x);
674  if((node = xmlNewChild(atom_node, NULL, (xmlChar *)"Cartn_x",
675  (xmlChar *)buffer))==NULL)
676  XMLDIE(doc); /* 25.02.15 */
677 
678  sprintf(buffer,"%.3f", p->y);
679  if((node = xmlNewChild(atom_node, NULL, (xmlChar *)"Cartn_y",
680  (xmlChar *)buffer))==NULL)
681  XMLDIE(doc); /* 25.02.15 */
682 
683 
684  sprintf(buffer,"%.3f", p->z);
685  if((node = xmlNewChild(atom_node, NULL, (xmlChar *)"Cartn_z",
686  (xmlChar *)buffer))==NULL)
687  XMLDIE(doc); /* 25.02.15 */
688 
689  /* author atom site labels */
690  if((node = xmlNewChild(atom_node, NULL, (xmlChar *)"auth_asym_id",
691  (xmlChar *)p->chain))==NULL)
692  XMLDIE(doc); /* 25.02.15 */
693 
694 
695  strcpy(buffer,p->atnam);
696  KILLTRAILSPACES(buffer);
697  if((node = xmlNewChild(atom_node, NULL, (xmlChar *)"auth_atom_id",
698  (xmlChar *)buffer))==NULL)
699  XMLDIE(doc); /* 25.02.15 */
700 
701  strcpy(buffer,p->resnam);
702  KILLTRAILSPACES(buffer);
703  KILLLEADSPACES(buffer_ptr,buffer);
704  if((node = xmlNewChild(atom_node, NULL, (xmlChar *)"auth_comp_id",
705  (xmlChar *)buffer_ptr))==NULL)
706  XMLDIE(doc); /* 25.02.15 */
707 
708 
709  sprintf(buffer,"%d", p->resnum);
710  if((node = xmlNewChild(atom_node, NULL, (xmlChar *)"auth_seq_id",
711  (xmlChar *)buffer))==NULL)
712  XMLDIE(doc); /* 25.02.15 */
713 
714 
715  /* record type atom/hetatm */
716  strcpy(buffer,p->record_type);
717  KILLTRAILSPACES(buffer);
718  if((node = xmlNewChild(atom_node, NULL, (xmlChar *)"group_PDB",
719  (xmlChar *)buffer))==NULL)
720  XMLDIE(doc); /* 25.02.15 */
721 
722 
723  /* atom site labels */
724  if((node = xmlNewChild(atom_node, NULL, (xmlChar *)"label_alt_id",
725  NULL))==NULL)
726  XMLDIE(doc); /* 25.02.15 */
727 
728  if(p->altpos == ' ')
729  {
730  xmlNewNsProp(node, xsi, (xmlChar *)"nil", (xmlChar *)"true");
731  }
732  else
733  {
734  buffer[0] = p->altpos;
735  buffer[1] = '\0';
736  xmlNodeSetContent(node, (xmlChar *)buffer);
737  }
738 
739  if((node = xmlNewChild(atom_node, NULL,
740  (xmlChar *)"label_asym_id",
741  (xmlChar *)p->chain))==NULL)
742  XMLDIE(doc); /* 25.02.15 */
743 
744  strcpy(buffer,p->atnam);
745  KILLTRAILSPACES(buffer);
746  if((node = xmlNewChild(atom_node, NULL,
747  (xmlChar *)"label_atom_id",
748  (xmlChar *)buffer))==NULL)
749  XMLDIE(doc); /* 25.02.15 */
750 
751  strcpy(buffer,p->resnam);
752  KILLTRAILSPACES(buffer);
753  KILLLEADSPACES(buffer_ptr,buffer);
754  if((node = xmlNewChild(atom_node, NULL,
755  (xmlChar *)"label_comp_id",
756  (xmlChar *)buffer_ptr))==NULL)
757  XMLDIE(doc); /* 25.02.15 */
758 
759  /* Note: Entity ID is not set for PDB format.
760  If entity_id is not set in PDB list then set from COMPND
761  or default to 1.
762  */
763  if(p->entity_id)
764  {
765  /* set from PDB list */
766  sprintf(buffer,"%d", p->entity_id);
767  }
768  else if(chain_to_entity != NULL &&
769  blHashKeyDefined(chain_to_entity, p->chain))
770  {
771  /* set from COMPND record */
772  sprintf(buffer,"%d",
773  blGetHashValueInt(chain_to_entity, p->chain));
774  }
775  else
776  {
777  /* default */
778  strcpy(buffer,"1");
779  }
780  if((node = xmlNewChild(atom_node, NULL,
781  (xmlChar *)"label_entity_id",
782  (xmlChar *)buffer))==NULL)
783  XMLDIE(doc);
784 
785 
786  sprintf(buffer,"%d", p->resnum);
787  if((node = xmlNewChild(atom_node, NULL, (xmlChar *)"label_seq_id",
788  (xmlChar *)buffer))==NULL)
789  XMLDIE(doc); /* 25.02.15 */
790 
791  /* occupancy */
792  sprintf(buffer,"%.2f", p->occ);
793  if((node = xmlNewChild(atom_node, NULL, (xmlChar *)"occupancy",
794  (xmlChar *)buffer))==NULL)
795  XMLDIE(doc); /* 25.02.15 */
796 
797  /* insertion code
798  Note: Insertion code node only included for residues with
799  insertion codes
800  */
801  if(strcmp(p->insert," "))
802  {
803  sprintf(buffer,"%s", p->insert);
804  if((node = xmlNewChild(atom_node, NULL,
805  (xmlChar *)"pdbx_PDB_ins_code",
806  (xmlChar *)buffer))==NULL)
807  XMLDIE(doc); /* 25.02.15 */
808  }
809 
810  /* model number
811  Note: Model number is not stored in PDB data structure.
812  Value set to 1
813  */
814  if((node = xmlNewChild(atom_node, NULL,
815  (xmlChar *)"pdbx_PDB_model_num",
816  (xmlChar *)"1"))==NULL)
817  XMLDIE(doc); /* 25.02.15 */
818 
819  /* formal charge
820  Note: Formal charge node not included for neutral atoms
821  */
822  if(p->formal_charge != 0)
823  {
824  sprintf(buffer,"%d", p->formal_charge);
825  if((node = xmlNewChild(atom_node, NULL,
826  (xmlChar *)"pdbx_formal_charge",
827  (xmlChar *)buffer))==NULL)
828  XMLDIE(doc); /* 25.02.15 */
829  }
830 
831  /* atom symbol
832  Note: If the atomic symbol is not set in PDB data structure then
833  the value set is based on columns 13-14 of pdb-formated
834  text file.
835  */
836  sprintf(buffer,"%s", p->element);
837  KILLLEADSPACES(buffer_ptr,buffer);
838  if(strlen(buffer_ptr))
839  {
840  if((node = xmlNewChild(atom_node, NULL, (xmlChar *)"type_symbol",
841  (xmlChar *)buffer_ptr))==NULL)
842  XMLDIE(doc); /* 25.02.15 */
843 
844  }
845  else
846  {
848  if((node = xmlNewChild(atom_node, NULL, (xmlChar *)"type_symbol",
849  (xmlChar *)buffer))==NULL)
850  XMLDIE(doc); /* 25.02.15 */
851  }
852 
853  /* Segment ID
854  Note: Segment ID is not included if blank
855  */
856  if(strncmp(p->segid, " ", 4))
857  {
858  if((node = xmlNewChild(atom_node, NULL,
859  (xmlChar *)"seg_id",
860  (xmlChar *)p->segid))==NULL)
861  XMLDIE(doc); /* 25.02.15 */
862  }
863  }
864 
865  /* Finished Coordinate Data */
866  /* Clean up and return if doWhole == FALSE */
867  if(doWhole == FALSE)
868  {
869  /* Write to doc file pointer */
870  xmlDocFormatDump(fp,doc,1);
871 
872  /* Free Memory */
873  xmlFreeDoc(doc);
874  xmlCleanupParser();
875  blFreeHash(chain_to_entity);
876 
877  return(TRUE);
878  }
879 
880 
881  /*** Write Header and trailer data in PDBML-format ***/
882 
883  /* struct_conn node */
884  for(p=wpdb->pdb; p!=NULL; NEXT(p))
885  {
886  if(p->nConect)
887  {
888  if((sites_node = xmlNewChild(root_node, NULL,
889  (xmlChar *)"struct_connCategory",
890  NULL))==NULL)
891  XMLDIE(doc);
892 
893  break;
894  }
895  }
896 
897  /* Conect nodes */
898  for(p=wpdb->pdb; p!=NULL; NEXT(p))
899  {
900  /* skip TER */
901  if(!strncmp("TER",p->resnam,3))
902  {
903  continue;
904  }
905 
906  /* Add conect nodes */
907  for(i=0; i < p->nConect; i++)
908  {
909  if((atom_node = xmlNewChild(sites_node, NULL,
910  (xmlChar *)"struct_conn", NULL))==NULL)
911  XMLDIE(doc);
912 
913  /* set conect atoms */
914  q = p->conect[i];
915  conect_id++;
916 
917  /* conect id */
918  sprintf(buffer, "%s%d", "conect", conect_id);
919  xmlNewProp(atom_node, (xmlChar *)"id", (xmlChar *)buffer);
920 
921  /* connection type */
922  sprintf(buffer, "%s", "covale"); /* set type to covale */
923  if((node = xmlNewChild(atom_node, NULL,
924  (xmlChar *)"conn_type_id",
925  (xmlChar *)buffer))==NULL)
926  XMLDIE(doc);
927 
928  /* bond length */
929  sprintf(buffer, "%.3f", DIST(p,q));
930  if((node = xmlNewChild(atom_node, NULL,
931  (xmlChar *)"pdbx_dist_value",
932  (xmlChar *)buffer))==NULL)
933  XMLDIE(doc);
934 
935  /* atom one data */
936  if((node = xmlNewChild(atom_node, NULL, (xmlChar *)"ptnr1_auth_asym_id",
937  (xmlChar *)p->chain))==NULL)
938  XMLDIE(doc);
939 
940  strcpy(buffer,p->resnam);
941  KILLTRAILSPACES(buffer);
942  KILLLEADSPACES(buffer_ptr,buffer);
943  if((node = xmlNewChild(atom_node, NULL, (xmlChar *)"ptnr1_auth_comp_id",
944  (xmlChar *)buffer_ptr))==NULL)
945  XMLDIE(doc);
946 
947  sprintf(buffer,"%d", p->resnum);
948  if((node = xmlNewChild(atom_node, NULL, (xmlChar *)"ptnr1_auth_seq_id",
949  (xmlChar *)buffer))==NULL)
950  XMLDIE(doc);
951 
952  /* include alt_id if present */
953  if(p->altpos != ' ')
954  {
955  if((node = xmlNewChild(atom_node, NULL,
956  (xmlChar *)"ptnr1_label_alt_id",
957  NULL))==NULL)
958  XMLDIE(doc);
959 
960  buffer[0] = p->altpos;
961  buffer[1] = '\0';
962  xmlNodeSetContent(node, (xmlChar *)buffer);
963  }
964 
965  if((node = xmlNewChild(atom_node, NULL,
966  (xmlChar *)"ptnr1_label_asym_id",
967  (xmlChar *)p->chain))==NULL)
968  XMLDIE(doc);
969 
970  strcpy(buffer,p->atnam);
971  KILLTRAILSPACES(buffer);
972  if((node = xmlNewChild(atom_node, NULL,
973  (xmlChar *)"ptnr1_label_atom_id",
974  (xmlChar *)buffer))==NULL)
975  XMLDIE(doc);
976 
977  strcpy(buffer,p->resnam);
978  KILLTRAILSPACES(buffer);
979  KILLLEADSPACES(buffer_ptr,buffer);
980  if((node = xmlNewChild(atom_node, NULL,
981  (xmlChar *)"ptnr1_label_comp_id",
982  (xmlChar *)buffer_ptr))==NULL)
983  XMLDIE(doc);
984 
985  sprintf(buffer,"%d", p->resnum);
986  if((node = xmlNewChild(atom_node, NULL,
987  (xmlChar *)"ptnr1_label_seq_id",
988  (xmlChar *)buffer))==NULL)
989  XMLDIE(doc);
990 
991  /* insertion code
992  Note: Insertion code node only included for residues with
993  insertion codes
994  */
995  if(strcmp(p->insert," "))
996  {
997  sprintf(buffer,"%s", p->insert);
998  if((node = xmlNewChild(atom_node, NULL,
999  (xmlChar *)"ptnr1_PDB_ins_code",
1000  (xmlChar *)buffer))==NULL)
1001  XMLDIE(doc);
1002  }
1003 
1004 
1005  /* atom two data */
1006  if((node = xmlNewChild(atom_node, NULL, (xmlChar *)"ptnr2_auth_asym_id",
1007  (xmlChar *)q->chain))==NULL)
1008  XMLDIE(doc);
1009 
1010  strcpy(buffer,q->resnam);
1011  KILLTRAILSPACES(buffer);
1012  KILLLEADSPACES(buffer_ptr,buffer);
1013  if((node = xmlNewChild(atom_node, NULL, (xmlChar *)"ptnr2_auth_comp_id",
1014  (xmlChar *)buffer_ptr))==NULL)
1015  XMLDIE(doc);
1016 
1017  sprintf(buffer,"%d", q->resnum);
1018  if((node = xmlNewChild(atom_node, NULL, (xmlChar *)"ptnr2_auth_seq_id",
1019  (xmlChar *)buffer))==NULL)
1020  XMLDIE(doc);
1021 
1022  /* include alt_id if present */
1023  if(q->altpos != ' ')
1024  {
1025  if((node = xmlNewChild(atom_node, NULL,
1026  (xmlChar *)"ptnr2_label_alt_id",
1027  NULL))==NULL)
1028  XMLDIE(doc);
1029 
1030  buffer[0] = q->altpos;
1031  buffer[1] = '\0';
1032  xmlNodeSetContent(node, (xmlChar *)buffer);
1033  }
1034 
1035  if((node = xmlNewChild(atom_node, NULL,
1036  (xmlChar *)"ptnr2_label_asym_id",
1037  (xmlChar *)q->chain))==NULL)
1038  XMLDIE(doc);
1039 
1040  strcpy(buffer,q->atnam);
1041  KILLTRAILSPACES(buffer);
1042  if((node = xmlNewChild(atom_node, NULL,
1043  (xmlChar *)"ptnr2_label_atom_id",
1044  (xmlChar *)buffer))==NULL)
1045  XMLDIE(doc);
1046 
1047  strcpy(buffer,q->resnam);
1048  KILLTRAILSPACES(buffer);
1049  KILLLEADSPACES(buffer_ptr,buffer);
1050  if((node = xmlNewChild(atom_node, NULL,
1051  (xmlChar *)"ptnr2_label_comp_id",
1052  (xmlChar *)buffer_ptr))==NULL)
1053  XMLDIE(doc);
1054 
1055  sprintf(buffer,"%d", q->resnum);
1056  if((node = xmlNewChild(atom_node, NULL,
1057  (xmlChar *)"ptnr2_label_seq_id",
1058  (xmlChar *)buffer))==NULL)
1059  XMLDIE(doc);
1060 
1061 
1062  /* insertion code
1063  Note: Insertion code node only included for residues with
1064  insertion codes
1065  */
1066  if(strcmp(q->insert," "))
1067  {
1068  sprintf(buffer,"%s", q->insert);
1069  if((node = xmlNewChild(atom_node, NULL,
1070  (xmlChar *)"ptnr2_PDB_ins_code",
1071  (xmlChar *)buffer))==NULL)
1072  XMLDIE(doc);
1073  }
1074  }
1075  }
1076 
1077  /* get header data */
1078  blGetHeaderWholePDB(wpdb, header, 82, date, 82, pdbcode, 82);
1079  KILLTRAILSPACES(pdbcode);
1080 
1081  /* get title */
1082  title = blGetTitleWholePDB(wpdb);
1083 
1084  /* add date node */
1085  if(blSetPDBMLDateField(pdbml_date, date))
1086  {
1087  if((sites_node = xmlNewChild(root_node, NULL,
1088  (xmlChar *)"database_PDB_revCategory",
1089  NULL))==NULL)
1090  XMLDIE(doc);
1091 
1092  if((atom_node = xmlNewChild(sites_node, NULL,
1093  (xmlChar *)"database_PDB_rev",
1094  NULL))==NULL)
1095  XMLDIE(doc);
1096  xmlNewProp(atom_node, (xmlChar *)"num", (xmlChar *)"1");
1097 
1098  if((node = xmlNewChild(atom_node, NULL,
1099  (xmlChar *)"date",
1100  (xmlChar *)pdbml_date))==NULL)
1101  XMLDIE(doc);
1102 
1103  if((node = xmlNewChild(atom_node, NULL,
1104  (xmlChar *)"date_original",
1105  (xmlChar *)pdbml_date))==NULL)
1106  XMLDIE(doc);
1107 
1108  if((node = xmlNewChild(atom_node, NULL,
1109  (xmlChar *)"mod_type",
1110  (xmlChar *)"0"))==NULL)
1111  XMLDIE(doc);
1112 
1113  if(strlen(pdbcode) == 4)
1114  {
1115  if((node = xmlNewChild(atom_node, NULL,
1116  (xmlChar *)"replaces",
1117  (xmlChar *)pdbcode))==NULL)
1118  XMLDIE(doc);
1119  }
1120  }
1121 
1122  /* add compnd nodes */
1123  sites_node = NULL;
1124  for(i=1; blGetCompoundWholePDBMolID(wpdb, i, &compound); i++)
1125  {
1126  molid = i;
1127 
1128  if(sites_node == NULL)
1129  {
1130  /* add COMPND node */
1131  if((sites_node = xmlNewChild(root_node, NULL,
1132  (xmlChar *)"entityCategory",
1133  NULL))==NULL)
1134  XMLDIE(doc);
1135  }
1136 
1137  if((atom_node = xmlNewChild(sites_node, NULL,
1138  (xmlChar *)"entity",
1139  NULL))==NULL){ XMLDIE(doc); }
1140 
1141  sprintf(buffer,"%d", i);
1142  xmlNewProp(atom_node, (xmlChar *)"id", (xmlChar *)buffer);
1143 
1144  if(strlen(compound.other))
1145  {
1146  if((node = xmlNewChild(atom_node, NULL,
1147  (xmlChar *)"details",
1148  (xmlChar *)compound.other))==NULL)
1149  { XMLDIE(doc); }
1150  }
1151 
1152  if(strlen(compound.molecule))
1153  {
1154  if((node = xmlNewChild(atom_node, NULL,
1155  (xmlChar *)"pdbx_description",
1156  (xmlChar *)compound.molecule))==NULL)
1157  { XMLDIE(doc); }
1158  }
1159 
1160  if(strlen(compound.ec))
1161  {
1162  if((node = xmlNewChild(atom_node, NULL,
1163  (xmlChar *)"pdbx_ec",
1164  (xmlChar *)compound.ec))==NULL)
1165  { XMLDIE(doc); }
1166  }
1167 
1168  if(strlen(compound.fragment))
1169  {
1170  if((node = xmlNewChild(atom_node, NULL,
1171  (xmlChar *)"pdbx_fragment",
1172  (xmlChar *)compound.fragment))==NULL)
1173  { XMLDIE(doc); }
1174  }
1175 
1176  if(strlen(compound.mutation))
1177  {
1178  if((node = xmlNewChild(atom_node, NULL,
1179  (xmlChar *)"pdbx_mutation",
1180  (xmlChar *)compound.mutation))==NULL)
1181  { XMLDIE(doc); }
1182  }
1183 
1184  /* set type to polymer */
1185  if((node = xmlNewChild(atom_node, NULL,
1186  (xmlChar *)"type",
1187  (xmlChar *)"polymer"))==NULL)
1188  { XMLDIE(doc); }
1189  }
1190 
1191  /* add source nodes */
1192  sites_node = NULL;
1193  j = 0;
1194  for(i=1; i <= molid; i++)
1195  {
1196  if(blGetSpeciesWholePDBMolID(wpdb, i, &species))
1197  {
1198  if(sites_node == NULL)
1199  {
1200  /* add SOURCE node */
1201  if((sites_node = xmlNewChild(root_node, NULL,
1202  (xmlChar *)"entity_src_genCategory",
1203  NULL))==NULL)
1204  XMLDIE(doc);
1205  }
1206 
1207  j++; /* pdbx_src_id */
1208 
1209  if((atom_node = xmlNewChild(sites_node, NULL,
1210  (xmlChar *)"entity_src_gen",
1211  NULL))==NULL){ XMLDIE(doc); }
1212 
1213  sprintf(buffer,"%d", i);
1214  xmlNewProp(atom_node,(xmlChar *)"entity_id",(xmlChar *)buffer);
1215  sprintf(buffer,"%d", j);
1216  xmlNewProp(atom_node,(xmlChar *)"pdbx_src_id",(xmlChar *)buffer);
1217 
1218  if(strlen(species.commonName))
1219  {
1220  if((node = xmlNewChild(atom_node, NULL,
1221  (xmlChar *)"pdbx_gene_src_common_name",
1222  (xmlChar *)species.commonName))==NULL)
1223  { XMLDIE(doc); }
1224  }
1225 
1226  if(strlen(species.strain))
1227  {
1228  if((node = xmlNewChild(atom_node, NULL,
1229  (xmlChar *)"pdbx_gene_src_strain",
1230  (xmlChar *)species.strain))==NULL)
1231  { XMLDIE(doc); }
1232  }
1233 
1234  if(species.taxid != 0)
1235  {
1236  sprintf(buffer,"%d", species.taxid);
1237  if((node = xmlNewChild(atom_node, NULL,
1238  (xmlChar *)"pdbx_gene_src_ncbi_taxonomy_id",
1239  (xmlChar *)buffer))==NULL)
1240  { XMLDIE(doc); }
1241  }
1242 
1243  if(strlen(species.scientificName))
1244  {
1245  if((node = xmlNewChild(atom_node, NULL,
1246  (xmlChar *)"pdbx_gene_src_scientific_name",
1247  (xmlChar *)species.scientificName))==NULL)
1248  { XMLDIE(doc); }
1249  }
1250  }
1251  }
1252 
1253 
1254  /* SEQRES nodes */
1255  /* get seqres chain ids from wpdb->header */
1256  seqres_chain = ReadSeqresChainLabelWholePDB(wpdb, &seqres_nchains);
1257  if(seqres_chain)
1258  {
1259  /* get seqres residues from wpdb->header */
1260  seqres_residues = ReadSeqresResidueListWholePDB(wpdb,
1261  &seqres_nchains);
1262 
1263  if(seqres_residues)
1264  {
1265  /* add pdbx_poly_seq_schemeCategory node */
1266  if((sites_node = xmlNewChild(root_node, NULL,
1267  (xmlChar *)"pdbx_poly_seq_schemeCategory",
1268  NULL))==NULL){ XMLDIE(doc); }
1269 
1270  /* cycle through chains */
1271  for(i=0;i<seqres_nchains;i++)
1272  {
1273  int res = 1, /* reset residue count */
1274  entity = 1; /* set entity_id to default */
1275 
1276  /* set entity based on chain id */
1277  if(chain_to_entity != NULL &&
1278  blHashKeyDefined(chain_to_entity, seqres_chain[i]))
1279  {
1280  entity = blGetHashValueInt(chain_to_entity,
1281  seqres_chain[i]);
1282  }
1283 
1284  /* cycle through residues */
1285  for(s=seqres_residues[i];s!=NULL;NEXT(s),res++)
1286  {
1287  /* add pdbx_poly_seq_scheme node */
1288  if((atom_node = xmlNewChild(sites_node, NULL,
1289  (xmlChar *)"pdbx_poly_seq_scheme", NULL))
1290  == NULL)
1291  { XMLDIE(doc); }
1292  /* add attributes */
1293  /* asym_id */
1294  xmlNewProp(atom_node, (xmlChar *)"asym_id",
1295  (xmlChar *)seqres_chain[i]);
1296  /* entity_id */
1297  sprintf(buffer, "%d", entity);
1298  xmlNewProp(atom_node, (xmlChar *)"entity_id",
1299  (xmlChar *)buffer);
1300  /* mon_id */
1301  xmlNewProp(atom_node, (xmlChar *)"mon_id",
1302  (xmlChar *)s->string);
1303  /* seq_id */
1304  sprintf(buffer, "%d", res);
1305  xmlNewProp(atom_node, (xmlChar *)"seq_id",
1306  (xmlChar *)buffer);
1307 
1308  /* add subnodes */
1309  /* auth_mon_id */
1310  sprintf(buffer,"%d", res);
1311  if((node = xmlNewChild(atom_node, NULL,
1312  (xmlChar *)"auth_mon_id",
1313  (xmlChar *)s->string))==NULL)
1314  XMLDIE(doc);
1315  /* ndb_seq_num */
1316  sprintf(buffer,"%d", res);
1317  if((node = xmlNewChild(atom_node, NULL,
1318  (xmlChar *)"ndb_seq_num",
1319  (xmlChar *)buffer))==NULL)
1320  XMLDIE(doc);
1321  /* pdb_mon_id */
1322  sprintf(buffer,"%d", res);
1323  if((node = xmlNewChild(atom_node, NULL,
1324  (xmlChar *)"pdb_mon_id",
1325  (xmlChar *)s->string))==NULL)
1326  XMLDIE(doc);
1327  /* pdb_strand_id */
1328  sprintf(buffer,"%d", res);
1329  if((node = xmlNewChild(atom_node, NULL,
1330  (xmlChar *)"pdb_strand_id",
1331  (xmlChar *)seqres_chain[i]))==NULL)
1332  XMLDIE(doc);
1333  }
1334 
1335  FREELIST(seqres_residues[i],STRINGLIST); /* free residues */
1336  free(seqres_chain[i]); /* free chain id */
1337  }
1338  free(seqres_residues); /* free residues array */
1339  }
1340  free(seqres_chain); /* free chain id array */
1341  }
1342 
1343 
1344  /* pdb entry */
1345  if(strlen(pdbcode))
1346  {
1347  if((sites_node = xmlNewChild(root_node, NULL,
1348  (xmlChar *)"entryCategory",
1349  NULL))==NULL)
1350  XMLDIE(doc);
1351 
1352  if((atom_node = xmlNewChild(sites_node, NULL,
1353  (xmlChar *)"entry",
1354  (xmlChar *)""))==NULL)
1355  XMLDIE(doc);
1356  xmlNewProp(atom_node, (xmlChar *)"id", (xmlChar *)pdbcode);
1357  }
1358 
1359  /* title node */
1360  if(title != NULL && strlen(pdbcode))
1361  {
1362  if((sites_node = xmlNewChild(root_node, NULL,
1363  (xmlChar *)"structCategory",
1364  NULL))==NULL)
1365  XMLDIE(doc);
1366 
1367  if((atom_node = xmlNewChild(sites_node, NULL,
1368  (xmlChar *)"struct",
1369  NULL))==NULL)
1370  XMLDIE(doc);
1371  xmlNewProp(atom_node, (xmlChar *)"entry_id", (xmlChar *)pdbcode);
1372 
1373  if((node = xmlNewChild(atom_node, NULL,
1374  (xmlChar *)"title",
1375  (xmlChar *)title))==NULL)
1376  XMLDIE(doc);
1377 
1378  }
1379  if(title != NULL){ free(title); }
1380 
1381  /* header node */
1382  if(strlen(header) && strlen(pdbcode))
1383  {
1384  if((sites_node = xmlNewChild(root_node, NULL,
1385  (xmlChar *)"struct_keywordsCategory",
1386  NULL))==NULL)
1387  XMLDIE(doc);
1388 
1389  if((atom_node = xmlNewChild(sites_node, NULL,
1390  (xmlChar *)"struct_keywords",
1391  NULL))==NULL)
1392  XMLDIE(doc);
1393  xmlNewProp(atom_node, (xmlChar *)"entry_id", (xmlChar *)pdbcode);
1394 
1395  if((node = xmlNewChild(atom_node, NULL,
1396  (xmlChar *)"pdbx_keywords",
1397  (xmlChar *)header))==NULL)
1398  XMLDIE(doc);
1399 
1400  }
1401 
1402 
1403  /* Write to doc file pointer */
1404  xmlDocFormatDump(fp,doc,1);
1405 
1406  /* Free Memory */
1407  xmlFreeDoc(doc);
1408  xmlCleanupParser();
1409  blFreeHash(chain_to_entity);
1410 
1411  return(TRUE);
1412 
1413 #endif
1414 }
1415 
1416 
1417 /************************************************************************/
1418 /*>void blSetElementSymbolFromAtomName(char *element, char *atom_name)
1419  -------------------------------------------------------------------
1420 *//**
1421 
1422  \param[out] *element Element symbol
1423  \param[in] *atom_name Atom name
1424 
1425  Set the element symbol (columns 77-78 of a pdb file) based on the
1426  atom name (columns 13-16 of a pdb file).
1427 
1428  The atom name is stored in the PDB data stucture as atnam_raw.
1429 
1430 - 17.07.14 Original. By: CTP
1431 
1432 */
1433 void blSetElementSymbolFromAtomName(char *element, char *atom_name)
1434 {
1435  char buffer[] = " ",
1436  *buffer_ptr;
1437 
1438  /* copy first two letters of atom name to buffer */
1439  strncpy(buffer,atom_name,2);
1440  buffer[2] = '\0';
1441  KILLLEADSPACES(buffer_ptr,buffer);
1442 
1443  /* remove digits */
1444  if(strlen(buffer_ptr) == 2 && isdigit(buffer[1]))
1445  {
1446  buffer[1] = '\0';
1447  }
1448  else if(strlen(buffer_ptr) == 2 && !isalpha(buffer[0]))
1449  {
1450  buffer_ptr += 1;
1451  }
1452 
1453  /* fix hydrogens and carbons */
1454  if(strlen(buffer_ptr) == 2 && atom_name[3] != ' ' &&
1455  (atom_name[0] == 'H' || atom_name[0] == 'C' ||
1456  atom_name[0] == 'N' || atom_name[0] == 'O' ||
1457  atom_name[0] == 'P'))
1458  {
1459  if(!isalpha(atom_name[2]) || !isalpha(atom_name[3]))
1460  {
1461  buffer[1] = '\0';
1462  }
1463  }
1464 
1465  /* copy atom symbol to element */
1466  strcpy(element, buffer_ptr);
1467 }
1468 
1469 
1470 /************************************************************************/
1471 /*>void blWriteGromosPDB(FILE *fp, PDB *pdb)
1472  -----------------------------------------
1473 *//**
1474 
1475  \param[in] *fp PDB file pointer to be written
1476  \param[in] *pdb PDB linked list to write
1477 
1478  Write a PDB linked list by calls to WritePDBRecord()
1479 
1480 - 08.03.89 Original
1481 - 01.06.92 ANSIed and autodoc'd
1482 - 10.06.93 Uses NEXT macro; void type
1483 - 08.07.93 Added insertion of TER cards
1484 - 22.02.94 And a TER card at the end of the file
1485 - 15.02.01 This is the old WritePDB()
1486 - 04.02.14 Use CHAINMATCH macro. By: CTP
1487 - 07.07.14 Use bl prefix for functions By: CTP
1488 - 23.02.15 Proper TER card support By: ACRM
1489 - 24.02.15 Now just uses blWritePDBAsPDBorGromos()
1490 */
1491 void blWriteGromosPDB(FILE *fp,
1492  PDB *pdb)
1493 {
1494  blWritePDBAsPDBorGromos(fp, pdb, TRUE);
1495 }
1496 
1497 
1498 /************************************************************************/
1499 /*>void blWriteGromosPDBRecord(FILE *fp, PDB *pdb)
1500  -----------------------------------------------
1501 *//**
1502 
1503  \param[in] *fp PDB file pointer to be written
1504  \param[in] *pdb PDB linked list record to write
1505 
1506  Write a PDB record
1507 
1508 - 08.03.89 Original
1509 - 28.03.90 Changed to match ReadPDB() V1.2 for column widths
1510 - 01.06.92 ANSIed and autodoc'd
1511 - 10.06.93 void type
1512 - 22.06.93 Changed to %lf. Ljust strings
1513 - 11.03.94 %lf back to %f (!)
1514 - 12.02.01 This is the old WritePDBRecord()
1515 - 07.07.14 Use bl prefix for functions By: CTP
1516 */
1518  PDB *pdb)
1519 {
1520  fprintf(fp,"%-6s%5d %-4s%-4s%1s%4d%1s %8.3f%8.3f%8.3f%6.2f%6.2f\n",
1521  pdb->record_type,
1522  pdb->atnum,
1523  pdb->atnam,
1524  pdb->resnam,
1525  pdb->chain,
1526  pdb->resnum,
1527  pdb->insert,
1528  pdb->x,
1529  pdb->y,
1530  pdb->z,
1531  pdb->occ,
1532  pdb->bval);
1533 }
1534 
1535 
1536 /************************************************************************/
1537 /*>BOOL blWriteWholePDB(FILE *fp, WHOLEPDB *wpdb)
1538  ----------------------------------------------
1539 *//**
1540 
1541  \param[in] *fp File pointer
1542  \param[in] *wpdb Whole PDB structure pointer
1543 
1544  Writes a PDB file including header and trailer information.
1545  Output in PDBML-format if flags set.
1546 
1547 - 21.06.14 Original By: CTP
1548 - 18.08.14 Added XML_SUPPORT option. Return error if attempting to write
1549  PDBML format. By: CTP
1550 - 12.02.15 Now a wrapper to blDoWriteWhilePDB()
1551 - 24.02.15 blWriteAsPDBML() changed to blWritePDBAsPDBML()
1552  blWriteAsPDB() changed to blWritePDBAsPDBorGromos()
1553 - 25.02.15 No longer a wrapper
1554 - 04.03.15 Added check on wpdb and wpdb->pdb being non-NULL
1555 - 11.05.15 Updated to use blDoWritePDBAsPDBML(). By: CTP
1556 */
1558 {
1559  int nter;
1560 
1561  if((wpdb==NULL) || (wpdb->pdb==NULL))
1562  return(FALSE);
1563 
1564  if((gPDBXMLForce == FORCEXML_XML) ||
1566  {
1567 #ifdef XML_SUPPORT
1568  /* Write PDBML file (including header and footer data) */
1569  blDoWritePDBAsPDBML(fp, wpdb, TRUE);
1570 #else
1571  /* PDBML not supported */
1572  return(FALSE);
1573 #endif
1574  }
1575  else
1576  {
1577  /* Check format */
1578  if(blFormatCheckWritePDB(wpdb->pdb) == FALSE)
1579  {
1580  return(FALSE);
1581  }
1582 
1583  /* Write whole PDB File */
1584  blWriteWholePDBHeader(fp, wpdb);
1585  nter = blWritePDBAsPDBorGromos(fp, wpdb->pdb, FALSE);
1586  blWriteWholePDBTrailer(fp, wpdb, nter);
1587  }
1588 
1589  return(TRUE);
1590 }
1591 
1592 
1593 /************************************************************************/
1594 /*>void blWriteWholePDBHeader(FILE *fp, WHOLEPDB *wpdb)
1595  ----------------------------------------------------
1596 *//**
1597 
1598  \param[in] *fp File pointer
1599  \param[in] *wpdb Whole PDB structure pointer
1600 
1601  Writes the header of a PDB file
1602 
1603 - 30.05.02 Original By: ACRM
1604 - 21.06.14 Renamed to blWriteWholePDBHeader() By: CTP
1605 - 12.02.15 Added XML check By: ACRM
1606 - 06.08.15 Updated XML check. By: CTP
1607 */
1608 void blWriteWholePDBHeader(FILE *fp, WHOLEPDB *wpdb)
1609 {
1610  STRINGLIST *s;
1611 
1612  if((gPDBXMLForce == FORCEXML_PDB) ||
1614  {
1615  for(s=wpdb->header; s!=NULL; NEXT(s))
1616  {
1617  fputs(s->string, fp);
1618  }
1619  }
1620 }
1621 
1622 
1623 /************************************************************************/
1624 /*>void blWriteWholePDBTrailer(FILE *fp, WHOLEPDB *wpdb, int numTer)
1625  -----------------------------------------------------------------
1626 *//**
1627 
1628  \param[in] *fp File pointer
1629  \param[in] *wpdb Whole PDB structure pointer
1630  \param[in] numTer Number of TER cards
1631 
1632  Writes the trailer of a PDB file
1633 
1634 - 30.05.02 Original By: ACRM
1635 - 21.06.14 Renamed to blWriteWholePDBTrailer() By: CTP
1636 - 12.02.15 Added XML check By: ACRM
1637 - 18.02.15 Complete rewrite to use the parsed CONECT data rather than
1638  simply rewriting what was read in
1639 - 23.02.15 Added numTer parameter
1640 - 02.03.15 Padded END and CONECT
1641 - 06.08.15 Updated XML check. By: CTP
1642 */
1643 void blWriteWholePDBTrailer(FILE *fp, WHOLEPDB *wpdb, int numTer)
1644 {
1645  int nConect = 0;
1646 
1647  if((gPDBXMLForce == FORCEXML_PDB) ||
1649  {
1650  /* Write the CONECT records */
1651  PDB *p;
1652  for(p=wpdb->pdb; p!=NULL; NEXT(p))
1653  {
1654  if(p->nConect)
1655  {
1656  BOOL conectPrinted = FALSE;
1657  int i,
1658  nPrinted,
1659  width=0;
1660  char format[8];
1661 
1662  for(i=0, nPrinted=0; i<p->nConect; i++)
1663  {
1664  if(!(nPrinted%4))
1665  {
1666  if(conectPrinted)
1667  fprintf(fp, "\n");
1668  fprintf(fp,"CONECT%5d", p->atnum);
1669  nConect++;
1670  width = 11;
1671  conectPrinted = 1;
1672  }
1673  if(p->conect[i] != NULL)
1674  {
1675  fprintf(fp,"%5d", p->conect[i]->atnum);
1676  width += 5;
1677  nPrinted++;
1678  }
1679  }
1680  sprintf(format, "%%%ds\n", 80-width);
1681  fprintf(fp, format, " ");
1682  }
1683  }
1684 
1685  /* Now write the MASTER record */
1686  WriteMaster(fp, wpdb, nConect, numTer);
1687 
1688  fprintf(fp, "END%77s\n", " ");
1689  }
1690 }
1691 
1692 
1693 /************************************************************************/
1694 /*>static void WriteMaster(FILE *fp, WHOLEPDB *wpdb, int numConect,
1695  int numTer)
1696  ----------------------------------------------------------------
1697 *//**
1698  \param[in] *fp File pointer for output
1699  \param[in] *wpdb WHOLEPDB structure
1700  \param[in] numConect Number of CONECT records
1701  \param[in] numTer Number of TER cards
1702 
1703  Writes the PDB MASTER record. Everything is calculated in this code
1704  apart from the number of CONECT records and the number of TER cards
1705  which must be passed in
1706 
1707 - 22.02.15 Original By: ACRM
1708 - 02.03.15 Corrected counting of ORIGX, SCALE and MTRIX
1709 - 02.04.15 Padded MASTER record to 80 columns. By: CTP
1710 */
1711 static void WriteMaster(FILE *fp, WHOLEPDB *wpdb, int numConect,
1712  int numTer)
1713 {
1714  int numRemark = 0, /* Number of REMARK records */
1715  numHet = 0, /* Number of HET records */
1716  numHelix = 0, /* Number of HELIX records */
1717  numSheet = 0, /* Number of SHEET records */
1718  numTurn = 0, /* Number of TURN records */
1719  numSite = 0, /* Number of SITE records */
1720  numXform = 0, /* Number of coordinate transformation records
1721  (ORIGX+SCALE+MTRIX) */
1722  numCoord = 0, /* Number of atomic coordinate records
1723  (ATOM+HETATM) */
1724  numSeq = 0; /* Number of SEQRES records */
1725  STRINGLIST *s;
1726  PDB *p;
1727 
1728 
1729  for(s=wpdb->header; s!=NULL; NEXT(s))
1730  {
1731  if(!strncmp(s->string, "REMARK", 6))
1732  numRemark++;
1733  if(!strncmp(s->string, "HET ", 6))
1734  numHet++;
1735  if(!strncmp(s->string, "HELIX ", 6))
1736  numHelix++;
1737  if(!strncmp(s->string, "SHEET ", 6))
1738  numSheet++;
1739  if(!strncmp(s->string, "TURN ", 6))
1740  numTurn++;
1741  if(!strncmp(s->string, "SITE ", 6))
1742  numSite++;
1743  if(!strncmp(s->string, "ORIGX", 5))
1744  numXform++;
1745  if(!strncmp(s->string, "SCALE", 5))
1746  numXform++;
1747  if(!strncmp(s->string, "MTRIX", 5))
1748  numXform++;
1749  if(!strncmp(s->string, "SEQRES", 6))
1750  numSeq++;
1751  }
1752 
1753  for(p=wpdb->pdb; p!=NULL; NEXT(p))
1754  numCoord++;
1755 
1756  fprintf(fp,"MASTER %5d 0%5d%5d%5d%5d%5d%5d%5d%5d%5d%5d \n",
1757  numRemark,
1758  numHet,
1759  numHelix,
1760  numSheet,
1761  numTurn,
1762  numSite,
1763  numXform,
1764  numCoord,
1765  numTer,
1766  numConect,
1767  numSeq);
1768 }
1769 
1770 
1771 /************************************************************************/
1772 /*>void blWriteWholePDBHeaderNoRes(FILE *fp, WHOLEPDB *wpdb)
1773  ---------------------------------------------------------
1774 *//**
1775 
1776  \param[in] *fp File pointer
1777  \param[in] *wpdb Whole PDB structure pointer
1778 
1779  Writes the header of a PDB file, but skips any records that include
1780  residue numbers for cases where these may have changed.
1781 
1782  Skips:
1783  REMARK 500
1784  DBREF
1785  HELIX
1786  SHEET
1787  SSBOND
1788  CISPEP
1789  SEQADV
1790  MODRES
1791  HET
1792  SITE
1793  REMARK 465
1794  REMARK 470
1795  REMARK 475
1796  REMARK 480
1797  REMARK 525
1798  REMARK 610
1799  REMARK 615
1800  REMARK 620
1801  REMARK 630
1802  REMARK 3
1803 
1804 - 02.03.15 Original By: ACRM
1805 - 09.03.15 Additionally skips SEQADV, MODRES, HET, SITE
1806 - 10.03.15 Additionally skips REMARK 3,465,470,475,480,525,610,615,620,630
1807 - 06.08.15 Updated XML check. By: CTP
1808 */
1810 {
1811  STRINGLIST *s;
1812  int i;
1813  char *recordLabels[] = {"REMARK 500",
1814  "DBREF ",
1815  "HELIX ",
1816  "SHEET ",
1817  "SSBOND",
1818  "CISPEP",
1819  "SEQADV",
1820  "MODRES",
1821  "HET ",
1822  "SITE ",
1823  "REMARK 465",
1824  "REMARK 470",
1825  "REMARK 475",
1826  "REMARK 480",
1827  "REMARK 525",
1828  "REMARK 610",
1829  "REMARK 615",
1830  "REMARK 620",
1831  "REMARK 630",
1832  "REMARK 3",
1833  NULL};
1834 
1835  if((gPDBXMLForce == FORCEXML_PDB) ||
1837  {
1838  for(s=wpdb->header; s!=NULL; NEXT(s))
1839  {
1840  BOOL printIt = TRUE;
1841  for(i=0; recordLabels[i] != NULL; i++)
1842  {
1843  if(!strncmp(s->string, recordLabels[i], strlen(recordLabels[i])))
1844  {
1845  printIt = FALSE;
1846  break;
1847  }
1848  }
1849  if(printIt)
1850  fputs(s->string, fp);
1851  }
1852  }
1853 }
1854 
1855 /************************************************************************/
1856 /*>static BOOL blSetPDBMLDateField(char *pdbml_date, char *pdb_date)
1857  -----------------------------------------------------------------
1858 *//**
1859 
1860  \param[out] *pdbml_date PDBML date string 'yyyy-mm-dd'
1861  \param[in] *pdb_date PDB date string 'dd-MTH-yy'
1862  \return Success?
1863 
1864  Convert pdb date format to pdbml date format.
1865 
1866 - 12.05.15 Original. By: CTP
1867 
1868 */
1869 static BOOL blSetPDBMLDateField(char *pdbml_date, char *pdb_date)
1870 {
1871  char month_letter[12][4] = {"JAN","FEB","MAR","APR","MAY","JUN",
1872  "JUL","AUG","SEP","OCT","NOV","DEC"};
1873  int day = 0,
1874  month = 0,
1875  year = 0,
1876  items = 0,
1877  i = 0;
1878 
1879  char pdb_month[4] = "";
1880 
1881  /* parse pdb date */
1882  items = sscanf(pdb_date, "%2d-%3s-%2d", &day, pdb_month, &year);
1883 
1884  /* convert month_pdb */
1885  for(i=0; i<12; i++)
1886  {
1887  if(!strcmp(month_letter[i], pdb_month))
1888  {
1889  month = i + 1;
1890  break;
1891  }
1892  }
1893 
1894  /* convert 2-digit year to 4-digit year (74 == 2074, 75 == 1975) */
1895  /* earliest searchable pdb structures date from 1976 */
1896  if(year < 75)
1897  { year = year + 2000; }
1898  else
1899  { year = year + 1900; }
1900 
1901  /* error check */
1902  if(items != 3 ||
1903  year == 0 || month == 0 || day == 0 ||
1904  day < 1 || day > 31 ||
1905  month < 1 || month > 12 ||
1906  year < 1975)
1907  {
1908  /* conversion failed */
1909  pdbml_date[0] = '\0';
1910  return FALSE;
1911  }
1912 
1913  /* set pdbml date */
1914  sprintf(pdbml_date, "%4d-%02d-%02d", year, month, day);
1915 
1916  return TRUE;
1917 }
1918 
1919 /************************************************************************/
1920 /*>static HASHTABLE *blMapChainsToEntity(WHOLEPDB *wpdb)
1921  -----------------------------------------------------
1922 *//**
1923 
1924  \param[in] *wpdb WHOLEPDB to parse.
1925  \return HASHTABLE mapping chain labels to MOL_ID
1926 
1927  Map chain labels to MOL_IDs from header COMPND records.
1928 
1929  Used to set entity_id for PDBML-format files if entity_id has not been
1930  set (eg if original input file was PDB-format).
1931 
1932 - 18.06.14 Original. By: CTP
1933 
1934 */
1935 static HASHTABLE *blMapChainsToEntity(WHOLEPDB *wpdb)
1936 {
1937  HASHTABLE *hashtable = NULL;
1938  char **chains = NULL;
1939  int nchains = 0,
1940  i = 0;
1941  COMPND compnd;
1942 
1943  /* return if wpdb not set */
1944  if(wpdb == NULL || wpdb->pdb == NULL || wpdb->header == NULL)
1945  { return NULL; }
1946 
1947  /* get chain array */
1948  chains = blGetPDBChainLabels(wpdb->pdb, &nchains);
1949 
1950  /* init hashtable */
1951  if((hashtable = blInitializeHash(0))==NULL)
1952  {
1953  fprintf(stderr,"No memory for hash table\n");
1954  return(NULL);
1955  }
1956 
1957  /* set hashtable */
1958  for(i=0;i<nchains;i++)
1959  {
1960  if(blGetCompoundWholePDBChain(wpdb, chains[i], &compnd))
1961  {
1962  if(compnd.molid)
1963  blSetHashValueInt(hashtable, chains[i], compnd.molid);
1964  }
1965  }
1966 
1967  /* free chains array */
1968  if(nchains)
1969  {
1970  for(i=0;i<nchains;i++){ free(chains[i]); }
1971  free(chains);
1972  }
1973 
1974  /* return hashtable */
1975  return hashtable;
1976 }
1977 
1978 /************************************************************************/
1979 /*>static char **blReadSeqresChainLabelWholePDB(WHOLEPDB *wpdb,
1980  int *nchains)
1981  ------------------------------------------------------------
1982 *//**
1983 
1984  \param[in] wpdb WHOLEPDB structure
1985  \param[out] *nchains Number of chains found
1986  \return Array of chain labels
1987 
1988  Reads the sequence from the SEQRES records from the PDB header
1989  stored in a WHOLEPDB structure. Creates an array of malloc()'d
1990  character arrays in which the chain label is stored.
1991 
1992 - 09.07.15 Original based on blReadSeqresResidueWholePDB() By: CTP
1993 */
1994 static char **ReadSeqresChainLabelWholePDB(WHOLEPDB *wpdb, int *nchains)
1995 {
1996  STRINGLIST *seqres = NULL,
1997  *s;
1998  char currchain[2] = " ",
1999  chain[2] = " ",
2000  **chainid;
2001  int chainnum = 0,
2002  i;
2003 
2004  *nchains = 0;
2005 
2006  /* First read the SEQRES records into a linked list */
2007  for(s=wpdb->header; s!=NULL; NEXT(s))
2008  {
2009  if(!strncmp(s->string,"SEQRES",6))
2010  {
2011  if((seqres = blStoreString(seqres, s->string)) == NULL)
2012  {
2013  FREELIST(seqres, STRINGLIST);
2014  return(NULL);
2015  }
2016  }
2017  }
2018 
2019  /* Return if no seqres records found */
2020  if(seqres == NULL)
2021  {
2022  return(NULL);
2023  }
2024 
2025  /* FIRST PASS: See how many chains there are */
2026  strncpy(currchain,&(seqres->string[11]),1);
2027  *nchains = 1;
2028  for(s=seqres; s!=NULL; NEXT(s))
2029  {
2030  strncpy(chain,&(s->string[11]),1);
2031  if(!CHAINMATCH(chain,currchain))
2032  {
2033  strncpy(currchain,chain,1);
2034  (*nchains)++;
2035  }
2036  }
2037 
2038  /* Allocate an array of character pointers to store this number of
2039  chain labels
2040  */
2041  if((chainid=(char **)malloc((*nchains) * sizeof(char *)))==NULL)
2042  {
2043  FREELIST(seqres, STRINGLIST);
2044  return(NULL);
2045  }
2046 
2047  /* allocate memory for chain labels */
2048  for(i=0;i<(*nchains);i++)
2049  {
2050  if((chainid[i] = (char *)malloc(8*sizeof(char))) == NULL)
2051  {
2052  FREELIST(seqres, STRINGLIST);
2053  free(chainid);
2054  return(NULL);
2055  }
2056  }
2057 
2058  /* SECOND PASS: Store the Chain labels */
2059  chainnum = 0;
2060  strcpy(currchain,"");
2061  for(s=seqres; s!=NULL; NEXT(s))
2062  {
2063  fsscanf(s->string,"%11x%1s",chain);
2064  if(!CHAINMATCH(chain,currchain))
2065  {
2066  /* store new chain id */
2067  strcpy(chainid[chainnum],chain);
2068  strcpy(currchain,chain);
2069  chainnum++;
2070  }
2071  }
2072 
2073  /* free memory and return */
2074  FREELIST(seqres, STRINGLIST);
2075  return(chainid);
2076 }
2077 
2078 
2079 
2080 /************************************************************************/
2081 /*>static STRINGLIST **ReadSeqresResidueListWholePDB(WHOLEPDB *wpdb,
2082  int *nchains)
2083  -----------------------------------------------------------------
2084 *//**
2085 
2086  \param[in] wpdb WHOLEPDB structure
2087  \param[out] *nchains Number of chains found
2088  \return Array of sequence strings
2089 
2090  Reads the sequence from the SEQRES records from the PDB header
2091  stored in a WHOLEPDB structure. Creates an array of malloc()'d
2092  STRINGLISTs in which the sequence is stored. Can therefore
2093  cope with any size of sequence information from the PDB file.
2094 
2095 - 09.07.15 Original based on blReadSeqresResidueWholePDB() By: CTP
2096 */
2097 static STRINGLIST **ReadSeqresResidueListWholePDB(WHOLEPDB *wpdb,
2098  int *nchains)
2099 {
2100  STRINGLIST *seqres = NULL,
2101  *s,
2102  **residuelist = NULL;
2103  char currchain[2] = " ",
2104  chain[2] = " ",
2105  res[13][8];
2106  int chainnum = 0,
2107  i;
2108 
2109  *nchains = 0;
2110 
2111 
2112  /* First read the SEQRES records into a linked list */
2113  for(s=wpdb->header; s!=NULL; NEXT(s))
2114  {
2115  if(!strncmp(s->string,"SEQRES",6))
2116  {
2117  if((seqres = blStoreString(seqres, s->string)) == NULL)
2118  {
2119  FREELIST(seqres, STRINGLIST);
2120  return(NULL);
2121  }
2122  }
2123  }
2124 
2125  /* Return if no seqres records found */
2126  if(seqres == NULL)
2127  {
2128  return(NULL);
2129  }
2130 
2131  /* FIRST PASS: See how many chains there are */
2132  strncpy(currchain,&(seqres->string[11]),1);
2133  *nchains = 1;
2134  for(s=seqres; s!=NULL; NEXT(s))
2135  {
2136  strncpy(chain,&(s->string[11]),1);
2137  if(!CHAINMATCH(chain,currchain))
2138  {
2139  strncpy(currchain,chain,1);
2140  (*nchains)++;
2141  }
2142  }
2143 
2144  /* Allocate array for residue sequences */
2145  if((residuelist=
2146  (STRINGLIST **)malloc((*nchains) * sizeof(STRINGLIST *)))==NULL)
2147  {
2148  FREELIST(seqres, STRINGLIST);
2149  return(NULL);
2150  }
2151 
2152  /* set stringlist pointers to NULL */
2153  for(i=0;i<(*nchains);i++)
2154  {
2155  residuelist[i] = NULL;
2156  }
2157 
2158  /* SECOND PASS: Store the sequence */
2159  chainnum = 0;
2160  strncpy(currchain,&(seqres->string[11]),1);
2161  for(s=seqres; s!=NULL; NEXT(s))
2162  {
2163  fsscanf(s->string,"%11x%1s%7x%4s%4s%4s%4s%4s%4s%4s%4s%4s%4s%4s%4s%4s",
2164  chain,res[0],res[1],res[2],res[3],res[4],res[5],res[6],
2165  res[7],res[8],res[9],res[10],res[11],res[12]);
2166  if(!CHAINMATCH(chain,currchain))
2167  {
2168  /* Start of new chain */
2169  strcpy(currchain,chain);
2170  chainnum++;
2171  }
2172 
2173  /* Store these sequence data */
2174  for(i=0; i<13; i++)
2175  {
2176  /* Break out if not all positions were filled in */
2177  if(!strncmp(res[i]," ",4))
2178  break;
2179 
2180  /* add to stringlist */
2181  residuelist[chainnum] = blStoreString(residuelist[chainnum],
2182  res[i]);
2183  }
2184  }
2185 
2186  /* free memory and return */
2187  FREELIST(seqres, STRINGLIST);
2188  return(residuelist);
2189 }
int natoms
Definition: pdb.h:377
#define DIST(a, b)
Definition: macros.h:231
char * blGetTitleWholePDB(WHOLEPDB *wpdb)
int blWritePDB(FILE *fp, PDB *pdb)
Definition: WritePDB.c:223
BOOL blGetCompoundWholePDBMolID(WHOLEPDB *wpdb, int molid, COMPND *compnd)
BOOL blGetSpeciesWholePDBMolID(WHOLEPDB *wpdb, int molid, PDBSOURCE *source)
STRINGLIST * trailer
Definition: pdb.h:376
char strain[MAXPDBANNOTATION]
Definition: pdb.h:395
Include file for PDB routines.
int resnum
Definition: pdb.h:310
char fragment[MAXPDBANNOTATION]
Definition: pdb.h:383
short BOOL
Definition: SysDefs.h:64
#define NULL
Definition: array2.c:99
Definition: pdb.h:298
#define KILLTRAILSPACES(x)
Definition: macros.h:414
#define FORCEXML_XML
Definition: pdb.h:587
Defines for using hash functions.
void blWriteWholePDBHeader(FILE *fp, WHOLEPDB *wpdb)
Definition: WritePDB.c:1608
BOOL gPDBXML
BOOL blGetCompoundWholePDBChain(WHOLEPDB *wpdb, char *chain, COMPND *compnd)
STRINGLIST * header
Definition: pdb.h:375
struct _memlist * prev
Definition: safemem.c:115
#define FALSE
Definition: macros.h:223
Definition: pdb.h:372
#define NEXT(x)
Definition: macros.h:249
void blSetElementSymbolFromAtomName(char *element, char *atom_name)
Definition: WritePDB.c:1433
char altpos
Definition: pdb.h:324
int atnum
Definition: pdb.h:309
char record_type[8]
Definition: pdb.h:315
BOOL blSetHashValueInt(HASHTABLE *hashtable, char *key, int value)
Definition: hash.c:472
BOOL blWriteWholePDB(FILE *fp, WHOLEPDB *wpdb)
Definition: WritePDB.c:1557
Useful macros.
int nConect
Definition: pdb.h:312
void blWriteGromosPDB(FILE *fp, PDB *pdb)
Definition: WritePDB.c:1491
char atnam[8]
Definition: pdb.h:316
int fsscanf(char *buffer, char *format,...)
Definition: fsscanf.c:177
char resnam[8]
Definition: pdb.h:319
int entity_id
Definition: pdb.h:313
void blWritePDBRecord(FILE *fp, PDB *pdb)
Definition: WritePDB.c:415
double REAL
Definition: MathType.h:67
HASHTABLE * blInitializeHash(ULONG hashsize)
Definition: hash.c:163
REAL z
Definition: pdb.h:300
PDB * pdb
Definition: pdb.h:374
Definition: hash.h:85
char other[MAXPDBANNOTATION]
Definition: pdb.h:383
char commonName[MAXPDBANNOTATION]
Definition: pdb.h:395
char element[8]
Definition: pdb.h:322
#define FORCEXML_PDB
Definition: pdb.h:586
BOOL blWritePDBAsPDBML(FILE *fp, PDB *pdb)
Definition: WritePDB.c:525
void blFreeHash(HASHTABLE *hashtable)
Definition: hash.c:293
int molid
Definition: pdb.h:382
void blWriteWholePDBHeaderNoRes(FILE *fp, WHOLEPDB *wpdb)
Definition: WritePDB.c:1809
int blGetHashValueInt(HASHTABLE *hashtable, char *key)
Definition: hash.c:551
Include file for fsscanf()
void blWriteTerCard(FILE *fp, PDB *p)
Definition: WritePDB.c:382
#define TRUE
Definition: macros.h:219
BOOL blHashKeyDefined(HASHTABLE *hashtable, char *key)
Definition: hash.c:775
#define FORCEXML_NOFORCE
Definition: pdb.h:585
int formal_charge
Definition: pdb.h:311
Definition: pdb.h:380
char ec[MAXPDBANNOTATION]
Definition: pdb.h:383
void blWriteGromosPDBRecord(FILE *fp, PDB *pdb)
Definition: WritePDB.c:1517
int taxid
Definition: pdb.h:398
char atnam_raw[8]
Definition: pdb.h:317
void blWriteWholePDBTrailer(FILE *fp, WHOLEPDB *wpdb, int numTer)
Definition: WritePDB.c:1643
STRINGLIST * blStoreString(STRINGLIST *StringList, char *string)
Definition: StoreString.c:131
BOOL blAreResiduePointersBonded(PDB *res1, PDB *res2, REAL tol)
Definition: BuildConect.c:394
BOOL blFormatCheckWritePDB(PDB *pdb)
Definition: WritePDB.c:269
PDB * blFindResidue(PDB *pdb, char *chain, int resnum, char *insert)
Definition: FindResidue.c:117
#define CHAINMATCH(chain1, chain2)
Definition: pdb.h:495
#define KILLLEADSPACES(y, x)
Definition: macros.h:408
#define FREELIST(y, z)
Definition: macros.h:264
char segid[8]
Definition: pdb.h:323
int gPDBXMLForce
REAL occ
Definition: pdb.h:300
#define ABS(x)
Definition: macros.h:235
char molecule[MAXPDBANNOTATION]
Definition: pdb.h:383
int blWritePDBAsPDBorGromos(FILE *fp, PDB *pdb, BOOL doGromos)
Definition: WritePDB.c:308
Type definitions for maths.
struct pdb_entry * conect[MAXCONECT]
Definition: pdb.h:308
char chain[blMAXCHAINLABEL]
Definition: pdb.h:321
char * string
Definition: general.h:85
char ** blGetPDBChainLabels(PDB *pdb, int *nChains)
void blWritePDBRecordAtnam(FILE *fp, PDB *pdb)
Definition: WritePDB.c:471
REAL x
Definition: pdb.h:300
char scientificName[MAXPDBANNOTATION]
Definition: pdb.h:395
REAL y
Definition: pdb.h:300
BOOL blGetHeaderWholePDB(WHOLEPDB *wpdb, char *header, int maxheader, char *date, int maxdate, char *pdbcode, int maxcode)
REAL bval
Definition: pdb.h:300
char insert[8]
Definition: pdb.h:320
char mutation[MAXPDBANNOTATION]
Definition: pdb.h:383