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