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 * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
48 #include "gmx_fatal.h"
54 /* use bonded types definitions in hackblock.h */
55 #define ekwRepl ebtsNR+1
56 #define ekwAdd ebtsNR+2
57 #define ekwDel ebtsNR+3
59 const char *kw_names
[ekwNR
] = {
60 "replace", "add", "delete"
63 int find_kw(char *keyw
)
67 for(i
=0; i
<ebtsNR
; i
++)
68 if (strcasecmp(btsNames
[i
],keyw
) == 0)
70 for(i
=0; i
<ekwNR
; i
++)
71 if (strcasecmp(kw_names
[i
],keyw
) == 0)
72 return ebtsNR
+ 1 + i
;
77 #define FATAL() gmx_fatal(FARGS,"Reading Termini Database: not enough items on line\n%s",line)
79 static void read_atom(char *line
, bool bAdd
,
80 char **nname
, t_atom
*a
, gpp_atomtype_t atype
, int *cgnr
)
83 char buf
[4][30],type
[12];
86 /* This code is messy, because of support for different formats:
87 * for replace: [new name] <atom type> <m> <q>
88 * for add: <atom type> <m> <q> [cgnr]
90 nr
= sscanf(line
,"%s %s %s %s %n", buf
[0], buf
[1], buf
[2], buf
[3], &n
);
91 if (!(nr
== 3 || nr
== 4)) {
92 gmx_fatal(FARGS
,"Reading Termini Database: expected %d or %d items of atom data in stead of %d on line\n%s", 3, 4, nr
, line
);
97 *nname
= strdup(buf
[i
++]);
102 a
->type
= get_atomtype_type(buf
[i
++],atype
);
103 sscanf(buf
[i
++],"%lf",&m
);
105 sscanf(buf
[i
++],"%lf",&q
);
107 if (bAdd
&& nr
== 4) {
108 sscanf(buf
[3],"%d", cgnr
);
114 static void print_atom(FILE *out
,t_atom
*a
,gpp_atomtype_t atype
,char *newnm
)
116 fprintf(out
,"\t%s\t%g\t%g\n",
117 get_atomtype_name(a
->type
,atype
),a
->m
,a
->q
);
120 static void print_ter_db(char *ff
,char C
,int nb
,t_hackblock tb
[],
121 gpp_atomtype_t atype
)
124 int i
,j
,k
,bt
,nrepl
,nadd
,ndel
;
125 char buf
[STRLEN
],nname
[STRLEN
];
127 sprintf(buf
,"%s-%c_new.tdb",ff
,C
);
128 out
= gmx_fio_fopen(buf
,"w");
130 for(i
=0; (i
<nb
); i
++) {
131 fprintf(out
,"[ %s ]\n",tb
[i
].name
);
137 for(j
=0; j
<tb
[i
].nhack
; j
++)
138 if ( tb
[i
].hack
[j
].oname
!=NULL
&& tb
[i
].hack
[j
].nname
!=NULL
)
140 else if ( tb
[i
].hack
[j
].oname
==NULL
&& tb
[i
].hack
[j
].nname
!=NULL
)
142 else if ( tb
[i
].hack
[j
].oname
!=NULL
&& tb
[i
].hack
[j
].nname
==NULL
)
144 else if ( tb
[i
].hack
[j
].oname
==NULL
&& tb
[i
].hack
[j
].nname
==NULL
)
145 gmx_fatal(FARGS
,"invalid hack (%s) in termini database",tb
[i
].name
);
147 fprintf(out
,"[ %s ]\n",kw_names
[ekwRepl
-ebtsNR
-1]);
148 for(j
=0; j
<tb
[i
].nhack
; j
++)
149 if ( tb
[i
].hack
[j
].oname
!=NULL
&& tb
[i
].hack
[j
].nname
!=NULL
) {
150 fprintf(out
,"%s\t",tb
[i
].hack
[j
].oname
);
151 print_atom(out
,tb
[i
].hack
[j
].atom
,atype
,tb
[i
].hack
[j
].nname
);
155 fprintf(out
,"[ %s ]\n",kw_names
[ekwAdd
-ebtsNR
-1]);
156 for(j
=0; j
<tb
[i
].nhack
; j
++)
157 if ( tb
[i
].hack
[j
].oname
==NULL
&& tb
[i
].hack
[j
].nname
!=NULL
) {
158 print_ab(out
,&(tb
[i
].hack
[j
]),tb
[i
].hack
[j
].nname
);
159 print_atom(out
,tb
[i
].hack
[j
].atom
,atype
,tb
[i
].hack
[j
].nname
);
163 fprintf(out
,"[ %s ]\n",kw_names
[ekwDel
-ebtsNR
-1]);
164 for(j
=0; j
<tb
[i
].nhack
; j
++)
165 if ( tb
[i
].hack
[j
].oname
!=NULL
&& tb
[i
].hack
[j
].nname
==NULL
)
166 fprintf(out
,"%s\n",tb
[i
].hack
[j
].oname
);
168 for(bt
=0; bt
<ebtsNR
; bt
++)
169 if (tb
[i
].rb
[bt
].nb
) {
170 fprintf(out
,"[ %s ]\n", btsNames
[bt
]);
171 for(j
=0; j
<tb
[i
].rb
[bt
].nb
; j
++) {
172 for(k
=0; k
<btsNiatoms
[bt
]; k
++)
173 fprintf(out
,"%s%s",k
?"\t":"",tb
[i
].rb
[bt
].b
[j
].a
[k
]);
174 if ( tb
[i
].rb
[bt
].b
[j
].s
)
175 fprintf(out
,"\t%s",tb
[i
].rb
[bt
].b
[j
].s
);
184 int read_ter_db(char *FF
,char ter
,t_hackblock
**tbptr
,gpp_atomtype_t atype
)
187 char inf
[STRLEN
],header
[STRLEN
],buf
[STRLEN
],line
[STRLEN
];
189 int i
,j
,n
,ni
,kwnr
,nb
,maxnb
,nh
;
191 sprintf(inf
,"%s-%c.tdb",FF
,ter
);
194 fprintf(debug
,"Opened %s\n",inf
);
200 get_a_line(in
,line
,STRLEN
);
202 if (get_header(line
,header
)) {
203 /* this is a new block, or a new keyword */
204 kwnr
=find_kw(header
);
206 if (kwnr
== NOTSET
) {
208 /* here starts a new block */
213 clear_t_hackblock(&tb
[nb
]);
214 tb
[nb
].name
=strdup(header
);
218 gmx_fatal(FARGS
,"reading termini database: "
219 "directive expected before line:\n%s\n"
220 "This might be a file in an old format.",line
);
221 /* this is not a header, so it must be data */
222 if (kwnr
>= ebtsNR
) {
223 /* this is a hack: add/rename/delete atoms */
224 /* make space for hacks */
225 if (tb
[nb
].nhack
>= tb
[nb
].maxhack
) {
227 srenew(tb
[nb
].hack
, tb
[nb
].maxhack
);
230 clear_t_hack(&(tb
[nb
].hack
[nh
]));
232 tb
[nb
].hack
[nh
].a
[i
]=NULL
;
237 if ( kwnr
==ekwRepl
|| kwnr
==ekwDel
) {
238 if (sscanf(line
, "%s%n", buf
, &n
) != 1)
239 gmx_fatal(FARGS
,"Reading Termini Database '%s': "
240 "expected atom name on line\n%s",inf
,line
);
241 tb
[nb
].hack
[nh
].oname
= strdup(buf
);
242 /* we only replace or delete one atom at a time */
243 tb
[nb
].hack
[nh
].nr
= 1;
244 } else if ( kwnr
==ekwAdd
) {
245 read_ab(line
, inf
, &(tb
[nb
].hack
[nh
]));
246 get_a_line(in
, line
, STRLEN
);
248 gmx_fatal(FARGS
,"unimplemented keyword number %d (%s:%d)",
249 kwnr
,__FILE__
,__LINE__
);
250 if ( kwnr
==ekwRepl
|| kwnr
==ekwAdd
) {
251 snew(tb
[nb
].hack
[nh
].atom
, 1);
252 read_atom(line
+n
,kwnr
==ekwAdd
,
253 &tb
[nb
].hack
[nh
].nname
, tb
[nb
].hack
[nh
].atom
, atype
,
254 &tb
[nb
].hack
[nh
].cgnr
);
255 if (tb
[nb
].hack
[nh
].nname
== NULL
) {
256 if (tb
[nb
].hack
[nh
].oname
!= NULL
) {
257 tb
[nb
].hack
[nh
].nname
= strdup(tb
[nb
].hack
[nh
].oname
);
259 gmx_fatal(FARGS
,"Reading Termini Database '%s': don't know which name the new atom should have on line\n%s",inf
,line
);
263 } else if (kwnr
>= 0 && kwnr
< ebtsNR
) {
264 /* this is bonded data: bonds, angles, dihedrals or impropers */
265 srenew(tb
[nb
].rb
[kwnr
].b
,tb
[nb
].rb
[kwnr
].nb
+1);
267 for(j
=0; j
<btsNiatoms
[kwnr
]; j
++) {
268 if ( sscanf(line
+n
, "%s%n", buf
, &ni
) == 1 )
269 tb
[nb
].rb
[kwnr
].b
[tb
[nb
].rb
[kwnr
].nb
].a
[j
] = strdup(buf
);
271 gmx_fatal(FARGS
,"Reading Termini Database '%s': expected %d atom names (found %d) on line\n%s", inf
, btsNiatoms
[kwnr
], j
-1, line
);
274 for( ; j
<MAXATOMLIST
; j
++)
275 tb
[nb
].rb
[kwnr
].b
[tb
[nb
].rb
[kwnr
].nb
].a
[j
] = NULL
;
277 sscanf(line
+n
, "%s", buf
);
278 tb
[nb
].rb
[kwnr
].b
[tb
[nb
].rb
[kwnr
].nb
].s
= strdup(buf
);
279 tb
[nb
].rb
[kwnr
].nb
++;
281 gmx_fatal(FARGS
,"Reading Termini Database: Expecting a header at line\n"
284 get_a_line(in
,line
,STRLEN
);
292 print_ter_db(FF
,ter
,nb
,tb
,atype
);
298 t_hackblock
**filter_ter(int nb
,t_hackblock tb
[],char *resname
,int *nret
)
300 /* Since some force fields (e.g. OPLS) needs different
301 * atomtypes for different residues there could be a lot
302 * of entries in the databases for specific residues
303 * (e.g. GLY-NH3+, SER-NH3+, ALA-NH3+).
305 * To reduce the database size, we assume that a terminus specifier liker
307 * [ GLY|SER|ALA-NH3+ ]
309 * would cover all of the three residue types above.
310 * Wildcards (*,?) are not OK. Don't worry about e.g. GLU vs. GLUH since
311 * pdb2gmx only uses the first 3 letters when calling this routine.
313 * To automate this, this routines scans a list of termini
314 * for the residue name "resname" and returns an allocated list of
315 * pointers to the termini that could be applied to the
316 * residue in question. The variable pointed to by nret will
317 * contain the number of valid pointers in the list.
318 * Remember to free the list when you are done with it...
321 int i
,j
,n
,len
,none_idx
;
333 if(!strncasecmp(resname
,s
,3)) {
338 } else { /* advance to next |-separated field */
343 } while(!found
&& s
!=NULL
);
346 /* All residue-specific termini have been added. See if there
347 * are some generic ones by searching for the occurence of
348 * '-' in the name prior to the last position (which indicates charge).
349 * The [ None ] alternative is special since we don't want that
350 * to be the default, so we put it last in the list we return.
355 if(!strcasecmp("None",s
)) {
359 if(c
==NULL
|| ((c
-s
+1)==strlen(s
))) {
360 /* Check that we haven't already added a residue-specific version
363 for(j
=0;j
<n
&& strstr((*list
[j
]).name
,s
)==NULL
;j
++);
374 list
[n
]=&(tb
[none_idx
]);
383 t_hackblock
*choose_ter(int nb
,t_hackblock
**tb
,const char *title
)
387 printf("%s\n",title
);
388 for(i
=0; (i
<nb
); i
++)
389 printf("%2d: %s\n",i
,(*tb
[i
]).name
);
391 ret
=fscanf(stdin
,"%d",&sel
);
392 } while ((ret
!= 1) || (sel
< 0) || (sel
>= nb
));