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,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 "vsite_parm.h"
47 #include "gromacs/gmxpreprocess/add_par.h"
48 #include "gromacs/gmxpreprocess/gpp_atomtype.h"
49 #include "gromacs/gmxpreprocess/grompp_impl.h"
50 #include "gromacs/gmxpreprocess/notset.h"
51 #include "gromacs/gmxpreprocess/toputil.h"
52 #include "gromacs/math/functions.h"
53 #include "gromacs/math/units.h"
54 #include "gromacs/math/vec.h"
55 #include "gromacs/mdtypes/md_enums.h"
56 #include "gromacs/topology/ifunc.h"
57 #include "gromacs/topology/topology.h"
58 #include "gromacs/utility/arrayref.h"
59 #include "gromacs/utility/cstringutil.h"
60 #include "gromacs/utility/fatalerror.h"
61 #include "gromacs/utility/gmxassert.h"
62 #include "gromacs/utility/smalloc.h"
63 #include "gromacs/utility/strconvert.h"
65 #include "hackblock.h"
71 t_iatom &ai() { return a[0]; }
72 t_iatom &aj() { return a[1]; }
73 t_iatom &ak() { return a[2]; }
74 t_iatom &al() { return a[3]; }
77 struct VsiteBondParameter
79 VsiteBondParameter(int ftype, const InteractionOfType &vsiteInteraction)
80 : ftype_(ftype), vsiteInteraction_(vsiteInteraction)
83 const InteractionOfType &vsiteInteraction_;
88 //! Function type for conversion.
90 //! The vsite parameters in a list.
91 std::vector<VsiteBondParameter> vSiteBondedParameters;
94 using Atom2VsiteConnection = std::vector<int>;
96 static int vsite_bond_nrcheck(int ftype)
100 if ((interaction_function[ftype].flags & (IF_BTYPE | IF_CONSTRAINT | IF_ATYPE)) || (ftype == F_IDIHS))
102 nrcheck = NRAL(ftype);
112 static void enter_bonded(int nratoms, int *nrbonded, t_mybonded **bondeds,
113 const InteractionOfType &type)
115 srenew(*bondeds, *nrbonded+1);
117 /* copy atom numbers */
118 gmx::ArrayRef<const int> atoms = type.atoms();
119 GMX_RELEASE_ASSERT(nratoms == atoms.ssize(), "Size of atom array must much");
120 for (int j = 0; j < nratoms; j++)
122 (*bondeds)[*nrbonded].a[j] = atoms[j];
125 (*bondeds)[*nrbonded].c = type.c0();
130 static void get_bondeds(int nrat, gmx::ArrayRef<const int> atoms,
131 gmx::ArrayRef<const Atom2VsiteBond> at2vb,
132 int *nrbond, t_mybonded **bonds,
133 int *nrang, t_mybonded **angles,
134 int *nridih, t_mybonded **idihs )
136 for (int k = 0; k < nrat; k++)
138 for (auto &vsite : at2vb[atoms[k]].vSiteBondedParameters)
140 int ftype = vsite.ftype_;
141 const InteractionOfType &type = vsite.vsiteInteraction_;
142 int nrcheck = vsite_bond_nrcheck(ftype);
143 /* abuse nrcheck to see if we're adding bond, angle or idih */
146 case 2: enter_bonded(nrcheck, nrbond, bonds, type); break;
147 case 3: enter_bonded(nrcheck, nrang, angles, type); break;
148 case 4: enter_bonded(nrcheck, nridih, idihs, type); break;
154 static std::vector<Atom2VsiteBond>
155 make_at2vsitebond(int natoms, gmx::ArrayRef<InteractionsOfType> plist)
159 std::vector<Atom2VsiteBond> at2vb(natoms);
162 for (int ftype = 0; (ftype < F_NRE); ftype++)
164 if ((interaction_function[ftype].flags & IF_VSITE) && ftype != F_VSITEN)
166 for (int i = 0; (i < gmx::ssize(plist[ftype])); i++)
168 gmx::ArrayRef<const int> atoms = plist[ftype].interactionTypes[i].atoms();
169 for (int j = 0; j < NRAL(ftype); j++)
171 bVSI[atoms[j]] = TRUE;
177 for (int ftype = 0; (ftype < F_NRE); ftype++)
179 int nrcheck = vsite_bond_nrcheck(ftype);
182 for (int i = 0; (i < gmx::ssize(plist[ftype])); i++)
184 gmx::ArrayRef<const int> aa = plist[ftype].interactionTypes[i].atoms();
185 for (int j = 0; j < nrcheck; j++)
189 at2vb[aa[j]].vSiteBondedParameters.emplace_back(ftype, plist[ftype].interactionTypes[i]);
200 static std::vector<Atom2VsiteConnection>
201 make_at2vsitecon(int natoms, gmx::ArrayRef<InteractionsOfType> plist)
203 std::vector<bool> bVSI(natoms);
204 std::vector<Atom2VsiteConnection> at2vc(natoms);
206 for (int ftype = 0; (ftype < F_NRE); ftype++)
208 if ((interaction_function[ftype].flags & IF_VSITE) && ftype != F_VSITEN)
210 for (int i = 0; (i < gmx::ssize(plist[ftype])); i++)
212 gmx::ArrayRef<const int> atoms = plist[ftype].interactionTypes[i].atoms();
213 for (int j = 0; j < NRAL(ftype); j++)
215 bVSI[atoms[j]] = TRUE;
221 for (int ftype = 0; (ftype < F_NRE); ftype++)
223 if (interaction_function[ftype].flags & IF_CONSTRAINT)
225 for (int i = 0; (i < gmx::ssize(plist[ftype])); i++)
227 int ai = plist[ftype].interactionTypes[i].ai();
228 int aj = plist[ftype].interactionTypes[i].aj();
229 if (bVSI[ai] && bVSI[aj])
231 /* Store forward direction */
232 at2vc[ai].emplace_back(aj);
233 /* Store backward direction */
234 at2vc[aj].emplace_back(ai);
243 static void print_bad(FILE *fp,
244 int nrbond, t_mybonded *bonds,
245 int nrang, t_mybonded *angles,
246 int nridih, t_mybonded *idihs )
250 fprintf(fp, "bonds:");
251 for (int i = 0; i < nrbond; i++)
253 fprintf(fp, " %d-%d (%g)",
254 bonds[i].ai()+1, bonds[i].aj()+1, bonds[i].c);
260 fprintf(fp, "angles:");
261 for (int i = 0; i < nrang; i++)
263 fprintf(fp, " %d-%d-%d (%g)",
264 angles[i].ai()+1, angles[i].aj()+1,
265 angles[i].ak()+1, angles[i].c);
271 fprintf(fp, "idihs:");
272 for (int i = 0; i < nridih; i++)
274 fprintf(fp, " %d-%d-%d-%d (%g)",
275 idihs[i].ai()+1, idihs[i].aj()+1,
276 idihs[i].ak()+1, idihs[i].al()+1, idihs[i].c);
282 static void printInteractionOfType(FILE *fp, int ftype, int i, const InteractionOfType &type)
285 static int prev_ftype = NOTSET;
286 static int prev_i = NOTSET;
288 if ( (ftype != prev_ftype) || (i != prev_i) )
294 fprintf(fp, "(%d) plist[%s].param[%d]",
295 pass, interaction_function[ftype].name, i);
296 gmx::ArrayRef<const real> forceParam = type.forceParam();
297 for (int j = 0; j < NRFP(ftype); j++)
299 fprintf(fp, ".c[%d]=%g ", j, forceParam[j]);
305 static real get_bond_length(int nrbond, t_mybonded bonds[],
306 t_iatom ai, t_iatom aj)
312 for (i = 0; i < nrbond && (bondlen == NOTSET); i++)
314 /* check both ways */
315 if ( ( (ai == bonds[i].ai()) && (aj == bonds[i].aj()) ) ||
316 ( (ai == bonds[i].aj()) && (aj == bonds[i].ai()) ) )
318 bondlen = bonds[i].c; /* note: bonds[i].c might be NOTSET */
324 static real get_angle(int nrang, t_mybonded angles[],
325 t_iatom ai, t_iatom aj, t_iatom ak)
331 for (i = 0; i < nrang && (angle == NOTSET); i++)
333 /* check both ways */
334 if ( ( (ai == angles[i].ai()) && (aj == angles[i].aj()) && (ak == angles[i].ak()) ) ||
335 ( (ai == angles[i].ak()) && (aj == angles[i].aj()) && (ak == angles[i].ai()) ) )
337 angle = DEG2RAD*angles[i].c;
343 static const char *get_atomtype_name_AB(t_atom *atom, PreprocessingAtomTypes *atypes)
345 const char* name = atypes->atomNameFromAtomType(atom->type);
347 /* When using the decoupling option, atom types are changed
348 * to decoupled for the non-bonded interactions, but the virtual
349 * sites constructions should be based on the "normal" interactions.
350 * So we return the state B atom type name if the state A atom
351 * type is the decoupled one. We should actually check for the atom
352 * type number, but that's not passed here. So we check for
353 * the decoupled atom type name. This should not cause trouble
354 * as this code is only used for topologies with v-sites without
355 * parameters generated by pdb2gmx.
357 if (strcmp(name, "decoupled") == 0)
359 name = atypes->atomNameFromAtomType(atom->typeB);
365 static bool calc_vsite3_param(PreprocessingAtomTypes *atypes,
366 InteractionOfType *param, t_atoms *at,
367 int nrbond, t_mybonded *bonds,
368 int nrang, t_mybonded *angles )
370 /* i = virtual site | ,k
371 * j = 1st bonded heavy atom | i-j
372 * k,l = 2nd bonded atoms | `l
376 real bjk, bjl, a = -1, b = -1;
377 /* check if this is part of a NH3 , NH2-umbrella or CH3 group,
378 * i.e. if atom k and l are dummy masses (MNH* or MCH3*) */
380 ( (gmx::equalCaseInsensitive(get_atomtype_name_AB(&at->atom[param->ak()], atypes), "MNH", 3)) &&
381 (gmx::equalCaseInsensitive(get_atomtype_name_AB(&at->atom[param->al()], atypes), "MNH", 3)) ) ||
382 ( (gmx::equalCaseInsensitive(get_atomtype_name_AB(&at->atom[param->ak()], atypes), "MCH3", 4)) &&
383 (gmx::equalCaseInsensitive(get_atomtype_name_AB(&at->atom[param->al()], atypes), "MCH3", 4)) );
385 bjk = get_bond_length(nrbond, bonds, param->aj(), param->ak());
386 bjl = get_bond_length(nrbond, bonds, param->aj(), param->al());
387 bError = (bjk == NOTSET) || (bjl == NOTSET);
390 /* now we get some XH2/XH3 group specific construction */
391 /* note: we call the heavy atom 'C' and the X atom 'N' */
392 real bMM, bCM, bCN, bNH, aCNH, dH, rH, dM, rM;
395 /* check if bonds from heavy atom (j) to dummy masses (k,l) are equal: */
396 bError = bError || (bjk != bjl);
398 /* the X atom (C or N) in the XH2/XH3 group is the first after the masses: */
399 aN = std::max(param->ak(), param->al())+1;
401 /* get common bonds */
402 bMM = get_bond_length(nrbond, bonds, param->ak(), param->al());
404 bCN = get_bond_length(nrbond, bonds, param->aj(), aN);
405 bError = bError || (bMM == NOTSET) || (bCN == NOTSET);
407 /* calculate common things */
409 dM = std::sqrt( gmx::square(bCM) - gmx::square(rM) );
411 /* are we dealing with the X atom? */
412 if (param->ai() == aN)
414 /* this is trivial */
415 a = b = 0.5 * bCN/dM;
420 /* get other bondlengths and angles: */
421 bNH = get_bond_length(nrbond, bonds, aN, param->ai());
422 aCNH = get_angle (nrang, angles, param->aj(), aN, param->ai());
423 bError = bError || (bNH == NOTSET) || (aCNH == NOTSET);
426 dH = bCN - bNH * std::cos(aCNH);
427 rH = bNH * std::sin(aCNH);
429 a = 0.5 * ( dH/dM + rH/rM );
430 b = 0.5 * ( dH/dM - rH/rM );
435 gmx_fatal(FARGS, "calc_vsite3_param not implemented for the general case "
436 "(atom %d)", param->ai()+1);
438 param->setForceParameter(0, a);
439 param->setForceParameter(1, b);
444 static bool calc_vsite3fd_param(InteractionOfType *param,
445 int nrbond, t_mybonded *bonds,
446 int nrang, t_mybonded *angles)
448 /* i = virtual site | ,k
449 * j = 1st bonded heavy atom | i-j
450 * k,l = 2nd bonded atoms | `l
454 real bij, bjk, bjl, aijk, aijl, rk, rl;
456 bij = get_bond_length(nrbond, bonds, param->ai(), param->aj());
457 bjk = get_bond_length(nrbond, bonds, param->aj(), param->ak());
458 bjl = get_bond_length(nrbond, bonds, param->aj(), param->al());
459 aijk = get_angle (nrang, angles, param->ai(), param->aj(), param->ak());
460 aijl = get_angle (nrang, angles, param->ai(), param->aj(), param->al());
461 bError = (bij == NOTSET) || (bjk == NOTSET) || (bjl == NOTSET) ||
462 (aijk == NOTSET) || (aijl == NOTSET);
464 rk = bjk * std::sin(aijk);
465 rl = bjl * std::sin(aijl);
466 param->setForceParameter(0, rk / (rk + rl));
467 param->setForceParameter(1, -bij);
472 static bool calc_vsite3fad_param(InteractionOfType *param,
473 int nrbond, t_mybonded *bonds,
474 int nrang, t_mybonded *angles)
476 /* i = virtual site |
477 * j = 1st bonded heavy atom | i-j
478 * k = 2nd bonded heavy atom | `k-l
479 * l = 3d bonded heavy atom |
482 bool bSwapParity, bError;
485 bSwapParity = ( param->c1() == -1 );
487 bij = get_bond_length(nrbond, bonds, param->ai(), param->aj());
488 aijk = get_angle (nrang, angles, param->ai(), param->aj(), param->ak());
489 bError = (bij == NOTSET) || (aijk == NOTSET);
491 param->setForceParameter(1, bij);
492 param->setForceParameter(0, RAD2DEG*aijk);
496 param->setForceParameter(0, 360 - param->c0());
502 static bool calc_vsite3out_param(PreprocessingAtomTypes *atypes,
503 InteractionOfType *param, t_atoms *at,
504 int nrbond, t_mybonded *bonds,
505 int nrang, t_mybonded *angles)
507 /* i = virtual site | ,k
508 * j = 1st bonded heavy atom | i-j
509 * k,l = 2nd bonded atoms | `l
510 * NOTE: i is out of the j-k-l plane!
513 bool bXH3, bError, bSwapParity;
514 real bij, bjk, bjl, aijk, aijl, akjl, pijk, pijl, a, b, c;
516 /* check if this is part of a NH2-umbrella, NH3 or CH3 group,
517 * i.e. if atom k and l are dummy masses (MNH* or MCH3*) */
519 ( (gmx::equalCaseInsensitive(get_atomtype_name_AB(&at->atom[param->ak()], atypes), "MNH", 3)) &&
520 (gmx::equalCaseInsensitive(get_atomtype_name_AB(&at->atom[param->al()], atypes), "MNH", 3)) ) ||
521 ( (gmx::equalCaseInsensitive(get_atomtype_name_AB(&at->atom[param->ak()], atypes), "MCH3", 4)) &&
522 (gmx::equalCaseInsensitive(get_atomtype_name_AB(&at->atom[param->al()], atypes), "MCH3", 4)) );
524 /* check if construction parity must be swapped */
525 bSwapParity = ( param->c1() == -1 );
527 bjk = get_bond_length(nrbond, bonds, param->aj(), param->ak());
528 bjl = get_bond_length(nrbond, bonds, param->aj(), param->al());
529 bError = (bjk == NOTSET) || (bjl == NOTSET);
532 /* now we get some XH3 group specific construction */
533 /* note: we call the heavy atom 'C' and the X atom 'N' */
534 real bMM, bCM, bCN, bNH, aCNH, dH, rH, rHx, rHy, dM, rM;
537 /* check if bonds from heavy atom (j) to dummy masses (k,l) are equal: */
538 bError = bError || (bjk != bjl);
540 /* the X atom (C or N) in the XH3 group is the first after the masses: */
541 aN = std::max(param->ak(), param->al())+1;
543 /* get all bondlengths and angles: */
544 bMM = get_bond_length(nrbond, bonds, param->ak(), param->al());
546 bCN = get_bond_length(nrbond, bonds, param->aj(), aN);
547 bNH = get_bond_length(nrbond, bonds, aN, param->ai());
548 aCNH = get_angle (nrang, angles, param->aj(), aN, param->ai());
550 (bMM == NOTSET) || (bCN == NOTSET) || (bNH == NOTSET) || (aCNH == NOTSET);
553 dH = bCN - bNH * std::cos(aCNH);
554 rH = bNH * std::sin(aCNH);
555 /* we assume the H's are symmetrically distributed */
556 rHx = rH*std::cos(DEG2RAD*30);
557 rHy = rH*std::sin(DEG2RAD*30);
559 dM = std::sqrt( gmx::square(bCM) - gmx::square(rM) );
560 a = 0.5*( (dH/dM) - (rHy/rM) );
561 b = 0.5*( (dH/dM) + (rHy/rM) );
567 /* this is the general construction */
569 bij = get_bond_length(nrbond, bonds, param->ai(), param->aj());
570 aijk = get_angle (nrang, angles, param->ai(), param->aj(), param->ak());
571 aijl = get_angle (nrang, angles, param->ai(), param->aj(), param->al());
572 akjl = get_angle (nrang, angles, param->ak(), param->aj(), param->al());
574 (bij == NOTSET) || (aijk == NOTSET) || (aijl == NOTSET) || (akjl == NOTSET);
576 pijk = std::cos(aijk)*bij;
577 pijl = std::cos(aijl)*bij;
578 a = ( pijk + (pijk*std::cos(akjl)-pijl) * std::cos(akjl) / gmx::square(std::sin(akjl)) ) / bjk;
579 b = ( pijl + (pijl*std::cos(akjl)-pijk) * std::cos(akjl) / gmx::square(std::sin(akjl)) ) / bjl;
580 c = -std::sqrt( gmx::square(bij) -
581 ( gmx::square(pijk) - 2*pijk*pijl*std::cos(akjl) + gmx::square(pijl) )
582 / gmx::square(std::sin(akjl)) )
583 / ( bjk*bjl*std::sin(akjl) );
586 param->setForceParameter(0, a);
587 param->setForceParameter(1, b);
590 param->setForceParameter(2, -c);
594 param->setForceParameter(2, c);
599 static bool calc_vsite4fd_param(InteractionOfType *param,
600 int nrbond, t_mybonded *bonds,
601 int nrang, t_mybonded *angles)
603 /* i = virtual site | ,k
604 * j = 1st bonded heavy atom | i-j-m
605 * k,l,m = 2nd bonded atoms | `l
609 real bij, bjk, bjl, bjm, aijk, aijl, aijm, akjm, akjl;
610 real pk, pl, pm, cosakl, cosakm, sinakl, sinakm, cl, cm;
612 bij = get_bond_length(nrbond, bonds, param->ai(), param->aj());
613 bjk = get_bond_length(nrbond, bonds, param->aj(), param->ak());
614 bjl = get_bond_length(nrbond, bonds, param->aj(), param->al());
615 bjm = get_bond_length(nrbond, bonds, param->aj(), param->am());
616 aijk = get_angle (nrang, angles, param->ai(), param->aj(), param->ak());
617 aijl = get_angle (nrang, angles, param->ai(), param->aj(), param->al());
618 aijm = get_angle (nrang, angles, param->ai(), param->aj(), param->am());
619 akjm = get_angle (nrang, angles, param->ak(), param->aj(), param->am());
620 akjl = get_angle (nrang, angles, param->ak(), param->aj(), param->al());
621 bError = (bij == NOTSET) || (bjk == NOTSET) || (bjl == NOTSET) || (bjm == NOTSET) ||
622 (aijk == NOTSET) || (aijl == NOTSET) || (aijm == NOTSET) || (akjm == NOTSET) ||
627 pk = bjk*std::sin(aijk);
628 pl = bjl*std::sin(aijl);
629 pm = bjm*std::sin(aijm);
630 cosakl = (std::cos(akjl) - std::cos(aijk)*std::cos(aijl)) / (std::sin(aijk)*std::sin(aijl));
631 cosakm = (std::cos(akjm) - std::cos(aijk)*std::cos(aijm)) / (std::sin(aijk)*std::sin(aijm));
632 if (cosakl < -1 || cosakl > 1 || cosakm < -1 || cosakm > 1)
634 fprintf(stderr, "virtual site %d: angle ijk = %f, angle ijl = %f, angle ijm = %f\n",
635 param->ai()+1, RAD2DEG*aijk, RAD2DEG*aijl, RAD2DEG*aijm);
636 gmx_fatal(FARGS, "invalid construction in calc_vsite4fd for atom %d: "
637 "cosakl=%f, cosakm=%f\n", param->ai()+1, cosakl, cosakm);
639 sinakl = std::sqrt(1-gmx::square(cosakl));
640 sinakm = std::sqrt(1-gmx::square(cosakm));
642 /* note: there is a '+' because of the way the sines are calculated */
643 cl = -pk / ( pl*cosakl - pk + pl*sinakl*(pm*cosakm-pk)/(pm*sinakm) );
644 cm = -pk / ( pm*cosakm - pk + pm*sinakm*(pl*cosakl-pk)/(pl*sinakl) );
646 param->setForceParameter(0, cl);
647 param->setForceParameter(1, cm);
648 param->setForceParameter(2, -bij);
656 calc_vsite4fdn_param(InteractionOfType *param,
657 int nrbond, t_mybonded *bonds,
658 int nrang, t_mybonded *angles)
660 /* i = virtual site | ,k
661 * j = 1st bonded heavy atom | i-j-m
662 * k,l,m = 2nd bonded atoms | `l
666 real bij, bjk, bjl, bjm, aijk, aijl, aijm;
667 real pk, pl, pm, a, b;
669 bij = get_bond_length(nrbond, bonds, param->ai(), param->aj());
670 bjk = get_bond_length(nrbond, bonds, param->aj(), param->ak());
671 bjl = get_bond_length(nrbond, bonds, param->aj(), param->al());
672 bjm = get_bond_length(nrbond, bonds, param->aj(), param->am());
673 aijk = get_angle (nrang, angles, param->ai(), param->aj(), param->ak());
674 aijl = get_angle (nrang, angles, param->ai(), param->aj(), param->al());
675 aijm = get_angle (nrang, angles, param->ai(), param->aj(), param->am());
677 bError = (bij == NOTSET) || (bjk == NOTSET) || (bjl == NOTSET) || (bjm == NOTSET) ||
678 (aijk == NOTSET) || (aijl == NOTSET) || (aijm == NOTSET);
683 /* Calculate component of bond j-k along the direction i-j */
684 pk = -bjk*std::cos(aijk);
686 /* Calculate component of bond j-l along the direction i-j */
687 pl = -bjl*std::cos(aijl);
689 /* Calculate component of bond j-m along the direction i-j */
690 pm = -bjm*std::cos(aijm);
692 if (fabs(pl) < 1000*GMX_REAL_MIN || fabs(pm) < 1000*GMX_REAL_MIN)
694 fprintf(stderr, "virtual site %d: angle ijk = %f, angle ijl = %f, angle ijm = %f\n",
695 param->ai()+1, RAD2DEG*aijk, RAD2DEG*aijl, RAD2DEG*aijm);
696 gmx_fatal(FARGS, "invalid construction in calc_vsite4fdn for atom %d: "
697 "pl=%f, pm=%f\n", param->ai()+1, pl, pm);
703 param->setForceParameter(0, a);
704 param->setForceParameter(1, b);
705 param->setForceParameter(2, bij);
713 int set_vsites(bool bVerbose, t_atoms *atoms, PreprocessingAtomTypes *atypes,
714 gmx::ArrayRef<InteractionsOfType> plist)
717 int nvsite, nrbond, nrang, nridih, nrset;
726 /* Make a reverse list to avoid ninteractions^2 operations */
727 std::vector<Atom2VsiteBond> at2vb = make_at2vsitebond(atoms->nr, plist);
729 for (ftype = 0; (ftype < F_NRE); ftype++)
731 if (interaction_function[ftype].flags & IF_VSITE)
733 nvsite += plist[ftype].size();
735 if (ftype == F_VSITEN)
737 /* We don't calculate parameters for VSITEN */
743 for (auto ¶m : plist[ftype].interactionTypes)
745 /* check if all parameters are set */
747 gmx::ArrayRef<const real> forceParam = param.forceParam();
748 for (int j = 0; (j < NRFP(ftype)) && bSet; j++)
750 bSet = forceParam[j] != NOTSET;
755 fprintf(debug, "bSet=%s ", gmx::boolToString(bSet));
756 printInteractionOfType(debug, ftype, i, plist[ftype].interactionTypes[i]);
760 if (bVerbose && bFirst)
762 fprintf(stderr, "Calculating parameters for virtual sites\n");
766 nrbond = nrang = nridih = 0;
771 /* now set the vsite parameters: */
772 get_bondeds(NRAL(ftype), param.atoms(), at2vb,
773 &nrbond, &bonds, &nrang, &angles, &nridih, &idihs);
776 fprintf(debug, "Found %d bonds, %d angles and %d idihs "
777 "for virtual site %d (%s)\n", nrbond, nrang, nridih,
779 interaction_function[ftype].longname);
780 print_bad(debug, nrbond, bonds, nrang, angles, nridih, idihs);
786 calc_vsite3_param(atypes, ¶m, atoms,
787 nrbond, bonds, nrang, angles);
791 calc_vsite3fd_param(¶m,
792 nrbond, bonds, nrang, angles);
796 calc_vsite3fad_param(¶m,
797 nrbond, bonds, nrang, angles);
801 calc_vsite3out_param(atypes, ¶m, atoms,
802 nrbond, bonds, nrang, angles);
806 calc_vsite4fd_param(¶m,
807 nrbond, bonds, nrang, angles);
811 calc_vsite4fdn_param(¶m,
812 nrbond, bonds, nrang, angles);
815 gmx_fatal(FARGS, "Automatic parameter generation not supported "
817 interaction_function[ftype].longname,
823 gmx_fatal(FARGS, "Automatic parameter generation not supported "
824 "for %s atom %d for this bonding configuration",
825 interaction_function[ftype].longname,
840 void set_vsites_ptype(bool bVerbose, gmx_moltype_t *molt)
846 fprintf(stderr, "Setting particle type to V for virtual sites\n");
848 for (ftype = 0; ftype < F_NRE; ftype++)
850 InteractionList *il = &molt->ilist[ftype];
851 if (interaction_function[ftype].flags & IF_VSITE)
853 const int nra = interaction_function[ftype].nratoms;
854 const int nrd = il->size();
855 gmx::ArrayRef<const int> ia = il->iatoms;
859 fprintf(stderr, "doing %d %s virtual sites\n",
860 (nrd / (nra+1)), interaction_function[ftype].longname);
863 for (i = 0; (i < nrd); )
865 /* The virtual site */
866 int avsite = ia[i + 1];
867 molt->atoms.atom[avsite].ptype = eptVSite;
877 * Convenience typedef for linking function type to parameter numbers.
879 * The entries in this datastructure are valid if the particle participates in
880 * a virtual site interaction and has a valid vsite function type other than VSITEN.
881 * \todo Change to remove empty constructor when gmx::compat::optional is available.
883 class VsiteAtomMapping
886 //! Only construct with all information in place or nothing
887 VsiteAtomMapping(int functionType, int interactionIndex)
888 : functionType_(functionType), interactionIndex_(interactionIndex)
891 : functionType_(-1), interactionIndex_(-1)
893 //! Get function type.
894 const int &functionType() const { return functionType_; }
895 //! Get parameter number.
896 const int &interactionIndex() const { return interactionIndex_; };
898 //! Function type for the linked parameter.
900 //! The linked parameter.
901 int interactionIndex_;
904 static void check_vsite_constraints(gmx::ArrayRef<InteractionsOfType> plist,
905 int cftype, const int vsite_type[])
908 for (const auto ¶m : plist[cftype].interactionTypes)
910 gmx::ArrayRef<const int> atoms = param.atoms();
911 for (int k = 0; k < 2; k++)
914 if (vsite_type[atom] != NOTSET)
916 fprintf(stderr, "ERROR: Cannot have constraint (%d-%d) with virtual site (%d)\n",
917 param.ai()+1, param.aj()+1, atom+1);
924 gmx_fatal(FARGS, "There were %d virtual sites involved in constraints", n);
928 static void clean_vsite_bonds(gmx::ArrayRef<InteractionsOfType> plist,
929 gmx::ArrayRef<const VsiteAtomMapping> pindex,
930 int cftype, const int vsite_type[])
933 int nconverted, nremoved;
935 bool bKeep, bRemove, bAllFD;
936 InteractionsOfType *ps;
938 if (cftype == F_CONNBONDS)
943 ps = &(plist[cftype]);
947 for (auto bond = ps->interactionTypes.begin(); bond != ps->interactionTypes.end(); )
950 const int *first_atoms = nullptr;
955 /* check if all virtual sites are constructed from the same atoms */
957 gmx::ArrayRef<const int> atoms = bond->atoms();
958 for (int k = 0; (k < 2) && !bKeep && !bRemove; k++)
960 /* for all atoms in the bond */
962 if (vsite_type[atom] != NOTSET && vsite_type[atom] != F_VSITEN)
965 bool bThisFD = ( (pindex[atom].functionType() == F_VSITE3FD ) ||
966 (pindex[atom].functionType() == F_VSITE3FAD) ||
967 (pindex[atom].functionType() == F_VSITE4FD ) ||
968 (pindex[atom].functionType() == F_VSITE4FDN ) );
969 bool bThisOUT = ( (pindex[atom].functionType() == F_VSITE3OUT) &&
970 ((interaction_function[cftype].flags & IF_CONSTRAINT) != 0u) );
971 bAllFD = bAllFD && bThisFD;
972 if (bThisFD || bThisOUT)
974 oatom = atoms[1-k]; /* the other atom */
975 if (vsite_type[oatom] == NOTSET &&
976 oatom == plist[pindex[atom].functionType()].interactionTypes[pindex[atom].interactionIndex()].aj())
978 /* if the other atom isn't a vsite, and it is AI */
988 /* TODO This fragment, and corresponding logic in
989 clean_vsite_angles and clean_vsite_dihs should
990 be refactored into a common function */
993 /* if this is the first vsite we encounter then
994 store construction atoms */
995 /* TODO This would be nicer to implement with
996 a C++ "vector view" class" with an
997 STL-container-like interface. */
998 vsnral = NRAL(pindex[atom].functionType()) - 1;
999 first_atoms = plist[pindex[atom].functionType()].interactionTypes[pindex[atom].interactionIndex()].atoms().data() + 1;
1003 GMX_ASSERT(vsnral != 0, "nvsite > 1 must have vsnral != 0");
1004 GMX_ASSERT(first_atoms != nullptr, "nvsite > 1 must have first_atoms != NULL");
1005 /* if it is not the first then
1006 check if this vsite is constructed from the same atoms */
1007 if (vsnral == NRAL(pindex[atom].functionType())-1)
1009 for (int m = 0; (m < vsnral) && !bKeep; m++)
1013 bool bPresent = false;
1014 atoms = plist[pindex[atom].functionType()].interactionTypes[pindex[atom].interactionIndex()].atoms().data() + 1;
1015 for (int n = 0; (n < vsnral) && !bPresent; n++)
1017 if (atoms[m] == first_atoms[n])
1043 /* if we have no virtual sites in this bond, keep it */
1049 /* TODO This loop and the corresponding loop in
1050 check_vsite_angles should be refactored into a common
1052 /* check if all non-vsite atoms are used in construction: */
1053 bool bFirstTwo = true;
1054 for (int k = 0; (k < 2) && !bKeep; k++) /* for all atoms in the bond */
1056 int atom = atoms[k];
1057 if (vsite_type[atom] == NOTSET)
1060 for (int m = 0; (m < vsnral) && !bUsed; m++)
1062 GMX_ASSERT(first_atoms != nullptr, "If we've seen a vsite before, we know what its first atom index was");
1064 if (atom == first_atoms[m])
1067 bFirstTwo = bFirstTwo && m < 2;
1077 if (!( bAllFD && bFirstTwo ) )
1079 /* Two atom bonded interactions include constraints.
1080 * We need to remove constraints between vsite pairs that have
1081 * a fixed distance due to being constructed from the same
1082 * atoms, since this can be numerically unstable.
1084 for (int m = 0; m < vsnral && !bKeep; m++) /* all constr. atoms */
1086 at1 = first_atoms[m];
1087 at2 = first_atoms[(m+1) % vsnral];
1088 bool bPresent = false;
1089 for (ftype = 0; ftype < F_NRE; ftype++)
1091 if (interaction_function[ftype].flags & IF_CONSTRAINT)
1093 for (auto entry = plist[ftype].interactionTypes.begin(); (entry != plist[ftype].interactionTypes.end()) && !bPresent; entry++)
1095 /* all constraints until one matches */
1096 bPresent = ( ( (entry->ai() == at1) &&
1097 (entry->aj() == at2) ) ||
1098 ( (entry->ai() == at2) &&
1099 (entry->aj() == at1) ) );
1115 else if (IS_CHEMBOND(cftype))
1117 plist[F_CONNBONDS].interactionTypes.emplace_back(*bond);
1118 bond = ps->interactionTypes.erase(bond);
1123 bond = ps->interactionTypes.erase(bond);
1130 fprintf(stderr, "Removed %4d %15ss with virtual sites, %zu left\n",
1131 nremoved, interaction_function[cftype].longname, ps->size());
1135 fprintf(stderr, "Converted %4d %15ss with virtual sites to connections, %zu left\n",
1136 nconverted, interaction_function[cftype].longname, ps->size());
1140 fprintf(stderr, "Warning: removed %d %ss with vsite with %s construction\n"
1141 " This vsite construction does not guarantee constant "
1143 " If the constructions were generated by pdb2gmx ignore "
1145 nOut, interaction_function[cftype].longname,
1146 interaction_function[F_VSITE3OUT].longname );
1150 static void clean_vsite_angles(gmx::ArrayRef<InteractionsOfType> plist,
1151 gmx::ArrayRef<VsiteAtomMapping> pindex,
1152 int cftype, const int vsite_type[],
1153 gmx::ArrayRef<const Atom2VsiteConnection> at2vc)
1156 InteractionsOfType *ps;
1158 ps = &(plist[cftype]);
1159 int oldSize = ps->size();
1160 for (auto angle = ps->interactionTypes.begin(); angle != ps->interactionTypes.end(); )
1163 const int *first_atoms = nullptr;
1166 bool bAll3FAD = true;
1167 /* check if all virtual sites are constructed from the same atoms */
1169 gmx::ArrayRef<const int> atoms = angle->atoms();
1170 for (int k = 0; (k < 3) && !bKeep; k++) /* for all atoms in the angle */
1172 int atom = atoms[k];
1173 if (vsite_type[atom] != NOTSET && vsite_type[atom] != F_VSITEN)
1176 bAll3FAD = bAll3FAD && (pindex[atom].functionType() == F_VSITE3FAD);
1179 /* store construction atoms of first vsite */
1180 vsnral = NRAL(pindex[atom].functionType()) - 1;
1181 first_atoms = plist[pindex[atom].functionType()].interactionTypes[pindex[atom].interactionIndex()].atoms().data() + 1;
1185 GMX_ASSERT(vsnral != 0, "If we've seen a vsite before, we know how many constructing atoms it had");
1186 GMX_ASSERT(first_atoms != nullptr, "If we've seen a vsite before, we know what its first atom index was");
1187 /* check if this vsite is constructed from the same atoms */
1188 if (vsnral == NRAL(pindex[atom].functionType())-1)
1190 for (int m = 0; (m < vsnral) && !bKeep; m++)
1192 const int *subAtoms;
1194 bool bPresent = false;
1195 subAtoms = plist[pindex[atom].functionType()].interactionTypes[pindex[atom].interactionIndex()].atoms().data() + 1;
1196 for (int n = 0; (n < vsnral) && !bPresent; n++)
1198 if (subAtoms[m] == first_atoms[n])
1217 /* keep all angles with no virtual sites in them or
1218 with virtual sites with more than 3 constr. atoms */
1219 if (nvsite == 0 && vsnral > 3)
1224 /* check if all non-vsite atoms are used in construction: */
1225 bool bFirstTwo = true;
1226 for (int k = 0; (k < 3) && !bKeep; k++) /* for all atoms in the angle */
1229 if (vsite_type[atom] == NOTSET)
1232 for (int m = 0; (m < vsnral) && !bUsed; m++)
1234 GMX_ASSERT(first_atoms != nullptr, "If we've seen a vsite before, we know what its first atom index was");
1236 if (atom == first_atoms[m])
1239 bFirstTwo = bFirstTwo && m < 2;
1249 if (!( bAll3FAD && bFirstTwo ) )
1251 /* check if all constructing atoms are constrained together */
1252 for (int m = 0; m < vsnral && !bKeep; m++) /* all constr. atoms */
1254 at1 = first_atoms[m];
1255 at2 = first_atoms[(m+1) % vsnral];
1256 bool bPresent = false;
1257 auto found = std::find(at2vc[at1].begin(), at2vc[at1].end(), at2);
1258 if (found != at2vc[at1].end())
1275 angle = ps->interactionTypes.erase(angle);
1279 if (oldSize != gmx::ssize(*ps))
1281 fprintf(stderr, "Removed %4zu %15ss with virtual sites, %zu left\n",
1282 oldSize-ps->size(), interaction_function[cftype].longname, ps->size());
1286 static void clean_vsite_dihs(gmx::ArrayRef<InteractionsOfType> plist,
1287 gmx::ArrayRef<const VsiteAtomMapping> pindex,
1288 int cftype, const int vsite_type[])
1290 InteractionsOfType *ps;
1292 ps = &(plist[cftype]);
1294 int oldSize = ps->size();
1295 for (auto dih = ps->interactionTypes.begin(); dih != ps->interactionTypes.end(); )
1298 const int *first_atoms = nullptr;
1301 gmx::ArrayRef<const int> atoms = dih->atoms();
1303 /* check if all virtual sites are constructed from the same atoms */
1305 for (int k = 0; (k < 4) && !bKeep; k++) /* for all atoms in the dihedral */
1308 if (vsite_type[atom] != NOTSET && vsite_type[atom] != F_VSITEN)
1312 /* store construction atoms of first vsite */
1313 vsnral = NRAL(pindex[atom].functionType()) - 1;
1314 first_atoms = plist[pindex[atom].functionType()].interactionTypes[pindex[atom].interactionIndex()].atoms().data() + 1;
1318 GMX_ASSERT(vsnral != 0, "If we've seen a vsite before, we know how many constructing atoms it had");
1319 GMX_ASSERT(first_atoms != nullptr, "If we've seen a vsite before, we know what its first atom index was");
1320 /* check if this vsite is constructed from the same atoms */
1321 if (vsnral == NRAL(pindex[atom].functionType())-1)
1323 for (int m = 0; (m < vsnral) && !bKeep; m++)
1325 const int *subAtoms;
1327 bool bPresent = false;
1328 subAtoms = plist[pindex[atom].functionType()].interactionTypes[pindex[atom].interactionIndex()].atoms().data() + 1;
1329 for (int n = 0; (n < vsnral) && !bPresent; n++)
1331 if (subAtoms[m] == first_atoms[n])
1343 /* TODO clean_site_bonds and _angles do this increment
1344 at the top of the loop. Refactor this for
1350 /* keep all dihedrals with no virtual sites in them */
1356 /* check if all atoms in dihedral are either virtual sites, or used in
1357 construction of virtual sites. If so, keep it, if not throw away: */
1358 for (int k = 0; (k < 4) && !bKeep; k++) /* for all atoms in the dihedral */
1360 GMX_ASSERT(vsnral != 0, "If we've seen a vsite before, we know how many constructing atoms it had");
1361 GMX_ASSERT(first_atoms != nullptr, "If we've seen a vsite before, we know what its first atom index was");
1363 if (vsite_type[atom] == NOTSET)
1365 /* vsnral will be set here, we don't get here with nvsite==0 */
1367 for (int m = 0; (m < vsnral) && !bUsed; m++)
1369 if (atom == first_atoms[m])
1387 dih = ps->interactionTypes.erase(dih);
1392 if (oldSize != gmx::ssize(*ps))
1394 fprintf(stderr, "Removed %4zu %15ss with virtual sites, %zu left\n",
1395 oldSize-ps->size(), interaction_function[cftype].longname, ps->size());
1399 // TODO use gmx::compat::optional for pindex.
1400 void clean_vsite_bondeds(gmx::ArrayRef<InteractionsOfType> plist, int natoms, bool bRmVSiteBds)
1404 std::vector<VsiteAtomMapping> pindex;
1405 std::vector<Atom2VsiteConnection> at2vc;
1407 /* make vsite_type array */
1408 snew(vsite_type, natoms);
1409 for (int i = 0; i < natoms; i++)
1411 vsite_type[i] = NOTSET;
1414 for (int ftype = 0; ftype < F_NRE; ftype++)
1416 if (interaction_function[ftype].flags & IF_VSITE)
1418 nvsite += plist[ftype].size();
1420 while (i < gmx::ssize(plist[ftype]))
1422 vsite = plist[ftype].interactionTypes[i].ai();
1423 if (vsite_type[vsite] == NOTSET)
1425 vsite_type[vsite] = ftype;
1429 gmx_fatal(FARGS, "multiple vsite constructions for atom %d", vsite+1);
1431 if (ftype == F_VSITEN)
1433 while (i < gmx::ssize(plist[ftype]) && plist[ftype].interactionTypes[i].ai() == vsite)
1446 /* the rest only if we have virtual sites: */
1449 fprintf(stderr, "Cleaning up constraints %swith virtual sites\n",
1450 bRmVSiteBds ? "and constant bonded interactions " : "");
1452 /* Make a reverse list to avoid ninteractions^2 operations */
1453 at2vc = make_at2vsitecon(natoms, plist);
1455 pindex.resize(natoms);
1456 for (int ftype = 0; ftype < F_NRE; ftype++)
1458 /* Here we skip VSITEN. In neary all practical use cases this
1459 * is not an issue, since VSITEN is intended for constructing
1460 * additional interaction sites, not for replacing normal atoms
1461 * with bonded interactions. Thus we do not expect constant
1462 * bonded interactions. If VSITEN does get used with constant
1463 * bonded interactions, these are not removed which only leads
1464 * to very minor extra computation and constant energy.
1465 * The only problematic case is onstraints between VSITEN
1466 * constructions with fixed distance (which is anyhow useless).
1467 * This will generate a fatal error in check_vsite_constraints.
1469 if ((interaction_function[ftype].flags & IF_VSITE) &&
1472 for (int interactionIndex = 0;
1473 interactionIndex < gmx::ssize(plist[ftype]);
1476 int k = plist[ftype].interactionTypes[interactionIndex].ai();
1477 pindex[k] = VsiteAtomMapping(ftype, interactionIndex);
1482 /* remove interactions that include virtual sites */
1483 for (int ftype = 0; ftype < F_NRE; ftype++)
1485 if ( ( ( interaction_function[ftype].flags & IF_BOND ) && bRmVSiteBds ) ||
1486 ( interaction_function[ftype].flags & IF_CONSTRAINT ) )
1488 if (interaction_function[ftype].flags & (IF_BTYPE | IF_CONSTRAINT) )
1490 clean_vsite_bonds (plist, pindex, ftype, vsite_type);
1492 else if (interaction_function[ftype].flags & IF_ATYPE)
1494 clean_vsite_angles(plist, pindex, ftype, vsite_type, at2vc);
1496 else if ( (ftype == F_PDIHS) || (ftype == F_IDIHS) )
1498 clean_vsite_dihs (plist, pindex, ftype, vsite_type);
1502 /* check that no remaining constraints include virtual sites */
1503 for (int ftype = 0; ftype < F_NRE; ftype++)
1505 if (interaction_function[ftype].flags & IF_CONSTRAINT)
1507 check_vsite_constraints(plist, ftype, vsite_type);