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