d8ad10e2cc5d85854f1402b013453d46b814a211
[alexxy/gromacs.git] / src / gromacs / tables / forcetable.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
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,2021, 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.
11  *
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.
16  *
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.
21  *
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.
26  *
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.
34  *
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.
37  */
38 #include "gmxpre.h"
39
40 #include "forcetable.h"
41
42 #include <cmath>
43
44 #include "gromacs/fileio/xvgr.h"
45 #include "gromacs/math/functions.h"
46 #include "gromacs/math/multidimarray.h"
47 #include "gromacs/math/units.h"
48 #include "gromacs/math/utilities.h"
49 #include "gromacs/mdspan/extensions.h"
50 #include "gromacs/mdtypes/fcdata.h"
51 #include "gromacs/mdtypes/interaction_const.h"
52 #include "gromacs/utility/arrayref.h"
53 #include "gromacs/utility/cstringutil.h"
54 #include "gromacs/utility/fatalerror.h"
55 #include "gromacs/utility/futil.h"
56
57 /* All the possible (implemented) table functions */
58 enum
59 {
60     etabLJ6,
61     etabLJ12,
62     etabLJ6Shift,
63     etabLJ12Shift,
64     etabShift,
65     etabRF,
66     etabRF_ZERO,
67     etabCOUL,
68     etabEwald,
69     etabEwaldSwitch,
70     etabEwaldUser,
71     etabEwaldUserSwitch,
72     etabLJ6Ewald,
73     etabLJ6Switch,
74     etabLJ12Switch,
75     etabCOULSwitch,
76     etabEXPMIN,
77     etabUSER,
78     etabNR
79 };
80
81 /** Evaluates to true if the table type contains user data. */
82 #define ETAB_USER(e) ((e) == etabUSER || (e) == etabEwaldUser || (e) == etabEwaldUserSwitch)
83
84 typedef struct
85 {
86     const char* name;
87     gmx_bool    bCoulomb;
88 } t_tab_props;
89
90 /* This structure holds name and a flag that tells whether
91    this is a Coulomb type funtion */
92 static const t_tab_props tprops[etabNR] = {
93     { "LJ6", FALSE },         { "LJ12", FALSE },      { "LJ6Shift", FALSE },
94     { "LJ12Shift", FALSE },   { "Shift", TRUE },      { "RF", TRUE },
95     { "RF-zero", TRUE },      { "COUL", TRUE },       { "Ewald", TRUE },
96     { "Ewald-Switch", TRUE }, { "Ewald-User", TRUE }, { "Ewald-User-Switch", TRUE },
97     { "LJ6Ewald", FALSE },    { "LJ6Switch", FALSE }, { "LJ12Switch", FALSE },
98     { "COULSwitch", TRUE },   { "EXPMIN", FALSE },    { "USER", FALSE },
99 };
100
101 struct t_tabledata
102 {
103     t_tabledata() = default;
104     t_tabledata(int n, int firstTableNum, double scale, bool bAlloc);
105     int                 nx;
106     int                 nx0;
107     double              tabscale;
108     std::vector<double> x;
109     std::vector<double> v;
110     std::vector<double> f;
111 };
112
113 double v_q_ewald_lr(double beta, double r)
114 {
115     if (r == 0)
116     {
117         return beta * 2 / sqrt(M_PI);
118     }
119     else
120     {
121         return std::erf(beta * r) / r;
122     }
123 }
124
125 double v_lj_ewald_lr(double beta, double r)
126 {
127     double br, br2, br4, r6, factor;
128     if (r == 0)
129     {
130         return gmx::power6(beta) / 6;
131     }
132     else
133     {
134         br     = beta * r;
135         br2    = br * br;
136         br4    = br2 * br2;
137         r6     = gmx::power6(r);
138         factor = (1.0 - std::exp(-br2) * (1 + br2 + 0.5 * br4)) / r6;
139         return factor;
140     }
141 }
142
143 EwaldCorrectionTables generateEwaldCorrectionTables(const int    numPoints,
144                                                     const double tableScaling,
145                                                     const real   beta,
146                                                     real_space_grid_contribution_computer v_lr)
147 {
148     real     tab_max;
149     int      i, i_inrange;
150     double   dc, dc_new;
151     gmx_bool bOutOfRange;
152     double   v_r0, v_r1, v_inrange, vi, a0, a1, a2dx;
153     double   x_r0;
154
155     /* This function is called using either v_ewald_lr or v_lj_ewald_lr as a function argument
156      * depending on wether we should create electrostatic or Lennard-Jones Ewald tables.
157      */
158
159     if (numPoints < 2)
160     {
161         gmx_fatal(FARGS, "Can not make a spline table with less than 2 points");
162     }
163
164     const double dx = 1 / tableScaling;
165
166     EwaldCorrectionTables tables;
167     tables.scale = tableScaling;
168     tables.tableF.resize(numPoints);
169     tables.tableV.resize(numPoints);
170     tables.tableFDV0.resize(numPoints * 4);
171     gmx::ArrayRef<real> table_f    = tables.tableF;
172     gmx::ArrayRef<real> table_v    = tables.tableV;
173     gmx::ArrayRef<real> table_fdv0 = tables.tableFDV0;
174
175     /* We need some margin to be able to divide table values by r
176      * in the kernel and also to do the integration arithmetics
177      * without going out of range. Furthemore, we divide by dx below.
178      */
179     tab_max = GMX_REAL_MAX * 0.0001;
180
181     /* This function produces a table with:
182      * maximum energy error: V'''/(6*12*sqrt(3))*dx^3
183      * maximum force error:  V'''/(6*4)*dx^2
184      * The rms force error is the max error times 1/sqrt(5)=0.45.
185      */
186
187     bOutOfRange = FALSE;
188     i_inrange   = numPoints;
189     v_inrange   = 0;
190     dc          = 0;
191     for (i = numPoints - 1; i >= 0; i--)
192     {
193         x_r0 = i * dx;
194
195         v_r0 = (*v_lr)(beta, x_r0);
196
197         if (!bOutOfRange)
198         {
199             i_inrange = i;
200             v_inrange = v_r0;
201
202             vi = v_r0;
203         }
204         else
205         {
206             /* Linear continuation for the last point in range */
207             vi = v_inrange - dc * (i - i_inrange) * dx;
208         }
209
210         table_v[i] = vi;
211
212         if (i == 0)
213         {
214             continue;
215         }
216
217         /* Get the potential at table point i-1 */
218         v_r1 = (*v_lr)(beta, (i - 1) * dx);
219
220         if (v_r1 != v_r1 || v_r1 < -tab_max || v_r1 > tab_max)
221         {
222             bOutOfRange = TRUE;
223         }
224
225         if (!bOutOfRange)
226         {
227             /* Calculate the average second derivative times dx over interval i-1 to i.
228              * Using the function values at the end points and in the middle.
229              */
230             a2dx = (v_r0 + v_r1 - 2 * (*v_lr)(beta, x_r0 - 0.5 * dx)) / (0.25 * dx);
231             /* Set the derivative of the spline to match the difference in potential
232              * over the interval plus the average effect of the quadratic term.
233              * This is the essential step for minimizing the error in the force.
234              */
235             dc = (v_r0 - v_r1) / dx + 0.5 * a2dx;
236         }
237
238         if (i == numPoints - 1)
239         {
240             /* Fill the table with the force, minus the derivative of the spline */
241             table_f[i] = -dc;
242         }
243         else
244         {
245             /* tab[i] will contain the average of the splines over the two intervals */
246             table_f[i] += -0.5 * dc;
247         }
248
249         if (!bOutOfRange)
250         {
251             /* Make spline s(x) = a0 + a1*(x - xr) + 0.5*a2*(x - xr)^2
252              * matching the potential at the two end points
253              * and the derivative dc at the end point xr.
254              */
255             a0   = v_r0;
256             a1   = dc;
257             a2dx = (a1 * dx + v_r1 - a0) * 2 / dx;
258
259             /* Set dc to the derivative at the next point */
260             dc_new = a1 - a2dx;
261
262             if (dc_new != dc_new || dc_new < -tab_max || dc_new > tab_max)
263             {
264                 bOutOfRange = TRUE;
265             }
266             else
267             {
268                 dc = dc_new;
269             }
270         }
271
272         table_f[(i - 1)] = -0.5 * dc;
273     }
274     /* Currently the last value only contains half the force: double it */
275     table_f[0] *= 2;
276
277     if (!table_fdv0.empty())
278     {
279         /* Copy to FDV0 table too. Allocation occurs in forcerec.c,
280          * init_ewald_f_table().
281          */
282         for (i = 0; i < numPoints - 1; i++)
283         {
284             table_fdv0[4 * i]     = table_f[i];
285             table_fdv0[4 * i + 1] = table_f[i + 1] - table_f[i];
286             table_fdv0[4 * i + 2] = table_v[i];
287             table_fdv0[4 * i + 3] = 0.0;
288         }
289         const int lastPoint           = numPoints - 1;
290         table_fdv0[4 * lastPoint]     = table_f[lastPoint];
291         table_fdv0[4 * lastPoint + 1] = -table_f[lastPoint];
292         table_fdv0[4 * lastPoint + 2] = table_v[lastPoint];
293         table_fdv0[4 * lastPoint + 3] = 0.0;
294     }
295
296     return tables;
297 }
298
299 /* Returns the spacing for a function using the maximum of
300  * the third derivative, x_scale (unit 1/length)
301  * and function tolerance.
302  */
303 static double spline3_table_scale(double third_deriv_max, double x_scale, double func_tol)
304 {
305     double deriv_tol;
306     double sc_deriv, sc_func;
307
308     /* Force tolerance: single precision accuracy */
309     deriv_tol = GMX_FLOAT_EPS;
310     sc_deriv  = sqrt(third_deriv_max / (6 * 4 * deriv_tol * x_scale)) * x_scale;
311
312     /* Don't try to be more accurate on energy than the precision */
313     func_tol = std::max(func_tol, static_cast<double>(GMX_REAL_EPS));
314     sc_func  = std::cbrt(third_deriv_max / (6 * 12 * std::sqrt(3.0) * func_tol)) * x_scale;
315
316     return std::max(sc_deriv, sc_func);
317 }
318
319 /* The scale (1/spacing) for third order spline interpolation
320  * of the Ewald mesh contribution which needs to be subtracted
321  * from the non-bonded interactions.
322  * Since there is currently only one spacing for Coulomb and LJ,
323  * the finest spacing is used if both Ewald types are present.
324  *
325  * Note that we could also implement completely separate tables
326  * for Coulomb and LJ Ewald, each with their own spacing.
327  * The current setup with the same spacing can provide slightly
328  * faster kernels with both Coulomb and LJ Ewald, especially
329  * when interleaving both tables (currently not implemented).
330  */
331 real ewald_spline3_table_scale(const interaction_const_t& ic,
332                                const bool                 generateCoulombTables,
333                                const bool                 generateVdwTables)
334 {
335     GMX_RELEASE_ASSERT(!generateCoulombTables || EEL_PME_EWALD(ic.eeltype),
336                        "Can only use tables with Ewald");
337     GMX_RELEASE_ASSERT(!generateVdwTables || EVDW_PME(ic.vdwtype), "Can only use tables with Ewald");
338
339     real sc = 0;
340
341     if (generateCoulombTables)
342     {
343         GMX_RELEASE_ASSERT(ic.ewaldcoeff_q > 0, "The Ewald coefficient shoule be positive");
344
345         double erf_x_d3 = 1.0522; /* max of (erf(x)/x)''' */
346         double etol;
347         real   sc_q;
348
349         /* Energy tolerance: 0.1 times the cut-off jump */
350         etol = 0.1 * std::erfc(ic.ewaldcoeff_q * ic.rcoulomb);
351
352         sc_q = spline3_table_scale(erf_x_d3, ic.ewaldcoeff_q, etol);
353
354         if (debug)
355         {
356             fprintf(debug, "Ewald Coulomb quadratic spline table spacing: %f nm\n", 1 / sc_q);
357         }
358
359         sc = std::max(sc, sc_q);
360     }
361
362     if (generateVdwTables)
363     {
364         GMX_RELEASE_ASSERT(ic.ewaldcoeff_lj > 0, "The Ewald coefficient shoule be positive");
365
366         double func_d3 = 0.42888; /* max of (x^-6 (1 - exp(-x^2)(1+x^2+x^4/2)))''' */
367         double xrc2, etol;
368         real   sc_lj;
369
370         /* Energy tolerance: 0.1 times the cut-off jump */
371         xrc2 = gmx::square(ic.ewaldcoeff_lj * ic.rvdw);
372         etol = 0.1 * std::exp(-xrc2) * (1 + xrc2 + xrc2 * xrc2 / 2.0);
373
374         sc_lj = spline3_table_scale(func_d3, ic.ewaldcoeff_lj, etol);
375
376         if (debug)
377         {
378             fprintf(debug, "Ewald LJ quadratic spline table spacing: %f nm\n", 1 / sc_lj);
379         }
380
381         sc = std::max(sc, sc_lj);
382     }
383
384     return sc;
385 }
386
387 static void copy2table(int                         n,
388                        int                         offset,
389                        int                         stride,
390                        gmx::ArrayRef<const double> x,
391                        gmx::ArrayRef<const double> Vtab,
392                        gmx::ArrayRef<const double> Ftab,
393                        real                        scalefactor,
394                        gmx::ArrayRef<real>         dest)
395 {
396     /* Use double prec. for the intermediary variables
397      * and temporary x/vtab/vtab2 data to avoid unnecessary
398      * loss of precision.
399      */
400     int    i, nn0;
401     double F, G, H, h;
402
403     h = 0;
404     for (i = 0; (i < n); i++)
405     {
406         if (i < n - 1)
407         {
408             h = x[i + 1] - x[i];
409             F = -Ftab[i] * h;
410             G = 3 * (Vtab[i + 1] - Vtab[i]) + (Ftab[i + 1] + 2 * Ftab[i]) * h;
411             H = -2 * (Vtab[i + 1] - Vtab[i]) - (Ftab[i + 1] + Ftab[i]) * h;
412         }
413         else
414         {
415             /* Fill the last entry with a linear potential,
416              * this is mainly for rounding issues with angle and dihedral potentials.
417              */
418             F = -Ftab[i] * h;
419             G = 0;
420             H = 0;
421         }
422         nn0           = offset + i * stride;
423         dest[nn0]     = scalefactor * Vtab[i];
424         dest[nn0 + 1] = scalefactor * F;
425         dest[nn0 + 2] = scalefactor * G;
426         dest[nn0 + 3] = scalefactor * H;
427     }
428 }
429
430 t_tabledata::t_tabledata(int n, int firstTableNum, double scale, bool bAlloc) :
431     nx(n), nx0(firstTableNum), tabscale(scale)
432 {
433     if (bAlloc)
434     {
435         x.resize(nx);
436         v.resize(nx);
437         f.resize(nx);
438     }
439 }
440
441 static void spline_forces(int nx, double h, const double v[], gmx_bool bS3, gmx_bool bE3, double f[])
442 {
443     int    start, end, i;
444     double v3, b_s, b_e, b;
445     double beta;
446
447     /* Formulas can be found in:
448      * H.J.C. Berendsen, Simulating the Physical World, Cambridge 2007
449      */
450
451     if (nx < 4 && (bS3 || bE3))
452     {
453         gmx_fatal(FARGS,
454                   "Can not generate splines with third derivative boundary conditions with less "
455                   "than 4 (%d) points",
456                   nx);
457     }
458
459     /* To make life easy we initially set the spacing to 1
460      * and correct for this at the end.
461      */
462     if (bS3)
463     {
464         /* Fit V''' at the start */
465         v3 = v[3] - 3 * v[2] + 3 * v[1] - v[0];
466         if (debug)
467         {
468             fprintf(debug, "The left third derivative is %g\n", v3 / (h * h * h));
469         }
470         b_s   = 2 * (v[1] - v[0]) + v3 / 6;
471         start = 0;
472
473         if (FALSE)
474         {
475             /* Fit V'' at the start */
476             real v2;
477
478             v2 = -v[3] + 4 * v[2] - 5 * v[1] + 2 * v[0];
479             /* v2  = v[2] - 2*v[1] + v[0]; */
480             if (debug)
481             {
482                 fprintf(debug, "The left second derivative is %g\n", v2 / (h * h));
483             }
484             b_s   = 3 * (v[1] - v[0]) - v2 / 2;
485             start = 0;
486         }
487     }
488     else
489     {
490         b_s   = 3 * (v[2] - v[0]) + f[0] * h;
491         start = 1;
492     }
493     if (bE3)
494     {
495         /* Fit V''' at the end */
496         v3 = v[nx - 1] - 3 * v[nx - 2] + 3 * v[nx - 3] - v[nx - 4];
497         if (debug)
498         {
499             fprintf(debug, "The right third derivative is %g\n", v3 / (h * h * h));
500         }
501         b_e = 2 * (v[nx - 1] - v[nx - 2]) + v3 / 6;
502         end = nx;
503     }
504     else
505     {
506         /* V'=0 at the end */
507         b_e = 3 * (v[nx - 1] - v[nx - 3]) + f[nx - 1] * h;
508         end = nx - 1;
509     }
510
511     std::vector<double> gamma(nx);
512     beta = (bS3 ? 1 : 4);
513
514     /* For V'' fitting */
515     /* beta = (bS3 ? 2 : 4); */
516
517     f[start] = b_s / beta;
518     for (i = start + 1; i < end; i++)
519     {
520         gamma[i] = 1 / beta;
521         beta     = 4 - gamma[i];
522         b        = 3 * (v[i + 1] - v[i - 1]);
523         f[i]     = (b - f[i - 1]) / beta;
524     }
525     gamma[end - 1] = 1 / beta;
526     beta           = (bE3 ? 1 : 4) - gamma[end - 1];
527     f[end - 1]     = (b_e - f[end - 2]) / beta;
528
529     for (i = end - 2; i >= start; i--)
530     {
531         f[i] -= gamma[i + 1] * f[i + 1];
532     }
533
534     /* Correct for the minus sign and the spacing */
535     for (i = start; i < end; i++)
536     {
537         f[i] = -f[i] / h;
538     }
539 }
540
541 static void set_forces(FILE* fp, int angle, int nx, double h, double v[], double f[], int table)
542 {
543     int start, end;
544
545     if (angle == 2)
546     {
547         gmx_fatal(FARGS, "Force generation for dihedral tables is not (yet) implemented");
548     }
549
550     start = 0;
551     while (v[start] == 0)
552     {
553         start++;
554     }
555
556     end = nx;
557     while (v[end - 1] == 0)
558     {
559         end--;
560     }
561     if (end > nx - 2)
562     {
563         end = nx;
564     }
565     else
566     {
567         end++;
568     }
569
570     if (fp)
571     {
572         fprintf(fp,
573                 "Generating forces for table %d, boundary conditions: V''' at %g, %s at %g\n",
574                 table + 1,
575                 start * h,
576                 end == nx ? "V'''" : "V'=0",
577                 (end - 1) * h);
578     }
579     spline_forces(end - start, h, v + start, TRUE, end == nx, f + start);
580 }
581
582 static std::vector<t_tabledata> read_tables(FILE* fp, const char* filename, int ntab, int angle)
583 {
584     char     buf[STRLEN];
585     double   start, end, dx0, dx1, ssd, vm, vp, f, numf;
586     int      k, i, nx0 = 0, nny, ns;
587     gmx_bool bAllZero, bZeroV, bZeroF;
588     double   tabscale;
589
590     nny               = 2 * ntab + 1;
591     std::string libfn = gmx::findLibraryFile(filename);
592     gmx::MultiDimArray<std::vector<double>, gmx::dynamicExtents2D> xvgData    = readXvgData(libfn);
593     int                                                            numColumns = xvgData.extent(0);
594     if (numColumns != nny)
595     {
596         gmx_fatal(FARGS, "Trying to read file %s, but nr columns = %d, should be %d", libfn.c_str(), numColumns, nny);
597     }
598     int numRows = xvgData.extent(1);
599
600     const auto& yy = xvgData.asView();
601     if (angle == 0)
602     {
603         if (yy[0][0] != 0.0)
604         {
605             gmx_fatal(FARGS,
606                       "The first distance in file %s is %f nm instead of %f nm",
607                       libfn.c_str(),
608                       yy[0][0],
609                       0.0);
610         }
611     }
612     else
613     {
614         if (angle == 1)
615         {
616             start = 0.0;
617         }
618         else
619         {
620             start = -180.0;
621         }
622         end = 180.0;
623         if (yy[0][0] != start || yy[0][numRows - 1] != end)
624         {
625             gmx_fatal(FARGS,
626                       "The angles in file %s should go from %f to %f instead of %f to %f\n",
627                       libfn.c_str(),
628                       start,
629                       end,
630                       yy[0][0],
631                       yy[0][numRows - 1]);
632         }
633     }
634
635     tabscale = (numRows - 1) / (yy[0][numRows - 1] - yy[0][0]);
636
637     if (fp)
638     {
639         fprintf(fp, "Read user tables from %s with %d data points.\n", libfn.c_str(), numRows);
640         if (angle == 0)
641         {
642             fprintf(fp, "Tabscale = %g points/nm\n", tabscale);
643         }
644     }
645
646     bAllZero = TRUE;
647     for (k = 0; k < ntab; k++)
648     {
649         bZeroV = TRUE;
650         bZeroF = TRUE;
651         for (i = 0; (i < numRows); i++)
652         {
653             if (i >= 2)
654             {
655                 dx0 = yy[0][i - 1] - yy[0][i - 2];
656                 dx1 = yy[0][i] - yy[0][i - 1];
657                 /* Check for 1% deviation in spacing */
658                 if (fabs(dx1 - dx0) >= 0.005 * (fabs(dx0) + fabs(dx1)))
659                 {
660                     gmx_fatal(FARGS,
661                               "In table file '%s' the x values are not equally spaced: %f %f %f",
662                               filename,
663                               yy[0][i - 2],
664                               yy[0][i - 1],
665                               yy[0][i]);
666                 }
667             }
668             if (yy[1 + k * 2][i] != 0)
669             {
670                 bZeroV = FALSE;
671                 if (bAllZero)
672                 {
673                     bAllZero = FALSE;
674                     nx0      = i;
675                 }
676                 if (yy[1 + k * 2][i] > 0.01 * GMX_REAL_MAX || yy[1 + k * 2][i] < -0.01 * GMX_REAL_MAX)
677                 {
678                     gmx_fatal(FARGS, "Out of range potential value %g in file '%s'", yy[1 + k * 2][i], filename);
679                 }
680             }
681             if (yy[1 + k * 2 + 1][i] != 0)
682             {
683                 bZeroF = FALSE;
684                 if (bAllZero)
685                 {
686                     bAllZero = FALSE;
687                     nx0      = i;
688                 }
689                 if (yy[1 + k * 2 + 1][i] > 0.01 * GMX_REAL_MAX || yy[1 + k * 2 + 1][i] < -0.01 * GMX_REAL_MAX)
690                 {
691                     gmx_fatal(FARGS, "Out of range force value %g in file '%s'", yy[1 + k * 2 + 1][i], filename);
692                 }
693             }
694         }
695
696         if (!bZeroV && bZeroF)
697         {
698             set_forces(fp, angle, numRows, 1 / tabscale, yy[1 + k * 2].data(), yy[1 + k * 2 + 1].data(), k);
699         }
700         else
701         {
702             /* Check if the second column is close to minus the numerical
703              * derivative of the first column.
704              */
705             ssd = 0;
706             ns  = 0;
707             for (i = 1; (i < numRows - 1); i++)
708             {
709                 vm = yy[1 + 2 * k][i - 1];
710                 vp = yy[1 + 2 * k][i + 1];
711                 f  = yy[1 + 2 * k + 1][i];
712                 if (vm != 0 && vp != 0 && f != 0)
713                 {
714                     /* Take the centered difference */
715                     numf = -(vp - vm) * 0.5 * tabscale;
716                     if (f + numf != 0)
717                     {
718                         ssd += fabs(2 * (f - numf) / (f + numf));
719                     }
720                     ns++;
721                 }
722             }
723             if (ns > 0)
724             {
725                 ssd /= ns;
726                 sprintf(buf,
727                         "For the %d non-zero entries for table %d in %s the forces deviate on "
728                         "average %" PRId64
729                         "%% from minus the numerical derivative of the potential\n",
730                         ns,
731                         k,
732                         libfn.c_str(),
733                         gmx::roundToInt64(100 * ssd));
734                 if (debug)
735                 {
736                     fprintf(debug, "%s", buf);
737                 }
738                 if (ssd > 0.2)
739                 {
740                     if (fp)
741                     {
742                         fprintf(fp, "\nWARNING: %s\n", buf);
743                     }
744                     fprintf(stderr, "\nWARNING: %s\n", buf);
745                 }
746             }
747         }
748     }
749     if (bAllZero && fp)
750     {
751         fprintf(fp, "\nNOTE: All elements in table %s are zero\n\n", libfn.c_str());
752     }
753
754     std::vector<t_tabledata> td;
755     for (k = 0; (k < ntab); k++)
756     {
757         td.emplace_back(numRows, nx0, tabscale, true);
758         for (i = 0; (i < numRows); i++)
759         {
760             td[k].x[i] = yy[0][i];
761             td[k].v[i] = yy[2 * k + 1][i];
762             td[k].f[i] = yy[2 * k + 2][i];
763         }
764     }
765     return td;
766 }
767
768 static void fill_table(t_tabledata* td, int tp, const interaction_const_t* ic, gmx_bool b14only)
769 {
770     /* Fill the table according to the formulas in the manual.
771      * In principle, we only need the potential and the second
772      * derivative, but then we would have to do lots of calculations
773      * in the inner loop. By precalculating some terms (see manual)
774      * we get better eventual performance, despite a larger table.
775      *
776      * Since some of these higher-order terms are very small,
777      * we always use double precision to calculate them here, in order
778      * to avoid unnecessary loss of precision.
779      */
780     int    i;
781     double reppow, p;
782     double r1, rc, r12, r13;
783     double r, r2, r6, rc2;
784     double expr, Vtab, Ftab;
785     /* Parameters for David's function */
786     double A = 0, B = 0, C = 0, A_3 = 0, B_4 = 0;
787     /* Parameters for the switching function */
788     double ksw, swi, swi1;
789     /* Temporary parameters */
790     gmx_bool bPotentialSwitch, bForceSwitch, bPotentialShift;
791     double   ewc   = ic->ewaldcoeff_q;
792     double   ewclj = ic->ewaldcoeff_lj;
793     double   Vcut  = 0;
794
795     if (b14only)
796     {
797         bPotentialSwitch = FALSE;
798         bForceSwitch     = FALSE;
799         bPotentialShift  = FALSE;
800     }
801     else
802     {
803         bPotentialSwitch =
804                 ((tp == etabLJ6Switch) || (tp == etabLJ12Switch) || (tp == etabCOULSwitch)
805                  || (tp == etabEwaldSwitch) || (tp == etabEwaldUserSwitch)
806                  || (tprops[tp].bCoulomb && (ic->coulomb_modifier == InteractionModifiers::PotSwitch))
807                  || (!tprops[tp].bCoulomb && (ic->vdw_modifier == InteractionModifiers::PotSwitch)));
808         bForceSwitch =
809                 ((tp == etabLJ6Shift) || (tp == etabLJ12Shift) || (tp == etabShift)
810                  || (tprops[tp].bCoulomb && (ic->coulomb_modifier == InteractionModifiers::ForceSwitch))
811                  || (!tprops[tp].bCoulomb && (ic->vdw_modifier == InteractionModifiers::ForceSwitch)));
812         bPotentialShift =
813                 ((tprops[tp].bCoulomb && (ic->coulomb_modifier == InteractionModifiers::PotShift))
814                  || (!tprops[tp].bCoulomb && (ic->vdw_modifier == InteractionModifiers::PotShift)));
815     }
816
817     reppow = ic->reppow;
818
819     if (tprops[tp].bCoulomb)
820     {
821         r1 = ic->rcoulomb_switch;
822         rc = ic->rcoulomb;
823     }
824     else
825     {
826         r1 = ic->rvdw_switch;
827         rc = ic->rvdw;
828     }
829     if (bPotentialSwitch)
830     {
831         ksw = 1.0 / (gmx::power5(rc - r1));
832     }
833     else
834     {
835         ksw = 0.0;
836     }
837     if (bForceSwitch)
838     {
839         if (tp == etabShift)
840         {
841             p = 1;
842         }
843         else if (tp == etabLJ6Shift)
844         {
845             p = 6;
846         }
847         else
848         {
849             p = reppow;
850         }
851
852         A = p * ((p + 1) * r1 - (p + 4) * rc) / (std::pow(rc, p + 2) * gmx::square(rc - r1));
853         B = -p * ((p + 1) * r1 - (p + 3) * rc) / (std::pow(rc, p + 2) * gmx::power3(rc - r1));
854         C = 1.0 / std::pow(rc, p) - A / 3.0 * gmx::power3(rc - r1) - B / 4.0 * gmx::power4(rc - r1);
855         if (tp == etabLJ6Shift)
856         {
857             A = -A;
858             B = -B;
859             C = -C;
860         }
861         A_3 = A / 3.0;
862         B_4 = B / 4.0;
863     }
864     if (debug)
865     {
866         fprintf(debug, "Setting up tables\n");
867         fflush(debug);
868     }
869
870     if (bPotentialShift)
871     {
872         rc2        = rc * rc;
873         double rc6 = 1.0 / (rc2 * rc2 * rc2);
874         double rc12;
875         if (gmx_within_tol(reppow, 12.0, 10 * GMX_DOUBLE_EPS))
876         {
877             rc12 = rc6 * rc6;
878         }
879         else
880         {
881             rc12 = std::pow(rc, -reppow);
882         }
883
884         switch (tp)
885         {
886             case etabLJ6:
887                 /* Dispersion */
888                 Vcut = -rc6;
889                 break;
890             case etabLJ6Ewald:
891                 Vcut = -rc6 * exp(-ewclj * ewclj * rc2)
892                        * (1 + ewclj * ewclj * rc2 + gmx::power4(ewclj) * rc2 * rc2 / 2);
893                 break;
894             case etabLJ12:
895                 /* Repulsion */
896                 Vcut = rc12;
897                 break;
898             case etabCOUL: Vcut = 1.0 / rc; break;
899             case etabEwald:
900             case etabEwaldSwitch: Vcut = std::erfc(ewc * rc) / rc; break;
901             case etabEwaldUser:
902                 /* Only calculate minus the reciprocal space contribution */
903                 Vcut = -std::erf(ewc * rc) / rc;
904                 break;
905             case etabRF:
906             case etabRF_ZERO:
907                 /* No need for preventing the usage of modifiers with RF */
908                 Vcut = 0.0;
909                 break;
910             case etabEXPMIN: Vcut = exp(-rc); break;
911             default:
912                 gmx_fatal(FARGS,
913                           "Cannot apply new potential-shift modifier to interaction type '%s' yet. "
914                           "(%s,%d)",
915                           tprops[tp].name,
916                           __FILE__,
917                           __LINE__);
918         }
919     }
920
921     for (i = 0; (i < td->nx); i++)
922     {
923         td->x[i] = i / td->tabscale;
924     }
925     for (i = td->nx0; (i < td->nx); i++)
926     {
927         r  = td->x[i];
928         r2 = r * r;
929         r6 = 1.0 / (r2 * r2 * r2);
930         if (gmx_within_tol(reppow, 12.0, 10 * GMX_DOUBLE_EPS))
931         {
932             r12 = r6 * r6;
933         }
934         else
935         {
936             r12 = std::pow(r, -reppow);
937         }
938         Vtab = 0.0;
939         Ftab = 0.0;
940         if (bPotentialSwitch)
941         {
942             /* swi is function, swi1 1st derivative and swi2 2nd derivative */
943             /* The switch function is 1 for r<r1, 0 for r>rc, and smooth for
944              * r1<=r<=rc. The 1st and 2nd derivatives are both zero at
945              * r1 and rc.
946              * ksw is just the constant 1/(rc-r1)^5, to save some calculations...
947              */
948             if (r <= r1)
949             {
950                 swi  = 1.0;
951                 swi1 = 0.0;
952             }
953             else if (r >= rc)
954             {
955                 swi  = 0.0;
956                 swi1 = 0.0;
957             }
958             else
959             {
960                 swi = 1 - 10 * gmx::power3(r - r1) * ksw * gmx::square(rc - r1)
961                       + 15 * gmx::power4(r - r1) * ksw * (rc - r1) - 6 * gmx::power5(r - r1) * ksw;
962                 swi1 = -30 * gmx::square(r - r1) * ksw * gmx::square(rc - r1)
963                        + 60 * gmx::power3(r - r1) * ksw * (rc - r1) - 30 * gmx::power4(r - r1) * ksw;
964             }
965         }
966         else /* not really needed, but avoids compiler warnings... */
967         {
968             swi  = 1.0;
969             swi1 = 0.0;
970         }
971
972         switch (tp)
973         {
974             case etabLJ6:
975                 /* Dispersion */
976                 Vtab = -r6;
977                 Ftab = 6.0 * Vtab / r;
978                 break;
979             case etabLJ6Switch:
980             case etabLJ6Shift:
981                 /* Dispersion */
982                 if (r < rc)
983                 {
984                     Vtab = -r6;
985                     Ftab = 6.0 * Vtab / r;
986                     break;
987                 }
988                 break;
989             case etabLJ12:
990                 /* Repulsion */
991                 Vtab = r12;
992                 Ftab = reppow * Vtab / r;
993                 break;
994             case etabLJ12Switch:
995             case etabLJ12Shift:
996                 /* Repulsion */
997                 if (r < rc)
998                 {
999                     Vtab = r12;
1000                     Ftab = reppow * Vtab / r;
1001                 }
1002                 break;
1003             case etabCOUL:
1004                 Vtab = 1.0 / r;
1005                 Ftab = 1.0 / r2;
1006                 break;
1007             case etabCOULSwitch:
1008             case etabShift:
1009                 if (r < rc)
1010                 {
1011                     Vtab = 1.0 / r;
1012                     Ftab = 1.0 / r2;
1013                 }
1014                 break;
1015             case etabEwald:
1016             case etabEwaldSwitch:
1017                 Vtab = std::erfc(ewc * r) / r;
1018                 Ftab = std::erfc(ewc * r) / r2 + exp(-(ewc * ewc * r2)) * ewc * M_2_SQRTPI / r;
1019                 break;
1020             case etabEwaldUser:
1021             case etabEwaldUserSwitch:
1022                 /* Only calculate the negative of the reciprocal space contribution */
1023                 Vtab = -std::erf(ewc * r) / r;
1024                 Ftab = -std::erf(ewc * r) / r2 + exp(-(ewc * ewc * r2)) * ewc * M_2_SQRTPI / r;
1025                 break;
1026             case etabLJ6Ewald:
1027                 Vtab = -r6 * exp(-ewclj * ewclj * r2)
1028                        * (1 + ewclj * ewclj * r2 + gmx::power4(ewclj) * r2 * r2 / 2);
1029                 Ftab = 6.0 * Vtab / r
1030                        - r6 * exp(-ewclj * ewclj * r2) * gmx::power5(ewclj) * ewclj * r2 * r2 * r;
1031                 break;
1032             case etabRF:
1033             case etabRF_ZERO:
1034                 Vtab = 1.0 / r + ic->reactionFieldCoefficient * r2 - ic->reactionFieldShift;
1035                 Ftab = 1.0 / r2 - 2 * ic->reactionFieldCoefficient * r;
1036                 if (tp == etabRF_ZERO && r >= rc)
1037                 {
1038                     Vtab = 0;
1039                     Ftab = 0;
1040                 }
1041                 break;
1042             case etabEXPMIN:
1043                 expr = exp(-r);
1044                 Vtab = expr;
1045                 Ftab = expr;
1046                 break;
1047             default:
1048                 gmx_fatal(FARGS, "Table type %d not implemented yet. (%s,%d)", tp, __FILE__, __LINE__);
1049         }
1050         if (bForceSwitch)
1051         {
1052             /* Normal coulomb with cut-off correction for potential */
1053             if (r < rc)
1054             {
1055                 Vtab -= C;
1056                 /* If in Shifting range add something to it */
1057                 if (r > r1)
1058                 {
1059                     r12 = (r - r1) * (r - r1);
1060                     r13 = (r - r1) * r12;
1061                     Vtab += -A_3 * r13 - B_4 * r12 * r12;
1062                     Ftab += A * r12 + B * r13;
1063                 }
1064             }
1065             else
1066             {
1067                 /* Make sure interactions are zero outside cutoff with modifiers */
1068                 Vtab = 0;
1069                 Ftab = 0;
1070             }
1071         }
1072         if (bPotentialShift)
1073         {
1074             if (r < rc)
1075             {
1076                 Vtab -= Vcut;
1077             }
1078             else
1079             {
1080                 /* Make sure interactions are zero outside cutoff with modifiers */
1081                 Vtab = 0;
1082                 Ftab = 0;
1083             }
1084         }
1085
1086         if (ETAB_USER(tp))
1087         {
1088             Vtab += td->v[i];
1089             Ftab += td->f[i];
1090         }
1091
1092         if (bPotentialSwitch)
1093         {
1094             if (r >= rc)
1095             {
1096                 /* Make sure interactions are zero outside cutoff with modifiers */
1097                 Vtab = 0;
1098                 Ftab = 0;
1099             }
1100             else if (r > r1)
1101             {
1102                 Ftab = Ftab * swi - Vtab * swi1;
1103                 Vtab = Vtab * swi;
1104             }
1105         }
1106         /* Convert to single precision when we store to mem */
1107         td->v[i] = Vtab;
1108         td->f[i] = Ftab;
1109     }
1110
1111     /* Continue the table linearly from nx0 to 0.
1112      * These values are only required for energy minimization with overlap or TPI.
1113      */
1114     for (i = td->nx0 - 1; i >= 0; i--)
1115     {
1116         td->v[i] = td->v[i + 1] + td->f[i + 1] * (td->x[i + 1] - td->x[i]);
1117         td->f[i] = td->f[i + 1];
1118     }
1119 }
1120
1121 static void set_table_type(int tabsel[], const interaction_const_t* ic, gmx_bool b14only)
1122 {
1123     /* Set the different table indices.
1124      * Coulomb first.
1125      */
1126
1127     CoulombInteractionType eltype;
1128     VanDerWaalsType        vdwtype;
1129
1130     if (b14only)
1131     {
1132         switch (ic->eeltype)
1133         {
1134             case CoulombInteractionType::User:
1135             case CoulombInteractionType::PmeUser:
1136             case CoulombInteractionType::PmeUserSwitch:
1137                 eltype = CoulombInteractionType::User;
1138                 break;
1139             default: eltype = CoulombInteractionType::Cut;
1140         }
1141     }
1142     else
1143     {
1144         eltype = ic->eeltype;
1145     }
1146
1147     switch (eltype)
1148     {
1149         case CoulombInteractionType::Cut: tabsel[etiCOUL] = etabCOUL; break;
1150         case CoulombInteractionType::Poisson: tabsel[etiCOUL] = etabShift; break;
1151         case CoulombInteractionType::Shift:
1152             if (ic->rcoulomb > ic->rcoulomb_switch)
1153             {
1154                 tabsel[etiCOUL] = etabShift;
1155             }
1156             else
1157             {
1158                 tabsel[etiCOUL] = etabCOUL;
1159             }
1160             break;
1161         case CoulombInteractionType::Ewald:
1162         case CoulombInteractionType::Pme:
1163         case CoulombInteractionType::P3mAD: tabsel[etiCOUL] = etabEwald; break;
1164         case CoulombInteractionType::PmeSwitch: tabsel[etiCOUL] = etabEwaldSwitch; break;
1165         case CoulombInteractionType::PmeUser: tabsel[etiCOUL] = etabEwaldUser; break;
1166         case CoulombInteractionType::PmeUserSwitch: tabsel[etiCOUL] = etabEwaldUserSwitch; break;
1167         case CoulombInteractionType::RF:
1168         case CoulombInteractionType::RFZero: tabsel[etiCOUL] = etabRF_ZERO; break;
1169         case CoulombInteractionType::Switch: tabsel[etiCOUL] = etabCOULSwitch; break;
1170         case CoulombInteractionType::User: tabsel[etiCOUL] = etabUSER; break;
1171         default: gmx_fatal(FARGS, "Invalid eeltype %s", enumValueToString(eltype));
1172     }
1173
1174     /* Van der Waals time */
1175     if (ic->useBuckingham && !b14only)
1176     {
1177         tabsel[etiLJ6]  = etabLJ6;
1178         tabsel[etiLJ12] = etabEXPMIN;
1179     }
1180     else
1181     {
1182         if (b14only && ic->vdwtype != VanDerWaalsType::User)
1183         {
1184             vdwtype = VanDerWaalsType::Cut;
1185         }
1186         else
1187         {
1188             vdwtype = ic->vdwtype;
1189         }
1190
1191         switch (vdwtype)
1192         {
1193             case VanDerWaalsType::Switch:
1194                 tabsel[etiLJ6]  = etabLJ6Switch;
1195                 tabsel[etiLJ12] = etabLJ12Switch;
1196                 break;
1197             case VanDerWaalsType::Shift:
1198                 tabsel[etiLJ6]  = etabLJ6Shift;
1199                 tabsel[etiLJ12] = etabLJ12Shift;
1200                 break;
1201             case VanDerWaalsType::User:
1202                 tabsel[etiLJ6]  = etabUSER;
1203                 tabsel[etiLJ12] = etabUSER;
1204                 break;
1205             case VanDerWaalsType::Cut:
1206                 tabsel[etiLJ6]  = etabLJ6;
1207                 tabsel[etiLJ12] = etabLJ12;
1208                 break;
1209             case VanDerWaalsType::Pme:
1210                 tabsel[etiLJ6]  = etabLJ6Ewald;
1211                 tabsel[etiLJ12] = etabLJ12;
1212                 break;
1213             default:
1214                 gmx_fatal(FARGS, "Invalid vdwtype %s in %s line %d", enumValueToString(vdwtype), __FILE__, __LINE__);
1215         }
1216
1217         if (!b14only && ic->vdw_modifier != InteractionModifiers::None)
1218         {
1219             if (ic->vdw_modifier != InteractionModifiers::PotShift && ic->vdwtype != VanDerWaalsType::Cut)
1220             {
1221                 gmx_incons(
1222                         "Potential modifiers other than potential-shift are only implemented for "
1223                         "LJ cut-off");
1224             }
1225
1226             /* LJ-PME and other (shift-only) modifiers are handled by applying the modifiers
1227              * to the original interaction forms when we fill the table, so we only check cutoffs here.
1228              */
1229             if (ic->vdwtype == VanDerWaalsType::Cut)
1230             {
1231                 switch (ic->vdw_modifier)
1232                 {
1233                     case InteractionModifiers::None:
1234                     case InteractionModifiers::PotShift:
1235                     case InteractionModifiers::ExactCutoff:
1236                         /* No modification */
1237                         break;
1238                     case InteractionModifiers::PotSwitch:
1239                         tabsel[etiLJ6]  = etabLJ6Switch;
1240                         tabsel[etiLJ12] = etabLJ12Switch;
1241                         break;
1242                     case InteractionModifiers::ForceSwitch:
1243                         tabsel[etiLJ6]  = etabLJ6Shift;
1244                         tabsel[etiLJ12] = etabLJ12Shift;
1245                         break;
1246                     default: gmx_incons("Unsupported vdw_modifier");
1247                 }
1248             }
1249         }
1250     }
1251 }
1252
1253 std::unique_ptr<t_forcetable>
1254 make_tables(FILE* fp, const interaction_const_t* ic, const char* fn, real rtab, int flags)
1255 {
1256     gmx_bool b14only, useUserTable;
1257     int      nx0, tabsel[etiNR];
1258     real     scalefactor;
1259
1260     auto table = std::make_unique<t_forcetable>(
1261             TableInteraction::ElectrostaticVdwRepulsionVdwDispersion, TableFormat::CubicsplineYfgh);
1262
1263     b14only = ((flags & GMX_MAKETABLES_14ONLY) != 0);
1264
1265     if (flags & GMX_MAKETABLES_FORCEUSER)
1266     {
1267         tabsel[etiCOUL] = etabUSER;
1268         tabsel[etiLJ6]  = etabUSER;
1269         tabsel[etiLJ12] = etabUSER;
1270     }
1271     else
1272     {
1273         set_table_type(tabsel, ic, b14only);
1274     }
1275     std::vector<t_tabledata> td;
1276     table->interactionRange = rtab;
1277     table->scale            = 0;
1278     table->numTablePoints   = 0;
1279
1280     table->numInteractions = etiNR;
1281     table->stride          = table->formatsize * table->numInteractions;
1282
1283     /* Check whether we have to read or generate */
1284     useUserTable = FALSE;
1285     for (unsigned int i = 0; (i < etiNR); i++)
1286     {
1287         if (ETAB_USER(tabsel[i]))
1288         {
1289             useUserTable = TRUE;
1290         }
1291     }
1292     if (useUserTable)
1293     {
1294         td = read_tables(fp, fn, etiNR, 0);
1295         if (rtab == 0 || (flags & GMX_MAKETABLES_14ONLY))
1296         {
1297             table->numTablePoints = td[0].nx;
1298         }
1299         else
1300         {
1301             if (td[0].x[td[0].nx - 1] < rtab)
1302             {
1303                 gmx_fatal(FARGS,
1304                           "Tables in file %s not long enough for cut-off:\n"
1305                           "\tshould be at least %f nm\n",
1306                           fn,
1307                           rtab);
1308             }
1309             table->numTablePoints = gmx::roundToInt(rtab * td[0].tabscale);
1310         }
1311         table->scale = td[0].tabscale;
1312         nx0          = td[0].nx0;
1313     }
1314     else
1315     {
1316         td.resize(etiNR);
1317         // No tables are read
1318 #if GMX_DOUBLE
1319         table->scale = 2000.0;
1320 #else
1321         table->scale = 500.0;
1322 #endif
1323         table->numTablePoints = static_cast<int>(rtab * table->scale);
1324         nx0                   = 10;
1325     }
1326
1327     /* Each table type (e.g. coul,lj6,lj12) requires four
1328      * numbers per table->numTablePoints+1 data points. For performance reasons we want
1329      * the table data to be aligned to (at least) a 32-byte boundary.
1330      */
1331     table->data.resize(table->stride * (table->numTablePoints + 1) * sizeof(real));
1332
1333     for (int k = 0; (k < etiNR); k++)
1334     {
1335         /* Now fill data for tables that have not been read
1336          * or add the Ewald long-range correction for Ewald user tables.
1337          */
1338         if (tabsel[k] != etabUSER)
1339         {
1340             real scale = table->scale;
1341             if (ic->useBuckingham && (ic->buckinghamBMax != 0) && tabsel[k] == etabEXPMIN)
1342             {
1343                 scale /= ic->buckinghamBMax;
1344             }
1345             td[k] = t_tabledata(table->numTablePoints, nx0, scale, !useUserTable);
1346
1347             fill_table(&(td[k]), tabsel[k], ic, b14only);
1348             if (fp)
1349             {
1350                 fprintf(fp,
1351                         "Generated table with %d data points for %s%s.\n"
1352                         "Tabscale = %g points/nm\n",
1353                         td[k].nx,
1354                         b14only ? "1-4 " : "",
1355                         tprops[tabsel[k]].name,
1356                         td[k].tabscale);
1357             }
1358         }
1359
1360         /* Set scalefactor for c6/c12 tables. This is because we save flops in the non-table kernels
1361          * by including the derivative constants (6.0 or 12.0) in the parameters, since
1362          * we no longer calculate force in most steps. This means the c6/c12 parameters
1363          * have been scaled up, so we need to scale down the table interactions too.
1364          * It comes here since we need to scale user tables too.
1365          */
1366         if (k == etiLJ6)
1367         {
1368             scalefactor = 1.0 / 6.0;
1369         }
1370         else if (k == etiLJ12 && tabsel[k] != etabEXPMIN)
1371         {
1372             scalefactor = 1.0 / 12.0;
1373         }
1374         else
1375         {
1376             scalefactor = 1.0;
1377         }
1378
1379         copy2table(table->numTablePoints,
1380                    k * table->formatsize,
1381                    table->stride,
1382                    td[k].x,
1383                    td[k].v,
1384                    td[k].f,
1385                    scalefactor,
1386                    table->data);
1387     }
1388
1389     return table;
1390 }
1391
1392 bondedtable_t make_bonded_table(FILE* fplog, const char* fn, int angle)
1393 {
1394     int           i;
1395     bondedtable_t tab;
1396     int           stride = 4;
1397
1398     t_tabledata td = read_tables(fplog, fn, 1, angle)[0];
1399     if (angle > 0)
1400     {
1401         /* Convert the table from degrees to radians */
1402         for (i = 0; i < td.nx; i++)
1403         {
1404             td.x[i] *= gmx::c_deg2Rad;
1405             td.f[i] *= gmx::c_rad2Deg;
1406         }
1407         td.tabscale *= gmx::c_rad2Deg;
1408     }
1409     tab.n     = td.nx;
1410     tab.scale = td.tabscale;
1411     tab.data.resize(tab.n * stride);
1412     copy2table(tab.n, 0, stride, td.x, td.v, td.f, 1.0, tab.data);
1413
1414     return tab;
1415 }
1416
1417 std::unique_ptr<t_forcetable>
1418 makeDispersionCorrectionTable(FILE* fp, const interaction_const_t* ic, real rtab, const char* tabfn)
1419 {
1420     GMX_RELEASE_ASSERT(ic->vdwtype != VanDerWaalsType::User || tabfn,
1421                        "With VdW user tables we need a table file name");
1422
1423     std::unique_ptr<t_forcetable> fullTable = make_tables(fp, ic, tabfn, rtab, 0);
1424     /* Copy the contents of the table to one that has just dispersion
1425      * and repulsion, to improve cache performance. We want the table
1426      * data to be aligned to 32-byte boundaries.
1427      */
1428     std::unique_ptr<t_forcetable> dispersionCorrectionTable = std::make_unique<t_forcetable>(
1429             TableInteraction::VdwRepulsionVdwDispersion, fullTable->format);
1430     dispersionCorrectionTable->interactionRange = fullTable->interactionRange;
1431     dispersionCorrectionTable->numTablePoints   = fullTable->numTablePoints;
1432     dispersionCorrectionTable->scale            = fullTable->scale;
1433     dispersionCorrectionTable->numInteractions  = 2;
1434     dispersionCorrectionTable->stride =
1435             dispersionCorrectionTable->formatsize * dispersionCorrectionTable->numInteractions;
1436     dispersionCorrectionTable->data.resize(dispersionCorrectionTable->stride
1437                                            * (dispersionCorrectionTable->numTablePoints + 1));
1438
1439     for (int i = 0; i <= fullTable->numTablePoints; i++)
1440     {
1441         for (int j = 0; j < 8; j++)
1442         {
1443             dispersionCorrectionTable->data[8 * i + j] = fullTable->data[12 * i + 4 + j];
1444         }
1445     }
1446
1447     return dispersionCorrectionTable;
1448 }
1449
1450 t_forcetable::t_forcetable(enum TableInteraction interaction, enum TableFormat format) :
1451     interaction(interaction),
1452     format(format),
1453     interactionRange(0),
1454     numTablePoints(0),
1455     scale(0),
1456     numInteractions(0),
1457     stride(0)
1458 {
1459 }
1460
1461 t_forcetable::~t_forcetable() = default;