Performance improvements
^^^^^^^^^^^^^^^^^^^^^^^^
+PME on GPU when running free energy perturbations not involving charges
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+PME can now be run on a GPU when doing free energy perturbations
+that do not involve perturbing charges.
#include "gromacs/timing/cyclecounter.h"
#include "gromacs/timing/wallcycle.h"
#include "gromacs/timing/walltime_accounting.h"
+#include "gromacs/topology/topology.h"
#include "gromacs/utility/basedefinitions.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/fatalerror.h"
return addMessageIfNotSupported(errorReasons, error);
}
-bool pme_gpu_supports_input(const t_inputrec *ir, std::string *error)
+bool pme_gpu_supports_input(const t_inputrec &ir, const gmx_mtop_t &mtop, std::string *error)
{
std::list<std::string> errorReasons;
- if (!EEL_PME(ir->coulombtype))
+ if (!EEL_PME(ir.coulombtype))
{
errorReasons.emplace_back("systems that do not use PME for electrostatics");
}
- if (ir->pme_order != 4)
+ if (ir.pme_order != 4)
{
errorReasons.emplace_back("interpolation orders other than 4");
}
- if (ir->efep != efepNO)
+ if (ir.efep != efepNO)
{
- errorReasons.emplace_back("free energy calculations (multiple grids)");
+ if (gmx_mtop_has_perturbed_charges(mtop))
+ {
+ errorReasons.emplace_back("free energy calculations with perturbed charges (multiple grids)");
+ }
}
- if (EVDW_PME(ir->vdwtype))
+ if (EVDW_PME(ir.vdwtype))
{
errorReasons.emplace_back("Lennard-Jones PME");
}
- if (ir->cutoff_scheme == ecutsGROUP)
+ if (ir.cutoff_scheme == ecutsGROUP)
{
errorReasons.emplace_back("group cutoff scheme");
}
- if (!EI_DYNAMICS(ir->eI))
+ if (!EI_DYNAMICS(ir.eI))
{
errorReasons.emplace_back("not a dynamical integrator");
}
struct PmeGpu;
struct gmx_wallclock_gpu_pme_t;
struct gmx_device_info_t;
+struct gmx_mtop_t;
struct gmx_pme_t;
struct gmx_wallcycle;
struct NumPmeDomains;
* formed gmx_pme_t structure. Should that one go away/work with inputrec?
*
* \param[in] ir Input system.
+ * \param[in] mtop Complete system topology to check if an FE simulation perturbs charges.
* \param[out] error If non-null, the error message if the input is not supported on GPU.
*
* \returns true if PME can run on GPU with this input, false otherwise.
*/
-bool pme_gpu_supports_input(const t_inputrec *ir, std::string *error);
+bool pme_gpu_supports_input(const t_inputrec &ir, const gmx_mtop_t &mtop, std::string *error);
/*! \brief
* Returns the active PME codepath (CPU, GPU, mixed).
#include "gromacs/math/invertmatrix.h"
#include "gromacs/mdtypes/commrec.h"
#include "gromacs/pbcutil/pbc.h"
+#include "gromacs/topology/topology.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/gmxassert.h"
#include "gromacs/utility/logger.h"
bool pmeSupportsInputForMode(const t_inputrec *inputRec, CodePath mode)
{
- bool implemented;
+ bool implemented;
+ gmx_mtop_t mtop;
switch (mode)
{
case CodePath::CPU:
case CodePath::CUDA:
implemented = (pme_gpu_supports_build(nullptr) &&
- pme_gpu_supports_input(inputRec, nullptr));
+ pme_gpu_supports_input(*inputRec, mtop, nullptr));
break;
default:
inputrec->cutoff_scheme == ecutsVERLET,
gpuAccelerationOfNonbondedIsUseful(mdlog, inputrec, GMX_THREAD_MPI),
hw_opt.nthreads_tmpi);
- auto canUseGpuForPme = pme_gpu_supports_build(nullptr) && pme_gpu_supports_input(inputrec, nullptr);
+ auto canUseGpuForPme = pme_gpu_supports_build(nullptr) && pme_gpu_supports_input(*inputrec, mtop, nullptr);
useGpuForPme = decideWhetherToUseGpusForPmeWithThreadMpi
(useGpuForNonbonded, pmeTarget, gpuIdsToUse, userGpuTaskAssignment,
canUseGpuForPme, hw_opt.nthreads_tmpi, domdecOptions.numPmeRanks);
emulateGpuNonbonded, inputrec->cutoff_scheme == ecutsVERLET,
gpuAccelerationOfNonbondedIsUseful(mdlog, inputrec, !GMX_THREAD_MPI),
gpusWereDetected);
- auto canUseGpuForPme = pme_gpu_supports_build(nullptr) && pme_gpu_supports_input(inputrec, nullptr);
+ auto canUseGpuForPme = pme_gpu_supports_build(nullptr) && pme_gpu_supports_input(*inputrec, mtop, nullptr);
useGpuForPme = decideWhetherToUseGpusForPme(useGpuForNonbonded, pmeTarget, userGpuTaskAssignment,
canUseGpuForPme, cr->nnodes, domdecOptions.numPmeRanks,
gpusWereDetected);
if (pmeOnGpu)
{
GMX_RELEASE_ASSERT((EEL_PME(inputrec->coulombtype) || EVDW_PME(inputrec->vdwtype)) &&
- pme_gpu_supports_build(nullptr) && pme_gpu_supports_input(inputrec, nullptr),
+ pme_gpu_supports_build(nullptr) && pme_gpu_supports_input(*inputrec, *mtop, nullptr),
"PME can't be on GPUs unless we are using PME");
// PME on GPUs supports a single PME rank with PP running on the same or few other ranks.
return mtop->moltype.empty() || mtop->moltype[0].atoms.haveCharge;
}
+bool gmx_mtop_has_perturbed_charges(const gmx_mtop_t &mtop)
+{
+ for (const gmx_moltype_t &moltype : mtop.moltype)
+ {
+ const t_atoms &atoms = moltype.atoms;
+ if (atoms.haveBState)
+ {
+ for (int a = 0; a < atoms.nr; a++)
+ {
+ if (atoms.atom[a].q != atoms.atom[a].qB)
+ {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
bool gmx_mtop_has_atomtypes(const gmx_mtop_t *mtop)
{
if (mtop == nullptr)
bool gmx_mtop_has_masses(const gmx_mtop_t *mtop);
bool gmx_mtop_has_charges(const gmx_mtop_t *mtop);
+bool gmx_mtop_has_perturbed_charges(const gmx_mtop_t &mtop);
bool gmx_mtop_has_atomtypes(const gmx_mtop_t *mtop);
bool gmx_mtop_has_pdbinfo(const gmx_mtop_t *mtop);