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"
52 #include "fflibutil.h"
55 /* use bonded types definitions in hackblock.h */
56 #define ekwRepl ebtsNR+1
57 #define ekwAdd ebtsNR+2
58 #define ekwDel ebtsNR+3
60 const char *kw_names[ekwNR] = {
61 "replace", "add", "delete"
64 int find_kw(char *keyw)
68 for (i = 0; i < ebtsNR; i++)
70 if (gmx_strcasecmp(btsNames[i], keyw) == 0)
75 for (i = 0; i < ekwNR; i++)
77 if (gmx_strcasecmp(kw_names[i], keyw) == 0)
79 return ebtsNR + 1 + i;
86 #define FATAL() gmx_fatal(FARGS, "Reading Termini Database: not enough items on line\n%s", line)
88 static void read_atom(char *line, gmx_bool bAdd,
89 char **nname, t_atom *a, gpp_atomtype_t atype, int *cgnr)
92 char buf[5][30], type[12];
95 /* This code is messy, because of support for different formats:
96 * for replace: [new name] <atom type> <m> <q> [cgnr (old format)]
97 * for add: <atom type> <m> <q> [cgnr]
99 nr = sscanf(line, "%s %s %s %s %s", buf[0], buf[1], buf[2], buf[3], buf[4]);
101 /* Here there an ambiguity due to the old replace format with cgnr,
102 * which was read for years, but ignored in the rest of the code.
103 * We have to assume that the atom type does not start with a digit
104 * to make a line with 4 entries uniquely interpretable.
106 if (!bAdd && nr == 4 && isdigit(buf[1][0]))
111 if (nr < 3 || nr > 4)
113 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);
120 *nname = strdup(buf[i++]);
127 a->type = get_atomtype_type(buf[i++], atype);
128 sscanf(buf[i++], "%lf", &m);
130 sscanf(buf[i++], "%lf", &q);
134 sscanf(buf[i++], "%d", cgnr);
142 static void print_atom(FILE *out, t_atom *a, gpp_atomtype_t atype, char *newnm)
144 fprintf(out, "\t%s\t%g\t%g\n",
145 get_atomtype_name(a->type, atype), a->m, a->q);
148 static void print_ter_db(const char *ff, char C, int nb, t_hackblock tb[],
149 gpp_atomtype_t atype)
152 int i, j, k, bt, nrepl, nadd, ndel;
153 char buf[STRLEN], nname[STRLEN];
155 sprintf(buf, "%s-%c.tdb", ff, C);
156 out = gmx_fio_fopen(buf, "w");
158 for (i = 0; (i < nb); i++)
160 fprintf(out, "[ %s ]\n", tb[i].name);
166 for (j = 0; j < tb[i].nhack; j++)
168 if (tb[i].hack[j].oname != NULL && tb[i].hack[j].nname != NULL)
172 else if (tb[i].hack[j].oname == NULL && tb[i].hack[j].nname != NULL)
176 else if (tb[i].hack[j].oname != NULL && tb[i].hack[j].nname == NULL)
180 else if (tb[i].hack[j].oname == NULL && tb[i].hack[j].nname == NULL)
182 gmx_fatal(FARGS, "invalid hack (%s) in termini database", tb[i].name);
187 fprintf(out, "[ %s ]\n", kw_names[ekwRepl-ebtsNR-1]);
188 for (j = 0; j < tb[i].nhack; j++)
190 if (tb[i].hack[j].oname != NULL && tb[i].hack[j].nname != NULL)
192 fprintf(out, "%s\t", tb[i].hack[j].oname);
193 print_atom(out, tb[i].hack[j].atom, atype, tb[i].hack[j].nname);
199 fprintf(out, "[ %s ]\n", kw_names[ekwAdd-ebtsNR-1]);
200 for (j = 0; j < tb[i].nhack; j++)
202 if (tb[i].hack[j].oname == NULL && tb[i].hack[j].nname != NULL)
204 print_ab(out, &(tb[i].hack[j]), tb[i].hack[j].nname);
205 print_atom(out, tb[i].hack[j].atom, atype, tb[i].hack[j].nname);
211 fprintf(out, "[ %s ]\n", kw_names[ekwDel-ebtsNR-1]);
212 for (j = 0; j < tb[i].nhack; j++)
214 if (tb[i].hack[j].oname != NULL && tb[i].hack[j].nname == NULL)
216 fprintf(out, "%s\n", tb[i].hack[j].oname);
220 for (bt = 0; bt < ebtsNR; bt++)
224 fprintf(out, "[ %s ]\n", btsNames[bt]);
225 for (j = 0; j < tb[i].rb[bt].nb; j++)
227 for (k = 0; k < btsNiatoms[bt]; k++)
229 fprintf(out, "%s%s", k ? "\t" : "", tb[i].rb[bt].b[j].a[k]);
231 if (tb[i].rb[bt].b[j].s)
233 fprintf(out, "\t%s", tb[i].rb[bt].b[j].s);
244 static void read_ter_db_file(char *fn,
245 int *ntbptr, t_hackblock **tbptr,
246 gpp_atomtype_t atype)
248 char filebase[STRLEN], *ptr;
250 char header[STRLEN], buf[STRLEN], line[STRLEN];
252 int i, j, n, ni, kwnr, nb, maxnb, nh;
254 fflib_filename_base(fn, filebase, STRLEN);
255 /* Remove the C/N termini extension */
256 ptr = strrchr(filebase, '.');
265 fprintf(debug, "Opened %s\n", fn);
272 get_a_line(in, line, STRLEN);
275 if (get_header(line, header))
277 /* this is a new block, or a new keyword */
278 kwnr = find_kw(header);
283 /* here starts a new block */
289 clear_t_hackblock(&tb[nb]);
290 tb[nb].name = strdup(header);
291 tb[nb].filebase = strdup(filebase);
298 gmx_fatal(FARGS, "reading termini database: "
299 "directive expected before line:\n%s\n"
300 "This might be a file in an old format.", line);
302 /* this is not a header, so it must be data */
305 /* this is a hack: add/rename/delete atoms */
306 /* make space for hacks */
307 if (tb[nb].nhack >= tb[nb].maxhack)
309 tb[nb].maxhack += 10;
310 srenew(tb[nb].hack, tb[nb].maxhack);
313 clear_t_hack(&(tb[nb].hack[nh]));
314 for (i = 0; i < 4; i++)
316 tb[nb].hack[nh].a[i] = NULL;
322 if (kwnr == ekwRepl || kwnr == ekwDel)
324 if (sscanf(line, "%s%n", buf, &n) != 1)
326 gmx_fatal(FARGS, "Reading Termini Database '%s': "
327 "expected atom name on line\n%s", fn, line);
329 tb[nb].hack[nh].oname = strdup(buf);
330 /* we only replace or delete one atom at a time */
331 tb[nb].hack[nh].nr = 1;
333 else if (kwnr == ekwAdd)
335 read_ab(line, fn, &(tb[nb].hack[nh]));
336 get_a_line(in, line, STRLEN);
340 gmx_fatal(FARGS, "unimplemented keyword number %d (%s:%d)",
341 kwnr, __FILE__, __LINE__);
343 if (kwnr == ekwRepl || kwnr == ekwAdd)
345 snew(tb[nb].hack[nh].atom, 1);
346 read_atom(line+n, kwnr == ekwAdd,
347 &tb[nb].hack[nh].nname, tb[nb].hack[nh].atom, atype,
348 &tb[nb].hack[nh].cgnr);
349 if (tb[nb].hack[nh].nname == NULL)
351 if (tb[nb].hack[nh].oname != NULL)
353 tb[nb].hack[nh].nname = strdup(tb[nb].hack[nh].oname);
357 gmx_fatal(FARGS, "Reading Termini Database '%s': don't know which name the new atom should have on line\n%s", fn, line);
362 else if (kwnr >= 0 && kwnr < ebtsNR)
364 /* this is bonded data: bonds, angles, dihedrals or impropers */
365 srenew(tb[nb].rb[kwnr].b, tb[nb].rb[kwnr].nb+1);
367 for (j = 0; j < btsNiatoms[kwnr]; j++)
369 if (sscanf(line+n, "%s%n", buf, &ni) == 1)
371 tb[nb].rb[kwnr].b[tb[nb].rb[kwnr].nb].a[j] = strdup(buf);
375 gmx_fatal(FARGS, "Reading Termini Database '%s': expected %d atom names (found %d) on line\n%s", fn, btsNiatoms[kwnr], j-1, line);
379 for (; j < MAXATOMLIST; j++)
381 tb[nb].rb[kwnr].b[tb[nb].rb[kwnr].nb].a[j] = NULL;
384 sscanf(line+n, "%s", buf);
385 tb[nb].rb[kwnr].b[tb[nb].rb[kwnr].nb].s = strdup(buf);
386 tb[nb].rb[kwnr].nb++;
390 gmx_fatal(FARGS, "Reading Termini Database: Expecting a header at line\n"
394 get_a_line(in, line, STRLEN);
405 int read_ter_db(const char *ffdir, char ter,
406 t_hackblock **tbptr, gpp_atomtype_t atype)
413 sprintf(ext, ".%c.tdb", ter);
415 /* Search for termini database files.
416 * Do not generate an error when none are found.
418 ntdbf = fflib_search_file_end(ffdir, ext, FALSE, &tdbf);
421 for (f = 0; f < ntdbf; f++)
423 read_ter_db_file(tdbf[f], &ntb, tbptr, atype);
430 print_ter_db("new", ter, ntb, *tbptr, atype);
436 t_hackblock **filter_ter(int nrtp, t_restp rtp[],
437 int nb, t_hackblock tb[],
442 /* Since some force fields (e.g. OPLS) needs different
443 * atomtypes for different residues there could be a lot
444 * of entries in the databases for specific residues
445 * (e.g. GLY-NH3+, SER-NH3+, ALA-NH3+).
447 * To reduce the database size, we assume that a terminus specifier liker
449 * [ GLY|SER|ALA-NH3+ ]
451 * would cover all of the three residue types above.
452 * Wildcards (*,?) are not OK. Don't worry about e.g. GLU vs. GLUH since
453 * pdb2gmx only uses the first 3 letters when calling this routine.
455 * To automate this, this routines scans a list of termini
456 * for the residue name "resname" and returns an allocated list of
457 * pointers to the termini that could be applied to the
458 * residue in question. The variable pointed to by nret will
459 * contain the number of valid pointers in the list.
460 * Remember to free the list when you are done with it...
464 int i, j, n, len, none_idx;
466 char *rtpname_match, *s, *s2, *c;
469 rtpname_match = search_rtp(rtpname, nrtp, rtp);
470 restp = get_restp(rtpname_match, nrtp, rtp);
475 for (i = 0; i < nb; i++)
481 /* The residue name should appear in a tdb file with the same base name
482 * as the file containing the rtp entry.
483 * This makes termini selection for different molecule types
486 if (gmx_strcasecmp(restp->filebase, tb[i].filebase) == 0 &&
487 gmx_strncasecmp(resname, s, 3) == 0)
496 /* advance to next |-separated field */
504 while (!found && s != NULL);
507 /* All residue-specific termini have been added. See if there
508 * are some generic ones by searching for the occurence of
509 * '-' in the name prior to the last position (which indicates charge).
510 * The [ None ] alternative is special since we don't want that
511 * to be the default, so we put it last in the list we return.
514 for (i = 0; i < nb; i++)
517 /* The residue name should appear in a tdb file with the same base name
518 * as the file containing the rtp entry.
519 * This makes termini selection for different molecule types
522 if (gmx_strcasecmp(restp->filebase, tb[i].filebase) == 0)
524 if (!gmx_strcasecmp("None", s))
531 if (c == NULL || ((c-s+1) == strlen(s)))
533 /* Check that we haven't already added a residue-specific version
536 for (j = 0; j < n && strstr((*list[j]).name, s) == NULL; j++)
553 list[n] = &(tb[none_idx]);
562 t_hackblock *choose_ter(int nb, t_hackblock **tb, const char *title)
566 printf("%s\n", title);
567 for (i = 0; (i < nb); i++)
569 char *advice_string = "";
570 if (0 == gmx_wcmatch("*ZWITTERION*", (*tb[i]).name))
572 advice_string = " (only use with zwitterions containing exactly one residue)";
574 printf("%2d: %s%s\n", i, (*tb[i]).name, advice_string);
578 ret = fscanf(stdin, "%d", &sel);
580 while ((ret != 1) || (sel < 0) || (sel >= nb));