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 */
449 template<BondedKernelFlavor flavor>
450 real bonds(int nbonds,
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 template<BondedKernelFlavor flavor>
497 real restraint_bonds(int nbonds,
498 const t_iatom forceatoms[],
499 const t_iparams forceparams[],
506 const t_mdatoms gmx_unused* md,
507 t_fcdata gmx_unused* fcd,
508 int gmx_unused* global_atom_index)
510 int i, ki, ai, aj, type;
511 real dr, dr2, fbond, vbond, vtot;
513 real low, dlow, up1, dup1, up2, dup2, k, dk;
520 for (i = 0; (i < nbonds);)
522 type = forceatoms[i++];
523 ai = forceatoms[i++];
524 aj = forceatoms[i++];
526 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
527 dr2 = iprod(dx, dx); /* 5 */
528 dr = dr2 * gmx::invsqrt(dr2); /* 10 */
530 low = L1 * forceparams[type].restraint.lowA + lambda * forceparams[type].restraint.lowB;
531 dlow = -forceparams[type].restraint.lowA + forceparams[type].restraint.lowB;
532 up1 = L1 * forceparams[type].restraint.up1A + lambda * forceparams[type].restraint.up1B;
533 dup1 = -forceparams[type].restraint.up1A + forceparams[type].restraint.up1B;
534 up2 = L1 * forceparams[type].restraint.up2A + lambda * forceparams[type].restraint.up2B;
535 dup2 = -forceparams[type].restraint.up2A + forceparams[type].restraint.up2B;
536 k = L1 * forceparams[type].restraint.kA + lambda * forceparams[type].restraint.kB;
537 dk = -forceparams[type].restraint.kA + forceparams[type].restraint.kB;
544 vbond = 0.5 * k * drh2;
546 *dvdlambda += 0.5 * dk * drh2 - k * dlow * drh;
557 vbond = 0.5 * k * drh2;
559 *dvdlambda += 0.5 * dk * drh2 - k * dup1 * drh;
564 vbond = k * (up2 - up1) * (0.5 * (up2 - up1) + drh);
565 fbond = -k * (up2 - up1);
566 *dvdlambda += dk * (up2 - up1) * (0.5 * (up2 - up1) + drh)
567 + k * (dup2 - dup1) * (up2 - up1 + drh) - k * (up2 - up1) * dup2;
575 vtot += vbond; /* 1*/
576 fbond *= gmx::invsqrt(dr2); /* 6 */
578 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
584 template<BondedKernelFlavor flavor>
585 real polarize(int nbonds,
586 const t_iatom forceatoms[],
587 const t_iparams forceparams[],
595 t_fcdata gmx_unused* fcd,
596 int gmx_unused* global_atom_index)
598 int i, ki, ai, aj, type;
599 real dr, dr2, fbond, vbond, vtot, ksh;
603 for (i = 0; (i < nbonds);)
605 type = forceatoms[i++];
606 ai = forceatoms[i++];
607 aj = forceatoms[i++];
608 ksh = gmx::square(md->chargeA[aj]) * ONE_4PI_EPS0 / forceparams[type].polarize.alpha;
610 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
611 dr2 = iprod(dx, dx); /* 5 */
612 dr = std::sqrt(dr2); /* 10 */
614 *dvdlambda += harmonic(ksh, ksh, 0, 0, dr, lambda, &vbond, &fbond); /* 19 */
621 vtot += vbond; /* 1*/
622 fbond *= gmx::invsqrt(dr2); /* 6 */
624 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
629 template<BondedKernelFlavor flavor>
630 real anharm_polarize(int nbonds,
631 const t_iatom forceatoms[],
632 const t_iparams forceparams[],
640 t_fcdata gmx_unused* fcd,
641 int gmx_unused* global_atom_index)
643 int i, ki, ai, aj, type;
644 real dr, dr2, fbond, vbond, vtot, ksh, khyp, drcut, ddr, ddr3;
648 for (i = 0; (i < nbonds);)
650 type = forceatoms[i++];
651 ai = forceatoms[i++];
652 aj = forceatoms[i++];
653 ksh = gmx::square(md->chargeA[aj]) * ONE_4PI_EPS0 / forceparams[type].anharm_polarize.alpha; /* 7*/
654 khyp = forceparams[type].anharm_polarize.khyp;
655 drcut = forceparams[type].anharm_polarize.drcut;
657 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
658 dr2 = iprod(dx, dx); /* 5 */
659 dr = dr2 * gmx::invsqrt(dr2); /* 10 */
661 *dvdlambda += harmonic(ksh, ksh, 0, 0, dr, lambda, &vbond, &fbond); /* 19 */
671 ddr3 = ddr * ddr * ddr;
672 vbond += khyp * ddr * ddr3;
673 fbond -= 4 * khyp * ddr3;
675 fbond *= gmx::invsqrt(dr2); /* 6 */
676 vtot += vbond; /* 1*/
678 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
683 template<BondedKernelFlavor flavor>
684 real water_pol(int nbonds,
685 const t_iatom forceatoms[],
686 const t_iparams forceparams[],
689 rvec gmx_unused fshift[],
690 const t_pbc gmx_unused* pbc,
691 real gmx_unused lambda,
692 real gmx_unused* dvdlambda,
693 const t_mdatoms gmx_unused* md,
694 t_fcdata gmx_unused* fcd,
695 int gmx_unused* global_atom_index)
697 /* This routine implements anisotropic polarizibility for water, through
698 * a shell connected to a dummy with spring constant that differ in the
699 * three spatial dimensions in the molecular frame.
701 int i, m, aO, aH1, aH2, aD, aS, type, type0, ki;
702 rvec dOH1, dOH2, dHH, dOD, dDS, nW, kk, dx, kdx, proj;
703 real vtot, fij, r_HH, r_OD, r_nW, tx, ty, tz, qS;
708 type0 = forceatoms[0];
710 qS = md->chargeA[aS];
711 kk[XX] = gmx::square(qS) * ONE_4PI_EPS0 / forceparams[type0].wpol.al_x;
712 kk[YY] = gmx::square(qS) * ONE_4PI_EPS0 / forceparams[type0].wpol.al_y;
713 kk[ZZ] = gmx::square(qS) * ONE_4PI_EPS0 / forceparams[type0].wpol.al_z;
714 r_HH = 1.0 / forceparams[type0].wpol.rHH;
715 for (i = 0; (i < nbonds); i += 6)
717 type = forceatoms[i];
720 gmx_fatal(FARGS, "Sorry, type = %d, type0 = %d, file = %s, line = %d", type, type0,
723 aO = forceatoms[i + 1];
724 aH1 = forceatoms[i + 2];
725 aH2 = forceatoms[i + 3];
726 aD = forceatoms[i + 4];
727 aS = forceatoms[i + 5];
729 /* Compute vectors describing the water frame */
730 pbc_rvec_sub(pbc, x[aH1], x[aO], dOH1);
731 pbc_rvec_sub(pbc, x[aH2], x[aO], dOH2);
732 pbc_rvec_sub(pbc, x[aH2], x[aH1], dHH);
733 pbc_rvec_sub(pbc, x[aD], x[aO], dOD);
734 ki = pbc_rvec_sub(pbc, x[aS], x[aD], dDS);
735 cprod(dOH1, dOH2, nW);
737 /* Compute inverse length of normal vector
738 * (this one could be precomputed, but I'm too lazy now)
740 r_nW = gmx::invsqrt(iprod(nW, nW));
741 /* This is for precision, but does not make a big difference,
744 r_OD = gmx::invsqrt(iprod(dOD, dOD));
746 /* Normalize the vectors in the water frame */
748 svmul(r_HH, dHH, dHH);
749 svmul(r_OD, dOD, dOD);
751 /* Compute displacement of shell along components of the vector */
752 dx[ZZ] = iprod(dDS, dOD);
753 /* Compute projection on the XY plane: dDS - dx[ZZ]*dOD */
754 for (m = 0; (m < DIM); m++)
756 proj[m] = dDS[m] - dx[ZZ] * dOD[m];
759 /*dx[XX] = iprod(dDS,nW);
760 dx[YY] = iprod(dDS,dHH);*/
761 dx[XX] = iprod(proj, nW);
762 for (m = 0; (m < DIM); m++)
764 proj[m] -= dx[XX] * nW[m];
766 dx[YY] = iprod(proj, dHH);
767 /* Now compute the forces and energy */
768 kdx[XX] = kk[XX] * dx[XX];
769 kdx[YY] = kk[YY] * dx[YY];
770 kdx[ZZ] = kk[ZZ] * dx[ZZ];
771 vtot += iprod(dx, kdx);
773 for (m = 0; (m < DIM); m++)
775 /* This is a tensor operation but written out for speed */
776 tx = nW[m] * kdx[XX];
777 ty = dHH[m] * kdx[YY];
778 tz = dOD[m] * kdx[ZZ];
782 if (computeVirial(flavor))
784 fshift[ki][m] += fij;
785 fshift[CENTRAL][m] -= fij;
793 template<BondedKernelFlavor flavor>
795 do_1_thole(const rvec xi, const rvec xj, rvec fi, rvec fj, const t_pbc* pbc, real qq, rvec fshift[], real afac)
798 real r12sq, r12_1, r12bar, v0, v1, fscal, ebar, fff;
801 t = pbc_rvec_sub(pbc, xi, xj, r12); /* 3 */
803 r12sq = iprod(r12, r12); /* 5 */
804 r12_1 = gmx::invsqrt(r12sq); /* 5 */
805 r12bar = afac / r12_1; /* 5 */
806 v0 = qq * ONE_4PI_EPS0 * r12_1; /* 2 */
807 ebar = std::exp(-r12bar); /* 5 */
808 v1 = (1 - (1 + 0.5 * r12bar) * ebar); /* 4 */
809 fscal = ((v0 * r12_1) * v1 - v0 * 0.5 * afac * ebar * (r12bar + 1)) * r12_1; /* 9 */
811 for (m = 0; (m < DIM); m++)
813 fff = fscal * r12[m];
816 if (computeVirial(flavor))
819 fshift[CENTRAL][m] -= fff;
823 return v0 * v1; /* 1 */
827 template<BondedKernelFlavor flavor>
828 real thole_pol(int nbonds,
829 const t_iatom forceatoms[],
830 const t_iparams forceparams[],
835 real gmx_unused lambda,
836 real gmx_unused* dvdlambda,
838 t_fcdata gmx_unused* fcd,
839 int gmx_unused* global_atom_index)
841 /* Interaction between two pairs of particles with opposite charge */
842 int i, type, a1, da1, a2, da2;
843 real q1, q2, qq, a, al1, al2, afac;
846 for (i = 0; (i < nbonds);)
848 type = forceatoms[i++];
849 a1 = forceatoms[i++];
850 da1 = forceatoms[i++];
851 a2 = forceatoms[i++];
852 da2 = forceatoms[i++];
853 q1 = md->chargeA[da1];
854 q2 = md->chargeA[da2];
855 a = forceparams[type].thole.a;
856 al1 = forceparams[type].thole.alpha1;
857 al2 = forceparams[type].thole.alpha2;
859 afac = a * gmx::invsixthroot(al1 * al2);
860 V += do_1_thole<flavor>(x[a1], x[a2], f[a1], f[a2], pbc, qq, fshift, afac);
861 V += do_1_thole<flavor>(x[da1], x[a2], f[da1], f[a2], pbc, -qq, fshift, afac);
862 V += do_1_thole<flavor>(x[a1], x[da2], f[a1], f[da2], pbc, -qq, fshift, afac);
863 V += do_1_thole<flavor>(x[da1], x[da2], f[da1], f[da2], pbc, qq, fshift, afac);
869 // Avoid gcc 386 -O3 code generation bug in this function (see Issue
870 // #3205 for more information)
871 #if defined(__GNUC__) && defined(__i386__) && defined(__OPTIMIZE__)
872 # pragma GCC push_options
873 # pragma GCC optimize("O1")
874 # define avoid_gcc_i386_o3_code_generation_bug
877 template<BondedKernelFlavor flavor>
878 std::enable_if_t<flavor != BondedKernelFlavor::ForcesSimdWhenAvailable || !GMX_SIMD_HAVE_REAL, real>
880 const t_iatom forceatoms[],
881 const t_iparams forceparams[],
888 const t_mdatoms gmx_unused* md,
889 t_fcdata gmx_unused* fcd,
890 int gmx_unused* global_atom_index)
892 int i, ai, aj, ak, t1, t2, type;
894 real cos_theta, cos_theta2, theta, dVdt, va, vtot;
897 for (i = 0; i < nbonds;)
899 type = forceatoms[i++];
900 ai = forceatoms[i++];
901 aj = forceatoms[i++];
902 ak = forceatoms[i++];
904 theta = bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
906 *dvdlambda += harmonic(forceparams[type].harmonic.krA, forceparams[type].harmonic.krB,
907 forceparams[type].harmonic.rA * DEG2RAD,
908 forceparams[type].harmonic.rB * DEG2RAD, theta, lambda, &va, &dVdt); /* 21 */
911 cos_theta2 = gmx::square(cos_theta);
921 st = dVdt * gmx::invsqrt(1 - cos_theta2); /* 12 */
922 sth = st * cos_theta; /* 1 */
923 nrij2 = iprod(r_ij, r_ij); /* 5 */
924 nrkj2 = iprod(r_kj, r_kj); /* 5 */
926 nrij_1 = gmx::invsqrt(nrij2); /* 10 */
927 nrkj_1 = gmx::invsqrt(nrkj2); /* 10 */
929 cik = st * nrij_1 * nrkj_1; /* 2 */
930 cii = sth * nrij_1 * nrij_1; /* 2 */
931 ckk = sth * nrkj_1 * nrkj_1; /* 2 */
933 for (m = 0; m < DIM; m++)
935 f_i[m] = -(cik * r_kj[m] - cii * r_ij[m]);
936 f_k[m] = -(cik * r_ij[m] - ckk * r_kj[m]);
937 f_j[m] = -f_i[m] - f_k[m];
942 if (computeVirial(flavor))
944 rvec_inc(fshift[t1], f_i);
945 rvec_inc(fshift[CENTRAL], f_j);
946 rvec_inc(fshift[t2], f_k);
954 #ifdef avoid_gcc_i386_o3_code_generation_bug
955 # pragma GCC pop_options
956 # undef avoid_gcc_i386_o3_code_generation_bug
959 #if GMX_SIMD_HAVE_REAL
961 /* As angles, but using SIMD to calculate many angles at once.
962 * This routines does not calculate energies and shift forces.
964 template<BondedKernelFlavor flavor>
965 std::enable_if_t<flavor == BondedKernelFlavor::ForcesSimdWhenAvailable, real>
967 const t_iatom forceatoms[],
968 const t_iparams forceparams[],
971 rvec gmx_unused fshift[],
973 real gmx_unused lambda,
974 real gmx_unused* dvdlambda,
975 const t_mdatoms gmx_unused* md,
976 t_fcdata gmx_unused* fcd,
977 int gmx_unused* global_atom_index)
982 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[GMX_SIMD_REAL_WIDTH];
983 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[GMX_SIMD_REAL_WIDTH];
984 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ak[GMX_SIMD_REAL_WIDTH];
985 alignas(GMX_SIMD_ALIGNMENT) real coeff[2 * GMX_SIMD_REAL_WIDTH];
986 SimdReal deg2rad_S(DEG2RAD);
987 SimdReal xi_S, yi_S, zi_S;
988 SimdReal xj_S, yj_S, zj_S;
989 SimdReal xk_S, yk_S, zk_S;
990 SimdReal k_S, theta0_S;
991 SimdReal rijx_S, rijy_S, rijz_S;
992 SimdReal rkjx_S, rkjy_S, rkjz_S;
994 SimdReal min_one_plus_eps_S(-1.0 + 2.0 * GMX_REAL_EPS); // Smallest number > -1
997 SimdReal nrij2_S, nrij_1_S;
998 SimdReal nrkj2_S, nrkj_1_S;
999 SimdReal cos_S, invsin_S;
1001 SimdReal st_S, sth_S;
1002 SimdReal cik_S, cii_S, ckk_S;
1003 SimdReal f_ix_S, f_iy_S, f_iz_S;
1004 SimdReal f_kx_S, f_ky_S, f_kz_S;
1005 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9 * GMX_SIMD_REAL_WIDTH];
1007 set_pbc_simd(pbc, pbc_simd);
1009 /* nbonds is the number of angles times nfa1, here we step GMX_SIMD_REAL_WIDTH angles */
1010 for (i = 0; (i < nbonds); i += GMX_SIMD_REAL_WIDTH * nfa1)
1012 /* Collect atoms for GMX_SIMD_REAL_WIDTH angles.
1013 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
1016 for (s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
1018 type = forceatoms[iu];
1019 ai[s] = forceatoms[iu + 1];
1020 aj[s] = forceatoms[iu + 2];
1021 ak[s] = forceatoms[iu + 3];
1023 /* At the end fill the arrays with the last atoms and 0 params */
1024 if (i + s * nfa1 < nbonds)
1026 coeff[s] = forceparams[type].harmonic.krA;
1027 coeff[GMX_SIMD_REAL_WIDTH + s] = forceparams[type].harmonic.rA;
1029 if (iu + nfa1 < nbonds)
1037 coeff[GMX_SIMD_REAL_WIDTH + s] = 0;
1041 /* Store the non PBC corrected distances packed and aligned */
1042 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ai, &xi_S, &yi_S, &zi_S);
1043 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), aj, &xj_S, &yj_S, &zj_S);
1044 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ak, &xk_S, &yk_S, &zk_S);
1045 rijx_S = xi_S - xj_S;
1046 rijy_S = yi_S - yj_S;
1047 rijz_S = zi_S - zj_S;
1048 rkjx_S = xk_S - xj_S;
1049 rkjy_S = yk_S - yj_S;
1050 rkjz_S = zk_S - zj_S;
1052 k_S = load<SimdReal>(coeff);
1053 theta0_S = load<SimdReal>(coeff + GMX_SIMD_REAL_WIDTH) * deg2rad_S;
1055 pbc_correct_dx_simd(&rijx_S, &rijy_S, &rijz_S, pbc_simd);
1056 pbc_correct_dx_simd(&rkjx_S, &rkjy_S, &rkjz_S, pbc_simd);
1058 rij_rkj_S = iprod(rijx_S, rijy_S, rijz_S, rkjx_S, rkjy_S, rkjz_S);
1060 nrij2_S = norm2(rijx_S, rijy_S, rijz_S);
1061 nrkj2_S = norm2(rkjx_S, rkjy_S, rkjz_S);
1063 nrij_1_S = invsqrt(nrij2_S);
1064 nrkj_1_S = invsqrt(nrkj2_S);
1066 cos_S = rij_rkj_S * nrij_1_S * nrkj_1_S;
1068 /* To allow for 180 degrees, we take the max of cos and -1 + 1bit,
1069 * so we can safely get the 1/sin from 1/sqrt(1 - cos^2).
1070 * This also ensures that rounding errors would cause the argument
1071 * of simdAcos to be < -1.
1072 * Note that we do not take precautions for cos(0)=1, so the outer
1073 * atoms in an angle should not be on top of each other.
1075 cos_S = max(cos_S, min_one_plus_eps_S);
1077 theta_S = acos(cos_S);
1079 invsin_S = invsqrt(one_S - cos_S * cos_S);
1081 st_S = k_S * (theta0_S - theta_S) * invsin_S;
1082 sth_S = st_S * cos_S;
1084 cik_S = st_S * nrij_1_S * nrkj_1_S;
1085 cii_S = sth_S * nrij_1_S * nrij_1_S;
1086 ckk_S = sth_S * nrkj_1_S * nrkj_1_S;
1088 f_ix_S = cii_S * rijx_S;
1089 f_ix_S = fnma(cik_S, rkjx_S, f_ix_S);
1090 f_iy_S = cii_S * rijy_S;
1091 f_iy_S = fnma(cik_S, rkjy_S, f_iy_S);
1092 f_iz_S = cii_S * rijz_S;
1093 f_iz_S = fnma(cik_S, rkjz_S, f_iz_S);
1094 f_kx_S = ckk_S * rkjx_S;
1095 f_kx_S = fnma(cik_S, rijx_S, f_kx_S);
1096 f_ky_S = ckk_S * rkjy_S;
1097 f_ky_S = fnma(cik_S, rijy_S, f_ky_S);
1098 f_kz_S = ckk_S * rkjz_S;
1099 f_kz_S = fnma(cik_S, rijz_S, f_kz_S);
1101 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ai, f_ix_S, f_iy_S, f_iz_S);
1102 transposeScatterDecrU<4>(reinterpret_cast<real*>(f), aj, f_ix_S + f_kx_S, f_iy_S + f_ky_S,
1104 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ak, f_kx_S, f_ky_S, f_kz_S);
1110 #endif // GMX_SIMD_HAVE_REAL
1112 template<BondedKernelFlavor flavor>
1113 real linear_angles(int nbonds,
1114 const t_iatom forceatoms[],
1115 const t_iparams forceparams[],
1122 const t_mdatoms gmx_unused* md,
1123 t_fcdata gmx_unused* fcd,
1124 int gmx_unused* global_atom_index)
1126 int i, m, ai, aj, ak, t1, t2, type;
1128 real L1, kA, kB, aA, aB, dr, dr2, va, vtot, a, b, klin;
1129 rvec r_ij, r_kj, r_ik, dx;
1133 for (i = 0; (i < nbonds);)
1135 type = forceatoms[i++];
1136 ai = forceatoms[i++];
1137 aj = forceatoms[i++];
1138 ak = forceatoms[i++];
1140 kA = forceparams[type].linangle.klinA;
1141 kB = forceparams[type].linangle.klinB;
1142 klin = L1 * kA + lambda * kB;
1144 aA = forceparams[type].linangle.aA;
1145 aB = forceparams[type].linangle.aB;
1146 a = L1 * aA + lambda * aB;
1149 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], r_ij);
1150 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], r_kj);
1151 rvec_sub(r_ij, r_kj, r_ik);
1154 for (m = 0; (m < DIM); m++)
1156 dr = -a * r_ij[m] - b * r_kj[m];
1159 f_i[m] = a * klin * dr;
1160 f_k[m] = b * klin * dr;
1161 f_j[m] = -(f_i[m] + f_k[m]);
1166 va = 0.5 * klin * dr2;
1167 *dvdlambda += 0.5 * (kB - kA) * dr2 + klin * (aB - aA) * iprod(dx, r_ik);
1171 if (computeVirial(flavor))
1173 rvec_inc(fshift[t1], f_i);
1174 rvec_inc(fshift[CENTRAL], f_j);
1175 rvec_inc(fshift[t2], f_k);
1181 template<BondedKernelFlavor flavor>
1182 std::enable_if_t<flavor != BondedKernelFlavor::ForcesSimdWhenAvailable || !GMX_SIMD_HAVE_REAL, real>
1183 urey_bradley(int nbonds,
1184 const t_iatom forceatoms[],
1185 const t_iparams forceparams[],
1192 const t_mdatoms gmx_unused* md,
1193 t_fcdata gmx_unused* fcd,
1194 int gmx_unused* global_atom_index)
1196 int i, m, ai, aj, ak, t1, t2, type, ki;
1197 rvec r_ij, r_kj, r_ik;
1198 real cos_theta, cos_theta2, theta;
1199 real dVdt, va, vtot, dr, dr2, vbond, fbond, fik;
1200 real kthA, th0A, kUBA, r13A, kthB, th0B, kUBB, r13B;
1203 for (i = 0; (i < nbonds);)
1205 type = forceatoms[i++];
1206 ai = forceatoms[i++];
1207 aj = forceatoms[i++];
1208 ak = forceatoms[i++];
1209 th0A = forceparams[type].u_b.thetaA * DEG2RAD;
1210 kthA = forceparams[type].u_b.kthetaA;
1211 r13A = forceparams[type].u_b.r13A;
1212 kUBA = forceparams[type].u_b.kUBA;
1213 th0B = forceparams[type].u_b.thetaB * DEG2RAD;
1214 kthB = forceparams[type].u_b.kthetaB;
1215 r13B = forceparams[type].u_b.r13B;
1216 kUBB = forceparams[type].u_b.kUBB;
1218 theta = bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
1220 *dvdlambda += harmonic(kthA, kthB, th0A, th0B, theta, lambda, &va, &dVdt); /* 21 */
1223 ki = pbc_rvec_sub(pbc, x[ai], x[ak], r_ik); /* 3 */
1224 dr2 = iprod(r_ik, r_ik); /* 5 */
1225 dr = dr2 * gmx::invsqrt(dr2); /* 10 */
1227 *dvdlambda += harmonic(kUBA, kUBB, r13A, r13B, dr, lambda, &vbond, &fbond); /* 19 */
1229 cos_theta2 = gmx::square(cos_theta); /* 1 */
1237 st = dVdt * gmx::invsqrt(1 - cos_theta2); /* 12 */
1238 sth = st * cos_theta; /* 1 */
1239 nrkj2 = iprod(r_kj, r_kj); /* 5 */
1240 nrij2 = iprod(r_ij, r_ij);
1242 cik = st * gmx::invsqrt(nrkj2 * nrij2); /* 12 */
1243 cii = sth / nrij2; /* 10 */
1244 ckk = sth / nrkj2; /* 10 */
1246 for (m = 0; (m < DIM); m++) /* 39 */
1248 f_i[m] = -(cik * r_kj[m] - cii * r_ij[m]);
1249 f_k[m] = -(cik * r_ij[m] - ckk * r_kj[m]);
1250 f_j[m] = -f_i[m] - f_k[m];
1255 if (computeVirial(flavor))
1257 rvec_inc(fshift[t1], f_i);
1258 rvec_inc(fshift[CENTRAL], f_j);
1259 rvec_inc(fshift[t2], f_k);
1262 /* Time for the bond calculations */
1268 vtot += vbond; /* 1*/
1269 fbond *= gmx::invsqrt(dr2); /* 6 */
1271 for (m = 0; (m < DIM); m++) /* 15 */
1273 fik = fbond * r_ik[m];
1276 if (computeVirial(flavor))
1278 fshift[ki][m] += fik;
1279 fshift[CENTRAL][m] -= fik;
1286 #if GMX_SIMD_HAVE_REAL
1288 /* As urey_bradley, but using SIMD to calculate many potentials at once.
1289 * This routines does not calculate energies and shift forces.
1291 template<BondedKernelFlavor flavor>
1292 std::enable_if_t<flavor == BondedKernelFlavor::ForcesSimdWhenAvailable, real>
1293 urey_bradley(int nbonds,
1294 const t_iatom forceatoms[],
1295 const t_iparams forceparams[],
1298 rvec gmx_unused fshift[],
1300 real gmx_unused lambda,
1301 real gmx_unused* dvdlambda,
1302 const t_mdatoms gmx_unused* md,
1303 t_fcdata gmx_unused* fcd,
1304 int gmx_unused* global_atom_index)
1306 constexpr int nfa1 = 4;
1307 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[GMX_SIMD_REAL_WIDTH];
1308 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[GMX_SIMD_REAL_WIDTH];
1309 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ak[GMX_SIMD_REAL_WIDTH];
1310 alignas(GMX_SIMD_ALIGNMENT) real coeff[4 * GMX_SIMD_REAL_WIDTH];
1311 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9 * GMX_SIMD_REAL_WIDTH];
1313 set_pbc_simd(pbc, pbc_simd);
1315 /* nbonds is the number of angles times nfa1, here we step GMX_SIMD_REAL_WIDTH angles */
1316 for (int i = 0; i < nbonds; i += GMX_SIMD_REAL_WIDTH * nfa1)
1318 /* Collect atoms for GMX_SIMD_REAL_WIDTH angles.
1319 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
1322 for (int s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
1324 const int type = forceatoms[iu];
1325 ai[s] = forceatoms[iu + 1];
1326 aj[s] = forceatoms[iu + 2];
1327 ak[s] = forceatoms[iu + 3];
1329 /* At the end fill the arrays with the last atoms and 0 params */
1330 if (i + s * nfa1 < nbonds)
1332 coeff[s] = forceparams[type].u_b.kthetaA;
1333 coeff[GMX_SIMD_REAL_WIDTH + s] = forceparams[type].u_b.thetaA;
1334 coeff[GMX_SIMD_REAL_WIDTH * 2 + s] = forceparams[type].u_b.kUBA;
1335 coeff[GMX_SIMD_REAL_WIDTH * 3 + s] = forceparams[type].u_b.r13A;
1337 if (iu + nfa1 < nbonds)
1345 coeff[GMX_SIMD_REAL_WIDTH + s] = 0;
1346 coeff[GMX_SIMD_REAL_WIDTH * 2 + s] = 0;
1347 coeff[GMX_SIMD_REAL_WIDTH * 3 + s] = 0;
1351 SimdReal xi_S, yi_S, zi_S;
1352 SimdReal xj_S, yj_S, zj_S;
1353 SimdReal xk_S, yk_S, zk_S;
1355 /* Store the non PBC corrected distances packed and aligned */
1356 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ai, &xi_S, &yi_S, &zi_S);
1357 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), aj, &xj_S, &yj_S, &zj_S);
1358 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ak, &xk_S, &yk_S, &zk_S);
1359 SimdReal rijx_S = xi_S - xj_S;
1360 SimdReal rijy_S = yi_S - yj_S;
1361 SimdReal rijz_S = zi_S - zj_S;
1362 SimdReal rkjx_S = xk_S - xj_S;
1363 SimdReal rkjy_S = yk_S - yj_S;
1364 SimdReal rkjz_S = zk_S - zj_S;
1365 SimdReal rikx_S = xi_S - xk_S;
1366 SimdReal riky_S = yi_S - yk_S;
1367 SimdReal rikz_S = zi_S - zk_S;
1369 const SimdReal ktheta_S = load<SimdReal>(coeff);
1370 const SimdReal theta0_S = load<SimdReal>(coeff + GMX_SIMD_REAL_WIDTH) * DEG2RAD;
1371 const SimdReal kUB_S = load<SimdReal>(coeff + 2 * GMX_SIMD_REAL_WIDTH);
1372 const SimdReal r13_S = load<SimdReal>(coeff + 3 * GMX_SIMD_REAL_WIDTH);
1374 pbc_correct_dx_simd(&rijx_S, &rijy_S, &rijz_S, pbc_simd);
1375 pbc_correct_dx_simd(&rkjx_S, &rkjy_S, &rkjz_S, pbc_simd);
1376 pbc_correct_dx_simd(&rikx_S, &riky_S, &rikz_S, pbc_simd);
1378 const SimdReal rij_rkj_S = iprod(rijx_S, rijy_S, rijz_S, rkjx_S, rkjy_S, rkjz_S);
1380 const SimdReal dr2_S = iprod(rikx_S, riky_S, rikz_S, rikx_S, riky_S, rikz_S);
1382 const SimdReal nrij2_S = norm2(rijx_S, rijy_S, rijz_S);
1383 const SimdReal nrkj2_S = norm2(rkjx_S, rkjy_S, rkjz_S);
1385 const SimdReal nrij_1_S = invsqrt(nrij2_S);
1386 const SimdReal nrkj_1_S = invsqrt(nrkj2_S);
1387 const SimdReal invdr2_S = invsqrt(dr2_S);
1388 const SimdReal dr_S = dr2_S * invdr2_S;
1390 constexpr real min_one_plus_eps = -1.0 + 2.0 * GMX_REAL_EPS; // Smallest number > -1
1392 /* To allow for 180 degrees, we take the max of cos and -1 + 1bit,
1393 * so we can safely get the 1/sin from 1/sqrt(1 - cos^2).
1394 * This also ensures that rounding errors would cause the argument
1395 * of simdAcos to be < -1.
1396 * Note that we do not take precautions for cos(0)=1, so the bonds
1397 * in an angle should not align at an angle of 0 degrees.
1399 const SimdReal cos_S = max(rij_rkj_S * nrij_1_S * nrkj_1_S, min_one_plus_eps);
1401 const SimdReal theta_S = acos(cos_S);
1402 const SimdReal invsin_S = invsqrt(1.0 - cos_S * cos_S);
1403 const SimdReal st_S = ktheta_S * (theta0_S - theta_S) * invsin_S;
1404 const SimdReal sth_S = st_S * cos_S;
1406 const SimdReal cik_S = st_S * nrij_1_S * nrkj_1_S;
1407 const SimdReal cii_S = sth_S * nrij_1_S * nrij_1_S;
1408 const SimdReal ckk_S = sth_S * nrkj_1_S * nrkj_1_S;
1410 const SimdReal sUB_S = kUB_S * (r13_S - dr_S) * invdr2_S;
1412 const SimdReal f_ikx_S = sUB_S * rikx_S;
1413 const SimdReal f_iky_S = sUB_S * riky_S;
1414 const SimdReal f_ikz_S = sUB_S * rikz_S;
1416 const SimdReal f_ix_S = fnma(cik_S, rkjx_S, cii_S * rijx_S) + f_ikx_S;
1417 const SimdReal f_iy_S = fnma(cik_S, rkjy_S, cii_S * rijy_S) + f_iky_S;
1418 const SimdReal f_iz_S = fnma(cik_S, rkjz_S, cii_S * rijz_S) + f_ikz_S;
1419 const SimdReal f_kx_S = fnma(cik_S, rijx_S, ckk_S * rkjx_S) - f_ikx_S;
1420 const SimdReal f_ky_S = fnma(cik_S, rijy_S, ckk_S * rkjy_S) - f_iky_S;
1421 const SimdReal f_kz_S = fnma(cik_S, rijz_S, ckk_S * rkjz_S) - f_ikz_S;
1423 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ai, f_ix_S, f_iy_S, f_iz_S);
1424 transposeScatterDecrU<4>(reinterpret_cast<real*>(f), aj, f_ix_S + f_kx_S, f_iy_S + f_ky_S,
1426 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ak, f_kx_S, f_ky_S, f_kz_S);
1432 #endif // GMX_SIMD_HAVE_REAL
1434 template<BondedKernelFlavor flavor>
1435 real quartic_angles(int nbonds,
1436 const t_iatom forceatoms[],
1437 const t_iparams forceparams[],
1442 real gmx_unused lambda,
1443 real gmx_unused* dvdlambda,
1444 const t_mdatoms gmx_unused* md,
1445 t_fcdata gmx_unused* fcd,
1446 int gmx_unused* global_atom_index)
1448 int i, j, ai, aj, ak, t1, t2, type;
1450 real cos_theta, cos_theta2, theta, dt, dVdt, va, dtp, c, vtot;
1453 for (i = 0; (i < nbonds);)
1455 type = forceatoms[i++];
1456 ai = forceatoms[i++];
1457 aj = forceatoms[i++];
1458 ak = forceatoms[i++];
1460 theta = bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
1462 dt = theta - forceparams[type].qangle.theta * DEG2RAD; /* 2 */
1465 va = forceparams[type].qangle.c[0];
1467 for (j = 1; j <= 4; j++)
1469 c = forceparams[type].qangle.c[j];
1470 dVdt -= j * c * dtp;
1478 cos_theta2 = gmx::square(cos_theta); /* 1 */
1487 st = dVdt * gmx::invsqrt(1 - cos_theta2); /* 12 */
1488 sth = st * cos_theta; /* 1 */
1489 nrkj2 = iprod(r_kj, r_kj); /* 5 */
1490 nrij2 = iprod(r_ij, r_ij);
1492 cik = st * gmx::invsqrt(nrkj2 * nrij2); /* 12 */
1493 cii = sth / nrij2; /* 10 */
1494 ckk = sth / nrkj2; /* 10 */
1496 for (m = 0; (m < DIM); m++) /* 39 */
1498 f_i[m] = -(cik * r_kj[m] - cii * r_ij[m]);
1499 f_k[m] = -(cik * r_ij[m] - ckk * r_kj[m]);
1500 f_j[m] = -f_i[m] - f_k[m];
1506 if (computeVirial(flavor))
1508 rvec_inc(fshift[t1], f_i);
1509 rvec_inc(fshift[CENTRAL], f_j);
1510 rvec_inc(fshift[t2], f_k);
1518 #if GMX_SIMD_HAVE_REAL
1520 /* As dih_angle above, but calculates 4 dihedral angles at once using SIMD,
1521 * also calculates the pre-factor required for the dihedral force update.
1522 * Note that bv and buf should be register aligned.
1524 inline void dih_angle_simd(const rvec* x,
1529 const real* pbc_simd,
1537 SimdReal* nrkj_m2_S,
1538 SimdReal* nrkj_n2_S,
1542 SimdReal xi_S, yi_S, zi_S;
1543 SimdReal xj_S, yj_S, zj_S;
1544 SimdReal xk_S, yk_S, zk_S;
1545 SimdReal xl_S, yl_S, zl_S;
1546 SimdReal rijx_S, rijy_S, rijz_S;
1547 SimdReal rkjx_S, rkjy_S, rkjz_S;
1548 SimdReal rklx_S, rkly_S, rklz_S;
1549 SimdReal cx_S, cy_S, cz_S;
1553 SimdReal iprm_S, iprn_S;
1554 SimdReal nrkj2_S, nrkj_1_S, nrkj_2_S, nrkj_S;
1556 SimdReal nrkj2_min_S;
1557 SimdReal real_eps_S;
1559 /* Used to avoid division by zero.
1560 * We take into acount that we multiply the result by real_eps_S.
1562 nrkj2_min_S = SimdReal(GMX_REAL_MIN / (2 * GMX_REAL_EPS));
1564 /* The value of the last significant bit (GMX_REAL_EPS is half of that) */
1565 real_eps_S = SimdReal(2 * GMX_REAL_EPS);
1567 /* Store the non PBC corrected distances packed and aligned */
1568 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ai, &xi_S, &yi_S, &zi_S);
1569 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), aj, &xj_S, &yj_S, &zj_S);
1570 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ak, &xk_S, &yk_S, &zk_S);
1571 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), al, &xl_S, &yl_S, &zl_S);
1572 rijx_S = xi_S - xj_S;
1573 rijy_S = yi_S - yj_S;
1574 rijz_S = zi_S - zj_S;
1575 rkjx_S = xk_S - xj_S;
1576 rkjy_S = yk_S - yj_S;
1577 rkjz_S = zk_S - zj_S;
1578 rklx_S = xk_S - xl_S;
1579 rkly_S = yk_S - yl_S;
1580 rklz_S = zk_S - zl_S;
1582 pbc_correct_dx_simd(&rijx_S, &rijy_S, &rijz_S, pbc_simd);
1583 pbc_correct_dx_simd(&rkjx_S, &rkjy_S, &rkjz_S, pbc_simd);
1584 pbc_correct_dx_simd(&rklx_S, &rkly_S, &rklz_S, pbc_simd);
1586 cprod(rijx_S, rijy_S, rijz_S, rkjx_S, rkjy_S, rkjz_S, mx_S, my_S, mz_S);
1588 cprod(rkjx_S, rkjy_S, rkjz_S, rklx_S, rkly_S, rklz_S, nx_S, ny_S, nz_S);
1590 cprod(*mx_S, *my_S, *mz_S, *nx_S, *ny_S, *nz_S, &cx_S, &cy_S, &cz_S);
1592 cn_S = sqrt(norm2(cx_S, cy_S, cz_S));
1594 s_S = iprod(*mx_S, *my_S, *mz_S, *nx_S, *ny_S, *nz_S);
1596 /* Determine the dihedral angle, the sign might need correction */
1597 *phi_S = atan2(cn_S, s_S);
1599 ipr_S = iprod(rijx_S, rijy_S, rijz_S, *nx_S, *ny_S, *nz_S);
1601 iprm_S = norm2(*mx_S, *my_S, *mz_S);
1602 iprn_S = norm2(*nx_S, *ny_S, *nz_S);
1604 nrkj2_S = norm2(rkjx_S, rkjy_S, rkjz_S);
1606 /* Avoid division by zero. When zero, the result is multiplied by 0
1607 * anyhow, so the 3 max below do not affect the final result.
1609 nrkj2_S = max(nrkj2_S, nrkj2_min_S);
1610 nrkj_1_S = invsqrt(nrkj2_S);
1611 nrkj_2_S = nrkj_1_S * nrkj_1_S;
1612 nrkj_S = nrkj2_S * nrkj_1_S;
1614 toler_S = nrkj2_S * real_eps_S;
1616 /* Here the plain-C code uses a conditional, but we can't do that in SIMD.
1617 * So we take a max with the tolerance instead. Since we multiply with
1618 * m or n later, the max does not affect the results.
1620 iprm_S = max(iprm_S, toler_S);
1621 iprn_S = max(iprn_S, toler_S);
1622 *nrkj_m2_S = nrkj_S * inv(iprm_S);
1623 *nrkj_n2_S = nrkj_S * inv(iprn_S);
1625 /* Set sign of phi_S with the sign of ipr_S; phi_S is currently positive */
1626 *phi_S = copysign(*phi_S, ipr_S);
1627 *p_S = iprod(rijx_S, rijy_S, rijz_S, rkjx_S, rkjy_S, rkjz_S);
1628 *p_S = *p_S * nrkj_2_S;
1630 *q_S = iprod(rklx_S, rkly_S, rklz_S, rkjx_S, rkjy_S, rkjz_S);
1631 *q_S = *q_S * nrkj_2_S;
1634 #endif // GMX_SIMD_HAVE_REAL
1638 template<BondedKernelFlavor flavor>
1639 void do_dih_fup(int i,
1658 rvec f_i, f_j, f_k, f_l;
1659 rvec uvec, vvec, svec, dx_jl;
1660 real iprm, iprn, nrkj, nrkj2, nrkj_1, nrkj_2;
1661 real a, b, p, q, toler;
1663 iprm = iprod(m, m); /* 5 */
1664 iprn = iprod(n, n); /* 5 */
1665 nrkj2 = iprod(r_kj, r_kj); /* 5 */
1666 toler = nrkj2 * GMX_REAL_EPS;
1667 if ((iprm > toler) && (iprn > toler))
1669 nrkj_1 = gmx::invsqrt(nrkj2); /* 10 */
1670 nrkj_2 = nrkj_1 * nrkj_1; /* 1 */
1671 nrkj = nrkj2 * nrkj_1; /* 1 */
1672 a = -ddphi * nrkj / iprm; /* 11 */
1673 svmul(a, m, f_i); /* 3 */
1674 b = ddphi * nrkj / iprn; /* 11 */
1675 svmul(b, n, f_l); /* 3 */
1676 p = iprod(r_ij, r_kj); /* 5 */
1677 p *= nrkj_2; /* 1 */
1678 q = iprod(r_kl, r_kj); /* 5 */
1679 q *= nrkj_2; /* 1 */
1680 svmul(p, f_i, uvec); /* 3 */
1681 svmul(q, f_l, vvec); /* 3 */
1682 rvec_sub(uvec, vvec, svec); /* 3 */
1683 rvec_sub(f_i, svec, f_j); /* 3 */
1684 rvec_add(f_l, svec, f_k); /* 3 */
1685 rvec_inc(f[i], f_i); /* 3 */
1686 rvec_dec(f[j], f_j); /* 3 */
1687 rvec_dec(f[k], f_k); /* 3 */
1688 rvec_inc(f[l], f_l); /* 3 */
1690 if (computeVirial(flavor))
1694 t3 = pbc_rvec_sub(pbc, x[l], x[j], dx_jl);
1701 rvec_inc(fshift[t1], f_i);
1702 rvec_dec(fshift[CENTRAL], f_j);
1703 rvec_dec(fshift[t2], f_k);
1704 rvec_inc(fshift[t3], f_l);
1713 #if GMX_SIMD_HAVE_REAL
1714 /* As do_dih_fup_noshiftf above, but with SIMD and pre-calculated pre-factors */
1715 inline void gmx_simdcall do_dih_fup_noshiftf_simd(const int* ai,
1729 SimdReal sx = p * f_i_x + q * mf_l_x;
1730 SimdReal sy = p * f_i_y + q * mf_l_y;
1731 SimdReal sz = p * f_i_z + q * mf_l_z;
1732 SimdReal f_j_x = f_i_x - sx;
1733 SimdReal f_j_y = f_i_y - sy;
1734 SimdReal f_j_z = f_i_z - sz;
1735 SimdReal f_k_x = mf_l_x - sx;
1736 SimdReal f_k_y = mf_l_y - sy;
1737 SimdReal f_k_z = mf_l_z - sz;
1738 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ai, f_i_x, f_i_y, f_i_z);
1739 transposeScatterDecrU<4>(reinterpret_cast<real*>(f), aj, f_j_x, f_j_y, f_j_z);
1740 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ak, f_k_x, f_k_y, f_k_z);
1741 transposeScatterDecrU<4>(reinterpret_cast<real*>(f), al, mf_l_x, mf_l_y, mf_l_z);
1743 #endif // GMX_SIMD_HAVE_REAL
1745 /*! \brief Computes and returns the proper dihedral force
1747 * With the appropriate kernel flavor, also computes and accumulates
1748 * the energy and dV/dlambda.
1750 template<BondedKernelFlavor flavor>
1751 real dopdihs(real cpA, real cpB, real phiA, real phiB, int mult, real phi, real lambda, real* V, real* dvdlambda)
1753 const real L1 = 1.0 - lambda;
1754 const real ph0 = (L1 * phiA + lambda * phiB) * DEG2RAD;
1755 const real dph0 = (phiB - phiA) * DEG2RAD;
1756 const real cp = L1 * cpA + lambda * cpB;
1758 const real mdphi = mult * phi - ph0;
1759 const real sdphi = std::sin(mdphi);
1760 const real ddphi = -cp * mult * sdphi;
1761 if (computeEnergy(flavor))
1763 const real v1 = 1 + std::cos(mdphi);
1766 *dvdlambda += (cpB - cpA) * v1 + cp * dph0 * sdphi;
1770 /* That was 40 flops */
1773 /*! \brief Similar to \p dopdihs(), except for a minus sign and a different treatment of mult/phi0 */
1774 real dopdihs_min(real cpA, real cpB, real phiA, real phiB, int mult, real phi, real lambda, real* V, real* F)
1776 real v, dvdlambda, mdphi, v1, sdphi, ddphi;
1777 real L1 = 1.0 - lambda;
1778 real ph0 = (L1 * phiA + lambda * phiB) * DEG2RAD;
1779 real dph0 = (phiB - phiA) * DEG2RAD;
1780 real cp = L1 * cpA + lambda * cpB;
1782 mdphi = mult * (phi - ph0);
1783 sdphi = std::sin(mdphi);
1784 ddphi = cp * mult * sdphi;
1785 v1 = 1.0 - std::cos(mdphi);
1788 dvdlambda = (cpB - cpA) * v1 + cp * dph0 * sdphi;
1795 /* That was 40 flops */
1798 template<BondedKernelFlavor flavor>
1799 std::enable_if_t<flavor != BondedKernelFlavor::ForcesSimdWhenAvailable || !GMX_SIMD_HAVE_REAL, real>
1801 const t_iatom forceatoms[],
1802 const t_iparams forceparams[],
1809 const t_mdatoms gmx_unused* md,
1810 t_fcdata gmx_unused* fcd,
1811 int gmx_unused* global_atom_index)
1814 rvec r_ij, r_kj, r_kl, m, n;
1818 for (int i = 0; i < nbonds;)
1820 const int ai = forceatoms[i + 1];
1821 const int aj = forceatoms[i + 2];
1822 const int ak = forceatoms[i + 3];
1823 const int al = forceatoms[i + 4];
1825 const real phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n, &t1,
1828 /* Loop over dihedrals working on the same atoms,
1829 * so we avoid recalculating angles and distributing forces.
1834 const int type = forceatoms[i];
1835 ddphi_tot += dopdihs<flavor>(forceparams[type].pdihs.cpA, forceparams[type].pdihs.cpB,
1836 forceparams[type].pdihs.phiA, forceparams[type].pdihs.phiB,
1837 forceparams[type].pdihs.mult, phi, lambda, &vtot, dvdlambda);
1840 } while (i < nbonds && forceatoms[i + 1] == ai && forceatoms[i + 2] == aj
1841 && forceatoms[i + 3] == ak && forceatoms[i + 4] == al);
1843 do_dih_fup<flavor>(ai, aj, ak, al, ddphi_tot, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1,
1850 #if GMX_SIMD_HAVE_REAL
1852 /* As pdihs above, but using SIMD to calculate multiple dihedrals at once */
1853 template<BondedKernelFlavor flavor>
1854 std::enable_if_t<flavor == BondedKernelFlavor::ForcesSimdWhenAvailable, real>
1856 const t_iatom forceatoms[],
1857 const t_iparams forceparams[],
1860 rvec gmx_unused fshift[],
1862 real gmx_unused lambda,
1863 real gmx_unused* dvdlambda,
1864 const t_mdatoms gmx_unused* md,
1865 t_fcdata gmx_unused* fcd,
1866 int gmx_unused* global_atom_index)
1871 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[GMX_SIMD_REAL_WIDTH];
1872 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[GMX_SIMD_REAL_WIDTH];
1873 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ak[GMX_SIMD_REAL_WIDTH];
1874 alignas(GMX_SIMD_ALIGNMENT) std::int32_t al[GMX_SIMD_REAL_WIDTH];
1875 alignas(GMX_SIMD_ALIGNMENT) real buf[3 * GMX_SIMD_REAL_WIDTH];
1876 real * cp, *phi0, *mult;
1877 SimdReal deg2rad_S(DEG2RAD);
1879 SimdReal phi0_S, phi_S;
1880 SimdReal mx_S, my_S, mz_S;
1881 SimdReal nx_S, ny_S, nz_S;
1882 SimdReal nrkj_m2_S, nrkj_n2_S;
1883 SimdReal cp_S, mdphi_S, mult_S;
1884 SimdReal sin_S, cos_S;
1886 SimdReal sf_i_S, msf_l_S;
1887 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9 * GMX_SIMD_REAL_WIDTH];
1889 /* Extract aligned pointer for parameters and variables */
1890 cp = buf + 0 * GMX_SIMD_REAL_WIDTH;
1891 phi0 = buf + 1 * GMX_SIMD_REAL_WIDTH;
1892 mult = buf + 2 * GMX_SIMD_REAL_WIDTH;
1894 set_pbc_simd(pbc, pbc_simd);
1896 /* nbonds is the number of dihedrals times nfa1, here we step GMX_SIMD_REAL_WIDTH dihs */
1897 for (i = 0; (i < nbonds); i += GMX_SIMD_REAL_WIDTH * nfa1)
1899 /* Collect atoms quadruplets for GMX_SIMD_REAL_WIDTH dihedrals.
1900 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
1903 for (s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
1905 type = forceatoms[iu];
1906 ai[s] = forceatoms[iu + 1];
1907 aj[s] = forceatoms[iu + 2];
1908 ak[s] = forceatoms[iu + 3];
1909 al[s] = forceatoms[iu + 4];
1911 /* At the end fill the arrays with the last atoms and 0 params */
1912 if (i + s * nfa1 < nbonds)
1914 cp[s] = forceparams[type].pdihs.cpA;
1915 phi0[s] = forceparams[type].pdihs.phiA;
1916 mult[s] = forceparams[type].pdihs.mult;
1918 if (iu + nfa1 < nbonds)
1931 /* Caclulate GMX_SIMD_REAL_WIDTH dihedral angles at once */
1932 dih_angle_simd(x, ai, aj, ak, al, pbc_simd, &phi_S, &mx_S, &my_S, &mz_S, &nx_S, &ny_S,
1933 &nz_S, &nrkj_m2_S, &nrkj_n2_S, &p_S, &q_S);
1935 cp_S = load<SimdReal>(cp);
1936 phi0_S = load<SimdReal>(phi0) * deg2rad_S;
1937 mult_S = load<SimdReal>(mult);
1939 mdphi_S = fms(mult_S, phi_S, phi0_S);
1941 /* Calculate GMX_SIMD_REAL_WIDTH sines at once */
1942 sincos(mdphi_S, &sin_S, &cos_S);
1943 mddphi_S = cp_S * mult_S * sin_S;
1944 sf_i_S = mddphi_S * nrkj_m2_S;
1945 msf_l_S = mddphi_S * nrkj_n2_S;
1947 /* After this m?_S will contain f[i] */
1948 mx_S = sf_i_S * mx_S;
1949 my_S = sf_i_S * my_S;
1950 mz_S = sf_i_S * mz_S;
1952 /* After this m?_S will contain -f[l] */
1953 nx_S = msf_l_S * nx_S;
1954 ny_S = msf_l_S * ny_S;
1955 nz_S = msf_l_S * nz_S;
1957 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);
1963 /* This is mostly a copy of the SIMD flavor of pdihs above, but with using
1964 * the RB potential instead of a harmonic potential.
1965 * This function can replace rbdihs() when no energy and virial are needed.
1967 template<BondedKernelFlavor flavor>
1968 std::enable_if_t<flavor == BondedKernelFlavor::ForcesSimdWhenAvailable, real>
1970 const t_iatom forceatoms[],
1971 const t_iparams forceparams[],
1974 rvec gmx_unused fshift[],
1976 real gmx_unused lambda,
1977 real gmx_unused* dvdlambda,
1978 const t_mdatoms gmx_unused* md,
1979 t_fcdata gmx_unused* fcd,
1980 int gmx_unused* global_atom_index)
1985 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[GMX_SIMD_REAL_WIDTH];
1986 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[GMX_SIMD_REAL_WIDTH];
1987 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ak[GMX_SIMD_REAL_WIDTH];
1988 alignas(GMX_SIMD_ALIGNMENT) std::int32_t al[GMX_SIMD_REAL_WIDTH];
1989 alignas(GMX_SIMD_ALIGNMENT) real parm[NR_RBDIHS * GMX_SIMD_REAL_WIDTH];
1993 SimdReal ddphi_S, cosfac_S;
1994 SimdReal mx_S, my_S, mz_S;
1995 SimdReal nx_S, ny_S, nz_S;
1996 SimdReal nrkj_m2_S, nrkj_n2_S;
1997 SimdReal parm_S, c_S;
1998 SimdReal sin_S, cos_S;
1999 SimdReal sf_i_S, msf_l_S;
2000 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9 * GMX_SIMD_REAL_WIDTH];
2002 SimdReal pi_S(M_PI);
2003 SimdReal one_S(1.0);
2005 set_pbc_simd(pbc, pbc_simd);
2007 /* nbonds is the number of dihedrals times nfa1, here we step GMX_SIMD_REAL_WIDTH dihs */
2008 for (i = 0; (i < nbonds); i += GMX_SIMD_REAL_WIDTH * nfa1)
2010 /* Collect atoms quadruplets for GMX_SIMD_REAL_WIDTH dihedrals.
2011 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
2014 for (s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
2016 type = forceatoms[iu];
2017 ai[s] = forceatoms[iu + 1];
2018 aj[s] = forceatoms[iu + 2];
2019 ak[s] = forceatoms[iu + 3];
2020 al[s] = forceatoms[iu + 4];
2022 /* At the end fill the arrays with the last atoms and 0 params */
2023 if (i + s * nfa1 < nbonds)
2025 /* We don't need the first parameter, since that's a constant
2026 * which only affects the energies, not the forces.
2028 for (j = 1; j < NR_RBDIHS; j++)
2030 parm[j * GMX_SIMD_REAL_WIDTH + s] = forceparams[type].rbdihs.rbcA[j];
2033 if (iu + nfa1 < nbonds)
2040 for (j = 1; j < NR_RBDIHS; j++)
2042 parm[j * GMX_SIMD_REAL_WIDTH + s] = 0;
2047 /* Caclulate GMX_SIMD_REAL_WIDTH dihedral angles at once */
2048 dih_angle_simd(x, ai, aj, ak, al, pbc_simd, &phi_S, &mx_S, &my_S, &mz_S, &nx_S, &ny_S,
2049 &nz_S, &nrkj_m2_S, &nrkj_n2_S, &p_S, &q_S);
2051 /* Change to polymer convention */
2052 phi_S = phi_S - pi_S;
2054 sincos(phi_S, &sin_S, &cos_S);
2056 ddphi_S = setZero();
2059 for (j = 1; j < NR_RBDIHS; j++)
2061 parm_S = load<SimdReal>(parm + j * GMX_SIMD_REAL_WIDTH);
2062 ddphi_S = fma(c_S * parm_S, cosfac_S, ddphi_S);
2063 cosfac_S = cosfac_S * cos_S;
2067 /* Note that here we do not use the minus sign which is present
2068 * in the normal RB code. This is corrected for through (m)sf below.
2070 ddphi_S = ddphi_S * sin_S;
2072 sf_i_S = ddphi_S * nrkj_m2_S;
2073 msf_l_S = ddphi_S * nrkj_n2_S;
2075 /* After this m?_S will contain f[i] */
2076 mx_S = sf_i_S * mx_S;
2077 my_S = sf_i_S * my_S;
2078 mz_S = sf_i_S * mz_S;
2080 /* After this m?_S will contain -f[l] */
2081 nx_S = msf_l_S * nx_S;
2082 ny_S = msf_l_S * ny_S;
2083 nz_S = msf_l_S * nz_S;
2085 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);
2091 #endif // GMX_SIMD_HAVE_REAL
2094 template<BondedKernelFlavor flavor>
2095 real idihs(int nbonds,
2096 const t_iatom forceatoms[],
2097 const t_iparams forceparams[],
2104 const t_mdatoms gmx_unused* md,
2105 t_fcdata gmx_unused* fcd,
2106 int gmx_unused* global_atom_index)
2108 int i, type, ai, aj, ak, al;
2110 real phi, phi0, dphi0, ddphi, vtot;
2111 rvec r_ij, r_kj, r_kl, m, n;
2112 real L1, kk, dp, dp2, kA, kB, pA, pB, dvdl_term;
2117 for (i = 0; (i < nbonds);)
2119 type = forceatoms[i++];
2120 ai = forceatoms[i++];
2121 aj = forceatoms[i++];
2122 ak = forceatoms[i++];
2123 al = forceatoms[i++];
2125 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3); /* 84 */
2127 /* phi can jump if phi0 is close to Pi/-Pi, which will cause huge
2128 * force changes if we just apply a normal harmonic.
2129 * Instead, we first calculate phi-phi0 and take it modulo (-Pi,Pi).
2130 * This means we will never have the periodicity problem, unless
2131 * the dihedral is Pi away from phiO, which is very unlikely due to
2134 kA = forceparams[type].harmonic.krA;
2135 kB = forceparams[type].harmonic.krB;
2136 pA = forceparams[type].harmonic.rA;
2137 pB = forceparams[type].harmonic.rB;
2139 kk = L1 * kA + lambda * kB;
2140 phi0 = (L1 * pA + lambda * pB) * DEG2RAD;
2141 dphi0 = (pB - pA) * DEG2RAD;
2145 make_dp_periodic(&dp);
2149 vtot += 0.5 * kk * dp2;
2152 dvdl_term += 0.5 * (kB - kA) * dp2 - kk * dphi0 * dp;
2154 do_dih_fup<flavor>(ai, aj, ak, al, -ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1,
2159 *dvdlambda += dvdl_term;
2163 /*! \brief Computes angle restraints of two different types */
2164 template<BondedKernelFlavor flavor>
2165 real low_angres(int nbonds,
2166 const t_iatom forceatoms[],
2167 const t_iparams forceparams[],
2176 int i, m, type, ai, aj, ak, al;
2178 real phi, cos_phi, cos_phi2, vid, vtot, dVdphi;
2179 rvec r_ij, r_kl, f_i, f_k = { 0, 0, 0 };
2180 real st, sth, nrij2, nrkl2, c, cij, ckl;
2182 t2 = 0; /* avoid warning with gcc-3.3. It is never used uninitialized */
2185 ak = al = 0; /* to avoid warnings */
2186 for (i = 0; i < nbonds;)
2188 type = forceatoms[i++];
2189 ai = forceatoms[i++];
2190 aj = forceatoms[i++];
2191 t1 = pbc_rvec_sub(pbc, x[aj], x[ai], r_ij); /* 3 */
2194 ak = forceatoms[i++];
2195 al = forceatoms[i++];
2196 t2 = pbc_rvec_sub(pbc, x[al], x[ak], r_kl); /* 3 */
2205 cos_phi = cos_angle(r_ij, r_kl); /* 25 */
2206 phi = std::acos(cos_phi); /* 10 */
2208 *dvdlambda += dopdihs_min(forceparams[type].pdihs.cpA, forceparams[type].pdihs.cpB,
2209 forceparams[type].pdihs.phiA, forceparams[type].pdihs.phiB,
2210 forceparams[type].pdihs.mult, phi, lambda, &vid, &dVdphi); /* 40 */
2214 cos_phi2 = gmx::square(cos_phi); /* 1 */
2217 st = -dVdphi * gmx::invsqrt(1 - cos_phi2); /* 12 */
2218 sth = st * cos_phi; /* 1 */
2219 nrij2 = iprod(r_ij, r_ij); /* 5 */
2220 nrkl2 = iprod(r_kl, r_kl); /* 5 */
2222 c = st * gmx::invsqrt(nrij2 * nrkl2); /* 11 */
2223 cij = sth / nrij2; /* 10 */
2224 ckl = sth / nrkl2; /* 10 */
2226 for (m = 0; m < DIM; m++) /* 18+18 */
2228 f_i[m] = (c * r_kl[m] - cij * r_ij[m]);
2233 f_k[m] = (c * r_ij[m] - ckl * r_kl[m]);
2239 if (computeVirial(flavor))
2241 rvec_inc(fshift[t1], f_i);
2242 rvec_dec(fshift[CENTRAL], f_i);
2245 rvec_inc(fshift[t2], f_k);
2246 rvec_dec(fshift[CENTRAL], f_k);
2252 return vtot; /* 184 / 157 (bZAxis) total */
2255 template<BondedKernelFlavor flavor>
2256 real angres(int nbonds,
2257 const t_iatom forceatoms[],
2258 const t_iparams forceparams[],
2265 const t_mdatoms gmx_unused* md,
2266 t_fcdata gmx_unused* fcd,
2267 int gmx_unused* global_atom_index)
2269 return low_angres<flavor>(nbonds, forceatoms, forceparams, x, f, fshift, pbc, lambda, dvdlambda, FALSE);
2272 template<BondedKernelFlavor flavor>
2273 real angresz(int nbonds,
2274 const t_iatom forceatoms[],
2275 const t_iparams forceparams[],
2282 const t_mdatoms gmx_unused* md,
2283 t_fcdata gmx_unused* fcd,
2284 int gmx_unused* global_atom_index)
2286 return low_angres<flavor>(nbonds, forceatoms, forceparams, x, f, fshift, pbc, lambda, dvdlambda, TRUE);
2289 template<BondedKernelFlavor flavor>
2290 real dihres(int nbonds,
2291 const t_iatom forceatoms[],
2292 const t_iparams forceparams[],
2299 const t_mdatoms gmx_unused* md,
2300 t_fcdata gmx_unused* fcd,
2301 int gmx_unused* global_atom_index)
2304 int ai, aj, ak, al, i, type, t1, t2, t3;
2305 real phi0A, phi0B, dphiA, dphiB, kfacA, kfacB, phi0, dphi, kfac;
2306 real phi, ddphi, ddp, ddp2, dp, d2r, L1;
2307 rvec r_ij, r_kj, r_kl, m, n;
2313 for (i = 0; (i < nbonds);)
2315 type = forceatoms[i++];
2316 ai = forceatoms[i++];
2317 aj = forceatoms[i++];
2318 ak = forceatoms[i++];
2319 al = forceatoms[i++];
2321 phi0A = forceparams[type].dihres.phiA * d2r;
2322 dphiA = forceparams[type].dihres.dphiA * d2r;
2323 kfacA = forceparams[type].dihres.kfacA;
2325 phi0B = forceparams[type].dihres.phiB * d2r;
2326 dphiB = forceparams[type].dihres.dphiB * d2r;
2327 kfacB = forceparams[type].dihres.kfacB;
2329 phi0 = L1 * phi0A + lambda * phi0B;
2330 dphi = L1 * dphiA + lambda * dphiB;
2331 kfac = L1 * kfacA + lambda * kfacB;
2333 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3);
2336 /* phi can jump if phi0 is close to Pi/-Pi, which will cause huge
2337 * force changes if we just apply a normal harmonic.
2338 * Instead, we first calculate phi-phi0 and take it modulo (-Pi,Pi).
2339 * This means we will never have the periodicity problem, unless
2340 * the dihedral is Pi away from phiO, which is very unlikely due to
2344 make_dp_periodic(&dp);
2350 else if (dp < -dphi)
2362 vtot += 0.5 * kfac * ddp2;
2365 *dvdlambda += 0.5 * (kfacB - kfacA) * ddp2;
2366 /* lambda dependence from changing restraint distances */
2369 *dvdlambda -= kfac * ddp * ((dphiB - dphiA) + (phi0B - phi0A));
2373 *dvdlambda += kfac * ddp * ((dphiB - dphiA) - (phi0B - phi0A));
2375 do_dih_fup<flavor>(ai, aj, ak, al, ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1,
2383 real unimplemented(int gmx_unused nbonds,
2384 const t_iatom gmx_unused forceatoms[],
2385 const t_iparams gmx_unused forceparams[],
2386 const rvec gmx_unused x[],
2387 rvec4 gmx_unused f[],
2388 rvec gmx_unused fshift[],
2389 const t_pbc gmx_unused* pbc,
2390 real gmx_unused lambda,
2391 real gmx_unused* dvdlambda,
2392 const t_mdatoms gmx_unused* md,
2393 t_fcdata gmx_unused* fcd,
2394 int gmx_unused* global_atom_index)
2396 gmx_impl("*** you are using a not implemented function");
2399 template<BondedKernelFlavor flavor>
2400 real restrangles(int nbonds,
2401 const t_iatom forceatoms[],
2402 const t_iparams forceparams[],
2407 real gmx_unused lambda,
2408 real gmx_unused* dvdlambda,
2409 const t_mdatoms gmx_unused* md,
2410 t_fcdata gmx_unused* fcd,
2411 int gmx_unused* global_atom_index)
2413 int i, d, ai, aj, ak, type, m;
2417 double prefactor, ratio_ante, ratio_post;
2418 rvec delta_ante, delta_post, vec_temp;
2421 for (i = 0; (i < nbonds);)
2423 type = forceatoms[i++];
2424 ai = forceatoms[i++];
2425 aj = forceatoms[i++];
2426 ak = forceatoms[i++];
2428 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], vec_temp);
2429 pbc_rvec_sub(pbc, x[aj], x[ai], delta_ante);
2430 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], delta_post);
2433 /* This function computes factors needed for restricted angle potential.
2434 * The restricted angle potential is used in coarse-grained simulations to avoid singularities
2435 * when three particles align and the dihedral angle and dihedral potential
2436 * cannot be calculated. This potential is calculated using the formula:
2437 real restrangles(int nbonds,
2438 const t_iatom forceatoms[],const t_iparams forceparams[],
2439 const rvec x[],rvec4 f[],rvec fshift[],
2441 real gmx_unused lambda,real gmx_unused *dvdlambda,
2442 const t_mdatoms gmx_unused *md,t_fcdata gmx_unused *fcd,
2443 int gmx_unused *global_atom_index)
2445 int i, d, ai, aj, ak, type, m;
2450 real prefactor, ratio_ante, ratio_post;
2451 rvec delta_ante, delta_post, vec_temp;
2454 for(i=0; (i<nbonds); )
2456 type = forceatoms[i++];
2457 ai = forceatoms[i++];
2458 aj = forceatoms[i++];
2459 ak = forceatoms[i++];
2461 * \f[V_{\rm ReB}(\theta_i) = \frac{1}{2} k_{\theta} \frac{(\cos\theta_i - \cos\theta_0)^2}
2462 * {\sin^2\theta_i}\f] ({eq:ReB} and ref \cite{MonicaGoga2013} from the manual).
2463 * For more explanations see comments file "restcbt.h". */
2465 compute_factors_restangles(type, forceparams, delta_ante, delta_post, &prefactor,
2466 &ratio_ante, &ratio_post, &v);
2468 /* Forces are computed per component */
2469 for (d = 0; d < DIM; d++)
2471 f_i[d] = prefactor * (ratio_ante * delta_ante[d] - delta_post[d]);
2473 * ((ratio_post + 1.0) * delta_post[d] - (ratio_ante + 1.0) * delta_ante[d]);
2474 f_k[d] = prefactor * (delta_ante[d] - ratio_post * delta_post[d]);
2477 /* Computation of potential energy */
2483 for (m = 0; (m < DIM); m++)
2490 if (computeVirial(flavor))
2492 rvec_inc(fshift[t1], f_i);
2493 rvec_inc(fshift[CENTRAL], f_j);
2494 rvec_inc(fshift[t2], f_k);
2501 template<BondedKernelFlavor flavor>
2502 real restrdihs(int nbonds,
2503 const t_iatom forceatoms[],
2504 const t_iparams forceparams[],
2509 real gmx_unused lambda,
2510 real gmx_unused* dvlambda,
2511 const t_mdatoms gmx_unused* md,
2512 t_fcdata gmx_unused* fcd,
2513 int gmx_unused* global_atom_index)
2515 int i, d, type, ai, aj, ak, al;
2516 rvec f_i, f_j, f_k, f_l;
2520 rvec delta_ante, delta_crnt, delta_post, vec_temp;
2521 real factor_phi_ai_ante, factor_phi_ai_crnt, factor_phi_ai_post;
2522 real factor_phi_aj_ante, factor_phi_aj_crnt, factor_phi_aj_post;
2523 real factor_phi_ak_ante, factor_phi_ak_crnt, factor_phi_ak_post;
2524 real factor_phi_al_ante, factor_phi_al_crnt, factor_phi_al_post;
2529 for (i = 0; (i < nbonds);)
2531 type = forceatoms[i++];
2532 ai = forceatoms[i++];
2533 aj = forceatoms[i++];
2534 ak = forceatoms[i++];
2535 al = 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_crnt);
2540 pbc_rvec_sub(pbc, x[ak], x[al], vec_temp);
2541 pbc_rvec_sub(pbc, x[al], x[ak], delta_post);
2543 /* This function computes factors needed for restricted angle potential.
2544 * The restricted angle potential is used in coarse-grained simulations to avoid singularities
2545 * when three particles align and the dihedral angle and dihedral potential cannot be calculated.
2546 * This potential is calculated using the formula:
2547 * \f[V_{\rm ReB}(\theta_i) = \frac{1}{2} k_{\theta}
2548 * \frac{(\cos\theta_i - \cos\theta_0)^2}{\sin^2\theta_i}\f]
2549 * ({eq:ReB} and ref \cite{MonicaGoga2013} from the manual).
2550 * For more explanations see comments file "restcbt.h" */
2552 compute_factors_restrdihs(
2553 type, forceparams, delta_ante, delta_crnt, delta_post, &factor_phi_ai_ante,
2554 &factor_phi_ai_crnt, &factor_phi_ai_post, &factor_phi_aj_ante, &factor_phi_aj_crnt,
2555 &factor_phi_aj_post, &factor_phi_ak_ante, &factor_phi_ak_crnt, &factor_phi_ak_post,
2556 &factor_phi_al_ante, &factor_phi_al_crnt, &factor_phi_al_post, &prefactor_phi, &v);
2559 /* Computation of forces per component */
2560 for (d = 0; d < DIM; d++)
2562 f_i[d] = prefactor_phi
2563 * (factor_phi_ai_ante * delta_ante[d] + factor_phi_ai_crnt * delta_crnt[d]
2564 + factor_phi_ai_post * delta_post[d]);
2565 f_j[d] = prefactor_phi
2566 * (factor_phi_aj_ante * delta_ante[d] + factor_phi_aj_crnt * delta_crnt[d]
2567 + factor_phi_aj_post * delta_post[d]);
2568 f_k[d] = prefactor_phi
2569 * (factor_phi_ak_ante * delta_ante[d] + factor_phi_ak_crnt * delta_crnt[d]
2570 + factor_phi_ak_post * delta_post[d]);
2571 f_l[d] = prefactor_phi
2572 * (factor_phi_al_ante * delta_ante[d] + factor_phi_al_crnt * delta_crnt[d]
2573 + factor_phi_al_post * delta_post[d]);
2575 /* Computation of the energy */
2580 /* Updating the forces */
2582 rvec_inc(f[ai], f_i);
2583 rvec_inc(f[aj], f_j);
2584 rvec_inc(f[ak], f_k);
2585 rvec_inc(f[al], f_l);
2587 if (computeVirial(flavor))
2591 t3 = pbc_rvec_sub(pbc, x[al], x[aj], dx_jl);
2598 rvec_inc(fshift[t1], f_i);
2599 rvec_inc(fshift[CENTRAL], f_j);
2600 rvec_inc(fshift[t2], f_k);
2601 rvec_inc(fshift[t3], f_l);
2609 template<BondedKernelFlavor flavor>
2610 real cbtdihs(int nbonds,
2611 const t_iatom forceatoms[],
2612 const t_iparams forceparams[],
2617 real gmx_unused lambda,
2618 real gmx_unused* dvdlambda,
2619 const t_mdatoms gmx_unused* md,
2620 t_fcdata gmx_unused* fcd,
2621 int gmx_unused* global_atom_index)
2623 int type, ai, aj, ak, al, i, d;
2627 rvec f_i, f_j, f_k, f_l;
2629 rvec delta_ante, delta_crnt, delta_post;
2630 rvec f_phi_ai, f_phi_aj, f_phi_ak, f_phi_al;
2631 rvec f_theta_ante_ai, f_theta_ante_aj, f_theta_ante_ak;
2632 rvec f_theta_post_aj, f_theta_post_ak, f_theta_post_al;
2636 for (i = 0; (i < nbonds);)
2638 type = forceatoms[i++];
2639 ai = forceatoms[i++];
2640 aj = forceatoms[i++];
2641 ak = forceatoms[i++];
2642 al = forceatoms[i++];
2645 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], vec_temp);
2646 pbc_rvec_sub(pbc, x[aj], x[ai], delta_ante);
2647 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], vec_temp);
2648 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 /* \brief Compute factors for CBT potential
2653 * The combined bending-torsion potential goes to zero in a very smooth manner, eliminating the numerical
2654 * instabilities, when three coarse-grained particles align and the dihedral angle and standard
2655 * dihedral potentials cannot be calculated. The CBT potential is calculated using the formula:
2656 * \f[V_{\rm CBT}(\theta_{i-1}, \theta_i, \phi_i) = k_{\phi} \sin^3\theta_{i-1} \sin^3\theta_{i}
2657 * \sum_{n=0}^4 { a_n \cos^n\phi_i}\f] ({eq:CBT} and ref \cite{MonicaGoga2013} from the manual).
2658 * It contains in its expression not only the dihedral angle \f$\phi\f$
2659 * but also \f[\theta_{i-1}\f] (theta_ante bellow) and \f[\theta_{i}\f] (theta_post bellow)
2660 * --- the adjacent bending angles.
2661 * For more explanations see comments file "restcbt.h". */
2663 compute_factors_cbtdihs(type, forceparams, delta_ante, delta_crnt, delta_post, f_phi_ai,
2664 f_phi_aj, f_phi_ak, f_phi_al, f_theta_ante_ai, f_theta_ante_aj,
2665 f_theta_ante_ak, f_theta_post_aj, f_theta_post_ak, f_theta_post_al, &v);
2668 /* Acumulate the resuts per beads */
2669 for (d = 0; d < DIM; d++)
2671 f_i[d] = f_phi_ai[d] + f_theta_ante_ai[d];
2672 f_j[d] = f_phi_aj[d] + f_theta_ante_aj[d] + f_theta_post_aj[d];
2673 f_k[d] = f_phi_ak[d] + f_theta_ante_ak[d] + f_theta_post_ak[d];
2674 f_l[d] = f_phi_al[d] + f_theta_post_al[d];
2677 /* Compute the potential energy */
2682 /* Updating the forces */
2683 rvec_inc(f[ai], f_i);
2684 rvec_inc(f[aj], f_j);
2685 rvec_inc(f[ak], f_k);
2686 rvec_inc(f[al], f_l);
2689 if (computeVirial(flavor))
2693 t3 = pbc_rvec_sub(pbc, x[al], x[aj], dx_jl);
2700 rvec_inc(fshift[t1], f_i);
2701 rvec_inc(fshift[CENTRAL], f_j);
2702 rvec_inc(fshift[t2], f_k);
2703 rvec_inc(fshift[t3], f_l);
2710 template<BondedKernelFlavor flavor>
2711 std::enable_if_t<flavor != BondedKernelFlavor::ForcesSimdWhenAvailable || !GMX_SIMD_HAVE_REAL, real>
2713 const t_iatom forceatoms[],
2714 const t_iparams forceparams[],
2721 const t_mdatoms gmx_unused* md,
2722 t_fcdata gmx_unused* fcd,
2723 int gmx_unused* global_atom_index)
2725 const real c0 = 0.0, c1 = 1.0, c2 = 2.0, c3 = 3.0, c4 = 4.0, c5 = 5.0;
2726 int type, ai, aj, ak, al, i, j;
2728 rvec r_ij, r_kj, r_kl, m, n;
2729 real parmA[NR_RBDIHS];
2730 real parmB[NR_RBDIHS];
2731 real parm[NR_RBDIHS];
2732 real cos_phi, phi, rbp, rbpBA;
2733 real v, ddphi, sin_phi;
2735 real L1 = 1.0 - lambda;
2739 for (i = 0; (i < nbonds);)
2741 type = forceatoms[i++];
2742 ai = forceatoms[i++];
2743 aj = forceatoms[i++];
2744 ak = forceatoms[i++];
2745 al = forceatoms[i++];
2747 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3); /* 84 */
2749 /* Change to polymer convention */
2756 phi -= M_PI; /* 1 */
2758 cos_phi = std::cos(phi);
2759 /* Beware of accuracy loss, cannot use 1-sqrt(cos^2) ! */
2760 sin_phi = std::sin(phi);
2762 for (j = 0; (j < NR_RBDIHS); j++)
2764 parmA[j] = forceparams[type].rbdihs.rbcA[j];
2765 parmB[j] = forceparams[type].rbdihs.rbcB[j];
2766 parm[j] = L1 * parmA[j] + lambda * parmB[j];
2768 /* Calculate cosine powers */
2769 /* Calculate the energy */
2770 /* Calculate the derivative */
2773 dvdl_term += (parmB[0] - parmA[0]);
2778 rbpBA = parmB[1] - parmA[1];
2779 ddphi += rbp * cosfac;
2782 dvdl_term += cosfac * rbpBA;
2784 rbpBA = parmB[2] - parmA[2];
2785 ddphi += c2 * rbp * cosfac;
2788 dvdl_term += cosfac * rbpBA;
2790 rbpBA = parmB[3] - parmA[3];
2791 ddphi += c3 * rbp * cosfac;
2794 dvdl_term += cosfac * rbpBA;
2796 rbpBA = parmB[4] - parmA[4];
2797 ddphi += c4 * rbp * cosfac;
2800 dvdl_term += cosfac * rbpBA;
2802 rbpBA = parmB[5] - parmA[5];
2803 ddphi += c5 * rbp * cosfac;
2806 dvdl_term += cosfac * rbpBA;
2808 ddphi = -ddphi * sin_phi; /* 11 */
2810 do_dih_fup<flavor>(ai, aj, ak, al, ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1, t2,
2814 *dvdlambda += dvdl_term;
2821 /*! \brief Mysterious undocumented function */
2822 int cmap_setup_grid_index(int ip, int grid_spacing, int* ipm1, int* ipp1, int* ipp2)
2828 ip = ip + grid_spacing - 1;
2830 else if (ip > grid_spacing)
2832 ip = ip - grid_spacing - 1;
2841 im1 = grid_spacing - 1;
2843 else if (ip == grid_spacing - 2)
2847 else if (ip == grid_spacing - 1)
2862 real cmap_dihs(int nbonds,
2863 const t_iatom forceatoms[],
2864 const t_iparams forceparams[],
2865 const gmx_cmap_t* cmap_grid,
2869 const struct t_pbc* pbc,
2870 real gmx_unused lambda,
2871 real gmx_unused* dvdlambda,
2872 const t_mdatoms gmx_unused* md,
2873 t_fcdata gmx_unused* fcd,
2874 int gmx_unused* global_atom_index)
2877 int ai, aj, ak, al, am;
2878 int a1i, a1j, a1k, a1l, a2i, a2j, a2k, a2l;
2880 int t11, t21, t31, t12, t22, t32;
2881 int iphi1, ip1m1, ip1p1, ip1p2;
2882 int iphi2, ip2m1, ip2p1, ip2p2;
2884 int pos1, pos2, pos3, pos4;
2886 real ty[4], ty1[4], ty2[4], ty12[4], tx[16];
2887 real phi1, cos_phi1, sin_phi1, xphi1;
2888 real phi2, cos_phi2, sin_phi2, xphi2;
2889 real dx, tt, tu, e, df1, df2, vtot;
2890 real ra21, rb21, rg21, rg1, rgr1, ra2r1, rb2r1, rabr1;
2891 real ra22, rb22, rg22, rg2, rgr2, ra2r2, rb2r2, rabr2;
2892 real fg1, hg1, fga1, hgb1, gaa1, gbb1;
2893 real fg2, hg2, fga2, hgb2, gaa2, gbb2;
2896 rvec r1_ij, r1_kj, r1_kl, m1, n1;
2897 rvec r2_ij, r2_kj, r2_kl, m2, n2;
2898 rvec f1_i, f1_j, f1_k, f1_l;
2899 rvec f2_i, f2_j, f2_k, f2_l;
2900 rvec a1, b1, a2, b2;
2901 rvec f1, g1, h1, f2, g2, h2;
2902 rvec dtf1, dtg1, dth1, dtf2, dtg2, dth2;
2904 int loop_index[4][4] = { { 0, 4, 8, 12 }, { 1, 5, 9, 13 }, { 2, 6, 10, 14 }, { 3, 7, 11, 15 } };
2906 /* Total CMAP energy */
2909 for (n = 0; n < nbonds;)
2911 /* Five atoms are involved in the two torsions */
2912 type = forceatoms[n++];
2913 ai = forceatoms[n++];
2914 aj = forceatoms[n++];
2915 ak = forceatoms[n++];
2916 al = forceatoms[n++];
2917 am = forceatoms[n++];
2919 /* Which CMAP type is this */
2920 const int cmapA = forceparams[type].cmap.cmapA;
2921 const real* cmapd = cmap_grid->cmapdata[cmapA].cmap.data();
2929 phi1 = dih_angle(x[a1i], x[a1j], x[a1k], x[a1l], pbc, r1_ij, r1_kj, r1_kl, m1, n1, &t11,
2930 &t21, &t31); /* 84 */
2932 cos_phi1 = std::cos(phi1);
2934 a1[0] = r1_ij[1] * r1_kj[2] - r1_ij[2] * r1_kj[1];
2935 a1[1] = r1_ij[2] * r1_kj[0] - r1_ij[0] * r1_kj[2];
2936 a1[2] = r1_ij[0] * r1_kj[1] - r1_ij[1] * r1_kj[0]; /* 9 */
2938 b1[0] = r1_kl[1] * r1_kj[2] - r1_kl[2] * r1_kj[1];
2939 b1[1] = r1_kl[2] * r1_kj[0] - r1_kl[0] * r1_kj[2];
2940 b1[2] = r1_kl[0] * r1_kj[1] - r1_kl[1] * r1_kj[0]; /* 9 */
2942 pbc_rvec_sub(pbc, x[a1l], x[a1k], h1);
2944 ra21 = iprod(a1, a1); /* 5 */
2945 rb21 = iprod(b1, b1); /* 5 */
2946 rg21 = iprod(r1_kj, r1_kj); /* 5 */
2952 rabr1 = sqrt(ra2r1 * rb2r1);
2954 sin_phi1 = rg1 * rabr1 * iprod(a1, h1) * (-1);
2956 if (cos_phi1 < -0.5 || cos_phi1 > 0.5)
2958 phi1 = std::asin(sin_phi1);
2968 phi1 = -M_PI - phi1;
2974 phi1 = std::acos(cos_phi1);
2982 xphi1 = phi1 + M_PI; /* 1 */
2984 /* Second torsion */
2990 phi2 = dih_angle(x[a2i], x[a2j], x[a2k], x[a2l], pbc, r2_ij, r2_kj, r2_kl, m2, n2, &t12,
2991 &t22, &t32); /* 84 */
2993 cos_phi2 = std::cos(phi2);
2995 a2[0] = r2_ij[1] * r2_kj[2] - r2_ij[2] * r2_kj[1];
2996 a2[1] = r2_ij[2] * r2_kj[0] - r2_ij[0] * r2_kj[2];
2997 a2[2] = r2_ij[0] * r2_kj[1] - r2_ij[1] * r2_kj[0]; /* 9 */
2999 b2[0] = r2_kl[1] * r2_kj[2] - r2_kl[2] * r2_kj[1];
3000 b2[1] = r2_kl[2] * r2_kj[0] - r2_kl[0] * r2_kj[2];
3001 b2[2] = r2_kl[0] * r2_kj[1] - r2_kl[1] * r2_kj[0]; /* 9 */
3003 pbc_rvec_sub(pbc, x[a2l], x[a2k], h2);
3005 ra22 = iprod(a2, a2); /* 5 */
3006 rb22 = iprod(b2, b2); /* 5 */
3007 rg22 = iprod(r2_kj, r2_kj); /* 5 */
3013 rabr2 = sqrt(ra2r2 * rb2r2);
3015 sin_phi2 = rg2 * rabr2 * iprod(a2, h2) * (-1);
3017 if (cos_phi2 < -0.5 || cos_phi2 > 0.5)
3019 phi2 = std::asin(sin_phi2);
3029 phi2 = -M_PI - phi2;
3035 phi2 = std::acos(cos_phi2);
3043 xphi2 = phi2 + M_PI; /* 1 */
3045 /* Range mangling */
3048 xphi1 = xphi1 + 2 * M_PI;
3050 else if (xphi1 >= 2 * M_PI)
3052 xphi1 = xphi1 - 2 * M_PI;
3057 xphi2 = xphi2 + 2 * M_PI;
3059 else if (xphi2 >= 2 * M_PI)
3061 xphi2 = xphi2 - 2 * M_PI;
3064 /* Number of grid points */
3065 dx = 2 * M_PI / cmap_grid->grid_spacing;
3067 /* Where on the grid are we */
3068 iphi1 = static_cast<int>(xphi1 / dx);
3069 iphi2 = static_cast<int>(xphi2 / dx);
3071 iphi1 = cmap_setup_grid_index(iphi1, cmap_grid->grid_spacing, &ip1m1, &ip1p1, &ip1p2);
3072 iphi2 = cmap_setup_grid_index(iphi2, cmap_grid->grid_spacing, &ip2m1, &ip2p1, &ip2p2);
3074 pos1 = iphi1 * cmap_grid->grid_spacing + iphi2;
3075 pos2 = ip1p1 * cmap_grid->grid_spacing + iphi2;
3076 pos3 = ip1p1 * cmap_grid->grid_spacing + ip2p1;
3077 pos4 = iphi1 * cmap_grid->grid_spacing + ip2p1;
3079 ty[0] = cmapd[pos1 * 4];
3080 ty[1] = cmapd[pos2 * 4];
3081 ty[2] = cmapd[pos3 * 4];
3082 ty[3] = cmapd[pos4 * 4];
3084 ty1[0] = cmapd[pos1 * 4 + 1];
3085 ty1[1] = cmapd[pos2 * 4 + 1];
3086 ty1[2] = cmapd[pos3 * 4 + 1];
3087 ty1[3] = cmapd[pos4 * 4 + 1];
3089 ty2[0] = cmapd[pos1 * 4 + 2];
3090 ty2[1] = cmapd[pos2 * 4 + 2];
3091 ty2[2] = cmapd[pos3 * 4 + 2];
3092 ty2[3] = cmapd[pos4 * 4 + 2];
3094 ty12[0] = cmapd[pos1 * 4 + 3];
3095 ty12[1] = cmapd[pos2 * 4 + 3];
3096 ty12[2] = cmapd[pos3 * 4 + 3];
3097 ty12[3] = cmapd[pos4 * 4 + 3];
3099 /* Switch to degrees */
3100 dx = 360.0 / cmap_grid->grid_spacing;
3101 xphi1 = xphi1 * RAD2DEG;
3102 xphi2 = xphi2 * RAD2DEG;
3104 for (i = 0; i < 4; i++) /* 16 */
3107 tx[i + 4] = ty1[i] * dx;
3108 tx[i + 8] = ty2[i] * dx;
3109 tx[i + 12] = ty12[i] * dx * dx;
3112 real tc[16] = { 0 };
3113 for (int idx = 0; idx < 16; idx++) /* 1056 */
3115 for (int k = 0; k < 16; k++)
3117 tc[idx] += cmap_coeff_matrix[k * 16 + idx] * tx[k];
3121 tt = (xphi1 - iphi1 * dx) / dx;
3122 tu = (xphi2 - iphi2 * dx) / dx;
3128 for (i = 3; i >= 0; i--)
3130 l1 = loop_index[i][3];
3131 l2 = loop_index[i][2];
3132 l3 = loop_index[i][1];
3134 e = tt * e + ((tc[i * 4 + 3] * tu + tc[i * 4 + 2]) * tu + tc[i * 4 + 1]) * tu + tc[i * 4];
3135 df1 = tu * df1 + (3.0 * tc[l1] * tt + 2.0 * tc[l2]) * tt + tc[l3];
3136 df2 = tt * df2 + (3.0 * tc[i * 4 + 3] * tu + 2.0 * tc[i * 4 + 2]) * tu + tc[i * 4 + 1];
3146 /* Do forces - first torsion */
3147 fg1 = iprod(r1_ij, r1_kj);
3148 hg1 = iprod(r1_kl, r1_kj);
3149 fga1 = fg1 * ra2r1 * rgr1;
3150 hgb1 = hg1 * rb2r1 * rgr1;
3151 gaa1 = -ra2r1 * rg1;
3154 for (i = 0; i < DIM; i++)
3156 dtf1[i] = gaa1 * a1[i];
3157 dtg1[i] = fga1 * a1[i] - hgb1 * b1[i];
3158 dth1[i] = gbb1 * b1[i];
3160 f1[i] = df1 * dtf1[i];
3161 g1[i] = df1 * dtg1[i];
3162 h1[i] = df1 * dth1[i];
3165 f1_j[i] = -f1[i] - g1[i];
3166 f1_k[i] = h1[i] + g1[i];
3169 f[a1i][i] = f[a1i][i] + f1_i[i];
3170 f[a1j][i] = f[a1j][i] + f1_j[i]; /* - f1[i] - g1[i] */
3171 f[a1k][i] = f[a1k][i] + f1_k[i]; /* h1[i] + g1[i] */
3172 f[a1l][i] = f[a1l][i] + f1_l[i]; /* h1[i] */
3175 /* Do forces - second torsion */
3176 fg2 = iprod(r2_ij, r2_kj);
3177 hg2 = iprod(r2_kl, r2_kj);
3178 fga2 = fg2 * ra2r2 * rgr2;
3179 hgb2 = hg2 * rb2r2 * rgr2;
3180 gaa2 = -ra2r2 * rg2;
3183 for (i = 0; i < DIM; i++)
3185 dtf2[i] = gaa2 * a2[i];
3186 dtg2[i] = fga2 * a2[i] - hgb2 * b2[i];
3187 dth2[i] = gbb2 * b2[i];
3189 f2[i] = df2 * dtf2[i];
3190 g2[i] = df2 * dtg2[i];
3191 h2[i] = df2 * dth2[i];
3194 f2_j[i] = -f2[i] - g2[i];
3195 f2_k[i] = h2[i] + g2[i];
3198 f[a2i][i] = f[a2i][i] + f2_i[i]; /* f2[i] */
3199 f[a2j][i] = f[a2j][i] + f2_j[i]; /* - f2[i] - g2[i] */
3200 f[a2k][i] = f[a2k][i] + f2_k[i]; /* h2[i] + g2[i] */
3201 f[a2l][i] = f[a2l][i] + f2_l[i]; /* - h2[i] */
3205 if (fshift != nullptr)
3209 t31 = pbc_rvec_sub(pbc, x[a1l], x[a1j], h1);
3210 t32 = pbc_rvec_sub(pbc, x[a2l], x[a2j], h2);
3218 rvec_inc(fshift[t11], f1_i);
3219 rvec_inc(fshift[CENTRAL], f1_j);
3220 rvec_inc(fshift[t21], f1_k);
3221 rvec_inc(fshift[t31], f1_l);
3223 rvec_inc(fshift[t12], f2_i);
3224 rvec_inc(fshift[CENTRAL], f2_j);
3225 rvec_inc(fshift[t22], f2_k);
3226 rvec_inc(fshift[t32], f2_l);
3236 /***********************************************************
3238 * G R O M O S 9 6 F U N C T I O N S
3240 ***********************************************************/
3241 real g96harmonic(real kA, real kB, real xA, real xB, real x, real lambda, real* V, real* F)
3243 const real half = 0.5;
3244 real L1, kk, x0, dx, dx2;
3245 real v, f, dvdlambda;
3248 kk = L1 * kA + lambda * kB;
3249 x0 = L1 * xA + lambda * xB;
3255 v = half * kk * dx2;
3256 dvdlambda = half * (kB - kA) * dx2 + (xA - xB) * kk * dx;
3263 /* That was 21 flops */
3266 template<BondedKernelFlavor flavor>
3267 real g96bonds(int nbonds,
3268 const t_iatom forceatoms[],
3269 const t_iparams forceparams[],
3276 const t_mdatoms gmx_unused* md,
3277 t_fcdata gmx_unused* fcd,
3278 int gmx_unused* global_atom_index)
3280 int i, ki, ai, aj, type;
3281 real dr2, fbond, vbond, vtot;
3285 for (i = 0; (i < nbonds);)
3287 type = forceatoms[i++];
3288 ai = forceatoms[i++];
3289 aj = forceatoms[i++];
3291 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
3292 dr2 = iprod(dx, dx); /* 5 */
3294 *dvdlambda += g96harmonic(forceparams[type].harmonic.krA, forceparams[type].harmonic.krB,
3295 forceparams[type].harmonic.rA, forceparams[type].harmonic.rB, dr2,
3296 lambda, &vbond, &fbond);
3298 vtot += 0.5 * vbond; /* 1*/
3300 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
3305 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)
3306 /* Return value is the angle between the bonds i-j and j-k */
3310 *t1 = pbc_rvec_sub(pbc, xi, xj, r_ij); /* 3 */
3311 *t2 = pbc_rvec_sub(pbc, xk, xj, r_kj); /* 3 */
3313 costh = cos_angle(r_ij, r_kj); /* 25 */
3318 template<BondedKernelFlavor flavor>
3319 real g96angles(int nbonds,
3320 const t_iatom forceatoms[],
3321 const t_iparams forceparams[],
3328 const t_mdatoms gmx_unused* md,
3329 t_fcdata gmx_unused* fcd,
3330 int gmx_unused* global_atom_index)
3332 int i, ai, aj, ak, type, m, t1, t2;
3334 real cos_theta, dVdt, va, vtot;
3335 real rij_1, rij_2, rkj_1, rkj_2, rijrkj_1;
3339 for (i = 0; (i < nbonds);)
3341 type = forceatoms[i++];
3342 ai = forceatoms[i++];
3343 aj = forceatoms[i++];
3344 ak = forceatoms[i++];
3346 cos_theta = g96bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &t1, &t2);
3348 *dvdlambda += g96harmonic(forceparams[type].harmonic.krA, forceparams[type].harmonic.krB,
3349 forceparams[type].harmonic.rA, forceparams[type].harmonic.rB,
3350 cos_theta, lambda, &va, &dVdt);
3353 rij_1 = gmx::invsqrt(iprod(r_ij, r_ij));
3354 rkj_1 = gmx::invsqrt(iprod(r_kj, r_kj));
3355 rij_2 = rij_1 * rij_1;
3356 rkj_2 = rkj_1 * rkj_1;
3357 rijrkj_1 = rij_1 * rkj_1; /* 23 */
3359 for (m = 0; (m < DIM); m++) /* 42 */
3361 f_i[m] = dVdt * (r_kj[m] * rijrkj_1 - r_ij[m] * rij_2 * cos_theta);
3362 f_k[m] = dVdt * (r_ij[m] * rijrkj_1 - r_kj[m] * rkj_2 * cos_theta);
3363 f_j[m] = -f_i[m] - f_k[m];
3369 if (computeVirial(flavor))
3371 rvec_inc(fshift[t1], f_i);
3372 rvec_inc(fshift[CENTRAL], f_j);
3373 rvec_inc(fshift[t2], f_k); /* 9 */
3380 template<BondedKernelFlavor flavor>
3381 real cross_bond_bond(int nbonds,
3382 const t_iatom forceatoms[],
3383 const t_iparams forceparams[],
3388 real gmx_unused lambda,
3389 real gmx_unused* dvdlambda,
3390 const t_mdatoms gmx_unused* md,
3391 t_fcdata gmx_unused* fcd,
3392 int gmx_unused* global_atom_index)
3394 /* Potential from Lawrence and Skimmer, Chem. Phys. Lett. 372 (2003)
3397 int i, ai, aj, ak, type, m, t1, t2;
3399 real vtot, vrr, s1, s2, r1, r2, r1e, r2e, krr;
3403 for (i = 0; (i < nbonds);)
3405 type = forceatoms[i++];
3406 ai = forceatoms[i++];
3407 aj = forceatoms[i++];
3408 ak = forceatoms[i++];
3409 r1e = forceparams[type].cross_bb.r1e;
3410 r2e = forceparams[type].cross_bb.r2e;
3411 krr = forceparams[type].cross_bb.krr;
3413 /* Compute distance vectors ... */
3414 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], r_ij);
3415 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], r_kj);
3417 /* ... and their lengths */
3421 /* Deviations from ideality */
3425 /* Energy (can be negative!) */
3426 vrr = krr * s1 * s2;
3430 svmul(-krr * s2 / r1, r_ij, f_i);
3431 svmul(-krr * s1 / r2, r_kj, f_k);
3433 for (m = 0; (m < DIM); m++) /* 12 */
3435 f_j[m] = -f_i[m] - f_k[m];
3441 if (computeVirial(flavor))
3443 rvec_inc(fshift[t1], f_i);
3444 rvec_inc(fshift[CENTRAL], f_j);
3445 rvec_inc(fshift[t2], f_k); /* 9 */
3452 template<BondedKernelFlavor flavor>
3453 real cross_bond_angle(int nbonds,
3454 const t_iatom forceatoms[],
3455 const t_iparams forceparams[],
3460 real gmx_unused lambda,
3461 real gmx_unused* dvdlambda,
3462 const t_mdatoms gmx_unused* md,
3463 t_fcdata gmx_unused* fcd,
3464 int gmx_unused* global_atom_index)
3466 /* Potential from Lawrence and Skimmer, Chem. Phys. Lett. 372 (2003)
3469 int i, ai, aj, ak, type, m, t1, t2;
3470 rvec r_ij, r_kj, r_ik;
3471 real vtot, vrt, s1, s2, s3, r1, r2, r3, r1e, r2e, r3e, krt, k1, k2, k3;
3475 for (i = 0; (i < nbonds);)
3477 type = forceatoms[i++];
3478 ai = forceatoms[i++];
3479 aj = forceatoms[i++];
3480 ak = forceatoms[i++];
3481 r1e = forceparams[type].cross_ba.r1e;
3482 r2e = forceparams[type].cross_ba.r2e;
3483 r3e = forceparams[type].cross_ba.r3e;
3484 krt = forceparams[type].cross_ba.krt;
3486 /* Compute distance vectors ... */
3487 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], r_ij);
3488 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], r_kj);
3489 pbc_rvec_sub(pbc, x[ai], x[ak], r_ik);
3491 /* ... and their lengths */
3496 /* Deviations from ideality */
3501 /* Energy (can be negative!) */
3502 vrt = krt * s3 * (s1 + s2);
3506 k1 = -krt * (s3 / r1);
3507 k2 = -krt * (s3 / r2);
3508 k3 = -krt * (s1 + s2) / r3;
3509 for (m = 0; (m < DIM); m++)
3511 f_i[m] = k1 * r_ij[m] + k3 * r_ik[m];
3512 f_k[m] = k2 * r_kj[m] - k3 * r_ik[m];
3513 f_j[m] = -f_i[m] - f_k[m];
3516 for (m = 0; (m < DIM); m++) /* 12 */
3523 if (computeVirial(flavor))
3525 rvec_inc(fshift[t1], f_i);
3526 rvec_inc(fshift[CENTRAL], f_j);
3527 rvec_inc(fshift[t2], f_k); /* 9 */
3534 /*! \brief Computes the potential and force for a tabulated potential */
3535 real bonded_tab(const char* type,
3537 const bondedtable_t* table,
3545 real k, tabscale, *VFtab, rt, eps, eps2, Yt, Ft, Geps, Heps2, Fp, VV, FF;
3549 k = (1.0 - lambda) * kA + lambda * kB;
3551 tabscale = table->scale;
3552 VFtab = table->data;
3555 n0 = static_cast<int>(rt);
3559 "A tabulated %s interaction table number %d is out of the table range: r %f, "
3560 "between table indices %d and %d, table length %d",
3561 type, table_nr, r, n0, n0 + 1, table->n);
3567 Ft = VFtab[nnn + 1];
3568 Geps = VFtab[nnn + 2] * eps;
3569 Heps2 = VFtab[nnn + 3] * eps2;
3570 Fp = Ft + Geps + Heps2;
3572 FF = Fp + Geps + 2.0 * Heps2;
3574 *F = -k * FF * tabscale;
3576 dvdlambda = (kB - kA) * VV;
3580 /* That was 22 flops */
3583 template<BondedKernelFlavor flavor>
3584 real tab_bonds(int nbonds,
3585 const t_iatom forceatoms[],
3586 const t_iparams forceparams[],
3593 const t_mdatoms gmx_unused* md,
3595 int gmx_unused* global_atom_index)
3597 int i, ki, ai, aj, type, table;
3598 real dr, dr2, fbond, vbond, vtot;
3602 for (i = 0; (i < nbonds);)
3604 type = forceatoms[i++];
3605 ai = forceatoms[i++];
3606 aj = forceatoms[i++];
3608 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
3609 dr2 = iprod(dx, dx); /* 5 */
3610 dr = dr2 * gmx::invsqrt(dr2); /* 10 */
3612 table = forceparams[type].tab.table;
3614 *dvdlambda += bonded_tab("bond", table, &fcd->bondtab[table], forceparams[type].tab.kA,
3615 forceparams[type].tab.kB, dr, lambda, &vbond, &fbond); /* 22 */
3623 vtot += vbond; /* 1*/
3624 fbond *= gmx::invsqrt(dr2); /* 6 */
3626 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
3631 template<BondedKernelFlavor flavor>
3632 real tab_angles(int nbonds,
3633 const t_iatom forceatoms[],
3634 const t_iparams forceparams[],
3641 const t_mdatoms gmx_unused* md,
3643 int gmx_unused* global_atom_index)
3645 int i, ai, aj, ak, t1, t2, type, table;
3647 real cos_theta, cos_theta2, theta, dVdt, va, vtot;
3650 for (i = 0; (i < nbonds);)
3652 type = forceatoms[i++];
3653 ai = forceatoms[i++];
3654 aj = forceatoms[i++];
3655 ak = forceatoms[i++];
3657 theta = bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
3659 table = forceparams[type].tab.table;
3661 *dvdlambda += bonded_tab("angle", table, &fcd->angletab[table], forceparams[type].tab.kA,
3662 forceparams[type].tab.kB, theta, lambda, &va, &dVdt); /* 22 */
3665 cos_theta2 = gmx::square(cos_theta); /* 1 */
3674 st = dVdt * gmx::invsqrt(1 - cos_theta2); /* 12 */
3675 sth = st * cos_theta; /* 1 */
3676 nrkj2 = iprod(r_kj, r_kj); /* 5 */
3677 nrij2 = iprod(r_ij, r_ij);
3679 cik = st * gmx::invsqrt(nrkj2 * nrij2); /* 12 */
3680 cii = sth / nrij2; /* 10 */
3681 ckk = sth / nrkj2; /* 10 */
3683 for (m = 0; (m < DIM); m++) /* 39 */
3685 f_i[m] = -(cik * r_kj[m] - cii * r_ij[m]);
3686 f_k[m] = -(cik * r_ij[m] - ckk * r_kj[m]);
3687 f_j[m] = -f_i[m] - f_k[m];
3693 if (computeVirial(flavor))
3695 rvec_inc(fshift[t1], f_i);
3696 rvec_inc(fshift[CENTRAL], f_j);
3697 rvec_inc(fshift[t2], f_k);
3704 template<BondedKernelFlavor flavor>
3705 real tab_dihs(int nbonds,
3706 const t_iatom forceatoms[],
3707 const t_iparams forceparams[],
3714 const t_mdatoms gmx_unused* md,
3716 int gmx_unused* global_atom_index)
3718 int i, type, ai, aj, ak, al, table;
3720 rvec r_ij, r_kj, r_kl, m, n;
3721 real phi, ddphi, vpd, vtot;
3724 for (i = 0; (i < nbonds);)
3726 type = forceatoms[i++];
3727 ai = forceatoms[i++];
3728 aj = forceatoms[i++];
3729 ak = forceatoms[i++];
3730 al = forceatoms[i++];
3732 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3); /* 84 */
3734 table = forceparams[type].tab.table;
3736 /* Hopefully phi+M_PI never results in values < 0 */
3737 *dvdlambda += bonded_tab("dihedral", table, &fcd->dihtab[table], forceparams[type].tab.kA,
3738 forceparams[type].tab.kB, phi + M_PI, lambda, &vpd, &ddphi);
3741 do_dih_fup<flavor>(ai, aj, ak, al, -ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1,
3749 struct BondedInteractions
3751 BondedFunction function;
3755 // Bug in old clang versions prevents constexpr. constexpr is needed for MSVC.
3756 #if defined(__clang__) && __clang_major__ < 6
3757 # define CONSTEXPR_EXCL_OLD_CLANG const
3759 # define CONSTEXPR_EXCL_OLD_CLANG constexpr
3762 /*! \brief Lookup table of bonded interaction functions
3764 * This must have as many entries as interaction_function in ifunc.cpp */
3765 template<BondedKernelFlavor flavor>
3766 CONSTEXPR_EXCL_OLD_CLANG std::array<BondedInteractions, F_NRE> c_bondedInteractionFunctions = {
3767 BondedInteractions{ bonds<flavor>, eNR_BONDS }, // F_BONDS
3768 BondedInteractions{ g96bonds<flavor>, eNR_BONDS }, // F_G96BONDS
3769 BondedInteractions{ morse_bonds<flavor>, eNR_MORSE }, // F_MORSE
3770 BondedInteractions{ cubic_bonds<flavor>, eNR_CUBICBONDS }, // F_CUBICBONDS
3771 BondedInteractions{ unimplemented, -1 }, // F_CONNBONDS
3772 BondedInteractions{ bonds<flavor>, eNR_BONDS }, // F_HARMONIC
3773 BondedInteractions{ FENE_bonds<flavor>, eNR_FENEBONDS }, // F_FENEBONDS
3774 BondedInteractions{ tab_bonds<flavor>, eNR_TABBONDS }, // F_TABBONDS
3775 BondedInteractions{ tab_bonds<flavor>, eNR_TABBONDS }, // F_TABBONDSNC
3776 BondedInteractions{ restraint_bonds<flavor>, eNR_RESTRBONDS }, // F_RESTRBONDS
3777 BondedInteractions{ angles<flavor>, eNR_ANGLES }, // F_ANGLES
3778 BondedInteractions{ g96angles<flavor>, eNR_ANGLES }, // F_G96ANGLES
3779 BondedInteractions{ restrangles<flavor>, eNR_ANGLES }, // F_RESTRANGLES
3780 BondedInteractions{ linear_angles<flavor>, eNR_ANGLES }, // F_LINEAR_ANGLES
3781 BondedInteractions{ cross_bond_bond<flavor>, eNR_CROSS_BOND_BOND }, // F_CROSS_BOND_BONDS
3782 BondedInteractions{ cross_bond_angle<flavor>, eNR_CROSS_BOND_ANGLE }, // F_CROSS_BOND_ANGLES
3783 BondedInteractions{ urey_bradley<flavor>, eNR_UREY_BRADLEY }, // F_UREY_BRADLEY
3784 BondedInteractions{ quartic_angles<flavor>, eNR_QANGLES }, // F_QUARTIC_ANGLES
3785 BondedInteractions{ tab_angles<flavor>, eNR_TABANGLES }, // F_TABANGLES
3786 BondedInteractions{ pdihs<flavor>, eNR_PROPER }, // F_PDIHS
3787 BondedInteractions{ rbdihs<flavor>, eNR_RB }, // F_RBDIHS
3788 BondedInteractions{ restrdihs<flavor>, eNR_PROPER }, // F_RESTRDIHS
3789 BondedInteractions{ cbtdihs<flavor>, eNR_RB }, // F_CBTDIHS
3790 BondedInteractions{ rbdihs<flavor>, eNR_FOURDIH }, // F_FOURDIHS
3791 BondedInteractions{ idihs<flavor>, eNR_IMPROPER }, // F_IDIHS
3792 BondedInteractions{ pdihs<flavor>, eNR_IMPROPER }, // F_PIDIHS
3793 BondedInteractions{ tab_dihs<flavor>, eNR_TABDIHS }, // F_TABDIHS
3794 BondedInteractions{ unimplemented, eNR_CMAP }, // F_CMAP
3795 BondedInteractions{ unimplemented, -1 }, // F_GB12_NOLONGERUSED
3796 BondedInteractions{ unimplemented, -1 }, // F_GB13_NOLONGERUSED
3797 BondedInteractions{ unimplemented, -1 }, // F_GB14_NOLONGERUSED
3798 BondedInteractions{ unimplemented, -1 }, // F_GBPOL_NOLONGERUSED
3799 BondedInteractions{ unimplemented, -1 }, // F_NPSOLVATION_NOLONGERUSED
3800 BondedInteractions{ unimplemented, eNR_NB14 }, // F_LJ14
3801 BondedInteractions{ unimplemented, -1 }, // F_COUL14
3802 BondedInteractions{ unimplemented, eNR_NB14 }, // F_LJC14_Q
3803 BondedInteractions{ unimplemented, eNR_NB14 }, // F_LJC_PAIRS_NB
3804 BondedInteractions{ unimplemented, -1 }, // F_LJ
3805 BondedInteractions{ unimplemented, -1 }, // F_BHAM
3806 BondedInteractions{ unimplemented, -1 }, // F_LJ_LR_NOLONGERUSED
3807 BondedInteractions{ unimplemented, -1 }, // F_BHAM_LR_NOLONGERUSED
3808 BondedInteractions{ unimplemented, -1 }, // F_DISPCORR
3809 BondedInteractions{ unimplemented, -1 }, // F_COUL_SR
3810 BondedInteractions{ unimplemented, -1 }, // F_COUL_LR_NOLONGERUSED
3811 BondedInteractions{ unimplemented, -1 }, // F_RF_EXCL
3812 BondedInteractions{ unimplemented, -1 }, // F_COUL_RECIP
3813 BondedInteractions{ unimplemented, -1 }, // F_LJ_RECIP
3814 BondedInteractions{ unimplemented, -1 }, // F_DPD
3815 BondedInteractions{ polarize<flavor>, eNR_POLARIZE }, // F_POLARIZATION
3816 BondedInteractions{ water_pol<flavor>, eNR_WPOL }, // F_WATER_POL
3817 BondedInteractions{ thole_pol<flavor>, eNR_THOLE }, // F_THOLE_POL
3818 BondedInteractions{ anharm_polarize<flavor>, eNR_ANHARM_POL }, // F_ANHARM_POL
3819 BondedInteractions{ unimplemented, -1 }, // F_POSRES
3820 BondedInteractions{ unimplemented, -1 }, // F_FBPOSRES
3821 BondedInteractions{ ta_disres, eNR_DISRES }, // F_DISRES
3822 BondedInteractions{ unimplemented, -1 }, // F_DISRESVIOL
3823 BondedInteractions{ orires, eNR_ORIRES }, // F_ORIRES
3824 BondedInteractions{ unimplemented, -1 }, // F_ORIRESDEV
3825 BondedInteractions{ angres<flavor>, eNR_ANGRES }, // F_ANGRES
3826 BondedInteractions{ angresz<flavor>, eNR_ANGRESZ }, // F_ANGRESZ
3827 BondedInteractions{ dihres<flavor>, eNR_DIHRES }, // F_DIHRES
3828 BondedInteractions{ unimplemented, -1 }, // F_DIHRESVIOL
3829 BondedInteractions{ unimplemented, -1 }, // F_CONSTR
3830 BondedInteractions{ unimplemented, -1 }, // F_CONSTRNC
3831 BondedInteractions{ unimplemented, -1 }, // F_SETTLE
3832 BondedInteractions{ unimplemented, -1 }, // F_VSITE2
3833 BondedInteractions{ unimplemented, -1 }, // F_VSITE3
3834 BondedInteractions{ unimplemented, -1 }, // F_VSITE3FD
3835 BondedInteractions{ unimplemented, -1 }, // F_VSITE3FAD
3836 BondedInteractions{ unimplemented, -1 }, // F_VSITE3OUT
3837 BondedInteractions{ unimplemented, -1 }, // F_VSITE4FD
3838 BondedInteractions{ unimplemented, -1 }, // F_VSITE4FDN
3839 BondedInteractions{ unimplemented, -1 }, // F_VSITEN
3840 BondedInteractions{ unimplemented, -1 }, // F_COM_PULL
3841 BondedInteractions{ unimplemented, -1 }, // F_DENSITYFITTING
3842 BondedInteractions{ unimplemented, -1 }, // F_EQM
3843 BondedInteractions{ unimplemented, -1 }, // F_EPOT
3844 BondedInteractions{ unimplemented, -1 }, // F_EKIN
3845 BondedInteractions{ unimplemented, -1 }, // F_ETOT
3846 BondedInteractions{ unimplemented, -1 }, // F_ECONSERVED
3847 BondedInteractions{ unimplemented, -1 }, // F_TEMP
3848 BondedInteractions{ unimplemented, -1 }, // F_VTEMP_NOLONGERUSED
3849 BondedInteractions{ unimplemented, -1 }, // F_PDISPCORR
3850 BondedInteractions{ unimplemented, -1 }, // F_PRES
3851 BondedInteractions{ unimplemented, -1 }, // F_DVDL_CONSTR
3852 BondedInteractions{ unimplemented, -1 }, // F_DVDL
3853 BondedInteractions{ unimplemented, -1 }, // F_DKDL
3854 BondedInteractions{ unimplemented, -1 }, // F_DVDL_COUL
3855 BondedInteractions{ unimplemented, -1 }, // F_DVDL_VDW
3856 BondedInteractions{ unimplemented, -1 }, // F_DVDL_BONDED
3857 BondedInteractions{ unimplemented, -1 }, // F_DVDL_RESTRAINT
3858 BondedInteractions{ unimplemented, -1 }, // F_DVDL_TEMPERATURE
3861 /*! \brief List of instantiated BondedInteractions list */
3862 CONSTEXPR_EXCL_OLD_CLANG
3863 gmx::EnumerationArray<BondedKernelFlavor, std::array<BondedInteractions, F_NRE>> c_bondedInteractionFunctionsPerFlavor = {
3864 c_bondedInteractionFunctions<BondedKernelFlavor::ForcesSimdWhenAvailable>,
3865 c_bondedInteractionFunctions<BondedKernelFlavor::ForcesNoSimd>,
3866 c_bondedInteractionFunctions<BondedKernelFlavor::ForcesAndVirialAndEnergy>,
3867 c_bondedInteractionFunctions<BondedKernelFlavor::ForcesAndEnergy>
3874 real calculateSimpleBond(const int ftype,
3875 const int numForceatoms,
3876 const t_iatom forceatoms[],
3877 const t_iparams forceparams[],
3881 const struct t_pbc* pbc,
3884 const t_mdatoms* md,
3886 int gmx_unused* global_atom_index,
3887 const BondedKernelFlavor bondedKernelFlavor)
3889 const BondedInteractions& bonded = c_bondedInteractionFunctionsPerFlavor[bondedKernelFlavor][ftype];
3891 real v = bonded.function(numForceatoms, forceatoms, forceparams, x, f, fshift, pbc, lambda,
3892 dvdlambda, md, fcd, global_atom_index);
3897 int nrnbIndex(int ftype)
3899 return c_bondedInteractionFunctions<BondedKernelFlavor::ForcesAndVirialAndEnergy>[ftype].nrnbIndex;