2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
5 * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
6 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
7 * and including many others, as listed in the AUTHORS file in the
8 * top-level source directory and at http://www.gromacs.org.
10 * GROMACS is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * as published by the Free Software Foundation; either version 2.1
13 * of the License, or (at your option) any later version.
15 * GROMACS is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with GROMACS; if not, see
22 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * If you want to redistribute modifications to GROMACS, please
26 * consider that scientific software is very special. Version
27 * control is crucial - bugs must be traceable. We will be happy to
28 * consider code for inclusion in the official distribution, but
29 * derived work must not be called official GROMACS. Details are found
30 * in the README & COPYING files - if they are missing, get the
31 * official version at http://www.gromacs.org.
33 * To help us fund GROMACS development, we humbly ask that you cite
34 * the research papers on the package. Check out http://www.gromacs.org.
38 * \brief This file defines functions for "pair" interactions
39 * (i.e. listed non-bonded interactions, e.g. 1-4 interactions)
41 * \author Mark Abraham <mark.j.abraham@gmail.com>
43 * \ingroup module_listed_forces
51 #include "gromacs/listed_forces/bonded.h"
52 #include "gromacs/math/functions.h"
53 #include "gromacs/math/vec.h"
54 #include "gromacs/mdtypes/forcerec.h"
55 #include "gromacs/mdtypes/group.h"
56 #include "gromacs/mdtypes/interaction_const.h"
57 #include "gromacs/mdtypes/md_enums.h"
58 #include "gromacs/mdtypes/nblist.h"
59 #include "gromacs/mdtypes/simulation_workload.h"
60 #include "gromacs/pbcutil/ishift.h"
61 #include "gromacs/pbcutil/pbc.h"
62 #include "gromacs/pbcutil/pbc_simd.h"
63 #include "gromacs/simd/simd.h"
64 #include "gromacs/simd/simd_math.h"
65 #include "gromacs/simd/vector_operations.h"
66 #include "gromacs/tables/forcetable.h"
67 #include "gromacs/utility/basedefinitions.h"
68 #include "gromacs/utility/fatalerror.h"
69 #include "gromacs/utility/gmxassert.h"
71 #include "listed_internal.h"
73 using namespace gmx; // TODO: Remove when this file is moved into gmx namespace
75 /*! \brief Issue a warning if a listed interaction is beyond a table limit */
76 static void warning_rlimit(const rvec* x, int ai, int aj, int* global_atom_index, real r, real rlimit)
79 "Listed nonbonded interaction between particles %d and %d\n"
80 "at distance %.3f which is larger than the table limit %.3f nm.\n\n"
81 "This is likely either a 1,4 interaction, or a listed interaction inside\n"
82 "a smaller molecule you are decoupling during a free energy calculation.\n"
83 "Since interactions at distances beyond the table cannot be computed,\n"
84 "they are skipped until they are inside the table limit again. You will\n"
85 "only see this message once, even if it occurs for several interactions.\n\n"
86 "IMPORTANT: This should not happen in a stable simulation, so there is\n"
87 "probably something wrong with your system. Only change the table-extension\n"
88 "distance in the mdp file if you are really sure that is the reason.\n",
89 glatnr(global_atom_index, ai),
90 glatnr(global_atom_index, aj),
97 "%8f %8f %8f\n%8f %8f %8f\n1-4 (%d,%d) interaction not within cut-off! r=%g. "
105 glatnr(global_atom_index, ai),
106 glatnr(global_atom_index, aj),
111 /*! \brief Compute the energy and force for a single pair interaction */
112 static real evaluate_single(real r2,
122 real rinv, r, rtab, eps, eps2, Y, F, Geps, Heps2, Fp, VVe, FFe, VVd, FFd, VVr, FFr, fscal;
125 /* Do the tabulated interactions - first table lookup */
126 rinv = gmx::invsqrt(r2);
129 ntab = static_cast<int>(rtab);
132 ntab = static_cast<int>(tableStride * ntab);
136 Geps = eps * vftab[ntab + 2];
137 Heps2 = eps2 * vftab[ntab + 3];
138 Fp = F + Geps + Heps2;
140 FFe = Fp + Geps + 2.0 * Heps2;
144 Geps = eps * vftab[ntab + 6];
145 Heps2 = eps2 * vftab[ntab + 7];
146 Fp = F + Geps + Heps2;
148 FFd = Fp + Geps + 2.0 * Heps2;
152 Geps = eps * vftab[ntab + 10];
153 Heps2 = eps2 * vftab[ntab + 11];
154 Fp = F + Geps + Heps2;
156 FFr = Fp + Geps + 2.0 * Heps2;
159 *vvdw = c6 * VVd + c12 * VVr;
161 fscal = -(qq * FFe + c6 * FFd + c12 * FFr) * tabscale * rinv;
166 static inline real sixthRoot(const real r)
168 return gmx::invsqrt(std::cbrt(r));
171 /*! \brief Compute the energy and force for a single pair interaction under FEP */
172 template<KernelSoftcoreType softcoreType>
173 static real free_energy_evaluate_single(real r2,
175 const interaction_const_t::SoftCoreParameters& scParams,
189 const real lfac_coul[2],
190 const real lfac_vdw[2],
191 const real dlfac_coul[2],
192 const real dlfac_vdw[2],
197 real rtab, eps, eps2, Y, F, Geps, Heps2, Fp, VV, FF, fscal;
198 real qq[2], c6[2], c12[2], sigma6[2], sigma_pow[2];
199 real alpha_coul_eff, alpha_vdw_eff, dvdl_coul_sum, dvdl_vdw_sum;
200 real rpinv, r_coul, r_vdw, velecsum, vvdwsum;
201 real fscal_vdw[2], fscal_elec[2];
202 real velec[2], vvdw[2];
203 real dvdl_elec[2], dvdl_vdw[2];
204 real gapsysScaleLinpointCoul, gapsysScaleLinpointVdW, gapsysSigma6VdW[2];
208 const real half = 0.5_real;
209 const real one = 1.0_real;
210 const real two = 2.0_real;
219 const real rpm2 = r2 * r2; /* r4 */
220 const real rp = rpm2 * r2; /* r6 */
221 const real r = sqrt(r2); /* r1 */
223 /* Loop over state A(0) and B(1) */
224 for (i = 0; i < 2; i++)
226 if constexpr (softcoreType == KernelSoftcoreType::Beutler)
228 if ((c6[i] > 0) && (c12[i] > 0))
230 /* The c6 & c12 coefficients now contain the constants 6.0 and 12.0, respectively.
231 * Correct for this by multiplying with (1/12.0)/(1/6.0)=6.0/12.0=0.5.
233 sigma6[i] = half * c12[i] / c6[i];
234 if (sigma6[i] < scParams.sigma6Minimum) /* for disappearing coul and vdw with soft core at the same time */
236 sigma6[i] = scParams.sigma6Minimum;
241 sigma6[i] = scParams.sigma6WithInvalidSigma;
243 sigma_pow[i] = sigma6[i];
245 if constexpr (softcoreType == KernelSoftcoreType::Gapsys)
247 if ((c6[i] > 0) && (c12[i] > 0))
249 /* The c6 & c12 coefficients now contain the constants 6.0 and 12.0, respectively.
250 * Correct for this by multiplying with (1/12.0)/(1/6.0)=6.0/12.0=0.5.
252 gapsysSigma6VdW[i] = half * c12[i] / c6[i];
256 gapsysSigma6VdW[i] = scParams.gapsysSigma6VdW;
261 if constexpr (softcoreType == KernelSoftcoreType::Beutler)
263 /* only use softcore if one of the states has a zero endstate - softcore is for avoiding infinities!*/
264 if ((c12[0] > 0) && (c12[1] > 0))
271 alpha_vdw_eff = scParams.alphaVdw;
272 alpha_coul_eff = scParams.alphaCoulomb;
275 if constexpr (softcoreType == KernelSoftcoreType::Gapsys)
277 /* only use softcore if one of the states has a zero endstate - softcore is for avoiding infinities!*/
278 if ((c12[0] > 0) && (c12[1] > 0))
280 gapsysScaleLinpointVdW = 0;
281 gapsysScaleLinpointCoul = 0;
285 gapsysScaleLinpointVdW = scParams.gapsysScaleLinpointVdW;
286 gapsysScaleLinpointCoul = scParams.gapsysScaleLinpointCoul;
290 /* Loop over A and B states again */
291 for (i = 0; i < 2; i++)
302 /* Only spend time on A or B state if it is non-zero */
303 if ((qq[i] != 0) || (c6[i] != 0) || (c12[i] != 0))
306 if constexpr (softcoreType == KernelSoftcoreType::Beutler)
308 rpinv = one / (alpha_coul_eff * lfac_coul[i] * sigma_pow[i] + rp);
309 r_coul = sixthRoot(rpinv);
317 if constexpr (softcoreType == KernelSoftcoreType::Gapsys)
319 if ((facel != 0) && (LFC[i] < 1))
321 rQ = gmx::sixthroot(one - LFC[i]) * (one + std::fabs(qq[i] / facel));
322 rQ *= gapsysScaleLinpointCoul;
329 if (rQ > rCoulCutoff)
336 if ((softcoreType == KernelSoftcoreType::Gapsys) && (r < rQ))
338 real rInvQ = one / rQ;
339 real constFac = qq[i] * rInvQ;
340 real linFac = constFac * r * rInvQ;
341 real quadrFac = linFac * r * rInvQ;
343 /* Computing Coulomb force and potential energy */
344 fscal_elec[i] = -2 * quadrFac + 3 * linFac;
345 fscal_elec[i] *= rpinv;
347 velec[i] = quadrFac - 3 * (linFac - constFac);
349 dvdl_elec[i] += scaleDvdlRCoul * DLF[i] * half * (LFC[i] / (1 - LFC[i]))
350 * (quadrFac - 2 * linFac + constFac);
352 else // Beutler, resp. hardcore
354 /* Electrostatics table lookup data */
355 rtab = r_coul * tabscale;
356 ntab = static_cast<int>(rtab);
359 ntab = static_cast<int>(tableStride * ntab);
363 Geps = eps * vftab[ntab + 2];
364 Heps2 = eps2 * vftab[ntab + 3];
365 Fp = F + Geps + Heps2;
367 FF = Fp + Geps + two * Heps2;
368 velec[i] = qq[i] * VV;
369 fscal_elec[i] = -qq[i] * FF * r_coul * rpinv * tabscale;
373 if constexpr (softcoreType == KernelSoftcoreType::Beutler)
375 rpinv = one / (alpha_vdw_eff * lfac_vdw[i] * sigma_pow[i] + rp);
376 r_vdw = sixthRoot(rpinv);
384 if constexpr (softcoreType == KernelSoftcoreType::Gapsys)
386 constexpr real c_twentySixSeventh = 26.0_real / 7.0_real;
391 rLJ = gmx::sixthroot(c_twentySixSeventh * gapsysSigma6VdW[i] * (one - LFV[i]));
392 rLJ *= gapsysScaleLinpointVdW;
400 if ((softcoreType == KernelSoftcoreType::Gapsys) && (r < rLJ))
402 // scaled values for c6 and c12
404 c6s = c6[i] / 6.0_real;
405 c12s = c12[i] / 12.0_real;
407 /* Temporary variables for inverted values */
408 real rInvLJ = one / rLJ;
409 real rInv14, rInv13, rInv12;
410 real rInv8, rInv7, rInv6;
411 rInv6 = rInvLJ * rInvLJ * rInvLJ;
413 rInv7 = rInv6 * rInvLJ;
414 rInv8 = rInv7 * rInvLJ;
415 rInv14 = c12s * rInv7 * rInv7 * r2;
416 rInv13 = c12s * rInv7 * rInv6 * r;
417 rInv12 = c12s * rInv6 * rInv6;
422 /* Temporary variables for A and B */
423 real quadrFac, linearFac, constFac;
424 quadrFac = 156 * rInv14 - 42 * rInv8;
425 linearFac = 168 * rInv13 - 48 * rInv7;
426 constFac = 91 * rInv12 - 28 * rInv6;
428 /* Computing LJ force and potential energy*/
429 fscal_vdw[i] = -quadrFac + linearFac;
430 fscal_vdw[i] *= rpinv;
432 vvdw[i] = 0.5_real * quadrFac - linearFac + constFac;
434 dvdl_vdw[i] += DLF[i] * 28 * (LFV[i] / (one - LFV[i]))
435 * ((6.5_real * rInv14 - rInv8) - (13 * rInv13 - 2 * rInv7)
436 + (6.5_real * rInv12 - rInv6));
438 else // Beutler, resp. hardcore
440 /* Vdw table lookup data */
441 rtab = r_vdw * tabscale;
442 ntab = static_cast<int>(rtab);
449 Geps = eps * vftab[ntab + 6];
450 Heps2 = eps2 * vftab[ntab + 7];
451 Fp = F + Geps + Heps2;
453 FF = Fp + Geps + two * Heps2;
454 vvdw[i] = c6[i] * VV;
455 fscal_vdw[i] = -c6[i] * FF;
460 Geps = eps * vftab[ntab + 10];
461 Heps2 = eps2 * vftab[ntab + 11];
462 Fp = F + Geps + Heps2;
464 FF = Fp + Geps + two * Heps2;
465 vvdw[i] += c12[i] * VV;
466 fscal_vdw[i] -= c12[i] * FF;
467 fscal_vdw[i] *= r_vdw * rpinv * tabscale;
471 /* Now we have velec[i], vvdw[i], and fscal[i] for both states */
472 /* Assemble A and B states */
478 for (i = 0; i < 2; i++)
480 velecsum += LFC[i] * velec[i];
481 vvdwsum += LFV[i] * vvdw[i];
483 fscal += (LFC[i] * fscal_elec[i] + LFV[i] * fscal_vdw[i]) * rpm2;
485 if constexpr (softcoreType == KernelSoftcoreType::Gapsys)
487 dvdl_coul_sum += dvdl_elec[i];
488 dvdl_vdw_sum += dvdl_vdw[i];
490 dvdl_coul_sum += velec[i] * DLF[i];
491 dvdl_vdw_sum += vvdw[i] * DLF[i];
492 if constexpr (softcoreType == KernelSoftcoreType::Beutler)
494 dvdl_coul_sum += LFC[i] * alpha_coul_eff * dlfac_coul[i] * fscal_elec[i] * sigma_pow[i];
495 dvdl_vdw_sum += LFV[i] * alpha_vdw_eff * dlfac_vdw[i] * fscal_vdw[i] * sigma_pow[i];
499 dvdl[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)] += dvdl_coul_sum;
500 dvdl[static_cast<int>(FreeEnergyPerturbationCouplingType::Vdw)] += dvdl_vdw_sum;
502 *velectot = velecsum;
508 /*! \brief Calculate pair interactions, supports all types and conditions. */
509 template<BondedKernelFlavor flavor>
510 static real do_pairs_general(int ftype,
512 const t_iatom iatoms[],
513 const t_iparams iparams[],
517 const struct t_pbc* pbc,
520 gmx::ArrayRef<real> chargeA,
521 gmx::ArrayRef<real> chargeB,
522 gmx::ArrayRef<bool> atomIsPerturbed,
523 gmx::ArrayRef<unsigned short> cENER,
525 const t_forcerec* fr,
526 gmx_grppairener_t* grppener,
527 int* global_atom_index)
531 int i, itype, ai, aj, gid;
534 real fscal, velec, vvdw;
535 real* energygrp_elec;
537 static gmx_bool warned_rlimit = FALSE;
538 /* Free energy stuff */
539 gmx_bool bFreeEnergy;
540 real LFC[2], LFV[2], DLF[2], lfac_coul[2], lfac_vdw[2], dlfac_coul[2], dlfac_vdw[2];
542 const real oneSixth = 1.0_real / 6.0_real;
548 energygrp_elec = grppener->energyGroupPairTerms[NonBondedEnergyTerms::Coulomb14].data();
549 energygrp_vdw = grppener->energyGroupPairTerms[NonBondedEnergyTerms::LJ14].data();
552 energygrp_elec = grppener->energyGroupPairTerms[NonBondedEnergyTerms::CoulombSR].data();
553 energygrp_vdw = grppener->energyGroupPairTerms[NonBondedEnergyTerms::LJSR].data();
556 energygrp_elec = nullptr; /* Keep compiler happy */
557 energygrp_vdw = nullptr; /* Keep compiler happy */
558 gmx_fatal(FARGS, "Unknown function type %d in do_nonbonded14", ftype);
561 if (fr->efep != FreeEnergyPerturbationType::No)
563 /* Lambda factor for state A=1-lambda and B=lambda */
564 LFC[0] = 1.0 - lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)];
565 LFV[0] = 1.0 - lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Vdw)];
566 LFC[1] = lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)];
567 LFV[1] = lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Vdw)];
569 /*derivative of the lambda factor for state A and B */
573 GMX_ASSERT(fr->ic->softCoreParameters, "We need soft-core parameters");
574 const auto& scParams = *fr->ic->softCoreParameters;
576 for (i = 0; i < 2; i++)
578 lfac_coul[i] = (scParams.lambdaPower == 2 ? (1 - LFC[i]) * (1 - LFC[i]) : (1 - LFC[i]));
579 dlfac_coul[i] = DLF[i] * scParams.lambdaPower * oneSixth
580 * (scParams.lambdaPower == 2 ? (1 - LFC[i]) : 1);
581 lfac_vdw[i] = (scParams.lambdaPower == 2 ? (1 - LFV[i]) * (1 - LFV[i]) : (1 - LFV[i]));
582 dlfac_vdw[i] = DLF[i] * scParams.lambdaPower * oneSixth
583 * (scParams.lambdaPower == 2 ? (1 - LFV[i]) : 1);
587 /* TODO This code depends on the logic in tables.c that constructs
588 the table layout, which should be made explicit in future
592 "Pair-interaction code that uses GROMACS interaction tables supports exactly 3 tables");
594 fr->pairsTable->interaction == TableInteraction::ElectrostaticVdwRepulsionVdwDispersion,
595 "Pair interaction kernels need a table with Coulomb, repulsion and dispersion entries");
597 const real epsfac = fr->ic->epsfac;
600 for (i = 0; (i < nbonds);)
605 gid = GID(cENER[ai], cENER[aj], numEnergyGroups);
612 (fr->efep != FreeEnergyPerturbationType::No
613 && ((!atomIsPerturbed.empty() && (atomIsPerturbed[ai] || atomIsPerturbed[aj]))
614 || iparams[itype].lj14.c6A != iparams[itype].lj14.c6B
615 || iparams[itype].lj14.c12A != iparams[itype].lj14.c12B));
616 qq = chargeA[ai] * chargeA[aj] * epsfac * fr->fudgeQQ;
617 c6 = iparams[itype].lj14.c6A;
618 c12 = iparams[itype].lj14.c12A;
621 qq = iparams[itype].ljc14.qi * iparams[itype].ljc14.qj * epsfac
622 * iparams[itype].ljc14.fqq;
623 c6 = iparams[itype].ljc14.c6;
624 c12 = iparams[itype].ljc14.c12;
627 qq = iparams[itype].ljcnb.qi * iparams[itype].ljcnb.qj * epsfac;
628 c6 = iparams[itype].ljcnb.c6;
629 c12 = iparams[itype].ljcnb.c12;
632 /* Cannot happen since we called gmx_fatal() above in this case */
633 qq = c6 = c12 = 0; /* Keep compiler happy */
637 /* To save flops in the optimized kernels, c6/c12 have 6.0/12.0 derivative prefactors
638 * included in the general nfbp array now. This means the tables are scaled down by the
639 * same factor, so when we use the original c6/c12 parameters from iparams[] they must
645 /* Do we need to apply full periodic boundary conditions? */
648 fshift_index = pbc_dx_aiuc(pbc, x[ai], x[aj], dx);
652 fshift_index = c_centralShiftIndex;
653 rvec_sub(x[ai], x[aj], dx);
657 if (r2 >= fr->pairsTable->interactionRange * fr->pairsTable->interactionRange)
659 /* This check isn't race free. But it doesn't matter because if a race occurs the only
660 * disadvantage is that the warning is printed twice */
663 warning_rlimit(x, ai, aj, global_atom_index, sqrt(r2), fr->pairsTable->interactionRange);
664 warned_rlimit = TRUE;
671 /* Currently free energy is only supported for F_LJ14, so no need to check for that if we got here */
672 qqB = chargeB[ai] * chargeB[aj] * epsfac * fr->fudgeQQ;
673 c6B = iparams[itype].lj14.c6B * 6.0;
674 c12B = iparams[itype].lj14.c12B * 12.0;
676 const auto& scParams = *fr->ic->softCoreParameters;
677 if (scParams.softcoreType == SoftcoreType::Beutler)
679 if (scParams.alphaCoulomb == 0 && scParams.alphaVdw == 0)
681 fscal = free_energy_evaluate_single<KernelSoftcoreType::None>(
684 *fr->ic->softCoreParameters,
685 fr->pairsTable->scale,
686 fr->pairsTable->data.data(),
687 fr->pairsTable->stride,
708 fscal = free_energy_evaluate_single<KernelSoftcoreType::Beutler>(
711 *fr->ic->softCoreParameters,
712 fr->pairsTable->scale,
713 fr->pairsTable->data.data(),
714 fr->pairsTable->stride,
736 if (scParams.gapsysScaleLinpointCoul == 0 && scParams.gapsysScaleLinpointVdW == 0)
738 fscal = free_energy_evaluate_single<KernelSoftcoreType::None>(
741 *fr->ic->softCoreParameters,
742 fr->pairsTable->scale,
743 fr->pairsTable->data.data(),
744 fr->pairsTable->stride,
765 fscal = free_energy_evaluate_single<KernelSoftcoreType::Gapsys>(
768 *fr->ic->softCoreParameters,
769 fr->pairsTable->scale,
770 fr->pairsTable->data.data(),
771 fr->pairsTable->stride,
794 /* Evaluate tabulated interaction without free energy */
795 fscal = evaluate_single(r2,
796 fr->pairsTable->scale,
797 fr->pairsTable->data.data(),
798 fr->pairsTable->stride,
806 energygrp_elec[gid] += velec;
807 energygrp_vdw[gid] += vvdw;
808 svmul(fscal, dx, dx);
814 if (computeVirial(flavor))
816 if (fshift_index != c_centralShiftIndex)
818 rvec_inc(fshift[fshift_index], dx);
819 rvec_dec(fshift[c_centralShiftIndex], dx);
826 /*! \brief Calculate pairs, only for plain-LJ + plain Coulomb normal type.
828 * This function is templated for real/SimdReal and for optimization.
830 template<typename T, int pack_size, typename pbc_type>
831 static void do_pairs_simple(int nbonds,
832 const t_iatom iatoms[],
833 const t_iparams iparams[],
837 gmx::ArrayRef<real> charge,
838 const real scale_factor)
840 const int nfa1 = 1 + 2;
846 #if GMX_SIMD_HAVE_REAL
847 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[pack_size];
848 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[pack_size];
849 alignas(GMX_SIMD_ALIGNMENT) real coeff[3 * pack_size];
851 std::int32_t ai[pack_size];
852 std::int32_t aj[pack_size];
853 real coeff[3 * pack_size];
856 /* nbonds is #pairs*nfa1, here we step pack_size pairs */
857 for (int i = 0; i < nbonds; i += pack_size * nfa1)
859 /* Collect atoms for pack_size pairs.
860 * iu indexes into iatoms, we should not let iu go beyond nbonds.
863 for (int s = 0; s < pack_size; s++)
865 int itype = iatoms[iu];
866 ai[s] = iatoms[iu + 1];
867 aj[s] = iatoms[iu + 2];
869 if (i + s * nfa1 < nbonds)
871 coeff[0 * pack_size + s] = iparams[itype].lj14.c6A;
872 coeff[1 * pack_size + s] = iparams[itype].lj14.c12A;
873 coeff[2 * pack_size + s] = charge[ai[s]] * charge[aj[s]];
875 /* Avoid indexing the iatoms array out of bounds.
876 * We pad the coordinate indices with the last atom pair.
878 if (iu + nfa1 < nbonds)
885 /* Pad the coefficient arrays with zeros to get zero forces */
886 coeff[0 * pack_size + s] = 0;
887 coeff[1 * pack_size + s] = 0;
888 coeff[2 * pack_size + s] = 0;
892 /* Load the coordinates */
894 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ai, &xi[XX], &xi[YY], &xi[ZZ]);
895 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), aj, &xj[XX], &xj[YY], &xj[ZZ]);
897 T c6 = load<T>(coeff + 0 * pack_size);
898 T c12 = load<T>(coeff + 1 * pack_size);
899 T qq = load<T>(coeff + 2 * pack_size);
901 /* We could save these operations by storing 6*C6,12*C12 */
906 pbc_dx_aiuc(pbc, xi, xj, dr);
908 T rsq = dr[XX] * dr[XX] + dr[YY] * dr[YY] + dr[ZZ] * dr[ZZ];
909 T rinv = gmx::invsqrt(rsq);
910 T rinv2 = rinv * rinv;
911 T rinv6 = rinv2 * rinv2 * rinv2;
913 /* Calculate the Coulomb force * r */
914 T cfr = ef * qq * rinv;
916 /* Calculate the LJ force * r and add it to the Coulomb part */
917 T fr = gmx::fma(fms(c12, rinv6, c6), rinv6, cfr);
919 T finvr = fr * rinv2;
920 T fx = finvr * dr[XX];
921 T fy = finvr * dr[YY];
922 T fz = finvr * dr[ZZ];
924 /* Add the pair forces to the force array.
925 * Note that here we might add multiple force components for some atoms
926 * due to the SIMD padding. But the extra force components are zero.
928 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ai, fx, fy, fz);
929 transposeScatterDecrU<4>(reinterpret_cast<real*>(f), aj, fx, fy, fz);
933 /*! \brief Calculate all listed pair interactions */
934 void do_pairs(int ftype,
936 const t_iatom iatoms[],
937 const t_iparams iparams[],
941 const struct t_pbc* pbc,
944 gmx::ArrayRef<real> chargeA,
945 gmx::ArrayRef<real> chargeB,
946 gmx::ArrayRef<bool> atomIsPerturbed,
947 gmx::ArrayRef<unsigned short> cENER,
948 const int numEnergyGroups,
949 const t_forcerec* fr,
950 const bool havePerturbedInteractions,
951 const gmx::StepWorkload& stepWork,
952 gmx_grppairener_t* grppener,
953 int* global_atom_index)
955 if (ftype == F_LJ14 && fr->ic->vdwtype != VanDerWaalsType::User && !EEL_USER(fr->ic->eeltype)
956 && !havePerturbedInteractions && (!stepWork.computeVirial && !stepWork.computeEnergy))
958 /* We use a fast code-path for plain LJ 1-4 without FEP.
960 * TODO: Add support for energies (straightforward) and virial
961 * in the SIMD template. For the virial it's inconvenient to store
962 * the force sums for the shifts and we should directly calculate
963 * and sum the virial for the shifts. But we should do this
964 * at once for the angles and dihedrals as well.
966 #if GMX_SIMD_HAVE_REAL
967 if (fr->use_simd_kernels)
969 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9 * GMX_SIMD_REAL_WIDTH];
970 set_pbc_simd(pbc, pbc_simd);
972 do_pairs_simple<SimdReal, GMX_SIMD_REAL_WIDTH, const real*>(
973 nbonds, iatoms, iparams, x, f, pbc_simd, chargeA, fr->ic->epsfac * fr->fudgeQQ);
978 /* This construct is needed because pbc_dx_aiuc doesn't accept pbc=NULL */
980 const t_pbc* pbc_nonnull;
988 set_pbc(&pbc_no, PbcType::No, nullptr);
989 pbc_nonnull = &pbc_no;
992 do_pairs_simple<real, 1, const t_pbc*>(
993 nbonds, iatoms, iparams, x, f, pbc_nonnull, chargeA, fr->ic->epsfac * fr->fudgeQQ);
996 else if (stepWork.computeVirial)
998 do_pairs_general<BondedKernelFlavor::ForcesAndVirialAndEnergy>(ftype,
1019 do_pairs_general<BondedKernelFlavor::ForcesAndEnergy>(ftype,