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-2004, The GROMACS development team.
6 * Copyright (c) 2013,2014,2015,2016,2017,2018, 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.
50 #include "gromacs/fileio/pdbio.h"
51 #include "gromacs/gmxpreprocess/add_par.h"
52 #include "gromacs/gmxpreprocess/fflibutil.h"
53 #include "gromacs/gmxpreprocess/gen_ad.h"
54 #include "gromacs/gmxpreprocess/gen_vsite.h"
55 #include "gromacs/gmxpreprocess/gpp_nextnb.h"
56 #include "gromacs/gmxpreprocess/h_db.h"
57 #include "gromacs/gmxpreprocess/notset.h"
58 #include "gromacs/gmxpreprocess/pgutil.h"
59 #include "gromacs/gmxpreprocess/resall.h"
60 #include "gromacs/gmxpreprocess/topdirs.h"
61 #include "gromacs/gmxpreprocess/topio.h"
62 #include "gromacs/gmxpreprocess/toputil.h"
63 #include "gromacs/math/functions.h"
64 #include "gromacs/math/vec.h"
65 #include "gromacs/topology/residuetypes.h"
66 #include "gromacs/topology/symtab.h"
67 #include "gromacs/utility/binaryinformation.h"
68 #include "gromacs/utility/cstringutil.h"
69 #include "gromacs/utility/dir_separator.h"
70 #include "gromacs/utility/exceptions.h"
71 #include "gromacs/utility/fatalerror.h"
72 #include "gromacs/utility/futil.h"
73 #include "gromacs/utility/niceheader.h"
74 #include "gromacs/utility/path.h"
75 #include "gromacs/utility/programcontext.h"
76 #include "gromacs/utility/smalloc.h"
77 #include "gromacs/utility/strconvert.h"
78 #include "gromacs/utility/strdb.h"
79 #include "gromacs/utility/stringutil.h"
80 #include "gromacs/utility/textwriter.h"
82 /* this must correspond to enum in pdb2top.h */
83 const char *hh[ehisNR] = { "HISD", "HISE", "HISH", "HIS1" };
85 static int missing_atoms(t_restp *rp, int resind, t_atoms *at, int i0, int i)
92 for (j = 0; j < rp->natom; j++)
94 name = *(rp->atomname[j]);
96 for (k = i0; k < i; k++)
98 bFound = (bFound || (gmx_strcasecmp(*(at->atomname[k]), name) == 0));
103 fprintf(stderr, "\nWARNING: "
104 "atom %s is missing in residue %s %d in the pdb file\n",
105 name, *(at->resinfo[resind].name), at->resinfo[resind].nr);
106 if (name[0] == 'H' || name[0] == 'h')
108 fprintf(stderr, " You might need to add atom %s to the hydrogen database of building block %s\n"
109 " in the file %s.hdb (see the manual)\n",
110 name, *(at->resinfo[resind].rtp), rp->filebase);
112 fprintf(stderr, "\n");
119 bool is_int(double x)
121 const double tol = 1e-4;
128 ix = gmx::roundToInt(x);
130 return (fabs(x-ix) < tol);
134 choose_ff_impl(const char *ffsel,
135 char *forcefield, int ff_maxlen,
136 char *ffdir, int ffdir_maxlen)
138 std::vector<gmx::DataFileInfo> ffdirs = fflib_enumerate_forcefields();
139 const int nff = static_cast<int>(ffdirs.size());
141 /* Replace with unix path separators */
142 #if DIR_SEPARATOR != '/'
143 for (int i = 0; i < nff; ++i)
145 std::replace(ffdirs[i].dir.begin(), ffdirs[i].dir.end(), DIR_SEPARATOR, '/');
149 /* Store the force field names in ffs */
150 std::vector<std::string> ffs;
151 ffs.reserve(ffdirs.size());
152 for (int i = 0; i < nff; ++i)
154 ffs.push_back(gmx::stripSuffixIfPresent(ffdirs[i].name,
155 fflib_forcefield_dir_ext()));
159 if (ffsel != nullptr)
164 for (int i = 0; i < nff; ++i)
168 /* Matching ff name */
172 if (ffdirs[i].dir == ".")
189 "Force field '%s' occurs in %d places. pdb2gmx is using the one in the\n"
190 "current directory. Use interactive selection (not the -ff option) if\n"
191 "you would prefer a different one.\n", ffsel, nfound);
195 std::string message = gmx::formatString(
196 "Force field '%s' occurs in %d places, but not in "
197 "the current directory.\n"
198 "Run without the -ff switch and select the force "
199 "field interactively.", ffsel, nfound);
200 GMX_THROW(gmx::InconsistentInputError(message));
203 else if (nfound == 0)
205 std::string message = gmx::formatString(
206 "Could not find force field '%s' in current directory, "
207 "install tree or GMXLIB path.", ffsel);
208 GMX_THROW(gmx::InconsistentInputError(message));
213 std::vector<std::string> desc;
214 desc.reserve(ffdirs.size());
215 for (int i = 0; i < nff; ++i)
217 std::string docFileName(
218 gmx::Path::join(ffdirs[i].dir, ffdirs[i].name,
219 fflib_forcefield_doc()));
220 // TODO: Just try to open the file with a method that does not
221 // throw/bail out with a fatal error instead of multiple checks.
222 if (gmx::File::exists(docFileName, gmx::File::returnFalseOnError))
224 // TODO: Use a C++ API without such an intermediate/fixed-length buffer.
226 /* We don't use fflib_open, because we don't want printf's */
227 FILE *fp = gmx_ffopen(docFileName, "r");
228 get_a_line(fp, buf, STRLEN);
230 desc.emplace_back(buf);
234 desc.push_back(ffs[i]);
237 /* Order force fields from the same dir alphabetically
238 * and put deprecated force fields at the end.
240 for (int i = 0; i < nff; ++i)
242 for (int j = i + 1; j < nff; ++j)
244 if (ffdirs[i].dir == ffdirs[j].dir &&
245 ((desc[i][0] == '[' && desc[j][0] != '[') ||
246 ((desc[i][0] == '[' || desc[j][0] != '[') &&
247 gmx_strcasecmp(desc[i].c_str(), desc[j].c_str()) > 0)))
249 std::swap(ffdirs[i].name, ffdirs[j].name);
250 std::swap(ffs[i], ffs[j]);
251 std::swap(desc[i], desc[j]);
256 printf("\nSelect the Force Field:\n");
257 for (int i = 0; i < nff; ++i)
259 if (i == 0 || ffdirs[i-1].dir != ffdirs[i].dir)
261 if (ffdirs[i].dir == ".")
263 printf("From current directory:\n");
267 printf("From '%s':\n", ffdirs[i].dir.c_str());
270 printf("%2d: %s\n", i+1, desc[i].c_str());
274 // TODO: Add a C++ API for this.
279 pret = fgets(buf, STRLEN, stdin);
283 sel = strtol(buf, nullptr, 10);
287 while (pret == nullptr || (sel < 0) || (sel >= nff));
289 /* Check for a current limitation of the fflib code.
290 * It will always read from the first ff directory in the list.
291 * This check assumes that the order of ffs matches the order
292 * in which fflib_open searches ff library files.
294 for (int i = 0; i < sel; i++)
296 if (ffs[i] == ffs[sel])
298 std::string message = gmx::formatString(
299 "Can only select the first of multiple force "
300 "field entries with directory name '%s%s' in "
301 "the list. If you want to use the next entry, "
302 "run pdb2gmx in a different directory, set GMXLIB "
303 "to point to the desired force field first, and/or "
304 "rename or move the force field directory present "
305 "in the current working directory.",
306 ffs[sel].c_str(), fflib_forcefield_dir_ext());
307 GMX_THROW(gmx::NotImplementedError(message));
316 if (ffs[sel].length() >= static_cast<size_t>(ff_maxlen))
318 std::string message = gmx::formatString(
319 "Length of force field name (%d) >= maxlen (%d)",
320 static_cast<int>(ffs[sel].length()), ff_maxlen);
321 GMX_THROW(gmx::InvalidInputError(message));
323 strcpy(forcefield, ffs[sel].c_str());
326 if (ffdirs[sel].bFromDefaultDir)
328 ffpath = ffdirs[sel].name;
332 ffpath = gmx::Path::join(ffdirs[sel].dir, ffdirs[sel].name);
334 if (ffpath.length() >= static_cast<size_t>(ffdir_maxlen))
336 std::string message = gmx::formatString(
337 "Length of force field dir (%d) >= maxlen (%d)",
338 static_cast<int>(ffpath.length()), ffdir_maxlen);
339 GMX_THROW(gmx::InvalidInputError(message));
341 strcpy(ffdir, ffpath.c_str());
345 choose_ff(const char *ffsel,
346 char *forcefield, int ff_maxlen,
347 char *ffdir, int ffdir_maxlen)
351 choose_ff_impl(ffsel, forcefield, ff_maxlen, ffdir, ffdir_maxlen);
353 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
356 void choose_watermodel(const char *wmsel, const char *ffdir,
359 const char *fn_watermodels = "watermodels.dat";
366 if (strcmp(wmsel, "none") == 0)
368 *watermodel = nullptr;
372 else if (strcmp(wmsel, "select") != 0)
374 *watermodel = gmx_strdup(wmsel);
379 std::string filename = gmx::Path::join(ffdir, fn_watermodels);
380 if (!fflib_fexist(filename))
382 fprintf(stderr, "No file '%s' found, will not include a water model\n",
384 *watermodel = nullptr;
389 fp = fflib_open(filename);
390 printf("\nSelect the Water Model:\n");
393 while (get_a_line(fp, buf, STRLEN))
395 srenew(model, nwm+1);
396 snew(model[nwm], STRLEN);
397 sscanf(buf, "%s%n", model[nwm], &i);
401 fprintf(stderr, "%2d: %s\n", nwm+1, buf+i);
410 fprintf(stderr, "%2d: %s\n", nwm+1, "None");
415 pret = fgets(buf, STRLEN, stdin);
419 sel = strtol(buf, nullptr, 10);
423 while (pret == nullptr || sel < 0 || sel > nwm);
427 *watermodel = nullptr;
431 *watermodel = gmx_strdup(model[sel]);
434 for (i = 0; i < nwm; i++)
441 static int name2type(t_atoms *at, int **cgnr,
442 t_restp restp[], gmx_residuetype_t *rt)
444 int i, j, prevresind, resind, i0, prevcg, cg, curcg;
460 for (i = 0; (i < at->nr); i++)
463 if (at->atom[i].resind != resind)
466 resind = at->atom[i].resind;
467 bProt = gmx_residuetype_is_protein(rt, *(at->resinfo[resind].name));
468 bNterm = bProt && (resind == 0);
471 nmissat += missing_atoms(&restp[prevresind], prevresind, at, i0, i);
475 if (at->atom[i].m == 0)
479 name = *(at->atomname[i]);
480 j = search_jtype(&restp[resind], name, bNterm);
481 at->atom[i].type = restp[resind].atom[j].type;
482 at->atom[i].q = restp[resind].atom[j].q;
483 at->atom[i].m = restp[resind].atom[j].m;
484 cg = restp[resind].cgnr[j];
485 /* A charge group number -1 signals a separate charge group
488 if ( (cg == -1) || (cg != prevcg) || (resind != prevresind) )
504 at->atom[i].typeB = at->atom[i].type;
505 at->atom[i].qB = at->atom[i].q;
506 at->atom[i].mB = at->atom[i].m;
508 nmissat += missing_atoms(&restp[resind], resind, at, i0, i);
513 static void print_top_heavy_H(FILE *out, real mHmult)
517 fprintf(out, "; Using deuterium instead of hydrogen\n\n");
519 else if (mHmult == 4.0)
521 fprintf(out, "#define HEAVY_H\n\n");
523 else if (mHmult != 1.0)
525 fprintf(stderr, "WARNING: unsupported proton mass multiplier (%g) "
526 "in pdb2top\n", mHmult);
530 void print_top_comment(FILE *out,
531 const char *filename,
535 char ffdir_parent[STRLEN];
540 gmx::TextWriter writer(out);
541 gmx::niceHeader(&writer, filename, ';');
542 writer.writeLine(gmx::formatString(";\tThis is a %s topology file", bITP ? "include" : "standalone"));
543 writer.writeLine(";");
545 gmx::BinaryInformationSettings settings;
546 settings.generatedByHeader(true);
547 settings.linePrefix(";\t");
548 gmx::printBinaryInformation(&writer, gmx::getProgramContext(), settings);
550 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
552 if (strchr(ffdir, '/') == nullptr)
554 fprintf(out, ";\tForce field was read from the standard GROMACS share directory.\n;\n\n");
556 else if (ffdir[0] == '.')
558 fprintf(out, ";\tForce field was read from current directory or a relative path - path added.\n;\n\n");
562 strncpy(ffdir_parent, ffdir, STRLEN-1);
563 ffdir_parent[STRLEN-1] = '\0'; /*make sure it is 0-terminated even for long string*/
564 p = strrchr(ffdir_parent, '/');
569 ";\tForce field data was read from:\n"
573 ";\tThis might be a non-standard force field location. When you use this topology, the\n"
574 ";\tforce field must either be present in the current directory, or the location\n"
575 ";\tspecified in the GMXLIB path variable or with the 'include' mdp file option.\n;\n\n",
580 void print_top_header(FILE *out, const char *filename,
581 bool bITP, const char *ffdir, real mHmult)
585 print_top_comment(out, filename, ffdir, bITP);
587 print_top_heavy_H(out, mHmult);
588 fprintf(out, "; Include forcefield parameters\n");
590 p = strrchr(ffdir, '/');
591 p = (ffdir[0] == '.' || p == nullptr) ? ffdir : p+1;
593 fprintf(out, "#include \"%s/%s\"\n\n", p, fflib_forcefield_itp());
596 static void print_top_posre(FILE *out, const char *pr)
598 fprintf(out, "; Include Position restraint file\n");
599 fprintf(out, "#ifdef POSRES\n");
600 fprintf(out, "#include \"%s\"\n", pr);
601 fprintf(out, "#endif\n\n");
604 static void print_top_water(FILE *out, const char *ffdir, const char *water)
609 fprintf(out, "; Include water topology\n");
611 p = strrchr(ffdir, '/');
612 p = (ffdir[0] == '.' || p == nullptr) ? ffdir : p+1;
613 fprintf(out, "#include \"%s/%s.itp\"\n", p, water);
616 fprintf(out, "#ifdef POSRES_WATER\n");
617 fprintf(out, "; Position restraint for each water oxygen\n");
618 fprintf(out, "[ position_restraints ]\n");
619 fprintf(out, ";%3s %5s %9s %10s %10s\n", "i", "funct", "fcx", "fcy", "fcz");
620 fprintf(out, "%4d %4d %10g %10g %10g\n", 1, 1, 1000.0, 1000.0, 1000.0);
621 fprintf(out, "#endif\n");
624 sprintf(buf, "%s/ions.itp", p);
626 if (fflib_fexist(buf))
628 fprintf(out, "; Include topology for ions\n");
629 fprintf(out, "#include \"%s\"\n", buf);
634 static void print_top_system(FILE *out, const char *title)
636 fprintf(out, "[ %s ]\n", dir2str(d_system));
637 fprintf(out, "; Name\n");
638 fprintf(out, "%s\n\n", title[0] ? title : "Protein");
641 void print_top_mols(FILE *out,
642 const char *title, const char *ffdir, const char *water,
643 int nincl, char **incls, int nmol, t_mols *mols)
650 fprintf(out, "; Include chain topologies\n");
651 for (i = 0; (i < nincl); i++)
653 incl = strrchr(incls[i], DIR_SEPARATOR);
660 /* Remove the path from the include name */
663 fprintf(out, "#include \"%s\"\n", incl);
670 print_top_water(out, ffdir, water);
672 print_top_system(out, title);
676 fprintf(out, "[ %s ]\n", dir2str(d_molecules));
677 fprintf(out, "; %-15s %5s\n", "Compound", "#mols");
678 for (i = 0; (i < nmol); i++)
680 fprintf(out, "%-15s %5d\n", mols[i].name, mols[i].nr);
685 void write_top(FILE *out, const char *pr, const char *molname,
686 t_atoms *at, bool bRTPresname,
687 int bts[], t_params plist[], t_excls excls[],
688 gpp_atomtype_t atype, int *cgnr, int nrexcl)
689 /* NOTE: nrexcl is not the size of *excl! */
691 if (at && atype && cgnr)
693 fprintf(out, "[ %s ]\n", dir2str(d_moleculetype));
694 fprintf(out, "; %-15s %5s\n", "Name", "nrexcl");
695 fprintf(out, "%-15s %5d\n\n", molname ? molname : "Protein", nrexcl);
697 print_atoms(out, atype, at, cgnr, bRTPresname);
698 print_bondeds(out, at->nr, d_bonds, F_BONDS, bts[ebtsBONDS], plist);
699 print_bondeds(out, at->nr, d_constraints, F_CONSTR, 0, plist);
700 print_bondeds(out, at->nr, d_constraints, F_CONSTRNC, 0, plist);
701 print_bondeds(out, at->nr, d_pairs, F_LJ14, 0, plist);
702 print_excl(out, at->nr, excls);
703 print_bondeds(out, at->nr, d_angles, F_ANGLES, bts[ebtsANGLES], plist);
704 print_bondeds(out, at->nr, d_dihedrals, F_PDIHS, bts[ebtsPDIHS], plist);
705 print_bondeds(out, at->nr, d_dihedrals, F_IDIHS, bts[ebtsIDIHS], plist);
706 print_bondeds(out, at->nr, d_cmap, F_CMAP, bts[ebtsCMAP], plist);
707 print_bondeds(out, at->nr, d_polarization, F_POLARIZATION, 0, plist);
708 print_bondeds(out, at->nr, d_thole_polarization, F_THOLE_POL, 0, plist);
709 print_bondeds(out, at->nr, d_vsites2, F_VSITE2, 0, plist);
710 print_bondeds(out, at->nr, d_vsites3, F_VSITE3, 0, plist);
711 print_bondeds(out, at->nr, d_vsites3, F_VSITE3FD, 0, plist);
712 print_bondeds(out, at->nr, d_vsites3, F_VSITE3FAD, 0, plist);
713 print_bondeds(out, at->nr, d_vsites3, F_VSITE3OUT, 0, plist);
714 print_bondeds(out, at->nr, d_vsites4, F_VSITE4FD, 0, plist);
715 print_bondeds(out, at->nr, d_vsites4, F_VSITE4FDN, 0, plist);
719 print_top_posre(out, pr);
726 static void do_ssbonds(t_params *ps, t_atoms *atoms,
727 int nssbonds, t_ssbond *ssbonds, bool bAllowMissing)
732 for (i = 0; (i < nssbonds); i++)
734 ri = ssbonds[i].res1;
735 rj = ssbonds[i].res2;
736 ai = search_res_atom(ssbonds[i].a1, ri, atoms,
737 "special bond", bAllowMissing);
738 aj = search_res_atom(ssbonds[i].a2, rj, atoms,
739 "special bond", bAllowMissing);
740 if ((ai == -1) || (aj == -1))
742 gmx_fatal(FARGS, "Trying to make impossible special bond (%s-%s)!",
743 ssbonds[i].a1, ssbonds[i].a2);
745 add_param(ps, ai, aj, nullptr, nullptr);
749 static void at2bonds(t_params *psb, t_hackblock *hb,
752 real long_bond_dist, real short_bond_dist)
756 real dist2, long_bond_dist2, short_bond_dist2;
759 long_bond_dist2 = gmx::square(long_bond_dist);
760 short_bond_dist2 = gmx::square(short_bond_dist);
771 fprintf(stderr, "Making bonds...\n");
773 for (resind = 0; (resind < atoms->nres) && (i < atoms->nr); resind++)
775 /* add bonds from list of bonded interactions */
776 for (j = 0; j < hb[resind].rb[ebtsBONDS].nb; j++)
778 /* Unfortunately we can not issue errors or warnings
779 * for missing atoms in bonds, as the hydrogens and terminal atoms
780 * have not been added yet.
782 ai = search_atom(hb[resind].rb[ebtsBONDS].b[j].a[0], i, atoms,
784 aj = search_atom(hb[resind].rb[ebtsBONDS].b[j].a[1], i, atoms,
786 if (ai != -1 && aj != -1)
788 dist2 = distance2(x[ai], x[aj]);
789 if (dist2 > long_bond_dist2)
792 fprintf(stderr, "Warning: Long Bond (%d-%d = %g nm)\n",
793 ai+1, aj+1, std::sqrt(dist2));
795 else if (dist2 < short_bond_dist2)
797 fprintf(stderr, "Warning: Short Bond (%d-%d = %g nm)\n",
798 ai+1, aj+1, std::sqrt(dist2));
800 add_param(psb, ai, aj, nullptr, hb[resind].rb[ebtsBONDS].b[j].s);
803 /* add bonds from list of hacks (each added atom gets a bond) */
804 while ( (i < atoms->nr) && (atoms->atom[i].resind == resind) )
806 for (j = 0; j < hb[resind].nhack; j++)
808 if ( ( hb[resind].hack[j].tp > 0 ||
809 hb[resind].hack[j].oname == nullptr ) &&
810 strcmp(hb[resind].hack[j].a[0], *(atoms->atomname[i])) == 0)
812 switch (hb[resind].hack[j].tp)
814 case 9: /* COOH terminus */
815 add_param(psb, i, i+1, nullptr, nullptr); /* C-O */
816 add_param(psb, i, i+2, nullptr, nullptr); /* C-OA */
817 add_param(psb, i+2, i+3, nullptr, nullptr); /* OA-H */
820 for (k = 0; (k < hb[resind].hack[j].nr); k++)
822 add_param(psb, i, i+k+1, nullptr, nullptr);
829 /* we're now at the start of the next residue */
833 static int pcompar(const void *a, const void *b)
835 const t_param *pa, *pb;
837 pa = static_cast<const t_param *>(a);
838 pb = static_cast<const t_param *>(b);
840 d = pa->a[0] - pb->a[0];
843 d = pa->a[1] - pb->a[1];
847 return strlen(pb->s) - strlen(pa->s);
855 static void clean_bonds(t_params *ps)
862 /* swap atomnumbers in bond if first larger than second: */
863 for (i = 0; (i < ps->nr); i++)
865 if (ps->param[i].a[1] < ps->param[i].a[0])
867 a = ps->param[i].a[0];
868 ps->param[i].a[0] = ps->param[i].a[1];
869 ps->param[i].a[1] = a;
874 qsort(ps->param, ps->nr, static_cast<size_t>(sizeof(ps->param[0])), pcompar);
876 /* remove doubles, keep the first one always. */
878 for (i = 1; (i < ps->nr); i++)
880 if ((ps->param[i].a[0] != ps->param[j-1].a[0]) ||
881 (ps->param[i].a[1] != ps->param[j-1].a[1]) )
885 cp_param(&(ps->param[j]), &(ps->param[i]));
890 fprintf(stderr, "Number of bonds was %d, now %d\n", ps->nr, j);
895 fprintf(stderr, "No bonds\n");
899 void print_sums(t_atoms *atoms, bool bSystem)
907 where = " in system";
916 for (i = 0; (i < atoms->nr); i++)
918 m += atoms->atom[i].m;
919 qtot += atoms->atom[i].q;
922 fprintf(stderr, "Total mass%s %.3f a.m.u.\n", where, m);
923 fprintf(stderr, "Total charge%s %.3f e\n", where, qtot);
926 static void check_restp_type(const char *name, int t1, int t2)
930 gmx_fatal(FARGS, "Residues in one molecule have a different '%s' type: %d and %d", name, t1, t2);
934 static void check_restp_types(t_restp *r0, t_restp *r1)
938 check_restp_type("all dihedrals", static_cast<int>(r0->bKeepAllGeneratedDihedrals), static_cast<int>(r1->bKeepAllGeneratedDihedrals));
939 check_restp_type("nrexcl", r0->nrexcl, r1->nrexcl);
940 check_restp_type("HH14", static_cast<int>(r0->bGenerateHH14Interactions), static_cast<int>(r1->bGenerateHH14Interactions));
941 check_restp_type("remove dihedrals", static_cast<int>(r0->bRemoveDihedralIfWithImproper), static_cast<int>(r1->bRemoveDihedralIfWithImproper));
943 for (i = 0; i < ebtsNR; i++)
945 check_restp_type(btsNames[i], r0->rb[i].type, r1->rb[i].type);
949 static void add_atom_to_restp(t_restp *restp, int at_start, const t_hack *hack)
953 const char *Hnum = "123456";
955 strcpy(buf, hack->nname);
956 buf[strlen(buf)+1] = '\0';
959 buf[strlen(buf)] = '-';
962 restp->natom += hack->nr;
963 srenew(restp->atom, restp->natom);
964 srenew(restp->atomname, restp->natom);
965 srenew(restp->cgnr, restp->natom);
967 for (k = restp->natom-1; k > at_start+hack->nr; k--)
970 restp->atom [k - hack->nr];
972 restp->atomname[k - hack->nr];
974 restp->cgnr [k - hack->nr];
977 for (k = 0; k < hack->nr; k++)
979 /* set counter in atomname */
982 buf[strlen(buf)-1] = Hnum[k];
984 snew( restp->atomname[at_start+1+k], 1);
985 restp->atom [at_start+1+k] = *hack->atom;
986 *restp->atomname[at_start+1+k] = gmx_strdup(buf);
987 if (hack->cgnr != NOTSET)
989 restp->cgnr [at_start+1+k] = hack->cgnr;
993 restp->cgnr [at_start+1+k] = restp->cgnr[at_start];
998 void get_hackblocks_rtp(t_hackblock **hb, t_restp **restp,
999 int nrtp, t_restp rtp[],
1000 int nres, t_resinfo *resinfo,
1002 t_hackblock **ntdb, t_hackblock **ctdb,
1003 const int *rn, const int *rc,
1014 /* first the termini */
1015 for (i = 0; i < nterpairs; i++)
1017 if (rn[i] >= 0 && ntdb[i] != nullptr)
1019 copy_t_hackblock(ntdb[i], &(*hb)[rn[i]]);
1021 if (rc[i] >= 0 && ctdb[i] != nullptr)
1023 merge_t_hackblock(ctdb[i], &(*hb)[rc[i]]);
1027 /* then the whole rtp */
1028 for (i = 0; i < nres; i++)
1030 /* Here we allow a mismatch of one character when looking for the rtp entry.
1031 * For such a mismatch there should be only one mismatching name.
1032 * This is mainly useful for small molecules such as ions.
1033 * Note that this will usually not work for protein, DNA and RNA,
1034 * since there the residue names should be listed in residuetypes.dat
1035 * and an error will have been generated earlier in the process.
1037 key = *resinfo[i].rtp;
1038 snew(resinfo[i].rtp, 1);
1039 *resinfo[i].rtp = search_rtp(key, nrtp, rtp);
1040 res = get_restp(*resinfo[i].rtp, nrtp, rtp);
1041 copy_t_restp(res, &(*restp)[i]);
1043 /* Check that we do not have different bonded types in one molecule */
1044 check_restp_types(&(*restp)[0], &(*restp)[i]);
1047 for (j = 0; j < nterpairs && tern == -1; j++)
1055 for (j = 0; j < nterpairs && terc == -1; j++)
1062 bRM = merge_t_bondeds(res->rb, (*hb)[i].rb, tern >= 0, terc >= 0);
1064 if (bRM && ((tern >= 0 && ntdb[tern] == nullptr) ||
1065 (terc >= 0 && ctdb[terc] == nullptr)))
1067 const char *errString = "There is a dangling bond at at least one of the terminal ends and the force field does not provide terminal entries or files. Fix your terminal residues so that they match the residue database (.rtp) entries, or provide terminal database entries (.tdb).";
1070 fprintf(stderr, "%s\n", errString);
1074 gmx_fatal(FARGS, "%s", errString);
1077 else if (bRM && ((tern >= 0 && ntdb[tern]->nhack == 0) ||
1078 (terc >= 0 && ctdb[terc]->nhack == 0)))
1080 const char *errString = "There is a dangling bond at at least one of the terminal ends. Fix your coordinate file, add a new terminal database entry (.tdb), or select the proper existing terminal entry.";
1083 fprintf(stderr, "%s\n", errString);
1087 gmx_fatal(FARGS, "%s", errString);
1092 /* now perform t_hack's on t_restp's,
1093 i.e. add's and deletes from termini database will be
1094 added to/removed from residue topology
1095 we'll do this on one big dirty loop, so it won't make easy reading! */
1096 for (i = 0; i < nres; i++)
1098 for (j = 0; j < (*hb)[i].nhack; j++)
1100 if ( (*hb)[i].hack[j].nr)
1102 /* find atom in restp */
1103 for (l = 0; l < (*restp)[i].natom; l++)
1105 if ( ( (*hb)[i].hack[j].oname == nullptr &&
1106 strcmp((*hb)[i].hack[j].a[0], *(*restp)[i].atomname[l]) == 0 ) ||
1107 ( (*hb)[i].hack[j].oname != nullptr &&
1108 strcmp((*hb)[i].hack[j].oname, *(*restp)[i].atomname[l]) == 0 ) )
1113 if (l == (*restp)[i].natom)
1115 /* If we are doing an atom rename only, we don't need
1116 * to generate a fatal error if the old name is not found
1119 /* Deleting can happen also only on the input atoms,
1120 * not necessarily always on the rtp entry.
1122 if (!((*hb)[i].hack[j].oname != nullptr &&
1123 (*hb)[i].hack[j].nname != nullptr) &&
1124 !((*hb)[i].hack[j].oname != nullptr &&
1125 (*hb)[i].hack[j].nname == nullptr))
1128 "atom %s not found in buiding block %d%s "
1129 "while combining tdb and rtp",
1130 (*hb)[i].hack[j].oname != nullptr ?
1131 (*hb)[i].hack[j].oname : (*hb)[i].hack[j].a[0],
1132 i+1, *resinfo[i].rtp);
1137 if ( (*hb)[i].hack[j].oname == nullptr)
1140 add_atom_to_restp(&(*restp)[i], l, &(*hb)[i].hack[j]);
1145 if ( (*hb)[i].hack[j].nname == nullptr)
1146 { /* we're deleting */
1147 /* shift the rest */
1148 (*restp)[i].natom--;
1149 for (k = l; k < (*restp)[i].natom; k++)
1151 (*restp)[i].atom [k] = (*restp)[i].atom [k+1];
1152 (*restp)[i].atomname[k] = (*restp)[i].atomname[k+1];
1153 (*restp)[i].cgnr [k] = (*restp)[i].cgnr [k+1];
1155 /* give back space */
1156 srenew((*restp)[i].atom, (*restp)[i].natom);
1157 srenew((*restp)[i].atomname, (*restp)[i].natom);
1158 srenew((*restp)[i].cgnr, (*restp)[i].natom);
1160 else /* nname != NULL */
1161 { /* we're replacing */
1162 snew( (*restp)[i].atomname[l], 1);
1163 (*restp)[i].atom[l] = *(*hb)[i].hack[j].atom;
1164 *(*restp)[i].atomname[l] = gmx_strdup((*hb)[i].hack[j].nname);
1165 if ( (*hb)[i].hack[j].cgnr != NOTSET)
1167 (*restp)[i].cgnr [l] = (*hb)[i].hack[j].cgnr;
1177 static bool atomname_cmp_nr(const char *anm, t_hack *hack, int *nr)
1184 return (gmx_strcasecmp(anm, hack->nname) == 0);
1188 if (isdigit(anm[strlen(anm)-1]))
1190 *nr = anm[strlen(anm)-1] - '0';
1196 if (*nr <= 0 || *nr > hack->nr)
1202 return (strlen(anm) == strlen(hack->nname) + 1 &&
1203 gmx_strncasecmp(anm, hack->nname, strlen(hack->nname)) == 0);
1208 static bool match_atomnames_with_rtp_atom(t_atoms *pdba, rvec *x, int atind,
1209 t_restp *rptr, t_hackblock *hbr,
1214 char *oldnm, *newnm;
1216 char *start_at, buf[STRLEN];
1218 bool bReplaceReplace, bFoundInAdd;
1221 oldnm = *pdba->atomname[atind];
1222 resnr = pdba->resinfo[pdba->atom[atind].resind].nr;
1225 for (j = 0; j < hbr->nhack; j++)
1227 if (hbr->hack[j].oname != nullptr && hbr->hack[j].nname != nullptr &&
1228 gmx_strcasecmp(oldnm, hbr->hack[j].oname) == 0)
1230 /* This is a replace entry. */
1231 /* Check if we are not replacing a replaced atom. */
1232 bReplaceReplace = FALSE;
1233 for (k = 0; k < hbr->nhack; k++)
1236 hbr->hack[k].oname != nullptr && hbr->hack[k].nname != nullptr &&
1237 gmx_strcasecmp(hbr->hack[k].nname, hbr->hack[j].oname) == 0)
1239 /* The replace in hack[j] replaces an atom that
1240 * was already replaced in hack[k], we do not want
1241 * second or higher level replaces at this stage.
1243 bReplaceReplace = TRUE;
1246 if (bReplaceReplace)
1248 /* Skip this replace. */
1252 /* This atom still has the old name, rename it */
1253 newnm = hbr->hack[j].nname;
1254 for (k = 0; k < rptr->natom; k++)
1256 if (gmx_strcasecmp(newnm, *rptr->atomname[k]) == 0)
1261 if (k == rptr->natom)
1263 /* The new name is not present in the rtp.
1264 * We need to apply the replace also to the rtp entry.
1267 /* We need to find the add hack that can add this atom
1268 * to find out after which atom it should be added.
1270 bFoundInAdd = FALSE;
1271 for (k = 0; k < hbr->nhack; k++)
1273 if (hbr->hack[k].oname == nullptr &&
1274 hbr->hack[k].nname != nullptr &&
1275 atomname_cmp_nr(newnm, &hbr->hack[k], &anmnr))
1279 start_at = hbr->hack[k].a[0];
1283 sprintf(buf, "%s%d", hbr->hack[k].nname, anmnr-1);
1286 for (start_nr = 0; start_nr < rptr->natom; start_nr++)
1288 if (gmx_strcasecmp(start_at, (*rptr->atomname[start_nr])) == 0)
1293 if (start_nr == rptr->natom)
1295 gmx_fatal(FARGS, "Could not find atom '%s' in residue building block '%s' to add atom '%s' to",
1296 start_at, rptr->resname, newnm);
1298 /* We can add the atom after atom start_nr */
1299 add_atom_to_restp(rptr, start_nr, &hbr->hack[j]);
1307 gmx_fatal(FARGS, "Could not find an 'add' entry for atom named '%s' corresponding to the 'replace' entry from atom name '%s' to '%s' for tdb or hdb database of residue type '%s'",
1309 hbr->hack[j].oname, hbr->hack[j].nname,
1316 printf("Renaming atom '%s' in residue '%s' %d to '%s'\n",
1317 oldnm, rptr->resname, resnr, newnm);
1319 /* Rename the atom in pdba */
1320 snew(pdba->atomname[atind], 1);
1321 *pdba->atomname[atind] = gmx_strdup(newnm);
1323 else if (hbr->hack[j].oname != nullptr && hbr->hack[j].nname == nullptr &&
1324 gmx_strcasecmp(oldnm, hbr->hack[j].oname) == 0)
1326 /* This is a delete entry, check if this atom is present
1327 * in the rtp entry of this residue.
1329 for (k = 0; k < rptr->natom; k++)
1331 if (gmx_strcasecmp(oldnm, *rptr->atomname[k]) == 0)
1336 if (k == rptr->natom)
1338 /* This atom is not present in the rtp entry,
1339 * delete is now from the input pdba.
1343 printf("Deleting atom '%s' in residue '%s' %d\n",
1344 oldnm, rptr->resname, resnr);
1346 /* We should free the atom name,
1347 * but it might be used multiple times in the symtab.
1348 * sfree(pdba->atomname[atind]);
1350 for (k = atind+1; k < pdba->nr; k++)
1352 pdba->atom[k-1] = pdba->atom[k];
1353 pdba->atomname[k-1] = pdba->atomname[k];
1354 copy_rvec(x[k], x[k-1]);
1365 void match_atomnames_with_rtp(t_restp restp[], t_hackblock hb[],
1366 t_atoms *pdba, rvec *x,
1373 for (i = 0; i < pdba->nr; i++)
1375 oldnm = *pdba->atomname[i];
1376 rptr = &restp[pdba->atom[i].resind];
1377 for (j = 0; (j < rptr->natom); j++)
1379 if (gmx_strcasecmp(oldnm, *(rptr->atomname[j])) == 0)
1384 if (j == rptr->natom)
1386 /* Not found yet, check if we have to rename this atom */
1387 if (match_atomnames_with_rtp_atom(pdba, x, i,
1388 rptr, &(hb[pdba->atom[i].resind]),
1391 /* We deleted this atom, decrease the atom counter by 1. */
1398 #define NUM_CMAP_ATOMS 5
1399 static void gen_cmap(t_params *psb, t_restp *restp, t_atoms *atoms)
1401 int residx, i, j, k;
1404 t_resinfo *resinfo = atoms->resinfo;
1405 int nres = atoms->nres;
1407 int cmap_atomid[NUM_CMAP_ATOMS];
1408 int cmap_chainnum = -1, this_residue_index;
1419 fprintf(stderr, "Making cmap torsions...\n");
1421 /* Most cmap entries use the N atom from the next residue, so the last
1422 * residue should not have its CMAP entry in that case, but for things like
1423 * dipeptides we sometimes define a complete CMAP entry inside a residue,
1424 * and in this case we need to process everything through the last residue.
1426 for (residx = 0; residx < nres; residx++)
1428 /* Add CMAP terms from the list of CMAP interactions */
1429 for (j = 0; j < restp[residx].rb[ebtsCMAP].nb; j++)
1432 /* Loop over atoms in a candidate CMAP interaction and
1433 * check that they exist, are from the same chain and are
1434 * from residues labelled as protein. */
1435 for (k = 0; k < NUM_CMAP_ATOMS && bAddCMAP; k++)
1437 /* Assign the pointer to the name of the next reference atom.
1438 * This can use -/+ labels to refer to previous/next residue.
1440 pname = restp[residx].rb[ebtsCMAP].b[j].a[k];
1441 /* Skip this CMAP entry if it refers to residues before the
1442 * first or after the last residue.
1444 if (((strchr(pname, '-') != nullptr) && (residx == 0)) ||
1445 ((strchr(pname, '+') != nullptr) && (residx == nres-1)))
1451 cmap_atomid[k] = search_atom(pname,
1452 i, atoms, ptr, TRUE);
1453 bAddCMAP = bAddCMAP && (cmap_atomid[k] != -1);
1456 /* This break is necessary, because cmap_atomid[k]
1457 * == -1 cannot be safely used as an index
1458 * into the atom array. */
1461 this_residue_index = atoms->atom[cmap_atomid[k]].resind;
1464 cmap_chainnum = resinfo[this_residue_index].chainnum;
1468 /* Does the residue for this atom have the same
1469 * chain number as the residues for previous
1471 bAddCMAP = bAddCMAP &&
1472 cmap_chainnum == resinfo[this_residue_index].chainnum;
1474 /* Here we used to check that the residuetype was protein and
1475 * disable bAddCMAP if that was not the case. However, some
1476 * special residues (say, alanine dipeptides) might not adhere
1477 * to standard naming, and if we start calling them normal
1478 * protein residues the user will be bugged to select termini.
1480 * Instead, I believe that the right course of action is to
1481 * keep the CMAP interaction if it is present in the RTP file
1482 * and we correctly identified all atoms (which is the case
1489 add_cmap_param(psb, cmap_atomid[0], cmap_atomid[1], cmap_atomid[2], cmap_atomid[3], cmap_atomid[4], restp[residx].rb[ebtsCMAP].b[j].s);
1493 if (residx < nres-1)
1495 while (atoms->atom[i].resind < residx+1)
1501 /* Start the next residue */
1505 scrub_charge_groups(int *cgnr, int natoms)
1509 for (i = 0; i < natoms; i++)
1516 void pdb2top(FILE *top_file, const char *posre_fn, const char *molname,
1517 t_atoms *atoms, rvec **x, gpp_atomtype_t atype, t_symtab *tab,
1518 int nrtp, t_restp rtp[],
1519 t_restp *restp, t_hackblock *hb,
1521 bool bVsites, bool bVsiteAromatics,
1524 int nssbonds, t_ssbond *ssbonds,
1525 real long_bond_dist, real short_bond_dist,
1526 bool bDeuterate, bool bChargeGroups, bool bCmap,
1527 bool bRenumRes, bool bRTPresname)
1533 t_params plist[F_NRE];
1540 gmx_residuetype_t*rt;
1543 gmx_residuetype_init(&rt);
1546 at2bonds(&(plist[F_BONDS]), hb,
1548 long_bond_dist, short_bond_dist);
1550 /* specbonds: disulphide bonds & heme-his */
1551 do_ssbonds(&(plist[F_BONDS]),
1552 atoms, nssbonds, ssbonds,
1555 nmissat = name2type(atoms, &cgnr, restp, rt);
1560 fprintf(stderr, "There were %d missing atoms in molecule %s\n",
1565 gmx_fatal(FARGS, "There were %d missing atoms in molecule %s, if you want to use this incomplete topology anyhow, use the option -missing",
1570 /* Cleanup bonds (sort and rm doubles) */
1571 clean_bonds(&(plist[F_BONDS]));
1573 snew(vsite_type, atoms->nr);
1574 for (i = 0; i < atoms->nr; i++)
1576 vsite_type[i] = NOTSET;
1580 /* determine which atoms will be vsites and add dummy masses
1581 also renumber atom numbers in plist[0..F_NRE]! */
1582 do_vsites(nrtp, rtp, atype, atoms, tab, x, plist,
1583 &vsite_type, &cgnr, mHmult, bVsiteAromatics, ffdir);
1586 /* Make Angles and Dihedrals */
1587 fprintf(stderr, "Generating angles, dihedrals and pairs...\n");
1588 snew(excls, atoms->nr);
1589 init_nnb(&nnb, atoms->nr, 4);
1590 gen_nnb(&nnb, plist);
1591 print_nnb(&nnb, "NNB");
1592 gen_pad(&nnb, atoms, restp, plist, excls, hb, bAllowMissing);
1598 gen_cmap(&(plist[F_CMAP]), restp, atoms);
1599 if (plist[F_CMAP].nr > 0)
1601 fprintf(stderr, "There are %4d cmap torsion pairs\n",
1606 /* set mass of all remaining hydrogen atoms */
1609 do_h_mass(&(plist[F_BONDS]), vsite_type, atoms, mHmult, bDeuterate);
1613 /* Cleanup bonds (sort and rm doubles) */
1614 /* clean_bonds(&(plist[F_BONDS]));*/
1617 "There are %4d dihedrals, %4d impropers, %4d angles\n"
1618 " %4d pairs, %4d bonds and %4d virtual sites\n",
1619 plist[F_PDIHS].nr, plist[F_IDIHS].nr, plist[F_ANGLES].nr,
1620 plist[F_LJ14].nr, plist[F_BONDS].nr,
1621 plist[F_VSITE2].nr +
1622 plist[F_VSITE3].nr +
1623 plist[F_VSITE3FD].nr +
1624 plist[F_VSITE3FAD].nr +
1625 plist[F_VSITE3OUT].nr +
1626 plist[F_VSITE4FD].nr +
1627 plist[F_VSITE4FDN].nr );
1629 print_sums(atoms, FALSE);
1633 scrub_charge_groups(cgnr, atoms->nr);
1638 for (i = 0; i < atoms->nres; i++)
1640 atoms->resinfo[i].nr = i + 1;
1641 atoms->resinfo[i].ic = ' ';
1647 fprintf(stderr, "Writing topology\n");
1648 /* We can copy the bonded types from the first restp,
1649 * since the types have to be identical for all residues in one molecule.
1651 for (i = 0; i < ebtsNR; i++)
1653 bts[i] = restp[0].rb[i].type;
1655 write_top(top_file, posre_fn, molname,
1657 bts, plist, excls, atype, cgnr, restp[0].nrexcl);
1661 free_t_hackblock(atoms->nres, &hb);
1662 free_t_restp(atoms->nres, &restp);
1663 gmx_residuetype_destroy(rt);
1665 /* we should clean up hb and restp here, but that is a *L*O*T* of work! */
1667 for (i = 0; i < F_NRE; i++)
1669 sfree(plist[i].param);
1671 for (i = 0; i < atoms->nr; i++)