/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2016,2017,2018, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,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.
*/
#include "gmxpre.h"
-#include "config.h"
-
#include <map>
#include <string>
#include <vector>
#include <gtest/gtest-spi.h>
-#include "gromacs/gpu_utils/gpu_utils.h"
-#include "gromacs/hardware/gpu_hw_info.h"
+#include "gromacs/ewald/pme.h"
+#include "gromacs/hardware/detecthardware.h"
+#include "gromacs/hardware/device_management.h"
+#include "gromacs/hardware/hw_info.h"
+#include "gromacs/trajectory/energyframe.h"
+#include "gromacs/utility/basenetwork.h"
#include "gromacs/utility/cstringutil.h"
#include "gromacs/utility/gmxmpi.h"
+#include "gromacs/utility/physicalnodecommunicator.h"
#include "gromacs/utility/stringutil.h"
#include "testutils/mpitest.h"
* \todo Consider also using GpuTest class. */
class PmeTest : public MdrunTestFixture
{
- public:
- //! Before any test is run, work out whether any compatible GPUs exist.
- static void SetUpTestCase();
- //! Store whether any compatible GPUs exist.
- static bool s_hasCompatibleCudaGpus;
- //! Convenience typedef
- using RunModesList = std::map < std::string, std::vector < const char *>>;
- //! Runs the test with the given inputs
- void runTest(const RunModesList &runModes);
+public:
+ //! Convenience typedef
+ using RunModesList = std::map<std::string, std::vector<const char*>>;
+ //! Runs the test with the given inputs
+ void runTest(const RunModesList& runModes);
};
-bool PmeTest::s_hasCompatibleCudaGpus = false;
-
-void PmeTest::SetUpTestCase()
-{
- gmx_gpu_info_t gpuInfo {};
- // It would be nicer to do this detection once and have mdrun
- // re-use it, but this is OK. Note that this also caters for when
- // there is no GPU support in the build.
- //
- // TODO report any error messages gracefully.
- if (GMX_GPU == GMX_GPU_CUDA &&
- canDetectGpus(nullptr))
- {
- findGpus(&gpuInfo);
- s_hasCompatibleCudaGpus = (gpuInfo.n_dev_compatible > 0);
- }
- free_gpu_info(&gpuInfo);
-}
-
-void PmeTest::runTest(const RunModesList &runModes)
+void PmeTest::runTest(const RunModesList& runModes)
{
const std::string inputFile = "spc-and-methanol";
- runner_.useTopGroAndNdxFromDatabase(inputFile.c_str());
+ runner_.useTopGroAndNdxFromDatabase(inputFile);
// With single rank we can and will always test PP+PME as part of mdrun-test.
// With multiple ranks we can additionally test a single PME-only rank within mdrun-mpi-test.
{
EXPECT_NONFATAL_FAILURE(rootChecker.checkUnusedEntries(), ""); // skip checks on other ranks
}
- for (const auto &mode : runModes)
+
+ auto hardwareInfo_ =
+ gmx_detect_hardware(PhysicalNodeCommunicator(MPI_COMM_WORLD, gmx_physicalnode_id_hash()));
+
+ for (const auto& mode : runModes)
{
+ SCOPED_TRACE("mdrun " + joinStrings(mode.second, " "));
auto modeTargetsGpus = (mode.first.find("Gpu") != std::string::npos);
- if (modeTargetsGpus && !s_hasCompatibleCudaGpus)
+ if (modeTargetsGpus && getCompatibleDevices(hardwareInfo_->deviceInfoList).empty())
{
// This run mode will cause a fatal error from mdrun when
// it can't find GPUs, which is not something we're trying
// to test here.
continue;
}
+ auto modeTargetsPmeOnGpus = (mode.first.find("PmeOnGpu") != std::string::npos);
+ if (modeTargetsPmeOnGpus
+ && !(pme_gpu_supports_build(nullptr) && pme_gpu_supports_hardware(*hardwareInfo_, nullptr)))
+ {
+ // This run mode will cause a fatal error from mdrun when
+ // it finds an unsuitable device, which is not something
+ // we're trying to test here.
+ continue;
+ }
- runner_.edrFileName_ = fileManager_.getTemporaryFilePath(inputFile + "_" + mode.first + ".edr");
+ runner_.edrFileName_ =
+ fileManager_.getTemporaryFilePath(inputFile + "_" + mode.first + ".edr");
CommandLine commandLine(mode.second);
- const bool usePmeTuning = (mode.first.find("Tune") != std::string::npos);
+ const bool usePmeTuning = (mode.first.find("Tune") != std::string::npos);
if (usePmeTuning)
{
commandLine.append("-tunepme");
if (thisRankChecks)
{
- auto energyReader = openEnergyFileToReadFields(runner_.edrFileName_, {"Coul. recip.", "Total Energy", "Kinetic En."});
+ auto energyReader = openEnergyFileToReadTerms(
+ runner_.edrFileName_, { "Coul. recip.", "Total Energy", "Kinetic En." });
auto conservedChecker = rootChecker.checkCompound("Energy", "Conserved");
auto reciprocalChecker = rootChecker.checkCompound("Energy", "Reciprocal");
bool firstIteration = true;
while (energyReader->readNextFrame())
{
- const EnergyFrame &frame = energyReader->frame();
- const std::string stepName = frame.getFrameName();
+ const EnergyFrame& frame = energyReader->frame();
+ const std::string stepName = frame.frameName();
const real conservedEnergy = frame.at("Total Energy");
const real reciprocalEnergy = frame.at("Coul. recip.");
if (firstIteration)
{
// use first step values as references for tolerance
const real startingKineticEnergy = frame.at("Kinetic En.");
- const auto conservedTolerance = relativeToleranceAsFloatingPoint(startingKineticEnergy, 2e-5);
- const auto reciprocalTolerance = relativeToleranceAsFloatingPoint(reciprocalEnergy, 3e-5);
+ const auto conservedTolerance =
+ relativeToleranceAsFloatingPoint(startingKineticEnergy, 2e-5);
+ const auto reciprocalTolerance =
+ relativeToleranceAsFloatingPoint(reciprocalEnergy, 3e-5);
reciprocalChecker.setDefaultTolerance(reciprocalTolerance);
conservedChecker.setDefaultTolerance(conservedTolerance);
firstIteration = false;
TEST_F(PmeTest, ReproducesEnergies)
{
const int nsteps = 20;
- const std::string theMdpFile = formatString("coulombtype = PME\n"
- "nstcalcenergy = 1\n"
- "nstenergy = 1\n"
- "pme-order = 4\n"
- "nsteps = %d\n",
- nsteps
- );
+ const std::string theMdpFile = formatString(
+ "coulombtype = PME\n"
+ "nstcalcenergy = 1\n"
+ "nstenergy = 1\n"
+ "pme-order = 4\n"
+ "nsteps = %d\n",
+ nsteps);
runner_.useStringAsMdpFile(theMdpFile);
- //TODO test all proper/improper combinations in more thorough way?
+ // TODO test all proper/improper combinations in more thorough way?
RunModesList runModes;
- runModes["PmeOnCpu"] = {"-pme", "cpu"};
- runModes["PmeAuto"] = {"-pme", "auto"};
- runModes["PmeOnGpuFftOnCpu"] = {"-pme", "gpu", "-pmefft", "cpu"};
- runModes["PmeOnGpuFftOnGpu"] = {"-pme", "gpu", "-pmefft", "gpu"};
- runModes["PmeOnGpuFftAuto"] = {"-pme", "gpu", "-pmefft", "auto"};
+ runModes["PmeOnCpu"] = { "-pme", "cpu" };
+ runModes["PmeAuto"] = { "-pme", "auto" };
+ runModes["PmeOnGpuFftOnCpu"] = { "-pme", "gpu", "-pmefft", "cpu" };
+ runModes["PmeOnGpuFftOnGpu"] = { "-pme", "gpu", "-pmefft", "gpu" };
+ runModes["PmeOnGpuFftAuto"] = { "-pme", "gpu", "-pmefft", "auto" };
// same manual modes but marked for PME tuning
- runModes["PmeOnCpuTune"] = {"-pme", "cpu"};
- runModes["PmeOnGpuFftOnCpuTune"] = {"-pme", "gpu", "-pmefft", "cpu"};
- runModes["PmeOnGpuFftOnGpuTune"] = {"-pme", "gpu", "-pmefft", "gpu"};
+ runModes["PmeOnCpuTune"] = { "-pme", "cpu" };
+ runModes["PmeOnGpuFftOnCpuTune"] = { "-pme", "gpu", "-pmefft", "cpu" };
+ runModes["PmeOnGpuFftOnGpuTune"] = { "-pme", "gpu", "-pmefft", "gpu" };
runTest(runModes);
}
TEST_F(PmeTest, ScalesTheBox)
{
const int nsteps = 0;
- const std::string theMdpFile = formatString("coulombtype = PME\n"
- "nstcalcenergy = 1\n"
- "nstenergy = 1\n"
- "pme-order = 4\n"
- "pbc = xy\n"
- "nwall = 2\n"
- "ewald-geometry = 3dc\n"
- "wall_atomtype = OMet CMet\n"
- "wall_density = 9 9.0\n"
- "wall-ewald-zfac = 5\n"
- "nsteps = %d\n",
- nsteps
- );
+ const std::string theMdpFile = formatString(
+ "coulombtype = PME\n"
+ "nstcalcenergy = 1\n"
+ "nstenergy = 1\n"
+ "pme-order = 4\n"
+ "pbc = xyz\n"
+ "nsteps = %d\n",
+ nsteps);
runner_.useStringAsMdpFile(theMdpFile);
RunModesList runModes;
- runModes["PmeOnCpu"] = {"-pme", "cpu"};
- runModes["PmeOnGpuFftOnCpu"] = {"-pme", "gpu", "-pmefft", "cpu"};
- runModes["PmeOnGpuFftOnGpu"] = {"-pme", "gpu", "-pmefft", "gpu"};
+ runModes["PmeOnCpu"] = { "-pme", "cpu" };
+ runModes["PmeOnGpuFftOnCpu"] = { "-pme", "gpu", "-pmefft", "cpu" };
+ runModes["PmeOnGpuFftOnGpu"] = { "-pme", "gpu", "-pmefft", "gpu" };
runTest(runModes);
}
+TEST_F(PmeTest, ScalesTheBoxWithWalls)
+{
+ const int nsteps = 0;
+ const std::string theMdpFile = formatString(
+ "coulombtype = PME\n"
+ "nstcalcenergy = 1\n"
+ "nstenergy = 1\n"
+ "pme-order = 4\n"
+ "pbc = xy\n"
+ "nwall = 2\n"
+ "ewald-geometry = 3dc\n"
+ "wall_atomtype = CMet H\n"
+ "wall_density = 9 9.0\n"
+ "wall-ewald-zfac = 5\n"
+ "nsteps = %d\n",
+ nsteps);
+
+ runner_.useStringAsMdpFile(theMdpFile);
+
+ RunModesList runModes;
+ runModes["PmeOnCpu"] = { "-pme", "cpu" };
+ runModes["PmeOnGpuFftOnCpu"] = { "-pme", "gpu", "-pmefft", "cpu" };
+ runModes["PmeOnGpuFftOnGpu"] = { "-pme", "gpu", "-pmefft", "gpu" };
+
+ runTest(runModes);
}
-}
-}
+
+} // namespace
+} // namespace test
+} // namespace gmx