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;
1002 SimdReal st_S, sth_S;
1003 SimdReal cik_S, cii_S, ckk_S;
1004 SimdReal f_ix_S, f_iy_S, f_iz_S;
1005 SimdReal f_kx_S, f_ky_S, f_kz_S;
1006 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9 * GMX_SIMD_REAL_WIDTH];
1008 set_pbc_simd(pbc, pbc_simd);
1010 /* nbonds is the number of angles times nfa1, here we step GMX_SIMD_REAL_WIDTH angles */
1011 for (i = 0; (i < nbonds); i += GMX_SIMD_REAL_WIDTH * nfa1)
1013 /* Collect atoms for GMX_SIMD_REAL_WIDTH angles.
1014 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
1017 for (s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
1019 type = forceatoms[iu];
1020 ai[s] = forceatoms[iu + 1];
1021 aj[s] = forceatoms[iu + 2];
1022 ak[s] = forceatoms[iu + 3];
1024 /* At the end fill the arrays with the last atoms and 0 params */
1025 if (i + s * nfa1 < nbonds)
1027 coeff[s] = forceparams[type].harmonic.krA;
1028 coeff[GMX_SIMD_REAL_WIDTH + s] = forceparams[type].harmonic.rA;
1030 if (iu + nfa1 < nbonds)
1038 coeff[GMX_SIMD_REAL_WIDTH + s] = 0;
1042 /* Store the non PBC corrected distances packed and aligned */
1043 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ai, &xi_S, &yi_S, &zi_S);
1044 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), aj, &xj_S, &yj_S, &zj_S);
1045 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ak, &xk_S, &yk_S, &zk_S);
1046 rijx_S = xi_S - xj_S;
1047 rijy_S = yi_S - yj_S;
1048 rijz_S = zi_S - zj_S;
1049 rkjx_S = xk_S - xj_S;
1050 rkjy_S = yk_S - yj_S;
1051 rkjz_S = zk_S - zj_S;
1053 k_S = load<SimdReal>(coeff);
1054 theta0_S = load<SimdReal>(coeff + GMX_SIMD_REAL_WIDTH) * deg2rad_S;
1056 pbc_correct_dx_simd(&rijx_S, &rijy_S, &rijz_S, pbc_simd);
1057 pbc_correct_dx_simd(&rkjx_S, &rkjy_S, &rkjz_S, pbc_simd);
1059 rij_rkj_S = iprod(rijx_S, rijy_S, rijz_S, rkjx_S, rkjy_S, rkjz_S);
1061 nrij2_S = norm2(rijx_S, rijy_S, rijz_S);
1062 nrkj2_S = norm2(rkjx_S, rkjy_S, rkjz_S);
1064 nrij_1_S = invsqrt(nrij2_S);
1065 nrkj_1_S = invsqrt(nrkj2_S);
1067 cos_S = rij_rkj_S * nrij_1_S * nrkj_1_S;
1069 /* We compute cos^2 using a division instead of squaring cos_S,
1070 * as we would then get additional error contributions from
1071 * the two invsqrt operations, which get amplified by
1072 * the 1/sqrt(1-cos^2) for cos values close to 1.
1074 * Note that the non-SIMD version of angles() avoids this issue
1075 * by computing the cosine using double precision.
1077 cos2_S = rij_rkj_S * rij_rkj_S / (nrij2_S * nrkj2_S);
1079 /* To allow for 180 degrees, we take the max of cos and -1 + 1bit,
1080 * so we can safely get the 1/sin from 1/sqrt(1 - cos^2).
1081 * This also ensures that rounding errors would cause the argument
1082 * of simdAcos to be < -1.
1083 * Note that we do not take precautions for cos(0)=1, so the outer
1084 * atoms in an angle should not be on top of each other.
1086 cos_S = max(cos_S, min_one_plus_eps_S);
1088 theta_S = acos(cos_S);
1090 invsin_S = invsqrt(one_S - cos2_S);
1092 st_S = k_S * (theta0_S - theta_S) * invsin_S;
1093 sth_S = st_S * cos_S;
1095 cik_S = st_S * nrij_1_S * nrkj_1_S;
1096 cii_S = sth_S * nrij_1_S * nrij_1_S;
1097 ckk_S = sth_S * nrkj_1_S * nrkj_1_S;
1099 f_ix_S = cii_S * rijx_S;
1100 f_ix_S = fnma(cik_S, rkjx_S, f_ix_S);
1101 f_iy_S = cii_S * rijy_S;
1102 f_iy_S = fnma(cik_S, rkjy_S, f_iy_S);
1103 f_iz_S = cii_S * rijz_S;
1104 f_iz_S = fnma(cik_S, rkjz_S, f_iz_S);
1105 f_kx_S = ckk_S * rkjx_S;
1106 f_kx_S = fnma(cik_S, rijx_S, f_kx_S);
1107 f_ky_S = ckk_S * rkjy_S;
1108 f_ky_S = fnma(cik_S, rijy_S, f_ky_S);
1109 f_kz_S = ckk_S * rkjz_S;
1110 f_kz_S = fnma(cik_S, rijz_S, f_kz_S);
1112 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ai, f_ix_S, f_iy_S, f_iz_S);
1113 transposeScatterDecrU<4>(reinterpret_cast<real*>(f), aj, f_ix_S + f_kx_S, f_iy_S + f_ky_S,
1115 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ak, f_kx_S, f_ky_S, f_kz_S);
1121 #endif // GMX_SIMD_HAVE_REAL
1123 template<BondedKernelFlavor flavor>
1124 real linear_angles(int nbonds,
1125 const t_iatom forceatoms[],
1126 const t_iparams forceparams[],
1133 const t_mdatoms gmx_unused* md,
1134 t_fcdata gmx_unused* fcd,
1135 int gmx_unused* global_atom_index)
1137 int i, m, ai, aj, ak, t1, t2, type;
1139 real L1, kA, kB, aA, aB, dr, dr2, va, vtot, a, b, klin;
1140 rvec r_ij, r_kj, r_ik, dx;
1144 for (i = 0; (i < nbonds);)
1146 type = forceatoms[i++];
1147 ai = forceatoms[i++];
1148 aj = forceatoms[i++];
1149 ak = forceatoms[i++];
1151 kA = forceparams[type].linangle.klinA;
1152 kB = forceparams[type].linangle.klinB;
1153 klin = L1 * kA + lambda * kB;
1155 aA = forceparams[type].linangle.aA;
1156 aB = forceparams[type].linangle.aB;
1157 a = L1 * aA + lambda * aB;
1160 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], r_ij);
1161 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], r_kj);
1162 rvec_sub(r_ij, r_kj, r_ik);
1165 for (m = 0; (m < DIM); m++)
1167 dr = -a * r_ij[m] - b * r_kj[m];
1170 f_i[m] = a * klin * dr;
1171 f_k[m] = b * klin * dr;
1172 f_j[m] = -(f_i[m] + f_k[m]);
1177 va = 0.5 * klin * dr2;
1178 *dvdlambda += 0.5 * (kB - kA) * dr2 + klin * (aB - aA) * iprod(dx, r_ik);
1182 if (computeVirial(flavor))
1184 rvec_inc(fshift[t1], f_i);
1185 rvec_inc(fshift[CENTRAL], f_j);
1186 rvec_inc(fshift[t2], f_k);
1192 template<BondedKernelFlavor flavor>
1193 std::enable_if_t<flavor != BondedKernelFlavor::ForcesSimdWhenAvailable || !GMX_SIMD_HAVE_REAL, real>
1194 urey_bradley(int nbonds,
1195 const t_iatom forceatoms[],
1196 const t_iparams forceparams[],
1203 const t_mdatoms gmx_unused* md,
1204 t_fcdata gmx_unused* fcd,
1205 int gmx_unused* global_atom_index)
1207 int i, m, ai, aj, ak, t1, t2, type, ki;
1208 rvec r_ij, r_kj, r_ik;
1209 real cos_theta, cos_theta2, theta;
1210 real dVdt, va, vtot, dr, dr2, vbond, fbond, fik;
1211 real kthA, th0A, kUBA, r13A, kthB, th0B, kUBB, r13B;
1214 for (i = 0; (i < nbonds);)
1216 type = forceatoms[i++];
1217 ai = forceatoms[i++];
1218 aj = forceatoms[i++];
1219 ak = forceatoms[i++];
1220 th0A = forceparams[type].u_b.thetaA * DEG2RAD;
1221 kthA = forceparams[type].u_b.kthetaA;
1222 r13A = forceparams[type].u_b.r13A;
1223 kUBA = forceparams[type].u_b.kUBA;
1224 th0B = forceparams[type].u_b.thetaB * DEG2RAD;
1225 kthB = forceparams[type].u_b.kthetaB;
1226 r13B = forceparams[type].u_b.r13B;
1227 kUBB = forceparams[type].u_b.kUBB;
1229 theta = bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
1231 *dvdlambda += harmonic(kthA, kthB, th0A, th0B, theta, lambda, &va, &dVdt); /* 21 */
1234 ki = pbc_rvec_sub(pbc, x[ai], x[ak], r_ik); /* 3 */
1235 dr2 = iprod(r_ik, r_ik); /* 5 */
1236 dr = dr2 * gmx::invsqrt(dr2); /* 10 */
1238 *dvdlambda += harmonic(kUBA, kUBB, r13A, r13B, dr, lambda, &vbond, &fbond); /* 19 */
1240 cos_theta2 = gmx::square(cos_theta); /* 1 */
1248 st = dVdt * gmx::invsqrt(1 - cos_theta2); /* 12 */
1249 sth = st * cos_theta; /* 1 */
1250 nrkj2 = iprod(r_kj, r_kj); /* 5 */
1251 nrij2 = iprod(r_ij, r_ij);
1253 cik = st * gmx::invsqrt(nrkj2 * nrij2); /* 12 */
1254 cii = sth / nrij2; /* 10 */
1255 ckk = sth / nrkj2; /* 10 */
1257 for (m = 0; (m < DIM); m++) /* 39 */
1259 f_i[m] = -(cik * r_kj[m] - cii * r_ij[m]);
1260 f_k[m] = -(cik * r_ij[m] - ckk * r_kj[m]);
1261 f_j[m] = -f_i[m] - f_k[m];
1266 if (computeVirial(flavor))
1268 rvec_inc(fshift[t1], f_i);
1269 rvec_inc(fshift[CENTRAL], f_j);
1270 rvec_inc(fshift[t2], f_k);
1273 /* Time for the bond calculations */
1279 vtot += vbond; /* 1*/
1280 fbond *= gmx::invsqrt(dr2); /* 6 */
1282 for (m = 0; (m < DIM); m++) /* 15 */
1284 fik = fbond * r_ik[m];
1287 if (computeVirial(flavor))
1289 fshift[ki][m] += fik;
1290 fshift[CENTRAL][m] -= fik;
1297 #if GMX_SIMD_HAVE_REAL
1299 /* As urey_bradley, but using SIMD to calculate many potentials at once.
1300 * This routines does not calculate energies and shift forces.
1302 template<BondedKernelFlavor flavor>
1303 std::enable_if_t<flavor == BondedKernelFlavor::ForcesSimdWhenAvailable, real>
1304 urey_bradley(int nbonds,
1305 const t_iatom forceatoms[],
1306 const t_iparams forceparams[],
1309 rvec gmx_unused fshift[],
1311 real gmx_unused lambda,
1312 real gmx_unused* dvdlambda,
1313 const t_mdatoms gmx_unused* md,
1314 t_fcdata gmx_unused* fcd,
1315 int gmx_unused* global_atom_index)
1317 constexpr int nfa1 = 4;
1318 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[GMX_SIMD_REAL_WIDTH];
1319 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[GMX_SIMD_REAL_WIDTH];
1320 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ak[GMX_SIMD_REAL_WIDTH];
1321 alignas(GMX_SIMD_ALIGNMENT) real coeff[4 * GMX_SIMD_REAL_WIDTH];
1322 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9 * GMX_SIMD_REAL_WIDTH];
1324 set_pbc_simd(pbc, pbc_simd);
1326 /* nbonds is the number of angles times nfa1, here we step GMX_SIMD_REAL_WIDTH angles */
1327 for (int i = 0; i < nbonds; i += GMX_SIMD_REAL_WIDTH * nfa1)
1329 /* Collect atoms for GMX_SIMD_REAL_WIDTH angles.
1330 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
1333 for (int s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
1335 const int type = forceatoms[iu];
1336 ai[s] = forceatoms[iu + 1];
1337 aj[s] = forceatoms[iu + 2];
1338 ak[s] = forceatoms[iu + 3];
1340 /* At the end fill the arrays with the last atoms and 0 params */
1341 if (i + s * nfa1 < nbonds)
1343 coeff[s] = forceparams[type].u_b.kthetaA;
1344 coeff[GMX_SIMD_REAL_WIDTH + s] = forceparams[type].u_b.thetaA;
1345 coeff[GMX_SIMD_REAL_WIDTH * 2 + s] = forceparams[type].u_b.kUBA;
1346 coeff[GMX_SIMD_REAL_WIDTH * 3 + s] = forceparams[type].u_b.r13A;
1348 if (iu + nfa1 < nbonds)
1356 coeff[GMX_SIMD_REAL_WIDTH + s] = 0;
1357 coeff[GMX_SIMD_REAL_WIDTH * 2 + s] = 0;
1358 coeff[GMX_SIMD_REAL_WIDTH * 3 + s] = 0;
1362 SimdReal xi_S, yi_S, zi_S;
1363 SimdReal xj_S, yj_S, zj_S;
1364 SimdReal xk_S, yk_S, zk_S;
1366 /* Store the non PBC corrected distances packed and aligned */
1367 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ai, &xi_S, &yi_S, &zi_S);
1368 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), aj, &xj_S, &yj_S, &zj_S);
1369 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ak, &xk_S, &yk_S, &zk_S);
1370 SimdReal rijx_S = xi_S - xj_S;
1371 SimdReal rijy_S = yi_S - yj_S;
1372 SimdReal rijz_S = zi_S - zj_S;
1373 SimdReal rkjx_S = xk_S - xj_S;
1374 SimdReal rkjy_S = yk_S - yj_S;
1375 SimdReal rkjz_S = zk_S - zj_S;
1376 SimdReal rikx_S = xi_S - xk_S;
1377 SimdReal riky_S = yi_S - yk_S;
1378 SimdReal rikz_S = zi_S - zk_S;
1380 const SimdReal ktheta_S = load<SimdReal>(coeff);
1381 const SimdReal theta0_S = load<SimdReal>(coeff + GMX_SIMD_REAL_WIDTH) * DEG2RAD;
1382 const SimdReal kUB_S = load<SimdReal>(coeff + 2 * GMX_SIMD_REAL_WIDTH);
1383 const SimdReal r13_S = load<SimdReal>(coeff + 3 * GMX_SIMD_REAL_WIDTH);
1385 pbc_correct_dx_simd(&rijx_S, &rijy_S, &rijz_S, pbc_simd);
1386 pbc_correct_dx_simd(&rkjx_S, &rkjy_S, &rkjz_S, pbc_simd);
1387 pbc_correct_dx_simd(&rikx_S, &riky_S, &rikz_S, pbc_simd);
1389 const SimdReal rij_rkj_S = iprod(rijx_S, rijy_S, rijz_S, rkjx_S, rkjy_S, rkjz_S);
1391 const SimdReal dr2_S = iprod(rikx_S, riky_S, rikz_S, rikx_S, riky_S, rikz_S);
1393 const SimdReal nrij2_S = norm2(rijx_S, rijy_S, rijz_S);
1394 const SimdReal nrkj2_S = norm2(rkjx_S, rkjy_S, rkjz_S);
1396 const SimdReal nrij_1_S = invsqrt(nrij2_S);
1397 const SimdReal nrkj_1_S = invsqrt(nrkj2_S);
1398 const SimdReal invdr2_S = invsqrt(dr2_S);
1399 const SimdReal dr_S = dr2_S * invdr2_S;
1401 constexpr real min_one_plus_eps = -1.0 + 2.0 * GMX_REAL_EPS; // Smallest number > -1
1403 /* To allow for 180 degrees, we take the max of cos and -1 + 1bit,
1404 * so we can safely get the 1/sin from 1/sqrt(1 - cos^2).
1405 * This also ensures that rounding errors would cause the argument
1406 * of simdAcos to be < -1.
1407 * Note that we do not take precautions for cos(0)=1, so the bonds
1408 * in an angle should not align at an angle of 0 degrees.
1410 const SimdReal cos_S = max(rij_rkj_S * nrij_1_S * nrkj_1_S, min_one_plus_eps);
1412 const SimdReal theta_S = acos(cos_S);
1413 const SimdReal invsin_S = invsqrt(1.0 - cos_S * cos_S);
1414 const SimdReal st_S = ktheta_S * (theta0_S - theta_S) * invsin_S;
1415 const SimdReal sth_S = st_S * cos_S;
1417 const SimdReal cik_S = st_S * nrij_1_S * nrkj_1_S;
1418 const SimdReal cii_S = sth_S * nrij_1_S * nrij_1_S;
1419 const SimdReal ckk_S = sth_S * nrkj_1_S * nrkj_1_S;
1421 const SimdReal sUB_S = kUB_S * (r13_S - dr_S) * invdr2_S;
1423 const SimdReal f_ikx_S = sUB_S * rikx_S;
1424 const SimdReal f_iky_S = sUB_S * riky_S;
1425 const SimdReal f_ikz_S = sUB_S * rikz_S;
1427 const SimdReal f_ix_S = fnma(cik_S, rkjx_S, cii_S * rijx_S) + f_ikx_S;
1428 const SimdReal f_iy_S = fnma(cik_S, rkjy_S, cii_S * rijy_S) + f_iky_S;
1429 const SimdReal f_iz_S = fnma(cik_S, rkjz_S, cii_S * rijz_S) + f_ikz_S;
1430 const SimdReal f_kx_S = fnma(cik_S, rijx_S, ckk_S * rkjx_S) - f_ikx_S;
1431 const SimdReal f_ky_S = fnma(cik_S, rijy_S, ckk_S * rkjy_S) - f_iky_S;
1432 const SimdReal f_kz_S = fnma(cik_S, rijz_S, ckk_S * rkjz_S) - f_ikz_S;
1434 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ai, f_ix_S, f_iy_S, f_iz_S);
1435 transposeScatterDecrU<4>(reinterpret_cast<real*>(f), aj, f_ix_S + f_kx_S, f_iy_S + f_ky_S,
1437 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ak, f_kx_S, f_ky_S, f_kz_S);
1443 #endif // GMX_SIMD_HAVE_REAL
1445 template<BondedKernelFlavor flavor>
1446 real quartic_angles(int nbonds,
1447 const t_iatom forceatoms[],
1448 const t_iparams forceparams[],
1453 real gmx_unused lambda,
1454 real gmx_unused* dvdlambda,
1455 const t_mdatoms gmx_unused* md,
1456 t_fcdata gmx_unused* fcd,
1457 int gmx_unused* global_atom_index)
1459 int i, j, ai, aj, ak, t1, t2, type;
1461 real cos_theta, cos_theta2, theta, dt, dVdt, va, dtp, c, vtot;
1464 for (i = 0; (i < nbonds);)
1466 type = forceatoms[i++];
1467 ai = forceatoms[i++];
1468 aj = forceatoms[i++];
1469 ak = forceatoms[i++];
1471 theta = bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
1473 dt = theta - forceparams[type].qangle.theta * DEG2RAD; /* 2 */
1476 va = forceparams[type].qangle.c[0];
1478 for (j = 1; j <= 4; j++)
1480 c = forceparams[type].qangle.c[j];
1481 dVdt -= j * c * dtp;
1489 cos_theta2 = gmx::square(cos_theta); /* 1 */
1498 st = dVdt * gmx::invsqrt(1 - cos_theta2); /* 12 */
1499 sth = st * cos_theta; /* 1 */
1500 nrkj2 = iprod(r_kj, r_kj); /* 5 */
1501 nrij2 = iprod(r_ij, r_ij);
1503 cik = st * gmx::invsqrt(nrkj2 * nrij2); /* 12 */
1504 cii = sth / nrij2; /* 10 */
1505 ckk = sth / nrkj2; /* 10 */
1507 for (m = 0; (m < DIM); m++) /* 39 */
1509 f_i[m] = -(cik * r_kj[m] - cii * r_ij[m]);
1510 f_k[m] = -(cik * r_ij[m] - ckk * r_kj[m]);
1511 f_j[m] = -f_i[m] - f_k[m];
1517 if (computeVirial(flavor))
1519 rvec_inc(fshift[t1], f_i);
1520 rvec_inc(fshift[CENTRAL], f_j);
1521 rvec_inc(fshift[t2], f_k);
1529 #if GMX_SIMD_HAVE_REAL
1531 /* As dih_angle above, but calculates 4 dihedral angles at once using SIMD,
1532 * also calculates the pre-factor required for the dihedral force update.
1533 * Note that bv and buf should be register aligned.
1535 inline void dih_angle_simd(const rvec* x,
1540 const real* pbc_simd,
1548 SimdReal* nrkj_m2_S,
1549 SimdReal* nrkj_n2_S,
1553 SimdReal xi_S, yi_S, zi_S;
1554 SimdReal xj_S, yj_S, zj_S;
1555 SimdReal xk_S, yk_S, zk_S;
1556 SimdReal xl_S, yl_S, zl_S;
1557 SimdReal rijx_S, rijy_S, rijz_S;
1558 SimdReal rkjx_S, rkjy_S, rkjz_S;
1559 SimdReal rklx_S, rkly_S, rklz_S;
1560 SimdReal cx_S, cy_S, cz_S;
1564 SimdReal iprm_S, iprn_S;
1565 SimdReal nrkj2_S, nrkj_1_S, nrkj_2_S, nrkj_S;
1567 SimdReal nrkj2_min_S;
1568 SimdReal real_eps_S;
1570 /* Used to avoid division by zero.
1571 * We take into acount that we multiply the result by real_eps_S.
1573 nrkj2_min_S = SimdReal(GMX_REAL_MIN / (2 * GMX_REAL_EPS));
1575 /* The value of the last significant bit (GMX_REAL_EPS is half of that) */
1576 real_eps_S = SimdReal(2 * GMX_REAL_EPS);
1578 /* Store the non PBC corrected distances packed and aligned */
1579 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ai, &xi_S, &yi_S, &zi_S);
1580 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), aj, &xj_S, &yj_S, &zj_S);
1581 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ak, &xk_S, &yk_S, &zk_S);
1582 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), al, &xl_S, &yl_S, &zl_S);
1583 rijx_S = xi_S - xj_S;
1584 rijy_S = yi_S - yj_S;
1585 rijz_S = zi_S - zj_S;
1586 rkjx_S = xk_S - xj_S;
1587 rkjy_S = yk_S - yj_S;
1588 rkjz_S = zk_S - zj_S;
1589 rklx_S = xk_S - xl_S;
1590 rkly_S = yk_S - yl_S;
1591 rklz_S = zk_S - zl_S;
1593 pbc_correct_dx_simd(&rijx_S, &rijy_S, &rijz_S, pbc_simd);
1594 pbc_correct_dx_simd(&rkjx_S, &rkjy_S, &rkjz_S, pbc_simd);
1595 pbc_correct_dx_simd(&rklx_S, &rkly_S, &rklz_S, pbc_simd);
1597 cprod(rijx_S, rijy_S, rijz_S, rkjx_S, rkjy_S, rkjz_S, mx_S, my_S, mz_S);
1599 cprod(rkjx_S, rkjy_S, rkjz_S, rklx_S, rkly_S, rklz_S, nx_S, ny_S, nz_S);
1601 cprod(*mx_S, *my_S, *mz_S, *nx_S, *ny_S, *nz_S, &cx_S, &cy_S, &cz_S);
1603 cn_S = sqrt(norm2(cx_S, cy_S, cz_S));
1605 s_S = iprod(*mx_S, *my_S, *mz_S, *nx_S, *ny_S, *nz_S);
1607 /* Determine the dihedral angle, the sign might need correction */
1608 *phi_S = atan2(cn_S, s_S);
1610 ipr_S = iprod(rijx_S, rijy_S, rijz_S, *nx_S, *ny_S, *nz_S);
1612 iprm_S = norm2(*mx_S, *my_S, *mz_S);
1613 iprn_S = norm2(*nx_S, *ny_S, *nz_S);
1615 nrkj2_S = norm2(rkjx_S, rkjy_S, rkjz_S);
1617 /* Avoid division by zero. When zero, the result is multiplied by 0
1618 * anyhow, so the 3 max below do not affect the final result.
1620 nrkj2_S = max(nrkj2_S, nrkj2_min_S);
1621 nrkj_1_S = invsqrt(nrkj2_S);
1622 nrkj_2_S = nrkj_1_S * nrkj_1_S;
1623 nrkj_S = nrkj2_S * nrkj_1_S;
1625 toler_S = nrkj2_S * real_eps_S;
1627 /* Here the plain-C code uses a conditional, but we can't do that in SIMD.
1628 * So we take a max with the tolerance instead. Since we multiply with
1629 * m or n later, the max does not affect the results.
1631 iprm_S = max(iprm_S, toler_S);
1632 iprn_S = max(iprn_S, toler_S);
1633 *nrkj_m2_S = nrkj_S * inv(iprm_S);
1634 *nrkj_n2_S = nrkj_S * inv(iprn_S);
1636 /* Set sign of phi_S with the sign of ipr_S; phi_S is currently positive */
1637 *phi_S = copysign(*phi_S, ipr_S);
1638 *p_S = iprod(rijx_S, rijy_S, rijz_S, rkjx_S, rkjy_S, rkjz_S);
1639 *p_S = *p_S * nrkj_2_S;
1641 *q_S = iprod(rklx_S, rkly_S, rklz_S, rkjx_S, rkjy_S, rkjz_S);
1642 *q_S = *q_S * nrkj_2_S;
1645 #endif // GMX_SIMD_HAVE_REAL
1649 template<BondedKernelFlavor flavor>
1650 void do_dih_fup(int i,
1669 rvec f_i, f_j, f_k, f_l;
1670 rvec uvec, vvec, svec, dx_jl;
1671 real iprm, iprn, nrkj, nrkj2, nrkj_1, nrkj_2;
1672 real a, b, p, q, toler;
1674 iprm = iprod(m, m); /* 5 */
1675 iprn = iprod(n, n); /* 5 */
1676 nrkj2 = iprod(r_kj, r_kj); /* 5 */
1677 toler = nrkj2 * GMX_REAL_EPS;
1678 if ((iprm > toler) && (iprn > toler))
1680 nrkj_1 = gmx::invsqrt(nrkj2); /* 10 */
1681 nrkj_2 = nrkj_1 * nrkj_1; /* 1 */
1682 nrkj = nrkj2 * nrkj_1; /* 1 */
1683 a = -ddphi * nrkj / iprm; /* 11 */
1684 svmul(a, m, f_i); /* 3 */
1685 b = ddphi * nrkj / iprn; /* 11 */
1686 svmul(b, n, f_l); /* 3 */
1687 p = iprod(r_ij, r_kj); /* 5 */
1688 p *= nrkj_2; /* 1 */
1689 q = iprod(r_kl, r_kj); /* 5 */
1690 q *= nrkj_2; /* 1 */
1691 svmul(p, f_i, uvec); /* 3 */
1692 svmul(q, f_l, vvec); /* 3 */
1693 rvec_sub(uvec, vvec, svec); /* 3 */
1694 rvec_sub(f_i, svec, f_j); /* 3 */
1695 rvec_add(f_l, svec, f_k); /* 3 */
1696 rvec_inc(f[i], f_i); /* 3 */
1697 rvec_dec(f[j], f_j); /* 3 */
1698 rvec_dec(f[k], f_k); /* 3 */
1699 rvec_inc(f[l], f_l); /* 3 */
1701 if (computeVirial(flavor))
1705 t3 = pbc_rvec_sub(pbc, x[l], x[j], dx_jl);
1712 rvec_inc(fshift[t1], f_i);
1713 rvec_dec(fshift[CENTRAL], f_j);
1714 rvec_dec(fshift[t2], f_k);
1715 rvec_inc(fshift[t3], f_l);
1724 #if GMX_SIMD_HAVE_REAL
1725 /* As do_dih_fup_noshiftf above, but with SIMD and pre-calculated pre-factors */
1726 inline void gmx_simdcall do_dih_fup_noshiftf_simd(const int* ai,
1740 SimdReal sx = p * f_i_x + q * mf_l_x;
1741 SimdReal sy = p * f_i_y + q * mf_l_y;
1742 SimdReal sz = p * f_i_z + q * mf_l_z;
1743 SimdReal f_j_x = f_i_x - sx;
1744 SimdReal f_j_y = f_i_y - sy;
1745 SimdReal f_j_z = f_i_z - sz;
1746 SimdReal f_k_x = mf_l_x - sx;
1747 SimdReal f_k_y = mf_l_y - sy;
1748 SimdReal f_k_z = mf_l_z - sz;
1749 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ai, f_i_x, f_i_y, f_i_z);
1750 transposeScatterDecrU<4>(reinterpret_cast<real*>(f), aj, f_j_x, f_j_y, f_j_z);
1751 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ak, f_k_x, f_k_y, f_k_z);
1752 transposeScatterDecrU<4>(reinterpret_cast<real*>(f), al, mf_l_x, mf_l_y, mf_l_z);
1754 #endif // GMX_SIMD_HAVE_REAL
1756 /*! \brief Computes and returns the proper dihedral force
1758 * With the appropriate kernel flavor, also computes and accumulates
1759 * the energy and dV/dlambda.
1761 template<BondedKernelFlavor flavor>
1762 real dopdihs(real cpA, real cpB, real phiA, real phiB, int mult, real phi, real lambda, real* V, real* dvdlambda)
1764 const real L1 = 1.0 - lambda;
1765 const real ph0 = (L1 * phiA + lambda * phiB) * DEG2RAD;
1766 const real dph0 = (phiB - phiA) * DEG2RAD;
1767 const real cp = L1 * cpA + lambda * cpB;
1769 const real mdphi = mult * phi - ph0;
1770 const real sdphi = std::sin(mdphi);
1771 const real ddphi = -cp * mult * sdphi;
1772 if (computeEnergy(flavor))
1774 const real v1 = 1 + std::cos(mdphi);
1777 *dvdlambda += (cpB - cpA) * v1 + cp * dph0 * sdphi;
1781 /* That was 40 flops */
1784 /*! \brief Similar to \p dopdihs(), except for a minus sign and a different treatment of mult/phi0 */
1785 real dopdihs_min(real cpA, real cpB, real phiA, real phiB, int mult, real phi, real lambda, real* V, real* F)
1787 real v, dvdlambda, mdphi, v1, sdphi, ddphi;
1788 real L1 = 1.0 - lambda;
1789 real ph0 = (L1 * phiA + lambda * phiB) * DEG2RAD;
1790 real dph0 = (phiB - phiA) * DEG2RAD;
1791 real cp = L1 * cpA + lambda * cpB;
1793 mdphi = mult * (phi - ph0);
1794 sdphi = std::sin(mdphi);
1795 ddphi = cp * mult * sdphi;
1796 v1 = 1.0 - std::cos(mdphi);
1799 dvdlambda = (cpB - cpA) * v1 + cp * dph0 * sdphi;
1806 /* That was 40 flops */
1809 template<BondedKernelFlavor flavor>
1810 std::enable_if_t<flavor != BondedKernelFlavor::ForcesSimdWhenAvailable || !GMX_SIMD_HAVE_REAL, real>
1812 const t_iatom forceatoms[],
1813 const t_iparams forceparams[],
1820 const t_mdatoms gmx_unused* md,
1821 t_fcdata gmx_unused* fcd,
1822 int gmx_unused* global_atom_index)
1825 rvec r_ij, r_kj, r_kl, m, n;
1829 for (int i = 0; i < nbonds;)
1831 const int ai = forceatoms[i + 1];
1832 const int aj = forceatoms[i + 2];
1833 const int ak = forceatoms[i + 3];
1834 const int al = forceatoms[i + 4];
1836 const real phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n, &t1,
1839 /* Loop over dihedrals working on the same atoms,
1840 * so we avoid recalculating angles and distributing forces.
1845 const int type = forceatoms[i];
1846 ddphi_tot += dopdihs<flavor>(forceparams[type].pdihs.cpA, forceparams[type].pdihs.cpB,
1847 forceparams[type].pdihs.phiA, forceparams[type].pdihs.phiB,
1848 forceparams[type].pdihs.mult, phi, lambda, &vtot, dvdlambda);
1851 } while (i < nbonds && forceatoms[i + 1] == ai && forceatoms[i + 2] == aj
1852 && forceatoms[i + 3] == ak && forceatoms[i + 4] == al);
1854 do_dih_fup<flavor>(ai, aj, ak, al, ddphi_tot, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1,
1861 #if GMX_SIMD_HAVE_REAL
1863 /* As pdihs above, but using SIMD to calculate multiple dihedrals at once */
1864 template<BondedKernelFlavor flavor>
1865 std::enable_if_t<flavor == BondedKernelFlavor::ForcesSimdWhenAvailable, real>
1867 const t_iatom forceatoms[],
1868 const t_iparams forceparams[],
1871 rvec gmx_unused fshift[],
1873 real gmx_unused lambda,
1874 real gmx_unused* dvdlambda,
1875 const t_mdatoms gmx_unused* md,
1876 t_fcdata gmx_unused* fcd,
1877 int gmx_unused* global_atom_index)
1882 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[GMX_SIMD_REAL_WIDTH];
1883 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[GMX_SIMD_REAL_WIDTH];
1884 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ak[GMX_SIMD_REAL_WIDTH];
1885 alignas(GMX_SIMD_ALIGNMENT) std::int32_t al[GMX_SIMD_REAL_WIDTH];
1886 alignas(GMX_SIMD_ALIGNMENT) real buf[3 * GMX_SIMD_REAL_WIDTH];
1887 real * cp, *phi0, *mult;
1888 SimdReal deg2rad_S(DEG2RAD);
1890 SimdReal phi0_S, phi_S;
1891 SimdReal mx_S, my_S, mz_S;
1892 SimdReal nx_S, ny_S, nz_S;
1893 SimdReal nrkj_m2_S, nrkj_n2_S;
1894 SimdReal cp_S, mdphi_S, mult_S;
1895 SimdReal sin_S, cos_S;
1897 SimdReal sf_i_S, msf_l_S;
1898 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9 * GMX_SIMD_REAL_WIDTH];
1900 /* Extract aligned pointer for parameters and variables */
1901 cp = buf + 0 * GMX_SIMD_REAL_WIDTH;
1902 phi0 = buf + 1 * GMX_SIMD_REAL_WIDTH;
1903 mult = buf + 2 * GMX_SIMD_REAL_WIDTH;
1905 set_pbc_simd(pbc, pbc_simd);
1907 /* nbonds is the number of dihedrals times nfa1, here we step GMX_SIMD_REAL_WIDTH dihs */
1908 for (i = 0; (i < nbonds); i += GMX_SIMD_REAL_WIDTH * nfa1)
1910 /* Collect atoms quadruplets for GMX_SIMD_REAL_WIDTH dihedrals.
1911 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
1914 for (s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
1916 type = forceatoms[iu];
1917 ai[s] = forceatoms[iu + 1];
1918 aj[s] = forceatoms[iu + 2];
1919 ak[s] = forceatoms[iu + 3];
1920 al[s] = forceatoms[iu + 4];
1922 /* At the end fill the arrays with the last atoms and 0 params */
1923 if (i + s * nfa1 < nbonds)
1925 cp[s] = forceparams[type].pdihs.cpA;
1926 phi0[s] = forceparams[type].pdihs.phiA;
1927 mult[s] = forceparams[type].pdihs.mult;
1929 if (iu + nfa1 < nbonds)
1942 /* Caclulate GMX_SIMD_REAL_WIDTH dihedral angles at once */
1943 dih_angle_simd(x, ai, aj, ak, al, pbc_simd, &phi_S, &mx_S, &my_S, &mz_S, &nx_S, &ny_S,
1944 &nz_S, &nrkj_m2_S, &nrkj_n2_S, &p_S, &q_S);
1946 cp_S = load<SimdReal>(cp);
1947 phi0_S = load<SimdReal>(phi0) * deg2rad_S;
1948 mult_S = load<SimdReal>(mult);
1950 mdphi_S = fms(mult_S, phi_S, phi0_S);
1952 /* Calculate GMX_SIMD_REAL_WIDTH sines at once */
1953 sincos(mdphi_S, &sin_S, &cos_S);
1954 mddphi_S = cp_S * mult_S * sin_S;
1955 sf_i_S = mddphi_S * nrkj_m2_S;
1956 msf_l_S = mddphi_S * nrkj_n2_S;
1958 /* After this m?_S will contain f[i] */
1959 mx_S = sf_i_S * mx_S;
1960 my_S = sf_i_S * my_S;
1961 mz_S = sf_i_S * mz_S;
1963 /* After this m?_S will contain -f[l] */
1964 nx_S = msf_l_S * nx_S;
1965 ny_S = msf_l_S * ny_S;
1966 nz_S = msf_l_S * nz_S;
1968 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);
1974 /* This is mostly a copy of the SIMD flavor of pdihs above, but with using
1975 * the RB potential instead of a harmonic potential.
1976 * This function can replace rbdihs() when no energy and virial are needed.
1978 template<BondedKernelFlavor flavor>
1979 std::enable_if_t<flavor == BondedKernelFlavor::ForcesSimdWhenAvailable, real>
1981 const t_iatom forceatoms[],
1982 const t_iparams forceparams[],
1985 rvec gmx_unused fshift[],
1987 real gmx_unused lambda,
1988 real gmx_unused* dvdlambda,
1989 const t_mdatoms gmx_unused* md,
1990 t_fcdata gmx_unused* fcd,
1991 int gmx_unused* global_atom_index)
1996 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[GMX_SIMD_REAL_WIDTH];
1997 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[GMX_SIMD_REAL_WIDTH];
1998 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ak[GMX_SIMD_REAL_WIDTH];
1999 alignas(GMX_SIMD_ALIGNMENT) std::int32_t al[GMX_SIMD_REAL_WIDTH];
2000 alignas(GMX_SIMD_ALIGNMENT) real parm[NR_RBDIHS * GMX_SIMD_REAL_WIDTH];
2004 SimdReal ddphi_S, cosfac_S;
2005 SimdReal mx_S, my_S, mz_S;
2006 SimdReal nx_S, ny_S, nz_S;
2007 SimdReal nrkj_m2_S, nrkj_n2_S;
2008 SimdReal parm_S, c_S;
2009 SimdReal sin_S, cos_S;
2010 SimdReal sf_i_S, msf_l_S;
2011 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9 * GMX_SIMD_REAL_WIDTH];
2013 SimdReal pi_S(M_PI);
2014 SimdReal one_S(1.0);
2016 set_pbc_simd(pbc, pbc_simd);
2018 /* nbonds is the number of dihedrals times nfa1, here we step GMX_SIMD_REAL_WIDTH dihs */
2019 for (i = 0; (i < nbonds); i += GMX_SIMD_REAL_WIDTH * nfa1)
2021 /* Collect atoms quadruplets for GMX_SIMD_REAL_WIDTH dihedrals.
2022 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
2025 for (s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
2027 type = forceatoms[iu];
2028 ai[s] = forceatoms[iu + 1];
2029 aj[s] = forceatoms[iu + 2];
2030 ak[s] = forceatoms[iu + 3];
2031 al[s] = forceatoms[iu + 4];
2033 /* At the end fill the arrays with the last atoms and 0 params */
2034 if (i + s * nfa1 < nbonds)
2036 /* We don't need the first parameter, since that's a constant
2037 * which only affects the energies, not the forces.
2039 for (j = 1; j < NR_RBDIHS; j++)
2041 parm[j * GMX_SIMD_REAL_WIDTH + s] = forceparams[type].rbdihs.rbcA[j];
2044 if (iu + nfa1 < nbonds)
2051 for (j = 1; j < NR_RBDIHS; j++)
2053 parm[j * GMX_SIMD_REAL_WIDTH + s] = 0;
2058 /* Caclulate GMX_SIMD_REAL_WIDTH dihedral angles at once */
2059 dih_angle_simd(x, ai, aj, ak, al, pbc_simd, &phi_S, &mx_S, &my_S, &mz_S, &nx_S, &ny_S,
2060 &nz_S, &nrkj_m2_S, &nrkj_n2_S, &p_S, &q_S);
2062 /* Change to polymer convention */
2063 phi_S = phi_S - pi_S;
2065 sincos(phi_S, &sin_S, &cos_S);
2067 ddphi_S = setZero();
2070 for (j = 1; j < NR_RBDIHS; j++)
2072 parm_S = load<SimdReal>(parm + j * GMX_SIMD_REAL_WIDTH);
2073 ddphi_S = fma(c_S * parm_S, cosfac_S, ddphi_S);
2074 cosfac_S = cosfac_S * cos_S;
2078 /* Note that here we do not use the minus sign which is present
2079 * in the normal RB code. This is corrected for through (m)sf below.
2081 ddphi_S = ddphi_S * sin_S;
2083 sf_i_S = ddphi_S * nrkj_m2_S;
2084 msf_l_S = ddphi_S * nrkj_n2_S;
2086 /* After this m?_S will contain f[i] */
2087 mx_S = sf_i_S * mx_S;
2088 my_S = sf_i_S * my_S;
2089 mz_S = sf_i_S * mz_S;
2091 /* After this m?_S will contain -f[l] */
2092 nx_S = msf_l_S * nx_S;
2093 ny_S = msf_l_S * ny_S;
2094 nz_S = msf_l_S * nz_S;
2096 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);
2102 #endif // GMX_SIMD_HAVE_REAL
2105 template<BondedKernelFlavor flavor>
2106 real idihs(int nbonds,
2107 const t_iatom forceatoms[],
2108 const t_iparams forceparams[],
2115 const t_mdatoms gmx_unused* md,
2116 t_fcdata gmx_unused* fcd,
2117 int gmx_unused* global_atom_index)
2119 int i, type, ai, aj, ak, al;
2121 real phi, phi0, dphi0, ddphi, vtot;
2122 rvec r_ij, r_kj, r_kl, m, n;
2123 real L1, kk, dp, dp2, kA, kB, pA, pB, dvdl_term;
2128 for (i = 0; (i < nbonds);)
2130 type = forceatoms[i++];
2131 ai = forceatoms[i++];
2132 aj = forceatoms[i++];
2133 ak = forceatoms[i++];
2134 al = forceatoms[i++];
2136 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3); /* 84 */
2138 /* phi can jump if phi0 is close to Pi/-Pi, which will cause huge
2139 * force changes if we just apply a normal harmonic.
2140 * Instead, we first calculate phi-phi0 and take it modulo (-Pi,Pi).
2141 * This means we will never have the periodicity problem, unless
2142 * the dihedral is Pi away from phiO, which is very unlikely due to
2145 kA = forceparams[type].harmonic.krA;
2146 kB = forceparams[type].harmonic.krB;
2147 pA = forceparams[type].harmonic.rA;
2148 pB = forceparams[type].harmonic.rB;
2150 kk = L1 * kA + lambda * kB;
2151 phi0 = (L1 * pA + lambda * pB) * DEG2RAD;
2152 dphi0 = (pB - pA) * DEG2RAD;
2156 make_dp_periodic(&dp);
2160 vtot += 0.5 * kk * dp2;
2163 dvdl_term += 0.5 * (kB - kA) * dp2 - kk * dphi0 * dp;
2165 do_dih_fup<flavor>(ai, aj, ak, al, -ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1,
2170 *dvdlambda += dvdl_term;
2174 /*! \brief Computes angle restraints of two different types */
2175 template<BondedKernelFlavor flavor>
2176 real low_angres(int nbonds,
2177 const t_iatom forceatoms[],
2178 const t_iparams forceparams[],
2187 int i, m, type, ai, aj, ak, al;
2189 real phi, cos_phi, cos_phi2, vid, vtot, dVdphi;
2190 rvec r_ij, r_kl, f_i, f_k = { 0, 0, 0 };
2191 real st, sth, nrij2, nrkl2, c, cij, ckl;
2193 t2 = 0; /* avoid warning with gcc-3.3. It is never used uninitialized */
2196 ak = al = 0; /* to avoid warnings */
2197 for (i = 0; i < nbonds;)
2199 type = forceatoms[i++];
2200 ai = forceatoms[i++];
2201 aj = forceatoms[i++];
2202 t1 = pbc_rvec_sub(pbc, x[aj], x[ai], r_ij); /* 3 */
2205 ak = forceatoms[i++];
2206 al = forceatoms[i++];
2207 t2 = pbc_rvec_sub(pbc, x[al], x[ak], r_kl); /* 3 */
2216 cos_phi = cos_angle(r_ij, r_kl); /* 25 */
2217 phi = std::acos(cos_phi); /* 10 */
2219 *dvdlambda += dopdihs_min(forceparams[type].pdihs.cpA, forceparams[type].pdihs.cpB,
2220 forceparams[type].pdihs.phiA, forceparams[type].pdihs.phiB,
2221 forceparams[type].pdihs.mult, phi, lambda, &vid, &dVdphi); /* 40 */
2225 cos_phi2 = gmx::square(cos_phi); /* 1 */
2228 st = -dVdphi * gmx::invsqrt(1 - cos_phi2); /* 12 */
2229 sth = st * cos_phi; /* 1 */
2230 nrij2 = iprod(r_ij, r_ij); /* 5 */
2231 nrkl2 = iprod(r_kl, r_kl); /* 5 */
2233 c = st * gmx::invsqrt(nrij2 * nrkl2); /* 11 */
2234 cij = sth / nrij2; /* 10 */
2235 ckl = sth / nrkl2; /* 10 */
2237 for (m = 0; m < DIM; m++) /* 18+18 */
2239 f_i[m] = (c * r_kl[m] - cij * r_ij[m]);
2244 f_k[m] = (c * r_ij[m] - ckl * r_kl[m]);
2250 if (computeVirial(flavor))
2252 rvec_inc(fshift[t1], f_i);
2253 rvec_dec(fshift[CENTRAL], f_i);
2256 rvec_inc(fshift[t2], f_k);
2257 rvec_dec(fshift[CENTRAL], f_k);
2263 return vtot; /* 184 / 157 (bZAxis) total */
2266 template<BondedKernelFlavor flavor>
2267 real angres(int nbonds,
2268 const t_iatom forceatoms[],
2269 const t_iparams forceparams[],
2276 const t_mdatoms gmx_unused* md,
2277 t_fcdata gmx_unused* fcd,
2278 int gmx_unused* global_atom_index)
2280 return low_angres<flavor>(nbonds, forceatoms, forceparams, x, f, fshift, pbc, lambda, dvdlambda, FALSE);
2283 template<BondedKernelFlavor flavor>
2284 real angresz(int nbonds,
2285 const t_iatom forceatoms[],
2286 const t_iparams forceparams[],
2293 const t_mdatoms gmx_unused* md,
2294 t_fcdata gmx_unused* fcd,
2295 int gmx_unused* global_atom_index)
2297 return low_angres<flavor>(nbonds, forceatoms, forceparams, x, f, fshift, pbc, lambda, dvdlambda, TRUE);
2300 template<BondedKernelFlavor flavor>
2301 real dihres(int nbonds,
2302 const t_iatom forceatoms[],
2303 const t_iparams forceparams[],
2310 const t_mdatoms gmx_unused* md,
2311 t_fcdata gmx_unused* fcd,
2312 int gmx_unused* global_atom_index)
2315 int ai, aj, ak, al, i, type, t1, t2, t3;
2316 real phi0A, phi0B, dphiA, dphiB, kfacA, kfacB, phi0, dphi, kfac;
2317 real phi, ddphi, ddp, ddp2, dp, d2r, L1;
2318 rvec r_ij, r_kj, r_kl, m, n;
2324 for (i = 0; (i < nbonds);)
2326 type = forceatoms[i++];
2327 ai = forceatoms[i++];
2328 aj = forceatoms[i++];
2329 ak = forceatoms[i++];
2330 al = forceatoms[i++];
2332 phi0A = forceparams[type].dihres.phiA * d2r;
2333 dphiA = forceparams[type].dihres.dphiA * d2r;
2334 kfacA = forceparams[type].dihres.kfacA;
2336 phi0B = forceparams[type].dihres.phiB * d2r;
2337 dphiB = forceparams[type].dihres.dphiB * d2r;
2338 kfacB = forceparams[type].dihres.kfacB;
2340 phi0 = L1 * phi0A + lambda * phi0B;
2341 dphi = L1 * dphiA + lambda * dphiB;
2342 kfac = L1 * kfacA + lambda * kfacB;
2344 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3);
2347 /* phi can jump if phi0 is close to Pi/-Pi, which will cause huge
2348 * force changes if we just apply a normal harmonic.
2349 * Instead, we first calculate phi-phi0 and take it modulo (-Pi,Pi).
2350 * This means we will never have the periodicity problem, unless
2351 * the dihedral is Pi away from phiO, which is very unlikely due to
2355 make_dp_periodic(&dp);
2361 else if (dp < -dphi)
2373 vtot += 0.5 * kfac * ddp2;
2376 *dvdlambda += 0.5 * (kfacB - kfacA) * ddp2;
2377 /* lambda dependence from changing restraint distances */
2380 *dvdlambda -= kfac * ddp * ((dphiB - dphiA) + (phi0B - phi0A));
2384 *dvdlambda += kfac * ddp * ((dphiB - dphiA) - (phi0B - phi0A));
2386 do_dih_fup<flavor>(ai, aj, ak, al, ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1,
2394 real unimplemented(int gmx_unused nbonds,
2395 const t_iatom gmx_unused forceatoms[],
2396 const t_iparams gmx_unused forceparams[],
2397 const rvec gmx_unused x[],
2398 rvec4 gmx_unused f[],
2399 rvec gmx_unused fshift[],
2400 const t_pbc gmx_unused* pbc,
2401 real gmx_unused lambda,
2402 real gmx_unused* dvdlambda,
2403 const t_mdatoms gmx_unused* md,
2404 t_fcdata gmx_unused* fcd,
2405 int gmx_unused* global_atom_index)
2407 gmx_impl("*** you are using a not implemented function");
2410 template<BondedKernelFlavor flavor>
2411 real restrangles(int nbonds,
2412 const t_iatom forceatoms[],
2413 const t_iparams forceparams[],
2418 real gmx_unused lambda,
2419 real gmx_unused* dvdlambda,
2420 const t_mdatoms gmx_unused* md,
2421 t_fcdata gmx_unused* fcd,
2422 int gmx_unused* global_atom_index)
2424 int i, d, ai, aj, ak, type, m;
2428 double prefactor, ratio_ante, ratio_post;
2429 rvec delta_ante, delta_post, vec_temp;
2432 for (i = 0; (i < nbonds);)
2434 type = forceatoms[i++];
2435 ai = forceatoms[i++];
2436 aj = forceatoms[i++];
2437 ak = forceatoms[i++];
2439 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], vec_temp);
2440 pbc_rvec_sub(pbc, x[aj], x[ai], delta_ante);
2441 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], delta_post);
2444 /* This function computes factors needed for restricted angle potential.
2445 * The restricted angle potential is used in coarse-grained simulations to avoid singularities
2446 * when three particles align and the dihedral angle and dihedral potential
2447 * cannot be calculated. This potential is calculated using the formula:
2448 real restrangles(int nbonds,
2449 const t_iatom forceatoms[],const t_iparams forceparams[],
2450 const rvec x[],rvec4 f[],rvec fshift[],
2452 real gmx_unused lambda,real gmx_unused *dvdlambda,
2453 const t_mdatoms gmx_unused *md,t_fcdata gmx_unused *fcd,
2454 int gmx_unused *global_atom_index)
2456 int i, d, ai, aj, ak, type, m;
2461 real prefactor, ratio_ante, ratio_post;
2462 rvec delta_ante, delta_post, vec_temp;
2465 for(i=0; (i<nbonds); )
2467 type = forceatoms[i++];
2468 ai = forceatoms[i++];
2469 aj = forceatoms[i++];
2470 ak = forceatoms[i++];
2472 * \f[V_{\rm ReB}(\theta_i) = \frac{1}{2} k_{\theta} \frac{(\cos\theta_i - \cos\theta_0)^2}
2473 * {\sin^2\theta_i}\f] ({eq:ReB} and ref \cite{MonicaGoga2013} from the manual).
2474 * For more explanations see comments file "restcbt.h". */
2476 compute_factors_restangles(type, forceparams, delta_ante, delta_post, &prefactor,
2477 &ratio_ante, &ratio_post, &v);
2479 /* Forces are computed per component */
2480 for (d = 0; d < DIM; d++)
2482 f_i[d] = prefactor * (ratio_ante * delta_ante[d] - delta_post[d]);
2484 * ((ratio_post + 1.0) * delta_post[d] - (ratio_ante + 1.0) * delta_ante[d]);
2485 f_k[d] = prefactor * (delta_ante[d] - ratio_post * delta_post[d]);
2488 /* Computation of potential energy */
2494 for (m = 0; (m < DIM); m++)
2501 if (computeVirial(flavor))
2503 rvec_inc(fshift[t1], f_i);
2504 rvec_inc(fshift[CENTRAL], f_j);
2505 rvec_inc(fshift[t2], f_k);
2512 template<BondedKernelFlavor flavor>
2513 real restrdihs(int nbonds,
2514 const t_iatom forceatoms[],
2515 const t_iparams forceparams[],
2520 real gmx_unused lambda,
2521 real gmx_unused* dvlambda,
2522 const t_mdatoms gmx_unused* md,
2523 t_fcdata gmx_unused* fcd,
2524 int gmx_unused* global_atom_index)
2526 int i, d, type, ai, aj, ak, al;
2527 rvec f_i, f_j, f_k, f_l;
2531 rvec delta_ante, delta_crnt, delta_post, vec_temp;
2532 real factor_phi_ai_ante, factor_phi_ai_crnt, factor_phi_ai_post;
2533 real factor_phi_aj_ante, factor_phi_aj_crnt, factor_phi_aj_post;
2534 real factor_phi_ak_ante, factor_phi_ak_crnt, factor_phi_ak_post;
2535 real factor_phi_al_ante, factor_phi_al_crnt, factor_phi_al_post;
2540 for (i = 0; (i < nbonds);)
2542 type = forceatoms[i++];
2543 ai = forceatoms[i++];
2544 aj = forceatoms[i++];
2545 ak = forceatoms[i++];
2546 al = forceatoms[i++];
2548 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], vec_temp);
2549 pbc_rvec_sub(pbc, x[aj], x[ai], delta_ante);
2550 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], delta_crnt);
2551 pbc_rvec_sub(pbc, x[ak], x[al], vec_temp);
2552 pbc_rvec_sub(pbc, x[al], x[ak], delta_post);
2554 /* This function computes factors needed for restricted angle potential.
2555 * The restricted angle potential is used in coarse-grained simulations to avoid singularities
2556 * when three particles align and the dihedral angle and dihedral potential cannot be calculated.
2557 * This potential is calculated using the formula:
2558 * \f[V_{\rm ReB}(\theta_i) = \frac{1}{2} k_{\theta}
2559 * \frac{(\cos\theta_i - \cos\theta_0)^2}{\sin^2\theta_i}\f]
2560 * ({eq:ReB} and ref \cite{MonicaGoga2013} from the manual).
2561 * For more explanations see comments file "restcbt.h" */
2563 compute_factors_restrdihs(
2564 type, forceparams, delta_ante, delta_crnt, delta_post, &factor_phi_ai_ante,
2565 &factor_phi_ai_crnt, &factor_phi_ai_post, &factor_phi_aj_ante, &factor_phi_aj_crnt,
2566 &factor_phi_aj_post, &factor_phi_ak_ante, &factor_phi_ak_crnt, &factor_phi_ak_post,
2567 &factor_phi_al_ante, &factor_phi_al_crnt, &factor_phi_al_post, &prefactor_phi, &v);
2570 /* Computation of forces per component */
2571 for (d = 0; d < DIM; d++)
2573 f_i[d] = prefactor_phi
2574 * (factor_phi_ai_ante * delta_ante[d] + factor_phi_ai_crnt * delta_crnt[d]
2575 + factor_phi_ai_post * delta_post[d]);
2576 f_j[d] = prefactor_phi
2577 * (factor_phi_aj_ante * delta_ante[d] + factor_phi_aj_crnt * delta_crnt[d]
2578 + factor_phi_aj_post * delta_post[d]);
2579 f_k[d] = prefactor_phi
2580 * (factor_phi_ak_ante * delta_ante[d] + factor_phi_ak_crnt * delta_crnt[d]
2581 + factor_phi_ak_post * delta_post[d]);
2582 f_l[d] = prefactor_phi
2583 * (factor_phi_al_ante * delta_ante[d] + factor_phi_al_crnt * delta_crnt[d]
2584 + factor_phi_al_post * delta_post[d]);
2586 /* Computation of the energy */
2591 /* Updating the forces */
2593 rvec_inc(f[ai], f_i);
2594 rvec_inc(f[aj], f_j);
2595 rvec_inc(f[ak], f_k);
2596 rvec_inc(f[al], f_l);
2598 if (computeVirial(flavor))
2602 t3 = pbc_rvec_sub(pbc, x[al], x[aj], dx_jl);
2609 rvec_inc(fshift[t1], f_i);
2610 rvec_inc(fshift[CENTRAL], f_j);
2611 rvec_inc(fshift[t2], f_k);
2612 rvec_inc(fshift[t3], f_l);
2620 template<BondedKernelFlavor flavor>
2621 real cbtdihs(int nbonds,
2622 const t_iatom forceatoms[],
2623 const t_iparams forceparams[],
2628 real gmx_unused lambda,
2629 real gmx_unused* dvdlambda,
2630 const t_mdatoms gmx_unused* md,
2631 t_fcdata gmx_unused* fcd,
2632 int gmx_unused* global_atom_index)
2634 int type, ai, aj, ak, al, i, d;
2638 rvec f_i, f_j, f_k, f_l;
2640 rvec delta_ante, delta_crnt, delta_post;
2641 rvec f_phi_ai, f_phi_aj, f_phi_ak, f_phi_al;
2642 rvec f_theta_ante_ai, f_theta_ante_aj, f_theta_ante_ak;
2643 rvec f_theta_post_aj, f_theta_post_ak, f_theta_post_al;
2647 for (i = 0; (i < nbonds);)
2649 type = forceatoms[i++];
2650 ai = forceatoms[i++];
2651 aj = forceatoms[i++];
2652 ak = forceatoms[i++];
2653 al = forceatoms[i++];
2656 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], vec_temp);
2657 pbc_rvec_sub(pbc, x[aj], x[ai], delta_ante);
2658 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], vec_temp);
2659 pbc_rvec_sub(pbc, x[ak], x[aj], delta_crnt);
2660 pbc_rvec_sub(pbc, x[ak], x[al], vec_temp);
2661 pbc_rvec_sub(pbc, x[al], x[ak], delta_post);
2663 /* \brief Compute factors for CBT potential
2664 * The combined bending-torsion potential goes to zero in a very smooth manner, eliminating the numerical
2665 * instabilities, when three coarse-grained particles align and the dihedral angle and standard
2666 * dihedral potentials cannot be calculated. The CBT potential is calculated using the formula:
2667 * \f[V_{\rm CBT}(\theta_{i-1}, \theta_i, \phi_i) = k_{\phi} \sin^3\theta_{i-1} \sin^3\theta_{i}
2668 * \sum_{n=0}^4 { a_n \cos^n\phi_i}\f] ({eq:CBT} and ref \cite{MonicaGoga2013} from the manual).
2669 * It contains in its expression not only the dihedral angle \f$\phi\f$
2670 * but also \f[\theta_{i-1}\f] (theta_ante bellow) and \f[\theta_{i}\f] (theta_post bellow)
2671 * --- the adjacent bending angles.
2672 * For more explanations see comments file "restcbt.h". */
2674 compute_factors_cbtdihs(type, forceparams, delta_ante, delta_crnt, delta_post, f_phi_ai,
2675 f_phi_aj, f_phi_ak, f_phi_al, f_theta_ante_ai, f_theta_ante_aj,
2676 f_theta_ante_ak, f_theta_post_aj, f_theta_post_ak, f_theta_post_al, &v);
2679 /* Acumulate the resuts per beads */
2680 for (d = 0; d < DIM; d++)
2682 f_i[d] = f_phi_ai[d] + f_theta_ante_ai[d];
2683 f_j[d] = f_phi_aj[d] + f_theta_ante_aj[d] + f_theta_post_aj[d];
2684 f_k[d] = f_phi_ak[d] + f_theta_ante_ak[d] + f_theta_post_ak[d];
2685 f_l[d] = f_phi_al[d] + f_theta_post_al[d];
2688 /* Compute the potential energy */
2693 /* Updating the forces */
2694 rvec_inc(f[ai], f_i);
2695 rvec_inc(f[aj], f_j);
2696 rvec_inc(f[ak], f_k);
2697 rvec_inc(f[al], f_l);
2700 if (computeVirial(flavor))
2704 t3 = pbc_rvec_sub(pbc, x[al], x[aj], dx_jl);
2711 rvec_inc(fshift[t1], f_i);
2712 rvec_inc(fshift[CENTRAL], f_j);
2713 rvec_inc(fshift[t2], f_k);
2714 rvec_inc(fshift[t3], f_l);
2721 template<BondedKernelFlavor flavor>
2722 std::enable_if_t<flavor != BondedKernelFlavor::ForcesSimdWhenAvailable || !GMX_SIMD_HAVE_REAL, real>
2724 const t_iatom forceatoms[],
2725 const t_iparams forceparams[],
2732 const t_mdatoms gmx_unused* md,
2733 t_fcdata gmx_unused* fcd,
2734 int gmx_unused* global_atom_index)
2736 const real c0 = 0.0, c1 = 1.0, c2 = 2.0, c3 = 3.0, c4 = 4.0, c5 = 5.0;
2737 int type, ai, aj, ak, al, i, j;
2739 rvec r_ij, r_kj, r_kl, m, n;
2740 real parmA[NR_RBDIHS];
2741 real parmB[NR_RBDIHS];
2742 real parm[NR_RBDIHS];
2743 real cos_phi, phi, rbp, rbpBA;
2744 real v, ddphi, sin_phi;
2746 real L1 = 1.0 - lambda;
2750 for (i = 0; (i < nbonds);)
2752 type = forceatoms[i++];
2753 ai = forceatoms[i++];
2754 aj = forceatoms[i++];
2755 ak = forceatoms[i++];
2756 al = forceatoms[i++];
2758 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3); /* 84 */
2760 /* Change to polymer convention */
2767 phi -= M_PI; /* 1 */
2769 cos_phi = std::cos(phi);
2770 /* Beware of accuracy loss, cannot use 1-sqrt(cos^2) ! */
2771 sin_phi = std::sin(phi);
2773 for (j = 0; (j < NR_RBDIHS); j++)
2775 parmA[j] = forceparams[type].rbdihs.rbcA[j];
2776 parmB[j] = forceparams[type].rbdihs.rbcB[j];
2777 parm[j] = L1 * parmA[j] + lambda * parmB[j];
2779 /* Calculate cosine powers */
2780 /* Calculate the energy */
2781 /* Calculate the derivative */
2784 dvdl_term += (parmB[0] - parmA[0]);
2789 rbpBA = parmB[1] - parmA[1];
2790 ddphi += rbp * cosfac;
2793 dvdl_term += cosfac * rbpBA;
2795 rbpBA = parmB[2] - parmA[2];
2796 ddphi += c2 * rbp * cosfac;
2799 dvdl_term += cosfac * rbpBA;
2801 rbpBA = parmB[3] - parmA[3];
2802 ddphi += c3 * rbp * cosfac;
2805 dvdl_term += cosfac * rbpBA;
2807 rbpBA = parmB[4] - parmA[4];
2808 ddphi += c4 * rbp * cosfac;
2811 dvdl_term += cosfac * rbpBA;
2813 rbpBA = parmB[5] - parmA[5];
2814 ddphi += c5 * rbp * cosfac;
2817 dvdl_term += cosfac * rbpBA;
2819 ddphi = -ddphi * sin_phi; /* 11 */
2821 do_dih_fup<flavor>(ai, aj, ak, al, ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1, t2,
2825 *dvdlambda += dvdl_term;
2832 /*! \brief Mysterious undocumented function */
2833 int cmap_setup_grid_index(int ip, int grid_spacing, int* ipm1, int* ipp1, int* ipp2)
2839 ip = ip + grid_spacing - 1;
2841 else if (ip > grid_spacing)
2843 ip = ip - grid_spacing - 1;
2852 im1 = grid_spacing - 1;
2854 else if (ip == grid_spacing - 2)
2858 else if (ip == grid_spacing - 1)
2873 real cmap_dihs(int nbonds,
2874 const t_iatom forceatoms[],
2875 const t_iparams forceparams[],
2876 const gmx_cmap_t* cmap_grid,
2880 const struct t_pbc* pbc,
2881 real gmx_unused lambda,
2882 real gmx_unused* dvdlambda,
2883 const t_mdatoms gmx_unused* md,
2884 t_fcdata gmx_unused* fcd,
2885 int gmx_unused* global_atom_index)
2888 int ai, aj, ak, al, am;
2889 int a1i, a1j, a1k, a1l, a2i, a2j, a2k, a2l;
2891 int t11, t21, t31, t12, t22, t32;
2892 int iphi1, ip1m1, ip1p1, ip1p2;
2893 int iphi2, ip2m1, ip2p1, ip2p2;
2895 int pos1, pos2, pos3, pos4;
2897 real ty[4], ty1[4], ty2[4], ty12[4], tx[16];
2898 real phi1, cos_phi1, sin_phi1, xphi1;
2899 real phi2, cos_phi2, sin_phi2, xphi2;
2900 real dx, tt, tu, e, df1, df2, vtot;
2901 real ra21, rb21, rg21, rg1, rgr1, ra2r1, rb2r1, rabr1;
2902 real ra22, rb22, rg22, rg2, rgr2, ra2r2, rb2r2, rabr2;
2903 real fg1, hg1, fga1, hgb1, gaa1, gbb1;
2904 real fg2, hg2, fga2, hgb2, gaa2, gbb2;
2907 rvec r1_ij, r1_kj, r1_kl, m1, n1;
2908 rvec r2_ij, r2_kj, r2_kl, m2, n2;
2909 rvec f1_i, f1_j, f1_k, f1_l;
2910 rvec f2_i, f2_j, f2_k, f2_l;
2911 rvec a1, b1, a2, b2;
2912 rvec f1, g1, h1, f2, g2, h2;
2913 rvec dtf1, dtg1, dth1, dtf2, dtg2, dth2;
2915 int loop_index[4][4] = { { 0, 4, 8, 12 }, { 1, 5, 9, 13 }, { 2, 6, 10, 14 }, { 3, 7, 11, 15 } };
2917 /* Total CMAP energy */
2920 for (n = 0; n < nbonds;)
2922 /* Five atoms are involved in the two torsions */
2923 type = forceatoms[n++];
2924 ai = forceatoms[n++];
2925 aj = forceatoms[n++];
2926 ak = forceatoms[n++];
2927 al = forceatoms[n++];
2928 am = forceatoms[n++];
2930 /* Which CMAP type is this */
2931 const int cmapA = forceparams[type].cmap.cmapA;
2932 const real* cmapd = cmap_grid->cmapdata[cmapA].cmap.data();
2940 phi1 = dih_angle(x[a1i], x[a1j], x[a1k], x[a1l], pbc, r1_ij, r1_kj, r1_kl, m1, n1, &t11,
2941 &t21, &t31); /* 84 */
2943 cos_phi1 = std::cos(phi1);
2945 a1[0] = r1_ij[1] * r1_kj[2] - r1_ij[2] * r1_kj[1];
2946 a1[1] = r1_ij[2] * r1_kj[0] - r1_ij[0] * r1_kj[2];
2947 a1[2] = r1_ij[0] * r1_kj[1] - r1_ij[1] * r1_kj[0]; /* 9 */
2949 b1[0] = r1_kl[1] * r1_kj[2] - r1_kl[2] * r1_kj[1];
2950 b1[1] = r1_kl[2] * r1_kj[0] - r1_kl[0] * r1_kj[2];
2951 b1[2] = r1_kl[0] * r1_kj[1] - r1_kl[1] * r1_kj[0]; /* 9 */
2953 pbc_rvec_sub(pbc, x[a1l], x[a1k], h1);
2955 ra21 = iprod(a1, a1); /* 5 */
2956 rb21 = iprod(b1, b1); /* 5 */
2957 rg21 = iprod(r1_kj, r1_kj); /* 5 */
2963 rabr1 = sqrt(ra2r1 * rb2r1);
2965 sin_phi1 = rg1 * rabr1 * iprod(a1, h1) * (-1);
2967 if (cos_phi1 < -0.5 || cos_phi1 > 0.5)
2969 phi1 = std::asin(sin_phi1);
2979 phi1 = -M_PI - phi1;
2985 phi1 = std::acos(cos_phi1);
2993 xphi1 = phi1 + M_PI; /* 1 */
2995 /* Second torsion */
3001 phi2 = dih_angle(x[a2i], x[a2j], x[a2k], x[a2l], pbc, r2_ij, r2_kj, r2_kl, m2, n2, &t12,
3002 &t22, &t32); /* 84 */
3004 cos_phi2 = std::cos(phi2);
3006 a2[0] = r2_ij[1] * r2_kj[2] - r2_ij[2] * r2_kj[1];
3007 a2[1] = r2_ij[2] * r2_kj[0] - r2_ij[0] * r2_kj[2];
3008 a2[2] = r2_ij[0] * r2_kj[1] - r2_ij[1] * r2_kj[0]; /* 9 */
3010 b2[0] = r2_kl[1] * r2_kj[2] - r2_kl[2] * r2_kj[1];
3011 b2[1] = r2_kl[2] * r2_kj[0] - r2_kl[0] * r2_kj[2];
3012 b2[2] = r2_kl[0] * r2_kj[1] - r2_kl[1] * r2_kj[0]; /* 9 */
3014 pbc_rvec_sub(pbc, x[a2l], x[a2k], h2);
3016 ra22 = iprod(a2, a2); /* 5 */
3017 rb22 = iprod(b2, b2); /* 5 */
3018 rg22 = iprod(r2_kj, r2_kj); /* 5 */
3024 rabr2 = sqrt(ra2r2 * rb2r2);
3026 sin_phi2 = rg2 * rabr2 * iprod(a2, h2) * (-1);
3028 if (cos_phi2 < -0.5 || cos_phi2 > 0.5)
3030 phi2 = std::asin(sin_phi2);
3040 phi2 = -M_PI - phi2;
3046 phi2 = std::acos(cos_phi2);
3054 xphi2 = phi2 + M_PI; /* 1 */
3056 /* Range mangling */
3059 xphi1 = xphi1 + 2 * M_PI;
3061 else if (xphi1 >= 2 * M_PI)
3063 xphi1 = xphi1 - 2 * M_PI;
3068 xphi2 = xphi2 + 2 * M_PI;
3070 else if (xphi2 >= 2 * M_PI)
3072 xphi2 = xphi2 - 2 * M_PI;
3075 /* Number of grid points */
3076 dx = 2 * M_PI / cmap_grid->grid_spacing;
3078 /* Where on the grid are we */
3079 iphi1 = static_cast<int>(xphi1 / dx);
3080 iphi2 = static_cast<int>(xphi2 / dx);
3082 iphi1 = cmap_setup_grid_index(iphi1, cmap_grid->grid_spacing, &ip1m1, &ip1p1, &ip1p2);
3083 iphi2 = cmap_setup_grid_index(iphi2, cmap_grid->grid_spacing, &ip2m1, &ip2p1, &ip2p2);
3085 pos1 = iphi1 * cmap_grid->grid_spacing + iphi2;
3086 pos2 = ip1p1 * cmap_grid->grid_spacing + iphi2;
3087 pos3 = ip1p1 * cmap_grid->grid_spacing + ip2p1;
3088 pos4 = iphi1 * cmap_grid->grid_spacing + ip2p1;
3090 ty[0] = cmapd[pos1 * 4];
3091 ty[1] = cmapd[pos2 * 4];
3092 ty[2] = cmapd[pos3 * 4];
3093 ty[3] = cmapd[pos4 * 4];
3095 ty1[0] = cmapd[pos1 * 4 + 1];
3096 ty1[1] = cmapd[pos2 * 4 + 1];
3097 ty1[2] = cmapd[pos3 * 4 + 1];
3098 ty1[3] = cmapd[pos4 * 4 + 1];
3100 ty2[0] = cmapd[pos1 * 4 + 2];
3101 ty2[1] = cmapd[pos2 * 4 + 2];
3102 ty2[2] = cmapd[pos3 * 4 + 2];
3103 ty2[3] = cmapd[pos4 * 4 + 2];
3105 ty12[0] = cmapd[pos1 * 4 + 3];
3106 ty12[1] = cmapd[pos2 * 4 + 3];
3107 ty12[2] = cmapd[pos3 * 4 + 3];
3108 ty12[3] = cmapd[pos4 * 4 + 3];
3110 /* Switch to degrees */
3111 dx = 360.0 / cmap_grid->grid_spacing;
3112 xphi1 = xphi1 * RAD2DEG;
3113 xphi2 = xphi2 * RAD2DEG;
3115 for (i = 0; i < 4; i++) /* 16 */
3118 tx[i + 4] = ty1[i] * dx;
3119 tx[i + 8] = ty2[i] * dx;
3120 tx[i + 12] = ty12[i] * dx * dx;
3123 real tc[16] = { 0 };
3124 for (int idx = 0; idx < 16; idx++) /* 1056 */
3126 for (int k = 0; k < 16; k++)
3128 tc[idx] += cmap_coeff_matrix[k * 16 + idx] * tx[k];
3132 tt = (xphi1 - iphi1 * dx) / dx;
3133 tu = (xphi2 - iphi2 * dx) / dx;
3139 for (i = 3; i >= 0; i--)
3141 l1 = loop_index[i][3];
3142 l2 = loop_index[i][2];
3143 l3 = loop_index[i][1];
3145 e = tt * e + ((tc[i * 4 + 3] * tu + tc[i * 4 + 2]) * tu + tc[i * 4 + 1]) * tu + tc[i * 4];
3146 df1 = tu * df1 + (3.0 * tc[l1] * tt + 2.0 * tc[l2]) * tt + tc[l3];
3147 df2 = tt * df2 + (3.0 * tc[i * 4 + 3] * tu + 2.0 * tc[i * 4 + 2]) * tu + tc[i * 4 + 1];
3157 /* Do forces - first torsion */
3158 fg1 = iprod(r1_ij, r1_kj);
3159 hg1 = iprod(r1_kl, r1_kj);
3160 fga1 = fg1 * ra2r1 * rgr1;
3161 hgb1 = hg1 * rb2r1 * rgr1;
3162 gaa1 = -ra2r1 * rg1;
3165 for (i = 0; i < DIM; i++)
3167 dtf1[i] = gaa1 * a1[i];
3168 dtg1[i] = fga1 * a1[i] - hgb1 * b1[i];
3169 dth1[i] = gbb1 * b1[i];
3171 f1[i] = df1 * dtf1[i];
3172 g1[i] = df1 * dtg1[i];
3173 h1[i] = df1 * dth1[i];
3176 f1_j[i] = -f1[i] - g1[i];
3177 f1_k[i] = h1[i] + g1[i];
3180 f[a1i][i] = f[a1i][i] + f1_i[i];
3181 f[a1j][i] = f[a1j][i] + f1_j[i]; /* - f1[i] - g1[i] */
3182 f[a1k][i] = f[a1k][i] + f1_k[i]; /* h1[i] + g1[i] */
3183 f[a1l][i] = f[a1l][i] + f1_l[i]; /* h1[i] */
3186 /* Do forces - second torsion */
3187 fg2 = iprod(r2_ij, r2_kj);
3188 hg2 = iprod(r2_kl, r2_kj);
3189 fga2 = fg2 * ra2r2 * rgr2;
3190 hgb2 = hg2 * rb2r2 * rgr2;
3191 gaa2 = -ra2r2 * rg2;
3194 for (i = 0; i < DIM; i++)
3196 dtf2[i] = gaa2 * a2[i];
3197 dtg2[i] = fga2 * a2[i] - hgb2 * b2[i];
3198 dth2[i] = gbb2 * b2[i];
3200 f2[i] = df2 * dtf2[i];
3201 g2[i] = df2 * dtg2[i];
3202 h2[i] = df2 * dth2[i];
3205 f2_j[i] = -f2[i] - g2[i];
3206 f2_k[i] = h2[i] + g2[i];
3209 f[a2i][i] = f[a2i][i] + f2_i[i]; /* f2[i] */
3210 f[a2j][i] = f[a2j][i] + f2_j[i]; /* - f2[i] - g2[i] */
3211 f[a2k][i] = f[a2k][i] + f2_k[i]; /* h2[i] + g2[i] */
3212 f[a2l][i] = f[a2l][i] + f2_l[i]; /* - h2[i] */
3216 if (fshift != nullptr)
3220 t31 = pbc_rvec_sub(pbc, x[a1l], x[a1j], h1);
3221 t32 = pbc_rvec_sub(pbc, x[a2l], x[a2j], h2);
3229 rvec_inc(fshift[t11], f1_i);
3230 rvec_inc(fshift[CENTRAL], f1_j);
3231 rvec_inc(fshift[t21], f1_k);
3232 rvec_inc(fshift[t31], f1_l);
3234 rvec_inc(fshift[t12], f2_i);
3235 rvec_inc(fshift[CENTRAL], f2_j);
3236 rvec_inc(fshift[t22], f2_k);
3237 rvec_inc(fshift[t32], f2_l);
3247 /***********************************************************
3249 * G R O M O S 9 6 F U N C T I O N S
3251 ***********************************************************/
3252 real g96harmonic(real kA, real kB, real xA, real xB, real x, real lambda, real* V, real* F)
3254 const real half = 0.5;
3255 real L1, kk, x0, dx, dx2;
3256 real v, f, dvdlambda;
3259 kk = L1 * kA + lambda * kB;
3260 x0 = L1 * xA + lambda * xB;
3266 v = half * kk * dx2;
3267 dvdlambda = half * (kB - kA) * dx2 + (xA - xB) * kk * dx;
3274 /* That was 21 flops */
3277 template<BondedKernelFlavor flavor>
3278 real g96bonds(int nbonds,
3279 const t_iatom forceatoms[],
3280 const t_iparams forceparams[],
3287 const t_mdatoms gmx_unused* md,
3288 t_fcdata gmx_unused* fcd,
3289 int gmx_unused* global_atom_index)
3291 int i, ki, ai, aj, type;
3292 real dr2, fbond, vbond, vtot;
3296 for (i = 0; (i < nbonds);)
3298 type = forceatoms[i++];
3299 ai = forceatoms[i++];
3300 aj = forceatoms[i++];
3302 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
3303 dr2 = iprod(dx, dx); /* 5 */
3305 *dvdlambda += g96harmonic(forceparams[type].harmonic.krA, forceparams[type].harmonic.krB,
3306 forceparams[type].harmonic.rA, forceparams[type].harmonic.rB, dr2,
3307 lambda, &vbond, &fbond);
3309 vtot += 0.5 * vbond; /* 1*/
3311 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
3316 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)
3317 /* Return value is the angle between the bonds i-j and j-k */
3321 *t1 = pbc_rvec_sub(pbc, xi, xj, r_ij); /* 3 */
3322 *t2 = pbc_rvec_sub(pbc, xk, xj, r_kj); /* 3 */
3324 costh = cos_angle(r_ij, r_kj); /* 25 */
3329 template<BondedKernelFlavor flavor>
3330 real g96angles(int nbonds,
3331 const t_iatom forceatoms[],
3332 const t_iparams forceparams[],
3339 const t_mdatoms gmx_unused* md,
3340 t_fcdata gmx_unused* fcd,
3341 int gmx_unused* global_atom_index)
3343 int i, ai, aj, ak, type, m, t1, t2;
3345 real cos_theta, dVdt, va, vtot;
3346 real rij_1, rij_2, rkj_1, rkj_2, rijrkj_1;
3350 for (i = 0; (i < nbonds);)
3352 type = forceatoms[i++];
3353 ai = forceatoms[i++];
3354 aj = forceatoms[i++];
3355 ak = forceatoms[i++];
3357 cos_theta = g96bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &t1, &t2);
3359 *dvdlambda += g96harmonic(forceparams[type].harmonic.krA, forceparams[type].harmonic.krB,
3360 forceparams[type].harmonic.rA, forceparams[type].harmonic.rB,
3361 cos_theta, lambda, &va, &dVdt);
3364 rij_1 = gmx::invsqrt(iprod(r_ij, r_ij));
3365 rkj_1 = gmx::invsqrt(iprod(r_kj, r_kj));
3366 rij_2 = rij_1 * rij_1;
3367 rkj_2 = rkj_1 * rkj_1;
3368 rijrkj_1 = rij_1 * rkj_1; /* 23 */
3370 for (m = 0; (m < DIM); m++) /* 42 */
3372 f_i[m] = dVdt * (r_kj[m] * rijrkj_1 - r_ij[m] * rij_2 * cos_theta);
3373 f_k[m] = dVdt * (r_ij[m] * rijrkj_1 - r_kj[m] * rkj_2 * cos_theta);
3374 f_j[m] = -f_i[m] - f_k[m];
3380 if (computeVirial(flavor))
3382 rvec_inc(fshift[t1], f_i);
3383 rvec_inc(fshift[CENTRAL], f_j);
3384 rvec_inc(fshift[t2], f_k); /* 9 */
3391 template<BondedKernelFlavor flavor>
3392 real cross_bond_bond(int nbonds,
3393 const t_iatom forceatoms[],
3394 const t_iparams forceparams[],
3399 real gmx_unused lambda,
3400 real gmx_unused* dvdlambda,
3401 const t_mdatoms gmx_unused* md,
3402 t_fcdata gmx_unused* fcd,
3403 int gmx_unused* global_atom_index)
3405 /* Potential from Lawrence and Skimmer, Chem. Phys. Lett. 372 (2003)
3408 int i, ai, aj, ak, type, m, t1, t2;
3410 real vtot, vrr, s1, s2, r1, r2, r1e, r2e, krr;
3414 for (i = 0; (i < nbonds);)
3416 type = forceatoms[i++];
3417 ai = forceatoms[i++];
3418 aj = forceatoms[i++];
3419 ak = forceatoms[i++];
3420 r1e = forceparams[type].cross_bb.r1e;
3421 r2e = forceparams[type].cross_bb.r2e;
3422 krr = forceparams[type].cross_bb.krr;
3424 /* Compute distance vectors ... */
3425 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], r_ij);
3426 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], r_kj);
3428 /* ... and their lengths */
3432 /* Deviations from ideality */
3436 /* Energy (can be negative!) */
3437 vrr = krr * s1 * s2;
3441 svmul(-krr * s2 / r1, r_ij, f_i);
3442 svmul(-krr * s1 / r2, r_kj, f_k);
3444 for (m = 0; (m < DIM); m++) /* 12 */
3446 f_j[m] = -f_i[m] - f_k[m];
3452 if (computeVirial(flavor))
3454 rvec_inc(fshift[t1], f_i);
3455 rvec_inc(fshift[CENTRAL], f_j);
3456 rvec_inc(fshift[t2], f_k); /* 9 */
3463 template<BondedKernelFlavor flavor>
3464 real cross_bond_angle(int nbonds,
3465 const t_iatom forceatoms[],
3466 const t_iparams forceparams[],
3471 real gmx_unused lambda,
3472 real gmx_unused* dvdlambda,
3473 const t_mdatoms gmx_unused* md,
3474 t_fcdata gmx_unused* fcd,
3475 int gmx_unused* global_atom_index)
3477 /* Potential from Lawrence and Skimmer, Chem. Phys. Lett. 372 (2003)
3480 int i, ai, aj, ak, type, m, t1, t2;
3481 rvec r_ij, r_kj, r_ik;
3482 real vtot, vrt, s1, s2, s3, r1, r2, r3, r1e, r2e, r3e, krt, k1, k2, k3;
3486 for (i = 0; (i < nbonds);)
3488 type = forceatoms[i++];
3489 ai = forceatoms[i++];
3490 aj = forceatoms[i++];
3491 ak = forceatoms[i++];
3492 r1e = forceparams[type].cross_ba.r1e;
3493 r2e = forceparams[type].cross_ba.r2e;
3494 r3e = forceparams[type].cross_ba.r3e;
3495 krt = forceparams[type].cross_ba.krt;
3497 /* Compute distance vectors ... */
3498 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], r_ij);
3499 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], r_kj);
3500 pbc_rvec_sub(pbc, x[ai], x[ak], r_ik);
3502 /* ... and their lengths */
3507 /* Deviations from ideality */
3512 /* Energy (can be negative!) */
3513 vrt = krt * s3 * (s1 + s2);
3517 k1 = -krt * (s3 / r1);
3518 k2 = -krt * (s3 / r2);
3519 k3 = -krt * (s1 + s2) / r3;
3520 for (m = 0; (m < DIM); m++)
3522 f_i[m] = k1 * r_ij[m] + k3 * r_ik[m];
3523 f_k[m] = k2 * r_kj[m] - k3 * r_ik[m];
3524 f_j[m] = -f_i[m] - f_k[m];
3527 for (m = 0; (m < DIM); m++) /* 12 */
3534 if (computeVirial(flavor))
3536 rvec_inc(fshift[t1], f_i);
3537 rvec_inc(fshift[CENTRAL], f_j);
3538 rvec_inc(fshift[t2], f_k); /* 9 */
3545 /*! \brief Computes the potential and force for a tabulated potential */
3546 real bonded_tab(const char* type,
3548 const bondedtable_t* table,
3556 real k, tabscale, rt, eps, eps2, Yt, Ft, Geps, Heps2, Fp, VV, FF;
3560 k = (1.0 - lambda) * kA + lambda * kB;
3562 tabscale = table->scale;
3563 const real* VFtab = table->data.data();
3566 n0 = static_cast<int>(rt);
3570 "A tabulated %s interaction table number %d is out of the table range: r %f, "
3571 "between table indices %d and %d, table length %d",
3572 type, table_nr, r, n0, n0 + 1, table->n);
3578 Ft = VFtab[nnn + 1];
3579 Geps = VFtab[nnn + 2] * eps;
3580 Heps2 = VFtab[nnn + 3] * eps2;
3581 Fp = Ft + Geps + Heps2;
3583 FF = Fp + Geps + 2.0 * Heps2;
3585 *F = -k * FF * tabscale;
3587 dvdlambda = (kB - kA) * VV;
3591 /* That was 22 flops */
3594 template<BondedKernelFlavor flavor>
3595 real tab_bonds(int nbonds,
3596 const t_iatom forceatoms[],
3597 const t_iparams forceparams[],
3604 const t_mdatoms gmx_unused* md,
3606 int gmx_unused* global_atom_index)
3608 int i, ki, ai, aj, type, table;
3609 real dr, dr2, fbond, vbond, vtot;
3613 for (i = 0; (i < nbonds);)
3615 type = forceatoms[i++];
3616 ai = forceatoms[i++];
3617 aj = forceatoms[i++];
3619 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
3620 dr2 = iprod(dx, dx); /* 5 */
3621 dr = dr2 * gmx::invsqrt(dr2); /* 10 */
3623 table = forceparams[type].tab.table;
3625 *dvdlambda += bonded_tab("bond", table, &fcd->bondtab[table], forceparams[type].tab.kA,
3626 forceparams[type].tab.kB, dr, lambda, &vbond, &fbond); /* 22 */
3634 vtot += vbond; /* 1*/
3635 fbond *= gmx::invsqrt(dr2); /* 6 */
3637 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, fshift); /* 15 */
3642 template<BondedKernelFlavor flavor>
3643 real tab_angles(int nbonds,
3644 const t_iatom forceatoms[],
3645 const t_iparams forceparams[],
3652 const t_mdatoms gmx_unused* md,
3654 int gmx_unused* global_atom_index)
3656 int i, ai, aj, ak, t1, t2, type, table;
3658 real cos_theta, cos_theta2, theta, dVdt, va, vtot;
3661 for (i = 0; (i < nbonds);)
3663 type = forceatoms[i++];
3664 ai = forceatoms[i++];
3665 aj = forceatoms[i++];
3666 ak = forceatoms[i++];
3668 theta = bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
3670 table = forceparams[type].tab.table;
3672 *dvdlambda += bonded_tab("angle", table, &fcd->angletab[table], forceparams[type].tab.kA,
3673 forceparams[type].tab.kB, theta, lambda, &va, &dVdt); /* 22 */
3676 cos_theta2 = gmx::square(cos_theta); /* 1 */
3685 st = dVdt * gmx::invsqrt(1 - cos_theta2); /* 12 */
3686 sth = st * cos_theta; /* 1 */
3687 nrkj2 = iprod(r_kj, r_kj); /* 5 */
3688 nrij2 = iprod(r_ij, r_ij);
3690 cik = st * gmx::invsqrt(nrkj2 * nrij2); /* 12 */
3691 cii = sth / nrij2; /* 10 */
3692 ckk = sth / nrkj2; /* 10 */
3694 for (m = 0; (m < DIM); m++) /* 39 */
3696 f_i[m] = -(cik * r_kj[m] - cii * r_ij[m]);
3697 f_k[m] = -(cik * r_ij[m] - ckk * r_kj[m]);
3698 f_j[m] = -f_i[m] - f_k[m];
3704 if (computeVirial(flavor))
3706 rvec_inc(fshift[t1], f_i);
3707 rvec_inc(fshift[CENTRAL], f_j);
3708 rvec_inc(fshift[t2], f_k);
3715 template<BondedKernelFlavor flavor>
3716 real tab_dihs(int nbonds,
3717 const t_iatom forceatoms[],
3718 const t_iparams forceparams[],
3725 const t_mdatoms gmx_unused* md,
3727 int gmx_unused* global_atom_index)
3729 int i, type, ai, aj, ak, al, table;
3731 rvec r_ij, r_kj, r_kl, m, n;
3732 real phi, ddphi, vpd, vtot;
3735 for (i = 0; (i < nbonds);)
3737 type = forceatoms[i++];
3738 ai = forceatoms[i++];
3739 aj = forceatoms[i++];
3740 ak = forceatoms[i++];
3741 al = forceatoms[i++];
3743 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3); /* 84 */
3745 table = forceparams[type].tab.table;
3747 /* Hopefully phi+M_PI never results in values < 0 */
3748 *dvdlambda += bonded_tab("dihedral", table, &fcd->dihtab[table], forceparams[type].tab.kA,
3749 forceparams[type].tab.kB, phi + M_PI, lambda, &vpd, &ddphi);
3752 do_dih_fup<flavor>(ai, aj, ak, al, -ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1,
3760 struct BondedInteractions
3762 BondedFunction function;
3766 // Bug in old clang versions prevents constexpr. constexpr is needed for MSVC.
3767 #if defined(__clang__) && __clang_major__ < 6
3768 # define CONSTEXPR_EXCL_OLD_CLANG const
3770 # define CONSTEXPR_EXCL_OLD_CLANG constexpr
3773 /*! \brief Lookup table of bonded interaction functions
3775 * This must have as many entries as interaction_function in ifunc.cpp */
3776 template<BondedKernelFlavor flavor>
3777 CONSTEXPR_EXCL_OLD_CLANG std::array<BondedInteractions, F_NRE> c_bondedInteractionFunctions = {
3778 BondedInteractions{ bonds<flavor>, eNR_BONDS }, // F_BONDS
3779 BondedInteractions{ g96bonds<flavor>, eNR_BONDS }, // F_G96BONDS
3780 BondedInteractions{ morse_bonds<flavor>, eNR_MORSE }, // F_MORSE
3781 BondedInteractions{ cubic_bonds<flavor>, eNR_CUBICBONDS }, // F_CUBICBONDS
3782 BondedInteractions{ unimplemented, -1 }, // F_CONNBONDS
3783 BondedInteractions{ bonds<flavor>, eNR_BONDS }, // F_HARMONIC
3784 BondedInteractions{ FENE_bonds<flavor>, eNR_FENEBONDS }, // F_FENEBONDS
3785 BondedInteractions{ tab_bonds<flavor>, eNR_TABBONDS }, // F_TABBONDS
3786 BondedInteractions{ tab_bonds<flavor>, eNR_TABBONDS }, // F_TABBONDSNC
3787 BondedInteractions{ restraint_bonds<flavor>, eNR_RESTRBONDS }, // F_RESTRBONDS
3788 BondedInteractions{ angles<flavor>, eNR_ANGLES }, // F_ANGLES
3789 BondedInteractions{ g96angles<flavor>, eNR_ANGLES }, // F_G96ANGLES
3790 BondedInteractions{ restrangles<flavor>, eNR_ANGLES }, // F_RESTRANGLES
3791 BondedInteractions{ linear_angles<flavor>, eNR_ANGLES }, // F_LINEAR_ANGLES
3792 BondedInteractions{ cross_bond_bond<flavor>, eNR_CROSS_BOND_BOND }, // F_CROSS_BOND_BONDS
3793 BondedInteractions{ cross_bond_angle<flavor>, eNR_CROSS_BOND_ANGLE }, // F_CROSS_BOND_ANGLES
3794 BondedInteractions{ urey_bradley<flavor>, eNR_UREY_BRADLEY }, // F_UREY_BRADLEY
3795 BondedInteractions{ quartic_angles<flavor>, eNR_QANGLES }, // F_QUARTIC_ANGLES
3796 BondedInteractions{ tab_angles<flavor>, eNR_TABANGLES }, // F_TABANGLES
3797 BondedInteractions{ pdihs<flavor>, eNR_PROPER }, // F_PDIHS
3798 BondedInteractions{ rbdihs<flavor>, eNR_RB }, // F_RBDIHS
3799 BondedInteractions{ restrdihs<flavor>, eNR_PROPER }, // F_RESTRDIHS
3800 BondedInteractions{ cbtdihs<flavor>, eNR_RB }, // F_CBTDIHS
3801 BondedInteractions{ rbdihs<flavor>, eNR_FOURDIH }, // F_FOURDIHS
3802 BondedInteractions{ idihs<flavor>, eNR_IMPROPER }, // F_IDIHS
3803 BondedInteractions{ pdihs<flavor>, eNR_IMPROPER }, // F_PIDIHS
3804 BondedInteractions{ tab_dihs<flavor>, eNR_TABDIHS }, // F_TABDIHS
3805 BondedInteractions{ unimplemented, eNR_CMAP }, // F_CMAP
3806 BondedInteractions{ unimplemented, -1 }, // F_GB12_NOLONGERUSED
3807 BondedInteractions{ unimplemented, -1 }, // F_GB13_NOLONGERUSED
3808 BondedInteractions{ unimplemented, -1 }, // F_GB14_NOLONGERUSED
3809 BondedInteractions{ unimplemented, -1 }, // F_GBPOL_NOLONGERUSED
3810 BondedInteractions{ unimplemented, -1 }, // F_NPSOLVATION_NOLONGERUSED
3811 BondedInteractions{ unimplemented, eNR_NB14 }, // F_LJ14
3812 BondedInteractions{ unimplemented, -1 }, // F_COUL14
3813 BondedInteractions{ unimplemented, eNR_NB14 }, // F_LJC14_Q
3814 BondedInteractions{ unimplemented, eNR_NB14 }, // F_LJC_PAIRS_NB
3815 BondedInteractions{ unimplemented, -1 }, // F_LJ
3816 BondedInteractions{ unimplemented, -1 }, // F_BHAM
3817 BondedInteractions{ unimplemented, -1 }, // F_LJ_LR_NOLONGERUSED
3818 BondedInteractions{ unimplemented, -1 }, // F_BHAM_LR_NOLONGERUSED
3819 BondedInteractions{ unimplemented, -1 }, // F_DISPCORR
3820 BondedInteractions{ unimplemented, -1 }, // F_COUL_SR
3821 BondedInteractions{ unimplemented, -1 }, // F_COUL_LR_NOLONGERUSED
3822 BondedInteractions{ unimplemented, -1 }, // F_RF_EXCL
3823 BondedInteractions{ unimplemented, -1 }, // F_COUL_RECIP
3824 BondedInteractions{ unimplemented, -1 }, // F_LJ_RECIP
3825 BondedInteractions{ unimplemented, -1 }, // F_DPD
3826 BondedInteractions{ polarize<flavor>, eNR_POLARIZE }, // F_POLARIZATION
3827 BondedInteractions{ water_pol<flavor>, eNR_WPOL }, // F_WATER_POL
3828 BondedInteractions{ thole_pol<flavor>, eNR_THOLE }, // F_THOLE_POL
3829 BondedInteractions{ anharm_polarize<flavor>, eNR_ANHARM_POL }, // F_ANHARM_POL
3830 BondedInteractions{ unimplemented, -1 }, // F_POSRES
3831 BondedInteractions{ unimplemented, -1 }, // F_FBPOSRES
3832 BondedInteractions{ ta_disres, eNR_DISRES }, // F_DISRES
3833 BondedInteractions{ unimplemented, -1 }, // F_DISRESVIOL
3834 BondedInteractions{ orires, eNR_ORIRES }, // F_ORIRES
3835 BondedInteractions{ unimplemented, -1 }, // F_ORIRESDEV
3836 BondedInteractions{ angres<flavor>, eNR_ANGRES }, // F_ANGRES
3837 BondedInteractions{ angresz<flavor>, eNR_ANGRESZ }, // F_ANGRESZ
3838 BondedInteractions{ dihres<flavor>, eNR_DIHRES }, // F_DIHRES
3839 BondedInteractions{ unimplemented, -1 }, // F_DIHRESVIOL
3840 BondedInteractions{ unimplemented, -1 }, // F_CONSTR
3841 BondedInteractions{ unimplemented, -1 }, // F_CONSTRNC
3842 BondedInteractions{ unimplemented, -1 }, // F_SETTLE
3843 BondedInteractions{ unimplemented, -1 }, // F_VSITE2
3844 BondedInteractions{ unimplemented, -1 }, // F_VSITE3
3845 BondedInteractions{ unimplemented, -1 }, // F_VSITE3FD
3846 BondedInteractions{ unimplemented, -1 }, // F_VSITE3FAD
3847 BondedInteractions{ unimplemented, -1 }, // F_VSITE3OUT
3848 BondedInteractions{ unimplemented, -1 }, // F_VSITE4FD
3849 BondedInteractions{ unimplemented, -1 }, // F_VSITE4FDN
3850 BondedInteractions{ unimplemented, -1 }, // F_VSITEN
3851 BondedInteractions{ unimplemented, -1 }, // F_COM_PULL
3852 BondedInteractions{ unimplemented, -1 }, // F_DENSITYFITTING
3853 BondedInteractions{ unimplemented, -1 }, // F_EQM
3854 BondedInteractions{ unimplemented, -1 }, // F_EPOT
3855 BondedInteractions{ unimplemented, -1 }, // F_EKIN
3856 BondedInteractions{ unimplemented, -1 }, // F_ETOT
3857 BondedInteractions{ unimplemented, -1 }, // F_ECONSERVED
3858 BondedInteractions{ unimplemented, -1 }, // F_TEMP
3859 BondedInteractions{ unimplemented, -1 }, // F_VTEMP_NOLONGERUSED
3860 BondedInteractions{ unimplemented, -1 }, // F_PDISPCORR
3861 BondedInteractions{ unimplemented, -1 }, // F_PRES
3862 BondedInteractions{ unimplemented, -1 }, // F_DVDL_CONSTR
3863 BondedInteractions{ unimplemented, -1 }, // F_DVDL
3864 BondedInteractions{ unimplemented, -1 }, // F_DKDL
3865 BondedInteractions{ unimplemented, -1 }, // F_DVDL_COUL
3866 BondedInteractions{ unimplemented, -1 }, // F_DVDL_VDW
3867 BondedInteractions{ unimplemented, -1 }, // F_DVDL_BONDED
3868 BondedInteractions{ unimplemented, -1 }, // F_DVDL_RESTRAINT
3869 BondedInteractions{ unimplemented, -1 }, // F_DVDL_TEMPERATURE
3872 /*! \brief List of instantiated BondedInteractions list */
3873 CONSTEXPR_EXCL_OLD_CLANG
3874 gmx::EnumerationArray<BondedKernelFlavor, std::array<BondedInteractions, F_NRE>> c_bondedInteractionFunctionsPerFlavor = {
3875 c_bondedInteractionFunctions<BondedKernelFlavor::ForcesSimdWhenAvailable>,
3876 c_bondedInteractionFunctions<BondedKernelFlavor::ForcesNoSimd>,
3877 c_bondedInteractionFunctions<BondedKernelFlavor::ForcesAndVirialAndEnergy>,
3878 c_bondedInteractionFunctions<BondedKernelFlavor::ForcesAndEnergy>
3885 real calculateSimpleBond(const int ftype,
3886 const int numForceatoms,
3887 const t_iatom forceatoms[],
3888 const t_iparams forceparams[],
3892 const struct t_pbc* pbc,
3895 const t_mdatoms* md,
3897 int gmx_unused* global_atom_index,
3898 const BondedKernelFlavor bondedKernelFlavor)
3900 const BondedInteractions& bonded = c_bondedInteractionFunctionsPerFlavor[bondedKernelFlavor][ftype];
3902 real v = bonded.function(numForceatoms, forceatoms, forceparams, x, f, fshift, pbc, lambda,
3903 dvdlambda, md, fcd, global_atom_index);
3908 int nrnbIndex(int ftype)
3910 return c_bondedInteractionFunctions<BondedKernelFlavor::ForcesAndVirialAndEnergy>[ftype].nrnbIndex;