Merge branch release-2019
authorMark Abraham <mark.j.abraham@gmail.com>
Wed, 2 Jan 2019 10:56:32 +0000 (11:56 +0100)
committerPaul Bauer <paul.bauer.q@gmail.com>
Wed, 2 Jan 2019 11:22:29 +0000 (12:22 +0100)
Change-Id: I71d9bc751e14f821392f802ee9222b864f1e69b6

23 files changed:
1  2 
CMakeLists.txt
admin/builds/gromacs.py
cmake/gmxManageClangCudaConfig.cmake
cmake/gmxManageNvccConfig.cmake
cmake/gmxVersionInfo.cmake
docs/CMakeLists.txt
docs/release-notes/index.rst
src/api/cpp/tests/CMakeLists.txt
src/api/cpp/workflow/tests/CMakeLists.txt
src/config.h.cmakein
src/gromacs/gpu_utils/gpu_utils.cpp
src/gromacs/gpu_utils/gpu_utils.cu
src/gromacs/gpu_utils/gpu_utils.h
src/gromacs/gpu_utils/gpu_utils_ocl.cpp
src/gromacs/gpu_utils/oclraii.h
src/gromacs/mdlib/md_support.cpp
src/gromacs/mdlib/md_support.h
src/gromacs/mdlib/update.cpp
src/gromacs/mdrun/md.cpp
src/gromacs/mdrun/runner.cpp
src/gromacs/taskassignment/decidegpuusage.cpp
src/gromacs/taskassignment/decidegpuusage.h
src/gromacs/timing/cyclecounter.cpp

diff --combined CMakeLists.txt
index 90c253920d1af8a3b8baf8ea236835354fb7702f,0191097c78c1962b53da399b1b797a01739ccc36..59dc5a7f42ca2389623b01de96af763450d21d1c
@@@ -1,7 -1,7 +1,7 @@@
  #
  # This file is part of the GROMACS molecular simulation package.
  #
--# Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
++# Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019, 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.
@@@ -217,7 -217,9 +217,9 @@@ endif(
  set(REQUIRED_CUDA_COMPUTE_CAPABILITY 3.0)
  
  # OpenCL required version: 1.2 or newer
- set(REQUIRED_OPENCL_MIN_VERSION 1.2)
+ set(REQUIRED_OPENCL_MIN_VERSION_MAJOR 1)
+ set(REQUIRED_OPENCL_MIN_VERSION_MINOR 2)
+ set(REQUIRED_OPENCL_MIN_VERSION ${REQUIRED_OPENCL_MIN_VERSION_MAJOR}.${REQUIRED_OPENCL_MIN_VERSION_MINOR})
  
  if(NOT GMX_USE_OPENCL)
      # CUDA detection is done only if GMX_USE_OPENCL is OFF.
diff --combined admin/builds/gromacs.py
index c4776b7b27863eb13e8f754f16fb94b4a78cf6bc,b1bde7ad28d666f7d0ff9e0cfb97ed7ee46d79fc..ec6fa73a5cd74e0decd1ce2e6f9823ef91ec49ca
@@@ -1,7 -1,7 +1,7 @@@
  #
  # This file is part of the GROMACS molecular simulation package.
  #
--# Copyright (c) 2015,2016,2017,2018, by the GROMACS development team, led by
++# Copyright (c) 2015,2016,2017,2018,2019, 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.
@@@ -125,6 -125,8 +125,8 @@@ def do_build(context)
          cmake_opts['GMX_FFT_LIBRARY'] = 'fftpack'
      elif context.opts.buildfftw:
          cmake_opts['GMX_BUILD_OWN_FFTW'] = 'ON'
+         cmake_opts['GMX_BUILD_OWN_FFTW_URL'] = 'ftp://ftp.gromacs.org/misc/fftw-3.3.8.tar.gz'
+         cmake_opts['GMX_BUILD_OWN_FFTW_MD5'] = '8aac833c943d8e90d51b697b27d4384d'
      if context.opts.mkl or context.opts.atlas or context.opts.armpl:
          cmake_opts['GMX_EXTERNAL_BLAS'] = 'ON'
          cmake_opts['GMX_EXTERNAL_LAPACK'] = 'ON'
index 542674d56c477a2240838c20a622df33ade1899c,c06a4ca710404a4eb9a6e80fb75bb2a7280172f8..4d8f45510801f1219fe175135a2096ef4af4ed75
@@@ -1,7 -1,7 +1,7 @@@
  #
  # This file is part of the GROMACS molecular simulation package.
  #
--# Copyright (c) 2017,2018, by the GROMACS development team, led by
++# Copyright (c) 2017,2018,2019, 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.
@@@ -79,6 -79,10 +79,10 @@@ else(
      if (NOT CUDA_VERSION VERSION_LESS 9.0)
          list(APPEND _CUDA_CLANG_GENCODE_FLAGS "--cuda-gpu-arch=sm_70")
      endif()
+     # Enable this when clang (8.0 ?) introduces sm_75 support
+     #if (NOT CUDA_VERSION VERSION_LESS 10.0)
+     #    list(APPEND _CUDA_CLANG_GENCODE_FLAGS "--cuda-gpu-arch=sm_75")
+     #endif()
  endif()
  if (GMX_CUDA_TARGET_SM)
      set_property(CACHE GMX_CUDA_TARGET_SM PROPERTY HELPSTRING "List of CUDA GPU architecture codes to compile for (without the sm_ prefix)")
index 5704baaff32c09f663d799ee232fcae60859af77,ba338394bbdefc0b69234e37d83fd378ff6840d4..8a021d67ac5a57151fb9a8597e4b2732a8016bac
@@@ -1,7 -1,7 +1,7 @@@
  #
  # This file is part of the GROMACS molecular simulation package.
  #
--# Copyright (c) 2012,2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
++# Copyright (c) 2012,2013,2014,2015,2016,2017,2018,2019, 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.
@@@ -142,8 -142,10 +142,10 @@@ else(
      elseif(CUDA_VERSION VERSION_LESS "9.0")
          list (APPEND GMX_CUDA_NVCC_GENCODE_FLAGS "-gencode;arch=compute_60,code=compute_60")
          list (APPEND GMX_CUDA_NVCC_GENCODE_FLAGS "-gencode;arch=compute_61,code=compute_61")
-     else() # version >= 9.0
+     elseif(CUDA_VERSION VERSION_LESS "10.0")
          list (APPEND GMX_CUDA_NVCC_GENCODE_FLAGS "-gencode;arch=compute_70,code=compute_70")
+     else() # version >= 10.0
+         list (APPEND GMX_CUDA_NVCC_GENCODE_FLAGS "-gencode;arch=compute_75,code=compute_75")
      endif()
  endif()
  
index 00c28c65a07f50895a41fb3b903a255deb55362b,970a572d7b56cd01744d21865b21a5974de991cb..6531d44d3eeaa86b592cb307a71d206532043094
@@@ -1,7 -1,7 +1,7 @@@
  #
  # This file is part of the GROMACS molecular simulation package.
  #
--# Copyright (c) 2014,2015,2016,2017,2018, by the GROMACS development team, led by
++# Copyright (c) 2014,2015,2016,2017,2018,2019, 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.
@@@ -57,7 -57,6 +57,7 @@@
  #         GROMACS     2016   2
  #         GROMACS     2018   3
  #         GROMACS     2019   4
 +#         GROMACS     2020   5
  #   LIBRARY_SOVERSION_MINOR so minor version for the built libraries.
  #       Should be increased for each release that changes only the implementation.
  #       In GROMACS, the typical policy is to increase it for each patch version
  
  # The GROMACS convention is that these are the version number of the next
  # release that is going to be made from this branch.
 -set(GMX_VERSION_MAJOR 2019)
 -set(GMX_VERSION_PATCH 1)
 +set(GMX_VERSION_MAJOR 2020)
 +set(GMX_VERSION_PATCH 0)
  # The suffix, on the other hand, is used mainly for betas and release
  # candidates, where it signifies the most recent such release from
  # this branch; it will be empty before the first such release, as well
@@@ -213,7 -212,7 +213,7 @@@ set(GMX_VERSION_SUFFIX ""
  # here. The important thing is to minimize the chance of third-party
  # code being able to dynamically link with a version of libgromacs
  # that might not work.
 -set(LIBRARY_SOVERSION_MAJOR 4)
 +set(LIBRARY_SOVERSION_MAJOR 5)
  set(LIBRARY_SOVERSION_MINOR 0)
  set(LIBRARY_VERSION ${LIBRARY_SOVERSION_MAJOR}.${LIBRARY_SOVERSION_MINOR}.0)
  
@@@ -236,13 -235,13 +236,13 @@@ if (NOT SOURCE_IS_SOURCE_DISTRIBUTION A
  endif()
  
  set(REGRESSIONTEST_VERSION "${GMX_VERSION_STRING}")
 -set(REGRESSIONTEST_BRANCH "refs/heads/release-2019")
 +set(REGRESSIONTEST_BRANCH "refs/heads/master")
  # Run the regressiontests packaging job with the correct pakage
  # version string, and the release box checked, in order to have it
  # build the regressiontests tarball with all the right naming. The
  # naming affects the md5sum that has to go here, and if it isn't right
  # release workflow will report a failure.
 -set(REGRESSIONTEST_MD5SUM "1271a74bfe91028b7f184866d5aee98e" CACHE INTERNAL "MD5 sum of the regressiontests tarball for this GROMACS version")
 +set(REGRESSIONTEST_MD5SUM "3d06d41e07f523d70ae575b9ad75c670" CACHE INTERNAL "MD5 sum of the regressiontests tarball for this GROMACS version")
  
  math(EXPR GMX_VERSION_NUMERIC
       "${GMX_VERSION_MAJOR}*10000 + ${GMX_VERSION_PATCH}")
@@@ -259,8 -258,8 +259,8 @@@ endif(
  # from Zenodo for the manual and source code
  # Has to be done by hand before every final release
  # Use force to override anything given as a cmake command line input
- set(GMX_MANUAL_DOI "" CACHE INTERNAL "reserved doi for GROMACS manual" FORCE)
- set(GMX_SOURCE_DOI "" CACHE INTERNAL "reserved doi for GROMACS source code" FORCE)
+ set(GMX_MANUAL_DOI "10.5281/zenodo.2424486" CACHE INTERNAL "reserved doi for GROMACS manual" FORCE)
+ set(GMX_SOURCE_DOI "10.5281/zenodo.2424363" CACHE INTERNAL "reserved doi for GROMACS source code" FORCE)
  
  #####################################################################
  # git version info management
diff --combined docs/CMakeLists.txt
index 5c4fc632c7c67abc8838564c64c7f4b6b86324b2,dff9e6cd2e053c3e096b34f1ff59934fd9a6b62b..e9742372813c54b8746bf16972bc9f0e0c0fe821
@@@ -1,7 -1,7 +1,7 @@@
  #
  # This file is part of the GROMACS molecular simulation package.
  #
--# Copyright (c) 2014,2015,2016,2017,2018, by the GROMACS development team, led by
++# Copyright (c) 2014,2015,2016,2017,2018,2019, 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.
@@@ -367,15 -367,7 +367,16 @@@ if (SPHINX_FOUND
          how-to/visualize.rst
          install-guide/index.rst
          release-notes/index.rst
 +        release-notes/highlights.rst
 +        release-notes/features.rst
 +        release-notes/performance.rst
 +        release-notes/tools.rst
 +        release-notes/bugs-fixed.rst
 +        release-notes/removed-functionality.rst
 +        release-notes/deprecated-functionality.rst
 +        release-notes/portability.rst
 +        release-notes/miscellaneous.rst
+         release-notes/2019/2019.1.rst
          release-notes/2019/major/highlights.rst
          release-notes/2019/major/features.rst
          release-notes/2019/major/performance.rst
index efa62f1b555acbc1d64ea676c3d93defe2cd0801,99f9c866d3edfdd13a39d3dcec8839e7cbe0e08f..41afbdde4633ed9e3a69879c45e950859cc36def
@@@ -8,35 -8,18 +8,35 @@@ releases of |Gromacs|. Major releases c
  functionality supported, whereas patch releases contain only fixes for
  issues identified in the corresponding major releases.
  
 -Two versions of |Gromacs| are under active maintenance, the 2019
 -series and the 2018 series. In the latter, only highly conservative
 +Two versions of |Gromacs| are under active maintenance, the NEXT
 +series and the 2019 series. In the latter, only highly conservative
  fixes will be made, and only to address issues that affect scientific
  correctness. Naturally, some of those releases will be made after the
 -year 2018 ends, but we keep 2018 in the name so users understand how
 +year 2019 ends, but we keep 2018 in the name so users understand how
  up to date their version is. Such fixes will also be incorporated into
 -the 2019 release series, as appropriate. Around the time the 2020
 -release is made, the 2018 series will no longer be maintained.
 +the NEXT release series, as appropriate. Around the time the NEXT+1
 +release is made, the 2019 series will no longer be maintained.
  
  Where issue numbers are reported in these release notes, more details
  can be found at https://redmine.gromacs.org at that issue number.
  
 +|Gromacs| NEXT series
 +---------------------
 +
 +.. toctree::
 +   :maxdepth: 1
 +
 +   highlights
 +   features
 +   performance
 +   tools
 +   bugs-fixed
 +   deprecated-functionality
 +   removed-functionality
 +   portability
 +   miscellaneous
 +
 +
  |Gromacs| 2019 series
  ---------------------
  
@@@ -46,6 -29,8 +46,8 @@@ Patch release
  .. toctree::
     :maxdepth: 1
  
+    2019/2019.1
  Major release
  ^^^^^^^^^^^^^
  
index 726ce22753b5a04e814c144548a098ac7fd1196f,17f35a123c46f76d5e3be2cb8e4738cec0204b76..c4c733d253ff8aba4895e088c9b294a0b14716b9
@@@ -1,7 -1,7 +1,7 @@@
  #
  # This file is part of the GROMACS molecular simulation package.
  #
--# Copyright (c) 2018, by the GROMACS development team, led by
++# Copyright (c) 2018,2019, 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.
@@@ -73,7 -73,7 +73,7 @@@ target_include_directories(gmxapi-test 
  # Link against the gmxapi libraries and get access to its public (installed) headers.
  target_link_libraries(gmxapi-test Gromacs::gmxapi)
  
- gmx_register_gtest_test(GmxapiExternalInterfaceTests gmxapi-test INTEGRATION_TEST)
+ gmx_register_gtest_test(GmxapiExternalInterfaceTests gmxapi-test OPENMP_THREADS 2 INTEGRATION_TEST)
  
  set_tests_properties(GmxapiExternalInterfaceTests PROPERTIES
                       WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
@@@ -105,4 -105,4 +105,4 @@@ target_include_directories(gmxapi-mpi-t
                             ${CMAKE_CURRENT_SOURCE_DIR})
  target_link_libraries(gmxapi-mpi-test Gromacs::gmxapi)
  
- gmx_register_gtest_test(GmxapiMpiTests gmxapi-mpi-test MPI_RANKS 2 INTEGRATION_TEST)
+ gmx_register_gtest_test(GmxapiMpiTests gmxapi-mpi-test MPI_RANKS 2 OPENMP_THREADS 2 INTEGRATION_TEST)
index 80f3e448319d8383b90f3759525fd21aace26709,5f75ee5b4fb20d35b28849229146d1feea406d3c..b37ecdb7d2aa48b0048d3d5e9a330f890307bd41
@@@ -1,7 -1,7 +1,7 @@@
  #
  # This file is part of the GROMACS molecular simulation package.
  #
--# Copyright (c) 2018, by the GROMACS development team, led by
++# Copyright (c) 2018,2019, 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.
@@@ -47,7 -47,7 +47,7 @@@ gmx_add_gtest_executable
  
  target_link_libraries(workflow-details-test Gromacs::gmxapi gmxapi-detail)
  
- gmx_register_gtest_test(GmxapiInternalInterfaceTests workflow-details-test INTEGRATION_TEST)
+ gmx_register_gtest_test(GmxapiInternalInterfaceTests workflow-details-test OPENMP_THREADS 2 INTEGRATION_TEST)
  
  set_tests_properties(GmxapiInternalInterfaceTests PROPERTIES
                       WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
@@@ -67,7 -67,4 +67,4 @@@ gmx_add_gtest_executable
  
  target_link_libraries(workflow-details-mpi-test Gromacs::gmxapi gmxapi-detail)
  
- # Tests that specify MPI_RANKS will be passed a ``-ntmpi`` command-line option
- # when GMX_THREAD_MPI is true, but the test executables in this directory do not
- # yet understand that command-line option.
- gmx_register_gtest_test(GmxapiInternalsMpiTests workflow-details-mpi-test MPI_RANKS 2 INTEGRATION_TEST)
+ gmx_register_gtest_test(GmxapiInternalsMpiTests workflow-details-mpi-test MPI_RANKS 2 OPENMP_THREADS 2 INTEGRATION_TEST)
diff --combined src/config.h.cmakein
index 5fdeeb61f10cb78a02c86724c8d1e73f0712188f,c685f264b5e4b23cbc7669b87e945dc1be873a54..2723c0511756b5cb27af8358be7d799c07fd595f
@@@ -1,7 -1,7 +1,7 @@@
  /*
   * This file is part of the GROMACS molecular simulation package.
   *
-- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
++ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019, 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.
  /* Define relative path to OpenCL kernels */
  #define GMX_INSTALL_OCLDIR "@GMX_INSTALL_OCLDIR@"
  
+ /* Minimum required OpenCL version support (both API and device) - split into integer components for convenience */
+ #define REQUIRED_OPENCL_MIN_VERSION_MAJOR @REQUIRED_OPENCL_MIN_VERSION_MAJOR@
+ #define REQUIRED_OPENCL_MIN_VERSION_MINOR @REQUIRED_OPENCL_MIN_VERSION_MINOR@
  /* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
  #cmakedefine01 HAVE_FSEEKO
  
index 753c5d88484c8d3fe15e184db592688d8d4683d3,905de06b728ce30fa7a2f511ed92f5fab6bb7dbc..7105b498c2ec16ef74aaf77eddcb0ff938ee925d
@@@ -1,7 -1,7 +1,7 @@@
  /*
   * This file is part of the GROMACS molecular simulation package.
   *
-- * Copyright (c) 2014,2015,2017,2018, by the GROMACS development team, led by
++ * Copyright (c) 2014,2015,2017,2018,2019, 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.
@@@ -46,7 -46,9 +46,9 @@@
  #include <cassert>
  
  #include "gromacs/hardware/gpu_hw_info.h"
+ #include "gromacs/utility/arrayref.h"
  #include "gromacs/utility/smalloc.h"
+ #include "gromacs/utility/stringutil.h"
  
  #if !GMX_GPU
  /*! \brief Set allocation functions used by the GPU host
@@@ -95,3 -97,33 +97,33 @@@ const char *getGpuCompatibilityDescript
              gpu_detect_res_str[egpuNonexistent] :
              gpu_detect_res_str[gpu_info_get_stat(gpu_info, index)]);
  }
+ /*! \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 == GMX_GPU_NONE)
+     {
+         errorReasons.emplace_back("non-GPU build of GROMACS");
+     }
+     return addMessageIfNotSupported(errorReasons, error);
+ }
index 307cdcd99d90c02daccc48791ecc43a61e33cb68,56047d32c2ac78a04c91b9bd20368d8bc250fc81..9fbde4f09aa287368e70c8abb5ff6be091f6c4eb
@@@ -1,7 -1,7 +1,7 @@@
  /*
   * This file is part of the GROMACS molecular simulation package.
   *
-- * Copyright (c) 2010,2011,2012,2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
++ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019, 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.
@@@ -75,25 -75,26 +75,26 @@@ static __global__ void k_dummy_test(voi
  {
  }
  
- static void checkCompiledTargetCompatibility(const gmx_device_info_t *devInfo)
+ static void checkCompiledTargetCompatibility(int                   deviceId,
+                                              const cudaDeviceProp &deviceProp)
  {
-     assert(devInfo);
      cudaFuncAttributes attributes;
      cudaError_t        stat = cudaFuncGetAttributes(&attributes, k_dummy_test);
  
      if (cudaErrorInvalidDeviceFunction == stat)
      {
          gmx_fatal(FARGS,
-                   "The %s binary does not include support for the CUDA architecture "
-                   "of the selected GPU (device ID #%d, compute capability %d.%d). "
+                   "The %s binary does not include support for the CUDA architecture of "
+                   "the GPU ID #%d (compute capability %d.%d) detected during detection. "
                    "By default, GROMACS supports all architectures of compute "
                    "capability >= 3.0, so your GPU "
                    "might be rare, or some architectures were disabled in the build. "
                    "Consult the install guide for how to use the GMX_CUDA_TARGET_SM and "
-                   "GMX_CUDA_TARGET_COMPUTE CMake variables to add this architecture.",
-                   gmx::getProgramContext().displayName(), devInfo->id,
-                   devInfo->prop.major, devInfo->prop.minor);
+                   "GMX_CUDA_TARGET_COMPUTE CMake variables to add this architecture. "
+                   "To work around this error, use the CUDA_VISIBLE_DEVICES environment"
+                   "variable to pass a list of GPUs that excludes the ID %d.",
+                   gmx::getProgramContext().displayName(), deviceId,
+                   deviceProp.major, deviceProp.minor, deviceId);
      }
  
      CU_RET_ERR(stat, "cudaFuncGetAttributes failed");
@@@ -129,16 -130,14 +130,14 @@@ bool isHostMemoryPinned(const void *h_p
   *
   * Runs a series of checks to determine that the given GPU and underlying CUDA
   * driver/runtime functions properly.
-  * Returns properties of a device with given ID or the one that has
-  * already been initialized earlier in the case if of \dev_id == -1.
   *
   * \param[in]  dev_id      the device ID of the GPU or -1 if the device has already been initialized
-  * \param[out] dev_prop    pointer to the structure in which the device properties will be returned
+  * \param[in]  dev_prop    The device properties structure
   * \returns                0 if the device looks OK
   *
   * TODO: introduce errors codes and handle errors more smoothly.
   */
- static int do_sanity_checks(int dev_id, cudaDeviceProp *dev_prop)
+ static int do_sanity_checks(int dev_id, const cudaDeviceProp &dev_prop)
  {
      cudaError_t cu_err;
      int         dev_count, id;
          }
      }
  
-     memset(dev_prop, 0, sizeof(cudaDeviceProp));
-     cu_err = cudaGetDeviceProperties(dev_prop, id);
-     if (cu_err != cudaSuccess)
-     {
-         fprintf(stderr, "Error %d while querying device properties: %s\n", cu_err,
-                 cudaGetErrorString(cu_err));
-         return -1;
-     }
      /* both major & minor is 9999 if no CUDA capable devices are present */
-     if (dev_prop->major == 9999 && dev_prop->minor == 9999)
+     if (dev_prop.major == 9999 && dev_prop.minor == 9999)
      {
          return -1;
      }
      /* we don't care about emulation mode */
-     if (dev_prop->major == 0)
+     if (dev_prop.major == 0)
      {
          return -1;
      }
      }
  
      /* try to execute a dummy kernel */
+     checkCompiledTargetCompatibility(dev_id, dev_prop);
      KernelLaunchConfig config;
      config.blockSize[0] = 512;
      const auto         dummyArguments = prepareGpuKernelArguments(k_dummy_test, config);
@@@ -252,8 -244,6 +244,6 @@@ void init_gpu(const gmx_device_info_t *
      {
          fprintf(stderr, "Initialized GPU ID #%d: %s\n", deviceInfo->id, deviceInfo->prop.name);
      }
-     checkCompiledTargetCompatibility(deviceInfo);
  }
  
  void free_gpu(const gmx_device_info_t *deviceInfo)
@@@ -300,40 -290,31 +290,31 @@@ gmx_device_info_t *getDeviceInfo(const 
   * \returns             true if the GPU properties passed indicate a compatible
   *                      GPU, otherwise false.
   */
- static bool is_gmx_supported_gpu(const cudaDeviceProp *dev_prop)
+ static bool is_gmx_supported_gpu(const cudaDeviceProp &dev_prop)
  {
-     return (dev_prop->major >= 3);
+     return (dev_prop.major >= 3);
  }
  
  /*! \brief Checks if a GPU with a given ID is supported by the native GROMACS acceleration.
   *
   *  Returns a status value which indicates compatibility or one of the following
-  *  errors: incompatibility, insistence, or insanity (=unexpected behavior).
-  *  It also returns the respective device's properties in \dev_prop (if applicable).
+  *  errors: incompatibility or insanity (=unexpected behavior).
   *
   *  As the error handling only permits returning the state of the GPU, this function
   *  does not clear the CUDA runtime API status allowing the caller to inspect the error
   *  upon return. Note that this also means it is the caller's responsibility to
   *  reset the CUDA runtime state.
   *
-  *  \param[in]  dev_id   the ID of the GPU to check.
-  *  \param[out] dev_prop the CUDA device properties of the device checked.
-  *  \returns             the status of the requested device
+  *  \param[in]  deviceId   the ID of the GPU to check.
+  *  \param[in]  deviceProp the CUDA device properties of the device checked.
+  *  \returns               the status of the requested device
   */
- static int is_gmx_supported_gpu_id(int dev_id, cudaDeviceProp *dev_prop)
+ static int is_gmx_supported_gpu_id(int                   deviceId,
+                                    const cudaDeviceProp &deviceProp)
  {
-     cudaError_t stat;
-     int         ndev;
-     stat = cudaGetDeviceCount(&ndev);
-     if (stat != cudaSuccess)
+     if (!is_gmx_supported_gpu(deviceProp))
      {
-         return egpuInsane;
-     }
-     if (dev_id > ndev - 1)
-     {
-         return egpuNonexistent;
+         return egpuIncompatible;
      }
  
      /* TODO: currently we do not make a distinction between the type of errors
       * the dummy test kernel fails to execute with a "device busy message" we
       * should appropriately report that the device is busy instead of insane.
       */
-     if (do_sanity_checks(dev_id, dev_prop) == 0)
-     {
-         if (is_gmx_supported_gpu(dev_prop))
-         {
-             return egpuCompatible;
-         }
-         else
-         {
-             return egpuIncompatible;
-         }
-     }
-     else
+     if (do_sanity_checks(deviceId, deviceProp) != 0)
      {
          return egpuInsane;
      }
+     return egpuCompatible;
  }
  
  bool canDetectGpus(std::string *errorMessage)
@@@ -432,13 -404,24 +404,24 @@@ void findGpus(gmx_gpu_info_t *gpu_info
      for (int i = 0; i < ndev; i++)
      {
          cudaDeviceProp prop;
-         int            checkres = is_gmx_supported_gpu_id(i, &prop);
+         memset(&prop, 0, sizeof(cudaDeviceProp));
+         stat = cudaGetDeviceProperties(&prop, i);
+         int checkResult;
+         if (stat != cudaSuccess)
+         {
+             // Will handle the error reporting below
+             checkResult = egpuInsane;
+         }
+         else
+         {
+             checkResult = is_gmx_supported_gpu_id(i, prop);
+         }
  
          devs[i].id   = i;
          devs[i].prop = prop;
-         devs[i].stat = checkres;
+         devs[i].stat = checkResult;
  
-         if (checkres == egpuCompatible)
+         if (checkResult == egpuCompatible)
          {
              gpu_info->n_dev_compatible++;
          }
index 69e8ee410cb2ca205c01049f021f68b00410a10f,88058dba56b38a065d5edd1e9aae7172561136f1..6755f1c587929412e3d8ce0f7ab26a4e84184618
@@@ -3,7 -3,7 +3,7 @@@
   *
   * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
   * Copyright (c) 2001-2010, The GROMACS development team.
-- * Copyright (c) 2012,2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
++ * Copyright (c) 2012,2013,2014,2015,2016,2017,2018,2019, 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.
@@@ -249,6 -249,13 +249,13 @@@ void gpu_set_host_malloc_and_free(boo
  //! Get status of device with specified index
  int gpu_info_get_stat(const gmx_gpu_info_t &info, int index);
  
+ /*! \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 a9fea0d2840cef5c4b59761d34e7d2007c55e087,ea49214e7a026b2aed24b8323d7ccb4bdf287319..83536a257113b5abeab70085377ff92ad0b7c0ac
@@@ -1,7 -1,7 +1,7 @@@
  /*
   * This file is part of the GROMACS molecular simulation package.
   *
-- * Copyright (c) 2012,2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
++ * Copyright (c) 2012,2013,2014,2015,2016,2017,2018,2019, 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.
@@@ -38,6 -38,8 +38,8 @@@
   *  \author Anca Hamuraru <anca@streamcomputing.eu>
   *  \author Dimitrios Karkoulis <dimitris.karkoulis@gmail.com>
   *  \author Teemu Virolainen <teemu@streamcomputing.eu>
+  *  \author Mark Abraham <mark.j.abraham@gmail.com>
+  *  \author Szilárd Páll <pall.szilard@gmail.com>
   */
  
  #include "gmxpre.h"
@@@ -48,6 -50,8 +50,8 @@@
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
+ #include <cstdio>
  #ifdef __APPLE__
  #    include <sys/sysctl.h>
  #endif
@@@ -56,6 -60,7 +60,7 @@@
  
  #include "gromacs/gpu_utils/gpu_utils.h"
  #include "gromacs/gpu_utils/ocl_compiler.h"
+ #include "gromacs/gpu_utils/oclraii.h"
  #include "gromacs/gpu_utils/oclutils.h"
  #include "gromacs/hardware/hw_info.h"
  #include "gromacs/utility/cstringutil.h"
@@@ -97,20 -102,141 +102,141 @@@ runningOnCompatibleOSForAmd(
  #endif
  }
  
- /*! \brief Returns true if the gpu characterized by the device properties is
-  *  supported by the native gpu acceleration.
-  * \returns             true if the GPU properties passed indicate a compatible
-  *                      GPU, otherwise false.
+ namespace gmx
+ {
+ /*! \brief Make an error string following an OpenCL API call.
+  *
+  *  It is meant to be called with \p status != CL_SUCCESS, but it will
+  *  work correctly even if it is called with no OpenCL failure.
+  *
+  * \param[in]  message  Supplies context, e.g. the name of the API call that returned the error.
+  * \param[in]  status   OpenCL API status code
+  * \returns             A string describing the OpenCL error.
+  */
+ static std::string
+ makeOpenClInternalErrorString(const char *message, cl_int status)
+ {
+     if (message != nullptr)
+     {
+         return formatString("%s did %ssucceed %d: %s",
+                             message,
+                             ((status != CL_SUCCESS) ? "not " : ""),
+                             status, ocl_get_error_string(status).c_str());
+     }
+     else
+     {
+         return formatString("%sOpenCL error encountered %d: %s",
+                             ((status != CL_SUCCESS) ? "" : "No "),
+                             status, ocl_get_error_string(status).c_str());
+     }
+ }
+ /*!
+  * \brief Checks that device \c devInfo is sane (ie can run a kernel).
+  *
+  * Compiles and runs a dummy kernel to determine whether the given
+  * OpenCL device functions properly.
+  *
+  *
+  * \param[in]  devInfo         The device info pointer.
+  * \param[out] errorMessage    An error message related to a failing OpenCL API call.
+  * \throws     std::bad_alloc  When out of memory.
+  * \returns                    Whether the device passed sanity checks
   */
- static int is_gmx_supported_gpu_id(gmx_device_info_t *ocl_gpu_device)
+ static bool isDeviceSane(const gmx_device_info_t *devInfo,
+                          std::string             *errorMessage)
  {
-     if ((getenv("GMX_OCL_DISABLE_COMPATIBILITY_CHECK")) != nullptr)
+     cl_context_properties properties[] = {
+         CL_CONTEXT_PLATFORM,
+         (cl_context_properties) devInfo->ocl_gpu_id.ocl_platform_id,
+         0
+     };
+     // uncrustify spacing
+     cl_int    status;
+     auto      deviceId = devInfo->ocl_gpu_id.ocl_device_id;
+     ClContext context(clCreateContext(properties, 1, &deviceId, nullptr, nullptr, &status));
+     if (status != CL_SUCCESS)
      {
+         errorMessage->assign(makeOpenClInternalErrorString("clCreateContext", status));
+         return false;
+     }
+     ClCommandQueue commandQueue(clCreateCommandQueue(context, deviceId, 0, &status));
+     if (status != CL_SUCCESS)
+     {
+         errorMessage->assign(makeOpenClInternalErrorString("clCreateCommandQueue", status));
+         return false;
+     }
+     const char *lines[] = { "__kernel void dummyKernel(){}" };
+     ClProgram   program(clCreateProgramWithSource(context, 1, lines, nullptr, &status));
+     if (status != CL_SUCCESS)
+     {
+         errorMessage->assign(makeOpenClInternalErrorString("clCreateProgramWithSource", status));
+         return false;
+     }
+     if ((status = clBuildProgram(program, 0, nullptr, nullptr, nullptr, nullptr)) != CL_SUCCESS)
+     {
+         errorMessage->assign(makeOpenClInternalErrorString("clBuildProgram", status));
+         return false;
+     }
+     ClKernel kernel(clCreateKernel(program, "dummyKernel", &status));
+     if (status != CL_SUCCESS)
+     {
+         errorMessage->assign(makeOpenClInternalErrorString("clCreateKernel", status));
+         return false;
+     }
+     const size_t localWorkSize = 1, globalWorkSize = 1;
+     if ((status =
+              clEnqueueNDRangeKernel(commandQueue, kernel, 1, nullptr,
+                                     &globalWorkSize, &localWorkSize, 0, nullptr, nullptr)) != CL_SUCCESS)
+     {
+         errorMessage->assign(makeOpenClInternalErrorString("clEnqueueNDRangeKernel", status));
+         return false;
+     }
+     return true;
+ }
+ /*!
+  * \brief Checks that device \c devInfo is compatible with GROMACS.
+  *
+  *  Vendor and OpenCL version support checks are executed an the result
+  *  of these returned.
+  *
+  * \param[in]  devInfo         The device info pointer.
+  * \returns                    The result of the compatibility checks.
+  */
+ static int isDeviceSupported(const gmx_device_info_t *devInfo)
+ {
+     if (getenv("GMX_OCL_DISABLE_COMPATIBILITY_CHECK") != nullptr)
+     {
+         // Assume the device is compatible because checking has been disabled.
          return egpuCompatible;
      }
  
+     // OpenCL device version check, ensure >= REQUIRED_OPENCL_MIN_VERSION
+     constexpr unsigned int minVersionMajor = REQUIRED_OPENCL_MIN_VERSION_MAJOR;
+     constexpr unsigned int minVersionMinor = REQUIRED_OPENCL_MIN_VERSION_MINOR;
+     // Based on the OpenCL spec we're checking the version supported by
+     // the device which has the following format:
+     //      OpenCL<space><major_version.minor_version><space><vendor-specific information>
+     unsigned int deviceVersionMinor, deviceVersionMajor;
+     const int    valuesScanned      = std::sscanf(devInfo->device_version, "OpenCL %u.%u", &deviceVersionMajor, &deviceVersionMinor);
+     const bool   versionLargeEnough = ((valuesScanned == 2) &&
+                                        ((deviceVersionMajor > minVersionMajor) ||
+                                         (deviceVersionMajor == minVersionMajor && deviceVersionMinor >= minVersionMinor)));
+     if (!versionLargeEnough)
+     {
+         return egpuIncompatible;
+     }
      /* Only AMD, Intel, and NVIDIA GPUs are supported for now */
-     switch (ocl_gpu_device->vendor_e)
+     switch (devInfo->vendor_e)
      {
          case OCL_VENDOR_NVIDIA:
              return egpuCompatible;
  }
  
  
+ /*! \brief Check whether the \c ocl_gpu_device is suitable for use by mdrun
+  *
+  * Runs sanity checks: checking that the runtime can compile a dummy kernel
+  * and this can be executed;
+  * Runs compatibility checks verifying the device OpenCL version requirement
+  * and vendor/OS support.
+  *
+  * \param[in]  deviceId      The runtime-reported numeric ID of the device.
+  * \param[in]  deviceInfo    The device info pointer.
+  * \returns  An e_gpu_detect_res_t to indicate how the GPU coped with
+  *           the sanity and compatibility check.
+  */
+ static int checkGpu(size_t                   deviceId,
+                     const gmx_device_info_t *deviceInfo)
+ {
+     int supportStatus = isDeviceSupported(deviceInfo);
+     if (supportStatus != egpuCompatible)
+     {
+         return supportStatus;
+     }
+     std::string errorMessage;
+     if (!isDeviceSane(deviceInfo, &errorMessage))
+     {
+         gmx_warning((formatString("While sanity checking device #%zu, ", deviceId) + errorMessage).c_str());
+         return egpuInsane;
+     }
+     return egpuCompatible;
+ }
+ } // namespace
  /*! \brief Returns an ocl_vendor_id_t value corresponding to the input OpenCL vendor name.
   *
   *  \param[in] vendor_name String with OpenCL vendor name.
@@@ -290,7 -451,7 +451,7 @@@ void findGpus(gmx_gpu_info_t *gpu_info
  
                      clGetDeviceInfo(ocl_device_ids[j], CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(size_t), &gpu_info->gpu_dev[device_index].maxWorkGroupSize, nullptr);
  
-                     gpu_info->gpu_dev[device_index].stat = is_gmx_supported_gpu_id(gpu_info->gpu_dev + device_index);
+                     gpu_info->gpu_dev[device_index].stat = gmx::checkGpu(device_index, gpu_info->gpu_dev + device_index);
  
                      if (egpuCompatible == gpu_info->gpu_dev[device_index].stat)
                      {
index 0000000000000000000000000000000000000000,c541623217f740852ef737942784646438cb6c24..227ba844e536cd541ff12cfaf993538aa4c409f4
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,138 +1,138 @@@
 - * Copyright (c) 2018, by the GROMACS development team, led by
+ /*
+  * This file is part of the GROMACS molecular simulation package.
+  *
++ * Copyright (c) 2018,2019, 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.
+  *
+  * GROMACS is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU Lesser General Public License
+  * as published by the Free Software Foundation; either version 2.1
+  * of the License, or (at your option) any later version.
+  *
+  * GROMACS is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * Lesser General Public License for more details.
+  *
+  * You should have received a copy of the GNU Lesser General Public
+  * License along with GROMACS; if not, see
+  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+  *
+  * If you want to redistribute modifications to GROMACS, please
+  * consider that scientific software is very special. Version
+  * control is crucial - bugs must be traceable. We will be happy to
+  * consider code for inclusion in the official distribution, but
+  * derived work must not be called official GROMACS. Details are found
+  * in the README & COPYING files - if they are missing, get the
+  * official version at http://www.gromacs.org.
+  *
+  * To help us fund GROMACS development, we humbly ask that you cite
+  * the research papers on the package. Check out http://www.gromacs.org.
+  */
+ /*! \libinternal \file
+  * \brief Declare RAII helpers for OpenCL types, along with
+  * supporting type traits.
+  *
+  * \author Mark Abraham <mark.j.abraham@gmail.com>
+  * \inlibraryapi
+  */
+ #ifndef GMX_GPU_UTILS_OCLRAII_H
+ #define GMX_GPU_UTILS_OCLRAII_H
+ #include "gromacs/gpu_utils/gmxopencl.h"
+ namespace gmx
+ {
+ /*! \libinternal \brief Stub for OpenCL type traits */
+ template <typename cl_type>
+ struct OpenClTraits;
+ /*! \libinternal \brief Implements common trait infrastructure for OpenCL types. */
+ template <typename cl_type>
+ struct OpenClTraitsBase
+ {
+     //! Type of the function that will release a handle of this type.
+     using ReleaserType = cl_int(*)(cl_type);
+ };
+ /*! \libinternal \brief Implements traits for cl_context. */
+ template <>
+ struct OpenClTraits<cl_context> : public OpenClTraitsBase<cl_context>
+ {
+     //! Function that will release a handle of this type.
+     static constexpr ReleaserType releaser = clReleaseContext;
+ };
+ /*! \libinternal \brief Implements traits for cl_command_queue. */
+ template <>
+ struct OpenClTraits<cl_command_queue> : public OpenClTraitsBase<cl_command_queue>
+ {
+     //! Function that will release a handle of this type.
+     static constexpr ReleaserType releaser = clReleaseCommandQueue;
+ };
+ /*! \libinternal \brief Implements traits for cl_program. */
+ template <>
+ struct OpenClTraits<cl_program> : public OpenClTraitsBase<cl_program>
+ {
+     //! Function that will release a handle of this type.
+     static constexpr ReleaserType releaser = clReleaseProgram;
+ };
+ /*! \libinternal \brief Implements traits for cl_kernel. */
+ template <>
+ struct OpenClTraits<cl_kernel> : public OpenClTraitsBase<cl_kernel>
+ {
+     //! Function that will release a handle of this type.
+     static constexpr ReleaserType releaser = clReleaseKernel;
+ };
+ /*! \libinternal \brief Wrapper of OpenCL type \c cl_type to implement RAII.
+  *
+  * Works by calling the releaser function associated with cl_type
+  * by OpenClTraits.
+  *
+  * Simple copying and assignment are not supported, because there's no
+  * need for that, and would require OpenCL API calls for deep copies
+  * if they were needed. Move and move assignment are fine, however. */
+ template <typename cl_type>
+ class ClHandle
+ {
+     public:
+         //! Constructor that takes an already created handle.
+         explicit ClHandle(cl_type handle) : handle_(handle) {}
+         //! Destructor that calls the releaser associated with cl_type.
+         ~ClHandle() { OpenClTraits<cl_type>::releaser(handle_); }
+         //! Deleted default constructor.
+         ClHandle()                            = delete;
+         //! Deleted assignment operator.
+         ClHandle &operator=(const ClHandle &) = delete;
+         //! Deleted copy constructor.
+         ClHandle(const ClHandle &)            = delete;
+         //! Default move assignment operator.
+         ClHandle &operator=(ClHandle &&)      = default;
+         //! Default copy constructor.
+         ClHandle(ClHandle &&)                 = default;
+         /*! \brief Convenience conversion operator so the wrapper type
+          * can simply convert to the wrapped type. */
+         operator cl_type() const { return handle_; }
+     private:
+         //! The wrapped object.
+         cl_type handle_;
+ };
+ //! Convenience declarations.
+ /*! @{ */
+ using ClContext      = ClHandle<cl_context>;
+ using ClCommandQueue = ClHandle<cl_command_queue>;
+ using ClProgram      = ClHandle<cl_program>;
+ using ClKernel       = ClHandle<cl_kernel>;
+ /*! @} */
+ } // namespace
+ #endif
index 85fac9fa337f725876684c61f46b8c78f9630e23,2069668f825ad96a769946eb973f127b6ca77281..f87fe607c78bb4a3e948d70e9fd10fdcae56a969
@@@ -3,7 -3,7 +3,7 @@@
   *
   * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
   * Copyright (c) 2001-2004, The GROMACS development team.
-- * Copyright (c) 2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
++ * Copyright (c) 2013,2014,2015,2016,2017,2018,2019, 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.
@@@ -445,7 -445,7 +445,7 @@@ static int lcd4(int i1, int i2, int i3
      return nst;
  }
  
- int check_nstglobalcomm(const gmx::MDLogger &mdlog, int nstglobalcomm, t_inputrec *ir)
+ int check_nstglobalcomm(const gmx::MDLogger &mdlog, int nstglobalcomm, t_inputrec *ir, const t_commrec * cr)
  {
      if (!EI_DYNAMICS(ir->eI))
      {
          ir->nstcomm = nstglobalcomm;
      }
  
-     GMX_LOG(mdlog.info).appendTextFormatted(
-             "Intra-simulation communication will occur every %d steps.\n", nstglobalcomm);
+     if (cr->nnodes > 1)
+     {
+         GMX_LOG(mdlog.info).appendTextFormatted(
+                 "Intra-simulation communication will occur every %d steps.\n", nstglobalcomm);
+     }
      return nstglobalcomm;
  }
  
  void rerun_parallel_comm(t_commrec *cr, t_trxframe *fr,
index 5e57ce7c19906e6fab79023a62c2d7113c791401,b45012de168ee48eb9d001805d8ad4e06ca90389..eb6c45d615ceeef5f7d98b885a33a65458b6a4fe
@@@ -3,7 -3,7 +3,7 @@@
   *
   * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
   * Copyright (c) 2001-2004, The GROMACS development team.
-- * Copyright (c) 2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
++ * Copyright (c) 2013,2014,2015,2016,2017,2018,2019, 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.
@@@ -95,7 -95,8 +95,8 @@@ class SimulationSignaller
   * inputrec and the value of mdrun -gcom. */
  int check_nstglobalcomm(const gmx::MDLogger &mdlog,
                          int                  nstglobalcomm,
-                         t_inputrec          *ir);
+                         t_inputrec          *ir,
+                         const t_commrec    * cr);
  
  /*! \brief Return true if the \p value is equal across the set of multi-simulations
   *
index 80aba49efa53b8d1f1d02cdd4309c62aba835495,af0e485c75713fe5e221bf3fcb09213a955b8671..2f6c8aedf45f1b367b34a8eb436d3deaff6e89fc
@@@ -3,7 -3,7 +3,7 @@@
   *
   * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
   * Copyright (c) 2001-2004, The GROMACS development team.
-- * Copyright (c) 2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
++ * Copyright (c) 2013,2014,2015,2016,2017,2018,2019, 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.
@@@ -43,7 -43,6 +43,7 @@@
  
  #include <algorithm>
  
 +#include "gromacs/compat/make_unique.h"
  #include "gromacs/domdec/domdec_struct.h"
  #include "gromacs/fileio/confio.h"
  #include "gromacs/gmxlib/network.h"
@@@ -93,25 -92,22 +93,25 @@@ typedef struct 
      real V;
  } gmx_sd_sigma_t;
  
 -typedef struct {
 +struct gmx_stochd_t
 +{
      /* BD stuff */
 -    real           *bd_rf;
 +    std::vector<real>           bd_rf;
      /* SD stuff */
 -    gmx_sd_const_t *sdc;
 -    gmx_sd_sigma_t *sdsig;
 +    std::vector<gmx_sd_const_t> sdc;
 +    std::vector<gmx_sd_sigma_t> sdsig;
      /* andersen temperature control stuff */
 -    gmx_bool       *randomize_group;
 -    real           *boltzfac;
 -} gmx_stochd_t;
 +    std::vector<bool>           randomize_group;
 +    std::vector<real>           boltzfac;
 +
 +    gmx_stochd_t(const t_inputrec *ir);
 +};
  
  struct gmx_update_t
  {
 -    gmx_stochd_t           *sd;
 +    std::unique_ptr<gmx_stochd_t> sd;
      /* xprime for constraint algorithms */
 -    PaddedVector<gmx::RVec> xp;
 +    PaddedVector<gmx::RVec>       xp;
  
      /* Variables for the deform algorithm */
      int64_t           deformref_step;
@@@ -452,6 -448,8 +452,8 @@@ updateMDLeapfrogGeneral(in
      int  gt       = 0;
      real factorNH = 0;
  
+     real omega_Z  = 2*static_cast<real>(M_PI)/box[ZZ][ZZ];
      for (int n = start; n < nrend; n++)
      {
          if (cTC)
                  rvec_sub(v[n], grpstat[ga].u, vRel);
                  break;
              case AccelerationType::cosine:
-                 cosineZ = std::cos(x[n][ZZ]*static_cast<real>(M_PI)/box[ZZ][ZZ]);
+                 cosineZ = std::cos(x[n][ZZ]*omega_Z);
                  vCosine = cosineZ*ekind->cosacc.vcos;
                  /* Avoid scaling the cosine profile velocity */
                  copy_rvec(v[n], vRel);
@@@ -767,19 -765,25 +769,19 @@@ static void do_update_vv_pos(int start
      }
  } /* do_update_vv_pos */
  
 -static gmx_stochd_t *init_stochd(const t_inputrec *ir)
 +gmx_stochd_t::gmx_stochd_t(const t_inputrec *ir)
  {
 -    gmx_stochd_t   *sd;
 -
 -    snew(sd, 1);
 -
      const t_grpopts *opts = &ir->opts;
 -    int              ngtc = opts->ngtc;
 +    const int        ngtc = opts->ngtc;
  
      if (ir->eI == eiBD)
      {
 -        snew(sd->bd_rf, ngtc);
 +        bd_rf.resize(ngtc);
      }
      else if (EI_SD(ir->eI))
      {
 -        snew(sd->sdc, ngtc);
 -        snew(sd->sdsig, ngtc);
 -
 -        gmx_sd_const_t *sdc = sd->sdc;
 +        sdc.resize(ngtc);
 +        sdsig.resize(ngtc);
  
          for (int gt = 0; gt < ngtc; gt++)
          {
      }
      else if (ETC_ANDERSEN(ir->etc))
      {
 -        snew(sd->randomize_group, ngtc);
 -        snew(sd->boltzfac, ngtc);
 +        randomize_group.resize(ngtc);
 +        boltzfac.resize(ngtc);
  
          /* for now, assume that all groups, if randomized, are randomized at the same rate, i.e. tau_t is the same. */
          /* since constraint groups don't necessarily match up with temperature groups! This is checked in readir.c */
              real reft = std::max<real>(0, opts->ref_t[gt]);
              if ((opts->tau_t[gt] > 0) && (reft > 0))  /* tau_t or ref_t = 0 means that no randomization is done */
              {
 -                sd->randomize_group[gt] = TRUE;
 -                sd->boltzfac[gt]        = BOLTZ*opts->ref_t[gt];
 +                randomize_group[gt] = true;
 +                boltzfac[gt]        = BOLTZ*opts->ref_t[gt];
              }
              else
              {
 -                sd->randomize_group[gt] = FALSE;
 +                randomize_group[gt] = false;
              }
          }
      }
 -
 -    return sd;
  }
  
  void update_temperature_constants(gmx_update_t *upd, const t_inputrec *ir)
@@@ -853,7 -859,10 +855,7 @@@ gmx_update_t *init_update(const t_input
  {
      gmx_update_t *upd = new(gmx_update_t);
  
 -    if (ir->eI == eiBD || EI_SD(ir->eI) || ir->etc == etcVRESCALE || ETC_ANDERSEN(ir->etc))
 -    {
 -        upd->sd    = init_stochd(ir);
 -    }
 +    upd->sd    = gmx::compat::make_unique<gmx_stochd_t>(ir);
  
      update_temperature_constants(upd, ir);
  
@@@ -892,7 -901,7 +894,7 @@@ enum class SDUpdate : in
   * two with only one contribution, and one with both contributions. */
  template <SDUpdate updateType>
  static void
 -doSDUpdateGeneral(gmx_stochd_t *sd,
 +doSDUpdateGeneral(const gmx_stochd_t &sd,
                    int start, int nrend, real dt,
                    const rvec accel[], const ivec nFreeze[],
                    const real invmass[], const unsigned short ptype[],
      gmx::ThreeFry2x64<0> rng(seed, gmx::RandomDomain::UpdateCoordinates);
      gmx::TabulatedNormalDistribution<real, 14> dist;
  
 -    gmx_sd_const_t *sdc = sd->sdc;
 -    gmx_sd_sigma_t *sig = sd->sdsig;
 -
      for (int n = start; n < nrend; n++)
      {
          int globalAtomIndex = gatindex ? gatindex[n] : n;
                  else if (updateType == SDUpdate::FrictionAndNoiseOnly)
                  {
                      real vn      = v[n][d];
 -                    v[n][d]      = (vn*sdc[temperatureGroup].em +
 -                                    invsqrtMass*sig[temperatureGroup].V*dist(rng));
 +                    v[n][d]      = (vn*sd.sdc[temperatureGroup].em +
 +                                    invsqrtMass*sd.sdsig[temperatureGroup].V*dist(rng));
                      // The previous phase already updated the
                      // positions with a full v*dt term that must
                      // now be half removed.
                  else
                  {
                      real vn      = v[n][d] + (inverseMass*f[n][d] + accel[accelerationGroup][d])*dt;
 -                    v[n][d]      = (vn*sdc[temperatureGroup].em +
 -                                    invsqrtMass*sig[temperatureGroup].V*dist(rng));
 +                    v[n][d]      = (vn*sd.sdc[temperatureGroup].em +
 +                                    invsqrtMass*sd.sdsig[temperatureGroup].V*dist(rng));
                      // Here we include half of the friction+noise
                      // update of v into the position update.
                      xprime[n][d] = x[n][d] + 0.5*(vn + v[n][d])*dt;
@@@ -1558,7 -1570,7 +1560,7 @@@ update_sd_second_half(int64_
                  getThreadAtomRange(nth, th, homenr, &start_th, &end_th);
  
                  doSDUpdateGeneral<SDUpdate::FrictionAndNoiseOnly>
 -                    (upd->sd,
 +                    (*upd->sd,
                      start_th, end_th, dt,
                      inputrec->opts.acc, inputrec->opts.nFreeze,
                      md->invmass, md->ptype,
@@@ -1836,7 -1848,7 +1838,7 @@@ void update_coords(int64_
                      {
                          // With constraints, the SD update is done in 2 parts
                          doSDUpdateGeneral<SDUpdate::ForcesOnly>
 -                            (upd->sd,
 +                            (*upd->sd,
                              start_th, end_th, dt,
                              inputrec->opts.acc, inputrec->opts.nFreeze,
                              md->invmass, md->ptype,
                      else
                      {
                          doSDUpdateGeneral<SDUpdate::Combined>
 -                            (upd->sd,
 +                            (*upd->sd,
                              start_th, end_th, dt,
                              inputrec->opts.acc, inputrec->opts.nFreeze,
                              md->invmass, md->ptype,
                                   md->cFREEZE, md->cTC,
                                   x_rvec, xp_rvec, v_rvec, f_rvec,
                                   inputrec->bd_fric,
 -                                 upd->sd->bd_rf,
 +                                 upd->sd->bd_rf.data(),
                                   step, inputrec->ld_seed, DOMAINDECOMP(cr) ? cr->dd->globalAtomIndices.data() : nullptr);
                      break;
                  case (eiVV):
@@@ -1930,8 -1942,7 +1932,8 @@@ extern gmx_bool update_randomize_veloci
      if ((ir->etc == etcANDERSEN) || do_per_step(step, roundToInt(1.0/rate)))
      {
          andersen_tcoupl(ir, step, cr, md, v, rate,
 -                        upd->sd->randomize_group, upd->sd->boltzfac);
 +                        upd->sd->randomize_group,
 +                        upd->sd->boltzfac);
          return TRUE;
      }
      return FALSE;
diff --combined src/gromacs/mdrun/md.cpp
index 050eb74284e51bdc810545131d7d775866fb6db0,a49a15df53a4246970f4f4a00e542f1c9a7cedbe..7da1d2e46bf8176fb3a516ef755c00629ab87d99
@@@ -3,7 -3,7 +3,7 @@@
   *
   * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
   * Copyright (c) 2001-2004, The GROMACS development team.
-- * Copyright (c) 2011,2012,2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
++ * Copyright (c) 2011,2012,2013,2014,2015,2016,2017,2018,2019, 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.
@@@ -192,6 -192,7 +192,6 @@@ void gmx::Integrator::do_md(
      real                    saved_conserved_quantity = 0;
      real                    last_ekin                = 0;
      t_extmass               MassQ;
 -    int                   **trotter_seq;
      char                    sbuf[STEPSTRSIZE], sbuf2[STEPSTRSIZE];
  
      /* PME load balancing data for GPU kernels */
      const bool bRerunMD      = false;
      int        nstglobalcomm = mdrunOptions.globalCommunicationInterval;
  
-     nstglobalcomm   = check_nstglobalcomm(mdlog, nstglobalcomm, ir);
+     nstglobalcomm   = check_nstglobalcomm(mdlog, nstglobalcomm, ir, cr);
      bGStatEveryStep = (nstglobalcomm == 1);
  
      groups = &top_global->groups;
  
      /* need to make an initiation call to get the Trotter variables set, as well as other constants for non-trotter
         temperature control */
 -    trotter_seq = init_npt_vars(ir, state, &MassQ, bTrotter);
 +    auto trotter_seq = init_npt_vars(ir, state, &MassQ, bTrotter);
  
      if (MASTER(cr))
      {
      walltime_accounting_set_nsteps_done(walltime_accounting, step_rel);
  
      destroy_enerdata(enerd);
 +
      sfree(enerd);
 +
 +    global_stat_destroy(gstat);
 +
 +    /* Clean up topology. top->atomtypes has an allocated pointer if no domain decomposition*/
 +    if (!DOMAINDECOMP(cr))
 +    {
 +        done_atomtypes(&top->atomtypes);
 +    }
      sfree(top);
  }
index 81ae467a68d7c03153a299c4578d95495b51852b,110c9e3c3720b31a89c1e9317dd674f2383000cd..6f2657b02f3f6c2ccab52eec797b154dc164972d
@@@ -3,7 -3,7 +3,7 @@@
   *
   * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
   * Copyright (c) 2001-2004, The GROMACS development team.
-- * Copyright (c) 2011,2012,2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
++ * Copyright (c) 2011,2012,2013,2014,2015,2016,2017,2018,2019, 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.
@@@ -614,9 -614,10 +614,10 @@@ int Mdrunner::mdrunner(
              // If the user specified the number of ranks, then we must
              // respect that, but in default mode, we need to allow for
              // the number of GPUs to choose the number of ranks.
+             auto canUseGpuForNonbonded = buildSupportsNonbondedOnGpu(nullptr);
              useGpuForNonbonded = decideWhetherToUseGpusForNonbondedWithThreadMpi
                      (nonbondedTarget, gpuIdsToUse, userGpuTaskAssignment, emulateGpuNonbonded,
+                     canUseGpuForNonbonded,
                      inputrec->cutoff_scheme == ecutsVERLET,
                      gpuAccelerationOfNonbondedIsUseful(mdlog, inputrec, GMX_THREAD_MPI),
                      hw_opt.nthreads_tmpi);
          // different nodes, which is the user's responsibilty to
          // handle. If unsuitable, we will notice that during task
          // assignment.
-         bool gpusWereDetected  = hwinfo->ngpu_compatible_tot > 0;
-         bool usingVerletScheme = inputrec->cutoff_scheme == ecutsVERLET;
+         bool gpusWereDetected      = hwinfo->ngpu_compatible_tot > 0;
+         bool usingVerletScheme     = inputrec->cutoff_scheme == ecutsVERLET;
+         auto canUseGpuForNonbonded = buildSupportsNonbondedOnGpu(nullptr);
          useGpuForNonbonded = decideWhetherToUseGpusForNonbonded(nonbondedTarget, userGpuTaskAssignment,
-                                                                 emulateGpuNonbonded, usingVerletScheme,
+                                                                 emulateGpuNonbonded,
+                                                                 canUseGpuForNonbonded,
+                                                                 usingVerletScheme,
                                                                  gpuAccelerationOfNonbondedIsUseful(mdlog, inputrec, !GMX_THREAD_MPI),
                                                                  gpusWereDetected);
          auto canUseGpuForPme   = pme_gpu_supports_build(*hwinfo, nullptr) && pme_gpu_supports_input(*inputrec, mtop, nullptr);
                 pmedata,
                 EI_DYNAMICS(inputrec->eI) && !isMultiSim(ms));
  
 +    // clean up cycle counter
 +    wallcycle_destroy(wcycle);
 +
      // Free PME data
      if (pmedata)
      {
         wait for that. */
      if (PAR(cr) && MASTER(cr))
      {
 -        done_commrec(cr);
          tMPI_Finalize();
      }
 +    //TODO free commrec in MPI simulations
 +    done_commrec(cr);
  #endif
 -
      return rc;
  }
  
index 4488f8d5893dc47df9cbda9e294669a9b52c2ec0,8e74f9b0872cebae8854770b08175478032226d3..b10f236a1e61247a3d2e771e00780fab42083120
@@@ -1,7 -1,7 +1,7 @@@
  /*
   * This file is part of the GROMACS molecular simulation package.
   *
-- * Copyright (c) 2015,2016,2017,2018, by the GROMACS development team, led by
++ * Copyright (c) 2015,2016,2017,2018,2019, 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.
@@@ -105,6 -105,7 +105,7 @@@ decideWhetherToUseGpusForNonbondedWithT
                                                  const std::vector<int>   &gpuIdsToUse,
                                                  const std::vector<int>   &userGpuTaskAssignment,
                                                  const EmulateGpuNonbonded emulateGpuNonbonded,
+                                                 const bool                buildSupportsNonbondedOnGpu,
                                                  const bool                usingVerletScheme,
                                                  const bool                nonbondedOnGpuIsUseful,
                                                  const int                 numRanksPerSimulation)
      if (nonbondedTarget == TaskTarget::Cpu ||
          emulateGpuNonbonded == EmulateGpuNonbonded::Yes ||
          !usingVerletScheme ||
-         !nonbondedOnGpuIsUseful)
+         !nonbondedOnGpuIsUseful ||
+         !buildSupportsNonbondedOnGpu)
      {
          // If the user required NB on GPUs, we issue an error later.
          return false;
@@@ -235,6 -237,7 +237,7 @@@ decideWhetherToUseGpusForPmeWithThreadM
  bool decideWhetherToUseGpusForNonbonded(const TaskTarget           nonbondedTarget,
                                          const std::vector<int>    &userGpuTaskAssignment,
                                          const EmulateGpuNonbonded  emulateGpuNonbonded,
+                                         const bool                 buildSupportsNonbondedOnGpu,
                                          const bool                 usingVerletScheme,
                                          const bool                 nonbondedOnGpuIsUseful,
                                          const bool                 gpusWereDetected)
          return false;
      }
  
+     if (!buildSupportsNonbondedOnGpu && nonbondedTarget == TaskTarget::Gpu)
+     {
+         GMX_THROW(InconsistentInputError
+                       ("Nonbonded interactions on the GPU were requested with -nb gpu, "
+                       "but the GROMACS binary has been built without GPU support. "
+                       "Either run without selecting GPU options, or recompile GROMACS "
+                       "with GPU support enabled"));
+     }
      // TODO refactor all these TaskTarget::Gpu checks into one place?
      // e.g. use a subfunction that handles only the cases where
      // TaskTargets are not Cpu?
index 3f67d36f3dd278e09508bcab74f08474e54b900e,34e61ffa9284bafb42da9d761200548990e33906..ac2fe27478218d17c854e43ad788fb9073f12e98
@@@ -1,7 -1,7 +1,7 @@@
  /*
   * This file is part of the GROMACS molecular simulation package.
   *
-- * Copyright (c) 2017,2018, by the GROMACS development team, led by
++ * Copyright (c) 2017,2018,2019, 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.
@@@ -68,11 -68,12 +68,12 @@@ enum class TaskTarget : in
   * user. So we need to consider this before any automated choice of
   * the number of thread-MPI ranks.
   *
-  * \param[in]  nonbondedTarget           The user's choice for mdrun -nb for where to assign short-ranged nonbonded interaction tasks.
-  * \param[in]  gpuIdsToUse               The compatible GPUs that the user permitted us to use.
-  * \param[in]  userGpuTaskAssignment     The user-specified assignment of GPU tasks to device IDs.
-  * \param[in]  emulateGpuNonbonded       Whether we will emulate GPU calculation of nonbonded interactions.
-  * \param[in]  usingVerletScheme         Whether the nonbondeds are using the Verlet scheme.
+  * \param[in]  nonbondedTarget             The user's choice for mdrun -nb for where to assign short-ranged nonbonded interaction tasks.
+  * \param[in]  gpuIdsToUse                 The compatible GPUs that the user permitted us to use.
+  * \param[in]  userGpuTaskAssignment       The user-specified assignment of GPU tasks to device IDs.
+  * \param[in]  emulateGpuNonbonded         Whether we will emulate GPU calculation of nonbonded interactions.
+  * \param[in]  buildSupportsNonbondedOnGpu Whether GROMACS was built with GPU support.
+  * \param[in]  usingVerletScheme           Whether the nonbondeds are using the Verlet scheme.
   * \param[in]  nonbondedOnGpuIsUseful    Whether computing nonbonded interactions on a GPU is useful for this calculation.
   * \param[in]  numRanksPerSimulation     The number of ranks in each simulation.
   *
   *
   * \throws     std::bad_alloc          If out of memory
   *             InconsistentInputError  If the user requirements are inconsistent. */
- bool decideWhetherToUseGpusForNonbondedWithThreadMpi(TaskTarget                nonbondedTarget,
-                                                      const std::vector<int>   &gpuIdsToUse,
-                                                      const std::vector<int>   &userGpuTaskAssignment,
-                                                      EmulateGpuNonbonded       emulateGpuNonbonded,
-                                                      bool                      usingVerletScheme,
-                                                      bool                      nonbondedOnGpuIsUseful,
-                                                      int                       numRanksPerSimulation);
+ bool decideWhetherToUseGpusForNonbondedWithThreadMpi(TaskTarget              nonbondedTarget,
+                                                      const std::vector<int> &gpuIdsToUse,
+                                                      const std::vector<int> &userGpuTaskAssignment,
+                                                      EmulateGpuNonbonded     emulateGpuNonbonded,
+                                                      bool                    buildSupportsNonbondedOnGpu,
+                                                      bool                    usingVerletScheme,
+                                                      bool                    nonbondedOnGpuIsUseful,
+                                                      int                     numRanksPerSimulation);
  
  /*! \brief Decide whether this thread-MPI simulation will run
   * PME tasks on GPUs.
@@@ -132,23 -134,25 +134,25 @@@ bool decideWhetherToUseGpusForPmeWithTh
   * decision is made in this routine, along with many more
   * consistency checks.
   *
-  * \param[in]  nonbondedTarget           The user's choice for mdrun -nb for where to assign short-ranged nonbonded interaction tasks.
-  * \param[in]  userGpuTaskAssignment     The user-specified assignment of GPU tasks to device IDs.
-  * \param[in]  emulateGpuNonbonded       Whether we will emulate GPU calculation of nonbonded interactions.
-  * \param[in]  usingVerletScheme         Whether the nonbondeds are using the Verlet scheme.
-  * \param[in]  nonbondedOnGpuIsUseful    Whether computing nonbonded interactions on a GPU is useful for this calculation.
-  * \param[in]  gpusWereDetected          Whether compatible GPUs were detected on any node.
+  * \param[in]  nonbondedTarget             The user's choice for mdrun -nb for where to assign short-ranged nonbonded interaction tasks.
+  * \param[in]  userGpuTaskAssignment       The user-specified assignment of GPU tasks to device IDs.
+  * \param[in]  emulateGpuNonbonded         Whether we will emulate GPU calculation of nonbonded interactions.
+  * \param[in]  buildSupportsNonbondedOnGpu Whether GROMACS was build with GPU support.
+  * \param[in]  usingVerletScheme           Whether the nonbondeds are using the Verlet scheme.
+  * \param[in]  nonbondedOnGpuIsUseful      Whether computing nonbonded interactions on a GPU is useful for this calculation.
+  * \param[in]  gpusWereDetected            Whether compatible GPUs were detected on any node.
   *
   * \returns    Whether the simulation will run nonbonded and PME tasks, respectively, on GPUs.
   *
   * \throws     std::bad_alloc          If out of memory
   *             InconsistentInputError  If the user requirements are inconsistent. */
- bool decideWhetherToUseGpusForNonbonded(TaskTarget                 nonbondedTarget,
-                                         const std::vector<int>    &userGpuTaskAssignment,
-                                         EmulateGpuNonbonded        emulateGpuNonbonded,
-                                         bool                       usingVerletScheme,
-                                         bool                       nonbondedOnGpuIsUseful,
-                                         bool                       gpusWereDetected);
+ bool decideWhetherToUseGpusForNonbonded(TaskTarget              nonbondedTarget,
+                                         const std::vector<int> &userGpuTaskAssignment,
+                                         EmulateGpuNonbonded     emulateGpuNonbonded,
+                                         bool                    buildSupportsNonbondedOnGpu,
+                                         bool                    usingVerletScheme,
+                                         bool                    nonbondedOnGpuIsUseful,
+                                         bool                    gpusWereDetected);
  
  /*! \brief Decide whether the simulation will try to run tasks of
   * different types on GPUs.
index 46757699746271b829c049a49ab2027b0cb399f5,b5644feae4b6b7509c5b53b2b9ae5f0668f84218..6778a9d48463a70ff78d145820fde57e24877d42
@@@ -2,7 -2,7 +2,7 @@@
   * This file is part of the GROMACS molecular simulation package.
   *
   * Copyright (c) 1991-2006 David van der Spoel, Erik Lindahl, Berk Hess, University of Groningen.
-  * Copyright (c) 2013,2014,2015,2016,2017, by the GROMACS development team, led by
 - * Copyright (c) 2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
++ * Copyright (c) 2013,2014,2015,2016,2017,2018,2019, 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.
@@@ -48,6 -48,8 +48,8 @@@
  #include <windows.h>
  #endif
  
+ #include "gromacs/utility/basedefinitions.h"
  /*! \brief Calculate number of seconds per cycle tick on host
   *
   *  This routine runs a timer loop to calibrate the number of
@@@ -140,5 -142,6 +142,6 @@@ gmx_cycles_calibrate(double sampletime
  #else
      /* No timing function available */
      return -1;
+     GMX_UNUSED_VALUE(sampletime);
  #endif
  }