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 scaleLinpointCoulGapsys, scaleLinpointVdWGapsys, sigma6VdWGapsys[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 sigma6VdWGapsys[i] = half * c12[i] / c6[i];
253 if (sigma6VdWGapsys[i]
254 < scParams.sigma6VdWGapsys) /* for disappearing coul and vdw with soft core at the same time */
256 sigma6VdWGapsys[i] = scParams.sigma6VdWGapsys;
261 sigma6VdWGapsys[i] = scParams.sigma6VdWGapsys;
266 if constexpr (softcoreType == KernelSoftcoreType::Beutler)
268 /* only use softcore if one of the states has a zero endstate - softcore is for avoiding infinities!*/
269 if ((c12[0] > 0) && (c12[1] > 0))
276 alpha_vdw_eff = scParams.alphaVdw;
277 alpha_coul_eff = scParams.alphaCoulomb;
280 if constexpr (softcoreType == KernelSoftcoreType::Gapsys)
282 /* only use softcore if one of the states has a zero endstate - softcore is for avoiding infinities!*/
283 if ((c12[0] > 0) && (c12[1] > 0))
285 scaleLinpointVdWGapsys = 0;
286 scaleLinpointCoulGapsys = 0;
290 scaleLinpointVdWGapsys = scParams.scaleLinpointVdWGapsys;
291 scaleLinpointCoulGapsys = scParams.scaleLinpointCoulGapsys;
295 /* Loop over A and B states again */
296 for (i = 0; i < 2; i++)
307 /* Only spend time on A or B state if it is non-zero */
308 if ((qq[i] != 0) || (c6[i] != 0) || (c12[i] != 0))
311 if constexpr (softcoreType == KernelSoftcoreType::Beutler)
313 rpinv = one / (alpha_coul_eff * lfac_coul[i] * sigma_pow[i] + rp);
314 r_coul = sixthRoot(rpinv);
322 if constexpr (softcoreType == KernelSoftcoreType::Gapsys)
324 rQ = gmx::sixthroot(one - LFC[i]) * (one + std::fabs(qq[i] / facel));
325 rQ *= scaleLinpointCoulGapsys;
327 if (rQ > rCoulCutoff)
334 if ((softcoreType == KernelSoftcoreType::Gapsys) && (r < rQ))
336 real rInvQ = one / rQ;
337 real constFac = qq[i] * rInvQ;
338 real linFac = constFac * r * rInvQ;
339 real quadrFac = linFac * r * rInvQ;
341 /* Computing Coulomb force and potential energy */
342 fscal_elec[i] = 2 * quadrFac - 3 * linFac;
343 fscal_elec[i] *= rpinv;
345 velec[i] = quadrFac - 3 * (linFac - constFac);
347 dvdl_elec[i] += scaleDvdlRCoul * DLF[i] * half * (LFC[i] / (1 - LFC[i]))
348 * (quadrFac - 2 * linFac + constFac);
350 else // Beutler, resp. hardcore
352 /* Electrostatics table lookup data */
353 rtab = r_coul * tabscale;
354 ntab = static_cast<int>(rtab);
357 ntab = static_cast<int>(tableStride * ntab);
361 Geps = eps * vftab[ntab + 2];
362 Heps2 = eps2 * vftab[ntab + 3];
363 Fp = F + Geps + Heps2;
365 FF = Fp + Geps + two * Heps2;
366 velec[i] = qq[i] * VV;
367 fscal_elec[i] = -qq[i] * FF * r_coul * rpinv * tabscale;
371 if constexpr (softcoreType == KernelSoftcoreType::Beutler)
373 rpinv = one / (alpha_vdw_eff * lfac_vdw[i] * sigma_pow[i] + rp);
374 r_vdw = sixthRoot(rpinv);
382 if constexpr (softcoreType == KernelSoftcoreType::Gapsys)
384 constexpr real c_twentySixSeventh = 26.0_real / 7.0_real;
386 rLJ = gmx::sixthroot(c_twentySixSeventh * sigma6VdWGapsys[i] * (one - LFV[i]));
387 rLJ *= scaleLinpointVdWGapsys;
390 if ((softcoreType == KernelSoftcoreType::Gapsys) && (r < rLJ))
392 // scaled values for c6 and c12
394 c6s = c6[i] / 6.0_real;
395 c12s = c12[i] / 12.0_real;
397 /* Temporary variables for inverted values */
398 real rInvLJ = one / rLJ;
399 real rInv14, rInv13, rInv12;
400 real rInv8, rInv7, rInv6;
401 rInv6 = rInvLJ * rInvLJ * rInvLJ;
403 rInv7 = rInv6 * rInvLJ;
404 rInv8 = rInv7 * rInvLJ;
405 rInv14 = c12s * rInv7 * rInv7 * r2;
406 rInv13 = c12s * rInv7 * rInv6 * r;
407 rInv12 = c12s * rInv6 * rInv6;
412 /* Temporary variables for A and B */
413 real quadrFac, linearFac, constFac;
414 quadrFac = 156 * rInv14 - 42 * rInv8;
415 linearFac = 168 * rInv13 - 48 * rInv7;
416 constFac = 91 * rInv12 - 28 * rInv6;
418 /* Computing LJ force and potential energy*/
419 fscal_vdw[i] = quadrFac - linearFac;
420 fscal_vdw[i] *= rpinv;
422 vvdw[i] = 0.5 * quadrFac - linearFac + constFac;
424 dvdl_vdw[i] += DLF[i] * 28 * (LFV[i] / (one - LFV[i]))
425 * ((6.5_real * rInv14 - rInv8) - (13 * rInv13 - 2 * rInv7)
426 + (6.5_real * rInv12 - rInv6));
428 else // Beutler, resp. hardcore
430 /* Vdw table lookup data */
431 rtab = r_vdw * tabscale;
432 ntab = static_cast<int>(rtab);
439 Geps = eps * vftab[ntab + 6];
440 Heps2 = eps2 * vftab[ntab + 7];
441 Fp = F + Geps + Heps2;
443 FF = Fp + Geps + two * Heps2;
444 vvdw[i] = c6[i] * VV;
445 fscal_vdw[i] = -c6[i] * FF;
450 Geps = eps * vftab[ntab + 10];
451 Heps2 = eps2 * vftab[ntab + 11];
452 Fp = F + Geps + Heps2;
454 FF = Fp + Geps + two * Heps2;
455 vvdw[i] += c12[i] * VV;
456 fscal_vdw[i] -= c12[i] * FF;
457 fscal_vdw[i] *= r_vdw * rpinv * tabscale;
461 /* Now we have velec[i], vvdw[i], and fscal[i] for both states */
462 /* Assemble A and B states */
468 for (i = 0; i < 2; i++)
470 velecsum += LFC[i] * velec[i];
471 vvdwsum += LFV[i] * vvdw[i];
473 fscal += (LFC[i] * fscal_elec[i] + LFV[i] * fscal_vdw[i]) * rpm2;
475 if constexpr (softcoreType == KernelSoftcoreType::Gapsys)
477 dvdl_coul_sum += dvdl_elec[i];
478 dvdl_vdw_sum += dvdl_vdw[i];
480 dvdl_coul_sum += velec[i] * DLF[i];
481 dvdl_vdw_sum += vvdw[i] * DLF[i];
482 if constexpr (softcoreType == KernelSoftcoreType::Beutler)
484 dvdl_coul_sum += LFC[i] * alpha_coul_eff * dlfac_coul[i] * fscal_elec[i] * sigma_pow[i];
485 dvdl_vdw_sum += LFV[i] * alpha_vdw_eff * dlfac_vdw[i] * fscal_vdw[i] * sigma_pow[i];
489 dvdl[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)] += dvdl_coul_sum;
490 dvdl[static_cast<int>(FreeEnergyPerturbationCouplingType::Vdw)] += dvdl_vdw_sum;
492 *velectot = velecsum;
498 /*! \brief Calculate pair interactions, supports all types and conditions. */
499 template<BondedKernelFlavor flavor>
500 static real do_pairs_general(int ftype,
502 const t_iatom iatoms[],
503 const t_iparams iparams[],
507 const struct t_pbc* pbc,
510 gmx::ArrayRef<real> chargeA,
511 gmx::ArrayRef<real> chargeB,
512 gmx::ArrayRef<bool> atomIsPerturbed,
513 gmx::ArrayRef<unsigned short> cENER,
515 const t_forcerec* fr,
516 gmx_grppairener_t* grppener,
517 int* global_atom_index)
521 int i, itype, ai, aj, gid;
524 real fscal, velec, vvdw;
525 real* energygrp_elec;
527 static gmx_bool warned_rlimit = FALSE;
528 /* Free energy stuff */
529 gmx_bool bFreeEnergy;
530 real LFC[2], LFV[2], DLF[2], lfac_coul[2], lfac_vdw[2], dlfac_coul[2], dlfac_vdw[2];
532 const real oneSixth = 1.0_real / 6.0_real;
538 energygrp_elec = grppener->energyGroupPairTerms[NonBondedEnergyTerms::Coulomb14].data();
539 energygrp_vdw = grppener->energyGroupPairTerms[NonBondedEnergyTerms::LJ14].data();
542 energygrp_elec = grppener->energyGroupPairTerms[NonBondedEnergyTerms::CoulombSR].data();
543 energygrp_vdw = grppener->energyGroupPairTerms[NonBondedEnergyTerms::LJSR].data();
546 energygrp_elec = nullptr; /* Keep compiler happy */
547 energygrp_vdw = nullptr; /* Keep compiler happy */
548 gmx_fatal(FARGS, "Unknown function type %d in do_nonbonded14", ftype);
551 if (fr->efep != FreeEnergyPerturbationType::No)
553 /* Lambda factor for state A=1-lambda and B=lambda */
554 LFC[0] = 1.0 - lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)];
555 LFV[0] = 1.0 - lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Vdw)];
556 LFC[1] = lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)];
557 LFV[1] = lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Vdw)];
559 /*derivative of the lambda factor for state A and B */
563 GMX_ASSERT(fr->ic->softCoreParameters, "We need soft-core parameters");
564 const auto& scParams = *fr->ic->softCoreParameters;
566 for (i = 0; i < 2; i++)
568 lfac_coul[i] = (scParams.lambdaPower == 2 ? (1 - LFC[i]) * (1 - LFC[i]) : (1 - LFC[i]));
569 dlfac_coul[i] = DLF[i] * scParams.lambdaPower * oneSixth
570 * (scParams.lambdaPower == 2 ? (1 - LFC[i]) : 1);
571 lfac_vdw[i] = (scParams.lambdaPower == 2 ? (1 - LFV[i]) * (1 - LFV[i]) : (1 - LFV[i]));
572 dlfac_vdw[i] = DLF[i] * scParams.lambdaPower * oneSixth
573 * (scParams.lambdaPower == 2 ? (1 - LFV[i]) : 1);
577 /* TODO This code depends on the logic in tables.c that constructs
578 the table layout, which should be made explicit in future
582 "Pair-interaction code that uses GROMACS interaction tables supports exactly 3 tables");
584 fr->pairsTable->interaction == TableInteraction::ElectrostaticVdwRepulsionVdwDispersion,
585 "Pair interaction kernels need a table with Coulomb, repulsion and dispersion entries");
587 const real epsfac = fr->ic->epsfac;
590 for (i = 0; (i < nbonds);)
595 gid = GID(cENER[ai], cENER[aj], numEnergyGroups);
602 (fr->efep != FreeEnergyPerturbationType::No
603 && ((!atomIsPerturbed.empty() && (atomIsPerturbed[ai] || atomIsPerturbed[aj]))
604 || iparams[itype].lj14.c6A != iparams[itype].lj14.c6B
605 || iparams[itype].lj14.c12A != iparams[itype].lj14.c12B));
606 qq = chargeA[ai] * chargeA[aj] * epsfac * fr->fudgeQQ;
607 c6 = iparams[itype].lj14.c6A;
608 c12 = iparams[itype].lj14.c12A;
611 qq = iparams[itype].ljc14.qi * iparams[itype].ljc14.qj * epsfac
612 * iparams[itype].ljc14.fqq;
613 c6 = iparams[itype].ljc14.c6;
614 c12 = iparams[itype].ljc14.c12;
617 qq = iparams[itype].ljcnb.qi * iparams[itype].ljcnb.qj * epsfac;
618 c6 = iparams[itype].ljcnb.c6;
619 c12 = iparams[itype].ljcnb.c12;
622 /* Cannot happen since we called gmx_fatal() above in this case */
623 qq = c6 = c12 = 0; /* Keep compiler happy */
627 /* To save flops in the optimized kernels, c6/c12 have 6.0/12.0 derivative prefactors
628 * included in the general nfbp array now. This means the tables are scaled down by the
629 * same factor, so when we use the original c6/c12 parameters from iparams[] they must
635 /* Do we need to apply full periodic boundary conditions? */
638 fshift_index = pbc_dx_aiuc(pbc, x[ai], x[aj], dx);
642 fshift_index = c_centralShiftIndex;
643 rvec_sub(x[ai], x[aj], dx);
647 if (r2 >= fr->pairsTable->interactionRange * fr->pairsTable->interactionRange)
649 /* This check isn't race free. But it doesn't matter because if a race occurs the only
650 * disadvantage is that the warning is printed twice */
653 warning_rlimit(x, ai, aj, global_atom_index, sqrt(r2), fr->pairsTable->interactionRange);
654 warned_rlimit = TRUE;
661 /* Currently free energy is only supported for F_LJ14, so no need to check for that if we got here */
662 qqB = chargeB[ai] * chargeB[aj] * epsfac * fr->fudgeQQ;
663 c6B = iparams[itype].lj14.c6B * 6.0;
664 c12B = iparams[itype].lj14.c12B * 12.0;
666 const auto& scParams = *fr->ic->softCoreParameters;
667 if (scParams.softcoreType == SoftcoreType::Beutler)
669 if (scParams.alphaCoulomb == 0 && scParams.alphaVdw == 0)
671 fscal = free_energy_evaluate_single<KernelSoftcoreType::None>(
674 *fr->ic->softCoreParameters,
675 fr->pairsTable->scale,
676 fr->pairsTable->data.data(),
677 fr->pairsTable->stride,
698 fscal = free_energy_evaluate_single<KernelSoftcoreType::Beutler>(
701 *fr->ic->softCoreParameters,
702 fr->pairsTable->scale,
703 fr->pairsTable->data.data(),
704 fr->pairsTable->stride,
726 if (scParams.scaleLinpointCoulGapsys == 0 && scParams.scaleLinpointVdWGapsys == 0)
728 fscal = free_energy_evaluate_single<KernelSoftcoreType::None>(
731 *fr->ic->softCoreParameters,
732 fr->pairsTable->scale,
733 fr->pairsTable->data.data(),
734 fr->pairsTable->stride,
755 fscal = free_energy_evaluate_single<KernelSoftcoreType::Gapsys>(
758 *fr->ic->softCoreParameters,
759 fr->pairsTable->scale,
760 fr->pairsTable->data.data(),
761 fr->pairsTable->stride,
784 /* Evaluate tabulated interaction without free energy */
785 fscal = evaluate_single(r2,
786 fr->pairsTable->scale,
787 fr->pairsTable->data.data(),
788 fr->pairsTable->stride,
796 energygrp_elec[gid] += velec;
797 energygrp_vdw[gid] += vvdw;
798 svmul(fscal, dx, dx);
804 if (computeVirial(flavor))
806 if (fshift_index != c_centralShiftIndex)
808 rvec_inc(fshift[fshift_index], dx);
809 rvec_dec(fshift[c_centralShiftIndex], dx);
816 /*! \brief Calculate pairs, only for plain-LJ + plain Coulomb normal type.
818 * This function is templated for real/SimdReal and for optimization.
820 template<typename T, int pack_size, typename pbc_type>
821 static void do_pairs_simple(int nbonds,
822 const t_iatom iatoms[],
823 const t_iparams iparams[],
827 gmx::ArrayRef<real> charge,
828 const real scale_factor)
830 const int nfa1 = 1 + 2;
836 #if GMX_SIMD_HAVE_REAL
837 alignas(GMX_SIMD_ALIGNMENT) std::int32_t ai[pack_size];
838 alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[pack_size];
839 alignas(GMX_SIMD_ALIGNMENT) real coeff[3 * pack_size];
841 std::int32_t ai[pack_size];
842 std::int32_t aj[pack_size];
843 real coeff[3 * pack_size];
846 /* nbonds is #pairs*nfa1, here we step pack_size pairs */
847 for (int i = 0; i < nbonds; i += pack_size * nfa1)
849 /* Collect atoms for pack_size pairs.
850 * iu indexes into iatoms, we should not let iu go beyond nbonds.
853 for (int s = 0; s < pack_size; s++)
855 int itype = iatoms[iu];
856 ai[s] = iatoms[iu + 1];
857 aj[s] = iatoms[iu + 2];
859 if (i + s * nfa1 < nbonds)
861 coeff[0 * pack_size + s] = iparams[itype].lj14.c6A;
862 coeff[1 * pack_size + s] = iparams[itype].lj14.c12A;
863 coeff[2 * pack_size + s] = charge[ai[s]] * charge[aj[s]];
865 /* Avoid indexing the iatoms array out of bounds.
866 * We pad the coordinate indices with the last atom pair.
868 if (iu + nfa1 < nbonds)
875 /* Pad the coefficient arrays with zeros to get zero forces */
876 coeff[0 * pack_size + s] = 0;
877 coeff[1 * pack_size + s] = 0;
878 coeff[2 * pack_size + s] = 0;
882 /* Load the coordinates */
884 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), ai, &xi[XX], &xi[YY], &xi[ZZ]);
885 gatherLoadUTranspose<3>(reinterpret_cast<const real*>(x), aj, &xj[XX], &xj[YY], &xj[ZZ]);
887 T c6 = load<T>(coeff + 0 * pack_size);
888 T c12 = load<T>(coeff + 1 * pack_size);
889 T qq = load<T>(coeff + 2 * pack_size);
891 /* We could save these operations by storing 6*C6,12*C12 */
896 pbc_dx_aiuc(pbc, xi, xj, dr);
898 T rsq = dr[XX] * dr[XX] + dr[YY] * dr[YY] + dr[ZZ] * dr[ZZ];
899 T rinv = gmx::invsqrt(rsq);
900 T rinv2 = rinv * rinv;
901 T rinv6 = rinv2 * rinv2 * rinv2;
903 /* Calculate the Coulomb force * r */
904 T cfr = ef * qq * rinv;
906 /* Calculate the LJ force * r and add it to the Coulomb part */
907 T fr = gmx::fma(fms(c12, rinv6, c6), rinv6, cfr);
909 T finvr = fr * rinv2;
910 T fx = finvr * dr[XX];
911 T fy = finvr * dr[YY];
912 T fz = finvr * dr[ZZ];
914 /* Add the pair forces to the force array.
915 * Note that here we might add multiple force components for some atoms
916 * due to the SIMD padding. But the extra force components are zero.
918 transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ai, fx, fy, fz);
919 transposeScatterDecrU<4>(reinterpret_cast<real*>(f), aj, fx, fy, fz);
923 /*! \brief Calculate all listed pair interactions */
924 void do_pairs(int ftype,
926 const t_iatom iatoms[],
927 const t_iparams iparams[],
931 const struct t_pbc* pbc,
934 gmx::ArrayRef<real> chargeA,
935 gmx::ArrayRef<real> chargeB,
936 gmx::ArrayRef<bool> atomIsPerturbed,
937 gmx::ArrayRef<unsigned short> cENER,
938 const int numEnergyGroups,
939 const t_forcerec* fr,
940 const bool havePerturbedInteractions,
941 const gmx::StepWorkload& stepWork,
942 gmx_grppairener_t* grppener,
943 int* global_atom_index)
945 if (ftype == F_LJ14 && fr->ic->vdwtype != VanDerWaalsType::User && !EEL_USER(fr->ic->eeltype)
946 && !havePerturbedInteractions && (!stepWork.computeVirial && !stepWork.computeEnergy))
948 /* We use a fast code-path for plain LJ 1-4 without FEP.
950 * TODO: Add support for energies (straightforward) and virial
951 * in the SIMD template. For the virial it's inconvenient to store
952 * the force sums for the shifts and we should directly calculate
953 * and sum the virial for the shifts. But we should do this
954 * at once for the angles and dihedrals as well.
956 #if GMX_SIMD_HAVE_REAL
957 if (fr->use_simd_kernels)
959 alignas(GMX_SIMD_ALIGNMENT) real pbc_simd[9 * GMX_SIMD_REAL_WIDTH];
960 set_pbc_simd(pbc, pbc_simd);
962 do_pairs_simple<SimdReal, GMX_SIMD_REAL_WIDTH, const real*>(
963 nbonds, iatoms, iparams, x, f, pbc_simd, chargeA, fr->ic->epsfac * fr->fudgeQQ);
968 /* This construct is needed because pbc_dx_aiuc doesn't accept pbc=NULL */
970 const t_pbc* pbc_nonnull;
978 set_pbc(&pbc_no, PbcType::No, nullptr);
979 pbc_nonnull = &pbc_no;
982 do_pairs_simple<real, 1, const t_pbc*>(
983 nbonds, iatoms, iparams, x, f, pbc_nonnull, chargeA, fr->ic->epsfac * fr->fudgeQQ);
986 else if (stepWork.computeVirial)
988 do_pairs_general<BondedKernelFlavor::ForcesAndVirialAndEnergy>(ftype,
1009 do_pairs_general<BondedKernelFlavor::ForcesAndEnergy>(ftype,