72a028be78af0c19af93a2f15b595b3a686cfb38
[alexxy/gromacs.git] / src / gromacs / nbnxm / pairlist.h
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 #ifndef GMX_NBNXM_PAIRLIST_H
37 #define GMX_NBNXM_PAIRLIST_H
38
39 #include "config.h"
40
41 #include <cstddef>
42
43 #include "gromacs/gpu_utils/hostallocator.h"
44 #include "gromacs/math/vectypes.h"
45 #include "gromacs/mdtypes/nblist.h"
46 #include "gromacs/utility/basedefinitions.h"
47 #include "gromacs/utility/bitmask.h"
48 #include "gromacs/utility/defaultinitializationallocator.h"
49 #include "gromacs/utility/enumerationhelpers.h"
50 #include "gromacs/utility/real.h"
51
52 // This file with constants is separate from this file to be able
53 // to include it during OpenCL jitting without including config.h
54 #include "gromacs/nbnxm/constants.h"
55
56 struct NbnxnListParameters;
57 struct NbnxnPairlistCpuWork;
58 struct NbnxnPairlistGpuWork;
59 struct tMPI_Atomic;
60
61 namespace Nbnxm
62 {
63 enum class KernelType;
64 }
65
66 /* Convenience type for vector with aligned memory */
67 template<typename T>
68 using AlignedVector = std::vector < T, gmx::AlignedAllocator < T>>;
69
70 /* Convenience type for vector that avoids initialization at resize() */
71 template<typename T>
72 using FastVector = std::vector < T, gmx::DefaultInitializationAllocator < T>>;
73
74 enum class PairlistType : int
75 {
76     Simple4x2,
77     Simple4x4,
78     Simple4x8,
79     Hierarchical8x8,
80     Count
81 };
82
83 static constexpr gmx::EnumerationArray<PairlistType, int> IClusterSizePerListType = { { 4, 4, 4, 8 } };
84 static constexpr gmx::EnumerationArray<PairlistType, int> JClusterSizePerListType = { { 2, 4, 8, 8 } };
85
86 /* With CPU kernels the i-cluster size is always 4 atoms. */
87 static constexpr int c_nbnxnCpuIClusterSize = 4;
88
89 /* With GPU kernels the i and j cluster size is 8 atoms for CUDA and can be set at compile time for OpenCL */
90 #if GMX_GPU == GMX_GPU_OPENCL
91 static constexpr int c_nbnxnGpuClusterSize = GMX_OPENCL_NB_CLUSTER_SIZE;
92 #else
93 static constexpr int c_nbnxnGpuClusterSize = 8;
94 #endif
95
96 /* The number of clusters in a pair-search cell, used for GPU */
97 static constexpr int c_gpuNumClusterPerCellZ = 2;
98 static constexpr int c_gpuNumClusterPerCellY = 2;
99 static constexpr int c_gpuNumClusterPerCellX = 2;
100 static constexpr int c_gpuNumClusterPerCell  = c_gpuNumClusterPerCellZ*c_gpuNumClusterPerCellY*c_gpuNumClusterPerCellX;
101
102
103 /* In CUDA the number of threads in a warp is 32 and we have cluster pairs
104  * of 8*8=64 atoms, so it's convenient to store data for cluster pair halves.
105  */
106 static constexpr int c_nbnxnGpuClusterpairSplit = 2;
107
108 /* The fixed size of the exclusion mask array for a half cluster pair */
109 static constexpr int c_nbnxnGpuExclSize = c_nbnxnGpuClusterSize*c_nbnxnGpuClusterSize/c_nbnxnGpuClusterpairSplit;
110
111 /* A buffer data structure of 64 bytes
112  * to be placed at the beginning and end of structs
113  * to avoid cache invalidation of the real contents
114  * of the struct by writes to neighboring memory.
115  */
116 typedef struct {
117     int dummy[16];
118 } gmx_cache_protect_t;
119
120 /* This is the actual cluster-pair list j-entry.
121  * cj is the j-cluster.
122  * The interaction bits in excl are indexed i-major, j-minor.
123  * The cj entries are sorted such that ones with exclusions come first.
124  * This means that once a full mask (=NBNXN_INTERACTION_MASK_ALL)
125  * is found, all subsequent j-entries in the i-entry also have full masks.
126  */
127 struct nbnxn_cj_t
128 {
129     int          cj;    /* The j-cluster                    */
130     unsigned int excl;  /* The exclusion (interaction) bits */
131 };
132
133 /* In nbnxn_ci_t the integer shift contains the shift in the lower 7 bits.
134  * The upper bits contain information for non-bonded kernel optimization.
135  * Simply calculating LJ and Coulomb for all pairs in a cluster pair is fine.
136  * But three flags can be used to skip interactions, currently only for subc=0
137  * !(shift & NBNXN_CI_DO_LJ(subc))   => we can skip LJ for all pairs
138  * shift & NBNXN_CI_HALF_LJ(subc)    => we can skip LJ for the second half of i
139  * !(shift & NBNXN_CI_DO_COUL(subc)) => we can skip Coulomb for all pairs
140  */
141 #define NBNXN_CI_SHIFT          127
142 #define NBNXN_CI_DO_LJ(subc)    (1<<(7+3*(subc)))
143 #define NBNXN_CI_HALF_LJ(subc)  (1<<(8+3*(subc)))
144 #define NBNXN_CI_DO_COUL(subc)  (1<<(9+3*(subc)))
145
146 /* Cluster-pair Interaction masks
147  * Bit i*j-cluster-size + j tells if atom i and j interact.
148  */
149 // TODO: Rename according to convention when moving into Nbnxn namespace
150 /* All interaction mask is the same for all kernels */
151 constexpr unsigned int NBNXN_INTERACTION_MASK_ALL       = 0xffffffffU;
152 /* 4x4 kernel diagonal mask */
153 constexpr unsigned int NBNXN_INTERACTION_MASK_DIAG      = 0x08ceU;
154 /* 4x2 kernel diagonal masks */
155 constexpr unsigned int NBNXN_INTERACTION_MASK_DIAG_J2_0 = 0x0002U;
156 constexpr unsigned int NBNXN_INTERACTION_MASK_DIAG_J2_1 = 0x002fU;
157 /* 4x8 kernel diagonal masks */
158 constexpr unsigned int NBNXN_INTERACTION_MASK_DIAG_J8_0 = 0xf0f8fcfeU;
159 constexpr unsigned int NBNXN_INTERACTION_MASK_DIAG_J8_1 = 0x0080c0e0U;
160
161 /* Simple pair-list i-unit */
162 struct nbnxn_ci_t
163 {
164     int ci;             /* i-cluster             */
165     int shift;          /* Shift vector index plus possible flags, see above */
166     int cj_ind_start;   /* Start index into cj   */
167     int cj_ind_end;     /* End index into cj     */
168 };
169
170 /* Grouped pair-list i-unit */
171 typedef struct {
172     /* Returns the number of j-cluster groups in this entry */
173     int numJClusterGroups() const
174     {
175         return cj4_ind_end - cj4_ind_start;
176     }
177
178     int sci;            /* i-super-cluster       */
179     int shift;          /* Shift vector index plus possible flags */
180     int cj4_ind_start;  /* Start index into cj4  */
181     int cj4_ind_end;    /* End index into cj4    */
182 } nbnxn_sci_t;
183
184 /* Interaction data for a j-group for one warp */
185 struct nbnxn_im_ei_t
186 {
187     // The i-cluster interactions mask for 1 warp
188     unsigned int imask    = 0U;
189     // Index into the exclusion array for 1 warp, default index 0 which means no exclusions
190     int          excl_ind = 0;
191 };
192
193 typedef struct {
194     int           cj[c_nbnxnGpuJgroupSize];         /* The 4 j-clusters */
195     nbnxn_im_ei_t imei[c_nbnxnGpuClusterpairSplit]; /* The i-cluster mask data       for 2 warps   */
196 } nbnxn_cj4_t;
197
198 /* Struct for storing the atom-pair interaction bits for a cluster pair in a GPU pairlist */
199 struct nbnxn_excl_t
200 {
201     /* Constructor, sets no exclusions, so all atom pairs interacting */
202     nbnxn_excl_t()
203     {
204         for (unsigned int &pairEntry : pair)
205         {
206             pairEntry = NBNXN_INTERACTION_MASK_ALL;
207         }
208     }
209
210     /* Topology exclusion interaction bits per warp */
211     unsigned int pair[c_nbnxnGpuExclSize];
212 };
213
214 /* Cluster pairlist type for use on CPUs */
215 struct NbnxnPairlistCpu
216 {
217     gmx_cache_protect_t     cp0;
218
219     int                     na_ci;       /* The number of atoms per i-cluster        */
220     int                     na_cj;       /* The number of atoms per j-cluster        */
221     real                    rlist;       /* The radius for constructing the list     */
222     FastVector<nbnxn_ci_t>  ci;          /* The i-cluster list                       */
223     FastVector<nbnxn_ci_t>  ciOuter;     /* The outer, unpruned i-cluster list       */
224
225     FastVector<nbnxn_cj_t>  cj;          /* The j-cluster list, size ncj             */
226     FastVector<nbnxn_cj_t>  cjOuter;     /* The outer, unpruned j-cluster list       */
227     int                     ncjInUse;    /* The number of j-clusters that are used by ci entries in this list, will be <= cj.size() */
228
229     int                     nci_tot;     /* The total number of i clusters           */
230
231     NbnxnPairlistCpuWork   *work;
232
233     gmx_cache_protect_t     cp1;
234 };
235
236 /* Cluster pairlist type, with extra hierarchies, for on the GPU
237  *
238  * NOTE: for better performance when combining lists over threads,
239  *       all vectors should use default initialization. But when
240  *       changing this, excl should be intialized when adding entries.
241  */
242 struct NbnxnPairlistGpu
243 {
244     /* Constructor
245      *
246      * \param[in] pinningPolicy  Sets the pinning policy for all buffers used on the GPU
247      */
248     NbnxnPairlistGpu(gmx::PinningPolicy pinningPolicy);
249
250     gmx_cache_protect_t            cp0;
251
252     int                            na_ci; /* The number of atoms per i-cluster        */
253     int                            na_cj; /* The number of atoms per j-cluster        */
254     int                            na_sc; /* The number of atoms per super cluster    */
255     real                           rlist; /* The radius for constructing the list     */
256     // The i-super-cluster list, indexes into cj4;
257     gmx::HostVector<nbnxn_sci_t>   sci;
258     // The list of 4*j-cluster groups
259     gmx::HostVector<nbnxn_cj4_t>   cj4;
260     // Atom interaction bits (non-exclusions)
261     gmx::HostVector<nbnxn_excl_t>  excl;
262     // The total number of i-clusters
263     int                            nci_tot;
264
265     NbnxnPairlistGpuWork          *work;
266
267     gmx_cache_protect_t            cp1;
268 };
269
270 struct nbnxn_pairlist_set_t
271 {
272     nbnxn_pairlist_set_t(const NbnxnListParameters &listParams);
273
274     int                         nnbl;         /* number of lists */
275     NbnxnPairlistCpu          **nbl;          /* lists for CPU */
276     NbnxnPairlistCpu          **nbl_work;     /* work space for rebalancing lists */
277     NbnxnPairlistGpu          **nblGpu;       /* lists for GPU */
278     const NbnxnListParameters  &params;       /* Pairlist parameters desribing setup and ranges */
279     gmx_bool                    bCombined;    /* TRUE if lists get combined into one (the 1st) */
280     gmx_bool                    bSimple;      /* TRUE if the list of of type "simple"
281                                                  (na_sc=na_s, no super-clusters used) */
282
283     /* Counts for debug printing */
284     int                     natpair_ljq;           /* Total number of atom pairs for LJ+Q kernel */
285     int                     natpair_lj;            /* Total number of atom pairs for LJ kernel   */
286     int                     natpair_q;             /* Total number of atom pairs for Q kernel    */
287     std::vector<t_nblist *> nbl_fep;               /* List of free-energy atom pair interactions */
288 };
289
290 enum {
291     nbatXYZ, nbatXYZQ, nbatX4, nbatX8
292 };
293
294 // Struct that holds force and energy output buffers
295 struct nbnxn_atomdata_output_t
296 {
297     /* Constructor
298      *
299      * \param[in] kernelType              Type of non-bonded kernel
300      * \param[in] numEnergyGroups         The number of energy groups
301      * \param[in] simdEnergyBufferStride  Stride for entries in the energy buffers for SIMD kernels
302      * \param[in] pinningPolicy           Sets the pinning policy for all buffers used on the GPU
303      */
304     nbnxn_atomdata_output_t(Nbnxm::KernelType  kernelType,
305                             int                numEnergyGroups,
306                             int                simdEnergyBUfferStride,
307                             gmx::PinningPolicy pinningPolicy);
308
309     gmx::HostVector<real> f;      // f, size natoms*fstride
310     gmx::HostVector<real> fshift; // Shift force array, size SHIFTS*DIM
311     gmx::HostVector<real> Vvdw;   // Temporary Van der Waals group energy storage
312     gmx::HostVector<real> Vc;     // Temporary Coulomb group energy storage
313     AlignedVector<real>   VSvdw;  // Temporary SIMD Van der Waals group energy storage
314     AlignedVector<real>   VSc;    // Temporary SIMD Coulomb group energy storage
315 };
316
317 /* Block size in atoms for the non-bonded thread force-buffer reduction,
318  * should be a multiple of all cell and x86 SIMD sizes (i.e. 2, 4 and 8).
319  * Should be small to reduce the reduction and zeroing cost,
320  * but too small will result in overhead.
321  * Currently the block size is NBNXN_BUFFERFLAG_SIZE*3*sizeof(real)=192 bytes.
322  */
323 #if GMX_DOUBLE
324 #define NBNXN_BUFFERFLAG_SIZE   8
325 #else
326 #define NBNXN_BUFFERFLAG_SIZE  16
327 #endif
328
329 /* We store the reduction flags as gmx_bitmask_t.
330  * This limits the number of flags to BITMASK_SIZE.
331  */
332 #define NBNXN_BUFFERFLAG_MAX_THREADS  (BITMASK_SIZE)
333
334 /* Flags for telling if threads write to force output buffers */
335 typedef struct {
336     int               nflag;       /* The number of flag blocks                         */
337     gmx_bitmask_t    *flag;        /* Bit i is set when thread i writes to a cell-block */
338     int               flag_nalloc; /* Allocation size of cxy_flag                       */
339 } nbnxn_buffer_flags_t;
340
341 /* LJ combination rules: geometric, Lorentz-Berthelot, none */
342 enum {
343     ljcrGEOM, ljcrLB, ljcrNONE, ljcrNR
344 };
345
346 /* Struct that stores atom related data for the nbnxn module
347  *
348  * Note: performance would improve slightly when all std::vector containers
349  *       in this struct would not initialize during resize().
350  */
351 struct nbnxn_atomdata_t
352 {   //NOLINT(clang-analyzer-optin.performance.Padding)
353     struct Params
354     {
355         /* Constructor
356          *
357          * \param[in] pinningPolicy  Sets the pinning policy for all data that might be transfered to a GPU
358          */
359         Params(gmx::PinningPolicy pinningPolicy);
360
361         // The number of different atom types
362         int                   numTypes;
363         // Lennard-Jone 6*C6 and 12*C12 parameters, size numTypes*2*2
364         gmx::HostVector<real> nbfp;
365         // Combination rule, see enum defined above
366         int                   comb_rule;
367         // LJ parameters per atom type, size numTypes*2
368         gmx::HostVector<real> nbfp_comb;
369         // As nbfp, but with a stride for the present SIMD architecture
370         AlignedVector<real>   nbfp_aligned;
371         // Atom types per atom
372         gmx::HostVector<int>  type;
373         // LJ parameters per atom for fast SIMD loading
374         gmx::HostVector<real> lj_comb;
375         // Charges per atom, not set with format nbatXYZQ
376         gmx::HostVector<real> q;
377         // The number of energy groups
378         int                   nenergrp;
379         // 2log(nenergrp)
380         int                   neg_2log;
381         // The energy groups, one int entry per cluster, only set when needed
382         gmx::HostVector<int>  energrp;
383     };
384
385     // Diagonal and topology exclusion helper data for all SIMD kernels
386     struct SimdMasks
387     {
388         SimdMasks();
389
390         // Helper data for setting up diagonal exclusion masks in the SIMD 4xN kernels
391         AlignedVector<real>     diagonal_4xn_j_minus_i;
392         // Helper data for setting up diaginal exclusion masks in the SIMD 2xNN kernels
393         AlignedVector<real>     diagonal_2xnn_j_minus_i;
394         // Filters for topology exclusion masks for the SIMD kernels
395         AlignedVector<uint32_t> exclusion_filter;
396         // Filters for topology exclusion masks for double SIMD kernels without SIMD int32 logical support
397         AlignedVector<uint64_t> exclusion_filter64;
398         // Array of masks needed for exclusions
399         AlignedVector<real>     interaction_array;
400     };
401
402     /* Constructor
403      *
404      * \param[in] pinningPolicy  Sets the pinning policy for all data that might be transfered to a GPU
405      */
406     nbnxn_atomdata_t(gmx::PinningPolicy pinningPolicy);
407
408     /* Returns a const reference to the parameters */
409     const Params &params() const
410     {
411         return params_;
412     }
413
414     /* Returns a non-const reference to the parameters */
415     Params &paramsDeprecated()
416     {
417         return params_;
418     }
419
420     /* Returns the current total number of atoms stored */
421     int numAtoms() const
422     {
423         return numAtoms_;
424     }
425
426     /* Return the coordinate buffer, and q with xFormat==nbatXYZQ */
427     gmx::ArrayRef<const real> x() const
428     {
429         return x_;
430     }
431
432     /* Return the coordinate buffer, and q with xFormat==nbatXYZQ */
433     gmx::ArrayRef<real> x()
434     {
435         return x_;
436     }
437
438     /* Resizes the coordinate buffer and sets the number of atoms */
439     void resizeCoordinateBuffer(int numAtoms);
440
441     /* Resizes the force buffers for the current number of atoms */
442     void resizeForceBuffers();
443
444     private:
445         // The LJ and charge parameters
446         Params                     params_;
447         // The total number of atoms currently stored
448         int                        numAtoms_;
449     public:
450         int                        natoms_local; /* Number of local atoms                           */
451         int                        XFormat;      /* The format of x (and q), enum                      */
452         int                        FFormat;      /* The format of f, enum                              */
453         gmx_bool                   bDynamicBox;  /* Do we need to update shift_vec every step?    */
454         gmx::HostVector<gmx::RVec> shift_vec;    /* Shift vectors, copied from t_forcerec              */
455         int                        xstride;      /* stride for a coordinate in x (usually 3 or 4)      */
456         int                        fstride;      /* stride for a coordinate in f (usually 3 or 4)      */
457     private:
458         gmx::HostVector<real>      x_;           /* x and possibly q, size natoms*xstride              */
459
460     public:
461         // Masks for handling exclusions in the SIMD kernels
462         const SimdMasks          simdMasks;
463
464         /* Output data */
465         std::vector<nbnxn_atomdata_output_t> out; /* Output data structures, 1 per thread */
466
467         /* Reduction related data */
468         gmx_bool                 bUseBufferFlags;     /* Use the flags or operate on all atoms     */
469         nbnxn_buffer_flags_t     buffer_flags;        /* Flags for buffer zeroing+reduc.  */
470         gmx_bool                 bUseTreeReduce;      /* Use tree for force reduction */
471         tMPI_Atomic             *syncStep;            /* Synchronization step for tree reduce */
472 };
473
474 #endif