14402aca91c080e2f080d9c2db47e39b9e3d3359
[alexxy/gromacs.git] / src / gromacs / nbnxm / kerneldispatch.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2012,2013,2014,2015,2016,2017,2018,2019, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35
36 #include "gmxpre.h"
37
38 #include "gromacs/gmxlib/nrnb.h"
39 #include "gromacs/math/vectypes.h"
40 #include "gromacs/mdlib/force_flags.h"
41 #include "gromacs/mdlib/gmx_omp_nthreads.h"
42 #include "gromacs/mdtypes/enerdata.h"
43 #include "gromacs/mdtypes/interaction_const.h"
44 #include "gromacs/mdtypes/md_enums.h"
45 #include "gromacs/nbnxm/gpu_data_mgmt.h"
46 #include "gromacs/nbnxm/nbnxm.h"
47 #include "gromacs/nbnxm/nbnxm_simd.h"
48 #include "gromacs/nbnxm/kernels_reference/kernel_gpu_ref.h"
49 #include "gromacs/simd/simd.h"
50 #include "gromacs/utility/gmxassert.h"
51 #include "gromacs/utility/real.h"
52
53 #include "kernel_common.h"
54 #define INCLUDE_KERNELFUNCTION_TABLES
55 #include "gromacs/nbnxm/kernels_reference/kernel_ref.h"
56 #ifdef GMX_NBNXN_SIMD_2XNN
57 #include "gromacs/nbnxm/kernels_simd_2xmm/kernels.h"
58 #endif
59 #ifdef GMX_NBNXN_SIMD_4XN
60 #include "gromacs/nbnxm/kernels_simd_4xm/kernels.h"
61 #endif
62 #undef INCLUDE_FUNCTION_TABLES
63
64 /*! \brief Clears the energy group output buffers
65  *
66  * \param[in,out] out  nbnxn kernel output struct
67  */
68 static void clearGroupEnergies(nbnxn_atomdata_output_t *out)
69 {
70     std::fill(out->Vvdw.begin(), out->Vvdw.end(), 0.0_real);
71     std::fill(out->Vc.begin(), out->Vc.end(), 0.0_real);
72     std::fill(out->VSvdw.begin(), out->VSvdw.end(), 0.0_real);
73     std::fill(out->VSc.begin(), out->VSc.end(), 0.0_real);
74 }
75
76 /*! \brief Reduce the group-pair energy buffers produced by a SIMD kernel
77  * to single terms in the output buffers.
78  *
79  * The SIMD kernels produce a large number of energy buffer in SIMD registers
80  * to avoid scattered reads and writes.
81  *
82  * \tparam        unrollj         The unroll size for j-particles in the SIMD kernel
83  * \param[in]     numGroups       The number of energy groups
84  * \param[in]     numGroups_2log  Log2 of numGroups, rounded up
85  * \param[in,out] out             Struct with energy buffers
86  */
87 template <int unrollj> static void
88 reduceGroupEnergySimdBuffers(int                       numGroups,
89                              int                       numGroups_2log,
90                              nbnxn_atomdata_output_t  *out)
91 {
92     const int                 unrollj_half     = unrollj/2;
93     /* Energies are stored in SIMD registers with size 2^numGroups_2log */
94     const int                 numGroupsStorage = (1 << numGroups_2log);
95
96     const real * gmx_restrict vVdwSimd     = out->VSvdw.data();
97     const real * gmx_restrict vCoulombSimd = out->VSc.data();
98     real * gmx_restrict       vVdw         = out->Vvdw.data();
99     real * gmx_restrict       vCoulomb     = out->Vc.data();
100
101     /* The size of the SIMD energy group buffer array is:
102      * numGroups*numGroups*numGroupsStorage*unrollj_half*simd_width
103      */
104     for (int i = 0; i < numGroups; i++)
105     {
106         for (int j1 = 0; j1 < numGroups; j1++)
107         {
108             for (int j0 = 0; j0 < numGroups; j0++)
109             {
110                 int c = ((i*numGroups + j1)*numGroupsStorage + j0)*unrollj_half*unrollj;
111                 for (int s = 0; s < unrollj_half; s++)
112                 {
113                     vVdw    [i*numGroups + j0] += vVdwSimd    [c + 0];
114                     vVdw    [i*numGroups + j1] += vVdwSimd    [c + 1];
115                     vCoulomb[i*numGroups + j0] += vCoulombSimd[c + 0];
116                     vCoulomb[i*numGroups + j1] += vCoulombSimd[c + 1];
117                     c                          += unrollj + 2;
118                 }
119             }
120         }
121     }
122 }
123
124 /*! \brief Dispatches the non-bonded N versus M atom cluster CPU kernels.
125  *
126  * OpenMP parallelization is performed within this function.
127  * Energy reduction, but not force and shift force reduction, is performed
128  * within this function.
129  *
130  * \param[in]     nbvg          The group (local/non-local) to compute interaction for
131  * \param[in,out] nbat          The atomdata for the interactions
132  * \param[in]     ic            Non-bonded interaction constants
133  * \param[in]     shiftVectors  The PBC shift vectors
134  * \param[in]     forceFlags    Flags that tell what to compute
135  * \param[in]     clearF        Enum that tells if to clear the force output buffer
136  * \param[out]    fshift        Shift force output buffer
137  * \param[out]    vCoulomb      Output buffer for Coulomb energies
138  * \param[out]    vVdw          Output buffer for Van der Waals energies
139  */
140 static void
141 nbnxn_kernel_cpu(const nonbonded_verlet_group_t *nbvg,
142                  nbnxn_atomdata_t               *nbat,
143                  const interaction_const_t      &ic,
144                  rvec                           *shiftVectors,
145                  int                             forceFlags,
146                  int                             clearF,
147                  real                           *fshift,
148                  real                           *vCoulomb,
149                  real                           *vVdw)
150 {
151
152     int                      coulkt;
153     if (EEL_RF(ic.eeltype) || ic.eeltype == eelCUT)
154     {
155         coulkt = coulktRF;
156     }
157     else
158     {
159         if (nbvg->ewald_excl == ewaldexclTable)
160         {
161             if (ic.rcoulomb == ic.rvdw)
162             {
163                 coulkt = coulktTAB;
164             }
165             else
166             {
167                 coulkt = coulktTAB_TWIN;
168             }
169         }
170         else
171         {
172             if (ic.rcoulomb == ic.rvdw)
173             {
174                 coulkt = coulktEWALD;
175             }
176             else
177             {
178                 coulkt = coulktEWALD_TWIN;
179             }
180         }
181     }
182
183     const nbnxn_atomdata_t::Params &nbatParams = nbat->params();
184
185     int vdwkt = 0;
186     if (ic.vdwtype == evdwCUT)
187     {
188         switch (ic.vdw_modifier)
189         {
190             case eintmodNONE:
191             case eintmodPOTSHIFT:
192                 switch (nbatParams.comb_rule)
193                 {
194                     case ljcrGEOM: vdwkt = vdwktLJCUT_COMBGEOM; break;
195                     case ljcrLB:   vdwkt = vdwktLJCUT_COMBLB;   break;
196                     case ljcrNONE: vdwkt = vdwktLJCUT_COMBNONE; break;
197                     default:
198                         GMX_RELEASE_ASSERT(false, "Unknown combination rule");
199                 }
200                 break;
201             case eintmodFORCESWITCH:
202                 vdwkt = vdwktLJFORCESWITCH;
203                 break;
204             case eintmodPOTSWITCH:
205                 vdwkt = vdwktLJPOTSWITCH;
206                 break;
207             default:
208                 GMX_RELEASE_ASSERT(false, "Unsupported VdW interaction modifier");
209         }
210     }
211     else if (ic.vdwtype == evdwPME)
212     {
213         if (ic.ljpme_comb_rule == eljpmeGEOM)
214         {
215             vdwkt = vdwktLJEWALDCOMBGEOM;
216         }
217         else
218         {
219             vdwkt = vdwktLJEWALDCOMBLB;
220             /* At setup we (should have) selected the C reference kernel */
221             GMX_RELEASE_ASSERT(nbvg->kernel_type == nbnxnk4x4_PlainC, "Only the C reference nbnxn SIMD kernel supports LJ-PME with LB combination rules");
222         }
223     }
224     else
225     {
226         GMX_RELEASE_ASSERT(false, "Unsupported VdW interaction type");
227     }
228
229     int                        nnbl = nbvg->nbl_lists.nnbl;
230     NbnxnPairlistCpu * const * nbl  = nbvg->nbl_lists.nbl;
231
232     int gmx_unused             nthreads = gmx_omp_nthreads_get(emntNonbonded);
233 #pragma omp parallel for schedule(static) num_threads(nthreads)
234     for (int nb = 0; nb < nnbl; nb++)
235     {
236         // Presently, the kernels do not call C++ code that can throw,
237         // so no need for a try/catch pair in this OpenMP region.
238         nbnxn_atomdata_output_t *out = &nbat->out[nb];
239
240         if (clearF == enbvClearFYes)
241         {
242             clear_f(nbat, nb, out->f.data());
243         }
244
245         real *fshift_p;
246         if ((forceFlags & GMX_FORCE_VIRIAL) && nnbl == 1)
247         {
248             fshift_p = fshift;
249         }
250         else
251         {
252             fshift_p = out->fshift.data();
253
254             if (clearF == enbvClearFYes)
255             {
256                 clear_fshift(fshift_p);
257             }
258         }
259
260         if (!(forceFlags & GMX_FORCE_ENERGY))
261         {
262             /* Don't calculate energies */
263             switch (nbvg->kernel_type)
264             {
265                 case nbnxnk4x4_PlainC:
266                     nbnxn_kernel_noener_ref[coulkt][vdwkt](nbl[nb], nbat,
267                                                            &ic,
268                                                            shiftVectors,
269                                                            out->f.data(),
270                                                            fshift_p);
271                     break;
272 #ifdef GMX_NBNXN_SIMD_2XNN
273                 case nbnxnk4xN_SIMD_2xNN:
274                     nbnxm_kernel_noener_simd_2xmm[coulkt][vdwkt](nbl[nb], nbat,
275                                                                  &ic,
276                                                                  shiftVectors,
277                                                                  out->f.data(),
278                                                                  fshift_p);
279                     break;
280 #endif
281 #ifdef GMX_NBNXN_SIMD_4XN
282                 case nbnxnk4xN_SIMD_4xN:
283                     nbnxm_kernel_noener_simd_4xm[coulkt][vdwkt](nbl[nb], nbat,
284                                                                 &ic,
285                                                                 shiftVectors,
286                                                                 out->f.data(),
287                                                                 fshift_p);
288                     break;
289 #endif
290                 default:
291                     GMX_RELEASE_ASSERT(false, "Unsupported kernel architecture");
292             }
293         }
294         else if (out->Vvdw.size() == 1)
295         {
296             /* A single energy group (pair) */
297             out->Vvdw[0] = 0;
298             out->Vc[0]   = 0;
299
300             switch (nbvg->kernel_type)
301             {
302                 case nbnxnk4x4_PlainC:
303                     nbnxn_kernel_ener_ref[coulkt][vdwkt](nbl[nb], nbat,
304                                                          &ic,
305                                                          shiftVectors,
306                                                          out->f.data(),
307                                                          fshift_p,
308                                                          out->Vvdw.data(),
309                                                          out->Vc.data());
310                     break;
311 #ifdef GMX_NBNXN_SIMD_2XNN
312                 case nbnxnk4xN_SIMD_2xNN:
313                     nbnxm_kernel_ener_simd_2xmm[coulkt][vdwkt](nbl[nb], nbat,
314                                                                &ic,
315                                                                shiftVectors,
316                                                                out->f.data(),
317                                                                fshift_p,
318                                                                out->Vvdw.data(),
319                                                                out->Vc.data());
320                     break;
321 #endif
322 #ifdef GMX_NBNXN_SIMD_4XN
323                 case nbnxnk4xN_SIMD_4xN:
324                     nbnxm_kernel_ener_simd_4xm[coulkt][vdwkt](nbl[nb], nbat,
325                                                               &ic,
326                                                               shiftVectors,
327                                                               out->f.data(),
328                                                               fshift_p,
329                                                               out->Vvdw.data(),
330                                                               out->Vc.data());
331                     break;
332 #endif
333                 default:
334                     GMX_RELEASE_ASSERT(false, "Unsupported kernel architecture");
335             }
336         }
337         else
338         {
339             /* Calculate energy group contributions */
340             clearGroupEnergies(out);
341
342             int unrollj = 0;
343
344             switch (nbvg->kernel_type)
345             {
346                 case nbnxnk4x4_PlainC:
347                     unrollj = c_nbnxnCpuIClusterSize;
348                     nbnxn_kernel_energrp_ref[coulkt][vdwkt](nbl[nb], nbat,
349                                                             &ic,
350                                                             shiftVectors,
351                                                             out->f.data(),
352                                                             fshift_p,
353                                                             out->Vvdw.data(),
354                                                             out->Vc.data());
355                     break;
356 #ifdef GMX_NBNXN_SIMD_2XNN
357                 case nbnxnk4xN_SIMD_2xNN:
358                     unrollj = GMX_SIMD_REAL_WIDTH/2;
359                     nbnxm_kernel_energrp_simd_2xmm[coulkt][vdwkt](nbl[nb], nbat,
360                                                                   &ic,
361                                                                   shiftVectors,
362                                                                   out->f.data(),
363                                                                   fshift_p,
364                                                                   out->VSvdw.data(),
365                                                                   out->VSc.data());
366                     break;
367 #endif
368 #ifdef GMX_NBNXN_SIMD_4XN
369                 case nbnxnk4xN_SIMD_4xN:
370                     unrollj = GMX_SIMD_REAL_WIDTH;
371                     nbnxm_kernel_energrp_simd_4xm[coulkt][vdwkt](nbl[nb], nbat,
372                                                                  &ic,
373                                                                  shiftVectors,
374                                                                  out->f.data(),
375                                                                  fshift_p,
376                                                                  out->VSvdw.data(),
377                                                                  out->VSc.data());
378                     break;
379 #endif
380                 default:
381                     GMX_RELEASE_ASSERT(false, "Unsupported kernel architecture");
382             }
383
384             if (nbvg->kernel_type != nbnxnk4x4_PlainC)
385             {
386                 switch (unrollj)
387                 {
388                     case 2:
389                         reduceGroupEnergySimdBuffers<2>(nbatParams.nenergrp,
390                                                         nbatParams.neg_2log,
391                                                         out);
392                         break;
393                     case 4:
394                         reduceGroupEnergySimdBuffers<4>(nbatParams.nenergrp,
395                                                         nbatParams.neg_2log,
396                                                         out);
397                         break;
398                     case 8:
399                         reduceGroupEnergySimdBuffers<8>(nbatParams.nenergrp,
400                                                         nbatParams.neg_2log,
401                                                         out);
402                         break;
403                     default:
404                         GMX_RELEASE_ASSERT(false, "Unsupported j-unroll size");
405                 }
406             }
407         }
408     }
409
410     if (forceFlags & GMX_FORCE_ENERGY)
411     {
412         reduce_energies_over_lists(nbat, nnbl, vVdw, vCoulomb);
413     }
414 }
415
416 static void accountFlops(t_nrnb                           *nrnb,
417                          const nonbonded_verlet_t         &nbv,
418                          const Nbnxm::InteractionLocality  iLocality,
419                          const interaction_const_t        &ic,
420                          const int                         forceFlags)
421 {
422     const nonbonded_verlet_group_t &nbvg            = nbv.grp[iLocality];
423     const bool                      usingGpuKernels = (nbvg.kernel_type == nbnxnk8x8x8_GPU);
424
425     int enr_nbnxn_kernel_ljc;
426     if (EEL_RF(ic.eeltype) || ic.eeltype == eelCUT)
427     {
428         enr_nbnxn_kernel_ljc = eNR_NBNXN_LJ_RF;
429     }
430     else if ((!usingGpuKernels && nbvg.ewald_excl == ewaldexclAnalytical) ||
431              (usingGpuKernels && Nbnxm::gpu_is_kernel_ewald_analytical(nbv.gpu_nbv)))
432     {
433         enr_nbnxn_kernel_ljc = eNR_NBNXN_LJ_EWALD;
434     }
435     else
436     {
437         enr_nbnxn_kernel_ljc = eNR_NBNXN_LJ_TAB;
438     }
439     int enr_nbnxn_kernel_lj = eNR_NBNXN_LJ;
440     if (forceFlags & GMX_FORCE_ENERGY)
441     {
442         /* In eNR_??? the nbnxn F+E kernels are always the F kernel + 1 */
443         enr_nbnxn_kernel_ljc += 1;
444         enr_nbnxn_kernel_lj  += 1;
445     }
446
447     inc_nrnb(nrnb, enr_nbnxn_kernel_ljc,
448              nbvg.nbl_lists.natpair_ljq);
449     inc_nrnb(nrnb, enr_nbnxn_kernel_lj,
450              nbvg.nbl_lists.natpair_lj);
451     /* The Coulomb-only kernels are offset -eNR_NBNXN_LJ_RF+eNR_NBNXN_RF */
452     inc_nrnb(nrnb, enr_nbnxn_kernel_ljc-eNR_NBNXN_LJ_RF+eNR_NBNXN_RF,
453              nbvg.nbl_lists.natpair_q);
454
455     const bool calcEnergy = ((forceFlags & GMX_FORCE_ENERGY) != 0);
456     if (ic.vdw_modifier == eintmodFORCESWITCH)
457     {
458         /* We add up the switch cost separately */
459         inc_nrnb(nrnb, eNR_NBNXN_ADD_LJ_FSW + (calcEnergy ? 1 : 0),
460                  nbvg.nbl_lists.natpair_ljq + nbvg.nbl_lists.natpair_lj);
461     }
462     if (ic.vdw_modifier == eintmodPOTSWITCH)
463     {
464         /* We add up the switch cost separately */
465         inc_nrnb(nrnb, eNR_NBNXN_ADD_LJ_PSW + (calcEnergy ? 1 : 0),
466                  nbvg.nbl_lists.natpair_ljq + nbvg.nbl_lists.natpair_lj);
467     }
468     if (ic.vdwtype == evdwPME)
469     {
470         /* We add up the LJ Ewald cost separately */
471         inc_nrnb(nrnb, eNR_NBNXN_ADD_LJ_EWALD + (calcEnergy ? 1 : 0),
472                  nbvg.nbl_lists.natpair_ljq + nbvg.nbl_lists.natpair_lj);
473     }
474 }
475
476 void NbnxnDispatchKernel(nonbonded_verlet_t        *nbv,
477                          Nbnxm::InteractionLocality iLocality,
478                          const interaction_const_t &ic,
479                          int                        forceFlags,
480                          int                        clearF,
481                          t_forcerec                *fr,
482                          gmx_enerdata_t            *enerd,
483                          t_nrnb                    *nrnb)
484 {
485     const nonbonded_verlet_group_t &nbvg = nbv->grp[iLocality];
486
487     switch (nbvg.kernel_type)
488     {
489         case nbnxnk4x4_PlainC:
490         case nbnxnk4xN_SIMD_4xN:
491         case nbnxnk4xN_SIMD_2xNN:
492             nbnxn_kernel_cpu(&nbvg,
493                              nbv->nbat,
494                              ic,
495                              fr->shift_vec,
496                              forceFlags,
497                              clearF,
498                              fr->fshift[0],
499                              enerd->grpp.ener[egCOULSR],
500                              fr->bBHAM ?
501                              enerd->grpp.ener[egBHAMSR] :
502                              enerd->grpp.ener[egLJSR]);
503             break;
504
505         case nbnxnk8x8x8_GPU:
506             Nbnxm::gpu_launch_kernel(nbv->gpu_nbv, forceFlags, iLocality);
507             break;
508
509         case nbnxnk8x8x8_PlainC:
510             nbnxn_kernel_gpu_ref(nbvg.nbl_lists.nblGpu[0],
511                                  nbv->nbat, &ic,
512                                  fr->shift_vec,
513                                  forceFlags,
514                                  clearF,
515                                  nbv->nbat->out[0].f,
516                                  fr->fshift[0],
517                                  enerd->grpp.ener[egCOULSR],
518                                  fr->bBHAM ?
519                                  enerd->grpp.ener[egBHAMSR] :
520                                  enerd->grpp.ener[egLJSR]);
521             break;
522
523         default:
524             GMX_RELEASE_ASSERT(false, "Invalid nonbonded kernel type passed!");
525
526     }
527
528     accountFlops(nrnb, *nbv, iLocality, ic, forceFlags);
529 }