Don't use POSIX fnmatch() for pattern matching.
[gromacs/qmmm-gamess-us.git] / src / kernel / ter_db.c
blob610b60b32fda7fdaa3fc3b0002cf5bf34d49acb4
1 /*
2 *
3 * This source code is part of
4 *
5 * G R O M A C S
6 *
7 * GROningen MAchine for Chemical Simulations
8 *
9 * VERSION 3.2.0
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
32 * And Hey:
33 * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
39 #include "sysstuff.h"
40 #include "smalloc.h"
41 #include "typedefs.h"
42 #include "symtab.h"
43 #include "futil.h"
44 #include "resall.h"
45 #include "h_db.h"
46 #include "string2.h"
47 #include "strdb.h"
48 #include "gmx_fatal.h"
49 #include "ter_db.h"
50 #include "toputil.h"
51 #include "gmxfio.h"
54 /* use bonded types definitions in hackblock.h */
55 #define ekwRepl ebtsNR+1
56 #define ekwAdd ebtsNR+2
57 #define ekwDel ebtsNR+3
58 #define ekwNR 3
59 const char *kw_names[ekwNR] = {
60 "replace", "add", "delete"
63 int find_kw(char *keyw)
65 int i;
67 for(i=0; i<ebtsNR; i++)
68 if (strcasecmp(btsNames[i],keyw) == 0)
69 return i;
70 for(i=0; i<ekwNR; i++)
71 if (strcasecmp(kw_names[i],keyw) == 0)
72 return ebtsNR + 1 + i;
74 return NOTSET;
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)
82 int nr, i, n;
83 char buf[4][30],type[12];
84 double m, q;
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);
94 i = 0;
95 if (!bAdd) {
96 if (nr == 4) {
97 *nname = strdup(buf[i++]);
98 } else {
99 *nname = NULL;
102 a->type = get_atomtype_type(buf[i++],atype);
103 sscanf(buf[i++],"%lf",&m);
104 a->m = m;
105 sscanf(buf[i++],"%lf",&q);
106 a->q = q;
107 if (bAdd && nr == 4) {
108 sscanf(buf[3],"%d", cgnr);
109 } else {
110 *cgnr = NOTSET;
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)
123 FILE *out;
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);
133 /* first count: */
134 nrepl=0;
135 nadd=0;
136 ndel=0;
137 for(j=0; j<tb[i].nhack; j++)
138 if ( tb[i].hack[j].oname!=NULL && tb[i].hack[j].nname!=NULL )
139 nrepl++;
140 else if ( tb[i].hack[j].oname==NULL && tb[i].hack[j].nname!=NULL )
141 nadd++;
142 else if ( tb[i].hack[j].oname!=NULL && tb[i].hack[j].nname==NULL )
143 ndel++;
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);
146 if (nrepl) {
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);
154 if (nadd) {
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);
162 if (ndel) {
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);
176 fprintf(out,"\n");
179 fprintf(out,"\n");
181 gmx_fio_fclose(out);
184 int read_ter_db(char *FF,char ter,t_hackblock **tbptr,gpp_atomtype_t atype)
186 FILE *in;
187 char inf[STRLEN],header[STRLEN],buf[STRLEN],line[STRLEN];
188 t_hackblock *tb;
189 int i,j,n,ni,kwnr,nb,maxnb,nh;
191 sprintf(inf,"%s-%c.tdb",FF,ter);
192 in=libopen(inf);
193 if (debug)
194 fprintf(debug,"Opened %s\n",inf);
196 tb=NULL;
197 nb=-1;
198 maxnb=0;
199 kwnr=NOTSET;
200 get_a_line(in,line,STRLEN);
201 while (!feof(in)) {
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) {
207 nb++;
208 /* here starts a new block */
209 if ( nb >= maxnb ) {
210 maxnb+=100;
211 srenew(tb,maxnb);
213 clear_t_hackblock(&tb[nb]);
214 tb[nb].name=strdup(header);
216 } else {
217 if (nb < 0)
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) {
226 tb[nb].maxhack+=10;
227 srenew(tb[nb].hack, tb[nb].maxhack);
229 nh=tb[nb].nhack;
230 clear_t_hack(&(tb[nb].hack[nh]));
231 for(i=0; i<4; i++)
232 tb[nb].hack[nh].a[i]=NULL;
233 tb[nb].nhack++;
235 /* get data */
236 n=0;
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);
247 } else
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);
258 } else {
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);
266 n=0;
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);
270 else
271 gmx_fatal(FARGS,"Reading Termini Database '%s': expected %d atom names (found %d) on line\n%s", inf, btsNiatoms[kwnr], j-1, line);
272 n+=ni;
274 for( ; j<MAXATOMLIST; j++)
275 tb[nb].rb[kwnr].b[tb[nb].rb[kwnr].nb].a[j] = NULL;
276 strcpy(buf, "");
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++;
280 } else
281 gmx_fatal(FARGS,"Reading Termini Database: Expecting a header at line\n"
282 "%s",line);
284 get_a_line(in,line,STRLEN);
286 nb++;
287 srenew(tb,nb);
289 fclose(in);
291 if (debug)
292 print_ter_db(FF,ter,nb,tb,atype);
294 *tbptr=tb;
295 return nb;
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;
322 bool found;
323 char *s,*s2,*c;
324 t_hackblock **list;
326 n=0;
327 list=NULL;
329 for(i=0;i<nb;i++) {
330 s=tb[i].name;
331 found=FALSE;
332 do {
333 if(!strncasecmp(resname,s,3)) {
334 found=TRUE;
335 srenew(list,n+1);
336 list[n]=&(tb[i]);
337 n++;
338 } else { /* advance to next |-separated field */
339 s=strchr(s,'|');
340 if(s!=NULL)
341 s++;
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.
352 none_idx=-1;
353 for(i=0;i<nb;i++) {
354 s=tb[i].name;
355 if(!strcasecmp("None",s)) {
356 none_idx=i;
357 } else {
358 c=strchr(s,'-');
359 if(c==NULL || ((c-s+1)==strlen(s))) {
360 /* Check that we haven't already added a residue-specific version
361 * of this terminus.
363 for(j=0;j<n && strstr((*list[j]).name,s)==NULL;j++);
364 if(j==n) {
365 srenew(list,n+1);
366 list[n]=&(tb[i]);
367 n++;
372 if(none_idx>=0) {
373 srenew(list,n+1);
374 list[n]=&(tb[none_idx]);
375 n++;
378 *nret=n;
379 return list;
383 t_hackblock *choose_ter(int nb,t_hackblock **tb,const char *title)
385 int i,sel,ret;
387 printf("%s\n",title);
388 for(i=0; (i<nb); i++)
389 printf("%2d: %s\n",i,(*tb[i]).name);
390 do {
391 ret=fscanf(stdin,"%d",&sel);
392 } while ((ret != 1) || (sel < 0) || (sel >= nb));
394 return tb[sel];