Move remaining C files in utility to C++
[alexxy/gromacs.git] / src / gromacs / gmxpreprocess / x2top.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
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, 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.
10  *
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.
15  *
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.
20  *
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.
25  *
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.
33  *
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.
36  */
37 #include "gmxpre.h"
38
39 #include "x2top.h"
40
41 #include <cmath>
42
43 #include "gromacs/commandline/pargs.h"
44 #include "gromacs/fileio/confio.h"
45 #include "gromacs/fileio/gmxfio.h"
46 #include "gromacs/gmxpreprocess/gen_ad.h"
47 #include "gromacs/gmxpreprocess/gpp_nextnb.h"
48 #include "gromacs/gmxpreprocess/hackblock.h"
49 #include "gromacs/gmxpreprocess/nm2type.h"
50 #include "gromacs/gmxpreprocess/pdb2top.h"
51 #include "gromacs/gmxpreprocess/toppush.h"
52 #include "gromacs/legacyheaders/copyrite.h"
53 #include "gromacs/legacyheaders/macros.h"
54 #include "gromacs/legacyheaders/names.h"
55 #include "gromacs/legacyheaders/readinp.h"
56 #include "gromacs/legacyheaders/txtdump.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/pbcutil/pbc.h"
62 #include "gromacs/topology/symtab.h"
63 #include "gromacs/utility/cstringutil.h"
64 #include "gromacs/utility/fatalerror.h"
65 #include "gromacs/utility/gmxassert.h"
66 #include "gromacs/utility/smalloc.h"
67
68 char atp[7] = "HCNOSX";
69 #define NATP (asize(atp)-1)
70
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 }
78 };
79
80 #define MARGIN_FAC 1.1
81
82 static gmx_bool is_bond(int nnm, t_nm2type nmt[], char *ai, char *aj, real blen)
83 {
84     int i, j;
85
86     for (i = 0; (i < nnm); i++)
87     {
88         for (j = 0; (j < nmt[i].nbonds); j++)
89         {
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]))
95             {
96                 return TRUE;
97             }
98         }
99     }
100     return FALSE;
101 }
102
103 static int get_atype(char *nm)
104 {
105     int i, aai = NATP-1;
106
107     for (i = 0; (i < NATP-1); i++)
108     {
109         if (nm[0] == atp[i])
110         {
111             aai = i;
112             break;
113         }
114     }
115     return aai;
116 }
117
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)
121 {
122     t_param b;
123     int     i, j;
124     t_pbc   pbc;
125     rvec    dx;
126     real    dx2;
127
128     for (i = 0; (i < MAXATOMLIST); i++)
129     {
130         b.a[i] = -1;
131     }
132     for (i = 0; (i < MAXFORCEPARAM); i++)
133     {
134         b.c[i] = 0.0;
135     }
136
137     if (bPBC)
138     {
139         set_pbc(&pbc, -1, box);
140     }
141     for (i = 0; (i < atoms->nr); i++)
142     {
143         if ((i % 10) == 0)
144         {
145             fprintf(stderr, "\ratom %d", i);
146         }
147         for (j = i+1; (j < atoms->nr); j++)
148         {
149             if (bPBC)
150             {
151                 pbc_dx(&pbc, x[i], x[j], dx);
152             }
153             else
154             {
155                 rvec_sub(x[i], x[j], dx);
156             }
157
158             dx2 = iprod(dx, dx);
159             if (is_bond(nnm, nmt, *atoms->atomname[i], *atoms->atomname[j],
160                         std::sqrt(dx2)))
161             {
162                 b.AI = i;
163                 b.AJ = j;
164                 b.C0 = std::sqrt(dx2);
165                 add_param_to_list (bond, &b);
166                 nbond[i]++;
167                 nbond[j]++;
168                 if (debug)
169                 {
170                     fprintf(debug, "Bonding atoms %s-%d and %s-%d\n",
171                             *atoms->atomname[i], i+1, *atoms->atomname[j], j+1);
172                 }
173             }
174         }
175     }
176     fprintf(stderr, "\ratom %d\n", i);
177 }
178
179 int *set_cgnr(t_atoms *atoms, gmx_bool bUsePDBcharge, real *qtot, real *mtot)
180 {
181     int     i, n = 1;
182     int    *cgnr;
183     double  qt = 0;
184
185     *qtot = *mtot = 0;
186     snew(cgnr, atoms->nr);
187     for (i = 0; (i < atoms->nr); i++)
188     {
189         if (atoms->pdbinfo && bUsePDBcharge)
190         {
191             atoms->atom[i].q = atoms->pdbinfo[i].bfac;
192         }
193         qt     += atoms->atom[i].q;
194         *qtot  += atoms->atom[i].q;
195         *mtot  += atoms->atom[i].m;
196         cgnr[i] = n;
197         if (is_int(qt))
198         {
199             n++;
200             qt = 0;
201         }
202     }
203     return cgnr;
204 }
205
206 gpp_atomtype_t set_atom_type(t_symtab *tab, t_atoms *atoms, t_params *bonds,
207                              int *nbonds, int nnm, t_nm2type nm2t[])
208 {
209     gpp_atomtype_t atype;
210     int            nresolved;
211
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)
216     {
217         gmx_fatal(FARGS, "Could only find a forcefield type for %d out of %d atoms",
218                   nresolved, atoms->nr);
219     }
220
221     fprintf(stderr, "There are %d different atom types in your sample\n",
222             get_atomtype_ntypes(atype));
223
224     return atype;
225 }
226
227 void lo_set_force_const(t_params *plist, real c[], int nrfp, gmx_bool bRound,
228                         gmx_bool bDih, gmx_bool bParam)
229 {
230     int    i, j;
231     double cc;
232     char   buf[32];
233
234     for (i = 0; (i < plist->nr); i++)
235     {
236         if (!bParam)
237         {
238             for (j = 0; j < nrfp; j++)
239             {
240                 c[j] = NOTSET;
241             }
242         }
243         else
244         {
245             if (bRound)
246             {
247                 sprintf(buf, "%.2e", plist->param[i].c[0]);
248                 sscanf(buf, "%lf", &cc);
249                 c[0] = cc;
250             }
251             else
252             {
253                 c[0] = plist->param[i].c[0];
254             }
255             if (bDih)
256             {
257                 c[0] *= c[2];
258                 c[0]  = ((int)(c[0] + 3600)) % 360;
259                 if (c[0] > 180)
260                 {
261                     c[0] -= 360;
262                 }
263                 /* To put the minimum at the current angle rather than the maximum */
264                 c[0] += 180;
265             }
266         }
267         GMX_ASSERT(nrfp <= MAXFORCEPARAM/2, "Only 6 parameters may be used for an interaction");
268         for (j = 0; (j < nrfp); j++)
269         {
270             plist->param[i].c[j]      = c[j];
271             plist->param[i].c[nrfp+j] = c[j];
272         }
273         set_p_string(&(plist->param[i]), "");
274     }
275 }
276
277 void set_force_const(t_params plist[], real kb, real kt, real kp, gmx_bool bRound,
278                      gmx_bool bParam)
279 {
280     real c[MAXFORCEPARAM];
281
282     c[0] = 0;
283     c[1] = kb;
284     lo_set_force_const(&plist[F_BONDS], c, 2, bRound, FALSE, bParam);
285     c[1] = kt;
286     lo_set_force_const(&plist[F_ANGLES], c, 2, bRound, FALSE, bParam);
287     c[1] = kp;
288     c[2] = 3;
289     lo_set_force_const(&plist[F_PDIHS], c, 3, bRound, TRUE, bParam);
290 }
291
292 void calc_angles_dihs(t_params *ang, t_params *dih, rvec x[], gmx_bool bPBC,
293                       matrix box)
294 {
295     int    i, ai, aj, ak, al, t1, t2, t3;
296     rvec   r_ij, r_kj, r_kl, m, n;
297     real   sign, th, costh, ph;
298     t_pbc  pbc;
299
300     if (bPBC)
301     {
302         set_pbc(&pbc, epbcXYZ, box);
303     }
304     if (debug)
305     {
306         pr_rvecs(debug, 0, "X2TOP", box, DIM);
307     }
308     for (i = 0; (i < ang->nr); i++)
309     {
310         ai = ang->param[i].AI;
311         aj = ang->param[i].AJ;
312         ak = ang->param[i].AK;
313         th = RAD2DEG*bond_angle(x[ai], x[aj], x[ak], bPBC ? &pbc : NULL,
314                                 r_ij, r_kj, &costh, &t1, &t2);
315         if (debug)
316         {
317             fprintf(debug, "X2TOP: ai=%3d aj=%3d ak=%3d r_ij=%8.3f r_kj=%8.3f th=%8.3f\n",
318                     ai, aj, ak, norm(r_ij), norm(r_kj), th);
319         }
320         ang->param[i].C0 = th;
321     }
322     for (i = 0; (i < dih->nr); i++)
323     {
324         ai = dih->param[i].AI;
325         aj = dih->param[i].AJ;
326         ak = dih->param[i].AK;
327         al = dih->param[i].AL;
328         ph = RAD2DEG*dih_angle(x[ai], x[aj], x[ak], x[al], bPBC ? &pbc : NULL,
329                                r_ij, r_kj, r_kl, m, n, &sign, &t1, &t2, &t3);
330         if (debug)
331         {
332             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",
333                     ai, aj, ak, al, norm(r_ij), norm(r_kj), norm(r_kl), ph);
334         }
335         dih->param[i].C0 = ph;
336     }
337 }
338
339 static void dump_hybridization(FILE *fp, t_atoms *atoms, int nbonds[])
340 {
341     int i;
342
343     for (i = 0; (i < atoms->nr); i++)
344     {
345         fprintf(fp, "Atom %5s has %1d bonds\n", *atoms->atomname[i], nbonds[i]);
346     }
347 }
348
349 static void print_pl(FILE *fp, t_params plist[], int ftp, const char *name,
350                      char ***atomname)
351 {
352     int i, j, nral, nrfp;
353
354     if (plist[ftp].nr > 0)
355     {
356         fprintf(fp, "\n");
357         fprintf(fp, "[ %s ]\n", name);
358         nral = interaction_function[ftp].nratoms;
359         nrfp = interaction_function[ftp].nrfpA;
360         for (i = 0; (i < plist[ftp].nr); i++)
361         {
362             for (j = 0; (j < nral); j++)
363             {
364                 fprintf(fp, "  %5s", *atomname[plist[ftp].param[i].a[j]]);
365             }
366             for (j = 0; (j < nrfp); j++)
367             {
368                 if (plist[ftp].param[i].c[j] != NOTSET)
369                 {
370                     fprintf(fp, "  %10.3e", plist[ftp].param[i].c[j]);
371                 }
372             }
373             fprintf(fp, "\n");
374         }
375     }
376 }
377
378 static void print_rtp(const char *filenm, const char *title, t_atoms *atoms,
379                       t_params plist[], gpp_atomtype_t atype, int cgnr[])
380 {
381     FILE *fp;
382     int   i, tp;
383     char *tpnm;
384
385     fp = gmx_fio_fopen(filenm, "w");
386     fprintf(fp, "; %s\n", title);
387     fprintf(fp, "\n");
388     fprintf(fp, "[ %s ]\n", *atoms->resinfo[0].name);
389     fprintf(fp, "\n");
390     fprintf(fp, "[ atoms ]\n");
391     for (i = 0; (i < atoms->nr); i++)
392     {
393         tp = atoms->atom[i].type;
394         if ((tpnm = get_atomtype_name(tp, atype)) == NULL)
395         {
396             gmx_fatal(FARGS, "tp = %d, i = %d in print_rtp", tp, i);
397         }
398         fprintf(fp, "%-8s  %12s  %8.4f  %5d\n",
399                 *atoms->atomname[i], tpnm,
400                 atoms->atom[i].q, cgnr[i]);
401     }
402     print_pl(fp, plist, F_BONDS, "bonds", atoms->atomname);
403     print_pl(fp, plist, F_ANGLES, "angles", atoms->atomname);
404     print_pl(fp, plist, F_PDIHS, "dihedrals", atoms->atomname);
405     print_pl(fp, plist, F_IDIHS, "impropers", atoms->atomname);
406
407     gmx_fio_fclose(fp);
408 }
409
410 int gmx_x2top(int argc, char *argv[])
411 {
412     const char        *desc[] = {
413         "[THISMODULE] generates a primitive topology from a coordinate file.",
414         "The program assumes all hydrogens are present when defining",
415         "the hybridization from the atom name and the number of bonds.",
416         "The program can also make an [REF].rtp[ref] entry, which you can then add",
417         "to the [REF].rtp[ref] database.[PAR]",
418         "When [TT]-param[tt] is set, equilibrium distances and angles",
419         "and force constants will be printed in the topology for all",
420         "interactions. The equilibrium distances and angles are taken",
421         "from the input coordinates, the force constant are set with",
422         "command line options.",
423         "The force fields somewhat supported currently are:[PAR]",
424         "G53a5  GROMOS96 53a5 Forcefield (official distribution)[PAR]",
425         "oplsaa OPLS-AA/L all-atom force field (2001 aminoacid dihedrals)[PAR]",
426         "The corresponding data files can be found in the library directory",
427         "with name [TT]atomname2type.n2t[tt]. Check Chapter 5 of the manual for more",
428         "information about file formats. By default, the force field selection",
429         "is interactive, but you can use the [TT]-ff[tt] option to specify",
430         "one of the short names above on the command line instead. In that",
431         "case [THISMODULE] just looks for the corresponding file.[PAR]",
432     };
433     const char        *bugs[] = {
434         "The atom type selection is primitive. Virtually no chemical knowledge is used",
435         "Periodic boundary conditions screw up the bonding",
436         "No improper dihedrals are generated",
437         "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."
438     };
439     FILE              *fp;
440     t_params           plist[F_NRE];
441     t_excls           *excls;
442     t_atoms           *atoms; /* list with all atoms */
443     gpp_atomtype_t     atype;
444     t_nextnb           nnb;
445     t_nm2type         *nm2t;
446     t_mols             mymol;
447     int                nnm;
448     char               title[STRLEN], forcefield[32], ffdir[STRLEN];
449     rvec              *x; /* coordinates? */
450     int               *nbonds, *cgnr;
451     int                bts[] = { 1, 1, 1, 2 };
452     matrix             box;    /* box length matrix */
453     int                natoms; /* number of atoms in one molecule  */
454     int                epbc;
455     gmx_bool           bRTP, bTOP, bOPLS;
456     t_symtab           symtab;
457     real               qtot, mtot;
458     char               n2t[STRLEN];
459     output_env_t       oenv;
460
461     t_filenm           fnm[] = {
462         { efSTX, "-f", "conf", ffREAD  },
463         { efTOP, "-o", "out",  ffOPTWR },
464         { efRTP, "-r", "out",  ffOPTWR }
465     };
466 #define NFILE asize(fnm)
467     static real        kb = 4e5, kt = 400, kp = 5;
468     static t_restp     rtp_header_settings;
469     static gmx_bool    bRemoveDihedralIfWithImproper = FALSE;
470     static gmx_bool    bGenerateHH14Interactions     = TRUE;
471     static gmx_bool    bKeepAllGeneratedDihedrals    = FALSE;
472     static int         nrexcl                        = 3;
473     static gmx_bool    bParam                        = TRUE, bRound = TRUE;
474     static gmx_bool    bPairs                        = TRUE, bPBC = TRUE;
475     static gmx_bool    bUsePDBcharge                 = FALSE, bVerbose = FALSE;
476     static const char *molnm                         = "ICE";
477     static const char *ff                            = "oplsaa";
478     t_pargs            pa[]                          = {
479         { "-ff",     FALSE, etSTR, {&ff},
480           "Force field for your simulation. Type \"select\" for interactive selection." },
481         { "-v",      FALSE, etBOOL, {&bVerbose},
482           "Generate verbose output in the top file." },
483         { "-nexcl", FALSE, etINT,  {&nrexcl},
484           "Number of exclusions" },
485         { "-H14",    FALSE, etBOOL, {&bGenerateHH14Interactions},
486           "Use 3rd neighbour interactions for hydrogen atoms" },
487         { "-alldih", FALSE, etBOOL, {&bKeepAllGeneratedDihedrals},
488           "Generate all proper dihedrals" },
489         { "-remdih", FALSE, etBOOL, {&bRemoveDihedralIfWithImproper},
490           "Remove dihedrals on the same bond as an improper" },
491         { "-pairs",  FALSE, etBOOL, {&bPairs},
492           "Output 1-4 interactions (pairs) in topology file" },
493         { "-name",   FALSE, etSTR,  {&molnm},
494           "Name of your molecule" },
495         { "-pbc",    FALSE, etBOOL, {&bPBC},
496           "Use periodic boundary conditions." },
497         { "-pdbq",  FALSE, etBOOL, {&bUsePDBcharge},
498           "Use the B-factor supplied in a [REF].pdb[ref] file for the atomic charges" },
499         { "-param", FALSE, etBOOL, {&bParam},
500           "Print parameters in the output" },
501         { "-round",  FALSE, etBOOL, {&bRound},
502           "Round off measured values" },
503         { "-kb",    FALSE, etREAL, {&kb},
504           "Bonded force constant (kJ/mol/nm^2)" },
505         { "-kt",    FALSE, etREAL, {&kt},
506           "Angle force constant (kJ/mol/rad^2)" },
507         { "-kp",    FALSE, etREAL, {&kp},
508           "Dihedral angle force constant (kJ/mol/rad^2)" }
509     };
510
511     if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa,
512                            asize(desc), desc, asize(bugs), bugs, &oenv))
513     {
514         return 0;
515     }
516     bRTP = opt2bSet("-r", NFILE, fnm);
517     bTOP = opt2bSet("-o", NFILE, fnm);
518     /* C89 requirements mean that these struct members cannot be used in
519      * the declaration of pa. So some temporary variables are needed. */
520     rtp_header_settings.bRemoveDihedralIfWithImproper = bRemoveDihedralIfWithImproper;
521     rtp_header_settings.bGenerateHH14Interactions     = bGenerateHH14Interactions;
522     rtp_header_settings.bKeepAllGeneratedDihedrals    = bKeepAllGeneratedDihedrals;
523     rtp_header_settings.nrexcl = nrexcl;
524
525     if (!bRTP && !bTOP)
526     {
527         gmx_fatal(FARGS, "Specify at least one output file");
528     }
529
530     /* Force field selection, interactive or direct */
531     choose_ff(strcmp(ff, "select") == 0 ? NULL : ff,
532               forcefield, sizeof(forcefield),
533               ffdir, sizeof(ffdir));
534
535     bOPLS = (strcmp(forcefield, "oplsaa") == 0);
536
537
538     mymol.name = gmx_strdup(molnm);
539     mymol.nr   = 1;
540
541     /* Init parameter lists */
542     init_plist(plist);
543
544     /* Read coordinates */
545     get_stx_coordnum(opt2fn("-f", NFILE, fnm), &natoms);
546     snew(atoms, 1);
547
548     /* make space for all the atoms */
549     init_t_atoms(atoms, natoms, TRUE);
550     snew(x, natoms);
551
552     read_stx_conf(opt2fn("-f", NFILE, fnm), title, atoms, x, NULL, &epbc, box);
553
554     sprintf(n2t, "%s", ffdir);
555     nm2t = rd_nm2type(n2t, &nnm);
556     if (nnm == 0)
557     {
558         gmx_fatal(FARGS, "No or incorrect atomname2type.n2t file found (looking for %s)",
559                   n2t);
560     }
561     else
562     {
563         printf("There are %d name to type translations in file %s\n", nnm, n2t);
564     }
565     if (debug)
566     {
567         dump_nm2type(debug, nnm, nm2t);
568     }
569     printf("Generating bonds from distances...\n");
570     snew(nbonds, atoms->nr);
571     mk_bonds(nnm, nm2t, atoms, x, &(plist[F_BONDS]), nbonds, bPBC, box);
572
573     open_symtab(&symtab);
574     atype = set_atom_type(&symtab, atoms, &(plist[F_BONDS]), nbonds, nnm, nm2t);
575
576     /* Make Angles and Dihedrals */
577     snew(excls, atoms->nr);
578     printf("Generating angles and dihedrals from bonds...\n");
579     init_nnb(&nnb, atoms->nr, 4);
580     gen_nnb(&nnb, plist);
581     print_nnb(&nnb, "NNB");
582     gen_pad(&nnb, atoms, &rtp_header_settings, plist, excls, NULL, TRUE);
583     done_nnb(&nnb);
584
585     if (!bPairs)
586     {
587         plist[F_LJ14].nr = 0;
588     }
589     fprintf(stderr,
590             "There are %4d %s dihedrals, %4d impropers, %4d angles\n"
591             "          %4d pairs,     %4d bonds and  %4d atoms\n",
592             plist[F_PDIHS].nr,
593             bOPLS ? "Ryckaert-Bellemans" : "proper",
594             plist[F_IDIHS].nr, plist[F_ANGLES].nr,
595             plist[F_LJ14].nr, plist[F_BONDS].nr, atoms->nr);
596
597     calc_angles_dihs(&plist[F_ANGLES], &plist[F_PDIHS], x, bPBC, box);
598
599     set_force_const(plist, kb, kt, kp, bRound, bParam);
600
601     cgnr = set_cgnr(atoms, bUsePDBcharge, &qtot, &mtot);
602     printf("Total charge is %g, total mass is %g\n", qtot, mtot);
603     if (bOPLS)
604     {
605         bts[2] = 3;
606         bts[3] = 1;
607     }
608
609     if (bTOP)
610     {
611         fp = ftp2FILE(efTOP, NFILE, fnm, "w");
612         print_top_header(fp, ftp2fn(efTOP, NFILE, fnm), TRUE, ffdir, 1.0);
613
614         write_top(fp, NULL, mymol.name, atoms, FALSE, bts, plist, excls, atype,
615                   cgnr, rtp_header_settings.nrexcl);
616         print_top_mols(fp, mymol.name, ffdir, NULL, 0, NULL, 1, &mymol);
617
618         gmx_ffclose(fp);
619     }
620     if (bRTP)
621     {
622         print_rtp(ftp2fn(efRTP, NFILE, fnm), "Generated by x2top",
623                   atoms, plist, atype, cgnr);
624     }
625
626     if (debug)
627     {
628         dump_hybridization(debug, atoms, nbonds);
629     }
630     close_symtab(&symtab);
631     sfree(mymol.name);
632
633     printf("\nWARNING: topologies generated by %s can not be trusted at face value.\n",
634            output_env_get_program_display_name(oenv));
635     printf("         Please verify atomtypes and charges by comparison to other\n");
636     printf("         topologies.\n");
637
638     return 0;
639 }