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"
51 #include "gromacs/utility/smalloc.h"
53 #include "gromacs/fileio/confio.h"
55 #include "gromacs/commandline/pargs.h"
57 #include "gromacs/math/3dview.h"
64 #include "gpp_nextnb.h"
67 #include "hackblock.h"
71 char atp[7] = "HCNOSX";
72 #define NATP (asize(atp)-1)
74 real blen[NATP][NATP] = {
75 { 0.00, 0.108, 0.105, 0.10, 0.10, 0.10 },
76 { 0.108, 0.15, 0.14, 0.14, 0.16, 0.14 },
77 { 0.105, 0.14, 0.14, 0.14, 0.16, 0.14 },
78 { 0.10, 0.14, 0.14, 0.14, 0.17, 0.14 },
79 { 0.10, 0.16, 0.16, 0.17, 0.20, 0.17 },
80 { 0.10, 0.14, 0.14, 0.14, 0.17, 0.17 }
83 #define MARGIN_FAC 1.1
85 static gmx_bool is_bond(int nnm, t_nm2type nmt[], char *ai, char *aj, real blen)
89 for (i = 0; (i < nnm); i++)
91 for (j = 0; (j < nmt[i].nbonds); j++)
93 if ((((gmx_strncasecmp(ai, nmt[i].elem, 1) == 0) &&
94 (gmx_strncasecmp(aj, nmt[i].bond[j], 1) == 0)) ||
95 ((gmx_strncasecmp(ai, nmt[i].bond[j], 1) == 0) &&
96 (gmx_strncasecmp(aj, nmt[i].elem, 1) == 0))) &&
97 (fabs(blen-nmt[i].blen[j]) <= 0.1*nmt[i].blen[j]))
106 static int get_atype(char *nm)
110 for (i = 0; (i < NATP-1); i++)
121 void mk_bonds(int nnm, t_nm2type nmt[],
122 t_atoms *atoms, rvec x[], t_params *bond, int nbond[],
123 gmx_bool bPBC, matrix box)
131 for (i = 0; (i < MAXATOMLIST); i++)
135 for (i = 0; (i < MAXFORCEPARAM); i++)
142 set_pbc(&pbc, -1, box);
144 for (i = 0; (i < atoms->nr); i++)
148 fprintf(stderr, "\ratom %d", i);
150 for (j = i+1; (j < atoms->nr); j++)
154 pbc_dx(&pbc, x[i], x[j], dx);
158 rvec_sub(x[i], x[j], dx);
162 if (is_bond(nnm, nmt, *atoms->atomname[i], *atoms->atomname[j],
168 add_param_to_list (bond, &b);
173 fprintf(debug, "Bonding atoms %s-%d and %s-%d\n",
174 *atoms->atomname[i], i+1, *atoms->atomname[j], j+1);
179 fprintf(stderr, "\ratom %d\n", i);
182 int *set_cgnr(t_atoms *atoms, gmx_bool bUsePDBcharge, real *qtot, real *mtot)
186 double qt = 0, mt = 0;
189 snew(cgnr, atoms->nr);
190 for (i = 0; (i < atoms->nr); i++)
192 if (atoms->pdbinfo && bUsePDBcharge)
194 atoms->atom[i].q = atoms->pdbinfo[i].bfac;
196 qt += atoms->atom[i].q;
197 *qtot += atoms->atom[i].q;
198 *mtot += atoms->atom[i].m;
209 gpp_atomtype_t set_atom_type(t_symtab *tab, t_atoms *atoms, t_params *bonds,
210 int *nbonds, int nnm, t_nm2type nm2t[])
212 gpp_atomtype_t atype;
215 atype = init_atomtype();
216 snew(atoms->atomtype, atoms->nr);
217 nresolved = nm2type(nnm, nm2t, tab, atoms, atype, nbonds, bonds);
218 if (nresolved != atoms->nr)
220 gmx_fatal(FARGS, "Could only find a forcefield type for %d out of %d atoms",
221 nresolved, atoms->nr);
224 fprintf(stderr, "There are %d different atom types in your sample\n",
225 get_atomtype_ntypes(atype));
230 void lo_set_force_const(t_params *plist, real c[], int nrfp, gmx_bool bRound,
231 gmx_bool bDih, gmx_bool bParam)
237 for (i = 0; (i < plist->nr); i++)
241 for (j = 0; j < nrfp; j++)
250 sprintf(buf, "%.2e", plist->param[i].c[0]);
251 sscanf(buf, "%lf", &cc);
256 c[0] = plist->param[i].c[0];
261 c[0] = ((int)(c[0] + 3600)) % 360;
266 /* To put the minimum at the current angle rather than the maximum */
270 assert(nrfp <= MAXFORCEPARAM/2);
271 for (j = 0; (j < nrfp); j++)
273 plist->param[i].c[j] = c[j];
274 plist->param[i].c[nrfp+j] = c[j];
276 set_p_string(&(plist->param[i]), "");
280 void set_force_const(t_params plist[], real kb, real kt, real kp, gmx_bool bRound,
284 real c[MAXFORCEPARAM];
288 lo_set_force_const(&plist[F_BONDS], c, 2, bRound, FALSE, bParam);
290 lo_set_force_const(&plist[F_ANGLES], c, 2, bRound, FALSE, bParam);
293 lo_set_force_const(&plist[F_PDIHS], c, 3, bRound, TRUE, bParam);
296 void calc_angles_dihs(t_params *ang, t_params *dih, rvec x[], gmx_bool bPBC,
299 int i, ai, aj, ak, al, t1, t2, t3;
300 rvec r_ij, r_kj, r_kl, m, n;
301 real sign, th, costh, ph;
306 set_pbc(&pbc, epbcXYZ, box);
310 pr_rvecs(debug, 0, "X2TOP", box, DIM);
312 for (i = 0; (i < ang->nr); i++)
314 ai = ang->param[i].AI;
315 aj = ang->param[i].AJ;
316 ak = ang->param[i].AK;
317 th = RAD2DEG*bond_angle(x[ai], x[aj], x[ak], bPBC ? &pbc : NULL,
318 r_ij, r_kj, &costh, &t1, &t2);
321 fprintf(debug, "X2TOP: ai=%3d aj=%3d ak=%3d r_ij=%8.3f r_kj=%8.3f th=%8.3f\n",
322 ai, aj, ak, norm(r_ij), norm(r_kj), th);
324 ang->param[i].C0 = th;
326 for (i = 0; (i < dih->nr); i++)
328 ai = dih->param[i].AI;
329 aj = dih->param[i].AJ;
330 ak = dih->param[i].AK;
331 al = dih->param[i].AL;
332 ph = RAD2DEG*dih_angle(x[ai], x[aj], x[ak], x[al], bPBC ? &pbc : NULL,
333 r_ij, r_kj, r_kl, m, n, &sign, &t1, &t2, &t3);
336 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",
337 ai, aj, ak, al, norm(r_ij), norm(r_kj), norm(r_kl), ph);
339 dih->param[i].C0 = ph;
343 static void dump_hybridization(FILE *fp, t_atoms *atoms, int nbonds[])
347 for (i = 0; (i < atoms->nr); i++)
349 fprintf(fp, "Atom %5s has %1d bonds\n", *atoms->atomname[i], nbonds[i]);
353 static void print_pl(FILE *fp, t_params plist[], int ftp, const char *name,
356 int i, j, nral, nrfp;
358 if (plist[ftp].nr > 0)
361 fprintf(fp, "[ %s ]\n", name);
362 nral = interaction_function[ftp].nratoms;
363 nrfp = interaction_function[ftp].nrfpA;
364 for (i = 0; (i < plist[ftp].nr); i++)
366 for (j = 0; (j < nral); j++)
368 fprintf(fp, " %5s", *atomname[plist[ftp].param[i].a[j]]);
370 for (j = 0; (j < nrfp); j++)
372 if (plist[ftp].param[i].c[j] != NOTSET)
374 fprintf(fp, " %10.3e", plist[ftp].param[i].c[j]);
382 static void print_rtp(const char *filenm, const char *title, t_atoms *atoms,
383 t_params plist[], gpp_atomtype_t atype, int cgnr[])
389 fp = gmx_fio_fopen(filenm, "w");
390 fprintf(fp, "; %s\n", title);
392 fprintf(fp, "[ %s ]\n", *atoms->resinfo[0].name);
394 fprintf(fp, "[ atoms ]\n");
395 for (i = 0; (i < atoms->nr); i++)
397 tp = atoms->atom[i].type;
398 if ((tpnm = get_atomtype_name(tp, atype)) == NULL)
400 gmx_fatal(FARGS, "tp = %d, i = %d in print_rtp", tp, i);
402 fprintf(fp, "%-8s %12s %8.4f %5d\n",
403 *atoms->atomname[i], tpnm,
404 atoms->atom[i].q, cgnr[i]);
406 print_pl(fp, plist, F_BONDS, "bonds", atoms->atomname);
407 print_pl(fp, plist, F_ANGLES, "angles", atoms->atomname);
408 print_pl(fp, plist, F_PDIHS, "dihedrals", atoms->atomname);
409 print_pl(fp, plist, F_IDIHS, "impropers", atoms->atomname);
414 int gmx_x2top(int argc, char *argv[])
416 const char *desc[] = {
417 "[THISMODULE] generates a primitive topology from a coordinate file.",
418 "The program assumes all hydrogens are present when defining",
419 "the hybridization from the atom name and the number of bonds.",
420 "The program can also make an [TT].rtp[tt] entry, which you can then add",
421 "to the [TT].rtp[tt] database.[PAR]",
422 "When [TT]-param[tt] is set, equilibrium distances and angles",
423 "and force constants will be printed in the topology for all",
424 "interactions. The equilibrium distances and angles are taken",
425 "from the input coordinates, the force constant are set with",
426 "command line options.",
427 "The force fields somewhat supported currently are:[PAR]",
428 "G53a5 GROMOS96 53a5 Forcefield (official distribution)[PAR]",
429 "oplsaa OPLS-AA/L all-atom force field (2001 aminoacid dihedrals)[PAR]",
430 "The corresponding data files can be found in the library directory",
431 "with name [TT]atomname2type.n2t[tt]. Check Chapter 5 of the manual for more",
432 "information about file formats. By default, the force field selection",
433 "is interactive, but you can use the [TT]-ff[tt] option to specify",
434 "one of the short names above on the command line instead. In that",
435 "case [THISMODULE] just looks for the corresponding file.[PAR]",
437 const char *bugs[] = {
438 "The atom type selection is primitive. Virtually no chemical knowledge is used",
439 "Periodic boundary conditions screw up the bonding",
440 "No improper dihedrals are generated",
441 "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."
444 t_params plist[F_NRE];
446 t_atoms *atoms; /* list with all atoms */
447 gpp_atomtype_t atype;
452 char title[STRLEN], forcefield[32], ffdir[STRLEN];
453 rvec *x; /* coordinates? */
455 int bts[] = { 1, 1, 1, 2 };
456 matrix box; /* box length matrix */
457 int natoms; /* number of atoms in one molecule */
458 int nres; /* number of molecules? */
459 int i, j, k, l, m, ndih;
461 gmx_bool bRTP, bTOP, bOPLS;
463 real cutoff, qtot, mtot;
468 { efSTX, "-f", "conf", ffREAD },
469 { efTOP, "-o", "out", ffOPTWR },
470 { efRTP, "-r", "out", ffOPTWR }
472 #define NFILE asize(fnm)
473 static real scale = 1.1, kb = 4e5, kt = 400, kp = 5;
474 static t_restp rtp_header_settings;
475 static gmx_bool bRemoveDihedralIfWithImproper = FALSE;
476 static gmx_bool bGenerateHH14Interactions = TRUE;
477 static gmx_bool bKeepAllGeneratedDihedrals = FALSE;
478 static int nrexcl = 3;
479 static gmx_bool bParam = TRUE, bRound = TRUE;
480 static gmx_bool bPairs = TRUE, bPBC = TRUE;
481 static gmx_bool bUsePDBcharge = FALSE, bVerbose = FALSE;
482 static const char *molnm = "ICE";
483 static const char *ff = "oplsaa";
485 { "-ff", FALSE, etSTR, {&ff},
486 "Force field for your simulation. Type \"select\" for interactive selection." },
487 { "-v", FALSE, etBOOL, {&bVerbose},
488 "Generate verbose output in the top file." },
489 { "-nexcl", FALSE, etINT, {&nrexcl},
490 "Number of exclusions" },
491 { "-H14", FALSE, etBOOL, {&bGenerateHH14Interactions},
492 "Use 3rd neighbour interactions for hydrogen atoms" },
493 { "-alldih", FALSE, etBOOL, {&bKeepAllGeneratedDihedrals},
494 "Generate all proper dihedrals" },
495 { "-remdih", FALSE, etBOOL, {&bRemoveDihedralIfWithImproper},
496 "Remove dihedrals on the same bond as an improper" },
497 { "-pairs", FALSE, etBOOL, {&bPairs},
498 "Output 1-4 interactions (pairs) in topology file" },
499 { "-name", FALSE, etSTR, {&molnm},
500 "Name of your molecule" },
501 { "-pbc", FALSE, etBOOL, {&bPBC},
502 "Use periodic boundary conditions." },
503 { "-pdbq", FALSE, etBOOL, {&bUsePDBcharge},
504 "Use the B-factor supplied in a [TT].pdb[tt] file for the atomic charges" },
505 { "-param", FALSE, etBOOL, {&bParam},
506 "Print parameters in the output" },
507 { "-round", FALSE, etBOOL, {&bRound},
508 "Round off measured values" },
509 { "-kb", FALSE, etREAL, {&kb},
510 "Bonded force constant (kJ/mol/nm^2)" },
511 { "-kt", FALSE, etREAL, {&kt},
512 "Angle force constant (kJ/mol/rad^2)" },
513 { "-kp", FALSE, etREAL, {&kp},
514 "Dihedral angle force constant (kJ/mol/rad^2)" }
517 if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa,
518 asize(desc), desc, asize(bugs), bugs, &oenv))
522 bRTP = opt2bSet("-r", NFILE, fnm);
523 bTOP = opt2bSet("-o", NFILE, fnm);
524 /* C89 requirements mean that these struct members cannot be used in
525 * the declaration of pa. So some temporary variables are needed. */
526 rtp_header_settings.bRemoveDihedralIfWithImproper = bRemoveDihedralIfWithImproper;
527 rtp_header_settings.bGenerateHH14Interactions = bGenerateHH14Interactions;
528 rtp_header_settings.bKeepAllGeneratedDihedrals = bKeepAllGeneratedDihedrals;
529 rtp_header_settings.nrexcl = nrexcl;
533 gmx_fatal(FARGS, "Specify at least one output file");
536 /* Force field selection, interactive or direct */
537 choose_ff(strcmp(ff, "select") == 0 ? NULL : ff,
538 forcefield, sizeof(forcefield),
539 ffdir, sizeof(ffdir));
541 bOPLS = (strcmp(forcefield, "oplsaa") == 0);
544 mymol.name = strdup(molnm);
547 /* Init parameter lists */
550 /* Read coordinates */
551 get_stx_coordnum(opt2fn("-f", NFILE, fnm), &natoms);
554 /* make space for all the atoms */
555 init_t_atoms(atoms, natoms, TRUE);
558 read_stx_conf(opt2fn("-f", NFILE, fnm), title, atoms, x, NULL, &epbc, box);
560 sprintf(n2t, "%s", ffdir);
561 nm2t = rd_nm2type(n2t, &nnm);
564 gmx_fatal(FARGS, "No or incorrect atomname2type.n2t file found (looking for %s)",
569 printf("There are %d name to type translations in file %s\n", nnm, n2t);
573 dump_nm2type(debug, nnm, nm2t);
575 printf("Generating bonds from distances...\n");
576 snew(nbonds, atoms->nr);
577 mk_bonds(nnm, nm2t, atoms, x, &(plist[F_BONDS]), nbonds, bPBC, box);
579 open_symtab(&symtab);
580 atype = set_atom_type(&symtab, atoms, &(plist[F_BONDS]), nbonds, nnm, nm2t);
582 /* Make Angles and Dihedrals */
583 snew(excls, atoms->nr);
584 printf("Generating angles and dihedrals from bonds...\n");
585 init_nnb(&nnb, atoms->nr, 4);
586 gen_nnb(&nnb, plist);
587 print_nnb(&nnb, "NNB");
588 gen_pad(&nnb, atoms, &rtp_header_settings, plist, excls, NULL, TRUE);
593 plist[F_LJ14].nr = 0;
596 "There are %4d %s dihedrals, %4d impropers, %4d angles\n"
597 " %4d pairs, %4d bonds and %4d atoms\n",
599 bOPLS ? "Ryckaert-Bellemans" : "proper",
600 plist[F_IDIHS].nr, plist[F_ANGLES].nr,
601 plist[F_LJ14].nr, plist[F_BONDS].nr, atoms->nr);
603 calc_angles_dihs(&plist[F_ANGLES], &plist[F_PDIHS], x, bPBC, box);
605 set_force_const(plist, kb, kt, kp, bRound, bParam);
607 cgnr = set_cgnr(atoms, bUsePDBcharge, &qtot, &mtot);
608 printf("Total charge is %g, total mass is %g\n", qtot, mtot);
617 fp = ftp2FILE(efTOP, NFILE, fnm, "w");
618 print_top_header(fp, ftp2fn(efTOP, NFILE, fnm), TRUE, ffdir, 1.0);
620 write_top(fp, NULL, mymol.name, atoms, FALSE, bts, plist, excls, atype,
621 cgnr, rtp_header_settings.nrexcl);
622 print_top_mols(fp, mymol.name, ffdir, NULL, 0, NULL, 1, &mymol);
628 print_rtp(ftp2fn(efRTP, NFILE, fnm), "Generated by x2top",
629 atoms, plist, atype, cgnr);
634 dump_hybridization(debug, atoms, nbonds);
636 close_symtab(&symtab);
639 printf("\nWARNING: topologies generated by %s can not be trusted at face value.\n",
641 printf(" Please verify atomtypes and charges by comparison to other\n");
642 printf(" topologies.\n");