Give bTypePerturbed a valid initial value
[alexxy/gromacs.git] / src / gromacs / mdlib / perf_est.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-2008, The GROMACS development team.
6  * Copyright (c) 2012,2014,2015, 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 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #include <math.h>
42
43 #include "perf_est.h"
44 #include "physics.h"
45 #include "vec.h"
46 #include "mtop_util.h"
47 #include "types/commrec.h"
48 #include "nbnxn_search.h"
49 #include "nbnxn_consts.h"
50
51
52 /* Computational cost of bonded, non-bonded and PME calculations.
53  * This will be machine dependent.
54  * The numbers here are accurate for Intel Core2 and AMD Athlon 64
55  * in single precision. In double precision PME mesh is slightly cheaper,
56  * although not so much that the numbers need to be adjusted.
57  */
58
59 /* Cost of a pair interaction in the "group" cut-off scheme */
60 #define C_GR_FQ        1.5
61 #define C_GR_QLJ_CUT   1.5
62 #define C_GR_QLJ_TAB   2.0
63 #define C_GR_LJ_CUT    1.0
64 #define C_GR_LJ_TAB    1.75
65 /* Cost of 1 water with one Q/LJ atom */
66 #define C_GR_QLJW_CUT  2.0
67 #define C_GR_QLJW_TAB  2.25
68 /* Cost of 1 water with one Q atom or with 1/3 water (LJ negligible) */
69 #define C_GR_QW        1.75
70
71 /* Cost of a pair interaction in the "Verlet" cut-off scheme, QEXP is Ewald */
72 #define C_VT_LJ        0.30
73 #define C_VT_QRF_LJ    0.40
74 #define C_VT_QRF       0.30
75 #define C_VT_QEXP_LJ   0.55
76 #define C_VT_QEXP      0.50
77 /* Extra cost for expensive LJ interaction, e.g. pot-switch or LJ-PME */
78 #define C_VT_LJEXP_ADD 0.20
79
80 /* Cost of PME, with all components running with SSE instructions */
81 /* Cost of particle reordering and redistribution */
82 #define C_PME_REDIST  12.0
83 /* Cost of q spreading and force interpolation per charge (mainly memory) */
84 #define C_PME_SPREAD  0.30
85 /* Cost of fft's, will be multiplied with N log(N) */
86 #define C_PME_FFT     0.20
87 /* Cost of pme_solve, will be multiplied with N */
88 #define C_PME_SOLVE   0.50
89
90 /* Cost of a bonded interaction divided by the number of (pbc_)dx nrequired */
91 #define C_BOND        5.0
92
93 int n_bonded_dx(gmx_mtop_t *mtop, gmx_bool bExcl)
94 {
95     int            mb, nmol, ftype, ndxb, ndx_excl;
96     int            ndx;
97     gmx_moltype_t *molt;
98
99     /* Count the number of pbc_rvec_sub calls required for bonded interactions.
100      * This number is also roughly proportional to the computational cost.
101      */
102     ndx      = 0;
103     ndx_excl = 0;
104 #if __ICC == 1400 || __ICL == 1400
105 #pragma novector /* Work-around for incorrect vectorization */
106 #endif
107     for (mb = 0; mb < mtop->nmolblock; mb++)
108     {
109         molt = &mtop->moltype[mtop->molblock[mb].type];
110         nmol = mtop->molblock[mb].nmol;
111         for (ftype = 0; ftype < F_NRE; ftype++)
112         {
113             if (interaction_function[ftype].flags & IF_BOND)
114             {
115                 switch (ftype)
116                 {
117                     case F_POSRES:
118                     case F_FBPOSRES:  ndxb = 1; break;
119                     case F_CONNBONDS: ndxb = 0; break;
120                     default:     ndxb      = NRAL(ftype) - 1; break;
121                 }
122                 ndx += nmol*ndxb*molt->ilist[ftype].nr/(1 + NRAL(ftype));
123             }
124         }
125         if (bExcl)
126         {
127             ndx_excl += nmol*(molt->excls.nra - molt->atoms.nr)/2;
128         }
129         else
130         {
131             ndx_excl = 0;
132         }
133     }
134
135     if (debug)
136     {
137         fprintf(debug, "ndx bonded %d exclusions %d\n", ndx, ndx_excl);
138     }
139
140     ndx += ndx_excl;
141
142     return ndx;
143 }
144
145 static void pp_group_load(gmx_mtop_t *mtop, t_inputrec *ir, matrix box,
146                           int *nq_tot, int *nlj_tot,
147                           double *cost_pp,
148                           gmx_bool *bChargePerturbed, gmx_bool *bTypePerturbed)
149 {
150     t_atom        *atom;
151     int            mb, nmol, atnr, cg, a, a0, ncqlj, ncq, nclj;
152     gmx_bool       bBHAM, bLJcut, bWater, bQ, bLJ;
153     int            nw, nqlj, nq, nlj;
154     float          fq, fqlj, flj, fljtab, fqljw, fqw;
155     t_iparams     *iparams;
156     gmx_moltype_t *molt;
157
158     bBHAM = (mtop->ffparams.functype[0] == F_BHAM);
159
160     bLJcut = ((ir->vdwtype == evdwCUT) && !bBHAM);
161
162     /* Computational cost of bonded, non-bonded and PME calculations.
163      * This will be machine dependent.
164      * The numbers here are accurate for Intel Core2 and AMD Athlon 64
165      * in single precision. In double precision PME mesh is slightly cheaper,
166      * although not so much that the numbers need to be adjusted.
167      */
168     fq    = C_GR_FQ;
169     fqlj  = (bLJcut ? C_GR_QLJ_CUT : C_GR_QLJ_TAB);
170     flj   = (bLJcut ? C_GR_LJ_CUT  : C_GR_LJ_TAB);
171     /* Cost of 1 water with one Q/LJ atom */
172     fqljw = (bLJcut ? C_GR_QLJW_CUT : C_GR_QLJW_TAB);
173     /* Cost of 1 water with one Q atom or with 1/3 water (LJ negligible) */
174     fqw   = C_GR_QW;
175
176     iparams           = mtop->ffparams.iparams;
177     atnr              = mtop->ffparams.atnr;
178     nw                = 0;
179     nqlj              = 0;
180     nq                = 0;
181     nlj               = 0;
182     *bChargePerturbed = FALSE;
183     *bTypePerturbed   = FALSE;
184     for (mb = 0; mb < mtop->nmolblock; mb++)
185     {
186         molt = &mtop->moltype[mtop->molblock[mb].type];
187         atom = molt->atoms.atom;
188         nmol = mtop->molblock[mb].nmol;
189         a    = 0;
190         for (cg = 0; cg < molt->cgs.nr; cg++)
191         {
192             bWater = !bBHAM;
193             ncqlj  = 0;
194             ncq    = 0;
195             nclj   = 0;
196             a0     = a;
197             while (a < molt->cgs.index[cg+1])
198             {
199                 bQ  = (atom[a].q != 0 || atom[a].qB != 0);
200                 bLJ = (iparams[(atnr+1)*atom[a].type].lj.c6  != 0 ||
201                        iparams[(atnr+1)*atom[a].type].lj.c12 != 0);
202                 if (atom[a].q != atom[a].qB)
203                 {
204                     *bChargePerturbed = TRUE;
205                 }
206                 if (atom[a].type != atom[a].typeB)
207                 {
208                     *bTypePerturbed = TRUE;
209                 }
210                 /* This if this atom fits into water optimization */
211                 if (!((a == a0   &&  bQ &&  bLJ) ||
212                       (a == a0+1 &&  bQ && !bLJ) ||
213                       (a == a0+2 &&  bQ && !bLJ && atom[a].q == atom[a-1].q) ||
214                       (a == a0+3 && !bQ &&  bLJ)))
215                 {
216                     bWater = FALSE;
217                 }
218                 if (bQ && bLJ)
219                 {
220                     ncqlj++;
221                 }
222                 else
223                 {
224                     if (bQ)
225                     {
226                         ncq++;
227                     }
228                     if (bLJ)
229                     {
230                         nclj++;
231                     }
232                 }
233                 a++;
234             }
235             if (bWater)
236             {
237                 nw   += nmol;
238             }
239             else
240             {
241                 nqlj += nmol*ncqlj;
242                 nq   += nmol*ncq;
243                 nlj  += nmol*nclj;
244             }
245         }
246     }
247
248     *nq_tot  = nq  + nqlj + nw*3;
249     *nlj_tot = nlj + nqlj + nw;
250
251     if (debug)
252     {
253         fprintf(debug, "nw %d nqlj %d nq %d nlj %d\n", nw, nqlj, nq, nlj);
254     }
255
256     /* For the PP non-bonded cost it is (unrealistically) assumed
257      * that all atoms are distributed homogeneously in space.
258      * Factor 3 is used because a water molecule has 3 atoms
259      * (and TIP4P effectively has 3 interactions with (water) atoms)).
260      */
261     *cost_pp = 0.5*(fqljw*nw*nqlj +
262                     fqw  *nw*(3*nw + nq) +
263                     fqlj *nqlj*nqlj +
264                     fq   *nq*(3*nw + nqlj + nq) +
265                     flj  *nlj*(nw + nqlj + nlj))
266         *4/3*M_PI*ir->rlist*ir->rlist*ir->rlist/det(box);
267 }
268
269 static void pp_verlet_load(gmx_mtop_t *mtop, t_inputrec *ir, matrix box,
270                            int *nq_tot, int *nlj_tot,
271                            double *cost_pp,
272                            gmx_bool *bChargePerturbed, gmx_bool *bTypePerturbed)
273 {
274     t_atom        *atom;
275     int            mb, nmol, atnr, cg, a, a0, nqlj, nq, nlj;
276     gmx_bool       bQRF;
277     t_iparams     *iparams;
278     gmx_moltype_t *molt;
279     real           r_eff;
280     double         c_qlj, c_q, c_lj;
281     double         nat;
282     /* Conversion factor for reference vs SIMD kernel performance.
283      * The factor is about right for SSE2/4, but should be 2 higher for AVX256.
284      */
285 #ifdef GMX_DOUBLE
286     const real     nbnxn_refkernel_fac = 4.0;
287 #else
288     const real     nbnxn_refkernel_fac = 8.0;
289 #endif
290
291     bQRF = (EEL_RF(ir->coulombtype) || ir->coulombtype == eelCUT);
292
293     iparams           = mtop->ffparams.iparams;
294     atnr              = mtop->ffparams.atnr;
295     nqlj              = 0;
296     nq                = 0;
297     *bChargePerturbed = FALSE;
298     *bTypePerturbed   = FALSE;
299     for (mb = 0; mb < mtop->nmolblock; mb++)
300     {
301         molt = &mtop->moltype[mtop->molblock[mb].type];
302         atom = molt->atoms.atom;
303         nmol = mtop->molblock[mb].nmol;
304         a    = 0;
305         for (a = 0; a < molt->atoms.nr; a++)
306         {
307             if (atom[a].q != 0 || atom[a].qB != 0)
308             {
309                 if (iparams[(atnr+1)*atom[a].type].lj.c6  != 0 ||
310                     iparams[(atnr+1)*atom[a].type].lj.c12 != 0)
311                 {
312                     nqlj += nmol;
313                 }
314                 else
315                 {
316                     nq += nmol;
317                 }
318             }
319             if (atom[a].q != atom[a].qB)
320             {
321                 *bChargePerturbed = TRUE;
322             }
323             if (atom[a].type != atom[a].typeB)
324             {
325                 *bTypePerturbed = TRUE;
326             }
327         }
328     }
329
330     nlj = mtop->natoms - nqlj - nq;
331
332     *nq_tot  = nqlj + nq;
333     *nlj_tot = nqlj + nlj;
334
335     /* Effective cut-off for cluster pair list of 4x4 atoms */
336     r_eff = ir->rlist + nbnxn_get_rlist_effective_inc(NBNXN_CPU_CLUSTER_I_SIZE, mtop->natoms/det(box));
337
338     if (debug)
339     {
340         fprintf(debug, "nqlj %d nq %d nlj %d rlist %.3f r_eff %.3f\n",
341                 nqlj, nq, nlj, ir->rlist, r_eff);
342     }
343
344     /* Determine the cost per pair interaction */
345     c_qlj = (bQRF ? C_VT_QRF_LJ : C_VT_QEXP_LJ);
346     c_q   = (bQRF ? C_VT_QRF    : C_VT_QEXP);
347     c_lj  = C_VT_LJ;
348     if (ir->vdw_modifier == eintmodPOTSWITCH || EVDW_PME(ir->vdwtype))
349     {
350         c_qlj += C_VT_LJEXP_ADD;
351         c_lj  += C_VT_LJEXP_ADD;
352     }
353     if (EVDW_PME(ir->vdwtype) && ir->ljpme_combination_rule == eljpmeLB)
354     {
355         /* We don't have LJ-PME LB comb. rule kernels, we use slow kernels */
356         c_qlj *= nbnxn_refkernel_fac;
357         c_q   *= nbnxn_refkernel_fac;
358         c_lj  *= nbnxn_refkernel_fac;
359     }
360
361     /* For the PP non-bonded cost it is (unrealistically) assumed
362      * that all atoms are distributed homogeneously in space.
363      */
364     /* Convert mtop->natoms to double to avoid int overflow */
365     nat      = mtop->natoms;
366     *cost_pp = 0.5*nat*(nqlj*c_qlj + nq*c_q + nlj*c_lj)
367         *4/3*M_PI*r_eff*r_eff*r_eff/det(box);
368 }
369
370 float pme_load_estimate(gmx_mtop_t *mtop, t_inputrec *ir, matrix box)
371 {
372     t_atom        *atom;
373     int            mb, nmol, atnr, cg, a, a0, nq_tot, nlj_tot, f;
374     gmx_bool       bBHAM, bLJcut, bChargePerturbed, bTypePerturbed;
375     gmx_bool       bWater, bQ, bLJ;
376     double         cost_bond, cost_pp, cost_redist, cost_spread, cost_fft, cost_solve, cost_pme;
377     float          ratio;
378     t_iparams     *iparams;
379     gmx_moltype_t *molt;
380
381     /* Computational cost of bonded, non-bonded and PME calculations.
382      * This will be machine dependent.
383      * The numbers here are accurate for Intel Core2 and AMD Athlon 64
384      * in single precision. In double precision PME mesh is slightly cheaper,
385      * although not so much that the numbers need to be adjusted.
386      */
387
388     iparams = mtop->ffparams.iparams;
389     atnr    = mtop->ffparams.atnr;
390
391     cost_bond = C_BOND*n_bonded_dx(mtop, TRUE);
392
393     if (ir->cutoff_scheme == ecutsGROUP)
394     {
395         pp_group_load(mtop, ir, box,
396                       &nq_tot, &nlj_tot, &cost_pp,
397                       &bChargePerturbed, &bTypePerturbed);
398     }
399     else
400     {
401         pp_verlet_load(mtop, ir, box,
402                        &nq_tot, &nlj_tot, &cost_pp,
403                        &bChargePerturbed, &bTypePerturbed);
404     }
405
406     cost_redist = 0;
407     cost_spread = 0;
408     cost_fft    = 0;
409     cost_solve  = 0;
410
411     if (EEL_PME(ir->coulombtype))
412     {
413         f            = ((ir->efep != efepNO && bChargePerturbed) ? 2 : 1);
414         cost_redist +=   C_PME_REDIST*nq_tot;
415         cost_spread += f*C_PME_SPREAD*nq_tot*pow(ir->pme_order, 3);
416         cost_fft    += f*C_PME_FFT*ir->nkx*ir->nky*ir->nkz*log(ir->nkx*ir->nky*ir->nkz);
417         cost_solve  += f*C_PME_SOLVE*ir->nkx*ir->nky*ir->nkz;
418     }
419
420     if (EVDW_PME(ir->vdwtype))
421     {
422         f            = ((ir->efep != efepNO && bTypePerturbed) ? 2 : 1);
423         if (ir->ljpme_combination_rule == eljpmeLB)
424         {
425             /* LB combination rule: we have 7 mesh terms */
426             f       *= 7;
427         }
428         cost_redist +=   C_PME_REDIST*nlj_tot;
429         cost_spread += f*C_PME_SPREAD*nlj_tot*pow(ir->pme_order, 3);
430         cost_fft    += f*C_PME_FFT*ir->nkx*ir->nky*ir->nkz*log(ir->nkx*ir->nky*ir->nkz);
431         cost_solve  += f*C_PME_SOLVE*ir->nkx*ir->nky*ir->nkz;
432     }
433
434     cost_pme = cost_redist + cost_spread + cost_fft + cost_solve;
435
436     ratio = cost_pme/(cost_bond + cost_pp + cost_pme);
437
438     if (debug)
439     {
440         fprintf(debug,
441                 "cost_bond   %f\n"
442                 "cost_pp     %f\n"
443                 "cost_redist %f\n"
444                 "cost_spread %f\n"
445                 "cost_fft    %f\n"
446                 "cost_solve  %f\n",
447                 cost_bond, cost_pp, cost_redist, cost_spread, cost_fft, cost_solve);
448
449         fprintf(debug, "Estimate for relative PME load: %.3f\n", ratio);
450     }
451
452     return ratio;
453 }