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.
44 #include "gromacs/math/utilities.h"
47 #include "gromacs/fileio/gmxfio.h"
48 #include "gromacs/fileio/confio.h"
49 #include "gromacs/math/units.h"
56 #include "gpp_nextnb.h"
57 #include "hackblock.h"
60 #include "gromacs/commandline/pargs.h"
61 #include "gromacs/math/vec.h"
62 #include "gromacs/pbcutil/pbc.h"
63 #include "gromacs/topology/symtab.h"
64 #include "gromacs/utility/cstringutil.h"
65 #include "gromacs/utility/fatalerror.h"
66 #include "gromacs/utility/smalloc.h"
68 char atp
[7] = "HCNOSX";
69 #define NATP (asize(atp)-1)
71 real blen
[NATP
][NATP
] = {
72 { 0.00, 0.108, 0.105, 0.10, 0.10, 0.10 },
73 { 0.108, 0.15, 0.14, 0.14, 0.16, 0.14 },
74 { 0.105, 0.14, 0.14, 0.14, 0.16, 0.14 },
75 { 0.10, 0.14, 0.14, 0.14, 0.17, 0.14 },
76 { 0.10, 0.16, 0.16, 0.17, 0.20, 0.17 },
77 { 0.10, 0.14, 0.14, 0.14, 0.17, 0.17 }
80 #define MARGIN_FAC 1.1
82 static gmx_bool
is_bond(int nnm
, t_nm2type nmt
[], char *ai
, char *aj
, real blen
)
86 for (i
= 0; (i
< nnm
); i
++)
88 for (j
= 0; (j
< nmt
[i
].nbonds
); j
++)
90 if ((((gmx_strncasecmp(ai
, nmt
[i
].elem
, 1) == 0) &&
91 (gmx_strncasecmp(aj
, nmt
[i
].bond
[j
], 1) == 0)) ||
92 ((gmx_strncasecmp(ai
, nmt
[i
].bond
[j
], 1) == 0) &&
93 (gmx_strncasecmp(aj
, nmt
[i
].elem
, 1) == 0))) &&
94 (fabs(blen
-nmt
[i
].blen
[j
]) <= 0.1*nmt
[i
].blen
[j
]))
103 static int get_atype(char *nm
)
107 for (i
= 0; (i
< NATP
-1); i
++)
118 void mk_bonds(int nnm
, t_nm2type nmt
[],
119 t_atoms
*atoms
, rvec x
[], t_params
*bond
, int nbond
[],
120 gmx_bool bPBC
, matrix box
)
128 for (i
= 0; (i
< MAXATOMLIST
); i
++)
132 for (i
= 0; (i
< MAXFORCEPARAM
); i
++)
139 set_pbc(&pbc
, -1, box
);
141 for (i
= 0; (i
< atoms
->nr
); i
++)
145 fprintf(stderr
, "\ratom %d", i
);
147 for (j
= i
+1; (j
< atoms
->nr
); j
++)
151 pbc_dx(&pbc
, x
[i
], x
[j
], dx
);
155 rvec_sub(x
[i
], x
[j
], dx
);
159 if (is_bond(nnm
, nmt
, *atoms
->atomname
[i
], *atoms
->atomname
[j
],
165 add_param_to_list (bond
, &b
);
170 fprintf(debug
, "Bonding atoms %s-%d and %s-%d\n",
171 *atoms
->atomname
[i
], i
+1, *atoms
->atomname
[j
], j
+1);
176 fprintf(stderr
, "\ratom %d\n", i
);
179 int *set_cgnr(t_atoms
*atoms
, gmx_bool bUsePDBcharge
, real
*qtot
, real
*mtot
)
183 double qt
= 0, mt
= 0;
186 snew(cgnr
, atoms
->nr
);
187 for (i
= 0; (i
< atoms
->nr
); i
++)
189 if (atoms
->pdbinfo
&& bUsePDBcharge
)
191 atoms
->atom
[i
].q
= atoms
->pdbinfo
[i
].bfac
;
193 qt
+= atoms
->atom
[i
].q
;
194 *qtot
+= atoms
->atom
[i
].q
;
195 *mtot
+= atoms
->atom
[i
].m
;
206 gpp_atomtype_t
set_atom_type(t_symtab
*tab
, t_atoms
*atoms
, t_params
*bonds
,
207 int *nbonds
, int nnm
, t_nm2type nm2t
[])
209 gpp_atomtype_t atype
;
212 atype
= init_atomtype();
213 snew(atoms
->atomtype
, atoms
->nr
);
214 nresolved
= nm2type(nnm
, nm2t
, tab
, atoms
, atype
, nbonds
, bonds
);
215 if (nresolved
!= atoms
->nr
)
217 gmx_fatal(FARGS
, "Could only find a forcefield type for %d out of %d atoms",
218 nresolved
, atoms
->nr
);
221 fprintf(stderr
, "There are %d different atom types in your sample\n",
222 get_atomtype_ntypes(atype
));
227 void lo_set_force_const(t_params
*plist
, real c
[], int nrfp
, gmx_bool bRound
,
228 gmx_bool bDih
, gmx_bool bParam
)
234 for (i
= 0; (i
< plist
->nr
); i
++)
238 for (j
= 0; j
< nrfp
; j
++)
247 sprintf(buf
, "%.2e", plist
->param
[i
].c
[0]);
248 sscanf(buf
, "%lf", &cc
);
253 c
[0] = plist
->param
[i
].c
[0];
258 c
[0] = ((int)(c
[0] + 3600)) % 360;
263 /* To put the minimum at the current angle rather than the maximum */
267 assert(nrfp
<= MAXFORCEPARAM
/2);
268 for (j
= 0; (j
< nrfp
); j
++)
270 plist
->param
[i
].c
[j
] = c
[j
];
271 plist
->param
[i
].c
[nrfp
+j
] = c
[j
];
273 set_p_string(&(plist
->param
[i
]), "");
277 void set_force_const(t_params plist
[], real kb
, real kt
, real kp
, gmx_bool bRound
,
281 real c
[MAXFORCEPARAM
];
285 lo_set_force_const(&plist
[F_BONDS
], c
, 2, bRound
, FALSE
, bParam
);
287 lo_set_force_const(&plist
[F_ANGLES
], c
, 2, bRound
, FALSE
, bParam
);
290 lo_set_force_const(&plist
[F_PDIHS
], c
, 3, bRound
, TRUE
, bParam
);
293 void calc_angles_dihs(t_params
*ang
, t_params
*dih
, rvec x
[], gmx_bool bPBC
,
296 int i
, ai
, aj
, ak
, al
, t1
, t2
, t3
;
297 rvec r_ij
, r_kj
, r_kl
, m
, n
;
298 real sign
, th
, costh
, ph
;
303 set_pbc(&pbc
, epbcXYZ
, box
);
307 pr_rvecs(debug
, 0, "X2TOP", box
, DIM
);
309 for (i
= 0; (i
< ang
->nr
); i
++)
311 ai
= ang
->param
[i
].AI
;
312 aj
= ang
->param
[i
].AJ
;
313 ak
= ang
->param
[i
].AK
;
314 th
= RAD2DEG
*bond_angle(x
[ai
], x
[aj
], x
[ak
], bPBC
? &pbc
: NULL
,
315 r_ij
, r_kj
, &costh
, &t1
, &t2
);
318 fprintf(debug
, "X2TOP: ai=%3d aj=%3d ak=%3d r_ij=%8.3f r_kj=%8.3f th=%8.3f\n",
319 ai
, aj
, ak
, norm(r_ij
), norm(r_kj
), th
);
321 ang
->param
[i
].C0
= th
;
323 for (i
= 0; (i
< dih
->nr
); i
++)
325 ai
= dih
->param
[i
].AI
;
326 aj
= dih
->param
[i
].AJ
;
327 ak
= dih
->param
[i
].AK
;
328 al
= dih
->param
[i
].AL
;
329 ph
= RAD2DEG
*dih_angle(x
[ai
], x
[aj
], x
[ak
], x
[al
], bPBC
? &pbc
: NULL
,
330 r_ij
, r_kj
, r_kl
, m
, n
, &sign
, &t1
, &t2
, &t3
);
333 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",
334 ai
, aj
, ak
, al
, norm(r_ij
), norm(r_kj
), norm(r_kl
), ph
);
336 dih
->param
[i
].C0
= ph
;
340 static void dump_hybridization(FILE *fp
, t_atoms
*atoms
, int nbonds
[])
344 for (i
= 0; (i
< atoms
->nr
); i
++)
346 fprintf(fp
, "Atom %5s has %1d bonds\n", *atoms
->atomname
[i
], nbonds
[i
]);
350 static void print_pl(FILE *fp
, t_params plist
[], int ftp
, const char *name
,
353 int i
, j
, nral
, nrfp
;
355 if (plist
[ftp
].nr
> 0)
358 fprintf(fp
, "[ %s ]\n", name
);
359 nral
= interaction_function
[ftp
].nratoms
;
360 nrfp
= interaction_function
[ftp
].nrfpA
;
361 for (i
= 0; (i
< plist
[ftp
].nr
); i
++)
363 for (j
= 0; (j
< nral
); j
++)
365 fprintf(fp
, " %5s", *atomname
[plist
[ftp
].param
[i
].a
[j
]]);
367 for (j
= 0; (j
< nrfp
); j
++)
369 if (plist
[ftp
].param
[i
].c
[j
] != NOTSET
)
371 fprintf(fp
, " %10.3e", plist
[ftp
].param
[i
].c
[j
]);
379 static void print_rtp(const char *filenm
, const char *title
, t_atoms
*atoms
,
380 t_params plist
[], gpp_atomtype_t atype
, int cgnr
[])
386 fp
= gmx_fio_fopen(filenm
, "w");
387 fprintf(fp
, "; %s\n", title
);
389 fprintf(fp
, "[ %s ]\n", *atoms
->resinfo
[0].name
);
391 fprintf(fp
, "[ atoms ]\n");
392 for (i
= 0; (i
< atoms
->nr
); i
++)
394 tp
= atoms
->atom
[i
].type
;
395 if ((tpnm
= get_atomtype_name(tp
, atype
)) == NULL
)
397 gmx_fatal(FARGS
, "tp = %d, i = %d in print_rtp", tp
, i
);
399 fprintf(fp
, "%-8s %12s %8.4f %5d\n",
400 *atoms
->atomname
[i
], tpnm
,
401 atoms
->atom
[i
].q
, cgnr
[i
]);
403 print_pl(fp
, plist
, F_BONDS
, "bonds", atoms
->atomname
);
404 print_pl(fp
, plist
, F_ANGLES
, "angles", atoms
->atomname
);
405 print_pl(fp
, plist
, F_PDIHS
, "dihedrals", atoms
->atomname
);
406 print_pl(fp
, plist
, F_IDIHS
, "impropers", atoms
->atomname
);
411 int gmx_x2top(int argc
, char *argv
[])
413 const char *desc
[] = {
414 "[THISMODULE] generates a primitive topology from a coordinate file.",
415 "The program assumes all hydrogens are present when defining",
416 "the hybridization from the atom name and the number of bonds.",
417 "The program can also make an [TT].rtp[tt] entry, which you can then add",
418 "to the [TT].rtp[tt] database.[PAR]",
419 "When [TT]-param[tt] is set, equilibrium distances and angles",
420 "and force constants will be printed in the topology for all",
421 "interactions. The equilibrium distances and angles are taken",
422 "from the input coordinates, the force constant are set with",
423 "command line options.",
424 "The force fields somewhat supported currently are:[PAR]",
425 "G53a5 GROMOS96 53a5 Forcefield (official distribution)[PAR]",
426 "oplsaa OPLS-AA/L all-atom force field (2001 aminoacid dihedrals)[PAR]",
427 "The corresponding data files can be found in the library directory",
428 "with name [TT]atomname2type.n2t[tt]. Check Chapter 5 of the manual for more",
429 "information about file formats. By default, the force field selection",
430 "is interactive, but you can use the [TT]-ff[tt] option to specify",
431 "one of the short names above on the command line instead. In that",
432 "case [THISMODULE] just looks for the corresponding file.[PAR]",
434 const char *bugs
[] = {
435 "The atom type selection is primitive. Virtually no chemical knowledge is used",
436 "Periodic boundary conditions screw up the bonding",
437 "No improper dihedrals are generated",
438 "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."
441 t_params plist
[F_NRE
];
443 t_atoms
*atoms
; /* list with all atoms */
444 gpp_atomtype_t atype
;
449 char title
[STRLEN
], forcefield
[32], ffdir
[STRLEN
];
450 rvec
*x
; /* coordinates? */
452 int bts
[] = { 1, 1, 1, 2 };
453 matrix box
; /* box length matrix */
454 int natoms
; /* number of atoms in one molecule */
455 int nres
; /* number of molecules? */
456 int i
, j
, k
, l
, m
, ndih
;
458 gmx_bool bRTP
, bTOP
, bOPLS
;
460 real cutoff
, qtot
, mtot
;
465 { efSTX
, "-f", "conf", ffREAD
},
466 { efTOP
, "-o", "out", ffOPTWR
},
467 { efRTP
, "-r", "out", ffOPTWR
}
469 #define NFILE asize(fnm)
470 static real scale
= 1.1, kb
= 4e5
, kt
= 400, kp
= 5;
471 static t_restp rtp_header_settings
;
472 static gmx_bool bRemoveDihedralIfWithImproper
= FALSE
;
473 static gmx_bool bGenerateHH14Interactions
= TRUE
;
474 static gmx_bool bKeepAllGeneratedDihedrals
= FALSE
;
475 static int nrexcl
= 3;
476 static gmx_bool bParam
= TRUE
, bRound
= TRUE
;
477 static gmx_bool bPairs
= TRUE
, bPBC
= TRUE
;
478 static gmx_bool bUsePDBcharge
= FALSE
, bVerbose
= FALSE
;
479 static const char *molnm
= "ICE";
480 static const char *ff
= "oplsaa";
482 { "-ff", FALSE
, etSTR
, {&ff
},
483 "Force field for your simulation. Type \"select\" for interactive selection." },
484 { "-v", FALSE
, etBOOL
, {&bVerbose
},
485 "Generate verbose output in the top file." },
486 { "-nexcl", FALSE
, etINT
, {&nrexcl
},
487 "Number of exclusions" },
488 { "-H14", FALSE
, etBOOL
, {&bGenerateHH14Interactions
},
489 "Use 3rd neighbour interactions for hydrogen atoms" },
490 { "-alldih", FALSE
, etBOOL
, {&bKeepAllGeneratedDihedrals
},
491 "Generate all proper dihedrals" },
492 { "-remdih", FALSE
, etBOOL
, {&bRemoveDihedralIfWithImproper
},
493 "Remove dihedrals on the same bond as an improper" },
494 { "-pairs", FALSE
, etBOOL
, {&bPairs
},
495 "Output 1-4 interactions (pairs) in topology file" },
496 { "-name", FALSE
, etSTR
, {&molnm
},
497 "Name of your molecule" },
498 { "-pbc", FALSE
, etBOOL
, {&bPBC
},
499 "Use periodic boundary conditions." },
500 { "-pdbq", FALSE
, etBOOL
, {&bUsePDBcharge
},
501 "Use the B-factor supplied in a [TT].pdb[tt] file for the atomic charges" },
502 { "-param", FALSE
, etBOOL
, {&bParam
},
503 "Print parameters in the output" },
504 { "-round", FALSE
, etBOOL
, {&bRound
},
505 "Round off measured values" },
506 { "-kb", FALSE
, etREAL
, {&kb
},
507 "Bonded force constant (kJ/mol/nm^2)" },
508 { "-kt", FALSE
, etREAL
, {&kt
},
509 "Angle force constant (kJ/mol/rad^2)" },
510 { "-kp", FALSE
, etREAL
, {&kp
},
511 "Dihedral angle force constant (kJ/mol/rad^2)" }
514 if (!parse_common_args(&argc
, argv
, 0, NFILE
, fnm
, asize(pa
), pa
,
515 asize(desc
), desc
, asize(bugs
), bugs
, &oenv
))
519 bRTP
= opt2bSet("-r", NFILE
, fnm
);
520 bTOP
= opt2bSet("-o", NFILE
, fnm
);
521 /* C89 requirements mean that these struct members cannot be used in
522 * the declaration of pa. So some temporary variables are needed. */
523 rtp_header_settings
.bRemoveDihedralIfWithImproper
= bRemoveDihedralIfWithImproper
;
524 rtp_header_settings
.bGenerateHH14Interactions
= bGenerateHH14Interactions
;
525 rtp_header_settings
.bKeepAllGeneratedDihedrals
= bKeepAllGeneratedDihedrals
;
526 rtp_header_settings
.nrexcl
= nrexcl
;
530 gmx_fatal(FARGS
, "Specify at least one output file");
533 /* Force field selection, interactive or direct */
534 choose_ff(strcmp(ff
, "select") == 0 ? NULL
: ff
,
535 forcefield
, sizeof(forcefield
),
536 ffdir
, sizeof(ffdir
));
538 bOPLS
= (strcmp(forcefield
, "oplsaa") == 0);
541 mymol
.name
= strdup(molnm
);
544 /* Init parameter lists */
547 /* Read coordinates */
548 get_stx_coordnum(opt2fn("-f", NFILE
, fnm
), &natoms
);
551 /* make space for all the atoms */
552 init_t_atoms(atoms
, natoms
, TRUE
);
555 read_stx_conf(opt2fn("-f", NFILE
, fnm
), title
, atoms
, x
, NULL
, &epbc
, box
);
557 sprintf(n2t
, "%s", ffdir
);
558 nm2t
= rd_nm2type(n2t
, &nnm
);
561 gmx_fatal(FARGS
, "No or incorrect atomname2type.n2t file found (looking for %s)",
566 printf("There are %d name to type translations in file %s\n", nnm
, n2t
);
570 dump_nm2type(debug
, nnm
, nm2t
);
572 printf("Generating bonds from distances...\n");
573 snew(nbonds
, atoms
->nr
);
574 mk_bonds(nnm
, nm2t
, atoms
, x
, &(plist
[F_BONDS
]), nbonds
, bPBC
, box
);
576 open_symtab(&symtab
);
577 atype
= set_atom_type(&symtab
, atoms
, &(plist
[F_BONDS
]), nbonds
, nnm
, nm2t
);
579 /* Make Angles and Dihedrals */
580 snew(excls
, atoms
->nr
);
581 printf("Generating angles and dihedrals from bonds...\n");
582 init_nnb(&nnb
, atoms
->nr
, 4);
583 gen_nnb(&nnb
, plist
);
584 print_nnb(&nnb
, "NNB");
585 gen_pad(&nnb
, atoms
, &rtp_header_settings
, plist
, excls
, NULL
, TRUE
);
590 plist
[F_LJ14
].nr
= 0;
593 "There are %4d %s dihedrals, %4d impropers, %4d angles\n"
594 " %4d pairs, %4d bonds and %4d atoms\n",
596 bOPLS
? "Ryckaert-Bellemans" : "proper",
597 plist
[F_IDIHS
].nr
, plist
[F_ANGLES
].nr
,
598 plist
[F_LJ14
].nr
, plist
[F_BONDS
].nr
, atoms
->nr
);
600 calc_angles_dihs(&plist
[F_ANGLES
], &plist
[F_PDIHS
], x
, bPBC
, box
);
602 set_force_const(plist
, kb
, kt
, kp
, bRound
, bParam
);
604 cgnr
= set_cgnr(atoms
, bUsePDBcharge
, &qtot
, &mtot
);
605 printf("Total charge is %g, total mass is %g\n", qtot
, mtot
);
614 fp
= ftp2FILE(efTOP
, NFILE
, fnm
, "w");
615 print_top_header(fp
, ftp2fn(efTOP
, NFILE
, fnm
), TRUE
, ffdir
, 1.0);
617 write_top(fp
, NULL
, mymol
.name
, atoms
, FALSE
, bts
, plist
, excls
, atype
,
618 cgnr
, rtp_header_settings
.nrexcl
);
619 print_top_mols(fp
, mymol
.name
, ffdir
, NULL
, 0, NULL
, 1, &mymol
);
625 print_rtp(ftp2fn(efRTP
, NFILE
, fnm
), "Generated by x2top",
626 atoms
, plist
, atype
, cgnr
);
631 dump_hybridization(debug
, atoms
, nbonds
);
633 close_symtab(&symtab
);
636 printf("\nWARNING: topologies generated by %s can not be trusted at face value.\n",
637 output_env_get_program_display_name(oenv
));
638 printf(" Please verify atomtypes and charges by comparison to other\n");
639 printf(" topologies.\n");