Reimplement constant acceleration groups
authorBerk Hess <hess@kth.se>
Fri, 29 Oct 2021 14:50:28 +0000 (14:50 +0000)
committerMark Abraham <mark.j.abraham@gmail.com>
Fri, 29 Oct 2021 14:50:28 +0000 (14:50 +0000)
32 files changed:
docs/reference-manual/algorithms/group-concept.rst
docs/release-notes/2022/major/bugs-fixed.rst
docs/release-notes/2022/major/removed-functionality.rst
docs/user-guide/mdp-options.rst
src/gromacs/fileio/tpxio.cpp
src/gromacs/gmxpreprocess/readir.cpp
src/gromacs/gmxpreprocess/tests/refdata/GetIrTest_AcceptsDefineParametersWithValuesIncludingAssignment.xml
src/gromacs/gmxpreprocess/tests/refdata/GetIrTest_AcceptsElectricField.xml
src/gromacs/gmxpreprocess/tests/refdata/GetIrTest_AcceptsElectricFieldOscillating.xml
src/gromacs/gmxpreprocess/tests/refdata/GetIrTest_AcceptsElectricFieldPulsed.xml
src/gromacs/gmxpreprocess/tests/refdata/GetIrTest_AcceptsEmptyLines.xml
src/gromacs/gmxpreprocess/tests/refdata/GetIrTest_AcceptsImplicitSolventNo.xml
src/gromacs/gmxpreprocess/tests/refdata/GetIrTest_AcceptsKeyWithoutValue.xml
src/gromacs/gmxpreprocess/tests/refdata/GetIrTest_AcceptsMimic.xml
src/gromacs/gmxpreprocess/tests/refdata/GetIrTest_HandlesDifferentKindsOfMdpLines.xml
src/gromacs/mdlib/mdatoms.cpp
src/gromacs/mdlib/tests/leapfrogtestdata.cpp
src/gromacs/mdlib/update.cpp
src/gromacs/mdlib/update.h
src/gromacs/mdrun/md.cpp
src/gromacs/mdrun/runner.cpp
src/gromacs/mdrun/shellfc.cpp
src/gromacs/mdtypes/inputrec.cpp
src/gromacs/mdtypes/inputrec.h
src/gromacs/mdtypes/mdatom.h
src/gromacs/modularsimulator/modularsimulator.cpp
src/gromacs/taskassignment/decidegpuusage.cpp
src/gromacs/tools/dump.cpp
src/gromacs/topology/topology.h
src/programs/mdrun/tests/CMakeLists.txt
src/programs/mdrun/tests/constantacceleration.cpp [new file with mode: 0644]
src/testutils/testmatchers.cpp

index 1c97ea602c6df8e894a90ec7360674e96dd9bca0..f62eae61ebb5e65eca19e15531e5d2edde1f4e1d 100644 (file)
@@ -40,6 +40,14 @@ freeze group
     simulation, and afterward use position restraints in conjunction
     with constant pressure.
 
     simulation, and afterward use position restraints in conjunction
     with constant pressure.
 
+accelerate group
+
+    On each atom in an “accelerate group” an acceleration
+    :math:`\mathbf{a}^g` is imposed. This is equivalent to
+    a mass-weighted external force. This feature makes it possible to
+    drive the system into a non-equilibrium state to compute,
+    for example, transport properties.
+
 energy-monitor group
 
     Mutual interactions between all energy-monitor groups are compiled
 energy-monitor group
 
     Mutual interactions between all energy-monitor groups are compiled
index c41151c576e07ec3d314e23c38717787ae249968..9be30ced0976fcca2b26cb76e8ae55a1792c951c 100644 (file)
@@ -26,11 +26,18 @@ both dhdl.xvg and the energy file, which is used by e.g. gmx bar, was correct.
    Also, please use the syntax :issue:`number` to reference issues on GitLab, without the
    a space between the colon and number!
 
    Also, please use the syntax :issue:`number` to reference issues on GitLab, without the
    a space between the colon and number!
 
+Removed velocity output for acceleration groups
+"""""""""""""""""""""""""""""""""""""""""""""""
+
+The reported velocity in the energy file for acceleration groups was always
+zero. Now their velocity is no longer reported in the energy file.
+
+:issue:`1354`
+
 Use correct c0 parameter in Me2PO4 in OPLSAA
 """"""""""""""""""""""""""""""""""""""""""""
 
 Use correct c0 parameter in Me2PO4 in OPLSAA
 """"""""""""""""""""""""""""""""""""""""""""
 
-OPLSAA torsions must sum to 0, but the paramters for Me2PO4 did not do so. Changed the c0
+OPLSAA torsions must sum to 0, but the parameters for Me2PO4 did not do so. Changed the c0
 parameter to the correct value.
 
 :issue:`4075`
 parameter to the correct value.
 
 :issue:`4075`
-
index 440bb6413e2c23b79948e2840ecddaf49aab58c6..f21e37f0c8bd73a731979848ec732883732c23d5 100644 (file)
@@ -1,13 +1,6 @@
 Removed functionality
 ^^^^^^^^^^^^^^^^^^^^^
 
 Removed functionality
 ^^^^^^^^^^^^^^^^^^^^^
 
-Removed constant-acceleration groups support
-""""""""""""""""""""""""""""""""""""""""""""
-This code has been broken since before GROMACS 4.6, so it has been
-removed.
-
-:issue:`1354`
-
 .. Note to developers!
    Please use """"""" to underline the individual entries for fixed issues in the subfolders,
    otherwise the formatting on the webpage is messed up.
 .. Note to developers!
    Please use """"""" to underline the individual entries for fixed issues in the subfolders,
    otherwise the formatting on the webpage is messed up.
index d0e990632a2d1c6cffd21ef5b0184893162a25b7..a1b96fa84ac135e94694637e732a0e86f0c1580d 100644 (file)
@@ -3023,6 +3023,23 @@ Expanded Ensemble calculations
 Non-equilibrium MD
 ^^^^^^^^^^^^^^^^^^
 
 Non-equilibrium MD
 ^^^^^^^^^^^^^^^^^^
 
+.. mdp:: acc-grps
+
+   groups for constant acceleration (*e.g.* ``Protein Sol``) all atoms
+   in groups Protein and Sol will experience constant acceleration as
+   specified in the :mdp:`accelerate` line. Note that the kinetic energy
+   of the center of mass of accelarated groups contributes to the kinetic
+   energy and temperature of the system. If this is not desired, make
+   each accelerate group also a separate temperature coupling group.
+
+.. mdp:: accelerate
+
+   (0) [nm ps\ :sup:`-2`]
+   acceleration for :mdp:`acc-grps`; x, y and z for each group
+   (*e.g.* ``0.1 0.0 0.0 -0.1 0.0 0.0`` means that first group has
+   constant acceleration of 0.1 nm ps\ :sup:`-2` in X direction, second group
+   the opposite).
+
 .. mdp:: freezegrps
 
    Groups that are to be frozen (*i.e.* their X, Y, and/or Z position
 .. mdp:: freezegrps
 
    Groups that are to be frozen (*i.e.* their X, Y, and/or Z position
index c71bc38f2d61fb76e2c819076d47ef62d6198be3..d190d663ed65439cde1a942b82d33e4199ba6572 100644 (file)
@@ -139,6 +139,7 @@ enum tpxv
     tpxv_RemovedConstantAcceleration, /**< Removed support for constant acceleration NEMD. */
     tpxv_TransformationPullCoord,     /**< Support for transformation pull coordinates */
     tpxv_SoftcoreGapsys,              /**< Added gapsys softcore function */
     tpxv_RemovedConstantAcceleration, /**< Removed support for constant acceleration NEMD. */
     tpxv_TransformationPullCoord,     /**< Support for transformation pull coordinates */
     tpxv_SoftcoreGapsys,              /**< Added gapsys softcore function */
+    tpxv_ReaddedConstantAcceleration, /**< Re-added support for constant acceleration NEMD. */
     tpxv_Count                        /**< the total number of tpxv versions */
 };
 
     tpxv_Count                        /**< the total number of tpxv versions */
 };
 
@@ -1579,10 +1580,14 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
     {
         ir->opts.nhchainlength = 1;
     }
     {
         ir->opts.nhchainlength = 1;
     }
-    int removedOptsNgacc = 0;
-    if (serializer->reading() && file_version < tpxv_RemovedConstantAcceleration)
+    if (serializer->reading() && file_version >= tpxv_RemovedConstantAcceleration
+        && file_version < tpxv_ReaddedConstantAcceleration)
     {
     {
-        serializer->doInt(&removedOptsNgacc);
+        ir->opts.ngacc = 0;
+    }
+    else
+    {
+        serializer->doInt(&ir->opts.ngacc);
     }
     serializer->doInt(&ir->opts.ngfrz);
     serializer->doInt(&ir->opts.ngener);
     }
     serializer->doInt(&ir->opts.ngfrz);
     serializer->doInt(&ir->opts.ngener);
@@ -1597,6 +1602,7 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
         snew(ir->opts.anneal_temp, ir->opts.ngtc);
         snew(ir->opts.tau_t, ir->opts.ngtc);
         snew(ir->opts.nFreeze, ir->opts.ngfrz);
         snew(ir->opts.anneal_temp, ir->opts.ngtc);
         snew(ir->opts.tau_t, ir->opts.ngtc);
         snew(ir->opts.nFreeze, ir->opts.ngfrz);
+        snew(ir->opts.acceleration, ir->opts.ngacc);
         snew(ir->opts.egp_flags, ir->opts.ngener * ir->opts.ngener);
     }
     if (ir->opts.ngtc > 0)
         snew(ir->opts.egp_flags, ir->opts.ngener * ir->opts.ngener);
     }
     if (ir->opts.ngtc > 0)
@@ -1609,18 +1615,20 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
     {
         serializer->doIvecArray(ir->opts.nFreeze, ir->opts.ngfrz);
     }
     {
         serializer->doIvecArray(ir->opts.nFreeze, ir->opts.ngfrz);
     }
-    if (serializer->reading() && file_version < tpxv_RemovedConstantAcceleration && removedOptsNgacc > 0)
+    if (ir->opts.ngacc > 0)
     {
     {
-        std::vector<gmx::RVec> dummy;
-        dummy.resize(removedOptsNgacc);
-        serializer->doRvecArray(reinterpret_cast<rvec*>(dummy.data()), removedOptsNgacc);
-        ir->useConstantAcceleration = std::any_of(dummy.begin(), dummy.end(), [](const gmx::RVec& vec) {
-            return vec[XX] != 0.0 || vec[YY] != 0.0 || vec[ZZ] != 0.0;
-        });
+        serializer->doRvecArray(ir->opts.acceleration, ir->opts.ngacc);
     }
     }
-    else
+    if (serializer->reading())
     {
         ir->useConstantAcceleration = false;
     {
         ir->useConstantAcceleration = false;
+        for (int g = 0; g < ir->opts.ngacc; g++)
+        {
+            if (norm2(ir->opts.acceleration[g]) != 0)
+            {
+                ir->useConstantAcceleration = true;
+            }
+        }
     }
     serializer->doIntArray(ir->opts.egp_flags, ir->opts.ngener * ir->opts.ngener);
 
     }
     serializer->doIntArray(ir->opts.egp_flags, ir->opts.ngener * ir->opts.ngener);
 
@@ -2632,11 +2640,6 @@ static void do_mtop(gmx::ISerializer* serializer, gmx_mtop_t* mtop, int file_ver
     }
 
     do_groups(serializer, &mtop->groups, &(mtop->symtab));
     }
 
     do_groups(serializer, &mtop->groups, &(mtop->symtab));
-    if (file_version < tpxv_RemovedConstantAcceleration)
-    {
-        mtop->groups.groups[SimulationAtomGroupType::AccelerationUnused].clear();
-        mtop->groups.groupNumbers[SimulationAtomGroupType::AccelerationUnused].clear();
-    }
 
     mtop->haveMoleculeIndices = true;
 
 
     mtop->haveMoleculeIndices = true;
 
index ff47ab5a35ea0e2ee71578db6db51c298f087985..557a361c8f2f472ffc94c0b719a7a6633d9b2cde 100644 (file)
@@ -107,10 +107,11 @@ using gmx::BasicVector;
 
 struct gmx_inputrec_strings
 {
 
 struct gmx_inputrec_strings
 {
-    char tcgrps[STRLEN], tau_t[STRLEN], ref_t[STRLEN], freeze[STRLEN], frdim[STRLEN],
-            energy[STRLEN], user1[STRLEN], user2[STRLEN], vcm[STRLEN], x_compressed_groups[STRLEN],
-            couple_moltype[STRLEN], orirefitgrp[STRLEN], egptable[STRLEN], egpexcl[STRLEN],
-            wall_atomtype[STRLEN], wall_density[STRLEN], deform[STRLEN], QMMM[STRLEN], imd_grp[STRLEN];
+    char tcgrps[STRLEN], tau_t[STRLEN], ref_t[STRLEN], accelerationGroups[STRLEN],
+            acceleration[STRLEN], freeze[STRLEN], frdim[STRLEN], energy[STRLEN], user1[STRLEN],
+            user2[STRLEN], vcm[STRLEN], x_compressed_groups[STRLEN], couple_moltype[STRLEN],
+            orirefitgrp[STRLEN], egptable[STRLEN], egpexcl[STRLEN], wall_atomtype[STRLEN],
+            wall_density[STRLEN], deform[STRLEN], QMMM[STRLEN], imd_grp[STRLEN];
     gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, std::string> fep_lambda;
     char                                                                   lambda_weights[STRLEN];
     std::vector<std::string>                                               pullGroupNames;
     gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, std::string> fep_lambda;
     char                                                                   lambda_weights[STRLEN];
     std::vector<std::string>                                               pullGroupNames;
@@ -1771,6 +1772,33 @@ static void convertReals(warninp_t wi, gmx::ArrayRef<const std::string> inputs,
     }
 }
 
     }
 }
 
+static void convertRvecs(warninp_t wi, gmx::ArrayRef<const std::string> inputs, const char* name, rvec* outputs)
+{
+    int i = 0, d = 0;
+    for (const auto& input : inputs)
+    {
+        try
+        {
+            outputs[i][d] = gmx::fromString<real>(input);
+        }
+        catch (gmx::GromacsException&)
+        {
+            auto message = gmx::formatString(
+                    "Invalid value for mdp option %s. %s should only consist of real numbers "
+                    "separated by spaces.",
+                    name,
+                    name);
+            warning_error(wi, message);
+        }
+        ++d;
+        if (d == DIM)
+        {
+            d = 0;
+            ++i;
+        }
+    }
+}
+
 static void do_wall_params(t_inputrec* ir, char* wall_atomtype, char* wall_density, t_gromppopts* opts, warninp_t wi)
 {
     opts->wall_atomtype[0] = nullptr;
 static void do_wall_params(t_inputrec* ir, char* wall_atomtype, char* wall_density, t_gromppopts* opts, warninp_t wi)
 {
     opts->wall_atomtype[0] = nullptr;
@@ -2340,6 +2368,8 @@ void get_ir(const char*     mdparin,
 
     /* Non-equilibrium MD stuff */
     printStringNewline(&inp, "Non-equilibrium MD stuff");
 
     /* Non-equilibrium MD stuff */
     printStringNewline(&inp, "Non-equilibrium MD stuff");
+    setStringEntry(&inp, "acc-grps", inputrecStrings->accelerationGroups, nullptr);
+    setStringEntry(&inp, "accelerate", inputrecStrings->acceleration, nullptr);
     setStringEntry(&inp, "freezegrps", inputrecStrings->freeze, nullptr);
     setStringEntry(&inp, "freezedim", inputrecStrings->frdim, nullptr);
     ir->cos_accel = get_ereal(&inp, "cos-acceleration", 0, wi);
     setStringEntry(&inp, "freezegrps", inputrecStrings->freeze, nullptr);
     setStringEntry(&inp, "freezedim", inputrecStrings->frdim, nullptr);
     ir->cos_accel = get_ereal(&inp, "cos-acceleration", 0, wi);
@@ -3907,6 +3937,31 @@ void do_index(const char*                    mdparin,
             *defaultIndexGroups, gmx::arrayRefFromArray(gnames, defaultIndexGroups->nr));
     mdModulesNotifiers.preProcessingNotifier_.notify(defaultIndexGroupsAndNames);
 
             *defaultIndexGroups, gmx::arrayRefFromArray(gnames, defaultIndexGroups->nr));
     mdModulesNotifiers.preProcessingNotifier_.notify(defaultIndexGroupsAndNames);
 
+    auto accelerations          = gmx::splitString(inputrecStrings->acceleration);
+    auto accelerationGroupNames = gmx::splitString(inputrecStrings->accelerationGroups);
+    if (accelerationGroupNames.size() * DIM != accelerations.size())
+    {
+        gmx_fatal(FARGS,
+                  "Invalid Acceleration input: %zu groups and %zu acc. values",
+                  accelerationGroupNames.size(),
+                  accelerations.size());
+    }
+    do_numbering(natoms,
+                 groups,
+                 accelerationGroupNames,
+                 defaultIndexGroups,
+                 gnames,
+                 SimulationAtomGroupType::Acceleration,
+                 restnm,
+                 GroupCoverage::AllGenerateRest,
+                 bVerbose,
+                 wi);
+    nr = groups->groups[SimulationAtomGroupType::Acceleration].size();
+    snew(ir->opts.acceleration, nr);
+    ir->opts.ngacc = nr;
+
+    convertRvecs(wi, accelerations, "accelerations", ir->opts.acceleration);
+
     auto freezeDims       = gmx::splitString(inputrecStrings->frdim);
     auto freezeGroupNames = gmx::splitString(inputrecStrings->freeze);
     if (freezeDims.size() != DIM * freezeGroupNames.size())
     auto freezeDims       = gmx::splitString(inputrecStrings->frdim);
     auto freezeGroupNames = gmx::splitString(inputrecStrings->freeze);
     if (freezeDims.size() != DIM * freezeGroupNames.size())
@@ -4370,6 +4425,7 @@ void triple_check(const char* mdparin, t_inputrec* ir, gmx_mtop_t* sys, warninp_
     char                      err_buf[STRLEN];
     int                       i, m, c, nmol;
     bool                      bCharge;
     char                      err_buf[STRLEN];
     int                       i, m, c, nmol;
     bool                      bCharge;
+    real *                    mgrp, mt;
     gmx_mtop_atomloop_block_t aloopb;
     char                      warn_buf[STRLEN];
 
     gmx_mtop_atomloop_block_t aloopb;
     char                      warn_buf[STRLEN];
 
@@ -4571,6 +4627,57 @@ void triple_check(const char* mdparin, t_inputrec* ir, gmx_mtop_t* sys, warninp_
                       "constant by hand.");
     }
 
                       "constant by hand.");
     }
 
+    ir->useConstantAcceleration = false;
+    for (int i = 0; (i < gmx::ssize(sys->groups.groups[SimulationAtomGroupType::Acceleration])); i++)
+    {
+        if (norm2(ir->opts.acceleration[i]) != 0)
+        {
+            ir->useConstantAcceleration = true;
+        }
+    }
+    if (ir->useConstantAcceleration)
+    {
+        gmx::RVec acceleration = { 0.0_real, 0.0_real, 0.0_real };
+        snew(mgrp, sys->groups.groups[SimulationAtomGroupType::Acceleration].size());
+        for (const AtomProxy atomP : AtomRange(*sys))
+        {
+            const t_atom& local = atomP.atom();
+            int           i     = atomP.globalAtomNumber();
+            mgrp[getGroupType(sys->groups, SimulationAtomGroupType::Acceleration, i)] += local.m;
+        }
+        mt = 0.0;
+        for (i = 0; (i < gmx::ssize(sys->groups.groups[SimulationAtomGroupType::Acceleration])); i++)
+        {
+            for (m = 0; (m < DIM); m++)
+            {
+                acceleration[m] += ir->opts.acceleration[i][m] * mgrp[i];
+            }
+            mt += mgrp[i];
+        }
+        for (m = 0; (m < DIM); m++)
+        {
+            if (fabs(acceleration[m]) > 1e-6)
+            {
+                const char* dim[DIM] = { "X", "Y", "Z" };
+                fprintf(stderr,
+                        "Net Acceleration in %s direction, will %s be corrected\n",
+                        dim[m],
+                        ir->nstcomm != 0 ? "" : "not");
+                if (ir->nstcomm != 0 && m < ndof_com(ir))
+                {
+                    acceleration[m] /= mt;
+                    for (i = 0;
+                         (i < gmx::ssize(sys->groups.groups[SimulationAtomGroupType::Acceleration]));
+                         i++)
+                    {
+                        ir->opts.acceleration[i][m] -= acceleration[m];
+                    }
+                }
+            }
+        }
+        sfree(mgrp);
+    }
+
     if (ir->efep != FreeEnergyPerturbationType::No && ir->fepvals->sc_alpha != 0
         && !gmx_within_tol(sys->ffparams.reppow, 12.0, 10 * GMX_DOUBLE_EPS))
     {
     if (ir->efep != FreeEnergyPerturbationType::No && ir->fepvals->sc_alpha != 0
         && !gmx_within_tol(sys->ffparams.reppow, 12.0, 10 * GMX_DOUBLE_EPS))
     {
index a7cc35f439494cb71a6eac5ccdf50193d87afe82..0cf43f926cf3f10dd02ea09fd748e5bd2e7a45c6 100644 (file)
@@ -264,6 +264,8 @@ dh_hist_size             = 0
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
+acc-grps                 = 
+accelerate               = 
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
index cbf5084ddc1e8688f3b8ebfc4da981306c7b124c..184ec9c259840a64e5f31ad2d94b887a05b42eb3 100644 (file)
@@ -264,6 +264,8 @@ dh_hist_size             = 0
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
+acc-grps                 = 
+accelerate               = 
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
index 7e439fa8b5fb80babed83e495fc003e9d13d2970..53a4f45999cfade268f11b6add23d8ba59fe86ba 100644 (file)
@@ -264,6 +264,8 @@ dh_hist_size             = 0
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
+acc-grps                 = 
+accelerate               = 
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
index 71826f94aa694cff9c4068ea18639038d7c5a5e0..9b6639cc6480f7b1d524f1e7b7f30fd584cc1af2 100644 (file)
@@ -264,6 +264,8 @@ dh_hist_size             = 0
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
+acc-grps                 = 
+accelerate               = 
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
index d6fc03c7cbe2e66b420c91792f76e441535bacd1..2298676e1656d32c757d780dfeef2d002c0b4317 100644 (file)
@@ -264,6 +264,8 @@ dh_hist_size             = 0
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
+acc-grps                 = 
+accelerate               = 
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
index d6fc03c7cbe2e66b420c91792f76e441535bacd1..2298676e1656d32c757d780dfeef2d002c0b4317 100644 (file)
@@ -264,6 +264,8 @@ dh_hist_size             = 0
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
+acc-grps                 = 
+accelerate               = 
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
index d6fc03c7cbe2e66b420c91792f76e441535bacd1..2298676e1656d32c757d780dfeef2d002c0b4317 100644 (file)
@@ -264,6 +264,8 @@ dh_hist_size             = 0
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
+acc-grps                 = 
+accelerate               = 
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
index 391a10118cdd1b97e4070ac2786e2f19a1b182cd..38dfb294cbbc93b47f9dfc3994d1979c638bc147 100644 (file)
@@ -264,6 +264,8 @@ dh_hist_size             = 0
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
+acc-grps                 = 
+accelerate               = 
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
index 202eac0de7cb7a2d89aba7edd219c78eb7548629..f1a0281dc907616ccd7ad911421fb1b300188f3f 100644 (file)
@@ -264,6 +264,8 @@ dh_hist_size             = 0
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
+acc-grps                 = 
+accelerate               = 
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
index 3749019a9dd95abc1df245f5cc3c6971c434471b..e4ee7b7b57abc81466d0d94f3b80790d1e5917a4 100644 (file)
@@ -87,6 +87,7 @@ MDAtoms::~MDAtoms()
     sfree(mdatoms_->ptype);
     sfree(mdatoms_->cTC);
     sfree(mdatoms_->cENER);
     sfree(mdatoms_->ptype);
     sfree(mdatoms_->cTC);
     sfree(mdatoms_->cENER);
+    sfree(mdatoms_->cACC);
     sfree(mdatoms_->cFREEZE);
     sfree(mdatoms_->cVCM);
     sfree(mdatoms_->cORF);
     sfree(mdatoms_->cFREEZE);
     sfree(mdatoms_->cVCM);
     sfree(mdatoms_->cORF);
@@ -288,6 +289,10 @@ void atoms2md(const gmx_mtop_t&  mtop,
             /* We always copy cTC with domain decomposition */
         }
         srenew(md->cENER, md->nalloc);
             /* We always copy cTC with domain decomposition */
         }
         srenew(md->cENER, md->nalloc);
+        if (inputrec.useConstantAcceleration)
+        {
+            srenew(md->cACC, md->nalloc);
+        }
         if (inputrecFrozenAtoms(&inputrec))
         {
             srenew(md->cFREEZE, md->nalloc);
         if (inputrecFrozenAtoms(&inputrec))
         {
             srenew(md->cFREEZE, md->nalloc);
@@ -474,6 +479,10 @@ void atoms2md(const gmx_mtop_t&  mtop,
                 md->cTC[i] = groups.groupNumbers[SimulationAtomGroupType::TemperatureCoupling][ag];
             }
             md->cENER[i] = getGroupType(groups, SimulationAtomGroupType::EnergyOutput, ag);
                 md->cTC[i] = groups.groupNumbers[SimulationAtomGroupType::TemperatureCoupling][ag];
             }
             md->cENER[i] = getGroupType(groups, SimulationAtomGroupType::EnergyOutput, ag);
+            if (md->cACC)
+            {
+                md->cACC[i] = groups.groupNumbers[SimulationAtomGroupType::Acceleration][ag];
+            }
             if (md->cVCM)
             {
                 md->cVCM[i] = groups.groupNumbers[SimulationAtomGroupType::MassCenterVelocityRemoval][ag];
             if (md->cVCM)
             {
                 md->cVCM[i] = groups.groupNumbers[SimulationAtomGroupType::MassCenterVelocityRemoval][ag];
index 3f66855450e8cdec66b8e57c54b1db109c8429ac..cf80cda412530db1c9f349f97979d534dc18b612 100644 (file)
@@ -175,7 +175,8 @@ LeapFrogTestData::LeapFrogTestData(int        numAtoms,
     update_ = std::make_unique<Update>(inputRecord_, nullptr);
     update_->updateAfterPartition(numAtoms,
                                   gmx::ArrayRef<const unsigned short>(),
     update_ = std::make_unique<Update>(inputRecord_, nullptr);
     update_->updateAfterPartition(numAtoms,
                                   gmx::ArrayRef<const unsigned short>(),
-                                  gmx::arrayRefFromArray(mdAtoms_.cTC, mdAtoms_.nr));
+                                  gmx::arrayRefFromArray(mdAtoms_.cTC, mdAtoms_.nr),
+                                  gmx::ArrayRef<const unsigned short>());
 
     doPressureCouple_ = (nstpcouple != 0);
 
 
     doPressureCouple_ = (nstpcouple != 0);
 
index 800d68aa1d830587c6add17129fed533a4eb181c..3a7c4b0961e5762d87120f8384d3e7b23032a94f 100644 (file)
@@ -174,6 +174,8 @@ public:
     gmx::ArrayRef<const unsigned short> cFREEZE_;
     //! Group index for temperature coupling
     gmx::ArrayRef<const unsigned short> cTC_;
     gmx::ArrayRef<const unsigned short> cFREEZE_;
     //! Group index for temperature coupling
     gmx::ArrayRef<const unsigned short> cTC_;
+    //! Group index for accleration groups
+    gmx::ArrayRef<const unsigned short> cAcceleration_;
 
 private:
     //! stochastic dynamics struct
 
 private:
     //! stochastic dynamics struct
@@ -517,6 +519,7 @@ updateMDLeapfrogSimpleSimd(int                               start,
 enum class AccelerationType
 {
     none,
 enum class AccelerationType
 {
     none,
+    group,
     cosine
 };
 
     cosine
 };
 
@@ -530,6 +533,8 @@ enum class AccelerationType
  * \param[in]     dtPressureCouple  Time step for pressure coupling, is 0 when no pressure
  *                                  coupling should be applied at this step.
  * \param[in]     cTC               Temperature coupling group indices
  * \param[in]     dtPressureCouple  Time step for pressure coupling, is 0 when no pressure
  *                                  coupling should be applied at this step.
  * \param[in]     cTC               Temperature coupling group indices
+ * \param[in]     cAcceleration     Acceleration group indices
+ * \param[in]     acceleration      Acceleration per group.
  * \param[in]     invMassPerDim     Inverse mass per dimension
  * \param[in]     ekind             Kinetic energy data.
  * \param[in]     box               The box dimensions.
  * \param[in]     invMassPerDim     Inverse mass per dimension
  * \param[in]     ekind             Kinetic energy data.
  * \param[in]     box               The box dimensions.
@@ -548,6 +553,8 @@ static void updateMDLeapfrogGeneral(int                                 start,
                                     real                                dt,
                                     real                                dtPressureCouple,
                                     gmx::ArrayRef<const unsigned short> cTC,
                                     real                                dt,
                                     real                                dtPressureCouple,
                                     gmx::ArrayRef<const unsigned short> cTC,
+                                    gmx::ArrayRef<const unsigned short> cAcceleration,
+                                    const rvec* gmx_restrict            acceleration,
                                     gmx::ArrayRef<const rvec>           invMassPerDim,
                                     const gmx_ekindata_t*               ekind,
                                     const matrix                        box,
                                     gmx::ArrayRef<const rvec>           invMassPerDim,
                                     const gmx_ekindata_t*               ekind,
                                     const matrix                        box,
@@ -568,6 +575,7 @@ static void updateMDLeapfrogGeneral(int                                 start,
     gmx::ArrayRef<const t_grp_tcstat> tcstat = ekind->tcstat;
 
     /* Initialize group values, changed later when multiple groups are used */
     gmx::ArrayRef<const t_grp_tcstat> tcstat = ekind->tcstat;
 
     /* Initialize group values, changed later when multiple groups are used */
+    int ga = 0;
     int gt = 0;
 
     real omega_Z = 2 * static_cast<real>(M_PI) / box[ZZ][ZZ];
     int gt = 0;
 
     real omega_Z = 2 * static_cast<real>(M_PI) / box[ZZ][ZZ];
@@ -585,6 +593,14 @@ static void updateMDLeapfrogGeneral(int                                 start,
         switch (accelerationType)
         {
             case AccelerationType::none: copy_rvec(v[n], vRel); break;
         switch (accelerationType)
         {
             case AccelerationType::none: copy_rvec(v[n], vRel); break;
+            case AccelerationType::group:
+                if (!cAcceleration.empty())
+                {
+                    ga = cAcceleration[n];
+                }
+                /* With constant acceleration we do scale the velocity of the accelerated groups */
+                copy_rvec(v[n], vRel);
+                break;
             case AccelerationType::cosine:
                 cosineZ = std::cos(x[n][ZZ] * omega_Z);
                 vCosine = cosineZ * ekind->cosacc.vcos;
             case AccelerationType::cosine:
                 cosineZ = std::cos(x[n][ZZ] * omega_Z);
                 vCosine = cosineZ * ekind->cosacc.vcos;
@@ -613,6 +629,10 @@ static void updateMDLeapfrogGeneral(int                                 start,
             switch (accelerationType)
             {
                 case AccelerationType::none: break;
             switch (accelerationType)
             {
                 case AccelerationType::none: break;
+                case AccelerationType::group:
+                    /* Apply the constant acceleration */
+                    vNew += acceleration[ga][d] * dt;
+                    break;
                 case AccelerationType::cosine:
                     if (d == XX)
                     {
                 case AccelerationType::cosine:
                     if (d == XX)
                     {
@@ -641,6 +661,9 @@ static void do_update_md(int                                  start,
                          const int                            nsttcouple,
                          const int                            nstpcouple,
                          gmx::ArrayRef<const unsigned short>  cTC,
                          const int                            nsttcouple,
                          const int                            nstpcouple,
                          gmx::ArrayRef<const unsigned short>  cTC,
+                         const bool                           useConstantAcceleration,
+                         gmx::ArrayRef<const unsigned short>  cAcceleration,
+                         const rvec*                          acceleration,
                          gmx::ArrayRef<const real> gmx_unused invmass,
                          gmx::ArrayRef<const rvec>            invMassPerDim,
                          const gmx_ekindata_t*                ekind,
                          gmx::ArrayRef<const real> gmx_unused invmass,
                          gmx::ArrayRef<const rvec>            invMassPerDim,
                          const gmx_ekindata_t*                ekind,
@@ -662,8 +685,8 @@ static void do_update_md(int                                  start,
 
     real dtPressureCouple = (doParrinelloRahman ? nstpcouple * dt : 0);
 
 
     real dtPressureCouple = (doParrinelloRahman ? nstpcouple * dt : 0);
 
-    /* NEMD cosine acceleration is applied in updateMDLeapFrogGeneral */
-    bool doAcceleration = (ekind->cosacc.cos_accel != 0);
+    /* NEMD (also cosine) acceleration is applied in updateMDLeapFrogGeneral */
+    const bool doAcceleration = (useConstantAcceleration || ekind->cosacc.cos_accel != 0);
 
     if (doNoseHoover || doPROffDiagonal || doAcceleration)
     {
 
     if (doNoseHoover || doPROffDiagonal || doAcceleration)
     {
@@ -686,6 +709,8 @@ static void do_update_md(int                                  start,
                                                             dt,
                                                             dtPressureCouple,
                                                             cTC,
                                                             dt,
                                                             dtPressureCouple,
                                                             cTC,
+                                                            cAcceleration,
+                                                            acceleration,
                                                             invMassPerDim,
                                                             ekind,
                                                             box,
                                                             invMassPerDim,
                                                             ekind,
                                                             box,
@@ -697,6 +722,27 @@ static void do_update_md(int                                  start,
                                                             nsttcouple,
                                                             stepM);
         }
                                                             nsttcouple,
                                                             stepM);
         }
+        else if (useConstantAcceleration)
+        {
+            updateMDLeapfrogGeneral<AccelerationType::group>(start,
+                                                             nrend,
+                                                             doNoseHoover,
+                                                             dt,
+                                                             dtPressureCouple,
+                                                             cTC,
+                                                             cAcceleration,
+                                                             acceleration,
+                                                             invMassPerDim,
+                                                             ekind,
+                                                             box,
+                                                             x,
+                                                             xprime,
+                                                             v,
+                                                             f,
+                                                             nh_vxi,
+                                                             nsttcouple,
+                                                             stepM);
+        }
         else
         {
             updateMDLeapfrogGeneral<AccelerationType::cosine>(start,
         else
         {
             updateMDLeapfrogGeneral<AccelerationType::cosine>(start,
@@ -705,6 +751,8 @@ static void do_update_md(int                                  start,
                                                               dt,
                                                               dtPressureCouple,
                                                               cTC,
                                                               dt,
                                                               dtPressureCouple,
                                                               cTC,
+                                                              cAcceleration,
+                                                              acceleration,
                                                               invMassPerDim,
                                                               ekind,
                                                               box,
                                                               invMassPerDim,
                                                               ekind,
                                                               box,
@@ -820,6 +868,8 @@ static void do_update_vv_vel(int                                 start,
                              int                                 nrend,
                              real                                dt,
                              gmx::ArrayRef<const ivec>           nFreeze,
                              int                                 nrend,
                              real                                dt,
                              gmx::ArrayRef<const ivec>           nFreeze,
+                             gmx::ArrayRef<const unsigned short> cAcceleration,
+                             const rvec*                         acceleration,
                              gmx::ArrayRef<const real>           invmass,
                              gmx::ArrayRef<const ParticleType>   ptype,
                              gmx::ArrayRef<const unsigned short> cFREEZE,
                              gmx::ArrayRef<const real>           invmass,
                              gmx::ArrayRef<const ParticleType>   ptype,
                              gmx::ArrayRef<const unsigned short> cFREEZE,
@@ -829,7 +879,7 @@ static void do_update_vv_vel(int                                 start,
                              real                                veta,
                              real                                alpha)
 {
                              real                                veta,
                              real                                alpha)
 {
-    int  gf = 0;
+    int  gf = 0, ga = 0;
     int  n, d;
     real g, mv1, mv2;
 
     int  n, d;
     real g, mv1, mv2;
 
@@ -851,12 +901,17 @@ static void do_update_vv_vel(int                                 start,
         {
             gf = cFREEZE[n];
         }
         {
             gf = cFREEZE[n];
         }
+        if (!cAcceleration.empty())
+        {
+            ga = cAcceleration[n];
+        }
 
         for (d = 0; d < DIM; d++)
         {
             if ((ptype[n] != ParticleType::Shell) && !nFreeze[gf][d])
             {
 
         for (d = 0; d < DIM; d++)
         {
             if ((ptype[n] != ParticleType::Shell) && !nFreeze[gf][d])
             {
-                v[n][d] = mv1 * (mv1 * v[n][d] + 0.5 * (w_dt * mv2 * f[n][d]));
+                v[n][d] = mv1 * (mv1 * v[n][d] + 0.5 * (w_dt * mv2 * f[n][d]))
+                          + 0.5 * acceleration[ga][d] * dt;
             }
             else
             {
             }
             else
             {
@@ -1009,12 +1064,14 @@ Update::Impl::Impl(const t_inputrec& inputRecord, BoxDeformation* boxDeformation
 
 void Update::updateAfterPartition(int                                 numAtoms,
                                   gmx::ArrayRef<const unsigned short> cFREEZE,
 
 void Update::updateAfterPartition(int                                 numAtoms,
                                   gmx::ArrayRef<const unsigned short> cFREEZE,
-                                  gmx::ArrayRef<const unsigned short> cTC)
+                                  gmx::ArrayRef<const unsigned short> cTC,
+                                  gmx::ArrayRef<const unsigned short> cAcceleration)
 {
 
     impl_->xp()->resizeWithPadding(numAtoms);
 {
 
     impl_->xp()->resizeWithPadding(numAtoms);
-    impl_->cFREEZE_ = cFREEZE;
-    impl_->cTC_     = cTC;
+    impl_->cFREEZE_       = cFREEZE;
+    impl_->cTC_           = cTC;
+    impl_->cAcceleration_ = cAcceleration;
 }
 
 /*! \brief Sets the SD update type */
 }
 
 /*! \brief Sets the SD update type */
@@ -1048,6 +1105,8 @@ static void doSDUpdateGeneral(const gmx_stochd_t&                 sd,
                               gmx::ArrayRef<const ParticleType>   ptype,
                               gmx::ArrayRef<const unsigned short> cFREEZE,
                               gmx::ArrayRef<const unsigned short> cTC,
                               gmx::ArrayRef<const ParticleType>   ptype,
                               gmx::ArrayRef<const unsigned short> cFREEZE,
                               gmx::ArrayRef<const unsigned short> cTC,
+                              gmx::ArrayRef<const unsigned short> cAcceleration,
+                              const rvec*                         acceleration,
                               const rvec                          x[],
                               rvec                                xprime[],
                               rvec                                v[],
                               const rvec                          x[],
                               rvec                                xprime[],
                               rvec                                v[],
@@ -1056,7 +1115,7 @@ static void doSDUpdateGeneral(const gmx_stochd_t&                 sd,
                               int                                 seed,
                               const int*                          gatindex)
 {
                               int                                 seed,
                               const int*                          gatindex)
 {
-    // cTC and cFREEZE can be nullptr any time, but various
+    // cTC, cACC and cFREEZE can be nullptr any time, but various
     // instantiations do not make sense with particular pointer
     // values.
     if (updateType == SDUpdate::ForcesOnly)
     // instantiations do not make sense with particular pointer
     // values.
     if (updateType == SDUpdate::ForcesOnly)
@@ -1067,6 +1126,8 @@ static void doSDUpdateGeneral(const gmx_stochd_t&                 sd,
     if (updateType == SDUpdate::FrictionAndNoiseOnly)
     {
         GMX_ASSERT(f == nullptr, "SD update with only noise cannot handle forces");
     if (updateType == SDUpdate::FrictionAndNoiseOnly)
     {
         GMX_ASSERT(f == nullptr, "SD update with only noise cannot handle forces");
+        GMX_ASSERT(cAcceleration.empty(),
+                   "SD update with only noise cannot handle acceleration groups");
     }
     if (updateType == SDUpdate::Combined)
     {
     }
     if (updateType == SDUpdate::Combined)
     {
@@ -1086,8 +1147,9 @@ static void doSDUpdateGeneral(const gmx_stochd_t&                 sd,
         real inverseMass = invmass[n];
         real invsqrtMass = std::sqrt(inverseMass);
 
         real inverseMass = invmass[n];
         real invsqrtMass = std::sqrt(inverseMass);
 
-        int freezeGroup      = !cFREEZE.empty() ? cFREEZE[n] : 0;
-        int temperatureGroup = !cTC.empty() ? cTC[n] : 0;
+        int freezeGroup       = !cFREEZE.empty() ? cFREEZE[n] : 0;
+        int accelerationGroup = !cAcceleration.empty() ? cAcceleration[n] : 0;
+        int temperatureGroup  = !cTC.empty() ? cTC[n] : 0;
 
         for (int d = 0; d < DIM; d++)
         {
 
         for (int d = 0; d < DIM; d++)
         {
@@ -1095,7 +1157,7 @@ static void doSDUpdateGeneral(const gmx_stochd_t&                 sd,
             {
                 if (updateType == SDUpdate::ForcesOnly)
                 {
             {
                 if (updateType == SDUpdate::ForcesOnly)
                 {
-                    real vn = v[n][d] + inverseMass * f[n][d] * dt;
+                    real vn = v[n][d] + (inverseMass * f[n][d] + acceleration[accelerationGroup][d]) * dt;
                     v[n][d] = vn;
                     // Simple position update.
                     xprime[n][d] = x[n][d] + v[n][d] * dt;
                     v[n][d] = vn;
                     // Simple position update.
                     xprime[n][d] = x[n][d] + v[n][d] * dt;
@@ -1112,7 +1174,7 @@ static void doSDUpdateGeneral(const gmx_stochd_t&                 sd,
                 }
                 else
                 {
                 }
                 else
                 {
-                    real vn = v[n][d] + inverseMass * f[n][d] * dt;
+                    real vn = v[n][d] + (inverseMass * f[n][d] + acceleration[accelerationGroup][d]) * dt;
                     v[n][d] = (vn * sd.sdc[temperatureGroup].em
                                + invsqrtMass * sd.sdsig[temperatureGroup].V * dist(rng));
                     // Here we include half of the friction+noise
                     v[n][d] = (vn * sd.sdc[temperatureGroup].em
                                + invsqrtMass * sd.sdsig[temperatureGroup].V * dist(rng));
                     // Here we include half of the friction+noise
@@ -1149,6 +1211,8 @@ static void do_update_sd(int                                 start,
                          gmx::ArrayRef<const ParticleType>   ptype,
                          gmx::ArrayRef<const unsigned short> cFREEZE,
                          gmx::ArrayRef<const unsigned short> cTC,
                          gmx::ArrayRef<const ParticleType>   ptype,
                          gmx::ArrayRef<const unsigned short> cFREEZE,
                          gmx::ArrayRef<const unsigned short> cTC,
+                         gmx::ArrayRef<const unsigned short> cAcceleration,
+                         const rvec*                         acceleration,
                          int                                 seed,
                          const t_commrec*                    cr,
                          const gmx_stochd_t&                 sd,
                          int                                 seed,
                          const t_commrec*                    cr,
                          const gmx_stochd_t&                 sd,
@@ -1166,6 +1230,8 @@ static void do_update_sd(int                                 start,
                                                 ptype,
                                                 cFREEZE,
                                                 gmx::ArrayRef<const unsigned short>(),
                                                 ptype,
                                                 cFREEZE,
                                                 gmx::ArrayRef<const unsigned short>(),
+                                                cAcceleration,
+                                                acceleration,
                                                 x,
                                                 xprime,
                                                 v,
                                                 x,
                                                 xprime,
                                                 v,
@@ -1186,6 +1252,8 @@ static void do_update_sd(int                                 start,
                 ptype,
                 cFREEZE,
                 cTC,
                 ptype,
                 cFREEZE,
                 cTC,
+                cAcceleration,
+                acceleration,
                 x,
                 xprime,
                 v,
                 x,
                 xprime,
                 v,
@@ -1426,6 +1494,8 @@ void Update::Impl::update_sd_second_half(const t_inputrec&                 input
                         ptype,
                         cFREEZE_,
                         cTC_,
                         ptype,
                         cFREEZE_,
                         cTC_,
+                        cAcceleration_,
+                        inputRecord.opts.acceleration,
                         state->x.rvec_array(),
                         xp_.rvec_array(),
                         state->v.rvec_array(),
                         state->x.rvec_array(),
                         xp_.rvec_array(),
                         state->v.rvec_array(),
@@ -1582,6 +1652,9 @@ void Update::Impl::update_coords(const t_inputrec&                 inputRecord,
                                  inputRecord.nsttcouple,
                                  inputRecord.nstpcouple,
                                  cTC_,
                                  inputRecord.nsttcouple,
                                  inputRecord.nstpcouple,
                                  cTC_,
+                                 inputRecord.useConstantAcceleration,
+                                 cAcceleration_,
+                                 inputRecord.opts.acceleration,
                                  invMass,
                                  invMassPerDim,
                                  ekind,
                                  invMass,
                                  invMassPerDim,
                                  ekind,
@@ -1604,6 +1677,8 @@ void Update::Impl::update_coords(const t_inputrec&                 inputRecord,
                                  ptype,
                                  cFREEZE_,
                                  cTC_,
                                  ptype,
                                  cFREEZE_,
                                  cTC_,
+                                 cAcceleration_,
+                                 inputRecord.opts.acceleration,
                                  inputRecord.ld_seed,
                                  cr,
                                  sd_,
                                  inputRecord.ld_seed,
                                  cr,
                                  sd_,
@@ -1646,6 +1721,8 @@ void Update::Impl::update_coords(const t_inputrec&                 inputRecord,
                                              dt,
                                              gmx::arrayRefFromArray(inputRecord.opts.nFreeze,
                                                                     inputRecord.opts.ngfrz),
                                              dt,
                                              gmx::arrayRefFromArray(inputRecord.opts.nFreeze,
                                                                     inputRecord.opts.ngfrz),
+                                             cAcceleration_,
+                                             inputRecord.opts.acceleration,
                                              invMass,
                                              ptype,
                                              cFREEZE_,
                                              invMass,
                                              ptype,
                                              cFREEZE_,
index a3c4844e2e06487f65b9bd6e33fd2c1e9f59a565..e8f95bc24cc5523859990280ba33f1545a9bb84b 100644 (file)
@@ -97,10 +97,12 @@ public:
      * \param[in] numAtoms  Updated number of atoms.
      * \param[in] cFREEZE   Group index for freezing
      * \param[in] cTC       Group index for center of mass motion removal
      * \param[in] numAtoms  Updated number of atoms.
      * \param[in] cFREEZE   Group index for freezing
      * \param[in] cTC       Group index for center of mass motion removal
+     * \param[in] cAcceleration  Group index for constant acceleration groups
      */
     void updateAfterPartition(int                                 numAtoms,
                               gmx::ArrayRef<const unsigned short> cFREEZE,
      */
     void updateAfterPartition(int                                 numAtoms,
                               gmx::ArrayRef<const unsigned short> cFREEZE,
-                              gmx::ArrayRef<const unsigned short> cTC);
+                              gmx::ArrayRef<const unsigned short> cTC,
+                              gmx::ArrayRef<const unsigned short> cAcceleration);
 
     /*! \brief Perform numerical integration step.
      *
 
     /*! \brief Perform numerical integration step.
      *
index 3898e07d3af54303c6059984bfc88b8a3e7a430f..735b5daa06cb44b98a31a7c6b572de0668bb4578 100644 (file)
@@ -395,7 +395,9 @@ void gmx::LegacySimulator::do_md()
                                  md->cFREEZE ? gmx::arrayRefFromArray(md->cFREEZE, md->nr)
                                              : gmx::ArrayRef<const unsigned short>(),
                                  md->cTC ? gmx::arrayRefFromArray(md->cTC, md->nr)
                                  md->cFREEZE ? gmx::arrayRefFromArray(md->cFREEZE, md->nr)
                                              : gmx::ArrayRef<const unsigned short>(),
                                  md->cTC ? gmx::arrayRefFromArray(md->cTC, md->nr)
-                                         : gmx::ArrayRef<const unsigned short>());
+                                         : gmx::ArrayRef<const unsigned short>(),
+                                 md->cACC ? gmx::arrayRefFromArray(md->cACC, md->nr)
+                                          : gmx::ArrayRef<const unsigned short>());
         fr->longRangeNonbondeds->updateAfterPartition(*md);
     }
     else
         fr->longRangeNonbondeds->updateAfterPartition(*md);
     }
     else
@@ -409,7 +411,9 @@ void gmx::LegacySimulator::do_md()
                                  md->cFREEZE ? gmx::arrayRefFromArray(md->cFREEZE, md->nr)
                                              : gmx::ArrayRef<const unsigned short>(),
                                  md->cTC ? gmx::arrayRefFromArray(md->cTC, md->nr)
                                  md->cFREEZE ? gmx::arrayRefFromArray(md->cFREEZE, md->nr)
                                              : gmx::ArrayRef<const unsigned short>(),
                                  md->cTC ? gmx::arrayRefFromArray(md->cTC, md->nr)
-                                         : gmx::ArrayRef<const unsigned short>());
+                                         : gmx::ArrayRef<const unsigned short>(),
+                                 md->cACC ? gmx::arrayRefFromArray(md->cACC, md->nr)
+                                          : gmx::ArrayRef<const unsigned short>());
         fr->longRangeNonbondeds->updateAfterPartition(*md);
     }
 
         fr->longRangeNonbondeds->updateAfterPartition(*md);
     }
 
@@ -1004,7 +1008,9 @@ void gmx::LegacySimulator::do_md()
                                          md->cFREEZE ? gmx::arrayRefFromArray(md->cFREEZE, md->nr)
                                                      : gmx::ArrayRef<const unsigned short>(),
                                          md->cTC ? gmx::arrayRefFromArray(md->cTC, md->nr)
                                          md->cFREEZE ? gmx::arrayRefFromArray(md->cFREEZE, md->nr)
                                                      : gmx::ArrayRef<const unsigned short>(),
                                          md->cTC ? gmx::arrayRefFromArray(md->cTC, md->nr)
-                                                 : gmx::ArrayRef<const unsigned short>());
+                                                 : gmx::ArrayRef<const unsigned short>(),
+                                         md->cACC ? gmx::arrayRefFromArray(md->cACC, md->nr)
+                                                  : gmx::ArrayRef<const unsigned short>());
                 fr->longRangeNonbondeds->updateAfterPartition(*md);
             }
         }
                 fr->longRangeNonbondeds->updateAfterPartition(*md);
             }
         }
@@ -1968,7 +1974,9 @@ void gmx::LegacySimulator::do_md()
                                      md->cFREEZE ? gmx::arrayRefFromArray(md->cFREEZE, md->nr)
                                                  : gmx::ArrayRef<const unsigned short>(),
                                      md->cTC ? gmx::arrayRefFromArray(md->cTC, md->nr)
                                      md->cFREEZE ? gmx::arrayRefFromArray(md->cFREEZE, md->nr)
                                                  : gmx::ArrayRef<const unsigned short>(),
                                      md->cTC ? gmx::arrayRefFromArray(md->cTC, md->nr)
-                                             : gmx::ArrayRef<const unsigned short>());
+                                             : gmx::ArrayRef<const unsigned short>(),
+                                     md->cACC ? gmx::arrayRefFromArray(md->cACC, md->nr)
+                                              : gmx::ArrayRef<const unsigned short>());
             fr->longRangeNonbondeds->updateAfterPartition(*md);
         }
 
             fr->longRangeNonbondeds->updateAfterPartition(*md);
         }
 
index 43551e0fdf4891d03ccacaca0ac9b4c66998d012..313b4ebb3409d37d90631281a3121e7e7a661bec 100644 (file)
@@ -970,13 +970,6 @@ int Mdrunner::mdrunner()
     GMX_RELEASE_ASSERT(inputrec != nullptr, "All ranks should have a valid inputrec now");
     partialDeserializedTpr.reset(nullptr);
 
     GMX_RELEASE_ASSERT(inputrec != nullptr, "All ranks should have a valid inputrec now");
     partialDeserializedTpr.reset(nullptr);
 
-    GMX_RELEASE_ASSERT(
-            !inputrec->useConstantAcceleration,
-            "Linear acceleration has been removed in GROMACS 2022, and was broken for many years "
-            "before that. Use GROMACS 4.5 or earlier if you need this feature.");
-
-    // Now we decide whether to use the domain decomposition machinery.
-    // Note that this does not necessarily imply actually using multiple domains.
     // Now the number of ranks is known to all ranks, and each knows
     // the inputrec read by the master rank. The ranks can now all run
     // the task-deciding functions and will agree on the result
     // Now the number of ranks is known to all ranks, and each knows
     // the inputrec read by the master rank. The ranks can now all run
     // the task-deciding functions and will agree on the result
index 2f4c2d6e935ed38f02fcdd7b38bb6952e423e928..7657596888178a4f4b6e4cb6ebaab1a9b8cd84af 100644 (file)
@@ -852,7 +852,7 @@ static void init_adir(gmx_shellfc_t*            shfc,
     auto  invmass = gmx::arrayRefFromArray(md.invmass, md.nr);
     dt            = ir->delta_t;
 
     auto  invmass = gmx::arrayRefFromArray(md.invmass, md.nr);
     dt            = ir->delta_t;
 
-    /* Does NOT work with freeze groups (yet) */
+    /* Does NOT work with freeze or acceleration groups (yet) */
     for (n = 0; n < end; n++)
     {
         w_dt = invmass[n] * dt;
     for (n = 0; n < end; n++)
     {
         w_dt = invmass[n] * dt;
index 9b51dd8cedb9c118821a34423edfd3edec85a2bf..d93e399c4f3ce703839a108807dddca21ec29baa 100644 (file)
@@ -330,6 +330,7 @@ void done_inputrec(t_inputrec* ir)
     sfree(ir->opts.anneal_time);
     sfree(ir->opts.anneal_temp);
     sfree(ir->opts.tau_t);
     sfree(ir->opts.anneal_time);
     sfree(ir->opts.anneal_temp);
     sfree(ir->opts.tau_t);
+    sfree(ir->opts.acceleration);
     sfree(ir->opts.nFreeze);
     sfree(ir->opts.egp_flags);
 
     sfree(ir->opts.nFreeze);
     sfree(ir->opts.egp_flags);
 
@@ -405,6 +406,17 @@ static void pr_grp_opts(FILE* out, int indent, const char* title, const t_grpopt
         }
     }
 
         }
     }
 
+    pr_indent(out, indent);
+    fprintf(out, "acc:\t");
+    for (i = 0; (i < opts->ngacc); i++)
+    {
+        for (m = 0; (m < DIM); m++)
+        {
+            fprintf(out, "  %10g", opts->acceleration[i][m]);
+        }
+    }
+    fprintf(out, "\n");
+
     pr_indent(out, indent);
     fprintf(out, "nfreeze:");
     for (i = 0; (i < opts->ngfrz); i++)
     pr_indent(out, indent);
     fprintf(out, "nfreeze:");
     for (i = 0; (i < opts->ngfrz); i++)
@@ -1077,6 +1089,7 @@ static void cmp_grpopts(FILE* fp, const t_grpopts* opt1, const t_grpopts* opt2,
     char buf1[256], buf2[256];
 
     cmp_int(fp, "inputrec->grpopts.ngtc", -1, opt1->ngtc, opt2->ngtc);
     char buf1[256], buf2[256];
 
     cmp_int(fp, "inputrec->grpopts.ngtc", -1, opt1->ngtc, opt2->ngtc);
+    cmp_int(fp, "inputrec->grpopts.ngacc", -1, opt1->ngacc, opt2->ngacc);
     cmp_int(fp, "inputrec->grpopts.ngfrz", -1, opt1->ngfrz, opt2->ngfrz);
     cmp_int(fp, "inputrec->grpopts.ngener", -1, opt1->ngener, opt2->ngener);
     for (i = 0; (i < std::min(opt1->ngtc, opt2->ngtc)); i++)
     cmp_int(fp, "inputrec->grpopts.ngfrz", -1, opt1->ngfrz, opt2->ngfrz);
     cmp_int(fp, "inputrec->grpopts.ngener", -1, opt1->ngener, opt2->ngener);
     for (i = 0; (i < std::min(opt1->ngtc, opt2->ngtc)); i++)
@@ -1108,6 +1121,10 @@ static void cmp_grpopts(FILE* fp, const t_grpopts* opt1, const t_grpopts* opt2,
             }
         }
     }
             }
         }
     }
+    for (i = 0; (i < std::min(opt1->ngacc, opt2->ngacc)); i++)
+    {
+        cmp_rvec(fp, "inputrec->grpopts.acceleration", i, opt1->acceleration[i], opt2->acceleration[i], ftol, abstol);
+    }
     for (i = 0; (i < std::min(opt1->ngfrz, opt2->ngfrz)); i++)
     {
         cmp_ivec(fp, "inputrec->grpopts.nFreeze", i, opt1->nFreeze[i], opt2->nFreeze[i]);
     for (i = 0; (i < std::min(opt1->ngfrz, opt2->ngfrz)); i++)
     {
         cmp_ivec(fp, "inputrec->grpopts.nFreeze", i, opt1->nFreeze[i], opt2->nFreeze[i]);
index a7e8e9c4e4833756e369109b0144bfbe5ed47123..4c01f0b93bf1c8ae4ef28c57d870be6bf5e449c1 100644 (file)
@@ -69,6 +69,8 @@ struct t_grpopts
     int ngtc = 0;
     //! Number of of Nose-Hoover chains per group
     int nhchainlength = 0;
     int ngtc = 0;
     //! Number of of Nose-Hoover chains per group
     int nhchainlength = 0;
+    //! Number of Accelerate groups
+    int ngacc;
     //! Number of Freeze groups
     int ngfrz = 0;
     //! Number of Energy groups
     //! Number of Freeze groups
     int ngfrz = 0;
     //! Number of Energy groups
@@ -87,6 +89,8 @@ struct t_grpopts
     real** anneal_temp = nullptr;
     //! Tau coupling time
     real* tau_t = nullptr;
     real** anneal_temp = nullptr;
     //! Tau coupling time
     real* tau_t = nullptr;
+    //! Acceleration per group
+    rvec* acceleration = nullptr;
     //! Whether the group will be frozen in each direction
     ivec* nFreeze = nullptr;
     //! Exclusions/tables of energy group pairs
     //! Whether the group will be frozen in each direction
     ivec* nFreeze = nullptr;
     //! Exclusions/tables of energy group pairs
@@ -566,7 +570,7 @@ struct t_inputrec // NOLINT (clang-analyzer-optin.performance.Padding)
     bool bAdress = false;
     //! Whether twin-range scheme is active - always false if a valid .tpr was read
     bool useTwinRange = false;
     bool bAdress = false;
     //! Whether twin-range scheme is active - always false if a valid .tpr was read
     bool useTwinRange = false;
-    //! Whether we have constant acceleration - removed in GROMACS 2022
+    //! Whether we have constant acceleration
     bool useConstantAcceleration = false;
 
     //! KVT object that contains input parameters converted to the new style.
     bool useConstantAcceleration = false;
 
     //! KVT object that contains input parameters converted to the new style.
index 91ee9f00d7d2e4afed8d34be4af8eeddf87fcab9..c80ffdeaeddc1024651a1bdfcdd47b8292cc333c 100644 (file)
@@ -117,6 +117,8 @@ typedef struct t_mdatoms
     unsigned short* cTC;
     //! Group index for energy matrix
     unsigned short* cENER;
     unsigned short* cTC;
     //! Group index for energy matrix
     unsigned short* cENER;
+    //! Group index for acceleration
+    unsigned short* cACC;
     //! Group index for freezing
     unsigned short* cFREEZE;
     //! Group index for center of mass motion removal
     //! Group index for freezing
     unsigned short* cFREEZE;
     //! Group index for center of mass motion removal
index fac5ea0d86bfd2c0db059fe66598559d18d15617..03e64cc6e36c6fdb4c95fd04625eab68fed98a4a 100644 (file)
@@ -401,7 +401,7 @@ bool ModularSimulator::isInputCompatible(bool                             exitOn
             && conditionalAssert(!doRerun, "Rerun is not supported by the modular simulator.");
     isInputCompatible =
             isInputCompatible
             && conditionalAssert(!doRerun, "Rerun is not supported by the modular simulator.");
     isInputCompatible =
             isInputCompatible
-            && conditionalAssert(inputrec->cos_accel == 0.0,
+            && conditionalAssert(!inputrec->useConstantAcceleration && inputrec->cos_accel == 0.0,
                                  "Acceleration is not supported by the modular simulator.");
     isInputCompatible =
             isInputCompatible
                                  "Acceleration is not supported by the modular simulator.");
     isInputCompatible =
             isInputCompatible
index 5bac5adcef47df7fd726cdb4fd16aa3d7b02930a..1c9b27b72978f11800f048d5be8f184bedfc4598 100644 (file)
@@ -637,6 +637,10 @@ bool decideWhetherToUseGpuForUpdate(const bool                     isDomainDecom
                 "Only Parrinello-Rahman, Berendsen, and C-rescale pressure coupling are "
                 "supported.\n";
     }
                 "Only Parrinello-Rahman, Berendsen, and C-rescale pressure coupling are "
                 "supported.\n";
     }
+    if (inputrec.cos_accel != 0 || inputrec.useConstantAcceleration)
+    {
+        errorMessage += "Acceleration is not supported.\n";
+    }
     if (EEL_PME_EWALD(inputrec.coulombtype) && inputrec.epsilon_surface != 0)
     {
         // The graph is needed, but not supported
     if (EEL_PME_EWALD(inputrec.coulombtype) && inputrec.epsilon_surface != 0)
     {
         // The graph is needed, but not supported
index 541d6da1bfdc2107cbfdbefee978d3fab0d15fe5..d6506af7f99dfc769768bcb6350bf89591de0a41 100644 (file)
@@ -168,10 +168,6 @@ void list_tpr(const char* fn,
         {
             for (auto group : keysOf(gcount))
             {
         {
             for (auto group : keysOf(gcount))
             {
-                if (group == SimulationAtomGroupType::AccelerationUnused)
-                {
-                    continue;
-                }
                 gcount[group][getGroupType(groups, group, i)]++;
             }
         }
                 gcount[group][getGroupType(groups, group, i)]++;
             }
         }
index ed809ab4181799f15918b6066ffc08e30ed85b2f..9278a2a8644e0f4a49a55c4c3be83a8b59b76651 100644 (file)
@@ -56,7 +56,7 @@ enum class SimulationAtomGroupType : int
 {
     TemperatureCoupling,
     EnergyOutput,
 {
     TemperatureCoupling,
     EnergyOutput,
-    AccelerationUnused,
+    Acceleration,
     Freeze,
     User1,
     User2,
     Freeze,
     User1,
     User2,
index 74c4b9c3568cb0f8270bdaaa45c743d51aa17523..086dc308ca011831647720788b45ad6f0faf0ea6 100644 (file)
@@ -111,6 +111,7 @@ gmx_add_gtest_executable(${exename}
         swapcoords.cpp
         tabulated_bonded_interactions.cpp
         freezegroups.cpp
         swapcoords.cpp
         tabulated_bonded_interactions.cpp
         freezegroups.cpp
+       constantacceleration.cpp
         # pseudo-library for code for mdrun
         $<TARGET_OBJECTS:mdrun_objlib>
     )
         # pseudo-library for code for mdrun
         $<TARGET_OBJECTS:mdrun_objlib>
     )
diff --git a/src/programs/mdrun/tests/constantacceleration.cpp b/src/programs/mdrun/tests/constantacceleration.cpp
new file mode 100644 (file)
index 0000000..08e1b21
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+
+/*! \internal \file
+ * \brief End-to-end tests checking sanity of results of simulations
+ *        containing constant acceleration groups
+ *
+ * \author Berk Hess <hess@kth.se>
+ * \ingroup module_mdrun_integration_tests
+ */
+#include "gmxpre.h"
+
+#include "config.h"
+
+#include "gromacs/topology/ifunc.h"
+#include "gromacs/utility/stringutil.h"
+
+#include "testutils/mpitest.h"
+#include "testutils/simulationdatabase.h"
+#include "testutils/testmatchers.h"
+
+#include "moduletest.h"
+#include "simulatorcomparison.h"
+#include "trajectoryreader.h"
+
+namespace gmx::test
+{
+namespace
+{
+/*! \brief Test fixture checking the velocities of aomts
+ *
+ * This tests that velocities of non-accelerated atoms are zero
+ * and that velocities of accelarated atoms match acceleration*time.
+ * This code assumes the first half the atoms are non-accelerated
+ * and the second half are accelerated
+ */
+using AccelerationGroupTestParams = std::tuple<std::string, std::string>;
+class AccelerationGroupTest :
+    public MdrunTestFixture,
+    public ::testing::WithParamInterface<AccelerationGroupTestParams>
+{
+public:
+    //! Check that the velocities are zero or accelerated
+    static void checkVelocities(const std::string&            trajectoryName,
+                                const RVec                    acceleration,
+                                const FloatingPointTolerance& tolerance)
+    {
+        const size_t c_groupSize = 3;
+
+        const std::vector<RVec> zeroVelocities(c_groupSize, RVec{ 0, 0, 0 });
+
+        TrajectoryFrameReader trajectoryFrameReader(trajectoryName);
+        while (trajectoryFrameReader.readNextFrame())
+        {
+            const auto frame = trajectoryFrameReader.frame();
+            GMX_RELEASE_ASSERT(frame.v().size() == 2 * c_groupSize,
+                               "Expect velocities for both atom groups");
+
+            const RVec              referenceVelocity = real(frame.time()) * acceleration;
+            const std::vector<RVec> referenceVelocities(c_groupSize, referenceVelocity);
+
+            SCOPED_TRACE("Checking velocities of non-accelerated atoms");
+            ArrayRef<const RVec> nonAcceleratedVelocities = frame.v().subArray(0, c_groupSize);
+            EXPECT_THAT(nonAcceleratedVelocities, Pointwise(RVecEq(tolerance), zeroVelocities));
+
+            SCOPED_TRACE("Checking velocities of accelerated atoms");
+            ArrayRef<const RVec> acceleratedVelocities = frame.v().subArray(c_groupSize, c_groupSize);
+            EXPECT_THAT(acceleratedVelocities, Pointwise(RVecEq(tolerance), referenceVelocities));
+        }
+    }
+};
+
+TEST_P(AccelerationGroupTest, WithinTolerances)
+{
+    const auto& params         = GetParam();
+    const auto& integrator     = std::get<0>(params);
+    const auto& tcoupling      = std::get<1>(params);
+    const auto& simulationName = "spc2";
+
+    // Prepare mdp input
+    auto mdpFieldValues       = prepareMdpFieldValues(simulationName, integrator, tcoupling, "no");
+    mdpFieldValues["nsteps"]  = "8";
+    mdpFieldValues["dt"]      = "0.002";
+    mdpFieldValues["nstxout"] = "0";
+    mdpFieldValues["nstvout"] = "8";
+    mdpFieldValues["nstfout"] = "0";
+    mdpFieldValues["comm-mode"] = "none";
+    // The two groups will not see each other when the cut-off is 0.9 nm
+    mdpFieldValues["coulombtype"]             = "reaction-field";
+    mdpFieldValues["rcoulomb"]                = "0.8";
+    mdpFieldValues["rvdw"]                    = "0.8";
+    mdpFieldValues["verlet-buffer-tolerance"] = "-1";
+    mdpFieldValues["rlist"]                   = "0.9";
+    // Couple the (non-)accelerated groups separately, so their velocties are independent
+    mdpFieldValues["tc-grps"] = "firstWaterMolecule secondWaterMolecule";
+    mdpFieldValues["ref-t"]   = "0.001 0.001";
+    // Use weak coupling so we can check vecolities of atoms with a tight tolerance
+    mdpFieldValues["tau-t"]      = "10.0 10.0";
+    const RVec c_acceleration    = { 2.0, 3.0, 1.5 };
+    mdpFieldValues["acc-grps"]   = "secondWaterMolecule";
+    mdpFieldValues["accelerate"] = "2.0 3.0 1.5";
+    // Set initial velocities to zero
+    mdpFieldValues["gen-vel"]  = "yes";
+    mdpFieldValues["gen-temp"] = "0";
+
+    // Run grompp
+    runner_.useTopGroAndNdxFromDatabase(simulationName);
+    runner_.useStringAsMdpFile(prepareMdpFileContents(mdpFieldValues));
+    runGrompp(&runner_);
+    // Run mdrun
+    runMdrun(&runner_);
+
+    // T-coupling causes changes in the velocities up to 1e-4
+    auto tolerance = absoluteTolerance((GMX_DOUBLE && tcoupling == "no") ? 1e-10 : 1e-4);
+
+    // Check the velocities of the non-accelerated and accelerated groups
+    checkVelocities(runner_.fullPrecisionTrajectoryFileName_, c_acceleration, tolerance);
+}
+
+// The v-rescale case check that Ekin computation and temperature coupling
+// can be performed independently for atoms groups, so the accelerations
+// are not affected. This can be useful in practice.
+INSTANTIATE_TEST_SUITE_P(AccelerationWorks,
+                         AccelerationGroupTest,
+                         ::testing::Combine(::testing::Values("md", "md-vv"),
+                                            ::testing::Values("no", "v-rescale")));
+} // namespace
+} // namespace gmx::test
index 782d0bd162468fb04f748f717b946a77d2fda5ce..1e7f5bd9fa1ab2ac4e3ccad71a77583ca14c2a9b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -80,10 +80,14 @@ public:
         {
             return true;
         }
         {
             return true;
         }
-        *listener->stream() << "  Actual value: " << value2 << std::endl
-                            << "Expected value: " << value1 << std::endl
-                            << "    Difference: " << diff.toString() << std::endl
-                            << "     Tolerance: " << tolerance_.toString(diff);
+        if (listener->stream())
+        {
+            *listener->stream() << "  Actual value: " << value2 << std::endl
+                                << "Expected value: " << value1 << std::endl
+                                << "    Difference: " << diff.toString() << std::endl
+                                << "     Tolerance: " << tolerance_.toString(diff);
+        }
+
         return false;
     }
     //! Describe to a human what matching means.
         return false;
     }
     //! Describe to a human what matching means.