Use MessageStringCollector class to construct error messages
authorArtem Zhmurov <zhmurov@gmail.com>
Thu, 20 May 2021 14:01:15 +0000 (14:01 +0000)
committerPaul Bauer <paul.bauer.q@gmail.com>
Thu, 20 May 2021 14:01:15 +0000 (14:01 +0000)
src/gromacs/ewald/pme.cpp
src/gromacs/gpu_utils/gpu_utils.cpp
src/gromacs/gpu_utils/gpu_utils.h
src/gromacs/listed_forces/gpubonded_impl.cpp
src/gromacs/nbnxm/nbnxm.cpp
src/gromacs/nbnxm/nbnxm.h

index a3dd8357556c86b88c0f77ba32c2848d0be5b959..fe488dc50844bde64ba5623693ce8de0946a610e 100644 (file)
 #include "gromacs/utility/logger.h"
 #include "gromacs/utility/real.h"
 #include "gromacs/utility/smalloc.h"
-#include "gromacs/utility/stringutil.h"
+#include "gromacs/utility/message_string_collector.h"
 #include "gromacs/utility/unique_cptr.h"
 
 #include "calculate_spline_moduli.h"
 #include "pme_spline_work.h"
 #include "pme_spread.h"
 
-/*! \brief Help build a descriptive message in \c error if there are
- * \c errorReasons why PME on GPU is not supported.
- *
- * \returns Whether the lack of errorReasons indicate there is support. */
-static bool addMessageIfNotSupported(const std::list<std::string>& errorReasons, std::string* error)
-{
-    bool isSupported = errorReasons.empty();
-    if (!isSupported && error)
-    {
-        std::string regressionTestMarker = "PME GPU does not support";
-        // this prefix is tested for in the regression tests script gmxtest.pl
-        *error = regressionTestMarker;
-        if (errorReasons.size() == 1)
-        {
-            *error += " " + errorReasons.back();
-        }
-        else
-        {
-            *error += ": " + gmx::joinStrings(errorReasons, "; ");
-        }
-        *error += ".";
-    }
-    return isSupported;
-}
-
 bool pme_gpu_supports_build(std::string* error)
 {
-    std::list<std::string> errorReasons;
-    if (GMX_DOUBLE)
-    {
-        errorReasons.emplace_back("a double-precision build");
-    }
-    if (!GMX_GPU)
-    {
-        errorReasons.emplace_back("a non-GPU build");
-    }
-    if (GMX_GPU_SYCL)
-    {
-        errorReasons.emplace_back("SYCL build"); // SYCL-TODO
-    }
-    return addMessageIfNotSupported(errorReasons, error);
+    gmx::MessageStringCollector errorReasons;
+    // Before changing the prefix string, make sure that it is not searched for in regression tests.
+    errorReasons.startContext("PME GPU does not support:");
+    errorReasons.appendIf(GMX_DOUBLE, "Double-precision build of GROMACS.");
+    errorReasons.appendIf(!GMX_GPU, "Non-GPU build of GROMACS.");
+    errorReasons.appendIf(GMX_GPU_SYCL, "SYCL build."); // SYCL-TODO
+    errorReasons.finishContext();
+    if (error != nullptr)
+    {
+        *error = errorReasons.toString();
+    }
+    return errorReasons.isEmpty();
 }
 
 bool pme_gpu_supports_hardware(const gmx_hw_info_t gmx_unused& hwinfo, std::string* error)
 {
-    std::list<std::string> errorReasons;
-
-    if (GMX_GPU_OPENCL)
-    {
+    gmx::MessageStringCollector errorReasons;
+    // Before changing the prefix string, make sure that it is not searched for in regression tests.
+    errorReasons.startContext("PME GPU does not support:");
 #ifdef __APPLE__
-        errorReasons.emplace_back("Apple OS X operating system");
+    errorReasons.appendIf(GMX_GPU_OPENCL, "Apple OS X operating system");
 #endif
+    errorReasons.finishContext();
+    if (error != nullptr)
+    {
+        *error = errorReasons.toString();
     }
-    return addMessageIfNotSupported(errorReasons, error);
+    return errorReasons.isEmpty();
 }
 
 bool pme_gpu_supports_input(const t_inputrec& ir, std::string* error)
 {
-    std::list<std::string> errorReasons;
-    if (!EEL_PME(ir.coulombtype))
-    {
-        errorReasons.emplace_back("systems that do not use PME for electrostatics");
-    }
-    if (ir.pme_order != 4)
-    {
-        errorReasons.emplace_back("interpolation orders other than 4");
-    }
-    if (EVDW_PME(ir.vdwtype))
-    {
-        errorReasons.emplace_back("Lennard-Jones PME");
-    }
-    if (!EI_DYNAMICS(ir.eI))
-    {
-        errorReasons.emplace_back(
-                "Cannot compute PME interactions on a GPU, because PME GPU requires a dynamical "
-                "integrator (md, sd, etc).");
-    }
-    return addMessageIfNotSupported(errorReasons, error);
+    gmx::MessageStringCollector errorReasons;
+    // Before changing the prefix string, make sure that it is not searched for in regression tests.
+    errorReasons.startContext("PME GPU does not support:");
+    errorReasons.appendIf(!EEL_PME(ir.coulombtype),
+                          "Systems that do not use PME for electrostatics.");
+    errorReasons.appendIf((ir.pme_order != 4), "Interpolation orders other than 4.");
+    errorReasons.appendIf(EVDW_PME(ir.vdwtype), "Lennard-Jones PME.");
+    errorReasons.appendIf(!EI_DYNAMICS(ir.eI), "Non-dynamical integrator (use md, sd, etc).");
+    errorReasons.finishContext();
+    if (error != nullptr)
+    {
+        *error = errorReasons.toString();
+    }
+    return errorReasons.isEmpty();
 }
 
 /*! \brief \libinternal
@@ -218,32 +188,21 @@ bool pme_gpu_supports_input(const t_inputrec& ir, std::string* error)
  */
 static bool pme_gpu_check_restrictions(const gmx_pme_t* pme, std::string* error)
 {
-    std::list<std::string> errorReasons;
-    if (pme->nnodes != 1)
-    {
-        errorReasons.emplace_back("PME decomposition");
-    }
-    if (pme->pme_order != 4)
-    {
-        errorReasons.emplace_back("interpolation orders other than 4");
-    }
-    if (pme->doLJ)
-    {
-        errorReasons.emplace_back("Lennard-Jones PME");
-    }
-    if (GMX_DOUBLE)
-    {
-        errorReasons.emplace_back("double precision");
-    }
-    if (!GMX_GPU)
-    {
-        errorReasons.emplace_back("non-GPU build of GROMACS");
-    }
-    if (GMX_GPU_SYCL)
-    {
-        errorReasons.emplace_back("SYCL build of GROMACS"); // SYCL-TODO
-    }
-    return addMessageIfNotSupported(errorReasons, error);
+    gmx::MessageStringCollector errorReasons;
+    // Before changing the prefix string, make sure that it is not searched for in regression tests.
+    errorReasons.startContext("PME GPU does not support:");
+    errorReasons.appendIf((pme->nnodes != 1), "PME decomposition.");
+    errorReasons.appendIf((pme->pme_order != 4), "interpolation orders other than 4.");
+    errorReasons.appendIf(pme->doLJ, "Lennard-Jones PME.");
+    errorReasons.appendIf(GMX_DOUBLE, "Double precision build of GROMACS.");
+    errorReasons.appendIf(!GMX_GPU, "Non-GPU build of GROMACS.");
+    errorReasons.appendIf(GMX_GPU_SYCL, "SYCL build of GROMACS."); // SYCL-TODO
+    errorReasons.finishContext();
+    if (error != nullptr)
+    {
+        *error = errorReasons.toString();
+    }
+    return errorReasons.isEmpty();
 }
 
 PmeRunMode pme_run_mode(const gmx_pme_t* pme)
index 5fab6b73795b5d496d6b35e163695673ea4960d6..501d6b625fc8ff9b0aeea6478e64c232e9950a78 100644 (file)
@@ -59,32 +59,3 @@ const char* enumValueToString(GpuApiCallBehavior enumValue)
     };
     return s_gpuApiCallBehaviorNames[enumValue];
 }
-
-/*! \brief Help build a descriptive message in \c error if there are
- * \c errorReasons why nonbondeds on a GPU are not supported.
- *
- * \returns Whether the lack of errorReasons indicate there is support. */
-static bool addMessageIfNotSupported(gmx::ArrayRef<const std::string> errorReasons, std::string* error)
-{
-    bool isSupported = errorReasons.empty();
-    if (!isSupported && error)
-    {
-        *error = "Nonbonded interactions cannot run on GPUs: ";
-        *error += joinStrings(errorReasons, "; ") + ".";
-    }
-    return isSupported;
-}
-
-bool buildSupportsNonbondedOnGpu(std::string* error)
-{
-    std::vector<std::string> errorReasons;
-    if (GMX_DOUBLE)
-    {
-        errorReasons.emplace_back("double precision");
-    }
-    if (!GMX_GPU)
-    {
-        errorReasons.emplace_back("non-GPU build of GROMACS");
-    }
-    return addMessageIfNotSupported(errorReasons, error);
-}
index 378015fb309729f3c1ef5886de03cffdf1b358f5..f9c5353b748ce43e05a18e11968fe99b6f19a7d9 100644 (file)
@@ -80,13 +80,6 @@ enum class GpuTaskCompletion
     Check /*<< Only check whether the task has completed */
 };
 
-/*! \brief Check if GROMACS has been built with GPU support.
- *
- * \param[in] error Pointer to error string or nullptr.
- * \todo Move this to NB module once it exists.
- */
-bool buildSupportsNonbondedOnGpu(std::string* error);
-
 /*! \brief Starts the GPU profiler if mdrun is being profiled.
  *
  *  When a profiler run is in progress (based on the presence of the NVPROF_ID
index 0e3f2cb54cadc06ffeaf4fb0c53a5a6d8ad2f61c..1fe74e0082e4a92ca18c8983371e9ffa073cd340 100644 (file)
@@ -51,7 +51,7 @@
 #include "gromacs/listed_forces/gpubonded.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/topology/topology.h"
-#include "gromacs/utility/stringutil.h"
+#include "gromacs/utility/message_string_collector.h"
 
 namespace gmx
 {
@@ -93,71 +93,44 @@ static bool bondedInteractionsCanRunOnGpu(const gmx_mtop_t& mtop)
     return false;
 }
 
-/*! \brief Help build a descriptive message in \c error if there are
- * \c errorReasons why bondeds on a GPU are not supported.
- *
- * \returns Whether the lack of errorReasons indicate there is support. */
-static bool addMessageIfNotSupported(ArrayRef<const std::string> errorReasons, std::string* error)
-{
-    bool isSupported = errorReasons.empty();
-    if (!isSupported && error)
-    {
-        *error = "Bonded interactions cannot run on GPUs: ";
-        *error += joinStrings(errorReasons, "; ") + ".";
-    }
-    return isSupported;
-}
-
 bool buildSupportsGpuBondeds(std::string* error)
 {
-    std::vector<std::string> errorReasons;
-
-    if (GMX_DOUBLE)
-    {
-        errorReasons.emplace_back("not supported with double precision");
-    }
-    if (GMX_GPU_OPENCL)
-    {
-        errorReasons.emplace_back("not supported with OpenCL build of GROMACS");
-    }
-    if (GMX_GPU_SYCL)
+    MessageStringCollector errorReasons;
+    // Before changing the prefix string, make sure that it is not searched for in regression tests.
+    errorReasons.startContext("Bonded interactions on GPU are not supported in:");
+    errorReasons.appendIf(GMX_DOUBLE, "Double precision build of GROMACS");
+    errorReasons.appendIf(GMX_GPU_OPENCL, "OpenCL build of GROMACS");
+    errorReasons.appendIf(GMX_GPU_SYCL, "SYCL build of GROMACS");
+    errorReasons.appendIf(!GMX_GPU, "CPU-only build of GROMACS");
+    errorReasons.finishContext();
+    if (error != nullptr)
     {
-        errorReasons.emplace_back("not supported with SYCL build of GROMACS");
+        *error = errorReasons.toString();
     }
-    else if (!GMX_GPU)
-    {
-        errorReasons.emplace_back("not supported with CPU-only build of GROMACS");
-    }
-    return addMessageIfNotSupported(errorReasons, error);
+    return errorReasons.isEmpty();
 }
 
 bool inputSupportsGpuBondeds(const t_inputrec& ir, const gmx_mtop_t& mtop, std::string* error)
 {
-    std::vector<std::string> errorReasons;
-
-    if (!bondedInteractionsCanRunOnGpu(mtop))
-    {
-        errorReasons.emplace_back("No supported bonded interactions are present");
-    }
-    if (!EI_DYNAMICS(ir.eI))
-    {
-        errorReasons.emplace_back(
-                "Cannot compute bonded interactions on a GPU, because GPU implementation requires "
-                "a dynamical integrator (md, sd, etc).");
-    }
-    if (EI_MIMIC(ir.eI))
-    {
-        errorReasons.emplace_back("MiMiC");
-    }
-    if (ir.useMts)
-    {
-        errorReasons.emplace_back("Cannot run with multiple time stepping");
-    }
-    if (ir.opts.ngener > 1)
+    MessageStringCollector errorReasons;
+    // Before changing the prefix string, make sure that it is not searched for in regression tests.
+    errorReasons.startContext("Bonded interactions can not be computed on a GPU:");
+
+    errorReasons.appendIf(!bondedInteractionsCanRunOnGpu(mtop),
+                          "None of the bonded types are implemented on the GPU.");
+    errorReasons.appendIf(
+            !EI_DYNAMICS(ir.eI),
+            "Cannot compute bonded interactions on a GPU, because GPU implementation requires "
+            "a dynamical integrator (md, sd, etc).");
+    errorReasons.appendIf(EI_MIMIC(ir.eI), "MiMiC");
+    errorReasons.appendIf(ir.useMts, "Cannot run with multiple time stepping");
+    errorReasons.appendIf((ir.opts.ngener > 1), "Cannot run with multiple energy groups");
+    errorReasons.finishContext();
+    if (error != nullptr)
     {
-        errorReasons.emplace_back("Cannot run with multiple energy groups");
+        *error = errorReasons.toString();
     }
-    return addMessageIfNotSupported(errorReasons, error);
+    return errorReasons.isEmpty();
 }
 
 #if !GMX_GPU_CUDA
index 89ad3ea294e176452d937c1bda46ece6c772638e..361483b84c1e529830742e6af993f73e0a27655a 100644 (file)
@@ -48,6 +48,7 @@
 #include "gromacs/domdec/domdec_struct.h"
 #include "gromacs/nbnxm/atomdata.h"
 #include "gromacs/timing/wallcycle.h"
+#include "gromacs/utility/message_string_collector.h"
 
 #include "nbnxm_gpu.h"
 #include "pairlistsets.h"
@@ -242,4 +243,20 @@ void nonbonded_verlet_t::atomdata_init_copy_x_to_nbat_x_gpu() const
     Nbnxm::nbnxn_gpu_init_x_to_nbat_x(pairSearch_->gridSet(), gpu_nbv);
 }
 
+bool buildSupportsNonbondedOnGpu(std::string* error)
+{
+    gmx::MessageStringCollector errorReasons;
+    // Before changing the prefix string, make sure that it is not searched for in regression tests.
+    errorReasons.startContext("Nonbonded interactions on GPUs are not supported in:");
+    errorReasons.appendIf(GMX_DOUBLE, "Double precision build of GROMACS");
+    errorReasons.appendIf(!GMX_GPU, "Non-GPU build of GROMACS.");
+    errorReasons.finishContext();
+    if (error != nullptr)
+    {
+        *error = errorReasons.toString();
+    }
+    return errorReasons.isEmpty();
+}
+
+
 /*! \endcond */
index e22e3a089fc7f3ce60179fe21c6e68ef3ecd0ae3..5195a61f92bda15c440f354a05c4f7cbcdbffc2a 100644 (file)
@@ -496,4 +496,11 @@ void nbnxn_put_on_grid_nonlocal(nonbonded_verlet_t*              nb_verlet,
                                 gmx::ArrayRef<const int>         atomInfo,
                                 gmx::ArrayRef<const gmx::RVec>   x);
 
+/*! \brief Check if GROMACS has been built with GPU support.
+ *
+ * \param[in] error Pointer to error string or nullptr.
+ * \todo Move this to NB module once it exists.
+ */
+bool buildSupportsNonbondedOnGpu(std::string* error);
+
 #endif // GMX_NBNXN_NBNXM_H