Use std::vector in LINCS
[alexxy/gromacs.git] / src / gromacs / mdlib / lincs.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team.
6  * Copyright (c) 2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
7  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8  * and including many others, as listed in the AUTHORS file in the
9  * top-level source directory and at http://www.gromacs.org.
10  *
11  * GROMACS is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * as published by the Free Software Foundation; either version 2.1
14  * of the License, or (at your option) any later version.
15  *
16  * GROMACS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with GROMACS; if not, see
23  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
25  *
26  * If you want to redistribute modifications to GROMACS, please
27  * consider that scientific software is very special. Version
28  * control is crucial - bugs must be traceable. We will be happy to
29  * consider code for inclusion in the official distribution, but
30  * derived work must not be called official GROMACS. Details are found
31  * in the README & COPYING files - if they are missing, get the
32  * official version at http://www.gromacs.org.
33  *
34  * To help us fund GROMACS development, we humbly ask that you cite
35  * the research papers on the package. Check out http://www.gromacs.org.
36  */
37 /*! \internal \file
38  * \brief Defines LINCS code.
39  *
40  * \author Berk Hess <hess@kth.se>
41  * \author Mark Abraham <mark.j.abraham@gmail.com>
42  * \ingroup module_mdlib
43  */
44 #include "gmxpre.h"
45
46 #include "lincs.h"
47
48 #include "config.h"
49
50 #include <cassert>
51 #include <cmath>
52 #include <cstdlib>
53
54 #include <algorithm>
55 #include <vector>
56
57 #include "gromacs/domdec/domdec.h"
58 #include "gromacs/domdec/domdec_struct.h"
59 #include "gromacs/gmxlib/nrnb.h"
60 #include "gromacs/math/functions.h"
61 #include "gromacs/math/paddedvector.h"
62 #include "gromacs/math/units.h"
63 #include "gromacs/math/vec.h"
64 #include "gromacs/mdlib/constr.h"
65 #include "gromacs/mdlib/gmx_omp_nthreads.h"
66 #include "gromacs/mdlib/mdrun.h"
67 #include "gromacs/mdtypes/commrec.h"
68 #include "gromacs/mdtypes/inputrec.h"
69 #include "gromacs/mdtypes/md_enums.h"
70 #include "gromacs/mdtypes/mdatom.h"
71 #include "gromacs/pbcutil/pbc.h"
72 #include "gromacs/pbcutil/pbc-simd.h"
73 #include "gromacs/simd/simd.h"
74 #include "gromacs/simd/simd_math.h"
75 #include "gromacs/simd/vector_operations.h"
76 #include "gromacs/topology/block.h"
77 #include "gromacs/topology/mtop_util.h"
78 #include "gromacs/utility/alignedallocator.h"
79 #include "gromacs/utility/arrayref.h"
80 #include "gromacs/utility/basedefinitions.h"
81 #include "gromacs/utility/bitmask.h"
82 #include "gromacs/utility/cstringutil.h"
83 #include "gromacs/utility/exceptions.h"
84 #include "gromacs/utility/fatalerror.h"
85 #include "gromacs/utility/gmxomp.h"
86 #include "gromacs/utility/pleasecite.h"
87
88 using namespace gmx; // TODO: Remove when this file is moved into gmx namespace
89
90 namespace gmx
91 {
92
93 //! Unit of work within LINCS.
94 struct Task
95 {
96     //! First constraint for this task.
97     int              b0 = 0;
98     //! b1-1 is the last constraint for this task.
99     int              b1 = 0;
100     //! The number of constraints in triangles.
101     int              ntriangle = 0;
102     //! The list of triangle constraints.
103     std::vector<int> triangle;
104     //! The bits tell if the matrix element should be used.
105     std::vector<int> tri_bits;
106     //! Constraint index for updating atom data.
107     std::vector<int> ind;
108     //! Constraint index for updating atom data.
109     std::vector<int> ind_r;
110     //! Temporary variable for virial calculation.
111     tensor           vir_r_m_dr = {{0}};
112     //! Temporary variable for lambda derivative.
113     real             dhdlambda;
114 };
115
116 /*! \brief Data for LINCS algorithm.
117  */
118 class Lincs
119 {
120     public:
121         //! The global number of constraints.
122         int             ncg = 0;
123         //! The global number of flexible constraints.
124         int             ncg_flex = 0;
125         //! The global number of constraints in triangles.
126         int             ncg_triangle = 0;
127         //! The number of iterations.
128         int             nIter = 0;
129         //! The order of the matrix expansion.
130         int             nOrder = 0;
131         //! The maximum number of constraints connected to a single atom.
132         int             max_connect = 0;
133
134         //! The number of real constraints.
135         int              nc_real = 0;
136         //! The number of constraints including padding for SIMD.
137         int              nc = 0;
138         //! The number of constraint connections.
139         int              ncc = 0;
140         //! The FE lambda value used for filling blc and blmf.
141         real             matlam = 0;
142         //! mapping from topology to LINCS constraints.
143         std::vector<int> con_index;
144         //! The reference distance in topology A.
145         std::vector < real, AlignedAllocator < real>> bllen0;
146         //! The reference distance in top B - the r.d. in top A.
147         std::vector < real, AlignedAllocator < real>> ddist;
148         //! The atom pairs involved in the constraints.
149         std::vector<int> bla;
150         //! 1/sqrt(invmass1  invmass2).
151         std::vector < real, AlignedAllocator < real>> blc;
152         //! As blc, but with all masses 1.
153         std::vector < real, AlignedAllocator < real>> blc1;
154         //! Index into blbnb and blmf.
155         std::vector<int>  blnr;
156         //! List of constraint connections.
157         std::vector<int>  blbnb;
158         //! The local number of constraints in triangles.
159         int               ntriangle = 0;
160         //! The number of constraint connections in triangles.
161         int               ncc_triangle = 0;
162         //! Communicate before each LINCS interation.
163         bool              bCommIter = false;
164         //! Matrix of mass factors for constraint connections.
165         std::vector<real> blmf;
166         //! As blmf, but with all masses 1.
167         std::vector<real> blmf1;
168         //! The reference bond length.
169         std::vector < real, AlignedAllocator < real>> bllen;
170         //! The local atom count per constraint, can be NULL.
171         std::vector<int>  nlocat;
172
173         /*! \brief The number of tasks used for LINCS work.
174          *
175          * \todo This is mostly used to loop over \c task, which would
176          * be nicer to do with range-based for loops, but the thread
177          * index is used for constructing bit masks and organizing the
178          * virial output buffer, so other things need to change,
179          * first. */
180         int                        ntask = 0;
181         /*! \brief LINCS thread division */
182         std::vector<Task>          task;
183         //! Atom flags for thread parallelization.
184         std::vector<gmx_bitmask_t> atf;
185         //! Are the LINCS tasks interdependent?
186         bool                       bTaskDep = false;
187         //! Are there triangle constraints that cross task borders?
188         bool                       bTaskDepTri = false;
189         //! Arrays for temporary storage in the LINCS algorithm.
190         /*! @{ */
191         PaddedVector<gmx::RVec>                   tmpv;
192         std::vector<real>                         tmpncc;
193         std::vector < real, AlignedAllocator < real>> tmp1;
194         std::vector < real, AlignedAllocator < real>> tmp2;
195         std::vector < real, AlignedAllocator < real>> tmp3;
196         std::vector < real, AlignedAllocator < real>> tmp4;
197         /*! @} */
198         //! The Lagrange multipliers times -1.
199         std::vector < real, AlignedAllocator < real>> mlambda;
200         //! Storage for the constraint RMS relative deviation output.
201         std::array<real, 2> rmsdData = {{0}};
202 };
203
204 /*! \brief Define simd_width for memory allocation used for SIMD code */
205 #if GMX_SIMD_HAVE_REAL
206 static const int simd_width = GMX_SIMD_REAL_WIDTH;
207 #else
208 static const int simd_width = 1;
209 #endif
210
211 ArrayRef<real> lincs_rmsdData(Lincs *lincsd)
212 {
213     return lincsd->rmsdData;
214 }
215
216 real lincs_rmsd(const Lincs *lincsd)
217 {
218     if (lincsd->rmsdData[0] > 0)
219     {
220         return std::sqrt(lincsd->rmsdData[1]/lincsd->rmsdData[0]);
221     }
222     else
223     {
224         return 0;
225     }
226 }
227
228 /*! \brief Do a set of nrec LINCS matrix multiplications.
229  *
230  * This function will return with up to date thread-local
231  * constraint data, without an OpenMP barrier.
232  */
233 static void lincs_matrix_expand(const Lincs *lincsd,
234                                 const Task *li_task,
235                                 const real *blcc,
236                                 real *rhs1, real *rhs2, real *sol)
237 {
238     gmx::ArrayRef<const int> blnr  = lincsd->blnr;
239     gmx::ArrayRef<const int> blbnb = lincsd->blbnb;
240
241     const int                b0   = li_task->b0;
242     const int                b1   = li_task->b1;
243     const int                nrec = lincsd->nOrder;
244
245     for (int rec = 0; rec < nrec; rec++)
246     {
247         if (lincsd->bTaskDep)
248         {
249 #pragma omp barrier
250         }
251         for (int b = b0; b < b1; b++)
252         {
253             real mvb;
254             int  n;
255
256             mvb = 0;
257             for (n = blnr[b]; n < blnr[b+1]; n++)
258             {
259                 mvb = mvb + blcc[n]*rhs1[blbnb[n]];
260             }
261             rhs2[b] = mvb;
262             sol[b]  = sol[b] + mvb;
263         }
264
265         real *swap;
266
267         swap = rhs1;
268         rhs1 = rhs2;
269         rhs2 = swap;
270     }   /* nrec*(ncons+2*nrtot) flops */
271
272     if (lincsd->ntriangle > 0)
273     {
274         /* Perform an extra nrec recursions for only the constraints
275          * involved in rigid triangles.
276          * In this way their accuracy should come close to those of the other
277          * constraints, since traingles of constraints can produce eigenvalues
278          * around 0.7, while the effective eigenvalue for bond constraints
279          * is around 0.4 (and 0.7*0.7=0.5).
280          */
281
282         if (lincsd->bTaskDep)
283         {
284             /* We need a barrier here, since other threads might still be
285              * reading the contents of rhs1 and/o rhs2.
286              * We could avoid this barrier by introducing two extra rhs
287              * arrays for the triangle constraints only.
288              */
289 #pragma omp barrier
290         }
291
292         /* Constraints involved in a triangle are ensured to be in the same
293          * LINCS task. This means no barriers are required during the extra
294          * iterations for the triangle constraints.
295          */
296         gmx::ArrayRef<const int> triangle = li_task->triangle;
297         gmx::ArrayRef<const int> tri_bits = li_task->tri_bits;
298
299         for (int rec = 0; rec < nrec; rec++)
300         {
301             for (int tb = 0; tb < li_task->ntriangle; tb++)
302             {
303                 int  b, bits, nr0, nr1, n;
304                 real mvb;
305
306                 b    = triangle[tb];
307                 bits = tri_bits[tb];
308                 mvb  = 0;
309                 nr0  = blnr[b];
310                 nr1  = blnr[b+1];
311                 for (n = nr0; n < nr1; n++)
312                 {
313                     if (bits & (1 << (n - nr0)))
314                     {
315                         mvb = mvb + blcc[n]*rhs1[blbnb[n]];
316                     }
317                 }
318                 rhs2[b] = mvb;
319                 sol[b]  = sol[b] + mvb;
320             }
321
322             real *swap;
323
324             swap = rhs1;
325             rhs1 = rhs2;
326             rhs2 = swap;
327         }   /* nrec*(ntriangle + ncc_triangle*2) flops */
328
329         if (lincsd->bTaskDepTri)
330         {
331             /* The constraints triangles are decoupled from each other,
332              * but constraints in one triangle cross thread task borders.
333              * We could probably avoid this with more advanced setup code.
334              */
335 #pragma omp barrier
336         }
337     }
338 }
339
340 //! Update atomic coordinates when an index is not required.
341 static void lincs_update_atoms_noind(int ncons,
342                                      gmx::ArrayRef<const int> bla,
343                                      real prefac,
344                                      const real *fac, rvec *r,
345                                      const real *invmass,
346                                      rvec *x)
347 {
348     int  b, i, j;
349     real mvb, im1, im2, tmp0, tmp1, tmp2;
350
351     if (invmass != nullptr)
352     {
353         for (b = 0; b < ncons; b++)
354         {
355             i        = bla[2*b];
356             j        = bla[2*b+1];
357             mvb      = prefac*fac[b];
358             im1      = invmass[i];
359             im2      = invmass[j];
360             tmp0     = r[b][0]*mvb;
361             tmp1     = r[b][1]*mvb;
362             tmp2     = r[b][2]*mvb;
363             x[i][0] -= tmp0*im1;
364             x[i][1] -= tmp1*im1;
365             x[i][2] -= tmp2*im1;
366             x[j][0] += tmp0*im2;
367             x[j][1] += tmp1*im2;
368             x[j][2] += tmp2*im2;
369         }   /* 16 ncons flops */
370     }
371     else
372     {
373         for (b = 0; b < ncons; b++)
374         {
375             i        = bla[2*b];
376             j        = bla[2*b+1];
377             mvb      = prefac*fac[b];
378             tmp0     = r[b][0]*mvb;
379             tmp1     = r[b][1]*mvb;
380             tmp2     = r[b][2]*mvb;
381             x[i][0] -= tmp0;
382             x[i][1] -= tmp1;
383             x[i][2] -= tmp2;
384             x[j][0] += tmp0;
385             x[j][1] += tmp1;
386             x[j][2] += tmp2;
387         }
388     }
389 }
390
391 //! Update atomic coordinates when an index is required.
392 static void lincs_update_atoms_ind(gmx::ArrayRef<const int> ind,
393                                    gmx::ArrayRef<const int> bla,
394                                    real prefac,
395                                    const real *fac, rvec *r,
396                                    const real *invmass,
397                                    rvec *x)
398 {
399     int  i, j;
400     real mvb, im1, im2, tmp0, tmp1, tmp2;
401
402     if (invmass != nullptr)
403     {
404         for (int b : ind)
405         {
406             i        = bla[2*b];
407             j        = bla[2*b+1];
408             mvb      = prefac*fac[b];
409             im1      = invmass[i];
410             im2      = invmass[j];
411             tmp0     = r[b][0]*mvb;
412             tmp1     = r[b][1]*mvb;
413             tmp2     = r[b][2]*mvb;
414             x[i][0] -= tmp0*im1;
415             x[i][1] -= tmp1*im1;
416             x[i][2] -= tmp2*im1;
417             x[j][0] += tmp0*im2;
418             x[j][1] += tmp1*im2;
419             x[j][2] += tmp2*im2;
420         }   /* 16 ncons flops */
421     }
422     else
423     {
424         for (int b : ind)
425         {
426             i        = bla[2*b];
427             j        = bla[2*b+1];
428             mvb      = prefac*fac[b];
429             tmp0     = r[b][0]*mvb;
430             tmp1     = r[b][1]*mvb;
431             tmp2     = r[b][2]*mvb;
432             x[i][0] -= tmp0;
433             x[i][1] -= tmp1;
434             x[i][2] -= tmp2;
435             x[j][0] += tmp0;
436             x[j][1] += tmp1;
437             x[j][2] += tmp2;
438         }   /* 16 ncons flops */
439     }
440 }
441
442 //! Update coordinates for atoms.
443 static void lincs_update_atoms(Lincs *li, int th,
444                                real prefac,
445                                const real *fac, rvec *r,
446                                const real *invmass,
447                                rvec *x)
448 {
449     if (li->ntask == 1)
450     {
451         /* Single thread, we simply update for all constraints */
452         lincs_update_atoms_noind(li->nc_real,
453                                  li->bla, prefac, fac, r, invmass, x);
454     }
455     else
456     {
457         /* Update the atom vector components for our thread local
458          * constraints that only access our local atom range.
459          * This can be done without a barrier.
460          */
461         lincs_update_atoms_ind(li->task[th].ind,
462                                li->bla, prefac, fac, r, invmass, x);
463
464         if (!li->task[li->ntask].ind.empty())
465         {
466             /* Update the constraints that operate on atoms
467              * in multiple thread atom blocks on the master thread.
468              */
469 #pragma omp barrier
470 #pragma omp master
471             {
472                 lincs_update_atoms_ind(li->task[li->ntask].ind,
473                                        li->bla, prefac, fac, r, invmass, x);
474             }
475         }
476     }
477 }
478
479 #if GMX_SIMD_HAVE_REAL
480 //! Helper function so that we can run TSAN with SIMD support (where implemented).
481 template <int align>
482 static inline void gmx_simdcall
483 gatherLoadUTransposeTSANSafe(const real         *base,
484                              const std::int32_t *offset,
485                              SimdReal           *v0,
486                              SimdReal           *v1,
487                              SimdReal           *v2)
488 {
489 #if (CMAKE_BUILD_TYPE == CMAKE_BUILD_TYPE_TSAN) && GMX_SIMD_X86_AVX2_256
490     // This function is only implemented in this case
491     gatherLoadUTransposeSafe<align>(base, offset, v0, v1, v2);
492 #else
493     gatherLoadUTranspose<align>(base, offset, v0, v1, v2);
494 #endif
495 }
496
497 /*! \brief Calculate the constraint distance vectors r to project on from x.
498  *
499  * Determine the right-hand side of the matrix equation using quantity f.
500  * This function only differs from calc_dr_x_xp_simd below in that
501  * no constraint length is subtracted and no PBC is used for f. */
502 static void gmx_simdcall
503 calc_dr_x_f_simd(int                       b0,
504                  int                       b1,
505                  const int *               bla,
506                  const rvec * gmx_restrict x,
507                  const rvec * gmx_restrict f,
508                  const real * gmx_restrict blc,
509                  const real *              pbc_simd,
510                  rvec * gmx_restrict       r,
511                  real * gmx_restrict       rhs,
512                  real * gmx_restrict       sol)
513 {
514     assert(b0 % GMX_SIMD_REAL_WIDTH == 0);
515
516     alignas(GMX_SIMD_ALIGNMENT) std::int32_t offset2[GMX_SIMD_REAL_WIDTH];
517
518     for (int i = 0; i < GMX_SIMD_REAL_WIDTH; i++)
519     {
520         offset2[i] = i;
521     }
522
523     for (int bs = b0; bs < b1; bs += GMX_SIMD_REAL_WIDTH)
524     {
525         SimdReal x0_S, y0_S, z0_S;
526         SimdReal x1_S, y1_S, z1_S;
527         SimdReal rx_S, ry_S, rz_S, n2_S, il_S;
528         SimdReal fx_S, fy_S, fz_S, ip_S, rhs_S;
529         alignas(GMX_SIMD_ALIGNMENT) std::int32_t      offset0[GMX_SIMD_REAL_WIDTH];
530         alignas(GMX_SIMD_ALIGNMENT) std::int32_t      offset1[GMX_SIMD_REAL_WIDTH];
531
532         for (int i = 0; i < GMX_SIMD_REAL_WIDTH; i++)
533         {
534             offset0[i] = bla[bs*2 + i*2];
535             offset1[i] = bla[bs*2 + i*2 + 1];
536         }
537
538         gatherLoadUTransposeTSANSafe<3>(reinterpret_cast<const real *>(x), offset0, &x0_S, &y0_S, &z0_S);
539         gatherLoadUTransposeTSANSafe<3>(reinterpret_cast<const real *>(x), offset1, &x1_S, &y1_S, &z1_S);
540         rx_S = x0_S - x1_S;
541         ry_S = y0_S - y1_S;
542         rz_S = z0_S - z1_S;
543
544         pbc_correct_dx_simd(&rx_S, &ry_S, &rz_S, pbc_simd);
545
546         n2_S  = norm2(rx_S, ry_S, rz_S);
547         il_S  = invsqrt(n2_S);
548
549         rx_S  = rx_S * il_S;
550         ry_S  = ry_S * il_S;
551         rz_S  = rz_S * il_S;
552
553         transposeScatterStoreU<3>(reinterpret_cast<real *>(r + bs), offset2, rx_S, ry_S, rz_S);
554
555         gatherLoadUTransposeTSANSafe<3>(reinterpret_cast<const real *>(f), offset0, &x0_S, &y0_S, &z0_S);
556         gatherLoadUTransposeTSANSafe<3>(reinterpret_cast<const real *>(f), offset1, &x1_S, &y1_S, &z1_S);
557         fx_S = x0_S - x1_S;
558         fy_S = y0_S - y1_S;
559         fz_S = z0_S - z1_S;
560
561         ip_S  = iprod(rx_S, ry_S, rz_S, fx_S, fy_S, fz_S);
562
563         rhs_S = load<SimdReal>(blc + bs) * ip_S;
564
565         store(rhs + bs, rhs_S);
566         store(sol + bs, rhs_S);
567     }
568 }
569 #endif // GMX_SIMD_HAVE_REAL
570
571 /*! \brief LINCS projection, works on derivatives of the coordinates. */
572 static void do_lincsp(const rvec *x, rvec *f, rvec *fp, t_pbc *pbc,
573                       Lincs *lincsd, int th,
574                       real *invmass,
575                       ConstraintVariable econq, bool bCalcDHDL,
576                       bool bCalcVir, tensor rmdf)
577 {
578     int      b0, b1, b;
579     int     *bla, *blnr, *blbnb;
580     rvec    *r;
581     real    *blc, *blmf, *blcc, *rhs1, *rhs2, *sol;
582
583     b0 = lincsd->task[th].b0;
584     b1 = lincsd->task[th].b1;
585
586     bla    = lincsd->bla.data();
587     r      = as_rvec_array(lincsd->tmpv.data());
588     blnr   = lincsd->blnr.data();
589     blbnb  = lincsd->blbnb.data();
590     if (econq != ConstraintVariable::Force)
591     {
592         /* Use mass-weighted parameters */
593         blc  = lincsd->blc.data();
594         blmf = lincsd->blmf.data();
595     }
596     else
597     {
598         /* Use non mass-weighted parameters */
599         blc  = lincsd->blc1.data();
600         blmf = lincsd->blmf1.data();
601     }
602     blcc   = lincsd->tmpncc.data();
603     rhs1   = lincsd->tmp1.data();
604     rhs2   = lincsd->tmp2.data();
605     sol    = lincsd->tmp3.data();
606
607 #if GMX_SIMD_HAVE_REAL
608     /* This SIMD code does the same as the plain-C code after the #else.
609      * The only difference is that we always call pbc code, as with SIMD
610      * the overhead of pbc computation (when not needed) is small.
611      */
612     alignas(GMX_SIMD_ALIGNMENT) real    pbc_simd[9*GMX_SIMD_REAL_WIDTH];
613
614     /* Convert the pbc struct for SIMD */
615     set_pbc_simd(pbc, pbc_simd);
616
617     /* Compute normalized x i-j vectors, store in r.
618      * Compute the inner product of r and xp i-j and store in rhs1.
619      */
620     calc_dr_x_f_simd(b0, b1, bla, x, f, blc,
621                      pbc_simd,
622                      r, rhs1, sol);
623
624 #else   // GMX_SIMD_HAVE_REAL
625
626     /* Compute normalized i-j vectors */
627     if (pbc)
628     {
629         for (b = b0; b < b1; b++)
630         {
631             rvec dx;
632
633             pbc_dx_aiuc(pbc, x[bla[2*b]], x[bla[2*b+1]], dx);
634             unitv(dx, r[b]);
635         }
636     }
637     else
638     {
639         for (b = b0; b < b1; b++)
640         {
641             rvec dx;
642
643             rvec_sub(x[bla[2*b]], x[bla[2*b+1]], dx);
644             unitv(dx, r[b]);
645         }   /* 16 ncons flops */
646     }
647
648     for (b = b0; b < b1; b++)
649     {
650         int  i, j;
651         real mvb;
652
653         i       = bla[2*b];
654         j       = bla[2*b+1];
655         mvb     = blc[b]*(r[b][0]*(f[i][0] - f[j][0]) +
656                           r[b][1]*(f[i][1] - f[j][1]) +
657                           r[b][2]*(f[i][2] - f[j][2]));
658         rhs1[b] = mvb;
659         sol[b]  = mvb;
660         /* 7 flops */
661     }
662
663 #endif  // GMX_SIMD_HAVE_REAL
664
665     if (lincsd->bTaskDep)
666     {
667         /* We need a barrier, since the matrix construction below
668          * can access entries in r of other threads.
669          */
670 #pragma omp barrier
671     }
672
673     /* Construct the (sparse) LINCS matrix */
674     for (b = b0; b < b1; b++)
675     {
676         int n;
677
678         for (n = blnr[b]; n < blnr[b+1]; n++)
679         {
680             blcc[n] = blmf[n]*::iprod(r[b], r[blbnb[n]]);
681         }   /* 6 nr flops */
682     }
683     /* Together: 23*ncons + 6*nrtot flops */
684
685     lincs_matrix_expand(lincsd, &lincsd->task[th], blcc, rhs1, rhs2, sol);
686     /* nrec*(ncons+2*nrtot) flops */
687
688     if (econq == ConstraintVariable::Deriv_FlexCon)
689     {
690         /* We only want to constraint the flexible constraints,
691          * so we mask out the normal ones by setting sol to 0.
692          */
693         for (b = b0; b < b1; b++)
694         {
695             if (!(lincsd->bllen0[b] == 0 && lincsd->ddist[b] == 0))
696             {
697                 sol[b] = 0;
698             }
699         }
700     }
701
702     /* We multiply sol by blc, so we can use lincs_update_atoms for OpenMP */
703     for (b = b0; b < b1; b++)
704     {
705         sol[b] *= blc[b];
706     }
707
708     /* When constraining forces, we should not use mass weighting,
709      * so we pass invmass=NULL, which results in the use of 1 for all atoms.
710      */
711     lincs_update_atoms(lincsd, th, 1.0, sol, r,
712                        (econq != ConstraintVariable::Force) ? invmass : nullptr, fp);
713
714     if (bCalcDHDL)
715     {
716         real dhdlambda;
717
718         dhdlambda = 0;
719         for (b = b0; b < b1; b++)
720         {
721             dhdlambda -= sol[b]*lincsd->ddist[b];
722         }
723
724         lincsd->task[th].dhdlambda = dhdlambda;
725     }
726
727     if (bCalcVir)
728     {
729         /* Constraint virial,
730          * determines sum r_bond x delta f,
731          * where delta f is the constraint correction
732          * of the quantity that is being constrained.
733          */
734         for (b = b0; b < b1; b++)
735         {
736             real mvb, tmp1;
737             int  i, j;
738
739             mvb = lincsd->bllen[b]*sol[b];
740             for (i = 0; i < DIM; i++)
741             {
742                 tmp1 = mvb*r[b][i];
743                 for (j = 0; j < DIM; j++)
744                 {
745                     rmdf[i][j] += tmp1*r[b][j];
746                 }
747             }
748         }   /* 23 ncons flops */
749     }
750 }
751
752 #if GMX_SIMD_HAVE_REAL
753
754 /*! \brief Calculate the constraint distance vectors r to project on from x.
755  *
756  * Determine the right-hand side of the matrix equation using coordinates xp. */
757 static void gmx_simdcall
758 calc_dr_x_xp_simd(int                       b0,
759                   int                       b1,
760                   const int *               bla,
761                   const rvec * gmx_restrict x,
762                   const rvec * gmx_restrict xp,
763                   const real * gmx_restrict bllen,
764                   const real * gmx_restrict blc,
765                   const real *              pbc_simd,
766                   rvec * gmx_restrict       r,
767                   real * gmx_restrict       rhs,
768                   real * gmx_restrict       sol)
769 {
770     assert(b0 % GMX_SIMD_REAL_WIDTH == 0);
771     alignas(GMX_SIMD_ALIGNMENT) std::int32_t offset2[GMX_SIMD_REAL_WIDTH];
772
773     for (int i = 0; i < GMX_SIMD_REAL_WIDTH; i++)
774     {
775         offset2[i] = i;
776     }
777
778     for (int bs = b0; bs < b1; bs += GMX_SIMD_REAL_WIDTH)
779     {
780         SimdReal x0_S, y0_S, z0_S;
781         SimdReal x1_S, y1_S, z1_S;
782         SimdReal rx_S, ry_S, rz_S, n2_S, il_S;
783         SimdReal rxp_S, ryp_S, rzp_S, ip_S, rhs_S;
784         alignas(GMX_SIMD_ALIGNMENT) std::int32_t      offset0[GMX_SIMD_REAL_WIDTH];
785         alignas(GMX_SIMD_ALIGNMENT) std::int32_t      offset1[GMX_SIMD_REAL_WIDTH];
786
787         for (int i = 0; i < GMX_SIMD_REAL_WIDTH; i++)
788         {
789             offset0[i] = bla[bs*2 + i*2];
790             offset1[i] = bla[bs*2 + i*2 + 1];
791         }
792
793         gatherLoadUTransposeTSANSafe<3>(reinterpret_cast<const real *>(x), offset0, &x0_S, &y0_S, &z0_S);
794         gatherLoadUTransposeTSANSafe<3>(reinterpret_cast<const real *>(x), offset1, &x1_S, &y1_S, &z1_S);
795         rx_S = x0_S - x1_S;
796         ry_S = y0_S - y1_S;
797         rz_S = z0_S - z1_S;
798
799         pbc_correct_dx_simd(&rx_S, &ry_S, &rz_S, pbc_simd);
800
801         n2_S  = norm2(rx_S, ry_S, rz_S);
802         il_S  = invsqrt(n2_S);
803
804         rx_S  = rx_S * il_S;
805         ry_S  = ry_S * il_S;
806         rz_S  = rz_S * il_S;
807
808         transposeScatterStoreU<3>(reinterpret_cast<real *>(r + bs), offset2, rx_S, ry_S, rz_S);
809
810         gatherLoadUTransposeTSANSafe<3>(reinterpret_cast<const real *>(xp), offset0, &x0_S, &y0_S, &z0_S);
811         gatherLoadUTransposeTSANSafe<3>(reinterpret_cast<const real *>(xp), offset1, &x1_S, &y1_S, &z1_S);
812
813         rxp_S = x0_S - x1_S;
814         ryp_S = y0_S - y1_S;
815         rzp_S = z0_S - z1_S;
816
817         pbc_correct_dx_simd(&rxp_S, &ryp_S, &rzp_S, pbc_simd);
818
819         ip_S  = iprod(rx_S, ry_S, rz_S, rxp_S, ryp_S, rzp_S);
820
821         rhs_S = load<SimdReal>(blc + bs) * (ip_S - load<SimdReal>(bllen + bs));
822
823         store(rhs + bs, rhs_S);
824         store(sol + bs, rhs_S);
825     }
826 }
827 #endif // GMX_SIMD_HAVE_REAL
828
829 /*! \brief Determine the distances and right-hand side for the next iteration. */
830 gmx_unused static void calc_dist_iter(
831         int                       b0,
832         int                       b1,
833         const int *               bla,
834         const rvec * gmx_restrict xp,
835         const real * gmx_restrict bllen,
836         const real * gmx_restrict blc,
837         const t_pbc *             pbc,
838         real                      wfac,
839         real * gmx_restrict       rhs,
840         real * gmx_restrict       sol,
841         bool *                    bWarn)
842 {
843     int b;
844
845     for (b = b0; b < b1; b++)
846     {
847         real len, len2, dlen2, mvb;
848         rvec dx;
849
850         len = bllen[b];
851         if (pbc)
852         {
853             pbc_dx_aiuc(pbc, xp[bla[2*b]], xp[bla[2*b+1]], dx);
854         }
855         else
856         {
857             rvec_sub(xp[bla[2*b]], xp[bla[2*b+1]], dx);
858         }
859         len2  = len*len;
860         dlen2 = 2*len2 - ::norm2(dx);
861         if (dlen2 < wfac*len2)
862         {
863             /* not race free - see detailed comment in caller */
864             *bWarn = TRUE;
865         }
866         if (dlen2 > 0)
867         {
868             mvb = blc[b]*(len - dlen2*gmx::invsqrt(dlen2));
869         }
870         else
871         {
872             mvb = blc[b]*len;
873         }
874         rhs[b]  = mvb;
875         sol[b]  = mvb;
876     }   /* 20*ncons flops */
877 }
878
879 #if GMX_SIMD_HAVE_REAL
880 /*! \brief As calc_dist_iter(), but using SIMD intrinsics. */
881 static void gmx_simdcall
882 calc_dist_iter_simd(int                       b0,
883                     int                       b1,
884                     const int *               bla,
885                     const rvec * gmx_restrict x,
886                     const real * gmx_restrict bllen,
887                     const real * gmx_restrict blc,
888                     const real *              pbc_simd,
889                     real                      wfac,
890                     real * gmx_restrict       rhs,
891                     real * gmx_restrict       sol,
892                     bool *                    bWarn)
893 {
894     SimdReal        min_S(GMX_REAL_MIN);
895     SimdReal        two_S(2.0);
896     SimdReal        wfac_S(wfac);
897     SimdBool        warn_S;
898
899     int             bs;
900
901     assert(b0 % GMX_SIMD_REAL_WIDTH == 0);
902
903     /* Initialize all to FALSE */
904     warn_S = (two_S < setZero());
905
906     for (bs = b0; bs < b1; bs += GMX_SIMD_REAL_WIDTH)
907     {
908         SimdReal x0_S, y0_S, z0_S;
909         SimdReal x1_S, y1_S, z1_S;
910         SimdReal rx_S, ry_S, rz_S, n2_S;
911         SimdReal len_S, len2_S, dlen2_S, lc_S, blc_S;
912         alignas(GMX_SIMD_ALIGNMENT) std::int32_t      offset0[GMX_SIMD_REAL_WIDTH];
913         alignas(GMX_SIMD_ALIGNMENT) std::int32_t      offset1[GMX_SIMD_REAL_WIDTH];
914
915         for (int i = 0; i < GMX_SIMD_REAL_WIDTH; i++)
916         {
917             offset0[i] = bla[bs*2 + i*2];
918             offset1[i] = bla[bs*2 + i*2 + 1];
919         }
920
921         gatherLoadUTransposeTSANSafe<3>(reinterpret_cast<const real *>(x), offset0, &x0_S, &y0_S, &z0_S);
922         gatherLoadUTransposeTSANSafe<3>(reinterpret_cast<const real *>(x), offset1, &x1_S, &y1_S, &z1_S);
923
924         rx_S = x0_S - x1_S;
925         ry_S = y0_S - y1_S;
926         rz_S = z0_S - z1_S;
927
928         pbc_correct_dx_simd(&rx_S, &ry_S, &rz_S, pbc_simd);
929
930         n2_S    = norm2(rx_S, ry_S, rz_S);
931
932         len_S   = load<SimdReal>(bllen + bs);
933         len2_S  = len_S * len_S;
934
935         dlen2_S = fms(two_S, len2_S, n2_S);
936
937         warn_S  = warn_S || (dlen2_S < (wfac_S * len2_S));
938
939         /* Avoid 1/0 by taking the max with REAL_MIN.
940          * Note: when dlen2 is close to zero (90 degree constraint rotation),
941          * the accuracy of the algorithm is no longer relevant.
942          */
943         dlen2_S = max(dlen2_S, min_S);
944
945         lc_S    = fnma(dlen2_S, invsqrt(dlen2_S), len_S);
946
947         blc_S   = load<SimdReal>(blc + bs);
948
949         lc_S    = blc_S * lc_S;
950
951         store(rhs + bs, lc_S);
952         store(sol + bs, lc_S);
953     }
954
955     if (anyTrue(warn_S))
956     {
957         *bWarn = TRUE;
958     }
959 }
960 #endif // GMX_SIMD_HAVE_REAL
961
962 //! Implements LINCS constraining.
963 static void do_lincs(const rvec *x, rvec *xp, matrix box, t_pbc *pbc,
964                      Lincs *lincsd, int th,
965                      const real *invmass,
966                      const t_commrec *cr,
967                      bool bCalcDHDL,
968                      real wangle, bool *bWarn,
969                      real invdt, rvec * gmx_restrict v,
970                      bool bCalcVir, tensor vir_r_m_dr)
971 {
972     int      b0, b1, b, i, j, n, iter;
973     int     *bla, *blnr, *blbnb;
974     rvec    *r;
975     real    *blc, *blmf, *bllen, *blcc, *rhs1, *rhs2, *sol, *blc_sol, *mlambda;
976     int     *nlocat;
977
978     b0 = lincsd->task[th].b0;
979     b1 = lincsd->task[th].b1;
980
981     bla     = lincsd->bla.data();
982     r       = as_rvec_array(lincsd->tmpv.data());
983     blnr    = lincsd->blnr.data();
984     blbnb   = lincsd->blbnb.data();
985     blc     = lincsd->blc.data();
986     blmf    = lincsd->blmf.data();
987     bllen   = lincsd->bllen.data();
988     blcc    = lincsd->tmpncc.data();
989     rhs1    = lincsd->tmp1.data();
990     rhs2    = lincsd->tmp2.data();
991     sol     = lincsd->tmp3.data();
992     blc_sol = lincsd->tmp4.data();
993     mlambda = lincsd->mlambda.data();
994     nlocat  = lincsd->nlocat.data();
995
996 #if GMX_SIMD_HAVE_REAL
997
998     /* This SIMD code does the same as the plain-C code after the #else.
999      * The only difference is that we always call pbc code, as with SIMD
1000      * the overhead of pbc computation (when not needed) is small.
1001      */
1002     alignas(GMX_SIMD_ALIGNMENT) real    pbc_simd[9*GMX_SIMD_REAL_WIDTH];
1003
1004     /* Convert the pbc struct for SIMD */
1005     set_pbc_simd(pbc, pbc_simd);
1006
1007     /* Compute normalized x i-j vectors, store in r.
1008      * Compute the inner product of r and xp i-j and store in rhs1.
1009      */
1010     calc_dr_x_xp_simd(b0, b1, bla, x, xp, bllen, blc,
1011                       pbc_simd,
1012                       r, rhs1, sol);
1013
1014 #else   // GMX_SIMD_HAVE_REAL
1015
1016     if (pbc)
1017     {
1018         /* Compute normalized i-j vectors */
1019         for (b = b0; b < b1; b++)
1020         {
1021             rvec dx;
1022             real mvb;
1023
1024             pbc_dx_aiuc(pbc, x[bla[2*b]], x[bla[2*b+1]], dx);
1025             unitv(dx, r[b]);
1026
1027             pbc_dx_aiuc(pbc, xp[bla[2*b]], xp[bla[2*b+1]], dx);
1028             mvb     = blc[b]*(::iprod(r[b], dx) - bllen[b]);
1029             rhs1[b] = mvb;
1030             sol[b]  = mvb;
1031         }
1032     }
1033     else
1034     {
1035         /* Compute normalized i-j vectors */
1036         for (b = b0; b < b1; b++)
1037         {
1038             real tmp0, tmp1, tmp2, rlen, mvb;
1039
1040             i       = bla[2*b];
1041             j       = bla[2*b+1];
1042             tmp0    = x[i][0] - x[j][0];
1043             tmp1    = x[i][1] - x[j][1];
1044             tmp2    = x[i][2] - x[j][2];
1045             rlen    = gmx::invsqrt(tmp0*tmp0 + tmp1*tmp1 + tmp2*tmp2);
1046             r[b][0] = rlen*tmp0;
1047             r[b][1] = rlen*tmp1;
1048             r[b][2] = rlen*tmp2;
1049             /* 16 ncons flops */
1050
1051             i       = bla[2*b];
1052             j       = bla[2*b+1];
1053             mvb     = blc[b]*(r[b][0]*(xp[i][0] - xp[j][0]) +
1054                               r[b][1]*(xp[i][1] - xp[j][1]) +
1055                               r[b][2]*(xp[i][2] - xp[j][2]) - bllen[b]);
1056             rhs1[b] = mvb;
1057             sol[b]  = mvb;
1058             /* 10 flops */
1059         }
1060         /* Together: 26*ncons + 6*nrtot flops */
1061     }
1062
1063 #endif  // GMX_SIMD_HAVE_REAL
1064
1065     if (lincsd->bTaskDep)
1066     {
1067         /* We need a barrier, since the matrix construction below
1068          * can access entries in r of other threads.
1069          */
1070 #pragma omp barrier
1071     }
1072
1073     /* Construct the (sparse) LINCS matrix */
1074     for (b = b0; b < b1; b++)
1075     {
1076         for (n = blnr[b]; n < blnr[b+1]; n++)
1077         {
1078             blcc[n] = blmf[n]*::iprod(r[b], r[blbnb[n]]);
1079         }
1080     }
1081     /* Together: 26*ncons + 6*nrtot flops */
1082
1083     lincs_matrix_expand(lincsd, &lincsd->task[th], blcc, rhs1, rhs2, sol);
1084     /* nrec*(ncons+2*nrtot) flops */
1085
1086 #if GMX_SIMD_HAVE_REAL
1087     for (b = b0; b < b1; b += GMX_SIMD_REAL_WIDTH)
1088     {
1089         SimdReal t1 = load<SimdReal>(blc + b);
1090         SimdReal t2 = load<SimdReal>(sol + b);
1091         store(mlambda + b, t1 * t2);
1092     }
1093 #else
1094     for (b = b0; b < b1; b++)
1095     {
1096         mlambda[b] = blc[b]*sol[b];
1097     }
1098 #endif  // GMX_SIMD_HAVE_REAL
1099
1100     /* Update the coordinates */
1101     lincs_update_atoms(lincsd, th, 1.0, mlambda, r, invmass, xp);
1102
1103     /*
1104      ********  Correction for centripetal effects  ********
1105      */
1106
1107     real wfac;
1108
1109     wfac = std::cos(DEG2RAD*wangle);
1110     wfac = wfac*wfac;
1111
1112     for (iter = 0; iter < lincsd->nIter; iter++)
1113     {
1114         if ((lincsd->bCommIter && DOMAINDECOMP(cr) && cr->dd->constraints))
1115         {
1116 #pragma omp barrier
1117 #pragma omp master
1118             {
1119                 /* Communicate the corrected non-local coordinates */
1120                 if (DOMAINDECOMP(cr))
1121                 {
1122                     dd_move_x_constraints(cr->dd, box, xp, nullptr, FALSE);
1123                 }
1124             }
1125 #pragma omp barrier
1126         }
1127         else if (lincsd->bTaskDep)
1128         {
1129 #pragma omp barrier
1130         }
1131
1132 #if GMX_SIMD_HAVE_REAL
1133         calc_dist_iter_simd(b0, b1, bla, xp, bllen, blc, pbc_simd, wfac,
1134                             rhs1, sol, bWarn);
1135 #else
1136         calc_dist_iter(b0, b1, bla, xp, bllen, blc, pbc, wfac,
1137                        rhs1, sol, bWarn);
1138         /* 20*ncons flops */
1139 #endif      // GMX_SIMD_HAVE_REAL
1140
1141         lincs_matrix_expand(lincsd, &lincsd->task[th], blcc, rhs1, rhs2, sol);
1142         /* nrec*(ncons+2*nrtot) flops */
1143
1144 #if GMX_SIMD_HAVE_REAL
1145         for (b = b0; b < b1; b += GMX_SIMD_REAL_WIDTH)
1146         {
1147             SimdReal t1  = load<SimdReal>(blc + b);
1148             SimdReal t2  = load<SimdReal>(sol + b);
1149             SimdReal mvb = t1 * t2;
1150             store(blc_sol + b, mvb);
1151             store(mlambda + b, load<SimdReal>(mlambda + b) + mvb);
1152         }
1153 #else
1154         for (b = b0; b < b1; b++)
1155         {
1156             real mvb;
1157
1158             mvb         = blc[b]*sol[b];
1159             blc_sol[b]  = mvb;
1160             mlambda[b] += mvb;
1161         }
1162 #endif      // GMX_SIMD_HAVE_REAL
1163
1164         /* Update the coordinates */
1165         lincs_update_atoms(lincsd, th, 1.0, blc_sol, r, invmass, xp);
1166     }
1167     /* nit*ncons*(37+9*nrec) flops */
1168
1169     if (v != nullptr)
1170     {
1171         /* Update the velocities */
1172         lincs_update_atoms(lincsd, th, invdt, mlambda, r, invmass, v);
1173         /* 16 ncons flops */
1174     }
1175
1176     if (nlocat != nullptr && (bCalcDHDL || bCalcVir))
1177     {
1178         if (lincsd->bTaskDep)
1179         {
1180             /* In lincs_update_atoms threads might cross-read mlambda */
1181 #pragma omp barrier
1182         }
1183
1184         /* Only account for local atoms */
1185         for (b = b0; b < b1; b++)
1186         {
1187             mlambda[b] *= 0.5*nlocat[b];
1188         }
1189     }
1190
1191     if (bCalcDHDL)
1192     {
1193         real dhdl;
1194
1195         dhdl = 0;
1196         for (b = b0; b < b1; b++)
1197         {
1198             /* Note that this this is dhdl*dt^2, the dt^2 factor is corrected
1199              * later after the contributions are reduced over the threads.
1200              */
1201             dhdl -= lincsd->mlambda[b]*lincsd->ddist[b];
1202         }
1203         lincsd->task[th].dhdlambda = dhdl;
1204     }
1205
1206     if (bCalcVir)
1207     {
1208         /* Constraint virial */
1209         for (b = b0; b < b1; b++)
1210         {
1211             real tmp0, tmp1;
1212
1213             tmp0 = -bllen[b]*mlambda[b];
1214             for (i = 0; i < DIM; i++)
1215             {
1216                 tmp1 = tmp0*r[b][i];
1217                 for (j = 0; j < DIM; j++)
1218                 {
1219                     vir_r_m_dr[i][j] -= tmp1*r[b][j];
1220                 }
1221             }
1222         }   /* 22 ncons flops */
1223     }
1224
1225     /* Total:
1226      * 26*ncons + 6*nrtot + nrec*(ncons+2*nrtot)
1227      * + nit * (20*ncons + nrec*(ncons+2*nrtot) + 17 ncons)
1228      *
1229      * (26+nrec)*ncons + (6+2*nrec)*nrtot
1230      * + nit * ((37+nrec)*ncons + 2*nrec*nrtot)
1231      * if nit=1
1232      * (63+nrec)*ncons + (6+4*nrec)*nrtot
1233      */
1234 }
1235
1236 /*! \brief Sets the elements in the LINCS matrix for task task. */
1237 static void set_lincs_matrix_task(Lincs                *li,
1238                                   Task                 *li_task,
1239                                   const real           *invmass,
1240                                   int                  *ncc_triangle,
1241                                   int                  *nCrossTaskTriangles)
1242 {
1243     int        i;
1244
1245     /* Construct the coupling coefficient matrix blmf */
1246     li_task->ntriangle   = 0;
1247     *ncc_triangle        = 0;
1248     *nCrossTaskTriangles = 0;
1249     for (i = li_task->b0; i < li_task->b1; i++)
1250     {
1251         int a1, a2, n;
1252
1253         a1 = li->bla[2*i];
1254         a2 = li->bla[2*i+1];
1255         for (n = li->blnr[i]; (n < li->blnr[i+1]); n++)
1256         {
1257             int k, sign, center, end;
1258
1259             k = li->blbnb[n];
1260
1261             /* If we are using multiple, independent tasks for LINCS,
1262              * the calls to check_assign_connected should have
1263              * put all connected constraints in our task.
1264              */
1265             assert(li->bTaskDep || (k >= li_task->b0 && k < li_task->b1));
1266
1267             if (a1 == li->bla[2*k] || a2 == li->bla[2*k+1])
1268             {
1269                 sign = -1;
1270             }
1271             else
1272             {
1273                 sign = 1;
1274             }
1275             if (a1 == li->bla[2*k] || a1 == li->bla[2*k+1])
1276             {
1277                 center = a1;
1278                 end    = a2;
1279             }
1280             else
1281             {
1282                 center = a2;
1283                 end    = a1;
1284             }
1285             li->blmf[n]  = sign*invmass[center]*li->blc[i]*li->blc[k];
1286             li->blmf1[n] = sign*0.5;
1287             if (li->ncg_triangle > 0)
1288             {
1289                 int nk, kk;
1290
1291                 /* Look for constraint triangles */
1292                 for (nk = li->blnr[k]; (nk < li->blnr[k+1]); nk++)
1293                 {
1294                     kk = li->blbnb[nk];
1295                     if (kk != i && kk != k &&
1296                         (li->bla[2*kk] == end || li->bla[2*kk+1] == end))
1297                     {
1298                         /* Check if the constraints in this triangle actually
1299                          * belong to a different task. We still assign them
1300                          * here, since it's convenient for the triangle
1301                          * iterations, but we then need an extra barrier.
1302                          */
1303                         if (k  < li_task->b0 || k  >= li_task->b1 ||
1304                             kk < li_task->b0 || kk >= li_task->b1)
1305                         {
1306                             (*nCrossTaskTriangles)++;
1307                         }
1308
1309                         if (li_task->ntriangle == 0 ||
1310                             li_task->triangle[li_task->ntriangle - 1] < i)
1311                         {
1312                             /* Add this constraint to the triangle list */
1313                             li_task->triangle[li_task->ntriangle] = i;
1314                             li_task->tri_bits[li_task->ntriangle] = 0;
1315                             li_task->ntriangle++;
1316                             if (li->blnr[i+1] - li->blnr[i] > static_cast<int>(sizeof(li_task->tri_bits[0])*8 - 1))
1317                             {
1318                                 gmx_fatal(FARGS, "A constraint is connected to %d constraints, this is more than the %zu allowed for constraints participating in triangles",
1319                                           li->blnr[i+1] - li->blnr[i],
1320                                           sizeof(li_task->tri_bits[0])*8-1);
1321                             }
1322                         }
1323                         li_task->tri_bits[li_task->ntriangle-1] |= (1 << (n - li->blnr[i]));
1324                         (*ncc_triangle)++;
1325                     }
1326                 }
1327             }
1328         }
1329     }
1330 }
1331
1332 /*! \brief Sets the elements in the LINCS matrix. */
1333 static void set_lincs_matrix(Lincs *li, real *invmass, real lambda)
1334 {
1335     int        i;
1336     const real invsqrt2 = 0.7071067811865475244;
1337
1338     for (i = 0; (i < li->nc); i++)
1339     {
1340         int a1, a2;
1341
1342         a1          = li->bla[2*i];
1343         a2          = li->bla[2*i+1];
1344         li->blc[i]  = gmx::invsqrt(invmass[a1] + invmass[a2]);
1345         li->blc1[i] = invsqrt2;
1346     }
1347
1348     /* Construct the coupling coefficient matrix blmf */
1349     int th, ntriangle = 0, ncc_triangle = 0, nCrossTaskTriangles = 0;
1350 #pragma omp parallel for reduction(+: ntriangle, ncc_triangle, nCrossTaskTriangles) num_threads(li->ntask) schedule(static)
1351     for (th = 0; th < li->ntask; th++)
1352     {
1353         try
1354         {
1355             set_lincs_matrix_task(li, &li->task[th], invmass,
1356                                   &ncc_triangle, &nCrossTaskTriangles);
1357             ntriangle = li->task[th].ntriangle;
1358         }
1359         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
1360     }
1361     li->ntriangle    = ntriangle;
1362     li->ncc_triangle = ncc_triangle;
1363     li->bTaskDepTri  = (nCrossTaskTriangles > 0);
1364
1365     if (debug)
1366     {
1367         fprintf(debug, "The %d constraints participate in %d triangles\n",
1368                 li->nc, li->ntriangle);
1369         fprintf(debug, "There are %d constraint couplings, of which %d in triangles\n",
1370                 li->ncc, li->ncc_triangle);
1371         if (li->ntriangle > 0 && li->ntask > 1)
1372         {
1373             fprintf(debug, "%d constraint triangles contain constraints assigned to different tasks\n",
1374                     nCrossTaskTriangles);
1375         }
1376     }
1377
1378     /* Set matlam,
1379      * so we know with which lambda value the masses have been set.
1380      */
1381     li->matlam = lambda;
1382 }
1383
1384 //! Finds all triangles of atoms that share constraints to a central atom.
1385 static int count_triangle_constraints(const InteractionLists &ilist,
1386                                       const t_blocka         &at2con)
1387 {
1388     int      ncon1, ncon_tot;
1389     int      c0, n1, c1, ac1, n2, c2;
1390     int      ncon_triangle;
1391
1392     ncon1    = ilist[F_CONSTR].size()/3;
1393     ncon_tot = ncon1 + ilist[F_CONSTRNC].size()/3;
1394
1395     gmx::ArrayRef<const int> ia1 = ilist[F_CONSTR].iatoms;
1396     gmx::ArrayRef<const int> ia2 = ilist[F_CONSTRNC].iatoms;
1397
1398     ncon_triangle = 0;
1399     for (c0 = 0; c0 < ncon_tot; c0++)
1400     {
1401         bool       bTriangle = FALSE;
1402         const int *iap       = constr_iatomptr(ia1, ia2, c0);
1403         const int  a00       = iap[1];
1404         const int  a01       = iap[2];
1405         for (n1 = at2con.index[a01]; n1 < at2con.index[a01+1]; n1++)
1406         {
1407             c1 = at2con.a[n1];
1408             if (c1 != c0)
1409             {
1410                 const int *iap = constr_iatomptr(ia1, ia2, c1);
1411                 const int  a10 = iap[1];
1412                 const int  a11 = iap[2];
1413                 if (a10 == a01)
1414                 {
1415                     ac1 = a11;
1416                 }
1417                 else
1418                 {
1419                     ac1 = a10;
1420                 }
1421                 for (n2 = at2con.index[ac1]; n2 < at2con.index[ac1+1]; n2++)
1422                 {
1423                     c2 = at2con.a[n2];
1424                     if (c2 != c0 && c2 != c1)
1425                     {
1426                         const int *iap = constr_iatomptr(ia1, ia2, c2);
1427                         const int  a20 = iap[1];
1428                         const int  a21 = iap[2];
1429                         if (a20 == a00 || a21 == a00)
1430                         {
1431                             bTriangle = TRUE;
1432                         }
1433                     }
1434                 }
1435             }
1436         }
1437         if (bTriangle)
1438         {
1439             ncon_triangle++;
1440         }
1441     }
1442
1443     return ncon_triangle;
1444 }
1445
1446 //! Finds sequences of sequential constraints.
1447 static bool more_than_two_sequential_constraints(const InteractionLists &ilist,
1448                                                  const t_blocka         &at2con)
1449 {
1450     int       ncon1, ncon_tot, c;
1451     bool      bMoreThanTwoSequentialConstraints;
1452
1453     ncon1    = ilist[F_CONSTR].size()/3;
1454     ncon_tot = ncon1 + ilist[F_CONSTRNC].size()/3;
1455
1456     gmx::ArrayRef<const int> ia1 = ilist[F_CONSTR].iatoms;
1457     gmx::ArrayRef<const int> ia2 = ilist[F_CONSTRNC].iatoms;
1458
1459     bMoreThanTwoSequentialConstraints = FALSE;
1460     for (c = 0; c < ncon_tot && !bMoreThanTwoSequentialConstraints; c++)
1461     {
1462         const int *iap = constr_iatomptr(ia1, ia2, c);
1463         const int  a1  = iap[1];
1464         const int  a2  = iap[2];
1465         /* Check if this constraint has constraints connected at both atoms */
1466         if (at2con.index[a1+1] - at2con.index[a1] > 1 &&
1467             at2con.index[a2+1] - at2con.index[a2] > 1)
1468         {
1469             bMoreThanTwoSequentialConstraints = TRUE;
1470         }
1471     }
1472
1473     return bMoreThanTwoSequentialConstraints;
1474 }
1475
1476 Lincs *init_lincs(FILE *fplog, const gmx_mtop_t &mtop,
1477                   int nflexcon_global, ArrayRef<const t_blocka> at2con,
1478                   bool bPLINCS, int nIter, int nProjOrder)
1479 {
1480     // TODO this should become a unique_ptr
1481     Lincs                *li;
1482     bool                  bMoreThanTwoSeq;
1483
1484     if (fplog)
1485     {
1486         fprintf(fplog, "\nInitializing%s LINear Constraint Solver\n",
1487                 bPLINCS ? " Parallel" : "");
1488     }
1489
1490     li = new Lincs;
1491
1492     li->ncg      =
1493         gmx_mtop_ftype_count(mtop, F_CONSTR) +
1494         gmx_mtop_ftype_count(mtop, F_CONSTRNC);
1495     li->ncg_flex = nflexcon_global;
1496
1497     li->nIter  = nIter;
1498     li->nOrder = nProjOrder;
1499
1500     li->max_connect = 0;
1501     for (size_t mt = 0; mt < mtop.moltype.size(); mt++)
1502     {
1503         for (int a = 0; a < mtop.moltype[mt].atoms.nr; a++)
1504         {
1505             li->max_connect = std::max(li->max_connect,
1506                                        at2con[mt].index[a + 1] - at2con[mt].index[a]);
1507         }
1508     }
1509
1510     li->ncg_triangle = 0;
1511     bMoreThanTwoSeq  = FALSE;
1512     for (const gmx_molblock_t &molb : mtop.molblock)
1513     {
1514         const gmx_moltype_t &molt = mtop.moltype[molb.type];
1515
1516         li->ncg_triangle +=
1517             molb.nmol*
1518             count_triangle_constraints(molt.ilist, at2con[molb.type]);
1519
1520         if (!bMoreThanTwoSeq &&
1521             more_than_two_sequential_constraints(molt.ilist, at2con[molb.type]))
1522         {
1523             bMoreThanTwoSeq = TRUE;
1524         }
1525     }
1526
1527     /* Check if we need to communicate not only before LINCS,
1528      * but also before each iteration.
1529      * The check for only two sequential constraints is only
1530      * useful for the common case of H-bond only constraints.
1531      * With more effort we could also make it useful for small
1532      * molecules with nr. sequential constraints <= nOrder-1.
1533      */
1534     li->bCommIter = (bPLINCS && (li->nOrder < 1 || bMoreThanTwoSeq));
1535
1536     if (debug && bPLINCS)
1537     {
1538         fprintf(debug, "PLINCS communication before each iteration: %d\n",
1539                 static_cast<int>(li->bCommIter));
1540     }
1541
1542     /* LINCS can run on any number of threads.
1543      * Currently the number is fixed for the whole simulation,
1544      * but it could be set in set_lincs().
1545      * The current constraint to task assignment code can create independent
1546      * tasks only when not more than two constraints are connected sequentially.
1547      */
1548     li->ntask    = gmx_omp_nthreads_get(emntLINCS);
1549     li->bTaskDep = (li->ntask > 1 && bMoreThanTwoSeq);
1550     if (debug)
1551     {
1552         fprintf(debug, "LINCS: using %d threads, tasks are %sdependent\n",
1553                 li->ntask, li->bTaskDep ? "" : "in");
1554     }
1555     if (li->ntask == 1)
1556     {
1557         li->task.resize(1);
1558     }
1559     else
1560     {
1561         /* Allocate an extra elements for "task-overlap" constraints */
1562         li->task.resize(li->ntask + 1);
1563     }
1564
1565     if (bPLINCS || li->ncg_triangle > 0)
1566     {
1567         please_cite(fplog, "Hess2008a");
1568     }
1569     else
1570     {
1571         please_cite(fplog, "Hess97a");
1572     }
1573
1574     if (fplog)
1575     {
1576         fprintf(fplog, "The number of constraints is %d\n", li->ncg);
1577         if (bPLINCS)
1578         {
1579             fprintf(fplog, "There are constraints between atoms in different decomposition domains,\n"
1580                     "will communicate selected coordinates each lincs iteration\n");
1581         }
1582         if (li->ncg_triangle > 0)
1583         {
1584             fprintf(fplog,
1585                     "%d constraints are involved in constraint triangles,\n"
1586                     "will apply an additional matrix expansion of order %d for couplings\n"
1587                     "between constraints inside triangles\n",
1588                     li->ncg_triangle, li->nOrder);
1589         }
1590     }
1591
1592     return li;
1593 }
1594
1595 void done_lincs(Lincs *li)
1596 {
1597     delete li;
1598 }
1599
1600 /*! \brief Sets up the work division over the threads. */
1601 static void lincs_thread_setup(Lincs *li, int natoms)
1602 {
1603     li->atf.resize(natoms);
1604
1605     gmx::ArrayRef<gmx_bitmask_t> atf = li->atf;
1606
1607     /* Clear the atom flags */
1608     for (gmx_bitmask_t &mask : atf)
1609     {
1610         bitmask_clear(&mask);
1611     }
1612
1613     if (li->ntask > BITMASK_SIZE)
1614     {
1615         gmx_fatal(FARGS, "More than %d threads is not supported for LINCS.", BITMASK_SIZE);
1616     }
1617
1618     for (int th = 0; th < li->ntask; th++)
1619     {
1620         const Task *li_task = &li->task[th];
1621
1622         /* For each atom set a flag for constraints from each */
1623         for (int b = li_task->b0; b < li_task->b1; b++)
1624         {
1625             bitmask_set_bit(&atf[li->bla[b*2    ]], th);
1626             bitmask_set_bit(&atf[li->bla[b*2 + 1]], th);
1627         }
1628     }
1629
1630 #pragma omp parallel for num_threads(li->ntask) schedule(static)
1631     for (int th = 0; th < li->ntask; th++)
1632     {
1633         try
1634         {
1635             Task          *li_task;
1636             gmx_bitmask_t  mask;
1637             int            b;
1638
1639             li_task = &li->task[th];
1640
1641             bitmask_init_low_bits(&mask, th);
1642
1643             li_task->ind.clear();
1644             li_task->ind_r.clear();
1645             for (b = li_task->b0; b < li_task->b1; b++)
1646             {
1647                 /* We let the constraint with the lowest thread index
1648                  * operate on atoms with constraints from multiple threads.
1649                  */
1650                 if (bitmask_is_disjoint(atf[li->bla[b*2]], mask) &&
1651                     bitmask_is_disjoint(atf[li->bla[b*2+1]], mask))
1652                 {
1653                     /* Add the constraint to the local atom update index */
1654                     li_task->ind.push_back(b);
1655                 }
1656                 else
1657                 {
1658                     /* Add the constraint to the rest block */
1659                     li_task->ind_r.push_back(b);
1660                 }
1661             }
1662         }
1663         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
1664     }
1665
1666     /* We need to copy all constraints which have not be assigned
1667      * to a thread to a separate list which will be handled by one thread.
1668      */
1669     Task *li_m = &li->task[li->ntask];
1670
1671     li_m->ind.clear();
1672     for (int th = 0; th < li->ntask; th++)
1673     {
1674         const Task &li_task = li->task[th];
1675
1676         for (int ind_r : li_task.ind_r)
1677         {
1678             li_m->ind.push_back(ind_r);
1679         }
1680
1681         if (debug)
1682         {
1683             fprintf(debug, "LINCS thread %d: %zu constraints\n",
1684                     th, li_task.ind.size());
1685         }
1686     }
1687
1688     if (debug)
1689     {
1690         fprintf(debug, "LINCS thread r: %zu constraints\n",
1691                 li_m->ind.size());
1692     }
1693 }
1694
1695 //! Assign a constraint.
1696 static void assign_constraint(Lincs *li,
1697                               int constraint_index,
1698                               int a1, int a2,
1699                               real lenA, real lenB,
1700                               const t_blocka *at2con)
1701 {
1702     int con;
1703
1704     con = li->nc;
1705
1706     /* Make an mapping of local topology constraint index to LINCS index */
1707     li->con_index[constraint_index] = con;
1708
1709     li->bllen0[con]  = lenA;
1710     li->ddist[con]   = lenB - lenA;
1711     /* Set the length to the topology A length */
1712     li->bllen[con]   = lenA;
1713     li->bla[2*con]   = a1;
1714     li->bla[2*con+1] = a2;
1715
1716     /* Make space in the constraint connection matrix for constraints
1717      * connected to both end of the current constraint.
1718      */
1719     li->ncc +=
1720         at2con->index[a1 + 1] - at2con->index[a1] - 1 +
1721         at2con->index[a2 + 1] - at2con->index[a2] - 1;
1722
1723     li->blnr[con + 1] = li->ncc;
1724
1725     /* Increase the constraint count */
1726     li->nc++;
1727 }
1728
1729 /*! \brief Check if constraint with topology index constraint_index is connected
1730  * to other constraints, and if so add those connected constraints to our task. */
1731 static void check_assign_connected(Lincs *li,
1732                                    const t_iatom *iatom,
1733                                    const t_idef &idef,
1734                                    bool bDynamics,
1735                                    int a1, int a2,
1736                                    const t_blocka *at2con)
1737 {
1738     /* Currently this function only supports constraint groups
1739      * in which all constraints share at least one atom
1740      * (e.g. H-bond constraints).
1741      * Check both ends of the current constraint for
1742      * connected constraints. We need to assign those
1743      * to the same task.
1744      */
1745     int end;
1746
1747     for (end = 0; end < 2; end++)
1748     {
1749         int a, k;
1750
1751         a = (end == 0 ? a1 : a2);
1752
1753         for (k = at2con->index[a]; k < at2con->index[a + 1]; k++)
1754         {
1755             int cc;
1756
1757             cc = at2con->a[k];
1758             /* Check if constraint cc has not yet been assigned */
1759             if (li->con_index[cc] == -1)
1760             {
1761                 int  type;
1762                 real lenA, lenB;
1763
1764                 type = iatom[cc*3];
1765                 lenA = idef.iparams[type].constr.dA;
1766                 lenB = idef.iparams[type].constr.dB;
1767
1768                 if (bDynamics || lenA != 0 || lenB != 0)
1769                 {
1770                     assign_constraint(li, cc, iatom[3*cc + 1], iatom[3*cc + 2], lenA, lenB, at2con);
1771                 }
1772             }
1773         }
1774     }
1775 }
1776
1777 /*! \brief Check if constraint with topology index constraint_index is involved
1778  * in a constraint triangle, and if so add the other two constraints
1779  * in the triangle to our task. */
1780 static void check_assign_triangle(Lincs *li,
1781                                   const t_iatom *iatom,
1782                                   const t_idef &idef,
1783                                   bool bDynamics,
1784                                   int constraint_index,
1785                                   int a1, int a2,
1786                                   const t_blocka *at2con)
1787 {
1788     int nca, cc[32], ca[32], k;
1789     int c_triangle[2] = { -1, -1 };
1790
1791     nca = 0;
1792     for (k = at2con->index[a1]; k < at2con->index[a1 + 1]; k++)
1793     {
1794         int c;
1795
1796         c = at2con->a[k];
1797         if (c != constraint_index)
1798         {
1799             int aa1, aa2;
1800
1801             aa1 = iatom[c*3 + 1];
1802             aa2 = iatom[c*3 + 2];
1803             if (aa1 != a1)
1804             {
1805                 cc[nca] = c;
1806                 ca[nca] = aa1;
1807                 nca++;
1808             }
1809             if (aa2 != a1)
1810             {
1811                 cc[nca] = c;
1812                 ca[nca] = aa2;
1813                 nca++;
1814             }
1815         }
1816     }
1817
1818     for (k = at2con->index[a2]; k < at2con->index[a2 + 1]; k++)
1819     {
1820         int c;
1821
1822         c = at2con->a[k];
1823         if (c != constraint_index)
1824         {
1825             int aa1, aa2, i;
1826
1827             aa1 = iatom[c*3 + 1];
1828             aa2 = iatom[c*3 + 2];
1829             if (aa1 != a2)
1830             {
1831                 for (i = 0; i < nca; i++)
1832                 {
1833                     if (aa1 == ca[i])
1834                     {
1835                         c_triangle[0] = cc[i];
1836                         c_triangle[1] = c;
1837                     }
1838                 }
1839             }
1840             if (aa2 != a2)
1841             {
1842                 for (i = 0; i < nca; i++)
1843                 {
1844                     if (aa2 == ca[i])
1845                     {
1846                         c_triangle[0] = cc[i];
1847                         c_triangle[1] = c;
1848                     }
1849                 }
1850             }
1851         }
1852     }
1853
1854     if (c_triangle[0] >= 0)
1855     {
1856         int end;
1857
1858         for (end = 0; end < 2; end++)
1859         {
1860             /* Check if constraint c_triangle[end] has not yet been assigned */
1861             if (li->con_index[c_triangle[end]] == -1)
1862             {
1863                 int  i, type;
1864                 real lenA, lenB;
1865
1866                 i    = c_triangle[end]*3;
1867                 type = iatom[i];
1868                 lenA = idef.iparams[type].constr.dA;
1869                 lenB = idef.iparams[type].constr.dB;
1870
1871                 if (bDynamics || lenA != 0 || lenB != 0)
1872                 {
1873                     assign_constraint(li, c_triangle[end], iatom[i + 1], iatom[i + 2], lenA, lenB, at2con);
1874                 }
1875             }
1876         }
1877     }
1878 }
1879
1880 //! Sets matrix indices.
1881 static void set_matrix_indices(Lincs                *li,
1882                                const Task           *li_task,
1883                                const t_blocka       *at2con,
1884                                bool                  bSortMatrix)
1885 {
1886     int b;
1887
1888     for (b = li_task->b0; b < li_task->b1; b++)
1889     {
1890         int a1, a2, i, k;
1891
1892         a1 = li->bla[b*2];
1893         a2 = li->bla[b*2 + 1];
1894
1895         i = li->blnr[b];
1896         for (k = at2con->index[a1]; k < at2con->index[a1 + 1]; k++)
1897         {
1898             int concon;
1899
1900             concon = li->con_index[at2con->a[k]];
1901             if (concon != b)
1902             {
1903                 li->blbnb[i++] = concon;
1904             }
1905         }
1906         for (k = at2con->index[a2]; k < at2con->index[a2 + 1]; k++)
1907         {
1908             int concon;
1909
1910             concon = li->con_index[at2con->a[k]];
1911             if (concon != b)
1912             {
1913                 li->blbnb[i++] = concon;
1914             }
1915         }
1916
1917         if (bSortMatrix)
1918         {
1919             /* Order the blbnb matrix to optimize memory access */
1920             std::sort(&(li->blbnb[li->blnr[b]]), &(li->blbnb[li->blnr[b+1]]));
1921         }
1922     }
1923 }
1924
1925 void set_lincs(const t_idef         &idef,
1926                const t_mdatoms      &md,
1927                bool                  bDynamics,
1928                const t_commrec      *cr,
1929                Lincs                *li)
1930 {
1931     int          natoms;
1932     t_blocka     at2con;
1933     t_iatom     *iatom;
1934
1935     li->nc_real = 0;
1936     li->nc      = 0;
1937     li->ncc     = 0;
1938     /* Zero the thread index ranges.
1939      * Otherwise without local constraints we could return with old ranges.
1940      */
1941     for (int i = 0; i < li->ntask; i++)
1942     {
1943         li->task[i].b0   = 0;
1944         li->task[i].b1   = 0;
1945         li->task[i].ind.clear();
1946     }
1947     if (li->ntask > 1)
1948     {
1949         li->task[li->ntask].ind.clear();
1950     }
1951
1952     /* This is the local topology, so there are only F_CONSTR constraints */
1953     if (idef.il[F_CONSTR].nr == 0)
1954     {
1955         /* There are no constraints,
1956          * we do not need to fill any data structures.
1957          */
1958         return;
1959     }
1960
1961     if (debug)
1962     {
1963         fprintf(debug, "Building the LINCS connectivity\n");
1964     }
1965
1966     if (DOMAINDECOMP(cr))
1967     {
1968         if (cr->dd->constraints)
1969         {
1970             int start;
1971
1972             dd_get_constraint_range(cr->dd, &start, &natoms);
1973         }
1974         else
1975         {
1976             natoms = dd_numHomeAtoms(*cr->dd);
1977         }
1978     }
1979     else
1980     {
1981         natoms = md.homenr;
1982     }
1983
1984     at2con = make_at2con(natoms, idef.il, idef.iparams,
1985                          flexibleConstraintTreatment(bDynamics));
1986
1987     const int ncon_tot = idef.il[F_CONSTR].nr/3;
1988
1989     /* Ensure we have enough padding for aligned loads for each thread */
1990     const int numEntries = ncon_tot + li->ntask*simd_width;
1991     li->con_index.resize(numEntries);
1992     li->bllen0.resize(numEntries);
1993     li->ddist.resize(numEntries);
1994     li->bla.resize(numEntries*2);
1995     li->blc.resize(numEntries);
1996     li->blc1.resize(numEntries);
1997     li->blnr.resize(numEntries);
1998     li->bllen.resize(numEntries);
1999     li->tmpv.resizeWithPadding(numEntries);
2000     if (DOMAINDECOMP(cr))
2001     {
2002         li->nlocat.resize(numEntries);
2003     }
2004     li->tmp1.resize(numEntries);
2005     li->tmp2.resize(numEntries);
2006     li->tmp3.resize(numEntries);
2007     li->tmp4.resize(numEntries);
2008     li->mlambda.resize(numEntries);
2009
2010     iatom = idef.il[F_CONSTR].iatoms;
2011
2012     li->blnr[0]   = li->ncc;
2013
2014     /* Assign the constraints for li->ntask LINCS tasks.
2015      * We target a uniform distribution of constraints over the tasks.
2016      * Note that when flexible constraints are present, but are removed here
2017      * (e.g. because we are doing EM) we get imbalance, but since that doesn't
2018      * happen during normal MD, that's ok.
2019      */
2020     int ncon_assign, ncon_target, con, th;
2021
2022     /* Determine the number of constraints we need to assign here */
2023     ncon_assign      = ncon_tot;
2024     if (!bDynamics)
2025     {
2026         /* With energy minimization, flexible constraints are ignored
2027          * (and thus minimized, as they should be).
2028          */
2029         ncon_assign -= countFlexibleConstraints(idef.il, idef.iparams);
2030     }
2031
2032     /* Set the target constraint count per task to exactly uniform,
2033      * this might be overridden below.
2034      */
2035     ncon_target = (ncon_assign + li->ntask - 1)/li->ntask;
2036
2037     /* Mark all constraints as unassigned by setting their index to -1 */
2038     for (con = 0; con < ncon_tot; con++)
2039     {
2040         li->con_index[con] = -1;
2041     }
2042
2043     con = 0;
2044     for (th = 0; th < li->ntask; th++)
2045     {
2046         Task *li_task;
2047
2048         li_task = &li->task[th];
2049
2050 #if GMX_SIMD_HAVE_REAL
2051         /* With indepedent tasks we likely have H-bond constraints or constraint
2052          * pairs. The connected constraints will be pulled into the task, so the
2053          * constraints per task will often exceed ncon_target.
2054          * Triangle constraints can also increase the count, but there are
2055          * relatively few of those, so we usually expect to get ncon_target.
2056          */
2057         if (li->bTaskDep)
2058         {
2059             /* We round ncon_target to a multiple of GMX_SIMD_WIDTH,
2060              * since otherwise a lot of operations can be wasted.
2061              * There are several ways to round here, we choose the one
2062              * that alternates block sizes, which helps with Intel HT.
2063              */
2064             ncon_target = ((ncon_assign*(th + 1))/li->ntask - li->nc_real + GMX_SIMD_REAL_WIDTH - 1) & ~(GMX_SIMD_REAL_WIDTH - 1);
2065         }
2066 #endif      // GMX_SIMD==2 && GMX_SIMD_HAVE_REAL
2067
2068         /* Continue filling the arrays where we left off with the previous task,
2069          * including padding for SIMD.
2070          */
2071         li_task->b0 = li->nc;
2072
2073         while (con < ncon_tot && li->nc - li_task->b0 < ncon_target)
2074         {
2075             if (li->con_index[con] == -1)
2076             {
2077                 int  type, a1, a2;
2078                 real lenA, lenB;
2079
2080                 type   = iatom[3*con];
2081                 a1     = iatom[3*con + 1];
2082                 a2     = iatom[3*con + 2];
2083                 lenA   = idef.iparams[type].constr.dA;
2084                 lenB   = idef.iparams[type].constr.dB;
2085                 /* Skip the flexible constraints when not doing dynamics */
2086                 if (bDynamics || lenA != 0 || lenB != 0)
2087                 {
2088                     assign_constraint(li, con, a1, a2, lenA, lenB, &at2con);
2089
2090                     if (li->ntask > 1 && !li->bTaskDep)
2091                     {
2092                         /* We can generate independent tasks. Check if we
2093                          * need to assign connected constraints to our task.
2094                          */
2095                         check_assign_connected(li, iatom, idef, bDynamics,
2096                                                a1, a2, &at2con);
2097                     }
2098                     if (li->ntask > 1 && li->ncg_triangle > 0)
2099                     {
2100                         /* Ensure constraints in one triangle are assigned
2101                          * to the same task.
2102                          */
2103                         check_assign_triangle(li, iatom, idef, bDynamics,
2104                                               con, a1, a2, &at2con);
2105                     }
2106                 }
2107             }
2108
2109             con++;
2110         }
2111
2112         li_task->b1 = li->nc;
2113
2114         if (simd_width > 1)
2115         {
2116             /* Copy the last atom pair indices and lengths for constraints
2117              * up to a multiple of simd_width, such that we can do all
2118              * SIMD operations without having to worry about end effects.
2119              */
2120             int i, last;
2121
2122             li->nc = ((li_task->b1 + simd_width - 1)/simd_width)*simd_width;
2123             last   = li_task->b1 - 1;
2124             for (i = li_task->b1; i < li->nc; i++)
2125             {
2126                 li->bla[i*2    ] = li->bla[last*2    ];
2127                 li->bla[i*2 + 1] = li->bla[last*2 + 1];
2128                 li->bllen0[i]    = li->bllen0[last];
2129                 li->ddist[i]     = li->ddist[last];
2130                 li->bllen[i]     = li->bllen[last];
2131                 li->blnr[i + 1]  = li->blnr[last + 1];
2132             }
2133         }
2134
2135         /* Keep track of how many constraints we assigned */
2136         li->nc_real += li_task->b1 - li_task->b0;
2137
2138         if (debug)
2139         {
2140             fprintf(debug, "LINCS task %d constraints %d - %d\n",
2141                     th, li_task->b0, li_task->b1);
2142         }
2143     }
2144
2145     assert(li->nc_real == ncon_assign);
2146
2147     bool bSortMatrix;
2148
2149     /* Without DD we order the blbnb matrix to optimize memory access.
2150      * With DD the overhead of sorting is more than the gain during access.
2151      */
2152     bSortMatrix = !DOMAINDECOMP(cr);
2153
2154     li->blbnb.resize(li->ncc);
2155
2156 #pragma omp parallel for num_threads(li->ntask) schedule(static)
2157     for (th = 0; th < li->ntask; th++)
2158     {
2159         try
2160         {
2161             Task *li_task;
2162
2163             li_task = &li->task[th];
2164
2165             if (li->ncg_triangle > 0)
2166             {
2167                 /* This is allocating too much, but it is difficult to improve */
2168                 li_task->triangle.resize(li_task->b1 - li_task->b0);
2169                 li_task->tri_bits.resize(li_task->b1 - li_task->b0);
2170             }
2171
2172             set_matrix_indices(li, li_task, &at2con, bSortMatrix);
2173         }
2174         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
2175     }
2176
2177     done_blocka(&at2con);
2178
2179     if (cr->dd == nullptr)
2180     {
2181         /* Since the matrix is static, we should free some memory */
2182         li->blbnb.resize(li->ncc);
2183     }
2184
2185     li->blmf.resize(li->ncc);
2186     li->blmf1.resize(li->ncc);
2187     li->tmpncc.resize(li->ncc);
2188
2189     gmx::ArrayRef<const int> nlocat_dd = dd_constraints_nlocalatoms(cr->dd);
2190     if (!nlocat_dd.empty())
2191     {
2192         /* Convert nlocat from local topology to LINCS constraint indexing */
2193         for (con = 0; con < ncon_tot; con++)
2194         {
2195             li->nlocat[li->con_index[con]] = nlocat_dd[con];
2196         }
2197     }
2198     else
2199     {
2200         li->nlocat.clear();
2201     }
2202
2203     if (debug)
2204     {
2205         fprintf(debug, "Number of constraints is %d, padded %d, couplings %d\n",
2206                 li->nc_real, li->nc, li->ncc);
2207     }
2208
2209     if (li->ntask > 1)
2210     {
2211         lincs_thread_setup(li, md.nr);
2212     }
2213
2214     set_lincs_matrix(li, md.invmass, md.lambda);
2215 }
2216
2217 //! Issues a warning when LINCS constraints cannot be satisfied.
2218 static void lincs_warning(gmx_domdec_t *dd, const rvec *x, rvec *xprime, t_pbc *pbc,
2219                           int ncons, gmx::ArrayRef<const int> bla,
2220                           gmx::ArrayRef<const real> bllen, real wangle,
2221                           int maxwarn, int *warncount)
2222 {
2223     int  b, i, j;
2224     rvec v0, v1;
2225     real wfac, d0, d1, cosine;
2226
2227     wfac = std::cos(DEG2RAD*wangle);
2228
2229     fprintf(stderr,
2230             "bonds that rotated more than %g degrees:\n"
2231             " atom 1 atom 2  angle  previous, current, constraint length\n",
2232             wangle);
2233
2234     for (b = 0; b < ncons; b++)
2235     {
2236         i = bla[2*b];
2237         j = bla[2*b+1];
2238         if (pbc)
2239         {
2240             pbc_dx_aiuc(pbc, x[i], x[j], v0);
2241             pbc_dx_aiuc(pbc, xprime[i], xprime[j], v1);
2242         }
2243         else
2244         {
2245             rvec_sub(x[i], x[j], v0);
2246             rvec_sub(xprime[i], xprime[j], v1);
2247         }
2248         d0     = norm(v0);
2249         d1     = norm(v1);
2250         cosine = ::iprod(v0, v1)/(d0*d1);
2251         if (cosine < wfac)
2252         {
2253             fprintf(stderr,
2254                     " %6d %6d  %5.1f  %8.4f %8.4f    %8.4f\n",
2255                     ddglatnr(dd, i), ddglatnr(dd, j),
2256                     RAD2DEG*std::acos(cosine), d0, d1, bllen[b]);
2257             if (!std::isfinite(d1))
2258             {
2259                 gmx_fatal(FARGS, "Bond length not finite.");
2260             }
2261
2262             (*warncount)++;
2263         }
2264     }
2265     if (*warncount > maxwarn)
2266     {
2267         too_many_constraint_warnings(econtLINCS, *warncount);
2268     }
2269 }
2270
2271 //! Determine how well the constraints have been satisfied.
2272 static void cconerr(const Lincs *lincsd,
2273                     rvec *x, t_pbc *pbc,
2274                     real *ncons_loc, real *ssd, real *max, int *imax)
2275 {
2276     gmx::ArrayRef<const int>  bla    = lincsd->bla;
2277     gmx::ArrayRef<const real> bllen  = lincsd->bllen;
2278     gmx::ArrayRef<const int>  nlocat = lincsd->nlocat;
2279
2280     real ma    = 0;
2281     real ssd2  = 0;
2282     int  im    = 0;
2283     int  count = 0;
2284     for (int task = 0; task < lincsd->ntask; task++)
2285     {
2286         int b;
2287
2288         for (b = lincsd->task[task].b0; b < lincsd->task[task].b1; b++)
2289         {
2290             real len, d, r2;
2291             rvec dx;
2292
2293             if (pbc)
2294             {
2295                 pbc_dx_aiuc(pbc, x[bla[2*b]], x[bla[2*b+1]], dx);
2296             }
2297             else
2298             {
2299                 rvec_sub(x[bla[2*b]], x[bla[2*b+1]], dx);
2300             }
2301             r2  = ::norm2(dx);
2302             len = r2*gmx::invsqrt(r2);
2303             d   = std::abs(len/bllen[b]-1);
2304             if (d > ma && (nlocat.empty() || nlocat[b]))
2305             {
2306                 ma = d;
2307                 im = b;
2308             }
2309             if (nlocat.empty())
2310             {
2311                 ssd2 += d*d;
2312                 count++;
2313             }
2314             else
2315             {
2316                 ssd2  += nlocat[b]*d*d;
2317                 count += nlocat[b];
2318             }
2319         }
2320     }
2321
2322     *ncons_loc = (nlocat.empty() ? 1 : 0.5)*count;
2323     *ssd       = (nlocat.empty() ? 1 : 0.5)*ssd2;
2324     *max       = ma;
2325     *imax      = im;
2326 }
2327
2328 bool constrain_lincs(bool computeRmsd,
2329                      const t_inputrec &ir,
2330                      int64_t step,
2331                      Lincs *lincsd, const t_mdatoms &md,
2332                      const t_commrec *cr,
2333                      const gmx_multisim_t &ms,
2334                      const rvec *x, rvec *xprime, rvec *min_proj,
2335                      matrix box, t_pbc *pbc,
2336                      real lambda, real *dvdlambda,
2337                      real invdt, rvec *v,
2338                      bool bCalcVir, tensor vir_r_m_dr,
2339                      ConstraintVariable econq,
2340                      t_nrnb *nrnb,
2341                      int maxwarn, int *warncount)
2342 {
2343     gmx_bool  bCalcDHDL;
2344     char      buf2[22], buf3[STRLEN];
2345     int       i, p_imax;
2346     real      ncons_loc, p_ssd, p_max = 0;
2347     rvec      dx;
2348     bool      bOK, bWarn;
2349
2350     bOK = TRUE;
2351
2352     /* This boolean should be set by a flag passed to this routine.
2353      * We can also easily check if any constraint length is changed,
2354      * if not dH/dlambda=0 and we can also set the boolean to FALSE.
2355      */
2356     bCalcDHDL = (ir.efep != efepNO && dvdlambda != nullptr);
2357
2358     if (lincsd->nc == 0 && cr->dd == nullptr)
2359     {
2360         if (computeRmsd)
2361         {
2362             lincsd->rmsdData = {{0}};
2363         }
2364
2365         return bOK;
2366     }
2367
2368     if (econq == ConstraintVariable::Positions)
2369     {
2370         /* We can't use bCalcDHDL here, since NULL can be passed for dvdlambda
2371          * also with efep!=fepNO.
2372          */
2373         if (ir.efep != efepNO)
2374         {
2375             if (md.nMassPerturbed && lincsd->matlam != md.lambda)
2376             {
2377                 set_lincs_matrix(lincsd, md.invmass, md.lambda);
2378             }
2379
2380             for (i = 0; i < lincsd->nc; i++)
2381             {
2382                 lincsd->bllen[i] = lincsd->bllen0[i] + lambda*lincsd->ddist[i];
2383             }
2384         }
2385
2386         if (lincsd->ncg_flex)
2387         {
2388             /* Set the flexible constraint lengths to the old lengths */
2389             if (pbc != nullptr)
2390             {
2391                 for (i = 0; i < lincsd->nc; i++)
2392                 {
2393                     if (lincsd->bllen[i] == 0)
2394                     {
2395                         pbc_dx_aiuc(pbc, x[lincsd->bla[2*i]], x[lincsd->bla[2*i+1]], dx);
2396                         lincsd->bllen[i] = norm(dx);
2397                     }
2398                 }
2399             }
2400             else
2401             {
2402                 for (i = 0; i < lincsd->nc; i++)
2403                 {
2404                     if (lincsd->bllen[i] == 0)
2405                     {
2406                         lincsd->bllen[i] =
2407                             std::sqrt(distance2(x[lincsd->bla[2*i]],
2408                                                 x[lincsd->bla[2*i+1]]));
2409                     }
2410                 }
2411             }
2412         }
2413
2414         if (debug)
2415         {
2416             cconerr(lincsd, xprime, pbc,
2417                     &ncons_loc, &p_ssd, &p_max, &p_imax);
2418         }
2419
2420         /* This bWarn var can be updated by multiple threads
2421          * at the same time. But as we only need to detect
2422          * if a warning occurred or not, this is not an issue.
2423          */
2424         bWarn = FALSE;
2425
2426         /* The OpenMP parallel region of constrain_lincs for coords */
2427 #pragma omp parallel num_threads(lincsd->ntask)
2428         {
2429             try
2430             {
2431                 int th = gmx_omp_get_thread_num();
2432
2433                 clear_mat(lincsd->task[th].vir_r_m_dr);
2434
2435                 do_lincs(x, xprime, box, pbc, lincsd, th,
2436                          md.invmass, cr,
2437                          bCalcDHDL,
2438                          ir.LincsWarnAngle, &bWarn,
2439                          invdt, v, bCalcVir,
2440                          th == 0 ? vir_r_m_dr : lincsd->task[th].vir_r_m_dr);
2441             }
2442             GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
2443         }
2444
2445         if (debug && lincsd->nc > 0)
2446         {
2447             fprintf(debug, "   Rel. Constraint Deviation:  RMS         MAX     between atoms\n");
2448             fprintf(debug, "       Before LINCS          %.6f    %.6f %6d %6d\n",
2449                     std::sqrt(p_ssd/ncons_loc), p_max,
2450                     ddglatnr(cr->dd, lincsd->bla[2*p_imax]),
2451                     ddglatnr(cr->dd, lincsd->bla[2*p_imax+1]));
2452         }
2453         if (computeRmsd || debug)
2454         {
2455             cconerr(lincsd, xprime, pbc,
2456                     &ncons_loc, &p_ssd, &p_max, &p_imax);
2457             lincsd->rmsdData[0] = ncons_loc;
2458             lincsd->rmsdData[1] = p_ssd;
2459         }
2460         else
2461         {
2462             lincsd->rmsdData = {{0}};
2463         }
2464         if (debug && lincsd->nc > 0)
2465         {
2466             fprintf(debug,
2467                     "        After LINCS          %.6f    %.6f %6d %6d\n\n",
2468                     std::sqrt(p_ssd/ncons_loc), p_max,
2469                     ddglatnr(cr->dd, lincsd->bla[2*p_imax]),
2470                     ddglatnr(cr->dd, lincsd->bla[2*p_imax+1]));
2471         }
2472
2473         if (bWarn)
2474         {
2475             if (maxwarn < INT_MAX)
2476             {
2477                 cconerr(lincsd, xprime, pbc,
2478                         &ncons_loc, &p_ssd, &p_max, &p_imax);
2479                 if (isMultiSim(&ms))
2480                 {
2481                     sprintf(buf3, " in simulation %d", ms.sim);
2482                 }
2483                 else
2484                 {
2485                     buf3[0] = 0;
2486                 }
2487                 fprintf(stderr,
2488                         "\nStep %s, time %g (ps)  LINCS WARNING%s\n"
2489                         "relative constraint deviation after LINCS:\n"
2490                         "rms %.6f, max %.6f (between atoms %d and %d)\n",
2491                         gmx_step_str(step, buf2), ir.init_t+step*ir.delta_t,
2492                         buf3,
2493                         std::sqrt(p_ssd/ncons_loc), p_max,
2494                         ddglatnr(cr->dd, lincsd->bla[2*p_imax]),
2495                         ddglatnr(cr->dd, lincsd->bla[2*p_imax+1]));
2496
2497                 lincs_warning(cr->dd, x, xprime, pbc,
2498                               lincsd->nc, lincsd->bla, lincsd->bllen,
2499                               ir.LincsWarnAngle, maxwarn, warncount);
2500             }
2501             bOK = (p_max < 0.5);
2502         }
2503
2504         if (lincsd->ncg_flex)
2505         {
2506             for (i = 0; (i < lincsd->nc); i++)
2507             {
2508                 if (lincsd->bllen0[i] == 0 && lincsd->ddist[i] == 0)
2509                 {
2510                     lincsd->bllen[i] = 0;
2511                 }
2512             }
2513         }
2514     }
2515     else
2516     {
2517         /* The OpenMP parallel region of constrain_lincs for derivatives */
2518 #pragma omp parallel num_threads(lincsd->ntask)
2519         {
2520             try
2521             {
2522                 int th = gmx_omp_get_thread_num();
2523
2524                 do_lincsp(x, xprime, min_proj, pbc, lincsd, th,
2525                           md.invmass, econq, bCalcDHDL,
2526                           bCalcVir, th == 0 ? vir_r_m_dr : lincsd->task[th].vir_r_m_dr);
2527             }
2528             GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
2529         }
2530     }
2531
2532     if (bCalcDHDL)
2533     {
2534         /* Reduce the dH/dlambda contributions over the threads */
2535         real dhdlambda;
2536         int  th;
2537
2538         dhdlambda = 0;
2539         for (th = 0; th < lincsd->ntask; th++)
2540         {
2541             dhdlambda += lincsd->task[th].dhdlambda;
2542         }
2543         if (econq == ConstraintVariable::Positions)
2544         {
2545             /* dhdlambda contains dH/dlambda*dt^2, correct for this */
2546             /* TODO This should probably use invdt, so that sd integrator scaling works properly */
2547             dhdlambda /= ir.delta_t*ir.delta_t;
2548         }
2549         *dvdlambda += dhdlambda;
2550     }
2551
2552     if (bCalcVir && lincsd->ntask > 1)
2553     {
2554         for (i = 1; i < lincsd->ntask; i++)
2555         {
2556             m_add(vir_r_m_dr, lincsd->task[i].vir_r_m_dr, vir_r_m_dr);
2557         }
2558     }
2559
2560     /* count assuming nit=1 */
2561     inc_nrnb(nrnb, eNR_LINCS, lincsd->nc_real);
2562     inc_nrnb(nrnb, eNR_LINCSMAT, (2+lincsd->nOrder)*lincsd->ncc);
2563     if (lincsd->ntriangle > 0)
2564     {
2565         inc_nrnb(nrnb, eNR_LINCSMAT, lincsd->nOrder*lincsd->ncc_triangle);
2566     }
2567     if (v)
2568     {
2569         inc_nrnb(nrnb, eNR_CONSTR_V, lincsd->nc_real*2);
2570     }
2571     if (bCalcVir)
2572     {
2573         inc_nrnb(nrnb, eNR_CONSTR_VIR, lincsd->nc_real);
2574     }
2575
2576     return bOK;
2577 }
2578
2579 }  // namespace gmx