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