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,2018,2019, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
39 * \brief This file defines low-level functions necessary for
40 * computing energies and forces for listed interactions.
42 * \author Mark Abraham <mark.j.abraham@gmail.com>
44 * \ingroup module_listed_forces
57 #include "gromacs/gmxlib/nrnb.h"
58 #include "gromacs/listed_forces/disre.h"
59 #include "gromacs/listed_forces/orires.h"
60 #include "gromacs/math/functions.h"
61 #include "gromacs/math/units.h"
62 #include "gromacs/math/utilities.h"
63 #include "gromacs/math/vec.h"
64 #include "gromacs/mdtypes/fcdata.h"
65 #include "gromacs/mdtypes/mdatom.h"
66 #include "gromacs/pbcutil/ishift.h"
67 #include "gromacs/pbcutil/mshift.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, const t_iatom iatoms[],
89 const t_iparams iparams[],
90 const rvec x[], rvec4 f[], rvec fshift[],
91 const t_pbc *pbc, const t_graph *g,
92 real lambda, real *dvdlambda,
93 const t_mdatoms *md, t_fcdata *fcd,
96 /*! \brief Mysterious CMAP coefficient matrix */
97 const int cmap_coeff_matrix[] = {
98 1, 0, -3, 2, 0, 0, 0, 0, -3, 0, 9, -6, 2, 0, -6, 4,
99 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, -9, 6, -2, 0, 6, -4,
100 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, -6, 0, 0, -6, 4,
101 0, 0, 3, -2, 0, 0, 0, 0, 0, 0, -9, 6, 0, 0, 6, -4,
102 0, 0, 0, 0, 1, 0, -3, 2, -2, 0, 6, -4, 1, 0, -3, 2,
103 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 3, -2, 1, 0, -3, 2,
104 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 2, 0, 0, 3, -2,
105 0, 0, 0, 0, 0, 0, 3, -2, 0, 0, -6, 4, 0, 0, 3, -2,
106 0, 1, -2, 1, 0, 0, 0, 0, 0, -3, 6, -3, 0, 2, -4, 2,
107 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, -6, 3, 0, -2, 4, -2,
108 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, 2, -2,
109 0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 3, -3, 0, 0, -2, 2,
110 0, 0, 0, 0, 0, 1, -2, 1, 0, -2, 4, -2, 0, 1, -2, 1,
111 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 2, -1, 0, 1, -2, 1,
112 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, const rvec xj, const rvec xk, const t_pbc *pbc,
137 rvec r_ij, rvec r_kj, real *costh,
139 /* Return value is the angle between the bonds i-j and j-k */
144 *t1 = pbc_rvec_sub(pbc, xi, xj, r_ij); /* 3 */
145 *t2 = pbc_rvec_sub(pbc, xk, xj, r_kj); /* 3 */
147 *costh = cos_angle(r_ij, r_kj); /* 25 */
148 th = std::acos(*costh); /* 10 */
153 real dih_angle(const rvec xi, const rvec xj, const rvec xk, const rvec xl,
155 rvec r_ij, rvec r_kj, rvec r_kl, rvec m, rvec n,
156 int *t1, int *t2, int *t3)
158 *t1 = pbc_rvec_sub(pbc, xi, xj, r_ij); /* 3 */
159 *t2 = pbc_rvec_sub(pbc, xk, xj, r_kj); /* 3 */
160 *t3 = pbc_rvec_sub(pbc, xk, xl, r_kl); /* 3 */
162 cprod(r_ij, r_kj, m); /* 9 */
163 cprod(r_kj, r_kl, n); /* 9 */
164 real phi = gmx_angle(m, n); /* 49 (assuming 25 for atan2) */
165 real ipr = iprod(r_ij, n); /* 5 */
166 real sign = (ipr < 0.0) ? -1.0 : 1.0;
167 phi = sign*phi; /* 1 */
173 void make_dp_periodic(real *dp) /* 1 flop? */
175 /* dp cannot be outside (-pi,pi) */
180 else if (*dp < -M_PI)
189 /*! \brief Spreads and accumulates the bonded forces to the two atoms and adds the virial contribution when needed
191 * When \p g==nullptr, \p shiftIndex is used as the periodic shift.
192 * When \p g!=nullptr, the graph is used to compute the periodic shift.
194 template <BondedKernelFlavor flavor>
195 inline void spreadBondForces(const real bondForce,
204 if (computeVirial(flavor) && g)
207 ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, aj), dt);
208 shiftIndex = IVEC2IS(dt);
211 for (int m = 0; m < DIM; m++) /* 15 */
213 const real fij = bondForce*dx[m];
216 if (computeVirial(flavor))
218 fshift[shiftIndex][m] += fij;
219 fshift[CENTRAL][m] -= fij;
224 /*! \brief Morse potential bond
226 * By Frank Everdij. Three parameters needed:
228 * b0 = equilibrium distance in nm
229 * be = beta in nm^-1 (actually, it's nu_e*Sqrt(2*pi*pi*mu/D_e))
230 * cb = well depth in kJ/mol
232 * Note: the potential is referenced to be +cb at infinite separation
233 * and zero at the equilibrium distance!
235 template <BondedKernelFlavor flavor>
236 real morse_bonds(int nbonds,
237 const t_iatom forceatoms[], const t_iparams forceparams[],
238 const rvec x[], rvec4 f[], rvec fshift[],
239 const t_pbc *pbc, const t_graph *g,
240 real lambda, real *dvdlambda,
241 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
242 int gmx_unused *global_atom_index)
244 const real one = 1.0;
245 const real two = 2.0;
246 real dr, dr2, temp, omtemp, cbomtemp, fbond, vbond, vtot;
247 real b0, be, cb, b0A, beA, cbA, b0B, beB, cbB, L1;
249 int i, ki, type, ai, aj;
252 for (i = 0; (i < nbonds); )
254 type = forceatoms[i++];
255 ai = forceatoms[i++];
256 aj = forceatoms[i++];
258 b0A = forceparams[type].morse.b0A;
259 beA = forceparams[type].morse.betaA;
260 cbA = forceparams[type].morse.cbA;
262 b0B = forceparams[type].morse.b0B;
263 beB = forceparams[type].morse.betaB;
264 cbB = forceparams[type].morse.cbB;
266 L1 = one-lambda; /* 1 */
267 b0 = L1*b0A + lambda*b0B; /* 3 */
268 be = L1*beA + lambda*beB; /* 3 */
269 cb = L1*cbA + lambda*cbB; /* 3 */
271 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
272 dr2 = iprod(dx, dx); /* 5 */
273 dr = dr2*gmx::invsqrt(dr2); /* 10 */
274 temp = std::exp(-be*(dr-b0)); /* 12 */
278 /* bonds are constrainted. This may _not_ include bond constraints if they are lambda dependent */
279 *dvdlambda += cbB-cbA;
283 omtemp = one-temp; /* 1 */
284 cbomtemp = cb*omtemp; /* 1 */
285 vbond = cbomtemp*omtemp; /* 1 */
286 fbond = -two*be*temp*cbomtemp*gmx::invsqrt(dr2); /* 9 */
287 vtot += vbond; /* 1 */
289 *dvdlambda += (cbB - cbA) * omtemp * omtemp - (2-2*omtemp)*omtemp * cb * ((b0B-b0A)*be - (beB-beA)*(dr-b0)); /* 15 */
291 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, g, fshift); /* 15 */
297 template <BondedKernelFlavor flavor>
298 real cubic_bonds(int nbonds,
299 const t_iatom forceatoms[], const t_iparams forceparams[],
300 const rvec x[], rvec4 f[], rvec fshift[],
301 const t_pbc *pbc, const t_graph *g,
302 real gmx_unused lambda, real gmx_unused *dvdlambda,
303 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
304 int gmx_unused *global_atom_index)
306 const real three = 3.0;
307 const real two = 2.0;
309 real dr, dr2, dist, kdist, kdist2, fbond, vbond, vtot;
311 int i, ki, type, ai, aj;
314 for (i = 0; (i < nbonds); )
316 type = forceatoms[i++];
317 ai = forceatoms[i++];
318 aj = forceatoms[i++];
320 b0 = forceparams[type].cubic.b0;
321 kb = forceparams[type].cubic.kb;
322 kcub = forceparams[type].cubic.kcub;
324 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
325 dr2 = iprod(dx, dx); /* 5 */
332 dr = dr2*gmx::invsqrt(dr2); /* 10 */
337 vbond = kdist2 + kcub*kdist2*dist;
338 fbond = -(two*kdist + three*kdist2*kcub)/dr;
340 vtot += vbond; /* 21 */
342 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, g, fshift); /* 15 */
347 template <BondedKernelFlavor flavor>
348 real FENE_bonds(int nbonds,
349 const t_iatom forceatoms[], const t_iparams forceparams[],
350 const rvec x[], rvec4 f[], rvec fshift[],
351 const t_pbc *pbc, const t_graph *g,
352 real gmx_unused lambda, real gmx_unused *dvdlambda,
353 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
354 int *global_atom_index)
356 const real half = 0.5;
357 const real one = 1.0;
359 real dr2, bm2, omdr2obm2, fbond, vbond, vtot;
361 int i, ki, type, ai, aj;
364 for (i = 0; (i < nbonds); )
366 type = forceatoms[i++];
367 ai = forceatoms[i++];
368 aj = forceatoms[i++];
370 bm = forceparams[type].fene.bm;
371 kb = forceparams[type].fene.kb;
373 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
374 dr2 = iprod(dx, dx); /* 5 */
386 "r^2 (%f) >= bm^2 (%f) in FENE bond between atoms %d and %d",
388 glatnr(global_atom_index, ai),
389 glatnr(global_atom_index, aj));
392 omdr2obm2 = one - dr2/bm2;
394 vbond = -half*kb*bm2*std::log(omdr2obm2);
395 fbond = -kb/omdr2obm2;
397 vtot += vbond; /* 35 */
399 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, g, fshift); /* 15 */
404 real harmonic(real kA, real kB, real xA, real xB, real x, real lambda,
407 const real half = 0.5;
408 real L1, kk, x0, dx, dx2;
409 real v, f, dvdlambda;
412 kk = L1*kA+lambda*kB;
413 x0 = L1*xA+lambda*xB;
420 dvdlambda = half*(kB-kA)*dx2 + (xA-xB)*kk*dx;
427 /* That was 19 flops */
431 template <BondedKernelFlavor flavor>
432 real bonds(int nbonds,
433 const t_iatom forceatoms[], const t_iparams forceparams[],
434 const rvec x[], rvec4 f[], rvec fshift[],
435 const t_pbc *pbc, const t_graph *g,
436 real lambda, real *dvdlambda,
437 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
438 int gmx_unused *global_atom_index)
440 int i, ki, ai, aj, type;
441 real dr, dr2, fbond, vbond, vtot;
445 for (i = 0; (i < nbonds); )
447 type = forceatoms[i++];
448 ai = forceatoms[i++];
449 aj = forceatoms[i++];
451 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
452 dr2 = iprod(dx, dx); /* 5 */
453 dr = std::sqrt(dr2); /* 10 */
455 *dvdlambda += harmonic(forceparams[type].harmonic.krA,
456 forceparams[type].harmonic.krB,
457 forceparams[type].harmonic.rA,
458 forceparams[type].harmonic.rB,
459 dr, lambda, &vbond, &fbond); /* 19 */
467 vtot += vbond; /* 1*/
468 fbond *= gmx::invsqrt(dr2); /* 6 */
470 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, g, fshift); /* 15 */
475 template <BondedKernelFlavor flavor>
476 real restraint_bonds(int nbonds,
477 const t_iatom forceatoms[], const t_iparams forceparams[],
478 const rvec x[], rvec4 f[], rvec fshift[],
479 const t_pbc *pbc, const t_graph *g,
480 real lambda, real *dvdlambda,
481 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
482 int gmx_unused *global_atom_index)
484 int i, ki, ai, aj, type;
485 real dr, dr2, fbond, vbond, vtot;
487 real low, dlow, up1, dup1, up2, dup2, k, dk;
494 for (i = 0; (i < nbonds); )
496 type = forceatoms[i++];
497 ai = forceatoms[i++];
498 aj = forceatoms[i++];
500 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
501 dr2 = iprod(dx, dx); /* 5 */
502 dr = dr2*gmx::invsqrt(dr2); /* 10 */
504 low = L1*forceparams[type].restraint.lowA + lambda*forceparams[type].restraint.lowB;
505 dlow = -forceparams[type].restraint.lowA + forceparams[type].restraint.lowB;
506 up1 = L1*forceparams[type].restraint.up1A + lambda*forceparams[type].restraint.up1B;
507 dup1 = -forceparams[type].restraint.up1A + forceparams[type].restraint.up1B;
508 up2 = L1*forceparams[type].restraint.up2A + lambda*forceparams[type].restraint.up2B;
509 dup2 = -forceparams[type].restraint.up2A + forceparams[type].restraint.up2B;
510 k = L1*forceparams[type].restraint.kA + lambda*forceparams[type].restraint.kB;
511 dk = -forceparams[type].restraint.kA + forceparams[type].restraint.kB;
520 *dvdlambda += 0.5*dk*drh2 - k*dlow*drh;
533 *dvdlambda += 0.5*dk*drh2 - k*dup1*drh;
538 vbond = k*(up2 - up1)*(0.5*(up2 - up1) + drh);
539 fbond = -k*(up2 - up1);
540 *dvdlambda += dk*(up2 - up1)*(0.5*(up2 - up1) + drh)
541 + k*(dup2 - dup1)*(up2 - up1 + drh)
542 - k*(up2 - up1)*dup2;
550 vtot += vbond; /* 1*/
551 fbond *= gmx::invsqrt(dr2); /* 6 */
553 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, g, fshift); /* 15 */
559 template <BondedKernelFlavor flavor>
560 real polarize(int nbonds,
561 const t_iatom forceatoms[], const t_iparams forceparams[],
562 const rvec x[], rvec4 f[], rvec fshift[],
563 const t_pbc *pbc, const t_graph *g,
564 real lambda, real *dvdlambda,
565 const t_mdatoms *md, t_fcdata gmx_unused *fcd,
566 int gmx_unused *global_atom_index)
568 int i, ki, ai, aj, type;
569 real dr, dr2, fbond, vbond, vtot, ksh;
573 for (i = 0; (i < nbonds); )
575 type = forceatoms[i++];
576 ai = forceatoms[i++];
577 aj = forceatoms[i++];
578 ksh = gmx::square(md->chargeA[aj])*ONE_4PI_EPS0/forceparams[type].polarize.alpha;
580 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
581 dr2 = iprod(dx, dx); /* 5 */
582 dr = std::sqrt(dr2); /* 10 */
584 *dvdlambda += harmonic(ksh, ksh, 0, 0, dr, lambda, &vbond, &fbond); /* 19 */
591 vtot += vbond; /* 1*/
592 fbond *= gmx::invsqrt(dr2); /* 6 */
594 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, g, fshift); /* 15 */
599 template <BondedKernelFlavor flavor>
600 real anharm_polarize(int nbonds,
601 const t_iatom forceatoms[], const t_iparams forceparams[],
602 const rvec x[], rvec4 f[], rvec fshift[],
603 const t_pbc *pbc, const t_graph *g,
604 real lambda, real *dvdlambda,
605 const t_mdatoms *md, t_fcdata gmx_unused *fcd,
606 int gmx_unused *global_atom_index)
608 int i, ki, ai, aj, type;
609 real dr, dr2, fbond, vbond, vtot, ksh, khyp, drcut, ddr, ddr3;
613 for (i = 0; (i < nbonds); )
615 type = forceatoms[i++];
616 ai = forceatoms[i++];
617 aj = forceatoms[i++];
618 ksh = gmx::square(md->chargeA[aj])*ONE_4PI_EPS0/forceparams[type].anharm_polarize.alpha; /* 7*/
619 khyp = forceparams[type].anharm_polarize.khyp;
620 drcut = forceparams[type].anharm_polarize.drcut;
622 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
623 dr2 = iprod(dx, dx); /* 5 */
624 dr = dr2*gmx::invsqrt(dr2); /* 10 */
626 *dvdlambda += harmonic(ksh, ksh, 0, 0, dr, lambda, &vbond, &fbond); /* 19 */
637 vbond += khyp*ddr*ddr3;
638 fbond -= 4*khyp*ddr3;
640 fbond *= gmx::invsqrt(dr2); /* 6 */
641 vtot += vbond; /* 1*/
643 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, g, fshift); /* 15 */
648 template <BondedKernelFlavor flavor>
649 real water_pol(int nbonds,
650 const t_iatom forceatoms[], const t_iparams forceparams[],
651 const rvec x[], rvec4 f[], rvec gmx_unused fshift[],
652 const t_pbc gmx_unused *pbc, const t_graph gmx_unused *g,
653 real gmx_unused lambda, real gmx_unused *dvdlambda,
654 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
655 int gmx_unused *global_atom_index)
657 /* This routine implements anisotropic polarizibility for water, through
658 * a shell connected to a dummy with spring constant that differ in the
659 * three spatial dimensions in the molecular frame.
661 int i, m, aO, aH1, aH2, aD, aS, type, type0, ki;
663 rvec dOH1, dOH2, dHH, dOD, dDS, nW, kk, dx, kdx, proj;
664 real vtot, fij, r_HH, r_OD, r_nW, tx, ty, tz, qS;
669 type0 = forceatoms[0];
671 qS = md->chargeA[aS];
672 kk[XX] = gmx::square(qS)*ONE_4PI_EPS0/forceparams[type0].wpol.al_x;
673 kk[YY] = gmx::square(qS)*ONE_4PI_EPS0/forceparams[type0].wpol.al_y;
674 kk[ZZ] = gmx::square(qS)*ONE_4PI_EPS0/forceparams[type0].wpol.al_z;
675 r_HH = 1.0/forceparams[type0].wpol.rHH;
676 for (i = 0; (i < nbonds); i += 6)
678 type = forceatoms[i];
681 gmx_fatal(FARGS, "Sorry, type = %d, type0 = %d, file = %s, line = %d",
682 type, type0, __FILE__, __LINE__);
684 aO = forceatoms[i+1];
685 aH1 = forceatoms[i+2];
686 aH2 = forceatoms[i+3];
687 aD = forceatoms[i+4];
688 aS = forceatoms[i+5];
690 /* Compute vectors describing the water frame */
691 pbc_rvec_sub(pbc, x[aH1], x[aO], dOH1);
692 pbc_rvec_sub(pbc, x[aH2], x[aO], dOH2);
693 pbc_rvec_sub(pbc, x[aH2], x[aH1], dHH);
694 pbc_rvec_sub(pbc, x[aD], x[aO], dOD);
695 ki = pbc_rvec_sub(pbc, x[aS], x[aD], dDS);
696 cprod(dOH1, dOH2, nW);
698 /* Compute inverse length of normal vector
699 * (this one could be precomputed, but I'm too lazy now)
701 r_nW = gmx::invsqrt(iprod(nW, nW));
702 /* This is for precision, but does not make a big difference,
705 r_OD = gmx::invsqrt(iprod(dOD, dOD));
707 /* Normalize the vectors in the water frame */
709 svmul(r_HH, dHH, dHH);
710 svmul(r_OD, dOD, dOD);
712 /* Compute displacement of shell along components of the vector */
713 dx[ZZ] = iprod(dDS, dOD);
714 /* Compute projection on the XY plane: dDS - dx[ZZ]*dOD */
715 for (m = 0; (m < DIM); m++)
717 proj[m] = dDS[m]-dx[ZZ]*dOD[m];
720 /*dx[XX] = iprod(dDS,nW);
721 dx[YY] = iprod(dDS,dHH);*/
722 dx[XX] = iprod(proj, nW);
723 for (m = 0; (m < DIM); m++)
725 proj[m] -= dx[XX]*nW[m];
727 dx[YY] = iprod(proj, dHH);
728 /* Now compute the forces and energy */
729 kdx[XX] = kk[XX]*dx[XX];
730 kdx[YY] = kk[YY]*dx[YY];
731 kdx[ZZ] = kk[ZZ]*dx[ZZ];
732 vtot += iprod(dx, kdx);
734 if (computeVirial(flavor) && g)
736 ivec_sub(SHIFT_IVEC(g, aS), SHIFT_IVEC(g, aD), dt);
740 for (m = 0; (m < DIM); m++)
742 /* This is a tensor operation but written out for speed */
749 if (computeVirial(flavor))
751 fshift[ki][m] += fij;
752 fshift[CENTRAL][m] -= fij;
760 template <BondedKernelFlavor flavor>
761 static real do_1_thole(const rvec xi, const rvec xj, rvec fi, rvec fj,
762 const t_pbc *pbc, real qq,
763 rvec fshift[], real afac)
766 real r12sq, r12_1, r12bar, v0, v1, fscal, ebar, fff;
769 t = pbc_rvec_sub(pbc, xi, xj, r12); /* 3 */
771 r12sq = iprod(r12, r12); /* 5 */
772 r12_1 = gmx::invsqrt(r12sq); /* 5 */
773 r12bar = afac/r12_1; /* 5 */
774 v0 = qq*ONE_4PI_EPS0*r12_1; /* 2 */
775 ebar = std::exp(-r12bar); /* 5 */
776 v1 = (1-(1+0.5*r12bar)*ebar); /* 4 */
777 fscal = ((v0*r12_1)*v1 - v0*0.5*afac*ebar*(r12bar+1))*r12_1; /* 9 */
779 for (m = 0; (m < DIM); m++)
784 if (computeVirial(flavor))
787 fshift[CENTRAL][m] -= fff;
791 return v0*v1; /* 1 */
795 template <BondedKernelFlavor flavor>
796 real thole_pol(int nbonds,
797 const t_iatom forceatoms[], const t_iparams forceparams[],
798 const rvec x[], rvec4 f[], rvec fshift[],
799 const t_pbc *pbc, const t_graph gmx_unused *g,
800 real gmx_unused lambda, real gmx_unused *dvdlambda,
801 const t_mdatoms *md, t_fcdata gmx_unused *fcd,
802 int gmx_unused *global_atom_index)
804 /* Interaction between two pairs of particles with opposite charge */
805 int i, type, a1, da1, a2, da2;
806 real q1, q2, qq, a, al1, al2, afac;
809 for (i = 0; (i < nbonds); )
811 type = forceatoms[i++];
812 a1 = forceatoms[i++];
813 da1 = forceatoms[i++];
814 a2 = forceatoms[i++];
815 da2 = forceatoms[i++];
816 q1 = md->chargeA[da1];
817 q2 = md->chargeA[da2];
818 a = forceparams[type].thole.a;
819 al1 = forceparams[type].thole.alpha1;
820 al2 = forceparams[type].thole.alpha2;
822 afac = a*gmx::invsixthroot(al1*al2);
823 V += do_1_thole<flavor>(x[a1], x[a2], f[a1], f[a2], pbc, qq, fshift, afac);
824 V += do_1_thole<flavor>(x[da1], x[a2], f[da1], f[a2], pbc, -qq, fshift, afac);
825 V += do_1_thole<flavor>(x[a1], x[da2], f[a1], f[da2], pbc, -qq, fshift, afac);
826 V += do_1_thole<flavor>(x[da1], x[da2], f[da1], f[da2], pbc, qq, fshift, afac);
832 template <BondedKernelFlavor flavor>
833 std::enable_if_t<flavor != BondedKernelFlavor::ForcesSimdWhenAvailable || !GMX_SIMD_HAVE_REAL, real>
835 const t_iatom forceatoms[], const t_iparams forceparams[],
836 const rvec x[], rvec4 f[], rvec fshift[],
837 const t_pbc *pbc, const t_graph *g,
838 real lambda, real *dvdlambda,
839 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
840 int gmx_unused *global_atom_index)
842 int i, ai, aj, ak, t1, t2, type;
844 real cos_theta, cos_theta2, theta, dVdt, va, vtot;
845 ivec jt, dt_ij, dt_kj;
848 for (i = 0; i < nbonds; )
850 type = forceatoms[i++];
851 ai = forceatoms[i++];
852 aj = forceatoms[i++];
853 ak = forceatoms[i++];
855 theta = bond_angle(x[ai], x[aj], x[ak], pbc,
856 r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
858 *dvdlambda += harmonic(forceparams[type].harmonic.krA,
859 forceparams[type].harmonic.krB,
860 forceparams[type].harmonic.rA*DEG2RAD,
861 forceparams[type].harmonic.rB*DEG2RAD,
862 theta, lambda, &va, &dVdt); /* 21 */
865 cos_theta2 = gmx::square(cos_theta);
875 st = dVdt*gmx::invsqrt(1 - cos_theta2); /* 12 */
876 sth = st*cos_theta; /* 1 */
877 nrij2 = iprod(r_ij, r_ij); /* 5 */
878 nrkj2 = iprod(r_kj, r_kj); /* 5 */
880 nrij_1 = gmx::invsqrt(nrij2); /* 10 */
881 nrkj_1 = gmx::invsqrt(nrkj2); /* 10 */
883 cik = st*nrij_1*nrkj_1; /* 2 */
884 cii = sth*nrij_1*nrij_1; /* 2 */
885 ckk = sth*nrkj_1*nrkj_1; /* 2 */
887 for (m = 0; m < DIM; m++)
889 f_i[m] = -(cik*r_kj[m] - cii*r_ij[m]);
890 f_k[m] = -(cik*r_ij[m] - ckk*r_kj[m]);
891 f_j[m] = -f_i[m] - f_k[m];
896 if (computeVirial(flavor))
900 copy_ivec(SHIFT_IVEC(g, aj), jt);
902 ivec_sub(SHIFT_IVEC(g, ai), jt, dt_ij);
903 ivec_sub(SHIFT_IVEC(g, ak), jt, dt_kj);
907 rvec_inc(fshift[t1], f_i);
908 rvec_inc(fshift[CENTRAL], f_j);
909 rvec_inc(fshift[t2], f_k);
917 #if GMX_SIMD_HAVE_REAL
919 /* As angles, but using SIMD to calculate many angles at once.
920 * This routines does not calculate energies and shift forces.
922 template <BondedKernelFlavor flavor>
923 std::enable_if_t<flavor == BondedKernelFlavor::ForcesSimdWhenAvailable, real>
925 const t_iatom forceatoms[], const t_iparams forceparams[],
926 const rvec x[], rvec4 f[], rvec gmx_unused fshift[],
927 const t_pbc *pbc, const t_graph gmx_unused *g,
928 real gmx_unused lambda, real gmx_unused *dvdlambda,
929 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
930 int gmx_unused *global_atom_index)
935 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[GMX_SIMD_REAL_WIDTH];
936 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[GMX_SIMD_REAL_WIDTH];
937 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ak[GMX_SIMD_REAL_WIDTH];
938 alignas(GMX_SIMD_ALIGNMENT) real coeff[2*GMX_SIMD_REAL_WIDTH];
939 SimdReal deg2rad_S(DEG2RAD);
940 SimdReal xi_S, yi_S, zi_S;
941 SimdReal xj_S, yj_S, zj_S;
942 SimdReal xk_S, yk_S, zk_S;
943 SimdReal k_S, theta0_S;
944 SimdReal rijx_S, rijy_S, rijz_S;
945 SimdReal rkjx_S, rkjy_S, rkjz_S;
947 SimdReal min_one_plus_eps_S(-1.0 + 2.0*GMX_REAL_EPS); // Smallest number > -1
950 SimdReal nrij2_S, nrij_1_S;
951 SimdReal nrkj2_S, nrkj_1_S;
952 SimdReal cos_S, invsin_S;
954 SimdReal st_S, sth_S;
955 SimdReal cik_S, cii_S, ckk_S;
956 SimdReal f_ix_S, f_iy_S, f_iz_S;
957 SimdReal f_kx_S, f_ky_S, f_kz_S;
958 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9*GMX_SIMD_REAL_WIDTH];
960 set_pbc_simd(pbc, pbc_simd);
962 /* nbonds is the number of angles times nfa1, here we step GMX_SIMD_REAL_WIDTH angles */
963 for (i = 0; (i < nbonds); i += GMX_SIMD_REAL_WIDTH*nfa1)
965 /* Collect atoms for GMX_SIMD_REAL_WIDTH angles.
966 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
969 for (s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
971 type = forceatoms[iu];
972 ai[s] = forceatoms[iu+1];
973 aj[s] = forceatoms[iu+2];
974 ak[s] = forceatoms[iu+3];
976 /* At the end fill the arrays with the last atoms and 0 params */
977 if (i + s*nfa1 < nbonds)
979 coeff[s] = forceparams[type].harmonic.krA;
980 coeff[GMX_SIMD_REAL_WIDTH+s] = forceparams[type].harmonic.rA;
982 if (iu + nfa1 < nbonds)
990 coeff[GMX_SIMD_REAL_WIDTH+s] = 0;
994 /* Store the non PBC corrected distances packed and aligned */
995 gatherLoadUTranspose<3>(reinterpret_cast<const real *>(x), ai, &xi_S, &yi_S, &zi_S);
996 gatherLoadUTranspose<3>(reinterpret_cast<const real *>(x), aj, &xj_S, &yj_S, &zj_S);
997 gatherLoadUTranspose<3>(reinterpret_cast<const real *>(x), ak, &xk_S, &yk_S, &zk_S);
998 rijx_S = xi_S - xj_S;
999 rijy_S = yi_S - yj_S;
1000 rijz_S = zi_S - zj_S;
1001 rkjx_S = xk_S - xj_S;
1002 rkjy_S = yk_S - yj_S;
1003 rkjz_S = zk_S - zj_S;
1005 k_S = load<SimdReal>(coeff);
1006 theta0_S = load<SimdReal>(coeff+GMX_SIMD_REAL_WIDTH) * deg2rad_S;
1008 pbc_correct_dx_simd(&rijx_S, &rijy_S, &rijz_S, pbc_simd);
1009 pbc_correct_dx_simd(&rkjx_S, &rkjy_S, &rkjz_S, pbc_simd);
1011 rij_rkj_S = iprod(rijx_S, rijy_S, rijz_S,
1012 rkjx_S, rkjy_S, rkjz_S);
1014 nrij2_S = norm2(rijx_S, rijy_S, rijz_S);
1015 nrkj2_S = norm2(rkjx_S, rkjy_S, rkjz_S);
1017 nrij_1_S = invsqrt(nrij2_S);
1018 nrkj_1_S = invsqrt(nrkj2_S);
1020 cos_S = rij_rkj_S * nrij_1_S * nrkj_1_S;
1022 /* To allow for 180 degrees, we take the max of cos and -1 + 1bit,
1023 * so we can safely get the 1/sin from 1/sqrt(1 - cos^2).
1024 * This also ensures that rounding errors would cause the argument
1025 * of simdAcos to be < -1.
1026 * Note that we do not take precautions for cos(0)=1, so the outer
1027 * atoms in an angle should not be on top of each other.
1029 cos_S = max(cos_S, min_one_plus_eps_S);
1031 theta_S = acos(cos_S);
1033 invsin_S = invsqrt( one_S - cos_S * cos_S );
1035 st_S = k_S * (theta0_S - theta_S) * invsin_S;
1036 sth_S = st_S * cos_S;
1038 cik_S = st_S * nrij_1_S * nrkj_1_S;
1039 cii_S = sth_S * nrij_1_S * nrij_1_S;
1040 ckk_S = sth_S * nrkj_1_S * nrkj_1_S;
1042 f_ix_S = cii_S * rijx_S;
1043 f_ix_S = fnma(cik_S, rkjx_S, f_ix_S);
1044 f_iy_S = cii_S * rijy_S;
1045 f_iy_S = fnma(cik_S, rkjy_S, f_iy_S);
1046 f_iz_S = cii_S * rijz_S;
1047 f_iz_S = fnma(cik_S, rkjz_S, f_iz_S);
1048 f_kx_S = ckk_S * rkjx_S;
1049 f_kx_S = fnma(cik_S, rijx_S, f_kx_S);
1050 f_ky_S = ckk_S * rkjy_S;
1051 f_ky_S = fnma(cik_S, rijy_S, f_ky_S);
1052 f_kz_S = ckk_S * rkjz_S;
1053 f_kz_S = fnma(cik_S, rijz_S, f_kz_S);
1055 transposeScatterIncrU<4>(reinterpret_cast<real *>(f), ai, f_ix_S, f_iy_S, f_iz_S);
1056 transposeScatterDecrU<4>(reinterpret_cast<real *>(f), aj, f_ix_S + f_kx_S, f_iy_S + f_ky_S, f_iz_S + f_kz_S);
1057 transposeScatterIncrU<4>(reinterpret_cast<real *>(f), ak, f_kx_S, f_ky_S, f_kz_S);
1063 #endif // GMX_SIMD_HAVE_REAL
1065 template <BondedKernelFlavor flavor>
1066 real linear_angles(int nbonds,
1067 const t_iatom forceatoms[], const t_iparams forceparams[],
1068 const rvec x[], rvec4 f[], rvec fshift[],
1069 const t_pbc *pbc, const t_graph *g,
1070 real lambda, real *dvdlambda,
1071 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
1072 int gmx_unused *global_atom_index)
1074 int i, m, ai, aj, ak, t1, t2, type;
1076 real L1, kA, kB, aA, aB, dr, dr2, va, vtot, a, b, klin;
1077 ivec jt, dt_ij, dt_kj;
1078 rvec r_ij, r_kj, r_ik, dx;
1082 for (i = 0; (i < nbonds); )
1084 type = forceatoms[i++];
1085 ai = forceatoms[i++];
1086 aj = forceatoms[i++];
1087 ak = forceatoms[i++];
1089 kA = forceparams[type].linangle.klinA;
1090 kB = forceparams[type].linangle.klinB;
1091 klin = L1*kA + lambda*kB;
1093 aA = forceparams[type].linangle.aA;
1094 aB = forceparams[type].linangle.aB;
1095 a = L1*aA+lambda*aB;
1098 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], r_ij);
1099 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], r_kj);
1100 rvec_sub(r_ij, r_kj, r_ik);
1103 for (m = 0; (m < DIM); m++)
1105 dr = -a * r_ij[m] - b * r_kj[m];
1110 f_j[m] = -(f_i[m]+f_k[m]);
1116 *dvdlambda += 0.5*(kB-kA)*dr2 + klin*(aB-aA)*iprod(dx, r_ik);
1120 if (computeVirial(flavor))
1124 copy_ivec(SHIFT_IVEC(g, aj), jt);
1126 ivec_sub(SHIFT_IVEC(g, ai), jt, dt_ij);
1127 ivec_sub(SHIFT_IVEC(g, ak), jt, dt_kj);
1128 t1 = IVEC2IS(dt_ij);
1129 t2 = IVEC2IS(dt_kj);
1131 rvec_inc(fshift[t1], f_i);
1132 rvec_inc(fshift[CENTRAL], f_j);
1133 rvec_inc(fshift[t2], f_k);
1139 template <BondedKernelFlavor flavor>
1140 std::enable_if_t<flavor != BondedKernelFlavor::ForcesSimdWhenAvailable || !GMX_SIMD_HAVE_REAL, real>
1141 urey_bradley(int nbonds,
1142 const t_iatom forceatoms[], const t_iparams forceparams[],
1143 const rvec x[], rvec4 f[], rvec fshift[],
1144 const t_pbc *pbc, const t_graph *g,
1145 real lambda, real *dvdlambda,
1146 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
1147 int gmx_unused *global_atom_index)
1149 int i, m, ai, aj, ak, t1, t2, type, ki;
1150 rvec r_ij, r_kj, r_ik;
1151 real cos_theta, cos_theta2, theta;
1152 real dVdt, va, vtot, dr, dr2, vbond, fbond, fik;
1153 real kthA, th0A, kUBA, r13A, kthB, th0B, kUBB, r13B;
1154 ivec jt, dt_ij, dt_kj, dt_ik;
1157 for (i = 0; (i < nbonds); )
1159 type = forceatoms[i++];
1160 ai = forceatoms[i++];
1161 aj = forceatoms[i++];
1162 ak = forceatoms[i++];
1163 th0A = forceparams[type].u_b.thetaA*DEG2RAD;
1164 kthA = forceparams[type].u_b.kthetaA;
1165 r13A = forceparams[type].u_b.r13A;
1166 kUBA = forceparams[type].u_b.kUBA;
1167 th0B = forceparams[type].u_b.thetaB*DEG2RAD;
1168 kthB = forceparams[type].u_b.kthetaB;
1169 r13B = forceparams[type].u_b.r13B;
1170 kUBB = forceparams[type].u_b.kUBB;
1172 theta = bond_angle(x[ai], x[aj], x[ak], pbc,
1173 r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
1175 *dvdlambda += harmonic(kthA, kthB, th0A, th0B, theta, lambda, &va, &dVdt); /* 21 */
1178 ki = pbc_rvec_sub(pbc, x[ai], x[ak], r_ik); /* 3 */
1179 dr2 = iprod(r_ik, r_ik); /* 5 */
1180 dr = dr2*gmx::invsqrt(dr2); /* 10 */
1182 *dvdlambda += harmonic(kUBA, kUBB, r13A, r13B, dr, lambda, &vbond, &fbond); /* 19 */
1184 cos_theta2 = gmx::square(cos_theta); /* 1 */
1192 st = dVdt*gmx::invsqrt(1 - cos_theta2); /* 12 */
1193 sth = st*cos_theta; /* 1 */
1194 nrkj2 = iprod(r_kj, r_kj); /* 5 */
1195 nrij2 = iprod(r_ij, r_ij);
1197 cik = st*gmx::invsqrt(nrkj2*nrij2); /* 12 */
1198 cii = sth/nrij2; /* 10 */
1199 ckk = sth/nrkj2; /* 10 */
1201 for (m = 0; (m < DIM); m++) /* 39 */
1203 f_i[m] = -(cik*r_kj[m]-cii*r_ij[m]);
1204 f_k[m] = -(cik*r_ij[m]-ckk*r_kj[m]);
1205 f_j[m] = -f_i[m]-f_k[m];
1210 if (computeVirial(flavor))
1214 copy_ivec(SHIFT_IVEC(g, aj), jt);
1216 ivec_sub(SHIFT_IVEC(g, ai), jt, dt_ij);
1217 ivec_sub(SHIFT_IVEC(g, ak), jt, dt_kj);
1218 t1 = IVEC2IS(dt_ij);
1219 t2 = IVEC2IS(dt_kj);
1221 rvec_inc(fshift[t1], f_i);
1222 rvec_inc(fshift[CENTRAL], f_j);
1223 rvec_inc(fshift[t2], f_k);
1226 /* Time for the bond calculations */
1232 vtot += vbond; /* 1*/
1233 fbond *= gmx::invsqrt(dr2); /* 6 */
1235 if (computeVirial(flavor) && g)
1237 ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, ak), dt_ik);
1238 ki = IVEC2IS(dt_ik);
1240 for (m = 0; (m < DIM); m++) /* 15 */
1242 fik = fbond*r_ik[m];
1245 if (computeVirial(flavor))
1247 fshift[ki][m] += fik;
1248 fshift[CENTRAL][m] -= fik;
1255 #if GMX_SIMD_HAVE_REAL
1257 /* As urey_bradley, but using SIMD to calculate many potentials at once.
1258 * This routines does not calculate energies and shift forces.
1260 template <BondedKernelFlavor flavor>
1261 std::enable_if_t<flavor == BondedKernelFlavor::ForcesSimdWhenAvailable, real>
1262 urey_bradley(int nbonds,
1263 const t_iatom forceatoms[], const t_iparams forceparams[],
1264 const rvec x[], rvec4 f[], rvec gmx_unused fshift[],
1265 const t_pbc *pbc, const t_graph gmx_unused *g,
1266 real gmx_unused lambda, real gmx_unused *dvdlambda,
1267 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
1268 int gmx_unused *global_atom_index)
1270 constexpr int nfa1 = 4;
1271 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[GMX_SIMD_REAL_WIDTH];
1272 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[GMX_SIMD_REAL_WIDTH];
1273 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ak[GMX_SIMD_REAL_WIDTH];
1274 alignas(GMX_SIMD_ALIGNMENT) real coeff[4*GMX_SIMD_REAL_WIDTH];
1275 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9*GMX_SIMD_REAL_WIDTH];
1277 set_pbc_simd(pbc, pbc_simd);
1279 /* nbonds is the number of angles times nfa1, here we step GMX_SIMD_REAL_WIDTH angles */
1280 for (int i = 0; i < nbonds; i += GMX_SIMD_REAL_WIDTH*nfa1)
1282 /* Collect atoms for GMX_SIMD_REAL_WIDTH angles.
1283 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
1286 for (int s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
1288 const int type = forceatoms[iu];
1289 ai[s] = forceatoms[iu+1];
1290 aj[s] = forceatoms[iu+2];
1291 ak[s] = forceatoms[iu+3];
1293 /* At the end fill the arrays with the last atoms and 0 params */
1294 if (i + s*nfa1 < nbonds)
1296 coeff[s] = forceparams[type].u_b.kthetaA;
1297 coeff[GMX_SIMD_REAL_WIDTH+s] = forceparams[type].u_b.thetaA;
1298 coeff[GMX_SIMD_REAL_WIDTH*2+s] = forceparams[type].u_b.kUBA;
1299 coeff[GMX_SIMD_REAL_WIDTH*3+s] = forceparams[type].u_b.r13A;
1301 if (iu + nfa1 < nbonds)
1309 coeff[GMX_SIMD_REAL_WIDTH+s] = 0;
1310 coeff[GMX_SIMD_REAL_WIDTH*2+s] = 0;
1311 coeff[GMX_SIMD_REAL_WIDTH*3+s] = 0;
1315 SimdReal xi_S, yi_S, zi_S;
1316 SimdReal xj_S, yj_S, zj_S;
1317 SimdReal xk_S, yk_S, zk_S;
1319 /* Store the non PBC corrected distances packed and aligned */
1320 gatherLoadUTranspose<3>(reinterpret_cast<const real *>(x), ai, &xi_S, &yi_S, &zi_S);
1321 gatherLoadUTranspose<3>(reinterpret_cast<const real *>(x), aj, &xj_S, &yj_S, &zj_S);
1322 gatherLoadUTranspose<3>(reinterpret_cast<const real *>(x), ak, &xk_S, &yk_S, &zk_S);
1323 SimdReal rijx_S = xi_S - xj_S;
1324 SimdReal rijy_S = yi_S - yj_S;
1325 SimdReal rijz_S = zi_S - zj_S;
1326 SimdReal rkjx_S = xk_S - xj_S;
1327 SimdReal rkjy_S = yk_S - yj_S;
1328 SimdReal rkjz_S = zk_S - zj_S;
1329 SimdReal rikx_S = xi_S - xk_S;
1330 SimdReal riky_S = yi_S - yk_S;
1331 SimdReal rikz_S = zi_S - zk_S;
1333 const SimdReal ktheta_S = load<SimdReal>(coeff);
1334 const SimdReal theta0_S = load<SimdReal>(coeff+GMX_SIMD_REAL_WIDTH) * DEG2RAD;
1335 const SimdReal kUB_S = load<SimdReal>(coeff+2*GMX_SIMD_REAL_WIDTH);
1336 const SimdReal r13_S = load<SimdReal>(coeff+3*GMX_SIMD_REAL_WIDTH);
1338 pbc_correct_dx_simd(&rijx_S, &rijy_S, &rijz_S, pbc_simd);
1339 pbc_correct_dx_simd(&rkjx_S, &rkjy_S, &rkjz_S, pbc_simd);
1340 pbc_correct_dx_simd(&rikx_S, &riky_S, &rikz_S, pbc_simd);
1342 const SimdReal rij_rkj_S = iprod(rijx_S, rijy_S, rijz_S,
1343 rkjx_S, rkjy_S, rkjz_S);
1345 const SimdReal dr2_S = iprod(rikx_S, riky_S, rikz_S,
1346 rikx_S, riky_S, rikz_S);
1348 const SimdReal nrij2_S = norm2(rijx_S, rijy_S, rijz_S);
1349 const SimdReal nrkj2_S = norm2(rkjx_S, rkjy_S, rkjz_S);
1351 const SimdReal nrij_1_S = invsqrt(nrij2_S);
1352 const SimdReal nrkj_1_S = invsqrt(nrkj2_S);
1353 const SimdReal invdr2_S = invsqrt(dr2_S);
1354 const SimdReal dr_S = dr2_S*invdr2_S;
1356 constexpr real min_one_plus_eps = -1.0 + 2.0*GMX_REAL_EPS; // Smallest number > -1
1358 /* To allow for 180 degrees, we take the max of cos and -1 + 1bit,
1359 * so we can safely get the 1/sin from 1/sqrt(1 - cos^2).
1360 * This also ensures that rounding errors would cause the argument
1361 * of simdAcos to be < -1.
1362 * Note that we do not take precautions for cos(0)=1, so the bonds
1363 * in an angle should not align at an angle of 0 degrees.
1365 const SimdReal cos_S = max(rij_rkj_S * nrij_1_S * nrkj_1_S, min_one_plus_eps);
1367 const SimdReal theta_S = acos(cos_S);
1368 const SimdReal invsin_S = invsqrt( 1.0 - cos_S * cos_S );
1369 const SimdReal st_S = ktheta_S * (theta0_S - theta_S) * invsin_S;
1370 const SimdReal sth_S = st_S * cos_S;
1372 const SimdReal cik_S = st_S * nrij_1_S * nrkj_1_S;
1373 const SimdReal cii_S = sth_S * nrij_1_S * nrij_1_S;
1374 const SimdReal ckk_S = sth_S * nrkj_1_S * nrkj_1_S;
1376 const SimdReal sUB_S = kUB_S * (r13_S - dr_S) * invdr2_S;
1378 const SimdReal f_ikx_S = sUB_S * rikx_S;
1379 const SimdReal f_iky_S = sUB_S * riky_S;
1380 const SimdReal f_ikz_S = sUB_S * rikz_S;
1382 const SimdReal f_ix_S = fnma(cik_S, rkjx_S, cii_S * rijx_S) + f_ikx_S;
1383 const SimdReal f_iy_S = fnma(cik_S, rkjy_S, cii_S * rijy_S) + f_iky_S;
1384 const SimdReal f_iz_S = fnma(cik_S, rkjz_S, cii_S * rijz_S) + f_ikz_S;
1385 const SimdReal f_kx_S = fnma(cik_S, rijx_S, ckk_S * rkjx_S) - f_ikx_S;
1386 const SimdReal f_ky_S = fnma(cik_S, rijy_S, ckk_S * rkjy_S) - f_iky_S;
1387 const SimdReal f_kz_S = fnma(cik_S, rijz_S, ckk_S * rkjz_S) - f_ikz_S;
1389 transposeScatterIncrU<4>(reinterpret_cast<real *>(f), ai, f_ix_S, f_iy_S, f_iz_S);
1390 transposeScatterDecrU<4>(reinterpret_cast<real *>(f), aj, f_ix_S + f_kx_S, f_iy_S + f_ky_S, f_iz_S + f_kz_S);
1391 transposeScatterIncrU<4>(reinterpret_cast<real *>(f), ak, f_kx_S, f_ky_S, f_kz_S);
1397 #endif // GMX_SIMD_HAVE_REAL
1399 template <BondedKernelFlavor flavor>
1400 real quartic_angles(int nbonds,
1401 const t_iatom forceatoms[], const t_iparams forceparams[],
1402 const rvec x[], rvec4 f[], rvec fshift[],
1403 const t_pbc *pbc, const t_graph *g,
1404 real gmx_unused lambda, real gmx_unused *dvdlambda,
1405 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
1406 int gmx_unused *global_atom_index)
1408 int i, j, ai, aj, ak, t1, t2, type;
1410 real cos_theta, cos_theta2, theta, dt, dVdt, va, dtp, c, vtot;
1411 ivec jt, dt_ij, dt_kj;
1414 for (i = 0; (i < nbonds); )
1416 type = forceatoms[i++];
1417 ai = forceatoms[i++];
1418 aj = forceatoms[i++];
1419 ak = forceatoms[i++];
1421 theta = bond_angle(x[ai], x[aj], x[ak], pbc,
1422 r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
1424 dt = theta - forceparams[type].qangle.theta*DEG2RAD; /* 2 */
1427 va = forceparams[type].qangle.c[0];
1429 for (j = 1; j <= 4; j++)
1431 c = forceparams[type].qangle.c[j];
1440 cos_theta2 = gmx::square(cos_theta); /* 1 */
1449 st = dVdt*gmx::invsqrt(1 - cos_theta2); /* 12 */
1450 sth = st*cos_theta; /* 1 */
1451 nrkj2 = iprod(r_kj, r_kj); /* 5 */
1452 nrij2 = iprod(r_ij, r_ij);
1454 cik = st*gmx::invsqrt(nrkj2*nrij2); /* 12 */
1455 cii = sth/nrij2; /* 10 */
1456 ckk = sth/nrkj2; /* 10 */
1458 for (m = 0; (m < DIM); m++) /* 39 */
1460 f_i[m] = -(cik*r_kj[m]-cii*r_ij[m]);
1461 f_k[m] = -(cik*r_ij[m]-ckk*r_kj[m]);
1462 f_j[m] = -f_i[m]-f_k[m];
1468 if (computeVirial(flavor))
1472 copy_ivec(SHIFT_IVEC(g, aj), jt);
1474 ivec_sub(SHIFT_IVEC(g, ai), jt, dt_ij);
1475 ivec_sub(SHIFT_IVEC(g, ak), jt, dt_kj);
1476 t1 = IVEC2IS(dt_ij);
1477 t2 = IVEC2IS(dt_kj);
1479 rvec_inc(fshift[t1], f_i);
1480 rvec_inc(fshift[CENTRAL], f_j);
1481 rvec_inc(fshift[t2], f_k);
1489 #if GMX_SIMD_HAVE_REAL
1491 /* As dih_angle above, but calculates 4 dihedral angles at once using SIMD,
1492 * also calculates the pre-factor required for the dihedral force update.
1493 * Note that bv and buf should be register aligned.
1496 dih_angle_simd(const rvec *x,
1497 const int *ai, const int *aj, const int *ak, const int *al,
1498 const real *pbc_simd,
1500 SimdReal *mx_S, SimdReal *my_S, SimdReal *mz_S,
1501 SimdReal *nx_S, SimdReal *ny_S, SimdReal *nz_S,
1502 SimdReal *nrkj_m2_S,
1503 SimdReal *nrkj_n2_S,
1507 SimdReal xi_S, yi_S, zi_S;
1508 SimdReal xj_S, yj_S, zj_S;
1509 SimdReal xk_S, yk_S, zk_S;
1510 SimdReal xl_S, yl_S, zl_S;
1511 SimdReal rijx_S, rijy_S, rijz_S;
1512 SimdReal rkjx_S, rkjy_S, rkjz_S;
1513 SimdReal rklx_S, rkly_S, rklz_S;
1514 SimdReal cx_S, cy_S, cz_S;
1518 SimdReal iprm_S, iprn_S;
1519 SimdReal nrkj2_S, nrkj_1_S, nrkj_2_S, nrkj_S;
1521 SimdReal nrkj2_min_S;
1522 SimdReal real_eps_S;
1524 /* Used to avoid division by zero.
1525 * We take into acount that we multiply the result by real_eps_S.
1527 nrkj2_min_S = SimdReal(GMX_REAL_MIN/(2*GMX_REAL_EPS));
1529 /* The value of the last significant bit (GMX_REAL_EPS is half of that) */
1530 real_eps_S = SimdReal(2*GMX_REAL_EPS);
1532 /* Store the non PBC corrected distances packed and aligned */
1533 gatherLoadUTranspose<3>(reinterpret_cast<const real *>(x), ai, &xi_S, &yi_S, &zi_S);
1534 gatherLoadUTranspose<3>(reinterpret_cast<const real *>(x), aj, &xj_S, &yj_S, &zj_S);
1535 gatherLoadUTranspose<3>(reinterpret_cast<const real *>(x), ak, &xk_S, &yk_S, &zk_S);
1536 gatherLoadUTranspose<3>(reinterpret_cast<const real *>(x), al, &xl_S, &yl_S, &zl_S);
1537 rijx_S = xi_S - xj_S;
1538 rijy_S = yi_S - yj_S;
1539 rijz_S = zi_S - zj_S;
1540 rkjx_S = xk_S - xj_S;
1541 rkjy_S = yk_S - yj_S;
1542 rkjz_S = zk_S - zj_S;
1543 rklx_S = xk_S - xl_S;
1544 rkly_S = yk_S - yl_S;
1545 rklz_S = zk_S - zl_S;
1547 pbc_correct_dx_simd(&rijx_S, &rijy_S, &rijz_S, pbc_simd);
1548 pbc_correct_dx_simd(&rkjx_S, &rkjy_S, &rkjz_S, pbc_simd);
1549 pbc_correct_dx_simd(&rklx_S, &rkly_S, &rklz_S, pbc_simd);
1551 cprod(rijx_S, rijy_S, rijz_S,
1552 rkjx_S, rkjy_S, rkjz_S,
1555 cprod(rkjx_S, rkjy_S, rkjz_S,
1556 rklx_S, rkly_S, rklz_S,
1559 cprod(*mx_S, *my_S, *mz_S,
1560 *nx_S, *ny_S, *nz_S,
1561 &cx_S, &cy_S, &cz_S);
1563 cn_S = sqrt(norm2(cx_S, cy_S, cz_S));
1565 s_S = iprod(*mx_S, *my_S, *mz_S, *nx_S, *ny_S, *nz_S);
1567 /* Determine the dihedral angle, the sign might need correction */
1568 *phi_S = atan2(cn_S, s_S);
1570 ipr_S = iprod(rijx_S, rijy_S, rijz_S,
1571 *nx_S, *ny_S, *nz_S);
1573 iprm_S = norm2(*mx_S, *my_S, *mz_S);
1574 iprn_S = norm2(*nx_S, *ny_S, *nz_S);
1576 nrkj2_S = norm2(rkjx_S, rkjy_S, rkjz_S);
1578 /* Avoid division by zero. When zero, the result is multiplied by 0
1579 * anyhow, so the 3 max below do not affect the final result.
1581 nrkj2_S = max(nrkj2_S, nrkj2_min_S);
1582 nrkj_1_S = invsqrt(nrkj2_S);
1583 nrkj_2_S = nrkj_1_S * nrkj_1_S;
1584 nrkj_S = nrkj2_S * nrkj_1_S;
1586 toler_S = nrkj2_S * real_eps_S;
1588 /* Here the plain-C code uses a conditional, but we can't do that in SIMD.
1589 * So we take a max with the tolerance instead. Since we multiply with
1590 * m or n later, the max does not affect the results.
1592 iprm_S = max(iprm_S, toler_S);
1593 iprn_S = max(iprn_S, toler_S);
1594 *nrkj_m2_S = nrkj_S * inv(iprm_S);
1595 *nrkj_n2_S = nrkj_S * inv(iprn_S);
1597 /* Set sign of phi_S with the sign of ipr_S; phi_S is currently positive */
1598 *phi_S = copysign(*phi_S, ipr_S);
1599 *p_S = iprod(rijx_S, rijy_S, rijz_S, rkjx_S, rkjy_S, rkjz_S);
1600 *p_S = *p_S * nrkj_2_S;
1602 *q_S = iprod(rklx_S, rkly_S, rklz_S, rkjx_S, rkjy_S, rkjz_S);
1603 *q_S = *q_S * nrkj_2_S;
1606 #endif // GMX_SIMD_HAVE_REAL
1610 template <BondedKernelFlavor flavor>
1611 void do_dih_fup(int i, int j, int k, int l, real ddphi,
1612 rvec r_ij, rvec r_kj, rvec r_kl,
1613 rvec m, rvec n, rvec4 f[], rvec fshift[],
1614 const t_pbc *pbc, const t_graph *g,
1615 const rvec x[], int t1, int t2, int t3)
1618 rvec f_i, f_j, f_k, f_l;
1619 rvec uvec, vvec, svec, dx_jl;
1620 real iprm, iprn, nrkj, nrkj2, nrkj_1, nrkj_2;
1621 real a, b, p, q, toler;
1622 ivec jt, dt_ij, dt_kj, dt_lj;
1624 iprm = iprod(m, m); /* 5 */
1625 iprn = iprod(n, n); /* 5 */
1626 nrkj2 = iprod(r_kj, r_kj); /* 5 */
1627 toler = nrkj2*GMX_REAL_EPS;
1628 if ((iprm > toler) && (iprn > toler))
1630 nrkj_1 = gmx::invsqrt(nrkj2); /* 10 */
1631 nrkj_2 = nrkj_1*nrkj_1; /* 1 */
1632 nrkj = nrkj2*nrkj_1; /* 1 */
1633 a = -ddphi*nrkj/iprm; /* 11 */
1634 svmul(a, m, f_i); /* 3 */
1635 b = ddphi*nrkj/iprn; /* 11 */
1636 svmul(b, n, f_l); /* 3 */
1637 p = iprod(r_ij, r_kj); /* 5 */
1638 p *= nrkj_2; /* 1 */
1639 q = iprod(r_kl, r_kj); /* 5 */
1640 q *= nrkj_2; /* 1 */
1641 svmul(p, f_i, uvec); /* 3 */
1642 svmul(q, f_l, vvec); /* 3 */
1643 rvec_sub(uvec, vvec, svec); /* 3 */
1644 rvec_sub(f_i, svec, f_j); /* 3 */
1645 rvec_add(f_l, svec, f_k); /* 3 */
1646 rvec_inc(f[i], f_i); /* 3 */
1647 rvec_dec(f[j], f_j); /* 3 */
1648 rvec_dec(f[k], f_k); /* 3 */
1649 rvec_inc(f[l], f_l); /* 3 */
1651 if (computeVirial(flavor))
1655 copy_ivec(SHIFT_IVEC(g, j), jt);
1656 ivec_sub(SHIFT_IVEC(g, i), jt, dt_ij);
1657 ivec_sub(SHIFT_IVEC(g, k), jt, dt_kj);
1658 ivec_sub(SHIFT_IVEC(g, l), jt, dt_lj);
1659 t1 = IVEC2IS(dt_ij);
1660 t2 = IVEC2IS(dt_kj);
1661 t3 = IVEC2IS(dt_lj);
1665 t3 = pbc_rvec_sub(pbc, x[l], x[j], dx_jl);
1672 rvec_inc(fshift[t1], f_i);
1673 rvec_dec(fshift[CENTRAL], f_j);
1674 rvec_dec(fshift[t2], f_k);
1675 rvec_inc(fshift[t3], f_l);
1684 #if GMX_SIMD_HAVE_REAL
1685 /* As do_dih_fup_noshiftf above, but with SIMD and pre-calculated pre-factors */
1686 inline void gmx_simdcall
1687 do_dih_fup_noshiftf_simd(const int *ai, const int *aj, const int *ak, const int *al,
1688 SimdReal p, SimdReal q,
1689 SimdReal f_i_x, SimdReal f_i_y, SimdReal f_i_z,
1690 SimdReal mf_l_x, SimdReal mf_l_y, SimdReal mf_l_z,
1693 SimdReal sx = p * f_i_x + q * mf_l_x;
1694 SimdReal sy = p * f_i_y + q * mf_l_y;
1695 SimdReal sz = p * f_i_z + q * mf_l_z;
1696 SimdReal f_j_x = f_i_x - sx;
1697 SimdReal f_j_y = f_i_y - sy;
1698 SimdReal f_j_z = f_i_z - sz;
1699 SimdReal f_k_x = mf_l_x - sx;
1700 SimdReal f_k_y = mf_l_y - sy;
1701 SimdReal f_k_z = mf_l_z - sz;
1702 transposeScatterIncrU<4>(reinterpret_cast<real *>(f), ai, f_i_x, f_i_y, f_i_z);
1703 transposeScatterDecrU<4>(reinterpret_cast<real *>(f), aj, f_j_x, f_j_y, f_j_z);
1704 transposeScatterIncrU<4>(reinterpret_cast<real *>(f), ak, f_k_x, f_k_y, f_k_z);
1705 transposeScatterDecrU<4>(reinterpret_cast<real *>(f), al, mf_l_x, mf_l_y, mf_l_z);
1707 #endif // GMX_SIMD_HAVE_REAL
1709 /*! \brief Computes and returns the proper dihedral force
1711 * With the appropriate kernel flavor, also computes and accumulates
1712 * the energy and dV/dlambda.
1714 template <BondedKernelFlavor flavor>
1715 real dopdihs(real cpA, real cpB, real phiA, real phiB, int mult,
1716 real phi, real lambda, real *V, real *dvdlambda)
1718 const real L1 = 1.0 - lambda;
1719 const real ph0 = (L1*phiA + lambda*phiB)*DEG2RAD;
1720 const real dph0 = (phiB - phiA)*DEG2RAD;
1721 const real cp = L1*cpA + lambda*cpB;
1723 const real mdphi = mult*phi - ph0;
1724 const real sdphi = std::sin(mdphi);
1725 const real ddphi = -cp*mult*sdphi;
1726 if (computeEnergy(flavor))
1728 const real v1 = 1 + std::cos(mdphi);
1731 *dvdlambda += (cpB - cpA)*v1 + cp*dph0*sdphi;
1735 /* That was 40 flops */
1738 /*! \brief Similar to \p dopdihs(), except for a minus sign and a different treatment of mult/phi0 */
1739 real dopdihs_min(real cpA, real cpB, real phiA, real phiB, int mult,
1740 real phi, real lambda, real *V, real *F)
1742 real v, dvdlambda, mdphi, v1, sdphi, ddphi;
1743 real L1 = 1.0 - lambda;
1744 real ph0 = (L1*phiA + lambda*phiB)*DEG2RAD;
1745 real dph0 = (phiB - phiA)*DEG2RAD;
1746 real cp = L1*cpA + lambda*cpB;
1748 mdphi = mult*(phi-ph0);
1749 sdphi = std::sin(mdphi);
1750 ddphi = cp*mult*sdphi;
1751 v1 = 1.0-std::cos(mdphi);
1754 dvdlambda = (cpB-cpA)*v1 + cp*dph0*sdphi;
1761 /* That was 40 flops */
1764 template <BondedKernelFlavor flavor>
1765 std::enable_if_t<flavor != BondedKernelFlavor::ForcesSimdWhenAvailable || !GMX_SIMD_HAVE_REAL, real>
1767 const t_iatom forceatoms[], const t_iparams forceparams[],
1768 const rvec x[], rvec4 f[], rvec fshift[],
1769 const t_pbc *pbc, const t_graph *g,
1770 real lambda, real *dvdlambda,
1771 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
1772 int gmx_unused *global_atom_index)
1775 rvec r_ij, r_kj, r_kl, m, n;
1779 for (int i = 0; i < nbonds; )
1781 const int ai = forceatoms[i + 1];
1782 const int aj = forceatoms[i + 2];
1783 const int ak = forceatoms[i + 3];
1784 const int al = forceatoms[i + 4];
1786 const real phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n,
1787 &t1, &t2, &t3); /* 84 */
1789 /* Loop over dihedrals working on the same atoms,
1790 * so we avoid recalculating angles and distributing forces.
1795 const int type = forceatoms[i];
1797 dopdihs<flavor>(forceparams[type].pdihs.cpA,
1798 forceparams[type].pdihs.cpB,
1799 forceparams[type].pdihs.phiA,
1800 forceparams[type].pdihs.phiB,
1801 forceparams[type].pdihs.mult,
1802 phi, lambda, &vtot, dvdlambda);
1806 while (i < nbonds &&
1807 forceatoms[i + 1] == ai &&
1808 forceatoms[i + 2] == aj &&
1809 forceatoms[i + 3] == ak &&
1810 forceatoms[i + 4] == al);
1812 do_dih_fup<flavor>(ai, aj, ak, al, ddphi_tot, r_ij, r_kj, r_kl, m, n,
1813 f, fshift, pbc, g, x, t1, t2, t3); /* 112 */
1819 #if GMX_SIMD_HAVE_REAL
1821 /* As pdihs above, but using SIMD to calculate multiple dihedrals at once */
1822 template <BondedKernelFlavor flavor>
1823 std::enable_if_t<flavor == BondedKernelFlavor::ForcesSimdWhenAvailable, real>
1825 const t_iatom forceatoms[], const t_iparams forceparams[],
1826 const rvec x[], rvec4 f[], rvec gmx_unused fshift[],
1827 const t_pbc *pbc, const t_graph gmx_unused *g,
1828 real gmx_unused lambda, real gmx_unused *dvdlambda,
1829 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
1830 int gmx_unused *global_atom_index)
1835 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[GMX_SIMD_REAL_WIDTH];
1836 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[GMX_SIMD_REAL_WIDTH];
1837 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ak[GMX_SIMD_REAL_WIDTH];
1838 alignas(GMX_SIMD_ALIGNMENT) std::int32_t al[GMX_SIMD_REAL_WIDTH];
1839 alignas(GMX_SIMD_ALIGNMENT) real buf[3*GMX_SIMD_REAL_WIDTH];
1840 real *cp, *phi0, *mult;
1841 SimdReal deg2rad_S(DEG2RAD);
1843 SimdReal phi0_S, phi_S;
1844 SimdReal mx_S, my_S, mz_S;
1845 SimdReal nx_S, ny_S, nz_S;
1846 SimdReal nrkj_m2_S, nrkj_n2_S;
1847 SimdReal cp_S, mdphi_S, mult_S;
1848 SimdReal sin_S, cos_S;
1850 SimdReal sf_i_S, msf_l_S;
1851 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9*GMX_SIMD_REAL_WIDTH];
1853 /* Extract aligned pointer for parameters and variables */
1854 cp = buf + 0*GMX_SIMD_REAL_WIDTH;
1855 phi0 = buf + 1*GMX_SIMD_REAL_WIDTH;
1856 mult = buf + 2*GMX_SIMD_REAL_WIDTH;
1858 set_pbc_simd(pbc, pbc_simd);
1860 /* nbonds is the number of dihedrals times nfa1, here we step GMX_SIMD_REAL_WIDTH dihs */
1861 for (i = 0; (i < nbonds); i += GMX_SIMD_REAL_WIDTH*nfa1)
1863 /* Collect atoms quadruplets for GMX_SIMD_REAL_WIDTH dihedrals.
1864 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
1867 for (s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
1869 type = forceatoms[iu];
1870 ai[s] = forceatoms[iu+1];
1871 aj[s] = forceatoms[iu+2];
1872 ak[s] = forceatoms[iu+3];
1873 al[s] = forceatoms[iu+4];
1875 /* At the end fill the arrays with the last atoms and 0 params */
1876 if (i + s*nfa1 < nbonds)
1878 cp[s] = forceparams[type].pdihs.cpA;
1879 phi0[s] = forceparams[type].pdihs.phiA;
1880 mult[s] = forceparams[type].pdihs.mult;
1882 if (iu + nfa1 < nbonds)
1895 /* Caclulate GMX_SIMD_REAL_WIDTH dihedral angles at once */
1896 dih_angle_simd(x, ai, aj, ak, al, pbc_simd,
1898 &mx_S, &my_S, &mz_S,
1899 &nx_S, &ny_S, &nz_S,
1904 cp_S = load<SimdReal>(cp);
1905 phi0_S = load<SimdReal>(phi0) * deg2rad_S;
1906 mult_S = load<SimdReal>(mult);
1908 mdphi_S = fms(mult_S, phi_S, phi0_S);
1910 /* Calculate GMX_SIMD_REAL_WIDTH sines at once */
1911 sincos(mdphi_S, &sin_S, &cos_S);
1912 mddphi_S = cp_S * mult_S * sin_S;
1913 sf_i_S = mddphi_S * nrkj_m2_S;
1914 msf_l_S = mddphi_S * nrkj_n2_S;
1916 /* After this m?_S will contain f[i] */
1917 mx_S = sf_i_S * mx_S;
1918 my_S = sf_i_S * my_S;
1919 mz_S = sf_i_S * mz_S;
1921 /* After this m?_S will contain -f[l] */
1922 nx_S = msf_l_S * nx_S;
1923 ny_S = msf_l_S * ny_S;
1924 nz_S = msf_l_S * nz_S;
1926 do_dih_fup_noshiftf_simd(ai, aj, ak, al,
1936 /* This is mostly a copy of the SIMD flavor of pdihs above, but with using
1937 * the RB potential instead of a harmonic potential.
1938 * This function can replace rbdihs() when no energy and virial are needed.
1940 template <BondedKernelFlavor flavor>
1941 std::enable_if_t<flavor == BondedKernelFlavor::ForcesSimdWhenAvailable, real>
1943 const t_iatom forceatoms[], const t_iparams forceparams[],
1944 const rvec x[], rvec4 f[], rvec gmx_unused fshift[],
1945 const t_pbc *pbc, const t_graph gmx_unused *g,
1946 real gmx_unused lambda, real gmx_unused *dvdlambda,
1947 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
1948 int gmx_unused *global_atom_index)
1953 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[GMX_SIMD_REAL_WIDTH];
1954 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[GMX_SIMD_REAL_WIDTH];
1955 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ak[GMX_SIMD_REAL_WIDTH];
1956 alignas(GMX_SIMD_ALIGNMENT) std::int32_t al[GMX_SIMD_REAL_WIDTH];
1957 alignas(GMX_SIMD_ALIGNMENT) real parm[NR_RBDIHS*GMX_SIMD_REAL_WIDTH];
1961 SimdReal ddphi_S, cosfac_S;
1962 SimdReal mx_S, my_S, mz_S;
1963 SimdReal nx_S, ny_S, nz_S;
1964 SimdReal nrkj_m2_S, nrkj_n2_S;
1965 SimdReal parm_S, c_S;
1966 SimdReal sin_S, cos_S;
1967 SimdReal sf_i_S, msf_l_S;
1968 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9*GMX_SIMD_REAL_WIDTH];
1970 SimdReal pi_S(M_PI);
1971 SimdReal one_S(1.0);
1973 set_pbc_simd(pbc, pbc_simd);
1975 /* nbonds is the number of dihedrals times nfa1, here we step GMX_SIMD_REAL_WIDTH dihs */
1976 for (i = 0; (i < nbonds); i += GMX_SIMD_REAL_WIDTH*nfa1)
1978 /* Collect atoms quadruplets for GMX_SIMD_REAL_WIDTH dihedrals.
1979 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
1982 for (s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
1984 type = forceatoms[iu];
1985 ai[s] = forceatoms[iu+1];
1986 aj[s] = forceatoms[iu+2];
1987 ak[s] = forceatoms[iu+3];
1988 al[s] = forceatoms[iu+4];
1990 /* At the end fill the arrays with the last atoms and 0 params */
1991 if (i + s*nfa1 < nbonds)
1993 /* We don't need the first parameter, since that's a constant
1994 * which only affects the energies, not the forces.
1996 for (j = 1; j < NR_RBDIHS; j++)
1998 parm[j*GMX_SIMD_REAL_WIDTH + s] =
1999 forceparams[type].rbdihs.rbcA[j];
2002 if (iu + nfa1 < nbonds)
2009 for (j = 1; j < NR_RBDIHS; j++)
2011 parm[j*GMX_SIMD_REAL_WIDTH + s] = 0;
2016 /* Caclulate GMX_SIMD_REAL_WIDTH dihedral angles at once */
2017 dih_angle_simd(x, ai, aj, ak, al, pbc_simd,
2019 &mx_S, &my_S, &mz_S,
2020 &nx_S, &ny_S, &nz_S,
2025 /* Change to polymer convention */
2026 phi_S = phi_S - pi_S;
2028 sincos(phi_S, &sin_S, &cos_S);
2030 ddphi_S = setZero();
2033 for (j = 1; j < NR_RBDIHS; j++)
2035 parm_S = load<SimdReal>(parm + j*GMX_SIMD_REAL_WIDTH);
2036 ddphi_S = fma(c_S * parm_S, cosfac_S, ddphi_S);
2037 cosfac_S = cosfac_S * cos_S;
2041 /* Note that here we do not use the minus sign which is present
2042 * in the normal RB code. This is corrected for through (m)sf below.
2044 ddphi_S = ddphi_S * sin_S;
2046 sf_i_S = ddphi_S * nrkj_m2_S;
2047 msf_l_S = ddphi_S * nrkj_n2_S;
2049 /* After this m?_S will contain f[i] */
2050 mx_S = sf_i_S * mx_S;
2051 my_S = sf_i_S * my_S;
2052 mz_S = sf_i_S * mz_S;
2054 /* After this m?_S will contain -f[l] */
2055 nx_S = msf_l_S * nx_S;
2056 ny_S = msf_l_S * ny_S;
2057 nz_S = msf_l_S * nz_S;
2059 do_dih_fup_noshiftf_simd(ai, aj, ak, al,
2069 #endif // GMX_SIMD_HAVE_REAL
2072 template <BondedKernelFlavor flavor>
2073 real idihs(int nbonds,
2074 const t_iatom forceatoms[], const t_iparams forceparams[],
2075 const rvec x[], rvec4 f[], rvec fshift[],
2076 const t_pbc *pbc, const t_graph *g,
2077 real lambda, real *dvdlambda,
2078 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
2079 int gmx_unused *global_atom_index)
2081 int i, type, ai, aj, ak, al;
2083 real phi, phi0, dphi0, ddphi, vtot;
2084 rvec r_ij, r_kj, r_kl, m, n;
2085 real L1, kk, dp, dp2, kA, kB, pA, pB, dvdl_term;
2090 for (i = 0; (i < nbonds); )
2092 type = forceatoms[i++];
2093 ai = forceatoms[i++];
2094 aj = forceatoms[i++];
2095 ak = forceatoms[i++];
2096 al = forceatoms[i++];
2098 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n,
2099 &t1, &t2, &t3); /* 84 */
2101 /* phi can jump if phi0 is close to Pi/-Pi, which will cause huge
2102 * force changes if we just apply a normal harmonic.
2103 * Instead, we first calculate phi-phi0 and take it modulo (-Pi,Pi).
2104 * This means we will never have the periodicity problem, unless
2105 * the dihedral is Pi away from phiO, which is very unlikely due to
2108 kA = forceparams[type].harmonic.krA;
2109 kB = forceparams[type].harmonic.krB;
2110 pA = forceparams[type].harmonic.rA;
2111 pB = forceparams[type].harmonic.rB;
2113 kk = L1*kA + lambda*kB;
2114 phi0 = (L1*pA + lambda*pB)*DEG2RAD;
2115 dphi0 = (pB - pA)*DEG2RAD;
2119 make_dp_periodic(&dp);
2126 dvdl_term += 0.5*(kB - kA)*dp2 - kk*dphi0*dp;
2128 do_dih_fup<flavor>(ai, aj, ak, al, -ddphi, r_ij, r_kj, r_kl, m, n,
2129 f, fshift, pbc, g, x, t1, t2, t3); /* 112 */
2133 *dvdlambda += dvdl_term;
2137 /*! \brief Computes angle restraints of two different types */
2138 template <BondedKernelFlavor flavor>
2139 real low_angres(int nbonds,
2140 const t_iatom forceatoms[], const t_iparams forceparams[],
2141 const rvec x[], rvec4 f[], rvec fshift[],
2142 const t_pbc *pbc, const t_graph *g,
2143 real lambda, real *dvdlambda,
2146 int i, m, type, ai, aj, ak, al;
2148 real phi, cos_phi, cos_phi2, vid, vtot, dVdphi;
2149 rvec r_ij, r_kl, f_i, f_k = {0, 0, 0};
2150 real st, sth, nrij2, nrkl2, c, cij, ckl;
2153 t2 = 0; /* avoid warning with gcc-3.3. It is never used uninitialized */
2156 ak = al = 0; /* to avoid warnings */
2157 for (i = 0; i < nbonds; )
2159 type = forceatoms[i++];
2160 ai = forceatoms[i++];
2161 aj = forceatoms[i++];
2162 t1 = pbc_rvec_sub(pbc, x[aj], x[ai], r_ij); /* 3 */
2165 ak = forceatoms[i++];
2166 al = forceatoms[i++];
2167 t2 = pbc_rvec_sub(pbc, x[al], x[ak], r_kl); /* 3 */
2176 cos_phi = cos_angle(r_ij, r_kl); /* 25 */
2177 phi = std::acos(cos_phi); /* 10 */
2179 *dvdlambda += dopdihs_min(forceparams[type].pdihs.cpA,
2180 forceparams[type].pdihs.cpB,
2181 forceparams[type].pdihs.phiA,
2182 forceparams[type].pdihs.phiB,
2183 forceparams[type].pdihs.mult,
2184 phi, lambda, &vid, &dVdphi); /* 40 */
2188 cos_phi2 = gmx::square(cos_phi); /* 1 */
2191 st = -dVdphi*gmx::invsqrt(1 - cos_phi2); /* 12 */
2192 sth = st*cos_phi; /* 1 */
2193 nrij2 = iprod(r_ij, r_ij); /* 5 */
2194 nrkl2 = iprod(r_kl, r_kl); /* 5 */
2196 c = st*gmx::invsqrt(nrij2*nrkl2); /* 11 */
2197 cij = sth/nrij2; /* 10 */
2198 ckl = sth/nrkl2; /* 10 */
2200 for (m = 0; m < DIM; m++) /* 18+18 */
2202 f_i[m] = (c*r_kl[m]-cij*r_ij[m]);
2207 f_k[m] = (c*r_ij[m]-ckl*r_kl[m]);
2213 if (computeVirial(flavor))
2217 ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, aj), dt);
2220 rvec_inc(fshift[t1], f_i);
2221 rvec_dec(fshift[CENTRAL], f_i);
2226 ivec_sub(SHIFT_IVEC(g, ak), SHIFT_IVEC(g, al), dt);
2229 rvec_inc(fshift[t2], f_k);
2230 rvec_dec(fshift[CENTRAL], f_k);
2236 return vtot; /* 184 / 157 (bZAxis) total */
2239 template <BondedKernelFlavor flavor>
2240 real angres(int nbonds,
2241 const t_iatom forceatoms[], const t_iparams forceparams[],
2242 const rvec x[], rvec4 f[], rvec fshift[],
2243 const t_pbc *pbc, const t_graph *g,
2244 real lambda, real *dvdlambda,
2245 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
2246 int gmx_unused *global_atom_index)
2248 return low_angres<flavor>(nbonds, forceatoms, forceparams, x, f, fshift, pbc, g,
2249 lambda, dvdlambda, FALSE);
2252 template <BondedKernelFlavor flavor>
2253 real angresz(int nbonds,
2254 const t_iatom forceatoms[], const t_iparams forceparams[],
2255 const rvec x[], rvec4 f[], rvec fshift[],
2256 const t_pbc *pbc, const t_graph *g,
2257 real lambda, real *dvdlambda,
2258 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
2259 int gmx_unused *global_atom_index)
2261 return low_angres<flavor>(nbonds, forceatoms, forceparams, x, f, fshift, pbc, g,
2262 lambda, dvdlambda, TRUE);
2265 template <BondedKernelFlavor flavor>
2266 real dihres(int nbonds,
2267 const t_iatom forceatoms[], const t_iparams forceparams[],
2268 const rvec x[], rvec4 f[], rvec fshift[],
2269 const t_pbc *pbc, const t_graph *g,
2270 real lambda, real *dvdlambda,
2271 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
2272 int gmx_unused *global_atom_index)
2275 int ai, aj, ak, al, i, type, t1, t2, t3;
2276 real phi0A, phi0B, dphiA, dphiB, kfacA, kfacB, phi0, dphi, kfac;
2277 real phi, ddphi, ddp, ddp2, dp, d2r, L1;
2278 rvec r_ij, r_kj, r_kl, m, n;
2284 for (i = 0; (i < nbonds); )
2286 type = forceatoms[i++];
2287 ai = forceatoms[i++];
2288 aj = forceatoms[i++];
2289 ak = forceatoms[i++];
2290 al = forceatoms[i++];
2292 phi0A = forceparams[type].dihres.phiA*d2r;
2293 dphiA = forceparams[type].dihres.dphiA*d2r;
2294 kfacA = forceparams[type].dihres.kfacA;
2296 phi0B = forceparams[type].dihres.phiB*d2r;
2297 dphiB = forceparams[type].dihres.dphiB*d2r;
2298 kfacB = forceparams[type].dihres.kfacB;
2300 phi0 = L1*phi0A + lambda*phi0B;
2301 dphi = L1*dphiA + lambda*dphiB;
2302 kfac = L1*kfacA + lambda*kfacB;
2304 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n,
2308 /* phi can jump if phi0 is close to Pi/-Pi, which will cause huge
2309 * force changes if we just apply a normal harmonic.
2310 * Instead, we first calculate phi-phi0 and take it modulo (-Pi,Pi).
2311 * This means we will never have the periodicity problem, unless
2312 * the dihedral is Pi away from phiO, which is very unlikely due to
2316 make_dp_periodic(&dp);
2322 else if (dp < -dphi)
2334 vtot += 0.5*kfac*ddp2;
2337 *dvdlambda += 0.5*(kfacB - kfacA)*ddp2;
2338 /* lambda dependence from changing restraint distances */
2341 *dvdlambda -= kfac*ddp*((dphiB - dphiA)+(phi0B - phi0A));
2345 *dvdlambda += kfac*ddp*((dphiB - dphiA)-(phi0B - phi0A));
2347 do_dih_fup<flavor>(ai, aj, ak, al, ddphi, r_ij, r_kj, r_kl, m, n,
2348 f, fshift, pbc, g, x, t1, t2, t3); /* 112 */
2355 real unimplemented(int gmx_unused nbonds,
2356 const t_iatom gmx_unused forceatoms[], const t_iparams gmx_unused forceparams[],
2357 const rvec gmx_unused x[], rvec4 gmx_unused f[], rvec gmx_unused fshift[],
2358 const t_pbc gmx_unused *pbc, const t_graph gmx_unused *g,
2359 real gmx_unused lambda, real gmx_unused *dvdlambda,
2360 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
2361 int gmx_unused *global_atom_index)
2363 gmx_impl("*** you are using a not implemented function");
2366 template <BondedKernelFlavor flavor>
2367 real restrangles(int nbonds,
2368 const t_iatom forceatoms[], const t_iparams forceparams[],
2369 const rvec x[], rvec4 f[], rvec fshift[],
2370 const t_pbc *pbc, const t_graph *g,
2371 real gmx_unused lambda, real gmx_unused *dvdlambda,
2372 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
2373 int gmx_unused *global_atom_index)
2375 int i, d, ai, aj, ak, type, m;
2378 ivec jt, dt_ij, dt_kj;
2380 double prefactor, ratio_ante, ratio_post;
2381 rvec delta_ante, delta_post, vec_temp;
2384 for (i = 0; (i < nbonds); )
2386 type = forceatoms[i++];
2387 ai = forceatoms[i++];
2388 aj = forceatoms[i++];
2389 ak = forceatoms[i++];
2391 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], vec_temp);
2392 pbc_rvec_sub(pbc, x[aj], x[ai], delta_ante);
2393 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], delta_post);
2396 /* This function computes factors needed for restricted angle potential.
2397 * The restricted angle potential is used in coarse-grained simulations to avoid singularities
2398 * when three particles align and the dihedral angle and dihedral potential
2399 * cannot be calculated. This potential is calculated using the formula:
2400 real restrangles(int nbonds,
2401 const t_iatom forceatoms[],const t_iparams forceparams[],
2402 const rvec x[],rvec4 f[],rvec fshift[],
2403 const t_pbc *pbc,const t_graph *g,
2404 real gmx_unused lambda,real gmx_unused *dvdlambda,
2405 const t_mdatoms gmx_unused *md,t_fcdata gmx_unused *fcd,
2406 int gmx_unused *global_atom_index)
2408 int i, d, ai, aj, ak, type, m;
2412 ivec jt,dt_ij,dt_kj;
2414 real prefactor, ratio_ante, ratio_post;
2415 rvec delta_ante, delta_post, vec_temp;
2418 for(i=0; (i<nbonds); )
2420 type = forceatoms[i++];
2421 ai = forceatoms[i++];
2422 aj = forceatoms[i++];
2423 ak = forceatoms[i++];
2425 * \f[V_{\rm ReB}(\theta_i) = \frac{1}{2} k_{\theta} \frac{(\cos\theta_i - \cos\theta_0)^2}
2426 * {\sin^2\theta_i}\f] ({eq:ReB} and ref \cite{MonicaGoga2013} from the manual).
2427 * For more explanations see comments file "restcbt.h". */
2429 compute_factors_restangles(type, forceparams, delta_ante, delta_post,
2430 &prefactor, &ratio_ante, &ratio_post, &v);
2432 /* Forces are computed per component */
2433 for (d = 0; d < DIM; d++)
2435 f_i[d] = prefactor * (ratio_ante * delta_ante[d] - delta_post[d]);
2436 f_j[d] = prefactor * ((ratio_post + 1.0) * delta_post[d] - (ratio_ante + 1.0) * delta_ante[d]);
2437 f_k[d] = prefactor * (delta_ante[d] - ratio_post * delta_post[d]);
2440 /* Computation of potential energy */
2446 for (m = 0; (m < DIM); m++)
2453 if (computeVirial(flavor))
2457 copy_ivec(SHIFT_IVEC(g, aj), jt);
2458 ivec_sub(SHIFT_IVEC(g, ai), jt, dt_ij);
2459 ivec_sub(SHIFT_IVEC(g, ak), jt, dt_kj);
2460 t1 = IVEC2IS(dt_ij);
2461 t2 = IVEC2IS(dt_kj);
2464 rvec_inc(fshift[t1], f_i);
2465 rvec_inc(fshift[CENTRAL], f_j);
2466 rvec_inc(fshift[t2], f_k);
2473 template <BondedKernelFlavor flavor>
2474 real restrdihs(int nbonds,
2475 const t_iatom forceatoms[], const t_iparams forceparams[],
2476 const rvec x[], rvec4 f[], rvec fshift[],
2477 const t_pbc *pbc, const t_graph *g,
2478 real gmx_unused lambda, real gmx_unused *dvlambda,
2479 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
2480 int gmx_unused *global_atom_index)
2482 int i, d, type, ai, aj, ak, al;
2483 rvec f_i, f_j, f_k, f_l;
2485 ivec jt, dt_ij, dt_kj, dt_lj;
2488 rvec delta_ante, delta_crnt, delta_post, vec_temp;
2489 real factor_phi_ai_ante, factor_phi_ai_crnt, factor_phi_ai_post;
2490 real factor_phi_aj_ante, factor_phi_aj_crnt, factor_phi_aj_post;
2491 real factor_phi_ak_ante, factor_phi_ak_crnt, factor_phi_ak_post;
2492 real factor_phi_al_ante, factor_phi_al_crnt, factor_phi_al_post;
2497 for (i = 0; (i < nbonds); )
2499 type = forceatoms[i++];
2500 ai = forceatoms[i++];
2501 aj = forceatoms[i++];
2502 ak = forceatoms[i++];
2503 al = forceatoms[i++];
2505 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], vec_temp);
2506 pbc_rvec_sub(pbc, x[aj], x[ai], delta_ante);
2507 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], delta_crnt);
2508 pbc_rvec_sub(pbc, x[ak], x[al], vec_temp);
2509 pbc_rvec_sub(pbc, x[al], x[ak], delta_post);
2511 /* This function computes factors needed for restricted angle potential.
2512 * The restricted angle potential is used in coarse-grained simulations to avoid singularities
2513 * when three particles align and the dihedral angle and dihedral potential cannot be calculated.
2514 * This potential is calculated using the formula:
2515 * \f[V_{\rm ReB}(\theta_i) = \frac{1}{2} k_{\theta}
2516 * \frac{(\cos\theta_i - \cos\theta_0)^2}{\sin^2\theta_i}\f]
2517 * ({eq:ReB} and ref \cite{MonicaGoga2013} from the manual).
2518 * For more explanations see comments file "restcbt.h" */
2520 compute_factors_restrdihs(type, forceparams,
2521 delta_ante, delta_crnt, delta_post,
2522 &factor_phi_ai_ante, &factor_phi_ai_crnt, &factor_phi_ai_post,
2523 &factor_phi_aj_ante, &factor_phi_aj_crnt, &factor_phi_aj_post,
2524 &factor_phi_ak_ante, &factor_phi_ak_crnt, &factor_phi_ak_post,
2525 &factor_phi_al_ante, &factor_phi_al_crnt, &factor_phi_al_post,
2526 &prefactor_phi, &v);
2529 /* Computation of forces per component */
2530 for (d = 0; d < DIM; d++)
2532 f_i[d] = prefactor_phi * (factor_phi_ai_ante * delta_ante[d] + factor_phi_ai_crnt * delta_crnt[d] + factor_phi_ai_post * delta_post[d]);
2533 f_j[d] = prefactor_phi * (factor_phi_aj_ante * delta_ante[d] + factor_phi_aj_crnt * delta_crnt[d] + factor_phi_aj_post * delta_post[d]);
2534 f_k[d] = prefactor_phi * (factor_phi_ak_ante * delta_ante[d] + factor_phi_ak_crnt * delta_crnt[d] + factor_phi_ak_post * delta_post[d]);
2535 f_l[d] = prefactor_phi * (factor_phi_al_ante * delta_ante[d] + factor_phi_al_crnt * delta_crnt[d] + factor_phi_al_post * delta_post[d]);
2537 /* Computation of the energy */
2543 /* Updating the forces */
2545 rvec_inc(f[ai], f_i);
2546 rvec_inc(f[aj], f_j);
2547 rvec_inc(f[ak], f_k);
2548 rvec_inc(f[al], f_l);
2550 if (computeVirial(flavor))
2554 copy_ivec(SHIFT_IVEC(g, aj), jt);
2555 ivec_sub(SHIFT_IVEC(g, ai), jt, dt_ij);
2556 ivec_sub(SHIFT_IVEC(g, ak), jt, dt_kj);
2557 ivec_sub(SHIFT_IVEC(g, al), jt, dt_lj);
2558 t1 = IVEC2IS(dt_ij);
2559 t2 = IVEC2IS(dt_kj);
2560 t3 = IVEC2IS(dt_lj);
2564 t3 = pbc_rvec_sub(pbc, x[al], x[aj], dx_jl);
2571 rvec_inc(fshift[t1], f_i);
2572 rvec_inc(fshift[CENTRAL], f_j);
2573 rvec_inc(fshift[t2], f_k);
2574 rvec_inc(fshift[t3], f_l);
2582 template <BondedKernelFlavor flavor>
2583 real cbtdihs(int nbonds,
2584 const t_iatom forceatoms[], const t_iparams forceparams[],
2585 const rvec x[], rvec4 f[], rvec fshift[],
2586 const t_pbc *pbc, const t_graph *g,
2587 real gmx_unused lambda, real gmx_unused *dvdlambda,
2588 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
2589 int gmx_unused *global_atom_index)
2591 int type, ai, aj, ak, al, i, d;
2595 rvec f_i, f_j, f_k, f_l;
2596 ivec jt, dt_ij, dt_kj, dt_lj;
2598 rvec delta_ante, delta_crnt, delta_post;
2599 rvec f_phi_ai, f_phi_aj, f_phi_ak, f_phi_al;
2600 rvec f_theta_ante_ai, f_theta_ante_aj, f_theta_ante_ak;
2601 rvec f_theta_post_aj, f_theta_post_ak, f_theta_post_al;
2607 for (i = 0; (i < nbonds); )
2609 type = forceatoms[i++];
2610 ai = forceatoms[i++];
2611 aj = forceatoms[i++];
2612 ak = forceatoms[i++];
2613 al = forceatoms[i++];
2616 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], vec_temp);
2617 pbc_rvec_sub(pbc, x[aj], x[ai], delta_ante);
2618 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], vec_temp);
2619 pbc_rvec_sub(pbc, x[ak], x[aj], delta_crnt);
2620 pbc_rvec_sub(pbc, x[ak], x[al], vec_temp);
2621 pbc_rvec_sub(pbc, x[al], x[ak], delta_post);
2623 /* \brief Compute factors for CBT potential
2624 * The combined bending-torsion potential goes to zero in a very smooth manner, eliminating the numerical
2625 * instabilities, when three coarse-grained particles align and the dihedral angle and standard
2626 * dihedral potentials cannot be calculated. The CBT potential is calculated using the formula:
2627 * \f[V_{\rm CBT}(\theta_{i-1}, \theta_i, \phi_i) = k_{\phi} \sin^3\theta_{i-1} \sin^3\theta_{i}
2628 * \sum_{n=0}^4 { a_n \cos^n\phi_i}\f] ({eq:CBT} and ref \cite{MonicaGoga2013} from the manual).
2629 * It contains in its expression not only the dihedral angle \f$\phi\f$
2630 * but also \f[\theta_{i-1}\f] (theta_ante bellow) and \f[\theta_{i}\f] (theta_post bellow)
2631 * --- the adjacent bending angles.
2632 * For more explanations see comments file "restcbt.h". */
2634 compute_factors_cbtdihs(type, forceparams, delta_ante, delta_crnt, delta_post,
2635 f_phi_ai, f_phi_aj, f_phi_ak, f_phi_al,
2636 f_theta_ante_ai, f_theta_ante_aj, f_theta_ante_ak,
2637 f_theta_post_aj, f_theta_post_ak, f_theta_post_al,
2641 /* Acumulate the resuts per beads */
2642 for (d = 0; d < DIM; d++)
2644 f_i[d] = f_phi_ai[d] + f_theta_ante_ai[d];
2645 f_j[d] = f_phi_aj[d] + f_theta_ante_aj[d] + f_theta_post_aj[d];
2646 f_k[d] = f_phi_ak[d] + f_theta_ante_ak[d] + f_theta_post_ak[d];
2647 f_l[d] = f_phi_al[d] + f_theta_post_al[d];
2650 /* Compute the potential energy */
2655 /* Updating the forces */
2656 rvec_inc(f[ai], f_i);
2657 rvec_inc(f[aj], f_j);
2658 rvec_inc(f[ak], f_k);
2659 rvec_inc(f[al], f_l);
2662 if (computeVirial(flavor))
2666 copy_ivec(SHIFT_IVEC(g, aj), jt);
2667 ivec_sub(SHIFT_IVEC(g, ai), jt, dt_ij);
2668 ivec_sub(SHIFT_IVEC(g, ak), jt, dt_kj);
2669 ivec_sub(SHIFT_IVEC(g, al), jt, dt_lj);
2670 t1 = IVEC2IS(dt_ij);
2671 t2 = IVEC2IS(dt_kj);
2672 t3 = IVEC2IS(dt_lj);
2676 t3 = pbc_rvec_sub(pbc, x[al], x[aj], dx_jl);
2683 rvec_inc(fshift[t1], f_i);
2684 rvec_inc(fshift[CENTRAL], f_j);
2685 rvec_inc(fshift[t2], f_k);
2686 rvec_inc(fshift[t3], f_l);
2693 template <BondedKernelFlavor flavor>
2694 std::enable_if_t<flavor != BondedKernelFlavor::ForcesSimdWhenAvailable || !GMX_SIMD_HAVE_REAL, real>
2696 const t_iatom forceatoms[], const t_iparams forceparams[],
2697 const rvec x[], rvec4 f[], rvec fshift[],
2698 const t_pbc *pbc, const t_graph *g,
2699 real lambda, real *dvdlambda,
2700 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
2701 int gmx_unused *global_atom_index)
2703 const real c0 = 0.0, c1 = 1.0, c2 = 2.0, c3 = 3.0, c4 = 4.0, c5 = 5.0;
2704 int type, ai, aj, ak, al, i, j;
2706 rvec r_ij, r_kj, r_kl, m, n;
2707 real parmA[NR_RBDIHS];
2708 real parmB[NR_RBDIHS];
2709 real parm[NR_RBDIHS];
2710 real cos_phi, phi, rbp, rbpBA;
2711 real v, ddphi, sin_phi;
2713 real L1 = 1.0-lambda;
2717 for (i = 0; (i < nbonds); )
2719 type = forceatoms[i++];
2720 ai = forceatoms[i++];
2721 aj = forceatoms[i++];
2722 ak = forceatoms[i++];
2723 al = forceatoms[i++];
2725 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n,
2726 &t1, &t2, &t3); /* 84 */
2728 /* Change to polymer convention */
2735 phi -= M_PI; /* 1 */
2738 cos_phi = std::cos(phi);
2739 /* Beware of accuracy loss, cannot use 1-sqrt(cos^2) ! */
2740 sin_phi = std::sin(phi);
2742 for (j = 0; (j < NR_RBDIHS); j++)
2744 parmA[j] = forceparams[type].rbdihs.rbcA[j];
2745 parmB[j] = forceparams[type].rbdihs.rbcB[j];
2746 parm[j] = L1*parmA[j]+lambda*parmB[j];
2748 /* Calculate cosine powers */
2749 /* Calculate the energy */
2750 /* Calculate the derivative */
2753 dvdl_term += (parmB[0]-parmA[0]);
2758 rbpBA = parmB[1]-parmA[1];
2759 ddphi += rbp*cosfac;
2762 dvdl_term += cosfac*rbpBA;
2764 rbpBA = parmB[2]-parmA[2];
2765 ddphi += c2*rbp*cosfac;
2768 dvdl_term += cosfac*rbpBA;
2770 rbpBA = parmB[3]-parmA[3];
2771 ddphi += c3*rbp*cosfac;
2774 dvdl_term += cosfac*rbpBA;
2776 rbpBA = parmB[4]-parmA[4];
2777 ddphi += c4*rbp*cosfac;
2780 dvdl_term += cosfac*rbpBA;
2782 rbpBA = parmB[5]-parmA[5];
2783 ddphi += c5*rbp*cosfac;
2786 dvdl_term += cosfac*rbpBA;
2788 ddphi = -ddphi*sin_phi; /* 11 */
2790 do_dih_fup<flavor>(ai, aj, ak, al, ddphi, r_ij, r_kj, r_kl, m, n,
2791 f, fshift, pbc, g, x, t1, t2, t3); /* 112 */
2794 *dvdlambda += dvdl_term;
2801 /*! \brief Mysterious undocumented function */
2803 cmap_setup_grid_index(int ip, int grid_spacing, int *ipm1, int *ipp1, int *ipp2)
2809 ip = ip + grid_spacing - 1;
2811 else if (ip > grid_spacing)
2813 ip = ip - grid_spacing - 1;
2822 im1 = grid_spacing - 1;
2824 else if (ip == grid_spacing-2)
2828 else if (ip == grid_spacing-1)
2845 cmap_dihs(int nbonds,
2846 const t_iatom forceatoms[], const t_iparams forceparams[],
2847 const gmx_cmap_t *cmap_grid,
2848 const rvec x[], rvec4 f[], rvec fshift[],
2849 const struct t_pbc *pbc, const struct t_graph *g,
2850 real gmx_unused lambda, real gmx_unused *dvdlambda,
2851 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
2852 int gmx_unused *global_atom_index)
2855 int ai, aj, ak, al, am;
2856 int a1i, a1j, a1k, a1l, a2i, a2j, a2k, a2l;
2858 int t11, t21, t31, t12, t22, t32;
2859 int iphi1, ip1m1, ip1p1, ip1p2;
2860 int iphi2, ip2m1, ip2p1, ip2p2;
2862 int pos1, pos2, pos3, pos4;
2864 real ty[4], ty1[4], ty2[4], ty12[4], tx[16];
2865 real phi1, cos_phi1, sin_phi1, xphi1;
2866 real phi2, cos_phi2, sin_phi2, xphi2;
2867 real dx, tt, tu, e, df1, df2, vtot;
2868 real ra21, rb21, rg21, rg1, rgr1, ra2r1, rb2r1, rabr1;
2869 real ra22, rb22, rg22, rg2, rgr2, ra2r2, rb2r2, rabr2;
2870 real fg1, hg1, fga1, hgb1, gaa1, gbb1;
2871 real fg2, hg2, fga2, hgb2, gaa2, gbb2;
2874 rvec r1_ij, r1_kj, r1_kl, m1, n1;
2875 rvec r2_ij, r2_kj, r2_kl, m2, n2;
2876 rvec f1_i, f1_j, f1_k, f1_l;
2877 rvec f2_i, f2_j, f2_k, f2_l;
2878 rvec a1, b1, a2, b2;
2879 rvec f1, g1, h1, f2, g2, h2;
2880 rvec dtf1, dtg1, dth1, dtf2, dtg2, dth2;
2881 ivec jt1, dt1_ij, dt1_kj, dt1_lj;
2882 ivec jt2, dt2_ij, dt2_kj, dt2_lj;
2884 int loop_index[4][4] = {
2891 /* Total CMAP energy */
2894 for (n = 0; n < nbonds; )
2896 /* Five atoms are involved in the two torsions */
2897 type = forceatoms[n++];
2898 ai = forceatoms[n++];
2899 aj = forceatoms[n++];
2900 ak = forceatoms[n++];
2901 al = forceatoms[n++];
2902 am = forceatoms[n++];
2904 /* Which CMAP type is this */
2905 const int cmapA = forceparams[type].cmap.cmapA;
2906 const real *cmapd = cmap_grid->cmapdata[cmapA].cmap.data();
2914 phi1 = dih_angle(x[a1i], x[a1j], x[a1k], x[a1l], pbc, r1_ij, r1_kj, r1_kl, m1, n1,
2915 &t11, &t21, &t31); /* 84 */
2917 cos_phi1 = std::cos(phi1);
2919 a1[0] = r1_ij[1]*r1_kj[2]-r1_ij[2]*r1_kj[1];
2920 a1[1] = r1_ij[2]*r1_kj[0]-r1_ij[0]*r1_kj[2];
2921 a1[2] = r1_ij[0]*r1_kj[1]-r1_ij[1]*r1_kj[0]; /* 9 */
2923 b1[0] = r1_kl[1]*r1_kj[2]-r1_kl[2]*r1_kj[1];
2924 b1[1] = r1_kl[2]*r1_kj[0]-r1_kl[0]*r1_kj[2];
2925 b1[2] = r1_kl[0]*r1_kj[1]-r1_kl[1]*r1_kj[0]; /* 9 */
2927 pbc_rvec_sub(pbc, x[a1l], x[a1k], h1);
2929 ra21 = iprod(a1, a1); /* 5 */
2930 rb21 = iprod(b1, b1); /* 5 */
2931 rg21 = iprod(r1_kj, r1_kj); /* 5 */
2937 rabr1 = sqrt(ra2r1*rb2r1);
2939 sin_phi1 = rg1 * rabr1 * iprod(a1, h1) * (-1);
2941 if (cos_phi1 < -0.5 || cos_phi1 > 0.5)
2943 phi1 = std::asin(sin_phi1);
2953 phi1 = -M_PI - phi1;
2959 phi1 = std::acos(cos_phi1);
2967 xphi1 = phi1 + M_PI; /* 1 */
2969 /* Second torsion */
2975 phi2 = dih_angle(x[a2i], x[a2j], x[a2k], x[a2l], pbc, r2_ij, r2_kj, r2_kl, m2, n2,
2976 &t12, &t22, &t32); /* 84 */
2978 cos_phi2 = std::cos(phi2);
2980 a2[0] = r2_ij[1]*r2_kj[2]-r2_ij[2]*r2_kj[1];
2981 a2[1] = r2_ij[2]*r2_kj[0]-r2_ij[0]*r2_kj[2];
2982 a2[2] = r2_ij[0]*r2_kj[1]-r2_ij[1]*r2_kj[0]; /* 9 */
2984 b2[0] = r2_kl[1]*r2_kj[2]-r2_kl[2]*r2_kj[1];
2985 b2[1] = r2_kl[2]*r2_kj[0]-r2_kl[0]*r2_kj[2];
2986 b2[2] = r2_kl[0]*r2_kj[1]-r2_kl[1]*r2_kj[0]; /* 9 */
2988 pbc_rvec_sub(pbc, x[a2l], x[a2k], h2);
2990 ra22 = iprod(a2, a2); /* 5 */
2991 rb22 = iprod(b2, b2); /* 5 */
2992 rg22 = iprod(r2_kj, r2_kj); /* 5 */
2998 rabr2 = sqrt(ra2r2*rb2r2);
3000 sin_phi2 = rg2 * rabr2 * iprod(a2, h2) * (-1);
3002 if (cos_phi2 < -0.5 || cos_phi2 > 0.5)
3004 phi2 = std::asin(sin_phi2);
3014 phi2 = -M_PI - phi2;
3020 phi2 = std::acos(cos_phi2);
3028 xphi2 = phi2 + M_PI; /* 1 */
3030 /* Range mangling */
3033 xphi1 = xphi1 + 2*M_PI;
3035 else if (xphi1 >= 2*M_PI)
3037 xphi1 = xphi1 - 2*M_PI;
3042 xphi2 = xphi2 + 2*M_PI;
3044 else if (xphi2 >= 2*M_PI)
3046 xphi2 = xphi2 - 2*M_PI;
3049 /* Number of grid points */
3050 dx = 2*M_PI / cmap_grid->grid_spacing;
3052 /* Where on the grid are we */
3053 iphi1 = static_cast<int>(xphi1/dx);
3054 iphi2 = static_cast<int>(xphi2/dx);
3056 iphi1 = cmap_setup_grid_index(iphi1, cmap_grid->grid_spacing, &ip1m1, &ip1p1, &ip1p2);
3057 iphi2 = cmap_setup_grid_index(iphi2, cmap_grid->grid_spacing, &ip2m1, &ip2p1, &ip2p2);
3059 pos1 = iphi1*cmap_grid->grid_spacing+iphi2;
3060 pos2 = ip1p1*cmap_grid->grid_spacing+iphi2;
3061 pos3 = ip1p1*cmap_grid->grid_spacing+ip2p1;
3062 pos4 = iphi1*cmap_grid->grid_spacing+ip2p1;
3064 ty[0] = cmapd[pos1*4];
3065 ty[1] = cmapd[pos2*4];
3066 ty[2] = cmapd[pos3*4];
3067 ty[3] = cmapd[pos4*4];
3069 ty1[0] = cmapd[pos1*4+1];
3070 ty1[1] = cmapd[pos2*4+1];
3071 ty1[2] = cmapd[pos3*4+1];
3072 ty1[3] = cmapd[pos4*4+1];
3074 ty2[0] = cmapd[pos1*4+2];
3075 ty2[1] = cmapd[pos2*4+2];
3076 ty2[2] = cmapd[pos3*4+2];
3077 ty2[3] = cmapd[pos4*4+2];
3079 ty12[0] = cmapd[pos1*4+3];
3080 ty12[1] = cmapd[pos2*4+3];
3081 ty12[2] = cmapd[pos3*4+3];
3082 ty12[3] = cmapd[pos4*4+3];
3084 /* Switch to degrees */
3085 dx = 360.0 / cmap_grid->grid_spacing;
3086 xphi1 = xphi1 * RAD2DEG;
3087 xphi2 = xphi2 * RAD2DEG;
3089 for (i = 0; i < 4; i++) /* 16 */
3092 tx[i+4] = ty1[i]*dx;
3093 tx[i+8] = ty2[i]*dx;
3094 tx[i+12] = ty12[i]*dx*dx;
3098 for (int idx = 0; idx < 16; idx++) /* 1056 */
3100 for (int k = 0; k < 16; k++)
3102 tc[idx] += cmap_coeff_matrix[k*16+idx]*tx[k];
3106 tt = (xphi1-iphi1*dx)/dx;
3107 tu = (xphi2-iphi2*dx)/dx;
3113 for (i = 3; i >= 0; i--)
3115 l1 = loop_index[i][3];
3116 l2 = loop_index[i][2];
3117 l3 = loop_index[i][1];
3119 e = tt * e + ((tc[i*4+3]*tu+tc[i*4+2])*tu + tc[i*4+1])*tu+tc[i*4];
3120 df1 = tu * df1 + (3.0*tc[l1]*tt+2.0*tc[l2])*tt+tc[l3];
3121 df2 = tt * df2 + (3.0*tc[i*4+3]*tu+2.0*tc[i*4+2])*tu+tc[i*4+1];
3131 /* Do forces - first torsion */
3132 fg1 = iprod(r1_ij, r1_kj);
3133 hg1 = iprod(r1_kl, r1_kj);
3134 fga1 = fg1*ra2r1*rgr1;
3135 hgb1 = hg1*rb2r1*rgr1;
3139 for (i = 0; i < DIM; i++)
3141 dtf1[i] = gaa1 * a1[i];
3142 dtg1[i] = fga1 * a1[i] - hgb1 * b1[i];
3143 dth1[i] = gbb1 * b1[i];
3145 f1[i] = df1 * dtf1[i];
3146 g1[i] = df1 * dtg1[i];
3147 h1[i] = df1 * dth1[i];
3150 f1_j[i] = -f1[i] - g1[i];
3151 f1_k[i] = h1[i] + g1[i];
3154 f[a1i][i] = f[a1i][i] + f1_i[i];
3155 f[a1j][i] = f[a1j][i] + f1_j[i]; /* - f1[i] - g1[i] */
3156 f[a1k][i] = f[a1k][i] + f1_k[i]; /* h1[i] + g1[i] */
3157 f[a1l][i] = f[a1l][i] + f1_l[i]; /* h1[i] */
3160 /* Do forces - second torsion */
3161 fg2 = iprod(r2_ij, r2_kj);
3162 hg2 = iprod(r2_kl, r2_kj);
3163 fga2 = fg2*ra2r2*rgr2;
3164 hgb2 = hg2*rb2r2*rgr2;
3168 for (i = 0; i < DIM; i++)
3170 dtf2[i] = gaa2 * a2[i];
3171 dtg2[i] = fga2 * a2[i] - hgb2 * b2[i];
3172 dth2[i] = gbb2 * b2[i];
3174 f2[i] = df2 * dtf2[i];
3175 g2[i] = df2 * dtg2[i];
3176 h2[i] = df2 * dth2[i];
3179 f2_j[i] = -f2[i] - g2[i];
3180 f2_k[i] = h2[i] + g2[i];
3183 f[a2i][i] = f[a2i][i] + f2_i[i]; /* f2[i] */
3184 f[a2j][i] = f[a2j][i] + f2_j[i]; /* - f2[i] - g2[i] */
3185 f[a2k][i] = f[a2k][i] + f2_k[i]; /* h2[i] + g2[i] */
3186 f[a2l][i] = f[a2l][i] + f2_l[i]; /* - h2[i] */
3190 if (fshift != nullptr)
3194 copy_ivec(SHIFT_IVEC(g, a1j), jt1);
3195 ivec_sub(SHIFT_IVEC(g, a1i), jt1, dt1_ij);
3196 ivec_sub(SHIFT_IVEC(g, a1k), jt1, dt1_kj);
3197 ivec_sub(SHIFT_IVEC(g, a1l), jt1, dt1_lj);
3198 t11 = IVEC2IS(dt1_ij);
3199 t21 = IVEC2IS(dt1_kj);
3200 t31 = IVEC2IS(dt1_lj);
3202 copy_ivec(SHIFT_IVEC(g, a2j), jt2);
3203 ivec_sub(SHIFT_IVEC(g, a2i), jt2, dt2_ij);
3204 ivec_sub(SHIFT_IVEC(g, a2k), jt2, dt2_kj);
3205 ivec_sub(SHIFT_IVEC(g, a2l), jt2, dt2_lj);
3206 t12 = IVEC2IS(dt2_ij);
3207 t22 = IVEC2IS(dt2_kj);
3208 t32 = IVEC2IS(dt2_lj);
3212 t31 = pbc_rvec_sub(pbc, x[a1l], x[a1j], h1);
3213 t32 = pbc_rvec_sub(pbc, x[a2l], x[a2j], h2);
3221 rvec_inc(fshift[t11], f1_i);
3222 rvec_inc(fshift[CENTRAL], f1_j);
3223 rvec_inc(fshift[t21], f1_k);
3224 rvec_inc(fshift[t31], f1_l);
3226 rvec_inc(fshift[t21], f2_i);
3227 rvec_inc(fshift[CENTRAL], f2_j);
3228 rvec_inc(fshift[t22], f2_k);
3229 rvec_inc(fshift[t32], f2_l);
3239 /***********************************************************
3241 * G R O M O S 9 6 F U N C T I O N S
3243 ***********************************************************/
3244 real g96harmonic(real kA, real kB, real xA, real xB, real x, real lambda,
3247 const real half = 0.5;
3248 real L1, kk, x0, dx, dx2;
3249 real v, f, dvdlambda;
3252 kk = L1*kA+lambda*kB;
3253 x0 = L1*xA+lambda*xB;
3260 dvdlambda = half*(kB-kA)*dx2 + (xA-xB)*kk*dx;
3267 /* That was 21 flops */
3270 template <BondedKernelFlavor flavor>
3271 real g96bonds(int nbonds,
3272 const t_iatom forceatoms[], const t_iparams forceparams[],
3273 const rvec x[], rvec4 f[], rvec fshift[],
3274 const t_pbc *pbc, const t_graph *g,
3275 real lambda, real *dvdlambda,
3276 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
3277 int gmx_unused *global_atom_index)
3279 int i, ki, ai, aj, type;
3280 real dr2, fbond, vbond, vtot;
3284 for (i = 0; (i < nbonds); )
3286 type = forceatoms[i++];
3287 ai = forceatoms[i++];
3288 aj = forceatoms[i++];
3290 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
3291 dr2 = iprod(dx, dx); /* 5 */
3293 *dvdlambda += g96harmonic(forceparams[type].harmonic.krA,
3294 forceparams[type].harmonic.krB,
3295 forceparams[type].harmonic.rA,
3296 forceparams[type].harmonic.rB,
3297 dr2, lambda, &vbond, &fbond);
3299 vtot += 0.5*vbond; /* 1*/
3301 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, g, fshift); /* 15 */
3306 real g96bond_angle(const rvec xi, const rvec xj, const rvec xk, const t_pbc *pbc,
3307 rvec r_ij, rvec r_kj,
3309 /* Return value is the angle between the bonds i-j and j-k */
3313 *t1 = pbc_rvec_sub(pbc, xi, xj, r_ij); /* 3 */
3314 *t2 = pbc_rvec_sub(pbc, xk, xj, r_kj); /* 3 */
3316 costh = cos_angle(r_ij, r_kj); /* 25 */
3321 template <BondedKernelFlavor flavor>
3322 real g96angles(int nbonds,
3323 const t_iatom forceatoms[], const t_iparams forceparams[],
3324 const rvec x[], rvec4 f[], rvec fshift[],
3325 const t_pbc *pbc, const t_graph *g,
3326 real lambda, real *dvdlambda,
3327 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
3328 int gmx_unused *global_atom_index)
3330 int i, ai, aj, ak, type, m, t1, t2;
3332 real cos_theta, dVdt, va, vtot;
3333 real rij_1, rij_2, rkj_1, rkj_2, rijrkj_1;
3335 ivec jt, dt_ij, dt_kj;
3338 for (i = 0; (i < nbonds); )
3340 type = forceatoms[i++];
3341 ai = forceatoms[i++];
3342 aj = forceatoms[i++];
3343 ak = forceatoms[i++];
3345 cos_theta = g96bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &t1, &t2);
3347 *dvdlambda += g96harmonic(forceparams[type].harmonic.krA,
3348 forceparams[type].harmonic.krB,
3349 forceparams[type].harmonic.rA,
3350 forceparams[type].harmonic.rB,
3351 cos_theta, lambda, &va, &dVdt);
3354 rij_1 = gmx::invsqrt(iprod(r_ij, r_ij));
3355 rkj_1 = gmx::invsqrt(iprod(r_kj, r_kj));
3356 rij_2 = rij_1*rij_1;
3357 rkj_2 = rkj_1*rkj_1;
3358 rijrkj_1 = rij_1*rkj_1; /* 23 */
3360 for (m = 0; (m < DIM); m++) /* 42 */
3362 f_i[m] = dVdt*(r_kj[m]*rijrkj_1 - r_ij[m]*rij_2*cos_theta);
3363 f_k[m] = dVdt*(r_ij[m]*rijrkj_1 - r_kj[m]*rkj_2*cos_theta);
3364 f_j[m] = -f_i[m]-f_k[m];
3370 if (computeVirial(flavor))
3374 copy_ivec(SHIFT_IVEC(g, aj), jt);
3376 ivec_sub(SHIFT_IVEC(g, ai), jt, dt_ij);
3377 ivec_sub(SHIFT_IVEC(g, ak), jt, dt_kj);
3378 t1 = IVEC2IS(dt_ij);
3379 t2 = IVEC2IS(dt_kj);
3381 rvec_inc(fshift[t1], f_i);
3382 rvec_inc(fshift[CENTRAL], f_j);
3383 rvec_inc(fshift[t2], f_k); /* 9 */
3390 template <BondedKernelFlavor flavor>
3391 real cross_bond_bond(int nbonds,
3392 const t_iatom forceatoms[], const t_iparams forceparams[],
3393 const rvec x[], rvec4 f[], rvec fshift[],
3394 const t_pbc *pbc, const t_graph *g,
3395 real gmx_unused lambda, real gmx_unused *dvdlambda,
3396 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
3397 int gmx_unused *global_atom_index)
3399 /* Potential from Lawrence and Skimmer, Chem. Phys. Lett. 372 (2003)
3402 int i, ai, aj, ak, type, m, t1, t2;
3404 real vtot, vrr, s1, s2, r1, r2, r1e, r2e, krr;
3406 ivec jt, dt_ij, dt_kj;
3409 for (i = 0; (i < nbonds); )
3411 type = forceatoms[i++];
3412 ai = forceatoms[i++];
3413 aj = forceatoms[i++];
3414 ak = forceatoms[i++];
3415 r1e = forceparams[type].cross_bb.r1e;
3416 r2e = forceparams[type].cross_bb.r2e;
3417 krr = forceparams[type].cross_bb.krr;
3419 /* Compute distance vectors ... */
3420 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], r_ij);
3421 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], r_kj);
3423 /* ... and their lengths */
3427 /* Deviations from ideality */
3431 /* Energy (can be negative!) */
3436 svmul(-krr*s2/r1, r_ij, f_i);
3437 svmul(-krr*s1/r2, r_kj, f_k);
3439 for (m = 0; (m < DIM); m++) /* 12 */
3441 f_j[m] = -f_i[m] - f_k[m];
3447 if (computeVirial(flavor))
3451 copy_ivec(SHIFT_IVEC(g, aj), jt);
3453 ivec_sub(SHIFT_IVEC(g, ai), jt, dt_ij);
3454 ivec_sub(SHIFT_IVEC(g, ak), jt, dt_kj);
3455 t1 = IVEC2IS(dt_ij);
3456 t2 = IVEC2IS(dt_kj);
3458 rvec_inc(fshift[t1], f_i);
3459 rvec_inc(fshift[CENTRAL], f_j);
3460 rvec_inc(fshift[t2], f_k); /* 9 */
3467 template <BondedKernelFlavor flavor>
3468 real cross_bond_angle(int nbonds,
3469 const t_iatom forceatoms[], const t_iparams forceparams[],
3470 const rvec x[], rvec4 f[], rvec fshift[],
3471 const t_pbc *pbc, const t_graph *g,
3472 real gmx_unused lambda, real gmx_unused *dvdlambda,
3473 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
3474 int gmx_unused *global_atom_index)
3476 /* Potential from Lawrence and Skimmer, Chem. Phys. Lett. 372 (2003)
3479 int i, ai, aj, ak, type, m, t1, t2;
3480 rvec r_ij, r_kj, r_ik;
3481 real vtot, vrt, s1, s2, s3, r1, r2, r3, r1e, r2e, r3e, krt, k1, k2, k3;
3483 ivec jt, dt_ij, dt_kj;
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);
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))
3538 copy_ivec(SHIFT_IVEC(g, aj), jt);
3540 ivec_sub(SHIFT_IVEC(g, ai), jt, dt_ij);
3541 ivec_sub(SHIFT_IVEC(g, ak), jt, dt_kj);
3542 t1 = IVEC2IS(dt_ij);
3543 t2 = IVEC2IS(dt_kj);
3545 rvec_inc(fshift[t1], f_i);
3546 rvec_inc(fshift[CENTRAL], f_j);
3547 rvec_inc(fshift[t2], f_k); /* 9 */
3554 /*! \brief Computes the potential and force for a tabulated potential */
3555 real bonded_tab(const char *type, int table_nr,
3556 const bondedtable_t *table, real kA, real kB, real r,
3557 real lambda, real *V, real *F)
3559 real k, tabscale, *VFtab, rt, eps, eps2, Yt, Ft, Geps, Heps2, Fp, VV, FF;
3563 k = (1.0 - lambda)*kA + lambda*kB;
3565 tabscale = table->scale;
3566 VFtab = table->data;
3569 n0 = static_cast<int>(rt);
3572 gmx_fatal(FARGS, "A tabulated %s interaction table number %d is out of the table range: r %f, between table indices %d and %d, table length %d",
3573 type, table_nr, r, n0, n0+1, table->n);
3580 Geps = VFtab[nnn+2]*eps;
3581 Heps2 = VFtab[nnn+3]*eps2;
3582 Fp = Ft + Geps + Heps2;
3584 FF = Fp + Geps + 2.0*Heps2;
3586 *F = -k*FF*tabscale;
3588 dvdlambda = (kB - kA)*VV;
3592 /* That was 22 flops */
3595 template <BondedKernelFlavor flavor>
3596 real tab_bonds(int nbonds,
3597 const t_iatom forceatoms[], const t_iparams forceparams[],
3598 const rvec x[], rvec4 f[], rvec fshift[],
3599 const t_pbc *pbc, const t_graph *g,
3600 real lambda, real *dvdlambda,
3601 const t_mdatoms gmx_unused *md, t_fcdata *fcd,
3602 int gmx_unused *global_atom_index)
3604 int i, ki, ai, aj, type, table;
3605 real dr, dr2, fbond, vbond, vtot;
3609 for (i = 0; (i < nbonds); )
3611 type = forceatoms[i++];
3612 ai = forceatoms[i++];
3613 aj = forceatoms[i++];
3615 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
3616 dr2 = iprod(dx, dx); /* 5 */
3617 dr = dr2*gmx::invsqrt(dr2); /* 10 */
3619 table = forceparams[type].tab.table;
3621 *dvdlambda += bonded_tab("bond", table,
3622 &fcd->bondtab[table],
3623 forceparams[type].tab.kA,
3624 forceparams[type].tab.kB,
3625 dr, lambda, &vbond, &fbond); /* 22 */
3633 vtot += vbond; /* 1*/
3634 fbond *= gmx::invsqrt(dr2); /* 6 */
3636 spreadBondForces<flavor>(fbond, dx, ai, aj, f, ki, g, fshift); /* 15 */
3641 template <BondedKernelFlavor flavor>
3642 real tab_angles(int nbonds,
3643 const t_iatom forceatoms[], const t_iparams forceparams[],
3644 const rvec x[], rvec4 f[], rvec fshift[],
3645 const t_pbc *pbc, const t_graph *g,
3646 real lambda, real *dvdlambda,
3647 const t_mdatoms gmx_unused *md, t_fcdata *fcd,
3648 int gmx_unused *global_atom_index)
3650 int i, ai, aj, ak, t1, t2, type, table;
3652 real cos_theta, cos_theta2, theta, dVdt, va, vtot;
3653 ivec jt, dt_ij, dt_kj;
3656 for (i = 0; (i < nbonds); )
3658 type = forceatoms[i++];
3659 ai = forceatoms[i++];
3660 aj = forceatoms[i++];
3661 ak = forceatoms[i++];
3663 theta = bond_angle(x[ai], x[aj], x[ak], pbc,
3664 r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
3666 table = forceparams[type].tab.table;
3668 *dvdlambda += bonded_tab("angle", table,
3669 &fcd->angletab[table],
3670 forceparams[type].tab.kA,
3671 forceparams[type].tab.kB,
3672 theta, lambda, &va, &dVdt); /* 22 */
3675 cos_theta2 = gmx::square(cos_theta); /* 1 */
3684 st = dVdt*gmx::invsqrt(1 - cos_theta2); /* 12 */
3685 sth = st*cos_theta; /* 1 */
3686 nrkj2 = iprod(r_kj, r_kj); /* 5 */
3687 nrij2 = iprod(r_ij, r_ij);
3689 cik = st*gmx::invsqrt(nrkj2*nrij2); /* 12 */
3690 cii = sth/nrij2; /* 10 */
3691 ckk = sth/nrkj2; /* 10 */
3693 for (m = 0; (m < DIM); m++) /* 39 */
3695 f_i[m] = -(cik*r_kj[m]-cii*r_ij[m]);
3696 f_k[m] = -(cik*r_ij[m]-ckk*r_kj[m]);
3697 f_j[m] = -f_i[m]-f_k[m];
3703 if (computeVirial(flavor))
3707 copy_ivec(SHIFT_IVEC(g, aj), jt);
3709 ivec_sub(SHIFT_IVEC(g, ai), jt, dt_ij);
3710 ivec_sub(SHIFT_IVEC(g, ak), jt, dt_kj);
3711 t1 = IVEC2IS(dt_ij);
3712 t2 = IVEC2IS(dt_kj);
3714 rvec_inc(fshift[t1], f_i);
3715 rvec_inc(fshift[CENTRAL], f_j);
3716 rvec_inc(fshift[t2], f_k);
3723 template <BondedKernelFlavor flavor>
3724 real tab_dihs(int nbonds,
3725 const t_iatom forceatoms[], const t_iparams forceparams[],
3726 const rvec x[], rvec4 f[], rvec fshift[],
3727 const t_pbc *pbc, const t_graph *g,
3728 real lambda, real *dvdlambda,
3729 const t_mdatoms gmx_unused *md, t_fcdata *fcd,
3730 int gmx_unused *global_atom_index)
3732 int i, type, ai, aj, ak, al, table;
3734 rvec r_ij, r_kj, r_kl, m, n;
3735 real phi, ddphi, vpd, vtot;
3738 for (i = 0; (i < nbonds); )
3740 type = forceatoms[i++];
3741 ai = forceatoms[i++];
3742 aj = forceatoms[i++];
3743 ak = forceatoms[i++];
3744 al = forceatoms[i++];
3746 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n,
3747 &t1, &t2, &t3); /* 84 */
3749 table = forceparams[type].tab.table;
3751 /* Hopefully phi+M_PI never results in values < 0 */
3752 *dvdlambda += bonded_tab("dihedral", table,
3753 &fcd->dihtab[table],
3754 forceparams[type].tab.kA,
3755 forceparams[type].tab.kB,
3756 phi+M_PI, lambda, &vpd, &ddphi);
3759 do_dih_fup<flavor>(ai, aj, ak, al, -ddphi, r_ij, r_kj, r_kl, m, n,
3760 f, fshift, pbc, g, x, t1, t2, t3); /* 112 */
3767 struct BondedInteractions
3769 BondedFunction function;
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 const std::array<BondedInteractions, F_NRE> c_bondedInteractionFunctions
3779 BondedInteractions {bonds<flavor>, eNR_BONDS }, // F_BONDS
3780 BondedInteractions {g96bonds<flavor>, eNR_BONDS }, // F_G96BONDS
3781 BondedInteractions {morse_bonds<flavor>, eNR_MORSE }, // F_MORSE
3782 BondedInteractions {cubic_bonds<flavor>, eNR_CUBICBONDS }, // F_CUBICBONDS
3783 BondedInteractions {unimplemented, -1 }, // F_CONNBONDS
3784 BondedInteractions {bonds<flavor>, eNR_BONDS }, // F_HARMONIC
3785 BondedInteractions {FENE_bonds<flavor>, eNR_FENEBONDS }, // F_FENEBONDS
3786 BondedInteractions {tab_bonds<flavor>, eNR_TABBONDS }, // F_TABBONDS
3787 BondedInteractions {tab_bonds<flavor>, eNR_TABBONDS }, // F_TABBONDSNC
3788 BondedInteractions {restraint_bonds<flavor>, eNR_RESTRBONDS }, // F_RESTRBONDS
3789 BondedInteractions {angles<flavor>, eNR_ANGLES }, // F_ANGLES
3790 BondedInteractions {g96angles<flavor>, eNR_ANGLES }, // F_G96ANGLES
3791 BondedInteractions {restrangles<flavor>, eNR_ANGLES }, // F_RESTRANGLES
3792 BondedInteractions {linear_angles<flavor>, eNR_ANGLES }, // F_LINEAR_ANGLES
3793 BondedInteractions {cross_bond_bond<flavor>, eNR_CROSS_BOND_BOND }, // F_CROSS_BOND_BONDS
3794 BondedInteractions {cross_bond_angle<flavor>, eNR_CROSS_BOND_ANGLE }, // F_CROSS_BOND_ANGLES
3795 BondedInteractions {urey_bradley<flavor>, eNR_UREY_BRADLEY }, // F_UREY_BRADLEY
3796 BondedInteractions {quartic_angles<flavor>, eNR_QANGLES }, // F_QUARTIC_ANGLES
3797 BondedInteractions {tab_angles<flavor>, eNR_TABANGLES }, // F_TABANGLES
3798 BondedInteractions {pdihs<flavor>, eNR_PROPER }, // F_PDIHS
3799 BondedInteractions {rbdihs<flavor>, eNR_RB }, // F_RBDIHS
3800 BondedInteractions {restrdihs<flavor>, eNR_PROPER }, // F_RESTRDIHS
3801 BondedInteractions {cbtdihs<flavor>, eNR_RB }, // F_CBTDIHS
3802 BondedInteractions {rbdihs<flavor>, eNR_FOURDIH }, // F_FOURDIHS
3803 BondedInteractions {idihs<flavor>, eNR_IMPROPER }, // F_IDIHS
3804 BondedInteractions {pdihs<flavor>, eNR_IMPROPER }, // F_PIDIHS
3805 BondedInteractions {tab_dihs<flavor>, eNR_TABDIHS }, // F_TABDIHS
3806 BondedInteractions {unimplemented, eNR_CMAP }, // F_CMAP
3807 BondedInteractions {unimplemented, -1 }, // F_GB12_NOLONGERUSED
3808 BondedInteractions {unimplemented, -1 }, // F_GB13_NOLONGERUSED
3809 BondedInteractions {unimplemented, -1 }, // F_GB14_NOLONGERUSED
3810 BondedInteractions {unimplemented, -1 }, // F_GBPOL_NOLONGERUSED
3811 BondedInteractions {unimplemented, -1 }, // F_NPSOLVATION_NOLONGERUSED
3812 BondedInteractions {unimplemented, eNR_NB14 }, // F_LJ14
3813 BondedInteractions {unimplemented, -1 }, // F_COUL14
3814 BondedInteractions {unimplemented, eNR_NB14 }, // F_LJC14_Q
3815 BondedInteractions {unimplemented, eNR_NB14 }, // F_LJC_PAIRS_NB
3816 BondedInteractions {unimplemented, -1 }, // F_LJ
3817 BondedInteractions {unimplemented, -1 }, // F_BHAM
3818 BondedInteractions {unimplemented, -1 }, // F_LJ_LR_NOLONGERUSED
3819 BondedInteractions {unimplemented, -1 }, // F_BHAM_LR_NOLONGERUSED
3820 BondedInteractions {unimplemented, -1 }, // F_DISPCORR
3821 BondedInteractions {unimplemented, -1 }, // F_COUL_SR
3822 BondedInteractions {unimplemented, -1 }, // F_COUL_LR_NOLONGERUSED
3823 BondedInteractions {unimplemented, -1 }, // F_RF_EXCL
3824 BondedInteractions {unimplemented, -1 }, // F_COUL_RECIP
3825 BondedInteractions {unimplemented, -1 }, // F_LJ_RECIP
3826 BondedInteractions {unimplemented, -1 }, // F_DPD
3827 BondedInteractions {polarize<flavor>, eNR_POLARIZE }, // F_POLARIZATION
3828 BondedInteractions {water_pol<flavor>, eNR_WPOL }, // F_WATER_POL
3829 BondedInteractions {thole_pol<flavor>, eNR_THOLE }, // F_THOLE_POL
3830 BondedInteractions {anharm_polarize<flavor>, eNR_ANHARM_POL }, // F_ANHARM_POL
3831 BondedInteractions {unimplemented, -1 }, // F_POSRES
3832 BondedInteractions {unimplemented, -1 }, // F_FBPOSRES
3833 BondedInteractions {ta_disres, eNR_DISRES }, // F_DISRES
3834 BondedInteractions {unimplemented, -1 }, // F_DISRESVIOL
3835 BondedInteractions {orires, eNR_ORIRES }, // F_ORIRES
3836 BondedInteractions {unimplemented, -1 }, // F_ORIRESDEV
3837 BondedInteractions {angres<flavor>, eNR_ANGRES }, // F_ANGRES
3838 BondedInteractions {angresz<flavor>, eNR_ANGRESZ }, // F_ANGRESZ
3839 BondedInteractions {dihres<flavor>, eNR_DIHRES }, // F_DIHRES
3840 BondedInteractions {unimplemented, -1 }, // F_DIHRESVIOL
3841 BondedInteractions {unimplemented, -1 }, // F_CONSTR
3842 BondedInteractions {unimplemented, -1 }, // F_CONSTRNC
3843 BondedInteractions {unimplemented, -1 }, // F_SETTLE
3844 BondedInteractions {unimplemented, -1 }, // F_VSITE2
3845 BondedInteractions {unimplemented, -1 }, // F_VSITE3
3846 BondedInteractions {unimplemented, -1 }, // F_VSITE3FD
3847 BondedInteractions {unimplemented, -1 }, // F_VSITE3FAD
3848 BondedInteractions {unimplemented, -1 }, // F_VSITE3OUT
3849 BondedInteractions {unimplemented, -1 }, // F_VSITE4FD
3850 BondedInteractions {unimplemented, -1 }, // F_VSITE4FDN
3851 BondedInteractions {unimplemented, -1 }, // F_VSITEN
3852 BondedInteractions {unimplemented, -1 }, // F_COM_PULL
3853 BondedInteractions {unimplemented, -1 }, // F_DENSITYFITTING
3854 BondedInteractions {unimplemented, -1 }, // F_EQM
3855 BondedInteractions {unimplemented, -1 }, // F_EPOT
3856 BondedInteractions {unimplemented, -1 }, // F_EKIN
3857 BondedInteractions {unimplemented, -1 }, // F_ETOT
3858 BondedInteractions {unimplemented, -1 }, // F_ECONSERVED
3859 BondedInteractions {unimplemented, -1 }, // F_TEMP
3860 BondedInteractions {unimplemented, -1 }, // F_VTEMP_NOLONGERUSED
3861 BondedInteractions {unimplemented, -1 }, // F_PDISPCORR
3862 BondedInteractions {unimplemented, -1 }, // F_PRES
3863 BondedInteractions {unimplemented, -1 }, // F_DVDL_CONSTR
3864 BondedInteractions {unimplemented, -1 }, // F_DVDL
3865 BondedInteractions {unimplemented, -1 }, // F_DKDL
3866 BondedInteractions {unimplemented, -1 }, // F_DVDL_COUL
3867 BondedInteractions {unimplemented, -1 }, // F_DVDL_VDW
3868 BondedInteractions {unimplemented, -1 }, // F_DVDL_BONDED
3869 BondedInteractions {unimplemented, -1 }, // F_DVDL_RESTRAINT
3870 BondedInteractions {unimplemented, -1 }, // F_DVDL_TEMPERATURE
3873 /*! \brief List of instantiated BondedInteractions list */
3874 const gmx::EnumerationArray < BondedKernelFlavor, std::array < BondedInteractions, F_NRE>> c_bondedInteractionFunctionsPerFlavor =
3876 c_bondedInteractionFunctions<BondedKernelFlavor::ForcesSimdWhenAvailable>,
3877 c_bondedInteractionFunctions<BondedKernelFlavor::ForcesNoSimd>,
3878 c_bondedInteractionFunctions<BondedKernelFlavor::ForcesAndVirialAndEnergy>,
3879 c_bondedInteractionFunctions<BondedKernelFlavor::ForcesAndEnergy>
3886 real calculateSimpleBond(const int ftype,
3887 const int numForceatoms, const t_iatom forceatoms[],
3888 const t_iparams forceparams[],
3889 const rvec x[], rvec4 f[], rvec fshift[],
3890 const struct t_pbc *pbc,
3891 const struct t_graph gmx_unused *g,
3892 const real lambda, real *dvdlambda,
3893 const t_mdatoms *md, t_fcdata *fcd,
3894 int gmx_unused *global_atom_index,
3895 const BondedKernelFlavor bondedKernelFlavor)
3897 const BondedInteractions &bonded =
3898 c_bondedInteractionFunctionsPerFlavor[bondedKernelFlavor][ftype];
3900 real v = bonded.function(numForceatoms, forceatoms,
3903 pbc, g, lambda, dvdlambda,
3904 md, fcd, global_atom_index);
3909 int nrnbIndex(int ftype)
3911 return c_bondedInteractionFunctions<BondedKernelFlavor::ForcesAndVirialAndEnergy>[ftype].nrnbIndex;