Use bitmask for bonded
[alexxy/gromacs.git] / src / gromacs / listed-forces / listed-forces.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2014, 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 /*! \internal \file
36  *
37  * \brief This file defines high-level functions for mdrun to compute
38  * energies and forces for listed interactions.
39  *
40  * \author Mark Abraham <mark.j.abraham@gmail.com>
41  *
42  * \ingroup module_listed-forces
43  */
44 #include "gmxpre.h"
45
46 #include "listed-forces.h"
47
48 #include "config.h"
49
50 #include <assert.h>
51
52 #include <algorithm>
53
54 #include "gromacs/legacyheaders/disre.h"
55 #include "gromacs/legacyheaders/force.h"
56 #include "gromacs/legacyheaders/network.h"
57 #include "gromacs/legacyheaders/nrnb.h"
58 #include "gromacs/legacyheaders/orires.h"
59 #include "gromacs/legacyheaders/types/force_flags.h"
60 #include "gromacs/listed-forces/bonded.h"
61 #include "gromacs/listed-forces/position-restraints.h"
62 #include "gromacs/math/vec.h"
63 #include "gromacs/mdlib/forcerec-threading.h"
64 #include "gromacs/pbcutil/ishift.h"
65 #include "gromacs/pbcutil/pbc.h"
66 #include "gromacs/timing/wallcycle.h"
67 #include "gromacs/utility/smalloc.h"
68
69 #include "pairs.h"
70
71 namespace
72 {
73
74 /*! \brief Return true if ftype is an explicit pair-listed LJ or
75  * COULOMB interaction type: bonded LJ (usually 1-4), or special
76  * listed non-bonded for FEP. */
77 bool
78 isPairInteraction(int ftype)
79 {
80     return ((ftype) >= F_LJ14 && (ftype) <= F_LJC_PAIRS_NB);
81 }
82
83 /*! \brief Zero thread-local force-output buffers */
84 void
85 zero_thread_forces(f_thread_t *f_t, int n,
86                    int nblock, int blocksize)
87 {
88     int b, a0, a1, a, i, j;
89
90     if (n > f_t->f_nalloc)
91     {
92         f_t->f_nalloc = over_alloc_large(n);
93         srenew(f_t->f, f_t->f_nalloc);
94     }
95
96     if (!bitmask_is_zero(f_t->red_mask))
97     {
98         for (b = 0; b < nblock; b++)
99         {
100             if (bitmask_is_set(f_t->red_mask, b))
101             {
102                 a0 = b*blocksize;
103                 a1 = std::min((b+1)*blocksize, n);
104                 for (a = a0; a < a1; a++)
105                 {
106                     clear_rvec(f_t->f[a]);
107                 }
108             }
109         }
110     }
111     for (i = 0; i < SHIFTS; i++)
112     {
113         clear_rvec(f_t->fshift[i]);
114     }
115     for (i = 0; i < F_NRE; i++)
116     {
117         f_t->ener[i] = 0;
118     }
119     for (i = 0; i < egNR; i++)
120     {
121         for (j = 0; j < f_t->grpp.nener; j++)
122         {
123             f_t->grpp.ener[i][j] = 0;
124         }
125     }
126     for (i = 0; i < efptNR; i++)
127     {
128         f_t->dvdl[i] = 0;
129     }
130 }
131
132 /*! \brief The max thread number is arbitrary, we used a fixed number
133  * to avoid memory management.  Using more than 16 threads is probably
134  * never useful performance wise. */
135 #define MAX_BONDED_THREADS 256
136
137 /*! \brief Reduce thread-local force buffers */
138 void
139 reduce_thread_force_buffer(int n, rvec *f,
140                            int nthreads, f_thread_t *f_t,
141                            int nblock, int block_size)
142 {
143     int b;
144
145     if (nthreads > MAX_BONDED_THREADS)
146     {
147         gmx_fatal(FARGS, "Can not reduce bonded forces on more than %d threads",
148                   MAX_BONDED_THREADS);
149     }
150
151     /* This reduction can run on any number of threads,
152      * independently of nthreads.
153      */
154 #pragma omp parallel for num_threads(nthreads) schedule(static)
155     for (b = 0; b < nblock; b++)
156     {
157         rvec *fp[MAX_BONDED_THREADS];
158         int   nfb, ft, fb;
159         int   a0, a1, a;
160
161         /* Determine which threads contribute to this block */
162         nfb = 0;
163         for (ft = 1; ft < nthreads; ft++)
164         {
165             if (bitmask_is_set(f_t[ft].red_mask, b))
166             {
167                 fp[nfb++] = f_t[ft].f;
168             }
169         }
170         if (nfb > 0)
171         {
172             /* Reduce force buffers for threads that contribute */
173             a0 =  b   *block_size;
174             a1 = (b+1)*block_size;
175             a1 = std::min(a1, n);
176             for (a = a0; a < a1; a++)
177             {
178                 for (fb = 0; fb < nfb; fb++)
179                 {
180                     rvec_inc(f[a], fp[fb][a]);
181                 }
182             }
183         }
184     }
185 }
186
187 /*! \brief Reduce thread-local forces */
188 void
189 reduce_thread_forces(int n, rvec *f, rvec *fshift,
190                      real *ener, gmx_grppairener_t *grpp, real *dvdl,
191                      int nthreads, f_thread_t *f_t,
192                      int nblock, int block_size,
193                      gmx_bool bCalcEnerVir,
194                      gmx_bool bDHDL)
195 {
196     if (nblock > 0)
197     {
198         /* Reduce the bonded force buffer */
199         reduce_thread_force_buffer(n, f, nthreads, f_t, nblock, block_size);
200     }
201
202     /* When necessary, reduce energy and virial using one thread only */
203     if (bCalcEnerVir)
204     {
205         int t, i, j;
206
207         for (i = 0; i < SHIFTS; i++)
208         {
209             for (t = 1; t < nthreads; t++)
210             {
211                 rvec_inc(fshift[i], f_t[t].fshift[i]);
212             }
213         }
214         for (i = 0; i < F_NRE; i++)
215         {
216             for (t = 1; t < nthreads; t++)
217             {
218                 ener[i] += f_t[t].ener[i];
219             }
220         }
221         for (i = 0; i < egNR; i++)
222         {
223             for (j = 0; j < f_t[1].grpp.nener; j++)
224             {
225                 for (t = 1; t < nthreads; t++)
226                 {
227
228                     grpp->ener[i][j] += f_t[t].grpp.ener[i][j];
229                 }
230             }
231         }
232         if (bDHDL)
233         {
234             for (i = 0; i < efptNR; i++)
235             {
236
237                 for (t = 1; t < nthreads; t++)
238                 {
239                     dvdl[i] += f_t[t].dvdl[i];
240                 }
241             }
242         }
243     }
244 }
245
246 /*! \brief Calculate one element of the list of bonded interactions
247     for this thread */
248 real
249 calc_one_bond(int thread,
250               int ftype, const t_idef *idef,
251               const rvec x[], rvec f[], rvec fshift[],
252               t_forcerec *fr,
253               const t_pbc *pbc, const t_graph *g,
254               gmx_grppairener_t *grpp,
255               t_nrnb *nrnb,
256               real *lambda, real *dvdl,
257               const t_mdatoms *md, t_fcdata *fcd,
258               gmx_bool bCalcEnerVir,
259               int *global_atom_index)
260 {
261     int      nat1, nbonds, efptFTYPE;
262     real     v = 0;
263     t_iatom *iatoms;
264     int      nb0, nbn;
265
266     if (IS_RESTRAINT_TYPE(ftype))
267     {
268         efptFTYPE = efptRESTRAINT;
269     }
270     else
271     {
272         efptFTYPE = efptBONDED;
273     }
274
275     nat1      = interaction_function[ftype].nratoms + 1;
276     nbonds    = idef->il[ftype].nr/nat1;
277     iatoms    = idef->il[ftype].iatoms;
278
279     nb0 = idef->il_thread_division[ftype*(idef->nthreads+1)+thread];
280     nbn = idef->il_thread_division[ftype*(idef->nthreads+1)+thread+1] - nb0;
281
282     if (!isPairInteraction(ftype))
283     {
284         if (ftype == F_CMAP)
285         {
286             v = cmap_dihs(nbn, iatoms+nb0,
287                           idef->iparams, &idef->cmap_grid,
288                           x, f, fshift,
289                           pbc, g, lambda[efptFTYPE], &(dvdl[efptFTYPE]),
290                           md, fcd, global_atom_index);
291         }
292 #ifdef GMX_SIMD_HAVE_REAL
293         else if (ftype == F_ANGLES &&
294                  !bCalcEnerVir && fr->efep == efepNO)
295         {
296             /* No energies, shift forces, dvdl */
297             angles_noener_simd(nbn, idef->il[ftype].iatoms+nb0,
298                                idef->iparams,
299                                x, f,
300                                pbc, g, lambda[efptFTYPE], md, fcd,
301                                global_atom_index);
302             v = 0;
303         }
304 #endif
305         else if (ftype == F_PDIHS &&
306                  !bCalcEnerVir && fr->efep == efepNO)
307         {
308             /* No energies, shift forces, dvdl */
309 #ifdef GMX_SIMD_HAVE_REAL
310             pdihs_noener_simd
311 #else
312             pdihs_noener
313 #endif
314                 (nbn, idef->il[ftype].iatoms+nb0,
315                 idef->iparams,
316                 x, f,
317                 pbc, g, lambda[efptFTYPE], md, fcd,
318                 global_atom_index);
319             v = 0;
320         }
321         else
322         {
323             v = interaction_function[ftype].ifunc(nbn, iatoms+nb0,
324                                                   idef->iparams,
325                                                   x, f, fshift,
326                                                   pbc, g, lambda[efptFTYPE], &(dvdl[efptFTYPE]),
327                                                   md, fcd, global_atom_index);
328         }
329     }
330     else
331     {
332         v = do_pairs(ftype, nbn, iatoms+nb0, idef->iparams, x, f, fshift,
333                      pbc, g, lambda, dvdl, md, fr, grpp, global_atom_index);
334     }
335
336     if (thread == 0)
337     {
338         inc_nrnb(nrnb, interaction_function[ftype].nrnb_ind, nbonds);
339     }
340
341     return v;
342 }
343
344 } // namespace
345
346 void calc_listed(const gmx_multisim_t *ms,
347                  const t_idef *idef,
348                  const rvec x[], history_t *hist,
349                  rvec f[], t_forcerec *fr,
350                  const struct t_pbc *pbc,
351                  const struct t_pbc *pbc_full,
352                  const struct t_graph *g,
353                  gmx_enerdata_t *enerd, t_nrnb *nrnb,
354                  real *lambda,
355                  const t_mdatoms *md,
356                  t_fcdata *fcd, int *global_atom_index,
357                  int force_flags)
358 {
359     gmx_bool      bCalcEnerVir;
360     int           i;
361     real          dvdl[efptNR]; /* The dummy array is to have a place to store the dhdl at other values
362                                                         of lambda, which will be thrown away in the end*/
363     const  t_pbc *pbc_null;
364     int           thread;
365
366     assert(fr->nthreads == idef->nthreads);
367
368     bCalcEnerVir = (force_flags & (GMX_FORCE_VIRIAL | GMX_FORCE_ENERGY));
369
370     for (i = 0; i < efptNR; i++)
371     {
372         dvdl[i] = 0.0;
373     }
374     if (fr->bMolPBC)
375     {
376         pbc_null = pbc;
377     }
378     else
379     {
380         pbc_null = NULL;
381     }
382
383 #ifdef DEBUG
384     if (g && debug)
385     {
386         p_graph(debug, "Bondage is fun", g);
387     }
388 #endif
389
390     if (idef->il[F_POSRES].nr > 0)
391     {
392         posres_wrapper(nrnb, idef, pbc_full, x, enerd, lambda, fr);
393     }
394
395     if (idef->il[F_FBPOSRES].nr > 0)
396     {
397         fbposres_wrapper(nrnb, idef, pbc_full, x, enerd, fr);
398     }
399
400     /* Do pre force calculation stuff which might require communication */
401     if (idef->il[F_ORIRES].nr)
402     {
403         enerd->term[F_ORIRESDEV] =
404             calc_orires_dev(ms, idef->il[F_ORIRES].nr,
405                             idef->il[F_ORIRES].iatoms,
406                             idef->iparams, md, x,
407                             pbc_null, fcd, hist);
408     }
409     if (idef->il[F_DISRES].nr)
410     {
411         calc_disres_R_6(idef->il[F_DISRES].nr,
412                         idef->il[F_DISRES].iatoms,
413                         idef->iparams, x, pbc_null,
414                         fcd, hist);
415 #ifdef GMX_MPI
416         if (fcd->disres.nsystems > 1)
417         {
418             gmx_sum_sim(2*fcd->disres.nres, fcd->disres.Rt_6, ms);
419         }
420 #endif
421     }
422
423 #pragma omp parallel for num_threads(fr->nthreads) schedule(static)
424     for (thread = 0; thread < fr->nthreads; thread++)
425     {
426         int                ftype;
427         real              *epot, v;
428         /* thread stuff */
429         rvec              *ft, *fshift;
430         real              *dvdlt;
431         gmx_grppairener_t *grpp;
432
433         if (thread == 0)
434         {
435             ft     = f;
436             fshift = fr->fshift;
437             epot   = enerd->term;
438             grpp   = &enerd->grpp;
439             dvdlt  = dvdl;
440         }
441         else
442         {
443             zero_thread_forces(&fr->f_t[thread], fr->natoms_force,
444                                fr->red_nblock, 1<<fr->red_ashift);
445
446             ft     = fr->f_t[thread].f;
447             fshift = fr->f_t[thread].fshift;
448             epot   = fr->f_t[thread].ener;
449             grpp   = &fr->f_t[thread].grpp;
450             dvdlt  = fr->f_t[thread].dvdl;
451         }
452         /* Loop over all bonded force types to calculate the bonded forces */
453         for (ftype = 0; (ftype < F_NRE); ftype++)
454         {
455             if (idef->il[ftype].nr > 0 && ftype_is_bonded_potential(ftype))
456             {
457                 v = calc_one_bond(thread, ftype, idef, x,
458                                   ft, fshift, fr, pbc_null, g, grpp,
459                                   nrnb, lambda, dvdlt,
460                                   md, fcd, bCalcEnerVir,
461                                   global_atom_index);
462                 epot[ftype] += v;
463             }
464         }
465     }
466     if (fr->nthreads > 1)
467     {
468         reduce_thread_forces(fr->natoms_force, f, fr->fshift,
469                              enerd->term, &enerd->grpp, dvdl,
470                              fr->nthreads, fr->f_t,
471                              fr->red_nblock, 1<<fr->red_ashift,
472                              bCalcEnerVir,
473                              force_flags & GMX_FORCE_DHDL);
474     }
475     if (force_flags & GMX_FORCE_DHDL)
476     {
477         for (i = 0; i < efptNR; i++)
478         {
479             enerd->dvdl_nonlin[i] += dvdl[i];
480         }
481     }
482
483     /* Copy the sum of violations for the distance restraints from fcd */
484     if (fcd)
485     {
486         enerd->term[F_DISRESVIOL] = fcd->disres.sumviol;
487
488     }
489 }
490
491 void calc_listed_lambda(const t_idef *idef,
492                         const rvec x[],
493                         t_forcerec *fr,
494                         const struct t_pbc *pbc, const struct t_graph *g,
495                         gmx_grppairener_t *grpp, real *epot, t_nrnb *nrnb,
496                         real *lambda,
497                         const t_mdatoms *md,
498                         t_fcdata *fcd,
499                         int *global_atom_index)
500 {
501     int           ftype, nr_nonperturbed, nr;
502     real          v;
503     real          dvdl_dum[efptNR];
504     rvec         *f, *fshift;
505     const  t_pbc *pbc_null;
506     t_idef        idef_fe;
507
508     if (fr->bMolPBC)
509     {
510         pbc_null = pbc;
511     }
512     else
513     {
514         pbc_null = NULL;
515     }
516
517     /* Copy the whole idef, so we can modify the contents locally */
518     idef_fe          = *idef;
519     idef_fe.nthreads = 1;
520     snew(idef_fe.il_thread_division, F_NRE*(idef_fe.nthreads+1));
521
522     /* We already have the forces, so we use temp buffers here */
523     snew(f, fr->natoms_force);
524     snew(fshift, SHIFTS);
525
526     /* Loop over all bonded force types to calculate the bonded energies */
527     for (ftype = 0; (ftype < F_NRE); ftype++)
528     {
529         if (ftype_is_bonded_potential(ftype))
530         {
531             /* Set the work range of thread 0 to the perturbed bondeds only */
532             nr_nonperturbed                       = idef->il[ftype].nr_nonperturbed;
533             nr                                    = idef->il[ftype].nr;
534             idef_fe.il_thread_division[ftype*2+0] = nr_nonperturbed;
535             idef_fe.il_thread_division[ftype*2+1] = nr;
536
537             /* This is only to get the flop count correct */
538             idef_fe.il[ftype].nr = nr - nr_nonperturbed;
539
540             if (nr - nr_nonperturbed > 0)
541             {
542                 v = calc_one_bond(0, ftype, &idef_fe,
543                                   x, f, fshift, fr, pbc_null, g,
544                                   grpp, nrnb, lambda, dvdl_dum,
545                                   md, fcd, TRUE,
546                                   global_atom_index);
547                 epot[ftype] += v;
548             }
549         }
550     }
551
552     sfree(fshift);
553     sfree(f);
554
555     sfree(idef_fe.il_thread_division);
556 }
557
558 void
559 do_force_listed(gmx_wallcycle        *wcycle,
560                 matrix                box,
561                 const t_lambda       *fepvals,
562                 const gmx_multisim_t *ms,
563                 const t_idef         *idef,
564                 const rvec            x[],
565                 history_t            *hist,
566                 rvec                  f[],
567                 t_forcerec           *fr,
568                 const struct t_pbc   *pbc,
569                 const struct t_graph *graph,
570                 gmx_enerdata_t       *enerd,
571                 t_nrnb               *nrnb,
572                 real                 *lambda,
573                 const t_mdatoms      *md,
574                 t_fcdata             *fcd,
575                 int                  *global_atom_index,
576                 int                   flags)
577 {
578     t_pbc pbc_full; /* Full PBC is needed for position restraints */
579
580     if (!(flags & GMX_FORCE_LISTED))
581     {
582         return;
583     }
584
585     wallcycle_sub_start(wcycle, ewcsLISTED);
586
587     if ((idef->il[F_POSRES].nr > 0) ||
588         (idef->il[F_FBPOSRES].nr > 0))
589     {
590         set_pbc(&pbc_full, fr->ePBC, box);
591     }
592     calc_listed(ms, idef, x, hist, f, fr, pbc, &pbc_full,
593                 graph, enerd, nrnb, lambda, md, fcd,
594                 global_atom_index, flags);
595
596     /* Check if we have to determine energy differences
597      * at foreign lambda's.
598      */
599     if (fepvals->n_lambda > 0 && (flags & GMX_FORCE_DHDL))
600     {
601         posres_wrapper_lambda(fepvals, idef, &pbc_full, x, enerd, lambda, fr);
602
603         if (idef->ilsort != ilsortNO_FE)
604         {
605             if (idef->ilsort != ilsortFE_SORTED)
606             {
607                 gmx_incons("The bonded interactions are not sorted for free energy");
608             }
609             for (int i = 0; i < enerd->n_lambda; i++)
610             {
611                 real lam_i[efptNR];
612
613                 reset_foreign_enerdata(enerd);
614                 for (int j = 0; j < efptNR; j++)
615                 {
616                     lam_i[j] = (i == 0 ? lambda[j] : fepvals->all_lambda[j][i-1]);
617                 }
618                 calc_listed_lambda(idef, x, fr, pbc, graph, &(enerd->foreign_grpp), enerd->foreign_term, nrnb, lam_i, md,
619                                    fcd, global_atom_index);
620                 sum_epot(&(enerd->foreign_grpp), enerd->foreign_term);
621                 enerd->enerpart_lambda[i] += enerd->foreign_term[F_EPOT];
622             }
623         }
624     }
625     debug_gmx();
626
627     wallcycle_sub_stop(wcycle, ewcsLISTED);
628 }