2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
7 * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
8 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
9 * and including many others, as listed in the AUTHORS file in the
10 * top-level source directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
40 #include "nb_free_energy.h"
46 #include "gromacs/gmxlib/nrnb.h"
47 #include "gromacs/gmxlib/nonbonded/nb_kernel.h"
48 #include "gromacs/gmxlib/nonbonded/nonbonded.h"
49 #include "gromacs/math/functions.h"
50 #include "gromacs/math/vec.h"
51 #include "gromacs/mdtypes/forceoutput.h"
52 #include "gromacs/mdtypes/forcerec.h"
53 #include "gromacs/mdtypes/md_enums.h"
54 #include "gromacs/utility/fatalerror.h"
57 //! Computes r^(1/p) and 1/r^(1/p) for the standard p=6
58 static inline void pthRoot(const real r, real* pthRoot, real* invPthRoot)
60 *invPthRoot = gmx::invsqrt(std::cbrt(r));
61 *pthRoot = 1 / (*invPthRoot);
64 static inline real calculateRinv6(const real rinvV)
66 real rinv6 = rinvV * rinvV;
67 return (rinv6 * rinv6 * rinv6);
70 static inline real calculateVdw6(const real c6, const real rinv6)
75 static inline real calculateVdw12(const real c12, const real rinv6)
77 return (c12 * rinv6 * rinv6);
80 /* reaction-field electrostatics */
82 reactionFieldScalarForce(const real qq, const real rinv, const real r, const real krf, const real two)
84 return (qq * (rinv - two * krf * r * r));
86 static inline real reactionFieldPotential(const real qq, const real rinv, const real r, const real krf, const real potentialShift)
88 return (qq * (rinv + krf * r * r - potentialShift));
91 /* Ewald electrostatics */
92 static inline real ewaldScalarForce(const real coulomb, const real rinv)
94 return (coulomb * rinv);
96 static inline real ewaldPotential(const real coulomb, const real rinv, const real potentialShift)
98 return (coulomb * (rinv - potentialShift));
102 static inline real lennardJonesScalarForce(const real v6, const real v12)
106 static inline real lennardJonesPotential(const real v6,
110 const real repulsionShift,
111 const real dispersionShift,
113 const real onetwelfth)
115 return ((v12 + c12 * repulsionShift) * onetwelfth - (v6 + c6 * dispersionShift) * onesixth);
119 static inline real ewaldLennardJonesGridSubtract(const real c6grid, const real potentialShift, const real onesixth)
121 return (c6grid * potentialShift * onesixth);
124 /* LJ Potential switch */
125 static inline real potSwitchScalarForceMod(const real fScalarInp,
126 const real potential,
135 real fScalar = fScalarInp * sw - r * potential * dsw;
141 potSwitchPotentialMod(const real potentialInp, const real sw, const real r, const real rVdw, const real zero)
145 real potential = potentialInp * sw;
152 //! Templated free-energy non-bonded kernel
153 template<bool useSoftCore, bool scLambdasOrAlphasDiffer, bool vdwInteractionTypeIsEwald, bool elecInteractionTypeIsEwald, bool vdwModifierIsPotSwitch>
154 static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
155 rvec* gmx_restrict xx,
156 gmx::ForceWithShiftForces* forceWithShiftForces,
157 const t_forcerec* gmx_restrict fr,
158 const t_mdatoms* gmx_restrict mdatoms,
159 nb_kernel_data_t* gmx_restrict kernel_data,
160 t_nrnb* gmx_restrict nrnb)
166 constexpr real onetwelfth = 1.0 / 12.0;
167 constexpr real onesixth = 1.0 / 6.0;
168 constexpr real zero = 0.0;
169 constexpr real half = 0.5;
170 constexpr real one = 1.0;
171 constexpr real two = 2.0;
172 constexpr real six = 6.0;
174 /* Extract pointer to non-bonded interaction constants */
175 const interaction_const_t* ic = fr->ic;
177 // Extract pair list data
178 const int nri = nlist->nri;
179 const int* iinr = nlist->iinr;
180 const int* jindex = nlist->jindex;
181 const int* jjnr = nlist->jjnr;
182 const int* shift = nlist->shift;
183 const int* gid = nlist->gid;
185 const real* shiftvec = fr->shift_vec[0];
186 const real* chargeA = mdatoms->chargeA;
187 const real* chargeB = mdatoms->chargeB;
188 real* Vc = kernel_data->energygrp_elec;
189 const int* typeA = mdatoms->typeA;
190 const int* typeB = mdatoms->typeB;
191 const int ntype = fr->ntype;
192 const real* nbfp = fr->nbfp.data();
193 const real* nbfp_grid = fr->ljpme_c6grid;
194 real* Vv = kernel_data->energygrp_vdw;
195 const real lambda_coul = kernel_data->lambda[efptCOUL];
196 const real lambda_vdw = kernel_data->lambda[efptVDW];
197 real* dvdl = kernel_data->dvdl;
198 const real alpha_coul = fr->sc_alphacoul;
199 const real alpha_vdw = fr->sc_alphavdw;
200 const real lam_power = fr->sc_power;
201 const real sigma6_def = fr->sc_sigma6_def;
202 const real sigma6_min = fr->sc_sigma6_min;
203 const bool doForces = ((kernel_data->flags & GMX_NONBONDED_DO_FORCE) != 0);
204 const bool doShiftForces = ((kernel_data->flags & GMX_NONBONDED_DO_SHIFTFORCE) != 0);
205 const bool doPotential = ((kernel_data->flags & GMX_NONBONDED_DO_POTENTIAL) != 0);
207 // Extract data from interaction_const_t
208 const real facel = ic->epsfac;
209 const real rcoulomb = ic->rcoulomb;
210 const real krf = ic->k_rf;
211 const real crf = ic->c_rf;
212 const real sh_lj_ewald = ic->sh_lj_ewald;
213 const real rvdw = ic->rvdw;
214 const real dispersionShift = ic->dispersion_shift.cpot;
215 const real repulsionShift = ic->repulsion_shift.cpot;
217 // Note that the nbnxm kernels do not support Coulomb potential switching at all
218 GMX_ASSERT(ic->coulomb_modifier != eintmodPOTSWITCH,
219 "Potential switching is not supported for Coulomb with FEP");
221 real vdw_swV3, vdw_swV4, vdw_swV5, vdw_swF2, vdw_swF3, vdw_swF4;
222 if (vdwModifierIsPotSwitch)
224 const real d = ic->rvdw - ic->rvdw_switch;
225 vdw_swV3 = -10.0 / (d * d * d);
226 vdw_swV4 = 15.0 / (d * d * d * d);
227 vdw_swV5 = -6.0 / (d * d * d * d * d);
228 vdw_swF2 = -30.0 / (d * d * d);
229 vdw_swF3 = 60.0 / (d * d * d * d);
230 vdw_swF4 = -30.0 / (d * d * d * d * d);
234 /* Avoid warnings from stupid compilers (looking at you, Clang!) */
235 vdw_swV3 = vdw_swV4 = vdw_swV5 = vdw_swF2 = vdw_swF3 = vdw_swF4 = 0.0;
239 if (ic->eeltype == eelCUT || EEL_RF(ic->eeltype))
241 icoul = GMX_NBKERNEL_ELEC_REACTIONFIELD;
245 icoul = GMX_NBKERNEL_ELEC_NONE;
248 real rcutoff_max2 = std::max(ic->rcoulomb, ic->rvdw);
249 rcutoff_max2 = rcutoff_max2 * rcutoff_max2;
251 const real* tab_ewald_F_lj = nullptr;
252 const real* tab_ewald_V_lj = nullptr;
253 const real* ewtab = nullptr;
255 real ewtabhalfspace = 0;
257 if (elecInteractionTypeIsEwald || vdwInteractionTypeIsEwald)
259 const auto& tables = *ic->coulombEwaldTables;
260 sh_ewald = ic->sh_ewald;
261 ewtab = tables.tableFDV0.data();
262 ewtabscale = tables.scale;
263 ewtabhalfspace = half / ewtabscale;
264 tab_ewald_F_lj = tables.tableF.data();
265 tab_ewald_V_lj = tables.tableV.data();
268 /* For Ewald/PME interactions we cannot easily apply the soft-core component to
269 * reciprocal space. When we use non-switched Ewald interactions, we
270 * assume the soft-coring does not significantly affect the grid contribution
271 * and apply the soft-core only to the full 1/r (- shift) pair contribution.
273 * However, we cannot use this approach for switch-modified since we would then
274 * effectively end up evaluating a significantly different interaction here compared to the
275 * normal (non-free-energy) kernels, either by applying a cutoff at a different
276 * position than what the user requested, or by switching different
277 * things (1/r rather than short-range Ewald). For these settings, we just
278 * use the traditional short-range Ewald interaction in that case.
280 GMX_RELEASE_ASSERT(!(vdwInteractionTypeIsEwald && vdwModifierIsPotSwitch),
281 "Can not apply soft-core to switched Ewald potentials");
286 /* Lambda factor for state A, 1-lambda*/
287 real LFC[NSTATES], LFV[NSTATES];
288 LFC[STATE_A] = one - lambda_coul;
289 LFV[STATE_A] = one - lambda_vdw;
291 /* Lambda factor for state B, lambda*/
292 LFC[STATE_B] = lambda_coul;
293 LFV[STATE_B] = lambda_vdw;
295 /*derivative of the lambda factor for state A and B */
300 real lfac_coul[NSTATES], dlfac_coul[NSTATES], lfac_vdw[NSTATES], dlfac_vdw[NSTATES];
301 constexpr real sc_r_power = 6.0_real;
302 for (int i = 0; i < NSTATES; i++)
304 lfac_coul[i] = (lam_power == 2 ? (1 - LFC[i]) * (1 - LFC[i]) : (1 - LFC[i]));
305 dlfac_coul[i] = DLF[i] * lam_power / sc_r_power * (lam_power == 2 ? (1 - LFC[i]) : 1);
306 lfac_vdw[i] = (lam_power == 2 ? (1 - LFV[i]) * (1 - LFV[i]) : (1 - LFV[i]));
307 dlfac_vdw[i] = DLF[i] * lam_power / sc_r_power * (lam_power == 2 ? (1 - LFV[i]) : 1);
310 // TODO: We should get rid of using pointers to real
311 const real* x = xx[0];
312 real* gmx_restrict f = &(forceWithShiftForces->force()[0][0]);
313 real* gmx_restrict fshift = &(forceWithShiftForces->shiftForces()[0][0]);
315 for (int n = 0; n < nri; n++)
317 int npair_within_cutoff = 0;
319 const int is3 = 3 * shift[n];
320 const real shX = shiftvec[is3];
321 const real shY = shiftvec[is3 + 1];
322 const real shZ = shiftvec[is3 + 2];
323 const int nj0 = jindex[n];
324 const int nj1 = jindex[n + 1];
325 const int ii = iinr[n];
326 const int ii3 = 3 * ii;
327 const real ix = shX + x[ii3 + 0];
328 const real iy = shY + x[ii3 + 1];
329 const real iz = shZ + x[ii3 + 2];
330 const real iqA = facel * chargeA[ii];
331 const real iqB = facel * chargeB[ii];
332 const int ntiA = 2 * ntype * typeA[ii];
333 const int ntiB = 2 * ntype * typeB[ii];
340 for (int k = nj0; k < nj1; k++)
343 const int jnr = jjnr[k];
344 const int j3 = 3 * jnr;
345 real c6[NSTATES], c12[NSTATES], qq[NSTATES], Vcoul[NSTATES], Vvdw[NSTATES];
346 real r, rinv, rp, rpm2;
347 real alpha_vdw_eff, alpha_coul_eff, sigma6[NSTATES];
348 const real dx = ix - x[j3];
349 const real dy = iy - x[j3 + 1];
350 const real dz = iz - x[j3 + 2];
351 const real rsq = dx * dx + dy * dy + dz * dz;
352 real FscalC[NSTATES], FscalV[NSTATES];
354 if (rsq >= rcutoff_max2)
356 /* We save significant time by skipping all code below.
357 * Note that with soft-core interactions, the actual cut-off
358 * check might be different. But since the soft-core distance
359 * is always larger than r, checking on r here is safe.
363 npair_within_cutoff++;
367 /* Note that unlike in the nbnxn kernels, we do not need
368 * to clamp the value of rsq before taking the invsqrt
369 * to avoid NaN in the LJ calculation, since here we do
370 * not calculate LJ interactions when C6 and C12 are zero.
373 rinv = gmx::invsqrt(rsq);
378 /* The force at r=0 is zero, because of symmetry.
379 * But note that the potential is in general non-zero,
380 * since the soft-cored r will be non-zero.
388 rpm2 = rsq * rsq; /* r4 */
389 rp = rpm2 * rsq; /* r6 */
393 /* The soft-core power p will not affect the results
394 * with not using soft-core, so we use power of 0 which gives
395 * the simplest math and cheapest code.
403 qq[STATE_A] = iqA * chargeA[jnr];
404 qq[STATE_B] = iqB * chargeB[jnr];
406 tj[STATE_A] = ntiA + 2 * typeA[jnr];
407 tj[STATE_B] = ntiB + 2 * typeB[jnr];
409 if (nlist->excl_fep == nullptr || nlist->excl_fep[k])
411 c6[STATE_A] = nbfp[tj[STATE_A]];
412 c6[STATE_B] = nbfp[tj[STATE_B]];
414 for (int i = 0; i < NSTATES; i++)
416 c12[i] = nbfp[tj[i] + 1];
419 if ((c6[i] > 0) && (c12[i] > 0))
421 /* c12 is stored scaled with 12.0 and c6 is scaled with 6.0 - correct for this */
422 sigma6[i] = half * c12[i] / c6[i];
423 if (sigma6[i] < sigma6_min) /* for disappearing coul and vdw with soft core at the same time */
425 sigma6[i] = sigma6_min;
430 sigma6[i] = sigma6_def;
437 /* only use softcore if one of the states has a zero endstate - softcore is for avoiding infinities!*/
438 if ((c12[STATE_A] > 0) && (c12[STATE_B] > 0))
445 alpha_vdw_eff = alpha_vdw;
446 alpha_coul_eff = alpha_coul;
450 for (int i = 0; i < NSTATES; i++)
457 real rinvC, rinvV, rC, rV, rpinvC, rpinvV;
459 /* Only spend time on A or B state if it is non-zero */
460 if ((qq[i] != 0) || (c6[i] != 0) || (c12[i] != 0))
462 /* this section has to be inside the loop because of the dependence on sigma6 */
465 rpinvC = one / (alpha_coul_eff * lfac_coul[i] * sigma6[i] + rp);
466 pthRoot(rpinvC, &rinvC, &rC);
467 if (scLambdasOrAlphasDiffer)
469 rpinvV = one / (alpha_vdw_eff * lfac_vdw[i] * sigma6[i] + rp);
470 pthRoot(rpinvV, &rinvV, &rV);
474 /* We can avoid one expensive pow and one / operation */
491 /* Only process the coulomb interactions if we have charges,
492 * and if we either include all entries in the list (no cutoff
493 * used in the kernel), or if we are within the cutoff.
495 bool computeElecInteraction = (elecInteractionTypeIsEwald && r < rcoulomb)
496 || (!elecInteractionTypeIsEwald && rC < rcoulomb);
498 if ((qq[i] != 0) && computeElecInteraction)
500 if (elecInteractionTypeIsEwald)
502 Vcoul[i] = ewaldPotential(qq[i], rinvC, sh_ewald);
503 FscalC[i] = ewaldScalarForce(qq[i], rinvC);
507 Vcoul[i] = reactionFieldPotential(qq[i], rinvC, rC, krf, crf);
508 FscalC[i] = reactionFieldScalarForce(qq[i], rinvC, rC, krf, two);
512 /* Only process the VDW interactions if we have
513 * some non-zero parameters, and if we either
514 * include all entries in the list (no cutoff used
515 * in the kernel), or if we are within the cutoff.
517 bool computeVdwInteraction = (vdwInteractionTypeIsEwald && r < rvdw)
518 || (!vdwInteractionTypeIsEwald && rV < rvdw);
519 if ((c6[i] != 0 || c12[i] != 0) && computeVdwInteraction)
528 rinv6 = calculateRinv6(rinvV);
530 real Vvdw6 = calculateVdw6(c6[i], rinv6);
531 real Vvdw12 = calculateVdw12(c12[i], rinv6);
533 Vvdw[i] = lennardJonesPotential(Vvdw6, Vvdw12, c6[i], c12[i], repulsionShift,
534 dispersionShift, onesixth, onetwelfth);
535 FscalV[i] = lennardJonesScalarForce(Vvdw6, Vvdw12);
537 if (vdwInteractionTypeIsEwald)
539 /* Subtract the grid potential at the cut-off */
540 Vvdw[i] += ewaldLennardJonesGridSubtract(nbfp_grid[tj[i]],
541 sh_lj_ewald, onesixth);
544 if (vdwModifierIsPotSwitch)
546 real d = rV - ic->rvdw_switch;
547 d = (d > zero) ? d : zero;
548 const real d2 = d * d;
549 const real sw = one + d2 * d * (vdw_swV3 + d * (vdw_swV4 + d * vdw_swV5));
550 const real dsw = d2 * (vdw_swF2 + d * (vdw_swF3 + d * vdw_swF4));
552 FscalV[i] = potSwitchScalarForceMod(FscalV[i], Vvdw[i], sw, rV,
554 Vvdw[i] = potSwitchPotentialMod(Vvdw[i], sw, rV, rvdw, zero);
558 /* FscalC (and FscalV) now contain: dV/drC * rC
559 * Now we multiply by rC^-p, so it will be: dV/drC * rC^1-p
560 * Further down we first multiply by r^p-2 and then by
561 * the vector r, which in total gives: dV/drC * (r/rC)^1-p
568 /* Assemble A and B states */
569 for (int i = 0; i < NSTATES; i++)
571 vctot += LFC[i] * Vcoul[i];
572 vvtot += LFV[i] * Vvdw[i];
574 Fscal += LFC[i] * FscalC[i] * rpm2;
575 Fscal += LFV[i] * FscalV[i] * rpm2;
579 dvdl_coul += Vcoul[i] * DLF[i]
580 + LFC[i] * alpha_coul_eff * dlfac_coul[i] * FscalC[i] * sigma6[i];
581 dvdl_vdw += Vvdw[i] * DLF[i]
582 + LFV[i] * alpha_vdw_eff * dlfac_vdw[i] * FscalV[i] * sigma6[i];
586 dvdl_coul += Vcoul[i] * DLF[i];
587 dvdl_vdw += Vvdw[i] * DLF[i];
591 else if (icoul == GMX_NBKERNEL_ELEC_REACTIONFIELD)
593 /* For excluded pairs, which are only in this pair list when
594 * using the Verlet scheme, we don't use soft-core.
595 * As there is no singularity, there is no need for soft-core.
597 const real FF = -two * krf;
598 real VV = krf * rsq - crf;
605 for (int i = 0; i < NSTATES; i++)
607 vctot += LFC[i] * qq[i] * VV;
608 Fscal += LFC[i] * qq[i] * FF;
609 dvdl_coul += DLF[i] * qq[i] * VV;
613 if (elecInteractionTypeIsEwald && r < rcoulomb)
615 /* See comment in the preamble. When using Ewald interactions
616 * (unless we use a switch modifier) we subtract the reciprocal-space
617 * Ewald component here which made it possible to apply the free
618 * energy interaction to 1/r (vanilla coulomb short-range part)
619 * above. This gets us closer to the ideal case of applying
620 * the softcore to the entire electrostatic interaction,
621 * including the reciprocal-space component.
625 const real ewrt = r * ewtabscale;
626 int ewitab = static_cast<int>(ewrt);
627 const real eweps = ewrt - ewitab;
629 f_lr = ewtab[ewitab] + eweps * ewtab[ewitab + 1];
630 v_lr = (ewtab[ewitab + 2] - ewtabhalfspace * eweps * (ewtab[ewitab] + f_lr));
633 /* Note that any possible Ewald shift has already been applied in
634 * the normal interaction part above.
639 /* If we get here, the i particle (ii) has itself (jnr)
640 * in its neighborlist. This can only happen with the Verlet
641 * scheme, and corresponds to a self-interaction that will
642 * occur twice. Scale it down by 50% to only include it once.
647 for (int i = 0; i < NSTATES; i++)
649 vctot -= LFC[i] * qq[i] * v_lr;
650 Fscal -= LFC[i] * qq[i] * f_lr;
651 dvdl_coul -= (DLF[i] * qq[i]) * v_lr;
655 if (vdwInteractionTypeIsEwald && r < rvdw)
657 /* See comment in the preamble. When using LJ-Ewald interactions
658 * (unless we use a switch modifier) we subtract the reciprocal-space
659 * Ewald component here which made it possible to apply the free
660 * energy interaction to r^-6 (vanilla LJ6 short-range part)
661 * above. This gets us closer to the ideal case of applying
662 * the softcore to the entire VdW interaction,
663 * including the reciprocal-space component.
665 /* We could also use the analytical form here
666 * iso a table, but that can cause issues for
667 * r close to 0 for non-interacting pairs.
670 const real rs = rsq * rinv * ewtabscale;
671 const int ri = static_cast<int>(rs);
672 const real frac = rs - ri;
673 const real f_lr = (1 - frac) * tab_ewald_F_lj[ri] + frac * tab_ewald_F_lj[ri + 1];
674 /* TODO: Currently the Ewald LJ table does not contain
675 * the factor 1/6, we should add this.
677 const real FF = f_lr * rinv / six;
678 real VV = (tab_ewald_V_lj[ri] - ewtabhalfspace * frac * (tab_ewald_F_lj[ri] + f_lr)) / six;
682 /* If we get here, the i particle (ii) has itself (jnr)
683 * in its neighborlist. This can only happen with the Verlet
684 * scheme, and corresponds to a self-interaction that will
685 * occur twice. Scale it down by 50% to only include it once.
690 for (int i = 0; i < NSTATES; i++)
692 const real c6grid = nbfp_grid[tj[i]];
693 vvtot += LFV[i] * c6grid * VV;
694 Fscal += LFV[i] * c6grid * FF;
695 dvdl_vdw += (DLF[i] * c6grid) * VV;
701 const real tx = Fscal * dx;
702 const real ty = Fscal * dy;
703 const real tz = Fscal * dz;
707 /* OpenMP atomics are expensive, but this kernels is also
708 * expensive, so we can take this hit, instead of using
709 * thread-local output buffers and extra reduction.
711 * All the OpenMP regions in this file are trivial and should
712 * not throw, so no need for try/catch.
723 /* The atomics below are expensive with many OpenMP threads.
724 * Here unperturbed i-particles will usually only have a few
725 * (perturbed) j-particles in the list. Thus with a buffered list
726 * we can skip a significant number of i-reductions with a check.
728 if (npair_within_cutoff > 0)
744 fshift[is3 + 1] += fiy;
746 fshift[is3 + 2] += fiz;
760 dvdl[efptCOUL] += dvdl_coul;
762 dvdl[efptVDW] += dvdl_vdw;
764 /* Estimate flops, average for free energy stuff:
765 * 12 flops per outer iteration
766 * 150 flops per inner iteration
769 inc_nrnb(nrnb, eNR_NBKERNEL_FREE_ENERGY, nlist->nri * 12 + nlist->jindex[nri] * 150);
772 typedef void (*KernelFunction)(const t_nblist* gmx_restrict nlist,
773 rvec* gmx_restrict xx,
774 gmx::ForceWithShiftForces* forceWithShiftForces,
775 const t_forcerec* gmx_restrict fr,
776 const t_mdatoms* gmx_restrict mdatoms,
777 nb_kernel_data_t* gmx_restrict kernel_data,
778 t_nrnb* gmx_restrict nrnb);
780 template<bool useSoftCore, bool scLambdasOrAlphasDiffer, bool vdwInteractionTypeIsEwald, bool elecInteractionTypeIsEwald>
781 static KernelFunction dispatchKernelOnVdwModifier(const bool vdwModifierIsPotSwitch)
783 if (vdwModifierIsPotSwitch)
785 return (nb_free_energy_kernel<useSoftCore, scLambdasOrAlphasDiffer,
786 vdwInteractionTypeIsEwald, elecInteractionTypeIsEwald, true>);
790 return (nb_free_energy_kernel<useSoftCore, scLambdasOrAlphasDiffer,
791 vdwInteractionTypeIsEwald, elecInteractionTypeIsEwald, false>);
795 template<bool useSoftCore, bool scLambdasOrAlphasDiffer, bool vdwInteractionTypeIsEwald>
796 static KernelFunction dispatchKernelOnElecInteractionType(const bool elecInteractionTypeIsEwald,
797 const bool vdwModifierIsPotSwitch)
799 if (elecInteractionTypeIsEwald)
801 return (dispatchKernelOnVdwModifier<useSoftCore, scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald, true>(
802 vdwModifierIsPotSwitch));
806 return (dispatchKernelOnVdwModifier<useSoftCore, scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald, false>(
807 vdwModifierIsPotSwitch));
811 template<bool useSoftCore, bool scLambdasOrAlphasDiffer>
812 static KernelFunction dispatchKernelOnVdwInteractionType(const bool vdwInteractionTypeIsEwald,
813 const bool elecInteractionTypeIsEwald,
814 const bool vdwModifierIsPotSwitch)
816 if (vdwInteractionTypeIsEwald)
818 return (dispatchKernelOnElecInteractionType<useSoftCore, scLambdasOrAlphasDiffer, true>(
819 elecInteractionTypeIsEwald, vdwModifierIsPotSwitch));
823 return (dispatchKernelOnElecInteractionType<useSoftCore, scLambdasOrAlphasDiffer, false>(
824 elecInteractionTypeIsEwald, vdwModifierIsPotSwitch));
828 template<bool useSoftCore>
829 static KernelFunction dispatchKernelOnScLambdasOrAlphasDifference(const bool scLambdasOrAlphasDiffer,
830 const bool vdwInteractionTypeIsEwald,
831 const bool elecInteractionTypeIsEwald,
832 const bool vdwModifierIsPotSwitch)
834 if (scLambdasOrAlphasDiffer)
836 return (dispatchKernelOnVdwInteractionType<useSoftCore, true>(
837 vdwInteractionTypeIsEwald, elecInteractionTypeIsEwald, vdwModifierIsPotSwitch));
841 return (dispatchKernelOnVdwInteractionType<useSoftCore, false>(
842 vdwInteractionTypeIsEwald, elecInteractionTypeIsEwald, vdwModifierIsPotSwitch));
846 static KernelFunction dispatchKernel(const bool scLambdasOrAlphasDiffer,
847 const bool vdwInteractionTypeIsEwald,
848 const bool elecInteractionTypeIsEwald,
849 const bool vdwModifierIsPotSwitch,
850 const t_forcerec* fr)
852 if (fr->sc_alphacoul == 0 && fr->sc_alphavdw == 0)
854 return (dispatchKernelOnScLambdasOrAlphasDifference<false>(
855 scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald, elecInteractionTypeIsEwald,
856 vdwModifierIsPotSwitch));
860 return (dispatchKernelOnScLambdasOrAlphasDifference<true>(
861 scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald, elecInteractionTypeIsEwald,
862 vdwModifierIsPotSwitch));
867 void gmx_nb_free_energy_kernel(const t_nblist* nlist,
869 gmx::ForceWithShiftForces* ff,
870 const t_forcerec* fr,
871 const t_mdatoms* mdatoms,
872 nb_kernel_data_t* kernel_data,
875 GMX_ASSERT(EEL_PME_EWALD(fr->ic->eeltype) || fr->ic->eeltype == eelCUT || EEL_RF(fr->ic->eeltype),
876 "Unsupported eeltype with free energy");
878 const bool vdwInteractionTypeIsEwald = (EVDW_PME(fr->ic->vdwtype));
879 const bool elecInteractionTypeIsEwald = (EEL_PME_EWALD(fr->ic->eeltype));
880 const bool vdwModifierIsPotSwitch = (fr->ic->vdw_modifier == eintmodPOTSWITCH);
881 bool scLambdasOrAlphasDiffer = true;
883 if (fr->sc_alphacoul == 0 && fr->sc_alphavdw == 0)
885 scLambdasOrAlphasDiffer = false;
887 else if (fr->sc_r_power == 6.0_real)
889 if (kernel_data->lambda[efptCOUL] == kernel_data->lambda[efptVDW] && fr->sc_alphacoul == fr->sc_alphavdw)
891 scLambdasOrAlphasDiffer = false;
896 GMX_RELEASE_ASSERT(false, "Unsupported soft-core r-power");
898 KernelFunction kernelFunc = dispatchKernel(scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald,
899 elecInteractionTypeIsEwald, vdwModifierIsPotSwitch, fr);
900 kernelFunc(nlist, xx, ff, fr, mdatoms, kernel_data, nrnb);