/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
* one- or two-part run.
*
* \todo This class has a similar interface with one in
- * mdcomparison.cpp, but not enough to warrant extracting an interface
+ * mdcomparison.h, but not enough to warrant extracting an interface
* class. Perhaps parts of this should be cast as a class that returns
* iterators to successive frames, so that the fancy footwork for
* pretending a two-part run is one sequence is separate from the
*
* \tparam FrameReader Has readNextFrame() and frame() methods
* useful for returning successive Frame objects */
-template <class FrameReader>
+template<class FrameReader>
class ContinuationFramePairManager
{
- public:
- //! Convenience typedef
- typedef std::unique_ptr<FrameReader> FrameReaderPtr;
- //! Constructor
- ContinuationFramePairManager(FrameReaderPtr full,
- FrameReaderPtr firstPart,
- FrameReaderPtr secondPart) :
- full_(std::move(full)),
- firstPart_(std::move(firstPart)),
- secondPart_(std::move(secondPart)),
- isFirstPart_(true)
- {}
- /*! \brief Probe for a pair of valid frames, and return true if both are found.
- *
- * Gives a test failure if exactly one frame is found, because
- * it is an error for either run to have missing or extra
- * frames. Note that the frame where the two-part run ends
- * and begins is duplicated between the two output files by
- * mdrun, and the test accommodates this.
- *
- * \todo This would be straightforward if velocity Verlet
- * behaved like other integrators. */
- bool shouldContinueComparing()
+public:
+ //! Convenience typedef
+ typedef std::unique_ptr<FrameReader> FrameReaderPtr;
+ //! Constructor
+ ContinuationFramePairManager(FrameReaderPtr full, FrameReaderPtr firstPart, FrameReaderPtr secondPart) :
+ full_(std::move(full)),
+ firstPart_(std::move(firstPart)),
+ secondPart_(std::move(secondPart)),
+ isFirstPart_(true)
+ {
+ }
+ /*! \brief Probe for a pair of valid frames, and return true if both are found.
+ *
+ * Gives a test failure if exactly one frame is found, because
+ * it is an error for either run to have missing or extra
+ * frames. Note that the frame where the two-part run ends
+ * and begins is duplicated between the two output files by
+ * mdrun, and the test accommodates this.
+ *
+ * \todo This would be straightforward if velocity Verlet
+ * behaved like other integrators. */
+ bool shouldContinueComparing()
+ {
+ if (full_->readNextFrame())
{
- if (full_->readNextFrame())
+ if (isFirstPart_)
{
- if (isFirstPart_)
+ if (firstPart_->readNextFrame())
{
- if (firstPart_->readNextFrame())
- {
- // Two valid next frames exist, so we should continue comparing.
- return true;
- }
- else
+ // Two valid next frames exist, so we should continue comparing.
+ return true;
+ }
+ else
+ {
+ // First part ran out of frames, move on to the second part
+ isFirstPart_ = false;
+ if (secondPart_->readNextFrame())
{
- // First part ran out of frames, move on to the second part
- isFirstPart_ = false;
+ // Skip a second-part frame so the one we will
+ // read can compare with the next full-run
+ // frames.
+ secondPart_->frame();
if (secondPart_->readNextFrame())
{
- // Skip a second-part frame so the one we will
- // read can compare with the next full-run
- // frames.
- secondPart_->frame();
- if (secondPart_->readNextFrame())
- {
- // Two valid next frames exist, so we should continue comparing.
- return true;
- }
- else
- {
- ADD_FAILURE() << "Second-part energy file had no (new) frames";
- }
+ // Two valid next frames exist, so we should continue comparing.
+ return true;
}
else
{
- ADD_FAILURE() << "Second-part energy file had no frames";
+ ADD_FAILURE() << "Second-part energy file had no (new) frames";
}
}
- }
- else
- {
- if (secondPart_->readNextFrame())
- {
- // Two valid next frames exist, so we should continue comparing.
- return true;
- }
else
{
- ADD_FAILURE() << "Full run energy file had at least one more frame than two-part run energy file";
+ ADD_FAILURE() << "Second-part energy file had no frames";
}
}
}
else
{
- if (isFirstPart_)
+ if (secondPart_->readNextFrame())
{
- ADD_FAILURE() << "Full-run energy file ran out of frames before the first part of the two-part run completed";
+ // Two valid next frames exist, so we should continue comparing.
+ return true;
}
else
{
- if (secondPart_->readNextFrame())
- {
- ADD_FAILURE() << "Two-part run energy file had at least one more frame than full-run energy file";
- }
- else
- {
- // Both files ran out of frames at the same time, which is the expected behaviour.
- }
+ ADD_FAILURE() << "Full run energy file had at least one more frame than "
+ "two-part run energy file";
}
}
- // At least one file is out of frames, so should not continue comparing.
- return false;
}
- /*! \brief Compare all possible pairs of frames using \c compareTwoFrames.
- *
- * \tparam Frame The type of frame used in the comparison (returned
- * by FrameReader and used by compareTwoFrames). */
- template <class Frame>
- void compareAllFramePairs(std::function<void(const Frame &, const Frame &)> compareTwoFrames)
+ else
{
- while (shouldContinueComparing())
+ if (isFirstPart_)
{
- Frame firstFrame = full_->frame();
- Frame secondFrame = isFirstPart_ ? firstPart_->frame() : secondPart_->frame();
- SCOPED_TRACE("Comparing frames from two runs '" + firstFrame.frameName() + "' and '" + secondFrame.frameName() + "'");
- compareTwoFrames(firstFrame, secondFrame);
+ ADD_FAILURE() << "Full-run energy file ran out of frames before the first part of "
+ "the two-part run completed";
}
-
+ else
+ {
+ if (secondPart_->readNextFrame())
+ {
+ ADD_FAILURE() << "Two-part run energy file had at least one more frame than "
+ "full-run energy 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;
+ }
+ /*! \brief Compare all possible pairs of frames using \c compareTwoFrames.
+ *
+ * \tparam Frame The type of frame used in the comparison (returned
+ * by FrameReader and used by compareTwoFrames). */
+ template<class Frame>
+ void compareAllFramePairs(std::function<void(const Frame&, const Frame&)> compareTwoFrames)
+ {
+ while (shouldContinueComparing())
+ {
+ EnergyFrame firstFrame = full_->frame();
+ EnergyFrame secondFrame = isFirstPart_ ? firstPart_->frame() : secondPart_->frame();
+ SCOPED_TRACE("Comparing frames from two runs '" + firstFrame.frameName() + "' and '"
+ + secondFrame.frameName() + "'");
+ compareTwoFrames(firstFrame, secondFrame);
}
+ }
- private:
- EnergyFrameReaderPtr full_;
- EnergyFrameReaderPtr firstPart_;
- EnergyFrameReaderPtr secondPart_;
- bool isFirstPart_;
+private:
+ EnergyFrameReaderPtr full_;
+ EnergyFrameReaderPtr firstPart_;
+ EnergyFrameReaderPtr secondPart_;
+ bool isFirstPart_;
};
/*! \brief Run grompp for a normal mdrun, the same mdrun stopping part
* way, doing a continuation, and compare the results. */
-void runTest(TestFileManager *fileManager,
- SimulationRunner *runner,
- const std::string &simulationName,
- int maxWarningsTolerated,
- const MdpFieldValues &mdpFieldValues,
- const EnergyTolerances &energiesToMatch)
+void runTest(TestFileManager* fileManager,
+ SimulationRunner* runner,
+ const std::string& simulationName,
+ int maxWarningsTolerated,
+ const MdpFieldValues& mdpFieldValues,
+ const EnergyTermsToCompare& energyTermsToCompare)
{
int numRanksAvailable = getNumberOfTestMpiRanks();
if (!isNumberOfPpRanksSupported(simulationName, numRanksAvailable))
{
- fprintf(stdout, "Test system '%s' cannot run with %d ranks.\n"
+ fprintf(stdout,
+ "Test system '%s' cannot run with %d ranks.\n"
"The supported numbers are: %s\n",
- simulationName.c_str(), numRanksAvailable,
+ simulationName.c_str(),
+ numRanksAvailable,
reportNumbersOfPpRanksSupported(simulationName).c_str());
return;
}
// prepare some names for files to use with the two mdrun calls
- std::string fullRunTprFileName = fileManager->getTemporaryFilePath("full.tpr");
- std::string firstPartRunTprFileName = fileManager->getTemporaryFilePath("firstpart.tpr");
- std::string fullRunEdrFileName = fileManager->getTemporaryFilePath("full.edr");
- std::string firstPartRunEdrFileName = fileManager->getTemporaryFilePath("firstpart.edr");
- std::string firstPartRunCheckpointFileName = fileManager->getTemporaryFilePath("firstpart.cpt");
- std::string secondPartRunEdrFileName = fileManager->getTemporaryFilePath("secondpart");
+ std::string fullRunTprFileName = fileManager->getTemporaryFilePath("full.tpr");
+ std::string firstPartRunTprFileName = fileManager->getTemporaryFilePath("firstpart.tpr");
+ std::string fullRunEdrFileName = fileManager->getTemporaryFilePath("full.edr");
+ std::string firstPartRunEdrFileName = fileManager->getTemporaryFilePath("firstpart.edr");
+ std::string firstPartRunCheckpointFileName = fileManager->getTemporaryFilePath("firstpart.cpt");
+ std::string secondPartRunEdrFileName = fileManager->getTemporaryFilePath("secondpart");
// prepare the full run .tpr file, which will be used for the full
// run, and for the second part of the two-part run.
EXPECT_EQ(0, runner->callGrompp(caller));
}
+ const std::string splitPoint = std::to_string(std::stoi(mdpFieldValues.at("nsteps")) / 2);
+
// prepare the .tpr file for the first part of the two-part run
{
// TODO evolve grompp to report the number of warnings issued, so
caller.append("grompp");
caller.addOption("-maxwarn", maxWarningsTolerated);
runner->useTopGroAndNdxFromDatabase(simulationName);
- auto firstPartMdpFieldValues = mdpFieldValues;
- firstPartMdpFieldValues["nsteps"] = "8";
+ auto firstPartMdpFieldValues = mdpFieldValues;
+ firstPartMdpFieldValues["nsteps"] = splitPoint;
runner->useStringAsMdpFile(prepareMdpFileContents(firstPartMdpFieldValues));
runner->tprFileName_ = firstPartRunTprFileName;
EXPECT_EQ(0, runner->callGrompp(caller));
runner->edrFileName_ = fullRunEdrFileName;
CommandLine fullRunCaller;
fullRunCaller.append("mdrun");
+ /* Force neighborlist update at the beginning of the second half of the trajectory.
+ * Doing so through CLI options prevents pairlist tuning from changing it. */
+ fullRunCaller.addOption("-nstlist", splitPoint);
ASSERT_EQ(0, runner->callMdrun(fullRunCaller));
}
secondPartRunEdrFileName += ".part0002.edr";
}
- // Build the functor that will compare reference and test
- // energy frames on the chosen energy fields.
- //
- // TODO It would be less code if we used a lambda for this, but either
- // clang 3.4 or libstdc++ 5.2.1 have an issue with capturing a
- // std::unordered_map
- EnergyComparator energyComparator(energiesToMatch);
+ // Build the functor that will compare energy frames on the chosen
+ // energy terms.
+ EnergyComparison energyComparison(energyTermsToCompare, MaxNumFrames::compareAllFrames());
+
// Build the manager that will present matching pairs of frames to compare.
//
- // TODO Here is an unnecessary copy of keys (ie. the energy field
+ // TODO Here is an unnecessary copy of keys (ie. the energy term
// names), for convenience. In the future, use a range.
- auto namesOfEnergiesToMatch = getKeys(energiesToMatch);
- ContinuationFramePairManager<EnergyFrameReader>
- energyManager(openEnergyFileToReadFields(fullRunEdrFileName, namesOfEnergiesToMatch),
- openEnergyFileToReadFields(firstPartRunEdrFileName, namesOfEnergiesToMatch),
- openEnergyFileToReadFields(secondPartRunEdrFileName, namesOfEnergiesToMatch));
+ auto namesOfEnergiesToMatch = energyComparison.getEnergyNames();
+ ContinuationFramePairManager<EnergyFrameReader> energyManager(
+ openEnergyFileToReadTerms(fullRunEdrFileName, namesOfEnergiesToMatch),
+ openEnergyFileToReadTerms(firstPartRunEdrFileName, namesOfEnergiesToMatch),
+ openEnergyFileToReadTerms(secondPartRunEdrFileName, namesOfEnergiesToMatch));
// Compare the energy frames.
- energyManager.compareAllFramePairs<EnergyFrame>(energyComparator);
+ energyManager.compareAllFramePairs<EnergyFrame>(energyComparison);
}
/*! \brief Test fixture for mdrun exact continuations
* without it?
*
* \todo Add FEP case. */
-class MdrunNoAppendContinuationIsExact : public MdrunTestFixture,
- public ::testing::WithParamInterface <
- std::tuple < std::string, std::string, std::string, std::string >>
+class MdrunNoAppendContinuationIsExact :
+ public MdrunTestFixture,
+ public ::testing::WithParamInterface<std::tuple<std::string, std::string, std::string, std::string, MdpParameterDatabase>>
{
- public:
- //! Constructor
- MdrunNoAppendContinuationIsExact() {}
+public:
+ //! Constructor
+ MdrunNoAppendContinuationIsExact() {}
};
/* Listing all of these is tedious, but there's no other way to get a
TEST_P(MdrunNoAppendContinuationIsExact, WithinTolerances)
{
- auto params = GetParam();
- auto simulationName = std::get<0>(params);
- auto integrator = std::get<1>(params);
- auto temperatureCoupling = std::get<2>(params);
- auto pressureCoupling = std::get<3>(params);
- SCOPED_TRACE(formatString("Comparing normal and two-part run of simulation '%s' "
- "with integrator '%s'",
- simulationName.c_str(), integrator.c_str()));
+ auto params = GetParam();
+ auto simulationName = std::get<0>(params);
+ auto integrator = std::get<1>(params);
+ auto temperatureCoupling = std::get<2>(params);
+ auto pressureCoupling = std::get<3>(params);
+ auto additionalMdpParameters = std::get<4>(params);
+
+ // Check for unimplemented functionality
+ // TODO: Update this as modular simulator gains functionality
+ const bool isModularSimulatorExplicitlyDisabled = (getenv("GMX_DISABLE_MODULAR_SIMULATOR") != nullptr);
+ const bool isTCouplingCompatibleWithModularSimulator =
+ (temperatureCoupling == "no" || temperatureCoupling == "v-rescale"
+ || temperatureCoupling == "berendsen");
+ // GPU update is not compatible with modular simulator
+ const bool isGpuUpdateRequested = (getenv("GMX_FORCE_UPDATE_DEFAULT_GPU") != nullptr);
+ if (integrator == "md-vv" && pressureCoupling == "parrinello-rahman"
+ && (isModularSimulatorExplicitlyDisabled || !isTCouplingCompatibleWithModularSimulator
+ || isGpuUpdateRequested))
+ {
+ // Under md-vv, Parrinello-Rahman is only implemented for the modular simulator
+ return;
+ }
+ if (integrator == "md-vv" && temperatureCoupling == "nose-hoover"
+ && pressureCoupling == "berendsen")
+ {
+ // This combination is not implemented in either legacy or modular simulator
+ return;
+ }
+
+ SCOPED_TRACE(
+ formatString("Comparing normal and two-part run of simulation '%s' "
+ "with integrator '%s'",
+ simulationName.c_str(),
+ integrator.c_str()));
auto mdpFieldValues = prepareMdpFieldValues(simulationName.c_str(),
integrator.c_str(),
temperatureCoupling.c_str(),
- pressureCoupling.c_str());
+ pressureCoupling.c_str(),
+ additionalMdpParameters);
// The exact lambda state choice is unimportant, so long as there
// is one when using an FEP input.
- mdpFieldValues["other"] += formatString("\ninit-lambda-state = %d", 3);
+ mdpFieldValues["init-lambda-state"] = "3";
+ mdpFieldValues["nsteps"] = "16";
- // Forces on GPUs are generally not reproducible enough for a tight
- // tolerance. Similarly, the propagation of sd and bd are not as
+ // Forces and update on GPUs are generally not reproducible enough for a tight
+ // tolerance. Similarly, the propagation of bd is not as
// reproducible as the others. So we use several ULP tolerance
// in all cases. This is looser than needed e.g. for md and md-vv
// with forces on CPUs, but there is no real risk of a bug with
// those propagators that would only be caught with a tighter
// tolerance in this particular test.
- EnergyTolerances energiesToMatch
- {{
- {
- interaction_function[F_EPOT].longname,
- relativeToleranceAsPrecisionDependentUlp(10.0, 32, 64)
- },
- }};
+ int ulpToleranceInMixed = 128;
+ int ulpToleranceInDouble = 64;
+ if (integrator == "bd")
+ {
+ // Somehow, the bd integrator has never been as reproducible
+ // as the others, either in continuations or reruns.
+ ulpToleranceInMixed = 200;
+ }
+ EnergyTermsToCompare energyTermsToCompare{
+ { { interaction_function[F_EPOT].longname,
+ relativeToleranceAsPrecisionDependentUlp(10.0, ulpToleranceInMixed, ulpToleranceInDouble) },
+ { interaction_function[F_EKIN].longname,
+ relativeToleranceAsPrecisionDependentUlp(10.0, ulpToleranceInMixed, ulpToleranceInDouble) } }
+ };
+
+ if (temperatureCoupling != "no" || pressureCoupling != "no")
+ {
+ if (simulationName == "alanine_vacuo")
+ {
+ // This is slightly less reproducible
+ energyTermsToCompare.insert({ interaction_function[F_ECONSERVED].longname,
+ relativeToleranceAsPrecisionDependentUlp(
+ 10.0, ulpToleranceInMixed * 2, ulpToleranceInDouble) });
+ }
+ else
+ {
+ energyTermsToCompare.insert({ interaction_function[F_ECONSERVED].longname,
+ relativeToleranceAsPrecisionDependentUlp(
+ 10.0, ulpToleranceInMixed, ulpToleranceInDouble) });
+ }
+ }
+
+ if (pressureCoupling == "parrinello-rahman")
+ {
+ energyTermsToCompare.insert({ "Box-Vel-XX",
+ relativeToleranceAsPrecisionDependentUlp(
+ 1e-12, ulpToleranceInMixed, ulpToleranceInDouble) });
+ energyTermsToCompare.insert({ "Box-Vel-YY",
+ relativeToleranceAsPrecisionDependentUlp(
+ 1e-12, ulpToleranceInMixed, ulpToleranceInDouble) });
+ energyTermsToCompare.insert({ "Box-Vel-ZZ",
+ relativeToleranceAsPrecisionDependentUlp(
+ 1e-12, ulpToleranceInMixed, ulpToleranceInDouble) });
+ }
int numWarningsToTolerate = 1;
- runTest(&fileManager_, &runner_,
- simulationName,
- numWarningsToTolerate, mdpFieldValues,
- energiesToMatch);
+ runTest(&fileManager_, &runner_, simulationName, numWarningsToTolerate, mdpFieldValues, energyTermsToCompare);
}
// TODO The time for OpenCL kernel compilation means these tests time
// out. Once that compilation is cached for the whole process, these
// tests can run in such configurations.
-#if GMX_GPU != GMX_GPU_OPENCL
-
-INSTANTIATE_TEST_CASE_P(NormalIntegrators, MdrunNoAppendContinuationIsExact,
- ::testing::Combine(::testing::Values("argon12", "spc2", "alanine_vsite_vacuo"),
- ::testing::Values("md", "md-vv", "bd", "sd"),
- ::testing::Values("no"),
- ::testing::Values("no")));
-
-INSTANTIATE_TEST_CASE_P(NormalIntegratorsWithFEP, MdrunNoAppendContinuationIsExact,
- ::testing::Combine(::testing::Values("nonanol_vacuo"),
- ::testing::Values("md", "md-vv", "bd", "sd"),
- ::testing::Values("no"),
- ::testing::Values("no")));
-
-INSTANTIATE_TEST_CASE_P(NormalNVT, MdrunNoAppendContinuationIsExact,
- ::testing::Combine(::testing::Values("argon12"),
- ::testing::Values("md", "md-vv"),
- ::testing::Values("berendsen", "v-rescale", "nose-hoover"),
- ::testing::Values("no")));
-
-INSTANTIATE_TEST_CASE_P(LeapfrogNPH, MdrunNoAppendContinuationIsExact,
- ::testing::Combine(::testing::Values("argon12"),
- ::testing::Values("md"),
- ::testing::Values("no"),
- ::testing::Values("berendsen", "parrinello-rahman")));
-
-INSTANTIATE_TEST_CASE_P(LeapfrogNPT, MdrunNoAppendContinuationIsExact,
- ::testing::Combine(::testing::Values("argon12"),
- ::testing::Values("md"),
- ::testing::Values("berendsen", "v-rescale", "nose-hoover"),
- ::testing::Values("berendsen", "parrinello-rahman")));
-
-INSTANTIATE_TEST_CASE_P(VelocityVerletNPH, MdrunNoAppendContinuationIsExact,
- ::testing::Combine(::testing::Values("argon12"),
- ::testing::Values("md-vv"),
- ::testing::Values("no"),
- ::testing::Values("berendsen")));
-
-INSTANTIATE_TEST_CASE_P(VelocityVerletNPT, MdrunNoAppendContinuationIsExact,
- ::testing::Combine(::testing::Values("argon12"),
- ::testing::Values("md-vv"),
- ::testing::Values("v-rescale"),
- ::testing::Values("berendsen")));
-
-INSTANTIATE_TEST_CASE_P(MTTK, MdrunNoAppendContinuationIsExact,
- ::testing::Combine(::testing::Values("argon12"),
- ::testing::Values("md-vv"),
- ::testing::Values("nose-hoover"),
- ::testing::Values("mttk")));
-
+#if !GMX_GPU_OPENCL
+
+INSTANTIATE_TEST_SUITE_P(
+ NormalIntegrators,
+ MdrunNoAppendContinuationIsExact,
+ ::testing::Combine(::testing::Values("argon12", "spc2", "alanine_vsite_vacuo"),
+ ::testing::Values("md", "md-vv", "bd", "sd"),
+ ::testing::Values("no"),
+ ::testing::Values("no"),
+ ::testing::Values(MdpParameterDatabase::Default)));
+
+INSTANTIATE_TEST_SUITE_P(NormalIntegratorsWithFEP,
+ MdrunNoAppendContinuationIsExact,
+ ::testing::Combine(::testing::Values("nonanol_vacuo"),
+ ::testing::Values("md", "md-vv", "bd", "sd"),
+ ::testing::Values("no"),
+ ::testing::Values("no"),
+ ::testing::Values(MdpParameterDatabase::Default)));
+
+INSTANTIATE_TEST_SUITE_P(
+ NVT,
+ MdrunNoAppendContinuationIsExact,
+ ::testing::Combine(::testing::Values("argon12"),
+ ::testing::Values("md", "md-vv"),
+ ::testing::Values("berendsen", "v-rescale", "nose-hoover"),
+ ::testing::Values("no"),
+ ::testing::Values(MdpParameterDatabase::Default)));
+
+INSTANTIATE_TEST_SUITE_P(
+ NPH,
+ MdrunNoAppendContinuationIsExact,
+ ::testing::Combine(::testing::Values("argon12"),
+ ::testing::Values("md", "md-vv"),
+ ::testing::Values("no"),
+ ::testing::Values("berendsen", "parrinello-rahman", "C-rescale"),
+ ::testing::Values(MdpParameterDatabase::Default)));
+
+INSTANTIATE_TEST_SUITE_P(
+ NPT,
+ MdrunNoAppendContinuationIsExact,
+ ::testing::Combine(::testing::Values("argon12"),
+ ::testing::Values("md", "md-vv"),
+ ::testing::Values("berendsen", "v-rescale", "nose-hoover"),
+ ::testing::Values("berendsen", "parrinello-rahman", "C-rescale"),
+ ::testing::Values(MdpParameterDatabase::Default)));
+
+INSTANTIATE_TEST_SUITE_P(MTTK,
+ MdrunNoAppendContinuationIsExact,
+ ::testing::Combine(::testing::Values("argon12"),
+ ::testing::Values("md-vv"),
+ ::testing::Values("nose-hoover"),
+ ::testing::Values("mttk"),
+ ::testing::Values(MdpParameterDatabase::Default)));
+
+INSTANTIATE_TEST_SUITE_P(Pull,
+ MdrunNoAppendContinuationIsExact,
+ ::testing::Combine(::testing::Values("spc2"),
+ ::testing::Values("md", "md-vv"),
+ ::testing::Values("no"),
+ ::testing::Values("no"),
+ ::testing::Values(MdpParameterDatabase::Pull)));
+
+INSTANTIATE_TEST_SUITE_P(Awh,
+ MdrunNoAppendContinuationIsExact,
+ ::testing::Combine(::testing::Values("alanine_vacuo"),
+ ::testing::Values("md", "md-vv"),
+ ::testing::Values("v-rescale"),
+ ::testing::Values("no"),
+ ::testing::Values(MdpParameterDatabase::Awh)));
+
+#else
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MdrunNoAppendContinuationIsExact);
#endif
} // namespace