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.
37 * \brief Implemention of functions for comparing trajectories
40 * \author Mark Abraham <mark.j.abraham@gmail.com>
41 * \ingroup module_mdrun_integration_tests
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"
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
67 static void compareBox(const TrajectoryFrame
&reference
,
68 const TrajectoryFrame
&test
,
69 const TrajectoryFrameMatchSettings
&matchSettings
,
70 const FloatingPointTolerance tolerance
)
72 if (!matchSettings
.mustCompareBox
)
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;
85 ADD_FAILURE() << "Comparing the box was required, "
86 "but the test frame did not have one";
87 canCompareBox
= false;
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());
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
122 put_atoms_in_box(frame
.pbc(), box
, x
);
126 /*! \brief Return whether the \c comparisonConditions and emptiness of
127 * reference and test frames means that a comparison should be
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
)
141 bool doComparison
= true;
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
||
158 comparisonConditions
== ComparisonConditions::CompareIfTestFound
))
160 ADD_FAILURE() << "Reference frame lacked quantity for required comparison";
162 doComparison
= false;
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(),
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;
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)";
202 if ((matchSettings
.handlePbcIfPossible
|| matchSettings
.requirePbcHandling
) && canHandlePbc
)
204 EXPECT_THAT(putAtomsInBox(test
), Pointwise(RVecEq(tolerance
), putAtomsInBox(reference
)));
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(),
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(),
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
);