Introduce the modular simulator
[gromacs.git] / src / programs / mdrun / tests / trajectorycomparison.cpp
blobde5ea639e14a5ee5a1cd47eab6ef8eda183bf7b5
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2016,2017,2018,2019, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
36 /*! \internal \file
37 * \brief Implemention of functions for comparing trajectories
38 * produced by mdrun.
40 * \author Mark Abraham <mark.j.abraham@gmail.com>
41 * \ingroup module_mdrun_integration_tests
43 #include "gmxpre.h"
45 #include "trajectorycomparison.h"
47 #include <gmock/gmock.h>
49 #include "gromacs/pbcutil/pbc.h"
50 #include "gromacs/trajectory/trajectoryframe.h"
52 #include "testutils/testasserts.h"
53 #include "testutils/testmatchers.h"
55 namespace gmx
57 namespace test
60 using ::testing::Pointwise;
62 /*! \brief Compares the box from \c reference and \c test
63 * according to the \c matchSettings and \c tolerance.
65 * \todo This could be streamlined when we have a proper 3D matrix
66 * class and view. */
67 static void compareBox(const TrajectoryFrame &reference,
68 const TrajectoryFrame &test,
69 const TrajectoryFrameMatchSettings &matchSettings,
70 const FloatingPointTolerance tolerance)
72 if (!matchSettings.mustCompareBox)
74 return;
76 bool canCompareBox = true;
77 if (!reference.hasBox())
79 ADD_FAILURE() << "Comparing the box was required, "
80 "but the reference frame did not have one";
81 canCompareBox = false;
83 if (!test.hasBox())
85 ADD_FAILURE() << "Comparing the box was required, "
86 "but the test frame did not have one";
87 canCompareBox = false;
89 if (!canCompareBox)
91 return;
94 // Do the comparing.
95 for (int d = 0; d < DIM; ++d)
97 for (int dd = 0; dd < DIM; ++dd)
99 EXPECT_REAL_EQ_TOL(reference.box()[d][dd], test.box()[d][dd], tolerance);
104 /*! \brief Help put all atom coordinates in \c frame into its box.
106 * This can perhaps go away when frame->x is a container. */
107 static std::vector<RVec>
108 putAtomsInBox(const TrajectoryFrame &frame)
110 std::vector<RVec> x(frame.x().begin(), frame.x().end());
111 matrix box;
112 for (int d = 0; d < DIM; ++d)
114 for (int dd = 0; dd < DIM; ++dd)
116 box[d][dd] = frame.box()[d][dd];
119 // Note we don't need to compare bPBC because put_atoms_in_box
120 // implements a fallback if nothing specific was set in the
121 // trajectory frame.
122 put_atoms_in_box(frame.pbc(), box, x);
123 return x;
126 /*! \brief Return whether the \c comparisonConditions and emptiness of
127 * reference and test frames means that a comparison should be
128 * attempted.
130 * This allows the framework to determine whether it is an error if a
131 * comparison cannot be made. */
132 static bool shouldDoComparison(const ComparisonConditions comparisonConditions,
133 const bool referenceIsEmpty,
134 const bool testIsEmpty)
136 if (comparisonConditions == ComparisonConditions::NoComparison)
138 return false;
141 bool doComparison = true;
142 if (testIsEmpty)
144 if (comparisonConditions == ComparisonConditions::MustCompare ||
145 comparisonConditions == ComparisonConditions::CompareIfBothFound ||
146 (!referenceIsEmpty &&
147 comparisonConditions == ComparisonConditions::CompareIfReferenceFound))
149 ADD_FAILURE() << "Test frame lacked quantitiy for required comparison";
151 doComparison = false;
153 if (referenceIsEmpty)
155 if (comparisonConditions == ComparisonConditions::MustCompare ||
156 comparisonConditions == ComparisonConditions::CompareIfBothFound ||
157 (!testIsEmpty &&
158 comparisonConditions == ComparisonConditions::CompareIfTestFound))
160 ADD_FAILURE() << "Reference frame lacked quantity for required comparison";
162 doComparison = false;
164 return doComparison;
167 /*! \brief Compares the position coordinates from \c reference and \c test
168 * according to the \c matchSettings and \c tolerance. */
169 static void compareCoordinates(const TrajectoryFrame &reference,
170 const TrajectoryFrame &test,
171 const TrajectoryFrameMatchSettings &matchSettings,
172 const FloatingPointTolerance tolerance)
174 SCOPED_TRACE("Comparing coordinates");
175 if (!shouldDoComparison(matchSettings.coordinatesComparison,
176 reference.x().empty(),
177 test.x().empty()))
179 return;
182 bool canHandlePbc = true;
183 if (!reference.hasBox())
185 ADD_FAILURE() << "Comparing positions required PBC handling, "
186 "but the reference frame did not have a box";
187 canHandlePbc = false;
189 if (!test.hasBox())
191 ADD_FAILURE() << "Comparing positions required PBC handling, "
192 "but the test frame did not have a box";
193 canHandlePbc = false;
196 if (matchSettings.requirePbcHandling && !canHandlePbc)
198 ADD_FAILURE() << "Cannot compare positions for the above reason(s)";
199 return;
202 if ((matchSettings.handlePbcIfPossible || matchSettings.requirePbcHandling) && canHandlePbc)
204 EXPECT_THAT(putAtomsInBox(test), Pointwise(RVecEq(tolerance), putAtomsInBox(reference)));
206 else
208 EXPECT_THAT(test.x(), Pointwise(RVecEq(tolerance), reference.x()));
212 /*! \brief Compares the velocities from \c reference and \c test
213 * according to the \c matchSettings and \c tolerance. */
214 static void compareVelocities(const TrajectoryFrame &reference,
215 const TrajectoryFrame &test,
216 const TrajectoryFrameMatchSettings &matchSettings,
217 const FloatingPointTolerance tolerance)
219 SCOPED_TRACE("Comparing velocities");
220 if (!shouldDoComparison(matchSettings.velocitiesComparison,
221 reference.v().empty(),
222 test.v().empty()))
224 return;
226 EXPECT_THAT(test.v(), Pointwise(RVecEq(tolerance), reference.v()));
229 /*! \brief Compares the forces from \c reference and \c test
230 * according to the \c matchSettings and \c tolerance. */
231 static void compareForces(const TrajectoryFrame &reference,
232 const TrajectoryFrame &test,
233 const TrajectoryFrameMatchSettings &matchSettings,
234 const FloatingPointTolerance tolerance)
236 SCOPED_TRACE("Comparing forces");
237 if (!shouldDoComparison(matchSettings.forcesComparison,
238 reference.f().empty(),
239 test.f().empty()))
241 return;
243 EXPECT_THAT(test.f(), Pointwise(RVecEq(tolerance), reference.f()));
247 const TrajectoryTolerances TrajectoryComparison::s_defaultTrajectoryTolerances {
248 defaultRealTolerance(), // box
249 relativeToleranceAsFloatingPoint(1.0, 1.0e-3), // positions
250 defaultRealTolerance(), // velocities
251 relativeToleranceAsFloatingPoint(100.0, GMX_DOUBLE ? 1.0e-7 : 5.0e-5) // forces
255 TrajectoryComparison::TrajectoryComparison(const TrajectoryFrameMatchSettings &matchSettings,
256 const TrajectoryTolerances &tolerances)
257 : matchSettings_(matchSettings),
258 tolerances_(tolerances)
262 void TrajectoryComparison::operator()(const TrajectoryFrame &reference,
263 const TrajectoryFrame &test) const
265 SCOPED_TRACE("Comparing trajectory reference frame " + reference.frameName() + " and test frame " + test.frameName());
266 EXPECT_EQ(reference.step(), test.step());
267 EXPECT_EQ(reference.time(), test.time());
268 compareBox(reference, test, matchSettings_, tolerances_.box);
269 compareCoordinates(reference, test, matchSettings_, tolerances_.coordinates);
270 compareVelocities(reference, test, matchSettings_, tolerances_.velocities);
271 compareForces(reference, test, matchSettings_, tolerances_.forces);
274 } // namespace test
275 } // namespace gmx