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"
69 * Data type to store information about bonded interactions for virtual sites.
71 class VsiteBondedInteraction
74 //! Constructor initializes datastructure.
75 VsiteBondedInteraction(gmx::ArrayRef
<const int> atomIndex
,
77 : parameterValue_(parameterValue
)
79 GMX_RELEASE_ASSERT(atomIndex
.size() <= atomIndex_
.size(),
80 "Cannot add more atom indices than maximum number");
81 auto atomIndexIt
= atomIndex_
.begin();
82 for (const auto index
: atomIndex
)
84 *atomIndexIt
++ = index
;
88 //! Access the individual elements set for the vsite bonded interaction.
89 const int &ai() const { return atomIndex_
[0]; }
90 const int &aj() const { return atomIndex_
[1]; }
91 const int &ak() const { return atomIndex_
[2]; }
92 const int &al() const { return atomIndex_
[3]; }
94 const real
¶meterValue() const { return parameterValue_
; }
98 //! The distance value for this bonded interaction.
100 //! Array of atom indices
101 std::array
<int, 4> atomIndex_
;
105 * Stores information about single virtual site bonded parameter.
107 struct VsiteBondParameter
109 //! Constructor initializes datastructure.
110 VsiteBondParameter(int ftype
, const InteractionOfType
&vsiteInteraction
)
111 : ftype_(ftype
), vsiteInteraction_(vsiteInteraction
)
113 //! Function type for virtual site.
116 * Interaction type data.
118 * The datastructure should never be used in a case where the InteractionType
119 * used to construct it might go out of scope before this object, as it would cause
120 * the reference to type_ to dangle.
122 const InteractionOfType
&vsiteInteraction_
;
126 * Helper type for conversion of bonded parameters to virtual sites.
128 struct Atom2VsiteBond
130 //! Function type for conversion.
132 //! The vsite parameters in a list.
133 std::vector
<VsiteBondParameter
> vSiteBondedParameters
;
136 //! Convenience type def for virtual site connections.
137 using Atom2VsiteConnection
= std::vector
<int>;
139 static int vsite_bond_nrcheck(int ftype
)
143 if ((interaction_function
[ftype
].flags
& (IF_BTYPE
| IF_CONSTRAINT
| IF_ATYPE
)) || (ftype
== F_IDIHS
))
145 nrcheck
= NRAL(ftype
);
155 static void enter_bonded(int nratoms
, std::vector
<VsiteBondedInteraction
> *bondeds
,
156 const InteractionOfType
&type
)
158 GMX_RELEASE_ASSERT(nratoms
== type
.atoms().ssize(), "Size of atom array must match");
159 bondeds
->emplace_back(VsiteBondedInteraction(type
.atoms(), type
.c0()));
163 * Wraps the datastructures for the different vsite bondeds.
165 struct AllVsiteBondedInteractions
168 std::vector
<VsiteBondedInteraction
> bonds
;
170 std::vector
<VsiteBondedInteraction
> angles
;
172 std::vector
<VsiteBondedInteraction
> dihedrals
;
175 static AllVsiteBondedInteractions
176 createVsiteBondedInformation(int nrat
,
177 gmx::ArrayRef
<const int> atoms
,
178 gmx::ArrayRef
<const Atom2VsiteBond
> at2vb
)
180 AllVsiteBondedInteractions allVsiteBondeds
;
181 for (int k
= 0; k
< nrat
; k
++)
183 for (auto &vsite
: at2vb
[atoms
[k
]].vSiteBondedParameters
)
185 int ftype
= vsite
.ftype_
;
186 const InteractionOfType
&type
= vsite
.vsiteInteraction_
;
187 int nrcheck
= vsite_bond_nrcheck(ftype
);
188 /* abuse nrcheck to see if we're adding bond, angle or idih */
191 case 2: enter_bonded(nrcheck
, &allVsiteBondeds
.bonds
, type
); break;
192 case 3: enter_bonded(nrcheck
, &allVsiteBondeds
.angles
, type
); break;
193 case 4: enter_bonded(nrcheck
, &allVsiteBondeds
.dihedrals
, type
); break;
197 return allVsiteBondeds
;
200 static std::vector
<Atom2VsiteBond
>
201 make_at2vsitebond(int natoms
, gmx::ArrayRef
<InteractionsOfType
> plist
)
205 std::vector
<Atom2VsiteBond
> at2vb(natoms
);
208 for (int ftype
= 0; (ftype
< F_NRE
); ftype
++)
210 if ((interaction_function
[ftype
].flags
& IF_VSITE
) && ftype
!= F_VSITEN
)
212 for (int i
= 0; (i
< gmx::ssize(plist
[ftype
])); i
++)
214 gmx::ArrayRef
<const int> atoms
= plist
[ftype
].interactionTypes
[i
].atoms();
215 for (int j
= 0; j
< NRAL(ftype
); j
++)
217 bVSI
[atoms
[j
]] = TRUE
;
223 for (int ftype
= 0; (ftype
< F_NRE
); ftype
++)
225 int nrcheck
= vsite_bond_nrcheck(ftype
);
228 for (int i
= 0; (i
< gmx::ssize(plist
[ftype
])); i
++)
230 gmx::ArrayRef
<const int> aa
= plist
[ftype
].interactionTypes
[i
].atoms();
231 for (int j
= 0; j
< nrcheck
; j
++)
235 at2vb
[aa
[j
]].vSiteBondedParameters
.emplace_back(ftype
, plist
[ftype
].interactionTypes
[i
]);
246 static std::vector
<Atom2VsiteConnection
>
247 make_at2vsitecon(int natoms
, gmx::ArrayRef
<InteractionsOfType
> plist
)
249 std::vector
<bool> bVSI(natoms
);
250 std::vector
<Atom2VsiteConnection
> at2vc(natoms
);
252 for (int ftype
= 0; (ftype
< F_NRE
); ftype
++)
254 if ((interaction_function
[ftype
].flags
& IF_VSITE
) && ftype
!= F_VSITEN
)
256 for (int i
= 0; (i
< gmx::ssize(plist
[ftype
])); i
++)
258 gmx::ArrayRef
<const int> atoms
= plist
[ftype
].interactionTypes
[i
].atoms();
259 for (int j
= 0; j
< NRAL(ftype
); j
++)
261 bVSI
[atoms
[j
]] = TRUE
;
267 for (int ftype
= 0; (ftype
< F_NRE
); ftype
++)
269 if (interaction_function
[ftype
].flags
& IF_CONSTRAINT
)
271 for (int i
= 0; (i
< gmx::ssize(plist
[ftype
])); i
++)
273 int ai
= plist
[ftype
].interactionTypes
[i
].ai();
274 int aj
= plist
[ftype
].interactionTypes
[i
].aj();
275 if (bVSI
[ai
] && bVSI
[aj
])
277 /* Store forward direction */
278 at2vc
[ai
].emplace_back(aj
);
279 /* Store backward direction */
280 at2vc
[aj
].emplace_back(ai
);
289 static void print_bad(FILE *fp
,
290 gmx::ArrayRef
<const VsiteBondedInteraction
> bonds
,
291 gmx::ArrayRef
<const VsiteBondedInteraction
> angles
,
292 gmx::ArrayRef
<const VsiteBondedInteraction
> idihs
)
296 fprintf(fp
, "bonds:");
297 for (const auto &bond
: bonds
)
299 fprintf(fp
, " %d-%d (%g)",
300 bond
.ai()+1, bond
.aj()+1, bond
.parameterValue());
306 fprintf(fp
, "angles:");
307 for (const auto &angle
: angles
)
309 fprintf(fp
, " %d-%d-%d (%g)",
310 angle
.ai()+1, angle
.aj()+1,
311 angle
.ak()+1, angle
.parameterValue());
317 fprintf(fp
, "idihs:");
318 for (const auto &idih
: idihs
)
320 fprintf(fp
, " %d-%d-%d-%d (%g)",
321 idih
.ai()+1, idih
.aj()+1,
322 idih
.ak()+1, idih
.al()+1, idih
.parameterValue());
328 static void printInteractionOfType(FILE *fp
, int ftype
, int i
, const InteractionOfType
&type
)
331 static int prev_ftype
= NOTSET
;
332 static int prev_i
= NOTSET
;
334 if ( (ftype
!= prev_ftype
) || (i
!= prev_i
) )
340 fprintf(fp
, "(%d) plist[%s].param[%d]",
341 pass
, interaction_function
[ftype
].name
, i
);
342 gmx::ArrayRef
<const real
> forceParam
= type
.forceParam();
343 for (int j
= 0; j
< NRFP(ftype
); j
++)
345 fprintf(fp
, ".c[%d]=%g ", j
, forceParam
[j
]);
351 static real
get_bond_length(gmx::ArrayRef
<const VsiteBondedInteraction
> bonds
,
352 t_iatom ai
, t_iatom aj
)
357 for (const auto &bond
: bonds
)
359 /* check both ways */
360 if ( ( (ai
== bond
.ai()) && (aj
== bond
.aj()) ) ||
361 ( (ai
== bond
.aj()) && (aj
== bond
.ai()) ) )
363 bondlen
= bond
.parameterValue(); /* note: parameterValue might be NOTSET */
370 static real
get_angle(gmx::ArrayRef
<const VsiteBondedInteraction
> angles
,
371 t_iatom ai
, t_iatom aj
, t_iatom ak
)
376 for (const auto &ang
: angles
)
378 /* check both ways */
379 if ( ( (ai
== ang
.ai()) && (aj
== ang
.aj()) && (ak
== ang
.ak()) ) ||
380 ( (ai
== ang
.ak()) && (aj
== ang
.aj()) && (ak
== ang
.ai()) ) )
382 angle
= DEG2RAD
*ang
.parameterValue();
389 static const char *get_atomtype_name_AB(t_atom
*atom
, PreprocessingAtomTypes
*atypes
)
391 const char* name
= atypes
->atomNameFromAtomType(atom
->type
);
393 /* When using the decoupling option, atom types are changed
394 * to decoupled for the non-bonded interactions, but the virtual
395 * sites constructions should be based on the "normal" interactions.
396 * So we return the state B atom type name if the state A atom
397 * type is the decoupled one. We should actually check for the atom
398 * type number, but that's not passed here. So we check for
399 * the decoupled atom type name. This should not cause trouble
400 * as this code is only used for topologies with v-sites without
401 * parameters generated by pdb2gmx.
403 if (strcmp(name
, "decoupled") == 0)
405 name
= atypes
->atomNameFromAtomType(atom
->typeB
);
411 static bool calc_vsite3_param(PreprocessingAtomTypes
*atypes
,
412 InteractionOfType
*vsite
, t_atoms
*at
,
413 gmx::ArrayRef
<const VsiteBondedInteraction
> bonds
,
414 gmx::ArrayRef
<const VsiteBondedInteraction
> angles
)
416 /* i = virtual site | ,k
417 * j = 1st bonded heavy atom | i-j
418 * k,l = 2nd bonded atoms | `l
422 real bjk
, bjl
, a
= -1, b
= -1;
423 /* check if this is part of a NH3 , NH2-umbrella or CH3 group,
424 * i.e. if atom k and l are dummy masses (MNH* or MCH3*) */
426 ( (gmx::equalCaseInsensitive(get_atomtype_name_AB(&at
->atom
[vsite
->ak()], atypes
), "MNH", 3)) &&
427 (gmx::equalCaseInsensitive(get_atomtype_name_AB(&at
->atom
[vsite
->al()], atypes
), "MNH", 3)) ) ||
428 ( (gmx::equalCaseInsensitive(get_atomtype_name_AB(&at
->atom
[vsite
->ak()], atypes
), "MCH3", 4)) &&
429 (gmx::equalCaseInsensitive(get_atomtype_name_AB(&at
->atom
[vsite
->al()], atypes
), "MCH3", 4)) );
431 bjk
= get_bond_length(bonds
, vsite
->aj(), vsite
->ak());
432 bjl
= get_bond_length(bonds
, vsite
->aj(), vsite
->al());
433 bError
= (bjk
== NOTSET
) || (bjl
== NOTSET
);
436 /* now we get some XH2/XH3 group specific construction */
437 /* note: we call the heavy atom 'C' and the X atom 'N' */
438 real bMM
, bCM
, bCN
, bNH
, aCNH
, dH
, rH
, dM
, rM
;
441 /* check if bonds from heavy atom (j) to dummy masses (k,l) are equal: */
442 bError
= bError
|| (bjk
!= bjl
);
444 /* the X atom (C or N) in the XH2/XH3 group is the first after the masses: */
445 aN
= std::max(vsite
->ak(), vsite
->al())+1;
447 /* get common bonds */
448 bMM
= get_bond_length(bonds
, vsite
->ak(), vsite
->al());
450 bCN
= get_bond_length(bonds
, vsite
->aj(), aN
);
451 bError
= bError
|| (bMM
== NOTSET
) || (bCN
== NOTSET
);
453 /* calculate common things */
455 dM
= std::sqrt( gmx::square(bCM
) - gmx::square(rM
) );
457 /* are we dealing with the X atom? */
458 if (vsite
->ai() == aN
)
460 /* this is trivial */
461 a
= b
= 0.5 * bCN
/dM
;
466 /* get other bondlengths and angles: */
467 bNH
= get_bond_length(bonds
, aN
, vsite
->ai());
468 aCNH
= get_angle (angles
, vsite
->aj(), aN
, vsite
->ai());
469 bError
= bError
|| (bNH
== NOTSET
) || (aCNH
== NOTSET
);
472 dH
= bCN
- bNH
* std::cos(aCNH
);
473 rH
= bNH
* std::sin(aCNH
);
475 a
= 0.5 * ( dH
/dM
+ rH
/rM
);
476 b
= 0.5 * ( dH
/dM
- rH
/rM
);
481 gmx_fatal(FARGS
, "calc_vsite3_param not implemented for the general case "
482 "(atom %d)", vsite
->ai()+1);
484 vsite
->setForceParameter(0, a
);
485 vsite
->setForceParameter(1, b
);
490 static bool calc_vsite3fd_param(InteractionOfType
*vsite
,
491 gmx::ArrayRef
<const VsiteBondedInteraction
> bonds
,
492 gmx::ArrayRef
<const VsiteBondedInteraction
> angles
)
494 /* i = virtual site | ,k
495 * j = 1st bonded heavy atom | i-j
496 * k,l = 2nd bonded atoms | `l
500 real bij
, bjk
, bjl
, aijk
, aijl
, rk
, rl
;
502 bij
= get_bond_length(bonds
, vsite
->ai(), vsite
->aj());
503 bjk
= get_bond_length(bonds
, vsite
->aj(), vsite
->ak());
504 bjl
= get_bond_length(bonds
, vsite
->aj(), vsite
->al());
505 aijk
= get_angle (angles
, vsite
->ai(), vsite
->aj(), vsite
->ak());
506 aijl
= get_angle (angles
, vsite
->ai(), vsite
->aj(), vsite
->al());
507 bError
= (bij
== NOTSET
) || (bjk
== NOTSET
) || (bjl
== NOTSET
) ||
508 (aijk
== NOTSET
) || (aijl
== NOTSET
);
510 rk
= bjk
* std::sin(aijk
);
511 rl
= bjl
* std::sin(aijl
);
512 vsite
->setForceParameter(0, rk
/ (rk
+ rl
));
513 vsite
->setForceParameter(1, -bij
);
518 static bool calc_vsite3fad_param(InteractionOfType
*vsite
,
519 gmx::ArrayRef
<const VsiteBondedInteraction
> bonds
,
520 gmx::ArrayRef
<const VsiteBondedInteraction
> angles
)
522 /* i = virtual site |
523 * j = 1st bonded heavy atom | i-j
524 * k = 2nd bonded heavy atom | `k-l
525 * l = 3d bonded heavy atom |
528 bool bSwapParity
, bError
;
531 bSwapParity
= ( vsite
->c1() == -1 );
533 bij
= get_bond_length(bonds
, vsite
->ai(), vsite
->aj());
534 aijk
= get_angle (angles
, vsite
->ai(), vsite
->aj(), vsite
->ak());
535 bError
= (bij
== NOTSET
) || (aijk
== NOTSET
);
537 vsite
->setForceParameter(1, bij
);
538 vsite
->setForceParameter(0, RAD2DEG
*aijk
);
542 vsite
->setForceParameter(0, 360 - vsite
->c0());
548 static bool calc_vsite3out_param(PreprocessingAtomTypes
*atypes
,
549 InteractionOfType
*vsite
, t_atoms
*at
,
550 gmx::ArrayRef
<const VsiteBondedInteraction
> bonds
,
551 gmx::ArrayRef
<const VsiteBondedInteraction
> angles
)
553 /* i = virtual site | ,k
554 * j = 1st bonded heavy atom | i-j
555 * k,l = 2nd bonded atoms | `l
556 * NOTE: i is out of the j-k-l plane!
559 bool bXH3
, bError
, bSwapParity
;
560 real bij
, bjk
, bjl
, aijk
, aijl
, akjl
, pijk
, pijl
, a
, b
, c
;
562 /* check if this is part of a NH2-umbrella, NH3 or CH3 group,
563 * i.e. if atom k and l are dummy masses (MNH* or MCH3*) */
565 ( (gmx::equalCaseInsensitive(get_atomtype_name_AB(&at
->atom
[vsite
->ak()], atypes
), "MNH", 3)) &&
566 (gmx::equalCaseInsensitive(get_atomtype_name_AB(&at
->atom
[vsite
->al()], atypes
), "MNH", 3)) ) ||
567 ( (gmx::equalCaseInsensitive(get_atomtype_name_AB(&at
->atom
[vsite
->ak()], atypes
), "MCH3", 4)) &&
568 (gmx::equalCaseInsensitive(get_atomtype_name_AB(&at
->atom
[vsite
->al()], atypes
), "MCH3", 4)) );
570 /* check if construction parity must be swapped */
571 bSwapParity
= ( vsite
->c1() == -1 );
573 bjk
= get_bond_length(bonds
, vsite
->aj(), vsite
->ak());
574 bjl
= get_bond_length(bonds
, vsite
->aj(), vsite
->al());
575 bError
= (bjk
== NOTSET
) || (bjl
== NOTSET
);
578 /* now we get some XH3 group specific construction */
579 /* note: we call the heavy atom 'C' and the X atom 'N' */
580 real bMM
, bCM
, bCN
, bNH
, aCNH
, dH
, rH
, rHx
, rHy
, dM
, rM
;
583 /* check if bonds from heavy atom (j) to dummy masses (k,l) are equal: */
584 bError
= bError
|| (bjk
!= bjl
);
586 /* the X atom (C or N) in the XH3 group is the first after the masses: */
587 aN
= std::max(vsite
->ak(), vsite
->al())+1;
589 /* get all bondlengths and angles: */
590 bMM
= get_bond_length(bonds
, vsite
->ak(), vsite
->al());
592 bCN
= get_bond_length(bonds
, vsite
->aj(), aN
);
593 bNH
= get_bond_length(bonds
, aN
, vsite
->ai());
594 aCNH
= get_angle (angles
, vsite
->aj(), aN
, vsite
->ai());
596 (bMM
== NOTSET
) || (bCN
== NOTSET
) || (bNH
== NOTSET
) || (aCNH
== NOTSET
);
599 dH
= bCN
- bNH
* std::cos(aCNH
);
600 rH
= bNH
* std::sin(aCNH
);
601 /* we assume the H's are symmetrically distributed */
602 rHx
= rH
*std::cos(DEG2RAD
*30);
603 rHy
= rH
*std::sin(DEG2RAD
*30);
605 dM
= std::sqrt( gmx::square(bCM
) - gmx::square(rM
) );
606 a
= 0.5*( (dH
/dM
) - (rHy
/rM
) );
607 b
= 0.5*( (dH
/dM
) + (rHy
/rM
) );
613 /* this is the general construction */
615 bij
= get_bond_length(bonds
, vsite
->ai(), vsite
->aj());
616 aijk
= get_angle (angles
, vsite
->ai(), vsite
->aj(), vsite
->ak());
617 aijl
= get_angle (angles
, vsite
->ai(), vsite
->aj(), vsite
->al());
618 akjl
= get_angle (angles
, vsite
->ak(), vsite
->aj(), vsite
->al());
620 (bij
== NOTSET
) || (aijk
== NOTSET
) || (aijl
== NOTSET
) || (akjl
== NOTSET
);
622 pijk
= std::cos(aijk
)*bij
;
623 pijl
= std::cos(aijl
)*bij
;
624 a
= ( pijk
+ (pijk
*std::cos(akjl
)-pijl
) * std::cos(akjl
) / gmx::square(std::sin(akjl
)) ) / bjk
;
625 b
= ( pijl
+ (pijl
*std::cos(akjl
)-pijk
) * std::cos(akjl
) / gmx::square(std::sin(akjl
)) ) / bjl
;
626 c
= -std::sqrt( gmx::square(bij
) -
627 ( gmx::square(pijk
) - 2*pijk
*pijl
*std::cos(akjl
) + gmx::square(pijl
) )
628 / gmx::square(std::sin(akjl
)) )
629 / ( bjk
*bjl
*std::sin(akjl
) );
632 vsite
->setForceParameter(0, a
);
633 vsite
->setForceParameter(1, b
);
636 vsite
->setForceParameter(2, -c
);
640 vsite
->setForceParameter(2, c
);
645 static bool calc_vsite4fd_param(InteractionOfType
*vsite
,
646 gmx::ArrayRef
<const VsiteBondedInteraction
> bonds
,
647 gmx::ArrayRef
<const VsiteBondedInteraction
> angles
)
649 /* i = virtual site | ,k
650 * j = 1st bonded heavy atom | i-j-m
651 * k,l,m = 2nd bonded atoms | `l
655 real bij
, bjk
, bjl
, bjm
, aijk
, aijl
, aijm
, akjm
, akjl
;
656 real pk
, pl
, pm
, cosakl
, cosakm
, sinakl
, sinakm
, cl
, cm
;
658 bij
= get_bond_length(bonds
, vsite
->ai(), vsite
->aj());
659 bjk
= get_bond_length(bonds
, vsite
->aj(), vsite
->ak());
660 bjl
= get_bond_length(bonds
, vsite
->aj(), vsite
->al());
661 bjm
= get_bond_length(bonds
, vsite
->aj(), vsite
->am());
662 aijk
= get_angle (angles
, vsite
->ai(), vsite
->aj(), vsite
->ak());
663 aijl
= get_angle (angles
, vsite
->ai(), vsite
->aj(), vsite
->al());
664 aijm
= get_angle (angles
, vsite
->ai(), vsite
->aj(), vsite
->am());
665 akjm
= get_angle (angles
, vsite
->ak(), vsite
->aj(), vsite
->am());
666 akjl
= get_angle (angles
, vsite
->ak(), vsite
->aj(), vsite
->al());
667 bError
= (bij
== NOTSET
) || (bjk
== NOTSET
) || (bjl
== NOTSET
) || (bjm
== NOTSET
) ||
668 (aijk
== NOTSET
) || (aijl
== NOTSET
) || (aijm
== NOTSET
) || (akjm
== NOTSET
) ||
673 pk
= bjk
*std::sin(aijk
);
674 pl
= bjl
*std::sin(aijl
);
675 pm
= bjm
*std::sin(aijm
);
676 cosakl
= (std::cos(akjl
) - std::cos(aijk
)*std::cos(aijl
)) / (std::sin(aijk
)*std::sin(aijl
));
677 cosakm
= (std::cos(akjm
) - std::cos(aijk
)*std::cos(aijm
)) / (std::sin(aijk
)*std::sin(aijm
));
678 if (cosakl
< -1 || cosakl
> 1 || cosakm
< -1 || cosakm
> 1)
680 fprintf(stderr
, "virtual site %d: angle ijk = %f, angle ijl = %f, angle ijm = %f\n",
681 vsite
->ai()+1, RAD2DEG
*aijk
, RAD2DEG
*aijl
, RAD2DEG
*aijm
);
682 gmx_fatal(FARGS
, "invalid construction in calc_vsite4fd for atom %d: "
683 "cosakl=%f, cosakm=%f\n", vsite
->ai()+1, cosakl
, cosakm
);
685 sinakl
= std::sqrt(1-gmx::square(cosakl
));
686 sinakm
= std::sqrt(1-gmx::square(cosakm
));
688 /* note: there is a '+' because of the way the sines are calculated */
689 cl
= -pk
/ ( pl
*cosakl
- pk
+ pl
*sinakl
*(pm
*cosakm
-pk
)/(pm
*sinakm
) );
690 cm
= -pk
/ ( pm
*cosakm
- pk
+ pm
*sinakm
*(pl
*cosakl
-pk
)/(pl
*sinakl
) );
692 vsite
->setForceParameter(0, cl
);
693 vsite
->setForceParameter(1, cm
);
694 vsite
->setForceParameter(2, -bij
);
702 calc_vsite4fdn_param(InteractionOfType
*vsite
,
703 gmx::ArrayRef
<const VsiteBondedInteraction
> bonds
,
704 gmx::ArrayRef
<const VsiteBondedInteraction
> angles
)
706 /* i = virtual site | ,k
707 * j = 1st bonded heavy atom | i-j-m
708 * k,l,m = 2nd bonded atoms | `l
712 real bij
, bjk
, bjl
, bjm
, aijk
, aijl
, aijm
;
713 real pk
, pl
, pm
, a
, b
;
715 bij
= get_bond_length(bonds
, vsite
->ai(), vsite
->aj());
716 bjk
= get_bond_length(bonds
, vsite
->aj(), vsite
->ak());
717 bjl
= get_bond_length(bonds
, vsite
->aj(), vsite
->al());
718 bjm
= get_bond_length(bonds
, vsite
->aj(), vsite
->am());
719 aijk
= get_angle (angles
, vsite
->ai(), vsite
->aj(), vsite
->ak());
720 aijl
= get_angle (angles
, vsite
->ai(), vsite
->aj(), vsite
->al());
721 aijm
= get_angle (angles
, vsite
->ai(), vsite
->aj(), vsite
->am());
723 bError
= (bij
== NOTSET
) || (bjk
== NOTSET
) || (bjl
== NOTSET
) || (bjm
== NOTSET
) ||
724 (aijk
== NOTSET
) || (aijl
== NOTSET
) || (aijm
== NOTSET
);
729 /* Calculate component of bond j-k along the direction i-j */
730 pk
= -bjk
*std::cos(aijk
);
732 /* Calculate component of bond j-l along the direction i-j */
733 pl
= -bjl
*std::cos(aijl
);
735 /* Calculate component of bond j-m along the direction i-j */
736 pm
= -bjm
*std::cos(aijm
);
738 if (fabs(pl
) < 1000*GMX_REAL_MIN
|| fabs(pm
) < 1000*GMX_REAL_MIN
)
740 fprintf(stderr
, "virtual site %d: angle ijk = %f, angle ijl = %f, angle ijm = %f\n",
741 vsite
->ai()+1, RAD2DEG
*aijk
, RAD2DEG
*aijl
, RAD2DEG
*aijm
);
742 gmx_fatal(FARGS
, "invalid construction in calc_vsite4fdn for atom %d: "
743 "pl=%f, pm=%f\n", vsite
->ai()+1, pl
, pm
);
749 vsite
->setForceParameter(0, a
);
750 vsite
->setForceParameter(1, b
);
751 vsite
->setForceParameter(2, bij
);
759 int set_vsites(bool bVerbose
, t_atoms
*atoms
, PreprocessingAtomTypes
*atypes
,
760 gmx::ArrayRef
<InteractionsOfType
> plist
)
769 /* Make a reverse list to avoid ninteractions^2 operations */
770 std::vector
<Atom2VsiteBond
> at2vb
= make_at2vsitebond(atoms
->nr
, plist
);
772 for (ftype
= 0; (ftype
< F_NRE
); ftype
++)
774 if (interaction_function
[ftype
].flags
& IF_VSITE
)
776 nvsite
+= plist
[ftype
].size();
778 if (ftype
== F_VSITEN
)
780 /* We don't calculate parameters for VSITEN */
786 for (auto ¶m
: plist
[ftype
].interactionTypes
)
788 /* check if all parameters are set */
790 gmx::ArrayRef
<const real
> forceParam
= param
.forceParam();
791 for (int j
= 0; (j
< NRFP(ftype
)) && bSet
; j
++)
793 bSet
= forceParam
[j
] != NOTSET
;
798 fprintf(debug
, "bSet=%s ", gmx::boolToString(bSet
));
799 printInteractionOfType(debug
, ftype
, i
, plist
[ftype
].interactionTypes
[i
]);
803 if (bVerbose
&& bFirst
)
805 fprintf(stderr
, "Calculating parameters for virtual sites\n");
810 /* now set the vsite parameters: */
811 AllVsiteBondedInteractions allVsiteBondeds
=
812 createVsiteBondedInformation(NRAL(ftype
), param
.atoms(), at2vb
);
815 fprintf(debug
, "Found %zu bonds, %zu angles and %zu idihs "
816 "for virtual site %d (%s)\n",
817 allVsiteBondeds
.bonds
.size(),
818 allVsiteBondeds
.angles
.size(),
819 allVsiteBondeds
.dihedrals
.size(),
821 interaction_function
[ftype
].longname
);
823 allVsiteBondeds
.bonds
,
824 allVsiteBondeds
.angles
,
825 allVsiteBondeds
.dihedrals
);
831 calc_vsite3_param(atypes
,
834 allVsiteBondeds
.bonds
,
835 allVsiteBondeds
.angles
);
839 calc_vsite3fd_param(¶m
,
840 allVsiteBondeds
.bonds
,
841 allVsiteBondeds
.angles
);
845 calc_vsite3fad_param(¶m
,
846 allVsiteBondeds
.bonds
,
847 allVsiteBondeds
.angles
);
851 calc_vsite3out_param(atypes
,
854 allVsiteBondeds
.bonds
,
855 allVsiteBondeds
.angles
);
859 calc_vsite4fd_param(¶m
,
860 allVsiteBondeds
.bonds
,
861 allVsiteBondeds
.angles
);
865 calc_vsite4fdn_param(¶m
,
866 allVsiteBondeds
.bonds
,
867 allVsiteBondeds
.angles
);
870 gmx_fatal(FARGS
, "Automatic parameter generation not supported "
872 interaction_function
[ftype
].longname
,
878 gmx_fatal(FARGS
, "Automatic parameter generation not supported "
879 "for %s atom %d for this bonding configuration",
880 interaction_function
[ftype
].longname
,
892 void set_vsites_ptype(bool bVerbose
, gmx_moltype_t
*molt
)
898 fprintf(stderr
, "Setting particle type to V for virtual sites\n");
900 for (ftype
= 0; ftype
< F_NRE
; ftype
++)
902 InteractionList
*il
= &molt
->ilist
[ftype
];
903 if (interaction_function
[ftype
].flags
& IF_VSITE
)
905 const int nra
= interaction_function
[ftype
].nratoms
;
906 const int nrd
= il
->size();
907 gmx::ArrayRef
<const int> ia
= il
->iatoms
;
911 fprintf(stderr
, "doing %d %s virtual sites\n",
912 (nrd
/ (nra
+1)), interaction_function
[ftype
].longname
);
915 for (i
= 0; (i
< nrd
); )
917 /* The virtual site */
918 int avsite
= ia
[i
+ 1];
919 molt
->atoms
.atom
[avsite
].ptype
= eptVSite
;
929 * Convenience typedef for linking function type to parameter numbers.
931 * The entries in this datastructure are valid if the particle participates in
932 * a virtual site interaction and has a valid vsite function type other than VSITEN.
933 * \todo Change to remove empty constructor when gmx::compat::optional is available.
935 class VsiteAtomMapping
938 //! Only construct with all information in place or nothing
939 VsiteAtomMapping(int functionType
, int interactionIndex
)
940 : functionType_(functionType
), interactionIndex_(interactionIndex
)
943 : functionType_(-1), interactionIndex_(-1)
945 //! Get function type.
946 const int &functionType() const { return functionType_
; }
947 //! Get parameter number.
948 const int &interactionIndex() const { return interactionIndex_
; }
950 //! Function type for the linked parameter.
952 //! The linked parameter.
953 int interactionIndex_
;
956 static void check_vsite_constraints(gmx::ArrayRef
<InteractionsOfType
> plist
,
957 int cftype
, const int vsite_type
[])
960 for (const auto ¶m
: plist
[cftype
].interactionTypes
)
962 gmx::ArrayRef
<const int> atoms
= param
.atoms();
963 for (int k
= 0; k
< 2; k
++)
966 if (vsite_type
[atom
] != NOTSET
)
968 fprintf(stderr
, "ERROR: Cannot have constraint (%d-%d) with virtual site (%d)\n",
969 param
.ai()+1, param
.aj()+1, atom
+1);
976 gmx_fatal(FARGS
, "There were %d virtual sites involved in constraints", n
);
980 static void clean_vsite_bonds(gmx::ArrayRef
<InteractionsOfType
> plist
,
981 gmx::ArrayRef
<const VsiteAtomMapping
> pindex
,
982 int cftype
, const int vsite_type
[])
985 int nconverted
, nremoved
;
987 bool bKeep
, bRemove
, bAllFD
;
988 InteractionsOfType
*ps
;
990 if (cftype
== F_CONNBONDS
)
995 ps
= &(plist
[cftype
]);
999 for (auto bond
= ps
->interactionTypes
.begin(); bond
!= ps
->interactionTypes
.end(); )
1002 const int *first_atoms
= nullptr;
1007 /* check if all virtual sites are constructed from the same atoms */
1009 gmx::ArrayRef
<const int> atoms
= bond
->atoms();
1010 for (int k
= 0; (k
< 2) && !bKeep
&& !bRemove
; k
++)
1012 /* for all atoms in the bond */
1013 int atom
= atoms
[k
];
1014 if (vsite_type
[atom
] != NOTSET
&& vsite_type
[atom
] != F_VSITEN
)
1017 bool bThisFD
= ( (pindex
[atom
].functionType() == F_VSITE3FD
) ||
1018 (pindex
[atom
].functionType() == F_VSITE3FAD
) ||
1019 (pindex
[atom
].functionType() == F_VSITE4FD
) ||
1020 (pindex
[atom
].functionType() == F_VSITE4FDN
) );
1021 bool bThisOUT
= ( (pindex
[atom
].functionType() == F_VSITE3OUT
) &&
1022 ((interaction_function
[cftype
].flags
& IF_CONSTRAINT
) != 0U) );
1023 bAllFD
= bAllFD
&& bThisFD
;
1024 if (bThisFD
|| bThisOUT
)
1026 oatom
= atoms
[1-k
]; /* the other atom */
1027 if (vsite_type
[oatom
] == NOTSET
&&
1028 oatom
== plist
[pindex
[atom
].functionType()].interactionTypes
[pindex
[atom
].interactionIndex()].aj())
1030 /* if the other atom isn't a vsite, and it is AI */
1040 /* TODO This fragment, and corresponding logic in
1041 clean_vsite_angles and clean_vsite_dihs should
1042 be refactored into a common function */
1045 /* if this is the first vsite we encounter then
1046 store construction atoms */
1047 /* TODO This would be nicer to implement with
1048 a C++ "vector view" class" with an
1049 STL-container-like interface. */
1050 vsnral
= NRAL(pindex
[atom
].functionType()) - 1;
1051 first_atoms
= plist
[pindex
[atom
].functionType()].interactionTypes
[pindex
[atom
].interactionIndex()].atoms().data() + 1;
1055 GMX_ASSERT(vsnral
!= 0, "nvsite > 1 must have vsnral != 0");
1056 GMX_ASSERT(first_atoms
!= nullptr, "nvsite > 1 must have first_atoms != NULL");
1057 /* if it is not the first then
1058 check if this vsite is constructed from the same atoms */
1059 if (vsnral
== NRAL(pindex
[atom
].functionType())-1)
1061 for (int m
= 0; (m
< vsnral
) && !bKeep
; m
++)
1065 bool bPresent
= false;
1066 atoms
= plist
[pindex
[atom
].functionType()].interactionTypes
[pindex
[atom
].interactionIndex()].atoms().data() + 1;
1067 for (int n
= 0; (n
< vsnral
) && !bPresent
; n
++)
1069 if (atoms
[m
] == first_atoms
[n
])
1095 /* if we have no virtual sites in this bond, keep it */
1101 /* TODO This loop and the corresponding loop in
1102 check_vsite_angles should be refactored into a common
1104 /* check if all non-vsite atoms are used in construction: */
1105 bool bFirstTwo
= true;
1106 for (int k
= 0; (k
< 2) && !bKeep
; k
++) /* for all atoms in the bond */
1108 int atom
= atoms
[k
];
1109 if (vsite_type
[atom
] == NOTSET
)
1112 for (int m
= 0; (m
< vsnral
) && !bUsed
; m
++)
1114 GMX_ASSERT(first_atoms
!= nullptr, "If we've seen a vsite before, we know what its first atom index was");
1116 if (atom
== first_atoms
[m
])
1119 bFirstTwo
= bFirstTwo
&& m
< 2;
1129 if (!( bAllFD
&& bFirstTwo
) )
1131 /* Two atom bonded interactions include constraints.
1132 * We need to remove constraints between vsite pairs that have
1133 * a fixed distance due to being constructed from the same
1134 * atoms, since this can be numerically unstable.
1136 for (int m
= 0; m
< vsnral
&& !bKeep
; m
++) /* all constr. atoms */
1138 at1
= first_atoms
[m
];
1139 at2
= first_atoms
[(m
+1) % vsnral
];
1140 bool bPresent
= false;
1141 for (ftype
= 0; ftype
< F_NRE
; ftype
++)
1143 if (interaction_function
[ftype
].flags
& IF_CONSTRAINT
)
1145 for (auto entry
= plist
[ftype
].interactionTypes
.begin(); (entry
!= plist
[ftype
].interactionTypes
.end()) && !bPresent
; entry
++)
1147 /* all constraints until one matches */
1148 bPresent
= ( ( (entry
->ai() == at1
) &&
1149 (entry
->aj() == at2
) ) ||
1150 ( (entry
->ai() == at2
) &&
1151 (entry
->aj() == at1
) ) );
1167 else if (IS_CHEMBOND(cftype
))
1169 plist
[F_CONNBONDS
].interactionTypes
.emplace_back(*bond
);
1170 bond
= ps
->interactionTypes
.erase(bond
);
1175 bond
= ps
->interactionTypes
.erase(bond
);
1182 fprintf(stderr
, "Removed %4d %15ss with virtual sites, %zu left\n",
1183 nremoved
, interaction_function
[cftype
].longname
, ps
->size());
1187 fprintf(stderr
, "Converted %4d %15ss with virtual sites to connections, %zu left\n",
1188 nconverted
, interaction_function
[cftype
].longname
, ps
->size());
1192 fprintf(stderr
, "Warning: removed %d %ss with vsite with %s construction\n"
1193 " This vsite construction does not guarantee constant "
1195 " If the constructions were generated by pdb2gmx ignore "
1197 nOut
, interaction_function
[cftype
].longname
,
1198 interaction_function
[F_VSITE3OUT
].longname
);
1202 static void clean_vsite_angles(gmx::ArrayRef
<InteractionsOfType
> plist
,
1203 gmx::ArrayRef
<VsiteAtomMapping
> pindex
,
1204 int cftype
, const int vsite_type
[],
1205 gmx::ArrayRef
<const Atom2VsiteConnection
> at2vc
)
1208 InteractionsOfType
*ps
;
1210 ps
= &(plist
[cftype
]);
1211 int oldSize
= ps
->size();
1212 for (auto angle
= ps
->interactionTypes
.begin(); angle
!= ps
->interactionTypes
.end(); )
1215 const int *first_atoms
= nullptr;
1218 bool bAll3FAD
= true;
1219 /* check if all virtual sites are constructed from the same atoms */
1221 gmx::ArrayRef
<const int> atoms
= angle
->atoms();
1222 for (int k
= 0; (k
< 3) && !bKeep
; k
++) /* for all atoms in the angle */
1224 int atom
= atoms
[k
];
1225 if (vsite_type
[atom
] != NOTSET
&& vsite_type
[atom
] != F_VSITEN
)
1228 bAll3FAD
= bAll3FAD
&& (pindex
[atom
].functionType() == F_VSITE3FAD
);
1231 /* store construction atoms of first vsite */
1232 vsnral
= NRAL(pindex
[atom
].functionType()) - 1;
1233 first_atoms
= plist
[pindex
[atom
].functionType()].interactionTypes
[pindex
[atom
].interactionIndex()].atoms().data() + 1;
1237 GMX_ASSERT(vsnral
!= 0, "If we've seen a vsite before, we know how many constructing atoms it had");
1238 GMX_ASSERT(first_atoms
!= nullptr, "If we've seen a vsite before, we know what its first atom index was");
1239 /* check if this vsite is constructed from the same atoms */
1240 if (vsnral
== NRAL(pindex
[atom
].functionType())-1)
1242 for (int m
= 0; (m
< vsnral
) && !bKeep
; m
++)
1244 const int *subAtoms
;
1246 bool bPresent
= false;
1247 subAtoms
= plist
[pindex
[atom
].functionType()].interactionTypes
[pindex
[atom
].interactionIndex()].atoms().data() + 1;
1248 for (int n
= 0; (n
< vsnral
) && !bPresent
; n
++)
1250 if (subAtoms
[m
] == first_atoms
[n
])
1269 /* keep all angles with no virtual sites in them or
1270 with virtual sites with more than 3 constr. atoms */
1271 if (nvsite
== 0 && vsnral
> 3)
1276 /* check if all non-vsite atoms are used in construction: */
1277 bool bFirstTwo
= true;
1278 for (int k
= 0; (k
< 3) && !bKeep
; k
++) /* for all atoms in the angle */
1281 if (vsite_type
[atom
] == NOTSET
)
1284 for (int m
= 0; (m
< vsnral
) && !bUsed
; m
++)
1286 GMX_ASSERT(first_atoms
!= nullptr, "If we've seen a vsite before, we know what its first atom index was");
1288 if (atom
== first_atoms
[m
])
1291 bFirstTwo
= bFirstTwo
&& m
< 2;
1301 if (!( bAll3FAD
&& bFirstTwo
) )
1303 /* check if all constructing atoms are constrained together */
1304 for (int m
= 0; m
< vsnral
&& !bKeep
; m
++) /* all constr. atoms */
1306 at1
= first_atoms
[m
];
1307 at2
= first_atoms
[(m
+1) % vsnral
];
1308 bool bPresent
= false;
1309 auto found
= std::find(at2vc
[at1
].begin(), at2vc
[at1
].end(), at2
);
1310 if (found
!= at2vc
[at1
].end())
1327 angle
= ps
->interactionTypes
.erase(angle
);
1331 if (oldSize
!= gmx::ssize(*ps
))
1333 fprintf(stderr
, "Removed %4zu %15ss with virtual sites, %zu left\n",
1334 oldSize
-ps
->size(), interaction_function
[cftype
].longname
, ps
->size());
1338 static void clean_vsite_dihs(gmx::ArrayRef
<InteractionsOfType
> plist
,
1339 gmx::ArrayRef
<const VsiteAtomMapping
> pindex
,
1340 int cftype
, const int vsite_type
[])
1342 InteractionsOfType
*ps
;
1344 ps
= &(plist
[cftype
]);
1346 int oldSize
= ps
->size();
1347 for (auto dih
= ps
->interactionTypes
.begin(); dih
!= ps
->interactionTypes
.end(); )
1350 const int *first_atoms
= nullptr;
1353 gmx::ArrayRef
<const int> atoms
= dih
->atoms();
1355 /* check if all virtual sites are constructed from the same atoms */
1357 for (int k
= 0; (k
< 4) && !bKeep
; k
++) /* for all atoms in the dihedral */
1360 if (vsite_type
[atom
] != NOTSET
&& vsite_type
[atom
] != F_VSITEN
)
1364 /* store construction atoms of first vsite */
1365 vsnral
= NRAL(pindex
[atom
].functionType()) - 1;
1366 first_atoms
= plist
[pindex
[atom
].functionType()].interactionTypes
[pindex
[atom
].interactionIndex()].atoms().data() + 1;
1370 GMX_ASSERT(vsnral
!= 0, "If we've seen a vsite before, we know how many constructing atoms it had");
1371 GMX_ASSERT(first_atoms
!= nullptr, "If we've seen a vsite before, we know what its first atom index was");
1372 /* check if this vsite is constructed from the same atoms */
1373 if (vsnral
== NRAL(pindex
[atom
].functionType())-1)
1375 for (int m
= 0; (m
< vsnral
) && !bKeep
; m
++)
1377 const int *subAtoms
;
1379 bool bPresent
= false;
1380 subAtoms
= plist
[pindex
[atom
].functionType()].interactionTypes
[pindex
[atom
].interactionIndex()].atoms().data() + 1;
1381 for (int n
= 0; (n
< vsnral
) && !bPresent
; n
++)
1383 if (subAtoms
[m
] == first_atoms
[n
])
1395 /* TODO clean_site_bonds and _angles do this increment
1396 at the top of the loop. Refactor this for
1402 /* keep all dihedrals with no virtual sites in them */
1408 /* check if all atoms in dihedral are either virtual sites, or used in
1409 construction of virtual sites. If so, keep it, if not throw away: */
1410 for (int k
= 0; (k
< 4) && !bKeep
; k
++) /* for all atoms in the dihedral */
1412 GMX_ASSERT(vsnral
!= 0, "If we've seen a vsite before, we know how many constructing atoms it had");
1413 GMX_ASSERT(first_atoms
!= nullptr, "If we've seen a vsite before, we know what its first atom index was");
1415 if (vsite_type
[atom
] == NOTSET
)
1417 /* vsnral will be set here, we don't get here with nvsite==0 */
1419 for (int m
= 0; (m
< vsnral
) && !bUsed
; m
++)
1421 if (atom
== first_atoms
[m
])
1439 dih
= ps
->interactionTypes
.erase(dih
);
1444 if (oldSize
!= gmx::ssize(*ps
))
1446 fprintf(stderr
, "Removed %4zu %15ss with virtual sites, %zu left\n",
1447 oldSize
-ps
->size(), interaction_function
[cftype
].longname
, ps
->size());
1451 // TODO use gmx::compat::optional for pindex.
1452 void clean_vsite_bondeds(gmx::ArrayRef
<InteractionsOfType
> plist
, int natoms
, bool bRmVSiteBds
)
1456 std::vector
<VsiteAtomMapping
> pindex
;
1457 std::vector
<Atom2VsiteConnection
> at2vc
;
1459 /* make vsite_type array */
1460 snew(vsite_type
, natoms
);
1461 for (int i
= 0; i
< natoms
; i
++)
1463 vsite_type
[i
] = NOTSET
;
1466 for (int ftype
= 0; ftype
< F_NRE
; ftype
++)
1468 if (interaction_function
[ftype
].flags
& IF_VSITE
)
1470 nvsite
+= plist
[ftype
].size();
1472 while (i
< gmx::ssize(plist
[ftype
]))
1474 vsite
= plist
[ftype
].interactionTypes
[i
].ai();
1475 if (vsite_type
[vsite
] == NOTSET
)
1477 vsite_type
[vsite
] = ftype
;
1481 gmx_fatal(FARGS
, "multiple vsite constructions for atom %d", vsite
+1);
1483 if (ftype
== F_VSITEN
)
1485 while (i
< gmx::ssize(plist
[ftype
]) && plist
[ftype
].interactionTypes
[i
].ai() == vsite
)
1498 /* the rest only if we have virtual sites: */
1501 fprintf(stderr
, "Cleaning up constraints %swith virtual sites\n",
1502 bRmVSiteBds
? "and constant bonded interactions " : "");
1504 /* Make a reverse list to avoid ninteractions^2 operations */
1505 at2vc
= make_at2vsitecon(natoms
, plist
);
1507 pindex
.resize(natoms
);
1508 for (int ftype
= 0; ftype
< F_NRE
; ftype
++)
1510 /* Here we skip VSITEN. In neary all practical use cases this
1511 * is not an issue, since VSITEN is intended for constructing
1512 * additional interaction sites, not for replacing normal atoms
1513 * with bonded interactions. Thus we do not expect constant
1514 * bonded interactions. If VSITEN does get used with constant
1515 * bonded interactions, these are not removed which only leads
1516 * to very minor extra computation and constant energy.
1517 * The only problematic case is onstraints between VSITEN
1518 * constructions with fixed distance (which is anyhow useless).
1519 * This will generate a fatal error in check_vsite_constraints.
1521 if ((interaction_function
[ftype
].flags
& IF_VSITE
) &&
1524 for (gmx::index interactionIndex
= 0;
1525 interactionIndex
< gmx::ssize(plist
[ftype
]);
1528 int k
= plist
[ftype
].interactionTypes
[interactionIndex
].ai();
1529 pindex
[k
] = VsiteAtomMapping(ftype
, interactionIndex
);
1534 /* remove interactions that include virtual sites */
1535 for (int ftype
= 0; ftype
< F_NRE
; ftype
++)
1537 if ( ( ( interaction_function
[ftype
].flags
& IF_BOND
) && bRmVSiteBds
) ||
1538 ( interaction_function
[ftype
].flags
& IF_CONSTRAINT
) )
1540 if (interaction_function
[ftype
].flags
& (IF_BTYPE
| IF_CONSTRAINT
) )
1542 clean_vsite_bonds (plist
, pindex
, ftype
, vsite_type
);
1544 else if (interaction_function
[ftype
].flags
& IF_ATYPE
)
1546 clean_vsite_angles(plist
, pindex
, ftype
, vsite_type
, at2vc
);
1548 else if ( (ftype
== F_PDIHS
) || (ftype
== F_IDIHS
) )
1550 clean_vsite_dihs (plist
, pindex
, ftype
, vsite_type
);
1554 /* check that no remaining constraints include virtual sites */
1555 for (int ftype
= 0; ftype
< F_NRE
; ftype
++)
1557 if (interaction_function
[ftype
].flags
& IF_CONSTRAINT
)
1559 check_vsite_constraints(plist
, ftype
, vsite_type
);