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 by the GROMACS development team.
7 * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
8 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
9 * and including many others, as listed in the AUTHORS file in the
10 * top-level source directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
40 * \brief This file defines low-level functions necessary for
41 * computing energies and forces for listed interactions.
43 * \author Mark Abraham <mark.j.abraham@gmail.com>
45 * \ingroup module_listed_forces
58 #include "gromacs/gmxlib/nrnb.h"
59 #include "gromacs/listed_forces/disre.h"
60 #include "gromacs/listed_forces/orires.h"
61 #include "gromacs/math/functions.h"
62 #include "gromacs/math/units.h"
63 #include "gromacs/math/utilities.h"
64 #include "gromacs/math/vec.h"
65 #include "gromacs/mdtypes/fcdata.h"
66 #include "gromacs/mdtypes/mdatom.h"
67 #include "gromacs/pbcutil/ishift.h"
68 #include "gromacs/pbcutil/pbc.h"
69 #include "gromacs/pbcutil/pbc_simd.h"
70 #include "gromacs/simd/simd.h"
71 #include "gromacs/simd/simd_math.h"
72 #include "gromacs/simd/vector_operations.h"
73 #include "gromacs/utility/basedefinitions.h"
74 #include "gromacs/utility/enumerationhelpers.h"
75 #include "gromacs/utility/fatalerror.h"
76 #include "gromacs/utility/real.h"
77 #include "gromacs/utility/smalloc.h"
79 #include "listed_internal.h"
82 using namespace gmx; // TODO: Remove when this file is moved into gmx namespace
84 const EnumerationArray<BondedKernelFlavor, std::string> c_bondedKernelFlavorStrings = {
85 "forces, using SIMD when available",
86 "forces, not using SIMD",
87 "forces, virial, and energy (ie. not using SIMD)",
88 "forces and energy (ie. not using SIMD)"
93 //! Type of CPU function to compute a bonded interaction.
94 using BondedFunction = real (*)(int nbonds,
95 const t_iatom iatoms[],
96 const t_iparams iparams[],
105 t_disresdata* disresdata,
106 t_oriresdata* oriresdata,
109 /*! \brief Mysterious CMAP coefficient matrix */
110 const int cmap_coeff_matrix[] = {
111 1, 0, -3, 2, 0, 0, 0, 0, -3, 0, 9, -6, 2, 0, -6, 4, 0, 0, 0, 0, 0, 0, 0, 0,
112 3, 0, -9, 6, -2, 0, 6, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, -6, 0, 0, -6, 4,
113 0, 0, 3, -2, 0, 0, 0, 0, 0, 0, -9, 6, 0, 0, 6, -4, 0, 0, 0, 0, 1, 0, -3, 2,
114 -2, 0, 6, -4, 1, 0, -3, 2, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 3, -2, 1, 0, -3, 2,
115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 2, 0, 0, 3, -2, 0, 0, 0, 0, 0, 0, 3, -2,
116 0, 0, -6, 4, 0, 0, 3, -2, 0, 1, -2, 1, 0, 0, 0, 0, 0, -3, 6, -3, 0, 2, -4, 2,
117 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, -6, 3, 0, -2, 4, -2, 0, 0, 0, 0, 0, 0, 0, 0,
118 0, 0, -3, 3, 0, 0, 2, -2, 0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 3, -3, 0, 0, -2, 2,
119 0, 0, 0, 0, 0, 1, -2, 1, 0, -2, 4, -2, 0, 1, -2, 1, 0, 0, 0, 0, 0, 0, 0, 0,
120 0, -1, 2, -1, 0, 1, -2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, -1, 1,
121 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 2, -2, 0, 0, -1, 1
125 /*! \brief Compute dx = xi - xj, modulo PBC if non-NULL
127 * \todo This kind of code appears in many places. Consolidate it */
128 int pbc_rvec_sub(const t_pbc* pbc, const rvec xi, const rvec xj, rvec dx)
132 return pbc_dx_aiuc(pbc, xi, xj, dx);
136 rvec_sub(xi, xj, dx);
144 real bond_angle(const rvec xi,
153 /* Return value is the angle between the bonds i-j and j-k */
158 *t1 = pbc_rvec_sub(pbc, xi, xj, r_ij); /* 3 */
159 *t2 = pbc_rvec_sub(pbc, xk, xj, r_kj); /* 3 */
161 *costh = cos_angle(r_ij, r_kj); /* 25 */
162 th = std::acos(*costh); /* 10 */
167 real dih_angle(const rvec xi,
181 *t1 = pbc_rvec_sub(pbc, xi, xj, r_ij); /* 3 */
182 *t2 = pbc_rvec_sub(pbc, xk, xj, r_kj); /* 3 */
183 *t3 = pbc_rvec_sub(pbc, xk, xl, r_kl); /* 3 */
185 cprod(r_ij, r_kj, m); /* 9 */
186 cprod(r_kj, r_kl, n); /* 9 */
187 real phi = gmx_angle(m, n); /* 49 (assuming 25 for atan2) */
188 real ipr = iprod(r_ij, n); /* 5 */
189 real sign = (ipr < 0.0) ? -1.0 : 1.0;
190 phi = sign * phi; /* 1 */
196 void make_dp_periodic(real* dp) /* 1 flop? */
198 /* dp cannot be outside (-pi,pi) */
203 else if (*dp < -M_PI)
212 /*! \brief Spreads and accumulates the bonded forces to the two atoms and adds the virial contribution when needed
214 * \p shiftIndex is used as the periodic shift.
216 template<BondedKernelFlavor flavor>
217 inline void spreadBondForces(const real bondForce,
225 for (int m = 0; m < DIM; m++) /* 15 */
227 const real fij = bondForce * dx[m];
230 if (computeVirial(flavor))
232 fshift[shiftIndex][m] += fij;
233 fshift[CENTRAL][m] -= fij;
238 /*! \brief Morse potential bond
240 * By Frank Everdij. Three parameters needed:
242 * b0 = equilibrium distance in nm
243 * be = beta in nm^-1 (actually, it's nu_e*Sqrt(2*pi*pi*mu/D_e))
244 * cb = well depth in kJ/mol
246 * Note: the potential is referenced to be +cb at infinite separation
247 * and zero at the equilibrium distance!
249 template<BondedKernelFlavor flavor>
250 real morse_bonds(int nbonds,
251 const t_iatom forceatoms[],
252 const t_iparams forceparams[],
259 const t_mdatoms gmx_unused* md,
260 t_fcdata gmx_unused* fcd,
261 t_disresdata gmx_unused* disresdata,
262 t_oriresdata gmx_unused* oriresdata,
263 int gmx_unused* global_atom_index)
265 const real one = 1.0;
266 const real two = 2.0;
267 real dr, dr2, temp, omtemp, cbomtemp, fbond, vbond, vtot;
268 real b0, be, cb, b0A, beA, cbA, b0B, beB, cbB, L1;
270 int i, ki, type, ai, aj;
273 for (i = 0; (i < nbonds);)
275 type = forceatoms[i++];
276 ai = forceatoms[i++];
277 aj = forceatoms[i++];
279 b0A = forceparams[type].morse.b0A;
280 beA = forceparams[type].morse.betaA;
281 cbA = forceparams[type].morse.cbA;
283 b0B = forceparams[type].morse.b0B;
284 beB = forceparams[type].morse.betaB;
285 cbB = forceparams[type].morse.cbB;
287 L1 = one - lambda; /* 1 */
288 b0 = L1 * b0A + lambda * b0B; /* 3 */
289 be = L1 * beA + lambda * beB; /* 3 */
290 cb = L1 * cbA + lambda * cbB; /* 3 */
292 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
293 dr2 = iprod(dx, dx); /* 5 */
294 dr = dr2 * gmx::invsqrt(dr2); /* 10 */
295 temp = std::exp(-be * (dr - b0)); /* 12 */
299 /* bonds are constrainted. This may _not_ include bond constraints if they are lambda dependent */
300 *dvdlambda += cbB - cbA;
304 omtemp = one - temp; /* 1 */
305 cbomtemp = cb * omtemp; /* 1 */
306 vbond = cbomtemp * omtemp; /* 1 */
307 fbond = -two * be * temp * cbomtemp * gmx::invsqrt(dr2); /* 9 */
308 vtot += vbond; /* 1 */
310 *dvdlambda += (cbB - cbA) * omtemp * omtemp
311 - (2 - 2 * omtemp) * omtemp * cb * ((b0B - b0A) * be - (beB - beA) * (dr - b0)); /* 15 */
313 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
319 template<BondedKernelFlavor flavor>
320 real cubic_bonds(int nbonds,
321 const t_iatom forceatoms[],
322 const t_iparams forceparams[],
327 real gmx_unused lambda,
328 real gmx_unused* dvdlambda,
329 const t_mdatoms gmx_unused* md,
330 t_fcdata gmx_unused* fcd,
331 t_disresdata gmx_unused* disresdata,
332 t_oriresdata gmx_unused* oriresdata,
333 int gmx_unused* global_atom_index)
335 const real three = 3.0;
336 const real two = 2.0;
338 real dr, dr2, dist, kdist, kdist2, fbond, vbond, vtot;
340 int i, ki, type, ai, aj;
343 for (i = 0; (i < nbonds);)
345 type = forceatoms[i++];
346 ai = forceatoms[i++];
347 aj = forceatoms[i++];
349 b0 = forceparams[type].cubic.b0;
350 kb = forceparams[type].cubic.kb;
351 kcub = forceparams[type].cubic.kcub;
353 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
354 dr2 = iprod(dx, dx); /* 5 */
361 dr = dr2 * gmx::invsqrt(dr2); /* 10 */
364 kdist2 = kdist * dist;
366 vbond = kdist2 + kcub * kdist2 * dist;
367 fbond = -(two * kdist + three * kdist2 * kcub) / dr;
369 vtot += vbond; /* 21 */
371 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
376 template<BondedKernelFlavor flavor>
377 real FENE_bonds(int nbonds,
378 const t_iatom forceatoms[],
379 const t_iparams forceparams[],
384 real gmx_unused lambda,
385 real gmx_unused* dvdlambda,
386 const t_mdatoms gmx_unused* md,
387 t_fcdata gmx_unused* fcd,
388 t_disresdata gmx_unused* disresdata,
389 t_oriresdata gmx_unused* oriresdata,
390 int* global_atom_index)
392 const real half = 0.5;
393 const real one = 1.0;
395 real dr2, bm2, omdr2obm2, fbond, vbond, vtot;
397 int i, ki, type, ai, aj;
400 for (i = 0; (i < nbonds);)
402 type = forceatoms[i++];
403 ai = forceatoms[i++];
404 aj = forceatoms[i++];
406 bm = forceparams[type].fene.bm;
407 kb = forceparams[type].fene.kb;
409 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
410 dr2 = iprod(dx, dx); /* 5 */
422 "r^2 (%f) >= bm^2 (%f) in FENE bond between atoms %d and %d",
425 glatnr(global_atom_index, ai),
426 glatnr(global_atom_index, aj));
429 omdr2obm2 = one - dr2 / bm2;
431 vbond = -half * kb * bm2 * std::log(omdr2obm2);
432 fbond = -kb / omdr2obm2;
434 vtot += vbond; /* 35 */
436 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
441 real harmonic(real kA, real kB, real xA, real xB, real x, real lambda, real* V, real* F)
443 const real half = 0.5;
444 real L1, kk, x0, dx, dx2;
445 real v, f, dvdlambda;
448 kk = L1 * kA + lambda * kB;
449 x0 = L1 * xA + lambda * xB;
456 dvdlambda = half * (kB - kA) * dx2 + (xA - xB) * kk * dx;
463 /* That was 19 flops */
466 template<BondedKernelFlavor flavor>
467 std::enable_if_t<flavor != BondedKernelFlavor::ForcesSimdWhenAvailable || !GMX_SIMD_HAVE_REAL, real>
469 const t_iatom forceatoms[],
470 const t_iparams forceparams[],
477 const t_mdatoms gmx_unused* md,
478 t_fcdata gmx_unused* fcd,
479 t_disresdata gmx_unused* disresdata,
480 t_oriresdata gmx_unused* oriresdata,
481 int gmx_unused* global_atom_index)
483 int i, ki, ai, aj, type;
484 real dr, dr2, fbond, vbond, vtot;
488 for (i = 0; (i < nbonds);)
490 type = forceatoms[i++];
491 ai = forceatoms[i++];
492 aj = forceatoms[i++];
494 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
495 dr2 = iprod(dx, dx); /* 5 */
496 dr = std::sqrt(dr2); /* 10 */
498 *dvdlambda += harmonic(forceparams[type].harmonic.krA,
499 forceparams[type].harmonic.krB,
500 forceparams[type].harmonic.rA,
501 forceparams[type].harmonic.rB,
513 vtot += vbond; /* 1*/
514 fbond *= gmx::invsqrt(dr2); /* 6 */
516 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
521 #if GMX_SIMD_HAVE_REAL
523 /*! \brief Computes forces (only) for harmonic bonds using SIMD intrinsics
525 * As plain-C bonds(), but using SIMD to calculate many bonds at once.
526 * This routines does not calculate energies and shift forces.
528 template<BondedKernelFlavor flavor>
529 std::enable_if_t<flavor == BondedKernelFlavor::ForcesSimdWhenAvailable, real>
531 const t_iatom forceatoms[],
532 const t_iparams forceparams[],
535 rvec gmx_unused fshift[],
537 real gmx_unused lambda,
538 real gmx_unused* dvdlambda,
539 const t_mdatoms gmx_unused* md,
540 t_fcdata gmx_unused* fcd,
541 t_disresdata gmx_unused* disresdata,
542 t_oriresdata gmx_unused* oriresdata,
543 int gmx_unused* global_atom_index)
545 constexpr int nfa1 = 3;
546 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[GMX_SIMD_REAL_WIDTH];
547 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[GMX_SIMD_REAL_WIDTH];
548 alignas(GMX_SIMD_ALIGNMENT) real coeff[2 * GMX_SIMD_REAL_WIDTH];
550 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9 * GMX_SIMD_REAL_WIDTH];
552 set_pbc_simd(pbc, pbc_simd);
554 const SimdReal real_eps = SimdReal(GMX_REAL_EPS);
556 /* nbonds is the number of bonds times nfa1, here we step GMX_SIMD_REAL_WIDTH angles */
557 for (int i = 0; i < nbonds; i += GMX_SIMD_REAL_WIDTH * nfa1)
559 /* Collect atoms for GMX_SIMD_REAL_WIDTH angles.
560 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
563 for (int s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
565 const int type = forceatoms[iu];
566 ai[s] = forceatoms[iu + 1];
567 aj[s] = forceatoms[iu + 2];
569 /* At the end fill the arrays with the last atoms and 0 params */
570 if (i + s * nfa1 < nbonds)
572 coeff[s] = forceparams[type].harmonic.krA;
573 coeff[GMX_SIMD_REAL_WIDTH + s] = forceparams[type].harmonic.rA;
575 if (iu + nfa1 < nbonds)
583 coeff[GMX_SIMD_REAL_WIDTH + s] = 0;
587 /* Store the non PBC corrected distances packed and aligned */
590 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ai, &xi, &yi, &zi);
591 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), aj, &xj, &yj, &zj);
592 SimdReal rij_x = xi - xj;
593 SimdReal rij_y = yi - yj;
594 SimdReal rij_z = zi - zj;
596 pbc_correct_dx_simd(&rij_x, &rij_y, &rij_z, pbc_simd);
598 const SimdReal dist2 = rij_x * rij_x + rij_y * rij_y + rij_z * rij_z;
599 // Here we avoid sqrt(0), the force will be zero because rij=0
600 const SimdReal invDist = invsqrt(max(dist2, real_eps));
602 const SimdReal k = load<SimdReal>(coeff);
603 const SimdReal r0 = load<SimdReal>(coeff + GMX_SIMD_REAL_WIDTH);
605 // Compute the force divided by the distance
606 const SimdReal forceOverR = -k * (dist2 * invDist - r0) * invDist;
608 const SimdReal f_x = forceOverR * rij_x;
609 const SimdReal f_y = forceOverR * rij_y;
610 const SimdReal f_z = forceOverR * rij_z;
612 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ai, f_x, f_y, f_z);
613 transposeScatterDecrU<4>(reinterpret_cast<real*>(f), aj, f_x, f_y, f_z);
619 #endif // GMX_SIMD_HAVE_REAL
621 template<BondedKernelFlavor flavor>
622 real restraint_bonds(int nbonds,
623 const t_iatom forceatoms[],
624 const t_iparams forceparams[],
631 const t_mdatoms gmx_unused* md,
632 t_fcdata gmx_unused* fcd,
633 t_disresdata gmx_unused* disresdata,
634 t_oriresdata gmx_unused* oriresdata,
635 int gmx_unused* global_atom_index)
637 int i, ki, ai, aj, type;
638 real dr, dr2, fbond, vbond, vtot;
640 real low, dlow, up1, dup1, up2, dup2, k, dk;
647 for (i = 0; (i < nbonds);)
649 type = forceatoms[i++];
650 ai = forceatoms[i++];
651 aj = forceatoms[i++];
653 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
654 dr2 = iprod(dx, dx); /* 5 */
655 dr = dr2 * gmx::invsqrt(dr2); /* 10 */
657 low = L1 * forceparams[type].restraint.lowA + lambda * forceparams[type].restraint.lowB;
658 dlow = -forceparams[type].restraint.lowA + forceparams[type].restraint.lowB;
659 up1 = L1 * forceparams[type].restraint.up1A + lambda * forceparams[type].restraint.up1B;
660 dup1 = -forceparams[type].restraint.up1A + forceparams[type].restraint.up1B;
661 up2 = L1 * forceparams[type].restraint.up2A + lambda * forceparams[type].restraint.up2B;
662 dup2 = -forceparams[type].restraint.up2A + forceparams[type].restraint.up2B;
663 k = L1 * forceparams[type].restraint.kA + lambda * forceparams[type].restraint.kB;
664 dk = -forceparams[type].restraint.kA + forceparams[type].restraint.kB;
671 vbond = 0.5 * k * drh2;
673 *dvdlambda += 0.5 * dk * drh2 - k * dlow * drh;
684 vbond = 0.5 * k * drh2;
686 *dvdlambda += 0.5 * dk * drh2 - k * dup1 * drh;
691 vbond = k * (up2 - up1) * (0.5 * (up2 - up1) + drh);
692 fbond = -k * (up2 - up1);
693 *dvdlambda += dk * (up2 - up1) * (0.5 * (up2 - up1) + drh)
694 + k * (dup2 - dup1) * (up2 - up1 + drh) - k * (up2 - up1) * dup2;
702 vtot += vbond; /* 1*/
703 fbond *= gmx::invsqrt(dr2); /* 6 */
705 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
711 template<BondedKernelFlavor flavor>
712 real polarize(int nbonds,
713 const t_iatom forceatoms[],
714 const t_iparams forceparams[],
722 t_fcdata gmx_unused* fcd,
723 t_disresdata gmx_unused* disresdata,
724 t_oriresdata gmx_unused* oriresdata,
725 int gmx_unused* global_atom_index)
727 int i, ki, ai, aj, type;
728 real dr, dr2, fbond, vbond, vtot, ksh;
732 for (i = 0; (i < nbonds);)
734 type = forceatoms[i++];
735 ai = forceatoms[i++];
736 aj = forceatoms[i++];
737 ksh = gmx::square(md->chargeA[aj]) * gmx::c_one4PiEps0 / forceparams[type].polarize.alpha;
739 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
740 dr2 = iprod(dx, dx); /* 5 */
741 dr = std::sqrt(dr2); /* 10 */
743 *dvdlambda += harmonic(ksh, ksh, 0, 0, dr, lambda, &vbond, &fbond); /* 19 */
750 vtot += vbond; /* 1*/
751 fbond *= gmx::invsqrt(dr2); /* 6 */
753 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
758 template<BondedKernelFlavor flavor>
759 real anharm_polarize(int nbonds,
760 const t_iatom forceatoms[],
761 const t_iparams forceparams[],
769 t_fcdata gmx_unused* fcd,
770 t_disresdata gmx_unused* disresdata,
771 t_oriresdata gmx_unused* oriresdata,
772 int gmx_unused* global_atom_index)
774 int i, ki, ai, aj, type;
775 real dr, dr2, fbond, vbond, vtot, ksh, khyp, drcut, ddr, ddr3;
779 for (i = 0; (i < nbonds);)
781 type = forceatoms[i++];
782 ai = forceatoms[i++];
783 aj = forceatoms[i++];
784 ksh = gmx::square(md->chargeA[aj]) * gmx::c_one4PiEps0 / forceparams[type].anharm_polarize.alpha; /* 7*/
785 khyp = forceparams[type].anharm_polarize.khyp;
786 drcut = forceparams[type].anharm_polarize.drcut;
788 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
789 dr2 = iprod(dx, dx); /* 5 */
790 dr = dr2 * gmx::invsqrt(dr2); /* 10 */
792 *dvdlambda += harmonic(ksh, ksh, 0, 0, dr, lambda, &vbond, &fbond); /* 19 */
802 ddr3 = ddr * ddr * ddr;
803 vbond += khyp * ddr * ddr3;
804 fbond -= 4 * khyp * ddr3;
806 fbond *= gmx::invsqrt(dr2); /* 6 */
807 vtot += vbond; /* 1*/
809 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
814 template<BondedKernelFlavor flavor>
815 real water_pol(int nbonds,
816 const t_iatom forceatoms[],
817 const t_iparams forceparams[],
820 rvec gmx_unused fshift[],
821 const t_pbc gmx_unused* pbc,
822 real gmx_unused lambda,
823 real gmx_unused* dvdlambda,
824 const t_mdatoms gmx_unused* md,
825 t_fcdata gmx_unused* fcd,
826 t_disresdata gmx_unused* disresdata,
827 t_oriresdata gmx_unused* oriresdata,
828 int gmx_unused* global_atom_index)
830 /* This routine implements anisotropic polarizibility for water, through
831 * a shell connected to a dummy with spring constant that differ in the
832 * three spatial dimensions in the molecular frame.
834 int i, m, aO, aH1, aH2, aD, aS, type, type0, ki;
835 rvec dOH1, dOH2, dHH, dOD, dDS, nW, kk, dx, kdx, proj;
836 real vtot, fij, r_HH, r_OD, r_nW, tx, ty, tz, qS;
841 type0 = forceatoms[0];
843 qS = md->chargeA[aS];
844 kk[XX] = gmx::square(qS) * gmx::c_one4PiEps0 / forceparams[type0].wpol.al_x;
845 kk[YY] = gmx::square(qS) * gmx::c_one4PiEps0 / forceparams[type0].wpol.al_y;
846 kk[ZZ] = gmx::square(qS) * gmx::c_one4PiEps0 / forceparams[type0].wpol.al_z;
847 r_HH = 1.0 / forceparams[type0].wpol.rHH;
848 for (i = 0; (i < nbonds); i += 6)
850 type = forceatoms[i];
853 gmx_fatal(FARGS, "Sorry, type = %d, type0 = %d, file = %s, line = %d", type, type0, __FILE__, __LINE__);
855 aO = forceatoms[i + 1];
856 aH1 = forceatoms[i + 2];
857 aH2 = forceatoms[i + 3];
858 aD = forceatoms[i + 4];
859 aS = forceatoms[i + 5];
861 /* Compute vectors describing the water frame */
862 pbc_rvec_sub(pbc, x[aH1], x[aO], dOH1);
863 pbc_rvec_sub(pbc, x[aH2], x[aO], dOH2);
864 pbc_rvec_sub(pbc, x[aH2], x[aH1], dHH);
865 pbc_rvec_sub(pbc, x[aD], x[aO], dOD);
866 ki = pbc_rvec_sub(pbc, x[aS], x[aD], dDS);
867 cprod(dOH1, dOH2, nW);
869 /* Compute inverse length of normal vector
870 * (this one could be precomputed, but I'm too lazy now)
872 r_nW = gmx::invsqrt(iprod(nW, nW));
873 /* This is for precision, but does not make a big difference,
876 r_OD = gmx::invsqrt(iprod(dOD, dOD));
878 /* Normalize the vectors in the water frame */
880 svmul(r_HH, dHH, dHH);
881 svmul(r_OD, dOD, dOD);
883 /* Compute displacement of shell along components of the vector */
884 dx[ZZ] = iprod(dDS, dOD);
885 /* Compute projection on the XY plane: dDS - dx[ZZ]*dOD */
886 for (m = 0; (m < DIM); m++)
888 proj[m] = dDS[m] - dx[ZZ] * dOD[m];
891 /*dx[XX] = iprod(dDS,nW);
892 dx[YY] = iprod(dDS,dHH);*/
893 dx[XX] = iprod(proj, nW);
894 for (m = 0; (m < DIM); m++)
896 proj[m] -= dx[XX] * nW[m];
898 dx[YY] = iprod(proj, dHH);
899 /* Now compute the forces and energy */
900 kdx[XX] = kk[XX] * dx[XX];
901 kdx[YY] = kk[YY] * dx[YY];
902 kdx[ZZ] = kk[ZZ] * dx[ZZ];
903 vtot += iprod(dx, kdx);
905 for (m = 0; (m < DIM); m++)
907 /* This is a tensor operation but written out for speed */
908 tx = nW[m] * kdx[XX];
909 ty = dHH[m] * kdx[YY];
910 tz = dOD[m] * kdx[ZZ];
914 if (computeVirial(flavor))
916 fshift[ki][m] += fij;
917 fshift[CENTRAL][m] -= fij;
925 template<BondedKernelFlavor flavor>
927 do_1_thole(const rvec xi, const rvec xj, rvec fi, rvec fj, const t_pbc* pbc, real qq, rvec fshift[], real afac)
930 real r12sq, r12_1, r12bar, v0, v1, fscal, ebar, fff;
933 t = pbc_rvec_sub(pbc, xi, xj, r12); /* 3 */
935 r12sq = iprod(r12, r12); /* 5 */
936 r12_1 = gmx::invsqrt(r12sq); /* 5 */
937 r12bar = afac / r12_1; /* 5 */
938 v0 = qq * gmx::c_one4PiEps0 * r12_1; /* 2 */
939 ebar = std::exp(-r12bar); /* 5 */
940 v1 = (1 - (1 + 0.5 * r12bar) * ebar); /* 4 */
941 fscal = ((v0 * r12_1) * v1 - v0 * 0.5 * afac * ebar * (r12bar + 1)) * r12_1; /* 9 */
943 for (m = 0; (m < DIM); m++)
945 fff = fscal * r12[m];
948 if (computeVirial(flavor))
951 fshift[CENTRAL][m] -= fff;
955 return v0 * v1; /* 1 */
959 template<BondedKernelFlavor flavor>
960 real thole_pol(int nbonds,
961 const t_iatom forceatoms[],
962 const t_iparams forceparams[],
967 real gmx_unused lambda,
968 real gmx_unused* dvdlambda,
970 t_fcdata gmx_unused* fcd,
971 t_disresdata gmx_unused* disresdata,
972 t_oriresdata gmx_unused* oriresdata,
973 int gmx_unused* global_atom_index)
975 /* Interaction between two pairs of particles with opposite charge */
976 int i, type, a1, da1, a2, da2;
977 real q1, q2, qq, a, al1, al2, afac;
980 for (i = 0; (i < nbonds);)
982 type = forceatoms[i++];
983 a1 = forceatoms[i++];
984 da1 = forceatoms[i++];
985 a2 = forceatoms[i++];
986 da2 = forceatoms[i++];
987 q1 = md->chargeA[da1];
988 q2 = md->chargeA[da2];
989 a = forceparams[type].thole.a;
990 al1 = forceparams[type].thole.alpha1;
991 al2 = forceparams[type].thole.alpha2;
993 afac = a * gmx::invsixthroot(al1 * al2);
994 V += do_1_thole<flavor>(x[a1], x[a2], f[a1], f[a2], pbc, qq, fshift, afac);
995 V += do_1_thole<flavor>(x[da1], x[a2], f[da1], f[a2], pbc, -qq, fshift, afac);
996 V += do_1_thole<flavor>(x[a1], x[da2], f[a1], f[da2], pbc, -qq, fshift, afac);
997 V += do_1_thole<flavor>(x[da1], x[da2], f[da1], f[da2], pbc, qq, fshift, afac);
1003 // Avoid gcc 386 -O3 code generation bug in this function (see Issue
1004 // #3205 for more information)
1005 #if defined(__GNUC__) && defined(__i386__) && defined(__OPTIMIZE__)
1006 # pragma GCC push_options
1007 # pragma GCC optimize("O1")
1008 # define avoid_gcc_i386_o3_code_generation_bug
1011 template<BondedKernelFlavor flavor>
1012 std::enable_if_t<flavor != BondedKernelFlavor::ForcesSimdWhenAvailable || !GMX_SIMD_HAVE_REAL, real>
1014 const t_iatom forceatoms[],
1015 const t_iparams forceparams[],
1022 const t_mdatoms gmx_unused* md,
1023 t_fcdata gmx_unused* fcd,
1024 t_disresdata gmx_unused* disresdata,
1025 t_oriresdata gmx_unused* oriresdata,
1026 int gmx_unused* global_atom_index)
1028 int i, ai, aj, ak, t1, t2, type;
1030 real cos_theta, cos_theta2, theta, dVdt, va, vtot;
1033 for (i = 0; i < nbonds;)
1035 type = forceatoms[i++];
1036 ai = forceatoms[i++];
1037 aj = forceatoms[i++];
1038 ak = forceatoms[i++];
1040 theta = bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
1042 *dvdlambda += harmonic(forceparams[type].harmonic.krA,
1043 forceparams[type].harmonic.krB,
1044 forceparams[type].harmonic.rA * gmx::c_deg2Rad,
1045 forceparams[type].harmonic.rB * gmx::c_deg2Rad,
1052 cos_theta2 = gmx::square(cos_theta);
1059 real nrkj_1, nrij_1;
1062 st = dVdt * gmx::invsqrt(1 - cos_theta2); /* 12 */
1063 sth = st * cos_theta; /* 1 */
1064 nrij2 = iprod(r_ij, r_ij); /* 5 */
1065 nrkj2 = iprod(r_kj, r_kj); /* 5 */
1067 nrij_1 = gmx::invsqrt(nrij2); /* 10 */
1068 nrkj_1 = gmx::invsqrt(nrkj2); /* 10 */
1070 cik = st * nrij_1 * nrkj_1; /* 2 */
1071 cii = sth * nrij_1 * nrij_1; /* 2 */
1072 ckk = sth * nrkj_1 * nrkj_1; /* 2 */
1074 for (m = 0; m < DIM; m++)
1076 f_i[m] = -(cik * r_kj[m] - cii * r_ij[m]);
1077 f_k[m] = -(cik * r_ij[m] - ckk * r_kj[m]);
1078 f_j[m] = -f_i[m] - f_k[m];
1083 if (computeVirial(flavor))
1085 rvec_inc(fshift[t1], f_i);
1086 rvec_inc(fshift[CENTRAL], f_j);
1087 rvec_inc(fshift[t2], f_k);
1095 #ifdef avoid_gcc_i386_o3_code_generation_bug
1096 # pragma GCC pop_options
1097 # undef avoid_gcc_i386_o3_code_generation_bug
1100 #if GMX_SIMD_HAVE_REAL
1102 /* As angles, but using SIMD to calculate many angles at once.
1103 * This routines does not calculate energies and shift forces.
1105 template<BondedKernelFlavor flavor>
1106 std::enable_if_t<flavor == BondedKernelFlavor::ForcesSimdWhenAvailable, real>
1108 const t_iatom forceatoms[],
1109 const t_iparams forceparams[],
1112 rvec gmx_unused fshift[],
1114 real gmx_unused lambda,
1115 real gmx_unused* dvdlambda,
1116 const t_mdatoms gmx_unused* md,
1117 t_fcdata gmx_unused* fcd,
1118 t_disresdata gmx_unused* disresdata,
1119 t_oriresdata gmx_unused* oriresdata,
1120 int gmx_unused* global_atom_index)
1125 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[GMX_SIMD_REAL_WIDTH];
1126 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[GMX_SIMD_REAL_WIDTH];
1127 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ak[GMX_SIMD_REAL_WIDTH];
1128 alignas(GMX_SIMD_ALIGNMENT) real coeff[2 * GMX_SIMD_REAL_WIDTH];
1129 SimdReal deg2rad_S(gmx::c_deg2Rad);
1130 SimdReal xi_S, yi_S, zi_S;
1131 SimdReal xj_S, yj_S, zj_S;
1132 SimdReal xk_S, yk_S, zk_S;
1133 SimdReal k_S, theta0_S;
1134 SimdReal rijx_S, rijy_S, rijz_S;
1135 SimdReal rkjx_S, rkjy_S, rkjz_S;
1136 SimdReal one_S(1.0);
1137 SimdReal one_min_eps_S(1.0_real - GMX_REAL_EPS); // Largest number < 1
1140 SimdReal nrij2_S, nrij_1_S;
1141 SimdReal nrkj2_S, nrkj_1_S;
1142 SimdReal cos_S, invsin_S;
1145 SimdReal st_S, sth_S;
1146 SimdReal cik_S, cii_S, ckk_S;
1147 SimdReal f_ix_S, f_iy_S, f_iz_S;
1148 SimdReal f_kx_S, f_ky_S, f_kz_S;
1149 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9 * GMX_SIMD_REAL_WIDTH];
1151 set_pbc_simd(pbc, pbc_simd);
1153 /* nbonds is the number of angles times nfa1, here we step GMX_SIMD_REAL_WIDTH angles */
1154 for (i = 0; (i < nbonds); i += GMX_SIMD_REAL_WIDTH * nfa1)
1156 /* Collect atoms for GMX_SIMD_REAL_WIDTH angles.
1157 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
1160 for (s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
1162 type = forceatoms[iu];
1163 ai[s] = forceatoms[iu + 1];
1164 aj[s] = forceatoms[iu + 2];
1165 ak[s] = forceatoms[iu + 3];
1167 /* At the end fill the arrays with the last atoms and 0 params */
1168 if (i + s * nfa1 < nbonds)
1170 coeff[s] = forceparams[type].harmonic.krA;
1171 coeff[GMX_SIMD_REAL_WIDTH + s] = forceparams[type].harmonic.rA;
1173 if (iu + nfa1 < nbonds)
1181 coeff[GMX_SIMD_REAL_WIDTH + s] = 0;
1185 /* Store the non PBC corrected distances packed and aligned */
1186 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ai, &xi_S, &yi_S, &zi_S);
1187 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), aj, &xj_S, &yj_S, &zj_S);
1188 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ak, &xk_S, &yk_S, &zk_S);
1189 rijx_S = xi_S - xj_S;
1190 rijy_S = yi_S - yj_S;
1191 rijz_S = zi_S - zj_S;
1192 rkjx_S = xk_S - xj_S;
1193 rkjy_S = yk_S - yj_S;
1194 rkjz_S = zk_S - zj_S;
1196 k_S = load<SimdReal>(coeff);
1197 theta0_S = load<SimdReal>(coeff + GMX_SIMD_REAL_WIDTH) * deg2rad_S;
1199 pbc_correct_dx_simd(&rijx_S, &rijy_S, &rijz_S, pbc_simd);
1200 pbc_correct_dx_simd(&rkjx_S, &rkjy_S, &rkjz_S, pbc_simd);
1202 rij_rkj_S = iprod(rijx_S, rijy_S, rijz_S, rkjx_S, rkjy_S, rkjz_S);
1204 nrij2_S = norm2(rijx_S, rijy_S, rijz_S);
1205 nrkj2_S = norm2(rkjx_S, rkjy_S, rkjz_S);
1207 nrij_1_S = invsqrt(nrij2_S);
1208 nrkj_1_S = invsqrt(nrkj2_S);
1210 cos_S = rij_rkj_S * nrij_1_S * nrkj_1_S;
1212 /* We compute cos^2 using a division instead of squaring cos_S,
1213 * as we would then get additional error contributions from
1214 * the two invsqrt operations, which get amplified by
1215 * the 1/sqrt(1-cos^2) for cos values close to 1.
1217 * Note that the non-SIMD version of angles() avoids this issue
1218 * by computing the cosine using double precision.
1220 cos2_S = rij_rkj_S * rij_rkj_S / (nrij2_S * nrkj2_S);
1222 /* To allow for 0 and 180 degrees, we need to avoid issues when
1223 * the cosine is close to -1 and 1. For acos() the argument needs
1224 * to be in that range. For cos^2 we take the min of cos^2 and 1 - 1bit,
1225 * so we can safely compute 1/sin as 1/sqrt(1 - cos^2).
1227 cos_S = max(cos_S, -one_S);
1228 cos_S = min(cos_S, one_S);
1229 cos2_S = min(cos2_S, one_min_eps_S);
1231 theta_S = acos(cos_S);
1233 invsin_S = invsqrt(one_S - cos2_S);
1235 st_S = k_S * (theta0_S - theta_S) * invsin_S;
1236 sth_S = st_S * cos_S;
1238 cik_S = st_S * nrij_1_S * nrkj_1_S;
1239 cii_S = sth_S * nrij_1_S * nrij_1_S;
1240 ckk_S = sth_S * nrkj_1_S * nrkj_1_S;
1242 f_ix_S = cii_S * rijx_S;
1243 f_ix_S = fnma(cik_S, rkjx_S, f_ix_S);
1244 f_iy_S = cii_S * rijy_S;
1245 f_iy_S = fnma(cik_S, rkjy_S, f_iy_S);
1246 f_iz_S = cii_S * rijz_S;
1247 f_iz_S = fnma(cik_S, rkjz_S, f_iz_S);
1248 f_kx_S = ckk_S * rkjx_S;
1249 f_kx_S = fnma(cik_S, rijx_S, f_kx_S);
1250 f_ky_S = ckk_S * rkjy_S;
1251 f_ky_S = fnma(cik_S, rijy_S, f_ky_S);
1252 f_kz_S = ckk_S * rkjz_S;
1253 f_kz_S = fnma(cik_S, rijz_S, f_kz_S);
1255 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ai, f_ix_S, f_iy_S, f_iz_S);
1256 transposeScatterDecrU<4>(
1257 reinterpret_cast<real*>(f), aj, f_ix_S + f_kx_S, f_iy_S + f_ky_S, f_iz_S + f_kz_S);
1258 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ak, f_kx_S, f_ky_S, f_kz_S);
1264 #endif // GMX_SIMD_HAVE_REAL
1266 template<BondedKernelFlavor flavor>
1267 real linear_angles(int nbonds,
1268 const t_iatom forceatoms[],
1269 const t_iparams forceparams[],
1276 const t_mdatoms gmx_unused* md,
1277 t_fcdata gmx_unused* fcd,
1278 t_disresdata gmx_unused* disresdata,
1279 t_oriresdata gmx_unused* oriresdata,
1280 int gmx_unused* global_atom_index)
1282 int i, m, ai, aj, ak, t1, t2, type;
1284 real L1, kA, kB, aA, aB, dr, dr2, va, vtot, a, b, klin;
1285 rvec r_ij, r_kj, r_ik, dx;
1289 for (i = 0; (i < nbonds);)
1291 type = forceatoms[i++];
1292 ai = forceatoms[i++];
1293 aj = forceatoms[i++];
1294 ak = forceatoms[i++];
1296 kA = forceparams[type].linangle.klinA;
1297 kB = forceparams[type].linangle.klinB;
1298 klin = L1 * kA + lambda * kB;
1300 aA = forceparams[type].linangle.aA;
1301 aB = forceparams[type].linangle.aB;
1302 a = L1 * aA + lambda * aB;
1305 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], r_ij);
1306 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], r_kj);
1307 rvec_sub(r_ij, r_kj, r_ik);
1310 for (m = 0; (m < DIM); m++)
1312 dr = -a * r_ij[m] - b * r_kj[m];
1315 f_i[m] = a * klin * dr;
1316 f_k[m] = b * klin * dr;
1317 f_j[m] = -(f_i[m] + f_k[m]);
1322 va = 0.5 * klin * dr2;
1323 *dvdlambda += 0.5 * (kB - kA) * dr2 + klin * (aB - aA) * iprod(dx, r_ik);
1327 if (computeVirial(flavor))
1329 rvec_inc(fshift[t1], f_i);
1330 rvec_inc(fshift[CENTRAL], f_j);
1331 rvec_inc(fshift[t2], f_k);
1337 template<BondedKernelFlavor flavor>
1338 std::enable_if_t<flavor != BondedKernelFlavor::ForcesSimdWhenAvailable || !GMX_SIMD_HAVE_REAL, real>
1339 urey_bradley(int nbonds,
1340 const t_iatom forceatoms[],
1341 const t_iparams forceparams[],
1348 const t_mdatoms gmx_unused* md,
1349 t_fcdata gmx_unused* fcd,
1350 t_disresdata gmx_unused* disresdata,
1351 t_oriresdata gmx_unused* oriresdata,
1352 int gmx_unused* global_atom_index)
1354 int i, m, ai, aj, ak, t1, t2, type, ki;
1355 rvec r_ij, r_kj, r_ik;
1356 real cos_theta, cos_theta2, theta;
1357 real dVdt, va, vtot, dr, dr2, vbond, fbond, fik;
1358 real kthA, th0A, kUBA, r13A, kthB, th0B, kUBB, r13B;
1361 for (i = 0; (i < nbonds);)
1363 type = forceatoms[i++];
1364 ai = forceatoms[i++];
1365 aj = forceatoms[i++];
1366 ak = forceatoms[i++];
1367 th0A = forceparams[type].u_b.thetaA * gmx::c_deg2Rad;
1368 kthA = forceparams[type].u_b.kthetaA;
1369 r13A = forceparams[type].u_b.r13A;
1370 kUBA = forceparams[type].u_b.kUBA;
1371 th0B = forceparams[type].u_b.thetaB * gmx::c_deg2Rad;
1372 kthB = forceparams[type].u_b.kthetaB;
1373 r13B = forceparams[type].u_b.r13B;
1374 kUBB = forceparams[type].u_b.kUBB;
1376 theta = bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
1378 *dvdlambda += harmonic(kthA, kthB, th0A, th0B, theta, lambda, &va, &dVdt); /* 21 */
1381 ki = pbc_rvec_sub(pbc, x[ai], x[ak], r_ik); /* 3 */
1382 dr2 = iprod(r_ik, r_ik); /* 5 */
1383 dr = dr2 * gmx::invsqrt(dr2); /* 10 */
1385 *dvdlambda += harmonic(kUBA, kUBB, r13A, r13B, dr, lambda, &vbond, &fbond); /* 19 */
1387 cos_theta2 = gmx::square(cos_theta); /* 1 */
1395 st = dVdt * gmx::invsqrt(1 - cos_theta2); /* 12 */
1396 sth = st * cos_theta; /* 1 */
1397 nrkj2 = iprod(r_kj, r_kj); /* 5 */
1398 nrij2 = iprod(r_ij, r_ij);
1400 cik = st * gmx::invsqrt(nrkj2 * nrij2); /* 12 */
1401 cii = sth / nrij2; /* 10 */
1402 ckk = sth / nrkj2; /* 10 */
1404 for (m = 0; (m < DIM); m++) /* 39 */
1406 f_i[m] = -(cik * r_kj[m] - cii * r_ij[m]);
1407 f_k[m] = -(cik * r_ij[m] - ckk * r_kj[m]);
1408 f_j[m] = -f_i[m] - f_k[m];
1413 if (computeVirial(flavor))
1415 rvec_inc(fshift[t1], f_i);
1416 rvec_inc(fshift[CENTRAL], f_j);
1417 rvec_inc(fshift[t2], f_k);
1420 /* Time for the bond calculations */
1426 vtot += vbond; /* 1*/
1427 fbond *= gmx::invsqrt(dr2); /* 6 */
1429 for (m = 0; (m < DIM); m++) /* 15 */
1431 fik = fbond * r_ik[m];
1434 if (computeVirial(flavor))
1436 fshift[ki][m] += fik;
1437 fshift[CENTRAL][m] -= fik;
1444 #if GMX_SIMD_HAVE_REAL
1446 /* As urey_bradley, but using SIMD to calculate many potentials at once.
1447 * This routines does not calculate energies and shift forces.
1449 template<BondedKernelFlavor flavor>
1450 std::enable_if_t<flavor == BondedKernelFlavor::ForcesSimdWhenAvailable, real>
1451 urey_bradley(int nbonds,
1452 const t_iatom forceatoms[],
1453 const t_iparams forceparams[],
1456 rvec gmx_unused fshift[],
1458 real gmx_unused lambda,
1459 real gmx_unused* dvdlambda,
1460 const t_mdatoms gmx_unused* md,
1461 t_fcdata gmx_unused* fcd,
1462 t_disresdata gmx_unused* disresdata,
1463 t_oriresdata gmx_unused* oriresdata,
1464 int gmx_unused* global_atom_index)
1466 constexpr int nfa1 = 4;
1467 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[GMX_SIMD_REAL_WIDTH];
1468 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[GMX_SIMD_REAL_WIDTH];
1469 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ak[GMX_SIMD_REAL_WIDTH];
1470 alignas(GMX_SIMD_ALIGNMENT) real coeff[4 * GMX_SIMD_REAL_WIDTH];
1471 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9 * GMX_SIMD_REAL_WIDTH];
1473 set_pbc_simd(pbc, pbc_simd);
1475 /* nbonds is the number of angles times nfa1, here we step GMX_SIMD_REAL_WIDTH angles */
1476 for (int i = 0; i < nbonds; i += GMX_SIMD_REAL_WIDTH * nfa1)
1478 /* Collect atoms for GMX_SIMD_REAL_WIDTH angles.
1479 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
1482 for (int s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
1484 const int type = forceatoms[iu];
1485 ai[s] = forceatoms[iu + 1];
1486 aj[s] = forceatoms[iu + 2];
1487 ak[s] = forceatoms[iu + 3];
1489 /* At the end fill the arrays with the last atoms and 0 params */
1490 if (i + s * nfa1 < nbonds)
1492 coeff[s] = forceparams[type].u_b.kthetaA;
1493 coeff[GMX_SIMD_REAL_WIDTH + s] = forceparams[type].u_b.thetaA;
1494 coeff[GMX_SIMD_REAL_WIDTH * 2 + s] = forceparams[type].u_b.kUBA;
1495 coeff[GMX_SIMD_REAL_WIDTH * 3 + s] = forceparams[type].u_b.r13A;
1497 if (iu + nfa1 < nbonds)
1505 coeff[GMX_SIMD_REAL_WIDTH + s] = 0;
1506 coeff[GMX_SIMD_REAL_WIDTH * 2 + s] = 0;
1507 coeff[GMX_SIMD_REAL_WIDTH * 3 + s] = 0;
1511 SimdReal xi_S, yi_S, zi_S;
1512 SimdReal xj_S, yj_S, zj_S;
1513 SimdReal xk_S, yk_S, zk_S;
1515 /* Store the non PBC corrected distances packed and aligned */
1516 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ai, &xi_S, &yi_S, &zi_S);
1517 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), aj, &xj_S, &yj_S, &zj_S);
1518 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ak, &xk_S, &yk_S, &zk_S);
1519 SimdReal rijx_S = xi_S - xj_S;
1520 SimdReal rijy_S = yi_S - yj_S;
1521 SimdReal rijz_S = zi_S - zj_S;
1522 SimdReal rkjx_S = xk_S - xj_S;
1523 SimdReal rkjy_S = yk_S - yj_S;
1524 SimdReal rkjz_S = zk_S - zj_S;
1525 SimdReal rikx_S = xi_S - xk_S;
1526 SimdReal riky_S = yi_S - yk_S;
1527 SimdReal rikz_S = zi_S - zk_S;
1529 const SimdReal ktheta_S = load<SimdReal>(coeff);
1530 const SimdReal theta0_S = load<SimdReal>(coeff + GMX_SIMD_REAL_WIDTH) * gmx::c_deg2Rad;
1531 const SimdReal kUB_S = load<SimdReal>(coeff + 2 * GMX_SIMD_REAL_WIDTH);
1532 const SimdReal r13_S = load<SimdReal>(coeff + 3 * GMX_SIMD_REAL_WIDTH);
1534 pbc_correct_dx_simd(&rijx_S, &rijy_S, &rijz_S, pbc_simd);
1535 pbc_correct_dx_simd(&rkjx_S, &rkjy_S, &rkjz_S, pbc_simd);
1536 pbc_correct_dx_simd(&rikx_S, &riky_S, &rikz_S, pbc_simd);
1538 const SimdReal rij_rkj_S = iprod(rijx_S, rijy_S, rijz_S, rkjx_S, rkjy_S, rkjz_S);
1540 const SimdReal dr2_S = iprod(rikx_S, riky_S, rikz_S, rikx_S, riky_S, rikz_S);
1542 const SimdReal nrij2_S = norm2(rijx_S, rijy_S, rijz_S);
1543 const SimdReal nrkj2_S = norm2(rkjx_S, rkjy_S, rkjz_S);
1545 const SimdReal nrij_1_S = invsqrt(nrij2_S);
1546 const SimdReal nrkj_1_S = invsqrt(nrkj2_S);
1547 const SimdReal invdr2_S = invsqrt(dr2_S);
1548 const SimdReal dr_S = dr2_S * invdr2_S;
1550 constexpr real min_one_plus_eps = -1.0 + 2.0 * GMX_REAL_EPS; // Smallest number > -1
1552 /* To allow for 180 degrees, we take the max of cos and -1 + 1bit,
1553 * so we can safely get the 1/sin from 1/sqrt(1 - cos^2).
1554 * This also ensures that rounding errors would cause the argument
1555 * of simdAcos to be < -1.
1556 * Note that we do not take precautions for cos(0)=1, so the bonds
1557 * in an angle should not align at an angle of 0 degrees.
1559 const SimdReal cos_S = max(rij_rkj_S * nrij_1_S * nrkj_1_S, min_one_plus_eps);
1561 const SimdReal theta_S = acos(cos_S);
1562 const SimdReal invsin_S = invsqrt(1.0 - cos_S * cos_S);
1563 const SimdReal st_S = ktheta_S * (theta0_S - theta_S) * invsin_S;
1564 const SimdReal sth_S = st_S * cos_S;
1566 const SimdReal cik_S = st_S * nrij_1_S * nrkj_1_S;
1567 const SimdReal cii_S = sth_S * nrij_1_S * nrij_1_S;
1568 const SimdReal ckk_S = sth_S * nrkj_1_S * nrkj_1_S;
1570 const SimdReal sUB_S = kUB_S * (r13_S - dr_S) * invdr2_S;
1572 const SimdReal f_ikx_S = sUB_S * rikx_S;
1573 const SimdReal f_iky_S = sUB_S * riky_S;
1574 const SimdReal f_ikz_S = sUB_S * rikz_S;
1576 const SimdReal f_ix_S = fnma(cik_S, rkjx_S, cii_S * rijx_S) + f_ikx_S;
1577 const SimdReal f_iy_S = fnma(cik_S, rkjy_S, cii_S * rijy_S) + f_iky_S;
1578 const SimdReal f_iz_S = fnma(cik_S, rkjz_S, cii_S * rijz_S) + f_ikz_S;
1579 const SimdReal f_kx_S = fnma(cik_S, rijx_S, ckk_S * rkjx_S) - f_ikx_S;
1580 const SimdReal f_ky_S = fnma(cik_S, rijy_S, ckk_S * rkjy_S) - f_iky_S;
1581 const SimdReal f_kz_S = fnma(cik_S, rijz_S, ckk_S * rkjz_S) - f_ikz_S;
1583 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ai, f_ix_S, f_iy_S, f_iz_S);
1584 transposeScatterDecrU<4>(
1585 reinterpret_cast<real*>(f), aj, f_ix_S + f_kx_S, f_iy_S + f_ky_S, f_iz_S + f_kz_S);
1586 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ak, f_kx_S, f_ky_S, f_kz_S);
1592 #endif // GMX_SIMD_HAVE_REAL
1594 template<BondedKernelFlavor flavor>
1595 real quartic_angles(int nbonds,
1596 const t_iatom forceatoms[],
1597 const t_iparams forceparams[],
1602 real gmx_unused lambda,
1603 real gmx_unused* dvdlambda,
1604 const t_mdatoms gmx_unused* md,
1605 t_fcdata gmx_unused* fcd,
1606 t_disresdata gmx_unused* disresdata,
1607 t_oriresdata gmx_unused* oriresdata,
1608 int gmx_unused* global_atom_index)
1610 int i, j, ai, aj, ak, t1, t2, type;
1612 real cos_theta, cos_theta2, theta, dt, dVdt, va, dtp, c, vtot;
1615 for (i = 0; (i < nbonds);)
1617 type = forceatoms[i++];
1618 ai = forceatoms[i++];
1619 aj = forceatoms[i++];
1620 ak = forceatoms[i++];
1622 theta = bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
1624 dt = theta - forceparams[type].qangle.theta * gmx::c_deg2Rad; /* 2 */
1627 va = forceparams[type].qangle.c[0];
1629 for (j = 1; j <= 4; j++)
1631 c = forceparams[type].qangle.c[j];
1632 dVdt -= j * c * dtp;
1640 cos_theta2 = gmx::square(cos_theta); /* 1 */
1649 st = dVdt * gmx::invsqrt(1 - cos_theta2); /* 12 */
1650 sth = st * cos_theta; /* 1 */
1651 nrkj2 = iprod(r_kj, r_kj); /* 5 */
1652 nrij2 = iprod(r_ij, r_ij);
1654 cik = st * gmx::invsqrt(nrkj2 * nrij2); /* 12 */
1655 cii = sth / nrij2; /* 10 */
1656 ckk = sth / nrkj2; /* 10 */
1658 for (m = 0; (m < DIM); m++) /* 39 */
1660 f_i[m] = -(cik * r_kj[m] - cii * r_ij[m]);
1661 f_k[m] = -(cik * r_ij[m] - ckk * r_kj[m]);
1662 f_j[m] = -f_i[m] - f_k[m];
1668 if (computeVirial(flavor))
1670 rvec_inc(fshift[t1], f_i);
1671 rvec_inc(fshift[CENTRAL], f_j);
1672 rvec_inc(fshift[t2], f_k);
1680 #if GMX_SIMD_HAVE_REAL
1682 /* As dih_angle above, but calculates 4 dihedral angles at once using SIMD,
1683 * also calculates the pre-factor required for the dihedral force update.
1684 * Note that bv and buf should be register aligned.
1686 inline void dih_angle_simd(const rvec* x,
1691 const real* pbc_simd,
1699 SimdReal* nrkj_m2_S,
1700 SimdReal* nrkj_n2_S,
1704 SimdReal xi_S, yi_S, zi_S;
1705 SimdReal xj_S, yj_S, zj_S;
1706 SimdReal xk_S, yk_S, zk_S;
1707 SimdReal xl_S, yl_S, zl_S;
1708 SimdReal rijx_S, rijy_S, rijz_S;
1709 SimdReal rkjx_S, rkjy_S, rkjz_S;
1710 SimdReal rklx_S, rkly_S, rklz_S;
1711 SimdReal cx_S, cy_S, cz_S;
1715 SimdReal iprm_S, iprn_S;
1716 SimdReal nrkj2_S, nrkj_1_S, nrkj_2_S, nrkj_S;
1718 SimdReal nrkj2_min_S;
1719 SimdReal real_eps_S;
1721 /* Used to avoid division by zero.
1722 * We take into acount that we multiply the result by real_eps_S.
1724 nrkj2_min_S = SimdReal(GMX_REAL_MIN / (2 * GMX_REAL_EPS));
1726 /* The value of the last significant bit (GMX_REAL_EPS is half of that) */
1727 real_eps_S = SimdReal(2 * GMX_REAL_EPS);
1729 /* Store the non PBC corrected distances packed and aligned */
1730 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ai, &xi_S, &yi_S, &zi_S);
1731 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), aj, &xj_S, &yj_S, &zj_S);
1732 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ak, &xk_S, &yk_S, &zk_S);
1733 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), al, &xl_S, &yl_S, &zl_S);
1734 rijx_S = xi_S - xj_S;
1735 rijy_S = yi_S - yj_S;
1736 rijz_S = zi_S - zj_S;
1737 rkjx_S = xk_S - xj_S;
1738 rkjy_S = yk_S - yj_S;
1739 rkjz_S = zk_S - zj_S;
1740 rklx_S = xk_S - xl_S;
1741 rkly_S = yk_S - yl_S;
1742 rklz_S = zk_S - zl_S;
1744 pbc_correct_dx_simd(&rijx_S, &rijy_S, &rijz_S, pbc_simd);
1745 pbc_correct_dx_simd(&rkjx_S, &rkjy_S, &rkjz_S, pbc_simd);
1746 pbc_correct_dx_simd(&rklx_S, &rkly_S, &rklz_S, pbc_simd);
1748 cprod(rijx_S, rijy_S, rijz_S, rkjx_S, rkjy_S, rkjz_S, mx_S, my_S, mz_S);
1750 cprod(rkjx_S, rkjy_S, rkjz_S, rklx_S, rkly_S, rklz_S, nx_S, ny_S, nz_S);
1752 cprod(*mx_S, *my_S, *mz_S, *nx_S, *ny_S, *nz_S, &cx_S, &cy_S, &cz_S);
1754 cn_S = sqrt(norm2(cx_S, cy_S, cz_S));
1756 s_S = iprod(*mx_S, *my_S, *mz_S, *nx_S, *ny_S, *nz_S);
1758 /* Determine the dihedral angle, the sign might need correction */
1759 *phi_S = atan2(cn_S, s_S);
1761 ipr_S = iprod(rijx_S, rijy_S, rijz_S, *nx_S, *ny_S, *nz_S);
1763 iprm_S = norm2(*mx_S, *my_S, *mz_S);
1764 iprn_S = norm2(*nx_S, *ny_S, *nz_S);
1766 nrkj2_S = norm2(rkjx_S, rkjy_S, rkjz_S);
1768 /* Avoid division by zero. When zero, the result is multiplied by 0
1769 * anyhow, so the 3 max below do not affect the final result.
1771 nrkj2_S = max(nrkj2_S, nrkj2_min_S);
1772 nrkj_1_S = invsqrt(nrkj2_S);
1773 nrkj_2_S = nrkj_1_S * nrkj_1_S;
1774 nrkj_S = nrkj2_S * nrkj_1_S;
1776 toler_S = nrkj2_S * real_eps_S;
1778 /* Here the plain-C code uses a conditional, but we can't do that in SIMD.
1779 * So we take a max with the tolerance instead. Since we multiply with
1780 * m or n later, the max does not affect the results.
1782 iprm_S = max(iprm_S, toler_S);
1783 iprn_S = max(iprn_S, toler_S);
1784 *nrkj_m2_S = nrkj_S * inv(iprm_S);
1785 *nrkj_n2_S = nrkj_S * inv(iprn_S);
1787 /* Set sign of phi_S with the sign of ipr_S; phi_S is currently positive */
1788 *phi_S = copysign(*phi_S, ipr_S);
1789 *p_S = iprod(rijx_S, rijy_S, rijz_S, rkjx_S, rkjy_S, rkjz_S);
1790 *p_S = *p_S * nrkj_2_S;
1792 *q_S = iprod(rklx_S, rkly_S, rklz_S, rkjx_S, rkjy_S, rkjz_S);
1793 *q_S = *q_S * nrkj_2_S;
1796 #endif // GMX_SIMD_HAVE_REAL
1800 template<BondedKernelFlavor flavor>
1801 void do_dih_fup(int i,
1820 rvec f_i, f_j, f_k, f_l;
1821 rvec uvec, vvec, svec, dx_jl;
1822 real iprm, iprn, nrkj, nrkj2, nrkj_1, nrkj_2;
1823 real a, b, p, q, toler;
1825 iprm = iprod(m, m); /* 5 */
1826 iprn = iprod(n, n); /* 5 */
1827 nrkj2 = iprod(r_kj, r_kj); /* 5 */
1828 toler = nrkj2 * GMX_REAL_EPS;
1829 if ((iprm > toler) && (iprn > toler))
1831 nrkj_1 = gmx::invsqrt(nrkj2); /* 10 */
1832 nrkj_2 = nrkj_1 * nrkj_1; /* 1 */
1833 nrkj = nrkj2 * nrkj_1; /* 1 */
1834 a = -ddphi * nrkj / iprm; /* 11 */
1835 svmul(a, m, f_i); /* 3 */
1836 b = ddphi * nrkj / iprn; /* 11 */
1837 svmul(b, n, f_l); /* 3 */
1838 p = iprod(r_ij, r_kj); /* 5 */
1839 p *= nrkj_2; /* 1 */
1840 q = iprod(r_kl, r_kj); /* 5 */
1841 q *= nrkj_2; /* 1 */
1842 svmul(p, f_i, uvec); /* 3 */
1843 svmul(q, f_l, vvec); /* 3 */
1844 rvec_sub(uvec, vvec, svec); /* 3 */
1845 rvec_sub(f_i, svec, f_j); /* 3 */
1846 rvec_add(f_l, svec, f_k); /* 3 */
1847 rvec_inc(f[i], f_i); /* 3 */
1848 rvec_dec(f[j], f_j); /* 3 */
1849 rvec_dec(f[k], f_k); /* 3 */
1850 rvec_inc(f[l], f_l); /* 3 */
1852 if (computeVirial(flavor))
1856 t3 = pbc_rvec_sub(pbc, x[l], x[j], dx_jl);
1863 rvec_inc(fshift[t1], f_i);
1864 rvec_dec(fshift[CENTRAL], f_j);
1865 rvec_dec(fshift[t2], f_k);
1866 rvec_inc(fshift[t3], f_l);
1875 #if GMX_SIMD_HAVE_REAL
1876 /* As do_dih_fup_noshiftf above, but with SIMD and pre-calculated pre-factors */
1877 inline void gmx_simdcall do_dih_fup_noshiftf_simd(const int* ai,
1891 SimdReal sx = p * f_i_x + q * mf_l_x;
1892 SimdReal sy = p * f_i_y + q * mf_l_y;
1893 SimdReal sz = p * f_i_z + q * mf_l_z;
1894 SimdReal f_j_x = f_i_x - sx;
1895 SimdReal f_j_y = f_i_y - sy;
1896 SimdReal f_j_z = f_i_z - sz;
1897 SimdReal f_k_x = mf_l_x - sx;
1898 SimdReal f_k_y = mf_l_y - sy;
1899 SimdReal f_k_z = mf_l_z - sz;
1900 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ai, f_i_x, f_i_y, f_i_z);
1901 transposeScatterDecrU<4>(reinterpret_cast<real*>(f), aj, f_j_x, f_j_y, f_j_z);
1902 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ak, f_k_x, f_k_y, f_k_z);
1903 transposeScatterDecrU<4>(reinterpret_cast<real*>(f), al, mf_l_x, mf_l_y, mf_l_z);
1905 #endif // GMX_SIMD_HAVE_REAL
1907 /*! \brief Computes and returns the proper dihedral force
1909 * With the appropriate kernel flavor, also computes and accumulates
1910 * the energy and dV/dlambda.
1912 template<BondedKernelFlavor flavor>
1913 real dopdihs(real cpA, real cpB, real phiA, real phiB, int mult, real phi, real lambda, real* V, real* dvdlambda)
1915 const real L1 = 1.0 - lambda;
1916 const real ph0 = (L1 * phiA + lambda * phiB) * gmx::c_deg2Rad;
1917 const real dph0 = (phiB - phiA) * gmx::c_deg2Rad;
1918 const real cp = L1 * cpA + lambda * cpB;
1920 const real mdphi = mult * phi - ph0;
1921 const real sdphi = std::sin(mdphi);
1922 const real ddphi = -cp * mult * sdphi;
1923 if (computeEnergy(flavor))
1925 const real v1 = 1 + std::cos(mdphi);
1928 *dvdlambda += (cpB - cpA) * v1 + cp * dph0 * sdphi;
1932 /* That was 40 flops */
1935 /*! \brief Similar to \p dopdihs(), except for a minus sign and a different treatment of mult/phi0 */
1936 real dopdihs_min(real cpA, real cpB, real phiA, real phiB, int mult, real phi, real lambda, real* V, real* F)
1938 real v, dvdlambda, mdphi, v1, sdphi, ddphi;
1939 real L1 = 1.0 - lambda;
1940 real ph0 = (L1 * phiA + lambda * phiB) * gmx::c_deg2Rad;
1941 real dph0 = (phiB - phiA) * gmx::c_deg2Rad;
1942 real cp = L1 * cpA + lambda * cpB;
1944 mdphi = mult * (phi - ph0);
1945 sdphi = std::sin(mdphi);
1946 ddphi = cp * mult * sdphi;
1947 v1 = 1.0 - std::cos(mdphi);
1950 dvdlambda = (cpB - cpA) * v1 + cp * dph0 * sdphi;
1957 /* That was 40 flops */
1960 template<BondedKernelFlavor flavor>
1961 std::enable_if_t<flavor != BondedKernelFlavor::ForcesSimdWhenAvailable || !GMX_SIMD_HAVE_REAL, real>
1963 const t_iatom forceatoms[],
1964 const t_iparams forceparams[],
1971 const t_mdatoms gmx_unused* md,
1972 t_fcdata gmx_unused* fcd,
1973 t_disresdata gmx_unused* disresdata,
1974 t_oriresdata gmx_unused* oriresdata,
1975 int gmx_unused* global_atom_index)
1978 rvec r_ij, r_kj, r_kl, m, n;
1982 for (int i = 0; i < nbonds;)
1984 const int ai = forceatoms[i + 1];
1985 const int aj = forceatoms[i + 2];
1986 const int ak = forceatoms[i + 3];
1987 const int al = forceatoms[i + 4];
1990 dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3); /* 84 */
1992 /* Loop over dihedrals working on the same atoms,
1993 * so we avoid recalculating angles and distributing forces.
1998 const int type = forceatoms[i];
1999 ddphi_tot += dopdihs<flavor>(forceparams[type].pdihs.cpA,
2000 forceparams[type].pdihs.cpB,
2001 forceparams[type].pdihs.phiA,
2002 forceparams[type].pdihs.phiB,
2003 forceparams[type].pdihs.mult,
2010 } while (i < nbonds && forceatoms[i + 1] == ai && forceatoms[i + 2] == aj
2011 && forceatoms[i + 3] == ak && forceatoms[i + 4] == al);
2014 ai, aj, ak, al, ddphi_tot, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1, t2, t3); /* 112 */
2020 #if GMX_SIMD_HAVE_REAL
2022 /* As pdihs above, but using SIMD to calculate multiple dihedrals at once */
2023 template<BondedKernelFlavor flavor>
2024 std::enable_if_t<flavor == BondedKernelFlavor::ForcesSimdWhenAvailable, real>
2026 const t_iatom forceatoms[],
2027 const t_iparams forceparams[],
2030 rvec gmx_unused fshift[],
2032 real gmx_unused lambda,
2033 real gmx_unused* dvdlambda,
2034 const t_mdatoms gmx_unused* md,
2035 t_fcdata gmx_unused* fcd,
2036 t_disresdata gmx_unused* disresdata,
2037 t_oriresdata gmx_unused* oriresdata,
2038 int gmx_unused* global_atom_index)
2043 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[GMX_SIMD_REAL_WIDTH];
2044 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[GMX_SIMD_REAL_WIDTH];
2045 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ak[GMX_SIMD_REAL_WIDTH];
2046 alignas(GMX_SIMD_ALIGNMENT) std::int32_t al[GMX_SIMD_REAL_WIDTH];
2047 alignas(GMX_SIMD_ALIGNMENT) real buf[3 * GMX_SIMD_REAL_WIDTH];
2048 real * cp, *phi0, *mult;
2049 SimdReal deg2rad_S(gmx::c_deg2Rad);
2051 SimdReal phi0_S, phi_S;
2052 SimdReal mx_S, my_S, mz_S;
2053 SimdReal nx_S, ny_S, nz_S;
2054 SimdReal nrkj_m2_S, nrkj_n2_S;
2055 SimdReal cp_S, mdphi_S, mult_S;
2056 SimdReal sin_S, cos_S;
2058 SimdReal sf_i_S, msf_l_S;
2059 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9 * GMX_SIMD_REAL_WIDTH];
2061 /* Extract aligned pointer for parameters and variables */
2062 cp = buf + 0 * GMX_SIMD_REAL_WIDTH;
2063 phi0 = buf + 1 * GMX_SIMD_REAL_WIDTH;
2064 mult = buf + 2 * GMX_SIMD_REAL_WIDTH;
2066 set_pbc_simd(pbc, pbc_simd);
2068 /* nbonds is the number of dihedrals times nfa1, here we step GMX_SIMD_REAL_WIDTH dihs */
2069 for (i = 0; (i < nbonds); i += GMX_SIMD_REAL_WIDTH * nfa1)
2071 /* Collect atoms quadruplets for GMX_SIMD_REAL_WIDTH dihedrals.
2072 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
2075 for (s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
2077 type = forceatoms[iu];
2078 ai[s] = forceatoms[iu + 1];
2079 aj[s] = forceatoms[iu + 2];
2080 ak[s] = forceatoms[iu + 3];
2081 al[s] = forceatoms[iu + 4];
2083 /* At the end fill the arrays with the last atoms and 0 params */
2084 if (i + s * nfa1 < nbonds)
2086 cp[s] = forceparams[type].pdihs.cpA;
2087 phi0[s] = forceparams[type].pdihs.phiA;
2088 mult[s] = forceparams[type].pdihs.mult;
2090 if (iu + nfa1 < nbonds)
2103 /* Calculate GMX_SIMD_REAL_WIDTH dihedral angles at once */
2105 x, ai, aj, ak, al, pbc_simd, &phi_S, &mx_S, &my_S, &mz_S, &nx_S, &ny_S, &nz_S, &nrkj_m2_S, &nrkj_n2_S, &p_S, &q_S);
2107 cp_S = load<SimdReal>(cp);
2108 phi0_S = load<SimdReal>(phi0) * deg2rad_S;
2109 mult_S = load<SimdReal>(mult);
2111 mdphi_S = fms(mult_S, phi_S, phi0_S);
2113 /* Calculate GMX_SIMD_REAL_WIDTH sines at once */
2114 sincos(mdphi_S, &sin_S, &cos_S);
2115 mddphi_S = cp_S * mult_S * sin_S;
2116 sf_i_S = mddphi_S * nrkj_m2_S;
2117 msf_l_S = mddphi_S * nrkj_n2_S;
2119 /* After this m?_S will contain f[i] */
2120 mx_S = sf_i_S * mx_S;
2121 my_S = sf_i_S * my_S;
2122 mz_S = sf_i_S * mz_S;
2124 /* After this m?_S will contain -f[l] */
2125 nx_S = msf_l_S * nx_S;
2126 ny_S = msf_l_S * ny_S;
2127 nz_S = msf_l_S * nz_S;
2129 do_dih_fup_noshiftf_simd(ai, aj, ak, al, p_S, q_S, mx_S, my_S, mz_S, nx_S, ny_S, nz_S, f);
2135 /* This is mostly a copy of the SIMD flavor of pdihs above, but with using
2136 * the RB potential instead of a harmonic potential.
2137 * This function can replace rbdihs() when no energy and virial are needed.
2139 template<BondedKernelFlavor flavor>
2140 std::enable_if_t<flavor == BondedKernelFlavor::ForcesSimdWhenAvailable, real>
2142 const t_iatom forceatoms[],
2143 const t_iparams forceparams[],
2146 rvec gmx_unused fshift[],
2148 real gmx_unused lambda,
2149 real gmx_unused* dvdlambda,
2150 const t_mdatoms gmx_unused* md,
2151 t_fcdata gmx_unused* fcd,
2152 t_disresdata gmx_unused* disresdata,
2153 t_oriresdata gmx_unused* oriresdata,
2154 int gmx_unused* global_atom_index)
2159 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[GMX_SIMD_REAL_WIDTH];
2160 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[GMX_SIMD_REAL_WIDTH];
2161 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ak[GMX_SIMD_REAL_WIDTH];
2162 alignas(GMX_SIMD_ALIGNMENT) std::int32_t al[GMX_SIMD_REAL_WIDTH];
2163 alignas(GMX_SIMD_ALIGNMENT) real parm[NR_RBDIHS * GMX_SIMD_REAL_WIDTH];
2167 SimdReal ddphi_S, cosfac_S;
2168 SimdReal mx_S, my_S, mz_S;
2169 SimdReal nx_S, ny_S, nz_S;
2170 SimdReal nrkj_m2_S, nrkj_n2_S;
2171 SimdReal parm_S, c_S;
2172 SimdReal sin_S, cos_S;
2173 SimdReal sf_i_S, msf_l_S;
2174 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9 * GMX_SIMD_REAL_WIDTH];
2176 SimdReal pi_S(M_PI);
2177 SimdReal one_S(1.0);
2179 set_pbc_simd(pbc, pbc_simd);
2181 /* nbonds is the number of dihedrals times nfa1, here we step GMX_SIMD_REAL_WIDTH dihs */
2182 for (i = 0; (i < nbonds); i += GMX_SIMD_REAL_WIDTH * nfa1)
2184 /* Collect atoms quadruplets for GMX_SIMD_REAL_WIDTH dihedrals.
2185 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
2188 for (s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
2190 type = forceatoms[iu];
2191 ai[s] = forceatoms[iu + 1];
2192 aj[s] = forceatoms[iu + 2];
2193 ak[s] = forceatoms[iu + 3];
2194 al[s] = forceatoms[iu + 4];
2196 /* At the end fill the arrays with the last atoms and 0 params */
2197 if (i + s * nfa1 < nbonds)
2199 /* We don't need the first parameter, since that's a constant
2200 * which only affects the energies, not the forces.
2202 for (j = 1; j < NR_RBDIHS; j++)
2204 parm[j * GMX_SIMD_REAL_WIDTH + s] = forceparams[type].rbdihs.rbcA[j];
2207 if (iu + nfa1 < nbonds)
2214 for (j = 1; j < NR_RBDIHS; j++)
2216 parm[j * GMX_SIMD_REAL_WIDTH + s] = 0;
2221 /* Calculate GMX_SIMD_REAL_WIDTH dihedral angles at once */
2223 x, ai, aj, ak, al, pbc_simd, &phi_S, &mx_S, &my_S, &mz_S, &nx_S, &ny_S, &nz_S, &nrkj_m2_S, &nrkj_n2_S, &p_S, &q_S);
2225 /* Change to polymer convention */
2226 phi_S = phi_S - pi_S;
2228 sincos(phi_S, &sin_S, &cos_S);
2230 ddphi_S = setZero();
2233 for (j = 1; j < NR_RBDIHS; j++)
2235 parm_S = load<SimdReal>(parm + j * GMX_SIMD_REAL_WIDTH);
2236 ddphi_S = fma(c_S * parm_S, cosfac_S, ddphi_S);
2237 cosfac_S = cosfac_S * cos_S;
2241 /* Note that here we do not use the minus sign which is present
2242 * in the normal RB code. This is corrected for through (m)sf below.
2244 ddphi_S = ddphi_S * sin_S;
2246 sf_i_S = ddphi_S * nrkj_m2_S;
2247 msf_l_S = ddphi_S * nrkj_n2_S;
2249 /* After this m?_S will contain f[i] */
2250 mx_S = sf_i_S * mx_S;
2251 my_S = sf_i_S * my_S;
2252 mz_S = sf_i_S * mz_S;
2254 /* After this m?_S will contain -f[l] */
2255 nx_S = msf_l_S * nx_S;
2256 ny_S = msf_l_S * ny_S;
2257 nz_S = msf_l_S * nz_S;
2259 do_dih_fup_noshiftf_simd(ai, aj, ak, al, p_S, q_S, mx_S, my_S, mz_S, nx_S, ny_S, nz_S, f);
2265 #endif // GMX_SIMD_HAVE_REAL
2268 template<BondedKernelFlavor flavor>
2269 real idihs(int nbonds,
2270 const t_iatom forceatoms[],
2271 const t_iparams forceparams[],
2278 const t_mdatoms gmx_unused* md,
2279 t_fcdata gmx_unused* fcd,
2280 t_disresdata gmx_unused* disresdata,
2281 t_oriresdata gmx_unused* oriresdata,
2282 int gmx_unused* global_atom_index)
2284 int i, type, ai, aj, ak, al;
2286 real phi, phi0, dphi0, ddphi, vtot;
2287 rvec r_ij, r_kj, r_kl, m, n;
2288 real L1, kk, dp, dp2, kA, kB, pA, pB, dvdl_term;
2293 for (i = 0; (i < nbonds);)
2295 type = forceatoms[i++];
2296 ai = forceatoms[i++];
2297 aj = forceatoms[i++];
2298 ak = forceatoms[i++];
2299 al = forceatoms[i++];
2301 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3); /* 84 */
2303 /* phi can jump if phi0 is close to Pi/-Pi, which will cause huge
2304 * force changes if we just apply a normal harmonic.
2305 * Instead, we first calculate phi-phi0 and take it modulo (-Pi,Pi).
2306 * This means we will never have the periodicity problem, unless
2307 * the dihedral is Pi away from phiO, which is very unlikely due to
2310 kA = forceparams[type].harmonic.krA;
2311 kB = forceparams[type].harmonic.krB;
2312 pA = forceparams[type].harmonic.rA;
2313 pB = forceparams[type].harmonic.rB;
2315 kk = L1 * kA + lambda * kB;
2316 phi0 = (L1 * pA + lambda * pB) * gmx::c_deg2Rad;
2317 dphi0 = (pB - pA) * gmx::c_deg2Rad;
2321 make_dp_periodic(&dp);
2325 vtot += 0.5 * kk * dp2;
2328 dvdl_term += 0.5 * (kB - kA) * dp2 - kk * dphi0 * dp;
2330 do_dih_fup<flavor>(ai, aj, ak, al, -ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1, t2, t3); /* 112 */
2334 *dvdlambda += dvdl_term;
2338 /*! \brief Computes angle restraints of two different types */
2339 template<BondedKernelFlavor flavor>
2340 real low_angres(int nbonds,
2341 const t_iatom forceatoms[],
2342 const t_iparams forceparams[],
2351 int i, m, type, ai, aj, ak, al;
2353 real phi, cos_phi, cos_phi2, vid, vtot, dVdphi;
2354 rvec r_ij, r_kl, f_i, f_k = { 0, 0, 0 };
2355 real st, sth, nrij2, nrkl2, c, cij, ckl;
2357 t2 = 0; /* avoid warning with gcc-3.3. It is never used uninitialized */
2360 ak = al = 0; /* to avoid warnings */
2361 for (i = 0; i < nbonds;)
2363 type = forceatoms[i++];
2364 ai = forceatoms[i++];
2365 aj = forceatoms[i++];
2366 t1 = pbc_rvec_sub(pbc, x[aj], x[ai], r_ij); /* 3 */
2369 ak = forceatoms[i++];
2370 al = forceatoms[i++];
2371 t2 = pbc_rvec_sub(pbc, x[al], x[ak], r_kl); /* 3 */
2380 cos_phi = cos_angle(r_ij, r_kl); /* 25 */
2381 phi = std::acos(cos_phi); /* 10 */
2383 *dvdlambda += dopdihs_min(forceparams[type].pdihs.cpA,
2384 forceparams[type].pdihs.cpB,
2385 forceparams[type].pdihs.phiA,
2386 forceparams[type].pdihs.phiB,
2387 forceparams[type].pdihs.mult,
2395 cos_phi2 = gmx::square(cos_phi); /* 1 */
2398 st = -dVdphi * gmx::invsqrt(1 - cos_phi2); /* 12 */
2399 sth = st * cos_phi; /* 1 */
2400 nrij2 = iprod(r_ij, r_ij); /* 5 */
2401 nrkl2 = iprod(r_kl, r_kl); /* 5 */
2403 c = st * gmx::invsqrt(nrij2 * nrkl2); /* 11 */
2404 cij = sth / nrij2; /* 10 */
2405 ckl = sth / nrkl2; /* 10 */
2407 for (m = 0; m < DIM; m++) /* 18+18 */
2409 f_i[m] = (c * r_kl[m] - cij * r_ij[m]);
2414 f_k[m] = (c * r_ij[m] - ckl * r_kl[m]);
2420 if (computeVirial(flavor))
2422 rvec_inc(fshift[t1], f_i);
2423 rvec_dec(fshift[CENTRAL], f_i);
2426 rvec_inc(fshift[t2], f_k);
2427 rvec_dec(fshift[CENTRAL], f_k);
2433 return vtot; /* 184 / 157 (bZAxis) total */
2436 template<BondedKernelFlavor flavor>
2437 real angres(int nbonds,
2438 const t_iatom forceatoms[],
2439 const t_iparams forceparams[],
2446 const t_mdatoms gmx_unused* md,
2447 t_fcdata gmx_unused* fcd,
2448 t_disresdata gmx_unused* disresdata,
2449 t_oriresdata gmx_unused* oriresdata,
2450 int gmx_unused* global_atom_index)
2452 return low_angres<flavor>(nbonds, forceatoms, forceparams, x, f, fshift, pbc, lambda, dvdlambda, FALSE);
2455 template<BondedKernelFlavor flavor>
2456 real angresz(int nbonds,
2457 const t_iatom forceatoms[],
2458 const t_iparams forceparams[],
2465 const t_mdatoms gmx_unused* md,
2466 t_fcdata gmx_unused* fcd,
2467 t_disresdata gmx_unused* disresdata,
2468 t_oriresdata gmx_unused* oriresdata,
2469 int gmx_unused* global_atom_index)
2471 return low_angres<flavor>(nbonds, forceatoms, forceparams, x, f, fshift, pbc, lambda, dvdlambda, TRUE);
2474 template<BondedKernelFlavor flavor>
2475 real dihres(int nbonds,
2476 const t_iatom forceatoms[],
2477 const t_iparams forceparams[],
2484 const t_mdatoms gmx_unused* md,
2485 t_fcdata gmx_unused* fcd,
2486 t_disresdata gmx_unused* disresdata,
2487 t_oriresdata gmx_unused* oriresdata,
2488 int gmx_unused* global_atom_index)
2491 int ai, aj, ak, al, i, type, t1, t2, t3;
2492 real phi0A, phi0B, dphiA, dphiB, kfacA, kfacB, phi0, dphi, kfac;
2493 real phi, ddphi, ddp, ddp2, dp, d2r, L1;
2494 rvec r_ij, r_kj, r_kl, m, n;
2498 d2r = gmx::c_deg2Rad;
2500 for (i = 0; (i < nbonds);)
2502 type = forceatoms[i++];
2503 ai = forceatoms[i++];
2504 aj = forceatoms[i++];
2505 ak = forceatoms[i++];
2506 al = forceatoms[i++];
2508 phi0A = forceparams[type].dihres.phiA * d2r;
2509 dphiA = forceparams[type].dihres.dphiA * d2r;
2510 kfacA = forceparams[type].dihres.kfacA;
2512 phi0B = forceparams[type].dihres.phiB * d2r;
2513 dphiB = forceparams[type].dihres.dphiB * d2r;
2514 kfacB = forceparams[type].dihres.kfacB;
2516 phi0 = L1 * phi0A + lambda * phi0B;
2517 dphi = L1 * dphiA + lambda * dphiB;
2518 kfac = L1 * kfacA + lambda * kfacB;
2520 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3);
2523 /* phi can jump if phi0 is close to Pi/-Pi, which will cause huge
2524 * force changes if we just apply a normal harmonic.
2525 * Instead, we first calculate phi-phi0 and take it modulo (-Pi,Pi).
2526 * This means we will never have the periodicity problem, unless
2527 * the dihedral is Pi away from phiO, which is very unlikely due to
2531 make_dp_periodic(&dp);
2537 else if (dp < -dphi)
2549 vtot += 0.5 * kfac * ddp2;
2552 *dvdlambda += 0.5 * (kfacB - kfacA) * ddp2;
2553 /* lambda dependence from changing restraint distances */
2556 *dvdlambda -= kfac * ddp * ((dphiB - dphiA) + (phi0B - phi0A));
2560 *dvdlambda += kfac * ddp * ((dphiB - dphiA) - (phi0B - phi0A));
2563 ai, aj, ak, al, ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1, t2, t3); /* 112 */
2570 real unimplemented(int gmx_unused nbonds,
2571 const t_iatom gmx_unused forceatoms[],
2572 const t_iparams gmx_unused forceparams[],
2573 const rvec gmx_unused x[],
2574 rvec4 gmx_unused f[],
2575 rvec gmx_unused fshift[],
2576 const t_pbc gmx_unused* pbc,
2577 real gmx_unused lambda,
2578 real gmx_unused* dvdlambda,
2579 const t_mdatoms gmx_unused* md,
2580 t_fcdata gmx_unused* fcd,
2581 t_disresdata gmx_unused* disresdata,
2582 t_oriresdata gmx_unused* oriresdata,
2583 int gmx_unused* global_atom_index)
2585 gmx_impl("*** you are using a not implemented function");
2588 template<BondedKernelFlavor flavor>
2589 real restrangles(int nbonds,
2590 const t_iatom forceatoms[],
2591 const t_iparams forceparams[],
2596 real gmx_unused lambda,
2597 real gmx_unused* dvdlambda,
2598 const t_mdatoms gmx_unused* md,
2599 t_fcdata gmx_unused* fcd,
2600 t_disresdata gmx_unused* disresdata,
2601 t_oriresdata gmx_unused* oriresdata,
2602 int gmx_unused* global_atom_index)
2604 int i, d, ai, aj, ak, type, m;
2608 double prefactor, ratio_ante, ratio_post;
2609 rvec delta_ante, delta_post, vec_temp;
2612 for (i = 0; (i < nbonds);)
2614 type = forceatoms[i++];
2615 ai = forceatoms[i++];
2616 aj = forceatoms[i++];
2617 ak = forceatoms[i++];
2619 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], vec_temp);
2620 pbc_rvec_sub(pbc, x[aj], x[ai], delta_ante);
2621 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], delta_post);
2624 /* This function computes factors needed for restricted angle potential.
2625 * The restricted angle potential is used in coarse-grained simulations to avoid singularities
2626 * when three particles align and the dihedral angle and dihedral potential
2627 * cannot be calculated. This potential is calculated using the formula:
2628 real restrangles(int nbonds,
2629 const t_iatom forceatoms[],const t_iparams forceparams[],
2630 const rvec x[],rvec4 f[],rvec fshift[],
2632 real gmx_unused lambda,real gmx_unused *dvdlambda,
2633 const t_mdatoms gmx_unused *md,t_fcdata gmx_unused *fcd,
2634 int gmx_unused *global_atom_index)
2636 int i, d, ai, aj, ak, type, m;
2641 real prefactor, ratio_ante, ratio_post;
2642 rvec delta_ante, delta_post, vec_temp;
2645 for(i=0; (i<nbonds); )
2647 type = forceatoms[i++];
2648 ai = forceatoms[i++];
2649 aj = forceatoms[i++];
2650 ak = forceatoms[i++];
2652 * \f[V_{\rm ReB}(\theta_i) = \frac{1}{2} k_{\theta} \frac{(\cos\theta_i - \cos\theta_0)^2}
2653 * {\sin^2\theta_i}\f] ({eq:ReB} and ref \cite{MonicaGoga2013} from the manual).
2654 * For more explanations see comments file "restcbt.h". */
2656 compute_factors_restangles(
2657 type, forceparams, delta_ante, delta_post, &prefactor, &ratio_ante, &ratio_post, &v);
2659 /* Forces are computed per component */
2660 for (d = 0; d < DIM; d++)
2662 f_i[d] = prefactor * (ratio_ante * delta_ante[d] - delta_post[d]);
2664 * ((ratio_post + 1.0) * delta_post[d] - (ratio_ante + 1.0) * delta_ante[d]);
2665 f_k[d] = prefactor * (delta_ante[d] - ratio_post * delta_post[d]);
2668 /* Computation of potential energy */
2674 for (m = 0; (m < DIM); m++)
2681 if (computeVirial(flavor))
2683 rvec_inc(fshift[t1], f_i);
2684 rvec_inc(fshift[CENTRAL], f_j);
2685 rvec_inc(fshift[t2], f_k);
2692 template<BondedKernelFlavor flavor>
2693 real restrdihs(int nbonds,
2694 const t_iatom forceatoms[],
2695 const t_iparams forceparams[],
2700 real gmx_unused lambda,
2701 real gmx_unused* dvlambda,
2702 const t_mdatoms gmx_unused* md,
2703 t_fcdata gmx_unused* fcd,
2704 t_disresdata gmx_unused* disresdata,
2705 t_oriresdata gmx_unused* oriresdata,
2706 int gmx_unused* global_atom_index)
2708 int i, d, type, ai, aj, ak, al;
2709 rvec f_i, f_j, f_k, f_l;
2713 rvec delta_ante, delta_crnt, delta_post, vec_temp;
2714 real factor_phi_ai_ante, factor_phi_ai_crnt, factor_phi_ai_post;
2715 real factor_phi_aj_ante, factor_phi_aj_crnt, factor_phi_aj_post;
2716 real factor_phi_ak_ante, factor_phi_ak_crnt, factor_phi_ak_post;
2717 real factor_phi_al_ante, factor_phi_al_crnt, factor_phi_al_post;
2722 for (i = 0; (i < nbonds);)
2724 type = forceatoms[i++];
2725 ai = forceatoms[i++];
2726 aj = forceatoms[i++];
2727 ak = forceatoms[i++];
2728 al = forceatoms[i++];
2730 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], vec_temp);
2731 pbc_rvec_sub(pbc, x[aj], x[ai], delta_ante);
2732 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], delta_crnt);
2733 pbc_rvec_sub(pbc, x[ak], x[al], vec_temp);
2734 pbc_rvec_sub(pbc, x[al], x[ak], delta_post);
2736 /* This function computes factors needed for restricted angle potential.
2737 * The restricted angle potential is used in coarse-grained simulations to avoid singularities
2738 * when three particles align and the dihedral angle and dihedral potential cannot be calculated.
2739 * This potential is calculated using the formula:
2740 * \f[V_{\rm ReB}(\theta_i) = \frac{1}{2} k_{\theta}
2741 * \frac{(\cos\theta_i - \cos\theta_0)^2}{\sin^2\theta_i}\f]
2742 * ({eq:ReB} and ref \cite{MonicaGoga2013} from the manual).
2743 * For more explanations see comments file "restcbt.h" */
2745 compute_factors_restrdihs(type,
2750 &factor_phi_ai_ante,
2751 &factor_phi_ai_crnt,
2752 &factor_phi_ai_post,
2753 &factor_phi_aj_ante,
2754 &factor_phi_aj_crnt,
2755 &factor_phi_aj_post,
2756 &factor_phi_ak_ante,
2757 &factor_phi_ak_crnt,
2758 &factor_phi_ak_post,
2759 &factor_phi_al_ante,
2760 &factor_phi_al_crnt,
2761 &factor_phi_al_post,
2766 /* Computation of forces per component */
2767 for (d = 0; d < DIM; d++)
2769 f_i[d] = prefactor_phi
2770 * (factor_phi_ai_ante * delta_ante[d] + factor_phi_ai_crnt * delta_crnt[d]
2771 + factor_phi_ai_post * delta_post[d]);
2772 f_j[d] = prefactor_phi
2773 * (factor_phi_aj_ante * delta_ante[d] + factor_phi_aj_crnt * delta_crnt[d]
2774 + factor_phi_aj_post * delta_post[d]);
2775 f_k[d] = prefactor_phi
2776 * (factor_phi_ak_ante * delta_ante[d] + factor_phi_ak_crnt * delta_crnt[d]
2777 + factor_phi_ak_post * delta_post[d]);
2778 f_l[d] = prefactor_phi
2779 * (factor_phi_al_ante * delta_ante[d] + factor_phi_al_crnt * delta_crnt[d]
2780 + factor_phi_al_post * delta_post[d]);
2782 /* Computation of the energy */
2787 /* Updating the forces */
2789 rvec_inc(f[ai], f_i);
2790 rvec_inc(f[aj], f_j);
2791 rvec_inc(f[ak], f_k);
2792 rvec_inc(f[al], f_l);
2794 if (computeVirial(flavor))
2798 t3 = pbc_rvec_sub(pbc, x[al], x[aj], dx_jl);
2805 rvec_inc(fshift[t1], f_i);
2806 rvec_inc(fshift[CENTRAL], f_j);
2807 rvec_inc(fshift[t2], f_k);
2808 rvec_inc(fshift[t3], f_l);
2816 template<BondedKernelFlavor flavor>
2817 real cbtdihs(int nbonds,
2818 const t_iatom forceatoms[],
2819 const t_iparams forceparams[],
2824 real gmx_unused lambda,
2825 real gmx_unused* dvdlambda,
2826 const t_mdatoms gmx_unused* md,
2827 t_fcdata gmx_unused* fcd,
2828 t_disresdata gmx_unused* disresdata,
2829 t_oriresdata gmx_unused* oriresdata,
2830 int gmx_unused* global_atom_index)
2832 int type, ai, aj, ak, al, i, d;
2836 rvec f_i, f_j, f_k, f_l;
2838 rvec delta_ante, delta_crnt, delta_post;
2839 rvec f_phi_ai, f_phi_aj, f_phi_ak, f_phi_al;
2840 rvec f_theta_ante_ai, f_theta_ante_aj, f_theta_ante_ak;
2841 rvec f_theta_post_aj, f_theta_post_ak, f_theta_post_al;
2845 for (i = 0; (i < nbonds);)
2847 type = forceatoms[i++];
2848 ai = forceatoms[i++];
2849 aj = forceatoms[i++];
2850 ak = forceatoms[i++];
2851 al = forceatoms[i++];
2854 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], vec_temp);
2855 pbc_rvec_sub(pbc, x[aj], x[ai], delta_ante);
2856 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], vec_temp);
2857 pbc_rvec_sub(pbc, x[ak], x[aj], delta_crnt);
2858 pbc_rvec_sub(pbc, x[ak], x[al], vec_temp);
2859 pbc_rvec_sub(pbc, x[al], x[ak], delta_post);
2861 /* \brief Compute factors for CBT potential
2862 * The combined bending-torsion potential goes to zero in a very smooth manner, eliminating the numerical
2863 * instabilities, when three coarse-grained particles align and the dihedral angle and standard
2864 * dihedral potentials cannot be calculated. The CBT potential is calculated using the formula:
2865 * \f[V_{\rm CBT}(\theta_{i-1}, \theta_i, \phi_i) = k_{\phi} \sin^3\theta_{i-1} \sin^3\theta_{i}
2866 * \sum_{n=0}^4 { a_n \cos^n\phi_i}\f] ({eq:CBT} and ref \cite{MonicaGoga2013} from the manual).
2867 * It contains in its expression not only the dihedral angle \f$\phi\f$
2868 * but also \f[\theta_{i-1}\f] (theta_ante bellow) and \f[\theta_{i}\f] (theta_post bellow)
2869 * --- the adjacent bending angles.
2870 * For more explanations see comments file "restcbt.h". */
2872 compute_factors_cbtdihs(type,
2890 /* Acumulate the resuts per beads */
2891 for (d = 0; d < DIM; d++)
2893 f_i[d] = f_phi_ai[d] + f_theta_ante_ai[d];
2894 f_j[d] = f_phi_aj[d] + f_theta_ante_aj[d] + f_theta_post_aj[d];
2895 f_k[d] = f_phi_ak[d] + f_theta_ante_ak[d] + f_theta_post_ak[d];
2896 f_l[d] = f_phi_al[d] + f_theta_post_al[d];
2899 /* Compute the potential energy */
2904 /* Updating the forces */
2905 rvec_inc(f[ai], f_i);
2906 rvec_inc(f[aj], f_j);
2907 rvec_inc(f[ak], f_k);
2908 rvec_inc(f[al], f_l);
2911 if (computeVirial(flavor))
2915 t3 = pbc_rvec_sub(pbc, x[al], x[aj], dx_jl);
2922 rvec_inc(fshift[t1], f_i);
2923 rvec_inc(fshift[CENTRAL], f_j);
2924 rvec_inc(fshift[t2], f_k);
2925 rvec_inc(fshift[t3], f_l);
2932 template<BondedKernelFlavor flavor>
2933 std::enable_if_t<flavor != BondedKernelFlavor::ForcesSimdWhenAvailable || !GMX_SIMD_HAVE_REAL, real>
2935 const t_iatom forceatoms[],
2936 const t_iparams forceparams[],
2943 const t_mdatoms gmx_unused* md,
2944 t_fcdata gmx_unused* fcd,
2945 t_disresdata gmx_unused* disresdata,
2946 t_oriresdata gmx_unused* oriresdata,
2947 int gmx_unused* global_atom_index)
2949 const real c0 = 0.0, c1 = 1.0, c2 = 2.0, c3 = 3.0, c4 = 4.0, c5 = 5.0;
2950 int type, ai, aj, ak, al, i, j;
2952 rvec r_ij, r_kj, r_kl, m, n;
2953 real parmA[NR_RBDIHS];
2954 real parmB[NR_RBDIHS];
2955 real parm[NR_RBDIHS];
2956 real cos_phi, phi, rbp, rbpBA;
2957 real v, ddphi, sin_phi;
2959 real L1 = 1.0 - lambda;
2963 for (i = 0; (i < nbonds);)
2965 type = forceatoms[i++];
2966 ai = forceatoms[i++];
2967 aj = forceatoms[i++];
2968 ak = forceatoms[i++];
2969 al = forceatoms[i++];
2971 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3); /* 84 */
2973 /* Change to polymer convention */
2980 phi -= M_PI; /* 1 */
2982 cos_phi = std::cos(phi);
2983 /* Beware of accuracy loss, cannot use 1-sqrt(cos^2) ! */
2984 sin_phi = std::sin(phi);
2986 for (j = 0; (j < NR_RBDIHS); j++)
2988 parmA[j] = forceparams[type].rbdihs.rbcA[j];
2989 parmB[j] = forceparams[type].rbdihs.rbcB[j];
2990 parm[j] = L1 * parmA[j] + lambda * parmB[j];
2992 /* Calculate cosine powers */
2993 /* Calculate the energy */
2994 /* Calculate the derivative */
2997 dvdl_term += (parmB[0] - parmA[0]);
3002 rbpBA = parmB[1] - parmA[1];
3003 ddphi += rbp * cosfac;
3006 dvdl_term += cosfac * rbpBA;
3008 rbpBA = parmB[2] - parmA[2];
3009 ddphi += c2 * rbp * cosfac;
3012 dvdl_term += cosfac * rbpBA;
3014 rbpBA = parmB[3] - parmA[3];
3015 ddphi += c3 * rbp * cosfac;
3018 dvdl_term += cosfac * rbpBA;
3020 rbpBA = parmB[4] - parmA[4];
3021 ddphi += c4 * rbp * cosfac;
3024 dvdl_term += cosfac * rbpBA;
3026 rbpBA = parmB[5] - parmA[5];
3027 ddphi += c5 * rbp * cosfac;
3030 dvdl_term += cosfac * rbpBA;
3032 ddphi = -ddphi * sin_phi; /* 11 */
3034 do_dih_fup<flavor>(ai, aj, ak, al, ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1, t2, t3); /* 112 */
3037 *dvdlambda += dvdl_term;
3044 /*! \brief Mysterious undocumented function */
3045 int cmap_setup_grid_index(int ip, int grid_spacing, int* ipm1, int* ipp1, int* ipp2)
3051 ip = ip + grid_spacing - 1;
3053 else if (ip > grid_spacing)
3055 ip = ip - grid_spacing - 1;
3064 im1 = grid_spacing - 1;
3066 else if (ip == grid_spacing - 2)
3070 else if (ip == grid_spacing - 1)
3085 real cmap_dihs(int nbonds,
3086 const t_iatom forceatoms[],
3087 const t_iparams forceparams[],
3088 const gmx_cmap_t* cmap_grid,
3092 const struct t_pbc* pbc,
3093 real gmx_unused lambda,
3094 real gmx_unused* dvdlambda,
3095 const t_mdatoms gmx_unused* md,
3096 t_fcdata gmx_unused* fcd,
3097 t_disresdata gmx_unused* disresdata,
3098 t_oriresdata gmx_unused* oriresdata,
3099 int gmx_unused* global_atom_index)
3102 int ai, aj, ak, al, am;
3103 int a1i, a1j, a1k, a1l, a2i, a2j, a2k, a2l;
3105 int t11, t21, t31, t12, t22, t32;
3106 int iphi1, ip1m1, ip1p1, ip1p2;
3107 int iphi2, ip2m1, ip2p1, ip2p2;
3109 int pos1, pos2, pos3, pos4;
3111 real ty[4], ty1[4], ty2[4], ty12[4], tx[16];
3112 real phi1, cos_phi1, sin_phi1, xphi1;
3113 real phi2, cos_phi2, sin_phi2, xphi2;
3114 real dx, tt, tu, e, df1, df2, vtot;
3115 real ra21, rb21, rg21, rg1, rgr1, ra2r1, rb2r1, rabr1;
3116 real ra22, rb22, rg22, rg2, rgr2, ra2r2, rb2r2, rabr2;
3117 real fg1, hg1, fga1, hgb1, gaa1, gbb1;
3118 real fg2, hg2, fga2, hgb2, gaa2, gbb2;
3121 rvec r1_ij, r1_kj, r1_kl, m1, n1;
3122 rvec r2_ij, r2_kj, r2_kl, m2, n2;
3123 rvec f1_i, f1_j, f1_k, f1_l;
3124 rvec f2_i, f2_j, f2_k, f2_l;
3125 rvec a1, b1, a2, b2;
3126 rvec f1, g1, h1, f2, g2, h2;
3127 rvec dtf1, dtg1, dth1, dtf2, dtg2, dth2;
3129 int loop_index[4][4] = { { 0, 4, 8, 12 }, { 1, 5, 9, 13 }, { 2, 6, 10, 14 }, { 3, 7, 11, 15 } };
3131 /* Total CMAP energy */
3134 for (n = 0; n < nbonds;)
3136 /* Five atoms are involved in the two torsions */
3137 type = forceatoms[n++];
3138 ai = forceatoms[n++];
3139 aj = forceatoms[n++];
3140 ak = forceatoms[n++];
3141 al = forceatoms[n++];
3142 am = forceatoms[n++];
3144 /* Which CMAP type is this */
3145 const int cmapA = forceparams[type].cmap.cmapA;
3146 const real* cmapd = cmap_grid->cmapdata[cmapA].cmap.data();
3155 x[a1i], x[a1j], x[a1k], x[a1l], pbc, r1_ij, r1_kj, r1_kl, m1, n1, &t11, &t21, &t31); /* 84 */
3157 cos_phi1 = std::cos(phi1);
3159 a1[0] = r1_ij[1] * r1_kj[2] - r1_ij[2] * r1_kj[1];
3160 a1[1] = r1_ij[2] * r1_kj[0] - r1_ij[0] * r1_kj[2];
3161 a1[2] = r1_ij[0] * r1_kj[1] - r1_ij[1] * r1_kj[0]; /* 9 */
3163 b1[0] = r1_kl[1] * r1_kj[2] - r1_kl[2] * r1_kj[1];
3164 b1[1] = r1_kl[2] * r1_kj[0] - r1_kl[0] * r1_kj[2];
3165 b1[2] = r1_kl[0] * r1_kj[1] - r1_kl[1] * r1_kj[0]; /* 9 */
3167 pbc_rvec_sub(pbc, x[a1l], x[a1k], h1);
3169 ra21 = iprod(a1, a1); /* 5 */
3170 rb21 = iprod(b1, b1); /* 5 */
3171 rg21 = iprod(r1_kj, r1_kj); /* 5 */
3177 rabr1 = sqrt(ra2r1 * rb2r1);
3179 sin_phi1 = rg1 * rabr1 * iprod(a1, h1) * (-1);
3181 if (cos_phi1 < -0.5 || cos_phi1 > 0.5)
3183 phi1 = std::asin(sin_phi1);
3193 phi1 = -M_PI - phi1;
3199 phi1 = std::acos(cos_phi1);
3207 xphi1 = phi1 + M_PI; /* 1 */
3209 /* Second torsion */
3216 x[a2i], x[a2j], x[a2k], x[a2l], pbc, r2_ij, r2_kj, r2_kl, m2, n2, &t12, &t22, &t32); /* 84 */
3218 cos_phi2 = std::cos(phi2);
3220 a2[0] = r2_ij[1] * r2_kj[2] - r2_ij[2] * r2_kj[1];
3221 a2[1] = r2_ij[2] * r2_kj[0] - r2_ij[0] * r2_kj[2];
3222 a2[2] = r2_ij[0] * r2_kj[1] - r2_ij[1] * r2_kj[0]; /* 9 */
3224 b2[0] = r2_kl[1] * r2_kj[2] - r2_kl[2] * r2_kj[1];
3225 b2[1] = r2_kl[2] * r2_kj[0] - r2_kl[0] * r2_kj[2];
3226 b2[2] = r2_kl[0] * r2_kj[1] - r2_kl[1] * r2_kj[0]; /* 9 */
3228 pbc_rvec_sub(pbc, x[a2l], x[a2k], h2);
3230 ra22 = iprod(a2, a2); /* 5 */
3231 rb22 = iprod(b2, b2); /* 5 */
3232 rg22 = iprod(r2_kj, r2_kj); /* 5 */
3238 rabr2 = sqrt(ra2r2 * rb2r2);
3240 sin_phi2 = rg2 * rabr2 * iprod(a2, h2) * (-1);
3242 if (cos_phi2 < -0.5 || cos_phi2 > 0.5)
3244 phi2 = std::asin(sin_phi2);
3254 phi2 = -M_PI - phi2;
3260 phi2 = std::acos(cos_phi2);
3268 xphi2 = phi2 + M_PI; /* 1 */
3270 /* Range mangling */
3273 xphi1 = xphi1 + 2 * M_PI;
3275 else if (xphi1 >= 2 * M_PI)
3277 xphi1 = xphi1 - 2 * M_PI;
3282 xphi2 = xphi2 + 2 * M_PI;
3284 else if (xphi2 >= 2 * M_PI)
3286 xphi2 = xphi2 - 2 * M_PI;
3289 /* Number of grid points */
3290 dx = 2 * M_PI / cmap_grid->grid_spacing;
3292 /* Where on the grid are we */
3293 iphi1 = static_cast<int>(xphi1 / dx);
3294 iphi2 = static_cast<int>(xphi2 / dx);
3296 iphi1 = cmap_setup_grid_index(iphi1, cmap_grid->grid_spacing, &ip1m1, &ip1p1, &ip1p2);
3297 iphi2 = cmap_setup_grid_index(iphi2, cmap_grid->grid_spacing, &ip2m1, &ip2p1, &ip2p2);
3299 pos1 = iphi1 * cmap_grid->grid_spacing + iphi2;
3300 pos2 = ip1p1 * cmap_grid->grid_spacing + iphi2;
3301 pos3 = ip1p1 * cmap_grid->grid_spacing + ip2p1;
3302 pos4 = iphi1 * cmap_grid->grid_spacing + ip2p1;
3304 ty[0] = cmapd[pos1 * 4];
3305 ty[1] = cmapd[pos2 * 4];
3306 ty[2] = cmapd[pos3 * 4];
3307 ty[3] = cmapd[pos4 * 4];
3309 ty1[0] = cmapd[pos1 * 4 + 1];
3310 ty1[1] = cmapd[pos2 * 4 + 1];
3311 ty1[2] = cmapd[pos3 * 4 + 1];
3312 ty1[3] = cmapd[pos4 * 4 + 1];
3314 ty2[0] = cmapd[pos1 * 4 + 2];
3315 ty2[1] = cmapd[pos2 * 4 + 2];
3316 ty2[2] = cmapd[pos3 * 4 + 2];
3317 ty2[3] = cmapd[pos4 * 4 + 2];
3319 ty12[0] = cmapd[pos1 * 4 + 3];
3320 ty12[1] = cmapd[pos2 * 4 + 3];
3321 ty12[2] = cmapd[pos3 * 4 + 3];
3322 ty12[3] = cmapd[pos4 * 4 + 3];
3324 /* Switch to degrees */
3325 dx = 360.0 / cmap_grid->grid_spacing;
3326 xphi1 = xphi1 * gmx::c_rad2Deg;
3327 xphi2 = xphi2 * gmx::c_rad2Deg;
3329 for (i = 0; i < 4; i++) /* 16 */
3332 tx[i + 4] = ty1[i] * dx;
3333 tx[i + 8] = ty2[i] * dx;
3334 tx[i + 12] = ty12[i] * dx * dx;
3337 real tc[16] = { 0 };
3338 for (int idx = 0; idx < 16; idx++) /* 1056 */
3340 for (int k = 0; k < 16; k++)
3342 tc[idx] += cmap_coeff_matrix[k * 16 + idx] * tx[k];
3346 tt = (xphi1 - iphi1 * dx) / dx;
3347 tu = (xphi2 - iphi2 * dx) / dx;
3353 for (i = 3; i >= 0; i--)
3355 l1 = loop_index[i][3];
3356 l2 = loop_index[i][2];
3357 l3 = loop_index[i][1];
3359 e = tt * e + ((tc[i * 4 + 3] * tu + tc[i * 4 + 2]) * tu + tc[i * 4 + 1]) * tu + tc[i * 4];
3360 df1 = tu * df1 + (3.0 * tc[l1] * tt + 2.0 * tc[l2]) * tt + tc[l3];
3361 df2 = tt * df2 + (3.0 * tc[i * 4 + 3] * tu + 2.0 * tc[i * 4 + 2]) * tu + tc[i * 4 + 1];
3364 fac = gmx::c_rad2Deg / dx;
3371 /* Do forces - first torsion */
3372 fg1 = iprod(r1_ij, r1_kj);
3373 hg1 = iprod(r1_kl, r1_kj);
3374 fga1 = fg1 * ra2r1 * rgr1;
3375 hgb1 = hg1 * rb2r1 * rgr1;
3376 gaa1 = -ra2r1 * rg1;
3379 for (i = 0; i < DIM; i++)
3381 dtf1[i] = gaa1 * a1[i];
3382 dtg1[i] = fga1 * a1[i] - hgb1 * b1[i];
3383 dth1[i] = gbb1 * b1[i];
3385 f1[i] = df1 * dtf1[i];
3386 g1[i] = df1 * dtg1[i];
3387 h1[i] = df1 * dth1[i];
3390 f1_j[i] = -f1[i] - g1[i];
3391 f1_k[i] = h1[i] + g1[i];
3394 f[a1i][i] = f[a1i][i] + f1_i[i];
3395 f[a1j][i] = f[a1j][i] + f1_j[i]; /* - f1[i] - g1[i] */
3396 f[a1k][i] = f[a1k][i] + f1_k[i]; /* h1[i] + g1[i] */
3397 f[a1l][i] = f[a1l][i] + f1_l[i]; /* h1[i] */
3400 /* Do forces - second torsion */
3401 fg2 = iprod(r2_ij, r2_kj);
3402 hg2 = iprod(r2_kl, r2_kj);
3403 fga2 = fg2 * ra2r2 * rgr2;
3404 hgb2 = hg2 * rb2r2 * rgr2;
3405 gaa2 = -ra2r2 * rg2;
3408 for (i = 0; i < DIM; i++)
3410 dtf2[i] = gaa2 * a2[i];
3411 dtg2[i] = fga2 * a2[i] - hgb2 * b2[i];
3412 dth2[i] = gbb2 * b2[i];
3414 f2[i] = df2 * dtf2[i];
3415 g2[i] = df2 * dtg2[i];
3416 h2[i] = df2 * dth2[i];
3419 f2_j[i] = -f2[i] - g2[i];
3420 f2_k[i] = h2[i] + g2[i];
3423 f[a2i][i] = f[a2i][i] + f2_i[i]; /* f2[i] */
3424 f[a2j][i] = f[a2j][i] + f2_j[i]; /* - f2[i] - g2[i] */
3425 f[a2k][i] = f[a2k][i] + f2_k[i]; /* h2[i] + g2[i] */
3426 f[a2l][i] = f[a2l][i] + f2_l[i]; /* - h2[i] */
3430 if (fshift != nullptr)
3434 t31 = pbc_rvec_sub(pbc, x[a1l], x[a1j], h1);
3435 t32 = pbc_rvec_sub(pbc, x[a2l], x[a2j], h2);
3443 rvec_inc(fshift[t11], f1_i);
3444 rvec_inc(fshift[CENTRAL], f1_j);
3445 rvec_inc(fshift[t21], f1_k);
3446 rvec_inc(fshift[t31], f1_l);
3448 rvec_inc(fshift[t12], f2_i);
3449 rvec_inc(fshift[CENTRAL], f2_j);
3450 rvec_inc(fshift[t22], f2_k);
3451 rvec_inc(fshift[t32], f2_l);
3461 /***********************************************************
3463 * G R O M O S 9 6 F U N C T I O N S
3465 ***********************************************************/
3466 real g96harmonic(real kA, real kB, real xA, real xB, real x, real lambda, real* V, real* F)
3468 const real half = 0.5;
3469 real L1, kk, x0, dx, dx2;
3470 real v, f, dvdlambda;
3473 kk = L1 * kA + lambda * kB;
3474 x0 = L1 * xA + lambda * xB;
3480 v = half * kk * dx2;
3481 dvdlambda = half * (kB - kA) * dx2 + (xA - xB) * kk * dx;
3488 /* That was 21 flops */
3491 template<BondedKernelFlavor flavor>
3492 real g96bonds(int nbonds,
3493 const t_iatom forceatoms[],
3494 const t_iparams forceparams[],
3501 const t_mdatoms gmx_unused* md,
3502 t_fcdata gmx_unused* fcd,
3503 t_disresdata gmx_unused* disresdata,
3504 t_oriresdata gmx_unused* oriresdata,
3505 int gmx_unused* global_atom_index)
3507 int i, ki, ai, aj, type;
3508 real dr2, fbond, vbond, vtot;
3512 for (i = 0; (i < nbonds);)
3514 type = forceatoms[i++];
3515 ai = forceatoms[i++];
3516 aj = forceatoms[i++];
3518 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
3519 dr2 = iprod(dx, dx); /* 5 */
3521 *dvdlambda += g96harmonic(forceparams[type].harmonic.krA,
3522 forceparams[type].harmonic.krB,
3523 forceparams[type].harmonic.rA,
3524 forceparams[type].harmonic.rB,
3530 vtot += 0.5 * vbond; /* 1*/
3532 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
3537 real g96bond_angle(const rvec xi, const rvec xj, const rvec xk, const t_pbc* pbc, rvec r_ij, rvec r_kj, int* t1, int* t2)
3538 /* Return value is the angle between the bonds i-j and j-k */
3542 *t1 = pbc_rvec_sub(pbc, xi, xj, r_ij); /* 3 */
3543 *t2 = pbc_rvec_sub(pbc, xk, xj, r_kj); /* 3 */
3545 costh = cos_angle(r_ij, r_kj); /* 25 */
3550 template<BondedKernelFlavor flavor>
3551 real g96angles(int nbonds,
3552 const t_iatom forceatoms[],
3553 const t_iparams forceparams[],
3560 const t_mdatoms gmx_unused* md,
3561 t_fcdata gmx_unused* fcd,
3562 t_disresdata gmx_unused* disresdata,
3563 t_oriresdata gmx_unused* oriresdata,
3564 int gmx_unused* global_atom_index)
3566 int i, ai, aj, ak, type, m, t1, t2;
3568 real cos_theta, dVdt, va, vtot;
3569 real rij_1, rij_2, rkj_1, rkj_2, rijrkj_1;
3573 for (i = 0; (i < nbonds);)
3575 type = forceatoms[i++];
3576 ai = forceatoms[i++];
3577 aj = forceatoms[i++];
3578 ak = forceatoms[i++];
3580 cos_theta = g96bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &t1, &t2);
3582 *dvdlambda += g96harmonic(forceparams[type].harmonic.krA,
3583 forceparams[type].harmonic.krB,
3584 forceparams[type].harmonic.rA,
3585 forceparams[type].harmonic.rB,
3592 rij_1 = gmx::invsqrt(iprod(r_ij, r_ij));
3593 rkj_1 = gmx::invsqrt(iprod(r_kj, r_kj));
3594 rij_2 = rij_1 * rij_1;
3595 rkj_2 = rkj_1 * rkj_1;
3596 rijrkj_1 = rij_1 * rkj_1; /* 23 */
3598 for (m = 0; (m < DIM); m++) /* 42 */
3600 f_i[m] = dVdt * (r_kj[m] * rijrkj_1 - r_ij[m] * rij_2 * cos_theta);
3601 f_k[m] = dVdt * (r_ij[m] * rijrkj_1 - r_kj[m] * rkj_2 * cos_theta);
3602 f_j[m] = -f_i[m] - f_k[m];
3608 if (computeVirial(flavor))
3610 rvec_inc(fshift[t1], f_i);
3611 rvec_inc(fshift[CENTRAL], f_j);
3612 rvec_inc(fshift[t2], f_k); /* 9 */
3619 template<BondedKernelFlavor flavor>
3620 real cross_bond_bond(int nbonds,
3621 const t_iatom forceatoms[],
3622 const t_iparams forceparams[],
3627 real gmx_unused lambda,
3628 real gmx_unused* dvdlambda,
3629 const t_mdatoms gmx_unused* md,
3630 t_fcdata gmx_unused* fcd,
3631 t_disresdata gmx_unused* disresdata,
3632 t_oriresdata gmx_unused* oriresdata,
3633 int gmx_unused* global_atom_index)
3635 /* Potential from Lawrence and Skimmer, Chem. Phys. Lett. 372 (2003)
3638 int i, ai, aj, ak, type, m, t1, t2;
3640 real vtot, vrr, s1, s2, r1, r2, r1e, r2e, krr;
3644 for (i = 0; (i < nbonds);)
3646 type = forceatoms[i++];
3647 ai = forceatoms[i++];
3648 aj = forceatoms[i++];
3649 ak = forceatoms[i++];
3650 r1e = forceparams[type].cross_bb.r1e;
3651 r2e = forceparams[type].cross_bb.r2e;
3652 krr = forceparams[type].cross_bb.krr;
3654 /* Compute distance vectors ... */
3655 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], r_ij);
3656 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], r_kj);
3658 /* ... and their lengths */
3662 /* Deviations from ideality */
3666 /* Energy (can be negative!) */
3667 vrr = krr * s1 * s2;
3671 svmul(-krr * s2 / r1, r_ij, f_i);
3672 svmul(-krr * s1 / r2, r_kj, f_k);
3674 for (m = 0; (m < DIM); m++) /* 12 */
3676 f_j[m] = -f_i[m] - f_k[m];
3682 if (computeVirial(flavor))
3684 rvec_inc(fshift[t1], f_i);
3685 rvec_inc(fshift[CENTRAL], f_j);
3686 rvec_inc(fshift[t2], f_k); /* 9 */
3693 template<BondedKernelFlavor flavor>
3694 real cross_bond_angle(int nbonds,
3695 const t_iatom forceatoms[],
3696 const t_iparams forceparams[],
3701 real gmx_unused lambda,
3702 real gmx_unused* dvdlambda,
3703 const t_mdatoms gmx_unused* md,
3704 t_fcdata gmx_unused* fcd,
3705 t_disresdata gmx_unused* disresdata,
3706 t_oriresdata gmx_unused* oriresdata,
3707 int gmx_unused* global_atom_index)
3709 /* Potential from Lawrence and Skimmer, Chem. Phys. Lett. 372 (2003)
3712 int i, ai, aj, ak, type, m, t1, t2;
3713 rvec r_ij, r_kj, r_ik;
3714 real vtot, vrt, s1, s2, s3, r1, r2, r3, r1e, r2e, r3e, krt, k1, k2, k3;
3718 for (i = 0; (i < nbonds);)
3720 type = forceatoms[i++];
3721 ai = forceatoms[i++];
3722 aj = forceatoms[i++];
3723 ak = forceatoms[i++];
3724 r1e = forceparams[type].cross_ba.r1e;
3725 r2e = forceparams[type].cross_ba.r2e;
3726 r3e = forceparams[type].cross_ba.r3e;
3727 krt = forceparams[type].cross_ba.krt;
3729 /* Compute distance vectors ... */
3730 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], r_ij);
3731 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], r_kj);
3732 pbc_rvec_sub(pbc, x[ai], x[ak], r_ik);
3734 /* ... and their lengths */
3739 /* Deviations from ideality */
3744 /* Energy (can be negative!) */
3745 vrt = krt * s3 * (s1 + s2);
3749 k1 = -krt * (s3 / r1);
3750 k2 = -krt * (s3 / r2);
3751 k3 = -krt * (s1 + s2) / r3;
3752 for (m = 0; (m < DIM); m++)
3754 f_i[m] = k1 * r_ij[m] + k3 * r_ik[m];
3755 f_k[m] = k2 * r_kj[m] - k3 * r_ik[m];
3756 f_j[m] = -f_i[m] - f_k[m];
3759 for (m = 0; (m < DIM); m++) /* 12 */
3766 if (computeVirial(flavor))
3768 rvec_inc(fshift[t1], f_i);
3769 rvec_inc(fshift[CENTRAL], f_j);
3770 rvec_inc(fshift[t2], f_k); /* 9 */
3777 /*! \brief Computes the potential and force for a tabulated potential */
3778 real bonded_tab(const char* type,
3780 const bondedtable_t* table,
3788 real k, tabscale, rt, eps, eps2, Yt, Ft, Geps, Heps2, Fp, VV, FF;
3792 k = (1.0 - lambda) * kA + lambda * kB;
3794 tabscale = table->scale;
3795 const real* VFtab = table->data.data();
3798 n0 = static_cast<int>(rt);
3802 "A tabulated %s interaction table number %d is out of the table range: r %f, "
3803 "between table indices %d and %d, table length %d",
3815 Ft = VFtab[nnn + 1];
3816 Geps = VFtab[nnn + 2] * eps;
3817 Heps2 = VFtab[nnn + 3] * eps2;
3818 Fp = Ft + Geps + Heps2;
3820 FF = Fp + Geps + 2.0 * Heps2;
3822 *F = -k * FF * tabscale;
3824 dvdlambda = (kB - kA) * VV;
3828 /* That was 22 flops */
3831 template<BondedKernelFlavor flavor>
3832 real tab_bonds(int nbonds,
3833 const t_iatom forceatoms[],
3834 const t_iparams forceparams[],
3841 const t_mdatoms gmx_unused* md,
3843 t_disresdata gmx_unused* disresdata,
3844 t_oriresdata gmx_unused* oriresdata,
3845 int gmx_unused* global_atom_index)
3847 int i, ki, ai, aj, type, table;
3848 real dr, dr2, fbond, vbond, vtot;
3852 for (i = 0; (i < nbonds);)
3854 type = forceatoms[i++];
3855 ai = forceatoms[i++];
3856 aj = forceatoms[i++];
3858 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
3859 dr2 = iprod(dx, dx); /* 5 */
3860 dr = dr2 * gmx::invsqrt(dr2); /* 10 */
3862 table = forceparams[type].tab.table;
3864 *dvdlambda += bonded_tab("bond",
3866 &fcd->bondtab[table],
3867 forceparams[type].tab.kA,
3868 forceparams[type].tab.kB,
3880 vtot += vbond; /* 1*/
3881 fbond *= gmx::invsqrt(dr2); /* 6 */
3883 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
3888 template<BondedKernelFlavor flavor>
3889 real tab_angles(int nbonds,
3890 const t_iatom forceatoms[],
3891 const t_iparams forceparams[],
3898 const t_mdatoms gmx_unused* md,
3900 t_disresdata gmx_unused* disresdata,
3901 t_oriresdata gmx_unused* oriresdata,
3902 int gmx_unused* global_atom_index)
3904 int i, ai, aj, ak, t1, t2, type, table;
3906 real cos_theta, cos_theta2, theta, dVdt, va, vtot;
3909 for (i = 0; (i < nbonds);)
3911 type = forceatoms[i++];
3912 ai = forceatoms[i++];
3913 aj = forceatoms[i++];
3914 ak = forceatoms[i++];
3916 theta = bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
3918 table = forceparams[type].tab.table;
3920 *dvdlambda += bonded_tab("angle",
3922 &fcd->angletab[table],
3923 forceparams[type].tab.kA,
3924 forceparams[type].tab.kB,
3931 cos_theta2 = gmx::square(cos_theta); /* 1 */
3940 st = dVdt * gmx::invsqrt(1 - cos_theta2); /* 12 */
3941 sth = st * cos_theta; /* 1 */
3942 nrkj2 = iprod(r_kj, r_kj); /* 5 */
3943 nrij2 = iprod(r_ij, r_ij);
3945 cik = st * gmx::invsqrt(nrkj2 * nrij2); /* 12 */
3946 cii = sth / nrij2; /* 10 */
3947 ckk = sth / nrkj2; /* 10 */
3949 for (m = 0; (m < DIM); m++) /* 39 */
3951 f_i[m] = -(cik * r_kj[m] - cii * r_ij[m]);
3952 f_k[m] = -(cik * r_ij[m] - ckk * r_kj[m]);
3953 f_j[m] = -f_i[m] - f_k[m];
3959 if (computeVirial(flavor))
3961 rvec_inc(fshift[t1], f_i);
3962 rvec_inc(fshift[CENTRAL], f_j);
3963 rvec_inc(fshift[t2], f_k);
3970 template<BondedKernelFlavor flavor>
3971 real tab_dihs(int nbonds,
3972 const t_iatom forceatoms[],
3973 const t_iparams forceparams[],
3980 const t_mdatoms gmx_unused* md,
3982 t_disresdata gmx_unused* disresdata,
3983 t_oriresdata gmx_unused* oriresdata,
3984 int gmx_unused* global_atom_index)
3986 int i, type, ai, aj, ak, al, table;
3988 rvec r_ij, r_kj, r_kl, m, n;
3989 real phi, ddphi, vpd, vtot;
3992 for (i = 0; (i < nbonds);)
3994 type = forceatoms[i++];
3995 ai = forceatoms[i++];
3996 aj = forceatoms[i++];
3997 ak = forceatoms[i++];
3998 al = forceatoms[i++];
4000 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3); /* 84 */
4002 table = forceparams[type].tab.table;
4004 /* Hopefully phi+M_PI never results in values < 0 */
4005 *dvdlambda += bonded_tab("dihedral",
4007 &fcd->dihtab[table],
4008 forceparams[type].tab.kA,
4009 forceparams[type].tab.kB,
4016 do_dih_fup<flavor>(ai, aj, ak, al, -ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1, t2, t3); /* 112 */
4023 struct BondedInteractions
4025 BondedFunction function;
4029 // Bug in old clang versions prevents constexpr. constexpr is needed for MSVC.
4030 #if defined(__clang__) && __clang_major__ < 6
4031 # define CONSTEXPR_EXCL_OLD_CLANG const
4033 # define CONSTEXPR_EXCL_OLD_CLANG constexpr
4036 /*! \brief Lookup table of bonded interaction functions
4038 * This must have as many entries as interaction_function in ifunc.cpp */
4039 template<BondedKernelFlavor flavor>
4040 CONSTEXPR_EXCL_OLD_CLANG std::array<BondedInteractions, F_NRE> c_bondedInteractionFunctions = {
4041 BondedInteractions{ bonds<flavor>, eNR_BONDS }, // F_BONDS
4042 BondedInteractions{ g96bonds<flavor>, eNR_BONDS }, // F_G96BONDS
4043 BondedInteractions{ morse_bonds<flavor>, eNR_MORSE }, // F_MORSE
4044 BondedInteractions{ cubic_bonds<flavor>, eNR_CUBICBONDS }, // F_CUBICBONDS
4045 BondedInteractions{ unimplemented, -1 }, // F_CONNBONDS
4046 BondedInteractions{ bonds<flavor>, eNR_BONDS }, // F_HARMONIC
4047 BondedInteractions{ FENE_bonds<flavor>, eNR_FENEBONDS }, // F_FENEBONDS
4048 BondedInteractions{ tab_bonds<flavor>, eNR_TABBONDS }, // F_TABBONDS
4049 BondedInteractions{ tab_bonds<flavor>, eNR_TABBONDS }, // F_TABBONDSNC
4050 BondedInteractions{ restraint_bonds<flavor>, eNR_RESTRBONDS }, // F_RESTRBONDS
4051 BondedInteractions{ angles<flavor>, eNR_ANGLES }, // F_ANGLES
4052 BondedInteractions{ g96angles<flavor>, eNR_ANGLES }, // F_G96ANGLES
4053 BondedInteractions{ restrangles<flavor>, eNR_ANGLES }, // F_RESTRANGLES
4054 BondedInteractions{ linear_angles<flavor>, eNR_ANGLES }, // F_LINEAR_ANGLES
4055 BondedInteractions{ cross_bond_bond<flavor>, eNR_CROSS_BOND_BOND }, // F_CROSS_BOND_BONDS
4056 BondedInteractions{ cross_bond_angle<flavor>, eNR_CROSS_BOND_ANGLE }, // F_CROSS_BOND_ANGLES
4057 BondedInteractions{ urey_bradley<flavor>, eNR_UREY_BRADLEY }, // F_UREY_BRADLEY
4058 BondedInteractions{ quartic_angles<flavor>, eNR_QANGLES }, // F_QUARTIC_ANGLES
4059 BondedInteractions{ tab_angles<flavor>, eNR_TABANGLES }, // F_TABANGLES
4060 BondedInteractions{ pdihs<flavor>, eNR_PROPER }, // F_PDIHS
4061 BondedInteractions{ rbdihs<flavor>, eNR_RB }, // F_RBDIHS
4062 BondedInteractions{ restrdihs<flavor>, eNR_PROPER }, // F_RESTRDIHS
4063 BondedInteractions{ cbtdihs<flavor>, eNR_RB }, // F_CBTDIHS
4064 BondedInteractions{ rbdihs<flavor>, eNR_FOURDIH }, // F_FOURDIHS
4065 BondedInteractions{ idihs<flavor>, eNR_IMPROPER }, // F_IDIHS
4066 BondedInteractions{ pdihs<flavor>, eNR_IMPROPER }, // F_PIDIHS
4067 BondedInteractions{ tab_dihs<flavor>, eNR_TABDIHS }, // F_TABDIHS
4068 BondedInteractions{ unimplemented, eNR_CMAP }, // F_CMAP
4069 BondedInteractions{ unimplemented, -1 }, // F_GB12_NOLONGERUSED
4070 BondedInteractions{ unimplemented, -1 }, // F_GB13_NOLONGERUSED
4071 BondedInteractions{ unimplemented, -1 }, // F_GB14_NOLONGERUSED
4072 BondedInteractions{ unimplemented, -1 }, // F_GBPOL_NOLONGERUSED
4073 BondedInteractions{ unimplemented, -1 }, // F_NPSOLVATION_NOLONGERUSED
4074 BondedInteractions{ unimplemented, eNR_NB14 }, // F_LJ14
4075 BondedInteractions{ unimplemented, -1 }, // F_COUL14
4076 BondedInteractions{ unimplemented, eNR_NB14 }, // F_LJC14_Q
4077 BondedInteractions{ unimplemented, eNR_NB14 }, // F_LJC_PAIRS_NB
4078 BondedInteractions{ unimplemented, -1 }, // F_LJ
4079 BondedInteractions{ unimplemented, -1 }, // F_BHAM
4080 BondedInteractions{ unimplemented, -1 }, // F_LJ_LR_NOLONGERUSED
4081 BondedInteractions{ unimplemented, -1 }, // F_BHAM_LR_NOLONGERUSED
4082 BondedInteractions{ unimplemented, -1 }, // F_DISPCORR
4083 BondedInteractions{ unimplemented, -1 }, // F_COUL_SR
4084 BondedInteractions{ unimplemented, -1 }, // F_COUL_LR_NOLONGERUSED
4085 BondedInteractions{ unimplemented, -1 }, // F_RF_EXCL
4086 BondedInteractions{ unimplemented, -1 }, // F_COUL_RECIP
4087 BondedInteractions{ unimplemented, -1 }, // F_LJ_RECIP
4088 BondedInteractions{ unimplemented, -1 }, // F_DPD
4089 BondedInteractions{ polarize<flavor>, eNR_POLARIZE }, // F_POLARIZATION
4090 BondedInteractions{ water_pol<flavor>, eNR_WPOL }, // F_WATER_POL
4091 BondedInteractions{ thole_pol<flavor>, eNR_THOLE }, // F_THOLE_POL
4092 BondedInteractions{ anharm_polarize<flavor>, eNR_ANHARM_POL }, // F_ANHARM_POL
4093 BondedInteractions{ unimplemented, -1 }, // F_POSRES
4094 BondedInteractions{ unimplemented, -1 }, // F_FBPOSRES
4095 BondedInteractions{ ta_disres, eNR_DISRES }, // F_DISRES
4096 BondedInteractions{ unimplemented, -1 }, // F_DISRESVIOL
4097 BondedInteractions{ orires, eNR_ORIRES }, // F_ORIRES
4098 BondedInteractions{ unimplemented, -1 }, // F_ORIRESDEV
4099 BondedInteractions{ angres<flavor>, eNR_ANGRES }, // F_ANGRES
4100 BondedInteractions{ angresz<flavor>, eNR_ANGRESZ }, // F_ANGRESZ
4101 BondedInteractions{ dihres<flavor>, eNR_DIHRES }, // F_DIHRES
4102 BondedInteractions{ unimplemented, -1 }, // F_DIHRESVIOL
4103 BondedInteractions{ unimplemented, -1 }, // F_CONSTR
4104 BondedInteractions{ unimplemented, -1 }, // F_CONSTRNC
4105 BondedInteractions{ unimplemented, -1 }, // F_SETTLE
4106 BondedInteractions{ unimplemented, -1 }, // F_VSITE2
4107 BondedInteractions{ unimplemented, -1 }, // F_VSITE3
4108 BondedInteractions{ unimplemented, -1 }, // F_VSITE3FD
4109 BondedInteractions{ unimplemented, -1 }, // F_VSITE3FAD
4110 BondedInteractions{ unimplemented, -1 }, // F_VSITE3OUT
4111 BondedInteractions{ unimplemented, -1 }, // F_VSITE4FD
4112 BondedInteractions{ unimplemented, -1 }, // F_VSITE4FDN
4113 BondedInteractions{ unimplemented, -1 }, // F_VSITEN
4114 BondedInteractions{ unimplemented, -1 }, // F_COM_PULL
4115 BondedInteractions{ unimplemented, -1 }, // F_DENSITYFITTING
4116 BondedInteractions{ unimplemented, -1 }, // F_EQM
4117 BondedInteractions{ unimplemented, -1 }, // F_EPOT
4118 BondedInteractions{ unimplemented, -1 }, // F_EKIN
4119 BondedInteractions{ unimplemented, -1 }, // F_ETOT
4120 BondedInteractions{ unimplemented, -1 }, // F_ECONSERVED
4121 BondedInteractions{ unimplemented, -1 }, // F_TEMP
4122 BondedInteractions{ unimplemented, -1 }, // F_VTEMP_NOLONGERUSED
4123 BondedInteractions{ unimplemented, -1 }, // F_PDISPCORR
4124 BondedInteractions{ unimplemented, -1 }, // F_PRES
4125 BondedInteractions{ unimplemented, -1 }, // F_DVDL_CONSTR
4126 BondedInteractions{ unimplemented, -1 }, // F_DVDL
4127 BondedInteractions{ unimplemented, -1 }, // F_DKDL
4128 BondedInteractions{ unimplemented, -1 }, // F_DVDL_COUL
4129 BondedInteractions{ unimplemented, -1 }, // F_DVDL_VDW
4130 BondedInteractions{ unimplemented, -1 }, // F_DVDL_BONDED
4131 BondedInteractions{ unimplemented, -1 }, // F_DVDL_RESTRAINT
4132 BondedInteractions{ unimplemented, -1 }, // F_DVDL_TEMPERATURE
4135 /*! \brief List of instantiated BondedInteractions list */
4136 CONSTEXPR_EXCL_OLD_CLANG
4137 gmx::EnumerationArray<BondedKernelFlavor, std::array<BondedInteractions, F_NRE>> c_bondedInteractionFunctionsPerFlavor = {
4138 c_bondedInteractionFunctions<BondedKernelFlavor::ForcesSimdWhenAvailable>,
4139 c_bondedInteractionFunctions<BondedKernelFlavor::ForcesNoSimd>,
4140 c_bondedInteractionFunctions<BondedKernelFlavor::ForcesAndVirialAndEnergy>,
4141 c_bondedInteractionFunctions<BondedKernelFlavor::ForcesAndEnergy>
4148 real calculateSimpleBond(const int ftype,
4149 const int numForceatoms,
4150 const t_iatom forceatoms[],
4151 const t_iparams forceparams[],
4155 const struct t_pbc* pbc,
4158 const t_mdatoms* md,
4160 t_disresdata* disresdata,
4161 t_oriresdata* oriresdata,
4162 int gmx_unused* global_atom_index,
4163 const BondedKernelFlavor bondedKernelFlavor)
4165 const BondedInteractions& bonded = c_bondedInteractionFunctionsPerFlavor[bondedKernelFlavor][ftype];
4167 real v = bonded.function(
4168 numForceatoms, forceatoms, forceparams, x, f, fshift, pbc, lambda, dvdlambda, md, fcd, disresdata, oriresdata, global_atom_index);
4173 int nrnbIndex(int ftype)
4175 return c_bondedInteractionFunctions<BondedKernelFlavor::ForcesAndVirialAndEnergy>[ftype].nrnbIndex;