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,2015,2016,2017,2018,2019, 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.
44 #include "gromacs/commandline/pargs.h"
45 #include "gromacs/fileio/confio.h"
46 #include "gromacs/fileio/gmxfio.h"
47 #include "gromacs/gmxpreprocess/gen_ad.h"
48 #include "gromacs/gmxpreprocess/gpp_atomtype.h"
49 #include "gromacs/gmxpreprocess/gpp_nextnb.h"
50 #include "gromacs/gmxpreprocess/grompp-impl.h"
51 #include "gromacs/gmxpreprocess/hackblock.h"
52 #include "gromacs/gmxpreprocess/nm2type.h"
53 #include "gromacs/gmxpreprocess/notset.h"
54 #include "gromacs/gmxpreprocess/pdb2top.h"
55 #include "gromacs/gmxpreprocess/toppush.h"
56 #include "gromacs/gmxpreprocess/toputil.h"
57 #include "gromacs/listed-forces/bonded.h"
58 #include "gromacs/math/units.h"
59 #include "gromacs/math/utilities.h"
60 #include "gromacs/math/vec.h"
61 #include "gromacs/math/vecdump.h"
62 #include "gromacs/mdtypes/md_enums.h"
63 #include "gromacs/pbcutil/pbc.h"
64 #include "gromacs/topology/symtab.h"
65 #include "gromacs/topology/topology.h"
66 #include "gromacs/utility/arraysize.h"
67 #include "gromacs/utility/cstringutil.h"
68 #include "gromacs/utility/fatalerror.h"
69 #include "gromacs/utility/gmxassert.h"
70 #include "gromacs/utility/smalloc.h"
72 #define MARGIN_FAC 1.1
74 static bool is_bond(int nnm, t_nm2type nmt[], char *ai, char *aj, real blen)
78 for (i = 0; (i < nnm); i++)
80 for (j = 0; (j < nmt[i].nbonds); j++)
82 if ((((gmx_strncasecmp(ai, nmt[i].elem, 1) == 0) &&
83 (gmx_strncasecmp(aj, nmt[i].bond[j], 1) == 0)) ||
84 ((gmx_strncasecmp(ai, nmt[i].bond[j], 1) == 0) &&
85 (gmx_strncasecmp(aj, nmt[i].elem, 1) == 0))) &&
86 (fabs(blen-nmt[i].blen[j]) <= 0.1*nmt[i].blen[j]))
95 static void mk_bonds(int nnm, t_nm2type nmt[],
96 t_atoms *atoms, const rvec x[], t_params *bond, int nbond[],
97 bool bPBC, matrix box)
105 for (i = 0; (i < MAXATOMLIST); i++)
109 for (i = 0; (i < MAXFORCEPARAM); i++)
116 set_pbc(&pbc, -1, box);
118 for (i = 0; (i < atoms->nr); i++)
122 fprintf(stderr, "\ratom %d", i);
125 for (j = i+1; (j < atoms->nr); j++)
129 pbc_dx(&pbc, x[i], x[j], dx);
133 rvec_sub(x[i], x[j], dx);
137 if (is_bond(nnm, nmt, *atoms->atomname[i], *atoms->atomname[j],
142 b.c0() = std::sqrt(dx2);
143 add_param_to_list (bond, &b);
149 fprintf(stderr, "\ratom %d\n", i);
153 static int *set_cgnr(t_atoms *atoms, bool bUsePDBcharge, real *qtot, real *mtot)
160 snew(cgnr, atoms->nr);
161 for (i = 0; (i < atoms->nr); i++)
163 if (atoms->pdbinfo && bUsePDBcharge)
165 atoms->atom[i].q = atoms->pdbinfo[i].bfac;
167 qt += atoms->atom[i].q;
168 *qtot += atoms->atom[i].q;
169 *mtot += atoms->atom[i].m;
180 static gpp_atomtype *set_atom_type(t_symtab *tab, t_atoms *atoms, t_params *bonds,
181 int *nbonds, int nnm, t_nm2type nm2t[])
186 atype = init_atomtype();
187 snew(atoms->atomtype, atoms->nr);
188 nresolved = nm2type(nnm, nm2t, tab, atoms, atype, nbonds, bonds);
189 if (nresolved != atoms->nr)
191 gmx_fatal(FARGS, "Could only find a forcefield type for %d out of %d atoms",
192 nresolved, atoms->nr);
195 fprintf(stderr, "There are %d different atom types in your sample\n",
196 get_atomtype_ntypes(atype));
201 static void lo_set_force_const(t_params *plist, real c[], int nrfp, bool bRound,
202 bool bDih, bool bParam)
208 for (i = 0; (i < plist->nr); i++)
212 for (j = 0; j < nrfp; j++)
221 sprintf(buf, "%.2e", plist->param[i].c[0]);
222 sscanf(buf, "%lf", &cc);
227 c[0] = plist->param[i].c[0];
232 c[0] = (static_cast<int>(c[0] + 3600)) % 360;
237 /* To put the minimum at the current angle rather than the maximum */
241 GMX_ASSERT(nrfp <= MAXFORCEPARAM/2, "Only 6 parameters may be used for an interaction");
242 for (j = 0; (j < nrfp); j++)
244 plist->param[i].c[j] = c[j];
245 plist->param[i].c[nrfp+j] = c[j];
247 set_p_string(&(plist->param[i]), "");
251 static void set_force_const(t_params plist[], real kb, real kt, real kp, bool bRound,
254 real c[MAXFORCEPARAM];
258 lo_set_force_const(&plist[F_BONDS], c, 2, bRound, FALSE, bParam);
260 lo_set_force_const(&plist[F_ANGLES], c, 2, bRound, FALSE, bParam);
263 lo_set_force_const(&plist[F_PDIHS], c, 3, bRound, TRUE, bParam);
266 static void calc_angles_dihs(t_params *ang, t_params *dih, const rvec x[], bool bPBC,
269 int i, ai, aj, ak, al, t1, t2, t3;
270 rvec r_ij, r_kj, r_kl, m, n;
276 set_pbc(&pbc, epbcXYZ, box);
278 for (i = 0; (i < ang->nr); i++)
280 ai = ang->param[i].ai();
281 aj = ang->param[i].aj();
282 ak = ang->param[i].ak();
283 th = RAD2DEG*bond_angle(x[ai], x[aj], x[ak], bPBC ? &pbc : nullptr,
284 r_ij, r_kj, &costh, &t1, &t2);
285 ang->param[i].c0() = th;
287 for (i = 0; (i < dih->nr); i++)
289 ai = dih->param[i].ai();
290 aj = dih->param[i].aj();
291 ak = dih->param[i].ak();
292 al = dih->param[i].al();
293 ph = RAD2DEG*dih_angle(x[ai], x[aj], x[ak], x[al], bPBC ? &pbc : nullptr,
294 r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3);
295 dih->param[i].c0() = ph;
299 static void dump_hybridization(FILE *fp, t_atoms *atoms, int nbonds[])
303 for (i = 0; (i < atoms->nr); i++)
305 fprintf(fp, "Atom %5s has %1d bonds\n", *atoms->atomname[i], nbonds[i]);
309 static void print_pl(FILE *fp, t_params plist[], int ftp, const char *name,
312 int i, j, nral, nrfp;
314 if (plist[ftp].nr > 0)
317 fprintf(fp, "[ %s ]\n", name);
318 nral = interaction_function[ftp].nratoms;
319 nrfp = interaction_function[ftp].nrfpA;
320 for (i = 0; (i < plist[ftp].nr); i++)
322 for (j = 0; (j < nral); j++)
324 fprintf(fp, " %5s", *atomname[plist[ftp].param[i].a[j]]);
326 for (j = 0; (j < nrfp); j++)
328 if (plist[ftp].param[i].c[j] != NOTSET)
330 fprintf(fp, " %10.3e", plist[ftp].param[i].c[j]);
338 static void print_rtp(const char *filenm, const char *title, t_atoms *atoms,
339 t_params plist[], gpp_atomtype *atype, int cgnr[])
345 fp = gmx_fio_fopen(filenm, "w");
346 fprintf(fp, "; %s\n", title);
348 fprintf(fp, "[ %s ]\n", *atoms->resinfo[0].name);
350 fprintf(fp, "[ atoms ]\n");
351 for (i = 0; (i < atoms->nr); i++)
353 tp = atoms->atom[i].type;
354 if ((tpnm = get_atomtype_name(tp, atype)) == nullptr)
356 gmx_fatal(FARGS, "tp = %d, i = %d in print_rtp", tp, i);
358 fprintf(fp, "%-8s %12s %8.4f %5d\n",
359 *atoms->atomname[i], tpnm,
360 atoms->atom[i].q, cgnr[i]);
362 print_pl(fp, plist, F_BONDS, "bonds", atoms->atomname);
363 print_pl(fp, plist, F_ANGLES, "angles", atoms->atomname);
364 print_pl(fp, plist, F_PDIHS, "dihedrals", atoms->atomname);
365 print_pl(fp, plist, F_IDIHS, "impropers", atoms->atomname);
370 int gmx_x2top(int argc, char *argv[])
372 const char *desc[] = {
373 "[THISMODULE] generates a primitive topology from a coordinate file.",
374 "The program assumes all hydrogens are present when defining",
375 "the hybridization from the atom name and the number of bonds.",
376 "The program can also make an [REF].rtp[ref] entry, which you can then add",
377 "to the [REF].rtp[ref] database.[PAR]",
378 "When [TT]-param[tt] is set, equilibrium distances and angles",
379 "and force constants will be printed in the topology for all",
380 "interactions. The equilibrium distances and angles are taken",
381 "from the input coordinates, the force constant are set with",
382 "command line options.",
383 "The force fields somewhat supported currently are:[PAR]",
384 "G53a5 GROMOS96 53a5 Forcefield (official distribution)[PAR]",
385 "oplsaa OPLS-AA/L all-atom force field (2001 aminoacid dihedrals)[PAR]",
386 "The corresponding data files can be found in the library directory",
387 "with name [TT]atomname2type.n2t[tt]. Check Chapter 5 of the manual for more",
388 "information about file formats. By default, the force field selection",
389 "is interactive, but you can use the [TT]-ff[tt] option to specify",
390 "one of the short names above on the command line instead. In that",
391 "case [THISMODULE] just looks for the corresponding file.[PAR]",
393 const char *bugs[] = {
394 "The atom type selection is primitive. Virtually no chemical knowledge is used",
395 "Periodic boundary conditions screw up the bonding",
396 "No improper dihedrals are generated",
397 "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."
400 t_params plist[F_NRE];
407 char forcefield[32], ffdir[STRLEN];
408 rvec *x; /* coordinates? */
410 int bts[] = { 1, 1, 1, 2 };
411 matrix box; /* box length matrix */
412 int natoms; /* number of atoms in one molecule */
414 bool bRTP, bTOP, bOPLS;
418 gmx_output_env_t *oenv;
421 { efSTX, "-f", "conf", ffREAD },
422 { efTOP, "-o", "out", ffOPTWR },
423 { efRTP, "-r", "out", ffOPTWR }
425 #define NFILE asize(fnm)
426 real kb = 4e5, kt = 400, kp = 5;
427 t_restp rtp_header_settings = { nullptr };
428 bool bRemoveDihedralIfWithImproper = FALSE;
429 bool bGenerateHH14Interactions = TRUE;
430 bool bKeepAllGeneratedDihedrals = FALSE;
432 bool bParam = TRUE, bRound = TRUE;
433 bool bPairs = TRUE, bPBC = TRUE;
434 bool bUsePDBcharge = FALSE, bVerbose = FALSE;
435 const char *molnm = "ICE";
436 const char *ff = "oplsaa";
438 { "-ff", FALSE, etSTR, {&ff},
439 "Force field for your simulation. Type \"select\" for interactive selection." },
440 { "-v", FALSE, etBOOL, {&bVerbose},
441 "Generate verbose output in the top file." },
442 { "-nexcl", FALSE, etINT, {&nrexcl},
443 "Number of exclusions" },
444 { "-H14", FALSE, etBOOL, {&bGenerateHH14Interactions},
445 "Use 3rd neighbour interactions for hydrogen atoms" },
446 { "-alldih", FALSE, etBOOL, {&bKeepAllGeneratedDihedrals},
447 "Generate all proper dihedrals" },
448 { "-remdih", FALSE, etBOOL, {&bRemoveDihedralIfWithImproper},
449 "Remove dihedrals on the same bond as an improper" },
450 { "-pairs", FALSE, etBOOL, {&bPairs},
451 "Output 1-4 interactions (pairs) in topology file" },
452 { "-name", FALSE, etSTR, {&molnm},
453 "Name of your molecule" },
454 { "-pbc", FALSE, etBOOL, {&bPBC},
455 "Use periodic boundary conditions." },
456 { "-pdbq", FALSE, etBOOL, {&bUsePDBcharge},
457 "Use the B-factor supplied in a [REF].pdb[ref] file for the atomic charges" },
458 { "-param", FALSE, etBOOL, {&bParam},
459 "Print parameters in the output" },
460 { "-round", FALSE, etBOOL, {&bRound},
461 "Round off measured values" },
462 { "-kb", FALSE, etREAL, {&kb},
463 "Bonded force constant (kJ/mol/nm^2)" },
464 { "-kt", FALSE, etREAL, {&kt},
465 "Angle force constant (kJ/mol/rad^2)" },
466 { "-kp", FALSE, etREAL, {&kp},
467 "Dihedral angle force constant (kJ/mol/rad^2)" }
470 if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa,
471 asize(desc), desc, asize(bugs), bugs, &oenv))
475 bRTP = opt2bSet("-r", NFILE, fnm);
476 bTOP = opt2bSet("-o", NFILE, fnm);
477 /* C89 requirements mean that these struct members cannot be used in
478 * the declaration of pa. So some temporary variables are needed. */
479 rtp_header_settings.bRemoveDihedralIfWithImproper = bRemoveDihedralIfWithImproper;
480 rtp_header_settings.bGenerateHH14Interactions = bGenerateHH14Interactions;
481 rtp_header_settings.bKeepAllGeneratedDihedrals = bKeepAllGeneratedDihedrals;
482 rtp_header_settings.nrexcl = nrexcl;
486 gmx_fatal(FARGS, "Specify at least one output file");
489 /* Force field selection, interactive or direct */
490 choose_ff(strcmp(ff, "select") == 0 ? nullptr : ff,
491 forcefield, sizeof(forcefield),
492 ffdir, sizeof(ffdir));
494 bOPLS = (strcmp(forcefield, "oplsaa") == 0);
497 mymol.name = gmx_strdup(molnm);
500 /* Init parameter lists */
503 /* Read coordinates */
506 read_tps_conf(opt2fn("-f", NFILE, fnm), top, &epbc, &x, nullptr, box, FALSE);
507 t_atoms *atoms = &top->atoms;
509 if (atoms->pdbinfo == nullptr)
511 snew(atoms->pdbinfo, natoms);
514 sprintf(n2t, "%s", ffdir);
515 nm2t = rd_nm2type(n2t, &nnm);
518 gmx_fatal(FARGS, "No or incorrect atomname2type.n2t file found (looking for %s)",
523 printf("There are %d name to type translations in file %s\n", nnm, n2t);
527 dump_nm2type(debug, nnm, nm2t);
529 printf("Generating bonds from distances...\n");
530 snew(nbonds, atoms->nr);
531 mk_bonds(nnm, nm2t, atoms, x, &(plist[F_BONDS]), nbonds, bPBC, box);
533 open_symtab(&symtab);
534 atype = set_atom_type(&symtab, atoms, &(plist[F_BONDS]), nbonds, nnm, nm2t);
536 /* Make Angles and Dihedrals */
537 snew(excls, atoms->nr);
538 printf("Generating angles and dihedrals from bonds...\n");
539 init_nnb(&nnb, atoms->nr, 4);
540 gen_nnb(&nnb, plist);
541 print_nnb(&nnb, "NNB");
542 gen_pad(&nnb, atoms, &rtp_header_settings, plist, excls, nullptr, TRUE);
547 plist[F_LJ14].nr = 0;
550 "There are %4d %s dihedrals, %4d impropers, %4d angles\n"
551 " %4d pairs, %4d bonds and %4d atoms\n",
553 bOPLS ? "Ryckaert-Bellemans" : "proper",
554 plist[F_IDIHS].nr, plist[F_ANGLES].nr,
555 plist[F_LJ14].nr, plist[F_BONDS].nr, atoms->nr);
557 calc_angles_dihs(&plist[F_ANGLES], &plist[F_PDIHS], x, bPBC, box);
559 set_force_const(plist, kb, kt, kp, bRound, bParam);
561 cgnr = set_cgnr(atoms, bUsePDBcharge, &qtot, &mtot);
562 printf("Total charge is %g, total mass is %g\n", qtot, mtot);
571 fp = ftp2FILE(efTOP, NFILE, fnm, "w");
572 print_top_header(fp, ftp2fn(efTOP, NFILE, fnm), TRUE, ffdir, 1.0);
574 write_top(fp, nullptr, mymol.name, atoms, FALSE, bts, plist, excls, atype,
575 cgnr, rtp_header_settings.nrexcl);
576 print_top_mols(fp, mymol.name, ffdir, nullptr, 0, nullptr, 1, &mymol);
582 print_rtp(ftp2fn(efRTP, NFILE, fnm), "Generated by x2top",
583 atoms, plist, atype, cgnr);
588 dump_hybridization(debug, atoms, nbonds);
590 close_symtab(&symtab);
593 printf("\nWARNING: topologies generated by %s can not be trusted at face value.\n",
594 output_env_get_program_display_name(oenv));
595 printf(" Please verify atomtypes and charges by comparison to other\n");
596 printf(" topologies.\n");