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 //! Enum for templating the soft-core treatment in the kernel
58 enum class SoftCoreTreatment
60 None, //!< No soft-core
61 RPower6, //!< Soft-core with r-power = 6
62 RPower48 //!< Soft-core with r-power = 48
65 //! Most treatments are fine with float in mixed-precision mode.
66 template<SoftCoreTreatment softCoreTreatment>
69 //! Real type for soft-core calculations
73 //! This treatment requires double precision for some computations.
75 struct SoftCoreReal<SoftCoreTreatment::RPower48>
77 //! Real type for soft-core calculations
81 //! Computes r^(1/p) and 1/r^(1/p) for the standard p=6
82 template<SoftCoreTreatment softCoreTreatment>
83 static inline void pthRoot(const real r, real* pthRoot, real* invPthRoot)
85 *invPthRoot = gmx::invsqrt(std::cbrt(r));
86 *pthRoot = 1 / (*invPthRoot);
89 // We need a double version to make the specialization below work
91 //! Computes r^(1/p) and 1/r^(1/p) for the standard p=6
92 template<SoftCoreTreatment softCoreTreatment>
93 static inline void pthRoot(const double r, real* pthRoot, double* invPthRoot)
95 *invPthRoot = gmx::invsqrt(std::cbrt(r));
96 *pthRoot = 1 / (*invPthRoot);
100 //! Computes r^(1/p) and 1/r^(1/p) for p=48
102 inline void pthRoot<SoftCoreTreatment::RPower48>(const double r, real* pthRoot, double* invPthRoot)
104 *pthRoot = std::pow(r, 1.0 / 48.0);
105 *invPthRoot = 1 / (*pthRoot);
108 template<SoftCoreTreatment softCoreTreatment>
109 static inline real calculateSigmaPow(const real sigma6)
111 if (softCoreTreatment == SoftCoreTreatment::RPower6)
117 real sigmaPow = sigma6 * sigma6; /* sigma^12 */
118 sigmaPow = sigmaPow * sigmaPow; /* sigma^24 */
119 sigmaPow = sigmaPow * sigmaPow; /* sigma^48 */
124 template<SoftCoreTreatment softCoreTreatment, class SCReal>
125 static inline real calculateRinv6(const SCReal rinvV)
127 if (softCoreTreatment == SoftCoreTreatment::RPower6)
133 real rinv6 = rinvV * rinvV;
134 return (rinv6 * rinv6 * rinv6);
138 static inline real calculateVdw6(const real c6, const real rinv6)
143 static inline real calculateVdw12(const real c12, const real rinv6)
145 return (c12 * rinv6 * rinv6);
148 /* reaction-field electrostatics */
149 template<class SCReal>
151 reactionFieldScalarForce(const real qq, const real rinv, const SCReal r, const real krf, const real two)
153 return (qq * (rinv - two * krf * r * r));
155 template<class SCReal>
157 reactionFieldPotential(const real qq, const real rinv, const SCReal r, const real krf, const real potentialShift)
159 return (qq * (rinv + krf * r * r - potentialShift));
162 /* Ewald electrostatics */
163 static inline real ewaldScalarForce(const real coulomb, const real rinv)
165 return (coulomb * rinv);
167 static inline real ewaldPotential(const real coulomb, const real rinv, const real potentialShift)
169 return (coulomb * (rinv - potentialShift));
173 static inline real lennardJonesScalarForce(const real v6, const real v12)
177 static inline real lennardJonesPotential(const real v6,
181 const real repulsionShift,
182 const real dispersionShift,
184 const real onetwelfth)
186 return ((v12 + c12 * repulsionShift) * onetwelfth - (v6 + c6 * dispersionShift) * onesixth);
190 static inline real ewaldLennardJonesGridSubtract(const real c6grid, const real potentialShift, const real onesixth)
192 return (c6grid * potentialShift * onesixth);
195 /* LJ Potential switch */
196 template<class SCReal>
197 static inline SCReal potSwitchScalarForceMod(const SCReal fScalarInp,
198 const real potential,
207 SCReal fScalar = fScalarInp * sw - r * potential * dsw;
212 template<class SCReal>
214 potSwitchPotentialMod(const real potentialInp, const real sw, const SCReal r, const real rVdw, const real zero)
218 real potential = potentialInp * sw;
225 //! Templated free-energy non-bonded kernel
226 template<SoftCoreTreatment softCoreTreatment, bool scLambdasOrAlphasDiffer, bool vdwInteractionTypeIsEwald, bool elecInteractionTypeIsEwald, bool vdwModifierIsPotSwitch>
227 static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
228 rvec* gmx_restrict xx,
229 gmx::ForceWithShiftForces* forceWithShiftForces,
230 const t_forcerec* gmx_restrict fr,
231 const t_mdatoms* gmx_restrict mdatoms,
232 nb_kernel_data_t* gmx_restrict kernel_data,
233 t_nrnb* gmx_restrict nrnb)
235 using SCReal = typename SoftCoreReal<softCoreTreatment>::Real;
237 constexpr bool useSoftCore = (softCoreTreatment != SoftCoreTreatment::None);
243 constexpr real onetwelfth = 1.0 / 12.0;
244 constexpr real onesixth = 1.0 / 6.0;
245 constexpr real zero = 0.0;
246 constexpr real half = 0.5;
247 constexpr real one = 1.0;
248 constexpr real two = 2.0;
249 constexpr real six = 6.0;
251 /* Extract pointer to non-bonded interaction constants */
252 const interaction_const_t* ic = fr->ic;
254 // Extract pair list data
255 const int nri = nlist->nri;
256 const int* iinr = nlist->iinr;
257 const int* jindex = nlist->jindex;
258 const int* jjnr = nlist->jjnr;
259 const int* shift = nlist->shift;
260 const int* gid = nlist->gid;
262 const real* shiftvec = fr->shift_vec[0];
263 const real* chargeA = mdatoms->chargeA;
264 const real* chargeB = mdatoms->chargeB;
265 real* Vc = kernel_data->energygrp_elec;
266 const int* typeA = mdatoms->typeA;
267 const int* typeB = mdatoms->typeB;
268 const int ntype = fr->ntype;
269 const real* nbfp = fr->nbfp.data();
270 const real* nbfp_grid = fr->ljpme_c6grid;
271 real* Vv = kernel_data->energygrp_vdw;
272 const real lambda_coul = kernel_data->lambda[efptCOUL];
273 const real lambda_vdw = kernel_data->lambda[efptVDW];
274 real* dvdl = kernel_data->dvdl;
275 const real alpha_coul = fr->sc_alphacoul;
276 const real alpha_vdw = fr->sc_alphavdw;
277 const real lam_power = fr->sc_power;
278 const real sigma6_def = fr->sc_sigma6_def;
279 const real sigma6_min = fr->sc_sigma6_min;
280 const bool doForces = ((kernel_data->flags & GMX_NONBONDED_DO_FORCE) != 0);
281 const bool doShiftForces = ((kernel_data->flags & GMX_NONBONDED_DO_SHIFTFORCE) != 0);
282 const bool doPotential = ((kernel_data->flags & GMX_NONBONDED_DO_POTENTIAL) != 0);
284 // Extract data from interaction_const_t
285 const real facel = ic->epsfac;
286 const real rcoulomb = ic->rcoulomb;
287 const real krf = ic->k_rf;
288 const real crf = ic->c_rf;
289 const real sh_lj_ewald = ic->sh_lj_ewald;
290 const real rvdw = ic->rvdw;
291 const real dispersionShift = ic->dispersion_shift.cpot;
292 const real repulsionShift = ic->repulsion_shift.cpot;
294 // Note that the nbnxm kernels do not support Coulomb potential switching at all
295 GMX_ASSERT(ic->coulomb_modifier != eintmodPOTSWITCH,
296 "Potential switching is not supported for Coulomb with FEP");
298 real vdw_swV3, vdw_swV4, vdw_swV5, vdw_swF2, vdw_swF3, vdw_swF4;
299 if (vdwModifierIsPotSwitch)
301 const real d = ic->rvdw - ic->rvdw_switch;
302 vdw_swV3 = -10.0 / (d * d * d);
303 vdw_swV4 = 15.0 / (d * d * d * d);
304 vdw_swV5 = -6.0 / (d * d * d * d * d);
305 vdw_swF2 = -30.0 / (d * d * d);
306 vdw_swF3 = 60.0 / (d * d * d * d);
307 vdw_swF4 = -30.0 / (d * d * d * d * d);
311 /* Avoid warnings from stupid compilers (looking at you, Clang!) */
312 vdw_swV3 = vdw_swV4 = vdw_swV5 = vdw_swF2 = vdw_swF3 = vdw_swF4 = 0.0;
316 if (ic->eeltype == eelCUT || EEL_RF(ic->eeltype))
318 icoul = GMX_NBKERNEL_ELEC_REACTIONFIELD;
322 icoul = GMX_NBKERNEL_ELEC_NONE;
325 real rcutoff_max2 = std::max(ic->rcoulomb, ic->rvdw);
326 rcutoff_max2 = rcutoff_max2 * rcutoff_max2;
328 const real* tab_ewald_F_lj = nullptr;
329 const real* tab_ewald_V_lj = nullptr;
330 const real* ewtab = nullptr;
332 real ewtabhalfspace = 0;
334 if (elecInteractionTypeIsEwald || vdwInteractionTypeIsEwald)
336 const auto& tables = *ic->coulombEwaldTables;
337 sh_ewald = ic->sh_ewald;
338 ewtab = tables.tableFDV0.data();
339 ewtabscale = tables.scale;
340 ewtabhalfspace = half / ewtabscale;
341 tab_ewald_F_lj = tables.tableF.data();
342 tab_ewald_V_lj = tables.tableV.data();
345 /* For Ewald/PME interactions we cannot easily apply the soft-core component to
346 * reciprocal space. When we use non-switched Ewald interactions, we
347 * assume the soft-coring does not significantly affect the grid contribution
348 * and apply the soft-core only to the full 1/r (- shift) pair contribution.
350 * However, we cannot use this approach for switch-modified since we would then
351 * effectively end up evaluating a significantly different interaction here compared to the
352 * normal (non-free-energy) kernels, either by applying a cutoff at a different
353 * position than what the user requested, or by switching different
354 * things (1/r rather than short-range Ewald). For these settings, we just
355 * use the traditional short-range Ewald interaction in that case.
357 GMX_RELEASE_ASSERT(!(vdwInteractionTypeIsEwald && vdwModifierIsPotSwitch),
358 "Can not apply soft-core to switched Ewald potentials");
360 SCReal dvdl_coul = 0; /* Needs double for sc_power==48 */
361 SCReal dvdl_vdw = 0; /* Needs double for sc_power==48 */
363 /* Lambda factor for state A, 1-lambda*/
364 real LFC[NSTATES], LFV[NSTATES];
365 LFC[STATE_A] = one - lambda_coul;
366 LFV[STATE_A] = one - lambda_vdw;
368 /* Lambda factor for state B, lambda*/
369 LFC[STATE_B] = lambda_coul;
370 LFV[STATE_B] = lambda_vdw;
372 /*derivative of the lambda factor for state A and B */
377 real lfac_coul[NSTATES], dlfac_coul[NSTATES], lfac_vdw[NSTATES], dlfac_vdw[NSTATES];
378 constexpr real sc_r_power = (softCoreTreatment == SoftCoreTreatment::RPower48 ? 48.0_real : 6.0_real);
379 for (int i = 0; i < NSTATES; i++)
381 lfac_coul[i] = (lam_power == 2 ? (1 - LFC[i]) * (1 - LFC[i]) : (1 - LFC[i]));
382 dlfac_coul[i] = DLF[i] * lam_power / sc_r_power * (lam_power == 2 ? (1 - LFC[i]) : 1);
383 lfac_vdw[i] = (lam_power == 2 ? (1 - LFV[i]) * (1 - LFV[i]) : (1 - LFV[i]));
384 dlfac_vdw[i] = DLF[i] * lam_power / sc_r_power * (lam_power == 2 ? (1 - LFV[i]) : 1);
387 // TODO: We should get rid of using pointers to real
388 const real* x = xx[0];
389 real* gmx_restrict f = &(forceWithShiftForces->force()[0][0]);
390 real* gmx_restrict fshift = &(forceWithShiftForces->shiftForces()[0][0]);
392 for (int n = 0; n < nri; n++)
394 int npair_within_cutoff = 0;
396 const int is3 = 3 * shift[n];
397 const real shX = shiftvec[is3];
398 const real shY = shiftvec[is3 + 1];
399 const real shZ = shiftvec[is3 + 2];
400 const int nj0 = jindex[n];
401 const int nj1 = jindex[n + 1];
402 const int ii = iinr[n];
403 const int ii3 = 3 * ii;
404 const real ix = shX + x[ii3 + 0];
405 const real iy = shY + x[ii3 + 1];
406 const real iz = shZ + x[ii3 + 2];
407 const real iqA = facel * chargeA[ii];
408 const real iqB = facel * chargeB[ii];
409 const int ntiA = 2 * ntype * typeA[ii];
410 const int ntiB = 2 * ntype * typeB[ii];
417 for (int k = nj0; k < nj1; k++)
420 const int jnr = jjnr[k];
421 const int j3 = 3 * jnr;
422 real c6[NSTATES], c12[NSTATES], qq[NSTATES], Vcoul[NSTATES], Vvdw[NSTATES];
423 real r, rinv, rp, rpm2;
424 real alpha_vdw_eff, alpha_coul_eff, sigma_pow[NSTATES];
425 const real dx = ix - x[j3];
426 const real dy = iy - x[j3 + 1];
427 const real dz = iz - x[j3 + 2];
428 const real rsq = dx * dx + dy * dy + dz * dz;
429 SCReal FscalC[NSTATES], FscalV[NSTATES]; /* Needs double for sc_power==48 */
431 if (rsq >= rcutoff_max2)
433 /* We save significant time by skipping all code below.
434 * Note that with soft-core interactions, the actual cut-off
435 * check might be different. But since the soft-core distance
436 * is always larger than r, checking on r here is safe.
440 npair_within_cutoff++;
444 /* Note that unlike in the nbnxn kernels, we do not need
445 * to clamp the value of rsq before taking the invsqrt
446 * to avoid NaN in the LJ calculation, since here we do
447 * not calculate LJ interactions when C6 and C12 are zero.
450 rinv = gmx::invsqrt(rsq);
455 /* The force at r=0 is zero, because of symmetry.
456 * But note that the potential is in general non-zero,
457 * since the soft-cored r will be non-zero.
463 if (softCoreTreatment == SoftCoreTreatment::None)
465 /* The soft-core power p will not affect the results
466 * with not using soft-core, so we use power of 0 which gives
467 * the simplest math and cheapest code.
472 if (softCoreTreatment == SoftCoreTreatment::RPower6)
474 rpm2 = rsq * rsq; /* r4 */
475 rp = rpm2 * rsq; /* r6 */
477 if (softCoreTreatment == SoftCoreTreatment::RPower48)
479 rp = rsq * rsq * rsq; /* r6 */
480 rp = rp * rp; /* r12 */
481 rp = rp * rp; /* r24 */
482 rp = rp * rp; /* r48 */
483 rpm2 = rp / rsq; /* r46 */
488 qq[STATE_A] = iqA * chargeA[jnr];
489 qq[STATE_B] = iqB * chargeB[jnr];
491 tj[STATE_A] = ntiA + 2 * typeA[jnr];
492 tj[STATE_B] = ntiB + 2 * typeB[jnr];
494 if (nlist->excl_fep == nullptr || nlist->excl_fep[k])
496 c6[STATE_A] = nbfp[tj[STATE_A]];
497 c6[STATE_B] = nbfp[tj[STATE_B]];
499 for (int i = 0; i < NSTATES; i++)
501 c12[i] = nbfp[tj[i] + 1];
504 real sigma6[NSTATES];
505 if ((c6[i] > 0) && (c12[i] > 0))
507 /* c12 is stored scaled with 12.0 and c6 is scaled with 6.0 - correct for this */
508 sigma6[i] = half * c12[i] / c6[i];
509 if (sigma6[i] < sigma6_min) /* for disappearing coul and vdw with soft core at the same time */
511 sigma6[i] = sigma6_min;
516 sigma6[i] = sigma6_def;
518 sigma_pow[i] = calculateSigmaPow<softCoreTreatment>(sigma6[i]);
524 /* only use softcore if one of the states has a zero endstate - softcore is for avoiding infinities!*/
525 if ((c12[STATE_A] > 0) && (c12[STATE_B] > 0))
532 alpha_vdw_eff = alpha_vdw;
533 alpha_coul_eff = alpha_coul;
537 for (int i = 0; i < NSTATES; i++)
545 SCReal rC, rV, rpinvC, rpinvV; /* Needs double for sc_power==48 */
547 /* Only spend time on A or B state if it is non-zero */
548 if ((qq[i] != 0) || (c6[i] != 0) || (c12[i] != 0))
550 /* this section has to be inside the loop because of the dependence on sigma_pow */
553 rpinvC = one / (alpha_coul_eff * lfac_coul[i] * sigma_pow[i] + rp);
554 pthRoot<softCoreTreatment>(rpinvC, &rinvC, &rC);
555 if (scLambdasOrAlphasDiffer)
557 rpinvV = one / (alpha_vdw_eff * lfac_vdw[i] * sigma_pow[i] + rp);
558 pthRoot<softCoreTreatment>(rpinvV, &rinvV, &rV);
562 /* We can avoid one expensive pow and one / operation */
579 /* Only process the coulomb interactions if we have charges,
580 * and if we either include all entries in the list (no cutoff
581 * used in the kernel), or if we are within the cutoff.
583 bool computeElecInteraction = (elecInteractionTypeIsEwald && r < rcoulomb)
584 || (!elecInteractionTypeIsEwald && rC < rcoulomb);
586 if ((qq[i] != 0) && computeElecInteraction)
588 if (elecInteractionTypeIsEwald)
590 Vcoul[i] = ewaldPotential(qq[i], rinvC, sh_ewald);
591 FscalC[i] = ewaldScalarForce(qq[i], rinvC);
595 Vcoul[i] = reactionFieldPotential(qq[i], rinvC, rC, krf, crf);
596 FscalC[i] = reactionFieldScalarForce(qq[i], rinvC, rC, krf, two);
600 /* Only process the VDW interactions if we have
601 * some non-zero parameters, and if we either
602 * include all entries in the list (no cutoff used
603 * in the kernel), or if we are within the cutoff.
605 bool computeVdwInteraction = (vdwInteractionTypeIsEwald && r < rvdw)
606 || (!vdwInteractionTypeIsEwald && rV < rvdw);
607 if ((c6[i] != 0 || c12[i] != 0) && computeVdwInteraction)
610 if (softCoreTreatment == SoftCoreTreatment::RPower6)
612 rinv6 = calculateRinv6<softCoreTreatment>(rpinvV);
616 rinv6 = calculateRinv6<softCoreTreatment>(rinvV);
618 real Vvdw6 = calculateVdw6(c6[i], rinv6);
619 real Vvdw12 = calculateVdw12(c12[i], rinv6);
621 Vvdw[i] = lennardJonesPotential(Vvdw6, Vvdw12, c6[i], c12[i], repulsionShift,
622 dispersionShift, onesixth, onetwelfth);
623 FscalV[i] = lennardJonesScalarForce(Vvdw6, Vvdw12);
625 if (vdwInteractionTypeIsEwald)
627 /* Subtract the grid potential at the cut-off */
628 Vvdw[i] += ewaldLennardJonesGridSubtract(nbfp_grid[tj[i]],
629 sh_lj_ewald, onesixth);
632 if (vdwModifierIsPotSwitch)
634 real d = rV - ic->rvdw_switch;
635 d = (d > zero) ? d : zero;
636 const real d2 = d * d;
637 const real sw = one + d2 * d * (vdw_swV3 + d * (vdw_swV4 + d * vdw_swV5));
638 const real dsw = d2 * (vdw_swF2 + d * (vdw_swF3 + d * vdw_swF4));
640 FscalV[i] = potSwitchScalarForceMod(FscalV[i], Vvdw[i], sw, rV,
642 Vvdw[i] = potSwitchPotentialMod(Vvdw[i], sw, rV, rvdw, zero);
646 /* FscalC (and FscalV) now contain: dV/drC * rC
647 * Now we multiply by rC^-p, so it will be: dV/drC * rC^1-p
648 * Further down we first multiply by r^p-2 and then by
649 * the vector r, which in total gives: dV/drC * (r/rC)^1-p
656 /* Assemble A and B states */
657 for (int i = 0; i < NSTATES; i++)
659 vctot += LFC[i] * Vcoul[i];
660 vvtot += LFV[i] * Vvdw[i];
662 Fscal += LFC[i] * FscalC[i] * rpm2;
663 Fscal += LFV[i] * FscalV[i] * rpm2;
669 + LFC[i] * alpha_coul_eff * dlfac_coul[i] * FscalC[i] * sigma_pow[i];
670 dvdl_vdw += Vvdw[i] * DLF[i]
671 + LFV[i] * alpha_vdw_eff * dlfac_vdw[i] * FscalV[i] * sigma_pow[i];
675 dvdl_coul += Vcoul[i] * DLF[i];
676 dvdl_vdw += Vvdw[i] * DLF[i];
680 else if (icoul == GMX_NBKERNEL_ELEC_REACTIONFIELD)
682 /* For excluded pairs, which are only in this pair list when
683 * using the Verlet scheme, we don't use soft-core.
684 * As there is no singularity, there is no need for soft-core.
686 const real FF = -two * krf;
687 real VV = krf * rsq - crf;
694 for (int i = 0; i < NSTATES; i++)
696 vctot += LFC[i] * qq[i] * VV;
697 Fscal += LFC[i] * qq[i] * FF;
698 dvdl_coul += DLF[i] * qq[i] * VV;
702 if (elecInteractionTypeIsEwald && r < rcoulomb)
704 /* See comment in the preamble. When using Ewald interactions
705 * (unless we use a switch modifier) we subtract the reciprocal-space
706 * Ewald component here which made it possible to apply the free
707 * energy interaction to 1/r (vanilla coulomb short-range part)
708 * above. This gets us closer to the ideal case of applying
709 * the softcore to the entire electrostatic interaction,
710 * including the reciprocal-space component.
714 const real ewrt = r * ewtabscale;
715 int ewitab = static_cast<int>(ewrt);
716 const real eweps = ewrt - ewitab;
718 f_lr = ewtab[ewitab] + eweps * ewtab[ewitab + 1];
719 v_lr = (ewtab[ewitab + 2] - ewtabhalfspace * eweps * (ewtab[ewitab] + f_lr));
722 /* Note that any possible Ewald shift has already been applied in
723 * the normal interaction part above.
728 /* If we get here, the i particle (ii) has itself (jnr)
729 * in its neighborlist. This can only happen with the Verlet
730 * scheme, and corresponds to a self-interaction that will
731 * occur twice. Scale it down by 50% to only include it once.
736 for (int i = 0; i < NSTATES; i++)
738 vctot -= LFC[i] * qq[i] * v_lr;
739 Fscal -= LFC[i] * qq[i] * f_lr;
740 dvdl_coul -= (DLF[i] * qq[i]) * v_lr;
744 if (vdwInteractionTypeIsEwald && r < rvdw)
746 /* See comment in the preamble. When using LJ-Ewald interactions
747 * (unless we use a switch modifier) we subtract the reciprocal-space
748 * Ewald component here which made it possible to apply the free
749 * energy interaction to r^-6 (vanilla LJ6 short-range part)
750 * above. This gets us closer to the ideal case of applying
751 * the softcore to the entire VdW interaction,
752 * including the reciprocal-space component.
754 /* We could also use the analytical form here
755 * iso a table, but that can cause issues for
756 * r close to 0 for non-interacting pairs.
759 const real rs = rsq * rinv * ewtabscale;
760 const int ri = static_cast<int>(rs);
761 const real frac = rs - ri;
762 const real f_lr = (1 - frac) * tab_ewald_F_lj[ri] + frac * tab_ewald_F_lj[ri + 1];
763 /* TODO: Currently the Ewald LJ table does not contain
764 * the factor 1/6, we should add this.
766 const real FF = f_lr * rinv / six;
767 real VV = (tab_ewald_V_lj[ri] - ewtabhalfspace * frac * (tab_ewald_F_lj[ri] + f_lr)) / six;
771 /* If we get here, the i particle (ii) has itself (jnr)
772 * in its neighborlist. This can only happen with the Verlet
773 * scheme, and corresponds to a self-interaction that will
774 * occur twice. Scale it down by 50% to only include it once.
779 for (int i = 0; i < NSTATES; i++)
781 const real c6grid = nbfp_grid[tj[i]];
782 vvtot += LFV[i] * c6grid * VV;
783 Fscal += LFV[i] * c6grid * FF;
784 dvdl_vdw += (DLF[i] * c6grid) * VV;
790 const real tx = Fscal * dx;
791 const real ty = Fscal * dy;
792 const real tz = Fscal * dz;
796 /* OpenMP atomics are expensive, but this kernels is also
797 * expensive, so we can take this hit, instead of using
798 * thread-local output buffers and extra reduction.
800 * All the OpenMP regions in this file are trivial and should
801 * not throw, so no need for try/catch.
812 /* The atomics below are expensive with many OpenMP threads.
813 * Here unperturbed i-particles will usually only have a few
814 * (perturbed) j-particles in the list. Thus with a buffered list
815 * we can skip a significant number of i-reductions with a check.
817 if (npair_within_cutoff > 0)
833 fshift[is3 + 1] += fiy;
835 fshift[is3 + 2] += fiz;
849 dvdl[efptCOUL] += dvdl_coul;
851 dvdl[efptVDW] += dvdl_vdw;
853 /* Estimate flops, average for free energy stuff:
854 * 12 flops per outer iteration
855 * 150 flops per inner iteration
858 inc_nrnb(nrnb, eNR_NBKERNEL_FREE_ENERGY, nlist->nri * 12 + nlist->jindex[nri] * 150);
861 typedef void (*KernelFunction)(const t_nblist* gmx_restrict nlist,
862 rvec* gmx_restrict xx,
863 gmx::ForceWithShiftForces* forceWithShiftForces,
864 const t_forcerec* gmx_restrict fr,
865 const t_mdatoms* gmx_restrict mdatoms,
866 nb_kernel_data_t* gmx_restrict kernel_data,
867 t_nrnb* gmx_restrict nrnb);
869 template<SoftCoreTreatment softCoreTreatment, bool scLambdasOrAlphasDiffer, bool vdwInteractionTypeIsEwald, bool elecInteractionTypeIsEwald>
870 static KernelFunction dispatchKernelOnVdwModifier(const bool vdwModifierIsPotSwitch)
872 if (vdwModifierIsPotSwitch)
874 return (nb_free_energy_kernel<softCoreTreatment, scLambdasOrAlphasDiffer,
875 vdwInteractionTypeIsEwald, elecInteractionTypeIsEwald, true>);
879 return (nb_free_energy_kernel<softCoreTreatment, scLambdasOrAlphasDiffer,
880 vdwInteractionTypeIsEwald, elecInteractionTypeIsEwald, false>);
884 template<SoftCoreTreatment softCoreTreatment, bool scLambdasOrAlphasDiffer, bool vdwInteractionTypeIsEwald>
885 static KernelFunction dispatchKernelOnElecInteractionType(const bool elecInteractionTypeIsEwald,
886 const bool vdwModifierIsPotSwitch)
888 if (elecInteractionTypeIsEwald)
890 return (dispatchKernelOnVdwModifier<softCoreTreatment, scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald, true>(
891 vdwModifierIsPotSwitch));
895 return (dispatchKernelOnVdwModifier<softCoreTreatment, scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald, false>(
896 vdwModifierIsPotSwitch));
900 template<SoftCoreTreatment softCoreTreatment, bool scLambdasOrAlphasDiffer>
901 static KernelFunction dispatchKernelOnVdwInteractionType(const bool vdwInteractionTypeIsEwald,
902 const bool elecInteractionTypeIsEwald,
903 const bool vdwModifierIsPotSwitch)
905 if (vdwInteractionTypeIsEwald)
907 return (dispatchKernelOnElecInteractionType<softCoreTreatment, scLambdasOrAlphasDiffer, true>(
908 elecInteractionTypeIsEwald, vdwModifierIsPotSwitch));
912 return (dispatchKernelOnElecInteractionType<softCoreTreatment, scLambdasOrAlphasDiffer, false>(
913 elecInteractionTypeIsEwald, vdwModifierIsPotSwitch));
917 template<SoftCoreTreatment softCoreTreatment>
918 static KernelFunction dispatchKernelOnScLambdasOrAlphasDifference(const bool scLambdasOrAlphasDiffer,
919 const bool vdwInteractionTypeIsEwald,
920 const bool elecInteractionTypeIsEwald,
921 const bool vdwModifierIsPotSwitch)
923 if (scLambdasOrAlphasDiffer)
925 return (dispatchKernelOnVdwInteractionType<softCoreTreatment, true>(
926 vdwInteractionTypeIsEwald, elecInteractionTypeIsEwald, vdwModifierIsPotSwitch));
930 return (dispatchKernelOnVdwInteractionType<softCoreTreatment, false>(
931 vdwInteractionTypeIsEwald, elecInteractionTypeIsEwald, vdwModifierIsPotSwitch));
935 static KernelFunction dispatchKernel(const bool scLambdasOrAlphasDiffer,
936 const bool vdwInteractionTypeIsEwald,
937 const bool elecInteractionTypeIsEwald,
938 const bool vdwModifierIsPotSwitch,
939 const t_forcerec* fr)
941 if (fr->sc_alphacoul == 0 && fr->sc_alphavdw == 0)
943 return (dispatchKernelOnScLambdasOrAlphasDifference<SoftCoreTreatment::None>(
944 scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald, elecInteractionTypeIsEwald,
945 vdwModifierIsPotSwitch));
947 else if (fr->sc_r_power == 6.0_real)
949 return (dispatchKernelOnScLambdasOrAlphasDifference<SoftCoreTreatment::RPower6>(
950 scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald, elecInteractionTypeIsEwald,
951 vdwModifierIsPotSwitch));
955 return (dispatchKernelOnScLambdasOrAlphasDifference<SoftCoreTreatment::RPower48>(
956 scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald, elecInteractionTypeIsEwald,
957 vdwModifierIsPotSwitch));
962 void gmx_nb_free_energy_kernel(const t_nblist* nlist,
964 gmx::ForceWithShiftForces* ff,
965 const t_forcerec* fr,
966 const t_mdatoms* mdatoms,
967 nb_kernel_data_t* kernel_data,
970 GMX_ASSERT(EEL_PME_EWALD(fr->ic->eeltype) || fr->ic->eeltype == eelCUT || EEL_RF(fr->ic->eeltype),
971 "Unsupported eeltype with free energy");
973 const bool vdwInteractionTypeIsEwald = (EVDW_PME(fr->ic->vdwtype));
974 const bool elecInteractionTypeIsEwald = (EEL_PME_EWALD(fr->ic->eeltype));
975 const bool vdwModifierIsPotSwitch = (fr->ic->vdw_modifier == eintmodPOTSWITCH);
976 bool scLambdasOrAlphasDiffer = true;
978 if (fr->sc_alphacoul == 0 && fr->sc_alphavdw == 0)
980 scLambdasOrAlphasDiffer = false;
982 else if (fr->sc_r_power == 6.0_real || fr->sc_r_power == 48.0_real)
984 if (kernel_data->lambda[efptCOUL] == kernel_data->lambda[efptVDW] && fr->sc_alphacoul == fr->sc_alphavdw)
986 scLambdasOrAlphasDiffer = false;
991 GMX_RELEASE_ASSERT(false, "Unsupported soft-core r-power");
993 KernelFunction kernelFunc = dispatchKernel(scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald,
994 elecInteractionTypeIsEwald, vdwModifierIsPotSwitch, fr);
995 kernelFunc(nlist, xx, ff, fr, mdatoms, kernel_data, nrnb);