Sort all includes in src/gromacs
[alexxy/gromacs.git] / src / gromacs / gmxlib / nonbonded / nb_kernel_c / nb_kernel_allvsall.c
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-2009, The GROMACS Development Team.
6  * Copyright (c) 2013,2014, 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 "nb_kernel_allvsall.h"
40
41 #include "config.h"
42
43 #include <math.h>
44
45 #include "gromacs/legacyheaders/nrnb.h"
46 #include "gromacs/legacyheaders/types/simple.h"
47 #include "gromacs/math/vec.h"
48 #include "gromacs/utility/smalloc.h"
49
50 typedef struct
51 {
52     real **    pvdwparam;
53     int *      jindex;
54     int **     exclusion_mask;
55 }
56 gmx_allvsall_data_t;
57
58 static int
59 calc_maxoffset(int i, int natoms)
60 {
61     int maxoffset;
62
63     if ((natoms % 2) == 1)
64     {
65         /* Odd number of atoms, easy */
66         maxoffset = natoms/2;
67     }
68     else if ((natoms % 4) == 0)
69     {
70         /* Multiple of four is hard */
71         if (i < natoms/2)
72         {
73             if ((i % 2) == 0)
74             {
75                 maxoffset = natoms/2;
76             }
77             else
78             {
79                 maxoffset = natoms/2-1;
80             }
81         }
82         else
83         {
84             if ((i % 2) == 1)
85             {
86                 maxoffset = natoms/2;
87             }
88             else
89             {
90                 maxoffset = natoms/2-1;
91             }
92         }
93     }
94     else
95     {
96         /* natoms/2 = odd */
97         if ((i % 2) == 0)
98         {
99             maxoffset = natoms/2;
100         }
101         else
102         {
103             maxoffset = natoms/2-1;
104         }
105     }
106
107     return maxoffset;
108 }
109
110
111 static void
112 setup_exclusions_and_indices(gmx_allvsall_data_t *   aadata,
113                              t_blocka *              excl,
114                              int                     natoms)
115 {
116     int i, j, k, iexcl;
117     int nj0, nj1;
118     int max_offset;
119     int max_excl_offset;
120     int nj;
121
122     /* This routine can appear to be a bit complex, but it is mostly book-keeping.
123      * To enable the fast all-vs-all kernel we need to be able to stream through all coordinates
124      * whether they should interact or not.
125      *
126      * To avoid looping over the exclusions, we create a simple mask that is 1 if the interaction
127      * should be present, otherwise 0. Since exclusions typically only occur when i & j are close,
128      * we create a jindex array with three elements per i atom: the starting point, the point to
129      * which we need to check exclusions, and the end point.
130      * This way we only have to allocate a short exclusion mask per i atom.
131      */
132
133     /* Allocate memory for our modified jindex array */
134     snew(aadata->jindex, 3*natoms);
135
136     /* Pointer to lists with exclusion masks */
137     snew(aadata->exclusion_mask, natoms);
138
139     for (i = 0; i < natoms; i++)
140     {
141         /* Start */
142         aadata->jindex[3*i]   = i+1;
143         max_offset            = calc_maxoffset(i, natoms);
144
145         /* Exclusions */
146         nj0   = excl->index[i];
147         nj1   = excl->index[i+1];
148
149         /* first check the max range */
150         max_excl_offset = -1;
151
152         for (j = nj0; j < nj1; j++)
153         {
154             iexcl = excl->a[j];
155
156             k = iexcl - i;
157
158             if (k+natoms <= max_offset)
159             {
160                 k += natoms;
161             }
162
163             max_excl_offset = (k > max_excl_offset) ? k : max_excl_offset;
164         }
165
166         max_excl_offset = (max_offset < max_excl_offset) ? max_offset : max_excl_offset;
167
168         aadata->jindex[3*i+1] = i+1+max_excl_offset;
169
170
171         snew(aadata->exclusion_mask[i], max_excl_offset);
172         /* Include everything by default */
173         for (j = 0; j < max_excl_offset; j++)
174         {
175             /* Use all-ones to mark interactions that should be present, compatible with SSE */
176             aadata->exclusion_mask[i][j] = 0xFFFFFFFF;
177         }
178
179         /* Go through exclusions again */
180         for (j = nj0; j < nj1; j++)
181         {
182             iexcl = excl->a[j];
183
184             k = iexcl - i;
185
186             if (k+natoms <= max_offset)
187             {
188                 k += natoms;
189             }
190
191             if (k > 0 && k <= max_excl_offset)
192             {
193                 /* Excluded, kill it! */
194                 aadata->exclusion_mask[i][k-1] = 0;
195             }
196         }
197
198         /* End */
199         aadata->jindex[3*i+2] = i+1+max_offset;
200     }
201 }
202
203 static void
204 setup_aadata(gmx_allvsall_data_t **  p_aadata,
205              t_blocka *              excl,
206              int                     natoms,
207              int *                   type,
208              int                     ntype,
209              real *                  pvdwparam)
210 {
211     int                  i, j, idx;
212     gmx_allvsall_data_t *aadata;
213     real                *p;
214
215     snew(aadata, 1);
216     *p_aadata = aadata;
217
218     /* Generate vdw params */
219     snew(aadata->pvdwparam, ntype);
220
221     for (i = 0; i < ntype; i++)
222     {
223         snew(aadata->pvdwparam[i], 2*natoms);
224         p = aadata->pvdwparam[i];
225
226         /* Lets keep it simple and use multiple steps - first create temp. c6/c12 arrays */
227         for (j = 0; j < natoms; j++)
228         {
229             idx             = i*ntype+type[j];
230             p[2*j]          = pvdwparam[2*idx];
231             p[2*j+1]        = pvdwparam[2*idx+1];
232         }
233     }
234
235     setup_exclusions_and_indices(aadata, excl, natoms);
236 }
237
238
239
240 void
241 nb_kernel_allvsall(t_nblist gmx_unused *     nlist,
242                    rvec *                    xx,
243                    rvec *                    ff,
244                    t_forcerec *              fr,
245                    t_mdatoms *               mdatoms,
246                    nb_kernel_data_t *        kernel_data,
247                    t_nrnb *                  nrnb)
248 {
249     gmx_allvsall_data_t *aadata;
250     int                  natoms;
251     int                  ni0, ni1;
252     int                  nj0, nj1, nj2;
253     int                  i, j, k;
254     real           *     charge;
255     int           *      type;
256     real                 facel;
257     real           *     pvdw;
258     int                  ggid;
259     int           *      mask;
260
261     real                 ix, iy, iz, iq;
262     real                 fix, fiy, fiz;
263     real                 jx, jy, jz, qq;
264     real                 dx, dy, dz;
265     real                 tx, ty, tz;
266     real                 rsq, rinv, rinvsq, rinvsix;
267     real                 vcoul, vctot;
268     real                 c6, c12, Vvdw6, Vvdw12, Vvdwtot;
269     real                 fscal;
270     t_blocka           * excl;
271     real           *     f;
272     real           *     x;
273     real           *     Vvdw;
274     real           *     Vc;
275
276     x                   = xx[0];
277     f                   = ff[0];
278     charge              = mdatoms->chargeA;
279     type                = mdatoms->typeA;
280     facel               = fr->epsfac;
281     natoms              = mdatoms->nr;
282     ni0                 = 0;
283     ni1                 = mdatoms->homenr;
284     aadata              = fr->AllvsAll_work;
285     excl                = kernel_data->exclusions;
286
287     Vc                  = kernel_data->energygrp_elec;
288     Vvdw                = kernel_data->energygrp_vdw;
289
290     if (aadata == NULL)
291     {
292         setup_aadata(&aadata, excl, natoms, type, fr->ntype, fr->nbfp);
293         fr->AllvsAll_work  = aadata;
294     }
295
296     for (i = ni0; i < ni1; i++)
297     {
298         /* We assume shifts are NOT used for all-vs-all interactions */
299
300         /* Load i atom data */
301         ix                = x[3*i];
302         iy                = x[3*i+1];
303         iz                = x[3*i+2];
304         iq                = facel*charge[i];
305
306         pvdw              = aadata->pvdwparam[type[i]];
307
308         /* Zero the potential energy for this list */
309         Vvdwtot           = 0.0;
310         vctot             = 0.0;
311
312         /* Clear i atom forces */
313         fix               = 0.0;
314         fiy               = 0.0;
315         fiz               = 0.0;
316
317         /* Load limits for loop over neighbors */
318         nj0              = aadata->jindex[3*i];
319         nj1              = aadata->jindex[3*i+1];
320         nj2              = aadata->jindex[3*i+2];
321
322         mask             = aadata->exclusion_mask[i];
323
324         /* Prologue part, including exclusion mask */
325         for (j = nj0; j < nj1; j++, mask++)
326         {
327             if (*mask != 0)
328             {
329                 k = j%natoms;
330
331                 /* load j atom coordinates */
332                 jx                = x[3*k];
333                 jy                = x[3*k+1];
334                 jz                = x[3*k+2];
335
336                 /* Calculate distance */
337                 dx                = ix - jx;
338                 dy                = iy - jy;
339                 dz                = iz - jz;
340                 rsq               = dx*dx+dy*dy+dz*dz;
341
342                 /* Calculate 1/r and 1/r2 */
343                 rinv              = gmx_invsqrt(rsq);
344                 rinvsq            = rinv*rinv;
345
346                 /* Load parameters for j atom */
347                 qq                = iq*charge[k];
348                 c6                = pvdw[2*k];
349                 c12               = pvdw[2*k+1];
350
351                 /* Coulomb interaction */
352                 vcoul             = qq*rinv;
353                 vctot             = vctot+vcoul;
354
355                 /* Lennard-Jones interaction */
356                 rinvsix           = rinvsq*rinvsq*rinvsq;
357                 Vvdw6             = c6*rinvsix;
358                 Vvdw12            = c12*rinvsix*rinvsix;
359                 Vvdwtot           = Vvdwtot+Vvdw12-Vvdw6;
360                 fscal             = (vcoul+12.0*Vvdw12-6.0*Vvdw6)*rinvsq;
361
362                 /* Calculate temporary vectorial force */
363                 tx                = fscal*dx;
364                 ty                = fscal*dy;
365                 tz                = fscal*dz;
366
367                 /* Increment i atom force */
368                 fix               = fix + tx;
369                 fiy               = fiy + ty;
370                 fiz               = fiz + tz;
371
372                 /* Decrement j atom force */
373                 f[3*k]            = f[3*k]   - tx;
374                 f[3*k+1]          = f[3*k+1] - ty;
375                 f[3*k+2]          = f[3*k+2] - tz;
376             }
377             /* Inner loop uses 38 flops/iteration */
378         }
379
380         /* Main part, no exclusions */
381         for (j = nj1; j < nj2; j++)
382         {
383             k = j%natoms;
384
385             /* load j atom coordinates */
386             jx                = x[3*k];
387             jy                = x[3*k+1];
388             jz                = x[3*k+2];
389
390             /* Calculate distance */
391             dx                = ix - jx;
392             dy                = iy - jy;
393             dz                = iz - jz;
394             rsq               = dx*dx+dy*dy+dz*dz;
395
396             /* Calculate 1/r and 1/r2 */
397             rinv              = gmx_invsqrt(rsq);
398             rinvsq            = rinv*rinv;
399
400             /* Load parameters for j atom */
401             qq                = iq*charge[k];
402             c6                = pvdw[2*k];
403             c12               = pvdw[2*k+1];
404
405             /* Coulomb interaction */
406             vcoul             = qq*rinv;
407             vctot             = vctot+vcoul;
408
409             /* Lennard-Jones interaction */
410             rinvsix           = rinvsq*rinvsq*rinvsq;
411             Vvdw6             = c6*rinvsix;
412             Vvdw12            = c12*rinvsix*rinvsix;
413             Vvdwtot           = Vvdwtot+Vvdw12-Vvdw6;
414             fscal             = (vcoul+12.0*Vvdw12-6.0*Vvdw6)*rinvsq;
415
416             /* Calculate temporary vectorial force */
417             tx                = fscal*dx;
418             ty                = fscal*dy;
419             tz                = fscal*dz;
420
421             /* Increment i atom force */
422             fix               = fix + tx;
423             fiy               = fiy + ty;
424             fiz               = fiz + tz;
425
426             /* Decrement j atom force */
427             f[3*k]            = f[3*k]   - tx;
428             f[3*k+1]          = f[3*k+1] - ty;
429             f[3*k+2]          = f[3*k+2] - tz;
430
431             /* Inner loop uses 38 flops/iteration */
432         }
433
434         f[3*i]   += fix;
435         f[3*i+1] += fiy;
436         f[3*i+2] += fiz;
437
438         /* Add potential energies to the group for this list */
439         ggid             = 0;
440
441         Vc[ggid]         = Vc[ggid] + vctot;
442         Vvdw[ggid]       = Vvdw[ggid] + Vvdwtot;
443
444         /* Outer loop uses 6 flops/iteration */
445     }
446
447     /* 12 flops per outer iteration
448      * 19 flops per inner iteration
449      */
450     inc_nrnb(nrnb, eNR_NBKERNEL_ELEC_VDW_VF, (ni1-ni0)*12 + ((ni1-ni0)*natoms/2)*19);
451 }