#include "gromacs/utility/fatalerror.h"
#include "gromacs/utility/gmxassert.h"
#include "gromacs/utility/logger.h"
+#include "gromacs/utility/message_string_collector.h"
#include "gromacs/utility/stringutil.h"
return haveAvailableDevices;
}
+static bool canUseGpusForPme(const bool useGpuForNonbonded,
+ const TaskTarget pmeTarget,
+ const TaskTarget pmeFftTarget,
+ const gmx_hw_info_t& hardwareInfo,
+ const t_inputrec& inputrec,
+ std::string* errorMessage)
+{
+ if (pmeTarget == TaskTarget::Cpu)
+ {
+ return false;
+ }
+
+ std::string tempString;
+ gmx::MessageStringCollector errorReasons;
+ // Before changing the prefix string, make sure that it is not searched for in regression tests.
+ errorReasons.startContext("Cannot compute PME interactions on a GPU, because:");
+ errorReasons.appendIf(!useGpuForNonbonded, "Nonbonded interactions must also run on GPUs.");
+ errorReasons.appendIf(!pme_gpu_supports_build(&tempString), tempString);
+ errorReasons.appendIf(!pme_gpu_supports_hardware(hardwareInfo, &tempString), tempString);
+ errorReasons.appendIf(!pme_gpu_supports_input(inputrec, &tempString), tempString);
+ if (pmeFftTarget == TaskTarget::Cpu)
+ {
+ // User requested PME FFT on CPU, so we check whether we are able to use PME Mixed mode.
+ errorReasons.appendIf(!pme_gpu_mixed_mode_supports_input(inputrec, &tempString), tempString);
+ }
+ errorReasons.finishContext();
+
+ if (errorReasons.isEmpty())
+ {
+ return true;
+ }
+ else
+ {
+ if (pmeTarget == TaskTarget::Gpu && errorMessage != nullptr)
+ {
+ *errorMessage = errorReasons.toString();
+ }
+ return false;
+ }
+}
+
bool decideWhetherToUseGpusForPmeWithThreadMpi(const bool useGpuForNonbonded,
const TaskTarget pmeTarget,
+ const TaskTarget pmeFftTarget,
const int numDevicesToUse,
const std::vector<int>& userGpuTaskAssignment,
const gmx_hw_info_t& hardwareInfo,
const int numPmeRanksPerSimulation)
{
// First, exclude all cases where we can't run PME on GPUs.
- if ((pmeTarget == TaskTarget::Cpu) || !useGpuForNonbonded || !pme_gpu_supports_build(nullptr)
- || !pme_gpu_supports_hardware(hardwareInfo, nullptr) || !pme_gpu_supports_input(inputrec, nullptr))
+ if (!canUseGpusForPme(useGpuForNonbonded, pmeTarget, pmeFftTarget, hardwareInfo, inputrec, nullptr))
{
- // PME can't run on a GPU. If the user required that, we issue
- // an error later.
+ // PME can't run on a GPU. If the user required that, we issue an error later.
return false;
}
bool decideWhetherToUseGpusForPme(const bool useGpuForNonbonded,
const TaskTarget pmeTarget,
+ const TaskTarget pmeFftTarget,
const std::vector<int>& userGpuTaskAssignment,
const gmx_hw_info_t& hardwareInfo,
const t_inputrec& inputrec,
const int numPmeRanksPerSimulation,
const bool gpusWereDetected)
{
- if (pmeTarget == TaskTarget::Cpu)
- {
- return false;
- }
-
- if (!useGpuForNonbonded)
- {
- if (pmeTarget == TaskTarget::Gpu)
- {
- GMX_THROW(NotImplementedError(
- "PME on GPUs is only supported when nonbonded interactions run on GPUs also."));
- }
- return false;
- }
-
std::string message;
- if (!pme_gpu_supports_build(&message))
+ if (!canUseGpusForPme(useGpuForNonbonded, pmeTarget, pmeFftTarget, hardwareInfo, inputrec, &message))
{
- if (pmeTarget == TaskTarget::Gpu)
- {
- GMX_THROW(NotImplementedError("Cannot compute PME interactions on a GPU, because " + message));
- }
- return false;
- }
- if (!pme_gpu_supports_hardware(hardwareInfo, &message))
- {
- if (pmeTarget == TaskTarget::Gpu)
- {
- GMX_THROW(NotImplementedError("Cannot compute PME interactions on a GPU, because " + message));
- }
- return false;
- }
- if (!pme_gpu_supports_input(inputrec, &message))
- {
- if (pmeTarget == TaskTarget::Gpu)
+ if (!message.empty())
{
- GMX_THROW(NotImplementedError("Cannot compute PME interactions on a GPU, because " + message));
+ GMX_THROW(InconsistentInputError(message));
}
return false;
}
// is busy, for which we currently only check PME or Ewald.
// (It would be better to dynamically assign bondeds based on timings)
// Note that here we assume that the auto setting of PME ranks will not
- // choose seperate PME ranks when nonBonded are assigned to the GPU.
+ // choose separate PME ranks when nonBonded are assigned to the GPU.
bool usingOurCpuForPmeOrEwald =
(EVDW_PME(inputrec.vdwtype)
|| (EEL_PME_EWALD(inputrec.coulombtype) && !useGpuForPme && numPmeRanksPerSimulation <= 0));