2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2008, The GROMACS development team.
6 * Copyright (c) 2013,2014, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
46 #include "gromacs/math/utilities.h"
49 #include "gromacs/fileio/gmxfio.h"
50 #include "gromacs/fileio/confio.h"
51 #include "gromacs/math/units.h"
58 #include "gpp_nextnb.h"
60 #include "hackblock.h"
63 #include "gromacs/commandline/pargs.h"
64 #include "gromacs/math/vec.h"
65 #include "gromacs/utility/cstringutil.h"
66 #include "gromacs/utility/fatalerror.h"
67 #include "gromacs/utility/smalloc.h"
69 char atp[7] = "HCNOSX";
70 #define NATP (asize(atp)-1)
72 real blen[NATP][NATP] = {
73 { 0.00, 0.108, 0.105, 0.10, 0.10, 0.10 },
74 { 0.108, 0.15, 0.14, 0.14, 0.16, 0.14 },
75 { 0.105, 0.14, 0.14, 0.14, 0.16, 0.14 },
76 { 0.10, 0.14, 0.14, 0.14, 0.17, 0.14 },
77 { 0.10, 0.16, 0.16, 0.17, 0.20, 0.17 },
78 { 0.10, 0.14, 0.14, 0.14, 0.17, 0.17 }
81 #define MARGIN_FAC 1.1
83 static gmx_bool is_bond(int nnm, t_nm2type nmt[], char *ai, char *aj, real blen)
87 for (i = 0; (i < nnm); i++)
89 for (j = 0; (j < nmt[i].nbonds); j++)
91 if ((((gmx_strncasecmp(ai, nmt[i].elem, 1) == 0) &&
92 (gmx_strncasecmp(aj, nmt[i].bond[j], 1) == 0)) ||
93 ((gmx_strncasecmp(ai, nmt[i].bond[j], 1) == 0) &&
94 (gmx_strncasecmp(aj, nmt[i].elem, 1) == 0))) &&
95 (fabs(blen-nmt[i].blen[j]) <= 0.1*nmt[i].blen[j]))
104 static int get_atype(char *nm)
108 for (i = 0; (i < NATP-1); i++)
119 void mk_bonds(int nnm, t_nm2type nmt[],
120 t_atoms *atoms, rvec x[], t_params *bond, int nbond[],
121 gmx_bool bPBC, matrix box)
129 for (i = 0; (i < MAXATOMLIST); i++)
133 for (i = 0; (i < MAXFORCEPARAM); i++)
140 set_pbc(&pbc, -1, box);
142 for (i = 0; (i < atoms->nr); i++)
146 fprintf(stderr, "\ratom %d", i);
148 for (j = i+1; (j < atoms->nr); j++)
152 pbc_dx(&pbc, x[i], x[j], dx);
156 rvec_sub(x[i], x[j], dx);
160 if (is_bond(nnm, nmt, *atoms->atomname[i], *atoms->atomname[j],
166 add_param_to_list (bond, &b);
171 fprintf(debug, "Bonding atoms %s-%d and %s-%d\n",
172 *atoms->atomname[i], i+1, *atoms->atomname[j], j+1);
177 fprintf(stderr, "\ratom %d\n", i);
180 int *set_cgnr(t_atoms *atoms, gmx_bool bUsePDBcharge, real *qtot, real *mtot)
184 double qt = 0, mt = 0;
187 snew(cgnr, atoms->nr);
188 for (i = 0; (i < atoms->nr); i++)
190 if (atoms->pdbinfo && bUsePDBcharge)
192 atoms->atom[i].q = atoms->pdbinfo[i].bfac;
194 qt += atoms->atom[i].q;
195 *qtot += atoms->atom[i].q;
196 *mtot += atoms->atom[i].m;
207 gpp_atomtype_t set_atom_type(t_symtab *tab, t_atoms *atoms, t_params *bonds,
208 int *nbonds, int nnm, t_nm2type nm2t[])
210 gpp_atomtype_t atype;
213 atype = init_atomtype();
214 snew(atoms->atomtype, atoms->nr);
215 nresolved = nm2type(nnm, nm2t, tab, atoms, atype, nbonds, bonds);
216 if (nresolved != atoms->nr)
218 gmx_fatal(FARGS, "Could only find a forcefield type for %d out of %d atoms",
219 nresolved, atoms->nr);
222 fprintf(stderr, "There are %d different atom types in your sample\n",
223 get_atomtype_ntypes(atype));
228 void lo_set_force_const(t_params *plist, real c[], int nrfp, gmx_bool bRound,
229 gmx_bool bDih, gmx_bool bParam)
235 for (i = 0; (i < plist->nr); i++)
239 for (j = 0; j < nrfp; j++)
248 sprintf(buf, "%.2e", plist->param[i].c[0]);
249 sscanf(buf, "%lf", &cc);
254 c[0] = plist->param[i].c[0];
259 c[0] = ((int)(c[0] + 3600)) % 360;
264 /* To put the minimum at the current angle rather than the maximum */
268 assert(nrfp <= MAXFORCEPARAM/2);
269 for (j = 0; (j < nrfp); j++)
271 plist->param[i].c[j] = c[j];
272 plist->param[i].c[nrfp+j] = c[j];
274 set_p_string(&(plist->param[i]), "");
278 void set_force_const(t_params plist[], real kb, real kt, real kp, gmx_bool bRound,
282 real c[MAXFORCEPARAM];
286 lo_set_force_const(&plist[F_BONDS], c, 2, bRound, FALSE, bParam);
288 lo_set_force_const(&plist[F_ANGLES], c, 2, bRound, FALSE, bParam);
291 lo_set_force_const(&plist[F_PDIHS], c, 3, bRound, TRUE, bParam);
294 void calc_angles_dihs(t_params *ang, t_params *dih, rvec x[], gmx_bool bPBC,
297 int i, ai, aj, ak, al, t1, t2, t3;
298 rvec r_ij, r_kj, r_kl, m, n;
299 real sign, th, costh, ph;
304 set_pbc(&pbc, epbcXYZ, box);
308 pr_rvecs(debug, 0, "X2TOP", box, DIM);
310 for (i = 0; (i < ang->nr); i++)
312 ai = ang->param[i].AI;
313 aj = ang->param[i].AJ;
314 ak = ang->param[i].AK;
315 th = RAD2DEG*bond_angle(x[ai], x[aj], x[ak], bPBC ? &pbc : NULL,
316 r_ij, r_kj, &costh, &t1, &t2);
319 fprintf(debug, "X2TOP: ai=%3d aj=%3d ak=%3d r_ij=%8.3f r_kj=%8.3f th=%8.3f\n",
320 ai, aj, ak, norm(r_ij), norm(r_kj), th);
322 ang->param[i].C0 = th;
324 for (i = 0; (i < dih->nr); i++)
326 ai = dih->param[i].AI;
327 aj = dih->param[i].AJ;
328 ak = dih->param[i].AK;
329 al = dih->param[i].AL;
330 ph = RAD2DEG*dih_angle(x[ai], x[aj], x[ak], x[al], bPBC ? &pbc : NULL,
331 r_ij, r_kj, r_kl, m, n, &sign, &t1, &t2, &t3);
334 fprintf(debug, "X2TOP: ai=%3d aj=%3d ak=%3d al=%3d r_ij=%8.3f r_kj=%8.3f r_kl=%8.3f ph=%8.3f\n",
335 ai, aj, ak, al, norm(r_ij), norm(r_kj), norm(r_kl), ph);
337 dih->param[i].C0 = ph;
341 static void dump_hybridization(FILE *fp, t_atoms *atoms, int nbonds[])
345 for (i = 0; (i < atoms->nr); i++)
347 fprintf(fp, "Atom %5s has %1d bonds\n", *atoms->atomname[i], nbonds[i]);
351 static void print_pl(FILE *fp, t_params plist[], int ftp, const char *name,
354 int i, j, nral, nrfp;
356 if (plist[ftp].nr > 0)
359 fprintf(fp, "[ %s ]\n", name);
360 nral = interaction_function[ftp].nratoms;
361 nrfp = interaction_function[ftp].nrfpA;
362 for (i = 0; (i < plist[ftp].nr); i++)
364 for (j = 0; (j < nral); j++)
366 fprintf(fp, " %5s", *atomname[plist[ftp].param[i].a[j]]);
368 for (j = 0; (j < nrfp); j++)
370 if (plist[ftp].param[i].c[j] != NOTSET)
372 fprintf(fp, " %10.3e", plist[ftp].param[i].c[j]);
380 static void print_rtp(const char *filenm, const char *title, t_atoms *atoms,
381 t_params plist[], gpp_atomtype_t atype, int cgnr[])
387 fp = gmx_fio_fopen(filenm, "w");
388 fprintf(fp, "; %s\n", title);
390 fprintf(fp, "[ %s ]\n", *atoms->resinfo[0].name);
392 fprintf(fp, "[ atoms ]\n");
393 for (i = 0; (i < atoms->nr); i++)
395 tp = atoms->atom[i].type;
396 if ((tpnm = get_atomtype_name(tp, atype)) == NULL)
398 gmx_fatal(FARGS, "tp = %d, i = %d in print_rtp", tp, i);
400 fprintf(fp, "%-8s %12s %8.4f %5d\n",
401 *atoms->atomname[i], tpnm,
402 atoms->atom[i].q, cgnr[i]);
404 print_pl(fp, plist, F_BONDS, "bonds", atoms->atomname);
405 print_pl(fp, plist, F_ANGLES, "angles", atoms->atomname);
406 print_pl(fp, plist, F_PDIHS, "dihedrals", atoms->atomname);
407 print_pl(fp, plist, F_IDIHS, "impropers", atoms->atomname);
412 int gmx_x2top(int argc, char *argv[])
414 const char *desc[] = {
415 "[THISMODULE] generates a primitive topology from a coordinate file.",
416 "The program assumes all hydrogens are present when defining",
417 "the hybridization from the atom name and the number of bonds.",
418 "The program can also make an [TT].rtp[tt] entry, which you can then add",
419 "to the [TT].rtp[tt] database.[PAR]",
420 "When [TT]-param[tt] is set, equilibrium distances and angles",
421 "and force constants will be printed in the topology for all",
422 "interactions. The equilibrium distances and angles are taken",
423 "from the input coordinates, the force constant are set with",
424 "command line options.",
425 "The force fields somewhat supported currently are:[PAR]",
426 "G53a5 GROMOS96 53a5 Forcefield (official distribution)[PAR]",
427 "oplsaa OPLS-AA/L all-atom force field (2001 aminoacid dihedrals)[PAR]",
428 "The corresponding data files can be found in the library directory",
429 "with name [TT]atomname2type.n2t[tt]. Check Chapter 5 of the manual for more",
430 "information about file formats. By default, the force field selection",
431 "is interactive, but you can use the [TT]-ff[tt] option to specify",
432 "one of the short names above on the command line instead. In that",
433 "case [THISMODULE] just looks for the corresponding file.[PAR]",
435 const char *bugs[] = {
436 "The atom type selection is primitive. Virtually no chemical knowledge is used",
437 "Periodic boundary conditions screw up the bonding",
438 "No improper dihedrals are generated",
439 "The atoms to atomtype translation table is incomplete ([TT]atomname2type.n2t[tt] file in the data directory). Please extend it and send the results back to the GROMACS crew."
442 t_params plist[F_NRE];
444 t_atoms *atoms; /* list with all atoms */
445 gpp_atomtype_t atype;
450 char title[STRLEN], forcefield[32], ffdir[STRLEN];
451 rvec *x; /* coordinates? */
453 int bts[] = { 1, 1, 1, 2 };
454 matrix box; /* box length matrix */
455 int natoms; /* number of atoms in one molecule */
456 int nres; /* number of molecules? */
457 int i, j, k, l, m, ndih;
459 gmx_bool bRTP, bTOP, bOPLS;
461 real cutoff, qtot, mtot;
466 { efSTX, "-f", "conf", ffREAD },
467 { efTOP, "-o", "out", ffOPTWR },
468 { efRTP, "-r", "out", ffOPTWR }
470 #define NFILE asize(fnm)
471 static real scale = 1.1, kb = 4e5, kt = 400, kp = 5;
472 static t_restp rtp_header_settings;
473 static gmx_bool bRemoveDihedralIfWithImproper = FALSE;
474 static gmx_bool bGenerateHH14Interactions = TRUE;
475 static gmx_bool bKeepAllGeneratedDihedrals = FALSE;
476 static int nrexcl = 3;
477 static gmx_bool bParam = TRUE, bRound = TRUE;
478 static gmx_bool bPairs = TRUE, bPBC = TRUE;
479 static gmx_bool bUsePDBcharge = FALSE, bVerbose = FALSE;
480 static const char *molnm = "ICE";
481 static const char *ff = "oplsaa";
483 { "-ff", FALSE, etSTR, {&ff},
484 "Force field for your simulation. Type \"select\" for interactive selection." },
485 { "-v", FALSE, etBOOL, {&bVerbose},
486 "Generate verbose output in the top file." },
487 { "-nexcl", FALSE, etINT, {&nrexcl},
488 "Number of exclusions" },
489 { "-H14", FALSE, etBOOL, {&bGenerateHH14Interactions},
490 "Use 3rd neighbour interactions for hydrogen atoms" },
491 { "-alldih", FALSE, etBOOL, {&bKeepAllGeneratedDihedrals},
492 "Generate all proper dihedrals" },
493 { "-remdih", FALSE, etBOOL, {&bRemoveDihedralIfWithImproper},
494 "Remove dihedrals on the same bond as an improper" },
495 { "-pairs", FALSE, etBOOL, {&bPairs},
496 "Output 1-4 interactions (pairs) in topology file" },
497 { "-name", FALSE, etSTR, {&molnm},
498 "Name of your molecule" },
499 { "-pbc", FALSE, etBOOL, {&bPBC},
500 "Use periodic boundary conditions." },
501 { "-pdbq", FALSE, etBOOL, {&bUsePDBcharge},
502 "Use the B-factor supplied in a [TT].pdb[tt] file for the atomic charges" },
503 { "-param", FALSE, etBOOL, {&bParam},
504 "Print parameters in the output" },
505 { "-round", FALSE, etBOOL, {&bRound},
506 "Round off measured values" },
507 { "-kb", FALSE, etREAL, {&kb},
508 "Bonded force constant (kJ/mol/nm^2)" },
509 { "-kt", FALSE, etREAL, {&kt},
510 "Angle force constant (kJ/mol/rad^2)" },
511 { "-kp", FALSE, etREAL, {&kp},
512 "Dihedral angle force constant (kJ/mol/rad^2)" }
515 if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa,
516 asize(desc), desc, asize(bugs), bugs, &oenv))
520 bRTP = opt2bSet("-r", NFILE, fnm);
521 bTOP = opt2bSet("-o", NFILE, fnm);
522 /* C89 requirements mean that these struct members cannot be used in
523 * the declaration of pa. So some temporary variables are needed. */
524 rtp_header_settings.bRemoveDihedralIfWithImproper = bRemoveDihedralIfWithImproper;
525 rtp_header_settings.bGenerateHH14Interactions = bGenerateHH14Interactions;
526 rtp_header_settings.bKeepAllGeneratedDihedrals = bKeepAllGeneratedDihedrals;
527 rtp_header_settings.nrexcl = nrexcl;
531 gmx_fatal(FARGS, "Specify at least one output file");
534 /* Force field selection, interactive or direct */
535 choose_ff(strcmp(ff, "select") == 0 ? NULL : ff,
536 forcefield, sizeof(forcefield),
537 ffdir, sizeof(ffdir));
539 bOPLS = (strcmp(forcefield, "oplsaa") == 0);
542 mymol.name = strdup(molnm);
545 /* Init parameter lists */
548 /* Read coordinates */
549 get_stx_coordnum(opt2fn("-f", NFILE, fnm), &natoms);
552 /* make space for all the atoms */
553 init_t_atoms(atoms, natoms, TRUE);
556 read_stx_conf(opt2fn("-f", NFILE, fnm), title, atoms, x, NULL, &epbc, box);
558 sprintf(n2t, "%s", ffdir);
559 nm2t = rd_nm2type(n2t, &nnm);
562 gmx_fatal(FARGS, "No or incorrect atomname2type.n2t file found (looking for %s)",
567 printf("There are %d name to type translations in file %s\n", nnm, n2t);
571 dump_nm2type(debug, nnm, nm2t);
573 printf("Generating bonds from distances...\n");
574 snew(nbonds, atoms->nr);
575 mk_bonds(nnm, nm2t, atoms, x, &(plist[F_BONDS]), nbonds, bPBC, box);
577 open_symtab(&symtab);
578 atype = set_atom_type(&symtab, atoms, &(plist[F_BONDS]), nbonds, nnm, nm2t);
580 /* Make Angles and Dihedrals */
581 snew(excls, atoms->nr);
582 printf("Generating angles and dihedrals from bonds...\n");
583 init_nnb(&nnb, atoms->nr, 4);
584 gen_nnb(&nnb, plist);
585 print_nnb(&nnb, "NNB");
586 gen_pad(&nnb, atoms, &rtp_header_settings, plist, excls, NULL, TRUE);
591 plist[F_LJ14].nr = 0;
594 "There are %4d %s dihedrals, %4d impropers, %4d angles\n"
595 " %4d pairs, %4d bonds and %4d atoms\n",
597 bOPLS ? "Ryckaert-Bellemans" : "proper",
598 plist[F_IDIHS].nr, plist[F_ANGLES].nr,
599 plist[F_LJ14].nr, plist[F_BONDS].nr, atoms->nr);
601 calc_angles_dihs(&plist[F_ANGLES], &plist[F_PDIHS], x, bPBC, box);
603 set_force_const(plist, kb, kt, kp, bRound, bParam);
605 cgnr = set_cgnr(atoms, bUsePDBcharge, &qtot, &mtot);
606 printf("Total charge is %g, total mass is %g\n", qtot, mtot);
615 fp = ftp2FILE(efTOP, NFILE, fnm, "w");
616 print_top_header(fp, ftp2fn(efTOP, NFILE, fnm), TRUE, ffdir, 1.0);
618 write_top(fp, NULL, mymol.name, atoms, FALSE, bts, plist, excls, atype,
619 cgnr, rtp_header_settings.nrexcl);
620 print_top_mols(fp, mymol.name, ffdir, NULL, 0, NULL, 1, &mymol);
626 print_rtp(ftp2fn(efRTP, NFILE, fnm), "Generated by x2top",
627 atoms, plist, atype, cgnr);
632 dump_hybridization(debug, atoms, nbonds);
634 close_symtab(&symtab);
637 printf("\nWARNING: topologies generated by %s can not be trusted at face value.\n",
639 printf(" Please verify atomtypes and charges by comparison to other\n");
640 printf(" topologies.\n");