Test for LINCS and SHAKE constraints.
authorArtem Zhmurov <zhmurov@gmail.com>
Tue, 15 Jan 2019 15:04:49 +0000 (16:04 +0100)
committerMark Abraham <mark.j.abraham@gmail.com>
Thu, 21 Feb 2019 08:42:00 +0000 (09:42 +0100)
This version updates the tests making the selection of the
constraining algorithm more abstract. Makes it possible
to use the same test routines for new implementations (e.g.
CPU- or GPU-based) or (and) algorithms (e.g. LINCS or SHAKE).
Partly this is preparation for the GPU-based version of
the constraints (Refs #2816).

Change-Id: Ice7dfdcc6d86c04656b0a1dd4e328c5afdb8a263

src/gromacs/mdlib/tests/constr.cpp
src/gromacs/mdlib/tests/constrdata.h [deleted file]

index 31e499e7022a9d2153e814ed17b3fa3a9e684531..7b2ff93c45c8974d3d908437d43b97a34132c3a7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019, 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.
@@ -48,6 +48,7 @@
 #include <cmath>
 
 #include <algorithm>
+#include <unordered_map>
 #include <vector>
 
 #include <gtest/gtest.h>
 #include "testutils/refdata.h"
 #include "testutils/testasserts.h"
 
-#include "constrdata.h"
-
 namespace gmx
 {
 namespace test
 {
 
-/*! \brief Test fixture for SHAKE and LINCS
- *
- * The fixture uses three simple and one real-life system for testing.
- * Simple systems include:
- * 1.1. Two atoms, connected with one constrain.
- * 1.2. Three atoms, connected consequently with two constraints
- * 1.3. Four atoms, connected by two independent constraints.
- * 1.4. Three atoms, connected by three constraints in a triangle.
- * 1.5. Four atoms, connected by three consequentive constraints.
- * The real-life system is a Cys-Val-Trp peptide with constraints
- * on:
- * 2.1. Bonds, containing hydrogens (SHAKE and LINCS)
- * 2.2. All bonds (SHAKE and LINCS).
- * 2.3. Angles with hydrogens and all bonds (SHAKE).
- * 2.4. All angles and all bonds (disabled).
+/*! \brief
+ * Constraints test data structure.
  *
- * For all systems, the final length of the constraints is tested ageinst the
- * reference values. For systems 2.1 and 2.2, the exact final coordinates of
- * all atoms are also tested against the reference values.
+ * Structure to collect all the necessary data, including system coordinates and topology,
+ * constraints information, etc. The structure can be reset and reused.
  */
-class ConstraintsTest : public ::testing::Test
+struct ConstraintsTestData
 {
     public:
+        std::string           title_;                   //!< Human-friendly name for a system
+        int                   nAtom_;                   //!< Number of atoms
+        gmx_mtop_t            mtop_;                    //!< Topology
+        std::vector<real>     masses_;                  //!< Masses
+        std::vector<real>     invmass_;                 //!< Inverse masses
+        t_commrec             cr_;                      //!< Communication record
+        t_inputrec            ir_;                      //!< Input record (info that usually in .mdp file)
+        t_idef                idef_;                    //!< Local topology
+        t_mdatoms             md_;                      //!< MD atoms
+        gmx_multisim_t        ms_;                      //!< Multisim data
+        t_nrnb                nrnb_;                    //!< Computational time array (normally used in benchmarks)
+
+        real                  invdt_;                   //!< Inverse timestep
+        int                   nflexcon_   = 0;          //!< Number of flexible constraints
+        bool                  computeVirial_;           //!< Whether the virial should be computed
+        tensor                virialScaled_;            //!< Scaled virial
+        tensor                virialScaledRef_;         //!< Scaled virial (reference values)
+        bool                  compute_dHdLambda_;       //!< If the free energy is computed
+        real                  dHdLambda_;               //!< For free energy computation
+        real                  dHdLambdaRef_;            //!< For free energy computation (reference value)
+
+        std::vector<RVec>     x_;                       //!< Coordinates before the timestep
+        std::vector<RVec>     xPrime_;                  //!< Coordinates after timestep, output for the constraints
+        std::vector<RVec>     xPrime0_;                 //!< Backup for coordinates (for reset)
+        std::vector<RVec>     xPrime2_;                 //!< Intermediate set of coordinates used by LINCS and
+                                                        //!< SHAKE for different purposes
+        std::vector<RVec>     v_;                       //!< Velocities
+        std::vector<RVec>     v0_;                      //!< Backup for velocities (for reset)
 
-        /*! \brief
-         * Cleaning up the memory.
-         */
-        void TearDown() override
-        {
-            sfree(idef.il[F_CONSTR].iatoms);
-            sfree(idef.iparams);
-            sfree(x);
-            sfree(xprime);
-            sfree(xprime2);
-            sfree(v);
-            gmx_fio_close(log);
-        }
+        // Fields to store constraints data for testing
+        std::vector<int>      constraints_;             //!< Constraints data (type1-i1-j1-type2-i2-j2-...)
+        std::vector<real>     constraintsR0_;           //!< Target lengths for all constraint types
 
         /*! \brief
-         * Method used to initialize atoms, constraints and their parameters.
+         * Constructor for the object with all parameters and variables needed by constraints algorithms.
          *
-         * This method constructs stubs for all the data structures, required to initialize
-         * and apply LINCS and SHAKE constraints. The constraints data is also saved as a field
-         * to check if the target distances are achieved after the constraints are applied.
+         * This constructor assembles stubs for all the data structures, required to initialize
+         * and apply LINCS and SHAKE constraints. The coordinates and velocities before constraining
+         * are saved to allow for reset. The constraints data are stored for testing after constraints
+         * were applied.
          *
-         * \param[in] natom          Number of atoms in the system.
-         * \param[in] masses         Atom masses. Size of this vector should be equal to natom.
-         * \param[in] constraints    List of constraints, organized in tripples of integers.
-         *                           First integer is the index of type for a constrain, second
-         *                           and third are the indices of constrained atoms. The types
-         *                           of constraints should be sequential but not nesseseraly
-         *                           start from zero (which is the way they normally are in
-         *                           GROMACS).
-         * \param[in] constraintsR0  Target values for bond lengths for bonds of each type. The
-         *                           size of this vector should be equal to the total number of
-         *                           unique types in constraints vector.
-         * \param[in] firstType      The index of first interaction type used for constraints
-         *                           (i.e. the lowest number that appear as type in constraints
-         *                           vector). This is not fail-safe, since technically the
-         *                           numbering of the types may not be sequantial, but (i) this
-         *                           is the way things are in GROMACS, (ii) everything is fine
-         *                           in the examples provided for the test.
-         * \param[in] epbc           Type of PBC (epbcXYZ / epbcNONE are used in this test,
-         *                           see src/gromacs/pbcutil/pbc.h for details).
-         * \param[in] box            The PBC box.
-         * \param[in] init_t         Initial time.
-         * \param[in] delta_t        Timestep.
-         * \param[in] coordinates    Initial (unconstrained) coordinates.
+         * \param[in]  title              Human-friendly name of the system.
+         * \param[in]  nAtom              Number of atoms in the system.
+         * \param[in]  masses             Atom masses. Size of this vector should be equal to nAtom.
+         * \param[in]  constraints        List of constraints, organized in triples of integers.
+         *                                First integer is the index of type for a constraint, second
+         *                                and third are the indices of constrained atoms. The types
+         *                                of constraints should be sequential but not necessarily
+         *                                start from zero (which is the way they normally are in
+         *                                GROMACS).
+         * \param[in]  constraintsR0      Target values for bond lengths for bonds of each type. The
+         *                                size of this vector should be equal to the total number of
+         *                                unique types in constraints vector.
+         * \param[in]  computeVirial      Whether the virial should be computed.
+         * \param[in]  virialScaledRef    Reference values for scaled virial tensor.
+         * \param[in]  compute_dHdLambda  Whether free energy should be computed.
+         * \param[in]  dHdLambdaRef       Reference value for dHdLambda.
+         * \param[in]  initialTime        Initial time.
+         * \param[in]  timestep           Timestep.
+         * \param[in]  x                  Coordinates before integration step.
+         * \param[in]  xPrime             Coordinates after integration step, but before constraining.
+         * \param[in]  v                  Velocities before constraining.
+         * \param[in]  shakeTolerance     Target tolerance for SHAKE.
+         * \param[in]  shakeUseSOR        Use successive over-relaxation method for SHAKE iterations.
+         *                                The general formula is:
+         *                                   x_n+1 = (1-omega)*x_n + omega*f(x_n),
+         *                                where omega = 1 if SOR is off and may be < 1 if SOR is on.
+         * \param[in]  nLincsIter         Number of iterations used to compute the inverse matrix.
+         * \param[in]  nProjOrder         The order for algorithm that adjusts the direction of the
+         *                                bond after constraints are applied.
+         * \param[in]  lincsWarnAngle     The threshold value for the change in bond angle. When
+         *                                exceeded the program will issue a warning.
          *
          */
-        void initSystem(int natom, std::vector<real> masses,
-                        std::vector<int> constraints, std::vector<real> constraintsR0, int firstType,
-                        int epbc, const matrix box,
-                        real init_t, real delta_t,
-                        std::vector<RVec> coordinates)
-
+        ConstraintsTestData(const std::string &title,
+                            int nAtom, std::vector<real> masses,
+                            std::vector<int> constraints, std::vector<real> constraintsR0,
+                            bool computeVirial, tensor virialScaledRef,
+                            bool compute_dHdLambda, float dHdLambdaRef,
+                            real initialTime, real timestep,
+                            const std::vector<RVec> &x, const std::vector<RVec> &xPrime, const std::vector<RVec> &v,
+                            real shakeTolerance, gmx_bool shakeUseSOR,
+                            int nLincsIter, int nProjOrder, real lincsWarnAngle)
         {
+            title_ = title;   // Human-friendly name of the system
+            nAtom_ = nAtom;   // Number of atoms
 
-            this->n = natom;   // Number of atoms
-
-            invmass.resize(n); // Vector of inverce masses
+            // Masses of atoms
+            masses_ = masses;
+            invmass_.resize(nAtom); // Vector of inverse masses
 
-            for (int i = 0; i < n; i++)
+            for (int i = 0; i < nAtom; i++)
             {
-                invmass.at(i) = 1.0/masses.at(i);
+                invmass_[i] = 1.0/masses.at(i);
             }
 
             // Saving constraints to check if they are satisfied after algorithm was applied
-            this->constraints   = constraints;   // Constraints indexes (in type-i-j format)
-            this->constraintsR0 = constraintsR0; // Euilibrium distances for each type of constraint
-            this->firstType     = firstType;     // The first type index used for constraints
+            constraints_   = constraints;   // Constraints indexes (in type-i-j format)
+            constraintsR0_ = constraintsR0; // Equilibrium distances for each type of constraint
 
-            // PBC initialization
-            this->epbc = epbc;
-            for (int i = 0; i < DIM; i++)
+            invdt_  = 1.0/timestep;         // Inverse timestep
+
+            // Communication record
+            cr_.nnodes = 1;
+            cr_.dd     = nullptr;
+
+            // Multisim data
+            ms_.sim  = 0;
+            ms_.nsim = 1;
+
+            // Input record - data that usually comes from configuration file (.mdp)
+            ir_.efep           = 0;
+            ir_.init_t         = initialTime;
+            ir_.delta_t        = timestep;
+            ir_.eI             = 0;
+
+            // MD atoms data
+            md_.nMassPerturbed = 0;
+            md_.lambda         = 0.0;
+            md_.invmass        = invmass_.data();
+            md_.nr             = nAtom;
+            md_.homenr         = nAtom;
+
+            // Virial evaluation
+            computeVirial_ = computeVirial;
+            if (computeVirial)
             {
-                for (int j = 0; j < DIM; j++)
+                for (int i = 0; i < DIM; i++)
                 {
-                    this->box[i][j] = box[i][j]; // Periodic box
+                    for (int j = 0; j < DIM; j++)
+                    {
+                        virialScaled_[i][j]    = 0;
+                        virialScaledRef_[i][j] = virialScaledRef[i][j];
+                    }
                 }
             }
-            set_pbc(&pbc, epbc, box);
-
-            this->invdt  = 1.0/delta_t; // Inverse timestep
-
-            // Communication record
-            cr.nnodes = 1;
-            cr.dd     = nullptr;
 
-            // Input record - data that usualy comes from configurtion file (.mdp)
-            ir.efep           = 0;
-            ir.init_t         = init_t;
-            ir.delta_t        = delta_t;
-            ir.eI             = 0;
 
-            // MD atoms data
-            md.nMassPerturbed = 0;
-            md.lambda         = 0.0;
-            md.invmass        = invmass.data();
-            md.nr             = n;
-            md.homenr         = n;
+            // Free energy evaluation
+            compute_dHdLambda_ = compute_dHdLambda;
+            dHdLambda_         = 0;
+            if (compute_dHdLambda_)
+            {
+                ir_.efep                    = efepYES;
+                dHdLambdaRef_               = dHdLambdaRef;
+            }
+            else
+            {
+                ir_.efep                    = efepNO;
+                dHdLambdaRef_               = 0;
+            }
 
-            // Constraints and their parameters in old data format (local topology)
+            // Constraints and their parameters (local topology)
             for (int i = 0; i < F_NRE; i++)
             {
-                idef.il[i].nr = 0;
+                idef_.il[i].nr = 0;
             }
-            idef.il[F_CONSTR].nr   = constraints.size();
+            idef_.il[F_CONSTR].nr   = constraints.size();
 
-            snew(idef.il[F_CONSTR].iatoms, constraints.size());
+            snew(idef_.il[F_CONSTR].iatoms, constraints.size());
             int maxType = 0;
             for (unsigned i = 0; i < constraints.size(); i++)
             {
@@ -221,118 +259,250 @@ class ConstraintsTest : public ::testing::Test
                         maxType = constraints.at(i);
                     }
                 }
-                idef.il[F_CONSTR].iatoms[i] = constraints.at(i);
+                idef_.il[F_CONSTR].iatoms[i] = constraints.at(i);
             }
-            snew(idef.iparams, maxType + 1);
+            snew(idef_.iparams, maxType + 1);
             for (unsigned i = 0; i < constraints.size()/3; i++)
             {
-                idef.iparams[constraints.at(3*i)].constr.dA = constraintsR0.at(constraints.at(3*i) - firstType);
-                idef.iparams[constraints.at(3*i)].constr.dB = constraintsR0.at(constraints.at(3*i) - firstType);
+                idef_.iparams[constraints.at(3*i)].constr.dA = constraintsR0.at(constraints.at(3*i));
+                idef_.iparams[constraints.at(3*i)].constr.dB = constraintsR0.at(constraints.at(3*i));
             }
 
-
-            // Constraints and their parameters in new data format (global topology)
-            InteractionList ilist;
-            ilist.iatoms.resize(constraints.size());
+            // Constraints and their parameters (global topology)
+            InteractionList interactionList;
+            interactionList.iatoms.resize(constraints.size());
             for (unsigned i = 0; i < constraints.size(); i++)
             {
-                ilist.iatoms.at(i) = constraints.at(i);
+                interactionList.iatoms.at(i) = constraints.at(i);
             }
-            InteractionList ilistEmpty;
-            ilistEmpty.iatoms.resize(0);
-
-            gmx_moltype_t moltype;
-            moltype.atoms.nr             = n;
-            moltype.ilist.at(F_CONSTR)   = ilist;
-            moltype.ilist.at(F_CONSTRNC) = ilistEmpty;
-            mtop.moltype.push_back(moltype);
-
-            gmx_molblock_t molblock;
-            molblock.type = 0;
-            molblock.nmol = 1;
-            mtop.molblock.push_back(molblock);
-
-            mtop.natoms = n;
-            mtop.ffparams.iparams.resize(maxType + 1);
+            InteractionList interactionListEmpty;
+            interactionListEmpty.iatoms.resize(0);
+
+            gmx_moltype_t molType;
+            molType.atoms.nr             = nAtom;
+            molType.ilist.at(F_CONSTR)   = interactionList;
+            molType.ilist.at(F_CONSTRNC) = interactionListEmpty;
+            mtop_.moltype.push_back(molType);
+
+            gmx_molblock_t molBlock;
+            molBlock.type = 0;
+            molBlock.nmol = 1;
+            mtop_.molblock.push_back(molBlock);
+
+            mtop_.natoms = nAtom;
+            mtop_.ffparams.iparams.resize(maxType + 1);
             for (int i = 0; i <= maxType; i++)
             {
-                mtop.ffparams.iparams.at(i) = idef.iparams[i];
+                mtop_.ffparams.iparams.at(i) = idef_.iparams[i];
             }
-            mtop.bIntermolecularInteractions = false;
+            mtop_.bIntermolecularInteractions = false;
+
+            // Coordinates and velocities
+            x_       = x;
+            xPrime_  = xPrime;
+            xPrime0_ = xPrime;
+            xPrime2_ = xPrime;
 
-            // Log file may be here. Redirect it somewhere usefull?
-            log = gmx_fio_open("constraintstest.log", "w");
+            v_  = v;
+            v0_ = v;
 
-            // Set the coordinates in convinient format
-            snew(x, n);
-            snew(xprime, n);
-            snew(xprime2, n);
+            // SHAKE-specific parameters
+            ir_.shake_tol           = shakeTolerance;
+            ir_.bShakeSOR           = shakeUseSOR;
 
-            for (int i = 0; i < n; i++)
+            // LINCS-specific parameters
+            ir_.nLincsIter          = nLincsIter;
+            ir_.nProjOrder          = nProjOrder;
+            ir_.LincsWarnAngle      = lincsWarnAngle;
+        }
+
+        /*! \brief
+         * Reset the data structure so it can be reused.
+         *
+         * Set the coordinates and velocities back to their values before
+         * constraining. The scaled virial tensor and dHdLambda are zeroed.
+         *
+         */
+        void reset()
+        {
+            xPrime_  = xPrime0_;
+            xPrime2_ = xPrime0_;
+            v_       = v0_;
+
+            if (computeVirial_)
             {
-                for (int j = 0; j < DIM; j++)
+                for (int i = 0; i < DIM; i++)
                 {
-                    x[i][j]      = coordinates.at(i)[j];
-                    xprime[i][j] = coordinates.at(i)[j];
+                    for (int j = 0; j < DIM; j++)
+                    {
+                        virialScaled_[i][j] = 0;
+                    }
                 }
             }
+            dHdLambda_         = 0;
+        }
+
+        /*! \brief
+         * Cleaning up the memory.
+         */
+        ~ConstraintsTestData()
+        {
+            sfree(idef_.il[F_CONSTR].iatoms);
+            sfree(idef_.iparams);
+        }
 
-            // Velocities (not used)
-            snew(v, n);
+};
 
+/*! \brief The two-dimensional parameter space for test.
+ *
+ * The test will run for all possible combinations of accessible
+ * values of the:
+ * 1. PBC setup ("PBCNONE" or "PBCXYZ")
+ * 2. The algorithm ("SHAKE" or "LINCS").
+ */
+typedef std::tuple<std::string, std::string> ConstraintsTestParameters;
 
+/*! \brief Test fixture for constraints.
+ *
+ * The fixture uses following test systems:
+ * 1. Two atoms, connected with one constraint (e.g. NH).
+ * 2. Three atoms, connected consequently with two constraints (e.g. CH2).
+ * 3. Three atoms, constrained to the fourth atom (e.g. CH3).
+ * 4. Four atoms, connected by two independent constraints.
+ * 5. Three atoms, connected by three constraints in a triangle
+ *      (e.g. H2O with constrained H-O-H angle).
+ * 6. Four atoms, connected by three consequential constraints.
+ *
+ * For all systems, the final lengths of the constraints are tested against the
+ * reference values, the direction of each constraint is checked.
+ * Test also verifies that the center of mass has not been
+ * shifted by the constraints and that its velocity has not changed.
+ * For some systems, the value for scaled virial tensor is checked against
+ * pre-computed data.
+ */
+class ConstraintsTest : public ::testing::TestWithParam<ConstraintsTestParameters>
+{
+    public:
+        //! PBC setups
+        std::unordered_map <std::string, t_pbc>                                             pbcs_;
+        //! Algorithms (SHAKE and LINCS)
+        std::unordered_map <std::string, void(*)(ConstraintsTestData *testData, t_pbc pbc)> algorithms_;
+
+        /*! \brief Test setup function.
+         *
+         * Setting up the pbcs and algorithms. Note, that corresponding string keywords
+         * have to be explicitly added at the end of this file when the tests are called.
+         *
+         */
+        void SetUp() override
+        {
+
+            //
+            // PBC initialization
+            //
+            t_pbc pbc;
+
+            // Infinitely small box
+            matrix boxNone = { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} };
+            set_pbc(&pbc, epbcNONE, boxNone);
+            pbcs_["PBCNone"] = pbc;
+
+            // Rectangular box
+            matrix boxXyz = { {10.0, 0.0, 0.0}, {0.0, 20.0, 0.0}, {0.0, 0.0, 15.0} };
+            set_pbc(&pbc, epbcXYZ, boxXyz);
+            pbcs_["PBCXYZ"] = pbc;
+
+            //
+            // Algorithms
+            //
+            // SHAKE
+            algorithms_["SHAKE"] = applyShake;
+            // LINCS
+            algorithms_["LINCS"] = applyLincs;
+
+        }
+
+        /*! \brief
+         * Initialize and apply SHAKE constraints.
+         *
+         * \param[in] testData        Test data structure.
+         * \param[in] pbc             Periodic boundary data (not used in SHAKE).
+         */
+        static void applyShake(ConstraintsTestData *testData, t_pbc gmx_unused pbc)
+        {
+            shakedata* shaked = shake_init();
+            make_shake_sblock_serial(shaked, &testData->idef_, testData->md_);
+            bool       success = constrain_shake(
+                        nullptr,
+                        shaked,
+                        testData->invmass_.data(),
+                        testData->idef_,
+                        testData->ir_,
+                        as_rvec_array(testData->x_.data()),
+                        as_rvec_array(testData->xPrime_.data()),
+                        as_rvec_array(testData->xPrime2_.data()),
+                        &testData->nrnb_,
+                        testData->md_.lambda,
+                        &testData->dHdLambda_,
+                        testData->invdt_,
+                        as_rvec_array(testData->v_.data()),
+                        testData->computeVirial_,
+                        testData->virialScaled_,
+                        false,
+                        gmx::ConstraintVariable::Positions);
+            EXPECT_TRUE(success) << "Test failed with a false return value in SHAKE.";
+            done_shake(shaked);
         }
 
         /*! \brief
-         * This method initializes and applies LINCS constraints.
+         * Initialize and apply LINCS constraints.
          *
-         * \param[in] nLincsIter     Number of iterations used to compute the inverse matrix.
-         * \param[in] nProjOrder     The order for algorithm that adjusts the direction of the
-         *                           bond after constraints are applied.
-         * \param[in] LincsWarnAngle The value for the change in bond angle after which the
-         *                           program will issue a warning.
+         * \param[in] testData        Test data structure.
+         * \param[in] pbc             Periodic boundary data.
          */
-        void applyConstraintsLincs(int nLincsIter, int nProjOrder, real LincsWarnAngle)
+        static void applyLincs(ConstraintsTestData *testData, t_pbc pbc)
         {
 
             Lincs                *lincsd;
             int                   maxwarn         = 100;
             int                   warncount_lincs = 0;
-            ir.nLincsIter     = nLincsIter;
-            ir.nProjOrder     = nProjOrder;
-            ir.LincsWarnAngle = LincsWarnAngle;
             gmx_omp_nthreads_set(emntLINCS, 1);
 
             // Make blocka structure for faster LINCS setup
             std::vector<t_blocka> at2con_mt;
-            at2con_mt.reserve(mtop.moltype.size());
-            for (const gmx_moltype_t &moltype : mtop.moltype)
+            at2con_mt.reserve(testData->mtop_.moltype.size());
+            for (const gmx_moltype_t &moltype : testData->mtop_.moltype)
             {
                 // This function is in constr.cpp
                 at2con_mt.push_back(make_at2con(moltype,
-                                                mtop.ffparams.iparams,
-                                                flexibleConstraintTreatment(EI_DYNAMICS(ir.eI))));
+                                                testData->mtop_.ffparams.iparams,
+                                                flexibleConstraintTreatment(EI_DYNAMICS(testData->ir_.eI))));
             }
-            // Initialie LINCS
-            lincsd = init_lincs(gmx_fio_getfp(log), mtop,
-                                nflexcon, at2con_mt,
+            // Initialize LINCS
+            lincsd = init_lincs(nullptr, testData->mtop_,
+                                testData->nflexcon_, at2con_mt,
                                 false,
-                                ir.nLincsIter, ir.nProjOrder);
-            set_lincs(idef, md, EI_DYNAMICS(ir.eI), &cr, lincsd);
+                                testData->ir_.nLincsIter, testData->ir_.nProjOrder);
+            set_lincs(testData->idef_, testData->md_, EI_DYNAMICS(testData->ir_.eI), &testData->cr_, lincsd);
 
             // Evaluate constraints
-            bool bOK = constrain_lincs(false, ir, 0, lincsd, md,
-                                       &cr,
-                                       nullptr,
-                                       x, xprime, xprime2,
-                                       box, &pbc, md.lambda, dvdlambda,
-                                       invdt, v,
-                                       computeVirial, vir_r_m_dr,
-                                       gmx::ConstraintVariable::Positions, &nrnb,
-                                       maxwarn, &warncount_lincs);
-            EXPECT_TRUE(bOK) << "Something went wrong: LINCS returned false value.";
+            bool sucess = constrain_lincs(false, testData->ir_, 0, lincsd, testData->md_,
+                                          &testData->cr_,
+                                          &testData->ms_,
+                                          as_rvec_array(testData->x_.data()),
+                                          as_rvec_array(testData->xPrime_.data()),
+                                          as_rvec_array(testData->xPrime2_.data()),
+                                          pbc.box, &pbc,
+                                          testData->md_.lambda, &testData->dHdLambda_,
+                                          testData->invdt_,
+                                          as_rvec_array(testData->v_.data()),
+                                          testData->computeVirial_, testData->virialScaled_,
+                                          gmx::ConstraintVariable::Positions,
+                                          &testData->nrnb_,
+                                          maxwarn, &warncount_lincs);
+            EXPECT_TRUE(sucess) << "Test failed with a false return value in LINCS.";
             EXPECT_EQ(warncount_lincs, 0) << "There were warnings in LINCS.";
-            for (unsigned int i = 0; i < mtop.moltype.size(); i++)
+            for (unsigned int i = 0; i < testData->mtop_.moltype.size(); i++)
             {
                 sfree(at2con_mt.at(i).index);
                 sfree(at2con_mt.at(i).a);
@@ -341,413 +511,555 @@ class ConstraintsTest : public ::testing::Test
         }
 
         /*! \brief
-         * Initialize and apply SHAKE constraints.
+         * The test on the final length of constrained bonds.
          *
-         * \param[in] shake_tol      Target tolerance for SHAKE.
-         * \param[in] bShakeSOR      Use successive over-relaxation method for SHAKE iterative process.
-         *                           The general formula is:
-         *                              x_n+1 = (1-omega)*x_n + omega*f(x_n),
-         *                           where omega = 1 if SOR is off and may be < 1 if SOR is on.
+         * Goes through all the constraints and checks if the final length of all the constraints is equal
+         * to the target length with provided tolerance.
          *
+         * \param[in] tolerance       Allowed tolerance in final lengths.
+         * \param[in] testData        Test data structure.
+         * \param[in] pbc             Periodic boundary data.
          */
-        void applyConstraintsShake(real shake_tol, gmx_bool bShakeSOR)
+        void checkConstrainsLength(FloatingPointTolerance tolerance, const ConstraintsTestData &testData, t_pbc pbc)
         {
 
-            ir.shake_tol      = shake_tol;
-            ir.bShakeSOR      = bShakeSOR;
-
-            shakedata* shaked = shake_init();
-            make_shake_sblock_serial(shaked, &idef, md);
-            bool       bOK = constrain_shake(
-                        gmx_fio_getfp(log),
-                        shaked,
-                        invmass.data(),
-                        idef,
-                        ir,
-                        x,
-                        xprime,
-                        xprime2,
-                        &nrnb,
-                        md.lambda,
-                        dvdlambda,
-                        invdt,
-                        v,
-                        computeVirial,
-                        vir_r_m_dr,
-                        false,
-                        gmx::ConstraintVariable::Positions);
-            EXPECT_TRUE(bOK) << "Something went wrong: SHAKE returned false value.";
-            done_shake(shaked);  // Not yet implemented. We will have memory leaks without this.
+            // Test if all the constraints are satisfied
+            for (unsigned c = 0; c < testData.constraints_.size()/3; c++)
+            {
+                real r0 = testData.constraintsR0_.at(testData.constraints_.at(3*c));
+                int  i  = testData.constraints_.at(3*c + 1);
+                int  j  = testData.constraints_.at(3*c + 2);
+                RVec xij0, xij1;
+                real d0, d1;
+                if (pbc.ePBC == epbcXYZ)
+                {
+                    pbc_dx_aiuc(&pbc, testData.x_[i], testData.x_[j], xij0);
+                    pbc_dx_aiuc(&pbc, testData.xPrime_[i], testData.xPrime_[j], xij1);
+                }
+                else
+                {
+                    rvec_sub(testData.x_[i], testData.x_[j], xij0);
+                    rvec_sub(testData.xPrime_[i], testData.xPrime_[j], xij1);
+                }
+                d0 = norm(xij0);
+                d1 = norm(xij1);
+                EXPECT_REAL_EQ_TOL(r0, d1, tolerance) << gmx::formatString(
+                        "rij = %f, which is not equal to r0 = %f for constraint #%u, between atoms %d and %d"
+                        " (before constraining rij was %f).", d1, r0, c, i, j, d0);
+            }
         }
 
         /*! \brief
          * The test on the final length of constrained bonds.
          *
-         * Goes through all the constraints and checks if the final length of all the constraints is equal
-         * to the target lenght with provided tolerance.
+         * Goes through all the constraints and checks if the direction of constraint has not changed
+         * by the algorithm (i.e. the constraints algorithm arrived to the solution that is closest
+         * to the initial system conformation).
          *
-         * \param[in] tolerance                  Allowed tolerance in final lengths.
+         * \param[in] testData        Test data structure.
+         * \param[in] pbc             Periodic boundary data.
          */
-
-        void checkConstrained(FloatingPointTolerance tolerance)
+        void checkConstrainsDirection(const ConstraintsTestData &testData, t_pbc pbc)
         {
 
-            // Test if all the constraints are satisfied
-            for (unsigned c = 0; c < constraints.size()/3; c++)
+            for (unsigned c = 0; c < testData.constraints_.size()/3; c++)
             {
-                real r0 = constraintsR0.at(constraints.at(3*c) - firstType);
-                int  i  = constraints.at(3*c + 1);
-                int  j  = constraints.at(3*c + 2);
-                rvec v0, v1;
-                real d0, d1;
-                if (this->epbc == epbcXYZ)
+                int  i  = testData.constraints_.at(3*c + 1);
+                int  j  = testData.constraints_.at(3*c + 2);
+                RVec xij0, xij1;
+                if (pbc.ePBC == epbcXYZ)
                 {
-                    pbc_dx_aiuc(&pbc, x[i], x[j], v0);
-                    pbc_dx_aiuc(&pbc, xprime[i], xprime[j], v1);
+                    pbc_dx_aiuc(&pbc, testData.x_[i], testData.x_[j], xij0);
+                    pbc_dx_aiuc(&pbc, testData.xPrime_[i], testData.xPrime_[j], xij1);
                 }
                 else
                 {
-                    rvec_sub(x[i], x[j], v0);
-                    rvec_sub(xprime[i], xprime[j], v1);
+                    rvec_sub(testData.x_[i], testData.x_[j], xij0);
+                    rvec_sub(testData.xPrime_[i], testData.xPrime_[j], xij1);
                 }
-                d0 = norm(v0);
-                d1 = norm(v1);
-                EXPECT_REAL_EQ_TOL(r0, d1, tolerance) << "rij = " << d1 << ", which is not equal to r0 = " << r0
-                << " for constraint #" << c << ", between atoms " << i << " and " << j
-                << " (before lincs rij was " << d0 << ").";
+
+                real dot = xij0.dot(xij1);
+
+                EXPECT_GE(dot, 0.0) << gmx::formatString(
+                        "The constraint %u changed direction. Constraining algorithm might have returned the wrong root "
+                        "of the constraints equation.", c);
+
+            }
+        }
+
+        /*! \brief
+         * The test on the coordinates of the center of the mass (COM) of the system.
+         *
+         * Checks if the center of mass has not been shifted by the constraints. Note,
+         * that this test does not take into account the periodic boundary conditions.
+         * Hence it will not work should the constraints decide to move atoms across
+         * PBC borders.
+         *
+         * \param[in] tolerance       Allowed tolerance in COM coordinates.
+         * \param[in] testData        Test data structure.
+         */
+        void checkCOMCoordinates(FloatingPointTolerance tolerance, const ConstraintsTestData &testData)
+        {
+
+            RVec comPrime0({0.0, 0.0, 0.0});
+            RVec comPrime({0.0, 0.0, 0.0});
+            for (int i = 0; i < testData.nAtom_; i++)
+            {
+                comPrime0 += testData.masses_[i]*testData.xPrime0_[i];
+                comPrime  += testData.masses_[i]*testData.xPrime_[i];
+            }
+
+            comPrime0 /= testData.nAtom_;
+            comPrime  /= testData.nAtom_;
+
+            EXPECT_REAL_EQ_TOL(comPrime[XX], comPrime0[XX], tolerance)
+            << "Center of mass was shifted by constraints in x-direction.";
+            EXPECT_REAL_EQ_TOL(comPrime[YY], comPrime0[YY], tolerance)
+            << "Center of mass was shifted by constraints in y-direction.";
+            EXPECT_REAL_EQ_TOL(comPrime[ZZ], comPrime0[ZZ], tolerance)
+            << "Center of mass was shifted by constraints in z-direction.";
+
+        }
+
+        /*! \brief
+         * The test on the velocity of the center of the mass (COM) of the system.
+         *
+         * Checks if the velocity of the center of mass has not changed.
+         *
+         * \param[in] tolerance       Allowed tolerance in COM velocity components.
+         * \param[in] testData        Test data structure.
+         */
+        void checkCOMVelocity(FloatingPointTolerance tolerance, const ConstraintsTestData &testData)
+        {
+
+            RVec comV0({0.0, 0.0, 0.0});
+            RVec comV({0.0, 0.0, 0.0});
+            for (int i = 0; i < testData.nAtom_; i++)
+            {
+                comV0 += testData.masses_[i]*testData.v0_[i];
+                comV  += testData.masses_[i]*testData.v_[i];
             }
+            comV0 /= testData.nAtom_;
+            comV  /= testData.nAtom_;
+
+            EXPECT_REAL_EQ_TOL(comV[XX], comV0[XX], tolerance)
+            << "Velocity of the center of mass in x-direction has been changed by constraints.";
+            EXPECT_REAL_EQ_TOL(comV[YY], comV0[YY], tolerance)
+            << "Velocity of the center of mass in y-direction has been changed by constraints.";
+            EXPECT_REAL_EQ_TOL(comV[ZZ], comV0[ZZ], tolerance)
+            << "Velocity of the center of mass in z-direction has been changed by constraints.";
         }
 
         /*! \brief
-         * The test on the final coordinates.
+         * The test on the final coordinates (not used).
          *
          * Goes through all atoms and checks if the final positions correspond to the
          * provided reference set of coordinates.
          *
-         * \param[in] finalCoordinates           The reference set of coordinates.
-         * \param[in] finalCoordinatesTolerance  Tolerance for the coordinaes test.
+         * \param[in] xPrimeRef       The reference set of coordinates.
+         * \param[in] tolerance       Tolerance for the coordinates test.
+         * \param[in] testData        Test data structure.
          */
-        void checkFinalCoordinates(std::vector<RVec> finalCoordinates, FloatingPointTolerance finalCoordinatesTolerance)
+        void checkFinalCoordinates(std::vector<RVec> xPrimeRef, FloatingPointTolerance tolerance,
+                                   const ConstraintsTestData &testData)
         {
-            for (int i = 0; i < n; i++)
+            for (int i = 0; i < testData.nAtom_; i++)
             {
                 for (int d = 0; d < DIM; d++)
                 {
-                    EXPECT_REAL_EQ_TOL(finalCoordinates.at(i)[d], xprime[i][d], finalCoordinatesTolerance) <<
-                    "Coordinates after constrains were applied differ from these in the reference set for atom #" << i << ".";
+                    EXPECT_REAL_EQ_TOL(xPrimeRef.at(i)[d], testData.xPrime_[i][d], tolerance) << gmx::formatString(
+                            "Coordinates after constrains were applied differ from these in the reference set for atom #%d.", i);
                 }
             }
         }
 
+        /*! \brief
+         * The test of virial tensor.
+         *
+         * Checks if the values in the scaled virial tensor are equal to pre-computed values.
+         *
+         * \param[in] tolerance       Tolerance for the tensor values.
+         * \param[in] testData        Test data structure.
+         */
+        void checkVirialTensor(FloatingPointTolerance tolerance, const ConstraintsTestData &testData)
+        {
+            for (int i = 0; i < DIM; i++)
+            {
+                for (int j = 0; j < DIM; j++)
+                {
+                    EXPECT_REAL_EQ_TOL(testData.virialScaledRef_[i][j], testData.virialScaled_[i][j],
+                                       tolerance) << gmx::formatString(
+                            "Values in virial tensor at [%d][%d] are not within the tolerance from reference value.", i, j);
+                }
+            }
+        }
 
-    private:
-        int                   n;                            // Number of atoms
-        gmx_mtop_t            mtop;                         // Topology
-        std::vector<real>     invmass;                      // Inverse masses
-        int                   epbc;                         // PBC used (epbcNONE/epbcXYZ)
-        matrix                box;                          // PBC box
-        t_pbc                 pbc;                          // PBC object
-        t_commrec             cr;                           // Communication record
-        t_inputrec            ir;                           // Input record (info that usually in .mdp file)
-        t_idef                idef;                         // Local topology
-        t_mdatoms             md;                           // MD atoms
-        t_nrnb                nrnb;
-
-        real                  invdt         = 1.0/0.001;    // Inverse timestep
-        int                   nflexcon      = 0;            // Number of flexible constraints
-        real                 *dvdlambda     = nullptr;      // Free energy computation stub (not tested)
-        bool                  computeVirial = false;        // If the virials should be conputed (not tested)
-        tensor                vir_r_m_dr;                   // Virials stuff
-        rvec                 *x;                            // Coordinates before constraints are applied
-        rvec                 *xprime;                       // Coordinates after constraints are applied
-        rvec                 *xprime2;                      // Intermediate set of coordinates used by LINCS and
-                                                            // SHAKE for different purposes
-        rvec                 *v;                            // Velocities (can also be constrained, this is not tested)
-        t_fileio             *log;                          // log file (now set to "constraintstest.log")
+        /*! \brief
+         * The test for FEP (not used).
+         *
+         * Checks if the value of dH/dLambda is equal to the reference value.
+         * \todo Add tests for dHdLambda values.
+         *
+         * \param[in] dHdLambdaRef    Reference value.
+         * \param[in] tolerance       Tolerance.
+         * \param[in] testData        Test data structure.
+         */
+        void checkFEP(const real dHdLambdaRef, FloatingPointTolerance tolerance,
+                      const ConstraintsTestData &testData)
+        {
+            EXPECT_REAL_EQ_TOL(dHdLambdaRef, testData.dHdLambda_, tolerance) <<
+            "Computed value for dV/dLambda is not equal to the reference value. ";
+        }
 
-        // Fields to store constraints data for testing
-        int                   firstType;                    // First interaction type used for constraints
-        std::vector<int>      constraints;                  // Constraints data (type1-i1-j1-type2-i2-j2-...)
-        std::vector<real>     constraintsR0;                // Target lengths for al the constrain
-};
 
-/*
- *
- * Tests that the interatomic distance along constraints correspond to the reference distances.
- * Performed on basic systems of up to four constaints.
- *
- */
 
-/*
- * Simple bond test for SHAKE
- */
-TEST_F(ConstraintsTest, ShakeOneBond)
-{
+};
+
+TEST_P(ConstraintsTest, SingleConstraint){
+    std::string       title = "one constraint (e.g. OH)";
+    int               nAtom = 2;
+
+    std::vector<real> masses        = {1.0, 12.0};
+    std::vector<int>  constraints   = {0, 0, 1};
+    std::vector<real> constraintsR0 = {0.1};
+
+    real              oneTenthOverSqrtTwo    = 0.1_real / std::sqrt(2.0_real);
+
+    std::vector<RVec> x = {{ 0.0, oneTenthOverSqrtTwo, 0.0 },
+                           { oneTenthOverSqrtTwo, 0.0, 0.0 }};
+    std::vector<RVec> xPrime = {{ 0.01,  0.08,  0.01 },
+                                { 0.06,  0.01, -0.01 }};
+    std::vector<RVec> v = {{ 1.0, 2.0, 3.0 },
+                           { 3.0, 2.0, 1.0 }};
+
+    tensor            virialScaledRef = {{-5.58e-04,  5.58e-04, 0.00e+00 },
+                                         { 5.58e-04, -5.58e-04, 0.00e+00 },
+                                         { 0.00e+00,  0.00e+00, 0.00e+00 } };
+
+    real              shakeTolerance         = 0.0001;
+    gmx_bool          shakeUseSOR            = false;
+
+    int               lincsNIter             = 1;
+    int               lincsNProjOrder        = 4;
+    real              lincsWarnAngle         = 30.0;
+
+    std::unique_ptr<ConstraintsTestData>   testData = std::make_unique<ConstraintsTestData>
+            (title, nAtom, masses,
+            constraints, constraintsR0,
+            true, virialScaledRef,
+            false, 0,
+            real(0.0), real(0.001),
+            x, xPrime, v,
+            shakeTolerance, shakeUseSOR,
+            lincsNIter, lincsNProjOrder, lincsWarnAngle);
+    std::string pbcName;
+    std::string algorithmName;
+    std::tie(pbcName, algorithmName) = GetParam();
+    t_pbc                                   pbc       = pbcs_.at(pbcName);
+
+    // Apply constraints
+    algorithms_.at(algorithmName)(testData.get(), pbc);
+
+    checkConstrainsLength(absoluteTolerance(0.0002), *testData, pbc);
+    checkConstrainsDirection(*testData, pbc);
+    checkCOMCoordinates(absoluteTolerance(0.0001), *testData);
+    checkCOMVelocity(absoluteTolerance(0.0001), *testData);
+
+    checkVirialTensor(absoluteTolerance(0.0001), *testData);
 
-    FloatingPointTolerance tolerance = relativeToleranceAsFloatingPoint(0.1, 0.0001);
-    initSystem(2, c_oneBondMasses,
-               c_oneBondConstraints, c_oneBondConstraintsR0, c_oneBondConstraintsFirstType,
-               epbcNONE, c_infinitesimalBox,
-               real(0.0), real(0.001), c_oneBondCoordinates);
-    applyConstraintsShake(0.0001, false);
-    checkConstrained(tolerance);
 }
 
-/*
- * Simple bond test for LINCS
- */
-TEST_F(ConstraintsTest, LincsOneBond)
-{
+TEST_P(ConstraintsTest, TwoDisjointConstraints){
 
-    FloatingPointTolerance tolerance = relativeToleranceAsFloatingPoint(0.1, 0.0000002);
-    initSystem(2, c_oneBondMasses,
-               c_oneBondConstraints, c_oneBondConstraintsR0, c_oneBondConstraintsFirstType,
-               epbcNONE, c_infinitesimalBox,
-               real(0.0), real(0.001), c_oneBondCoordinates);
-    applyConstraintsLincs(1, 4, real(30.0));
-    checkConstrained(tolerance);
-}
+    std::string       title         = "two disjoint constraints";
+    int               nAtom         = 4;
+    std::vector<real> masses        = {0.5, 1.0/3.0, 0.25, 1.0};
+    std::vector<int>  constraints   = {0, 0, 1, 1, 2, 3};
+    std::vector<real> constraintsR0 = {2.0, 1.0};
 
-/*
- * Two disjoint bonds test for SHAKE
- */
-TEST_F(ConstraintsTest, ShakeTwoDisjointBonds)
-{
 
-    FloatingPointTolerance tolerance = relativeToleranceAsFloatingPoint(0.1, 0.000001);
-    initSystem(4, c_twoDJBondsMasses,
-               c_twoDJBondsConstraints, c_twoDJBondsConstraintsR0, c_twoDJBondsConstraintsFirstType,
-               epbcNONE, c_infinitesimalBox,
-               real(0.0), real(0.001), c_twoDJBondsCoordinates);
+    std::vector<RVec> x = {{  2.50, -3.10, 15.70 },
+                           {  0.51, -3.02, 15.55 },
+                           { -0.50, -3.00, 15.20 },
+                           { -1.51, -2.95, 15.05 }};
 
-    applyConstraintsShake(0.000001, true);
-    checkConstrained(tolerance);
-}
+    std::vector<RVec> xPrime = {{  2.50, -3.10, 15.70 },
+                                {  0.51, -3.02, 15.55 },
+                                { -0.50, -3.00, 15.20 },
+                                { -1.51, -2.95, 15.05 }};
 
-/*
- * Two disjoint bonds test for LINCS
- */
-TEST_F(ConstraintsTest, LincsTwoDisjointBonds)
-{
+    std::vector<RVec> v = {{ 0.0, 1.0, 0.0 },
+                           { 1.0, 0.0, 0.0 },
+                           { 0.0, 0.0, 1.0 },
+                           { 0.0, 0.0, 0.0 }};
 
-    FloatingPointTolerance tolerance = relativeToleranceAsFloatingPoint(0.1, 0.0000002);
-    initSystem(4, c_twoDJBondsMasses,
-               c_twoDJBondsConstraints, c_twoDJBondsConstraintsR0, c_twoDJBondsConstraintsFirstType,
-               epbcNONE, c_infinitesimalBox,
-               real(0.0), real(0.001), c_twoDJBondsCoordinates);
+    tensor            virialScaledRef = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
 
-    applyConstraintsLincs(1, 4, real(30.0));
-    checkConstrained(tolerance);
-}
+    real              shakeTolerance         = 0.0001;
+    gmx_bool          shakeUseSOR            = false;
 
-/*
- * Two consequentive constraints test for SHAKE.
- */
-TEST_F(ConstraintsTest, ShakeTwoBonds)
-{
+    int               lincsNIter             = 1;
+    int               lincsNProjOrder        = 4;
+    real              lincsWarnAngle         = 30.0;
 
-    FloatingPointTolerance tolerance = relativeToleranceAsFloatingPoint(0.1, 0.0001);
-    initSystem(3, c_twoBondsMasses,
-               c_twoBondsConstraints, c_twoBondsConstraintsR0, c_twoBondsConstraintsFirstType,
-               epbcNONE, c_infinitesimalBox,
-               real(0.0), real(0.001), c_twoBondsCoordinates);
+    std::unique_ptr<ConstraintsTestData>   testData = std::make_unique<ConstraintsTestData>
+            (title, nAtom, masses,
+            constraints, constraintsR0,
+            false, virialScaledRef,
+            false, 0,
+            real(0.0), real(0.001),
+            x, xPrime, v,
+            shakeTolerance, shakeUseSOR,
+            lincsNIter, lincsNProjOrder, lincsWarnAngle);
 
-    applyConstraintsShake(0.0001, true);
-    checkConstrained(tolerance);
-}
+    std::string pbcName;
+    std::string algorithmName;
+    std::tie(pbcName, algorithmName) = GetParam();
+    t_pbc                                   pbc       = pbcs_.at(pbcName);
 
-/*
- * Two consequentive constraints test for LINCS.
- */
-TEST_F(ConstraintsTest, LincsTwoBonds)
-{
+    // Apply constraints
+    algorithms_.at(algorithmName)(testData.get(), pbc);
 
-    FloatingPointTolerance tolerance = relativeToleranceAsFloatingPoint(0.1, 0.000001);
-    initSystem(3, c_twoBondsMasses,
-               c_twoBondsConstraints, c_twoBondsConstraintsR0, c_twoBondsConstraintsFirstType,
-               epbcNONE, c_infinitesimalBox,
-               real(0.0), real(0.001), c_twoBondsCoordinates);
+    checkConstrainsLength(absoluteTolerance(0.0002), *testData, pbc);
+    checkConstrainsDirection(*testData, pbc);
+    checkCOMCoordinates(absoluteTolerance(0.0001), *testData);
+    checkCOMVelocity(absoluteTolerance(0.0001), *testData);
 
-    applyConstraintsLincs(1, 4, real(30.0));
-    checkConstrained(tolerance);
 }
 
-/*
- * Triangle of constraints test for SHAKE
- */
-TEST_F(ConstraintsTest, ShakeTriangleOfBonds)
-{
+TEST_P(ConstraintsTest, ThreeSequentialConstraints){
 
-    FloatingPointTolerance tolerance = relativeToleranceAsFloatingPoint(0.1, 0.0001);
-    initSystem(3, c_triangleMasses,
-               c_triangleConstraints, c_triangleConstraintsR0, c_triangleConstraintsFirstType,
-               epbcNONE, c_infinitesimalBox,
-               real(0.0), real(0.001), c_triangleCoordinates);
-    applyConstraintsShake(0.0001, true);
-    checkConstrained(tolerance);
-}
+    std::string       title         = "three atoms, connected longitudinally (e.g. CH2)";
+    int               nAtom         = 3;
+    std::vector<real> masses        = {1.0, 12.0, 16.0 };
+    std::vector<int>  constraints   = {0, 0, 1, 1, 1, 2};
+    std::vector<real> constraintsR0 = {0.1, 0.2};
 
-/*
- * Triangle of constraints test for LINCS
- */
-TEST_F(ConstraintsTest, LincsTriangleOfBonds)
-{
+    real              oneTenthOverSqrtTwo    = 0.1_real / std::sqrt(2.0_real);
+    real              twoTenthsOverSqrtThree = 0.2_real / std::sqrt(3.0_real);
 
-    FloatingPointTolerance tolerance = relativeToleranceAsFloatingPoint(0.1, 0.0001);
-    initSystem(3, c_triangleMasses,
-               c_triangleConstraints, c_triangleConstraintsR0, c_triangleConstraintsFirstType,
-               epbcNONE, c_infinitesimalBox,
-               real(0.0), real(0.001), c_triangleCoordinates);
-    applyConstraintsLincs(4, 4, real(30.0));
-    checkConstrained(tolerance);
-}
+    std::vector<RVec> x = {{ oneTenthOverSqrtTwo, oneTenthOverSqrtTwo, 0.0 },
+                           { 0.0, 0.0, 0.0 },
+                           { twoTenthsOverSqrtThree, twoTenthsOverSqrtThree, twoTenthsOverSqrtThree }};
 
-/*
- * Three consecutive constraints test for SHAKE.
- */
-TEST_F(ConstraintsTest, ShakeThreeConsequativeConstraints)
-{
+    std::vector<RVec> xPrime = {{  0.08, 0.07,  0.01 },
+                                { -0.02, 0.01, -0.02 },
+                                {  0.10, 0.12,  0.11 }};
 
-    FloatingPointTolerance tolerance = relativeToleranceAsFloatingPoint(0.1, 0.001);
-    initSystem(4, c_threeBondsMasses,
-               c_threeBondsConstraints, c_threeBondsConstraintsR0, c_threeBondsConstraintsFirstType,
-               epbcNONE, c_infinitesimalBox,
-               real(0.0), real(0.001), c_threeBondsCoordinates);
-    applyConstraintsShake(0.0001, true);
-    checkConstrained(tolerance);
-}
+    std::vector<RVec> v = {{ 1.0, 0.0, 0.0 },
+                           { 0.0, 1.0, 0.0 },
+                           { 0.0, 0.0, 1.0 }};
 
-/*
- * Three consecutive constraints test for LINCS.
- */
-TEST_F(ConstraintsTest, LincsThreeConsequativeConstraints)
-{
+    tensor            virialScaledRef = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
 
-    FloatingPointTolerance tolerance = relativeToleranceAsFloatingPoint(0.1, 0.001);
-    initSystem(4, c_threeBondsMasses,
-               c_threeBondsConstraints, c_threeBondsConstraintsR0, c_threeBondsConstraintsFirstType,
-               epbcNONE, c_infinitesimalBox,
-               real(0.0), real(0.001), c_threeBondsCoordinates);
-    applyConstraintsLincs(4, 4, real(30.0));
-    checkConstrained(tolerance);
-}
+    real              shakeTolerance         = 0.0001;
+    gmx_bool          shakeUseSOR            = false;
 
+    int               lincsNIter             = 1;
+    int               lincsNProjOrder        = 4;
+    real              lincsWarnAngle         = 30.0;
 
-/*
- *
- * Tests of both final interatomic distances and final coordinates.
- * Peformed on the peptide Cys-Val-Trp, with constraints along HBonds,
- * AllBonds (for both SHAKE and LINCS), HAngles and AllAlngles (for
- * SHAKE only).
- */
+    std::unique_ptr<ConstraintsTestData>   testData = std::make_unique<ConstraintsTestData>
+            (title, nAtom, masses,
+            constraints, constraintsR0,
+            false, virialScaledRef,
+            false, 0,
+            real(0.0), real(0.001),
+            x, xPrime, v,
+            shakeTolerance, shakeUseSOR,
+            lincsNIter, lincsNProjOrder, lincsWarnAngle);
 
-/*
- * All bonds that involve hydrogen atom (HBonds) are constrained by SHAKE. Both final length
- * of each constraint and final coordinates for each atom are tested.
- */
-TEST_F(ConstraintsTest, ShakeCysValTrpHBonds)
-{
+    std::string pbcName;
+    std::string algorithmName;
+    std::tie(pbcName, algorithmName) = GetParam();
+    t_pbc                                   pbc       = pbcs_.at(pbcName);
+
+    // Apply constraints
+    algorithms_.at(algorithmName)(testData.get(), pbc);
 
-    FloatingPointTolerance tolerance            = relativeToleranceAsFloatingPoint(0.1, 0.0001);
-    FloatingPointTolerance coordinatesTolerance = absoluteTolerance(0.0001);
+    checkConstrainsLength(absoluteTolerance(0.0002), *testData, pbc);
+    checkConstrainsDirection(*testData, pbc);
+    checkCOMCoordinates(absoluteTolerance(0.0001), *testData);
+    checkCOMVelocity(absoluteTolerance(0.0001), *testData);
 
-    initSystem(54, c_cvwMasses,
-               c_cvwHBondsConstraints, c_cvwHBondsConstraintsR0, c_cvwHBondsConstraintsFirstType,
-               epbcXYZ, c_cvwBox,
-               real(0.0), real(0.001), c_cvwInitialCoordinates);
-    applyConstraintsShake(0.0001, true);
-    checkConstrained(tolerance);
-    checkFinalCoordinates(c_cvwFinalCoordinatesHBonds, coordinatesTolerance);
 }
 
-/*
- * All bonds that involve hydrogen atom (HBonds) are constrained by LINCS. Both final length
- * of each constraint and final coordinates for each atom are tested.
- */
-TEST_F(ConstraintsTest, LincsCysValTrpHBonds)
-{
+TEST_P(ConstraintsTest, ThreeConstraintsWithCentralAtom){
 
-    FloatingPointTolerance tolerance            = relativeToleranceAsFloatingPoint(0.1, 0.00001);
-    FloatingPointTolerance coordinatesTolerance = absoluteTolerance(0.0001);
+    std::string       title         = "three atoms, connected to the central atom (e.g. CH3)";
+    int               nAtom         = 4;
+    std::vector<real> masses        = {12.0, 1.0, 1.0, 1.0 };
+    std::vector<int>  constraints   = {0, 0, 1, 0, 0, 2, 0, 0, 3};
+    std::vector<real> constraintsR0 = {0.1};
 
-    initSystem(54, c_cvwMasses,
-               c_cvwHBondsConstraints, c_cvwHBondsConstraintsR0, c_cvwHBondsConstraintsFirstType,
-               epbcXYZ, c_cvwBox,
-               real(0.0), real(0.001), c_cvwInitialCoordinates);
-    applyConstraintsLincs(1, 4, real(30.0));
-    checkConstrained(tolerance);
-    checkFinalCoordinates(c_cvwFinalCoordinatesHBonds, coordinatesTolerance);
-}
 
-/*
- * All bonds are constrained by SHAKE. Both final length of each constraint and final coordinates
- * for each atom are tested.
- */
-TEST_F(ConstraintsTest, ShakeCysValTrpAllBonds)
-{
+    std::vector<RVec> x = {{ 0.00,  0.00,  0.00 },
+                           { 0.10,  0.00,  0.00 },
+                           { 0.00, -0.10,  0.00 },
+                           { 0.00,  0.00,  0.10 }};
+
+    std::vector<RVec> xPrime = {{ 0.004,  0.009, -0.010 },
+                                { 0.110, -0.006,  0.003 },
+                                {-0.007, -0.102, -0.007 },
+                                {-0.005,  0.011,  0.102 }};
+
+    std::vector<RVec> v = {{ 1.0, 0.0, 0.0 },
+                           { 1.0, 0.0, 0.0 },
+                           { 1.0, 0.0, 0.0 },
+                           { 1.0, 0.0, 0.0 }};
+
+    tensor            virialScaledRef = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
+
+    real              shakeTolerance         = 0.0001;
+    gmx_bool          shakeUseSOR            = false;
 
-    FloatingPointTolerance tolerance            = relativeToleranceAsFloatingPoint(0.1, 0.0001);
-    FloatingPointTolerance coordinatesTolerance = absoluteTolerance(0.001);
+    int               lincsNIter             = 1;
+    int               lincsNProjOrder        = 4;
+    real              lincsWarnAngle         = 30.0;
+
+    std::unique_ptr<ConstraintsTestData>   testData = std::make_unique<ConstraintsTestData>
+            (title, nAtom, masses,
+            constraints, constraintsR0,
+            false, virialScaledRef,
+            false, 0,
+            real(0.0), real(0.001),
+            x, xPrime, v,
+            shakeTolerance, shakeUseSOR,
+            lincsNIter, lincsNProjOrder, lincsWarnAngle);
+
+    std::string pbcName;
+    std::string algorithmName;
+    std::tie(pbcName, algorithmName) = GetParam();
+    t_pbc                                   pbc       = pbcs_.at(pbcName);
+
+    // Apply constraints
+    algorithms_.at(algorithmName)(testData.get(), pbc);
+
+    checkConstrainsLength(absoluteTolerance(0.0002), *testData, pbc);
+    checkConstrainsDirection(*testData, pbc);
+    checkCOMCoordinates(absoluteTolerance(0.0001), *testData);
+    checkCOMVelocity(absoluteTolerance(0.0001), *testData);
 
-    initSystem(54, c_cvwMasses,
-               c_cvwAllBondsConstraints, c_cvwAllBondsConstraintsR0, c_cvwAllBondsConstraintsFirstType,
-               epbcXYZ, c_cvwBox,
-               real(0.0), real(0.001), c_cvwInitialCoordinates);
-    applyConstraintsShake(0.0001, true);
-    checkConstrained(tolerance);
-    checkFinalCoordinates(c_cvwFinalCoordinatesAllBonds, coordinatesTolerance);
 }
 
-/*
- * All bonds are constrained by LINCS. Both final length of each constraint and final coordinates
- * for each atom are tested.
- */
-TEST_F(ConstraintsTest, LincsCysValTrpAllBonds)
-{
+TEST_P(ConstraintsTest, FourSequentialConstraints){
 
-    FloatingPointTolerance tolerance            = relativeToleranceAsFloatingPoint(0.1, 0.0001);
-    FloatingPointTolerance coordinatesTolerance = absoluteTolerance(0.001);
+    std::string       title         = "four atoms, connected longitudinally";
+    int               nAtom         = 4;
+    std::vector<real> masses        = {0.5, 1.0/3.0, 0.25, 1.0};
+    std::vector<int>  constraints   = {0, 0, 1, 1, 1, 2, 2, 2, 3};
+    std::vector<real> constraintsR0 = {2.0, 1.0, 1.0};
+
+
+    std::vector<RVec> x = {{  2.50, -3.10, 15.70 },
+                           {  0.51, -3.02, 15.55 },
+                           { -0.50, -3.00, 15.20 },
+                           { -1.51, -2.95, 15.05 }};
+
+    std::vector<RVec> xPrime = {{  2.50, -3.10, 15.70 },
+                                {  0.51, -3.02, 15.55 },
+                                { -0.50, -3.00, 15.20 },
+                                { -1.51, -2.95, 15.05 }};
+
+    std::vector<RVec> v = {{ 0.0, 0.0,  2.0 },
+                           { 0.0, 0.0,  3.0 },
+                           { 0.0, 0.0, -4.0 },
+                           { 0.0, 0.0, -1.0 }};
+
+    tensor            virialScaledRef = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
+
+    real              shakeTolerance         = 0.0001;
+    gmx_bool          shakeUseSOR            = false;
+
+    int               lincsNIter             = 4;
+    int               lincsNProjOrder        = 8;
+    real              lincsWarnAngle         = 30.0;
+
+    std::unique_ptr<ConstraintsTestData>   testData = std::make_unique<ConstraintsTestData>
+            (title, nAtom, masses,
+            constraints, constraintsR0,
+            false, virialScaledRef,
+            false, 0,
+            real(0.0), real(0.001),
+            x, xPrime, v,
+            shakeTolerance, shakeUseSOR,
+            lincsNIter, lincsNProjOrder, lincsWarnAngle);
+
+    std::string pbcName;
+    std::string algorithmName;
+    std::tie(pbcName, algorithmName) = GetParam();
+    t_pbc                                   pbc       = pbcs_.at(pbcName);
+
+    // Apply constraints
+    algorithms_.at(algorithmName)(testData.get(), pbc);
+
+    checkConstrainsLength(absoluteTolerance(0.0002), *testData, pbc);
+    checkConstrainsDirection(*testData, pbc);
+    checkCOMCoordinates(absoluteTolerance(0.0001), *testData);
+    checkCOMVelocity(absoluteTolerance(0.0001), *testData);
 
-    initSystem(54, c_cvwMasses,
-               c_cvwAllBondsConstraints, c_cvwAllBondsConstraintsR0, c_cvwAllBondsConstraintsFirstType,
-               epbcXYZ, c_cvwBox,
-               real(0.0), real(0.001), c_cvwInitialCoordinates);
-    applyConstraintsLincs(4, 4, real(30.0));
-    checkConstrained(tolerance);
-    checkFinalCoordinates(c_cvwFinalCoordinatesAllBonds, coordinatesTolerance);
 }
 
-/*
- * H angles and all bonds are constrained by SHAKE. Only final lengths of constraints are tested.
- */
-TEST_F(ConstraintsTest, ShakeCysValTrpHAngles)
-{
+TEST_P(ConstraintsTest, TriangleOfConstraints){
+
+    std::string       title         = "basic triangle (tree atoms, connected to each other)";
+    int               nAtom         = 3;
+    std::vector<real> masses        = {1.0, 1.0, 1.0};
+    std::vector<int>  constraints   = {0, 0, 1, 2, 0, 2, 1, 1, 2};
+    std::vector<real> constraintsR0 = {0.1, 0.1, 0.1};
 
-    FloatingPointTolerance tolerance            = relativeToleranceAsFloatingPoint(0.1, 0.0001);
+    real              oneTenthOverSqrtTwo    = 0.1_real / std::sqrt(2.0_real);
+
+    std::vector<RVec> x = {{ oneTenthOverSqrtTwo, 0.0, 0.0 },
+                           { 0.0, oneTenthOverSqrtTwo, 0.0 },
+                           { 0.0, 0.0, oneTenthOverSqrtTwo }};
+
+    std::vector<RVec> xPrime = {{  0.09, -0.02,  0.01 },
+                                { -0.02,  0.10, -0.02 },
+                                {  0.03, -0.01,  0.07 }};
+
+    std::vector<RVec> v = {{  1.0,  1.0,  1.0 },
+                           { -2.0, -2.0, -2.0 },
+                           {  1.0,  1.0,  1.0 }};
+
+    tensor            virialScaledRef = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
+
+    real              shakeTolerance         = 0.0001;
+    gmx_bool          shakeUseSOR            = false;
+
+    int               lincsNIter             = 1;
+    int               lincsNProjOrder        = 4;
+    real              lincsWarnAngle         = 30.0;
+
+    std::unique_ptr<ConstraintsTestData>   testData = std::make_unique<ConstraintsTestData>
+            (title, nAtom, masses,
+            constraints, constraintsR0,
+            false, virialScaledRef,
+            false, 0,
+            real(0.0), real(0.001),
+            x, xPrime, v,
+            shakeTolerance, shakeUseSOR,
+            lincsNIter, lincsNProjOrder, lincsWarnAngle);
+
+    std::string pbcName;
+    std::string algorithmName;
+    std::tie(pbcName, algorithmName) = GetParam();
+    t_pbc                                   pbc       = pbcs_.at(pbcName);
+
+    // Apply constraints
+    algorithms_.at(algorithmName)(testData.get(), pbc);
+
+    checkConstrainsLength(absoluteTolerance(0.0002), *testData, pbc);
+    checkConstrainsDirection(*testData, pbc);
+    checkCOMCoordinates(absoluteTolerance(0.0001), *testData);
+    checkCOMVelocity(absoluteTolerance(0.0001), *testData);
 
-    initSystem(54, c_cvwMasses,
-               c_cvwHAnglesConstraints, c_cvwHAnglesConstraintsR0, c_cvwHAnglesConstraintsFirstType,
-               epbcXYZ, c_cvwBox,
-               real(0.0), real(0.001), c_cvwInitialCoordinates);
-    applyConstraintsShake(0.0001, true);
-    checkConstrained(tolerance);
 }
 
-/*
- * All angles and all bonds are constrained by SHAKE. Only final lengths of constraints are tested.
- */
-/*TEST_F(ConstraintsTest, ShakeCysValTrpAllAngles)
-   {
-
-    FloatingPointTolerance tolerance            = relativeToleranceAsFloatingPoint(0.1, 0.001);
-
-    initSystem(54, c_cvwMasses,
-               c_cvwAllAnglesConstraints, c_cvwAllAnglesConstraintsR0, c_cvwAllAnglesConstraintsFirstType,
-               epbcXYZ, c_cvwBox,
-               real(0.0), real(0.001), c_cvwInitialCoordinates);
-    applyConstraintsShake(0.000001, true);
-    checkConstrained(tolerance);
-   }
- */
+
+INSTANTIATE_TEST_CASE_P(WithParameters, ConstraintsTest,
+                            ::testing::Combine(::testing::Values("PBCNone", "PBCXYZ"),
+                                                   ::testing::Values("SHAKE", "LINCS")));
+
 } // namespace test
 } // namespace gmx
diff --git a/src/gromacs/mdlib/tests/constrdata.h b/src/gromacs/mdlib/tests/constrdata.h
deleted file mode 100644 (file)
index 72c3576..0000000
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2018, 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 Data used by LINCS tests.
- *
- * \author Artem Zhmurov <zhmurov@gmail.com>
- * \ingroup module_mdlib
- */
-
-#include "gromacs/math/vectypes.h"
-
-namespace gmx
-{
-
-namespace test
-{
-
-//! A box with zero sides to check if PBC are actually disabled.
-static const matrix c_infinitesimalBox = { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} };
-
-/*
- * System of two connected atoms.
- */
-//! System of two connected atoms: one constraint (type, i, j).
-static const std::vector<int>  c_oneBondConstraints( {0, 0, 1} );
-//! System of two connected atoms: equilibrium distance.
-static const std::vector<real> c_oneBondConstraintsR0( {0.1} );
-//! System of two connected atoms: starting type id for constraints.
-static const int               c_oneBondConstraintsFirstType = 0;
-//! System of two connected atoms: coordinates.
-static const std::vector<RVec> c_oneBondCoordinates(
-        {{
-             {  0.10, -0.13,  0.05 },
-             { -0.13,  0.05, -0.10 }
-         }} );
-//! System of two connected atoms: masses.
-static const std::vector<real> c_oneBondMasses ( {1.0, 12.0} );
-
-/*
- * Two disjoint bonds (taken from the SHAKE test).
- */
-//! Two disjoint bonds: two constraint (type1, i1, j1, type2, i2, j2).
-static const std::vector<int>  c_twoDJBondsConstraints( {0, 0, 1, 1, 2, 3} );
-//! Two disjoint bonds: equilibrium distances.
-static const std::vector<real> c_twoDJBondsConstraintsR0( {2.0, 1.0} );
-//! Two disjoint bonds: starting type id for constraints.
-static const int               c_twoDJBondsConstraintsFirstType = 0;
-//! Two disjoint bonds: coordinates.
-static const std::vector<RVec> c_twoDJBondsCoordinates(
-        {{
-             {  2.50, -3.10, 15.70 },
-             {  0.51, -3.02, 15.55 },
-             { -0.50, -3.00, 15.20 },
-             { -1.51, -2.95, 15.05 }
-         }} );
-//! Two disjoint bonds: masses.
-static const std::vector<real> c_twoDJBondsMasses ( {0.5, 1.0/3.0, 0.25, 1.0} );
-
-
-/*
- * Three atoms, connected longitudaly.
- */
-//! Three atoms, connected longitudaly: two constraints (type1, i1, j1, type2, i2, j2).
-static const std::vector<int>  c_twoBondsConstraints( {0, 0, 1, 1, 1, 2} );
-//! Three atoms, connected longitudaly: two distances.
-static const std::vector<real> c_twoBondsConstraintsR0( {0.1, 0.2} );
-//! Three atoms, connected longitudaly: starting type id for constraints.
-static const int               c_twoBondsConstraintsFirstType = 0;
-//! Three atoms, connected longitudaly: coordinates.
-static const std::vector<RVec> c_twoBondsCoordinates(
-        {{
-             {  0.08, 0.05,  0.01 },
-             { -0.02, 0.03, -0.02 },
-             {  0.14, 0.02,  0.01 }
-         }} );
-//! Three atoms, connected longitudaly: masses.
-static const std::vector<real> c_twoBondsMasses ( {1.0, 12.0, 16.0 } );
-
-/*
- * Four atoms, connected longitudaly (taken from SHAKE test).
- */
-//! Four atoms, connected longitudaly: two constraints (type1, i1, j1, type2, i2, j2).
-static const std::vector<int>  c_threeBondsConstraints( {0, 0, 1, 1, 1, 2, 2, 2, 3} );
-//! Four atoms, connected longitudaly: two distances.
-static const std::vector<real> c_threeBondsConstraintsR0( {2.0, 1.0, 1.0} );
-//! Four atoms, connected longitudaly: starting type id for constraints.
-static const int               c_threeBondsConstraintsFirstType = 0;
-//! Four atoms, connected longitudaly: coordinates.
-static const std::vector<RVec> c_threeBondsCoordinates(
-        {{
-             {  2.50, -3.10, 15.70 },
-             {  0.51, -3.02, 15.55 },
-             { -0.50, -3.00, 15.20 },
-             { -1.51, -2.95, 15.05 }
-         }} );
-//! Four atoms, connected longitudaly: masses.
-static const std::vector<real> c_threeBondsMasses ( {0.5, 1.0/3.0, 0.25, 1.0} );
-
-/*
- * Basic triangle (tree atoms, connected with each other).
- */
-//! Basic triangle: three constraints (type1, i1, j1, type2, i2, j2, type3, i3, j3).
-static const std::vector<int>  c_triangleConstraints( {0, 0, 1, 2, 0, 2, 1, 1, 2} );
-//! Basic triangle: euilibrium distances.
-static const std::vector<real> c_triangleConstraintsR0( {0.1, 0.1, 0.1} );
-//! Basic triangle: starting type id for constraints.
-static const int               c_triangleConstraintsFirstType = 0;
-//! Basic triangle: coordinates.
-static const std::vector<RVec> c_triangleCoordinates(
-        {{
-             {  0.09, -0.02,  0.01 },
-             { -0.02,  0.10, -0.02 },
-             {  0.03, -0.01,  0.07 }
-         }} );
-//! Basic triangle: masses.
-static const std::vector<real> c_triangleMasses ( {1.0, 1.0, 1.0} );
-
-
-
-/*
- * Real-life system: Cys-Val-Trp peptide.
- */
-//! CVW peptide: periodic box.
-static const matrix c_cvwBox = {{real(2.570950), 0, 0}, {0, real(2.570950), 0}, {0, 0, real(2.570950)}};
-
-
-/*
- * Constraints only on covalent bonds with hydrogens.
- */
-//! CVW peptide: constraints on bonds with hydrogens (type1, i1, j1, type2, i2, j2,...).
-static const std::vector<int> c_cvwHBondsConstraints(
-        {465,  0,  1, 465,  0,  2, 465,  0,  3, 466,  4,  5, 467,  6,  7, 467,  6,  8, 468,  9, 10, 469, 13, 14,
-         466, 15, 16, 467, 17, 18, 467, 19, 20, 467, 19, 21, 467, 19, 22, 467, 23, 24, 467, 23, 25, 467, 23, 26,
-         469, 29, 30, 466, 31, 32, 467, 33, 34, 467, 33, 35, 466, 37, 38, 470, 39, 40, 466, 43, 44, 466, 45, 46,
-         466, 47, 48, 466, 49, 50} );
-//! CVW peptide: equilibrium distances (one for each type of HBond).
-static const std::vector<real> c_cvwHBondsConstraintsR0(
-        {0.104000, 0.108000, 0.111100, 0.132500, 0.099700, 0.097600} );
-//! CVW peptide: first type id used for constraints when HBonds are constrained.
-static const int c_cvwHBondsConstraintsFirstType = 465;
-
-
-/*
- *  Constraints on all covalent bonds.
- */
-//! CVW peptide: constraints on all bonds (type1, i1, j1, type2, i2, j2,...).
-static const std::vector<int> c_cvwAllBondsConstraints(
-        {447,  0,  1, 447,  0,  2, 447,  0,  3, 448,  0,  4, 449,  4,  5, 450,  4,  6, 451,  4, 11, 452,  6,  7,
-         452,  6,  8, 453,  6,  9, 454,  9, 10, 455, 11, 12, 456, 11, 13, 457, 13, 14, 458, 13, 15, 449, 15, 16,
-         459, 15, 17, 451, 15, 27, 452, 17, 18, 450, 17, 19, 450, 17, 23, 452, 19, 20, 452, 19, 21, 452, 19, 22,
-         452, 23, 24, 452, 23, 25, 452, 23, 26, 455, 27, 28, 456, 27, 29, 457, 29, 30, 458, 29, 31, 449, 31, 32,
-         450, 31, 33, 460, 31, 51, 452, 33, 34, 452, 33, 35, 461, 33, 36, 462, 36, 37, 463, 36, 42, 449, 37, 38,
-         464, 37, 39, 465, 39, 40, 466, 39, 41, 467, 41, 42, 468, 41, 47, 468, 42, 43, 449, 43, 44, 466, 43, 45,
-         449, 45, 46, 466, 45, 49, 449, 47, 48, 466, 47, 49, 449, 49, 50, 469, 51, 52, 469, 51, 53} );
-//! CVW peptide: equilibrium distances (one for each type of bond).
-static const std::vector<real> c_cvwAllBondsConstraintsR0(
-        {0.104000, 0.148000, 0.108000, 0.153800, 0.149000, 0.111100, 0.181800, 0.132500, 0.123000, 0.134500,
-         0.099700, 0.143000, 0.150000, 0.152200, 0.151000, 0.136500, 0.144000, 0.137000, 0.097600, 0.137500,
-         0.140000, 0.136800, 0.126000} );
-//! CVW peptide: first type id used for constraints when all bonds are constrained.
-static const int c_cvwAllBondsConstraintsFirstType = 447;
-
-
-/*
- *  Constraints on all covalent bonds and all angles with hydrogens.
- */
-//! CVW peptide: constraints on angles with hydrogens and all bonds (type1, i1, j1, type2, i2, j2,...).
-static const std::vector<int> c_cvwHAnglesConstraints(
-        {444,  1,  2, 444,  1,  3, 444,  2,  3, 445,  7,  8, 446, 20, 21, 446, 20, 22, 446, 21, 22, 446, 24, 25,
-         446, 24, 26, 446, 25, 26, 445, 34, 35, 447,  0,  1, 447,  0,  2, 447,  0,  3, 448,  0,  4, 449,  4,  5,
-         450,  4,  6, 451,  4, 11, 452,  6,  7, 452,  6,  8, 453,  6,  9, 454,  9, 10, 455, 11, 12, 456, 11, 13,
-         457, 13, 14, 458, 13, 15, 449, 15, 16, 459, 15, 17, 451, 15, 27, 452, 17, 18, 450, 17, 19, 450, 17, 23,
-         452, 19, 20, 452, 19, 21, 452, 19, 22, 452, 23, 24, 452, 23, 25, 452, 23, 26, 455, 27, 28, 456, 27, 29,
-         457, 29, 30, 458, 29, 31, 449, 31, 32, 450, 31, 33, 460, 31, 51, 452, 33, 34, 452, 33, 35, 461, 33, 36,
-         462, 36, 37, 463, 36, 42, 449, 37, 38, 464, 37, 39, 465, 39, 40, 466, 39, 41, 467, 41, 42, 468, 41, 47,
-         468, 42, 43, 449, 43, 44, 466, 43, 45, 449, 45, 46, 466, 45, 49, 449, 47, 48, 466, 47, 49, 449, 49, 50,
-         469, 51, 52, 469, 51, 53} );
-//! CVW peptide: equilibrium distances (one for each type of constraint).
-static const std::vector<real> c_cvwHAnglesConstraintsR0(
-        {0.169861, 0.180896, 0.180218, 0.104000, 0.148000, 0.108000, 0.153800, 0.149000, 0.111100, 0.181800,
-         0.132500, 0.123000, 0.134500, 0.099700, 0.143000, 0.150000, 0.152200, 0.151000, 0.136500, 0.144000,
-         0.137000, 0.097600, 0.137500, 0.140000, 0.136800, 0.126000} );
-//! CVW peptide: first type id used.
-static const int c_cvwHAnglesConstraintsFirstType = 444;
-
-// Constrain all bonds and angles.
-//! CVW peptide: constraints on all angles and all bonds (type1, i1, j1, type2, i2, j2,...).
-static const std::vector<int> c_cvwAllAnglesConstraints(
-        {402,  1,  2, 403, 52, 53, 404, 31, 53, 404, 31, 52, 405, 47, 50, 405, 45, 50, 406, 45, 47, 405, 48, 49,
-         407, 41, 49, 408, 41, 48, 405, 46, 49, 406, 43, 49, 405, 43, 46, 405, 44, 45, 407, 42, 45, 408, 42, 44,
-         409, 41, 43, 410, 36, 43, 411, 36, 41, 409, 42, 47, 412, 39, 47, 413, 39, 42, 414, 40, 41, 415, 37, 41,
-         416, 37, 40, 417, 38, 39, 418, 36, 39, 419, 36, 38, 420, 37, 42, 421, 33, 42, 422, 33, 37, 423, 35, 36,
-         423, 34, 36, 424, 34, 35, 425, 31, 36, 426, 31, 35, 426, 31, 34, 427, 33, 51, 428, 32, 51, 429, 32, 33,
-         430, 29, 51, 431, 29, 33, 432, 29, 32, 433, 30, 31, 434, 27, 31, 435, 27, 30, 436, 28, 29, 437, 15, 29,
-         438, 15, 28, 439, 25, 26, 439, 24, 26, 439, 24, 25, 426, 17, 26, 426, 17, 25, 426, 17, 24, 439, 21, 22,
-         439, 20, 22, 439, 20, 21, 426, 17, 22, 426, 17, 21, 426, 17, 20, 440, 19, 23, 441, 18, 23, 441, 18, 19,
-         442, 15, 23, 442, 15, 19, 443, 15, 18, 444, 17, 27, 445, 16, 27, 446, 16, 17, 447, 13, 27, 448, 13, 17,
-         432, 13, 16, 433, 14, 15, 434, 11, 15, 435, 11, 14, 436, 12, 13, 437,  4, 13, 438,  4, 12, 449,  6, 10,
-         450,  8,  9, 450,  7,  9, 424,  7,  8, 451,  4,  9, 426,  4,  8, 426,  4,  7, 452,  6, 11, 445,  5, 11,
-         429,  5,  6, 453,  0, 11, 454,  0,  6, 455,  0,  5, 456,  3,  4, 456,  2,  4, 402,  2,  3, 456,  1,  4,
-         402,  1,  3, 457,  0,  1, 457,  0,  2, 457,  0,  3, 458,  0,  4, 459,  4,  5, 460,  4,  6, 461,  4, 11,
-         462,  6,  7, 462,  6,  8, 463,  6,  9, 464,  9, 10, 465, 11, 12, 466, 11, 13, 467, 13, 14, 468, 13, 15,
-         459, 15, 16, 469, 15, 17, 461, 15, 27, 462, 17, 18, 460, 17, 19, 460, 17, 23, 462, 19, 20, 462, 19, 21,
-         462, 19, 22, 462, 23, 24, 462, 23, 25, 462, 23, 26, 465, 27, 28, 466, 27, 29, 467, 29, 30, 468, 29, 31,
-         459, 31, 32, 460, 31, 33, 470, 31, 51, 462, 33, 34, 462, 33, 35, 471, 33, 36, 472, 36, 37, 473, 36, 42,
-         459, 37, 38, 474, 37, 39, 475, 39, 40, 476, 39, 41, 477, 41, 42, 478, 41, 47, 478, 42, 43, 459, 43, 44,
-         476, 43, 45, 459, 45, 46, 476, 45, 49, 459, 47, 48, 476, 47, 49, 459, 49, 50, 479, 51, 52, 479, 51, 53} );
-//! CVW peptide: equilibrium distances (one for each type of constraint).
-static const std::vector<real> c_cvwAllAnglesConstraintsR0(
-        {0.169861, 0.222503, 0.238845, 0.213120, 0.238157, 0.235121, 0.214562, 0.242100, 0.255127, 0.228896,
-         0.249204, 0.223650, 0.210257, 0.222075, 0.209794, 0.217730, 0.224038, 0.217273, 0.226106, 0.260490,
-         0.259998, 0.215277, 0.180896, 0.255631, 0.218499, 0.247561, 0.214016, 0.217310, 0.237362, 0.248280,
-         0.204103, 0.208169, 0.240360, 0.206488, 0.225825, 0.241196, 0.237083, 0.180218, 0.257975, 0.218499,
-         0.246566, 0.215168, 0.241897, 0.211207, 0.213951, 0.234753, 0.245062, 0.234108, 0.245088, 0.279474,
-         0.244987, 0.243289, 0.247242, 0.207800, 0.207355, 0.104000, 0.148000, 0.108000, 0.153800, 0.149000,
-         0.111100, 0.181800, 0.132500, 0.123000, 0.134500, 0.099700, 0.143000, 0.150000, 0.152200, 0.151000,
-         0.136500, 0.144000, 0.137000, 0.097600, 0.137500, 0.140000, 0.136800, 0.126000} );
-//! CVW peptide: first type id used.
-static const int c_cvwAllAnglesConstraintsFirstType = 402;
-
-
-//! Coordinates of all 54 atoms of the Cys-Val-Trp system before constraints were applied
-static const std::vector<RVec> c_cvwInitialCoordinates(
-        {{
-             { 1.746000, 1.404000, 1.052000 },
-             { 1.806000, 1.450000, 0.979000 },
-             { 1.672000, 1.473000, 1.086000 },
-             { 1.814000, 1.368000, 1.123000 },
-             { 1.681000, 1.283000, 0.992000 },
-             { 1.612000, 1.309000, 0.913000 },
-             { 1.801000, 1.204000, 0.919000 },
-             { 1.772000, 1.100000, 0.896000 },
-             { 1.814000, 1.266000, 0.827000 },
-             { 1.974000, 1.193000, 0.998000 },
-             { 2.058000, 1.204000, 0.896000 },
-             { 1.594000, 1.204000, 1.095000 },
-             { 1.568000, 1.083000, 1.091000 },
-             { 1.533000, 1.270000, 1.201000 },
-             { 1.540000, 1.372000, 1.213000 },
-             { 1.458000, 1.206000, 1.310000 },
-             { 1.457000, 1.094000, 1.307000 },
-             { 1.532000, 1.230000, 1.433000 },
-             { 1.527000, 1.340000, 1.449000 },
-             { 1.478000, 1.148000, 1.544000 },
-             { 1.544000, 1.157000, 1.633000 },
-             { 1.378000, 1.176000, 1.581000 },
-             { 1.461000, 1.043000, 1.518000 },
-             { 1.685000, 1.181000, 1.411000 },
-             { 1.747000, 1.243000, 1.345000 },
-             { 1.730000, 1.190000, 1.515000 },
-             { 1.688000, 1.075000, 1.377000 },
-             { 1.312000, 1.253000, 1.324000 },
-             { 1.268000, 1.367000, 1.318000 },
-             { 1.224000, 1.149000, 1.344000 },
-             { 1.264000, 1.058000, 1.349000 },
-             { 1.095000, 1.170000, 1.405000 },
-             { 1.103000, 1.263000, 1.454000 },
-             { 0.975000, 1.166000, 1.297000 },
-             { 1.025000, 1.113000, 1.214000 },
-             { 0.887000, 1.110000, 1.333000 },
-             { 0.924000, 1.306000, 1.265000 },
-             { 0.952000, 1.386000, 1.165000 },
-             { 1.017000, 1.361000, 1.079000 },
-             { 0.882000, 1.507000, 1.174000 },
-             { 0.911000, 1.589000, 1.129000 },
-             { 0.819000, 1.515000, 1.296000 },
-             { 0.840000, 1.389000, 1.355000 },
-             { 0.777000, 1.364000, 1.480000 },
-             { 0.785000, 1.264000, 1.522000 },
-             { 0.698000, 1.458000, 1.538000 },
-             { 0.640000, 1.433000, 1.626000 },
-             { 0.746000, 1.617000, 1.350000 },
-             { 0.719000, 1.711000, 1.307000 },
-             { 0.682000, 1.582000, 1.472000 },
-             { 0.631000, 1.668000, 1.515000 },
-             { 1.070000, 1.060000, 1.508000 },
-             { 1.150000, 0.960000, 1.515000 },
-             { 0.966000, 1.066000, 1.569000 }
-         }});
-
-//! Coordinates of 54 atoms of the Cys-Val-Trp system after H-Bonds were constrained
-static const std::vector<RVec> c_cvwFinalCoordinatesHBonds(
-        {{
-             { 1.745950, 1.404137, 1.052042 },
-             { 1.805376, 1.449522, 0.979759 },
-             { 1.673804, 1.471318, 1.085171 },
-             { 1.813515, 1.368257, 1.122494 },
-             { 1.680997, 1.283001, 0.991996 },
-             { 1.612038, 1.308986, 0.913044 },
-             { 1.801019, 1.204075, 0.918974 },
-             { 1.771832, 1.099398, 0.895867 },
-             { 1.813938, 1.265703, 0.827441 },
-             { 1.974002, 1.193000, 0.997998 },
-             { 2.057943, 1.203992, 0.896070 },
-             { 1.594000, 1.204000, 1.095000 },
-             { 1.568000, 1.083000, 1.091000 },
-             { 1.533015, 1.270216, 1.201025 },
-             { 1.539794, 1.369004, 1.212648 },
-             { 1.457997, 1.205687, 1.309992 },
-             { 1.457033, 1.097730, 1.307100 },
-             { 1.531999, 1.230013, 1.433002 },
-             { 1.527007, 1.339845, 1.448977 },
-             { 1.478082, 1.148102, 1.544007 },
-             { 1.543998, 1.157000, 1.632997 },
-             { 1.377262, 1.176207, 1.581273 },
-             { 1.460769, 1.041573, 1.517647 },
-             { 1.685022, 1.180937, 1.411234 },
-             { 1.747673, 1.243673, 1.344284 },
-             { 1.729067, 1.189813, 1.512844 },
-             { 1.687993, 1.075258, 1.377083 },
-             { 1.312000, 1.253000, 1.324000 },
-             { 1.268000, 1.367000, 1.318000 },
-             { 1.223995, 1.149011, 1.343999 },
-             { 1.264064, 1.057854, 1.349008 },
-             { 1.094985, 1.169824, 1.404907 },
-             { 1.103180, 1.265097, 1.455105 },
-             { 0.975024, 1.166056, 1.297020 },
-             { 1.025283, 1.112700, 1.213531 },
-             { 0.886430, 1.109637, 1.333233 },
-             { 0.924000, 1.306000, 1.265000 },
-             { 0.952121, 1.385953, 1.164840 },
-             { 1.015558, 1.361555, 1.080908 },
-             { 0.882007, 1.507018, 1.173990 },
-             { 0.910909, 1.588743, 1.129141 },
-             { 0.819000, 1.515000, 1.296000 },
-             { 0.840000, 1.389000, 1.355000 },
-             { 0.777004, 1.363946, 1.480023 },
-             { 0.784949, 1.264642, 1.521730 },
-             { 0.697987, 1.457994, 1.538020 },
-             { 0.640158, 1.433068, 1.625761 },
-             { 0.746023, 1.616921, 1.350036 },
-             { 0.718729, 1.711945, 1.306568 },
-             { 0.681970, 1.582051, 1.472026 },
-             { 0.631363, 1.667388, 1.514694 },
-             { 1.070000, 1.060000, 1.508000 },
-             { 1.150000, 0.960000, 1.515000 },
-             { 0.966000, 1.066000, 1.569000 }
-         }});
-
-//! Coordinates of 54 atoms of the Cys-Val-Trp system after all bonds were constrained
-static const std::vector<RVec> c_cvwFinalCoordinatesAllBonds(
-        {{
-             { 1.744192, 1.400876, 1.050408 },
-             { 1.804620, 1.448942, 0.980679 },
-             { 1.674799, 1.470390, 1.084714 },
-             { 1.812763, 1.368655, 1.121708 },
-             { 1.683948, 1.276865, 0.996242 },
-             { 1.616170, 1.307429, 0.917774 },
-             { 1.803010, 1.207954, 0.927155 },
-             { 1.773417, 1.105083, 0.897124 },
-             { 1.813404, 1.263159, 0.831216 },
-             { 1.970550, 1.193223, 0.996389 },
-             { 2.057327, 1.203912, 0.896817 },
-             { 1.595071, 1.207624, 1.094104 },
-             { 1.568932, 1.087338, 1.091143 },
-             { 1.533602, 1.264980, 1.199359 },
-             { 1.539437, 1.363790, 1.212034 },
-             { 1.455744, 1.209606, 1.306025 },
-             { 1.457067, 1.101535, 1.307202 },
-             { 1.536585, 1.230178, 1.430802 },
-             { 1.527027, 1.339398, 1.448912 },
-             { 1.477277, 1.146856, 1.545698 },
-             { 1.544449, 1.157061, 1.633605 },
-             { 1.376383, 1.176453, 1.581598 },
-             { 1.460628, 1.040705, 1.517432 },
-             { 1.681448, 1.182094, 1.411715 },
-             { 1.746716, 1.242717, 1.345302 },
-             { 1.728696, 1.189739, 1.511987 },
-             { 1.687955, 1.076581, 1.377507 },
-             { 1.313454, 1.250569, 1.323999 },
-             { 1.268736, 1.365093, 1.318100 },
-             { 1.224082, 1.152044, 1.344591 },
-             { 1.262989, 1.060300, 1.348874 },
-             { 1.093660, 1.168520, 1.401086 },
-             { 1.102950, 1.262423, 1.453696 },
-             { 0.977797, 1.168815, 1.299821 },
-             { 1.024283, 1.113760, 1.215191 },
-             { 0.888605, 1.111021, 1.332343 },
-             { 0.921772, 1.305848, 1.269492 },
-             { 0.951364, 1.387941, 1.164422 },
-             { 1.015236, 1.361678, 1.081333 },
-             { 0.882251, 1.505804, 1.174960 },
-             { 0.910507, 1.587606, 1.129765 },
-             { 0.819059, 1.513487, 1.296914 },
-             { 0.840064, 1.387880, 1.355340 },
-             { 0.778667, 1.365803, 1.475722 },
-             { 0.784710, 1.267623, 1.520478 },
-             { 0.698397, 1.459946, 1.535866 },
-             { 0.641444, 1.433622, 1.623810 },
-             { 0.745363, 1.614637, 1.352384 },
-             { 0.719425, 1.709521, 1.307677 },
-             { 0.683959, 1.580100, 1.470510 },
-             { 0.632793, 1.664977, 1.513489 },
-             { 1.072860, 1.060117, 1.505945 },
-             { 1.149574, 0.960533, 1.514963 },
-             { 0.964441, 1.066090, 1.569914 }
-         }});
-
-//! Masses of atoms in the Cys-Val-Trp system
-static const std::vector<real> c_cvwMasses ( {
-                                                 14.007000,
-                                                 1.008000,
-                                                 1.008000,
-                                                 1.008000,
-                                                 12.011000,
-                                                 1.008000,
-                                                 12.011000,
-                                                 1.008000,
-                                                 1.008000,
-                                                 32.060001,
-                                                 1.008000,
-                                                 12.011000,
-                                                 15.999000,
-                                                 14.007000,
-                                                 1.008000,
-                                                 12.011000,
-                                                 1.008000,
-                                                 12.011000,
-                                                 1.008000,
-                                                 12.011000,
-                                                 1.008000,
-                                                 1.008000,
-                                                 1.008000,
-                                                 12.011000,
-                                                 1.008000,
-                                                 1.008000,
-                                                 1.008000,
-                                                 12.011000,
-                                                 15.999000,
-                                                 14.007000,
-                                                 1.008000,
-                                                 12.011000,
-                                                 1.008000,
-                                                 12.011000,
-                                                 1.008000,
-                                                 1.008000,
-                                                 12.011000,
-                                                 12.011000,
-                                                 1.008000,
-                                                 14.007000,
-                                                 1.008000,
-                                                 12.011000,
-                                                 12.011000,
-                                                 12.011000,
-                                                 1.008000,
-                                                 12.011000,
-                                                 1.008000,
-                                                 12.011000,
-                                                 1.008000,
-                                                 12.011000,
-                                                 1.008000,
-                                                 12.011000,
-                                                 15.999400,
-                                                 15.999400
-                                             } );
-
-
-}  // namespace test
-
-}  // namespace gmx