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,pdbformat);
329 strcpy(pdbform,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);
365 gmx_residuetype_destroy(rt);
368 void write_pdbfile(FILE *out,const char *title, t_atoms *atoms,rvec x[],
369 int ePBC,matrix box,char chainid,int model_nr,gmx_conect conect,gmx_bool bTerSepChains)
373 snew(index,atoms->nr);
374 for(i=0; i<atoms->nr; i++)
376 write_pdbfile_indexed(out,title,atoms,x,ePBC,box,chainid,model_nr,
377 atoms->nr,index,conect,bTerSepChains);
381 int line2type(char *line)
390 for(k=0; (k<epdbNR); k++)
391 if (strncmp(type,pdbtp[k],strlen(pdbtp[k])) == 0)
397 static void read_anisou(char line[],int natom,t_atoms *atoms)
401 char anr[12],anm[12];
405 for(k=0; (k<5); k++,j++) anr[k]=line[j];
408 for(k=0; (k<4); k++,j++) anm[k]=line[j];
412 /* Strip off spaces */
415 /* Search backwards for number and name only */
416 atomnr = strtol(anr, NULL, 10);
417 for(i=natom-1; (i>=0); i--)
418 if ((strcmp(anm,*(atoms->atomname[i])) == 0) &&
419 (atomnr == atoms->pdbinfo[i].atomnr))
422 fprintf(stderr,"Skipping ANISOU record (atom %s %d not found)\n",
425 if (sscanf(line+29,"%d%d%d%d%d%d",
426 &atoms->pdbinfo[i].uij[U11],&atoms->pdbinfo[i].uij[U22],
427 &atoms->pdbinfo[i].uij[U33],&atoms->pdbinfo[i].uij[U12],
428 &atoms->pdbinfo[i].uij[U13],&atoms->pdbinfo[i].uij[U23])
430 atoms->pdbinfo[i].bAnisotropic = TRUE;
433 fprintf(stderr,"Invalid ANISOU record for atom %d\n",i);
434 atoms->pdbinfo[i].bAnisotropic = FALSE;
439 void get_pdb_atomnumber(t_atoms *atoms,gmx_atomprop_t aps)
441 int i,atomnumber,len;
443 char anm[6],anm_copy[6],*ptr;
447 if (!atoms->pdbinfo) {
448 gmx_incons("Trying to deduce atomnumbers when no pdb information is present");
450 for(i=0; (i<atoms->nr); i++) {
451 strcpy(anm,atoms->pdbinfo[i].atomnm);
452 strcpy(anm_copy,atoms->pdbinfo[i].atomnm);
455 if ((anm[0] != ' ') && ((len <=2) || ((len > 2) && !isdigit(anm[2])))) {
457 if (gmx_atomprop_query(aps,epropElement,"???",anm_copy,&eval))
458 atomnumber = gmx_nint(eval);
461 if (gmx_atomprop_query(aps,epropElement,"???",anm_copy,&eval))
462 atomnumber = gmx_nint(eval);
465 if (atomnumber == NOTSET) {
467 while ((k < strlen(anm)) && (isspace(anm[k]) || isdigit(anm[k])))
469 anm_copy[0] = anm[k];
471 if (gmx_atomprop_query(aps,epropElement,"???",anm_copy,&eval))
472 atomnumber = gmx_nint(eval);
474 atoms->atom[i].atomnumber = atomnumber;
475 ptr = gmx_atomprop_element(aps,atomnumber);
476 strncpy(atoms->atom[i].elem,ptr==NULL ? "" : ptr,4);
478 fprintf(debug,"Atomnumber for atom '%s' is %d\n",anm,atomnumber);
482 static int read_atom(t_symtab *symtab,
483 char line[],int type,int natom,
484 t_atoms *atoms,rvec x[],int chainnum,gmx_bool bChange)
489 char anr[12],anm[12],anm_copy[12],altloc,resnm[12],rnr[12];
490 char xc[12],yc[12],zc[12],occup[12],bfac[12];
493 int resnr,atomnumber;
495 if (natom>=atoms->nr)
496 gmx_fatal(FARGS,"\nFound more atoms (%d) in pdb file than expected (%d)",
501 for(k=0; (k<5); k++,j++) anr[k]=line[j];
505 for(k=0; (k<4); k++,j++) anm[k]=line[j];
507 strcpy(anm_copy,anm);
513 for(k=0; (k<4); k++,j++)
521 for(k=0; (k<4); k++,j++) {
526 resnr = strtol(rnr, NULL, 10);
530 /* X,Y,Z Coordinate */
531 for(k=0; (k<8); k++,j++) xc[k]=line[j];
533 for(k=0; (k<8); k++,j++) yc[k]=line[j];
535 for(k=0; (k<8); k++,j++) zc[k]=line[j];
539 for(k=0; (k<6); k++,j++) occup[k]=line[j];
543 for(k=0; (k<7); k++,j++) bfac[k]=line[j];
547 atomn=&(atoms->atom[natom]);
549 atoms->resinfo[atoms->atom[natom-1].resind].nr != resnr ||
550 atoms->resinfo[atoms->atom[natom-1].resind].ic != resic ||
551 (strcmp(*atoms->resinfo[atoms->atom[natom-1].resind].name,resnm) != 0))
556 atomn->resind = atoms->atom[natom-1].resind + 1;
558 atoms->nres = atomn->resind + 1;
559 t_atoms_set_resinfo(atoms,natom,symtab,resnm,resnr,resic,chainnum,chainid);
563 atomn->resind = atoms->atom[natom-1].resind;
566 xlate_atomname_pdb2gmx(anm);
568 atoms->atomname[natom]=put_symtab(symtab,anm);
571 atomn->atomnumber = atomnumber;
572 atomn->elem[0] = '\0';
574 x[natom][XX]=strtod(xc,NULL)*0.1;
575 x[natom][YY]=strtod(yc,NULL)*0.1;
576 x[natom][ZZ]=strtod(zc,NULL)*0.1;
577 if (atoms->pdbinfo) {
578 atoms->pdbinfo[natom].type=type;
579 atoms->pdbinfo[natom].atomnr=strtol(anr, NULL, 10);
580 atoms->pdbinfo[natom].altloc=altloc;
581 strcpy(atoms->pdbinfo[natom].atomnm,anm_copy);
582 atoms->pdbinfo[natom].bfac=strtod(bfac,NULL);
583 atoms->pdbinfo[natom].occup=strtod(occup,NULL);
590 gmx_bool is_hydrogen(const char *nm)
599 else if ((isdigit(buf[0])) && (buf[1] == 'H'))
604 gmx_bool is_dummymass(const char *nm)
611 if ((buf[0] == 'M') && isdigit(buf[strlen(buf)-1]))
617 static void gmx_conect_addline(gmx_conect_t *con,char *line)
620 char format[32],form2[32];
622 sprintf(form2,"%%*s");
623 sprintf(format,"%s%%d",form2);
624 if (sscanf(line,format,&ai) == 1) {
627 sprintf(format,"%s%%d",form2);
628 n = sscanf(line,format,&aj);
630 srenew(con->conect,++con->nconect);
631 con->conect[con->nconect-1].ai = ai-1;
632 con->conect[con->nconect-1].aj = aj-1;
638 void gmx_conect_dump(FILE *fp,gmx_conect conect)
640 gmx_conect_t *gc = (gmx_conect_t *)conect;
643 for(i=0; (i<gc->nconect); i++)
644 fprintf(fp,"%6s%5d%5d\n","CONECT",
645 gc->conect[i].ai+1,gc->conect[i].aj+1);
648 gmx_conect gmx_conect_init()
654 return (gmx_conect) gc;
657 void gmx_conect_done(gmx_conect conect)
659 gmx_conect_t *gc = (gmx_conect_t *)conect;
664 gmx_bool gmx_conect_exist(gmx_conect conect,int ai,int aj)
666 gmx_conect_t *gc = (gmx_conect_t *)conect;
672 for(i=0; (i<gc->nconect); i++)
673 if (((gc->conect[i].ai == ai) &&
674 (gc->conect[i].aj == aj)) ||
675 ((gc->conect[i].aj == ai) &&
676 (gc->conect[i].ai == aj)))
681 void gmx_conect_add(gmx_conect conect,int ai,int aj)
683 gmx_conect_t *gc = (gmx_conect_t *)conect;
689 if (!gmx_conect_exist(conect,ai,aj)) {
690 srenew(gc->conect,++gc->nconect);
691 gc->conect[gc->nconect-1].ai = ai;
692 gc->conect[gc->nconect-1].aj = aj;
696 int read_pdbfile(FILE *in,char *title,int *model_nr,
697 t_atoms *atoms,rvec x[],int *ePBC,matrix box,gmx_bool bChange,
700 gmx_conect_t *gc = (gmx_conect_t *)conect;
703 gmx_bool bConnWarn = FALSE;
707 int natom,chainnum,nres_ter_prev=0;
709 gmx_bool bStop=FALSE;
713 /* Only assume pbc when there is a CRYST1 entry */
721 open_symtab(&symtab);
727 while (!bStop && (fgets2(line,STRLEN,in) != NULL))
729 line_type = line2type(line);
735 natom = read_atom(&symtab,line,line_type,natom,atoms,x,chainnum,bChange);
741 read_anisou(line,natom,atoms);
746 read_cryst1(line,ePBC,box);
751 if (strlen(line) > 6)
754 /* skip HEADER or TITLE and spaces */
755 while (c[0]!=' ') c++;
756 while (c[0]==' ') c++;
757 /* truncate after title */
771 if ((!strstr(line,": ")) || (strstr(line+6,"MOLECULE:")))
773 if ( !(c=strstr(line+6,"MOLECULE:")) )
777 /* skip 'MOLECULE:' and spaces */
778 while (c[0]!=' ') c++;
779 while (c[0]==' ') c++;
780 /* truncate after title */
784 while ( (d[-1]==';') && d>c) d--;
810 sscanf(line,"%*s%d",model_nr);
820 gmx_conect_addline(gc,line);
824 fprintf(stderr,"WARNING: all CONECT records are ignored\n");
834 free_symtab(&symtab);
838 void get_pdb_coordnum(FILE *in,int *natoms)
843 while (fgets2(line,STRLEN,in))
845 if ( strncmp(line,"ENDMDL",6) == 0 )
849 if ((strncmp(line,"ATOM ",6) == 0) || (strncmp(line,"HETATM",6) == 0))
856 void read_pdb_conf(const char *infile,char *title,
857 t_atoms *atoms,rvec x[],int *ePBC,matrix box,gmx_bool bChange,
862 in = gmx_fio_fopen(infile,"r");
863 read_pdbfile(in,title,NULL,atoms,x,ePBC,box,bChange,conect);
867 gmx_conect gmx_conect_generate(t_topology *top)
872 /* Fill the conect records */
873 gc = gmx_conect_init();
875 for(f=0; (f<F_NRE); f++) {
877 for(i=0; (i<top->idef.il[f].nr); i+=interaction_function[f].nratoms+1) {
878 gmx_conect_add(gc,top->idef.il[f].iatoms[i+1],
879 top->idef.il[f].iatoms[i+2]);