Merge branch release-5-1 into release-2016
[alexxy/gromacs.git] / src / gromacs / mdlib / forcerec.cpp
index d5710ab84be444861abd26013fcb063f16a1c280..703a1cd471ad50196031a097fa5ad0d9349ed62e 100644 (file)
  */
 #include "gmxpre.h"
 
+#include "forcerec.h"
+
 #include "config.h"
 
 #include <assert.h>
-#include <math.h>
 #include <stdlib.h>
 #include <string.h>
 
+#include <cmath>
+
 #include <algorithm>
 
+#include "gromacs/commandline/filenm.h"
 #include "gromacs/domdec/domdec.h"
+#include "gromacs/domdec/domdec_struct.h"
 #include "gromacs/ewald/ewald.h"
-#include "gromacs/fileio/filenm.h"
-#include "gromacs/gmxlib/gpu_utils/gpu_utils.h"
-#include "gromacs/legacyheaders/copyrite.h"
-#include "gromacs/legacyheaders/force.h"
-#include "gromacs/legacyheaders/gmx_detect_hardware.h"
-#include "gromacs/legacyheaders/gmx_omp_nthreads.h"
-#include "gromacs/legacyheaders/inputrec.h"
-#include "gromacs/legacyheaders/macros.h"
-#include "gromacs/legacyheaders/md_logging.h"
-#include "gromacs/legacyheaders/md_support.h"
-#include "gromacs/legacyheaders/names.h"
-#include "gromacs/legacyheaders/network.h"
-#include "gromacs/legacyheaders/nonbonded.h"
-#include "gromacs/legacyheaders/ns.h"
-#include "gromacs/legacyheaders/qmmm.h"
-#include "gromacs/legacyheaders/tables.h"
-#include "gromacs/legacyheaders/txtdump.h"
-#include "gromacs/legacyheaders/typedefs.h"
-#include "gromacs/legacyheaders/types/commrec.h"
+#include "gromacs/fileio/filetypes.h"
+#include "gromacs/gmxlib/md_logging.h"
+#include "gromacs/gmxlib/network.h"
+#include "gromacs/gmxlib/nonbonded/nonbonded.h"
+#include "gromacs/gpu_utils/gpu_utils.h"
+#include "gromacs/hardware/detecthardware.h"
 #include "gromacs/listed-forces/manage-threading.h"
+#include "gromacs/listed-forces/pairs.h"
 #include "gromacs/math/calculate-ewald-splitting-coefficient.h"
+#include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
+#include "gromacs/mdlib/force.h"
 #include "gromacs/mdlib/forcerec-threading.h"
+#include "gromacs/mdlib/gmx_omp_nthreads.h"
+#include "gromacs/mdlib/md_support.h"
 #include "gromacs/mdlib/nb_verlet.h"
 #include "gromacs/mdlib/nbnxn_atomdata.h"
 #include "gromacs/mdlib/nbnxn_gpu_data_mgmt.h"
 #include "gromacs/mdlib/nbnxn_search.h"
 #include "gromacs/mdlib/nbnxn_simd.h"
+#include "gromacs/mdlib/nbnxn_util.h"
+#include "gromacs/mdlib/ns.h"
+#include "gromacs/mdlib/qmmm.h"
+#include "gromacs/mdlib/sim_util.h"
+#include "gromacs/mdtypes/commrec.h"
+#include "gromacs/mdtypes/fcdata.h"
+#include "gromacs/mdtypes/group.h"
+#include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/pbcutil/ishift.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/simd/simd.h"
+#include "gromacs/tables/forcetable.h"
 #include "gromacs/topology/mtop_util.h"
+#include "gromacs/trajectory/trajectoryframe.h"
+#include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/pleasecite.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/stringutil.h"
 
 #include "nbnxn_gpu_jit_support.h"
 
+const char *egrp_nm[egNR+1] = {
+    "Coul-SR", "LJ-SR", "Buck-SR",
+    "Coul-14", "LJ-14", NULL
+};
+
 t_forcerec *mk_forcerec(void)
 {
     t_forcerec *fr;
@@ -164,7 +180,6 @@ static real *make_ljpme_c6grid(const gmx_ffparams_t *idef, t_forcerec *fr)
     int        i, j, k, atnr;
     real       c6, c6i, c6j, c12i, c12j, epsi, epsj, sigmai, sigmaj;
     real      *grid;
-    const real oneOverSix = 1.0 / 6.0;
 
     /* For LJ-PME simulations, we correct the energies with the reciprocal space
      * inside of the cut-off. To do this the non-bonded kernels needs to have
@@ -181,15 +196,15 @@ static real *make_ljpme_c6grid(const gmx_ffparams_t *idef, t_forcerec *fr)
             c12i = idef->iparams[i*(atnr+1)].lj.c12;
             c6j  = idef->iparams[j*(atnr+1)].lj.c6;
             c12j = idef->iparams[j*(atnr+1)].lj.c12;
-            c6   = sqrt(c6i * c6j);
+            c6   = std::sqrt(c6i * c6j);
             if (fr->ljpme_combination_rule == eljpmeLB
                 && !gmx_numzero(c6) && !gmx_numzero(c12i) && !gmx_numzero(c12j))
             {
-                sigmai = pow(c12i / c6i, oneOverSix);
-                sigmaj = pow(c12j / c6j, oneOverSix);
+                sigmai = gmx::sixthroot(c12i / c6i);
+                sigmaj = gmx::sixthroot(c12j / c6j);
                 epsi   = c6i * c6i / c12i;
                 epsj   = c6j * c6j / c12j;
-                c6     = sqrt(epsi * epsj) * pow(0.5*(sigmai+sigmaj), 6);
+                c6     = std::sqrt(epsi * epsj) * gmx::power6(0.5*(sigmai+sigmaj));
             }
             /* Store the elements at the same relative positions as C6 in nbfp in order
              * to simplify access in the kernels
@@ -206,7 +221,6 @@ static real *mk_nbfp_combination_rule(const gmx_ffparams_t *idef, int comb_rule)
     int        i, j, atnr;
     real       c6i, c6j, c12i, c12j, epsi, epsj, sigmai, sigmaj;
     real       c6, c12;
-    const real oneOverSix = 1.0 / 6.0;
 
     atnr = idef->atnr;
     snew(nbfp, 2*atnr*atnr);
@@ -218,17 +232,17 @@ static real *mk_nbfp_combination_rule(const gmx_ffparams_t *idef, int comb_rule)
             c12i = idef->iparams[i*(atnr+1)].lj.c12;
             c6j  = idef->iparams[j*(atnr+1)].lj.c6;
             c12j = idef->iparams[j*(atnr+1)].lj.c12;
-            c6   = sqrt(c6i  * c6j);
-            c12  = sqrt(c12i * c12j);
+            c6   = std::sqrt(c6i  * c6j);
+            c12  = std::sqrt(c12i * c12j);
             if (comb_rule == eCOMB_ARITHMETIC
                 && !gmx_numzero(c6) && !gmx_numzero(c12))
             {
-                sigmai = pow(c12i / c6i, oneOverSix);
-                sigmaj = pow(c12j / c6j, oneOverSix);
+                sigmai = gmx::sixthroot(c12i / c6i);
+                sigmaj = gmx::sixthroot(c12j / c6j);
                 epsi   = c6i * c6i / c12i;
                 epsj   = c6j * c6j / c12j;
-                c6     = sqrt(epsi * epsj) * pow(0.5*(sigmai+sigmaj), 6);
-                c12    = sqrt(epsi * epsj) * pow(0.5*(sigmai+sigmaj), 12);
+                c6     = std::sqrt(epsi * epsj) * gmx::power6(0.5*(sigmai+sigmaj));
+                c12    = std::sqrt(epsi * epsj) * gmx::power12(0.5*(sigmai+sigmaj));
             }
             C6(nbfp, atnr, i, j)   = c6*6.0;
             C12(nbfp, atnr, i, j)  = c12*12.0;
@@ -1274,9 +1288,8 @@ static void set_bham_b_max(FILE *fplog, t_forcerec *fr,
     }
 }
 
-static void make_nbf_tables(FILE *fp, const output_env_t oenv,
+static void make_nbf_tables(FILE *fp,
                             t_forcerec *fr, real rtab,
-                            const t_commrec *cr,
                             const char *tabfn, char *eg1, char *eg2,
                             t_nblists *nbl)
 {
@@ -1299,7 +1312,7 @@ static void make_nbf_tables(FILE *fp, const output_env_t oenv,
         sprintf(buf + strlen(tabfn) - strlen(ftp2ext(efXVG)) - 1, "_%s_%s.%s",
                 eg1, eg2, ftp2ext(efXVG));
     }
-    nbl->table_elec_vdw = make_tables(fp, oenv, fr, MASTER(cr), buf, rtab, 0);
+    nbl->table_elec_vdw = make_tables(fp, fr, buf, rtab, 0);
     /* Copy the contents of the table to separate coulomb and LJ tables too,
      * to improve cache performance.
      */
@@ -1307,37 +1320,37 @@ static void make_nbf_tables(FILE *fp, const output_env_t oenv,
      * the table data to be aligned to 16-byte. The pointers could be freed
      * but currently aren't.
      */
-    nbl->table_elec.interaction   = GMX_TABLE_INTERACTION_ELEC;
-    nbl->table_elec.format        = nbl->table_elec_vdw.format;
-    nbl->table_elec.r             = nbl->table_elec_vdw.r;
-    nbl->table_elec.n             = nbl->table_elec_vdw.n;
-    nbl->table_elec.scale         = nbl->table_elec_vdw.scale;
-    nbl->table_elec.scale_exp     = nbl->table_elec_vdw.scale_exp;
-    nbl->table_elec.formatsize    = nbl->table_elec_vdw.formatsize;
-    nbl->table_elec.ninteractions = 1;
-    nbl->table_elec.stride        = nbl->table_elec.formatsize * nbl->table_elec.ninteractions;
-    snew_aligned(nbl->table_elec.data, nbl->table_elec.stride*(nbl->table_elec.n+1), 32);
-
-    nbl->table_vdw.interaction   = GMX_TABLE_INTERACTION_VDWREP_VDWDISP;
-    nbl->table_vdw.format        = nbl->table_elec_vdw.format;
-    nbl->table_vdw.r             = nbl->table_elec_vdw.r;
-    nbl->table_vdw.n             = nbl->table_elec_vdw.n;
-    nbl->table_vdw.scale         = nbl->table_elec_vdw.scale;
-    nbl->table_vdw.scale_exp     = nbl->table_elec_vdw.scale_exp;
-    nbl->table_vdw.formatsize    = nbl->table_elec_vdw.formatsize;
-    nbl->table_vdw.ninteractions = 2;
-    nbl->table_vdw.stride        = nbl->table_vdw.formatsize * nbl->table_vdw.ninteractions;
-    snew_aligned(nbl->table_vdw.data, nbl->table_vdw.stride*(nbl->table_vdw.n+1), 32);
-
-    for (i = 0; i <= nbl->table_elec_vdw.n; i++)
+    snew(nbl->table_elec, 1);
+    nbl->table_elec->interaction   = GMX_TABLE_INTERACTION_ELEC;
+    nbl->table_elec->format        = nbl->table_elec_vdw->format;
+    nbl->table_elec->r             = nbl->table_elec_vdw->r;
+    nbl->table_elec->n             = nbl->table_elec_vdw->n;
+    nbl->table_elec->scale         = nbl->table_elec_vdw->scale;
+    nbl->table_elec->formatsize    = nbl->table_elec_vdw->formatsize;
+    nbl->table_elec->ninteractions = 1;
+    nbl->table_elec->stride        = nbl->table_elec->formatsize * nbl->table_elec->ninteractions;
+    snew_aligned(nbl->table_elec->data, nbl->table_elec->stride*(nbl->table_elec->n+1), 32);
+
+    snew(nbl->table_vdw, 1);
+    nbl->table_vdw->interaction   = GMX_TABLE_INTERACTION_VDWREP_VDWDISP;
+    nbl->table_vdw->format        = nbl->table_elec_vdw->format;
+    nbl->table_vdw->r             = nbl->table_elec_vdw->r;
+    nbl->table_vdw->n             = nbl->table_elec_vdw->n;
+    nbl->table_vdw->scale         = nbl->table_elec_vdw->scale;
+    nbl->table_vdw->formatsize    = nbl->table_elec_vdw->formatsize;
+    nbl->table_vdw->ninteractions = 2;
+    nbl->table_vdw->stride        = nbl->table_vdw->formatsize * nbl->table_vdw->ninteractions;
+    snew_aligned(nbl->table_vdw->data, nbl->table_vdw->stride*(nbl->table_vdw->n+1), 32);
+
+    for (i = 0; i <= nbl->table_elec_vdw->n; i++)
     {
         for (j = 0; j < 4; j++)
         {
-            nbl->table_elec.data[4*i+j] = nbl->table_elec_vdw.data[12*i+j];
+            nbl->table_elec->data[4*i+j] = nbl->table_elec_vdw->data[12*i+j];
         }
         for (j = 0; j < 8; j++)
         {
-            nbl->table_vdw.data[8*i+j] = nbl->table_elec_vdw.data[12*i+4+j];
+            nbl->table_vdw->data[8*i+j] = nbl->table_elec_vdw->data[12*i+4+j];
         }
     }
 }
@@ -1487,11 +1500,6 @@ void forcerec_set_ranges(t_forcerec *fr,
     if (fr->natoms_force_constr > fr->nalloc_force)
     {
         fr->nalloc_force = over_alloc_dd(fr->natoms_force_constr);
-
-        if (fr->bTwinRange)
-        {
-            srenew(fr->f_twin, fr->nalloc_force);
-        }
     }
 
     if (fr->bF_NoVirSum)
@@ -1519,37 +1527,6 @@ static real cutoff_inf(real cutoff)
     return cutoff;
 }
 
-static void make_adress_tf_tables(FILE *fp, const output_env_t oenv,
-                                  t_forcerec *fr, const t_inputrec *ir,
-                                  const char *tabfn, const gmx_mtop_t *mtop,
-                                  matrix     box)
-{
-    char buf[STRLEN];
-    int  i, j;
-
-    if (tabfn == NULL)
-    {
-        gmx_fatal(FARGS, "No thermoforce table file given. Use -tabletf to specify a file\n");
-        return;
-    }
-
-    snew(fr->atf_tabs, ir->adress->n_tf_grps);
-
-    sprintf(buf, "%s", tabfn);
-    for (i = 0; i < ir->adress->n_tf_grps; i++)
-    {
-        j = ir->adress->tf_table_index[i]; /* get energy group index */
-        sprintf(buf + strlen(tabfn) - strlen(ftp2ext(efXVG)) - 1, "tf_%s.%s",
-                *(mtop->groups.grpname[mtop->groups.grps[egcENER].nm_ind[j]]), ftp2ext(efXVG));
-        if (fp)
-        {
-            fprintf(fp, "loading tf table for energygrp index %d from %s\n", ir->adress->tf_table_index[i], buf);
-        }
-        fr->atf_tabs[i] = make_atf_table(fp, oenv, fr, buf, box);
-    }
-
-}
-
 gmx_bool can_use_allvsall(const t_inputrec *ir, gmx_bool bPrintNote, t_commrec *cr, FILE *fp)
 {
     gmx_bool bAllvsAll;
@@ -1643,7 +1620,7 @@ static void pick_nbnxn_kernel_cpu(const t_inputrec gmx_unused *ir,
     *kernel_type = nbnxnk4x4_PlainC;
     *ewald_excl  = ewaldexclTable;
 
-#ifdef GMX_NBNXN_SIMD
+#if GMX_SIMD
     {
 #ifdef GMX_NBNXN_SIMD_4XN
         *kernel_type = nbnxnk4xN_SIMD_4xN;
@@ -1671,7 +1648,7 @@ static void pick_nbnxn_kernel_cpu(const t_inputrec gmx_unused *ir,
          */
         *kernel_type = nbnxnk4xN_SIMD_4xN;
 
-#ifndef GMX_SIMD_HAVE_FMA
+#if !GMX_SIMD_HAVE_FMA
         if (EEL_PME_EWALD(ir->coulombtype) ||
             EVDW_PME(ir->vdwtype))
         {
@@ -1710,8 +1687,7 @@ static void pick_nbnxn_kernel_cpu(const t_inputrec gmx_unused *ir,
          * In single precision, this is faster on Bulldozer.
          */
 #if GMX_SIMD_REAL_WIDTH >= 8 || \
-        (GMX_SIMD_REAL_WIDTH >= 4 && defined GMX_SIMD_HAVE_FMA && !defined GMX_DOUBLE) || \
-        defined GMX_SIMD_IBM_QPX
+        (GMX_SIMD_REAL_WIDTH >= 4 && GMX_SIMD_HAVE_FMA && !GMX_DOUBLE) || GMX_SIMD_IBM_QPX
         *ewald_excl = ewaldexclAnalytical;
 #endif
         if (getenv("GMX_NBNXN_EWALD_TABLE") != NULL)
@@ -1724,7 +1700,7 @@ static void pick_nbnxn_kernel_cpu(const t_inputrec gmx_unused *ir,
         }
 
     }
-#endif /* GMX_NBNXN_SIMD */
+#endif // GMX_SIMD
 }
 
 
@@ -1741,23 +1717,11 @@ const char *lookup_nbnxn_kernel_name(int kernel_type)
             break;
         case nbnxnk4xN_SIMD_4xN:
         case nbnxnk4xN_SIMD_2xNN:
-#ifdef GMX_NBNXN_SIMD
-#if defined GMX_SIMD_X86_SSE2
-            returnvalue = "SSE2";
-#elif defined GMX_SIMD_X86_SSE4_1
-            returnvalue = "SSE4.1";
-#elif defined GMX_SIMD_X86_AVX_128_FMA
-            returnvalue = "AVX_128_FMA";
-#elif defined GMX_SIMD_X86_AVX_256
-            returnvalue = "AVX_256";
-#elif defined GMX_SIMD_X86_AVX2_256
-            returnvalue = "AVX2_256";
-#else
+#if GMX_SIMD
             returnvalue = "SIMD";
-#endif
-#else  /* GMX_NBNXN_SIMD */
+#else  // GMX_SIMD
             returnvalue = "not available";
-#endif /* GMX_NBNXN_SIMD */
+#endif // GMX_SIMD
             break;
         case nbnxnk8x8x8_GPU: returnvalue    = "GPU"; break;
         case nbnxnk8x8x8_PlainC: returnvalue = "plain C"; break;
@@ -1817,8 +1781,8 @@ static void pick_nbnxn_kernel(FILE                *fp,
     {
         fprintf(fp, "\nUsing %s %dx%d non-bonded kernels\n\n",
                 lookup_nbnxn_kernel_name(*kernel_type),
-                nbnxn_kernel_to_ci_size(*kernel_type),
-                nbnxn_kernel_to_cj_size(*kernel_type));
+                nbnxn_kernel_to_cluster_i_size(*kernel_type),
+                nbnxn_kernel_to_cluster_j_size(*kernel_type));
 
         if (nbnxnk4x4_PlainC == *kernel_type ||
             nbnxnk8x8x8_PlainC == *kernel_type)
@@ -1937,7 +1901,7 @@ static void init_ewald_f_table(interaction_const_t *ic,
     sfree_aligned(ic->tabq_vdw_F);
     sfree_aligned(ic->tabq_vdw_V);
 
-    if (ic->eeltype == eelEWALD || EEL_PME(ic->eeltype))
+    if (EEL_PME_EWALD(ic->eeltype))
     {
         /* Create the original table data in FDV0 */
         snew_aligned(ic->tabq_coul_FDV0, ic->tabq_size*4, 32);
@@ -1961,7 +1925,7 @@ void init_interaction_const_tables(FILE                *fp,
                                    interaction_const_t *ic,
                                    real                 rtab)
 {
-    if (ic->eeltype == eelEWALD || EEL_PME(ic->eeltype) || EVDW_PME(ic->vdwtype))
+    if (EEL_PME_EWALD(ic->eeltype) || EVDW_PME(ic->vdwtype))
     {
         init_ewald_f_table(ic, rtab);
 
@@ -1992,9 +1956,9 @@ static void force_switch_constants(real p,
      * 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);
+    sc->c2   =  ((p + 1)*rsw - (p + 4)*rc)/(pow(rc, p + 2)*gmx::square(rc - rsw));
+    sc->c3   = -((p + 1)*rsw - (p + 3)*rc)/(pow(rc, p + 2)*gmx::power3(rc - rsw));
+    sc->cpot = -pow(rc, -p) + p*sc->c2/3*gmx::power3(rc - rsw) + p*sc->c3/4*gmx::power4(rc - rsw);
 }
 
 static void potential_switch_constants(real rsw, real rc,
@@ -2008,9 +1972,9 @@ static void potential_switch_constants(real rsw, real rc,
      * 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);
+    sc->c3 = -10/gmx::power3(rc - rsw);
+    sc->c4 =  15/gmx::power4(rc - rsw);
+    sc->c5 =  -6/gmx::power5(rc - rsw);
 }
 
 /*! \brief Construct interaction constants
@@ -2025,8 +1989,6 @@ init_interaction_const(FILE                       *fp,
                        const t_forcerec           *fr)
 {
     interaction_const_t *ic;
-    const real           minusSix          = -6.0;
-    const real           minusTwelve       = -12.0;
 
     snew(ic, 1);
 
@@ -2038,7 +2000,6 @@ init_interaction_const(FILE                       *fp,
     snew_aligned(ic->tabq_coul_V, 16, 32);
 
     ic->rlist           = fr->rlist;
-    ic->rlistlong       = fr->rlistlong;
 
     /* Lennard-Jones */
     ic->vdwtype         = fr->vdwtype;
@@ -2055,14 +2016,14 @@ init_interaction_const(FILE                       *fp,
     {
         case eintmodPOTSHIFT:
             /* Only shift the potential, don't touch the force */
-            ic->dispersion_shift.cpot = -pow(ic->rvdw, minusSix);
-            ic->repulsion_shift.cpot  = -pow(ic->rvdw, minusTwelve);
+            ic->dispersion_shift.cpot = -1.0/gmx::power6(ic->rvdw);
+            ic->repulsion_shift.cpot  = -1.0/gmx::power12(ic->rvdw);
             if (EVDW_PME(ic->vdwtype))
             {
                 real crc2;
 
-                crc2            = sqr(ic->ewaldcoeff_lj*ic->rvdw);
-                ic->sh_lj_ewald = (exp(-crc2)*(1 + crc2 + 0.5*crc2*crc2) - 1)*pow(ic->rvdw, minusSix);
+                crc2            = gmx::square(ic->ewaldcoeff_lj*ic->rvdw);
+                ic->sh_lj_ewald = (std::exp(-crc2)*(1 + crc2 + 0.5*crc2*crc2) - 1)/gmx::power6(ic->rvdw);
             }
             break;
         case eintmodFORCESWITCH:
@@ -2097,7 +2058,7 @@ init_interaction_const(FILE                       *fp,
 
     if (fr->coulomb_modifier == eintmodPOTSHIFT)
     {
-        ic->sh_ewald = gmx_erfc(ic->ewaldcoeff_q*ic->rcoulomb);
+        ic->sh_ewald = std::erfc(ic->ewaldcoeff_q*ic->rcoulomb);
     }
     else
     {
@@ -2241,7 +2202,10 @@ static void init_nb_verlet(FILE                *fp,
 
             bSimpleList = nbnxn_kernel_pairlist_simple(nbv->grp[i].kernel_type);
 
-            if (bSimpleList && (fr->vdwtype == evdwCUT && (fr->vdw_modifier == eintmodNONE || fr->vdw_modifier == eintmodPOTSHIFT)))
+            if (fr->vdwtype == evdwCUT &&
+                (fr->vdw_modifier == eintmodNONE ||
+                 fr->vdw_modifier == eintmodPOTSHIFT) &&
+                getenv("GMX_NO_LJ_COMB_RULE") == NULL)
             {
                 /* Plain LJ cut-off: we can optimize with combination rules */
                 enbnxninitcombrule = enbnxninitcombruleDETECT;
@@ -2285,7 +2249,7 @@ static void init_nb_verlet(FILE                *fp,
     {
         /* init the NxN GPU data; the last argument tells whether we'll have
          * both local and non-local NB calculation on GPU */
-        nbnxn_gpu_init(fp, &nbv->gpu_nbv,
+        nbnxn_gpu_init(&nbv->gpu_nbv,
                        &fr->hwinfo->gpu_info,
                        fr->gpu_opt,
                        fr->ic,
@@ -2306,7 +2270,7 @@ static void init_nb_verlet(FILE                *fp,
          * texture objects are used), but as this is initialization code, there
          * is no point in complicating things.
          */
-#ifdef GMX_THREAD_MPI
+#if GMX_THREAD_MPI
         if (PAR(cr))
         {
             gmx_barrier(cr);
@@ -2318,9 +2282,9 @@ static void init_nb_verlet(FILE                *fp,
             char *end;
 
             nbv->min_ci_balanced = strtol(env, &end, 10);
-            if (!end || (*end != 0) || nbv->min_ci_balanced <= 0)
+            if (!end || (*end != 0) || nbv->min_ci_balanced < 0)
             {
-                gmx_fatal(FARGS, "Invalid value passed in GMX_NB_MIN_CI=%s, positive integer required", env);
+                gmx_fatal(FARGS, "Invalid value passed in GMX_NB_MIN_CI=%s, non-negative integer required", env);
             }
 
             if (debug)
@@ -2350,7 +2314,6 @@ gmx_bool usingGpu(nonbonded_verlet_t *nbv)
 }
 
 void init_forcerec(FILE              *fp,
-                   const output_env_t oenv,
                    t_forcerec        *fr,
                    t_fcdata          *fcd,
                    const t_inputrec  *ir,
@@ -2358,7 +2321,6 @@ void init_forcerec(FILE              *fp,
                    const t_commrec   *cr,
                    matrix             box,
                    const char        *tabfn,
-                   const char        *tabafn,
                    const char        *tabpfn,
                    const t_filenm    *tabbfnm,
                    const char        *nbpu_opt,
@@ -2371,7 +2333,7 @@ void init_forcerec(FILE              *fp,
     double         dbl;
     const t_block *cgs;
     gmx_bool       bGenericKernelOnly;
-    gmx_bool       bMakeTables, bMakeSeparate14Table, bSomeNormalNbListsAreInUse;
+    gmx_bool       needGroupSchemeTables, bSomeNormalNbListsAreInUse;
     gmx_bool       bFEP_NonBonded;
     int           *nm_ind, egp_flags;
 
@@ -2413,39 +2375,20 @@ void init_forcerec(FILE              *fp,
         fr->n_tpi = 0;
     }
 
-    /* Copy AdResS parameters */
-    if (ir->bAdress)
+    if (ir->coulombtype == eelRF_NEC_UNSUPPORTED)
     {
-        fr->adress_type           = ir->adress->type;
-        fr->adress_const_wf       = ir->adress->const_wf;
-        fr->adress_ex_width       = ir->adress->ex_width;
-        fr->adress_hy_width       = ir->adress->hy_width;
-        fr->adress_icor           = ir->adress->icor;
-        fr->adress_site           = ir->adress->site;
-        fr->adress_ex_forcecap    = ir->adress->ex_forcecap;
-        fr->adress_do_hybridpairs = ir->adress->do_hybridpairs;
-
-
-        snew(fr->adress_group_explicit, ir->adress->n_energy_grps);
-        for (i = 0; i < ir->adress->n_energy_grps; i++)
-        {
-            fr->adress_group_explicit[i] = ir->adress->group_explicit[i];
-        }
+        gmx_fatal(FARGS, "%s electrostatics is no longer supported",
+                  eel_names[ir->coulombtype]);
+    }
 
-        fr->n_adress_tf_grps = ir->adress->n_tf_grps;
-        snew(fr->adress_tf_table_index, fr->n_adress_tf_grps);
-        for (i = 0; i < fr->n_adress_tf_grps; i++)
-        {
-            fr->adress_tf_table_index[i] = ir->adress->tf_table_index[i];
-        }
-        copy_rvec(ir->adress->refs, fr->adress_refs);
+    if (ir->bAdress)
+    {
+        gmx_fatal(FARGS, "AdResS simulations are no longer supported");
     }
-    else
+    if (ir->useTwinRange)
     {
-        fr->adress_type           = eAdressOff;
-        fr->adress_do_hybridpairs = FALSE;
+        gmx_fatal(FARGS, "Twin-range simulations are no longer supported");
     }
-
     /* Copy the user determined parameters */
     fr->userint1  = ir->userint1;
     fr->userint2  = ir->userint2;
@@ -2465,7 +2408,7 @@ void init_forcerec(FILE              *fp,
     if (ir->fepvals->bScCoul)
     {
         fr->sc_alphacoul  = ir->fepvals->sc_alpha;
-        fr->sc_sigma6_min = pow(ir->fepvals->sc_sigma_min, 6);
+        fr->sc_sigma6_min = gmx::power6(ir->fepvals->sc_sigma_min);
     }
     else
     {
@@ -2474,14 +2417,14 @@ void init_forcerec(FILE              *fp,
     }
     fr->sc_power      = ir->fepvals->sc_power;
     fr->sc_r_power    = ir->fepvals->sc_r_power;
-    fr->sc_sigma6_def = pow(ir->fepvals->sc_sigma, 6);
+    fr->sc_sigma6_def = gmx::power6(ir->fepvals->sc_sigma);
 
     env = getenv("GMX_SCSIGMA_MIN");
     if (env != NULL)
     {
         dbl = 0;
         sscanf(env, "%20lf", &dbl);
-        fr->sc_sigma6_min = pow(dbl, 6);
+        fr->sc_sigma6_min = gmx::power6(dbl);
         if (fp)
         {
             fprintf(fp, "Setting the minimum soft core sigma to %g nm\n", dbl);
@@ -2640,7 +2583,6 @@ void init_forcerec(FILE              *fp,
     copy_rvec(ir->posres_com, fr->posres_com);
     copy_rvec(ir->posres_comB, fr->posres_comB);
     fr->rlist                    = cutoff_inf(ir->rlist);
-    fr->rlistlong                = cutoff_inf(ir->rlistlong);
     fr->eeltype                  = ir->coulombtype;
     fr->vdwtype                  = ir->vdwtype;
     fr->ljpme_combination_rule   = ir->ljpme_combination_rule;
@@ -2657,7 +2599,6 @@ void init_forcerec(FILE              *fp,
 
         case eelRF:
         case eelGRF:
-        case eelRF_NEC:
             fr->nbkernel_elec_interaction = GMX_NBKERNEL_ELEC_REACTIONFIELD;
             break;
 
@@ -2725,8 +2666,7 @@ void init_forcerec(FILE              *fp,
     fr->rcoulomb         = cutoff_inf(ir->rcoulomb);
     fr->rcoulomb_switch  = ir->rcoulomb_switch;
 
-    fr->bTwinRange = fr->rlistlong > fr->rlist;
-    fr->bEwald     = (EEL_PME(fr->eeltype) || fr->eeltype == eelEWALD);
+    fr->bEwald     = EEL_PME_EWALD(fr->eeltype);
 
     fr->reppow     = mtop->ffparams.reppow;
 
@@ -2785,8 +2725,10 @@ void init_forcerec(FILE              *fp,
 
         if (fp)
         {
-            fprintf(fp, "Table routines are used for coulomb: %s\n", bool_names[fr->bcoultab]);
-            fprintf(fp, "Table routines are used for vdw:     %s\n", bool_names[fr->bvdwtab ]);
+            fprintf(fp, "Table routines are used for coulomb: %s\n",
+                    gmx::boolToString(fr->bcoultab));
+            fprintf(fp, "Table routines are used for vdw:     %s\n",
+                    gmx::boolToString(fr->bvdwtab));
         }
 
         if (fr->bvdwtab == TRUE)
@@ -2880,8 +2822,7 @@ void init_forcerec(FILE              *fp,
     fr->bF_NoVirSum = (EEL_FULL(fr->eeltype) || EVDW_PME(fr->vdwtype) ||
                        gmx_mtop_ftype_count(mtop, F_POSRES) > 0 ||
                        gmx_mtop_ftype_count(mtop, F_FBPOSRES) > 0 ||
-                       IR_ELEC_FIELD(*ir) ||
-                       (fr->adress_icor != eAdressICOff)
+                       inputrecElecField(ir)
                        );
 
     if (fr->cutoff_scheme == ecutsGROUP &&
@@ -2952,6 +2893,7 @@ void init_forcerec(FILE              *fp,
     }
 
     fr->eDispCorr = ir->eDispCorr;
+    fr->numAtomsForDispersionCorrection = mtop->natoms;
     if (ir->eDispCorr != edispcNO)
     {
         set_avcsixtwelve(fp, fr, mtop);
@@ -3000,14 +2942,14 @@ void init_forcerec(FILE              *fp,
     /* Generate the GB table if needed */
     if (fr->bGB)
     {
-#ifdef GMX_DOUBLE
+#if GMX_DOUBLE
         fr->gbtabscale = 2000;
 #else
         fr->gbtabscale = 500;
 #endif
 
         fr->gbtabr = 100;
-        fr->gbtab  = make_gb_table(oenv, fr);
+        fr->gbtab  = make_gb_table(fr);
 
         init_gb(&fr->born, fr, ir, mtop, ir->gb_algorithm);
 
@@ -3040,37 +2982,23 @@ void init_forcerec(FILE              *fp,
     /*This now calculates sum for q and c6*/
     set_chargesum(fp, fr, mtop);
 
-    /* if we are using LR electrostatics, and they are tabulated,
-     * the tables will contain modified coulomb interactions.
-     * Since we want to use the non-shifted ones for 1-4
-     * coulombic interactions, we must have an extra set of tables.
-     */
-
-    /* Construct tables.
-     * A little unnecessary to make both vdw and coul tables sometimes,
-     * but what the heck... */
-
-    bMakeTables = fr->bcoultab || fr->bvdwtab || fr->bEwald ||
-        (ir->eDispCorr != edispcNO && ir_vdw_switched(ir));
-
-    bMakeSeparate14Table = ((!bMakeTables || fr->eeltype != eelCUT || fr->vdwtype != evdwCUT ||
-                             fr->coulomb_modifier != eintmodNONE ||
-                             fr->vdw_modifier != eintmodNONE ||
-                             fr->bBHAM || fr->bEwald) &&
-                            (gmx_mtop_ftype_count(mtop, F_LJ14) > 0 ||
-                             gmx_mtop_ftype_count(mtop, F_LJC14_Q) > 0 ||
-                             gmx_mtop_ftype_count(mtop, F_LJC_PAIRS_NB) > 0));
+    /* Construct tables for the group scheme. A little unnecessary to
+     * make both vdw and coul tables sometimes, but what the
+     * heck. Note that both cutoff schemes construct Ewald tables in
+     * init_interaction_const_tables. */
+    needGroupSchemeTables = (ir->cutoff_scheme == ecutsGROUP &&
+                             (fr->bcoultab || fr->bvdwtab));
 
     negp_pp   = ir->opts.ngener - ir->nwall;
     negptable = 0;
-    if (!bMakeTables)
+    if (!needGroupSchemeTables)
     {
         bSomeNormalNbListsAreInUse = TRUE;
         fr->nnblists               = 1;
     }
     else
     {
-        bSomeNormalNbListsAreInUse = (ir->eDispCorr != edispcNO);
+        bSomeNormalNbListsAreInUse = FALSE;
         for (egi = 0; egi < negp_pp; egi++)
         {
             for (egj = egi; egj < negp_pp; egj++)
@@ -3103,33 +3031,20 @@ void init_forcerec(FILE              *fp,
         }
     }
 
-    if (ir->adress)
-    {
-        fr->nnblists *= 2;
-    }
-
     snew(fr->nblists, fr->nnblists);
 
     /* This code automatically gives table length tabext without cut-off's,
      * in that case grompp should already have checked that we do not need
      * normal tables and we only generate tables for 1-4 interactions.
      */
-    rtab = ir->rlistlong + ir->tabext;
+    rtab = ir->rlist + ir->tabext;
 
-    if (bMakeTables)
+    if (needGroupSchemeTables)
     {
         /* make tables for ordinary interactions */
         if (bSomeNormalNbListsAreInUse)
         {
-            make_nbf_tables(fp, oenv, fr, rtab, cr, tabfn, NULL, NULL, &fr->nblists[0]);
-            if (ir->adress)
-            {
-                make_nbf_tables(fp, oenv, fr, rtab, cr, tabfn, NULL, NULL, &fr->nblists[fr->nnblists/2]);
-            }
-            if (!bMakeSeparate14Table)
-            {
-                fr->tab14 = fr->nblists[0].table_elec_vdw;
-            }
+            make_nbf_tables(fp, fr, rtab, tabfn, NULL, NULL, &fr->nblists[0]);
             m = 1;
         }
         else
@@ -3152,17 +3067,10 @@ void init_forcerec(FILE              *fp,
                             fr->gid2nblists[GID(egi, egj, ir->opts.ngener)] = m;
                         }
                         /* Read the table file with the two energy groups names appended */
-                        make_nbf_tables(fp, oenv, fr, rtab, cr, tabfn,
+                        make_nbf_tables(fp, fr, rtab, tabfn,
                                         *mtop->groups.grpname[nm_ind[egi]],
                                         *mtop->groups.grpname[nm_ind[egj]],
                                         &fr->nblists[m]);
-                        if (ir->adress)
-                        {
-                            make_nbf_tables(fp, oenv, fr, rtab, cr, tabfn,
-                                            *mtop->groups.grpname[nm_ind[egi]],
-                                            *mtop->groups.grpname[nm_ind[egj]],
-                                            &fr->nblists[fr->nnblists/2+m]);
-                        }
                         m++;
                     }
                     else if (fr->nnblists > 1)
@@ -3173,47 +3081,31 @@ void init_forcerec(FILE              *fp,
             }
         }
     }
-    else if ((fr->eDispCorr != edispcNO) &&
-             ((fr->vdw_modifier == eintmodPOTSWITCH) ||
-              (fr->vdw_modifier == eintmodFORCESWITCH) ||
-              (fr->vdw_modifier == eintmodPOTSHIFT)))
-    {
-        /* Tables might not be used for the potential modifier interactions per se, but
-         * we still need them to evaluate switch/shift dispersion corrections in this case.
-         */
-        make_nbf_tables(fp, oenv, fr, rtab, cr, tabfn, NULL, NULL, &fr->nblists[0]);
-    }
 
-    if (bMakeSeparate14Table)
+    /* Tables might not be used for the potential modifier
+     * interactions per se, but we still need them to evaluate
+     * switch/shift dispersion corrections in this case. */
+    if (fr->eDispCorr != edispcNO)
     {
-        /* generate extra tables with plain Coulomb for 1-4 interactions only */
-        fr->tab14 = make_tables(fp, oenv, fr, MASTER(cr), tabpfn, rtab,
-                                GMX_MAKETABLES_14ONLY);
+        fr->dispersionCorrectionTable = makeDispersionCorrectionTable(fp, fr, rtab, tabfn);
     }
 
-    /* Read AdResS Thermo Force table if needed */
-    if (fr->adress_icor == eAdressICThermoForce)
+    /* We want to use unmodified tables for 1-4 coulombic
+     * interactions, so we must in general have an extra set of
+     * tables. */
+    if (gmx_mtop_ftype_count(mtop, F_LJ14) > 0 ||
+        gmx_mtop_ftype_count(mtop, F_LJC14_Q) > 0 ||
+        gmx_mtop_ftype_count(mtop, F_LJC_PAIRS_NB) > 0)
     {
-        /* old todo replace */
-
-        if (ir->adress->n_tf_grps > 0)
-        {
-            make_adress_tf_tables(fp, oenv, fr, ir, tabfn, mtop, box);
-
-        }
-        else
-        {
-            /* load the default table */
-            snew(fr->atf_tabs, 1);
-            fr->atf_tabs[DEFAULT_TF_TABLE] = make_atf_table(fp, oenv, fr, tabafn, box);
-        }
+        fr->pairsTable = make_tables(fp, fr, tabpfn, rtab,
+                                     GMX_MAKETABLES_14ONLY);
     }
 
     /* Wall stuff */
     fr->nwall = ir->nwall;
     if (ir->nwall && ir->wall_type == ewtTABLE)
     {
-        make_wall_tables(fp, oenv, ir, tabfn, &mtop->groups, fr);
+        make_wall_tables(fp, ir, tabfn, &mtop->groups, fr);
     }
 
     if (fcd && tabbfnm)
@@ -3280,23 +3172,21 @@ void init_forcerec(FILE              *fp,
     fr->timesteps = 0;
 
     /* Initialize neighbor search */
-    init_ns(fp, cr, &fr->ns, fr, mtop);
+    snew(fr->ns, 1);
+    init_ns(fp, cr, fr->ns, fr, mtop);
 
     if (cr->duty & DUTY_PP)
     {
         gmx_nonbonded_setup(fr, bGenericKernelOnly);
-        /*
-           if (ir->bAdress)
-            {
-                gmx_setup_adress_kernels(fp,bGenericKernelOnly);
-            }
-         */
     }
 
     /* Initialize the thread working data for bonded interactions */
-    init_bonded_threading(fp, fr, mtop->groups.grps[egcENER].nr);
+    init_bonded_threading(fp, mtop->groups.grps[egcENER].nr,
+                          &fr->bonded_threading);
 
-    snew(fr->excl_load, fr->nthreads+1);
+    fr->nthread_ewc = gmx_omp_nthreads_get(emntBonded);
+    snew(fr->ewc_t, fr->nthread_ewc);
+    snew(fr->excl_load, fr->nthread_ewc + 1);
 
     /* fr->ic is used both by verlet and group kernels (to some extent) now */
     init_interaction_const(fp, &fr->ic, fr);
@@ -3304,9 +3194,15 @@ void init_forcerec(FILE              *fp,
 
     if (fr->cutoff_scheme == ecutsVERLET)
     {
-        if (ir->rcoulomb != ir->rvdw)
+        // We checked the cut-offs in grompp, but double-check here.
+        // We have PME+LJcutoff kernels for rcoulomb>rvdw.
+        if (EEL_PME_EWALD(ir->coulombtype) && ir->vdwtype == eelCUT)
+        {
+            GMX_RELEASE_ASSERT(ir->rcoulomb >= ir->rvdw, "With Verlet lists and PME we should have rcoulomb>=rvdw");
+        }
+        else
         {
-            gmx_fatal(FARGS, "With Verlet lists rcoulomb and rvdw should be identical");
+            GMX_RELEASE_ASSERT(ir->rcoulomb == ir->rvdw, "With Verlet lists and no PME rcoulomb and rvdw should be identical");
         }
 
         init_nb_verlet(fp, &fr->nbv, bFEP_NonBonded, ir, fr, cr, nbpu_opt);
@@ -3320,7 +3216,7 @@ void init_forcerec(FILE              *fp,
 
 #define pr_real(fp, r) fprintf(fp, "%s: %e\n",#r, r)
 #define pr_int(fp, i)  fprintf((fp), "%s: %d\n",#i, i)
-#define pr_bool(fp, b) fprintf((fp), "%s: %s\n",#b, bool_names[b])
+#define pr_bool(fp, b) fprintf((fp), "%s: %s\n",#b, gmx::boolToString(b))
 
 void pr_forcerec(FILE *fp, t_forcerec *fr)
 {
@@ -3330,12 +3226,11 @@ void pr_forcerec(FILE *fp, t_forcerec *fr)
     pr_real(fp, fr->rcoulomb);
     pr_real(fp, fr->fudgeQQ);
     pr_bool(fp, fr->bGrid);
-    pr_bool(fp, fr->bTwinRange);
     /*pr_int(fp,fr->cg0);
        pr_int(fp,fr->hcg);*/
     for (i = 0; i < fr->nnblists; i++)
     {
-        pr_int(fp, fr->nblists[i].table_elec_vdw.n);
+        pr_int(fp, fr->nblists[i].table_elec_vdw->n);
     }
     pr_real(fp, fr->rcoulomb_switch);
     pr_real(fp, fr->rcoulomb);
@@ -3367,9 +3262,9 @@ void forcerec_set_excl_load(t_forcerec           *fr,
     fr->excl_load[0] = 0;
     n                = 0;
     i                = 0;
-    for (t = 1; t <= fr->nthreads; t++)
+    for (t = 1; t <= fr->nthread_ewc; t++)
     {
-        ntarget = (ntot*t)/fr->nthreads;
+        ntarget = (ntot*t)/fr->nthread_ewc;
         while (i < top->excls.nr && n < ntarget)
         {
             for (j = ind[i]; j < ind[i+1]; j++)
@@ -3405,14 +3300,20 @@ void free_gpu_resources(const t_forcerec     *fr,
     {
         /* free nbnxn data in GPU memory */
         nbnxn_gpu_free(fr->nbv->gpu_nbv);
+        /* stop the GPU profiler (only CUDA) */
+        stopGpuProfiler();
 
         /* With tMPI we need to wait for all ranks to finish deallocation before
-         * destroying the context in free_gpu() as some ranks may be sharing
+         * destroying the CUDA context in free_gpu() as some tMPI ranks may be sharing
          * GPU and context.
+         *
+         * This is not a concern in OpenCL where we use one context per rank which
+         * is freed in nbnxn_gpu_free().
+         *
          * Note: as only PP ranks need to free GPU resources, so it is safe to
          * not call the barrier on PME ranks.
          */
-#ifdef GMX_THREAD_MPI
+#if GMX_THREAD_MPI
         if (PAR(cr))
         {
             gmx_barrier(cr);