23a0639167cdff96eee5ee1ef7ef507c4d09247f
[alexxy/gromacs.git] / src / gromacs / mdlib / forcerec.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-2019,2020,2021, by the GROMACS development team, led by
7  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8  * and including many others, as listed in the AUTHORS file in the
9  * top-level source directory and at http://www.gromacs.org.
10  *
11  * GROMACS is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * as published by the Free Software Foundation; either version 2.1
14  * of the License, or (at your option) any later version.
15  *
16  * GROMACS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with GROMACS; if not, see
23  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
25  *
26  * If you want to redistribute modifications to GROMACS, please
27  * consider that scientific software is very special. Version
28  * control is crucial - bugs must be traceable. We will be happy to
29  * consider code for inclusion in the official distribution, but
30  * derived work must not be called official GROMACS. Details are found
31  * in the README & COPYING files - if they are missing, get the
32  * official version at http://www.gromacs.org.
33  *
34  * To help us fund GROMACS development, we humbly ask that you cite
35  * the research papers on the package. Check out http://www.gromacs.org.
36  */
37 #include "gmxpre.h"
38
39 #include "forcerec.h"
40
41 #include "config.h"
42
43 #include <cmath>
44 #include <cstdlib>
45 #include <cstring>
46
47 #include <algorithm>
48 #include <memory>
49
50 #include "gromacs/commandline/filenm.h"
51 #include "gromacs/domdec/domdec.h"
52 #include "gromacs/domdec/domdec_struct.h"
53 #include "gromacs/ewald/ewald.h"
54 #include "gromacs/ewald/pme_pp_comm_gpu.h"
55 #include "gromacs/fileio/filetypes.h"
56 #include "gromacs/gmxlib/network.h"
57 #include "gromacs/gmxlib/nonbonded/nonbonded.h"
58 #include "gromacs/gpu_utils/gpu_utils.h"
59 #include "gromacs/hardware/hw_info.h"
60 #include "gromacs/listed_forces/listed_forces_gpu.h"
61 #include "gromacs/listed_forces/listed_forces.h"
62 #include "gromacs/listed_forces/pairs.h"
63 #include "gromacs/math/functions.h"
64 #include "gromacs/math/utilities.h"
65 #include "gromacs/math/vec.h"
66 #include "gromacs/mdlib/dispersioncorrection.h"
67 #include "gromacs/mdlib/force.h"
68 #include "gromacs/mdlib/forcerec_threading.h"
69 #include "gromacs/mdlib/gmx_omp_nthreads.h"
70 #include "gromacs/mdlib/md_support.h"
71 #include "gromacs/mdlib/wall.h"
72 #include "gromacs/mdlib/wholemoleculetransform.h"
73 #include "gromacs/mdtypes/commrec.h"
74 #include "gromacs/mdtypes/fcdata.h"
75 #include "gromacs/mdtypes/forcerec.h"
76 #include "gromacs/mdtypes/group.h"
77 #include "gromacs/mdtypes/iforceprovider.h"
78 #include "gromacs/mdtypes/inputrec.h"
79 #include "gromacs/mdtypes/interaction_const.h"
80 #include "gromacs/mdtypes/md_enums.h"
81 #include "gromacs/mdtypes/multipletimestepping.h"
82 #include "gromacs/mdtypes/nblist.h"
83 #include "gromacs/mdtypes/simulation_workload.h"
84 #include "gromacs/nbnxm/nbnxm.h"
85 #include "gromacs/pbcutil/ishift.h"
86 #include "gromacs/pbcutil/pbc.h"
87 #include "gromacs/tables/forcetable.h"
88 #include "gromacs/topology/mtop_util.h"
89 #include "gromacs/topology/idef.h"
90 #include "gromacs/trajectory/trajectoryframe.h"
91 #include "gromacs/utility/cstringutil.h"
92 #include "gromacs/utility/exceptions.h"
93 #include "gromacs/utility/fatalerror.h"
94 #include "gromacs/utility/gmxassert.h"
95 #include "gromacs/utility/logger.h"
96 #include "gromacs/utility/physicalnodecommunicator.h"
97 #include "gromacs/utility/pleasecite.h"
98 #include "gromacs/utility/smalloc.h"
99 #include "gromacs/utility/strconvert.h"
100
101 #include "gpuforcereduction.h"
102
103 ForceHelperBuffers::ForceHelperBuffers(bool haveDirectVirialContributions) :
104     haveDirectVirialContributions_(haveDirectVirialContributions)
105 {
106     shiftForces_.resize(gmx::c_numShiftVectors);
107 }
108
109 void ForceHelperBuffers::resize(int numAtoms)
110 {
111     if (haveDirectVirialContributions_)
112     {
113         forceBufferForDirectVirialContributions_.resize(numAtoms);
114     }
115 }
116
117 std::vector<real> makeNonBondedParameterLists(const int                      numAtomTypes,
118                                               gmx::ArrayRef<const t_iparams> iparams,
119                                               bool                           useBuckinghamPotential)
120 {
121     std::vector<real> nbfp;
122
123     if (useBuckinghamPotential)
124     {
125         nbfp.resize(3 * numAtomTypes * numAtomTypes);
126         int k = 0;
127         for (int i = 0; (i < numAtomTypes); i++)
128         {
129             for (int j = 0; (j < numAtomTypes); j++, k++)
130             {
131                 BHAMA(nbfp, numAtomTypes, i, j) = iparams[k].bham.a;
132                 BHAMB(nbfp, numAtomTypes, i, j) = iparams[k].bham.b;
133                 /* nbfp now includes the 6.0 derivative prefactor */
134                 BHAMC(nbfp, numAtomTypes, i, j) = iparams[k].bham.c * 6.0;
135             }
136         }
137     }
138     else
139     {
140         nbfp.resize(2 * numAtomTypes * numAtomTypes);
141         int k = 0;
142         for (int i = 0; (i < numAtomTypes); i++)
143         {
144             for (int j = 0; (j < numAtomTypes); j++, k++)
145             {
146                 /* nbfp now includes the 6.0/12.0 derivative prefactors */
147                 C6(nbfp, numAtomTypes, i, j)  = iparams[k].lj.c6 * 6.0;
148                 C12(nbfp, numAtomTypes, i, j) = iparams[k].lj.c12 * 12.0;
149             }
150         }
151     }
152
153     return nbfp;
154 }
155
156 std::vector<real> makeLJPmeC6GridCorrectionParameters(const int                      numAtomTypes,
157                                                       gmx::ArrayRef<const t_iparams> iparams,
158                                                       LongRangeVdW ljpme_combination_rule)
159 {
160     /* For LJ-PME simulations, we correct the energies with the reciprocal space
161      * inside of the cut-off. To do this the non-bonded kernels needs to have
162      * access to the C6-values used on the reciprocal grid in pme.c
163      */
164
165     std::vector<real> grid(2 * numAtomTypes * numAtomTypes, 0.0);
166     int               k = 0;
167     for (int i = 0; (i < numAtomTypes); i++)
168     {
169         for (int j = 0; (j < numAtomTypes); j++, k++)
170         {
171             real c6i  = iparams[i * (numAtomTypes + 1)].lj.c6;
172             real c12i = iparams[i * (numAtomTypes + 1)].lj.c12;
173             real c6j  = iparams[j * (numAtomTypes + 1)].lj.c6;
174             real c12j = iparams[j * (numAtomTypes + 1)].lj.c12;
175             real c6   = std::sqrt(c6i * c6j);
176             if (ljpme_combination_rule == LongRangeVdW::LB && !gmx_numzero(c6) && !gmx_numzero(c12i)
177                 && !gmx_numzero(c12j))
178             {
179                 real sigmai = gmx::sixthroot(c12i / c6i);
180                 real sigmaj = gmx::sixthroot(c12j / c6j);
181                 real epsi   = c6i * c6i / c12i;
182                 real epsj   = c6j * c6j / c12j;
183                 c6          = std::sqrt(epsi * epsj) * gmx::power6(0.5 * (sigmai + sigmaj));
184             }
185             /* Store the elements at the same relative positions as C6 in nbfp in order
186              * to simplify access in the kernels
187              */
188             grid[2 * (numAtomTypes * i + j)] = c6 * 6.0;
189         }
190     }
191     return grid;
192 }
193
194 //! What kind of constraint affects an atom
195 enum class ConstraintTypeForAtom : int
196 {
197     None,       //!< No constraint active
198     Constraint, //!< F_CONSTR or F_CONSTRNC active
199     Settle,     //! F_SETTLE active
200 };
201
202 static std::vector<gmx::AtomInfoWithinMoleculeBlock>
203 makeAtomInfoForEachMoleculeBlock(const gmx_mtop_t& mtop, const t_forcerec* fr)
204 {
205     std::vector<bool> atomUsesVdw(fr->ntype, false);
206     for (int ai = 0; ai < fr->ntype; ai++)
207     {
208         for (int j = 0; j < fr->ntype; j++)
209         {
210             atomUsesVdw[ai] = atomUsesVdw[ai] || fr->haveBuckingham || C6(fr->nbfp, fr->ntype, ai, j) != 0
211                               || C12(fr->nbfp, fr->ntype, ai, j) != 0;
212         }
213     }
214
215     std::vector<gmx::AtomInfoWithinMoleculeBlock> atomInfoForEachMoleculeBlock;
216     int                                           indexOfFirstAtomInMoleculeBlock = 0;
217     for (size_t mb = 0; mb < mtop.molblock.size(); mb++)
218     {
219         const gmx_molblock_t& molb = mtop.molblock[mb];
220         const gmx_moltype_t&  molt = mtop.moltype[molb.type];
221         const auto&           excl = molt.excls;
222
223         /* Check if all molecules in this block have identical
224          * atominfo. (That's true unless some kind of group- or
225          * distance-based algorithm is involved, e.g. QM/MM groups
226          * affecting multiple molecules within a block differently.)
227          * If so, we only need an array of the size of one molecule.
228          * Otherwise we make an array of #mol times #atoms per
229          * molecule.
230          */
231         bool allMoleculesWithinBlockAreIdentical = true;
232         for (int m = 0; m < molb.nmol; m++)
233         {
234             const int numAtomsInAllMolecules = m * molt.atoms.nr;
235             for (int a = 0; a < molt.atoms.nr; a++)
236             {
237                 if (getGroupType(mtop.groups,
238                                  SimulationAtomGroupType::QuantumMechanics,
239                                  indexOfFirstAtomInMoleculeBlock + numAtomsInAllMolecules + a)
240                     != getGroupType(mtop.groups,
241                                     SimulationAtomGroupType::QuantumMechanics,
242                                     indexOfFirstAtomInMoleculeBlock + a))
243                 {
244                     allMoleculesWithinBlockAreIdentical = false;
245                 }
246                 if (!mtop.groups.groupNumbers[SimulationAtomGroupType::QuantumMechanics].empty())
247                 {
248                     if (mtop.groups.groupNumbers[SimulationAtomGroupType::QuantumMechanics]
249                                                 [indexOfFirstAtomInMoleculeBlock + numAtomsInAllMolecules + a]
250                         != mtop.groups.groupNumbers[SimulationAtomGroupType::QuantumMechanics]
251                                                    [indexOfFirstAtomInMoleculeBlock + a])
252                     {
253                         allMoleculesWithinBlockAreIdentical = false;
254                     }
255                 }
256             }
257         }
258
259         gmx::AtomInfoWithinMoleculeBlock atomInfoOfMoleculeBlock;
260         atomInfoOfMoleculeBlock.indexOfFirstAtomInMoleculeBlock = indexOfFirstAtomInMoleculeBlock;
261         atomInfoOfMoleculeBlock.indexOfLastAtomInMoleculeBlock =
262                 indexOfFirstAtomInMoleculeBlock + molb.nmol * molt.atoms.nr;
263         int atomInfoSize = (allMoleculesWithinBlockAreIdentical ? 1 : molb.nmol) * molt.atoms.nr;
264         atomInfoOfMoleculeBlock.atomInfo.resize(atomInfoSize);
265
266         /* Set constraints flags for constrained atoms */
267         std::vector<ConstraintTypeForAtom> constraintTypeOfAtom(molt.atoms.nr, ConstraintTypeForAtom::None);
268         for (int ftype = 0; ftype < F_NRE; ftype++)
269         {
270             if (interaction_function[ftype].flags & IF_CONSTRAINT)
271             {
272                 const int nral = NRAL(ftype);
273                 for (int ia = 0; ia < molt.ilist[ftype].size(); ia += 1 + nral)
274                 {
275                     for (int a = 0; a < nral; a++)
276                     {
277                         constraintTypeOfAtom[molt.ilist[ftype].iatoms[ia + 1 + a]] =
278                                 (ftype == F_SETTLE ? ConstraintTypeForAtom::Settle
279                                                    : ConstraintTypeForAtom::Constraint);
280                     }
281                 }
282             }
283         }
284
285         for (int m = 0; m < (allMoleculesWithinBlockAreIdentical ? 1 : molb.nmol); m++)
286         {
287             const int moleculeOffsetInBlock = m * molt.atoms.nr;
288             for (int a = 0; a < molt.atoms.nr; a++)
289             {
290                 const t_atom& atom = molt.atoms.atom[a];
291                 int64_t& atomInfo  = atomInfoOfMoleculeBlock.atomInfo[moleculeOffsetInBlock + a];
292
293                 /* Store the energy group in atomInfo */
294                 int gid  = getGroupType(mtop.groups,
295                                        SimulationAtomGroupType::EnergyOutput,
296                                        indexOfFirstAtomInMoleculeBlock + moleculeOffsetInBlock + a);
297                 atomInfo = (atomInfo & ~gmx::sc_atomInfo_EnergyGroupIdMask) | gid;
298
299                 bool bHaveVDW = (atomUsesVdw[atom.type] || atomUsesVdw[atom.typeB]);
300                 bool bHaveQ   = (atom.q != 0 || atom.qB != 0);
301
302                 bool haveExclusions = false;
303                 /* Loop over all the exclusions of atom ai */
304                 for (const int j : excl[a])
305                 {
306                     if (j != a)
307                     {
308                         haveExclusions = true;
309                         break;
310                     }
311                 }
312
313                 switch (constraintTypeOfAtom[a])
314                 {
315                     case ConstraintTypeForAtom::Constraint:
316                         atomInfo |= gmx::sc_atomInfo_Constraint;
317                         break;
318                     case ConstraintTypeForAtom::Settle: atomInfo |= gmx::sc_atomInfo_Settle; break;
319                     default: break;
320                 }
321                 if (haveExclusions)
322                 {
323                     atomInfo |= gmx::sc_atomInfo_Exclusion;
324                 }
325                 if (bHaveVDW)
326                 {
327                     atomInfo |= gmx::sc_atomInfo_HasVdw;
328                 }
329                 if (bHaveQ)
330                 {
331                     atomInfo |= gmx::sc_atomInfo_HasCharge;
332                 }
333                 if (fr->efep != FreeEnergyPerturbationType::No)
334                 {
335                     if (PERTURBED(atom))
336                     {
337                         atomInfo |= gmx::sc_atomInfo_FreeEnergyPerturbation;
338                     }
339                     if (atomHasPerturbedChargeIn14Interaction(a, molt))
340                     {
341                         atomInfo |= gmx::sc_atomInfo_HasPerturbedChargeIn14Interaction;
342                     }
343                 }
344             }
345         }
346
347         atomInfoForEachMoleculeBlock.push_back(atomInfoOfMoleculeBlock);
348
349         indexOfFirstAtomInMoleculeBlock += molb.nmol * molt.atoms.nr;
350     }
351
352     return atomInfoForEachMoleculeBlock;
353 }
354
355 static std::vector<int64_t> expandAtomInfo(const int nmb,
356                                            gmx::ArrayRef<const gmx::AtomInfoWithinMoleculeBlock> atomInfoForEachMoleculeBlock)
357 {
358     const int numAtoms = atomInfoForEachMoleculeBlock[nmb - 1].indexOfLastAtomInMoleculeBlock;
359
360     std::vector<int64_t> atomInfo(numAtoms);
361
362     int mb = 0;
363     for (int a = 0; a < numAtoms; a++)
364     {
365         while (a >= atomInfoForEachMoleculeBlock[mb].indexOfLastAtomInMoleculeBlock)
366         {
367             mb++;
368         }
369         atomInfo[a] = atomInfoForEachMoleculeBlock[mb]
370                               .atomInfo[(a - atomInfoForEachMoleculeBlock[mb].indexOfFirstAtomInMoleculeBlock)
371                                         % atomInfoForEachMoleculeBlock[mb].atomInfo.size()];
372     }
373
374     return atomInfo;
375 }
376
377 /* Sets the sum of charges (squared) and C6 in the system in fr.
378  * Returns whether the system has a net charge.
379  */
380 static bool set_chargesum(FILE* log, t_forcerec* fr, const gmx_mtop_t& mtop)
381 {
382     /*This now calculates sum for q and c6*/
383     double qsum, q2sum, q, c6sum, c6;
384
385     qsum  = 0;
386     q2sum = 0;
387     c6sum = 0;
388     for (const gmx_molblock_t& molb : mtop.molblock)
389     {
390         int            nmol  = molb.nmol;
391         const t_atoms* atoms = &mtop.moltype[molb.type].atoms;
392         for (int i = 0; i < atoms->nr; i++)
393         {
394             q = atoms->atom[i].q;
395             qsum += nmol * q;
396             q2sum += nmol * q * q;
397             c6 = mtop.ffparams.iparams[atoms->atom[i].type * (mtop.ffparams.atnr + 1)].lj.c6;
398             c6sum += nmol * c6;
399         }
400     }
401     fr->qsum[0]  = qsum;
402     fr->q2sum[0] = q2sum;
403     fr->c6sum[0] = c6sum;
404
405     if (fr->efep != FreeEnergyPerturbationType::No)
406     {
407         qsum  = 0;
408         q2sum = 0;
409         c6sum = 0;
410         for (const gmx_molblock_t& molb : mtop.molblock)
411         {
412             int            nmol  = molb.nmol;
413             const t_atoms* atoms = &mtop.moltype[molb.type].atoms;
414             for (int i = 0; i < atoms->nr; i++)
415             {
416                 q = atoms->atom[i].qB;
417                 qsum += nmol * q;
418                 q2sum += nmol * q * q;
419                 c6 = mtop.ffparams.iparams[atoms->atom[i].typeB * (mtop.ffparams.atnr + 1)].lj.c6;
420                 c6sum += nmol * c6;
421             }
422             fr->qsum[1]  = qsum;
423             fr->q2sum[1] = q2sum;
424             fr->c6sum[1] = c6sum;
425         }
426     }
427     else
428     {
429         fr->qsum[1]  = fr->qsum[0];
430         fr->q2sum[1] = fr->q2sum[0];
431         fr->c6sum[1] = fr->c6sum[0];
432     }
433     if (log)
434     {
435         if (fr->efep == FreeEnergyPerturbationType::No)
436         {
437             fprintf(log, "System total charge: %.3f\n", fr->qsum[0]);
438         }
439         else
440         {
441             fprintf(log, "System total charge, top. A: %.3f top. B: %.3f\n", fr->qsum[0], fr->qsum[1]);
442         }
443     }
444
445     /* A cut-off of 1e-4 is used to catch rounding errors due to ascii input */
446     return (std::abs(fr->qsum[0]) > 1e-4 || std::abs(fr->qsum[1]) > 1e-4);
447 }
448
449 /*!\brief If there's bonded interactions of type \c ftype1 or \c
450  * ftype2 present in the topology, build an array of the number of
451  * interactions present for each bonded interaction index found in the
452  * topology.
453  *
454  * \c ftype1 or \c ftype2 may be set to -1 to disable seeking for a
455  * valid type with that parameter.
456  *
457  * \c count will be reallocated as necessary to fit the largest bonded
458  * interaction index found, and its current size will be returned in
459  * \c ncount. It will contain zero for every bonded interaction index
460  * for which no interactions are present in the topology.
461  */
462 static void count_tables(int ftype1, int ftype2, const gmx_mtop_t& mtop, int* ncount, int** count)
463 {
464     int ftype, i, j, tabnr;
465
466     // Loop over all moleculetypes
467     for (const gmx_moltype_t& molt : mtop.moltype)
468     {
469         // Loop over all interaction types
470         for (ftype = 0; ftype < F_NRE; ftype++)
471         {
472             // If the current interaction type is one of the types whose tables we're trying to count...
473             if (ftype == ftype1 || ftype == ftype2)
474             {
475                 const InteractionList& il     = molt.ilist[ftype];
476                 const int              stride = 1 + NRAL(ftype);
477                 // ... and there are actually some interactions for this type
478                 for (i = 0; i < il.size(); i += stride)
479                 {
480                     // Find out which table index the user wanted
481                     tabnr = mtop.ffparams.iparams[il.iatoms[i]].tab.table;
482                     if (tabnr < 0)
483                     {
484                         gmx_fatal(FARGS, "A bonded table number is smaller than 0: %d\n", tabnr);
485                     }
486                     // Make room for this index in the data structure
487                     if (tabnr >= *ncount)
488                     {
489                         srenew(*count, tabnr + 1);
490                         for (j = *ncount; j < tabnr + 1; j++)
491                         {
492                             (*count)[j] = 0;
493                         }
494                         *ncount = tabnr + 1;
495                     }
496                     // Record that this table index is used and must have a valid file
497                     (*count)[tabnr]++;
498                 }
499             }
500         }
501     }
502 }
503
504 /*!\brief If there's bonded interactions of flavour \c tabext and type
505  * \c ftype1 or \c ftype2 present in the topology, seek them in the
506  * list of filenames passed to mdrun, and make bonded tables from
507  * those files.
508  *
509  * \c ftype1 or \c ftype2 may be set to -1 to disable seeking for a
510  * valid type with that parameter.
511  *
512  * A fatal error occurs if no matching filename is found.
513  */
514 static std::vector<bondedtable_t> make_bonded_tables(FILE*                            fplog,
515                                                      int                              ftype1,
516                                                      int                              ftype2,
517                                                      const gmx_mtop_t&                mtop,
518                                                      gmx::ArrayRef<const std::string> tabbfnm,
519                                                      const char*                      tabext)
520 {
521     std::vector<bondedtable_t> tab;
522
523     int  ncount = 0;
524     int* count  = nullptr;
525     count_tables(ftype1, ftype2, mtop, &ncount, &count);
526
527     // Are there any relevant tabulated bond interactions?
528     if (ncount > 0)
529     {
530         tab.resize(ncount);
531         for (int i = 0; i < ncount; i++)
532         {
533             // Do any interactions exist that requires this table?
534             if (count[i] > 0)
535             {
536                 // This pattern enforces the current requirement that
537                 // table filenames end in a characteristic sequence
538                 // before the file type extension, and avoids table 13
539                 // being recognized and used for table 1.
540                 std::string patternToFind = gmx::formatString("_%s%d.%s", tabext, i, ftp2ext(efXVG));
541                 bool        madeTable     = false;
542                 for (gmx::index j = 0; j < tabbfnm.ssize() && !madeTable; ++j)
543                 {
544                     if (gmx::endsWith(tabbfnm[j], patternToFind))
545                     {
546                         // Finally read the table from the file found
547                         tab[i]    = make_bonded_table(fplog, tabbfnm[j].c_str(), NRAL(ftype1) - 2);
548                         madeTable = true;
549                     }
550                 }
551                 if (!madeTable)
552                 {
553                     bool isPlural = (ftype2 != -1);
554                     gmx_fatal(FARGS,
555                               "Tabulated interaction of type '%s%s%s' with index %d cannot be used "
556                               "because no table file whose name matched '%s' was passed via the "
557                               "gmx mdrun -tableb command-line option.",
558                               interaction_function[ftype1].longname,
559                               isPlural ? "' or '" : "",
560                               isPlural ? interaction_function[ftype2].longname : "",
561                               i,
562                               patternToFind.c_str());
563                 }
564             }
565         }
566         sfree(count);
567     }
568
569     return tab;
570 }
571
572 void forcerec_set_ranges(t_forcerec* fr, int natoms_force, int natoms_force_constr, int natoms_f_novirsum)
573 {
574     fr->natoms_force        = natoms_force;
575     fr->natoms_force_constr = natoms_force_constr;
576
577     for (auto& forceHelperBuffers : fr->forceHelperBuffers)
578     {
579         forceHelperBuffers.resize(natoms_f_novirsum);
580     }
581 }
582
583 /* Generate Coulomb and/or Van der Waals Ewald long-range correction tables
584  *
585  * Tables are generated for one or both, depending on if the pointers
586  * are non-null. The spacing for both table sets is the same and obeys
587  * both accuracy requirements, when relevant.
588  */
589 static void init_ewald_f_table(const interaction_const_t& ic,
590                                const real                 rlist,
591                                const real                 tabext,
592                                EwaldCorrectionTables*     coulombTables,
593                                EwaldCorrectionTables*     vdwTables)
594 {
595     const bool useCoulombTable = (EEL_PME_EWALD(ic.eeltype) && coulombTables != nullptr);
596     const bool useVdwTable     = (EVDW_PME(ic.vdwtype) && vdwTables != nullptr);
597
598     /* Get the Ewald table spacing based on Coulomb and/or LJ
599      * Ewald coefficients and rtol.
600      */
601     const real tableScale = ewald_spline3_table_scale(ic, useCoulombTable, useVdwTable);
602
603     const bool havePerturbedNonbondeds = (ic.softCoreParameters != nullptr);
604
605     real tableLen = ic.rcoulomb;
606     if ((useCoulombTable || useVdwTable) && havePerturbedNonbondeds && rlist + tabext > 0.0)
607     {
608         /* TODO: Ideally this should also check if couple-intramol == no, but that isn't
609          * stored in ir. Grompp puts that info into an opts structure that doesn't make it into the tpr.
610          * The alternative is to look through all the exclusions and check if they come from
611          * couple-intramol == no. Meanwhile, always having larger tables should only affect
612          * memory consumption, not speed (barring cache issues).
613          */
614         tableLen = rlist + tabext;
615     }
616     const int tableSize = static_cast<int>(tableLen * tableScale) + 2;
617
618     if (useCoulombTable)
619     {
620         *coulombTables =
621                 generateEwaldCorrectionTables(tableSize, tableScale, ic.ewaldcoeff_q, v_q_ewald_lr);
622     }
623
624     if (useVdwTable)
625     {
626         *vdwTables = generateEwaldCorrectionTables(tableSize, tableScale, ic.ewaldcoeff_lj, v_lj_ewald_lr);
627     }
628 }
629
630 void init_interaction_const_tables(FILE* fp, interaction_const_t* ic, const real rlist, const real tableExtensionLength)
631 {
632     if (EEL_PME_EWALD(ic->eeltype) || EVDW_PME(ic->vdwtype))
633     {
634         init_ewald_f_table(
635                 *ic, rlist, tableExtensionLength, ic->coulombEwaldTables.get(), ic->vdwEwaldTables.get());
636         if (fp != nullptr)
637         {
638             fprintf(fp,
639                     "Initialized non-bonded Ewald tables, spacing: %.2e size: %zu\n\n",
640                     1 / ic->coulombEwaldTables->scale,
641                     ic->coulombEwaldTables->tableF.size());
642         }
643     }
644 }
645
646 real cutoff_inf(real cutoff)
647 {
648     if (cutoff == 0)
649     {
650         cutoff = GMX_CUTOFF_INF;
651     }
652
653     return cutoff;
654 }
655
656 void init_forcerec(FILE*                            fplog,
657                    const gmx::MDLogger&             mdlog,
658                    const gmx::SimulationWorkload&   simulationWork,
659                    t_forcerec*                      forcerec,
660                    const t_inputrec&                inputrec,
661                    const gmx_mtop_t&                mtop,
662                    const t_commrec*                 commrec,
663                    matrix                           box,
664                    const char*                      tabfn,
665                    const char*                      tabpfn,
666                    gmx::ArrayRef<const std::string> tabbfnm,
667                    real                             print_force)
668 {
669     /* The CMake default turns SIMD kernels on, but it might be turned off further down... */
670     forcerec->use_simd_kernels = GMX_USE_SIMD_KERNELS;
671
672     if (check_box(inputrec.pbcType, box))
673     {
674         gmx_fatal(FARGS, "%s", check_box(inputrec.pbcType, box));
675     }
676
677     /* Test particle insertion ? */
678     if (EI_TPI(inputrec.eI))
679     {
680         /* Set to the size of the molecule to be inserted (the last one) */
681         gmx::RangePartitioning molecules = gmx_mtop_molecules(mtop);
682         forcerec->n_tpi                  = molecules.block(molecules.numBlocks() - 1).size();
683     }
684     else
685     {
686         forcerec->n_tpi = 0;
687     }
688
689     if (inputrec.coulombtype == CoulombInteractionType::RFNecUnsupported
690         || inputrec.coulombtype == CoulombInteractionType::GRFNotused)
691     {
692         gmx_fatal(FARGS, "%s electrostatics is no longer supported", enumValueToString(inputrec.coulombtype));
693     }
694
695     if (inputrec.bAdress)
696     {
697         gmx_fatal(FARGS, "AdResS simulations are no longer supported");
698     }
699     if (inputrec.useTwinRange)
700     {
701         gmx_fatal(FARGS, "Twin-range simulations are no longer supported");
702     }
703     /* Copy the user determined parameters */
704     forcerec->userint1  = inputrec.userint1;
705     forcerec->userint2  = inputrec.userint2;
706     forcerec->userint3  = inputrec.userint3;
707     forcerec->userint4  = inputrec.userint4;
708     forcerec->userreal1 = inputrec.userreal1;
709     forcerec->userreal2 = inputrec.userreal2;
710     forcerec->userreal3 = inputrec.userreal3;
711     forcerec->userreal4 = inputrec.userreal4;
712
713     /* Shell stuff */
714     forcerec->fc_stepsize = inputrec.fc_stepsize;
715
716     /* Free energy */
717     forcerec->efep = inputrec.efep;
718
719     if ((getenv("GMX_DISABLE_SIMD_KERNELS") != nullptr) || (getenv("GMX_NOOPTIMIZEDKERNELS") != nullptr))
720     {
721         forcerec->use_simd_kernels = FALSE;
722         if (fplog != nullptr)
723         {
724             fprintf(fplog,
725                     "\nFound environment variable GMX_DISABLE_SIMD_KERNELS.\n"
726                     "Disabling the usage of any SIMD-specific non-bonded & bonded kernel routines\n"
727                     "(e.g. SSE2/SSE4.1/AVX).\n\n");
728         }
729     }
730
731     forcerec->haveBuckingham = (mtop.ffparams.functype[0] == F_BHAM);
732
733     /* Neighbour searching stuff */
734     forcerec->pbcType = inputrec.pbcType;
735
736     /* Determine if we will do PBC for distances in bonded interactions */
737     if (forcerec->pbcType == PbcType::No)
738     {
739         forcerec->bMolPBC = FALSE;
740     }
741     else
742     {
743         forcerec->bMolPBC = (!DOMAINDECOMP(commrec) || dd_bonded_molpbc(*commrec->dd, forcerec->pbcType));
744
745         // Check and set up PBC for Ewald surface corrections or orientation restraints
746         const bool useEwaldSurfaceCorrection =
747                 (EEL_PME_EWALD(inputrec.coulombtype) && inputrec.epsilon_surface != 0);
748         const bool haveOrientationRestraints = (gmx_mtop_ftype_count(mtop, F_ORIRES) > 0);
749         const bool moleculesAreAlwaysWhole =
750                 (DOMAINDECOMP(commrec) && dd_moleculesAreAlwaysWhole(*commrec->dd));
751         // WholeMoleculeTransform is only supported with a single PP rank
752         if (!moleculesAreAlwaysWhole && !havePPDomainDecomposition(commrec)
753             && (useEwaldSurfaceCorrection || haveOrientationRestraints))
754         {
755             if (havePPDomainDecomposition(commrec))
756             {
757                 gmx_fatal(FARGS,
758                           "You requested Ewald surface correction or orientation restraints, "
759                           "but molecules are broken "
760                           "over periodic boundary conditions by the domain decomposition. "
761                           "Run without domain decomposition instead.");
762             }
763
764             forcerec->wholeMoleculeTransform = std::make_unique<gmx::WholeMoleculeTransform>(
765                     mtop, inputrec.pbcType, DOMAINDECOMP(commrec));
766         }
767
768         forcerec->bMolPBC = !DOMAINDECOMP(commrec) || dd_bonded_molpbc(*commrec->dd, forcerec->pbcType);
769
770         if (useEwaldSurfaceCorrection)
771         {
772             GMX_RELEASE_ASSERT(moleculesAreAlwaysWhole || forcerec->wholeMoleculeTransform,
773                                "Molecules can not be broken by PBC with epsilon_surface > 0");
774         }
775     }
776
777     forcerec->rc_scaling = inputrec.refcoord_scaling;
778     copy_rvec(inputrec.posres_com, forcerec->posres_com);
779     copy_rvec(inputrec.posres_comB, forcerec->posres_comB);
780     forcerec->rlist                  = cutoff_inf(inputrec.rlist);
781     forcerec->ljpme_combination_rule = inputrec.ljpme_combination_rule;
782
783     /* This now calculates sum for q and c6*/
784     bool systemHasNetCharge = set_chargesum(fplog, forcerec, mtop);
785
786     /* Make data structure used by kernels */
787     forcerec->ic = std::make_unique<interaction_const_t>(
788             init_interaction_const(fplog, inputrec, mtop, systemHasNetCharge));
789     init_interaction_const_tables(fplog, forcerec->ic.get(), forcerec->rlist, inputrec.tabext);
790
791     const interaction_const_t* interactionConst = forcerec->ic.get();
792
793     /* TODO: Replace this Ewald table or move it into interaction_const_t */
794     if (inputrec.coulombtype == CoulombInteractionType::Ewald)
795     {
796         forcerec->ewald_table = std::make_unique<gmx_ewald_tab_t>(inputrec, fplog);
797     }
798
799     /* Electrostatics: Translate from interaction-setting-in-mdp-file to kernel interaction format */
800     switch (interactionConst->eeltype)
801     {
802         case CoulombInteractionType::Cut:
803             forcerec->nbkernel_elec_interaction = NbkernelElecType::Coulomb;
804             break;
805
806         case CoulombInteractionType::RF:
807         case CoulombInteractionType::RFZero:
808             forcerec->nbkernel_elec_interaction = NbkernelElecType::ReactionField;
809             break;
810
811         case CoulombInteractionType::Switch:
812         case CoulombInteractionType::Shift:
813         case CoulombInteractionType::User:
814         case CoulombInteractionType::PmeSwitch:
815         case CoulombInteractionType::PmeUser:
816         case CoulombInteractionType::PmeUserSwitch:
817             forcerec->nbkernel_elec_interaction = NbkernelElecType::CubicSplineTable;
818             break;
819
820         case CoulombInteractionType::Pme:
821         case CoulombInteractionType::P3mAD:
822         case CoulombInteractionType::Ewald:
823             forcerec->nbkernel_elec_interaction = NbkernelElecType::Ewald;
824             break;
825
826         default:
827             gmx_fatal(FARGS,
828                       "Unsupported electrostatic interaction: %s",
829                       enumValueToString(interactionConst->eeltype));
830     }
831     forcerec->nbkernel_elec_modifier = interactionConst->coulomb_modifier;
832
833     /* Vdw: Translate from mdp settings to kernel format */
834     switch (interactionConst->vdwtype)
835     {
836         case VanDerWaalsType::Cut:
837             if (forcerec->haveBuckingham)
838             {
839                 forcerec->nbkernel_vdw_interaction = NbkernelVdwType::Buckingham;
840             }
841             else
842             {
843                 forcerec->nbkernel_vdw_interaction = NbkernelVdwType::LennardJones;
844             }
845             break;
846         case VanDerWaalsType::Pme:
847             forcerec->nbkernel_vdw_interaction = NbkernelVdwType::LJEwald;
848             break;
849
850         case VanDerWaalsType::Switch:
851         case VanDerWaalsType::Shift:
852         case VanDerWaalsType::User:
853             forcerec->nbkernel_vdw_interaction = NbkernelVdwType::CubicSplineTable;
854             break;
855
856         default:
857             gmx_fatal(FARGS, "Unsupported vdw interaction: %s", enumValueToString(interactionConst->vdwtype));
858     }
859     forcerec->nbkernel_vdw_modifier = interactionConst->vdw_modifier;
860
861     if (!gmx_within_tol(interactionConst->reppow, 12.0, 10 * GMX_DOUBLE_EPS))
862     {
863         gmx_fatal(FARGS, "Only LJ repulsion power 12 is supported");
864     }
865     /* Older tpr files can contain Coulomb user tables with the Verlet cutoff-scheme,
866      * while mdrun does not (and never did) support this.
867      */
868     if (EEL_USER(forcerec->ic->eeltype))
869     {
870         gmx_fatal(FARGS,
871                   "Electrostatics type %s is currently not supported",
872                   enumValueToString(inputrec.coulombtype));
873     }
874
875     /* 1-4 interaction electrostatics */
876     forcerec->fudgeQQ = mtop.ffparams.fudgeQQ;
877
878     if (simulationWork.useMts)
879     {
880         GMX_ASSERT(gmx::checkMtsRequirements(inputrec).empty(),
881                    "All MTS requirements should be met here");
882     }
883
884     const bool haveDirectVirialContributionsFast =
885             forcerec->forceProviders->hasForceProvider() || gmx_mtop_ftype_count(mtop, F_POSRES) > 0
886             || gmx_mtop_ftype_count(mtop, F_FBPOSRES) > 0 || inputrec.nwall > 0 || inputrec.bPull
887             || inputrec.bRot || inputrec.bIMD;
888     const bool haveDirectVirialContributionsSlow =
889             EEL_FULL(interactionConst->eeltype) || EVDW_PME(interactionConst->vdwtype);
890     for (int i = 0; i < (simulationWork.useMts ? 2 : 1); i++)
891     {
892         bool haveDirectVirialContributions =
893                 (((!simulationWork.useMts || i == 0) && haveDirectVirialContributionsFast)
894                  || ((!simulationWork.useMts || i == 1) && haveDirectVirialContributionsSlow));
895         forcerec->forceHelperBuffers.emplace_back(haveDirectVirialContributions);
896     }
897
898     if (forcerec->shift_vec.empty())
899     {
900         forcerec->shift_vec.resize(gmx::c_numShiftVectors);
901     }
902
903     GMX_ASSERT(forcerec->nbfp.empty(), "The nonbonded force parameters should not be set up yet.");
904     forcerec->ntype = mtop.ffparams.atnr;
905     forcerec->nbfp  = makeNonBondedParameterLists(
906             mtop.ffparams.atnr, mtop.ffparams.iparams, forcerec->haveBuckingham);
907     if (EVDW_PME(interactionConst->vdwtype))
908     {
909         forcerec->ljpme_c6grid = makeLJPmeC6GridCorrectionParameters(
910                 mtop.ffparams.atnr, mtop.ffparams.iparams, forcerec->ljpme_combination_rule);
911     }
912
913     /* Copy the energy group exclusions */
914     forcerec->egp_flags = inputrec.opts.egp_flags;
915
916     /* Van der Waals stuff */
917     if ((interactionConst->vdwtype != VanDerWaalsType::Cut)
918         && (interactionConst->vdwtype != VanDerWaalsType::User) && !forcerec->haveBuckingham)
919     {
920         if (interactionConst->rvdw_switch >= interactionConst->rvdw)
921         {
922             gmx_fatal(FARGS,
923                       "rvdw_switch (%f) must be < rvdw (%f)",
924                       interactionConst->rvdw_switch,
925                       interactionConst->rvdw);
926         }
927         if (fplog)
928         {
929             fprintf(fplog,
930                     "Using %s Lennard-Jones, switch between %g and %g nm\n",
931                     (interactionConst->eeltype == CoulombInteractionType::Switch) ? "switched" : "shifted",
932                     interactionConst->rvdw_switch,
933                     interactionConst->rvdw);
934         }
935     }
936
937     if (forcerec->haveBuckingham && EVDW_PME(interactionConst->vdwtype))
938     {
939         gmx_fatal(FARGS, "LJ PME not supported with Buckingham");
940     }
941
942     if (forcerec->haveBuckingham
943         && (interactionConst->vdwtype == VanDerWaalsType::Shift
944             || interactionConst->vdwtype == VanDerWaalsType::Switch))
945     {
946         gmx_fatal(FARGS, "Switch/shift interaction not supported with Buckingham");
947     }
948
949     if (forcerec->haveBuckingham)
950     {
951         gmx_fatal(FARGS, "The Verlet cutoff-scheme does not (yet) support Buckingham");
952     }
953
954     if (inputrec.implicit_solvent)
955     {
956         gmx_fatal(FARGS, "Implict solvation is no longer supported.");
957     }
958
959
960     /* This code automatically gives table length tabext without cut-off's,
961      * in that case grompp should already have checked that we do not need
962      * normal tables and we only generate tables for 1-4 interactions.
963      */
964     real rtab = inputrec.rlist + inputrec.tabext;
965
966     /* We want to use unmodified tables for 1-4 coulombic
967      * interactions, so we must in general have an extra set of
968      * tables. */
969     if (gmx_mtop_ftype_count(mtop, F_LJ14) > 0 || gmx_mtop_ftype_count(mtop, F_LJC14_Q) > 0
970         || gmx_mtop_ftype_count(mtop, F_LJC_PAIRS_NB) > 0)
971     {
972         forcerec->pairsTable = make_tables(fplog, interactionConst, tabpfn, rtab, GMX_MAKETABLES_14ONLY);
973     }
974
975     /* Wall stuff */
976     forcerec->nwall = inputrec.nwall;
977     if (inputrec.nwall && inputrec.wall_type == WallType::Table)
978     {
979         make_wall_tables(fplog, inputrec, tabfn, &mtop.groups, forcerec);
980     }
981
982     forcerec->fcdata = std::make_unique<t_fcdata>();
983
984     if (!tabbfnm.empty())
985     {
986         t_fcdata& fcdata = *forcerec->fcdata;
987         // Need to catch std::bad_alloc
988         // TODO Don't need to catch this here, when merging with master branch
989         try
990         {
991             // TODO move these tables into a separate struct and store reference in ListedForces
992             fcdata.bondtab = make_bonded_tables(fplog, F_TABBONDS, F_TABBONDSNC, mtop, tabbfnm, "b");
993             fcdata.angletab = make_bonded_tables(fplog, F_TABANGLES, -1, mtop, tabbfnm, "a");
994             fcdata.dihtab   = make_bonded_tables(fplog, F_TABDIHS, -1, mtop, tabbfnm, "d");
995         }
996         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
997     }
998     else
999     {
1000         if (debug)
1001         {
1002             fprintf(debug,
1003                     "No fcdata or table file name passed, can not read table, can not do bonded "
1004                     "interactions\n");
1005         }
1006     }
1007
1008     /* Initialize the thread working data for bonded interactions */
1009     if (simulationWork.useMts)
1010     {
1011         // Add one ListedForces object for each MTS level
1012         bool isFirstLevel = true;
1013         for (const auto& mtsLevel : inputrec.mtsLevels)
1014         {
1015             ListedForces::InteractionSelection interactionSelection;
1016             const auto&                        forceGroups = mtsLevel.forceGroups;
1017             if (forceGroups[static_cast<int>(gmx::MtsForceGroups::Pair)])
1018             {
1019                 interactionSelection.set(static_cast<int>(ListedForces::InteractionGroup::Pairs));
1020             }
1021             if (forceGroups[static_cast<int>(gmx::MtsForceGroups::Dihedral)])
1022             {
1023                 interactionSelection.set(static_cast<int>(ListedForces::InteractionGroup::Dihedrals));
1024             }
1025             if (forceGroups[static_cast<int>(gmx::MtsForceGroups::Angle)])
1026             {
1027                 interactionSelection.set(static_cast<int>(ListedForces::InteractionGroup::Angles));
1028             }
1029             if (isFirstLevel)
1030             {
1031                 interactionSelection.set(static_cast<int>(ListedForces::InteractionGroup::Rest));
1032                 isFirstLevel = false;
1033             }
1034             forcerec->listedForces.emplace_back(
1035                     mtop.ffparams,
1036                     mtop.groups.groups[SimulationAtomGroupType::EnergyOutput].size(),
1037                     gmx_omp_nthreads_get(ModuleMultiThread::Bonded),
1038                     interactionSelection,
1039                     fplog);
1040         }
1041     }
1042     else
1043     {
1044         // Add one ListedForces object with all listed interactions
1045         forcerec->listedForces.emplace_back(
1046                 mtop.ffparams,
1047                 mtop.groups.groups[SimulationAtomGroupType::EnergyOutput].size(),
1048                 gmx_omp_nthreads_get(ModuleMultiThread::Bonded),
1049                 ListedForces::interactionSelectionAll(),
1050                 fplog);
1051     }
1052
1053     // QM/MM initialization if requested
1054     if (inputrec.bQMMM)
1055     {
1056         gmx_incons("QM/MM was requested, but is no longer available in GROMACS");
1057     }
1058
1059     /* Set all the static charge group info */
1060     forcerec->atomInfoForEachMoleculeBlock = makeAtomInfoForEachMoleculeBlock(mtop, forcerec);
1061     if (!DOMAINDECOMP(commrec))
1062     {
1063         forcerec->atomInfo = expandAtomInfo(mtop.molblock.size(), forcerec->atomInfoForEachMoleculeBlock);
1064     }
1065
1066     if (!DOMAINDECOMP(commrec))
1067     {
1068         forcerec_set_ranges(forcerec, mtop.natoms, mtop.natoms, mtop.natoms);
1069     }
1070
1071     forcerec->print_force = print_force;
1072
1073     forcerec->nthread_ewc = gmx_omp_nthreads_get(ModuleMultiThread::Bonded);
1074     forcerec->ewc_t.resize(forcerec->nthread_ewc);
1075
1076     if (inputrec.eDispCorr != DispersionCorrectionType::No)
1077     {
1078         forcerec->dispersionCorrection = std::make_unique<DispersionCorrection>(
1079                 mtop, inputrec, forcerec->haveBuckingham, forcerec->ntype, forcerec->nbfp, *forcerec->ic, tabfn);
1080         forcerec->dispersionCorrection->print(mdlog);
1081     }
1082
1083     if (fplog != nullptr)
1084     {
1085         /* Here we switch from using mdlog, which prints the newline before
1086          * the paragraph, to our old fprintf logging, which prints the newline
1087          * after the paragraph, so we should add a newline here.
1088          */
1089         fprintf(fplog, "\n");
1090     }
1091 }
1092
1093 t_forcerec::t_forcerec() = default;
1094
1095 t_forcerec::~t_forcerec() = default;