Merge release-4-6 into master
[alexxy/gromacs.git] / src / gromacs / gmxlib / nonbonded / nb_kernel_sse4_1_double / nb_kernel_ElecCoul_VdwNone_GeomW4P1_sse4_1_double.c
1 /*
2  * Note: this file was generated by the Gromacs sse4_1_double kernel generator.
3  *
4  *                This source code is part of
5  *
6  *                 G   R   O   M   A   C   S
7  *
8  * Copyright (c) 2001-2012, The GROMACS Development Team
9  *
10  * Gromacs is a library for molecular simulation and trajectory analysis,
11  * written by Erik Lindahl, David van der Spoel, Berk Hess, and others - for
12  * a full list of developers and information, check out http://www.gromacs.org
13  *
14  * This program is free software; you can redistribute it and/or modify it under
15  * the terms of the GNU Lesser General Public License as published by the Free
16  * Software Foundation; either version 2 of the License, or (at your option) any
17  * later version.
18  *
19  * To help fund GROMACS development, we humbly ask that you cite
20  * the papers people have written on it - you can find them on the website.
21  */
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <math.h>
27
28 #include "../nb_kernel.h"
29 #include "types/simple.h"
30 #include "vec.h"
31 #include "nrnb.h"
32
33 #include "gmx_math_x86_sse4_1_double.h"
34 #include "kernelutil_x86_sse4_1_double.h"
35
36 /*
37  * Gromacs nonbonded kernel:   nb_kernel_ElecCoul_VdwNone_GeomW4P1_VF_sse4_1_double
38  * Electrostatics interaction: Coulomb
39  * VdW interaction:            None
40  * Geometry:                   Water4-Particle
41  * Calculate force/pot:        PotentialAndForce
42  */
43 void
44 nb_kernel_ElecCoul_VdwNone_GeomW4P1_VF_sse4_1_double
45                     (t_nblist * gmx_restrict                nlist,
46                      rvec * gmx_restrict                    xx,
47                      rvec * gmx_restrict                    ff,
48                      t_forcerec * gmx_restrict              fr,
49                      t_mdatoms * gmx_restrict               mdatoms,
50                      nb_kernel_data_t * gmx_restrict        kernel_data,
51                      t_nrnb * gmx_restrict                  nrnb)
52 {
53     /* Suffixes 0,1,2,3 refer to particle indices for waters in the inner or outer loop, or
54      * just 0 for non-waters.
55      * Suffixes A,B refer to j loop unrolling done with SSE double precision, e.g. for the two different
56      * jnr indices corresponding to data put in the four positions in the SIMD register.
57      */
58     int              i_shift_offset,i_coord_offset,outeriter,inneriter;
59     int              j_index_start,j_index_end,jidx,nri,inr,ggid,iidx;
60     int              jnrA,jnrB;
61     int              j_coord_offsetA,j_coord_offsetB;
62     int              *iinr,*jindex,*jjnr,*shiftidx,*gid;
63     real             rcutoff_scalar;
64     real             *shiftvec,*fshift,*x,*f;
65     __m128d          tx,ty,tz,fscal,rcutoff,rcutoff2,jidxall;
66     int              vdwioffset1;
67     __m128d          ix1,iy1,iz1,fix1,fiy1,fiz1,iq1,isai1;
68     int              vdwioffset2;
69     __m128d          ix2,iy2,iz2,fix2,fiy2,fiz2,iq2,isai2;
70     int              vdwioffset3;
71     __m128d          ix3,iy3,iz3,fix3,fiy3,fiz3,iq3,isai3;
72     int              vdwjidx0A,vdwjidx0B;
73     __m128d          jx0,jy0,jz0,fjx0,fjy0,fjz0,jq0,isaj0;
74     __m128d          dx10,dy10,dz10,rsq10,rinv10,rinvsq10,r10,qq10,c6_10,c12_10;
75     __m128d          dx20,dy20,dz20,rsq20,rinv20,rinvsq20,r20,qq20,c6_20,c12_20;
76     __m128d          dx30,dy30,dz30,rsq30,rinv30,rinvsq30,r30,qq30,c6_30,c12_30;
77     __m128d          velec,felec,velecsum,facel,crf,krf,krf2;
78     real             *charge;
79     __m128d          dummy_mask,cutoff_mask;
80     __m128d          signbit   = gmx_mm_castsi128_pd( _mm_set_epi32(0x80000000,0x00000000,0x80000000,0x00000000) );
81     __m128d          one     = _mm_set1_pd(1.0);
82     __m128d          two     = _mm_set1_pd(2.0);
83     x                = xx[0];
84     f                = ff[0];
85
86     nri              = nlist->nri;
87     iinr             = nlist->iinr;
88     jindex           = nlist->jindex;
89     jjnr             = nlist->jjnr;
90     shiftidx         = nlist->shift;
91     gid              = nlist->gid;
92     shiftvec         = fr->shift_vec[0];
93     fshift           = fr->fshift[0];
94     facel            = _mm_set1_pd(fr->epsfac);
95     charge           = mdatoms->chargeA;
96
97     /* Setup water-specific parameters */
98     inr              = nlist->iinr[0];
99     iq1              = _mm_mul_pd(facel,_mm_set1_pd(charge[inr+1]));
100     iq2              = _mm_mul_pd(facel,_mm_set1_pd(charge[inr+2]));
101     iq3              = _mm_mul_pd(facel,_mm_set1_pd(charge[inr+3]));
102
103     /* Avoid stupid compiler warnings */
104     jnrA = jnrB = 0;
105     j_coord_offsetA = 0;
106     j_coord_offsetB = 0;
107
108     outeriter        = 0;
109     inneriter        = 0;
110
111     /* Start outer loop over neighborlists */
112     for(iidx=0; iidx<nri; iidx++)
113     {
114         /* Load shift vector for this list */
115         i_shift_offset   = DIM*shiftidx[iidx];
116
117         /* Load limits for loop over neighbors */
118         j_index_start    = jindex[iidx];
119         j_index_end      = jindex[iidx+1];
120
121         /* Get outer coordinate index */
122         inr              = iinr[iidx];
123         i_coord_offset   = DIM*inr;
124
125         /* Load i particle coords and add shift vector */
126         gmx_mm_load_shift_and_3rvec_broadcast_pd(shiftvec+i_shift_offset,x+i_coord_offset+DIM,
127                                                  &ix1,&iy1,&iz1,&ix2,&iy2,&iz2,&ix3,&iy3,&iz3);
128
129         fix1             = _mm_setzero_pd();
130         fiy1             = _mm_setzero_pd();
131         fiz1             = _mm_setzero_pd();
132         fix2             = _mm_setzero_pd();
133         fiy2             = _mm_setzero_pd();
134         fiz2             = _mm_setzero_pd();
135         fix3             = _mm_setzero_pd();
136         fiy3             = _mm_setzero_pd();
137         fiz3             = _mm_setzero_pd();
138
139         /* Reset potential sums */
140         velecsum         = _mm_setzero_pd();
141
142         /* Start inner kernel loop */
143         for(jidx=j_index_start; jidx<j_index_end-1; jidx+=2)
144         {
145
146             /* Get j neighbor index, and coordinate index */
147             jnrA             = jjnr[jidx];
148             jnrB             = jjnr[jidx+1];
149             j_coord_offsetA  = DIM*jnrA;
150             j_coord_offsetB  = DIM*jnrB;
151
152             /* load j atom coordinates */
153             gmx_mm_load_1rvec_2ptr_swizzle_pd(x+j_coord_offsetA,x+j_coord_offsetB,
154                                               &jx0,&jy0,&jz0);
155
156             /* Calculate displacement vector */
157             dx10             = _mm_sub_pd(ix1,jx0);
158             dy10             = _mm_sub_pd(iy1,jy0);
159             dz10             = _mm_sub_pd(iz1,jz0);
160             dx20             = _mm_sub_pd(ix2,jx0);
161             dy20             = _mm_sub_pd(iy2,jy0);
162             dz20             = _mm_sub_pd(iz2,jz0);
163             dx30             = _mm_sub_pd(ix3,jx0);
164             dy30             = _mm_sub_pd(iy3,jy0);
165             dz30             = _mm_sub_pd(iz3,jz0);
166
167             /* Calculate squared distance and things based on it */
168             rsq10            = gmx_mm_calc_rsq_pd(dx10,dy10,dz10);
169             rsq20            = gmx_mm_calc_rsq_pd(dx20,dy20,dz20);
170             rsq30            = gmx_mm_calc_rsq_pd(dx30,dy30,dz30);
171
172             rinv10           = gmx_mm_invsqrt_pd(rsq10);
173             rinv20           = gmx_mm_invsqrt_pd(rsq20);
174             rinv30           = gmx_mm_invsqrt_pd(rsq30);
175
176             rinvsq10         = _mm_mul_pd(rinv10,rinv10);
177             rinvsq20         = _mm_mul_pd(rinv20,rinv20);
178             rinvsq30         = _mm_mul_pd(rinv30,rinv30);
179
180             /* Load parameters for j particles */
181             jq0              = gmx_mm_load_2real_swizzle_pd(charge+jnrA+0,charge+jnrB+0);
182
183             fjx0             = _mm_setzero_pd();
184             fjy0             = _mm_setzero_pd();
185             fjz0             = _mm_setzero_pd();
186
187             /**************************
188              * CALCULATE INTERACTIONS *
189              **************************/
190
191             /* Compute parameters for interactions between i and j atoms */
192             qq10             = _mm_mul_pd(iq1,jq0);
193
194             /* COULOMB ELECTROSTATICS */
195             velec            = _mm_mul_pd(qq10,rinv10);
196             felec            = _mm_mul_pd(velec,rinvsq10);
197
198             /* Update potential sum for this i atom from the interaction with this j atom. */
199             velecsum         = _mm_add_pd(velecsum,velec);
200
201             fscal            = felec;
202
203             /* Calculate temporary vectorial force */
204             tx               = _mm_mul_pd(fscal,dx10);
205             ty               = _mm_mul_pd(fscal,dy10);
206             tz               = _mm_mul_pd(fscal,dz10);
207
208             /* Update vectorial force */
209             fix1             = _mm_add_pd(fix1,tx);
210             fiy1             = _mm_add_pd(fiy1,ty);
211             fiz1             = _mm_add_pd(fiz1,tz);
212
213             fjx0             = _mm_add_pd(fjx0,tx);
214             fjy0             = _mm_add_pd(fjy0,ty);
215             fjz0             = _mm_add_pd(fjz0,tz);
216
217             /**************************
218              * CALCULATE INTERACTIONS *
219              **************************/
220
221             /* Compute parameters for interactions between i and j atoms */
222             qq20             = _mm_mul_pd(iq2,jq0);
223
224             /* COULOMB ELECTROSTATICS */
225             velec            = _mm_mul_pd(qq20,rinv20);
226             felec            = _mm_mul_pd(velec,rinvsq20);
227
228             /* Update potential sum for this i atom from the interaction with this j atom. */
229             velecsum         = _mm_add_pd(velecsum,velec);
230
231             fscal            = felec;
232
233             /* Calculate temporary vectorial force */
234             tx               = _mm_mul_pd(fscal,dx20);
235             ty               = _mm_mul_pd(fscal,dy20);
236             tz               = _mm_mul_pd(fscal,dz20);
237
238             /* Update vectorial force */
239             fix2             = _mm_add_pd(fix2,tx);
240             fiy2             = _mm_add_pd(fiy2,ty);
241             fiz2             = _mm_add_pd(fiz2,tz);
242
243             fjx0             = _mm_add_pd(fjx0,tx);
244             fjy0             = _mm_add_pd(fjy0,ty);
245             fjz0             = _mm_add_pd(fjz0,tz);
246
247             /**************************
248              * CALCULATE INTERACTIONS *
249              **************************/
250
251             /* Compute parameters for interactions between i and j atoms */
252             qq30             = _mm_mul_pd(iq3,jq0);
253
254             /* COULOMB ELECTROSTATICS */
255             velec            = _mm_mul_pd(qq30,rinv30);
256             felec            = _mm_mul_pd(velec,rinvsq30);
257
258             /* Update potential sum for this i atom from the interaction with this j atom. */
259             velecsum         = _mm_add_pd(velecsum,velec);
260
261             fscal            = felec;
262
263             /* Calculate temporary vectorial force */
264             tx               = _mm_mul_pd(fscal,dx30);
265             ty               = _mm_mul_pd(fscal,dy30);
266             tz               = _mm_mul_pd(fscal,dz30);
267
268             /* Update vectorial force */
269             fix3             = _mm_add_pd(fix3,tx);
270             fiy3             = _mm_add_pd(fiy3,ty);
271             fiz3             = _mm_add_pd(fiz3,tz);
272
273             fjx0             = _mm_add_pd(fjx0,tx);
274             fjy0             = _mm_add_pd(fjy0,ty);
275             fjz0             = _mm_add_pd(fjz0,tz);
276
277             gmx_mm_decrement_1rvec_2ptr_swizzle_pd(f+j_coord_offsetA,f+j_coord_offsetB,fjx0,fjy0,fjz0);
278
279             /* Inner loop uses 87 flops */
280         }
281
282         if(jidx<j_index_end)
283         {
284
285             jnrA             = jjnr[jidx];
286             j_coord_offsetA  = DIM*jnrA;
287
288             /* load j atom coordinates */
289             gmx_mm_load_1rvec_1ptr_swizzle_pd(x+j_coord_offsetA,
290                                               &jx0,&jy0,&jz0);
291
292             /* Calculate displacement vector */
293             dx10             = _mm_sub_pd(ix1,jx0);
294             dy10             = _mm_sub_pd(iy1,jy0);
295             dz10             = _mm_sub_pd(iz1,jz0);
296             dx20             = _mm_sub_pd(ix2,jx0);
297             dy20             = _mm_sub_pd(iy2,jy0);
298             dz20             = _mm_sub_pd(iz2,jz0);
299             dx30             = _mm_sub_pd(ix3,jx0);
300             dy30             = _mm_sub_pd(iy3,jy0);
301             dz30             = _mm_sub_pd(iz3,jz0);
302
303             /* Calculate squared distance and things based on it */
304             rsq10            = gmx_mm_calc_rsq_pd(dx10,dy10,dz10);
305             rsq20            = gmx_mm_calc_rsq_pd(dx20,dy20,dz20);
306             rsq30            = gmx_mm_calc_rsq_pd(dx30,dy30,dz30);
307
308             rinv10           = gmx_mm_invsqrt_pd(rsq10);
309             rinv20           = gmx_mm_invsqrt_pd(rsq20);
310             rinv30           = gmx_mm_invsqrt_pd(rsq30);
311
312             rinvsq10         = _mm_mul_pd(rinv10,rinv10);
313             rinvsq20         = _mm_mul_pd(rinv20,rinv20);
314             rinvsq30         = _mm_mul_pd(rinv30,rinv30);
315
316             /* Load parameters for j particles */
317             jq0              = _mm_load_sd(charge+jnrA+0);
318
319             fjx0             = _mm_setzero_pd();
320             fjy0             = _mm_setzero_pd();
321             fjz0             = _mm_setzero_pd();
322
323             /**************************
324              * CALCULATE INTERACTIONS *
325              **************************/
326
327             /* Compute parameters for interactions between i and j atoms */
328             qq10             = _mm_mul_pd(iq1,jq0);
329
330             /* COULOMB ELECTROSTATICS */
331             velec            = _mm_mul_pd(qq10,rinv10);
332             felec            = _mm_mul_pd(velec,rinvsq10);
333
334             /* Update potential sum for this i atom from the interaction with this j atom. */
335             velec            = _mm_unpacklo_pd(velec,_mm_setzero_pd());
336             velecsum         = _mm_add_pd(velecsum,velec);
337
338             fscal            = felec;
339
340             fscal            = _mm_unpacklo_pd(fscal,_mm_setzero_pd());
341
342             /* Calculate temporary vectorial force */
343             tx               = _mm_mul_pd(fscal,dx10);
344             ty               = _mm_mul_pd(fscal,dy10);
345             tz               = _mm_mul_pd(fscal,dz10);
346
347             /* Update vectorial force */
348             fix1             = _mm_add_pd(fix1,tx);
349             fiy1             = _mm_add_pd(fiy1,ty);
350             fiz1             = _mm_add_pd(fiz1,tz);
351
352             fjx0             = _mm_add_pd(fjx0,tx);
353             fjy0             = _mm_add_pd(fjy0,ty);
354             fjz0             = _mm_add_pd(fjz0,tz);
355
356             /**************************
357              * CALCULATE INTERACTIONS *
358              **************************/
359
360             /* Compute parameters for interactions between i and j atoms */
361             qq20             = _mm_mul_pd(iq2,jq0);
362
363             /* COULOMB ELECTROSTATICS */
364             velec            = _mm_mul_pd(qq20,rinv20);
365             felec            = _mm_mul_pd(velec,rinvsq20);
366
367             /* Update potential sum for this i atom from the interaction with this j atom. */
368             velec            = _mm_unpacklo_pd(velec,_mm_setzero_pd());
369             velecsum         = _mm_add_pd(velecsum,velec);
370
371             fscal            = felec;
372
373             fscal            = _mm_unpacklo_pd(fscal,_mm_setzero_pd());
374
375             /* Calculate temporary vectorial force */
376             tx               = _mm_mul_pd(fscal,dx20);
377             ty               = _mm_mul_pd(fscal,dy20);
378             tz               = _mm_mul_pd(fscal,dz20);
379
380             /* Update vectorial force */
381             fix2             = _mm_add_pd(fix2,tx);
382             fiy2             = _mm_add_pd(fiy2,ty);
383             fiz2             = _mm_add_pd(fiz2,tz);
384
385             fjx0             = _mm_add_pd(fjx0,tx);
386             fjy0             = _mm_add_pd(fjy0,ty);
387             fjz0             = _mm_add_pd(fjz0,tz);
388
389             /**************************
390              * CALCULATE INTERACTIONS *
391              **************************/
392
393             /* Compute parameters for interactions between i and j atoms */
394             qq30             = _mm_mul_pd(iq3,jq0);
395
396             /* COULOMB ELECTROSTATICS */
397             velec            = _mm_mul_pd(qq30,rinv30);
398             felec            = _mm_mul_pd(velec,rinvsq30);
399
400             /* Update potential sum for this i atom from the interaction with this j atom. */
401             velec            = _mm_unpacklo_pd(velec,_mm_setzero_pd());
402             velecsum         = _mm_add_pd(velecsum,velec);
403
404             fscal            = felec;
405
406             fscal            = _mm_unpacklo_pd(fscal,_mm_setzero_pd());
407
408             /* Calculate temporary vectorial force */
409             tx               = _mm_mul_pd(fscal,dx30);
410             ty               = _mm_mul_pd(fscal,dy30);
411             tz               = _mm_mul_pd(fscal,dz30);
412
413             /* Update vectorial force */
414             fix3             = _mm_add_pd(fix3,tx);
415             fiy3             = _mm_add_pd(fiy3,ty);
416             fiz3             = _mm_add_pd(fiz3,tz);
417
418             fjx0             = _mm_add_pd(fjx0,tx);
419             fjy0             = _mm_add_pd(fjy0,ty);
420             fjz0             = _mm_add_pd(fjz0,tz);
421
422             gmx_mm_decrement_1rvec_1ptr_swizzle_pd(f+j_coord_offsetA,fjx0,fjy0,fjz0);
423
424             /* Inner loop uses 87 flops */
425         }
426
427         /* End of innermost loop */
428
429         gmx_mm_update_iforce_3atom_swizzle_pd(fix1,fiy1,fiz1,fix2,fiy2,fiz2,fix3,fiy3,fiz3,
430                                               f+i_coord_offset+DIM,fshift+i_shift_offset);
431
432         ggid                        = gid[iidx];
433         /* Update potential energies */
434         gmx_mm_update_1pot_pd(velecsum,kernel_data->energygrp_elec+ggid);
435
436         /* Increment number of inner iterations */
437         inneriter                  += j_index_end - j_index_start;
438
439         /* Outer loop uses 19 flops */
440     }
441
442     /* Increment number of outer iterations */
443     outeriter        += nri;
444
445     /* Update outer/inner flops */
446
447     inc_nrnb(nrnb,eNR_NBKERNEL_ELEC_W4_VF,outeriter*19 + inneriter*87);
448 }
449 /*
450  * Gromacs nonbonded kernel:   nb_kernel_ElecCoul_VdwNone_GeomW4P1_F_sse4_1_double
451  * Electrostatics interaction: Coulomb
452  * VdW interaction:            None
453  * Geometry:                   Water4-Particle
454  * Calculate force/pot:        Force
455  */
456 void
457 nb_kernel_ElecCoul_VdwNone_GeomW4P1_F_sse4_1_double
458                     (t_nblist * gmx_restrict                nlist,
459                      rvec * gmx_restrict                    xx,
460                      rvec * gmx_restrict                    ff,
461                      t_forcerec * gmx_restrict              fr,
462                      t_mdatoms * gmx_restrict               mdatoms,
463                      nb_kernel_data_t * gmx_restrict        kernel_data,
464                      t_nrnb * gmx_restrict                  nrnb)
465 {
466     /* Suffixes 0,1,2,3 refer to particle indices for waters in the inner or outer loop, or
467      * just 0 for non-waters.
468      * Suffixes A,B refer to j loop unrolling done with SSE double precision, e.g. for the two different
469      * jnr indices corresponding to data put in the four positions in the SIMD register.
470      */
471     int              i_shift_offset,i_coord_offset,outeriter,inneriter;
472     int              j_index_start,j_index_end,jidx,nri,inr,ggid,iidx;
473     int              jnrA,jnrB;
474     int              j_coord_offsetA,j_coord_offsetB;
475     int              *iinr,*jindex,*jjnr,*shiftidx,*gid;
476     real             rcutoff_scalar;
477     real             *shiftvec,*fshift,*x,*f;
478     __m128d          tx,ty,tz,fscal,rcutoff,rcutoff2,jidxall;
479     int              vdwioffset1;
480     __m128d          ix1,iy1,iz1,fix1,fiy1,fiz1,iq1,isai1;
481     int              vdwioffset2;
482     __m128d          ix2,iy2,iz2,fix2,fiy2,fiz2,iq2,isai2;
483     int              vdwioffset3;
484     __m128d          ix3,iy3,iz3,fix3,fiy3,fiz3,iq3,isai3;
485     int              vdwjidx0A,vdwjidx0B;
486     __m128d          jx0,jy0,jz0,fjx0,fjy0,fjz0,jq0,isaj0;
487     __m128d          dx10,dy10,dz10,rsq10,rinv10,rinvsq10,r10,qq10,c6_10,c12_10;
488     __m128d          dx20,dy20,dz20,rsq20,rinv20,rinvsq20,r20,qq20,c6_20,c12_20;
489     __m128d          dx30,dy30,dz30,rsq30,rinv30,rinvsq30,r30,qq30,c6_30,c12_30;
490     __m128d          velec,felec,velecsum,facel,crf,krf,krf2;
491     real             *charge;
492     __m128d          dummy_mask,cutoff_mask;
493     __m128d          signbit   = gmx_mm_castsi128_pd( _mm_set_epi32(0x80000000,0x00000000,0x80000000,0x00000000) );
494     __m128d          one     = _mm_set1_pd(1.0);
495     __m128d          two     = _mm_set1_pd(2.0);
496     x                = xx[0];
497     f                = ff[0];
498
499     nri              = nlist->nri;
500     iinr             = nlist->iinr;
501     jindex           = nlist->jindex;
502     jjnr             = nlist->jjnr;
503     shiftidx         = nlist->shift;
504     gid              = nlist->gid;
505     shiftvec         = fr->shift_vec[0];
506     fshift           = fr->fshift[0];
507     facel            = _mm_set1_pd(fr->epsfac);
508     charge           = mdatoms->chargeA;
509
510     /* Setup water-specific parameters */
511     inr              = nlist->iinr[0];
512     iq1              = _mm_mul_pd(facel,_mm_set1_pd(charge[inr+1]));
513     iq2              = _mm_mul_pd(facel,_mm_set1_pd(charge[inr+2]));
514     iq3              = _mm_mul_pd(facel,_mm_set1_pd(charge[inr+3]));
515
516     /* Avoid stupid compiler warnings */
517     jnrA = jnrB = 0;
518     j_coord_offsetA = 0;
519     j_coord_offsetB = 0;
520
521     outeriter        = 0;
522     inneriter        = 0;
523
524     /* Start outer loop over neighborlists */
525     for(iidx=0; iidx<nri; iidx++)
526     {
527         /* Load shift vector for this list */
528         i_shift_offset   = DIM*shiftidx[iidx];
529
530         /* Load limits for loop over neighbors */
531         j_index_start    = jindex[iidx];
532         j_index_end      = jindex[iidx+1];
533
534         /* Get outer coordinate index */
535         inr              = iinr[iidx];
536         i_coord_offset   = DIM*inr;
537
538         /* Load i particle coords and add shift vector */
539         gmx_mm_load_shift_and_3rvec_broadcast_pd(shiftvec+i_shift_offset,x+i_coord_offset+DIM,
540                                                  &ix1,&iy1,&iz1,&ix2,&iy2,&iz2,&ix3,&iy3,&iz3);
541
542         fix1             = _mm_setzero_pd();
543         fiy1             = _mm_setzero_pd();
544         fiz1             = _mm_setzero_pd();
545         fix2             = _mm_setzero_pd();
546         fiy2             = _mm_setzero_pd();
547         fiz2             = _mm_setzero_pd();
548         fix3             = _mm_setzero_pd();
549         fiy3             = _mm_setzero_pd();
550         fiz3             = _mm_setzero_pd();
551
552         /* Start inner kernel loop */
553         for(jidx=j_index_start; jidx<j_index_end-1; jidx+=2)
554         {
555
556             /* Get j neighbor index, and coordinate index */
557             jnrA             = jjnr[jidx];
558             jnrB             = jjnr[jidx+1];
559             j_coord_offsetA  = DIM*jnrA;
560             j_coord_offsetB  = DIM*jnrB;
561
562             /* load j atom coordinates */
563             gmx_mm_load_1rvec_2ptr_swizzle_pd(x+j_coord_offsetA,x+j_coord_offsetB,
564                                               &jx0,&jy0,&jz0);
565
566             /* Calculate displacement vector */
567             dx10             = _mm_sub_pd(ix1,jx0);
568             dy10             = _mm_sub_pd(iy1,jy0);
569             dz10             = _mm_sub_pd(iz1,jz0);
570             dx20             = _mm_sub_pd(ix2,jx0);
571             dy20             = _mm_sub_pd(iy2,jy0);
572             dz20             = _mm_sub_pd(iz2,jz0);
573             dx30             = _mm_sub_pd(ix3,jx0);
574             dy30             = _mm_sub_pd(iy3,jy0);
575             dz30             = _mm_sub_pd(iz3,jz0);
576
577             /* Calculate squared distance and things based on it */
578             rsq10            = gmx_mm_calc_rsq_pd(dx10,dy10,dz10);
579             rsq20            = gmx_mm_calc_rsq_pd(dx20,dy20,dz20);
580             rsq30            = gmx_mm_calc_rsq_pd(dx30,dy30,dz30);
581
582             rinv10           = gmx_mm_invsqrt_pd(rsq10);
583             rinv20           = gmx_mm_invsqrt_pd(rsq20);
584             rinv30           = gmx_mm_invsqrt_pd(rsq30);
585
586             rinvsq10         = _mm_mul_pd(rinv10,rinv10);
587             rinvsq20         = _mm_mul_pd(rinv20,rinv20);
588             rinvsq30         = _mm_mul_pd(rinv30,rinv30);
589
590             /* Load parameters for j particles */
591             jq0              = gmx_mm_load_2real_swizzle_pd(charge+jnrA+0,charge+jnrB+0);
592
593             fjx0             = _mm_setzero_pd();
594             fjy0             = _mm_setzero_pd();
595             fjz0             = _mm_setzero_pd();
596
597             /**************************
598              * CALCULATE INTERACTIONS *
599              **************************/
600
601             /* Compute parameters for interactions between i and j atoms */
602             qq10             = _mm_mul_pd(iq1,jq0);
603
604             /* COULOMB ELECTROSTATICS */
605             velec            = _mm_mul_pd(qq10,rinv10);
606             felec            = _mm_mul_pd(velec,rinvsq10);
607
608             fscal            = felec;
609
610             /* Calculate temporary vectorial force */
611             tx               = _mm_mul_pd(fscal,dx10);
612             ty               = _mm_mul_pd(fscal,dy10);
613             tz               = _mm_mul_pd(fscal,dz10);
614
615             /* Update vectorial force */
616             fix1             = _mm_add_pd(fix1,tx);
617             fiy1             = _mm_add_pd(fiy1,ty);
618             fiz1             = _mm_add_pd(fiz1,tz);
619
620             fjx0             = _mm_add_pd(fjx0,tx);
621             fjy0             = _mm_add_pd(fjy0,ty);
622             fjz0             = _mm_add_pd(fjz0,tz);
623
624             /**************************
625              * CALCULATE INTERACTIONS *
626              **************************/
627
628             /* Compute parameters for interactions between i and j atoms */
629             qq20             = _mm_mul_pd(iq2,jq0);
630
631             /* COULOMB ELECTROSTATICS */
632             velec            = _mm_mul_pd(qq20,rinv20);
633             felec            = _mm_mul_pd(velec,rinvsq20);
634
635             fscal            = felec;
636
637             /* Calculate temporary vectorial force */
638             tx               = _mm_mul_pd(fscal,dx20);
639             ty               = _mm_mul_pd(fscal,dy20);
640             tz               = _mm_mul_pd(fscal,dz20);
641
642             /* Update vectorial force */
643             fix2             = _mm_add_pd(fix2,tx);
644             fiy2             = _mm_add_pd(fiy2,ty);
645             fiz2             = _mm_add_pd(fiz2,tz);
646
647             fjx0             = _mm_add_pd(fjx0,tx);
648             fjy0             = _mm_add_pd(fjy0,ty);
649             fjz0             = _mm_add_pd(fjz0,tz);
650
651             /**************************
652              * CALCULATE INTERACTIONS *
653              **************************/
654
655             /* Compute parameters for interactions between i and j atoms */
656             qq30             = _mm_mul_pd(iq3,jq0);
657
658             /* COULOMB ELECTROSTATICS */
659             velec            = _mm_mul_pd(qq30,rinv30);
660             felec            = _mm_mul_pd(velec,rinvsq30);
661
662             fscal            = felec;
663
664             /* Calculate temporary vectorial force */
665             tx               = _mm_mul_pd(fscal,dx30);
666             ty               = _mm_mul_pd(fscal,dy30);
667             tz               = _mm_mul_pd(fscal,dz30);
668
669             /* Update vectorial force */
670             fix3             = _mm_add_pd(fix3,tx);
671             fiy3             = _mm_add_pd(fiy3,ty);
672             fiz3             = _mm_add_pd(fiz3,tz);
673
674             fjx0             = _mm_add_pd(fjx0,tx);
675             fjy0             = _mm_add_pd(fjy0,ty);
676             fjz0             = _mm_add_pd(fjz0,tz);
677
678             gmx_mm_decrement_1rvec_2ptr_swizzle_pd(f+j_coord_offsetA,f+j_coord_offsetB,fjx0,fjy0,fjz0);
679
680             /* Inner loop uses 84 flops */
681         }
682
683         if(jidx<j_index_end)
684         {
685
686             jnrA             = jjnr[jidx];
687             j_coord_offsetA  = DIM*jnrA;
688
689             /* load j atom coordinates */
690             gmx_mm_load_1rvec_1ptr_swizzle_pd(x+j_coord_offsetA,
691                                               &jx0,&jy0,&jz0);
692
693             /* Calculate displacement vector */
694             dx10             = _mm_sub_pd(ix1,jx0);
695             dy10             = _mm_sub_pd(iy1,jy0);
696             dz10             = _mm_sub_pd(iz1,jz0);
697             dx20             = _mm_sub_pd(ix2,jx0);
698             dy20             = _mm_sub_pd(iy2,jy0);
699             dz20             = _mm_sub_pd(iz2,jz0);
700             dx30             = _mm_sub_pd(ix3,jx0);
701             dy30             = _mm_sub_pd(iy3,jy0);
702             dz30             = _mm_sub_pd(iz3,jz0);
703
704             /* Calculate squared distance and things based on it */
705             rsq10            = gmx_mm_calc_rsq_pd(dx10,dy10,dz10);
706             rsq20            = gmx_mm_calc_rsq_pd(dx20,dy20,dz20);
707             rsq30            = gmx_mm_calc_rsq_pd(dx30,dy30,dz30);
708
709             rinv10           = gmx_mm_invsqrt_pd(rsq10);
710             rinv20           = gmx_mm_invsqrt_pd(rsq20);
711             rinv30           = gmx_mm_invsqrt_pd(rsq30);
712
713             rinvsq10         = _mm_mul_pd(rinv10,rinv10);
714             rinvsq20         = _mm_mul_pd(rinv20,rinv20);
715             rinvsq30         = _mm_mul_pd(rinv30,rinv30);
716
717             /* Load parameters for j particles */
718             jq0              = _mm_load_sd(charge+jnrA+0);
719
720             fjx0             = _mm_setzero_pd();
721             fjy0             = _mm_setzero_pd();
722             fjz0             = _mm_setzero_pd();
723
724             /**************************
725              * CALCULATE INTERACTIONS *
726              **************************/
727
728             /* Compute parameters for interactions between i and j atoms */
729             qq10             = _mm_mul_pd(iq1,jq0);
730
731             /* COULOMB ELECTROSTATICS */
732             velec            = _mm_mul_pd(qq10,rinv10);
733             felec            = _mm_mul_pd(velec,rinvsq10);
734
735             fscal            = felec;
736
737             fscal            = _mm_unpacklo_pd(fscal,_mm_setzero_pd());
738
739             /* Calculate temporary vectorial force */
740             tx               = _mm_mul_pd(fscal,dx10);
741             ty               = _mm_mul_pd(fscal,dy10);
742             tz               = _mm_mul_pd(fscal,dz10);
743
744             /* Update vectorial force */
745             fix1             = _mm_add_pd(fix1,tx);
746             fiy1             = _mm_add_pd(fiy1,ty);
747             fiz1             = _mm_add_pd(fiz1,tz);
748
749             fjx0             = _mm_add_pd(fjx0,tx);
750             fjy0             = _mm_add_pd(fjy0,ty);
751             fjz0             = _mm_add_pd(fjz0,tz);
752
753             /**************************
754              * CALCULATE INTERACTIONS *
755              **************************/
756
757             /* Compute parameters for interactions between i and j atoms */
758             qq20             = _mm_mul_pd(iq2,jq0);
759
760             /* COULOMB ELECTROSTATICS */
761             velec            = _mm_mul_pd(qq20,rinv20);
762             felec            = _mm_mul_pd(velec,rinvsq20);
763
764             fscal            = felec;
765
766             fscal            = _mm_unpacklo_pd(fscal,_mm_setzero_pd());
767
768             /* Calculate temporary vectorial force */
769             tx               = _mm_mul_pd(fscal,dx20);
770             ty               = _mm_mul_pd(fscal,dy20);
771             tz               = _mm_mul_pd(fscal,dz20);
772
773             /* Update vectorial force */
774             fix2             = _mm_add_pd(fix2,tx);
775             fiy2             = _mm_add_pd(fiy2,ty);
776             fiz2             = _mm_add_pd(fiz2,tz);
777
778             fjx0             = _mm_add_pd(fjx0,tx);
779             fjy0             = _mm_add_pd(fjy0,ty);
780             fjz0             = _mm_add_pd(fjz0,tz);
781
782             /**************************
783              * CALCULATE INTERACTIONS *
784              **************************/
785
786             /* Compute parameters for interactions between i and j atoms */
787             qq30             = _mm_mul_pd(iq3,jq0);
788
789             /* COULOMB ELECTROSTATICS */
790             velec            = _mm_mul_pd(qq30,rinv30);
791             felec            = _mm_mul_pd(velec,rinvsq30);
792
793             fscal            = felec;
794
795             fscal            = _mm_unpacklo_pd(fscal,_mm_setzero_pd());
796
797             /* Calculate temporary vectorial force */
798             tx               = _mm_mul_pd(fscal,dx30);
799             ty               = _mm_mul_pd(fscal,dy30);
800             tz               = _mm_mul_pd(fscal,dz30);
801
802             /* Update vectorial force */
803             fix3             = _mm_add_pd(fix3,tx);
804             fiy3             = _mm_add_pd(fiy3,ty);
805             fiz3             = _mm_add_pd(fiz3,tz);
806
807             fjx0             = _mm_add_pd(fjx0,tx);
808             fjy0             = _mm_add_pd(fjy0,ty);
809             fjz0             = _mm_add_pd(fjz0,tz);
810
811             gmx_mm_decrement_1rvec_1ptr_swizzle_pd(f+j_coord_offsetA,fjx0,fjy0,fjz0);
812
813             /* Inner loop uses 84 flops */
814         }
815
816         /* End of innermost loop */
817
818         gmx_mm_update_iforce_3atom_swizzle_pd(fix1,fiy1,fiz1,fix2,fiy2,fiz2,fix3,fiy3,fiz3,
819                                               f+i_coord_offset+DIM,fshift+i_shift_offset);
820
821         /* Increment number of inner iterations */
822         inneriter                  += j_index_end - j_index_start;
823
824         /* Outer loop uses 18 flops */
825     }
826
827     /* Increment number of outer iterations */
828     outeriter        += nri;
829
830     /* Update outer/inner flops */
831
832     inc_nrnb(nrnb,eNR_NBKERNEL_ELEC_W4_F,outeriter*18 + inneriter*84);
833 }