clang-tidy modernize
[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, 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/domdec/domdec_struct.h"
47 #include "gromacs/fileio/confio.h"
48 #include "gromacs/gmxlib/network.h"
49 #include "gromacs/gmxlib/nrnb.h"
50 #include "gromacs/listed-forces/disre.h"
51 #include "gromacs/listed-forces/orires.h"
52 #include "gromacs/math/functions.h"
53 #include "gromacs/math/invertmatrix.h"
54 #include "gromacs/math/paddedvector.h"
55 #include "gromacs/math/units.h"
56 #include "gromacs/math/vec.h"
57 #include "gromacs/math/vecdump.h"
58 #include "gromacs/mdlib/boxdeformation.h"
59 #include "gromacs/mdlib/constr.h"
60 #include "gromacs/mdlib/gmx_omp_nthreads.h"
61 #include "gromacs/mdlib/mdrun.h"
62 #include "gromacs/mdlib/sim_util.h"
63 #include "gromacs/mdlib/tgroup.h"
64 #include "gromacs/mdtypes/commrec.h"
65 #include "gromacs/mdtypes/group.h"
66 #include "gromacs/mdtypes/inputrec.h"
67 #include "gromacs/mdtypes/md_enums.h"
68 #include "gromacs/mdtypes/state.h"
69 #include "gromacs/pbcutil/boxutilities.h"
70 #include "gromacs/pbcutil/mshift.h"
71 #include "gromacs/pbcutil/pbc.h"
72 #include "gromacs/pulling/pull.h"
73 #include "gromacs/random/tabulatednormaldistribution.h"
74 #include "gromacs/random/threefry.h"
75 #include "gromacs/simd/simd.h"
76 #include "gromacs/timing/wallcycle.h"
77 #include "gromacs/topology/atoms.h"
78 #include "gromacs/utility/exceptions.h"
79 #include "gromacs/utility/fatalerror.h"
80 #include "gromacs/utility/futil.h"
81 #include "gromacs/utility/gmxassert.h"
82 #include "gromacs/utility/gmxomp.h"
83 #include "gromacs/utility/smalloc.h"
84
85 using namespace gmx; // TODO: Remove when this file is moved into gmx namespace
86
87 typedef struct {
88     double em;
89 } gmx_sd_const_t;
90
91 typedef struct {
92     real V;
93 } gmx_sd_sigma_t;
94
95 typedef struct {
96     /* BD stuff */
97     real           *bd_rf;
98     /* SD stuff */
99     gmx_sd_const_t *sdc;
100     gmx_sd_sigma_t *sdsig;
101     /* andersen temperature control stuff */
102     gmx_bool       *randomize_group;
103     real           *boltzfac;
104 } gmx_stochd_t;
105
106 struct gmx_update_t
107 {
108     gmx_stochd_t     *sd;
109     /* xprime for constraint algorithms */
110     PaddedRVecVector  xp;
111
112     /* Variables for the deform algorithm */
113     int64_t           deformref_step;
114     matrix            deformref_box;
115
116     //! Box deformation handler (or nullptr if inactive).
117     gmx::BoxDeformation *deform;
118 };
119
120 static bool isTemperatureCouplingStep(int64_t step, const t_inputrec *ir)
121 {
122     /* We should only couple after a step where energies were determined (for leapfrog versions)
123        or the step energies are determined, for velocity verlet versions */
124     int offset;
125     if (EI_VV(ir->eI))
126     {
127         offset = 0;
128     }
129     else
130     {
131         offset = 1;
132     }
133     return ir->etc != etcNO &&
134            (ir->nsttcouple == 1 ||
135             do_per_step(step + ir->nsttcouple - offset, ir->nsttcouple));
136 }
137
138 static bool isPressureCouplingStep(int64_t step, const t_inputrec *ir)
139 {
140     GMX_ASSERT(ir->epc != epcMTTK, "MTTK pressure coupling is not handled here");
141
142     int offset;
143     if (ir->epc == epcBERENDSEN)
144     {
145         offset = 0;
146     }
147     else
148     {
149         offset = 1;
150     }
151     /* We should only couple after a step where pressures were determined */
152     return ir->epc != etcNO &&
153            (ir->nstpcouple == 1 ||
154             do_per_step(step + ir->nstpcouple - offset, ir->nstpcouple));
155 }
156
157 /*! \brief Sets the velocities of virtual sites to zero */
158 static void clearVsiteVelocities(int                   start,
159                                  int                   nrend,
160                                  const unsigned short *particleType,
161                                  rvec * gmx_restrict   v)
162 {
163     for (int a = start; a < nrend; a++)
164     {
165         if (particleType[a] == eptVSite)
166         {
167             clear_rvec(v[a]);
168         }
169     }
170 }
171
172 /*! \brief Sets the number of different temperature coupling values */
173 enum class NumTempScaleValues
174 {
175     single,   //!< Single T-scaling value (either one group or all values =1)
176     multiple  //!< Multiple T-scaling values, need to use T-group indices
177 };
178
179 /*! \brief Sets if to apply no or diagonal Parrinello-Rahman pressure scaling
180  *
181  * Note that this enum is only used in updateMDLeapfrogSimple(), which does
182  * not handle fully anistropic Parrinello-Rahman scaling, so we only have
183  * options \p no and \p diagonal here and no anistropic option.
184  */
185 enum class ApplyParrinelloRahmanVScaling
186 {
187     no,       //!< Do not apply velocity scaling (not a PR-coupling run or step)
188     diagonal  //!< Apply velocity scaling using a diagonal matrix
189 };
190
191 /*! \brief Integrate using leap-frog with T-scaling and optionally diagonal Parrinello-Rahman p-coupling
192  *
193  * \tparam       numTempScaleValues     The number of different T-couple values
194  * \tparam       applyPRVScaling        Apply Parrinello-Rahman velocity scaling
195  * \param[in]    start                  Index of first atom to update
196  * \param[in]    nrend                  Last atom to update: \p nrend - 1
197  * \param[in]    dt                     The time step
198  * \param[in]    dtPressureCouple       Time step for pressure coupling
199  * \param[in]    invMassPerDim          1/mass per atom and dimension
200  * \param[in]    tcstat                 Temperature coupling information
201  * \param[in]    cTC                    T-coupling group index per atom
202  * \param[in]    pRVScaleMatrixDiagonal Parrinello-Rahman v-scale matrix diagonal
203  * \param[in]    x                      Input coordinates
204  * \param[out]   xprime                 Updated coordinates
205  * \param[inout] v                      Velocities
206  * \param[in]    f                      Forces
207  *
208  * We expect this template to get good SIMD acceleration by most compilers,
209  * unlike the more complex general template.
210  * Note that we might get even better SIMD acceleration when we introduce
211  * aligned (and padded) memory, possibly with some hints for the compilers.
212  */
213 template<NumTempScaleValues            numTempScaleValues,
214          ApplyParrinelloRahmanVScaling applyPRVScaling>
215 static void
216 updateMDLeapfrogSimple(int                       start,
217                        int                       nrend,
218                        real                      dt,
219                        real                      dtPressureCouple,
220                        const rvec * gmx_restrict invMassPerDim,
221                        const t_grp_tcstat      * tcstat,
222                        const unsigned short    * cTC,
223                        const rvec                pRVScaleMatrixDiagonal,
224                        const rvec * gmx_restrict x,
225                        rvec       * gmx_restrict xprime,
226                        rvec       * gmx_restrict v,
227                        const rvec * gmx_restrict f)
228 {
229     real lambdaGroup;
230
231     if (numTempScaleValues == NumTempScaleValues::single)
232     {
233         lambdaGroup = tcstat[0].lambda;
234     }
235
236     for (int a = start; a < nrend; a++)
237     {
238         if (numTempScaleValues == NumTempScaleValues::multiple)
239         {
240             lambdaGroup = tcstat[cTC[a]].lambda;
241         }
242
243         for (int d = 0; d < DIM; d++)
244         {
245             /* Note that using rvec invMassPerDim results in more efficient
246              * SIMD code, but this increases the cache pressure.
247              * For large systems with PME on the CPU this slows down the
248              * (then already slow) update by 20%. If all data remains in cache,
249              * using rvec is much faster.
250              */
251             real vNew = lambdaGroup*v[a][d] + f[a][d]*invMassPerDim[a][d]*dt;
252
253             if (applyPRVScaling == ApplyParrinelloRahmanVScaling::diagonal)
254             {
255                 vNew -= dtPressureCouple*pRVScaleMatrixDiagonal[d]*v[a][d];
256             }
257             v[a][d]      = vNew;
258             xprime[a][d] = x[a][d] + vNew*dt;
259         }
260     }
261 }
262
263 #if GMX_SIMD && GMX_SIMD_HAVE_REAL
264 #define GMX_HAVE_SIMD_UPDATE 1
265 #else
266 #define GMX_HAVE_SIMD_UPDATE 0
267 #endif
268
269 #if GMX_HAVE_SIMD_UPDATE
270
271 /*! \brief Load (aligned) the contents of GMX_SIMD_REAL_WIDTH rvec elements sequentially into 3 SIMD registers
272  *
273  * The loaded output is:
274  * \p r0: { r[index][XX], r[index][YY], ... }
275  * \p r1: { ... }
276  * \p r2: { ..., r[index+GMX_SIMD_REAL_WIDTH-1][YY], r[index+GMX_SIMD_REAL_WIDTH-1][ZZ] }
277  *
278  * \param[in]  r      Real to an rvec array, has to be aligned to SIMD register width
279  * \param[in]  index  Index of the first rvec triplet of reals to load
280  * \param[out] r0     Pointer to first SIMD register
281  * \param[out] r1     Pointer to second SIMD register
282  * \param[out] r2     Pointer to third SIMD register
283  */
284 static inline void simdLoadRvecs(const rvec *r,
285                                  int         index,
286                                  SimdReal   *r0,
287                                  SimdReal   *r1,
288                                  SimdReal   *r2)
289 {
290     const real *realPtr = r[index];
291
292     GMX_ASSERT(isSimdAligned(realPtr), "Pointer should be SIMD aligned");
293
294     *r0 = simdLoad(realPtr + 0*GMX_SIMD_REAL_WIDTH);
295     *r1 = simdLoad(realPtr + 1*GMX_SIMD_REAL_WIDTH);
296     *r2 = simdLoad(realPtr + 2*GMX_SIMD_REAL_WIDTH);
297 }
298
299 /*! \brief Store (aligned) 3 SIMD registers sequentially to GMX_SIMD_REAL_WIDTH rvec elements
300  *
301  * The stored output is:
302  * \p r[index] = { { r0[0], r0[1], ... }
303  * ...
304  * \p r[index+GMX_SIMD_REAL_WIDTH-1] =  { ... , r2[GMX_SIMD_REAL_WIDTH-2], r2[GMX_SIMD_REAL_WIDTH-1] }
305  *
306  * \param[out] r      Pointer to an rvec array, has to be aligned to SIMD register width
307  * \param[in]  index  Index of the first rvec triplet of reals to store to
308  * \param[in]  r0     First SIMD register
309  * \param[in]  r1     Second SIMD register
310  * \param[in]  r2     Third SIMD register
311  */
312 static inline void simdStoreRvecs(rvec     *r,
313                                   int       index,
314                                   SimdReal  r0,
315                                   SimdReal  r1,
316                                   SimdReal  r2)
317 {
318     real *realPtr = r[index];
319
320     GMX_ASSERT(isSimdAligned(realPtr), "Pointer should be SIMD aligned");
321
322     store(realPtr + 0*GMX_SIMD_REAL_WIDTH, r0);
323     store(realPtr + 1*GMX_SIMD_REAL_WIDTH, r1);
324     store(realPtr + 2*GMX_SIMD_REAL_WIDTH, r2);
325 }
326
327 /*! \brief Integrate using leap-frog with single group T-scaling and SIMD
328  *
329  * \param[in]    start                  Index of first atom to update
330  * \param[in]    nrend                  Last atom to update: \p nrend - 1
331  * \param[in]    dt                     The time step
332  * \param[in]    invMass                1/mass per atom
333  * \param[in]    tcstat                 Temperature coupling information
334  * \param[in]    x                      Input coordinates
335  * \param[out]   xprime                 Updated coordinates
336  * \param[inout] v                      Velocities
337  * \param[in]    f                      Forces
338  */
339 static void
340 updateMDLeapfrogSimpleSimd(int                       start,
341                            int                       nrend,
342                            real                      dt,
343                            const real * gmx_restrict invMass,
344                            const t_grp_tcstat      * tcstat,
345                            const rvec * gmx_restrict x,
346                            rvec       * gmx_restrict xprime,
347                            rvec       * gmx_restrict v,
348                            const rvec * gmx_restrict f)
349 {
350     SimdReal                  timestep(dt);
351     SimdReal                  lambdaSystem(tcstat[0].lambda);
352
353     /* We declare variables here, since code is often slower when declaring them inside the loop */
354
355     /* Note: We should implement a proper PaddedVector, so we don't need this check */
356     GMX_ASSERT(isSimdAligned(invMass), "invMass should be aligned");
357
358     for (int a = start; a < nrend; a += GMX_SIMD_REAL_WIDTH)
359     {
360         SimdReal invMass0, invMass1, invMass2;
361         expandScalarsToTriplets(simdLoad(invMass + a),
362                                 &invMass0, &invMass1, &invMass2);
363
364         SimdReal v0, v1, v2;
365         SimdReal f0, f1, f2;
366         simdLoadRvecs(v, a, &v0, &v1, &v2);
367         simdLoadRvecs(f, a, &f0, &f1, &f2);
368
369         v0 = fma(f0*invMass0, timestep, lambdaSystem*v0);
370         v1 = fma(f1*invMass1, timestep, lambdaSystem*v1);
371         v2 = fma(f2*invMass2, timestep, lambdaSystem*v2);
372
373         simdStoreRvecs(v, a, v0, v1, v2);
374
375         SimdReal x0, x1, x2;
376         simdLoadRvecs(x, a, &x0, &x1, &x2);
377
378         SimdReal xprime0 = fma(v0, timestep, x0);
379         SimdReal xprime1 = fma(v1, timestep, x1);
380         SimdReal xprime2 = fma(v2, timestep, x2);
381
382         simdStoreRvecs(xprime, a, xprime0, xprime1, xprime2);
383     }
384 }
385
386 #endif // GMX_HAVE_SIMD_UPDATE
387
388 /*! \brief Sets the NEMD acceleration type */
389 enum class AccelerationType
390 {
391     none, group, cosine
392 };
393
394 /*! \brief Integrate using leap-frog with support for everything
395  *
396  * \tparam       accelerationType       Type of NEMD acceleration
397  * \param[in]    start                  Index of first atom to update
398  * \param[in]    nrend                  Last atom to update: \p nrend - 1
399  * \param[in]    doNoseHoover           If to apply Nose-Hoover T-coupling
400  * \param[in]    dt                     The time step
401  * \param[in]    dtPressureCouple       Time step for pressure coupling, is 0 when no pressure coupling should be applied at this step
402  * \param[in]    ir                     The input parameter record
403  * \param[in]    md                     Atom properties
404  * \param[in]    ekind                  Kinetic energy data
405  * \param[in]    box                    The box dimensions
406  * \param[in]    x                      Input coordinates
407  * \param[out]   xprime                 Updated coordinates
408  * \param[inout] v                      Velocities
409  * \param[in]    f                      Forces
410  * \param[in]    nh_vxi                 Nose-Hoover velocity scaling factors
411  * \param[in]    M                      Parrinello-Rahman scaling matrix
412  */
413 template<AccelerationType accelerationType>
414 static void
415 updateMDLeapfrogGeneral(int                         start,
416                         int                         nrend,
417                         bool                        doNoseHoover,
418                         real                        dt,
419                         real                        dtPressureCouple,
420                         const t_inputrec          * ir,
421                         const t_mdatoms           * md,
422                         const gmx_ekindata_t      * ekind,
423                         const matrix                box,
424                         const rvec   * gmx_restrict x,
425                         rvec         * gmx_restrict xprime,
426                         rvec         * gmx_restrict v,
427                         const rvec   * gmx_restrict f,
428                         const double * gmx_restrict nh_vxi,
429                         const matrix                M)
430 {
431     /* This is a version of the leap-frog integrator that supports
432      * all combinations of T-coupling, P-coupling and NEMD.
433      * Nose-Hoover uses the reversible leap-frog integrator from
434      * Holian et al. Phys Rev E 52(3) : 2338, 1995
435      */
436
437     const unsigned short    * cTC           = md->cTC;
438     const t_grp_tcstat      * tcstat        = ekind->tcstat;
439
440     const unsigned short    * cACC          = md->cACC;
441     const rvec              * accel         = ir->opts.acc;
442     const t_grp_acc         * grpstat       = ekind->grpstat;
443
444     const rvec * gmx_restrict invMassPerDim = md->invMassPerDim;
445
446     /* Initialize group values, changed later when multiple groups are used */
447     int  ga       = 0;
448     int  gt       = 0;
449     real factorNH = 0;
450
451     for (int n = start; n < nrend; n++)
452     {
453         if (cTC)
454         {
455             gt  = cTC[n];
456         }
457         real lg = tcstat[gt].lambda;
458
459         rvec vRel;
460         real cosineZ, vCosine;
461 #ifdef __INTEL_COMPILER
462 #pragma warning( disable : 280 )
463 #endif
464         switch (accelerationType)
465         {
466             case AccelerationType::none:
467                 copy_rvec(v[n], vRel);
468                 break;
469             case AccelerationType::group:
470                 if (cACC)
471                 {
472                     ga = cACC[n];
473                 }
474                 /* Avoid scaling the group velocity */
475                 rvec_sub(v[n], grpstat[ga].u, vRel);
476                 break;
477             case AccelerationType::cosine:
478                 cosineZ = std::cos(x[n][ZZ]*static_cast<real>(M_PI)/box[ZZ][ZZ]);
479                 vCosine = cosineZ*ekind->cosacc.vcos;
480                 /* Avoid scaling the cosine profile velocity */
481                 copy_rvec(v[n], vRel);
482                 vRel[XX] -= vCosine;
483                 break;
484         }
485
486         if (doNoseHoover)
487         {
488             /* Here we account for multiple time stepping, by increasing
489              * the Nose-Hoover correction by nsttcouple
490              */
491             factorNH = 0.5*ir->nsttcouple*dt*nh_vxi[gt];
492         }
493
494         for (int d = 0; d < DIM; d++)
495         {
496             real vNew =
497                 (lg*vRel[d] + (f[n][d]*invMassPerDim[n][d]*dt - factorNH*vRel[d]
498                                - dtPressureCouple*iprod(M[d], vRel)))/(1 + factorNH);
499             switch (accelerationType)
500             {
501                 case AccelerationType::none:
502                     break;
503                 case AccelerationType::group:
504                     /* Add back the mean velocity and apply acceleration */
505                     vNew += grpstat[ga].u[d] + accel[ga][d]*dt;
506                     break;
507                 case AccelerationType::cosine:
508                     if (d == XX)
509                     {
510                         /* Add back the mean velocity and apply acceleration */
511                         vNew += vCosine + cosineZ*ekind->cosacc.cos_accel*dt;
512                     }
513                     break;
514             }
515             v[n][d]       = vNew;
516             xprime[n][d]  = x[n][d] + vNew*dt;
517         }
518     }
519 }
520
521 /*! \brief Handles the Leap-frog MD x and v integration */
522 static void do_update_md(int                         start,
523                          int                         nrend,
524                          int64_t                     step,
525                          real                        dt,
526                          const t_inputrec          * ir,
527                          const t_mdatoms           * md,
528                          const gmx_ekindata_t      * ekind,
529                          const matrix                box,
530                          const rvec   * gmx_restrict x,
531                          rvec         * gmx_restrict xprime,
532                          rvec         * gmx_restrict v,
533                          const rvec   * gmx_restrict f,
534                          const double * gmx_restrict nh_vxi,
535                          const matrix                M)
536 {
537     GMX_ASSERT(nrend == start || xprime != x, "For SIMD optimization certain compilers need to have xprime != x");
538
539     /* Note: Berendsen pressure scaling is handled after do_update_md() */
540     bool doTempCouple       = isTemperatureCouplingStep(step, ir);
541     bool doNoseHoover       = (ir->etc == etcNOSEHOOVER && doTempCouple);
542     bool doParrinelloRahman = (ir->epc == epcPARRINELLORAHMAN && isPressureCouplingStep(step, ir));
543     bool doPROffDiagonal    = (doParrinelloRahman && (M[YY][XX] != 0 || M[ZZ][XX] != 0 || M[ZZ][YY] != 0));
544
545     real dtPressureCouple   = (doParrinelloRahman ? ir->nstpcouple*dt : 0);
546
547     /* NEMD (also cosine) acceleration is applied in updateMDLeapFrogGeneral */
548     bool doAcceleration     = (ekind->bNEMD || ekind->cosacc.cos_accel != 0);
549
550     if (doNoseHoover || doPROffDiagonal || doAcceleration)
551     {
552         matrix stepM;
553         if (!doParrinelloRahman)
554         {
555             /* We should not apply PR scaling at this step */
556             clear_mat(stepM);
557         }
558         else
559         {
560             copy_mat(M, stepM);
561         }
562
563         if (!doAcceleration)
564         {
565             updateMDLeapfrogGeneral<AccelerationType::none>
566                 (start, nrend, doNoseHoover, dt, dtPressureCouple,
567                 ir, md, ekind, box, x, xprime, v, f, nh_vxi, stepM);
568         }
569         else if (ekind->bNEMD)
570         {
571             updateMDLeapfrogGeneral<AccelerationType::group>
572                 (start, nrend, doNoseHoover, dt, dtPressureCouple,
573                 ir, md, ekind, box, x, xprime, v, f, nh_vxi, stepM);
574         }
575         else
576         {
577             updateMDLeapfrogGeneral<AccelerationType::cosine>
578                 (start, nrend, doNoseHoover, dt, dtPressureCouple,
579                 ir, md, ekind, box, x, xprime, v, f, nh_vxi, stepM);
580         }
581     }
582     else
583     {
584         /* Use a simple and thus more efficient integration loop. */
585         /* The simple loop does not check for particle type (so it can
586          * be vectorized), which means we need to clear the velocities
587          * of virtual sites in advance, when present. Note that vsite
588          * velocities are computed after update and constraints from
589          * their displacement.
590          */
591         if (md->haveVsites)
592         {
593             /* Note: The overhead of this loop is completely neligible */
594             clearVsiteVelocities(start, nrend, md->ptype, v);
595         }
596
597         /* We determine if we have a single T-coupling lambda value for all
598          * atoms. That allows for better SIMD acceleration in the template.
599          * If we do not do temperature coupling (in the run or this step),
600          * all scaling values are 1, so we effectively have a single value.
601          */
602         bool haveSingleTempScaleValue = (!doTempCouple || ekind->ngtc == 1);
603
604         /* Extract some pointers needed by all cases */
605         const unsigned short *cTC           = md->cTC;
606         const t_grp_tcstat   *tcstat        = ekind->tcstat;
607         const rvec           *invMassPerDim = md->invMassPerDim;
608
609         if (doParrinelloRahman)
610         {
611             GMX_ASSERT(!doPROffDiagonal, "updateMDLeapfrogSimple only support diagonal Parrinello-Rahman scaling matrices");
612
613             rvec diagM;
614             for (int d = 0; d < DIM; d++)
615             {
616                 diagM[d] = M[d][d];
617             }
618
619             if (haveSingleTempScaleValue)
620             {
621                 updateMDLeapfrogSimple
622                 <NumTempScaleValues::single,
623                  ApplyParrinelloRahmanVScaling::diagonal>
624                     (start, nrend, dt, dtPressureCouple,
625                     invMassPerDim, tcstat, cTC, diagM, x, xprime, v, f);
626             }
627             else
628             {
629                 updateMDLeapfrogSimple
630                 <NumTempScaleValues::multiple,
631                  ApplyParrinelloRahmanVScaling::diagonal>
632                     (start, nrend, dt, dtPressureCouple,
633                     invMassPerDim, tcstat, cTC, diagM, x, xprime, v, f);
634             }
635         }
636         else
637         {
638             if (haveSingleTempScaleValue)
639             {
640                 /* Note that modern compilers are pretty good at vectorizing
641                  * updateMDLeapfrogSimple(). But the SIMD version will still
642                  * be faster because invMass lowers the cache pressure
643                  * compared to invMassPerDim.
644                  */
645 #if GMX_HAVE_SIMD_UPDATE
646                 /* Check if we can use invmass instead of invMassPerDim */
647                 if (!md->havePartiallyFrozenAtoms)
648                 {
649                     updateMDLeapfrogSimpleSimd
650                         (start, nrend, dt, md->invmass, tcstat, x, xprime, v, f);
651                 }
652                 else
653 #endif
654                 {
655                     updateMDLeapfrogSimple
656                     <NumTempScaleValues::single,
657                      ApplyParrinelloRahmanVScaling::no>
658                         (start, nrend, dt, dtPressureCouple,
659                         invMassPerDim, tcstat, cTC, nullptr, x, xprime, v, f);
660                 }
661             }
662             else
663             {
664                 updateMDLeapfrogSimple
665                 <NumTempScaleValues::multiple,
666                  ApplyParrinelloRahmanVScaling::no>
667                     (start, nrend, dt, dtPressureCouple,
668                     invMassPerDim, tcstat, cTC, nullptr, x, xprime, v, f);
669             }
670         }
671     }
672 }
673
674 static void do_update_vv_vel(int start, int nrend, real dt,
675                              rvec accel[], ivec nFreeze[], const real invmass[],
676                              const unsigned short ptype[], const unsigned short cFREEZE[],
677                              const unsigned short cACC[], rvec v[], const rvec f[],
678                              gmx_bool bExtended, real veta, real alpha)
679 {
680     int    gf = 0, ga = 0;
681     int    n, d;
682     real   g, mv1, mv2;
683
684     if (bExtended)
685     {
686         g        = 0.25*dt*veta*alpha;
687         mv1      = std::exp(-g);
688         mv2      = gmx::series_sinhx(g);
689     }
690     else
691     {
692         mv1      = 1.0;
693         mv2      = 1.0;
694     }
695     for (n = start; n < nrend; n++)
696     {
697         real w_dt = invmass[n]*dt;
698         if (cFREEZE)
699         {
700             gf   = cFREEZE[n];
701         }
702         if (cACC)
703         {
704             ga   = cACC[n];
705         }
706
707         for (d = 0; d < DIM; d++)
708         {
709             if ((ptype[n] != eptVSite) && (ptype[n] != eptShell) && !nFreeze[gf][d])
710             {
711                 v[n][d]             = mv1*(mv1*v[n][d] + 0.5*(w_dt*mv2*f[n][d]))+0.5*accel[ga][d]*dt;
712             }
713             else
714             {
715                 v[n][d]        = 0.0;
716             }
717         }
718     }
719 } /* do_update_vv_vel */
720
721 static void do_update_vv_pos(int start, int nrend, real dt,
722                              ivec nFreeze[],
723                              const unsigned short ptype[], const unsigned short cFREEZE[],
724                              const rvec x[], rvec xprime[], rvec v[],
725                              gmx_bool bExtended, real veta)
726 {
727     int    gf = 0;
728     int    n, d;
729     real   g, mr1, mr2;
730
731     /* Would it make more sense if Parrinello-Rahman was put here? */
732     if (bExtended)
733     {
734         g        = 0.5*dt*veta;
735         mr1      = std::exp(g);
736         mr2      = gmx::series_sinhx(g);
737     }
738     else
739     {
740         mr1      = 1.0;
741         mr2      = 1.0;
742     }
743
744     for (n = start; n < nrend; n++)
745     {
746
747         if (cFREEZE)
748         {
749             gf   = cFREEZE[n];
750         }
751
752         for (d = 0; d < DIM; d++)
753         {
754             if ((ptype[n] != eptVSite) && (ptype[n] != eptShell) && !nFreeze[gf][d])
755             {
756                 xprime[n][d]   = mr1*(mr1*x[n][d]+mr2*dt*v[n][d]);
757             }
758             else
759             {
760                 xprime[n][d]   = x[n][d];
761             }
762         }
763     }
764 } /* do_update_vv_pos */
765
766 static gmx_stochd_t *init_stochd(const t_inputrec *ir)
767 {
768     gmx_stochd_t   *sd;
769
770     snew(sd, 1);
771
772     const t_grpopts *opts = &ir->opts;
773     int              ngtc = opts->ngtc;
774
775     if (ir->eI == eiBD)
776     {
777         snew(sd->bd_rf, ngtc);
778     }
779     else if (EI_SD(ir->eI))
780     {
781         snew(sd->sdc, ngtc);
782         snew(sd->sdsig, ngtc);
783
784         gmx_sd_const_t *sdc = sd->sdc;
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         snew(sd->randomize_group, ngtc);
802         snew(sd->boltzfac, 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                 sd->randomize_group[gt] = TRUE;
813                 sd->boltzfac[gt]        = BOLTZ*opts->ref_t[gt];
814             }
815             else
816             {
817                 sd->randomize_group[gt] = FALSE;
818             }
819         }
820     }
821
822     return sd;
823 }
824
825 void update_temperature_constants(gmx_update_t *upd, const t_inputrec *ir)
826 {
827     if (ir->eI == eiBD)
828     {
829         if (ir->bd_fric != 0)
830         {
831             for (int gt = 0; gt < ir->opts.ngtc; gt++)
832             {
833                 upd->sd->bd_rf[gt] = std::sqrt(2.0*BOLTZ*ir->opts.ref_t[gt]/(ir->bd_fric*ir->delta_t));
834             }
835         }
836         else
837         {
838             for (int gt = 0; gt < ir->opts.ngtc; gt++)
839             {
840                 upd->sd->bd_rf[gt] = std::sqrt(2.0*BOLTZ*ir->opts.ref_t[gt]);
841             }
842         }
843     }
844     if (ir->eI == eiSD1)
845     {
846         for (int gt = 0; gt < ir->opts.ngtc; gt++)
847         {
848             real kT = BOLTZ*ir->opts.ref_t[gt];
849             /* The mass is accounted for later, since this differs per atom */
850             upd->sd->sdsig[gt].V  = std::sqrt(kT*(1 - upd->sd->sdc[gt].em*upd->sd->sdc[gt].em));
851         }
852     }
853 }
854
855 gmx_update_t *init_update(const t_inputrec    *ir,
856                           gmx::BoxDeformation *deform)
857 {
858     gmx_update_t *upd = new(gmx_update_t);
859
860     if (ir->eI == eiBD || EI_SD(ir->eI) || ir->etc == etcVRESCALE || ETC_ANDERSEN(ir->etc))
861     {
862         upd->sd    = init_stochd(ir);
863     }
864
865     update_temperature_constants(upd, ir);
866
867     upd->xp.resize(0);
868
869     upd->deform = deform;
870
871     return upd;
872 }
873
874 void update_realloc(gmx_update_t *upd, int natoms)
875 {
876     GMX_ASSERT(upd, "upd must be allocated before its fields can be reallocated");
877
878     upd->xp.resize(gmx::paddedRVecVectorSize(natoms));
879 }
880
881 /*! \brief Sets the SD update type */
882 enum class SDUpdate : int
883 {
884     ForcesOnly, FrictionAndNoiseOnly, Combined
885 };
886
887 /*! \brief SD integrator update
888  *
889  * Two phases are required in the general case of a constrained
890  * update, the first phase from the contribution of forces, before
891  * applying constraints, and then a second phase applying the friction
892  * and noise, and then further constraining. For details, see
893  * Goga2012.
894  *
895  * Without constraints, the two phases can be combined, for
896  * efficiency.
897  *
898  * Thus three instantiations of this templated function will be made,
899  * two with only one contribution, and one with both contributions. */
900 template <SDUpdate updateType>
901 static void
902 doSDUpdateGeneral(gmx_stochd_t *sd,
903                   int start, int nrend, real dt,
904                   rvec accel[], ivec nFreeze[],
905                   const real invmass[], const unsigned short ptype[],
906                   const unsigned short cFREEZE[], const unsigned short cACC[],
907                   const unsigned short cTC[],
908                   const rvec x[], rvec xprime[], rvec v[], const rvec f[],
909                   int64_t step, int seed, const int *gatindex)
910 {
911     if (updateType != SDUpdate::FrictionAndNoiseOnly)
912     {
913         GMX_ASSERT(f != nullptr, "SD update with forces requires forces");
914         GMX_ASSERT(cACC != nullptr, "SD update with forces requires acceleration groups");
915     }
916     if (updateType != SDUpdate::ForcesOnly)
917     {
918         GMX_ASSERT(cTC != nullptr, "SD update with noise requires temperature groups");
919     }
920
921     // Even 0 bits internal counter gives 2x64 ints (more than enough for three table lookups)
922     gmx::ThreeFry2x64<0> rng(seed, gmx::RandomDomain::UpdateCoordinates);
923     gmx::TabulatedNormalDistribution<real, 14> dist;
924
925     gmx_sd_const_t *sdc = sd->sdc;
926     gmx_sd_sigma_t *sig = sd->sdsig;
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*sdc[temperatureGroup].em +
956                                     invsqrtMass*sig[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*sdc[temperatureGroup].em +
966                                     invsqrtMass*sig[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                          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(rvec v[], t_grpopts *opts, 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(matrix box, rvec x[], rvec v[],
1171                               t_grpopts *opts, 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(t_state *state, t_grpopts *opts, 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(as_rvec_array(state->v.data()), opts, md, ekind, nrnb, bEkinAveVel);
1249     }
1250     else
1251     {
1252         calc_ke_part_visc(state->box, as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), 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, 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                     t_inputrec       *inputrec,
1342                     t_state          *state,
1343                     gmx_ekindata_t   *ekind,
1344                     t_extmass        *MassQ,
1345                     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, as_rvec_array(state->v.data()));
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_wallcycle_t                wcycle,
1446                           gmx::Constraints              *constr,
1447                           gmx_bool                       bCalcVir,
1448                           bool                           do_log,
1449                           bool                           do_ene)
1450 {
1451     if (!constr)
1452     {
1453         return;
1454     }
1455
1456     /*
1457      *  Steps (7C, 8C)
1458      *  APPLY CONSTRAINTS:
1459      *  BLOCK SHAKE
1460      */
1461
1462     {
1463         tensor vir_con;
1464
1465         /* clear out constraints before applying */
1466         clear_mat(vir_part);
1467
1468         /* Constrain the coordinates upd->xp */
1469         wallcycle_start(wcycle, ewcCONSTR);
1470         {
1471             constr->apply(do_log, do_ene,
1472                           step, 1, 1.0,
1473                           as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), as_rvec_array(state->v.data()),
1474                           state->box,
1475                           state->lambda[efptBONDED], dvdlambda,
1476                           nullptr, bCalcVir ? &vir_con : nullptr, ConstraintVariable::Velocities);
1477         }
1478         wallcycle_stop(wcycle, ewcCONSTR);
1479
1480         if (bCalcVir)
1481         {
1482             m_add(vir_part, vir_con, vir_part);
1483         }
1484     }
1485 }
1486
1487 void constrain_coordinates(int64_t                        step,
1488                            real                          *dvdlambda, /* the contribution to be added to the bonded interactions */
1489                            t_state                       *state,
1490                            tensor                         vir_part,
1491                            gmx_wallcycle_t                wcycle,
1492                            gmx_update_t                  *upd,
1493                            gmx::Constraints              *constr,
1494                            gmx_bool                       bCalcVir,
1495                            bool                           do_log,
1496                            bool                           do_ene)
1497 {
1498     if (!constr)
1499     {
1500         return;
1501     }
1502
1503     {
1504         tensor vir_con;
1505
1506         /* clear out constraints before applying */
1507         clear_mat(vir_part);
1508
1509         /* Constrain the coordinates upd->xp */
1510         wallcycle_start(wcycle, ewcCONSTR);
1511         {
1512             constr->apply(do_log, do_ene,
1513                           step, 1, 1.0,
1514                           as_rvec_array(state->x.data()), as_rvec_array(upd->xp.data()), nullptr,
1515                           state->box,
1516                           state->lambda[efptBONDED], dvdlambda,
1517                           as_rvec_array(state->v.data()), bCalcVir ? &vir_con : nullptr, ConstraintVariable::Positions);
1518         }
1519         wallcycle_stop(wcycle, ewcCONSTR);
1520
1521         if (bCalcVir)
1522         {
1523             m_add(vir_part, vir_con, vir_part);
1524         }
1525     }
1526 }
1527
1528 void
1529 update_sd_second_half(int64_t                        step,
1530                       real                          *dvdlambda,   /* the contribution to be added to the bonded interactions */
1531                       const t_inputrec              *inputrec,    /* input record and box stuff */
1532                       t_mdatoms                     *md,
1533                       t_state                       *state,
1534                       const t_commrec               *cr,
1535                       t_nrnb                        *nrnb,
1536                       gmx_wallcycle_t                wcycle,
1537                       gmx_update_t                  *upd,
1538                       gmx::Constraints              *constr,
1539                       bool                           do_log,
1540                       bool                           do_ene)
1541 {
1542     if (!constr)
1543     {
1544         return;
1545     }
1546     if (inputrec->eI == eiSD1)
1547     {
1548         int nth, th;
1549         int homenr = md->homenr;
1550
1551         /* Cast delta_t from double to real to make the integrators faster.
1552          * The only reason for having delta_t double is to get accurate values
1553          * for t=delta_t*step when step is larger than float precision.
1554          * For integration dt the accuracy of real suffices, since with
1555          * integral += dt*integrand the increment is nearly always (much) smaller
1556          * than the integral (and the integrand has real precision).
1557          */
1558         real dt     = inputrec->delta_t;
1559
1560         wallcycle_start(wcycle, ewcUPDATE);
1561
1562         nth = gmx_omp_nthreads_get(emntUpdate);
1563
1564 #pragma omp parallel for num_threads(nth) schedule(static)
1565         for (th = 0; th < nth; th++)
1566         {
1567             try
1568             {
1569                 int start_th, end_th;
1570                 getThreadAtomRange(nth, th, homenr, &start_th, &end_th);
1571
1572                 doSDUpdateGeneral<SDUpdate::FrictionAndNoiseOnly>
1573                     (upd->sd,
1574                     start_th, end_th, dt,
1575                     inputrec->opts.acc, inputrec->opts.nFreeze,
1576                     md->invmass, md->ptype,
1577                     md->cFREEZE, nullptr, md->cTC,
1578                     as_rvec_array(state->x.data()), as_rvec_array(upd->xp.data()),
1579                     as_rvec_array(state->v.data()), nullptr,
1580                     step, inputrec->ld_seed,
1581                     DOMAINDECOMP(cr) ? cr->dd->globalAtomIndices.data() : nullptr);
1582             }
1583             GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
1584         }
1585         inc_nrnb(nrnb, eNR_UPDATE, homenr);
1586         wallcycle_stop(wcycle, ewcUPDATE);
1587
1588         {
1589             /* Constrain the coordinates upd->xp for half a time step */
1590             wallcycle_start(wcycle, ewcCONSTR);
1591             constr->apply(do_log, do_ene,
1592                           step, 1, 0.5,
1593                           as_rvec_array(state->x.data()), as_rvec_array(upd->xp.data()), nullptr,
1594                           state->box,
1595                           state->lambda[efptBONDED], dvdlambda,
1596                           as_rvec_array(state->v.data()), nullptr, ConstraintVariable::Positions);
1597             wallcycle_stop(wcycle, ewcCONSTR);
1598         }
1599     }
1600 }
1601
1602 void finish_update(const t_inputrec              *inputrec,  /* input record and box stuff      */
1603                    t_mdatoms                     *md,
1604                    t_state                       *state,
1605                    t_graph                       *graph,
1606                    t_nrnb                        *nrnb,
1607                    gmx_wallcycle_t                wcycle,
1608                    gmx_update_t                  *upd,
1609                    gmx::Constraints              *constr)
1610 {
1611     int homenr = md->homenr;
1612
1613     /* We must always unshift after updating coordinates; if we did not shake
1614        x was shifted in do_force */
1615
1616     /* NOTE Currently we always integrate to a temporary buffer and
1617      * then copy the results back. */
1618     {
1619         wallcycle_start_nocount(wcycle, ewcUPDATE);
1620
1621         if (md->cFREEZE != nullptr && constr != nullptr)
1622         {
1623             /* If we have atoms that are frozen along some, but not all
1624              * dimensions, then any constraints will have moved them also along
1625              * the frozen dimensions. To freeze such degrees of freedom
1626              * we copy them back here to later copy them forward. It would
1627              * be more elegant and slightly more efficient to copies zero
1628              * times instead of twice, but the graph case below prevents this.
1629              */
1630             const ivec *nFreeze                     = inputrec->opts.nFreeze;
1631             bool        partialFreezeAndConstraints = false;
1632             for (int g = 0; g < inputrec->opts.ngfrz; g++)
1633             {
1634                 int numFreezeDim = nFreeze[g][XX] + nFreeze[g][YY] + nFreeze[g][ZZ];
1635                 if (numFreezeDim > 0 && numFreezeDim < 3)
1636                 {
1637                     partialFreezeAndConstraints = true;
1638                 }
1639             }
1640             if (partialFreezeAndConstraints)
1641             {
1642                 for (int i = 0; i < homenr; i++)
1643                 {
1644                     int g = md->cFREEZE[i];
1645
1646                     for (int d = 0; d < DIM; d++)
1647                     {
1648                         if (nFreeze[g][d])
1649                         {
1650                             upd->xp[i][d] = state->x[i][d];
1651                         }
1652                     }
1653                 }
1654             }
1655         }
1656
1657         if (graph && (graph->nnodes > 0))
1658         {
1659             unshift_x(graph, state->box, as_rvec_array(state->x.data()), as_rvec_array(upd->xp.data()));
1660             if (TRICLINIC(state->box))
1661             {
1662                 inc_nrnb(nrnb, eNR_SHIFTX, 2*graph->nnodes);
1663             }
1664             else
1665             {
1666                 inc_nrnb(nrnb, eNR_SHIFTX, graph->nnodes);
1667             }
1668         }
1669         else
1670         {
1671             /* The copy is performance sensitive, so use a bare pointer */
1672             rvec          *xp = as_rvec_array(upd->xp.data());
1673 #ifndef __clang_analyzer__
1674             int gmx_unused nth = gmx_omp_nthreads_get(emntUpdate);
1675 #endif
1676 #pragma omp parallel for num_threads(nth) schedule(static)
1677             for (int i = 0; i < homenr; i++)
1678             {
1679                 // Trivial statement, does not throw
1680                 copy_rvec(xp[i], state->x[i]);
1681             }
1682         }
1683         wallcycle_stop(wcycle, ewcUPDATE);
1684     }
1685     /* ############# END the update of velocities and positions ######### */
1686 }
1687
1688 void update_pcouple_after_coordinates(FILE             *fplog,
1689                                       int64_t           step,
1690                                       const t_inputrec *inputrec,
1691                                       const t_mdatoms  *md,
1692                                       const matrix      pressure,
1693                                       const matrix      forceVirial,
1694                                       const matrix      constraintVirial,
1695                                       const matrix      parrinellorahmanMu,
1696                                       t_state          *state,
1697                                       t_nrnb           *nrnb,
1698                                       gmx_update_t     *upd)
1699 {
1700     int  start  = 0;
1701     int  homenr = md->homenr;
1702
1703     /* Cast to real for faster code, no loss in precision (see comment above) */
1704     real dt     = inputrec->delta_t;
1705
1706
1707     /* now update boxes */
1708     switch (inputrec->epc)
1709     {
1710         case (epcNO):
1711             break;
1712         case (epcBERENDSEN):
1713             if (isPressureCouplingStep(step, inputrec))
1714             {
1715                 real   dtpc = inputrec->nstpcouple*dt;
1716                 matrix mu;
1717                 berendsen_pcoupl(fplog, step, inputrec, dtpc,
1718                                  pressure, state->box,
1719                                  forceVirial, constraintVirial,
1720                                  mu, &state->baros_integral);
1721                 berendsen_pscale(inputrec, mu, state->box, state->box_rel,
1722                                  start, homenr, as_rvec_array(state->x.data()),
1723                                  md->cFREEZE, nrnb);
1724             }
1725             break;
1726         case (epcPARRINELLORAHMAN):
1727             if (isPressureCouplingStep(step, inputrec))
1728             {
1729                 /* The box velocities were updated in do_pr_pcoupl,
1730                  * but we dont change the box vectors until we get here
1731                  * since we need to be able to shift/unshift above.
1732                  */
1733                 real dtpc = inputrec->nstpcouple*dt;
1734                 for (int i = 0; i < DIM; i++)
1735                 {
1736                     for (int m = 0; m <= i; m++)
1737                     {
1738                         state->box[i][m] += dtpc*state->boxv[i][m];
1739                     }
1740                 }
1741                 preserve_box_shape(inputrec, state->box_rel, state->box);
1742
1743                 /* Scale the coordinates */
1744                 for (int n = start; n < start + homenr; n++)
1745                 {
1746                     tmvmul_ur0(parrinellorahmanMu, state->x[n], state->x[n]);
1747                 }
1748             }
1749             break;
1750         case (epcMTTK):
1751             switch (inputrec->epct)
1752             {
1753                 case (epctISOTROPIC):
1754                     /* DIM * eta = ln V.  so DIM*eta_new = DIM*eta_old + DIM*dt*veta =>
1755                        ln V_new = ln V_old + 3*dt*veta => V_new = V_old*exp(3*dt*veta) =>
1756                        Side length scales as exp(veta*dt) */
1757
1758                     msmul(state->box, std::exp(state->veta*dt), state->box);
1759
1760                     /* Relate veta to boxv.  veta = d(eta)/dT = (1/DIM)*1/V dV/dT.
1761                        o               If we assume isotropic scaling, and box length scaling
1762                        factor L, then V = L^DIM (det(M)).  So dV/dt = DIM
1763                        L^(DIM-1) dL/dt det(M), and veta = (1/L) dL/dt.  The
1764                        determinant of B is L^DIM det(M), and the determinant
1765                        of dB/dt is (dL/dT)^DIM det (M).  veta will be
1766                        (det(dB/dT)/det(B))^(1/3).  Then since M =
1767                        B_new*(vol_new)^(1/3), dB/dT_new = (veta_new)*B(new). */
1768
1769                     msmul(state->box, state->veta, state->boxv);
1770                     break;
1771                 default:
1772                     break;
1773             }
1774             break;
1775         default:
1776             break;
1777     }
1778
1779     if (upd->deform)
1780     {
1781         auto localX = gmx::ArrayRef<gmx::RVec>(state->x).subArray(start, homenr);
1782         upd->deform->apply(localX, state->box, step);
1783     }
1784 }
1785
1786 void update_coords(int64_t                        step,
1787                    t_inputrec                    *inputrec, /* input record and box stuff       */
1788                    t_mdatoms                     *md,
1789                    t_state                       *state,
1790                    gmx::PaddedArrayRef<gmx::RVec> f,        /* forces on home particles */
1791                    t_fcdata                      *fcd,
1792                    gmx_ekindata_t                *ekind,
1793                    matrix                         M,
1794                    gmx_update_t                  *upd,
1795                    int                            UpdatePart,
1796                    const t_commrec               *cr, /* these shouldn't be here -- need to think about it */
1797                    gmx::Constraints              *constr)
1798 {
1799     gmx_bool bDoConstr = (nullptr != constr);
1800
1801     /* Running the velocity half does nothing except for velocity verlet */
1802     if ((UpdatePart == etrtVELOCITY1 || UpdatePart == etrtVELOCITY2) &&
1803         !EI_VV(inputrec->eI))
1804     {
1805         gmx_incons("update_coords called for velocity without VV integrator");
1806     }
1807
1808     int  homenr = md->homenr;
1809
1810     /* Cast to real for faster code, no loss in precision (see comment above) */
1811     real dt     = inputrec->delta_t;
1812
1813     /* We need to update the NMR restraint history when time averaging is used */
1814     if (state->flags & (1<<estDISRE_RM3TAV))
1815     {
1816         update_disres_history(fcd, &state->hist);
1817     }
1818     if (state->flags & (1<<estORIRE_DTAV))
1819     {
1820         update_orires_history(fcd, &state->hist);
1821     }
1822
1823     /* ############# START The update of velocities and positions ######### */
1824     int nth = gmx_omp_nthreads_get(emntUpdate);
1825
1826 #pragma omp parallel for num_threads(nth) schedule(static)
1827     for (int th = 0; th < nth; th++)
1828     {
1829         try
1830         {
1831             int start_th, end_th;
1832             getThreadAtomRange(nth, th, homenr, &start_th, &end_th);
1833
1834             /* Strictly speaking, we would only need this check with SIMD
1835              * and for the actual SIMD width. But since the code currently
1836              * always adds padding for GMX_REAL_MAX_SIMD_WIDTH, we check that.
1837              */
1838             gmx::index gmx_used_in_debug homenrSimdPadded;
1839             homenrSimdPadded = ((homenr + GMX_REAL_MAX_SIMD_WIDTH - 1)/GMX_REAL_MAX_SIMD_WIDTH)*GMX_REAL_MAX_SIMD_WIDTH;
1840             GMX_ASSERT(gmx::index(state->x.size()) >= homenrSimdPadded, "state->x needs to be padded for SIMD access");
1841             GMX_ASSERT(gmx::index(upd->xp.size())  >= homenrSimdPadded, "upd->xp needs to be padded for SIMD access");
1842             GMX_ASSERT(gmx::index(state->v.size()) >= homenrSimdPadded, "state->v needs to be padded for SIMD access");
1843             GMX_ASSERT(f.size()        >= homenrSimdPadded, "f needs to be padded for SIMD access");
1844
1845             const rvec *x_rvec  = as_rvec_array(state->x.data());
1846             rvec       *xp_rvec = as_rvec_array(upd->xp.data());
1847             rvec       *v_rvec  = as_rvec_array(state->v.data());
1848             const rvec *f_rvec  = as_rvec_array(f.data());
1849
1850             switch (inputrec->eI)
1851             {
1852                 case (eiMD):
1853                     do_update_md(start_th, end_th, step, dt,
1854                                  inputrec, md, ekind, state->box,
1855                                  x_rvec, xp_rvec, v_rvec, f_rvec,
1856                                  state->nosehoover_vxi.data(), M);
1857                     break;
1858                 case (eiSD1):
1859                     if (bDoConstr)
1860                     {
1861                         // With constraints, the SD update is done in 2 parts
1862                         doSDUpdateGeneral<SDUpdate::ForcesOnly>
1863                             (upd->sd,
1864                             start_th, end_th, dt,
1865                             inputrec->opts.acc, inputrec->opts.nFreeze,
1866                             md->invmass, md->ptype,
1867                             md->cFREEZE, md->cACC, nullptr,
1868                             x_rvec, xp_rvec, v_rvec, f_rvec,
1869                             step, inputrec->ld_seed, nullptr);
1870                     }
1871                     else
1872                     {
1873                         doSDUpdateGeneral<SDUpdate::Combined>
1874                             (upd->sd,
1875                             start_th, end_th, dt,
1876                             inputrec->opts.acc, inputrec->opts.nFreeze,
1877                             md->invmass, md->ptype,
1878                             md->cFREEZE, md->cACC, md->cTC,
1879                             x_rvec, xp_rvec, v_rvec, f_rvec,
1880                             step, inputrec->ld_seed,
1881                             DOMAINDECOMP(cr) ? cr->dd->globalAtomIndices.data() : nullptr);
1882                     }
1883                     break;
1884                 case (eiBD):
1885                     do_update_bd(start_th, end_th, dt,
1886                                  inputrec->opts.nFreeze, md->invmass, md->ptype,
1887                                  md->cFREEZE, md->cTC,
1888                                  x_rvec, xp_rvec, v_rvec, f_rvec,
1889                                  inputrec->bd_fric,
1890                                  upd->sd->bd_rf,
1891                                  step, inputrec->ld_seed, DOMAINDECOMP(cr) ? cr->dd->globalAtomIndices.data() : nullptr);
1892                     break;
1893                 case (eiVV):
1894                 case (eiVVAK):
1895                 {
1896                     gmx_bool bExtended = (inputrec->etc == etcNOSEHOOVER ||
1897                                           inputrec->epc == epcPARRINELLORAHMAN ||
1898                                           inputrec->epc == epcMTTK);
1899
1900                     /* assuming barostat coupled to group 0 */
1901                     real alpha = 1.0 + DIM/static_cast<real>(inputrec->opts.nrdf[0]);
1902                     switch (UpdatePart)
1903                     {
1904                         case etrtVELOCITY1:
1905                         case etrtVELOCITY2:
1906                             do_update_vv_vel(start_th, end_th, dt,
1907                                              inputrec->opts.acc, inputrec->opts.nFreeze,
1908                                              md->invmass, md->ptype,
1909                                              md->cFREEZE, md->cACC,
1910                                              v_rvec, f_rvec,
1911                                              bExtended, state->veta, alpha);
1912                             break;
1913                         case etrtPOSITION:
1914                             do_update_vv_pos(start_th, end_th, dt,
1915                                              inputrec->opts.nFreeze,
1916                                              md->ptype, md->cFREEZE,
1917                                              x_rvec, xp_rvec, v_rvec,
1918                                              bExtended, state->veta);
1919                             break;
1920                     }
1921                     break;
1922                 }
1923                 default:
1924                     gmx_fatal(FARGS, "Don't know how to update coordinates");
1925             }
1926         }
1927         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
1928     }
1929
1930 }
1931
1932 extern gmx_bool update_randomize_velocities(t_inputrec *ir, int64_t step, const t_commrec *cr,
1933                                             t_mdatoms *md, t_state *state, gmx_update_t *upd, gmx::Constraints *constr)
1934 {
1935
1936     real rate = (ir->delta_t)/ir->opts.tau_t[0];
1937
1938     if (ir->etc == etcANDERSEN && constr != nullptr)
1939     {
1940         /* Currently, Andersen thermostat does not support constrained
1941            systems. Functionality exists in the andersen_tcoupl
1942            function in GROMACS 4.5.7 to allow this combination. That
1943            code could be ported to the current random-number
1944            generation approach, but has not yet been done because of
1945            lack of time and resources. */
1946         gmx_fatal(FARGS, "Normal Andersen is currently not supported with constraints, use massive Andersen instead");
1947     }
1948
1949     /* proceed with andersen if 1) it's fixed probability per
1950        particle andersen or 2) it's massive andersen and it's tau_t/dt */
1951     if ((ir->etc == etcANDERSEN) || do_per_step(step, static_cast<int>(1.0/rate + 0.5)))
1952     {
1953         andersen_tcoupl(ir, step, cr, md, state, rate,
1954                         upd->sd->randomize_group, upd->sd->boltzfac);
1955         return TRUE;
1956     }
1957     return FALSE;
1958 }