c2a93a826ef305963e34a704049597dfef3a23a9
[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     PaddedVector<gmx::RVec> 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                              const rvec accel[], const 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                              const ivec nFreeze[],
723                              const unsigned short ptype[], const unsigned short cFREEZE[],
724                              const rvec x[], rvec xprime[], const 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.resizeWithPadding(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.resizeWithPadding(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                   const rvec accel[], const 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     // cTC, cACC and cFreeze can be nullptr any time, but various
912     // instantiations do not make sense with particular pointer
913     // values.
914     if (updateType == SDUpdate::ForcesOnly)
915     {
916         GMX_ASSERT(f != nullptr, "SD update with only forces requires forces");
917         GMX_ASSERT(cTC == nullptr, "SD update with only forces cannot handle temperature groups");
918     }
919     if (updateType == SDUpdate::FrictionAndNoiseOnly)
920     {
921         GMX_ASSERT(f == nullptr, "SD update with only noise cannot handle forces");
922         GMX_ASSERT(cACC == nullptr, "SD update with only noise cannot handle acceleration groups");
923     }
924     if (updateType == SDUpdate::Combined)
925     {
926         GMX_ASSERT(f != nullptr, "SD update with forces and noise requires forces");
927     }
928
929     // Even 0 bits internal counter gives 2x64 ints (more than enough for three table lookups)
930     gmx::ThreeFry2x64<0> rng(seed, gmx::RandomDomain::UpdateCoordinates);
931     gmx::TabulatedNormalDistribution<real, 14> dist;
932
933     gmx_sd_const_t *sdc = sd->sdc;
934     gmx_sd_sigma_t *sig = sd->sdsig;
935
936     for (int n = start; n < nrend; n++)
937     {
938         int globalAtomIndex = gatindex ? gatindex[n] : n;
939         rng.restart(step, globalAtomIndex);
940         dist.reset();
941
942         real inverseMass     = invmass[n];
943         real invsqrtMass     = std::sqrt(inverseMass);
944
945         int  freezeGroup       = cFREEZE ? cFREEZE[n] : 0;
946         int  accelerationGroup = cACC ? cACC[n] : 0;
947         int  temperatureGroup  = cTC ? cTC[n] : 0;
948
949         for (int d = 0; d < DIM; d++)
950         {
951             if ((ptype[n] != eptVSite) && (ptype[n] != eptShell) && !nFreeze[freezeGroup][d])
952             {
953                 if (updateType == SDUpdate::ForcesOnly)
954                 {
955                     real vn      = v[n][d] + (inverseMass*f[n][d] + accel[accelerationGroup][d])*dt;
956                     v[n][d]      = vn;
957                     // Simple position update.
958                     xprime[n][d] = x[n][d] + v[n][d]*dt;
959                 }
960                 else if (updateType == SDUpdate::FrictionAndNoiseOnly)
961                 {
962                     real vn      = v[n][d];
963                     v[n][d]      = (vn*sdc[temperatureGroup].em +
964                                     invsqrtMass*sig[temperatureGroup].V*dist(rng));
965                     // The previous phase already updated the
966                     // positions with a full v*dt term that must
967                     // now be half removed.
968                     xprime[n][d] = xprime[n][d] + 0.5*(v[n][d] - vn)*dt;
969                 }
970                 else
971                 {
972                     real vn      = v[n][d] + (inverseMass*f[n][d] + accel[accelerationGroup][d])*dt;
973                     v[n][d]      = (vn*sdc[temperatureGroup].em +
974                                     invsqrtMass*sig[temperatureGroup].V*dist(rng));
975                     // Here we include half of the friction+noise
976                     // update of v into the position update.
977                     xprime[n][d] = x[n][d] + 0.5*(vn + v[n][d])*dt;
978                 }
979             }
980             else
981             {
982                 // When using constraints, the update is split into
983                 // two phases, but we only need to zero the update of
984                 // virtual, shell or frozen particles in at most one
985                 // of the phases.
986                 if (updateType != SDUpdate::FrictionAndNoiseOnly)
987                 {
988                     v[n][d]      = 0.0;
989                     xprime[n][d] = x[n][d];
990                 }
991             }
992         }
993     }
994 }
995
996 static void do_update_bd(int start, int nrend, real dt,
997                          const ivec nFreeze[],
998                          const real invmass[], const unsigned short ptype[],
999                          const unsigned short cFREEZE[], const unsigned short cTC[],
1000                          const rvec x[], rvec xprime[], rvec v[],
1001                          const rvec f[], real friction_coefficient,
1002                          const real *rf, int64_t step, int seed,
1003                          const int* gatindex)
1004 {
1005     /* note -- these appear to be full step velocities . . .  */
1006     int    gf = 0, gt = 0;
1007     real   vn;
1008     real   invfr = 0;
1009     int    n, d;
1010     // Use 1 bit of internal counters to give us 2*2 64-bits values per stream
1011     // Each 64-bit value is enough for 4 normal distribution table numbers.
1012     gmx::ThreeFry2x64<0> rng(seed, gmx::RandomDomain::UpdateCoordinates);
1013     gmx::TabulatedNormalDistribution<real, 14> dist;
1014
1015     if (friction_coefficient != 0)
1016     {
1017         invfr = 1.0/friction_coefficient;
1018     }
1019
1020     for (n = start; (n < nrend); n++)
1021     {
1022         int  ng  = gatindex ? gatindex[n] : n;
1023
1024         rng.restart(step, ng);
1025         dist.reset();
1026
1027         if (cFREEZE)
1028         {
1029             gf = cFREEZE[n];
1030         }
1031         if (cTC)
1032         {
1033             gt = cTC[n];
1034         }
1035         for (d = 0; (d < DIM); d++)
1036         {
1037             if ((ptype[n] != eptVSite) && (ptype[n] != eptShell) && !nFreeze[gf][d])
1038             {
1039                 if (friction_coefficient != 0)
1040                 {
1041                     vn = invfr*f[n][d] + rf[gt]*dist(rng);
1042                 }
1043                 else
1044                 {
1045                     /* NOTE: invmass = 2/(mass*friction_constant*dt) */
1046                     vn = 0.5*invmass[n]*f[n][d]*dt
1047                         + std::sqrt(0.5*invmass[n])*rf[gt]*dist(rng);
1048                 }
1049
1050                 v[n][d]      = vn;
1051                 xprime[n][d] = x[n][d]+vn*dt;
1052             }
1053             else
1054             {
1055                 v[n][d]      = 0.0;
1056                 xprime[n][d] = x[n][d];
1057             }
1058         }
1059     }
1060 }
1061
1062 static void calc_ke_part_normal(const rvec v[], const t_grpopts *opts, const t_mdatoms *md,
1063                                 gmx_ekindata_t *ekind, t_nrnb *nrnb, gmx_bool bEkinAveVel)
1064 {
1065     int           g;
1066     t_grp_tcstat *tcstat  = ekind->tcstat;
1067     t_grp_acc    *grpstat = ekind->grpstat;
1068     int           nthread, thread;
1069
1070     /* three main: VV with AveVel, vv with AveEkin, leap with AveEkin.  Leap with AveVel is also
1071        an option, but not supported now.
1072        bEkinAveVel: If TRUE, we sum into ekin, if FALSE, into ekinh.
1073      */
1074
1075     /* group velocities are calculated in update_ekindata and
1076      * accumulated in acumulate_groups.
1077      * Now the partial global and groups ekin.
1078      */
1079     for (g = 0; (g < opts->ngtc); g++)
1080     {
1081         copy_mat(tcstat[g].ekinh, tcstat[g].ekinh_old);
1082         if (bEkinAveVel)
1083         {
1084             clear_mat(tcstat[g].ekinf);
1085             tcstat[g].ekinscalef_nhc = 1.0;   /* need to clear this -- logic is complicated! */
1086         }
1087         else
1088         {
1089             clear_mat(tcstat[g].ekinh);
1090         }
1091     }
1092     ekind->dekindl_old = ekind->dekindl;
1093     nthread            = gmx_omp_nthreads_get(emntUpdate);
1094
1095 #pragma omp parallel for num_threads(nthread) schedule(static)
1096     for (thread = 0; thread < nthread; thread++)
1097     {
1098         // This OpenMP only loops over arrays and does not call any functions
1099         // or memory allocation. It should not be able to throw, so for now
1100         // we do not need a try/catch wrapper.
1101         int     start_t, end_t, n;
1102         int     ga, gt;
1103         rvec    v_corrt;
1104         real    hm;
1105         int     d, m;
1106         matrix *ekin_sum;
1107         real   *dekindl_sum;
1108
1109         start_t = ((thread+0)*md->homenr)/nthread;
1110         end_t   = ((thread+1)*md->homenr)/nthread;
1111
1112         ekin_sum    = ekind->ekin_work[thread];
1113         dekindl_sum = ekind->dekindl_work[thread];
1114
1115         for (gt = 0; gt < opts->ngtc; gt++)
1116         {
1117             clear_mat(ekin_sum[gt]);
1118         }
1119         *dekindl_sum = 0.0;
1120
1121         ga = 0;
1122         gt = 0;
1123         for (n = start_t; n < end_t; n++)
1124         {
1125             if (md->cACC)
1126             {
1127                 ga = md->cACC[n];
1128             }
1129             if (md->cTC)
1130             {
1131                 gt = md->cTC[n];
1132             }
1133             hm   = 0.5*md->massT[n];
1134
1135             for (d = 0; (d < DIM); d++)
1136             {
1137                 v_corrt[d]  = v[n][d]  - grpstat[ga].u[d];
1138             }
1139             for (d = 0; (d < DIM); d++)
1140             {
1141                 for (m = 0; (m < DIM); m++)
1142                 {
1143                     /* if we're computing a full step velocity, v_corrt[d] has v(t).  Otherwise, v(t+dt/2) */
1144                     ekin_sum[gt][m][d] += hm*v_corrt[m]*v_corrt[d];
1145                 }
1146             }
1147             if (md->nMassPerturbed && md->bPerturbed[n])
1148             {
1149                 *dekindl_sum +=
1150                     0.5*(md->massB[n] - md->massA[n])*iprod(v_corrt, v_corrt);
1151             }
1152         }
1153     }
1154
1155     ekind->dekindl = 0;
1156     for (thread = 0; thread < nthread; thread++)
1157     {
1158         for (g = 0; g < opts->ngtc; g++)
1159         {
1160             if (bEkinAveVel)
1161             {
1162                 m_add(tcstat[g].ekinf, ekind->ekin_work[thread][g],
1163                       tcstat[g].ekinf);
1164             }
1165             else
1166             {
1167                 m_add(tcstat[g].ekinh, ekind->ekin_work[thread][g],
1168                       tcstat[g].ekinh);
1169             }
1170         }
1171
1172         ekind->dekindl += *ekind->dekindl_work[thread];
1173     }
1174
1175     inc_nrnb(nrnb, eNR_EKIN, md->homenr);
1176 }
1177
1178 static void calc_ke_part_visc(const matrix box, const rvec x[], const rvec v[],
1179                               const t_grpopts *opts, const t_mdatoms *md,
1180                               gmx_ekindata_t *ekind,
1181                               t_nrnb *nrnb, gmx_bool bEkinAveVel)
1182 {
1183     int           start = 0, homenr = md->homenr;
1184     int           g, d, n, m, gt = 0;
1185     rvec          v_corrt;
1186     real          hm;
1187     t_grp_tcstat *tcstat = ekind->tcstat;
1188     t_cos_acc    *cosacc = &(ekind->cosacc);
1189     real          dekindl;
1190     real          fac, cosz;
1191     double        mvcos;
1192
1193     for (g = 0; g < opts->ngtc; g++)
1194     {
1195         copy_mat(ekind->tcstat[g].ekinh, ekind->tcstat[g].ekinh_old);
1196         clear_mat(ekind->tcstat[g].ekinh);
1197     }
1198     ekind->dekindl_old = ekind->dekindl;
1199
1200     fac     = 2*M_PI/box[ZZ][ZZ];
1201     mvcos   = 0;
1202     dekindl = 0;
1203     for (n = start; n < start+homenr; n++)
1204     {
1205         if (md->cTC)
1206         {
1207             gt = md->cTC[n];
1208         }
1209         hm   = 0.5*md->massT[n];
1210
1211         /* Note that the times of x and v differ by half a step */
1212         /* MRS -- would have to be changed for VV */
1213         cosz         = std::cos(fac*x[n][ZZ]);
1214         /* Calculate the amplitude of the new velocity profile */
1215         mvcos       += 2*cosz*md->massT[n]*v[n][XX];
1216
1217         copy_rvec(v[n], v_corrt);
1218         /* Subtract the profile for the kinetic energy */
1219         v_corrt[XX] -= cosz*cosacc->vcos;
1220         for (d = 0; (d < DIM); d++)
1221         {
1222             for (m = 0; (m < DIM); m++)
1223             {
1224                 /* if we're computing a full step velocity, v_corrt[d] has v(t).  Otherwise, v(t+dt/2) */
1225                 if (bEkinAveVel)
1226                 {
1227                     tcstat[gt].ekinf[m][d] += hm*v_corrt[m]*v_corrt[d];
1228                 }
1229                 else
1230                 {
1231                     tcstat[gt].ekinh[m][d] += hm*v_corrt[m]*v_corrt[d];
1232                 }
1233             }
1234         }
1235         if (md->nPerturbed && md->bPerturbed[n])
1236         {
1237             /* The minus sign here might be confusing.
1238              * The kinetic contribution from dH/dl doesn't come from
1239              * d m(l)/2 v^2 / dl, but rather from d p^2/2m(l) / dl,
1240              * where p are the momenta. The difference is only a minus sign.
1241              */
1242             dekindl -= 0.5*(md->massB[n] - md->massA[n])*iprod(v_corrt, v_corrt);
1243         }
1244     }
1245     ekind->dekindl = dekindl;
1246     cosacc->mvcos  = mvcos;
1247
1248     inc_nrnb(nrnb, eNR_EKIN, homenr);
1249 }
1250
1251 void calc_ke_part(const t_state *state, const t_grpopts *opts, const t_mdatoms *md,
1252                   gmx_ekindata_t *ekind, t_nrnb *nrnb, gmx_bool bEkinAveVel)
1253 {
1254     if (ekind->cosacc.cos_accel == 0)
1255     {
1256         calc_ke_part_normal(state->v.rvec_array(), opts, md, ekind, nrnb, bEkinAveVel);
1257     }
1258     else
1259     {
1260         calc_ke_part_visc(state->box, state->x.rvec_array(), state->v.rvec_array(), opts, md, ekind, nrnb, bEkinAveVel);
1261     }
1262 }
1263
1264 extern void init_ekinstate(ekinstate_t *ekinstate, const t_inputrec *ir)
1265 {
1266     ekinstate->ekin_n = ir->opts.ngtc;
1267     snew(ekinstate->ekinh, ekinstate->ekin_n);
1268     snew(ekinstate->ekinf, ekinstate->ekin_n);
1269     snew(ekinstate->ekinh_old, ekinstate->ekin_n);
1270     ekinstate->ekinscalef_nhc.resize(ekinstate->ekin_n);
1271     ekinstate->ekinscaleh_nhc.resize(ekinstate->ekin_n);
1272     ekinstate->vscale_nhc.resize(ekinstate->ekin_n);
1273     ekinstate->dekindl = 0;
1274     ekinstate->mvcos   = 0;
1275 }
1276
1277 void update_ekinstate(ekinstate_t *ekinstate, const gmx_ekindata_t *ekind)
1278 {
1279     int i;
1280
1281     for (i = 0; i < ekinstate->ekin_n; i++)
1282     {
1283         copy_mat(ekind->tcstat[i].ekinh, ekinstate->ekinh[i]);
1284         copy_mat(ekind->tcstat[i].ekinf, ekinstate->ekinf[i]);
1285         copy_mat(ekind->tcstat[i].ekinh_old, ekinstate->ekinh_old[i]);
1286         ekinstate->ekinscalef_nhc[i] = ekind->tcstat[i].ekinscalef_nhc;
1287         ekinstate->ekinscaleh_nhc[i] = ekind->tcstat[i].ekinscaleh_nhc;
1288         ekinstate->vscale_nhc[i]     = ekind->tcstat[i].vscale_nhc;
1289     }
1290
1291     copy_mat(ekind->ekin, ekinstate->ekin_total);
1292     ekinstate->dekindl = ekind->dekindl;
1293     ekinstate->mvcos   = ekind->cosacc.mvcos;
1294
1295 }
1296
1297 void restore_ekinstate_from_state(const t_commrec *cr,
1298                                   gmx_ekindata_t *ekind, const ekinstate_t *ekinstate)
1299 {
1300     int i, n;
1301
1302     if (MASTER(cr))
1303     {
1304         for (i = 0; i < ekinstate->ekin_n; i++)
1305         {
1306             copy_mat(ekinstate->ekinh[i], ekind->tcstat[i].ekinh);
1307             copy_mat(ekinstate->ekinf[i], ekind->tcstat[i].ekinf);
1308             copy_mat(ekinstate->ekinh_old[i], ekind->tcstat[i].ekinh_old);
1309             ekind->tcstat[i].ekinscalef_nhc = ekinstate->ekinscalef_nhc[i];
1310             ekind->tcstat[i].ekinscaleh_nhc = ekinstate->ekinscaleh_nhc[i];
1311             ekind->tcstat[i].vscale_nhc     = ekinstate->vscale_nhc[i];
1312         }
1313
1314         copy_mat(ekinstate->ekin_total, ekind->ekin);
1315
1316         ekind->dekindl      = ekinstate->dekindl;
1317         ekind->cosacc.mvcos = ekinstate->mvcos;
1318         n                   = ekinstate->ekin_n;
1319     }
1320
1321     if (PAR(cr))
1322     {
1323         gmx_bcast(sizeof(n), &n, cr);
1324         for (i = 0; i < n; i++)
1325         {
1326             gmx_bcast(DIM*DIM*sizeof(ekind->tcstat[i].ekinh[0][0]),
1327                       ekind->tcstat[i].ekinh[0], cr);
1328             gmx_bcast(DIM*DIM*sizeof(ekind->tcstat[i].ekinf[0][0]),
1329                       ekind->tcstat[i].ekinf[0], cr);
1330             gmx_bcast(DIM*DIM*sizeof(ekind->tcstat[i].ekinh_old[0][0]),
1331                       ekind->tcstat[i].ekinh_old[0], cr);
1332
1333             gmx_bcast(sizeof(ekind->tcstat[i].ekinscalef_nhc),
1334                       &(ekind->tcstat[i].ekinscalef_nhc), cr);
1335             gmx_bcast(sizeof(ekind->tcstat[i].ekinscaleh_nhc),
1336                       &(ekind->tcstat[i].ekinscaleh_nhc), cr);
1337             gmx_bcast(sizeof(ekind->tcstat[i].vscale_nhc),
1338                       &(ekind->tcstat[i].vscale_nhc), cr);
1339         }
1340         gmx_bcast(DIM*DIM*sizeof(ekind->ekin[0][0]),
1341                   ekind->ekin[0], cr);
1342
1343         gmx_bcast(sizeof(ekind->dekindl), &ekind->dekindl, cr);
1344         gmx_bcast(sizeof(ekind->cosacc.mvcos), &ekind->cosacc.mvcos, cr);
1345     }
1346 }
1347
1348 void update_tcouple(int64_t           step,
1349                     const t_inputrec *inputrec,
1350                     t_state          *state,
1351                     gmx_ekindata_t   *ekind,
1352                     const t_extmass  *MassQ,
1353                     const t_mdatoms  *md)
1354
1355 {
1356     bool doTemperatureCoupling = false;
1357
1358     /* if using vv with trotter decomposition methods, we do this elsewhere in the code */
1359     if (!(EI_VV(inputrec->eI) &&
1360           (inputrecNvtTrotter(inputrec) || inputrecNptTrotter(inputrec) || inputrecNphTrotter(inputrec))))
1361     {
1362         doTemperatureCoupling = isTemperatureCouplingStep(step, inputrec);
1363     }
1364
1365     if (doTemperatureCoupling)
1366     {
1367         real dttc = inputrec->nsttcouple*inputrec->delta_t;
1368
1369         switch (inputrec->etc)
1370         {
1371             case etcNO:
1372                 break;
1373             case etcBERENDSEN:
1374                 berendsen_tcoupl(inputrec, ekind, dttc, state->therm_integral);
1375                 break;
1376             case etcNOSEHOOVER:
1377                 nosehoover_tcoupl(&(inputrec->opts), ekind, dttc,
1378                                   state->nosehoover_xi.data(), state->nosehoover_vxi.data(), MassQ);
1379                 break;
1380             case etcVRESCALE:
1381                 vrescale_tcoupl(inputrec, step, ekind, dttc,
1382                                 state->therm_integral.data());
1383                 break;
1384         }
1385         /* rescale in place here */
1386         if (EI_VV(inputrec->eI))
1387         {
1388             rescale_velocities(ekind, md, 0, md->homenr, state->v.rvec_array());
1389         }
1390     }
1391     else
1392     {
1393         /* Set the T scaling lambda to 1 to have no scaling */
1394         for (int i = 0; (i < inputrec->opts.ngtc); i++)
1395         {
1396             ekind->tcstat[i].lambda = 1.0;
1397         }
1398     }
1399 }
1400
1401 /*! \brief Computes the atom range for a thread to operate on, ensured SIMD aligned ranges
1402  *
1403  * \param[in]  numThreads   The number of threads to divide atoms over
1404  * \param[in]  threadIndex  The thread to get the range for
1405  * \param[in]  numAtoms     The total number of atoms (on this rank)
1406  * \param[out] startAtom    The start of the atom range
1407  * \param[out] endAtom      The end of the atom range, note that this is in general not a multiple of the SIMD width
1408  */
1409 static void getThreadAtomRange(int numThreads, int threadIndex, int numAtoms,
1410                                int *startAtom, int *endAtom)
1411 {
1412 #if GMX_HAVE_SIMD_UPDATE
1413     constexpr int blockSize = GMX_SIMD_REAL_WIDTH;
1414 #else
1415     constexpr int blockSize = 1;
1416 #endif
1417     int           numBlocks = (numAtoms + blockSize - 1)/blockSize;
1418
1419     *startAtom    = ((numBlocks* threadIndex     )/numThreads)*blockSize;
1420     *endAtom      = ((numBlocks*(threadIndex + 1))/numThreads)*blockSize;
1421     if (threadIndex == numThreads - 1)
1422     {
1423         *endAtom  = numAtoms;
1424     }
1425 }
1426
1427 void update_pcouple_before_coordinates(FILE             *fplog,
1428                                        int64_t           step,
1429                                        const t_inputrec *inputrec,
1430                                        t_state          *state,
1431                                        matrix            parrinellorahmanMu,
1432                                        matrix            M,
1433                                        gmx_bool          bInitStep)
1434 {
1435     /* Berendsen P-coupling is completely handled after the coordinate update.
1436      * Trotter P-coupling is handled by separate calls to trotter_update().
1437      */
1438     if (inputrec->epc == epcPARRINELLORAHMAN &&
1439         isPressureCouplingStep(step, inputrec))
1440     {
1441         real dtpc = inputrec->nstpcouple*inputrec->delta_t;
1442
1443         parrinellorahman_pcoupl(fplog, step, inputrec, dtpc, state->pres_prev,
1444                                 state->box, state->box_rel, state->boxv,
1445                                 M, parrinellorahmanMu, bInitStep);
1446     }
1447 }
1448
1449 void constrain_velocities(int64_t                        step,
1450                           real                          *dvdlambda, /* the contribution to be added to the bonded interactions */
1451                           t_state                       *state,
1452                           tensor                         vir_part,
1453                           gmx::Constraints              *constr,
1454                           gmx_bool                       bCalcVir,
1455                           bool                           do_log,
1456                           bool                           do_ene)
1457 {
1458     if (!constr)
1459     {
1460         return;
1461     }
1462
1463     /*
1464      *  Steps (7C, 8C)
1465      *  APPLY CONSTRAINTS:
1466      *  BLOCK SHAKE
1467      */
1468
1469     {
1470         tensor vir_con;
1471
1472         /* clear out constraints before applying */
1473         clear_mat(vir_part);
1474
1475         /* Constrain the coordinates upd->xp */
1476         constr->apply(do_log, do_ene,
1477                       step, 1, 1.0,
1478                       state->x.rvec_array(), state->v.rvec_array(), state->v.rvec_array(),
1479                       state->box,
1480                       state->lambda[efptBONDED], dvdlambda,
1481                       nullptr, bCalcVir ? &vir_con : nullptr, ConstraintVariable::Velocities);
1482
1483         if (bCalcVir)
1484         {
1485             m_add(vir_part, vir_con, vir_part);
1486         }
1487     }
1488 }
1489
1490 void constrain_coordinates(int64_t                        step,
1491                            real                          *dvdlambda, /* the contribution to be added to the bonded interactions */
1492                            t_state                       *state,
1493                            tensor                         vir_part,
1494                            gmx_update_t                  *upd,
1495                            gmx::Constraints              *constr,
1496                            gmx_bool                       bCalcVir,
1497                            bool                           do_log,
1498                            bool                           do_ene)
1499 {
1500     if (!constr)
1501     {
1502         return;
1503     }
1504
1505     {
1506         tensor vir_con;
1507
1508         /* clear out constraints before applying */
1509         clear_mat(vir_part);
1510
1511         /* Constrain the coordinates upd->xp */
1512         constr->apply(do_log, do_ene,
1513                       step, 1, 1.0,
1514                       state->x.rvec_array(), upd->xp.rvec_array(), nullptr,
1515                       state->box,
1516                       state->lambda[efptBONDED], dvdlambda,
1517                       as_rvec_array(state->v.data()), bCalcVir ? &vir_con : nullptr, ConstraintVariable::Positions);
1518
1519         if (bCalcVir)
1520         {
1521             m_add(vir_part, vir_con, vir_part);
1522         }
1523     }
1524 }
1525
1526 void
1527 update_sd_second_half(int64_t                        step,
1528                       real                          *dvdlambda,   /* the contribution to be added to the bonded interactions */
1529                       const t_inputrec              *inputrec,    /* input record and box stuff */
1530                       const t_mdatoms               *md,
1531                       t_state                       *state,
1532                       const t_commrec               *cr,
1533                       t_nrnb                        *nrnb,
1534                       gmx_wallcycle_t                wcycle,
1535                       gmx_update_t                  *upd,
1536                       gmx::Constraints              *constr,
1537                       bool                           do_log,
1538                       bool                           do_ene)
1539 {
1540     if (!constr)
1541     {
1542         return;
1543     }
1544     if (inputrec->eI == eiSD1)
1545     {
1546         int nth, th;
1547         int homenr = md->homenr;
1548
1549         /* Cast delta_t from double to real to make the integrators faster.
1550          * The only reason for having delta_t double is to get accurate values
1551          * for t=delta_t*step when step is larger than float precision.
1552          * For integration dt the accuracy of real suffices, since with
1553          * integral += dt*integrand the increment is nearly always (much) smaller
1554          * than the integral (and the integrand has real precision).
1555          */
1556         real dt     = inputrec->delta_t;
1557
1558         wallcycle_start(wcycle, ewcUPDATE);
1559
1560         nth = gmx_omp_nthreads_get(emntUpdate);
1561
1562 #pragma omp parallel for num_threads(nth) schedule(static)
1563         for (th = 0; th < nth; th++)
1564         {
1565             try
1566             {
1567                 int start_th, end_th;
1568                 getThreadAtomRange(nth, th, homenr, &start_th, &end_th);
1569
1570                 doSDUpdateGeneral<SDUpdate::FrictionAndNoiseOnly>
1571                     (upd->sd,
1572                     start_th, end_th, dt,
1573                     inputrec->opts.acc, inputrec->opts.nFreeze,
1574                     md->invmass, md->ptype,
1575                     md->cFREEZE, nullptr, md->cTC,
1576                     state->x.rvec_array(), upd->xp.rvec_array(),
1577                     state->v.rvec_array(), nullptr,
1578                     step, inputrec->ld_seed,
1579                     DOMAINDECOMP(cr) ? cr->dd->globalAtomIndices.data() : nullptr);
1580             }
1581             GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
1582         }
1583         inc_nrnb(nrnb, eNR_UPDATE, homenr);
1584         wallcycle_stop(wcycle, ewcUPDATE);
1585
1586         /* Constrain the coordinates upd->xp for half a time step */
1587         constr->apply(do_log, do_ene,
1588                       step, 1, 0.5,
1589                       state->x.rvec_array(), upd->xp.rvec_array(), nullptr,
1590                       state->box,
1591                       state->lambda[efptBONDED], dvdlambda,
1592                       as_rvec_array(state->v.data()), nullptr, ConstraintVariable::Positions);
1593     }
1594 }
1595
1596 void finish_update(const t_inputrec              *inputrec,  /* input record and box stuff      */
1597                    const t_mdatoms               *md,
1598                    t_state                       *state,
1599                    const t_graph                 *graph,
1600                    t_nrnb                        *nrnb,
1601                    gmx_wallcycle_t                wcycle,
1602                    gmx_update_t                  *upd,
1603                    const gmx::Constraints        *constr)
1604 {
1605     int homenr = md->homenr;
1606
1607     /* We must always unshift after updating coordinates; if we did not shake
1608        x was shifted in do_force */
1609
1610     /* NOTE Currently we always integrate to a temporary buffer and
1611      * then copy the results back. */
1612     {
1613         wallcycle_start_nocount(wcycle, ewcUPDATE);
1614
1615         if (md->cFREEZE != nullptr && constr != nullptr)
1616         {
1617             /* If we have atoms that are frozen along some, but not all
1618              * dimensions, then any constraints will have moved them also along
1619              * the frozen dimensions. To freeze such degrees of freedom
1620              * we copy them back here to later copy them forward. It would
1621              * be more elegant and slightly more efficient to copies zero
1622              * times instead of twice, but the graph case below prevents this.
1623              */
1624             const ivec *nFreeze                     = inputrec->opts.nFreeze;
1625             bool        partialFreezeAndConstraints = false;
1626             for (int g = 0; g < inputrec->opts.ngfrz; g++)
1627             {
1628                 int numFreezeDim = nFreeze[g][XX] + nFreeze[g][YY] + nFreeze[g][ZZ];
1629                 if (numFreezeDim > 0 && numFreezeDim < 3)
1630                 {
1631                     partialFreezeAndConstraints = true;
1632                 }
1633             }
1634             if (partialFreezeAndConstraints)
1635             {
1636                 auto xp = makeArrayRef(upd->xp).subArray(0, homenr);
1637                 auto x  = makeConstArrayRef(state->x).subArray(0, homenr);
1638                 for (int i = 0; i < homenr; i++)
1639                 {
1640                     int g = md->cFREEZE[i];
1641
1642                     for (int d = 0; d < DIM; d++)
1643                     {
1644                         if (nFreeze[g][d])
1645                         {
1646                             xp[i][d] = x[i][d];
1647                         }
1648                     }
1649                 }
1650             }
1651         }
1652
1653         if (graph && (graph->nnodes > 0))
1654         {
1655             unshift_x(graph, state->box, state->x.rvec_array(), upd->xp.rvec_array());
1656             if (TRICLINIC(state->box))
1657             {
1658                 inc_nrnb(nrnb, eNR_SHIFTX, 2*graph->nnodes);
1659             }
1660             else
1661             {
1662                 inc_nrnb(nrnb, eNR_SHIFTX, graph->nnodes);
1663             }
1664         }
1665         else
1666         {
1667             auto           xp = makeConstArrayRef(upd->xp).subArray(0, homenr);
1668             auto           x  = makeArrayRef(state->x).subArray(0, homenr);
1669 #ifndef __clang_analyzer__
1670             int gmx_unused nth = gmx_omp_nthreads_get(emntUpdate);
1671 #endif
1672 #pragma omp parallel for num_threads(nth) schedule(static)
1673             for (int i = 0; i < homenr; i++)
1674             {
1675                 // Trivial statement, does not throw
1676                 x[i] = xp[i];
1677             }
1678         }
1679         wallcycle_stop(wcycle, ewcUPDATE);
1680     }
1681     /* ############# END the update of velocities and positions ######### */
1682 }
1683
1684 void update_pcouple_after_coordinates(FILE             *fplog,
1685                                       int64_t           step,
1686                                       const t_inputrec *inputrec,
1687                                       const t_mdatoms  *md,
1688                                       const matrix      pressure,
1689                                       const matrix      forceVirial,
1690                                       const matrix      constraintVirial,
1691                                       const matrix      parrinellorahmanMu,
1692                                       t_state          *state,
1693                                       t_nrnb           *nrnb,
1694                                       gmx_update_t     *upd)
1695 {
1696     int  start  = 0;
1697     int  homenr = md->homenr;
1698
1699     /* Cast to real for faster code, no loss in precision (see comment above) */
1700     real dt     = inputrec->delta_t;
1701
1702
1703     /* now update boxes */
1704     switch (inputrec->epc)
1705     {
1706         case (epcNO):
1707             break;
1708         case (epcBERENDSEN):
1709             if (isPressureCouplingStep(step, inputrec))
1710             {
1711                 real   dtpc = inputrec->nstpcouple*dt;
1712                 matrix mu;
1713                 berendsen_pcoupl(fplog, step, inputrec, dtpc,
1714                                  pressure, state->box,
1715                                  forceVirial, constraintVirial,
1716                                  mu, &state->baros_integral);
1717                 berendsen_pscale(inputrec, mu, state->box, state->box_rel,
1718                                  start, homenr, state->x.rvec_array(),
1719                                  md->cFREEZE, nrnb);
1720             }
1721             break;
1722         case (epcPARRINELLORAHMAN):
1723             if (isPressureCouplingStep(step, inputrec))
1724             {
1725                 /* The box velocities were updated in do_pr_pcoupl,
1726                  * but we dont change the box vectors until we get here
1727                  * since we need to be able to shift/unshift above.
1728                  */
1729                 real dtpc = inputrec->nstpcouple*dt;
1730                 for (int i = 0; i < DIM; i++)
1731                 {
1732                     for (int m = 0; m <= i; m++)
1733                     {
1734                         state->box[i][m] += dtpc*state->boxv[i][m];
1735                     }
1736                 }
1737                 preserve_box_shape(inputrec, state->box_rel, state->box);
1738
1739                 /* Scale the coordinates */
1740                 auto x = state->x.rvec_array();
1741                 for (int n = start; n < start + homenr; n++)
1742                 {
1743                     tmvmul_ur0(parrinellorahmanMu, x[n], x[n]);
1744                 }
1745             }
1746             break;
1747         case (epcMTTK):
1748             switch (inputrec->epct)
1749             {
1750                 case (epctISOTROPIC):
1751                     /* DIM * eta = ln V.  so DIM*eta_new = DIM*eta_old + DIM*dt*veta =>
1752                        ln V_new = ln V_old + 3*dt*veta => V_new = V_old*exp(3*dt*veta) =>
1753                        Side length scales as exp(veta*dt) */
1754
1755                     msmul(state->box, std::exp(state->veta*dt), state->box);
1756
1757                     /* Relate veta to boxv.  veta = d(eta)/dT = (1/DIM)*1/V dV/dT.
1758                        o               If we assume isotropic scaling, and box length scaling
1759                        factor L, then V = L^DIM (det(M)).  So dV/dt = DIM
1760                        L^(DIM-1) dL/dt det(M), and veta = (1/L) dL/dt.  The
1761                        determinant of B is L^DIM det(M), and the determinant
1762                        of dB/dt is (dL/dT)^DIM det (M).  veta will be
1763                        (det(dB/dT)/det(B))^(1/3).  Then since M =
1764                        B_new*(vol_new)^(1/3), dB/dT_new = (veta_new)*B(new). */
1765
1766                     msmul(state->box, state->veta, state->boxv);
1767                     break;
1768                 default:
1769                     break;
1770             }
1771             break;
1772         default:
1773             break;
1774     }
1775
1776     if (upd->deform)
1777     {
1778         auto localX = makeArrayRef(state->x).subArray(start, homenr);
1779         upd->deform->apply(localX, state->box, step);
1780     }
1781 }
1782
1783 void update_coords(int64_t                             step,
1784                    const t_inputrec                   *inputrec, /* input record and box stuff  */
1785                    const t_mdatoms                    *md,
1786                    t_state                            *state,
1787                    gmx::ArrayRefWithPadding<gmx::RVec> f,
1788                    const t_fcdata                     *fcd,
1789                    const gmx_ekindata_t               *ekind,
1790                    const matrix                        M,
1791                    gmx_update_t                       *upd,
1792                    int                                 UpdatePart,
1793                    const t_commrec                    *cr, /* these shouldn't be here -- need to think about it */
1794                    const gmx::Constraints             *constr)
1795 {
1796     gmx_bool bDoConstr = (nullptr != constr);
1797
1798     /* Running the velocity half does nothing except for velocity verlet */
1799     if ((UpdatePart == etrtVELOCITY1 || UpdatePart == etrtVELOCITY2) &&
1800         !EI_VV(inputrec->eI))
1801     {
1802         gmx_incons("update_coords called for velocity without VV integrator");
1803     }
1804
1805     int  homenr = md->homenr;
1806
1807     /* Cast to real for faster code, no loss in precision (see comment above) */
1808     real dt     = inputrec->delta_t;
1809
1810     /* We need to update the NMR restraint history when time averaging is used */
1811     if (state->flags & (1<<estDISRE_RM3TAV))
1812     {
1813         update_disres_history(fcd, &state->hist);
1814     }
1815     if (state->flags & (1<<estORIRE_DTAV))
1816     {
1817         update_orires_history(fcd, &state->hist);
1818     }
1819
1820     /* ############# START The update of velocities and positions ######### */
1821     int nth = gmx_omp_nthreads_get(emntUpdate);
1822
1823 #pragma omp parallel for num_threads(nth) schedule(static)
1824     for (int th = 0; th < nth; th++)
1825     {
1826         try
1827         {
1828             int start_th, end_th;
1829             getThreadAtomRange(nth, th, homenr, &start_th, &end_th);
1830
1831             const rvec *x_rvec  = state->x.rvec_array();
1832             rvec       *xp_rvec = upd->xp.rvec_array();
1833             rvec       *v_rvec  = state->v.rvec_array();
1834             const rvec *f_rvec  = as_rvec_array(f.unpaddedArrayRef().data());
1835
1836             switch (inputrec->eI)
1837             {
1838                 case (eiMD):
1839                     do_update_md(start_th, end_th, step, dt,
1840                                  inputrec, md, ekind, state->box,
1841                                  x_rvec, xp_rvec, v_rvec, f_rvec,
1842                                  state->nosehoover_vxi.data(), M);
1843                     break;
1844                 case (eiSD1):
1845                     if (bDoConstr)
1846                     {
1847                         // With constraints, the SD update is done in 2 parts
1848                         doSDUpdateGeneral<SDUpdate::ForcesOnly>
1849                             (upd->sd,
1850                             start_th, end_th, dt,
1851                             inputrec->opts.acc, inputrec->opts.nFreeze,
1852                             md->invmass, md->ptype,
1853                             md->cFREEZE, md->cACC, nullptr,
1854                             x_rvec, xp_rvec, v_rvec, f_rvec,
1855                             step, inputrec->ld_seed, nullptr);
1856                     }
1857                     else
1858                     {
1859                         doSDUpdateGeneral<SDUpdate::Combined>
1860                             (upd->sd,
1861                             start_th, end_th, dt,
1862                             inputrec->opts.acc, inputrec->opts.nFreeze,
1863                             md->invmass, md->ptype,
1864                             md->cFREEZE, md->cACC, md->cTC,
1865                             x_rvec, xp_rvec, v_rvec, f_rvec,
1866                             step, inputrec->ld_seed,
1867                             DOMAINDECOMP(cr) ? cr->dd->globalAtomIndices.data() : nullptr);
1868                     }
1869                     break;
1870                 case (eiBD):
1871                     do_update_bd(start_th, end_th, dt,
1872                                  inputrec->opts.nFreeze, md->invmass, md->ptype,
1873                                  md->cFREEZE, md->cTC,
1874                                  x_rvec, xp_rvec, v_rvec, f_rvec,
1875                                  inputrec->bd_fric,
1876                                  upd->sd->bd_rf,
1877                                  step, inputrec->ld_seed, DOMAINDECOMP(cr) ? cr->dd->globalAtomIndices.data() : nullptr);
1878                     break;
1879                 case (eiVV):
1880                 case (eiVVAK):
1881                 {
1882                     gmx_bool bExtended = (inputrec->etc == etcNOSEHOOVER ||
1883                                           inputrec->epc == epcPARRINELLORAHMAN ||
1884                                           inputrec->epc == epcMTTK);
1885
1886                     /* assuming barostat coupled to group 0 */
1887                     real alpha = 1.0 + DIM/static_cast<real>(inputrec->opts.nrdf[0]);
1888                     switch (UpdatePart)
1889                     {
1890                         case etrtVELOCITY1:
1891                         case etrtVELOCITY2:
1892                             do_update_vv_vel(start_th, end_th, dt,
1893                                              inputrec->opts.acc, inputrec->opts.nFreeze,
1894                                              md->invmass, md->ptype,
1895                                              md->cFREEZE, md->cACC,
1896                                              v_rvec, f_rvec,
1897                                              bExtended, state->veta, alpha);
1898                             break;
1899                         case etrtPOSITION:
1900                             do_update_vv_pos(start_th, end_th, dt,
1901                                              inputrec->opts.nFreeze,
1902                                              md->ptype, md->cFREEZE,
1903                                              x_rvec, xp_rvec, v_rvec,
1904                                              bExtended, state->veta);
1905                             break;
1906                     }
1907                     break;
1908                 }
1909                 default:
1910                     gmx_fatal(FARGS, "Don't know how to update coordinates");
1911             }
1912         }
1913         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
1914     }
1915
1916 }
1917
1918 extern gmx_bool update_randomize_velocities(const t_inputrec *ir, int64_t step, const t_commrec *cr,
1919                                             const t_mdatoms *md,
1920                                             gmx::ArrayRef<gmx::RVec> v,
1921                                             const gmx_update_t *upd,
1922                                             const gmx::Constraints *constr)
1923 {
1924
1925     real rate = (ir->delta_t)/ir->opts.tau_t[0];
1926
1927     if (ir->etc == etcANDERSEN && constr != nullptr)
1928     {
1929         /* Currently, Andersen thermostat does not support constrained
1930            systems. Functionality exists in the andersen_tcoupl
1931            function in GROMACS 4.5.7 to allow this combination. That
1932            code could be ported to the current random-number
1933            generation approach, but has not yet been done because of
1934            lack of time and resources. */
1935         gmx_fatal(FARGS, "Normal Andersen is currently not supported with constraints, use massive Andersen instead");
1936     }
1937
1938     /* proceed with andersen if 1) it's fixed probability per
1939        particle andersen or 2) it's massive andersen and it's tau_t/dt */
1940     if ((ir->etc == etcANDERSEN) || do_per_step(step, roundToInt(1.0/rate)))
1941     {
1942         andersen_tcoupl(ir, step, cr, md, v, rate,
1943                         upd->sd->randomize_group, upd->sd->boltzfac);
1944         return TRUE;
1945     }
1946     return FALSE;
1947 }