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