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,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.
39 #include "gen_vsite.h"
51 #include "gromacs/fileio/pdbio.h"
52 #include "gromacs/gmxpreprocess/add_par.h"
53 #include "gromacs/gmxpreprocess/fflibutil.h"
54 #include "gromacs/gmxpreprocess/gpp_atomtype.h"
55 #include "gromacs/gmxpreprocess/grompp_impl.h"
56 #include "gromacs/gmxpreprocess/notset.h"
57 #include "gromacs/gmxpreprocess/toputil.h"
58 #include "gromacs/math/functions.h"
59 #include "gromacs/math/units.h"
60 #include "gromacs/math/vec.h"
61 #include "gromacs/mdtypes/md_enums.h"
62 #include "gromacs/topology/ifunc.h"
63 #include "gromacs/topology/residuetypes.h"
64 #include "gromacs/topology/symtab.h"
65 #include "gromacs/utility/basedefinitions.h"
66 #include "gromacs/utility/cstringutil.h"
67 #include "gromacs/utility/fatalerror.h"
68 #include "gromacs/utility/futil.h"
69 #include "gromacs/utility/real.h"
70 #include "gromacs/utility/smalloc.h"
72 #include "hackblock.h"
76 #define OPENDIR '[' /* starting sign for directive */
77 #define CLOSEDIR ']' /* ending sign for directive */
79 /*! \libinternal \brief
80 * The configuration describing a virtual site.
82 struct VirtualSiteConfiguration
85 * Explicit constructor.
87 * \param[in] type Atomtype for vsite configuration.
88 * \param[in] planar Is the input conf planar.
89 * \param[in] nhyd How many hydrogens are in the configuration.
90 * \param[in] nextheavy Type of bonded heavy atom.
91 * \param[in] dummy What kind of dummy is used in the vsite.
93 explicit VirtualSiteConfiguration(const std::string
&type
, bool planar
,
94 int nhyd
, const std::string
&nextheavy
, const std::string
&dummy
)
95 : atomtype(type
), isplanar(planar
), nHydrogens(nhyd
), nextHeavyType(nextheavy
),
98 //! Type for the XH3/XH2 atom.
100 /*! \brief Is the configuration planar?
102 * If true, the atomtype above and the three connected
103 * ones are in a planar geometry. The two next entries
104 * are undefined in that case.
106 bool isplanar
= false;
107 //!cnumber of connected hydrogens.
109 //! Type for the heavy atom bonded to XH2/XH3.
110 std::string nextHeavyType
;
111 //! The type of MNH* or MCH3* dummy mass to use.
112 std::string dummyMass
;
116 /*!\libinternal \brief
117 * Virtual site topology datastructure.
119 * Structure to represent average bond and angles values in vsite aromatic
120 * residues. Note that these are NOT necessarily the bonds and angles from the
121 * forcefield; many forcefields (like Amber, OPLS) have some inherent strain in
122 * 5-rings (i.e. the sum of angles is !=540, but impropers keep it planar)
124 struct VirtualSiteTopology
127 * Explicit constructor
129 * \param[in] name Residue name.
131 explicit VirtualSiteTopology(const std::string
&name
) : resname(name
)
135 //! Helper struct for single bond in virtual site.
136 struct VirtualSiteBond
139 * Explicit constructor
141 * \param[in] a1 First atom name.
142 * \param[in] a2 Second atom name.
143 * \param[in] v Value for distance.
145 VirtualSiteBond(const std::string
&a1
, const std::string
&a2
, real v
) :
146 atom1(a1
), atom2(a2
), value(v
)
152 //! Distance value between atoms.
155 //! Container of all bonds in virtual site.
156 std::vector
<VirtualSiteBond
> bond
;
157 //! Helper struct for single angle in virtual site.
158 struct VirtualSiteAngle
161 * Explicit constructor
163 * \param[in] a1 First atom name.
164 * \param[in] a2 Second atom name.
165 * \param[in] a3 Third atom name.
166 * \param[in] v Value for angle.
168 VirtualSiteAngle(const std::string
&a1
, const std::string
&a2
, const std::string
&a3
, real v
) :
169 atom1(a1
), atom2(a2
), atom3(a3
), value(v
)
180 //! Container for all angles in virtual site.
181 std::vector
<VirtualSiteAngle
> angle
;
186 DDB_CH3
, DDB_NH3
, DDB_NH2
, DDB_PHE
, DDB_TYR
,
187 DDB_TRP
, DDB_HISA
, DDB_HISB
, DDB_HISH
, DDB_DIR_NR
190 typedef char t_dirname
[STRLEN
];
192 static const t_dirname ddb_dirnames
[DDB_DIR_NR
] = {
204 static int ddb_name2dir(char *name
)
206 /* Translate a directive name to the number of the directive.
207 * HID/HIE/HIP names are translated to the ones we use in Gromacs.
214 for (i
= 0; i
< DDB_DIR_NR
&& index
< 0; i
++)
216 if (!gmx_strcasecmp(name
, ddb_dirnames
[i
]))
226 static void read_vsite_database(const char *ddbname
,
227 std::vector
<VirtualSiteConfiguration
> *vsiteconflist
,
228 std::vector
<VirtualSiteTopology
> *vsitetoplist
)
230 /* This routine is a quick hack to fix the problem with hardcoded atomtypes
231 * and aromatic vsite parameters by reading them from a ff???.vsd file.
233 * The file can contain sections [ NH3 ], [ CH3 ], [ NH2 ], and ring residue names.
234 * For the NH3 and CH3 section each line has three fields. The first is the atomtype
235 * (nb: not bonded type) of the N/C atom to be replaced, the second field is
236 * the type of the next heavy atom it is bonded to, and the third field the type
237 * of dummy mass that will be used for this group.
239 * If the NH2 group planar (sp2 N) a different vsite construct is used, so in this
240 * case the second field should just be the word planar.
247 char s1
[MAXNAME
], s2
[MAXNAME
], s3
[MAXNAME
], s4
[MAXNAME
];
249 gmx::FilePtr ddb
= gmx::openLibraryFile(ddbname
);
253 while (fgets2(pline
, STRLEN
-2, ddb
.get()) != nullptr)
255 strip_comment(pline
);
257 if (strlen(pline
) > 0)
259 if (pline
[0] == OPENDIR
)
261 strncpy(dirstr
, pline
+1, STRLEN
-2);
262 if ((ch
= strchr (dirstr
, CLOSEDIR
)) != nullptr)
268 if (!gmx_strcasecmp(dirstr
, "HID") ||
269 !gmx_strcasecmp(dirstr
, "HISD"))
271 sprintf(dirstr
, "HISA");
273 else if (!gmx_strcasecmp(dirstr
, "HIE") ||
274 !gmx_strcasecmp(dirstr
, "HISE"))
276 sprintf(dirstr
, "HISB");
278 else if (!gmx_strcasecmp(dirstr
, "HIP"))
280 sprintf(dirstr
, "HISH");
283 curdir
= ddb_name2dir(dirstr
);
286 gmx_fatal(FARGS
, "Invalid directive %s in vsite database %s",
295 gmx_fatal(FARGS
, "First entry in vsite database must be a directive.\n");
300 int numberOfSites
= sscanf(pline
, "%s%s%s", s1
, s2
, s3
);
301 std::string s1String
= s1
;
302 std::string s2String
= s2
;
303 std::string s3String
= s3
;
304 if (numberOfSites
< 3 && gmx::equalCaseInsensitive(s2String
, "planar"))
306 VirtualSiteConfiguration
newVsiteConf(s1String
, true, 2, "0", "0");
307 vsiteconflist
->push_back(newVsiteConf
);
309 else if (numberOfSites
== 3)
311 VirtualSiteConfiguration
newVsiteConf(s1String
, false, -1, s2String
, s3String
);
312 if (curdir
== DDB_NH2
)
314 newVsiteConf
.nHydrogens
= 2;
318 newVsiteConf
.nHydrogens
= 3;
320 vsiteconflist
->push_back(newVsiteConf
);
324 gmx_fatal(FARGS
, "Not enough directives in vsite database line: %s\n", pline
);
335 const auto found
= std::find_if(vsitetoplist
->begin(), vsitetoplist
->end(),
336 [&dirstr
](const auto &entry
)
337 { return gmx::equalCaseInsensitive(dirstr
, entry
.resname
); });
338 /* Allocate a new topology entry if this is a new residue */
339 if (found
== vsitetoplist
->end())
341 vsitetoplist
->push_back(VirtualSiteTopology(dirstr
));
343 int numberOfSites
= sscanf(pline
, "%s%s%s%s", s1
, s2
, s3
, s4
);
344 std::string s1String
= s1
;
345 std::string s2String
= s2
;
346 std::string s3String
= s3
;
348 if (numberOfSites
== 3)
351 vsitetoplist
->back().bond
.emplace_back(s1String
, s2String
, strtod(s3
, nullptr));
353 else if (numberOfSites
== 4)
356 vsitetoplist
->back().angle
.emplace_back(s1String
, s2String
, s3String
, strtod(s4
, nullptr));
361 gmx_fatal(FARGS
, "Need 3 or 4 values to specify bond/angle values in %s: %s\n", ddbname
, pline
);
366 gmx_fatal(FARGS
, "Didnt find a case for directive %s in read_vsite_database\n", dirstr
);
373 static int nitrogen_is_planar(gmx::ArrayRef
<const VirtualSiteConfiguration
> vsiteconflist
,
374 const std::string
&atomtype
)
376 /* Return 1 if atomtype exists in database list and is planar, 0 if not,
377 * and -1 if not found.
380 const auto found
= std::find_if(vsiteconflist
.begin(), vsiteconflist
.end(),
381 [&atomtype
](const auto &entry
)
382 { return (gmx::equalCaseInsensitive(entry
.atomtype
, atomtype
) &&
383 entry
.nHydrogens
== 2); });
384 if (found
!= vsiteconflist
.end())
386 res
= static_cast<int>(found
->isplanar
);
396 static std::string
get_dummymass_name(gmx::ArrayRef
<const VirtualSiteConfiguration
> vsiteconflist
,
397 const std::string
&atom
, const std::string
&nextheavy
)
399 /* Return the dummy mass name if found, or NULL if not set in ddb database */
400 const auto found
= std::find_if(vsiteconflist
.begin(), vsiteconflist
.end(),
401 [&atom
, &nextheavy
](const auto &entry
)
402 { return (gmx::equalCaseInsensitive(atom
, entry
.atomtype
) &&
403 gmx::equalCaseInsensitive(nextheavy
, entry
.nextHeavyType
)); });
404 if (found
!= vsiteconflist
.end())
406 return found
->dummyMass
;
416 static real
get_ddb_bond(gmx::ArrayRef
<const VirtualSiteTopology
> vsitetop
,
417 const std::string
&res
,
418 const std::string
&atom1
,
419 const std::string
&atom2
)
421 const auto found
= std::find_if(vsitetop
.begin(), vsitetop
.end(),
422 [&res
](const auto &entry
)
423 { return gmx::equalCaseInsensitive(res
, entry
.resname
); });
425 if (found
== vsitetop
.end())
427 gmx_fatal(FARGS
, "No vsite information for residue %s found in vsite database.\n", res
.c_str());
429 const auto foundBond
= std::find_if(found
->bond
.begin(), found
->bond
.end(),
430 [&atom1
, &atom2
](const auto &entry
)
431 { return ((atom1
== entry
.atom1
&& atom2
== entry
.atom2
) ||
432 (atom1
== entry
.atom2
&& atom2
== entry
.atom1
)); });
433 if (foundBond
== found
->bond
.end())
435 gmx_fatal(FARGS
, "Couldnt find bond %s-%s for residue %s in vsite database.\n", atom1
.c_str(), atom2
.c_str(), res
.c_str());
438 return foundBond
->value
;
442 static real
get_ddb_angle(gmx::ArrayRef
<const VirtualSiteTopology
> vsitetop
,
443 const std::string
&res
,
444 const std::string
&atom1
,
445 const std::string
&atom2
,
446 const std::string
&atom3
)
448 const auto found
= std::find_if(vsitetop
.begin(), vsitetop
.end(),
449 [&res
](const auto &entry
)
450 { return gmx::equalCaseInsensitive(res
, entry
.resname
); });
452 if (found
== vsitetop
.end())
454 gmx_fatal(FARGS
, "No vsite information for residue %s found in vsite database.\n", res
.c_str());
456 const auto foundAngle
= std::find_if(found
->angle
.begin(), found
->angle
.end(),
457 [&atom1
, &atom2
, &atom3
](const auto &entry
)
458 { return ((atom1
== entry
.atom1
&& atom2
== entry
.atom2
&& atom3
== entry
.atom3
) ||
459 (atom1
== entry
.atom3
&& atom2
== entry
.atom2
&& atom3
== entry
.atom1
) ||
460 (atom1
== entry
.atom2
&& atom2
== entry
.atom1
&& atom3
== entry
.atom3
) ||
461 (atom1
== entry
.atom3
&& atom2
== entry
.atom1
&& atom3
== entry
.atom2
)); });
463 if (foundAngle
== found
->angle
.end())
465 gmx_fatal(FARGS
, "Couldnt find angle %s-%s-%s for residue %s in vsite database.\n", atom1
.c_str(), atom2
.c_str(), atom3
.c_str(), res
.c_str());
468 return foundAngle
->value
;
472 static void count_bonds(int atom
, InteractionsOfType
*psb
, char ***atomname
,
473 int *nrbonds
, int *nrHatoms
, int Hatoms
[], int *Heavy
,
474 int *nrheavies
, int heavies
[])
476 int heavy
, other
, nrb
, nrH
, nrhv
;
478 /* find heavy atom bound to this hydrogen */
480 for (auto parm
= psb
->interactionTypes
.begin(); (parm
!= psb
->interactionTypes
.end()) && (heavy
== NOTSET
); parm
++)
482 if (parm
->ai() == atom
)
486 else if (parm
->aj() == atom
)
493 gmx_fatal(FARGS
, "unbound hydrogen atom %d", atom
+1);
495 /* find all atoms bound to heavy atom */
500 for (const auto &parm
: psb
->interactionTypes
)
502 if (parm
.ai() == heavy
)
506 else if (parm
.aj() == heavy
)
513 if (is_hydrogen(*(atomname
[other
])))
520 heavies
[nrhv
] = other
;
532 static void print_bonds(FILE *fp
, int o2n
[],
533 int nrHatoms
, const int Hatoms
[], int Heavy
,
534 int nrheavies
, const int heavies
[])
538 fprintf(fp
, "Found: %d Hatoms: ", nrHatoms
);
539 for (i
= 0; i
< nrHatoms
; i
++)
541 fprintf(fp
, " %d", o2n
[Hatoms
[i
]]+1);
543 fprintf(fp
, "; %d Heavy atoms: %d", nrheavies
+1, o2n
[Heavy
]+1);
544 for (i
= 0; i
< nrheavies
; i
++)
546 fprintf(fp
, " %d", o2n
[heavies
[i
]]+1);
551 static int get_atype(int atom
, t_atoms
*at
, gmx::ArrayRef
<const PreprocessResidue
> rtpFFDB
,
557 if (at
->atom
[atom
].m
!= 0.0F
)
559 type
= at
->atom
[atom
].type
;
563 /* get type from rtpFFDB */
564 auto localPpResidue
= getDatabaseEntry(*(at
->resinfo
[at
->atom
[atom
].resind
].name
), rtpFFDB
);
565 bNterm
= rt
->namedResidueHasType(*(at
->resinfo
[at
->atom
[atom
].resind
].name
), "Protein") &&
566 (at
->atom
[atom
].resind
== 0);
567 int j
= search_jtype(*localPpResidue
, *(at
->atomname
[atom
]), bNterm
);
568 type
= localPpResidue
->atom
[j
].type
;
573 static int vsite_nm2type(const char *name
, PreprocessingAtomTypes
*atype
)
577 tp
= atype
->atomTypeFromName(name
);
580 gmx_fatal(FARGS
, "Dummy mass type (%s) not found in atom type database",
587 static real
get_amass(int atom
, t_atoms
*at
, gmx::ArrayRef
<const PreprocessResidue
> rtpFFDB
,
593 if (at
->atom
[atom
].m
!= 0.0F
)
595 mass
= at
->atom
[atom
].m
;
599 /* get mass from rtpFFDB */
600 auto localPpResidue
= getDatabaseEntry(*(at
->resinfo
[at
->atom
[atom
].resind
].name
), rtpFFDB
);
601 bNterm
= rt
->namedResidueHasType(*(at
->resinfo
[at
->atom
[atom
].resind
].name
), "Protein") &&
602 (at
->atom
[atom
].resind
== 0);
603 int j
= search_jtype(*localPpResidue
, *(at
->atomname
[atom
]), bNterm
);
604 mass
= localPpResidue
->atom
[j
].m
;
609 static void my_add_param(InteractionsOfType
*plist
, int ai
, int aj
, real b
)
611 static real c
[MAXFORCEPARAM
] =
612 { NOTSET
, NOTSET
, NOTSET
, NOTSET
, NOTSET
, NOTSET
};
615 add_param(plist
, ai
, aj
, c
, nullptr);
618 static void add_vsites(gmx::ArrayRef
<InteractionsOfType
> plist
, int vsite_type
[],
619 int Heavy
, int nrHatoms
, int Hatoms
[],
620 int nrheavies
, int heavies
[])
622 int other
, moreheavy
;
624 for (int i
= 0; i
< nrHatoms
; i
++)
626 int ftype
= vsite_type
[Hatoms
[i
]];
627 /* Errors in setting the vsite_type should really be caugth earlier,
628 * because here it's not possible to print any useful error message.
629 * But it's still better to print a message than to segfault.
633 gmx_incons("Undetected error in setting up virtual sites");
635 bool bSwapParity
= (ftype
< 0);
636 vsite_type
[Hatoms
[i
]] = ftype
= abs(ftype
);
637 if (ftype
== F_BONDS
)
639 if ( (nrheavies
!= 1) && (nrHatoms
!= 1) )
641 gmx_fatal(FARGS
, "cannot make constraint in add_vsites for %d heavy "
642 "atoms and %d hydrogen atoms", nrheavies
, nrHatoms
);
644 my_add_param(&(plist
[F_CONSTRNC
]), Hatoms
[i
], heavies
[0], NOTSET
);
655 gmx_fatal(FARGS
, "Not enough heavy atoms (%d) for %s (min 3)",
657 interaction_function
[vsite_type
[Hatoms
[i
]]].name
);
659 add_vsite3_atoms(&plist
[ftype
], Hatoms
[i
], Heavy
, heavies
[0], heavies
[1],
666 moreheavy
= heavies
[1];
670 /* find more heavy atoms */
671 other
= moreheavy
= NOTSET
;
672 for (auto parm
= plist
[F_BONDS
].interactionTypes
.begin();
673 (parm
!= plist
[F_BONDS
].interactionTypes
.end()) && (moreheavy
== NOTSET
); parm
++)
675 if (parm
->ai() == heavies
[0])
679 else if (parm
->aj() == heavies
[0])
683 if ( (other
!= NOTSET
) && (other
!= Heavy
) )
688 if (moreheavy
== NOTSET
)
690 gmx_fatal(FARGS
, "Unbound molecule part %d-%d", Heavy
+1, Hatoms
[0]+1);
693 add_vsite3_atoms(&plist
[ftype
], Hatoms
[i
], Heavy
, heavies
[0], moreheavy
,
701 gmx_fatal(FARGS
, "Not enough heavy atoms (%d) for %s (min 4)",
703 interaction_function
[vsite_type
[Hatoms
[i
]]].name
);
705 add_vsite4_atoms(&plist
[ftype
],
706 Hatoms
[0], Heavy
, heavies
[0], heavies
[1], heavies
[2]);
710 gmx_fatal(FARGS
, "can't use add_vsites for interaction function %s",
711 interaction_function
[vsite_type
[Hatoms
[i
]]].name
);
717 #define ANGLE_6RING (DEG2RAD*120)
719 /* cosine rule: a^2 = b^2 + c^2 - 2 b c cos(alpha) */
720 /* get a^2 when a, b and alpha are given: */
721 #define cosrule(b, c, alpha) ( gmx::square(b) + gmx::square(c) - 2*(b)*(c)*std::cos(alpha) )
722 /* get cos(alpha) when a, b and c are given: */
723 #define acosrule(a, b, c) ( (gmx::square(b)+gmx::square(c)-gmx::square(a))/(2*(b)*(c)) )
725 static int gen_vsites_6ring(t_atoms
*at
, int *vsite_type
[], gmx::ArrayRef
<InteractionsOfType
> plist
,
726 int nrfound
, int *ats
, real bond_cc
, real bond_ch
,
727 real xcom
, bool bDoZ
)
729 /* these MUST correspond to the atnms array in do_vsite_aromatics! */
731 atCG
, atCD1
, atHD1
, atCD2
, atHD2
, atCE1
, atHE1
, atCE2
, atHE2
,
736 real a
, b
, dCGCE
, tmp1
, tmp2
, mtot
, mG
, mrest
;
738 /* CG, CE1 and CE2 stay and each get a part of the total mass,
739 * so the c-o-m stays the same.
746 gmx_incons("Generating vsites on 6-rings");
750 /* constraints between CG, CE1 and CE2: */
751 dCGCE
= std::sqrt( cosrule(bond_cc
, bond_cc
, ANGLE_6RING
) );
752 my_add_param(&(plist
[F_CONSTRNC
]), ats
[atCG
], ats
[atCE1
], dCGCE
);
753 my_add_param(&(plist
[F_CONSTRNC
]), ats
[atCG
], ats
[atCE2
], dCGCE
);
754 my_add_param(&(plist
[F_CONSTRNC
]), ats
[atCE1
], ats
[atCE2
], dCGCE
);
756 /* rest will be vsite3 */
759 for (i
= 0; i
< (bDoZ
? atNR
: atHZ
); i
++)
761 mtot
+= at
->atom
[ats
[i
]].m
;
762 if (i
!= atCG
&& i
!= atCE1
&& i
!= atCE2
&& (bDoZ
|| (i
!= atHZ
&& i
!= atCZ
) ) )
764 at
->atom
[ats
[i
]].m
= at
->atom
[ats
[i
]].mB
= 0;
765 (*vsite_type
)[ats
[i
]] = F_VSITE3
;
769 /* Distribute mass so center-of-mass stays the same.
770 * The center-of-mass in the call is defined with x=0 at
771 * the CE1-CE2 bond and y=0 at the line from CG to the middle of CE1-CE2 bond.
773 xCG
= -bond_cc
+bond_cc
*std::cos(ANGLE_6RING
);
775 mG
= at
->atom
[ats
[atCG
]].m
= at
->atom
[ats
[atCG
]].mB
= xcom
*mtot
/xCG
;
777 at
->atom
[ats
[atCE1
]].m
= at
->atom
[ats
[atCE1
]].mB
=
778 at
->atom
[ats
[atCE2
]].m
= at
->atom
[ats
[atCE2
]].mB
= mrest
/ 2;
780 /* vsite3 construction: r_d = r_i + a r_ij + b r_ik */
781 tmp1
= dCGCE
*std::sin(ANGLE_6RING
*0.5);
782 tmp2
= bond_cc
*std::cos(0.5*ANGLE_6RING
) + tmp1
;
784 a
= b
= -bond_ch
/ tmp1
;
786 add_vsite3_param(&plist
[F_VSITE3
],
787 ats
[atHE1
], ats
[atCE1
], ats
[atCE2
], ats
[atCG
], a
, b
);
788 add_vsite3_param(&plist
[F_VSITE3
],
789 ats
[atHE2
], ats
[atCE2
], ats
[atCE1
], ats
[atCG
], a
, b
);
790 /* CD1, CD2 and CZ: */
792 add_vsite3_param(&plist
[F_VSITE3
],
793 ats
[atCD1
], ats
[atCE2
], ats
[atCE1
], ats
[atCG
], a
, b
);
794 add_vsite3_param(&plist
[F_VSITE3
],
795 ats
[atCD2
], ats
[atCE1
], ats
[atCE2
], ats
[atCG
], a
, b
);
798 add_vsite3_param(&plist
[F_VSITE3
],
799 ats
[atCZ
], ats
[atCG
], ats
[atCE1
], ats
[atCE2
], a
, b
);
801 /* HD1, HD2 and HZ: */
802 a
= b
= ( bond_ch
+ tmp2
) / tmp1
;
803 add_vsite3_param(&plist
[F_VSITE3
],
804 ats
[atHD1
], ats
[atCE2
], ats
[atCE1
], ats
[atCG
], a
, b
);
805 add_vsite3_param(&plist
[F_VSITE3
],
806 ats
[atHD2
], ats
[atCE1
], ats
[atCE2
], ats
[atCG
], a
, b
);
809 add_vsite3_param(&plist
[F_VSITE3
],
810 ats
[atHZ
], ats
[atCG
], ats
[atCE1
], ats
[atCE2
], a
, b
);
816 static int gen_vsites_phe(t_atoms
*at
, int *vsite_type
[], gmx::ArrayRef
<InteractionsOfType
> plist
,
817 int nrfound
, int *ats
, gmx::ArrayRef
<const VirtualSiteTopology
> vsitetop
)
819 real bond_cc
, bond_ch
;
822 /* these MUST correspond to the atnms array in do_vsite_aromatics! */
824 atCG
, atCD1
, atHD1
, atCD2
, atHD2
, atCE1
, atHE1
, atCE2
, atHE2
,
828 /* Aromatic rings have 6-fold symmetry, so we only need one bond length.
829 * (angle is always 120 degrees).
831 bond_cc
= get_ddb_bond(vsitetop
, "PHE", "CD1", "CE1");
832 bond_ch
= get_ddb_bond(vsitetop
, "PHE", "CD1", "HD1");
834 x
[atCG
] = -bond_cc
+bond_cc
*std::cos(ANGLE_6RING
);
836 x
[atHD1
] = x
[atCD1
]+bond_ch
*std::cos(ANGLE_6RING
);
838 x
[atHE1
] = x
[atCE1
]-bond_ch
*std::cos(ANGLE_6RING
);
843 x
[atCZ
] = bond_cc
*std::cos(0.5*ANGLE_6RING
);
844 x
[atHZ
] = x
[atCZ
]+bond_ch
;
847 for (i
= 0; i
< atNR
; i
++)
849 xcom
+= x
[i
]*at
->atom
[ats
[i
]].m
;
850 mtot
+= at
->atom
[ats
[i
]].m
;
854 return gen_vsites_6ring(at
, vsite_type
, plist
, nrfound
, ats
, bond_cc
, bond_ch
, xcom
, TRUE
);
857 static void calc_vsite3_param(real xd
, real yd
, real xi
, real yi
, real xj
, real yj
,
858 real xk
, real yk
, real
*a
, real
*b
)
860 /* determine parameters by solving the equation system, since we know the
861 * virtual site coordinates here.
863 real dx_ij
, dx_ik
, dy_ij
, dy_ik
;
870 *a
= ( (xd
-xi
)*dy_ik
- dx_ik
*(yd
-yi
) ) / (dx_ij
*dy_ik
- dx_ik
*dy_ij
);
871 *b
= ( yd
- yi
- (*a
)*dy_ij
) / dy_ik
;
875 static int gen_vsites_trp(PreprocessingAtomTypes
*atype
,
876 std::vector
<gmx::RVec
> *newx
,
877 t_atom
*newatom
[], char ***newatomname
[],
878 int *o2n
[], int *newvsite_type
[], int *newcgnr
[],
879 t_symtab
*symtab
, int *nadd
,
880 gmx::ArrayRef
<const gmx::RVec
> x
, int *cgnr
[],
881 t_atoms
*at
, int *vsite_type
[],
882 gmx::ArrayRef
<InteractionsOfType
> plist
,
883 int nrfound
, int *ats
, int add_shift
,
884 gmx::ArrayRef
<const VirtualSiteTopology
> vsitetop
)
887 /* these MUST correspond to the atnms array in do_vsite_aromatics! */
889 atCB
, atCG
, atCD1
, atHD1
, atCD2
, atNE1
, atHE1
, atCE2
, atCE3
, atHE3
,
890 atCZ2
, atHZ2
, atCZ3
, atHZ3
, atCH2
, atHH2
, atNR
892 /* weights for determining the COM's of both rings (M1 and M2): */
893 real mw
[NMASS
][atNR
] = {
894 { 0, 1, 1, 1, 0.5, 1, 1, 0.5, 0, 0,
896 { 0, 0, 0, 0, 0.5, 0, 0, 0.5, 1, 1,
900 real xi
[atNR
], yi
[atNR
];
901 real xcom
[NMASS
], ycom
[NMASS
], alpha
;
902 real b_CD2_CE2
, b_NE1_CE2
, b_CG_CD2
, b_CH2_HH2
, b_CE2_CZ2
;
903 real b_NE1_HE1
, b_CD2_CE3
, b_CE3_CZ3
, b_CB_CG
;
904 real b_CZ2_CH2
, b_CZ2_HZ2
, b_CD1_HD1
, b_CE3_HE3
;
905 real b_CG_CD1
, b_CZ3_HZ3
;
906 real a_NE1_CE2_CD2
, a_CE2_CD2_CG
, a_CB_CG_CD2
, a_CE2_CD2_CE3
;
907 real a_CD2_CG_CD1
, a_CE2_CZ2_HZ2
, a_CZ2_CH2_HH2
;
908 real a_CD2_CE2_CZ2
, a_CD2_CE3_CZ3
, a_CE3_CZ3_HZ3
, a_CG_CD1_HD1
;
909 real a_CE2_CZ2_CH2
, a_HE1_NE1_CE2
, a_CD2_CE3_HE3
;
910 int atM
[NMASS
], tpM
, i
, i0
, j
, nvsite
;
911 real mM
[NMASS
], dCBM1
, dCBM2
, dM1M2
;
913 rvec r_ij
, r_ik
, t1
, t2
;
918 gmx_incons("atom types in gen_vsites_trp");
920 /* Get geometry from database */
921 b_CD2_CE2
= get_ddb_bond(vsitetop
, "TRP", "CD2", "CE2");
922 b_NE1_CE2
= get_ddb_bond(vsitetop
, "TRP", "NE1", "CE2");
923 b_CG_CD1
= get_ddb_bond(vsitetop
, "TRP", "CG", "CD1");
924 b_CG_CD2
= get_ddb_bond(vsitetop
, "TRP", "CG", "CD2");
925 b_CB_CG
= get_ddb_bond(vsitetop
, "TRP", "CB", "CG");
926 b_CE2_CZ2
= get_ddb_bond(vsitetop
, "TRP", "CE2", "CZ2");
927 b_CD2_CE3
= get_ddb_bond(vsitetop
, "TRP", "CD2", "CE3");
928 b_CE3_CZ3
= get_ddb_bond(vsitetop
, "TRP", "CE3", "CZ3");
929 b_CZ2_CH2
= get_ddb_bond(vsitetop
, "TRP", "CZ2", "CH2");
931 b_CD1_HD1
= get_ddb_bond(vsitetop
, "TRP", "CD1", "HD1");
932 b_CZ2_HZ2
= get_ddb_bond(vsitetop
, "TRP", "CZ2", "HZ2");
933 b_NE1_HE1
= get_ddb_bond(vsitetop
, "TRP", "NE1", "HE1");
934 b_CH2_HH2
= get_ddb_bond(vsitetop
, "TRP", "CH2", "HH2");
935 b_CE3_HE3
= get_ddb_bond(vsitetop
, "TRP", "CE3", "HE3");
936 b_CZ3_HZ3
= get_ddb_bond(vsitetop
, "TRP", "CZ3", "HZ3");
938 a_NE1_CE2_CD2
= DEG2RAD
*get_ddb_angle(vsitetop
, "TRP", "NE1", "CE2", "CD2");
939 a_CE2_CD2_CG
= DEG2RAD
*get_ddb_angle(vsitetop
, "TRP", "CE2", "CD2", "CG");
940 a_CB_CG_CD2
= DEG2RAD
*get_ddb_angle(vsitetop
, "TRP", "CB", "CG", "CD2");
941 a_CD2_CG_CD1
= DEG2RAD
*get_ddb_angle(vsitetop
, "TRP", "CD2", "CG", "CD1");
943 a_CE2_CD2_CE3
= DEG2RAD
*get_ddb_angle(vsitetop
, "TRP", "CE2", "CD2", "CE3");
944 a_CD2_CE2_CZ2
= DEG2RAD
*get_ddb_angle(vsitetop
, "TRP", "CD2", "CE2", "CZ2");
945 a_CD2_CE3_CZ3
= DEG2RAD
*get_ddb_angle(vsitetop
, "TRP", "CD2", "CE3", "CZ3");
946 a_CE3_CZ3_HZ3
= DEG2RAD
*get_ddb_angle(vsitetop
, "TRP", "CE3", "CZ3", "HZ3");
947 a_CZ2_CH2_HH2
= DEG2RAD
*get_ddb_angle(vsitetop
, "TRP", "CZ2", "CH2", "HH2");
948 a_CE2_CZ2_HZ2
= DEG2RAD
*get_ddb_angle(vsitetop
, "TRP", "CE2", "CZ2", "HZ2");
949 a_CE2_CZ2_CH2
= DEG2RAD
*get_ddb_angle(vsitetop
, "TRP", "CE2", "CZ2", "CH2");
950 a_CG_CD1_HD1
= DEG2RAD
*get_ddb_angle(vsitetop
, "TRP", "CG", "CD1", "HD1");
951 a_HE1_NE1_CE2
= DEG2RAD
*get_ddb_angle(vsitetop
, "TRP", "HE1", "NE1", "CE2");
952 a_CD2_CE3_HE3
= DEG2RAD
*get_ddb_angle(vsitetop
, "TRP", "CD2", "CE3", "HE3");
954 /* Calculate local coordinates.
955 * y-axis (x=0) is the bond CD2-CE2.
956 * x-axis (y=0) is perpendicular to the bond CD2-CE2 and
957 * intersects the middle of the bond.
960 yi
[atCD2
] = -0.5*b_CD2_CE2
;
963 yi
[atCE2
] = 0.5*b_CD2_CE2
;
965 xi
[atNE1
] = -b_NE1_CE2
*std::sin(a_NE1_CE2_CD2
);
966 yi
[atNE1
] = yi
[atCE2
]-b_NE1_CE2
*std::cos(a_NE1_CE2_CD2
);
968 xi
[atCG
] = -b_CG_CD2
*std::sin(a_CE2_CD2_CG
);
969 yi
[atCG
] = yi
[atCD2
]+b_CG_CD2
*std::cos(a_CE2_CD2_CG
);
971 alpha
= a_CE2_CD2_CG
+ M_PI
- a_CB_CG_CD2
;
972 xi
[atCB
] = xi
[atCG
]-b_CB_CG
*std::sin(alpha
);
973 yi
[atCB
] = yi
[atCG
]+b_CB_CG
*std::cos(alpha
);
975 alpha
= a_CE2_CD2_CG
+ a_CD2_CG_CD1
- M_PI
;
976 xi
[atCD1
] = xi
[atCG
]-b_CG_CD1
*std::sin(alpha
);
977 yi
[atCD1
] = yi
[atCG
]+b_CG_CD1
*std::cos(alpha
);
979 xi
[atCE3
] = b_CD2_CE3
*std::sin(a_CE2_CD2_CE3
);
980 yi
[atCE3
] = yi
[atCD2
]+b_CD2_CE3
*std::cos(a_CE2_CD2_CE3
);
982 xi
[atCZ2
] = b_CE2_CZ2
*std::sin(a_CD2_CE2_CZ2
);
983 yi
[atCZ2
] = yi
[atCE2
]-b_CE2_CZ2
*std::cos(a_CD2_CE2_CZ2
);
985 alpha
= a_CE2_CD2_CE3
+ a_CD2_CE3_CZ3
- M_PI
;
986 xi
[atCZ3
] = xi
[atCE3
]+b_CE3_CZ3
*std::sin(alpha
);
987 yi
[atCZ3
] = yi
[atCE3
]+b_CE3_CZ3
*std::cos(alpha
);
989 alpha
= a_CD2_CE2_CZ2
+ a_CE2_CZ2_CH2
- M_PI
;
990 xi
[atCH2
] = xi
[atCZ2
]+b_CZ2_CH2
*std::sin(alpha
);
991 yi
[atCH2
] = yi
[atCZ2
]-b_CZ2_CH2
*std::cos(alpha
);
994 alpha
= a_CE2_CD2_CG
+ a_CD2_CG_CD1
- a_CG_CD1_HD1
;
995 xi
[atHD1
] = xi
[atCD1
]-b_CD1_HD1
*std::sin(alpha
);
996 yi
[atHD1
] = yi
[atCD1
]+b_CD1_HD1
*std::cos(alpha
);
998 alpha
= a_NE1_CE2_CD2
+ M_PI
- a_HE1_NE1_CE2
;
999 xi
[atHE1
] = xi
[atNE1
]-b_NE1_HE1
*std::sin(alpha
);
1000 yi
[atHE1
] = yi
[atNE1
]-b_NE1_HE1
*std::cos(alpha
);
1002 alpha
= a_CE2_CD2_CE3
+ M_PI
- a_CD2_CE3_HE3
;
1003 xi
[atHE3
] = xi
[atCE3
]+b_CE3_HE3
*std::sin(alpha
);
1004 yi
[atHE3
] = yi
[atCE3
]+b_CE3_HE3
*std::cos(alpha
);
1006 alpha
= a_CD2_CE2_CZ2
+ M_PI
- a_CE2_CZ2_HZ2
;
1007 xi
[atHZ2
] = xi
[atCZ2
]+b_CZ2_HZ2
*std::sin(alpha
);
1008 yi
[atHZ2
] = yi
[atCZ2
]-b_CZ2_HZ2
*std::cos(alpha
);
1010 alpha
= a_CD2_CE2_CZ2
+ a_CE2_CZ2_CH2
- a_CZ2_CH2_HH2
;
1011 xi
[atHZ3
] = xi
[atCZ3
]+b_CZ3_HZ3
*std::sin(alpha
);
1012 yi
[atHZ3
] = yi
[atCZ3
]+b_CZ3_HZ3
*std::cos(alpha
);
1014 alpha
= a_CE2_CD2_CE3
+ a_CD2_CE3_CZ3
- a_CE3_CZ3_HZ3
;
1015 xi
[atHH2
] = xi
[atCH2
]+b_CH2_HH2
*std::sin(alpha
);
1016 yi
[atHH2
] = yi
[atCH2
]-b_CH2_HH2
*std::cos(alpha
);
1018 /* Calculate masses for each ring and put it on the dummy masses */
1019 for (j
= 0; j
< NMASS
; j
++)
1021 mM
[j
] = xcom
[j
] = ycom
[j
] = 0;
1023 for (i
= 0; i
< atNR
; i
++)
1027 for (j
= 0; j
< NMASS
; j
++)
1029 mM
[j
] += mw
[j
][i
] * at
->atom
[ats
[i
]].m
;
1030 xcom
[j
] += xi
[i
] * mw
[j
][i
] * at
->atom
[ats
[i
]].m
;
1031 ycom
[j
] += yi
[i
] * mw
[j
][i
] * at
->atom
[ats
[i
]].m
;
1035 for (j
= 0; j
< NMASS
; j
++)
1041 /* get dummy mass type */
1042 tpM
= vsite_nm2type("MW", atype
);
1043 /* make space for 2 masses: shift all atoms starting with CB */
1045 for (j
= 0; j
< NMASS
; j
++)
1047 atM
[j
] = i0
+*nadd
+j
;
1051 fprintf(stderr
, "Inserting %d dummy masses at %d\n", NMASS
, (*o2n
)[i0
]+1);
1054 for (j
= i0
; j
< at
->nr
; j
++)
1056 (*o2n
)[j
] = j
+*nadd
;
1058 newx
->resize(at
->nr
+*nadd
);
1059 srenew(*newatom
, at
->nr
+*nadd
);
1060 srenew(*newatomname
, at
->nr
+*nadd
);
1061 srenew(*newvsite_type
, at
->nr
+*nadd
);
1062 srenew(*newcgnr
, at
->nr
+*nadd
);
1063 for (j
= 0; j
< NMASS
; j
++)
1065 (*newatomname
)[at
->nr
+*nadd
-1-j
] = nullptr;
1068 /* Dummy masses will be placed at the center-of-mass in each ring. */
1070 /* calc initial position for dummy masses in real (non-local) coordinates.
1071 * Cheat by using the routine to calculate virtual site parameters. It is
1072 * much easier when we have the coordinates expressed in terms of
1075 rvec_sub(x
[ats
[atCB
]], x
[ats
[atCG
]], r_ij
);
1076 rvec_sub(x
[ats
[atCD2
]], x
[ats
[atCG
]], r_ik
);
1077 calc_vsite3_param(xcom
[0], ycom
[0], xi
[atCG
], yi
[atCG
], xi
[atCB
], yi
[atCB
],
1078 xi
[atCD2
], yi
[atCD2
], &a
, &b
);
1081 rvec_add(t1
, t2
, t1
);
1082 rvec_add(t1
, x
[ats
[atCG
]], (*newx
)[atM
[0]]);
1084 calc_vsite3_param(xcom
[1], ycom
[1], xi
[atCG
], yi
[atCG
], xi
[atCB
], yi
[atCB
],
1085 xi
[atCD2
], yi
[atCD2
], &a
, &b
);
1088 rvec_add(t1
, t2
, t1
);
1089 rvec_add(t1
, x
[ats
[atCG
]], (*newx
)[atM
[1]]);
1091 /* set parameters for the masses */
1092 for (j
= 0; j
< NMASS
; j
++)
1094 sprintf(name
, "MW%d", j
+1);
1095 (*newatomname
) [atM
[j
]] = put_symtab(symtab
, name
);
1096 (*newatom
) [atM
[j
]].m
= (*newatom
)[atM
[j
]].mB
= mM
[j
];
1097 (*newatom
) [atM
[j
]].q
= (*newatom
)[atM
[j
]].qB
= 0.0;
1098 (*newatom
) [atM
[j
]].type
= (*newatom
)[atM
[j
]].typeB
= tpM
;
1099 (*newatom
) [atM
[j
]].ptype
= eptAtom
;
1100 (*newatom
) [atM
[j
]].resind
= at
->atom
[i0
].resind
;
1101 (*newatom
) [atM
[j
]].elem
[0] = 'M';
1102 (*newatom
) [atM
[j
]].elem
[1] = '\0';
1103 (*newvsite_type
)[atM
[j
]] = NOTSET
;
1104 (*newcgnr
) [atM
[j
]] = (*cgnr
)[i0
];
1106 /* renumber cgnr: */
1107 for (i
= i0
; i
< at
->nr
; i
++)
1112 /* constraints between CB, M1 and M2 */
1113 /* 'add_shift' says which atoms won't be renumbered afterwards */
1114 dCBM1
= std::hypot( xcom
[0]-xi
[atCB
], ycom
[0]-yi
[atCB
] );
1115 dM1M2
= std::hypot( xcom
[0]-xcom
[1], ycom
[0]-ycom
[1] );
1116 dCBM2
= std::hypot( xcom
[1]-xi
[atCB
], ycom
[1]-yi
[atCB
] );
1117 my_add_param(&(plist
[F_CONSTRNC
]), ats
[atCB
], add_shift
+atM
[0], dCBM1
);
1118 my_add_param(&(plist
[F_CONSTRNC
]), ats
[atCB
], add_shift
+atM
[1], dCBM2
);
1119 my_add_param(&(plist
[F_CONSTRNC
]), add_shift
+atM
[0], add_shift
+atM
[1], dM1M2
);
1121 /* rest will be vsite3 */
1123 for (i
= 0; i
< atNR
; i
++)
1127 at
->atom
[ats
[i
]].m
= at
->atom
[ats
[i
]].mB
= 0;
1128 (*vsite_type
)[ats
[i
]] = F_VSITE3
;
1133 /* now define all vsites from M1, M2, CB, ie:
1134 r_d = r_M1 + a r_M1_M2 + b r_M1_CB */
1135 for (i
= 0; i
< atNR
; i
++)
1137 if ( (*vsite_type
)[ats
[i
]] == F_VSITE3
)
1139 calc_vsite3_param(xi
[i
], yi
[i
], xcom
[0], ycom
[0], xcom
[1], ycom
[1], xi
[atCB
], yi
[atCB
], &a
, &b
);
1140 add_vsite3_param(&plist
[F_VSITE3
],
1141 ats
[i
], add_shift
+atM
[0], add_shift
+atM
[1], ats
[atCB
], a
, b
);
1149 static int gen_vsites_tyr(PreprocessingAtomTypes
*atype
,
1150 std::vector
<gmx::RVec
> *newx
,
1151 t_atom
*newatom
[], char ***newatomname
[],
1152 int *o2n
[], int *newvsite_type
[], int *newcgnr
[],
1153 t_symtab
*symtab
, int *nadd
,
1154 gmx::ArrayRef
<const gmx::RVec
> x
, int *cgnr
[],
1155 t_atoms
*at
, int *vsite_type
[],
1156 gmx::ArrayRef
<InteractionsOfType
> plist
,
1157 int nrfound
, int *ats
, int add_shift
,
1158 gmx::ArrayRef
<const VirtualSiteTopology
> vsitetop
)
1160 int nvsite
, i
, i0
, j
, atM
, tpM
;
1161 real dCGCE
, dCEOH
, dCGM
, tmp1
, a
, b
;
1162 real bond_cc
, bond_ch
, bond_co
, bond_oh
, angle_coh
;
1168 /* these MUST correspond to the atnms array in do_vsite_aromatics! */
1170 atCG
, atCD1
, atHD1
, atCD2
, atHD2
, atCE1
, atHE1
, atCE2
, atHE2
,
1171 atCZ
, atOH
, atHH
, atNR
1174 /* CG, CE1, CE2 (as in general 6-ring) and OH and HH stay,
1175 rest gets virtualized.
1176 Now we have two linked triangles with one improper keeping them flat */
1177 if (atNR
!= nrfound
)
1179 gmx_incons("Number of atom types in gen_vsites_tyr");
1182 /* Aromatic rings have 6-fold symmetry, so we only need one bond length
1183 * for the ring part (angle is always 120 degrees).
1185 bond_cc
= get_ddb_bond(vsitetop
, "TYR", "CD1", "CE1");
1186 bond_ch
= get_ddb_bond(vsitetop
, "TYR", "CD1", "HD1");
1187 bond_co
= get_ddb_bond(vsitetop
, "TYR", "CZ", "OH");
1188 bond_oh
= get_ddb_bond(vsitetop
, "TYR", "OH", "HH");
1189 angle_coh
= DEG2RAD
*get_ddb_angle(vsitetop
, "TYR", "CZ", "OH", "HH");
1191 xi
[atCG
] = -bond_cc
+bond_cc
*std::cos(ANGLE_6RING
);
1192 xi
[atCD1
] = -bond_cc
;
1193 xi
[atHD1
] = xi
[atCD1
]+bond_ch
*std::cos(ANGLE_6RING
);
1195 xi
[atHE1
] = xi
[atCE1
]-bond_ch
*std::cos(ANGLE_6RING
);
1196 xi
[atCD2
] = xi
[atCD1
];
1197 xi
[atHD2
] = xi
[atHD1
];
1198 xi
[atCE2
] = xi
[atCE1
];
1199 xi
[atHE2
] = xi
[atHE1
];
1200 xi
[atCZ
] = bond_cc
*std::cos(0.5*ANGLE_6RING
);
1201 xi
[atOH
] = xi
[atCZ
]+bond_co
;
1204 for (i
= 0; i
< atOH
; i
++)
1206 xcom
+= xi
[i
]*at
->atom
[ats
[i
]].m
;
1207 mtot
+= at
->atom
[ats
[i
]].m
;
1211 /* first do 6 ring as default,
1212 except CZ (we'll do that different) and HZ (we don't have that): */
1213 nvsite
= gen_vsites_6ring(at
, vsite_type
, plist
, nrfound
, ats
, bond_cc
, bond_ch
, xcom
, FALSE
);
1215 /* then construct CZ from the 2nd triangle */
1216 /* vsite3 construction: r_d = r_i + a r_ij + b r_ik */
1217 a
= b
= 0.5 * bond_co
/ ( bond_co
- bond_cc
*std::cos(ANGLE_6RING
) );
1218 add_vsite3_param(&plist
[F_VSITE3
],
1219 ats
[atCZ
], ats
[atOH
], ats
[atCE1
], ats
[atCE2
], a
, b
);
1220 at
->atom
[ats
[atCZ
]].m
= at
->atom
[ats
[atCZ
]].mB
= 0;
1222 /* constraints between CE1, CE2 and OH */
1223 dCGCE
= std::sqrt( cosrule(bond_cc
, bond_cc
, ANGLE_6RING
) );
1224 dCEOH
= std::sqrt( cosrule(bond_cc
, bond_co
, ANGLE_6RING
) );
1225 my_add_param(&(plist
[F_CONSTRNC
]), ats
[atCE1
], ats
[atOH
], dCEOH
);
1226 my_add_param(&(plist
[F_CONSTRNC
]), ats
[atCE2
], ats
[atOH
], dCEOH
);
1228 /* We also want to constrain the angle C-O-H, but since CZ is constructed
1229 * we need to introduce a constraint to CG.
1230 * CG is much further away, so that will lead to instabilities in LINCS
1231 * when we constrain both CG-HH and OH-HH distances. Instead of requiring
1232 * the use of lincs_order=8 we introduce a dummy mass three times further
1233 * away from OH than HH. The mass is accordingly a third, with the remaining
1234 * 2/3 moved to OH. This shouldn't cause any problems since the forces will
1235 * apply to the HH constructed atom and not directly on the virtual mass.
1238 vdist
= 2.0*bond_oh
;
1239 mM
= at
->atom
[ats
[atHH
]].m
/2.0;
1240 at
->atom
[ats
[atOH
]].m
+= mM
; /* add 1/2 of original H mass */
1241 at
->atom
[ats
[atOH
]].mB
+= mM
; /* add 1/2 of original H mass */
1242 at
->atom
[ats
[atHH
]].m
= at
->atom
[ats
[atHH
]].mB
= 0;
1244 /* get dummy mass type */
1245 tpM
= vsite_nm2type("MW", atype
);
1246 /* make space for 1 mass: shift HH only */
1251 fprintf(stderr
, "Inserting 1 dummy mass at %d\n", (*o2n
)[i0
]+1);
1254 for (j
= i0
; j
< at
->nr
; j
++)
1256 (*o2n
)[j
] = j
+*nadd
;
1258 newx
->resize(at
->nr
+*nadd
);
1259 srenew(*newatom
, at
->nr
+*nadd
);
1260 srenew(*newatomname
, at
->nr
+*nadd
);
1261 srenew(*newvsite_type
, at
->nr
+*nadd
);
1262 srenew(*newcgnr
, at
->nr
+*nadd
);
1263 (*newatomname
)[at
->nr
+*nadd
-1] = nullptr;
1265 /* Calc the dummy mass initial position */
1266 rvec_sub(x
[ats
[atHH
]], x
[ats
[atOH
]], r1
);
1268 rvec_add(r1
, x
[ats
[atHH
]], (*newx
)[atM
]);
1270 strcpy(name
, "MW1");
1271 (*newatomname
) [atM
] = put_symtab(symtab
, name
);
1272 (*newatom
) [atM
].m
= (*newatom
)[atM
].mB
= mM
;
1273 (*newatom
) [atM
].q
= (*newatom
)[atM
].qB
= 0.0;
1274 (*newatom
) [atM
].type
= (*newatom
)[atM
].typeB
= tpM
;
1275 (*newatom
) [atM
].ptype
= eptAtom
;
1276 (*newatom
) [atM
].resind
= at
->atom
[i0
].resind
;
1277 (*newatom
) [atM
].elem
[0] = 'M';
1278 (*newatom
) [atM
].elem
[1] = '\0';
1279 (*newvsite_type
)[atM
] = NOTSET
;
1280 (*newcgnr
) [atM
] = (*cgnr
)[i0
];
1281 /* renumber cgnr: */
1282 for (i
= i0
; i
< at
->nr
; i
++)
1287 (*vsite_type
)[ats
[atHH
]] = F_VSITE2
;
1289 /* assume we also want the COH angle constrained: */
1290 tmp1
= bond_cc
*std::cos(0.5*ANGLE_6RING
) + dCGCE
*std::sin(ANGLE_6RING
*0.5) + bond_co
;
1291 dCGM
= std::sqrt( cosrule(tmp1
, vdist
, angle_coh
) );
1292 my_add_param(&(plist
[F_CONSTRNC
]), ats
[atCG
], add_shift
+atM
, dCGM
);
1293 my_add_param(&(plist
[F_CONSTRNC
]), ats
[atOH
], add_shift
+atM
, vdist
);
1295 add_vsite2_param(&plist
[F_VSITE2
],
1296 ats
[atHH
], ats
[atOH
], add_shift
+atM
, 1.0/2.0);
1300 static int gen_vsites_his(t_atoms
*at
, int *vsite_type
[],
1301 gmx::ArrayRef
<InteractionsOfType
> plist
,
1302 int nrfound
, int *ats
, gmx::ArrayRef
<const VirtualSiteTopology
> vsitetop
)
1305 real a
, b
, alpha
, dCGCE1
, dCGNE2
;
1306 real sinalpha
, cosalpha
;
1307 real xcom
, ycom
, mtot
;
1308 real mG
, mrest
, mCE1
, mNE2
;
1309 real b_CG_ND1
, b_ND1_CE1
, b_CE1_NE2
, b_CG_CD2
, b_CD2_NE2
;
1310 real b_ND1_HD1
, b_NE2_HE2
, b_CE1_HE1
, b_CD2_HD2
;
1311 real a_CG_ND1_CE1
, a_CG_CD2_NE2
, a_ND1_CE1_NE2
, a_CE1_NE2_CD2
;
1312 real a_NE2_CE1_HE1
, a_NE2_CD2_HD2
, a_CE1_ND1_HD1
, a_CE1_NE2_HE2
;
1315 /* these MUST correspond to the atnms array in do_vsite_aromatics! */
1317 atCG
, atND1
, atHD1
, atCD2
, atHD2
, atCE1
, atHE1
, atNE2
, atHE2
, atNR
1319 real x
[atNR
], y
[atNR
];
1321 /* CG, CE1 and NE2 stay, each gets part of the total mass,
1322 rest gets virtualized */
1323 /* check number of atoms, 3 hydrogens may be missing: */
1324 /* assert( nrfound >= atNR-3 || nrfound <= atNR );
1325 * Don't understand the above logic. Shouldn't it be && rather than || ???
1327 if ((nrfound
< atNR
-3) || (nrfound
> atNR
))
1329 gmx_incons("Generating vsites for HIS");
1332 /* avoid warnings about uninitialized variables */
1333 b_ND1_HD1
= b_NE2_HE2
= b_CE1_HE1
= b_CD2_HD2
= a_NE2_CE1_HE1
=
1334 a_NE2_CD2_HD2
= a_CE1_ND1_HD1
= a_CE1_NE2_HE2
= 0;
1336 if (ats
[atHD1
] != NOTSET
)
1338 if (ats
[atHE2
] != NOTSET
)
1340 sprintf(resname
, "HISH");
1344 sprintf(resname
, "HISA");
1349 sprintf(resname
, "HISB");
1352 /* Get geometry from database */
1353 b_CG_ND1
= get_ddb_bond(vsitetop
, resname
, "CG", "ND1");
1354 b_ND1_CE1
= get_ddb_bond(vsitetop
, resname
, "ND1", "CE1");
1355 b_CE1_NE2
= get_ddb_bond(vsitetop
, resname
, "CE1", "NE2");
1356 b_CG_CD2
= get_ddb_bond(vsitetop
, resname
, "CG", "CD2");
1357 b_CD2_NE2
= get_ddb_bond(vsitetop
, resname
, "CD2", "NE2");
1358 a_CG_ND1_CE1
= DEG2RAD
*get_ddb_angle(vsitetop
, resname
, "CG", "ND1", "CE1");
1359 a_CG_CD2_NE2
= DEG2RAD
*get_ddb_angle(vsitetop
, resname
, "CG", "CD2", "NE2");
1360 a_ND1_CE1_NE2
= DEG2RAD
*get_ddb_angle(vsitetop
, resname
, "ND1", "CE1", "NE2");
1361 a_CE1_NE2_CD2
= DEG2RAD
*get_ddb_angle(vsitetop
, resname
, "CE1", "NE2", "CD2");
1363 if (ats
[atHD1
] != NOTSET
)
1365 b_ND1_HD1
= get_ddb_bond(vsitetop
, resname
, "ND1", "HD1");
1366 a_CE1_ND1_HD1
= DEG2RAD
*get_ddb_angle(vsitetop
, resname
, "CE1", "ND1", "HD1");
1368 if (ats
[atHE2
] != NOTSET
)
1370 b_NE2_HE2
= get_ddb_bond(vsitetop
, resname
, "NE2", "HE2");
1371 a_CE1_NE2_HE2
= DEG2RAD
*get_ddb_angle(vsitetop
, resname
, "CE1", "NE2", "HE2");
1373 if (ats
[atHD2
] != NOTSET
)
1375 b_CD2_HD2
= get_ddb_bond(vsitetop
, resname
, "CD2", "HD2");
1376 a_NE2_CD2_HD2
= DEG2RAD
*get_ddb_angle(vsitetop
, resname
, "NE2", "CD2", "HD2");
1378 if (ats
[atHE1
] != NOTSET
)
1380 b_CE1_HE1
= get_ddb_bond(vsitetop
, resname
, "CE1", "HE1");
1381 a_NE2_CE1_HE1
= DEG2RAD
*get_ddb_angle(vsitetop
, resname
, "NE2", "CE1", "HE1");
1384 /* constraints between CG, CE1 and NE1 */
1385 dCGCE1
= std::sqrt( cosrule(b_CG_ND1
, b_ND1_CE1
, a_CG_ND1_CE1
) );
1386 dCGNE2
= std::sqrt( cosrule(b_CG_CD2
, b_CD2_NE2
, a_CG_CD2_NE2
) );
1388 my_add_param(&(plist
[F_CONSTRNC
]), ats
[atCG
], ats
[atCE1
], dCGCE1
);
1389 my_add_param(&(plist
[F_CONSTRNC
]), ats
[atCG
], ats
[atNE2
], dCGNE2
);
1390 /* we already have a constraint CE1-NE2, so we don't add it again */
1392 /* calculate the positions in a local frame of reference.
1393 * The x-axis is the line from CG that makes a right angle
1394 * with the bond CE1-NE2, and the y-axis the bond CE1-NE2.
1396 /* First calculate the x-axis intersection with y-axis (=yCE1).
1397 * Get cos(angle CG-CE1-NE2) :
1399 cosalpha
= acosrule(dCGNE2
, dCGCE1
, b_CE1_NE2
);
1401 y
[atCE1
] = cosalpha
*dCGCE1
;
1403 y
[atNE2
] = y
[atCE1
]-b_CE1_NE2
;
1404 sinalpha
= std::sqrt(1-cosalpha
*cosalpha
);
1405 x
[atCG
] = -sinalpha
*dCGCE1
;
1407 x
[atHE1
] = x
[atHE2
] = x
[atHD1
] = x
[atHD2
] = 0;
1408 y
[atHE1
] = y
[atHE2
] = y
[atHD1
] = y
[atHD2
] = 0;
1410 /* calculate ND1 and CD2 positions from CE1 and NE2 */
1412 x
[atND1
] = -b_ND1_CE1
*std::sin(a_ND1_CE1_NE2
);
1413 y
[atND1
] = y
[atCE1
]-b_ND1_CE1
*std::cos(a_ND1_CE1_NE2
);
1415 x
[atCD2
] = -b_CD2_NE2
*std::sin(a_CE1_NE2_CD2
);
1416 y
[atCD2
] = y
[atNE2
]+b_CD2_NE2
*std::cos(a_CE1_NE2_CD2
);
1418 /* And finally the hydrogen positions */
1419 if (ats
[atHE1
] != NOTSET
)
1421 x
[atHE1
] = x
[atCE1
] + b_CE1_HE1
*std::sin(a_NE2_CE1_HE1
);
1422 y
[atHE1
] = y
[atCE1
] - b_CE1_HE1
*std::cos(a_NE2_CE1_HE1
);
1424 /* HD2 - first get (ccw) angle from (positive) y-axis */
1425 if (ats
[atHD2
] != NOTSET
)
1427 alpha
= a_CE1_NE2_CD2
+ M_PI
- a_NE2_CD2_HD2
;
1428 x
[atHD2
] = x
[atCD2
] - b_CD2_HD2
*std::sin(alpha
);
1429 y
[atHD2
] = y
[atCD2
] + b_CD2_HD2
*std::cos(alpha
);
1431 if (ats
[atHD1
] != NOTSET
)
1433 /* HD1 - first get (cw) angle from (positive) y-axis */
1434 alpha
= a_ND1_CE1_NE2
+ M_PI
- a_CE1_ND1_HD1
;
1435 x
[atHD1
] = x
[atND1
] - b_ND1_HD1
*std::sin(alpha
);
1436 y
[atHD1
] = y
[atND1
] - b_ND1_HD1
*std::cos(alpha
);
1438 if (ats
[atHE2
] != NOTSET
)
1440 x
[atHE2
] = x
[atNE2
] + b_NE2_HE2
*std::sin(a_CE1_NE2_HE2
);
1441 y
[atHE2
] = y
[atNE2
] + b_NE2_HE2
*std::cos(a_CE1_NE2_HE2
);
1443 /* Have all coordinates now */
1445 /* calc center-of-mass; keep atoms CG, CE1, NE2 and
1446 * set the rest to vsite3
1448 mtot
= xcom
= ycom
= 0;
1450 for (i
= 0; i
< atNR
; i
++)
1452 if (ats
[i
] != NOTSET
)
1454 mtot
+= at
->atom
[ats
[i
]].m
;
1455 xcom
+= x
[i
]*at
->atom
[ats
[i
]].m
;
1456 ycom
+= y
[i
]*at
->atom
[ats
[i
]].m
;
1457 if (i
!= atCG
&& i
!= atCE1
&& i
!= atNE2
)
1459 at
->atom
[ats
[i
]].m
= at
->atom
[ats
[i
]].mB
= 0;
1460 (*vsite_type
)[ats
[i
]] = F_VSITE3
;
1465 if (nvsite
+3 != nrfound
)
1467 gmx_incons("Generating vsites for HIS");
1473 /* distribute mass so that com stays the same */
1474 mG
= xcom
*mtot
/x
[atCG
];
1476 mCE1
= (ycom
-y
[atNE2
])*mrest
/(y
[atCE1
]-y
[atNE2
]);
1479 at
->atom
[ats
[atCG
]].m
= at
->atom
[ats
[atCG
]].mB
= mG
;
1480 at
->atom
[ats
[atCE1
]].m
= at
->atom
[ats
[atCE1
]].mB
= mCE1
;
1481 at
->atom
[ats
[atNE2
]].m
= at
->atom
[ats
[atNE2
]].mB
= mNE2
;
1484 if (ats
[atHE1
] != NOTSET
)
1486 calc_vsite3_param(x
[atHE1
], y
[atHE1
], x
[atCE1
], y
[atCE1
], x
[atNE2
], y
[atNE2
],
1487 x
[atCG
], y
[atCG
], &a
, &b
);
1488 add_vsite3_param(&plist
[F_VSITE3
],
1489 ats
[atHE1
], ats
[atCE1
], ats
[atNE2
], ats
[atCG
], a
, b
);
1492 if (ats
[atHE2
] != NOTSET
)
1494 calc_vsite3_param(x
[atHE2
], y
[atHE2
], x
[atNE2
], y
[atNE2
], x
[atCE1
], y
[atCE1
],
1495 x
[atCG
], y
[atCG
], &a
, &b
);
1496 add_vsite3_param(&plist
[F_VSITE3
],
1497 ats
[atHE2
], ats
[atNE2
], ats
[atCE1
], ats
[atCG
], a
, b
);
1501 calc_vsite3_param(x
[atND1
], y
[atND1
], x
[atNE2
], y
[atNE2
], x
[atCE1
], y
[atCE1
],
1502 x
[atCG
], y
[atCG
], &a
, &b
);
1503 add_vsite3_param(&plist
[F_VSITE3
],
1504 ats
[atND1
], ats
[atNE2
], ats
[atCE1
], ats
[atCG
], a
, b
);
1507 calc_vsite3_param(x
[atCD2
], y
[atCD2
], x
[atCE1
], y
[atCE1
], x
[atNE2
], y
[atNE2
],
1508 x
[atCG
], y
[atCG
], &a
, &b
);
1509 add_vsite3_param(&plist
[F_VSITE3
],
1510 ats
[atCD2
], ats
[atCE1
], ats
[atNE2
], ats
[atCG
], a
, b
);
1513 if (ats
[atHD1
] != NOTSET
)
1515 calc_vsite3_param(x
[atHD1
], y
[atHD1
], x
[atNE2
], y
[atNE2
], x
[atCE1
], y
[atCE1
],
1516 x
[atCG
], y
[atCG
], &a
, &b
);
1517 add_vsite3_param(&plist
[F_VSITE3
],
1518 ats
[atHD1
], ats
[atNE2
], ats
[atCE1
], ats
[atCG
], a
, b
);
1521 if (ats
[atHD2
] != NOTSET
)
1523 calc_vsite3_param(x
[atHD2
], y
[atHD2
], x
[atCE1
], y
[atCE1
], x
[atNE2
], y
[atNE2
],
1524 x
[atCG
], y
[atCG
], &a
, &b
);
1525 add_vsite3_param(&plist
[F_VSITE3
],
1526 ats
[atHD2
], ats
[atCE1
], ats
[atNE2
], ats
[atCG
], a
, b
);
1531 static bool is_vsite(int vsite_type
)
1533 if (vsite_type
== NOTSET
)
1537 switch (abs(vsite_type
) )
1551 static char atomnamesuffix
[] = "1234";
1553 void do_vsites(gmx::ArrayRef
<const PreprocessResidue
> rtpFFDB
, PreprocessingAtomTypes
*atype
,
1554 t_atoms
*at
, t_symtab
*symtab
,
1555 std::vector
<gmx::RVec
> *x
,
1556 gmx::ArrayRef
<InteractionsOfType
> plist
, int *vsite_type
[], int *cgnr
[],
1557 real mHmult
, bool bVsiteAromatics
,
1560 #define MAXATOMSPERRESIDUE 16
1561 int k
, m
, i0
, ni0
, whatres
, add_shift
, nvsite
, nadd
;
1563 int nrfound
= 0, needed
, nrbonds
, nrHatoms
, Heavy
, nrheavies
, tpM
, tpHeavy
;
1564 int Hatoms
[4], heavies
[4];
1565 bool bWARNING
, bAddVsiteParam
, bFirstWater
;
1567 real mHtot
, mtot
, fact
, fact2
;
1568 rvec rpar
, rperp
, temp
;
1569 char tpname
[32], nexttpname
[32];
1570 int *o2n
, *newvsite_type
, *newcgnr
, ats
[MAXATOMSPERRESIDUE
];
1572 char ***newatomname
;
1574 bool isN
, planarN
, bFound
;
1576 /* if bVsiteAromatics=TRUE do_vsites will specifically convert atoms in
1577 PHE, TRP, TYR and HIS to a construction of virtual sites */
1579 resPHE
, resTRP
, resTYR
, resHIS
, resNR
1581 const char *resnms
[resNR
] = { "PHE", "TRP", "TYR", "HIS" };
1582 /* Amber03 alternative names for termini */
1583 const char *resnmsN
[resNR
] = { "NPHE", "NTRP", "NTYR", "NHIS" };
1584 const char *resnmsC
[resNR
] = { "CPHE", "CTRP", "CTYR", "CHIS" };
1585 /* HIS can be known as HISH, HIS1, HISA, HID, HIE, HIP, etc. too */
1586 bool bPartial
[resNR
] = { FALSE
, FALSE
, FALSE
, TRUE
};
1587 /* the atnms for every residue MUST correspond to the enums in the
1588 gen_vsites_* (one for each residue) routines! */
1589 /* also the atom names in atnms MUST be in the same order as in the .rtp! */
1590 const char *atnms
[resNR
][MAXATOMSPERRESIDUE
+1] = {
1592 "CD1", "HD1", "CD2", "HD2",
1593 "CE1", "HE1", "CE2", "HE2",
1594 "CZ", "HZ", nullptr },
1597 "CD1", "HD1", "CD2",
1598 "NE1", "HE1", "CE2", "CE3", "HE3",
1599 "CZ2", "HZ2", "CZ3", "HZ3",
1600 "CH2", "HH2", nullptr },
1602 "CD1", "HD1", "CD2", "HD2",
1603 "CE1", "HE1", "CE2", "HE2",
1604 "CZ", "OH", "HH", nullptr },
1606 "ND1", "HD1", "CD2", "HD2",
1607 "CE1", "HE1", "NE2", "HE2", nullptr }
1612 printf("Searching for atoms to make virtual sites ...\n");
1613 fprintf(debug
, "# # # VSITES # # #\n");
1616 std::vector
<std::string
> db
= fflib_search_file_end(ffdir
, ".vsd", FALSE
);
1618 /* Container of CH3/NH3/NH2 configuration entries.
1619 * See comments in read_vsite_database. It isnt beautiful,
1620 * but it had to be fixed, and I dont even want to try to
1621 * maintain this part of the code...
1623 std::vector
<VirtualSiteConfiguration
> vsiteconflist
;
1625 // TODO those have been deprecated and should be removed completely.
1626 /* Container of geometry (bond/angle) entries for
1627 * residues like PHE, TRP, TYR, HIS, etc., where we need
1628 * to know the geometry to construct vsite aromatics.
1629 * Note that equilibrium geometry isnt necessarily the same
1630 * as the individual bond and angle values given in the
1631 * force field (rings can be strained).
1633 std::vector
<VirtualSiteTopology
> vsitetop
;
1634 for (const auto &filename
: db
)
1636 read_vsite_database(filename
.c_str(), &vsiteconflist
, &vsitetop
);
1642 /* we need a marker for which atoms should *not* be renumbered afterwards */
1643 add_shift
= 10*at
->nr
;
1644 /* make arrays where masses can be inserted into */
1645 std::vector
<gmx::RVec
> newx(at
->nr
);
1646 snew(newatom
, at
->nr
);
1647 snew(newatomname
, at
->nr
);
1648 snew(newvsite_type
, at
->nr
);
1649 snew(newcgnr
, at
->nr
);
1650 /* make index array to tell where the atoms go to when masses are inserted */
1652 for (int i
= 0; i
< at
->nr
; i
++)
1656 /* make index to tell which residues were already processed */
1657 std::vector
<bool> bResProcessed(at
->nres
);
1661 /* generate vsite constructions */
1662 /* loop over all atoms */
1664 for (int i
= 0; (i
< at
->nr
); i
++)
1666 if (at
->atom
[i
].resind
!= resind
)
1668 resind
= at
->atom
[i
].resind
;
1670 const char *resnm
= *(at
->resinfo
[resind
].name
);
1671 /* first check for aromatics to virtualize */
1672 /* don't waste our effort on DNA, water etc. */
1673 /* Only do the vsite aromatic stuff when we reach the
1674 * CA atom, since there might be an X2/X3 group on the
1675 * N-terminus that must be treated first.
1677 if (bVsiteAromatics
&&
1678 (strcmp(*(at
->atomname
[i
]), "CA") == 0) &&
1679 !bResProcessed
[resind
] &&
1680 rt
.namedResidueHasType(*(at
->resinfo
[resind
].name
), "Protein") )
1682 /* mark this residue */
1683 bResProcessed
[resind
] = TRUE
;
1684 /* find out if this residue needs converting */
1686 for (int j
= 0; j
< resNR
&& whatres
== NOTSET
; j
++)
1689 cmplength
= bPartial
[j
] ? strlen(resnm
)-1 : strlen(resnm
);
1691 bFound
= ((gmx::equalCaseInsensitive(resnm
, resnms
[j
], cmplength
)) ||
1692 (gmx::equalCaseInsensitive(resnm
, resnmsN
[j
], cmplength
)) ||
1693 (gmx::equalCaseInsensitive(resnm
, resnmsC
[j
], cmplength
)));
1698 /* get atoms we will be needing for the conversion */
1700 for (k
= 0; atnms
[j
][k
]; k
++)
1703 for (m
= i
; m
< at
->nr
&& at
->atom
[m
].resind
== resind
&& ats
[k
] == NOTSET
; m
++)
1705 if (gmx_strcasecmp(*(at
->atomname
[m
]), atnms
[j
][k
]) == 0)
1713 /* now k is number of atom names in atnms[j] */
1722 if (nrfound
< needed
)
1724 gmx_fatal(FARGS
, "not enough atoms found (%d, need %d) in "
1725 "residue %s %d while\n "
1726 "generating aromatics virtual site construction",
1727 nrfound
, needed
, resnm
, at
->resinfo
[resind
].nr
);
1729 /* Advance overall atom counter */
1733 /* the enums for every residue MUST correspond to atnms[residue] */
1739 fprintf(stderr
, "PHE at %d\n", o2n
[ats
[0]]+1);
1741 nvsite
+= gen_vsites_phe(at
, vsite_type
, plist
, nrfound
, ats
, vsitetop
);
1746 fprintf(stderr
, "TRP at %d\n", o2n
[ats
[0]]+1);
1748 nvsite
+= gen_vsites_trp(atype
, &newx
, &newatom
, &newatomname
, &o2n
,
1749 &newvsite_type
, &newcgnr
, symtab
, &nadd
, *x
, cgnr
,
1750 at
, vsite_type
, plist
, nrfound
, ats
, add_shift
, vsitetop
);
1755 fprintf(stderr
, "TYR at %d\n", o2n
[ats
[0]]+1);
1757 nvsite
+= gen_vsites_tyr(atype
, &newx
, &newatom
, &newatomname
, &o2n
,
1758 &newvsite_type
, &newcgnr
, symtab
, &nadd
, *x
, cgnr
,
1759 at
, vsite_type
, plist
, nrfound
, ats
, add_shift
, vsitetop
);
1764 fprintf(stderr
, "HIS at %d\n", o2n
[ats
[0]]+1);
1766 nvsite
+= gen_vsites_his(at
, vsite_type
, plist
, nrfound
, ats
, vsitetop
);
1769 /* this means this residue won't be processed */
1772 gmx_fatal(FARGS
, "DEATH HORROR in do_vsites (%s:%d)",
1773 __FILE__
, __LINE__
);
1774 } /* switch whatres */
1775 /* skip back to beginning of residue */
1776 while (i
> 0 && at
->atom
[i
-1].resind
== resind
)
1780 } /* if bVsiteAromatics & is protein */
1782 /* now process the rest of the hydrogens */
1783 /* only process hydrogen atoms which are not already set */
1784 if ( ((*vsite_type
)[i
] == NOTSET
) && is_hydrogen(*(at
->atomname
[i
])))
1786 /* find heavy atom, count #bonds from it and #H atoms bound to it
1787 and return H atom numbers (Hatoms) and heavy atom numbers (heavies) */
1788 count_bonds(i
, &plist
[F_BONDS
], at
->atomname
,
1789 &nrbonds
, &nrHatoms
, Hatoms
, &Heavy
, &nrheavies
, heavies
);
1790 /* get Heavy atom type */
1791 tpHeavy
= get_atype(Heavy
, at
, rtpFFDB
, &rt
);
1792 strcpy(tpname
, atype
->atomNameFromAtomType(tpHeavy
));
1795 bAddVsiteParam
= TRUE
;
1796 /* nested if's which check nrHatoms, nrbonds and atomname */
1802 (*vsite_type
)[i
] = F_BONDS
;
1804 case 3: /* =CH-, -NH- or =NH+- */
1805 (*vsite_type
)[i
] = F_VSITE3FD
;
1807 case 4: /* --CH- (tert) */
1808 /* The old type 4FD had stability issues, so
1809 * all new constructs should use 4FDN
1811 (*vsite_type
)[i
] = F_VSITE4FDN
;
1813 /* Check parity of heavy atoms from coordinates */
1818 rvec_sub((*x
)[aj
], (*x
)[ai
], tmpmat
[0]);
1819 rvec_sub((*x
)[ak
], (*x
)[ai
], tmpmat
[1]);
1820 rvec_sub((*x
)[al
], (*x
)[ai
], tmpmat
[2]);
1822 if (det(tmpmat
) > 0)
1830 default: /* nrbonds != 2, 3 or 4 */
1835 else if ( (nrHatoms
== 2) && (nrbonds
== 2) &&
1836 (at
->atom
[Heavy
].atomnumber
== 8) )
1838 bAddVsiteParam
= FALSE
; /* this is water: skip these hydrogens */
1841 bFirstWater
= FALSE
;
1845 "Not converting hydrogens in water to virtual sites\n");
1849 else if ( (nrHatoms
== 2) && (nrbonds
== 4) )
1851 /* -CH2- , -NH2+- */
1852 (*vsite_type
)[Hatoms
[0]] = F_VSITE3OUT
;
1853 (*vsite_type
)[Hatoms
[1]] = -F_VSITE3OUT
;
1857 /* 2 or 3 hydrogen atom, with 3 or 4 bonds in total to the heavy atom.
1858 * If it is a nitrogen, first check if it is planar.
1860 isN
= planarN
= FALSE
;
1861 if ((nrHatoms
== 2) && ((*at
->atomname
[Heavy
])[0] == 'N'))
1864 int j
= nitrogen_is_planar(vsiteconflist
, tpname
);
1867 gmx_fatal(FARGS
, "No vsite database NH2 entry for type %s\n", tpname
);
1871 if ( (nrHatoms
== 2) && (nrbonds
== 3) && ( !isN
|| planarN
) )
1873 /* =CH2 or, if it is a nitrogen NH2, it is a planar one */
1874 (*vsite_type
)[Hatoms
[0]] = F_VSITE3FAD
;
1875 (*vsite_type
)[Hatoms
[1]] = -F_VSITE3FAD
;
1877 else if ( ( (nrHatoms
== 2) && (nrbonds
== 3) &&
1878 ( isN
&& !planarN
) ) ||
1879 ( (nrHatoms
== 3) && (nrbonds
== 4) ) )
1881 /* CH3, NH3 or non-planar NH2 group */
1882 int Hat_vsite_type
[3] = { F_VSITE3
, F_VSITE3OUT
, F_VSITE3OUT
};
1883 bool Hat_SwapParity
[3] = { FALSE
, TRUE
, FALSE
};
1887 fprintf(stderr
, "-XH3 or nonplanar NH2 group at %d\n", i
+1);
1889 bAddVsiteParam
= FALSE
; /* we'll do this ourselves! */
1890 /* -NH2 (umbrella), -NH3+ or -CH3 */
1891 (*vsite_type
)[Heavy
] = F_VSITE3
;
1892 for (int j
= 0; j
< nrHatoms
; j
++)
1894 (*vsite_type
)[Hatoms
[j
]] = Hat_vsite_type
[j
];
1896 /* get dummy mass type from first char of heavy atom type (N or C) */
1898 strcpy(nexttpname
, atype
->atomNameFromAtomType(get_atype(heavies
[0], at
, rtpFFDB
, &rt
)));
1899 std::string ch
= get_dummymass_name(vsiteconflist
, tpname
, nexttpname
);
1905 gmx_fatal(FARGS
, "Can't find dummy mass for type %s bonded to type %s in the virtual site database (.vsd files). Add it to the database!\n", tpname
, nexttpname
);
1909 gmx_fatal(FARGS
, "A dummy mass for type %s bonded to type %s is required, but no virtual site database (.vsd) files where found.\n", tpname
, nexttpname
);
1917 tpM
= vsite_nm2type(name
.c_str(), atype
);
1918 /* make space for 2 masses: shift all atoms starting with 'Heavy' */
1924 fprintf(stderr
, "Inserting %d dummy masses at %d\n", NMASS
, o2n
[i0
]+1);
1927 for (int j
= i0
; j
< at
->nr
; j
++)
1932 newx
.resize(at
->nr
+nadd
);
1933 srenew(newatom
, at
->nr
+nadd
);
1934 srenew(newatomname
, at
->nr
+nadd
);
1935 srenew(newvsite_type
, at
->nr
+nadd
);
1936 srenew(newcgnr
, at
->nr
+nadd
);
1938 for (int j
= 0; j
< NMASS
; j
++)
1940 newatomname
[at
->nr
+nadd
-1-j
] = nullptr;
1943 /* calculate starting position for the masses */
1945 /* get atom masses, and set Heavy and Hatoms mass to zero */
1946 for (int j
= 0; j
< nrHatoms
; j
++)
1948 mHtot
+= get_amass(Hatoms
[j
], at
, rtpFFDB
, &rt
);
1949 at
->atom
[Hatoms
[j
]].m
= at
->atom
[Hatoms
[j
]].mB
= 0;
1951 mtot
= mHtot
+ get_amass(Heavy
, at
, rtpFFDB
, &rt
);
1952 at
->atom
[Heavy
].m
= at
->atom
[Heavy
].mB
= 0;
1958 fact
= std::sqrt(fact2
);
1959 /* generate vectors parallel and perpendicular to rotational axis:
1960 * rpar = Heavy -> Hcom
1961 * rperp = Hcom -> H1 */
1963 for (int j
= 0; j
< nrHatoms
; j
++)
1965 rvec_inc(rpar
, (*x
)[Hatoms
[j
]]);
1967 svmul(1.0/nrHatoms
, rpar
, rpar
); /* rpar = ( H1+H2+H3 ) / 3 */
1968 rvec_dec(rpar
, (*x
)[Heavy
]); /* - Heavy */
1969 rvec_sub((*x
)[Hatoms
[0]], (*x
)[Heavy
], rperp
);
1970 rvec_dec(rperp
, rpar
); /* rperp = H1 - Heavy - rpar */
1971 /* calc mass positions */
1972 svmul(fact2
, rpar
, temp
);
1973 for (int j
= 0; (j
< NMASS
); j
++) /* xM = xN + fact2 * rpar +/- fact * rperp */
1975 rvec_add((*x
)[Heavy
], temp
, newx
[ni0
+j
]);
1977 svmul(fact
, rperp
, temp
);
1978 rvec_inc(newx
[ni0
], temp
);
1979 rvec_dec(newx
[ni0
+1], temp
);
1980 /* set atom parameters for the masses */
1981 for (int j
= 0; (j
< NMASS
); j
++)
1983 /* make name: "M??#" or "M?#" (? is atomname, # is number) */
1986 for (k
= 0; (*at
->atomname
[Heavy
])[k
] && ( k
< NMASS
); k
++)
1988 name
[k
+1] = (*at
->atomname
[Heavy
])[k
];
1990 name
[k
+1] = atomnamesuffix
[j
];
1992 newatomname
[ni0
+j
] = put_symtab(symtab
, name
.c_str());
1993 newatom
[ni0
+j
].m
= newatom
[ni0
+j
].mB
= mtot
/NMASS
;
1994 newatom
[ni0
+j
].q
= newatom
[ni0
+j
].qB
= 0.0;
1995 newatom
[ni0
+j
].type
= newatom
[ni0
+j
].typeB
= tpM
;
1996 newatom
[ni0
+j
].ptype
= eptAtom
;
1997 newatom
[ni0
+j
].resind
= at
->atom
[i0
].resind
;
1998 newatom
[ni0
+j
].elem
[0] = 'M';
1999 newatom
[ni0
+j
].elem
[1] = '\0';
2000 newvsite_type
[ni0
+j
] = NOTSET
;
2001 newcgnr
[ni0
+j
] = (*cgnr
)[i0
];
2003 /* add constraints between dummy masses and to heavies[0] */
2004 /* 'add_shift' says which atoms won't be renumbered afterwards */
2005 my_add_param(&(plist
[F_CONSTRNC
]), heavies
[0], add_shift
+ni0
, NOTSET
);
2006 my_add_param(&(plist
[F_CONSTRNC
]), heavies
[0], add_shift
+ni0
+1, NOTSET
);
2007 my_add_param(&(plist
[F_CONSTRNC
]), add_shift
+ni0
, add_shift
+ni0
+1, NOTSET
);
2009 /* generate Heavy, H1, H2 and H3 from M1, M2 and heavies[0] */
2010 /* note that vsite_type cannot be NOTSET, because we just set it */
2011 add_vsite3_atoms (&plist
[(*vsite_type
)[Heavy
]],
2012 Heavy
, heavies
[0], add_shift
+ni0
, add_shift
+ni0
+1,
2014 for (int j
= 0; j
< nrHatoms
; j
++)
2016 add_vsite3_atoms(&plist
[(*vsite_type
)[Hatoms
[j
]]],
2017 Hatoms
[j
], heavies
[0], add_shift
+ni0
, add_shift
+ni0
+1,
2030 gmx_fatal(FARGS
, "Cannot convert atom %d %s (bound to a heavy atom "
2032 " %d bonds and %d bound hydrogens atoms) to virtual site\n",
2033 i
+1, *(at
->atomname
[i
]), tpname
, nrbonds
, nrHatoms
);
2037 /* add vsite parameters to topology,
2038 also get rid of negative vsite_types */
2039 add_vsites(plist
, (*vsite_type
), Heavy
, nrHatoms
, Hatoms
,
2040 nrheavies
, heavies
);
2041 /* transfer mass of virtual site to Heavy atom */
2042 for (int j
= 0; j
< nrHatoms
; j
++)
2044 if (is_vsite((*vsite_type
)[Hatoms
[j
]]))
2046 at
->atom
[Heavy
].m
+= at
->atom
[Hatoms
[j
]].m
;
2047 at
->atom
[Heavy
].mB
= at
->atom
[Heavy
].m
;
2048 at
->atom
[Hatoms
[j
]].m
= at
->atom
[Hatoms
[j
]].mB
= 0;
2055 fprintf(debug
, "atom %d: ", o2n
[i
]+1);
2056 print_bonds(debug
, o2n
, nrHatoms
, Hatoms
, Heavy
, nrheavies
, heavies
);
2058 } /* if vsite NOTSET & is hydrogen */
2060 } /* for i < at->nr */
2064 fprintf(debug
, "Before inserting new atoms:\n");
2065 for (int i
= 0; i
< at
->nr
; i
++)
2067 fprintf(debug
, "%4d %4d %4s %4d %4s %6d %-10s\n", i
+1, o2n
[i
]+1,
2068 at
->atomname
[i
] ? *(at
->atomname
[i
]) : "(NULL)",
2069 at
->resinfo
[at
->atom
[i
].resind
].nr
,
2070 at
->resinfo
[at
->atom
[i
].resind
].name
?
2071 *(at
->resinfo
[at
->atom
[i
].resind
].name
) : "(NULL)",
2073 ((*vsite_type
)[i
] == NOTSET
) ?
2074 "NOTSET" : interaction_function
[(*vsite_type
)[i
]].name
);
2076 fprintf(debug
, "new atoms to be inserted:\n");
2077 for (int i
= 0; i
< at
->nr
+nadd
; i
++)
2081 fprintf(debug
, "%4d %4s %4d %6d %-10s\n", i
+1,
2082 newatomname
[i
] ? *(newatomname
[i
]) : "(NULL)",
2083 newatom
[i
].resind
, newcgnr
[i
],
2084 (newvsite_type
[i
] == NOTSET
) ?
2085 "NOTSET" : interaction_function
[newvsite_type
[i
]].name
);
2090 /* add all original atoms to the new arrays, using o2n index array */
2091 for (int i
= 0; i
< at
->nr
; i
++)
2093 newatomname
[o2n
[i
]] = at
->atomname
[i
];
2094 newatom
[o2n
[i
]] = at
->atom
[i
];
2095 newvsite_type
[o2n
[i
]] = (*vsite_type
)[i
];
2096 newcgnr
[o2n
[i
]] = (*cgnr
) [i
];
2097 copy_rvec((*x
)[i
], newx
[o2n
[i
]]);
2099 /* throw away old atoms */
2101 sfree(at
->atomname
);
2104 /* put in the new ones */
2107 at
->atomname
= newatomname
;
2108 *vsite_type
= newvsite_type
;
2111 if (at
->nr
> add_shift
)
2113 gmx_fatal(FARGS
, "Added impossible amount of dummy masses "
2114 "(%d on a total of %d atoms)\n", nadd
, at
->nr
-nadd
);
2119 fprintf(debug
, "After inserting new atoms:\n");
2120 for (int i
= 0; i
< at
->nr
; i
++)
2122 fprintf(debug
, "%4d %4s %4d %4s %6d %-10s\n", i
+1,
2123 at
->atomname
[i
] ? *(at
->atomname
[i
]) : "(NULL)",
2124 at
->resinfo
[at
->atom
[i
].resind
].nr
,
2125 at
->resinfo
[at
->atom
[i
].resind
].name
?
2126 *(at
->resinfo
[at
->atom
[i
].resind
].name
) : "(NULL)",
2128 ((*vsite_type
)[i
] == NOTSET
) ?
2129 "NOTSET" : interaction_function
[(*vsite_type
)[i
]].name
);
2133 /* now renumber all the interactions because of the added atoms */
2134 for (int ftype
= 0; ftype
< F_NRE
; ftype
++)
2136 InteractionsOfType
*params
= &(plist
[ftype
]);
2139 fprintf(debug
, "Renumbering %zu %s\n", params
->size(),
2140 interaction_function
[ftype
].longname
);
2142 /* Horrible hacks needed here to get this to work */
2143 for (auto parm
= params
->interactionTypes
.begin(); parm
!= params
->interactionTypes
.end(); parm
++)
2145 gmx::ArrayRef
<const int> atomNumbers(parm
->atoms());
2146 std::vector
<int> newAtomNumber
;
2147 for (int j
= 0; j
< NRAL(ftype
); j
++)
2149 if (atomNumbers
[j
] >= add_shift
)
2153 fprintf(debug
, " [%d -> %d]", atomNumbers
[j
],
2154 atomNumbers
[j
]-add_shift
);
2156 newAtomNumber
.emplace_back(atomNumbers
[j
]-add_shift
);
2162 fprintf(debug
, " [%d -> %d]", atomNumbers
[j
],
2163 o2n
[atomNumbers
[j
]]);
2165 newAtomNumber
.emplace_back(o2n
[atomNumbers
[j
]]);
2168 *parm
= InteractionOfType(newAtomNumber
, parm
->forceParam(), parm
->interactionTypeName());
2171 fprintf(debug
, "\n");
2175 /* sort constraint parameters */
2176 InteractionsOfType
*params
= &(plist
[F_CONSTRNC
]);
2177 for (auto &type
: params
->interactionTypes
)
2185 /* tell the user what we did */
2186 fprintf(stderr
, "Marked %d virtual sites\n", nvsite
);
2187 fprintf(stderr
, "Added %d dummy masses\n", nadd
);
2188 fprintf(stderr
, "Added %zu new constraints\n", plist
[F_CONSTRNC
].size());
2191 void do_h_mass(InteractionsOfType
*psb
, int vsite_type
[], t_atoms
*at
, real mHmult
,
2194 /* loop over all atoms */
2195 for (int i
= 0; i
< at
->nr
; i
++)
2197 /* adjust masses if i is hydrogen and not a virtual site */
2198 if (!is_vsite(vsite_type
[i
]) && is_hydrogen(*(at
->atomname
[i
])) )
2200 /* find bonded heavy atom */
2202 for (auto parm
= psb
->interactionTypes
.begin(); (parm
!= psb
->interactionTypes
.end()) && (a
== NOTSET
); parm
++)
2204 /* if other atom is not a virtual site, it is the one we want */
2205 if ( (parm
->ai() == i
) &&
2206 !is_vsite(vsite_type
[parm
->aj()]) )
2210 else if ( (parm
->aj() == i
) &&
2211 !is_vsite(vsite_type
[parm
->ai()]) )
2218 gmx_fatal(FARGS
, "Unbound hydrogen atom (%d) found while adjusting mass",
2222 /* adjust mass of i (hydrogen) with mHmult
2223 and correct mass of a (bonded atom) with same amount */
2226 at
->atom
[a
].m
-= (mHmult
-1.0)*at
->atom
[i
].m
;
2227 at
->atom
[a
].mB
-= (mHmult
-1.0)*at
->atom
[i
].m
;
2229 at
->atom
[i
].m
*= mHmult
;
2230 at
->atom
[i
].mB
*= mHmult
;