Merge branch release-2016
authorMark Abraham <mark.j.abraham@gmail.com>
Sat, 14 Jan 2017 20:58:57 +0000 (21:58 +0100)
committerMark Abraham <mark.j.abraham@gmail.com>
Sat, 14 Jan 2017 21:21:56 +0000 (22:21 +0100)
Retained master branch version of fixes for ICC on windows.

Preserved the fix for 2efc195a97f92 despite refactoring of init_em.

Change-Id: Iae54ac040cb2d72d38b0bf3a0a762a9384e4c02d

12 files changed:
1  2 
CMakeLists.txt
cmake/FindFFTW.cmake
cmake/gmxCFlags.cmake
cmake/gmxManagePluginSupport.cmake
cmake/gmxTestCXX11.cmake
src/gromacs/domdec/domdec_topology.cpp
src/gromacs/gmxana/gmx_anaeig.cpp
src/gromacs/gmxana/gmx_covar.cpp
src/gromacs/gmxana/gmx_editconf.cpp
src/gromacs/gmxana/gmx_nmeig.cpp
src/gromacs/gmxana/gmx_tune_pme.cpp
src/gromacs/mdlib/minimize.cpp

diff --combined CMakeLists.txt
index 4f0181e0827cab82ae009e815038340e338a36ed,9864bd500cf85dfeadeb64652ce0f2917b5005cf..8aa1f796a1351daa8bc819ecb0e30ebabde3e712
@@@ -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, by the GROMACS development team, led by
++# Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016,2017, 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.
  # To help us fund GROMACS development, we humbly ask that you cite
  # the research papers on the package. Check out http://www.gromacs.org.
  
 -cmake_minimum_required(VERSION 2.8.8)
 -# When we require cmake >= 2.8.12, it will provide
 -# CMAKE_MINIMUM_REQUIRED_VERSION automatically, but in the meantime we
 -# need to set a variable, and it must have a different name.
 -set(GMX_CMAKE_MINIMUM_REQUIRED_VERSION "2.8.8")
 +cmake_minimum_required(VERSION 3.4.3)
  
  # CMake modules/macros are in a subdirectory to keep this file cleaner
  # This needs to be set before project() in order to pick up toolchain files
@@@ -66,10 -70,11 +66,10 @@@ include(gmxBuildTypeMSAN
  include(gmxBuildTypeReleaseWithAssert)
  
  if(NOT CMAKE_BUILD_TYPE)
 -    set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel Reference RelWithAssert Profile." FORCE)
 -    # There's no need to offer a user the choice of ThreadSanitizer
 +    set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel Reference RelWithAssert Profile TSAN ASAN MSAN." FORCE)
      # Set the possible values of build type for cmake-gui
      set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
 -        "MinSizeRel" "RelWithDebInfo" "Reference" "RelWithAssert" "Profile")
 +        "MinSizeRel" "RelWithDebInfo" "Reference" "RelWithAssert" "Profile" "TSAN" "ASAN" "MSAN")
  endif()
  if(CMAKE_CONFIGURATION_TYPES)
      # Add appropriate GROMACS-specific build types for the Visual
@@@ -85,8 -90,14 +85,8 @@@ set(build_types_with_explicit_flags REL
  
  set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS ON)
  
 -# Set a default valgrind suppression file.
 -# This unfortunately needs to duplicate information from CTest to work as
 -# expected...
 -set(MEMORYCHECK_SUPPRESSIONS_FILE
 -    "${CMAKE_SOURCE_DIR}/cmake/legacy_and_external.supp"
 -    CACHE FILEPATH
 -    "File that contains suppressions for the memory checker")
 -include(CTest)
 +include(gmxCTestUtilities)
 +gmx_ctest_init()
  
  include(gmxCPackUtilities)
  gmx_cpack_init()
@@@ -186,16 -197,12 +186,16 @@@ gmx_add_cache_dependency(GMX_COOL_QUOTE
  
  option(GMX_USE_OPENCL "Enable OpenCL acceleration" OFF)
  
 -# Decide on GPU settings based on user-settings and GPU/CUDA detection.
 -# GCC 4.6 requires CUDA 5.0 and VS2015 requires CUDA 8.0
 +# Decide on GPU settings based on user-settings and GPU/CUDA
 +# detection.  GCC 4.8 requires CUDA 6.0 (but we choose 6.5 for the
 +# preliminary C++11 support), icc 15 requires CUDA 7.0, and VS2015
 +# requires CUDA 8.0
  if(MSVC)
      set(REQUIRED_CUDA_VERSION 8.0)
 +elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel")
 +    set(REQUIRED_CUDA_VERSION 7.0)
  else()
 -    set(REQUIRED_CUDA_VERSION 5.0)
 +    set(REQUIRED_CUDA_VERSION 6.5)
  endif()
  set(REQUIRED_CUDA_COMPUTE_CAPABILITY 2.0)
  
@@@ -267,8 -274,6 +267,6 @@@ gmx_dependent_cache_variable(GMX_SIMD_R
  
  option(GMX_BROKEN_CALLOC "Work around broken calloc()" OFF)
  mark_as_advanced(GMX_BROKEN_CALLOC)
- option(GMX_LOAD_PLUGINS "Compile with plugin support, needed to read VMD supported file formats" ON)
- mark_as_advanced(GMX_LOAD_PLUGINS)
  
  option(GMX_OPENMP "Enable OpenMP-based multithreading" ON)
  
@@@ -321,15 -326,6 +319,15 @@@ include(gmxManageOpenMP
  include(gmxCFlags)
  gmx_c_flags()
  
 +# These collect libraries that Gromacs requires for linking:
 +#  - Libraries that are required for libgromacs (only)
 +set(GMX_EXTRA_LIBRARIES "")
 +#  - Libraries that are required for all code in the repository
 +set(GMX_COMMON_LIBRARIES "")
 +#  - Libraries that all code linked against libgromacs needs
 +#    (i.e., something that is exposed in installed headers).
 +set(GMX_PUBLIC_LIBRARIES "")
 +
  # This variable should be used for additional compiler flags which are not
  # generated in gmxCFlags nor are SIMD or MPI related.
  set(EXTRA_C_FLAGS "")
@@@ -338,6 -334,17 +336,6 @@@ set(EXTRA_CXX_FLAGS ""
  # Run through a number of tests for buggy compilers and other issues
  include(gmxTestCompilerProblems)
  gmx_test_compiler_problems()
 -# GMX_SIMD will not be set automatically until the second
 -# pass (which is not strictly guaranteed to occur), so putting this
 -# check here among logically-related tests is inefficient, but the
 -# potential loss is likely zero.
 -if(GMX_SIMD STREQUAL "AVX_256"
 -        AND CMAKE_COMPILER_IS_GNUCC
 -        AND (C_COMPILER_VERSION VERSION_EQUAL "4.6.1"
 -            OR CXX_COMPILER_VERSION VERSION_EQUAL "4.6.1"))
 -    message(FATAL_ERROR "gcc 4.6.1 has buggy support for AVX, and GROMACS mdrun will not work. If you want simulation performance, use a more recent compiler. Otherwise, use GMX_SIMD=SSE4.1")
 -    # See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49002
 -endif()
  
  # Implement double-precision option. This is complicated because we
  # need installed headers to use the precision mode of the build that
@@@ -457,6 -464,11 +455,6 @@@ include(gmxManageSharedLibraries
  # Find external packages                                               #
  ########################################################################
  
 -# TNG wants zlib if it is available. And static libxml2 might have a dependency
 -find_package(ZLIB QUIET)
 -include(gmxTestZLib)
 -gmx_test_zlib(HAVE_ZLIB)
 -
  # Unconditionally find the package, as it is also required for unit
  # tests. This exports LIBXML2_FOUND, which we should not use because
  # it does not tell us that linking will succeed. Instead, we test that
@@@ -502,7 -514,7 +500,7 @@@ endif(
  option(GMX_HWLOC "Add support for hwloc Portable Hardware locality library" ${GMX_HWLOC_DEFAULT})
  if(GMX_HWLOC)
      if(HWLOC_FOUND)
 -        include_directories(${HWLOC_INCLUDE_DIRS})
 +        include_directories(SYSTEM ${HWLOC_INCLUDE_DIRS})
          list(APPEND GMX_EXTRA_LIBRARIES ${HWLOC_LIBRARIES})
      else()
          message(FATAL_ERROR "Hwloc package support requested, but not found.")
@@@ -561,6 -573,7 +559,6 @@@ if (TMPI_ATOMICS_DISABLED
     add_definitions(-DTMPI_ATOMICS_DISABLED)
  endif()
  
 -# Note this relies on zlib detection having already run
  include(gmxManageTNG)
  
  include(gmxManageLmfit)
  if(GMX_GPU)
      # now that we have detected the dependencies, do the second configure pass
      gmx_gpu_setup()
 -else()
 -    mark_as_advanced(CUDA_HOST_COMPILER)
  endif()
  
  if(CYGWIN)
@@@ -600,9 -615,7 +598,9 @@@ gmx_add_cache_dependency(GMX_BUILD_UNIT
  
  add_definitions( -DHAVE_CONFIG_H )
  include_directories(BEFORE ${CMAKE_SOURCE_DIR}/src)
 -include_directories(BEFORE ${CMAKE_SOURCE_DIR}/src/external/thread_mpi/include)
 +# TODO required at high level because both libgromacs and progs/mdrun
 +# require it, both for thread-MPI and its atomics and mutexes.
 +include_directories(BEFORE SYSTEM ${CMAKE_SOURCE_DIR}/src/external/thread_mpi/include)
  # Required for config.h, maybe should only be set in src/CMakeLists.txt
  include_directories(BEFORE ${CMAKE_BINARY_DIR}/src)
  
@@@ -687,32 -700,13 +685,13 @@@ include(gmxManageFFTLibraries
  
  include(gmxManageLinearAlgebraLibraries)
  
- # Whether GROMACS will really try to compile support for VMD plugins
- set(GMX_USE_PLUGINS OFF)
+ include(gmxManagePluginSupport)
  
- if(GMX_LOAD_PLUGINS)
-   if(NOT WIN32)
-     # Native Windows does not have, nor need dlopen
-     include(gmxTestdlopen)
-     gmx_test_dlopen(HAVE_DLOPEN)
-   endif()
-   # so, should we use plug-ins?
-   if(WIN32 OR (HAVE_DLOPEN AND BUILD_SHARED_LIBS))
-     if(NOT VMD_QUIETLY)
-       MESSAGE(STATUS "Using dynamic plugins (e.g VMD-supported file formats)")
-     endif()
+ if (GMX_USE_PLUGINS)
      if(NOT GMX_VMD_PLUGIN_PATH)
-       find_package(VMD)
+         find_package(VMD)
      endif()
-     set(GMX_USE_PLUGINS ON)
-     list(APPEND GMX_EXTRA_LIBRARIES ${CMAKE_DL_LIBS}) # magic cross-platform pre-set variable for dlopen library
-     set(PKG_DL_LIBS "-l${CMAKE_DL_LIBS}")
-   else()
-     set(PKG_DL_LIBS)
-   endif()
  endif()
- set(VMD_QUIETLY TRUE CACHE INTERNAL "")
  
  # Link real-time library for POSIX timers. The check for clock_gettime
  # confirms the linkability of rt.
@@@ -721,8 -715,8 +700,8 @@@ if(HAVE_TIME_H AND HAVE_UNISTD_H AND HA
  endif()
  
  # Math and thread libraries must often come after all others when linking...
 -if(HAVE_LIBM)
 -    list(APPEND GMX_EXTRA_LIBRARIES m)
 +if (HAVE_LIBM)
 +    list(APPEND GMX_PUBLIC_LIBRARIES m)
  endif()
  
  option(GMX_NACL "Configure for Native Client builds" OFF)
@@@ -772,7 -766,7 +751,7 @@@ else(
      message("CMAKE_CXX_FLAGS_RELEASE: ${GMXC_CXXFLAGS_RELEASE}")
      message("CMAKE_CXX_FLAGS_DEBUG: ${GMXC_CXXFLAGS_DEBUG}")
      message("CMAKE_EXE_LINKER_FLAGS: ${FFT_LINKER_FLAGS} ${MPI_LINKER_FLAGS}")
 -    message("CMAKE_SHARED_LINKER_FLAGS: ${MPI_LINKER_FLAGS}")
 +    message("CMAKE_SHARED_LINKER_FLAGS: ${FFT_LINKER_FLAGS} ${MPI_LINKER_FLAGS}")
  endif()
  
  if(NOT GMX_OPENMP)
@@@ -822,12 -816,17 +801,12 @@@ include(gmxManageSuffixes
  ################################################################
  # Shared library load path settings
  ################################################################
 -# CMake supports RPATH on OS X only from 2.8.12 upwards.
 -# CMAKE_SYSTEM_VERSION > 8.0 matches OS X 10.5 and above, where RPATH support
 -# was added.
 -
  if(NOT GMX_BUILD_SHARED_EXE)
      # No rpath
      set(CMAKE_SKIP_RPATH TRUE)
      set(CMAKE_EXE_LINK_DYNAMIC_C_FLAGS) # remove -Wl,-Bdynamic
      set(CMAKE_EXE_LINK_DYNAMIC_CXX_FLAGS)
 -elseif((NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin") OR
 -   ((CMAKE_SYSTEM_VERSION VERSION_GREATER 8.0) AND (NOT CMAKE_VERSION VERSION_LESS 2.8.12)))
 +else()
      # The build folder always has bin/ and lib/; if we are also going to
      # install to lib/, then the installation RPATH works also in the build
      # tree.  This makes installation slightly faster (no need to rewrite the
      endif()
      # Set the RPATH as relative to the executable location to make the
      # binaries relocatable.
 -    if(NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin")
 +    if(NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin") #Assume OS X >=10.5
          set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${GMX_LIB_INSTALL_DIR}")
      else()
          set(CMAKE_INSTALL_RPATH "@executable_path/../${GMX_LIB_INSTALL_DIR}")
      endif()
      set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
      set(CMAKE_MACOSX_RPATH 1)
 -else()
 -    # We are on Darwin/OSX, and CMake cannot handle RPATHs automatically.
 -    if(CMAKE_SYSTEM_VERSION VERSION_GREATER 8.0)
 -        # Set the RPATH options manually.
 -        set(CMAKE_INSTALL_NAME_DIR "@rpath")
 -        set(GMX_EXE_LINKER_FLAGS ${GMX_EXE_LINKER_FLAGS} "-Wl,-rpath,@executable_path/../${GMX_LIB_INSTALL_DIR}")
 -    else()
 -        # Use the old INSTALL_NAME_DIR mechanism if RPATH is not supported.
 -        set(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}")
 -    endif()
  endif()
  
  #COPYING file: Only necessary for binary distributions.
@@@ -860,7 -869,18 +839,7 @@@ if (GMX_BUILD_FOR_COVERAGE
  endif()
  
  if (BUILD_TESTING)
 -    # "tests" target builds all the separate test binaries.
 -    add_custom_target(tests)
 -    # "run-ctest" is an internal target that actually runs the tests.
 -    # This is necessary to be able to add separate targets that execute as part
 -    # of 'make check', but are ensured to be executed after the actual tests.
 -    add_custom_target(run-ctest
 -                      COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
 -                      COMMENT "Running all tests"
 -                      VERBATIM)
 -    add_dependencies(run-ctest tests)
 -    # "check" target builds and runs all tests.
 -    add_custom_target(check DEPENDS run-ctest)
 +    include(tests/CheckTarget.cmake)
  endif()
  
  if (NOT GMX_BUILD_MDRUN_ONLY)
diff --combined cmake/FindFFTW.cmake
index c6058a7561ed227640e4962717fc7e14bc74a4ec,6781ad0e8c22504a9fa669256de8f0a3ff51fce1..9e4620f35616c1602ed6c664b74292c739c21ffd
@@@ -1,7 -1,7 +1,7 @@@
  #
  # This file is part of the GROMACS molecular simulation package.
  #
- # Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
 -# Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
++# Copyright (c) 2012,2013,2014,2015,2016,2017, 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.
@@@ -152,7 -152,7 +152,7 @@@ if (${FFTW}_FOUND
    endif()
  
    #Verify FFTW is compiled with fPIC (necessary for shared libraries)
-   if (CMAKE_OBJDUMP AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND BUILD_SHARED_LIBS AND NOT CYGWIN)
+   if (CMAKE_OBJDUMP AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND BUILD_SHARED_LIBS AND NOT CYGWIN AND NOT APPLE)
        execute_process(COMMAND ${CMAKE_OBJDUMP} --reloc ${${FFTW}_LIBRARY} OUTPUT_VARIABLE ${FFTW}_OBJDUMP)
        if (${${FFTW}_OBJDUMP} MATCHES "R_X86_64" #Should always be true for static libraries. Checks that objdump works properly and that the library isn't dynamic
                AND NOT ${${FFTW}_OBJDUMP} MATCHES "R_X86_64_PLT32")
diff --combined cmake/gmxCFlags.cmake
index 6210a2e04fe4828e6eb950ed11b7c60325d2a64c,2a86ced5fcca1755042b6a22046d339674c90376..924db05e03183a19ad7a8b1e8e0136498607e605
@@@ -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, by the GROMACS development team, led by
+ # Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016,2017, 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.
@@@ -134,11 -134,7 +134,11 @@@ macro (gmx_c_flags
              # Problematic with CUDA
              # GMX_TEST_CXXFLAG(CXXFLAGS_WARN_EFFCXX "-Wnon-virtual-dtor" GMXC_CXXFLAGS)
              GMX_TEST_CXXFLAG(CXXFLAGS_WARN_EXTRA "-Wextra -Wno-missing-field-initializers -Wpointer-arith" GMXC_CXXFLAGS)
 -            GMX_TEST_CXXFLAG(CXXFLAGS_WARN_UNDEF "-Wundef" GMXC_CXXFLAGS)
 +            # CUDA versions prior to 7.5 come with a header (math_functions.h) which uses the _MSC_VER macro
 +            # unconditionally, so we don't use -Wundef for earlier CUDA versions.
 +            if(NOT(GMX_GPU AND CUDA_VERSION VERSION_LESS "7.5"))
 +                GMX_TEST_CXXFLAG(CXXFLAGS_WARN_UNDEF "-Wundef" GMXC_CXXFLAGS)
 +            endif()
              GMX_TEST_CFLAG(CXXFLAGS_WARN_REL "-Wno-array-bounds" GMXC_CXXFLAGS_RELEASE_ONLY)
          endif()
          # new in gcc 4.5
      if (CMAKE_C_COMPILER_ID MATCHES "Intel")
          if (NOT WIN32)
              if(NOT GMX_OPENMP)
 -                if(CMAKE_C_COMPILER_VERSION VERSION_GREATER 13.99.99)
  # 3180: unrecognized OpenMP #pragma
 -                    GMX_TEST_CFLAG(CFLAGS_PRAGMA "-wd3180" GMXC_CFLAGS)
 -                else()
 -# 161: unrecognized #pragma
 -                    GMX_TEST_CFLAG(CFLAGS_PRAGMA "-wd161" GMXC_CFLAGS)
 -                endif()
 +                GMX_TEST_CFLAG(CFLAGS_PRAGMA "-wd3180" GMXC_CFLAGS)
              endif()
              if (GMX_COMPILER_WARNINGS)
 -                if(CMAKE_C_COMPILER_VERSION VERSION_LESS 15.00.00)
 -# 193: zero used for undefined preprocessing identifier ".."
 -                    GMX_TEST_CFLAG(CFLAGS_WARN_OLD -wd193 GMXC_CFLAGS)
 -                endif()
  # 177: function/variable ".." was declared but never referenced
 -# 271: trailing comma is nonstandard
 -# 304: access control not specified ("public" by default)
 -# 383: value copied to temporary, reference to temporary used
 -# 424: extra ";" ignored
 -# 444: destructor for base class ".." is not virtual
 -# 522: function ".." redeclared "inline" after being called
 +# 411: class defines no constructor to initialize the following (incorrect for struct, initializer list works)
  # 593: variable ".." was set but never used
 -# 869: parameter ".." was never referenced
  # 981: operands are evaluated in unspecified order
  #1418: external function definition with no prior declaration
  #1419: external declaration in primary source file
  #2547: ".." was specified as both a system and non-system include directory
  #2557: comparison between signed and unsigned operands
  #3280: declaration hides member ".."
 -#3346: dynamic exception specifications are deprecated
  #11074: Inlining inhibited by limit max-size(/max-total-size)
  #11076: To get full report use -opt-report=3 -opt-report-phase ipo (shown for previous remark)
 -                GMX_TEST_CFLAG(CFLAGS_WARN "-w3 -wd177 -wd271 -wd304 -wd383 -wd424 -wd444 -wd522 -wd593 -wd869 -wd981 -wd1418 -wd1419 -wd1572 -wd1599 -wd2259 -wd2415 -wd2547 -wd2557 -wd3280 -wd3346 -wd11074 -wd11076" GMXC_CFLAGS)
 +                GMX_TEST_CFLAG(CFLAGS_WARN "-w3 -wd177 -wd411 -wd593 -wd981 -wd1418 -wd1419 -wd1572 -wd1599 -wd2259 -wd2415 -wd2547 -wd2557 -wd3280 -wd11074 -wd11076" GMXC_CFLAGS)
              endif()
              GMX_TEST_CFLAG(CFLAGS_STDGNU "-std=gnu99" GMXC_CFLAGS)
 -            GMX_TEST_CFLAG(CFLAGS_OPT "-ip -funroll-all-loops -alias-const -ansi-alias" GMXC_CFLAGS_RELEASE)
 +            GMX_TEST_CFLAG(CFLAGS_OPT "-ip -funroll-all-loops -alias-const -ansi-alias -no-prec-div -fimf-domain-exclusion=14 -static-intel" GMXC_CFLAGS_RELEASE)
              GMX_TEST_CFLAG(CFLAGS_DEBUG "-O0" GMXC_CFLAGS_DEBUG) #icc defaults to -O2 even with -g
              GMX_TEST_CFLAG(CFLAGS_FP_RELASSERT "-fp-model except -fp-model precise" GMXC_CFLAGS_RELWITHASSERT)
          else()
              if(NOT GMX_OPENMP)
 -                if(CMAKE_C_COMPILER_VERSION VERSION_GREATER 13.99.99)
 -                    GMX_TEST_CFLAG(CFLAGS_PRAGMA "/wd3180" GMXC_CFLAGS)
 -                else()
 -                    GMX_TEST_CFLAG(CFLAGS_PRAGMA "/wd161" GMXC_CFLAGS)
 -                endif()
 +                GMX_TEST_CFLAG(CFLAGS_PRAGMA "/wd3180" GMXC_CFLAGS)
              endif()
              if (GMX_COMPILER_WARNINGS)
 -                if(CMAKE_C_COMPILER_VERSION VERSION_LESS 15.00.00)
 -                    GMX_TEST_CFLAG(CFLAGS_WARN_OLD /wd193 GMXC_CFLAGS)
 -                endif()
 -                GMX_TEST_CFLAG(CFLAGS_WARN "/W3 /wd177 /wd271 /wd304 /wd383 /wd424 /wd444 /wd522 /wd593 /wd869 /wd981 /wd1418 /wd1419 /wd1572 /wd1599 /wd2259 /wd2415 /wd2547 /wd2557 /wd3280 /wd3346" GMXC_CFLAGS)
 +GMX_TEST_CFLAG(CFLAGS_WARN "/W3 /wd177 /wd411 /wd593 /wd981 /wd1418 /wd1419 /wd1572 /wd1599 /wd2259 /wd2415 /wd2547 /wd2557 /wd3280" GMXC_CFLAGS)
              endif()
              GMX_TEST_CFLAG(CFLAGS_OPT "/Qip" GMXC_CFLAGS_RELEASE)
          endif()
      if (CMAKE_CXX_COMPILER_ID MATCHES "Intel")
          if (NOT WIN32) 
              if(NOT GMX_OPENMP)
 -                if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 13.99.99)
 -                    GMX_TEST_CXXFLAG(CXXFLAGS_PRAGMA "-wd3180" GMXC_CXXFLAGS)
 -                else()
 -                    GMX_TEST_CXXFLAG(CXXFLAGS_PRAGMA "-wd161" GMXC_CXXFLAGS)
 -                endif()
 +                GMX_TEST_CXXFLAG(CXXFLAGS_PRAGMA "-wd3180" GMXC_CXXFLAGS)
              endif()
              if (GMX_COMPILER_WARNINGS)
 -                if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.00.00)
 -                    GMX_TEST_CXXFLAG(CXXFLAGS_WARN_OLD -wd193 GMXC_CXXFLAGS)
 +                if (GMX_GPU)
 +# Suppress warnings from CUDA headers
 +# 7:   unrecognized token
 +# 82:  storage class is not first
 +# The below are also required for math_functions.h / math_functions.hpp at least until CUDA 8.0-RC
 +# 193: zero used for undefined preprocessing identifer
 +# 3346:dynamic exception specifiers are deprecated
 +                    GMX_TEST_CXXFLAG(CXXFLAGS_WARN_OLD_GPU "-wd7 -wd82 -wd193 -wd3346" GMXC_CXXFLAGS)
                  endif()
  #All but the following warnings are identical for the C-compiler (see above)
 -#1782: #pragma once is obsolete
 +# 383: value copied to temporary, reference to temporary used
 +# 444: destructor for base class ".." is not virtual
  #2282: unrecognized GCC pragma
 -                GMX_TEST_CXXFLAG(CXXFLAGS_WARN "-w3 -wd177 -wd271 -wd304 -wd383 -wd424 -wd444 -wd522 -wd593 -wd869 -wd981 -wd1418 -wd1419 -wd1572 -wd1599 -wd2259 -wd2415 -wd2547 -wd2557 -wd3280 -wd3346 -wd11074 -wd11076 -wd1782 -wd2282" GMXC_CXXFLAGS)
 +                GMX_TEST_CXXFLAG(CXXFLAGS_WARN "-w3 -wd177 -wd383 -wd411 -wd444 -wd981 -wd1418 -wd1572 -wd1599 -wd2259 -wd3280 -wd11074 -wd11076 -wd2282" GMXC_CXXFLAGS)
              endif()
 -            GMX_TEST_CXXFLAG(CXXFLAGS_OPT "-ip -funroll-all-loops -alias-const -ansi-alias" GMXC_CXXFLAGS_RELEASE)
 +            GMX_TEST_CXXFLAG(CXXFLAGS_OPT "-ip -funroll-all-loops -alias-const -ansi-alias -no-prec-div -fimf-domain-exclusion=14 -static-intel" GMXC_CXXFLAGS_RELEASE)
              GMX_TEST_CXXFLAG(CXXFLAGS_DEBUG "-O0" GMXC_CXXFLAGS_DEBUG)
              GMX_TEST_CXXFLAG(CXXFLAGS_FP_RELASSERT "-fp-model except -fp-model precise" GMXC_CXXFLAGS_RELWITHASSERT)
          else()
- #809: exception specification for virtual function X is incompatible with that of overridden function
              if(NOT GMX_OPENMP)
 -                if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 13.99.99)
 -                    GMX_TEST_CXXFLAG(CXXFLAGS_PRAGMA "/wd3180" GMXC_CFLAGS)
 -                else()
 -                    GMX_TEST_CXXFLAG(CXXFLAGS_PRAGMA "/wd161" GMXC_CXXFLAGS)
 -                endif()
 +                GMX_TEST_CXXFLAG(CXXFLAGS_PRAGMA "/wd3180" GMXC_CFLAGS)
              endif()
              if (GMX_COMPILER_WARNINGS)
- GMX_TEST_CXXFLAG(CXXFLAGS_WARN "/W3 /wd177 /wd383 /wd411 /wd444 /wd809 /wd981 /wd1418 /wd1572 /wd1599 /wd2259 /wd3280 /wd11074 /wd11076 /wd2282" GMXC_CXXFLAGS)
 -                if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.00.00)
 -                    GMX_TEST_CXXFLAG(CXXFLAGS_WARN_OLD /wd193 GMXC_CXXFLAGS)
 -                endif()
+ #809: exception specification for virtual function X is incompatible with that of overridden function
 -                GMX_TEST_CXXFLAG(CXXFLAGS_WARN "/W3 /wd177 /wd271 /wd304 /wd383 /wd424 /wd444 /wd522 /wd593 /wd809 /wd869 /wd981 /wd1418 /wd1419 /wd1572 /wd1599 /wd2259 /wd2415 /wd2547 /wd2557 /wd3280 /wd3346 /wd1782 /wd2282" GMXC_CXXFLAGS)
++                GMX_TEST_CXXFLAG(CXXFLAGS_WARN "/W3 /wd177 /wd383 /wd411 /wd444 /wd809 /wd981 /wd1418 /wd1572 /wd1599 /wd2259 /wd3280 /wd11074 /wd11076 /wd2282" GMXC_CXXFLAGS)
              endif()
              GMX_TEST_CXXFLAG(CXXFLAGS_OPT "/Qip" GMXC_CXXFLAGS_RELEASE)
          endif()
index 0000000000000000000000000000000000000000,69c1e4c55ab34eb919be17c629beb6b8d7184d74..e3af82761e3cf698127305f0023b1c501f350ede
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,98 +1,98 @@@
 -# Copyright (c) 2016, by the GROMACS development team, led by
+ #
+ # This file is part of the GROMACS molecular simulation package.
+ #
++# Copyright (c) 2016,2017, 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.
+ include(gmxOptionUtilities)
+ # Sets GMX_USE_PLUGINS=ON in the parent scope if the toolchain and
+ # user selections permit the build to support plugin loading.
+ function(gmx_manage_plugin_support)
+     gmx_option_trivalue(GMX_LOAD_PLUGINS "Compile with plugin support, needed to read VMD supported file formats" AUTO)
+     mark_as_advanced(GMX_LOAD_PLUGINS)
+     # Find out if non-Windows builds can support plugins. Native Windows
+     # neither needs nor has library support.
+     if (NOT WIN32)
+         # TODO Make a proper find_package for dlopen to find
+         # dlfcn.h. The CMake variable CMAKE_DL_LIBS works magically
+         # for the library, however.
+         include(gmxTestdlopen)
+         gmx_test_dlopen(HAVE_DLOPEN)
+     endif()
+     # Keep the status line quiet unless something relevant has
+     # changed.
+     gmx_check_if_changed(EMIT_STATUS_MESSAGES GMX_LOAD_PLUGINS BUILD_SHARED_LIBS HAVE_DLOPEN)
+     # Whether GROMACS will really try to compile support for VMD
+     # plugins.
+     set(GMX_USE_PLUGINS OFF)
+     # Plugins are supported natively on Windows
+     if (WIN32 OR (BUILD_SHARED_LIBS AND HAVE_DLOPEN))
+         set(GMX_USE_PLUGINS ${GMX_LOAD_PLUGINS})
+     elseif(GMX_LOAD_PLUGINS)
+         # Can't support plugins for some reason. If the user required
+         # plugins, emit fatal errors. Otherwise, emit status messages
+         # for AUTO and be silent for OFF.
+         set(message "")
+         if (NOT HAVE_DLOPEN)
+             set(message "${message}dlopen() support for using dynamic plugins for VMD-supported file formats is missing. ")
+         endif()
+         if(NOT BUILD_SHARED_LIBS)
+             set(message "${message}GROMACS only supports plugins in a build that uses shared libraries, which can be disabled for various reasons. BUILD_SHARED_LIBS=on and a toolchain that supports dynamic linking is required. (Hint: GMX_PREFER_STATIC_LIBS and GMX_BUILD_MDRUN_ONLY can influence the default BUILD_SHARED_LIBS, so if you need plugins, reconsider those choices.) ")
+         endif()
+         if (GMX_LOAD_PLUGINS_FORCE)
+             message(FATAL_ERROR "${message}Cannot build with GMX_LOAD_PLUGINS=${GMX_LOAD_PLUGINS}.")
+         endif()
+         if (GMX_LOAD_PLUGINS_AUTO AND EMIT_STATUS_MESSAGES)
+             message(STATUS "${message}")
+         endif()
+     endif()
+     if(EMIT_STATUS_MESSAGES)
+         if(GMX_USE_PLUGINS)
+             MESSAGE(STATUS "Using dynamic plugins (e.g VMD-supported file formats)")
+         else()
+             MESSAGE(STATUS "Not using dynamic plugins (e.g VMD-supported file formats)")
+         endif()
+     endif()
+     set(GMX_USE_PLUGINS ${GMX_USE_PLUGINS} PARENT_SCOPE)
+ endfunction()
+ gmx_manage_plugin_support()
+ if(GMX_USE_PLUGINS)
+     list(APPEND GMX_EXTRA_LIBRARIES ${CMAKE_DL_LIBS}) # magic cross-platform pre-set variable for dlopen library
+     set(PKG_DL_LIBS "-l${CMAKE_DL_LIBS}")
+ endif()
diff --combined cmake/gmxTestCXX11.cmake
index ea6bed874f22bf5500c1ca78e2ba70a8d55dd763,f289f811db2f1aa416ff1fde014651c1a7c017df..2e90358ba7863394109c9f1d4cb52b08a951042b
@@@ -1,7 -1,7 +1,7 @@@
  #
  # This file is part of the GROMACS molecular simulation package.
  #
- # Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
+ # Copyright (c) 2012,2013,2014,2015,2016,2017, 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.
@@@ -45,11 -45,11 +45,11 @@@ function(GMX_TEST_CXX11 CXX11_CXX_FLAG_
      # First check that the compiler is OK, and find the appropriate flag.
  
      if(WIN32 AND NOT MINGW)
 -        set(CXX11_CXX_FLAG "/Qstd=c++0x")
 +        set(CXX11_CXX_FLAG "/Qstd=c++11")
      elseif(CYGWIN)
 -        set(CXX11_CXX_FLAG "-std=gnu++0x") #required for strdup
 +        set(CXX11_CXX_FLAG "-std=gnu++11") #required for strdup
      else()
 -        set(CXX11_CXX_FLAG "-std=c++0x")
 +        set(CXX11_CXX_FLAG "-std=c++11")
      endif()
      CHECK_CXX_COMPILER_FLAG("${CXX11_CXX_FLAG}" CXXFLAG_STD_CXX0X)
      if(NOT CXXFLAG_STD_CXX0X)
@@@ -102,30 -102,12 +102,31 @@@ extern template void someFunction<int>(
  int main() {
    // Test nullptr
    double *x = nullptr;
+   (void)x; // Suppressing unused variable warning
    // Test range-based for loops
    int array[5] = { 1, 2, 3, 4, 5 };
    for (int& x : array)
      x *= 2;
 +  // Test alignas
 +  alignas(4*sizeof(int)) int y;
  }" CXX11_SUPPORTED)
 +    if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
 +        if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.8.1")
 +            message(FATAL_ERROR "GROMACS requires version 4.8.1 or later of the GNU C++ compiler for complete C++11 support")
 +        endif()
 +    elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
 +        if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "3.3")
 +            message(FATAL_ERROR "GROMACS requires version 3.3 or later of the Clang C++ compiler for complete C++11 support")
 +        endif()
 +    elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
 +        if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "15.0")
 +            message(FATAL_ERROR "GROMACS requires version 15.0 or later of the Intel C++ compiler for complete C++11 support")
 +        endif()
 +    elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
 +        if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.0.23026")
 +            message(FATAL_ERROR "GROMACS requires version 2015 (19.0.23026) or later of the MSVC C++ compiler for complete C++11 support")
 +        endif()
 +    endif()
      if(CXX11_SUPPORTED)
          set(${CXX11_CXX_FLAG_NAME} ${CXX11_CXX_FLAG} PARENT_SCOPE)
      else()
@@@ -147,8 -129,8 +148,8 @@@ int main() 
    intPointer p(new int(10));
    std::map<int, std::unique_ptr<int>> m;
    m.insert(std::make_pair(5, std::move(p)));
 -  auto start = std::chrono::system_clock::now();
 -  if (std::chrono::system_clock::now() - start < std::chrono::seconds(2))
 +  auto start = std::chrono::steady_clock::now();
 +  if (std::chrono::steady_clock::now() - start < std::chrono::seconds(2))
    {
        std::thread t;
    }
index d9950c7eb5b948ade529e13e5ec4aeda047e4c6e,6ef54dca4c72992af51fe82b286f1754f64a1606..f72368454ac20f3a8e184276cd9e3bfcfb6c5f9e
@@@ -49,8 -49,6 +49,8 @@@
  #include <stdlib.h>
  #include <string.h>
  
 +#include <cassert>
 +
  #include <algorithm>
  #include <string>
  
@@@ -421,7 -419,7 +421,7 @@@ void dd_print_missing_interactions(FIL
  
      print_missing_interactions_atoms(fplog, cr, top_global, &top_local->idef);
      write_dd_pdb("dd_dump_err", 0, "dump", top_global, cr,
 -                 -1, state_local->x, state_local->box);
 +                 -1, as_rvec_array(state_local->x.data()), state_local->box);
  
      std::string errorMessage;
  
@@@ -505,7 -503,7 +505,7 @@@ static void count_excls(const t_block *
      }
  }
  
 -/*! \brief Run the reverse ilist generation and store it when \p bAssign = TRUE */
 +/*! \brief Run the reverse ilist generation and store it in r_il when \p bAssign = TRUE */
  static int low_make_reverse_ilist(const t_ilist *il_mt, const t_atom *atom,
                                    const int * const * vsite_pbc,
                                    int *count,
                      a = ia[1+link];
                      if (bAssign)
                      {
 +                        assert(r_il); //with bAssign not allowed to be null
 +                        assert(r_index);
                          r_il[r_index[a]+count[a]] =
                              (ftype == F_CONSTRNC ? F_CONSTR : ftype);
                          r_il[r_index[a]+count[a]+1] = ia[0];
@@@ -626,7 -622,7 +626,7 @@@ static int make_reverse_ilist(const t_i
      snew(count, nat_mt);
      low_make_reverse_ilist(ilist, atoms->atom, vsite_pbc,
                             count,
 -                           bConstr, bSettle, bBCheck, NULL, NULL,
 +                           bConstr, bSettle, bBCheck, nullptr, nullptr,
                             bLinkToAllAtoms, FALSE);
  
      snew(ril_mt->index, nat_mt+1);
@@@ -692,7 -688,7 +692,7 @@@ static gmx_reverse_top_t *make_reverse_
          /* Make the atom to interaction list for this molecule type */
          nint_mt[mt] =
              make_reverse_ilist(molt->ilist, &molt->atoms,
 -                               vsite_pbc_molt ? vsite_pbc_molt[mt] : NULL,
 +                               vsite_pbc_molt ? vsite_pbc_molt[mt] : nullptr,
                                 rt->bConstr, rt->bSettle, rt->bBCheck, FALSE,
                                 &rt->ril_mt[mt]);
  
      {
          t_atoms atoms_global;
  
 -        rt->ril_intermol.index = NULL;
 -        rt->ril_intermol.il    = NULL;
 +        rt->ril_intermol.index = nullptr;
 +        rt->ril_intermol.il    = nullptr;
  
          atoms_global.nr   = mtop->natoms;
 -        atoms_global.atom = NULL; /* Only used with virtual sites */
 +        atoms_global.atom = nullptr; /* Only used with virtual sites */
  
          *nint +=
              make_reverse_ilist(mtop->intermolecular_ilist, &atoms_global,
 -                               NULL,
 +                               nullptr,
                                 rt->bConstr, rt->bSettle, rt->bBCheck, FALSE,
                                 &rt->ril_intermol);
      }
  
      rt->nthread = gmx_omp_nthreads_get(emntDomdec);
      snew(rt->th_work, rt->nthread);
 -    if (vsite_pbc_molt != NULL)
 +    if (vsite_pbc_molt != nullptr)
      {
          for (thread = 0; thread < rt->nthread; thread++)
          {
@@@ -782,7 -778,7 +782,7 @@@ void dd_make_reverse_top(FILE *fplog
       */
  
      dd->reverse_top = make_reverse_top(mtop, ir->efep != efepNO,
 -                                       vsite ? vsite->vsite_pbc_molt : NULL,
 +                                       vsite ? vsite->vsite_pbc_molt : nullptr,
                                         !dd->bInterCGcons, !dd->bInterCGsettles,
                                         bBCheck, &dd->nbonded_global);
  
@@@ -1227,7 -1223,7 +1227,7 @@@ static void combine_idef(t_idef *dest, 
              int      nral1 = 0, ftv = 0;
  
              vpbc = ((interaction_function[ftype].flags & IF_VSITE) &&
 -                    vsite->vsite_pbc_loc != NULL);
 +                    vsite->vsite_pbc_loc != nullptr);
              if (vpbc)
              {
                  nral1 = 1 + NRAL(ftype);
              /* Position restraints need an additional treatment */
              if (ftype == F_POSRES || ftype == F_FBPOSRES)
              {
-                 int nposres = dest->il[ftype].nr/2;
-                 if (nposres > dest->iparams_posres_nalloc)
+                 int          nposres       = dest->il[ftype].nr/2;
+                 // TODO: Simplify this code using std::vector
+                 t_iparams * &iparams_dest  = (ftype == F_POSRES ? dest->iparams_posres : dest->iparams_fbposres);
+                 int         &posres_nalloc = (ftype == F_POSRES ? dest->iparams_posres_nalloc : dest->iparams_fbposres_nalloc);
+                 if (nposres > posres_nalloc)
                  {
-                     dest->iparams_posres_nalloc = over_alloc_large(nposres);
-                     srenew(dest->iparams_posres, dest->iparams_posres_nalloc);
+                     posres_nalloc = over_alloc_large(nposres);
+                     srenew(iparams_dest, posres_nalloc);
                  }
                  /* Set nposres to the number of original position restraints in dest */
                  for (int s = 1; s < nsrc; s++)
                  {
                      nposres -= src[s].idef.il[ftype].nr/2;
                  }
                  for (int s = 1; s < nsrc; s++)
                  {
-                     if (ftype == F_POSRES)
-                     {
-                         for (int i = 0; i < src[s].idef.il[ftype].nr/2; i++)
-                         {
-                             /* Correct the index into iparams_posres */
-                             dest->il[ftype].iatoms[nposres*2] = nposres;
-                             /* Copy the position restraint force parameters */
-                             dest->iparams_posres[nposres] = src[s].idef.iparams_posres[i];
-                             nposres++;
-                         }
-                     }
-                     else
+                     const t_iparams *iparams_src = (ftype == F_POSRES ? src[s].idef.iparams_posres : src[s].idef.iparams_fbposres);
+                     for (int i = 0; i < src[s].idef.il[ftype].nr/2; i++)
                      {
-                         for (int i = 0; i < src[s].idef.il[ftype].nr/2; i++)
-                         {
-                             /* Correct the index into iparams_fbposres */
-                             dest->il[ftype].iatoms[nposres*2] = nposres;
-                             /* Copy the position restraint force parameters */
-                             dest->iparams_fbposres[nposres] = src[s].idef.iparams_fbposres[i];
-                             nposres++;
-                         }
+                         /* Correct the index into iparams_posres */
+                         dest->il[ftype].iatoms[nposres*2] = nposres;
+                         /* Copy the position restraint force parameters */
+                         iparams_dest[nposres]             = iparams_src[i];
+                         nposres++;
                      }
                  }
              }
@@@ -2032,8 -2021,8 +2025,8 @@@ static int make_local_bondeds_excls(gmx
                  }
                  else
                  {
 -                    vsite_pbc        = NULL;
 -                    vsite_pbc_nalloc = NULL;
 +                    vsite_pbc        = nullptr;
 +                    vsite_pbc_nalloc = nullptr;
                  }
  
                  rt->th_work[thread].nbonded =
@@@ -2144,7 -2133,7 +2137,7 @@@ void dd_make_local_top(gmx_domdec_t *dd
      real     rc = -1;
      ivec     rcheck;
      int      d, nexcl;
 -    t_pbc    pbc, *pbc_null = NULL;
 +    t_pbc    pbc, *pbc_null = nullptr;
  
      if (debug)
      {
              }
              else
              {
 -                pbc_null = NULL;
 +                pbc_null = nullptr;
              }
          }
      }
@@@ -2257,7 -2246,7 +2250,7 @@@ gmx_localtop_t *dd_init_local_top(cons
  
      for (i = 0; i < F_NRE; i++)
      {
 -        top->idef.il[i].iatoms = NULL;
 +        top->idef.il[i].iatoms = nullptr;
          top->idef.il[i].nalloc = 0;
      }
      top->idef.ilsort   = ilsortUNKNOWN;
@@@ -2276,7 -2265,7 +2269,7 @@@ void dd_init_local_state(gmx_domdec_t *
          buf[1] = state_global->ngtc;
          buf[2] = state_global->nnhpres;
          buf[3] = state_global->nhchainlength;
 -        buf[4] = state_global->dfhist.nlambda;
 +        buf[4] = state_global->dfhist ? state_global->dfhist->nlambda : 0;
      }
      dd_bcast(dd, NITEM_DD_INIT_LOCAL_STATE*sizeof(int), buf);
  
@@@ -2362,16 -2351,16 +2355,16 @@@ t_blocka *make_charge_group_links(cons
          t_atoms atoms;
  
          atoms.nr   = mtop->natoms;
 -        atoms.atom = NULL;
 +        atoms.atom = nullptr;
  
          make_reverse_ilist(mtop->intermolecular_ilist, &atoms,
 -                           NULL, FALSE, FALSE, FALSE, TRUE, &ril_intermol);
 +                           nullptr, FALSE, FALSE, FALSE, TRUE, &ril_intermol);
      }
  
      snew(link, 1);
      snew(link->index, ncg_mtop(mtop)+1);
      link->nalloc_a = 0;
 -    link->a        = NULL;
 +    link->a        = nullptr;
  
      link->index[0] = 0;
      cg_offset      = 0;
           * The constraints are discarded here.
           */
          make_reverse_ilist(molt->ilist, &molt->atoms,
 -                           NULL, FALSE, FALSE, FALSE, TRUE, &ril);
 +                           nullptr, FALSE, FALSE, FALSE, TRUE, &ril);
  
          cgi_mb = &cginfo_mb[mb];
  
@@@ -2652,7 -2641,7 +2645,7 @@@ static void get_cgcm_mol(const gmx_molt
  
      if (ePBC != epbcNONE)
      {
 -        mk_mshift(NULL, graph, ePBC, box, x);
 +        mk_mshift(nullptr, graph, ePBC, box, x);
  
          shift_x(graph, box, x, xs);
          /* By doing an extra mk_mshift the molecules that are broken
           * will be made whole again. Such are the healing powers
           * of GROMACS.
           */
 -        mk_mshift(NULL, graph, ePBC, box, xs);
 +        mk_mshift(nullptr, graph, ePBC, box, xs);
      }
      else
      {
  
      if (vsite)
      {
 -        construct_vsites(vsite, xs, 0.0, NULL,
 +        construct_vsites(vsite, xs, 0.0, nullptr,
                           ffparams->iparams, molt->ilist,
 -                         epbcNONE, TRUE, NULL, NULL);
 +                         epbcNONE, TRUE, nullptr, nullptr);
      }
  
 -    calc_cgcm(NULL, 0, molt->cgs.nr, &molt->cgs, xs, cg_cm);
 +    calc_cgcm(nullptr, 0, molt->cgs.nr, &molt->cgs, xs, cg_cm);
  }
  
  //! Returns whether \p molt has a virtual site
@@@ -2723,7 -2712,7 +2716,7 @@@ void dd_bonded_cg_distance(FILE *fplog
  
      bExclRequired = inputrecExclForces(ir);
  
 -    vsite = init_vsite(mtop, NULL, TRUE);
 +    vsite = init_vsite(mtop, nullptr, TRUE);
  
      *r_2b     = 0;
      *r_mb     = 0;
          {
              if (ir->ePBC != epbcNONE)
              {
 -                mk_graph_ilist(NULL, molt->ilist, 0, molt->atoms.nr, FALSE, FALSE,
 +                mk_graph_ilist(nullptr, molt->ilist, 0, molt->atoms.nr, FALSE, FALSE,
                                 &graph);
              }
  
              for (mol = 0; mol < molb->nmol; mol++)
              {
                  get_cgcm_mol(molt, &mtop->ffparams, ir->ePBC, &graph, box,
 -                             have_vsite_molt(molt) ? vsite : NULL,
 +                             have_vsite_molt(molt) ? vsite : nullptr,
                               x+at_offset, xs, cg_cm);
  
                  bonded_distance_t bd_mol_2b = { 0, -1, -1, -1 };
index 23251a08c6be14046a10b5515ff3755a96e6b549,702d6f208e5e43b3bf7b2b2cce1bdaea97b9306d..9e4b629b5b873480b193eebdd1cf31bf5ae32520
@@@ -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, by the GROMACS development team, led by
 + * Copyright (c) 2013,2014,2015,2016,2017, 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.
@@@ -36,7 -36,6 +36,7 @@@
   */
  #include "gmxpre.h"
  
 +#include <cassert>
  #include <cmath>
  #include <cstdlib>
  #include <cstring>
@@@ -181,7 -180,6 +181,7 @@@ static void write_xvgr_graphs(const cha
          }
          else
          {
 +            assert(sy);
              ymin = sy[g][0][0];
              ymax = sy[g][0][0];
              for (s = 0; s < nsetspergraph; s++)
@@@ -318,7 -316,7 +318,7 @@@ compare(int natoms, int n1, rvec **eigv
      // better to be safe than sorry, so we check it with an assert.
      // If we are in this comparison routine in the first place, neig2 should not be 0,
      // so eigval2 should always be a valid pointer.
 -    GMX_RELEASE_ASSERT(eigval2 != NULL, "NULL pointer provided for eigval2");
 +    GMX_RELEASE_ASSERT(eigval2 != nullptr, "NULL pointer provided for eigval2");
  
      for (i = n; i < neig2; i++)
      {
@@@ -511,19 -509,19 +511,19 @@@ static void project(const char *trajfil
                      int noutvec, int *outvec, gmx_bool bSplit,
                      const gmx_output_env_t *oenv)
  {
 -    FILE        *xvgrout = NULL;
 +    FILE        *xvgrout = nullptr;
      int          nat, i, j, d, v, vec, nfr, nframes = 0, snew_size, frame;
 -    t_trxstatus *out = NULL;
 +    t_trxstatus *out = nullptr;
      t_trxstatus *status;
      int          noutvec_extr, imin, imax;
      real        *pmin, *pmax;
      int         *all_at;
      matrix       box;
      rvec        *xread, *x;
 -    real         t, inp, **inprod = NULL;
 +    real         t, inp, **inprod = nullptr;
      char         str[STRLEN], str2[STRLEN], **ylabel, *c;
      real         fact;
 -    gmx_rmpbc_t  gpbc = NULL;
 +    gmx_rmpbc_t  gpbc = nullptr;
  
      snew(x, natoms);
  
                  /* calculate x: a fitted struture of the selected atoms */
                  if (bFit)
                  {
 -                    reset_x(nfit, ifit, nat, NULL, xread, w_rls);
 +                    reset_x(nfit, ifit, nat, nullptr, xread, w_rls);
                      do_fit(nat, w_rls, xref, xread);
                  }
                  for (i = 0; i < natoms; i++)
                              }
                          }
                      }
 -                    write_trx(out, natoms, index, atoms, 0, t, box, xread, NULL, NULL);
 +                    write_trx(out, natoms, index, atoms, 0, t, box, xread, nullptr, nullptr);
                  }
                  nframes++;
              }
  
      if (projfile)
      {
 -        GMX_RELEASE_ASSERT(inprod != NULL, "inprod must be non-NULL if projfile is non-NULL");
 +        GMX_RELEASE_ASSERT(inprod != nullptr, "inprod must be non-NULL if projfile is non-NULL");
          snew(ylabel, noutvec);
          for (v = 0; v < noutvec; v++)
          {
              ylabel[v] = gmx_strdup(str);
          }
          sprintf(str, "projection on eigenvectors (%s)", proj_unit);
 -        write_xvgr_graphs(projfile, noutvec, 1, str, NULL, output_env_get_xvgr_tlabel(oenv),
 +        write_xvgr_graphs(projfile, noutvec, 1, str, nullptr, output_env_get_xvgr_tlabel(oenv),
                            (const char **)ylabel,
 -                          nframes, inprod[noutvec], inprod, NULL,
 +                          nframes, inprod[noutvec], inprod, nullptr,
                            output_env_get_time_factor(oenv), FALSE, bSplit, oenv);
      }
  
      {
          t_atoms     atoms;
          rvec       *x;
 -        real       *b = NULL;
 +        real       *b = nullptr;
          matrix      box;
          char       *resnm, *atnm;
          gmx_bool    bPDB, b4D;
          }
          if ( ( b4D || bSplit ) && bPDB)
          {
 -            GMX_RELEASE_ASSERT(inprod != NULL, "inprod must be non-NULL with 4D or split PDB output options");
 +            GMX_RELEASE_ASSERT(inprod != nullptr, "inprod must be non-NULL with 4D or split PDB output options");
  
              out = gmx_ffopen(threedplotfile, "w");
              fprintf(out, "HEADER    %s\n", str);
          }
          else
          {
 -            write_sto_conf(threedplotfile, str, &atoms, x, NULL, ePBC, box);
 +            write_sto_conf(threedplotfile, str, &atoms, x, nullptr, ePBC, box);
          }
          done_atom(&atoms);
      }
          snew(pmax, noutvec_extr);
          if (extreme == 0)
          {
 -            GMX_RELEASE_ASSERT(inprod != NULL, "inprod must be non-NULL");
 +            GMX_RELEASE_ASSERT(inprod != nullptr, "inprod must be non-NULL");
              fprintf(stderr, "%11s %17s %17s\n", "eigenvector", "Minimum", "Maximum");
              fprintf(stderr,
                      "%11s %10s %10s %10s %10s\n", "", "value", "frame", "value", "frame");
                               *eigvec[outvec[v]][i][d]/sqrtm[i]);
                      }
                  }
 -                write_trx(out, natoms, index, atoms, 0, frame, topbox, xread, NULL, NULL);
 +                write_trx(out, natoms, index, atoms, 0, frame, topbox, xread, nullptr, nullptr);
              }
              close_trx(out);
          }
@@@ -912,7 -910,7 +912,7 @@@ static void components(const char *outf
      write_xvgr_graphs(outfile, noutvec, 4, "Eigenvector components",
                        "black: total, red: x, green: y, blue: z",
                        "Atom number", (const char **)ylabel,
 -                      natoms, x, NULL, y, 1, FALSE, FALSE, oenv);
 +                      natoms, x, nullptr, y, 1, FALSE, FALSE, oenv);
      fprintf(stderr, "\n");
  }
  
@@@ -958,9 -956,9 +958,9 @@@ static void rmsf(const char *outfile, i
              y[g][i] = std::sqrt(eigval[eignr[v]]*norm2(eigvec[v][i]))/sqrtm[i];
          }
      }
 -    write_xvgr_graphs(outfile, noutvec, 1, "RMS fluctuation (nm) ", NULL,
 +    write_xvgr_graphs(outfile, noutvec, 1, "RMS fluctuation (nm) ", nullptr,
                        "Atom number", (const char **)ylabel,
 -                      natoms, x, y, NULL, 1, TRUE, FALSE, oenv);
 +                      natoms, x, y, nullptr, 1, TRUE, FALSE, oenv);
      fprintf(stderr, "\n");
  }
  
@@@ -1026,9 -1024,11 +1026,11 @@@ int gmx_anaeig(int argc, char *argv[]
          "of both files will be used unless [TT]-first[tt] and [TT]-last[tt]",
          "have been set explicitly.[PAR]",
  
-         "When [TT]-v[tt], [TT]-eig[tt], [TT]-v2[tt] and [TT]-eig2[tt] are given,",
-         "a single number for the overlap between the covariance matrices is",
-         "generated. The formulas are::",
+         "When [TT]-v[tt] and [TT]-v2[tt] are given, a single number for the",
+         "overlap between the covariance matrices is generated. Note that the",
+         "eigenvalues are by default read from the timestamp field in the",
+         "eigenvector input files, but when [TT]-eig[tt], or [TT]-eig2[tt] are",
+         "given, the corresponding eigenvalues are used instead. The formulas are::",
          "",
          "         difference = sqrt(tr((sqrt(M1) - sqrt(M2))^2))",
          " normalized overlap = 1 - difference/sqrt(tr(M1) + tr(M2))",
  
      t_topology        top;
      int               ePBC  = -1;
 -    const t_atoms    *atoms = NULL;
 -    rvec             *xtop, *xref1, *xref2, *xrefp = NULL;
 +    const t_atoms    *atoms = nullptr;
 +    rvec             *xtop, *xref1, *xref2, *xrefp = nullptr;
      gmx_bool          bDMR1, bDMA1, bDMR2, bDMA2;
 -    int               nvec1, nvec2, *eignr1 = NULL, *eignr2 = NULL;
 -    rvec             *xav1, *xav2, **eigvec1 = NULL, **eigvec2 = NULL;
 +    int               nvec1, nvec2, *eignr1 = nullptr, *eignr2 = nullptr;
 +    rvec             *xav1, *xav2, **eigvec1 = nullptr, **eigvec2 = nullptr;
      matrix            topbox;
      real              totmass, *sqrtm, *w_rls, t;
      int               natoms;
      const char       *indexfile;
      int               i, j, d;
      int               nout, *iout, noutvec, *outvec, nfit;
 -    int              *index = NULL, *ifit = NULL;
 +    int              *index = nullptr, *ifit = nullptr;
      const char       *VecFile, *Vec2File, *topfile;
      const char       *EigFile, *Eig2File;
      const char       *CompFile, *RmsfFile, *ProjOnVecFile;
      const char       *OverlapFile, *InpMatFile;
      gmx_bool          bFit1, bFit2, bM, bIndex, bTPS, bTop, bVec2, bProj;
      gmx_bool          bFirstToLast, bFirstLastSet, bTraj, bCompare, bPDB3D;
 -    real             *eigval1 = NULL, *eigval2 = NULL;
 +    real             *eigval1 = nullptr, *eigval2 = nullptr;
      int               neig1, neig2;
      double          **xvgdata;
      gmx_output_env_t *oenv;
      t_filenm          fnm[] = {
          { efTRN, "-v",    "eigenvec",    ffREAD  },
          { efTRN, "-v2",   "eigenvec2",   ffOPTRD },
 -        { efTRX, "-f",    NULL,          ffOPTRD },
 -        { efTPS, NULL,    NULL,          ffOPTRD },
 -        { efNDX, NULL,    NULL,          ffOPTRD },
 +        { efTRX, "-f",    nullptr,          ffOPTRD },
 +        { efTPS, nullptr,    nullptr,          ffOPTRD },
 +        { efNDX, nullptr,    nullptr,          ffOPTRD },
          { efXVG, "-eig", "eigenval",     ffOPTRD },
          { efXVG, "-eig2", "eigenval2",   ffOPTRD },
          { efXVG, "-comp", "eigcomp",     ffOPTWR },
  
      if (!parse_common_args(&argc, argv,
                             PCA_CAN_TIME | PCA_TIME_UNIT | PCA_CAN_VIEW,
 -                           NFILE, fnm, NPA, pa, asize(desc), desc, 0, NULL, &oenv))
 +                           NFILE, fnm, NPA, pa, asize(desc), desc, 0, nullptr, &oenv))
      {
          return 0;
      }
      neig1 = DIM*natoms;
  
      /* Overwrite eigenvalues from separate files if the user provides them */
 -    if (EigFile != NULL)
 +    if (EigFile != nullptr)
      {
          int neig_tmp = read_xvg(EigFile, &xvgdata, &i);
          if (neig_tmp != neig1)
          neig2 = 0;
      }
  
 -    if (Eig2File != NULL)
 +    if (Eig2File != nullptr)
      {
          neig2 = read_xvg(Eig2File, &xvgdata, &i);
          srenew(eigval2, neig2);
      {
          bM = FALSE;
      }
 -    if ((xref1 == NULL) && (bM || bTraj))
 +    if ((xref1 == nullptr) && (bM || bTraj))
      {
          bTPS = TRUE;
      }
  
 -    xtop  = NULL;
 +    xtop  = nullptr;
      nfit  = 0;
 -    ifit  = NULL;
 -    w_rls = NULL;
 +    ifit  = nullptr;
 +    w_rls = nullptr;
  
      if (!bTPS)
      {
      else
      {
          bTop = read_tps_conf(ftp2fn(efTPS, NFILE, fnm),
 -                             &top, &ePBC, &xtop, NULL, topbox, bM);
 +                             &top, &ePBC, &xtop, nullptr, topbox, bM);
          atoms = &top.atoms;
          gpbc  = gmx_rmpbc_init(&top.idef, ePBC, atoms->nr);
          gmx_rmpbc(gpbc, atoms->nr, topbox, xtop);
          /* Fitting is only required for the projection */
          if (bProj && bFit1)
          {
 -            if (xref1 == NULL)
 +            if (xref1 == nullptr)
              {
                  printf("\nNote: the structure in %s should be the same\n"
                         "      as the one used for the fit in g_covar\n", topfile);
              }
  
              snew(xrefp, atoms->nr);
 -            if (xref1 != NULL)
 +            if (xref1 != nullptr)
              {
                  /* Safety check between selected fit-group and reference structure read from the eigenvector file */
                  if (natoms != nfit)
                  {
                      copy_rvec(xtop[ifit[i]], xrefp[ifit[i]]);
                  }
 -                reset_x(nfit, ifit, atoms->nr, NULL, xrefp, w_rls);
 +                reset_x(nfit, ifit, atoms->nr, nullptr, xrefp, w_rls);
              }
          }
          gmx_rmpbc_done(gpbc);
      {
          printf("Select eigenvectors for output, end your selection with 0\n");
          nout = -1;
 -        iout = NULL;
 +        iout = nullptr;
  
          do
          {
  
      if (bProj)
      {
 -        project(bTraj ? opt2fn("-f", NFILE, fnm) : NULL,
 -                bTop ? &top : NULL, ePBC, topbox,
 +        project(bTraj ? opt2fn("-f", NFILE, fnm) : nullptr,
 +                bTop ? &top : nullptr, ePBC, topbox,
                  ProjOnVecFile, TwoDPlotFile, ThreeDPlotFile, FilterFile, skip,
                  ExtremeFile, bFirstLastSet, max, nextr, atoms, natoms, index,
                  bFit1, xrefp, nfit, ifit, w_rls,
index 1234232ef53b8773e5410858b37ec14537af1aaf,34a5e03c3119ed662aa41752d7416979b1f0cd00..3c0a8499156b048c9e84dd2c8323e840c1620cdd
@@@ -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,2017, by the GROMACS development team, led by
 - * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
++ * Copyright (c) 2013,2014,2015,2016,2017, 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,7 -75,8 +75,8 @@@ int gmx_covar(int argc, char *argv[]
          "the reference structure for the fit is written first with t=-1.",
          "The average (or reference when [TT]-ref[tt] is used) structure is",
          "written with t=0, the eigenvectors",
-         "are written as frames with the eigenvector number as timestamp.",
+         "are written as frames with the eigenvector number and eigenvalue",
+         "as step number and timestamp, respectively.",
          "[PAR]",
          "The eigenvectors can be analyzed with [gmx-anaeig].",
          "[PAR]",
          { "-pbc",  FALSE,  etBOOL, {&bPBC},
            "Apply corrections for periodic boundary conditions" }
      };
 -    FILE             *out = NULL; /* initialization makes all compilers happy */
 +    FILE             *out = nullptr; /* initialization makes all compilers happy */
      t_trxstatus      *status;
      t_topology        top;
      int               ePBC;
      matrix            box, zerobox;
      real             *sqrtm, *mat, *eigenvalues, sum, trace, inv_nframes;
      real              t, tstart, tend, **mat2;
 -    real              xj, *w_rls = NULL;
 +    real              xj, *w_rls = nullptr;
      real              min, max, *axis;
      int               natoms, nat, nframes0, nframes, nlevels;
      gmx_int64_t       ndim, i, j, k, l;
      t_rgb             rlo, rmi, rhi;
      real             *eigenvectors;
      gmx_output_env_t *oenv;
 -    gmx_rmpbc_t       gpbc = NULL;
 +    gmx_rmpbc_t       gpbc = nullptr;
  
      t_filenm          fnm[] = {
 -        { efTRX, "-f",  NULL, ffREAD },
 -        { efTPS, NULL,  NULL, ffREAD },
 -        { efNDX, NULL,  NULL, ffOPTRD },
 -        { efXVG, NULL,  "eigenval", ffWRITE },
 +        { efTRX, "-f",  nullptr, ffREAD },
 +        { efTPS, nullptr,  nullptr, ffREAD },
 +        { efNDX, nullptr,  nullptr, ffOPTRD },
 +        { efXVG, nullptr,  "eigenval", ffWRITE },
          { efTRN, "-v",  "eigenvec", ffWRITE },
          { efSTO, "-av", "average.pdb", ffWRITE },
 -        { efLOG, NULL,  "covar", ffWRITE },
 +        { efLOG, nullptr,  "covar", ffWRITE },
          { efDAT, "-ascii", "covar", ffOPTWR },
          { efXPM, "-xpm", "covar", ffOPTWR },
          { efXPM, "-xpma", "covara", ffOPTWR }
  #define NFILE asize(fnm)
  
      if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT,
 -                           NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv))
 +                           NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
      {
          return 0;
      }
      xpmfile    = opt2fn_null("-xpm", NFILE, fnm);
      xpmafile   = opt2fn_null("-xpma", NFILE, fnm);
  
 -    read_tps_conf(fitfile, &top, &ePBC, &xref, NULL, box, TRUE);
 +    read_tps_conf(fitfile, &top, &ePBC, &xref, nullptr, box, TRUE);
      atoms = &top.atoms;
  
      if (bFit)
      }
      if (bFit)
      {
 -        reset_x(nfit, ifit, atoms->nr, NULL, xref, w_rls);
 +        reset_x(nfit, ifit, atoms->nr, nullptr, xref, w_rls);
      }
  
      snew(x, natoms);
          }
          if (bFit)
          {
 -            reset_x(nfit, ifit, nat, NULL, xread, w_rls);
 +            reset_x(nfit, ifit, nat, nullptr, xread, w_rls);
              do_fit(nat, w_rls, xref, xread);
          }
          for (i = 0; i < natoms; i++)
          }
      }
      write_sto_conf_indexed(opt2fn("-av", NFILE, fnm), "Average structure",
 -                           atoms, xread, NULL, epbcNONE, zerobox, natoms, index);
 +                           atoms, xread, nullptr, epbcNONE, zerobox, natoms, index);
      sfree(xread);
  
      fprintf(stderr, "Constructing covariance matrix (%dx%d) ...\n", static_cast<int>(ndim), static_cast<int>(ndim));
          }
          if (bFit)
          {
 -            reset_x(nfit, ifit, nat, NULL, xread, w_rls);
 +            reset_x(nfit, ifit, nat, nullptr, xread, w_rls);
              do_fit(nat, w_rls, xref, xread);
          }
          if (bRef)
index 6eb46c47f29335cc55ef77be18aade0e9b27db48,74405013a39c30b3e4f278f7ca657acdd94b0bef..a720ff0cf39670a8401431c3c35a9b21c72adc28
@@@ -223,14 -223,15 +223,15 @@@ void set_pdb_conf_bfac(int natoms, int 
      int      i, n;
      gmx_bool found;
  
+     if (n_bfac > atoms->nres)
+     {
+         peratom = TRUE;
+     }
      bfac_max = -1e10;
      bfac_min = 1e10;
      for (i = 0; (i < n_bfac); i++)
      {
-         if (bfac_nr[i] - 1 >= atoms->nres)
-         {
-             peratom = TRUE;
-         }
          /*    if ((bfac_nr[i]-1<0) || (bfac_nr[i]-1>=atoms->nr))
             gmx_fatal(FARGS,"Index of B-Factor %d is out of range: %d (%g)",
             i+1,bfac_nr[i],bfac[i]); */
@@@ -359,7 -360,7 +360,7 @@@ void visualize_images(const char *fn, i
      }
      calc_triclinic_images(box, img + 1);
  
 -    write_sto_conf(fn, "Images", &atoms, img, NULL, ePBC, box);
 +    write_sto_conf(fn, "Images", &atoms, img, nullptr, ePBC, box);
  
      done_atom(&atoms);
      sfree(img);
@@@ -492,7 -493,7 +493,7 @@@ static void renum_resnr(t_atoms *atoms
      resind_prev = -1;
      for (i = 0; i < isize; i++)
      {
 -        resind = atoms->atom[index == NULL ? i : index[i]].resind;
 +        resind = atoms->atom[index == nullptr ? i : index[i]].resind;
          if (resind != resind_prev)
          {
              atoms->resinfo[resind].nr = resnr_start;
@@@ -564,7 -565,7 +565,7 @@@ int gmx_editconf(int argc, char *argv[]
          "from a file with with following format: first line states number of",
          "entries in the file, next lines state an index",
          "followed by a B-factor. The B-factors will be attached per residue",
-         "unless an index is larger than the number of residues or unless the",
+         "unless the number of B-factors is larger than the number of the residues or unless the",
          "[TT]-atom[tt] option is set. Obviously, any type of numeric data can",
          "be added instead of B-factors. [TT]-legend[tt] will produce",
          "a row of CA atoms with B-factors ranging from the minimum to the",
      { 0, 0, 0 }, targetvec   =
      { 0, 0, 0 };
      static const char *btype[] =
 -    { NULL, "triclinic", "cubic", "dodecahedron", "octahedron", NULL },
 +    { nullptr, "triclinic", "cubic", "dodecahedron", "octahedron", nullptr },
      *label             = "A";
      static rvec visbox =
      { 0, 0, 0 };
      FILE             *out;
      const char       *infile, *outfile;
      int               outftp, inftp, natom, i, j, n_bfac, itype, ntype;
 -    double           *bfac    = NULL, c6, c12;
 -    int              *bfac_nr = NULL;
 -    t_topology       *top     = NULL;
 +    double           *bfac    = nullptr, c6, c12;
 +    int              *bfac_nr = nullptr;
 +    t_topology       *top     = nullptr;
      char             *grpname, *sgrpname, *agrpname;
      int               isize, ssize, asize;
      int              *index, *sindex, *aindex;
      gmx_output_env_t *oenv;
      t_filenm          fnm[] =
      {
 -        { efSTX, "-f", NULL, ffREAD },
 -        { efNDX, "-n", NULL, ffOPTRD },
 -        { efSTO, NULL, NULL, ffOPTWR },
 +        { efSTX, "-f", nullptr, ffREAD },
 +        { efNDX, "-n", nullptr, ffOPTRD },
 +        { efSTO, nullptr, nullptr, ffOPTWR },
          { efPQR, "-mead", "mead", ffOPTWR },
          { efDAT, "-bf", "bfact", ffOPTRD }
      };
      bScale    = bScale || bRho;
      bCalcGeom = bCenter || bRotate || bOrient || bScale;
  
 -    GMX_RELEASE_ASSERT(btype[0] != NULL, "Option setting inconsistency; btype[0] is NULL");
 +    GMX_RELEASE_ASSERT(btype[0] != nullptr, "Option setting inconsistency; btype[0] is NULL");
  
      bCalcDiam = (btype[0][0] == 'c' || btype[0][0] == 'd' || btype[0][0] == 'o');
  
      read_tps_conf(infile, top_tmp, &ePBC, &x, &v, box, FALSE);
      t_atoms  &atoms = top_tmp->atoms;
      natom = atoms.nr;
 -    if (atoms.pdbinfo == NULL)
 +    if (atoms.pdbinfo == nullptr)
      {
          snew(atoms.pdbinfo, atoms.nr);
      }
 +    atoms.havePdbInfo = TRUE;
 +
      if (fn2ftp(infile) == efPDB)
      {
          get_pdb_atomnumber(&atoms, aps);
  
      if (bMead || bGrasp || bCONECT)
      {
 -        top = read_top(infile, NULL);
 +        top = read_top(infile, nullptr);
      }
  
      if (bMead || bGrasp)
          else
          {
              ssize  = atoms.nr;
 -            sindex = NULL;
 +            sindex = nullptr;
          }
          diam = calc_geom(ssize, sindex, x, gc, rmin, rmax, bCalcDiam);
          rvec_sub(rmax, rmin, size);
          get_index(&atoms, ftp2fn_null(efNDX, NFILE, fnm), 1, &isize, &index, &grpnames);
  
          /* Orient the principal axes along the coordinate axes */
 -        orient_princ(&atoms, isize, index, natom, x, bHaveV ? v : NULL, NULL);
 +        orient_princ(&atoms, isize, index, natom, x, bHaveV ? v : nullptr, nullptr);
          sfree(index);
          sfree(grpnames);
      }
          else
          {
              ssize  = atoms.nr;
 -            sindex = NULL;
 +            sindex = nullptr;
          }
          printf("Translating %d atoms (out of %d) by %g %g %g nm\n", ssize, natom,
                 translation[XX], translation[YY], translation[ZZ]);
          }
      }
  
 -    if ((btype[0] != NULL) && (bSetSize || bDist || (btype[0][0] == 't' && bSetAng)))
 +    if ((btype[0] != nullptr) && (bSetSize || bDist || (btype[0][0] == 't' && bSetAng)))
      {
          ePBC = epbcXYZ;
          if (!(bSetSize || bDist))
      }
      else
      {
 -        conect = NULL;
 +        conect = nullptr;
      }
  
      if (bIndex)
          }
          else
          {
 -            write_sto_conf_indexed(outfile, *top_tmp->name, &atoms, x, bHaveV ? v : NULL, ePBC, box, isize, index);
 +            write_sto_conf_indexed(outfile, *top_tmp->name, &atoms, x, bHaveV ? v : nullptr, ePBC, box, isize, index);
          }
      }
      else
      {
          if (resnr_start >= 0)
          {
 -            renum_resnr(&atoms, atoms.nr, NULL, resnr_start);
 +            renum_resnr(&atoms, atoms.nr, nullptr, resnr_start);
          }
  
          if ((outftp == efPDB) || (outftp == efPQR))
          }
          else
          {
 -            write_sto_conf(outfile, *top_tmp->name, &atoms, x, bHaveV ? v : NULL, ePBC, box);
 +            write_sto_conf(outfile, *top_tmp->name, &atoms, x, bHaveV ? v : nullptr, ePBC, box);
          }
      }
      gmx_atomprop_destroy(aps);
  
 -    do_view(oenv, outfile, NULL);
 +    do_view(oenv, outfile, nullptr);
  
      return 0;
  }
index c818723932c8c7bc5914c747441ee1b582d53cff,531c004308585b3300d9337fc5608c0b9a972aa0..f29997f887690cb02468383ee8adfd7f82c634a9
@@@ -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, by the GROMACS development team, led by
 + * Copyright (c) 2013,2014,2015,2016,2017, 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.
@@@ -179,7 -179,7 +179,7 @@@ nma_full_hessian(rea
      eigensolver(hess, ndim, begin-1, end-1, eigenvalues, eigenvectors);
  
      /* And scale the output eigenvectors */
 -    if (bM && eigenvectors != NULL)
 +    if (bM && eigenvectors != nullptr)
      {
          for (int i = 0; i < (end-begin+1); i++)
          {
@@@ -218,7 -218,7 +218,7 @@@ nma_sparse_hessian(gmx_sparsematrix_
      /* Cannot check symmetry since we only store half matrix */
      /* divide elements hess[i][j] by sqrt(mas[i])*sqrt(mas[j]) when required */
  
 -    GMX_RELEASE_ASSERT(sparse_hessian != NULL, "NULL matrix pointer provided to nma_sparse_hessian");
 +    GMX_RELEASE_ASSERT(sparse_hessian != nullptr, "NULL matrix pointer provided to nma_sparse_hessian");
  
      if (bM)
      {
      sparse_eigensolver(sparse_hessian, neig, eigenvalues, eigenvectors, 10000000);
  
      /* Scale output eigenvectors */
 -    if (bM && eigenvectors != NULL)
 +    if (bM && eigenvectors != nullptr)
      {
          for (i = 0; i < neig; i++)
          {
@@@ -302,7 -302,8 +302,8 @@@ int gmx_nmeig(int argc, char *argv[]
          "which can be calculated with [gmx-mdrun].",
          "The eigenvectors are written to a trajectory file ([TT]-v[tt]).",
          "The structure is written first with t=0. The eigenvectors",
-         "are written as frames with the eigenvector number as timestamp.",
+         "are written as frames with the eigenvector number and eigenvalue",
+         "written as step number and timestamp, respectively.",
          "The eigenvectors can be analyzed with [gmx-anaeig].",
          "An ensemble of structures can be generated from the eigenvectors with",
          "[gmx-nmens]. When mass weighting is used, the generated eigenvectors",
      real                   value, omega, nu;
      real                   factor_gmx_to_omega2;
      real                   factor_omega_to_wavenumber;
 -    real                  *spectrum = NULL;
 +    real                  *spectrum = nullptr;
      real                   wfac;
      gmx_output_env_t      *oenv;
      const char            *qcleg[] = {
          "Heat Capacity cV (J/mol K)",
          "Enthalpy H (kJ/mol)"
      };
 -    real *                 full_hessian   = NULL;
 -    gmx_sparsematrix_t *   sparse_hessian = NULL;
 +    real *                 full_hessian   = nullptr;
 +    gmx_sparsematrix_t *   sparse_hessian = nullptr;
  
      t_filenm               fnm[] = {
          { efMTX, "-f", "hessian",    ffREAD  },
 -        { efTPR, NULL, NULL,         ffREAD  },
 +        { efTPR, nullptr, nullptr,         ffREAD  },
          { efXVG, "-of", "eigenfreq", ffWRITE },
          { efXVG, "-ol", "eigenval",  ffWRITE },
          { efXVG, "-os", "spectrum",  ffOPTWR },
  #define NFILE asize(fnm)
  
      if (!parse_common_args(&argc, argv, 0,
 -                           NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv))
 +                           NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
      {
          return 0;
      }
      snew(top_x, tpx.natoms);
  
      int natoms_tpx;
 -    read_tpx(ftp2fn(efTPR, NFILE, fnm), NULL, box, &natoms_tpx,
 -             top_x, NULL, &mtop);
 +    read_tpx(ftp2fn(efTPR, NFILE, fnm), nullptr, box, &natoms_tpx,
 +             top_x, nullptr, &mtop);
      int nharm = 0;
      if (bCons)
      {
      }
      std::vector<size_t> atom_index = get_atom_index(&mtop);
  
 -    top = gmx_mtop_t_to_t_topology(&mtop);
 +    top = gmx_mtop_t_to_t_topology(&mtop, true);
  
      bM       = TRUE;
      int ndim = DIM*atom_index.size();
       * If this is not valid we convert to full matrix storage,
       * but warn the user that we might run out of memory...
       */
 -    if ((sparse_hessian != NULL) && (end == ndim))
 +    if ((sparse_hessian != nullptr) && (end == ndim))
      {
          fprintf(stderr, "Cannot use sparse Hessian to calculate all eigenvectors.\n");
  
              }
          }
          gmx_sparsematrix_destroy(sparse_hessian);
 -        sparse_hessian = NULL;
 +        sparse_hessian = nullptr;
          fprintf(stderr, "Converted sparse to full matrix storage.\n");
      }
  
      snew(eigenvalues, nrow);
  
 -    if (full_hessian != NULL)
 +    if (full_hessian != nullptr)
      {
          /* Using full matrix storage */
          eigenvectors = allocateEigenvectors(nrow, begin, end, false);
      }
      else
      {
 -        qc = NULL;
 +        qc = nullptr;
      }
      printf("Writing eigenfrequencies - negative eigenvalues will be set to zero.\n");
  
          }
      }
      /* Spectrum ? */
 -    spec = NULL;
 +    spec = nullptr;
      if (opt2bSet("-os", NFILE, fnm) && (maxspec > 0))
      {
          snew(spectrum, maxspec);
          nu    = 1e-12*omega/(2*M_PI);
          value = omega*factor_omega_to_wavenumber;
          fprintf (out, "%6d %15g\n", i, value);
 -        if (NULL != spec)
 +        if (nullptr != spec)
          {
              wfac = eigenvalues[i-begin]/(width*std::sqrt(2*M_PI));
              for (j = 0; (j < maxspec); j++)
                  spectrum[j] += wfac*std::exp(-gmx::square(j-value)/(2*gmx::square(width)));
              }
          }
 -        if (NULL != qc)
 +        if (nullptr != qc)
          {
              qcv = cv_corr(nu, T);
              qu  = u_corr(nu, T);
          }
      }
      xvgrclose(out);
 -    if (NULL != spec)
 +    if (nullptr != spec)
      {
          for (j = 0; (j < maxspec); j++)
          {
          }
          xvgrclose(spec);
      }
 -    if (NULL != qc)
 +    if (nullptr != qc)
      {
          printf("Quantum corrections for harmonic degrees of freedom\n");
          printf("Use appropriate -first and -last options to get reliable results.\n");
       * will not be strictly orthogonal in plain cartesian scalar products.
       */
      const real *eigenvectorPtr;
 -    if (full_hessian != NULL)
 +    if (full_hessian != nullptr)
      {
          eigenvectorPtr = eigenvectors;
      }
          eigenvectorPtr = eigenvectors + (begin - 1)*atom_index.size();
      }
      write_eigenvectors(opt2fn("-v", NFILE, fnm), atom_index.size(), eigenvectorPtr, FALSE, begin, end,
 -                       eWXR_NO, NULL, FALSE, top_x, bM, eigenvalues);
 +                       eWXR_NO, nullptr, FALSE, top_x, bM, eigenvalues);
  
      return 0;
  }
index 251d81a5eae0180b72e5834f42e692b3cae3b1f0,90dc653b1ab0a2c9083537e4cb021997e6d9aa0c..ca8eae0e00e50f2c38f769230384b36d455814a3
  #include "gromacs/commandline/pargs.h"
  #include "gromacs/fft/calcgrid.h"
  #include "gromacs/fileio/checkpoint.h"
 -#include "gromacs/fileio/readinp.h"
  #include "gromacs/fileio/tpxio.h"
  #include "gromacs/gmxana/gmx_ana.h"
  #include "gromacs/math/utilities.h"
  #include "gromacs/math/vec.h"
  #include "gromacs/mdlib/perf_est.h"
 +#include "gromacs/mdrunutility/mdmodules.h"
  #include "gromacs/mdtypes/commrec.h"
  #include "gromacs/mdtypes/inputrec.h"
  #include "gromacs/mdtypes/md_enums.h"
@@@ -168,7 -168,7 +168,7 @@@ static void finalize(const char *fn_out
      fp = fopen(fn_out, "r");
      fprintf(stdout, "\n\n");
  
 -    while (fgets(buf, STRLEN-1, fp) != NULL)
 +    while (fgets(buf, STRLEN-1, fp) != nullptr)
      {
          fprintf(stdout, "%s", buf);
      }
@@@ -218,13 -218,13 +218,13 @@@ static int parse_logfile(const char *lo
          iFound = eFoundDDStr; /* Skip some case statements */
      }
  
 -    while (fgets(line, STRLEN, fp) != NULL)
 +    while (fgets(line, STRLEN, fp) != nullptr)
      {
          /* Remove leading spaces */
          ltrim(line);
  
          /* Check for TERM and INT signals from user: */
 -        if (std::strstr(line, errSIG) != NULL)
 +        if (std::strstr(line, errSIG) != nullptr)
          {
              fclose(fp);
              cleandata(perfdata, test_nr);
          /* Check whether cycle resetting  worked */
          if (presteps > 0 && !bFoundResetStr)
          {
 -            if (std::strstr(line, matchstrcr) != NULL)
 +            if (std::strstr(line, matchstrcr) != nullptr)
              {
                  sprintf(dumstring, "step %s", "%" GMX_SCNd64);
                  sscanf(line, dumstring, &resetsteps);
      if (gmx_fexist(errfile))
      {
          fp = fopen(errfile, "r");
 -        while (fgets(line, STRLEN, fp) != NULL)
 +        while (fgets(line, STRLEN, fp) != nullptr)
          {
              if (str_starts(line, "Fatal error:") )
              {
 -                if (fgets(line, STRLEN, fp) != NULL)
 +                if (fgets(line, STRLEN, fp) != nullptr)
                  {
                      fprintf(stderr, "\nWARNING: An error occurred during this benchmark:\n"
                              "%s\n", line);
@@@ -607,7 -607,7 +607,7 @@@ static void get_program_paths(gmx_bool 
      /* Get the commands we need to set up the runs from environment variables */
      if (!bThreads)
      {
 -        if ( (cp = getenv("MPIRUN")) != NULL)
 +        if ( (cp = getenv("MPIRUN")) != nullptr)
          {
              *cmd_mpirun = gmx_strdup(cp);
          }
          *cmd_mpirun = gmx_strdup(empty_mpirun);
      }
  
 -    if (*cmd_mdrun == NULL)
 +    if (*cmd_mdrun == nullptr)
      {
          /* The use of MDRUN is deprecated, but made available in 5.1
             for backward compatibility. It may be removed in a future
             version. */
 -        if ( (cp = getenv("MDRUN" )) != NULL)
 +        if ( (cp = getenv("MDRUN" )) != nullptr)
          {
              *cmd_mdrun = gmx_strdup(cp);
          }
@@@ -649,7 -649,7 +649,7 @@@ static void check_mdrun_works(gmx_boo
                                const char *cmd_mdrun,
                                gmx_bool    bNeedGpuSupport)
  {
 -    char      *command = NULL;
 +    char      *command = nullptr;
      char      *cp;
      char       line[STRLEN];
      FILE      *fp;
      while (!feof(fp) )
      {
          cp = fgets(line, STRLEN, fp);
 -        if (cp != NULL)
 +        if (cp != nullptr)
          {
              if (str_starts(line, match_mdrun) )
              {
@@@ -869,13 -869,12 +869,13 @@@ static void modify_PMEsettings
          const char     *fn_best_tpr, /* tpr file with the best performance */
          const char     *fn_sim_tpr)  /* name of tpr file to be launched */
  {
 -    t_inputrec   *ir;
 -    t_state       state;
 -    gmx_mtop_t    mtop;
 -    char          buf[200];
 +    t_inputrec    *ir;
 +    t_state        state;
 +    gmx_mtop_t     mtop;
 +    char           buf[200];
  
 -    snew(ir, 1);
 +    gmx::MDModules mdModules;
 +    ir = mdModules.inputrec();
      read_tpx_state(fn_best_tpr, ir, &state, &mtop);
  
      /* Reset nsteps and init_step to the value of the input .tpr file */
      fprintf(stdout, buf, ir->nsteps);
      fflush(stdout);
      write_tpx_state(fn_sim_tpr, ir, &state, &mtop);
 -
 -    sfree(ir);
  }
  
  static gmx_bool can_scale_rvdw(int vdwtype)
@@@ -936,8 -937,8 +936,8 @@@ static void make_benchmark_tprs
      }
      fprintf(stdout, ".\n");
  
 -
 -    snew(ir, 1);
 +    gmx::MDModules mdModules;
 +    ir = mdModules.inputrec();
      read_tpx_state(fn_sim_tpr, ir, &state, &mtop);
  
      /* Check if some kind of PME was chosen */
  
              /* Scale the Fourier grid spacing */
              ir->nkx = ir->nky = ir->nkz = 0;
 -            calc_grid(NULL, state.box, fourierspacing*fac, &ir->nkx, &ir->nky, &ir->nkz);
 +            calc_grid(nullptr, state.box, fourierspacing*fac, &ir->nkx, &ir->nky, &ir->nkz);
  
              /* Adjust other radii since various conditions need to be fulfilled */
              if (eelPME == ir->coulombtype)
      }
      fflush(stdout);
      fflush(fp);
 -    sfree(ir);
  }
  
  
@@@ -1178,7 -1180,7 +1178,7 @@@ static void cleanup(const t_filenm *fnm
  {
      char        numstring[STRLEN];
      char        newfilename[STRLEN];
 -    const char *fn = NULL;
 +    const char *fn = nullptr;
      int         i;
      const char *opt;
  
@@@ -1447,8 -1449,8 +1447,8 @@@ static void do_the_tests
                                                     * constructing mdrun command lines */
  {
      int      i, nr, k, ret, count = 0, totaltests;
 -    int     *nPMEnodes = NULL;
 -    t_perf  *pd        = NULL;
 +    int     *nPMEnodes = nullptr;
 +    t_perf  *pd        = nullptr;
      int      cmdline_length;
      char    *command, *cmd_stub;
      char     buf[STRLEN];
          /* Loop over various numbers of PME nodes: */
          for (i = 0; i < *pmeentries; i++)
          {
 -            char *cmd_gpu_ids = NULL;
 +            char *cmd_gpu_ids = nullptr;
  
              pd = &perfdata[k][i];
  
@@@ -2045,22 -2047,20 +2045,22 @@@ static float inspect_tpr(int nfile, t_f
      gmx_bool     bFree;     /* Is a free energy simulation requested?         */
      gmx_bool     bNM;       /* Is a normal mode analysis requested?           */
      gmx_bool     bSwap;     /* Is water/ion position swapping requested?      */
 -    t_inputrec   ir;
 +    t_inputrec  *ir;
      t_state      state;
      gmx_mtop_t   mtop;
  
  
      /* Check tpr file for options that trigger extra output files */
 -    read_tpx_state(opt2fn("-s", nfile, fnm), &ir, &state, &mtop);
 -    bFree = (efepNO  != ir.efep );
 -    bNM   = (eiNM    == ir.eI   );
 -    bSwap = (eswapNO != ir.eSwapCoords);
 -    bTpi  = EI_TPI(ir.eI);
 +    gmx::MDModules mdModules;
 +    ir = mdModules.inputrec();
 +    read_tpx_state(opt2fn("-s", nfile, fnm), ir, &state, &mtop);
 +    bFree = (efepNO  != ir->efep );
 +    bNM   = (eiNM    == ir->eI   );
 +    bSwap = (eswapNO != ir->eSwapCoords);
 +    bTpi  = EI_TPI(ir->eI);
  
      /* Set these output files on the tuning command-line */
 -    if (ir.bPull)
 +    if (ir->bPull)
      {
          setopt("-pf", nfile, fnm);
          setopt("-px", nfile, fnm);
          setopt("-swap", nfile, fnm);
      }
  
 -    *rcoulomb = ir.rcoulomb;
 +    *rcoulomb = ir->rcoulomb;
  
      /* Return the estimate for the number of PME nodes */
 -    return pme_load_estimate(&mtop, &ir, state.box);
 +    float npme = pme_load_estimate(&mtop, ir, state.box);
 +    return npme;
  }
  
  
@@@ -2202,30 -2201,30 +2202,30 @@@ int gmx_tune_pme(int argc, char *argv[]
      real            rcoulomb       = -1.0;            /* Coulomb radius as set in .tpr file */
      gmx_bool        bScaleRvdw     = TRUE;
      gmx_int64_t     bench_nsteps   = BENCHSTEPS;
-     gmx_int64_t     new_sim_nsteps = -1;  /* -1 indicates: not set by the user */
-     gmx_int64_t     cpt_steps      = 0;   /* Step counter in .cpt input file   */
-     int             presteps       = 100; /* Do a full cycle reset after presteps steps */
+     gmx_int64_t     new_sim_nsteps = -1;   /* -1 indicates: not set by the user */
+     gmx_int64_t     cpt_steps      = 0;    /* Step counter in .cpt input file   */
+     int             presteps       = 1500; /* Do a full cycle reset after presteps steps */
      gmx_bool        bOverwrite     = FALSE, bKeepTPR;
      gmx_bool        bLaunch        = FALSE;
 -    char           *ExtraArgs      = NULL;
 -    char          **tpr_names      = NULL;
 -    const char     *simulation_tpr = NULL;
 -    char           *deffnm         = NULL;
 +    char           *ExtraArgs      = nullptr;
 +    char          **tpr_names      = nullptr;
 +    const char     *simulation_tpr = nullptr;
 +    char           *deffnm         = nullptr;
      int             best_npme, best_tpr;
      int             sim_part = 1; /* For benchmarks with checkpoint files */
      char            bbuf[STRLEN];
  
  
      /* Default program names if nothing else is found */
 -    char               *cmd_mpirun = NULL, *cmd_mdrun = NULL;
 +    char               *cmd_mpirun = nullptr, *cmd_mdrun = nullptr;
      char               *cmd_args_bench, *cmd_args_launch;
 -    char               *cmd_np           = NULL;
 +    char               *cmd_np           = nullptr;
  
      /* IDs of GPUs that are eligible for computation */
 -    char               *eligible_gpu_ids = NULL;
 -    t_eligible_gpu_ids *gpu_ids          = NULL;
 +    char               *eligible_gpu_ids = nullptr;
 +    t_eligible_gpu_ids *gpu_ids          = nullptr;
  
 -    t_perf            **perfdata = NULL;
 +    t_perf            **perfdata = nullptr;
      t_inputinfo        *info;
      int                 i;
      FILE               *fp;
          { efLOG, "-err",    "bencherr", ffWRITE },
          { efTPR, "-so",     "tuned",    ffWRITE },
          /* mdrun: */
 -        { efTPR, NULL,      NULL,       ffREAD },
 -        { efTRN, "-o",      NULL,       ffWRITE },
 -        { efCOMPRESSED, "-x", NULL,     ffOPTWR },
 -        { efCPT, "-cpi",    NULL,       ffOPTRD },
 -        { efCPT, "-cpo",    NULL,       ffOPTWR },
 +        { efTPR, nullptr,      nullptr,       ffREAD },
 +        { efTRN, "-o",      nullptr,       ffWRITE },
 +        { efCOMPRESSED, "-x", nullptr,     ffOPTWR },
 +        { efCPT, "-cpi",    nullptr,       ffOPTRD },
 +        { efCPT, "-cpo",    nullptr,       ffOPTWR },
          { efSTO, "-c",      "confout",  ffWRITE },
          { efEDR, "-e",      "ener",     ffWRITE },
          { efLOG, "-g",      "md",       ffWRITE },
      int             nthreads = 1;
  
      const char     *procstring[] =
 -    { NULL, "np", "n", "none", NULL };
 +    { nullptr, "np", "n", "none", nullptr };
      const char     *npmevalues_opt[] =
 -    { NULL, "auto", "all", "subset", NULL };
 +    { nullptr, "auto", "all", "subset", nullptr };
  
      gmx_bool          bAppendFiles          = TRUE;
      gmx_bool          bKeepAndNumCPT        = FALSE;
      gmx_bool          bBenchmark            = TRUE;
      gmx_bool          bCheck                = TRUE;
  
 -    gmx_output_env_t *oenv = NULL;
 +    gmx_output_env_t *oenv = nullptr;
  
      t_pargs           pa[] = {
          /***********************/
  
      if (!parse_common_args(&argc, argv, PCA_NOEXIT_ON_ARGS,
                             NFILE, fnm, asize(pa), pa, asize(desc), desc,
 -                           0, NULL, &oenv))
 +                           0, nullptr, &oenv))
      {
          return 0;
      }
  
      // procstring[0] is used inside two different conditionals further down
 -    GMX_RELEASE_ASSERT(procstring[0] != NULL, "Options inconsistency; procstring[0] is NULL");
 +    GMX_RELEASE_ASSERT(procstring[0] != nullptr, "Options inconsistency; procstring[0] is NULL");
  
      /* Store the remaining unparsed command line entries in a string which
       * is then attached to the mdrun command line */
      get_program_paths(bThreads, &cmd_mpirun, &cmd_mdrun);
      if (bBenchmark && repeats > 0)
      {
 -        check_mdrun_works(bThreads, cmd_mpirun, cmd_np, cmd_mdrun, NULL != eligible_gpu_ids);
 +        check_mdrun_works(bThreads, cmd_mpirun, cmd_np, cmd_mdrun, nullptr != eligible_gpu_ids);
      }
  
      /* Print some header info to file */
      snew(perfdata, ntprs);
      if (bBenchmark)
      {
 -        GMX_RELEASE_ASSERT(npmevalues_opt[0] != NULL, "Options inconsistency; npmevalues_opt[0] is NULL");
 +        GMX_RELEASE_ASSERT(npmevalues_opt[0] != nullptr, "Options inconsistency; npmevalues_opt[0] is NULL");
          do_the_tests(fp, tpr_names, maxPMEnodes, minPMEnodes, npme_fixed, npmevalues_opt[0], perfdata, &pmeentries,
                       repeats, nnodes, ntprs, bThreads, cmd_mpirun, cmd_np, cmd_mdrun,
                       cmd_args_bench, fnm, NFILE, presteps, cpt_steps, bCheck, gpu_ids);
index b3529be7ca456cbb6aebbc94146c952b06df4ea5,dd00b95f1beee1b82c5140610a0a21e017c4cabd..d959351aef40b5ae2fcc2d14a6409efc95147dcf
@@@ -61,6 -61,7 +61,6 @@@
  #include "gromacs/ewald/pme.h"
  #include "gromacs/fileio/confio.h"
  #include "gromacs/fileio/mtxio.h"
 -#include "gromacs/gmxlib/md_logging.h"
  #include "gromacs/gmxlib/network.h"
  #include "gromacs/gmxlib/nrnb.h"
  #include "gromacs/imd/imd.h"
@@@ -76,7 -77,6 +76,7 @@@
  #include "gromacs/mdlib/mdatoms.h"
  #include "gromacs/mdlib/mdebin.h"
  #include "gromacs/mdlib/mdrun.h"
 +#include "gromacs/mdlib/mdsetup.h"
  #include "gromacs/mdlib/ns.h"
  #include "gromacs/mdlib/shellfc.h"
  #include "gromacs/mdlib/sim_util.h"
  #include "gromacs/timing/wallcycle.h"
  #include "gromacs/timing/walltime_accounting.h"
  #include "gromacs/topology/mtop_util.h"
 +#include "gromacs/topology/topology.h"
  #include "gromacs/utility/cstringutil.h"
  #include "gromacs/utility/exceptions.h"
  #include "gromacs/utility/fatalerror.h"
 +#include "gromacs/utility/logger.h"
  #include "gromacs/utility/smalloc.h"
  
  //! Utility structure for manipulating states during EM
  typedef struct {
      //! Copy of the global state
 -    t_state  s;
 +    t_state          s;
      //! Force array
 -    rvec    *f;
 +    PaddedRVecVector f;
      //! Potential energy
 -    real     epot;
 +    real             epot;
      //! Norm of the force
 -    real     fnorm;
 +    real             fnorm;
      //! Maximum force
 -    real     fmax;
 +    real             fmax;
      //! Direction
 -    int      a_fmax;
 +    int              a_fmax;
  } em_state_t;
  
 -//! Initiate em_state_t structure and return pointer to it
 -static em_state_t *init_em_state()
 -{
 -    em_state_t *ems;
 -
 -    snew(ems, 1);
 -
 -    /* does this need to be here?  Should the array be declared differently (staticaly)in the state definition? */
 -    snew(ems->s.lambda, efptNR);
 -
 -    return ems;
 -}
 -
  //! Print the EM starting conditions
  static void print_em_start(FILE                     *fplog,
                             t_commrec                *cr,
@@@ -184,7 -195,7 +184,7 @@@ static void warn_step(FILE *fp, real ft
  //! Print message about convergence of the EM
  static void print_converged(FILE *fp, const char *alg, real ftol,
                              gmx_int64_t count, gmx_bool bDone, gmx_int64_t nsteps,
 -                            real epot, real fmax, int nfmax, real fnorm)
 +                            const em_state_t *ems, double sqrtNumAtoms)
  {
      char buf[STEPSTRSIZE];
  
      }
  
  #if GMX_DOUBLE
 -    fprintf(fp, "Potential Energy  = %21.14e\n", epot);
 -    fprintf(fp, "Maximum force     = %21.14e on atom %d\n", fmax, nfmax+1);
 -    fprintf(fp, "Norm of force     = %21.14e\n", fnorm);
 +    fprintf(fp, "Potential Energy  = %21.14e\n", ems->epot);
 +    fprintf(fp, "Maximum force     = %21.14e on atom %d\n", ems->fmax, ems->a_fmax + 1);
 +    fprintf(fp, "Norm of force     = %21.14e\n", ems->fnorm/sqrtNumAtoms);
  #else
 -    fprintf(fp, "Potential Energy  = %14.7e\n", epot);
 -    fprintf(fp, "Maximum force     = %14.7e on atom %d\n", fmax, nfmax+1);
 -    fprintf(fp, "Norm of force     = %14.7e\n", fnorm);
 +    fprintf(fp, "Potential Energy  = %14.7e\n", ems->epot);
 +    fprintf(fp, "Maximum force     = %14.7e on atom %d\n", ems->fmax, ems->a_fmax + 1);
 +    fprintf(fp, "Norm of force     = %14.7e\n", ems->fnorm/sqrtNumAtoms);
  #endif
  }
  
  //! Compute the norm and max of the force array in parallel
  static void get_f_norm_max(t_commrec *cr,
 -                           t_grpopts *opts, t_mdatoms *mdatoms, rvec *f,
 +                           t_grpopts *opts, t_mdatoms *mdatoms, const rvec *f,
                             real *fnorm, real *fmax, int *a_fmax)
  {
      double fnorm2, *sum;
@@@ -315,8 -326,7 +315,8 @@@ static void get_state_f_norm_max(t_comm
                                   t_grpopts *opts, t_mdatoms *mdatoms,
                                   em_state_t *ems)
  {
 -    get_f_norm_max(cr, opts, mdatoms, ems->f, &ems->fnorm, &ems->fmax, &ems->a_fmax);
 +    get_f_norm_max(cr, opts, mdatoms, as_rvec_array(ems->f.data()),
 +                   &ems->fnorm, &ems->fmax, &ems->a_fmax);
  }
  
  //! Initialize the energy minimization
@@@ -324,15 -334,17 +324,15 @@@ void init_em(FILE *fplog, const char *t
               t_commrec *cr, t_inputrec *ir,
               t_state *state_global, gmx_mtop_t *top_global,
               em_state_t *ems, gmx_localtop_t **top,
 -             rvec **f,
               t_nrnb *nrnb, rvec mu_tot,
               t_forcerec *fr, gmx_enerdata_t **enerd,
               t_graph **graph, t_mdatoms *mdatoms, gmx_global_stat_t *gstat,
 -             gmx_vsite_t *vsite, gmx_constr_t constr,
 +             gmx_vsite_t *vsite, gmx_constr_t constr, gmx_shellfc_t **shellfc,
               int nfile, const t_filenm fnm[],
               gmx_mdoutf_t *outf, t_mdebin **mdebin,
               int imdport, unsigned long gmx_unused Flags,
               gmx_wallcycle_t wcycle)
  {
 -    int  i;
      real dvdl_constr;
  
      if (fplog)
      state_global->ngtc = 0;
  
      /* Initialize lambda variables */
 -    initialize_lambdas(fplog, ir, &(state_global->fep_state), state_global->lambda, NULL);
 +    initialize_lambdas(fplog, ir, &(state_global->fep_state), &state_global->lambda, nullptr);
  
      init_nrnb(nrnb);
  
      /* Interactive molecular dynamics */
 -    init_IMD(ir, cr, top_global, fplog, 1, state_global->x,
 -             nfile, fnm, NULL, imdport, Flags);
 +    init_IMD(ir, cr, top_global, fplog, 1, as_rvec_array(state_global->x.data()),
 +             nfile, fnm, nullptr, imdport, Flags);
 +
 +    if (ir->eI == eiNM)
 +    {
 +        GMX_ASSERT(shellfc != NULL, "With NM we always support shells");
 +
 +        *shellfc = init_shell_flexcon(stdout,
 +                                      top_global,
 +                                      n_flexible_constraints(constr),
 +                                      ir->nstcalcenergy,
 +                                      DOMAINDECOMP(cr));
 +    }
 +    else
 +    {
 +        GMX_ASSERT(EI_ENERGY_MINIMIZATION(ir->eI), "This else currently only handles energy minimizers, consider if your algorithm needs shell/flexible-constraint support");
 +
 +        /* With energy minimization, shells and flexible constraints are
 +         * automatically minimized when treated like normal DOFS.
 +         */
 +        if (shellfc != nullptr)
 +        {
 +            *shellfc = nullptr;
 +        }
 +    }
  
      if (DOMAINDECOMP(cr))
      {
  
          dd_init_local_state(cr->dd, state_global, &ems->s);
  
 -        *f = NULL;
 -
          /* Distribute the charge groups over the nodes from the master node */
          dd_partition_system(fplog, ir->init_step, cr, TRUE, 1,
                              state_global, top_global, ir,
                              &ems->s, &ems->f, mdatoms, *top,
                              fr, vsite, constr,
 -                            nrnb, NULL, FALSE);
 +                            nrnb, nullptr, FALSE);
          dd_store_state(cr->dd, &ems->s);
  
 -        *graph = NULL;
 +        *graph = nullptr;
      }
      else
      {
 -        snew(*f, top_global->natoms);
 -
          /* Just copy the state */
          ems->s = *state_global;
          /* We need to allocate one element extra, since we might use
           * (unaligned) 4-wide SIMD loads to access rvec entries.
           */
 -        snew(ems->s.x, ems->s.nalloc + 1);
 -        snew(ems->f, ems->s.nalloc+1);
 -        snew(ems->s.v, ems->s.nalloc+1);
 -        for (i = 0; i < state_global->natoms; i++)
 -        {
 -            copy_rvec(state_global->x[i], ems->s.x[i]);
 -        }
 -        copy_mat(state_global->box, ems->s.box);
 +        ems->s.x.resize(ems->s.natoms + 1);
 +        ems->f.resize(ems->s.natoms + 1);
  
 -        *top      = gmx_mtop_generate_local_top(top_global, ir->efep != efepNO);
 -
 -        setup_bonded_threading(fr, &(*top)->idef);
 -
 -        if (ir->ePBC != epbcNONE && !fr->bMolPBC)
 -        {
 -            *graph = mk_graph(fplog, &((*top)->idef), 0, top_global->natoms, FALSE, FALSE);
 -        }
 -        else
 -        {
 -            *graph = NULL;
 -        }
 -
 -        atoms2md(top_global, ir, 0, NULL, top_global->natoms, mdatoms);
 +        snew(*top, 1);
 +        mdAlgorithmsSetupAtomData(cr, ir, top_global, *top, fr,
 +                                  graph, mdatoms,
 +                                  vsite, shellfc ? *shellfc : nullptr);
  
-         update_mdatoms(mdatoms, state_global->lambda[efptFEP]);
          if (vsite)
          {
              set_vsite_top(vsite, *top, mdatoms, cr);
          }
      }
  
+     update_mdatoms(mdatoms, state_global->lambda[efptMASS]);
      if (constr)
      {
          if (ir->eConstrAlg == econtSHAKE &&
          {
              /* Constrain the starting coordinates */
              dvdl_constr = 0;
 -            constrain(PAR(cr) ? NULL : fplog, TRUE, TRUE, constr, &(*top)->idef,
 +            constrain(PAR(cr) ? nullptr : fplog, TRUE, TRUE, constr, &(*top)->idef,
                        ir, cr, -1, 0, 1.0, mdatoms,
 -                      ems->s.x, ems->s.x, NULL, fr->bMolPBC, ems->s.box,
 +                      as_rvec_array(ems->s.x.data()),
 +                      as_rvec_array(ems->s.x.data()),
 +                      nullptr,
 +                      fr->bMolPBC, ems->s.box,
                        ems->s.lambda[efptFEP], &dvdl_constr,
 -                      NULL, NULL, nrnb, econqCoord);
 +                      nullptr, nullptr, nrnb, econqCoord);
          }
      }
  
      }
      else
      {
 -        *gstat = NULL;
 +        *gstat = nullptr;
      }
  
 -    *outf = init_mdoutf(fplog, nfile, fnm, 0, cr, ir, top_global, NULL, wcycle);
 +    *outf = init_mdoutf(fplog, nfile, fnm, 0, cr, ir, top_global, nullptr, wcycle);
  
      snew(*enerd, 1);
      init_enerdata(top_global->groups.grps[egcENER].nr, ir->fepvals->n_lambda,
                    *enerd);
  
 -    if (mdebin != NULL)
 +    if (mdebin != nullptr)
      {
          /* Init bin for energy stuff */
 -        *mdebin = init_mdebin(mdoutf_get_fp_ene(*outf), top_global, ir, NULL);
 +        *mdebin = init_mdebin(mdoutf_get_fp_ene(*outf), top_global, ir, nullptr);
      }
  
      clear_rvec(mu_tot);
  }
  
  //! Finalize the minimization
 -static void finish_em(t_commrec *cr, gmx_mdoutf_t outf,
 +static void finish_em(t_commrec *cr, gmx_mdoutf_t outf, const t_inputrec *ir,
                        gmx_walltime_accounting_t walltime_accounting,
                        gmx_wallcycle_t wcycle)
  {
          gmx_pme_send_finish(cr);
      }
  
 -    done_mdoutf(outf);
 +    done_mdoutf(outf, ir);
  
      em_time_end(walltime_accounting, wcycle);
  }
  
  //! Swap two different EM states during minimization
 -static void swap_em_state(em_state_t *ems1, em_state_t *ems2)
 +static void swap_em_state(em_state_t **ems1, em_state_t **ems2)
  {
 -    em_state_t tmp;
 +    em_state_t *tmp;
  
      tmp   = *ems1;
      *ems1 = *ems2;
      *ems2 = tmp;
  }
  
 -//! Copy coordinate from an EM state to a "normal" state structure
 -static void copy_em_coords(em_state_t *ems, t_state *state)
 -{
 -    int i;
 -
 -    for (i = 0; (i < state->natoms); i++)
 -    {
 -        copy_rvec(ems->s.x[i], state->x[i]);
 -    }
 -}
 -
  //! Save the EM trajectory
  static void write_em_traj(FILE *fplog, t_commrec *cr,
                            gmx_mdoutf_t outf,
                            gmx_mtop_t *top_global,
                            t_inputrec *ir, gmx_int64_t step,
                            em_state_t *state,
 -                          t_state *state_global)
 +                          t_state *state_global,
 +                          energyhistory_t *energyHistory)
  {
 -    int      mdof_flags;
 -    gmx_bool bIMDout = FALSE;
 -
 +    int mdof_flags = 0;
  
 -    /* Shall we do IMD output? */
 -    if (ir->bIMD)
 -    {
 -        bIMDout = do_per_step(step, IMD_get_step(ir->imd->setup));
 -    }
 -
 -    if ((bX || bF || bIMDout || confout != NULL) && !DOMAINDECOMP(cr))
 -    {
 -        copy_em_coords(state, state_global);
 -    }
 -
 -    mdof_flags = 0;
      if (bX)
      {
          mdof_flags |= MDOF_X;
  
      mdoutf_write_to_trajectory_files(fplog, cr, outf, mdof_flags,
                                       top_global, step, (double)step,
 -                                     &state->s, state_global, state->f);
 +                                     &state->s, state_global, energyHistory,
 +                                     &state->f);
  
 -    if (confout != NULL && MASTER(cr))
 +    if (confout != nullptr && MASTER(cr))
      {
          if (ir->ePBC != epbcNONE && !ir->bPeriodicMols && DOMAINDECOMP(cr))
          {
              /* Make molecules whole only for confout writing */
              do_pbc_mtop(fplog, ir->ePBC, state_global->box, top_global,
 -                        state_global->x);
 +                        as_rvec_array(state_global->x.data()));
          }
  
          write_sto_conf_mtop(confout,
                              *top_global->name, top_global,
 -                            state_global->x, NULL, ir->ePBC, state_global->box);
 +                            as_rvec_array(state_global->x.data()), nullptr, ir->ePBC, state_global->box);
      }
  }
  
  // \returns true when the step succeeded, false when a constraint error occurred
  static bool do_em_step(t_commrec *cr, t_inputrec *ir, t_mdatoms *md,
                         gmx_bool bMolPBC,
 -                       em_state_t *ems1, real a, rvec *f, em_state_t *ems2,
 +                       em_state_t *ems1, real a, const PaddedRVecVector *force,
 +                       em_state_t *ems2,
                         gmx_constr_t constr, gmx_localtop_t *top,
                         t_nrnb *nrnb, gmx_wallcycle_t wcycle,
                         gmx_int64_t count)
  
      s2->flags = s1->flags;
  
 -    if (s2->nalloc != s1->nalloc)
 +    if (s2->natoms != s1->natoms)
      {
 -        s2->nalloc = s1->nalloc;
 +        s2->natoms = s1->natoms;
          /* We need to allocate one element extra, since we might use
           * (unaligned) 4-wide SIMD loads to access rvec entries.
           */
 -        srenew(s2->x, s1->nalloc + 1);
 -        srenew(ems2->f,  s1->nalloc);
 +        s2->x.resize(s1->natoms + 1);
 +        ems2->f.resize(s1->natoms + 1);
          if (s2->flags & (1<<estCGP))
          {
 -            srenew(s2->cg_p,  s1->nalloc + 1);
 +            s2->cg_p.resize(s1->natoms + 1);
          }
      }
 +    if (DOMAINDECOMP(cr) && s2->cg_gl.size() != s1->cg_gl.size())
 +    {
 +        s2->cg_gl.resize(s1->cg_gl.size());
 +    }
  
      s2->natoms = s1->natoms;
      copy_mat(s1->box, s2->box);
      /* Copy free energy state */
 -    for (int i = 0; i < efptNR; i++)
 -    {
 -        s2->lambda[i] = s1->lambda[i];
 -    }
 +    s2->lambda = s1->lambda;
      copy_mat(s1->box, s2->box);
  
      start = 0;
      nthreads = gmx_omp_nthreads_get(emntUpdate);
  #pragma omp parallel num_threads(nthreads)
      {
 -        rvec *x1 = s1->x;
 -        rvec *x2 = s2->x;
 +        const rvec *x1 = as_rvec_array(s1->x.data());
 +        rvec       *x2 = as_rvec_array(s2->x.data());
 +        const rvec *f  = as_rvec_array(force->data());
  
 -        int   gf = 0;
 +        int         gf = 0;
  #pragma omp for schedule(static) nowait
          for (int i = start; i < end; i++)
          {
          if (s2->flags & (1<<estCGP))
          {
              /* Copy the CG p vector */
 -            rvec *p1 = s1->cg_p;
 -            rvec *p2 = s2->cg_p;
 +            const rvec *p1 = as_rvec_array(s1->cg_p.data());
 +            rvec       *p2 = as_rvec_array(s2->cg_p.data());
  #pragma omp for schedule(static) nowait
              for (int i = start; i < end; i++)
              {
          if (DOMAINDECOMP(cr))
          {
              s2->ddp_count = s1->ddp_count;
 -            if (s2->cg_gl_nalloc < s1->cg_gl_nalloc)
 -            {
 -#pragma omp barrier
 -                s2->cg_gl_nalloc = s1->cg_gl_nalloc;
 -                try
 -                {
 -                    /* We need to allocate one element extra, since we might use
 -                     * (unaligned) 4-wide SIMD loads to access rvec entries.
 -                     */
 -                    srenew(s2->cg_gl, s2->cg_gl_nalloc + 1);
 -                }
 -                GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
 -#pragma omp barrier
 -            }
 -            s2->ncg_gl = s1->ncg_gl;
 +
 +            /* OpenMP does not supported unsigned loop variables */
  #pragma omp for schedule(static) nowait
 -            for (int i = 0; i < s2->ncg_gl; i++)
 +            for (int i = 0; i < static_cast<int>(s2->cg_gl.size()); i++)
              {
                  s2->cg_gl[i] = s1->cg_gl[i];
              }
          wallcycle_start(wcycle, ewcCONSTR);
          dvdl_constr = 0;
          validStep   =
 -            constrain(NULL, TRUE, TRUE, constr, &top->idef,
 +            constrain(nullptr, TRUE, TRUE, constr, &top->idef,
                        ir, cr, count, 0, 1.0, md,
 -                      s1->x, s2->x, NULL, bMolPBC, s2->box,
 +                      as_rvec_array(s1->x.data()), as_rvec_array(s2->x.data()),
 +                      nullptr, bMolPBC, s2->box,
                        s2->lambda[efptBONDED], &dvdl_constr,
 -                      NULL, NULL, nrnb, econqCoord);
 +                      nullptr, nullptr, nrnb, econqCoord);
          wallcycle_stop(wcycle, ewcCONSTR);
  
          // We should move this check to the different minimizers
@@@ -690,7 -728,7 +690,7 @@@ static void em_dd_partition_system(FIL
  {
      /* Repartition the domain decomposition */
      dd_partition_system(fplog, step, cr, FALSE, 1,
 -                        NULL, top_global, ir,
 +                        nullptr, top_global, ir,
                          &ems->s, &ems->f,
                          mdatoms, top, fr, vsite, constr,
                          nrnb, wcycle, FALSE);
@@@ -737,7 -775,7 +737,7 @@@ static void evaluate_energy(FILE *fplog
  
      if (vsite)
      {
 -        construct_vsites(vsite, ems->s.x, 1, NULL,
 +        construct_vsites(vsite, as_rvec_array(ems->s.x.data()), 1, nullptr,
                           top->idef.iparams, top->idef.il,
                           fr->ePBC, fr->bMolPBC, cr, ems->s.box);
      }
       */
      do_force(fplog, cr, inputrec,
               count, nrnb, wcycle, top, &top_global->groups,
 -             ems->s.box, ems->s.x, &ems->s.hist,
 -             ems->f, force_vir, mdatoms, enerd, fcd,
 -             ems->s.lambda, graph, fr, vsite, mu_tot, t, NULL, NULL, TRUE,
 +             ems->s.box, &ems->s.x, &ems->s.hist,
 +             &ems->f, force_vir, mdatoms, enerd, fcd,
 +             &ems->s.lambda, graph, fr, vsite, mu_tot, t, nullptr, TRUE,
               GMX_FORCE_STATECHANGED | GMX_FORCE_ALLFORCES |
               GMX_FORCE_VIRIAL | GMX_FORCE_ENERGY |
               (bNS ? GMX_FORCE_NS : 0));
          wallcycle_start(wcycle, ewcMoveE);
  
          global_stat(gstat, cr, enerd, force_vir, shake_vir, mu_tot,
 -                    inputrec, NULL, NULL, NULL, 1, &terminate,
 -                    NULL, FALSE,
 +                    inputrec, nullptr, nullptr, nullptr, 1, &terminate,
 +                    nullptr, FALSE,
                      CGLO_ENERGY |
                      CGLO_PRESSURE |
                      CGLO_CONSTRAINT);
          /* Project out the constraint components of the force */
          wallcycle_start(wcycle, ewcCONSTR);
          dvdl_constr = 0;
 -        constrain(NULL, FALSE, FALSE, constr, &top->idef,
 +        rvec *f_rvec = as_rvec_array(ems->f.data());
 +        constrain(nullptr, FALSE, FALSE, constr, &top->idef,
                    inputrec, cr, count, 0, 1.0, mdatoms,
 -                  ems->s.x, ems->f, ems->f, fr->bMolPBC, ems->s.box,
 +                  as_rvec_array(ems->s.x.data()), f_rvec, f_rvec,
 +                  fr->bMolPBC, ems->s.box,
                    ems->s.lambda[efptBONDED], &dvdl_constr,
 -                  NULL, &shake_vir, nrnb, econqForceDispl);
 +                  nullptr, &shake_vir, nrnb, econqForceDispl);
          enerd->term[F_DVDL_CONSTR] += dvdl_constr;
          m_add(force_vir, shake_vir, vir);
          wallcycle_stop(wcycle, ewcCONSTR);
      enerd->term[F_PRES] =
          calc_pres(fr->ePBC, inputrec->nwall, ems->s.box, ekin, vir, pres);
  
 -    sum_dhdl(enerd, ems->s.lambda, inputrec->fepvals);
 +    sum_dhdl(enerd, &ems->s.lambda, inputrec->fepvals);
  
      if (EI_ENERGY_MINIMIZATION(inputrec->eI))
      {
@@@ -830,6 -866,7 +830,6 @@@ static double reorder_partsum(t_commre
                                gmx_mtop_t *top_global,
                                em_state_t *s_min, em_state_t *s_b)
  {
 -    rvec          *fm, *fb, *fmg;
      t_block       *cgs_gl;
      int            ncg, *cg_gl, *index, c, cg, i, a0, a1, a, gf, m;
      double         partsum;
          fprintf(debug, "Doing reorder_partsum\n");
      }
  
 -    fm = s_min->f;
 -    fb = s_b->f;
 +    const rvec *fm = as_rvec_array(s_min->f.data());
 +    const rvec *fb = as_rvec_array(s_b->f.data());
  
      cgs_gl = dd_charge_groups_global(cr->dd);
      index  = cgs_gl->index;
       * This conflicts with the spirit of domain decomposition,
       * but to fully optimize this a much more complicated algorithm is required.
       */
 +    rvec *fmg;
      snew(fmg, top_global->natoms);
  
 -    ncg   = s_min->s.ncg_gl;
 -    cg_gl = s_min->s.cg_gl;
 +    ncg   = s_min->s.cg_gl.size();
 +    cg_gl = s_min->s.cg_gl.data();
      i     = 0;
      for (c = 0; c < ncg; c++)
      {
      gmx_sum(top_global->natoms*3, fmg[0], cr);
  
      /* Now we will determine the part of the sum for the cgs in state s_b */
 -    ncg         = s_b->s.ncg_gl;
 -    cg_gl       = s_b->s.cg_gl;
 +    ncg         = s_b->s.cg_gl.size();
 +    cg_gl       = s_b->s.cg_gl.data();
      partsum     = 0;
      i           = 0;
      gf          = 0;
@@@ -908,7 -944,9 +908,7 @@@ static real pr_beta(t_commrec *cr, t_gr
                      gmx_mtop_t *top_global,
                      em_state_t *s_min, em_state_t *s_b)
  {
 -    rvec  *fm, *fb;
      double sum;
 -    int    gf, i, m;
  
      /* This is just the classical Polak-Ribiere calculation of beta;
       * it looks a bit complicated since we take freeze groups into account,
          (s_min->s.ddp_count == cr->dd->ddp_count &&
           s_b->s.ddp_count   == cr->dd->ddp_count))
      {
 -        fm  = s_min->f;
 -        fb  = s_b->f;
 -        sum = 0;
 -        gf  = 0;
 +        const rvec *fm  = as_rvec_array(s_min->f.data());
 +        const rvec *fb  = as_rvec_array(s_b->f.data());
 +        sum             = 0;
 +        int         gf  = 0;
          /* This part of code can be incorrect with DD,
           * since the atom ordering in s_b and s_min might differ.
           */
 -        for (i = 0; i < mdatoms->homenr; i++)
 +        for (int i = 0; i < mdatoms->homenr; i++)
          {
              if (mdatoms->cFREEZE)
              {
                  gf = mdatoms->cFREEZE[i];
              }
 -            for (m = 0; m < DIM; m++)
 +            for (int m = 0; m < DIM; m++)
              {
                  if (!opts->nFreeze[gf][m])
                  {
@@@ -958,7 -996,7 +958,7 @@@ namespace gm
  {
  
  /*! \brief Do conjugate gradients minimization
 -    \copydoc integrator_t (FILE *fplog, t_commrec *cr,
 +    \copydoc integrator_t(FILE *fplog, t_commrec *cr, const gmx::MDLogger &mdlog,
                             int nfile, const t_filenm fnm[],
                             const gmx_output_env_t *oenv, gmx_bool bVerbose,
                             int nstglobalcomm,
                             unsigned long Flags,
                             gmx_walltime_accounting_t walltime_accounting)
   */
 -double do_cg(FILE *fplog, t_commrec *cr,
 +double do_cg(FILE *fplog, t_commrec *cr, const gmx::MDLogger gmx_unused &mdlog,
               int nfile, const t_filenm fnm[],
               const gmx_output_env_t gmx_unused *oenv, gmx_bool bVerbose,
               int gmx_unused nstglobalcomm,
               t_inputrec *inputrec,
               gmx_mtop_t *top_global, t_fcdata *fcd,
               t_state *state_global,
 +             energyhistory_t *energyHistory,
               t_mdatoms *mdatoms,
               t_nrnb *nrnb, gmx_wallcycle_t wcycle,
               gmx_edsam_t gmx_unused ed,
  {
      const char       *CG = "Polak-Ribiere Conjugate Gradients";
  
 -    em_state_t       *s_min, *s_a, *s_b, *s_c;
      gmx_localtop_t   *top;
      gmx_enerdata_t   *enerd;
 -    rvec             *f;
      gmx_global_stat_t gstat;
      t_graph          *graph;
 -    rvec             *p, *sf;
 -    double            gpa, gpb, gpc, tmp, minstep;
 -    real              fnormn;
 +    double            tmp, minstep;
      real              stepsize;
      real              a, b, c, beta = 0.0;
      real              epot_repl = 0;
      tensor            vir, pres;
      int               number_steps, neval = 0, nstcg = inputrec->nstcgsteep;
      gmx_mdoutf_t      outf;
 -    int               i, m, gf, step, nminstep;
 +    int               m, step, nminstep;
  
      step = 0;
  
 -    s_min = init_em_state();
 -    s_a   = init_em_state();
 -    s_b   = init_em_state();
 -    s_c   = init_em_state();
 +    /* Create 4 states on the stack and extract pointers that we will swap */
 +    em_state_t  s0 {}, s1 {}, s2 {}, s3 {};
 +    em_state_t *s_min = &s0;
 +    em_state_t *s_a   = &s1;
 +    em_state_t *s_b   = &s2;
 +    em_state_t *s_c   = &s3;
  
      /* Init em and store the local state in s_min */
      init_em(fplog, CG, cr, inputrec,
 -            state_global, top_global, s_min, &top, &f,
 -            nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat, vsite, constr,
 +            state_global, top_global, s_min, &top,
 +            nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat,
 +            vsite, constr, nullptr,
              nfile, fnm, &outf, &mdebin, imdport, Flags, wcycle);
  
      /* Print to log file */
          /* Copy stuff to the energy bin for easy printing etc. */
          upd_mdebin(mdebin, FALSE, FALSE, (double)step,
                     mdatoms->tmass, enerd, &s_min->s, inputrec->fepvals, inputrec->expandedvals, s_min->s.box,
 -                   NULL, NULL, vir, pres, NULL, mu_tot, constr);
 +                   nullptr, nullptr, vir, pres, nullptr, mu_tot, constr);
  
          print_ebin_header(fplog, step, step);
          print_ebin(mdoutf_get_fp_ene(outf), TRUE, FALSE, FALSE, fplog, step, step, eprNORMAL,
           */
  
          /* Calculate the new direction in p, and the gradient in this direction, gpa */
 -        p   = s_min->s.cg_p;
 -        sf  = s_min->f;
 -        gpa = 0;
 -        gf  = 0;
 -        for (i = 0; i < mdatoms->homenr; i++)
 +        rvec       *pm  = as_rvec_array(s_min->s.cg_p.data());
 +        const rvec *sfm = as_rvec_array(s_min->f.data());
 +        double      gpa = 0;
 +        int         gf  = 0;
 +        for (int i = 0; i < mdatoms->homenr; i++)
          {
              if (mdatoms->cFREEZE)
              {
              {
                  if (!inputrec->opts.nFreeze[gf][m])
                  {
 -                    p[i][m] = sf[i][m] + beta*p[i][m];
 -                    gpa    -= p[i][m]*sf[i][m];
 +                    pm[i][m] = sfm[i][m] + beta*pm[i][m];
 +                    gpa     -= pm[i][m]*sfm[i][m];
                      /* f is negative gradient, thus the sign */
                  }
                  else
                  {
 -                    p[i][m] = 0;
 +                    pm[i][m] = 0;
                  }
              }
          }
          }
  
          /* Calculate the norm of the search vector */
 -        get_f_norm_max(cr, &(inputrec->opts), mdatoms, p, &pnorm, NULL, NULL);
 +        get_f_norm_max(cr, &(inputrec->opts), mdatoms, pm, &pnorm, nullptr, nullptr);
  
          /* Just in case stepsize reaches zero due to numerical precision... */
          if (stepsize <= 0)
           * relative change in coordinate is smaller than precision
           */
          minstep = 0;
 -        for (i = 0; i < mdatoms->homenr; i++)
 +        for (int i = 0; i < mdatoms->homenr; i++)
          {
              for (m = 0; m < DIM; m++)
              {
                  {
                      tmp = 1.0;
                  }
 -                tmp      = p[i][m]/tmp;
 +                tmp      = pm[i][m]/tmp;
                  minstep += tmp*tmp;
              }
          }
          do_x = do_per_step(step, inputrec->nstxout);
          do_f = do_per_step(step, inputrec->nstfout);
  
 -        write_em_traj(fplog, cr, outf, do_x, do_f, NULL,
 +        write_em_traj(fplog, cr, outf, do_x, do_f, nullptr,
                        top_global, inputrec, step,
 -                      s_min, state_global);
 +                      s_min, state_global, energyHistory);
  
          /* Take a step downhill.
           * In theory, we should minimize the function along this direction.
          }
  
          /* Take a trial step (new coords in s_c) */
 -        do_em_step(cr, inputrec, mdatoms, fr->bMolPBC, s_min, c, s_min->s.cg_p, s_c,
 +        do_em_step(cr, inputrec, mdatoms, fr->bMolPBC, s_min, c, &s_min->s.cg_p, s_c,
                     constr, top, nrnb, wcycle, -1);
  
          neval++;
                          mu_tot, enerd, vir, pres, -1, FALSE);
  
          /* Calc derivative along line */
 -        p   = s_c->s.cg_p;
 -        sf  = s_c->f;
 -        gpc = 0;
 -        for (i = 0; i < mdatoms->homenr; i++)
 +        const rvec *pc  = as_rvec_array(s_c->s.cg_p.data());
 +        const rvec *sfc = as_rvec_array(s_c->f.data());
 +        double      gpc = 0;
 +        for (int i = 0; i < mdatoms->homenr; i++)
          {
              for (m = 0; m < DIM; m++)
              {
 -                gpc -= p[i][m]*sf[i][m]; /* f is negative gradient, thus the sign */
 +                gpc -= pc[i][m]*sfc[i][m]; /* f is negative gradient, thus the sign */
              }
          }
          /* Sum the gradient along the line across CPUs */
           *
           * If we already found a lower value we just skip this step and continue to the update.
           */
 +        double gpb;
          if (!foundlower)
          {
              nminstep = 0;
                  }
  
                  /* Take a trial step to this new point - new coords in s_b */
 -                do_em_step(cr, inputrec, mdatoms, fr->bMolPBC, s_min, b, s_min->s.cg_p, s_b,
 +                do_em_step(cr, inputrec, mdatoms, fr->bMolPBC, s_min, b, &s_min->s.cg_p, s_b,
                             constr, top, nrnb, wcycle, -1);
  
                  neval++;
                  /* p does not change within a step, but since the domain decomposition
                   * might change, we have to use cg_p of s_b here.
                   */
 -                p   = s_b->s.cg_p;
 -                sf  = s_b->f;
 -                gpb = 0;
 -                for (i = 0; i < mdatoms->homenr; i++)
 +                const rvec *pb  = as_rvec_array(s_b->s.cg_p.data());
 +                const rvec *sfb = as_rvec_array(s_b->f.data());
 +                gpb             = 0;
 +                for (int i = 0; i < mdatoms->homenr; i++)
                  {
                      for (m = 0; m < DIM; m++)
                      {
 -                        gpb -= p[i][m]*sf[i][m]; /* f is negative gradient, thus the sign */
 +                        gpb -= pb[i][m]*sfb[i][m]; /* f is negative gradient, thus the sign */
                      }
                  }
                  /* Sum the gradient along the line across CPUs */
                  if (gpb > 0)
                  {
                      /* Replace c endpoint with b */
 -                    swap_em_state(s_b, s_c);
 +                    swap_em_state(&s_b, &s_c);
                      c   = b;
                      gpc = gpb;
                  }
                  else
                  {
                      /* Replace a endpoint with b */
 -                    swap_em_state(s_b, s_a);
 +                    swap_em_state(&s_b, &s_a);
                      a   = b;
                      gpa = gpb;
                  }
                      fprintf(debug, "CGE: C (%f) is lower than A (%f), moving C to B\n",
                              s_c->epot, s_a->epot);
                  }
 -                swap_em_state(s_b, s_c);
 +                swap_em_state(&s_b, &s_c);
                  gpb = gpc;
              }
              else
                      fprintf(debug, "CGE: A (%f) is lower than C (%f), moving A to B\n",
                              s_a->epot, s_c->epot);
                  }
 -                swap_em_state(s_b, s_a);
 +                swap_em_state(&s_b, &s_a);
                  gpb = gpa;
              }
  
                  fprintf(debug, "CGE: Found a lower energy %f, moving C to B\n",
                          s_c->epot);
              }
 -            swap_em_state(s_b, s_c);
 +            swap_em_state(&s_b, &s_c);
              gpb = gpc;
          }
  
  
  
          /* update positions */
 -        swap_em_state(s_min, s_b);
 +        swap_em_state(&s_min, &s_b);
          gpa = gpb;
  
          /* Print it if necessary */
              /* Store the new (lower) energies */
              upd_mdebin(mdebin, FALSE, FALSE, (double)step,
                         mdatoms->tmass, enerd, &s_min->s, inputrec->fepvals, inputrec->expandedvals, s_min->s.box,
 -                       NULL, NULL, vir, pres, NULL, mu_tot, constr);
 +                       nullptr, nullptr, vir, pres, nullptr, mu_tot, constr);
  
              do_log = do_per_step(step, inputrec->nstlog);
              do_ene = do_per_step(step, inputrec->nstenergy);
                  print_ebin_header(fplog, step, step);
              }
              print_ebin(mdoutf_get_fp_ene(outf), do_ene, FALSE, FALSE,
 -                       do_log ? fplog : NULL, step, step, eprNORMAL,
 +                       do_log ? fplog : nullptr, step, step, eprNORMAL,
                         mdebin, fcd, &(top_global->groups), &(inputrec->opts));
          }
  
          /* Send energies and positions to the IMD client if bIMD is TRUE. */
 -        if (do_IMD(inputrec->bIMD, step, cr, TRUE, state_global->box, state_global->x, inputrec, 0, wcycle) && MASTER(cr))
 +        if (do_IMD(inputrec->bIMD, step, cr, TRUE, state_global->box, as_rvec_array(state_global->x.data()), inputrec, 0, wcycle) && MASTER(cr))
          {
              IMD_send_positions(inputrec->imd);
          }
          {
              /* Write final energy file entries */
              print_ebin(mdoutf_get_fp_ene(outf), !do_ene, FALSE, FALSE,
 -                       !do_log ? fplog : NULL, step, step, eprNORMAL,
 +                       !do_log ? fplog : nullptr, step, step, eprNORMAL,
                         mdebin, fcd, &(top_global->groups), &(inputrec->opts));
          }
      }
  
      write_em_traj(fplog, cr, outf, do_x, do_f, ftp2fn(efSTO, nfile, fnm),
                    top_global, inputrec, step,
 -                  s_min, state_global);
 +                  s_min, state_global, energyHistory);
  
  
      if (MASTER(cr))
      {
          double sqrtNumAtoms = sqrt(static_cast<double>(state_global->natoms));
 -        fnormn = s_min->fnorm/sqrtNumAtoms;
          print_converged(stderr, CG, inputrec->em_tol, step, converged, number_steps,
 -                        s_min->epot, s_min->fmax, s_min->a_fmax, fnormn);
 +                        s_min, sqrtNumAtoms);
          print_converged(fplog, CG, inputrec->em_tol, step, converged, number_steps,
 -                        s_min->epot, s_min->fmax, s_min->a_fmax, fnormn);
 +                        s_min, sqrtNumAtoms);
  
          fprintf(fplog, "\nPerformed %d energy evaluations in total.\n", neval);
      }
  
 -    finish_em(cr, outf, walltime_accounting, wcycle);
 +    finish_em(cr, outf, inputrec, walltime_accounting, wcycle);
  
      /* To print the actual number of steps we needed somewhere */
      walltime_accounting_set_nsteps_done(walltime_accounting, step);
  
  
  /*! \brief Do L-BFGS conjugate gradients minimization
 -    \copydoc integrator_t (FILE *fplog, t_commrec *cr,
 -                           int nfile, const t_filenm fnm[],
 -                           const gmx_output_env_t *oenv, gmx_bool bVerbose,
 -                           int nstglobalcomm,
 -                           gmx_vsite_t *vsite, gmx_constr_t constr,
 -                           int stepout,
 -                           t_inputrec *inputrec,
 -                           gmx_mtop_t *top_global, t_fcdata *fcd,
 -                           t_state *state_global,
 -                           t_mdatoms *mdatoms,
 -                           t_nrnb *nrnb, gmx_wallcycle_t wcycle,
 -                           gmx_edsam_t ed,
 -                           t_forcerec *fr,
 -                           int repl_ex_nst, int repl_ex_nex, int repl_ex_seed,
 -                           real cpt_period, real max_hours,
 -                           int imdport,
 -                           unsigned long Flags,
 -                           gmx_walltime_accounting_t walltime_accounting)
 +    \copydoc integrator_t(FILE *fplog, t_commrec *cr, const gmx::MDLogger &mdlog,
 +                          int nfile, const t_filenm fnm[],
 +                          const gmx_output_env_t *oenv, gmx_bool bVerbose,
 +                          int nstglobalcomm,
 +                          gmx_vsite_t *vsite, gmx_constr_t constr,
 +                          int stepout,
 +                          t_inputrec *inputrec,
 +                          gmx_mtop_t *top_global, t_fcdata *fcd,
 +                          t_state *state_global,
 +                          t_mdatoms *mdatoms,
 +                          t_nrnb *nrnb, gmx_wallcycle_t wcycle,
 +                          gmx_edsam_t ed,
 +                          t_forcerec *fr,
 +                          int repl_ex_nst, int repl_ex_nex, int repl_ex_seed,
 +                          real cpt_period, real max_hours,
 +                          int imdport,
 +                          unsigned long Flags,
 +                          gmx_walltime_accounting_t walltime_accounting)
   */
 -double do_lbfgs(FILE *fplog, t_commrec *cr,
 +double do_lbfgs(FILE *fplog, t_commrec *cr, const gmx::MDLogger gmx_unused &mdlog,
                  int nfile, const t_filenm fnm[],
                  const gmx_output_env_t gmx_unused *oenv, gmx_bool bVerbose,
                  int gmx_unused nstglobalcomm,
                  t_inputrec *inputrec,
                  gmx_mtop_t *top_global, t_fcdata *fcd,
                  t_state *state_global,
 +                energyhistory_t *energyHistory,
                  t_mdatoms *mdatoms,
                  t_nrnb *nrnb, gmx_wallcycle_t wcycle,
                  gmx_edsam_t gmx_unused ed,
      em_state_t         ems;
      gmx_localtop_t    *top;
      gmx_enerdata_t    *enerd;
 -    rvec              *f;
      gmx_global_stat_t  gstat;
      t_graph           *graph;
      int                ncorr, nmaxcorr, point, cp, neval, nminstep;
      double             stepsize, step_taken, gpa, gpb, gpc, tmp, minstep;
 -    real              *rho, *alpha, *ff, *xx, *p, *s, *lastx, *lastf, **dx, **dg;
 -    real              *xa, *xb, *xc, *fa, *fb, *fc, *xtmp, *ftmp;
 +    real              *rho, *alpha, *p, *s, **dx, **dg;
      real               a, b, c, maxdelta, delta;
 -    real               diag, Epot0, Epot, EpotA, EpotB, EpotC;
 +    real               diag, Epot0;
      real               dgdx, dgdg, sq, yr, beta;
      t_mdebin          *mdebin;
      gmx_bool           converged;
      rvec               mu_tot;
 -    real               fnorm, fmax;
      gmx_bool           do_log, do_ene, do_x, do_f, foundlower, *frozen;
      tensor             vir, pres;
      int                start, end, number_steps;
      gmx_mdoutf_t       outf;
 -    int                i, k, m, n, nfmax, gf, step;
 +    int                i, k, m, n, gf, step;
      int                mdof_flags;
  
      if (PAR(cr))
          gmx_fatal(FARGS, "Cannot do parallel L-BFGS Minimization - yet.\n");
      }
  
 -    if (NULL != constr)
 +    if (nullptr != constr)
      {
          gmx_fatal(FARGS, "The combination of constraints and L-BFGS minimization is not implemented. Either do not use constraints, or use another minimizer (e.g. steepest descent).");
      }
      n        = 3*state_global->natoms;
      nmaxcorr = inputrec->nbfgscorr;
  
 -    /* Allocate memory */
 -    /* Use pointers to real so we dont have to loop over both atoms and
 -     * dimensions all the time...
 -     * x/f are allocated as rvec *, so make new x0/f0 pointers-to-real
 -     * that point to the same memory.
 -     */
 -    snew(xa, n);
 -    snew(xb, n);
 -    snew(xc, n);
 -    snew(fa, n);
 -    snew(fb, n);
 -    snew(fc, n);
      snew(frozen, n);
  
      snew(p, n);
 -    snew(lastx, n);
 -    snew(lastf, n);
      snew(rho, nmaxcorr);
      snew(alpha, nmaxcorr);
  
  
      /* Init em */
      init_em(fplog, LBFGS, cr, inputrec,
 -            state_global, top_global, &ems, &top, &f,
 -            nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat, vsite, constr,
 +            state_global, top_global, &ems, &top,
 +            nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat,
 +            vsite, constr, nullptr,
              nfile, fnm, &outf, &mdebin, imdport, Flags, wcycle);
 -    /* Do_lbfgs is not completely updated like do_steep and do_cg,
 -     * so we free some memory again.
 -     */
 -    sfree(ems.s.x);
 -    sfree(ems.f);
 -
 -    xx = (real *)state_global->x;
 -    ff = (real *)f;
  
      start = 0;
      end   = mdatoms->homenr;
  
 +    /* We need 4 working states */
 +    em_state_t  s0 {}, s1 {}, s2 {}, s3 {};
 +    em_state_t *sa   = &s0;
 +    em_state_t *sb   = &s1;
 +    em_state_t *sc   = &s2;
 +    em_state_t *last = &s3;
 +    /* Initialize by copying the state from ems (we could skip x and f here) */
 +    *sa              = ems;
 +    *sb              = ems;
 +    *sc              = ems;
 +
      /* Print to log file */
      print_em_start(fplog, cr, walltime_accounting, wcycle, LBFGS);
  
  
      if (vsite)
      {
 -        construct_vsites(vsite, state_global->x, 1, NULL,
 +        construct_vsites(vsite, as_rvec_array(state_global->x.data()), 1, nullptr,
                           top->idef.iparams, top->idef.il,
                           fr->ePBC, fr->bMolPBC, cr, state_global->box);
      }
       * We do not unshift, so molecules are always whole
       */
      neval++;
 -    ems.s.x = state_global->x;
 -    ems.f   = f;
      evaluate_energy(fplog, cr,
                      top_global, &ems, top,
                      inputrec, nrnb, wcycle, gstat,
          /* Copy stuff to the energy bin for easy printing etc. */
          upd_mdebin(mdebin, FALSE, FALSE, (double)step,
                     mdatoms->tmass, enerd, state_global, inputrec->fepvals, inputrec->expandedvals, state_global->box,
 -                   NULL, NULL, vir, pres, NULL, mu_tot, constr);
 +                   nullptr, nullptr, vir, pres, nullptr, mu_tot, constr);
  
          print_ebin_header(fplog, step, step);
          print_ebin(mdoutf_get_fp_ene(outf), TRUE, FALSE, FALSE, fplog, step, step, eprNORMAL,
      }
      where();
  
 -    /* This is the starting energy */
 -    Epot = enerd->term[F_EPOT];
 -
 -    fnorm = ems.fnorm;
 -    fmax  = ems.fmax;
 -    nfmax = ems.a_fmax;
 -
      /* Set the initial step.
       * since it will be multiplied by the non-normalized search direction
       * vector (force vector the first time), we scale it by the
      {
          double sqrtNumAtoms = sqrt(static_cast<double>(state_global->natoms));
          fprintf(stderr, "Using %d BFGS correction steps.\n\n", nmaxcorr);
 -        fprintf(stderr, "   F-max             = %12.5e on atom %d\n", fmax, nfmax+1);
 -        fprintf(stderr, "   F-Norm            = %12.5e\n", fnorm/sqrtNumAtoms);
 +        fprintf(stderr, "   F-max             = %12.5e on atom %d\n", ems.fmax, ems.a_fmax + 1);
 +        fprintf(stderr, "   F-Norm            = %12.5e\n", ems.fnorm/sqrtNumAtoms);
          fprintf(stderr, "\n");
          /* and copy to the log file too... */
          fprintf(fplog, "Using %d BFGS correction steps.\n\n", nmaxcorr);
 -        fprintf(fplog, "   F-max             = %12.5e on atom %d\n", fmax, nfmax+1);
 -        fprintf(fplog, "   F-Norm            = %12.5e\n", fnorm/sqrtNumAtoms);
 +        fprintf(fplog, "   F-max             = %12.5e on atom %d\n", ems.fmax, ems.a_fmax + 1);
 +        fprintf(fplog, "   F-Norm            = %12.5e\n", ems.fnorm/sqrtNumAtoms);
          fprintf(fplog, "\n");
      }
  
      point = 0;
  
      // Set initial search direction to the force (-gradient), or 0 for frozen particles.
 +    real *fInit = static_cast<real *>(as_rvec_array(ems.f.data())[0]);
      for (i = 0; i < n; i++)
      {
          if (!frozen[i])
          {
 -            dx[point][i] = ff[i]; /* Initial search direction */
 +            dx[point][i] = fInit[i]; /* Initial search direction */
          }
          else
          {
      // (the main efficiency in the algorithm comes from changing directions), but
      // we still need an initial value, so estimate it as the inverse of the norm
      // so we take small steps where the potential fluctuates a lot.
 -    stepsize  = 1.0/fnorm;
 +    stepsize  = 1.0/ems.fnorm;
  
      /* Start the loop over BFGS steps.
       * Each successful step is counted, and we continue until
          }
  
          mdoutf_write_to_trajectory_files(fplog, cr, outf, mdof_flags,
 -                                         top_global, step, (real)step, state_global, state_global, f);
 +                                         top_global, step, (real)step, &ems.s, state_global, energyHistory, &ems.f);
  
          /* Do the linesearching in the direction dx[point][0..(n-1)] */
  
          /* make s a pointer to current search direction - point=0 first time we get here */
          s = dx[point];
  
 +        real *xx = static_cast<real *>(as_rvec_array(ems.s.x.data())[0]);
 +        real *ff = static_cast<real *>(as_rvec_array(ems.f.data())[0]);
 +
          // calculate line gradient in position A
          for (gpa = 0, i = 0; i < n; i++)
          {
          }
  
          // Before taking any steps along the line, store the old position
 -        for (i = 0; i < n; i++)
 -        {
 -            lastx[i] = xx[i];
 -            lastf[i] = ff[i];
 -        }
 -        Epot0 = Epot;
 +        *last       = ems;
 +        real *lastx = static_cast<real *>(as_rvec_array(last->s.x.data())[0]);
 +        real *lastf = static_cast<real *>(as_rvec_array(last->f.data())[0]);
 +        Epot0       = ems.epot;
  
 -        for (i = 0; i < n; i++)
 -        {
 -            xa[i] = xx[i];
 -        }
 +        *sa         = ems;
  
          /* Take a step downhill.
           * In theory, we should find the actual minimum of the function in this
  
          // State "A" is the first position along the line.
          // reference position along line is initially zero
 -        EpotA      = Epot0;
          a          = 0.0;
  
          // Check stepsize first. We do not allow displacements
          while (maxdelta > inputrec->em_stepsize);
  
          // Take a trial step and move the coordinate array xc[] to position C
 +        real *xc = static_cast<real *>(as_rvec_array(sc->s.x.data())[0]);
          for (i = 0; i < n; i++)
          {
              xc[i] = lastx[i] + c*s[i];
  
          neval++;
          // Calculate energy for the trial step in position C
 -        ems.s.x = (rvec *)xc;
 -        ems.f   = (rvec *)fc;
          evaluate_energy(fplog, cr,
 -                        top_global, &ems, top,
 +                        top_global, sc, top,
                          inputrec, nrnb, wcycle, gstat,
                          vsite, constr, fcd, graph, mdatoms, fr,
                          mu_tot, enerd, vir, pres, step, FALSE);
 -        EpotC = ems.epot;
  
          // Calc line gradient in position C
 +        real *fc = static_cast<real *>(as_rvec_array(sc->f.data())[0]);
          for (gpc = 0, i = 0; i < n; i++)
          {
              gpc -= s[i]*fc[i]; /* f is negative gradient, thus the sign */
          // This is the max amount of increase in energy we tolerate.
          // By allowing VERY small changes (close to numerical precision) we
          // frequently find even better (lower) final energies.
 -        tmp = sqrt(GMX_REAL_EPS)*fabs(EpotA);
 +        tmp = sqrt(GMX_REAL_EPS)*fabs(sa->epot);
  
          // Accept the step if the energy is lower in the new position C (compared to A),
          // or if it is not significantly higher and the line derivative is still negative.
 -        if (EpotC < EpotA || (gpc < 0 && EpotC < (EpotA+tmp)))
 +        if (sc->epot < sa->epot || (gpc < 0 && sc->epot < (sa->epot + tmp)))
          {
              // Great, we found a better energy. We no longer try to alter the
              // stepsize, but simply accept this new better position. The we select a new
              // to take smaller steps along a line. Set fnorm based on the new C position,
              // which will be used to update the stepsize to 1/fnorm further down.
              foundlower = TRUE;
 -            fnorm      = ems.fnorm;
          }
          else
          {
              // I also have a safeguard for potentially really pathological functions so we never
              // take more than 20 steps before we give up.
              // If we already found a lower value we just skip this step and continue to the update.
 -            nminstep = 0;
 +            real fnorm = 0;
 +            nminstep   = 0;
              do
              {
                  // Select a new trial point B in the interval [A,C].
                  }
  
                  // Take a trial step to point B
 +                real *xb = static_cast<real *>(as_rvec_array(sb->s.x.data())[0]);
                  for (i = 0; i < n; i++)
                  {
                      xb[i] = lastx[i] + b*s[i];
  
                  neval++;
                  // Calculate energy for the trial step in point B
 -                ems.s.x = (rvec *)xb;
 -                ems.f   = (rvec *)fb;
                  evaluate_energy(fplog, cr,
 -                                top_global, &ems, top,
 +                                top_global, sb, top,
                                  inputrec, nrnb, wcycle, gstat,
                                  vsite, constr, fcd, graph, mdatoms, fr,
                                  mu_tot, enerd, vir, pres, step, FALSE);
 -                EpotB = ems.epot;
 -                fnorm = ems.fnorm;
 +                fnorm = sb->fnorm;
  
                  // Calculate gradient in point B
 +                real *fb = static_cast<real *>(as_rvec_array(sb->f.data())[0]);
                  for (gpb = 0, i = 0; i < n; i++)
                  {
                      gpb -= s[i]*fb[i]; /* f is negative gradient, thus the sign */
                  if (gpb > 0)
                  {
                      /* Replace c endpoint with b */
 -                    EpotC = EpotB;
 -                    c     = b;
 -                    gpc   = gpb;
 -                    /* swap coord pointers b/c */
 -                    xtmp = xb;
 -                    ftmp = fb;
 -                    xb   = xc;
 -                    fb   = fc;
 -                    xc   = xtmp;
 -                    fc   = ftmp;
 +                    c   = b;
 +                    /* swap states b and c */
 +                    swap_em_state(&sb, &sc);
                  }
                  else
                  {
                      /* Replace a endpoint with b */
 -                    EpotA = EpotB;
 -                    a     = b;
 -                    gpa   = gpb;
 -                    /* swap coord pointers a/b */
 -                    xtmp = xb;
 -                    ftmp = fb;
 -                    xb   = xa;
 -                    fb   = fa;
 -                    xa   = xtmp;
 -                    fa   = ftmp;
 +                    a   = b;
 +                    /* swap states a and b */
 +                    swap_em_state(&sa, &sb);
                  }
  
                  /*
                   */
                  nminstep++;
              }
 -            while ((EpotB > EpotA || EpotB > EpotC) && (nminstep < 20));
 +            while ((sb->epot > sa->epot || sb->epot > sc->epot) && (nminstep < 20));
  
 -            if (fabs(EpotB-Epot0) < GMX_REAL_EPS || nminstep >= 20)
 +            if (fabs(sb->epot - Epot0) < GMX_REAL_EPS || nminstep >= 20)
              {
                  /* OK. We couldn't find a significantly lower energy.
                   * If ncorr==0 this was steepest descent, and then we give up.
  
              /* Select min energy state of A & C, put the best in xx/ff/Epot
               */
 -            if (EpotC < EpotA)
 +            if (sc->epot < sa->epot)
              {
 -                Epot = EpotC;
                  /* Use state C */
 -                for (i = 0; i < n; i++)
 -                {
 -                    xx[i] = xc[i];
 -                    ff[i] = fc[i];
 -                }
 +                ems        = *sc;
                  step_taken = c;
              }
              else
              {
 -                Epot = EpotA;
                  /* Use state A */
 -                for (i = 0; i < n; i++)
 -                {
 -                    xx[i] = xa[i];
 -                    ff[i] = fa[i];
 -                }
 +                ems        = *sa;
                  step_taken = a;
              }
  
          else
          {
              /* found lower */
 -            Epot = EpotC;
              /* Use state C */
 -            for (i = 0; i < n; i++)
 -            {
 -                xx[i] = xc[i];
 -                ff[i] = fc[i];
 -            }
 +            ems        = *sc;
              step_taken = c;
          }
  
              }
          }
  
 -        /* Test whether the convergence criterion is met */
 -        get_f_norm_max(cr, &(inputrec->opts), mdatoms, f, &fnorm, &fmax, &nfmax);
 -
          /* Print it if necessary */
          if (MASTER(cr))
          {
              {
                  double sqrtNumAtoms = sqrt(static_cast<double>(state_global->natoms));
                  fprintf(stderr, "\rStep %d, Epot=%12.6e, Fnorm=%9.3e, Fmax=%9.3e (atom %d)\n",
 -                        step, Epot, fnorm/sqrtNumAtoms, fmax, nfmax+1);
 +                        step, ems.epot, ems.fnorm/sqrtNumAtoms, ems.fmax, ems.a_fmax + 1);
                  fflush(stderr);
              }
              /* Store the new (lower) energies */
              upd_mdebin(mdebin, FALSE, FALSE, (double)step,
                         mdatoms->tmass, enerd, state_global, inputrec->fepvals, inputrec->expandedvals, state_global->box,
 -                       NULL, NULL, vir, pres, NULL, mu_tot, constr);
 +                       nullptr, nullptr, vir, pres, nullptr, mu_tot, constr);
              do_log = do_per_step(step, inputrec->nstlog);
              do_ene = do_per_step(step, inputrec->nstenergy);
              if (do_log)
                  print_ebin_header(fplog, step, step);
              }
              print_ebin(mdoutf_get_fp_ene(outf), do_ene, FALSE, FALSE,
 -                       do_log ? fplog : NULL, step, step, eprNORMAL,
 +                       do_log ? fplog : nullptr, step, step, eprNORMAL,
                         mdebin, fcd, &(top_global->groups), &(inputrec->opts));
          }
  
          /* Send x and E to IMD client, if bIMD is TRUE. */
 -        if (do_IMD(inputrec->bIMD, step, cr, TRUE, state_global->box, state_global->x, inputrec, 0, wcycle) && MASTER(cr))
 +        if (do_IMD(inputrec->bIMD, step, cr, TRUE, state_global->box, as_rvec_array(state_global->x.data()), inputrec, 0, wcycle) && MASTER(cr))
          {
              IMD_send_positions(inputrec->imd);
          }
  
          // Reset stepsize in we are doing more iterations
 -        stepsize = 1.0/fnorm;
 +        stepsize = 1.0/ems.fnorm;
  
          /* Stop when the maximum force lies below tolerance.
           * If we have reached machine precision, converged is already set to true.
           */
 -        converged = converged || (fmax < inputrec->em_tol);
 +        converged = converged || (ems.fmax < inputrec->em_tol);
  
      }   /* End of the loop */
  
          step--; /* we never took that last step in this case */
  
      }
 -    if (fmax > inputrec->em_tol)
 +    if (ems.fmax > inputrec->em_tol)
      {
          if (MASTER(cr))
          {
      if (!do_ene || !do_log) /* Write final energy file entries */
      {
          print_ebin(mdoutf_get_fp_ene(outf), !do_ene, FALSE, FALSE,
 -                   !do_log ? fplog : NULL, step, step, eprNORMAL,
 +                   !do_log ? fplog : nullptr, step, step, eprNORMAL,
                     mdebin, fcd, &(top_global->groups), &(inputrec->opts));
      }
  
      do_f = !do_per_step(step, inputrec->nstfout);
      write_em_traj(fplog, cr, outf, do_x, do_f, ftp2fn(efSTO, nfile, fnm),
                    top_global, inputrec, step,
 -                  &ems, state_global);
 +                  &ems, state_global, energyHistory);
  
      if (MASTER(cr))
      {
          double sqrtNumAtoms = sqrt(static_cast<double>(state_global->natoms));
          print_converged(stderr, LBFGS, inputrec->em_tol, step, converged,
 -                        number_steps, Epot, fmax, nfmax, fnorm/sqrtNumAtoms);
 +                        number_steps, &ems, sqrtNumAtoms);
          print_converged(fplog, LBFGS, inputrec->em_tol, step, converged,
 -                        number_steps, Epot, fmax, nfmax, fnorm/sqrtNumAtoms);
 +                        number_steps, &ems, sqrtNumAtoms);
  
          fprintf(fplog, "\nPerformed %d energy evaluations in total.\n", neval);
      }
  
 -    finish_em(cr, outf, walltime_accounting, wcycle);
 +    finish_em(cr, outf, inputrec, walltime_accounting, wcycle);
  
      /* To print the actual number of steps we needed somewhere */
      walltime_accounting_set_nsteps_done(walltime_accounting, step);
  }   /* That's all folks */
  
  /*! \brief Do steepest descents minimization
 -    \copydoc integrator_t (FILE *fplog, t_commrec *cr,
 -                           int nfile, const t_filenm fnm[],
 -                           const gmx_output_env_t *oenv, gmx_bool bVerbose,
 -                           int nstglobalcomm,
 -                           gmx_vsite_t *vsite, gmx_constr_t constr,
 -                           int stepout,
 -                           t_inputrec *inputrec,
 -                           gmx_mtop_t *top_global, t_fcdata *fcd,
 -                           t_state *state_global,
 -                           t_mdatoms *mdatoms,
 -                           t_nrnb *nrnb, gmx_wallcycle_t wcycle,
 -                           gmx_edsam_t ed,
 -                           t_forcerec *fr,
 -                           int repl_ex_nst, int repl_ex_nex, int repl_ex_seed,
 -                           real cpt_period, real max_hours,
 -                           int imdport,
 -                           unsigned long Flags,
 -                           gmx_walltime_accounting_t walltime_accounting)
 +    \copydoc integrator_t(FILE *fplog, t_commrec *cr, const gmx::MDLogger &mdlog,
 +                          int nfile, const t_filenm fnm[],
 +                          const gmx_output_env_t *oenv, gmx_bool bVerbose,
 +                          int nstglobalcomm,
 +                          gmx_vsite_t *vsite, gmx_constr_t constr,
 +                          int stepout,
 +                          t_inputrec *inputrec,
 +                          gmx_mtop_t *top_global, t_fcdata *fcd,
 +                          t_state *state_global,
 +                          t_mdatoms *mdatoms,
 +                          t_nrnb *nrnb, gmx_wallcycle_t wcycle,
 +                          gmx_edsam_t ed,
 +                          t_forcerec *fr,
 +                          int repl_ex_nst, int repl_ex_nex, int repl_ex_seed,
 +                          real cpt_period, real max_hours,
 +                          int imdport,
 +                          unsigned long Flags,
 +                          gmx_walltime_accounting_t walltime_accounting)
   */
 -double do_steep(FILE *fplog, t_commrec *cr,
 +double do_steep(FILE *fplog, t_commrec *cr, const gmx::MDLogger gmx_unused &mdlog,
                  int nfile, const t_filenm fnm[],
                  const gmx_output_env_t gmx_unused *oenv, gmx_bool bVerbose,
                  int gmx_unused nstglobalcomm,
                  t_inputrec *inputrec,
                  gmx_mtop_t *top_global, t_fcdata *fcd,
                  t_state *state_global,
 +                energyhistory_t *energyHistory,
                  t_mdatoms *mdatoms,
                  t_nrnb *nrnb, gmx_wallcycle_t wcycle,
                  gmx_edsam_t gmx_unused  ed,
                  gmx_walltime_accounting_t walltime_accounting)
  {
      const char       *SD = "Steepest Descents";
 -    em_state_t       *s_min, *s_try;
      gmx_localtop_t   *top;
      gmx_enerdata_t   *enerd;
 -    rvec             *f;
      gmx_global_stat_t gstat;
      t_graph          *graph;
      real              stepsize;
 -    real              ustep, fnormn;
 +    real              ustep;
      gmx_mdoutf_t      outf;
      t_mdebin         *mdebin;
      gmx_bool          bDone, bAbort, do_x, do_f;
      int               count          = 0;
      int               steps_accepted = 0;
  
 -    s_min = init_em_state();
 -    s_try = init_em_state();
 +    /* Create 2 states on the stack and extract pointers that we will swap */
 +    em_state_t  s0 {}, s1 {};
 +    em_state_t *s_min = &s0;
 +    em_state_t *s_try = &s1;
  
      /* Init em and store the local state in s_try */
      init_em(fplog, SD, cr, inputrec,
 -            state_global, top_global, s_try, &top, &f,
 -            nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat, vsite, constr,
 +            state_global, top_global, s_try, &top,
 +            nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat,
 +            vsite, constr, nullptr,
              nfile, fnm, &outf, &mdebin, imdport, Flags, wcycle);
  
      /* Print to log file  */
          {
              validStep =
                  do_em_step(cr, inputrec, mdatoms, fr->bMolPBC,
 -                           s_min, stepsize, s_min->f, s_try,
 +                           s_min, stepsize, &s_min->f, s_try,
                             constr, top, nrnb, wcycle, count);
          }
  
                  /* Store the new (lower) energies  */
                  upd_mdebin(mdebin, FALSE, FALSE, (double)count,
                             mdatoms->tmass, enerd, &s_try->s, inputrec->fepvals, inputrec->expandedvals,
 -                           s_try->s.box, NULL, NULL, vir, pres, NULL, mu_tot, constr);
 +                           s_try->s.box, nullptr, nullptr, vir, pres, nullptr, mu_tot, constr);
  
                  /* Prepare IMD energy record, if bIMD is TRUE. */
                  IMD_fill_energy_record(inputrec->bIMD, inputrec->imd, enerd, count, TRUE);
              /* Copy the arrays for force, positions and energy  */
              /* The 'Min' array always holds the coords and forces of the minimal
                 sampled energy  */
 -            swap_em_state(s_min, s_try);
 +            swap_em_state(&s_min, &s_try);
              if (count > 0)
              {
                  ustep *= 1.2;
              /* Write to trn, if necessary */
              do_x = do_per_step(steps_accepted, inputrec->nstxout);
              do_f = do_per_step(steps_accepted, inputrec->nstfout);
 -            write_em_traj(fplog, cr, outf, do_x, do_f, NULL,
 +            write_em_traj(fplog, cr, outf, do_x, do_f, nullptr,
                            top_global, inputrec, count,
 -                          s_min, state_global);
 +                          s_min, state_global, energyHistory);
          }
          else
          {
          {
              if (MASTER(cr))
              {
 -                warn_step(stderr, inputrec->em_tol, count == nsteps, constr != NULL);
 -                warn_step(fplog, inputrec->em_tol, count == nsteps, constr != NULL);
 +                warn_step(stderr, inputrec->em_tol, count == nsteps, constr != nullptr);
 +                warn_step(fplog, inputrec->em_tol, count == nsteps, constr != nullptr);
              }
              bAbort = TRUE;
          }
  
          /* Send IMD energies and positions, if bIMD is TRUE. */
 -        if (do_IMD(inputrec->bIMD, count, cr, TRUE, state_global->box, state_global->x, inputrec, 0, wcycle) && MASTER(cr))
 +        if (do_IMD(inputrec->bIMD, count, cr, TRUE, state_global->box, as_rvec_array(state_global->x.data()), inputrec, 0, wcycle) && MASTER(cr))
          {
              IMD_send_positions(inputrec->imd);
          }
      }
      write_em_traj(fplog, cr, outf, TRUE, inputrec->nstfout, ftp2fn(efSTO, nfile, fnm),
                    top_global, inputrec, count,
 -                  s_min, state_global);
 +                  s_min, state_global, energyHistory);
  
      if (MASTER(cr))
      {
          double sqrtNumAtoms = sqrt(static_cast<double>(state_global->natoms));
 -        fnormn = s_min->fnorm/sqrtNumAtoms;
  
          print_converged(stderr, SD, inputrec->em_tol, count, bDone, nsteps,
 -                        s_min->epot, s_min->fmax, s_min->a_fmax, fnormn);
 +                        s_min, sqrtNumAtoms);
          print_converged(fplog, SD, inputrec->em_tol, count, bDone, nsteps,
 -                        s_min->epot, s_min->fmax, s_min->a_fmax, fnormn);
 +                        s_min, sqrtNumAtoms);
      }
  
 -    finish_em(cr, outf, walltime_accounting, wcycle);
 +    finish_em(cr, outf, inputrec, walltime_accounting, wcycle);
  
      /* To print the actual number of steps we needed somewhere */
      inputrec->nsteps = count;
  }   /* That's all folks */
  
  /*! \brief Do normal modes analysis
 -    \copydoc integrator_t (FILE *fplog, t_commrec *cr,
 -                           int nfile, const t_filenm fnm[],
 -                           const gmx_output_env_t *oenv, gmx_bool bVerbose,
 -                           int nstglobalcomm,
 -                           gmx_vsite_t *vsite, gmx_constr_t constr,
 -                           int stepout,
 -                           t_inputrec *inputrec,
 -                           gmx_mtop_t *top_global, t_fcdata *fcd,
 -                           t_state *state_global,
 -                           t_mdatoms *mdatoms,
 -                           t_nrnb *nrnb, gmx_wallcycle_t wcycle,
 -                           gmx_edsam_t ed,
 -                           t_forcerec *fr,
 -                           int repl_ex_nst, int repl_ex_nex, int repl_ex_seed,
 -                           real cpt_period, real max_hours,
 -                           int imdport,
 -                           unsigned long Flags,
 -                           gmx_walltime_accounting_t walltime_accounting)
 +    \copydoc integrator_t(FILE *fplog, t_commrec *cr, const gmx::MDLogger &mdlog,
 +                          int nfile, const t_filenm fnm[],
 +                          const gmx_output_env_t *oenv, gmx_bool bVerbose,
 +                          int nstglobalcomm,
 +                          gmx_vsite_t *vsite, gmx_constr_t constr,
 +                          int stepout,
 +                          t_inputrec *inputrec,
 +                          gmx_mtop_t *top_global, t_fcdata *fcd,
 +                          t_state *state_global,
 +                          t_mdatoms *mdatoms,
 +                          t_nrnb *nrnb, gmx_wallcycle_t wcycle,
 +                          gmx_edsam_t ed,
 +                          t_forcerec *fr,
 +                          int repl_ex_nst, int repl_ex_nex, int repl_ex_seed,
 +                          real cpt_period, real max_hours,
 +                          int imdport,
 +                          unsigned long Flags,
 +                          gmx_walltime_accounting_t walltime_accounting)
   */
 -double do_nm(FILE *fplog, t_commrec *cr,
 +double do_nm(FILE *fplog, t_commrec *cr, const gmx::MDLogger &mdlog,
               int nfile, const t_filenm fnm[],
               const gmx_output_env_t gmx_unused *oenv, gmx_bool bVerbose,
               int gmx_unused nstglobalcomm,
               t_inputrec *inputrec,
               gmx_mtop_t *top_global, t_fcdata *fcd,
               t_state *state_global,
 +             energyhistory_t gmx_unused *energyHistory,
               t_mdatoms *mdatoms,
               t_nrnb *nrnb, gmx_wallcycle_t wcycle,
               gmx_edsam_t  gmx_unused ed,
      int                  nnodes, node;
      gmx_localtop_t      *top;
      gmx_enerdata_t      *enerd;
 -    rvec                *f;
      gmx_global_stat_t    gstat;
      t_graph             *graph;
      tensor               vir, pres;
      rvec                *fneg, *dfdx;
      gmx_bool             bSparse; /* use sparse matrix storage format */
      size_t               sz;
 -    gmx_sparsematrix_t * sparse_matrix           = NULL;
 -    real           *     full_matrix             = NULL;
 -    em_state_t       *   state_work;
 +    gmx_sparsematrix_t * sparse_matrix           = nullptr;
 +    real           *     full_matrix             = nullptr;
  
      /* added with respect to mdrun */
      int                       row, col;
      real                      x_min;
      bool                      bIsMaster = MASTER(cr);
  
 -    if (constr != NULL)
 +    if (constr != nullptr)
      {
          gmx_fatal(FARGS, "Constraints present with Normal Mode Analysis, this combination is not supported");
      }
  
 -    state_work = init_em_state();
 +    gmx_shellfc_t *shellfc;
 +
 +    em_state_t     state_work {};
  
      /* Init em and store the local state in state_minimum */
      init_em(fplog, NM, cr, inputrec,
 -            state_global, top_global, state_work, &top,
 -            &f,
 -            nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat, vsite, constr,
 -            nfile, fnm, &outf, NULL, imdport, Flags, wcycle);
 -
 -    gmx_shellfc_t *shellfc = init_shell_flexcon(stdout,
 -                                                top_global,
 -                                                n_flexible_constraints(constr),
 -                                                inputrec->nstcalcenergy,
 -                                                DOMAINDECOMP(cr));
 +            state_global, top_global, &state_work, &top,
 +            nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat,
 +            vsite, constr, &shellfc,
 +            nfile, fnm, &outf, nullptr, imdport, Flags, wcycle);
  
 -    if (shellfc)
 -    {
 -        make_local_shells(cr, mdatoms, shellfc);
 -    }
      std::vector<size_t> atom_index = get_atom_index(top_global);
      snew(fneg, atom_index.size());
      snew(dfdx, atom_index.size());
       */
      if (EEL_FULL(fr->eeltype) || fr->rlist == 0.0)
      {
 -        md_print_info(cr, fplog, "Non-cutoff electrostatics used, forcing full Hessian format.\n");
 +        GMX_LOG(mdlog.warning).appendText("Non-cutoff electrostatics used, forcing full Hessian format.");
          bSparse = FALSE;
      }
      else if (atom_index.size() < 1000)
      {
 -        md_print_info(cr, fplog, "Small system size (N=%d), using full Hessian format.\n", atom_index.size());
 +        GMX_LOG(mdlog.warning).appendTextFormatted("Small system size (N=%d), using full Hessian format.",
 +                                                   atom_index.size());
          bSparse = FALSE;
      }
      else
      {
 -        md_print_info(cr, fplog, "Using compressed symmetric sparse Hessian format.\n");
 +        GMX_LOG(mdlog.warning).appendText("Using compressed symmetric sparse Hessian format.");
          bSparse = TRUE;
      }
  
      /* Make evaluate_energy do a single node force calculation */
      cr->nnodes = 1;
      evaluate_energy(fplog, cr,
 -                    top_global, state_work, top,
 +                    top_global, &state_work, top,
                      inputrec, nrnb, wcycle, gstat,
                      vsite, constr, fcd, graph, mdatoms, fr,
                      mu_tot, enerd, vir, pres, -1, TRUE);
      cr->nnodes = nnodes;
  
      /* if forces are not small, warn user */
 -    get_state_f_norm_max(cr, &(inputrec->opts), mdatoms, state_work);
 +    get_state_f_norm_max(cr, &(inputrec->opts), mdatoms, &state_work);
  
 -    md_print_info(cr, fplog, "Maximum force:%12.5e\n", state_work->fmax);
 -    if (state_work->fmax > 1.0e-3)
 +    GMX_LOG(mdlog.warning).appendTextFormatted("Maximum force:%12.5e", state_work.fmax);
 +    if (state_work.fmax > 1.0e-3)
      {
 -        md_print_info(cr, fplog,
 -                      "The force is probably not small enough to "
 -                      "ensure that you are at a minimum.\n"
 -                      "Be aware that negative eigenvalues may occur\n"
 -                      "when the resulting matrix is diagonalized.\n\n");
 +        GMX_LOG(mdlog.warning).appendText(
 +                "The force is probably not small enough to "
 +                "ensure that you are at a minimum.\n"
 +                "Be aware that negative eigenvalues may occur\n"
 +                "when the resulting matrix is diagonalized.");
      }
  
      /***********************************************************
              int         force_flags = GMX_FORCE_STATECHANGED | GMX_FORCE_ALLFORCES;
              double      t           = 0;
  
 -            x_min = state_work->s.x[atom][d];
 +            x_min = state_work.s.x[atom][d];
  
              for (unsigned int dx = 0; (dx < 2); dx++)
              {
                  if (dx == 0)
                  {
 -                    state_work->s.x[atom][d] = x_min - der_range;
 +                    state_work.s.x[atom][d] = x_min - der_range;
                  }
                  else
                  {
 -                    state_work->s.x[atom][d] = x_min + der_range;
 +                    state_work.s.x[atom][d] = x_min + der_range;
                  }
  
                  /* Make evaluate_energy do a single node force calculation */
                                                 inputrec, bNS, force_flags,
                                                 top,
                                                 constr, enerd, fcd,
 -                                               &state_work->s, state_work->f, vir, mdatoms,
 +                                               &state_work.s, &state_work.f, vir, mdatoms,
                                                 nrnb, wcycle, graph, &top_global->groups,
                                                 shellfc, fr, bBornRadii, t, mu_tot,
 -                                               vsite, NULL);
 +                                               vsite);
                      bNS = false;
                      step++;
                  }
                  else
                  {
                      evaluate_energy(fplog, cr,
 -                                    top_global, state_work, top,
 +                                    top_global, &state_work, top,
                                      inputrec, nrnb, wcycle, gstat,
                                      vsite, constr, fcd, graph, mdatoms, fr,
                                      mu_tot, enerd, vir, pres, atom*2+dx, FALSE);
                  {
                      for (size_t i = 0; i < atom_index.size(); i++)
                      {
 -                        copy_rvec(state_work->f[atom_index[i]], fneg[i]);
 +                        copy_rvec(state_work.f[atom_index[i]], fneg[i]);
                      }
                  }
              }
  
              /* x is restored to original */
 -            state_work->s.x[atom][d] = x_min;
 +            state_work.s.x[atom][d] = x_min;
  
              for (size_t j = 0; j < atom_index.size(); j++)
              {
                  for (size_t k = 0; (k < DIM); k++)
                  {
                      dfdx[j][k] =
 -                        -(state_work->f[atom_index[j]][k] - fneg[j][k])/(2*der_range);
 +                        -(state_work.f[atom_index[j]][k] - fneg[j][k])/(2*der_range);
                  }
              }
  
          gmx_mtxio_write(ftp2fn(efMTX, nfile, fnm), sz, sz, full_matrix, sparse_matrix);
      }
  
 -    finish_em(cr, outf, walltime_accounting, wcycle);
 +    finish_em(cr, outf, inputrec, walltime_accounting, wcycle);
  
      walltime_accounting_set_nsteps_done(walltime_accounting, atom_index.size()*2);