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