3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
10 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12 * Copyright (c) 2001-2004, The GROMACS development team,
13 * check out http://www.gromacs.org for more information.
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * If you want to redistribute modifications, please consider that
21 * scientific software is very special. Version control is crucial -
22 * bugs must be traceable. We will be happy to consider code for
23 * inclusion in the official distribution, but derived work must not
24 * be called official GROMACS. Details are found in the README & COPYING
25 * files - if they are missing, get the official version at www.gromacs.org.
27 * To help us fund GROMACS development, we humbly ask that you cite
28 * the papers on the package - you can find them in the top README file.
30 * For more info, check our website at http://www.gromacs.org
33 * GROningen Mixture of Alchemy and Childrens' Stories
60 typedef struct gmx_conect_t {
63 gmx_conection_t *conect;
66 static const char *pdbtp[epdbNR]={
67 "ATOM ","HETATM", "ANISOU", "CRYST1",
68 "COMPND", "MODEL", "ENDMDL", "TER", "HEADER", "TITLE", "REMARK",
73 /* this is not very good,
74 but these are only used in gmx_trjconv and gmx_editconv */
75 static gmx_bool bWideFormat=FALSE;
76 #define REMARK_SIM_BOX "REMARK THIS IS A SIMULATION BOX"
78 void set_pdb_wide_format(gmx_bool bSet)
83 static void xlate_atomname_pdb2gmx(char *name)
89 if (length>3 && isdigit(name[0])) {
91 for(i=1; i<length; i++)
97 static void xlate_atomname_gmx2pdb(char *name)
103 if (length>3 && isdigit(name[length-1])) {
105 for(i=length-1; i>0; --i)
112 void gmx_write_pdb_box(FILE *out,int ePBC,matrix box)
114 real alpha,beta,gamma;
117 ePBC = guess_ePBC(box);
119 if (ePBC == epbcNONE)
122 if (norm2(box[YY])*norm2(box[ZZ])!=0)
123 alpha = RAD2DEG*acos(cos_angle_no_table(box[YY],box[ZZ]));
126 if (norm2(box[XX])*norm2(box[ZZ])!=0)
127 beta = RAD2DEG*acos(cos_angle_no_table(box[XX],box[ZZ]));
130 if (norm2(box[XX])*norm2(box[YY])!=0)
131 gamma = RAD2DEG*acos(cos_angle_no_table(box[XX],box[YY]));
134 fprintf(out,"REMARK THIS IS A SIMULATION BOX\n");
135 if (ePBC != epbcSCREW) {
136 fprintf(out,"CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f %-11s%4d\n",
137 10*norm(box[XX]),10*norm(box[YY]),10*norm(box[ZZ]),
138 alpha,beta,gamma,"P 1",1);
140 /* Double the a-vector length and write the correct space group */
141 fprintf(out,"CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f %-11s%4d\n",
142 20*norm(box[XX]),10*norm(box[YY]),10*norm(box[ZZ]),
143 alpha,beta,gamma,"P 21 1 1",1);
148 static void read_cryst1(char *line,int *ePBC,matrix box)
151 char sa[12],sb[12],sc[12],sg[SG_SIZE+1],ident;
152 double fa,fb,fc,alpha,beta,gamma,cosa,cosb,cosg,sing;
156 sscanf(line,"%*s%s%s%s%lf%lf%lf",sa,sb,sc,&alpha,&beta,&gamma);
159 if (strlen(line) >= 55) {
160 strncpy(sg,line+55,SG_SIZE);
166 sscanf(sg,"%c %d %d %d",&ident,&syma,&symb,&symc);
167 if (ident == 'P' && syma == 1 && symb <= 1 && symc <= 1) {
168 fc = strtod(sc,NULL)*0.1;
169 ePBC_file = (fc > 0 ? epbcXYZ : epbcXY);
171 if (ident == 'P' && syma == 21 && symb == 1 && symc == 1) {
172 ePBC_file = epbcSCREW;
180 fa = strtod(sa,NULL)*0.1;
181 fb = strtod(sb,NULL)*0.1;
182 fc = strtod(sc,NULL)*0.1;
183 if (ePBC_file == epbcSCREW) {
188 if ((alpha!=90.0) || (beta!=90.0) || (gamma!=90.0)) {
190 cosa = cos(alpha*DEG2RAD);
195 cosb = cos(beta*DEG2RAD);
200 cosg = cos(gamma*DEG2RAD);
201 sing = sin(gamma*DEG2RAD);
206 box[YY][XX] = fb*cosg;
207 box[YY][YY] = fb*sing;
208 box[ZZ][XX] = fc*cosb;
209 box[ZZ][YY] = fc*(cosa - cosb*cosg)/sing;
210 box[ZZ][ZZ] = sqrt(fc*fc
211 - box[ZZ][XX]*box[ZZ][XX] - box[ZZ][YY]*box[ZZ][YY]);
219 void write_pdbfile_indexed(FILE *out,const char *title,
220 t_atoms *atoms,rvec x[],
221 int ePBC,matrix box,char chainid,
222 int model_nr, atom_id nindex, atom_id index[],
223 gmx_conect conect, gmx_bool bTerSepChains)
225 gmx_conect_t *gc = (gmx_conect_t *)conect;
226 char resnm[6],nm[6],pdbform[128],pukestring[100];
228 int resind,resnr,type;
229 unsigned char resic,ch;
233 int chainnum,lastchainnum;
234 int lastresind,lastchainresind;
235 gmx_residuetype_t rt;
236 const char *p_restype;
237 const char *p_lastrestype;
239 gmx_residuetype_init(&rt);
241 bromacs(pukestring,99);
242 fprintf(out,"TITLE %s\n",(title && title[0])?title:pukestring);
244 fprintf(out,"REMARK This file does not adhere to the PDB standard\n");
245 fprintf(out,"REMARK As a result of, some programs may not like it\n");
247 if (box && ( norm2(box[XX]) || norm2(box[YY]) || norm2(box[ZZ]) ) ) {
248 gmx_write_pdb_box(out,ePBC,box);
250 if (atoms->pdbinfo) {
251 /* Check whether any occupancies are set, in that case leave it as is,
252 * otherwise set them all to one
255 for (ii=0; (ii<nindex) && bOccup; ii++) {
257 bOccup = bOccup && (atoms->pdbinfo[i].occup == 0.0);
263 fprintf(out,"MODEL %8d\n",model_nr>0 ? model_nr : 1);
265 lastchainresind = -1;
270 for (ii=0; ii<nindex; ii++) {
273 resind = atoms->atom[i].resind;
274 chainnum = atoms->resinfo[resind].chainnum;
275 p_lastrestype = p_restype;
276 gmx_residuetype_get_type(rt,*atoms->resinfo[resind].name,&p_restype);
278 /* Add a TER record if we changed chain, and if either the previous or this chain is protein/DNA/RNA. */
279 if( bTerSepChains && ii>0 && chainnum != lastchainnum)
281 /* Only add TER if the previous chain contained protein/DNA/RNA. */
282 if(gmx_residuetype_is_protein(rt,p_lastrestype) || gmx_residuetype_is_dna(rt,p_lastrestype) || gmx_residuetype_is_rna(rt,p_lastrestype))
284 fprintf(out,"TER\n");
286 lastchainnum = chainnum;
287 lastchainresind = lastresind;
290 strncpy(resnm,*atoms->resinfo[resind].name,sizeof(resnm)-1);
291 strncpy(nm,*atoms->atomname[i],sizeof(nm)-1);
292 /* rename HG12 to 2HG1, etc. */
293 xlate_atomname_gmx2pdb(nm);
294 resnr = atoms->resinfo[resind].nr;
295 resic = atoms->resinfo[resind].ic;
302 ch = atoms->resinfo[resind].chainid;
310 resnr = resnr % 10000;
311 if (atoms->pdbinfo) {
312 type = atoms->pdbinfo[i].type;
313 occup = bOccup ? 1.0 : atoms->pdbinfo[i].occup;
314 bfac = atoms->pdbinfo[i].bfac;
323 "%-6s%5u %-4.4s %3.3s %c%4d%c %10.5f%10.5f%10.5f%8.4f%8.4f %2s\n");
325 /* Check whether atomname is an element name */
326 if ((strlen(nm)<4) && (gmx_strcasecmp(nm,atoms->atom[i].elem) != 0))
327 strcpy(pdbform,get_pdbformat());
329 strcpy(pdbform,get_pdbformat4());
330 if (strlen(nm) > 4) {
332 if (nlongname < maxwln) {
333 fprintf(stderr,"WARNING: Writing out atom name (%s) longer than 4 characters to .pdb file\n",nm);
334 } else if (nlongname == maxwln) {
335 fprintf(stderr,"WARNING: More than %d long atom names, will not write more warnings\n",maxwln);
340 strcat(pdbform,"%6.2f%6.2f %2s\n");
342 fprintf(out,pdbform,pdbtp[type],(i+1)%100000,nm,resnm,ch,resnr,
343 (resic == '\0') ? ' ' : resic,
344 10*x[i][XX],10*x[i][YY],10*x[i][ZZ],occup,bfac,atoms->atom[i].elem);
345 if (atoms->pdbinfo && atoms->pdbinfo[i].bAnisotropic) {
346 fprintf(out,"ANISOU%5u %-4.4s%3.3s %c%4d%c %7d%7d%7d%7d%7d%7d\n",
347 (i+1)%100000,nm,resnm,ch,resnr,
348 (resic == '\0') ? ' ' : resic,
349 atoms->pdbinfo[i].uij[0],atoms->pdbinfo[i].uij[1],
350 atoms->pdbinfo[i].uij[2],atoms->pdbinfo[i].uij[3],
351 atoms->pdbinfo[i].uij[4],atoms->pdbinfo[i].uij[5]);
355 fprintf(out,"TER\n");
356 fprintf(out,"ENDMDL\n");
359 /* Write conect records */
360 for(i=0; (i<gc->nconect); i++) {
361 fprintf(out,"CONECT%5d%5d\n",gc->conect[i].ai+1,gc->conect[i].aj+1);
366 void write_pdbfile(FILE *out,const char *title, t_atoms *atoms,rvec x[],
367 int ePBC,matrix box,char chainid,int model_nr,gmx_conect conect,gmx_bool bTerSepChains)
371 snew(index,atoms->nr);
372 for(i=0; i<atoms->nr; i++)
374 write_pdbfile_indexed(out,title,atoms,x,ePBC,box,chainid,model_nr,
375 atoms->nr,index,conect,bTerSepChains);
379 int line2type(char *line)
388 for(k=0; (k<epdbNR); k++)
389 if (strncmp(type,pdbtp[k],strlen(pdbtp[k])) == 0)
395 static void read_anisou(char line[],int natom,t_atoms *atoms)
399 char anr[12],anm[12];
403 for(k=0; (k<5); k++,j++) anr[k]=line[j];
406 for(k=0; (k<4); k++,j++) anm[k]=line[j];
410 /* Strip off spaces */
413 /* Search backwards for number and name only */
414 atomnr = strtol(anr, NULL, 10);
415 for(i=natom-1; (i>=0); i--)
416 if ((strcmp(anm,*(atoms->atomname[i])) == 0) &&
417 (atomnr == atoms->pdbinfo[i].atomnr))
420 fprintf(stderr,"Skipping ANISOU record (atom %s %d not found)\n",
423 if (sscanf(line+29,"%d%d%d%d%d%d",
424 &atoms->pdbinfo[i].uij[U11],&atoms->pdbinfo[i].uij[U22],
425 &atoms->pdbinfo[i].uij[U33],&atoms->pdbinfo[i].uij[U12],
426 &atoms->pdbinfo[i].uij[U13],&atoms->pdbinfo[i].uij[U23])
428 atoms->pdbinfo[i].bAnisotropic = TRUE;
431 fprintf(stderr,"Invalid ANISOU record for atom %d\n",i);
432 atoms->pdbinfo[i].bAnisotropic = FALSE;
437 void get_pdb_atomnumber(t_atoms *atoms,gmx_atomprop_t aps)
439 int i,atomnumber,len;
441 char anm[6],anm_copy[6],*ptr;
445 if (!atoms->pdbinfo) {
446 gmx_incons("Trying to deduce atomnumbers when no pdb information is present");
448 for(i=0; (i<atoms->nr); i++) {
449 strcpy(anm,atoms->pdbinfo[i].atomnm);
450 strcpy(anm_copy,atoms->pdbinfo[i].atomnm);
453 if ((anm[0] != ' ') && ((len <=2) || ((len > 2) && !isdigit(anm[2])))) {
455 if (gmx_atomprop_query(aps,epropElement,"???",anm_copy,&eval))
456 atomnumber = gmx_nint(eval);
459 if (gmx_atomprop_query(aps,epropElement,"???",anm_copy,&eval))
460 atomnumber = gmx_nint(eval);
463 if (atomnumber == NOTSET) {
465 while ((k < strlen(anm)) && (isspace(anm[k]) || isdigit(anm[k])))
467 anm_copy[0] = anm[k];
469 if (gmx_atomprop_query(aps,epropElement,"???",anm_copy,&eval))
470 atomnumber = gmx_nint(eval);
472 atoms->atom[i].atomnumber = atomnumber;
473 ptr = gmx_atomprop_element(aps,atomnumber);
474 strncpy(atoms->atom[i].elem,ptr==NULL ? "" : ptr,4);
476 fprintf(debug,"Atomnumber for atom '%s' is %d\n",anm,atomnumber);
480 static int read_atom(t_symtab *symtab,
481 char line[],int type,int natom,
482 t_atoms *atoms,rvec x[],int chainnum,gmx_bool bChange)
487 char anr[12],anm[12],anm_copy[12],altloc,resnm[12],rnr[12];
488 char xc[12],yc[12],zc[12],occup[12],bfac[12];
491 int resnr,atomnumber;
493 if (natom>=atoms->nr)
494 gmx_fatal(FARGS,"\nFound more atoms (%d) in pdb file than expected (%d)",
499 for(k=0; (k<5); k++,j++) anr[k]=line[j];
503 for(k=0; (k<4); k++,j++) anm[k]=line[j];
505 strcpy(anm_copy,anm);
511 for(k=0; (k<4); k++,j++)
519 for(k=0; (k<4); k++,j++) {
524 resnr = strtol(rnr, NULL, 10);
528 /* X,Y,Z Coordinate */
529 for(k=0; (k<8); k++,j++) xc[k]=line[j];
531 for(k=0; (k<8); k++,j++) yc[k]=line[j];
533 for(k=0; (k<8); k++,j++) zc[k]=line[j];
537 for(k=0; (k<6); k++,j++) occup[k]=line[j];
541 for(k=0; (k<7); k++,j++) bfac[k]=line[j];
545 atomn=&(atoms->atom[natom]);
547 atoms->resinfo[atoms->atom[natom-1].resind].nr != resnr ||
548 atoms->resinfo[atoms->atom[natom-1].resind].ic != resic ||
549 (strcmp(*atoms->resinfo[atoms->atom[natom-1].resind].name,resnm) != 0))
554 atomn->resind = atoms->atom[natom-1].resind + 1;
556 atoms->nres = atomn->resind + 1;
557 t_atoms_set_resinfo(atoms,natom,symtab,resnm,resnr,resic,chainnum,chainid);
561 atomn->resind = atoms->atom[natom-1].resind;
564 xlate_atomname_pdb2gmx(anm);
566 atoms->atomname[natom]=put_symtab(symtab,anm);
569 atomn->atomnumber = atomnumber;
570 atomn->elem[0] = '\0';
572 x[natom][XX]=strtod(xc,NULL)*0.1;
573 x[natom][YY]=strtod(yc,NULL)*0.1;
574 x[natom][ZZ]=strtod(zc,NULL)*0.1;
575 if (atoms->pdbinfo) {
576 atoms->pdbinfo[natom].type=type;
577 atoms->pdbinfo[natom].atomnr=strtol(anr, NULL, 10);
578 atoms->pdbinfo[natom].altloc=altloc;
579 strcpy(atoms->pdbinfo[natom].atomnm,anm_copy);
580 atoms->pdbinfo[natom].bfac=strtod(bfac,NULL);
581 atoms->pdbinfo[natom].occup=strtod(occup,NULL);
588 gmx_bool is_hydrogen(const char *nm)
597 else if ((isdigit(buf[0])) && (buf[1] == 'H'))
602 gmx_bool is_dummymass(const char *nm)
609 if ((buf[0] == 'M') && isdigit(buf[strlen(buf)-1]))
615 static void gmx_conect_addline(gmx_conect_t *con,char *line)
618 char format[32],form2[32];
620 sprintf(form2,"%%*s");
621 sprintf(format,"%s%%d",form2);
622 if (sscanf(line,format,&ai) == 1) {
625 sprintf(format,"%s%%d",form2);
626 n = sscanf(line,format,&aj);
628 srenew(con->conect,++con->nconect);
629 con->conect[con->nconect-1].ai = ai-1;
630 con->conect[con->nconect-1].aj = aj-1;
636 void gmx_conect_dump(FILE *fp,gmx_conect conect)
638 gmx_conect_t *gc = (gmx_conect_t *)conect;
641 for(i=0; (i<gc->nconect); i++)
642 fprintf(fp,"%6s%5d%5d\n","CONECT",
643 gc->conect[i].ai+1,gc->conect[i].aj+1);
646 gmx_conect gmx_conect_init()
652 return (gmx_conect) gc;
655 void gmx_conect_done(gmx_conect conect)
657 gmx_conect_t *gc = (gmx_conect_t *)conect;
662 gmx_bool gmx_conect_exist(gmx_conect conect,int ai,int aj)
664 gmx_conect_t *gc = (gmx_conect_t *)conect;
670 for(i=0; (i<gc->nconect); i++)
671 if (((gc->conect[i].ai == ai) &&
672 (gc->conect[i].aj == aj)) ||
673 ((gc->conect[i].aj == ai) &&
674 (gc->conect[i].ai == aj)))
679 void gmx_conect_add(gmx_conect conect,int ai,int aj)
681 gmx_conect_t *gc = (gmx_conect_t *)conect;
687 if (!gmx_conect_exist(conect,ai,aj)) {
688 srenew(gc->conect,++gc->nconect);
689 gc->conect[gc->nconect-1].ai = ai;
690 gc->conect[gc->nconect-1].aj = aj;
694 int read_pdbfile(FILE *in,char *title,int *model_nr,
695 t_atoms *atoms,rvec x[],int *ePBC,matrix box,gmx_bool bChange,
698 gmx_conect_t *gc = (gmx_conect_t *)conect;
701 gmx_bool bConnWarn = FALSE;
705 int natom,chainnum,nres_ter_prev=0;
707 gmx_bool bStop=FALSE;
711 /* Only assume pbc when there is a CRYST1 entry */
719 open_symtab(&symtab);
725 while (!bStop && (fgets2(line,STRLEN,in) != NULL))
727 line_type = line2type(line);
733 natom = read_atom(&symtab,line,line_type,natom,atoms,x,chainnum,bChange);
739 read_anisou(line,natom,atoms);
744 read_cryst1(line,ePBC,box);
749 if (strlen(line) > 6)
752 /* skip HEADER or TITLE and spaces */
753 while (c[0]!=' ') c++;
754 while (c[0]==' ') c++;
755 /* truncate after title */
769 if ((!strstr(line,": ")) || (strstr(line+6,"MOLECULE:")))
771 if ( !(c=strstr(line+6,"MOLECULE:")) )
775 /* skip 'MOLECULE:' and spaces */
776 while (c[0]!=' ') c++;
777 while (c[0]==' ') c++;
778 /* truncate after title */
782 while ( (d[-1]==';') && d>c) d--;
808 sscanf(line,"%*s%d",model_nr);
818 gmx_conect_addline(gc,line);
822 fprintf(stderr,"WARNING: all CONECT records are ignored\n");
832 free_symtab(&symtab);
836 void get_pdb_coordnum(FILE *in,int *natoms)
841 while (fgets2(line,STRLEN,in))
843 if ( strncmp(line,"ENDMDL",6) == 0 )
847 if ((strncmp(line,"ATOM ",6) == 0) || (strncmp(line,"HETATM",6) == 0))
854 void read_pdb_conf(const char *infile,char *title,
855 t_atoms *atoms,rvec x[],int *ePBC,matrix box,gmx_bool bChange,
860 in = gmx_fio_fopen(infile,"r");
861 read_pdbfile(in,title,NULL,atoms,x,ePBC,box,bChange,conect);
865 gmx_conect gmx_conect_generate(t_topology *top)
870 /* Fill the conect records */
871 gc = gmx_conect_init();
873 for(f=0; (f<F_NRE); f++) {
875 for(i=0; (i<top->idef.il[f].nr); i+=interaction_function[f].nratoms+1) {
876 gmx_conect_add(gc,top->idef.il[f].iatoms[i+1],
877 top->idef.il[f].iatoms[i+2]);
883 const char* get_pdbformat()
885 static const char *pdbformat ="%-6s%5u %-4.4s%3.3s %c%4d%c %8.3f%8.3f%8.3f";
889 const char* get_pdbformat4()
891 static const char *pdbformat4="%-6s%5u %-4.4s %3.3s %c%4d%c %8.3f%8.3f%8.3f";