LCOV - code coverage report
Current view: top level - molfile - pdbplugin.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 87 211 41.2 %
Date: 2024-10-18 14:00:27 Functions: 5 14 35.7 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             : University of Illinois Open Source License
       3             : Copyright 2003 Theoretical and Computational Biophysics Group, 
       4             : All rights reserved.
       5             : 
       6             : Developed by:           Theoretical and Computational Biophysics Group
       7             :                         University of Illinois at Urbana-Champaign
       8             :                         http://www.ks.uiuc.edu/
       9             : 
      10             : Permission is hereby granted, free of charge, to any person obtaining a copy of
      11             : this software and associated documentation files (the Software), to deal with 
      12             : the Software without restriction, including without limitation the rights to 
      13             : use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
      14             : of the Software, and to permit persons to whom the Software is furnished to 
      15             : do so, subject to the following conditions:
      16             : 
      17             : Redistributions of source code must retain the above copyright notice, 
      18             : this list of conditions and the following disclaimers.
      19             : 
      20             : Redistributions in binary form must reproduce the above copyright notice, 
      21             : this list of conditions and the following disclaimers in the documentation 
      22             : and/or other materials provided with the distribution.
      23             : 
      24             : Neither the names of Theoretical and Computational Biophysics Group, 
      25             : University of Illinois at Urbana-Champaign, nor the names of its contributors 
      26             : may be used to endorse or promote products derived from this Software without 
      27             : specific prior written permission.
      28             : 
      29             : THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
      30             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
      31             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL 
      32             : THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 
      33             : OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
      34             : ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
      35             : OTHER DEALINGS WITH THE SOFTWARE.
      36             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      37             : #if defined(__PLUMED_HAS_MOLFILE_PLUGINS) && ! defined(__PLUMED_HAS_EXTERNAL_MOLFILE_PLUGINS)
      38             : /***************************************************************************
      39             :  *cr
      40             :  *cr            (C) Copyright 1995-2016 The Board of Trustees of the
      41             :  *cr                        University of Illinois
      42             :  *cr                         All Rights Reserved
      43             :  *cr
      44             :  ***************************************************************************/
      45             : 
      46             : /***************************************************************************
      47             :  * RCS INFORMATION:
      48             :  *
      49             :  *      $RCSfile: pdbplugin.c,v $
      50             :  *      $Author: johns $       $Locker:  $             $State: Exp $
      51             :  *      $Revision: 1.73 $       $Date: 2016/11/28 05:01:54 $
      52             :  *
      53             :  ***************************************************************************/
      54             : 
      55             : /*
      56             :  * PDB file format specifications:
      57             :  *   http://www.rcsb.org/pdb/static.do?p=file_formats/pdb/index.html
      58             :  */
      59             : 
      60             : #include "largefiles.h"   /* platform dependent 64-bit file I/O defines */
      61             : 
      62             : #include "molfile_plugin.h"
      63             : #include "readpdb.h"
      64             : #include "periodic_table.h"
      65             : #include <stdio.h>
      66             : #include <stdlib.h>
      67             : #include <string.h>
      68             : 
      69             : namespace PLMD{
      70             : namespace molfile{
      71             : 
      72             : /*
      73             :  * API functions start here
      74             :  */
      75             : 
      76             : typedef struct {
      77             :   FILE *fd;
      78             :   int first_frame;
      79             :   int natoms;
      80             :   molfile_atom_t *atomlist;
      81             :   molfile_metadata_t *meta;
      82             :   int nconect;
      83             :   int nbonds, maxbnum;
      84             :   int *from, *to, *idxmap;
      85             : } pdbdata;
      86             : 
      87          57 : static void *open_pdb_read(const char *filepath, const char *filetype, 
      88             :     int *natoms) {
      89             :   FILE *fd;
      90             :   pdbdata *pdb;
      91             :   char pdbstr[PDB_BUFFER_LENGTH];
      92             :   int indx, nconect;
      93             : 
      94          57 :   fd = fopen(filepath, "r");
      95          57 :   if (!fd) 
      96             :     return NULL;
      97          57 :   pdb = (pdbdata *)malloc(sizeof(pdbdata));
      98          57 :   pdb->fd = fd;
      99          57 :   pdb->meta = (molfile_metadata_t *) malloc(sizeof(molfile_metadata_t));
     100             :   memset(pdb->meta, 0, sizeof(molfile_metadata_t));
     101             : 
     102             :   pdb->meta->remarklen = 0;
     103             :   pdb->meta->remarks = NULL;
     104             : 
     105          57 :   *natoms=0;
     106             :   nconect=0;
     107             :   do {
     108      112709 :     indx = read_pdb_record(pdb->fd, pdbstr);
     109      112709 :     if (indx == PDB_ATOM) {
     110      111941 :       *natoms += 1;
     111         768 :     } else if (indx == PDB_CONECT) {
     112           0 :       nconect++;
     113         768 :     } else if (indx == PDB_HEADER) {
     114           0 :       get_pdb_header(pdbstr, pdb->meta->accession, pdb->meta->date, NULL);
     115           0 :       if (strlen(pdb->meta->accession) > 0) 
     116           0 :         strcpy(pdb->meta->database, "PDB");
     117         768 :     } else if (indx == PDB_REMARK || indx == PDB_CONECT || indx == PDB_UNKNOWN) {
     118         676 :       int len=strlen(pdbstr);
     119         676 :       int newlen = len + pdb->meta->remarklen;
     120             : 
     121         676 :       char *newstr=(char*)realloc(pdb->meta->remarks, newlen + 1);
     122         676 :       if (newstr != NULL) {
     123         676 :         pdb->meta->remarks = newstr;
     124         676 :         pdb->meta->remarks[pdb->meta->remarklen] = '\0';
     125         676 :         memcpy(pdb->meta->remarks + pdb->meta->remarklen, pdbstr, len);
     126         676 :         pdb->meta->remarks[newlen] = '\0';
     127         676 :         pdb->meta->remarklen = newlen;
     128             :       }
     129             :     }
     130             :  
     131      112709 :   } while (indx != PDB_END && indx != PDB_EOF);
     132             : 
     133             :   /* If no atoms were found, this is probably not a PDB file! */
     134          57 :   if (!*natoms) {
     135           0 :     fprintf(stderr, "PDB file '%s' contains no atoms.\n", filepath);
     136           0 :     if (pdb->meta->remarks != NULL)
     137           0 :       free(pdb->meta->remarks);
     138           0 :     if (pdb->meta != NULL)
     139           0 :       free(pdb->meta);
     140           0 :     free(pdb);
     141           0 :     return NULL;
     142             :   }
     143             : 
     144          57 :   rewind(pdb->fd); /* if ok, rewind file and prepare to parse it for real */
     145          57 :   pdb->natoms = *natoms;
     146          57 :   pdb->nconect = nconect;
     147          57 :   pdb->nbonds = 0;
     148          57 :   pdb->maxbnum = 0;
     149          57 :   pdb->from = NULL;
     150          57 :   pdb->to = NULL;
     151          57 :   pdb->idxmap = NULL;
     152          57 :   pdb->atomlist = NULL;
     153             : 
     154             : #if defined(VMDUSECONECTRECORDS)
     155             :   /* allocate atom index translation table if we have 99,999 atoms or less */
     156             :   /* and we have conect records to process                                 */
     157          57 :   if (pdb->natoms < 100000 && pdb->nconect > 0) {
     158           0 :     pdb->idxmap = (int *) malloc(100000 * sizeof(int));
     159             :     memset(pdb->idxmap, 0, 100000 * sizeof(int));
     160             :   }
     161             : #endif
     162             :  
     163             :   return pdb; 
     164             : }
     165             : 
     166           0 : static int read_pdb_structure(void *mydata, int *optflags, 
     167             :     molfile_atom_t *atoms) { 
     168             :   pdbdata *pdb = (pdbdata *)mydata;
     169             :   molfile_atom_t *atom;
     170             :   char pdbrec[PDB_BUFFER_LENGTH];
     171             :   int i, rectype, atomserial, pteidx;
     172             :   char ridstr[8];
     173             :   char elementsymbol[3];
     174             :   int badptecount = 0;
     175           0 :   long fpos = ftell(pdb->fd);
     176             : 
     177           0 :   *optflags = MOLFILE_INSERTION | MOLFILE_OCCUPANCY | MOLFILE_BFACTOR |
     178             :               MOLFILE_ALTLOC | MOLFILE_ATOMICNUMBER | MOLFILE_BONDSSPECIAL;
     179             : 
     180             :   i = 0;
     181             :   do {
     182           0 :     rectype = read_pdb_record(pdb->fd, pdbrec);
     183           0 :     switch (rectype) {
     184           0 :     case PDB_ATOM:
     185           0 :       atom = atoms+i;
     186           0 :       get_pdb_fields(pdbrec, strlen(pdbrec), &atomserial, 
     187           0 :           atom->name, atom->resname, atom->chain, atom->segid, 
     188           0 :           ridstr, atom->insertion, atom->altloc, elementsymbol,
     189             :           NULL, NULL, NULL, &atom->occupancy, &atom->bfactor);
     190             : 
     191           0 :       if (pdb->idxmap != NULL && atomserial < 100000) {
     192           0 :         pdb->idxmap[atomserial] = i; /* record new serial number translation */ 
     193             :       }
     194             :  
     195           0 :       atom->resid = atoi(ridstr);
     196             : 
     197             :       /* determine atomic number from the element symbol */
     198           0 :       pteidx = get_pte_idx_from_string(elementsymbol);
     199           0 :       atom->atomicnumber = pteidx;
     200           0 :       if (pteidx != 0) {
     201           0 :         atom->mass = get_pte_mass(pteidx);
     202           0 :         atom->radius = get_pte_vdw_radius(pteidx);
     203             :       } else {
     204           0 :         badptecount++; /* unrecognized element */
     205             :       }
     206             :  
     207           0 :       strcpy(atom->type, atom->name);
     208           0 :       i++;
     209           0 :       break;
     210             : 
     211           0 :     case PDB_CONECT:
     212             :       /* only read CONECT records for structures where we know they can */
     213             :       /* be valid for all of the atoms in the structure                 */
     214           0 :       if (pdb->idxmap != NULL) {
     215           0 :         get_pdb_conect(pdbrec, pdb->natoms, pdb->idxmap, 
     216             :                        &pdb->maxbnum, &pdb->nbonds, &pdb->from, &pdb->to);
     217             :       }
     218             :       break;
     219             : 
     220             :     default:
     221             :       /* other record types are ignored in the structure callback */
     222             :       /* and are dealt with in the timestep callback or elsewhere */
     223             :       break;
     224             :     }
     225           0 :   } while (rectype != PDB_END && rectype != PDB_EOF);
     226             : 
     227           0 :   fseek(pdb->fd, fpos, SEEK_SET);
     228             : 
     229             :   /* if all atoms are recognized, set the mass and radius flags too,  */
     230             :   /* otherwise let VMD guess these for itself using it's own methods  */
     231           0 :   if (badptecount == 0) {
     232           0 :     *optflags |= MOLFILE_MASS | MOLFILE_RADIUS;
     233             :   }
     234             : 
     235           0 :   return MOLFILE_SUCCESS;
     236             : }
     237             : 
     238           0 : static int read_bonds(void *v, int *nbonds, int **fromptr, int **toptr, 
     239             :                       float ** bondorder,int **bondtype, 
     240             :                       int *nbondtypes, char ***bondtypename) {
     241             :   pdbdata *pdb = (pdbdata *)v;
     242             :   
     243           0 :   *nbonds = 0;
     244           0 :   *fromptr = NULL;
     245           0 :   *toptr = NULL;
     246           0 :   *bondorder = NULL; /* PDB files don't have bond order information */
     247           0 :   *bondtype = NULL;
     248           0 :   *nbondtypes = 0;
     249           0 :   *bondtypename = NULL;
     250             : 
     251             : /* The newest plugin API allows us to return CONECT records as 
     252             :  * additional bonds above and beyond what the distance search returns.
     253             :  * Without that feature, we otherwise have to check completeness and
     254             :  * ignore them if they don't look to be fully specified for this molecule */
     255             : #if !defined(MOLFILE_BONDSSPECIAL)
     256             :   if (pdb->natoms >= 100000) {
     257             :     printf("pdbplugin) Warning: more than 99,999 atoms, ignored CONECT records\n");
     258             :     return MOLFILE_SUCCESS;
     259             :   } else if (((float) pdb->nconect / (float) pdb->natoms) <= 0.85) {
     260             :     printf("pdbplugin) Warning: Probable incomplete bond structure specified,\n");
     261             :     printf("pdbplugin)          ignoring CONECT records\n");
     262             :     return MOLFILE_SUCCESS;
     263             :   } else if (pdb->nconect == 0) {
     264             :     return MOLFILE_SUCCESS;
     265             :   }
     266             : #endif
     267             : 
     268           0 :   *nbonds = pdb->nbonds;
     269           0 :   *fromptr = pdb->from;
     270           0 :   *toptr = pdb->to;
     271             : 
     272           0 :   return MOLFILE_SUCCESS;
     273             : }
     274             : 
     275             : 
     276             : /* 
     277             :  * 
     278             :  */
     279         130 : static int read_next_timestep(void *v, int natoms, molfile_timestep_t *ts) {
     280             :   pdbdata *pdb = (pdbdata *)v;
     281             :   char pdbstr[PDB_BUFFER_LENGTH];
     282             :   int indx, i;
     283             :   float *x, *y, *z;
     284             :   float occup, bfac;
     285         130 :   if (pdb->natoms == 0) 
     286             :     return MOLFILE_ERROR; /* EOF */
     287         130 :   if (ts) {
     288         130 :     x = ts->coords;
     289         130 :     y = x+1;
     290         130 :     z = x+2;
     291             :   } else {
     292             :     x = y = z = 0;
     293             :   } 
     294             :   i = 0;
     295             :   do {
     296      127148 :     indx = read_pdb_record(pdb->fd, pdbstr);
     297      127148 :     if((indx == PDB_END || indx == PDB_EOF) && (i < pdb->natoms)) {
     298             :       return MOLFILE_ERROR;
     299      127091 :     } else if(indx == PDB_ATOM) {
     300      123714 :       if(i++ >= pdb->natoms) {
     301             :         break;      
     302             :       }
     303             :       /* just get the coordinates, and store them */
     304      123714 :       if (ts) {
     305      123714 :         get_pdb_coordinates(pdbstr, x, y, z, &occup, &bfac);
     306      123714 :         x += 3;
     307      123714 :         y += 3;
     308      123714 :         z += 3;
     309             :       } 
     310        3377 :     } else if (indx == PDB_CRYST1) {
     311          37 :       if (ts) {
     312          37 :         get_pdb_cryst1(pdbstr, &ts->alpha, &ts->beta, &ts->gamma,
     313             :                                &ts->A, &ts->B, &ts->C);
     314             :       }
     315             :     }
     316      127091 :   } while(!(indx == PDB_END || indx == PDB_EOF));
     317             : 
     318             :   return MOLFILE_SUCCESS;
     319             : }
     320             : 
     321          57 : static void close_pdb_read(void *v) { 
     322             :   pdbdata *pdb = (pdbdata *)v;
     323          57 :   if (pdb->fd != NULL)
     324          57 :     fclose(pdb->fd);
     325          57 :   if (pdb->idxmap != NULL)
     326           0 :     free(pdb->idxmap);
     327          57 :   if (pdb->meta->remarks != NULL)
     328          46 :     free(pdb->meta->remarks);
     329          57 :   if (pdb->meta != NULL) 
     330          57 :     free(pdb->meta);
     331          57 :   free(pdb);
     332          57 : }
     333             : 
     334           0 : static void *open_file_write(const char *path, const char *filetype, 
     335             :     int natoms) {
     336             : 
     337             :   FILE *fd;
     338             :   pdbdata *pdb;
     339           0 :   fd = fopen(path, "w");
     340           0 :   if (!fd) {
     341           0 :     fprintf(stderr, "Unable to open file %s for writing\n", path);
     342           0 :     return NULL;
     343             :   }
     344           0 :   pdb = (pdbdata *)malloc(sizeof(pdbdata));
     345           0 :   pdb->fd = fd;
     346           0 :   pdb->natoms = natoms; 
     347           0 :   pdb->atomlist = NULL;
     348           0 :   pdb->first_frame = 1;
     349           0 :   return pdb;
     350             : }
     351             :  
     352           0 : static int write_structure(void *v, int optflags, 
     353             :     const molfile_atom_t *atoms) {
     354             : 
     355             :   int i;
     356             :   pdbdata *pdb = (pdbdata *)v;
     357           0 :   int natoms = pdb->natoms;
     358           0 :   pdb->atomlist = (molfile_atom_t *)malloc(natoms*sizeof(molfile_atom_t));
     359             :   memcpy(pdb->atomlist, atoms, natoms*sizeof(molfile_atom_t));
     360             : 
     361             :   /* If occ, bfactor, and insertion aren't given, we assign defaultvalues. */
     362           0 :   if (!(optflags & MOLFILE_OCCUPANCY)) {
     363           0 :     for (i=0; i<natoms; i++) pdb->atomlist[i].occupancy = 0.0f;
     364             :   }
     365           0 :   if (!(optflags & MOLFILE_BFACTOR)) {
     366           0 :     for (i=0; i<natoms; i++) pdb->atomlist[i].bfactor= 0.0f;
     367             :   }
     368           0 :   if (!(optflags & MOLFILE_INSERTION)) {
     369           0 :     for (i=0; i<natoms; i++) {
     370           0 :       pdb->atomlist[i].insertion[0] =' ';
     371           0 :       pdb->atomlist[i].insertion[1] ='\0';
     372             :     }
     373             :   }
     374           0 :   if (!(optflags & MOLFILE_ALTLOC)) {
     375           0 :     for (i=0; i<natoms; i++) {
     376           0 :       pdb->atomlist[i].altloc[0]=' ';
     377           0 :       pdb->atomlist[i].altloc[1]='\0';
     378             :     }
     379             :   }
     380           0 :   if (!(optflags & MOLFILE_ATOMICNUMBER)) {
     381           0 :     for (i=0; i<natoms; i++) pdb->atomlist[i].atomicnumber = 0;
     382             :   }
     383             : 
     384             :   /* TODO: put bonds into CONECT records? */
     385           0 :   return MOLFILE_SUCCESS;
     386             : }
     387             : 
     388             : /* SEQRES records look like this:
     389             : 
     390             : COLUMNS        DATA TYPE       FIELD         DEFINITION
     391             : ---------------------------------------------------------------------------------
     392             :  1 -  6        Record name     "SEQRES"
     393             : 
     394             :  9 - 10        Integer         serNum        Serial number of the SEQRES record
     395             :                                              for the current chain.  Starts at 1
     396             :                                              and increments by one each line.
     397             :                                              Reset to 1 for each chain.
     398             : 
     399             : 12             Character       chainID       Chain identifier.  This may be any
     400             :                                              single legal character, including a
     401             :                                              blank which is used if there is
     402             :                                              only one chain.
     403             : 
     404             : 14 - 17        Integer         numRes        Number of residues in the chain.
     405             :                                              This value is repeated on every
     406             :                                              record.
     407             : 
     408             : 20 - 22        Residue name    resName       Residue name.
     409             : 
     410             : 24 - 26        Residue name    resName       Residue name.
     411             : 
     412             : ... and so forth out to 68-70, for a total of 13 in each line (except possibly
     413             : the last.
     414             : 
     415             : source:
     416             : http://www.rcsb.org/pdb/file_formats/pdb/pdbguide2.2/part_35.html
     417             : */
     418             : 
     419             : /*
     420             :  * However, we don't use them right now because of several issues that
     421             :  * can't presently be resolved satisfactorily in VMD:
     422             : 
     423             : According to the RCSB, SEQRES records have to contain all residues, not
     424             : just those in the structure, which means VMD will usually produce incorrect
     425             : output and there's nothing we can do about it.  The RCSB actually specifies
     426             : that all residues in the chain have to present in the SEQRES records, even
     427             : if they're not in the structure.
     428             :   
     429             : We can never know which residues to output.  Our current system of outputting   
     430             : everything is just terrible when you have 20,000 waters in your system; we
     431             : have to fix this immediately.  We could almost get away with making a hash
     432             : table of the names of protein and nucleic acid residues and only write chains
     433             : containing those residues.  However, there's this little snippet from the
     434             : specification:
     435             :   
     436             : * Heterogens which are integrated into the backbone of the chain are listed
     437             :   as being part of the chain and are included in the SEQRES records for
     438             :   that chain.
     439             :   
     440             : That means that we can never know what might appear in the sequence unless we
     441             : also read HET records and keep track of them in VMD as well.  We shouldn't 
     442             : get people depending on such fallible SEQRES records.
     443             :   
     444             : And of course, there's the fact that no other program that we know of besides   
     445             : CE needs these SEQRES records.
     446             : 
     447             :  * Uncomment the write_seqres line in write_timestep to turn them back on.
     448             :  */
     449             : 
     450             : 
     451             : #if 0
     452             : static void write_seqres(FILE * fd, int natoms, const molfile_atom_t *atomlist) {
     453             :   int i=0;
     454             :   while (i < natoms) {
     455             :     int k, serNum;
     456             :     int j = i;
     457             :     int ires, nres = 1;
     458             :     int resid = atomlist[i].resid;
     459             :     /* Count up the number of residues in the chain */
     460             :     const char *chain = atomlist[i].chain;
     461             :     while (j < natoms && !strcmp(chain, atomlist[j].chain)) {
     462             :       if (resid != atomlist[j].resid) {
     463             :         nres++;
     464             :         resid = atomlist[j].resid;
     465             :       }
     466             :       j++;
     467             :     }
     468             :     /* There are nres residues in the chain, from atoms i to j. */
     469             :     serNum = 1;
     470             :     ires = 1;
     471             :     resid = atomlist[i].resid;
     472             :     fprintf(fd, "SEQRES  %2d %c %4d  ",  serNum, chain[0], nres);
     473             :     serNum = 2;
     474             :     fprintf(fd, "%3s ", atomlist[i].resname);
     475             :     for (k=i; k<j; k++) {
     476             :       if (resid != atomlist[k].resid) {
     477             :         resid = atomlist[k].resid;
     478             :         if (!(ires % 13)) {
     479             :           fprintf(fd, "\nSEQRES  %2d %c %4d  ",  serNum, chain[0], nres);
     480             :           serNum++;
     481             :         }
     482             :         fprintf(fd, "%3s ", atomlist[k].resname);
     483             :         ires++;
     484             :       }
     485             :     }
     486             :     i = j;
     487             :     fprintf(fd, "\n");
     488             :   }
     489             : }
     490             : #endif
     491             : 
     492             : /*
     493             : CRYST1 records look like this:
     494             : The CRYST1 record presents the unit cell parameters, space group, and Z value. If the structure was not determined by crystallographic means, CRYST1 simply defines a unit cube. 
     495             : 
     496             : 
     497             : Record Format 
     498             : 
     499             : COLUMNS       DATA TYPE      FIELD         DEFINITION
     500             : -------------------------------------------------------------
     501             :  1 -  6       Record name    "CRYST1"
     502             : 
     503             :  7 - 15       Real(9.3)      a             a (Angstroms).
     504             : 
     505             : 16 - 24       Real(9.3)      b             b (Angstroms).
     506             : 
     507             : 25 - 33       Real(9.3)      c             c (Angstroms).
     508             : 
     509             : 34 - 40       Real(7.2)      alpha         alpha (degrees).
     510             : 
     511             : 41 - 47       Real(7.2)      beta          beta (degrees).
     512             : 
     513             : 48 - 54       Real(7.2)      gamma         gamma (degrees).
     514             : 
     515             : 56 - 66       LString        sGroup        Space group.
     516             : 
     517             : 67 - 70       Integer        z             Z value.
     518             : 
     519             : * If the coordinate entry describes a structure determined by a technique
     520             : other than crystallography, CRYST1 contains a = b = c = 1.0, alpha =
     521             : beta = gamma = 90 degrees, space group = P 1, and Z = 1.
     522             : 
     523             : We will use "P 1" and "1" for space group and z value, as recommended, but
     524             : we'll populate the other fields with the unit cell information we do have.
     525             : 
     526             : */
     527             :   
     528           0 : static void write_cryst1(FILE *fd, const molfile_timestep_t *ts) {
     529           0 :   fprintf(fd, "CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f P 1           1\n", 
     530           0 :     ts->A, ts->B, ts->C, ts->alpha, ts->beta, ts->gamma);
     531           0 : }
     532             : 
     533             : 
     534           0 : static int write_timestep(void *v, const molfile_timestep_t *ts) {
     535             :   pdbdata *pdb = (pdbdata *)v; 
     536             :   const molfile_atom_t *atom;
     537             :   const float *pos;
     538             :   int i;
     539             :   char elementsymbol[3];
     540             : 
     541           0 :   if (pdb->natoms == 0)
     542             :     return MOLFILE_SUCCESS;
     543             : 
     544           0 :   if (pdb->first_frame) {
     545             :     /* Turn off SEQRES writing for now; see comments above.
     546             :     write_seqres(pdb->fd, pdb->natoms, pdb->atomlist);
     547             :     */
     548           0 :     write_cryst1(pdb->fd, ts);
     549           0 :     pdb->first_frame = 0;
     550             :   }
     551           0 :   atom = pdb->atomlist;
     552           0 :   pos = ts->coords;
     553           0 :   for (i=0; i<pdb->natoms; i++) {
     554             :     /*
     555             :      * The 8.3 format for position, occupancy, and bfactor permits values 
     556             :      * only in the range of -999.9994 to 9999.9994 (so that they round
     557             :      * to the range [-999.999, 9999.999]).  If values fall outside of that
     558             :      * range, fail and emit an error message rather than generate a
     559             :      * misformatted PDB file.
     560             :      */
     561             : #define PDBBAD(x) ((x) < -999.9994f || (x) > 9999.9994f)
     562           0 :     if (PDBBAD(pos[0]) || PDBBAD(pos[1]) || PDBBAD(pos[2]) ||
     563           0 :                 PDBBAD(atom->occupancy) || PDBBAD(atom->bfactor)) {
     564           0 :             fprintf(stderr, "PDB WRITE ERROR: Position, occupancy, or b-factor (beta) for atom %d\n", i);
     565           0 :       fprintf(stderr, "                 cannot be written in PDB format.\n");
     566           0 :       fprintf(stderr, "                 File will be truncated.\n");
     567           0 :       return MOLFILE_ERROR;
     568             :     }
     569             : 
     570             :     /* check the atomicnumber and format the atomic element symbol string */
     571           0 :     strcpy(elementsymbol, (atom->atomicnumber < 1) ? "  " : get_pte_label(atom->atomicnumber));
     572           0 :     elementsymbol[0] = toupper(elementsymbol[0]);
     573           0 :     elementsymbol[1] = toupper(elementsymbol[1]);
     574             :  
     575           0 :     if (!write_raw_pdb_record(pdb->fd,  
     576           0 :         "ATOM  ", i+1, atom->name, atom->resname, atom->resid, 
     577           0 :         atom->insertion, atom->altloc, elementsymbol,
     578             :         pos[0], pos[1], pos[2], 
     579           0 :         atom->occupancy, atom->bfactor, atom->chain, atom->segid)) {
     580           0 :       fprintf(stderr, 
     581             :           "PDB: Error encountered writing atom %d; file may be incomplete.\n",
     582             :           i+1);
     583           0 :       return MOLFILE_ERROR;
     584             :     }
     585           0 :     ++atom;
     586           0 :     pos += 3;
     587             :   }
     588           0 :   fprintf(pdb->fd, "END\n");
     589             : 
     590             :   return MOLFILE_SUCCESS;
     591             : }
     592             :  
     593           0 : static void close_file_write(void *v) {
     594             :   pdbdata *pdb = (pdbdata *)v; 
     595           0 :   fclose(pdb->fd);
     596           0 :   free(pdb->atomlist);
     597           0 :   free(pdb);
     598           0 : }
     599             : 
     600           0 : static int read_molecule_metadata(void *v, molfile_metadata_t **metadata) {
     601             :   pdbdata *pdb = (pdbdata *)v; 
     602           0 :   *metadata = pdb->meta;
     603           0 :   return MOLFILE_SUCCESS;
     604             : }
     605             : 
     606             : /*
     607             :  * Initialization stuff down here
     608             :  */
     609             : 
     610             : static molfile_plugin_t plugin;
     611             :  
     612       10632 : VMDPLUGIN_API int VMDPLUGIN_init() {
     613             :   memset(&plugin, 0, sizeof(molfile_plugin_t));
     614       10632 :   plugin.abiversion = vmdplugin_ABIVERSION;
     615       10632 :   plugin.type = MOLFILE_PLUGIN_TYPE;
     616       10632 :   plugin.name = "pdb";
     617       10632 :   plugin.prettyname = "PDB";
     618       10632 :   plugin.author = "Justin Gullingsrud, John Stone";
     619       10632 :   plugin.majorv = 1;
     620       10632 :   plugin.minorv = 16;
     621       10632 :   plugin.is_reentrant = VMDPLUGIN_THREADSAFE;
     622       10632 :   plugin.filename_extension = "pdb,ent";
     623       10632 :   plugin.open_file_read = open_pdb_read;
     624       10632 :   plugin.read_structure = read_pdb_structure;
     625       10632 :   plugin.read_bonds = read_bonds;
     626       10632 :   plugin.read_next_timestep = read_next_timestep;
     627       10632 :   plugin.close_file_read = close_pdb_read;
     628       10632 :   plugin.open_file_write = open_file_write;
     629       10632 :   plugin.write_structure = write_structure;
     630       10632 :   plugin.write_timestep = write_timestep;
     631       10632 :   plugin.close_file_write = close_file_write;
     632       10632 :   plugin.read_molecule_metadata = read_molecule_metadata;
     633       10632 :   return VMDPLUGIN_SUCCESS;
     634             : }
     635             : 
     636       10632 : VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
     637       10632 :   (*cb)(v, (vmdplugin_t *)&plugin);
     638       10632 :   return VMDPLUGIN_SUCCESS;
     639             : }
     640             : 
     641           0 : VMDPLUGIN_API int VMDPLUGIN_fini() {
     642           0 :   return VMDPLUGIN_SUCCESS;
     643             : }
     644             : 
     645             : }
     646             : }
     647             : 
     648             : #endif

Generated by: LCOV version 1.16