d5b4e0770922a69300c79a430fbe62659be78b6d
[alexxy/gromacs.git] / src / gromacs / mdlib / vsite.cpp
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-2004, The GROMACS development team.
6  * Copyright (c) 2013,2014,2015,2016,2017,2018, 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 "vsite.h"
40
41 #include <cstdio>
42
43 #include <algorithm>
44 #include <vector>
45
46 #include "gromacs/compat/make_unique.h"
47 #include "gromacs/domdec/domdec.h"
48 #include "gromacs/domdec/domdec_struct.h"
49 #include "gromacs/gmxlib/network.h"
50 #include "gromacs/gmxlib/nrnb.h"
51 #include "gromacs/math/functions.h"
52 #include "gromacs/math/vec.h"
53 #include "gromacs/mdlib/gmx_omp_nthreads.h"
54 #include "gromacs/mdtypes/commrec.h"
55 #include "gromacs/mdtypes/mdatom.h"
56 #include "gromacs/pbcutil/ishift.h"
57 #include "gromacs/pbcutil/mshift.h"
58 #include "gromacs/pbcutil/pbc.h"
59 #include "gromacs/timing/wallcycle.h"
60 #include "gromacs/topology/ifunc.h"
61 #include "gromacs/topology/mtop_util.h"
62 #include "gromacs/topology/topology.h"
63 #include "gromacs/utility/exceptions.h"
64 #include "gromacs/utility/fatalerror.h"
65 #include "gromacs/utility/gmxassert.h"
66 #include "gromacs/utility/gmxomp.h"
67
68 /* The strategy used here for assigning virtual sites to (thread-)tasks
69  * is as follows:
70  *
71  * We divide the atom range that vsites operate on (natoms_local with DD,
72  * 0 - last atom involved in vsites without DD) equally over all threads.
73  *
74  * Vsites in the local range constructed from atoms in the local range
75  * and/or other vsites that are fully local are assigned to a simple,
76  * independent task.
77  *
78  * Vsites that are not assigned after using the above criterion get assigned
79  * to a so called "interdependent" thread task when none of the constructing
80  * atoms is a vsite. These tasks are called interdependent, because one task
81  * accesses atoms assigned to a different task/thread.
82  * Note that this option is turned off with large (local) atom counts
83  * to avoid high memory usage.
84  *
85  * Any remaining vsites are assigned to a separate master thread task.
86  */
87
88 using gmx::RVec;
89
90 static void init_ilist(t_ilist *ilist)
91 {
92     for (int i = 0; i < F_NRE; i++)
93     {
94         ilist[i].nr     = 0;
95         ilist[i].nalloc = 0;
96         ilist[i].iatoms = nullptr;
97     }
98 }
99
100 /*! \brief List of atom indices belonging to a task */
101 struct AtomIndex {
102     //! List of atom indices
103     std::vector<int> atom;
104 };
105
106 /*! \brief Data structure for thread tasks that use constructing atoms outside their own atom range */
107 struct InterdependentTask
108 {
109     //! The interaction lists, only vsite entries are used
110     t_ilist                ilist[F_NRE];
111     //! Thread/task-local force buffer
112     std::vector<RVec>      force;
113     //! The atom indices of the vsites of our task
114     std::vector<int>       vsite;
115     //! Flags if elements in force are spread to or not
116     std::vector<bool>      use;
117     //! The number of entries set to true in use
118     int                    nuse;
119     //! Array of atoms indices, size nthreads, covering all nuse set elements in use
120     std::vector<AtomIndex> atomIndex;
121     //! List of tasks (force blocks) this task spread forces to
122     std::vector<int>       spreadTask;
123     //! List of tasks that write to this tasks force block range
124     std::vector<int>       reduceTask;
125
126     InterdependentTask()
127     {
128         init_ilist(ilist);
129         nuse = 0;
130     }
131 };
132
133 /*! \brief Vsite thread task data structure */
134 struct VsiteThread
135 {
136     //! Start of atom range of this task
137     int                rangeStart;
138     //! End of atom range of this task
139     int                rangeEnd;
140     //! The interaction lists, only vsite entries are used
141     t_ilist            ilist[F_NRE];
142     //! Local fshift accumulation buffer
143     rvec               fshift[SHIFTS];
144     //! Local virial dx*df accumulation buffer
145     matrix             dxdf;
146     //! Tells if interdependent task idTask should be used (in addition to the rest of this task), this bool has the same value on all threads
147     bool               useInterdependentTask;
148     //! Data for vsites that involve constructing atoms in the atom range of other threads/tasks
149     InterdependentTask idTask;
150
151     /*! \brief Constructor */
152     VsiteThread()
153     {
154         rangeStart            = -1;
155         rangeEnd              = -1;
156         init_ilist(ilist);
157         clear_rvecs(SHIFTS, fshift);
158         clear_mat(dxdf);
159         useInterdependentTask = false;
160     }
161 };
162
163 /*! \brief Returns the sum of the vsite ilist sizes over all vsite types
164  *
165  * \param[in] ilist  The interaction list
166  */
167 template <typename T>
168 static int vsiteIlistNrCount(const T *ilist)
169 {
170     int nr = 0;
171     for (int ftype = c_ftypeVsiteStart; ftype < c_ftypeVsiteEnd; ftype++)
172     {
173         nr += ilist[ftype].size();
174     }
175
176     return nr;
177 }
178
179 static int pbc_rvec_sub(const t_pbc *pbc, const rvec xi, const rvec xj, rvec dx)
180 {
181     if (pbc)
182     {
183         return pbc_dx_aiuc(pbc, xi, xj, dx);
184     }
185     else
186     {
187         rvec_sub(xi, xj, dx);
188         return CENTRAL;
189     }
190 }
191
192 /* Vsite construction routines */
193
194 static void constr_vsite2(const rvec xi, const rvec xj, rvec x, real a, const t_pbc *pbc)
195 {
196     real b = 1 - a;
197     /* 1 flop */
198
199     if (pbc)
200     {
201         rvec dx;
202         pbc_dx_aiuc(pbc, xj, xi, dx);
203         x[XX] = xi[XX] + a*dx[XX];
204         x[YY] = xi[YY] + a*dx[YY];
205         x[ZZ] = xi[ZZ] + a*dx[ZZ];
206     }
207     else
208     {
209         x[XX] = b*xi[XX] + a*xj[XX];
210         x[YY] = b*xi[YY] + a*xj[YY];
211         x[ZZ] = b*xi[ZZ] + a*xj[ZZ];
212         /* 9 Flops */
213     }
214
215     /* TOTAL: 10 flops */
216 }
217
218 static void constr_vsite3(const rvec xi, const rvec xj, const rvec xk, rvec x, real a, real b,
219                           const t_pbc *pbc)
220 {
221     real c = 1 - a - b;
222     /* 2 flops */
223
224     if (pbc)
225     {
226         rvec dxj, dxk;
227
228         pbc_dx_aiuc(pbc, xj, xi, dxj);
229         pbc_dx_aiuc(pbc, xk, xi, dxk);
230         x[XX] = xi[XX] + a*dxj[XX] + b*dxk[XX];
231         x[YY] = xi[YY] + a*dxj[YY] + b*dxk[YY];
232         x[ZZ] = xi[ZZ] + a*dxj[ZZ] + b*dxk[ZZ];
233     }
234     else
235     {
236         x[XX] = c*xi[XX] + a*xj[XX] + b*xk[XX];
237         x[YY] = c*xi[YY] + a*xj[YY] + b*xk[YY];
238         x[ZZ] = c*xi[ZZ] + a*xj[ZZ] + b*xk[ZZ];
239         /* 15 Flops */
240     }
241
242     /* TOTAL: 17 flops */
243 }
244
245 static void constr_vsite3FD(const rvec xi, const rvec xj, const rvec xk, rvec x, real a, real b,
246                             const t_pbc *pbc)
247 {
248     rvec xij, xjk, temp;
249     real c;
250
251     pbc_rvec_sub(pbc, xj, xi, xij);
252     pbc_rvec_sub(pbc, xk, xj, xjk);
253     /* 6 flops */
254
255     /* temp goes from i to a point on the line jk */
256     temp[XX] = xij[XX] + a*xjk[XX];
257     temp[YY] = xij[YY] + a*xjk[YY];
258     temp[ZZ] = xij[ZZ] + a*xjk[ZZ];
259     /* 6 flops */
260
261     c = b*gmx::invsqrt(iprod(temp, temp));
262     /* 6 + 10 flops */
263
264     x[XX] = xi[XX] + c*temp[XX];
265     x[YY] = xi[YY] + c*temp[YY];
266     x[ZZ] = xi[ZZ] + c*temp[ZZ];
267     /* 6 Flops */
268
269     /* TOTAL: 34 flops */
270 }
271
272 static void constr_vsite3FAD(const rvec xi, const rvec xj, const rvec xk, rvec x, real a, real b, const t_pbc *pbc)
273 {
274     rvec xij, xjk, xp;
275     real a1, b1, c1, invdij;
276
277     pbc_rvec_sub(pbc, xj, xi, xij);
278     pbc_rvec_sub(pbc, xk, xj, xjk);
279     /* 6 flops */
280
281     invdij = gmx::invsqrt(iprod(xij, xij));
282     c1     = invdij * invdij * iprod(xij, xjk);
283     xp[XX] = xjk[XX] - c1*xij[XX];
284     xp[YY] = xjk[YY] - c1*xij[YY];
285     xp[ZZ] = xjk[ZZ] - c1*xij[ZZ];
286     a1     = a*invdij;
287     b1     = b*gmx::invsqrt(iprod(xp, xp));
288     /* 45 */
289
290     x[XX] = xi[XX] + a1*xij[XX] + b1*xp[XX];
291     x[YY] = xi[YY] + a1*xij[YY] + b1*xp[YY];
292     x[ZZ] = xi[ZZ] + a1*xij[ZZ] + b1*xp[ZZ];
293     /* 12 Flops */
294
295     /* TOTAL: 63 flops */
296 }
297
298 static void constr_vsite3OUT(const rvec xi, const rvec xj, const rvec xk, rvec x,
299                              real a, real b, real c, const t_pbc *pbc)
300 {
301     rvec xij, xik, temp;
302
303     pbc_rvec_sub(pbc, xj, xi, xij);
304     pbc_rvec_sub(pbc, xk, xi, xik);
305     cprod(xij, xik, temp);
306     /* 15 Flops */
307
308     x[XX] = xi[XX] + a*xij[XX] + b*xik[XX] + c*temp[XX];
309     x[YY] = xi[YY] + a*xij[YY] + b*xik[YY] + c*temp[YY];
310     x[ZZ] = xi[ZZ] + a*xij[ZZ] + b*xik[ZZ] + c*temp[ZZ];
311     /* 18 Flops */
312
313     /* TOTAL: 33 flops */
314 }
315
316 static void constr_vsite4FD(const rvec xi, const rvec xj, const rvec xk, const rvec xl, rvec x,
317                             real a, real b, real c, const t_pbc *pbc)
318 {
319     rvec xij, xjk, xjl, temp;
320     real d;
321
322     pbc_rvec_sub(pbc, xj, xi, xij);
323     pbc_rvec_sub(pbc, xk, xj, xjk);
324     pbc_rvec_sub(pbc, xl, xj, xjl);
325     /* 9 flops */
326
327     /* temp goes from i to a point on the plane jkl */
328     temp[XX] = xij[XX] + a*xjk[XX] + b*xjl[XX];
329     temp[YY] = xij[YY] + a*xjk[YY] + b*xjl[YY];
330     temp[ZZ] = xij[ZZ] + a*xjk[ZZ] + b*xjl[ZZ];
331     /* 12 flops */
332
333     d = c*gmx::invsqrt(iprod(temp, temp));
334     /* 6 + 10 flops */
335
336     x[XX] = xi[XX] + d*temp[XX];
337     x[YY] = xi[YY] + d*temp[YY];
338     x[ZZ] = xi[ZZ] + d*temp[ZZ];
339     /* 6 Flops */
340
341     /* TOTAL: 43 flops */
342 }
343
344 static void constr_vsite4FDN(const rvec xi, const rvec xj, const rvec xk, const rvec xl, rvec x,
345                              real a, real b, real c, const t_pbc *pbc)
346 {
347     rvec xij, xik, xil, ra, rb, rja, rjb, rm;
348     real d;
349
350     pbc_rvec_sub(pbc, xj, xi, xij);
351     pbc_rvec_sub(pbc, xk, xi, xik);
352     pbc_rvec_sub(pbc, xl, xi, xil);
353     /* 9 flops */
354
355     ra[XX] = a*xik[XX];
356     ra[YY] = a*xik[YY];
357     ra[ZZ] = a*xik[ZZ];
358
359     rb[XX] = b*xil[XX];
360     rb[YY] = b*xil[YY];
361     rb[ZZ] = b*xil[ZZ];
362
363     /* 6 flops */
364
365     rvec_sub(ra, xij, rja);
366     rvec_sub(rb, xij, rjb);
367     /* 6 flops */
368
369     cprod(rja, rjb, rm);
370     /* 9 flops */
371
372     d = c*gmx::invsqrt(norm2(rm));
373     /* 5+5+1 flops */
374
375     x[XX] = xi[XX] + d*rm[XX];
376     x[YY] = xi[YY] + d*rm[YY];
377     x[ZZ] = xi[ZZ] + d*rm[ZZ];
378     /* 6 Flops */
379
380     /* TOTAL: 47 flops */
381 }
382
383
384 static int constr_vsiten(const t_iatom *ia, const t_iparams ip[],
385                          rvec *x, const t_pbc *pbc)
386 {
387     rvec x1, dx;
388     dvec dsum;
389     int  n3, av, ai;
390     real a;
391
392     n3 = 3*ip[ia[0]].vsiten.n;
393     av = ia[1];
394     ai = ia[2];
395     copy_rvec(x[ai], x1);
396     clear_dvec(dsum);
397     for (int i = 3; i < n3; i += 3)
398     {
399         ai = ia[i+2];
400         a  = ip[ia[i]].vsiten.a;
401         if (pbc)
402         {
403             pbc_dx_aiuc(pbc, x[ai], x1, dx);
404         }
405         else
406         {
407             rvec_sub(x[ai], x1, dx);
408         }
409         dsum[XX] += a*dx[XX];
410         dsum[YY] += a*dx[YY];
411         dsum[ZZ] += a*dx[ZZ];
412         /* 9 Flops */
413     }
414
415     x[av][XX] = x1[XX] + dsum[XX];
416     x[av][YY] = x1[YY] + dsum[YY];
417     x[av][ZZ] = x1[ZZ] + dsum[ZZ];
418
419     return n3;
420 }
421
422 /*! \brief PBC modes for vsite construction and spreading */
423 enum class PbcMode
424 {
425     all,         // Apply normal, simple PBC for all vsites
426     chargeGroup, // Keep vsite in the same periodic image as the rest of it's charge group
427     none         // No PBC treatment needed
428 };
429
430 /*! \brief Returns the PBC mode based on the system PBC and vsite properties
431  *
432  * \param[in] pbcPtr  A pointer to a PBC struct or nullptr when no PBC treatment is required
433  * \param[in] vsite   A pointer to the vsite struct, can be nullptr
434  */
435 static PbcMode getPbcMode(const t_pbc       *pbcPtr,
436                           const gmx_vsite_t *vsite)
437 {
438     if (pbcPtr == nullptr)
439     {
440         return PbcMode::none;
441     }
442     else if (vsite != nullptr && vsite->bHaveChargeGroups)
443     {
444         return PbcMode::chargeGroup;
445     }
446     else
447     {
448         return PbcMode::all;
449     }
450 }
451
452 static void construct_vsites_thread(const gmx_vsite_t *vsite,
453                                     rvec x[],
454                                     real dt, rvec *v,
455                                     const t_iparams ip[], const t_ilist ilist[],
456                                     const t_pbc *pbc_null)
457 {
458     real         inv_dt;
459     if (v != nullptr)
460     {
461         inv_dt = 1.0/dt;
462     }
463     else
464     {
465         inv_dt = 1.0;
466     }
467
468     const PbcMode            pbcMode   = getPbcMode(pbc_null, vsite);
469     /* We need another pbc pointer, as with charge groups we switch per vsite */
470     const t_pbc             *pbc_null2 = pbc_null;
471     gmx::ArrayRef<const int> vsite_pbc;
472
473     for (int ftype = c_ftypeVsiteStart; ftype < c_ftypeVsiteEnd; ftype++)
474     {
475         if (ilist[ftype].nr == 0)
476         {
477             continue;
478         }
479
480         {   // TODO remove me
481             int            nra = interaction_function[ftype].nratoms;
482             int            inc = 1 + nra;
483             int            nr  = ilist[ftype].nr;
484
485             const t_iatom *ia = ilist[ftype].iatoms;
486
487             if (pbcMode == PbcMode::chargeGroup)
488             {
489                 vsite_pbc = (*vsite->vsite_pbc_loc)[ftype - c_ftypeVsiteStart];
490             }
491
492             for (int i = 0; i < nr; )
493             {
494                 int  tp     = ia[0];
495                 /* The vsite and constructing atoms */
496                 int  avsite = ia[1];
497                 int  ai     = ia[2];
498                 /* Constants for constructing vsites */
499                 real a1     = ip[tp].vsite.a;
500                 /* Check what kind of pbc we need to use */
501                 int  pbc_atom;
502                 rvec xpbc;
503                 if (pbcMode == PbcMode::all)
504                 {
505                     /* No charge groups, vsite follows its own pbc */
506                     pbc_atom = avsite;
507                     copy_rvec(x[avsite], xpbc);
508                 }
509                 else if (pbcMode == PbcMode::chargeGroup)
510                 {
511                     pbc_atom = vsite_pbc[i/(1 + nra)];
512                     if (pbc_atom > -2)
513                     {
514                         if (pbc_atom >= 0)
515                         {
516                             /* We need to copy the coordinates here,
517                              * single for single atom cg's pbc_atom
518                              * is the vsite itself.
519                              */
520                             copy_rvec(x[pbc_atom], xpbc);
521                         }
522                         pbc_null2 = pbc_null;
523                     }
524                     else
525                     {
526                         pbc_null2 = nullptr;
527                     }
528                 }
529                 else
530                 {
531                     pbc_atom = -2;
532                 }
533                 /* Copy the old position */
534                 rvec xv;
535                 copy_rvec(x[avsite], xv);
536
537                 /* Construct the vsite depending on type */
538                 int  aj, ak, al;
539                 real b1, c1;
540                 switch (ftype)
541                 {
542                     case F_VSITE2:
543                         aj = ia[3];
544                         constr_vsite2(x[ai], x[aj], x[avsite], a1, pbc_null2);
545                         break;
546                     case F_VSITE3:
547                         aj = ia[3];
548                         ak = ia[4];
549                         b1 = ip[tp].vsite.b;
550                         constr_vsite3(x[ai], x[aj], x[ak], x[avsite], a1, b1, pbc_null2);
551                         break;
552                     case F_VSITE3FD:
553                         aj = ia[3];
554                         ak = ia[4];
555                         b1 = ip[tp].vsite.b;
556                         constr_vsite3FD(x[ai], x[aj], x[ak], x[avsite], a1, b1, pbc_null2);
557                         break;
558                     case F_VSITE3FAD:
559                         aj = ia[3];
560                         ak = ia[4];
561                         b1 = ip[tp].vsite.b;
562                         constr_vsite3FAD(x[ai], x[aj], x[ak], x[avsite], a1, b1, pbc_null2);
563                         break;
564                     case F_VSITE3OUT:
565                         aj = ia[3];
566                         ak = ia[4];
567                         b1 = ip[tp].vsite.b;
568                         c1 = ip[tp].vsite.c;
569                         constr_vsite3OUT(x[ai], x[aj], x[ak], x[avsite], a1, b1, c1, pbc_null2);
570                         break;
571                     case F_VSITE4FD:
572                         aj = ia[3];
573                         ak = ia[4];
574                         al = ia[5];
575                         b1 = ip[tp].vsite.b;
576                         c1 = ip[tp].vsite.c;
577                         constr_vsite4FD(x[ai], x[aj], x[ak], x[al], x[avsite], a1, b1, c1,
578                                         pbc_null2);
579                         break;
580                     case F_VSITE4FDN:
581                         aj = ia[3];
582                         ak = ia[4];
583                         al = ia[5];
584                         b1 = ip[tp].vsite.b;
585                         c1 = ip[tp].vsite.c;
586                         constr_vsite4FDN(x[ai], x[aj], x[ak], x[al], x[avsite], a1, b1, c1,
587                                          pbc_null2);
588                         break;
589                     case F_VSITEN:
590                         inc = constr_vsiten(ia, ip, x, pbc_null2);
591                         break;
592                     default:
593                         gmx_fatal(FARGS, "No such vsite type %d in %s, line %d",
594                                   ftype, __FILE__, __LINE__);
595                 }
596
597                 if (pbc_atom >= 0)
598                 {
599                     /* Match the pbc of this vsite to the rest of its charge group */
600                     rvec dx;
601                     int  ishift = pbc_dx_aiuc(pbc_null, x[avsite], xpbc, dx);
602                     if (ishift != CENTRAL)
603                     {
604                         rvec_add(xpbc, dx, x[avsite]);
605                     }
606                 }
607                 if (v != nullptr)
608                 {
609                     /* Calculate velocity of vsite... */
610                     rvec vv;
611                     rvec_sub(x[avsite], xv, vv);
612                     svmul(inv_dt, vv, v[avsite]);
613                 }
614
615                 /* Increment loop variables */
616                 i  += inc;
617                 ia += inc;
618             }
619         }
620     }
621 }
622
623 void construct_vsites(const gmx_vsite_t *vsite,
624                       rvec x[],
625                       real dt, rvec *v,
626                       const t_iparams ip[], const t_ilist ilist[],
627                       int ePBC, gmx_bool bMolPBC,
628                       const t_commrec *cr,
629                       const matrix box)
630 {
631     const bool useDomdec = (vsite != nullptr && vsite->useDomdec);
632     GMX_ASSERT(!useDomdec || (cr != nullptr && DOMAINDECOMP(cr)), "When vsites are set up with domain decomposition, we need a valid commrec");
633     // TODO: Remove this assertion when we remove charge groups
634     GMX_ASSERT(vsite != nullptr || ePBC == epbcNONE, "Without a vsite struct we can not do PBC (in case we have charge groups)");
635
636     t_pbc     pbc, *pbc_null;
637
638     /* We only need to do pbc when we have inter-cg vsites.
639      * Note that with domain decomposition we do not need to apply PBC here
640      * when we have at least 3 domains along each dimension. Currently we
641      * do not optimize this case.
642      */
643     if (ePBC != epbcNONE && (useDomdec || bMolPBC) &&
644         !(vsite != nullptr && vsite->n_intercg_vsite == 0))
645     {
646         /* This is wasting some CPU time as we now do this multiple times
647          * per MD step.
648          */
649         ivec null_ivec;
650         clear_ivec(null_ivec);
651         pbc_null = set_pbc_dd(&pbc, ePBC,
652                               useDomdec ? cr->dd->nc : null_ivec,
653                               FALSE, box);
654     }
655     else
656     {
657         pbc_null = nullptr;
658     }
659
660     if (useDomdec)
661     {
662         dd_move_x_vsites(cr->dd, box, x);
663     }
664
665     if (vsite == nullptr || vsite->nthreads == 1)
666     {
667         construct_vsites_thread(vsite,
668                                 x, dt, v,
669                                 ip, ilist,
670                                 pbc_null);
671     }
672     else
673     {
674 #pragma omp parallel num_threads(vsite->nthreads)
675         {
676             try
677             {
678                 const int          th    = gmx_omp_get_thread_num();
679                 const VsiteThread &tData = *vsite->tData[th];
680                 GMX_ASSERT(tData.rangeStart >= 0, "The thread data should be initialized before calling construct_vsites");
681
682                 construct_vsites_thread(vsite,
683                                         x, dt, v,
684                                         ip, tData.ilist,
685                                         pbc_null);
686                 if (tData.useInterdependentTask)
687                 {
688                     /* Here we don't need a barrier (unlike the spreading),
689                      * since both tasks only construct vsites from particles,
690                      * or local vsites, not from non-local vsites.
691                      */
692                     construct_vsites_thread(vsite,
693                                             x, dt, v,
694                                             ip, tData.idTask.ilist,
695                                             pbc_null);
696                 }
697             }
698             GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
699         }
700         /* Now we can construct the vsites that might depend on other vsites */
701         construct_vsites_thread(vsite,
702                                 x, dt, v,
703                                 ip, vsite->tData[vsite->nthreads]->ilist,
704                                 pbc_null);
705     }
706 }
707
708 static void spread_vsite2(const t_iatom ia[], real a,
709                           const rvec x[],
710                           rvec f[], rvec fshift[],
711                           const t_pbc *pbc, const t_graph *g)
712 {
713     rvec    fi, fj, dx;
714     t_iatom av, ai, aj;
715     ivec    di;
716     int     siv, sij;
717
718     av = ia[1];
719     ai = ia[2];
720     aj = ia[3];
721
722     svmul(1 - a, f[av], fi);
723     svmul(    a, f[av], fj);
724     /* 7 flop */
725
726     rvec_inc(f[ai], fi);
727     rvec_inc(f[aj], fj);
728     /* 6 Flops */
729
730     if (g)
731     {
732         ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, av), di);
733         siv = IVEC2IS(di);
734         ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, aj), di);
735         sij = IVEC2IS(di);
736     }
737     else if (pbc)
738     {
739         siv = pbc_dx_aiuc(pbc, x[ai], x[av], dx);
740         sij = pbc_dx_aiuc(pbc, x[ai], x[aj], dx);
741     }
742     else
743     {
744         siv = CENTRAL;
745         sij = CENTRAL;
746     }
747
748     if (fshift && (siv != CENTRAL || sij != CENTRAL))
749     {
750         rvec_inc(fshift[siv], f[av]);
751         rvec_dec(fshift[CENTRAL], fi);
752         rvec_dec(fshift[sij], fj);
753     }
754
755     /* TOTAL: 13 flops */
756 }
757
758 void constructVsitesGlobal(const gmx_mtop_t         &mtop,
759                            gmx::ArrayRef<gmx::RVec>  x)
760 {
761     GMX_ASSERT(x.size() >= static_cast<gmx::index>(mtop.natoms), "x should contain the whole system");
762     GMX_ASSERT(!mtop.moleculeBlockIndices.empty(), "molblock indices are needed in constructVsitesGlobal");
763
764     for (size_t mb = 0; mb < mtop.molblock.size(); mb++)
765     {
766         const gmx_molblock_t  &molb = mtop.molblock[mb];
767         const gmx_moltype_t   &molt = mtop.moltype[molb.type];
768         if (vsiteIlistNrCount(molt.ilist.data()) > 0)
769         {
770             int atomOffset = mtop.moleculeBlockIndices[mb].globalAtomStart;
771             for (int mol = 0; mol < molb.nmol; mol++)
772             {
773                 t_ilist ilist[F_NRE];
774                 for (int ftype = c_ftypeVsiteStart; ftype < c_ftypeVsiteEnd; ftype++)
775                 {
776                     ilist[ftype].nr     = molt.ilist[ftype].size();
777                     ilist[ftype].iatoms = const_cast<t_iatom *>(molt.ilist[ftype].iatoms.data());
778                 }
779
780                 construct_vsites(nullptr, as_rvec_array(x.data()) + atomOffset,
781                                  0.0, nullptr,
782                                  mtop.ffparams.iparams.data(), ilist,
783                                  epbcNONE, TRUE, nullptr, nullptr);
784                 atomOffset += molt.atoms.nr;
785             }
786         }
787     }
788 }
789
790 static void spread_vsite3(const t_iatom ia[], real a, real b,
791                           const rvec x[],
792                           rvec f[], rvec fshift[],
793                           const t_pbc *pbc, const t_graph *g)
794 {
795     rvec    fi, fj, fk, dx;
796     int     av, ai, aj, ak;
797     ivec    di;
798     int     siv, sij, sik;
799
800     av = ia[1];
801     ai = ia[2];
802     aj = ia[3];
803     ak = ia[4];
804
805     svmul(1 - a - b, f[av], fi);
806     svmul(        a, f[av], fj);
807     svmul(        b, f[av], fk);
808     /* 11 flops */
809
810     rvec_inc(f[ai], fi);
811     rvec_inc(f[aj], fj);
812     rvec_inc(f[ak], fk);
813     /* 9 Flops */
814
815     if (g)
816     {
817         ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, ia[1]), di);
818         siv = IVEC2IS(di);
819         ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, aj), di);
820         sij = IVEC2IS(di);
821         ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, ak), di);
822         sik = IVEC2IS(di);
823     }
824     else if (pbc)
825     {
826         siv = pbc_dx_aiuc(pbc, x[ai], x[av], dx);
827         sij = pbc_dx_aiuc(pbc, x[ai], x[aj], dx);
828         sik = pbc_dx_aiuc(pbc, x[ai], x[ak], dx);
829     }
830     else
831     {
832         siv = CENTRAL;
833         sij = CENTRAL;
834         sik = CENTRAL;
835     }
836
837     if (fshift && (siv != CENTRAL || sij != CENTRAL || sik != CENTRAL))
838     {
839         rvec_inc(fshift[siv], f[av]);
840         rvec_dec(fshift[CENTRAL], fi);
841         rvec_dec(fshift[sij], fj);
842         rvec_dec(fshift[sik], fk);
843     }
844
845     /* TOTAL: 20 flops */
846 }
847
848 static void spread_vsite3FD(const t_iatom ia[], real a, real b,
849                             const rvec x[],
850                             rvec f[], rvec fshift[],
851                             gmx_bool VirCorr, matrix dxdf,
852                             const t_pbc *pbc, const t_graph *g)
853 {
854     real    c, invl, fproj, a1;
855     rvec    xvi, xij, xjk, xix, fv, temp;
856     t_iatom av, ai, aj, ak;
857     int     svi, sji, skj;
858     ivec    di;
859
860     av = ia[1];
861     ai = ia[2];
862     aj = ia[3];
863     ak = ia[4];
864     copy_rvec(f[av], fv);
865
866     sji = pbc_rvec_sub(pbc, x[aj], x[ai], xij);
867     skj = pbc_rvec_sub(pbc, x[ak], x[aj], xjk);
868     /* 6 flops */
869
870     /* xix goes from i to point x on the line jk */
871     xix[XX] = xij[XX]+a*xjk[XX];
872     xix[YY] = xij[YY]+a*xjk[YY];
873     xix[ZZ] = xij[ZZ]+a*xjk[ZZ];
874     /* 6 flops */
875
876     invl = gmx::invsqrt(iprod(xix, xix));
877     c    = b*invl;
878     /* 4 + ?10? flops */
879
880     fproj = iprod(xix, fv)*invl*invl; /* = (xix . f)/(xix . xix) */
881
882     temp[XX] = c*(fv[XX]-fproj*xix[XX]);
883     temp[YY] = c*(fv[YY]-fproj*xix[YY]);
884     temp[ZZ] = c*(fv[ZZ]-fproj*xix[ZZ]);
885     /* 16 */
886
887     /* c is already calculated in constr_vsite3FD
888        storing c somewhere will save 26 flops!     */
889
890     a1         = 1 - a;
891     f[ai][XX] += fv[XX] - temp[XX];
892     f[ai][YY] += fv[YY] - temp[YY];
893     f[ai][ZZ] += fv[ZZ] - temp[ZZ];
894     f[aj][XX] += a1*temp[XX];
895     f[aj][YY] += a1*temp[YY];
896     f[aj][ZZ] += a1*temp[ZZ];
897     f[ak][XX] += a*temp[XX];
898     f[ak][YY] += a*temp[YY];
899     f[ak][ZZ] += a*temp[ZZ];
900     /* 19 Flops */
901
902     if (g)
903     {
904         ivec_sub(SHIFT_IVEC(g, ia[1]), SHIFT_IVEC(g, ai), di);
905         svi = IVEC2IS(di);
906         ivec_sub(SHIFT_IVEC(g, aj), SHIFT_IVEC(g, ai), di);
907         sji = IVEC2IS(di);
908         ivec_sub(SHIFT_IVEC(g, ak), SHIFT_IVEC(g, aj), di);
909         skj = IVEC2IS(di);
910     }
911     else if (pbc)
912     {
913         svi = pbc_rvec_sub(pbc, x[av], x[ai], xvi);
914     }
915     else
916     {
917         svi = CENTRAL;
918     }
919
920     if (fshift && (svi != CENTRAL || sji != CENTRAL || skj != CENTRAL))
921     {
922         rvec_dec(fshift[svi], fv);
923         fshift[CENTRAL][XX] += fv[XX] - (1 + a)*temp[XX];
924         fshift[CENTRAL][YY] += fv[YY] - (1 + a)*temp[YY];
925         fshift[CENTRAL][ZZ] += fv[ZZ] - (1 + a)*temp[ZZ];
926         fshift[    sji][XX] += temp[XX];
927         fshift[    sji][YY] += temp[YY];
928         fshift[    sji][ZZ] += temp[ZZ];
929         fshift[    skj][XX] += a*temp[XX];
930         fshift[    skj][YY] += a*temp[YY];
931         fshift[    skj][ZZ] += a*temp[ZZ];
932     }
933
934     if (VirCorr)
935     {
936         /* When VirCorr=TRUE, the virial for the current forces is not
937          * calculated from the redistributed forces. This means that
938          * the effect of non-linear virtual site constructions on the virial
939          * needs to be added separately. This contribution can be calculated
940          * in many ways, but the simplest and cheapest way is to use
941          * the first constructing atom ai as a reference position in space:
942          * subtract (xv-xi)*fv and add (xj-xi)*fj + (xk-xi)*fk.
943          */
944         rvec xiv;
945
946         pbc_rvec_sub(pbc, x[av], x[ai], xiv);
947
948         for (int i = 0; i < DIM; i++)
949         {
950             for (int j = 0; j < DIM; j++)
951             {
952                 /* As xix is a linear combination of j and k, use that here */
953                 dxdf[i][j] += -xiv[i]*fv[j] + xix[i]*temp[j];
954             }
955         }
956     }
957
958     /* TOTAL: 61 flops */
959 }
960
961 static void spread_vsite3FAD(const t_iatom ia[], real a, real b,
962                              const rvec x[],
963                              rvec f[], rvec fshift[],
964                              gmx_bool VirCorr, matrix dxdf,
965                              const t_pbc *pbc, const t_graph *g)
966 {
967     rvec    xvi, xij, xjk, xperp, Fpij, Fppp, fv, f1, f2, f3;
968     real    a1, b1, c1, c2, invdij, invdij2, invdp, fproj;
969     t_iatom av, ai, aj, ak;
970     int     svi, sji, skj, d;
971     ivec    di;
972
973     av = ia[1];
974     ai = ia[2];
975     aj = ia[3];
976     ak = ia[4];
977     copy_rvec(f[ia[1]], fv);
978
979     sji = pbc_rvec_sub(pbc, x[aj], x[ai], xij);
980     skj = pbc_rvec_sub(pbc, x[ak], x[aj], xjk);
981     /* 6 flops */
982
983     invdij    = gmx::invsqrt(iprod(xij, xij));
984     invdij2   = invdij * invdij;
985     c1        = iprod(xij, xjk) * invdij2;
986     xperp[XX] = xjk[XX] - c1*xij[XX];
987     xperp[YY] = xjk[YY] - c1*xij[YY];
988     xperp[ZZ] = xjk[ZZ] - c1*xij[ZZ];
989     /* xperp in plane ijk, perp. to ij */
990     invdp = gmx::invsqrt(iprod(xperp, xperp));
991     a1    = a*invdij;
992     b1    = b*invdp;
993     /* 45 flops */
994
995     /* a1, b1 and c1 are already calculated in constr_vsite3FAD
996        storing them somewhere will save 45 flops!     */
997
998     fproj = iprod(xij, fv)*invdij2;
999     svmul(fproj,                      xij,  Fpij);    /* proj. f on xij */
1000     svmul(iprod(xperp, fv)*invdp*invdp, xperp, Fppp); /* proj. f on xperp */
1001     svmul(b1*fproj,                   xperp, f3);
1002     /* 23 flops */
1003
1004     rvec_sub(fv, Fpij, f1); /* f1 = f - Fpij */
1005     rvec_sub(f1, Fppp, f2); /* f2 = f - Fpij - Fppp */
1006     for (d = 0; (d < DIM); d++)
1007     {
1008         f1[d] *= a1;
1009         f2[d] *= b1;
1010     }
1011     /* 12 flops */
1012
1013     c2         = 1 + c1;
1014     f[ai][XX] += fv[XX] - f1[XX] + c1*f2[XX] + f3[XX];
1015     f[ai][YY] += fv[YY] - f1[YY] + c1*f2[YY] + f3[YY];
1016     f[ai][ZZ] += fv[ZZ] - f1[ZZ] + c1*f2[ZZ] + f3[ZZ];
1017     f[aj][XX] +=          f1[XX] - c2*f2[XX] - f3[XX];
1018     f[aj][YY] +=          f1[YY] - c2*f2[YY] - f3[YY];
1019     f[aj][ZZ] +=          f1[ZZ] - c2*f2[ZZ] - f3[ZZ];
1020     f[ak][XX] +=                      f2[XX];
1021     f[ak][YY] +=                      f2[YY];
1022     f[ak][ZZ] +=                      f2[ZZ];
1023     /* 30 Flops */
1024
1025     if (g)
1026     {
1027         ivec_sub(SHIFT_IVEC(g, ia[1]), SHIFT_IVEC(g, ai), di);
1028         svi = IVEC2IS(di);
1029         ivec_sub(SHIFT_IVEC(g, aj), SHIFT_IVEC(g, ai), di);
1030         sji = IVEC2IS(di);
1031         ivec_sub(SHIFT_IVEC(g, ak), SHIFT_IVEC(g, aj), di);
1032         skj = IVEC2IS(di);
1033     }
1034     else if (pbc)
1035     {
1036         svi = pbc_rvec_sub(pbc, x[av], x[ai], xvi);
1037     }
1038     else
1039     {
1040         svi = CENTRAL;
1041     }
1042
1043     if (fshift && (svi != CENTRAL || sji != CENTRAL || skj != CENTRAL))
1044     {
1045         rvec_dec(fshift[svi], fv);
1046         fshift[CENTRAL][XX] += fv[XX] - f1[XX] - (1-c1)*f2[XX] + f3[XX];
1047         fshift[CENTRAL][YY] += fv[YY] - f1[YY] - (1-c1)*f2[YY] + f3[YY];
1048         fshift[CENTRAL][ZZ] += fv[ZZ] - f1[ZZ] - (1-c1)*f2[ZZ] + f3[ZZ];
1049         fshift[    sji][XX] +=          f1[XX] -    c1 *f2[XX] - f3[XX];
1050         fshift[    sji][YY] +=          f1[YY] -    c1 *f2[YY] - f3[YY];
1051         fshift[    sji][ZZ] +=          f1[ZZ] -    c1 *f2[ZZ] - f3[ZZ];
1052         fshift[    skj][XX] +=                          f2[XX];
1053         fshift[    skj][YY] +=                          f2[YY];
1054         fshift[    skj][ZZ] +=                          f2[ZZ];
1055     }
1056
1057     if (VirCorr)
1058     {
1059         rvec xiv;
1060         int  i, j;
1061
1062         pbc_rvec_sub(pbc, x[av], x[ai], xiv);
1063
1064         for (i = 0; i < DIM; i++)
1065         {
1066             for (j = 0; j < DIM; j++)
1067             {
1068                 /* Note that xik=xij+xjk, so we have to add xij*f2 */
1069                 dxdf[i][j] +=
1070                     -xiv[i]*fv[j]
1071                     + xij[i]*(f1[j] + (1 - c2)*f2[j] - f3[j])
1072                     + xjk[i]*f2[j];
1073             }
1074         }
1075     }
1076
1077     /* TOTAL: 113 flops */
1078 }
1079
1080 static void spread_vsite3OUT(const t_iatom ia[], real a, real b, real c,
1081                              const rvec x[],
1082                              rvec f[], rvec fshift[],
1083                              gmx_bool VirCorr, matrix dxdf,
1084                              const t_pbc *pbc, const t_graph *g)
1085 {
1086     rvec    xvi, xij, xik, fv, fj, fk;
1087     real    cfx, cfy, cfz;
1088     int     av, ai, aj, ak;
1089     ivec    di;
1090     int     svi, sji, ski;
1091
1092     av = ia[1];
1093     ai = ia[2];
1094     aj = ia[3];
1095     ak = ia[4];
1096
1097     sji = pbc_rvec_sub(pbc, x[aj], x[ai], xij);
1098     ski = pbc_rvec_sub(pbc, x[ak], x[ai], xik);
1099     /* 6 Flops */
1100
1101     copy_rvec(f[av], fv);
1102
1103     cfx = c*fv[XX];
1104     cfy = c*fv[YY];
1105     cfz = c*fv[ZZ];
1106     /* 3 Flops */
1107
1108     fj[XX] = a*fv[XX]     -  xik[ZZ]*cfy +  xik[YY]*cfz;
1109     fj[YY] =  xik[ZZ]*cfx + a*fv[YY]     -  xik[XX]*cfz;
1110     fj[ZZ] = -xik[YY]*cfx +  xik[XX]*cfy + a*fv[ZZ];
1111
1112     fk[XX] = b*fv[XX]     +  xij[ZZ]*cfy -  xij[YY]*cfz;
1113     fk[YY] = -xij[ZZ]*cfx + b*fv[YY]     +  xij[XX]*cfz;
1114     fk[ZZ] =  xij[YY]*cfx -  xij[XX]*cfy + b*fv[ZZ];
1115     /* 30 Flops */
1116
1117     f[ai][XX] += fv[XX] - fj[XX] - fk[XX];
1118     f[ai][YY] += fv[YY] - fj[YY] - fk[YY];
1119     f[ai][ZZ] += fv[ZZ] - fj[ZZ] - fk[ZZ];
1120     rvec_inc(f[aj], fj);
1121     rvec_inc(f[ak], fk);
1122     /* 15 Flops */
1123
1124     if (g)
1125     {
1126         ivec_sub(SHIFT_IVEC(g, ia[1]), SHIFT_IVEC(g, ai), di);
1127         svi = IVEC2IS(di);
1128         ivec_sub(SHIFT_IVEC(g, aj), SHIFT_IVEC(g, ai), di);
1129         sji = IVEC2IS(di);
1130         ivec_sub(SHIFT_IVEC(g, ak), SHIFT_IVEC(g, ai), di);
1131         ski = IVEC2IS(di);
1132     }
1133     else if (pbc)
1134     {
1135         svi = pbc_rvec_sub(pbc, x[av], x[ai], xvi);
1136     }
1137     else
1138     {
1139         svi = CENTRAL;
1140     }
1141
1142     if (fshift && (svi != CENTRAL || sji != CENTRAL || ski != CENTRAL))
1143     {
1144         rvec_dec(fshift[svi], fv);
1145         fshift[CENTRAL][XX] += fv[XX] - fj[XX] - fk[XX];
1146         fshift[CENTRAL][YY] += fv[YY] - fj[YY] - fk[YY];
1147         fshift[CENTRAL][ZZ] += fv[ZZ] - fj[ZZ] - fk[ZZ];
1148         rvec_inc(fshift[sji], fj);
1149         rvec_inc(fshift[ski], fk);
1150     }
1151
1152     if (VirCorr)
1153     {
1154         rvec xiv;
1155
1156         pbc_rvec_sub(pbc, x[av], x[ai], xiv);
1157
1158         for (int i = 0; i < DIM; i++)
1159         {
1160             for (int j = 0; j < DIM; j++)
1161             {
1162                 dxdf[i][j] += -xiv[i]*fv[j] + xij[i]*fj[j] + xik[i]*fk[j];
1163             }
1164         }
1165     }
1166
1167     /* TOTAL: 54 flops */
1168 }
1169
1170 static void spread_vsite4FD(const t_iatom ia[], real a, real b, real c,
1171                             const rvec x[],
1172                             rvec f[], rvec fshift[],
1173                             gmx_bool VirCorr, matrix dxdf,
1174                             const t_pbc *pbc, const t_graph *g)
1175 {
1176     real    d, invl, fproj, a1;
1177     rvec    xvi, xij, xjk, xjl, xix, fv, temp;
1178     int     av, ai, aj, ak, al;
1179     ivec    di;
1180     int     svi, sji, skj, slj, m;
1181
1182     av = ia[1];
1183     ai = ia[2];
1184     aj = ia[3];
1185     ak = ia[4];
1186     al = ia[5];
1187
1188     sji = pbc_rvec_sub(pbc, x[aj], x[ai], xij);
1189     skj = pbc_rvec_sub(pbc, x[ak], x[aj], xjk);
1190     slj = pbc_rvec_sub(pbc, x[al], x[aj], xjl);
1191     /* 9 flops */
1192
1193     /* xix goes from i to point x on the plane jkl */
1194     for (m = 0; m < DIM; m++)
1195     {
1196         xix[m] = xij[m] + a*xjk[m] + b*xjl[m];
1197     }
1198     /* 12 flops */
1199
1200     invl = gmx::invsqrt(iprod(xix, xix));
1201     d    = c*invl;
1202     /* 4 + ?10? flops */
1203
1204     copy_rvec(f[av], fv);
1205
1206     fproj = iprod(xix, fv)*invl*invl; /* = (xix . f)/(xix . xix) */
1207
1208     for (m = 0; m < DIM; m++)
1209     {
1210         temp[m] = d*(fv[m] - fproj*xix[m]);
1211     }
1212     /* 16 */
1213
1214     /* c is already calculated in constr_vsite3FD
1215        storing c somewhere will save 35 flops!     */
1216
1217     a1 = 1 - a - b;
1218     for (m = 0; m < DIM; m++)
1219     {
1220         f[ai][m] += fv[m] - temp[m];
1221         f[aj][m] += a1*temp[m];
1222         f[ak][m] += a*temp[m];
1223         f[al][m] += b*temp[m];
1224     }
1225     /* 26 Flops */
1226
1227     if (g)
1228     {
1229         ivec_sub(SHIFT_IVEC(g, ia[1]), SHIFT_IVEC(g, ai), di);
1230         svi = IVEC2IS(di);
1231         ivec_sub(SHIFT_IVEC(g, aj), SHIFT_IVEC(g, ai), di);
1232         sji = IVEC2IS(di);
1233         ivec_sub(SHIFT_IVEC(g, ak), SHIFT_IVEC(g, aj), di);
1234         skj = IVEC2IS(di);
1235         ivec_sub(SHIFT_IVEC(g, al), SHIFT_IVEC(g, aj), di);
1236         slj = IVEC2IS(di);
1237     }
1238     else if (pbc)
1239     {
1240         svi = pbc_rvec_sub(pbc, x[av], x[ai], xvi);
1241     }
1242     else
1243     {
1244         svi = CENTRAL;
1245     }
1246
1247     if (fshift &&
1248         (svi != CENTRAL || sji != CENTRAL || skj != CENTRAL || slj != CENTRAL))
1249     {
1250         rvec_dec(fshift[svi], fv);
1251         for (m = 0; m < DIM; m++)
1252         {
1253             fshift[CENTRAL][m] += fv[m] - (1 + a + b)*temp[m];
1254             fshift[    sji][m] += temp[m];
1255             fshift[    skj][m] += a*temp[m];
1256             fshift[    slj][m] += b*temp[m];
1257         }
1258     }
1259
1260     if (VirCorr)
1261     {
1262         rvec xiv;
1263         int  i, j;
1264
1265         pbc_rvec_sub(pbc, x[av], x[ai], xiv);
1266
1267         for (i = 0; i < DIM; i++)
1268         {
1269             for (j = 0; j < DIM; j++)
1270             {
1271                 dxdf[i][j] += -xiv[i]*fv[j] + xix[i]*temp[j];
1272             }
1273         }
1274     }
1275
1276     /* TOTAL: 77 flops */
1277 }
1278
1279
1280 static void spread_vsite4FDN(const t_iatom ia[], real a, real b, real c,
1281                              const rvec x[],
1282                              rvec f[], rvec fshift[],
1283                              gmx_bool VirCorr, matrix dxdf,
1284                              const t_pbc *pbc, const t_graph *g)
1285 {
1286     rvec xvi, xij, xik, xil, ra, rb, rja, rjb, rab, rm, rt;
1287     rvec fv, fj, fk, fl;
1288     real invrm, denom;
1289     real cfx, cfy, cfz;
1290     ivec di;
1291     int  av, ai, aj, ak, al;
1292     int  svi, sij, sik, sil;
1293
1294     /* DEBUG: check atom indices */
1295     av = ia[1];
1296     ai = ia[2];
1297     aj = ia[3];
1298     ak = ia[4];
1299     al = ia[5];
1300
1301     copy_rvec(f[av], fv);
1302
1303     sij = pbc_rvec_sub(pbc, x[aj], x[ai], xij);
1304     sik = pbc_rvec_sub(pbc, x[ak], x[ai], xik);
1305     sil = pbc_rvec_sub(pbc, x[al], x[ai], xil);
1306     /* 9 flops */
1307
1308     ra[XX] = a*xik[XX];
1309     ra[YY] = a*xik[YY];
1310     ra[ZZ] = a*xik[ZZ];
1311
1312     rb[XX] = b*xil[XX];
1313     rb[YY] = b*xil[YY];
1314     rb[ZZ] = b*xil[ZZ];
1315
1316     /* 6 flops */
1317
1318     rvec_sub(ra, xij, rja);
1319     rvec_sub(rb, xij, rjb);
1320     rvec_sub(rb, ra, rab);
1321     /* 9 flops */
1322
1323     cprod(rja, rjb, rm);
1324     /* 9 flops */
1325
1326     invrm = gmx::invsqrt(norm2(rm));
1327     denom = invrm*invrm;
1328     /* 5+5+2 flops */
1329
1330     cfx = c*invrm*fv[XX];
1331     cfy = c*invrm*fv[YY];
1332     cfz = c*invrm*fv[ZZ];
1333     /* 6 Flops */
1334
1335     cprod(rm, rab, rt);
1336     /* 9 flops */
1337
1338     rt[XX] *= denom;
1339     rt[YY] *= denom;
1340     rt[ZZ] *= denom;
1341     /* 3flops */
1342
1343     fj[XX] = (        -rm[XX]*rt[XX]) * cfx + ( rab[ZZ]-rm[YY]*rt[XX]) * cfy + (-rab[YY]-rm[ZZ]*rt[XX]) * cfz;
1344     fj[YY] = (-rab[ZZ]-rm[XX]*rt[YY]) * cfx + (        -rm[YY]*rt[YY]) * cfy + ( rab[XX]-rm[ZZ]*rt[YY]) * cfz;
1345     fj[ZZ] = ( rab[YY]-rm[XX]*rt[ZZ]) * cfx + (-rab[XX]-rm[YY]*rt[ZZ]) * cfy + (        -rm[ZZ]*rt[ZZ]) * cfz;
1346     /* 30 flops */
1347
1348     cprod(rjb, rm, rt);
1349     /* 9 flops */
1350
1351     rt[XX] *= denom*a;
1352     rt[YY] *= denom*a;
1353     rt[ZZ] *= denom*a;
1354     /* 3flops */
1355
1356     fk[XX] = (          -rm[XX]*rt[XX]) * cfx + (-a*rjb[ZZ]-rm[YY]*rt[XX]) * cfy + ( a*rjb[YY]-rm[ZZ]*rt[XX]) * cfz;
1357     fk[YY] = ( a*rjb[ZZ]-rm[XX]*rt[YY]) * cfx + (          -rm[YY]*rt[YY]) * cfy + (-a*rjb[XX]-rm[ZZ]*rt[YY]) * cfz;
1358     fk[ZZ] = (-a*rjb[YY]-rm[XX]*rt[ZZ]) * cfx + ( a*rjb[XX]-rm[YY]*rt[ZZ]) * cfy + (          -rm[ZZ]*rt[ZZ]) * cfz;
1359     /* 36 flops */
1360
1361     cprod(rm, rja, rt);
1362     /* 9 flops */
1363
1364     rt[XX] *= denom*b;
1365     rt[YY] *= denom*b;
1366     rt[ZZ] *= denom*b;
1367     /* 3flops */
1368
1369     fl[XX] = (          -rm[XX]*rt[XX]) * cfx + ( b*rja[ZZ]-rm[YY]*rt[XX]) * cfy + (-b*rja[YY]-rm[ZZ]*rt[XX]) * cfz;
1370     fl[YY] = (-b*rja[ZZ]-rm[XX]*rt[YY]) * cfx + (          -rm[YY]*rt[YY]) * cfy + ( b*rja[XX]-rm[ZZ]*rt[YY]) * cfz;
1371     fl[ZZ] = ( b*rja[YY]-rm[XX]*rt[ZZ]) * cfx + (-b*rja[XX]-rm[YY]*rt[ZZ]) * cfy + (          -rm[ZZ]*rt[ZZ]) * cfz;
1372     /* 36 flops */
1373
1374     f[ai][XX] += fv[XX] - fj[XX] - fk[XX] - fl[XX];
1375     f[ai][YY] += fv[YY] - fj[YY] - fk[YY] - fl[YY];
1376     f[ai][ZZ] += fv[ZZ] - fj[ZZ] - fk[ZZ] - fl[ZZ];
1377     rvec_inc(f[aj], fj);
1378     rvec_inc(f[ak], fk);
1379     rvec_inc(f[al], fl);
1380     /* 21 flops */
1381
1382     if (g)
1383     {
1384         ivec_sub(SHIFT_IVEC(g, av), SHIFT_IVEC(g, ai), di);
1385         svi = IVEC2IS(di);
1386         ivec_sub(SHIFT_IVEC(g, aj), SHIFT_IVEC(g, ai), di);
1387         sij = IVEC2IS(di);
1388         ivec_sub(SHIFT_IVEC(g, ak), SHIFT_IVEC(g, ai), di);
1389         sik = IVEC2IS(di);
1390         ivec_sub(SHIFT_IVEC(g, al), SHIFT_IVEC(g, ai), di);
1391         sil = IVEC2IS(di);
1392     }
1393     else if (pbc)
1394     {
1395         svi = pbc_rvec_sub(pbc, x[av], x[ai], xvi);
1396     }
1397     else
1398     {
1399         svi = CENTRAL;
1400     }
1401
1402     if (fshift && (svi != CENTRAL || sij != CENTRAL || sik != CENTRAL || sil != CENTRAL))
1403     {
1404         rvec_dec(fshift[svi], fv);
1405         fshift[CENTRAL][XX] += fv[XX] - fj[XX] - fk[XX] - fl[XX];
1406         fshift[CENTRAL][YY] += fv[YY] - fj[YY] - fk[YY] - fl[YY];
1407         fshift[CENTRAL][ZZ] += fv[ZZ] - fj[ZZ] - fk[ZZ] - fl[ZZ];
1408         rvec_inc(fshift[sij], fj);
1409         rvec_inc(fshift[sik], fk);
1410         rvec_inc(fshift[sil], fl);
1411     }
1412
1413     if (VirCorr)
1414     {
1415         rvec xiv;
1416         int  i, j;
1417
1418         pbc_rvec_sub(pbc, x[av], x[ai], xiv);
1419
1420         for (i = 0; i < DIM; i++)
1421         {
1422             for (j = 0; j < DIM; j++)
1423             {
1424                 dxdf[i][j] += -xiv[i]*fv[j] + xij[i]*fj[j] + xik[i]*fk[j] + xil[i]*fl[j];
1425             }
1426         }
1427     }
1428
1429     /* Total: 207 flops (Yuck!) */
1430 }
1431
1432
1433 static int spread_vsiten(const t_iatom ia[], const t_iparams ip[],
1434                          const rvec x[],
1435                          rvec f[], rvec fshift[],
1436                          const t_pbc *pbc, const t_graph *g)
1437 {
1438     rvec xv, dx, fi;
1439     int  n3, av, i, ai;
1440     real a;
1441     ivec di;
1442     int  siv;
1443
1444     n3 = 3*ip[ia[0]].vsiten.n;
1445     av = ia[1];
1446     copy_rvec(x[av], xv);
1447
1448     for (i = 0; i < n3; i += 3)
1449     {
1450         ai = ia[i+2];
1451         if (g)
1452         {
1453             ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, av), di);
1454             siv = IVEC2IS(di);
1455         }
1456         else if (pbc)
1457         {
1458             siv = pbc_dx_aiuc(pbc, x[ai], xv, dx);
1459         }
1460         else
1461         {
1462             siv = CENTRAL;
1463         }
1464         a = ip[ia[i]].vsiten.a;
1465         svmul(a, f[av], fi);
1466         rvec_inc(f[ai], fi);
1467         if (fshift && siv != CENTRAL)
1468         {
1469             rvec_inc(fshift[siv], fi);
1470             rvec_dec(fshift[CENTRAL], fi);
1471         }
1472         /* 6 Flops */
1473     }
1474
1475     return n3;
1476 }
1477
1478
1479 static int vsite_count(const t_ilist *ilist, int ftype)
1480 {
1481     if (ftype == F_VSITEN)
1482     {
1483         return ilist[ftype].nr/3;
1484     }
1485     else
1486     {
1487         return ilist[ftype].nr/(1 + interaction_function[ftype].nratoms);
1488     }
1489 }
1490
1491 static void spread_vsite_f_thread(const gmx_vsite_t *vsite,
1492                                   const rvec x[],
1493                                   rvec f[], rvec *fshift,
1494                                   gmx_bool VirCorr, matrix dxdf,
1495                                   t_iparams ip[], const t_ilist ilist[],
1496                                   const t_graph *g, const t_pbc *pbc_null)
1497 {
1498     const PbcMode            pbcMode   = getPbcMode(pbc_null, vsite);
1499     /* We need another pbc pointer, as with charge groups we switch per vsite */
1500     const t_pbc             *pbc_null2 = pbc_null;
1501     gmx::ArrayRef<const int> vsite_pbc;
1502
1503     /* this loop goes backwards to be able to build *
1504      * higher type vsites from lower types         */
1505     for (int ftype = c_ftypeVsiteEnd - 1; ftype >= c_ftypeVsiteStart; ftype--)
1506     {
1507         if (ilist[ftype].nr == 0)
1508         {
1509             continue;
1510         }
1511
1512         {   // TODO remove me
1513             int            nra = interaction_function[ftype].nratoms;
1514             int            inc = 1 + nra;
1515             int            nr  = ilist[ftype].nr;
1516
1517             const t_iatom *ia = ilist[ftype].iatoms;
1518
1519             if (pbcMode == PbcMode::all)
1520             {
1521                 pbc_null2 = pbc_null;
1522             }
1523             else if (pbcMode == PbcMode::chargeGroup)
1524             {
1525                 if (vsite->vsite_pbc_loc)
1526                 {
1527                     vsite_pbc = (*vsite->vsite_pbc_loc)[ftype - c_ftypeVsiteStart];
1528                 }
1529             }
1530
1531             for (int i = 0; i < nr; )
1532             {
1533                 if (!vsite_pbc.empty())
1534                 {
1535                     if (vsite_pbc[i/(1 + nra)] > -2)
1536                     {
1537                         pbc_null2 = pbc_null;
1538                     }
1539                     else
1540                     {
1541                         pbc_null2 = nullptr;
1542                     }
1543                 }
1544
1545                 int tp = ia[0];
1546
1547                 /* Constants for constructing */
1548                 real a1, b1, c1;
1549                 a1 = ip[tp].vsite.a;
1550                 /* Construct the vsite depending on type */
1551                 switch (ftype)
1552                 {
1553                     case F_VSITE2:
1554                         spread_vsite2(ia, a1, x, f, fshift, pbc_null2, g);
1555                         break;
1556                     case F_VSITE3:
1557                         b1 = ip[tp].vsite.b;
1558                         spread_vsite3(ia, a1, b1, x, f, fshift, pbc_null2, g);
1559                         break;
1560                     case F_VSITE3FD:
1561                         b1 = ip[tp].vsite.b;
1562                         spread_vsite3FD(ia, a1, b1, x, f, fshift, VirCorr, dxdf, pbc_null2, g);
1563                         break;
1564                     case F_VSITE3FAD:
1565                         b1 = ip[tp].vsite.b;
1566                         spread_vsite3FAD(ia, a1, b1, x, f, fshift, VirCorr, dxdf, pbc_null2, g);
1567                         break;
1568                     case F_VSITE3OUT:
1569                         b1 = ip[tp].vsite.b;
1570                         c1 = ip[tp].vsite.c;
1571                         spread_vsite3OUT(ia, a1, b1, c1, x, f, fshift, VirCorr, dxdf, pbc_null2, g);
1572                         break;
1573                     case F_VSITE4FD:
1574                         b1 = ip[tp].vsite.b;
1575                         c1 = ip[tp].vsite.c;
1576                         spread_vsite4FD(ia, a1, b1, c1, x, f, fshift, VirCorr, dxdf, pbc_null2, g);
1577                         break;
1578                     case F_VSITE4FDN:
1579                         b1 = ip[tp].vsite.b;
1580                         c1 = ip[tp].vsite.c;
1581                         spread_vsite4FDN(ia, a1, b1, c1, x, f, fshift, VirCorr, dxdf, pbc_null2, g);
1582                         break;
1583                     case F_VSITEN:
1584                         inc = spread_vsiten(ia, ip, x, f, fshift, pbc_null2, g);
1585                         break;
1586                     default:
1587                         gmx_fatal(FARGS, "No such vsite type %d in %s, line %d",
1588                                   ftype, __FILE__, __LINE__);
1589                 }
1590                 clear_rvec(f[ia[1]]);
1591
1592                 /* Increment loop variables */
1593                 i  += inc;
1594                 ia += inc;
1595             }
1596         }
1597     }
1598 }
1599
1600 /*! \brief Clears the task force buffer elements that are written by task idTask */
1601 static void clearTaskForceBufferUsedElements(InterdependentTask *idTask)
1602 {
1603     int ntask = idTask->spreadTask.size();
1604     for (int ti = 0; ti < ntask; ti++)
1605     {
1606         const AtomIndex *atomList = &idTask->atomIndex[idTask->spreadTask[ti]];
1607         int              natom    = atomList->atom.size();
1608         RVec            *force    = idTask->force.data();
1609         for (int i = 0; i < natom; i++)
1610         {
1611             clear_rvec(force[atomList->atom[i]]);
1612         }
1613     }
1614 }
1615
1616 void spread_vsite_f(const gmx_vsite_t *vsite,
1617                     const rvec * gmx_restrict x,
1618                     rvec * gmx_restrict f, rvec * gmx_restrict fshift,
1619                     gmx_bool VirCorr, matrix vir,
1620                     t_nrnb *nrnb, const t_idef *idef,
1621                     int ePBC, gmx_bool bMolPBC, const t_graph *g, const matrix box,
1622                     const t_commrec *cr, gmx_wallcycle *wcycle)
1623 {
1624     wallcycle_start(wcycle, ewcVSITESPREAD);
1625     const bool useDomdec = vsite->useDomdec;
1626     GMX_ASSERT(!useDomdec || (cr != nullptr && DOMAINDECOMP(cr)), "When vsites are set up with domain decomposition, we need a valid commrec");
1627
1628     t_pbc pbc, *pbc_null;
1629
1630     /* We only need to do pbc when we have inter-cg vsites */
1631     if ((useDomdec || bMolPBC) && vsite->n_intercg_vsite)
1632     {
1633         /* This is wasting some CPU time as we now do this multiple times
1634          * per MD step.
1635          */
1636         pbc_null = set_pbc_dd(&pbc, ePBC, useDomdec ? cr->dd->nc : nullptr, FALSE, box);
1637     }
1638     else
1639     {
1640         pbc_null = nullptr;
1641     }
1642
1643     if (useDomdec)
1644     {
1645         dd_clear_f_vsites(cr->dd, f);
1646     }
1647
1648     if (vsite->nthreads == 1)
1649     {
1650         matrix dxdf;
1651         if (VirCorr)
1652         {
1653             clear_mat(dxdf);
1654         }
1655         spread_vsite_f_thread(vsite,
1656                               x, f, fshift,
1657                               VirCorr, dxdf,
1658                               idef->iparams, idef->il,
1659                               g, pbc_null);
1660
1661         if (VirCorr)
1662         {
1663             for (int i = 0; i < DIM; i++)
1664             {
1665                 for (int j = 0; j < DIM; j++)
1666                 {
1667                     vir[i][j] += -0.5*dxdf[i][j];
1668                 }
1669             }
1670         }
1671     }
1672     else
1673     {
1674         /* First spread the vsites that might depend on non-local vsites */
1675         if (VirCorr)
1676         {
1677             clear_mat(vsite->tData[vsite->nthreads]->dxdf);
1678         }
1679         spread_vsite_f_thread(vsite,
1680                               x, f, fshift,
1681                               VirCorr, vsite->tData[vsite->nthreads]->dxdf,
1682                               idef->iparams,
1683                               vsite->tData[vsite->nthreads]->ilist,
1684                               g, pbc_null);
1685
1686 #pragma omp parallel num_threads(vsite->nthreads)
1687         {
1688             try
1689             {
1690                 int          thread = gmx_omp_get_thread_num();
1691                 VsiteThread &tData  = *vsite->tData[thread];
1692
1693                 rvec        *fshift_t;
1694                 if (thread == 0 || fshift == nullptr)
1695                 {
1696                     fshift_t = fshift;
1697                 }
1698                 else
1699                 {
1700                     fshift_t = tData.fshift;
1701
1702                     for (int i = 0; i < SHIFTS; i++)
1703                     {
1704                         clear_rvec(fshift_t[i]);
1705                     }
1706                 }
1707                 if (VirCorr)
1708                 {
1709                     clear_mat(tData.dxdf);
1710                 }
1711
1712                 if (tData.useInterdependentTask)
1713                 {
1714                     /* Spread the vsites that spread outside our local range.
1715                      * This is done using a thread-local force buffer force.
1716                      * First we need to copy the input vsite forces to force.
1717                      */
1718                     InterdependentTask *idTask = &tData.idTask;
1719
1720                     /* Clear the buffer elements set by our task during
1721                      * the last call to spread_vsite_f.
1722                      */
1723                     clearTaskForceBufferUsedElements(idTask);
1724
1725                     int nvsite = idTask->vsite.size();
1726                     for (int i = 0; i < nvsite; i++)
1727                     {
1728                         copy_rvec(f[idTask->vsite[i]],
1729                                   idTask->force[idTask->vsite[i]]);
1730                     }
1731                     spread_vsite_f_thread(vsite,
1732                                           x, as_rvec_array(idTask->force.data()), fshift_t,
1733                                           VirCorr, tData.dxdf,
1734                                           idef->iparams,
1735                                           tData.idTask.ilist,
1736                                           g, pbc_null);
1737
1738                     /* We need a barrier before reducing forces below
1739                      * that have been produced by a different thread above.
1740                      */
1741 #pragma omp barrier
1742
1743                     /* Loop over all thread task and reduce forces they
1744                      * produced on atoms that fall in our range.
1745                      * Note that atomic reduction would be a simpler solution,
1746                      * but that might not have good support on all platforms.
1747                      */
1748                     int ntask = idTask->reduceTask.size();
1749                     for (int ti = 0; ti < ntask; ti++)
1750                     {
1751                         const InterdependentTask *idt_foreign = &vsite->tData[idTask->reduceTask[ti]]->idTask;
1752                         const AtomIndex          *atomList    = &idt_foreign->atomIndex[thread];
1753                         const RVec               *f_foreign   = idt_foreign->force.data();
1754
1755                         int natom = atomList->atom.size();
1756                         for (int i = 0; i < natom; i++)
1757                         {
1758                             int ind = atomList->atom[i];
1759                             rvec_inc(f[ind], f_foreign[ind]);
1760                             /* Clearing of f_foreign is done at the next step */
1761                         }
1762                     }
1763                     /* Clear the vsite forces, both in f and force */
1764                     for (int i = 0; i < nvsite; i++)
1765                     {
1766                         int ind = tData.idTask.vsite[i];
1767                         clear_rvec(f[ind]);
1768                         clear_rvec(tData.idTask.force[ind]);
1769                     }
1770                 }
1771
1772                 /* Spread the vsites that spread locally only */
1773                 spread_vsite_f_thread(vsite,
1774                                       x, f, fshift_t,
1775                                       VirCorr, tData.dxdf,
1776                                       idef->iparams,
1777                                       tData.ilist,
1778                                       g, pbc_null);
1779             }
1780             GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
1781         }
1782
1783         if (fshift != nullptr)
1784         {
1785             for (int th = 1; th < vsite->nthreads; th++)
1786             {
1787                 for (int i = 0; i < SHIFTS; i++)
1788                 {
1789                     rvec_inc(fshift[i], vsite->tData[th]->fshift[i]);
1790                 }
1791             }
1792         }
1793
1794         if (VirCorr)
1795         {
1796             for (int th = 0; th < vsite->nthreads + 1; th++)
1797             {
1798                 /* MSVC doesn't like matrix references, so we use a pointer */
1799                 const matrix *dxdf = &vsite->tData[th]->dxdf;
1800
1801                 for (int i = 0; i < DIM; i++)
1802                 {
1803                     for (int j = 0; j < DIM; j++)
1804                     {
1805                         vir[i][j] += -0.5*(*dxdf)[i][j];
1806                     }
1807                 }
1808             }
1809         }
1810     }
1811
1812     if (useDomdec)
1813     {
1814         dd_move_f_vsites(cr->dd, f, fshift);
1815     }
1816
1817     inc_nrnb(nrnb, eNR_VSITE2,   vsite_count(idef->il, F_VSITE2));
1818     inc_nrnb(nrnb, eNR_VSITE3,   vsite_count(idef->il, F_VSITE3));
1819     inc_nrnb(nrnb, eNR_VSITE3FD, vsite_count(idef->il, F_VSITE3FD));
1820     inc_nrnb(nrnb, eNR_VSITE3FAD, vsite_count(idef->il, F_VSITE3FAD));
1821     inc_nrnb(nrnb, eNR_VSITE3OUT, vsite_count(idef->il, F_VSITE3OUT));
1822     inc_nrnb(nrnb, eNR_VSITE4FD, vsite_count(idef->il, F_VSITE4FD));
1823     inc_nrnb(nrnb, eNR_VSITE4FDN, vsite_count(idef->il, F_VSITE4FDN));
1824     inc_nrnb(nrnb, eNR_VSITEN,   vsite_count(idef->il, F_VSITEN));
1825
1826     wallcycle_stop(wcycle, ewcVSITESPREAD);
1827 }
1828
1829 /*! \brief Returns the an array with charge-group indices for each atom
1830  *
1831  * \param[in] chargeGroups  The charge group block struct
1832  */
1833 static std::vector<int> atom2cg(const t_block &chargeGroups)
1834 {
1835     std::vector<int> a2cg(chargeGroups.index[chargeGroups.nr], 0);
1836
1837     for (int chargeGroup = 0; chargeGroup < chargeGroups.nr; chargeGroup++)
1838     {
1839         std::fill(a2cg.begin() + chargeGroups.index[chargeGroup],
1840                   a2cg.begin() + chargeGroups.index[chargeGroup + 1],
1841                   chargeGroup);
1842     }
1843
1844     return a2cg;
1845 }
1846
1847 int count_intercg_vsites(const gmx_mtop_t *mtop)
1848 {
1849     int n_intercg_vsite = 0;
1850     for (const gmx_molblock_t &molb : mtop->molblock)
1851     {
1852         const gmx_moltype_t &molt = mtop->moltype[molb.type];
1853
1854         std::vector<int>     a2cg = atom2cg(molt.cgs);
1855         for (int ftype = c_ftypeVsiteStart; ftype < c_ftypeVsiteEnd; ftype++)
1856         {
1857             const int              nral = NRAL(ftype);
1858             const InteractionList &il   = molt.ilist[ftype];
1859             for (int i = 0; i < il.size(); i += 1 + nral)
1860             {
1861                 int cg = a2cg[il.iatoms[1 + i]];
1862                 for (int a = 1; a < nral; a++)
1863                 {
1864                     if (a2cg[il.iatoms[1 + a]] != cg)
1865                     {
1866                         n_intercg_vsite += molb.nmol;
1867                         break;
1868                     }
1869                 }
1870             }
1871         }
1872     }
1873
1874     return n_intercg_vsite;
1875 }
1876
1877 template <typename T>
1878 static VsitePbc
1879 get_vsite_pbc(const t_iparams *iparams, const T *ilist,
1880               const t_atom *atom, const t_mdatoms *md,
1881               const t_block &cgs)
1882 {
1883     /* Make an atom to charge group index */
1884     std::vector<int> a2cg = atom2cg(cgs);
1885
1886     /* Make an array that tells if the pbc of an atom is set */
1887     std::vector<bool> pbc_set(cgs.index[cgs.nr], false);
1888     /* PBC is set for all non vsites */
1889     for (int a = 0; a < cgs.index[cgs.nr]; a++)
1890     {
1891         if ((atom && atom[a].ptype != eptVSite) ||
1892             (md   && md->ptype[a]  != eptVSite))
1893         {
1894             pbc_set[a] = true;
1895         }
1896     }
1897
1898     VsitePbc vsite_pbc;
1899
1900     for (int ftype = c_ftypeVsiteStart; ftype < c_ftypeVsiteEnd; ftype++)
1901     {
1902         {   // TODO remove me
1903             int               nral = NRAL(ftype);
1904             const T          &il   = ilist[ftype];
1905
1906             std::vector<int> &vsite_pbc_f = vsite_pbc[ftype - F_VSITE2];
1907             vsite_pbc_f.resize(il.size()/(1 + nral));
1908
1909             int i = 0;
1910             while (i < il.size())
1911             {
1912                 int     vsi   = i/(1 + nral);
1913                 t_iatom vsite = il.iatoms[i + 1];
1914                 int     cg_v  = a2cg[vsite];
1915                 /* A value of -2 signals that this vsite and its contructing
1916                  * atoms are all within the same cg, so no pbc is required.
1917                  */
1918                 vsite_pbc_f[vsi] = -2;
1919                 /* Check if constructing atoms are outside the vsite's cg */
1920                 int nc3 = 0;
1921                 if (ftype == F_VSITEN)
1922                 {
1923                     nc3 = 3*iparams[il.iatoms[i]].vsiten.n;
1924                     for (int j = 0; j < nc3; j += 3)
1925                     {
1926                         if (a2cg[il.iatoms[i + j + 2]] != cg_v)
1927                         {
1928                             vsite_pbc_f[vsi] = -1;
1929                         }
1930                     }
1931                 }
1932                 else
1933                 {
1934                     for (int a = 1; a < nral; a++)
1935                     {
1936                         if (a2cg[il.iatoms[i + 1 + a]] != cg_v)
1937                         {
1938                             vsite_pbc_f[vsi] = -1;
1939                         }
1940                     }
1941                 }
1942                 if (vsite_pbc_f[vsi] == -1)
1943                 {
1944                     /* Check if this is the first processed atom of a vsite only cg */
1945                     gmx_bool bViteOnlyCG_and_FirstAtom = TRUE;
1946                     for (int a = cgs.index[cg_v]; a < cgs.index[cg_v + 1]; a++)
1947                     {
1948                         /* Non-vsites already have pbc set, so simply check for pbc_set */
1949                         if (pbc_set[a])
1950                         {
1951                             bViteOnlyCG_and_FirstAtom = FALSE;
1952                             break;
1953                         }
1954                     }
1955                     if (bViteOnlyCG_and_FirstAtom)
1956                     {
1957                         /* First processed atom of a vsite only charge group.
1958                          * The pbc of the input coordinates to construct_vsites
1959                          * should be preserved.
1960                          */
1961                         vsite_pbc_f[vsi] = vsite;
1962                     }
1963                     else if (cg_v != a2cg[il.iatoms[1 + i + 1]])
1964                     {
1965                         /* This vsite has a different charge group index
1966                          * than it's first constructing atom
1967                          * and the charge group has more than one atom,
1968                          * search for the first normal particle
1969                          * or vsite that already had its pbc defined.
1970                          * If nothing is found, use full pbc for this vsite.
1971                          */
1972                         for (int a = cgs.index[cg_v]; a < cgs.index[cg_v + 1]; a++)
1973                         {
1974                             if (a != vsite && pbc_set[a])
1975                             {
1976                                 vsite_pbc_f[vsi] = a;
1977                                 if (gmx_debug_at)
1978                                 {
1979                                     fprintf(debug, "vsite %d match pbc with atom %d\n",
1980                                             vsite+1, a+1);
1981                                 }
1982                                 break;
1983                             }
1984                         }
1985                         if (gmx_debug_at)
1986                         {
1987                             fprintf(debug, "vsite atom %d  cg %d - %d pbc atom %d\n",
1988                                     vsite+1, cgs.index[cg_v] + 1, cgs.index[cg_v + 1],
1989                                     vsite_pbc_f[vsi] + 1);
1990                         }
1991                     }
1992                 }
1993                 if (ftype == F_VSITEN)
1994                 {
1995                     /* The other entries in vsite_pbc_f are not used for center vsites */
1996                     i += nc3;
1997                 }
1998                 else
1999                 {
2000                     i += 1 + nral;
2001                 }
2002
2003                 /* This vsite now has its pbc defined */
2004                 pbc_set[vsite] = true;
2005             }
2006         }
2007     }
2008
2009     return vsite_pbc;
2010 }
2011
2012
2013 std::unique_ptr<gmx_vsite_t>
2014 initVsite(const gmx_mtop_t &mtop,
2015           const t_commrec  *cr)
2016 {
2017     GMX_RELEASE_ASSERT(cr != nullptr, "We need a valid commrec");
2018
2019     std::unique_ptr<gmx_vsite_t> vsite;
2020
2021     /* check if there are vsites */
2022     int nvsite = 0;
2023     for (int ftype = 0; ftype < F_NRE; ftype++)
2024     {
2025         if (interaction_function[ftype].flags & IF_VSITE)
2026         {
2027             GMX_ASSERT(ftype >= c_ftypeVsiteStart && ftype < c_ftypeVsiteEnd, "c_ftypeVsiteStart and/or c_ftypeVsiteEnd do not have correct values");
2028
2029             nvsite += gmx_mtop_ftype_count(&mtop, ftype);
2030         }
2031         else
2032         {
2033             GMX_ASSERT(ftype < c_ftypeVsiteStart || ftype >= c_ftypeVsiteEnd, "c_ftypeVsiteStart and/or c_ftypeVsiteEnd do not have correct values");
2034         }
2035     }
2036
2037     if (nvsite == 0)
2038     {
2039         return vsite;
2040     }
2041
2042     vsite = gmx::compat::make_unique<gmx_vsite_t>();
2043
2044     vsite->n_intercg_vsite   = count_intercg_vsites(&mtop);
2045
2046     vsite->bHaveChargeGroups = (ncg_mtop(&mtop) < mtop.natoms);
2047
2048     vsite->useDomdec         = (DOMAINDECOMP(cr) && cr->dd->nnodes > 1);
2049
2050     /* If we don't have charge groups, the vsite follows its own pbc.
2051      *
2052      * With charge groups, each vsite needs to follow the pbc of the charge
2053      * group. Thus we need to keep track of PBC. Here we assume that without
2054      * domain decomposition all molecules are whole (which will not be
2055      * the case with periodic molecules).
2056      */
2057     if (vsite->bHaveChargeGroups &&
2058         vsite->n_intercg_vsite > 0 &&
2059         DOMAINDECOMP(cr))
2060     {
2061         vsite->vsite_pbc_molt.resize(mtop.moltype.size());
2062         for (size_t mt = 0; mt < mtop.moltype.size(); mt++)
2063         {
2064             const gmx_moltype_t &molt = mtop.moltype[mt];
2065             vsite->vsite_pbc_molt[mt] = get_vsite_pbc(mtop.ffparams.iparams.data(),
2066                                                       molt.ilist.data(),
2067                                                       molt.atoms.atom, nullptr,
2068                                                       molt.cgs);
2069         }
2070
2071         vsite->vsite_pbc_loc = gmx::compat::make_unique<VsitePbc>();
2072     }
2073
2074     vsite->nthreads = gmx_omp_nthreads_get(emntVSITE);
2075
2076     if (vsite->nthreads > 1)
2077     {
2078         /* We need one extra thread data structure for the overlap vsites */
2079         vsite->tData.resize(vsite->nthreads + 1);
2080 #pragma omp parallel for num_threads(vsite->nthreads) schedule(static)
2081         for (int thread = 0; thread < vsite->nthreads; thread++)
2082         {
2083             try
2084             {
2085                 vsite->tData[thread] = gmx::compat::make_unique<VsiteThread>();
2086
2087                 InterdependentTask &idTask = vsite->tData[thread]->idTask;
2088                 idTask.nuse                = 0;
2089                 idTask.atomIndex.resize(vsite->nthreads);
2090             }
2091             GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
2092         }
2093         if (vsite->nthreads > 1)
2094         {
2095             vsite->tData[vsite->nthreads] = gmx::compat::make_unique<VsiteThread>();
2096         }
2097     }
2098
2099     return vsite;
2100 }
2101
2102 gmx_vsite_t::gmx_vsite_t()
2103 {
2104 }
2105
2106 gmx_vsite_t::~gmx_vsite_t()
2107 {
2108 }
2109
2110 static inline void flagAtom(InterdependentTask *idTask, int atom,
2111                             int thread, int nthread, int natperthread)
2112 {
2113     if (!idTask->use[atom])
2114     {
2115         idTask->use[atom] = true;
2116         thread            = atom/natperthread;
2117         /* Assign all non-local atom force writes to thread 0 */
2118         if (thread >= nthread)
2119         {
2120             thread        = 0;
2121         }
2122         idTask->atomIndex[thread].atom.push_back(atom);
2123     }
2124 }
2125
2126 /*\brief Here we try to assign all vsites that are in our local range.
2127  *
2128  * Our task local atom range is tData->rangeStart - tData->rangeEnd.
2129  * Vsites that depend only on local atoms, as indicated by taskIndex[]==thread,
2130  * are assigned to task tData->ilist. Vsites that depend on non-local atoms
2131  * but not on other vsites are assigned to task tData->id_task.ilist.
2132  * taskIndex[] is set for all vsites in our range, either to our local tasks
2133  * or to the single last task as taskIndex[]=2*nthreads.
2134  */
2135 static void assignVsitesToThread(VsiteThread           *tData,
2136                                  int                    thread,
2137                                  int                    nthread,
2138                                  int                    natperthread,
2139                                  gmx::ArrayRef<int>     taskIndex,
2140                                  const t_ilist         *ilist,
2141                                  const t_iparams       *ip,
2142                                  const unsigned short  *ptype)
2143 {
2144     for (int ftype = c_ftypeVsiteStart; ftype < c_ftypeVsiteEnd; ftype++)
2145     {
2146         tData->ilist[ftype].nr        = 0;
2147         tData->idTask.ilist[ftype].nr = 0;
2148
2149         int      nral1 = 1 + NRAL(ftype);
2150         int      inc   = nral1;
2151         t_iatom *iat   = ilist[ftype].iatoms;
2152         for (int i = 0; i < ilist[ftype].nr; )
2153         {
2154             if (ftype == F_VSITEN)
2155             {
2156                 /* The 3 below is from 1+NRAL(ftype)=3 */
2157                 inc = ip[iat[i]].vsiten.n*3;
2158             }
2159
2160             if (iat[1 + i] <  tData->rangeStart ||
2161                 iat[1 + i] >= tData->rangeEnd)
2162             {
2163                 /* This vsite belongs to a different thread */
2164                 i += inc;
2165                 continue;
2166             }
2167
2168             /* We would like to assign this vsite to task thread,
2169              * but it might depend on atoms outside the atom range of thread
2170              * or on another vsite not assigned to task thread.
2171              */
2172             int task = thread;
2173             if (ftype != F_VSITEN)
2174             {
2175                 for (int j = i + 2; j < i + nral1; j++)
2176                 {
2177                     /* Do a range check to avoid a harmless race on taskIndex */
2178                     if (iat[j] <  tData->rangeStart ||
2179                         iat[j] >= tData->rangeEnd ||
2180                         taskIndex[iat[j]] != thread)
2181                     {
2182                         if (!tData->useInterdependentTask ||
2183                             ptype[iat[j]] == eptVSite)
2184                         {
2185                             /* At least one constructing atom is a vsite
2186                              * that is not assigned to the same thread.
2187                              * Put this vsite into a separate task.
2188                              */
2189                             task = 2*nthread;
2190                             break;
2191                         }
2192
2193                         /* There are constructing atoms outside our range,
2194                          * put this vsite into a second task to be executed
2195                          * on the same thread. During construction no barrier
2196                          * is needed between the two tasks on the same thread.
2197                          * During spreading we need to run this task with
2198                          * an additional thread-local intermediate force buffer
2199                          * (or atomic reduction) and a barrier between the two
2200                          * tasks.
2201                          */
2202                         task = nthread + thread;
2203                     }
2204                 }
2205             }
2206             else
2207             {
2208                 for (int j = i + 2; j < i + inc; j += 3)
2209                 {
2210                     /* Do a range check to avoid a harmless race on taskIndex */
2211                     if (iat[j] <  tData->rangeStart ||
2212                         iat[j] >= tData->rangeEnd ||
2213                         taskIndex[iat[j]] != thread)
2214                     {
2215                         GMX_ASSERT(ptype[iat[j]] != eptVSite, "A vsite to be assigned in assignVsitesToThread has a vsite as a constructing atom that does not belong to our task, such vsites should be assigned to the single 'master' task");
2216
2217                         task = nthread + thread;
2218                     }
2219                 }
2220             }
2221
2222             /* Update this vsite's thread index entry */
2223             taskIndex[iat[1+i]] = task;
2224
2225             if (task == thread || task == nthread + thread)
2226             {
2227                 /* Copy this vsite to the thread data struct of thread */
2228                 t_ilist *il_task;
2229                 if (task == thread)
2230                 {
2231                     il_task = &tData->ilist[ftype];
2232                 }
2233                 else
2234                 {
2235                     il_task = &tData->idTask.ilist[ftype];
2236                 }
2237                 /* Ensure we have sufficient memory allocated */
2238                 if (il_task->nr + inc > il_task->nalloc)
2239                 {
2240                     il_task->nalloc = over_alloc_large(il_task->nr + inc);
2241                     srenew(il_task->iatoms, il_task->nalloc);
2242                 }
2243                 /* Copy the vsite data to the thread-task local array */
2244                 for (int j = i; j < i + inc; j++)
2245                 {
2246                     il_task->iatoms[il_task->nr++] = iat[j];
2247                 }
2248                 if (task == nthread + thread)
2249                 {
2250                     /* This vsite write outside our own task force block.
2251                      * Put it into the interdependent task list and flag
2252                      * the atoms involved for reduction.
2253                      */
2254                     tData->idTask.vsite.push_back(iat[i + 1]);
2255                     if (ftype != F_VSITEN)
2256                     {
2257                         for (int j = i + 2; j < i + nral1; j++)
2258                         {
2259                             flagAtom(&tData->idTask, iat[j],
2260                                      thread, nthread, natperthread);
2261                         }
2262                     }
2263                     else
2264                     {
2265                         for (int j = i + 2; j < i + inc; j += 3)
2266                         {
2267                             flagAtom(&tData->idTask, iat[j],
2268                                      thread, nthread, natperthread);
2269                         }
2270                     }
2271                 }
2272             }
2273
2274             i += inc;
2275         }
2276     }
2277 }
2278
2279 /*! \brief Assign all vsites with taskIndex[]==task to task tData */
2280 static void assignVsitesToSingleTask(VsiteThread              *tData,
2281                                      int                       task,
2282                                      gmx::ArrayRef<const int>  taskIndex,
2283                                      const t_ilist            *ilist,
2284                                      const t_iparams          *ip)
2285 {
2286     for (int ftype = c_ftypeVsiteStart; ftype < c_ftypeVsiteEnd; ftype++)
2287     {
2288         tData->ilist[ftype].nr        = 0;
2289         tData->idTask.ilist[ftype].nr = 0;
2290
2291         int      nral1   = 1 + NRAL(ftype);
2292         int      inc     = nral1;
2293         t_iatom *iat     = ilist[ftype].iatoms;
2294         t_ilist *il_task = &tData->ilist[ftype];
2295
2296         for (int i = 0; i < ilist[ftype].nr; )
2297         {
2298             if (ftype == F_VSITEN)
2299             {
2300                 /* The 3 below is from 1+NRAL(ftype)=3 */
2301                 inc = ip[iat[i]].vsiten.n*3;
2302             }
2303             /* Check if the vsite is assigned to our task */
2304             if (taskIndex[iat[1 + i]] == task)
2305             {
2306                 /* Ensure we have sufficient memory allocated */
2307                 if (il_task->nr + inc > il_task->nalloc)
2308                 {
2309                     il_task->nalloc = over_alloc_large(il_task->nr + inc);
2310                     srenew(il_task->iatoms, il_task->nalloc);
2311                 }
2312                 /* Copy the vsite data to the thread-task local array */
2313                 for (int j = i; j < i + inc; j++)
2314                 {
2315                     il_task->iatoms[il_task->nr++] = iat[j];
2316                 }
2317             }
2318
2319             i += inc;
2320         }
2321     }
2322 }
2323
2324 void split_vsites_over_threads(const t_ilist   *ilist,
2325                                const t_iparams *ip,
2326                                const t_mdatoms *mdatoms,
2327                                gmx_vsite_t     *vsite)
2328 {
2329     int      vsite_atom_range, natperthread;
2330
2331     if (vsite->nthreads == 1)
2332     {
2333         /* Nothing to do */
2334         return;
2335     }
2336
2337     /* The current way of distributing the vsites over threads in primitive.
2338      * We divide the atom range 0 - natoms_in_vsite uniformly over threads,
2339      * without taking into account how the vsites are distributed.
2340      * Without domain decomposition we at least tighten the upper bound
2341      * of the range (useful for common systems such as a vsite-protein
2342      * in 3-site water).
2343      * With domain decomposition, as long as the vsites are distributed
2344      * uniformly in each domain along the major dimension, usually x,
2345      * it will also perform well.
2346      */
2347     if (!vsite->useDomdec)
2348     {
2349         vsite_atom_range = -1;
2350         for (int ftype = c_ftypeVsiteStart; ftype < c_ftypeVsiteEnd; ftype++)
2351         {
2352             {   // TODO remove me
2353                 if (ftype != F_VSITEN)
2354                 {
2355                     int            nral1 = 1 + NRAL(ftype);
2356                     const t_iatom *iat   = ilist[ftype].iatoms;
2357                     for (int i = 0; i < ilist[ftype].nr; i += nral1)
2358                     {
2359                         for (int j = i + 1; j < i + nral1; j++)
2360                         {
2361                             vsite_atom_range = std::max(vsite_atom_range, iat[j]);
2362                         }
2363                     }
2364                 }
2365                 else
2366                 {
2367                     int            vs_ind_end;
2368
2369                     const t_iatom *iat = ilist[ftype].iatoms;
2370
2371                     int            i = 0;
2372                     while (i < ilist[ftype].nr)
2373                     {
2374                         /* The 3 below is from 1+NRAL(ftype)=3 */
2375                         vs_ind_end = i + ip[iat[i]].vsiten.n*3;
2376
2377                         vsite_atom_range = std::max(vsite_atom_range, iat[i+1]);
2378                         while (i < vs_ind_end)
2379                         {
2380                             vsite_atom_range = std::max(vsite_atom_range, iat[i+2]);
2381                             i               += 3;
2382                         }
2383                     }
2384                 }
2385             }
2386         }
2387         vsite_atom_range++;
2388         natperthread     = (vsite_atom_range + vsite->nthreads - 1)/vsite->nthreads;
2389     }
2390     else
2391     {
2392         /* Any local or not local atom could be involved in virtual sites.
2393          * But since we usually have very few non-local virtual sites
2394          * (only non-local vsites that depend on local vsites),
2395          * we distribute the local atom range equally over the threads.
2396          * When assigning vsites to threads, we should take care that the last
2397          * threads also covers the non-local range.
2398          */
2399         vsite_atom_range = mdatoms->nr;
2400         natperthread     = (mdatoms->homenr + vsite->nthreads - 1)/vsite->nthreads;
2401     }
2402
2403     if (debug)
2404     {
2405         fprintf(debug, "virtual site thread dist: natoms %d, range %d, natperthread %d\n", mdatoms->nr, vsite_atom_range, natperthread);
2406     }
2407
2408     /* To simplify the vsite assignment, we make an index which tells us
2409      * to which task particles, both non-vsites and vsites, are assigned.
2410      */
2411     vsite->taskIndex.resize(mdatoms->nr);
2412
2413     /* Initialize the task index array. Here we assign the non-vsite
2414      * particles to task=thread, so we easily figure out if vsites
2415      * depend on local and/or non-local particles in assignVsitesToThread.
2416      */
2417     gmx::ArrayRef<int> taskIndex = vsite->taskIndex;
2418     {
2419         int  thread = 0;
2420         for (int i = 0; i < mdatoms->nr; i++)
2421         {
2422             if (mdatoms->ptype[i] == eptVSite)
2423             {
2424                 /* vsites are not assigned to a task yet */
2425                 taskIndex[i] = -1;
2426             }
2427             else
2428             {
2429                 /* assign non-vsite particles to task thread */
2430                 taskIndex[i] = thread;
2431             }
2432             if (i == (thread + 1)*natperthread && thread < vsite->nthreads)
2433             {
2434                 thread++;
2435             }
2436         }
2437     }
2438
2439 #pragma omp parallel num_threads(vsite->nthreads)
2440     {
2441         try
2442         {
2443             int          thread = gmx_omp_get_thread_num();
2444             VsiteThread &tData  = *vsite->tData[thread];
2445
2446             /* Clear the buffer use flags that were set before */
2447             if (tData.useInterdependentTask)
2448             {
2449                 InterdependentTask &idTask = tData.idTask;
2450
2451                 /* To avoid an extra OpenMP barrier in spread_vsite_f,
2452                  * we clear the force buffer at the next step,
2453                  * so we need to do it here as well.
2454                  */
2455                 clearTaskForceBufferUsedElements(&idTask);
2456
2457                 idTask.vsite.resize(0);
2458                 for (int t = 0; t < vsite->nthreads; t++)
2459                 {
2460                     AtomIndex &atomIndex = idTask.atomIndex[t];
2461                     int        natom     = atomIndex.atom.size();
2462                     for (int i = 0; i < natom; i++)
2463                     {
2464                         idTask.use[atomIndex.atom[i]] = false;
2465                     }
2466                     atomIndex.atom.resize(0);
2467                 }
2468                 idTask.nuse = 0;
2469             }
2470
2471             /* To avoid large f_buf allocations of #threads*vsite_atom_range
2472              * we don't use task2 with more than 200000 atoms. This doesn't
2473              * affect performance, since with such a large range relatively few
2474              * vsites will end up in the separate task.
2475              * Note that useTask2 should be the same for all threads.
2476              */
2477             tData.useInterdependentTask = (vsite_atom_range <= 200000);
2478             if (tData.useInterdependentTask)
2479             {
2480                 size_t              natoms_use_in_vsites = vsite_atom_range;
2481                 InterdependentTask &idTask               = tData.idTask;
2482                 /* To avoid resizing and re-clearing every nstlist steps,
2483                  * we never down size the force buffer.
2484                  */
2485                 if (natoms_use_in_vsites > idTask.force.size() ||
2486                     natoms_use_in_vsites > idTask.use.size())
2487                 {
2488                     idTask.force.resize(natoms_use_in_vsites, { 0, 0, 0 });
2489                     idTask.use.resize(natoms_use_in_vsites, false);
2490                 }
2491             }
2492
2493             /* Assign all vsites that can execute independently on threads */
2494             tData.rangeStart     =  thread     *natperthread;
2495             if (thread < vsite->nthreads - 1)
2496             {
2497                 tData.rangeEnd   = (thread + 1)*natperthread;
2498             }
2499             else
2500             {
2501                 /* The last thread should cover up to the end of the range */
2502                 tData.rangeEnd   = mdatoms->nr;
2503             }
2504             assignVsitesToThread(&tData,
2505                                  thread, vsite->nthreads,
2506                                  natperthread,
2507                                  taskIndex,
2508                                  ilist, ip, mdatoms->ptype);
2509
2510             if (tData.useInterdependentTask)
2511             {
2512                 /* In the worst case, all tasks write to force ranges of
2513                  * all other tasks, leading to #tasks^2 scaling (this is only
2514                  * the overhead, the actual flops remain constant).
2515                  * But in most cases there is far less coupling. To improve
2516                  * scaling at high thread counts we therefore construct
2517                  * an index to only loop over the actually affected tasks.
2518                  */
2519                 InterdependentTask &idTask = tData.idTask;
2520
2521                 /* Ensure assignVsitesToThread finished on other threads */
2522 #pragma omp barrier
2523
2524                 idTask.spreadTask.resize(0);
2525                 idTask.reduceTask.resize(0);
2526                 for (int t = 0; t < vsite->nthreads; t++)
2527                 {
2528                     /* Do we write to the force buffer of task t? */
2529                     if (!idTask.atomIndex[t].atom.empty())
2530                     {
2531                         idTask.spreadTask.push_back(t);
2532                     }
2533                     /* Does task t write to our force buffer? */
2534                     if (!vsite->tData[t]->idTask.atomIndex[thread].atom.empty())
2535                     {
2536                         idTask.reduceTask.push_back(t);
2537                     }
2538                 }
2539             }
2540         }
2541         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
2542     }
2543     /* Assign all remaining vsites, that will have taskIndex[]=2*vsite->nthreads,
2544      * to a single task that will not run in parallel with other tasks.
2545      */
2546     assignVsitesToSingleTask(vsite->tData[vsite->nthreads].get(),
2547                              2*vsite->nthreads,
2548                              taskIndex,
2549                              ilist, ip);
2550
2551     if (debug && vsite->nthreads > 1)
2552     {
2553         fprintf(debug, "virtual site useInterdependentTask %d, nuse:\n",
2554                 static_cast<int>(vsite->tData[0]->useInterdependentTask));
2555         for (int th = 0; th < vsite->nthreads + 1; th++)
2556         {
2557             fprintf(debug, " %4d", vsite->tData[th]->idTask.nuse);
2558         }
2559         fprintf(debug, "\n");
2560
2561         for (int ftype = c_ftypeVsiteStart; ftype < c_ftypeVsiteEnd; ftype++)
2562         {
2563             if (ilist[ftype].nr > 0)
2564             {
2565                 fprintf(debug, "%-20s thread dist:",
2566                         interaction_function[ftype].longname);
2567                 for (int th = 0; th < vsite->nthreads + 1; th++)
2568                 {
2569                     fprintf(debug, " %4d %4d ",
2570                             vsite->tData[th]->ilist[ftype].nr,
2571                             vsite->tData[th]->idTask.ilist[ftype].nr);
2572                 }
2573                 fprintf(debug, "\n");
2574             }
2575         }
2576     }
2577
2578 #ifndef NDEBUG
2579     int nrOrig     = vsiteIlistNrCount(ilist);
2580     int nrThreaded = 0;
2581     for (int th = 0; th < vsite->nthreads + 1; th++)
2582     {
2583         nrThreaded +=
2584             vsiteIlistNrCount(vsite->tData[th]->ilist) +
2585             vsiteIlistNrCount(vsite->tData[th]->idTask.ilist);
2586     }
2587     GMX_ASSERT(nrThreaded == nrOrig, "The number of virtual sites assigned to all thread task has to match the total number of virtual sites");
2588 #endif
2589 }
2590
2591 void set_vsite_top(gmx_vsite_t          *vsite,
2592                    const gmx_localtop_t *top,
2593                    const t_mdatoms      *md)
2594 {
2595     if (vsite->n_intercg_vsite > 0 && vsite->bHaveChargeGroups)
2596     {
2597         vsite->vsite_pbc_loc  = gmx::compat::make_unique<VsitePbc>();
2598         *vsite->vsite_pbc_loc = get_vsite_pbc(top->idef.iparams,
2599                                               top->idef.il, nullptr, md,
2600                                               top->cgs);
2601     }
2602
2603     if (vsite->nthreads > 1)
2604     {
2605         if (vsite->bHaveChargeGroups)
2606         {
2607             gmx_fatal(FARGS, "The combination of threading, virtual sites and charge groups is not implemented");
2608         }
2609
2610         split_vsites_over_threads(top->idef.il, top->idef.iparams,
2611                                   md, vsite);
2612     }
2613 }