'limits', 'list', 'map', 'memory', 'mutex',
'new', 'numeric', 'ostream', 'random',
'regex', 'set', 'sstream', 'stdexcept', 'streambuf', 'string', 'strstream',
- 'thread', 'tuple', 'type_traits', 'typeindex', 'typeinfo', 'vector', 'utility']
+ 'thread', 'tuple', 'type_traits', 'typeindex', 'typeinfo', 'vector',
+ 'unordered_map', 'utility']
def __init__(self, style='pub-priv', absolute=False):
"""Initialize a sorted with the given style."""
bool hasBox() const;
//! Return a handle to the frame's box, which is all zero if the frame has no box.
const BoxMatrix &box() const;
- // TODO make this private when updating trajectory comparison code
+ private:
//! Handle to trajectory data
const t_trxframe &frame_;
- private:
//! Box matrix data from the frame_.
BoxMatrix box_;
};
gmx_add_gtest_executable(
${exename}
# files with code for tests
- tabulated_bonded_interactions.cpp
+ compressed_x_output.cpp
+ energycomparison.cpp
grompp.cpp
initialconstraints.cpp
+ interactiveMD.cpp
rerun.cpp
- trajectory_writing.cpp
- trajectoryreader.cpp
- compressed_x_output.cpp
swapcoords.cpp
- interactiveMD.cpp
+ tabulated_bonded_interactions.cpp
termination.cpp
tpitest.cpp
+ trajectory_writing.cpp
+ trajectorycomparison.cpp
+ trajectoryreader.cpp
# pseudo-library for code for testing mdrun
$<TARGET_OBJECTS:mdrun_test_objlib>
# pseudo-library for code for mdrun
gmx_add_gtest_executable(
${exename} MPI
# files with code for tests
+ domain_decomposition.cpp
multisim.cpp
multisimtest.cpp
replicaexchange.cpp
- domain_decomposition.cpp
# pseudo-library for code for testing mdrun
$<TARGET_OBJECTS:mdrun_test_objlib>
# pseudo-library for code for mdrun
--- /dev/null
+/*
+ * 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 Implementions of related classes for tests that want to
+ * inspect energies produced by mdrun.
+ *
+ * \author Mark Abraham <mark.j.abraham@gmail.com>
+ * \ingroup module_mdrun_integration_tests
+ */
+#include "gmxpre.h"
+
+#include "energycomparison.h"
+
+#include "gromacs/trajectory/energyframe.h"
+
+#include "testutils/testasserts.h"
+
+namespace gmx
+{
+namespace test
+{
+
+void compareEnergyFrames(const EnergyFrame &reference,
+ const EnergyFrame &test,
+ const EnergyTolerances &tolerances)
+{
+ for (auto referenceIt = reference.begin(); referenceIt != reference.end(); ++referenceIt)
+ {
+ auto &energyName = referenceIt->first;
+ SCOPED_TRACE("Comparing " + energyName + " between frames");
+ auto testIt = test.find(energyName);
+ if (testIt != test.end())
+ {
+ auto &energyValueInReference = referenceIt->second;
+ auto &energyValueInTest = testIt->second;
+ EXPECT_REAL_EQ_TOL(energyValueInReference, energyValueInTest, tolerances.at(energyName));
+ }
+ else
+ {
+ ADD_FAILURE() << "Could not find energy component from reference frame in test frame";
+ }
+ }
+}
+
+} // namespace
+} // namespace
--- /dev/null
+/*
+ * 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 Declares function for comparing energy frames.
+ *
+ * \author Mark Abraham <mark.j.abraham@gmail.com>
+ * \ingroup module_mdrun_integration_tests
+ */
+#ifndef GMX_PROGRAMS_MDRUN_TESTS_ENERGYCOMPARISON_H
+#define GMX_PROGRAMS_MDRUN_TESTS_ENERGYCOMPARISON_H
+
+#include <map>
+#include <string>
+
+#include "testutils/testasserts.h"
+
+namespace gmx
+{
+
+class EnergyFrame;
+
+namespace test
+{
+
+//! Convenience type
+using EnergyTolerances = std::map<std::string, FloatingPointTolerance>;
+
+/*! \brief Compare all fields of reference with all matching fields from test
+ *
+ * Ignore any key found in either \c reference or \c test that is not
+ * found in the other. For all keys found in both frames, compare the
+ * values with EXPECT_REAL_EQ_TOL and the given tolerance for that
+ * key. */
+void compareEnergyFrames(const EnergyFrame &reference,
+ const EnergyFrame &test,
+ const EnergyTolerances &tolerances);
+
+} // namespace
+} // namespace
+
+#endif
#include <string>
#include <vector>
+#include "gromacs/compat/make_unique.h"
#include "gromacs/fileio/enxio.h"
#include "gromacs/trajectory/energyframe.h"
#include "gromacs/utility/exceptions.h"
GMX_THROW(APIError(requiredEnergiesNotFound));
}
- return EnergyFrameReaderPtr(new EnergyFrameReader(indicesOfEnergyFields, energyFile.release()));
+ return EnergyFrameReaderPtr(compat::make_unique<EnergyFrameReader>(indicesOfEnergyFields,
+ energyFile.release()));
}
//! Helper function to obtain resources
return EnergyFrame(*enxframeGuard_.get(), indicesOfEnergyFields_);
}
-void compareFrames(const std::pair<EnergyFrame, EnergyFrame> &frames,
- FloatingPointTolerance tolerance)
-{
- auto &reference = frames.first;
- auto &test = frames.second;
-
- for (auto referenceIt = reference.begin(); referenceIt != reference.end(); ++referenceIt)
- {
- auto testIt = test.find(referenceIt->first);
- if (testIt != test.end())
- {
- auto energyFieldInReference = referenceIt->second;
- auto energyFieldInTest = testIt->second;
- EXPECT_REAL_EQ_TOL(energyFieldInReference, energyFieldInTest, tolerance)
- << referenceIt->first << " didn't match between reference run " << reference.frameName() << " and test run " << test.frameName();
- }
- }
-}
-
} // namespace
} // namespace
#include <cstdint>
-#include <map>
#include <memory>
#include <string>
+#include <unordered_map>
#include <vector>
#include "gromacs/fileio/enxio.h"
namespace test
{
+//! Convenience type
+using EnergyTolerances = std::unordered_map<std::string, FloatingPointTolerance>;
+
//! Forward declaration
class EnergyFrameReader;
//! Convenience smart pointer typedef
GMX_DISALLOW_COPY_AND_ASSIGN(EnergyFrameReader);
};
-/*! \brief Compare all fields of reference with all matching fields from test
- *
- * Ignore any key found in either \c reference or \c test that is not
- * found in the other. For all keys found in both frames, compare the
- * values with EXPECT_REAL_EQ_TOL and the given tolerance. */
-void compareFrames(const std::pair<EnergyFrame, EnergyFrame> &frames,
- FloatingPointTolerance tolerance);
-
} // namespace
} // namespace
std::string
prepareMdpFileContents(const MdpFieldValues &mdpFieldValues);
+/*! \internal
+ * \brief Manages returning a pair of frames from two
+ * equivalent simulations that are meaningful to compare. */
+template <class FrameReader, class Frame>
+class FramePairManager
+{
+ public:
+ //! Convenience typedef
+ typedef std::unique_ptr<FrameReader> FrameReaderPtr;
+ //! Constructor
+ FramePairManager(FrameReaderPtr first,
+ FrameReaderPtr second) :
+ first_(std::move(first)),
+ second_(std::move(second))
+ {}
+ private:
+ /*! \brief Probe for a pair of valid frames, and return true if both are found.
+ *
+ * Give a test failure if exactly one frame is found, because
+ * that file is longer than the other one, and this is not
+ * expected behaviour. */
+ bool shouldContinueComparing()
+ {
+ if (first_->readNextFrame())
+ {
+ if (second_->readNextFrame())
+ {
+ // Two valid next frames exist, so we should continue comparing.
+ return true;
+ }
+ else
+ {
+ ADD_FAILURE() << "first file had at least one more frame than second file";
+ }
+ }
+ else
+ {
+ if (second_->readNextFrame())
+ {
+ ADD_FAILURE() << "second file had at least one more frame than first file";
+ }
+ else
+ {
+ // Both files ran out of frames at the same time, which is the expected behaviour.
+ }
+ }
+ // At least one file is out of frames, so should not continue comparing.
+ return false;
+ }
+ public:
+ //! Compare all possible pairs of frames using \c compareTwoFrames.
+ void compareAllFramePairs(std::function<void(const Frame &, const Frame &)> compareTwoFrames)
+ {
+ while (shouldContinueComparing())
+ {
+ auto firstFrame = first_->frame();
+ auto secondFrame = second_->frame();
+ SCOPED_TRACE("Comparing frames from two runs '" + firstFrame.frameName() + "' and '" + secondFrame.frameName() + "'");
+ compareTwoFrames(firstFrame, secondFrame);
+ }
+
+ }
+ private:
+ FrameReaderPtr first_;
+ FrameReaderPtr second_;
+};
+
} // namespace test
} // namespace gmx
--- /dev/null
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016,2017,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 Implemention of functions for comparing trajectories
+ * produced by mdrun.
+ *
+ * \author Mark Abraham <mark.j.abraham@gmail.com>
+ * \ingroup module_mdrun_integration_tests
+ */
+#include "gmxpre.h"
+
+#include "trajectorycomparison.h"
+
+#include <gmock/gmock.h>
+
+#include "gromacs/pbcutil/pbc.h"
+#include "gromacs/trajectory/trajectoryframe.h"
+
+#include "testutils/testasserts.h"
+#include "testutils/testmatchers.h"
+
+namespace gmx
+{
+namespace test
+{
+
+using ::testing::Pointwise;
+
+/*! \brief Compares the box from \c reference and \c test
+ * according to the \c matchSettings and \c tolerance.
+ *
+ * \todo This could be streamlined when we have a proper 3D matrix
+ * class and view. */
+static void compareBox(const TrajectoryFrame &reference,
+ const TrajectoryFrame &test,
+ const TrajectoryFrameMatchSettings &matchSettings,
+ const FloatingPointTolerance tolerance)
+{
+ if (!matchSettings.mustCompareBox)
+ {
+ return;
+ }
+ bool canCompareBox = true;
+ if (!reference.hasBox())
+ {
+ ADD_FAILURE() << "Comparing the box was required, "
+ "but the reference frame did not have one";
+ canCompareBox = false;
+ }
+ if (!test.hasBox())
+ {
+ ADD_FAILURE() << "Comparing the box was required, "
+ "but the test frame did not have one";
+ canCompareBox = false;
+ }
+ if (!canCompareBox)
+ {
+ return;
+ }
+
+ // Do the comparing.
+ for (int d = 0; d < DIM; ++d)
+ {
+ for (int dd = 0; dd < DIM; ++dd)
+ {
+ EXPECT_REAL_EQ_TOL(reference.box()[d][dd], test.box()[d][dd], tolerance);
+ }
+ }
+}
+
+/*! \brief Help put all atom positions in \c frame into its box.
+ *
+ * This can perhaps go away when frame->x is a container. */
+static std::vector<RVec>
+putAtomsInBox(const TrajectoryFrame &frame)
+{
+ std::vector<RVec> x(frame.x().begin(), frame.x().end());
+ matrix box;
+ for (int d = 0; d < DIM; ++d)
+ {
+ for (int dd = 0; dd < DIM; ++dd)
+ {
+ box[d][dd] = frame.box()[d][dd];
+ }
+ }
+ // Note we don't need to compare bPBC because put_atoms_in_box
+ // implements a fallback if nothing specific was set in the
+ // trajectory frame.
+ put_atoms_in_box(frame.pbc(), box, x);
+ return x;
+}
+
+/*! \brief Compares the positions from \c reference and \c test
+ * according to the \c matchSettings and \c tolerance. */
+static void comparePositions(const TrajectoryFrame &reference,
+ const TrajectoryFrame &test,
+ const TrajectoryFrameMatchSettings &matchSettings,
+ const FloatingPointTolerance tolerance)
+{
+ bool canHandlePbc = true;
+ if (!reference.hasBox())
+ {
+ if (matchSettings.mustComparePositions)
+ {
+ ADD_FAILURE() << "Comparing positions required PBC handling, "
+ "but the reference frame did not have a box";
+ }
+ canHandlePbc = false;
+ }
+ if (!test.hasBox())
+ {
+ if (matchSettings.mustComparePositions)
+ {
+ ADD_FAILURE() << "Comparing positions required PBC handling, "
+ "but the test frame did not have a box";
+ }
+ canHandlePbc = false;
+ }
+
+ if (matchSettings.requirePbcHandling && !canHandlePbc)
+ {
+ ADD_FAILURE() << "Cannot compare positions for the above reason(s)";
+ return;
+ }
+
+ if ((matchSettings.handlePbcIfPossible || matchSettings.requirePbcHandling) && canHandlePbc)
+ {
+ EXPECT_THAT(putAtomsInBox(test), Pointwise(RVecEq(tolerance), putAtomsInBox(reference)));
+ }
+ else
+ {
+ EXPECT_THAT(test.x(), Pointwise(RVecEq(tolerance), reference.x()));
+ }
+}
+
+/*! \brief Compares the velocities from \c reference and \c test
+ * according to the \c matchSettings and \c tolerance. */
+static void compareVelocities(const TrajectoryFrame &reference,
+ const TrajectoryFrame &test,
+ const TrajectoryFrameMatchSettings &matchSettings,
+ const FloatingPointTolerance tolerance)
+{
+ if (!matchSettings.mustCompareVelocities)
+ {
+ return;
+ }
+ EXPECT_THAT(test.v(), Pointwise(RVecEq(tolerance), reference.v()));
+}
+
+/*! \brief Compares the forces from \c reference and \c test
+ * according to the \c matchSettings and \c tolerance. */
+static void compareForces(const TrajectoryFrame &reference,
+ const TrajectoryFrame &test,
+ const TrajectoryFrameMatchSettings &matchSettings,
+ const FloatingPointTolerance tolerance)
+{
+ if (!matchSettings.mustCompareForces)
+ {
+ return;
+ }
+ EXPECT_THAT(test.f(), Pointwise(RVecEq(tolerance), reference.f()));
+}
+
+
+void compareTrajectoryFrames(const TrajectoryFrame &reference,
+ const TrajectoryFrame &test,
+ const TrajectoryFrameMatchSettings &matchSettings,
+ const TrajectoryTolerances &tolerances)
+{
+ SCOPED_TRACE("Comparing reference frame " + reference.frameName() + " and test frame " + test.frameName());
+ EXPECT_EQ(reference.step(), test.step());
+ EXPECT_EQ(reference.time(), test.time());
+ compareBox(reference, test, matchSettings, tolerances.box);
+ comparePositions(reference, test, matchSettings, tolerances.positions);
+ compareVelocities(reference, test, matchSettings, tolerances.velocities);
+ compareForces(reference, test, matchSettings, tolerances.forces);
+}
+
+} // namespace
+} // namespace
--- /dev/null
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016,2017,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 Declares types and functions for comparing trajectories
+ * produced by mdrun.
+ *
+ * \author Mark Abraham <mark.j.abraham@gmail.com>
+ * \ingroup module_mdrun_integration_tests
+ */
+#ifndef GMX_PROGRAMS_MDRUN_TESTS_TRAJECTORYCOMPARISON_H
+#define GMX_PROGRAMS_MDRUN_TESTS_TRAJECTORYCOMPARISON_H
+
+#include "testutils/testasserts.h"
+
+namespace gmx
+{
+
+class TrajectoryFrame;
+
+namespace test
+{
+
+/*! \internal
+ * \brief Helper struct for testing different trajectory components with different tolerances. */
+struct TrajectoryTolerances
+{
+ /*!@{*/
+ /*! \brief Tolerances for reproduction of different quantities. */
+ FloatingPointTolerance box, positions, velocities, forces;
+ /*!@}*/
+};
+
+/*! \internal
+ * \brief Helper struct to specify the expected behaviour of compareFrames().
+ *
+ * By default, nothing is required to be compared, but the comparer will
+ * compare what it can with the frames it is given.
+ *
+ * Handling PBC refers to putting all the atoms in the simulation box,
+ * which requires that both the PBC type and a simulation box are
+ * available from the trajectory frame. */
+struct TrajectoryFrameMatchSettings
+{
+ //! Whether boxes must be compared.
+ bool mustCompareBox;
+ //! Whether positions must be compared.
+ bool mustComparePositions;
+ //! Whether PBC will be handled if it can be handled.
+ bool handlePbcIfPossible;
+ //! Whether PBC handling must occur for a valid comparison.
+ bool requirePbcHandling;
+ //! Whether velocities must be compared.
+ bool mustCompareVelocities;
+ //! Whether forces must be compared.
+ bool mustCompareForces;
+};
+
+/*! \brief Compare the fields of the two frames for equality given
+ * the \c matchSettings and \c tolerances.
+ *
+ * The two frames are required to have valid and matching values for
+ * time and step. According to \c matchSettings, box, positions,
+ * velocities and/or forces will be compared between frames, using the
+ * \c tolerances. Comparisons will only occur when both frames have
+ * the requisite data, and will be expected to be equal within the
+ * matching component of \c tolerances. If a comparison fails, a
+ * GoogleTest expectation failure will be given. If a comparison is
+ * required by \c matchSettings but cannot be done because either (or
+ * both) frames lack the requisite data, descriptive expectation
+ * failures will be given. */
+void compareTrajectoryFrames(const TrajectoryFrame &reference,
+ const TrajectoryFrame &test,
+ const TrajectoryFrameMatchSettings &matchSettings,
+ const TrajectoryTolerances &tolerances);
+
+} // namespace
+} // namespace
+
+#endif
#include "gromacs/fileio/trxio.h"
#include "gromacs/trajectory/trajectoryframe.h"
#include "gromacs/utility/exceptions.h"
-#include "gromacs/utility/stringutil.h"
#include "testutils/testasserts.h"
+#include "testutils/testmatchers.h"
namespace gmx
{
sfree(fr);
}
-// === TrajectoryFrameReader ===
-
TrajectoryFrameReader::TrajectoryFrameReader(const std::string &filename)
: filename_(filename),
trajectoryFileGuard_(nullptr),
}
if (!nextFrameExists_)
{
- GMX_THROW(APIError("There is no next frame, so there should have been no attempt to use the data, e.g. by reacting to a call to readNextFrame()."));
+ GMX_THROW(APIError("There is no next frame, so there should have been no attempt to get it. Perhaps the return value of readNextFrame() was misused."));
}
// Prepare for reading future frames
return TrajectoryFrame(*trxframeGuard_.get());
}
-void compareFrames(const std::pair<TrajectoryFrame, TrajectoryFrame> &frames,
- FloatingPointTolerance tolerance)
-{
- auto &reference = frames.first;
- auto &test = frames.second;
-
- // NB We checked earlier for both frames that bStep and bTime are set
-
- EXPECT_EQ(reference.frame_.step, test.frame_.step)
- << "step didn't match between reference run " << reference.frameName() << " and test run " << test.frameName();
-
- EXPECT_EQ(reference.frame_.time, test.frame_.time)
- << "time didn't match between reference run " << reference.frameName() << " and test run " << test.frameName();
-
- for (int i = 0; i < reference.frame_.natoms && i < test.frame_.natoms; ++i)
- {
- for (int d = 0; d < DIM; ++d)
- {
- if (reference.frame_.bX && test.frame_.bX)
- {
- EXPECT_REAL_EQ_TOL(reference.frame_.x[i][d], test.frame_.x[i][d], tolerance)
- << " x[" << i << "][" << d <<"] didn't match between reference run " << reference.frameName() << " and test run " << test.frameName();
- }
- if (reference.frame_.bV && test.frame_.bV)
- {
- EXPECT_REAL_EQ_TOL(reference.frame_.v[i][d], test.frame_.v[i][d], tolerance)
- << " v[" << i << "][" << d <<"] didn't match between reference run " << reference.frameName() << " and test run " << test.frameName();
- }
- if (reference.frame_.bF && test.frame_.bF)
- {
- EXPECT_REAL_EQ_TOL(reference.frame_.f[i][d], test.frame_.f[i][d], tolerance)
- << " f[" << i << "][" << d <<"] didn't match between reference run " << reference.frameName() << " and test run " << test.frameName();
- }
- }
- }
-}
-
} // namespace
} // namespace
* trajectories produced by mdrun.
*
* Intended usage is to create a TrajectoryFrameReader. Successive
- * calls to its TrajectoryFrameReader::readNextFrame() and
- * TrajectoryFrameReader::frame() methods will return a handle to a
- * t_trxframe object for each frame.
+ * calls to its readNextFrameStub and frame methods will return a handle
+ * to a t_trxframe object for each frame.
*
* \author Mark Abraham <mark.j.abraham@gmail.com>
* \ingroup module_mdrun_integration_tests
#include "gromacs/fileio/oenv.h"
#include "gromacs/fileio/trxio.h"
#include "gromacs/trajectory/trajectoryframe.h"
+#include "gromacs/utility/classhelpers.h"
#include "gromacs/utility/unique_cptr.h"
-#include "testutils/testasserts.h"
-
-//! Forward declaration
-struct gmx_output_env_t;
-
namespace gmx
{
* API, which does the file opening as a side effect of
* reading the first frame.
*
- * If true is returned, then frame() should be called
+ * If true is returned, then TrajectoryFrame frame() should be called
* to get access to the data. If false is returned, then no
* further data exists and no further call to
- * readNextFrame() or frame() should occur.
+ * readNextFrameStub or TrajectoryFrame frame() should occur.
*
* \throws FileIOError upon reading the first frame, if the trajectory file cannot be opened
* \throws APIError if an earlier probe has not been properly handled
*
* If the next frame has not been probed for, then probe for
* it. If no next frame exists, then throw APIError, because
- * user code should have called readNextFrame() itself if this
+ * user code should have called readNextFrameStub itself if this
* is possible. (This permits user code to avoid making calls
- * to readNextFrame() in a case where it already knows that
+ * to readNextFrameStub in a case where it already knows that
* the frame exists.)
*
* \throws APIError if no next frame exists, or if it lacks either time or step number. */
//! Convenience smart pointer typedef
typedef std::unique_ptr<TrajectoryFrameReader> TrajectoryFrameReaderPtr;
-/*! \brief Compare the fields of the two frames for equality within
- * the \c tolerance.
- *
- * The two frames are required to have valid and matching values for
- * time and step. Positions, velocities and/or forces will be compared
- * when present in both frames, and expected to be equal within \c
- * tolerance. */
-void compareFrames(const std::pair<TrajectoryFrame, TrajectoryFrame> &frames,
- FloatingPointTolerance tolerance);
-
} // namespace
} // namespace
#
# This file is part of the GROMACS molecular simulation package.
#
-# Copyright (c) 2011,2012,2013,2014,2015,2016,2017, by the GROMACS development team, led by
+# Copyright (c) 2011,2012,2013,2014,2015,2016,2017,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.
testfilemanager.cpp
testfileredirector.cpp
testinit.cpp
+ testmatchers.cpp
testoptions.cpp
textblockmatchers.cpp
xvgtest.cpp
--- /dev/null
+/*
+ * 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 Implements floating-point matchers from testmatchers.h for
+ * use with Google Mock.
+ *
+ * \author Mark Abraham <mark.j.abraham@gmail.com>
+ * \ingroup module_testutils
+ */
+#include "gmxpre.h"
+
+#include "testmatchers.h"
+
+#include <memory>
+
+#include <gmock/gmock.h>
+
+#include "testutils/testasserts.h"
+
+namespace gmx
+{
+namespace test
+{
+
+/*! \brief Implementation class for RealEq matcher.
+ *
+ * See RealEq().
+ *
+ * The implementation is templated so that we can support all of real,
+ * float and double in the same build without duplication.
+ */
+template <typename FloatType>
+class FloatTypeMatcher : public testing::MatcherInterface < std::tuple < FloatType, FloatType>>
+{
+ public:
+ //! Constructor
+ FloatTypeMatcher(const FloatingPointTolerance &tolerance)
+ : tolerance_(tolerance) {}
+ //! Compare the two elements of \c arg, return whether they are equal, and comment on \c listener when they are not.
+ virtual bool MatchAndExplain(std::tuple<FloatType, FloatType> arg,
+ testing::MatchResultListener* listener) const
+ {
+ const FloatType &value1 = std::get<0>(arg);
+ const FloatType &value2 = std::get<1>(arg);
+ FloatingPointDifference diff(value1, value2);
+ if (tolerance_.isWithin(diff))
+ {
+ return true;
+ }
+ *listener->stream()
+ << " Actual value: " << value2 << std::endl
+ << "Expected value: " << value1 << std::endl
+ << " Difference: " << diff.toString() << std::endl
+ << " Tolerance: " << tolerance_.toString(diff);
+ return false;
+ }
+ //! Describe to a human what matching means.
+ virtual void DescribeTo(::std::ostream* os) const
+ {
+ *os << "matches within tolerance";
+ }
+ //! Describe to a human what failing to match means.
+ virtual void DescribeNegationTo(::std::ostream* os) const
+ {
+ *os << "does not match within tolerance";
+ }
+ private:
+ //! Tolerance used in matching
+ FloatingPointTolerance tolerance_;
+};
+
+testing::Matcher < std::tuple < float, float>>
+FloatEq(const FloatingPointTolerance &tolerance)
+{
+ return testing::MakeMatcher(new FloatTypeMatcher<float>(tolerance));
+}
+
+testing::Matcher < std::tuple < double, double>>
+DoubleEq(const FloatingPointTolerance &tolerance)
+{
+ return testing::MakeMatcher(new FloatTypeMatcher<double>(tolerance));
+}
+
+testing::Matcher < std::tuple < real, real>>
+RealEq(const FloatingPointTolerance &tolerance)
+{
+ return testing::MakeMatcher(new FloatTypeMatcher<real>(tolerance));
+}
+
+/*! \brief Implementation class for RvecEq matcher
+ *
+ * See RvecEq().
+ */
+template <typename FloatType>
+class RVecMatcher :
+ public testing::MatcherInterface < std::tuple < BasicVector<FloatType>, BasicVector<FloatType>>>
+{
+ public:
+ //! Convenience type
+ using VectorType = BasicVector<FloatType>;
+ //! Constructor
+ RVecMatcher(const FloatingPointTolerance &tolerance)
+ : tolerance_(tolerance) {}
+ //! Compare the two elements of \c arg, return whether they are equal, and comment on \c listener when they are not.
+ virtual bool MatchAndExplain(std::tuple<VectorType, VectorType> arg,
+ testing::MatchResultListener* listener) const
+ {
+ const VectorType &lhs = std::get<0>(arg);
+ const VectorType &rhs = std::get<1>(arg);
+ FloatTypeMatcher<FloatType> floatTypeMatcher(tolerance_);
+ bool matches = true;
+ for (int d = 0; d < DIM; ++d)
+ {
+ auto floatTuple = std::make_tuple<FloatType, FloatType>(lhs[d], rhs[d]);
+ matches = matches && floatTypeMatcher.MatchAndExplain(floatTuple, listener);
+ }
+ return matches;
+ }
+ //! Describe to a human what matching means.
+ virtual void DescribeTo(::std::ostream* os) const
+ {
+ *os << "matches all elements within tolerance";
+ }
+ //! Describe to a human what failing to match means.
+ virtual void DescribeNegationTo(::std::ostream* os) const
+ {
+ *os << "does not match all elements within tolerance";
+ }
+ private:
+ //! Tolerance used in matching
+ FloatingPointTolerance tolerance_;
+};
+
+// Currently there's no need for explicit float or double flavours of
+// RVec comparison, but those would be simple to add later.
+testing::Matcher < std::tuple < RVec, RVec>>
+RVecEq(const FloatingPointTolerance &tolerance)
+{
+ return testing::MakeMatcher(new RVecMatcher<real>(tolerance));
+}
+
+} // namespace
+} // namespace
--- /dev/null
+/*
+ * 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.
+ */
+
+/*! \libinternal \file
+ * \brief Extra GoogleMock matchers for unit tests.
+ *
+ * This file provides the usual kind of GoogleMock matchers that
+ * extend the usefulness of GoogleMock EXPECT_THAT constructs to the
+ * kinds of containers of reals commonly used. This means that test
+ * code can write one-liners rather than loops over whole containers.
+ *
+ * \author Mark Abraham <mark.j.abraham@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_testutils
+ */
+#ifndef GMX_TESTUTILS_TESTMATCHERS_H
+#define GMX_TESTUTILS_TESTMATCHERS_H
+
+#include <memory>
+
+#include <gmock/gmock.h>
+
+#include "gromacs/math/vectypes.h"
+#include "gromacs/utility/real.h"
+
+#include "testutils/testasserts.h"
+
+namespace gmx
+{
+namespace test
+{
+
+/*! \brief Make matcher for floats for use with GoogleMock that compare
+ * equal when \c tolerance is satisifed.
+ *
+ * Used like
+ *
+ * EXPECT_THAT(testFloats, Pointwise(FloatEq(tolerance), referenceFloats));
+ */
+testing::Matcher < std::tuple < float, float>>
+FloatEq(const FloatingPointTolerance &tolerance);
+
+/*! \brief Make matcher for doubles for use with GoogleMock that compare
+ * equal when \c tolerance is satisifed.
+ *
+ * Used like
+ *
+ * EXPECT_THAT(testDoubles, Pointwise(DoubleEq(tolerance), referenceDoubles));
+ */
+testing::Matcher < std::tuple < double, double>>
+DoubleEq(const FloatingPointTolerance &tolerance);
+
+/*! \brief Make matcher for reals for use with GoogleMock that compare
+ * equal when \c tolerance is satisifed.
+ *
+ * Used like
+ *
+ * EXPECT_THAT(testReals, Pointwise(RealEq(tolerance), referenceReals));
+ */
+testing::Matcher < std::tuple < real, real>>
+RealEq(const FloatingPointTolerance &tolerance);
+
+/*! \brief Make matcher for RVecs for use with GoogleMock that compare
+ * equal when \c tolerance is satisifed.
+ *
+ * Used like
+ *
+ * EXPECT_THAT(testRVecs, Pointwise(RVecEq(tolerance), referenceRVecs));
+ */
+testing::Matcher < std::tuple < RVec, RVec>>
+RVecEq(const FloatingPointTolerance &tolerance);
+
+} // namespace
+} // namespace
+
+#endif