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, 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
87 //! Type of CPU function to compute a bonded interaction.
88 using BondedFunction = real (*)(int nbonds,
89 const t_iatom iatoms[],
90 const t_iparams iparams[],
101 /*! \brief Mysterious CMAP coefficient matrix */
102 const int cmap_coeff_matrix[] = {
103 1, 0, -3, 2, 0, 0, 0, 0, -3, 0, 9, -6, 2, 0, -6, 4, 0, 0, 0, 0, 0, 0, 0, 0,
104 3, 0, -9, 6, -2, 0, 6, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, -6, 0, 0, -6, 4,
105 0, 0, 3, -2, 0, 0, 0, 0, 0, 0, -9, 6, 0, 0, 6, -4, 0, 0, 0, 0, 1, 0, -3, 2,
106 -2, 0, 6, -4, 1, 0, -3, 2, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 3, -2, 1, 0, -3, 2,
107 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 2, 0, 0, 3, -2, 0, 0, 0, 0, 0, 0, 3, -2,
108 0, 0, -6, 4, 0, 0, 3, -2, 0, 1, -2, 1, 0, 0, 0, 0, 0, -3, 6, -3, 0, 2, -4, 2,
109 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, -6, 3, 0, -2, 4, -2, 0, 0, 0, 0, 0, 0, 0, 0,
110 0, 0, -3, 3, 0, 0, 2, -2, 0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 3, -3, 0, 0, -2, 2,
111 0, 0, 0, 0, 0, 1, -2, 1, 0, -2, 4, -2, 0, 1, -2, 1, 0, 0, 0, 0, 0, 0, 0, 0,
112 0, -1, 2, -1, 0, 1, -2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, -1, 1,
113 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 2, -2, 0, 0, -1, 1
117 /*! \brief Compute dx = xi - xj, modulo PBC if non-NULL
119 * \todo This kind of code appears in many places. Consolidate it */
120 int pbc_rvec_sub(const t_pbc* pbc, const rvec xi, const rvec xj, rvec dx)
124 return pbc_dx_aiuc(pbc, xi, xj, dx);
128 rvec_sub(xi, xj, dx);
136 real bond_angle(const rvec xi,
145 /* Return value is the angle between the bonds i-j and j-k */
150 *t1 = pbc_rvec_sub(pbc, xi, xj, r_ij); /* 3 */
151 *t2 = pbc_rvec_sub(pbc, xk, xj, r_kj); /* 3 */
153 *costh = cos_angle(r_ij, r_kj); /* 25 */
154 th = std::acos(*costh); /* 10 */
159 real dih_angle(const rvec xi,
173 *t1 = pbc_rvec_sub(pbc, xi, xj, r_ij); /* 3 */
174 *t2 = pbc_rvec_sub(pbc, xk, xj, r_kj); /* 3 */
175 *t3 = pbc_rvec_sub(pbc, xk, xl, r_kl); /* 3 */
177 cprod(r_ij, r_kj, m); /* 9 */
178 cprod(r_kj, r_kl, n); /* 9 */
179 real phi = gmx_angle(m, n); /* 49 (assuming 25 for atan2) */
180 real ipr = iprod(r_ij, n); /* 5 */
181 real sign = (ipr < 0.0) ? -1.0 : 1.0;
182 phi = sign * phi; /* 1 */
188 void make_dp_periodic(real* dp) /* 1 flop? */
190 /* dp cannot be outside (-pi,pi) */
195 else if (*dp < -M_PI)
204 /*! \brief Spreads and accumulates the bonded forces to the two atoms and adds the virial contribution when needed
206 * \p shiftIndex is used as the periodic shift.
208 template<BondedKernelFlavor flavor>
209 inline void spreadBondForces(const real bondForce,
217 for (int m = 0; m < DIM; m++) /* 15 */
219 const real fij = bondForce * dx[m];
222 if (computeVirial(flavor))
224 fshift[shiftIndex][m] += fij;
225 fshift[CENTRAL][m] -= fij;
230 /*! \brief Morse potential bond
232 * By Frank Everdij. Three parameters needed:
234 * b0 = equilibrium distance in nm
235 * be = beta in nm^-1 (actually, it's nu_e*Sqrt(2*pi*pi*mu/D_e))
236 * cb = well depth in kJ/mol
238 * Note: the potential is referenced to be +cb at infinite separation
239 * and zero at the equilibrium distance!
241 template<BondedKernelFlavor flavor>
242 real morse_bonds(int nbonds,
243 const t_iatom forceatoms[],
244 const t_iparams forceparams[],
251 const t_mdatoms gmx_unused* md,
252 t_fcdata gmx_unused* fcd,
253 int gmx_unused* global_atom_index)
255 const real one = 1.0;
256 const real two = 2.0;
257 real dr, dr2, temp, omtemp, cbomtemp, fbond, vbond, vtot;
258 real b0, be, cb, b0A, beA, cbA, b0B, beB, cbB, L1;
260 int i, ki, type, ai, aj;
263 for (i = 0; (i < nbonds);)
265 type = forceatoms[i++];
266 ai = forceatoms[i++];
267 aj = forceatoms[i++];
269 b0A = forceparams[type].morse.b0A;
270 beA = forceparams[type].morse.betaA;
271 cbA = forceparams[type].morse.cbA;
273 b0B = forceparams[type].morse.b0B;
274 beB = forceparams[type].morse.betaB;
275 cbB = forceparams[type].morse.cbB;
277 L1 = one - lambda; /* 1 */
278 b0 = L1 * b0A + lambda * b0B; /* 3 */
279 be = L1 * beA + lambda * beB; /* 3 */
280 cb = L1 * cbA + lambda * cbB; /* 3 */
282 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
283 dr2 = iprod(dx, dx); /* 5 */
284 dr = dr2 * gmx::invsqrt(dr2); /* 10 */
285 temp = std::exp(-be * (dr - b0)); /* 12 */
289 /* bonds are constrainted. This may _not_ include bond constraints if they are lambda dependent */
290 *dvdlambda += cbB - cbA;
294 omtemp = one - temp; /* 1 */
295 cbomtemp = cb * omtemp; /* 1 */
296 vbond = cbomtemp * omtemp; /* 1 */
297 fbond = -two * be * temp * cbomtemp * gmx::invsqrt(dr2); /* 9 */
298 vtot += vbond; /* 1 */
300 *dvdlambda += (cbB - cbA) * omtemp * omtemp
301 - (2 - 2 * omtemp) * omtemp * cb * ((b0B - b0A) * be - (beB - beA) * (dr - b0)); /* 15 */
303 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
309 template<BondedKernelFlavor flavor>
310 real cubic_bonds(int nbonds,
311 const t_iatom forceatoms[],
312 const t_iparams forceparams[],
317 real gmx_unused lambda,
318 real gmx_unused* dvdlambda,
319 const t_mdatoms gmx_unused* md,
320 t_fcdata gmx_unused* fcd,
321 int gmx_unused* global_atom_index)
323 const real three = 3.0;
324 const real two = 2.0;
326 real dr, dr2, dist, kdist, kdist2, fbond, vbond, vtot;
328 int i, ki, type, ai, aj;
331 for (i = 0; (i < nbonds);)
333 type = forceatoms[i++];
334 ai = forceatoms[i++];
335 aj = forceatoms[i++];
337 b0 = forceparams[type].cubic.b0;
338 kb = forceparams[type].cubic.kb;
339 kcub = forceparams[type].cubic.kcub;
341 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
342 dr2 = iprod(dx, dx); /* 5 */
349 dr = dr2 * gmx::invsqrt(dr2); /* 10 */
352 kdist2 = kdist * dist;
354 vbond = kdist2 + kcub * kdist2 * dist;
355 fbond = -(two * kdist + three * kdist2 * kcub) / dr;
357 vtot += vbond; /* 21 */
359 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
364 template<BondedKernelFlavor flavor>
365 real FENE_bonds(int nbonds,
366 const t_iatom forceatoms[],
367 const t_iparams forceparams[],
372 real gmx_unused lambda,
373 real gmx_unused* dvdlambda,
374 const t_mdatoms gmx_unused* md,
375 t_fcdata gmx_unused* fcd,
376 int* global_atom_index)
378 const real half = 0.5;
379 const real one = 1.0;
381 real dr2, bm2, omdr2obm2, fbond, vbond, vtot;
383 int i, ki, type, ai, aj;
386 for (i = 0; (i < nbonds);)
388 type = forceatoms[i++];
389 ai = forceatoms[i++];
390 aj = forceatoms[i++];
392 bm = forceparams[type].fene.bm;
393 kb = forceparams[type].fene.kb;
395 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
396 dr2 = iprod(dx, dx); /* 5 */
407 gmx_fatal(FARGS, "r^2 (%f) >= bm^2 (%f) in FENE bond between atoms %d and %d", dr2, bm2,
408 glatnr(global_atom_index, ai), glatnr(global_atom_index, aj));
411 omdr2obm2 = one - dr2 / bm2;
413 vbond = -half * kb * bm2 * std::log(omdr2obm2);
414 fbond = -kb / omdr2obm2;
416 vtot += vbond; /* 35 */
418 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
423 real harmonic(real kA, real kB, real xA, real xB, real x, real lambda, real* V, real* F)
425 const real half = 0.5;
426 real L1, kk, x0, dx, dx2;
427 real v, f, dvdlambda;
430 kk = L1 * kA + lambda * kB;
431 x0 = L1 * xA + lambda * xB;
438 dvdlambda = half * (kB - kA) * dx2 + (xA - xB) * kk * dx;
445 /* That was 19 flops */
448 template<BondedKernelFlavor flavor>
449 std::enable_if_t<flavor != BondedKernelFlavor::ForcesSimdWhenAvailable || !GMX_SIMD_HAVE_REAL, real>
451 const t_iatom forceatoms[],
452 const t_iparams forceparams[],
459 const t_mdatoms gmx_unused* md,
460 t_fcdata gmx_unused* fcd,
461 int gmx_unused* global_atom_index)
463 int i, ki, ai, aj, type;
464 real dr, dr2, fbond, vbond, vtot;
468 for (i = 0; (i < nbonds);)
470 type = forceatoms[i++];
471 ai = forceatoms[i++];
472 aj = forceatoms[i++];
474 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
475 dr2 = iprod(dx, dx); /* 5 */
476 dr = std::sqrt(dr2); /* 10 */
478 *dvdlambda += harmonic(forceparams[type].harmonic.krA, forceparams[type].harmonic.krB,
479 forceparams[type].harmonic.rA, forceparams[type].harmonic.rB, dr,
480 lambda, &vbond, &fbond); /* 19 */
488 vtot += vbond; /* 1*/
489 fbond *= gmx::invsqrt(dr2); /* 6 */
491 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
496 #if GMX_SIMD_HAVE_REAL
498 /*! \brief Computes forces (only) for harmonic bonds using SIMD intrinsics
500 * As plain-C bonds(), but using SIMD to calculate many bonds at once.
501 * This routines does not calculate energies and shift forces.
503 template<BondedKernelFlavor flavor>
504 std::enable_if_t<flavor == BondedKernelFlavor::ForcesSimdWhenAvailable, real>
506 const t_iatom forceatoms[],
507 const t_iparams forceparams[],
510 rvec gmx_unused fshift[],
512 real gmx_unused lambda,
513 real gmx_unused* dvdlambda,
514 const t_mdatoms gmx_unused* md,
515 t_fcdata gmx_unused* fcd,
516 int gmx_unused* global_atom_index)
518 constexpr int nfa1 = 3;
519 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[GMX_SIMD_REAL_WIDTH];
520 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[GMX_SIMD_REAL_WIDTH];
521 alignas(GMX_SIMD_ALIGNMENT) real coeff[2 * GMX_SIMD_REAL_WIDTH];
523 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9 * GMX_SIMD_REAL_WIDTH];
525 set_pbc_simd(pbc, pbc_simd);
527 const SimdReal real_eps = SimdReal(GMX_REAL_EPS);
529 /* nbonds is the number of bonds times nfa1, here we step GMX_SIMD_REAL_WIDTH angles */
530 for (int i = 0; i < nbonds; i += GMX_SIMD_REAL_WIDTH * nfa1)
532 /* Collect atoms for GMX_SIMD_REAL_WIDTH angles.
533 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
536 for (int s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
538 const int type = forceatoms[iu];
539 ai[s] = forceatoms[iu + 1];
540 aj[s] = forceatoms[iu + 2];
542 /* At the end fill the arrays with the last atoms and 0 params */
543 if (i + s * nfa1 < nbonds)
545 coeff[s] = forceparams[type].harmonic.krA;
546 coeff[GMX_SIMD_REAL_WIDTH + s] = forceparams[type].harmonic.rA;
548 if (iu + nfa1 < nbonds)
556 coeff[GMX_SIMD_REAL_WIDTH + s] = 0;
560 /* Store the non PBC corrected distances packed and aligned */
563 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ai, &xi, &yi, &zi);
564 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), aj, &xj, &yj, &zj);
565 SimdReal rij_x = xi - xj;
566 SimdReal rij_y = yi - yj;
567 SimdReal rij_z = zi - zj;
569 pbc_correct_dx_simd(&rij_x, &rij_y, &rij_z, pbc_simd);
571 const SimdReal dist2 = rij_x * rij_x + rij_y * rij_y + rij_z * rij_z;
572 // Here we avoid sqrt(0), the force will be zero because rij=0
573 const SimdReal invDist = invsqrt(max(dist2, real_eps));
575 const SimdReal k = load<SimdReal>(coeff);
576 const SimdReal r0 = load<SimdReal>(coeff + GMX_SIMD_REAL_WIDTH);
578 // Compute the force divided by the distance
579 const SimdReal forceOverR = -k * (dist2 * invDist - r0) * invDist;
581 const SimdReal f_x = forceOverR * rij_x;
582 const SimdReal f_y = forceOverR * rij_y;
583 const SimdReal f_z = forceOverR * rij_z;
585 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ai, f_x, f_y, f_z);
586 transposeScatterDecrU<4>(reinterpret_cast<real*>(f), aj, f_x, f_y, f_z);
592 #endif // GMX_SIMD_HAVE_REAL
594 template<BondedKernelFlavor flavor>
595 real restraint_bonds(int nbonds,
596 const t_iatom forceatoms[],
597 const t_iparams forceparams[],
604 const t_mdatoms gmx_unused* md,
605 t_fcdata gmx_unused* fcd,
606 int gmx_unused* global_atom_index)
608 int i, ki, ai, aj, type;
609 real dr, dr2, fbond, vbond, vtot;
611 real low, dlow, up1, dup1, up2, dup2, k, dk;
618 for (i = 0; (i < nbonds);)
620 type = forceatoms[i++];
621 ai = forceatoms[i++];
622 aj = forceatoms[i++];
624 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
625 dr2 = iprod(dx, dx); /* 5 */
626 dr = dr2 * gmx::invsqrt(dr2); /* 10 */
628 low = L1 * forceparams[type].restraint.lowA + lambda * forceparams[type].restraint.lowB;
629 dlow = -forceparams[type].restraint.lowA + forceparams[type].restraint.lowB;
630 up1 = L1 * forceparams[type].restraint.up1A + lambda * forceparams[type].restraint.up1B;
631 dup1 = -forceparams[type].restraint.up1A + forceparams[type].restraint.up1B;
632 up2 = L1 * forceparams[type].restraint.up2A + lambda * forceparams[type].restraint.up2B;
633 dup2 = -forceparams[type].restraint.up2A + forceparams[type].restraint.up2B;
634 k = L1 * forceparams[type].restraint.kA + lambda * forceparams[type].restraint.kB;
635 dk = -forceparams[type].restraint.kA + forceparams[type].restraint.kB;
642 vbond = 0.5 * k * drh2;
644 *dvdlambda += 0.5 * dk * drh2 - k * dlow * drh;
655 vbond = 0.5 * k * drh2;
657 *dvdlambda += 0.5 * dk * drh2 - k * dup1 * drh;
662 vbond = k * (up2 - up1) * (0.5 * (up2 - up1) + drh);
663 fbond = -k * (up2 - up1);
664 *dvdlambda += dk * (up2 - up1) * (0.5 * (up2 - up1) + drh)
665 + k * (dup2 - dup1) * (up2 - up1 + drh) - k * (up2 - up1) * dup2;
673 vtot += vbond; /* 1*/
674 fbond *= gmx::invsqrt(dr2); /* 6 */
676 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
682 template<BondedKernelFlavor flavor>
683 real polarize(int nbonds,
684 const t_iatom forceatoms[],
685 const t_iparams forceparams[],
693 t_fcdata gmx_unused* fcd,
694 int gmx_unused* global_atom_index)
696 int i, ki, ai, aj, type;
697 real dr, dr2, fbond, vbond, vtot, ksh;
701 for (i = 0; (i < nbonds);)
703 type = forceatoms[i++];
704 ai = forceatoms[i++];
705 aj = forceatoms[i++];
706 ksh = gmx::square(md->chargeA[aj]) * ONE_4PI_EPS0 / forceparams[type].polarize.alpha;
708 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
709 dr2 = iprod(dx, dx); /* 5 */
710 dr = std::sqrt(dr2); /* 10 */
712 *dvdlambda += harmonic(ksh, ksh, 0, 0, dr, lambda, &vbond, &fbond); /* 19 */
719 vtot += vbond; /* 1*/
720 fbond *= gmx::invsqrt(dr2); /* 6 */
722 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
727 template<BondedKernelFlavor flavor>
728 real anharm_polarize(int nbonds,
729 const t_iatom forceatoms[],
730 const t_iparams forceparams[],
738 t_fcdata gmx_unused* fcd,
739 int gmx_unused* global_atom_index)
741 int i, ki, ai, aj, type;
742 real dr, dr2, fbond, vbond, vtot, ksh, khyp, drcut, ddr, ddr3;
746 for (i = 0; (i < nbonds);)
748 type = forceatoms[i++];
749 ai = forceatoms[i++];
750 aj = forceatoms[i++];
751 ksh = gmx::square(md->chargeA[aj]) * ONE_4PI_EPS0 / forceparams[type].anharm_polarize.alpha; /* 7*/
752 khyp = forceparams[type].anharm_polarize.khyp;
753 drcut = forceparams[type].anharm_polarize.drcut;
755 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
756 dr2 = iprod(dx, dx); /* 5 */
757 dr = dr2 * gmx::invsqrt(dr2); /* 10 */
759 *dvdlambda += harmonic(ksh, ksh, 0, 0, dr, lambda, &vbond, &fbond); /* 19 */
769 ddr3 = ddr * ddr * ddr;
770 vbond += khyp * ddr * ddr3;
771 fbond -= 4 * khyp * ddr3;
773 fbond *= gmx::invsqrt(dr2); /* 6 */
774 vtot += vbond; /* 1*/
776 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
781 template<BondedKernelFlavor flavor>
782 real water_pol(int nbonds,
783 const t_iatom forceatoms[],
784 const t_iparams forceparams[],
787 rvec gmx_unused fshift[],
788 const t_pbc gmx_unused* pbc,
789 real gmx_unused lambda,
790 real gmx_unused* dvdlambda,
791 const t_mdatoms gmx_unused* md,
792 t_fcdata gmx_unused* fcd,
793 int gmx_unused* global_atom_index)
795 /* This routine implements anisotropic polarizibility for water, through
796 * a shell connected to a dummy with spring constant that differ in the
797 * three spatial dimensions in the molecular frame.
799 int i, m, aO, aH1, aH2, aD, aS, type, type0, ki;
800 rvec dOH1, dOH2, dHH, dOD, dDS, nW, kk, dx, kdx, proj;
801 real vtot, fij, r_HH, r_OD, r_nW, tx, ty, tz, qS;
806 type0 = forceatoms[0];
808 qS = md->chargeA[aS];
809 kk[XX] = gmx::square(qS) * ONE_4PI_EPS0 / forceparams[type0].wpol.al_x;
810 kk[YY] = gmx::square(qS) * ONE_4PI_EPS0 / forceparams[type0].wpol.al_y;
811 kk[ZZ] = gmx::square(qS) * ONE_4PI_EPS0 / forceparams[type0].wpol.al_z;
812 r_HH = 1.0 / forceparams[type0].wpol.rHH;
813 for (i = 0; (i < nbonds); i += 6)
815 type = forceatoms[i];
818 gmx_fatal(FARGS, "Sorry, type = %d, type0 = %d, file = %s, line = %d", type, type0,
821 aO = forceatoms[i + 1];
822 aH1 = forceatoms[i + 2];
823 aH2 = forceatoms[i + 3];
824 aD = forceatoms[i + 4];
825 aS = forceatoms[i + 5];
827 /* Compute vectors describing the water frame */
828 pbc_rvec_sub(pbc, x[aH1], x[aO], dOH1);
829 pbc_rvec_sub(pbc, x[aH2], x[aO], dOH2);
830 pbc_rvec_sub(pbc, x[aH2], x[aH1], dHH);
831 pbc_rvec_sub(pbc, x[aD], x[aO], dOD);
832 ki = pbc_rvec_sub(pbc, x[aS], x[aD], dDS);
833 cprod(dOH1, dOH2, nW);
835 /* Compute inverse length of normal vector
836 * (this one could be precomputed, but I'm too lazy now)
838 r_nW = gmx::invsqrt(iprod(nW, nW));
839 /* This is for precision, but does not make a big difference,
842 r_OD = gmx::invsqrt(iprod(dOD, dOD));
844 /* Normalize the vectors in the water frame */
846 svmul(r_HH, dHH, dHH);
847 svmul(r_OD, dOD, dOD);
849 /* Compute displacement of shell along components of the vector */
850 dx[ZZ] = iprod(dDS, dOD);
851 /* Compute projection on the XY plane: dDS - dx[ZZ]*dOD */
852 for (m = 0; (m < DIM); m++)
854 proj[m] = dDS[m] - dx[ZZ] * dOD[m];
857 /*dx[XX] = iprod(dDS,nW);
858 dx[YY] = iprod(dDS,dHH);*/
859 dx[XX] = iprod(proj, nW);
860 for (m = 0; (m < DIM); m++)
862 proj[m] -= dx[XX] * nW[m];
864 dx[YY] = iprod(proj, dHH);
865 /* Now compute the forces and energy */
866 kdx[XX] = kk[XX] * dx[XX];
867 kdx[YY] = kk[YY] * dx[YY];
868 kdx[ZZ] = kk[ZZ] * dx[ZZ];
869 vtot += iprod(dx, kdx);
871 for (m = 0; (m < DIM); m++)
873 /* This is a tensor operation but written out for speed */
874 tx = nW[m] * kdx[XX];
875 ty = dHH[m] * kdx[YY];
876 tz = dOD[m] * kdx[ZZ];
880 if (computeVirial(flavor))
882 fshift[ki][m] += fij;
883 fshift[CENTRAL][m] -= fij;
891 template<BondedKernelFlavor flavor>
893 do_1_thole(const rvec xi, const rvec xj, rvec fi, rvec fj, const t_pbc* pbc, real qq, rvec fshift[], real afac)
896 real r12sq, r12_1, r12bar, v0, v1, fscal, ebar, fff;
899 t = pbc_rvec_sub(pbc, xi, xj, r12); /* 3 */
901 r12sq = iprod(r12, r12); /* 5 */
902 r12_1 = gmx::invsqrt(r12sq); /* 5 */
903 r12bar = afac / r12_1; /* 5 */
904 v0 = qq * ONE_4PI_EPS0 * r12_1; /* 2 */
905 ebar = std::exp(-r12bar); /* 5 */
906 v1 = (1 - (1 + 0.5 * r12bar) * ebar); /* 4 */
907 fscal = ((v0 * r12_1) * v1 - v0 * 0.5 * afac * ebar * (r12bar + 1)) * r12_1; /* 9 */
909 for (m = 0; (m < DIM); m++)
911 fff = fscal * r12[m];
914 if (computeVirial(flavor))
917 fshift[CENTRAL][m] -= fff;
921 return v0 * v1; /* 1 */
925 template<BondedKernelFlavor flavor>
926 real thole_pol(int nbonds,
927 const t_iatom forceatoms[],
928 const t_iparams forceparams[],
933 real gmx_unused lambda,
934 real gmx_unused* dvdlambda,
936 t_fcdata gmx_unused* fcd,
937 int gmx_unused* global_atom_index)
939 /* Interaction between two pairs of particles with opposite charge */
940 int i, type, a1, da1, a2, da2;
941 real q1, q2, qq, a, al1, al2, afac;
944 for (i = 0; (i < nbonds);)
946 type = forceatoms[i++];
947 a1 = forceatoms[i++];
948 da1 = forceatoms[i++];
949 a2 = forceatoms[i++];
950 da2 = forceatoms[i++];
951 q1 = md->chargeA[da1];
952 q2 = md->chargeA[da2];
953 a = forceparams[type].thole.a;
954 al1 = forceparams[type].thole.alpha1;
955 al2 = forceparams[type].thole.alpha2;
957 afac = a * gmx::invsixthroot(al1 * al2);
958 V += do_1_thole<flavor>(x[a1], x[a2], f[a1], f[a2], pbc, qq, fshift, afac);
959 V += do_1_thole<flavor>(x[da1], x[a2], f[da1], f[a2], pbc, -qq, fshift, afac);
960 V += do_1_thole<flavor>(x[a1], x[da2], f[a1], f[da2], pbc, -qq, fshift, afac);
961 V += do_1_thole<flavor>(x[da1], x[da2], f[da1], f[da2], pbc, qq, fshift, afac);
967 // Avoid gcc 386 -O3 code generation bug in this function (see Issue
968 // #3205 for more information)
969 #if defined(__GNUC__) && defined(__i386__) && defined(__OPTIMIZE__)
970 # pragma GCC push_options
971 # pragma GCC optimize("O1")
972 # define avoid_gcc_i386_o3_code_generation_bug
975 template<BondedKernelFlavor flavor>
976 std::enable_if_t<flavor != BondedKernelFlavor::ForcesSimdWhenAvailable || !GMX_SIMD_HAVE_REAL, real>
978 const t_iatom forceatoms[],
979 const t_iparams forceparams[],
986 const t_mdatoms gmx_unused* md,
987 t_fcdata gmx_unused* fcd,
988 int gmx_unused* global_atom_index)
990 int i, ai, aj, ak, t1, t2, type;
992 real cos_theta, cos_theta2, theta, dVdt, va, vtot;
995 for (i = 0; i < nbonds;)
997 type = forceatoms[i++];
998 ai = forceatoms[i++];
999 aj = forceatoms[i++];
1000 ak = forceatoms[i++];
1002 theta = bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
1004 *dvdlambda += harmonic(forceparams[type].harmonic.krA, forceparams[type].harmonic.krB,
1005 forceparams[type].harmonic.rA * DEG2RAD,
1006 forceparams[type].harmonic.rB * DEG2RAD, theta, lambda, &va, &dVdt); /* 21 */
1009 cos_theta2 = gmx::square(cos_theta);
1016 real nrkj_1, nrij_1;
1019 st = dVdt * gmx::invsqrt(1 - cos_theta2); /* 12 */
1020 sth = st * cos_theta; /* 1 */
1021 nrij2 = iprod(r_ij, r_ij); /* 5 */
1022 nrkj2 = iprod(r_kj, r_kj); /* 5 */
1024 nrij_1 = gmx::invsqrt(nrij2); /* 10 */
1025 nrkj_1 = gmx::invsqrt(nrkj2); /* 10 */
1027 cik = st * nrij_1 * nrkj_1; /* 2 */
1028 cii = sth * nrij_1 * nrij_1; /* 2 */
1029 ckk = sth * nrkj_1 * nrkj_1; /* 2 */
1031 for (m = 0; m < DIM; m++)
1033 f_i[m] = -(cik * r_kj[m] - cii * r_ij[m]);
1034 f_k[m] = -(cik * r_ij[m] - ckk * r_kj[m]);
1035 f_j[m] = -f_i[m] - f_k[m];
1040 if (computeVirial(flavor))
1042 rvec_inc(fshift[t1], f_i);
1043 rvec_inc(fshift[CENTRAL], f_j);
1044 rvec_inc(fshift[t2], f_k);
1052 #ifdef avoid_gcc_i386_o3_code_generation_bug
1053 # pragma GCC pop_options
1054 # undef avoid_gcc_i386_o3_code_generation_bug
1057 #if GMX_SIMD_HAVE_REAL
1059 /* As angles, but using SIMD to calculate many angles at once.
1060 * This routines does not calculate energies and shift forces.
1062 template<BondedKernelFlavor flavor>
1063 std::enable_if_t<flavor == BondedKernelFlavor::ForcesSimdWhenAvailable, real>
1065 const t_iatom forceatoms[],
1066 const t_iparams forceparams[],
1069 rvec gmx_unused fshift[],
1071 real gmx_unused lambda,
1072 real gmx_unused* dvdlambda,
1073 const t_mdatoms gmx_unused* md,
1074 t_fcdata gmx_unused* fcd,
1075 int gmx_unused* global_atom_index)
1080 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[GMX_SIMD_REAL_WIDTH];
1081 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[GMX_SIMD_REAL_WIDTH];
1082 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ak[GMX_SIMD_REAL_WIDTH];
1083 alignas(GMX_SIMD_ALIGNMENT) real coeff[2 * GMX_SIMD_REAL_WIDTH];
1084 SimdReal deg2rad_S(DEG2RAD);
1085 SimdReal xi_S, yi_S, zi_S;
1086 SimdReal xj_S, yj_S, zj_S;
1087 SimdReal xk_S, yk_S, zk_S;
1088 SimdReal k_S, theta0_S;
1089 SimdReal rijx_S, rijy_S, rijz_S;
1090 SimdReal rkjx_S, rkjy_S, rkjz_S;
1091 SimdReal one_S(1.0);
1092 SimdReal one_min_eps_S(1.0_real - GMX_REAL_EPS); // Largest number < 1
1095 SimdReal nrij2_S, nrij_1_S;
1096 SimdReal nrkj2_S, nrkj_1_S;
1097 SimdReal cos_S, invsin_S;
1100 SimdReal st_S, sth_S;
1101 SimdReal cik_S, cii_S, ckk_S;
1102 SimdReal f_ix_S, f_iy_S, f_iz_S;
1103 SimdReal f_kx_S, f_ky_S, f_kz_S;
1104 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9 * GMX_SIMD_REAL_WIDTH];
1106 set_pbc_simd(pbc, pbc_simd);
1108 /* nbonds is the number of angles times nfa1, here we step GMX_SIMD_REAL_WIDTH angles */
1109 for (i = 0; (i < nbonds); i += GMX_SIMD_REAL_WIDTH * nfa1)
1111 /* Collect atoms for GMX_SIMD_REAL_WIDTH angles.
1112 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
1115 for (s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
1117 type = forceatoms[iu];
1118 ai[s] = forceatoms[iu + 1];
1119 aj[s] = forceatoms[iu + 2];
1120 ak[s] = forceatoms[iu + 3];
1122 /* At the end fill the arrays with the last atoms and 0 params */
1123 if (i + s * nfa1 < nbonds)
1125 coeff[s] = forceparams[type].harmonic.krA;
1126 coeff[GMX_SIMD_REAL_WIDTH + s] = forceparams[type].harmonic.rA;
1128 if (iu + nfa1 < nbonds)
1136 coeff[GMX_SIMD_REAL_WIDTH + s] = 0;
1140 /* Store the non PBC corrected distances packed and aligned */
1141 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ai, &xi_S, &yi_S, &zi_S);
1142 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), aj, &xj_S, &yj_S, &zj_S);
1143 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ak, &xk_S, &yk_S, &zk_S);
1144 rijx_S = xi_S - xj_S;
1145 rijy_S = yi_S - yj_S;
1146 rijz_S = zi_S - zj_S;
1147 rkjx_S = xk_S - xj_S;
1148 rkjy_S = yk_S - yj_S;
1149 rkjz_S = zk_S - zj_S;
1151 k_S = load<SimdReal>(coeff);
1152 theta0_S = load<SimdReal>(coeff + GMX_SIMD_REAL_WIDTH) * deg2rad_S;
1154 pbc_correct_dx_simd(&rijx_S, &rijy_S, &rijz_S, pbc_simd);
1155 pbc_correct_dx_simd(&rkjx_S, &rkjy_S, &rkjz_S, pbc_simd);
1157 rij_rkj_S = iprod(rijx_S, rijy_S, rijz_S, rkjx_S, rkjy_S, rkjz_S);
1159 nrij2_S = norm2(rijx_S, rijy_S, rijz_S);
1160 nrkj2_S = norm2(rkjx_S, rkjy_S, rkjz_S);
1162 nrij_1_S = invsqrt(nrij2_S);
1163 nrkj_1_S = invsqrt(nrkj2_S);
1165 cos_S = rij_rkj_S * nrij_1_S * nrkj_1_S;
1167 /* We compute cos^2 using a division instead of squaring cos_S,
1168 * as we would then get additional error contributions from
1169 * the two invsqrt operations, which get amplified by
1170 * the 1/sqrt(1-cos^2) for cos values close to 1.
1172 * Note that the non-SIMD version of angles() avoids this issue
1173 * by computing the cosine using double precision.
1175 cos2_S = rij_rkj_S * rij_rkj_S / (nrij2_S * nrkj2_S);
1177 /* To allow for 0 and 180 degrees, we need to avoid issues when
1178 * the cosine is close to -1 and 1. For acos() the argument needs
1179 * to be in that range. For cos^2 we take the min of cos^2 and 1 - 1bit,
1180 * so we can safely compute 1/sin as 1/sqrt(1 - cos^2).
1182 cos_S = max(cos_S, -one_S);
1183 cos_S = min(cos_S, one_S);
1184 cos2_S = min(cos2_S, one_min_eps_S);
1186 theta_S = acos(cos_S);
1188 invsin_S = invsqrt(one_S - cos2_S);
1190 st_S = k_S * (theta0_S - theta_S) * invsin_S;
1191 sth_S = st_S * cos_S;
1193 cik_S = st_S * nrij_1_S * nrkj_1_S;
1194 cii_S = sth_S * nrij_1_S * nrij_1_S;
1195 ckk_S = sth_S * nrkj_1_S * nrkj_1_S;
1197 f_ix_S = cii_S * rijx_S;
1198 f_ix_S = fnma(cik_S, rkjx_S, f_ix_S);
1199 f_iy_S = cii_S * rijy_S;
1200 f_iy_S = fnma(cik_S, rkjy_S, f_iy_S);
1201 f_iz_S = cii_S * rijz_S;
1202 f_iz_S = fnma(cik_S, rkjz_S, f_iz_S);
1203 f_kx_S = ckk_S * rkjx_S;
1204 f_kx_S = fnma(cik_S, rijx_S, f_kx_S);
1205 f_ky_S = ckk_S * rkjy_S;
1206 f_ky_S = fnma(cik_S, rijy_S, f_ky_S);
1207 f_kz_S = ckk_S * rkjz_S;
1208 f_kz_S = fnma(cik_S, rijz_S, f_kz_S);
1210 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ai, f_ix_S, f_iy_S, f_iz_S);
1211 transposeScatterDecrU<4>(reinterpret_cast<real*>(f), aj, f_ix_S + f_kx_S, f_iy_S + f_ky_S,
1213 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ak, f_kx_S, f_ky_S, f_kz_S);
1219 #endif // GMX_SIMD_HAVE_REAL
1221 template<BondedKernelFlavor flavor>
1222 real linear_angles(int nbonds,
1223 const t_iatom forceatoms[],
1224 const t_iparams forceparams[],
1231 const t_mdatoms gmx_unused* md,
1232 t_fcdata gmx_unused* fcd,
1233 int gmx_unused* global_atom_index)
1235 int i, m, ai, aj, ak, t1, t2, type;
1237 real L1, kA, kB, aA, aB, dr, dr2, va, vtot, a, b, klin;
1238 rvec r_ij, r_kj, r_ik, dx;
1242 for (i = 0; (i < nbonds);)
1244 type = forceatoms[i++];
1245 ai = forceatoms[i++];
1246 aj = forceatoms[i++];
1247 ak = forceatoms[i++];
1249 kA = forceparams[type].linangle.klinA;
1250 kB = forceparams[type].linangle.klinB;
1251 klin = L1 * kA + lambda * kB;
1253 aA = forceparams[type].linangle.aA;
1254 aB = forceparams[type].linangle.aB;
1255 a = L1 * aA + lambda * aB;
1258 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], r_ij);
1259 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], r_kj);
1260 rvec_sub(r_ij, r_kj, r_ik);
1263 for (m = 0; (m < DIM); m++)
1265 dr = -a * r_ij[m] - b * r_kj[m];
1268 f_i[m] = a * klin * dr;
1269 f_k[m] = b * klin * dr;
1270 f_j[m] = -(f_i[m] + f_k[m]);
1275 va = 0.5 * klin * dr2;
1276 *dvdlambda += 0.5 * (kB - kA) * dr2 + klin * (aB - aA) * iprod(dx, r_ik);
1280 if (computeVirial(flavor))
1282 rvec_inc(fshift[t1], f_i);
1283 rvec_inc(fshift[CENTRAL], f_j);
1284 rvec_inc(fshift[t2], f_k);
1290 template<BondedKernelFlavor flavor>
1291 std::enable_if_t<flavor != BondedKernelFlavor::ForcesSimdWhenAvailable || !GMX_SIMD_HAVE_REAL, real>
1292 urey_bradley(int nbonds,
1293 const t_iatom forceatoms[],
1294 const t_iparams forceparams[],
1301 const t_mdatoms gmx_unused* md,
1302 t_fcdata gmx_unused* fcd,
1303 int gmx_unused* global_atom_index)
1305 int i, m, ai, aj, ak, t1, t2, type, ki;
1306 rvec r_ij, r_kj, r_ik;
1307 real cos_theta, cos_theta2, theta;
1308 real dVdt, va, vtot, dr, dr2, vbond, fbond, fik;
1309 real kthA, th0A, kUBA, r13A, kthB, th0B, kUBB, r13B;
1312 for (i = 0; (i < nbonds);)
1314 type = forceatoms[i++];
1315 ai = forceatoms[i++];
1316 aj = forceatoms[i++];
1317 ak = forceatoms[i++];
1318 th0A = forceparams[type].u_b.thetaA * DEG2RAD;
1319 kthA = forceparams[type].u_b.kthetaA;
1320 r13A = forceparams[type].u_b.r13A;
1321 kUBA = forceparams[type].u_b.kUBA;
1322 th0B = forceparams[type].u_b.thetaB * DEG2RAD;
1323 kthB = forceparams[type].u_b.kthetaB;
1324 r13B = forceparams[type].u_b.r13B;
1325 kUBB = forceparams[type].u_b.kUBB;
1327 theta = bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
1329 *dvdlambda += harmonic(kthA, kthB, th0A, th0B, theta, lambda, &va, &dVdt); /* 21 */
1332 ki = pbc_rvec_sub(pbc, x[ai], x[ak], r_ik); /* 3 */
1333 dr2 = iprod(r_ik, r_ik); /* 5 */
1334 dr = dr2 * gmx::invsqrt(dr2); /* 10 */
1336 *dvdlambda += harmonic(kUBA, kUBB, r13A, r13B, dr, lambda, &vbond, &fbond); /* 19 */
1338 cos_theta2 = gmx::square(cos_theta); /* 1 */
1346 st = dVdt * gmx::invsqrt(1 - cos_theta2); /* 12 */
1347 sth = st * cos_theta; /* 1 */
1348 nrkj2 = iprod(r_kj, r_kj); /* 5 */
1349 nrij2 = iprod(r_ij, r_ij);
1351 cik = st * gmx::invsqrt(nrkj2 * nrij2); /* 12 */
1352 cii = sth / nrij2; /* 10 */
1353 ckk = sth / nrkj2; /* 10 */
1355 for (m = 0; (m < DIM); m++) /* 39 */
1357 f_i[m] = -(cik * r_kj[m] - cii * r_ij[m]);
1358 f_k[m] = -(cik * r_ij[m] - ckk * r_kj[m]);
1359 f_j[m] = -f_i[m] - f_k[m];
1364 if (computeVirial(flavor))
1366 rvec_inc(fshift[t1], f_i);
1367 rvec_inc(fshift[CENTRAL], f_j);
1368 rvec_inc(fshift[t2], f_k);
1371 /* Time for the bond calculations */
1377 vtot += vbond; /* 1*/
1378 fbond *= gmx::invsqrt(dr2); /* 6 */
1380 for (m = 0; (m < DIM); m++) /* 15 */
1382 fik = fbond * r_ik[m];
1385 if (computeVirial(flavor))
1387 fshift[ki][m] += fik;
1388 fshift[CENTRAL][m] -= fik;
1395 #if GMX_SIMD_HAVE_REAL
1397 /* As urey_bradley, but using SIMD to calculate many potentials at once.
1398 * This routines does not calculate energies and shift forces.
1400 template<BondedKernelFlavor flavor>
1401 std::enable_if_t<flavor == BondedKernelFlavor::ForcesSimdWhenAvailable, real>
1402 urey_bradley(int nbonds,
1403 const t_iatom forceatoms[],
1404 const t_iparams forceparams[],
1407 rvec gmx_unused fshift[],
1409 real gmx_unused lambda,
1410 real gmx_unused* dvdlambda,
1411 const t_mdatoms gmx_unused* md,
1412 t_fcdata gmx_unused* fcd,
1413 int gmx_unused* global_atom_index)
1415 constexpr int nfa1 = 4;
1416 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[GMX_SIMD_REAL_WIDTH];
1417 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[GMX_SIMD_REAL_WIDTH];
1418 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ak[GMX_SIMD_REAL_WIDTH];
1419 alignas(GMX_SIMD_ALIGNMENT) real coeff[4 * GMX_SIMD_REAL_WIDTH];
1420 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9 * GMX_SIMD_REAL_WIDTH];
1422 set_pbc_simd(pbc, pbc_simd);
1424 /* nbonds is the number of angles times nfa1, here we step GMX_SIMD_REAL_WIDTH angles */
1425 for (int i = 0; i < nbonds; i += GMX_SIMD_REAL_WIDTH * nfa1)
1427 /* Collect atoms for GMX_SIMD_REAL_WIDTH angles.
1428 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
1431 for (int s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
1433 const int type = forceatoms[iu];
1434 ai[s] = forceatoms[iu + 1];
1435 aj[s] = forceatoms[iu + 2];
1436 ak[s] = forceatoms[iu + 3];
1438 /* At the end fill the arrays with the last atoms and 0 params */
1439 if (i + s * nfa1 < nbonds)
1441 coeff[s] = forceparams[type].u_b.kthetaA;
1442 coeff[GMX_SIMD_REAL_WIDTH + s] = forceparams[type].u_b.thetaA;
1443 coeff[GMX_SIMD_REAL_WIDTH * 2 + s] = forceparams[type].u_b.kUBA;
1444 coeff[GMX_SIMD_REAL_WIDTH * 3 + s] = forceparams[type].u_b.r13A;
1446 if (iu + nfa1 < nbonds)
1454 coeff[GMX_SIMD_REAL_WIDTH + s] = 0;
1455 coeff[GMX_SIMD_REAL_WIDTH * 2 + s] = 0;
1456 coeff[GMX_SIMD_REAL_WIDTH * 3 + s] = 0;
1460 SimdReal xi_S, yi_S, zi_S;
1461 SimdReal xj_S, yj_S, zj_S;
1462 SimdReal xk_S, yk_S, zk_S;
1464 /* Store the non PBC corrected distances packed and aligned */
1465 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ai, &xi_S, &yi_S, &zi_S);
1466 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), aj, &xj_S, &yj_S, &zj_S);
1467 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ak, &xk_S, &yk_S, &zk_S);
1468 SimdReal rijx_S = xi_S - xj_S;
1469 SimdReal rijy_S = yi_S - yj_S;
1470 SimdReal rijz_S = zi_S - zj_S;
1471 SimdReal rkjx_S = xk_S - xj_S;
1472 SimdReal rkjy_S = yk_S - yj_S;
1473 SimdReal rkjz_S = zk_S - zj_S;
1474 SimdReal rikx_S = xi_S - xk_S;
1475 SimdReal riky_S = yi_S - yk_S;
1476 SimdReal rikz_S = zi_S - zk_S;
1478 const SimdReal ktheta_S = load<SimdReal>(coeff);
1479 const SimdReal theta0_S = load<SimdReal>(coeff + GMX_SIMD_REAL_WIDTH) * DEG2RAD;
1480 const SimdReal kUB_S = load<SimdReal>(coeff + 2 * GMX_SIMD_REAL_WIDTH);
1481 const SimdReal r13_S = load<SimdReal>(coeff + 3 * GMX_SIMD_REAL_WIDTH);
1483 pbc_correct_dx_simd(&rijx_S, &rijy_S, &rijz_S, pbc_simd);
1484 pbc_correct_dx_simd(&rkjx_S, &rkjy_S, &rkjz_S, pbc_simd);
1485 pbc_correct_dx_simd(&rikx_S, &riky_S, &rikz_S, pbc_simd);
1487 const SimdReal rij_rkj_S = iprod(rijx_S, rijy_S, rijz_S, rkjx_S, rkjy_S, rkjz_S);
1489 const SimdReal dr2_S = iprod(rikx_S, riky_S, rikz_S, rikx_S, riky_S, rikz_S);
1491 const SimdReal nrij2_S = norm2(rijx_S, rijy_S, rijz_S);
1492 const SimdReal nrkj2_S = norm2(rkjx_S, rkjy_S, rkjz_S);
1494 const SimdReal nrij_1_S = invsqrt(nrij2_S);
1495 const SimdReal nrkj_1_S = invsqrt(nrkj2_S);
1496 const SimdReal invdr2_S = invsqrt(dr2_S);
1497 const SimdReal dr_S = dr2_S * invdr2_S;
1499 constexpr real min_one_plus_eps = -1.0 + 2.0 * GMX_REAL_EPS; // Smallest number > -1
1501 /* To allow for 180 degrees, we take the max of cos and -1 + 1bit,
1502 * so we can safely get the 1/sin from 1/sqrt(1 - cos^2).
1503 * This also ensures that rounding errors would cause the argument
1504 * of simdAcos to be < -1.
1505 * Note that we do not take precautions for cos(0)=1, so the bonds
1506 * in an angle should not align at an angle of 0 degrees.
1508 const SimdReal cos_S = max(rij_rkj_S * nrij_1_S * nrkj_1_S, min_one_plus_eps);
1510 const SimdReal theta_S = acos(cos_S);
1511 const SimdReal invsin_S = invsqrt(1.0 - cos_S * cos_S);
1512 const SimdReal st_S = ktheta_S * (theta0_S - theta_S) * invsin_S;
1513 const SimdReal sth_S = st_S * cos_S;
1515 const SimdReal cik_S = st_S * nrij_1_S * nrkj_1_S;
1516 const SimdReal cii_S = sth_S * nrij_1_S * nrij_1_S;
1517 const SimdReal ckk_S = sth_S * nrkj_1_S * nrkj_1_S;
1519 const SimdReal sUB_S = kUB_S * (r13_S - dr_S) * invdr2_S;
1521 const SimdReal f_ikx_S = sUB_S * rikx_S;
1522 const SimdReal f_iky_S = sUB_S * riky_S;
1523 const SimdReal f_ikz_S = sUB_S * rikz_S;
1525 const SimdReal f_ix_S = fnma(cik_S, rkjx_S, cii_S * rijx_S) + f_ikx_S;
1526 const SimdReal f_iy_S = fnma(cik_S, rkjy_S, cii_S * rijy_S) + f_iky_S;
1527 const SimdReal f_iz_S = fnma(cik_S, rkjz_S, cii_S * rijz_S) + f_ikz_S;
1528 const SimdReal f_kx_S = fnma(cik_S, rijx_S, ckk_S * rkjx_S) - f_ikx_S;
1529 const SimdReal f_ky_S = fnma(cik_S, rijy_S, ckk_S * rkjy_S) - f_iky_S;
1530 const SimdReal f_kz_S = fnma(cik_S, rijz_S, ckk_S * rkjz_S) - f_ikz_S;
1532 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ai, f_ix_S, f_iy_S, f_iz_S);
1533 transposeScatterDecrU<4>(reinterpret_cast<real*>(f), aj, f_ix_S + f_kx_S, f_iy_S + f_ky_S,
1535 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ak, f_kx_S, f_ky_S, f_kz_S);
1541 #endif // GMX_SIMD_HAVE_REAL
1543 template<BondedKernelFlavor flavor>
1544 real quartic_angles(int nbonds,
1545 const t_iatom forceatoms[],
1546 const t_iparams forceparams[],
1551 real gmx_unused lambda,
1552 real gmx_unused* dvdlambda,
1553 const t_mdatoms gmx_unused* md,
1554 t_fcdata gmx_unused* fcd,
1555 int gmx_unused* global_atom_index)
1557 int i, j, ai, aj, ak, t1, t2, type;
1559 real cos_theta, cos_theta2, theta, dt, dVdt, va, dtp, c, vtot;
1562 for (i = 0; (i < nbonds);)
1564 type = forceatoms[i++];
1565 ai = forceatoms[i++];
1566 aj = forceatoms[i++];
1567 ak = forceatoms[i++];
1569 theta = bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
1571 dt = theta - forceparams[type].qangle.theta * DEG2RAD; /* 2 */
1574 va = forceparams[type].qangle.c[0];
1576 for (j = 1; j <= 4; j++)
1578 c = forceparams[type].qangle.c[j];
1579 dVdt -= j * c * dtp;
1587 cos_theta2 = gmx::square(cos_theta); /* 1 */
1596 st = dVdt * gmx::invsqrt(1 - cos_theta2); /* 12 */
1597 sth = st * cos_theta; /* 1 */
1598 nrkj2 = iprod(r_kj, r_kj); /* 5 */
1599 nrij2 = iprod(r_ij, r_ij);
1601 cik = st * gmx::invsqrt(nrkj2 * nrij2); /* 12 */
1602 cii = sth / nrij2; /* 10 */
1603 ckk = sth / nrkj2; /* 10 */
1605 for (m = 0; (m < DIM); m++) /* 39 */
1607 f_i[m] = -(cik * r_kj[m] - cii * r_ij[m]);
1608 f_k[m] = -(cik * r_ij[m] - ckk * r_kj[m]);
1609 f_j[m] = -f_i[m] - f_k[m];
1615 if (computeVirial(flavor))
1617 rvec_inc(fshift[t1], f_i);
1618 rvec_inc(fshift[CENTRAL], f_j);
1619 rvec_inc(fshift[t2], f_k);
1627 #if GMX_SIMD_HAVE_REAL
1629 /* As dih_angle above, but calculates 4 dihedral angles at once using SIMD,
1630 * also calculates the pre-factor required for the dihedral force update.
1631 * Note that bv and buf should be register aligned.
1633 inline void dih_angle_simd(const rvec* x,
1638 const real* pbc_simd,
1646 SimdReal* nrkj_m2_S,
1647 SimdReal* nrkj_n2_S,
1651 SimdReal xi_S, yi_S, zi_S;
1652 SimdReal xj_S, yj_S, zj_S;
1653 SimdReal xk_S, yk_S, zk_S;
1654 SimdReal xl_S, yl_S, zl_S;
1655 SimdReal rijx_S, rijy_S, rijz_S;
1656 SimdReal rkjx_S, rkjy_S, rkjz_S;
1657 SimdReal rklx_S, rkly_S, rklz_S;
1658 SimdReal cx_S, cy_S, cz_S;
1662 SimdReal iprm_S, iprn_S;
1663 SimdReal nrkj2_S, nrkj_1_S, nrkj_2_S, nrkj_S;
1665 SimdReal nrkj2_min_S;
1666 SimdReal real_eps_S;
1668 /* Used to avoid division by zero.
1669 * We take into acount that we multiply the result by real_eps_S.
1671 nrkj2_min_S = SimdReal(GMX_REAL_MIN / (2 * GMX_REAL_EPS));
1673 /* The value of the last significant bit (GMX_REAL_EPS is half of that) */
1674 real_eps_S = SimdReal(2 * GMX_REAL_EPS);
1676 /* Store the non PBC corrected distances packed and aligned */
1677 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ai, &xi_S, &yi_S, &zi_S);
1678 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), aj, &xj_S, &yj_S, &zj_S);
1679 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ak, &xk_S, &yk_S, &zk_S);
1680 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), al, &xl_S, &yl_S, &zl_S);
1681 rijx_S = xi_S - xj_S;
1682 rijy_S = yi_S - yj_S;
1683 rijz_S = zi_S - zj_S;
1684 rkjx_S = xk_S - xj_S;
1685 rkjy_S = yk_S - yj_S;
1686 rkjz_S = zk_S - zj_S;
1687 rklx_S = xk_S - xl_S;
1688 rkly_S = yk_S - yl_S;
1689 rklz_S = zk_S - zl_S;
1691 pbc_correct_dx_simd(&rijx_S, &rijy_S, &rijz_S, pbc_simd);
1692 pbc_correct_dx_simd(&rkjx_S, &rkjy_S, &rkjz_S, pbc_simd);
1693 pbc_correct_dx_simd(&rklx_S, &rkly_S, &rklz_S, pbc_simd);
1695 cprod(rijx_S, rijy_S, rijz_S, rkjx_S, rkjy_S, rkjz_S, mx_S, my_S, mz_S);
1697 cprod(rkjx_S, rkjy_S, rkjz_S, rklx_S, rkly_S, rklz_S, nx_S, ny_S, nz_S);
1699 cprod(*mx_S, *my_S, *mz_S, *nx_S, *ny_S, *nz_S, &cx_S, &cy_S, &cz_S);
1701 cn_S = sqrt(norm2(cx_S, cy_S, cz_S));
1703 s_S = iprod(*mx_S, *my_S, *mz_S, *nx_S, *ny_S, *nz_S);
1705 /* Determine the dihedral angle, the sign might need correction */
1706 *phi_S = atan2(cn_S, s_S);
1708 ipr_S = iprod(rijx_S, rijy_S, rijz_S, *nx_S, *ny_S, *nz_S);
1710 iprm_S = norm2(*mx_S, *my_S, *mz_S);
1711 iprn_S = norm2(*nx_S, *ny_S, *nz_S);
1713 nrkj2_S = norm2(rkjx_S, rkjy_S, rkjz_S);
1715 /* Avoid division by zero. When zero, the result is multiplied by 0
1716 * anyhow, so the 3 max below do not affect the final result.
1718 nrkj2_S = max(nrkj2_S, nrkj2_min_S);
1719 nrkj_1_S = invsqrt(nrkj2_S);
1720 nrkj_2_S = nrkj_1_S * nrkj_1_S;
1721 nrkj_S = nrkj2_S * nrkj_1_S;
1723 toler_S = nrkj2_S * real_eps_S;
1725 /* Here the plain-C code uses a conditional, but we can't do that in SIMD.
1726 * So we take a max with the tolerance instead. Since we multiply with
1727 * m or n later, the max does not affect the results.
1729 iprm_S = max(iprm_S, toler_S);
1730 iprn_S = max(iprn_S, toler_S);
1731 *nrkj_m2_S = nrkj_S * inv(iprm_S);
1732 *nrkj_n2_S = nrkj_S * inv(iprn_S);
1734 /* Set sign of phi_S with the sign of ipr_S; phi_S is currently positive */
1735 *phi_S = copysign(*phi_S, ipr_S);
1736 *p_S = iprod(rijx_S, rijy_S, rijz_S, rkjx_S, rkjy_S, rkjz_S);
1737 *p_S = *p_S * nrkj_2_S;
1739 *q_S = iprod(rklx_S, rkly_S, rklz_S, rkjx_S, rkjy_S, rkjz_S);
1740 *q_S = *q_S * nrkj_2_S;
1743 #endif // GMX_SIMD_HAVE_REAL
1747 template<BondedKernelFlavor flavor>
1748 void do_dih_fup(int i,
1767 rvec f_i, f_j, f_k, f_l;
1768 rvec uvec, vvec, svec, dx_jl;
1769 real iprm, iprn, nrkj, nrkj2, nrkj_1, nrkj_2;
1770 real a, b, p, q, toler;
1772 iprm = iprod(m, m); /* 5 */
1773 iprn = iprod(n, n); /* 5 */
1774 nrkj2 = iprod(r_kj, r_kj); /* 5 */
1775 toler = nrkj2 * GMX_REAL_EPS;
1776 if ((iprm > toler) && (iprn > toler))
1778 nrkj_1 = gmx::invsqrt(nrkj2); /* 10 */
1779 nrkj_2 = nrkj_1 * nrkj_1; /* 1 */
1780 nrkj = nrkj2 * nrkj_1; /* 1 */
1781 a = -ddphi * nrkj / iprm; /* 11 */
1782 svmul(a, m, f_i); /* 3 */
1783 b = ddphi * nrkj / iprn; /* 11 */
1784 svmul(b, n, f_l); /* 3 */
1785 p = iprod(r_ij, r_kj); /* 5 */
1786 p *= nrkj_2; /* 1 */
1787 q = iprod(r_kl, r_kj); /* 5 */
1788 q *= nrkj_2; /* 1 */
1789 svmul(p, f_i, uvec); /* 3 */
1790 svmul(q, f_l, vvec); /* 3 */
1791 rvec_sub(uvec, vvec, svec); /* 3 */
1792 rvec_sub(f_i, svec, f_j); /* 3 */
1793 rvec_add(f_l, svec, f_k); /* 3 */
1794 rvec_inc(f[i], f_i); /* 3 */
1795 rvec_dec(f[j], f_j); /* 3 */
1796 rvec_dec(f[k], f_k); /* 3 */
1797 rvec_inc(f[l], f_l); /* 3 */
1799 if (computeVirial(flavor))
1803 t3 = pbc_rvec_sub(pbc, x[l], x[j], dx_jl);
1810 rvec_inc(fshift[t1], f_i);
1811 rvec_dec(fshift[CENTRAL], f_j);
1812 rvec_dec(fshift[t2], f_k);
1813 rvec_inc(fshift[t3], f_l);
1822 #if GMX_SIMD_HAVE_REAL
1823 /* As do_dih_fup_noshiftf above, but with SIMD and pre-calculated pre-factors */
1824 inline void gmx_simdcall do_dih_fup_noshiftf_simd(const int* ai,
1838 SimdReal sx = p * f_i_x + q * mf_l_x;
1839 SimdReal sy = p * f_i_y + q * mf_l_y;
1840 SimdReal sz = p * f_i_z + q * mf_l_z;
1841 SimdReal f_j_x = f_i_x - sx;
1842 SimdReal f_j_y = f_i_y - sy;
1843 SimdReal f_j_z = f_i_z - sz;
1844 SimdReal f_k_x = mf_l_x - sx;
1845 SimdReal f_k_y = mf_l_y - sy;
1846 SimdReal f_k_z = mf_l_z - sz;
1847 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ai, f_i_x, f_i_y, f_i_z);
1848 transposeScatterDecrU<4>(reinterpret_cast<real*>(f), aj, f_j_x, f_j_y, f_j_z);
1849 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ak, f_k_x, f_k_y, f_k_z);
1850 transposeScatterDecrU<4>(reinterpret_cast<real*>(f), al, mf_l_x, mf_l_y, mf_l_z);
1852 #endif // GMX_SIMD_HAVE_REAL
1854 /*! \brief Computes and returns the proper dihedral force
1856 * With the appropriate kernel flavor, also computes and accumulates
1857 * the energy and dV/dlambda.
1859 template<BondedKernelFlavor flavor>
1860 real dopdihs(real cpA, real cpB, real phiA, real phiB, int mult, real phi, real lambda, real* V, real* dvdlambda)
1862 const real L1 = 1.0 - lambda;
1863 const real ph0 = (L1 * phiA + lambda * phiB) * DEG2RAD;
1864 const real dph0 = (phiB - phiA) * DEG2RAD;
1865 const real cp = L1 * cpA + lambda * cpB;
1867 const real mdphi = mult * phi - ph0;
1868 const real sdphi = std::sin(mdphi);
1869 const real ddphi = -cp * mult * sdphi;
1870 if (computeEnergy(flavor))
1872 const real v1 = 1 + std::cos(mdphi);
1875 *dvdlambda += (cpB - cpA) * v1 + cp * dph0 * sdphi;
1879 /* That was 40 flops */
1882 /*! \brief Similar to \p dopdihs(), except for a minus sign and a different treatment of mult/phi0 */
1883 real dopdihs_min(real cpA, real cpB, real phiA, real phiB, int mult, real phi, real lambda, real* V, real* F)
1885 real v, dvdlambda, mdphi, v1, sdphi, ddphi;
1886 real L1 = 1.0 - lambda;
1887 real ph0 = (L1 * phiA + lambda * phiB) * DEG2RAD;
1888 real dph0 = (phiB - phiA) * DEG2RAD;
1889 real cp = L1 * cpA + lambda * cpB;
1891 mdphi = mult * (phi - ph0);
1892 sdphi = std::sin(mdphi);
1893 ddphi = cp * mult * sdphi;
1894 v1 = 1.0 - std::cos(mdphi);
1897 dvdlambda = (cpB - cpA) * v1 + cp * dph0 * sdphi;
1904 /* That was 40 flops */
1907 template<BondedKernelFlavor flavor>
1908 std::enable_if_t<flavor != BondedKernelFlavor::ForcesSimdWhenAvailable || !GMX_SIMD_HAVE_REAL, real>
1910 const t_iatom forceatoms[],
1911 const t_iparams forceparams[],
1918 const t_mdatoms gmx_unused* md,
1919 t_fcdata gmx_unused* fcd,
1920 int gmx_unused* global_atom_index)
1923 rvec r_ij, r_kj, r_kl, m, n;
1927 for (int i = 0; i < nbonds;)
1929 const int ai = forceatoms[i + 1];
1930 const int aj = forceatoms[i + 2];
1931 const int ak = forceatoms[i + 3];
1932 const int al = forceatoms[i + 4];
1934 const real phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n, &t1,
1937 /* Loop over dihedrals working on the same atoms,
1938 * so we avoid recalculating angles and distributing forces.
1943 const int type = forceatoms[i];
1944 ddphi_tot += dopdihs<flavor>(forceparams[type].pdihs.cpA, forceparams[type].pdihs.cpB,
1945 forceparams[type].pdihs.phiA, forceparams[type].pdihs.phiB,
1946 forceparams[type].pdihs.mult, phi, lambda, &vtot, dvdlambda);
1949 } while (i < nbonds && forceatoms[i + 1] == ai && forceatoms[i + 2] == aj
1950 && forceatoms[i + 3] == ak && forceatoms[i + 4] == al);
1952 do_dih_fup<flavor>(ai, aj, ak, al, ddphi_tot, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1,
1959 #if GMX_SIMD_HAVE_REAL
1961 /* As pdihs above, but using SIMD to calculate multiple dihedrals at once */
1962 template<BondedKernelFlavor flavor>
1963 std::enable_if_t<flavor == BondedKernelFlavor::ForcesSimdWhenAvailable, real>
1965 const t_iatom forceatoms[],
1966 const t_iparams forceparams[],
1969 rvec gmx_unused fshift[],
1971 real gmx_unused lambda,
1972 real gmx_unused* dvdlambda,
1973 const t_mdatoms gmx_unused* md,
1974 t_fcdata gmx_unused* fcd,
1975 int gmx_unused* global_atom_index)
1980 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[GMX_SIMD_REAL_WIDTH];
1981 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[GMX_SIMD_REAL_WIDTH];
1982 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ak[GMX_SIMD_REAL_WIDTH];
1983 alignas(GMX_SIMD_ALIGNMENT) std::int32_t al[GMX_SIMD_REAL_WIDTH];
1984 alignas(GMX_SIMD_ALIGNMENT) real buf[3 * GMX_SIMD_REAL_WIDTH];
1985 real * cp, *phi0, *mult;
1986 SimdReal deg2rad_S(DEG2RAD);
1988 SimdReal phi0_S, phi_S;
1989 SimdReal mx_S, my_S, mz_S;
1990 SimdReal nx_S, ny_S, nz_S;
1991 SimdReal nrkj_m2_S, nrkj_n2_S;
1992 SimdReal cp_S, mdphi_S, mult_S;
1993 SimdReal sin_S, cos_S;
1995 SimdReal sf_i_S, msf_l_S;
1996 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9 * GMX_SIMD_REAL_WIDTH];
1998 /* Extract aligned pointer for parameters and variables */
1999 cp = buf + 0 * GMX_SIMD_REAL_WIDTH;
2000 phi0 = buf + 1 * GMX_SIMD_REAL_WIDTH;
2001 mult = buf + 2 * GMX_SIMD_REAL_WIDTH;
2003 set_pbc_simd(pbc, pbc_simd);
2005 /* nbonds is the number of dihedrals times nfa1, here we step GMX_SIMD_REAL_WIDTH dihs */
2006 for (i = 0; (i < nbonds); i += GMX_SIMD_REAL_WIDTH * nfa1)
2008 /* Collect atoms quadruplets for GMX_SIMD_REAL_WIDTH dihedrals.
2009 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
2012 for (s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
2014 type = forceatoms[iu];
2015 ai[s] = forceatoms[iu + 1];
2016 aj[s] = forceatoms[iu + 2];
2017 ak[s] = forceatoms[iu + 3];
2018 al[s] = forceatoms[iu + 4];
2020 /* At the end fill the arrays with the last atoms and 0 params */
2021 if (i + s * nfa1 < nbonds)
2023 cp[s] = forceparams[type].pdihs.cpA;
2024 phi0[s] = forceparams[type].pdihs.phiA;
2025 mult[s] = forceparams[type].pdihs.mult;
2027 if (iu + nfa1 < nbonds)
2040 /* Caclulate GMX_SIMD_REAL_WIDTH dihedral angles at once */
2041 dih_angle_simd(x, ai, aj, ak, al, pbc_simd, &phi_S, &mx_S, &my_S, &mz_S, &nx_S, &ny_S,
2042 &nz_S, &nrkj_m2_S, &nrkj_n2_S, &p_S, &q_S);
2044 cp_S = load<SimdReal>(cp);
2045 phi0_S = load<SimdReal>(phi0) * deg2rad_S;
2046 mult_S = load<SimdReal>(mult);
2048 mdphi_S = fms(mult_S, phi_S, phi0_S);
2050 /* Calculate GMX_SIMD_REAL_WIDTH sines at once */
2051 sincos(mdphi_S, &sin_S, &cos_S);
2052 mddphi_S = cp_S * mult_S * sin_S;
2053 sf_i_S = mddphi_S * nrkj_m2_S;
2054 msf_l_S = mddphi_S * nrkj_n2_S;
2056 /* After this m?_S will contain f[i] */
2057 mx_S = sf_i_S * mx_S;
2058 my_S = sf_i_S * my_S;
2059 mz_S = sf_i_S * mz_S;
2061 /* After this m?_S will contain -f[l] */
2062 nx_S = msf_l_S * nx_S;
2063 ny_S = msf_l_S * ny_S;
2064 nz_S = msf_l_S * nz_S;
2066 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);
2072 /* This is mostly a copy of the SIMD flavor of pdihs above, but with using
2073 * the RB potential instead of a harmonic potential.
2074 * This function can replace rbdihs() when no energy and virial are needed.
2076 template<BondedKernelFlavor flavor>
2077 std::enable_if_t<flavor == BondedKernelFlavor::ForcesSimdWhenAvailable, real>
2079 const t_iatom forceatoms[],
2080 const t_iparams forceparams[],
2083 rvec gmx_unused fshift[],
2085 real gmx_unused lambda,
2086 real gmx_unused* dvdlambda,
2087 const t_mdatoms gmx_unused* md,
2088 t_fcdata gmx_unused* fcd,
2089 int gmx_unused* global_atom_index)
2094 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[GMX_SIMD_REAL_WIDTH];
2095 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[GMX_SIMD_REAL_WIDTH];
2096 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ak[GMX_SIMD_REAL_WIDTH];
2097 alignas(GMX_SIMD_ALIGNMENT) std::int32_t al[GMX_SIMD_REAL_WIDTH];
2098 alignas(GMX_SIMD_ALIGNMENT) real parm[NR_RBDIHS * GMX_SIMD_REAL_WIDTH];
2102 SimdReal ddphi_S, cosfac_S;
2103 SimdReal mx_S, my_S, mz_S;
2104 SimdReal nx_S, ny_S, nz_S;
2105 SimdReal nrkj_m2_S, nrkj_n2_S;
2106 SimdReal parm_S, c_S;
2107 SimdReal sin_S, cos_S;
2108 SimdReal sf_i_S, msf_l_S;
2109 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9 * GMX_SIMD_REAL_WIDTH];
2111 SimdReal pi_S(M_PI);
2112 SimdReal one_S(1.0);
2114 set_pbc_simd(pbc, pbc_simd);
2116 /* nbonds is the number of dihedrals times nfa1, here we step GMX_SIMD_REAL_WIDTH dihs */
2117 for (i = 0; (i < nbonds); i += GMX_SIMD_REAL_WIDTH * nfa1)
2119 /* Collect atoms quadruplets for GMX_SIMD_REAL_WIDTH dihedrals.
2120 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
2123 for (s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
2125 type = forceatoms[iu];
2126 ai[s] = forceatoms[iu + 1];
2127 aj[s] = forceatoms[iu + 2];
2128 ak[s] = forceatoms[iu + 3];
2129 al[s] = forceatoms[iu + 4];
2131 /* At the end fill the arrays with the last atoms and 0 params */
2132 if (i + s * nfa1 < nbonds)
2134 /* We don't need the first parameter, since that's a constant
2135 * which only affects the energies, not the forces.
2137 for (j = 1; j < NR_RBDIHS; j++)
2139 parm[j * GMX_SIMD_REAL_WIDTH + s] = forceparams[type].rbdihs.rbcA[j];
2142 if (iu + nfa1 < nbonds)
2149 for (j = 1; j < NR_RBDIHS; j++)
2151 parm[j * GMX_SIMD_REAL_WIDTH + s] = 0;
2156 /* Caclulate GMX_SIMD_REAL_WIDTH dihedral angles at once */
2157 dih_angle_simd(x, ai, aj, ak, al, pbc_simd, &phi_S, &mx_S, &my_S, &mz_S, &nx_S, &ny_S,
2158 &nz_S, &nrkj_m2_S, &nrkj_n2_S, &p_S, &q_S);
2160 /* Change to polymer convention */
2161 phi_S = phi_S - pi_S;
2163 sincos(phi_S, &sin_S, &cos_S);
2165 ddphi_S = setZero();
2168 for (j = 1; j < NR_RBDIHS; j++)
2170 parm_S = load<SimdReal>(parm + j * GMX_SIMD_REAL_WIDTH);
2171 ddphi_S = fma(c_S * parm_S, cosfac_S, ddphi_S);
2172 cosfac_S = cosfac_S * cos_S;
2176 /* Note that here we do not use the minus sign which is present
2177 * in the normal RB code. This is corrected for through (m)sf below.
2179 ddphi_S = ddphi_S * sin_S;
2181 sf_i_S = ddphi_S * nrkj_m2_S;
2182 msf_l_S = ddphi_S * nrkj_n2_S;
2184 /* After this m?_S will contain f[i] */
2185 mx_S = sf_i_S * mx_S;
2186 my_S = sf_i_S * my_S;
2187 mz_S = sf_i_S * mz_S;
2189 /* After this m?_S will contain -f[l] */
2190 nx_S = msf_l_S * nx_S;
2191 ny_S = msf_l_S * ny_S;
2192 nz_S = msf_l_S * nz_S;
2194 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);
2200 #endif // GMX_SIMD_HAVE_REAL
2203 template<BondedKernelFlavor flavor>
2204 real idihs(int nbonds,
2205 const t_iatom forceatoms[],
2206 const t_iparams forceparams[],
2213 const t_mdatoms gmx_unused* md,
2214 t_fcdata gmx_unused* fcd,
2215 int gmx_unused* global_atom_index)
2217 int i, type, ai, aj, ak, al;
2219 real phi, phi0, dphi0, ddphi, vtot;
2220 rvec r_ij, r_kj, r_kl, m, n;
2221 real L1, kk, dp, dp2, kA, kB, pA, pB, dvdl_term;
2226 for (i = 0; (i < nbonds);)
2228 type = forceatoms[i++];
2229 ai = forceatoms[i++];
2230 aj = forceatoms[i++];
2231 ak = forceatoms[i++];
2232 al = forceatoms[i++];
2234 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3); /* 84 */
2236 /* phi can jump if phi0 is close to Pi/-Pi, which will cause huge
2237 * force changes if we just apply a normal harmonic.
2238 * Instead, we first calculate phi-phi0 and take it modulo (-Pi,Pi).
2239 * This means we will never have the periodicity problem, unless
2240 * the dihedral is Pi away from phiO, which is very unlikely due to
2243 kA = forceparams[type].harmonic.krA;
2244 kB = forceparams[type].harmonic.krB;
2245 pA = forceparams[type].harmonic.rA;
2246 pB = forceparams[type].harmonic.rB;
2248 kk = L1 * kA + lambda * kB;
2249 phi0 = (L1 * pA + lambda * pB) * DEG2RAD;
2250 dphi0 = (pB - pA) * DEG2RAD;
2254 make_dp_periodic(&dp);
2258 vtot += 0.5 * kk * dp2;
2261 dvdl_term += 0.5 * (kB - kA) * dp2 - kk * dphi0 * dp;
2263 do_dih_fup<flavor>(ai, aj, ak, al, -ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1,
2268 *dvdlambda += dvdl_term;
2272 /*! \brief Computes angle restraints of two different types */
2273 template<BondedKernelFlavor flavor>
2274 real low_angres(int nbonds,
2275 const t_iatom forceatoms[],
2276 const t_iparams forceparams[],
2285 int i, m, type, ai, aj, ak, al;
2287 real phi, cos_phi, cos_phi2, vid, vtot, dVdphi;
2288 rvec r_ij, r_kl, f_i, f_k = { 0, 0, 0 };
2289 real st, sth, nrij2, nrkl2, c, cij, ckl;
2291 t2 = 0; /* avoid warning with gcc-3.3. It is never used uninitialized */
2294 ak = al = 0; /* to avoid warnings */
2295 for (i = 0; i < nbonds;)
2297 type = forceatoms[i++];
2298 ai = forceatoms[i++];
2299 aj = forceatoms[i++];
2300 t1 = pbc_rvec_sub(pbc, x[aj], x[ai], r_ij); /* 3 */
2303 ak = forceatoms[i++];
2304 al = forceatoms[i++];
2305 t2 = pbc_rvec_sub(pbc, x[al], x[ak], r_kl); /* 3 */
2314 cos_phi = cos_angle(r_ij, r_kl); /* 25 */
2315 phi = std::acos(cos_phi); /* 10 */
2317 *dvdlambda += dopdihs_min(forceparams[type].pdihs.cpA, forceparams[type].pdihs.cpB,
2318 forceparams[type].pdihs.phiA, forceparams[type].pdihs.phiB,
2319 forceparams[type].pdihs.mult, phi, lambda, &vid, &dVdphi); /* 40 */
2323 cos_phi2 = gmx::square(cos_phi); /* 1 */
2326 st = -dVdphi * gmx::invsqrt(1 - cos_phi2); /* 12 */
2327 sth = st * cos_phi; /* 1 */
2328 nrij2 = iprod(r_ij, r_ij); /* 5 */
2329 nrkl2 = iprod(r_kl, r_kl); /* 5 */
2331 c = st * gmx::invsqrt(nrij2 * nrkl2); /* 11 */
2332 cij = sth / nrij2; /* 10 */
2333 ckl = sth / nrkl2; /* 10 */
2335 for (m = 0; m < DIM; m++) /* 18+18 */
2337 f_i[m] = (c * r_kl[m] - cij * r_ij[m]);
2342 f_k[m] = (c * r_ij[m] - ckl * r_kl[m]);
2348 if (computeVirial(flavor))
2350 rvec_inc(fshift[t1], f_i);
2351 rvec_dec(fshift[CENTRAL], f_i);
2354 rvec_inc(fshift[t2], f_k);
2355 rvec_dec(fshift[CENTRAL], f_k);
2361 return vtot; /* 184 / 157 (bZAxis) total */
2364 template<BondedKernelFlavor flavor>
2365 real angres(int nbonds,
2366 const t_iatom forceatoms[],
2367 const t_iparams forceparams[],
2374 const t_mdatoms gmx_unused* md,
2375 t_fcdata gmx_unused* fcd,
2376 int gmx_unused* global_atom_index)
2378 return low_angres<flavor>(nbonds, forceatoms, forceparams, x, f, fshift, pbc, lambda, dvdlambda, FALSE);
2381 template<BondedKernelFlavor flavor>
2382 real angresz(int nbonds,
2383 const t_iatom forceatoms[],
2384 const t_iparams forceparams[],
2391 const t_mdatoms gmx_unused* md,
2392 t_fcdata gmx_unused* fcd,
2393 int gmx_unused* global_atom_index)
2395 return low_angres<flavor>(nbonds, forceatoms, forceparams, x, f, fshift, pbc, lambda, dvdlambda, TRUE);
2398 template<BondedKernelFlavor flavor>
2399 real dihres(int nbonds,
2400 const t_iatom forceatoms[],
2401 const t_iparams forceparams[],
2408 const t_mdatoms gmx_unused* md,
2409 t_fcdata gmx_unused* fcd,
2410 int gmx_unused* global_atom_index)
2413 int ai, aj, ak, al, i, type, t1, t2, t3;
2414 real phi0A, phi0B, dphiA, dphiB, kfacA, kfacB, phi0, dphi, kfac;
2415 real phi, ddphi, ddp, ddp2, dp, d2r, L1;
2416 rvec r_ij, r_kj, r_kl, m, n;
2422 for (i = 0; (i < nbonds);)
2424 type = forceatoms[i++];
2425 ai = forceatoms[i++];
2426 aj = forceatoms[i++];
2427 ak = forceatoms[i++];
2428 al = forceatoms[i++];
2430 phi0A = forceparams[type].dihres.phiA * d2r;
2431 dphiA = forceparams[type].dihres.dphiA * d2r;
2432 kfacA = forceparams[type].dihres.kfacA;
2434 phi0B = forceparams[type].dihres.phiB * d2r;
2435 dphiB = forceparams[type].dihres.dphiB * d2r;
2436 kfacB = forceparams[type].dihres.kfacB;
2438 phi0 = L1 * phi0A + lambda * phi0B;
2439 dphi = L1 * dphiA + lambda * dphiB;
2440 kfac = L1 * kfacA + lambda * kfacB;
2442 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3);
2445 /* phi can jump if phi0 is close to Pi/-Pi, which will cause huge
2446 * force changes if we just apply a normal harmonic.
2447 * Instead, we first calculate phi-phi0 and take it modulo (-Pi,Pi).
2448 * This means we will never have the periodicity problem, unless
2449 * the dihedral is Pi away from phiO, which is very unlikely due to
2453 make_dp_periodic(&dp);
2459 else if (dp < -dphi)
2471 vtot += 0.5 * kfac * ddp2;
2474 *dvdlambda += 0.5 * (kfacB - kfacA) * ddp2;
2475 /* lambda dependence from changing restraint distances */
2478 *dvdlambda -= kfac * ddp * ((dphiB - dphiA) + (phi0B - phi0A));
2482 *dvdlambda += kfac * ddp * ((dphiB - dphiA) - (phi0B - phi0A));
2484 do_dih_fup<flavor>(ai, aj, ak, al, ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1,
2492 real unimplemented(int gmx_unused nbonds,
2493 const t_iatom gmx_unused forceatoms[],
2494 const t_iparams gmx_unused forceparams[],
2495 const rvec gmx_unused x[],
2496 rvec4 gmx_unused f[],
2497 rvec gmx_unused fshift[],
2498 const t_pbc gmx_unused* pbc,
2499 real gmx_unused lambda,
2500 real gmx_unused* dvdlambda,
2501 const t_mdatoms gmx_unused* md,
2502 t_fcdata gmx_unused* fcd,
2503 int gmx_unused* global_atom_index)
2505 gmx_impl("*** you are using a not implemented function");
2508 template<BondedKernelFlavor flavor>
2509 real restrangles(int nbonds,
2510 const t_iatom forceatoms[],
2511 const t_iparams forceparams[],
2516 real gmx_unused lambda,
2517 real gmx_unused* dvdlambda,
2518 const t_mdatoms gmx_unused* md,
2519 t_fcdata gmx_unused* fcd,
2520 int gmx_unused* global_atom_index)
2522 int i, d, ai, aj, ak, type, m;
2526 double prefactor, ratio_ante, ratio_post;
2527 rvec delta_ante, delta_post, vec_temp;
2530 for (i = 0; (i < nbonds);)
2532 type = forceatoms[i++];
2533 ai = forceatoms[i++];
2534 aj = forceatoms[i++];
2535 ak = forceatoms[i++];
2537 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], vec_temp);
2538 pbc_rvec_sub(pbc, x[aj], x[ai], delta_ante);
2539 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], delta_post);
2542 /* This function computes factors needed for restricted angle potential.
2543 * The restricted angle potential is used in coarse-grained simulations to avoid singularities
2544 * when three particles align and the dihedral angle and dihedral potential
2545 * cannot be calculated. This potential is calculated using the formula:
2546 real restrangles(int nbonds,
2547 const t_iatom forceatoms[],const t_iparams forceparams[],
2548 const rvec x[],rvec4 f[],rvec fshift[],
2550 real gmx_unused lambda,real gmx_unused *dvdlambda,
2551 const t_mdatoms gmx_unused *md,t_fcdata gmx_unused *fcd,
2552 int gmx_unused *global_atom_index)
2554 int i, d, ai, aj, ak, type, m;
2559 real prefactor, ratio_ante, ratio_post;
2560 rvec delta_ante, delta_post, vec_temp;
2563 for(i=0; (i<nbonds); )
2565 type = forceatoms[i++];
2566 ai = forceatoms[i++];
2567 aj = forceatoms[i++];
2568 ak = forceatoms[i++];
2570 * \f[V_{\rm ReB}(\theta_i) = \frac{1}{2} k_{\theta} \frac{(\cos\theta_i - \cos\theta_0)^2}
2571 * {\sin^2\theta_i}\f] ({eq:ReB} and ref \cite{MonicaGoga2013} from the manual).
2572 * For more explanations see comments file "restcbt.h". */
2574 compute_factors_restangles(type, forceparams, delta_ante, delta_post, &prefactor,
2575 &ratio_ante, &ratio_post, &v);
2577 /* Forces are computed per component */
2578 for (d = 0; d < DIM; d++)
2580 f_i[d] = prefactor * (ratio_ante * delta_ante[d] - delta_post[d]);
2582 * ((ratio_post + 1.0) * delta_post[d] - (ratio_ante + 1.0) * delta_ante[d]);
2583 f_k[d] = prefactor * (delta_ante[d] - ratio_post * delta_post[d]);
2586 /* Computation of potential energy */
2592 for (m = 0; (m < DIM); m++)
2599 if (computeVirial(flavor))
2601 rvec_inc(fshift[t1], f_i);
2602 rvec_inc(fshift[CENTRAL], f_j);
2603 rvec_inc(fshift[t2], f_k);
2610 template<BondedKernelFlavor flavor>
2611 real restrdihs(int nbonds,
2612 const t_iatom forceatoms[],
2613 const t_iparams forceparams[],
2618 real gmx_unused lambda,
2619 real gmx_unused* dvlambda,
2620 const t_mdatoms gmx_unused* md,
2621 t_fcdata gmx_unused* fcd,
2622 int gmx_unused* global_atom_index)
2624 int i, d, type, ai, aj, ak, al;
2625 rvec f_i, f_j, f_k, f_l;
2629 rvec delta_ante, delta_crnt, delta_post, vec_temp;
2630 real factor_phi_ai_ante, factor_phi_ai_crnt, factor_phi_ai_post;
2631 real factor_phi_aj_ante, factor_phi_aj_crnt, factor_phi_aj_post;
2632 real factor_phi_ak_ante, factor_phi_ak_crnt, factor_phi_ak_post;
2633 real factor_phi_al_ante, factor_phi_al_crnt, factor_phi_al_post;
2638 for (i = 0; (i < nbonds);)
2640 type = forceatoms[i++];
2641 ai = forceatoms[i++];
2642 aj = forceatoms[i++];
2643 ak = forceatoms[i++];
2644 al = forceatoms[i++];
2646 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], vec_temp);
2647 pbc_rvec_sub(pbc, x[aj], x[ai], delta_ante);
2648 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], delta_crnt);
2649 pbc_rvec_sub(pbc, x[ak], x[al], vec_temp);
2650 pbc_rvec_sub(pbc, x[al], x[ak], delta_post);
2652 /* This function computes factors needed for restricted angle potential.
2653 * The restricted angle potential is used in coarse-grained simulations to avoid singularities
2654 * when three particles align and the dihedral angle and dihedral potential cannot be calculated.
2655 * This potential is calculated using the formula:
2656 * \f[V_{\rm ReB}(\theta_i) = \frac{1}{2} k_{\theta}
2657 * \frac{(\cos\theta_i - \cos\theta_0)^2}{\sin^2\theta_i}\f]
2658 * ({eq:ReB} and ref \cite{MonicaGoga2013} from the manual).
2659 * For more explanations see comments file "restcbt.h" */
2661 compute_factors_restrdihs(
2662 type, forceparams, delta_ante, delta_crnt, delta_post, &factor_phi_ai_ante,
2663 &factor_phi_ai_crnt, &factor_phi_ai_post, &factor_phi_aj_ante, &factor_phi_aj_crnt,
2664 &factor_phi_aj_post, &factor_phi_ak_ante, &factor_phi_ak_crnt, &factor_phi_ak_post,
2665 &factor_phi_al_ante, &factor_phi_al_crnt, &factor_phi_al_post, &prefactor_phi, &v);
2668 /* Computation of forces per component */
2669 for (d = 0; d < DIM; d++)
2671 f_i[d] = prefactor_phi
2672 * (factor_phi_ai_ante * delta_ante[d] + factor_phi_ai_crnt * delta_crnt[d]
2673 + factor_phi_ai_post * delta_post[d]);
2674 f_j[d] = prefactor_phi
2675 * (factor_phi_aj_ante * delta_ante[d] + factor_phi_aj_crnt * delta_crnt[d]
2676 + factor_phi_aj_post * delta_post[d]);
2677 f_k[d] = prefactor_phi
2678 * (factor_phi_ak_ante * delta_ante[d] + factor_phi_ak_crnt * delta_crnt[d]
2679 + factor_phi_ak_post * delta_post[d]);
2680 f_l[d] = prefactor_phi
2681 * (factor_phi_al_ante * delta_ante[d] + factor_phi_al_crnt * delta_crnt[d]
2682 + factor_phi_al_post * delta_post[d]);
2684 /* Computation of the energy */
2689 /* Updating the forces */
2691 rvec_inc(f[ai], f_i);
2692 rvec_inc(f[aj], f_j);
2693 rvec_inc(f[ak], f_k);
2694 rvec_inc(f[al], f_l);
2696 if (computeVirial(flavor))
2700 t3 = pbc_rvec_sub(pbc, x[al], x[aj], dx_jl);
2707 rvec_inc(fshift[t1], f_i);
2708 rvec_inc(fshift[CENTRAL], f_j);
2709 rvec_inc(fshift[t2], f_k);
2710 rvec_inc(fshift[t3], f_l);
2718 template<BondedKernelFlavor flavor>
2719 real cbtdihs(int nbonds,
2720 const t_iatom forceatoms[],
2721 const t_iparams forceparams[],
2726 real gmx_unused lambda,
2727 real gmx_unused* dvdlambda,
2728 const t_mdatoms gmx_unused* md,
2729 t_fcdata gmx_unused* fcd,
2730 int gmx_unused* global_atom_index)
2732 int type, ai, aj, ak, al, i, d;
2736 rvec f_i, f_j, f_k, f_l;
2738 rvec delta_ante, delta_crnt, delta_post;
2739 rvec f_phi_ai, f_phi_aj, f_phi_ak, f_phi_al;
2740 rvec f_theta_ante_ai, f_theta_ante_aj, f_theta_ante_ak;
2741 rvec f_theta_post_aj, f_theta_post_ak, f_theta_post_al;
2745 for (i = 0; (i < nbonds);)
2747 type = forceatoms[i++];
2748 ai = forceatoms[i++];
2749 aj = forceatoms[i++];
2750 ak = forceatoms[i++];
2751 al = forceatoms[i++];
2754 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], vec_temp);
2755 pbc_rvec_sub(pbc, x[aj], x[ai], delta_ante);
2756 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], vec_temp);
2757 pbc_rvec_sub(pbc, x[ak], x[aj], delta_crnt);
2758 pbc_rvec_sub(pbc, x[ak], x[al], vec_temp);
2759 pbc_rvec_sub(pbc, x[al], x[ak], delta_post);
2761 /* \brief Compute factors for CBT potential
2762 * The combined bending-torsion potential goes to zero in a very smooth manner, eliminating the numerical
2763 * instabilities, when three coarse-grained particles align and the dihedral angle and standard
2764 * dihedral potentials cannot be calculated. The CBT potential is calculated using the formula:
2765 * \f[V_{\rm CBT}(\theta_{i-1}, \theta_i, \phi_i) = k_{\phi} \sin^3\theta_{i-1} \sin^3\theta_{i}
2766 * \sum_{n=0}^4 { a_n \cos^n\phi_i}\f] ({eq:CBT} and ref \cite{MonicaGoga2013} from the manual).
2767 * It contains in its expression not only the dihedral angle \f$\phi\f$
2768 * but also \f[\theta_{i-1}\f] (theta_ante bellow) and \f[\theta_{i}\f] (theta_post bellow)
2769 * --- the adjacent bending angles.
2770 * For more explanations see comments file "restcbt.h". */
2772 compute_factors_cbtdihs(type, forceparams, delta_ante, delta_crnt, delta_post, f_phi_ai,
2773 f_phi_aj, f_phi_ak, f_phi_al, f_theta_ante_ai, f_theta_ante_aj,
2774 f_theta_ante_ak, f_theta_post_aj, f_theta_post_ak, f_theta_post_al, &v);
2777 /* Acumulate the resuts per beads */
2778 for (d = 0; d < DIM; d++)
2780 f_i[d] = f_phi_ai[d] + f_theta_ante_ai[d];
2781 f_j[d] = f_phi_aj[d] + f_theta_ante_aj[d] + f_theta_post_aj[d];
2782 f_k[d] = f_phi_ak[d] + f_theta_ante_ak[d] + f_theta_post_ak[d];
2783 f_l[d] = f_phi_al[d] + f_theta_post_al[d];
2786 /* Compute the potential energy */
2791 /* Updating the forces */
2792 rvec_inc(f[ai], f_i);
2793 rvec_inc(f[aj], f_j);
2794 rvec_inc(f[ak], f_k);
2795 rvec_inc(f[al], f_l);
2798 if (computeVirial(flavor))
2802 t3 = pbc_rvec_sub(pbc, x[al], x[aj], dx_jl);
2809 rvec_inc(fshift[t1], f_i);
2810 rvec_inc(fshift[CENTRAL], f_j);
2811 rvec_inc(fshift[t2], f_k);
2812 rvec_inc(fshift[t3], f_l);
2819 template<BondedKernelFlavor flavor>
2820 std::enable_if_t<flavor != BondedKernelFlavor::ForcesSimdWhenAvailable || !GMX_SIMD_HAVE_REAL, real>
2822 const t_iatom forceatoms[],
2823 const t_iparams forceparams[],
2830 const t_mdatoms gmx_unused* md,
2831 t_fcdata gmx_unused* fcd,
2832 int gmx_unused* global_atom_index)
2834 const real c0 = 0.0, c1 = 1.0, c2 = 2.0, c3 = 3.0, c4 = 4.0, c5 = 5.0;
2835 int type, ai, aj, ak, al, i, j;
2837 rvec r_ij, r_kj, r_kl, m, n;
2838 real parmA[NR_RBDIHS];
2839 real parmB[NR_RBDIHS];
2840 real parm[NR_RBDIHS];
2841 real cos_phi, phi, rbp, rbpBA;
2842 real v, ddphi, sin_phi;
2844 real L1 = 1.0 - lambda;
2848 for (i = 0; (i < nbonds);)
2850 type = forceatoms[i++];
2851 ai = forceatoms[i++];
2852 aj = forceatoms[i++];
2853 ak = forceatoms[i++];
2854 al = forceatoms[i++];
2856 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3); /* 84 */
2858 /* Change to polymer convention */
2865 phi -= M_PI; /* 1 */
2867 cos_phi = std::cos(phi);
2868 /* Beware of accuracy loss, cannot use 1-sqrt(cos^2) ! */
2869 sin_phi = std::sin(phi);
2871 for (j = 0; (j < NR_RBDIHS); j++)
2873 parmA[j] = forceparams[type].rbdihs.rbcA[j];
2874 parmB[j] = forceparams[type].rbdihs.rbcB[j];
2875 parm[j] = L1 * parmA[j] + lambda * parmB[j];
2877 /* Calculate cosine powers */
2878 /* Calculate the energy */
2879 /* Calculate the derivative */
2882 dvdl_term += (parmB[0] - parmA[0]);
2887 rbpBA = parmB[1] - parmA[1];
2888 ddphi += rbp * cosfac;
2891 dvdl_term += cosfac * rbpBA;
2893 rbpBA = parmB[2] - parmA[2];
2894 ddphi += c2 * rbp * cosfac;
2897 dvdl_term += cosfac * rbpBA;
2899 rbpBA = parmB[3] - parmA[3];
2900 ddphi += c3 * rbp * cosfac;
2903 dvdl_term += cosfac * rbpBA;
2905 rbpBA = parmB[4] - parmA[4];
2906 ddphi += c4 * rbp * cosfac;
2909 dvdl_term += cosfac * rbpBA;
2911 rbpBA = parmB[5] - parmA[5];
2912 ddphi += c5 * rbp * cosfac;
2915 dvdl_term += cosfac * rbpBA;
2917 ddphi = -ddphi * sin_phi; /* 11 */
2919 do_dih_fup<flavor>(ai, aj, ak, al, ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1, t2,
2923 *dvdlambda += dvdl_term;
2930 /*! \brief Mysterious undocumented function */
2931 int cmap_setup_grid_index(int ip, int grid_spacing, int* ipm1, int* ipp1, int* ipp2)
2937 ip = ip + grid_spacing - 1;
2939 else if (ip > grid_spacing)
2941 ip = ip - grid_spacing - 1;
2950 im1 = grid_spacing - 1;
2952 else if (ip == grid_spacing - 2)
2956 else if (ip == grid_spacing - 1)
2971 real cmap_dihs(int nbonds,
2972 const t_iatom forceatoms[],
2973 const t_iparams forceparams[],
2974 const gmx_cmap_t* cmap_grid,
2978 const struct t_pbc* pbc,
2979 real gmx_unused lambda,
2980 real gmx_unused* dvdlambda,
2981 const t_mdatoms gmx_unused* md,
2982 t_fcdata gmx_unused* fcd,
2983 int gmx_unused* global_atom_index)
2986 int ai, aj, ak, al, am;
2987 int a1i, a1j, a1k, a1l, a2i, a2j, a2k, a2l;
2989 int t11, t21, t31, t12, t22, t32;
2990 int iphi1, ip1m1, ip1p1, ip1p2;
2991 int iphi2, ip2m1, ip2p1, ip2p2;
2993 int pos1, pos2, pos3, pos4;
2995 real ty[4], ty1[4], ty2[4], ty12[4], tx[16];
2996 real phi1, cos_phi1, sin_phi1, xphi1;
2997 real phi2, cos_phi2, sin_phi2, xphi2;
2998 real dx, tt, tu, e, df1, df2, vtot;
2999 real ra21, rb21, rg21, rg1, rgr1, ra2r1, rb2r1, rabr1;
3000 real ra22, rb22, rg22, rg2, rgr2, ra2r2, rb2r2, rabr2;
3001 real fg1, hg1, fga1, hgb1, gaa1, gbb1;
3002 real fg2, hg2, fga2, hgb2, gaa2, gbb2;
3005 rvec r1_ij, r1_kj, r1_kl, m1, n1;
3006 rvec r2_ij, r2_kj, r2_kl, m2, n2;
3007 rvec f1_i, f1_j, f1_k, f1_l;
3008 rvec f2_i, f2_j, f2_k, f2_l;
3009 rvec a1, b1, a2, b2;
3010 rvec f1, g1, h1, f2, g2, h2;
3011 rvec dtf1, dtg1, dth1, dtf2, dtg2, dth2;
3013 int loop_index[4][4] = { { 0, 4, 8, 12 }, { 1, 5, 9, 13 }, { 2, 6, 10, 14 }, { 3, 7, 11, 15 } };
3015 /* Total CMAP energy */
3018 for (n = 0; n < nbonds;)
3020 /* Five atoms are involved in the two torsions */
3021 type = forceatoms[n++];
3022 ai = forceatoms[n++];
3023 aj = forceatoms[n++];
3024 ak = forceatoms[n++];
3025 al = forceatoms[n++];
3026 am = forceatoms[n++];
3028 /* Which CMAP type is this */
3029 const int cmapA = forceparams[type].cmap.cmapA;
3030 const real* cmapd = cmap_grid->cmapdata[cmapA].cmap.data();
3038 phi1 = dih_angle(x[a1i], x[a1j], x[a1k], x[a1l], pbc, r1_ij, r1_kj, r1_kl, m1, n1, &t11,
3039 &t21, &t31); /* 84 */
3041 cos_phi1 = std::cos(phi1);
3043 a1[0] = r1_ij[1] * r1_kj[2] - r1_ij[2] * r1_kj[1];
3044 a1[1] = r1_ij[2] * r1_kj[0] - r1_ij[0] * r1_kj[2];
3045 a1[2] = r1_ij[0] * r1_kj[1] - r1_ij[1] * r1_kj[0]; /* 9 */
3047 b1[0] = r1_kl[1] * r1_kj[2] - r1_kl[2] * r1_kj[1];
3048 b1[1] = r1_kl[2] * r1_kj[0] - r1_kl[0] * r1_kj[2];
3049 b1[2] = r1_kl[0] * r1_kj[1] - r1_kl[1] * r1_kj[0]; /* 9 */
3051 pbc_rvec_sub(pbc, x[a1l], x[a1k], h1);
3053 ra21 = iprod(a1, a1); /* 5 */
3054 rb21 = iprod(b1, b1); /* 5 */
3055 rg21 = iprod(r1_kj, r1_kj); /* 5 */
3061 rabr1 = sqrt(ra2r1 * rb2r1);
3063 sin_phi1 = rg1 * rabr1 * iprod(a1, h1) * (-1);
3065 if (cos_phi1 < -0.5 || cos_phi1 > 0.5)
3067 phi1 = std::asin(sin_phi1);
3077 phi1 = -M_PI - phi1;
3083 phi1 = std::acos(cos_phi1);
3091 xphi1 = phi1 + M_PI; /* 1 */
3093 /* Second torsion */
3099 phi2 = dih_angle(x[a2i], x[a2j], x[a2k], x[a2l], pbc, r2_ij, r2_kj, r2_kl, m2, n2, &t12,
3100 &t22, &t32); /* 84 */
3102 cos_phi2 = std::cos(phi2);
3104 a2[0] = r2_ij[1] * r2_kj[2] - r2_ij[2] * r2_kj[1];
3105 a2[1] = r2_ij[2] * r2_kj[0] - r2_ij[0] * r2_kj[2];
3106 a2[2] = r2_ij[0] * r2_kj[1] - r2_ij[1] * r2_kj[0]; /* 9 */
3108 b2[0] = r2_kl[1] * r2_kj[2] - r2_kl[2] * r2_kj[1];
3109 b2[1] = r2_kl[2] * r2_kj[0] - r2_kl[0] * r2_kj[2];
3110 b2[2] = r2_kl[0] * r2_kj[1] - r2_kl[1] * r2_kj[0]; /* 9 */
3112 pbc_rvec_sub(pbc, x[a2l], x[a2k], h2);
3114 ra22 = iprod(a2, a2); /* 5 */
3115 rb22 = iprod(b2, b2); /* 5 */
3116 rg22 = iprod(r2_kj, r2_kj); /* 5 */
3122 rabr2 = sqrt(ra2r2 * rb2r2);
3124 sin_phi2 = rg2 * rabr2 * iprod(a2, h2) * (-1);
3126 if (cos_phi2 < -0.5 || cos_phi2 > 0.5)
3128 phi2 = std::asin(sin_phi2);
3138 phi2 = -M_PI - phi2;
3144 phi2 = std::acos(cos_phi2);
3152 xphi2 = phi2 + M_PI; /* 1 */
3154 /* Range mangling */
3157 xphi1 = xphi1 + 2 * M_PI;
3159 else if (xphi1 >= 2 * M_PI)
3161 xphi1 = xphi1 - 2 * M_PI;
3166 xphi2 = xphi2 + 2 * M_PI;
3168 else if (xphi2 >= 2 * M_PI)
3170 xphi2 = xphi2 - 2 * M_PI;
3173 /* Number of grid points */
3174 dx = 2 * M_PI / cmap_grid->grid_spacing;
3176 /* Where on the grid are we */
3177 iphi1 = static_cast<int>(xphi1 / dx);
3178 iphi2 = static_cast<int>(xphi2 / dx);
3180 iphi1 = cmap_setup_grid_index(iphi1, cmap_grid->grid_spacing, &ip1m1, &ip1p1, &ip1p2);
3181 iphi2 = cmap_setup_grid_index(iphi2, cmap_grid->grid_spacing, &ip2m1, &ip2p1, &ip2p2);
3183 pos1 = iphi1 * cmap_grid->grid_spacing + iphi2;
3184 pos2 = ip1p1 * cmap_grid->grid_spacing + iphi2;
3185 pos3 = ip1p1 * cmap_grid->grid_spacing + ip2p1;
3186 pos4 = iphi1 * cmap_grid->grid_spacing + ip2p1;
3188 ty[0] = cmapd[pos1 * 4];
3189 ty[1] = cmapd[pos2 * 4];
3190 ty[2] = cmapd[pos3 * 4];
3191 ty[3] = cmapd[pos4 * 4];
3193 ty1[0] = cmapd[pos1 * 4 + 1];
3194 ty1[1] = cmapd[pos2 * 4 + 1];
3195 ty1[2] = cmapd[pos3 * 4 + 1];
3196 ty1[3] = cmapd[pos4 * 4 + 1];
3198 ty2[0] = cmapd[pos1 * 4 + 2];
3199 ty2[1] = cmapd[pos2 * 4 + 2];
3200 ty2[2] = cmapd[pos3 * 4 + 2];
3201 ty2[3] = cmapd[pos4 * 4 + 2];
3203 ty12[0] = cmapd[pos1 * 4 + 3];
3204 ty12[1] = cmapd[pos2 * 4 + 3];
3205 ty12[2] = cmapd[pos3 * 4 + 3];
3206 ty12[3] = cmapd[pos4 * 4 + 3];
3208 /* Switch to degrees */
3209 dx = 360.0 / cmap_grid->grid_spacing;
3210 xphi1 = xphi1 * RAD2DEG;
3211 xphi2 = xphi2 * RAD2DEG;
3213 for (i = 0; i < 4; i++) /* 16 */
3216 tx[i + 4] = ty1[i] * dx;
3217 tx[i + 8] = ty2[i] * dx;
3218 tx[i + 12] = ty12[i] * dx * dx;
3221 real tc[16] = { 0 };
3222 for (int idx = 0; idx < 16; idx++) /* 1056 */
3224 for (int k = 0; k < 16; k++)
3226 tc[idx] += cmap_coeff_matrix[k * 16 + idx] * tx[k];
3230 tt = (xphi1 - iphi1 * dx) / dx;
3231 tu = (xphi2 - iphi2 * dx) / dx;
3237 for (i = 3; i >= 0; i--)
3239 l1 = loop_index[i][3];
3240 l2 = loop_index[i][2];
3241 l3 = loop_index[i][1];
3243 e = tt * e + ((tc[i * 4 + 3] * tu + tc[i * 4 + 2]) * tu + tc[i * 4 + 1]) * tu + tc[i * 4];
3244 df1 = tu * df1 + (3.0 * tc[l1] * tt + 2.0 * tc[l2]) * tt + tc[l3];
3245 df2 = tt * df2 + (3.0 * tc[i * 4 + 3] * tu + 2.0 * tc[i * 4 + 2]) * tu + tc[i * 4 + 1];
3255 /* Do forces - first torsion */
3256 fg1 = iprod(r1_ij, r1_kj);
3257 hg1 = iprod(r1_kl, r1_kj);
3258 fga1 = fg1 * ra2r1 * rgr1;
3259 hgb1 = hg1 * rb2r1 * rgr1;
3260 gaa1 = -ra2r1 * rg1;
3263 for (i = 0; i < DIM; i++)
3265 dtf1[i] = gaa1 * a1[i];
3266 dtg1[i] = fga1 * a1[i] - hgb1 * b1[i];
3267 dth1[i] = gbb1 * b1[i];
3269 f1[i] = df1 * dtf1[i];
3270 g1[i] = df1 * dtg1[i];
3271 h1[i] = df1 * dth1[i];
3274 f1_j[i] = -f1[i] - g1[i];
3275 f1_k[i] = h1[i] + g1[i];
3278 f[a1i][i] = f[a1i][i] + f1_i[i];
3279 f[a1j][i] = f[a1j][i] + f1_j[i]; /* - f1[i] - g1[i] */
3280 f[a1k][i] = f[a1k][i] + f1_k[i]; /* h1[i] + g1[i] */
3281 f[a1l][i] = f[a1l][i] + f1_l[i]; /* h1[i] */
3284 /* Do forces - second torsion */
3285 fg2 = iprod(r2_ij, r2_kj);
3286 hg2 = iprod(r2_kl, r2_kj);
3287 fga2 = fg2 * ra2r2 * rgr2;
3288 hgb2 = hg2 * rb2r2 * rgr2;
3289 gaa2 = -ra2r2 * rg2;
3292 for (i = 0; i < DIM; i++)
3294 dtf2[i] = gaa2 * a2[i];
3295 dtg2[i] = fga2 * a2[i] - hgb2 * b2[i];
3296 dth2[i] = gbb2 * b2[i];
3298 f2[i] = df2 * dtf2[i];
3299 g2[i] = df2 * dtg2[i];
3300 h2[i] = df2 * dth2[i];
3303 f2_j[i] = -f2[i] - g2[i];
3304 f2_k[i] = h2[i] + g2[i];
3307 f[a2i][i] = f[a2i][i] + f2_i[i]; /* f2[i] */
3308 f[a2j][i] = f[a2j][i] + f2_j[i]; /* - f2[i] - g2[i] */
3309 f[a2k][i] = f[a2k][i] + f2_k[i]; /* h2[i] + g2[i] */
3310 f[a2l][i] = f[a2l][i] + f2_l[i]; /* - h2[i] */
3314 if (fshift != nullptr)
3318 t31 = pbc_rvec_sub(pbc, x[a1l], x[a1j], h1);
3319 t32 = pbc_rvec_sub(pbc, x[a2l], x[a2j], h2);
3327 rvec_inc(fshift[t11], f1_i);
3328 rvec_inc(fshift[CENTRAL], f1_j);
3329 rvec_inc(fshift[t21], f1_k);
3330 rvec_inc(fshift[t31], f1_l);
3332 rvec_inc(fshift[t12], f2_i);
3333 rvec_inc(fshift[CENTRAL], f2_j);
3334 rvec_inc(fshift[t22], f2_k);
3335 rvec_inc(fshift[t32], f2_l);
3345 /***********************************************************
3347 * G R O M O S 9 6 F U N C T I O N S
3349 ***********************************************************/
3350 real g96harmonic(real kA, real kB, real xA, real xB, real x, real lambda, real* V, real* F)
3352 const real half = 0.5;
3353 real L1, kk, x0, dx, dx2;
3354 real v, f, dvdlambda;
3357 kk = L1 * kA + lambda * kB;
3358 x0 = L1 * xA + lambda * xB;
3364 v = half * kk * dx2;
3365 dvdlambda = half * (kB - kA) * dx2 + (xA - xB) * kk * dx;
3372 /* That was 21 flops */
3375 template<BondedKernelFlavor flavor>
3376 real g96bonds(int nbonds,
3377 const t_iatom forceatoms[],
3378 const t_iparams forceparams[],
3385 const t_mdatoms gmx_unused* md,
3386 t_fcdata gmx_unused* fcd,
3387 int gmx_unused* global_atom_index)
3389 int i, ki, ai, aj, type;
3390 real dr2, fbond, vbond, vtot;
3394 for (i = 0; (i < nbonds);)
3396 type = forceatoms[i++];
3397 ai = forceatoms[i++];
3398 aj = forceatoms[i++];
3400 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
3401 dr2 = iprod(dx, dx); /* 5 */
3403 *dvdlambda += g96harmonic(forceparams[type].harmonic.krA, forceparams[type].harmonic.krB,
3404 forceparams[type].harmonic.rA, forceparams[type].harmonic.rB, dr2,
3405 lambda, &vbond, &fbond);
3407 vtot += 0.5 * vbond; /* 1*/
3409 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
3414 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)
3415 /* Return value is the angle between the bonds i-j and j-k */
3419 *t1 = pbc_rvec_sub(pbc, xi, xj, r_ij); /* 3 */
3420 *t2 = pbc_rvec_sub(pbc, xk, xj, r_kj); /* 3 */
3422 costh = cos_angle(r_ij, r_kj); /* 25 */
3427 template<BondedKernelFlavor flavor>
3428 real g96angles(int nbonds,
3429 const t_iatom forceatoms[],
3430 const t_iparams forceparams[],
3437 const t_mdatoms gmx_unused* md,
3438 t_fcdata gmx_unused* fcd,
3439 int gmx_unused* global_atom_index)
3441 int i, ai, aj, ak, type, m, t1, t2;
3443 real cos_theta, dVdt, va, vtot;
3444 real rij_1, rij_2, rkj_1, rkj_2, rijrkj_1;
3448 for (i = 0; (i < nbonds);)
3450 type = forceatoms[i++];
3451 ai = forceatoms[i++];
3452 aj = forceatoms[i++];
3453 ak = forceatoms[i++];
3455 cos_theta = g96bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &t1, &t2);
3457 *dvdlambda += g96harmonic(forceparams[type].harmonic.krA, forceparams[type].harmonic.krB,
3458 forceparams[type].harmonic.rA, forceparams[type].harmonic.rB,
3459 cos_theta, lambda, &va, &dVdt);
3462 rij_1 = gmx::invsqrt(iprod(r_ij, r_ij));
3463 rkj_1 = gmx::invsqrt(iprod(r_kj, r_kj));
3464 rij_2 = rij_1 * rij_1;
3465 rkj_2 = rkj_1 * rkj_1;
3466 rijrkj_1 = rij_1 * rkj_1; /* 23 */
3468 for (m = 0; (m < DIM); m++) /* 42 */
3470 f_i[m] = dVdt * (r_kj[m] * rijrkj_1 - r_ij[m] * rij_2 * cos_theta);
3471 f_k[m] = dVdt * (r_ij[m] * rijrkj_1 - r_kj[m] * rkj_2 * cos_theta);
3472 f_j[m] = -f_i[m] - f_k[m];
3478 if (computeVirial(flavor))
3480 rvec_inc(fshift[t1], f_i);
3481 rvec_inc(fshift[CENTRAL], f_j);
3482 rvec_inc(fshift[t2], f_k); /* 9 */
3489 template<BondedKernelFlavor flavor>
3490 real cross_bond_bond(int nbonds,
3491 const t_iatom forceatoms[],
3492 const t_iparams forceparams[],
3497 real gmx_unused lambda,
3498 real gmx_unused* dvdlambda,
3499 const t_mdatoms gmx_unused* md,
3500 t_fcdata gmx_unused* fcd,
3501 int gmx_unused* global_atom_index)
3503 /* Potential from Lawrence and Skimmer, Chem. Phys. Lett. 372 (2003)
3506 int i, ai, aj, ak, type, m, t1, t2;
3508 real vtot, vrr, s1, s2, r1, r2, r1e, r2e, krr;
3512 for (i = 0; (i < nbonds);)
3514 type = forceatoms[i++];
3515 ai = forceatoms[i++];
3516 aj = forceatoms[i++];
3517 ak = forceatoms[i++];
3518 r1e = forceparams[type].cross_bb.r1e;
3519 r2e = forceparams[type].cross_bb.r2e;
3520 krr = forceparams[type].cross_bb.krr;
3522 /* Compute distance vectors ... */
3523 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], r_ij);
3524 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], r_kj);
3526 /* ... and their lengths */
3530 /* Deviations from ideality */
3534 /* Energy (can be negative!) */
3535 vrr = krr * s1 * s2;
3539 svmul(-krr * s2 / r1, r_ij, f_i);
3540 svmul(-krr * s1 / r2, r_kj, f_k);
3542 for (m = 0; (m < DIM); m++) /* 12 */
3544 f_j[m] = -f_i[m] - f_k[m];
3550 if (computeVirial(flavor))
3552 rvec_inc(fshift[t1], f_i);
3553 rvec_inc(fshift[CENTRAL], f_j);
3554 rvec_inc(fshift[t2], f_k); /* 9 */
3561 template<BondedKernelFlavor flavor>
3562 real cross_bond_angle(int nbonds,
3563 const t_iatom forceatoms[],
3564 const t_iparams forceparams[],
3569 real gmx_unused lambda,
3570 real gmx_unused* dvdlambda,
3571 const t_mdatoms gmx_unused* md,
3572 t_fcdata gmx_unused* fcd,
3573 int gmx_unused* global_atom_index)
3575 /* Potential from Lawrence and Skimmer, Chem. Phys. Lett. 372 (2003)
3578 int i, ai, aj, ak, type, m, t1, t2;
3579 rvec r_ij, r_kj, r_ik;
3580 real vtot, vrt, s1, s2, s3, r1, r2, r3, r1e, r2e, r3e, krt, k1, k2, k3;
3584 for (i = 0; (i < nbonds);)
3586 type = forceatoms[i++];
3587 ai = forceatoms[i++];
3588 aj = forceatoms[i++];
3589 ak = forceatoms[i++];
3590 r1e = forceparams[type].cross_ba.r1e;
3591 r2e = forceparams[type].cross_ba.r2e;
3592 r3e = forceparams[type].cross_ba.r3e;
3593 krt = forceparams[type].cross_ba.krt;
3595 /* Compute distance vectors ... */
3596 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], r_ij);
3597 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], r_kj);
3598 pbc_rvec_sub(pbc, x[ai], x[ak], r_ik);
3600 /* ... and their lengths */
3605 /* Deviations from ideality */
3610 /* Energy (can be negative!) */
3611 vrt = krt * s3 * (s1 + s2);
3615 k1 = -krt * (s3 / r1);
3616 k2 = -krt * (s3 / r2);
3617 k3 = -krt * (s1 + s2) / r3;
3618 for (m = 0; (m < DIM); m++)
3620 f_i[m] = k1 * r_ij[m] + k3 * r_ik[m];
3621 f_k[m] = k2 * r_kj[m] - k3 * r_ik[m];
3622 f_j[m] = -f_i[m] - f_k[m];
3625 for (m = 0; (m < DIM); m++) /* 12 */
3632 if (computeVirial(flavor))
3634 rvec_inc(fshift[t1], f_i);
3635 rvec_inc(fshift[CENTRAL], f_j);
3636 rvec_inc(fshift[t2], f_k); /* 9 */
3643 /*! \brief Computes the potential and force for a tabulated potential */
3644 real bonded_tab(const char* type,
3646 const bondedtable_t* table,
3654 real k, tabscale, rt, eps, eps2, Yt, Ft, Geps, Heps2, Fp, VV, FF;
3658 k = (1.0 - lambda) * kA + lambda * kB;
3660 tabscale = table->scale;
3661 const real* VFtab = table->data.data();
3664 n0 = static_cast<int>(rt);
3668 "A tabulated %s interaction table number %d is out of the table range: r %f, "
3669 "between table indices %d and %d, table length %d",
3670 type, table_nr, r, n0, n0 + 1, table->n);
3676 Ft = VFtab[nnn + 1];
3677 Geps = VFtab[nnn + 2] * eps;
3678 Heps2 = VFtab[nnn + 3] * eps2;
3679 Fp = Ft + Geps + Heps2;
3681 FF = Fp + Geps + 2.0 * Heps2;
3683 *F = -k * FF * tabscale;
3685 dvdlambda = (kB - kA) * VV;
3689 /* That was 22 flops */
3692 template<BondedKernelFlavor flavor>
3693 real tab_bonds(int nbonds,
3694 const t_iatom forceatoms[],
3695 const t_iparams forceparams[],
3702 const t_mdatoms gmx_unused* md,
3704 int gmx_unused* global_atom_index)
3706 int i, ki, ai, aj, type, table;
3707 real dr, dr2, fbond, vbond, vtot;
3711 for (i = 0; (i < nbonds);)
3713 type = forceatoms[i++];
3714 ai = forceatoms[i++];
3715 aj = forceatoms[i++];
3717 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
3718 dr2 = iprod(dx, dx); /* 5 */
3719 dr = dr2 * gmx::invsqrt(dr2); /* 10 */
3721 table = forceparams[type].tab.table;
3723 *dvdlambda += bonded_tab("bond", table, &fcd->bondtab[table], forceparams[type].tab.kA,
3724 forceparams[type].tab.kB, dr, lambda, &vbond, &fbond); /* 22 */
3732 vtot += vbond; /* 1*/
3733 fbond *= gmx::invsqrt(dr2); /* 6 */
3735 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
3740 template<BondedKernelFlavor flavor>
3741 real tab_angles(int nbonds,
3742 const t_iatom forceatoms[],
3743 const t_iparams forceparams[],
3750 const t_mdatoms gmx_unused* md,
3752 int gmx_unused* global_atom_index)
3754 int i, ai, aj, ak, t1, t2, type, table;
3756 real cos_theta, cos_theta2, theta, dVdt, va, vtot;
3759 for (i = 0; (i < nbonds);)
3761 type = forceatoms[i++];
3762 ai = forceatoms[i++];
3763 aj = forceatoms[i++];
3764 ak = forceatoms[i++];
3766 theta = bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
3768 table = forceparams[type].tab.table;
3770 *dvdlambda += bonded_tab("angle", table, &fcd->angletab[table], forceparams[type].tab.kA,
3771 forceparams[type].tab.kB, theta, lambda, &va, &dVdt); /* 22 */
3774 cos_theta2 = gmx::square(cos_theta); /* 1 */
3783 st = dVdt * gmx::invsqrt(1 - cos_theta2); /* 12 */
3784 sth = st * cos_theta; /* 1 */
3785 nrkj2 = iprod(r_kj, r_kj); /* 5 */
3786 nrij2 = iprod(r_ij, r_ij);
3788 cik = st * gmx::invsqrt(nrkj2 * nrij2); /* 12 */
3789 cii = sth / nrij2; /* 10 */
3790 ckk = sth / nrkj2; /* 10 */
3792 for (m = 0; (m < DIM); m++) /* 39 */
3794 f_i[m] = -(cik * r_kj[m] - cii * r_ij[m]);
3795 f_k[m] = -(cik * r_ij[m] - ckk * r_kj[m]);
3796 f_j[m] = -f_i[m] - f_k[m];
3802 if (computeVirial(flavor))
3804 rvec_inc(fshift[t1], f_i);
3805 rvec_inc(fshift[CENTRAL], f_j);
3806 rvec_inc(fshift[t2], f_k);
3813 template<BondedKernelFlavor flavor>
3814 real tab_dihs(int nbonds,
3815 const t_iatom forceatoms[],
3816 const t_iparams forceparams[],
3823 const t_mdatoms gmx_unused* md,
3825 int gmx_unused* global_atom_index)
3827 int i, type, ai, aj, ak, al, table;
3829 rvec r_ij, r_kj, r_kl, m, n;
3830 real phi, ddphi, vpd, vtot;
3833 for (i = 0; (i < nbonds);)
3835 type = forceatoms[i++];
3836 ai = forceatoms[i++];
3837 aj = forceatoms[i++];
3838 ak = forceatoms[i++];
3839 al = forceatoms[i++];
3841 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3); /* 84 */
3843 table = forceparams[type].tab.table;
3845 /* Hopefully phi+M_PI never results in values < 0 */
3846 *dvdlambda += bonded_tab("dihedral", table, &fcd->dihtab[table], forceparams[type].tab.kA,
3847 forceparams[type].tab.kB, phi + M_PI, lambda, &vpd, &ddphi);
3850 do_dih_fup<flavor>(ai, aj, ak, al, -ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1,
3858 struct BondedInteractions
3860 BondedFunction function;
3864 // Bug in old clang versions prevents constexpr. constexpr is needed for MSVC.
3865 #if defined(__clang__) && __clang_major__ < 6
3866 # define CONSTEXPR_EXCL_OLD_CLANG const
3868 # define CONSTEXPR_EXCL_OLD_CLANG constexpr
3871 /*! \brief Lookup table of bonded interaction functions
3873 * This must have as many entries as interaction_function in ifunc.cpp */
3874 template<BondedKernelFlavor flavor>
3875 CONSTEXPR_EXCL_OLD_CLANG std::array<BondedInteractions, F_NRE> c_bondedInteractionFunctions = {
3876 BondedInteractions{ bonds<flavor>, eNR_BONDS }, // F_BONDS
3877 BondedInteractions{ g96bonds<flavor>, eNR_BONDS }, // F_G96BONDS
3878 BondedInteractions{ morse_bonds<flavor>, eNR_MORSE }, // F_MORSE
3879 BondedInteractions{ cubic_bonds<flavor>, eNR_CUBICBONDS }, // F_CUBICBONDS
3880 BondedInteractions{ unimplemented, -1 }, // F_CONNBONDS
3881 BondedInteractions{ bonds<flavor>, eNR_BONDS }, // F_HARMONIC
3882 BondedInteractions{ FENE_bonds<flavor>, eNR_FENEBONDS }, // F_FENEBONDS
3883 BondedInteractions{ tab_bonds<flavor>, eNR_TABBONDS }, // F_TABBONDS
3884 BondedInteractions{ tab_bonds<flavor>, eNR_TABBONDS }, // F_TABBONDSNC
3885 BondedInteractions{ restraint_bonds<flavor>, eNR_RESTRBONDS }, // F_RESTRBONDS
3886 BondedInteractions{ angles<flavor>, eNR_ANGLES }, // F_ANGLES
3887 BondedInteractions{ g96angles<flavor>, eNR_ANGLES }, // F_G96ANGLES
3888 BondedInteractions{ restrangles<flavor>, eNR_ANGLES }, // F_RESTRANGLES
3889 BondedInteractions{ linear_angles<flavor>, eNR_ANGLES }, // F_LINEAR_ANGLES
3890 BondedInteractions{ cross_bond_bond<flavor>, eNR_CROSS_BOND_BOND }, // F_CROSS_BOND_BONDS
3891 BondedInteractions{ cross_bond_angle<flavor>, eNR_CROSS_BOND_ANGLE }, // F_CROSS_BOND_ANGLES
3892 BondedInteractions{ urey_bradley<flavor>, eNR_UREY_BRADLEY }, // F_UREY_BRADLEY
3893 BondedInteractions{ quartic_angles<flavor>, eNR_QANGLES }, // F_QUARTIC_ANGLES
3894 BondedInteractions{ tab_angles<flavor>, eNR_TABANGLES }, // F_TABANGLES
3895 BondedInteractions{ pdihs<flavor>, eNR_PROPER }, // F_PDIHS
3896 BondedInteractions{ rbdihs<flavor>, eNR_RB }, // F_RBDIHS
3897 BondedInteractions{ restrdihs<flavor>, eNR_PROPER }, // F_RESTRDIHS
3898 BondedInteractions{ cbtdihs<flavor>, eNR_RB }, // F_CBTDIHS
3899 BondedInteractions{ rbdihs<flavor>, eNR_FOURDIH }, // F_FOURDIHS
3900 BondedInteractions{ idihs<flavor>, eNR_IMPROPER }, // F_IDIHS
3901 BondedInteractions{ pdihs<flavor>, eNR_IMPROPER }, // F_PIDIHS
3902 BondedInteractions{ tab_dihs<flavor>, eNR_TABDIHS }, // F_TABDIHS
3903 BondedInteractions{ unimplemented, eNR_CMAP }, // F_CMAP
3904 BondedInteractions{ unimplemented, -1 }, // F_GB12_NOLONGERUSED
3905 BondedInteractions{ unimplemented, -1 }, // F_GB13_NOLONGERUSED
3906 BondedInteractions{ unimplemented, -1 }, // F_GB14_NOLONGERUSED
3907 BondedInteractions{ unimplemented, -1 }, // F_GBPOL_NOLONGERUSED
3908 BondedInteractions{ unimplemented, -1 }, // F_NPSOLVATION_NOLONGERUSED
3909 BondedInteractions{ unimplemented, eNR_NB14 }, // F_LJ14
3910 BondedInteractions{ unimplemented, -1 }, // F_COUL14
3911 BondedInteractions{ unimplemented, eNR_NB14 }, // F_LJC14_Q
3912 BondedInteractions{ unimplemented, eNR_NB14 }, // F_LJC_PAIRS_NB
3913 BondedInteractions{ unimplemented, -1 }, // F_LJ
3914 BondedInteractions{ unimplemented, -1 }, // F_BHAM
3915 BondedInteractions{ unimplemented, -1 }, // F_LJ_LR_NOLONGERUSED
3916 BondedInteractions{ unimplemented, -1 }, // F_BHAM_LR_NOLONGERUSED
3917 BondedInteractions{ unimplemented, -1 }, // F_DISPCORR
3918 BondedInteractions{ unimplemented, -1 }, // F_COUL_SR
3919 BondedInteractions{ unimplemented, -1 }, // F_COUL_LR_NOLONGERUSED
3920 BondedInteractions{ unimplemented, -1 }, // F_RF_EXCL
3921 BondedInteractions{ unimplemented, -1 }, // F_COUL_RECIP
3922 BondedInteractions{ unimplemented, -1 }, // F_LJ_RECIP
3923 BondedInteractions{ unimplemented, -1 }, // F_DPD
3924 BondedInteractions{ polarize<flavor>, eNR_POLARIZE }, // F_POLARIZATION
3925 BondedInteractions{ water_pol<flavor>, eNR_WPOL }, // F_WATER_POL
3926 BondedInteractions{ thole_pol<flavor>, eNR_THOLE }, // F_THOLE_POL
3927 BondedInteractions{ anharm_polarize<flavor>, eNR_ANHARM_POL }, // F_ANHARM_POL
3928 BondedInteractions{ unimplemented, -1 }, // F_POSRES
3929 BondedInteractions{ unimplemented, -1 }, // F_FBPOSRES
3930 BondedInteractions{ ta_disres, eNR_DISRES }, // F_DISRES
3931 BondedInteractions{ unimplemented, -1 }, // F_DISRESVIOL
3932 BondedInteractions{ orires, eNR_ORIRES }, // F_ORIRES
3933 BondedInteractions{ unimplemented, -1 }, // F_ORIRESDEV
3934 BondedInteractions{ angres<flavor>, eNR_ANGRES }, // F_ANGRES
3935 BondedInteractions{ angresz<flavor>, eNR_ANGRESZ }, // F_ANGRESZ
3936 BondedInteractions{ dihres<flavor>, eNR_DIHRES }, // F_DIHRES
3937 BondedInteractions{ unimplemented, -1 }, // F_DIHRESVIOL
3938 BondedInteractions{ unimplemented, -1 }, // F_CONSTR
3939 BondedInteractions{ unimplemented, -1 }, // F_CONSTRNC
3940 BondedInteractions{ unimplemented, -1 }, // F_SETTLE
3941 BondedInteractions{ unimplemented, -1 }, // F_VSITE2
3942 BondedInteractions{ unimplemented, -1 }, // F_VSITE3
3943 BondedInteractions{ unimplemented, -1 }, // F_VSITE3FD
3944 BondedInteractions{ unimplemented, -1 }, // F_VSITE3FAD
3945 BondedInteractions{ unimplemented, -1 }, // F_VSITE3OUT
3946 BondedInteractions{ unimplemented, -1 }, // F_VSITE4FD
3947 BondedInteractions{ unimplemented, -1 }, // F_VSITE4FDN
3948 BondedInteractions{ unimplemented, -1 }, // F_VSITEN
3949 BondedInteractions{ unimplemented, -1 }, // F_COM_PULL
3950 BondedInteractions{ unimplemented, -1 }, // F_DENSITYFITTING
3951 BondedInteractions{ unimplemented, -1 }, // F_EQM
3952 BondedInteractions{ unimplemented, -1 }, // F_EPOT
3953 BondedInteractions{ unimplemented, -1 }, // F_EKIN
3954 BondedInteractions{ unimplemented, -1 }, // F_ETOT
3955 BondedInteractions{ unimplemented, -1 }, // F_ECONSERVED
3956 BondedInteractions{ unimplemented, -1 }, // F_TEMP
3957 BondedInteractions{ unimplemented, -1 }, // F_VTEMP_NOLONGERUSED
3958 BondedInteractions{ unimplemented, -1 }, // F_PDISPCORR
3959 BondedInteractions{ unimplemented, -1 }, // F_PRES
3960 BondedInteractions{ unimplemented, -1 }, // F_DVDL_CONSTR
3961 BondedInteractions{ unimplemented, -1 }, // F_DVDL
3962 BondedInteractions{ unimplemented, -1 }, // F_DKDL
3963 BondedInteractions{ unimplemented, -1 }, // F_DVDL_COUL
3964 BondedInteractions{ unimplemented, -1 }, // F_DVDL_VDW
3965 BondedInteractions{ unimplemented, -1 }, // F_DVDL_BONDED
3966 BondedInteractions{ unimplemented, -1 }, // F_DVDL_RESTRAINT
3967 BondedInteractions{ unimplemented, -1 }, // F_DVDL_TEMPERATURE
3970 /*! \brief List of instantiated BondedInteractions list */
3971 CONSTEXPR_EXCL_OLD_CLANG
3972 gmx::EnumerationArray<BondedKernelFlavor, std::array<BondedInteractions, F_NRE>> c_bondedInteractionFunctionsPerFlavor = {
3973 c_bondedInteractionFunctions<BondedKernelFlavor::ForcesSimdWhenAvailable>,
3974 c_bondedInteractionFunctions<BondedKernelFlavor::ForcesNoSimd>,
3975 c_bondedInteractionFunctions<BondedKernelFlavor::ForcesAndVirialAndEnergy>,
3976 c_bondedInteractionFunctions<BondedKernelFlavor::ForcesAndEnergy>
3983 real calculateSimpleBond(const int ftype,
3984 const int numForceatoms,
3985 const t_iatom forceatoms[],
3986 const t_iparams forceparams[],
3990 const struct t_pbc* pbc,
3993 const t_mdatoms* md,
3995 int gmx_unused* global_atom_index,
3996 const BondedKernelFlavor bondedKernelFlavor)
3998 const BondedInteractions& bonded = c_bondedInteractionFunctionsPerFlavor[bondedKernelFlavor][ftype];
4000 real v = bonded.function(numForceatoms, forceatoms, forceparams, x, f, fshift, pbc, lambda,
4001 dvdlambda, md, fcd, global_atom_index);
4006 int nrnbIndex(int ftype)
4008 return c_bondedInteractionFunctions<BondedKernelFlavor::ForcesAndVirialAndEnergy>[ftype].nrnbIndex;