Merge branch 'release-4-6', adds the nbnxn functionality
[alexxy/gromacs.git] / src / gromacs / mdlib / nbnxn_cuda / nbnxn_cuda_kernel.cuh
1 /* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
2  *
3  *
4  *                This source code is part of
5  *
6  *                 G   R   O   M   A   C   S
7  *
8  *          GROningen MAchine for Chemical Simulations
9  *
10  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12  * Copyright (c) 2001-2012, The GROMACS development team,
13  * check out http://www.gromacs.org for more information.
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * If you want to redistribute modifications, please consider that
21  * scientific software is very special. Version control is crucial -
22  * bugs must be traceable. We will be happy to consider code for
23  * inclusion in the official distribution, but derived work must not
24  * be called official GROMACS. Details are found in the README & COPYING
25  * files - if they are missing, get the official version at www.gromacs.org.
26  *
27  * To help us fund GROMACS development, we humbly ask that you cite
28  * the papers on the package - you can find them in the top README file.
29  *
30  * For more info, check our website at http://www.gromacs.org
31  *
32  * And Hey:
33  * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
34  */
35
36 #if __CUDA_ARCH__ >= 300
37 #define REDUCE_SHUFFLE
38 /* On Kepler pre-loading i-atom types to shmem gives a few %,
39    but on Fermi it does not */
40 #define IATYPE_SHMEM
41 #endif
42
43 /*
44    Kernel launch parameters:
45     - #blocks   = #pair lists, blockId = pair list Id
46     - #threads  = CL_SIZE^2
47     - shmem     = CL_SIZE^2 * sizeof(float)
48
49     Each thread calculates an i force-component taking one pair of i-j atoms.
50  */
51 #ifdef PRUNE_NBL
52 #ifdef CALC_ENERGIES
53 __global__ void NB_KERNEL_FUNC_NAME(k_nbnxn, _ener_prune)
54 #else
55 __global__ void NB_KERNEL_FUNC_NAME(k_nbnxn, _prune)
56 #endif
57 #else
58 #ifdef CALC_ENERGIES
59 __global__ void NB_KERNEL_FUNC_NAME(k_nbnxn, _ener)
60 #else
61 __global__ void NB_KERNEL_FUNC_NAME(k_nbnxn)
62 #endif
63 #endif
64             (const cu_atomdata_t atdat,
65              const cu_nbparam_t nbparam,
66              const cu_plist_t plist,
67              bool bCalcFshift)
68 {
69     /* convenience variables */
70     const nbnxn_sci_t *pl_sci   = plist.sci;
71 #ifndef PRUNE_NBL
72     const
73 #endif
74     nbnxn_cj4_t *pl_cj4         = plist.cj4;
75     const nbnxn_excl_t *excl    = plist.excl;
76     const int *atom_types       = atdat.atom_types;
77     int ntypes                  = atdat.ntypes;
78     const float4 *xq            = atdat.xq;
79     float3 *f                   = atdat.f;
80     const float3 *shift_vec     = atdat.shift_vec;
81     float rcoulomb_sq           = nbparam.rcoulomb_sq;
82 #ifdef VDW_CUTOFF_CHECK
83     float rvdw_sq               = nbparam.rvdw_sq;
84     float vdw_in_range;
85 #endif
86 #ifdef EL_RF
87     float two_k_rf              = nbparam.two_k_rf;
88 #endif
89 #ifdef EL_EWALD
90     float coulomb_tab_scale     = nbparam.coulomb_tab_scale;
91 #endif
92 #ifdef PRUNE_NBL
93     float rlist_sq              = nbparam.rlist_sq;
94 #endif
95
96 #ifdef CALC_ENERGIES
97     float lj_shift    = nbparam.sh_invrc6;
98 #ifdef EL_EWALD
99     float beta        = nbparam.ewald_beta;
100     float ewald_shift = nbparam.sh_ewald;
101 #else
102     float c_rf        = nbparam.c_rf;
103 #endif
104     float *e_lj       = atdat.e_lj;
105     float *e_el       = atdat.e_el;
106 #endif
107
108     /* thread/block/warp id-s */
109     unsigned int tidxi  = threadIdx.x;
110     unsigned int tidxj  = threadIdx.y;
111     unsigned int tidx   = threadIdx.y * blockDim.x + threadIdx.x;
112     unsigned int bidx   = blockIdx.x;
113     unsigned int widx   = tidx / WARP_SIZE; /* warp index */
114
115     int sci, ci, cj, ci_offset,
116         ai, aj,
117         cij4_start, cij4_end,
118         typei, typej,
119         i, jm, j4, wexcl_idx;
120     float qi, qj_f,
121           r2, inv_r, inv_r2, inv_r6,
122           c6, c12,
123           int_bit,
124 #ifdef CALC_ENERGIES
125           E_lj, E_el,
126 #endif
127           F_invr;
128     unsigned int wexcl, imask, mask_ji;
129     float4 xqbuf;
130     float3 xi, xj, rv, f_ij, fcj_buf, fshift_buf;
131     float3 fci_buf[NCL_PER_SUPERCL];    /* i force buffer */
132     nbnxn_sci_t nb_sci;
133
134     /* shmem buffer for i x+q pre-loading */
135     extern __shared__  float4 xqib[];
136 #ifdef IATYPE_SHMEM
137     /* shmem buffer for i atom-type pre-loading */
138     int *atib = (int *)(xqib + NCL_PER_SUPERCL * CL_SIZE);
139 #endif
140
141 #ifndef REDUCE_SHUFFLE
142     /* shmem j force buffer */
143 #ifdef IATYPE_SHMEM
144     float *f_buf = (float *)(atib + NCL_PER_SUPERCL * CL_SIZE);
145 #else
146     float *f_buf = (float *)(xqib + NCL_PER_SUPERCL * CL_SIZE);
147 #endif
148 #endif
149
150     nb_sci      = pl_sci[bidx];         /* my i super-cluster's index = current bidx */
151     sci         = nb_sci.sci;           /* super-cluster */
152     cij4_start  = nb_sci.cj4_ind_start; /* first ...*/
153     cij4_end    = nb_sci.cj4_ind_end;   /* and last index of j clusters */
154
155     /* Store the i-atom x and q in shared memory */
156     /* Note: the thread indexing here is inverted with respect to the
157        inner-loop as this results in slightly higher performance */
158     ci = sci * NCL_PER_SUPERCL + tidxi;
159     ai = ci * CL_SIZE + tidxj;
160     xqib[tidxi * CL_SIZE + tidxj] = xq[ai] + shift_vec[nb_sci.shift];
161 #ifdef IATYPE_SHMEM
162     ci = sci * NCL_PER_SUPERCL + tidxj;
163     ai = ci * CL_SIZE + tidxi;
164     atib[tidxj * CL_SIZE + tidxi] = atom_types[ai];
165 #endif
166     __syncthreads();
167
168     for(ci_offset = 0; ci_offset < NCL_PER_SUPERCL; ci_offset++)
169     {
170         fci_buf[ci_offset] = make_float3(0.0f);
171     }
172
173 #ifdef CALC_ENERGIES
174     E_lj = 0.0f;
175     E_el = 0.0f;
176
177 #if defined EL_EWALD || defined EL_RF
178     if (nb_sci.shift == CENTRAL && pl_cj4[cij4_start].cj[0] == sci*NCL_PER_SUPERCL)
179     {
180         /* we have the diagonal: add the charge self interaction energy term */
181         for (i = 0; i < NCL_PER_SUPERCL; i++)
182         {
183             qi    = xqib[i * CL_SIZE + tidxi].w;
184             E_el += qi*qi;
185         }
186         /* divide the self term equally over the j-threads */
187         E_el /= CL_SIZE;
188 #ifdef EL_RF
189         E_el *= -nbparam.epsfac*0.5f*c_rf;
190 #else
191         E_el *= -nbparam.epsfac*beta*0.56418958f; /* last factor 1/sqrt(pi) */
192 #endif
193     }
194 #endif
195 #endif
196
197     /* skip central shifts when summing shift forces */
198     if (nb_sci.shift == CENTRAL)
199     {
200         bCalcFshift = false;
201     }
202
203     fshift_buf = make_float3(0.0f);
204
205     /* loop over the j clusters = seen by any of the atoms in the current super-cluster */
206     for (j4 = cij4_start; j4 < cij4_end; j4++)
207     {
208         wexcl_idx   = pl_cj4[j4].imei[widx].excl_ind;
209         imask       = pl_cj4[j4].imei[widx].imask;
210         wexcl       = excl[wexcl_idx].pair[(tidx) & (WARP_SIZE - 1)];
211
212 #ifndef PRUNE_NBL
213         if (imask)
214 #endif
215         {
216             /* Unrolling this loop
217                - with pruning leads to register spilling;
218                - on Kepler is much slower;
219                - doesn't work on CUDA <v4.1
220                Tested with nvcc 3.2 - 5.0.7 */
221 #if !defined PRUNE_NBL && __CUDA_ARCH__ < 300 && CUDA_VERSION >= 4010
222 #pragma unroll 4
223 #endif
224             for (jm = 0; jm < 4; jm++)
225             {
226                 if (imask & (255U << (jm * NCL_PER_SUPERCL)))
227                 {
228                     mask_ji = (1U << (jm * NCL_PER_SUPERCL));
229
230                     cj      = pl_cj4[j4].cj[jm];
231                     aj      = cj * CL_SIZE + tidxj;
232
233                     /* load j atom data */
234                     xqbuf   = xq[aj];
235                     xj      = make_float3(xqbuf.x, xqbuf.y, xqbuf.z);
236                     qj_f    = nbparam.epsfac * xqbuf.w;
237                     typej   = atom_types[aj];
238
239                     fcj_buf = make_float3(0.0f);
240
241                     /* The PME and RF kernels don't unroll with CUDA <v4.1. */
242 #if !defined PRUNE_NBL && !(CUDA_VERSION < 4010 && (defined EL_EWALD || defined EL_RF))
243 #pragma unroll 8
244 #endif
245                     for(i = 0; i < NCL_PER_SUPERCL; i++)
246                     {
247                         if (imask & mask_ji)
248                         {
249                             ci_offset   = i;    /* i force buffer offset */
250
251                             ci      = sci * NCL_PER_SUPERCL + i; /* i cluster index */
252                             ai      = ci * CL_SIZE + tidxi;      /* i atom index */
253
254                             /* all threads load an atom from i cluster ci into shmem! */
255                             xqbuf   = xqib[i * CL_SIZE + tidxi];
256                             xi      = make_float3(xqbuf.x, xqbuf.y, xqbuf.z);
257
258                             /* distance between i and j atoms */
259                             rv      = xi - xj;
260                             r2      = norm2(rv);
261
262 #ifdef PRUNE_NBL
263                             /* If _none_ of the atoms pairs are in cutoff range,
264                                the bit corresponding to the current
265                                cluster-pair in imask gets set to 0. */
266                             if (!__any(r2 < rlist_sq))
267                             {
268                                 imask &= ~mask_ji;
269                             }
270 #endif
271
272                             int_bit = (wexcl & mask_ji) ? 1.0f : 0.0f;
273
274                             /* cutoff & exclusion check */
275 #if defined EL_EWALD || defined EL_RF
276                             if (r2 < rcoulomb_sq *
277                                 (nb_sci.shift != CENTRAL || ci != cj || tidxj > tidxi))
278 #else
279                             if (r2 < rcoulomb_sq * int_bit)
280 #endif
281                             {
282                                 /* load the rest of the i-atom parameters */
283                                 qi      = xqbuf.w;
284 #ifdef IATYPE_SHMEM
285                                 typei   = atib[i * CL_SIZE + tidxi];
286 #else
287                                 typei   = atom_types[ai];
288 #endif
289
290                                 /* LJ 6*C6 and 12*C12 */
291                                 c6      = tex1Dfetch(tex_nbfp, 2 * (ntypes * typei + typej));
292                                 c12     = tex1Dfetch(tex_nbfp, 2 * (ntypes * typei + typej) + 1);
293
294                                 /* avoid NaN for excluded pairs at r=0 */
295                                 r2      += (1.0f - int_bit) * NBNXN_AVOID_SING_R2_INC;
296
297                                 inv_r   = rsqrt(r2);
298                                 inv_r2  = inv_r * inv_r;
299                                 inv_r6  = inv_r2 * inv_r2 * inv_r2;
300 #if defined EL_EWALD || defined EL_RF
301                                 /* We could mask inv_r2, but with Ewald
302                                  * masking both inv_r6 and F_invr is faster */
303                                 inv_r6  *= int_bit;
304 #endif
305
306                                 F_invr  = inv_r6 * (c12 * inv_r6 - c6) * inv_r2;
307
308 #ifdef CALC_ENERGIES
309                                 E_lj    += int_bit * (c12 * (inv_r6 * inv_r6 - lj_shift * lj_shift) * 0.08333333f - c6 * (inv_r6 - lj_shift) * 0.16666667f);
310 #endif
311
312 #ifdef VDW_CUTOFF_CHECK
313                                 /* this enables twin-range cut-offs (rvdw < rcoulomb <= rlist) */
314                                 vdw_in_range = (r2 < rvdw_sq) ? 1.0f : 0.0f;
315                                 F_invr  *= vdw_in_range;
316 #ifdef CALC_ENERGIES
317                                 E_lj    *= vdw_in_range;
318 #endif
319 #endif
320
321 #ifdef EL_CUTOFF
322                                 F_invr  += qi * qj_f * inv_r2 * inv_r;
323 #endif
324 #ifdef EL_RF
325                                 F_invr  += qi * qj_f * (int_bit*inv_r2 * inv_r - two_k_rf);
326 #endif
327 #ifdef EL_EWALD
328                                 F_invr  += qi * qj_f * (int_bit*inv_r2 - interpolate_coulomb_force_r(r2 * inv_r, coulomb_tab_scale)) * inv_r;
329 #endif
330
331 #ifdef CALC_ENERGIES
332 #ifdef EL_CUTOFF
333                                 E_el    += qi * qj_f * (inv_r - c_rf);
334 #endif
335 #ifdef EL_RF
336                                 E_el    += qi * qj_f * (int_bit*inv_r + 0.5f * two_k_rf * r2 - c_rf);
337 #endif
338 #ifdef EL_EWALD
339                                 /* 1.0f - erff is faster than erfcf */
340                                 E_el    += qi * qj_f * (inv_r * (int_bit - erff(r2 * inv_r * beta)) - int_bit * ewald_shift);
341 #endif
342 #endif
343                                 f_ij    = rv * F_invr;
344
345                                 /* accumulate j forces in registers */
346                                 fcj_buf -= f_ij;
347
348                                 /* accumulate i forces in registers */
349                                 fci_buf[ci_offset] += f_ij;
350                             }
351                         }
352
353                         /* shift the mask bit by 1 */
354                         mask_ji += mask_ji;
355                     }
356
357                     /* reduce j forces */
358 #ifdef REDUCE_SHUFFLE
359                     reduce_force_j_warp_shfl(fcj_buf, f, tidxi, aj);
360 #else
361                     /* store j forces in shmem */
362                     f_buf[                  tidx] = fcj_buf.x;
363                     f_buf[    FBUF_STRIDE + tidx] = fcj_buf.y;
364                     f_buf[2 * FBUF_STRIDE + tidx] = fcj_buf.z;
365
366                     reduce_force_j_generic(f_buf, f, tidxi, tidxj, aj);
367 #endif
368                 }
369             }
370 #ifdef PRUNE_NBL
371             /* Update the imask with the new one which does not contain the
372                out of range clusters anymore. */
373             pl_cj4[j4].imei[widx].imask = imask;
374 #endif
375         }
376     }
377
378     /* reduce i forces */
379     for(ci_offset = 0; ci_offset < NCL_PER_SUPERCL; ci_offset++)
380     {
381         ai  = (sci * NCL_PER_SUPERCL + ci_offset) * CL_SIZE + tidxi;
382 #ifdef REDUCE_SHUFFLE
383         reduce_force_i_warp_shfl(fci_buf[ci_offset], f,
384                                  &fshift_buf, bCalcFshift,
385                                  tidxj, ai);
386 #else
387         f_buf[                  tidx] = fci_buf[ci_offset].x;
388         f_buf[    FBUF_STRIDE + tidx] = fci_buf[ci_offset].y;
389         f_buf[2 * FBUF_STRIDE + tidx] = fci_buf[ci_offset].z;
390         __syncthreads();
391         reduce_force_i(f_buf, f,
392                        &fshift_buf, bCalcFshift,
393                        tidxi, tidxj, ai);
394         __syncthreads();
395 #endif
396     }
397
398     /* add up local shift forces into global mem */
399 #ifdef REDUCE_SHUFFLE
400     if (bCalcFshift && (tidxj == 0 || tidxj == 4))
401 #else
402     if (bCalcFshift && tidxj == 0)
403 #endif
404     {
405         atomicAdd(&atdat.fshift[nb_sci.shift].x, fshift_buf.x);
406         atomicAdd(&atdat.fshift[nb_sci.shift].y, fshift_buf.y);
407         atomicAdd(&atdat.fshift[nb_sci.shift].z, fshift_buf.z);
408     }
409
410 #ifdef CALC_ENERGIES
411 #ifdef REDUCE_SHUFFLE
412     /* reduce the energies over warps and store into global memory */
413     reduce_energy_warp_shfl(E_lj, E_el, e_lj, e_el, tidx);
414 #else
415     /* flush the energies to shmem and reduce them */
416     f_buf[              tidx] = E_lj;
417     f_buf[FBUF_STRIDE + tidx] = E_el;
418     reduce_energy_pow2(f_buf + (tidx & WARP_SIZE), e_lj, e_el, tidx & ~WARP_SIZE);
419 #endif
420 #endif
421 }