Merge branch release-2019
[alexxy/gromacs.git] / src / gromacs / mdlib / update.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team.
6  * Copyright (c) 2013,2014,2015,2016,2017,2018,2019, by the GROMACS development team, led by
7  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8  * and including many others, as listed in the AUTHORS file in the
9  * top-level source directory and at http://www.gromacs.org.
10  *
11  * GROMACS is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * as published by the Free Software Foundation; either version 2.1
14  * of the License, or (at your option) any later version.
15  *
16  * GROMACS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with GROMACS; if not, see
23  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
25  *
26  * If you want to redistribute modifications to GROMACS, please
27  * consider that scientific software is very special. Version
28  * control is crucial - bugs must be traceable. We will be happy to
29  * consider code for inclusion in the official distribution, but
30  * derived work must not be called official GROMACS. Details are found
31  * in the README & COPYING files - if they are missing, get the
32  * official version at http://www.gromacs.org.
33  *
34  * To help us fund GROMACS development, we humbly ask that you cite
35  * the research papers on the package. Check out http://www.gromacs.org.
36  */
37 #include "gmxpre.h"
38
39 #include "update.h"
40
41 #include <cmath>
42 #include <cstdio>
43
44 #include <algorithm>
45
46 #include "gromacs/compat/make_unique.h"
47 #include "gromacs/domdec/domdec_struct.h"
48 #include "gromacs/fileio/confio.h"
49 #include "gromacs/gmxlib/network.h"
50 #include "gromacs/gmxlib/nrnb.h"
51 #include "gromacs/listed-forces/disre.h"
52 #include "gromacs/listed-forces/orires.h"
53 #include "gromacs/math/functions.h"
54 #include "gromacs/math/invertmatrix.h"
55 #include "gromacs/math/paddedvector.h"
56 #include "gromacs/math/units.h"
57 #include "gromacs/math/vec.h"
58 #include "gromacs/math/vecdump.h"
59 #include "gromacs/mdlib/boxdeformation.h"
60 #include "gromacs/mdlib/constr.h"
61 #include "gromacs/mdlib/gmx_omp_nthreads.h"
62 #include "gromacs/mdlib/mdrun.h"
63 #include "gromacs/mdlib/sim_util.h"
64 #include "gromacs/mdlib/tgroup.h"
65 #include "gromacs/mdtypes/commrec.h"
66 #include "gromacs/mdtypes/group.h"
67 #include "gromacs/mdtypes/inputrec.h"
68 #include "gromacs/mdtypes/md_enums.h"
69 #include "gromacs/mdtypes/state.h"
70 #include "gromacs/pbcutil/boxutilities.h"
71 #include "gromacs/pbcutil/mshift.h"
72 #include "gromacs/pbcutil/pbc.h"
73 #include "gromacs/pulling/pull.h"
74 #include "gromacs/random/tabulatednormaldistribution.h"
75 #include "gromacs/random/threefry.h"
76 #include "gromacs/simd/simd.h"
77 #include "gromacs/timing/wallcycle.h"
78 #include "gromacs/topology/atoms.h"
79 #include "gromacs/utility/exceptions.h"
80 #include "gromacs/utility/fatalerror.h"
81 #include "gromacs/utility/futil.h"
82 #include "gromacs/utility/gmxassert.h"
83 #include "gromacs/utility/gmxomp.h"
84 #include "gromacs/utility/smalloc.h"
85
86 using namespace gmx; // TODO: Remove when this file is moved into gmx namespace
87
88 typedef struct {
89     double em;
90 } gmx_sd_const_t;
91
92 typedef struct {
93     real V;
94 } gmx_sd_sigma_t;
95
96 struct gmx_stochd_t
97 {
98     /* BD stuff */
99     std::vector<real>           bd_rf;
100     /* SD stuff */
101     std::vector<gmx_sd_const_t> sdc;
102     std::vector<gmx_sd_sigma_t> sdsig;
103     /* andersen temperature control stuff */
104     std::vector<bool>           randomize_group;
105     std::vector<real>           boltzfac;
106
107     gmx_stochd_t(const t_inputrec *ir);
108 };
109
110 struct gmx_update_t
111 {
112     std::unique_ptr<gmx_stochd_t> sd;
113     /* xprime for constraint algorithms */
114     PaddedVector<gmx::RVec>       xp;
115
116     /* Variables for the deform algorithm */
117     int64_t           deformref_step;
118     matrix            deformref_box;
119
120     //! Box deformation handler (or nullptr if inactive).
121     gmx::BoxDeformation *deform;
122 };
123
124 static bool isTemperatureCouplingStep(int64_t step, const t_inputrec *ir)
125 {
126     /* We should only couple after a step where energies were determined (for leapfrog versions)
127        or the step energies are determined, for velocity verlet versions */
128     int offset;
129     if (EI_VV(ir->eI))
130     {
131         offset = 0;
132     }
133     else
134     {
135         offset = 1;
136     }
137     return ir->etc != etcNO &&
138            (ir->nsttcouple == 1 ||
139             do_per_step(step + ir->nsttcouple - offset, ir->nsttcouple));
140 }
141
142 static bool isPressureCouplingStep(int64_t step, const t_inputrec *ir)
143 {
144     GMX_ASSERT(ir->epc != epcMTTK, "MTTK pressure coupling is not handled here");
145
146     int offset;
147     if (ir->epc == epcBERENDSEN)
148     {
149         offset = 0;
150     }
151     else
152     {
153         offset = 1;
154     }
155     /* We should only couple after a step where pressures were determined */
156     return ir->epc != etcNO &&
157            (ir->nstpcouple == 1 ||
158             do_per_step(step + ir->nstpcouple - offset, ir->nstpcouple));
159 }
160
161 /*! \brief Sets the velocities of virtual sites to zero */
162 static void clearVsiteVelocities(int                   start,
163                                  int                   nrend,
164                                  const unsigned short *particleType,
165                                  rvec * gmx_restrict   v)
166 {
167     for (int a = start; a < nrend; a++)
168     {
169         if (particleType[a] == eptVSite)
170         {
171             clear_rvec(v[a]);
172         }
173     }
174 }
175
176 /*! \brief Sets the number of different temperature coupling values */
177 enum class NumTempScaleValues
178 {
179     single,   //!< Single T-scaling value (either one group or all values =1)
180     multiple  //!< Multiple T-scaling values, need to use T-group indices
181 };
182
183 /*! \brief Sets if to apply no or diagonal Parrinello-Rahman pressure scaling
184  *
185  * Note that this enum is only used in updateMDLeapfrogSimple(), which does
186  * not handle fully anistropic Parrinello-Rahman scaling, so we only have
187  * options \p no and \p diagonal here and no anistropic option.
188  */
189 enum class ApplyParrinelloRahmanVScaling
190 {
191     no,       //!< Do not apply velocity scaling (not a PR-coupling run or step)
192     diagonal  //!< Apply velocity scaling using a diagonal matrix
193 };
194
195 /*! \brief Integrate using leap-frog with T-scaling and optionally diagonal Parrinello-Rahman p-coupling
196  *
197  * \tparam       numTempScaleValues     The number of different T-couple values
198  * \tparam       applyPRVScaling        Apply Parrinello-Rahman velocity scaling
199  * \param[in]    start                  Index of first atom to update
200  * \param[in]    nrend                  Last atom to update: \p nrend - 1
201  * \param[in]    dt                     The time step
202  * \param[in]    dtPressureCouple       Time step for pressure coupling
203  * \param[in]    invMassPerDim          1/mass per atom and dimension
204  * \param[in]    tcstat                 Temperature coupling information
205  * \param[in]    cTC                    T-coupling group index per atom
206  * \param[in]    pRVScaleMatrixDiagonal Parrinello-Rahman v-scale matrix diagonal
207  * \param[in]    x                      Input coordinates
208  * \param[out]   xprime                 Updated coordinates
209  * \param[inout] v                      Velocities
210  * \param[in]    f                      Forces
211  *
212  * We expect this template to get good SIMD acceleration by most compilers,
213  * unlike the more complex general template.
214  * Note that we might get even better SIMD acceleration when we introduce
215  * aligned (and padded) memory, possibly with some hints for the compilers.
216  */
217 template<NumTempScaleValues            numTempScaleValues,
218          ApplyParrinelloRahmanVScaling applyPRVScaling>
219 static void
220 updateMDLeapfrogSimple(int                       start,
221                        int                       nrend,
222                        real                      dt,
223                        real                      dtPressureCouple,
224                        const rvec * gmx_restrict invMassPerDim,
225                        const t_grp_tcstat      * tcstat,
226                        const unsigned short    * cTC,
227                        const rvec                pRVScaleMatrixDiagonal,
228                        const rvec * gmx_restrict x,
229                        rvec       * gmx_restrict xprime,
230                        rvec       * gmx_restrict v,
231                        const rvec * gmx_restrict f)
232 {
233     real lambdaGroup;
234
235     if (numTempScaleValues == NumTempScaleValues::single)
236     {
237         lambdaGroup = tcstat[0].lambda;
238     }
239
240     for (int a = start; a < nrend; a++)
241     {
242         if (numTempScaleValues == NumTempScaleValues::multiple)
243         {
244             lambdaGroup = tcstat[cTC[a]].lambda;
245         }
246
247         for (int d = 0; d < DIM; d++)
248         {
249             /* Note that using rvec invMassPerDim results in more efficient
250              * SIMD code, but this increases the cache pressure.
251              * For large systems with PME on the CPU this slows down the
252              * (then already slow) update by 20%. If all data remains in cache,
253              * using rvec is much faster.
254              */
255             real vNew = lambdaGroup*v[a][d] + f[a][d]*invMassPerDim[a][d]*dt;
256
257             if (applyPRVScaling == ApplyParrinelloRahmanVScaling::diagonal)
258             {
259                 vNew -= dtPressureCouple*pRVScaleMatrixDiagonal[d]*v[a][d];
260             }
261             v[a][d]      = vNew;
262             xprime[a][d] = x[a][d] + vNew*dt;
263         }
264     }
265 }
266
267 #if GMX_SIMD && GMX_SIMD_HAVE_REAL
268 #define GMX_HAVE_SIMD_UPDATE 1
269 #else
270 #define GMX_HAVE_SIMD_UPDATE 0
271 #endif
272
273 #if GMX_HAVE_SIMD_UPDATE
274
275 /*! \brief Load (aligned) the contents of GMX_SIMD_REAL_WIDTH rvec elements sequentially into 3 SIMD registers
276  *
277  * The loaded output is:
278  * \p r0: { r[index][XX], r[index][YY], ... }
279  * \p r1: { ... }
280  * \p r2: { ..., r[index+GMX_SIMD_REAL_WIDTH-1][YY], r[index+GMX_SIMD_REAL_WIDTH-1][ZZ] }
281  *
282  * \param[in]  r      Real to an rvec array, has to be aligned to SIMD register width
283  * \param[in]  index  Index of the first rvec triplet of reals to load
284  * \param[out] r0     Pointer to first SIMD register
285  * \param[out] r1     Pointer to second SIMD register
286  * \param[out] r2     Pointer to third SIMD register
287  */
288 static inline void simdLoadRvecs(const rvec *r,
289                                  int         index,
290                                  SimdReal   *r0,
291                                  SimdReal   *r1,
292                                  SimdReal   *r2)
293 {
294     const real *realPtr = r[index];
295
296     GMX_ASSERT(isSimdAligned(realPtr), "Pointer should be SIMD aligned");
297
298     *r0 = simdLoad(realPtr + 0*GMX_SIMD_REAL_WIDTH);
299     *r1 = simdLoad(realPtr + 1*GMX_SIMD_REAL_WIDTH);
300     *r2 = simdLoad(realPtr + 2*GMX_SIMD_REAL_WIDTH);
301 }
302
303 /*! \brief Store (aligned) 3 SIMD registers sequentially to GMX_SIMD_REAL_WIDTH rvec elements
304  *
305  * The stored output is:
306  * \p r[index] = { { r0[0], r0[1], ... }
307  * ...
308  * \p r[index+GMX_SIMD_REAL_WIDTH-1] =  { ... , r2[GMX_SIMD_REAL_WIDTH-2], r2[GMX_SIMD_REAL_WIDTH-1] }
309  *
310  * \param[out] r      Pointer to an rvec array, has to be aligned to SIMD register width
311  * \param[in]  index  Index of the first rvec triplet of reals to store to
312  * \param[in]  r0     First SIMD register
313  * \param[in]  r1     Second SIMD register
314  * \param[in]  r2     Third SIMD register
315  */
316 static inline void simdStoreRvecs(rvec     *r,
317                                   int       index,
318                                   SimdReal  r0,
319                                   SimdReal  r1,
320                                   SimdReal  r2)
321 {
322     real *realPtr = r[index];
323
324     GMX_ASSERT(isSimdAligned(realPtr), "Pointer should be SIMD aligned");
325
326     store(realPtr + 0*GMX_SIMD_REAL_WIDTH, r0);
327     store(realPtr + 1*GMX_SIMD_REAL_WIDTH, r1);
328     store(realPtr + 2*GMX_SIMD_REAL_WIDTH, r2);
329 }
330
331 /*! \brief Integrate using leap-frog with single group T-scaling and SIMD
332  *
333  * \param[in]    start                  Index of first atom to update
334  * \param[in]    nrend                  Last atom to update: \p nrend - 1
335  * \param[in]    dt                     The time step
336  * \param[in]    invMass                1/mass per atom
337  * \param[in]    tcstat                 Temperature coupling information
338  * \param[in]    x                      Input coordinates
339  * \param[out]   xprime                 Updated coordinates
340  * \param[inout] v                      Velocities
341  * \param[in]    f                      Forces
342  */
343 static void
344 updateMDLeapfrogSimpleSimd(int                       start,
345                            int                       nrend,
346                            real                      dt,
347                            const real * gmx_restrict invMass,
348                            const t_grp_tcstat      * tcstat,
349                            const rvec * gmx_restrict x,
350                            rvec       * gmx_restrict xprime,
351                            rvec       * gmx_restrict v,
352                            const rvec * gmx_restrict f)
353 {
354     SimdReal                  timestep(dt);
355     SimdReal                  lambdaSystem(tcstat[0].lambda);
356
357     /* We declare variables here, since code is often slower when declaring them inside the loop */
358
359     /* Note: We should implement a proper PaddedVector, so we don't need this check */
360     GMX_ASSERT(isSimdAligned(invMass), "invMass should be aligned");
361
362     for (int a = start; a < nrend; a += GMX_SIMD_REAL_WIDTH)
363     {
364         SimdReal invMass0, invMass1, invMass2;
365         expandScalarsToTriplets(simdLoad(invMass + a),
366                                 &invMass0, &invMass1, &invMass2);
367
368         SimdReal v0, v1, v2;
369         SimdReal f0, f1, f2;
370         simdLoadRvecs(v, a, &v0, &v1, &v2);
371         simdLoadRvecs(f, a, &f0, &f1, &f2);
372
373         v0 = fma(f0*invMass0, timestep, lambdaSystem*v0);
374         v1 = fma(f1*invMass1, timestep, lambdaSystem*v1);
375         v2 = fma(f2*invMass2, timestep, lambdaSystem*v2);
376
377         simdStoreRvecs(v, a, v0, v1, v2);
378
379         SimdReal x0, x1, x2;
380         simdLoadRvecs(x, a, &x0, &x1, &x2);
381
382         SimdReal xprime0 = fma(v0, timestep, x0);
383         SimdReal xprime1 = fma(v1, timestep, x1);
384         SimdReal xprime2 = fma(v2, timestep, x2);
385
386         simdStoreRvecs(xprime, a, xprime0, xprime1, xprime2);
387     }
388 }
389
390 #endif // GMX_HAVE_SIMD_UPDATE
391
392 /*! \brief Sets the NEMD acceleration type */
393 enum class AccelerationType
394 {
395     none, group, cosine
396 };
397
398 /*! \brief Integrate using leap-frog with support for everything
399  *
400  * \tparam       accelerationType       Type of NEMD acceleration
401  * \param[in]    start                  Index of first atom to update
402  * \param[in]    nrend                  Last atom to update: \p nrend - 1
403  * \param[in]    doNoseHoover           If to apply Nose-Hoover T-coupling
404  * \param[in]    dt                     The time step
405  * \param[in]    dtPressureCouple       Time step for pressure coupling, is 0 when no pressure coupling should be applied at this step
406  * \param[in]    ir                     The input parameter record
407  * \param[in]    md                     Atom properties
408  * \param[in]    ekind                  Kinetic energy data
409  * \param[in]    box                    The box dimensions
410  * \param[in]    x                      Input coordinates
411  * \param[out]   xprime                 Updated coordinates
412  * \param[inout] v                      Velocities
413  * \param[in]    f                      Forces
414  * \param[in]    nh_vxi                 Nose-Hoover velocity scaling factors
415  * \param[in]    M                      Parrinello-Rahman scaling matrix
416  */
417 template<AccelerationType accelerationType>
418 static void
419 updateMDLeapfrogGeneral(int                         start,
420                         int                         nrend,
421                         bool                        doNoseHoover,
422                         real                        dt,
423                         real                        dtPressureCouple,
424                         const t_inputrec          * ir,
425                         const t_mdatoms           * md,
426                         const gmx_ekindata_t      * ekind,
427                         const matrix                box,
428                         const rvec   * gmx_restrict x,
429                         rvec         * gmx_restrict xprime,
430                         rvec         * gmx_restrict v,
431                         const rvec   * gmx_restrict f,
432                         const double * gmx_restrict nh_vxi,
433                         const matrix                M)
434 {
435     /* This is a version of the leap-frog integrator that supports
436      * all combinations of T-coupling, P-coupling and NEMD.
437      * Nose-Hoover uses the reversible leap-frog integrator from
438      * Holian et al. Phys Rev E 52(3) : 2338, 1995
439      */
440
441     const unsigned short    * cTC           = md->cTC;
442     const t_grp_tcstat      * tcstat        = ekind->tcstat;
443
444     const unsigned short    * cACC          = md->cACC;
445     const rvec              * accel         = ir->opts.acc;
446     const t_grp_acc         * grpstat       = ekind->grpstat;
447
448     const rvec * gmx_restrict invMassPerDim = md->invMassPerDim;
449
450     /* Initialize group values, changed later when multiple groups are used */
451     int  ga       = 0;
452     int  gt       = 0;
453     real factorNH = 0;
454
455     real omega_Z  = 2*static_cast<real>(M_PI)/box[ZZ][ZZ];
456
457     for (int n = start; n < nrend; n++)
458     {
459         if (cTC)
460         {
461             gt  = cTC[n];
462         }
463         real lg = tcstat[gt].lambda;
464
465         rvec vRel;
466         real cosineZ, vCosine;
467 #ifdef __INTEL_COMPILER
468 #pragma warning( disable : 280 )
469 #endif
470         switch (accelerationType)
471         {
472             case AccelerationType::none:
473                 copy_rvec(v[n], vRel);
474                 break;
475             case AccelerationType::group:
476                 if (cACC)
477                 {
478                     ga = cACC[n];
479                 }
480                 /* Avoid scaling the group velocity */
481                 rvec_sub(v[n], grpstat[ga].u, vRel);
482                 break;
483             case AccelerationType::cosine:
484                 cosineZ = std::cos(x[n][ZZ]*omega_Z);
485                 vCosine = cosineZ*ekind->cosacc.vcos;
486                 /* Avoid scaling the cosine profile velocity */
487                 copy_rvec(v[n], vRel);
488                 vRel[XX] -= vCosine;
489                 break;
490         }
491
492         if (doNoseHoover)
493         {
494             /* Here we account for multiple time stepping, by increasing
495              * the Nose-Hoover correction by nsttcouple
496              */
497             factorNH = 0.5*ir->nsttcouple*dt*nh_vxi[gt];
498         }
499
500         for (int d = 0; d < DIM; d++)
501         {
502             real vNew =
503                 (lg*vRel[d] + (f[n][d]*invMassPerDim[n][d]*dt - factorNH*vRel[d]
504                                - dtPressureCouple*iprod(M[d], vRel)))/(1 + factorNH);
505             switch (accelerationType)
506             {
507                 case AccelerationType::none:
508                     break;
509                 case AccelerationType::group:
510                     /* Add back the mean velocity and apply acceleration */
511                     vNew += grpstat[ga].u[d] + accel[ga][d]*dt;
512                     break;
513                 case AccelerationType::cosine:
514                     if (d == XX)
515                     {
516                         /* Add back the mean velocity and apply acceleration */
517                         vNew += vCosine + cosineZ*ekind->cosacc.cos_accel*dt;
518                     }
519                     break;
520             }
521             v[n][d]       = vNew;
522             xprime[n][d]  = x[n][d] + vNew*dt;
523         }
524     }
525 }
526
527 /*! \brief Handles the Leap-frog MD x and v integration */
528 static void do_update_md(int                         start,
529                          int                         nrend,
530                          int64_t                     step,
531                          real                        dt,
532                          const t_inputrec          * ir,
533                          const t_mdatoms           * md,
534                          const gmx_ekindata_t      * ekind,
535                          const matrix                box,
536                          const rvec   * gmx_restrict x,
537                          rvec         * gmx_restrict xprime,
538                          rvec         * gmx_restrict v,
539                          const rvec   * gmx_restrict f,
540                          const double * gmx_restrict nh_vxi,
541                          const matrix                M)
542 {
543     GMX_ASSERT(nrend == start || xprime != x, "For SIMD optimization certain compilers need to have xprime != x");
544
545     /* Note: Berendsen pressure scaling is handled after do_update_md() */
546     bool doTempCouple       = isTemperatureCouplingStep(step, ir);
547     bool doNoseHoover       = (ir->etc == etcNOSEHOOVER && doTempCouple);
548     bool doParrinelloRahman = (ir->epc == epcPARRINELLORAHMAN && isPressureCouplingStep(step, ir));
549     bool doPROffDiagonal    = (doParrinelloRahman && (M[YY][XX] != 0 || M[ZZ][XX] != 0 || M[ZZ][YY] != 0));
550
551     real dtPressureCouple   = (doParrinelloRahman ? ir->nstpcouple*dt : 0);
552
553     /* NEMD (also cosine) acceleration is applied in updateMDLeapFrogGeneral */
554     bool doAcceleration     = (ekind->bNEMD || ekind->cosacc.cos_accel != 0);
555
556     if (doNoseHoover || doPROffDiagonal || doAcceleration)
557     {
558         matrix stepM;
559         if (!doParrinelloRahman)
560         {
561             /* We should not apply PR scaling at this step */
562             clear_mat(stepM);
563         }
564         else
565         {
566             copy_mat(M, stepM);
567         }
568
569         if (!doAcceleration)
570         {
571             updateMDLeapfrogGeneral<AccelerationType::none>
572                 (start, nrend, doNoseHoover, dt, dtPressureCouple,
573                 ir, md, ekind, box, x, xprime, v, f, nh_vxi, stepM);
574         }
575         else if (ekind->bNEMD)
576         {
577             updateMDLeapfrogGeneral<AccelerationType::group>
578                 (start, nrend, doNoseHoover, dt, dtPressureCouple,
579                 ir, md, ekind, box, x, xprime, v, f, nh_vxi, stepM);
580         }
581         else
582         {
583             updateMDLeapfrogGeneral<AccelerationType::cosine>
584                 (start, nrend, doNoseHoover, dt, dtPressureCouple,
585                 ir, md, ekind, box, x, xprime, v, f, nh_vxi, stepM);
586         }
587     }
588     else
589     {
590         /* Use a simple and thus more efficient integration loop. */
591         /* The simple loop does not check for particle type (so it can
592          * be vectorized), which means we need to clear the velocities
593          * of virtual sites in advance, when present. Note that vsite
594          * velocities are computed after update and constraints from
595          * their displacement.
596          */
597         if (md->haveVsites)
598         {
599             /* Note: The overhead of this loop is completely neligible */
600             clearVsiteVelocities(start, nrend, md->ptype, v);
601         }
602
603         /* We determine if we have a single T-coupling lambda value for all
604          * atoms. That allows for better SIMD acceleration in the template.
605          * If we do not do temperature coupling (in the run or this step),
606          * all scaling values are 1, so we effectively have a single value.
607          */
608         bool haveSingleTempScaleValue = (!doTempCouple || ekind->ngtc == 1);
609
610         /* Extract some pointers needed by all cases */
611         const unsigned short *cTC           = md->cTC;
612         const t_grp_tcstat   *tcstat        = ekind->tcstat;
613         const rvec           *invMassPerDim = md->invMassPerDim;
614
615         if (doParrinelloRahman)
616         {
617             GMX_ASSERT(!doPROffDiagonal, "updateMDLeapfrogSimple only support diagonal Parrinello-Rahman scaling matrices");
618
619             rvec diagM;
620             for (int d = 0; d < DIM; d++)
621             {
622                 diagM[d] = M[d][d];
623             }
624
625             if (haveSingleTempScaleValue)
626             {
627                 updateMDLeapfrogSimple
628                 <NumTempScaleValues::single,
629                  ApplyParrinelloRahmanVScaling::diagonal>
630                     (start, nrend, dt, dtPressureCouple,
631                     invMassPerDim, tcstat, cTC, diagM, x, xprime, v, f);
632             }
633             else
634             {
635                 updateMDLeapfrogSimple
636                 <NumTempScaleValues::multiple,
637                  ApplyParrinelloRahmanVScaling::diagonal>
638                     (start, nrend, dt, dtPressureCouple,
639                     invMassPerDim, tcstat, cTC, diagM, x, xprime, v, f);
640             }
641         }
642         else
643         {
644             if (haveSingleTempScaleValue)
645             {
646                 /* Note that modern compilers are pretty good at vectorizing
647                  * updateMDLeapfrogSimple(). But the SIMD version will still
648                  * be faster because invMass lowers the cache pressure
649                  * compared to invMassPerDim.
650                  */
651 #if GMX_HAVE_SIMD_UPDATE
652                 /* Check if we can use invmass instead of invMassPerDim */
653                 if (!md->havePartiallyFrozenAtoms)
654                 {
655                     updateMDLeapfrogSimpleSimd
656                         (start, nrend, dt, md->invmass, tcstat, x, xprime, v, f);
657                 }
658                 else
659 #endif
660                 {
661                     updateMDLeapfrogSimple
662                     <NumTempScaleValues::single,
663                      ApplyParrinelloRahmanVScaling::no>
664                         (start, nrend, dt, dtPressureCouple,
665                         invMassPerDim, tcstat, cTC, nullptr, x, xprime, v, f);
666                 }
667             }
668             else
669             {
670                 updateMDLeapfrogSimple
671                 <NumTempScaleValues::multiple,
672                  ApplyParrinelloRahmanVScaling::no>
673                     (start, nrend, dt, dtPressureCouple,
674                     invMassPerDim, tcstat, cTC, nullptr, x, xprime, v, f);
675             }
676         }
677     }
678 }
679
680 static void do_update_vv_vel(int start, int nrend, real dt,
681                              const rvec accel[], const ivec nFreeze[], const real invmass[],
682                              const unsigned short ptype[], const unsigned short cFREEZE[],
683                              const unsigned short cACC[], rvec v[], const rvec f[],
684                              gmx_bool bExtended, real veta, real alpha)
685 {
686     int    gf = 0, ga = 0;
687     int    n, d;
688     real   g, mv1, mv2;
689
690     if (bExtended)
691     {
692         g        = 0.25*dt*veta*alpha;
693         mv1      = std::exp(-g);
694         mv2      = gmx::series_sinhx(g);
695     }
696     else
697     {
698         mv1      = 1.0;
699         mv2      = 1.0;
700     }
701     for (n = start; n < nrend; n++)
702     {
703         real w_dt = invmass[n]*dt;
704         if (cFREEZE)
705         {
706             gf   = cFREEZE[n];
707         }
708         if (cACC)
709         {
710             ga   = cACC[n];
711         }
712
713         for (d = 0; d < DIM; d++)
714         {
715             if ((ptype[n] != eptVSite) && (ptype[n] != eptShell) && !nFreeze[gf][d])
716             {
717                 v[n][d]             = mv1*(mv1*v[n][d] + 0.5*(w_dt*mv2*f[n][d]))+0.5*accel[ga][d]*dt;
718             }
719             else
720             {
721                 v[n][d]        = 0.0;
722             }
723         }
724     }
725 } /* do_update_vv_vel */
726
727 static void do_update_vv_pos(int start, int nrend, real dt,
728                              const ivec nFreeze[],
729                              const unsigned short ptype[], const unsigned short cFREEZE[],
730                              const rvec x[], rvec xprime[], const rvec v[],
731                              gmx_bool bExtended, real veta)
732 {
733     int    gf = 0;
734     int    n, d;
735     real   g, mr1, mr2;
736
737     /* Would it make more sense if Parrinello-Rahman was put here? */
738     if (bExtended)
739     {
740         g        = 0.5*dt*veta;
741         mr1      = std::exp(g);
742         mr2      = gmx::series_sinhx(g);
743     }
744     else
745     {
746         mr1      = 1.0;
747         mr2      = 1.0;
748     }
749
750     for (n = start; n < nrend; n++)
751     {
752
753         if (cFREEZE)
754         {
755             gf   = cFREEZE[n];
756         }
757
758         for (d = 0; d < DIM; d++)
759         {
760             if ((ptype[n] != eptVSite) && (ptype[n] != eptShell) && !nFreeze[gf][d])
761             {
762                 xprime[n][d]   = mr1*(mr1*x[n][d]+mr2*dt*v[n][d]);
763             }
764             else
765             {
766                 xprime[n][d]   = x[n][d];
767             }
768         }
769     }
770 } /* do_update_vv_pos */
771
772 gmx_stochd_t::gmx_stochd_t(const t_inputrec *ir)
773 {
774     const t_grpopts *opts = &ir->opts;
775     const int        ngtc = opts->ngtc;
776
777     if (ir->eI == eiBD)
778     {
779         bd_rf.resize(ngtc);
780     }
781     else if (EI_SD(ir->eI))
782     {
783         sdc.resize(ngtc);
784         sdsig.resize(ngtc);
785
786         for (int gt = 0; gt < ngtc; gt++)
787         {
788             if (opts->tau_t[gt] > 0)
789             {
790                 sdc[gt].em  = std::exp(-ir->delta_t/opts->tau_t[gt]);
791             }
792             else
793             {
794                 /* No friction and noise on this group */
795                 sdc[gt].em  = 1;
796             }
797         }
798     }
799     else if (ETC_ANDERSEN(ir->etc))
800     {
801         randomize_group.resize(ngtc);
802         boltzfac.resize(ngtc);
803
804         /* for now, assume that all groups, if randomized, are randomized at the same rate, i.e. tau_t is the same. */
805         /* since constraint groups don't necessarily match up with temperature groups! This is checked in readir.c */
806
807         for (int gt = 0; gt < ngtc; gt++)
808         {
809             real reft = std::max<real>(0, opts->ref_t[gt]);
810             if ((opts->tau_t[gt] > 0) && (reft > 0))  /* tau_t or ref_t = 0 means that no randomization is done */
811             {
812                 randomize_group[gt] = true;
813                 boltzfac[gt]        = BOLTZ*opts->ref_t[gt];
814             }
815             else
816             {
817                 randomize_group[gt] = false;
818             }
819         }
820     }
821 }
822
823 void update_temperature_constants(gmx_update_t *upd, const t_inputrec *ir)
824 {
825     if (ir->eI == eiBD)
826     {
827         if (ir->bd_fric != 0)
828         {
829             for (int gt = 0; gt < ir->opts.ngtc; gt++)
830             {
831                 upd->sd->bd_rf[gt] = std::sqrt(2.0*BOLTZ*ir->opts.ref_t[gt]/(ir->bd_fric*ir->delta_t));
832             }
833         }
834         else
835         {
836             for (int gt = 0; gt < ir->opts.ngtc; gt++)
837             {
838                 upd->sd->bd_rf[gt] = std::sqrt(2.0*BOLTZ*ir->opts.ref_t[gt]);
839             }
840         }
841     }
842     if (ir->eI == eiSD1)
843     {
844         for (int gt = 0; gt < ir->opts.ngtc; gt++)
845         {
846             real kT = BOLTZ*ir->opts.ref_t[gt];
847             /* The mass is accounted for later, since this differs per atom */
848             upd->sd->sdsig[gt].V  = std::sqrt(kT*(1 - upd->sd->sdc[gt].em*upd->sd->sdc[gt].em));
849         }
850     }
851 }
852
853 gmx_update_t *init_update(const t_inputrec    *ir,
854                           gmx::BoxDeformation *deform)
855 {
856     gmx_update_t *upd = new(gmx_update_t);
857
858     upd->sd    = gmx::compat::make_unique<gmx_stochd_t>(ir);
859
860     update_temperature_constants(upd, ir);
861
862     upd->xp.resizeWithPadding(0);
863
864     upd->deform = deform;
865
866     return upd;
867 }
868
869 void update_realloc(gmx_update_t *upd, int natoms)
870 {
871     GMX_ASSERT(upd, "upd must be allocated before its fields can be reallocated");
872
873     upd->xp.resizeWithPadding(natoms);
874 }
875
876 /*! \brief Sets the SD update type */
877 enum class SDUpdate : int
878 {
879     ForcesOnly, FrictionAndNoiseOnly, Combined
880 };
881
882 /*! \brief SD integrator update
883  *
884  * Two phases are required in the general case of a constrained
885  * update, the first phase from the contribution of forces, before
886  * applying constraints, and then a second phase applying the friction
887  * and noise, and then further constraining. For details, see
888  * Goga2012.
889  *
890  * Without constraints, the two phases can be combined, for
891  * efficiency.
892  *
893  * Thus three instantiations of this templated function will be made,
894  * two with only one contribution, and one with both contributions. */
895 template <SDUpdate updateType>
896 static void
897 doSDUpdateGeneral(const gmx_stochd_t &sd,
898                   int start, int nrend, real dt,
899                   const rvec accel[], const ivec nFreeze[],
900                   const real invmass[], const unsigned short ptype[],
901                   const unsigned short cFREEZE[], const unsigned short cACC[],
902                   const unsigned short cTC[],
903                   const rvec x[], rvec xprime[], rvec v[], const rvec f[],
904                   int64_t step, int seed, const int *gatindex)
905 {
906     // cTC, cACC and cFreeze can be nullptr any time, but various
907     // instantiations do not make sense with particular pointer
908     // values.
909     if (updateType == SDUpdate::ForcesOnly)
910     {
911         GMX_ASSERT(f != nullptr, "SD update with only forces requires forces");
912         GMX_ASSERT(cTC == nullptr, "SD update with only forces cannot handle temperature groups");
913     }
914     if (updateType == SDUpdate::FrictionAndNoiseOnly)
915     {
916         GMX_ASSERT(f == nullptr, "SD update with only noise cannot handle forces");
917         GMX_ASSERT(cACC == nullptr, "SD update with only noise cannot handle acceleration groups");
918     }
919     if (updateType == SDUpdate::Combined)
920     {
921         GMX_ASSERT(f != nullptr, "SD update with forces and noise requires forces");
922     }
923
924     // Even 0 bits internal counter gives 2x64 ints (more than enough for three table lookups)
925     gmx::ThreeFry2x64<0> rng(seed, gmx::RandomDomain::UpdateCoordinates);
926     gmx::TabulatedNormalDistribution<real, 14> dist;
927
928     for (int n = start; n < nrend; n++)
929     {
930         int globalAtomIndex = gatindex ? gatindex[n] : n;
931         rng.restart(step, globalAtomIndex);
932         dist.reset();
933
934         real inverseMass     = invmass[n];
935         real invsqrtMass     = std::sqrt(inverseMass);
936
937         int  freezeGroup       = cFREEZE ? cFREEZE[n] : 0;
938         int  accelerationGroup = cACC ? cACC[n] : 0;
939         int  temperatureGroup  = cTC ? cTC[n] : 0;
940
941         for (int d = 0; d < DIM; d++)
942         {
943             if ((ptype[n] != eptVSite) && (ptype[n] != eptShell) && !nFreeze[freezeGroup][d])
944             {
945                 if (updateType == SDUpdate::ForcesOnly)
946                 {
947                     real vn      = v[n][d] + (inverseMass*f[n][d] + accel[accelerationGroup][d])*dt;
948                     v[n][d]      = vn;
949                     // Simple position update.
950                     xprime[n][d] = x[n][d] + v[n][d]*dt;
951                 }
952                 else if (updateType == SDUpdate::FrictionAndNoiseOnly)
953                 {
954                     real vn      = v[n][d];
955                     v[n][d]      = (vn*sd.sdc[temperatureGroup].em +
956                                     invsqrtMass*sd.sdsig[temperatureGroup].V*dist(rng));
957                     // The previous phase already updated the
958                     // positions with a full v*dt term that must
959                     // now be half removed.
960                     xprime[n][d] = xprime[n][d] + 0.5*(v[n][d] - vn)*dt;
961                 }
962                 else
963                 {
964                     real vn      = v[n][d] + (inverseMass*f[n][d] + accel[accelerationGroup][d])*dt;
965                     v[n][d]      = (vn*sd.sdc[temperatureGroup].em +
966                                     invsqrtMass*sd.sdsig[temperatureGroup].V*dist(rng));
967                     // Here we include half of the friction+noise
968                     // update of v into the position update.
969                     xprime[n][d] = x[n][d] + 0.5*(vn + v[n][d])*dt;
970                 }
971             }
972             else
973             {
974                 // When using constraints, the update is split into
975                 // two phases, but we only need to zero the update of
976                 // virtual, shell or frozen particles in at most one
977                 // of the phases.
978                 if (updateType != SDUpdate::FrictionAndNoiseOnly)
979                 {
980                     v[n][d]      = 0.0;
981                     xprime[n][d] = x[n][d];
982                 }
983             }
984         }
985     }
986 }
987
988 static void do_update_bd(int start, int nrend, real dt,
989                          const ivec nFreeze[],
990                          const real invmass[], const unsigned short ptype[],
991                          const unsigned short cFREEZE[], const unsigned short cTC[],
992                          const rvec x[], rvec xprime[], rvec v[],
993                          const rvec f[], real friction_coefficient,
994                          const real *rf, int64_t step, int seed,
995                          const int* gatindex)
996 {
997     /* note -- these appear to be full step velocities . . .  */
998     int    gf = 0, gt = 0;
999     real   vn;
1000     real   invfr = 0;
1001     int    n, d;
1002     // Use 1 bit of internal counters to give us 2*2 64-bits values per stream
1003     // Each 64-bit value is enough for 4 normal distribution table numbers.
1004     gmx::ThreeFry2x64<0> rng(seed, gmx::RandomDomain::UpdateCoordinates);
1005     gmx::TabulatedNormalDistribution<real, 14> dist;
1006
1007     if (friction_coefficient != 0)
1008     {
1009         invfr = 1.0/friction_coefficient;
1010     }
1011
1012     for (n = start; (n < nrend); n++)
1013     {
1014         int  ng  = gatindex ? gatindex[n] : n;
1015
1016         rng.restart(step, ng);
1017         dist.reset();
1018
1019         if (cFREEZE)
1020         {
1021             gf = cFREEZE[n];
1022         }
1023         if (cTC)
1024         {
1025             gt = cTC[n];
1026         }
1027         for (d = 0; (d < DIM); d++)
1028         {
1029             if ((ptype[n] != eptVSite) && (ptype[n] != eptShell) && !nFreeze[gf][d])
1030             {
1031                 if (friction_coefficient != 0)
1032                 {
1033                     vn = invfr*f[n][d] + rf[gt]*dist(rng);
1034                 }
1035                 else
1036                 {
1037                     /* NOTE: invmass = 2/(mass*friction_constant*dt) */
1038                     vn = 0.5*invmass[n]*f[n][d]*dt
1039                         + std::sqrt(0.5*invmass[n])*rf[gt]*dist(rng);
1040                 }
1041
1042                 v[n][d]      = vn;
1043                 xprime[n][d] = x[n][d]+vn*dt;
1044             }
1045             else
1046             {
1047                 v[n][d]      = 0.0;
1048                 xprime[n][d] = x[n][d];
1049             }
1050         }
1051     }
1052 }
1053
1054 static void calc_ke_part_normal(const rvec v[], const t_grpopts *opts, const t_mdatoms *md,
1055                                 gmx_ekindata_t *ekind, t_nrnb *nrnb, gmx_bool bEkinAveVel)
1056 {
1057     int           g;
1058     t_grp_tcstat *tcstat  = ekind->tcstat;
1059     t_grp_acc    *grpstat = ekind->grpstat;
1060     int           nthread, thread;
1061
1062     /* three main: VV with AveVel, vv with AveEkin, leap with AveEkin.  Leap with AveVel is also
1063        an option, but not supported now.
1064        bEkinAveVel: If TRUE, we sum into ekin, if FALSE, into ekinh.
1065      */
1066
1067     /* group velocities are calculated in update_ekindata and
1068      * accumulated in acumulate_groups.
1069      * Now the partial global and groups ekin.
1070      */
1071     for (g = 0; (g < opts->ngtc); g++)
1072     {
1073         copy_mat(tcstat[g].ekinh, tcstat[g].ekinh_old);
1074         if (bEkinAveVel)
1075         {
1076             clear_mat(tcstat[g].ekinf);
1077             tcstat[g].ekinscalef_nhc = 1.0;   /* need to clear this -- logic is complicated! */
1078         }
1079         else
1080         {
1081             clear_mat(tcstat[g].ekinh);
1082         }
1083     }
1084     ekind->dekindl_old = ekind->dekindl;
1085     nthread            = gmx_omp_nthreads_get(emntUpdate);
1086
1087 #pragma omp parallel for num_threads(nthread) schedule(static)
1088     for (thread = 0; thread < nthread; thread++)
1089     {
1090         // This OpenMP only loops over arrays and does not call any functions
1091         // or memory allocation. It should not be able to throw, so for now
1092         // we do not need a try/catch wrapper.
1093         int     start_t, end_t, n;
1094         int     ga, gt;
1095         rvec    v_corrt;
1096         real    hm;
1097         int     d, m;
1098         matrix *ekin_sum;
1099         real   *dekindl_sum;
1100
1101         start_t = ((thread+0)*md->homenr)/nthread;
1102         end_t   = ((thread+1)*md->homenr)/nthread;
1103
1104         ekin_sum    = ekind->ekin_work[thread];
1105         dekindl_sum = ekind->dekindl_work[thread];
1106
1107         for (gt = 0; gt < opts->ngtc; gt++)
1108         {
1109             clear_mat(ekin_sum[gt]);
1110         }
1111         *dekindl_sum = 0.0;
1112
1113         ga = 0;
1114         gt = 0;
1115         for (n = start_t; n < end_t; n++)
1116         {
1117             if (md->cACC)
1118             {
1119                 ga = md->cACC[n];
1120             }
1121             if (md->cTC)
1122             {
1123                 gt = md->cTC[n];
1124             }
1125             hm   = 0.5*md->massT[n];
1126
1127             for (d = 0; (d < DIM); d++)
1128             {
1129                 v_corrt[d]  = v[n][d]  - grpstat[ga].u[d];
1130             }
1131             for (d = 0; (d < DIM); d++)
1132             {
1133                 for (m = 0; (m < DIM); m++)
1134                 {
1135                     /* if we're computing a full step velocity, v_corrt[d] has v(t).  Otherwise, v(t+dt/2) */
1136                     ekin_sum[gt][m][d] += hm*v_corrt[m]*v_corrt[d];
1137                 }
1138             }
1139             if (md->nMassPerturbed && md->bPerturbed[n])
1140             {
1141                 *dekindl_sum +=
1142                     0.5*(md->massB[n] - md->massA[n])*iprod(v_corrt, v_corrt);
1143             }
1144         }
1145     }
1146
1147     ekind->dekindl = 0;
1148     for (thread = 0; thread < nthread; thread++)
1149     {
1150         for (g = 0; g < opts->ngtc; g++)
1151         {
1152             if (bEkinAveVel)
1153             {
1154                 m_add(tcstat[g].ekinf, ekind->ekin_work[thread][g],
1155                       tcstat[g].ekinf);
1156             }
1157             else
1158             {
1159                 m_add(tcstat[g].ekinh, ekind->ekin_work[thread][g],
1160                       tcstat[g].ekinh);
1161             }
1162         }
1163
1164         ekind->dekindl += *ekind->dekindl_work[thread];
1165     }
1166
1167     inc_nrnb(nrnb, eNR_EKIN, md->homenr);
1168 }
1169
1170 static void calc_ke_part_visc(const matrix box, const rvec x[], const rvec v[],
1171                               const t_grpopts *opts, const t_mdatoms *md,
1172                               gmx_ekindata_t *ekind,
1173                               t_nrnb *nrnb, gmx_bool bEkinAveVel)
1174 {
1175     int           start = 0, homenr = md->homenr;
1176     int           g, d, n, m, gt = 0;
1177     rvec          v_corrt;
1178     real          hm;
1179     t_grp_tcstat *tcstat = ekind->tcstat;
1180     t_cos_acc    *cosacc = &(ekind->cosacc);
1181     real          dekindl;
1182     real          fac, cosz;
1183     double        mvcos;
1184
1185     for (g = 0; g < opts->ngtc; g++)
1186     {
1187         copy_mat(ekind->tcstat[g].ekinh, ekind->tcstat[g].ekinh_old);
1188         clear_mat(ekind->tcstat[g].ekinh);
1189     }
1190     ekind->dekindl_old = ekind->dekindl;
1191
1192     fac     = 2*M_PI/box[ZZ][ZZ];
1193     mvcos   = 0;
1194     dekindl = 0;
1195     for (n = start; n < start+homenr; n++)
1196     {
1197         if (md->cTC)
1198         {
1199             gt = md->cTC[n];
1200         }
1201         hm   = 0.5*md->massT[n];
1202
1203         /* Note that the times of x and v differ by half a step */
1204         /* MRS -- would have to be changed for VV */
1205         cosz         = std::cos(fac*x[n][ZZ]);
1206         /* Calculate the amplitude of the new velocity profile */
1207         mvcos       += 2*cosz*md->massT[n]*v[n][XX];
1208
1209         copy_rvec(v[n], v_corrt);
1210         /* Subtract the profile for the kinetic energy */
1211         v_corrt[XX] -= cosz*cosacc->vcos;
1212         for (d = 0; (d < DIM); d++)
1213         {
1214             for (m = 0; (m < DIM); m++)
1215             {
1216                 /* if we're computing a full step velocity, v_corrt[d] has v(t).  Otherwise, v(t+dt/2) */
1217                 if (bEkinAveVel)
1218                 {
1219                     tcstat[gt].ekinf[m][d] += hm*v_corrt[m]*v_corrt[d];
1220                 }
1221                 else
1222                 {
1223                     tcstat[gt].ekinh[m][d] += hm*v_corrt[m]*v_corrt[d];
1224                 }
1225             }
1226         }
1227         if (md->nPerturbed && md->bPerturbed[n])
1228         {
1229             /* The minus sign here might be confusing.
1230              * The kinetic contribution from dH/dl doesn't come from
1231              * d m(l)/2 v^2 / dl, but rather from d p^2/2m(l) / dl,
1232              * where p are the momenta. The difference is only a minus sign.
1233              */
1234             dekindl -= 0.5*(md->massB[n] - md->massA[n])*iprod(v_corrt, v_corrt);
1235         }
1236     }
1237     ekind->dekindl = dekindl;
1238     cosacc->mvcos  = mvcos;
1239
1240     inc_nrnb(nrnb, eNR_EKIN, homenr);
1241 }
1242
1243 void calc_ke_part(const t_state *state, const t_grpopts *opts, const t_mdatoms *md,
1244                   gmx_ekindata_t *ekind, t_nrnb *nrnb, gmx_bool bEkinAveVel)
1245 {
1246     if (ekind->cosacc.cos_accel == 0)
1247     {
1248         calc_ke_part_normal(state->v.rvec_array(), opts, md, ekind, nrnb, bEkinAveVel);
1249     }
1250     else
1251     {
1252         calc_ke_part_visc(state->box, state->x.rvec_array(), state->v.rvec_array(), opts, md, ekind, nrnb, bEkinAveVel);
1253     }
1254 }
1255
1256 extern void init_ekinstate(ekinstate_t *ekinstate, const t_inputrec *ir)
1257 {
1258     ekinstate->ekin_n = ir->opts.ngtc;
1259     snew(ekinstate->ekinh, ekinstate->ekin_n);
1260     snew(ekinstate->ekinf, ekinstate->ekin_n);
1261     snew(ekinstate->ekinh_old, ekinstate->ekin_n);
1262     ekinstate->ekinscalef_nhc.resize(ekinstate->ekin_n);
1263     ekinstate->ekinscaleh_nhc.resize(ekinstate->ekin_n);
1264     ekinstate->vscale_nhc.resize(ekinstate->ekin_n);
1265     ekinstate->dekindl = 0;
1266     ekinstate->mvcos   = 0;
1267 }
1268
1269 void update_ekinstate(ekinstate_t *ekinstate, const gmx_ekindata_t *ekind)
1270 {
1271     int i;
1272
1273     for (i = 0; i < ekinstate->ekin_n; i++)
1274     {
1275         copy_mat(ekind->tcstat[i].ekinh, ekinstate->ekinh[i]);
1276         copy_mat(ekind->tcstat[i].ekinf, ekinstate->ekinf[i]);
1277         copy_mat(ekind->tcstat[i].ekinh_old, ekinstate->ekinh_old[i]);
1278         ekinstate->ekinscalef_nhc[i] = ekind->tcstat[i].ekinscalef_nhc;
1279         ekinstate->ekinscaleh_nhc[i] = ekind->tcstat[i].ekinscaleh_nhc;
1280         ekinstate->vscale_nhc[i]     = ekind->tcstat[i].vscale_nhc;
1281     }
1282
1283     copy_mat(ekind->ekin, ekinstate->ekin_total);
1284     ekinstate->dekindl = ekind->dekindl;
1285     ekinstate->mvcos   = ekind->cosacc.mvcos;
1286
1287 }
1288
1289 void restore_ekinstate_from_state(const t_commrec *cr,
1290                                   gmx_ekindata_t *ekind, const ekinstate_t *ekinstate)
1291 {
1292     int i, n;
1293
1294     if (MASTER(cr))
1295     {
1296         for (i = 0; i < ekinstate->ekin_n; i++)
1297         {
1298             copy_mat(ekinstate->ekinh[i], ekind->tcstat[i].ekinh);
1299             copy_mat(ekinstate->ekinf[i], ekind->tcstat[i].ekinf);
1300             copy_mat(ekinstate->ekinh_old[i], ekind->tcstat[i].ekinh_old);
1301             ekind->tcstat[i].ekinscalef_nhc = ekinstate->ekinscalef_nhc[i];
1302             ekind->tcstat[i].ekinscaleh_nhc = ekinstate->ekinscaleh_nhc[i];
1303             ekind->tcstat[i].vscale_nhc     = ekinstate->vscale_nhc[i];
1304         }
1305
1306         copy_mat(ekinstate->ekin_total, ekind->ekin);
1307
1308         ekind->dekindl      = ekinstate->dekindl;
1309         ekind->cosacc.mvcos = ekinstate->mvcos;
1310         n                   = ekinstate->ekin_n;
1311     }
1312
1313     if (PAR(cr))
1314     {
1315         gmx_bcast(sizeof(n), &n, cr);
1316         for (i = 0; i < n; i++)
1317         {
1318             gmx_bcast(DIM*DIM*sizeof(ekind->tcstat[i].ekinh[0][0]),
1319                       ekind->tcstat[i].ekinh[0], cr);
1320             gmx_bcast(DIM*DIM*sizeof(ekind->tcstat[i].ekinf[0][0]),
1321                       ekind->tcstat[i].ekinf[0], cr);
1322             gmx_bcast(DIM*DIM*sizeof(ekind->tcstat[i].ekinh_old[0][0]),
1323                       ekind->tcstat[i].ekinh_old[0], cr);
1324
1325             gmx_bcast(sizeof(ekind->tcstat[i].ekinscalef_nhc),
1326                       &(ekind->tcstat[i].ekinscalef_nhc), cr);
1327             gmx_bcast(sizeof(ekind->tcstat[i].ekinscaleh_nhc),
1328                       &(ekind->tcstat[i].ekinscaleh_nhc), cr);
1329             gmx_bcast(sizeof(ekind->tcstat[i].vscale_nhc),
1330                       &(ekind->tcstat[i].vscale_nhc), cr);
1331         }
1332         gmx_bcast(DIM*DIM*sizeof(ekind->ekin[0][0]),
1333                   ekind->ekin[0], cr);
1334
1335         gmx_bcast(sizeof(ekind->dekindl), &ekind->dekindl, cr);
1336         gmx_bcast(sizeof(ekind->cosacc.mvcos), &ekind->cosacc.mvcos, cr);
1337     }
1338 }
1339
1340 void update_tcouple(int64_t           step,
1341                     const t_inputrec *inputrec,
1342                     t_state          *state,
1343                     gmx_ekindata_t   *ekind,
1344                     const t_extmass  *MassQ,
1345                     const t_mdatoms  *md)
1346
1347 {
1348     bool doTemperatureCoupling = false;
1349
1350     /* if using vv with trotter decomposition methods, we do this elsewhere in the code */
1351     if (!(EI_VV(inputrec->eI) &&
1352           (inputrecNvtTrotter(inputrec) || inputrecNptTrotter(inputrec) || inputrecNphTrotter(inputrec))))
1353     {
1354         doTemperatureCoupling = isTemperatureCouplingStep(step, inputrec);
1355     }
1356
1357     if (doTemperatureCoupling)
1358     {
1359         real dttc = inputrec->nsttcouple*inputrec->delta_t;
1360
1361         switch (inputrec->etc)
1362         {
1363             case etcNO:
1364                 break;
1365             case etcBERENDSEN:
1366                 berendsen_tcoupl(inputrec, ekind, dttc, state->therm_integral);
1367                 break;
1368             case etcNOSEHOOVER:
1369                 nosehoover_tcoupl(&(inputrec->opts), ekind, dttc,
1370                                   state->nosehoover_xi.data(), state->nosehoover_vxi.data(), MassQ);
1371                 break;
1372             case etcVRESCALE:
1373                 vrescale_tcoupl(inputrec, step, ekind, dttc,
1374                                 state->therm_integral.data());
1375                 break;
1376         }
1377         /* rescale in place here */
1378         if (EI_VV(inputrec->eI))
1379         {
1380             rescale_velocities(ekind, md, 0, md->homenr, state->v.rvec_array());
1381         }
1382     }
1383     else
1384     {
1385         /* Set the T scaling lambda to 1 to have no scaling */
1386         for (int i = 0; (i < inputrec->opts.ngtc); i++)
1387         {
1388             ekind->tcstat[i].lambda = 1.0;
1389         }
1390     }
1391 }
1392
1393 /*! \brief Computes the atom range for a thread to operate on, ensured SIMD aligned ranges
1394  *
1395  * \param[in]  numThreads   The number of threads to divide atoms over
1396  * \param[in]  threadIndex  The thread to get the range for
1397  * \param[in]  numAtoms     The total number of atoms (on this rank)
1398  * \param[out] startAtom    The start of the atom range
1399  * \param[out] endAtom      The end of the atom range, note that this is in general not a multiple of the SIMD width
1400  */
1401 static void getThreadAtomRange(int numThreads, int threadIndex, int numAtoms,
1402                                int *startAtom, int *endAtom)
1403 {
1404 #if GMX_HAVE_SIMD_UPDATE
1405     constexpr int blockSize = GMX_SIMD_REAL_WIDTH;
1406 #else
1407     constexpr int blockSize = 1;
1408 #endif
1409     int           numBlocks = (numAtoms + blockSize - 1)/blockSize;
1410
1411     *startAtom    = ((numBlocks* threadIndex     )/numThreads)*blockSize;
1412     *endAtom      = ((numBlocks*(threadIndex + 1))/numThreads)*blockSize;
1413     if (threadIndex == numThreads - 1)
1414     {
1415         *endAtom  = numAtoms;
1416     }
1417 }
1418
1419 void update_pcouple_before_coordinates(FILE             *fplog,
1420                                        int64_t           step,
1421                                        const t_inputrec *inputrec,
1422                                        t_state          *state,
1423                                        matrix            parrinellorahmanMu,
1424                                        matrix            M,
1425                                        gmx_bool          bInitStep)
1426 {
1427     /* Berendsen P-coupling is completely handled after the coordinate update.
1428      * Trotter P-coupling is handled by separate calls to trotter_update().
1429      */
1430     if (inputrec->epc == epcPARRINELLORAHMAN &&
1431         isPressureCouplingStep(step, inputrec))
1432     {
1433         real dtpc = inputrec->nstpcouple*inputrec->delta_t;
1434
1435         parrinellorahman_pcoupl(fplog, step, inputrec, dtpc, state->pres_prev,
1436                                 state->box, state->box_rel, state->boxv,
1437                                 M, parrinellorahmanMu, bInitStep);
1438     }
1439 }
1440
1441 void constrain_velocities(int64_t                        step,
1442                           real                          *dvdlambda, /* the contribution to be added to the bonded interactions */
1443                           t_state                       *state,
1444                           tensor                         vir_part,
1445                           gmx::Constraints              *constr,
1446                           gmx_bool                       bCalcVir,
1447                           bool                           do_log,
1448                           bool                           do_ene)
1449 {
1450     if (!constr)
1451     {
1452         return;
1453     }
1454
1455     /*
1456      *  Steps (7C, 8C)
1457      *  APPLY CONSTRAINTS:
1458      *  BLOCK SHAKE
1459      */
1460
1461     {
1462         tensor vir_con;
1463
1464         /* clear out constraints before applying */
1465         clear_mat(vir_part);
1466
1467         /* Constrain the coordinates upd->xp */
1468         constr->apply(do_log, do_ene,
1469                       step, 1, 1.0,
1470                       state->x.rvec_array(), state->v.rvec_array(), state->v.rvec_array(),
1471                       state->box,
1472                       state->lambda[efptBONDED], dvdlambda,
1473                       nullptr, bCalcVir ? &vir_con : nullptr, ConstraintVariable::Velocities);
1474
1475         if (bCalcVir)
1476         {
1477             m_add(vir_part, vir_con, vir_part);
1478         }
1479     }
1480 }
1481
1482 void constrain_coordinates(int64_t                        step,
1483                            real                          *dvdlambda, /* the contribution to be added to the bonded interactions */
1484                            t_state                       *state,
1485                            tensor                         vir_part,
1486                            gmx_update_t                  *upd,
1487                            gmx::Constraints              *constr,
1488                            gmx_bool                       bCalcVir,
1489                            bool                           do_log,
1490                            bool                           do_ene)
1491 {
1492     if (!constr)
1493     {
1494         return;
1495     }
1496
1497     {
1498         tensor vir_con;
1499
1500         /* clear out constraints before applying */
1501         clear_mat(vir_part);
1502
1503         /* Constrain the coordinates upd->xp */
1504         constr->apply(do_log, do_ene,
1505                       step, 1, 1.0,
1506                       state->x.rvec_array(), upd->xp.rvec_array(), nullptr,
1507                       state->box,
1508                       state->lambda[efptBONDED], dvdlambda,
1509                       as_rvec_array(state->v.data()), bCalcVir ? &vir_con : nullptr, ConstraintVariable::Positions);
1510
1511         if (bCalcVir)
1512         {
1513             m_add(vir_part, vir_con, vir_part);
1514         }
1515     }
1516 }
1517
1518 void
1519 update_sd_second_half(int64_t                        step,
1520                       real                          *dvdlambda,   /* the contribution to be added to the bonded interactions */
1521                       const t_inputrec              *inputrec,    /* input record and box stuff */
1522                       const t_mdatoms               *md,
1523                       t_state                       *state,
1524                       const t_commrec               *cr,
1525                       t_nrnb                        *nrnb,
1526                       gmx_wallcycle_t                wcycle,
1527                       gmx_update_t                  *upd,
1528                       gmx::Constraints              *constr,
1529                       bool                           do_log,
1530                       bool                           do_ene)
1531 {
1532     if (!constr)
1533     {
1534         return;
1535     }
1536     if (inputrec->eI == eiSD1)
1537     {
1538         int nth, th;
1539         int homenr = md->homenr;
1540
1541         /* Cast delta_t from double to real to make the integrators faster.
1542          * The only reason for having delta_t double is to get accurate values
1543          * for t=delta_t*step when step is larger than float precision.
1544          * For integration dt the accuracy of real suffices, since with
1545          * integral += dt*integrand the increment is nearly always (much) smaller
1546          * than the integral (and the integrand has real precision).
1547          */
1548         real dt     = inputrec->delta_t;
1549
1550         wallcycle_start(wcycle, ewcUPDATE);
1551
1552         nth = gmx_omp_nthreads_get(emntUpdate);
1553
1554 #pragma omp parallel for num_threads(nth) schedule(static)
1555         for (th = 0; th < nth; th++)
1556         {
1557             try
1558             {
1559                 int start_th, end_th;
1560                 getThreadAtomRange(nth, th, homenr, &start_th, &end_th);
1561
1562                 doSDUpdateGeneral<SDUpdate::FrictionAndNoiseOnly>
1563                     (*upd->sd,
1564                     start_th, end_th, dt,
1565                     inputrec->opts.acc, inputrec->opts.nFreeze,
1566                     md->invmass, md->ptype,
1567                     md->cFREEZE, nullptr, md->cTC,
1568                     state->x.rvec_array(), upd->xp.rvec_array(),
1569                     state->v.rvec_array(), nullptr,
1570                     step, inputrec->ld_seed,
1571                     DOMAINDECOMP(cr) ? cr->dd->globalAtomIndices.data() : nullptr);
1572             }
1573             GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
1574         }
1575         inc_nrnb(nrnb, eNR_UPDATE, homenr);
1576         wallcycle_stop(wcycle, ewcUPDATE);
1577
1578         /* Constrain the coordinates upd->xp for half a time step */
1579         constr->apply(do_log, do_ene,
1580                       step, 1, 0.5,
1581                       state->x.rvec_array(), upd->xp.rvec_array(), nullptr,
1582                       state->box,
1583                       state->lambda[efptBONDED], dvdlambda,
1584                       as_rvec_array(state->v.data()), nullptr, ConstraintVariable::Positions);
1585     }
1586 }
1587
1588 void finish_update(const t_inputrec              *inputrec,  /* input record and box stuff      */
1589                    const t_mdatoms               *md,
1590                    t_state                       *state,
1591                    const t_graph                 *graph,
1592                    t_nrnb                        *nrnb,
1593                    gmx_wallcycle_t                wcycle,
1594                    gmx_update_t                  *upd,
1595                    const gmx::Constraints        *constr)
1596 {
1597     int homenr = md->homenr;
1598
1599     /* We must always unshift after updating coordinates; if we did not shake
1600        x was shifted in do_force */
1601
1602     /* NOTE Currently we always integrate to a temporary buffer and
1603      * then copy the results back. */
1604     {
1605         wallcycle_start_nocount(wcycle, ewcUPDATE);
1606
1607         if (md->cFREEZE != nullptr && constr != nullptr)
1608         {
1609             /* If we have atoms that are frozen along some, but not all
1610              * dimensions, then any constraints will have moved them also along
1611              * the frozen dimensions. To freeze such degrees of freedom
1612              * we copy them back here to later copy them forward. It would
1613              * be more elegant and slightly more efficient to copies zero
1614              * times instead of twice, but the graph case below prevents this.
1615              */
1616             const ivec *nFreeze                     = inputrec->opts.nFreeze;
1617             bool        partialFreezeAndConstraints = false;
1618             for (int g = 0; g < inputrec->opts.ngfrz; g++)
1619             {
1620                 int numFreezeDim = nFreeze[g][XX] + nFreeze[g][YY] + nFreeze[g][ZZ];
1621                 if (numFreezeDim > 0 && numFreezeDim < 3)
1622                 {
1623                     partialFreezeAndConstraints = true;
1624                 }
1625             }
1626             if (partialFreezeAndConstraints)
1627             {
1628                 auto xp = makeArrayRef(upd->xp).subArray(0, homenr);
1629                 auto x  = makeConstArrayRef(state->x).subArray(0, homenr);
1630                 for (int i = 0; i < homenr; i++)
1631                 {
1632                     int g = md->cFREEZE[i];
1633
1634                     for (int d = 0; d < DIM; d++)
1635                     {
1636                         if (nFreeze[g][d])
1637                         {
1638                             xp[i][d] = x[i][d];
1639                         }
1640                     }
1641                 }
1642             }
1643         }
1644
1645         if (graph && (graph->nnodes > 0))
1646         {
1647             unshift_x(graph, state->box, state->x.rvec_array(), upd->xp.rvec_array());
1648             if (TRICLINIC(state->box))
1649             {
1650                 inc_nrnb(nrnb, eNR_SHIFTX, 2*graph->nnodes);
1651             }
1652             else
1653             {
1654                 inc_nrnb(nrnb, eNR_SHIFTX, graph->nnodes);
1655             }
1656         }
1657         else
1658         {
1659             auto           xp = makeConstArrayRef(upd->xp).subArray(0, homenr);
1660             auto           x  = makeArrayRef(state->x).subArray(0, homenr);
1661 #ifndef __clang_analyzer__
1662             int gmx_unused nth = gmx_omp_nthreads_get(emntUpdate);
1663 #endif
1664 #pragma omp parallel for num_threads(nth) schedule(static)
1665             for (int i = 0; i < homenr; i++)
1666             {
1667                 // Trivial statement, does not throw
1668                 x[i] = xp[i];
1669             }
1670         }
1671         wallcycle_stop(wcycle, ewcUPDATE);
1672     }
1673     /* ############# END the update of velocities and positions ######### */
1674 }
1675
1676 void update_pcouple_after_coordinates(FILE             *fplog,
1677                                       int64_t           step,
1678                                       const t_inputrec *inputrec,
1679                                       const t_mdatoms  *md,
1680                                       const matrix      pressure,
1681                                       const matrix      forceVirial,
1682                                       const matrix      constraintVirial,
1683                                       const matrix      parrinellorahmanMu,
1684                                       t_state          *state,
1685                                       t_nrnb           *nrnb,
1686                                       gmx_update_t     *upd)
1687 {
1688     int  start  = 0;
1689     int  homenr = md->homenr;
1690
1691     /* Cast to real for faster code, no loss in precision (see comment above) */
1692     real dt     = inputrec->delta_t;
1693
1694
1695     /* now update boxes */
1696     switch (inputrec->epc)
1697     {
1698         case (epcNO):
1699             break;
1700         case (epcBERENDSEN):
1701             if (isPressureCouplingStep(step, inputrec))
1702             {
1703                 real   dtpc = inputrec->nstpcouple*dt;
1704                 matrix mu;
1705                 berendsen_pcoupl(fplog, step, inputrec, dtpc,
1706                                  pressure, state->box,
1707                                  forceVirial, constraintVirial,
1708                                  mu, &state->baros_integral);
1709                 berendsen_pscale(inputrec, mu, state->box, state->box_rel,
1710                                  start, homenr, state->x.rvec_array(),
1711                                  md->cFREEZE, nrnb);
1712             }
1713             break;
1714         case (epcPARRINELLORAHMAN):
1715             if (isPressureCouplingStep(step, inputrec))
1716             {
1717                 /* The box velocities were updated in do_pr_pcoupl,
1718                  * but we dont change the box vectors until we get here
1719                  * since we need to be able to shift/unshift above.
1720                  */
1721                 real dtpc = inputrec->nstpcouple*dt;
1722                 for (int i = 0; i < DIM; i++)
1723                 {
1724                     for (int m = 0; m <= i; m++)
1725                     {
1726                         state->box[i][m] += dtpc*state->boxv[i][m];
1727                     }
1728                 }
1729                 preserve_box_shape(inputrec, state->box_rel, state->box);
1730
1731                 /* Scale the coordinates */
1732                 auto x = state->x.rvec_array();
1733                 for (int n = start; n < start + homenr; n++)
1734                 {
1735                     tmvmul_ur0(parrinellorahmanMu, x[n], x[n]);
1736                 }
1737             }
1738             break;
1739         case (epcMTTK):
1740             switch (inputrec->epct)
1741             {
1742                 case (epctISOTROPIC):
1743                     /* DIM * eta = ln V.  so DIM*eta_new = DIM*eta_old + DIM*dt*veta =>
1744                        ln V_new = ln V_old + 3*dt*veta => V_new = V_old*exp(3*dt*veta) =>
1745                        Side length scales as exp(veta*dt) */
1746
1747                     msmul(state->box, std::exp(state->veta*dt), state->box);
1748
1749                     /* Relate veta to boxv.  veta = d(eta)/dT = (1/DIM)*1/V dV/dT.
1750                        o               If we assume isotropic scaling, and box length scaling
1751                        factor L, then V = L^DIM (det(M)).  So dV/dt = DIM
1752                        L^(DIM-1) dL/dt det(M), and veta = (1/L) dL/dt.  The
1753                        determinant of B is L^DIM det(M), and the determinant
1754                        of dB/dt is (dL/dT)^DIM det (M).  veta will be
1755                        (det(dB/dT)/det(B))^(1/3).  Then since M =
1756                        B_new*(vol_new)^(1/3), dB/dT_new = (veta_new)*B(new). */
1757
1758                     msmul(state->box, state->veta, state->boxv);
1759                     break;
1760                 default:
1761                     break;
1762             }
1763             break;
1764         default:
1765             break;
1766     }
1767
1768     if (upd->deform)
1769     {
1770         auto localX = makeArrayRef(state->x).subArray(start, homenr);
1771         upd->deform->apply(localX, state->box, step);
1772     }
1773 }
1774
1775 void update_coords(int64_t                             step,
1776                    const t_inputrec                   *inputrec, /* input record and box stuff  */
1777                    const t_mdatoms                    *md,
1778                    t_state                            *state,
1779                    gmx::ArrayRefWithPadding<gmx::RVec> f,
1780                    const t_fcdata                     *fcd,
1781                    const gmx_ekindata_t               *ekind,
1782                    const matrix                        M,
1783                    gmx_update_t                       *upd,
1784                    int                                 UpdatePart,
1785                    const t_commrec                    *cr, /* these shouldn't be here -- need to think about it */
1786                    const gmx::Constraints             *constr)
1787 {
1788     gmx_bool bDoConstr = (nullptr != constr);
1789
1790     /* Running the velocity half does nothing except for velocity verlet */
1791     if ((UpdatePart == etrtVELOCITY1 || UpdatePart == etrtVELOCITY2) &&
1792         !EI_VV(inputrec->eI))
1793     {
1794         gmx_incons("update_coords called for velocity without VV integrator");
1795     }
1796
1797     int  homenr = md->homenr;
1798
1799     /* Cast to real for faster code, no loss in precision (see comment above) */
1800     real dt     = inputrec->delta_t;
1801
1802     /* We need to update the NMR restraint history when time averaging is used */
1803     if (state->flags & (1<<estDISRE_RM3TAV))
1804     {
1805         update_disres_history(fcd, &state->hist);
1806     }
1807     if (state->flags & (1<<estORIRE_DTAV))
1808     {
1809         update_orires_history(fcd, &state->hist);
1810     }
1811
1812     /* ############# START The update of velocities and positions ######### */
1813     int nth = gmx_omp_nthreads_get(emntUpdate);
1814
1815 #pragma omp parallel for num_threads(nth) schedule(static)
1816     for (int th = 0; th < nth; th++)
1817     {
1818         try
1819         {
1820             int start_th, end_th;
1821             getThreadAtomRange(nth, th, homenr, &start_th, &end_th);
1822
1823             const rvec *x_rvec  = state->x.rvec_array();
1824             rvec       *xp_rvec = upd->xp.rvec_array();
1825             rvec       *v_rvec  = state->v.rvec_array();
1826             const rvec *f_rvec  = as_rvec_array(f.unpaddedArrayRef().data());
1827
1828             switch (inputrec->eI)
1829             {
1830                 case (eiMD):
1831                     do_update_md(start_th, end_th, step, dt,
1832                                  inputrec, md, ekind, state->box,
1833                                  x_rvec, xp_rvec, v_rvec, f_rvec,
1834                                  state->nosehoover_vxi.data(), M);
1835                     break;
1836                 case (eiSD1):
1837                     if (bDoConstr)
1838                     {
1839                         // With constraints, the SD update is done in 2 parts
1840                         doSDUpdateGeneral<SDUpdate::ForcesOnly>
1841                             (*upd->sd,
1842                             start_th, end_th, dt,
1843                             inputrec->opts.acc, inputrec->opts.nFreeze,
1844                             md->invmass, md->ptype,
1845                             md->cFREEZE, md->cACC, nullptr,
1846                             x_rvec, xp_rvec, v_rvec, f_rvec,
1847                             step, inputrec->ld_seed, nullptr);
1848                     }
1849                     else
1850                     {
1851                         doSDUpdateGeneral<SDUpdate::Combined>
1852                             (*upd->sd,
1853                             start_th, end_th, dt,
1854                             inputrec->opts.acc, inputrec->opts.nFreeze,
1855                             md->invmass, md->ptype,
1856                             md->cFREEZE, md->cACC, md->cTC,
1857                             x_rvec, xp_rvec, v_rvec, f_rvec,
1858                             step, inputrec->ld_seed,
1859                             DOMAINDECOMP(cr) ? cr->dd->globalAtomIndices.data() : nullptr);
1860                     }
1861                     break;
1862                 case (eiBD):
1863                     do_update_bd(start_th, end_th, dt,
1864                                  inputrec->opts.nFreeze, md->invmass, md->ptype,
1865                                  md->cFREEZE, md->cTC,
1866                                  x_rvec, xp_rvec, v_rvec, f_rvec,
1867                                  inputrec->bd_fric,
1868                                  upd->sd->bd_rf.data(),
1869                                  step, inputrec->ld_seed, DOMAINDECOMP(cr) ? cr->dd->globalAtomIndices.data() : nullptr);
1870                     break;
1871                 case (eiVV):
1872                 case (eiVVAK):
1873                 {
1874                     gmx_bool bExtended = (inputrec->etc == etcNOSEHOOVER ||
1875                                           inputrec->epc == epcPARRINELLORAHMAN ||
1876                                           inputrec->epc == epcMTTK);
1877
1878                     /* assuming barostat coupled to group 0 */
1879                     real alpha = 1.0 + DIM/static_cast<real>(inputrec->opts.nrdf[0]);
1880                     switch (UpdatePart)
1881                     {
1882                         case etrtVELOCITY1:
1883                         case etrtVELOCITY2:
1884                             do_update_vv_vel(start_th, end_th, dt,
1885                                              inputrec->opts.acc, inputrec->opts.nFreeze,
1886                                              md->invmass, md->ptype,
1887                                              md->cFREEZE, md->cACC,
1888                                              v_rvec, f_rvec,
1889                                              bExtended, state->veta, alpha);
1890                             break;
1891                         case etrtPOSITION:
1892                             do_update_vv_pos(start_th, end_th, dt,
1893                                              inputrec->opts.nFreeze,
1894                                              md->ptype, md->cFREEZE,
1895                                              x_rvec, xp_rvec, v_rvec,
1896                                              bExtended, state->veta);
1897                             break;
1898                     }
1899                     break;
1900                 }
1901                 default:
1902                     gmx_fatal(FARGS, "Don't know how to update coordinates");
1903             }
1904         }
1905         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
1906     }
1907
1908 }
1909
1910 extern gmx_bool update_randomize_velocities(const t_inputrec *ir, int64_t step, const t_commrec *cr,
1911                                             const t_mdatoms *md,
1912                                             gmx::ArrayRef<gmx::RVec> v,
1913                                             const gmx_update_t *upd,
1914                                             const gmx::Constraints *constr)
1915 {
1916
1917     real rate = (ir->delta_t)/ir->opts.tau_t[0];
1918
1919     if (ir->etc == etcANDERSEN && constr != nullptr)
1920     {
1921         /* Currently, Andersen thermostat does not support constrained
1922            systems. Functionality exists in the andersen_tcoupl
1923            function in GROMACS 4.5.7 to allow this combination. That
1924            code could be ported to the current random-number
1925            generation approach, but has not yet been done because of
1926            lack of time and resources. */
1927         gmx_fatal(FARGS, "Normal Andersen is currently not supported with constraints, use massive Andersen instead");
1928     }
1929
1930     /* proceed with andersen if 1) it's fixed probability per
1931        particle andersen or 2) it's massive andersen and it's tau_t/dt */
1932     if ((ir->etc == etcANDERSEN) || do_per_step(step, roundToInt(1.0/rate)))
1933     {
1934         andersen_tcoupl(ir, step, cr, md, v, rate,
1935                         upd->sd->randomize_group,
1936                         upd->sd->boltzfac);
1937         return TRUE;
1938     }
1939     return FALSE;
1940 }