Implemented nbnxn LJ switch functions
[alexxy/gromacs.git] / src / gromacs / mdlib / forcerec.c
index f5ecbb13325de3d1406f876d975413a71b291ea8..c88c0f4f7770182615ad900945ca2444b0647b37 100644 (file)
@@ -74,6 +74,7 @@
 #include "nbnxn_consts.h"
 #include "gmx_omp_nthreads.h"
 #include "gmx_detect_hardware.h"
+#include "inputrec.h"
 
 #ifdef _MSC_VER
 /* MSVC definition for __cpuid() */
@@ -1835,11 +1836,52 @@ void init_interaction_const_tables(FILE                *fp,
     }
 }
 
-static void init_interaction_const(FILE                       *fp,
-                                   const t_commrec gmx_unused *cr,
-                                   interaction_const_t       **interaction_const,
-                                   const t_forcerec           *fr,
-                                   real                        rtab)
+static void clear_force_switch_constants(shift_consts_t *sc)
+{
+    sc->c2   = 0;
+    sc->c3   = 0;
+    sc->cpot = 0;
+}
+
+static void force_switch_constants(real p,
+                                   real rsw, real rc,
+                                   shift_consts_t *sc)
+{
+    /* Here we determine the coefficient for shifting the force to zero
+     * between distance rsw and the cut-off rc.
+     * For a potential of r^-p, we have force p*r^-(p+1).
+     * But to save flops we absorb p in the coefficient.
+     * Thus we get:
+     * force/p   = r^-(p+1) + c2*r^2 + c3*r^3
+     * potential = r^-p + c2/3*r^3 + c3/4*r^4 + cpot
+     */
+    sc->c2   =  ((p + 1)*rsw - (p + 4)*rc)/(pow(rc, p + 2)*pow(rc - rsw, 2));
+    sc->c3   = -((p + 1)*rsw - (p + 3)*rc)/(pow(rc, p + 2)*pow(rc - rsw, 3));
+    sc->cpot = -pow(rc, -p) + p*sc->c2/3*pow(rc - rsw, 3) + p*sc->c3/4*pow(rc - rsw, 4);
+}
+
+static void potential_switch_constants(real rsw, real rc,
+                                       switch_consts_t *sc)
+{
+    /* The switch function is 1 at rsw and 0 at rc.
+     * The derivative and second derivate are zero at both ends.
+     * rsw        = max(r - r_switch, 0)
+     * sw         = 1 + c3*rsw^3 + c4*rsw^4 + c5*rsw^5
+     * dsw        = 3*c3*rsw^2 + 4*c4*rsw^3 + 5*c5*rsw^4
+     * force      = force*dsw - potential*sw
+     * potential *= sw
+     */
+    sc->c3 = -10*pow(rc - rsw, -3);
+    sc->c4 =  15*pow(rc - rsw, -4);
+    sc->c5 =  -6*pow(rc - rsw, -5);
+}
+
+static void
+init_interaction_const(FILE                       *fp,
+                       const t_commrec gmx_unused *cr,
+                       interaction_const_t       **interaction_const,
+                       const t_forcerec           *fr,
+                       real                        rtab)
 {
     interaction_const_t *ic;
     gmx_bool             bUsesSimpleTables = TRUE;
@@ -1855,16 +1897,41 @@ static void init_interaction_const(FILE                       *fp,
     ic->rlistlong   = fr->rlistlong;
 
     /* Lennard-Jones */
-    ic->rvdw        = fr->rvdw;
-    if (fr->vdw_modifier == eintmodPOTSHIFT)
-    {
-        ic->sh_invrc6 = pow(ic->rvdw, -6.0);
-    }
-    else
-    {
-        ic->sh_invrc6 = 0;
+    ic->vdw_modifier = fr->vdw_modifier;
+    ic->rvdw         = fr->rvdw;
+    ic->rvdw_switch  = fr->rvdw_switch;
+    clear_force_switch_constants(&ic->dispersion_shift);
+    clear_force_switch_constants(&ic->repulsion_shift);
+
+    switch (ic->vdw_modifier)
+    {
+        case eintmodPOTSHIFT:
+            /* Only shift the potential, don't touch the force */
+            ic->dispersion_shift.cpot = -pow(ic->rvdw, -6.0);
+            ic->repulsion_shift.cpot  = -pow(ic->rvdw, -12.0);
+            break;
+        case eintmodFORCESWITCH:
+            /* Switch the force, switch and shift the potential */
+            force_switch_constants(6.0, ic->rvdw_switch, ic->rvdw,
+                                   &ic->dispersion_shift);
+            force_switch_constants(12.0, ic->rvdw_switch, ic->rvdw,
+                                   &ic->repulsion_shift);
+            break;
+        case eintmodPOTSWITCH:
+            /* Switch the potential and force */
+            potential_switch_constants(ic->rvdw_switch, ic->rvdw,
+                                       &ic->vdw_switch);
+            break;
+        case eintmodNONE:
+        case eintmodEXACTCUTOFF:
+            /* Nothing to do here */
+            break;
+        default:
+            gmx_incons("unimplemented potential modifier");
     }
 
+    ic->sh_invrc6 = -ic->dispersion_shift.cpot;
+
     /* Electrostatics */
     ic->eeltype     = fr->eeltype;
     ic->rcoulomb    = fr->rcoulomb;
@@ -1909,14 +1976,14 @@ static void init_interaction_const(FILE                       *fp,
     if (fp != NULL)
     {
         fprintf(fp, "Potential shift: LJ r^-12: %.3f r^-6 %.3f",
-                sqr(ic->sh_invrc6), ic->sh_invrc6);
+                ic->repulsion_shift.cpot, ic->dispersion_shift.cpot);
         if (ic->eeltype == eelCUT)
         {
-            fprintf(fp, ", Coulomb %.3f", ic->c_rf);
+            fprintf(fp, ", Coulomb %.3f", -ic->c_rf);
         }
         else if (EEL_PME(ic->eeltype))
         {
-            fprintf(fp, ", Ewald %.3e", ic->sh_ewald);
+            fprintf(fp, ", Ewald %.3e", -ic->sh_ewald);
         }
         fprintf(fp, "\n");
     }
@@ -2082,13 +2149,19 @@ static void init_nb_verlet(FILE                *fp,
         if (i == 0 ||
             nbv->grp[0].kernel_type != nbv->grp[i].kernel_type)
         {
+            gmx_bool bSimpleList;
+
+            bSimpleList = nbnxn_kernel_pairlist_simple(nbv->grp[i].kernel_type);
+
             snew(nbv->grp[i].nbat, 1);
             nbnxn_atomdata_init(fp,
                                 nbv->grp[i].nbat,
                                 nbv->grp[i].kernel_type,
+                                /* SIMD LJ switch kernels don't support LJ combination rules */
+                                bSimpleList && !(fr->vdw_modifier == eintmodFORCESWITCH || fr->vdw_modifier == eintmodPOTSWITCH),
                                 fr->ntype, fr->nbfp,
                                 ir->opts.ngener,
-                                nbnxn_kernel_pairlist_simple(nbv->grp[i].kernel_type) ? gmx_omp_nthreads_get(emntNonbonded) : 1,
+                                bSimpleList ? gmx_omp_nthreads_get(emntNonbonded) : 1,
                                 nb_alloc, nb_free);
         }
         else
@@ -2740,7 +2813,8 @@ void init_forcerec(FILE              *fp,
      * A little unnecessary to make both vdw and coul tables sometimes,
      * but what the heck... */
 
-    bMakeTables = fr->bcoultab || fr->bvdwtab || fr->bEwald;
+    bMakeTables = fr->bcoultab || fr->bvdwtab || fr->bEwald ||
+        (ir->eDispCorr != edispcNO && ir_vdw_switched(ir));
 
     bMakeSeparate14Table = ((!bMakeTables || fr->eeltype != eelCUT || fr->vdwtype != evdwCUT ||
                              fr->bBHAM || fr->bEwald) &&