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