Merge branch release-2016
authorBerk Hess <hess@kth.se>
Fri, 16 Sep 2016 11:40:25 +0000 (13:40 +0200)
committerBerk Hess <hess@kth.se>
Fri, 16 Sep 2016 11:41:08 +0000 (13:41 +0200)
Change-Id: I0c8c02d4fbd56042ad77e7b646323b2570d06c7c

297 files changed:
CMakeLists.txt
admin/builds/coverage.py
admin/builds/pre-submit-matrix.txt
admin/builds/release-matrix.txt
cmake/TestAVXMaskload.c [deleted file]
cmake/TestClangVersion.c [deleted file]
cmake/gmxBuildTypeReference.cmake
cmake/gmxCFlags.cmake
cmake/gmxManageGPU.cmake
cmake/gmxManageLinearAlgebraLibraries.cmake
cmake/gmxManageMPI.cmake
cmake/gmxManageNvccConfig.cmake
cmake/gmxManageOpenMP.cmake
cmake/gmxManageSimd.cmake
cmake/gmxManageTNG.cmake
cmake/gmxTestAVXMaskload.cmake [deleted file]
cmake/gmxTestCXX11.cmake
cmake/gmxTestCompilerProblems.cmake
cmake/gmxVersionInfo.cmake
docs/CMakeLists.txt
docs/conf-vars.py.cmakein
docs/conf.py
docs/dev-manual/build-system.rst
docs/dev-manual/language-features.rst
docs/doxygen/includesorter.py
docs/doxygen/lib/logging.md [new file with mode: 0644]
docs/doxygen/user/mainpage.md
docs/install-guide/index.rst
docs/manual/forcefield.tex
docs/manual/monster.bib
src/CMakeLists.txt
src/config.h.cmakein
src/external/gmock-1.7.0/CMakeLists.txt
src/external/thread_mpi/include/thread_mpi/tmpi.h
src/external/thread_mpi/src/gather.c
src/external/thread_mpi/src/p2p_send_recv.c
src/external/thread_mpi/src/scatter.c
src/external/tng_io/BuildTNG.cmake
src/external/tng_io/CMakeLists.txt
src/gromacs/analysisdata/datamodulemanager.cpp
src/gromacs/analysisdata/datastorage.cpp
src/gromacs/analysisdata/modules/displacement.cpp
src/gromacs/analysisdata/modules/lifetime.cpp
src/gromacs/analysisdata/modules/plot.cpp
src/gromacs/analysisdata/tests/datatest.h
src/gromacs/commandline/cmdlinehelpmodule.cpp
src/gromacs/commandline/cmdlinehelpwriter.cpp
src/gromacs/commandline/cmdlinemodulemanager.cpp
src/gromacs/commandline/cmdlineoptionsmodule.cpp
src/gromacs/commandline/pargs.cpp
src/gromacs/commandline/shellcompletions.cpp
src/gromacs/commandline/tests/CMakeLists.txt
src/gromacs/commandline/tests/cmdlinehelpwriter.cpp
src/gromacs/commandline/tests/cmdlineparser.cpp
src/gromacs/commandline/tests/cmdlineprogramcontext.cpp
src/gromacs/commandline/tests/pargs.cpp
src/gromacs/domdec/domdec.cpp
src/gromacs/domdec/domdec.h
src/gromacs/domdec/domdec_network.cpp
src/gromacs/domdec/domdec_topology.cpp
src/gromacs/essentialdynamics/edsam.cpp
src/gromacs/essentialdynamics/edsam.h
src/gromacs/ewald/pme-grid.cpp
src/gromacs/ewald/pme-internal.h
src/gromacs/ewald/pme-load-balancing.cpp
src/gromacs/ewald/pme-load-balancing.h
src/gromacs/ewald/pme-only.cpp
src/gromacs/ewald/pme-pp.cpp
src/gromacs/ewald/pme-solve.cpp
src/gromacs/ewald/pme-solve.h
src/gromacs/ewald/pme.cpp
src/gromacs/ewald/pme.h
src/gromacs/fft/fft_mkl.cpp
src/gromacs/fileio/checkpoint.cpp
src/gromacs/fileio/enxio.cpp
src/gromacs/fileio/enxio.h
src/gromacs/fileio/tests/confio.cpp
src/gromacs/fileio/tpxio.cpp
src/gromacs/gmxana/gmx_analyze.cpp
src/gromacs/gmxana/gmx_angle.cpp
src/gromacs/gmxana/gmx_chi.cpp
src/gromacs/gmxana/gmx_dipoles.cpp
src/gromacs/gmxana/gmx_disre.cpp
src/gromacs/gmxana/gmx_dos.cpp
src/gromacs/gmxana/gmx_energy.cpp
src/gromacs/gmxana/gmx_gyrate.cpp
src/gromacs/gmxana/gmx_hbond.cpp
src/gromacs/gmxana/gmx_pme_error.cpp
src/gromacs/gmxana/gmx_rotacf.cpp
src/gromacs/gmxana/gmx_spol.cpp
src/gromacs/gmxana/gmx_tcaf.cpp
src/gromacs/gmxana/gmx_tune_pme.cpp
src/gromacs/gmxana/gmx_velacc.cpp
src/gromacs/gmxana/legacytests/CMakeLists.txt
src/gromacs/gmxana/legacytests/gmx_traj_tests.cpp
src/gromacs/gmxlib/network.cpp
src/gromacs/gmxlib/nonbonded/nb_kernel_avx_128_fma_single/kernelutil_x86_avx_128_fma_single.h
src/gromacs/gmxlib/nonbonded/nb_kernel_avx_256_single/kernelutil_x86_avx_256_single.h
src/gromacs/gmxpreprocess/genconf.cpp
src/gromacs/gmxpreprocess/grompp.cpp
src/gromacs/gmxpreprocess/pdb2top.cpp
src/gromacs/gmxpreprocess/readpull.cpp
src/gromacs/gpu_utils/cudautils.cu
src/gromacs/gpu_utils/cudautils.cuh
src/gromacs/gpu_utils/gpu_utils.cu
src/gromacs/gpu_utils/gpu_utils.h
src/gromacs/gpu_utils/gpu_utils_ocl.cpp
src/gromacs/hardware/detecthardware.cpp
src/gromacs/hardware/detecthardware.h
src/gromacs/hardware/hardwaretopology.cpp
src/gromacs/hardware/hardwaretopology.h
src/gromacs/linearalgebra/gmx_lapack/dbdsqr.cpp
src/gromacs/linearalgebra/gmx_lapack/sbdsqr.cpp
src/gromacs/math/tests/vectypes.cpp
src/gromacs/math/veccompare.cpp [new file with mode: 0644]
src/gromacs/math/veccompare.h [moved from src/gromacs/tools/compare.h with 70% similarity]
src/gromacs/mdlib/broadcaststructs.cpp
src/gromacs/mdlib/constr.cpp
src/gromacs/mdlib/constr.h
src/gromacs/mdlib/csettle.cpp
src/gromacs/mdlib/force.cpp
src/gromacs/mdlib/force.h
src/gromacs/mdlib/forcerec.cpp
src/gromacs/mdlib/forcerec.h
src/gromacs/mdlib/gmx_omp_nthreads.cpp
src/gromacs/mdlib/gmx_omp_nthreads.h
src/gromacs/mdlib/integrator.h
src/gromacs/mdlib/md_support.cpp
src/gromacs/mdlib/md_support.h
src/gromacs/mdlib/mdatoms.cpp
src/gromacs/mdlib/mdsetup.cpp [new file with mode: 0644]
src/gromacs/mdlib/mdsetup.h [new file with mode: 0644]
src/gromacs/mdlib/minimize.cpp
src/gromacs/mdlib/nbnxn_cuda/nbnxn_cuda.cu
src/gromacs/mdlib/sim_util.cpp
src/gromacs/mdlib/sim_util.h
src/gromacs/mdlib/simulationsignal.h
src/gromacs/mdlib/tests/settle.cpp
src/gromacs/mdlib/tpi.cpp
src/gromacs/mdrunutility/CMakeLists.txt
src/gromacs/mdrunutility/mdmodules.cpp [new file with mode: 0644]
src/gromacs/mdrunutility/mdmodules.h [new file with mode: 0644]
src/gromacs/mdrunutility/tests/CMakeLists.txt [new file with mode: 0644]
src/gromacs/mdrunutility/tests/threadaffinity.cpp [new file with mode: 0644]
src/gromacs/mdrunutility/tests/threadaffinitytest.cpp [new file with mode: 0644]
src/gromacs/mdrunutility/tests/threadaffinitytest.h [new file with mode: 0644]
src/gromacs/mdrunutility/threadaffinity.cpp
src/gromacs/mdrunutility/threadaffinity.h
src/gromacs/mdtypes/inputrec.cpp
src/gromacs/mdtypes/inputrec.h
src/gromacs/mdtypes/state.cpp
src/gromacs/mdtypes/state.h
src/gromacs/onlinehelp/helpformat.cpp
src/gromacs/onlinehelp/helpwritercontext.cpp
src/gromacs/onlinehelp/tests/CMakeLists.txt
src/gromacs/options/CMakeLists.txt
src/gromacs/options/abstractoption.cpp
src/gromacs/options/abstractoption.h
src/gromacs/options/abstractoptionstorage.h
src/gromacs/options/abstractsection.cpp [new file with mode: 0644]
src/gromacs/options/abstractsection.h [new file with mode: 0644]
src/gromacs/options/basicoptions.cpp
src/gromacs/options/basicoptions.h
src/gromacs/options/basicoptionstorage.h
src/gromacs/options/filenameoption.cpp
src/gromacs/options/filenameoptionstorage.h
src/gromacs/options/ioptionscontainer.h
src/gromacs/options/ioptionscontainerwithsections.h [new file with mode: 0644]
src/gromacs/options/isectionstorage.h [new file with mode: 0644]
src/gromacs/options/ivaluestore.h [new file with mode: 0644]
src/gromacs/options/options-impl.h
src/gromacs/options/options.cpp
src/gromacs/options/options.h
src/gromacs/options/optionsassigner.cpp
src/gromacs/options/optionsassigner.h
src/gromacs/options/optionsection.cpp [new file with mode: 0644]
src/gromacs/options/optionsection.h [new file with mode: 0644]
src/gromacs/options/optionstoragetemplate.h
src/gromacs/options/optionsvisitor.cpp
src/gromacs/options/optionsvisitor.h
src/gromacs/options/repeatingsection.h [new file with mode: 0644]
src/gromacs/options/tests/CMakeLists.txt
src/gromacs/options/tests/abstractoptionstorage.cpp
src/gromacs/options/tests/filenameoption.cpp
src/gromacs/options/tests/filenameoptionmanager.cpp
src/gromacs/options/tests/option.cpp
src/gromacs/options/tests/optionsassigner.cpp
src/gromacs/options/tests/repeatingsection.cpp [new file with mode: 0644]
src/gromacs/options/tests/timeunitmanager.cpp
src/gromacs/options/tests/treesupport.cpp [new file with mode: 0644]
src/gromacs/options/timeunitmanager.cpp
src/gromacs/options/treesupport.cpp [new file with mode: 0644]
src/gromacs/options/treesupport.h [moved from src/gromacs/gmxlib/md_logging.h with 63% similarity]
src/gromacs/options/valueconverter.h [new file with mode: 0644]
src/gromacs/options/valuestore.h [new file with mode: 0644]
src/gromacs/random/gammadistribution.h
src/gromacs/selection/indexutil.cpp
src/gromacs/selection/parser.cpp
src/gromacs/selection/parser.h
src/gromacs/selection/parser.patch
src/gromacs/selection/parser.y
src/gromacs/selection/selectioncollection.cpp
src/gromacs/selection/selectionfileoptionstorage.h
src/gromacs/selection/selectionoption.cpp
src/gromacs/selection/selectionoptionmanager.cpp
src/gromacs/selection/selectionoptionstorage.h
src/gromacs/selection/sm_keywords.cpp
src/gromacs/selection/tests/nbsearch.cpp
src/gromacs/selection/tests/poscalc.cpp
src/gromacs/selection/tests/selectionoption.cpp
src/gromacs/selection/tests/toputils.cpp
src/gromacs/simd/impl_ibm_qpx/impl_ibm_qpx_general.h
src/gromacs/simd/impl_ibm_qpx/impl_ibm_qpx_simd4_double.h
src/gromacs/simd/impl_x86_avx_128_fma/impl_x86_avx_128_fma_definitions.h
src/gromacs/swap/swapcoords.cpp
src/gromacs/swap/swapcoords.h
src/gromacs/timing/wallcycle.cpp
src/gromacs/timing/wallcyclereporting.h
src/gromacs/timing/walltime_accounting.cpp
src/gromacs/tools/check.cpp
src/gromacs/tools/compare.cpp [deleted file]
src/gromacs/tools/convert_tpr.cpp
src/gromacs/tools/dump.cpp
src/gromacs/topology/atoms.cpp
src/gromacs/topology/atoms.h
src/gromacs/topology/index.cpp
src/gromacs/topology/topology.cpp
src/gromacs/topology/topology.h
src/gromacs/trajectory/CMakeLists.txt
src/gromacs/trajectory/trajectoryframe.cpp [new file with mode: 0644]
src/gromacs/trajectory/trajectoryframe.h
src/gromacs/trajectoryanalysis/analysismodule.cpp
src/gromacs/trajectoryanalysis/modules/select.cpp
src/gromacs/trajectoryanalysis/tests/surfacearea.cpp
src/gromacs/utility.h
src/gromacs/utility/arrayref.h
src/gromacs/utility/basedefinitions.h
src/gromacs/utility/classhelpers.h
src/gromacs/utility/compare.cpp [new file with mode: 0644]
src/gromacs/utility/compare.h [new file with mode: 0644]
src/gromacs/utility/datafilefinder.cpp
src/gromacs/utility/gmxmpi.h
src/gromacs/utility/keyvaluetree.h [new file with mode: 0644]
src/gromacs/utility/keyvaluetreebuilder.h [new file with mode: 0644]
src/gromacs/utility/keyvaluetreetransform.cpp [new file with mode: 0644]
src/gromacs/utility/keyvaluetreetransform.h [new file with mode: 0644]
src/gromacs/utility/logger.cpp [moved from src/gromacs/gmxlib/md_logging.cpp with 60% similarity]
src/gromacs/utility/logger.h [new file with mode: 0644]
src/gromacs/utility/loggerbuilder.cpp [new file with mode: 0644]
src/gromacs/utility/loggerbuilder.h [new file with mode: 0644]
src/gromacs/utility/messagestringcollector.cpp
src/gromacs/utility/strconvert.cpp [new file with mode: 0644]
src/gromacs/utility/strconvert.h [new file with mode: 0644]
src/gromacs/utility/stringutil.cpp
src/gromacs/utility/stringutil.h
src/gromacs/utility/tests/CMakeLists.txt
src/gromacs/utility/tests/arrayref.cpp
src/gromacs/utility/tests/keyvaluetreetransform.cpp [new file with mode: 0644]
src/gromacs/utility/tests/logger.cpp [new file with mode: 0644]
src/gromacs/utility/tests/refdata/LoggerTest_LevelFilteringWorks.xml [new file with mode: 0644]
src/gromacs/utility/tests/refdata/LoggerTest_LogsToFile.xml [new file with mode: 0644]
src/gromacs/utility/tests/refdata/LoggerTest_LogsToMultipleStreams.xml [new file with mode: 0644]
src/gromacs/utility/tests/refdata/LoggerTest_LogsToStream.xml [new file with mode: 0644]
src/gromacs/utility/tests/refdata/TreeValueTransformTest_ObjectFromMultipleStrings.xml [new file with mode: 0644]
src/gromacs/utility/tests/refdata/TreeValueTransformTest_ObjectFromString.xml [new file with mode: 0644]
src/gromacs/utility/tests/refdata/TreeValueTransformTest_SimpleTransforms.xml [new file with mode: 0644]
src/gromacs/utility/tests/refdata/TreeValueTransformTest_SimpleTransformsToObject.xml [new file with mode: 0644]
src/gromacs/utility/tests/stringutil.cpp
src/gromacs/utility/variant.h [new file with mode: 0644]
src/programs/mdrun/md.cpp
src/programs/mdrun/mdrun.cpp
src/programs/mdrun/resource-division.cpp
src/programs/mdrun/resource-division.h
src/programs/mdrun/runner.cpp
src/programs/mdrun/tests/CMakeLists.txt
src/programs/mdrun/tests/moduletest.cpp
src/testutils/CMakeLists.txt
src/testutils/TestMacros.cmake
src/testutils/cmdlinetest.cpp
src/testutils/interactivetest.cpp
src/testutils/mpitest.cpp [new file with mode: 0644]
src/testutils/mpitest.h [new file with mode: 0644]
src/testutils/refdata-impl.h
src/testutils/refdata.cpp
src/testutils/refdata.h
src/testutils/testasserts.cpp
src/testutils/testasserts.h
src/testutils/testfileredirector.cpp
src/testutils/testinit.cpp
src/testutils/tests/CMakeLists.txt
src/testutils/tests/interactivetest.cpp
src/testutils/tests/mpitest.cpp [new file with mode: 0644]
src/testutils/tests/refdata_tests.cpp
src/testutils/tests/xvgtest_tests.cpp
src/testutils/xvgtest.cpp
tests/CMakeLists.txt
tests/CheckTarget.cmake [new file with mode: 0644]

index 047600e5ff48ae411db9fe4f3b3972fccc5c9258..a3dbf9f4154a43f1a231dee71a10978b1d2a6bb6 100644 (file)
 # 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
@@ -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
@@ -197,12 +192,16 @@ gmx_add_cache_dependency(GMX_COOL_QUOTES BOOL "NOT GMX_FAHCORE" OFF)
 
 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)
 
@@ -336,17 +335,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
@@ -506,7 +494,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.")
@@ -573,8 +561,6 @@ 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)
@@ -607,7 +593,9 @@ gmx_add_cache_dependency(GMX_BUILD_UNITTESTS BOOL BUILD_TESTING OFF)
 
 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)
 
@@ -827,17 +815,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
@@ -847,23 +830,13 @@ elseif((NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin") OR
     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.
@@ -880,18 +853,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)
index 022aafdf96e028449852f2bf5dd72302c09d99f0..317f0aedce74bb4d3be9dd345114c0811e895c21 100644 (file)
@@ -34,7 +34,7 @@
 
 import os.path
 
-build_options = ['gcc-4.6']
+build_options = ['gcc-6.1', 'gcov-6.1']
 extra_projects = [Project.REGRESSIONTESTS]
 
 def do_build(context):
index 6f24dcad9a562e4badc3abb453b81b3ad5316a0b..260e1eba29597706c7b8ff4435424ca276414975 100644 (file)
@@ -1,13 +1,13 @@
-gcc-4.6 gpu cuda-5.0 mpi openmp x11 cmake-2.8.8
+gcc-4.8 gpu cuda-6.5 mpi openmp x11
 gcc-4.8 gpu cuda-7.5 openmp release
 gcc-4.9 tsan fftpack simd=avx2_256
 gcc-6.1 double
-clang-3.4 double no-openmp fftpack asan
+clang-3.4 double no-openmp fftpack asan cmake-3.4.3
 # TODO move mdrun-only config to post-submit matrix
-clang-3.7 double mpi no-openmp fftpack mdrun-only
+clang-3.7 double mpi no-openmp fftpack mdrun-only cmake-3.4.3
 msvc-2015 openmp release
 icc-16.0 msvc-2015 fftpack
-icc-16.0 no-thread-mpi openmp mkl cmake-3.3.2 simd=avx_256
-gcc-5.2 mpi openmp simd=avx_128_fma
+icc-16.0 no-thread-mpi openmp mkl simd=avx_256
+gcc-5.1 mpi openmp cmake-3.4.3
 gcc-4.8 openmp opencl cuda-7.5 mpi release
-gcc-5.2 openmp opencl amdappsdk-3.0
+gcc-5.2 openmp opencl simd=avx_128_fma amdappsdk-3.0
index ef5faea09b18ebad1480c5e220fb4bfd4f76ce11..36e4df93ad61b8a83150c1ebc80c1a9b95a0a052 100644 (file)
@@ -1,6 +1,6 @@
 # These configurations will be used to build and test the tarballs
 # before the release.
 gcc-4.8 mpi mdrun-only
-gcc-4.6 static
-gcc-4.7 double
+gcc-6.1 static
+gcc-5.1 double
 clang-3.4 static double
diff --git a/cmake/TestAVXMaskload.c b/cmake/TestAVXMaskload.c
deleted file mode 100644 (file)
index e8438a1..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#include<immintrin.h>
-int main()
-{
-    __m256d a;
-    __m256i mask;
-    double  d[4]={1,2,3,4};
-
-    a = _mm256_setzero_pd();
-    mask = _mm256_castpd_si256(a);
-
-#if GMX_SIMD_X86_AVX_GCC_MASKLOAD_BUG
-    a = _mm256_maskload_pd(d,_mm256_castsi256_pd(mask));
-#else
-    a = _mm256_maskload_pd(d,mask);
-#endif
-    return 0;
-}
-
diff --git a/cmake/TestClangVersion.c b/cmake/TestClangVersion.c
deleted file mode 100644 (file)
index f47c777..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-int main()
-{
-/* This detects 3.0 versions for both C and C++ clang. It detects the
- * version of the LLVM back end, and not (for example) the Apple clang
- * version number (which might be 4.1 or some number based on its
- * "compatibility with gcc 4.2.1," even though the LLVM back end is
- * 3.0!).
- *
- * If/when we have time or user complaints, we can maybe ban earlier
- * versions of clang, but we don't actually know there's a problem
- * with them at the time of this commit.
- */
-#if (__clang_major__ == 3) && (__clang_minor__ == 0)
-    return 0;
-#else
-#error clang version information not found
-#endif
-}
index 6c33a5fe99d96de2d849085162d85b500bbb7ee6..8116ac7b7f44cafb4b12764ffee92ec2ef5eafe9 100644 (file)
@@ -48,8 +48,8 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Reference")
     set(GMX_SOFTWARE_INVSQRT OFF CACHE BOOL "Disabled for regressiontests reference builds" FORCE)
     set(GMX_THREAD_MPI OFF CACHE BOOL "Disabled for regressiontests reference builds" FORCE)
 
-    if(NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR NOT "${CMAKE_C_COMPILER_VERSION}" MATCHES "4.7")
+    if(NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR NOT "${CMAKE_C_COMPILER_VERSION}" MATCHES "4.8")
         message(WARNING "Reference values for regressiontests should use GROMACS compiled with "
-            "gcc 4.7, but your configuration is using ${CMAKE_C_COMPILER_ID}-${CMAKE_C_COMPILER_VERSION}.")
+            "gcc 4.8, but your configuration is using ${CMAKE_C_COMPILER_ID}-${CMAKE_C_COMPILER_VERSION}.")
     endif()
 endif()
index 69bc7956f2da4d209dd5b3340853c258340cff6e..8e1614be1a47f65b3cd66a6f648fbaa6ab0a0d20 100644 (file)
@@ -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
@@ -148,28 +152,12 @@ macro (gmx_c_flags)
     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
 # 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
@@ -180,10 +168,9 @@ macro (gmx_c_flags)
 #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 -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)
@@ -191,17 +178,10 @@ macro (gmx_c_flags)
             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 /wd593 /wd981 /wd1418 /wd1419 /wd1572 /wd1599 /wd2259 /wd2415 /wd2547 /wd2557 /wd3280" GMXC_CFLAGS)
             endif()
             GMX_TEST_CFLAG(CFLAGS_OPT "/Qip" GMXC_CFLAGS_RELEASE)
         endif()
@@ -210,37 +190,33 @@ macro (gmx_c_flags)
     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 -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_DEBUG "-O0" GMXC_CXXFLAGS_DEBUG)
             GMX_TEST_CXXFLAG(CXXFLAGS_FP_RELASSERT "-fp-model except -fp-model precise" GMXC_CXXFLAGS_RELWITHASSERT)
         else()
             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)
-                if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.00.00)
-                    GMX_TEST_CXXFLAG(CXXFLAGS_WARN_OLD /wd193 GMXC_CXXFLAGS)
-                endif()
-                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 /wd1782 /wd2282" GMXC_CXXFLAGS)
+                GMX_TEST_CXXFLAG(CXXFLAGS_WARN "/W3 /wd177 /wd383 /wd444 /wd981 /wd1418 /wd1572 /wd1599 /wd2259 /wd3280 /wd11074 /wd11076 /wd2282" GMXC_CXXFLAGS)
             endif()
             GMX_TEST_CXXFLAG(CXXFLAGS_OPT "/Qip" GMXC_CXXFLAGS_RELEASE)
         endif()
index a6b5439303a32ea1a687c026bf262d6e7de91e0f..60a74291ecf64a174b7366d30efb143388c05b2a 100644 (file)
@@ -57,18 +57,8 @@ if ((GMX_GPU OR GMX_GPU_AUTO) AND NOT GMX_GPU_DETECTION_DONE)
     gmx_detect_gpu()
 endif()
 
-# CMake 3.0-3.1 has a bug in the following case, which breaks
-# configuration on at least BlueGene/Q. Fixed in 3.1.1
-if ((NOT CMAKE_VERSION VERSION_LESS "3.0.0") AND
-    (CMAKE_VERSION VERSION_LESS "3.1.1") AND
-        (CMAKE_CROSSCOMPILING AND NOT CMAKE_SYSTEM_PROCESSOR))
-    message(STATUS "Cannot search for CUDA because the CMake find package has a bug. Set a valid CMAKE_SYSTEM_PROCESSOR if you need to detect CUDA")
-else()
-    set(CAN_RUN_CUDA_FIND_PACKAGE 1)
-endif()
-
 # We need to call find_package even when we've already done the detection/setup
-if(GMX_GPU OR GMX_GPU_AUTO AND CAN_RUN_CUDA_FIND_PACKAGE)
+if(GMX_GPU OR GMX_GPU_AUTO)
     if(NOT GMX_GPU AND NOT GMX_DETECT_GPU_AVAILABLE)
         # Stay quiet when detection has occured and found no GPU.
         # Noise is acceptable when there is a GPU or the user required one.
@@ -82,23 +72,6 @@ if(GMX_GPU OR GMX_GPU_AUTO AND CAN_RUN_CUDA_FIND_PACKAGE)
     endif()
 
     find_package(CUDA ${REQUIRED_CUDA_VERSION} ${FIND_CUDA_QUIETLY})
-
-    # Cmake 2.8.12 (and CMake 3.0) introduced a new bug where the cuda
-    # library dir is added twice as an rpath on APPLE, which in turn causes
-    # the install_name_tool to wreck the binaries when it tries to remove this
-    # path. Since this is set inside the cuda module, we remove the extra rpath
-    # added in the library string - an rpath is not a library anyway, and at
-    # least for Gromacs this works on all CMake versions. This should be
-    # reasonably future-proof, since newer versions of CMake appear to handle
-    # the rpath automatically based on the provided library path, meaning
-    # the explicit rpath specification is no longer needed.
-    if(APPLE AND (CMAKE_VERSION VERSION_GREATER 2.8.11))
-        foreach(elem ${CUDA_LIBRARIES})
-            if(elem MATCHES "-Wl,.*")
-                list(REMOVE_ITEM CUDA_LIBRARIES ${elem})
-            endif()
-        endforeach(elem)
-    endif()
 endif()
 
 # Depending on the current vale of GMX_GPU and GMX_GPU_AUTO:
@@ -182,13 +155,13 @@ endif()
 # We need to mark these advanced outside the conditional, otherwise, if the
 # user turns GMX_GPU=OFF after a failed cmake pass, these variables will be
 # left behind in the cache.
-mark_as_advanced(CUDA_BUILD_CUBIN CUDA_BUILD_EMULATION CUDA_SDK_ROOT_DIR CUDA_VERBOSE_BUILD # cmake 2.8.9 still spews these, check again when requirements change
-                 CUDA_SEPARABLE_COMPILATION      # not present at least with cmake 3.2, remove when required
-                 CUDA_USE_STATIC_CUDA_RUNTIME    # since cmake 3.3
-                 CUDA_dl_LIBRARY CUDA_rt_LIBRARY # - || -
+mark_as_advanced(CUDA_SDK_ROOT_DIR
+                 CUDA_USE_STATIC_CUDA_RUNTIME
+                 CUDA_dl_LIBRARY CUDA_rt_LIBRARY
                  )
 if(NOT GMX_GPU)
     mark_as_advanced(CUDA_TOOLKIT_ROOT_DIR)
+    mark_as_advanced(CUDA_HOST_COMPILER)
 endif()
 
 # Try to execute ${CUDA_NVCC_EXECUTABLE} --version and set the output
index 8c8562b9c75dc100154a1679ee369d26dc821284..aeb7937c7405d06c7d3213dcff64df7c7fe83258 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2013,2014, by the GROMACS development team, led by
+# Copyright (c) 2013,2014,2016, 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.
@@ -89,7 +89,7 @@ macro(manage_linear_algebra_library name function_in_library)
             set(CMAKE_REQUIRED_FLAGS "${FFT_LINKER_FLAGS}")
             # This may also not work correctly if the user changes
             # MKL_LIBRARIES after the first run. However,
-            # MKL_LIBRARIES is only needed for icc version < 11, or
+            # MKL_LIBRARIES is only needed
             # for trying to use MKL with a non-Intel compiler, and we
             # can live with that for now.
             check_function_exists(${function_in_library} _${name}_mkl_works)
@@ -110,8 +110,7 @@ macro(manage_linear_algebra_library name function_in_library)
         if (NOT _library_was_found)
             set(${name}_FIND_QUIETLY ${_find_quietly})
             # Note that this finds all kinds of system libraries,
-            # including Apple's Accelerate Framework (and perhaps MKL for
-            # icc < 11).
+            # including Apple's Accelerate Framework
             find_package(${name})
             if (${name}_FOUND)
                 set(_libraries_to_link ${${name}_LIBRARIES})
index 1d3645a44383c704275d67fb88e3457b8f6ffd5a..2fe4b52bb78aea0f74674ce8a8e26c595081ee4a 100644 (file)
@@ -165,15 +165,6 @@ if(GMX_MPI)
       endif()
     endif()
     unset(MPINAME_BIN CACHE)
-
-    # Using find_file() runs the CMake standard module
-    # GetPrerequisites.cmake, which adds the file_cmd
-    # variable to the top-level CMake namespace. This is
-    # fixed in CMake 2.8.10. Meanwhile, clean up for it.
-    if(CMAKE_VERSION VERSION_LESS "2.8.10")
-        mark_as_advanced(file_cmd)
-    endif()
-
   else()
       message(FATAL_ERROR
         "MPI support requested, but no MPI compiler found. Either set the "
index 34de4bad36cf1cacbe6c5e54b650770e1153412b..c8561f44febf6f6e004c7c838a56a0d0e54cf0b8 100644 (file)
@@ -36,7 +36,7 @@
 # pain as much as possible:
 # - use the CUDA_HOST_COMPILER if defined by the user, otherwise
 # - auto-detect compatible nvcc host compiler and set nvcc -ccbin (if not MPI wrapper)
-# - set icc compatibility mode to gcc 4.6
+# - set icc compatibility mode to gcc 4.8.1
 # - (advanced) variables set:
 #   * CUDA_HOST_COMPILER            - the host compiler for nvcc (only with cmake <2.8.10)
 #   * CUDA_HOST_COMPILER_OPTIONS    - the full host-compiler related option list passed to nvcc
@@ -87,25 +87,7 @@ endfunction()
 
 # set up host compiler and its options
 if(CUDA_HOST_COMPILER_CHANGED)
-    # FindCUDA in CMake 2.8.10 sets the host compiler internally
-    if (CMAKE_VERSION VERSION_LESS "2.8.10")
-        set(CUDA_HOST_COMPILER ${CUDA_HOST_COMPILER}
-            CACHE PATH "Host compiler for nvcc")
-    endif()
-
-    # On *nix force icc in gcc 4.6 compatibility mode. This is needed
-    # as even with icc used as host compiler, when icc's gcc compatibility
-    # mode is higher than the max gcc version officially supported by CUDA,
-    # nvcc will freak out.
     set(CUDA_HOST_COMPILER_OPTIONS "")
-    if (UNIX AND
-            ((CMAKE_C_COMPILER_ID MATCHES "Intel" AND
-              (CUDA_HOST_COMPILER_AUTOSET OR CMAKE_C_COMPILER STREQUAL CUDA_HOST_COMPILER)) OR
-            (CMAKE_CXX_COMPILER_ID MATCHES "Intel" AND CMAKE_CXX_COMPILER STREQUAL CUDA_HOST_COMPILER))
-        )
-        message(STATUS "Setting Intel Compiler compatibity mode to gcc 4.6 for nvcc host compilation")
-        list(APPEND CUDA_HOST_COMPILER_OPTIONS "-Xcompiler;-gcc-version=460")
-    endif()
 
     if(APPLE AND CMAKE_C_COMPILER_ID MATCHES "GNU")
         # Some versions of gcc-4.8 and gcc-4.9 produce errors (in particular on OS X)
@@ -191,52 +173,11 @@ list(APPEND GMX_CUDA_NVCC_FLAGS "${GMX_CUDA_NVCC_GENCODE_FLAGS}")
 list(APPEND GMX_CUDA_NVCC_FLAGS "-use_fast_math")
 
 # assemble the CUDA host compiler flags
-# with CMake <2.8.10 the host compiler needs to be set on the nvcc command line
-if (CMAKE_VERSION VERSION_LESS "2.8.10")
-    list(APPEND GMX_CUDA_NVCC_FLAGS "-ccbin=${CUDA_HOST_COMPILER}")
-endif()
 list(APPEND GMX_CUDA_NVCC_FLAGS "${CUDA_HOST_COMPILER_OPTIONS}")
 
 # The flags are set as local variables which shadow the cache variables. The cache variables
 # (can be set by the user) are appended. This is done in a macro to set the flags when all
 # host compiler flags are already set.
 macro(GMX_SET_CUDA_NVCC_FLAGS)
-    if(CUDA_PROPAGATE_HOST_FLAGS)
-        set(CUDA_PROPAGATE_HOST_FLAGS OFF)
-
-        # When CUDA 6.5 is required we should use C++11 also for CUDA and also propagate
-        # the C++11 flag to CUDA. Then we can use the solution implemented in FindCUDA
-        # (starting with 3.3 - can be backported). For now we need to remove the C++11
-        # flag which means we need to manually propagate all other flags.
-        string(REGEX REPLACE "[-]+std=c\\+\\+0x" "" _CMAKE_CXX_FLAGS_SANITIZED "${CMAKE_CXX_FLAGS}")
-
-        # The IBM xlc compiler chokes if we use both altivec and Cuda. Solve
-        # this by not propagating the flag in this case.
-        if(CMAKE_CXX_COMPILER_ID MATCHES "XL")
-            string(REGEX REPLACE "-qaltivec" "" _CMAKE_CXX_FLAGS_SANITIZED "${_CMAKE_CXX_FLAGS_SANITIZED}")
-        endif()
-
-        # CUDA versions prior to 7.5 come with a header (math_functions.h) which uses the _MSC_VER macro
-        # unconditionally, so we strip -Wundef from the propagatest flags for earlier CUDA versions.
-        if (CUDA_VERSION VERSION_LESS "7.5")
-            string(REGEX REPLACE "-Wundef" "" _CMAKE_CXX_FLAGS_SANITIZED "${_CMAKE_CXX_FLAGS_SANITIZED}")
-        endif()
-
-        string(REPLACE " " "," _flags "${_CMAKE_CXX_FLAGS_SANITIZED}")
-        set(CUDA_NVCC_FLAGS "${GMX_CUDA_NVCC_FLAGS};${CUDA_NVCC_FLAGS};-Xcompiler;${_flags}")
-
-        # Create list of all possible configurations. For multi-configuration this is CMAKE_CONFIGURATION_TYPES
-        # and for single configuration CMAKE_BUILD_TYPE. Not sure why to add the default ones, but FindCUDA
-        # claims one should.
-        set(CUDA_configuration_types ${CMAKE_CONFIGURATION_TYPES} ${CMAKE_BUILD_TYPE} Debug MinSizeRel Release RelWithDebInfo)
-        list(REMOVE_DUPLICATES CUDA_configuration_types)
-
-        foreach(_config ${CUDA_configuration_types})
-            string(TOUPPER ${_config} _config_upper)
-            string(REPLACE " " "," _flags "${CMAKE_CXX_FLAGS_${_config_upper}}")
-            set(CUDA_NVCC_FLAGS_${_config_upper} "${CUDA_NVCC_FLAGS_${_config_upper}};-Xcompiler;${_flags}")
-        endforeach()
-    else()
-        set(CUDA_NVCC_FLAGS "${GMX_CUDA_NVCC_FLAGS};${CUDA_NVCC_FLAGS}")
-    endif()
+    set(CUDA_NVCC_FLAGS "${GMX_CUDA_NVCC_FLAGS};${CUDA_NVCC_FLAGS}")
 endmacro()
index 5903957beff2a67a1d01d03e107a79e8bf0b202d..f1b373159e5149bc1fe4e2b2a48c56e370a0b2e8 100644 (file)
@@ -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
 # 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.
 # and then does some additional tests for flags afterwards.
 
 if(GMX_OPENMP)
-    if(CMAKE_C_COMPILER_ID MATCHES "Cray" AND CMAKE_VERSION VERSION_LESS 3)
-        message(STATUS "OpenMP multithreading is not detected correctly for the Cray compiler with CMake before version 3.0 (see http://public.kitware.com/Bug/view.php?id=14567)")
-        set(GMX_OPENMP OFF CACHE BOOL
-            "OpenMP multithreading is not detected correctly for the Cray compiler with CMake before version 3.0 (see http://public.kitware.com/Bug/view.php?id=14567)" FORCE)
-    else()
-        # We should do OpenMP detection if we get here
-        # OpenMP check must come before other CFLAGS!
-        find_package(OpenMP)
-        if(OPENMP_FOUND)
-            # CMake on Windows doesn't support linker flags passed to target_link_libraries
-            # (i.e. it treats /openmp as \openmp library file). Also, no OpenMP linker flags are needed.
-            if(NOT (WIN32 AND NOT MINGW))
-                if(CMAKE_COMPILER_IS_GNUCC AND GMX_PREFER_STATIC_OPENMP AND NOT APPLE)
-                    set(OpenMP_LINKER_FLAGS "-Wl,-static -lgomp -lrt -Wl,-Bdynamic -lpthread")
-                    set(OpenMP_SHARED_LINKER_FLAGS "")
-                else()
-                    # Only set a linker flag if the user didn't set them manually
-                    if(NOT DEFINED OpenMP_LINKER_FLAGS)
-                        set(OpenMP_LINKER_FLAGS "${OpenMP_C_FLAGS}")
-                    endif()
-                    if(NOT DEFINED OpenMP_SHARED_LINKER_FLAGS)
-                        set(OpenMP_SHARED_LINKER_FLAGS "${OpenMP_C_FLAGS}")
-                    endif()
+    # We should do OpenMP detection if we get here
+    # OpenMP check must come before other CFLAGS!
+    find_package(OpenMP)
+    if(OPENMP_FOUND)
+        # CMake on Windows doesn't support linker flags passed to target_link_libraries
+        # (i.e. it treats /openmp as \openmp library file). Also, no OpenMP linker flags are needed.
+        if(NOT (WIN32 AND NOT MINGW))
+            if(CMAKE_COMPILER_IS_GNUCC AND GMX_PREFER_STATIC_OPENMP AND NOT APPLE)
+                set(OpenMP_LINKER_FLAGS "-Wl,-static -lgomp -lrt -Wl,-Bdynamic -lpthread")
+                set(OpenMP_SHARED_LINKER_FLAGS "")
+            else()
+                # Only set a linker flag if the user didn't set them manually
+                if(NOT DEFINED OpenMP_LINKER_FLAGS)
+                    set(OpenMP_LINKER_FLAGS "${OpenMP_C_FLAGS}")
+                endif()
+                if(NOT DEFINED OpenMP_SHARED_LINKER_FLAGS)
+                    set(OpenMP_SHARED_LINKER_FLAGS "${OpenMP_C_FLAGS}")
                 endif()
             endif()
-            if(MINGW)
-                #GCC Bug 48659
-                set(OpenMP_C_FLAGS "${OpenMP_C_FLAGS} -mstackrealign")
-            endif()
-        else()
-            message(WARNING
-                    "The compiler you are using does not support OpenMP parallelism. This might hurt your performance a lot, in particular with GPUs. Try using a more recent version, or a different compiler. For now, we are proceeding by turning off OpenMP.")
-            set(GMX_OPENMP OFF CACHE STRING "Whether GROMACS will use OpenMP parallelism." FORCE)
         endif()
+        if(MINGW)
+            #GCC Bug 48659
+            set(OpenMP_C_FLAGS "${OpenMP_C_FLAGS} -mstackrealign")
+        endif()
+    else()
+        message(WARNING
+                "The compiler you are using does not support OpenMP parallelism. This might hurt your performance a lot, in particular with GPUs. Try using a more recent version, or a different compiler. For now, we are proceeding by turning off OpenMP.")
+        set(GMX_OPENMP OFF CACHE STRING "Whether GROMACS will use OpenMP parallelism." FORCE)
     endif()
 endif()
 gmx_dependent_cache_variable(GMX_OPENMP_MAX_THREADS
index f3bf27bde9c7f11d3ed6866a954d7ec9ba591b47..b862a71cd61344571c3dc699903248cc19164bb6 100644 (file)
@@ -32,8 +32,6 @@
 # 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 avx test source, used if the AVX flags are set below
-include(gmxTestAVXMaskload)
 include(gmxFindFlagsForSource)
 
 # Macro that manages setting the respective C and C++ toolchain
@@ -247,8 +245,6 @@ elseif(GMX_SIMD STREQUAL "AVX_128_FMA")
     set(GMX_SIMD_X86_${GMX_SIMD} 1)
     set(SIMD_STATUS_MESSAGE "Enabling 128-bit AVX SIMD GROMACS SIMD (with fused-multiply add)")
 
-    gmx_test_avx_gcc_maskload_bug(GMX_SIMD_X86_AVX_GCC_MASKLOAD_BUG "${SIMD_C_FLAGS}")
-
 elseif(GMX_SIMD STREQUAL "AVX_256")
 
     prepare_x86_toolchain(TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS)
@@ -269,8 +265,6 @@ elseif(GMX_SIMD STREQUAL "AVX_256")
     set(GMX_SIMD_X86_${GMX_SIMD} 1)
     set(SIMD_STATUS_MESSAGE "Enabling 256-bit AVX SIMD instructions")
 
-    gmx_test_avx_gcc_maskload_bug(GMX_SIMD_X86_AVX_GCC_MASKLOAD_BUG "${SIMD_C_FLAGS}")
-
 elseif(GMX_SIMD STREQUAL "AVX2_256")
 
     prepare_x86_toolchain(TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS)
@@ -291,8 +285,6 @@ elseif(GMX_SIMD STREQUAL "AVX2_256")
     set(GMX_SIMD_X86_${GMX_SIMD} 1)
     set(SIMD_STATUS_MESSAGE "Enabling 256-bit AVX2 SIMD instructions")
 
-    # No need to test for Maskload bug - it was fixed before gcc added AVX2 support
-
 elseif(GMX_SIMD STREQUAL "MIC")
 
     # No flags needed. Not testing.
@@ -386,7 +378,7 @@ elseif(GMX_SIMD STREQUAL "IBM_QPX")
         set(SIMD_STATUS_MESSAGE "Enabling IBM QPX SIMD instructions")
 
     else()
-        gmx_give_fatal_error_when_simd_support_not_found("IBM QPX" "or 'cmake .. -DCMAKE_TOOLCHAIN_FILE=Platform/BlueGeneQ-static-XL-CXX' to set up the tool chain" "${SUGGEST_BINUTILS_UPDATE}")
+        gmx_give_fatal_error_when_simd_support_not_found("IBM QPX" "or 'cmake .. -DCMAKE_TOOLCHAIN_FILE=Platform/BlueGeneQ-static-bgclang-CXX' to set up the tool chain" "${SUGGEST_BINUTILS_UPDATE}")
     endif()
 
 elseif(GMX_SIMD STREQUAL "IBM_VMX")
index 12ada3d967fdb597064c9bfdd5bc64335e8fff3f..b14b0130286daca6a17f566a456da9bf46e758cb 100644 (file)
@@ -46,7 +46,8 @@ if(GMX_USE_TNG)
         include_directories(SYSTEM ${TNG_IO_INCLUDE_DIRS})
     else()
         include(${BUNDLED_TNG_LOCATION}/BuildTNG.cmake)
-        tng_get_source_list(TNG_SOURCES TNG_IO_DEFINITIONS)
+        tng_get_source_list(TNG_SOURCES TNG_IO_DEFINITIONS TNG_INCLUDE_DIRS)
+        include_directories(BEFORE SYSTEM "${TNG_INCLUDE_DIRS}")
 
         if (HAVE_ZLIB)
             list(APPEND GMX_EXTRA_LIBRARIES ${ZLIB_LIBRARIES})
diff --git a/cmake/gmxTestAVXMaskload.cmake b/cmake/gmxTestAVXMaskload.cmake
deleted file mode 100644 (file)
index a522d6c..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#
-# This file is part of the GROMACS molecular simulation package.
-#
-# Copyright (c) 2012,2013,2014,2015, 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.
-
-#  GMX_TEST_AVX_GCC_MASKLOAD_BUG(VARIABLE AVX_CFLAGS)
-#
-#  VARIABLE will be set if the compiler is a buggy version
-#  of GCC (prior to 4.5.3, and maybe 4.6) that has an incorrect second
-#  argument to the AVX _mm256_maskload_ps() intrinsic.
-#
-#  You need to use this variable in a cmakedefine, and then handle
-#  the case separately in your code - no automatic cure, unfortunately.
-#
-MACRO(GMX_TEST_AVX_GCC_MASKLOAD_BUG VARIABLE AVX_CFLAGS)
-    IF(NOT DEFINED ${VARIABLE})
-        MESSAGE(STATUS "Checking for gcc AVX maskload bug")
-        # some compilers like clang accept both cases, 
-        # so first try a normal compile to avoid flagging those as buggy.
-        TRY_COMPILE(${VARIABLE}_COMPILEOK "${CMAKE_BINARY_DIR}"
-                    "${CMAKE_SOURCE_DIR}/cmake/TestAVXMaskload.c"
-                    COMPILE_DEFINITIONS "${AVX_CFLAGS} -DGMX_SIMD_X86_AVX_GCC_MASKLOAD_BUG=0" )
-        IF(${VARIABLE}_COMPILEOK)
-            SET(${VARIABLE} 0 CACHE INTERNAL "Work around GCC bug in AVX maskload argument" FORCE)
-            MESSAGE(STATUS "Checking for gcc AVX maskload bug - not present")
-        ELSE()
-            TRY_COMPILE(${VARIABLE}_COMPILEOK "${CMAKE_BINARY_DIR}"
-                        "${CMAKE_SOURCE_DIR}/cmake/TestAVXMaskload.c"
-                         COMPILE_DEFINITIONS "${AVX_CFLAGS} -DGMX_SIMD_X86_AVX_GCC_MASKLOAD_BUG=1" )
-            IF(${VARIABLE}_COMPILEOK)
-                SET(${VARIABLE} 1 CACHE INTERNAL "Work around GCC bug in AVX maskload argument" FORCE)
-                MESSAGE(STATUS "Checking for gcc AVX maskload bug - found, will try to work around")
-            ELSE()
-                MESSAGE(WARNING "Cannot compile AVX code - assuming gcc AVX maskload bug not present." )
-                MESSAGE(STATUS "Checking for gcc AVX maskload bug - not present")
-            ENDIF()
-        ENDIF()
-    ENDIF()
-ENDMACRO()
index 65a15984634ba80982868dec654aaed2ff211ae9..ea6bed874f22bf5500c1ca78e2ba70a8d55dd763 100644 (file)
@@ -45,11 +45,11 @@ function(GMX_TEST_CXX11 CXX11_CXX_FLAG_NAME STDLIB_CXX_FLAG_NAME STDLIB_LIBRARIE
     # 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)
@@ -106,7 +106,26 @@ int main() {
   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()
@@ -128,8 +147,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 80bfc062f3ead631863ba40f09f26e1fada75798..26eeb298df4c1c7497abd12f3dfb906491f6e494 100644 (file)
@@ -44,37 +44,21 @@ macro(gmx_test_compiler_problems)
         message(WARNING "The versions of the C and C++ compilers do not match (${CMAKE_C_COMPILER_VERSION} and ${CMAKE_CXX_COMPILER_VERSION}, respectively). Mixing different C/C++ compilers can cause problems.")
     endif()
 
-    # clang 3.0 is buggy for some unknown reason detected during adding
-    # the SSE2 group kernels for GROMACS 4.6. If we ever work out what
-    # that is, we should replace these tests with a compiler feature test,
-    # update GROMACS Redmine task #1039 and perhaps report a clang bug.
-    #
-    # In the meantime, until we require CMake 2.8.10 we cannot rely on it to detect
-    # the compiler version for us. So we need a manual check for clang 3.0.
-    include(gmxDetectClang30)
-    gmx_detect_clang_3_0(COMPILER_IS_CLANG_3_0)
-    if(COMPILER_IS_CLANG_3_0)
-        message(FATAL_ERROR "Your compiler is clang version 3.0, which is known to be buggy for GROMACS. Use a different compiler.")
-    endif()
-
-    if (CMAKE_C_COMPILER_ID STREQUAL "PGI")
-        message(WARNING "Currently tested PGI compiler versions (up to 15.7) generate binaries that do not pass all regression test, and the generated binaries are significantly slower than with GCC, ICC or Clang. For now we do not recommend PGI beyond development testing - make sure to run the regressiontests.")
-    endif()
+    # Note that we've already tested that the compiler works with C++11
+    if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
 
-    if(CMAKE_COMPILER_IS_GNUCC AND
-            (CMAKE_C_COMPILER_VERSION VERSION_LESS "4.9.0" OR CMAKE_SIZEOF_VOID_P EQUAL 8)
-            AND (WIN32 OR CYGWIN)
-            AND GMX_SIMD MATCHES "AVX" AND NOT GMX_SIMD STREQUAL AVX_128_FMA)
-        message(WARNING "GCC on Windows (GCC older than 4.9 or any version when compiling for 64bit) with AVX (other than AVX_128_FMA) crashes. Choose a different GMX_SIMD or a different compiler.") # GCC bug 49001, 54412.
-    endif()
-
-    if(CMAKE_C_COMPILER_ID MATCHES "Clang" AND WIN32)
-        if(CMAKE_VERSION VERSION_LESS 3.0.0)
-            message(WARNING "Clang on Windows requires cmake 3.0.0")
+        # GCC bug 49001, 54412 on Windows (just warn, since it might be fixed in later versions)
+        if((CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.9.0" OR CMAKE_SIZEOF_VOID_P EQUAL 8)
+           AND (WIN32 OR CYGWIN)
+           AND (GMX_SIMD MATCHES "AVX") AND NOT (GMX_SIMD STREQUAL AVX_128_FMA))
+            message(WARNING "GCC on Windows (GCC older than 4.9 in 32-bit mode, or any version in 64-bit mode) with 256-bit AVX will probably crashes. You might want to choose a different GMX_SIMD or a different compiler.")
         endif()
-        if(CMAKE_C_COMPILER_VERSION VERSION_LESS 3.5.0)
-            message(WARNING "Clang on Windows requires clang 3.5.0")
+    elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+        if(WIN32 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "3.5.0")
+            message(WARNING "Using Clang on Windows requires Clang 3.5.0")
         endif()
+    elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "PGI")
+        message(WARNING "Currently tested PGI compiler versions (up to 15.7) generate binaries that do not pass all regression test, and the generated binaries are significantly slower than with GCC, ICC or Clang. For now we do not recommend PGI beyond development testing - make sure to run the regressiontests.")
     endif()
 
 endmacro(gmx_test_compiler_problems)
index 2e383d277b3be0ecb969250446f040047a1fc6ab..f7d7a2bc9efbefdca7b65c78e3bc2480f82557db 100644 (file)
 
 # The GROMACS convention is that these are the version number of the next
 # release that is going to be made from this branch.
-set(GMX_VERSION_MAJOR 2016)
-set(GMX_VERSION_PATCH 1)
+set(GMX_VERSION_MAJOR 2017)
+set(GMX_VERSION_PATCH 0)
 # The suffix, on the other hand, is used mainly for betas and release
 # candidates, where it signifies the most recent such release from
 # this branch; it will be empty before the first such release, as well
@@ -204,7 +204,7 @@ set(GMX_VERSION_SUFFIX "")
 # here. The important thing is to minimize the chance of third-party
 # code being able to dynamically link with a version of libgromacs
 # that might not work.
-set(LIBRARY_SOVERSION_MAJOR 2)
+set(LIBRARY_SOVERSION_MAJOR 3)
 set(LIBRARY_SOVERSION_MINOR 0)
 set(LIBRARY_VERSION ${LIBRARY_SOVERSION_MAJOR}.${LIBRARY_SOVERSION_MINOR}.0)
 
index ec6e4550ef5366f00ee9f979c5a096bdbcc22b4b..f769fb0cb1fd248af095235c7c62baa9a33e0135 100644 (file)
@@ -141,7 +141,7 @@ if (SPHINX_FOUND)
         EXTRA_VARS
             SPHINX_EXTENSION_PATH RELENG_PATH
             EXPECTED_DOXYGEN_VERSION
-            GMX_CMAKE_MINIMUM_REQUIRED_VERSION REQUIRED_CUDA_VERSION
+            CMAKE_MINIMUM_REQUIRED_VERSION REQUIRED_CUDA_VERSION
             REQUIRED_OPENCL_MIN_VERSION
             REQUIRED_CUDA_COMPUTE_CAPABILITY REGRESSIONTEST_VERSION
             SOURCE_MD5SUM REGRESSIONTEST_MD5SUM_STRING
index a8bbe35e3c153b5f3ceb2bd6655ba3bc489b01b1..b7c216a81be246e658a194a4d1db193d95f1ca11 100644 (file)
@@ -39,7 +39,7 @@ gmx_version_string_full = '@GMX_VERSION_STRING_FULL@'
 regressiontest_version = '@REGRESSIONTEST_VERSION@'
 variables = [
         ('EXPECTED_DOXYGEN_VERSION', '@EXPECTED_DOXYGEN_VERSION@'),
-        ('GMX_CMAKE_MINIMUM_REQUIRED_VERSION', '@GMX_CMAKE_MINIMUM_REQUIRED_VERSION@'),
+        ('CMAKE_MINIMUM_REQUIRED_VERSION', '@CMAKE_MINIMUM_REQUIRED_VERSION@'),
         ('REQUIRED_CUDA_VERSION', '@REQUIRED_CUDA_VERSION@'),
         ('REQUIRED_CUDA_COMPUTE_CAPABILITY', '@REQUIRED_CUDA_COMPUTE_CAPABILITY@'),
         ('REQUIRED_OPENCL_MIN_VERSION', '@REQUIRED_OPENCL_MIN_VERSION@'),
index 94c0012893adb693507dcf2e75bbe6f4d8e4a6f1..58a676adf47f3c9c18cd9246ea6f806306276d19 100644 (file)
@@ -161,6 +161,8 @@ rst_epilog += """
 .. _LAM-MPI: http://www.lam-mpi.org
 .. _OpenMP: http://en.wikipedia.org/wiki/OpenMP
 .. _CMake installation page: http://www.cmake.org/install/
+.. _Ubuntu toolchain ppa page: https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test
+.. _EPEL page: https://fedoraproject.org/wiki/EPEL
 .. _running CMake: http://www.cmake.org/runningcmake/
 .. _CMake environment variables: http://cmake.org/Wiki/CMake_Useful_Variables#Environment_Variables
 .. _FFTW: http://www.fftw.org
index a86c6cebd6306492d2fe00548329d4767d4c0c9c..ae313c1bfbf1d1340de416bd147c46d3a12cceb2 100644 (file)
@@ -4,7 +4,7 @@ Build system overview
 =====================
 
 The |Gromacs| build system uses CMake (version
-|GMX_CMAKE_MINIMUM_REQUIRED_VERSION| or newer is required) to generate the
+|CMAKE_MINIMUM_REQUIRED_VERSION| or newer is required) to generate the
 actual build system for the build tool choosen by the user.  See CMake
 documentation for general introduction to CMake and how to use it.  This
 documentation focuses on how the |Gromacs| build system is organized and
index d4d3a9edd8b216fb0e464a3c72eef47b7c1255c7..3fc98799c775d3692e71b8ba5caa48251923c877 100644 (file)
@@ -10,8 +10,9 @@ these standards fully.
 
 * MSVC supports only a subset of C99 and work-arounds are required in those cases.
 * Before 7.0 (partial support in 6.5) CUDA didn't support C++11. Therefore any
-  header file which is needed (or likly will be nedded) by CUDA should not use C++11.
-* C++11 features which are not widely implemented (including in MSVC 2015 and GCC 4.6)
-  should not be used.
+  header file which is needed (or likely will be nedded) by CUDA should not use C++11.
+* We should be able to use virtually all C++ features outside of the header files
+  required by CUDA code (and OpenCL kernels), since we have gradually moved to
+  compilers that have full support for C++11.
 
 .. TODO: Copy important points from http://www.gromacs.org/index.php?title=Developer_Zone/Programming_Guide/Allowed_C%2B%2B_Features
index f3f8b77a7b6f96aa2e860cecf1c9bd71378de3d0..92ac3371085610774d5b04319d3f9ded0058a34c 100755 (executable)
@@ -105,7 +105,8 @@ class GroupedSorter(object):
             'time.h']
     _std_c_cpp_headers = ['c' + x[:-2] for x in _std_c_headers]
     _std_cpp_headers = ['algorithm', 'array', 'chrono', 'deque', 'exception', 'fstream',
-            'functional', 'iomanip', 'ios', 'iosfwd', 'iostream', 'istream', 'iterator',
+            'functional', 'initializer_list', 'iomanip', 'ios', 'iosfwd',
+            'iostream', 'istream', 'iterator',
             'limits', 'list', 'map', 'memory', 'new', 'numeric', 'ostream', 'random',
             'regex', 'set', 'sstream', 'stdexcept', 'streambuf', 'string', 'strstream',
             'thread', 'tuple', 'type_traits', 'typeindex', 'typeinfo', 'vector', 'utility']
diff --git a/docs/doxygen/lib/logging.md b/docs/doxygen/lib/logging.md
new file mode 100644 (file)
index 0000000..7cdc697
--- /dev/null
@@ -0,0 +1,53 @@
+Logging {#page_logging}
+=======
+
+Currently, mdrun is using a combination of direct C-style I/O into `fplog` and
+`stderr`, and the facilities described here.  However, more and more should get
+moved to this interface in the future.
+
+The parts that make up the logging system are shown below.
+
+\dot
+    digraph logging_overview {
+        builder [label="LoggerBuilder", URL="\ref gmx::LoggerBuilder"]
+        owner [label="LoggerOwner", URL="\ref gmx::LoggerOwner"]
+        logger [label="MDLogger", URL="\ref gmx::MDLogger"]
+        target [label="ILogTarget", URL="\ref gmx::ILogTarget"]
+        user [label="using code"]
+
+        builder -> owner [label="builds"]
+        owner -> logger
+        owner -> target [label="owns"]
+        logger -> target [label="references"]
+        user -> builder [label="set logging targets"]
+        user -> logger [label="write with\nGMX_LOG()"]
+    }
+\enddot
+
+To initialize the logging system, the using code creates an instance of
+gmx::LoggerBuilder, and sets the desired logging targets with provided methods.
+Once all targets have been initialized, the code calls
+gmx::LoggerBuilder::build() and gets a gmx::LoggerOwner, which is responsible
+of managing the memory allocated for the logger.
+
+To log information, the using code uses an gmx::MDLogger returned by
+gmx::LoggerOwner::logger() with the ::GMX_LOG macro.  Code that writes to the
+log only needs to know of this class (and helper classes used to implement the
+macro), which is a relatively simple container for references to the logging
+targets.  If there is no log target that would consume the information written
+with ::GMX_LOG, the whole statement evaluates to a conditional that reads the
+log target from a member variable and compares it against `nullptr`.  All the
+code that formats the output is skipped in this case.
+
+Currently the implementation is geared to making ::GMX_LOG behavior stable, and
+to be relatively extensible.  However, using any other approach than ::GMX_LOG
+for writing to the log should first think about how the API could be best
+organized for that.
+
+All information written to the log is composed of _log entries_.  Each
+::GMX_LOG statement writes a single log entry, meaning that newlines are
+automatically added.
+
+The logging methods are not thread-safe, so it is the responsibility of the
+calling code to only use them from a single thread or otherwise synchronize
+access.
index 0177a2717a5d932811a452cf69ff672b5889d3fe..82dd8d040c4e8a46d6dc962bc05ea1bec3186bf7 100644 (file)
@@ -60,6 +60,8 @@ give an overview of some of the topics that are documented:
 \if libapi
  - \subpage page_wrapperbinary <br/>
    Provides an overview of how the `gmx` wrapper binary is implemented.
+ - \subpage page_logging <br/>
+   Documentation for logging and status output (for now, within mdrun).
  - \subpage page_simd <br/>
    Documentation about the new SIMD module that makes it possible to write
    highly accelerated CPU code that is still portable.
index 7737fec08435d24b57df6ac9e22c7e09d0f0ed16..ffa7047de32472cfb70c0ea714e86c0cb9de51ea 100644 (file)
@@ -15,7 +15,7 @@ These instructions pertain to building |Gromacs|
 Quick and dirty installation
 ----------------------------
 1. Get the latest version of your C and C++ compilers.
-2. Check that you have CMake version |GMX_CMAKE_MINIMUM_REQUIRED_VERSION| or later.
+2. Check that you have CMake version |CMAKE_MINIMUM_REQUIRED_VERSION| or later.
 3. Get and unpack the latest version of the |Gromacs| tarball.
 4. Make a separate build directory and change to it. 
 5. Run ``cmake`` with the path to the source as an argument
@@ -91,10 +91,11 @@ compiler. We recommend gcc, because it is free, widely available and
 frequently provides the best performance.
 
 You should strive to use the most recent version of your
-compiler. Minimum supported compiler versions are
-* GNU (gcc) 4.6
-* Intel (icc) 14
-* LLVM (clang) 3.4
+compiler. Since we require full C++11 support the minimum supported
+compiler versions are
+* GNU (gcc) 4.8.1
+* Intel (icc) 15.0
+* LLVM (clang) 3.3
 * Microsoft (MSVC) 2015
 Other compilers may work (Cray, Pathscale, older clang) but do
 not offer competitive performance. We recommend against PGI because
@@ -111,7 +112,7 @@ other compilers, read on.
 
 On Linux, both the Intel and clang compiler use the libstdc++ which
 comes with gcc as the default C++ library. For |Gromacs|, we require
-the compiler to support libstc++ version 4.6.1 or higher. To select a
+the compiler to support libstc++ version 4.8.1 or higher. To select a
 particular libstdc++ library, use:
 
 * For Intel: ``-DGMX_STDLIB_CXX_FLAGS=-gcc-name=/path/to/gcc/binary``
@@ -140,6 +141,11 @@ For all non-x86 platforms, your best option is typically to use gcc or
 the vendor's default or recommended compiler, and check for
 specialized information below.
 
+For updated versions of gcc to add to your Linux OS, see
+
+* Ubuntu: `Ubuntu toolchain ppa page`_
+* RHEL/CentOS: `EPEL page`_ or the RedHat Developer Toolset
+
 Compiling with parallelization options
 --------------------------------------
 
@@ -151,8 +157,10 @@ generally built into your compiler and detected automatically.
 GPU support
 ^^^^^^^^^^^
 |Gromacs| has excellent support for NVIDIA GPUs supported via CUDA.
-NVIDIA's CUDA_ version |REQUIRED_CUDA_VERSION| software development kit is required,
-and the latest version is strongly encouraged. NVIDIA GPUs with at
+On Linux with gcc, NVIDIA's CUDA_ version |REQUIRED_CUDA_VERSION|
+software development kit is required, and the latest
+version is strongly encouraged. Using Intel or Microsoft compilers
+requires version 7.0 and 8.0, respectively. NVIDIA GPUs with at
 least NVIDIA compute capability |REQUIRED_CUDA_COMPUTE_CAPABILITY| are
 required, e.g. Fermi, Kepler, Maxwell or Pascal cards. You are strongly recommended to
 get the latest CUDA version and driver supported by your hardware, but
@@ -209,7 +217,7 @@ CMake
 -----
 
 |Gromacs| builds with the CMake build system, requiring at least
-version |GMX_CMAKE_MINIMUM_REQUIRED_VERSION|. You can check whether
+version |CMAKE_MINIMUM_REQUIRED_VERSION|. You can check whether
 CMake is installed, and what version it is, with ``cmake
 --version``. If you need to install CMake, then first check whether
 your platform's package management system provides a suitable version,
@@ -1126,9 +1134,9 @@ much everywhere, it is important that we tell you where we really know
 it works because we have tested it. We do test on Linux, Windows, and
 Mac with a range of compilers and libraries for a range of our
 configuration options. Every commit in our git source code repository
-is currently tested on x86 with gcc versions ranging from 4.6 through
-5.2, and versions 16 of the Intel compiler as well as Clang
-version 3.4 through 3.8. For this, we use a variety of GNU/Linux
+is currently tested on x86 with a number of gcc versions ranging from 4.8.1
+through 6.1, versions 16 of the Intel compiler, and Clang
+versions 3.4 through 3.8. For this, we use a variety of GNU/Linux
 flavors and versions as well as recent versions of Windows. Under
 Windows, we test both MSVC 2015 and version 16 of the Intel compiler.
 For details, you can
index c754382c77b980f7b04224190c7e0f1c6734f0c9..59d8650e80831f40a7389ea14c71ff4000a93ffe 100644 (file)
@@ -1653,7 +1653,43 @@ virtual sites. The energy of the shell particle is then minimized at
 each time step in order to remain on the Born-Oppenheimer surface.
 
 \subsection{Simple polarization}
-This is merely a harmonic potential with equilibrium distance 0.
+This is implemented as a harmonic potential with equilibrium distance
+0.
+The input given in the topology file is the polarizability $\alpha$ (in
+{\gromacs} units) as follows:
+\begin{verbatim}
+[ polarization ]
+; Atom i  j  type  alpha
+1         2  1     0.001
+\end{verbatim}
+in this case the polarizability volume is 0.001 nm$^3$ (or 1
+{\AA$^3$}). In order to compute the harmonic force constant $k_{cs}$
+(where $cs$ stands for core-shell), the
+following is used~\cite{Maaren2001a}:
+\begin{equation}
+k_{cs} ~=~ \frac{q_s^2}{\alpha}
+\end{equation}
+where $q_s$ is the charge on the shell particle.
+
+\subsection{Anharmonic polarization}
+For the development of the Drude force field by Roux and McKerell~\cite{Lopes2013a}
+it was found
+that some particles can overpolarize and this was fixed by introducing
+a higher order term in the polarization energy:
+\begin{eqnarray}
+V_{pol} ~=& \frac{k_{cs}}{2} r_{cs}^2 & r_{cs} \le \delta \\
+            =& \frac{k_{cs}}{2} r_{cs}^2 + k_{hyp} (r_{cs}-\delta)^4 & r_{cs} > \delta
+\end{eqnarray}
+where $\delta$ is a user-defined constant that is set to 0.02 nm for
+anions in the Drude force field~\cite{HYu2010}. Since this original introduction it
+has also been used in other atom types~\cite{Lopes2013a}.
+\begin{verbatim}
+[ polarization ]
+;Atom i j    type   alpha (nm^3)    delta  khyp
+1       2       2       0.001786     0.02  16.736e8
+\end{verbatim}
+The above force constant $k_{hyp}$ corresponds to 4$\cdot$10$^8$
+kcal/mol/nm$^4$, hence the strange number.
 
 \subsection{Water polarization}
 A special potential for water that allows anisotropic polarization of
index b6d97cc0b7ea9305cd09f94464f953ec0651bc66..cc94429cf0a8f61f1ccdb74fcddd16bfa49f818c 100644 (file)
@@ -6487,6 +6487,18 @@ pages = {2044--2053}
   pages =        "294--305",
 }
 
+@ARTICLE{HYu2010,
+  author = {Yu, Haibo and Whitfield, Troy W and Harder, Edward and Lamoureux,
+       Guillaume and Vorobyov, Igor and Anisimov, Victor M and {MacKerell,
+       Jr.}, Alexander D and Roux, Benoit},
+  title = {{Simulating Monovalent and Divalent Ions in Aqueous Solution Using
+       a Drude Polarizable Force Field}},
+  journal = BTjctc,
+  year = {2010},
+  volume = {6},
+  pages = {774--786},
+}
+
 @Article{Zettlmeissl83,
   author =       "Gerd Zettlmeissl and Rainer Rudolph and Rainer
                  Jaenicke",
@@ -8756,3 +8768,12 @@ doi = "http://dx.doi.org/10.1016/j.softx.2015.06.001"
        volume = {31},
        pages = {2169--2174}
 }
+
+@Article{Lopes2013a,
+  author =       {Lopes, Pedro E. M. and Huang, Jing and Shim, Jihyun and Luo, Yun and Li, Hui and Roux, Benoit and MacKerell, Alexander D., Jr.},
+  title =        {Polarizable Force Field for Peptides and Proteins Based on the Classical Drude Oscillator},
+  journal =      {J. Chem. Theory Comput},
+  year =         2013,
+  volume =    9,
+  pages =     {5430-5449}}
+
index 11829495889c933dc8b9fa05e0f3af8ff8791f41..f120b01add4bf0da3db4321cc72aeafd86a88513 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+# Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, 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.
@@ -55,15 +55,7 @@ if (BUILD_TESTING)
         add_subdirectory(external/gmock-1.7.0)
     endif()
     include(testutils/TestMacros.cmake)
-    if (GMX_BUILD_UNITTESTS)
-        add_subdirectory(testutils)
-    else()
-        add_custom_target(unittests-notice
-            ${CMAKE_COMMAND} -E echo "NOTE: Unit tests have not been run. You need to set GMX_BUILD_UNITTESTS=ON if you want to build and run them."
-            DEPENDS run-ctest
-            COMMENT "Unit tests disabled" VERBATIM)
-        add_dependencies(check unittests-notice)
-    endif()
+    add_subdirectory(testutils)
 endif()
 
 add_subdirectory(gromacs)
index c7bd5fb3dab936c13a5ce09708c54fcb0572acc3..0885ec38c4166b15509df1f4b0f98256a8a353f2 100644 (file)
@@ -74,9 +74,6 @@
 /** Define if we are building for Cygwin */
 #cmakedefine01 GMX_CYGWIN
 
-/* GCC bug in AVX maskload/maskstore arguments - worked around internally */
-#cmakedefine01 GMX_SIMD_X86_AVX_GCC_MASKLOAD_BUG
-
 /* SSE2 was selected for SIMD instruction set level */
 #cmakedefine01 GMX_SIMD_X86_SSE2
 
index 35acd0a7e6717c378ac0b3406624443181b51c58..fa220cf29a26299d2be310491c336a13ec0f1e1e 100644 (file)
@@ -65,6 +65,11 @@ find_package(Threads)
 set(PTHREADS_LIBRARIES)
 if (CMAKE_USE_PTHREADS_INIT)
     set(PTHREADS_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
+    list(APPEND GMOCK_COMPILE_DEFINITIONS "GTEST_HAS_PTHREAD=1")
+    set(GTEST_IS_THREADSAFE 1)
+else()
+    list(APPEND GMOCK_COMPILE_DEFINITIONS "GTEST_HAS_PTHREAD=0")
+    set(GTEST_IS_THREADSAFE 0)
 endif()
 
 # Skip variadic implementation of matchers if using GCC < 4.7 due to
@@ -101,3 +106,4 @@ set(GMOCK_INCLUDE_DIRS ${GMOCK_INCLUDE_DIRS} PARENT_SCOPE)
 set(GTEST_INCLUDE_DIRS ${GTEST_INCLUDE_DIRS} PARENT_SCOPE)
 set(GMOCK_COMPILE_DEFINITIONS ${GMOCK_COMPILE_DEFINITIONS} PARENT_SCOPE)
 set(GMOCK_COMPILE_FLAGS "${GMOCK_COMPILE_FLAGS}" PARENT_SCOPE)
+set(GTEST_IS_THREADSAFE "${GTEST_IS_THREADSAFE}" PARENT_SCOPE)
index 38af58fe2426c630e14eed18fee47f2ff28a7109..5e9c472806b05ce0f50f26b3a44f6e0e39527402 100644 (file)
@@ -2,7 +2,7 @@
    This source code file is part of thread_mpi.
    Written by Sander Pronk, Erik Lindahl, and possibly others.
 
-   Copyright (c) 2009, Sander Pronk, Erik Lindahl.
+   Copyright (c) 2009,2016, Sander Pronk, Erik Lindahl.
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
@@ -884,7 +884,7 @@ int tMPI_Type_commit(tMPI_Datatype *datatype);
     \param[in]  comm        The shared communicator.
     \return  TMPI_SUCCESS on success, TMPI_FAILURE on failure.  */
 TMPI_EXPORT
-int tMPI_Send(void* buf, int count, tMPI_Datatype datatype, int dest,
+int tMPI_Send(const void* buf, int count, tMPI_Datatype datatype, int dest,
               int tag, tMPI_Comm comm);
 
 /** Receive message; blocks until buf is filled.
@@ -919,7 +919,7 @@ int tMPI_Recv(void* buf, int count, tMPI_Datatype datatype, int source,
     \param[out] status      The received message status.
     \return  TMPI_SUCCESS on success, TMPI_FAILURE on failure.  */
 TMPI_EXPORT
-int tMPI_Sendrecv(void *sendbuf, int sendcount, tMPI_Datatype sendtype,
+int tMPI_Sendrecv(const void *sendbuf, int sendcount, tMPI_Datatype sendtype,
                   int dest, int sendtag, void *recvbuf, int recvcount,
                   tMPI_Datatype recvtype, int source, int recvtag,
                   tMPI_Comm comm, tMPI_Status *status);
@@ -945,7 +945,7 @@ int tMPI_Sendrecv(void *sendbuf, int sendcount, tMPI_Datatype sendtype,
                             tMPI_Test, etc.
     \return  TMPI_SUCCESS on success, TMPI_FAILURE on failure.  */
 TMPI_EXPORT
-int tMPI_Isend(void* buf, int count, tMPI_Datatype datatype, int dest,
+int tMPI_Isend(const void* buf, int count, tMPI_Datatype datatype, int dest,
                int tag, tMPI_Comm comm, tMPI_Request *request);
 
 /** Initiate receiving a message.
@@ -1164,7 +1164,7 @@ int tMPI_Bcast(void* buffer, int count, tMPI_Datatype datatype, int root,
 
     \return  TMPI_SUCCESS on success, TMPI_FAILURE on failure.  */
 TMPI_EXPORT
-int tMPI_Gather(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
+int tMPI_Gather(const void* sendbuf, int sendcount, tMPI_Datatype sendtype,
                 void* recvbuf, int recvcount, tMPI_Datatype recvtype, int root,
                 tMPI_Comm comm);
 
@@ -1189,7 +1189,7 @@ int tMPI_Gather(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
 
     \return  TMPI_SUCCESS on success, TMPI_FAILURE on failure.  */
 TMPI_EXPORT
-int tMPI_Gatherv(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
+int tMPI_Gatherv(const void* sendbuf, int sendcount, tMPI_Datatype sendtype,
                  void* recvbuf, int *recvcounts, int *displs,
                  tMPI_Datatype recvtype, int root, tMPI_Comm comm);
 
@@ -1212,7 +1212,7 @@ int tMPI_Gatherv(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
 
     \return  TMPI_SUCCESS on success, TMPI_FAILURE on failure.  */
 TMPI_EXPORT
-int tMPI_Scatter(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
+int tMPI_Scatter(const void* sendbuf, int sendcount, tMPI_Datatype sendtype,
                  void* recvbuf, int recvcount, tMPI_Datatype recvtype, int root,
                  tMPI_Comm comm);
 
@@ -1237,7 +1237,7 @@ int tMPI_Scatter(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
 
     \return  TMPI_SUCCESS on success, TMPI_FAILURE on failure.  */
 TMPI_EXPORT
-int tMPI_Scatterv(void* sendbuf, int *sendcounts, int *displs,
+int tMPI_Scatterv(const void* sendbuf, int *sendcounts, int *displs,
                   tMPI_Datatype sendtype, void* recvbuf, int recvcount,
                   tMPI_Datatype recvtype, int root, tMPI_Comm comm);
 
index 54e91bf69b64430ad336ed53cd82d0eba9b529c8..ca928a197aa1c91665616cab49f36ce1e2778255 100644 (file)
@@ -2,7 +2,7 @@
    This source code file is part of thread_mpi.
    Written by Sander Pronk, Erik Lindahl, and possibly others.
 
-   Copyright (c) 2009, Sander Pronk, Erik Lindahl.
+   Copyright (c) 2009,2016, Sander Pronk, Erik Lindahl.
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
@@ -58,7 +58,7 @@
 #include "collective.h"
 
 
-int tMPI_Gather(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
+int tMPI_Gather(const void* sendbuf, int sendcount, tMPI_Datatype sendtype,
                 void* recvbuf, int recvcount, tMPI_Datatype recvtype,
                 int root, tMPI_Comm comm)
 {
@@ -96,7 +96,7 @@ int tMPI_Gather(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
             tMPI_Coll_root_xfer(comm, sendtype, recvtype,
                                 sendtype->size*sendcount,
                                 recvtype->size*recvcount,
-                                sendbuf,
+                                (void*)sendbuf,
                                 (char*)recvbuf+myrank*recvcount*recvtype->size,
                                 &ret);
         }
@@ -146,7 +146,7 @@ int tMPI_Gather(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
 
         /* first set up the data just to root. */
         ret = tMPI_Post_multi(cev, myrank, 0, TMPI_GATHER_TAG, sendtype,
-                              sendcount*sendtype->size, sendbuf, 1, synct, root);
+                              sendcount*sendtype->size, (void*)sendbuf, 1, synct, root);
         if (ret != TMPI_SUCCESS)
         {
             return ret;
@@ -165,7 +165,7 @@ int tMPI_Gather(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
 
 
 
-int tMPI_Gatherv(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
+int tMPI_Gatherv(const void* sendbuf, int sendcount, tMPI_Datatype sendtype,
                  void* recvbuf, int *recvcounts, int *displs,
                  tMPI_Datatype recvtype, int root, tMPI_Comm comm)
 {
@@ -203,7 +203,7 @@ int tMPI_Gatherv(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
             tMPI_Coll_root_xfer(comm, sendtype, recvtype,
                                 sendtype->size*sendcount,
                                 recvtype->size*recvcounts[myrank],
-                                sendbuf,
+                                (void*)sendbuf,
                                 (char*)recvbuf+displs[myrank]*recvtype->size,
                                 &ret);
         }
@@ -252,7 +252,7 @@ int tMPI_Gatherv(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
 
         /* first set up the data just to root. */
         ret = tMPI_Post_multi(cev, myrank, 0, TMPI_GATHERV_TAG, sendtype,
-                              sendcount*sendtype->size, sendbuf, 1, synct, root);
+                              sendcount*sendtype->size, (void*)sendbuf, 1, synct, root);
         if (ret != TMPI_SUCCESS)
         {
             return ret;
index 3d0379cac7fc6b328dd2f930ce69ef747d9e473a..d3a2dcad7e91633690595747c0214b6d830471a3 100644 (file)
@@ -2,7 +2,7 @@
    This source code file is part of thread_mpi.
    Written by Sander Pronk, Erik Lindahl, and possibly others.
 
-   Copyright (c) 2009, Sander Pronk, Erik Lindahl.
+   Copyright (c) 2009,2016, Sander Pronk, Erik Lindahl.
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
@@ -61,7 +61,7 @@
 
 /* point-to-point communication exported functions */
 
-int tMPI_Send(void* buf, int count, tMPI_Datatype datatype, int dest,
+int tMPI_Send(const void* buf, int count, tMPI_Datatype datatype, int dest,
               int tag, tMPI_Comm comm)
 {
     struct envelope    *sev;
@@ -86,7 +86,7 @@ int tMPI_Send(void* buf, int count, tMPI_Datatype datatype, int dest,
         return tMPI_Error(comm, TMPI_ERR_SEND_DEST);
     }
 
-    sev = tMPI_Post_send(cur, comm, send_dst, buf, count, datatype, tag, FALSE);
+    sev = tMPI_Post_send(cur, comm, send_dst, (void*)buf, count, datatype, tag, FALSE);
     if (sev == NULL)
     {
         return TMPI_ERR_ENVELOPES;
@@ -152,7 +152,7 @@ int tMPI_Recv(void* buf, int count, tMPI_Datatype datatype, int source,
 
 
 
-int tMPI_Sendrecv(void *sendbuf, int sendcount, tMPI_Datatype sendtype,
+int tMPI_Sendrecv(const void *sendbuf, int sendcount, tMPI_Datatype sendtype,
                   int dest, int sendtag, void *recvbuf, int recvcount,
                   tMPI_Datatype recvtype, int source, int recvtag,
                   tMPI_Comm comm, tMPI_Status *status)
@@ -191,7 +191,7 @@ int tMPI_Sendrecv(void *sendbuf, int sendcount, tMPI_Datatype sendtype,
     }
 
     /* we first prepare to send */
-    sev = tMPI_Post_send(cur, comm, send_dst, sendbuf, sendcount,
+    sev = tMPI_Post_send(cur, comm, send_dst, (void*)sendbuf, sendcount,
                          sendtype, sendtag, FALSE);
     if (sev == NULL)
     {
@@ -244,7 +244,7 @@ int tMPI_Sendrecv(void *sendbuf, int sendcount, tMPI_Datatype sendtype,
 
 /* async */
 
-int tMPI_Isend(void* buf, int count, tMPI_Datatype datatype, int dest,
+int tMPI_Isend(const void* buf, int count, tMPI_Datatype datatype, int dest,
                int tag, tMPI_Comm comm, tMPI_Request *request)
 {
     struct tmpi_thread *cur = tMPI_Get_current();
@@ -271,7 +271,7 @@ int tMPI_Isend(void* buf, int count, tMPI_Datatype datatype, int dest,
         tMPI_Return_req(rql, rq);
         return tMPI_Error(comm, TMPI_ERR_SEND_DEST);
     }
-    ev = tMPI_Post_send(cur, comm, send_dst, buf, count, datatype, tag, TRUE);
+    ev = tMPI_Post_send(cur, comm, send_dst, (void*)buf, count, datatype, tag, TRUE);
     if (ev == NULL)
     {
         return TMPI_ERR_ENVELOPES;
index 807f85a3959255e769b1bd306cf59c7dbace76aa..03117a34b977c75529c8fb0216b105ba791e65bf 100644 (file)
@@ -2,7 +2,7 @@
    This source code file is part of thread_mpi.
    Written by Sander Pronk, Erik Lindahl, and possibly others.
 
-   Copyright (c) 2009, Sander Pronk, Erik Lindahl.
+   Copyright (c) 2009,2016, Sander Pronk, Erik Lindahl.
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
@@ -59,7 +59,7 @@
 
 
 
-int tMPI_Scatter(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
+int tMPI_Scatter(const void* sendbuf, int sendcount, tMPI_Datatype sendtype,
                  void* recvbuf, int recvcount, tMPI_Datatype recvtype,
                  int root, tMPI_Comm comm)
 {
@@ -195,7 +195,7 @@ int tMPI_Scatter(void* sendbuf, int sendcount, tMPI_Datatype sendtype,
 
 
 
-int tMPI_Scatterv(void* sendbuf, int *sendcounts, int *displs,
+int tMPI_Scatterv(const void* sendbuf, int *sendcounts, int *displs,
                   tMPI_Datatype sendtype, void* recvbuf, int recvcount,
                   tMPI_Datatype recvtype, int root, tMPI_Comm comm)
 {
index 5a7432cd8289df56f68625fa951699dae6e8287c..8fbd77170fb41b1b00ac9cf20f539e7f40fb775b 100644 (file)
@@ -22,9 +22,9 @@ test_big_endian(TNG_INTEGER_BIG_ENDIAN)
 include(CheckIncludeFile)
 check_include_file(inttypes.h TNG_HAVE_INTTYPES_H)
 
-macro(TNG_GET_SOURCE_LIST TNG_SOURCELIST TNG_COMPILEDEFS)
-    include_directories(BEFORE ${TNG_ROOT_SOURCE_DIR}/include)
-    include_directories(BEFORE ${TNG_ROOT_BINARY_DIR}/include)
+# TODO propagate changes involving TNG_INCLUDE_DIRS to TNG repo
+macro(TNG_GET_SOURCE_LIST TNG_SOURCELIST TNG_COMPILEDEFS TNG_INCLUDE_DIRS)
+    set(${TNG_INCLUDE_DIRS} ${TNG_ROOT_SOURCE_DIR}/include ${TNG_ROOT_BINARY_DIR}/include)
     set(_tng_compression_sources bwlzh.c bwt.c coder.c dict.c fixpoint.c huffman.c huffmem.c lz77.c merge_sort.c mtf.c rle.c tng_compress.c vals16.c warnmalloc.c widemuldiv.c xtc2.c xtc3.c)
     set(_tng_io_sources tng_io.c md5.c)
     set(${TNG_SOURCELIST})
index 87c10be8be43ef8f6fdda77ec6536a176f62711f..5c43e6082f424eca1d5a43c2e4e2d5c4f9eb2fc4 100644 (file)
@@ -27,7 +27,9 @@ include(CheckIncludeFile)
 check_include_file(inttypes.h   HAVE_INTTYPES_H)
 
 include(BuildTNG.cmake)
-tng_get_source_list(TNG_SOURCES TNG_COMPILE_DEFS)
+# TODO propagate changes involving TNG_INCLUDE_DIRS to TNG repo
+tng_get_source_list(TNG_SOURCES TNG_COMPILE_DEFS TNG_INCLUDE_DIRS)
+include_directories(BEFORE "${TNG_INCLUDE_DIRS}")
 
 tng_set_source_properties(WITH_ZLIB ${ZLIB_FOUND})
 
index f9e4d8dbb3919b8d5be36f2d2b9fb3e7afeffa30..4eb0a4afafc7c23c32a9c77977a80d5e23ecbf06 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, 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.
@@ -302,7 +302,7 @@ AnalysisDataModuleManager::addModule(AbstractAnalysisData      *data,
     {
         impl_->bAllowMissing_ = false;
     }
-    impl_->modules_.push_back(Impl::ModuleInfo(module));
+    impl_->modules_.emplace_back(module);
 }
 
 void
index 41ffc5f35c233263b5069c704949ac2e5147b585..8eb79be9884a2b9a074db12022a18ee66b5586c0 100644 (file)
@@ -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
  * 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.
@@ -574,8 +574,7 @@ AnalysisDataStorageFrameData::AnalysisDataStorageFrameData(
         for (int i = 0; i < baseData().dataSetCount(); ++i)
         {
             int columnCount = baseData().columnCount(i);
-            pointSets_.push_back(
-                    AnalysisDataPointSetInfo(offset, columnCount, i, 0));
+            pointSets_.emplace_back(offset, columnCount, i, 0);
             offset += columnCount;
         }
     }
@@ -625,9 +624,8 @@ AnalysisDataStorageFrameData::addPointSet(int dataSetIndex, int firstColumn,
     }
     else if (storageImpl().needStorage())
     {
-        pointSets_.push_back(
-                AnalysisDataPointSetInfo(values_.size(), valueCount,
-                                         dataSetIndex, firstColumn));
+        pointSets_.emplace_back(values_.size(), valueCount,
+                                dataSetIndex, firstColumn);
         std::copy(begin, end, std::back_inserter(values_));
     }
 }
index 9b9b2f468d142476098947a1fc85a9f169308264..586357097dd9571340d7c76736bc03e94ce4df97 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2016, 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.
@@ -280,7 +280,7 @@ AnalysisDataDisplacementModule::frameFinished(const AnalysisDataFrameHeader & /*
             i += _impl->max_store;
         }
         _impl->currValues_.clear();
-        _impl->currValues_.push_back(AnalysisDataValue(step * _impl->dt));
+        _impl->currValues_.emplace_back(step * _impl->dt);
         int k = 1;
         for (int j = 0; j < _impl->nmax; j += _impl->ndim, ++k)
         {
@@ -292,7 +292,7 @@ AnalysisDataDisplacementModule::frameFinished(const AnalysisDataFrameHeader & /*
                     - _impl->oldval[i + j + d];
                 dist2 += displ * displ;
             }
-            _impl->currValues_.push_back(AnalysisDataValue(dist2));
+            _impl->currValues_.emplace_back(dist2);
         }
         moduleManager().notifyPointsAdd(AnalysisDataPointSetRef(header, _impl->currValues_));
     }
index 1c64c4d5172f489a8f3fa0e7132cc4f3ac9e0a3a..9278d288c81c9c947fc73c368942fa9f31b4d2af 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -142,8 +142,8 @@ AnalysisDataLifetimeModule::dataStarted(AbstractAnalysisData *data)
     impl_->lifetimeHistograms_.reserve(data->dataSetCount());
     for (int i = 0; i < data->dataSetCount(); ++i)
     {
-        impl_->currentLifetimes_.push_back(std::vector<int>(data->columnCount(i), 0));
-        impl_->lifetimeHistograms_.push_back(std::deque<int>());
+        impl_->currentLifetimes_.emplace_back(data->columnCount(i), 0);
+        impl_->lifetimeHistograms_.emplace_back();
     }
 }
 
index e24160f28feec6d8e0342e26ed5d8a136acab2cc..10e14a9b656faad6af88e8b5c3a6dcebdef58533 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, 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.
@@ -282,7 +282,7 @@ AbstractPlotModule::setLegend(int nsets, const char * const *setname)
 void
 AbstractPlotModule::appendLegend(const char *setname)
 {
-    impl_->legend_.push_back(setname);
+    impl_->legend_.emplace_back(setname);
 }
 
 
index 28abff7f0c7b841c03ee9af80bf23a45f22e8c4d..5ac37f1921a7137e081104d2b01af5841226b52e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2011,2012,2013,2014,2015,2016, 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.
@@ -115,11 +115,11 @@ class AnalysisDataTestInputPointSet
         }
 
         //! Appends a value to this point set.
-        void addValue(real y) { values_.push_back(Value(y)); }
+        void addValue(real y) { values_.emplace_back(y); }
         //! Appends a value with an error estimate to this point set.
         void addValueWithError(real y, real error)
         {
-            values_.push_back(Value(y, error));
+            values_.emplace_back(y, error);
         }
 
     private:
index 054b5b3530ee4b2a37f7ff8b9907c7d07a9b9b17..0a2ceac2ec1e64441020e7ff76bb2caba326739e 100644 (file)
@@ -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
  * 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.
@@ -108,7 +108,7 @@ class RootHelpTopic : public AbstractCompositeHelpTopic
         {
             if (bExported)
             {
-                exportedTopics_.push_back(topic->name());
+                exportedTopics_.emplace_back(topic->name());
             }
             addSubTopic(std::move(topic));
         }
@@ -743,7 +743,7 @@ void HelpExportCompletion::exportModuleHelp(
         const std::string                 & /*tag*/,
         const std::string                 & /*displayName*/)
 {
-    modules_.push_back(module.name());
+    modules_.emplace_back(module.name());
     {
         CommandLineHelpContext context(&bashWriter_);
         // We use the display name to pass the name of the module to the
@@ -949,7 +949,7 @@ int CommandLineHelpModule::run(int argc, char *argv[])
 
     const char *const exportFormats[] = { "rst", "completion" };
     std::string       exportFormat;
-    Options           options(NULL, NULL);
+    Options           options;
     options.addOption(StringOption("export").store(&exportFormat)
                           .enumValue(exportFormats));
     CommandLineParser(&options).parse(&argc, argv);
index 275f70fb9d4fe1363b27ef483b1b46cbd413a384..1ecd452d7e5d7933d40297aaf268805f1178d129 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, 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.
@@ -136,7 +136,7 @@ class OptionsFilter : public OptionsVisitor
                             IOptionsFormatter         *formatter,
                             const Options             &options);
 
-        virtual void visitSubSection(const Options &section);
+        virtual void visitSection(const OptionSectionInfo &section);
         virtual void visitOption(const OptionInfo &option);
 
     private:
@@ -153,13 +153,13 @@ void OptionsFilter::formatSelected(FilterType                 type,
 {
     formatter_  = formatter;
     filterType_ = type;
-    visitSubSection(options);
+    visitSection(options.rootSection());
 }
 
-void OptionsFilter::visitSubSection(const Options &section)
+void OptionsFilter::visitSection(const OptionSectionInfo &section)
 {
     OptionsIterator iterator(section);
-    iterator.acceptSubSections(this);
+    iterator.acceptSections(this);
     iterator.acceptOptions(this);
 }
 
index 556fd878b55a8490995c1c57cc4354b7deb1a693..1eaf5bc99f54ca7d58e61471d9c63a65c4763633 100644 (file)
@@ -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
  * 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.
@@ -144,7 +144,7 @@ class CMainCommandLineModule : public ICommandLineModule
  */
 
 CommandLineCommonOptionsHolder::CommandLineCommonOptionsHolder()
-    : options_(NULL, NULL), bHelp_(false), bHidden_(false),
+    : bHelp_(false), bHidden_(false),
       bQuiet_(false), bVersion_(false), bCopyright_(true),
       niceLevel_(19), bNiceSet_(false), bBackup_(true), bFpexcept_(false),
       debugLevel_(0)
index ed87db95422c6780692fc6c42238c2367ba97836..b4d45d37556010611c2e8accdb319a7a28f08127 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016, 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.
@@ -154,7 +154,7 @@ void CommandLineOptionsModule::writeHelp(const CommandLineHelpContext &context)
         moduleGuard = factory_();
         module      = moduleGuard.get();
     }
-    Options                          options(name(), shortDescription());
+    Options                          options;
     OptionsBehaviorCollection        behaviors(&options);
     CommandLineOptionsModuleSettings settings(&behaviors);
     module->initOptions(&options, &settings);
@@ -166,7 +166,7 @@ void CommandLineOptionsModule::writeHelp(const CommandLineHelpContext &context)
 void CommandLineOptionsModule::parseOptions(int argc, char *argv[])
 {
     FileNameOptionManager fileoptManager;
-    Options               options(name_, description_);
+    Options               options;
 
     options.addManager(&fileoptManager);
 
index 8fd3da8f470efc9d4d7b8f477524192962d26afb..38052ac57c3deedc8b21a39d6991125b9c936fff 100644 (file)
@@ -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, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, 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.
@@ -344,7 +344,7 @@ void OptionsAdapter::filenmToOptions(Options *options, t_filenm *fnm)
         GMX_RELEASE_ASSERT(defType != efNR,
                            "File name option specifies an invalid extension");
     }
-    fileNameOptions_.push_back(FileNameData(fnm));
+    fileNameOptions_.emplace_back(fnm);
     FileNameData &data = fileNameOptions_.back();
     data.optionInfo = options->addOption(
                 FileNameOption(name).storeVector(&data.values)
@@ -361,7 +361,7 @@ void OptionsAdapter::pargsToOptions(Options *options, t_pargs *pa)
     const bool        bHidden = startsWith(pa->desc, "HIDDEN");
     const char *const name    = &pa->option[1];
     const char *const desc    = (bHidden ? &pa->desc[6] : pa->desc);
-    programArgs_.push_back(ProgramArgData(pa));
+    programArgs_.emplace_back(pa);
     ProgramArgData   &data = programArgs_.back();
     switch (pa->type)
     {
@@ -494,7 +494,7 @@ gmx_bool parse_common_args(int *argc, char *argv[], unsigned long Flags,
         bool                            bView         = false;
         int                             xvgFormat     = 0;
         gmx::OptionsAdapter             adapter(*argc, argv);
-        gmx::Options                    options(NULL, NULL);
+        gmx::Options                    options;
         gmx::OptionsBehaviorCollection  behaviors(&options);
         gmx::FileNameOptionManager      fileOptManager;
 
index be1cd70d97fcfa30844436087c35ef19e4c2cf11..88d64ab8c627d2060d5abbedaabc4e905ff21177 100644 (file)
@@ -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, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, 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.
@@ -56,6 +56,7 @@
 #include "gromacs/fileio/filetypes.h"
 #include "gromacs/options/basicoptions.h"
 #include "gromacs/options/filenameoption.h"
+#include "gromacs/options/options.h"
 #include "gromacs/options/optionsvisitor.h"
 #include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/exceptions.h"
@@ -74,10 +75,10 @@ class OptionsListWriter : public OptionsVisitor
     public:
         const std::string &optionList() const { return optionList_; }
 
-        virtual void visitSubSection(const Options &section)
+        virtual void visitSection(const OptionSectionInfo &section)
         {
             OptionsIterator iterator(section);
-            iterator.acceptSubSections(this);
+            iterator.acceptSections(this);
             iterator.acceptOptions(this);
         }
         virtual void visitOption(const OptionInfo &option)
@@ -109,10 +110,10 @@ class OptionCompletionWriter : public OptionsVisitor
     public:
         explicit OptionCompletionWriter(TextWriter *out) : out_(*out) {}
 
-        virtual void visitSubSection(const Options &section)
+        virtual void visitSection(const OptionSectionInfo &section)
         {
             OptionsIterator iterator(section);
-            iterator.acceptSubSections(this);
+            iterator.acceptSections(this);
             iterator.acceptOptions(this);
         }
         virtual void visitOption(const OptionInfo &option);
@@ -237,12 +238,12 @@ void ShellCompletionWriter::writeModuleCompletions(
     out.writeLine("COMPREPLY=()");
 
     OptionsListWriter listWriter;
-    listWriter.visitSubSection(options);
+    listWriter.visitSection(options.rootSection());
     out.writeLine(formatString("if (( $COMP_CWORD <= 1 )) || [[ $c == -* ]]; then COMPREPLY=( $(compgen -S ' '  -W $'%s' -- $c)); return 0; fi", listWriter.optionList().c_str()));
 
     out.writeLine("case \"$p\" in");
     OptionCompletionWriter optionWriter(&out);
-    optionWriter.visitSubSection(options);
+    optionWriter.visitSection(options.rootSection());
     out.writeLine("esac }");
 }
 
@@ -261,7 +262,7 @@ void ShellCompletionWriter::writeWrapperCompletions(
     impl_->file_->writeLine("if (( i == COMP_CWORD )); then");
     impl_->file_->writeLine("c=${COMP_WORDS[COMP_CWORD]}");
     OptionsListWriter lister;
-    lister.visitSubSection(options);
+    lister.visitSection(options.rootSection());
     std::string       completions(lister.optionList());
     for (ModuleNameList::const_iterator i = modules.begin();
          i != modules.end(); ++i)
index 2e9be1a9086bf9c5ab148b9939adc5c765cae608..c05cc559b84288c353640f9f8d690f04e69921ac 100644 (file)
@@ -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
 # 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.
@@ -60,11 +60,3 @@ gmx_add_unit_test(CommandLineUnitTests commandline-test
                   cmdlineprogramcontext.cpp
                   pargs.cpp
                   $<TARGET_OBJECTS:onlinehelp-test-shared>)
-
-if (CMAKE_CXX_COMPILER_ID MATCHES "XL")
-    # This suppression stops a very verbose cascade of messages about the
-    # mocks, which is probably a compiler issue.
-    #   1540-2924 (W) Cannot pass an argument of non-POD class type "const gmx::CommandLineHelpContext" through ellipsis.
-    set_property(SOURCE cmdlinehelpmodule.cpp cmdlinemodulemanager.cpp cmdlinemodulemanagertest.cpp
-                 PROPERTY COMPILE_FLAGS "-qsuppress=1540-2924")
-endif()
index ae34edf40f6dcae859d0dabda4cce221c2498558..84f70e7891cdbb82565e95f341fb5c33ad32fd07 100644 (file)
@@ -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
  * 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.
@@ -101,7 +101,7 @@ TEST_F(CommandLineHelpWriterTest, HandlesOptionTypes)
 {
     using namespace gmx;
 
-    Options options("test", "Short Description");
+    Options options;
     options.addOption(BooleanOption("bool").description("Boolean option")
                           .defaultValue(true));
     options.addOption(BooleanOption("hidden").description("Hidden option")
@@ -166,7 +166,7 @@ TEST_F(CommandLineHelpWriterTest, HandlesDefaultValuesFromVariables)
 {
     using namespace gmx;
 
-    Options options("test", "Short Description");
+    Options options;
 
     bool    bValue = true;
     options.addOption(BooleanOption("bool").description("Boolean option")
@@ -181,7 +181,7 @@ TEST_F(CommandLineHelpWriterTest, HandlesDefaultValuesFromVariables)
                           .store(iavalue).valueCount(2));
 
     std::vector<std::string> svalues;
-    svalues.push_back("foo");
+    svalues.emplace_back("foo");
     options.addOption(StringOption("str").description("String option")
                           .storeVector(&svalues).multiValue());
 
@@ -204,7 +204,7 @@ TEST_F(CommandLineHelpWriterTest, HandlesLongFileOptions)
     using gmx::eftGenericData;
     using gmx::eftTrajectory;
 
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     options.addOption(FileNameOption("f")
                           .description("File name option with a long value")
                           .filetype(eftTrajectory).inputFile().required()
@@ -240,7 +240,7 @@ TEST_F(CommandLineHelpWriterTest, HandlesLongOptions)
     using gmx::DoubleOption;
     using gmx::StringOption;
 
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     options.addOption(BooleanOption("longboolean")
                           .description("Boolean option with a long name")
                           .defaultValue(true));
@@ -248,8 +248,8 @@ TEST_F(CommandLineHelpWriterTest, HandlesLongOptions)
     options.addOption(DoubleOption("dvec").description("Double vector option")
                           .vector().store(dblvec));
     std::vector<std::string> values;
-    values.push_back("A very long string value that overflows even the description column");
-    values.push_back("Another very long string value that overflows even the description column");
+    values.emplace_back("A very long string value that overflows even the description column");
+    values.emplace_back("Another very long string value that overflows even the description column");
     options.addOption(StringOption("string")
                           .description("String option with very long values (may "
                                        "be less relevant with selections having "
@@ -270,7 +270,7 @@ TEST_F(CommandLineHelpWriterTest, HandlesSelectionOptions)
     using gmx::SelectionFileOption;
     using gmx::SelectionOption;
 
-    gmx::Options                options(NULL, NULL);
+    gmx::Options                options;
     gmx::SelectionCollection    selections;
     gmx::SelectionOptionManager manager(&selections);
     options.addManager(&manager);
@@ -298,7 +298,7 @@ TEST_F(CommandLineHelpWriterTest, HandlesOptionGroups)
 {
     using gmx::IntegerOption;
 
-    gmx::Options            options(NULL, NULL);
+    gmx::Options            options;
     gmx::IOptionsContainer &group1 = options.addGroup();
     gmx::IOptionsContainer &group2 = options.addGroup();
     group2.addOption(IntegerOption("sub2").description("Option in group 2"));
@@ -321,7 +321,7 @@ TEST_F(CommandLineHelpWriterTest, HandlesHelpText)
     };
     using gmx::IntegerOption;
 
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     options.addOption(IntegerOption("int").description("Integer option")
                           .defaultValue(2));
 
index 719e69d34f71917e67a1c1a2198387b44eee4e99..d9f973d0117eeace823313c28981a5d8f23a0a51 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2016, 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.
@@ -76,8 +76,7 @@ class CommandLineParserTest : public ::testing::Test
 };
 
 CommandLineParserTest::CommandLineParserTest()
-    : options_(NULL, NULL), parser_(&options_),
-      flag_(false), ivalue1p_(0), ivalue12_(0)
+    : parser_(&options_), flag_(false), ivalue1p_(0), ivalue12_(0)
 {
     using gmx::BooleanOption;
     using gmx::IntegerOption;
index 376908bdb03ab9ea391d7bf987fe487980f9d628..4308ac80e7ba754176b845939787b4cfd0e38b14 100644 (file)
@@ -146,7 +146,7 @@ TEST_F(CommandLineProgramContextTest, FindsBinaryFromPath)
 TEST_F(CommandLineProgramContextTest, FindsBinaryFromCurrentDirectory)
 {
     env_->workingDirectory_ = Path::join(env_->getWorkingDirectory(), "bin");
-    env_->path_.push_back("");
+    env_->path_.emplace_back("");
     testBinaryPathSearch("test-exe");
 }
 
index cf6edc3d04f1a8f82885ff7841dfce05e4824c0c..28cb5ad88d0c690c08d250ecf5c8d4ab60632430 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, 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.
@@ -350,7 +350,7 @@ TEST_F(ParseCommonArgsTest, ParsesFileArgsWithDefaults)
     parseFromArray(cmdline, 0, fnm, gmx::EmptyArrayRef());
     EXPECT_STREQ("topol.tpr", ftp2fn(efTPS, nfile(), fnm));
     EXPECT_STREQ("traj.xtc", opt2fn("-f2", nfile(), fnm));
-    EXPECT_NULL(opt2fn_null("-f2", nfile(), fnm));
+    EXPECT_EQ(nullptr, opt2fn_null("-f2", nfile(), fnm));
     EXPECT_STREQ("trj3.xtc", opt2fn("-f3", nfile(), fnm));
     EXPECT_STREQ("out.xvg", opt2fn("-o", nfile(), fnm));
     EXPECT_STREQ("outm.xvg", opt2fn("-om", nfile(), fnm));
@@ -551,9 +551,9 @@ TEST_F(ParseCommonArgsTest, HandlesNonReadNode)
         "test", "-f", "-f2", "other"
     };
     parseFromArray(cmdline, PCA_NOT_READ_NODE, fnm, gmx::EmptyArrayRef());
-    EXPECT_NULL(fnm[0].fns);
-    EXPECT_NULL(fnm[1].fns);
-    EXPECT_NULL(fnm[2].fns);
+    EXPECT_EQ(nullptr, fnm[0].fns);
+    EXPECT_EQ(nullptr, fnm[1].fns);
+    EXPECT_EQ(nullptr, fnm[2].fns);
     done_filenms(nfile(), fnm);
 }
 
@@ -568,9 +568,9 @@ TEST_F(ParseCommonArgsTest, HandlesNonReadNodeWithDefaultFileName)
         "test", "-deffnm", "def", "-f", "-f2", "other"
     };
     parseFromArray(cmdline, PCA_CAN_SET_DEFFNM | PCA_NOT_READ_NODE, fnm, gmx::EmptyArrayRef());
-    EXPECT_NULL(fnm[0].fns);
-    EXPECT_NULL(fnm[1].fns);
-    EXPECT_NULL(fnm[2].fns);
+    EXPECT_EQ(nullptr, fnm[0].fns);
+    EXPECT_EQ(nullptr, fnm[1].fns);
+    EXPECT_EQ(nullptr, fnm[2].fns);
     done_filenms(nfile(), fnm);
 }
 
index 84017c079328ee46cdb74c7c78b1e68075c9e3e1..88cc3593a4553b39c3c48b5e48475b75f05d7d04 100644 (file)
@@ -70,6 +70,7 @@
 #include "gromacs/mdlib/gmx_omp_nthreads.h"
 #include "gromacs/mdlib/mdatoms.h"
 #include "gromacs/mdlib/mdrun.h"
+#include "gromacs/mdlib/mdsetup.h"
 #include "gromacs/mdlib/nb_verlet.h"
 #include "gromacs/mdlib/nbnxn_grid.h"
 #include "gromacs/mdlib/nsgrid.h"
@@ -346,6 +347,15 @@ void dd_get_ns_ranges(const gmx_domdec_t *dd, int icg,
     }
 }
 
+int dd_natoms_mdatoms(const gmx_domdec_t *dd)
+{
+    /* We currently set mdatoms entries for all atoms:
+     * local + non-local + communicated for vsite + constraints
+     */
+
+    return dd->comm->nat[ddnatNR - 1];
+}
+
 int dd_natoms_vsite(const gmx_domdec_t *dd)
 {
     return dd->comm->nat[ddnatVSITE];
@@ -1501,7 +1511,11 @@ static void dd_distribute_vec(gmx_domdec_t *dd, t_block *cgs, rvec *v, rvec *lv)
 
 static void dd_distribute_dfhist(gmx_domdec_t *dd, df_history_t *dfhist)
 {
-    int i;
+    if (dfhist == NULL)
+    {
+        return;
+    }
+
     dd_bcast(dd, sizeof(int), &dfhist->bEquil);
     dd_bcast(dd, sizeof(int), &dfhist->nlambda);
     dd_bcast(dd, sizeof(real), &dfhist->wl_delta);
@@ -1516,7 +1530,7 @@ static void dd_distribute_dfhist(gmx_domdec_t *dd, df_history_t *dfhist)
         dd_bcast(dd, sizeof(real)*nlam, dfhist->sum_minvar);
         dd_bcast(dd, sizeof(real)*nlam, dfhist->sum_variance);
 
-        for (i = 0; i < nlam; i++)
+        for (int i = 0; i < nlam; i++)
         {
             dd_bcast(dd, sizeof(real)*nlam, dfhist->accum_p[i]);
             dd_bcast(dd, sizeof(real)*nlam, dfhist->accum_m[i]);
@@ -1550,7 +1564,10 @@ static void dd_distribute_state(gmx_domdec_t *dd, t_block *cgs,
         copy_mat(state->boxv, state_local->boxv);
         copy_mat(state->svir_prev, state_local->svir_prev);
         copy_mat(state->fvir_prev, state_local->fvir_prev);
-        copy_df_history(&state_local->dfhist, &state->dfhist);
+        if (state->dfhist != NULL)
+        {
+            copy_df_history(state_local->dfhist, state->dfhist);
+        }
         for (i = 0; i < state_local->ngtc; i++)
         {
             for (j = 0; j < nh; j++)
@@ -1585,7 +1602,7 @@ static void dd_distribute_state(gmx_domdec_t *dd, t_block *cgs,
     dd_bcast(dd, ((state_local->nnhpres*nh)*sizeof(double)), state_local->nhpres_vxi);
 
     /* communicate df_history -- required for restarting from checkpoint */
-    dd_distribute_dfhist(dd, &state_local->dfhist);
+    dd_distribute_dfhist(dd, state_local->dfhist);
 
     if (dd->nat_home > state_local->nalloc)
     {
@@ -5716,8 +5733,8 @@ static void make_pp_communicator(FILE                 *fplog,
     }
 }
 
-static void receive_ddindex2simnodeid(gmx_domdec_t         *dd,
-                                      t_commrec gmx_unused *cr)
+static void receive_ddindex2simnodeid(gmx_domdec_t gmx_unused *dd,
+                                      t_commrec    gmx_unused *cr)
 {
 #if GMX_MPI
     gmx_domdec_comm_t *comm = dd->comm;
@@ -9553,31 +9570,15 @@ void dd_partition_system(FILE                *fplog,
     forcerec_set_ranges(fr, dd->ncg_home, dd->ncg_tot,
                         dd->nat_tot, comm->nat[ddnatCON], nat_f_novirsum);
 
-    /* We make the all mdatoms up to nat_tot_con.
-     * We could save some work by only setting invmass
-     * between nat_tot and nat_tot_con.
-     */
-    /* This call also sets the new number of home particles to dd->nat_home */
-    atoms2md(top_global, ir,
-             comm->nat[ddnatCON], dd->gatindex, dd->nat_home, mdatoms);
-
-    /* Now we have the charges we can sort the FE interactions */
-    dd_sort_local_top(dd, mdatoms, top_local);
-
-    if (vsite != NULL)
-    {
-        /* Now we have updated mdatoms, we can do the last vsite bookkeeping */
-        split_vsites_over_threads(top_local->idef.il, top_local->idef.iparams,
-                                  mdatoms, FALSE, vsite);
-    }
+    /* Update atom data for mdatoms and several algorithms */
+    mdAlgorithmsSetupAtomData(cr, ir, top_global, top_local, fr,
+                              NULL, mdatoms, vsite, NULL);
 
     if (ir->implicit_solvent)
     {
         make_local_gb(cr, fr->born, ir->gb_algorithm);
     }
 
-    setup_bonded_threading(fr, &top_local->idef);
-
     if (!(cr->duty & DUTY_PME))
     {
         /* Send the charges and/or c6/sigmas to our PME only node */
index a2d772a2214273c9bf43f7c2d7c15f1d0d0f7e01..5164004d68a8e9f875d59a1b8267a4beaaa00037 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2005,2006,2007,2008,2009,2010,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2005,2006,2007,2008,2009,2010,2012,2013,2014,2015,2016, 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.
@@ -109,6 +109,9 @@ struct gmx_domdec_zones_t *domdec_zones(struct gmx_domdec_t *dd);
 void dd_get_ns_ranges(const gmx_domdec_t *dd, int icg,
                       int *jcg0, int *jcg1, ivec shift0, ivec shift1);
 
+/*! \brief Returns the atom range in the local state for atoms that need to be present in mdatoms */
+int dd_natoms_mdatoms(const gmx_domdec_t *dd);
+
 /*! \brief Returns the atom range in the local state for atoms involved in virtual sites */
 int dd_natoms_vsite(const gmx_domdec_t *dd);
 
index 907e60c5f947398ab2f4d7cd8fc27f3eb653642a..95ba742703c777753d98bf1635dbacf43110f200 100644 (file)
@@ -223,26 +223,13 @@ void dd_sendrecv2_rvec(const struct gmx_domdec_t gmx_unused *dd,
 #endif
 }
 
-/* IBM's BlueGene(/L) MPI_Bcast dereferences the data pointer
- * even when 0 == nbytes, so we protect calls to it on BlueGene.
- * Fortunately dd_bcast() and dd_bcastc() are only
- * called during DD setup and partition.
- */
-
 void dd_bcast(gmx_domdec_t gmx_unused *dd, int gmx_unused nbytes, void gmx_unused *data)
 {
 #if GMX_MPI
     if (dd->nnodes > 1)
     {
-#ifdef GMX_BLUEGENE
-        if (nbytes > 0)
-        {
-#endif
         MPI_Bcast(data, nbytes, MPI_BYTE,
                   DDMASTERRANK(dd), dd->mpi_comm_all);
-#ifdef GMX_BLUEGENE
-    }
-#endif
     }
 #endif
 }
@@ -256,15 +243,8 @@ void dd_bcastc(gmx_domdec_t *dd, int nbytes, void *src, void *dest)
 #if GMX_MPI
     if (dd->nnodes > 1)
     {
-#ifdef GMX_BLUEGENE
-        if (nbytes > 0)
-        {
-#endif
         MPI_Bcast(dest, nbytes, MPI_BYTE,
                   DDMASTERRANK(dd), dd->mpi_comm_all);
-#ifdef GMX_BLUEGENE
-    }
-#endif
     }
 #endif
 }
index 46b05ddd71ddf01e40ece4a02723cd8fa42f0143..d34ec487d85b8309fc325280fc24a7656c07fe53 100644 (file)
@@ -2272,7 +2272,7 @@ void dd_init_local_state(gmx_domdec_t *dd,
         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);
 
index 41bbd3078e683f59f87c497f8db99faa5216cbf3..6dec771bddba3027fffbfb9edc7701da8164cc50 100644 (file)
@@ -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, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, 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.
@@ -1184,7 +1184,7 @@ static void get_flood_energies(t_edpar *edi, real Vfl[], int nnames)
 #endif
 
 
-gmx_edsam_t ed_open(int natoms, edsamstate_t *EDstate, int nfile, const t_filenm fnm[], unsigned long Flags, const gmx_output_env_t *oenv, t_commrec *cr)
+gmx_edsam_t ed_open(int natoms, edsamstate_t **EDstatePtr, int nfile, const t_filenm fnm[], unsigned long Flags, const gmx_output_env_t *oenv, t_commrec *cr)
 {
     gmx_edsam_t ed;
     int         nED;
@@ -1193,6 +1193,12 @@ gmx_edsam_t ed_open(int natoms, edsamstate_t *EDstate, int nfile, const t_filenm
     /* Allocate space for the ED data structure */
     snew(ed, 1);
 
+    if (*EDstatePtr == NULL)
+    {
+        snew(*EDstatePtr, 1);
+    }
+    edsamstate_t *EDstate = *EDstatePtr;
+
     /* We want to perform ED (this switch might later be upgraded to eEDflood) */
     ed->eEDtype = eEDedsam;
 
index 57afb0fcf4b3dad17a52b793f30d0fbd69167c2b..ea87ceccbdba587e5e34352209db571cb5c5539d 100644 (file)
@@ -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, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, 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.
@@ -88,7 +88,7 @@ void do_edsam(const t_inputrec *ir, gmx_int64_t step,
  * gmx make_edi can be used to create an .edi input file.
  *
  * \param natoms            Number of atoms of the whole MD system.
- * \param EDstate           Essential dynamics and flooding data stored in the checkpoint file.
+ * \param EDstatePtr        Essential dynamics and flooding data stored in the checkpoint file.
  * \param nfile             Number of entries (files) in the fnm structure.
  * \param fnm               The filenames struct; it contains also the names of the
  *                          essential dynamics and flooding in + output files.
@@ -98,7 +98,7 @@ void do_edsam(const t_inputrec *ir, gmx_int64_t step,
  * \param cr                Data needed for MPI communication.
  * \returns                 Pointer to the initialized essential dynamics / flooding data.
  */
-gmx_edsam_t ed_open(int natoms, edsamstate_t *EDstate, int nfile, const t_filenm fnm[],
+gmx_edsam_t ed_open(int natoms, edsamstate_t **EDstatePtr, int nfile, const t_filenm fnm[],
                     unsigned long Flags, const gmx_output_env_t *oenv, t_commrec *cr);
 
 /*! \brief Initializes the essential dynamics and flooding module.
index d4ec0d361913b12cb4ec22cfc5264caa6c8cd043..c522c41152d89d3397914b3937e9a54ad3d4c9f6 100644 (file)
@@ -768,18 +768,13 @@ void pmegrids_init(pmegrids_t *grids,
 
 void pmegrids_destroy(pmegrids_t *grids)
 {
-    int t;
-
     if (grids->grid.grid != NULL)
     {
-        sfree(grids->grid.grid);
+        sfree_aligned(grids->grid.grid);
 
         if (grids->nthread > 0)
         {
-            for (t = 0; t < grids->nthread; t++)
-            {
-                sfree(grids->grid_th[t].grid);
-            }
+            sfree_aligned(grids->grid_all);
             sfree(grids->grid_th);
         }
     }
@@ -864,6 +859,7 @@ void reuse_pmegrids(const pmegrids_t *oldgrid, pmegrids_t *newgrid)
     if (newgrid->grid_th != NULL && newgrid->nthread == oldgrid->nthread)
     {
         sfree_aligned(newgrid->grid_all);
+        newgrid->grid_all = oldgrid->grid_all;
         for (t = 0; t < newgrid->nthread; t++)
         {
             newgrid->grid_th[t].grid = oldgrid->grid_th[t].grid;
index a74070a431d2d33b465cb2148796ab8858a8d339..dfa7240e947e0563f6d9a88ed8d3803f1f2e45a3 100644 (file)
@@ -94,12 +94,17 @@ static const real lb_scale_factor_symm[] = { 2.0/64, 12.0/64, 30.0/64, 20.0/64 }
  */
 #define PME_ORDER_MAX 12
 
-/*! \brief As gmx_pme_init, but takes most settings, except the grid, from pme_src */
+/*! \brief As gmx_pme_init, but takes most settings, except the grid/Ewald coefficients, from pme_src.
+ * This is only called when the PME cut-off/grid size changes.
+ */
 int gmx_pme_reinit(struct gmx_pme_t **pmedata,
                    t_commrec *        cr,
                    struct gmx_pme_t * pme_src,
                    const t_inputrec * ir,
-                   ivec               grid_size);
+                   ivec               grid_size,
+                   real               ewaldcoeff_q,
+                   real               ewaldcoeff_lj);
+
 
 /* The following three routines are for PME/PP node splitting in pme_pp.c */
 
@@ -244,12 +249,16 @@ typedef struct gmx_pme_t {
     int        nthread;       /* The number of threads doing PME on our rank */
 
     gmx_bool   bPPnode;       /* Node also does particle-particle forces */
+    bool       doCoulomb;     /* Apply PME to electrostatics */
+    bool       doLJ;          /* Apply PME to Lennard-Jones r^-6 interactions */
     gmx_bool   bFEP;          /* Compute Free energy contribution */
     gmx_bool   bFEP_q;
     gmx_bool   bFEP_lj;
     int        nkx, nky, nkz; /* Grid dimensions */
     gmx_bool   bP3M;          /* Do P3M: optimize the influence function */
     int        pme_order;
+    real       ewaldcoeff_q;  /* Ewald splitting coefficient for Coulomb */
+    real       ewaldcoeff_lj; /* Ewald splitting coefficient for r^-6 */
     real       epsilon_r;
 
     int        ljpme_combination_rule;  /* Type of combination rule in LJ-PME */
@@ -365,9 +374,8 @@ int gmx_pme_recv_coeffs_coords(struct gmx_pme_pp *pme_pp,
                                real **sigmaA, real **sigmaB,
                                matrix box, rvec **x, rvec **f,
                                int *maxshift_x, int *maxshift_y,
-                               gmx_bool *bFreeEnergy_q, gmx_bool *bFreeEnergy_lj,
                                real *lambda_q, real *lambda_lj,
-                               gmx_bool *bEnerVir, int *pme_flags,
+                               gmx_bool *bEnerVir,
                                gmx_int64_t *step,
                                ivec grid_size, real *ewaldcoeff_q, real *ewaldcoeff_lj);
 
index a028c1cb987b011236930bf7075969c2d9996284..ed4e6e038dc6430ce10f6d3a0fece02f219a8adf 100644 (file)
@@ -57,7 +57,6 @@
 #include "gromacs/domdec/domdec_network.h"
 #include "gromacs/domdec/domdec_struct.h"
 #include "gromacs/fft/calcgrid.h"
-#include "gromacs/gmxlib/md_logging.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/math/functions.h"
 #include "gromacs/math/vec.h"
@@ -72,6 +71,7 @@
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/smalloc.h"
 
 #include "pme-internal.h"
@@ -155,11 +155,11 @@ bool pme_loadbal_is_active(const pme_load_balancing_t *pme_lb)
 
 void pme_loadbal_init(pme_load_balancing_t     **pme_lb_p,
                       t_commrec                 *cr,
-                      FILE                      *fp_log,
+                      const gmx::MDLogger       &mdlog,
                       const t_inputrec          *ir,
                       matrix                     box,
                       const interaction_const_t *ic,
-                      struct gmx_pme_t          *pmedata,
+                      gmx_pme_t                 *pmedata,
                       gmx_bool                   bUseGPU,
                       gmx_bool                  *bPrinting)
 {
@@ -244,7 +244,7 @@ void pme_loadbal_init(pme_load_balancing_t     **pme_lb_p,
 
     if (!wallcycle_have_counter())
     {
-        md_print_warn(cr, fp_log, "NOTE: Cycle counters unsupported or not enabled in kernel. Cannot use PME-PP balancing.\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText("NOTE: Cycle counters unsupported or not enabled in kernel. Cannot use PME-PP balancing.");
     }
 
     /* Tune with GPUs and/or separate PME ranks.
@@ -274,7 +274,7 @@ void pme_loadbal_init(pme_load_balancing_t     **pme_lb_p,
         dd_dlb_lock(cr->dd);
         if (dd_dlb_is_locked(cr->dd))
         {
-            md_print_warn(cr, fp_log, "NOTE: DLB will not turn on during the first phase of PME tuning\n");
+            GMX_LOG(mdlog.warning).asParagraph().appendText("NOTE: DLB will not turn on during the first phase of PME tuning");
         }
     }
 
@@ -518,6 +518,7 @@ pme_load_balance(pme_load_balancing_t      *pme_lb,
                  t_commrec                 *cr,
                  FILE                      *fp_err,
                  FILE                      *fp_log,
+                 const gmx::MDLogger       &mdlog,
                  const t_inputrec          *ir,
                  t_state                   *state,
                  double                     cycles,
@@ -746,7 +747,8 @@ pme_load_balance(pme_load_balancing_t      *pme_lb,
                 /* This should not happen, as we set limits on the DLB bounds.
                  * But we implement a complete failsafe solution anyhow.
                  */
-                md_print_warn(cr, fp_log, "The fastest PP/PME load balancing setting (cutoff %.3f nm) is no longer available due to DD DLB or box size limitations\n");
+                GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                        "The fastest PP/PME load balancing setting (cutoff %.3f nm) is no longer available due to DD DLB or box size limitations", pme_lb->fastest);
                 pme_lb->fastest = pme_lb->lower_limit;
                 pme_lb->start   = pme_lb->lower_limit;
             }
@@ -820,7 +822,7 @@ pme_load_balance(pme_load_balancing_t      *pme_lb,
              */
             gmx_pme_reinit(&set->pmedata,
                            cr, pme_lb->setup[0].pmedata, ir,
-                           set->grid);
+                           set->grid, set->ewaldcoeff_q, set->ewaldcoeff_lj);
         }
         *pmedata = set->pmedata;
     }
@@ -870,6 +872,7 @@ void pme_loadbal_do(pme_load_balancing_t *pme_lb,
                     t_commrec            *cr,
                     FILE                 *fp_err,
                     FILE                 *fp_log,
+                    const gmx::MDLogger  &mdlog,
                     const t_inputrec     *ir,
                     t_forcerec           *fr,
                     t_state              *state,
@@ -951,7 +954,7 @@ void pme_loadbal_do(pme_load_balancing_t *pme_lb,
         {
             /* Unlock the DLB=auto, DLB is allowed to activate */
             dd_dlb_unlock(cr->dd);
-            md_print_warn(cr, fp_log, "NOTE: DLB can now turn on, when beneficial\n");
+            GMX_LOG(mdlog.warning).asParagraph().appendText("NOTE: DLB can now turn on, when beneficial");
 
             /* We don't deactivate the tuning yet, since we will balance again
              * after DLB gets turned on, if it does within PMETune_period.
@@ -984,7 +987,7 @@ void pme_loadbal_do(pme_load_balancing_t *pme_lb,
          * but the first data collected is skipped anyhow.
          */
         pme_load_balance(pme_lb, cr,
-                         fp_err, fp_log,
+                         fp_err, fp_log, mdlog,
                          ir, state, pme_lb->cycles_c - cycles_prev,
                          fr->ic, fr->nbv, &fr->pmedata,
                          step);
@@ -1015,7 +1018,7 @@ void pme_loadbal_do(pme_load_balancing_t *pme_lb,
     {
         /* Make sure DLB is allowed when we deactivate PME tuning */
         dd_dlb_unlock(cr->dd);
-        md_print_warn(cr, fp_log, "NOTE: DLB can now turn on, when beneficial\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText("NOTE: DLB can now turn on, when beneficial");
     }
 
     *bPrinting = pme_lb->bBalance;
@@ -1042,8 +1045,8 @@ static void print_pme_loadbal_setting(FILE              *fplog,
 
 /*! \brief Print all load-balancing settings */
 static void print_pme_loadbal_settings(pme_load_balancing_t *pme_lb,
-                                       t_commrec            *cr,
                                        FILE                 *fplog,
+                                       const gmx::MDLogger  &mdlog,
                                        gmx_bool              bNonBondedOnGPU)
 {
     double     pp_ratio, grid_ratio;
@@ -1081,10 +1084,10 @@ static void print_pme_loadbal_settings(pme_load_balancing_t *pme_lb,
 
     if (pp_ratio > 1.5 && !bNonBondedOnGPU)
     {
-        md_print_warn(cr, fplog,
-                      "NOTE: PME load balancing increased the non-bonded workload by more than 50%%.\n"
-                      "      For better performance, use (more) PME ranks (mdrun -npme),\n"
-                      "      or if you are beyond the scaling limit, use fewer total ranks (or nodes).\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText(
+                "NOTE: PME load balancing increased the non-bonded workload by more than 50%.\n"
+                "      For better performance, use (more) PME ranks (mdrun -npme),\n"
+                "      or if you are beyond the scaling limit, use fewer total ranks (or nodes).");
     }
     else
     {
@@ -1093,13 +1096,13 @@ static void print_pme_loadbal_settings(pme_load_balancing_t *pme_lb,
 }
 
 void pme_loadbal_done(pme_load_balancing_t *pme_lb,
-                      t_commrec            *cr,
                       FILE                 *fplog,
+                      const gmx::MDLogger  &mdlog,
                       gmx_bool              bNonBondedOnGPU)
 {
     if (fplog != NULL && (pme_lb->cur > 0 || pme_lb->elimited != epmelblimNO))
     {
-        print_pme_loadbal_settings(pme_lb, cr, fplog, bNonBondedOnGPU);
+        print_pme_loadbal_settings(pme_lb, fplog, mdlog, bNonBondedOnGPU);
     }
 
     /* TODO: Here we should free all pointers in pme_lb,
index d0e305a8eb91f248dbe2f40942a8340927b1fbb0..80ddbbebb3b6c2ac2c2b468b6efa44bb8b067a29 100644 (file)
@@ -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
  * 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.
 struct t_commrec;
 struct t_inputrec;
 
+namespace gmx
+{
+class MDLogger;
+}
+
 /*! \brief Object to manage PME load balancing */
 struct pme_load_balancing_t;
 
@@ -69,12 +74,12 @@ bool pme_loadbal_is_active(const pme_load_balancing_t *pme_lb);
  * usage.
  */
 void pme_loadbal_init(pme_load_balancing_t     **pme_lb_p,
-                      struct t_commrec          *cr,
-                      FILE                      *fp_log,
+                      t_commrec                 *cr,
+                      const gmx::MDLogger       &mdlog,
                       const t_inputrec          *ir,
                       matrix                     box,
                       const interaction_const_t *ic,
-                      struct gmx_pme_t          *pmedata,
+                      gmx_pme_t                 *pmedata,
                       gmx_bool                   bUseGPU,
                       gmx_bool                  *bPrinting);
 
@@ -89,6 +94,7 @@ void pme_loadbal_do(pme_load_balancing_t  *pme_lb,
                     struct t_commrec      *cr,
                     FILE                  *fp_err,
                     FILE                  *fp_log,
+                    const gmx::MDLogger   &mdlog,
                     const t_inputrec      *ir,
                     t_forcerec            *fr,
                     t_state               *state,
@@ -99,8 +105,8 @@ void pme_loadbal_do(pme_load_balancing_t  *pme_lb,
 
 /*! \brief Finish the PME load balancing and print the settings when fplog!=NULL */
 void pme_loadbal_done(pme_load_balancing_t *pme_lb,
-                      struct t_commrec     *cr,
                       FILE                 *fplog,
+                      const gmx::MDLogger  &mdlog,
                       gmx_bool              bNonBondedOnGPU);
 
 #endif
index 326cf977f97c56aa20c0e62d444fed4d1af5ad9c..6d8c0984357626a346079437b562ad4a3adcfcf2 100644 (file)
@@ -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, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, 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.
@@ -107,6 +107,7 @@ static void reset_pmeonly_counters(gmx_wallcycle_t wcycle,
 
 static void gmx_pmeonly_switch(int *npmedata, struct gmx_pme_t ***pmedata,
                                ivec grid_size,
+                               real ewaldcoeff_q, real ewaldcoeff_lj,
                                t_commrec *cr, t_inputrec *ir,
                                struct gmx_pme_t **pme_ret)
 {
@@ -133,7 +134,7 @@ static void gmx_pmeonly_switch(int *npmedata, struct gmx_pme_t ***pmedata,
     srenew(*pmedata, *npmedata);
 
     /* Generate a new PME data structure, copying part of the old pointers */
-    gmx_pme_reinit(&((*pmedata)[ind]), cr, pme, ir, grid_size);
+    gmx_pme_reinit(&((*pmedata)[ind]), cr, pme, ir, grid_size, ewaldcoeff_q, ewaldcoeff_lj);
 
     *pme_ret = (*pmedata)[ind];
 }
@@ -163,7 +164,6 @@ int gmx_pmeonly(struct gmx_pme_t *pme,
     float              cycles;
     int                count;
     gmx_bool           bEnerVir;
-    int                pme_flags;
     gmx_int64_t        step;
     ivec               grid_switch;
 
@@ -190,17 +190,15 @@ int gmx_pmeonly(struct gmx_pme_t *pme,
                                              &sigmaA, &sigmaB,
                                              box, &x_pp, &f_pp,
                                              &maxshift_x, &maxshift_y,
-                                             &pme->bFEP_q, &pme->bFEP_lj,
                                              &lambda_q, &lambda_lj,
                                              &bEnerVir,
-                                             &pme_flags,
                                              &step,
                                              grid_switch, &ewaldcoeff_q, &ewaldcoeff_lj);
 
             if (ret == pmerecvqxSWITCHGRID)
             {
                 /* Switch the PME grid to grid_switch */
-                gmx_pmeonly_switch(&npmedata, &pmedata, grid_switch, cr, ir, &pme);
+                gmx_pmeonly_switch(&npmedata, &pmedata, grid_switch, ewaldcoeff_q, ewaldcoeff_lj, cr, ir, &pme);
             }
 
             if (ret == pmerecvqxRESETCOUNTERS)
@@ -233,9 +231,9 @@ int gmx_pmeonly(struct gmx_pme_t *pme,
         gmx_pme_do(pme, 0, natoms, x_pp, f_pp,
                    chargeA, chargeB, c6A, c6B, sigmaA, sigmaB, box,
                    cr, maxshift_x, maxshift_y, mynrnb, wcycle,
-                   vir_q, ewaldcoeff_q, vir_lj, ewaldcoeff_lj,
+                   vir_q, vir_lj,
                    &energy_q, &energy_lj, lambda_q, lambda_lj, &dvdlambda_q, &dvdlambda_lj,
-                   pme_flags | GMX_PME_DO_ALL_F | (bEnerVir ? GMX_PME_CALC_ENER_VIR : 0));
+                   GMX_PME_DO_ALL_F | (bEnerVir ? GMX_PME_CALC_ENER_VIR : 0));
 
         cycles = wallcycle_stop(wcycle, ewcPMEMESH);
 
index d7642deda6f85c3c606e5d8da53ede11bdcb02d5..daa937b57164ab60f445b40589704d7e827ec362 100644 (file)
@@ -79,9 +79,6 @@ enum {
  *
  * Some parts of the code(gmx_pme_send_q, gmx_pme_recv_q_x) assume
  * that the six first flags are exactly in this order.
- * If more PP_PME_...-flags are to be introduced be aware of some of
- * the PME-specific flags in pme.h. Currently, they are also passed
- * through here.
  */
 
 #define PP_PME_CHARGE         (1<<0)
@@ -91,8 +88,6 @@ enum {
 #define PP_PME_SIGMA          (1<<4)
 #define PP_PME_SIGMAB         (1<<5)
 #define PP_PME_COORD          (1<<6)
-#define PP_PME_FEP_Q          (1<<7)
-#define PP_PME_FEP_LJ         (1<<8)
 #define PP_PME_ENER_VIR       (1<<9)
 #define PP_PME_FINISH         (1<<10)
 #define PP_PME_SWITCHGRID     (1<<11)
@@ -111,7 +106,6 @@ struct gmx_pme_pp {
     int         *node;           /**< The PP node ranks                          */
     int          node_peer;      /**< The peer PP node rank                      */
     int         *nat;            /**< The number of atom for each PP node        */
-    int          flags_charge;   /**< The flags sent along with the last charges */
     //@{
     /**< Vectors of A- and B-state parameters used to transfer vectors to PME ranks  */
     real        *chargeA;
@@ -141,7 +135,7 @@ struct gmx_pme_comm_n_box_t {
     int             maxshift_y; /**< Maximum shift in y direction */
     real            lambda_q;   /**< Free-energy lambda for electrostatics */
     real            lambda_lj;  /**< Free-energy lambda for Lennard-Jones */
-    int             flags;      /**< Control flags */
+    unsigned int    flags;      /**< Control flags */
     gmx_int64_t     step;       /**< MD integration step number */
     //@{
     /*! \brief Used in PME grid tuning */
@@ -182,7 +176,6 @@ gmx_pme_pp_t gmx_pme_pp_init(t_commrec *cr)
     snew(pme_pp->req, eCommType_NR*pme_pp->nnode);
     snew(pme_pp->stat, eCommType_NR*pme_pp->nnode);
     pme_pp->nalloc       = 0;
-    pme_pp->flags_charge = 0;
 #else
     GMX_UNUSED_VALUE(cr);
 #endif
@@ -207,7 +200,7 @@ static void gmx_pme_send_coeffs_coords_wait(gmx_domdec_t gmx_unused *dd)
 }
 
 /*! \brief Send data to PME ranks */
-static void gmx_pme_send_coeffs_coords(t_commrec *cr, int flags,
+static void gmx_pme_send_coeffs_coords(t_commrec *cr, unsigned int flags,
                                        real gmx_unused *chargeA, real gmx_unused *chargeB,
                                        real gmx_unused *c6A, real gmx_unused *c6B,
                                        real gmx_unused *sigmaA, real gmx_unused *sigmaB,
@@ -339,9 +332,8 @@ void gmx_pme_send_parameters(t_commrec *cr,
                              real *sigmaA, real *sigmaB,
                              int maxshift_x, int maxshift_y)
 {
-    int flags;
+    unsigned int flags = 0;
 
-    flags = 0;
     if (EEL_PME(ic->eeltype))
     {
         flags |= PP_PME_CHARGE;
@@ -364,22 +356,11 @@ void gmx_pme_send_parameters(t_commrec *cr,
 }
 
 void gmx_pme_send_coordinates(t_commrec *cr, matrix box, rvec *x,
-                              gmx_bool bFreeEnergy_q, gmx_bool bFreeEnergy_lj,
                               real lambda_q, real lambda_lj,
-                              gmx_bool bEnerVir, int pme_flags,
+                              gmx_bool bEnerVir,
                               gmx_int64_t step)
 {
-    int flags;
-
-    flags = pme_flags | PP_PME_COORD;
-    if (bFreeEnergy_q)
-    {
-        flags |= PP_PME_FEP_Q;
-    }
-    if (bFreeEnergy_lj)
-    {
-        flags |= PP_PME_FEP_LJ;
-    }
+    unsigned int flags = PP_PME_COORD;
     if (bEnerVir)
     {
         flags |= PP_PME_ENER_VIR;
@@ -390,9 +371,7 @@ void gmx_pme_send_coordinates(t_commrec *cr, matrix box, rvec *x,
 
 void gmx_pme_send_finish(t_commrec *cr)
 {
-    int flags;
-
-    flags = PP_PME_FINISH;
+    unsigned int flags = PP_PME_FINISH;
 
     gmx_pme_send_coeffs_coords(cr, flags, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, -1);
 }
@@ -451,34 +430,36 @@ int gmx_pme_recv_coeffs_coords(struct gmx_pme_pp *pme_pp,
                                rvec             **f,
                                int               *maxshift_x,
                                int               *maxshift_y,
-                               gmx_bool          *bFreeEnergy_q,
-                               gmx_bool          *bFreeEnergy_lj,
                                real              *lambda_q,
                                real              *lambda_lj,
                                gmx_bool          *bEnerVir,
-                               int               *pme_flags,
                                gmx_int64_t       *step,
                                ivec               grid_size,
                                real              *ewaldcoeff_q,
                                real              *ewaldcoeff_lj)
 {
-    int                  nat = 0, status;
+    int status = -1;
+    int nat    = 0;
 
-    *pme_flags = 0;
 #if GMX_MPI
-    gmx_pme_comm_n_box_t cnb;
-    int                  messages;
+    unsigned int flags    = 0;
+    int          messages = 0;
 
-    cnb.flags  = 0;
-    messages   = 0;
     do
     {
+        gmx_pme_comm_n_box_t cnb;
+        cnb.flags = 0;
 
         /* Receive the send count, box and time step from the peer PP node */
         MPI_Recv(&cnb, sizeof(cnb), MPI_BYTE,
                  pme_pp->node_peer, eCommType_CNB,
                  pme_pp->mpi_comm_mysim, MPI_STATUS_IGNORE);
 
+        /* We accumulate all received flags */
+        flags |= cnb.flags;
+
+        *step  = cnb.step;
+
         if (debug)
         {
             fprintf(debug, "PME only rank receiving:%s%s%s%s%s\n",
@@ -489,21 +470,25 @@ int gmx_pme_recv_coeffs_coords(struct gmx_pme_pp *pme_pp,
                     (cnb.flags & PP_PME_RESETCOUNTERS) ? " reset counters" : "");
         }
 
+        if (cnb.flags & PP_PME_FINISH)
+        {
+            status = pmerecvqxFINISH;
+        }
+
         if (cnb.flags & PP_PME_SWITCHGRID)
         {
             /* Special case, receive the new parameters and return */
             copy_ivec(cnb.grid_size, grid_size);
             *ewaldcoeff_q  = cnb.ewaldcoeff_q;
             *ewaldcoeff_lj = cnb.ewaldcoeff_lj;
-            return pmerecvqxSWITCHGRID;
+
+            status         = pmerecvqxSWITCHGRID;
         }
 
         if (cnb.flags & PP_PME_RESETCOUNTERS)
         {
-            /* Special case, receive the step and return */
-            *step = cnb.step;
-
-            return pmerecvqxRESETCOUNTERS;
+            /* Special case, receive the step (set above) and return */
+            status = pmerecvqxRESETCOUNTERS;
         }
 
         if (cnb.flags & (PP_PME_CHARGE | PP_PME_SQRTC6 | PP_PME_SIGMA))
@@ -608,41 +593,17 @@ int gmx_pme_recv_coeffs_coords(struct gmx_pme_pp *pme_pp,
                     }
                 }
             }
-
-            pme_pp->flags_charge = cnb.flags;
         }
 
         if (cnb.flags & PP_PME_COORD)
         {
-            if (!(pme_pp->flags_charge & (PP_PME_CHARGE | PP_PME_SQRTC6)))
-            {
-                gmx_incons("PME-only rank received coordinates before charges and/or C6-values"
-                           );
-            }
-
             /* The box, FE flag and lambda are sent along with the coordinates
              *  */
             copy_mat(cnb.box, box);
-            *bFreeEnergy_q  = ((cnb.flags & GMX_PME_DO_COULOMB) &&
-                               (cnb.flags & PP_PME_FEP_Q));
-            *bFreeEnergy_lj = ((cnb.flags & GMX_PME_DO_LJ) &&
-                               (cnb.flags & PP_PME_FEP_LJ));
             *lambda_q       = cnb.lambda_q;
             *lambda_lj      = cnb.lambda_lj;
             *bEnerVir       = (cnb.flags & PP_PME_ENER_VIR);
-            *pme_flags      = cnb.flags;
-
-            if (*bFreeEnergy_q && !(pme_pp->flags_charge & PP_PME_CHARGEB))
-            {
-                gmx_incons("PME-only rank received free energy request, but "
-                           "did not receive B-state charges");
-            }
-
-            if (*bFreeEnergy_lj && !(pme_pp->flags_charge & PP_PME_SQRTC6B))
-            {
-                gmx_incons("PME-only rank received free energy request, but "
-                           "did not receive B-state C6-values");
-            }
+            *step           = cnb.step;
 
             /* Receive the coordinates in place */
             nat = 0;
@@ -663,22 +624,19 @@ int gmx_pme_recv_coeffs_coords(struct gmx_pme_pp *pme_pp,
                     }
                 }
             }
+
+            status = pmerecvqxX;
         }
 
         /* Wait for the coordinates and/or charges to arrive */
         MPI_Waitall(messages, pme_pp->req, pme_pp->stat);
         messages = 0;
     }
-    while (!(cnb.flags & (PP_PME_COORD | PP_PME_FINISH)));
-    status = ((cnb.flags & PP_PME_FINISH) ? pmerecvqxFINISH : pmerecvqxX);
-
-    *step = cnb.step;
+    while (status == -1);
 #else
     GMX_UNUSED_VALUE(box);
     GMX_UNUSED_VALUE(maxshift_x);
     GMX_UNUSED_VALUE(maxshift_y);
-    GMX_UNUSED_VALUE(bFreeEnergy_q);
-    GMX_UNUSED_VALUE(bFreeEnergy_lj);
     GMX_UNUSED_VALUE(lambda_q);
     GMX_UNUSED_VALUE(lambda_lj);
     GMX_UNUSED_VALUE(bEnerVir);
@@ -690,15 +648,18 @@ int gmx_pme_recv_coeffs_coords(struct gmx_pme_pp *pme_pp,
     status = pmerecvqxX;
 #endif
 
-    *natoms   = nat;
-    *chargeA  = pme_pp->chargeA;
-    *chargeB  = pme_pp->chargeB;
-    *sqrt_c6A = pme_pp->sqrt_c6A;
-    *sqrt_c6B = pme_pp->sqrt_c6B;
-    *sigmaA   = pme_pp->sigmaA;
-    *sigmaB   = pme_pp->sigmaB;
-    *x        = pme_pp->x;
-    *f        = pme_pp->f;
+    if (status == pmerecvqxX)
+    {
+        *natoms   = nat;
+        *chargeA  = pme_pp->chargeA;
+        *chargeB  = pme_pp->chargeB;
+        *sqrt_c6A = pme_pp->sqrt_c6A;
+        *sqrt_c6B = pme_pp->sqrt_c6B;
+        *sigmaA   = pme_pp->sigmaA;
+        *sigmaB   = pme_pp->sigmaB;
+        *x        = pme_pp->x;
+        *f        = pme_pp->f;
+    }
 
     return status;
 }
index a7599b029e36be538079db4bfe1c43e6b94d670f..71553ad7a2d51ee41a2b502a3d898649df4c0afb 100644 (file)
@@ -159,7 +159,7 @@ void pme_free_all_work(struct pme_solve_work_t **work, int nthread)
     {
         free_work(&(*work)[thread]);
     }
-    sfree(work);
+    sfree(*work);
     *work = NULL;
 }
 
@@ -287,8 +287,7 @@ gmx_inline static void calc_exponentials_lj(int start, int end, real *r, real *t
 }
 #endif
 
-int solve_pme_yzx(struct gmx_pme_t *pme, t_complex *grid,
-                  real ewaldcoeff, real vol,
+int solve_pme_yzx(struct gmx_pme_t *pme, t_complex *grid, real vol,
                   gmx_bool bEnerVir,
                   int nthread, int thread)
 {
@@ -298,7 +297,8 @@ int solve_pme_yzx(struct gmx_pme_t *pme, t_complex *grid,
     int                      kx, ky, kz, maxkx, maxky;
     int                      nx, ny, nz, iyz0, iyz1, iyz, iy, iz, kxstart, kxend;
     real                     mx, my, mz;
-    real                     factor = M_PI*M_PI/(ewaldcoeff*ewaldcoeff);
+    real                     ewaldcoeff = pme->ewaldcoeff_q;
+    real                     factor     = M_PI*M_PI/(ewaldcoeff*ewaldcoeff);
     real                     ets2, struct2, vfactor, ets2vf;
     real                     d1, d2, energy = 0;
     real                     by, bz;
@@ -538,8 +538,7 @@ int solve_pme_yzx(struct gmx_pme_t *pme, t_complex *grid,
     return local_ndata[YY]*local_ndata[XX];
 }
 
-int solve_pme_lj_yzx(struct gmx_pme_t *pme, t_complex **grid, gmx_bool bLB,
-                     real ewaldcoeff, real vol,
+int solve_pme_lj_yzx(struct gmx_pme_t *pme, t_complex **grid, gmx_bool bLB, real vol,
                      gmx_bool bEnerVir, int nthread, int thread)
 {
     /* do recip sum over local cells in grid */
@@ -548,7 +547,8 @@ int solve_pme_lj_yzx(struct gmx_pme_t *pme, t_complex **grid, gmx_bool bLB,
     int                      kx, ky, kz, maxkx, maxky;
     int                      nx, ny, nz, iy, iyz0, iyz1, iyz, iz, kxstart, kxend;
     real                     mx, my, mz;
-    real                     factor = M_PI*M_PI/(ewaldcoeff*ewaldcoeff);
+    real                     ewaldcoeff = pme->ewaldcoeff_lj;
+    real                     factor     = M_PI*M_PI/(ewaldcoeff*ewaldcoeff);
     real                     ets2, ets2vf;
     real                     eterm, vterm, d1, d2, energy = 0;
     real                     by, bz;
index 6b26a58f1bc37df9b0ac46c5475d0b663b22ae5a..33c828a39d58db951039b6dca8a3945739d699ad 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016, 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.
@@ -70,12 +70,12 @@ void get_pme_ener_vir_lj(struct pme_solve_work_t *work, int nthread,
                          real *mesh_energy, matrix vir);
 
 int solve_pme_yzx(struct gmx_pme_t *pme, t_complex *grid,
-                  real ewaldcoeff, real vol,
+                  real vol,
                   gmx_bool bEnerVir,
                   int nthread, int thread);
 
 int solve_pme_lj_yzx(struct gmx_pme_t *pme, t_complex **grid, gmx_bool bLB,
-                     real ewaldcoeff, real vol,
+                     real vol,
                      gmx_bool bEnerVir, int nthread, int thread);
 
 #endif
index 5824e580ada49cc7b693832127decb1e0d3b802c..fa65128965d588c9370a18250a75f934c27c5a41 100644 (file)
@@ -150,38 +150,6 @@ static void setup_coordinate_communication(pme_atomcomm_t *atc)
     }
 }
 
-int gmx_pme_destroy(FILE *log, struct gmx_pme_t **pmedata)
-{
-    int i;
-
-    if (NULL != log)
-    {
-        fprintf(log, "Destroying PME data structures.\n");
-    }
-
-    sfree((*pmedata)->nnx);
-    sfree((*pmedata)->nny);
-    sfree((*pmedata)->nnz);
-
-    for (i = 0; i < (*pmedata)->ngrids; ++i)
-    {
-        pmegrids_destroy(&(*pmedata)->pmegrid[i]);
-        sfree((*pmedata)->fftgrid[i]);
-        sfree((*pmedata)->cfftgrid[i]);
-        gmx_parallel_3dfft_destroy((*pmedata)->pfft_setup[i]);
-    }
-
-    sfree((*pmedata)->lb_buf1);
-    sfree((*pmedata)->lb_buf2);
-
-    pme_free_all_work(&(*pmedata)->solve_work, (*pmedata)->nthread);
-
-    sfree(*pmedata);
-    *pmedata = NULL;
-
-    return 0;
-}
-
 /*! \brief Round \p n up to the next multiple of \p f */
 static int mult_up(int n, int f)
 {
@@ -266,6 +234,48 @@ static void init_atomcomm(struct gmx_pme_t *pme, pme_atomcomm_t *atc,
     }
 }
 
+/*! \brief Destroy an atom communication data structure and its child structs */
+static void destroy_atomcomm(pme_atomcomm_t *atc)
+{
+    sfree(atc->pd);
+    if (atc->nslab > 1)
+    {
+        sfree(atc->node_dest);
+        sfree(atc->node_src);
+        for (int i = 0; i < atc->nthread; i++)
+        {
+            sfree(atc->count_thread[i]);
+        }
+        sfree(atc->count_thread);
+        sfree(atc->rcount);
+        sfree(atc->buf_index);
+
+        sfree(atc->x);
+        sfree(atc->coefficient);
+        sfree(atc->f);
+    }
+    sfree(atc->idx);
+    sfree(atc->fractx);
+
+    sfree(atc->thread_idx);
+    for (int i = 0; i < atc->nthread; i++)
+    {
+        if (atc->nthread > 1)
+        {
+            int *n_ptr = atc->thread_plist[i].n - gmxCacheLineSize;
+            sfree(n_ptr);
+            sfree(atc->thread_plist[i].i);
+        }
+        sfree(atc->spline[i].thread_one);
+        sfree(atc->spline[i].ind);
+    }
+    if (atc->nthread > 1)
+    {
+        sfree(atc->thread_plist);
+    }
+    sfree(atc->spline);
+}
+
 /*! \brief Initialize data structure for communication */
 static void
 init_overlap_comm(pme_overlap_t *  ol,
@@ -469,6 +479,8 @@ int gmx_pme_init(struct gmx_pme_t **pmedata,
                  gmx_bool           bFreeEnergy_q,
                  gmx_bool           bFreeEnergy_lj,
                  gmx_bool           bReproducible,
+                 real               ewaldcoeff_q,
+                 real               ewaldcoeff_lj,
                  int                nthread)
 {
     struct gmx_pme_t *pme = NULL;
@@ -591,17 +603,29 @@ int gmx_pme_init(struct gmx_pme_t **pmedata,
         gmx_fatal(FARGS, "pme does not (yet) work with pbc = screw");
     }
 
-    pme->bFEP_q      = ((ir->efep != efepNO) && bFreeEnergy_q);
-    pme->bFEP_lj     = ((ir->efep != efepNO) && bFreeEnergy_lj);
-    pme->bFEP        = (pme->bFEP_q || pme->bFEP_lj);
-    pme->nkx         = ir->nkx;
-    pme->nky         = ir->nky;
-    pme->nkz         = ir->nkz;
-    pme->bP3M        = (ir->coulombtype == eelP3M_AD || getenv("GMX_PME_P3M") != NULL);
-    pme->pme_order   = ir->pme_order;
+    /* NOTE:
+     * It is likely that the current gmx_pme_do() routine supports calculating
+     * only Coulomb or LJ while gmx_pme_init() configures for both,
+     * but that has never been tested.
+     * It is likely that the current gmx_pme_do() routine supports calculating,
+     * not calculating free-energy for Coulomb and/or LJ while gmx_pme_init()
+     * configures with free-energy, but that has never been tested.
+     */
+    pme->doCoulomb     = EEL_PME(ir->coulombtype);
+    pme->doLJ          = EVDW_PME(ir->vdwtype);
+    pme->bFEP_q        = ((ir->efep != efepNO) && bFreeEnergy_q);
+    pme->bFEP_lj       = ((ir->efep != efepNO) && bFreeEnergy_lj);
+    pme->bFEP          = (pme->bFEP_q || pme->bFEP_lj);
+    pme->nkx           = ir->nkx;
+    pme->nky           = ir->nky;
+    pme->nkz           = ir->nkz;
+    pme->bP3M          = (ir->coulombtype == eelP3M_AD || getenv("GMX_PME_P3M") != NULL);
+    pme->pme_order     = ir->pme_order;
+    pme->ewaldcoeff_q  = ewaldcoeff_q;
+    pme->ewaldcoeff_lj = ewaldcoeff_lj;
 
     /* Always constant electrostatics coefficients */
-    pme->epsilon_r   = ir->epsilon_r;
+    pme->epsilon_r     = ir->epsilon_r;
 
     /* Always constant LJ coefficients */
     pme->ljpme_combination_rule = ir->ljpme_combination_rule;
@@ -719,7 +743,7 @@ int gmx_pme_init(struct gmx_pme_t **pmedata,
     /* It doesn't matter if we allocate too many grids here,
      * we only allocate and use the ones we need.
      */
-    if (EVDW_PME(ir->vdwtype))
+    if (pme->doLJ)
     {
         pme->ngrids = ((ir->ljpme_combination_rule == eljpmeLB) ? DO_Q_AND_LJ_LB : DO_Q_AND_LJ);
     }
@@ -733,11 +757,11 @@ int gmx_pme_init(struct gmx_pme_t **pmedata,
 
     for (i = 0; i < pme->ngrids; ++i)
     {
-        if ((i <  DO_Q && EEL_PME(ir->coulombtype) && (i == 0 ||
-                                                       bFreeEnergy_q)) ||
-            (i >= DO_Q && EVDW_PME(ir->vdwtype) && (i == 2 ||
-                                                    bFreeEnergy_lj ||
-                                                    ir->ljpme_combination_rule == eljpmeLB)))
+        if ((i <  DO_Q && pme->doCoulomb && (i == 0 ||
+                                             bFreeEnergy_q)) ||
+            (i >= DO_Q && pme->doLJ && (i == 2 ||
+                                        bFreeEnergy_lj ||
+                                        ir->ljpme_combination_rule == eljpmeLB)))
         {
             pmegrids_init(&pme->pmegrid[i],
                           pme->pmegrid_nx, pme->pmegrid_ny, pme->pmegrid_nz,
@@ -795,7 +819,9 @@ int gmx_pme_reinit(struct gmx_pme_t **pmedata,
                    t_commrec *        cr,
                    struct gmx_pme_t * pme_src,
                    const t_inputrec * ir,
-                   ivec               grid_size)
+                   ivec               grid_size,
+                   real               ewaldcoeff_q,
+                   real               ewaldcoeff_lj)
 {
     t_inputrec irc;
     int        homenr;
@@ -816,7 +842,7 @@ int gmx_pme_reinit(struct gmx_pme_t **pmedata,
     }
 
     ret = gmx_pme_init(pmedata, cr, pme_src->nnodes_major, pme_src->nnodes_minor,
-                       &irc, homenr, pme_src->bFEP_q, pme_src->bFEP_lj, FALSE, pme_src->nthread);
+                       &irc, homenr, pme_src->bFEP_q, pme_src->bFEP_lj, FALSE, ewaldcoeff_q, ewaldcoeff_lj, pme_src->nthread);
 
     if (ret == 0)
     {
@@ -901,8 +927,7 @@ int gmx_pme_do(struct gmx_pme_t *pme,
                matrix box,      t_commrec *cr,
                int  maxshift_x, int maxshift_y,
                t_nrnb *nrnb,    gmx_wallcycle_t wcycle,
-               matrix vir_q,    real ewaldcoeff_q,
-               matrix vir_lj,   real ewaldcoeff_lj,
+               matrix vir_q,    matrix vir_lj,
                real *energy_q,  real *energy_lj,
                real lambda_q,   real lambda_lj,
                real *dvdlambda_q, real *dvdlambda_lj,
@@ -971,7 +996,7 @@ int gmx_pme_do(struct gmx_pme_t *pme,
      * that don't yet have them.
      */
 
-    bDoSplines = pme->bFEP || ((flags & GMX_PME_DO_COULOMB) && (flags & GMX_PME_DO_LJ));
+    bDoSplines = pme->bFEP || (pme->doCoulomb && pme->doLJ);
 
     /* We need a maximum of four separate PME calculations:
      * grid_index=0: Coulomb PME with charges from state A
@@ -992,9 +1017,9 @@ int gmx_pme_do(struct gmx_pme_t *pme,
          * If grid_index < 2 we should be doing electrostatic PME
          * If grid_index >= 2 we should be doing LJ-PME
          */
-        if ((grid_index <  DO_Q && (!(flags & GMX_PME_DO_COULOMB) ||
+        if ((grid_index <  DO_Q && (!pme->doCoulomb ||
                                     (grid_index == 1 && !pme->bFEP_q))) ||
-            (grid_index >= DO_Q && (!(flags & GMX_PME_DO_LJ) ||
+            (grid_index >= DO_Q && (!pme->doLJ ||
                                     (grid_index == 3 && !pme->bFEP_lj))))
         {
             continue;
@@ -1119,7 +1144,7 @@ int gmx_pme_do(struct gmx_pme_t *pme,
                     if (grid_index < DO_Q)
                     {
                         loop_count =
-                            solve_pme_yzx(pme, cfftgrid, ewaldcoeff_q,
+                            solve_pme_yzx(pme, cfftgrid,
                                           box[XX][XX]*box[YY][YY]*box[ZZ][ZZ],
                                           bCalcEnerVir,
                                           pme->nthread, thread);
@@ -1127,7 +1152,7 @@ int gmx_pme_do(struct gmx_pme_t *pme,
                     else
                     {
                         loop_count =
-                            solve_pme_lj_yzx(pme, &cfftgrid, FALSE, ewaldcoeff_lj,
+                            solve_pme_lj_yzx(pme, &cfftgrid, FALSE,
                                              box[XX][XX]*box[YY][YY]*box[ZZ][ZZ],
                                              bCalcEnerVir,
                                              pme->nthread, thread);
@@ -1245,7 +1270,7 @@ int gmx_pme_do(struct gmx_pme_t *pme,
     /* For Lorentz-Berthelot combination rules in LJ-PME, we need to calculate
      * seven terms. */
 
-    if ((flags & GMX_PME_DO_LJ) && pme->ljpme_combination_rule == eljpmeLB)
+    if (pme->doLJ && pme->ljpme_combination_rule == eljpmeLB)
     {
         /* Loop over A- and B-state if we are doing FEP */
         for (fep_state = 0; fep_state < fep_states_lj; ++fep_state)
@@ -1398,7 +1423,7 @@ int gmx_pme_do(struct gmx_pme_t *pme,
                         }
 
                         loop_count =
-                            solve_pme_lj_yzx(pme, &pme->cfftgrid[2], TRUE, ewaldcoeff_lj,
+                            solve_pme_lj_yzx(pme, &pme->cfftgrid[2], TRUE,
                                              box[XX][XX]*box[YY][YY]*box[ZZ][ZZ],
                                              bCalcEnerVir,
                                              pme->nthread, thread);
@@ -1423,7 +1448,7 @@ int gmx_pme_do(struct gmx_pme_t *pme,
 
             if (bBackFFT)
             {
-                bFirst = !(flags & GMX_PME_DO_COULOMB);
+                bFirst = !pme->doCoulomb;
                 calc_initial_lb_coeffs(pme, local_c6, local_sigma);
                 for (grid_index = 8; grid_index >= 2; --grid_index)
                 {
@@ -1541,7 +1566,7 @@ int gmx_pme_do(struct gmx_pme_t *pme,
 
     if (bCalcEnerVir)
     {
-        if (flags & GMX_PME_DO_COULOMB)
+        if (pme->doCoulomb)
         {
             if (!pme->bFEP_q)
             {
@@ -1571,7 +1596,7 @@ int gmx_pme_do(struct gmx_pme_t *pme,
             *energy_q = 0;
         }
 
-        if (flags & GMX_PME_DO_LJ)
+        if (pme->doLJ)
         {
             if (!pme->bFEP_lj)
             {
@@ -1602,3 +1627,39 @@ int gmx_pme_do(struct gmx_pme_t *pme,
     }
     return 0;
 }
+
+int gmx_pme_destroy(struct gmx_pme_t **pmedata)
+{
+    struct gmx_pme_t *pme = *pmedata;
+
+    sfree(pme->nnx);
+    sfree(pme->nny);
+    sfree(pme->nnz);
+
+    for (int i = 0; i < pme->ngrids; ++i)
+    {
+        pmegrids_destroy(&pme->pmegrid[i]);
+        gmx_parallel_3dfft_destroy(pme->pfft_setup[i]);
+    }
+
+    for (int i = 0; i < pme->ndecompdim; i++)
+    {
+        destroy_atomcomm(&pme->atc[i]);
+    }
+
+    sfree(pme->lb_buf1);
+    sfree(pme->lb_buf2);
+
+    sfree(pme->bufv);
+    sfree(pme->bufr);
+
+    pme_free_all_work(&pme->solve_work, pme->nthread);
+
+    sfree(pme->sum_qgrid_tmp);
+    sfree(pme->sum_qgrid_dd_tmp);
+
+    sfree(*pmedata);
+    *pmedata = NULL;
+
+    return 0;
+}
index 9f4f06375bfad374afaff5fd91d9e976b0921f1c..2712cc7e56bdbdc6fc8f381897c14642e6b55220 100644 (file)
@@ -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, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, 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.
@@ -74,13 +74,15 @@ int gmx_pme_init(struct gmx_pme_t **pmedata, struct t_commrec *cr,
                  int nnodes_major, int nnodes_minor,
                  t_inputrec *ir, int homenr,
                  gmx_bool bFreeEnergy_q, gmx_bool bFreeEnergy_lj,
-                 gmx_bool bReproducible, int nthread);
+                 gmx_bool bReproducible,
+                 real ewaldcoeff_q, real ewaldcoeff_lj,
+                 int nthread);
 
-/*! \brief Destroy the pme data structures resepectively.
+/*! \brief Destroy the PME data structures respectively.
  *
  * \return 0 indicates all well, non zero is an error code.
  */
-int gmx_pme_destroy(FILE *log, struct gmx_pme_t **pmedata);
+int gmx_pme_destroy(struct gmx_pme_t **pmedata);
 
 //@{
 /*! \brief Flag values that control what gmx_pme_do() will calculate
@@ -94,12 +96,6 @@ int gmx_pme_destroy(FILE *log, struct gmx_pme_t **pmedata);
 /* This forces the grid to be backtransformed even without GMX_PME_CALC_F */
 #define GMX_PME_CALC_POT      (1<<4)
 
-/* These values label bits used for sending messages to PME nodes using the
- * routines in pme_pp.c and shouldn't conflict with the flags used there
- */
-#define GMX_PME_DO_COULOMB    (1<<13)
-#define GMX_PME_DO_LJ         (1<<14)
-
 #define GMX_PME_DO_ALL_F  (GMX_PME_SPREAD | GMX_PME_SOLVE | GMX_PME_CALC_F)
 //@}
 
@@ -119,8 +115,7 @@ int gmx_pme_do(struct gmx_pme_t *pme,
                matrix box,      t_commrec *cr,
                int  maxshift_x, int maxshift_y,
                t_nrnb *nrnb,    gmx_wallcycle_t wcycle,
-               matrix vir_q,    real ewaldcoeff_q,
-               matrix vir_lj,   real ewaldcoeff_lj,
+               matrix vir_q,    matrix vir_lj,
                real *energy_q,  real *energy_lj,
                real lambda_q,   real lambda_lj,
                real *dvdlambda_q, real *dvdlambda_lj,
@@ -155,9 +150,8 @@ void gmx_pme_send_parameters(struct t_commrec *cr,
 
 /*! \brief Send the coordinates to our PME-only node and request a PME calculation */
 void gmx_pme_send_coordinates(struct t_commrec *cr, matrix box, rvec *x,
-                              gmx_bool bFreeEnergy_q, gmx_bool bFreeEnergy_lj,
                               real lambda_q, real lambda_lj,
-                              gmx_bool bEnerVir, int pme_flags,
+                              gmx_bool bEnerVir,
                               gmx_int64_t step);
 
 /*! \brief Tell our PME-only node to finish */
index ee86ced85eae5838fce51a24f9c59888a411441c..9eede3a3310d99a2c606935122adeddbab856334 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 1991-2003 David van der Spoel, Erik Lindahl, University of Groningen.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, 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.
@@ -111,9 +111,9 @@ struct gmx_fft
 
 
 int
-gmx_fft_init_1d(gmx_fft_t *        pfft,
-                int                nx,
-                gmx_fft_flag       flags)
+gmx_fft_init_1d(gmx_fft_t *             pfft,
+                int                     nx,
+                gmx_fft_flag gmx_unused flags)
 {
     gmx_fft_t      fft;
     int            d;
@@ -187,9 +187,9 @@ gmx_fft_init_1d(gmx_fft_t *        pfft,
 
 
 int
-gmx_fft_init_1d_real(gmx_fft_t *        pfft,
-                     int                nx,
-                     gmx_fft_flag       flags)
+gmx_fft_init_1d_real(gmx_fft_t *             pfft,
+                     int                     nx,
+                     gmx_fft_flag gmx_unused flags)
 {
     gmx_fft_t      fft;
     int            d;
@@ -271,10 +271,10 @@ gmx_fft_init_1d_real(gmx_fft_t *        pfft,
 
 
 int
-gmx_fft_init_2d_real(gmx_fft_t *        pfft,
-                     int                nx,
-                     int                ny,
-                     gmx_fft_flag       flags)
+gmx_fft_init_2d_real(gmx_fft_t *             pfft,
+                     int                     nx,
+                     int                     ny,
+                     gmx_fft_flag gmx_unused flags)
 {
     gmx_fft_t      fft;
     int            d;
index eb07c8ed68a61bd8a974f4a48eb156c2d431cad2..f5ac996264a8e970d39e55393a559f583126c6c5 100644 (file)
@@ -901,6 +901,10 @@ static void do_cpt_header(XDR *xd, gmx_bool bRead, int *file_version,
     {
         do_cpt_int_err(xd, "swap", eSwapCoords, list);
     }
+    else
+    {
+        *eSwapCoords = eswapNO;
+    }
 }
 
 static int do_cpt_footer(XDR *xd, int file_version)
@@ -925,7 +929,7 @@ static int do_cpt_footer(XDR *xd, int file_version)
     return 0;
 }
 
-static int do_cpt_state(XDR *xd, gmx_bool bRead,
+static int do_cpt_state(XDR *xd,
                         int fflags, t_state *state,
                         FILE *list)
 {
@@ -939,11 +943,6 @@ static int do_cpt_state(XDR *xd, gmx_bool bRead,
     nnht  = state->nhchainlength*state->ngtc;
     nnhtp = state->nhchainlength*state->nnhpres;
 
-    if (bRead) /* we need to allocate space for dfhist if we are reading */
-    {
-        init_df_history(&state->dfhist, state->dfhist.nlambda);
-    }
-
     sflags = state->flags;
     for (i = 0; (i < estNR && ret == 0); i++)
     {
@@ -1025,18 +1024,23 @@ static int do_cpt_ekinstate(XDR *xd, int fflags, ekinstate_t *ekins,
 }
 
 
-static int do_cpt_swapstate(XDR *xd, gmx_bool bRead, swapstate_t *swapstate, FILE *list)
+static int do_cpt_swapstate(XDR *xd, gmx_bool bRead,
+                            int eSwapCoords, swapstate_t **swapstatePtr, FILE *list)
 {
-    int ret              = 0;
     int swap_cpt_version = 2;
 
-
-    if (eswapNO == swapstate->eSwapCoords)
+    if (eSwapCoords == eswapNO)
     {
-        return ret;
+        return 0;
     }
 
-    swapstate->bFromCpt = bRead;
+    if (*swapstatePtr == NULL)
+    {
+        snew(*swapstatePtr, 1);
+    }
+    swapstate_t *swapstate = *swapstatePtr;
+    swapstate->bFromCpt    = bRead;
+    swapstate->eSwapCoords = eSwapCoords;
 
     do_cpt_int_err(xd, "swap checkpoint version", &swap_cpt_version, list);
     if (bRead && swap_cpt_version < 2)
@@ -1160,7 +1164,7 @@ static int do_cpt_swapstate(XDR *xd, gmx_bool bRead, swapstate_t *swapstate, FIL
         do_cpt_n_rvecs_err(xd, "Ch1 whole x", swapstate->nat[eChan1], *swapstate->xc_old_whole_p[eChan1], list);
     }
 
-    return ret;
+    return 0;
 }
 
 
@@ -1260,15 +1264,23 @@ static int do_cpt_enerhist(XDR *xd, gmx_bool bRead,
     return ret;
 }
 
-static int do_cpt_df_hist(XDR *xd, int fflags, df_history_t *dfhist, FILE *list)
+static int do_cpt_df_hist(XDR *xd, int fflags, int nlambda, df_history_t **dfhistPtr, FILE *list)
 {
-    int  i, nlambda;
-    int  ret;
+    if (fflags == 0)
+    {
+        return 0;
+    }
 
-    nlambda = dfhist->nlambda;
-    ret     = 0;
+    if (*dfhistPtr == NULL)
+    {
+        snew(*dfhistPtr, 1);
+        (*dfhistPtr)->nlambda = nlambda;
+        init_df_history(*dfhistPtr, nlambda);
+    }
+    df_history_t *dfhist = *dfhistPtr;
+    int           ret    = 0;
 
-    for (i = 0; (i < edfhNR && ret == 0); i++)
+    for (int i = 0; (i < edfhNR && ret == 0); i++)
     {
         if (fflags & (1<<i))
         {
@@ -1304,19 +1316,21 @@ static int do_cpt_df_hist(XDR *xd, int fflags, df_history_t *dfhist, FILE *list)
  * average structure in the .cpt file
  */
 static int do_cpt_EDstate(XDR *xd, gmx_bool bRead,
-                          edsamstate_t *EDstate, FILE *list)
+                          int nED, edsamstate_t **EDstatePtr, FILE *list)
 {
-    int  i;
-    int  ret = 0;
-    char buf[STRLEN];
-
-
-    EDstate->bFromCpt = bRead;
+    if (nED == 0)
+    {
+        return 0;
+    }
 
-    if (EDstate->nED <= 0)
+    if (*EDstatePtr == NULL)
     {
-        return ret;
+        snew(*EDstatePtr, 1);
     }
+    edsamstate_t *EDstate = *EDstatePtr;
+
+    EDstate->bFromCpt     = bRead;
+    EDstate->nED          = nED;
 
     /* When reading, init_edsam has not been called yet,
      * so we have to allocate memory first. */
@@ -1329,8 +1343,10 @@ static int do_cpt_EDstate(XDR *xd, gmx_bool bRead,
     }
 
     /* Read/write the last whole conformation of SREF and SAV for each ED dataset (usually only one) */
-    for (i = 0; i < EDstate->nED; i++)
+    for (int i = 0; i < EDstate->nED; i++)
     {
+        char buf[STRLEN];
+
         /* Reference structure SREF */
         sprintf(buf, "ED%d # of atoms in reference structure", i+1);
         do_cpt_int_err(xd, buf, &EDstate->nref[i], list);
@@ -1360,7 +1376,7 @@ static int do_cpt_EDstate(XDR *xd, gmx_bool bRead,
         }
     }
 
-    return ret;
+    return 0;
 }
 
 
@@ -1585,13 +1601,17 @@ void write_checkpoint(const char *fn, gmx_bool bNumberAndKeep,
 
     ftime   = &(timebuf[0]);
 
+    int nlambda     = (state->dfhist ? state->dfhist->nlambda : 0);
+    int nED         = (state->edsamstate ? state->edsamstate->nED : 0);
+    int eSwapCoords = (state->swapstate ? state->swapstate->eSwapCoords : eswapNO);
+
     do_cpt_header(gmx_fio_getxdr(fp), FALSE, &file_version,
                   &version, &btime, &buser, &bhost, &double_prec, &fprog, &ftime,
                   &eIntegrator, &simulation_part, &step, &t, &nppnodes,
                   DOMAINDECOMP(cr) ? domdecCells : NULL, &npmenodes,
                   &state->natoms, &state->ngtc, &state->nnhpres,
-                  &state->nhchainlength, &(state->dfhist.nlambda), &state->flags, &flags_eks, &flags_enh, &flags_dfh,
-                  &state->edsamstate.nED, &state->swapstate.eSwapCoords,
+                  &state->nhchainlength, &nlambda, &state->flags, &flags_eks, &flags_enh, &flags_dfh,
+                  &nED, &eSwapCoords,
                   NULL);
 
     sfree(version);
@@ -1600,12 +1620,12 @@ void write_checkpoint(const char *fn, gmx_bool bNumberAndKeep,
     sfree(bhost);
     sfree(fprog);
 
-    if ((do_cpt_state(gmx_fio_getxdr(fp), FALSE, state->flags, state, NULL) < 0)        ||
+    if ((do_cpt_state(gmx_fio_getxdr(fp), state->flags, state, NULL) < 0)        ||
         (do_cpt_ekinstate(gmx_fio_getxdr(fp), flags_eks, &state->ekinstate, NULL) < 0) ||
         (do_cpt_enerhist(gmx_fio_getxdr(fp), FALSE, flags_enh, state->enerhist, NULL) < 0)  ||
-        (do_cpt_df_hist(gmx_fio_getxdr(fp), flags_dfh, &state->dfhist, NULL) < 0)  ||
-        (do_cpt_EDstate(gmx_fio_getxdr(fp), FALSE, &state->edsamstate, NULL) < 0)      ||
-        (do_cpt_swapstate(gmx_fio_getxdr(fp), FALSE, &state->swapstate, NULL) < 0) ||
+        (do_cpt_df_hist(gmx_fio_getxdr(fp), flags_dfh, nlambda, &state->dfhist, NULL) < 0)  ||
+        (do_cpt_EDstate(gmx_fio_getxdr(fp), FALSE, nED, &state->edsamstate, NULL) < 0)      ||
+        (do_cpt_swapstate(gmx_fio_getxdr(fp), FALSE, eSwapCoords, &state->swapstate, NULL) < 0) ||
         (do_cpt_files(gmx_fio_getxdr(fp), FALSE, &outputfiles, &noutputfiles, NULL,
                       file_version) < 0))
     {
@@ -1862,6 +1882,7 @@ static void read_checkpoint(const char *fn, FILE **pfplog,
     int                  eIntegrator_f, nppnodes_f, npmenodes_f;
     ivec                 dd_nc_f;
     int                  natoms, ngtc, nnhpres, nhchainlength, nlambda, fflags, flags_eks, flags_enh, flags_dfh;
+    int                  nED, eSwapCoords;
     int                  d;
     int                  ret;
     gmx_file_position_t *outputfiles;
@@ -1893,7 +1914,7 @@ static void read_checkpoint(const char *fn, FILE **pfplog,
                   &nppnodes_f, dd_nc_f, &npmenodes_f,
                   &natoms, &ngtc, &nnhpres, &nhchainlength, &nlambda,
                   &fflags, &flags_eks, &flags_enh, &flags_dfh,
-                  &state->edsamstate.nED, &state->swapstate.eSwapCoords, NULL);
+                  &nED, &eSwapCoords, NULL);
 
     if (bAppendOutputFiles &&
         file_version >= 13 && double_prec != GMX_DOUBLE)
@@ -1937,9 +1958,10 @@ static void read_checkpoint(const char *fn, FILE **pfplog,
         gmx_fatal(FARGS, "Checkpoint file is for a system of %d NH-pressure-coupling variables, while the current system consists of %d NH-pressure-coupling variables", nnhpres, state->nnhpres);
     }
 
-    if (nlambda != state->dfhist.nlambda)
+    int nlambdaHistory = (state->dfhist ? state->dfhist->nlambda : 0);
+    if (nlambda != nlambdaHistory)
     {
-        gmx_fatal(FARGS, "Checkpoint file is for a system with %d lambda states, while the current system consists of %d lambda states", nlambda, state->dfhist.nlambda);
+        gmx_fatal(FARGS, "Checkpoint file is for a system with %d lambda states, while the current system consists of %d lambda states", nlambda, nlambdaHistory);
     }
 
     init_gtc_state(state, state->ngtc, state->nnhpres, nhchainlength); /* need to keep this here to keep the tpr format working */
@@ -2026,7 +2048,7 @@ static void read_checkpoint(const char *fn, FILE **pfplog,
                         reproducibilityRequested);
         }
     }
-    ret             = do_cpt_state(gmx_fio_getxdr(fp), TRUE, fflags, state, NULL);
+    ret             = do_cpt_state(gmx_fio_getxdr(fp), fflags, state, NULL);
     *init_fep_state = state->fep_state;  /* there should be a better way to do this than setting it here.
                                             Investigate for 5.0. */
     if (ret)
@@ -2061,19 +2083,19 @@ static void read_checkpoint(const char *fn, FILE **pfplog,
         state->enerhist->nsum_sim = *step;
     }
 
-    ret = do_cpt_df_hist(gmx_fio_getxdr(fp), flags_dfh, &state->dfhist, NULL);
+    ret = do_cpt_df_hist(gmx_fio_getxdr(fp), flags_dfh, nlambda, &state->dfhist, NULL);
     if (ret)
     {
         cp_error();
     }
 
-    ret = do_cpt_EDstate(gmx_fio_getxdr(fp), TRUE, &state->edsamstate, NULL);
+    ret = do_cpt_EDstate(gmx_fio_getxdr(fp), TRUE, nED, &state->edsamstate, NULL);
     if (ret)
     {
         cp_error();
     }
 
-    ret = do_cpt_swapstate(gmx_fio_getxdr(fp), TRUE, &state->swapstate, NULL);
+    ret = do_cpt_swapstate(gmx_fio_getxdr(fp), TRUE, eSwapCoords, &state->swapstate, NULL);
     if (ret)
     {
         cp_error();
@@ -2290,9 +2312,11 @@ void read_checkpoint_part_and_step(const char  *filename,
     int       eIntegrator;
     int       nppnodes, npme;
     ivec      dd_nc;
+    int       nlambda;
     int       flags_eks, flags_enh, flags_dfh;
     double    t;
     t_state   state;
+    int       nED, eSwapCoords;
     t_fileio *fp;
 
     if (filename == NULL ||
@@ -2312,8 +2336,8 @@ void read_checkpoint_part_and_step(const char  *filename,
                   &version, &btime, &buser, &bhost, &double_prec, &fprog, &ftime,
                   &eIntegrator, simulation_part, step, &t, &nppnodes, dd_nc, &npme,
                   &state.natoms, &state.ngtc, &state.nnhpres, &state.nhchainlength,
-                  &(state.dfhist.nlambda), &state.flags, &flags_eks, &flags_enh, &flags_dfh,
-                  &state.edsamstate.nED, &state.swapstate.eSwapCoords, NULL);
+                  &nlambda, &state.flags, &flags_eks, &flags_enh, &flags_dfh,
+                  &nED, &eSwapCoords, NULL);
 
     gmx_fio_close(fp);
 }
@@ -2328,7 +2352,9 @@ static void read_checkpoint_data(t_fileio *fp, int *simulation_part,
     int                  eIntegrator;
     int                  nppnodes, npme;
     ivec                 dd_nc;
+    int                  nlambda;
     int                  flags_eks, flags_enh, flags_dfh;
+    int                  nED, eSwapCoords;
     int                  nfiles_loc;
     gmx_file_position_t *files_loc = NULL;
     int                  ret;
@@ -2337,10 +2363,10 @@ static void read_checkpoint_data(t_fileio *fp, int *simulation_part,
                   &version, &btime, &buser, &bhost, &double_prec, &fprog, &ftime,
                   &eIntegrator, simulation_part, step, t, &nppnodes, dd_nc, &npme,
                   &state->natoms, &state->ngtc, &state->nnhpres, &state->nhchainlength,
-                  &(state->dfhist.nlambda), &state->flags, &flags_eks, &flags_enh, &flags_dfh,
-                  &state->edsamstate.nED, &state->swapstate.eSwapCoords, NULL);
+                  &nlambda, &state->flags, &flags_eks, &flags_enh, &flags_dfh,
+                  &nED, &eSwapCoords, NULL);
     ret =
-        do_cpt_state(gmx_fio_getxdr(fp), TRUE, state->flags, state, NULL);
+        do_cpt_state(gmx_fio_getxdr(fp), state->flags, state, NULL);
     if (ret)
     {
         cp_error();
@@ -2356,19 +2382,19 @@ static void read_checkpoint_data(t_fileio *fp, int *simulation_part,
     {
         cp_error();
     }
-    ret = do_cpt_df_hist(gmx_fio_getxdr(fp), flags_dfh, &state->dfhist, NULL);
+    ret = do_cpt_df_hist(gmx_fio_getxdr(fp), flags_dfh, nlambda, &state->dfhist, NULL);
     if (ret)
     {
         cp_error();
     }
 
-    ret = do_cpt_EDstate(gmx_fio_getxdr(fp), TRUE, &state->edsamstate, NULL);
+    ret = do_cpt_EDstate(gmx_fio_getxdr(fp), TRUE, nED, &state->edsamstate, NULL);
     if (ret)
     {
         cp_error();
     }
 
-    ret = do_cpt_swapstate(gmx_fio_getxdr(fp), TRUE, &state->swapstate, NULL);
+    ret = do_cpt_swapstate(gmx_fio_getxdr(fp), TRUE, eSwapCoords, &state->swapstate, NULL);
     if (ret)
     {
         cp_error();
@@ -2481,7 +2507,9 @@ void list_checkpoint(const char *fn, FILE *out)
     double               t;
     ivec                 dd_nc;
     t_state              state;
+    int                  nlambda;
     int                  flags_eks, flags_enh, flags_dfh;
+    int                  nED, eSwapCoords;
     int                  ret;
     gmx_file_position_t *outputfiles;
     int                  nfiles;
@@ -2493,10 +2521,10 @@ void list_checkpoint(const char *fn, FILE *out)
                   &version, &btime, &buser, &bhost, &double_prec, &fprog, &ftime,
                   &eIntegrator, &simulation_part, &step, &t, &nppnodes, dd_nc, &npme,
                   &state.natoms, &state.ngtc, &state.nnhpres, &state.nhchainlength,
-                  &(state.dfhist.nlambda), &state.flags,
-                  &flags_eks, &flags_enh, &flags_dfh, &state.edsamstate.nED,
-                  &state.swapstate.eSwapCoords, out);
-    ret = do_cpt_state(gmx_fio_getxdr(fp), TRUE, state.flags, &state, out);
+                  &nlambda, &state.flags,
+                  &flags_eks, &flags_enh, &flags_dfh, &nED, &eSwapCoords,
+                  out);
+    ret = do_cpt_state(gmx_fio_getxdr(fp), state.flags, &state, out);
     if (ret)
     {
         cp_error();
@@ -2512,17 +2540,17 @@ void list_checkpoint(const char *fn, FILE *out)
     if (ret == 0)
     {
         ret = do_cpt_df_hist(gmx_fio_getxdr(fp),
-                             flags_dfh, &state.dfhist, out);
+                             flags_dfh, nlambda, &state.dfhist, out);
     }
 
     if (ret == 0)
     {
-        ret = do_cpt_EDstate(gmx_fio_getxdr(fp), TRUE, &state.edsamstate, out);
+        ret = do_cpt_EDstate(gmx_fio_getxdr(fp), TRUE, nED, &state.edsamstate, out);
     }
 
     if (ret == 0)
     {
-        ret = do_cpt_swapstate(gmx_fio_getxdr(fp), TRUE, &state.swapstate, out);
+        ret = do_cpt_swapstate(gmx_fio_getxdr(fp), TRUE, eSwapCoords, &state.swapstate, out);
     }
 
     if (ret == 0)
index 48d4b7bc98f197a227ba369b5104ab4706e765f7..7ff5840ea994b47d17351ba626716309ed6b763a 100644 (file)
@@ -52,6 +52,7 @@
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/topology/topology.h"
+#include "gromacs/utility/compare.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
 #include "gromacs/utility/gmxassert.h"
@@ -1246,3 +1247,364 @@ void get_enx_state(const char *fn, real t, const gmx_groups_t *groups, t_inputre
     free_enxframe(fr);
     sfree(fr);
 }
+
+static real ener_tensor_diag(int n, int *ind1, int *ind2,
+                             gmx_enxnm_t *enm1,
+                             int *tensi, int i,
+                             t_energy e1[], t_energy e2[])
+{
+    int    d1, d2;
+    int    j;
+    real   prod1, prod2;
+    int    nfound;
+    size_t len;
+
+    d1 = tensi[i]/DIM;
+    d2 = tensi[i] - d1*DIM;
+
+    /* Find the diagonal elements d1 and d2 */
+    len    = std::strlen(enm1[ind1[i]].name);
+    prod1  = 1;
+    prod2  = 1;
+    nfound = 0;
+    for (j = 0; j < n; j++)
+    {
+        if (tensi[j] >= 0 &&
+            std::strlen(enm1[ind1[j]].name) == len &&
+            std::strncmp(enm1[ind1[i]].name, enm1[ind1[j]].name, len-2) == 0 &&
+            (tensi[j] == d1*DIM+d1 || tensi[j] == d2*DIM+d2))
+        {
+            prod1 *= fabs(e1[ind1[j]].e);
+            prod2 *= fabs(e2[ind2[j]].e);
+            nfound++;
+        }
+    }
+
+    if (nfound == 2)
+    {
+        return 0.5*(std::sqrt(prod1) + std::sqrt(prod2));
+    }
+    else
+    {
+        return 0;
+    }
+}
+
+static gmx_bool enernm_equal(const char *nm1, const char *nm2)
+{
+    int len1, len2;
+
+    len1 = std::strlen(nm1);
+    len2 = std::strlen(nm2);
+
+    /* Remove " (bar)" at the end of a name */
+    if (len1 > 6 && std::strcmp(nm1+len1-6, " (bar)") == 0)
+    {
+        len1 -= 6;
+    }
+    if (len2 > 6 && std::strcmp(nm2+len2-6, " (bar)") == 0)
+    {
+        len2 -= 6;
+    }
+
+    return (len1 == len2 && gmx_strncasecmp(nm1, nm2, len1) == 0);
+}
+
+static void cmp_energies(FILE *fp, int step1, int step2,
+                         t_energy e1[], t_energy e2[],
+                         gmx_enxnm_t *enm1,
+                         real ftol, real abstol,
+                         int nre, int *ind1, int *ind2, int maxener)
+{
+    int   i, ii;
+    int  *tensi, len, d1, d2;
+    real  ftol_i, abstol_i;
+
+    snew(tensi, maxener);
+    /* Check for tensor elements ending on "-XX", "-XY", ... , "-ZZ" */
+    for (i = 0; (i < maxener); i++)
+    {
+        ii       = ind1[i];
+        tensi[i] = -1;
+        len      = std::strlen(enm1[ii].name);
+        if (len > 3 && enm1[ii].name[len-3] == '-')
+        {
+            d1 = enm1[ii].name[len-2] - 'X';
+            d2 = enm1[ii].name[len-1] - 'X';
+            if (d1 >= 0 && d1 < DIM &&
+                d2 >= 0 && d2 < DIM)
+            {
+                tensi[i] = d1*DIM + d2;
+            }
+        }
+    }
+
+    for (i = 0; (i < maxener); i++)
+    {
+        /* Check if this is an off-diagonal tensor element */
+        if (tensi[i] >= 0 && tensi[i] != 0 && tensi[i] != 4 && tensi[i] != 8)
+        {
+            /* Turn on the relative tolerance check (4 is maximum relative diff.) */
+            ftol_i = 5;
+            /* Do the relative tolerance through an absolute tolerance times
+             * the size of diagonal components of the tensor.
+             */
+            abstol_i = ftol*ener_tensor_diag(nre, ind1, ind2, enm1, tensi, i, e1, e2);
+            if (debug)
+            {
+                fprintf(debug, "tensor '%s' val %f diag %f\n",
+                        enm1[i].name, e1[i].e, abstol_i/ftol);
+            }
+            if (abstol_i > 0)
+            {
+                /* We found a diagonal, we need to check with the minimum tolerance */
+                abstol_i = std::min(abstol_i, abstol);
+            }
+            else
+            {
+                /* We did not find a diagonal, ignore the relative tolerance check */
+                abstol_i = abstol;
+            }
+        }
+        else
+        {
+            ftol_i   = ftol;
+            abstol_i = abstol;
+        }
+        if (!equal_real(e1[ind1[i]].e, e2[ind2[i]].e, ftol_i, abstol_i))
+        {
+            fprintf(fp, "%-15s  step %3d:  %12g,  step %3d: %12g\n",
+                    enm1[ind1[i]].name,
+                    step1, e1[ind1[i]].e,
+                    step2, e2[ind2[i]].e);
+        }
+    }
+
+    sfree(tensi);
+}
+
+#if 0
+static void cmp_disres(t_enxframe *fr1, t_enxframe *fr2, real ftol, real abstol)
+{
+    int  i;
+    char bav[64], bt[64], bs[22];
+
+    cmp_int(stdout, "ndisre", -1, fr1->ndisre, fr2->ndisre);
+    if ((fr1->ndisre == fr2->ndisre) && (fr1->ndisre > 0))
+    {
+        sprintf(bav, "step %s: disre rav", gmx_step_str(fr1->step, bs));
+        sprintf(bt, "step %s: disre  rt", gmx_step_str(fr1->step, bs));
+        for (i = 0; (i < fr1->ndisre); i++)
+        {
+            cmp_real(stdout, bav, i, fr1->disre_rm3tav[i], fr2->disre_rm3tav[i], ftol, abstol);
+            cmp_real(stdout, bt, i, fr1->disre_rt[i], fr2->disre_rt[i], ftol, abstol);
+        }
+    }
+}
+#endif
+
+static void cmp_eblocks(t_enxframe *fr1, t_enxframe *fr2, real ftol, real abstol)
+{
+    int  i, j, k;
+    char buf[64], bs[22];
+
+    cmp_int(stdout, "nblock", -1, fr1->nblock, fr2->nblock);
+    if ((fr1->nblock == fr2->nblock) && (fr1->nblock > 0))
+    {
+        for (j = 0; (j < fr1->nblock); j++)
+        {
+            t_enxblock *b1, *b2; /* convenience vars */
+
+            b1 = &(fr1->block[j]);
+            b2 = &(fr2->block[j]);
+
+            sprintf(buf, "step %s: block[%d]", gmx_step_str(fr1->step, bs), j);
+            cmp_int(stdout, buf, -1, b1->nsub, b2->nsub);
+            cmp_int(stdout, buf, -1, b1->id, b2->id);
+
+            if ( (b1->nsub == b2->nsub) && (b1->id == b2->id) )
+            {
+                for (i = 0; i < b1->nsub; i++)
+                {
+                    t_enxsubblock *s1, *s2;
+
+                    s1 = &(b1->sub[i]);
+                    s2 = &(b2->sub[i]);
+
+                    cmp_int(stdout, buf, -1, (int)s1->type, (int)s2->type);
+                    cmp_int64(stdout, buf, s1->nr, s2->nr);
+
+                    if ((s1->type == s2->type) && (s1->nr == s2->nr))
+                    {
+                        switch (s1->type)
+                        {
+                            case xdr_datatype_float:
+                                for (k = 0; k < s1->nr; k++)
+                                {
+                                    cmp_float(stdout, buf, i,
+                                              s1->fval[k], s2->fval[k],
+                                              ftol, abstol);
+                                }
+                                break;
+                            case xdr_datatype_double:
+                                for (k = 0; k < s1->nr; k++)
+                                {
+                                    cmp_double(stdout, buf, i,
+                                               s1->dval[k], s2->dval[k],
+                                               ftol, abstol);
+                                }
+                                break;
+                            case xdr_datatype_int:
+                                for (k = 0; k < s1->nr; k++)
+                                {
+                                    cmp_int(stdout, buf, i,
+                                            s1->ival[k], s2->ival[k]);
+                                }
+                                break;
+                            case xdr_datatype_int64:
+                                for (k = 0; k < s1->nr; k++)
+                                {
+                                    cmp_int64(stdout, buf,
+                                              s1->lval[k], s2->lval[k]);
+                                }
+                                break;
+                            case xdr_datatype_char:
+                                for (k = 0; k < s1->nr; k++)
+                                {
+                                    cmp_uc(stdout, buf, i,
+                                           s1->cval[k], s2->cval[k]);
+                                }
+                                break;
+                            case xdr_datatype_string:
+                                for (k = 0; k < s1->nr; k++)
+                                {
+                                    cmp_str(stdout, buf, i,
+                                            s1->sval[k], s2->sval[k]);
+                                }
+                                break;
+                            default:
+                                gmx_incons("Unknown data type!!");
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+void comp_enx(const char *fn1, const char *fn2, real ftol, real abstol, const char *lastener)
+{
+    int            nre, nre1, nre2;
+    ener_file_t    in1, in2;
+    int            i, j, maxener, *ind1, *ind2, *have;
+    gmx_enxnm_t   *enm1 = NULL, *enm2 = NULL;
+    t_enxframe    *fr1, *fr2;
+    gmx_bool       b1, b2;
+
+    fprintf(stdout, "comparing energy file %s and %s\n\n", fn1, fn2);
+
+    in1 = open_enx(fn1, "r");
+    in2 = open_enx(fn2, "r");
+    do_enxnms(in1, &nre1, &enm1);
+    do_enxnms(in2, &nre2, &enm2);
+    if (nre1 != nre2)
+    {
+        fprintf(stdout, "There are %d and %d terms in the energy files\n\n",
+                nre1, nre2);
+    }
+    else
+    {
+        fprintf(stdout, "There are %d terms in the energy files\n\n", nre1);
+    }
+
+    snew(ind1, nre1);
+    snew(ind2, nre2);
+    snew(have, nre2);
+    nre = 0;
+    for (i = 0; i < nre1; i++)
+    {
+        for (j = 0; j < nre2; j++)
+        {
+            if (enernm_equal(enm1[i].name, enm2[j].name))
+            {
+                ind1[nre] = i;
+                ind2[nre] = j;
+                have[j]   = 1;
+                nre++;
+                break;
+            }
+        }
+        if (nre == 0 || ind1[nre-1] != i)
+        {
+            cmp_str(stdout, "enm", i, enm1[i].name, "-");
+        }
+    }
+    for (i = 0; i < nre2; i++)
+    {
+        if (have[i] == 0)
+        {
+            cmp_str(stdout, "enm", i, "-", enm2[i].name);
+        }
+    }
+
+    maxener = nre;
+    for (i = 0; i < nre; i++)
+    {
+        if ((lastener != NULL) && (std::strstr(enm1[i].name, lastener) != NULL))
+        {
+            maxener = i+1;
+            break;
+        }
+    }
+
+    fprintf(stdout, "There are %d terms to compare in the energy files\n\n",
+            maxener);
+
+    for (i = 0; i < maxener; i++)
+    {
+        cmp_str(stdout, "unit", i, enm1[ind1[i]].unit, enm2[ind2[i]].unit);
+    }
+
+    snew(fr1, 1);
+    snew(fr2, 1);
+    do
+    {
+        b1 = do_enx(in1, fr1);
+        b2 = do_enx(in2, fr2);
+        if (b1 && !b2)
+        {
+            fprintf(stdout, "\nEnd of file on %s but not on %s\n", fn2, fn1);
+        }
+        else if (!b1 && b2)
+        {
+            fprintf(stdout, "\nEnd of file on %s but not on %s\n", fn1, fn2);
+        }
+        else if (!b1 && !b2)
+        {
+            fprintf(stdout, "\nFiles read successfully\n");
+        }
+        else
+        {
+            cmp_real(stdout, "t", -1, fr1->t, fr2->t, ftol, abstol);
+            cmp_int(stdout, "step", -1, fr1->step, fr2->step);
+            /* We don't want to print the nre mismatch for every frame */
+            /* cmp_int(stdout,"nre",-1,fr1->nre,fr2->nre); */
+            if ((fr1->nre >= nre) && (fr2->nre >= nre))
+            {
+                cmp_energies(stdout, fr1->step, fr1->step, fr1->ener, fr2->ener,
+                             enm1, ftol, abstol, nre, ind1, ind2, maxener);
+            }
+            /*cmp_disres(fr1,fr2,ftol,abstol);*/
+            cmp_eblocks(fr1, fr2, ftol, abstol);
+        }
+    }
+    while (b1 && b2);
+
+    close_enx(in1);
+    close_enx(in2);
+
+    free_enxframe(fr2);
+    sfree(fr2);
+    free_enxframe(fr1);
+    sfree(fr1);
+}
index c9c9807885635aca5d040014a502d9f69f4f68d6..f9ccc534111858a9a5a5ae7b96f950d75125a05a 100644 (file)
 #include "gromacs/mdtypes/state.h"
 #include "gromacs/trajectory/energy.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 struct gmx_groups_t;
 struct t_fileio;
 struct t_inputrec;
@@ -216,10 +212,8 @@ t_enxblock *find_block_id_enxframe(t_enxframe *ef, int id, t_enxblock *prev);
    subbblocks. */
 void add_subblocks_enxblock(t_enxblock *eb, int n);
 
-
-
-#ifdef __cplusplus
-}
-#endif
+void comp_enx(const char *fn1, const char *fn2, real ftol, real abstol,
+              const char *lastener);
+/* Compare two binary energy files */
 
 #endif
index 2863a9795d7cd1b5e4d893a94dbbb0aa4dbeda27..aff4ee969be653ba30b7488b583ea21fd72079de 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016, 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.
@@ -181,7 +181,7 @@ class StructureIORoundtripTest : public gmx::test::StringTestBase,
             refX_.reserve(atomCount);
             for (int i = 0; i < atomCount; ++i)
             {
-                refX_.push_back(gmx::RVec(i%4, i/4, (i/2)%3));
+                refX_.emplace_back(i%4, i/4, (i/2)%3);
             }
         }
 
index 4b67fc762aa96042d9c256065612b6fd6215433c..d46d4c7483e09e0426db5b5e6c74f9598d2a3df2 100644 (file)
@@ -146,7 +146,7 @@ static const int tpx_generation = 26;
 /* This number should be the most recent backwards incompatible version
  * I.e., if this number is 9, we cannot read tpx version 9 with this code.
  */
-static const int tpx_incompatible_version = 9;
+static const int tpx_incompatible_version = 30; // GMX3.2 has version 31
 
 
 
@@ -162,24 +162,16 @@ typedef struct {
  * 2. ascending file version number
  */
 static const t_ftupd ftupd[] = {
-    { 20, F_CUBICBONDS        },
-    { 20, F_CONNBONDS         },
-    { 20, F_HARMONIC          },
     { 34, F_FENEBONDS         },
     { 43, F_TABBONDS          },
     { 43, F_TABBONDSNC        },
     { 70, F_RESTRBONDS        },
     { tpxv_RestrictedBendingAndCombinedAngleTorsionPotentials, F_RESTRANGLES },
     { 76, F_LINEAR_ANGLES     },
-    { 30, F_CROSS_BOND_BONDS  },
-    { 30, F_CROSS_BOND_ANGLES },
-    { 30, F_UREY_BRADLEY      },
     { 34, F_QUARTIC_ANGLES    },
     { 43, F_TABANGLES         },
     { tpxv_RestrictedBendingAndCombinedAngleTorsionPotentials, F_RESTRDIHS },
     { tpxv_RestrictedBendingAndCombinedAngleTorsionPotentials, F_CBTDIHS },
-    { 26, F_FOURDIHS          },
-    { 26, F_PIDIHS            },
     { 43, F_TABDIHS           },
     { 65, F_CMAP              },
     { 60, F_GB12              },
@@ -194,18 +186,11 @@ static const t_ftupd ftupd[] = {
     { 32, F_COUL_RECIP        },
     { 93, F_LJ_RECIP          },
     { 46, F_DPD               },
-    { 30, F_POLARIZATION      },
     { 36, F_THOLE_POL         },
     { 90, F_FBPOSRES          },
-    { 22, F_DISRESVIOL        },
-    { 22, F_ORIRES            },
-    { 22, F_ORIRESDEV         },
-    { 26, F_DIHRES            },
-    { 26, F_DIHRESVIOL        },
     { 49, F_VSITE4FDN         },
     { 50, F_VSITEN            },
     { 46, F_COM_PULL          },
-    { 20, F_EQM               },
     { 46, F_ECONSERVED        },
     { 69, F_VTEMP_NOLONGERUSED},
     { 66, F_PDISPCORR         },
@@ -558,14 +543,7 @@ static void do_fepvals(t_fileio *fio, t_lambda *fepvals, gmx_bool bRead, int fil
             fepvals->separate_dvdl[efptFEP] = TRUE;
         }
     }
-    if (file_version >= 13)
-    {
-        gmx_fio_do_real(fio, fepvals->sc_alpha);
-    }
-    else
-    {
-        fepvals->sc_alpha = 0;
-    }
+    gmx_fio_do_real(fio, fepvals->sc_alpha);
     if (file_version >= 38)
     {
         gmx_fio_do_int(fio, fepvals->sc_power);
@@ -582,14 +560,7 @@ static void do_fepvals(t_fileio *fio, t_lambda *fepvals, gmx_bool bRead, int fil
     {
         fepvals->sc_r_power = 6.0;
     }
-    if (file_version >= 15)
-    {
-        gmx_fio_do_real(fio, fepvals->sc_sigma);
-    }
-    else
-    {
-        fepvals->sc_sigma = 0.3;
-    }
+    gmx_fio_do_real(fio, fepvals->sc_sigma);
     if (bRead)
     {
         if (file_version >= 71)
@@ -951,11 +922,9 @@ static void do_swapcoords_tpx(t_fileio *fio, t_swapcoords *swap, gmx_bool bRead,
 static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
                         int file_version, real *fudgeQQ)
 {
-    int      i, j, k, *tmp, idum = 0;
+    int      i, j, k, idum = 0;
     real     rdum, bd_temp;
-    rvec     vdum;
-    gmx_bool bSimAnn, bdum = 0;
-    real     zerotemptime, finish_t, init_temp, finish_temp;
+    gmx_bool bdum = 0;
 
     if (file_version != tpx_version)
     {
@@ -964,11 +933,6 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
                 file_version, tpx_version);
     }
 
-    if (bRead)
-    {
-        init_inputrec(ir);
-    }
-
     if (file_version == 0)
     {
         return;
@@ -986,21 +950,14 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
         ir->nsteps = idum;
     }
 
-    if (file_version > 25)
+    if (file_version >= 62)
     {
-        if (file_version >= 62)
-        {
-            gmx_fio_do_int64(fio, ir->init_step);
-        }
-        else
-        {
-            gmx_fio_do_int(fio, idum);
-            ir->init_step = idum;
-        }
+        gmx_fio_do_int64(fio, ir->init_step);
     }
     else
     {
-        ir->init_step = 0;
+        gmx_fio_do_int(fio, idum);
+        ir->init_step = idum;
     }
 
     if (file_version >= 58)
@@ -1026,10 +983,6 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
          * since we always want it, also without reading the inputrec.
          */
         gmx_fio_do_int(fio, ir->ePBC);
-        if ((file_version <= 15) && (ir->ePBC == 2))
-        {
-            ir->ePBC = epbcNONE;
-        }
         if (file_version >= 45)
         {
             gmx_fio_do_int(fio, ir->bPeriodicMols);
@@ -1091,21 +1044,14 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
     ir->nstcomm = abs(ir->nstcomm);
 
     /* ignore nstcheckpoint */
-    if (file_version > 25 && file_version < tpxv_RemoveObsoleteParameters1)
+    if (file_version < tpxv_RemoveObsoleteParameters1)
     {
         gmx_fio_do_int(fio, idum);
     }
 
     gmx_fio_do_int(fio, ir->nstcgsteep);
 
-    if (file_version >= 30)
-    {
-        gmx_fio_do_int(fio, ir->nbfgscorr);
-    }
-    else if (bRead)
-    {
-        ir->nbfgscorr = 10;
-    }
+    gmx_fio_do_int(fio, ir->nbfgscorr);
 
     gmx_fio_do_int(fio, ir->nstlog);
     gmx_fio_do_int(fio, ir->nstxout);
@@ -1126,15 +1072,6 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
         ir->delta_t = rdum;
     }
     gmx_fio_do_real(fio, ir->x_compression_precision);
-    if (file_version < 19)
-    {
-        gmx_fio_do_int(fio, idum);
-        gmx_fio_do_int(fio, idum);
-    }
-    if (file_version < 18)
-    {
-        gmx_fio_do_int(fio, idum);
-    }
     if (file_version >= 81)
     {
         gmx_fio_do_real(fio, ir->verletbuf_tol);
@@ -1226,31 +1163,13 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
             ir->epsilon_rf = 1.0;
         }
     }
-    if (file_version >= 29)
-    {
-        gmx_fio_do_real(fio, ir->tabext);
-    }
-    else
-    {
-        ir->tabext = 1.0;
-    }
+    gmx_fio_do_real(fio, ir->tabext);
 
-    if (file_version > 25)
-    {
-        gmx_fio_do_int(fio, ir->gb_algorithm);
-        gmx_fio_do_int(fio, ir->nstgbradii);
-        gmx_fio_do_real(fio, ir->rgbradii);
-        gmx_fio_do_real(fio, ir->gb_saltconc);
-        gmx_fio_do_int(fio, ir->implicit_solvent);
-    }
-    else
-    {
-        ir->gb_algorithm     = egbSTILL;
-        ir->nstgbradii       = 1;
-        ir->rgbradii         = 1.0;
-        ir->gb_saltconc      = 0;
-        ir->implicit_solvent = eisNO;
-    }
+    gmx_fio_do_int(fio, ir->gb_algorithm);
+    gmx_fio_do_int(fio, ir->nstgbradii);
+    gmx_fio_do_real(fio, ir->rgbradii);
+    gmx_fio_do_real(fio, ir->gb_saltconc);
+    gmx_fio_do_int(fio, ir->implicit_solvent);
     if (file_version >= 55)
     {
         gmx_fio_do_real(fio, ir->gb_epsilon_solvent);
@@ -1316,28 +1235,8 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
     {
         ir->ewald_rtol_lj = ir->ewald_rtol;
     }
-
-    if (file_version >= 24)
-    {
-        gmx_fio_do_int(fio, ir->ewald_geometry);
-    }
-    else
-    {
-        ir->ewald_geometry = eewg3D;
-    }
-
-    if (file_version <= 17)
-    {
-        ir->epsilon_surface = 0;
-        if (file_version == 17)
-        {
-            gmx_fio_do_int(fio, idum);
-        }
-    }
-    else
-    {
-        gmx_fio_do_real(fio, ir->epsilon_surface);
-    }
+    gmx_fio_do_int(fio, ir->ewald_geometry);
+    gmx_fio_do_real(fio, ir->epsilon_surface);
 
     /* ignore bOptFFT */
     if (file_version < tpxv_RemoveObsoleteParameters1)
@@ -1367,38 +1266,8 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
     {
         ir->nsttcouple = ir->nstcalcenergy;
     }
-    if (file_version <= 15)
-    {
-        gmx_fio_do_int(fio, idum);
-    }
-    if (file_version <= 17)
-    {
-        gmx_fio_do_int(fio, ir->epct);
-        if (file_version <= 15)
-        {
-            if (ir->epct == 5)
-            {
-                ir->epct = epctSURFACETENSION;
-            }
-            gmx_fio_do_int(fio, idum);
-        }
-        ir->epct -= 1;
-        /* we have removed the NO alternative at the beginning */
-        if (ir->epct == -1)
-        {
-            ir->epc  = epcNO;
-            ir->epct = epctISOTROPIC;
-        }
-        else
-        {
-            ir->epc = epcBERENDSEN;
-        }
-    }
-    else
-    {
-        gmx_fio_do_int(fio, ir->epc);
-        gmx_fio_do_int(fio, ir->epct);
-    }
+    gmx_fio_do_int(fio, ir->epc);
+    gmx_fio_do_int(fio, ir->epct);
     if (file_version >= 71)
     {
         gmx_fio_do_int(fio, ir->nstpcouple);
@@ -1408,36 +1277,12 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
         ir->nstpcouple = ir->nstcalcenergy;
     }
     gmx_fio_do_real(fio, ir->tau_p);
-    if (file_version <= 15)
-    {
-        gmx_fio_do_rvec(fio, vdum);
-        clear_mat(ir->ref_p);
-        for (i = 0; i < DIM; i++)
-        {
-            ir->ref_p[i][i] = vdum[i];
-        }
-    }
-    else
-    {
-        gmx_fio_do_rvec(fio, ir->ref_p[XX]);
-        gmx_fio_do_rvec(fio, ir->ref_p[YY]);
-        gmx_fio_do_rvec(fio, ir->ref_p[ZZ]);
-    }
-    if (file_version <= 15)
-    {
-        gmx_fio_do_rvec(fio, vdum);
-        clear_mat(ir->compress);
-        for (i = 0; i < DIM; i++)
-        {
-            ir->compress[i][i] = vdum[i];
-        }
-    }
-    else
-    {
-        gmx_fio_do_rvec(fio, ir->compress[XX]);
-        gmx_fio_do_rvec(fio, ir->compress[YY]);
-        gmx_fio_do_rvec(fio, ir->compress[ZZ]);
-    }
+    gmx_fio_do_rvec(fio, ir->ref_p[XX]);
+    gmx_fio_do_rvec(fio, ir->ref_p[YY]);
+    gmx_fio_do_rvec(fio, ir->ref_p[ZZ]);
+    gmx_fio_do_rvec(fio, ir->compress[XX]);
+    gmx_fio_do_rvec(fio, ir->compress[YY]);
+    gmx_fio_do_rvec(fio, ir->compress[ZZ]);
     if (file_version >= 47)
     {
         gmx_fio_do_int(fio, ir->refcoord_scaling);
@@ -1450,7 +1295,7 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
         clear_rvec(ir->posres_com);
         clear_rvec(ir->posres_comB);
     }
-    if ((file_version > 25) && (file_version < 79))
+    if (file_version < 79)
     {
         gmx_fio_do_int(fio, ir->andersen_seed);
     }
@@ -1458,11 +1303,6 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
     {
         ir->andersen_seed = 0;
     }
-    if (file_version < 26)
-    {
-        gmx_fio_do_gmx_bool(fio, bSimAnn);
-        gmx_fio_do_real(fio, zerotemptime);
-    }
 
     if (file_version < 37)
     {
@@ -1476,10 +1316,6 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
     }
 
     gmx_fio_do_int(fio, ir->efep);
-    if (file_version <= 14 && ir->efep != efepNO)
-    {
-        ir->efep = efepYES;
-    }
     do_fepvals(fio, ir->fepvals, bRead, file_version);
 
     if (file_version >= 79)
@@ -1520,36 +1356,16 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
         gmx_fio_do_int(fio, ir->eDisre);
     }
     gmx_fio_do_int(fio, ir->eDisreWeighting);
-    if (file_version < 22)
-    {
-        if (ir->eDisreWeighting == 0)
-        {
-            ir->eDisreWeighting = edrwEqual;
-        }
-        else
-        {
-            ir->eDisreWeighting = edrwConservative;
-        }
-    }
     gmx_fio_do_gmx_bool(fio, ir->bDisreMixed);
     gmx_fio_do_real(fio, ir->dr_fc);
     gmx_fio_do_real(fio, ir->dr_tau);
     gmx_fio_do_int(fio, ir->nstdisreout);
-    if (file_version >= 22)
-    {
-        gmx_fio_do_real(fio, ir->orires_fc);
-        gmx_fio_do_real(fio, ir->orires_tau);
-        gmx_fio_do_int(fio, ir->nstorireout);
-    }
-    else
-    {
-        ir->orires_fc   = 0;
-        ir->orires_tau  = 0;
-        ir->nstorireout = 0;
-    }
+    gmx_fio_do_real(fio, ir->orires_fc);
+    gmx_fio_do_real(fio, ir->orires_tau);
+    gmx_fio_do_int(fio, ir->nstorireout);
 
     /* ignore dihre_fc */
-    if (file_version >= 26 && file_version < 79)
+    if (file_version < 79)
     {
         gmx_fio_do_real(fio, rdum);
         if (file_version < 56)
@@ -1561,49 +1377,13 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
 
     gmx_fio_do_real(fio, ir->em_stepsize);
     gmx_fio_do_real(fio, ir->em_tol);
-    if (file_version >= 22)
-    {
-        gmx_fio_do_gmx_bool(fio, ir->bShakeSOR);
-    }
-    else if (bRead)
-    {
-        ir->bShakeSOR = TRUE;
-    }
-    if (file_version >= 11)
-    {
-        gmx_fio_do_int(fio, ir->niter);
-    }
-    else if (bRead)
-    {
-        ir->niter = 25;
-        fprintf(stderr, "Note: niter not in run input file, setting it to %d\n",
-                ir->niter);
-    }
-    if (file_version >= 21)
-    {
-        gmx_fio_do_real(fio, ir->fc_stepsize);
-    }
-    else
-    {
-        ir->fc_stepsize = 0;
-    }
+    gmx_fio_do_gmx_bool(fio, ir->bShakeSOR);
+    gmx_fio_do_int(fio, ir->niter);
+    gmx_fio_do_real(fio, ir->fc_stepsize);
     gmx_fio_do_int(fio, ir->eConstrAlg);
     gmx_fio_do_int(fio, ir->nProjOrder);
     gmx_fio_do_real(fio, ir->LincsWarnAngle);
-    if (file_version <= 14)
-    {
-        gmx_fio_do_int(fio, idum);
-    }
-    if (file_version >= 26)
-    {
-        gmx_fio_do_int(fio, ir->nLincsIter);
-    }
-    else if (bRead)
-    {
-        ir->nLincsIter = 1;
-        fprintf(stderr, "Note: nLincsIter not in run input file, setting it to %d\n",
-                ir->nLincsIter);
-    }
+    gmx_fio_do_int(fio, ir->nLincsIter);
     if (file_version < 33)
     {
         gmx_fio_do_real(fio, bd_temp);
@@ -1632,14 +1412,8 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
             clear_rvec(ir->deform[i]);
         }
     }
-    if (file_version >= 14)
-    {
-        gmx_fio_do_real(fio, ir->cos_accel);
-    }
-    else if (bRead)
-    {
-        ir->cos_accel = 0;
-    }
+    gmx_fio_do_real(fio, ir->cos_accel);
+
     gmx_fio_do_int(fio, ir->userint1);
     gmx_fio_do_int(fio, ir->userint2);
     gmx_fio_do_int(fio, ir->userint3);
@@ -1784,20 +1558,7 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
     }
     if (ir->opts.ngtc > 0)
     {
-        if (bRead && file_version < 13)
-        {
-            snew(tmp, ir->opts.ngtc);
-            gmx_fio_ndo_int(fio, tmp, ir->opts.ngtc);
-            for (i = 0; i < ir->opts.ngtc; i++)
-            {
-                ir->opts.nrdf[i] = tmp[i];
-            }
-            sfree(tmp);
-        }
-        else
-        {
-            gmx_fio_ndo_real(fio, ir->opts.nrdf, ir->opts.ngtc);
-        }
+        gmx_fio_ndo_real(fio, ir->opts.nrdf, ir->opts.ngtc);
         gmx_fio_ndo_real(fio, ir->opts.ref_t, ir->opts.ngtc);
         gmx_fio_ndo_real(fio, ir->opts.tau_t, ir->opts.ngtc);
         if (file_version < 33 && ir->eI == eiBD)
@@ -1816,55 +1577,22 @@ static void do_inputrec(t_fileio *fio, t_inputrec *ir, gmx_bool bRead,
     {
         gmx_fio_ndo_rvec(fio, ir->opts.acc, ir->opts.ngacc);
     }
-    if (file_version >= 12)
-    {
-        gmx_fio_ndo_int(fio, ir->opts.egp_flags,
-                        ir->opts.ngener*ir->opts.ngener);
-    }
+    gmx_fio_ndo_int(fio, ir->opts.egp_flags,
+                    ir->opts.ngener*ir->opts.ngener);
 
-    if (bRead && file_version < 26)
+    /* First read the lists with annealing and npoints for each group */
+    gmx_fio_ndo_int(fio, ir->opts.annealing, ir->opts.ngtc);
+    gmx_fio_ndo_int(fio, ir->opts.anneal_npoints, ir->opts.ngtc);
+    for (j = 0; j < (ir->opts.ngtc); j++)
     {
-        for (i = 0; i < ir->opts.ngtc; i++)
+        k = ir->opts.anneal_npoints[j];
+        if (bRead)
         {
-            if (bSimAnn)
-            {
-                ir->opts.annealing[i]      = eannSINGLE;
-                ir->opts.anneal_npoints[i] = 2;
-                snew(ir->opts.anneal_time[i], 2);
-                snew(ir->opts.anneal_temp[i], 2);
-                /* calculate the starting/ending temperatures from reft, zerotemptime, and nsteps */
-                finish_t                   = ir->init_t + ir->nsteps * ir->delta_t;
-                init_temp                  = ir->opts.ref_t[i]*(1-ir->init_t/zerotemptime);
-                finish_temp                = ir->opts.ref_t[i]*(1-finish_t/zerotemptime);
-                ir->opts.anneal_time[i][0] = ir->init_t;
-                ir->opts.anneal_time[i][1] = finish_t;
-                ir->opts.anneal_temp[i][0] = init_temp;
-                ir->opts.anneal_temp[i][1] = finish_temp;
-            }
-            else
-            {
-                ir->opts.annealing[i]      = eannNO;
-                ir->opts.anneal_npoints[i] = 0;
-            }
-        }
-    }
-    else
-    {
-        /* file version 26 or later */
-        /* First read the lists with annealing and npoints for each group */
-        gmx_fio_ndo_int(fio, ir->opts.annealing, ir->opts.ngtc);
-        gmx_fio_ndo_int(fio, ir->opts.anneal_npoints, ir->opts.ngtc);
-        for (j = 0; j < (ir->opts.ngtc); j++)
-        {
-            k = ir->opts.anneal_npoints[j];
-            if (bRead)
-            {
-                snew(ir->opts.anneal_time[j], k);
-                snew(ir->opts.anneal_temp[j], k);
-            }
-            gmx_fio_ndo_real(fio, ir->opts.anneal_time[j], k);
-            gmx_fio_ndo_real(fio, ir->opts.anneal_temp[j], k);
+            snew(ir->opts.anneal_time[j], k);
+            snew(ir->opts.anneal_temp[j], k);
         }
+        gmx_fio_ndo_real(fio, ir->opts.anneal_time[j], k);
+        gmx_fio_ndo_real(fio, ir->opts.anneal_temp[j], k);
     }
     /* Walls */
     if (file_version >= 45)
@@ -2105,10 +1833,6 @@ void do_iparams(t_fileio *fio, t_functype ftype, t_iparams *iparams,
             gmx_fio_do_real(fio, iparams->anharm_polarize.khyp);
             break;
         case F_WATER_POL:
-            if (file_version < 31)
-            {
-                gmx_fatal(FARGS, "Old tpr files with water_polarization not supported. Make a new.");
-            }
             gmx_fio_do_real(fio, iparams->wpol.al_x);
             gmx_fio_do_real(fio, iparams->wpol.al_y);
             gmx_fio_do_real(fio, iparams->wpol.al_z);
@@ -2211,16 +1935,8 @@ void do_iparams(t_fileio *fio, t_functype ftype, t_iparams *iparams,
         case F_POSRES:
             gmx_fio_do_rvec(fio, iparams->posres.pos0A);
             gmx_fio_do_rvec(fio, iparams->posres.fcA);
-            if (bRead && file_version < 27)
-            {
-                copy_rvec(iparams->posres.pos0A, iparams->posres.pos0B);
-                copy_rvec(iparams->posres.fcA, iparams->posres.fcB);
-            }
-            else
-            {
-                gmx_fio_do_rvec(fio, iparams->posres.pos0B);
-                gmx_fio_do_rvec(fio, iparams->posres.fcB);
-            }
+            gmx_fio_do_rvec(fio, iparams->posres.pos0B);
+            gmx_fio_do_rvec(fio, iparams->posres.fcB);
             break;
         case F_FBPOSRES:
             gmx_fio_do_int(fio, iparams->fbposres.geom);
@@ -2233,10 +1949,7 @@ void do_iparams(t_fileio *fio, t_functype ftype, t_iparams *iparams,
             break;
         case F_RBDIHS:
             gmx_fio_ndo_real(fio, iparams->rbdihs.rbcA, NR_RBDIHS);
-            if (file_version >= 25)
-            {
-                gmx_fio_ndo_real(fio, iparams->rbdihs.rbcB, NR_RBDIHS);
-            }
+            gmx_fio_ndo_real(fio, iparams->rbdihs.rbcB, NR_RBDIHS);
             break;
         case F_FOURDIHS:
             /* Fourier dihedrals are internally represented
@@ -2575,11 +2288,7 @@ static void do_atom(t_fileio *fio, t_atom *atom, int ngrp, gmx_bool bRead,
     {
         atom->atomnumber = 0;
     }
-    if (file_version < 23)
-    {
-        myngrp = 8;
-    }
-    else if (file_version < 39)
+    if (file_version < 39)
     {
         myngrp = 9;
     }
@@ -2609,11 +2318,7 @@ static void do_grps(t_fileio *fio, int ngrp, t_grps grps[], gmx_bool bRead,
 {
     int      j, myngrp;
 
-    if (file_version < 23)
-    {
-        myngrp = 8;
-    }
-    else if (file_version < 39)
+    if (file_version < 39)
     {
         myngrp = 9;
     }
@@ -2724,19 +2429,9 @@ static void do_atoms(t_fileio *fio, t_atoms *atoms, gmx_bool bRead, t_symtab *sy
         do_atom(fio, &atoms->atom[i], egcNR, bRead, file_version, groups, i);
     }
     do_strstr(fio, atoms->nr, atoms->atomname, bRead, symtab);
-    if (bRead && (file_version <= 20))
-    {
-        for (i = 0; i < atoms->nr; i++)
-        {
-            atoms->atomtype[i]  = put_symtab(symtab, "?");
-            atoms->atomtypeB[i] = put_symtab(symtab, "?");
-        }
-    }
-    else
-    {
-        do_strstr(fio, atoms->nr, atoms->atomtype, bRead, symtab);
-        do_strstr(fio, atoms->nr, atoms->atomtypeB, bRead, symtab);
-    }
+    do_strstr(fio, atoms->nr, atoms->atomtype, bRead, symtab);
+    do_strstr(fio, atoms->nr, atoms->atomtypeB, bRead, symtab);
+
     do_resinfo(fio, atoms->nres, atoms->resinfo, bRead, symtab, file_version);
 
     if (file_version < 57)
@@ -2786,44 +2481,28 @@ static void do_atomtypes(t_fileio *fio, t_atomtypes *atomtypes, gmx_bool bRead,
 {
     int      j;
 
-    if (file_version > 25)
+    gmx_fio_do_int(fio, atomtypes->nr);
+    j = atomtypes->nr;
+    if (bRead)
     {
-        gmx_fio_do_int(fio, atomtypes->nr);
-        j = atomtypes->nr;
-        if (bRead)
-        {
-            snew(atomtypes->radius, j);
-            snew(atomtypes->vol, j);
-            snew(atomtypes->surftens, j);
-            snew(atomtypes->atomnumber, j);
-            snew(atomtypes->gb_radius, j);
-            snew(atomtypes->S_hct, j);
-        }
-        gmx_fio_ndo_real(fio, atomtypes->radius, j);
-        gmx_fio_ndo_real(fio, atomtypes->vol, j);
-        gmx_fio_ndo_real(fio, atomtypes->surftens, j);
-        if (file_version >= 40)
-        {
-            gmx_fio_ndo_int(fio, atomtypes->atomnumber, j);
-        }
-        if (file_version >= 60)
-        {
-            gmx_fio_ndo_real(fio, atomtypes->gb_radius, j);
-            gmx_fio_ndo_real(fio, atomtypes->S_hct, j);
-        }
+        snew(atomtypes->radius, j);
+        snew(atomtypes->vol, j);
+        snew(atomtypes->surftens, j);
+        snew(atomtypes->atomnumber, j);
+        snew(atomtypes->gb_radius, j);
+        snew(atomtypes->S_hct, j);
     }
-    else
+    gmx_fio_ndo_real(fio, atomtypes->radius, j);
+    gmx_fio_ndo_real(fio, atomtypes->vol, j);
+    gmx_fio_ndo_real(fio, atomtypes->surftens, j);
+    if (file_version >= 40)
     {
-        /* File versions prior to 26 cannot do GBSA,
-         * so they dont use this structure
-         */
-        atomtypes->nr         = 0;
-        atomtypes->radius     = NULL;
-        atomtypes->vol        = NULL;
-        atomtypes->surftens   = NULL;
-        atomtypes->atomnumber = NULL;
-        atomtypes->gb_radius  = NULL;
-        atomtypes->S_hct      = NULL;
+        gmx_fio_ndo_int(fio, atomtypes->atomnumber, j);
+    }
+    if (file_version >= 60)
+    {
+        gmx_fio_ndo_real(fio, atomtypes->gb_radius, j);
+        gmx_fio_ndo_real(fio, atomtypes->S_hct, j);
     }
 }
 
@@ -3312,14 +2991,7 @@ static void do_tpxheader(t_fileio *fio, gmx_bool bRead, t_tpxheader *tpx,
         gmx_fio_do_string(fio, file_tag);
     }
 
-    if (fileVersion >= 26)
-    {
-        gmx_fio_do_int(fio, fileGeneration);
-    }
-    else
-    {
-        fileGeneration = 0;
-    }
+    gmx_fio_do_int(fio, fileGeneration);
 
     if (fileVersion >= 81)
     {
@@ -3369,14 +3041,8 @@ static void do_tpxheader(t_fileio *fio, gmx_bool bRead, t_tpxheader *tpx,
     }
 
     gmx_fio_do_int(fio, tpx->natoms);
-    if (fileVersion >= 28)
-    {
-        gmx_fio_do_int(fio, tpx->ngtc);
-    }
-    else
-    {
-        tpx->ngtc = 0;
-    }
+    gmx_fio_do_int(fio, tpx->ngtc);
+
     if (fileVersion < 62)
     {
         gmx_fio_do_int(fio, idum);
@@ -3406,7 +3072,6 @@ static int do_tpx(t_fileio *fio, gmx_bool bRead,
                   gmx_bool bXVallocated)
 {
     t_tpxheader     tpx;
-    t_inputrec      dum_ir;
     gmx_mtop_t      dum_top;
     gmx_bool        TopOnlyOK;
     rvec           *xptr, *vptr;
@@ -3467,18 +3132,15 @@ static int do_tpx(t_fileio *fio, gmx_bool bRead,
             /* We initialize box_rel after reading the inputrec */
             clear_mat(state->box_rel);
         }
-        if (fileVersion >= 28)
+        gmx_fio_ndo_rvec(fio, state->boxv, DIM);
+        if (fileVersion < 56)
         {
-            gmx_fio_ndo_rvec(fio, state->boxv, DIM);
-            if (fileVersion < 56)
-            {
-                matrix mdum;
-                gmx_fio_ndo_rvec(fio, mdum, DIM);
-            }
+            matrix mdum;
+            gmx_fio_ndo_rvec(fio, mdum, DIM);
         }
     }
 
-    if (state->ngtc > 0 && fileVersion >= 28)
+    if (state->ngtc > 0)
     {
         real *dumv;
         snew(dumv, state->ngtc);
@@ -3491,30 +3153,6 @@ static int do_tpx(t_fileio *fio, gmx_bool bRead,
         sfree(dumv);
     }
 
-    /* Prior to tpx version 26, the inputrec was here.
-     * I moved it to enable partial forward-compatibility
-     * for analysis/viewer programs.
-     */
-    if (fileVersion < 26)
-    {
-        do_test(fio, tpx.bIr, ir);
-        if (tpx.bIr)
-        {
-            if (ir)
-            {
-                do_inputrec(fio, ir, bRead, fileVersion,
-                            mtop ? &mtop->ffparams.fudgeQQ : NULL);
-            }
-            else
-            {
-                do_inputrec(fio, &dum_ir, bRead, fileVersion,
-                            mtop ? &mtop->ffparams.fudgeQQ : NULL);
-                done_inputrec(&dum_ir);
-            }
-
-        }
-    }
-
     do_test(fio, tpx.bTop, mtop);
     if (tpx.bTop)
     {
@@ -3566,42 +3204,40 @@ static int do_tpx(t_fileio *fio, gmx_bool bRead,
      */
     ePBC          = -1;
     bPeriodicMols = FALSE;
-    if (fileVersion >= 26)
+
+    do_test(fio, tpx.bIr, ir);
+    if (tpx.bIr)
     {
-        do_test(fio, tpx.bIr, ir);
-        if (tpx.bIr)
+        if (fileVersion >= 53)
         {
-            if (fileVersion >= 53)
+            /* Removed the pbc info from do_inputrec, since we always want it */
+            if (!bRead)
             {
-                /* Removed the pbc info from do_inputrec, since we always want it */
-                if (!bRead)
-                {
-                    ePBC          = ir->ePBC;
-                    bPeriodicMols = ir->bPeriodicMols;
-                }
-                gmx_fio_do_int(fio, ePBC);
-                gmx_fio_do_gmx_bool(fio, bPeriodicMols);
+                ePBC          = ir->ePBC;
+                bPeriodicMols = ir->bPeriodicMols;
             }
-            if (fileGeneration <= tpx_generation && ir)
+            gmx_fio_do_int(fio, ePBC);
+            gmx_fio_do_gmx_bool(fio, bPeriodicMols);
+        }
+        if (fileGeneration <= tpx_generation && ir)
+        {
+            do_inputrec(fio, ir, bRead, fileVersion, mtop ? &mtop->ffparams.fudgeQQ : NULL);
+            if (fileVersion < 51)
             {
-                do_inputrec(fio, ir, bRead, fileVersion, mtop ? &mtop->ffparams.fudgeQQ : NULL);
-                if (fileVersion < 51)
-                {
-                    set_box_rel(ir, state);
-                }
-                if (fileVersion < 53)
-                {
-                    ePBC          = ir->ePBC;
-                    bPeriodicMols = ir->bPeriodicMols;
-                }
+                set_box_rel(ir, state);
             }
-            if (bRead && ir && fileVersion >= 53)
+            if (fileVersion < 53)
             {
-                /* We need to do this after do_inputrec, since that initializes ir */
-                ir->ePBC          = ePBC;
-                ir->bPeriodicMols = bPeriodicMols;
+                ePBC          = ir->ePBC;
+                bPeriodicMols = ir->bPeriodicMols;
             }
         }
+        if (bRead && ir && fileVersion >= 53)
+        {
+            /* We need to do this after do_inputrec, since that initializes ir */
+            ir->ePBC          = ePBC;
+            ir->bPeriodicMols = bPeriodicMols;
+        }
     }
 
     if (bRead)
index 8ed9dc6acf25e7a2f1f28b0a6ad4451819ddfb43..bf9549a7c9077cd3489610e1d1cb3035e40e4a82 100644 (file)
@@ -1132,6 +1132,7 @@ int gmx_analyze(int argc, char *argv[])
     if (!parse_common_args(&argc, argv, PCA_CAN_VIEW,
                            NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv))
     {
+        sfree(ppa);
         return 0;
     }
 
index 3bf3634461a902a5c100009302f6129c37381c66..5ebdeb124a4ef1cc736159003faf59bf2d3fc99f 100644 (file)
@@ -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, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, 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.
@@ -191,6 +191,7 @@ int gmx_g_angle(int argc, char *argv[])
                            NFILE, fnm, npargs, ppa, asize(desc), desc, asize(bugs), bugs,
                            &oenv))
     {
+        sfree(ppa);
         return 0;
     }
 
index 131e4142891eccd0d22c924e3306ea0a799cc698..5f227ed9a378286da320e7f3c8ae221aac427b0e 100644 (file)
@@ -1398,6 +1398,7 @@ int gmx_chi(int argc, char *argv[])
                            NFILE, fnm, npargs, ppa, asize(desc), desc, asize(bugs), bugs,
                            &oenv))
     {
+        sfree(ppa);
         return 0;
     }
 
index 99be1dab8cfb002ab720ea077d3a6bbbd7586eaa..f6654953db1a064c2c0ad7c15b047c425da187d4 100644 (file)
@@ -1620,6 +1620,7 @@ int gmx_dipoles(int argc, char *argv[])
     if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW,
                            NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv))
     {
+        sfree(ppa);
         return 0;
     }
 
index 94dc678cda99126a2d2c54e5054c361899d2be17..58413e45eaf951785c97162559a9eb03c351ca92 100644 (file)
@@ -839,7 +839,7 @@ int gmx_disre(int argc, char *argv[])
     }
 
     mdatoms = init_mdatoms(fplog, &mtop, ir.efep != efepNO);
-    atoms2md(&mtop, &ir, 0, NULL, mtop.natoms, mdatoms);
+    atoms2md(&mtop, &ir, -1, NULL, mtop.natoms, mdatoms);
     update_mdatoms(mdatoms, ir.fepvals->init_lambda);
     init_nrnb(&nrnb);
     if (ir.ePBC != epbcNONE)
index 88a3667a365e329fa6ad3854fef321f92686f3f9..3845ba98ca151538af70ed41abba1208d04ae759 100644 (file)
@@ -328,6 +328,7 @@ int gmx_dos(int argc, char *argv[])
                            NFILE, fnm, npargs, ppa, asize(desc), desc,
                            asize(bugs), bugs, &oenv))
     {
+        sfree(ppa);
         return 0;
     }
 
index 97d2be8a7176f0ca13c5bce484f28970689b4f3e..7c099e8ee87090603b91492a70e0272ac49eaf51 100644 (file)
@@ -2052,6 +2052,7 @@ int gmx_energy(int argc, char *argv[])
                            PCA_CAN_VIEW | PCA_CAN_BEGIN | PCA_CAN_END,
                            NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv))
     {
+        sfree(ppa);
         return 0;
     }
 
index 23fccd29519f034cfe9cb93ebe7a2d4babb60b0b..0d7248f8a8ec8f8d4d76b759067aa860b14b8621 100644 (file)
@@ -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, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, 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.
@@ -238,6 +238,7 @@ int gmx_gyrate(int argc, char *argv[])
     if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW,
                            NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv))
     {
+        sfree(ppa);
         return 0;
     }
     bACF = opt2bSet("-acf", NFILE, fnm);
index 2081edd40f3469a74488cc3129e96a0173623725..708671de319deee803131bfc47a098d2647d8bba 100644 (file)
@@ -912,8 +912,8 @@ static void reset_nhbonds(t_donors *ddd)
     }
 }
 
-void pbc_correct_gem(rvec dx, matrix box, rvec hbox);
-void pbc_in_gridbox(rvec dx, matrix box);
+static void pbc_correct_gem(rvec dx, matrix box, rvec hbox);
+static void pbc_in_gridbox(rvec dx, matrix box);
 
 static void build_grid(t_hbdata *hb, rvec x[], rvec xshell,
                        gmx_bool bBox, matrix box, rvec hbox,
@@ -1186,7 +1186,7 @@ static void free_grid(ivec ngrid, t_gridcell ****grid)
     g = NULL;
 }
 
-void pbc_correct_gem(rvec dx, matrix box, rvec hbox)
+static void pbc_correct_gem(rvec dx, matrix box, rvec hbox)
 {
     int      m;
     gmx_bool bDone = FALSE;
@@ -1209,7 +1209,7 @@ void pbc_correct_gem(rvec dx, matrix box, rvec hbox)
     }
 }
 
-void pbc_in_gridbox(rvec dx, matrix box)
+static void pbc_in_gridbox(rvec dx, matrix box)
 {
     int      m;
     gmx_bool bDone = FALSE;
@@ -2549,6 +2549,7 @@ int gmx_hbond(int argc, char *argv[])
     if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT, NFILE, fnm, npargs,
                            ppa, asize(desc), desc, asize(bugs), bugs, &oenv))
     {
+        sfree(ppa);
         return 0;
     }
 
index 3f8b6ad6a7960ef1e86c350e085838ddf0f79bbf..1fafd298bbf769d74f2636dedf22bbe8247878c2 100644 (file)
@@ -51,6 +51,7 @@
 #include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
 #include "gromacs/math/vec.h"
+#include "gromacs/mdrunutility/mdmodules.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
@@ -1136,6 +1137,7 @@ int gmx_pme_error(int argc, char *argv[])
                            NFILE, fnm, asize(pa), pa, asize(desc), desc,
                            0, NULL, &oenv))
     {
+        sfree(cr);
         return 0;
     }
 
@@ -1150,10 +1152,11 @@ int gmx_pme_error(int argc, char *argv[])
     create_info(&info);
     info.fourier_sp[0] = fs;
 
+    gmx::MDModules mdModules;
+
     if (MASTER(cr))
     {
-        /* Read in the tpr file */
-        snew(ir, 1);
+        ir = mdModules.inputrec();
         read_tpr_file(opt2fn("-s", NFILE, fnm), &info, &state, &mtop, ir, user_beta, fracself);
         /* Open logfile for reading */
         fp = fopen(opt2fn("-o", NFILE, fnm), "w");
index f30805be6b568e87421c7318aafdd5643bc5fdbf..a3c14129d27ddad2a6afa6c3a3dac9ee84498084 100644 (file)
@@ -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, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, 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.
@@ -115,6 +115,7 @@ int gmx_rotacf(int argc, char *argv[])
     if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME,
                            NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv))
     {
+        sfree(ppa);
         return 0;
     }
 
index a1d73058512e55c3c056ce2d97eb8903284c935b..0009d3ecb05923d7c004019b2ac6c31cff46eee7 100644 (file)
@@ -48,6 +48,7 @@
 #include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
 #include "gromacs/math/vec.h"
+#include "gromacs/mdrunutility/mdmodules.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/pbcutil/rmpbc.h"
@@ -222,7 +223,9 @@ int gmx_spol(int argc, char *argv[])
     }
 
     snew(top, 1);
-    snew(ir, 1);
+    // TODO: Only ePBC is used, not the full inputrec.
+    gmx::MDModules mdModules;
+    ir = mdModules.inputrec();
     read_tpx_top(ftp2fn(efTPR, NFILE, fnm),
                  ir, box, &natoms, NULL, NULL, top);
 
index 0c37c599a8e7deb2a0d1f54dfc6fd87dbfbd344a..5d3dd8bf3258ae2dcd5105007487a72298da409a 100644 (file)
@@ -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, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, 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.
@@ -343,6 +343,7 @@ int gmx_tcaf(int argc, char *argv[])
     if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME,
                            NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv))
     {
+        sfree(ppa);
         return 0;
     }
 
index adf950b8356c4e50042516cc88dff41fe8c391e6..93df67f2503d56645b9b639e869466a2205f8d86 100644 (file)
@@ -56,6 +56,7 @@
 #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"
@@ -869,12 +870,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 */
@@ -886,8 +888,6 @@ static void modify_PMEsettings(
     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)
@@ -937,8 +937,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 */
@@ -1169,7 +1169,6 @@ static void make_benchmark_tprs(
     }
     fflush(stdout);
     fflush(fp);
-    sfree(ir);
 }
 
 
@@ -2047,20 +2046,22 @@ static float inspect_tpr(int nfile, t_filenm fnm[], real *rcoulomb)
     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);
@@ -2083,10 +2084,11 @@ static float inspect_tpr(int nfile, t_filenm fnm[], real *rcoulomb)
         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;
 }
 
 
index 27e9aa18400153596ec63491037885394e079636..6ed7e737f9c62045967926af5b636b4e88f25234 100644 (file)
@@ -239,6 +239,7 @@ int gmx_velacc(int argc, char *argv[])
     if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME,
                            NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv))
     {
+        sfree(ppa);
         return 0;
     }
 
index af7a8080babb424ed4761fab9c4ca95f2cee4d02..558aa174a28af6bd114942f151dfe315feb45693 100644 (file)
@@ -32,7 +32,6 @@
 # To help us fund GROMACS development, we humbly ask that you cite
 # the research papers on the package. Check out http://www.gromacs.org.
 
-set(testname "LegacyToolsTests")
 set(exename "legacy-tools-test")
 
 gmx_add_gtest_executable(
@@ -40,7 +39,4 @@ gmx_add_gtest_executable(
     # files with code for test fixtures
     gmx_traj_tests.cpp
     )
-gmx_register_integration_test(
-    ${testname}
-    ${exename}
-    )
+gmx_register_gtest_test(LegacyToolsTest ${exename} INTEGRATION_TEST)
index 820ba06471a4b5240145e1de0f9a584bff3e3546..6ac20f7a110827b3dc5b2460e7ad2f14d5ed0b31 100644 (file)
@@ -150,10 +150,6 @@ const char *trajectoryFileNames[] = {
     "spc2-traj.g96"
 };
 
-#ifdef __INTEL_COMPILER
-#pragma warning( disable : 177 )
-#endif
-
 INSTANTIATE_TEST_CASE_P(NoFatalErrorWhenWritingFrom,
                         GmxTraj,
                             ::testing::ValuesIn(gmx::ArrayRef<const char*>(trajectoryFileNames)));
index 2a2cf40dd5097463dd186c20fe39853bd6baa84b..62bb3c51b9f74bde52a6c99b866cdc343a5d07e2 100644 (file)
@@ -720,6 +720,7 @@ void gmx_fatal_collective(int f_errno, const char *file, int line,
     /* Any result except MPI_UNEQUAL allows us to call MPI_Finalize */
     bFinalize = (result != MPI_UNEQUAL);
 #else
+    GMX_UNUSED_VALUE(comm);
     bFinalize = TRUE;
 #endif
 
index 25a7c83cd10314751b82eefa2c1cfac703c80d33..9285b21fa40f6bc6e25809cb8b16db1af4855178 100644 (file)
@@ -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
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 #define gmx_mm_castsi128_ps   _mm_castsi128_ps
 #define gmx_mm_extract_epi32  _mm_extract_epi32
 
-/* Work around gcc bug with wrong type for mask formal parameter to maskload/maskstore */
-#if GMX_SIMD_X86_AVX_GCC_MASKLOAD_BUG
-#    define gmx_mm_maskload_ps(mem, mask)       _mm_maskload_ps((mem), _mm_castsi128_ps(mask))
-#    define gmx_mm_maskstore_ps(mem, mask, x)    _mm_maskstore_ps((mem), _mm_castsi128_ps(mask), (x))
-#    define gmx_mm256_maskload_ps(mem, mask)    _mm256_maskload_ps((mem), _mm256_castsi256_ps(mask))
-#    define gmx_mm256_maskstore_ps(mem, mask, x) _mm256_maskstore_ps((mem), _mm256_castsi256_ps(mask), (x))
-#else
-#    define gmx_mm_maskload_ps(mem, mask)       _mm_maskload_ps((mem), (mask))
-#    define gmx_mm_maskstore_ps(mem, mask, x)    _mm_maskstore_ps((mem), (mask), (x))
-#    define gmx_mm256_maskload_ps(mem, mask)    _mm256_maskload_ps((mem), (mask))
-#    define gmx_mm256_maskstore_ps(mem, mask, x) _mm256_maskstore_ps((mem), (mask), (x))
-#endif
+#define gmx_mm_maskload_ps(mem, mask)       _mm_maskload_ps((mem), (mask))
+#define gmx_mm_maskstore_ps(mem, mask, x)    _mm_maskstore_ps((mem), (mask), (x))
+#define gmx_mm256_maskload_ps(mem, mask)    _mm256_maskload_ps((mem), (mask))
+#define gmx_mm256_maskstore_ps(mem, mask, x) _mm256_maskstore_ps((mem), (mask), (x))
 
 /* Normal sum of four xmm registers */
 #define gmx_mm_sum4_ps(t0, t1, t2, t3)  _mm_add_ps(_mm_add_ps(t0, t1), _mm_add_ps(t2, t3))
index bfbccd54deced3623f0ebebcc4a5dd52f8a6c821..ac489ea64b21db84737e635db5af0bfbbf9dca0c 100644 (file)
@@ -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
  * 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.
@@ -59,18 +59,10 @@ gmx_mm256_set_m128(__m128 hi, __m128 lo)
     return _mm256_insertf128_ps(_mm256_castps128_ps256(lo), hi, 0x1);
 }
 
-/* Work around gcc bug with wrong type for mask formal parameter to maskload/maskstore */
-#if GMX_SIMD_X86_AVX_GCC_MASKLOAD_BUG
-#    define gmx_mm_maskload_ps(mem, mask)       _mm_maskload_ps((mem), _mm_castsi128_ps(mask))
-#    define gmx_mm_maskstore_ps(mem, mask, x)    _mm_maskstore_ps((mem), _mm_castsi128_ps(mask), (x))
-#    define gmx_mm256_maskload_ps(mem, mask)    _mm256_maskload_ps((mem), _mm256_castsi256_ps(mask))
-#    define gmx_mm256_maskstore_ps(mem, mask, x) _mm256_maskstore_ps((mem), _mm256_castsi256_ps(mask), (x))
-#else
-#    define gmx_mm_maskload_ps(mem, mask)       _mm_maskload_ps((mem), (mask))
-#    define gmx_mm_maskstore_ps(mem, mask, x)    _mm_maskstore_ps((mem), (mask), (x))
-#    define gmx_mm256_maskload_ps(mem, mask)    _mm256_maskload_ps((mem), (mask))
-#    define gmx_mm256_maskstore_ps(mem, mask, x) _mm256_maskstore_ps((mem), (mask), (x))
-#endif
+#define gmx_mm_maskload_ps(mem, mask)       _mm_maskload_ps((mem), (mask))
+#define gmx_mm_maskstore_ps(mem, mask, x)    _mm_maskstore_ps((mem), (mask), (x))
+#define gmx_mm256_maskload_ps(mem, mask)    _mm256_maskload_ps((mem), (mask))
+#define gmx_mm256_maskstore_ps(mem, mask, x) _mm256_maskstore_ps((mem), (mask), (x))
 
 /* Transpose lower/upper half of 256-bit registers separately */
 #define GMX_MM256_HALFTRANSPOSE4_PS(ymm0, ymm1, ymm2, ymm3) {            \
index 7759c00cd49f15f28107d717608fa3f13d61c296..807e5323cf85c18ecf784791182d65955dc81456 100644 (file)
@@ -313,5 +313,15 @@ int gmx_genconf(int argc, char *argv[])
 
     write_sto_conf(opt2fn("-o", NFILE, fnm), *top->name, atoms, x, v, ePBC, box);
 
+    sfree(x);
+    sfree(v);
+    sfree(xrot);
+    sfree(vrot);
+    sfree(xx);
+    done_top(top);
+    sfree(top);
+    done_filenms(NFILE, fnm);
+    output_env_done(oenv);
+
     return 0;
 }
index cd4ee3af4b32efec9a78009825dd8e8a9f2fc6cc..6a3dcbbee4a0916e87d95cf4b9cc883a9086bbf1 100644 (file)
@@ -75,6 +75,7 @@
 #include "gromacs/mdlib/compute_io.h"
 #include "gromacs/mdlib/genborn.h"
 #include "gromacs/mdlib/perf_est.h"
+#include "gromacs/mdrunutility/mdmodules.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/mdtypes/nblist.h"
@@ -1627,11 +1628,6 @@ int gmx_grompp(int argc, char *argv[])
           "Renumber atomtypes and minimize number of atomtypes" }
     };
 
-    /* Initiate some variables */
-    snew(ir, 1);
-    snew(opts, 1);
-    init_ir(ir, opts);
-
     /* Parse the command line */
     if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa,
                            asize(desc), desc, 0, NULL, &oenv))
@@ -1639,6 +1635,12 @@ int gmx_grompp(int argc, char *argv[])
         return 0;
     }
 
+    /* Initiate some variables */
+    gmx::MDModules mdModules;
+    ir = mdModules.inputrec();
+    snew(opts, 1);
+    init_ir(ir, opts);
+
     wi = init_warning(TRUE, maxwarn);
 
     /* PARAMETER file processing */
index ff2f86e5705c5462c4bfe7e69395c8fb864db49e..1753d190f50ee0efbf940b8771bfbb940e8fad0f 100644 (file)
@@ -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, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, 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.
@@ -226,7 +226,7 @@ choose_ff_impl(const char *ffsel,
                 FILE *fp = gmx_ffopen(docFileName.c_str(), "r");
                 get_a_line(fp, buf, STRLEN);
                 gmx_ffclose(fp);
-                desc.push_back(buf);
+                desc.emplace_back(buf);
             }
             else
             {
index e49696700de5adbd41065207a169289546fd78b2..f07e366586af67e97b5f19b58bd9e8ba9eef5c96 100644 (file)
@@ -514,7 +514,7 @@ pull_t *set_pull_init(t_inputrec *ir, const gmx_mtop_t *mtop,
     pull      = ir->pull;
     pull_work = init_pull(NULL, pull, ir, 0, NULL, mtop, NULL, oenv, lambda, FALSE, 0);
     md        = init_mdatoms(NULL, mtop, ir->efep);
-    atoms2md(mtop, ir, 0, NULL, mtop->natoms, md);
+    atoms2md(mtop, ir, -1, NULL, mtop->natoms, md);
     if (ir->efep)
     {
         update_mdatoms(md, lambda);
index 5a43f00963ba9a528252fd6f697788570574e014..8ac8938075045fe3aa3ebd1baae8c545eebf36b0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2012,2014,2015,2016, 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.
@@ -85,18 +85,6 @@ int cu_copy_D2H_async(void * h_dest, void * d_src, size_t bytes, cudaStream_t s
     return cu_copy_D2H_generic(h_dest, d_src, bytes, true, s);
 }
 
-int cu_copy_D2H_alloc(void ** h_dest, void * d_src, size_t bytes)
-{
-    if (h_dest == NULL || d_src == NULL || bytes == 0)
-    {
-        return -1;
-    }
-
-    smalloc(*h_dest, bytes);
-
-    return cu_copy_D2H(*h_dest, d_src, bytes);
-}
-
 /*! Launches synchronous or asynchronous device to host memory copy.
  *
  *  The copy is launched in stream s or if not specified, in stream 0.
@@ -138,21 +126,6 @@ int cu_copy_H2D_async(void * d_dest, void * h_src, size_t bytes, cudaStream_t s
     return cu_copy_H2D_generic(d_dest, h_src, bytes, true, s);
 }
 
-int cu_copy_H2D_alloc(void ** d_dest, void * h_src, size_t bytes)
-{
-    cudaError_t stat;
-
-    if (d_dest == NULL || h_src == NULL || bytes == 0)
-    {
-        return -1;
-    }
-
-    stat = cudaMalloc(d_dest, bytes);
-    CU_RET_ERR(stat, "cudaMalloc failed in cu_copy_H2D_alloc");
-
-    return cu_copy_H2D(*d_dest, h_src, bytes);
-}
-
 float cu_event_elapsed(cudaEvent_t start, cudaEvent_t end)
 {
     float       t = 0.0;
index 5daa040d28f5e00e964766c351ed7af57917c991..1a99e1c904597b76a200c94156d86dc71f7f659d 100644 (file)
  * The CUDA device information is queried and set at detection and contains
  * both information about the device/hardware returned by the runtime as well
  * as additional data like support status.
+ *
+ * \todo extract an object to manage NVML details
  */
 struct gmx_device_info_t
 {
     int                 id;                      /* id of the CUDA device */
     cudaDeviceProp      prop;                    /* CUDA device properties */
     int                 stat;                    /* result of the device check */
-    gmx_bool            nvml_initialized;        /* If NVML was initialized */
     unsigned int        nvml_orig_app_sm_clock;  /* The original SM clock before we changed it */
     unsigned int        nvml_orig_app_mem_clock; /* The original memory clock before we changed it */
     gmx_bool            nvml_app_clocks_changed; /* If application clocks have been changed */
@@ -126,6 +127,7 @@ struct gmx_device_info_t
     unsigned int        nvml_set_app_mem_clock;  /* The memory clock we set */
 #if HAVE_NVML
     nvmlDevice_t        nvml_device_id;          /* NVML device id */
+    // TODO This can become a bool with a more useful name
     nvmlEnableState_t   nvml_is_restricted;      /* Status of application clocks permission */
 #endif                                           /* HAVE_NVML */
 };
@@ -137,9 +139,6 @@ int cu_copy_D2H(void * /*h_dest*/, void * /*d_src*/, size_t /*bytes*/);
 /*! Launches asynchronous host to device memory copy in stream s. */
 int cu_copy_D2H_async(void * /*h_dest*/, void * /*d_src*/, size_t /*bytes*/, cudaStream_t /*s = 0*/);
 
-/*! Allocates host memory and launches synchronous host to device memory copy. */
-int cu_copy_D2H_alloc(void ** /*h_dest*/, void * /*d_src*/, size_t /*bytes*/);
-
 
 /*! Launches synchronous host to device memory copy. */
 int cu_copy_H2D(void * /*d_dest*/, void * /*h_src*/, size_t /*bytes*/);
@@ -147,9 +146,6 @@ int cu_copy_H2D(void * /*d_dest*/, void * /*h_src*/, size_t /*bytes*/);
 /*! Launches asynchronous host to device memory copy in stream s. */
 int cu_copy_H2D_async(void * /*d_dest*/, void * /*h_src*/, size_t /*bytes*/, cudaStream_t /*s = 0*/);
 
-/*! Allocates device memory and launches synchronous host to device memory copy. */
-int cu_copy_H2D_alloc(void ** /*d_dest*/, void * /*h_src*/, size_t /*bytes*/);
-
 /*! Frees device memory and resets the size and allocation size to -1. */
 void cu_free_buffered(void *d_ptr, int *n = NULL, int *nalloc = NULL);
 
index e8b78249e909a45dcf6142ab1b3b83de3d1ff2c7..6e620cc144ca8bcfd9752ae7752e5c61bd8fcd1f 100644 (file)
@@ -55,6 +55,7 @@
 #include "gromacs/hardware/gpu_hw_info.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/smalloc.h"
 
 #if HAVE_NVML
@@ -206,59 +207,6 @@ static int do_sanity_checks(int dev_id, cudaDeviceProp *dev_prop)
     return 0;
 }
 
-#if HAVE_NVML
-/* TODO: We should actually be using md_print_warn in md_logging.c,
- * but we can't include mpi.h in CUDA code.
- */
-static void md_print_info(FILE       *fplog,
-                          const char *fmt, ...)
-{
-    va_list ap;
-
-    if (fplog != NULL)
-    {
-        /* We should only print to stderr on the master node,
-         * in most cases fplog is only set on the master node, so this works.
-         */
-        va_start(ap, fmt);
-        vfprintf(stderr, fmt, ap);
-        va_end(ap);
-
-        va_start(ap, fmt);
-        vfprintf(fplog, fmt, ap);
-        va_end(ap);
-    }
-}
-#endif /*HAVE_NVML*/
-
-/* TODO: We should actually be using md_print_warn in md_logging.c,
- * but we can't include mpi.h in CUDA code.
- * This is replicated from nbnxn_cuda_data_mgmt.cu.
- */
-static void md_print_warn(FILE       *fplog,
-                          const char *fmt, ...)
-{
-    va_list ap;
-
-    if (fplog != NULL)
-    {
-        /* We should only print to stderr on the master node,
-         * in most cases fplog is only set on the master node, so this works.
-         */
-        va_start(ap, fmt);
-        fprintf(stderr, "\n");
-        vfprintf(stderr, fmt, ap);
-        fprintf(stderr, "\n");
-        va_end(ap);
-
-        va_start(ap, fmt);
-        fprintf(fplog, "\n");
-        vfprintf(fplog, fmt, ap);
-        fprintf(fplog, "\n");
-        va_end(ap);
-    }
-}
-
 #if HAVE_NVML_APPLICATION_CLOCKS
 /*! \brief Determines and adds the NVML device ID to the passed \cuda_dev.
  *
@@ -271,9 +219,9 @@ static void md_print_warn(FILE       *fplog,
 static bool addNVMLDeviceId(gmx_device_info_t* cuda_dev)
 {
     nvmlDevice_t nvml_device_id;
-    unsigned int nvml_device_count = 0;
-    nvmlReturn_t nvml_stat         = nvmlDeviceGetCount ( &nvml_device_count );
-    cuda_dev->nvml_initialized = false;
+    unsigned int nvml_device_count  = 0;
+    nvmlReturn_t nvml_stat          = nvmlDeviceGetCount ( &nvml_device_count );
+    bool         nvmlWasInitialized = false;
     HANDLE_NVML_RET_ERR( nvml_stat, "nvmlDeviceGetCount failed" );
     for (unsigned int nvml_device_idx = 0; nvml_stat == NVML_SUCCESS && nvml_device_idx < nvml_device_count; ++nvml_device_idx)
     {
@@ -295,12 +243,12 @@ static bool addNVMLDeviceId(gmx_device_info_t* cuda_dev)
             static_cast<unsigned int>(cuda_dev->prop.pciDeviceID) == nvml_pci_info.device &&
             static_cast<unsigned int>(cuda_dev->prop.pciDomainID) == nvml_pci_info.domain)
         {
-            cuda_dev->nvml_initialized = true;
+            nvmlWasInitialized         = true;
             cuda_dev->nvml_device_id   = nvml_device_id;
             break;
         }
     }
-    return cuda_dev->nvml_initialized;
+    return nvmlWasInitialized;
 }
 
 /*! \brief Reads and returns the application clocks for device.
@@ -337,12 +285,17 @@ static bool getApplicationClocks(const gmx_device_info_t *cuda_dev,
  * allow this. For future GPU architectures a more sophisticated scheme might be
  * required.
  *
- * \param[out] fplog        log file to write to
+ * \todo Refactor this into a detection phase and a work phase. Also
+ * refactor to remove compile-time dependence on logging header.
+ *
+ * \param     mdlog         log file to write to
  * \param[in] gpuid         index of the GPU to set application clocks for
  * \param[in] gpu_info      GPU info of all detected devices in the system.
  * \returns                 true if no error occurs during application clocks handling.
  */
-static gmx_bool init_gpu_application_clocks(FILE gmx_unused *fplog, int gmx_unused gpuid, const gmx_gpu_info_t gmx_unused *gpu_info)
+static gmx_bool init_gpu_application_clocks(
+        const gmx::MDLogger &mdlog, int gmx_unused gpuid,
+        const gmx_gpu_info_t gmx_unused *gpu_info)
 {
     const cudaDeviceProp *prop                        = &gpu_info->gpu_dev[gpuid].prop;
     int                   cuda_version_number         = prop->major * 10 + prop->minor;
@@ -354,26 +307,20 @@ static gmx_bool init_gpu_application_clocks(FILE gmx_unused *fplog, int gmx_unus
         return true;
     }
 #if !HAVE_NVML
-    int cuda_driver  = 0;
-    int cuda_runtime = 0;
-    cudaDriverGetVersion(&cuda_driver);
-    cudaRuntimeGetVersion(&cuda_runtime);
-    md_print_warn( fplog, "NOTE: GROMACS was configured without NVML support hence it can not exploit\n"
-                   "      application clocks of the detected %s GPU to improve performance.\n"
-                   "      Recompile with the NVML library (compatible with the driver used) or set application clocks manually.\n",
-                   prop->name);
+    GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+            "NOTE: GROMACS was configured without NVML support hence it can not exploit\n"
+            "      application clocks of the detected %s GPU to improve performance.\n"
+            "      Recompile with the NVML library (compatible with the driver used) or set application clocks manually.",
+            prop->name);
     return true;
 #else
     if (!bCompiledWithApplicationClockSupport)
     {
-        int cuda_driver  = 0;
-        int cuda_runtime = 0;
-        cudaDriverGetVersion(&cuda_driver);
-        cudaRuntimeGetVersion(&cuda_runtime);
-        md_print_warn( fplog, "NOTE: GROMACS was compiled with an old NVML library which does not support\n"
-                       "      managing application clocks of the detected %s GPU to improve performance.\n"
-                       "      If your GPU supports application clocks, upgrade NVML (and driver) and recompile or set the clocks manually.\n",
-                       prop->name );
+        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                "NOTE: GROMACS was compiled with an old NVML library which does not support\n"
+                "      managing application clocks of the detected %s GPU to improve performance.\n"
+                "      If your GPU supports application clocks, upgrade NVML (and driver) and recompile or set the clocks manually.",
+                prop->name );
         return true;
     }
 
@@ -423,30 +370,43 @@ static gmx_bool init_gpu_application_clocks(FILE gmx_unused *fplog, int gmx_unus
     nvml_stat = nvmlDeviceGetAPIRestriction(cuda_dev->nvml_device_id, NVML_RESTRICTED_API_SET_APPLICATION_CLOCKS, &(cuda_dev->nvml_is_restricted));
     HANDLE_NVML_RET_ERR( nvml_stat, "nvmlDeviceGetAPIRestriction failed" );
 
-    /* Note: Distinguishing between different types of GPUs here might be necessary in the future,
-       e.g. if max application clocks should not be used for certain GPUs. */
-    if (nvml_stat == NVML_SUCCESS && cuda_dev->nvml_orig_app_sm_clock < max_sm_clock && cuda_dev->nvml_is_restricted == NVML_FEATURE_DISABLED)
-    {
-        md_print_info(fplog, "Changing GPU application clocks for %s to (%d,%d)\n", cuda_dev->prop.name, max_mem_clock, max_sm_clock);
-        nvml_stat = nvmlDeviceSetApplicationsClocks(cuda_dev->nvml_device_id, max_mem_clock, max_sm_clock);
-        HANDLE_NVML_RET_ERR( nvml_stat, "nvmlDeviceGetApplicationsClock failed" );
-        cuda_dev->nvml_app_clocks_changed = true;
-        cuda_dev->nvml_set_app_sm_clock   = max_sm_clock;
-        cuda_dev->nvml_set_app_mem_clock  = max_mem_clock;
-    }
-    else if (nvml_stat == NVML_SUCCESS && cuda_dev->nvml_orig_app_sm_clock < max_sm_clock)
+    if (nvml_stat != NVML_SUCCESS)
     {
-        md_print_warn(fplog, "Can not change application clocks for %s to optimal values due to insufficient permissions. Current values are (%d,%d), max values are (%d,%d).\nUse sudo nvidia-smi -acp UNRESTRICTED or contact your admin to change application clocks.\n", cuda_dev->prop.name, cuda_dev->nvml_orig_app_mem_clock, cuda_dev->nvml_orig_app_sm_clock, max_mem_clock, max_sm_clock);
+        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                "Can not change GPU application clocks to optimal values due to NVML error (%d): %s.",
+                nvml_stat, nvmlErrorString(nvml_stat));
+        return false;
     }
-    else if (nvml_stat == NVML_SUCCESS && cuda_dev->nvml_orig_app_sm_clock == max_sm_clock)
+
+    if (cuda_dev->nvml_is_restricted != NVML_FEATURE_DISABLED)
     {
-        md_print_info(fplog, "Application clocks (GPU clocks) for %s are (%d,%d)\n", cuda_dev->prop.name, cuda_dev->nvml_orig_app_mem_clock, cuda_dev->nvml_orig_app_sm_clock);
+        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                "Cannot change application clocks for %s to optimal values due to insufficient permissions. Current values are (%d,%d), max values are (%d,%d).\nUse sudo nvidia-smi -acp UNRESTRICTED or contact your admin to change application clocks.",
+                cuda_dev->prop.name, cuda_dev->nvml_orig_app_mem_clock, cuda_dev->nvml_orig_app_sm_clock, max_mem_clock, max_sm_clock);
+        return true;
     }
-    else
+
+    if (cuda_dev->nvml_orig_app_sm_clock >= max_sm_clock)
     {
-        md_print_warn( fplog,  "Can not change GPU application clocks to optimal values due to NVML error (%d): %s.\n", nvml_stat, nvmlErrorString(nvml_stat));
+        //TODO: This should probably be integrated into the GPU Properties table.
+        GMX_LOG(mdlog.warning).appendTextFormatted(
+                "Application clocks (GPU clocks) for %s are (%d,%d)",
+                cuda_dev->prop.name, cuda_dev->nvml_orig_app_mem_clock, cuda_dev->nvml_orig_app_sm_clock);
+        return true;
     }
-    return (nvml_stat == NVML_SUCCESS);
+
+    /* Note: Distinguishing between different types of GPUs here might be necessary in the future,
+       e.g. if max application clocks should not be used for certain GPUs. */
+    GMX_LOG(mdlog.warning).appendTextFormatted(
+            "Changing GPU application clocks for %s to (%d,%d)",
+            cuda_dev->prop.name, max_mem_clock, max_sm_clock);
+    nvml_stat = nvmlDeviceSetApplicationsClocks(cuda_dev->nvml_device_id, max_mem_clock, max_sm_clock);
+    HANDLE_NVML_RET_ERR( nvml_stat, "nvmlDeviceGetApplicationsClock failed" );
+    cuda_dev->nvml_app_clocks_changed = true;
+    cuda_dev->nvml_set_app_sm_clock   = max_sm_clock;
+    cuda_dev->nvml_set_app_mem_clock  = max_mem_clock;
+
+    return true;
 #endif /* HAVE_NVML */
 }
 
@@ -484,7 +444,7 @@ static gmx_bool reset_gpu_application_clocks(const gmx_device_info_t gmx_unused
 #endif /* HAVE_NVML_APPLICATION_CLOCKS */
 }
 
-gmx_bool init_gpu(FILE gmx_unused *fplog, int mygpu, char *result_str,
+gmx_bool init_gpu(const gmx::MDLogger &mdlog, int mygpu, char *result_str,
                   const struct gmx_gpu_info_t *gpu_info,
                   const struct gmx_gpu_opt_t *gpu_opt)
 {
@@ -497,7 +457,7 @@ gmx_bool init_gpu(FILE gmx_unused *fplog, int mygpu, char *result_str,
 
     if (mygpu < 0 || mygpu >= gpu_opt->n_dev_use)
     {
-        sprintf(sbuf, "Trying to initialize an inexistent GPU: "
+        sprintf(sbuf, "Trying to initialize an non-existent GPU: "
                 "there are %d %s-selected GPU(s), but #%d was requested.",
                 gpu_opt->n_dev_use, gpu_opt->bUserSet ? "user" : "auto", mygpu);
         gmx_incons(sbuf);
@@ -516,7 +476,7 @@ gmx_bool init_gpu(FILE gmx_unused *fplog, int mygpu, char *result_str,
     //Ignoring return value as NVML errors should be treated not critical.
     if (stat == cudaSuccess)
     {
-        init_gpu_application_clocks(fplog, gpuid, gpu_info);
+        init_gpu_application_clocks(mdlog, gpuid, gpu_info);
     }
     return (stat == cudaSuccess);
 }
index f485abb0fb4f1ff8b7b7661ff8c713180ab3919f..b99c57159730e13e293e89e00659cc0d232aabb1 100644 (file)
 struct gmx_gpu_info_t;
 struct gmx_gpu_opt_t;
 
+namespace gmx
+{
+class MDLogger;
+}
+
 /*! \brief Detect all GPUs in the system.
  *
  *  Will detect every GPU supported by the device driver in use. Also
@@ -115,7 +120,7 @@ void free_gpu_info(const struct gmx_gpu_info_t *GPU_FUNC_ARGUMENT(gpu_info)) GPU
  * The varible \p mygpu is the index of the GPU to initialize in the
  * gpu_info.gpu_dev array.
  *
- * \param[out] fplog        log file to write to
+ * \param      mdlog        log file to write to
  * \param[in]  mygpu        index of the GPU to initialize
  * \param[out] result_str   the message related to the error that occurred
  *                          during the initialization (if there was any).
@@ -124,7 +129,7 @@ void free_gpu_info(const struct gmx_gpu_info_t *GPU_FUNC_ARGUMENT(gpu_info)) GPU
  * \returns                 true if no error occurs during initialization.
  */
 GPU_FUNC_QUALIFIER
-gmx_bool init_gpu(FILE *GPU_FUNC_ARGUMENT(fplog),
+gmx_bool init_gpu(const gmx::MDLogger &GPU_FUNC_ARGUMENT(mdlog),
                   int GPU_FUNC_ARGUMENT(mygpu),
                   char *GPU_FUNC_ARGUMENT(result_str),
                   const struct gmx_gpu_info_t *GPU_FUNC_ARGUMENT(gpu_info),
index 3a41f41bb976d10597d5dd6e340538ee3662a5e9..a03839217d5ae4c9439bb362432d92846b6ce9ba 100644 (file)
@@ -447,7 +447,7 @@ void get_gpu_device_info_string(char gmx_unused *s, const gmx_gpu_info_t gmx_unu
 }
 
 //! This function is documented in the header file
-gmx_bool init_gpu(FILE gmx_unused                 *fplog,
+gmx_bool init_gpu(const gmx::MDLogger              & /*mdlog*/,
                   int                              mygpu,
                   char                            *result_str,
                   const gmx_gpu_info_t gmx_unused *gpu_info,
@@ -461,7 +461,7 @@ gmx_bool init_gpu(FILE gmx_unused                 *fplog,
     if (mygpu < 0 || mygpu >= gpu_opt->n_dev_use)
     {
         char        sbuf[STRLEN];
-        sprintf(sbuf, "Trying to initialize an inexistent GPU: "
+        sprintf(sbuf, "Trying to initialize an non-existent GPU: "
                 "there are %d %s-selected GPU(s), but #%d was requested.",
                 gpu_opt->n_dev_use, gpu_opt->bUserSet ? "user" : "auto", mygpu);
         gmx_incons(sbuf);
index 5dccfa37d4865738f4306f6dbc7bc467c9f47067..87504467a5e6258d14fc363b9bebb9f29ae3d721 100644 (file)
@@ -50,7 +50,6 @@
 
 #include "thread_mpi/threads.h"
 
-#include "gromacs/gmxlib/md_logging.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/gpu_utils/gpu_utils.h"
 #include "gromacs/hardware/cpuinfo.h"
@@ -68,6 +67,7 @@
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/programcontext.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/stringutil.h"
@@ -174,9 +174,8 @@ static void sprint_gpus(char *sbuf, const gmx_gpu_info_t *gpu_info)
     }
 }
 
-static void print_gpu_detection_stats(FILE                 *fplog,
-                                      const gmx_gpu_info_t *gpu_info,
-                                      const t_commrec      *cr)
+static void print_gpu_detection_stats(const gmx::MDLogger  &mdlog,
+                                      const gmx_gpu_info_t *gpu_info)
 {
     char onhost[HOSTNAMELEN+10], stmp[STRLEN];
     int  ngpu;
@@ -201,12 +200,13 @@ static void print_gpu_detection_stats(FILE                 *fplog,
     if (ngpu > 0)
     {
         sprint_gpus(stmp, gpu_info);
-        md_print_warn(cr, fplog, "%d GPU%s detected%s:\n%s\n",
-                      ngpu, (ngpu > 1) ? "s" : "", onhost, stmp);
+        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                "%d GPU%s detected%s:\n%s",
+                ngpu, (ngpu > 1) ? "s" : "", onhost, stmp);
     }
     else
     {
-        md_print_warn(cr, fplog, "No GPUs detected%s\n", onhost);
+        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted("No GPUs detected%s", onhost);
     }
 }
 
@@ -295,8 +295,7 @@ makeGpuUsageReport(const gmx_gpu_info_t *gpu_info,
 /* Give a suitable fatal error or warning if the build configuration
    and runtime CPU do not match. */
 static void
-check_use_of_rdtscp_on_this_cpu(FILE                  *fplog,
-                                const t_commrec       *cr,
+check_use_of_rdtscp_on_this_cpu(const gmx::MDLogger   &mdlog,
                                 const gmx::CpuInfo    &cpuInfo)
 {
 #ifdef HAVE_RDTSCP
@@ -311,10 +310,11 @@ check_use_of_rdtscp_on_this_cpu(FILE                  *fplog,
     {
         if (binaryUsesRdtscp)
         {
-            md_print_warn(cr, fplog, "The %s executable was compiled to use the rdtscp CPU instruction. "
-                          "We cannot detect the features of your current CPU, but will proceed anyway. "
-                          "If you get a crash, rebuild GROMACS with the GMX_USE_RDTSCP=OFF CMake option.",
-                          programName);
+            GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                    "The %s executable was compiled to use the rdtscp CPU instruction. "
+                    "We cannot detect the features of your current CPU, but will proceed anyway. "
+                    "If you get a crash, rebuild GROMACS with the GMX_USE_RDTSCP=OFF CMake option.",
+                    programName);
         }
     }
     else
@@ -331,16 +331,17 @@ check_use_of_rdtscp_on_this_cpu(FILE                  *fplog,
 
         if (cpuHasRdtscp && !binaryUsesRdtscp)
         {
-            md_print_warn(cr, fplog, "The current CPU can measure timings more accurately than the code in\n"
-                          "%s was configured to use. This might affect your simulation\n"
-                          "speed as accurate timings are needed for load-balancing.\n"
-                          "Please consider rebuilding %s with the GMX_USE_RDTSCP=ON CMake option.\n",
-                          programName, programName);
+            GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                    "The current CPU can measure timings more accurately than the code in\n"
+                    "%s was configured to use. This might affect your simulation\n"
+                    "speed as accurate timings are needed for load-balancing.\n"
+                    "Please consider rebuilding %s with the GMX_USE_RDTSCP=ON CMake option.",
+                    programName, programName);
         }
     }
 }
 
-void gmx_check_hw_runconf_consistency(FILE                *fplog,
+void gmx_check_hw_runconf_consistency(const gmx::MDLogger &mdlog,
                                       const gmx_hw_info_t *hwinfo,
                                       const t_commrec     *cr,
                                       const gmx_hw_opt_t  *hw_opt,
@@ -382,18 +383,18 @@ void gmx_check_hw_runconf_consistency(FILE                *fplog,
 
     if (hwinfo->gpu_info.n_dev_compatible > 0)
     {
-        std::string gpuUseageReport;
+        std::string gpuUsageReport;
         try
         {
-            gpuUseageReport = makeGpuUsageReport(&hwinfo->gpu_info,
-                                                 &hw_opt->gpu_opt,
-                                                 cr->nrank_pp_intranode,
-                                                 bMPI && cr->nnodes > 1);
+            gpuUsageReport = makeGpuUsageReport(&hwinfo->gpu_info,
+                                                &hw_opt->gpu_opt,
+                                                cr->nrank_pp_intranode,
+                                                bMPI && cr->nnodes > 1);
         }
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
 
         /* NOTE: this print is only for and on one physical node */
-        md_print_info(cr, fplog, "%s\n", gpuUseageReport.c_str());
+        GMX_LOG(mdlog.warning).appendText(gpuUsageReport);
     }
 
     /* Need to ensure that we have enough GPUs:
@@ -461,13 +462,13 @@ void gmx_check_hw_runconf_consistency(FILE                *fplog,
             {
                 /* There are more GPUs than tMPI threads; we have
                    limited the number GPUs used. */
-                md_print_warn(cr, fplog,
-                              "NOTE: %d GPU%s were detected, but only %d PP thread-MPI thread%s can be started.\n"
-                              "      %s can use one GPU per PP tread-MPI thread, so only %d GPU%s will be used.\n",
-                              ngpu_comp, gpu_comp_plural,
-                              npppn, th_or_proc_plural,
-                              programName, npppn,
-                              npppn > 1 ? "s" : "");
+                GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                        "NOTE: %d GPU%s were detected, but only %d PP thread-MPI thread%s can be started.\n"
+                        "      %s can use one GPU per PP tread-MPI thread, so only %d GPU%s will be used.",
+                        ngpu_comp, gpu_comp_plural,
+                        npppn, th_or_proc_plural,
+                        programName, npppn,
+                        npppn > 1 ? "s" : "");
             }
         }
 
@@ -489,13 +490,13 @@ void gmx_check_hw_runconf_consistency(FILE                *fplog,
             /* TODO Should we have a gpu_opt->n_dev_supported field? */
             if (ngpu_comp > npppn && gmx_multiple_gpu_per_node_supported())
             {
-                md_print_warn(cr, fplog,
-                              "NOTE: potentially sub-optimal launch configuration, %s started with less\n"
-                              "      PP %s%s%s than GPU%s available.\n"
-                              "      Each PP %s can use only one GPU, %d GPU%s%s will be used.\n",
-                              programName, th_or_proc,
-                              th_or_proc_plural, pernode, gpu_comp_plural,
-                              th_or_proc, npppn, gpu_use_plural, pernode);
+                GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                        "NOTE: potentially sub-optimal launch configuration, %s started with less\n"
+                        "      PP %s%s%s than GPU%s available.\n"
+                        "      Each PP %s can use only one GPU, %d GPU%s%s will be used.",
+                        programName, th_or_proc,
+                        th_or_proc_plural, pernode, gpu_comp_plural,
+                        th_or_proc, npppn, gpu_use_plural, pernode);
             }
 
             if (ngpu_use != npppn)
@@ -538,9 +539,9 @@ void gmx_check_hw_runconf_consistency(FILE                *fplog,
 
             if (same_count > 0)
             {
-                md_print_info(cr, fplog,
-                              "NOTE: You assigned %s to multiple %s%s.\n",
-                              same_count > 1 ? "GPUs" : "a GPU", th_or_proc, btMPI ? "s" : "es");
+                GMX_LOG(mdlog.warning).appendTextFormatted(
+                        "NOTE: You assigned %s to multiple %s%s.",
+                        same_count > 1 ? "GPUs" : "a GPU", th_or_proc, btMPI ? "s" : "es");
             }
         }
     }
@@ -626,7 +627,7 @@ static int gmx_count_gpu_dev_unique(const gmx_gpu_info_t *gpu_info,
     return uniq_count;
 }
 
-static void gmx_detect_gpus(FILE *fplog, const t_commrec *cr)
+static void gmx_detect_gpus(const gmx::MDLogger &mdlog, const t_commrec *cr)
 {
 #if GMX_LIB_MPI
     int              rank_world;
@@ -654,6 +655,7 @@ static void gmx_detect_gpus(FILE *fplog, const t_commrec *cr)
     MPI_Comm_split(MPI_COMM_WORLD, gmx_physicalnode_id_hash(),
                    rank_world, &physicalnode_comm);
     MPI_Comm_rank(physicalnode_comm, &rank_local);
+    GMX_UNUSED_VALUE(cr);
 #else
     /* Here there should be only one process, check this */
     GMX_RELEASE_ASSERT(cr->nnodes == 1 && cr->sim_nodeid == 0, "Only a single (master) process should execute here");
@@ -679,10 +681,10 @@ static void gmx_detect_gpus(FILE *fplog, const t_commrec *cr)
             {
                 sprintf(sbuf, ".");
             }
-            md_print_warn(cr, fplog,
-                          "NOTE: Error occurred during GPU detection%s"
-                          "      Can not use GPU acceleration, will fall back to CPU kernels.\n",
-                          sbuf);
+            GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                    "NOTE: Error occurred during GPU detection%s"
+                    "      Can not use GPU acceleration, will fall back to CPU kernels.",
+                    sbuf);
         }
     }
 
@@ -857,14 +859,12 @@ static void
 spinUpCore() noexcept
 {
 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_CONF) && defined(_SC_NPROCESSORS_ONLN)
-    // steady_clock is better than system_clock, but unsupported in gcc-4.6.4.
-    // For release-2017 we can retire gcc-4.6 support and move to steady_clock.
     float dummy           = 0.1;
     int   countConfigured = sysconf(_SC_NPROCESSORS_CONF);    // noexcept
-    auto  start           = std::chrono::system_clock::now(); // noexcept
+    auto  start           = std::chrono::steady_clock::now(); // noexcept
 
     while (sysconf(_SC_NPROCESSORS_ONLN) < countConfigured &&
-           std::chrono::system_clock::now() - start < std::chrono::seconds(2))
+           std::chrono::steady_clock::now() - start < std::chrono::seconds(2))
     {
         for (int i = 1; i < 10000; i++)
         {
@@ -924,19 +924,17 @@ hardwareTopologyPrepareDetection()
 #endif
 }
 
-/*! \brief Sanity check hardware topology and optionally print some notes to log
+/*! \brief Sanity check hardware topology and print some notes to log
  *
- *  \param fplog            Log file pointer. This can be NULL, but the then routine
- *                          will not do anything.
+ *  \param mdlog            Logger.
  *  \param hardwareTopology Reference to hardwareTopology object.
  */
 static void
-hardwareTopologyDoubleCheckDetection(FILE gmx_unused                          *fplog,
-                                     const gmx::HardwareTopology gmx_unused   &hardwareTopology)
+hardwareTopologyDoubleCheckDetection(const gmx::MDLogger gmx_unused         &mdlog,
+                                     const gmx::HardwareTopology gmx_unused &hardwareTopology)
 {
 #if defined HAVE_SYSCONF && defined(_SC_NPROCESSORS_CONF)
-    if (fplog == NULL ||
-        hardwareTopology.supportLevel() < gmx::HardwareTopology::SupportLevel::LogicalProcessorCount)
+    if (hardwareTopology.supportLevel() < gmx::HardwareTopology::SupportLevel::LogicalProcessorCount)
     {
         return;
     }
@@ -951,24 +949,27 @@ hardwareTopologyDoubleCheckDetection(FILE gmx_unused                          *f
      */
     if (countConfigured >= 0 && countConfigured != countFromDetection)
     {
-        fprintf(fplog, "Note: %d CPUs configured, but only %d were detected to be online.\n", countConfigured, countFromDetection);
+        GMX_LOG(mdlog.info).
+            appendTextFormatted("Note: %d CPUs configured, but only %d were detected to be online.\n", countConfigured, countFromDetection);
 
         if (isX86 && countConfigured == 2*countFromDetection)
         {
-            fprintf(fplog, "      X86 Hyperthreading is likely disabled; enable it for better performance.\n");
+            GMX_LOG(mdlog.info).
+                appendText("      X86 Hyperthreading is likely disabled; enable it for better performance.");
         }
         // For PowerPC (likely Power8) it is possible to set SMT to either 2,4, or 8-way hardware threads.
         // We only warn if it is completely disabled since default performance drops with SMT8.
         if (isPowerPC && countConfigured == 8*countFromDetection)
         {
-            fprintf(fplog, "      PowerPC SMT is likely disabled; enable SMT2/SMT4 for better performance.\n");
+            GMX_LOG(mdlog.info).
+                appendText("      PowerPC SMT is likely disabled; enable SMT2/SMT4 for better performance.");
         }
     }
 #endif
 }
 
 
-gmx_hw_info_t *gmx_detect_hardware(FILE *fplog, const t_commrec *cr,
+gmx_hw_info_t *gmx_detect_hardware(const gmx::MDLogger &mdlog, const t_commrec *cr,
                                    gmx_bool bDetectGPUs)
 {
     int ret;
@@ -993,7 +994,7 @@ gmx_hw_info_t *gmx_detect_hardware(FILE *fplog, const t_commrec *cr,
         // If we detected the topology on this system, double-check that it makes sense
         if (hwinfo_g->hardwareTopology->isThisSystem())
         {
-            hardwareTopologyDoubleCheckDetection(fplog, *(hwinfo_g->hardwareTopology));
+            hardwareTopologyDoubleCheckDetection(mdlog, *(hwinfo_g->hardwareTopology));
         }
 
         // TODO: Get rid of this altogether.
@@ -1012,7 +1013,7 @@ gmx_hw_info_t *gmx_detect_hardware(FILE *fplog, const t_commrec *cr,
              getenv("GMX_DISABLE_GPU_DETECTION") == NULL);
         if (hwinfo_g->gpu_info.bDetectGPUs)
         {
-            gmx_detect_gpus(fplog, cr);
+            gmx_detect_gpus(mdlog, cr);
         }
 
         gmx_collect_hardware_mpi(*hwinfo_g->cpuInfo);
@@ -1262,6 +1263,7 @@ static std::string detected_hardware_string(const gmx_hw_info_t *hwinfo,
 }
 
 void gmx_print_detected_hardware(FILE *fplog, const t_commrec *cr,
+                                 const gmx::MDLogger &mdlog,
                                  const gmx_hw_info_t *hwinfo)
 {
     const gmx::CpuInfo &cpuInfo = *hwinfo_g->cpuInfo;
@@ -1293,7 +1295,7 @@ void gmx_print_detected_hardware(FILE *fplog, const t_commrec *cr,
     }
 
     /* For RDTSCP we only check on our local node and skip the MPI reduction */
-    check_use_of_rdtscp_on_this_cpu(fplog, cr, cpuInfo);
+    check_use_of_rdtscp_on_this_cpu(mdlog, cpuInfo);
 }
 
 //! \brief Return if any GPU ID (e.g in a user-supplied string) is repeated
@@ -1363,7 +1365,7 @@ void gmx_parse_gpu_ids(gmx_gpu_opt_t *gpu_opt)
     }
 }
 
-void gmx_select_gpu_ids(FILE *fplog, const t_commrec *cr,
+void gmx_select_gpu_ids(const gmx::MDLogger &mdlog, const t_commrec *cr,
                         const gmx_gpu_info_t *gpu_info,
                         gmx_bool bForceUseGPU,
                         gmx_gpu_opt_t *gpu_opt)
@@ -1399,7 +1401,7 @@ void gmx_select_gpu_ids(FILE *fplog, const t_commrec *cr,
 
         if (!res)
         {
-            print_gpu_detection_stats(fplog, gpu_info, cr);
+            print_gpu_detection_stats(mdlog, gpu_info);
 
             sprintf(sbuf, "Some of the requested GPUs do not exist, behave strangely, or are not compatible:\n");
             for (i = 0; i < gpu_opt->n_dev_use; i++)
index e002d47d16e3bee26e21863002e9617232e05c13..37b71d561da6ced76b71da6e816b491406428097 100644 (file)
@@ -47,10 +47,9 @@ struct t_commrec;
 
 namespace gmx
 {
-
 class HardwareTopology;
-
-} // namespace
+class MDLogger;
+}
 
 /*! \brief Return whether mdrun can use more than one GPU per node
  *
@@ -72,27 +71,28 @@ gmx_bool gmx_gpu_sharing_supported();
  * available on all nodes.
  * Caller is responsible for freeing this pointer.
  */
-gmx_hw_info_t *gmx_detect_hardware(FILE *fplog, const t_commrec *cr,
-                                   gmx_bool bDetectGPUs);
+gmx_hw_info_t *gmx_detect_hardware(const gmx::MDLogger &mdlog,
+                                   const t_commrec *cr, gmx_bool bDetectGPUs);
 
 /* Print information about the detected hardware to fplog (if != NULL)
  * and to stderr the master rank.
  */
 void gmx_print_detected_hardware(FILE *fplog, const t_commrec *cr,
+                                 const gmx::MDLogger &mdlog,
                                  const gmx_hw_info_t *hwinfo);
 
 void gmx_hardware_info_free(gmx_hw_info_t *hwinfo);
 
 void gmx_parse_gpu_ids(gmx_gpu_opt_t *gpu_opt);
 
-void gmx_select_gpu_ids(FILE *fplog, const t_commrec *cr,
+void gmx_select_gpu_ids(const gmx::MDLogger &mdlog, const t_commrec *cr,
                         const gmx_gpu_info_t *gpu_info,
                         gmx_bool bForceUseGPU,
                         gmx_gpu_opt_t *gpu_opt);
 
 /* Check the consistency of hw_opt with hwinfo.
    This function should be called once on each MPI rank. */
-void gmx_check_hw_runconf_consistency(FILE                *fplog,
+void gmx_check_hw_runconf_consistency(const gmx::MDLogger &mdlog,
                                       const gmx_hw_info_t *hwinfo,
                                       const t_commrec     *cr,
                                       const gmx_hw_opt_t  *hw_opt,
index 84b8e3cb38acf71ad462f96889de05cd537dc621..dfe5dbaec0144dcaec5ff8e0e38bfc2d9136a36d 100644 (file)
@@ -582,13 +582,6 @@ HardwareTopology HardwareTopology::detect()
 {
     HardwareTopology result;
 
-    // Default values for machine and numa stuff
-    result.machine_.logicalProcessorCount   = 0;
-    result.machine_.numa.baseLatency        = 0.0;
-    result.machine_.numa.maxRelativeLatency = 0.0;
-    result.supportLevel_                    = SupportLevel::None;
-    result.isThisSystem_                    = true;
-
 #if GMX_HWLOC
     parseHwLoc(&result.machine_, &result.supportLevel_, &result.isThisSystem_);
 #endif
@@ -613,12 +606,33 @@ HardwareTopology HardwareTopology::detect()
     return result;
 }
 
+HardwareTopology::Machine::Machine()
+{
+    logicalProcessorCount   = 0;
+    numa.baseLatency        = 0.0;
+    numa.maxRelativeLatency = 0.0;
+}
+
 
 HardwareTopology::HardwareTopology()
-    : supportLevel_(SupportLevel::None)
+    : supportLevel_(SupportLevel::None),
+      machine_(),
+      isThisSystem_(true)
 {
 }
 
+HardwareTopology::HardwareTopology(int logicalProcessorCount)
+    : supportLevel_(SupportLevel::None),
+      machine_(),
+      isThisSystem_(true)
+{
+    if (logicalProcessorCount > 0)
+    {
+        machine_.logicalProcessorCount = logicalProcessorCount;
+        supportLevel_                  = SupportLevel::LogicalProcessorCount;
+    }
+}
+
 int HardwareTopology::numberOfCores() const
 {
     if (supportLevel() >= SupportLevel::Basic)
index f766a4d695d9eeb4266a5a1eac1ff069d6276f20..b2dcf352cb8fe65511f50cc06babb039e7216567 100644 (file)
@@ -177,6 +177,8 @@ class HardwareTopology
          */
         struct Machine
         {
+            Machine();
+
             int                            logicalProcessorCount; //!< Number of logical processors in system
             std::vector<LogicalProcessor>  logicalProcessors;     //!< Map logical processors to socket/core
             std::vector<Socket>            sockets;               //!< All the sockets in the system
@@ -190,6 +192,14 @@ class HardwareTopology
         /*! \brief Detects the hardware topology. */
         static HardwareTopology detect();
 
+        /*! \brief Creates a topology with given number of logical cores.
+         *
+         * The support level will be either None or LogicalProcessorCount.
+         *
+         * Intended for testing of code that uses the hardware topology.
+         */
+        explicit HardwareTopology(int logicalProcessorCount);
+
         /*! \brief Check what topology information that is available and valid
          *
          *  The amount of hardware topology information that can be detected depends
index 950d9392aac3d2501b6079bd3a4ba988c43192f0..7c9fdb5aae5f3e7d8469aa578147ad52ad1ddad1 100644 (file)
@@ -48,7 +48,7 @@ F77_FUNC(dbdsqr,DBDSQR)(const char *uplo,
     double unfl, sinl, cosr, smin, smax, sinr;
     double oldcs;
     int oldll;
-    double shift, sigmn, oldsn;
+    double shift, sigmn, oldsn = 0.;
     int maxit;
     double sminl;
     double sigmx;
index 2cd91a2fe4ac5ad5aa12bf7c42194fe443b407d8..18f302a5153242669b663caf30411215a02dca10 100644 (file)
@@ -48,7 +48,7 @@ F77_FUNC(sbdsqr,SBDSQR)(const char *uplo,
     float unfl, sinl, cosr, smin, smax, sinr;
     float oldcs;
     int oldll;
-    float shift, sigmn, oldsn;
+    float shift, sigmn, oldsn = 0.;
     int maxit;
     float sminl;
     float sigmx;
index 94fe43128c4f99ea808b287fe5bf9b05d71da0d8..30505b0e5fc795a896b3ee61228ca8a42363eb05 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016, 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.
@@ -61,7 +61,7 @@ using gmx::RVec;
 TEST(RVecTest, CanBeStoredInVector)
 {
     std::vector<RVec> v;
-    v.push_back(RVec(1, 2, 3));
+    v.emplace_back(1, 2, 3);
     v.resize(2);
     EXPECT_EQ(1, v[0][XX]);
     EXPECT_EQ(2, v[0][YY]);
@@ -72,7 +72,7 @@ TEST(RVecTest, ConvertsImplicitlyFrom_rvec)
 {
     std::vector<RVec> v;
     rvec              x = { 1, 2, 3 };
-    v.push_back(x);
+    v.emplace_back(x);
     EXPECT_EQ(1, v[0][XX]);
     EXPECT_EQ(2, v[0][YY]);
     EXPECT_EQ(3, v[0][ZZ]);
@@ -81,7 +81,7 @@ TEST(RVecTest, ConvertsImplicitlyFrom_rvec)
 TEST(RVecTest, ConvertsImplicitlyTo_rvec)
 {
     std::vector<RVec> v;
-    v.push_back(RVec(1, 2, 3));
+    v.emplace_back(1, 2, 3);
     rvec              x;
     copy_rvec(v[0], x);
     EXPECT_EQ(1, x[XX]);
@@ -92,7 +92,7 @@ TEST(RVecTest, ConvertsImplicitlyTo_rvec)
 TEST(RVecTest, WorksAsMutable_rvec)
 {
     std::vector<RVec> v;
-    v.push_back(RVec(1, 2, 3));
+    v.emplace_back(1, 2, 3);
     rvec              x = {2, 3, 4};
     copy_rvec(x, v[0]);
     EXPECT_EQ(2, v[0][XX]);
@@ -103,8 +103,8 @@ TEST(RVecTest, WorksAsMutable_rvec)
 TEST(RVecTest, WorksAs_rvec_Array)
 {
     std::vector<RVec> v;
-    v.push_back(RVec(1, 2, 3));
-    v.push_back(RVec(2, 3, 4));
+    v.emplace_back(1, 2, 3);
+    v.emplace_back(2, 3, 4);
     const rvec *r = as_rvec_array(v.data());
     EXPECT_EQ(1, r[0][XX]);
     EXPECT_EQ(2, r[0][YY]);
diff --git a/src/gromacs/math/veccompare.cpp b/src/gromacs/math/veccompare.cpp
new file mode 100644 (file)
index 0000000..54eece9
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * 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
+ * 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 "gmxpre.h"
+
+#include "veccompare.h"
+
+#include <cmath>
+#include <cstdio>
+
+#include "gromacs/utility/compare.h"
+
+void cmp_rvec(FILE *fp, const char *s, int index, const rvec i1, const rvec i2, real ftol, real abstol)
+{
+    if (!equal_real(i1[XX], i2[XX], ftol, abstol) ||
+        !equal_real(i1[YY], i2[YY], ftol, abstol) ||
+        !equal_real(i1[ZZ], i2[ZZ], ftol, abstol))
+    {
+        if (index != -1)
+        {
+            fprintf(fp, "%s[%5d] (%12.5e %12.5e %12.5e) - (%12.5e %12.5e %12.5e)\n",
+                    s, index, i1[XX], i1[YY], i1[ZZ], i2[XX], i2[YY], i2[ZZ]);
+        }
+        else
+        {
+            fprintf(fp, "%s (%12.5e %12.5e %12.5e) - (%12.5e %12.5e %12.5e)\n",
+                    s, i1[XX], i1[YY], i1[ZZ], i2[XX], i2[YY], i2[ZZ]);
+        }
+    }
+}
+
+void cmp_ivec(FILE *fp, const char *s, int index, const ivec i1, const ivec i2)
+{
+    if ((i1[XX] != i2[XX]) || (i1[YY] != i2[YY]) || (i1[ZZ] != i2[ZZ]))
+    {
+        if (index != -1)
+        {
+            fprintf(fp, "%s[%5d] (%8d,%8d,%8d - %8d,%8d,%8d)\n", s, index,
+                    i1[XX], i1[YY], i1[ZZ], i2[XX], i2[YY], i2[ZZ]);
+        }
+        else
+        {
+            fprintf(fp, "%s (%8d,%8d,%8d - %8d,%8d,%8d)\n", s,
+                    i1[XX], i1[YY], i1[ZZ], i2[XX], i2[YY], i2[ZZ]);
+        }
+    }
+}
+
+static void cmp_rvecs_rmstol(FILE *fp, const char *title, int n, const rvec x1[], const rvec x2[],
+                             real ftol, real abstol)
+{
+    int    i, m;
+    double rms;
+
+    /* For a vector you are usally not interested in a relative difference
+     * on a component that is very small compared to the other components.
+     * Therefore we do the relative comparision relative to the RMS component.
+     */
+    rms = 0.0;
+    for (i = 0; (i < n); i++)
+    {
+        for (m = 0; m < DIM; m++)
+        {
+            rms += x1[i][m]*x1[i][m] + x2[i][m]*x2[i][m];
+        }
+    }
+    rms = sqrt(rms/(2*n*DIM));
+
+    /* Convert the relative tolerance into an absolute tolerance */
+    if (ftol*rms < abstol)
+    {
+        abstol = ftol*rms;
+    }
+
+    /* And now do the actual comparision */
+    for (i = 0; (i < n); i++)
+    {
+        cmp_rvec(fp, title, i, x1[i], x2[i], 0.0, abstol);
+    }
+}
+
+void cmp_rvecs(FILE *fp, const char *title, int n, const rvec x1[], const rvec x2[],
+               gmx_bool bRMSD, real ftol, real abstol)
+{
+    int    i, m;
+    double d, ssd;
+
+    if (bRMSD)
+    {
+        ssd = 0;
+        for (i = 0; (i < n); i++)
+        {
+            for (m = 0; m < DIM; m++)
+            {
+                d    = x1[i][m] - x2[i][m];
+                ssd += d*d;
+            }
+        }
+        fprintf(fp, "%s RMSD %g\n", title, std::sqrt(ssd/n));
+    }
+    else
+    {
+        cmp_rvecs_rmstol(fp, title, n, x1, x2, ftol, abstol);
+    }
+}
similarity index 70%
rename from src/gromacs/tools/compare.h
rename to src/gromacs/math/veccompare.h
index 1ea889841a8e9225933c83bb8eea35f1f553c315..4b8ccca57598e4b5151e6a09d53ff4d5e5870a41 100644 (file)
  * To help us fund GROMACS development, we humbly ask that you cite
  * the research papers on the package. Check out http://www.gromacs.org.
  */
+#ifndef GMX_MATH_VECCOMPARE_H
+#define GMX_MATH_VECCOMPARE_H
 
-#ifndef GMX_TOOLS_COMPARE_H
-#define GMX_TOOLS_COMPARE_H
+#include <cstdio>
 
-struct gmx_output_env_t;
+#include "gromacs/math/vectypes.h"
+#include "gromacs/utility/basedefinitions.h"
+#include "gromacs/utility/real.h"
 
-/* Routines for comparing data structures from non-trajectory binary
-   file formats (e.g. as used by gmx check). */
+void cmp_rvec(FILE *fp, const char *s, int index, const rvec i1, const rvec i2, real ftol, real abstol);
 
-void
-comp_tpx(const char *fn1, const char *fn2, gmx_bool bRMSD, real ftol, real abstol);
-/* Compare two binary run input files */
+void cmp_ivec(FILE *fp, const char *s, int index, const ivec i1, const ivec i2);
 
-void comp_tpx_a_and_b_states(const char *fn, real ftol, real abstol);
-/* Compare two A and B states of a free-energy run input file. */
-
-void
-comp_trx(const gmx_output_env_t *oenv, const char *fn1, const char *fn2,
-         gmx_bool bRMSD, real ftol, real abstol);
-/* Compare two binary trajectory files */
-
-void
-comp_enx(const char *fn1, const char *fn2, real ftol, real abstol,
-         const char *lastener);
-/* Compare two binary energy files */
+void cmp_rvecs(FILE *fp, const char *title, int n, const rvec x1[], const rvec x2[],
+               gmx_bool bRMSD, real ftol, real abstol);
 
 #endif
index 6e9f04785c2244e6c209e34e9d622ed8c3f34c0d..ba50858af25a4f320017e574d505c25e03b311dc 100644 (file)
 #include "gromacs/utility/smalloc.h"
 
 #define   block_bc(cr,   d) gmx_bcast(     sizeof(d),     &(d), (cr))
-/* Probably the test for (nr) > 0 in the next macro is only needed
- * on BlueGene(/L), where IBM's MPI_Bcast will segfault after
- * dereferencing a null pointer, even when no data is to be transferred. */
-#define  nblock_bc(cr, nr, d) { if ((nr) > 0) {gmx_bcast((nr)*sizeof((d)[0]), (d), (cr)); }}
+#define  nblock_bc(cr, nr, d) { gmx_bcast((nr)*sizeof((d)[0]), (d), (cr)); }
 #define    snew_bc(cr, d, nr) { if (!MASTER(cr)) {snew((d), (nr)); }}
 /* Dirty macro with bAlloc not as an argument */
 #define nblock_abc(cr, nr, d) { if (bAlloc) {snew((d), (nr)); } nblock_bc(cr, (nr), (d)); }
index e45b6a0e0d3b3c71046f5bb6ab9c643d5cbfc957..c422a4bf1fd2fc9144e161ef0cf38ac2da8938c1 100644 (file)
@@ -1300,9 +1300,9 @@ gmx_constr_t init_constraints(FILE *fplog,
     /* Initialize the essential dynamics sampling.
      * Put the pointer to the ED struct in constr */
     constr->ed = ed;
-    if (ed != NULL || state->edsamstate.nED > 0)
+    if (ed != NULL || state->edsamstate != NULL)
     {
-        init_edsam(mtop, ir, cr, ed, state->x, state->box, &state->edsamstate);
+        init_edsam(mtop, ir, cr, ed, state->x, state->box, state->edsamstate);
     }
 
     constr->warn_mtop = mtop;
index 50c9a1b463fbc85c60d0ed59f4c9475f1ba1bdfb..b3f8657c08ce08fb6e7e89c9b8a3ec4f9d075369 100644 (file)
@@ -118,6 +118,8 @@ gmx_bool bshakef(FILE           *log,          /* Log file                  */
 gmx_settledata_t settle_init(const gmx_mtop_t *mtop);
 /* Initializes and returns a structure with SETTLE parameters */
 
+void settle_free(gmx_settledata_t settled);
+
 void settle_set_constraints(gmx_settledata_t  settled,
                             const t_ilist    *il_settle,
                             const t_mdatoms  *mdatoms);
index 092ee94ac94b6eca9922bc0bafcddd167f7c6a9f..74e9d498c3722ad6350ba6f0175a5b82289b1bf7 100644 (file)
@@ -94,44 +94,43 @@ typedef struct gmx_settledata
 } t_gmx_settledata;
 
 
-static void init_proj_matrix(settleparam_t *p,
-                             real invmO, real invmH, real dOH, real dHH)
+static void init_proj_matrix(real invmO, real invmH, real dOH, real dHH,
+                             matrix inverseCouplingMatrix)
 {
-    real   imOn, imHn;
-    matrix mat;
-
-    p->imO = invmO;
-    p->imH = invmH;
-    /* We normalize the inverse masses with imO for the matrix inversion.
+    /* We normalize the inverse masses with invmO for the matrix inversion.
      * so we can keep using masses of almost zero for frozen particles,
      * without running out of the float range in invertMatrix.
      */
-    imOn = 1;
-    imHn = p->imH/p->imO;
+    double invmORelative = 1.0;
+    double invmHRelative = invmH/static_cast<double>(invmO);
+    double distanceRatio = dHH/static_cast<double>(dOH);
 
     /* Construct the constraint coupling matrix */
-    mat[0][0] = imOn + imHn;
-    mat[0][1] = imOn*(1 - 0.5*dHH*dHH/(dOH*dOH));
-    mat[0][2] = imHn*0.5*dHH/dOH;
+    matrix mat;
+    mat[0][0] = invmORelative + invmHRelative;
+    mat[0][1] = invmORelative*(1.0 - 0.5*gmx::square(distanceRatio));
+    mat[0][2] = invmHRelative*0.5*distanceRatio;
     mat[1][1] = mat[0][0];
     mat[1][2] = mat[0][2];
-    mat[2][2] = imHn + imHn;
+    mat[2][2] = invmHRelative + invmHRelative;
     mat[1][0] = mat[0][1];
     mat[2][0] = mat[0][2];
     mat[2][1] = mat[1][2];
 
-    gmx::invertMatrix(mat, p->invmat);
+    invertMatrix(mat, inverseCouplingMatrix);
 
-    msmul(p->invmat, 1/p->imO, p->invmat);
-
-    p->invdOH = 1/dOH;
-    p->invdHH = 1/dHH;
+    msmul(inverseCouplingMatrix, 1/invmO, inverseCouplingMatrix);
 }
 
 static void settleparam_init(settleparam_t *p,
                              real mO, real mH, real invmO, real invmH,
                              real dOH, real dHH)
 {
+    /* We calculate parameters in double precision to minimize errors.
+     * The velocity correction applied during SETTLE coordinate constraining
+     * introduces a systematic error of approximately 1 bit per atom,
+     * depending on what the compiler does with the code.
+     */
     double wohh;
 
     p->mO     = mO;
@@ -140,13 +139,21 @@ static void settleparam_init(settleparam_t *p,
     p->wh     = mH/wohh;
     p->dOH    = dOH;
     p->dHH    = dHH;
-    p->rc     = dHH/2.0;
-    p->ra     = 2.0*mH*sqrt(dOH*dOH - p->rc*p->rc)/wohh;
-    p->rb     = sqrt(dOH*dOH - p->rc*p->rc) - p->ra;
+    double rc = dHH/2.0;
+    double ra = 2.0*mH*std::sqrt(dOH*dOH - rc*rc)/wohh;
+    p->rb     = std::sqrt(dOH*dOH - rc*rc) - ra;
+    p->rc     = rc;
+    p->ra     = ra;
     p->irc2   = 1.0/dHH;
 
-    /* For projection: connection matrix inversion */
-    init_proj_matrix(p, invmO, invmH, dOH, dHH);
+    /* For projection: inverse masses and coupling matrix inversion */
+    p->imO    = invmO;
+    p->imH    = invmH;
+
+    p->invdOH = 1.0/dOH;
+    p->invdHH = 1.0/dHH;
+
+    init_proj_matrix(invmO, invmH, dOH, dHH, p->invmat);
 
     if (debug)
     {
@@ -213,6 +220,15 @@ gmx_settledata_t settle_init(const gmx_mtop_t *mtop)
     return settled;
 }
 
+void settle_free(gmx_settledata_t settled)
+{
+    sfree_aligned(settled->ow1);
+    sfree_aligned(settled->hw2);
+    sfree_aligned(settled->hw3);
+    sfree_aligned(settled->virfac);
+    sfree(settled);
+}
+
 void settle_set_constraints(gmx_settledata_t  settled,
                             const t_ilist    *il_settle,
                             const t_mdatoms  *mdatoms)
index fa592e1993b0a7736fe2c524975858c6f2c0bf29..30c0ed7ecf18cb2e41d7034573105ebf8781802c 100644 (file)
@@ -496,14 +496,7 @@ void do_force_lowlevel(t_forcerec *fr,      t_inputrec *ir,
                 if (fr->n_tpi == 0 || (flags & GMX_FORCE_STATECHANGED))
                 {
                     pme_flags = GMX_PME_SPREAD | GMX_PME_SOLVE;
-                    if (EEL_PME(fr->eeltype))
-                    {
-                        pme_flags     |= GMX_PME_DO_COULOMB;
-                    }
-                    if (EVDW_PME(fr->vdwtype))
-                    {
-                        pme_flags |= GMX_PME_DO_LJ;
-                    }
+
                     if (flags & GMX_FORCE_FORCES)
                     {
                         pme_flags |= GMX_PME_CALC_F;
@@ -528,8 +521,7 @@ void do_force_lowlevel(t_forcerec *fr,      t_inputrec *ir,
                                         DOMAINDECOMP(cr) ? dd_pme_maxshift_x(cr->dd) : 0,
                                         DOMAINDECOMP(cr) ? dd_pme_maxshift_y(cr->dd) : 0,
                                         nrnb, wcycle,
-                                        fr->vir_el_recip, fr->ewaldcoeff_q,
-                                        fr->vir_lj_recip, fr->ewaldcoeff_lj,
+                                        fr->vir_el_recip, fr->vir_lj_recip,
                                         &Vlr_q, &Vlr_lj,
                                         lambda[efptCOUL], lambda[efptVDW],
                                         &dvdl_long_range_q, &dvdl_long_range_lj, pme_flags);
index 3fe505cf0b4f3397ac061371fdc115d1a1b5d8fb..4d145f582b5988b90f0bda062d66316fed598c0f 100644 (file)
@@ -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, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, 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.
@@ -60,6 +60,11 @@ struct t_mdatoms;
 struct t_nrnb;
 struct t_pbc;
 
+namespace gmx
+{
+class MDLogger;
+}
+
 void calc_vir(int nxf, rvec x[], rvec f[], tensor vir,
               gmx_bool bScrewPBC, matrix box);
 /* Calculate virial for nxf atoms, and add it to vir */
@@ -106,19 +111,17 @@ gmx_bool can_use_allvsall(const t_inputrec *ir,
  */
 
 
-gmx_bool nbnxn_gpu_acceleration_supported(FILE             *fplog,
-                                          const t_commrec  *cr,
-                                          const t_inputrec *ir,
-                                          gmx_bool          bRerunMD);
+gmx_bool nbnxn_gpu_acceleration_supported(const gmx::MDLogger &mdlog,
+                                          const t_inputrec    *ir,
+                                          gmx_bool             bRerunMD);
 /* Return if GPU acceleration is supported with the given settings.
  *
  * If the return value is FALSE and fplog/cr != NULL, prints a fallback
  * message to fplog/stderr.
  */
 
-gmx_bool nbnxn_simd_supported(FILE             *fplog,
-                              const t_commrec  *cr,
-                              const t_inputrec *ir);
+gmx_bool nbnxn_simd_supported(const gmx::MDLogger &mdlog,
+                              const t_inputrec    *ir);
 /* Return if CPU SIMD support exists for the given inputrec
  * If the return value is FALSE and fplog/cr != NULL, prints a fallback
  * message to fplog/stderr.
index 6b5a102f83a2f9adc68960e8b672e1c253384ca1..9b9b983734d1370c94ebb51d7412cd301c09888f 100644 (file)
@@ -53,7 +53,6 @@
 #include "gromacs/domdec/domdec_struct.h"
 #include "gromacs/ewald/ewald.h"
 #include "gromacs/fileio/filetypes.h"
-#include "gromacs/gmxlib/md_logging.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/gmxlib/nonbonded/nonbonded.h"
 #include "gromacs/gpu_utils/gpu_utils.h"
@@ -93,6 +92,7 @@
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/pleasecite.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/stringutil.h"
@@ -1574,10 +1574,9 @@ gmx_bool can_use_allvsall(const t_inputrec *ir, gmx_bool bPrintNote, t_commrec *
 }
 
 
-gmx_bool nbnxn_gpu_acceleration_supported(FILE             *fplog,
-                                          const t_commrec  *cr,
-                                          const t_inputrec *ir,
-                                          gmx_bool          bRerunMD)
+gmx_bool nbnxn_gpu_acceleration_supported(const gmx::MDLogger &mdlog,
+                                          const t_inputrec    *ir,
+                                          gmx_bool             bRerunMD)
 {
     if (bRerunMD && ir->opts.ngener > 1)
     {
@@ -1589,23 +1588,22 @@ gmx_bool nbnxn_gpu_acceleration_supported(FILE             *fplog,
          * (which runs much faster than a multiple-energy-groups
          * implementation would), and issue a note in the .log
          * file. Users can re-run if they want the information. */
-        md_print_warn(cr, fplog, "Rerun with energy groups is not implemented for GPUs, falling back to the CPU\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText("Rerun with energy groups is not implemented for GPUs, falling back to the CPU");
         return FALSE;
     }
 
     return TRUE;
 }
 
-gmx_bool nbnxn_simd_supported(FILE             *fplog,
-                              const t_commrec  *cr,
-                              const t_inputrec *ir)
+gmx_bool nbnxn_simd_supported(const gmx::MDLogger &mdlog,
+                              const t_inputrec    *ir)
 {
     if (ir->vdwtype == evdwPME && ir->ljpme_combination_rule == eljpmeLB)
     {
         /* LJ PME with LB combination rule does 7 mesh operations.
          * This so slow that we don't compile SIMD non-bonded kernels
          * for that. */
-        md_print_warn(cr, fplog, "LJ-PME with Lorentz-Berthelot is not supported with SIMD kernels, falling back to plain C kernels\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText("LJ-PME with Lorentz-Berthelot is not supported with SIMD kernels, falling back to plain C kernels");
         return FALSE;
     }
 
@@ -1736,7 +1734,7 @@ const char *lookup_nbnxn_kernel_name(int kernel_type)
 };
 
 static void pick_nbnxn_kernel(FILE                *fp,
-                              const t_commrec     *cr,
+                              const gmx::MDLogger &mdlog,
                               gmx_bool             use_simd_kernels,
                               gmx_bool             bUseGPU,
                               gmx_bool             bEmulateGPU,
@@ -1756,7 +1754,7 @@ static void pick_nbnxn_kernel(FILE                *fp,
 
         if (bDoNonbonded)
         {
-            md_print_warn(cr, fp, "Emulating a GPU run on the CPU (slow)");
+            GMX_LOG(mdlog.warning).asParagraph().appendText("Emulating a GPU run on the CPU (slow)");
         }
     }
     else if (bUseGPU)
@@ -1767,7 +1765,7 @@ static void pick_nbnxn_kernel(FILE                *fp,
     if (*kernel_type == nbnxnkNotSet)
     {
         if (use_simd_kernels &&
-            nbnxn_simd_supported(fp, cr, ir))
+            nbnxn_simd_supported(mdlog, ir))
         {
             pick_nbnxn_kernel_cpu(ir, kernel_type, ewald_excl);
         }
@@ -1787,15 +1785,15 @@ static void pick_nbnxn_kernel(FILE                *fp,
         if (nbnxnk4x4_PlainC == *kernel_type ||
             nbnxnk8x8x8_PlainC == *kernel_type)
         {
-            md_print_warn(cr, fp,
-                          "WARNING: Using the slow %s kernels. This should\n"
-                          "not happen during routine usage on supported platforms.\n\n",
-                          lookup_nbnxn_kernel_name(*kernel_type));
+            GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                    "WARNING: Using the slow %s kernels. This should\n"
+                    "not happen during routine usage on supported platforms.",
+                    lookup_nbnxn_kernel_name(*kernel_type));
         }
     }
 }
 
-static void pick_nbnxn_resources(FILE                *fp,
+static void pick_nbnxn_resources(const gmx::MDLogger &mdlog,
                                  const t_commrec     *cr,
                                  const gmx_hw_info_t *hwinfo,
                                  gmx_bool             bDoNonbonded,
@@ -1830,7 +1828,7 @@ static void pick_nbnxn_resources(FILE                *fp,
     {
         /* Each PP node will use the intra-node id-th device from the
          * list of detected/selected GPUs. */
-        if (!init_gpu(fp, cr->rank_pp_intranode, gpu_err_str,
+        if (!init_gpu(mdlog, cr->rank_pp_intranode, gpu_err_str,
                       &hwinfo->gpu_info, gpu_opt))
         {
             /* At this point the init should never fail as we made sure that
@@ -2114,6 +2112,7 @@ init_interaction_const(FILE                       *fp,
 }
 
 static void init_nb_verlet(FILE                *fp,
+                           const gmx::MDLogger &mdlog,
                            nonbonded_verlet_t **nb_verlet,
                            gmx_bool             bFEP_NonBonded,
                            const t_inputrec    *ir,
@@ -2131,7 +2130,7 @@ static void init_nb_verlet(FILE                *fp,
 
     snew(nbv, 1);
 
-    pick_nbnxn_resources(fp, cr, fr->hwinfo,
+    pick_nbnxn_resources(mdlog, cr, fr->hwinfo,
                          fr->bNonbonded,
                          &nbv->bUseGPU,
                          &bEmulateGPU,
@@ -2149,7 +2148,7 @@ static void init_nb_verlet(FILE                *fp,
 
         if (i == 0) /* local */
         {
-            pick_nbnxn_kernel(fp, cr, fr->use_simd_kernels,
+            pick_nbnxn_kernel(fp, mdlog, fr->use_simd_kernels,
                               nbv->bUseGPU, bEmulateGPU, ir,
                               &nbv->grp[i].kernel_type,
                               &nbv->grp[i].ewald_excl,
@@ -2160,7 +2159,7 @@ static void init_nb_verlet(FILE                *fp,
             if (nbpu_opt != NULL && strcmp(nbpu_opt, "gpu_cpu") == 0)
             {
                 /* Use GPU for local, select a CPU kernel for non-local */
-                pick_nbnxn_kernel(fp, cr, fr->use_simd_kernels,
+                pick_nbnxn_kernel(fp, mdlog, fr->use_simd_kernels,
                                   FALSE, FALSE, ir,
                                   &nbv->grp[i].kernel_type,
                                   &nbv->grp[i].ewald_excl,
@@ -2313,19 +2312,20 @@ gmx_bool usingGpu(nonbonded_verlet_t *nbv)
     return nbv != NULL && nbv->bUseGPU;
 }
 
-void init_forcerec(FILE              *fp,
-                   t_forcerec        *fr,
-                   t_fcdata          *fcd,
-                   const t_inputrec  *ir,
-                   const gmx_mtop_t  *mtop,
-                   const t_commrec   *cr,
-                   matrix             box,
-                   const char        *tabfn,
-                   const char        *tabpfn,
-                   const t_filenm    *tabbfnm,
-                   const char        *nbpu_opt,
-                   gmx_bool           bNoSolvOpt,
-                   real               print_force)
+void init_forcerec(FILE                *fp,
+                   const gmx::MDLogger &mdlog,
+                   t_forcerec          *fr,
+                   t_fcdata            *fcd,
+                   const t_inputrec    *ir,
+                   const gmx_mtop_t    *mtop,
+                   const t_commrec     *cr,
+                   matrix               box,
+                   const char          *tabfn,
+                   const char          *tabpfn,
+                   const t_filenm      *tabbfnm,
+                   const char          *nbpu_opt,
+                   gmx_bool             bNoSolvOpt,
+                   real                 print_force)
 {
     int            i, m, negp_pp, negptable, egi, egj;
     real           rtab;
@@ -2343,7 +2343,7 @@ void init_forcerec(FILE              *fp,
          * In mdrun, hwinfo has already been set before calling init_forcerec.
          * Here we ignore GPUs, as tools will not use them anyhow.
          */
-        fr->hwinfo = gmx_detect_hardware(fp, cr, FALSE);
+        fr->hwinfo = gmx_detect_hardware(mdlog, cr, FALSE);
     }
 
     /* By default we turn SIMD kernels on, but it might be turned off further down... */
@@ -2436,9 +2436,9 @@ void init_forcerec(FILE              *fp,
     {
         /* turn off non-bonded calculations */
         fr->bNonbonded = FALSE;
-        md_print_warn(cr, fp,
-                      "Found environment variable GMX_NO_NONBONDED.\n"
-                      "Disabling nonbonded calculations.\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText(
+                "Found environment variable GMX_NO_NONBONDED.\n"
+                "Disabling nonbonded calculations.");
     }
 
     bGenericKernelOnly = FALSE;
@@ -2557,12 +2557,12 @@ void init_forcerec(FILE              *fp,
                     fr->bMolPBC = FALSE;
                     if (fp)
                     {
-                        md_print_warn(cr, fp, "GMX_USE_GRAPH is set, using the graph for bonded interactions\n");
+                        GMX_LOG(mdlog.warning).asParagraph().appendText("GMX_USE_GRAPH is set, using the graph for bonded interactions");
                     }
 
                     if (mtop->bIntermolecularInteractions)
                     {
-                        md_print_warn(cr, fp, "WARNING: Molecules linked by intermolecular interactions have to reside in the same periodic image, otherwise artifacts will occur!\n");
+                        GMX_LOG(mdlog.warning).asParagraph().appendText("WARNING: Molecules linked by intermolecular interactions have to reside in the same periodic image, otherwise artifacts will occur!");
                     }
                 }
 
@@ -3204,7 +3204,7 @@ void init_forcerec(FILE              *fp,
             GMX_RELEASE_ASSERT(ir->rcoulomb == ir->rvdw, "With Verlet lists and no PME rcoulomb and rvdw should be identical");
         }
 
-        init_nb_verlet(fp, &fr->nbv, bFEP_NonBonded, ir, fr, cr, nbpu_opt);
+        init_nb_verlet(fp, mdlog, &fr->nbv, bFEP_NonBonded, ir, fr, cr, nbpu_opt);
     }
 
     if (ir->eDispCorr != edispcNO)
index 274d909bf82446a41c62461e03acac7e2639f165..f1aba0e1c3e3035ec36b5886e3d6bac3e775c93b 100644 (file)
@@ -48,6 +48,11 @@ struct t_commrec;
 struct t_fcdata;
 struct t_filenm;
 
+namespace gmx
+{
+class MDLogger;
+}
+
 /*! \brief Create a new forcerec structure */
 t_forcerec *mk_forcerec(void);
 
@@ -91,6 +96,7 @@ void init_interaction_const_tables(FILE                   *fp,
  *
  * The Force rec struct must be created with mk_forcerec.
  * \param[in]  fplog       File for printing
+ * \param[in]  mdlog       File for printing
  * \param[out] fr          The forcerec
  * \param[in]  fcd         Force constant data
  * \param[in]  ir          Inputrec structure
@@ -105,6 +111,7 @@ void init_interaction_const_tables(FILE                   *fp,
  * \param[in]  print_force Print forces for atoms with force >= print_force
  */
 void init_forcerec(FILE                   *fplog,
+                   const gmx::MDLogger    &mdlog,
                    t_forcerec             *fr,
                    t_fcdata               *fcd,
                    const t_inputrec       *ir,
index 479ca6592817f2fd06b65680c8148f141563adbd..644bb05a8b0e1deab070cc41afc4917a02b1dc0f 100644 (file)
 #include <cstdlib>
 #include <cstring>
 
-#include "gromacs/gmxlib/md_logging.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/gmxomp.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/programcontext.h"
 
 /** Structure with the number of threads for each OpenMP multi-threaded
@@ -107,14 +107,12 @@ static omp_module_nthreads_t modth = { 0, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0}, FALSE}
  *  The "group" scheme supports OpenMP only in PME and in thise case all but
  *  the PME nthread values default to 1.
  */
-static void pick_module_nthreads(FILE *fplog, int m,
-                                 gmx_bool bSimMaster,
+static void pick_module_nthreads(const gmx::MDLogger &mdlog, int m,
                                  gmx_bool bFullOmpSupport,
                                  gmx_bool bSepPME)
 {
     char      *env;
     int        nth;
-    char       sbuf[STRLEN];
 
     const bool bOMP = GMX_OPENMP;
 
@@ -161,16 +159,9 @@ static void pick_module_nthreads(FILE *fplog, int m,
         /* only babble if we are really overriding with a different value */
         if ((bSepPME && m == emntPME && nth != modth.gnth_pme) || (nth != modth.gnth))
         {
-            sprintf(sbuf, "%s=%d set, overriding the default number of %s threads",
+            GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                    "%s=%d set, overriding the default number of %s threads",
                     modth_env_var[m], nth, mod_name[m]);
-            if (bSimMaster)
-            {
-                fprintf(stderr, "\n%s\n", sbuf);
-            }
-            if (fplog)
-            {
-                fprintf(fplog, "%s\n", sbuf);
-            }
         }
     }
     else
@@ -235,16 +226,16 @@ void gmx_omp_nthreads_read_env(int     *nthreads_omp,
 /*! \brief Helper function for parsing various input about the number
     of OpenMP threads to use in various modules and deciding what to
     do about it. */
-static void manage_number_of_openmp_threads(FILE               *fplog,
-                                            const t_commrec    *cr,
-                                            bool                bOMP,
-                                            int                 nthreads_hw_avail,
-                                            int                 omp_nthreads_req,
-                                            int                 omp_nthreads_pme_req,
-                                            gmx_bool gmx_unused bThisNodePMEOnly,
-                                            gmx_bool            bFullOmpSupport,
-                                            int                 nppn,
-                                            gmx_bool            bSepPME)
+static void manage_number_of_openmp_threads(const gmx::MDLogger &mdlog,
+                                            const t_commrec     *cr,
+                                            bool                 bOMP,
+                                            int                  nthreads_hw_avail,
+                                            int                  omp_nthreads_req,
+                                            int                  omp_nthreads_pme_req,
+                                            gmx_bool gmx_unused  bThisNodePMEOnly,
+                                            gmx_bool             bFullOmpSupport,
+                                            int                  nppn,
+                                            gmx_bool             bSepPME)
 {
     int      nth;
     char    *env;
@@ -258,6 +249,8 @@ static void manage_number_of_openmp_threads(FILE               *fplog,
     {
         return;
     }
+#else
+    GMX_UNUSED_VALUE(cr);
 #endif
 
     if (modth.initialized)
@@ -352,15 +345,15 @@ static void manage_number_of_openmp_threads(FILE               *fplog,
 
     /* now set the per-module values */
     modth.nth[emntDefault] = modth.gnth;
-    pick_module_nthreads(fplog, emntDomdec, SIMMASTER(cr), bFullOmpSupport, bSepPME);
-    pick_module_nthreads(fplog, emntPairsearch, SIMMASTER(cr), bFullOmpSupport, bSepPME);
-    pick_module_nthreads(fplog, emntNonbonded, SIMMASTER(cr), bFullOmpSupport, bSepPME);
-    pick_module_nthreads(fplog, emntBonded, SIMMASTER(cr), bFullOmpSupport, bSepPME);
-    pick_module_nthreads(fplog, emntPME, SIMMASTER(cr), bFullOmpSupport, bSepPME);
-    pick_module_nthreads(fplog, emntUpdate, SIMMASTER(cr), bFullOmpSupport, bSepPME);
-    pick_module_nthreads(fplog, emntVSITE, SIMMASTER(cr), bFullOmpSupport, bSepPME);
-    pick_module_nthreads(fplog, emntLINCS, SIMMASTER(cr), bFullOmpSupport, bSepPME);
-    pick_module_nthreads(fplog, emntSETTLE, SIMMASTER(cr), bFullOmpSupport, bSepPME);
+    pick_module_nthreads(mdlog, emntDomdec, bFullOmpSupport, bSepPME);
+    pick_module_nthreads(mdlog, emntPairsearch, bFullOmpSupport, bSepPME);
+    pick_module_nthreads(mdlog, emntNonbonded, bFullOmpSupport, bSepPME);
+    pick_module_nthreads(mdlog, emntBonded, bFullOmpSupport, bSepPME);
+    pick_module_nthreads(mdlog, emntPME, bFullOmpSupport, bSepPME);
+    pick_module_nthreads(mdlog, emntUpdate, bFullOmpSupport, bSepPME);
+    pick_module_nthreads(mdlog, emntVSITE, bFullOmpSupport, bSepPME);
+    pick_module_nthreads(mdlog, emntLINCS, bFullOmpSupport, bSepPME);
+    pick_module_nthreads(mdlog, emntSETTLE, bFullOmpSupport, bSepPME);
 
     /* set the number of threads globally */
     if (bOMP)
@@ -389,11 +382,11 @@ static void manage_number_of_openmp_threads(FILE               *fplog,
 
 /*! \brief Report on the OpenMP settings that will be used */
 static void
-reportOpenmpSettings(FILE            *fplog,
-                     const t_commrec *cr,
-                     gmx_bool         bOMP,
-                     gmx_bool         bFullOmpSupport,
-                     gmx_bool         bSepPME)
+reportOpenmpSettings(const gmx::MDLogger &mdlog,
+                     const t_commrec     *cr,
+                     gmx_bool             bOMP,
+                     gmx_bool             bFullOmpSupport,
+                     gmx_bool             bSepPME)
 {
 #if GMX_THREAD_MPI
     const char *mpi_str = "per tMPI thread";
@@ -440,31 +433,35 @@ reportOpenmpSettings(FILE            *fplog,
     {
         if (nth_max == nth_min)
         {
-            md_print_info(cr, fplog, "Using %d OpenMP thread%s %s\n",
-                          nth_min, nth_min > 1 ? "s" : "",
-                          cr->nnodes > 1 ? mpi_str : "");
+            GMX_LOG(mdlog.warning).appendTextFormatted(
+                    "Using %d OpenMP thread%s %s",
+                    nth_min, nth_min > 1 ? "s" : "",
+                    cr->nnodes > 1 ? mpi_str : "");
         }
         else
         {
-            md_print_info(cr, fplog, "Using %d - %d OpenMP threads %s\n",
-                          nth_min, nth_max, mpi_str);
+            GMX_LOG(mdlog.warning).appendTextFormatted(
+                    "Using %d - %d OpenMP threads %s",
+                    nth_min, nth_max, mpi_str);
         }
     }
     if (bSepPME && (nth_pme_min != nth_min || nth_pme_max != nth_max))
     {
         if (nth_pme_max == nth_pme_min)
         {
-            md_print_info(cr, fplog, "Using %d OpenMP thread%s %s for PME\n",
-                          nth_pme_min, nth_pme_min > 1 ? "s" : "",
-                          cr->nnodes > 1 ? mpi_str : "");
+            GMX_LOG(mdlog.warning).appendTextFormatted(
+                    "Using %d OpenMP thread%s %s for PME",
+                    nth_pme_min, nth_pme_min > 1 ? "s" : "",
+                    cr->nnodes > 1 ? mpi_str : "");
         }
         else
         {
-            md_print_info(cr, fplog, "Using %d - %d OpenMP threads %s for PME\n",
-                          nth_pme_min, nth_pme_max, mpi_str);
+            GMX_LOG(mdlog.warning).appendTextFormatted(
+                    "Using %d - %d OpenMP threads %s for PME",
+                    nth_pme_min, nth_pme_max, mpi_str);
         }
     }
-    md_print_info(cr, fplog, "\n");
+    GMX_LOG(mdlog.warning);
 }
 
 /*! \brief Detect and warn about oversubscription of cores.
@@ -474,11 +471,11 @@ reportOpenmpSettings(FILE            *fplog,
  *
  * \todo Enable this for separate PME nodes as well! */
 static void
-issueOversubscriptionWarning(FILE            *fplog,
-                             const t_commrec *cr,
-                             int              nthreads_hw_avail,
-                             int              nppn,
-                             gmx_bool         bSepPME)
+issueOversubscriptionWarning(const gmx::MDLogger &mdlog,
+                             const t_commrec     *cr,
+                             int                  nthreads_hw_avail,
+                             int                  nppn,
+                             gmx_bool             bSepPME)
 {
     char sbuf[STRLEN], sbuf1[STRLEN], sbuf2[STRLEN];
 
@@ -504,14 +501,14 @@ issueOversubscriptionWarning(FILE            *fplog,
 #endif
         }
 #endif
-        md_print_warn(cr, fplog,
-                      "WARNING: %sversubscribing the available %d logical CPU cores%s with %d %s.\n"
-                      "         This will cause considerable performance loss!",
-                      sbuf2, nthreads_hw_avail, sbuf1, nppn*modth.gnth, sbuf);
+        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                "WARNING: %sversubscribing the available %d logical CPU cores%s with %d %s.\n"
+                "         This will cause considerable performance loss!",
+                sbuf2, nthreads_hw_avail, sbuf1, nppn*modth.gnth, sbuf);
     }
 }
 
-void gmx_omp_nthreads_init(FILE *fplog, t_commrec *cr,
+void gmx_omp_nthreads_init(const gmx::MDLogger &mdlog, t_commrec *cr,
                            int nthreads_hw_avail,
                            int omp_nthreads_req,
                            int omp_nthreads_pme_req,
@@ -529,7 +526,7 @@ void gmx_omp_nthreads_init(FILE *fplog, t_commrec *cr,
     bSepPME = ( (cr->duty & DUTY_PP) && !(cr->duty & DUTY_PME)) ||
         (!(cr->duty & DUTY_PP) &&  (cr->duty & DUTY_PME));
 
-    manage_number_of_openmp_threads(fplog, cr, bOMP,
+    manage_number_of_openmp_threads(mdlog, cr, bOMP,
                                     nthreads_hw_avail,
                                     omp_nthreads_req, omp_nthreads_pme_req,
                                     bThisNodePMEOnly, bFullOmpSupport,
@@ -544,8 +541,8 @@ void gmx_omp_nthreads_init(FILE *fplog, t_commrec *cr,
     }
 #endif
 
-    reportOpenmpSettings(fplog, cr, bOMP, bFullOmpSupport, bSepPME);
-    issueOversubscriptionWarning(fplog, cr, nthreads_hw_avail, nppn, bSepPME);
+    reportOpenmpSettings(mdlog, cr, bOMP, bFullOmpSupport, bSepPME);
+    issueOversubscriptionWarning(mdlog, cr, nthreads_hw_avail, nppn, bSepPME);
 }
 
 int gmx_omp_nthreads_get(int mod)
index 92ac2ceb54485b3613485c9c0fbccad5d9f124a7..dfa8f7944e9547aa05c0aae0f088d3ae34c22a48 100644 (file)
 
 struct t_commrec;
 
+namespace gmx
+{
+class MDLogger;
+}
+
 /** Enum values corresponding to multithreaded algorithmic modules. */
 typedef enum module_nth
 {
@@ -58,7 +63,7 @@ typedef enum module_nth
  * It is compatible with tMPI, thread-safety is ensured (for the features
  * available with tMPI).
  * This function should caled only once during the initialization of mdrun. */
-void gmx_omp_nthreads_init(FILE *fplog, t_commrec *cr,
+void gmx_omp_nthreads_init(const gmx::MDLogger &fplog, t_commrec *cr,
                            int nthreads_hw_avail,
                            int omp_nthreads_req,
                            int omp_nthreads_pme_req,
index aea0ec37ab5f7d9ea6f7fc0c970547fd6a113aaa..82157638e12d13b27dbb9d2515e9eb8e739dcb59 100644 (file)
@@ -63,10 +63,14 @@ struct t_inputrec;
 
 namespace gmx
 {
+
+class MDLogger;
+
 /*! \brief Integrator algorithm implementation.
  *
  * \param[in] fplog               Log file for output
  * \param[in] cr                  Communication record
+ * \param[in] mdlog               Log writer for important output
  * \param[in] nfile               Number of files
  * \param[in] fnm                 Filename structure array
  * \param[in] oenv                Output information
@@ -94,7 +98,7 @@ namespace gmx
  * \param[in] Flags               Flags to control mdrun
  * \param[in] walltime_accounting More timing information
  */
-typedef double integrator_t (FILE *fplog, t_commrec *cr,
+typedef double 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,
index 4ad4c7732b722e5dd0a4f687aaec1b603a9ca050..412aa9e7787d8c87889c2efd5b8093b607b34cb3 100644 (file)
@@ -44,7 +44,6 @@
 #include <algorithm>
 
 #include "gromacs/domdec/domdec.h"
-#include "gromacs/gmxlib/md_logging.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/gmxlib/nrnb.h"
 #include "gromacs/math/vec.h"
@@ -69,6 +68,7 @@
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/snprintf.h"
 
@@ -400,16 +400,18 @@ void compute_globals(FILE *fplog, gmx_global_stat *gstat, t_commrec *cr, t_input
     }
 }
 
-void check_nst_param(FILE *fplog, t_commrec *cr,
-                     const char *desc_nst, int nst,
-                     const char *desc_p, int *p)
+/* check whether an 'nst'-style parameter p is a multiple of nst, and
+   set it to be one if not, with a warning. */
+static void check_nst_param(const gmx::MDLogger &mdlog,
+                            const char *desc_nst, int nst,
+                            const char *desc_p, int *p)
 {
     if (*p > 0 && *p % nst != 0)
     {
         /* Round up to the next multiple of nst */
         *p = ((*p)/nst + 1)*nst;
-        md_print_warn(cr, fplog,
-                      "NOTE: %s changes %s to %d\n", desc_nst, desc_p, *p);
+        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                "NOTE: %s changes %s to %d", desc_nst, desc_p, *p);
     }
 }
 
@@ -537,8 +539,7 @@ static int lcd4(int i1, int i2, int i3, int i4)
     return nst;
 }
 
-int check_nstglobalcomm(FILE *fplog, t_commrec *cr,
-                        int nstglobalcomm, t_inputrec *ir)
+int check_nstglobalcomm(const gmx::MDLogger &mdlog, int nstglobalcomm, t_inputrec *ir)
 {
     if (!EI_DYNAMICS(ir->eI))
     {
@@ -586,42 +587,43 @@ int check_nstglobalcomm(FILE *fplog, t_commrec *cr,
             nstglobalcomm > ir->nstlist && nstglobalcomm % ir->nstlist != 0)
         {
             nstglobalcomm = (nstglobalcomm / ir->nstlist)*ir->nstlist;
-            md_print_warn(cr, fplog, "WARNING: nstglobalcomm is larger than nstlist, but not a multiple, setting it to %d\n", nstglobalcomm);
+            GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                    "WARNING: nstglobalcomm is larger than nstlist, but not a multiple, setting it to %d",
+                    nstglobalcomm);
         }
         if (ir->nstcalcenergy > 0)
         {
-            check_nst_param(fplog, cr, "-gcom", nstglobalcomm,
+            check_nst_param(mdlog, "-gcom", nstglobalcomm,
                             "nstcalcenergy", &ir->nstcalcenergy);
         }
         if (ir->etc != etcNO && ir->nsttcouple > 0)
         {
-            check_nst_param(fplog, cr, "-gcom", nstglobalcomm,
+            check_nst_param(mdlog, "-gcom", nstglobalcomm,
                             "nsttcouple", &ir->nsttcouple);
         }
         if (ir->epc != epcNO && ir->nstpcouple > 0)
         {
-            check_nst_param(fplog, cr, "-gcom", nstglobalcomm,
+            check_nst_param(mdlog, "-gcom", nstglobalcomm,
                             "nstpcouple", &ir->nstpcouple);
         }
 
-        check_nst_param(fplog, cr, "-gcom", nstglobalcomm,
+        check_nst_param(mdlog, "-gcom", nstglobalcomm,
                         "nstenergy", &ir->nstenergy);
 
-        check_nst_param(fplog, cr, "-gcom", nstglobalcomm,
+        check_nst_param(mdlog, "-gcom", nstglobalcomm,
                         "nstlog", &ir->nstlog);
     }
 
     if (ir->comm_mode != ecmNO && ir->nstcomm < nstglobalcomm)
     {
-        md_print_warn(cr, fplog, "WARNING: Changing nstcomm from %d to %d\n",
-                      ir->nstcomm, nstglobalcomm);
+        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                "WARNING: Changing nstcomm from %d to %d",
+                ir->nstcomm, nstglobalcomm);
         ir->nstcomm = nstglobalcomm;
     }
 
-    if (fplog)
-    {
-        fprintf(fplog, "Intra-simulation communication will occur every %d steps.\n", nstglobalcomm);
-    }
+    GMX_LOG(mdlog.info).appendTextFormatted(
+            "Intra-simulation communication will occur every %d steps.\n", nstglobalcomm);
     return nstglobalcomm;
 }
 
@@ -731,6 +733,17 @@ void set_state_entries(t_state *state, const t_inputrec *ir)
     init_ekinstate(&state->ekinstate, ir);
     snew(state->enerhist, 1);
     init_energyhistory(state->enerhist);
-    init_df_history(&state->dfhist, ir->fepvals->n_lambda);
-    state->swapstate.eSwapCoords = ir->eSwapCoords;
+    if (ir->bExpanded)
+    {
+        snew(state->dfhist, 1);
+        init_df_history(state->dfhist, ir->fepvals->n_lambda);
+    }
+    if (ir->eSwapCoords != eswapNO)
+    {
+        if (state->swapstate == NULL)
+        {
+            snew(state->swapstate, 1);
+        }
+        state->swapstate->eSwapCoords = ir->eSwapCoords;
+    }
 }
index ce594fc874068fdfc21f2aded79ad6a49aae78b9..409faf06949d0518cb455806284aecd0692547f6 100644 (file)
@@ -56,9 +56,8 @@ struct t_trxframe;
 
 namespace gmx
 {
-
+class MDLogger;
 class SimulationSignaller;
-
 }
 
 /* Define a number of flags to better control the information
@@ -92,16 +91,9 @@ class SimulationSignaller;
 /*! \brief Return the number of steps that will take place between
  * intra-simulation communications, given the constraints of the
  * inputrec and the value of mdrun -gcom. */
-int check_nstglobalcomm(FILE       *fplog,
-                        t_commrec  *cr,
-                        int         nstglobalcomm,
-                        t_inputrec *ir);
-
-/* check whether an 'nst'-style parameter p is a multiple of nst, and
-   set it to be one if not, with a warning. */
-void check_nst_param(FILE *fplog, t_commrec *cr,
-                     const char *desc_nst, int nst,
-                     const char *desc_p, int *p);
+int check_nstglobalcomm(const gmx::MDLogger &mdlog,
+                        int                  nstglobalcomm,
+                        t_inputrec          *ir);
 
 /*! \brief Return true if the \p value is equal across the set of multi-simulations
  *
index 63ff5e8b495b08bf6ed2715c681312d3aeaa1214..a035bc79ff89797cc3ac6444876a7cded6917eb5 100644 (file)
@@ -129,17 +129,14 @@ void atoms2md(const gmx_mtop_t *mtop, const t_inputrec *ir,
 
     groups = &mtop->groups;
 
-    /* Index==NULL indicates no DD (unless we have a DD node with no
-     * atoms), so also check for homenr. This should be
-     * signaled properly with an extra parameter or nindex==-1.
-     */
-    if (index == NULL && (homenr > 0))
+    /* nindex>=0 indicates DD where we use an index */
+    if (nindex >= 0)
     {
-        md->nr = mtop->natoms;
+        md->nr = nindex;
     }
     else
     {
-        md->nr = nindex;
+        md->nr = mtop->natoms;
     }
 
     if (md->nr > md->nalloc)
diff --git a/src/gromacs/mdlib/mdsetup.cpp b/src/gromacs/mdlib/mdsetup.cpp
new file mode 100644 (file)
index 0000000..3636544
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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 "gmxpre.h"
+
+#include "mdsetup.h"
+
+#include "gromacs/domdec/domdec.h"
+#include "gromacs/domdec/domdec_struct.h"
+#include "gromacs/listed-forces/manage-threading.h"
+#include "gromacs/mdlib/mdatoms.h"
+#include "gromacs/mdlib/shellfc.h"
+#include "gromacs/mdlib/vsite.h"
+#include "gromacs/mdtypes/commrec.h"
+#include "gromacs/mdtypes/forcerec.h"
+#include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/pbcutil/mshift.h"
+#include "gromacs/pbcutil/pbc.h"
+#include "gromacs/topology/mtop_util.h"
+#include "gromacs/topology/topology.h"
+#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/smalloc.h"
+
+/* TODO: Add a routine that collects the initial setup of the algorithms.
+ *
+ * The final solution should be an MD algorithm base class with methods
+ * for initialization and atom-data setup.
+ */
+
+void mdAlgorithmsSetupAtomData(t_commrec         *cr,
+                               const t_inputrec  *ir,
+                               const gmx_mtop_t  *top_global,
+                               gmx_localtop_t    *top,
+                               t_forcerec        *fr,
+                               t_graph          **graph,
+                               t_mdatoms         *mdatoms,
+                               gmx_vsite_t       *vsite,
+                               gmx_shellfc_t     *shellfc)
+{
+    bool  usingDomDec = DOMAINDECOMP(cr);
+
+    int   numAtomIndex, numHomeAtoms;
+    int  *atomIndex;
+
+    if (usingDomDec)
+    {
+        numAtomIndex = dd_natoms_mdatoms(cr->dd);
+        atomIndex    = cr->dd->gatindex;
+        numHomeAtoms = cr->dd->nat_home;
+    }
+    else
+    {
+        numAtomIndex = -1;
+        atomIndex    = NULL;
+        numHomeAtoms = top_global->natoms;
+    }
+    atoms2md(top_global, ir, numAtomIndex, atomIndex, numHomeAtoms, mdatoms);
+
+    if (usingDomDec)
+    {
+        dd_sort_local_top(cr->dd, mdatoms, top);
+    }
+    else
+    {
+        /* Currently gmx_generate_local_top allocates and returns a pointer.
+         * We should implement a more elegant solution.
+         */
+        gmx_localtop_t *tmpTop;
+
+        tmpTop = gmx_mtop_generate_local_top(top_global, ir->efep != efepNO);
+        *top   = *tmpTop;
+        sfree(tmpTop);
+    }
+
+    if (vsite)
+    {
+        if (usingDomDec)
+        {
+            /* The vsites were already assigned by the domdec topology code.
+             * We only need to do the thread division here.
+             */
+            split_vsites_over_threads(top->idef.il, top->idef.iparams,
+                                      mdatoms, FALSE, vsite);
+        }
+        else
+        {
+            set_vsite_top(vsite, top, mdatoms, cr);
+        }
+    }
+
+    if (!usingDomDec && ir->ePBC != epbcNONE && !fr->bMolPBC)
+    {
+        GMX_ASSERT(graph != NULL, "We use a graph with PBC (no periodic mols) and without DD");
+
+        *graph = mk_graph(NULL, &(top->idef), 0, top_global->natoms, FALSE, FALSE);
+    }
+    else if (graph != NULL)
+    {
+        *graph = NULL;
+    }
+
+    /* Note that with DD only flexible constraints, not shells, are supported
+     * and these don't require setup in make_local_shells().
+     */
+    if (!usingDomDec && shellfc)
+    {
+        make_local_shells(cr, mdatoms, shellfc);
+    }
+
+    setup_bonded_threading(fr, &top->idef);
+}
diff --git a/src/gromacs/mdlib/mdsetup.h b/src/gromacs/mdlib/mdsetup.h
new file mode 100644 (file)
index 0000000..c261643
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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.
+ */
+#ifndef GMX_MDLIB_MDSETUP_H
+#define GMX_MDLIB_MDSETUP_H
+
+#include "gromacs/mdlib/mdatoms.h"
+#include "gromacs/mdlib/shellfc.h"
+#include "gromacs/mdlib/vsite.h"
+#include "gromacs/mdtypes/commrec.h"
+#include "gromacs/mdtypes/forcerec.h"
+#include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/pbcutil/mshift.h"
+#include "gromacs/topology/topology.h"
+
+/*! \brief Sets atom data for several MD algorithms
+ *
+ * Most MD algorithms require two different setup calls:
+ * one for initialization and parameter setting and one for atom data setup.
+ * This routine sets the atom data for the (locally available) atoms.
+ * This is called at the start of serial runs and during domain decomposition.
+ *
+ * \param[in]     cr         Communication record
+ * \param[in]     ir         Input parameter record
+ * \param[in]     top_global The global topology
+ * \param[in,out] top        The local topology
+ * \param[in,out] fr         The force calculation parameter/data record
+ * \param[out]    graph      The molecular graph, can be NULL
+ * \param[out]    mdatoms    The MD atom data
+ * \param[in,out] vsite      The virtual site data, can be NULL
+ * \param[in,out] shellfc    The shell/flexible-constraint data, can be NULL
+ */
+void mdAlgorithmsSetupAtomData(t_commrec         *cr,
+                               const t_inputrec  *ir,
+                               const gmx_mtop_t  *top_global,
+                               gmx_localtop_t    *top,
+                               t_forcerec        *fr,
+                               t_graph          **graph,
+                               t_mdatoms         *mdatoms,
+                               gmx_vsite_t       *vsite,
+                               gmx_shellfc_t     *shellfc);
+
+#endif
index 2d5290d4b9502a9d1f900089717a5b1578c490ed..0246bfba100ca6fe6aaf7d2f274234bbd336b6b4 100644 (file)
@@ -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"
@@ -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
@@ -338,7 +340,7 @@ void init_em(FILE *fplog, const char *title,
              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,
@@ -363,6 +365,29 @@ void init_em(FILE *fplog, const char *title,
     init_IMD(ir, cr, top_global, fplog, 1, state_global->x,
              nfile, fnm, NULL, 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 != NULL)
+        {
+            *shellfc = NULL;
+        }
+    }
+
     if (DOMAINDECOMP(cr))
     {
         *top = dd_init_local_top(top_global);
@@ -399,20 +424,12 @@ void init_em(FILE *fplog, const char *title,
         }
         copy_mat(state_global->box, ems->s.box);
 
-        *top      = gmx_mtop_generate_local_top(top_global, ir->efep != efepNO);
 
-        setup_bonded_threading(fr, &(*top)->idef);
+        snew(*top, 1);
+        mdAlgorithmsSetupAtomData(cr, ir, top_global, *top, fr,
+                                  graph, mdatoms,
+                                  vsite, shellfc ? *shellfc : NULL);
 
-        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);
         update_mdatoms(mdatoms, state_global->lambda[efptFEP]);
 
         if (vsite)
@@ -995,7 +1012,7 @@ namespace gmx
 {
 
 /*! \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,
@@ -1015,7 +1032,7 @@ namespace gmx
                            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,
@@ -1069,7 +1086,8 @@ double do_cg(FILE *fplog, t_commrec *cr,
     /* 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,
+            nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat,
+            vsite, constr, NULL,
             nfile, fnm, &outf, &mdebin, imdport, Flags, wcycle);
 
     /* Print to log file */
@@ -1643,26 +1661,26 @@ double do_cg(FILE *fplog, t_commrec *cr,
 
 
 /*! \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,
@@ -1758,7 +1776,8 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
     /* 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,
+            nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat,
+            vsite, constr, NULL,
             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.
@@ -2471,26 +2490,26 @@ double do_lbfgs(FILE *fplog, t_commrec *cr,
 }   /* 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,
@@ -2534,7 +2553,8 @@ double do_steep(FILE *fplog, t_commrec *cr,
     /* 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,
+            nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat,
+            vsite, constr, NULL,
             nfile, fnm, &outf, &mdebin, imdport, Flags, wcycle);
 
     /* Print to log file  */
@@ -2739,26 +2759,26 @@ double do_steep(FILE *fplog, t_commrec *cr,
 }   /* 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,
@@ -2808,23 +2828,16 @@ double do_nm(FILE *fplog, t_commrec *cr,
 
     state_work = init_em_state();
 
+    gmx_shellfc_t *shellfc;
+
     /* 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,
+            nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat,
+            vsite, constr, &shellfc,
             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));
-
-    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());
@@ -2848,17 +2861,18 @@ double do_nm(FILE *fplog, t_commrec *cr,
      */
     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;
     }
 
@@ -2907,14 +2921,14 @@ double do_nm(FILE *fplog, t_commrec *cr,
     /* if forces are not small, warn user */
     get_state_f_norm_max(cr, &(inputrec->opts), mdatoms, state_work);
 
-    md_print_info(cr, fplog, "Maximum force:%12.5e\n", state_work->fmax);
+    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.");
     }
 
     /***********************************************************
index bd49f6aba2bb6111d127d60e9f2ac0bda2d54b43..ace59739463cf3fc2642429d7b736058e53d31b7 100644 (file)
@@ -435,8 +435,8 @@ void nbnxn_gpu_launch_kernel(gmx_nbnxn_cuda_t       *nb,
 
     if (debug)
     {
-        fprintf(debug, "GPU launch configuration:\n\tThread block: %dx%dx%d\n\t"
-                "\tGrid: %dx%d\n\t#Super-clusters/clusters: %d/%d (%d)\n"
+        fprintf(debug, "GPU launch configuration:\n\tThread block: %ux%ux%u\n\t"
+                "\tGrid: %ux%u\n\t#Super-clusters/clusters: %d/%d (%d)\n"
                 "\tShMem: %d\n",
                 dim_block.x, dim_block.y, dim_block.z,
                 dim_grid.x, dim_grid.y, plist->nsci*c_numClPerSupercl,
index d48e1594dde71fe4b1cbcd0b38ea1e221278da18..7311afcaec0f8f46496c0f1e9b74bdc8c3318257 100644 (file)
@@ -895,8 +895,6 @@ void do_force_cutsVERLET(FILE *fplog, t_commrec *cr,
          * we do not need to worry about shifting.
          */
 
-        int pme_flags = 0;
-
         wallcycle_start(wcycle, ewcPP_PMESENDX);
 
         bBS = (inputrec->nwall == 2);
@@ -906,20 +904,10 @@ void do_force_cutsVERLET(FILE *fplog, t_commrec *cr,
             svmul(inputrec->wall_ewald_zfac, boxs[ZZ], boxs[ZZ]);
         }
 
-        if (EEL_PME(fr->eeltype))
-        {
-            pme_flags |= GMX_PME_DO_COULOMB;
-        }
-
-        if (EVDW_PME(fr->vdwtype))
-        {
-            pme_flags |= GMX_PME_DO_LJ;
-        }
-
         gmx_pme_send_coordinates(cr, bBS ? boxs : box, x,
-                                 mdatoms->nChargePerturbed, mdatoms->nTypePerturbed, lambda[efptCOUL], lambda[efptVDW],
+                                 lambda[efptCOUL], lambda[efptVDW],
                                  (flags & (GMX_FORCE_VIRIAL | GMX_FORCE_ENERGY)),
-                                 pme_flags, step);
+                                 step);
 
         wallcycle_stop(wcycle, ewcPP_PMESENDX);
     }
@@ -1658,8 +1646,6 @@ void do_force_cutsGROUP(FILE *fplog, t_commrec *cr,
          * we do not need to worry about shifting.
          */
 
-        int pme_flags = 0;
-
         wallcycle_start(wcycle, ewcPP_PMESENDX);
 
         bBS = (inputrec->nwall == 2);
@@ -1669,20 +1655,10 @@ void do_force_cutsGROUP(FILE *fplog, t_commrec *cr,
             svmul(inputrec->wall_ewald_zfac, boxs[ZZ], boxs[ZZ]);
         }
 
-        if (EEL_PME(fr->eeltype))
-        {
-            pme_flags |= GMX_PME_DO_COULOMB;
-        }
-
-        if (EVDW_PME(fr->vdwtype))
-        {
-            pme_flags |= GMX_PME_DO_LJ;
-        }
-
         gmx_pme_send_coordinates(cr, bBS ? boxs : box, x,
-                                 mdatoms->nChargePerturbed, mdatoms->nTypePerturbed, lambda[efptCOUL], lambda[efptVDW],
+                                 lambda[efptCOUL], lambda[efptVDW],
                                  (flags & (GMX_FORCE_VIRIAL | GMX_FORCE_ENERGY)),
-                                 pme_flags, step);
+                                 step);
 
         wallcycle_stop(wcycle, ewcPP_PMESENDX);
     }
@@ -2569,7 +2545,7 @@ void put_atoms_in_box_omp(int ePBC, const matrix box, int natoms, rvec x[])
 }
 
 // TODO This can be cleaned up a lot, and move back to runner.cpp
-void finish_run(FILE *fplog, t_commrec *cr,
+void finish_run(FILE *fplog, const gmx::MDLogger &mdlog, t_commrec *cr,
                 t_inputrec *inputrec,
                 t_nrnb nrnb[], gmx_wallcycle_t wcycle,
                 gmx_walltime_accounting_t walltime_accounting,
@@ -2646,7 +2622,7 @@ void finish_run(FILE *fplog, t_commrec *cr,
     {
         struct gmx_wallclock_gpu_t* gputimes = use_GPU(nbv) ? nbnxn_gpu_get_timings(nbv->gpu_nbv) : NULL;
 
-        wallcycle_print(fplog, cr->nnodes, cr->npmenodes, nthreads_pp, nthreads_pme,
+        wallcycle_print(fplog, mdlog, cr->nnodes, cr->npmenodes, nthreads_pp, nthreads_pme,
                         elapsed_time_over_all_ranks,
                         wcycle, cycle_sum, gputimes);
 
index 930bf2c692f16935a3266c472d8c4171d67283c2..dc91aaa27211e667ad4656acf9d73284084d3c74 100644 (file)
@@ -53,6 +53,11 @@ struct t_graph;
 struct t_mdatoms;
 struct t_nrnb;
 
+namespace gmx
+{
+class MDLogger;
+}
+
 typedef struct gmx_global_stat *gmx_global_stat_t;
 
 void do_pbc_first(FILE *log, matrix box, t_forcerec *fr,
@@ -117,7 +122,7 @@ void print_start(FILE *fplog, t_commrec *cr,
                  gmx_walltime_accounting_t walltime_accounting,
                  const char *name);
 
-void finish_run(FILE *log, t_commrec *cr,
+void finish_run(FILE *log, const gmx::MDLogger &mdlog, t_commrec *cr,
                 t_inputrec *inputrec,
                 t_nrnb nrnb[], gmx_wallcycle_t wcycle,
                 gmx_walltime_accounting_t walltime_accounting,
index abd5ee7bb9fd7b098f1541b91201f3cfbe0917d7..794908c98091e2bede8a6d6bd9e9d2b9610a9503 100644 (file)
@@ -78,9 +78,6 @@ class ArrayRef;
  * signals can be sent together with other data). This means that the
  * only meaningful values are positive, negative or zero.
  *
- * Note that xlc on BG/Q requires sig to be of size char (see unit tests
- * of ArrayRef for details).
- *
  * isLocal permits (for example) replica-exchange to require that any
  * checkpointing is synchronized across all simulations, by setting
  * isLocal to false, so that the trigger for action is set only when
index 4fcb49b7194de52b2e0e96d3fae510b653260ef9..84d54af65615e857c40f6ee558c82fb138e4f5ae 100644 (file)
@@ -261,6 +261,7 @@ TEST_P(SettleTest, SatisfiesConstraints)
             startingPositions.data(), updatedPositions_.data(), reciprocalTimeStep,
             useVelocities ? velocities_.data() : nullptr,
             calcVirial, virial, &errorOccured);
+    settle_free(settled);
     EXPECT_FALSE(errorOccured) << testDescription;
 
     // The necessary tolerances for the test to pass were determined
@@ -309,39 +310,15 @@ TEST_P(SettleTest, SatisfiesConstraints)
     }
 }
 
-using ::testing::Bool;
 // Scan the full Cartesian product of numbers of SETTLE interactions
 // (4 and 17 are chosen to test cases that do and do not match
 // hardware SIMD widths), and whether or not we use PBC, velocities or
-// calculate the virial contribution. It would be nicer to generate
-// these combinations with ::testing::Combine, but gcc 4.6 can't cope
-// with the template meta-programming required to generate the tuples.
+// calculate the virial contribution.
 INSTANTIATE_TEST_CASE_P(WithParameters, SettleTest,
-                            ::testing::Values(SettleTestParameters(1,  true,  true,  true),
-                                              SettleTestParameters(4,  true,  true,  true),
-                                              SettleTestParameters(17, true,  true,  true),
-                                              SettleTestParameters(1,  false, true,  true),
-                                              SettleTestParameters(4,  false, true,  true),
-                                              SettleTestParameters(17, false, true,  true),
-                                              SettleTestParameters(1,  true,  false, true),
-                                              SettleTestParameters(4,  true,  false, true),
-                                              SettleTestParameters(17, true,  false, true),
-                                              SettleTestParameters(1,  false, false, true),
-                                              SettleTestParameters(4,  false, false, true),
-                                              SettleTestParameters(17, false, false, true),
-                                              SettleTestParameters(1,  true,  true,  false),
-                                              SettleTestParameters(4,  true,  true,  false),
-                                              SettleTestParameters(17, true,  true,  false),
-                                              SettleTestParameters(1,  false, true,  false),
-                                              SettleTestParameters(4,  false, true,  false),
-                                              SettleTestParameters(17, false, true,  false),
-                                              SettleTestParameters(1,  true,  false, false),
-                                              SettleTestParameters(4,  true,  false, false),
-                                              SettleTestParameters(17, true,  false, false),
-                                              SettleTestParameters(1,  false, false, false),
-                                              SettleTestParameters(4,  false, false, false),
-                                              SettleTestParameters(17, false, false, false)));
-
+                            ::testing::Combine(::testing::Values(1, 4, 7),
+                                                   ::testing::Bool(),
+                                                   ::testing::Bool(),
+                                                   ::testing::Bool()));
 
 } // namespace
 } // namespace
index aa1210a59fdc9641dc89ea5424e16311e0162ebb..085ce7af7fee931f4ecf21e2fb5305aa7076aac0 100644 (file)
@@ -126,7 +126,7 @@ namespace gmx
 {
 
 /*! \brief Do test particle insertion.
-    \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,
@@ -145,7 +145,7 @@ namespace gmx
                            unsigned long Flags,
                            gmx_walltime_accounting_t walltime_accounting)
  */
-double do_tpi(FILE *fplog, t_commrec *cr,
+double do_tpi(FILE *fplog, t_commrec *cr, const gmx::MDLogger gmx_unused &mdlog,
               int nfile, const t_filenm fnm[],
               const gmx_output_env_t *oenv, gmx_bool bVerbose,
               int gmx_unused nstglobalcomm,
@@ -284,7 +284,7 @@ double do_tpi(FILE *fplog, t_commrec *cr,
         sscanf(dump_pdb, "%20lf", &dump_ener);
     }
 
-    atoms2md(top_global, inputrec, 0, NULL, top_global->natoms, mdatoms);
+    atoms2md(top_global, inputrec, -1, NULL, top_global->natoms, mdatoms);
     update_mdatoms(mdatoms, inputrec->fepvals->init_lambda);
 
     snew(enerd, 1);
index 8f00f22207fcbc5d620b9c3d4e8c7e8557c46f06..a6ecc782efceb9aa93f4673e2c915b23ef4e6629 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2015, by the GROMACS development team, led by
+# Copyright (c) 2015,2016, 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.
 
-file(GLOB MDRUNUTILITY_SOURCES *.cpp)
-set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${MDRUNUTILITY_SOURCES} PARENT_SCOPE)
+gmx_add_libgromacs_sources(
+    handlerestart.cpp
+    mdmodules.cpp
+    threadaffinity.cpp
+    )
 
 if (BUILD_TESTING)
-#    add_subdirectory(tests)
+    add_subdirectory(tests)
 endif()
diff --git a/src/gromacs/mdrunutility/mdmodules.cpp b/src/gromacs/mdrunutility/mdmodules.cpp
new file mode 100644 (file)
index 0000000..5792041
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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 "gmxpre.h"
+
+#include "mdmodules.h"
+
+#include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/utility/smalloc.h"
+
+namespace gmx
+{
+
+class MDModules::Impl
+{
+    public:
+        Impl() : ir_(nullptr)
+        {
+        }
+        ~Impl()
+        {
+            if (ir_ != nullptr)
+            {
+                done_inputrec(ir_);
+                sfree(ir_);
+            }
+        }
+
+        void ensureInputrecInitialized()
+        {
+            if (ir_ == nullptr)
+            {
+                snew(ir_, 1);
+                snew(ir_->fepvals, 1);
+                snew(ir_->expandedvals, 1);
+                snew(ir_->simtempvals, 1);
+            }
+        }
+
+        t_inputrec *ir_;
+};
+
+MDModules::MDModules() : impl_(new Impl)
+{
+}
+
+MDModules::~MDModules()
+{
+}
+
+t_inputrec *MDModules::inputrec()
+{
+    impl_->ensureInputrecInitialized();
+    return impl_->ir_;
+}
+
+} // namespace gmx
diff --git a/src/gromacs/mdrunutility/mdmodules.h b/src/gromacs/mdrunutility/mdmodules.h
new file mode 100644 (file)
index 0000000..a951136
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares gmx::MDModules.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_mdrunutility
+ */
+#ifndef GMX_MDRUNUTILITY_MDMODULES_H
+#define GMX_MDRUNUTILITY_MDMODULES_H
+
+#include "gromacs/utility/classhelpers.h"
+
+struct t_inputrec;
+
+namespace gmx
+{
+
+/*! \libinternal \brief
+ * Factory for t_inputrec.
+ *
+ * This class acts as a central place for constructing t_inputrec (and possibly
+ * other mdrun structures in the future) and wiring up dependencies between
+ * modules that are referenced from these structures.
+ *
+ * \inlibraryapi
+ * \ingroup module_mdrunutility
+ */
+class MDModules
+{
+    public:
+        MDModules();
+        ~MDModules();
+
+        /*! \brief
+         * Returns an initialized t_inputrec structure.
+         *
+         * The inputrec structure is owned by MDModules and will be destroyed
+         * with it.
+         */
+        t_inputrec *inputrec();
+
+    private:
+        class Impl;
+
+        PrivateImplPointer<Impl> impl_;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/mdrunutility/tests/CMakeLists.txt b/src/gromacs/mdrunutility/tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7ccbbd9
--- /dev/null
@@ -0,0 +1,40 @@
+#
+# This file is part of the GROMACS molecular simulation package.
+#
+# Copyright (c) 2016, 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.
+
+gmx_add_unit_test_object_library(mdrunutility-test-shared
+                                 threadaffinitytest.cpp)
+
+gmx_add_unit_test(MdrunUtilityUnitTests mdrunutility-test
+                  threadaffinity.cpp
+                  $<TARGET_OBJECTS:mdrunutility-test-shared>)
diff --git a/src/gromacs/mdrunutility/tests/threadaffinity.cpp b/src/gromacs/mdrunutility/tests/threadaffinity.cpp
new file mode 100644 (file)
index 0000000..6d11834
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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 "gmxpre.h"
+
+#include "gromacs/mdrunutility/threadaffinity.h"
+
+#include "config.h"
+
+#include <gtest/gtest.h>
+
+#include "threadaffinitytest.h"
+
+namespace
+{
+
+class ThreadAffinityTest : public ::testing::Test
+{
+    public:
+        gmx::test::ThreadAffinityTestHelper helper_;
+};
+
+TEST_F(ThreadAffinityTest, DoesNothingWhenDisabled)
+{
+    helper_.setAffinityOption(threadaffOFF);
+    helper_.setAffinity(1);
+}
+
+TEST_F(ThreadAffinityTest, DoesNothingWhenNotSupported)
+{
+    helper_.setAffinitySupported(false);
+    helper_.setAffinity(1);
+}
+
+TEST_F(ThreadAffinityTest, DoesNothingWithAutoAndTooFewThreads)
+{
+    helper_.setLogicalProcessorCount(4);
+    helper_.setAffinity(2);
+}
+
+TEST_F(ThreadAffinityTest, DoesNothingWithAutoAndTooManyThreads)
+{
+    helper_.setLogicalProcessorCount(4);
+    helper_.setAffinity(8);
+}
+
+TEST_F(ThreadAffinityTest, DoesNothingWithUnknownHardware)
+{
+    helper_.setAffinityOption(threadaffON);
+    helper_.setLogicalProcessorCount(0);
+    helper_.setAffinity(2);
+}
+
+TEST_F(ThreadAffinityTest, DoesNothingWithTooManyThreads)
+{
+    helper_.setAffinityOption(threadaffON);
+    helper_.setLogicalProcessorCount(4);
+    helper_.setAffinity(8);
+}
+
+TEST_F(ThreadAffinityTest, DoesNothingWithTooLargeOffset)
+{
+    helper_.setAffinityOption(threadaffON);
+    helper_.setOffsetAndStride(2, 0);
+    helper_.setLogicalProcessorCount(4);
+    helper_.setAffinity(3);
+}
+
+TEST_F(ThreadAffinityTest, DoesNothingWithTooLargeStride)
+{
+    helper_.setAffinityOption(threadaffON);
+    helper_.setOffsetAndStride(0, 2);
+    helper_.setLogicalProcessorCount(4);
+    helper_.setAffinity(3);
+}
+
+TEST_F(ThreadAffinityTest, PinsSingleThreadWithAuto)
+{
+    helper_.setLogicalProcessorCount(1);
+    helper_.expectAffinitySet(0);
+    helper_.setAffinity(1);
+}
+
+TEST_F(ThreadAffinityTest, PinsSingleThreadWhenForced)
+{
+    helper_.setAffinityOption(threadaffON);
+    helper_.setLogicalProcessorCount(2);
+    helper_.expectAffinitySet(0);
+    helper_.setAffinity(1);
+}
+
+TEST_F(ThreadAffinityTest, PinsSingleThreadWithOffsetWhenForced)
+{
+    helper_.setAffinityOption(threadaffON);
+    helper_.setOffsetAndStride(2, 0);
+    helper_.setLogicalProcessorCount(4);
+    helper_.expectAffinitySet(2);
+    helper_.setAffinity(1);
+}
+
+TEST_F(ThreadAffinityTest, HandlesPinningFailureWithSingleThread)
+{
+    helper_.setLogicalProcessorCount(1);
+    helper_.expectAffinitySetThatFails(0);
+    helper_.setAffinity(1);
+}
+
+// TODO: If it wouldn't result in a multitude of #if's, it would be nice
+// to somehow indicate in a no-OpenMP build that some tests are missing.
+#if GMX_OPENMP
+TEST_F(ThreadAffinityTest, PinsMultipleThreadsWithAuto)
+{
+    helper_.setLogicalProcessorCount(2);
+    helper_.expectAffinitySet({0, 1});
+    helper_.setAffinity(2);
+}
+
+TEST_F(ThreadAffinityTest, PinsMultipleThreadsWithStrideWhenForced)
+{
+    helper_.setAffinityOption(threadaffON);
+    helper_.setOffsetAndStride(0, 2);
+    helper_.setLogicalProcessorCount(4);
+    helper_.expectAffinitySet({0, 2});
+    helper_.setAffinity(2);
+}
+
+TEST_F(ThreadAffinityTest, HandlesPinningFailureWithOneThreadFailing)
+{
+    helper_.setAffinityOption(threadaffON);
+    helper_.setLogicalProcessorCount(2);
+    helper_.expectAffinitySet(0);
+    helper_.expectAffinitySetThatFails(1);
+    helper_.setAffinity(2);
+}
+#endif
+
+} // namespace
diff --git a/src/gromacs/mdrunutility/tests/threadaffinitytest.cpp b/src/gromacs/mdrunutility/tests/threadaffinitytest.cpp
new file mode 100644 (file)
index 0000000..33824ce
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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 "gmxpre.h"
+
+#include "threadaffinitytest.h"
+
+#include "config.h"
+
+#include <gmock/gmock.h>
+
+#include "gromacs/hardware/hardwaretopology.h"
+#include "gromacs/mdtypes/commrec.h"
+#include "gromacs/utility/basenetwork.h"
+#include "gromacs/utility/gmxmpi.h"
+#include "gromacs/utility/smalloc.h"
+
+namespace gmx
+{
+namespace test
+{
+
+MockThreadAffinityAccess::MockThreadAffinityAccess()
+    : supported_(true)
+{
+    using ::testing::_;
+    using ::testing::Return;
+    ON_CALL(*this, setCurrentThreadAffinityToCore(_))
+        .WillByDefault(Return(true));
+}
+
+MockThreadAffinityAccess::~MockThreadAffinityAccess()
+{
+}
+
+
+ThreadAffinityTestHelper::ThreadAffinityTestHelper()
+{
+    snew(cr_, 1);
+    cr_->nnodes         = gmx_node_num();
+    cr_->nodeid         = gmx_node_rank();
+    cr_->rank_intranode = cr_->nodeid;
+    cr_->duty           = DUTY_PP;
+#if GMX_MPI
+    cr_->mpi_comm_mysim = MPI_COMM_WORLD;
+#endif
+    snew(hwOpt_, 1);
+    hwOpt_->thread_affinity = threadaffAUTO;
+}
+
+ThreadAffinityTestHelper::~ThreadAffinityTestHelper()
+{
+    sfree(cr_);
+    sfree(hwOpt_);
+}
+
+void ThreadAffinityTestHelper::setLogicalProcessorCount(int logicalProcessorCount)
+{
+    hwTop_.reset(new HardwareTopology(logicalProcessorCount));
+}
+
+} // namespace test
+} // namespace gmx
diff --git a/src/gromacs/mdrunutility/tests/threadaffinitytest.h b/src/gromacs/mdrunutility/tests/threadaffinitytest.h
new file mode 100644 (file)
index 0000000..027e6cf
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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.
+ */
+#ifndef GMX_MDRUNUTILITY_TESTS_THREADAFFINITYTEST_H
+#define GMX_MDRUNUTILITY_TESTS_THREADAFFINITYTEST_H
+
+#include <initializer_list>
+#include <memory>
+
+#include <gmock/gmock.h>
+
+#include "gromacs/hardware/hw_info.h"
+#include "gromacs/mdrunutility/threadaffinity.h"
+#include "gromacs/utility/logger.h"
+
+struct t_commrec;
+
+namespace gmx
+{
+
+class HardwareTopology;
+
+namespace test
+{
+
+class MockThreadAffinityAccess : public IThreadAffinityAccess
+{
+    public:
+        MockThreadAffinityAccess();
+        ~MockThreadAffinityAccess();
+
+        void setSupported(bool supported) { supported_ = supported; }
+
+        virtual bool isThreadAffinitySupported() const { return supported_; }
+        MOCK_METHOD1(setCurrentThreadAffinityToCore, bool(int core));
+
+    private:
+        bool supported_;
+};
+
+class ThreadAffinityTestHelper
+{
+    public:
+        ThreadAffinityTestHelper();
+        ~ThreadAffinityTestHelper();
+
+        void setAffinitySupported(bool supported)
+        {
+            affinityAccess_.setSupported(supported);
+        }
+        void setAffinityOption(int affinityOption)
+        {
+            hwOpt_->thread_affinity = affinityOption;
+        }
+        void setOffsetAndStride(int offset, int stride)
+        {
+            hwOpt_->core_pinning_offset = offset;
+            hwOpt_->core_pinning_stride = stride;
+        }
+
+        void setLogicalProcessorCount(int logicalProcessorCount);
+
+        void expectAffinitySet(int core)
+        {
+            EXPECT_CALL(affinityAccess_, setCurrentThreadAffinityToCore(core));
+        }
+        void expectAffinitySet(std::initializer_list<int> cores)
+        {
+            for (int core : cores)
+            {
+                expectAffinitySet(core);
+            }
+        }
+        void expectAffinitySetThatFails(int core)
+        {
+            using ::testing::Return;
+            EXPECT_CALL(affinityAccess_, setCurrentThreadAffinityToCore(core))
+                .WillOnce(Return(false));
+        }
+
+        void setAffinity(int nthread_local)
+        {
+            if (hwTop_ == nullptr)
+            {
+                setLogicalProcessorCount(1);
+            }
+            MDLogger mdlog;
+            gmx_set_thread_affinity(nullptr, mdlog, cr_, hwOpt_, *hwTop_,
+                                    nthread_local, &affinityAccess_);
+        }
+
+    private:
+        t_commrec                         *cr_;
+        gmx_hw_opt_t                      *hwOpt_;
+        std::unique_ptr<HardwareTopology>  hwTop_;
+        MockThreadAffinityAccess           affinityAccess_;
+};
+
+} // namespace test
+} // namespace gmx
+
+#endif
index a9387e6b3543d32c95d5f063e03fdaeef404fc13..d30e078a74833d64e9e8a0a5b1ace8ab0f8857a1 100644 (file)
 
 #include "thread_mpi/threads.h"
 
-#include "gromacs/gmxlib/md_logging.h"
 #include "gromacs/hardware/hardwaretopology.h"
 #include "gromacs/hardware/hw_info.h"
-#include "gromacs/mdlib/gmx_omp_nthreads.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/utility/basenetwork.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/gmxomp.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/programcontext.h"
 #include "gromacs/utility/scoped_cptr.h"
 #include "gromacs/utility/smalloc.h"
 
+namespace
+{
+
+class DefaultThreadAffinityAccess : public gmx::IThreadAffinityAccess
+{
+    public:
+        virtual bool isThreadAffinitySupported() const
+        {
+            return tMPI_Thread_setaffinity_support() == TMPI_SETAFFINITY_SUPPORT_YES;
+        }
+        virtual bool setCurrentThreadAffinityToCore(int core)
+        {
+            const int ret = tMPI_Thread_setaffinity_single(tMPI_Thread_self(), core);
+            return ret == 0;
+        }
+};
+
+//! Global instance of DefaultThreadAffinityAccess
+DefaultThreadAffinityAccess g_defaultAffinityAccess;
+
+} // namespace
+
+gmx::IThreadAffinityAccess::~IThreadAffinityAccess()
+{
+}
 
 static bool invalidWithinSimulation(const t_commrec *cr, bool invalidLocally)
 {
@@ -83,9 +107,9 @@ static bool invalidWithinSimulation(const t_commrec *cr, bool invalidLocally)
 }
 
 static bool
-get_thread_affinity_layout(FILE *fplog,
+get_thread_affinity_layout(FILE *fplog, const gmx::MDLogger &mdlog,
                            const t_commrec *cr,
-                           const gmx_hw_info_t * hwinfo,
+                           const gmx::HardwareTopology &hwTop,
                            int   threads,
                            bool  automatic,
                            int pin_offset, int * pin_stride,
@@ -97,8 +121,6 @@ get_thread_affinity_layout(FILE *fplog,
     bool                         haveTopology;
     bool                         invalidValue;
 
-    const gmx::HardwareTopology &hwTop = *hwinfo->hardwareTopology;
-
     haveTopology = (hwTop.supportLevel() >= gmx::HardwareTopology::SupportLevel::Basic);
 
     if (pin_offset < 0)
@@ -131,7 +153,7 @@ get_thread_affinity_layout(FILE *fplog,
     else
     {
         /* topology information not available or invalid, ignore it */
-        hwThreads       = hwinfo->nthreads_hw_avail;
+        hwThreads       = hwTop.machine().logicalProcessorCount;
         *localityOrder  = NULL;
     }
     // Only warn about the first problem per node.  Otherwise, the first test
@@ -144,8 +166,8 @@ get_thread_affinity_layout(FILE *fplog,
     if (invalidWithinSimulation(cr, invalidValue))
     {
         /* We don't know anything about the hardware, don't pin */
-        md_print_warn(cr, fplog,
-                      "NOTE: No information on available cores, thread pinning disabled.\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText(
+                "NOTE: No information on available cores, thread pinning disabled.");
         alreadyWarned = true;
     }
     bool validLayout = !invalidValue;
@@ -156,11 +178,11 @@ get_thread_affinity_layout(FILE *fplog,
         bool warn = (invalidValue && threads > 1 && threads < hwThreads);
         if (invalidWithinSimulation(cr, warn) && !alreadyWarned)
         {
-            md_print_warn(cr, fplog,
-                          "NOTE: The number of threads is not equal to the number of (logical) cores\n"
-                          "      and the -pin option is set to auto: will not pin thread to cores.\n"
-                          "      This can lead to significant performance degradation.\n"
-                          "      Consider using -pin on (and -pinoffset in case you run multiple jobs).\n");
+            GMX_LOG(mdlog.warning).asParagraph().appendText(
+                    "NOTE: The number of threads is not equal to the number of (logical) cores\n"
+                    "      and the -pin option is set to auto: will not pin thread to cores.\n"
+                    "      This can lead to significant performance degradation.\n"
+                    "      Consider using -pin on (and -pinoffset in case you run multiple jobs).");
             alreadyWarned = true;
         }
         validLayout = validLayout && !invalidValue;
@@ -169,8 +191,8 @@ get_thread_affinity_layout(FILE *fplog,
     invalidValue = (threads > hwThreads);
     if (invalidWithinSimulation(cr, invalidValue) && !alreadyWarned)
     {
-        md_print_warn(cr, fplog,
-                      "NOTE: Oversubscribing a CPU, will not pin threads.\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText(
+                "NOTE: Oversubscribing the CPU, will not pin threads");
         alreadyWarned = true;
     }
     validLayout = validLayout && !invalidValue;
@@ -178,8 +200,8 @@ get_thread_affinity_layout(FILE *fplog,
     invalidValue = (pin_offset + threads > hwThreads);
     if (invalidWithinSimulation(cr, invalidValue) && !alreadyWarned)
     {
-        md_print_warn(cr, fplog,
-                      "WARNING: Requested offset too large for available cores, thread pinning disabled.\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText(
+                "WARNING: Requested offset too large for available cores, thread pinning disabled.");
         alreadyWarned = true;
 
     }
@@ -219,8 +241,8 @@ get_thread_affinity_layout(FILE *fplog,
     if (invalidWithinSimulation(cr, invalidValue) && !alreadyWarned)
     {
         /* We are oversubscribing, don't pin */
-        md_print_warn(cr, fplog,
-                      "WARNING: Requested stride too large for available cores, thread pinning disabled.\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText(
+                "WARNING: Requested stride too large for available cores, thread pinning disabled.");
     }
     validLayout = validLayout && !invalidValue;
 
@@ -235,7 +257,8 @@ get_thread_affinity_layout(FILE *fplog,
 }
 
 static bool set_affinity(const t_commrec *cr, int nthread_local, int thread0_id_node,
-                         int offset, int core_pinning_stride, int *localityOrder)
+                         int offset, int core_pinning_stride, int *localityOrder,
+                         gmx::IThreadAffinityAccess *affinityAccess)
 {
     // Set the per-thread affinity. In order to be able to check the success
     // of affinity settings, we will set nth_affinity_set to 1 on threads
@@ -253,7 +276,6 @@ static bool set_affinity(const t_commrec *cr, int nthread_local, int thread0_id_
         {
             int      thread_id, thread_id_node;
             int      index, core;
-            gmx_bool setaffinity_ret;
 
             thread_id      = gmx_omp_get_thread_num();
             thread_id_node = thread0_id_node + thread_id;
@@ -267,15 +289,15 @@ static bool set_affinity(const t_commrec *cr, int nthread_local, int thread0_id_
                 core = index;
             }
 
-            setaffinity_ret = tMPI_Thread_setaffinity_single(tMPI_Thread_self(), core);
+            const bool ret = affinityAccess->setCurrentThreadAffinityToCore(core);
 
             /* store the per-thread success-values of the setaffinity */
-            nth_affinity_set += (setaffinity_ret == 0);
+            nth_affinity_set += (ret ? 1 : 0);
 
             if (debug)
             {
                 fprintf(debug, "On rank %2d, thread %2d, index %2d, core %2d the affinity setting returned %d\n",
-                        cr->nodeid, gmx_omp_get_thread_num(), index, core, setaffinity_ret);
+                        cr->nodeid, gmx_omp_get_thread_num(), index, core, ret ? 1 : 0);
             }
         }
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
@@ -332,13 +354,15 @@ static bool set_affinity(const t_commrec *cr, int nthread_local, int thread0_id_
    if only PME is using threads.
  */
 void
-gmx_set_thread_affinity(FILE                *fplog,
-                        const t_commrec     *cr,
-                        const gmx_hw_opt_t  *hw_opt,
-                        const gmx_hw_info_t *hwinfo)
+gmx_set_thread_affinity(FILE                        *fplog,
+                        const gmx::MDLogger         &mdlog,
+                        const t_commrec             *cr,
+                        const gmx_hw_opt_t          *hw_opt,
+                        const gmx::HardwareTopology &hwTop,
+                        int                          nthread_local,
+                        gmx::IThreadAffinityAccess  *affinityAccess)
 {
-    int        thread0_id_node,
-               nthread_local, nthread_node;
+    int        thread0_id_node, nthread_node;
     int *      localityOrder = nullptr;
 
     if (hw_opt->thread_affinity == threadaffOFF)
@@ -347,31 +371,26 @@ gmx_set_thread_affinity(FILE                *fplog,
         return;
     }
 
+    if (affinityAccess == nullptr)
+    {
+        affinityAccess = &g_defaultAffinityAccess;
+    }
+
     /* If the tMPI thread affinity setting is not supported encourage the user
      * to report it as it's either a bug or an exotic platform which we might
      * want to support. */
-    if (tMPI_Thread_setaffinity_support() != TMPI_SETAFFINITY_SUPPORT_YES)
+    if (!affinityAccess->isThreadAffinitySupported())
     {
         /* we know Mac OS & BlueGene do not support setting thread affinity, so there's
            no point in warning the user in that case. In any other case
            the user might be able to do something about it. */
 #if !defined(__APPLE__) && !defined(__bg__)
-        md_print_warn(cr, fplog,
-                      "NOTE: Cannot set thread affinities on the current platform.\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText(
+                "NOTE: Cannot set thread affinities on the current platform.");
 #endif  /* __APPLE__ */
         return;
     }
 
-    /* threads on this MPI process or TMPI thread */
-    if (cr->duty & DUTY_PP)
-    {
-        nthread_local = gmx_omp_nthreads_get(emntNonbonded);
-    }
-    else
-    {
-        nthread_local = gmx_omp_nthreads_get(emntPME);
-    }
-
     /* map the current process to cores */
     thread0_id_node = 0;
     nthread_node    = nthread_local;
@@ -399,12 +418,12 @@ gmx_set_thread_affinity(FILE                *fplog,
     int  core_pinning_stride = hw_opt->core_pinning_stride;
     if (offset != 0)
     {
-        md_print_info(cr, fplog, "Applying core pinning offset %d\n", offset);
+        GMX_LOG(mdlog.warning).appendTextFormatted("Applying core pinning offset %d", offset);
     }
 
     bool automatic = (hw_opt->thread_affinity == threadaffAUTO);
     bool validLayout
-        = get_thread_affinity_layout(fplog, cr, hwinfo, nthread_node, automatic,
+        = get_thread_affinity_layout(fplog, mdlog, cr, hwTop, nthread_node, automatic,
                                      offset, &core_pinning_stride, &localityOrder);
     gmx::scoped_guard_sfree localityOrderGuard(localityOrder);
 
@@ -412,7 +431,8 @@ gmx_set_thread_affinity(FILE                *fplog,
     if (validLayout)
     {
         allAffinitiesSet = set_affinity(cr, nthread_local, thread0_id_node,
-                                        offset, core_pinning_stride, localityOrder);
+                                        offset, core_pinning_stride, localityOrder,
+                                        affinityAccess);
     }
     else
     {
@@ -421,9 +441,9 @@ gmx_set_thread_affinity(FILE                *fplog,
     }
     if (invalidWithinSimulation(cr, !allAffinitiesSet))
     {
-        md_print_warn(cr, fplog,
-                      "NOTE: Thread affinity setting failed. This can cause performance degradation.\n"
-                      "      If you think your settings are correct, ask on the gmx-users list.\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText(
+                "NOTE: Thread affinity setting failed. This can cause performance degradation.\n"
+                "      If you think your settings are correct, ask on the gmx-users list.");
     }
 }
 
@@ -432,11 +452,11 @@ gmx_set_thread_affinity(FILE                *fplog,
  * Note that this will only work on Linux as we use a GNU feature.
  */
 void
-gmx_check_thread_affinity_set(FILE            *fplog,
-                              const t_commrec *cr,
-                              gmx_hw_opt_t    *hw_opt,
-                              int  gmx_unused  nthreads_hw_avail,
-                              gmx_bool         bAfterOpenmpInit)
+gmx_check_thread_affinity_set(const gmx::MDLogger &mdlog,
+                              const t_commrec     *cr,
+                              gmx_hw_opt_t        *hw_opt,
+                              int  gmx_unused      nthreads_hw_avail,
+                              gmx_bool             bAfterOpenmpInit)
 {
     GMX_RELEASE_ASSERT(hw_opt, "hw_opt must be a non-NULL pointer");
 
@@ -453,7 +473,7 @@ gmx_check_thread_affinity_set(FILE            *fplog,
             if (!gmx_omp_check_thread_affinity(&message))
             {
                 /* TODO: with -pin auto we should only warn when using all cores */
-                md_print_warn(cr, fplog, "%s", message);
+                GMX_LOG(mdlog.warning).asParagraph().appendText(message);
                 sfree(message);
                 hw_opt->thread_affinity = threadaffOFF;
             }
@@ -537,14 +557,14 @@ gmx_check_thread_affinity_set(FILE            *fplog,
         {
             if (!bAfterOpenmpInit)
             {
-                md_print_warn(cr, fplog,
-                              "Non-default thread affinity set, disabling internal thread affinity");
+                GMX_LOG(mdlog.warning).asParagraph().appendText(
+                        "Non-default thread affinity set, disabling internal thread affinity");
             }
             else
             {
-                md_print_warn(cr, fplog,
-                              "Non-default thread affinity set probably by the OpenMP library,\n"
-                              "disabling internal thread affinity");
+                GMX_LOG(mdlog.warning).asParagraph().appendText(
+                        "Non-default thread affinity set probably by the OpenMP library,\n"
+                        "disabling internal thread affinity");
             }
             hw_opt->thread_affinity = threadaffOFF;
         }
@@ -553,9 +573,9 @@ gmx_check_thread_affinity_set(FILE            *fplog,
             /* Only warn once, at the last check (bAfterOpenmpInit==TRUE) */
             if (bAfterOpenmpInit)
             {
-                md_print_warn(cr, fplog,
-                              "Overriding thread affinity set outside %s\n",
-                              gmx::getProgramContext().displayName());
+                GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                        "Overriding thread affinity set outside %s",
+                        gmx::getProgramContext().displayName());
             }
         }
 
index 8ca8854bf2d35f08c4b5e939a3cc2e98d0394c7b..28c7acddafb821237a99ebff51adb9080516d444 100644 (file)
@@ -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
  * 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.
 
 #include <cstdio>
 
-#include "gromacs/hardware/hw_info.h"
 #include "gromacs/utility/basedefinitions.h"
 
+struct gmx_hw_opt_t;
 struct t_commrec;
 
+namespace gmx
+{
+
+class HardwareTopology;
+class MDLogger;
+
+class IThreadAffinityAccess
+{
+    public:
+        virtual bool isThreadAffinitySupported() const        = 0;
+        virtual bool setCurrentThreadAffinityToCore(int core) = 0;
+
+    protected:
+        virtual ~IThreadAffinityAccess();
+};
+
+} // namespace gmx
+
 /*! \brief
  * Sets the thread affinity using the requested setting stored in hw_opt.
- *
- * The hardware topology is requested from hwinfo, when present.
  */
 void
-gmx_set_thread_affinity(FILE                *fplog,
-                        const t_commrec     *cr,
-                        const gmx_hw_opt_t  *hw_opt,
-                        const gmx_hw_info_t *hwinfo);
+gmx_set_thread_affinity(FILE                        *fplog,
+                        const gmx::MDLogger         &mdlog,
+                        const t_commrec             *cr,
+                        const gmx_hw_opt_t          *hw_opt,
+                        const gmx::HardwareTopology &hwTop,
+                        int                          nthread_local,
+                        gmx::IThreadAffinityAccess  *affinityAccess);
 
 /*! \brief
  * Checks the process affinity mask and if it is found to be non-zero,
@@ -75,7 +94,7 @@ gmx_set_thread_affinity(FILE                *fplog,
  * variables for setting the affinity are set.
  */
 void
-gmx_check_thread_affinity_set(FILE *fplog, const t_commrec *cr,
+gmx_check_thread_affinity_set(const gmx::MDLogger &mdlog, const t_commrec *cr,
                               gmx_hw_opt_t *hw_opt, int ncpus,
                               gmx_bool bAfterOpenmpInit);
 
index 5e6159b633b24317912a89e2e8633473bf7a7586..aa4b2502526beb5d775af8a9866c530e96af9db1 100644 (file)
 
 #include <algorithm>
 
+#include "gromacs/math/veccompare.h"
 #include "gromacs/math/vecdump.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/mdtypes/pull-params.h"
 #include "gromacs/pbcutil/pbc.h"
+#include "gromacs/utility/compare.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/smalloc.h"
@@ -251,14 +253,6 @@ gmx_bool ir_vdw_might_be_zero_at_cutoff(const t_inputrec *ir)
     return (ir_vdw_is_zero_at_cutoff(ir) || ir->vdwtype == evdwUSER);
 }
 
-void init_inputrec(t_inputrec *ir)
-{
-    std::memset(ir, 0, sizeof(*ir));
-    snew(ir->fepvals, 1);
-    snew(ir->expandedvals, 1);
-    snew(ir->simtempvals, 1);
-}
-
 static void done_pull_group(t_pull_group *pgrp)
 {
     if (pgrp->nat > 0)
@@ -1040,6 +1034,316 @@ void pr_inputrec(FILE *fp, int indent, const char *title, const t_inputrec *ir,
 #undef PR
 #undef PI
 
+static void cmp_grpopts(FILE *fp, const t_grpopts *opt1, const t_grpopts *opt2, real ftol, real abstol)
+{
+    int  i, j;
+    char buf1[256], buf2[256];
+
+    cmp_int(fp, "inputrec->grpopts.ngtc", -1,  opt1->ngtc, opt2->ngtc);
+    cmp_int(fp, "inputrec->grpopts.ngacc", -1, opt1->ngacc, opt2->ngacc);
+    cmp_int(fp, "inputrec->grpopts.ngfrz", -1, opt1->ngfrz, opt2->ngfrz);
+    cmp_int(fp, "inputrec->grpopts.ngener", -1, opt1->ngener, opt2->ngener);
+    for (i = 0; (i < std::min(opt1->ngtc, opt2->ngtc)); i++)
+    {
+        cmp_real(fp, "inputrec->grpopts.nrdf", i, opt1->nrdf[i], opt2->nrdf[i], ftol, abstol);
+        cmp_real(fp, "inputrec->grpopts.ref_t", i, opt1->ref_t[i], opt2->ref_t[i], ftol, abstol);
+        cmp_real(fp, "inputrec->grpopts.tau_t", i, opt1->tau_t[i], opt2->tau_t[i], ftol, abstol);
+        cmp_int(fp, "inputrec->grpopts.annealing", i, opt1->annealing[i], opt2->annealing[i]);
+        cmp_int(fp, "inputrec->grpopts.anneal_npoints", i,
+                opt1->anneal_npoints[i], opt2->anneal_npoints[i]);
+        if (opt1->anneal_npoints[i] == opt2->anneal_npoints[i])
+        {
+            sprintf(buf1, "inputrec->grpopts.anneal_time[%d]", i);
+            sprintf(buf2, "inputrec->grpopts.anneal_temp[%d]", i);
+            for (j = 0; j < opt1->anneal_npoints[i]; j++)
+            {
+                cmp_real(fp, buf1, j, opt1->anneal_time[i][j], opt2->anneal_time[i][j], ftol, abstol);
+                cmp_real(fp, buf2, j, opt1->anneal_temp[i][j], opt2->anneal_temp[i][j], ftol, abstol);
+            }
+        }
+    }
+    if (opt1->ngener == opt2->ngener)
+    {
+        for (i = 0; i < opt1->ngener; i++)
+        {
+            for (j = i; j < opt1->ngener; j++)
+            {
+                sprintf(buf1, "inputrec->grpopts.egp_flags[%d]", i);
+                cmp_int(fp, buf1, j,
+                        opt1->egp_flags[opt1->ngener*i+j],
+                        opt2->egp_flags[opt1->ngener*i+j]);
+            }
+        }
+    }
+    for (i = 0; (i < std::min(opt1->ngacc, opt2->ngacc)); i++)
+    {
+        cmp_rvec(fp, "inputrec->grpopts.acc", i, opt1->acc[i], opt2->acc[i], ftol, abstol);
+    }
+    for (i = 0; (i < std::min(opt1->ngfrz, opt2->ngfrz)); i++)
+    {
+        cmp_ivec(fp, "inputrec->grpopts.nFreeze", i, opt1->nFreeze[i], opt2->nFreeze[i]);
+    }
+}
+
+
+static void cmp_cosines(FILE *fp, const char *s, const t_cosines c1[DIM], const t_cosines c2[DIM], real ftol, real abstol)
+{
+    int  i, m;
+    char buf[256];
+
+    for (m = 0; (m < DIM); m++)
+    {
+        sprintf(buf, "inputrec->%s[%d]", s, m);
+        cmp_int(fp, buf, 0, c1->n, c2->n);
+        for (i = 0; (i < std::min(c1->n, c2->n)); i++)
+        {
+            cmp_real(fp, buf, i, c1->a[i], c2->a[i], ftol, abstol);
+            cmp_real(fp, buf, i, c1->phi[i], c2->phi[i], ftol, abstol);
+        }
+    }
+}
+static void cmp_pull(FILE *fp)
+{
+    fprintf(fp, "WARNING: Both files use COM pulling, but comparing of the pull struct is not implemented (yet). The pull parameters could be the same or different.\n");
+}
+
+static void cmp_simtempvals(FILE *fp, const t_simtemp *simtemp1, const t_simtemp *simtemp2, int n_lambda, real ftol, real abstol)
+{
+    int i;
+    cmp_int(fp, "inputrec->simtempvals->eSimTempScale", -1, simtemp1->eSimTempScale, simtemp2->eSimTempScale);
+    cmp_real(fp, "inputrec->simtempvals->simtemp_high", -1, simtemp1->simtemp_high, simtemp2->simtemp_high, ftol, abstol);
+    cmp_real(fp, "inputrec->simtempvals->simtemp_low", -1, simtemp1->simtemp_low, simtemp2->simtemp_low, ftol, abstol);
+    for (i = 0; i < n_lambda; i++)
+    {
+        cmp_real(fp, "inputrec->simtempvals->temperatures", -1, simtemp1->temperatures[i], simtemp2->temperatures[i], ftol, abstol);
+    }
+}
+
+static void cmp_expandedvals(FILE *fp, const t_expanded *expand1, const t_expanded *expand2, int n_lambda, real ftol, real abstol)
+{
+    int i;
+
+    cmp_bool(fp, "inputrec->fepvals->bInit_weights", -1, expand1->bInit_weights, expand2->bInit_weights);
+    cmp_bool(fp, "inputrec->fepvals->bWLoneovert", -1, expand1->bWLoneovert, expand2->bWLoneovert);
+
+    for (i = 0; i < n_lambda; i++)
+    {
+        cmp_real(fp, "inputrec->expandedvals->init_lambda_weights", -1,
+                 expand1->init_lambda_weights[i], expand2->init_lambda_weights[i], ftol, abstol);
+    }
+
+    cmp_int(fp, "inputrec->expandedvals->lambda-stats", -1, expand1->elamstats, expand2->elamstats);
+    cmp_int(fp, "inputrec->expandedvals->lambda-mc-move", -1, expand1->elmcmove, expand2->elmcmove);
+    cmp_int(fp, "inputrec->expandedvals->lmc-repeats", -1, expand1->lmc_repeats, expand2->lmc_repeats);
+    cmp_int(fp, "inputrec->expandedvals->lmc-gibbsdelta", -1, expand1->gibbsdeltalam, expand2->gibbsdeltalam);
+    cmp_int(fp, "inputrec->expandedvals->lmc-forced-nstart", -1, expand1->lmc_forced_nstart, expand2->lmc_forced_nstart);
+    cmp_int(fp, "inputrec->expandedvals->lambda-weights-equil", -1, expand1->elmceq, expand2->elmceq);
+    cmp_int(fp, "inputrec->expandedvals->,weight-equil-number-all-lambda", -1, expand1->equil_n_at_lam, expand2->equil_n_at_lam);
+    cmp_int(fp, "inputrec->expandedvals->weight-equil-number-samples", -1, expand1->equil_samples, expand2->equil_samples);
+    cmp_int(fp, "inputrec->expandedvals->weight-equil-number-steps", -1, expand1->equil_steps, expand2->equil_steps);
+    cmp_real(fp, "inputrec->expandedvals->weight-equil-wl-delta", -1, expand1->equil_wl_delta, expand2->equil_wl_delta, ftol, abstol);
+    cmp_real(fp, "inputrec->expandedvals->weight-equil-count-ratio", -1, expand1->equil_ratio, expand2->equil_ratio, ftol, abstol);
+    cmp_bool(fp, "inputrec->expandedvals->symmetrized-transition-matrix", -1, expand1->bSymmetrizedTMatrix, expand2->bSymmetrizedTMatrix);
+    cmp_int(fp, "inputrec->expandedvals->nstTij", -1, expand1->nstTij, expand2->nstTij);
+    cmp_int(fp, "inputrec->expandedvals->mininum-var-min", -1, expand1->minvarmin, expand2->minvarmin); /*default is reasonable */
+    cmp_int(fp, "inputrec->expandedvals->weight-c-range", -1, expand1->c_range, expand2->c_range);      /* default is just C=0 */
+    cmp_real(fp, "inputrec->expandedvals->wl-scale", -1, expand1->wl_scale, expand2->wl_scale, ftol, abstol);
+    cmp_real(fp, "inputrec->expandedvals->init-wl-delta", -1, expand1->init_wl_delta, expand2->init_wl_delta, ftol, abstol);
+    cmp_real(fp, "inputrec->expandedvals->wl-ratio", -1, expand1->wl_ratio, expand2->wl_ratio, ftol, abstol);
+    cmp_int(fp, "inputrec->expandedvals->nstexpanded", -1, expand1->nstexpanded, expand2->nstexpanded);
+    cmp_int(fp, "inputrec->expandedvals->lmc-seed", -1, expand1->lmc_seed, expand2->lmc_seed);
+    cmp_real(fp, "inputrec->expandedvals->mc-temperature", -1, expand1->mc_temp, expand2->mc_temp, ftol, abstol);
+}
+
+static void cmp_fepvals(FILE *fp, const t_lambda *fep1, const t_lambda *fep2, real ftol, real abstol)
+{
+    int i, j;
+    cmp_int(fp, "inputrec->nstdhdl", -1, fep1->nstdhdl, fep2->nstdhdl);
+    cmp_double(fp, "inputrec->fepvals->init_fep_state", -1, fep1->init_fep_state, fep2->init_fep_state, ftol, abstol);
+    cmp_double(fp, "inputrec->fepvals->delta_lambda", -1, fep1->delta_lambda, fep2->delta_lambda, ftol, abstol);
+    cmp_int(fp, "inputrec->fepvals->n_lambda", -1, fep1->n_lambda, fep2->n_lambda);
+    for (i = 0; i < efptNR; i++)
+    {
+        for (j = 0; j < std::min(fep1->n_lambda, fep2->n_lambda); j++)
+        {
+            cmp_double(fp, "inputrec->fepvals->all_lambda", -1, fep1->all_lambda[i][j], fep2->all_lambda[i][j], ftol, abstol);
+        }
+    }
+    cmp_int(fp, "inputrec->fepvals->lambda_neighbors", 1, fep1->lambda_neighbors,
+            fep2->lambda_neighbors);
+    cmp_real(fp, "inputrec->fepvals->sc_alpha", -1, fep1->sc_alpha, fep2->sc_alpha, ftol, abstol);
+    cmp_int(fp, "inputrec->fepvals->sc_power", -1, fep1->sc_power, fep2->sc_power);
+    cmp_real(fp, "inputrec->fepvals->sc_r_power", -1, fep1->sc_r_power, fep2->sc_r_power, ftol, abstol);
+    cmp_real(fp, "inputrec->fepvals->sc_sigma", -1, fep1->sc_sigma, fep2->sc_sigma, ftol, abstol);
+    cmp_int(fp, "inputrec->fepvals->edHdLPrintEnergy", -1, fep1->edHdLPrintEnergy, fep1->edHdLPrintEnergy);
+    cmp_bool(fp, "inputrec->fepvals->bScCoul", -1, fep1->bScCoul, fep1->bScCoul);
+    cmp_int(fp, "inputrec->separate_dhdl_file", -1, fep1->separate_dhdl_file, fep2->separate_dhdl_file);
+    cmp_int(fp, "inputrec->dhdl_derivatives", -1, fep1->dhdl_derivatives, fep2->dhdl_derivatives);
+    cmp_int(fp, "inputrec->dh_hist_size", -1, fep1->dh_hist_size, fep2->dh_hist_size);
+    cmp_double(fp, "inputrec->dh_hist_spacing", -1, fep1->dh_hist_spacing, fep2->dh_hist_spacing, ftol, abstol);
+}
+
+void cmp_inputrec(FILE *fp, const t_inputrec *ir1, const t_inputrec *ir2, real ftol, real abstol)
+{
+    fprintf(fp, "comparing inputrec\n");
+
+    /* gcc 2.96 doesnt like these defines at all, but issues a huge list
+     * of warnings. Maybe it will change in future versions, but for the
+     * moment I've spelled them out instead. /EL 000820
+     * #define CIB(s) cmp_int(fp,"inputrec->"#s,0,ir1->##s,ir2->##s)
+     * #define CII(s) cmp_int(fp,"inputrec->"#s,0,ir1->##s,ir2->##s)
+     * #define CIR(s) cmp_real(fp,"inputrec->"#s,0,ir1->##s,ir2->##s,ftol)
+     */
+    cmp_int(fp, "inputrec->eI", -1, ir1->eI, ir2->eI);
+    cmp_int64(fp, "inputrec->nsteps", ir1->nsteps, ir2->nsteps);
+    cmp_int64(fp, "inputrec->init_step", ir1->init_step, ir2->init_step);
+    cmp_int(fp, "inputrec->simulation_part", -1, ir1->simulation_part, ir2->simulation_part);
+    cmp_int(fp, "inputrec->ePBC", -1, ir1->ePBC, ir2->ePBC);
+    cmp_int(fp, "inputrec->bPeriodicMols", -1, ir1->bPeriodicMols, ir2->bPeriodicMols);
+    cmp_int(fp, "inputrec->cutoff_scheme", -1, ir1->cutoff_scheme, ir2->cutoff_scheme);
+    cmp_int(fp, "inputrec->ns_type", -1, ir1->ns_type, ir2->ns_type);
+    cmp_int(fp, "inputrec->nstlist", -1, ir1->nstlist, ir2->nstlist);
+    cmp_int(fp, "inputrec->nstcomm", -1, ir1->nstcomm, ir2->nstcomm);
+    cmp_int(fp, "inputrec->comm_mode", -1, ir1->comm_mode, ir2->comm_mode);
+    cmp_int(fp, "inputrec->nstlog", -1, ir1->nstlog, ir2->nstlog);
+    cmp_int(fp, "inputrec->nstxout", -1, ir1->nstxout, ir2->nstxout);
+    cmp_int(fp, "inputrec->nstvout", -1, ir1->nstvout, ir2->nstvout);
+    cmp_int(fp, "inputrec->nstfout", -1, ir1->nstfout, ir2->nstfout);
+    cmp_int(fp, "inputrec->nstcalcenergy", -1, ir1->nstcalcenergy, ir2->nstcalcenergy);
+    cmp_int(fp, "inputrec->nstenergy", -1, ir1->nstenergy, ir2->nstenergy);
+    cmp_int(fp, "inputrec->nstxout_compressed", -1, ir1->nstxout_compressed, ir2->nstxout_compressed);
+    cmp_double(fp, "inputrec->init_t", -1, ir1->init_t, ir2->init_t, ftol, abstol);
+    cmp_double(fp, "inputrec->delta_t", -1, ir1->delta_t, ir2->delta_t, ftol, abstol);
+    cmp_real(fp, "inputrec->x_compression_precision", -1, ir1->x_compression_precision, ir2->x_compression_precision, ftol, abstol);
+    cmp_real(fp, "inputrec->fourierspacing", -1, ir1->fourier_spacing, ir2->fourier_spacing, ftol, abstol);
+    cmp_int(fp, "inputrec->nkx", -1, ir1->nkx, ir2->nkx);
+    cmp_int(fp, "inputrec->nky", -1, ir1->nky, ir2->nky);
+    cmp_int(fp, "inputrec->nkz", -1, ir1->nkz, ir2->nkz);
+    cmp_int(fp, "inputrec->pme_order", -1, ir1->pme_order, ir2->pme_order);
+    cmp_real(fp, "inputrec->ewald_rtol", -1, ir1->ewald_rtol, ir2->ewald_rtol, ftol, abstol);
+    cmp_int(fp, "inputrec->ewald_geometry", -1, ir1->ewald_geometry, ir2->ewald_geometry);
+    cmp_real(fp, "inputrec->epsilon_surface", -1, ir1->epsilon_surface, ir2->epsilon_surface, ftol, abstol);
+    cmp_int(fp, "inputrec->bContinuation", -1, ir1->bContinuation, ir2->bContinuation);
+    cmp_int(fp, "inputrec->bShakeSOR", -1, ir1->bShakeSOR, ir2->bShakeSOR);
+    cmp_int(fp, "inputrec->etc", -1, ir1->etc, ir2->etc);
+    cmp_int(fp, "inputrec->bPrintNHChains", -1, ir1->bPrintNHChains, ir2->bPrintNHChains);
+    cmp_int(fp, "inputrec->epc", -1, ir1->epc, ir2->epc);
+    cmp_int(fp, "inputrec->epct", -1, ir1->epct, ir2->epct);
+    cmp_real(fp, "inputrec->tau_p", -1, ir1->tau_p, ir2->tau_p, ftol, abstol);
+    cmp_rvec(fp, "inputrec->ref_p(x)", -1, ir1->ref_p[XX], ir2->ref_p[XX], ftol, abstol);
+    cmp_rvec(fp, "inputrec->ref_p(y)", -1, ir1->ref_p[YY], ir2->ref_p[YY], ftol, abstol);
+    cmp_rvec(fp, "inputrec->ref_p(z)", -1, ir1->ref_p[ZZ], ir2->ref_p[ZZ], ftol, abstol);
+    cmp_rvec(fp, "inputrec->compress(x)", -1, ir1->compress[XX], ir2->compress[XX], ftol, abstol);
+    cmp_rvec(fp, "inputrec->compress(y)", -1, ir1->compress[YY], ir2->compress[YY], ftol, abstol);
+    cmp_rvec(fp, "inputrec->compress(z)", -1, ir1->compress[ZZ], ir2->compress[ZZ], ftol, abstol);
+    cmp_int(fp, "refcoord_scaling", -1, ir1->refcoord_scaling, ir2->refcoord_scaling);
+    cmp_rvec(fp, "inputrec->posres_com", -1, ir1->posres_com, ir2->posres_com, ftol, abstol);
+    cmp_rvec(fp, "inputrec->posres_comB", -1, ir1->posres_comB, ir2->posres_comB, ftol, abstol);
+    cmp_real(fp, "inputrec->verletbuf_tol", -1, ir1->verletbuf_tol, ir2->verletbuf_tol, ftol, abstol);
+    cmp_real(fp, "inputrec->rlist", -1, ir1->rlist, ir2->rlist, ftol, abstol);
+    cmp_real(fp, "inputrec->rtpi", -1, ir1->rtpi, ir2->rtpi, ftol, abstol);
+    cmp_int(fp, "inputrec->coulombtype", -1, ir1->coulombtype, ir2->coulombtype);
+    cmp_int(fp, "inputrec->coulomb_modifier", -1, ir1->coulomb_modifier, ir2->coulomb_modifier);
+    cmp_real(fp, "inputrec->rcoulomb_switch", -1, ir1->rcoulomb_switch, ir2->rcoulomb_switch, ftol, abstol);
+    cmp_real(fp, "inputrec->rcoulomb", -1, ir1->rcoulomb, ir2->rcoulomb, ftol, abstol);
+    cmp_int(fp, "inputrec->vdwtype", -1, ir1->vdwtype, ir2->vdwtype);
+    cmp_int(fp, "inputrec->vdw_modifier", -1, ir1->vdw_modifier, ir2->vdw_modifier);  cmp_real(fp, "inputrec->rvdw_switch", -1, ir1->rvdw_switch, ir2->rvdw_switch, ftol, abstol);
+    cmp_real(fp, "inputrec->rvdw", -1, ir1->rvdw, ir2->rvdw, ftol, abstol);
+    cmp_real(fp, "inputrec->epsilon_r", -1, ir1->epsilon_r, ir2->epsilon_r, ftol, abstol);
+    cmp_real(fp, "inputrec->epsilon_rf", -1, ir1->epsilon_rf, ir2->epsilon_rf, ftol, abstol);
+    cmp_real(fp, "inputrec->tabext", -1, ir1->tabext, ir2->tabext, ftol, abstol);
+    cmp_int(fp, "inputrec->implicit_solvent", -1, ir1->implicit_solvent, ir2->implicit_solvent);
+    cmp_int(fp, "inputrec->gb_algorithm", -1, ir1->gb_algorithm, ir2->gb_algorithm);
+    cmp_int(fp, "inputrec->nstgbradii", -1, ir1->nstgbradii, ir2->nstgbradii);
+    cmp_real(fp, "inputrec->rgbradii", -1, ir1->rgbradii, ir2->rgbradii, ftol, abstol);
+    cmp_real(fp, "inputrec->gb_saltconc", -1, ir1->gb_saltconc, ir2->gb_saltconc, ftol, abstol);
+    cmp_real(fp, "inputrec->gb_epsilon_solvent", -1, ir1->gb_epsilon_solvent, ir2->gb_epsilon_solvent, ftol, abstol);
+    cmp_real(fp, "inputrec->gb_obc_alpha", -1, ir1->gb_obc_alpha, ir2->gb_obc_alpha, ftol, abstol);
+    cmp_real(fp, "inputrec->gb_obc_beta", -1, ir1->gb_obc_beta, ir2->gb_obc_beta, ftol, abstol);
+    cmp_real(fp, "inputrec->gb_obc_gamma", -1, ir1->gb_obc_gamma, ir2->gb_obc_gamma, ftol, abstol);
+    cmp_real(fp, "inputrec->gb_dielectric_offset", -1, ir1->gb_dielectric_offset, ir2->gb_dielectric_offset, ftol, abstol);
+    cmp_int(fp, "inputrec->sa_algorithm", -1, ir1->sa_algorithm, ir2->sa_algorithm);
+    cmp_real(fp, "inputrec->sa_surface_tension", -1, ir1->sa_surface_tension, ir2->sa_surface_tension, ftol, abstol);
+
+    cmp_int(fp, "inputrec->eDispCorr", -1, ir1->eDispCorr, ir2->eDispCorr);
+    cmp_real(fp, "inputrec->shake_tol", -1, ir1->shake_tol, ir2->shake_tol, ftol, abstol);
+    cmp_int(fp, "inputrec->efep", -1, ir1->efep, ir2->efep);
+    cmp_fepvals(fp, ir1->fepvals, ir2->fepvals, ftol, abstol);
+    cmp_int(fp, "inputrec->bSimTemp", -1, ir1->bSimTemp, ir2->bSimTemp);
+    if ((ir1->bSimTemp == ir2->bSimTemp) && (ir1->bSimTemp))
+    {
+        cmp_simtempvals(fp, ir1->simtempvals, ir2->simtempvals, std::min(ir1->fepvals->n_lambda, ir2->fepvals->n_lambda), ftol, abstol);
+    }
+    cmp_int(fp, "inputrec->bExpanded", -1, ir1->bExpanded, ir2->bExpanded);
+    if ((ir1->bExpanded == ir2->bExpanded) && (ir1->bExpanded))
+    {
+        cmp_expandedvals(fp, ir1->expandedvals, ir2->expandedvals, std::min(ir1->fepvals->n_lambda, ir2->fepvals->n_lambda), ftol, abstol);
+    }
+    cmp_int(fp, "inputrec->nwall", -1, ir1->nwall, ir2->nwall);
+    cmp_int(fp, "inputrec->wall_type", -1, ir1->wall_type, ir2->wall_type);
+    cmp_int(fp, "inputrec->wall_atomtype[0]", -1, ir1->wall_atomtype[0], ir2->wall_atomtype[0]);
+    cmp_int(fp, "inputrec->wall_atomtype[1]", -1, ir1->wall_atomtype[1], ir2->wall_atomtype[1]);
+    cmp_real(fp, "inputrec->wall_density[0]", -1, ir1->wall_density[0], ir2->wall_density[0], ftol, abstol);
+    cmp_real(fp, "inputrec->wall_density[1]", -1, ir1->wall_density[1], ir2->wall_density[1], ftol, abstol);
+    cmp_real(fp, "inputrec->wall_ewald_zfac", -1, ir1->wall_ewald_zfac, ir2->wall_ewald_zfac, ftol, abstol);
+
+    cmp_bool(fp, "inputrec->bPull", -1, ir1->bPull, ir2->bPull);
+    if (ir1->bPull && ir2->bPull)
+    {
+        cmp_pull(fp);
+    }
+
+    cmp_int(fp, "inputrec->eDisre", -1, ir1->eDisre, ir2->eDisre);
+    cmp_real(fp, "inputrec->dr_fc", -1, ir1->dr_fc, ir2->dr_fc, ftol, abstol);
+    cmp_int(fp, "inputrec->eDisreWeighting", -1, ir1->eDisreWeighting, ir2->eDisreWeighting);
+    cmp_int(fp, "inputrec->bDisreMixed", -1, ir1->bDisreMixed, ir2->bDisreMixed);
+    cmp_int(fp, "inputrec->nstdisreout", -1, ir1->nstdisreout, ir2->nstdisreout);
+    cmp_real(fp, "inputrec->dr_tau", -1, ir1->dr_tau, ir2->dr_tau, ftol, abstol);
+    cmp_real(fp, "inputrec->orires_fc", -1, ir1->orires_fc, ir2->orires_fc, ftol, abstol);
+    cmp_real(fp, "inputrec->orires_tau", -1, ir1->orires_tau, ir2->orires_tau, ftol, abstol);
+    cmp_int(fp, "inputrec->nstorireout", -1, ir1->nstorireout, ir2->nstorireout);
+    cmp_real(fp, "inputrec->em_stepsize", -1, ir1->em_stepsize, ir2->em_stepsize, ftol, abstol);
+    cmp_real(fp, "inputrec->em_tol", -1, ir1->em_tol, ir2->em_tol, ftol, abstol);
+    cmp_int(fp, "inputrec->niter", -1, ir1->niter, ir2->niter);
+    cmp_real(fp, "inputrec->fc_stepsize", -1, ir1->fc_stepsize, ir2->fc_stepsize, ftol, abstol);
+    cmp_int(fp, "inputrec->nstcgsteep", -1, ir1->nstcgsteep, ir2->nstcgsteep);
+    cmp_int(fp, "inputrec->nbfgscorr", 0, ir1->nbfgscorr, ir2->nbfgscorr);
+    cmp_int(fp, "inputrec->eConstrAlg", -1, ir1->eConstrAlg, ir2->eConstrAlg);
+    cmp_int(fp, "inputrec->nProjOrder", -1, ir1->nProjOrder, ir2->nProjOrder);
+    cmp_real(fp, "inputrec->LincsWarnAngle", -1, ir1->LincsWarnAngle, ir2->LincsWarnAngle, ftol, abstol);
+    cmp_int(fp, "inputrec->nLincsIter", -1, ir1->nLincsIter, ir2->nLincsIter);
+    cmp_real(fp, "inputrec->bd_fric", -1, ir1->bd_fric, ir2->bd_fric, ftol, abstol);
+    cmp_int64(fp, "inputrec->ld_seed", ir1->ld_seed, ir2->ld_seed);
+    cmp_real(fp, "inputrec->cos_accel", -1, ir1->cos_accel, ir2->cos_accel, ftol, abstol);
+    cmp_rvec(fp, "inputrec->deform(a)", -1, ir1->deform[XX], ir2->deform[XX], ftol, abstol);
+    cmp_rvec(fp, "inputrec->deform(b)", -1, ir1->deform[YY], ir2->deform[YY], ftol, abstol);
+    cmp_rvec(fp, "inputrec->deform(c)", -1, ir1->deform[ZZ], ir2->deform[ZZ], ftol, abstol);
+
+
+    cmp_int(fp, "inputrec->userint1", -1, ir1->userint1, ir2->userint1);
+    cmp_int(fp, "inputrec->userint2", -1, ir1->userint2, ir2->userint2);
+    cmp_int(fp, "inputrec->userint3", -1, ir1->userint3, ir2->userint3);
+    cmp_int(fp, "inputrec->userint4", -1, ir1->userint4, ir2->userint4);
+    cmp_real(fp, "inputrec->userreal1", -1, ir1->userreal1, ir2->userreal1, ftol, abstol);
+    cmp_real(fp, "inputrec->userreal2", -1, ir1->userreal2, ir2->userreal2, ftol, abstol);
+    cmp_real(fp, "inputrec->userreal3", -1, ir1->userreal3, ir2->userreal3, ftol, abstol);
+    cmp_real(fp, "inputrec->userreal4", -1, ir1->userreal4, ir2->userreal4, ftol, abstol);
+    cmp_grpopts(fp, &(ir1->opts), &(ir2->opts), ftol, abstol);
+    cmp_cosines(fp, "ex", ir1->ex, ir2->ex, ftol, abstol);
+    cmp_cosines(fp, "et", ir1->et, ir2->et, ftol, abstol);
+}
+
+void comp_pull_AB(FILE *fp, pull_params_t *pull, real ftol, real abstol)
+{
+    int i;
+
+    for (i = 0; i < pull->ncoord; i++)
+    {
+        fprintf(fp, "comparing pull coord %d\n", i);
+        cmp_real(fp, "pull-coord->k", -1, pull->coord[i].k, pull->coord[i].kB, ftol, abstol);
+    }
+}
+
 gmx_bool inputrecDeform(const t_inputrec *ir)
 {
     return (ir->deform[XX][XX] != 0 || ir->deform[YY][YY] != 0 || ir->deform[ZZ][ZZ] != 0 ||
index 2f898195b257665cc6f7f086481f7734d70d1842..897c0d90a587b9fe4342957eea7eda5fff0925cd 100644 (file)
@@ -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, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, 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.
@@ -50,6 +50,8 @@
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
+struct pull_params_t;
+
 typedef struct {
     //! Number of terms
     int   n;
@@ -247,7 +249,8 @@ typedef struct t_swapcoords {
                                             * swapcoords.cpp                               */
 } t_swapcoords;
 
-typedef struct t_inputrec {
+struct t_inputrec
+{
     int             eI;                      /* Integration method                 */
     gmx_int64_t     nsteps;                  /* number of steps to be taken                    */
     int             simulation_part;         /* Used in checkpointing to separate chunks */
@@ -398,7 +401,7 @@ typedef struct t_inputrec {
     /* Fields for removed features go here (better caching) */
     gmx_bool        bAdress;       // Whether AdResS is enabled - always false if a valid .tpr was read
     gmx_bool        useTwinRange;  // Whether twin-range scheme is active - always false if a valid .tpr was read
-} t_inputrec;
+};
 
 int ir_optimal_nstcalcenergy(const t_inputrec *ir);
 
@@ -436,14 +439,6 @@ gmx_bool ir_vdw_is_zero_at_cutoff(const t_inputrec *ir);
  */
 gmx_bool ir_vdw_might_be_zero_at_cutoff(const t_inputrec *ir);
 
-/*! \brief Initiate input record structure
- *
- * Initialiazes all the arrays and pointers to NULL.
- *
- * \param[in] ir Inputrec must be pre-allocated
- */
-void init_inputrec(t_inputrec *ir);
-
 /*! \brief Free memory from input record.
  *
  * All arrays and pointers will be freed.
@@ -455,6 +450,11 @@ void done_inputrec(t_inputrec *ir);
 void pr_inputrec(FILE *fp, int indent, const char *title, const t_inputrec *ir,
                  gmx_bool bMDPformat);
 
+void cmp_inputrec(FILE *fp, const t_inputrec *ir1, const t_inputrec *ir2, real ftol, real abstol);
+
+void comp_pull_AB(FILE *fp, pull_params_t *pull, real ftol, real abstol);
+
+
 gmx_bool inputrecDeform(const t_inputrec *ir);
 
 gmx_bool inputrecDynamicBox(const t_inputrec *ir);
index 3bcf9a8987984528d83ac6097be997458624ae8b..206940317072616a3bfe8051be2919632b572cb4 100644 (file)
@@ -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, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, 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.
 #include <algorithm>
 
 #include "gromacs/math/vec.h"
+#include "gromacs/math/veccompare.h"
 #include "gromacs/mdtypes/df_history.h"
 #include "gromacs/mdtypes/energyhistory.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
+#include "gromacs/utility/compare.h"
 #include "gromacs/utility/smalloc.h"
 
 /* The source code in this file should be thread-safe.
@@ -147,7 +149,7 @@ void init_gtc_state(t_state *state, int ngtc, int nnhpres, int nhchainlength)
 }
 
 
-void init_state(t_state *state, int natoms, int ngtc, int nnhpres, int nhchainlength, int nlambda)
+void init_state(t_state *state, int natoms, int ngtc, int nnhpres, int nhchainlength, int dfhistNumLambda)
 {
     int i;
 
@@ -187,8 +189,17 @@ void init_state(t_state *state, int natoms, int ngtc, int nnhpres, int nhchainle
     zero_ekinstate(&state->ekinstate);
     snew(state->enerhist, 1);
     init_energyhistory(state->enerhist);
-    init_df_history(&state->dfhist, nlambda);
-    init_swapstate(&state->swapstate);
+    if (dfhistNumLambda > 0)
+    {
+        snew(state->dfhist, 1);
+        init_df_history(state->dfhist, dfhistNumLambda);
+    }
+    else
+    {
+        state->dfhist = NULL;
+    }
+    state->swapstate       = NULL;
+    state->edsamstate      = NULL;
     state->ddp_count       = 0;
     state->ddp_count_cg_gl = 0;
     state->cg_gl           = NULL;
@@ -197,28 +208,14 @@ void init_state(t_state *state, int natoms, int ngtc, int nnhpres, int nhchainle
 
 void done_state(t_state *state)
 {
-    if (state->x)
-    {
-        sfree(state->x);
-    }
-    if (state->v)
-    {
-        sfree(state->v);
-    }
-    if (state->cg_p)
-    {
-        sfree(state->cg_p);
-    }
+    sfree(state->x);
+    sfree(state->v);
+    sfree(state->cg_p);
+    sfree(state->enerhist);
     state->nalloc = 0;
-    if (state->cg_gl)
-    {
-        sfree(state->cg_gl);
-    }
+    sfree(state->cg_gl);
     state->cg_gl_nalloc = 0;
-    if (state->lambda)
-    {
-        sfree(state->lambda);
-    }
+    sfree(state->lambda);
     if (state->ngtc > 0)
     {
         sfree(state->nosehoover_xi);
@@ -245,3 +242,75 @@ t_state *serial_init_local_state(t_state *state_global)
 
     return state_local;
 }
+
+void comp_state(const t_state *st1, const t_state *st2,
+                gmx_bool bRMSD, real ftol, real abstol)
+{
+    int i, j, nc;
+
+    fprintf(stdout, "comparing flags\n");
+    cmp_int(stdout, "flags", -1, st1->flags, st2->flags);
+    fprintf(stdout, "comparing box\n");
+    cmp_rvecs(stdout, "box", DIM, st1->box, st2->box, FALSE, ftol, abstol);
+    fprintf(stdout, "comparing box_rel\n");
+    cmp_rvecs(stdout, "box_rel", DIM, st1->box_rel, st2->box_rel, FALSE, ftol, abstol);
+    fprintf(stdout, "comparing boxv\n");
+    cmp_rvecs(stdout, "boxv", DIM, st1->boxv, st2->boxv, FALSE, ftol, abstol);
+    if (st1->flags & (1<<estSVIR_PREV))
+    {
+        fprintf(stdout, "comparing shake vir_prev\n");
+        cmp_rvecs(stdout, "svir_prev", DIM, st1->svir_prev, st2->svir_prev, FALSE, ftol, abstol);
+    }
+    if (st1->flags & (1<<estFVIR_PREV))
+    {
+        fprintf(stdout, "comparing force vir_prev\n");
+        cmp_rvecs(stdout, "fvir_prev", DIM, st1->fvir_prev, st2->fvir_prev, FALSE, ftol, abstol);
+    }
+    if (st1->flags & (1<<estPRES_PREV))
+    {
+        fprintf(stdout, "comparing prev_pres\n");
+        cmp_rvecs(stdout, "pres_prev", DIM, st1->pres_prev, st2->pres_prev, FALSE, ftol, abstol);
+    }
+    cmp_int(stdout, "ngtc", -1, st1->ngtc, st2->ngtc);
+    cmp_int(stdout, "nhchainlength", -1, st1->nhchainlength, st2->nhchainlength);
+    if (st1->ngtc == st2->ngtc && st1->nhchainlength == st2->nhchainlength)
+    {
+        for (i = 0; i < st1->ngtc; i++)
+        {
+            nc = i*st1->nhchainlength;
+            for (j = 0; j < nc; j++)
+            {
+                cmp_real(stdout, "nosehoover_xi",
+                         i, st1->nosehoover_xi[nc+j], st2->nosehoover_xi[nc+j], ftol, abstol);
+            }
+        }
+    }
+    cmp_int(stdout, "nnhpres", -1, st1->nnhpres, st2->nnhpres);
+    if (st1->nnhpres == st2->nnhpres && st1->nhchainlength == st2->nhchainlength)
+    {
+        for (i = 0; i < st1->nnhpres; i++)
+        {
+            nc = i*st1->nhchainlength;
+            for (j = 0; j < nc; j++)
+            {
+                cmp_real(stdout, "nosehoover_xi",
+                         i, st1->nhpres_xi[nc+j], st2->nhpres_xi[nc+j], ftol, abstol);
+            }
+        }
+    }
+
+    cmp_int(stdout, "natoms", -1, st1->natoms, st2->natoms);
+    if (st1->natoms == st2->natoms)
+    {
+        if ((st1->flags & (1<<estX)) && (st2->flags & (1<<estX)))
+        {
+            fprintf(stdout, "comparing x\n");
+            cmp_rvecs(stdout, "x", st1->natoms, st1->x, st2->x, bRMSD, ftol, abstol);
+        }
+        if ((st1->flags & (1<<estV)) && (st2->flags & (1<<estV)))
+        {
+            fprintf(stdout, "comparing v\n");
+            cmp_rvecs(stdout, "v", st1->natoms, st1->v, st2->v, bRMSD, ftol, abstol);
+        }
+    }
+}
index 5d7b199640cdaca6b668655edd0efce10cd07dba..bbd87971102e088b7724e573ca2c3a8ebc76e74b 100644 (file)
@@ -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, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, 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.
@@ -223,9 +223,9 @@ typedef struct t_state
     ekinstate_t             ekinstate;       /* The state of the kinetic energy data      */
 
     struct energyhistory_t *enerhist;        /* Energy history for statistics           */
-    swapstate_t             swapstate;       /* Position swapping                       */
-    df_history_t            dfhist;          /*Free energy history for free energy analysis  */
-    edsamstate_t            edsamstate;      /* Essential dynamics / flooding history */
+    swapstate_t            *swapstate;       /* Position swapping                       */
+    df_history_t           *dfhist;          /*Free energy history for free energy analysis  */
+    edsamstate_t           *edsamstate;      /* Essential dynamics / flooding history */
 
     int                     ddp_count;       /* The DD partitioning count for this state  */
     int                     ddp_count_cg_gl; /* The DD part. count for index_gl     */
@@ -255,10 +255,12 @@ typedef struct
 
 void init_gtc_state(t_state *state, int ngtc, int nnhpres, int nhchainlength);
 
-void init_state(t_state *state, int natoms, int ngtc, int nnhpres, int nhchainlength, int nlambda);
+void init_state(t_state *state, int natoms, int ngtc, int nnhpres, int nhchainlength, int dfhistNumLambda);
 
 t_state *serial_init_local_state(t_state *state_global);
 
 void done_state(t_state *state);
 
+void comp_state(const t_state *st1, const t_state *st2, gmx_bool bRMSD, real ftol, real abstol);
+
 #endif
index e5f7212393d66871c6804010df9e76efa066ef30..2648150a59626b8727a697d77bab56ee3f8419d2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2016, 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.
@@ -229,7 +229,7 @@ void TextTableFormatter::addColumn(const char *title, int width, bool bWrap)
     {
         impl_->bPrintHeader_ = true;
     }
-    impl_->columns_.push_back(Impl::ColumnData(title, width, bWrap));
+    impl_->columns_.emplace_back(title, width, bWrap);
 }
 
 void TextTableFormatter::setFirstColumnIndent(int indent)
@@ -341,7 +341,7 @@ std::string TextTableFormatter::formatRow()
                 {
                     if (overflow > columnWidth && column->bWrap_)
                     {
-                        columnLines.push_back(std::string());
+                        columnLines.emplace_back();
                         continue;
                     }
                     columnWidth -= overflow;
index 2e5a578cb4ed2c8ea7729d6dabc07d6ad15984f2..5e7e3a7d9cc8281a435c4a0564cf4a56f1e01eab 100644 (file)
@@ -409,7 +409,7 @@ void HelpLinks::addLink(const std::string &linkName,
         default:
             GMX_RELEASE_ASSERT(false, "Output format not implemented for links");
     }
-    impl_->links_.push_back(Impl::LinkItem(linkName, replacement));
+    impl_->links_.emplace_back(linkName, replacement);
 }
 
 /********************************************************************
@@ -508,7 +508,7 @@ class HelpWriterContext::Impl
         void addReplacement(const std::string &search,
                             const std::string &replace)
         {
-            replacements_.push_back(ReplaceItem(search, replace));
+            replacements_.emplace_back(search, replace);
         }
 
         //! Replaces links in a given string.
index 0d7a3842f8700d6929a57b6e0589991395ec1e0b..1fb607a319ef12dbc849fa2a6b71a1a95844d14d 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2012,2014,2015, by the GROMACS development team, led by
+# Copyright (c) 2012,2014,2015,2016, 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.
 gmx_add_unit_test_object_library(onlinehelp-test-shared
                                  mock_helptopic.cpp)
 
-if (CMAKE_CXX_COMPILER_ID MATCHES "XL")
-    # This suppression stops a very verbose cascade of messages about the
-    # mocks, which is probably a compiler issue.
-    #   1540-2924 (W) Cannot pass an argument of non-POD class type "const gmx::HelpWriterContext" through ellipsis.
-    set_property(SOURCE mock_helptopic.cpp PROPERTY COMPILE_FLAGS "-qsuppress=1540-2924")
-endif()
-
 gmx_add_unit_test(OnlineHelpUnitTests onlinehelp-test
                   helpformat.cpp
                   helpmanager.cpp
index 62d006445c347feef7dba88995e2ca6ceabe13e2..172f357b55feabd68e28109c1e5a487fd3431a9d 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2010,2012,2013,2014,2015, by the GROMACS development team, led by
+# Copyright (c) 2010,2012,2013,2014,2015,2016, 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.
 
-file(GLOB OPTIONS_SOURCES *.cpp)
-set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${OPTIONS_SOURCES} PARENT_SCOPE)
+gmx_add_libgromacs_sources(
+    abstractoption.cpp
+    abstractsection.cpp
+    basicoptions.cpp
+    behaviorcollection.cpp
+    filenameoption.cpp
+    filenameoptionmanager.cpp
+    options.cpp
+    optionsassigner.cpp
+    optionsection.cpp
+    optionsvisitor.cpp
+    timeunitmanager.cpp
+    treesupport.cpp
+    )
 
 gmx_install_headers(
     abstractoption.h
+    abstractsection.h
     basicoptions.h
     filenameoption.h
     filenameoptionmanager.h
     ioptionsbehavior.h
     ioptionscontainer.h
+    ioptionscontainerwithsections.h
+    isectionstorage.h
+    ivaluestore.h
     optionfiletype.h
     optionflags.h
     options.h
+    optionsection.h
+    repeatingsection.h
     timeunitmanager.h
+    valuestore.h
     )
 
 if (BUILD_TESTING)
index 25d4ecab83908f7edc85c28bb40820dfcd61fe3f..b35eafd1cca8fb68ffa55f5823998872c2e402cf 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -47,6 +47,7 @@
 #include "gromacs/options/optionflags.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/variant.h"
 
 #include "basicoptionstorage.h"
 
@@ -116,14 +117,14 @@ void AbstractOptionStorage::startSet()
     bSetValuesHadErrors_ = false;
 }
 
-void AbstractOptionStorage::appendValue(const std::string &value)
+void AbstractOptionStorage::appendValue(const Variant &value)
 {
     GMX_RELEASE_ASSERT(bInSet_, "startSet() not called");
     try
     {
         convertValue(value);
     }
-    catch (...)
+    catch (const std::exception &)
     {
         bSetValuesHadErrors_ = true;
         throw;
index ff8a2596865374f82d1ba577d3ca34e934f16c09..fc1723cea59d86f884d7ad0e317209ac5c117d1b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, 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.
@@ -69,7 +69,7 @@ class OptionManagerContainer;
 
 namespace internal
 {
-class OptionsImpl;
+class OptionSectionImpl;
 }
 
 /*! \brief
@@ -198,7 +198,7 @@ class AbstractOption
          */
         friend class AbstractOptionStorage;
         //! Needed to be able to call createStorage().
-        friend class internal::OptionsImpl;
+        friend class internal::OptionSectionImpl;
 };
 
 /*! \brief
index 55ea22fd261cb7219fe70c8f2b948bf05dace184..889614542662b3821df0984df5dd76a2ab27d3d6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2014,2015,2016, 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.
@@ -54,6 +54,7 @@ namespace gmx
 class AbstractOption;
 class OptionInfo;
 class Options;
+class Variant;
 
 /*! \libinternal \brief
  * Abstract base class for converting, validating, and storing option values.
@@ -171,16 +172,16 @@ class AbstractOptionStorage
          */
         void startSet();
         /*! \brief
-         * Adds a new value for the option, converting it from a string.
+         * Adds a new value for the option.
          *
-         * \param[in] value  String value to convert.
+         * \param[in] value  Value to convert.
          * \throws  InvalidInputError if value cannot be converted, or
          *      if there are too many values.
          *
          * This method should only be called between startSet() and
          * finishSet().
          */
-        void appendValue(const std::string &value);
+        void appendValue(const Variant &value);
         /*! \brief
          * Performs validation and/or actions once a set of values has been
          * added.
@@ -270,9 +271,9 @@ class AbstractOptionStorage
          */
         virtual void clearSet() = 0;
         /*! \brief
-         * Adds a new value, converting it from a string.
+         * Adds a new value.
          *
-         * \param[in] value  String value to convert.
+         * \param[in] value  Value to convert.
          * \throws  InvalidInputError if \p value is not valid for this option
          *      or if there have been too many values in the set.
          *
@@ -281,7 +282,7 @@ class AbstractOptionStorage
          *
          * \see OptionStorageTemplate::convertValue()
          */
-        virtual void convertValue(const std::string &value) = 0;
+        virtual void convertValue(const Variant &value) = 0;
         /*! \brief
          * Performs validation and/or actions once a set of values has been
          * added.
diff --git a/src/gromacs/options/abstractsection.cpp b/src/gromacs/options/abstractsection.cpp
new file mode 100644 (file)
index 0000000..5dd1ede
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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.
+ */
+/*! \internal \file
+ * \brief
+ * Implements classes from abstractsection.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_options
+ */
+#include "gmxpre.h"
+
+#include "abstractsection.h"
+
+#include "options-impl.h"
+
+namespace gmx
+{
+
+// static
+IOptionSectionStorage *
+AbstractOptionSectionHandle::getStorage(internal::OptionSectionImpl *section)
+{
+    return section->storage_.get();
+}
+
+IOptionsContainer &AbstractOptionSectionHandle::addGroup()
+{
+    return section_->addGroup();
+}
+
+internal::OptionSectionImpl *
+AbstractOptionSectionHandle::addSectionImpl(const AbstractOptionSection &section)
+{
+    return section_->addSectionImpl(section);
+}
+
+OptionInfo *AbstractOptionSectionHandle::addOptionImpl(const AbstractOption &settings)
+{
+    return section_->addOptionImpl(settings);
+}
+
+} // namespace gmx
diff --git a/src/gromacs/options/abstractsection.h b/src/gromacs/options/abstractsection.h
new file mode 100644 (file)
index 0000000..049df53
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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.
+ */
+/*! \file
+ * \brief
+ * Declares base classes for declaring option sections.
+ *
+ * This header defines base classes for option section settings that are used
+ * with IOptionsContainerWithSections::addSection().  These classes implement
+ * the "named parameter" idiom for specifying section properties.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_ABSTRACTSECTION_H
+#define GMX_OPTIONS_ABSTRACTSECTION_H
+
+#include "gromacs/options/ioptionscontainerwithsections.h"
+#include "gromacs/options/isectionstorage.h"
+#include "gromacs/utility/classhelpers.h"
+#include "gromacs/utility/gmxassert.h"
+
+namespace gmx
+{
+
+class IOptionSectionStorage;
+
+namespace internal
+{
+class OptionSectionImpl;
+}
+
+/*! \brief
+ * Base class for specifying option section properties.
+ *
+ * \ingroup module_options
+ */
+class AbstractOptionSection
+{
+    protected:
+        //! \cond libapi
+        //! Initializes option properties with the given name.
+        explicit AbstractOptionSection(const char *name) : name_(name) {}
+
+        /*! \brief
+         * Creates a storage object corresponding to this section.
+         *
+         * Similar to AbstractOption::createStorage().
+         */
+        virtual IOptionSectionStorage *createStorage() const = 0;
+        //! \endcond
+
+    private:
+        const char *name_;
+
+        friend class internal::OptionSectionImpl;
+};
+
+/*! \brief
+ * Base class for handles to option sections.
+ *
+ * This class implements the common functionality for adding options and
+ * subsections to option sections.
+ *
+ * \ingroup module_options
+ */
+class AbstractOptionSectionHandle : public IOptionsContainerWithSections
+{
+    public:
+        // From IOptionsContainer
+        //! \copydoc IOptionsContainer::addGroup()
+        virtual IOptionsContainer &addGroup();
+
+    protected:
+        //! \cond libapi
+        /*! \brief
+         * Returns the storage for a particular type of section.
+         *
+         * This is intended for use in derived class constructors, where the
+         * handle needs access to the actual storage.  The handle should know
+         * the type of storage created for the section type it deals with, so
+         * the cast should always be successful.
+         */
+        template <typename StorageType>
+        static StorageType *getStorage(internal::OptionSectionImpl *section)
+        {
+            IOptionSectionStorage *storage = getStorage(section);
+            StorageType           *typedStorage
+                = dynamic_cast<StorageType *>(storage);
+            GMX_ASSERT(typedStorage != nullptr, "Mismatching section storage type");
+            return typedStorage;
+        }
+
+        //! Wraps a given section storage object.
+        explicit AbstractOptionSectionHandle(internal::OptionSectionImpl *section)
+            : section_(section)
+        {
+        }
+        //! \endcond
+
+    private:
+        // From IOptionsContainerWithSections
+        virtual internal::OptionSectionImpl *
+        addSectionImpl(const AbstractOptionSection &section);
+        // From IOptionsContainer
+        virtual OptionInfo *addOptionImpl(const AbstractOption &settings);
+
+        /*! \brief
+         * Implementation helper for the template method.
+         *
+         * This allows encapsulating the implementation within the source file.
+         */
+        static IOptionSectionStorage *getStorage(internal::OptionSectionImpl *section);
+
+        internal::OptionSectionImpl *section_;
+};
+
+class AbstractOptionSectionInfo
+{
+    public:
+        //! Wraps a given section storage object.
+        explicit AbstractOptionSectionInfo(internal::OptionSectionImpl *section)
+            : section_(*section)
+        {
+        }
+
+        //! Returns the wrapped section storage object.
+        internal::OptionSectionImpl       &section() { return section_; }
+        //! Returns the wrapped section storage object.
+        const internal::OptionSectionImpl &section() const { return section_; }
+
+    private:
+        internal::OptionSectionImpl &section_;
+
+        GMX_DISALLOW_COPY_AND_ASSIGN(AbstractOptionSectionInfo);
+};
+
+} // namespace gmx
+
+#endif
index 1a09d40569fbd53474e2d370ef55982a5956613f..ceead73cf908daa0e90fff47b1eff62268903bc5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, 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.
@@ -54,6 +54,7 @@
 
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/strconvert.h"
 #include "gromacs/utility/stringutil.h"
 
 #include "basicoptionstorage.h"
@@ -140,20 +141,9 @@ std::string BooleanOptionStorage::formatSingleValue(const bool &value) const
     return value ? "yes" : "no";
 }
 
-void BooleanOptionStorage::convertValue(const std::string &value)
+void BooleanOptionStorage::initConverter(ConverterType *converter)
 {
-    // TODO: Case-independence
-    if (value == "1" || value == "yes" || value == "true")
-    {
-        addValue(true);
-        return;
-    }
-    else if (value == "0" || value == "no" || value == "false")
-    {
-        addValue(false);
-        return;
-    }
-    GMX_THROW(InvalidInputError("Invalid value: '" + value + "'; supported values are: 1, 0, yes, no, true, false"));
+    converter->addConverter<std::string>(&fromStdString<bool>);
 }
 
 /********************************************************************
@@ -195,25 +185,9 @@ std::string IntegerOptionStorage::formatSingleValue(const int &value) const
     return formatString("%d", value);
 }
 
-void IntegerOptionStorage::convertValue(const std::string &value)
+void IntegerOptionStorage::initConverter(ConverterType *converter)
 {
-    const char *ptr = value.c_str();
-    char       *endptr;
-    errno = 0;
-    long int    ival = std::strtol(ptr, &endptr, 10);
-    if (errno == ERANGE
-        || ival < std::numeric_limits<int>::min()
-        || ival > std::numeric_limits<int>::max())
-    {
-        GMX_THROW(InvalidInputError("Invalid value: '" + value
-                                    + "'; it causes an integer overflow"));
-    }
-    if (*ptr == '\0' || *endptr != '\0')
-    {
-        GMX_THROW(InvalidInputError("Invalid value: '" + value
-                                    + "'; expected an integer"));
-    }
-    addValue(ival);
+    converter->addConverter<std::string>(&fromStdString<int>);
 }
 
 void IntegerOptionStorage::processSetValues(ValueList *values)
@@ -253,23 +227,9 @@ std::string Int64OptionStorage::formatSingleValue(const gmx_int64_t &value) cons
     return formatString("%" GMX_PRId64, value);
 }
 
-void Int64OptionStorage::convertValue(const std::string &value)
+void Int64OptionStorage::initConverter(ConverterType *converter)
 {
-    const char       *ptr = value.c_str();
-    char             *endptr;
-    errno = 0;
-    const gmx_int64_t ival = str_to_int64_t(ptr, &endptr);
-    if (errno == ERANGE)
-    {
-        GMX_THROW(InvalidInputError("Invalid value: '" + value
-                                    + "'; it causes an integer overflow"));
-    }
-    if (*ptr == '\0' || *endptr != '\0')
-    {
-        GMX_THROW(InvalidInputError("Invalid value: '" + value
-                                    + "'; expected an integer"));
-    }
-    addValue(ival);
+    converter->addConverter<std::string>(&fromStdString<gmx_int64_t>);
 }
 
 /********************************************************************
@@ -311,23 +271,15 @@ std::string DoubleOptionStorage::formatSingleValue(const double &value) const
     return formatString("%g", value / factor_);
 }
 
-void DoubleOptionStorage::convertValue(const std::string &value)
+void DoubleOptionStorage::initConverter(ConverterType *converter)
 {
-    const char *ptr = value.c_str();
-    char       *endptr;
-    errno = 0;
-    double      dval = std::strtod(ptr, &endptr);
-    if (errno == ERANGE)
-    {
-        GMX_THROW(InvalidInputError("Invalid value: '" + value
-                                    + "'; it causes an overflow/underflow"));
-    }
-    if (*ptr == '\0' || *endptr != '\0')
-    {
-        GMX_THROW(InvalidInputError("Invalid value: '" + value
-                                    + "'; expected a number"));
-    }
-    addValue(dval * factor_);
+    converter->addConverter<std::string>(&fromStdString<double>);
+}
+
+double DoubleOptionStorage::processValue(const double &value)
+{
+    // TODO: Consider testing for overflow when scaling with factor_.
+    return value * factor_;
 }
 
 void DoubleOptionStorage::processSetValues(ValueList *values)
@@ -343,13 +295,11 @@ void DoubleOptionStorage::setScaleFactor(double factor)
     GMX_RELEASE_ASSERT(factor > 0.0, "Invalid scaling factor");
     if (!hasFlag(efOption_HasDefaultValue))
     {
-        double              scale = factor / factor_;
-        ValueList::iterator i;
-        for (i = values().begin(); i != values().end(); ++i)
+        double scale = factor / factor_;
+        for (double &value : values())
         {
-            (*i) *= scale;
+            value *= scale;
         }
-        refreshValues();
     }
     factor_ = factor;
 }
@@ -413,25 +363,15 @@ std::string FloatOptionStorage::formatSingleValue(const float &value) const
     return formatString("%g", value / factor_);
 }
 
-void FloatOptionStorage::convertValue(const std::string &value)
+void FloatOptionStorage::initConverter(ConverterType *converter)
 {
-    const char *ptr = value.c_str();
-    char       *endptr;
-    errno = 0;
-    double      dval = std::strtod(ptr, &endptr);
-    if (errno == ERANGE
-        || dval * factor_ < -std::numeric_limits<float>::max()
-        || dval * factor_ >  std::numeric_limits<float>::max())
-    {
-        GMX_THROW(InvalidInputError("Invalid value: '" + value
-                                    + "'; it causes an overflow/underflow"));
-    }
-    if (*ptr == '\0' || *endptr != '\0')
-    {
-        GMX_THROW(InvalidInputError("Invalid value: '" + value
-                                    + "'; expected a number"));
-    }
-    addValue(dval * factor_);
+    converter->addConverter<std::string>(&fromStdString<float>);
+}
+
+float FloatOptionStorage::processValue(const float &value)
+{
+    // TODO: Consider testing for overflow when scaling with factor_.
+    return value * factor_;
 }
 
 void FloatOptionStorage::processSetValues(ValueList *values)
@@ -447,13 +387,11 @@ void FloatOptionStorage::setScaleFactor(double factor)
     GMX_RELEASE_ASSERT(factor > 0.0, "Invalid scaling factor");
     if (!hasFlag(efOption_HasDefaultValue))
     {
-        double              scale = factor / factor_;
-        ValueList::iterator i;
-        for (i = values().begin(); i != values().end(); ++i)
+        float scale = factor / factor_;
+        for (float &value : values())
         {
-            (*i) *= scale;
+            value *= scale;
         }
-        refreshValues();
     }
     factor_ = factor;
 }
@@ -526,7 +464,7 @@ StringOptionStorage::StringOptionStorage(const StringOption &settings)
             {
                 GMX_THROW(APIError("Enumeration value cannot be NULL"));
             }
-            allowed_.push_back(settings.enumValues_[i]);
+            allowed_.emplace_back(settings.enumValues_[i]);
         }
         if (settings.defaultEnumIndex_ >= 0)
         {
@@ -539,9 +477,7 @@ StringOptionStorage::StringOptionStorage(const StringOption &settings)
             {
                 GMX_THROW(APIError("Conflicting default values"));
             }
-            clear();
-            addValue(allowed_[settings.defaultEnumIndex_]);
-            commitValues();
+            setDefaultValue(allowed_[settings.defaultEnumIndex_]);
         }
     }
 }
@@ -562,17 +498,17 @@ std::string StringOptionStorage::formatSingleValue(const std::string &value) con
     return value;
 }
 
-void StringOptionStorage::convertValue(const std::string &value)
+void StringOptionStorage::initConverter(ConverterType * /*converter*/)
 {
-    if (allowed_.size() == 0)
-    {
-        addValue(value);
-    }
-    else
+}
+
+std::string StringOptionStorage::processValue(const std::string &value)
+{
+    if (allowed_.size() > 0)
     {
-        ValueList::const_iterator match = findEnumValue(allowed_, value);
-        addValue(*match);
+        return *findEnumValue(this->allowed_, value);
     }
+    return value;
 }
 
 /********************************************************************
@@ -617,8 +553,8 @@ StringOption::createStorage(const OptionManagerContainer & /*managers*/) const
 EnumOptionStorage::EnumOptionStorage(const AbstractOption &settings,
                                      const char *const *enumValues, int count,
                                      int defaultValue, int defaultValueIfSet,
-                                     EnumIndexStorePointer store)
-    : MyBase(settings), info_(this), store_(move(store))
+                                     StorePointer store)
+    : MyBase(settings, std::move(store)), info_(this)
 {
     if (enumValues == NULL)
     {
@@ -639,7 +575,7 @@ EnumOptionStorage::EnumOptionStorage(const AbstractOption &settings,
         {
             GMX_THROW(APIError("Enumeration value cannot be NULL"));
         }
-        allowed_.push_back(enumValues[i]);
+        allowed_.emplace_back(enumValues[i]);
     }
 
     GMX_ASSERT(defaultValue < count, "Default enumeration value is out of range");
@@ -653,12 +589,6 @@ EnumOptionStorage::EnumOptionStorage(const AbstractOption &settings,
     {
         setDefaultValueIfSet(defaultValueIfSet);
     }
-
-    if (values().empty())
-    {
-        values() = store_->initialValues();
-    }
-    refreshEnumIndexStore();
 }
 
 std::string EnumOptionStorage::formatExtraDescription() const
@@ -678,28 +608,13 @@ std::string EnumOptionStorage::formatSingleValue(const int &value) const
     return allowed_[value];
 }
 
-void EnumOptionStorage::convertValue(const std::string &value)
-{
-    std::vector<std::string>::const_iterator match = findEnumValue(allowed_, value);
-    addValue(match - allowed_.begin());
-}
-
-void EnumOptionStorage::processSetValues(ValueList *values)
-{
-    const size_t newSize = (hasFlag(efOption_ClearOnNextSet) ? 0 : valueCount())
-        + std::max<size_t>(values->size(), 1);
-    store_->reserveSpace(newSize);
-}
-
-void EnumOptionStorage::refreshValues()
-{
-    MyBase::refreshValues();
-    refreshEnumIndexStore();
-}
-
-void EnumOptionStorage::refreshEnumIndexStore()
+void EnumOptionStorage::initConverter(ConverterType *converter)
 {
-    store_->refreshValues(values());
+    converter->addConverter<std::string>(
+            [this] (const std::string &value)
+            {
+                return findEnumValue(this->allowed_, value) - this->allowed_.begin();
+            });
 }
 
 /********************************************************************
@@ -728,18 +643,14 @@ const std::vector<std::string> &EnumOptionInfo::allowedValues() const
 namespace internal
 {
 
-EnumIndexStoreInterface::~EnumIndexStoreInterface()
-{
-}
-
 //! \cond internal
 AbstractOptionStorage *
 createEnumOptionStorage(const AbstractOption &option,
                         const char *const *enumValues, int count,
                         int defaultValue, int defaultValueIfSet,
-                        EnumIndexStoreInterface *store)
+                        IOptionValueStore<int> *store)
 {
-    EnumOptionStorage::EnumIndexStorePointer storePtr(store);
+    std::unique_ptr<IOptionValueStore<int> > storePtr(store);
     return new EnumOptionStorage(option, enumValues, count, defaultValue,
                                  defaultValueIfSet, move(storePtr));
 }
index 257cf5100eb14f55ecbaa36c6fa888826001378c..0976f2bcb477e134a3bfa123d69025ce58df7629 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, 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.
@@ -50,6 +50,8 @@
 #include <vector>
 
 #include "gromacs/options/abstractoption.h"
+#include "gromacs/options/ivaluestore.h"
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/gmxassert.h"
 
@@ -376,97 +378,72 @@ namespace internal
 
 /*! \internal
  * \brief
- * Interface for handling storage of the enum indexes.
- *
- * This interface acts as a proxy between the EnumOptionStorage class (that
- * operates on `int` values), and the actual enum variable that receives the
- * values.  The implementation of this interface takes care of conversion of
- * the values and writing them out into the actual enum variables.
- *
- * \ingroup module_options
- */
-class EnumIndexStoreInterface
-{
-    public:
-        virtual ~EnumIndexStoreInterface();
-
-        //! Returns initial values from the actual enum variables.
-        virtual std::vector<int> initialValues() const = 0;
-        //! Reserves space for storage in the actual enum variables.
-        virtual void reserveSpace(size_t count) = 0;
-        //! Updates values in the actual enum variables based on option values.
-        virtual void refreshValues(const std::vector<int> &values) = 0;
-};
-
-/*! \internal
- * \brief
- * Type-specific implementation for EnumIndexStoreInterface.
+ * Type-specific implementation for IOptionValueStore for an enum option.
  *
  * This class is instantiated for each enum type for which EnumOption is used,
- * and takes care of managing the `int`-to-`enum` conversions as described in
- * EnumIndexStoreInterface.  Having this as a template in the header allows the
- * actual storage implementation to not be in the header, which would require
- * exposing all the internals through this one header...
+ * and takes care of managing `int`-to-`enum` conversions.  Having this part in
+ * the header allows the actual storage implementation to not be in the header,
+ * which would require exposing all the internals through this one header...
  *
  * \ingroup module_options
  */
 template <typename EnumType>
-class EnumIndexStore : public EnumIndexStoreInterface
+class EnumIndexStore : public IOptionValueStore<int>
 {
     public:
         //! Initializes the storage for the given actual enum variables.
         EnumIndexStore(EnumType *store, std::vector<EnumType> *storeVector)
             : store_(store), storeVector_(storeVector)
         {
-        }
-
-        virtual std::vector<int> initialValues() const
-        {
-            std::vector<int> result;
-            if (storeVector_ != NULL)
+            if (storeVector_ != nullptr)
             {
-                typename std::vector<EnumType>::const_iterator i;
-                for (i = storeVector_->begin(); i != storeVector_->end(); ++i)
+                for (EnumType value : *storeVector_)
                 {
-                    result.push_back(*i);
+                    intStore_.push_back(static_cast<int>(value));
                 }
             }
-            else if (store_ != NULL)
+            else if (store_ != nullptr)
             {
                 // TODO: Copy more than one value if that would make sense.
-                result.push_back(store_[0]);
+                intStore_.push_back(static_cast<int>(store_[0]));
             }
-            return result;
         }
-        virtual void reserveSpace(size_t count)
+
+        virtual int valueCount() { return static_cast<int>(intStore_.size()); }
+        virtual ArrayRef<int> values() { return intStore_; }
+        virtual void clear()
         {
-            if (storeVector_ != NULL)
+            intStore_.clear();
+            if (storeVector_ != nullptr)
             {
-                storeVector_->reserve(count);
+                storeVector_->clear();
             }
         }
-        virtual void refreshValues(const std::vector<int> &values)
+        virtual void reserve(size_t count)
         {
-            if (store_ != NULL)
+            intStore_.reserve(intStore_.size() + count);
+            if (storeVector_ != nullptr)
             {
-                for (size_t i = 0; i < values.size(); ++i)
-                {
-                    store_[i] = static_cast<EnumType>(values[i]);
-                }
+                storeVector_->reserve(storeVector_->size() + count);
             }
-            if (storeVector_ != NULL)
+        }
+        virtual void append(const int &value)
+        {
+            const size_t count = intStore_.size();
+            intStore_.push_back(value);
+            if (store_ != nullptr)
             {
-                GMX_ASSERT(storeVector_->capacity() >= values.size(),
-                           "reserveSpace() should have been called earlier");
-                storeVector_->resize(values.size());
-                for (size_t i = 0; i < values.size(); ++i)
-                {
-                    (*storeVector_)[i] = static_cast<EnumType>(values[i]);
-                }
+                store_[count] = static_cast<EnumType>(value);
+            }
+            if (storeVector_ != nullptr)
+            {
+                storeVector_->push_back(static_cast<EnumType>(value));
             }
         }
 
     private:
+        //! Stores the integer values for values().
+        std::vector<int>       intStore_;
         EnumType              *store_;
         std::vector<EnumType> *storeVector_;
 };
@@ -486,7 +463,7 @@ AbstractOptionStorage *
 createEnumOptionStorage(const AbstractOption &option,
                         const char *const *enumValues, int count,
                         int defaultValue, int defaultValueIfSet,
-                        EnumIndexStoreInterface *store);
+                        IOptionValueStore<int> *store);
 //! \endcond
 
 }   // namespace internal
index a4aa6ead9f3c448bf6e9ac86f786dd171d4b5f21..e4ae7e3441df75d803fd11ddd7db5febcdf4a0c0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, 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.
@@ -59,7 +59,7 @@ namespace gmx
 /*! \internal \brief
  * Converts, validates, and stores boolean values.
  */
-class BooleanOptionStorage : public OptionStorageTemplate<bool>
+class BooleanOptionStorage : public OptionStorageTemplateSimple<bool>
 {
     public:
         /*! \brief
@@ -80,7 +80,7 @@ class BooleanOptionStorage : public OptionStorageTemplate<bool>
         bool defaultValue() const { return valueCount() > 0 && values()[0]; }
 
     private:
-        virtual void convertValue(const std::string &value);
+        virtual void initConverter(ConverterType *converter);
 
         BooleanOptionInfo       info_;
 };
@@ -88,7 +88,7 @@ class BooleanOptionStorage : public OptionStorageTemplate<bool>
 /*! \internal \brief
  * Converts, validates, and stores integer values.
  */
-class IntegerOptionStorage : public OptionStorageTemplate<int>
+class IntegerOptionStorage : public OptionStorageTemplateSimple<int>
 {
     public:
         //! \copydoc BooleanOptionStorage::BooleanOptionStorage()
@@ -103,7 +103,7 @@ class IntegerOptionStorage : public OptionStorageTemplate<int>
         virtual std::string formatSingleValue(const int &value) const;
 
     private:
-        virtual void convertValue(const std::string &value);
+        virtual void initConverter(ConverterType *converter);
         virtual void processSetValues(ValueList *values);
 
         IntegerOptionInfo       info_;
@@ -112,7 +112,7 @@ class IntegerOptionStorage : public OptionStorageTemplate<int>
 /*! \internal \brief
  * Converts, validates, and stores integer values.
  */
-class Int64OptionStorage : public OptionStorageTemplate<gmx_int64_t>
+class Int64OptionStorage : public OptionStorageTemplateSimple<gmx_int64_t>
 {
     public:
         //! \copydoc BooleanOptionStorage::BooleanOptionStorage()
@@ -126,7 +126,7 @@ class Int64OptionStorage : public OptionStorageTemplate<gmx_int64_t>
         virtual std::string formatSingleValue(const gmx_int64_t &value) const;
 
     private:
-        virtual void convertValue(const std::string &value);
+        virtual void initConverter(ConverterType *converter);
 
         Int64OptionInfo       info_;
 };
@@ -134,7 +134,7 @@ class Int64OptionStorage : public OptionStorageTemplate<gmx_int64_t>
 /*! \internal \brief
  * Converts, validates, and stores floating-point (double) values.
  */
-class DoubleOptionStorage : public OptionStorageTemplate<double>
+class DoubleOptionStorage : public OptionStorageTemplateSimple<double>
 {
     public:
         //! \copydoc IntegerOptionStorage::IntegerOptionStorage()
@@ -150,7 +150,8 @@ class DoubleOptionStorage : public OptionStorageTemplate<double>
         void setScaleFactor(double factor);
 
     private:
-        virtual void convertValue(const std::string &value);
+        virtual void initConverter(ConverterType *converter);
+        virtual double processValue(const double &value);
         virtual void processSetValues(ValueList *values);
 
         DoubleOptionInfo        info_;
@@ -161,7 +162,7 @@ class DoubleOptionStorage : public OptionStorageTemplate<double>
 /*! \internal \brief
  * Converts, validates, and stores floating-point (float) values.
  */
-class FloatOptionStorage : public OptionStorageTemplate<float>
+class FloatOptionStorage : public OptionStorageTemplateSimple<float>
 {
     public:
         //! \copydoc IntegerOptionStorage::IntegerOptionStorage()
@@ -177,7 +178,8 @@ class FloatOptionStorage : public OptionStorageTemplate<float>
         void setScaleFactor(double factor);
 
     private:
-        virtual void convertValue(const std::string &value);
+        virtual void initConverter(ConverterType *converter);
+        virtual float processValue(const float &value);
         virtual void processSetValues(ValueList *values);
 
         FloatOptionInfo         info_;
@@ -188,7 +190,7 @@ class FloatOptionStorage : public OptionStorageTemplate<float>
 /*! \internal \brief
  * Converts, validates, and stores string values.
  */
-class StringOptionStorage : public OptionStorageTemplate<std::string>
+class StringOptionStorage : public OptionStorageTemplateSimple<std::string>
 {
     public:
         //! \copydoc DoubleOptionStorage::DoubleOptionStorage()
@@ -204,7 +206,8 @@ class StringOptionStorage : public OptionStorageTemplate<std::string>
         const ValueList &allowedValues() const { return allowed_; }
 
     private:
-        virtual void convertValue(const std::string &value);
+        virtual void initConverter(ConverterType *converter);
+        virtual std::string processValue(const std::string &value);
 
         StringOptionInfo        info_;
         ValueList               allowed_;
@@ -213,13 +216,9 @@ class StringOptionStorage : public OptionStorageTemplate<std::string>
 /*! \internal \brief
  * Converts, validates, and stores enum values.
  */
-class EnumOptionStorage : public OptionStorageTemplate<int>
+class EnumOptionStorage : public OptionStorageTemplateSimple<int>
 {
     public:
-        //! Shorthand for the enum index storage interface.
-        typedef std::unique_ptr<internal::EnumIndexStoreInterface>
-            EnumIndexStorePointer;
-
         /*! \brief
          * Initializes the storage from option settings.
          *
@@ -239,7 +238,7 @@ class EnumOptionStorage : public OptionStorageTemplate<int>
         EnumOptionStorage(const AbstractOption &settings,
                           const char *const *enumValues, int count,
                           int defaultValue, int defaultValueIfSet,
-                          EnumIndexStorePointer store);
+                          StorePointer store);
 
         virtual OptionInfo &optionInfo() { return info_; }
         virtual std::string typeString() const { return "enum"; }
@@ -250,15 +249,10 @@ class EnumOptionStorage : public OptionStorageTemplate<int>
         const std::vector<std::string> &allowedValues() const { return allowed_; }
 
     private:
-        virtual void convertValue(const std::string &value);
-        virtual void processSetValues(ValueList *values);
-        virtual void refreshValues();
-
-        void refreshEnumIndexStore();
+        virtual void initConverter(ConverterType *converter);
 
         EnumOptionInfo            info_;
         std::vector<std::string>  allowed_;
-        EnumIndexStorePointer     store_;
 };
 
 /*!\}*/
index b793a934b50dc862e7556c0a360efa34b5dd6d05..a23b6469fae4adeb5f2df69130b84e6f09039786 100644 (file)
@@ -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
  * 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.
@@ -313,7 +313,11 @@ std::string FileNameOptionStorage::formatSingleValue(const std::string &value) c
     return value;
 }
 
-void FileNameOptionStorage::convertValue(const std::string &value)
+void FileNameOptionStorage::initConverter(ConverterType * /*converter*/)
+{
+}
+
+std::string FileNameOptionStorage::processValue(const std::string &value)
 {
     if (manager_ != NULL)
     {
@@ -340,8 +344,7 @@ void FileNameOptionStorage::convertValue(const std::string &value)
                                "Manager returned an invalid file name");
                 }
             }
-            addValue(processedValue);
-            return;
+            return processedValue;
         }
     }
     // Currently, directory options are simple, and don't need any
@@ -349,8 +352,7 @@ void FileNameOptionStorage::convertValue(const std::string &value)
     // TODO: Consider splitting them into a separate DirectoryOption.
     if (isDirectoryOption())
     {
-        addValue(value);
-        return;
+        return value;
     }
     const int fileType = fn2ftp(value.c_str());
     if (fileType == efNR)
@@ -370,14 +372,14 @@ void FileNameOptionStorage::convertValue(const std::string &value)
                            value.c_str(), joinStrings(extensions(), ", ").c_str());
         GMX_THROW(InvalidInputError(message));
     }
-    addValue(value);
+    return value;
 }
 
 void FileNameOptionStorage::processAll()
 {
     if (manager_ != NULL && hasFlag(efOption_HasDefaultValue))
     {
-        ValueList &valueList = values();
+        ArrayRef<std::string> valueList = values();
         GMX_RELEASE_ASSERT(valueList.size() == 1,
                            "There should be only one default value");
         if (!valueList[0].empty())
@@ -394,7 +396,6 @@ void FileNameOptionStorage::processAll()
                 GMX_ASSERT(isValidType(fn2ftp(newValue.c_str())),
                            "Manager returned an invalid default value");
                 valueList[0] = newValue;
-                refreshValues();
             }
         }
     }
index 8e799687dd4e2de2157a5032fa8af7c7f96c6016..26ad20e5b99e61c86b599e196a2e956faa1f7018 100644 (file)
@@ -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
  * 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.
@@ -58,7 +58,7 @@ class FileNameOptionManager;
 /*! \internal \brief
  * Converts, validates, and stores file names.
  */
-class FileNameOptionStorage : public OptionStorageTemplate<std::string>
+class FileNameOptionStorage : public OptionStorageTemplateSimple<std::string>
 {
     public:
         /*! \brief
@@ -100,7 +100,8 @@ class FileNameOptionStorage : public OptionStorageTemplate<std::string>
         ConstArrayRef<int> fileTypes() const;
 
     private:
-        virtual void convertValue(const std::string &value);
+        virtual void initConverter(ConverterType *converter);
+        virtual std::string processValue(const std::string &value);
         virtual void processAll();
 
         FileNameOptionInfo      info_;
index 0cc29291c91d5ce5c99ce881e535272e2d6d8400..3cdaafc0210a4253255816dcf63301ff4401be8a 100644 (file)
@@ -92,18 +92,6 @@ class IOptionsContainer
          * output.
          */
         virtual IOptionsContainer &addGroup() = 0;
-        /*! \brief
-         * Adds a recognized option.
-         *
-         * \param[in] settings Option description.
-         * \returns   OptionInfo object for the created option (never NULL).
-         * \throws    APIError if invalid option settings are provided.
-         *
-         * This method provides the internal implementation, but in most cases
-         * the templated method is called from user code.
-         * See the templated method for more details.
-         */
-        virtual OptionInfo *addOption(const AbstractOption &settings) = 0;
         /*! \brief
          * Adds a recognized option.
          *
@@ -130,7 +118,7 @@ class IOptionsContainer
         typename OptionType::InfoType *addOption(const OptionType &settings)
         {
             OptionInfo *info
-                = addOption(static_cast<const AbstractOption &>(settings));
+                = addOptionImpl(static_cast<const AbstractOption &>(settings));
             GMX_ASSERT(info->isType<typename OptionType::InfoType>(),
                        "Mismatching option info type declaration and implementation");
             return info->toType<typename OptionType::InfoType>();
@@ -141,6 +129,19 @@ class IOptionsContainer
         // (no need for the virtual, but some compilers warn otherwise)
         virtual ~IOptionsContainer();
 
+        /*! \brief
+         * Adds a recognized option.
+         *
+         * \param[in] settings Option description.
+         * \returns   OptionInfo object for the created option (never NULL).
+         * \throws    APIError if invalid option settings are provided.
+         *
+         * This method provides the internal implementation, but the templated
+         * method is called from user code.  See the templated method for more
+         * details.
+         */
+        virtual OptionInfo *addOptionImpl(const AbstractOption &settings) = 0;
+
         GMX_DEFAULT_CONSTRUCTORS(IOptionsContainer);
 };
 
diff --git a/src/gromacs/options/ioptionscontainerwithsections.h b/src/gromacs/options/ioptionscontainerwithsections.h
new file mode 100644 (file)
index 0000000..198e0ca
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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.
+ */
+/*! \file
+ * \brief
+ * Declares gmx::IOptionsContainerWithSections.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inpublicapi
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_IOPTIONSCONTAINERWITHSECTIONS_H
+#define GMX_OPTIONS_IOPTIONSCONTAINERWITHSECTIONS_H
+
+#include "gromacs/options/ioptionscontainer.h"
+
+namespace gmx
+{
+
+class AbstractOptionSection;
+class AbstractOptionSectionHandle;
+
+namespace internal
+{
+class OptionSectionImpl;
+}
+
+/*! \brief
+ * Interface for adding input options with sections.
+ *
+ * This interface extends IOptionsContainer with an additional addSection()
+ * method that supports creating a hierarchy of sections for the options.
+ *
+ * Header optionsection.h provides OptionSection.
+ *
+ * \inpublicapi
+ * \ingroup module_options
+ */
+class IOptionsContainerWithSections : public IOptionsContainer
+{
+    public:
+        /*! \brief
+         * Adds a section to this collection.
+         *
+         * \tparam    SectionType Type of the section description object.
+         * \param[in] section     Section description.
+         * \returns   AbstractOptionSectionHandle object for the created option.
+         * \throws    APIError if invalid option settings are provided.
+         *
+         * Options can be added to the section through the returned handle.
+         *
+         * \internal
+         * \p SectionType::HandleType must specify a type that derives from
+         * AbstractinOptionSectionHandle and has a suitable constructor.
+         */
+        template <class SectionType>
+        typename SectionType::HandleType addSection(const SectionType &section)
+        {
+            internal::OptionSectionImpl *storage
+                = addSectionImpl(static_cast<const AbstractOptionSection &>(section));
+            return typename SectionType::HandleType(storage);
+        }
+
+    protected:
+        // Disallow deletion through the interface.
+        // (no need for the virtual, but some compilers warn otherwise)
+        virtual ~IOptionsContainerWithSections();
+
+        /*! \brief
+         * Adds a section to this container.
+         *
+         * \param[in] section     Section description.
+         * \returns   Pointer to the internal section representation object.
+         */
+        virtual internal::OptionSectionImpl *
+        addSectionImpl(const AbstractOptionSection &section) = 0;
+
+        GMX_DEFAULT_CONSTRUCTORS(IOptionsContainerWithSections);
+};
+
+} // namespace
+
+#endif
diff --git a/src/gromacs/options/isectionstorage.h b/src/gromacs/options/isectionstorage.h
new file mode 100644 (file)
index 0000000..f2a8073
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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.
+ */
+/*! \file
+ * \brief
+ * Declares gmx::IOptionSectionStorage.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_ISECTIONSTORAGE_H
+#define GMX_OPTIONS_ISECTIONSTORAGE_H
+
+namespace gmx
+{
+
+/*! \internal
+ * \brief
+ * Provides behavior specific to a certain option section type.
+ *
+ * \ingroup module_options
+ */
+class IOptionSectionStorage
+{
+    public:
+        virtual ~IOptionSectionStorage();
+
+        /*! \brief
+         * Called once before the first call to startSection().
+         *
+         * This is called once all options have been added to the section.
+         * The current implementation does not call this if startSection() is
+         * never called.
+         */
+        virtual void initStorage() = 0;
+        /*! \brief
+         * Called when option assignment enters this section.
+         */
+        virtual void startSection()  = 0;
+        /*! \brief
+         * Called when option assignment leaves this section.
+         */
+        virtual void finishSection() = 0;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/options/ivaluestore.h b/src/gromacs/options/ivaluestore.h
new file mode 100644 (file)
index 0000000..3476529
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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.
+ */
+/*! \file
+ * \brief
+ * Declares gmx::IOptionValueStore.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_IVALUESTORE_H
+#define GMX_OPTIONS_IVALUESTORE_H
+
+namespace gmx
+{
+
+template <typename T> class ArrayRef;
+
+/*! \internal
+ * \brief
+ * Represents the final storage location of option values.
+ *
+ * \todo
+ * Try to make this more like a write-only interface, getting rid of the need
+ * to access the stored values through this interface.  That would simplify
+ * things.
+ *
+ * \ingroup module_options
+ */
+template <typename T>
+class IOptionValueStore
+{
+    public:
+        virtual ~IOptionValueStore() {}
+
+        //! Returns the number of values stored so far.
+        virtual int valueCount() = 0;
+        //! Returns a reference to the actual values.
+        virtual ArrayRef<T> values() = 0;
+        //! Removes all stored values.
+        virtual void clear() = 0;
+        //! Reserves memory for additional `count` entries.
+        virtual void reserve(size_t count) = 0;
+        //! Appends a value to the store.
+        virtual void append(const T &value) = 0;
+};
+
+} // namespace gmx
+
+#endif
index e17a77617a77ddc015e2d07e7d54a8e6ca8287c6..d06ffb48d30a29c84e942f863a9a96f640cf7595 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, 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.
 #include <vector>
 
 #include "gromacs/options/abstractoption.h"
+#include "gromacs/options/abstractoptionstorage.h"
+#include "gromacs/options/ioptionscontainer.h"
+#include "gromacs/options/ioptionscontainerwithsections.h"
+#include "gromacs/options/isectionstorage.h"
 #include "gromacs/options/optionmanagercontainer.h"
 #include "gromacs/options/options.h"
+#include "gromacs/options/optionsection.h"
 
 namespace gmx
 {
 
-class AbstractOptionStorage;
-
 namespace internal
 {
 
 /*! \internal
  * \brief
- * Private implementation class for Options.
+ * Internal implementation class for storing an option section.
  *
- * Note that in addition to Options, the OptionsAssigner and OptionsIterator
- * classes also directly access this class.
+ * All options are stored within a section: the top-level contents of an
+ * Options object are handled within an unnamed, "root" section.
+ * This class handles the common functionality for all sections, related to
+ * storing the options and subsections.  Functionality specific to a section
+ * type is provided by IOptionSectionStorage.
  *
  * \ingroup module_options
  */
-class OptionsImpl
+class OptionSectionImpl : public IOptionsContainerWithSections
 {
     public:
         /*! \internal \brief
@@ -86,35 +92,55 @@ class OptionsImpl
                 typedef std::list<Group> SubgroupList;
 
                 //! Creates a group within the given Options.
-                explicit Group(OptionsImpl *parent) : parent_(parent) {}
+                explicit Group(OptionSectionImpl *parent) : parent_(parent) {}
 
                 // From IOptionsContainer
                 virtual IOptionsContainer &addGroup();
-                virtual OptionInfo *addOption(const AbstractOption &settings);
+                virtual OptionInfo *addOptionImpl(const AbstractOption &settings);
 
                 //! Containing options object.
-                OptionsImpl  *parent_;
+                OptionSectionImpl  *parent_;
                 /*! \brief
                  * List of options, in insertion order.
                  *
                  * Pointers in this container point to the objects managed by
                  * Impl::optionsMap_.
                  */
-                OptionList    options_;
+                OptionList          options_;
                 //! List of groups, in insertion order.
-                SubgroupList  subgroups_;
+                SubgroupList        subgroups_;
         };
 
         //! Smart pointer for managing an AbstractOptionStorage object.
         typedef std::unique_ptr<AbstractOptionStorage>
             AbstractOptionStoragePointer;
-        //! Convenience type for list of sections.
-        typedef std::vector<Options *> SubSectionList;
         //! Convenience typedef for a map that contains all the options.
         typedef std::map<std::string, AbstractOptionStoragePointer> OptionMap;
+        //! Smart pointer for managing subsections.
+        typedef std::unique_ptr<OptionSectionImpl> SectionPointer;
+        //! Convenience typedef for a container for subsections.
+        typedef std::vector<SectionPointer> SectionList;
+
+        //! Creates storage for a new section.
+        OptionSectionImpl(const OptionManagerContainer          &managers,
+                          std::unique_ptr<IOptionSectionStorage> storage,
+                          const char                            *name)
+            : managers_(managers), storage_(std::move(storage)), info_(this),
+              name_(name), rootGroup_(this), storageInitialized_(false)
+        {
+        }
 
-        //! Sets the name and title.
-        OptionsImpl(const char *name, const char *title);
+        // From IOptionsContainerWithSections
+        virtual OptionSectionImpl *addSectionImpl(const AbstractOptionSection &section);
+
+        // From IOptionsContainer
+        virtual IOptionsContainer &addGroup();
+        virtual OptionInfo *addOptionImpl(const AbstractOption &settings);
+
+        //! Returns section info object for this section.
+        OptionSectionInfo       &info() { return info_; }
+        //! Returns section info object for this section.
+        const OptionSectionInfo &info() const { return info_; }
 
         /*! \brief
          * Finds a subsection by name.
@@ -124,7 +150,7 @@ class OptionsImpl
          *
          * Does not throw.
          */
-        Options *findSubSection(const char *name) const;
+        OptionSectionImpl *findSection(const char *name) const;
         /*! \brief
          * Finds an option by name.
          *
@@ -136,38 +162,58 @@ class OptionsImpl
         AbstractOptionStorage *findOption(const char *name) const;
 
         /*! \brief
-         * Calls AbstractOptionStorage::startSource() for all options,
-         * including subsections.
+         * Called when entering the section.
          *
-         * Does not throw.
+         * Calls AbstractOptionStorage::startSource() for all options.
          */
-        void startSource();
-
-        //! Name for the Options object.
-        std::string             name_;
+        void start();
         /*! \brief
-         * Option managers set for this collection.
-         *
-         * This is non-empty only for the top-level Options object.
+         * Calls AbstractOptionStorage::finish() for all options.
          */
-        OptionManagerContainer  managers_;
+        void finish();
+
+        //! Reference to the option managers in the parent Options object.
+        const OptionManagerContainer           &managers_;
+        //! Type-specific storage object for this section.
+        std::unique_ptr<IOptionSectionStorage>  storage_;
+        //! Info object for this section.
+        OptionSectionInfo                       info_;
+        //! Name of this section (empty and unused for the root section).
+        std::string                             name_;
         /*! \brief
          * Group that contains all options (and subgroups).
          *
          * This is used to store the insertion order of options.
          */
-        Group                   rootGroup_;
+        Group                          rootGroup_;
         //! Map from option names to options; owns the option storage objects.
-        OptionMap               optionMap_;
-        /*! \brief
-         * List of subsections, in insertion order.
-         *
-         * This container contains only references to external objects; memory
-         * management is performed elsewhere.
-         */
-        SubSectionList          subSections_;
-        //! Options object that contains this object as a subsection, or NULL.
-        Options                *parent_;
+        OptionMap                      optionMap_;
+        //! List of subsections, in insertion order.
+        SectionList                    subsections_;
+        //! Whether initStorage() has been called for `storage_`.
+        bool                           storageInitialized_;
+
+        GMX_DISALLOW_COPY_AND_ASSIGN(OptionSectionImpl);
+};
+
+/*! \internal
+ * \brief
+ * Private implementation class for Options.
+ *
+ * Note that in addition to Options, the OptionsAssigner class also directly
+ * accesses this class.
+ *
+ * \ingroup module_options
+ */
+class OptionsImpl
+{
+    public:
+        OptionsImpl();
+
+        //! Option managers set for this collection.
+        OptionManagerContainer  managers_;
+        //! Root section for this collection.
+        OptionSectionImpl       rootSection_;
 };
 
 } // namespace internal
index 2a6e5f2ba5e0bcacb7cb6e16cddd5adf4031821d..4fdf0efd342f9f882d380774272ac26307447e83 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2014,2015,2016, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -47,6 +47,7 @@
 
 #include "gromacs/options/abstractoption.h"
 #include "gromacs/options/abstractoptionstorage.h"
+#include "gromacs/options/optionsection.h"
 #include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
@@ -73,6 +74,22 @@ IOptionsContainer::~IOptionsContainer()
 {
 }
 
+/********************************************************************
+ * IOptionsContainerWithSections
+ */
+
+IOptionsContainerWithSections::~IOptionsContainerWithSections()
+{
+}
+
+/********************************************************************
+ * IOptionSectionStorage
+ */
+
+IOptionSectionStorage::~IOptionSectionStorage()
+{
+}
+
 /********************************************************************
  * OptionsImpl
  */
@@ -80,76 +97,125 @@ IOptionsContainer::~IOptionsContainer()
 namespace internal
 {
 
-OptionsImpl::OptionsImpl(const char *name, const char * /*title*/)
-    : name_(name != NULL ? name : ""), rootGroup_(this),
-      parent_(NULL)
+OptionsImpl::OptionsImpl()
+    : rootSection_(managers_, nullptr, "")
+{
+}
+
+/********************************************************************
+ * OptionSectionImpl
+ */
+
+OptionSectionImpl *
+OptionSectionImpl::addSectionImpl(const AbstractOptionSection &section)
+{
+    const char *name = section.name_;
+    // Make sure that there are no duplicate sections.
+    GMX_RELEASE_ASSERT(findSection(name) == NULL, "Duplicate subsection name");
+    std::unique_ptr<IOptionSectionStorage> storage(section.createStorage());
+    subsections_.push_back(SectionPointer(new OptionSectionImpl(managers_, std::move(storage), name)));
+    return subsections_.back().get();
+}
+
+IOptionsContainer &OptionSectionImpl::addGroup()
 {
+    return rootGroup_.addGroup();
 }
 
-Options *OptionsImpl::findSubSection(const char *name) const
+OptionInfo *OptionSectionImpl::addOptionImpl(const AbstractOption &settings)
 {
-    SubSectionList::const_iterator i;
-    for (i = subSections_.begin(); i != subSections_.end(); ++i)
+    return rootGroup_.addOptionImpl(settings);
+}
+
+OptionSectionImpl *OptionSectionImpl::findSection(const char *name) const
+{
+    for (const auto &section : subsections_)
     {
-        if ((*i)->name() == name)
+        if (section->name_ == name)
         {
-            return *i;
+            return section.get();
         }
     }
-    return NULL;
+    return nullptr;
 }
 
-AbstractOptionStorage *OptionsImpl::findOption(const char *name) const
+AbstractOptionStorage *OptionSectionImpl::findOption(const char *name) const
 {
     OptionMap::const_iterator i = optionMap_.find(name);
     if (i == optionMap_.end())
     {
-        return NULL;
+        return nullptr;
     }
     return i->second.get();
 }
 
-void OptionsImpl::startSource()
+void OptionSectionImpl::start()
 {
-    OptionMap::const_iterator i;
-    for (i = optionMap_.begin(); i != optionMap_.end(); ++i)
+    for (const auto &entry : optionMap_)
+    {
+        entry.second->startSource();
+    }
+    if (storage_ != nullptr)
+    {
+        if (!storageInitialized_)
+        {
+            storage_->initStorage();
+            storageInitialized_ = true;
+        }
+        storage_->startSection();
+    }
+}
+
+void OptionSectionImpl::finish()
+{
+    // TODO: Consider how to customize these error messages based on context.
+    ExceptionInitializer  errors("Invalid input values");
+    for (const auto &entry : optionMap_)
+    {
+        AbstractOptionStorage &option = *entry.second;
+        try
+        {
+            option.finish();
+        }
+        catch (UserInputError &ex)
+        {
+            ex.prependContext("In option " + option.name());
+            errors.addCurrentExceptionAsNested();
+        }
+    }
+    if (errors.hasNestedExceptions())
     {
-        AbstractOptionStorage &option = *i->second;
-        option.startSource();
+        // TODO: This exception type may not always be appropriate.
+        GMX_THROW(InvalidInputError(errors));
     }
-    SubSectionList::const_iterator j;
-    for (j = subSections_.begin(); j != subSections_.end(); ++j)
+    if (storage_ != nullptr)
     {
-        Options &section = **j;
-        section.impl_->startSource();
+        storage_->finishSection();
     }
 }
 
 /********************************************************************
- * OptionsImpl::Group
+ * OptionSectionImpl::Group
  */
 
-IOptionsContainer &OptionsImpl::Group::addGroup()
+IOptionsContainer &OptionSectionImpl::Group::addGroup()
 {
-    subgroups_.push_back(Group(parent_));
+    subgroups_.emplace_back(parent_);
     return subgroups_.back();
 }
 
-OptionInfo *OptionsImpl::Group::addOption(const AbstractOption &settings)
+OptionInfo *OptionSectionImpl::Group::addOptionImpl(const AbstractOption &settings)
 {
-    OptionsImpl *root = parent_;
-    while (root->parent_ != NULL)
-    {
-        root = root->parent_->impl_.get();
-    }
-    AbstractOptionStoragePointer         option(settings.createStorage(root->managers_));
+    OptionSectionImpl::AbstractOptionStoragePointer
+         option(settings.createStorage(parent_->managers_));
     options_.reserve(options_.size() + 1);
-    std::pair<OptionMap::iterator, bool> insertionResult =
+    auto insertionResult =
         parent_->optionMap_.insert(std::make_pair(option->name(),
                                                   std::move(option)));
     if (!insertionResult.second)
     {
-        GMX_THROW(APIError("Duplicate option: " + option->name()));
+        const std::string &name = insertionResult.first->second->name();
+        GMX_THROW(APIError("Duplicate option: " + name));
     }
     AbstractOptionStorage &insertedOption = *insertionResult.first->second;
     options_.push_back(&insertedOption);
@@ -164,8 +230,8 @@ using internal::OptionsImpl;
  * Options
  */
 
-Options::Options(const char *name, const char *title)
-    : impl_(new OptionsImpl(name, title))
+Options::Options()
+    : impl_(new OptionsImpl)
 {
 }
 
@@ -173,90 +239,47 @@ Options::~Options()
 {
 }
 
-const std::string &Options::name() const
-{
-    return impl_->name_;
-}
-
 
 void Options::addManager(IOptionManager *manager)
 {
-    GMX_RELEASE_ASSERT(impl_->parent_ == NULL,
-                       "Can only add a manager in a top-level Options object");
     // This ensures that all options see the same set of managers.
-    GMX_RELEASE_ASSERT(impl_->optionMap_.empty(),
+    GMX_RELEASE_ASSERT(impl_->rootSection_.optionMap_.empty(),
                        "Can only add a manager before options");
     // This check could be relaxed if we instead checked that the subsections
     // do not have options.
-    GMX_RELEASE_ASSERT(impl_->subSections_.empty(),
+    GMX_RELEASE_ASSERT(impl_->rootSection_.subsections_.empty(),
                        "Can only add a manager before subsections");
     impl_->managers_.add(manager);
 }
 
-void Options::addSubSection(Options *section)
+internal::OptionSectionImpl *Options::addSectionImpl(const AbstractOptionSection &section)
 {
-    // This is required, because managers are used from the root Options
-    // object, so they are only seen after the subsection has been added.
-    GMX_RELEASE_ASSERT(section->impl_->optionMap_.empty(),
-                       "Can only add a subsection before it has any options");
-    GMX_RELEASE_ASSERT(section->impl_->managers_.empty(),
-                       "Can only have managers in a top-level Options object");
-    // Make sure that section is not already inserted somewhere.
-    GMX_RELEASE_ASSERT(section->impl_->parent_ == NULL,
-                       "Cannot add as subsection twice");
-    // Make sure that there are no duplicate sections.
-    GMX_RELEASE_ASSERT(impl_->findSubSection(section->name().c_str()) == NULL,
-                       "Duplicate subsection name");
-    impl_->subSections_.push_back(section);
-    section->impl_->parent_ = this;
+    return impl_->rootSection_.addSectionImpl(section);
 }
 
 IOptionsContainer &Options::addGroup()
 {
-    return impl_->rootGroup_.addGroup();
+    return impl_->rootSection_.addGroup();
+}
+
+OptionInfo *Options::addOptionImpl(const AbstractOption &settings)
+{
+    return impl_->rootSection_.addOptionImpl(settings);
 }
 
-OptionInfo *Options::addOption(const AbstractOption &settings)
+OptionSectionInfo &Options::rootSection()
 {
-    return impl_->rootGroup_.addOption(settings);
+    return impl_->rootSection_.info();
+}
+
+const OptionSectionInfo &Options::rootSection() const
+{
+    return impl_->rootSection_.info();
 }
 
 void Options::finish()
 {
-    // TODO: Consider how to customize these error messages based on context.
-    ExceptionInitializer                    errors("Invalid input values");
-    OptionsImpl::OptionMap::const_iterator  i;
-    for (i = impl_->optionMap_.begin(); i != impl_->optionMap_.end(); ++i)
-    {
-        AbstractOptionStorage &option = *i->second;
-        try
-        {
-            option.finish();
-        }
-        catch (UserInputError &ex)
-        {
-            ex.prependContext("In option " + option.name());
-            errors.addCurrentExceptionAsNested();
-        }
-    }
-    OptionsImpl::SubSectionList::const_iterator j;
-    for (j = impl_->subSections_.begin(); j != impl_->subSections_.end(); ++j)
-    {
-        Options &section = **j;
-        try
-        {
-            section.finish();
-        }
-        catch (const UserInputError &)
-        {
-            errors.addCurrentExceptionAsNested();
-        }
-    }
-    if (errors.hasNestedExceptions())
-    {
-        // TODO: This exception type may not always be appropriate.
-        GMX_THROW(InvalidInputError(errors));
-    }
+    impl_->rootSection_.finish();
 }
 
 } // namespace gmx
index 944606db1ba7ab1bfd451b0b1d5c511ed5b8c307..a4ba843633ac1889012a00e235958f30b8167844 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2014,2015,2016, 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.
 
 #include <string>
 
-#include "gromacs/options/ioptionscontainer.h"
+#include "gromacs/options/ioptionscontainerwithsections.h"
 #include "gromacs/utility/classhelpers.h"
 
 namespace gmx
 {
 
 class AbstractOption;
+class OptionSection;
+class OptionSectionInfo;
 class OptionsAssigner;
-class OptionsIterator;
 
 namespace internal
 {
@@ -88,7 +89,7 @@ class IOptionManager
  * Collection of options.
  *
  * See \ref module_options for an overview of how the options work.
- * The IOptionsContainer interface documents how to add options.
+ * The IOptionsContainerWithSections interface documents how to add options.
  *
  * In order to keep the public interface of this class simple, functionality
  * to assign values to options is provided by a separate OptionsAssigner class.
@@ -98,23 +99,13 @@ class IOptionManager
  * \inpublicapi
  * \ingroup module_options
  */
-class Options : public IOptionsContainer
+class Options : public IOptionsContainerWithSections
 {
     public:
-        /*! \brief
-         * Initializes the name and title of an option collection.
-         *
-         * \param[in] name  Single-word name.
-         * \param[in] title Descriptive title.
-         *
-         * Copies the input strings.
-         */
-        Options(const char *name, const char *title);
+        //! Initializes an empty options root container.
+        Options();
         ~Options();
 
-        //! Returns the short name of the option collection.
-        const std::string &name() const;
-
         /*! \brief
          * Adds an option manager.
          *
@@ -133,35 +124,17 @@ class Options : public IOptionsContainer
          * The Options object (and its contained options) only stores a
          * reference to the object.
          *
-         * This method cannot be called after adding options or subsections.
+         * This method cannot be called after adding options or sections.
          */
         void addManager(IOptionManager *manager);
 
-        /*! \brief
-         * Adds an option collection as a subsection of this collection.
-         *
-         * \param[in] section Subsection to add.
-         *
-         * The name() field of \p section is used as the name of the
-         * subsection.  If an attempt is made to add two different subsections
-         * with the same name, this function asserts.
-         *
-         * \p section should not have any options added at the point this
-         * method is called.
-         *
-         * Only a pointer to the provided object is stored.  The caller is
-         * responsible that the object exists for the lifetime of the
-         * collection.
-         * It is not possible to add the same Options object as a subsection to
-         * several different Options.
-         * If an attempt is made, the function asserts.
-         */
-        void addSubSection(Options *section);
-
         // From IOptionsContainer
         virtual IOptionsContainer &addGroup();
-        virtual OptionInfo *addOption(const AbstractOption &settings);
-        using IOptionsContainer::addOption;
+
+        //! Returns a handle to the root section.
+        OptionSectionInfo       &rootSection();
+        //! Returns a handle to the root section.
+        const OptionSectionInfo &rootSection() const;
 
         /*! \brief
          * Notifies the collection that all option values are assigned.
@@ -180,16 +153,16 @@ class Options : public IOptionsContainer
         void finish();
 
     private:
+        // From IOptionsContainerWithSections
+        virtual internal::OptionSectionImpl *
+        addSectionImpl(const AbstractOptionSection &section);
+        // From IOptionsContainer
+        virtual OptionInfo *addOptionImpl(const AbstractOption &settings);
+
         PrivateImplPointer<internal::OptionsImpl> impl_;
 
-        //! Needed for the implementation to access subsections.
-        friend class internal::OptionsImpl;
         //! Needed to be able to extend the interface of this object.
         friend class OptionsAssigner;
-        //! Needed to be able to extend the interface of this object.
-        friend class OptionsIterator;
-        //! Needed to be able to extend the interface of this object.
-        friend class OptionsModifyingIterator;
 };
 
 } // namespace gmx
index 2842655c54f438b38559d32d2989383ec69d1b39..7763f25961431f0c486fde8a6f7319a30e4e6c0d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, 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.
@@ -49,6 +49,7 @@
 #include "gromacs/options/options.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/variant.h"
 
 #include "options-impl.h"
 
@@ -67,13 +68,16 @@ namespace gmx
 class OptionsAssigner::Impl
 {
     public:
+        //! Shorthand for the internal type used to represent a section.
+        typedef internal::OptionSectionImpl Section;
+
         //! Sets the option object to assign to.
         explicit Impl(Options *options);
 
         //! Returns true if a subsection has been set.
-        bool inSubSection() const { return sectionStack_.size() > 1; }
+        bool inSection() const { return sectionStack_.size() > 1; }
         //! Returns the Options object for the current section.
-        Options &currentSection() const { return *sectionStack_.back(); }
+        Section &currentSection() const { return *sectionStack_.back(); }
         /*! \brief
          * Finds an option by the given name.
          *
@@ -95,7 +99,7 @@ class OptionsAssigner::Impl
          *
          * The first element always points to \a options_.
          */
-        std::vector<Options *>  sectionStack_;
+        std::vector<Section *>  sectionStack_;
         //! Current option being assigned to, or NULL if none.
         AbstractOptionStorage  *currentOption_;
         /*! \brief
@@ -113,7 +117,7 @@ OptionsAssigner::Impl::Impl(Options *options)
     : options_(*options), bAcceptBooleanNoPrefix_(false),
       currentOption_(NULL), currentValueCount_(0), reverseBoolean_(false)
 {
-    sectionStack_.push_back(&options_);
+    sectionStack_.push_back(&options_.impl_->rootSection_);
 }
 
 AbstractOptionStorage *
@@ -121,13 +125,13 @@ OptionsAssigner::Impl::findOption(const char *name)
 {
     GMX_RELEASE_ASSERT(currentOption_ == NULL,
                        "Cannot search for another option while processing one");
-    const Options         &section = currentSection();
-    AbstractOptionStorage *option  = section.impl_->findOption(name);
+    const Section         &section = currentSection();
+    AbstractOptionStorage *option  = section.findOption(name);
     if (option == NULL && bAcceptBooleanNoPrefix_)
     {
         if (name[0] == 'n' && name[1] == 'o')
         {
-            option = section.impl_->findOption(name + 2);
+            option = section.findOption(name + 2);
             if (option != NULL && option->isBoolean())
             {
                 reverseBoolean_ = true;
@@ -161,17 +165,18 @@ void OptionsAssigner::setAcceptBooleanNoPrefix(bool bEnabled)
 
 void OptionsAssigner::start()
 {
-    impl_->options_.impl_->startSource();
+    impl_->options_.impl_->rootSection_.start();
 }
 
-void OptionsAssigner::startSubSection(const char *name)
+void OptionsAssigner::startSection(const char *name)
 {
-    Options *section = impl_->currentSection().impl_->findSubSection(name);
+    Impl::Section *section = impl_->currentSection().findSection(name);
     if (section == NULL)
     {
         GMX_THROW(InvalidInputError("Unknown subsection"));
     }
     impl_->sectionStack_.push_back(section);
+    section->start();
 }
 
 void OptionsAssigner::startOption(const char *name)
@@ -197,6 +202,11 @@ bool OptionsAssigner::tryStartOption(const char *name)
 }
 
 void OptionsAssigner::appendValue(const std::string &value)
+{
+    appendValue(Variant(value));
+}
+
+void OptionsAssigner::appendValue(const Variant &value)
 {
     AbstractOptionStorage *option = impl_->currentOption_;
     GMX_RELEASE_ASSERT(option != NULL, "startOption() not called");
@@ -214,8 +224,7 @@ void OptionsAssigner::finishOption()
         if (impl_->currentValueCount_ == 0)
         {
             // Should not throw, otherwise something is wrong.
-            // TODO: Get rid of the hard-coded values.
-            option->appendValue(impl_->reverseBoolean_ ? "0" : "1");
+            option->appendValue(Variant::create<bool>(!impl_->reverseBoolean_));
         }
         else if (impl_->reverseBoolean_)
         {
@@ -231,17 +240,19 @@ void OptionsAssigner::finishOption()
     }
 }
 
-void OptionsAssigner::finishSubSection()
+void OptionsAssigner::finishSection()
 {
     // Should only be called if we are in a subsection.
-    GMX_RELEASE_ASSERT(impl_->inSubSection(), "startSubSection() not called");
+    GMX_RELEASE_ASSERT(impl_->inSection(), "startSection() not called");
+    Impl::Section *section = impl_->sectionStack_.back();
+    section->finish();
     impl_->sectionStack_.pop_back();
 }
 
 void OptionsAssigner::finish()
 {
     GMX_RELEASE_ASSERT(impl_->currentOption_ == NULL, "finishOption() not called");
-    GMX_RELEASE_ASSERT(!impl_->inSubSection(), "finishSubSection() not called");
+    GMX_RELEASE_ASSERT(!impl_->inSection(), "finishSection() not called");
 }
 
 } // namespace gmx
index 35bb70dce9225e3e5b71146ef832a3df43086011..cdefa7258276df7cb263d018d996e6535bbfbaad 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, 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.
@@ -53,6 +53,7 @@ namespace gmx
 {
 
 class Options;
+class Variant;
 
 /*! \libinternal \brief
  * Decorator class for assigning values to Options.
@@ -70,11 +71,11 @@ class Options;
    assigner.startOption("opt1");
    assigner.appendValue("3");
    assigner.finishOption();
-   assigner.startSubSection("section");
+   assigner.startSection("section");
    assigner.startOption("opt2"); // Now in the subsection
    assigner.appendValue("yes");
    assigner.finishOption();
-   assigner.finishSubSection()
+   assigner.finishSection()
    assigner.startOption("opt3"); // Again in the main options
    assigner.appendValue("2");
    assigner.finishOption();
@@ -124,7 +125,7 @@ class OptionsAssigner
          *
          * Strong exception safety guarantee.
          */
-        void startSubSection(const char *name);
+        void startSection(const char *name);
         /*! \brief
          * Starts assigning values for an option.
          *
@@ -145,7 +146,7 @@ class OptionsAssigner
         /*! \brief
          * Appends a value to the value list of the current option.
          *
-         * \param[in] value  String representation of the value to assign.
+         * \param[in] value  Value to assign.
          * \throws InvalidInputError if the value cannot be converted or if
          *      there are too many values for an option.
          *
@@ -166,6 +167,14 @@ class OptionsAssigner
          * OptionStorageTemplate::convertValue() method of the storage class
          * implementing the option where the value is assigned to.
          */
+        void appendValue(const Variant &value);
+        /*! \brief
+         * Appends a value to the value list of the current option.
+         *
+         * \param[in] value  Value to assign.
+         *
+         * See appendValue(const Variant &) for more details.
+         */
         void appendValue(const std::string &value);
         /*! \brief
          * Finish assigning values for the current option.
@@ -186,7 +195,7 @@ class OptionsAssigner
          *
          * Does not throw.
          */
-        void finishSubSection();
+        void finishSection();
         /*! \brief
          * Finish assigning options through the object.
          *
diff --git a/src/gromacs/options/optionsection.cpp b/src/gromacs/options/optionsection.cpp
new file mode 100644 (file)
index 0000000..5578d36
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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 "gmxpre.h"
+
+#include "optionsection.h"
+
+#include "gromacs/options/isectionstorage.h"
+
+namespace gmx
+{
+
+namespace
+{
+
+class OptionSectionStorage : public IOptionSectionStorage
+{
+    public:
+        virtual void initStorage() {}
+        virtual void startSection() {}
+        virtual void finishSection() {}
+};
+
+}   // namespace
+
+IOptionSectionStorage *OptionSection::createStorage() const
+{
+    return new OptionSectionStorage();
+}
+
+} // namespace gmx
diff --git a/src/gromacs/options/optionsection.h b/src/gromacs/options/optionsection.h
new file mode 100644 (file)
index 0000000..b5f5479
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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.
+ */
+/*! \file
+ * \brief
+ * Declares gmx::OptionSection and gmx::OptionSectionInfo.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inpublicapi
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_OPTIONSECTION_H
+#define GMX_OPTIONS_OPTIONSECTION_H
+
+#include "gromacs/options/abstractsection.h"
+#include "gromacs/utility/classhelpers.h"
+
+namespace gmx
+{
+
+class OptionSectionHandle;
+
+/*! \brief
+ * Declares a simple option section.
+ *
+ * This class declares a simple section that only provides structure for
+ * grouping the options, but does not otherwise influence the behavior of the
+ * contained options.
+ *
+ * \inpublicapi
+ * \ingroup module_options
+ */
+class OptionSection : public AbstractOptionSection
+{
+    public:
+        //! AbstractOptionSectionHandle corresponding to this option type.
+        typedef OptionSectionHandle HandleType;
+
+        //! Creates a section with the given name.
+        explicit OptionSection(const char *name) : AbstractOptionSection(name) {}
+
+    private:
+        virtual IOptionSectionStorage *createStorage() const;
+};
+
+/*! \brief
+ * Allows adding options to an OptionSection.
+ *
+ * An instance of this class is returned from
+ * IOptionsContainerWithSections::addSection(), and supports adding options and
+ * subsections to a section created with OptionSection.
+ *
+ * \inpublicapi
+ * \ingroup module_options
+ */
+class OptionSectionHandle : public AbstractOptionSectionHandle
+{
+    public:
+        //! Wraps a given section storage object.
+        explicit OptionSectionHandle(internal::OptionSectionImpl *section)
+            : AbstractOptionSectionHandle(section)
+        {
+        }
+};
+
+class OptionSectionInfo : public AbstractOptionSectionInfo
+{
+    public:
+        //! Wraps a given section storage object.
+        explicit OptionSectionInfo(internal::OptionSectionImpl *section)
+            : AbstractOptionSectionInfo(section)
+        {
+        }
+};
+
+} // namespace gmx
+
+#endif
index 108841e9cfa9d81904331d6c51d68ae190b2a5b1..796484ef4aecaf63f62cb9da1b0f4295855d8053 100644 (file)
 
 #include "gromacs/options/abstractoption.h"
 #include "gromacs/options/abstractoptionstorage.h"
+#include "gromacs/options/valuestore.h"
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
 
+#include "valueconverter.h"
+
 namespace gmx
 {
 
@@ -65,10 +69,8 @@ class Options;
  *
  * Provides an implementation of the clearSet(), valueCount(), and processSet()
  * methods of AbstractOptionStorage, as well as a basic no-action
- * implementation of processAll().  Two new virtual methods are added:
- * processSetValues() and refreshValues().  The default implementation of
- * processSetValues() does nothing, and refreshValues() is used to update
- * secondary storage after values have been added/changed.
+ * implementation of processAll().  One new virtual method is added:
+ * processSetValues().  The default implementation does nothing.
  * This leaves typeString(), formatValue(), and convertValue() to be
  * implemented in derived classes.  processSetValues() and processAll() can
  * also be implemented if necessary.
@@ -91,15 +93,13 @@ class OptionStorageTemplate : public AbstractOptionStorage
         //! Type of the container that contains the current values.
         typedef std::vector<T> ValueList;
 
-        virtual ~OptionStorageTemplate();
-
         // No implementation in this class for the pure virtual methods, but
         // the declarations are still included for clarity.
         // The various copydoc calls are needed with Doxygen 1.8.10, although
         // things work without with 1.8.5...
         virtual std::string typeString() const = 0;
         //! \copydoc gmx::AbstractOptionStorage::valueCount()
-        virtual int valueCount() const { return static_cast<int>(values_->size()); }
+        virtual int valueCount() const { return store_->valueCount(); }
         /*! \copydoc gmx::AbstractOptionStorage::formatValue()
          *
          * OptionStorageTemplate implements handling of DefaultValueIfSetIndex
@@ -110,6 +110,9 @@ class OptionStorageTemplate : public AbstractOptionStorage
         virtual std::string formatValue(int i) const;
 
     protected:
+        //! Smart pointer for managing the final storage interface.
+        typedef std::unique_ptr<IOptionValueStore<T> > StorePointer;
+
         /*! \brief
          * Initializes the storage from option settings.
          *
@@ -125,12 +128,14 @@ class OptionStorageTemplate : public AbstractOptionStorage
          * Initializes the storage from base option settings.
          *
          * \param[in] settings  Option settings.
+         * \param[in] store     Final storage location.
          * \throws  APIError if invalid settings have been provided.
          *
          * This constructor works for cases where there is no matching
          * OptionTemplate (e.g., EnumOption).
          */
-        explicit OptionStorageTemplate(const AbstractOption &settings);
+        OptionStorageTemplate(const AbstractOption &settings,
+                              StorePointer          store);
 
         //! \copydoc gmx::AbstractOptionStorage::clearSet()
         virtual void clearSet();
@@ -143,7 +148,7 @@ class OptionStorageTemplate : public AbstractOptionStorage
          * should be considered whether the implementation can be made strongly
          * exception safe.
          */
-        virtual void convertValue(const std::string &value) = 0;
+        virtual void convertValue(const Variant &value) = 0;
         /*! \brief
          * Processes values for a set after all have been converted.
          *
@@ -188,12 +193,6 @@ class OptionStorageTemplate : public AbstractOptionStorage
          */
         virtual std::string formatSingleValue(const T &value) const = 0;
 
-        /*! \brief
-         * Removes all values from the storage.
-         *
-         * Does not throw.
-         */
-        void clear() { values_->clear(); }
         /*! \brief
          * Adds a value to a temporary storage.
          *
@@ -226,24 +225,9 @@ class OptionStorageTemplate : public AbstractOptionStorage
          * See addValue() for cases where this method should be used in derived
          * classes.
          *
-         * Calls refreshValues() and clearSet() if it is successful.
+         * Calls clearSet() if it is successful.
          */
         void commitValues();
-        /*! \brief
-         * Updates alternative store locations.
-         *
-         * Derived classes should override this method if they implement
-         * alternative store locations, and copy/translate values from the
-         * values() vector to these alternative storages.  They should also
-         * call the base class implementation as part of their implementation.
-         *
-         * Should be called in derived classes if values are modified directly
-         * through the values() method, e.g., in processAll().  Does not need
-         * to be called if commitValues() is used.
-         *
-         * Does not throw, and derived classes should not change that.
-         */
-        virtual void refreshValues();
 
         /*! \brief
          * Sets the default value for the option.
@@ -270,71 +254,130 @@ class OptionStorageTemplate : public AbstractOptionStorage
          * Provides derived classes access to the current list of values.
          *
          * The non-const variant should only be used from processAll() in
-         * derived classes if necessary, and refreshValues() should be called
-         * if any changes are made.
+         * derived classes if necessary.
          */
-        ValueList       &values() { return *values_; }
+        ArrayRef<T>      values() { return store_->values(); }
         //! Provides derived classes access to the current list of values.
-        const ValueList &values() const { return *values_; }
+        ConstArrayRef<T> values() const { return store_->values(); }
 
     private:
+        //! Creates the internal storage object for final values..
+        StorePointer createStore(ValueList *storeVector,
+                                 T *store, int *storeCount,
+                                 int initialCount);
+
         /*! \brief
          * Vector for temporary storage of values before commitSet() is called.
          */
         ValueList               setValues_;
+        //! Final storage for option values.
+        const StorePointer      store_;
+        // This never releases ownership.
+        std::unique_ptr<T>      defaultValueIfSet_;
+
+        // Copy and assign disallowed by base.
+};
+
+
+/*! \libinternal \brief
+ * Simplified option storage template for options that have one-to-one value
+ * conversion.
+ *
+ * \tparam T Assignable type that stores a single option value.
+ *
+ * To implement an option that always map a single input value to a single
+ * output value, derive from this class instead of OptionStorageTemplate.
+ * This class implements convertValue() in terms of two new virtual methods:
+ * initConverter() and processValue().
+ *
+ * To specify how different types of values need to be converted, implement
+ * initConverter().
+ * To do common post-processing of the values after conversion, but before they
+ * are added to the underlying storage, override processValue().
+ *
+ * \inlibraryapi
+ * \ingroup module_options
+ */
+template <typename T>
+class OptionStorageTemplateSimple : public OptionStorageTemplate<T>
+{
+    public:
+        //! Alias for the template class for use in base classes.
+        typedef OptionStorageTemplateSimple<T> MyBase;
+
+    protected:
+        //! Alias for the converter parameter type for initConverter().
+        typedef OptionValueConverterSimple<T> ConverterType;
+
+        //! Initializes the storage.
+        template <class U>
+        explicit OptionStorageTemplateSimple(const OptionTemplate<T, U> &settings,
+                                             OptionFlags staticFlags = OptionFlags())
+            : OptionStorageTemplate<T>(settings, staticFlags), initialized_(false)
+        {
+        }
+        //! Initializes the storage.
+        OptionStorageTemplateSimple(const AbstractOption                            &settings,
+                                    typename OptionStorageTemplate<T>::StorePointer  store)
+            : OptionStorageTemplate<T>(settings, std::move(store)), initialized_(false)
+        {
+        }
+
         /*! \brief
-         * Vector for primary storage of option values.
+         * Specifies how different types are converted.
          *
-         * Is never NULL; points either to externally provided vector, or an
-         * internally allocated one.  The allocation is performed by the
-         * constructor.
+         * See OptionValueConverterSimple for more details.
+         */
+        virtual void initConverter(ConverterType *converter) = 0;
+        /*! \brief
+         * Post-processes a value after conversion to the output type.
          *
-         * Primarily, modifications to values are done only to this storage,
-         * and other storage locations are updated only when refreshValues() is
-         * called.
+         * \param[in] value  Value after conversion.
+         * \returns   Value to store for the option.
+         *
+         * The default implementation only provides an identity mapping.
          */
-        ValueList                   *values_;
-        T                           *store_;
-        int                         *countptr_;
-        // These never release ownership.
-        std::unique_ptr<ValueList>   ownedValues_;
-        std::unique_ptr<T>           defaultValueIfSet_;
+        virtual T processValue(const T &value)
+        {
+            return value;
+        }
 
-        // Copy and assign disallowed by base.
+    private:
+        virtual void convertValue(const Variant &variant)
+        {
+            if (!initialized_)
+            {
+                initConverter(&converter_);
+                initialized_ = true;
+            }
+            this->addValue(processValue(converter_.convert(variant)));
+        }
+
+        ConverterType  converter_;
+        bool           initialized_;
 };
 
 
+/********************************************************************
+ * OptionStorageTemplate implementation
+ */
+
 template <typename T>
 template <class U>
 OptionStorageTemplate<T>::OptionStorageTemplate(const OptionTemplate<T, U> &settings,
                                                 OptionFlags staticFlags)
     : AbstractOptionStorage(settings, staticFlags),
-      values_(settings.storeVector_),
-      store_(settings.store_),
-      countptr_(settings.countptr_)
+      store_(createStore(settings.storeVector_,
+                         settings.store_, settings.countptr_,
+                         (settings.isVector() ?
+                          settings.maxValueCount_ : settings.minValueCount_)))
 {
-    // If the maximum number of values is not known, storage to
-    // caller-allocated memory is unsafe.
-    if (store_ != NULL && (maxValueCount() < 0 || hasFlag(efOption_MultipleTimes)))
-    {
-        GMX_THROW(APIError("Cannot set user-allocated storage for arbitrary number of values"));
-    }
-    if (values_ == NULL)
-    {
-        ownedValues_.reset(new std::vector<T>);
-        values_ = ownedValues_.get();
-    }
     if (hasFlag(efOption_NoDefaultValue)
         && (settings.defaultValue_ != NULL
             || settings.defaultValueIfSet_ != NULL))
     {
         GMX_THROW(APIError("Option does not support default value, but one is set"));
     }
-    if (store_ != NULL && countptr_ == NULL && !isVector()
-        && minValueCount() != maxValueCount())
-    {
-        GMX_THROW(APIError("Count storage is not set, although the number of produced values is not known"));
-    }
     if (!hasFlag(efOption_NoDefaultValue))
     {
         setFlag(efOption_HasDefaultValue);
@@ -342,16 +385,6 @@ OptionStorageTemplate<T>::OptionStorageTemplate(const OptionTemplate<T, U> &sett
         {
             setDefaultValue(*settings.defaultValue_);
         }
-        else if (ownedValues_.get() != NULL && store_ != NULL)
-        {
-            values_->clear();
-            int count = (settings.isVector() ?
-                         settings.maxValueCount_ : settings.minValueCount_);
-            for (int i = 0; i < count; ++i)
-            {
-                values_->push_back(store_[i]);
-            }
-        }
         if (settings.defaultValueIfSet_ != NULL)
         {
             setDefaultValueIfSet(*settings.defaultValueIfSet_);
@@ -361,19 +394,44 @@ OptionStorageTemplate<T>::OptionStorageTemplate(const OptionTemplate<T, U> &sett
 
 
 template <typename T>
-// cppcheck-suppress uninitMemberVar
-OptionStorageTemplate<T>::OptionStorageTemplate(const AbstractOption &settings)
-    : AbstractOptionStorage(settings, OptionFlags()),
-      store_(NULL), countptr_(NULL),
-      ownedValues_(new std::vector<T>())
+OptionStorageTemplate<T>::OptionStorageTemplate(const AbstractOption &settings,
+                                                StorePointer          store)
+    : AbstractOptionStorage(settings, OptionFlags()), store_(std::move(store))
 {
-    values_ = ownedValues_.get();
 }
 
 
 template <typename T>
-OptionStorageTemplate<T>::~OptionStorageTemplate()
+std::unique_ptr<IOptionValueStore<T> > OptionStorageTemplate<T>::createStore(
+        ValueList *storeVector, T *store, int *storeCount, int initialCount)
 {
+    if (storeVector != nullptr)
+    {
+        GMX_RELEASE_ASSERT(store == nullptr && storeCount == nullptr,
+                           "Cannot specify more than one storage location");
+        return StorePointer(new OptionValueStoreVector<T>(storeVector));
+    }
+    else if (store != nullptr)
+    {
+        // If the maximum number of values is not known, storage to
+        // caller-allocated memory is unsafe.
+        if (maxValueCount() < 0 || hasFlag(efOption_MultipleTimes))
+        {
+            GMX_THROW(APIError("Cannot set user-allocated storage for arbitrary number of values"));
+        }
+        if (storeCount == nullptr && !isVector() && minValueCount() != maxValueCount())
+        {
+            GMX_THROW(APIError("Count storage is not set, although the number of produced values is not known"));
+        }
+        if (hasFlag(efOption_NoDefaultValue))
+        {
+            initialCount = 0;
+        }
+        return StorePointer(new OptionValueStorePlain<T>(store, storeCount, initialCount));
+    }
+    GMX_RELEASE_ASSERT(storeCount == nullptr,
+                       "Cannot specify count storage without value storage");
+    return StorePointer(new OptionValueStoreNull<T>());
 }
 
 
@@ -440,32 +498,14 @@ void OptionStorageTemplate<T>::commitValues()
 {
     if (hasFlag(efOption_ClearOnNextSet))
     {
-        values_->swap(setValues_);
+        store_->clear();
     }
-    else
+    store_->reserve(setValues_.size());
+    for (T value : setValues_)
     {
-        values_->reserve(values_->size() + setValues_.size());
-        values_->insert(values_->end(), setValues_.begin(), setValues_.end());
+        store_->append(value);
     }
     clearSet();
-    refreshValues();
-}
-
-
-template <typename T>
-void OptionStorageTemplate<T>::refreshValues()
-{
-    if (countptr_ != NULL)
-    {
-        *countptr_ = static_cast<int>(values_->size());
-    }
-    if (store_ != NULL)
-    {
-        for (size_t i = 0; i < values_->size(); ++i)
-        {
-            store_[i] = (*values_)[i];
-        }
-    }
 }
 
 
@@ -479,12 +519,8 @@ void OptionStorageTemplate<T>::setDefaultValue(const T &value)
     if (hasFlag(efOption_HasDefaultValue))
     {
         setFlag(efOption_ExplicitDefaultValue);
-        clear();
-        clearSet();
-        addValue(value);
-        // TODO: As this is called from the constructor, it should not call
-        // virtual functions.
-        commitValues();
+        store_->clear();
+        store_->append(value);
     }
 }
 
index c9584dee9eceb29528793f81022848cd94cd2e2c..07397c888638019dde71300a9ae36326c9706dbb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2012,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2012,2014,2015,2016, 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,6 +45,7 @@
 
 #include "gromacs/options/abstractoptionstorage.h"
 #include "gromacs/options/options.h"
+#include "gromacs/options/optionsection.h"
 
 #include "options-impl.h"
 
@@ -69,17 +70,15 @@ void visitOption(OptionsModifyingVisitor *visitor, OptionInfo &optionInfo)
 
 //! Helper function to recursively visit all options in a group.
 template <class VisitorType>
-void acceptOptionsGroup(const OptionsImpl::Group &group, VisitorType *visitor)
+void acceptOptionsGroup(const internal::OptionSectionImpl::Group &group, VisitorType *visitor)
 {
-    OptionsImpl::Group::OptionList::const_iterator option;
-    for (option = group.options_.begin(); option != group.options_.end(); ++option)
+    for (const auto &option : group.options_)
     {
-        visitOption(visitor, (*option)->optionInfo());
+        visitOption(visitor, option->optionInfo());
     }
-    OptionsImpl::Group::SubgroupList::const_iterator subgroup;
-    for (subgroup = group.subgroups_.begin(); subgroup != group.subgroups_.end(); ++subgroup)
+    for (const auto &subgroup : group.subgroups_)
     {
-        acceptOptionsGroup(*subgroup, visitor);
+        acceptOptionsGroup(subgroup, visitor);
     }
 }
 
@@ -90,24 +89,26 @@ void acceptOptionsGroup(const OptionsImpl::Group &group, VisitorType *visitor)
  */
 
 OptionsIterator::OptionsIterator(const Options &options)
-    : options_(options)
+    : section_(options.rootSection().section())
 {
 }
 
-void OptionsIterator::acceptSubSections(OptionsVisitor *visitor) const
+OptionsIterator::OptionsIterator(const OptionSectionInfo &section)
+    : section_(section.section())
 {
-    const OptionsImpl::SubSectionList          &subSectionList =
-        options_.impl_->subSections_;
-    OptionsImpl::SubSectionList::const_iterator i;
-    for (i = subSectionList.begin(); i != subSectionList.end(); ++i)
+}
+
+void OptionsIterator::acceptSections(OptionsVisitor *visitor) const
+{
+    for (const auto &section : section_.subsections_)
     {
-        visitor->visitSubSection(*(*i));
+        visitor->visitSection(section->info());
     }
 }
 
 void OptionsIterator::acceptOptions(OptionsVisitor *visitor) const
 {
-    acceptOptionsGroup(options_.impl_->rootGroup_, visitor);
+    acceptOptionsGroup(section_.rootGroup_, visitor);
 }
 
 /********************************************************************
@@ -115,24 +116,26 @@ void OptionsIterator::acceptOptions(OptionsVisitor *visitor) const
  */
 
 OptionsModifyingIterator::OptionsModifyingIterator(Options *options)
-    : options_(*options)
+    : section_(options->rootSection().section())
+{
+}
+
+OptionsModifyingIterator::OptionsModifyingIterator(OptionSectionInfo *section)
+    : section_(section->section())
 {
 }
 
-void OptionsModifyingIterator::acceptSubSections(OptionsModifyingVisitor *visitor) const
+void OptionsModifyingIterator::acceptSections(OptionsModifyingVisitor *visitor) const
 {
-    const OptionsImpl::SubSectionList          &subSectionList =
-        options_.impl_->subSections_;
-    OptionsImpl::SubSectionList::const_iterator i;
-    for (i = subSectionList.begin(); i != subSectionList.end(); ++i)
+    for (auto &section : section_.subsections_)
     {
-        visitor->visitSubSection(*i);
+        visitor->visitSection(&section->info());
     }
 }
 
 void OptionsModifyingIterator::acceptOptions(OptionsModifyingVisitor *visitor) const
 {
-    acceptOptionsGroup(options_.impl_->rootGroup_, visitor);
+    acceptOptionsGroup(section_.rootGroup_, visitor);
 }
 
 } // namespace gmx
index 44e265a2f78dd4e3ffd1127d5306085a248e9fdf..6502f836b7524d7e1b49a90dac12cad34ee6d1a4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2014, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2014,2016, 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.
@@ -54,6 +54,12 @@ namespace gmx
 {
 
 class Options;
+class OptionSectionInfo;
+
+namespace internal
+{
+class OptionSectionImpl;
+}
 
 /*! \libinternal \brief
  * Pure interface for visiting options in a Options object.
@@ -68,13 +74,9 @@ class OptionsVisitor
     public:
         virtual ~OptionsVisitor() {}
 
-        /*! \brief
-         * Called for each subsection in Options.
-         */
-        virtual void visitSubSection(const Options &section) = 0;
-        /*! \brief
-         * Called for each option in Options.
-         */
+        //! Called for each section.
+        virtual void visitSection(const OptionSectionInfo &section) = 0;
+        //! Called for each option.
         virtual void visitOption(const OptionInfo &option) = 0;
 };
 
@@ -93,7 +95,7 @@ class OptionsTypeVisitor : public OptionsVisitor
     public:
         virtual ~OptionsTypeVisitor() {}
 
-        virtual void visitSubSection(const Options &section) = 0;
+        virtual void visitSection(const OptionSectionInfo &section) = 0;
         /*! \brief
          * Called for each option of type \p InfoType.
          */
@@ -113,7 +115,7 @@ class OptionsTypeVisitor : public OptionsVisitor
 /*! \libinternal \brief
  * Decorator class for visiting options in a Options object.
  *
- * This class provides an interface for looping through subsections and
+ * This class provides an interface for looping through sections and
  * options in a Options object.
  *
  * Typical use (loop over all options, iteratively descending into
@@ -122,10 +124,10 @@ class OptionsTypeVisitor : public OptionsVisitor
    class Visitor : public gmx::OptionsVisitor
    {
        public:
-           void visitSubSection(const Options &section)
+           void visitSection(const Options &section)
            {
                OptionsIterator iterator(section);
-               iterator.acceptSubSections(this);
+               iterator.acceptSections(this);
                iterator.acceptOptions(this);
            }
 
@@ -135,7 +137,7 @@ class OptionsTypeVisitor : public OptionsVisitor
            }
    }
 
-   Visitor().visitSubSection(options);
+   Visitor().visitSection(options);
  * \endcode
  *
  * \inlibraryapi
@@ -146,21 +148,22 @@ class OptionsIterator
     public:
         /*! \brief
          * Creates an object for visiting options in a Options object.
+         *
+         * The created iterator iterates over the "root" section in the Options
+         * object.
          */
         explicit OptionsIterator(const Options &options);
+        //! Creates an object for visiting options in an options section.
+        explicit OptionsIterator(const OptionSectionInfo &section);
 
-        /*! \brief
-         * Visits each subsection in the wrapped Options object.
-         */
-        void acceptSubSections(OptionsVisitor *visitor) const;
-        /*! \brief
-         * Visits each option in the wrapped Options object.
-         */
+        //! Visits each section in the wrapped section.
+        void acceptSections(OptionsVisitor *visitor) const;
+        //! Visits each option in the wrapped section.
         void acceptOptions(OptionsVisitor *visitor) const;
 
     private:
-        //! The wrapped Options object.
-        const Options          &options_;
+        //! The wrapped section object.
+        const internal::OptionSectionImpl &section_;
 
         GMX_DISALLOW_COPY_AND_ASSIGN(OptionsIterator);
 };
@@ -179,13 +182,9 @@ class OptionsModifyingVisitor
     public:
         virtual ~OptionsModifyingVisitor() {}
 
-        /*! \brief
-         * Called for each subsection in Options.
-         */
-        virtual void visitSubSection(Options *section) = 0;
-        /*! \brief
-         * Called for each option in Options.
-         */
+        //! Called for each section.
+        virtual void visitSection(OptionSectionInfo *section) = 0;
+        //! Called for each option.
         virtual void visitOption(OptionInfo *option) = 0;
 };
 
@@ -205,7 +204,7 @@ class OptionsModifyingTypeVisitor : public OptionsModifyingVisitor
     public:
         virtual ~OptionsModifyingTypeVisitor() {}
 
-        virtual void visitSubSection(Options *section) = 0;
+        virtual void visitSection(OptionSectionInfo *section) = 0;
         /*! \brief
          * Called for each option of type \p InfoType.
          */
@@ -238,21 +237,22 @@ class OptionsModifyingIterator
     public:
         /*! \brief
          * Creates an object for visiting options in a Options object.
+         *
+         * The created iterator iterates over the "root" section in the Options
+         * object.
          */
         explicit OptionsModifyingIterator(Options *options);
+        //! Creates an object for visiting options in an options section.
+        explicit OptionsModifyingIterator(OptionSectionInfo *section);
 
-        /*! \brief
-         * Visits each subsection in the wrapped Options object.
-         */
-        void acceptSubSections(OptionsModifyingVisitor *visitor) const;
-        /*! \brief
-         * Visits each option in the wrapped Options object.
-         */
+        //! Visits each section in the wrapped section.
+        void acceptSections(OptionsModifyingVisitor *visitor) const;
+        //! Visits each option in the wrapped section.
         void acceptOptions(OptionsModifyingVisitor *visitor) const;
 
     private:
-        //! The wrapped Options object.
-        Options                &options_;
+        //! The wrapped section object.
+        internal::OptionSectionImpl &section_;
 
         GMX_DISALLOW_COPY_AND_ASSIGN(OptionsModifyingIterator);
 };
diff --git a/src/gromacs/options/repeatingsection.h b/src/gromacs/options/repeatingsection.h
new file mode 100644 (file)
index 0000000..683a41a
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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.
+ */
+/*! \file
+ * \brief
+ * Declares gmx::RepeatingOptionSection and related classes.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inpublicapi
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_REPEATINGSECTION_H
+#define GMX_OPTIONS_REPEATINGSECTION_H
+
+#include <memory>
+#include <vector>
+
+#include "gromacs/options/abstractsection.h"
+#include "gromacs/options/ioptionscontainerwithsections.h"
+#include "gromacs/options/isectionstorage.h"
+#include "gromacs/options/valuestore.h"
+
+namespace gmx
+{
+
+template <class T> class RepeatingOptionSectionHandle;
+template <class T> class RepeatingOptionSectionStorage;
+
+/*! \brief
+ * Declares an option section that creates a structure for each instance.
+ *
+ * \tparam  T  Structure that stores the values for an instance of the section.
+ *
+ * This class declares a section that can be specified multiple times, and
+ * creates an instance of `T` for each instance.  Options within the section
+ * can store their values in the created structure.
+ *
+ * \inpublicapi
+ * \ingroup module_options
+ */
+template <class T>
+class RepeatingOptionSection : public AbstractOptionSection
+{
+    public:
+        //! AbstractOptionSectionHandle corresponding to this option type.
+        typedef RepeatingOptionSectionHandle<T> HandleType;
+
+        //! Creates a section with the given name.
+        explicit RepeatingOptionSection(const char *name)
+            : AbstractOptionSection(name), values_(nullptr)
+        {
+        }
+
+        //! Specifies a vector to receive the section structures.
+        RepeatingOptionSection &storeVector(std::vector<T> *values)
+        {
+            values_ = values;
+            return *this;
+        }
+
+    private:
+        virtual IOptionSectionStorage *createStorage() const;
+
+        std::vector<T> *values_;
+
+        //! Allows accessing the properties when initializing the storage.
+        friend class RepeatingOptionSectionStorage<T>;
+};
+
+/*! \internal
+ * \brief
+ * Implements handling of the structures that stores per-section values.
+ *
+ * \ingroup module_options
+ */
+template <class T>
+class RepeatingOptionSectionStorage : public IOptionSectionStorage
+{
+    public:
+        //! Initializes the storage for given section properties.
+        explicit RepeatingOptionSectionStorage(const RepeatingOptionSection<T> &section)
+            : store_(new OptionValueStoreVector<T>(section.values_)), currentData_()
+        {
+        }
+
+        virtual void initStorage()
+        {
+            defaultValues_ = currentData_;
+        }
+        virtual void startSection()
+        {
+            resetSection();
+        }
+        virtual void finishSection()
+        {
+            store_->append(currentData_);
+            resetSection();
+        }
+
+    private:
+        void resetSection()
+        {
+            currentData_ = defaultValues_;
+        }
+
+        //! Final storage location for the section structures.
+        const std::unique_ptr<IOptionValueStore<T> > store_;
+        T                                            defaultValues_;
+        /*! \brief
+         * Stores the values for the current in-process section.
+         *
+         * Options within the section store their values to this structure, and
+         * they are then copied to the final storage when the section finishes.
+         */
+        T                                            currentData_;
+
+        //! Allows binding option storage to the current section data structure.
+        friend class RepeatingOptionSectionHandle<T>;
+};
+
+template <class T>
+IOptionSectionStorage *RepeatingOptionSection<T>::createStorage() const
+{
+    return new RepeatingOptionSectionStorage<T>(*this);
+}
+
+/*! \brief
+ * Allows adding options to an RepeatingOptionSection.
+ *
+ * An instance of this class is returned from
+ * IOptionsContainerWithSections::addSection(), and supports adding options and
+ * subsections to a section created with OptionSection.
+ *
+ * Example:
+ * \code
+   struct SectionData { int value; }
+   // as class attribute
+   std::vector<SectionData> values;
+
+   void MyClass::initOptions(gmx::IOptionsContainerWithSections *options)
+   {
+       auto sec = options->addSection(gmx::RepeatingOptionSection<SectionData>("sec").storeVector(&values));
+       sec->addOption(gmx::IntegerOption("arg").store(&sec.bind().value));
+   }
+   \endcode
+ *
+ * \inpublicapi
+ * \ingroup module_options
+ */
+template <class T>
+class RepeatingOptionSectionHandle : public AbstractOptionSectionHandle
+{
+    public:
+        //! Wraps a given section storage object.
+        explicit RepeatingOptionSectionHandle(internal::OptionSectionImpl *section)
+            : AbstractOptionSectionHandle(section),
+              storage_(getStorage<RepeatingOptionSectionStorage<T> >(section))
+        {
+        }
+
+        /*! \brief
+         * Supports storing option values within the per-section data structure.
+         *
+         * See class documentation for an example.
+         */
+        T &bind()
+        {
+            return storage_->currentData_;
+        }
+
+    private:
+        RepeatingOptionSectionStorage<T> *storage_;
+};
+
+} // namespace gmx
+
+#endif
index 21806d0aed9d027c61fbd37d476f7336763d8f89..e99c2a97750dff81e3e373d85cc5b80eeda24715 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2010,2011,2012,2014, by the GROMACS development team, led by
+# Copyright (c) 2010,2011,2012,2014,2016, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -38,4 +38,7 @@ gmx_add_unit_test(OptionsUnitTests options-test
                   filenameoptionmanager.cpp
                   option.cpp
                   optionsassigner.cpp
-                  timeunitmanager.cpp)
+                  repeatingsection.cpp
+                  timeunitmanager.cpp
+                  treesupport.cpp
+                  )
index 1682129575a0eec6f53c8cd1fd2ef746797d64d5..729607aeec2742b686ec2fd711755e33035c52a5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2016, 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.
@@ -90,7 +90,7 @@ class MockOptionStorage : public gmx::OptionStorageTemplate<std::string>
          *
          * \param[in] settings   Storage settings.
          */
-        MockOptionStorage(const MockOption &settings);
+        explicit MockOptionStorage(const MockOption &settings);
 
         /*! \brief
          * Calls addValue("dummy") in the base class.
@@ -99,25 +99,9 @@ class MockOptionStorage : public gmx::OptionStorageTemplate<std::string>
         {
             addValue("dummy");
         }
-        // using MyBase::markAsSet;
-        // using MyBase::addValue;
-        // using MyBase::commitValues;
-        // "using" is correct but MSVC gives error C2248. Workaround:
-        //! \copydoc gmx::OptionStorageTemplate::markAsSet()
-        void markAsSet()
-        {
-            MyBase::markAsSet();
-        }
-        //! \copydoc gmx::OptionStorageTemplate::addValue()
-        void addValue(const std::string &value)
-        {
-            MyBase::addValue(value);
-        }
-        //! \copydoc gmx::OptionStorageTemplate::commitValues()
-        void commitValues()
-        {
-            MyBase::commitValues();
-        }
+        using MyBase::markAsSet;
+        using MyBase::addValue;
+        using MyBase::commitValues;
 
         virtual gmx::OptionInfo &optionInfo() { return info_; }
         // These are not used.
@@ -127,6 +111,11 @@ class MockOptionStorage : public gmx::OptionStorageTemplate<std::string>
             return "";
         }
 
+        virtual void convertValue(const gmx::Variant &value)
+        {
+            convertValue(value.cast<std::string>());
+        }
+
         MOCK_METHOD1(convertValue, void(const std::string &value));
         MOCK_METHOD1(processSetValues, void(ValueList *values));
         MOCK_METHOD0(processAll, void());
@@ -186,7 +175,7 @@ MockOptionStorage &MockOptionInfo::option()
  */
 TEST(AbstractOptionStorageTest, HandlesSetInFinish)
 {
-    gmx::Options                options(NULL, NULL);
+    gmx::Options                options;
     std::vector<std::string>    values;
     MockOptionInfo             *info = options.addOption(
                 MockOption("name").required().storeVector(&values));
@@ -216,7 +205,7 @@ TEST(AbstractOptionStorageTest, HandlesSetInFinish)
  */
 TEST(AbstractOptionStorageTest, HandlesValueRemoval)
 {
-    gmx::Options                options(NULL, NULL);
+    gmx::Options                options;
     std::vector<std::string>    values;
     MockOptionInfo             *info = options.addOption(
                 MockOption("name").storeVector(&values).multiValue());
@@ -255,7 +244,7 @@ TEST(AbstractOptionStorageTest, HandlesValueRemoval)
  */
 TEST(AbstractOptionStorageTest, HandlesValueAddition)
 {
-    gmx::Options                options(NULL, NULL);
+    gmx::Options                options;
     std::vector<std::string>    values;
     MockOptionInfo             *info = options.addOption(
                 MockOption("name").storeVector(&values).multiValue());
@@ -295,7 +284,7 @@ TEST(AbstractOptionStorageTest, HandlesValueAddition)
  */
 TEST(AbstractOptionStorageTest, HandlesTooManyValueAddition)
 {
-    gmx::Options                options(NULL, NULL);
+    gmx::Options                options;
     std::vector<std::string>    values;
     MockOptionInfo             *info = options.addOption(
                 MockOption("name").storeVector(&values).valueCount(2));
@@ -331,7 +320,7 @@ TEST(AbstractOptionStorageTest, HandlesTooManyValueAddition)
  */
 TEST(AbstractOptionStorageTest, AllowsEmptyValues)
 {
-    gmx::Options                options(NULL, NULL);
+    gmx::Options                options;
     std::vector<std::string>    values;
     MockOptionInfo             *info = options.addOption(
                 MockOption("name").storeVector(&values).valueCount(0));
index 5ae358f3cbb3044d3d1a702599ffa5bb3ab3a37b..2d3cde55f528c945ba9e2f3041192148e04eaa13 100644 (file)
@@ -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
  * 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.
@@ -59,7 +59,7 @@ using gmx::FileNameOption;
 
 TEST(FileNameOptionTest, HandlesRequiredDefaultValueWithoutExtension)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     ASSERT_NO_THROW_GMX(options.addOption(
                                 FileNameOption("f").store(&value).required()
@@ -77,7 +77,7 @@ TEST(FileNameOptionTest, HandlesRequiredDefaultValueWithoutExtension)
 
 TEST(FileNameOptionTest, HandlesRequiredOptionWithoutValue)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     ASSERT_NO_THROW_GMX(options.addOption(
                                 FileNameOption("f").store(&value).required()
@@ -97,7 +97,7 @@ TEST(FileNameOptionTest, HandlesRequiredOptionWithoutValue)
 
 TEST(FileNameOptionTest, HandlesOptionalUnsetOption)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     ASSERT_NO_THROW_GMX(options.addOption(
                                 FileNameOption("f").store(&value)
@@ -115,7 +115,7 @@ TEST(FileNameOptionTest, HandlesOptionalUnsetOption)
 
 TEST(FileNameOptionTest, HandlesOptionalDefaultValueWithoutExtension)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     ASSERT_NO_THROW_GMX(options.addOption(
                                 FileNameOption("f").store(&value)
@@ -135,7 +135,7 @@ TEST(FileNameOptionTest, HandlesOptionalDefaultValueWithoutExtension)
 
 TEST(FileNameOptionTest, HandlesRequiredCustomDefaultExtension)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     ASSERT_NO_THROW_GMX(options.addOption(
                                 FileNameOption("f").store(&value).required()
@@ -154,7 +154,7 @@ TEST(FileNameOptionTest, HandlesRequiredCustomDefaultExtension)
 
 TEST(FileNameOptionTest, HandlesOptionalCustomDefaultExtension)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     ASSERT_NO_THROW_GMX(options.addOption(
                                 FileNameOption("f").store(&value)
@@ -175,7 +175,7 @@ TEST(FileNameOptionTest, HandlesOptionalCustomDefaultExtension)
 
 TEST(FileNameOptionTest, GivesErrorOnUnknownFileSuffix)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     ASSERT_NO_THROW_GMX(options.addOption(
                                 FileNameOption("f").store(&value)
@@ -195,7 +195,7 @@ TEST(FileNameOptionTest, GivesErrorOnUnknownFileSuffix)
 
 TEST(FileNameOptionTest, GivesErrorOnInvalidFileSuffix)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     ASSERT_NO_THROW_GMX(options.addOption(
                                 FileNameOption("f").store(&value)
index 6992689febcd245d5730cb8b3ad2e0cc31e6fa15..9a67461c05ebf87065b4c9fbd8bec1fe28ac50b4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016, 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.
@@ -63,7 +63,6 @@ class FileNameOptionManagerTest : public ::testing::Test
 {
     public:
         FileNameOptionManagerTest()
-            : options_(NULL, NULL)
         {
             manager_.setInputRedirector(&redirector_);
             options_.addManager(&manager_);
index 5d6cf976b66e85be1c1eb2cbc8969b402a1b4a76..c9d85b2b9bb223d5c7a9c60117e5c0119559bfa4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, 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.
@@ -60,7 +60,7 @@ namespace
 
 TEST(OptionsTest, FailsOnNonsafeStorage)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = -1;
     using gmx::IntegerOption;
     ASSERT_THROW_GMX(options.addOption(IntegerOption("name").store(&value)
index b9dd8eb5f8f77a7581388e1ad97bb74d29fd0c33..283fddc9609fa014b2f50c4b51d2c6e6759a864b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, 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.
@@ -56,6 +56,7 @@
 
 #include "gromacs/options/basicoptions.h"
 #include "gromacs/options/options.h"
+#include "gromacs/options/optionsection.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/stringutil.h"
 
@@ -70,7 +71,7 @@ namespace
 
 TEST(OptionsAssignerTest, HandlesMissingRequiredParameter)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = 0;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(
@@ -81,7 +82,7 @@ TEST(OptionsAssignerTest, HandlesMissingRequiredParameter)
 
 TEST(OptionsAssignerTest, HandlesRequiredParameterWithDefaultValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = 0;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(
@@ -94,7 +95,7 @@ TEST(OptionsAssignerTest, HandlesRequiredParameterWithDefaultValue)
 
 TEST(OptionsAssignerTest, HandlesInvalidMultipleParameter)
 {
-    gmx::Options     options(NULL, NULL);
+    gmx::Options     options;
     std::vector<int> values;
     bool             bIsSet = false;
     using gmx::IntegerOption;
@@ -119,7 +120,7 @@ TEST(OptionsAssignerTest, HandlesInvalidMultipleParameter)
 
 TEST(OptionsAssignerTest, HandlesMultipleParameter)
 {
-    gmx::Options     options(NULL, NULL);
+    gmx::Options     options;
     std::vector<int> values;
     bool             bIsSet = false;
     using gmx::IntegerOption;
@@ -147,7 +148,7 @@ TEST(OptionsAssignerTest, HandlesMultipleParameter)
 
 TEST(OptionsAssignerTest, HandlesMissingValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value1 = 0, value2 = 0;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value1)));
@@ -168,7 +169,7 @@ TEST(OptionsAssignerTest, HandlesMissingValue)
 
 TEST(OptionsAssignerTest, HandlesExtraValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value1 = 0;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value1)));
@@ -187,7 +188,7 @@ TEST(OptionsAssignerTest, HandlesExtraValue)
 
 TEST(OptionsAssignerTest, HandlesGroups)
 {
-    gmx::Options            options(NULL, NULL);
+    gmx::Options            options;
     gmx::IOptionsContainer &group1 = options.addGroup();
     gmx::IOptionsContainer &group2 = options.addGroup();
     int                     value  = 3;
@@ -217,36 +218,35 @@ TEST(OptionsAssignerTest, HandlesGroups)
     EXPECT_EQ(6, value2);
 }
 
-TEST(OptionsAssignerTest, HandlesSubSections)
+TEST(OptionsAssignerTest, HandlesSections)
 {
-    gmx::Options options(NULL, NULL);
-    gmx::Options sub1("section1", NULL);
-    gmx::Options sub2("section2", NULL);
+    using gmx::OptionSection;
+    gmx::Options options;
+    auto         sub1   = options.addSection(OptionSection("section1"));
+    auto         sub2   = options.addSection(OptionSection("section2"));
     int          value  = 3;
     int          value1 = 1;
     int          value2 = 2;
     using gmx::IntegerOption;
-    ASSERT_NO_THROW(options.addSubSection(&sub1));
-    ASSERT_NO_THROW(options.addSubSection(&sub2));
-    ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
-    ASSERT_NO_THROW(sub1.addOption(IntegerOption("p").store(&value1)));
-    ASSERT_NO_THROW(sub2.addOption(IntegerOption("p").store(&value2)));
+    ASSERT_NO_THROW_GMX(options.addOption(IntegerOption("p").store(&value)));
+    ASSERT_NO_THROW_GMX(sub1.addOption(IntegerOption("p").store(&value1)));
+    ASSERT_NO_THROW_GMX(sub2.addOption(IntegerOption("p").store(&value2)));
 
     gmx::OptionsAssigner assigner(&options);
     EXPECT_NO_THROW(assigner.start());
-    ASSERT_NO_THROW(assigner.startSubSection("section1"));
+    ASSERT_NO_THROW(assigner.startSection("section1"));
     ASSERT_NO_THROW(assigner.startOption("p"));
     EXPECT_NO_THROW(assigner.appendValue("5"));
     EXPECT_NO_THROW(assigner.finishOption());
-    EXPECT_NO_THROW(assigner.finishSubSection());
+    EXPECT_NO_THROW(assigner.finishSection());
     ASSERT_NO_THROW(assigner.startOption("p"));
     EXPECT_NO_THROW(assigner.appendValue("4"));
     EXPECT_NO_THROW(assigner.finishOption());
-    ASSERT_NO_THROW(assigner.startSubSection("section2"));
+    ASSERT_NO_THROW(assigner.startSection("section2"));
     ASSERT_NO_THROW(assigner.startOption("p"));
     EXPECT_NO_THROW(assigner.appendValue("6"));
     EXPECT_NO_THROW(assigner.finishOption());
-    EXPECT_NO_THROW(assigner.finishSubSection());
+    EXPECT_NO_THROW(assigner.finishSection());
     EXPECT_NO_THROW(assigner.finish());
     EXPECT_NO_THROW(options.finish());
 
@@ -257,7 +257,7 @@ TEST(OptionsAssignerTest, HandlesSubSections)
 
 TEST(OptionsAssignerTest, HandlesMultipleSources)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = -1;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
@@ -290,7 +290,7 @@ TEST(OptionsAssignerTest, HandlesMultipleSources)
 
 TEST(OptionsAssignerBooleanTest, StoresYesValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     bool         value = false;
     using gmx::BooleanOption;
     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
@@ -308,7 +308,7 @@ TEST(OptionsAssignerBooleanTest, StoresYesValue)
 
 TEST(OptionsAssignerBooleanTest, SetsBooleanWithoutExplicitValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     bool         value = false;
     using gmx::BooleanOption;
     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
@@ -325,7 +325,7 @@ TEST(OptionsAssignerBooleanTest, SetsBooleanWithoutExplicitValue)
 
 TEST(OptionsAssignerBooleanTest, ClearsBooleanWithPrefixNo)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     bool         value = true;
     using gmx::BooleanOption;
     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
@@ -343,7 +343,7 @@ TEST(OptionsAssignerBooleanTest, ClearsBooleanWithPrefixNo)
 
 TEST(OptionsAssignerBooleanTest, HandlesBooleanWithPrefixAndValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     bool         value = false;
     using gmx::BooleanOption;
     ASSERT_NO_THROW(options.addOption(BooleanOption("p").store(&value)));
@@ -374,7 +374,7 @@ TEST(OptionsAssignerBooleanTest, HandlesBooleanWithPrefixAndValue)
 
 TEST(OptionsAssignerIntegerTest, StoresSingleValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = 1;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
@@ -392,7 +392,7 @@ TEST(OptionsAssignerIntegerTest, StoresSingleValue)
 
 TEST(OptionsAssignerIntegerTest, HandlesEmptyValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = 1;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
@@ -410,7 +410,7 @@ TEST(OptionsAssignerIntegerTest, HandlesEmptyValue)
 
 TEST(OptionsAssignerIntegerTest, HandlesInvalidValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = 1;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
@@ -428,7 +428,7 @@ TEST(OptionsAssignerIntegerTest, HandlesInvalidValue)
 
 TEST(OptionsAssignerIntegerTest, HandlesOverflow)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = 1;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(&value)));
@@ -448,7 +448,7 @@ TEST(OptionsAssignerIntegerTest, HandlesOverflow)
 
 TEST(OptionsAssignerIntegerTest, StoresDefaultValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = -1;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(
@@ -465,7 +465,7 @@ TEST(OptionsAssignerIntegerTest, StoresDefaultValue)
 
 TEST(OptionsAssignerIntegerTest, StoresDefaultValueIfSet)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = -1;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(
@@ -484,7 +484,7 @@ TEST(OptionsAssignerIntegerTest, StoresDefaultValueIfSet)
 
 TEST(OptionsAssignerIntegerTest, HandlesDefaultValueIfSetWhenNotSet)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = -1;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(
@@ -501,7 +501,7 @@ TEST(OptionsAssignerIntegerTest, HandlesDefaultValueIfSetWhenNotSet)
 
 TEST(OptionsAssignerIntegerTest, HandlesBothDefaultValues)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          value = -1;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(
@@ -521,7 +521,7 @@ TEST(OptionsAssignerIntegerTest, HandlesBothDefaultValues)
 
 TEST(OptionsAssignerIntegerTest, StoresToVector)
 {
-    gmx::Options          options(NULL, NULL);
+    gmx::Options          options;
     std::vector<int>      values;
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(
@@ -545,7 +545,7 @@ TEST(OptionsAssignerIntegerTest, StoresToVector)
 
 TEST(OptionsAssignerIntegerTest, HandlesVectors)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          vec[3] = {0, 0, 0};
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec).vector()));
@@ -567,7 +567,7 @@ TEST(OptionsAssignerIntegerTest, HandlesVectors)
 
 TEST(OptionsAssignerIntegerTest, HandlesVectorFromSingleValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          vec[3] = {0, 0, 0};
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec).vector()));
@@ -587,7 +587,7 @@ TEST(OptionsAssignerIntegerTest, HandlesVectorFromSingleValue)
 
 TEST(OptionsAssignerIntegerTest, HandlesVectorsWithDefaultValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     int          vec[3] = {3, 2, 1};
     using gmx::IntegerOption;
     ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec).vector()));
@@ -601,12 +601,10 @@ TEST(OptionsAssignerIntegerTest, HandlesVectorsWithDefaultValue)
 
 TEST(OptionsAssignerIntegerTest, HandlesVectorsWithDefaultValueWithInvalidAssignment)
 {
-    gmx::Options     options(NULL, NULL);
+    gmx::Options     options;
     int              vec[3] = {3, 2, 1};
-    std::vector<int> vec2(vec, vec+3);
     using gmx::IntegerOption;
-    ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec)
-                                          .storeVector(&vec2).vector()));
+    ASSERT_NO_THROW(options.addOption(IntegerOption("p").store(vec).vector()));
 
     gmx::OptionsAssigner assigner(&options);
     EXPECT_NO_THROW(assigner.start());
@@ -620,10 +618,6 @@ TEST(OptionsAssignerIntegerTest, HandlesVectorsWithDefaultValueWithInvalidAssign
     EXPECT_EQ(3, vec[0]);
     EXPECT_EQ(2, vec[1]);
     EXPECT_EQ(1, vec[2]);
-    ASSERT_EQ(3U, vec2.size());
-    EXPECT_EQ(3, vec2[0]);
-    EXPECT_EQ(2, vec2[1]);
-    EXPECT_EQ(1, vec2[2]);
 }
 
 
@@ -633,7 +627,7 @@ TEST(OptionsAssignerIntegerTest, HandlesVectorsWithDefaultValueWithInvalidAssign
 
 TEST(OptionsAssignerDoubleTest, StoresSingleValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     double       value = 0.0;
     using gmx::DoubleOption;
     ASSERT_NO_THROW(options.addOption(DoubleOption("p").store(&value)));
@@ -651,7 +645,7 @@ TEST(OptionsAssignerDoubleTest, StoresSingleValue)
 
 TEST(OptionsAssignerDoubleTest, HandlesEmptyValue)
 {
-    gmx::Options options(NULL, NULL);
+    gmx::Options options;
     double       value = 1.0;
     using gmx::DoubleOption;
     ASSERT_NO_THROW(options.addOption(DoubleOption("p").store(&value)));
@@ -667,6 +661,44 @@ TEST(OptionsAssignerDoubleTest, HandlesEmptyValue)
     EXPECT_DOUBLE_EQ(1.0, value);
 }
 
+TEST(OptionsAssignerDoubleTest, HandlesPreSetScaleValue)
+{
+    gmx::Options           options;
+    double                 value = 1.0;
+    using gmx::DoubleOption;
+    gmx::DoubleOptionInfo *info = options.addOption(DoubleOption("p").store(&value));
+    EXPECT_NO_THROW(info->setScaleFactor(10));
+
+    gmx::OptionsAssigner assigner(&options);
+    EXPECT_NO_THROW(assigner.start());
+    ASSERT_NO_THROW(assigner.startOption("p"));
+    ASSERT_NO_THROW(assigner.appendValue("2.7"));
+    EXPECT_NO_THROW(assigner.finishOption());
+    EXPECT_NO_THROW(assigner.finish());
+    EXPECT_NO_THROW(options.finish());
+
+    EXPECT_DOUBLE_EQ(27, value);
+}
+
+TEST(OptionsAssignerDoubleTest, HandlesPostSetScaleValue)
+{
+    gmx::Options           options;
+    double                 value = 1.0;
+    using gmx::DoubleOption;
+    gmx::DoubleOptionInfo *info = options.addOption(DoubleOption("p").store(&value));
+
+    gmx::OptionsAssigner   assigner(&options);
+    EXPECT_NO_THROW(assigner.start());
+    ASSERT_NO_THROW(assigner.startOption("p"));
+    ASSERT_NO_THROW(assigner.appendValue("2.7"));
+    EXPECT_NO_THROW(assigner.finishOption());
+    EXPECT_NO_THROW(assigner.finish());
+    EXPECT_NO_THROW(info->setScaleFactor(10));
+    EXPECT_NO_THROW(options.finish());
+
+    EXPECT_DOUBLE_EQ(27, value);
+}
+
 
 /********************************************************************
  * Tests for string assignment
@@ -677,7 +709,7 @@ const char *const c_allowed[] = { "none", "test", "value" };
 
 TEST(OptionsAssignerStringTest, StoresSingleValue)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     using gmx::StringOption;
     ASSERT_NO_THROW(options.addOption(StringOption("p").store(&value)));
@@ -695,7 +727,7 @@ TEST(OptionsAssignerStringTest, StoresSingleValue)
 
 TEST(OptionsAssignerStringTest, HandlesEnumValue)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     using gmx::StringOption;
     ASSERT_NO_THROW(options.addOption(
@@ -715,7 +747,7 @@ TEST(OptionsAssignerStringTest, HandlesEnumValue)
 
 TEST(OptionsAssignerStringTest, HandlesEnumValueFromNullTerminatedArray)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     const char * const     allowed[] = { "none", "test", "value", NULL };
     using gmx::StringOption;
@@ -736,7 +768,7 @@ TEST(OptionsAssignerStringTest, HandlesEnumValueFromNullTerminatedArray)
 
 TEST(OptionsAssignerStringTest, HandlesIncorrectEnumValue)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     using gmx::StringOption;
     ASSERT_NO_THROW(options.addOption(
@@ -751,7 +783,7 @@ TEST(OptionsAssignerStringTest, HandlesIncorrectEnumValue)
 
 TEST(OptionsAssignerStringTest, CompletesEnumValue)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     using gmx::StringOption;
     ASSERT_NO_THROW(options.addOption(
@@ -771,7 +803,7 @@ TEST(OptionsAssignerStringTest, CompletesEnumValue)
 
 TEST(OptionsAssignerStringTest, HandlesEnumWithNoValue)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     using gmx::StringOption;
     ASSERT_NO_THROW(options.addOption(
@@ -786,7 +818,7 @@ TEST(OptionsAssignerStringTest, HandlesEnumWithNoValue)
 
 TEST(OptionsAssignerStringTest, HandlesEnumDefaultValue)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value;
     using gmx::StringOption;
     ASSERT_NO_THROW(options.addOption(
@@ -804,7 +836,7 @@ TEST(OptionsAssignerStringTest, HandlesEnumDefaultValue)
 
 TEST(OptionsAssignerStringTest, HandlesEnumDefaultValueFromVariable)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::string            value("test");
     using gmx::StringOption;
     ASSERT_NO_THROW(options.addOption(
@@ -822,10 +854,10 @@ TEST(OptionsAssignerStringTest, HandlesEnumDefaultValueFromVariable)
 
 TEST(OptionsAssignerStringTest, HandlesEnumDefaultValueFromVector)
 {
-    gmx::Options             options(NULL, NULL);
+    gmx::Options             options;
     std::vector<std::string> value;
-    value.push_back("test");
-    value.push_back("value");
+    value.emplace_back("test");
+    value.emplace_back("value");
     using gmx::StringOption;
     ASSERT_NO_THROW(options.addOption(
                             StringOption("p").storeVector(&value).valueCount(2)
@@ -860,7 +892,7 @@ enum TestEnum
 
 TEST(OptionsAssignerEnumTest, StoresSingleValue)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     TestEnum               value     = etestNone;
     using gmx::EnumOption;
     ASSERT_NO_THROW(options.addOption(
@@ -881,7 +913,7 @@ TEST(OptionsAssignerEnumTest, StoresSingleValue)
 
 TEST(OptionsAssignerEnumTest, StoresVectorValues)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     std::vector<TestEnum>  values;
     using gmx::EnumOption;
     ASSERT_NO_THROW(options.addOption(
@@ -905,7 +937,7 @@ TEST(OptionsAssignerEnumTest, StoresVectorValues)
 
 TEST(OptionsAssignerEnumTest, HandlesInitialValueOutOfRange)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     TestEnum               value     = etestNR;
     using gmx::EnumOption;
     ASSERT_NO_THROW(options.addOption(
@@ -923,7 +955,7 @@ TEST(OptionsAssignerEnumTest, HandlesInitialValueOutOfRange)
 
 TEST(OptionsAssignerEnumTest, HandlesEnumDefaultValue)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     TestEnum               value     = etestNone;
     using gmx::EnumOption;
     ASSERT_NO_THROW(options.addOption(
@@ -941,7 +973,7 @@ TEST(OptionsAssignerEnumTest, HandlesEnumDefaultValue)
 
 TEST(OptionsAssignerEnumTest, HandlesEnumDefaultValueFromVariable)
 {
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     TestEnum               value     = etestTest;
     using gmx::EnumOption;
     ASSERT_NO_THROW(options.addOption(
@@ -959,7 +991,7 @@ TEST(OptionsAssignerEnumTest, HandlesEnumDefaultValueFromVariable)
 
 TEST(OptionsAssignerEnumTest, HandlesEnumDefaultValueFromVector)
 {
-    gmx::Options             options(NULL, NULL);
+    gmx::Options             options;
     std::vector<TestEnum>    value;
     value.push_back(etestNone);
     value.push_back(etestTest);
diff --git a/src/gromacs/options/tests/repeatingsection.cpp b/src/gromacs/options/tests/repeatingsection.cpp
new file mode 100644 (file)
index 0000000..faf16c2
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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.
+ */
+/*! \internal \file
+ * \brief
+ * Tests functionality related to repeating sections.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_options
+ */
+#include "gmxpre.h"
+
+#include "gromacs/options/repeatingsection.h"
+
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/options.h"
+#include "gromacs/options/optionsassigner.h"
+
+#include "testutils/testasserts.h"
+
+namespace
+{
+
+using gmx::RepeatingOptionSection;
+
+struct SectionData
+{
+    int value;
+};
+
+TEST(RepeatingOptionSectionTest, HandlesNoInstance)
+{
+    std::vector<SectionData> values;
+    gmx::Options             options;
+    auto                     sec = options.addSection(
+                RepeatingOptionSection<SectionData>("section")
+                    .storeVector(&values));
+    using gmx::IntegerOption;
+    ASSERT_NO_THROW_GMX(sec.addOption(IntegerOption("p").store(&sec.bind().value)));
+
+    gmx::OptionsAssigner assigner(&options);
+    EXPECT_NO_THROW_GMX(assigner.start());
+    EXPECT_NO_THROW_GMX(assigner.finish());
+    EXPECT_NO_THROW_GMX(options.finish());
+
+    EXPECT_EQ(0U, values.size());
+}
+
+TEST(RepeatingOptionSectionTest, HandlesNoInstanceWithRequiredOption)
+{
+    std::vector<SectionData> values;
+    gmx::Options             options;
+    auto                     sec = options.addSection(
+                RepeatingOptionSection<SectionData>("section")
+                    .storeVector(&values));
+    using gmx::IntegerOption;
+    ASSERT_NO_THROW_GMX(sec.addOption(IntegerOption("p").store(&sec.bind().value)
+                                          .required()));
+
+    gmx::OptionsAssigner assigner(&options);
+    EXPECT_NO_THROW_GMX(assigner.start());
+    EXPECT_NO_THROW_GMX(assigner.finish());
+    EXPECT_NO_THROW_GMX(options.finish());
+
+    EXPECT_EQ(0U, values.size());
+}
+
+TEST(RepeatingOptionSectionTest, HandlesSingleInstance)
+{
+    std::vector<SectionData> values;
+    gmx::Options             options;
+    auto                     sec = options.addSection(
+                RepeatingOptionSection<SectionData>("section")
+                    .storeVector(&values));
+    using gmx::IntegerOption;
+    ASSERT_NO_THROW_GMX(sec.addOption(IntegerOption("p").store(&sec.bind().value)));
+
+    gmx::OptionsAssigner assigner(&options);
+    EXPECT_NO_THROW_GMX(assigner.start());
+    ASSERT_NO_THROW_GMX(assigner.startSection("section"));
+    ASSERT_NO_THROW_GMX(assigner.startOption("p"));
+    EXPECT_NO_THROW_GMX(assigner.appendValue("4"));
+    EXPECT_NO_THROW_GMX(assigner.finishOption());
+    EXPECT_NO_THROW_GMX(assigner.finishSection());
+    EXPECT_NO_THROW_GMX(assigner.finish());
+    EXPECT_NO_THROW_GMX(options.finish());
+
+    ASSERT_EQ(1U, values.size());
+    EXPECT_EQ(4, values[0].value);
+}
+
+TEST(RepeatingOptionSectionTest, HandlesDefaultValue)
+{
+    std::vector<SectionData> values;
+    gmx::Options             options;
+    auto                     sec = options.addSection(
+                RepeatingOptionSection<SectionData>("section")
+                    .storeVector(&values));
+    using gmx::IntegerOption;
+    ASSERT_NO_THROW_GMX(sec.addOption(IntegerOption("p").store(&sec.bind().value)
+                                          .defaultValue(3)));
+
+    gmx::OptionsAssigner assigner(&options);
+    EXPECT_NO_THROW_GMX(assigner.start());
+    ASSERT_NO_THROW_GMX(assigner.startSection("section"));
+    EXPECT_NO_THROW_GMX(assigner.finishSection());
+    EXPECT_NO_THROW_GMX(assigner.finish());
+    EXPECT_NO_THROW_GMX(options.finish());
+
+    ASSERT_EQ(1U, values.size());
+    EXPECT_EQ(3, values[0].value);
+}
+
+TEST(RepeatingOptionSectionTest, HandlesTwoInstances)
+{
+    std::vector<SectionData> values;
+    gmx::Options             options;
+    auto                     sec = options.addSection(
+                RepeatingOptionSection<SectionData>("section")
+                    .storeVector(&values));
+    using gmx::IntegerOption;
+    ASSERT_NO_THROW_GMX(sec.addOption(IntegerOption("p").store(&sec.bind().value)));
+
+    gmx::OptionsAssigner assigner(&options);
+    EXPECT_NO_THROW_GMX(assigner.start());
+    ASSERT_NO_THROW_GMX(assigner.startSection("section"));
+    ASSERT_NO_THROW_GMX(assigner.startOption("p"));
+    EXPECT_NO_THROW_GMX(assigner.appendValue("4"));
+    EXPECT_NO_THROW_GMX(assigner.finishOption());
+    EXPECT_NO_THROW_GMX(assigner.finishSection());
+    ASSERT_NO_THROW_GMX(assigner.startSection("section"));
+    ASSERT_NO_THROW_GMX(assigner.startOption("p"));
+    EXPECT_NO_THROW_GMX(assigner.appendValue("5"));
+    EXPECT_NO_THROW_GMX(assigner.finishOption());
+    EXPECT_NO_THROW_GMX(assigner.finishSection());
+    EXPECT_NO_THROW_GMX(assigner.finish());
+    EXPECT_NO_THROW_GMX(options.finish());
+
+    ASSERT_EQ(2U, values.size());
+    EXPECT_EQ(4, values[0].value);
+    EXPECT_EQ(5, values[1].value);
+}
+
+TEST(RepeatingOptionSectionTest, HandlesUnsetOptionWithImplicitDefault)
+{
+    std::vector<SectionData> values;
+    gmx::Options             options;
+    auto                     sec = options.addSection(
+                RepeatingOptionSection<SectionData>("section")
+                    .storeVector(&values));
+    using gmx::IntegerOption;
+    ASSERT_NO_THROW_GMX(sec.addOption(IntegerOption("p").store(&sec.bind().value)));
+
+    gmx::OptionsAssigner assigner(&options);
+    EXPECT_NO_THROW_GMX(assigner.start());
+    ASSERT_NO_THROW_GMX(assigner.startSection("section"));
+    ASSERT_NO_THROW_GMX(assigner.startOption("p"));
+    EXPECT_NO_THROW_GMX(assigner.appendValue("4"));
+    EXPECT_NO_THROW_GMX(assigner.finishOption());
+    EXPECT_NO_THROW_GMX(assigner.finishSection());
+    ASSERT_NO_THROW_GMX(assigner.startSection("section"));
+    EXPECT_NO_THROW_GMX(assigner.finishSection());
+    EXPECT_NO_THROW_GMX(assigner.finish());
+    EXPECT_NO_THROW_GMX(options.finish());
+
+    ASSERT_EQ(2U, values.size());
+    EXPECT_EQ(4, values[0].value);
+    EXPECT_EQ(0, values[1].value);
+}
+
+TEST(RepeatingOptionSectionTest, HandlesUnsetOptionWithExplicitDefault)
+{
+    std::vector<SectionData> values;
+    gmx::Options             options;
+    auto                     sec = options.addSection(
+                RepeatingOptionSection<SectionData>("section")
+                    .storeVector(&values));
+    using gmx::IntegerOption;
+    ASSERT_NO_THROW_GMX(sec.addOption(IntegerOption("p").store(&sec.bind().value)
+                                          .defaultValue(1)));
+
+    gmx::OptionsAssigner assigner(&options);
+    EXPECT_NO_THROW_GMX(assigner.start());
+    ASSERT_NO_THROW_GMX(assigner.startSection("section"));
+    ASSERT_NO_THROW_GMX(assigner.startOption("p"));
+    EXPECT_NO_THROW_GMX(assigner.appendValue("4"));
+    EXPECT_NO_THROW_GMX(assigner.finishOption());
+    EXPECT_NO_THROW_GMX(assigner.finishSection());
+    ASSERT_NO_THROW_GMX(assigner.startSection("section"));
+    EXPECT_NO_THROW_GMX(assigner.finishSection());
+    EXPECT_NO_THROW_GMX(assigner.finish());
+    EXPECT_NO_THROW_GMX(options.finish());
+
+    ASSERT_EQ(2U, values.size());
+    EXPECT_EQ(4, values[0].value);
+    EXPECT_EQ(1, values[1].value);
+}
+
+struct NestedSectionData
+{
+    int                      value;
+    std::vector<SectionData> subsec;
+};
+
+TEST(RepeatingOptionSectionTest, HandlesNestedSections)
+{
+    std::vector<NestedSectionData> values;
+    gmx::Options                   options;
+    auto                           sec = options.addSection(
+                RepeatingOptionSection<NestedSectionData>("section")
+                    .storeVector(&values));
+    auto                           subsec = sec.addSection(
+                RepeatingOptionSection<SectionData>("subsec")
+                    .storeVector(&sec.bind().subsec));
+    using gmx::IntegerOption;
+    ASSERT_NO_THROW_GMX(sec.addOption(IntegerOption("p").store(&sec.bind().value)));
+    ASSERT_NO_THROW_GMX(subsec.addOption(IntegerOption("p").store(&subsec.bind().value)));
+
+    gmx::OptionsAssigner assigner(&options);
+    EXPECT_NO_THROW_GMX(assigner.start());
+    ASSERT_NO_THROW_GMX(assigner.startSection("section"));
+    ASSERT_NO_THROW_GMX(assigner.startOption("p"));
+    EXPECT_NO_THROW_GMX(assigner.appendValue("4"));
+    EXPECT_NO_THROW_GMX(assigner.finishOption());
+    ASSERT_NO_THROW_GMX(assigner.startSection("subsec"));
+    ASSERT_NO_THROW_GMX(assigner.startOption("p"));
+    EXPECT_NO_THROW_GMX(assigner.appendValue("5"));
+    EXPECT_NO_THROW_GMX(assigner.finishOption());
+    EXPECT_NO_THROW_GMX(assigner.finishSection());
+    EXPECT_NO_THROW_GMX(assigner.finishSection());
+    EXPECT_NO_THROW_GMX(assigner.finish());
+    EXPECT_NO_THROW_GMX(options.finish());
+
+    ASSERT_EQ(1U, values.size());
+    EXPECT_EQ(4, values[0].value);
+    ASSERT_EQ(1U, values[0].subsec.size());
+    EXPECT_EQ(5, values[0].subsec[0].value);
+}
+
+} // namespace
index a66206b2e7e11b47566cadac06e327be5fe3fbb1..044f81ee7fc80f33aed12ce937f1f747cafb01f9 100644 (file)
@@ -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
  * 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.
@@ -72,7 +72,7 @@ TEST(TimeUnitBehaviorTest, ScalesAssignedOptionValue)
 {
     gmx::TimeUnitBehavior  behavior;
 
-    gmx::Options           options(NULL, NULL);
+    gmx::Options           options;
     double                 value = 0.0;
     using gmx::DoubleOption;
     ASSERT_NO_THROW_GMX(options.addOption(DoubleOption("p").store(&value).timeValue()));
@@ -108,7 +108,7 @@ TEST(TimeUnitBehaviorTest, DoesNotScaleDefaultValues)
 {
     gmx::TimeUnitBehavior behavior;
 
-    gmx::Options          options(NULL, NULL);
+    gmx::Options          options;
     double                value = 1.5, value2 = 0.0;
     using gmx::DoubleOption;
     ASSERT_NO_THROW_GMX(options.addOption(DoubleOption("p").store(&value).timeValue()));
@@ -133,7 +133,7 @@ TEST(TimeUnitBehaviorTest, ScalesUserInputWithMultipleSources)
 {
     gmx::TimeUnitBehavior behavior;
 
-    gmx::Options          options(NULL, NULL);
+    gmx::Options          options;
     double                value = 0.0;
     using gmx::DoubleOption;
     ASSERT_NO_THROW_GMX(options.addOption(DoubleOption("p").store(&value).timeValue()));
@@ -159,7 +159,7 @@ TEST(TimeUnitBehaviorTest, TimeUnitOptionWorks)
 {
     gmx::TimeUnitBehavior behavior;
 
-    gmx::Options          options(NULL, NULL);
+    gmx::Options          options;
     double                value = 0.0;
     using gmx::DoubleOption;
     ASSERT_NO_THROW_GMX(options.addOption(DoubleOption("p").store(&value).timeValue()));
diff --git a/src/gromacs/options/tests/treesupport.cpp b/src/gromacs/options/tests/treesupport.cpp
new file mode 100644 (file)
index 0000000..69c2db0
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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.
+ */
+/*! \internal \file
+ * \brief
+ * Tests option support for operations on KeyValueTree.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_options
+ */
+#include "gmxpre.h"
+
+#include "gromacs/options/treesupport.h"
+
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/options.h"
+#include "gromacs/options/optionsection.h"
+#include "gromacs/options/repeatingsection.h"
+#include "gromacs/utility/keyvaluetree.h"
+#include "gromacs/utility/keyvaluetreebuilder.h"
+
+#include "testutils/testasserts.h"
+
+namespace
+{
+
+TEST(TreeValueSupportTest, AssignsFromTree)
+{
+    int                      a0 = 0, a1 = 0;
+    std::string              b1;
+
+    gmx::Options             options;
+    options.addOption(gmx::IntegerOption("a").store(&a0));
+    auto                     sec = options.addSection(gmx::OptionSection("s"));
+    sec.addOption(gmx::IntegerOption("a").store(&a1));
+    sec.addOption(gmx::StringOption("b").store(&b1));
+
+    gmx::KeyValueTreeBuilder builder;
+    builder.rootObject().addValue<int>("a", 2);
+    auto                     obj = builder.rootObject().addObject("s");
+    obj.addValue<int>("a", 1);
+    obj.addValue<std::string>("b", "foo");
+    gmx::KeyValueTreeObject  tree = builder.build();
+
+    ASSERT_NO_THROW_GMX(gmx::assignOptionsFromKeyValueTree(&options, tree));
+    EXPECT_NO_THROW_GMX(options.finish());
+
+    EXPECT_EQ(2, a0);
+    EXPECT_EQ(1, a1);
+    EXPECT_EQ("foo", b1);
+}
+
+struct SectionData
+{
+    int a;
+};
+
+TEST(TreeValueSupportTest, AssignsFromTreeWithArrays)
+{
+    std::vector<int>         a0;
+    std::vector<SectionData> s;
+
+    gmx::Options             options;
+    options.addOption(gmx::IntegerOption("a").storeVector(&a0).multiValue());
+    auto                     sec = options.addSection(gmx::RepeatingOptionSection<SectionData>("s").storeVector(&s));
+    sec.addOption(gmx::IntegerOption("a").store(&sec.bind().a));
+
+    gmx::KeyValueTreeBuilder builder;
+    auto                     array = builder.rootObject().addUniformArray<int>("a");
+    array.addValue(1);
+    array.addValue(2);
+    auto                     objArray = builder.rootObject().addObjectArray("s");
+    auto                     obj1     = objArray.addObject();
+    obj1.addValue<int>("a", 3);
+    auto                     obj2 = objArray.addObject();
+    obj2.addValue<int>("a", 4);
+    gmx::KeyValueTreeObject  tree = builder.build();
+
+    ASSERT_NO_THROW_GMX(gmx::assignOptionsFromKeyValueTree(&options, tree));
+    EXPECT_NO_THROW_GMX(options.finish());
+
+    ASSERT_EQ(2U, a0.size());
+    EXPECT_EQ(1, a0[0]);
+    EXPECT_EQ(2, a0[1]);
+    ASSERT_EQ(2U, s.size());
+    EXPECT_EQ(3, s[0].a);
+    EXPECT_EQ(4, s[1].a);
+}
+
+} // namespace
index 73f8fc329b081311b76b770a174fb6dbee5ce157..8136f80681eabfcdd88fda6916b7e4071f96b654 100644 (file)
@@ -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
  * 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.
@@ -190,10 +190,10 @@ class TimeOptionScaler : public OptionsModifyingTypeVisitor<FloatingPointOptionI
         //! Initializes a scaler with the given factor.
         explicit TimeOptionScaler(double factor) : factor_(factor) {}
 
-        void visitSubSection(Options *section)
+        void visitSection(OptionSectionInfo *section)
         {
             OptionsModifyingIterator iterator(section);
-            iterator.acceptSubSections(this);
+            iterator.acceptSections(this);
             iterator.acceptOptions(this);
         }
 
@@ -214,8 +214,8 @@ class TimeOptionScaler : public OptionsModifyingTypeVisitor<FloatingPointOptionI
 void TimeUnitBehavior::optionsFinishing(Options *options)
 {
     double factor = TimeUnitManager(timeUnit()).timeScaleFactor();
-    TimeOptionScaler<DoubleOptionInfo>(factor).visitSubSection(options);
-    TimeOptionScaler<FloatOptionInfo>(factor).visitSubSection(options);
+    TimeOptionScaler<DoubleOptionInfo>(factor).visitSection(&options->rootSection());
+    TimeOptionScaler<FloatOptionInfo>(factor).visitSection(&options->rootSection());
     if (timeUnitStore_ != NULL)
     {
         *timeUnitStore_ = static_cast<TimeUnit>(timeUnit_);
diff --git a/src/gromacs/options/treesupport.cpp b/src/gromacs/options/treesupport.cpp
new file mode 100644 (file)
index 0000000..6cca3d2
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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.
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions from treesupport.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_options
+ */
+#include "gmxpre.h"
+
+#include "treesupport.h"
+
+#include "gromacs/options/optionsassigner.h"
+#include "gromacs/utility/keyvaluetree.h"
+
+namespace gmx
+{
+
+namespace
+{
+
+void assignSubTree(OptionsAssigner          *assigner,
+                   const KeyValueTreeObject &tree);
+
+/*! \brief
+ * Helper function for assigning from a KeyValueTreeArray.
+ *
+ * \ingroup module_options
+ */
+void assignArray(OptionsAssigner         *assigner,
+                 const std::string       &key,
+                 const KeyValueTreeArray &array)
+{
+    if (array.isObjectArray())
+    {
+        for (const KeyValueTreeValue &value : array.values())
+        {
+            assigner->startSection(key.c_str());
+            assignSubTree(assigner, value.asObject());
+            assigner->finishSection();
+        }
+    }
+    else
+    {
+        assigner->startOption(key.c_str());
+        for (const KeyValueTreeValue &value : array.values())
+        {
+            assigner->appendValue(value.asVariant());
+        }
+        assigner->finishOption();
+    }
+}
+
+/*! \brief
+ * Helper function for assigning from a KeyValueTreeObject subtree.
+ *
+ * \ingroup module_options
+ */
+void assignSubTree(OptionsAssigner          *assigner,
+                   const KeyValueTreeObject &tree)
+{
+    for (const KeyValueTreeProperty &prop : tree.properties())
+    {
+        if (prop.value().isArray())
+        {
+            assignArray(assigner, prop.key(), prop.value().asArray());
+        }
+        else if (prop.value().isObject())
+        {
+            assigner->startSection(prop.key().c_str());
+            assignSubTree(assigner, prop.value().asObject());
+            assigner->finishSection();
+        }
+        else
+        {
+            assigner->startOption(prop.key().c_str());
+            assigner->appendValue(prop.value().asVariant());
+            assigner->finishOption();
+        }
+    }
+}
+
+}   // namespace
+
+//! \cond libapi
+
+void assignOptionsFromKeyValueTree(Options                  *options,
+                                   const KeyValueTreeObject &tree)
+{
+    OptionsAssigner assigner(options);
+    assigner.start();
+    assignSubTree(&assigner, tree);
+    assigner.finish();
+}
+
+//! \endcond
+
+} // namespace gmx
similarity index 63%
rename from src/gromacs/gmxlib/md_logging.h
rename to src/gromacs/options/treesupport.h
index 8da09734f09707d10d5748e3bad2e042a4b5b5f3..965b06626b6e8ceaeeea1b6785199e9cebd92ab4 100644 (file)
@@ -1,9 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2012,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2016, 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.
  */
-#ifndef GMX_GMXLIB_MD_LOGGING_H
-#define GMX_GMXLIB_MD_LOGGING_H
+/*! \libinternal \file
+ * \brief
+ * Declares functions for using keyvaluetree.h with Options.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_TREESUPPORT_H
+#define GMX_OPTIONS_TREESUPPORT_H
 
-#include <cstdio>
+namespace gmx
+{
 
-struct t_commrec;
+class KeyValueTreeObject;
+class Options;
 
-void md_print_info(const t_commrec *cr, FILE *fplog,
-                   const char *fmt, ...);
-/* Print an general information message to stderr on the master node
- * and to fplog if fplog!=NULL.
- * fmt is a standard printf formatting string which should end in \n,
- * the arguments after that contain the values to be printed, as in printf.
- */
+//! \cond libapi
 
-void md_print_warn(const t_commrec *cr, FILE *fplog,
-                   const char *fmt, ...);
-/* As md_print_info above, but for important notices or warnings.
- * The only difference with md_print_info is that a newline is printed
- * before and after the message such that it stands out.
+/*! \libinternal \brief
+ * Assigns option values from a given KeyValueTreeObject.
+ *
+ * Each property with a simple value (or an array of simple values) is assigned
+ * to an option with the same name.  Objects and arrays of objects are assigned
+ * to sections with the same name.
+ *
+ * \ingroup module_options
  */
+void assignOptionsFromKeyValueTree(Options                  *options,
+                                   const KeyValueTreeObject &tree);
+
+//! \endcond
+
+} // namespace gmx
 
 #endif
diff --git a/src/gromacs/options/valueconverter.h b/src/gromacs/options/valueconverter.h
new file mode 100644 (file)
index 0000000..0f6cec4
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Provides gmx::OptionValueConverterSimple.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_VALUECONVERTER_H
+#define GMX_OPTIONS_VALUECONVERTER_H
+
+#include <functional>
+#include <map>
+#include <typeindex>
+
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/variant.h"
+
+namespace gmx
+{
+
+/*! \libinternal \brief
+ * Helper for converting from Variant to a given type.
+ *
+ * \tparam OutType  Type this converter converts to.
+ *
+ * Default-constructed converter only supports identity mapping from the a
+ * Variant holding `OutType`.  To add support for additional input types,
+ * provide conversion functions with addConverter().  To use a non-identity
+ * mapping for an `OutType` -> `OutType` conversion, provide an alternative
+ * conversion from `OutType` with addConverter().
+ *
+ * \inlibraryapi
+ * \ingroup module_options
+ */
+template <typename OutType>
+class OptionValueConverterSimple
+{
+    public:
+        /*! \brief
+         * Converts a Variant value to the output type.
+         *
+         * \returns  Converted value.
+         * \throws InvalidInputError If the input Variant has a type that is
+         *     not recognized by any conversion.
+         */
+        OutType convert(const Variant &value) const
+        {
+            std::type_index type(value.type());
+            auto            iter = converters_.find(type);
+            if (iter == converters_.end())
+            {
+                if (value.isType<OutType>())
+                {
+                    return value.cast<OutType>();
+                }
+                GMX_THROW(InvalidInputError("Invalid type of value"));
+            }
+            return iter->second(value);
+        }
+
+        /*! \brief
+         * Adds a supported conversion.
+         *
+         * \tparam InType  Type to convert from.
+         * \param  func    Function to convert from `InType` to `OutType`.
+         */
+        template <typename InType>
+        void addConverter(std::function<OutType(const InType &)> func)
+        {
+            converters_[std::type_index(typeid(InType))] =
+                [func] (const Variant &value)
+                {
+                    return func(value.cast<InType>());
+                };
+        }
+
+    private:
+        typedef std::function<OutType(const Variant &value)> ConversionFunction;
+
+        std::map<std::type_index, ConversionFunction> converters_;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/options/valuestore.h b/src/gromacs/options/valuestore.h
new file mode 100644 (file)
index 0000000..3a4730c
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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.
+ */
+/*! \file
+ * \brief
+ * Declares implementations for IOptionValueStore.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_VALUESTORE_H
+#define GMX_OPTIONS_VALUESTORE_H
+
+#include <vector>
+
+#include "gromacs/options/ivaluestore.h"
+#include "gromacs/utility/arrayref.h"
+
+namespace gmx
+{
+
+template <typename T>
+class OptionValueStorePlain : public IOptionValueStore<T>
+{
+    public:
+        OptionValueStorePlain(T *store, int *storeCount, int initialCount)
+            : count_(initialCount), store_(store), storeCount_(storeCount)
+        {
+        }
+
+        virtual int valueCount() { return count_; }
+        virtual ArrayRef<T> values() { return ArrayRef<T>::fromArray(store_, count_); }
+        virtual void clear()
+        {
+            count_ = 0;
+            if (storeCount_ != nullptr)
+            {
+                *storeCount_ = count_;
+            }
+        }
+        virtual void reserve(size_t /*count*/)
+        {
+        }
+        virtual void append(const T &value)
+        {
+            store_[count_] = value;
+            ++count_;
+            if (storeCount_ != nullptr)
+            {
+                *storeCount_ = count_;
+            }
+        }
+
+    private:
+        int                          count_;
+        T                           *store_;
+        int                         *storeCount_;
+};
+
+template <typename T>
+class OptionValueStoreVector : public IOptionValueStore<T>
+{
+    public:
+        // cppcheck-suppress uninitMemberVar
+        explicit OptionValueStoreVector(std::vector<T> *store) : store_(store) {}
+
+        virtual int valueCount() { return static_cast<int>(store_->size()); }
+        virtual ArrayRef<T> values() { return *store_; }
+        virtual void clear() { store_->clear(); }
+        virtual void reserve(size_t count)
+        {
+            store_->reserve(store_->size() + count);
+        }
+        virtual void append(const T &value)
+        {
+            store_->push_back(value);
+        }
+
+    private:
+        std::vector<T> *store_;
+};
+
+// Specialization that works around std::vector<bool> specialities.
+template <>
+class OptionValueStoreVector<bool> : public IOptionValueStore<bool>
+{
+    public:
+        explicit OptionValueStoreVector(std::vector<bool> *store) : store_(store)
+        {
+        }
+
+        virtual int valueCount() { return static_cast<int>(store_->size()); }
+        virtual ArrayRef<bool> values()
+        {
+            return ArrayRef<bool>::fromArray(reinterpret_cast<bool *>(boolStore_.data()),
+                                             boolStore_.size());
+        }
+        virtual void clear()
+        {
+            boolStore_.clear();
+            store_->clear();
+        }
+        virtual void reserve(size_t count)
+        {
+            boolStore_.reserve(boolStore_.size() + count);
+            store_->reserve(store_->size() + count);
+        }
+        virtual void append(const bool &value)
+        {
+            boolStore_.push_back({value});
+            store_->push_back(value);
+        }
+
+    private:
+        struct Bool
+        {
+            bool value;
+        };
+
+        std::vector<Bool>  boolStore_;
+        std::vector<bool> *store_;
+};
+
+/*! \internal
+ * \brief
+ * Value storage that does not store anywhere.
+ *
+ * This is needed because even though the values are not stored anywhere, the
+ * code still expects to access them later through valueCount() and values().
+ *
+ * \ingroup module_options
+ */
+template <typename T>
+class OptionValueStoreNull : public IOptionValueStore<T>
+{
+    public:
+        OptionValueStoreNull() : store_(&vector_) {}
+
+        virtual int valueCount() { return store_.valueCount(); }
+        virtual ArrayRef<T> values() { return store_.values(); }
+        virtual void clear() { store_.clear(); }
+        virtual void reserve(size_t count) { store_.reserve(count); }
+        virtual void append(const T &value) { store_.append(value); }
+
+    private:
+        std::vector<T>            vector_;
+        OptionValueStoreVector<T> store_;
+};
+
+} // namespace gmx
+
+#endif
index bb05dd0b28291eb3ddc620459d56b295490382ba..ac850cfeb87603918218b2c91ad968dc71ab08aa 100644 (file)
@@ -96,8 +96,9 @@ namespace gmx
  *  produce errors. Even for newer compilers, libstdc++ and libc++ appear to
  *  use different algorithms to generate it, which means their values differ
  *  in contrast to the uniform and normal distributions where they are
- *  identical. To avoid both the gcc-4.6 bug and make it easier to use GROMACS
- *   unit tests that depend on random numbers we have our own implementation.
+ *  identical. To avoid both compiler bugs and make it easier to use
+ *  GROMACS unit tests that depend on random numbers, we have our
+ *  own implementation.
  *
  *  Be warned that the gamma distribution works like the standard
  *  normal distribution and keeps drawing values from the random engine
index beb5fd8481e4d7c74151f3c9e13fb815ecb7650d..ccfb25064bf117ebe86585f0b03ad538f7dfa1ca 100644 (file)
@@ -140,7 +140,7 @@ gmx_ana_indexgrps_init(gmx_ana_indexgrps_t **g, t_topology *top,
                 grp->index[j] = block->a[block->index[i]+j];
             }
             grp->nalloc_index = grp->isize;
-            (*g)->names.push_back(names[i]);
+            (*g)->names.emplace_back(names[i]);
         }
     }
     catch (...)
index b65af7c791c0066dc00007c3f9c8ac639984d1b5..49471388783a6487da6ab8d78850a3567a08bca3 100644 (file)
@@ -1,19 +1,19 @@
-/* A Bison parser, made by GNU Bison 2.7.12-4996.  */
+/* A Bison parser, made by GNU Bison 3.0.4.  */
 
 /* Bison implementation for Yacc-like parsers in C
-   
-      Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
-   
+
+   Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
+
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
-   
+
    This program 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 General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
@@ -26,7 +26,7 @@
    special exception, which will cause the skeleton and the resulting
    Bison output files to be licensed under the GNU General Public
    License without this special exception.
-   
+
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 
@@ -44,7 +44,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "2.7.12-4996"
+#define YYBISON_VERSION "3.0.4"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -59,8 +59,7 @@
 #define YYPULL 0
 
 /* "%code top" blocks.  */
-/* Line 349 of yacc.c  */
-#line 43 "parser.y"
+#line 43 "parser.y" /* yacc.c:316  */
 
 /*! \internal \file parser.cpp
  * \brief Generated (from parser.y by Bison) parser for the selection language.
@@ -74,9 +73,7 @@
  */
 #include "gmxpre.h"
 
-
-/* Line 349 of yacc.c  */
-#line 80 "parser.cpp"
+#line 77 "parser.cpp" /* yacc.c:316  */
 
 /* Substitute the variable and function names.  */
 #define yypush_parse    _gmx_sel_yypush_parse
 #define yypstate        _gmx_sel_yypstate
 #define yylex           _gmx_sel_yylex
 #define yyerror         _gmx_sel_yyerror
-#define yylval          _gmx_sel_yylval
-#define yychar          _gmx_sel_yychar
 #define yydebug         _gmx_sel_yydebug
 #define yynerrs         _gmx_sel_yynerrs
-#define yylloc          _gmx_sel_yylloc
+
 
 /* Copy the first part of user declarations.  */
-/* Line 371 of yacc.c  */
-#line 56 "parser.y"
+#line 56 "parser.y" /* yacc.c:339  */
 
 #include "gromacs/utility/scoped_cptr.h"
 
@@ -113,14 +107,13 @@ using gmx::SelectionTreeElementPointer;
 #pragma warning(disable: 4065)
 #endif
 
-/* Line 371 of yacc.c  */
-#line 118 "parser.cpp"
+#line 111 "parser.cpp" /* yacc.c:339  */
 
-# ifndef YY_NULL
+# ifndef YY_NULLPTR
 #  if defined __cplusplus && 201103L <= __cplusplus
-#   define YY_NULL nullptr
+#   define YY_NULLPTR nullptr
 #  else
-#   define YY_NULL 0
+#   define YY_NULLPTR 0
 #  endif
 # endif
 
@@ -136,7 +129,7 @@ using gmx::SelectionTreeElementPointer;
    by #include "parser.h".  */
 #ifndef YY__GMX_SEL_YY_PARSER_H_INCLUDED
 # define YY__GMX_SEL_YY_PARSER_H_INCLUDED
-/* Enabling traces.  */
+/* Debug traces.  */
 #ifndef YYDEBUG
 # define YYDEBUG 1
 #endif
@@ -144,13 +137,12 @@ using gmx::SelectionTreeElementPointer;
 extern int _gmx_sel_yydebug;
 #endif
 /* "%code requires" blocks.  */
-/* Line 387 of yacc.c  */
-#line 1 "parser.y"
+#line 1 "parser.y" /* yacc.c:355  */
 
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, 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.
@@ -181,65 +173,60 @@ extern int _gmx_sel_yydebug;
  * To help us fund GROMACS development, we humbly ask that you cite
  * the research papers on the package. Check out http://www.gromacs.org.
  */
-
-/* Line 387 of yacc.c  */
-#line 76 "parser.y"
+#line 76 "parser.y" /* yacc.c:355  */
 
 #include "parsetree.h"
 #include "selelem.h"
 
 #define YYLTYPE ::gmx::SelectionLocation
 
+#line 184 "parser.cpp" /* yacc.c:355  */
 
-/* Line 387 of yacc.c  */
-#line 196 "parser.cpp"
-
-/* Tokens.  */
+/* Token type.  */
 #ifndef YYTOKENTYPE
 # define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     INVALID = 258,
-     TOK_INT = 259,
-     TOK_REAL = 260,
-     STR = 261,
-     IDENTIFIER = 262,
-     CMD_SEP = 263,
-     GROUP = 264,
-     TO = 265,
-     VARIABLE_NUMERIC = 266,
-     VARIABLE_GROUP = 267,
-     VARIABLE_POS = 268,
-     KEYWORD_NUMERIC = 269,
-     KEYWORD_STR = 270,
-     KEYWORD_POS = 271,
-     KEYWORD_GROUP = 272,
-     METHOD_NUMERIC = 273,
-     METHOD_GROUP = 274,
-     METHOD_POS = 275,
-     MODIFIER = 276,
-     EMPTY_POSMOD = 277,
-     PARAM = 278,
-     END_OF_METHOD = 279,
-     OF = 280,
-     CMP_OP = 281,
-     PARAM_REDUCT = 282,
-     XOR = 283,
-     OR = 284,
-     AND = 285,
-     NOT = 286,
-     UNARY_NEG = 287,
-     NUM_REDUCT = 288
-   };
+  enum yytokentype
+  {
+    INVALID = 258,
+    TOK_INT = 259,
+    TOK_REAL = 260,
+    STR = 261,
+    IDENTIFIER = 262,
+    CMD_SEP = 263,
+    GROUP = 264,
+    TO = 265,
+    VARIABLE_NUMERIC = 266,
+    VARIABLE_GROUP = 267,
+    VARIABLE_POS = 268,
+    KEYWORD_NUMERIC = 269,
+    KEYWORD_STR = 270,
+    KEYWORD_POS = 271,
+    KEYWORD_GROUP = 272,
+    METHOD_NUMERIC = 273,
+    METHOD_GROUP = 274,
+    METHOD_POS = 275,
+    MODIFIER = 276,
+    EMPTY_POSMOD = 277,
+    PARAM = 278,
+    END_OF_METHOD = 279,
+    OF = 280,
+    CMP_OP = 281,
+    PARAM_REDUCT = 282,
+    OR = 283,
+    XOR = 284,
+    AND = 285,
+    NOT = 286,
+    UNARY_NEG = 287,
+    NUM_REDUCT = 288
+  };
 #endif
 
-
+/* Value type.  */
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
+
+union YYSTYPE
 {
-/* Line 387 of yacc.c  */
-#line 83 "parser.y"
+#line 83 "parser.y" /* yacc.c:355  */
 
     int                         i;
     real                        r;
@@ -254,29 +241,30 @@ typedef union YYSTYPE
     gmx::SelectionParserParameter               *param;
     gmx::SelectionParserParameterListPointer    *plist;
 
+#line 245 "parser.cpp" /* yacc.c:355  */
+};
 
-/* Line 387 of yacc.c  */
-#line 260 "parser.cpp"
-} YYSTYPE;
+typedef union YYSTYPE YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
 #endif
 
+/* Location type.  */
 #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
-typedef struct YYLTYPE
+typedef struct YYLTYPE YYLTYPE;
+struct YYLTYPE
 {
   int first_line;
   int first_column;
   int last_line;
   int last_column;
-} YYLTYPE;
-# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+};
 # define YYLTYPE_IS_DECLARED 1
 # define YYLTYPE_IS_TRIVIAL 1
 #endif
 
 
+
 #ifndef YYPUSH_MORE_DEFINED
 # define YYPUSH_MORE_DEFINED
 enum { YYPUSH_MORE = 4 };
@@ -284,29 +272,16 @@ enum { YYPUSH_MORE = 4 };
 
 typedef struct _gmx_sel_yypstate _gmx_sel_yypstate;
 
-#if defined __STDC__ || defined __cplusplus
 int _gmx_sel_yypush_parse (_gmx_sel_yypstate *ps, int pushed_char, YYSTYPE const *pushed_val, YYLTYPE *pushed_loc, void *scanner);
-#else
-int _gmx_sel_yypush_parse ();
-#endif
 
-#if defined __STDC__ || defined __cplusplus
 _gmx_sel_yypstate * _gmx_sel_yypstate_new (void);
-#else
-_gmx_sel_yypstate * _gmx_sel_yypstate_new ();
-#endif
-#if defined __STDC__ || defined __cplusplus
 void _gmx_sel_yypstate_delete (_gmx_sel_yypstate *ps);
-#else
-void _gmx_sel_yypstate_delete ();
-#endif
 
 #endif /* !YY__GMX_SEL_YY_PARSER_H_INCLUDED  */
 
 /* Copy the second part of user declarations.  */
 
-/* Line 390 of yacc.c  */
-#line 310 "parser.cpp"
+#line 285 "parser.cpp" /* yacc.c:358  */
 
 #ifdef short
 # undef short
@@ -320,11 +295,8 @@ typedef unsigned char yytype_uint8;
 
 #ifdef YYTYPE_INT8
 typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
 #else
-typedef short int yytype_int8;
+typedef signed char yytype_int8;
 #endif
 
 #ifdef YYTYPE_UINT16
@@ -344,8 +316,7 @@ typedef short int yytype_int16;
 #  define YYSIZE_T __SIZE_TYPE__
 # elif defined size_t
 #  define YYSIZE_T size_t
-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
+# elif ! defined YYSIZE_T
 #  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
 #  define YYSIZE_T size_t
 # else
@@ -367,11 +338,30 @@ typedef short int yytype_int16;
 # endif
 #endif
 
-#ifndef __attribute__
-/* This feature is available in gcc versions 2.5 and later.  */
-# if (! defined __GNUC__ || __GNUC__ < 2 \
-      || (__GNUC__ == 2 && __GNUC_MINOR__ < 5))
-#  define __attribute__(Spec) /* empty */
+#ifndef YY_ATTRIBUTE
+# if (defined __GNUC__                                               \
+      && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__)))  \
+     || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
+#  define YY_ATTRIBUTE(Spec) __attribute__(Spec)
+# else
+#  define YY_ATTRIBUTE(Spec) /* empty */
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_PURE
+# define YY_ATTRIBUTE_PURE   YY_ATTRIBUTE ((__pure__))
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
+#endif
+
+#if !defined _Noreturn \
+     && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112)
+# if defined _MSC_VER && 1200 <= _MSC_VER
+#  define _Noreturn __declspec (noreturn)
+# else
+#  define _Noreturn YY_ATTRIBUTE ((__noreturn__))
 # endif
 #endif
 
@@ -382,32 +372,33 @@ typedef short int yytype_int16;
 # define YYUSE(E) /* empty */
 #endif
 
-
-/* Identity function, used to suppress warnings about constant conditions.  */
-#ifndef lint
-# define YYID(N) (N)
-#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int yyi)
+#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized.  */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+    _Pragma ("GCC diagnostic push") \
+    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+    _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+    _Pragma ("GCC diagnostic pop")
 #else
-static int
-YYID (yyi)
-    int yyi;
+# define YY_INITIAL_VALUE(Value) Value
 #endif
-{
-  return yyi;
-}
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
 #endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
 
 #if ! defined yyoverflow || YYERROR_VERBOSE
 
 /* The parser invokes alloca or malloc; define the necessary symbols.  */
 
 # ifdef YYSTACK_ALLOC
-   /* Pacify GCC's `empty if-body' warning.  */
-#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+   /* Pacify GCC's 'empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
 #  ifndef YYSTACK_ALLOC_MAXIMUM
     /* The OS might guarantee only one guard page at the bottom of the stack,
        and a page size can be as small as 4096 bytes.  So we cannot safely
@@ -423,7 +414,7 @@ YYID (yyi)
 #  endif
 #  if (defined __cplusplus && ! defined EXIT_SUCCESS \
        && ! ((defined YYMALLOC || defined malloc) \
-            && (defined YYFREE || defined free)))
+             && (defined YYFREE || defined free)))
 #   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
 #   ifndef EXIT_SUCCESS
 #    define EXIT_SUCCESS 0
@@ -431,15 +422,13 @@ YYID (yyi)
 #  endif
 #  ifndef YYMALLOC
 #   define YYMALLOC malloc
-#   if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
+#   if ! defined malloc && ! defined EXIT_SUCCESS
 void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
 #   endif
 #  endif
 #  ifndef YYFREE
 #   define YYFREE free
-#   if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
+#   if ! defined free && ! defined EXIT_SUCCESS
 void free (void *); /* INFRINGES ON USER NAME SPACE */
 #   endif
 #  endif
@@ -449,8 +438,8 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
 
 #if (! defined yyoverflow \
      && (! defined __cplusplus || defined GMX_YYFORCE_C_STACK_EXTENSION \
-        || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
-            && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+         || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
+             && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
 
 /* A type that is properly aligned for any stack member.  */
 union yyalloc
@@ -476,16 +465,16 @@ union yyalloc
    elements in the stack, and YYPTR gives the new location of the
    stack.  Advance YYPTR to a properly aligned location for the next
    stack.  */
-# define YYSTACK_RELOCATE(Stack_alloc, Stack)                          \
-    do                                                                 \
-      {                                                                        \
-       YYSIZE_T yynewbytes;                                            \
-       YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \
-       Stack = &yyptr->Stack_alloc;                                    \
-       yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
-       yyptr += yynewbytes / sizeof (*yyptr);                          \
-      }                                                                        \
-    while (YYID (0))
+# define YYSTACK_RELOCATE(Stack_alloc, Stack)                           \
+    do                                                                  \
+      {                                                                 \
+        YYSIZE_T yynewbytes;                                            \
+        YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \
+        Stack = &yyptr->Stack_alloc;                                    \
+        yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+        yyptr += yynewbytes / sizeof (*yyptr);                          \
+      }                                                                 \
+    while (0)
 
 #endif
 
@@ -504,7 +493,7 @@ union yyalloc
           for (yyi = 0; yyi < (Count); yyi++)   \
             (Dst)[yyi] = (Src)[yyi];            \
         }                                       \
-      while (YYID (0))
+      while (0)
 #  endif
 # endif
 #endif /* !YYCOPY_NEEDED */
@@ -520,17 +509,19 @@ union yyalloc
 #define YYNNTS  25
 /* YYNRULES -- Number of rules.  */
 #define YYNRULES  90
-/* YYNRULES -- Number of states.  */
+/* YYNSTATES -- Number of states.  */
 #define YYNSTATES  154
 
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
+   by yylex, with out-of-bounds checking.  */
 #define YYUNDEFTOK  2
 #define YYMAXUTOK   288
 
-#define YYTRANSLATE(YYX)                                               \
+#define YYTRANSLATE(YYX)                                                \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
 
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
+   as returned by yylex, without out-of-bounds checking.  */
 static const yytype_uint8 yytranslate[] =
 {
        0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -565,67 +556,19 @@ static const yytype_uint8 yytranslate[] =
 };
 
 #if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
-   YYRHS.  */
-static const yytype_uint16 yyprhs[] =
-{
-       0,     0,     3,     4,     7,    10,    13,    14,    16,    18,
-      20,    23,    27,    31,    35,    37,    39,    43,    47,    49,
-      52,    54,    57,    59,    61,    63,    65,    68,    72,    76,
-      80,    84,    87,    90,    92,    94,    96,    98,   100,   103,
-     107,   112,   116,   120,   122,   124,   127,   132,   136,   140,
-     144,   148,   152,   155,   159,   163,   165,   168,   176,   180,
-     183,   187,   189,   191,   193,   195,   198,   199,   202,   205,
-     207,   211,   212,   215,   219,   221,   225,   227,   230,   234,
-     236,   238,   240,   242,   244,   246,   248,   250,   252,   256,
-     260
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
-static const yytype_int8 yyrhs[] =
-{
-      50,     0,    -1,    -1,    50,    51,    -1,    52,     8,    -1,
-       1,     8,    -1,    -1,     4,    -1,    57,    -1,    53,    -1,
-       6,    53,    -1,     7,    39,    58,    -1,     7,    39,    61,
-      -1,     7,    39,    63,    -1,    63,    -1,    58,    -1,    40,
-      53,    41,    -1,    53,    21,    64,    -1,     4,    -1,    33,
-       4,    -1,     5,    -1,    33,     5,    -1,    54,    -1,    55,
-      -1,     6,    -1,     7,    -1,    31,    58,    -1,    58,    30,
-      58,    -1,    58,    29,    58,    -1,    40,    58,    41,    -1,
-      61,    26,    61,    -1,     9,    57,    -1,     9,     4,    -1,
-      22,    -1,    16,    -1,    42,    -1,    43,    -1,    39,    -1,
-      59,    17,    -1,    59,    15,    69,    -1,    59,    15,    60,
-      69,    -1,    59,    14,    69,    -1,    59,    19,    64,    -1,
-       4,    -1,     5,    -1,    59,    14,    -1,    59,    14,    25,
-      63,    -1,    59,    18,    64,    -1,    61,    32,    61,    -1,
-      61,    33,    61,    -1,    61,    34,    61,    -1,    61,    35,
-      61,    -1,    33,    61,    -1,    61,    37,    61,    -1,    40,
-      61,    41,    -1,    57,    -1,    59,    15,    -1,    44,    56,
-      45,    56,    45,    56,    46,    -1,    40,    63,    41,    -1,
-      20,    64,    -1,    16,    25,    58,    -1,    12,    -1,    11,
-      -1,    13,    -1,    65,    -1,    65,    24,    -1,    -1,    65,
-      66,    -1,    23,    67,    -1,    68,    -1,    47,    68,    48,
-      -1,    -1,    68,    71,    -1,    68,    45,    71,    -1,    70,
-      -1,    47,    70,    48,    -1,    72,    -1,    70,    72,    -1,
-      70,    45,    72,    -1,    58,    -1,    63,    -1,    61,    -1,
-      62,    -1,    73,    -1,    54,    -1,    55,    -1,    57,    -1,
-      73,    -1,    54,    10,    54,    -1,    54,    10,    55,    -1,
-      55,    10,    56,    -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+  /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   199,   199,   204,   215,   216,   236,   241,   252,   264,
-     270,   277,   284,   291,   301,   302,   309,   310,   324,   325,
-     329,   330,   333,   334,   337,   338,   346,   357,   368,   379,
-     383,   394,   401,   410,   411,   416,   417,   418,   422,   430,
-     438,   446,   457,   472,   483,   497,   505,   513,   524,   530,
-     536,   542,   548,   554,   560,   567,   578,   593,   602,   606,
-     616,   630,   638,   646,   659,   661,   667,   672,   683,   692,
-     693,   698,   703,   711,   722,   723,   727,   733,   741,   751,
-     757,   763,   769,   775,   779,   785,   791,   798,   802,   808,
-     814
+       0,   199,   199,   204,   217,   218,   238,   243,   254,   266,
+     272,   279,   286,   293,   303,   304,   311,   312,   326,   327,
+     331,   332,   335,   336,   339,   340,   348,   359,   370,   381,
+     385,   396,   403,   412,   413,   418,   419,   420,   424,   432,
+     440,   448,   459,   474,   485,   499,   507,   515,   526,   532,
+     538,   544,   550,   556,   562,   569,   580,   595,   604,   608,
+     618,   632,   640,   648,   661,   663,   669,   674,   685,   694,
+     695,   700,   705,   713,   724,   725,   729,   735,   743,   753,
+     759,   765,   771,   777,   781,   787,   793,   800,   804,   810,
+     816
 };
 #endif
 
@@ -639,7 +582,7 @@ static const char *const yytname[] =
   "VARIABLE_GROUP", "VARIABLE_POS", "KEYWORD_NUMERIC", "KEYWORD_STR",
   "KEYWORD_POS", "KEYWORD_GROUP", "METHOD_NUMERIC", "METHOD_GROUP",
   "METHOD_POS", "MODIFIER", "EMPTY_POSMOD", "PARAM", "END_OF_METHOD", "OF",
-  "CMP_OP", "PARAM_REDUCT", "XOR", "OR", "AND", "NOT", "'+'", "'-'", "'*'",
+  "CMP_OP", "PARAM_REDUCT", "OR", "XOR", "AND", "NOT", "'+'", "'-'", "'*'",
   "'/'", "UNARY_NEG", "'^'", "NUM_REDUCT", "'='", "'('", "')'", "'~'",
   "'?'", "'['", "','", "']'", "'{'", "'}'", "$accept", "commands",
   "command", "cmd_plain", "selection", "integer_number", "real_number",
@@ -647,13 +590,13 @@ static const char *const yytname[] =
   "str_expr", "pos_expr", "method_params", "method_param_list",
   "method_param", "value_list", "value_list_contents", "basic_value_list",
   "basic_value_list_contents", "value_item", "basic_value_item",
-  "value_item_range", YY_NULL
+  "value_item_range", YY_NULLPTR
 };
 #endif
 
 # ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
-   token YYLEX-NUM.  */
+/* YYTOKNUM[NUM] -- (External) token number corresponding to the
+   (internal) symbol number NUM (which must be that of a token).  */
 static const yytype_uint16 yytoknum[] =
 {
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
@@ -664,39 +607,41 @@ static const yytype_uint16 yytoknum[] =
 };
 # endif
 
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
-static const yytype_uint8 yyr1[] =
-{
-       0,    49,    50,    50,    51,    51,    52,    52,    52,    52,
-      52,    52,    52,    52,    53,    53,    53,    53,    54,    54,
-      55,    55,    56,    56,    57,    57,    58,    58,    58,    58,
-      58,    58,    58,    59,    59,    60,    60,    60,    58,    58,
-      58,    58,    58,    61,    61,    61,    61,    61,    61,    61,
-      61,    61,    61,    61,    61,    62,    62,    63,    63,    63,
-      63,    58,    61,    63,    64,    64,    65,    65,    66,    67,
-      67,    68,    68,    68,    69,    69,    70,    70,    70,    71,
-      71,    71,    71,    71,    72,    72,    72,    72,    73,    73,
-      73
-};
+#define YYPACT_NINF -85
 
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
-static const yytype_uint8 yyr2[] =
+#define yypact_value_is_default(Yystate) \
+  (!!((Yystate) == (-85)))
+
+#define YYTABLE_NINF -22
+
+#define yytable_value_is_error(Yytable_value) \
+  0
+
+  /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+     STATE-NUM.  */
+static const yytype_int16 yypact[] =
 {
-       0,     2,     0,     2,     2,     2,     0,     1,     1,     1,
-       2,     3,     3,     3,     1,     1,     3,     3,     1,     2,
-       1,     2,     1,     1,     1,     1,     2,     3,     3,     3,
-       3,     2,     2,     1,     1,     1,     1,     1,     2,     3,
-       4,     3,     3,     1,     1,     2,     4,     3,     3,     3,
-       3,     3,     2,     3,     3,     1,     2,     7,     3,     2,
-       3,     1,     1,     1,     1,     2,     0,     2,     2,     1,
-       3,     0,     2,     3,     1,     3,     1,     2,     3,     1,
-       1,     1,     1,     1,     1,     1,     1,     1,     3,     3,
-       3
+     -85,    10,   -85,    -2,    26,   -85,   273,     0,    55,   -85,
+     -85,   -85,    40,   -85,   -85,   310,   204,   273,    69,   -85,
+      62,    82,   -85,    -3,   139,   312,   -85,   -85,   -85,    82,
+     296,   -85,   -85,   -85,   -85,   310,   -85,    96,   -85,   310,
+     -85,   204,    -6,    73,    15,    71,   220,    67,   -85,   -85,
+     135,   -85,   -85,    83,   -85,   -85,   310,   310,    41,   185,
+     -85,   -85,   -85,   204,   204,   204,   204,   204,   204,   296,
+      -3,   312,   -85,    -3,    97,   -85,   -85,    71,   319,    91,
+     -85,   -85,   -85,   -85,   -85,   -85,    69,   -85,   113,   -85,
+      24,   206,   137,   140,   -85,   -85,    90,   -85,   -85,   -85,
+     -85,   -85,    85,   -85,   -85,   -85,   330,   167,   167,    73,
+      73,    73,    67,   -85,   -85,   229,   107,    40,    24,   -85,
+     174,    69,    69,   206,   -85,   -85,   155,   153,   159,   326,
+     259,   137,   140,   -85,    -3,   179,   330,   -85,   -85,   -85,
+     -85,    69,   -85,   -85,   -85,   -85,   -85,   -85,   160,   164,
+     -85,   185,   119,   -85
 };
 
-/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
-   Performed when YYTABLE doesn't specify something else to do.  Zero
-   means the default is an error.  */
+  /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+     Performed when YYTABLE does not specify something else to do.  Zero
+     means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
        2,     0,     1,     0,    43,    44,    24,    25,     0,    62,
@@ -717,7 +662,15 @@ static const yytype_uint8 yydefact[] =
       73,    56,     0,    57
 };
 
-/* YYDEFGOTO[NTERM-NUM].  */
+  /* YYPGOTO[NTERM-NUM].  */
+static const yytype_int8 yypgoto[] =
+{
+     -85,   -85,   -85,   -85,     7,   -17,   -15,   -84,    -1,   116,
+      19,   -85,    12,   -85,     3,    75,   -85,   -85,   -85,    63,
+     -53,    92,    52,   -65,   -63
+};
+
+  /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int16 yydefgoto[] =
 {
       -1,     1,    19,    20,    21,    92,    93,    53,    94,   134,
@@ -725,69 +678,37 @@ static const yytype_int16 yydefgoto[] =
      103,    96,   139,    97,    98
 };
 
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
-   STATE-NUM.  */
-#define YYPACT_NINF -85
-static const yytype_int16 yypact[] =
-{
-     -85,    10,   -85,    -2,    17,   -85,   273,   -12,    55,   -85,
-     -85,   -85,     9,   -85,   -85,   310,   204,   273,    69,   -85,
-      31,    44,   -85,   110,   179,   312,   -85,   -85,   -85,    44,
-     296,   -85,   -85,   -85,   -85,   310,   -85,    96,   -85,   310,
-     -85,   204,    -6,    33,    15,   124,   220,    58,   -85,   -85,
-     139,   -85,   -85,    56,   -85,   -85,   310,   310,    41,   185,
-     -85,   -85,   -85,   204,   204,   204,   204,   204,   204,   296,
-     110,   312,   -85,   110,    61,   -85,   -85,   124,   319,    78,
-     -85,   -85,   -85,   -85,   -85,   -85,    69,   -85,    80,   -85,
-      24,   206,   102,   106,   -85,   -85,    90,   -85,   -85,   -85,
-     -85,   -85,    85,   -85,   -85,   -85,   330,   213,   213,    33,
-      33,    33,    58,   -85,   -85,   229,    83,     9,    24,   -85,
-     174,    69,    69,   206,   -85,   -85,   155,   137,   140,   326,
-     259,   102,   106,   -85,   110,   187,   330,   -85,   -85,   -85,
-     -85,    69,   -85,   -85,   -85,   -85,   -85,   -85,   142,   146,
-     -85,   185,   111,   -85
-};
-
-/* YYPGOTO[NTERM-NUM].  */
-static const yytype_int8 yypgoto[] =
-{
-     -85,   -85,   -85,   -85,     7,   -17,   -15,   -84,    -1,   116,
-      19,   -85,    12,   -85,     3,    75,   -85,   -85,   -85,    45,
-     -53,    72,    39,   -65,   -63
-};
-
-/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
-   positive, shift that token.  If negative, reduce the rule which
-   number is the opposite.  If YYTABLE_NINF, syntax error.  */
-#define YYTABLE_NINF -22
+  /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
+     positive, shift that token.  If negative, reduce the rule whose
+     number is the opposite.  If YYTABLE_NINF, syntax error.  */
 static const yytype_int16 yytable[] =
 {
       22,    51,   116,    52,    26,    95,    27,    34,    79,    26,
        2,     3,    61,    29,     4,     5,     6,     7,    -6,     8,
-      47,     9,    10,    11,    44,    -7,    12,    30,    43,    46,
-      13,   124,    14,    72,    35,    42,    55,    11,   145,    54,
+      47,     9,    10,    11,    44,    56,    12,    57,    43,    46,
+      13,   124,    14,    72,    -7,    42,    55,    11,   145,    30,
      117,    15,    71,    16,    13,    48,    49,    32,    33,   125,
       17,    46,   140,    78,    18,   124,    80,   152,   146,    31,
-      42,    32,    33,   140,   118,    55,    90,   140,    18,    51,
-      68,    52,   112,    48,    49,   106,   107,   108,   109,   110,
+      42,    32,    33,   140,   118,    35,    90,   140,    18,    51,
+      54,    52,   112,    48,    49,   106,   107,   108,   109,   110,
      111,    46,    42,    42,    42,    42,    42,    42,    91,    48,
-      49,    32,    33,   119,    48,    49,    32,    33,   131,    83,
-     132,    86,    50,    90,   143,    51,   144,    52,   113,   131,
-      57,   132,   121,   131,   133,   132,   122,    23,    50,    74,
-      75,   112,    23,    50,    51,   133,    52,   136,   141,   133,
-      87,    40,    91,    45,   135,   123,   104,   105,   136,    56,
-      57,    43,   136,    84,    85,   135,    70,   -18,    42,   135,
-     -20,    73,   -19,    56,    57,    77,   -21,   153,   126,   127,
-     128,    32,    33,   120,     8,    81,     9,    10,    11,   150,
-       0,    12,    88,    89,     0,    13,     0,    14,    48,    49,
-      32,    33,     0,     0,     0,    77,    15,     0,   129,    48,
-      49,    32,    33,    58,    59,    69,    60,    61,    62,    18,
-     130,    58,   151,   147,    60,    61,    62,    50,    28,     5,
+      49,    32,    33,   119,    48,    49,    32,    33,   131,    56,
+     132,    57,    50,    55,   143,    51,   144,    52,    83,   131,
+      68,   132,    81,   131,   133,   132,    90,    23,    50,    74,
+      75,   112,    23,    50,    51,   133,    52,   136,    86,   133,
+      87,    40,    91,    45,   135,   123,   104,   105,   136,    84,
+      85,    43,   136,    57,   113,   135,    70,   121,    42,   135,
+     122,    73,   141,    58,    59,    77,    60,    61,    62,   127,
+     128,    32,    33,   -18,     8,   153,     9,    10,    11,   -20,
+     -19,    12,    88,    89,   -21,    13,   126,    14,    48,    49,
+      32,    33,   150,   120,     0,    77,    15,     0,   129,    48,
+      49,    32,    33,    58,   151,    69,    60,    61,    62,    18,
+     130,    66,    67,   147,    68,     0,     0,    50,    28,     5,
       48,    49,    32,    33,     0,     9,     0,     0,    50,   123,
       38,     0,   142,     0,    99,     0,    14,   100,   101,     0,
        0,     0,    91,   127,   128,    32,    33,    16,     8,    50,
-       9,    10,    11,     0,    41,    12,    63,    66,    67,    13,
-      68,    14,    64,    65,    66,    67,     0,    68,     0,     0,
+       9,    10,    11,     0,    41,    12,    63,     0,     0,    13,
+       0,    14,    64,    65,    66,    67,     0,    68,     0,     0,
       15,    82,   129,   127,   128,    32,    33,     0,     8,    69,
        9,    10,    11,    18,   130,    12,     0,    28,     5,    13,
        0,    14,     8,     0,     9,    10,    11,     0,     0,    12,
@@ -801,40 +722,34 @@ static const yytype_int16 yytable[] =
       82,     0,    64,    65,    66,    67,    41,    68
 };
 
-#define yypact_value_is_default(Yystate) \
-  (!!((Yystate) == (-85)))
-
-#define yytable_value_is_error(Yytable_value) \
-  YYID (0)
-
 static const yytype_int16 yycheck[] =
 {
        1,    18,    86,    18,     1,    58,     8,     8,    14,     6,
        0,     1,    18,     6,     4,     5,     6,     7,     8,     9,
-      17,    11,    12,    13,    17,     8,    16,    39,    16,    17,
-      20,    96,    22,    30,    25,    16,    21,    13,   122,     8,
+      17,    11,    12,    13,    17,    28,    16,    30,    16,    17,
+      20,    96,    22,    30,     8,    16,    21,    13,   122,    39,
       16,    31,    30,    33,    20,     4,     5,     6,     7,   102,
       40,    39,   115,    41,    44,   120,    41,   141,   123,     4,
-      41,     6,     7,   126,    40,    21,    25,   130,    44,    86,
-      37,    86,    69,     4,     5,    63,    64,    65,    66,    67,
+      41,     6,     7,   126,    40,    25,    25,   130,    44,    86,
+       8,    86,    69,     4,     5,    63,    64,    65,    66,    67,
       68,    69,    63,    64,    65,    66,    67,    68,    47,     4,
-       5,     6,     7,    90,     4,     5,     6,     7,   115,    41,
-     115,    45,    33,    25,   121,   122,   121,   122,    47,   126,
-      30,   126,    10,   130,   115,   130,    10,     1,    33,    23,
+       5,     6,     7,    90,     4,     5,     6,     7,   115,    28,
+     115,    30,    33,    21,   121,   122,   121,   122,    41,   126,
+      37,   126,    41,   130,   115,   130,    25,     1,    33,    23,
       24,   118,     6,    33,   141,   126,   141,   115,    45,   130,
-      55,    15,    47,    17,   115,    45,    61,    62,   126,    29,
-      30,   129,   130,     4,     5,   126,    30,    10,   129,   130,
-      10,    35,    10,    29,    30,    39,    10,    46,   113,     4,
-       5,     6,     7,    91,     9,    41,    11,    12,    13,   130,
-      -1,    16,    56,    57,    -1,    20,    -1,    22,     4,     5,
-       6,     7,    -1,    -1,    -1,    69,    31,    -1,    33,     4,
+      55,    15,    47,    17,   115,    45,    61,    62,   126,     4,
+       5,   129,   130,    30,    47,   126,    30,    10,   129,   130,
+      10,    35,    45,    14,    15,    39,    17,    18,    19,     4,
+       5,     6,     7,    10,     9,    46,    11,    12,    13,    10,
+      10,    16,    56,    57,    10,    20,   113,    22,     4,     5,
+       6,     7,   130,    91,    -1,    69,    31,    -1,    33,     4,
        5,     6,     7,    14,    15,    40,    17,    18,    19,    44,
-      45,    14,    15,    48,    17,    18,    19,    33,     4,     5,
+      45,    34,    35,    48,    37,    -1,    -1,    33,     4,     5,
        4,     5,     6,     7,    -1,    11,    -1,    -1,    33,    45,
       16,    -1,    48,    -1,    39,    -1,    22,    42,    43,    -1,
       -1,    -1,    47,     4,     5,     6,     7,    33,     9,    33,
-      11,    12,    13,    -1,    40,    16,    26,    34,    35,    20,
-      37,    22,    32,    33,    34,    35,    -1,    37,    -1,    -1,
+      11,    12,    13,    -1,    40,    16,    26,    -1,    -1,    20,
+      -1,    22,    32,    33,    34,    35,    -1,    37,    -1,    -1,
       31,    41,    33,     4,     5,     6,     7,    -1,     9,    40,
       11,    12,    13,    44,    45,    16,    -1,     4,     5,    20,
       -1,    22,     9,    -1,    11,    12,    13,    -1,    -1,    16,
@@ -848,8 +763,8 @@ static const yytype_int16 yycheck[] =
       41,    -1,    32,    33,    34,    35,    40,    37
 };
 
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
-   symbol of state STATE-NUM.  */
+  /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+     symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
        0,    50,     0,     1,     4,     5,     6,     7,     9,    11,
@@ -857,7 +772,7 @@ static const yytype_uint8 yystos[] =
       52,    53,    57,    58,    59,    61,    63,     8,     4,    53,
       39,     4,     6,     7,    57,    25,    64,    65,    16,    40,
       58,    40,    59,    61,    53,    58,    61,    63,     4,     5,
-      33,    54,    55,    56,     8,    21,    29,    30,    14,    15,
+      33,    54,    55,    56,     8,    21,    28,    30,    14,    15,
       17,    18,    19,    26,    32,    33,    34,    35,    37,    40,
       58,    61,    63,    58,    23,    24,    66,    58,    61,    14,
       41,    41,    41,    41,     4,     5,    45,    64,    58,    58,
@@ -870,30 +785,46 @@ static const yytype_uint8 yystos[] =
       71,    15,    56,    46
 };
 
-#define yyerrok                (yyerrstatus = 0)
-#define yyclearin      (yychar = YYEMPTY)
-#define YYEMPTY                (-2)
-#define YYEOF          0
-
-#define YYACCEPT       goto yyacceptlab
-#define YYABORT                goto yyabortlab
-#define YYERROR                goto yyerrorlab
-
-
-/* Like YYERROR except do call yyerror.  This remains here temporarily
-   to ease the transition to the new meaning of YYERROR, for GCC.
-   Once GCC version 2 has supplanted version 1, this can go.  However,
-   YYFAIL appears to be in use.  Nevertheless, it is formally deprecated
-   in Bison 2.4.2's NEWS entry, where a plan to phase it out is
-   discussed.  */
-
-#define YYFAIL         goto yyerrlab
-#if defined YYFAIL
-  /* This is here to suppress warnings from the GCC cpp's
-     -Wunused-macros.  Normally we don't worry about that warning, but
-     some users do, and we want to make it easy for users to remove
-     YYFAIL uses, which will produce warnings from Bison 2.5.  */
-#endif
+  /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    49,    50,    50,    51,    51,    52,    52,    52,    52,
+      52,    52,    52,    52,    53,    53,    53,    53,    54,    54,
+      55,    55,    56,    56,    57,    57,    58,    58,    58,    58,
+      58,    58,    58,    59,    59,    60,    60,    60,    58,    58,
+      58,    58,    58,    61,    61,    61,    61,    61,    61,    61,
+      61,    61,    61,    61,    61,    62,    62,    63,    63,    63,
+      63,    58,    61,    63,    64,    64,    65,    65,    66,    67,
+      67,    68,    68,    68,    69,    69,    70,    70,    70,    71,
+      71,    71,    71,    71,    72,    72,    72,    72,    73,    73,
+      73
+};
+
+  /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     0,     2,     2,     2,     0,     1,     1,     1,
+       2,     3,     3,     3,     1,     1,     3,     3,     1,     2,
+       1,     2,     1,     1,     1,     1,     2,     3,     3,     3,
+       3,     2,     2,     1,     1,     1,     1,     1,     2,     3,
+       4,     3,     3,     1,     1,     2,     4,     3,     3,     3,
+       3,     3,     2,     3,     3,     1,     2,     7,     3,     2,
+       3,     1,     1,     1,     1,     2,     0,     2,     2,     1,
+       3,     0,     2,     3,     1,     3,     1,     2,     3,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     3,     3,
+       3
+};
+
+
+#define yyerrok         (yyerrstatus = 0)
+#define yyclearin       (yychar = YYEMPTY)
+#define YYEMPTY         (-2)
+#define YYEOF           0
+
+#define YYACCEPT        goto yyacceptlab
+#define YYABORT         goto yyabortlab
+#define YYERROR         goto yyerrorlab
+
 
 #define YYRECOVERING()  (!!yyerrstatus)
 
@@ -910,13 +841,13 @@ do                                                              \
   else                                                          \
     {                                                           \
       yyerror (&yylloc, scanner, YY_("syntax error: cannot back up")); \
-      YYERROR;                                                 \
-    }                                                          \
-while (YYID (0))
+      YYERROR;                                                  \
+    }                                                           \
+while (0)
 
 /* Error token number */
-#define YYTERROR       1
-#define YYERRCODE      256
+#define YYTERROR        1
+#define YYERRCODE       256
 
 
 /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
@@ -926,7 +857,7 @@ while (YYID (0))
 #ifndef YYLLOC_DEFAULT
 # define YYLLOC_DEFAULT(Current, Rhs, N)                                \
     do                                                                  \
-      if (YYID (N))                                                     \
+      if (N)                                                            \
         {                                                               \
           (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;        \
           (Current).first_column = YYRHSLOC (Rhs, 1).first_column;      \
@@ -940,12 +871,27 @@ while (YYID (0))
           (Current).first_column = (Current).last_column =              \
             YYRHSLOC (Rhs, 0).last_column;                              \
         }                                                               \
-    while (YYID (0))
+    while (0)
 #endif
 
 #define YYRHSLOC(Rhs, K) ((Rhs)[K])
 
 
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)                        \
+do {                                            \
+  if (yydebug)                                  \
+    YYFPRINTF Args;                             \
+} while (0)
+
+
 /* YY_LOCATION_PRINT -- Print the location on the stream.
    This macro was not mandated originally: define only if we know
    we won't break user code: when these are the locations we know.  */
@@ -955,36 +901,28 @@ while (YYID (0))
 
 /* Print *YYLOCP on YYO.  Private, do not rely on its existence. */
 
-__attribute__((__unused__))
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
+YY_ATTRIBUTE_UNUSED
 static unsigned
 yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp)
-#else
-static unsigned
-yy_location_print_ (yyo, yylocp)
-    FILE *yyo;
-    YYLTYPE const * const yylocp;
-#endif
 {
   unsigned res = 0;
   int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0;
   if (0 <= yylocp->first_line)
     {
-      res += fprintf (yyo, "%d", yylocp->first_line);
+      res += YYFPRINTF (yyo, "%d", yylocp->first_line);
       if (0 <= yylocp->first_column)
-        res += fprintf (yyo, ".%d", yylocp->first_column);
+        res += YYFPRINTF (yyo, ".%d", yylocp->first_column);
     }
   if (0 <= yylocp->last_line)
     {
       if (yylocp->first_line < yylocp->last_line)
         {
-          res += fprintf (yyo, "-%d", yylocp->last_line);
+          res += YYFPRINTF (yyo, "-%d", yylocp->last_line);
           if (0 <= end_col)
-            res += fprintf (yyo, ".%d", end_col);
+            res += YYFPRINTF (yyo, ".%d", end_col);
         }
       else if (0 <= end_col && yylocp->first_column < end_col)
-        res += fprintf (yyo, "-%d", end_col);
+        res += YYFPRINTF (yyo, "-%d", end_col);
     }
   return res;
  }
@@ -998,69 +936,34 @@ yy_location_print_ (yyo, yylocp)
 #endif
 
 
-/* YYLEX -- calling `yylex' with the right arguments.  */
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM)
-#else
-# define YYLEX yylex (&yylval, &yylloc)
-#endif
-
-/* Enable debugging if requested.  */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args)                       \
-do {                                           \
-  if (yydebug)                                 \
-    YYFPRINTF Args;                            \
-} while (YYID (0))
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)                    \
+do {                                                                      \
+  if (yydebug)                                                            \
+    {                                                                     \
+      YYFPRINTF (stderr, "%s ", Title);                                   \
+      yy_symbol_print (stderr,                                            \
+                  Type, Value, Location, scanner); \
+      YYFPRINTF (stderr, "\n");                                           \
+    }                                                                     \
+} while (0)
 
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)                   \
-do {                                                                     \
-  if (yydebug)                                                           \
-    {                                                                    \
-      YYFPRINTF (stderr, "%s ", Title);                                          \
-      yy_symbol_print (stderr,                                           \
-                 Type, Value, Location, scanner); \
-      YYFPRINTF (stderr, "\n");                                                  \
-    }                                                                    \
-} while (YYID (0))
 
+/*----------------------------------------.
+| Print this symbol's value on YYOUTPUT.  |
+`----------------------------------------*/
 
-/*--------------------------------.
-| Print this symbol on YYOUTPUT.  |
-`--------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 static void
 yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, void *scanner)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, scanner)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE const * const yyvaluep;
-    YYLTYPE const * const yylocationp;
-    void *scanner;
-#endif
 {
   FILE *yyo gmx_unused = yyoutput;
   YYUSE (yyo);
-  if (!yyvaluep)
-    return;
   YYUSE (yylocationp);
   YYUSE (scanner);
+  if (!yyvaluep)
+    return;
 # ifdef YYPRINT
   if (yytype < YYNTOKENS)
     YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
-  YYUSE (yyoutput);
 # endif
   YYUSE (yytype);
 }
@@ -1070,24 +973,11 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, scanner)
 | Print this symbol on YYOUTPUT.  |
 `--------------------------------*/
 
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 static void
 yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, void *scanner)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, scanner)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE const * const yyvaluep;
-    YYLTYPE const * const yylocationp;
-    void *scanner;
-#endif
 {
-  if (yytype < YYNTOKENS)
-    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
-  else
-    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+  YYFPRINTF (yyoutput, "%s %s (",
+             yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
 
   YY_LOCATION_PRINT (yyoutput, *yylocationp);
   YYFPRINTF (yyoutput, ": ");
@@ -1100,16 +990,8 @@ yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, scanner)
 | TOP (included).                                                   |
 `------------------------------------------------------------------*/
 
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 static void
 yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
-#else
-static void
-yy_stack_print (yybottom, yytop)
-    yytype_int16 *yybottom;
-    yytype_int16 *yytop;
-#endif
 {
   YYFPRINTF (stderr, "Stack now");
   for (; yybottom <= yytop; yybottom++)
@@ -1120,51 +1002,42 @@ yy_stack_print (yybottom, yytop)
   YYFPRINTF (stderr, "\n");
 }
 
-# define YY_STACK_PRINT(Bottom, Top)                           \
-do {                                                           \
-  if (yydebug)                                                 \
-    yy_stack_print ((Bottom), (Top));                          \
-} while (YYID (0))
+# define YY_STACK_PRINT(Bottom, Top)                            \
+do {                                                            \
+  if (yydebug)                                                  \
+    yy_stack_print ((Bottom), (Top));                           \
+} while (0)
 
 
 /*------------------------------------------------.
 | Report that the YYRULE is going to be reduced.  |
 `------------------------------------------------*/
 
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, void *scanner)
-#else
 static void
-yy_reduce_print (yyvsp, yylsp, yyrule, scanner)
-    YYSTYPE *yyvsp;
-    YYLTYPE *yylsp;
-    int yyrule;
-    void *scanner;
-#endif
+yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, void *scanner)
 {
+  unsigned long int yylno = yyrline[yyrule];
   int yynrhs = yyr2[yyrule];
   int yyi;
-  unsigned long int yylno = yyrline[yyrule];
   YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
-            yyrule - 1, yylno);
+             yyrule - 1, yylno);
   /* The symbols being reduced.  */
   for (yyi = 0; yyi < yynrhs; yyi++)
     {
       YYFPRINTF (stderr, "   $%d = ", yyi + 1);
-      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
-                      &(yyvsp[(yyi + 1) - (yynrhs)])
-                      , &(yylsp[(yyi + 1) - (yynrhs)])                , scanner);
+      yy_symbol_print (stderr,
+                       yystos[yyssp[yyi + 1 - yynrhs]],
+                       &(yyvsp[(yyi + 1) - (yynrhs)])
+                       , &(yylsp[(yyi + 1) - (yynrhs)])                       , scanner);
       YYFPRINTF (stderr, "\n");
     }
 }
 
-# define YY_REDUCE_PRINT(Rule)         \
-do {                                   \
-  if (yydebug)                         \
-    yy_reduce_print (yyvsp, yylsp, Rule, scanner); \
-} while (YYID (0))
+# define YY_REDUCE_PRINT(Rule)          \
+do {                                    \
+  if (yydebug)                          \
+    yy_reduce_print (yyssp, yyvsp, yylsp, Rule, scanner); \
+} while (0)
 
 /* Nonzero means print parse trace.  It is left uninitialized so that
    multiple parsers can coexist.  */
@@ -1178,7 +1051,7 @@ int yydebug;
 
 
 /* YYINITDEPTH -- initial size of the parser's stacks.  */
-#ifndef        YYINITDEPTH
+#ifndef YYINITDEPTH
 # define YYINITDEPTH 200
 #endif
 
@@ -1201,15 +1074,8 @@ int yydebug;
 #   define yystrlen strlen
 #  else
 /* Return the length of YYSTR.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 static YYSIZE_T
 yystrlen (const char *yystr)
-#else
-static YYSIZE_T
-yystrlen (yystr)
-    const char *yystr;
-#endif
 {
   YYSIZE_T yylen;
   for (yylen = 0; yystr[yylen]; yylen++)
@@ -1225,16 +1091,8 @@ yystrlen (yystr)
 #  else
 /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
    YYDEST.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 static char *
 yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
-yystpcpy (yydest, yysrc)
-    char *yydest;
-    const char *yysrc;
-#endif
 {
   char *yyd = yydest;
   const char *yys = yysrc;
@@ -1264,27 +1122,27 @@ yytnamerr (char *yyres, const char *yystr)
       char const *yyp = yystr;
 
       for (;;)
-       switch (*++yyp)
-         {
-         case '\'':
-         case ',':
-           goto do_not_strip_quotes;
-
-         case '\\':
-           if (*++yyp != '\\')
-             goto do_not_strip_quotes;
-           /* Fall through.  */
-         default:
-           if (yyres)
-             yyres[yyn] = *yyp;
-           yyn++;
-           break;
-
-         case '"':
-           if (yyres)
-             yyres[yyn] = '\0';
-           return yyn;
-         }
+        switch (*++yyp)
+          {
+          case '\'':
+          case ',':
+            goto do_not_strip_quotes;
+
+          case '\\':
+            if (*++yyp != '\\')
+              goto do_not_strip_quotes;
+            /* Fall through.  */
+          default:
+            if (yyres)
+              yyres[yyn] = *yyp;
+            yyn++;
+            break;
+
+          case '"':
+            if (yyres)
+              yyres[yyn] = '\0';
+            return yyn;
+          }
     do_not_strip_quotes: ;
     }
 
@@ -1307,11 +1165,11 @@ static int
 yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
                 yytype_int16 *yyssp, int yytoken)
 {
-  YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
+  YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
   YYSIZE_T yysize = yysize0;
   enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
   /* Internationalized format string. */
-  const char *yyformat = YY_NULL;
+  const char *yyformat = YY_NULLPTR;
   /* Arguments of yyformat. */
   char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
   /* Number of reported tokens (one for the "unexpected", one per
@@ -1319,10 +1177,6 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
   int yycount = 0;
 
   /* There are many possibilities here to consider:
-     - Assume YYFAIL is not used.  It's too flawed to consider.  See
-       <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
-       for details.  YYERROR is fine as it does not invoke this
-       function.
      - If this state is a consistent state with a default action, then
        the only way this function was invoked is if the default action
        is an error action.  In that case, don't check for expected
@@ -1372,7 +1226,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
                   }
                 yyarg[yycount++] = yytname[yyx];
                 {
-                  YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
+                  YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]);
                   if (! (yysize <= yysize1
                          && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
                     return 2;
@@ -1439,210 +1293,174 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
 | Release the memory associated to this symbol.  |
 `-----------------------------------------------*/
 
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 static void
 yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, void *scanner)
-#else
-static void
-yydestruct (yymsg, yytype, yyvaluep, yylocationp, scanner)
-    const char *yymsg;
-    int yytype;
-    YYSTYPE *yyvaluep;
-    YYLTYPE *yylocationp;
-    void *scanner;
-#endif
 {
   YYUSE (yyvaluep);
   YYUSE (yylocationp);
   YYUSE (scanner);
-
   if (!yymsg)
     yymsg = "Deleting";
   YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
 
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   switch (yytype)
     {
-      case 6: /* STR */
-/* Line 1393 of yacc.c  */
-#line 178 "parser.y"
-        { free(((*yyvaluep).str));        };
-/* Line 1393 of yacc.c  */
-#line 1473 "parser.cpp"
+          case 6: /* STR  */
+#line 178 "parser.y" /* yacc.c:1257  */
+      { free(((*yyvaluep).str));        }
+#line 1313 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 7: /* IDENTIFIER */
-/* Line 1393 of yacc.c  */
-#line 178 "parser.y"
-        { free(((*yyvaluep).str));        };
-/* Line 1393 of yacc.c  */
-#line 1480 "parser.cpp"
+
+    case 7: /* IDENTIFIER  */
+#line 178 "parser.y" /* yacc.c:1257  */
+      { free(((*yyvaluep).str));        }
+#line 1319 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 16: /* KEYWORD_POS */
-/* Line 1393 of yacc.c  */
-#line 178 "parser.y"
-        { free(((*yyvaluep).str));        };
-/* Line 1393 of yacc.c  */
-#line 1487 "parser.cpp"
+
+    case 16: /* KEYWORD_POS  */
+#line 178 "parser.y" /* yacc.c:1257  */
+      { free(((*yyvaluep).str));        }
+#line 1325 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 23: /* PARAM */
-/* Line 1393 of yacc.c  */
-#line 179 "parser.y"
-        { if(((*yyvaluep).str)) free(((*yyvaluep).str)); };
-/* Line 1393 of yacc.c  */
-#line 1494 "parser.cpp"
+
+    case 23: /* PARAM  */
+#line 179 "parser.y" /* yacc.c:1257  */
+      { if(((*yyvaluep).str)) free(((*yyvaluep).str)); }
+#line 1331 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 26: /* CMP_OP */
-/* Line 1393 of yacc.c  */
-#line 178 "parser.y"
-        { free(((*yyvaluep).str));        };
-/* Line 1393 of yacc.c  */
-#line 1501 "parser.cpp"
+
+    case 26: /* CMP_OP  */
+#line 178 "parser.y" /* yacc.c:1257  */
+      { free(((*yyvaluep).str));        }
+#line 1337 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 50: /* commands */
-/* Line 1393 of yacc.c  */
-#line 180 "parser.y"
-        { delete ((*yyvaluep).sel);       };
-/* Line 1393 of yacc.c  */
-#line 1508 "parser.cpp"
+
+    case 50: /* commands  */
+#line 180 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).sel);       }
+#line 1343 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 51: /* command */
-/* Line 1393 of yacc.c  */
-#line 180 "parser.y"
-        { delete ((*yyvaluep).sel);       };
-/* Line 1393 of yacc.c  */
-#line 1515 "parser.cpp"
+
+    case 51: /* command  */
+#line 180 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).sel);       }
+#line 1349 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 52: /* cmd_plain */
-/* Line 1393 of yacc.c  */
-#line 180 "parser.y"
-        { delete ((*yyvaluep).sel);       };
-/* Line 1393 of yacc.c  */
-#line 1522 "parser.cpp"
+
+    case 52: /* cmd_plain  */
+#line 180 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).sel);       }
+#line 1355 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 53: /* selection */
-/* Line 1393 of yacc.c  */
-#line 180 "parser.y"
-        { delete ((*yyvaluep).sel);       };
-/* Line 1393 of yacc.c  */
-#line 1529 "parser.cpp"
+
+    case 53: /* selection  */
+#line 180 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).sel);       }
+#line 1361 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 57: /* string */
-/* Line 1393 of yacc.c  */
-#line 178 "parser.y"
-        { free(((*yyvaluep).str));        };
-/* Line 1393 of yacc.c  */
-#line 1536 "parser.cpp"
+
+    case 57: /* string  */
+#line 178 "parser.y" /* yacc.c:1257  */
+      { free(((*yyvaluep).str));        }
+#line 1367 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 58: /* sel_expr */
-/* Line 1393 of yacc.c  */
-#line 181 "parser.y"
-        { delete ((*yyvaluep).sel);       };
-/* Line 1393 of yacc.c  */
-#line 1543 "parser.cpp"
+
+    case 58: /* sel_expr  */
+#line 181 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).sel);       }
+#line 1373 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 59: /* pos_mod */
-/* Line 1393 of yacc.c  */
-#line 179 "parser.y"
-        { if(((*yyvaluep).str)) free(((*yyvaluep).str)); };
-/* Line 1393 of yacc.c  */
-#line 1550 "parser.cpp"
+
+    case 59: /* pos_mod  */
+#line 179 "parser.y" /* yacc.c:1257  */
+      { if(((*yyvaluep).str)) free(((*yyvaluep).str)); }
+#line 1379 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 61: /* num_expr */
-/* Line 1393 of yacc.c  */
-#line 181 "parser.y"
-        { delete ((*yyvaluep).sel);       };
-/* Line 1393 of yacc.c  */
-#line 1557 "parser.cpp"
+
+    case 61: /* num_expr  */
+#line 181 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).sel);       }
+#line 1385 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 62: /* str_expr */
-/* Line 1393 of yacc.c  */
-#line 181 "parser.y"
-        { delete ((*yyvaluep).sel);       };
-/* Line 1393 of yacc.c  */
-#line 1564 "parser.cpp"
+
+    case 62: /* str_expr  */
+#line 181 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).sel);       }
+#line 1391 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 63: /* pos_expr */
-/* Line 1393 of yacc.c  */
-#line 181 "parser.y"
-        { delete ((*yyvaluep).sel);       };
-/* Line 1393 of yacc.c  */
-#line 1571 "parser.cpp"
+
+    case 63: /* pos_expr  */
+#line 181 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).sel);       }
+#line 1397 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 64: /* method_params */
-/* Line 1393 of yacc.c  */
-#line 182 "parser.y"
-        { delete ((*yyvaluep).plist);       };
-/* Line 1393 of yacc.c  */
-#line 1578 "parser.cpp"
+
+    case 64: /* method_params  */
+#line 182 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).plist);       }
+#line 1403 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 65: /* method_param_list */
-/* Line 1393 of yacc.c  */
-#line 182 "parser.y"
-        { delete ((*yyvaluep).plist);       };
-/* Line 1393 of yacc.c  */
-#line 1585 "parser.cpp"
+
+    case 65: /* method_param_list  */
+#line 182 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).plist);       }
+#line 1409 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 66: /* method_param */
-/* Line 1393 of yacc.c  */
-#line 182 "parser.y"
-        { delete ((*yyvaluep).param);       };
-/* Line 1393 of yacc.c  */
-#line 1592 "parser.cpp"
+
+    case 66: /* method_param  */
+#line 182 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).param);       }
+#line 1415 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 67: /* value_list */
-/* Line 1393 of yacc.c  */
-#line 183 "parser.y"
-        { delete ((*yyvaluep).vlist);       };
-/* Line 1393 of yacc.c  */
-#line 1599 "parser.cpp"
+
+    case 67: /* value_list  */
+#line 183 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).vlist);       }
+#line 1421 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 68: /* value_list_contents */
-/* Line 1393 of yacc.c  */
-#line 183 "parser.y"
-        { delete ((*yyvaluep).vlist);       };
-/* Line 1393 of yacc.c  */
-#line 1606 "parser.cpp"
+
+    case 68: /* value_list_contents  */
+#line 183 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).vlist);       }
+#line 1427 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 69: /* basic_value_list */
-/* Line 1393 of yacc.c  */
-#line 183 "parser.y"
-        { delete ((*yyvaluep).vlist);       };
-/* Line 1393 of yacc.c  */
-#line 1613 "parser.cpp"
+
+    case 69: /* basic_value_list  */
+#line 183 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).vlist);       }
+#line 1433 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 70: /* basic_value_list_contents */
-/* Line 1393 of yacc.c  */
-#line 183 "parser.y"
-        { delete ((*yyvaluep).vlist);       };
-/* Line 1393 of yacc.c  */
-#line 1620 "parser.cpp"
+
+    case 70: /* basic_value_list_contents  */
+#line 183 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).vlist);       }
+#line 1439 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 71: /* value_item */
-/* Line 1393 of yacc.c  */
-#line 184 "parser.y"
-        { delete ((*yyvaluep).val);       };
-/* Line 1393 of yacc.c  */
-#line 1627 "parser.cpp"
+
+    case 71: /* value_item  */
+#line 184 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).val);       }
+#line 1445 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 72: /* basic_value_item */
-/* Line 1393 of yacc.c  */
-#line 184 "parser.y"
-        { delete ((*yyvaluep).val);       };
-/* Line 1393 of yacc.c  */
-#line 1634 "parser.cpp"
+
+    case 72: /* basic_value_item  */
+#line 184 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).val);       }
+#line 1451 "parser.cpp" /* yacc.c:1257  */
         break;
-      case 73: /* value_item_range */
-/* Line 1393 of yacc.c  */
-#line 184 "parser.y"
-        { delete ((*yyvaluep).val);       };
-/* Line 1393 of yacc.c  */
-#line 1641 "parser.cpp"
+
+    case 73: /* value_item_range  */
+#line 184 "parser.y" /* yacc.c:1257  */
+      { delete ((*yyvaluep).val);       }
+#line 1457 "parser.cpp" /* yacc.c:1257  */
         break;
 
+
       default:
         break;
     }
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
 }
 
 
@@ -1657,9 +1475,9 @@ struct yypstate
     int yyerrstatus;
 
     /* The stacks and their tools:
-       `yyss': related to states.
-       `yyvs': related to semantic values.
-       `yyls': related to locations.
+       'yyss': related to states.
+       'yyvs': related to semantic values.
+       'yyls': related to locations.
 
        Refer to the stacks through separate pointers, to allow yyoverflow
        to reallocate them elsewhere.  */
@@ -1689,33 +1507,19 @@ struct yypstate
   };
 
 /* Initialize the parser data structure.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 yypstate *
 yypstate_new (void)
-#else
-yypstate *
-yypstate_new ()
-
-#endif
 {
   yypstate *yyps;
   yyps = (yypstate *) malloc (sizeof *yyps);
   if (!yyps)
-    return YY_NULL;
+    return YY_NULLPTR;
   yyps->yynew = 1;
   return yyps;
 }
 
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 void
 yypstate_delete (yypstate *yyps)
-#else
-void
-yypstate_delete (yyps)
-    yypstate *yyps;
-#endif
 {
 #ifndef yyoverflow
   /* If the stack was reallocated but the parse did not complete, then the
@@ -1746,58 +1550,27 @@ yypstate_delete (yyps)
 | yypush_parse.  |
 `---------------*/
 
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 int
 yypush_parse (yypstate *yyps, int yypushed_char, YYSTYPE const *yypushed_val, YYLTYPE *yypushed_loc, void *scanner)
-#else
-int
-yypush_parse (yyps, yypushed_char, yypushed_val, yypushed_loc, scanner)
-    yypstate *yyps;
-    int yypushed_char;
-    YYSTYPE const *yypushed_val;
-    YYLTYPE *yypushed_loc;
-    void *scanner;
-#endif
 {
 /* The lookahead symbol.  */
 int yychar;
 
 
-#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
-/* Suppress an incorrect diagnostic about yylval being uninitialized.  */
-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
-    _Pragma ("GCC diagnostic push") \
-    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
-    _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
-# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
-    _Pragma ("GCC diagnostic pop")
-#else
+/* The semantic value of the lookahead symbol.  */
 /* Default value used for initialization, for pacifying older GCCs
    or non-GCC compilers.  */
-static YYSTYPE yyval_default;
-# define YY_INITIAL_VALUE(Value) = Value
-#endif
+YY_INITIAL_VALUE (static YYSTYPE yyval_default;)
+YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
+
+/* Location data for the lookahead symbol.  */
 static YYLTYPE yyloc_default
 # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
   = { 1, 1, 1, 1 }
 # endif
 ;
-#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-# define YY_IGNORE_MAYBE_UNINITIALIZED_END
-#endif
-#ifndef YY_INITIAL_VALUE
-# define YY_INITIAL_VALUE(Value) /* Nothing. */
-#endif
-
-/* The semantic value of the lookahead symbol.  */
-YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
-
-/* Location data for the lookahead symbol.  */
 YYLTYPE yylloc = yyloc_default;
 
-
   int yyn;
   int yyresult;
   /* Lookahead token as an internal (translated) token number.  */
@@ -1858,26 +1631,26 @@ YYLTYPE yylloc = yyloc_default;
 
 #ifdef yyoverflow
       {
-       /* Give user a chance to reallocate the stack.  Use copies of
-          these so that the &'s don't force the real ones into
-          memory.  */
-       YYSTYPE *yyvs1 = yyvs;
-       yytype_int16 *yyss1 = yyss;
-       YYLTYPE *yyls1 = yyls;
-
-       /* Each stack pointer address is followed by the size of the
-          data in use in that stack, in bytes.  This used to be a
-          conditional around just the two extra args, but that might
-          be undefined if yyoverflow is a macro.  */
-       yyoverflow (YY_("memory exhausted"),
-                   &yyss1, yysize * sizeof (*yyssp),
-                   &yyvs1, yysize * sizeof (*yyvsp),
-                   &yyls1, yysize * sizeof (*yylsp),
-                   &yystacksize);
-
-       yyls = yyls1;
-       yyss = yyss1;
-       yyvs = yyvs1;
+        /* Give user a chance to reallocate the stack.  Use copies of
+           these so that the &'s don't force the real ones into
+           memory.  */
+        YYSTYPE *yyvs1 = yyvs;
+        yytype_int16 *yyss1 = yyss;
+        YYLTYPE *yyls1 = yyls;
+
+        /* Each stack pointer address is followed by the size of the
+           data in use in that stack, in bytes.  This used to be a
+           conditional around just the two extra args, but that might
+           be undefined if yyoverflow is a macro.  */
+        yyoverflow (YY_("memory exhausted"),
+                    &yyss1, yysize * sizeof (*yyssp),
+                    &yyvs1, yysize * sizeof (*yyvsp),
+                    &yyls1, yysize * sizeof (*yylsp),
+                    &yystacksize);
+
+        yyls = yyls1;
+        yyss = yyss1;
+        yyvs = yyvs1;
       }
 #else /* no yyoverflow */
 # ifndef YYSTACK_RELOCATE
@@ -1885,23 +1658,23 @@ YYLTYPE yylloc = yyloc_default;
 # else
       /* Extend the stack our own way.  */
       if (YYMAXDEPTH <= yystacksize)
-       goto yyexhaustedlab;
+        goto yyexhaustedlab;
       yystacksize *= 2;
       if (YYMAXDEPTH < yystacksize)
-       yystacksize = YYMAXDEPTH;
+        yystacksize = YYMAXDEPTH;
 
       {
-       yytype_int16 *yyss1 = yyss;
-       union yyalloc *yyptr =
-         (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
-       if (! yyptr)
-         goto yyexhaustedlab;
-       YYSTACK_RELOCATE (yyss_alloc, yyss);
-       YYSTACK_RELOCATE (yyvs_alloc, yyvs);
-       YYSTACK_RELOCATE (yyls_alloc, yyls);
+        yytype_int16 *yyss1 = yyss;
+        union yyalloc *yyptr =
+          (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+        if (! yyptr)
+          goto yyexhaustedlab;
+        YYSTACK_RELOCATE (yyss_alloc, yyss);
+        YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+        YYSTACK_RELOCATE (yyls_alloc, yyls);
 #  undef YYSTACK_RELOCATE
-       if (yyss1 != yyssa)
-         YYSTACK_FREE (yyss1);
+        if (yyss1 != yyssa)
+          YYSTACK_FREE (yyss1);
       }
 # endif
 #endif /* no yyoverflow */
@@ -1911,10 +1684,10 @@ YYLTYPE yylloc = yyloc_default;
       yylsp = yyls + yysize - 1;
 
       YYDPRINTF ((stderr, "Stack size increased to %lu\n",
-                 (unsigned long int) yystacksize));
+                  (unsigned long int) yystacksize));
 
       if (yyss + yystacksize - 1 <= yyssp)
-       YYABORT;
+        YYABORT;
     }
 
   YYDPRINTF ((stderr, "Entering state %d\n", yystate));
@@ -2020,7 +1793,7 @@ yyreduce:
   yylen = yyr2[yyn];
 
   /* If YYLEN is nonzero, implement the default value of the action:
-     `$$ = $1'.
+     '$$ = $1'.
 
      Otherwise, the following line sets YYVAL to garbage.
      This behavior is undocumented and Bison
@@ -2035,36 +1808,37 @@ yyreduce:
   switch (yyn)
     {
         case 2:
-/* Line 1787 of yacc.c  */
-#line 199 "parser.y"
+#line 199 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
                  set_empty((yyval.sel));
                  END_ACTION_TOPLEVEL;
              }
+#line 1818 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 3:
-/* Line 1787 of yacc.c  */
-#line 205 "parser.y"
+#line 205 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_append_selection(get((yyvsp[(2) - (2)].sel)), get((yyvsp[(1) - (2)].sel)), scanner));
-                 if (_gmx_sel_parser_should_finish(scanner))
+                 set((yyval.sel), _gmx_sel_append_selection(get((yyvsp[0].sel)), get((yyvsp[-1].sel)), scanner));
+                 if (_gmx_sel_parser_should_finish(scanner)) {
+                     delete (yyval.sel);
                      YYACCEPT;
+                 }
                  END_ACTION_TOPLEVEL;
              }
+#line 1832 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 4:
-/* Line 1787 of yacc.c  */
-#line 215 "parser.y"
-    { (yyval.sel) = (yyvsp[(1) - (2)].sel); }
+#line 217 "parser.y" /* yacc.c:1646  */
+    { (yyval.sel) = (yyvsp[-1].sel); }
+#line 1838 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 5:
-/* Line 1787 of yacc.c  */
-#line 217 "parser.y"
+#line 219 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
                  _gmx_sel_lexer_clear_method_stack(scanner);
@@ -2080,191 +1854,191 @@ yyreduce:
                  set_empty((yyval.sel));
                  END_ACTION_TOPLEVEL;
              }
+#line 1858 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 6:
-/* Line 1787 of yacc.c  */
-#line 236 "parser.y"
+#line 238 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
                  set_empty((yyval.sel));
                  END_ACTION;
              }
+#line 1868 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 7:
-/* Line 1787 of yacc.c  */
-#line 242 "parser.y"
+#line 244 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer s
-                        = _gmx_sel_init_group_by_id((yyvsp[(1) - (1)].i), scanner);
+                        = _gmx_sel_init_group_by_id((yyvsp[0].i), scanner);
                  SelectionTreeElementPointer p
                         = _gmx_sel_init_position(s, NULL, scanner);
                  if (!p) YYERROR;
                  set((yyval.sel), _gmx_sel_init_selection(NULL, p, scanner));
                  END_ACTION;
              }
+#line 1883 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 8:
-/* Line 1787 of yacc.c  */
-#line 253 "parser.y"
+#line 255 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree nameGuard((yyvsp[(1) - (1)].str));
+                 scoped_guard_sfree nameGuard((yyvsp[0].str));
                  SelectionTreeElementPointer s
-                        = _gmx_sel_init_group_by_name((yyvsp[(1) - (1)].str), scanner);
+                        = _gmx_sel_init_group_by_name((yyvsp[0].str), scanner);
                  SelectionTreeElementPointer p
                         = _gmx_sel_init_position(s, NULL, scanner);
                  if (!p) YYERROR;
                  set((yyval.sel), _gmx_sel_init_selection(NULL, p, scanner));
                  END_ACTION;
              }
+#line 1899 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 9:
-/* Line 1787 of yacc.c  */
-#line 265 "parser.y"
+#line 267 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_selection(NULL, get((yyvsp[(1) - (1)].sel)), scanner));
+                 set((yyval.sel), _gmx_sel_init_selection(NULL, get((yyvsp[0].sel)), scanner));
                  END_ACTION;
              }
+#line 1909 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 10:
-/* Line 1787 of yacc.c  */
-#line 271 "parser.y"
+#line 273 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree nameGuard((yyvsp[(1) - (2)].str));
-                 set((yyval.sel), _gmx_sel_init_selection((yyvsp[(1) - (2)].str), get((yyvsp[(2) - (2)].sel)), scanner));
+                 scoped_guard_sfree nameGuard((yyvsp[-1].str));
+                 set((yyval.sel), _gmx_sel_init_selection((yyvsp[-1].str), get((yyvsp[0].sel)), scanner));
                  END_ACTION;
              }
+#line 1920 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 11:
-/* Line 1787 of yacc.c  */
-#line 278 "parser.y"
+#line 280 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree nameGuard((yyvsp[(1) - (3)].str));
-                 set((yyval.sel), _gmx_sel_assign_variable((yyvsp[(1) - (3)].str), get((yyvsp[(3) - (3)].sel)), scanner));
+                 scoped_guard_sfree nameGuard((yyvsp[-2].str));
+                 set((yyval.sel), _gmx_sel_assign_variable((yyvsp[-2].str), get((yyvsp[0].sel)), scanner));
                  END_ACTION;
              }
+#line 1931 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 12:
-/* Line 1787 of yacc.c  */
-#line 285 "parser.y"
+#line 287 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree nameGuard((yyvsp[(1) - (3)].str));
-                 set((yyval.sel), _gmx_sel_assign_variable((yyvsp[(1) - (3)].str), get((yyvsp[(3) - (3)].sel)), scanner));
+                 scoped_guard_sfree nameGuard((yyvsp[-2].str));
+                 set((yyval.sel), _gmx_sel_assign_variable((yyvsp[-2].str), get((yyvsp[0].sel)), scanner));
                  END_ACTION;
              }
+#line 1942 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 13:
-/* Line 1787 of yacc.c  */
-#line 292 "parser.y"
+#line 294 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree nameGuard((yyvsp[(1) - (3)].str));
-                 set((yyval.sel), _gmx_sel_assign_variable((yyvsp[(1) - (3)].str), get((yyvsp[(3) - (3)].sel)), scanner));
+                 scoped_guard_sfree nameGuard((yyvsp[-2].str));
+                 set((yyval.sel), _gmx_sel_assign_variable((yyvsp[-2].str), get((yyvsp[0].sel)), scanner));
                  END_ACTION;
              }
+#line 1953 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 14:
-/* Line 1787 of yacc.c  */
-#line 301 "parser.y"
-    { (yyval.sel) = (yyvsp[(1) - (1)].sel); }
+#line 303 "parser.y" /* yacc.c:1646  */
+    { (yyval.sel) = (yyvsp[0].sel); }
+#line 1959 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 15:
-/* Line 1787 of yacc.c  */
-#line 303 "parser.y"
+#line 305 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_position(get((yyvsp[(1) - (1)].sel)), NULL, scanner));
+                 set((yyval.sel), _gmx_sel_init_position(get((yyvsp[0].sel)), NULL, scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 1970 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 16:
-/* Line 1787 of yacc.c  */
-#line 309 "parser.y"
-    { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
+#line 311 "parser.y" /* yacc.c:1646  */
+    { (yyval.sel) = (yyvsp[-1].sel); }
+#line 1976 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 17:
-/* Line 1787 of yacc.c  */
-#line 311 "parser.y"
+#line 313 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_modifier((yyvsp[(2) - (3)].meth), get((yyvsp[(3) - (3)].plist)), get((yyvsp[(1) - (3)].sel)), scanner));
+                 set((yyval.sel), _gmx_sel_init_modifier((yyvsp[-1].meth), get((yyvsp[0].plist)), get((yyvsp[-2].sel)), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 1987 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 18:
-/* Line 1787 of yacc.c  */
-#line 324 "parser.y"
-    { (yyval.i) = (yyvsp[(1) - (1)].i); }
+#line 326 "parser.y" /* yacc.c:1646  */
+    { (yyval.i) = (yyvsp[0].i); }
+#line 1993 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 19:
-/* Line 1787 of yacc.c  */
-#line 325 "parser.y"
-    { (yyval.i) = -(yyvsp[(2) - (2)].i); }
+#line 327 "parser.y" /* yacc.c:1646  */
+    { (yyval.i) = -(yyvsp[0].i); }
+#line 1999 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 20:
-/* Line 1787 of yacc.c  */
-#line 329 "parser.y"
-    { (yyval.r) = (yyvsp[(1) - (1)].r); }
+#line 331 "parser.y" /* yacc.c:1646  */
+    { (yyval.r) = (yyvsp[0].r); }
+#line 2005 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 21:
-/* Line 1787 of yacc.c  */
-#line 330 "parser.y"
-    { (yyval.r) = -(yyvsp[(2) - (2)].r); }
+#line 332 "parser.y" /* yacc.c:1646  */
+    { (yyval.r) = -(yyvsp[0].r); }
+#line 2011 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 22:
-/* Line 1787 of yacc.c  */
-#line 333 "parser.y"
-    { (yyval.r) = (yyvsp[(1) - (1)].i); }
+#line 335 "parser.y" /* yacc.c:1646  */
+    { (yyval.r) = (yyvsp[0].i); }
+#line 2017 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 23:
-/* Line 1787 of yacc.c  */
-#line 334 "parser.y"
-    { (yyval.r) = (yyvsp[(1) - (1)].r); }
+#line 336 "parser.y" /* yacc.c:1646  */
+    { (yyval.r) = (yyvsp[0].r); }
+#line 2023 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 24:
-/* Line 1787 of yacc.c  */
-#line 337 "parser.y"
-    { (yyval.str) = (yyvsp[(1) - (1)].str); }
+#line 339 "parser.y" /* yacc.c:1646  */
+    { (yyval.str) = (yyvsp[0].str); }
+#line 2029 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 25:
-/* Line 1787 of yacc.c  */
-#line 338 "parser.y"
-    { (yyval.str) = (yyvsp[(1) - (1)].str); }
+#line 340 "parser.y" /* yacc.c:1646  */
+    { (yyval.str) = (yyvsp[0].str); }
+#line 2035 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 26:
-/* Line 1787 of yacc.c  */
-#line 347 "parser.y"
+#line 349 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 SelectionTreeElementPointer arg(get((yyvsp[(2) - (2)].sel)));
+                 SelectionTreeElementPointer arg(get((yyvsp[0].sel)));
                  SelectionTreeElementPointer sel(
                         new SelectionTreeElement(SEL_BOOLEAN, (yyloc)));
                  sel->u.boolt = BOOL_NOT;
@@ -2272,14 +2046,14 @@ yyreduce:
                  set((yyval.sel), sel);
                  END_ACTION;
              }
+#line 2050 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 27:
-/* Line 1787 of yacc.c  */
-#line 358 "parser.y"
+#line 360 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 SelectionTreeElementPointer arg1(get((yyvsp[(1) - (3)].sel))), arg2(get((yyvsp[(3) - (3)].sel)));
+                 SelectionTreeElementPointer arg1(get((yyvsp[-2].sel))), arg2(get((yyvsp[0].sel)));
                  SelectionTreeElementPointer sel(
                         new SelectionTreeElement(SEL_BOOLEAN, (yyloc)));
                  sel->u.boolt = BOOL_AND;
@@ -2287,14 +2061,14 @@ yyreduce:
                  set((yyval.sel), sel);
                  END_ACTION;
              }
+#line 2065 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 28:
-/* Line 1787 of yacc.c  */
-#line 369 "parser.y"
+#line 371 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 SelectionTreeElementPointer arg1(get((yyvsp[(1) - (3)].sel))), arg2(get((yyvsp[(3) - (3)].sel)));
+                 SelectionTreeElementPointer arg1(get((yyvsp[-2].sel))), arg2(get((yyvsp[0].sel)));
                  SelectionTreeElementPointer sel(
                         new SelectionTreeElement(SEL_BOOLEAN, (yyloc)));
                  sel->u.boolt = BOOL_OR;
@@ -2302,618 +2076,618 @@ yyreduce:
                  set((yyval.sel), sel);
                  END_ACTION;
              }
+#line 2080 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 29:
-/* Line 1787 of yacc.c  */
-#line 379 "parser.y"
-    { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
+#line 381 "parser.y" /* yacc.c:1646  */
+    { (yyval.sel) = (yyvsp[-1].sel); }
+#line 2086 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 30:
-/* Line 1787 of yacc.c  */
-#line 384 "parser.y"
+#line 386 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree opGuard((yyvsp[(2) - (3)].str));
-                 set((yyval.sel), _gmx_sel_init_comparison(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), (yyvsp[(2) - (3)].str), scanner));
+                 scoped_guard_sfree opGuard((yyvsp[-1].str));
+                 set((yyval.sel), _gmx_sel_init_comparison(get((yyvsp[-2].sel)), get((yyvsp[0].sel)), (yyvsp[-1].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2098 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 31:
-/* Line 1787 of yacc.c  */
-#line 395 "parser.y"
+#line 397 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree nameGuard((yyvsp[(2) - (2)].str));
-                 set((yyval.sel), _gmx_sel_init_group_by_name((yyvsp[(2) - (2)].str), scanner));
+                 scoped_guard_sfree nameGuard((yyvsp[0].str));
+                 set((yyval.sel), _gmx_sel_init_group_by_name((yyvsp[0].str), scanner));
                  END_ACTION;
              }
+#line 2109 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 32:
-/* Line 1787 of yacc.c  */
-#line 402 "parser.y"
+#line 404 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_group_by_id((yyvsp[(2) - (2)].i), scanner));
+                 set((yyval.sel), _gmx_sel_init_group_by_id((yyvsp[0].i), scanner));
                  END_ACTION;
              }
+#line 2119 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 33:
-/* Line 1787 of yacc.c  */
-#line 410 "parser.y"
+#line 412 "parser.y" /* yacc.c:1646  */
     { (yyval.str) = NULL; }
+#line 2125 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 34:
-/* Line 1787 of yacc.c  */
-#line 411 "parser.y"
-    { (yyval.str) = (yyvsp[(1) - (1)].str);   }
+#line 413 "parser.y" /* yacc.c:1646  */
+    { (yyval.str) = (yyvsp[0].str);   }
+#line 2131 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 35:
-/* Line 1787 of yacc.c  */
-#line 416 "parser.y"
+#line 418 "parser.y" /* yacc.c:1646  */
     { (yyval.smt) = gmx::eStringMatchType_RegularExpression; }
+#line 2137 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 36:
-/* Line 1787 of yacc.c  */
-#line 417 "parser.y"
+#line 419 "parser.y" /* yacc.c:1646  */
     { (yyval.smt) = gmx::eStringMatchType_Wildcard; }
+#line 2143 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 37:
-/* Line 1787 of yacc.c  */
-#line 418 "parser.y"
+#line 420 "parser.y" /* yacc.c:1646  */
     { (yyval.smt) = gmx::eStringMatchType_Exact; }
+#line 2149 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 38:
-/* Line 1787 of yacc.c  */
-#line 423 "parser.y"
+#line 425 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree posmodGuard((yyvsp[(1) - (2)].str));
-                 set((yyval.sel), _gmx_sel_init_keyword((yyvsp[(2) - (2)].meth), SelectionParserValueListPointer(), (yyvsp[(1) - (2)].str), scanner));
+                 scoped_guard_sfree posmodGuard((yyvsp[-1].str));
+                 set((yyval.sel), _gmx_sel_init_keyword((yyvsp[0].meth), SelectionParserValueListPointer(), (yyvsp[-1].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2161 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 39:
-/* Line 1787 of yacc.c  */
-#line 431 "parser.y"
+#line 433 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree posmodGuard((yyvsp[(1) - (3)].str));
-                 set((yyval.sel), _gmx_sel_init_keyword_strmatch((yyvsp[(2) - (3)].meth), gmx::eStringMatchType_Auto, get((yyvsp[(3) - (3)].vlist)), (yyvsp[(1) - (3)].str), scanner));
+                 scoped_guard_sfree posmodGuard((yyvsp[-2].str));
+                 set((yyval.sel), _gmx_sel_init_keyword_strmatch((yyvsp[-1].meth), gmx::eStringMatchType_Auto, get((yyvsp[0].vlist)), (yyvsp[-2].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2173 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 40:
-/* Line 1787 of yacc.c  */
-#line 439 "parser.y"
+#line 441 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree posmodGuard((yyvsp[(1) - (4)].str));
-                 set((yyval.sel), _gmx_sel_init_keyword_strmatch((yyvsp[(2) - (4)].meth), (yyvsp[(3) - (4)].smt), get((yyvsp[(4) - (4)].vlist)), (yyvsp[(1) - (4)].str), scanner));
+                 scoped_guard_sfree posmodGuard((yyvsp[-3].str));
+                 set((yyval.sel), _gmx_sel_init_keyword_strmatch((yyvsp[-2].meth), (yyvsp[-1].smt), get((yyvsp[0].vlist)), (yyvsp[-3].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2185 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 41:
-/* Line 1787 of yacc.c  */
-#line 447 "parser.y"
+#line 449 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree posmodGuard((yyvsp[(1) - (3)].str));
-                 set((yyval.sel), _gmx_sel_init_keyword((yyvsp[(2) - (3)].meth), get((yyvsp[(3) - (3)].vlist)), (yyvsp[(1) - (3)].str), scanner));
+                 scoped_guard_sfree posmodGuard((yyvsp[-2].str));
+                 set((yyval.sel), _gmx_sel_init_keyword((yyvsp[-1].meth), get((yyvsp[0].vlist)), (yyvsp[-2].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2197 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 42:
-/* Line 1787 of yacc.c  */
-#line 458 "parser.y"
+#line 460 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree posmodGuard((yyvsp[(1) - (3)].str));
-                 set((yyval.sel), _gmx_sel_init_method((yyvsp[(2) - (3)].meth), get((yyvsp[(3) - (3)].plist)), (yyvsp[(1) - (3)].str), scanner));
+                 scoped_guard_sfree posmodGuard((yyvsp[-2].str));
+                 set((yyval.sel), _gmx_sel_init_method((yyvsp[-1].meth), get((yyvsp[0].plist)), (yyvsp[-2].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2209 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 43:
-/* Line 1787 of yacc.c  */
-#line 473 "parser.y"
+#line 475 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer sel(
                         new SelectionTreeElement(SEL_CONST, (yyloc)));
                  _gmx_selelem_set_vtype(sel, INT_VALUE);
                  _gmx_selvalue_reserve(&sel->v, 1);
-                 sel->v.u.i[0] = (yyvsp[(1) - (1)].i);
+                 sel->v.u.i[0] = (yyvsp[0].i);
                  set((yyval.sel), sel);
                  END_ACTION;
              }
+#line 2224 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 44:
-/* Line 1787 of yacc.c  */
-#line 484 "parser.y"
+#line 486 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer sel(
                         new SelectionTreeElement(SEL_CONST, (yyloc)));
                  _gmx_selelem_set_vtype(sel, REAL_VALUE);
                  _gmx_selvalue_reserve(&sel->v, 1);
-                 sel->v.u.r[0] = (yyvsp[(1) - (1)].r);
+                 sel->v.u.r[0] = (yyvsp[0].r);
                  set((yyval.sel), sel);
                  END_ACTION;
              }
+#line 2239 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 45:
-/* Line 1787 of yacc.c  */
-#line 498 "parser.y"
+#line 500 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree posmodGuard((yyvsp[(1) - (2)].str));
-                 set((yyval.sel), _gmx_sel_init_keyword((yyvsp[(2) - (2)].meth), SelectionParserValueListPointer(), (yyvsp[(1) - (2)].str), scanner));
+                 scoped_guard_sfree posmodGuard((yyvsp[-1].str));
+                 set((yyval.sel), _gmx_sel_init_keyword((yyvsp[0].meth), SelectionParserValueListPointer(), (yyvsp[-1].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2251 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 46:
-/* Line 1787 of yacc.c  */
-#line 506 "parser.y"
+#line 508 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree posmodGuard((yyvsp[(1) - (4)].str));
-                 set((yyval.sel), _gmx_sel_init_keyword_of((yyvsp[(2) - (4)].meth), get((yyvsp[(4) - (4)].sel)), (yyvsp[(1) - (4)].str), scanner));
+                 scoped_guard_sfree posmodGuard((yyvsp[-3].str));
+                 set((yyval.sel), _gmx_sel_init_keyword_of((yyvsp[-2].meth), get((yyvsp[0].sel)), (yyvsp[-3].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2263 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 47:
-/* Line 1787 of yacc.c  */
-#line 514 "parser.y"
+#line 516 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree posmodGuard((yyvsp[(1) - (3)].str));
-                 set((yyval.sel), _gmx_sel_init_method((yyvsp[(2) - (3)].meth), get((yyvsp[(3) - (3)].plist)), (yyvsp[(1) - (3)].str), scanner));
+                 scoped_guard_sfree posmodGuard((yyvsp[-2].str));
+                 set((yyval.sel), _gmx_sel_init_method((yyvsp[-1].meth), get((yyvsp[0].plist)), (yyvsp[-2].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2275 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 48:
-/* Line 1787 of yacc.c  */
-#line 525 "parser.y"
+#line 527 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '+', scanner));
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[-2].sel)), get((yyvsp[0].sel)), '+', scanner));
                  END_ACTION;
              }
+#line 2285 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 49:
-/* Line 1787 of yacc.c  */
-#line 531 "parser.y"
+#line 533 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '-', scanner));
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[-2].sel)), get((yyvsp[0].sel)), '-', scanner));
                  END_ACTION;
              }
+#line 2295 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 50:
-/* Line 1787 of yacc.c  */
-#line 537 "parser.y"
+#line 539 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '*', scanner));
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[-2].sel)), get((yyvsp[0].sel)), '*', scanner));
                  END_ACTION;
              }
+#line 2305 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 51:
-/* Line 1787 of yacc.c  */
-#line 543 "parser.y"
+#line 545 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '/', scanner));
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[-2].sel)), get((yyvsp[0].sel)), '/', scanner));
                  END_ACTION;
              }
+#line 2315 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 52:
-/* Line 1787 of yacc.c  */
-#line 549 "parser.y"
+#line 551 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(2) - (2)].sel)), SelectionTreeElementPointer(), '-', scanner));
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[0].sel)), SelectionTreeElementPointer(), '-', scanner));
                  END_ACTION;
              }
+#line 2325 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 53:
-/* Line 1787 of yacc.c  */
-#line 555 "parser.y"
+#line 557 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '^', scanner));
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[-2].sel)), get((yyvsp[0].sel)), '^', scanner));
                  END_ACTION;
              }
+#line 2335 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 54:
-/* Line 1787 of yacc.c  */
-#line 560 "parser.y"
-    { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
+#line 562 "parser.y" /* yacc.c:1646  */
+    { (yyval.sel) = (yyvsp[-1].sel); }
+#line 2341 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 55:
-/* Line 1787 of yacc.c  */
-#line 568 "parser.y"
+#line 570 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer sel(
                         new SelectionTreeElement(SEL_CONST, (yyloc)));
                  _gmx_selelem_set_vtype(sel, STR_VALUE);
                  _gmx_selvalue_reserve(&sel->v, 1);
-                 sel->v.u.s[0] = (yyvsp[(1) - (1)].str);
+                 sel->v.u.s[0] = (yyvsp[0].str);
                  set((yyval.sel), sel);
                  END_ACTION;
              }
+#line 2356 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 56:
-/* Line 1787 of yacc.c  */
-#line 579 "parser.y"
+#line 581 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree posmodGuard((yyvsp[(1) - (2)].str));
-                 set((yyval.sel), _gmx_sel_init_keyword((yyvsp[(2) - (2)].meth), SelectionParserValueListPointer(), (yyvsp[(1) - (2)].str), scanner));
+                 scoped_guard_sfree posmodGuard((yyvsp[-1].str));
+                 set((yyval.sel), _gmx_sel_init_keyword((yyvsp[0].meth), SelectionParserValueListPointer(), (yyvsp[-1].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2368 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 57:
-/* Line 1787 of yacc.c  */
-#line 594 "parser.y"
+#line 596 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_const_position((yyvsp[(2) - (7)].r), (yyvsp[(4) - (7)].r), (yyvsp[(6) - (7)].r), scanner));
+                 set((yyval.sel), _gmx_sel_init_const_position((yyvsp[-5].r), (yyvsp[-3].r), (yyvsp[-1].r), scanner));
                  END_ACTION;
              }
+#line 2378 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 58:
-/* Line 1787 of yacc.c  */
-#line 602 "parser.y"
-    { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
+#line 604 "parser.y" /* yacc.c:1646  */
+    { (yyval.sel) = (yyvsp[-1].sel); }
+#line 2384 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 59:
-/* Line 1787 of yacc.c  */
-#line 607 "parser.y"
+#line 609 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_method((yyvsp[(1) - (2)].meth), get((yyvsp[(2) - (2)].plist)), NULL, scanner));
+                 set((yyval.sel), _gmx_sel_init_method((yyvsp[-1].meth), get((yyvsp[0].plist)), NULL, scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2395 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 60:
-/* Line 1787 of yacc.c  */
-#line 617 "parser.y"
+#line 619 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree keywordGuard((yyvsp[(1) - (3)].str));
-                 set((yyval.sel), _gmx_sel_init_position(get((yyvsp[(3) - (3)].sel)), (yyvsp[(1) - (3)].str), scanner));
+                 scoped_guard_sfree keywordGuard((yyvsp[-2].str));
+                 set((yyval.sel), _gmx_sel_init_position(get((yyvsp[0].sel)), (yyvsp[-2].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
+#line 2407 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 61:
-/* Line 1787 of yacc.c  */
-#line 631 "parser.y"
+#line 633 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel)), scanner));
+                 set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[0].sel)), scanner));
                  END_ACTION;
              }
+#line 2417 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 62:
-/* Line 1787 of yacc.c  */
-#line 639 "parser.y"
+#line 641 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel)), scanner));
+                 set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[0].sel)), scanner));
                  END_ACTION;
              }
+#line 2427 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 63:
-/* Line 1787 of yacc.c  */
-#line 647 "parser.y"
+#line 649 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel)), scanner));
+                 set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[0].sel)), scanner));
                  END_ACTION;
              }
+#line 2437 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 64:
-/* Line 1787 of yacc.c  */
-#line 660 "parser.y"
-    { (yyval.plist) = (yyvsp[(1) - (1)].plist); }
+#line 662 "parser.y" /* yacc.c:1646  */
+    { (yyval.plist) = (yyvsp[0].plist); }
+#line 2443 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 65:
-/* Line 1787 of yacc.c  */
-#line 662 "parser.y"
-    { (yyval.plist) = (yyvsp[(1) - (2)].plist); }
+#line 664 "parser.y" /* yacc.c:1646  */
+    { (yyval.plist) = (yyvsp[-1].plist); }
+#line 2449 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 66:
-/* Line 1787 of yacc.c  */
-#line 667 "parser.y"
+#line 669 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
                  set((yyval.plist), SelectionParserParameter::createList());
                  END_ACTION;
              }
+#line 2459 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 67:
-/* Line 1787 of yacc.c  */
-#line 673 "parser.y"
+#line 675 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 SelectionParserParameterListPointer list(get((yyvsp[(1) - (2)].plist)));
-                 list->push_back(get((yyvsp[(2) - (2)].param)));
+                 SelectionParserParameterListPointer list(get((yyvsp[-1].plist)));
+                 list->push_back(get((yyvsp[0].param)));
                  set((yyval.plist), std::move(list));
                  END_ACTION;
              }
+#line 2471 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 68:
-/* Line 1787 of yacc.c  */
-#line 684 "parser.y"
+#line 686 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree nameGuard((yyvsp[(1) - (2)].str));
-                 set((yyval.param), SelectionParserParameter::create((yyvsp[(1) - (2)].str), get((yyvsp[(2) - (2)].vlist)), (yyloc)));
+                 scoped_guard_sfree nameGuard((yyvsp[-1].str));
+                 set((yyval.param), SelectionParserParameter::create((yyvsp[-1].str), get((yyvsp[0].vlist)), (yyloc)));
                  END_ACTION;
              }
+#line 2482 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 69:
-/* Line 1787 of yacc.c  */
-#line 692 "parser.y"
-    { (yyval.vlist) = (yyvsp[(1) - (1)].vlist);   }
+#line 694 "parser.y" /* yacc.c:1646  */
+    { (yyval.vlist) = (yyvsp[0].vlist);   }
+#line 2488 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 70:
-/* Line 1787 of yacc.c  */
-#line 693 "parser.y"
-    { (yyval.vlist) = (yyvsp[(2) - (3)].vlist);   }
+#line 695 "parser.y" /* yacc.c:1646  */
+    { (yyval.vlist) = (yyvsp[-1].vlist);   }
+#line 2494 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 71:
-/* Line 1787 of yacc.c  */
-#line 698 "parser.y"
+#line 700 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
                  set((yyval.vlist), SelectionParserValue::createList());
                  END_ACTION;
              }
+#line 2504 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 72:
-/* Line 1787 of yacc.c  */
-#line 704 "parser.y"
+#line 706 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 SelectionParserValueListPointer list(get((yyvsp[(1) - (2)].vlist)));
-                 list->push_back(get((yyvsp[(2) - (2)].val)));
+                 SelectionParserValueListPointer list(get((yyvsp[-1].vlist)));
+                 list->push_back(get((yyvsp[0].val)));
                  set((yyval.vlist), std::move(list));
                  END_ACTION;
              }
+#line 2516 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 73:
-/* Line 1787 of yacc.c  */
-#line 712 "parser.y"
+#line 714 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 SelectionParserValueListPointer list(get((yyvsp[(1) - (3)].vlist)));
-                 list->push_back(get((yyvsp[(3) - (3)].val)));
+                 SelectionParserValueListPointer list(get((yyvsp[-2].vlist)));
+                 list->push_back(get((yyvsp[0].val)));
                  set((yyval.vlist), std::move(list));
                  END_ACTION;
              }
+#line 2528 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 74:
-/* Line 1787 of yacc.c  */
-#line 722 "parser.y"
-    { (yyval.vlist) = (yyvsp[(1) - (1)].vlist); }
+#line 724 "parser.y" /* yacc.c:1646  */
+    { (yyval.vlist) = (yyvsp[0].vlist); }
+#line 2534 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 75:
-/* Line 1787 of yacc.c  */
-#line 723 "parser.y"
-    { (yyval.vlist) = (yyvsp[(2) - (3)].vlist); }
+#line 725 "parser.y" /* yacc.c:1646  */
+    { (yyval.vlist) = (yyvsp[-1].vlist); }
+#line 2540 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 76:
-/* Line 1787 of yacc.c  */
-#line 728 "parser.y"
+#line 730 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.vlist), SelectionParserValue::createList(get((yyvsp[(1) - (1)].val))));
+                 set((yyval.vlist), SelectionParserValue::createList(get((yyvsp[0].val))));
                  END_ACTION;
              }
+#line 2550 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 77:
-/* Line 1787 of yacc.c  */
-#line 734 "parser.y"
+#line 736 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 SelectionParserValueListPointer list(get((yyvsp[(1) - (2)].vlist)));
-                 list->push_back(get((yyvsp[(2) - (2)].val)));
+                 SelectionParserValueListPointer list(get((yyvsp[-1].vlist)));
+                 list->push_back(get((yyvsp[0].val)));
                  set((yyval.vlist), std::move(list));
                  END_ACTION;
              }
+#line 2562 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 78:
-/* Line 1787 of yacc.c  */
-#line 742 "parser.y"
+#line 744 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 SelectionParserValueListPointer list(get((yyvsp[(1) - (3)].vlist)));
-                 list->push_back(get((yyvsp[(3) - (3)].val)));
+                 SelectionParserValueListPointer list(get((yyvsp[-2].vlist)));
+                 list->push_back(get((yyvsp[0].val)));
                  set((yyval.vlist), std::move(list));
                  END_ACTION;
              }
+#line 2574 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 79:
-/* Line 1787 of yacc.c  */
-#line 752 "parser.y"
+#line 754 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
+                 set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[0].sel))));
                  END_ACTION;
              }
+#line 2584 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 80:
-/* Line 1787 of yacc.c  */
-#line 758 "parser.y"
+#line 760 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
+                 set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[0].sel))));
                  END_ACTION;
              }
+#line 2594 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 81:
-/* Line 1787 of yacc.c  */
-#line 764 "parser.y"
+#line 766 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
+                 set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[0].sel))));
                  END_ACTION;
              }
+#line 2604 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 82:
-/* Line 1787 of yacc.c  */
-#line 770 "parser.y"
+#line 772 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
+                 set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[0].sel))));
                  END_ACTION;
              }
+#line 2614 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 83:
-/* Line 1787 of yacc.c  */
-#line 775 "parser.y"
-    { (yyval.val) = (yyvsp[(1) - (1)].val); }
+#line 777 "parser.y" /* yacc.c:1646  */
+    { (yyval.val) = (yyvsp[0].val); }
+#line 2620 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 84:
-/* Line 1787 of yacc.c  */
-#line 780 "parser.y"
+#line 782 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.val), SelectionParserValue::createInteger((yyvsp[(1) - (1)].i), (yyloc)));
+                 set((yyval.val), SelectionParserValue::createInteger((yyvsp[0].i), (yyloc)));
                  END_ACTION;
              }
+#line 2630 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 85:
-/* Line 1787 of yacc.c  */
-#line 786 "parser.y"
+#line 788 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.val), SelectionParserValue::createReal((yyvsp[(1) - (1)].r), (yyloc)));
+                 set((yyval.val), SelectionParserValue::createReal((yyvsp[0].r), (yyloc)));
                  END_ACTION;
              }
+#line 2640 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 86:
-/* Line 1787 of yacc.c  */
-#line 792 "parser.y"
+#line 794 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree stringGuard((yyvsp[(1) - (1)].str));
-                 set((yyval.val), SelectionParserValue::createString((yyvsp[(1) - (1)].str), (yyloc)));
+                 scoped_guard_sfree stringGuard((yyvsp[0].str));
+                 set((yyval.val), SelectionParserValue::createString((yyvsp[0].str), (yyloc)));
                  END_ACTION;
              }
+#line 2651 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 87:
-/* Line 1787 of yacc.c  */
-#line 798 "parser.y"
-    { (yyval.val) = (yyvsp[(1) - (1)].val); }
+#line 800 "parser.y" /* yacc.c:1646  */
+    { (yyval.val) = (yyvsp[0].val); }
+#line 2657 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 88:
-/* Line 1787 of yacc.c  */
-#line 803 "parser.y"
+#line 805 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.val), SelectionParserValue::createIntegerRange((yyvsp[(1) - (3)].i), (yyvsp[(3) - (3)].i), (yyloc)));
+                 set((yyval.val), SelectionParserValue::createIntegerRange((yyvsp[-2].i), (yyvsp[0].i), (yyloc)));
                  END_ACTION;
              }
+#line 2667 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 89:
-/* Line 1787 of yacc.c  */
-#line 809 "parser.y"
+#line 811 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.val), SelectionParserValue::createRealRange((yyvsp[(1) - (3)].i), (yyvsp[(3) - (3)].r), (yyloc)));
+                 set((yyval.val), SelectionParserValue::createRealRange((yyvsp[-2].i), (yyvsp[0].r), (yyloc)));
                  END_ACTION;
              }
+#line 2677 "parser.cpp" /* yacc.c:1646  */
     break;
 
   case 90:
-/* Line 1787 of yacc.c  */
-#line 815 "parser.y"
+#line 817 "parser.y" /* yacc.c:1646  */
     {
                  BEGIN_ACTION;
-                 set((yyval.val), SelectionParserValue::createRealRange((yyvsp[(1) - (3)].r), (yyvsp[(3) - (3)].r), (yyloc)));
+                 set((yyval.val), SelectionParserValue::createRealRange((yyvsp[-2].r), (yyvsp[0].r), (yyloc)));
                  END_ACTION;
              }
+#line 2687 "parser.cpp" /* yacc.c:1646  */
     break;
 
 
-/* Line 1787 of yacc.c  */
-#line 2917 "parser.cpp"
+#line 2691 "parser.cpp" /* yacc.c:1646  */
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -2936,7 +2710,7 @@ yyreduce:
   *++yyvsp = yyval;
   *++yylsp = yyloc;
 
-  /* Now `shift' the result of the reduction.  Determine what state
+  /* Now 'shift' the result of the reduction.  Determine what state
      that goes to, based on the state we popped back to and the rule
      number reduced by.  */
 
@@ -2951,9 +2725,9 @@ yyreduce:
   goto yynewstate;
 
 
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
+/*--------------------------------------.
+| yyerrlab -- here on detecting error |
+`--------------------------------------*/
 yyerrlab:
   /* Make sure we have latest lookahead translation.  See comments at
      user semantic actions for why this is necessary.  */
@@ -3004,20 +2778,20 @@ yyerrlab:
   if (yyerrstatus == 3)
     {
       /* If just tried and failed to reuse lookahead token after an
-        error, discard it.  */
+         error, discard it.  */
 
       if (yychar <= YYEOF)
-       {
-         /* Return failure if at end of input.  */
-         if (yychar == YYEOF)
-           YYABORT;
-       }
+        {
+          /* Return failure if at end of input.  */
+          if (yychar == YYEOF)
+            YYABORT;
+        }
       else
-       {
-         yydestruct ("Error: discarding",
-                     yytoken, &yylval, &yylloc, scanner);
-         yychar = YYEMPTY;
-       }
+        {
+          yydestruct ("Error: discarding",
+                      yytoken, &yylval, &yylloc, scanner);
+          yychar = YYEMPTY;
+        }
     }
 
   /* Else will try to reuse lookahead token after shifting the error
@@ -3037,7 +2811,7 @@ yyerrorlab:
      goto yyerrorlab;
 
   yyerror_range[1] = yylsp[1-yylen];
-  /* Do not reclaim the symbols of the rule which action triggered
+  /* Do not reclaim the symbols of the rule whose action triggered
      this YYERROR.  */
   YYPOPSTACK (yylen);
   yylen = 0;
@@ -3050,29 +2824,29 @@ yyerrorlab:
 | yyerrlab1 -- common code for both syntax error and YYERROR.  |
 `-------------------------------------------------------------*/
 yyerrlab1:
-  yyerrstatus = 3;     /* Each real token shifted decrements this.  */
+  yyerrstatus = 3;      /* Each real token shifted decrements this.  */
 
   for (;;)
     {
       yyn = yypact[yystate];
       if (!yypact_value_is_default (yyn))
-       {
-         yyn += YYTERROR;
-         if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
-           {
-             yyn = yytable[yyn];
-             if (0 < yyn)
-               break;
-           }
-       }
+        {
+          yyn += YYTERROR;
+          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+            {
+              yyn = yytable[yyn];
+              if (0 < yyn)
+                break;
+            }
+        }
 
       /* Pop the current state because it cannot handle the error token.  */
       if (yyssp == yyss)
-       YYABORT;
+        YYABORT;
 
       yyerror_range[1] = *yylsp;
       yydestruct ("Error: popping",
-                 yystos[yystate], yyvsp, yylsp, scanner);
+                  yystos[yystate], yyvsp, yylsp, scanner);
       YYPOPSTACK (1);
       yystate = *yyssp;
       YY_STACK_PRINT (yyss, yyssp);
@@ -3128,14 +2902,14 @@ yyreturn:
       yydestruct ("Cleanup: discarding lookahead",
                   yytoken, &yylval, &yylloc, scanner);
     }
-  /* Do not reclaim the symbols of the rule which action triggered
+  /* Do not reclaim the symbols of the rule whose action triggered
      this YYABORT or YYACCEPT.  */
   YYPOPSTACK (yylen);
   YY_STACK_PRINT (yyss, yyssp);
   while (yyssp != yyss)
     {
       yydestruct ("Cleanup: popping",
-                 yystos[*yyssp], yyvsp, yylsp, scanner);
+                  yystos[*yyssp], yyvsp, yylsp, scanner);
       YYPOPSTACK (1);
     }
 #ifndef yyoverflow
@@ -3149,8 +2923,5 @@ yypushreturn:
   if (yymsg != yymsgbuf)
     YYSTACK_FREE (yymsg);
 #endif
-  /* Make sure YYID is used.  */
-  return YYID (yyresult);
+  return yyresult;
 }
-
-
index 2e9a7611ee168993a43bbdfe37a5103cba1c700a..a0263cee49ccd82604ea1b7e7ea1fb3ef104ff16 100644 (file)
@@ -1,19 +1,19 @@
-/* A Bison parser, made by GNU Bison 2.7.12-4996.  */
+/* A Bison parser, made by GNU Bison 3.0.4.  */
 
 /* Bison interface for Yacc-like parsers in C
-   
-      Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
-   
+
+   Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
+
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
-   
+
    This program 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 General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
    special exception, which will cause the skeleton and the resulting
    Bison output files to be licensed under the GNU General Public
    License without this special exception.
-   
+
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 
 #ifndef YY__GMX_SEL_YY_PARSER_H_INCLUDED
 # define YY__GMX_SEL_YY_PARSER_H_INCLUDED
-/* Enabling traces.  */
+/* Debug traces.  */
 #ifndef YYDEBUG
 # define YYDEBUG 1
 #endif
 extern int _gmx_sel_yydebug;
 #endif
 /* "%code requires" blocks.  */
-/* Line 2053 of yacc.c  */
-#line 1 "parser.y"
+#line 1 "parser.y" /* yacc.c:1909  */
 
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, 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.
@@ -77,65 +76,60 @@ extern int _gmx_sel_yydebug;
  * To help us fund GROMACS development, we humbly ask that you cite
  * the research papers on the package. Check out http://www.gromacs.org.
  */
-
-/* Line 2053 of yacc.c  */
-#line 76 "parser.y"
+#line 76 "parser.y" /* yacc.c:1909  */
 
 #include "parsetree.h"
 #include "selelem.h"
 
 #define YYLTYPE ::gmx::SelectionLocation
 
+#line 87 "parser.h" /* yacc.c:1909  */
 
-/* Line 2053 of yacc.c  */
-#line 92 "parser.h"
-
-/* Tokens.  */
+/* Token type.  */
 #ifndef YYTOKENTYPE
 # define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     INVALID = 258,
-     TOK_INT = 259,
-     TOK_REAL = 260,
-     STR = 261,
-     IDENTIFIER = 262,
-     CMD_SEP = 263,
-     GROUP = 264,
-     TO = 265,
-     VARIABLE_NUMERIC = 266,
-     VARIABLE_GROUP = 267,
-     VARIABLE_POS = 268,
-     KEYWORD_NUMERIC = 269,
-     KEYWORD_STR = 270,
-     KEYWORD_POS = 271,
-     KEYWORD_GROUP = 272,
-     METHOD_NUMERIC = 273,
-     METHOD_GROUP = 274,
-     METHOD_POS = 275,
-     MODIFIER = 276,
-     EMPTY_POSMOD = 277,
-     PARAM = 278,
-     END_OF_METHOD = 279,
-     OF = 280,
-     CMP_OP = 281,
-     PARAM_REDUCT = 282,
-     XOR = 283,
-     OR = 284,
-     AND = 285,
-     NOT = 286,
-     UNARY_NEG = 287,
-     NUM_REDUCT = 288
-   };
+  enum yytokentype
+  {
+    INVALID = 258,
+    TOK_INT = 259,
+    TOK_REAL = 260,
+    STR = 261,
+    IDENTIFIER = 262,
+    CMD_SEP = 263,
+    GROUP = 264,
+    TO = 265,
+    VARIABLE_NUMERIC = 266,
+    VARIABLE_GROUP = 267,
+    VARIABLE_POS = 268,
+    KEYWORD_NUMERIC = 269,
+    KEYWORD_STR = 270,
+    KEYWORD_POS = 271,
+    KEYWORD_GROUP = 272,
+    METHOD_NUMERIC = 273,
+    METHOD_GROUP = 274,
+    METHOD_POS = 275,
+    MODIFIER = 276,
+    EMPTY_POSMOD = 277,
+    PARAM = 278,
+    END_OF_METHOD = 279,
+    OF = 280,
+    CMP_OP = 281,
+    PARAM_REDUCT = 282,
+    OR = 283,
+    XOR = 284,
+    AND = 285,
+    NOT = 286,
+    UNARY_NEG = 287,
+    NUM_REDUCT = 288
+  };
 #endif
 
-
+/* Value type.  */
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
+
+union YYSTYPE
 {
-/* Line 2053 of yacc.c  */
-#line 83 "parser.y"
+#line 83 "parser.y" /* yacc.c:1909  */
 
     int                         i;
     real                        r;
@@ -150,29 +144,30 @@ typedef union YYSTYPE
     gmx::SelectionParserParameter               *param;
     gmx::SelectionParserParameterListPointer    *plist;
 
+#line 148 "parser.h" /* yacc.c:1909  */
+};
 
-/* Line 2053 of yacc.c  */
-#line 156 "parser.h"
-} YYSTYPE;
+typedef union YYSTYPE YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
 #endif
 
+/* Location type.  */
 #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
-typedef struct YYLTYPE
+typedef struct YYLTYPE YYLTYPE;
+struct YYLTYPE
 {
   int first_line;
   int first_column;
   int last_line;
   int last_column;
-} YYLTYPE;
-# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+};
 # define YYLTYPE_IS_DECLARED 1
 # define YYLTYPE_IS_TRIVIAL 1
 #endif
 
 
+
 #ifndef YYPUSH_MORE_DEFINED
 # define YYPUSH_MORE_DEFINED
 enum { YYPUSH_MORE = 4 };
@@ -180,21 +175,9 @@ enum { YYPUSH_MORE = 4 };
 
 typedef struct _gmx_sel_yypstate _gmx_sel_yypstate;
 
-#if defined __STDC__ || defined __cplusplus
 int _gmx_sel_yypush_parse (_gmx_sel_yypstate *ps, int pushed_char, YYSTYPE const *pushed_val, YYLTYPE *pushed_loc, void *scanner);
-#else
-int _gmx_sel_yypush_parse ();
-#endif
 
-#if defined __STDC__ || defined __cplusplus
 _gmx_sel_yypstate * _gmx_sel_yypstate_new (void);
-#else
-_gmx_sel_yypstate * _gmx_sel_yypstate_new ();
-#endif
-#if defined __STDC__ || defined __cplusplus
 void _gmx_sel_yypstate_delete (_gmx_sel_yypstate *ps);
-#else
-void _gmx_sel_yypstate_delete ();
-#endif
 
 #endif /* !YY__GMX_SEL_YY_PARSER_H_INCLUDED  */
index de16101d2ba39ccbf28d0b1fb6db1ace6bf69c18..aa57eb089df2a6a4dd9188a6ae1f0a40f182ee60 100644 (file)
@@ -1,20 +1,20 @@
 --- parser.cpp 2014-11-03 06:56:28.000000000 +0200
 +++ parser.cpp 2014-11-03 06:57:35.000000000 +0200
-@@ -470,7 +470,7 @@
+@@ -437,7 +437,7 @@
  
  
  #if (! defined yyoverflow \
 -     && (! defined __cplusplus \
 +     && (! defined __cplusplus || defined GMX_YYFORCE_C_STACK_EXTENSION \
-        || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
-            && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+          || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
+              && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
  
-@@ -1076,7 +1076,7 @@
-     void *scanner;
- #endif
+@@ -955,7 +955,7 @@
+ static void
+ yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, void *scanner)
  {
 -  FILE *yyo = yyoutput;
 +  FILE *yyo gmx_unused = yyoutput;
    YYUSE (yyo);
-   if (!yyvaluep)
-     return;
+   YYUSE (yylocationp);
+   YYUSE (scanner);
index 3cae4446e4b871ea13e06845dd0b4a70418d85eb..c5b989885f0c1b35fa524408deaf600914c65aa0 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, 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.
@@ -189,7 +189,7 @@ using gmx::SelectionTreeElementPointer;
 %define api.push-pull push
 %locations
 
-%name-prefix="_gmx_sel_yy"
+%name-prefix "_gmx_sel_yy"
 %parse-param { void *scanner }
 
 %%
@@ -205,8 +205,10 @@ commands:    /* empty */
              {
                  BEGIN_ACTION;
                  set($$, _gmx_sel_append_selection(get($2), get($1), scanner));
-                 if (_gmx_sel_parser_should_finish(scanner))
+                 if (_gmx_sel_parser_should_finish(scanner)) {
+                     delete $$;
                      YYACCEPT;
+                 }
                  END_ACTION_TOPLEVEL;
              }
 ;
index 23fb458901e7c4db871a8d9ab67d5dde92a943c2..e2c1c071b768344e333e5388adf147429fb141d5 100644 (file)
@@ -406,7 +406,7 @@ early_termination:
     result.reserve(nr);
     for (i = sc->sel.begin() + oldCount; i != sc->sel.end(); ++i)
     {
-        result.push_back(Selection(i->get()));
+        result.emplace_back(i->get());
     }
     return result;
 }
index 9d877945982e7116c878598a8f8e12467059afaf..99c96accac2cf0a01bc7e6fa4f35d0c67e03a7e6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2016, 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,7 @@ class SelectionFileOptionStorage : public AbstractOptionStorage
 
     private:
         virtual void clearSet();
-        virtual void convertValue(const std::string &value);
+        virtual void convertValue(const Variant &value);
         virtual void processSet();
         virtual void processAll() {}
 
index 019f8965b5e27b05807f99a00ba447d3030a149c..909e3f0e0ca3acc93ae06c8e67d340660ea3a856 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, 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.
@@ -118,9 +118,9 @@ void SelectionOptionStorage::addSelections(
 }
 
 
-void SelectionOptionStorage::convertValue(const std::string &value)
+void SelectionOptionStorage::convertValue(const Variant &value)
 {
-    manager_.convertOptionValue(this, value, false);
+    manager_.convertOptionValue(this, value.cast<std::string>(), false);
 }
 
 void SelectionOptionStorage::processSetValues(ValueList *values)
@@ -180,10 +180,9 @@ void SelectionOptionStorage::setAllowedValueCount(int count)
 
 void SelectionOptionStorage::setSelectionFlag(SelectionFlag flag, bool bSet)
 {
-    ValueList::iterator i;
-    for (i = values().begin(); i != values().end(); ++i)
+    for (const Selection &value : values())
     {
-        if (flag == efSelection_OnlyStatic && bSet && i->isDynamic())
+        if (flag == efSelection_OnlyStatic && bSet && value.isDynamic())
         {
             MessageStringCollector errors;
             errors.startContext("In option '" + name() + "'");
@@ -193,9 +192,9 @@ void SelectionOptionStorage::setSelectionFlag(SelectionFlag flag, bool bSet)
         }
     }
     selectionFlags_.set(flag, bSet);
-    for (i = values().begin(); i != values().end(); ++i)
+    for (Selection &value : values())
     {
-        i->data().setFlags(selectionFlags_);
+        value.data().setFlags(selectionFlags_);
     }
 }
 
@@ -281,7 +280,7 @@ void SelectionFileOptionStorage::clearSet()
     bValueParsed_ = false;
 }
 
-void SelectionFileOptionStorage::convertValue(const std::string &value)
+void SelectionFileOptionStorage::convertValue(const Variant &value)
 {
     if (bValueParsed_)
     {
@@ -289,7 +288,7 @@ void SelectionFileOptionStorage::convertValue(const std::string &value)
     }
     bValueParsed_ = true;
     // TODO: Should we throw an InvalidInputError if the file does not exist?
-    manager_.parseRequestedFromFile(value);
+    manager_.parseRequestedFromFile(value.cast<std::string>());
 }
 
 void SelectionFileOptionStorage::processSet()
index a31859b59baec6dc1aefddd4cfcf6951e2ffd403..54d43a4cc554a940e022809bba3ba4cf8a32bb9a 100644 (file)
@@ -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
  * 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.
@@ -246,7 +246,7 @@ void SelectionOptionManager::Impl::requestUnsetRequiredOptions()
         SelectionOptionStorage &storage = **i;
         if (storage.isRequired() && !storage.isSet())
         {
-            requests_.push_back(SelectionRequest(&storage));
+            requests_.emplace_back(&storage);
         }
     }
 }
@@ -285,7 +285,7 @@ void
 SelectionOptionManager::requestOptionDelayedParsing(
         SelectionOptionStorage *storage)
 {
-    impl_->requests_.push_back(Impl::SelectionRequest(storage));
+    impl_->requests_.emplace_back(storage);
 }
 
 bool
index 0ef88da0a6411f22300bf8d79a2c30c333aa5fb7..7ccec2901cdf40cffd9ab6fab6c7419fca719bbf 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, 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.
@@ -126,7 +126,7 @@ class SelectionOptionStorage : public OptionStorageTemplate<Selection>
         void setSelectionFlag(SelectionFlag flag, bool bSet);
 
     private:
-        virtual void convertValue(const std::string &value);
+        virtual void convertValue(const Variant &value);
         virtual void processSetValues(ValueList *values);
         virtual void processAll();
 
index 5dbfc1833bcba4bd1d3783e5dc658bbace292345..476a337ab8aabff291a211af4afb061b94f21982 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, 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.
@@ -625,7 +625,7 @@ init_kwstr(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, vo
     for (int i = 0; i < n; ++i)
     {
         const char *s = param[1].val.u.s[i];
-        d->matches.push_back(StringKeywordMatchItem(d->matchType, s));
+        d->matches.emplace_back(d->matchType, s);
     }
 }
 
index 9cc30ecb704428cff573d13c3934d071ed269631..240f282ead94cd6920d8c7cdea50ae3e6ce4894b 100644 (file)
@@ -132,7 +132,7 @@ class NeighborhoodSearchTestData
                 testPos_.reserve(testPositions_.size());
                 for (size_t i = 0; i < testPositions_.size(); ++i)
                 {
-                    testPos_.push_back(testPositions_[i].x);
+                    testPos_.emplace_back(testPositions_[i].x);
                 }
             }
             return gmx::AnalysisNeighborhoodPositions(testPos_);
@@ -146,7 +146,7 @@ class NeighborhoodSearchTestData
         {
             GMX_RELEASE_ASSERT(testPos_.empty(),
                                "Cannot add positions after testPositions() call");
-            testPositions_.push_back(TestPosition(x));
+            testPositions_.emplace_back(x);
         }
         gmx::RVec generateRandomPosition();
         std::vector<int> generateIndex(int count, gmx_uint64_t seed) const;
index c9ed4c7f9418fbdc09019c7a5111649bb4789cb7..e51cbe41aa2f7de5a5c48fa1ad8051246edfe3e2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, 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.
@@ -201,7 +201,7 @@ PositionCalculationTest::initPositions(gmx_ana_poscalc_t *pc, const char *name)
     posList_.reserve(posList_.size() + 1);
     PositionPointer p(new gmx_ana_pos_t());
     gmx_ana_pos_t  *result = p.get();
-    posList_.push_back(PositionTest(std::move(p), pc, name));
+    posList_.emplace_back(std::move(p), pc, name);
     gmx_ana_poscalc_init_pos(pc, result);
     return result;
 }
index 8cd96fab1315ffa10d73d01ebe0fdb7cf82133fb..d6d6e7053fc6b5ba966b7f0daabdbc0907e34896 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, 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.
@@ -83,7 +83,7 @@ class SelectionOptionTestBase : public ::testing::Test
 };
 
 SelectionOptionTestBase::SelectionOptionTestBase()
-    : manager_(&sc_), options_(NULL, NULL)
+    : manager_(&sc_)
 {
     options_.addManager(&manager_);
     sc_.setReferencePosType("atom");
index 04796a2118fb9040ba2c66b139138dc11122fd58..4b13741d8ae10f283bfb6c8ea97bd920247113e9 100644 (file)
@@ -86,6 +86,11 @@ TopologyManager::~TopologyManager()
         sfree(frame_->index);
         sfree(frame_);
     }
+
+    for (char *atomtype : atomtypes_)
+    {
+        sfree(atomtype);
+    }
 }
 
 void TopologyManager::requestFrame()
index ab9e2290756eb6abbe1cfda5013688f8bc973a51..d2c318a923585f0fd79246e3c86a5395f57cabf9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016, 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.
@@ -42,9 +42,7 @@ namespace gmx
 static inline void
 simdPrefetch(const void * m)
 {
-#if defined(__ibmxl__) || defined(__xlC__)
-    __dcbt(m);
-#elif defined __GNUC__
+#if defined __GNUC__
     __builtin_prefetch(m);
 #endif
 }
index e0dd99d00a1ef6892370c58f25ee7ad66f06adc6..c93403685207532e12a47eeb0be02ae9696090ab 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016, 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.
@@ -41,6 +41,7 @@
 #include "config.h"
 
 // Assert is buggy on xlc with high optimization, so we skip it for QPX
+// TODO Add back the asserts for bgclang
 #include <cstddef>
 
 #ifdef __clang__
index bf81c8b3b356189dda06b96c37f8729835102ecb..f2b5a20d926d932e34e34071acc9c493f11fdbc2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016, 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,8 +36,6 @@
 #ifndef GMX_SIMD_IMPL_X86_AVX_128_FMA_DEFINITIONS_H
 #define GMX_SIMD_IMPL_X86_AVX_128_FMA_DEFINITIONS_H
 
-#include "config.h"
-
 // Capability definitions for AVX-128-FMA
 #define GMX_SIMD                                1
 #define GMX_SIMD_HAVE_FLOAT                     1
 #define GMX_SIMD_RSQRT_BITS                    11
 #define GMX_SIMD_RCP_BITS                      11
 
-// Work around gcc bug with wrong type for mask formal parameter to maskload/maskstore
-#if GMX_SIMD_X86_AVX_GCC_MASKLOAD_BUG
-#    define gmx_mm_maskload_ps(mem, mask)       _mm_maskload_ps((mem), _mm_castsi128_ps(mask))
-#    define gmx_mm_maskstore_ps(mem, mask, x)   _mm_maskstore_ps((mem), _mm_castsi128_ps(mask), (x))
-#else
-#    define gmx_mm_maskload_ps(mem, mask)       _mm_maskload_ps((mem), (mask))
-#    define gmx_mm_maskstore_ps(mem, mask, x)   _mm_maskstore_ps((mem), (mask), (x))
-#endif
+#define gmx_mm_maskload_ps(mem, mask)       _mm_maskload_ps((mem), (mask))
+#define gmx_mm_maskstore_ps(mem, mask, x)   _mm_maskstore_ps((mem), (mask), (x))
 
 #endif  // GMX_SIMD_IMPL_X86_AVX_128_FMA_DEFINITIONS_H
index 1746edfa87dea0e9f05a256bdaab55ebf70f8ac1..ad1e8372517942b22d69ad1c8790fa57a98046ce 100644 (file)
@@ -1459,7 +1459,7 @@ void init_swapcoords(
         gmx_mtop_t             *mtop,
         rvec                    x[],
         matrix                  box,
-        swapstate_t            *swapstate,
+        swapstate_t           **swapstatePtr,
         t_commrec              *cr,
         const gmx_output_env_t *oenv,
         unsigned long           Flags)
@@ -1562,6 +1562,12 @@ void init_swapcoords(
         }
     }
 
+    if (*swapstatePtr == NULL)
+    {
+        snew(*swapstatePtr, 1);
+    }
+    swapstate_t *swapstate = *swapstatePtr;
+
     if (MASTER(cr))
     {
         init_swapstate(swapstate, sc, mtop, x, box, ir->ePBC);
index 8ce0b590f7cbb48d49cb75edcf56c817e567f4f4..88b353ffa99b3e98fd53ffff247f628a9490e3fb 100644 (file)
@@ -74,7 +74,7 @@ struct t_swapcoords;
  * \param[in] mtop          Molecular topology.
  * \param[in] x             The initial positions of all particles.
  * \param[in] box           The simulation box.
- * \param[in] swapstate     Swap-related data that is read from or written to checkpoint.
+ * \param[in] swapstatePtr  Swap-related data that is read from or written to checkpoint.
  * \param[in] cr            Pointer to MPI communication data.
  * \param[in] oenv          Needed to open the swap output XVGR file.
  * \param[in] Flags         Flags passed over from main, used to determine
@@ -88,7 +88,7 @@ void init_swapcoords(
         gmx_mtop_t             *mtop,
         rvec                    x[],
         matrix                  box,
-        swapstate_t            *swapstate,
+        swapstate_t           **swapstatePtr,
         t_commrec              *cr,
         const gmx_output_env_t *oenv,
         unsigned long           Flags);
index 548827df384d3c35edc81dea1c689b1d952a610f..7b9ab440a2dfc5b3be1a631a298d571ea900782d 100644 (file)
@@ -44,7 +44,6 @@
 
 #include <array>
 
-#include "gromacs/gmxlib/md_logging.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/timing/cyclecounter.h"
 #include "gromacs/timing/gpu_timing.h"
@@ -52,6 +51,7 @@
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/gmxmpi.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/snprintf.h"
 
@@ -710,7 +710,7 @@ static void print_header(FILE *fplog, int nrank_pp, int nth_pp, int nrank_pme, i
 }
 
 
-void wallcycle_print(FILE *fplog, int nnodes, int npme,
+void wallcycle_print(FILE *fplog, const gmx::MDLogger &mdlog, int nnodes, int npme,
                      int nth_pp, int nth_pme, double realtime,
                      gmx_wallcycle_t wc, const WallcycleCounts &cyc_sum,
                      struct gmx_wallclock_gpu_t *gpu_t)
@@ -751,14 +751,15 @@ void wallcycle_print(FILE *fplog, int nnodes, int npme,
            timing data might still be sensible for some non-Jenkins
            run, than is lost from diagnosing Jenkins FP exceptions on
            runs about whose execution time we don't care. */
-        md_print_warn(NULL, fplog, "WARNING: A total of %f CPU cycles was recorded, so mdrun cannot print a time accounting\n", tot);
+        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                "WARNING: A total of %f CPU cycles was recorded, so mdrun cannot print a time accounting",
+                tot);
         return;
     }
 
     if (wc->haveInvalidCount)
     {
-        md_print_warn(NULL, fplog, "%s\n",
-                      "NOTE: Detected invalid cycle counts, probably because threads moved between CPU cores that do not have synchronized cycle counters. Will not print the cycle accounting.");
+        GMX_LOG(mdlog.warning).asParagraph().appendText("NOTE: Detected invalid cycle counts, probably because threads moved between CPU cores that do not have synchronized cycle counters. Will not print the cycle accounting.");
         return;
     }
 
@@ -948,26 +949,26 @@ void wallcycle_print(FILE *fplog, int nnodes, int npme,
                         /* The user could have used -notunepme,
                          * but we currently can't check that here.
                          */
-                        md_print_warn(NULL, fplog,
-                                      "\nNOTE: The GPU has >25%% less load than the CPU. This imbalance causes\n"
-                                      "      performance loss. Maybe the domain decomposition limits the PME tuning.\n"
-                                      "      In that case, try setting the DD grid manually (-dd) or lowering -dds.");
+                        GMX_LOG(mdlog.warning).asParagraph().appendText(
+                                "NOTE: The GPU has >25% less load than the CPU. This imbalance causes\n"
+                                "      performance loss. Maybe the domain decomposition limits the PME tuning.\n"
+                                "      In that case, try setting the DD grid manually (-dd) or lowering -dds.");
                     }
                     else
                     {
                         /* We should not end up here, unless the box is
                          * too small for increasing the cut-off for PME tuning.
                          */
-                        md_print_warn(NULL, fplog,
-                                      "\nNOTE: The GPU has >25%% less load than the CPU. This imbalance causes\n"
-                                      "      performance loss.");
+                        GMX_LOG(mdlog.warning).asParagraph().appendText(
+                                "NOTE: The GPU has >25% less load than the CPU. This imbalance causes\n"
+                                "      performance loss.");
                     }
                 }
                 if (gpu_cpu_ratio > 1.2)
                 {
-                    md_print_warn(NULL, fplog,
-                                  "\nNOTE: The GPU has >20%% more load than the CPU. This imbalance causes\n"
-                                  "      performance loss, consider using a shorter cut-off and a finer PME grid.");
+                    GMX_LOG(mdlog.warning).asParagraph().appendText(
+                            "NOTE: The GPU has >20% more load than the CPU. This imbalance causes\n"
+                            "      performance loss, consider using a shorter cut-off and a finer PME grid.");
                 }
             }
         }
@@ -975,9 +976,9 @@ void wallcycle_print(FILE *fplog, int nnodes, int npme,
 
     if (wc->wc_barrier)
     {
-        md_print_warn(NULL, fplog,
-                      "MPI_Barrier was called before each cycle start/stop\n"
-                      "call, so timings are not those of real runs.\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText(
+                "MPI_Barrier was called before each cycle start/stop\n"
+                "call, so timings are not those of real runs.");
     }
 
     if (wc->wcc[ewcNB_XF_BUF_OPS].n > 0 &&
@@ -987,29 +988,28 @@ void wallcycle_print(FILE *fplog, int nnodes, int npme,
         /* Only the sim master calls this function, so always print to stderr */
         if (wc->wcc[ewcDOMDEC].n == 0)
         {
-            md_print_warn(NULL, fplog,
-                          "NOTE: %d %% of the run time was spent in pair search,\n"
-                          "      you might want to increase nstlist (this has no effect on accuracy)\n",
-                          (int)(100*cyc_sum[ewcNS]/tot+0.5));
+            GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                    "NOTE: %d %% of the run time was spent in pair search,\n"
+                    "      you might want to increase nstlist (this has no effect on accuracy)\n",
+                    (int)(100*cyc_sum[ewcNS]/tot+0.5));
         }
         else
         {
-            md_print_warn(NULL, fplog,
-                          "NOTE: %d %% of the run time was spent in domain decomposition,\n"
-                          "      %d %% of the run time was spent in pair search,\n"
-                          "      you might want to increase nstlist (this has no effect on accuracy)\n",
-                          (int)(100*cyc_sum[ewcDOMDEC]/tot+0.5),
-                          (int)(100*cyc_sum[ewcNS]/tot+0.5));
+            GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                    "NOTE: %d %% of the run time was spent in domain decomposition,\n"
+                    "      %d %% of the run time was spent in pair search,\n"
+                    "      you might want to increase nstlist (this has no effect on accuracy)\n",
+                    (int)(100*cyc_sum[ewcDOMDEC]/tot+0.5),
+                    (int)(100*cyc_sum[ewcNS]/tot+0.5));
         }
     }
 
     if (cyc_sum[ewcMoveE] > tot*0.05)
     {
-        /* Only the sim master calls this function, so always print to stderr */
-        md_print_warn(NULL, fplog,
-                      "NOTE: %d %% of the run time was spent communicating energies,\n"
-                      "      you might want to use the -gcom option of mdrun\n",
-                      (int)(100*cyc_sum[ewcMoveE]/tot+0.5));
+        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                "NOTE: %d %% of the run time was spent communicating energies,\n"
+                "      you might want to use the -gcom option of mdrun\n",
+                (int)(100*cyc_sum[ewcMoveE]/tot+0.5));
     }
 }
 
index d3c316da592d8554e736b503e20697b525e28546..e84243fe8ca5f5e75a8d6896ef2f2c8875e5b11e 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2008, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, 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.
 
 #include "gromacs/utility/basedefinitions.h"
 
+struct t_commrec;
+
+namespace gmx
+{
+class MDLogger;
+}
+
 typedef struct gmx_wallcycle *gmx_wallcycle_t;
 typedef struct gmx_wallclock_gpu_t gmx_wallclock_gpu_t;
-struct t_commrec;
 
 typedef std::array<double, ewcNR+ewcsNR> WallcycleCounts;
 /* Convenience typedef */
@@ -57,7 +63,7 @@ WallcycleCounts wallcycle_sum(struct t_commrec *cr, gmx_wallcycle_t wc);
 /* Return a vector of the sum of cycle counts over the nodes in
    cr->mpi_comm_mysim. */
 
-void wallcycle_print(FILE *fplog, int nnodes, int npme,
+void wallcycle_print(FILE *fplog, const gmx::MDLogger &mdlog, int nnodes, int npme,
                      int nth_pp, int nth_pme, double realtime,
                      gmx_wallcycle_t wc, const WallcycleCounts &cyc_sum,
                      struct gmx_wallclock_gpu_t *gpu_t);
index bfcbf1d294cd28349c9483d850168e5a1b8911d7..4beac915f7c2e76998b7aa28860418ac54dee584 100644 (file)
@@ -200,7 +200,7 @@ gmx_gettime()
        headers claim sufficient support for POSIX (ie not Mac and
        Windows), and it isn't BG/Q (whose compute node kernel only
        supports gettimeofday, and bgclang doesn't provide a fully
-       functional implementation clock_gettime, unlike xlc). */
+       functional implementation clock_gettime). */
 #if HAVE_CLOCK_GETTIME && defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && !(defined __bgq__ && defined __clang__)
     struct timespec t;
     double          seconds;
@@ -237,7 +237,7 @@ gmx_gettime_per_thread()
        headers claim sufficient support for POSIX (ie not Mac and
        Windows), and it isn't BG/Q (whose compute node kernel only
        supports gettimeofday, and bgclang doesn't provide a fully
-       functional implementation clock_gettime, unlike xlc). */
+       functional implementation clock_gettime). */
 #if HAVE_CLOCK_GETTIME && defined(_POSIX_THREAD_CPUTIME) && _POSIX_THREAD_CPUTIME > 0 && !(defined __bgq__ && defined __clang__)
     struct timespec t;
     double          seconds;
index 17778e9b3b54a9eca520c09cc19a8a51b7fdb8d6..856d9809f7535679eddff8d6db01a37fabcac63f 100644 (file)
 #include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
 #include "gromacs/math/vec.h"
+#include "gromacs/mdrunutility/mdmodules.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/pbcutil/pbc.h"
-#include "gromacs/tools/compare.h"
 #include "gromacs/topology/atomprop.h"
 #include "gromacs/topology/block.h"
 #include "gromacs/topology/ifunc.h"
@@ -86,6 +86,104 @@ typedef struct {
     float bBox;
 } t_fr_time;
 
+static void comp_tpx(const char *fn1, const char *fn2,
+                     gmx_bool bRMSD, real ftol, real abstol)
+{
+    const char    *ff[2];
+    gmx::MDModules mdModules[2];
+    t_inputrec    *ir[2] = { mdModules[0].inputrec(), mdModules[1].inputrec() };
+    t_state        state[2];
+    gmx_mtop_t     mtop[2];
+    t_topology     top[2];
+    int            i;
+
+    ff[0] = fn1;
+    ff[1] = fn2;
+    for (i = 0; i < (fn2 ? 2 : 1); i++)
+    {
+        read_tpx_state(ff[i], ir[i], &state[i], &(mtop[i]));
+    }
+    if (fn2)
+    {
+        cmp_inputrec(stdout, ir[0], ir[1], ftol, abstol);
+        /* Convert gmx_mtop_t to t_topology.
+         * We should implement direct mtop comparison,
+         * but it might be useful to keep t_topology comparison as an option.
+         */
+        top[0] = gmx_mtop_t_to_t_topology(&mtop[0]);
+        top[1] = gmx_mtop_t_to_t_topology(&mtop[1]);
+        cmp_top(stdout, &top[0], &top[1], ftol, abstol);
+        cmp_groups(stdout, &mtop[0].groups, &mtop[1].groups,
+                   mtop[0].natoms, mtop[1].natoms);
+        comp_state(&state[0], &state[1], bRMSD, ftol, abstol);
+    }
+    else
+    {
+        if (ir[0]->efep == efepNO)
+        {
+            fprintf(stdout, "inputrec->efep = %s\n", efep_names[ir[0]->efep]);
+        }
+        else
+        {
+            if (ir[0]->bPull)
+            {
+                comp_pull_AB(stdout, ir[0]->pull, ftol, abstol);
+            }
+            /* Convert gmx_mtop_t to t_topology.
+             * We should implement direct mtop comparison,
+             * but it might be useful to keep t_topology comparison as an option.
+             */
+            top[0] = gmx_mtop_t_to_t_topology(&mtop[0]);
+            cmp_top(stdout, &top[0], NULL, ftol, abstol);
+        }
+    }
+}
+
+static void comp_trx(const gmx_output_env_t *oenv, const char *fn1, const char *fn2,
+                     gmx_bool bRMSD, real ftol, real abstol)
+{
+    int          i;
+    const char  *fn[2];
+    t_trxframe   fr[2];
+    t_trxstatus *status[2];
+    gmx_bool     b[2];
+
+    fn[0] = fn1;
+    fn[1] = fn2;
+    fprintf(stderr, "Comparing trajectory files %s and %s\n", fn1, fn2);
+    for (i = 0; i < 2; i++)
+    {
+        b[i] = read_first_frame(oenv, &status[i], fn[i], &fr[i], TRX_READ_X|TRX_READ_V|TRX_READ_F);
+    }
+
+    if (b[0] && b[1])
+    {
+        do
+        {
+            comp_frame(stdout, &(fr[0]), &(fr[1]), bRMSD, ftol, abstol);
+
+            for (i = 0; i < 2; i++)
+            {
+                b[i] = read_next_frame(oenv, status[i], &fr[i]);
+            }
+        }
+        while (b[0] && b[1]);
+
+        for (i = 0; i < 2; i++)
+        {
+            if (b[i] && !b[1-i])
+            {
+                fprintf(stdout, "\nEnd of file on %s but not on %s\n", fn[1-i], fn[i]);
+            }
+            close_trj(status[i]);
+        }
+    }
+    if (!b[0] && !b[1])
+    {
+        fprintf(stdout, "\nBoth files read correctly\n");
+    }
+}
+
 static void tpx2system(FILE *fp, const gmx_mtop_t *mtop)
 {
     int                       nmol, nvsite = 0;
@@ -146,16 +244,18 @@ static void tpx2params(FILE *fp, const t_inputrec *ir)
 
 static void tpx2methods(const char *tpx, const char *tex)
 {
-    FILE         *fp;
-    t_inputrec    ir;
-    t_state       state;
-    gmx_mtop_t    mtop;
-
-    read_tpx_state(tpx, &ir, &state, &mtop);
+    FILE          *fp;
+    t_inputrec    *ir;
+    t_state        state;
+    gmx_mtop_t     mtop;
+
+    gmx::MDModules mdModules;
+    ir = mdModules.inputrec();
+    read_tpx_state(tpx, ir, &state, &mtop);
     fp = gmx_fio_fopen(tex, "w");
     fprintf(fp, "\\section{Methods}\n");
     tpx2system(fp, &mtop);
-    tpx2params(fp, &ir);
+    tpx2params(fp, ir);
     gmx_fio_fclose(fp);
 }
 
@@ -288,12 +388,14 @@ void chk_trj(const gmx_output_env_t *oenv, const char *fn, const char *tpr, real
     gmx_mtop_t       mtop;
     gmx_localtop_t  *top = NULL;
     t_state          state;
-    t_inputrec       ir;
+    t_inputrec      *ir;
 
+    gmx::MDModules   mdModules;
+    ir = mdModules.inputrec();
     if (tpr)
     {
-        read_tpx_state(tpr, &ir, &state, &mtop);
-        top = gmx_mtop_generate_local_top(&mtop, ir.efep != efepNO);
+        read_tpx_state(tpr, ir, &state, &mtop);
+        top = gmx_mtop_generate_local_top(&mtop, ir->efep != efepNO);
     }
     new_natoms = -1;
     natoms     = -1;
@@ -360,7 +462,7 @@ void chk_trj(const gmx_output_env_t *oenv, const char *fn, const char *tpr, real
         natoms = new_natoms;
         if (tpr)
         {
-            chk_bonds(&top->idef, ir.ePBC, fr.x, fr.box, tol);
+            chk_bonds(&top->idef, ir->ePBC, fr.x, fr.box, tol);
         }
         if (fr.bX)
         {
diff --git a/src/gromacs/tools/compare.cpp b/src/gromacs/tools/compare.cpp
deleted file mode 100644 (file)
index b7313c5..0000000
+++ /dev/null
@@ -1,1469 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * 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
- * 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.
- */
-/* This file is completely threadsafe - keep it that way! */
-
-#include "gmxpre.h"
-
-#include <cmath>
-#include <cstdio>
-#include <cstring>
-
-#include <algorithm>
-
-#include "gromacs/fileio/enxio.h"
-#include "gromacs/fileio/tpxio.h"
-#include "gromacs/fileio/trxio.h"
-#include "gromacs/mdtypes/inputrec.h"
-#include "gromacs/mdtypes/md_enums.h"
-#include "gromacs/mdtypes/pull-params.h"
-#include "gromacs/topology/ifunc.h"
-#include "gromacs/topology/mtop_util.h"
-#include "gromacs/topology/topology.h"
-#include "gromacs/trajectory/trajectoryframe.h"
-#include "gromacs/utility/cstringutil.h"
-#include "gromacs/utility/fatalerror.h"
-#include "gromacs/utility/futil.h"
-#include "gromacs/utility/smalloc.h"
-#include "gromacs/utility/stringutil.h"
-
-static void cmp_int(FILE *fp, const char *s, int index, int i1, int i2)
-{
-    if (i1 != i2)
-    {
-        if (index != -1)
-        {
-            fprintf(fp, "%s[%d] (%d - %d)\n", s, index, i1, i2);
-        }
-        else
-        {
-            fprintf(fp, "%s (%d - %d)\n", s, i1, i2);
-        }
-    }
-}
-
-static void cmp_int64(FILE *fp, const char *s, gmx_int64_t i1, gmx_int64_t i2)
-{
-    if (i1 != i2)
-    {
-        fprintf(fp, "%s (", s);
-        fprintf(fp, "%" GMX_PRId64, i1);
-        fprintf(fp, " - ");
-        fprintf(fp, "%" GMX_PRId64, i2);
-        fprintf(fp, ")\n");
-    }
-}
-
-static void cmp_us(FILE *fp, const char *s, int index, unsigned short i1, unsigned short i2)
-{
-    if (i1 != i2)
-    {
-        if (index != -1)
-        {
-            fprintf(fp, "%s[%d] (%hu - %hu)\n", s, index, i1, i2);
-        }
-        else
-        {
-            fprintf(fp, "%s (%hu - %hu)\n", s, i1, i2);
-        }
-    }
-}
-
-static void cmp_uc(FILE *fp, const char *s, int index, unsigned char i1, unsigned char i2)
-{
-    if (i1 != i2)
-    {
-        if (index != -1)
-        {
-            fprintf(fp, "%s[%d] (%d - %d)\n", s, index, i1, i2);
-        }
-        else
-        {
-            fprintf(fp, "%s (%d - %d)\n", s, i1, i2);
-        }
-    }
-}
-
-static gmx_bool cmp_bool(FILE *fp, const char *s, int index, gmx_bool b1, gmx_bool b2)
-{
-    if (b1)
-    {
-        b1 = 1;
-    }
-    else
-    {
-        b1 = 0;
-    }
-    if (b2)
-    {
-        b2 = 1;
-    }
-    else
-    {
-        b2 = 0;
-    }
-    if (b1 != b2)
-    {
-        if (index != -1)
-        {
-            fprintf(fp, "%s[%d] (%s - %s)\n", s, index,
-                    gmx::boolToString(b1), gmx::boolToString(b2));
-        }
-        else
-        {
-            fprintf(fp, "%s (%s - %s)\n", s,
-                    gmx::boolToString(b1), gmx::boolToString(b2));
-        }
-    }
-    return b1 && b2;
-}
-
-static void cmp_str(FILE *fp, const char *s, int index,
-                    const char *s1, const char *s2)
-{
-    if (std::strcmp(s1, s2) != 0)
-    {
-        if (index != -1)
-        {
-            fprintf(fp, "%s[%d] (%s - %s)\n", s, index, s1, s2);
-        }
-        else
-        {
-            fprintf(fp, "%s (%s - %s)\n", s, s1, s2);
-        }
-    }
-}
-
-static gmx_bool equal_real(real i1, real i2, real ftol, real abstol)
-{
-    return ( ( 2*fabs(i1 - i2) <= (fabs(i1) + fabs(i2))*ftol ) || fabs(i1-i2) <= abstol );
-}
-
-static gmx_bool equal_float(float i1, float i2, float ftol, float abstol)
-{
-    return ( ( 2*fabs(i1 - i2) <= (fabs(i1) + fabs(i2))*ftol ) || fabs(i1-i2) <= abstol );
-}
-
-static gmx_bool equal_double(double i1, double i2, real ftol, real abstol)
-{
-    return ( ( 2*fabs(i1 - i2) <= (fabs(i1) + fabs(i2))*ftol ) || fabs(i1-i2) <= abstol );
-}
-
-static void
-cmp_real(FILE *fp, const char *s, int index, real i1, real i2, real ftol, real abstol)
-{
-    if (!equal_real(i1, i2, ftol, abstol))
-    {
-        if (index != -1)
-        {
-            fprintf(fp, "%s[%2d] (%e - %e)\n", s, index, i1, i2);
-        }
-        else
-        {
-            fprintf(fp, "%s (%e - %e)\n", s, i1, i2);
-        }
-    }
-}
-
-static void
-cmp_float(FILE *fp, const char *s, int index, float i1, float i2, float ftol, float abstol)
-{
-    if (!equal_float(i1, i2, ftol, abstol))
-    {
-        if (index != -1)
-        {
-            fprintf(fp, "%s[%2d] (%e - %e)\n", s, index, i1, i2);
-        }
-        else
-        {
-            fprintf(fp, "%s (%e - %e)\n", s, i1, i2);
-        }
-    }
-}
-
-
-
-static void
-cmp_double(FILE *fp, const char *s, int index, double i1, double i2, double ftol, double abstol)
-{
-    if (!equal_double(i1, i2, ftol, abstol))
-    {
-        if (index != -1)
-        {
-            fprintf(fp, "%s[%2d] (%16.9e - %16.9e)\n", s, index, i1, i2);
-        }
-        else
-        {
-            fprintf(fp, "%s (%16.9e - %16.9e)\n", s, i1, i2);
-        }
-    }
-}
-
-static void cmp_rvec(FILE *fp, const char *s, int index, const rvec i1, const rvec i2, real ftol, real abstol)
-{
-    if (!equal_real(i1[XX], i2[XX], ftol, abstol) ||
-        !equal_real(i1[YY], i2[YY], ftol, abstol) ||
-        !equal_real(i1[ZZ], i2[ZZ], ftol, abstol))
-    {
-        if (index != -1)
-        {
-            fprintf(fp, "%s[%5d] (%12.5e %12.5e %12.5e) - (%12.5e %12.5e %12.5e)\n",
-                    s, index, i1[XX], i1[YY], i1[ZZ], i2[XX], i2[YY], i2[ZZ]);
-        }
-        else
-        {
-            fprintf(fp, "%s (%12.5e %12.5e %12.5e) - (%12.5e %12.5e %12.5e)\n",
-                    s, i1[XX], i1[YY], i1[ZZ], i2[XX], i2[YY], i2[ZZ]);
-        }
-    }
-}
-
-static void cmp_ivec(FILE *fp, const char *s, int index, const ivec i1, const ivec i2)
-{
-    if ((i1[XX] != i2[XX]) || (i1[YY] != i2[YY]) || (i1[ZZ] != i2[ZZ]))
-    {
-        if (index != -1)
-        {
-            fprintf(fp, "%s[%5d] (%8d,%8d,%8d - %8d,%8d,%8d)\n", s, index,
-                    i1[XX], i1[YY], i1[ZZ], i2[XX], i2[YY], i2[ZZ]);
-        }
-        else
-        {
-            fprintf(fp, "%s (%8d,%8d,%8d - %8d,%8d,%8d)\n", s,
-                    i1[XX], i1[YY], i1[ZZ], i2[XX], i2[YY], i2[ZZ]);
-        }
-    }
-}
-
-static void cmp_ilist(FILE *fp, int ftype, const t_ilist *il1, const t_ilist *il2)
-{
-    int  i;
-    char buf[256];
-
-    fprintf(fp, "comparing ilist %s\n", interaction_function[ftype].name);
-    sprintf(buf, "%s->nr", interaction_function[ftype].name);
-    cmp_int(fp, buf, -1, il1->nr, il2->nr);
-    sprintf(buf, "%s->iatoms", interaction_function[ftype].name);
-    if (((il1->nr > 0) && (!il1->iatoms)) ||
-        ((il2->nr > 0) && (!il2->iatoms)) ||
-        ((il1->nr != il2->nr)))
-    {
-        fprintf(fp, "Comparing radically different topologies - %s is different\n",
-                buf);
-    }
-    else
-    {
-        for (i = 0; (i < il1->nr); i++)
-        {
-            cmp_int(fp, buf, i, il1->iatoms[i], il2->iatoms[i]);
-        }
-    }
-}
-
-void cmp_iparm(FILE *fp, const char *s, t_functype ft,
-               const t_iparams &ip1, const t_iparams &ip2, real ftol, real abstol)
-{
-    int      i;
-    gmx_bool bDiff;
-
-    bDiff = FALSE;
-    for (i = 0; i < MAXFORCEPARAM && !bDiff; i++)
-    {
-        bDiff = !equal_real(ip1.generic.buf[i], ip2.generic.buf[i], ftol, abstol);
-    }
-    if (bDiff)
-    {
-        fprintf(fp, "%s1: ", s);
-        pr_iparams(fp, ft, &ip1);
-        fprintf(fp, "%s2: ", s);
-        pr_iparams(fp, ft, &ip2);
-    }
-}
-
-void cmp_iparm_AB(FILE *fp, const char *s, t_functype ft, const t_iparams &ip1, real ftol, real abstol)
-{
-    int      nrfpA, nrfpB, p0, i;
-    gmx_bool bDiff;
-
-    /* Normally the first parameter is perturbable */
-    p0    = 0;
-    nrfpA = interaction_function[ft].nrfpA;
-    nrfpB = interaction_function[ft].nrfpB;
-    if (ft == F_PDIHS)
-    {
-        nrfpB = 2;
-    }
-    else if (interaction_function[ft].flags & IF_TABULATED)
-    {
-        /* For tabulated interactions only the second parameter is perturbable */
-        p0    = 1;
-        nrfpB = 1;
-    }
-    bDiff = FALSE;
-    for (i = 0; i < nrfpB && !bDiff; i++)
-    {
-        bDiff = !equal_real(ip1.generic.buf[p0+i], ip1.generic.buf[nrfpA+i], ftol, abstol);
-    }
-    if (bDiff)
-    {
-        fprintf(fp, "%s: ", s);
-        pr_iparams(fp, ft, &ip1);
-    }
-}
-
-static void cmp_cmap(FILE *fp, const gmx_cmap_t *cmap1, const gmx_cmap_t *cmap2, real ftol, real abstol)
-{
-    cmp_int(fp, "cmap ngrid", -1, cmap1->ngrid, cmap2->ngrid);
-    cmp_int(fp, "cmap grid_spacing", -1, cmap1->grid_spacing, cmap2->grid_spacing);
-    if (cmap1->ngrid == cmap2->ngrid &&
-        cmap1->grid_spacing == cmap2->grid_spacing)
-    {
-        int g;
-
-        for (g = 0; g < cmap1->ngrid; g++)
-        {
-            int i;
-
-            fprintf(fp, "comparing cmap %d\n", g);
-
-            for (i = 0; i < 4*cmap1->grid_spacing*cmap1->grid_spacing; i++)
-            {
-                cmp_real(fp, "", i, cmap1->cmapdata[g].cmap[i], cmap2->cmapdata[g].cmap[i], ftol, abstol);
-            }
-        }
-    }
-}
-
-static void cmp_idef(FILE *fp, const t_idef *id1, const t_idef *id2, real ftol, real abstol)
-{
-    int  i;
-    char buf1[64], buf2[64];
-
-    fprintf(fp, "comparing idef\n");
-    if (id2)
-    {
-        cmp_int(fp, "idef->ntypes", -1, id1->ntypes, id2->ntypes);
-        cmp_int(fp, "idef->atnr",  -1, id1->atnr, id2->atnr);
-        for (i = 0; (i < std::min(id1->ntypes, id2->ntypes)); i++)
-        {
-            sprintf(buf1, "idef->functype[%d]", i);
-            sprintf(buf2, "idef->iparam[%d]", i);
-            cmp_int(fp, buf1, i, (int)id1->functype[i], (int)id2->functype[i]);
-            cmp_iparm(fp, buf2, id1->functype[i],
-                      id1->iparams[i], id2->iparams[i], ftol, abstol);
-        }
-        cmp_real(fp, "fudgeQQ", -1, id1->fudgeQQ, id2->fudgeQQ, ftol, abstol);
-        cmp_cmap(fp, &id1->cmap_grid, &id2->cmap_grid, ftol, abstol);
-        for (i = 0; (i < F_NRE); i++)
-        {
-            cmp_ilist(fp, i, &(id1->il[i]), &(id2->il[i]));
-        }
-    }
-    else
-    {
-        for (i = 0; (i < id1->ntypes); i++)
-        {
-            cmp_iparm_AB(fp, "idef->iparam", id1->functype[i], id1->iparams[i], ftol, abstol);
-        }
-    }
-}
-
-static void cmp_block(FILE *fp, const t_block *b1, const t_block *b2, const char *s)
-{
-    char buf[32];
-
-    fprintf(fp, "comparing block %s\n", s);
-    sprintf(buf, "%s.nr", s);
-    cmp_int(fp, buf, -1, b1->nr, b2->nr);
-}
-
-static void cmp_blocka(FILE *fp, const t_blocka *b1, const t_blocka *b2, const char *s)
-{
-    char buf[32];
-
-    fprintf(fp, "comparing blocka %s\n", s);
-    sprintf(buf, "%s.nr", s);
-    cmp_int(fp, buf, -1, b1->nr, b2->nr);
-    sprintf(buf, "%s.nra", s);
-    cmp_int(fp, buf, -1, b1->nra, b2->nra);
-}
-
-static void cmp_atom(FILE *fp, int index, const t_atom *a1, const t_atom *a2, real ftol, real abstol)
-{
-    if (a2)
-    {
-        cmp_us(fp, "atom.type", index, a1->type, a2->type);
-        cmp_us(fp, "atom.ptype", index, a1->ptype, a2->ptype);
-        cmp_int(fp, "atom.resind", index, a1->resind, a2->resind);
-        cmp_int(fp, "atom.atomnumber", index, a1->atomnumber, a2->atomnumber);
-        cmp_real(fp, "atom.m", index, a1->m, a2->m, ftol, abstol);
-        cmp_real(fp, "atom.q", index, a1->q, a2->q, ftol, abstol);
-        cmp_us(fp, "atom.typeB", index, a1->typeB, a2->typeB);
-        cmp_real(fp, "atom.mB", index, a1->mB, a2->mB, ftol, abstol);
-        cmp_real(fp, "atom.qB", index, a1->qB, a2->qB, ftol, abstol);
-    }
-    else
-    {
-        cmp_us(fp, "atom.type", index, a1->type, a1->typeB);
-        cmp_real(fp, "atom.m", index, a1->m, a1->mB, ftol, abstol);
-        cmp_real(fp, "atom.q", index, a1->q, a1->qB, ftol, abstol);
-    }
-}
-
-static void cmp_atoms(FILE *fp, const t_atoms *a1, const t_atoms *a2, real ftol, real abstol)
-{
-    int i;
-
-    fprintf(fp, "comparing atoms\n");
-
-    if (a2)
-    {
-        cmp_int(fp, "atoms->nr", -1, a1->nr, a2->nr);
-        for (i = 0; (i < a1->nr); i++)
-        {
-            cmp_atom(fp, i, &(a1->atom[i]), &(a2->atom[i]), ftol, abstol);
-        }
-    }
-    else
-    {
-        for (i = 0; (i < a1->nr); i++)
-        {
-            cmp_atom(fp, i, &(a1->atom[i]), NULL, ftol, abstol);
-        }
-    }
-}
-
-static void cmp_top(FILE *fp, const t_topology *t1, const t_topology *t2, real ftol, real abstol)
-{
-    fprintf(fp, "comparing top\n");
-    if (t2)
-    {
-        cmp_idef(fp, &(t1->idef), &(t2->idef), ftol, abstol);
-        cmp_atoms(fp, &(t1->atoms), &(t2->atoms), ftol, abstol);
-        cmp_block(fp, &t1->cgs, &t2->cgs, "cgs");
-        cmp_block(fp, &t1->mols, &t2->mols, "mols");
-        cmp_bool(fp, "bIntermolecularInteractions", -1, t1->bIntermolecularInteractions, t2->bIntermolecularInteractions);
-        cmp_blocka(fp, &t1->excls, &t2->excls, "excls");
-    }
-    else
-    {
-        cmp_idef(fp, &(t1->idef), NULL, ftol, abstol);
-        cmp_atoms(fp, &(t1->atoms), NULL, ftol, abstol);
-    }
-}
-
-static void cmp_groups(FILE *fp, const gmx_groups_t *g0, const gmx_groups_t *g1,
-                       int natoms0, int natoms1)
-{
-    int  i, j;
-    char buf[32];
-
-    fprintf(fp, "comparing groups\n");
-
-    for (i = 0; i < egcNR; i++)
-    {
-        sprintf(buf, "grps[%d].nr", i);
-        cmp_int(fp, buf, -1, g0->grps[i].nr, g1->grps[i].nr);
-        if (g0->grps[i].nr == g1->grps[i].nr)
-        {
-            for (j = 0; j < g0->grps[i].nr; j++)
-            {
-                sprintf(buf, "grps[%d].name[%d]", i, j);
-                cmp_str(fp, buf, -1,
-                        *g0->grpname[g0->grps[i].nm_ind[j]],
-                        *g1->grpname[g1->grps[i].nm_ind[j]]);
-            }
-        }
-        cmp_int(fp, "ngrpnr", i, g0->ngrpnr[i], g1->ngrpnr[i]);
-        if (g0->ngrpnr[i] == g1->ngrpnr[i] && natoms0 == natoms1 &&
-            (g0->grpnr[i] != NULL || g1->grpnr[i] != NULL))
-        {
-            for (j = 0; j < natoms0; j++)
-            {
-                cmp_int(fp, gtypes[i], j, ggrpnr(g0, i, j), ggrpnr(g1, i, j));
-            }
-        }
-    }
-    /* We have compared the names in the groups lists,
-     * so we can skip the grpname list comparison.
-     */
-}
-
-static void cmp_rvecs_rmstol(FILE *fp, const char *title, int n, const rvec x1[], const rvec x2[],
-                             real ftol, real abstol)
-{
-    int    i, m;
-    double rms;
-
-    /* For a vector you are usally not interested in a relative difference
-     * on a component that is very small compared to the other components.
-     * Therefore we do the relative comparision relative to the RMS component.
-     */
-    rms = 0.0;
-    for (i = 0; (i < n); i++)
-    {
-        for (m = 0; m < DIM; m++)
-        {
-            rms += x1[i][m]*x1[i][m] + x2[i][m]*x2[i][m];
-        }
-    }
-    rms = sqrt(rms/(2*n*DIM));
-
-    /* Convert the relative tolerance into an absolute tolerance */
-    if (ftol*rms < abstol)
-    {
-        abstol = ftol*rms;
-    }
-
-    /* And now do the actual comparision */
-    for (i = 0; (i < n); i++)
-    {
-        cmp_rvec(fp, title, i, x1[i], x2[i], 0.0, abstol);
-    }
-}
-
-static void cmp_rvecs(FILE *fp, const char *title, int n, const rvec x1[], const rvec x2[],
-                      gmx_bool bRMSD, real ftol, real abstol)
-{
-    int    i, m;
-    double d, ssd;
-
-    if (bRMSD)
-    {
-        ssd = 0;
-        for (i = 0; (i < n); i++)
-        {
-            for (m = 0; m < DIM; m++)
-            {
-                d    = x1[i][m] - x2[i][m];
-                ssd += d*d;
-            }
-        }
-        fprintf(fp, "%s RMSD %g\n", title, std::sqrt(ssd/n));
-    }
-    else
-    {
-        cmp_rvecs_rmstol(fp, title, n, x1, x2, ftol, abstol);
-    }
-}
-
-static void cmp_grpopts(FILE *fp, const t_grpopts *opt1, const t_grpopts *opt2, real ftol, real abstol)
-{
-    int  i, j;
-    char buf1[256], buf2[256];
-
-    cmp_int(fp, "inputrec->grpopts.ngtc", -1,  opt1->ngtc, opt2->ngtc);
-    cmp_int(fp, "inputrec->grpopts.ngacc", -1, opt1->ngacc, opt2->ngacc);
-    cmp_int(fp, "inputrec->grpopts.ngfrz", -1, opt1->ngfrz, opt2->ngfrz);
-    cmp_int(fp, "inputrec->grpopts.ngener", -1, opt1->ngener, opt2->ngener);
-    for (i = 0; (i < std::min(opt1->ngtc, opt2->ngtc)); i++)
-    {
-        cmp_real(fp, "inputrec->grpopts.nrdf", i, opt1->nrdf[i], opt2->nrdf[i], ftol, abstol);
-        cmp_real(fp, "inputrec->grpopts.ref_t", i, opt1->ref_t[i], opt2->ref_t[i], ftol, abstol);
-        cmp_real(fp, "inputrec->grpopts.tau_t", i, opt1->tau_t[i], opt2->tau_t[i], ftol, abstol);
-        cmp_int(fp, "inputrec->grpopts.annealing", i, opt1->annealing[i], opt2->annealing[i]);
-        cmp_int(fp, "inputrec->grpopts.anneal_npoints", i,
-                opt1->anneal_npoints[i], opt2->anneal_npoints[i]);
-        if (opt1->anneal_npoints[i] == opt2->anneal_npoints[i])
-        {
-            sprintf(buf1, "inputrec->grpopts.anneal_time[%d]", i);
-            sprintf(buf2, "inputrec->grpopts.anneal_temp[%d]", i);
-            for (j = 0; j < opt1->anneal_npoints[i]; j++)
-            {
-                cmp_real(fp, buf1, j, opt1->anneal_time[i][j], opt2->anneal_time[i][j], ftol, abstol);
-                cmp_real(fp, buf2, j, opt1->anneal_temp[i][j], opt2->anneal_temp[i][j], ftol, abstol);
-            }
-        }
-    }
-    if (opt1->ngener == opt2->ngener)
-    {
-        for (i = 0; i < opt1->ngener; i++)
-        {
-            for (j = i; j < opt1->ngener; j++)
-            {
-                sprintf(buf1, "inputrec->grpopts.egp_flags[%d]", i);
-                cmp_int(fp, buf1, j,
-                        opt1->egp_flags[opt1->ngener*i+j],
-                        opt2->egp_flags[opt1->ngener*i+j]);
-            }
-        }
-    }
-    for (i = 0; (i < std::min(opt1->ngacc, opt2->ngacc)); i++)
-    {
-        cmp_rvec(fp, "inputrec->grpopts.acc", i, opt1->acc[i], opt2->acc[i], ftol, abstol);
-    }
-    for (i = 0; (i < std::min(opt1->ngfrz, opt2->ngfrz)); i++)
-    {
-        cmp_ivec(fp, "inputrec->grpopts.nFreeze", i, opt1->nFreeze[i], opt2->nFreeze[i]);
-    }
-}
-
-static void cmp_cosines(FILE *fp, const char *s, const t_cosines c1[DIM], const t_cosines c2[DIM], real ftol, real abstol)
-{
-    int  i, m;
-    char buf[256];
-
-    for (m = 0; (m < DIM); m++)
-    {
-        sprintf(buf, "inputrec->%s[%d]", s, m);
-        cmp_int(fp, buf, 0, c1->n, c2->n);
-        for (i = 0; (i < std::min(c1->n, c2->n)); i++)
-        {
-            cmp_real(fp, buf, i, c1->a[i], c2->a[i], ftol, abstol);
-            cmp_real(fp, buf, i, c1->phi[i], c2->phi[i], ftol, abstol);
-        }
-    }
-}
-static void cmp_pull(FILE *fp)
-{
-    fprintf(fp, "WARNING: Both files use COM pulling, but comparing of the pull struct is not implemented (yet). The pull parameters could be the same or different.\n");
-}
-
-static void cmp_simtempvals(FILE *fp, const t_simtemp *simtemp1, const t_simtemp *simtemp2, int n_lambda, real ftol, real abstol)
-{
-    int i;
-    cmp_int(fp, "inputrec->simtempvals->eSimTempScale", -1, simtemp1->eSimTempScale, simtemp2->eSimTempScale);
-    cmp_real(fp, "inputrec->simtempvals->simtemp_high", -1, simtemp1->simtemp_high, simtemp2->simtemp_high, ftol, abstol);
-    cmp_real(fp, "inputrec->simtempvals->simtemp_low", -1, simtemp1->simtemp_low, simtemp2->simtemp_low, ftol, abstol);
-    for (i = 0; i < n_lambda; i++)
-    {
-        cmp_real(fp, "inputrec->simtempvals->temperatures", -1, simtemp1->temperatures[i], simtemp2->temperatures[i], ftol, abstol);
-    }
-}
-
-static void cmp_expandedvals(FILE *fp, const t_expanded *expand1, const t_expanded *expand2, int n_lambda, real ftol, real abstol)
-{
-    int i;
-
-    cmp_bool(fp, "inputrec->fepvals->bInit_weights", -1, expand1->bInit_weights, expand2->bInit_weights);
-    cmp_bool(fp, "inputrec->fepvals->bWLoneovert", -1, expand1->bWLoneovert, expand2->bWLoneovert);
-
-    for (i = 0; i < n_lambda; i++)
-    {
-        cmp_real(fp, "inputrec->expandedvals->init_lambda_weights", -1,
-                 expand1->init_lambda_weights[i], expand2->init_lambda_weights[i], ftol, abstol);
-    }
-
-    cmp_int(fp, "inputrec->expandedvals->lambda-stats", -1, expand1->elamstats, expand2->elamstats);
-    cmp_int(fp, "inputrec->expandedvals->lambda-mc-move", -1, expand1->elmcmove, expand2->elmcmove);
-    cmp_int(fp, "inputrec->expandedvals->lmc-repeats", -1, expand1->lmc_repeats, expand2->lmc_repeats);
-    cmp_int(fp, "inputrec->expandedvals->lmc-gibbsdelta", -1, expand1->gibbsdeltalam, expand2->gibbsdeltalam);
-    cmp_int(fp, "inputrec->expandedvals->lmc-forced-nstart", -1, expand1->lmc_forced_nstart, expand2->lmc_forced_nstart);
-    cmp_int(fp, "inputrec->expandedvals->lambda-weights-equil", -1, expand1->elmceq, expand2->elmceq);
-    cmp_int(fp, "inputrec->expandedvals->,weight-equil-number-all-lambda", -1, expand1->equil_n_at_lam, expand2->equil_n_at_lam);
-    cmp_int(fp, "inputrec->expandedvals->weight-equil-number-samples", -1, expand1->equil_samples, expand2->equil_samples);
-    cmp_int(fp, "inputrec->expandedvals->weight-equil-number-steps", -1, expand1->equil_steps, expand2->equil_steps);
-    cmp_real(fp, "inputrec->expandedvals->weight-equil-wl-delta", -1, expand1->equil_wl_delta, expand2->equil_wl_delta, ftol, abstol);
-    cmp_real(fp, "inputrec->expandedvals->weight-equil-count-ratio", -1, expand1->equil_ratio, expand2->equil_ratio, ftol, abstol);
-    cmp_bool(fp, "inputrec->expandedvals->symmetrized-transition-matrix", -1, expand1->bSymmetrizedTMatrix, expand2->bSymmetrizedTMatrix);
-    cmp_int(fp, "inputrec->expandedvals->nstTij", -1, expand1->nstTij, expand2->nstTij);
-    cmp_int(fp, "inputrec->expandedvals->mininum-var-min", -1, expand1->minvarmin, expand2->minvarmin); /*default is reasonable */
-    cmp_int(fp, "inputrec->expandedvals->weight-c-range", -1, expand1->c_range, expand2->c_range);      /* default is just C=0 */
-    cmp_real(fp, "inputrec->expandedvals->wl-scale", -1, expand1->wl_scale, expand2->wl_scale, ftol, abstol);
-    cmp_real(fp, "inputrec->expandedvals->init-wl-delta", -1, expand1->init_wl_delta, expand2->init_wl_delta, ftol, abstol);
-    cmp_real(fp, "inputrec->expandedvals->wl-ratio", -1, expand1->wl_ratio, expand2->wl_ratio, ftol, abstol);
-    cmp_int(fp, "inputrec->expandedvals->nstexpanded", -1, expand1->nstexpanded, expand2->nstexpanded);
-    cmp_int(fp, "inputrec->expandedvals->lmc-seed", -1, expand1->lmc_seed, expand2->lmc_seed);
-    cmp_real(fp, "inputrec->expandedvals->mc-temperature", -1, expand1->mc_temp, expand2->mc_temp, ftol, abstol);
-}
-
-static void cmp_fepvals(FILE *fp, const t_lambda *fep1, const t_lambda *fep2, real ftol, real abstol)
-{
-    int i, j;
-    cmp_int(fp, "inputrec->nstdhdl", -1, fep1->nstdhdl, fep2->nstdhdl);
-    cmp_double(fp, "inputrec->fepvals->init_fep_state", -1, fep1->init_fep_state, fep2->init_fep_state, ftol, abstol);
-    cmp_double(fp, "inputrec->fepvals->delta_lambda", -1, fep1->delta_lambda, fep2->delta_lambda, ftol, abstol);
-    cmp_int(fp, "inputrec->fepvals->n_lambda", -1, fep1->n_lambda, fep2->n_lambda);
-    for (i = 0; i < efptNR; i++)
-    {
-        for (j = 0; j < std::min(fep1->n_lambda, fep2->n_lambda); j++)
-        {
-            cmp_double(fp, "inputrec->fepvals->all_lambda", -1, fep1->all_lambda[i][j], fep2->all_lambda[i][j], ftol, abstol);
-        }
-    }
-    cmp_int(fp, "inputrec->fepvals->lambda_neighbors", 1, fep1->lambda_neighbors,
-            fep2->lambda_neighbors);
-    cmp_real(fp, "inputrec->fepvals->sc_alpha", -1, fep1->sc_alpha, fep2->sc_alpha, ftol, abstol);
-    cmp_int(fp, "inputrec->fepvals->sc_power", -1, fep1->sc_power, fep2->sc_power);
-    cmp_real(fp, "inputrec->fepvals->sc_r_power", -1, fep1->sc_r_power, fep2->sc_r_power, ftol, abstol);
-    cmp_real(fp, "inputrec->fepvals->sc_sigma", -1, fep1->sc_sigma, fep2->sc_sigma, ftol, abstol);
-    cmp_int(fp, "inputrec->fepvals->edHdLPrintEnergy", -1, fep1->edHdLPrintEnergy, fep1->edHdLPrintEnergy);
-    cmp_bool(fp, "inputrec->fepvals->bScCoul", -1, fep1->bScCoul, fep1->bScCoul);
-    cmp_int(fp, "inputrec->separate_dhdl_file", -1, fep1->separate_dhdl_file, fep2->separate_dhdl_file);
-    cmp_int(fp, "inputrec->dhdl_derivatives", -1, fep1->dhdl_derivatives, fep2->dhdl_derivatives);
-    cmp_int(fp, "inputrec->dh_hist_size", -1, fep1->dh_hist_size, fep2->dh_hist_size);
-    cmp_double(fp, "inputrec->dh_hist_spacing", -1, fep1->dh_hist_spacing, fep2->dh_hist_spacing, ftol, abstol);
-}
-
-static void cmp_inputrec(FILE *fp, const t_inputrec *ir1, const t_inputrec *ir2, real ftol, real abstol)
-{
-    fprintf(fp, "comparing inputrec\n");
-
-    /* gcc 2.96 doesnt like these defines at all, but issues a huge list
-     * of warnings. Maybe it will change in future versions, but for the
-     * moment I've spelled them out instead. /EL 000820
-     * #define CIB(s) cmp_int(fp,"inputrec->"#s,0,ir1->##s,ir2->##s)
-     * #define CII(s) cmp_int(fp,"inputrec->"#s,0,ir1->##s,ir2->##s)
-     * #define CIR(s) cmp_real(fp,"inputrec->"#s,0,ir1->##s,ir2->##s,ftol)
-     */
-    cmp_int(fp, "inputrec->eI", -1, ir1->eI, ir2->eI);
-    cmp_int64(fp, "inputrec->nsteps", ir1->nsteps, ir2->nsteps);
-    cmp_int64(fp, "inputrec->init_step", ir1->init_step, ir2->init_step);
-    cmp_int(fp, "inputrec->simulation_part", -1, ir1->simulation_part, ir2->simulation_part);
-    cmp_int(fp, "inputrec->ePBC", -1, ir1->ePBC, ir2->ePBC);
-    cmp_int(fp, "inputrec->bPeriodicMols", -1, ir1->bPeriodicMols, ir2->bPeriodicMols);
-    cmp_int(fp, "inputrec->cutoff_scheme", -1, ir1->cutoff_scheme, ir2->cutoff_scheme);
-    cmp_int(fp, "inputrec->ns_type", -1, ir1->ns_type, ir2->ns_type);
-    cmp_int(fp, "inputrec->nstlist", -1, ir1->nstlist, ir2->nstlist);
-    cmp_int(fp, "inputrec->nstcomm", -1, ir1->nstcomm, ir2->nstcomm);
-    cmp_int(fp, "inputrec->comm_mode", -1, ir1->comm_mode, ir2->comm_mode);
-    cmp_int(fp, "inputrec->nstlog", -1, ir1->nstlog, ir2->nstlog);
-    cmp_int(fp, "inputrec->nstxout", -1, ir1->nstxout, ir2->nstxout);
-    cmp_int(fp, "inputrec->nstvout", -1, ir1->nstvout, ir2->nstvout);
-    cmp_int(fp, "inputrec->nstfout", -1, ir1->nstfout, ir2->nstfout);
-    cmp_int(fp, "inputrec->nstcalcenergy", -1, ir1->nstcalcenergy, ir2->nstcalcenergy);
-    cmp_int(fp, "inputrec->nstenergy", -1, ir1->nstenergy, ir2->nstenergy);
-    cmp_int(fp, "inputrec->nstxout_compressed", -1, ir1->nstxout_compressed, ir2->nstxout_compressed);
-    cmp_double(fp, "inputrec->init_t", -1, ir1->init_t, ir2->init_t, ftol, abstol);
-    cmp_double(fp, "inputrec->delta_t", -1, ir1->delta_t, ir2->delta_t, ftol, abstol);
-    cmp_real(fp, "inputrec->x_compression_precision", -1, ir1->x_compression_precision, ir2->x_compression_precision, ftol, abstol);
-    cmp_real(fp, "inputrec->fourierspacing", -1, ir1->fourier_spacing, ir2->fourier_spacing, ftol, abstol);
-    cmp_int(fp, "inputrec->nkx", -1, ir1->nkx, ir2->nkx);
-    cmp_int(fp, "inputrec->nky", -1, ir1->nky, ir2->nky);
-    cmp_int(fp, "inputrec->nkz", -1, ir1->nkz, ir2->nkz);
-    cmp_int(fp, "inputrec->pme_order", -1, ir1->pme_order, ir2->pme_order);
-    cmp_real(fp, "inputrec->ewald_rtol", -1, ir1->ewald_rtol, ir2->ewald_rtol, ftol, abstol);
-    cmp_int(fp, "inputrec->ewald_geometry", -1, ir1->ewald_geometry, ir2->ewald_geometry);
-    cmp_real(fp, "inputrec->epsilon_surface", -1, ir1->epsilon_surface, ir2->epsilon_surface, ftol, abstol);
-    cmp_int(fp, "inputrec->bContinuation", -1, ir1->bContinuation, ir2->bContinuation);
-    cmp_int(fp, "inputrec->bShakeSOR", -1, ir1->bShakeSOR, ir2->bShakeSOR);
-    cmp_int(fp, "inputrec->etc", -1, ir1->etc, ir2->etc);
-    cmp_int(fp, "inputrec->bPrintNHChains", -1, ir1->bPrintNHChains, ir2->bPrintNHChains);
-    cmp_int(fp, "inputrec->epc", -1, ir1->epc, ir2->epc);
-    cmp_int(fp, "inputrec->epct", -1, ir1->epct, ir2->epct);
-    cmp_real(fp, "inputrec->tau_p", -1, ir1->tau_p, ir2->tau_p, ftol, abstol);
-    cmp_rvec(fp, "inputrec->ref_p(x)", -1, ir1->ref_p[XX], ir2->ref_p[XX], ftol, abstol);
-    cmp_rvec(fp, "inputrec->ref_p(y)", -1, ir1->ref_p[YY], ir2->ref_p[YY], ftol, abstol);
-    cmp_rvec(fp, "inputrec->ref_p(z)", -1, ir1->ref_p[ZZ], ir2->ref_p[ZZ], ftol, abstol);
-    cmp_rvec(fp, "inputrec->compress(x)", -1, ir1->compress[XX], ir2->compress[XX], ftol, abstol);
-    cmp_rvec(fp, "inputrec->compress(y)", -1, ir1->compress[YY], ir2->compress[YY], ftol, abstol);
-    cmp_rvec(fp, "inputrec->compress(z)", -1, ir1->compress[ZZ], ir2->compress[ZZ], ftol, abstol);
-    cmp_int(fp, "refcoord_scaling", -1, ir1->refcoord_scaling, ir2->refcoord_scaling);
-    cmp_rvec(fp, "inputrec->posres_com", -1, ir1->posres_com, ir2->posres_com, ftol, abstol);
-    cmp_rvec(fp, "inputrec->posres_comB", -1, ir1->posres_comB, ir2->posres_comB, ftol, abstol);
-    cmp_real(fp, "inputrec->verletbuf_tol", -1, ir1->verletbuf_tol, ir2->verletbuf_tol, ftol, abstol);
-    cmp_real(fp, "inputrec->rlist", -1, ir1->rlist, ir2->rlist, ftol, abstol);
-    cmp_real(fp, "inputrec->rtpi", -1, ir1->rtpi, ir2->rtpi, ftol, abstol);
-    cmp_int(fp, "inputrec->coulombtype", -1, ir1->coulombtype, ir2->coulombtype);
-    cmp_int(fp, "inputrec->coulomb_modifier", -1, ir1->coulomb_modifier, ir2->coulomb_modifier);
-    cmp_real(fp, "inputrec->rcoulomb_switch", -1, ir1->rcoulomb_switch, ir2->rcoulomb_switch, ftol, abstol);
-    cmp_real(fp, "inputrec->rcoulomb", -1, ir1->rcoulomb, ir2->rcoulomb, ftol, abstol);
-    cmp_int(fp, "inputrec->vdwtype", -1, ir1->vdwtype, ir2->vdwtype);
-    cmp_int(fp, "inputrec->vdw_modifier", -1, ir1->vdw_modifier, ir2->vdw_modifier);  cmp_real(fp, "inputrec->rvdw_switch", -1, ir1->rvdw_switch, ir2->rvdw_switch, ftol, abstol);
-    cmp_real(fp, "inputrec->rvdw", -1, ir1->rvdw, ir2->rvdw, ftol, abstol);
-    cmp_real(fp, "inputrec->epsilon_r", -1, ir1->epsilon_r, ir2->epsilon_r, ftol, abstol);
-    cmp_real(fp, "inputrec->epsilon_rf", -1, ir1->epsilon_rf, ir2->epsilon_rf, ftol, abstol);
-    cmp_real(fp, "inputrec->tabext", -1, ir1->tabext, ir2->tabext, ftol, abstol);
-    cmp_int(fp, "inputrec->implicit_solvent", -1, ir1->implicit_solvent, ir2->implicit_solvent);
-    cmp_int(fp, "inputrec->gb_algorithm", -1, ir1->gb_algorithm, ir2->gb_algorithm);
-    cmp_int(fp, "inputrec->nstgbradii", -1, ir1->nstgbradii, ir2->nstgbradii);
-    cmp_real(fp, "inputrec->rgbradii", -1, ir1->rgbradii, ir2->rgbradii, ftol, abstol);
-    cmp_real(fp, "inputrec->gb_saltconc", -1, ir1->gb_saltconc, ir2->gb_saltconc, ftol, abstol);
-    cmp_real(fp, "inputrec->gb_epsilon_solvent", -1, ir1->gb_epsilon_solvent, ir2->gb_epsilon_solvent, ftol, abstol);
-    cmp_real(fp, "inputrec->gb_obc_alpha", -1, ir1->gb_obc_alpha, ir2->gb_obc_alpha, ftol, abstol);
-    cmp_real(fp, "inputrec->gb_obc_beta", -1, ir1->gb_obc_beta, ir2->gb_obc_beta, ftol, abstol);
-    cmp_real(fp, "inputrec->gb_obc_gamma", -1, ir1->gb_obc_gamma, ir2->gb_obc_gamma, ftol, abstol);
-    cmp_real(fp, "inputrec->gb_dielectric_offset", -1, ir1->gb_dielectric_offset, ir2->gb_dielectric_offset, ftol, abstol);
-    cmp_int(fp, "inputrec->sa_algorithm", -1, ir1->sa_algorithm, ir2->sa_algorithm);
-    cmp_real(fp, "inputrec->sa_surface_tension", -1, ir1->sa_surface_tension, ir2->sa_surface_tension, ftol, abstol);
-
-    cmp_int(fp, "inputrec->eDispCorr", -1, ir1->eDispCorr, ir2->eDispCorr);
-    cmp_real(fp, "inputrec->shake_tol", -1, ir1->shake_tol, ir2->shake_tol, ftol, abstol);
-    cmp_int(fp, "inputrec->efep", -1, ir1->efep, ir2->efep);
-    cmp_fepvals(fp, ir1->fepvals, ir2->fepvals, ftol, abstol);
-    cmp_int(fp, "inputrec->bSimTemp", -1, ir1->bSimTemp, ir2->bSimTemp);
-    if ((ir1->bSimTemp == ir2->bSimTemp) && (ir1->bSimTemp))
-    {
-        cmp_simtempvals(fp, ir1->simtempvals, ir2->simtempvals, std::min(ir1->fepvals->n_lambda, ir2->fepvals->n_lambda), ftol, abstol);
-    }
-    cmp_int(fp, "inputrec->bExpanded", -1, ir1->bExpanded, ir2->bExpanded);
-    if ((ir1->bExpanded == ir2->bExpanded) && (ir1->bExpanded))
-    {
-        cmp_expandedvals(fp, ir1->expandedvals, ir2->expandedvals, std::min(ir1->fepvals->n_lambda, ir2->fepvals->n_lambda), ftol, abstol);
-    }
-    cmp_int(fp, "inputrec->nwall", -1, ir1->nwall, ir2->nwall);
-    cmp_int(fp, "inputrec->wall_type", -1, ir1->wall_type, ir2->wall_type);
-    cmp_int(fp, "inputrec->wall_atomtype[0]", -1, ir1->wall_atomtype[0], ir2->wall_atomtype[0]);
-    cmp_int(fp, "inputrec->wall_atomtype[1]", -1, ir1->wall_atomtype[1], ir2->wall_atomtype[1]);
-    cmp_real(fp, "inputrec->wall_density[0]", -1, ir1->wall_density[0], ir2->wall_density[0], ftol, abstol);
-    cmp_real(fp, "inputrec->wall_density[1]", -1, ir1->wall_density[1], ir2->wall_density[1], ftol, abstol);
-    cmp_real(fp, "inputrec->wall_ewald_zfac", -1, ir1->wall_ewald_zfac, ir2->wall_ewald_zfac, ftol, abstol);
-
-    cmp_bool(fp, "inputrec->bPull", -1, ir1->bPull, ir2->bPull);
-    if (ir1->bPull && ir2->bPull)
-    {
-        cmp_pull(fp);
-    }
-
-    cmp_int(fp, "inputrec->eDisre", -1, ir1->eDisre, ir2->eDisre);
-    cmp_real(fp, "inputrec->dr_fc", -1, ir1->dr_fc, ir2->dr_fc, ftol, abstol);
-    cmp_int(fp, "inputrec->eDisreWeighting", -1, ir1->eDisreWeighting, ir2->eDisreWeighting);
-    cmp_int(fp, "inputrec->bDisreMixed", -1, ir1->bDisreMixed, ir2->bDisreMixed);
-    cmp_int(fp, "inputrec->nstdisreout", -1, ir1->nstdisreout, ir2->nstdisreout);
-    cmp_real(fp, "inputrec->dr_tau", -1, ir1->dr_tau, ir2->dr_tau, ftol, abstol);
-    cmp_real(fp, "inputrec->orires_fc", -1, ir1->orires_fc, ir2->orires_fc, ftol, abstol);
-    cmp_real(fp, "inputrec->orires_tau", -1, ir1->orires_tau, ir2->orires_tau, ftol, abstol);
-    cmp_int(fp, "inputrec->nstorireout", -1, ir1->nstorireout, ir2->nstorireout);
-    cmp_real(fp, "inputrec->em_stepsize", -1, ir1->em_stepsize, ir2->em_stepsize, ftol, abstol);
-    cmp_real(fp, "inputrec->em_tol", -1, ir1->em_tol, ir2->em_tol, ftol, abstol);
-    cmp_int(fp, "inputrec->niter", -1, ir1->niter, ir2->niter);
-    cmp_real(fp, "inputrec->fc_stepsize", -1, ir1->fc_stepsize, ir2->fc_stepsize, ftol, abstol);
-    cmp_int(fp, "inputrec->nstcgsteep", -1, ir1->nstcgsteep, ir2->nstcgsteep);
-    cmp_int(fp, "inputrec->nbfgscorr", 0, ir1->nbfgscorr, ir2->nbfgscorr);
-    cmp_int(fp, "inputrec->eConstrAlg", -1, ir1->eConstrAlg, ir2->eConstrAlg);
-    cmp_int(fp, "inputrec->nProjOrder", -1, ir1->nProjOrder, ir2->nProjOrder);
-    cmp_real(fp, "inputrec->LincsWarnAngle", -1, ir1->LincsWarnAngle, ir2->LincsWarnAngle, ftol, abstol);
-    cmp_int(fp, "inputrec->nLincsIter", -1, ir1->nLincsIter, ir2->nLincsIter);
-    cmp_real(fp, "inputrec->bd_fric", -1, ir1->bd_fric, ir2->bd_fric, ftol, abstol);
-    cmp_int64(fp, "inputrec->ld_seed", ir1->ld_seed, ir2->ld_seed);
-    cmp_real(fp, "inputrec->cos_accel", -1, ir1->cos_accel, ir2->cos_accel, ftol, abstol);
-    cmp_rvec(fp, "inputrec->deform(a)", -1, ir1->deform[XX], ir2->deform[XX], ftol, abstol);
-    cmp_rvec(fp, "inputrec->deform(b)", -1, ir1->deform[YY], ir2->deform[YY], ftol, abstol);
-    cmp_rvec(fp, "inputrec->deform(c)", -1, ir1->deform[ZZ], ir2->deform[ZZ], ftol, abstol);
-
-
-    cmp_int(fp, "inputrec->userint1", -1, ir1->userint1, ir2->userint1);
-    cmp_int(fp, "inputrec->userint2", -1, ir1->userint2, ir2->userint2);
-    cmp_int(fp, "inputrec->userint3", -1, ir1->userint3, ir2->userint3);
-    cmp_int(fp, "inputrec->userint4", -1, ir1->userint4, ir2->userint4);
-    cmp_real(fp, "inputrec->userreal1", -1, ir1->userreal1, ir2->userreal1, ftol, abstol);
-    cmp_real(fp, "inputrec->userreal2", -1, ir1->userreal2, ir2->userreal2, ftol, abstol);
-    cmp_real(fp, "inputrec->userreal3", -1, ir1->userreal3, ir2->userreal3, ftol, abstol);
-    cmp_real(fp, "inputrec->userreal4", -1, ir1->userreal4, ir2->userreal4, ftol, abstol);
-    cmp_grpopts(fp, &(ir1->opts), &(ir2->opts), ftol, abstol);
-    cmp_cosines(fp, "ex", ir1->ex, ir2->ex, ftol, abstol);
-    cmp_cosines(fp, "et", ir1->et, ir2->et, ftol, abstol);
-}
-
-static void comp_pull_AB(FILE *fp, pull_params_t *pull, real ftol, real abstol)
-{
-    int i;
-
-    for (i = 0; i < pull->ncoord; i++)
-    {
-        fprintf(fp, "comparing pull coord %d\n", i);
-        cmp_real(fp, "pull-coord->k", -1, pull->coord[i].k, pull->coord[i].kB, ftol, abstol);
-    }
-}
-
-static void comp_state(const t_state *st1, const t_state *st2,
-                       gmx_bool bRMSD, real ftol, real abstol)
-{
-    int i, j, nc;
-
-    fprintf(stdout, "comparing flags\n");
-    cmp_int(stdout, "flags", -1, st1->flags, st2->flags);
-    fprintf(stdout, "comparing box\n");
-    cmp_rvecs(stdout, "box", DIM, st1->box, st2->box, FALSE, ftol, abstol);
-    fprintf(stdout, "comparing box_rel\n");
-    cmp_rvecs(stdout, "box_rel", DIM, st1->box_rel, st2->box_rel, FALSE, ftol, abstol);
-    fprintf(stdout, "comparing boxv\n");
-    cmp_rvecs(stdout, "boxv", DIM, st1->boxv, st2->boxv, FALSE, ftol, abstol);
-    if (st1->flags & (1<<estSVIR_PREV))
-    {
-        fprintf(stdout, "comparing shake vir_prev\n");
-        cmp_rvecs(stdout, "svir_prev", DIM, st1->svir_prev, st2->svir_prev, FALSE, ftol, abstol);
-    }
-    if (st1->flags & (1<<estFVIR_PREV))
-    {
-        fprintf(stdout, "comparing force vir_prev\n");
-        cmp_rvecs(stdout, "fvir_prev", DIM, st1->fvir_prev, st2->fvir_prev, FALSE, ftol, abstol);
-    }
-    if (st1->flags & (1<<estPRES_PREV))
-    {
-        fprintf(stdout, "comparing prev_pres\n");
-        cmp_rvecs(stdout, "pres_prev", DIM, st1->pres_prev, st2->pres_prev, FALSE, ftol, abstol);
-    }
-    cmp_int(stdout, "ngtc", -1, st1->ngtc, st2->ngtc);
-    cmp_int(stdout, "nhchainlength", -1, st1->nhchainlength, st2->nhchainlength);
-    if (st1->ngtc == st2->ngtc && st1->nhchainlength == st2->nhchainlength)
-    {
-        for (i = 0; i < st1->ngtc; i++)
-        {
-            nc = i*st1->nhchainlength;
-            for (j = 0; j < nc; j++)
-            {
-                cmp_real(stdout, "nosehoover_xi",
-                         i, st1->nosehoover_xi[nc+j], st2->nosehoover_xi[nc+j], ftol, abstol);
-            }
-        }
-    }
-    cmp_int(stdout, "nnhpres", -1, st1->nnhpres, st2->nnhpres);
-    if (st1->nnhpres == st2->nnhpres && st1->nhchainlength == st2->nhchainlength)
-    {
-        for (i = 0; i < st1->nnhpres; i++)
-        {
-            nc = i*st1->nhchainlength;
-            for (j = 0; j < nc; j++)
-            {
-                cmp_real(stdout, "nosehoover_xi",
-                         i, st1->nhpres_xi[nc+j], st2->nhpres_xi[nc+j], ftol, abstol);
-            }
-        }
-    }
-
-    cmp_int(stdout, "natoms", -1, st1->natoms, st2->natoms);
-    if (st1->natoms == st2->natoms)
-    {
-        if ((st1->flags & (1<<estX)) && (st2->flags & (1<<estX)))
-        {
-            fprintf(stdout, "comparing x\n");
-            cmp_rvecs(stdout, "x", st1->natoms, st1->x, st2->x, bRMSD, ftol, abstol);
-        }
-        if ((st1->flags & (1<<estV)) && (st2->flags & (1<<estV)))
-        {
-            fprintf(stdout, "comparing v\n");
-            cmp_rvecs(stdout, "v", st1->natoms, st1->v, st2->v, bRMSD, ftol, abstol);
-        }
-    }
-}
-
-void comp_tpx(const char *fn1, const char *fn2,
-              gmx_bool bRMSD, real ftol, real abstol)
-{
-    const char  *ff[2];
-    t_inputrec   ir[2];
-    t_state      state[2];
-    gmx_mtop_t   mtop[2];
-    t_topology   top[2];
-    int          i;
-
-    ff[0] = fn1;
-    ff[1] = fn2;
-    for (i = 0; i < (fn2 ? 2 : 1); i++)
-    {
-        read_tpx_state(ff[i], &(ir[i]), &state[i], &(mtop[i]));
-    }
-    if (fn2)
-    {
-        cmp_inputrec(stdout, &ir[0], &ir[1], ftol, abstol);
-        /* Convert gmx_mtop_t to t_topology.
-         * We should implement direct mtop comparison,
-         * but it might be useful to keep t_topology comparison as an option.
-         */
-        top[0] = gmx_mtop_t_to_t_topology(&mtop[0]);
-        top[1] = gmx_mtop_t_to_t_topology(&mtop[1]);
-        cmp_top(stdout, &top[0], &top[1], ftol, abstol);
-        cmp_groups(stdout, &mtop[0].groups, &mtop[1].groups,
-                   mtop[0].natoms, mtop[1].natoms);
-        comp_state(&state[0], &state[1], bRMSD, ftol, abstol);
-    }
-    else
-    {
-        if (ir[0].efep == efepNO)
-        {
-            fprintf(stdout, "inputrec->efep = %s\n", efep_names[ir[0].efep]);
-        }
-        else
-        {
-            if (ir[0].bPull)
-            {
-                comp_pull_AB(stdout, ir->pull, ftol, abstol);
-            }
-            /* Convert gmx_mtop_t to t_topology.
-             * We should implement direct mtop comparison,
-             * but it might be useful to keep t_topology comparison as an option.
-             */
-            top[0] = gmx_mtop_t_to_t_topology(&mtop[0]);
-            cmp_top(stdout, &top[0], NULL, ftol, abstol);
-        }
-    }
-}
-
-void comp_frame(FILE *fp, t_trxframe *fr1, t_trxframe *fr2,
-                gmx_bool bRMSD, real ftol, real abstol)
-{
-    fprintf(fp, "\n");
-    cmp_int(fp, "not_ok", -1, fr1->not_ok, fr2->not_ok);
-    cmp_int(fp, "natoms", -1, fr1->natoms, fr2->natoms);
-    if (cmp_bool(fp, "bTitle", -1, fr1->bTitle, fr2->bTitle))
-    {
-        cmp_str(fp, "title", -1, fr1->title, fr2->title);
-    }
-    if (cmp_bool(fp, "bStep", -1, fr1->bStep, fr2->bStep))
-    {
-        cmp_int(fp, "step", -1, fr1->step, fr2->step);
-    }
-    cmp_int(fp, "step", -1, fr1->step, fr2->step);
-    if (cmp_bool(fp, "bTime", -1, fr1->bTime, fr2->bTime))
-    {
-        cmp_real(fp, "time", -1, fr1->time, fr2->time, ftol, abstol);
-    }
-    if (cmp_bool(fp, "bLambda", -1, fr1->bLambda, fr2->bLambda))
-    {
-        cmp_real(fp, "lambda", -1, fr1->lambda, fr2->lambda, ftol, abstol);
-    }
-    if (cmp_bool(fp, "bAtoms", -1, fr1->bAtoms, fr2->bAtoms))
-    {
-        cmp_atoms(fp, fr1->atoms, fr2->atoms, ftol, abstol);
-    }
-    if (cmp_bool(fp, "bPrec", -1, fr1->bPrec, fr2->bPrec))
-    {
-        cmp_real(fp, "prec", -1, fr1->prec, fr2->prec, ftol, abstol);
-    }
-    if (cmp_bool(fp, "bX", -1, fr1->bX, fr2->bX))
-    {
-        cmp_rvecs(fp, "x", std::min(fr1->natoms, fr2->natoms), fr1->x, fr2->x, bRMSD, ftol, abstol);
-    }
-    if (cmp_bool(fp, "bV", -1, fr1->bV, fr2->bV))
-    {
-        cmp_rvecs(fp, "v", std::min(fr1->natoms, fr2->natoms), fr1->v, fr2->v, bRMSD, ftol, abstol);
-    }
-    if (cmp_bool(fp, "bF", -1, fr1->bF, fr2->bF))
-    {
-        cmp_rvecs(fp, "f", std::min(fr1->natoms, fr2->natoms), fr1->f, fr2->f, bRMSD, ftol, abstol);
-    }
-    if (cmp_bool(fp, "bBox", -1, fr1->bBox, fr2->bBox))
-    {
-        cmp_rvecs(fp, "box", 3, fr1->box, fr2->box, FALSE, ftol, abstol);
-    }
-}
-
-void comp_trx(const gmx_output_env_t *oenv, const char *fn1, const char *fn2,
-              gmx_bool bRMSD, real ftol, real abstol)
-{
-    int          i;
-    const char  *fn[2];
-    t_trxframe   fr[2];
-    t_trxstatus *status[2];
-    gmx_bool     b[2];
-
-    fn[0] = fn1;
-    fn[1] = fn2;
-    fprintf(stderr, "Comparing trajectory files %s and %s\n", fn1, fn2);
-    for (i = 0; i < 2; i++)
-    {
-        b[i] = read_first_frame(oenv, &status[i], fn[i], &fr[i], TRX_READ_X|TRX_READ_V|TRX_READ_F);
-    }
-
-    if (b[0] && b[1])
-    {
-        do
-        {
-            comp_frame(stdout, &(fr[0]), &(fr[1]), bRMSD, ftol, abstol);
-
-            for (i = 0; i < 2; i++)
-            {
-                b[i] = read_next_frame(oenv, status[i], &fr[i]);
-            }
-        }
-        while (b[0] && b[1]);
-
-        for (i = 0; i < 2; i++)
-        {
-            if (b[i] && !b[1-i])
-            {
-                fprintf(stdout, "\nEnd of file on %s but not on %s\n", fn[1-i], fn[i]);
-            }
-            close_trj(status[i]);
-        }
-    }
-    if (!b[0] && !b[1])
-    {
-        fprintf(stdout, "\nBoth files read correctly\n");
-    }
-}
-
-static real ener_tensor_diag(int n, int *ind1, int *ind2,
-                             gmx_enxnm_t *enm1,
-                             int *tensi, int i,
-                             t_energy e1[], t_energy e2[])
-{
-    int    d1, d2;
-    int    j;
-    real   prod1, prod2;
-    int    nfound;
-    size_t len;
-
-    d1 = tensi[i]/DIM;
-    d2 = tensi[i] - d1*DIM;
-
-    /* Find the diagonal elements d1 and d2 */
-    len    = std::strlen(enm1[ind1[i]].name);
-    prod1  = 1;
-    prod2  = 1;
-    nfound = 0;
-    for (j = 0; j < n; j++)
-    {
-        if (tensi[j] >= 0 &&
-            std::strlen(enm1[ind1[j]].name) == len &&
-            std::strncmp(enm1[ind1[i]].name, enm1[ind1[j]].name, len-2) == 0 &&
-            (tensi[j] == d1*DIM+d1 || tensi[j] == d2*DIM+d2))
-        {
-            prod1 *= fabs(e1[ind1[j]].e);
-            prod2 *= fabs(e2[ind2[j]].e);
-            nfound++;
-        }
-    }
-
-    if (nfound == 2)
-    {
-        return 0.5*(std::sqrt(prod1) + std::sqrt(prod2));
-    }
-    else
-    {
-        return 0;
-    }
-}
-
-static gmx_bool enernm_equal(const char *nm1, const char *nm2)
-{
-    int len1, len2;
-
-    len1 = std::strlen(nm1);
-    len2 = std::strlen(nm2);
-
-    /* Remove " (bar)" at the end of a name */
-    if (len1 > 6 && std::strcmp(nm1+len1-6, " (bar)") == 0)
-    {
-        len1 -= 6;
-    }
-    if (len2 > 6 && std::strcmp(nm2+len2-6, " (bar)") == 0)
-    {
-        len2 -= 6;
-    }
-
-    return (len1 == len2 && gmx_strncasecmp(nm1, nm2, len1) == 0);
-}
-
-static void cmp_energies(FILE *fp, int step1, int step2,
-                         t_energy e1[], t_energy e2[],
-                         gmx_enxnm_t *enm1,
-                         real ftol, real abstol,
-                         int nre, int *ind1, int *ind2, int maxener)
-{
-    int   i, ii;
-    int  *tensi, len, d1, d2;
-    real  ftol_i, abstol_i;
-
-    snew(tensi, maxener);
-    /* Check for tensor elements ending on "-XX", "-XY", ... , "-ZZ" */
-    for (i = 0; (i < maxener); i++)
-    {
-        ii       = ind1[i];
-        tensi[i] = -1;
-        len      = std::strlen(enm1[ii].name);
-        if (len > 3 && enm1[ii].name[len-3] == '-')
-        {
-            d1 = enm1[ii].name[len-2] - 'X';
-            d2 = enm1[ii].name[len-1] - 'X';
-            if (d1 >= 0 && d1 < DIM &&
-                d2 >= 0 && d2 < DIM)
-            {
-                tensi[i] = d1*DIM + d2;
-            }
-        }
-    }
-
-    for (i = 0; (i < maxener); i++)
-    {
-        /* Check if this is an off-diagonal tensor element */
-        if (tensi[i] >= 0 && tensi[i] != 0 && tensi[i] != 4 && tensi[i] != 8)
-        {
-            /* Turn on the relative tolerance check (4 is maximum relative diff.) */
-            ftol_i = 5;
-            /* Do the relative tolerance through an absolute tolerance times
-             * the size of diagonal components of the tensor.
-             */
-            abstol_i = ftol*ener_tensor_diag(nre, ind1, ind2, enm1, tensi, i, e1, e2);
-            if (debug)
-            {
-                fprintf(debug, "tensor '%s' val %f diag %f\n",
-                        enm1[i].name, e1[i].e, abstol_i/ftol);
-            }
-            if (abstol_i > 0)
-            {
-                /* We found a diagonal, we need to check with the minimum tolerance */
-                abstol_i = std::min(abstol_i, abstol);
-            }
-            else
-            {
-                /* We did not find a diagonal, ignore the relative tolerance check */
-                abstol_i = abstol;
-            }
-        }
-        else
-        {
-            ftol_i   = ftol;
-            abstol_i = abstol;
-        }
-        if (!equal_real(e1[ind1[i]].e, e2[ind2[i]].e, ftol_i, abstol_i))
-        {
-            fprintf(fp, "%-15s  step %3d:  %12g,  step %3d: %12g\n",
-                    enm1[ind1[i]].name,
-                    step1, e1[ind1[i]].e,
-                    step2, e2[ind2[i]].e);
-        }
-    }
-
-    sfree(tensi);
-}
-
-#if 0
-static void cmp_disres(t_enxframe *fr1, t_enxframe *fr2, real ftol, real abstol)
-{
-    int  i;
-    char bav[64], bt[64], bs[22];
-
-    cmp_int(stdout, "ndisre", -1, fr1->ndisre, fr2->ndisre);
-    if ((fr1->ndisre == fr2->ndisre) && (fr1->ndisre > 0))
-    {
-        sprintf(bav, "step %s: disre rav", gmx_step_str(fr1->step, bs));
-        sprintf(bt, "step %s: disre  rt", gmx_step_str(fr1->step, bs));
-        for (i = 0; (i < fr1->ndisre); i++)
-        {
-            cmp_real(stdout, bav, i, fr1->disre_rm3tav[i], fr2->disre_rm3tav[i], ftol, abstol);
-            cmp_real(stdout, bt, i, fr1->disre_rt[i], fr2->disre_rt[i], ftol, abstol);
-        }
-    }
-}
-#endif
-
-static void cmp_eblocks(t_enxframe *fr1, t_enxframe *fr2, real ftol, real abstol)
-{
-    int  i, j, k;
-    char buf[64], bs[22];
-
-    cmp_int(stdout, "nblock", -1, fr1->nblock, fr2->nblock);
-    if ((fr1->nblock == fr2->nblock) && (fr1->nblock > 0))
-    {
-        for (j = 0; (j < fr1->nblock); j++)
-        {
-            t_enxblock *b1, *b2; /* convenience vars */
-
-            b1 = &(fr1->block[j]);
-            b2 = &(fr2->block[j]);
-
-            sprintf(buf, "step %s: block[%d]", gmx_step_str(fr1->step, bs), j);
-            cmp_int(stdout, buf, -1, b1->nsub, b2->nsub);
-            cmp_int(stdout, buf, -1, b1->id, b2->id);
-
-            if ( (b1->nsub == b2->nsub) && (b1->id == b2->id) )
-            {
-                for (i = 0; i < b1->nsub; i++)
-                {
-                    t_enxsubblock *s1, *s2;
-
-                    s1 = &(b1->sub[i]);
-                    s2 = &(b2->sub[i]);
-
-                    cmp_int(stdout, buf, -1, (int)s1->type, (int)s2->type);
-                    cmp_int64(stdout, buf, s1->nr, s2->nr);
-
-                    if ((s1->type == s2->type) && (s1->nr == s2->nr))
-                    {
-                        switch (s1->type)
-                        {
-                            case xdr_datatype_float:
-                                for (k = 0; k < s1->nr; k++)
-                                {
-                                    cmp_float(stdout, buf, i,
-                                              s1->fval[k], s2->fval[k],
-                                              ftol, abstol);
-                                }
-                                break;
-                            case xdr_datatype_double:
-                                for (k = 0; k < s1->nr; k++)
-                                {
-                                    cmp_double(stdout, buf, i,
-                                               s1->dval[k], s2->dval[k],
-                                               ftol, abstol);
-                                }
-                                break;
-                            case xdr_datatype_int:
-                                for (k = 0; k < s1->nr; k++)
-                                {
-                                    cmp_int(stdout, buf, i,
-                                            s1->ival[k], s2->ival[k]);
-                                }
-                                break;
-                            case xdr_datatype_int64:
-                                for (k = 0; k < s1->nr; k++)
-                                {
-                                    cmp_int64(stdout, buf,
-                                              s1->lval[k], s2->lval[k]);
-                                }
-                                break;
-                            case xdr_datatype_char:
-                                for (k = 0; k < s1->nr; k++)
-                                {
-                                    cmp_uc(stdout, buf, i,
-                                           s1->cval[k], s2->cval[k]);
-                                }
-                                break;
-                            case xdr_datatype_string:
-                                for (k = 0; k < s1->nr; k++)
-                                {
-                                    cmp_str(stdout, buf, i,
-                                            s1->sval[k], s2->sval[k]);
-                                }
-                                break;
-                            default:
-                                gmx_incons("Unknown data type!!");
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
-
-void comp_enx(const char *fn1, const char *fn2, real ftol, real abstol, const char *lastener)
-{
-    int            nre, nre1, nre2;
-    ener_file_t    in1, in2;
-    int            i, j, maxener, *ind1, *ind2, *have;
-    gmx_enxnm_t   *enm1 = NULL, *enm2 = NULL;
-    t_enxframe    *fr1, *fr2;
-    gmx_bool       b1, b2;
-
-    fprintf(stdout, "comparing energy file %s and %s\n\n", fn1, fn2);
-
-    in1 = open_enx(fn1, "r");
-    in2 = open_enx(fn2, "r");
-    do_enxnms(in1, &nre1, &enm1);
-    do_enxnms(in2, &nre2, &enm2);
-    if (nre1 != nre2)
-    {
-        fprintf(stdout, "There are %d and %d terms in the energy files\n\n",
-                nre1, nre2);
-    }
-    else
-    {
-        fprintf(stdout, "There are %d terms in the energy files\n\n", nre1);
-    }
-
-    snew(ind1, nre1);
-    snew(ind2, nre2);
-    snew(have, nre2);
-    nre = 0;
-    for (i = 0; i < nre1; i++)
-    {
-        for (j = 0; j < nre2; j++)
-        {
-            if (enernm_equal(enm1[i].name, enm2[j].name))
-            {
-                ind1[nre] = i;
-                ind2[nre] = j;
-                have[j]   = 1;
-                nre++;
-                break;
-            }
-        }
-        if (nre == 0 || ind1[nre-1] != i)
-        {
-            cmp_str(stdout, "enm", i, enm1[i].name, "-");
-        }
-    }
-    for (i = 0; i < nre2; i++)
-    {
-        if (have[i] == 0)
-        {
-            cmp_str(stdout, "enm", i, "-", enm2[i].name);
-        }
-    }
-
-    maxener = nre;
-    for (i = 0; i < nre; i++)
-    {
-        if ((lastener != NULL) && (std::strstr(enm1[i].name, lastener) != NULL))
-        {
-            maxener = i+1;
-            break;
-        }
-    }
-
-    fprintf(stdout, "There are %d terms to compare in the energy files\n\n",
-            maxener);
-
-    for (i = 0; i < maxener; i++)
-    {
-        cmp_str(stdout, "unit", i, enm1[ind1[i]].unit, enm2[ind2[i]].unit);
-    }
-
-    snew(fr1, 1);
-    snew(fr2, 1);
-    do
-    {
-        b1 = do_enx(in1, fr1);
-        b2 = do_enx(in2, fr2);
-        if (b1 && !b2)
-        {
-            fprintf(stdout, "\nEnd of file on %s but not on %s\n", fn2, fn1);
-        }
-        else if (!b1 && b2)
-        {
-            fprintf(stdout, "\nEnd of file on %s but not on %s\n", fn1, fn2);
-        }
-        else if (!b1 && !b2)
-        {
-            fprintf(stdout, "\nFiles read successfully\n");
-        }
-        else
-        {
-            cmp_real(stdout, "t", -1, fr1->t, fr2->t, ftol, abstol);
-            cmp_int(stdout, "step", -1, fr1->step, fr2->step);
-            /* We don't want to print the nre mismatch for every frame */
-            /* cmp_int(stdout,"nre",-1,fr1->nre,fr2->nre); */
-            if ((fr1->nre >= nre) && (fr2->nre >= nre))
-            {
-                cmp_energies(stdout, fr1->step, fr1->step, fr1->ener, fr2->ener,
-                             enm1, ftol, abstol, nre, ind1, ind2, maxener);
-            }
-            /*cmp_disres(fr1,fr2,ftol,abstol);*/
-            cmp_eblocks(fr1, fr2, ftol, abstol);
-        }
-    }
-    while (b1 && b2);
-
-    close_enx(in1);
-    close_enx(in2);
-
-    free_enxframe(fr2);
-    sfree(fr2);
-    free_enxframe(fr1);
-    sfree(fr1);
-}
index 5234d5d1d9262f88ba5cff7cfb147980691d700a..6cb6d9a8511e56b630d85b73f18f39e60ab11a06 100644 (file)
@@ -45,6 +45,7 @@
 #include "gromacs/fileio/trrio.h"
 #include "gromacs/gmxpreprocess/readir.h"
 #include "gromacs/math/vec.h"
+#include "gromacs/mdrunutility/mdmodules.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/mdtypes/state.h"
@@ -327,57 +328,38 @@ static void zeroq(int index[], gmx_mtop_t *mtop)
 int gmx_convert_tpr(int argc, char *argv[])
 {
     const char       *desc[] = {
-        "[THISMODULE] can edit run input files in four ways.[PAR]",
+        "[THISMODULE] can edit run input files in three ways.[PAR]",
         "[BB]1.[bb] by modifying the number of steps in a run input file",
         "with options [TT]-extend[tt], [TT]-until[tt] or [TT]-nsteps[tt]",
         "(nsteps=-1 means unlimited number of steps)[PAR]",
-        "[BB]2.[bb] (OBSOLETE) by creating a run input file",
-        "for a continuation run when your simulation has crashed due to e.g.",
-        "a full disk, or by making a continuation run input file.",
-        "This option is obsolete, since mdrun now writes and reads",
-        "checkpoint files.",
-        "[BB]Note[bb] that a frame with coordinates and velocities is needed.",
-        "When pressure and/or Nose-Hoover temperature coupling is used",
-        "an energy file can be supplied to get an exact continuation",
-        "of the original run.[PAR]",
-        "[BB]3.[bb] by creating a [REF].tpx[ref] file for a subset of your original",
+        "[BB]2.[bb] by creating a [REF].tpx[ref] file for a subset of your original",
         "tpx file, which is useful when you want to remove the solvent from",
         "your [REF].tpx[ref] file, or when you want to make e.g. a pure C[GRK]alpha[grk] [REF].tpx[ref] file.",
         "Note that you may need to use [TT]-nsteps -1[tt] (or similar) to get",
         "this to work.",
         "[BB]WARNING: this [REF].tpx[ref] file is not fully functional[bb].[PAR]",
-        "[BB]4.[bb] by setting the charges of a specified group",
+        "[BB]3.[bb] by setting the charges of a specified group",
         "to zero. This is useful when doing free energy estimates",
         "using the LIE (Linear Interaction Energy) method."
     };
 
-    const char       *top_fn, *frame_fn;
-    struct t_fileio  *fp;
-    ener_file_t       fp_ener = NULL;
-    gmx_trr_header_t  head;
+    const char       *top_fn;
     int               i;
-    gmx_int64_t       nsteps_req, run_step, frame;
+    gmx_int64_t       nsteps_req, run_step;
     double            run_t, state_t;
-    gmx_bool          bOK, bNsteps, bExtend, bUntil, bTime, bTraj;
-    gmx_bool          bFrame, bUse, bSel, bNeedEner, bReadEner, bScanEner, bFepState;
+    gmx_bool          bSel;
+    gmx_bool          bNsteps, bExtend, bUntil;
     gmx_mtop_t        mtop;
     t_atoms           atoms;
     t_inputrec       *ir;
     t_state           state;
-    rvec             *newx = NULL, *newv = NULL, *tmpx, *tmpv;
-    matrix            newbox;
     int               gnx;
     char             *grpname;
     int              *index = NULL;
-    int               nre;
-    gmx_enxnm_t      *enm     = NULL;
-    t_enxframe       *fr_ener = NULL;
     char              buf[200], buf2[200];
     gmx_output_env_t *oenv;
     t_filenm          fnm[] = {
         { efTPR, NULL,  NULL,    ffREAD  },
-        { efTRN, "-f",  NULL,    ffOPTRD },
-        { efEDR, "-e",  NULL,    ffOPTRD },
         { efNDX, NULL,  NULL,    ffOPTRD },
         { efTPR, "-o",  "tprout", ffWRITE }
     };
@@ -385,9 +367,8 @@ int gmx_convert_tpr(int argc, char *argv[])
 
     /* Command line options */
     static int      nsteps_req_int = 0;
-    static real     start_t        = -1.0, extend_t = 0.0, until_t = 0.0;
-    static int      init_fep_state = 0;
-    static gmx_bool bContinuation  = TRUE, bZeroQ = FALSE, bVel = TRUE;
+    static real     extend_t       = 0.0, until_t = 0.0;
+    static gmx_bool bZeroQ         = FALSE;
     static t_pargs  pa[]           = {
         { "-extend",        FALSE, etREAL, {&extend_t},
           "Extend runtime by this amount (ps)" },
@@ -395,16 +376,8 @@ int gmx_convert_tpr(int argc, char *argv[])
           "Extend runtime until this ending time (ps)" },
         { "-nsteps",        FALSE, etINT,  {&nsteps_req_int},
           "Change the number of steps" },
-        { "-time",          FALSE, etREAL, {&start_t},
-          "Continue from frame at this time (ps) instead of the last frame" },
         { "-zeroq",         FALSE, etBOOL, {&bZeroQ},
-          "Set the charges of a group (from the index) to zero" },
-        { "-vel",           FALSE, etBOOL, {&bVel},
-          "Require velocities from trajectory" },
-        { "-cont",          FALSE, etBOOL, {&bContinuation},
-          "For exact continuation, the constraints should not be applied before the first step" },
-        { "-init_fep_state", FALSE, etINT, {&init_fep_state},
-          "fep state to initialize from" },
+          "Set the charges of a group (from the index) to zero" }
     };
 
     /* Parse the command line */
@@ -419,195 +392,16 @@ int gmx_convert_tpr(int argc, char *argv[])
     bNsteps    = opt2parg_bSet("-nsteps", asize(pa), pa);
     bExtend    = opt2parg_bSet("-extend", asize(pa), pa);
     bUntil     = opt2parg_bSet("-until", asize(pa), pa);
-    bFepState  = opt2parg_bSet("-init_fep_state", asize(pa), pa);
-    bTime      = opt2parg_bSet("-time", asize(pa), pa);
-    bTraj      = (opt2bSet("-f", NFILE, fnm) || bTime);
 
     top_fn = ftp2fn(efTPR, NFILE, fnm);
     fprintf(stderr, "Reading toplogy and stuff from %s\n", top_fn);
 
-    snew(ir, 1);
+    gmx::MDModules mdModules;
+    ir = mdModules.inputrec();
     read_tpx_state(top_fn, ir, &state, &mtop);
     run_step = ir->init_step;
     run_t    = ir->init_step*ir->delta_t + ir->init_t;
 
-    if (!EI_STATE_VELOCITY(ir->eI))
-    {
-        bVel = FALSE;
-    }
-
-    if (bTraj)
-    {
-        fprintf(stderr, "\n"
-                "NOTE: Reading the state from trajectory is an obsolete feature of gmx convert-tpr.\n"
-                "      Continuation should be done by loading a checkpoint file with mdrun -cpi\n"
-                "      This guarantees that all state variables are transferred.\n"
-                "      gmx convert-tpr is now only useful for increasing nsteps,\n"
-                "      but even that can often be avoided by using mdrun -maxh\n"
-                "\n");
-
-        if (ir->bContinuation != bContinuation)
-        {
-            fprintf(stderr, "Modifying ir->bContinuation to %s\n",
-                    gmx::boolToString(bContinuation));
-        }
-        ir->bContinuation = bContinuation;
-
-
-        bNeedEner = (ir->epc == epcPARRINELLORAHMAN || ir->etc == etcNOSEHOOVER);
-        bReadEner = (bNeedEner && ftp2bSet(efEDR, NFILE, fnm));
-        bScanEner = (bReadEner && !bTime);
-
-        if (ir->epc != epcNO || EI_SD(ir->eI) || ir->eI == eiBD)
-        {
-            fprintf(stderr, "NOTE: The simulation uses pressure coupling and/or stochastic dynamics.\n"
-                    "gmx convert-tpr can not provide binary identical continuation.\n"
-                    "If you want that, supply a checkpoint file to mdrun\n\n");
-        }
-
-        if (EI_SD(ir->eI) || ir->eI == eiBD)
-        {
-            fprintf(stderr, "\nChanging ld-seed from %" GMX_PRId64 " ", ir->ld_seed);
-            ir->ld_seed = static_cast<int>(gmx::makeRandomSeed());
-            fprintf(stderr, "to %" GMX_PRId64 "\n\n", ir->ld_seed);
-        }
-
-        frame_fn = ftp2fn(efTRN, NFILE, fnm);
-
-        if (fn2ftp(frame_fn) == efCPT)
-        {
-            int sim_part;
-
-            fprintf(stderr,
-                    "\nREADING STATE FROM CHECKPOINT %s...\n\n",
-                    frame_fn);
-
-            read_checkpoint_state(frame_fn, &sim_part,
-                                  &run_step, &run_t, &state);
-        }
-        else
-        {
-            fprintf(stderr,
-                    "\nREADING COORDS, VELS AND BOX FROM TRAJECTORY %s...\n\n",
-                    frame_fn);
-
-            fp = gmx_trr_open(frame_fn, "r");
-            if (bScanEner)
-            {
-                fp_ener = open_enx(ftp2fn(efEDR, NFILE, fnm), "r");
-                do_enxnms(fp_ener, &nre, &enm);
-                snew(fr_ener, 1);
-                fr_ener->t = -1e-12;
-            }
-
-            /* Now scan until the last set of x and v (step == 0)
-             * or the ones at step step.
-             */
-            bFrame = TRUE;
-            frame  = 0;
-            while (bFrame)
-            {
-                bFrame = gmx_trr_read_frame_header(fp, &head, &bOK);
-                if (bOK && frame == 0)
-                {
-                    if (mtop.natoms != head.natoms)
-                    {
-                        gmx_fatal(FARGS, "Number of atoms in Topology (%d) "
-                                  "is not the same as in Trajectory (%d)\n",
-                                  mtop.natoms, head.natoms);
-                    }
-                    snew(newx, head.natoms);
-                    snew(newv, head.natoms);
-                }
-                bFrame = bFrame && bOK;
-                if (bFrame)
-                {
-                    bOK = gmx_trr_read_frame_data(fp, &head, newbox, newx, newv, NULL);
-                }
-                bFrame = bFrame && bOK;
-                bUse   = FALSE;
-                if (bFrame &&
-                    (head.x_size) && (head.v_size || !bVel))
-                {
-                    bUse = TRUE;
-                    if (bScanEner)
-                    {
-                        /* Read until the energy time is >= the trajectory time */
-                        while (fr_ener->t < head.t && do_enx(fp_ener, fr_ener))
-                        {
-                            ;
-                        }
-                        bUse = (fr_ener->t == head.t);
-                    }
-                    if (bUse)
-                    {
-                        tmpx                  = newx;
-                        newx                  = state.x;
-                        state.x               = tmpx;
-                        tmpv                  = newv;
-                        newv                  = state.v;
-                        state.v               = tmpv;
-                        run_t                 = head.t;
-                        run_step              = head.step;
-                        state.fep_state       = head.fep_state;
-                        state.lambda[efptFEP] = head.lambda;
-                        copy_mat(newbox, state.box);
-                    }
-                }
-                if (bFrame || !bOK)
-                {
-                    sprintf(buf, "\r%s %s frame %s%s: step %s%s time %s",
-                            "%s", "%s", "%6", GMX_PRId64, "%6", GMX_PRId64, " %8.3f");
-                    fprintf(stderr, buf,
-                            bUse ? "Read   " : "Skipped", ftp2ext(fn2ftp(frame_fn)),
-                            frame, head.step, head.t);
-                    fflush(stderr);
-                    frame++;
-                    if (bTime && (head.t >= start_t))
-                    {
-                        bFrame = FALSE;
-                    }
-                }
-            }
-            if (bScanEner)
-            {
-                close_enx(fp_ener);
-                free_enxframe(fr_ener);
-                free_enxnms(nre, enm);
-            }
-            gmx_trr_close(fp);
-            fprintf(stderr, "\n");
-
-            if (!bOK)
-            {
-                fprintf(stderr, "%s frame %s (step %s, time %g) is incomplete\n",
-                        ftp2ext(fn2ftp(frame_fn)), gmx_step_str(frame-1, buf2),
-                        gmx_step_str(head.step, buf), head.t);
-            }
-            fprintf(stderr, "\nUsing frame of step %s time %g\n",
-                    gmx_step_str(run_step, buf), run_t);
-
-            if (bNeedEner)
-            {
-                if (bReadEner)
-                {
-                    get_enx_state(ftp2fn(efEDR, NFILE, fnm), run_t, &mtop.groups, ir, &state);
-                }
-                else
-                {
-                    fprintf(stderr, "\nWARNING: The simulation uses %s temperature and/or %s pressure coupling,\n"
-                            "         the continuation will only be exact when an energy file is supplied\n\n",
-                            ETCOUPLTYPE(etcNOSEHOOVER),
-                            EPCOUPLTYPE(epcPARRINELLORAHMAN));
-                }
-            }
-            if (bFepState)
-            {
-                ir->fepvals->init_fep_state = init_fep_state;
-            }
-        }
-    }
-
     if (bNsteps)
     {
         fprintf(stderr, "Setting nsteps to %s\n", gmx_step_str(nsteps_req, buf));
@@ -646,7 +440,7 @@ int gmx_convert_tpr(int argc, char *argv[])
         ir->init_step = run_step;
 
         if (ftp2bSet(efNDX, NFILE, fnm) ||
-            !(bNsteps || bExtend || bUntil || bTraj))
+            !(bNsteps || bExtend || bUntil))
         {
             atoms = gmx_mtop_global_atoms(&mtop);
             get_index(&atoms, ftp2fn_null(efNDX, NFILE, fnm), 1,
index 432127302ebe5628842c5178633c6951729d0ab4..d795af9356e541250ef5f447a421b6173590e0da 100644 (file)
@@ -56,6 +56,7 @@
 #include "gromacs/gmxpreprocess/gmxcpp.h"
 #include "gromacs/linearalgebra/sparsematrix.h"
 #include "gromacs/math/vecdump.h"
+#include "gromacs/mdrunutility/mdmodules.h"
 #include "gromacs/mdtypes/forcerec.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
@@ -76,23 +77,27 @@ static void list_tpx(const char *fn, gmx_bool bShowNumbers, const char *mdpfn,
     FILE         *gp;
     int           indent, i, j, **gcount, atot;
     t_state       state;
-    t_inputrec    ir;
+    t_inputrec   *ir = nullptr;
     t_tpxheader   tpx;
     gmx_mtop_t    mtop;
     gmx_groups_t *groups;
     t_topology    top;
 
     read_tpxheader(fn, &tpx, TRUE);
-
+    gmx::MDModules mdModules;
+    if (tpx.bIr)
+    {
+        ir = mdModules.inputrec();
+    }
     read_tpx_state(fn,
-                   tpx.bIr  ? &ir : NULL,
+                   ir,
                    &state,
                    tpx.bTop ? &mtop : NULL);
 
     if (mdpfn && tpx.bIr)
     {
         gp = gmx_fio_fopen(mdpfn, "w");
-        pr_inputrec(gp, 0, NULL, &(ir), TRUE);
+        pr_inputrec(gp, 0, NULL, ir, TRUE);
         gmx_fio_fclose(gp);
     }
 
@@ -107,7 +112,7 @@ static void list_tpx(const char *fn, gmx_bool bShowNumbers, const char *mdpfn,
         {
             indent = 0;
             pr_title(stdout, indent, fn);
-            pr_inputrec(stdout, 0, "inputrec", tpx.bIr ? &(ir) : NULL, FALSE);
+            pr_inputrec(stdout, 0, "inputrec", ir, FALSE);
 
             pr_tpxheader(stdout, indent, "header", &(tpx));
 
index cc04615c90aa68ed1d6a7207be706889c496aaba..12df5df44c2d645c4c90b417d1f41001fdce5320 100644 (file)
@@ -44,6 +44,7 @@
 #include <algorithm>
 
 #include "gromacs/topology/symtab.h"
+#include "gromacs/utility/compare.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/txtdump.h"
 
@@ -326,3 +327,48 @@ void pr_atomtypes(FILE *fp, int indent, const char *title, const t_atomtypes *at
         }
     }
 }
+
+static void cmp_atom(FILE *fp, int index, const t_atom *a1, const t_atom *a2, real ftol, real abstol)
+{
+    if (a2)
+    {
+        cmp_us(fp, "atom.type", index, a1->type, a2->type);
+        cmp_us(fp, "atom.ptype", index, a1->ptype, a2->ptype);
+        cmp_int(fp, "atom.resind", index, a1->resind, a2->resind);
+        cmp_int(fp, "atom.atomnumber", index, a1->atomnumber, a2->atomnumber);
+        cmp_real(fp, "atom.m", index, a1->m, a2->m, ftol, abstol);
+        cmp_real(fp, "atom.q", index, a1->q, a2->q, ftol, abstol);
+        cmp_us(fp, "atom.typeB", index, a1->typeB, a2->typeB);
+        cmp_real(fp, "atom.mB", index, a1->mB, a2->mB, ftol, abstol);
+        cmp_real(fp, "atom.qB", index, a1->qB, a2->qB, ftol, abstol);
+    }
+    else
+    {
+        cmp_us(fp, "atom.type", index, a1->type, a1->typeB);
+        cmp_real(fp, "atom.m", index, a1->m, a1->mB, ftol, abstol);
+        cmp_real(fp, "atom.q", index, a1->q, a1->qB, ftol, abstol);
+    }
+}
+
+void cmp_atoms(FILE *fp, const t_atoms *a1, const t_atoms *a2, real ftol, real abstol)
+{
+    int i;
+
+    fprintf(fp, "comparing atoms\n");
+
+    if (a2)
+    {
+        cmp_int(fp, "atoms->nr", -1, a1->nr, a2->nr);
+        for (i = 0; (i < a1->nr); i++)
+        {
+            cmp_atom(fp, i, &(a1->atom[i]), &(a2->atom[i]), ftol, abstol);
+        }
+    }
+    else
+    {
+        for (i = 0; (i < a1->nr); i++)
+        {
+            cmp_atom(fp, i, &(a1->atom[i]), NULL, ftol, abstol);
+        }
+    }
+}
index faadaa98a3caba907454d3f66239ef0d91584d3f..e790fb478424b9cec69cee32d3bce26fe967765d 100644 (file)
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 struct t_symtab;
 
 /* The particle type */
@@ -164,8 +160,6 @@ void pr_atoms(FILE *fp, int indent, const char *title, const t_atoms *atoms,
 void pr_atomtypes(FILE *fp, int indent, const char *title,
                   const t_atomtypes *atomtypes, gmx_bool bShowNumbers);
 
-#ifdef __cplusplus
-}
-#endif
+void cmp_atoms(FILE *fp, const t_atoms *a1, const t_atoms *a2, real ftol, real abstol);
 
 #endif
index 0825ef1e667bf35cf21fe9c55fd67aec3784bc18..f1300f2f34bedbb197f7f935c10285cc48dde8a4 100644 (file)
@@ -85,14 +85,11 @@ void write_index(const char *outf, t_blocka *b, char **gnames, gmx_bool bDuplica
     /* fprintf(out,"%5d  %5d\n",b->nr,b->nra); */
     for (i = 0; (i < b->nr); i++)
     {
-        fprintf(out, "[ %s ]\n", gnames[i]);
+        fprintf(out, "[ %s ]", gnames[i]);
         for (k = 0, j = b->index[i]; j < b->index[i+1]; j++, k++)
         {
-            fprintf(out, "%4d ", b->a[j]+1);
-            if ((k % 15) == 14)
-            {
-                fprintf(out, "\n");
-            }
+            const char sep = (k % 15 == 0 ? '\n' : ' ');
+            fprintf(out, "%c%4d", sep, b->a[j]+1);
         }
         fprintf(out, "\n");
     }
@@ -103,14 +100,11 @@ void write_index(const char *outf, t_blocka *b, char **gnames, gmx_bool bDuplica
         fprintf(stderr, "Duplicating the whole system with an atom offset of %d atoms.\n", natoms);
         for (i = 0; (i < b->nr); i++)
         {
-            fprintf(out, "[ %s_copy ]\n", gnames[i]);
+            fprintf(out, "[ %s_copy ]", gnames[i]);
             for (k = 0, j = b->index[i]; j < b->index[i+1]; j++, k++)
             {
-                fprintf(out, "%4d ", b->a[j]+1 + natoms );
-                if ((k % 15) == 14)
-                {
-                    fprintf(out, "\n");
-                }
+                const char sep = (k % 15 == 0 ? '\n' : ' ');
+                fprintf(out, "%c%4d", sep, b->a[j]+1 + natoms);
             }
             fprintf(out, "\n");
         }
index c2d0f602ccce840000bd45c4c8113cf067deebca..a94f36ee5a5e80d81b97adbc96bb1111a7009d43 100644 (file)
@@ -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, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, 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.
 #include <algorithm>
 
 #include "gromacs/math/vecdump.h"
+#include "gromacs/topology/atoms.h"
+#include "gromacs/topology/idef.h"
 #include "gromacs/topology/ifunc.h"
 #include "gromacs/topology/symtab.h"
+#include "gromacs/utility/compare.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/stringutil.h"
 #include "gromacs/utility/txtdump.h"
@@ -330,3 +333,213 @@ void pr_top(FILE *fp, int indent, const char *title, const t_topology *top, gmx_
         pr_idef(fp, indent, "idef", &top->idef, bShowNumbers);
     }
 }
+
+static void cmp_ilist(FILE *fp, int ftype, const t_ilist *il1, const t_ilist *il2)
+{
+    int  i;
+    char buf[256];
+
+    fprintf(fp, "comparing ilist %s\n", interaction_function[ftype].name);
+    sprintf(buf, "%s->nr", interaction_function[ftype].name);
+    cmp_int(fp, buf, -1, il1->nr, il2->nr);
+    sprintf(buf, "%s->iatoms", interaction_function[ftype].name);
+    if (((il1->nr > 0) && (!il1->iatoms)) ||
+        ((il2->nr > 0) && (!il2->iatoms)) ||
+        ((il1->nr != il2->nr)))
+    {
+        fprintf(fp, "Comparing radically different topologies - %s is different\n",
+                buf);
+    }
+    else
+    {
+        for (i = 0; (i < il1->nr); i++)
+        {
+            cmp_int(fp, buf, i, il1->iatoms[i], il2->iatoms[i]);
+        }
+    }
+}
+
+static void cmp_iparm(FILE *fp, const char *s, t_functype ft,
+                      const t_iparams &ip1, const t_iparams &ip2, real ftol, real abstol)
+{
+    int      i;
+    gmx_bool bDiff;
+
+    bDiff = FALSE;
+    for (i = 0; i < MAXFORCEPARAM && !bDiff; i++)
+    {
+        bDiff = !equal_real(ip1.generic.buf[i], ip2.generic.buf[i], ftol, abstol);
+    }
+    if (bDiff)
+    {
+        fprintf(fp, "%s1: ", s);
+        pr_iparams(fp, ft, &ip1);
+        fprintf(fp, "%s2: ", s);
+        pr_iparams(fp, ft, &ip2);
+    }
+}
+
+static void cmp_iparm_AB(FILE *fp, const char *s, t_functype ft,
+                         const t_iparams &ip1, real ftol, real abstol)
+{
+    int      nrfpA, nrfpB, p0, i;
+    gmx_bool bDiff;
+
+    /* Normally the first parameter is perturbable */
+    p0    = 0;
+    nrfpA = interaction_function[ft].nrfpA;
+    nrfpB = interaction_function[ft].nrfpB;
+    if (ft == F_PDIHS)
+    {
+        nrfpB = 2;
+    }
+    else if (interaction_function[ft].flags & IF_TABULATED)
+    {
+        /* For tabulated interactions only the second parameter is perturbable */
+        p0    = 1;
+        nrfpB = 1;
+    }
+    bDiff = FALSE;
+    for (i = 0; i < nrfpB && !bDiff; i++)
+    {
+        bDiff = !equal_real(ip1.generic.buf[p0+i], ip1.generic.buf[nrfpA+i], ftol, abstol);
+    }
+    if (bDiff)
+    {
+        fprintf(fp, "%s: ", s);
+        pr_iparams(fp, ft, &ip1);
+    }
+}
+
+static void cmp_cmap(FILE *fp, const gmx_cmap_t *cmap1, const gmx_cmap_t *cmap2, real ftol, real abstol)
+{
+    cmp_int(fp, "cmap ngrid", -1, cmap1->ngrid, cmap2->ngrid);
+    cmp_int(fp, "cmap grid_spacing", -1, cmap1->grid_spacing, cmap2->grid_spacing);
+    if (cmap1->ngrid == cmap2->ngrid &&
+        cmap1->grid_spacing == cmap2->grid_spacing)
+    {
+        int g;
+
+        for (g = 0; g < cmap1->ngrid; g++)
+        {
+            int i;
+
+            fprintf(fp, "comparing cmap %d\n", g);
+
+            for (i = 0; i < 4*cmap1->grid_spacing*cmap1->grid_spacing; i++)
+            {
+                cmp_real(fp, "", i, cmap1->cmapdata[g].cmap[i], cmap2->cmapdata[g].cmap[i], ftol, abstol);
+            }
+        }
+    }
+}
+
+static void cmp_idef(FILE *fp, const t_idef *id1, const t_idef *id2, real ftol, real abstol)
+{
+    int  i;
+    char buf1[64], buf2[64];
+
+    fprintf(fp, "comparing idef\n");
+    if (id2)
+    {
+        cmp_int(fp, "idef->ntypes", -1, id1->ntypes, id2->ntypes);
+        cmp_int(fp, "idef->atnr",  -1, id1->atnr, id2->atnr);
+        for (i = 0; (i < std::min(id1->ntypes, id2->ntypes)); i++)
+        {
+            sprintf(buf1, "idef->functype[%d]", i);
+            sprintf(buf2, "idef->iparam[%d]", i);
+            cmp_int(fp, buf1, i, (int)id1->functype[i], (int)id2->functype[i]);
+            cmp_iparm(fp, buf2, id1->functype[i],
+                      id1->iparams[i], id2->iparams[i], ftol, abstol);
+        }
+        cmp_real(fp, "fudgeQQ", -1, id1->fudgeQQ, id2->fudgeQQ, ftol, abstol);
+        cmp_cmap(fp, &id1->cmap_grid, &id2->cmap_grid, ftol, abstol);
+        for (i = 0; (i < F_NRE); i++)
+        {
+            cmp_ilist(fp, i, &(id1->il[i]), &(id2->il[i]));
+        }
+    }
+    else
+    {
+        for (i = 0; (i < id1->ntypes); i++)
+        {
+            cmp_iparm_AB(fp, "idef->iparam", id1->functype[i], id1->iparams[i], ftol, abstol);
+        }
+    }
+}
+
+static void cmp_block(FILE *fp, const t_block *b1, const t_block *b2, const char *s)
+{
+    char buf[32];
+
+    fprintf(fp, "comparing block %s\n", s);
+    sprintf(buf, "%s.nr", s);
+    cmp_int(fp, buf, -1, b1->nr, b2->nr);
+}
+
+static void cmp_blocka(FILE *fp, const t_blocka *b1, const t_blocka *b2, const char *s)
+{
+    char buf[32];
+
+    fprintf(fp, "comparing blocka %s\n", s);
+    sprintf(buf, "%s.nr", s);
+    cmp_int(fp, buf, -1, b1->nr, b2->nr);
+    sprintf(buf, "%s.nra", s);
+    cmp_int(fp, buf, -1, b1->nra, b2->nra);
+}
+
+void cmp_top(FILE *fp, const t_topology *t1, const t_topology *t2, real ftol, real abstol)
+{
+    fprintf(fp, "comparing top\n");
+    if (t2)
+    {
+        cmp_idef(fp, &(t1->idef), &(t2->idef), ftol, abstol);
+        cmp_atoms(fp, &(t1->atoms), &(t2->atoms), ftol, abstol);
+        cmp_block(fp, &t1->cgs, &t2->cgs, "cgs");
+        cmp_block(fp, &t1->mols, &t2->mols, "mols");
+        cmp_bool(fp, "bIntermolecularInteractions", -1, t1->bIntermolecularInteractions, t2->bIntermolecularInteractions);
+        cmp_blocka(fp, &t1->excls, &t2->excls, "excls");
+    }
+    else
+    {
+        cmp_idef(fp, &(t1->idef), NULL, ftol, abstol);
+        cmp_atoms(fp, &(t1->atoms), NULL, ftol, abstol);
+    }
+}
+
+void cmp_groups(FILE *fp, const gmx_groups_t *g0, const gmx_groups_t *g1,
+                int natoms0, int natoms1)
+{
+    int  i, j;
+    char buf[32];
+
+    fprintf(fp, "comparing groups\n");
+
+    for (i = 0; i < egcNR; i++)
+    {
+        sprintf(buf, "grps[%d].nr", i);
+        cmp_int(fp, buf, -1, g0->grps[i].nr, g1->grps[i].nr);
+        if (g0->grps[i].nr == g1->grps[i].nr)
+        {
+            for (j = 0; j < g0->grps[i].nr; j++)
+            {
+                sprintf(buf, "grps[%d].name[%d]", i, j);
+                cmp_str(fp, buf, -1,
+                        *g0->grpname[g0->grps[i].nm_ind[j]],
+                        *g1->grpname[g1->grps[i].nm_ind[j]]);
+            }
+        }
+        cmp_int(fp, "ngrpnr", i, g0->ngrpnr[i], g1->ngrpnr[i]);
+        if (g0->ngrpnr[i] == g1->ngrpnr[i] && natoms0 == natoms1 &&
+            (g0->grpnr[i] != NULL || g1->grpnr[i] != NULL))
+        {
+            for (j = 0; j < natoms0; j++)
+            {
+                cmp_int(fp, gtypes[i], j, ggrpnr(g0, i, j), ggrpnr(g1, i, j));
+            }
+        }
+    }
+    /* We have compared the names in the groups lists,
+     * so we can skip the grpname list comparison.
+     */
+}
index 5d3426ccaffa827e17fee744425b31564e3f7b91..ec16e7cda7a999393ab3763b0d9f6cc928249818 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2011,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2011,2014,2015,2016, 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.
 #include "gromacs/topology/idef.h"
 #include "gromacs/topology/symtab.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 enum {
     egcTC,    egcENER,   egcACC, egcFREEZE,
     egcUser1, egcUser2,  egcVCM, egcCompressedX,
@@ -154,8 +150,8 @@ void pr_mtop(FILE *fp, int indent, const char *title, const gmx_mtop_t *mtop,
              gmx_bool bShowNumbers);
 void pr_top(FILE *fp, int indent, const char *title, const t_topology *top, gmx_bool bShowNumbers);
 
-#ifdef __cplusplus
-}
-#endif
+void cmp_top(FILE *fp, const t_topology *t1, const t_topology *t2, real ftol, real abstol);
+void cmp_groups(FILE *fp, const gmx_groups_t *g0, const gmx_groups_t *g1,
+                int natoms0, int natoms1);
 
 #endif
index 3bcbd3ced459f4c8407962817d14c524b37f593b..e6f935930714e163a23c2dab294c4eb239263bbc 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2015, by the GROMACS development team, led by
+# Copyright (c) 2015,2016, 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.
 
+gmx_add_libgromacs_sources(
+    trajectoryframe.cpp
+    )
+
 gmx_install_headers(
     energy.h
     trajectoryframe.h
     )
-
diff --git a/src/gromacs/trajectory/trajectoryframe.cpp b/src/gromacs/trajectory/trajectoryframe.cpp
new file mode 100644 (file)
index 0000000..c26d39a
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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 "gmxpre.h"
+
+#include "trajectoryframe.h"
+
+#include <cstdio>
+
+#include <algorithm>
+
+#include "gromacs/math/veccompare.h"
+#include "gromacs/topology/atoms.h"
+#include "gromacs/utility/compare.h"
+
+void comp_frame(FILE *fp, t_trxframe *fr1, t_trxframe *fr2,
+                gmx_bool bRMSD, real ftol, real abstol)
+{
+    fprintf(fp, "\n");
+    cmp_int(fp, "not_ok", -1, fr1->not_ok, fr2->not_ok);
+    cmp_int(fp, "natoms", -1, fr1->natoms, fr2->natoms);
+    if (cmp_bool(fp, "bTitle", -1, fr1->bTitle, fr2->bTitle))
+    {
+        cmp_str(fp, "title", -1, fr1->title, fr2->title);
+    }
+    if (cmp_bool(fp, "bStep", -1, fr1->bStep, fr2->bStep))
+    {
+        cmp_int(fp, "step", -1, fr1->step, fr2->step);
+    }
+    cmp_int(fp, "step", -1, fr1->step, fr2->step);
+    if (cmp_bool(fp, "bTime", -1, fr1->bTime, fr2->bTime))
+    {
+        cmp_real(fp, "time", -1, fr1->time, fr2->time, ftol, abstol);
+    }
+    if (cmp_bool(fp, "bLambda", -1, fr1->bLambda, fr2->bLambda))
+    {
+        cmp_real(fp, "lambda", -1, fr1->lambda, fr2->lambda, ftol, abstol);
+    }
+    if (cmp_bool(fp, "bAtoms", -1, fr1->bAtoms, fr2->bAtoms))
+    {
+        cmp_atoms(fp, fr1->atoms, fr2->atoms, ftol, abstol);
+    }
+    if (cmp_bool(fp, "bPrec", -1, fr1->bPrec, fr2->bPrec))
+    {
+        cmp_real(fp, "prec", -1, fr1->prec, fr2->prec, ftol, abstol);
+    }
+    if (cmp_bool(fp, "bX", -1, fr1->bX, fr2->bX))
+    {
+        cmp_rvecs(fp, "x", std::min(fr1->natoms, fr2->natoms), fr1->x, fr2->x, bRMSD, ftol, abstol);
+    }
+    if (cmp_bool(fp, "bV", -1, fr1->bV, fr2->bV))
+    {
+        cmp_rvecs(fp, "v", std::min(fr1->natoms, fr2->natoms), fr1->v, fr2->v, bRMSD, ftol, abstol);
+    }
+    if (cmp_bool(fp, "bF", -1, fr1->bF, fr2->bF))
+    {
+        cmp_rvecs(fp, "f", std::min(fr1->natoms, fr2->natoms), fr1->f, fr2->f, bRMSD, ftol, abstol);
+    }
+    if (cmp_bool(fp, "bBox", -1, fr1->bBox, fr2->bBox))
+    {
+        cmp_rvecs(fp, "box", 3, fr1->box, fr2->box, FALSE, ftol, abstol);
+    }
+}
index f329947fe6b987731d592bb116722865b64efdec..9b65402684304e10869a5996a1d4ac28926539de 100644 (file)
  * Do not try to use a pointer when its gmx_bool is FALSE, as memory might
  * not be allocated.
  */
-
 #ifndef GMX_TRAJECTORY_TRX_H
 #define GMX_TRAJECTORY_TRX_H
 
+#include <cstdio>
+
 #include "gromacs/math/vectypes.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
@@ -82,4 +83,7 @@ typedef struct t_trxframe
     int            *index;     /* atom indices of contained coordinates */
 } t_trxframe;
 
+void comp_frame(FILE *fp, t_trxframe *fr1, t_trxframe *fr2,
+                gmx_bool bRMSD, real ftol, real abstol);
+
 #endif
index fab17441dd41c7107b98fd58a0a5314703d86130..11b2fc2b14b3be6d2d58671a4dfb5a88848c6156 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, 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.
@@ -350,7 +350,7 @@ void TrajectoryAnalysisModule::registerBasicDataset(AbstractAnalysisData *data,
     GMX_RELEASE_ASSERT(impl_->datasets_.find(name) == impl_->datasets_.end(),
                        "Duplicate data set name registered");
     impl_->datasets_[name] = data;
-    impl_->datasetNames_.push_back(name);
+    impl_->datasetNames_.emplace_back(name);
 }
 
 
index 44b3db90f8d63a8d4706f4ff5036ec60e426b1e0..8a9f349193f408711bbd17bac9f300f5cfd25d32 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016, 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.
@@ -168,7 +168,7 @@ void IndexFileWriterModule::addGroup(const std::string &name, bool bDynamic)
 {
     std::string newName(name);
     std::replace(newName.begin(), newName.end(), ' ', '_');
-    groups_.push_back(GroupInfo(newName, bDynamic));
+    groups_.emplace_back(newName, bDynamic);
 }
 
 
index 30dc1a344eedc16ce8d74c6b7caed2c846827a52..f7607f6264913e1a20bf65873fb26fd2de0a8d9a 100644 (file)
@@ -88,7 +88,7 @@ class SurfaceAreaTest : public ::testing::Test
             {
                 index_.push_back(x_.size());
             }
-            x_.push_back(gmx::RVec(x, y, z));
+            x_.emplace_back(x, y, z);
             radius_.push_back(radius);
         }
 
index 0602323c3231fa225c02dae9c338543a3491722b..609b906cbeaa7b23473ff8a0881e9f39e659338c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, 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.
  * managing directories and files.
  * The fate of this header depends on what is decided in Redmine issue #950.
  *
+ * <H3>Logging</H3>
+ *
+ * The headers logger.h and loggerbuilder.h provide interfaces and classes for
+ * writing log files (or logging to other targets).  See \ref page_logging for
+ * an overview.
+ *
  * \endif
  *
  * <H3>Implementation helpers</H3>
  *
  * \if libapi
  *
+ * The header strconvert.h declares string parsing routines.
+ *
  * The header gmxmpi.h abstracts away the mechanism of including either MPI or
  * thread-MPI headers depending on compilation options.
  * Similarly, gmxomp.h removes the need to use conditional compilation for code
index ccf6e5e9d04202aed0ac46cf265c7b1dec1b6b2a..e62282a02e127b96ba77cff4934047b6a9867623 100644 (file)
@@ -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
  * 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.
@@ -231,11 +231,6 @@ class ArrayRef
          *
          * This constructor is not explicit to allow directly passing
          * a C array to a function that takes an ArrayRef parameter.
-         *
-         * xlc on BG/Q compiles wrong code if the C array is a struct
-         * field, unless value_type is char or unsigned char. There's
-         * no good way to assert on this before C++11 (which that
-         * compiler will never support).
          */
         template <size_t count>
         ArrayRef(value_type (&array)[count])
@@ -411,6 +406,10 @@ class ConstArrayRef
          * template type.  It is not explicit to enable that usage.
          */
         ConstArrayRef(const EmptyArrayRef &) : begin_(NULL), end_(NULL) {}
+        /*! \brief
+         * Constructs a const reference from a non-const reference.
+         */
+        ConstArrayRef(const ArrayRef<T> &other) : begin_(other.begin()), end_(other.end()) {}
         /*! \brief
          * Constructs a reference to a particular range.
          *
@@ -460,11 +459,6 @@ class ConstArrayRef
          *
          * This constructor is not explicit to allow directly passing
          * a C array to a function that takes a ConstArrayRef parameter.
-         *
-         * xlc on BG/Q compiles wrong code if the C array is a struct
-         * field, unless value_type is char or unsigned char. There's
-         * no good way to assert on this before C++11 (which that
-         * compiler will never support).
          */
         template <size_t count>
         ConstArrayRef(const value_type (&array)[count])
index 47a820a04588e8650ed5f7a9ece8ee3dc757d02f..509b8747a1af9f69299b78566395ed683cff91a9 100644 (file)
@@ -255,18 +255,10 @@ typedef uint64_t gmx_uint64_t;
    \endcode
  */
 
-#if (defined(__GNUC__) && !defined(__clang__)) || defined(__ibmxl__) || defined(__xlC__) || defined(__PATHCC__)
-// Gcc-4.6.4 does not support alignas, but both gcc, pathscale and xlc
-// support the standard GNU alignment attributes. PGI also sets __GNUC__ now,
-// and mostly supports it. clang 3.2 does not support the GCC alignment attribute.
-#    define GMX_ALIGNED(type, alignment) __attribute__ ((aligned(alignment*sizeof(type)))) type
-#else
-// If nothing else works we rely on C++11. This will for instance work for MSVC2015 and later.
+// We rely on C++11. This will for instance work for MSVC2015 and later.
 // If you get an error here, find out what attribute to use to get your compiler to align
 // data properly and add it as a case.
-#    define GMX_ALIGNED(type, alignment) alignas(alignment*alignof(type)) type
-#endif
-
+#define GMX_ALIGNED(type, alignment) alignas(alignment*sizeof(type)) type
 
 /*! \brief
  * Macro to explicitly ignore an unused value.
index 6dceffc528b3832a1e67c714e8438d52caf5438d..3714313fe6cd5dea3dc9172ea09df8c7fc4d531c 100644 (file)
@@ -52,6 +52,7 @@
 namespace gmx
 {
 
+#ifdef DOXYGEN
 /*! \brief
  * Macro to declare a class non-copyable and non-assignable.
  *
@@ -59,9 +60,12 @@ namespace gmx
  *
  * \ingroup module_utility
  */
+#define GMX_DISALLOW_COPY_AND_ASSIGN(ClassName)
+#else
 #define GMX_DISALLOW_COPY_AND_ASSIGN(ClassName) \
     ClassName &operator=(const ClassName &) = delete;   \
     ClassName(const ClassName &)            = delete
+#endif
 /*! \brief
  * Macro to declare a class non-assignable.
  *
diff --git a/src/gromacs/utility/compare.cpp b/src/gromacs/utility/compare.cpp
new file mode 100644 (file)
index 0000000..95e9fce
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * 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
+ * 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.
+ */
+/* This file is completely threadsafe - keep it that way! */
+
+#include "gmxpre.h"
+
+#include "compare.h"
+
+#include <cmath>
+#include <cstdio>
+#include <cstring>
+
+#include "gromacs/utility/stringutil.h"
+
+void cmp_int(FILE *fp, const char *s, int index, int i1, int i2)
+{
+    if (i1 != i2)
+    {
+        if (index != -1)
+        {
+            fprintf(fp, "%s[%d] (%d - %d)\n", s, index, i1, i2);
+        }
+        else
+        {
+            fprintf(fp, "%s (%d - %d)\n", s, i1, i2);
+        }
+    }
+}
+
+void cmp_int64(FILE *fp, const char *s, gmx_int64_t i1, gmx_int64_t i2)
+{
+    if (i1 != i2)
+    {
+        fprintf(fp, "%s (", s);
+        fprintf(fp, "%" GMX_PRId64, i1);
+        fprintf(fp, " - ");
+        fprintf(fp, "%" GMX_PRId64, i2);
+        fprintf(fp, ")\n");
+    }
+}
+
+void cmp_us(FILE *fp, const char *s, int index, unsigned short i1, unsigned short i2)
+{
+    if (i1 != i2)
+    {
+        if (index != -1)
+        {
+            fprintf(fp, "%s[%d] (%hu - %hu)\n", s, index, i1, i2);
+        }
+        else
+        {
+            fprintf(fp, "%s (%hu - %hu)\n", s, i1, i2);
+        }
+    }
+}
+
+void cmp_uc(FILE *fp, const char *s, int index, unsigned char i1, unsigned char i2)
+{
+    if (i1 != i2)
+    {
+        if (index != -1)
+        {
+            fprintf(fp, "%s[%d] (%d - %d)\n", s, index, i1, i2);
+        }
+        else
+        {
+            fprintf(fp, "%s (%d - %d)\n", s, i1, i2);
+        }
+    }
+}
+
+gmx_bool cmp_bool(FILE *fp, const char *s, int index, gmx_bool b1, gmx_bool b2)
+{
+    if (b1)
+    {
+        b1 = 1;
+    }
+    else
+    {
+        b1 = 0;
+    }
+    if (b2)
+    {
+        b2 = 1;
+    }
+    else
+    {
+        b2 = 0;
+    }
+    if (b1 != b2)
+    {
+        if (index != -1)
+        {
+            fprintf(fp, "%s[%d] (%s - %s)\n", s, index,
+                    gmx::boolToString(b1), gmx::boolToString(b2));
+        }
+        else
+        {
+            fprintf(fp, "%s (%s - %s)\n", s,
+                    gmx::boolToString(b1), gmx::boolToString(b2));
+        }
+    }
+    return b1 && b2;
+}
+
+void cmp_str(FILE *fp, const char *s, int index, const char *s1, const char *s2)
+{
+    if (std::strcmp(s1, s2) != 0)
+    {
+        if (index != -1)
+        {
+            fprintf(fp, "%s[%d] (%s - %s)\n", s, index, s1, s2);
+        }
+        else
+        {
+            fprintf(fp, "%s (%s - %s)\n", s, s1, s2);
+        }
+    }
+}
+
+gmx_bool equal_real(real i1, real i2, real ftol, real abstol)
+{
+    return ( ( 2*fabs(i1 - i2) <= (fabs(i1) + fabs(i2))*ftol ) || fabs(i1-i2) <= abstol );
+}
+
+static gmx_bool equal_float(float i1, float i2, float ftol, float abstol)
+{
+    return ( ( 2*fabs(i1 - i2) <= (fabs(i1) + fabs(i2))*ftol ) || fabs(i1-i2) <= abstol );
+}
+
+static gmx_bool equal_double(double i1, double i2, real ftol, real abstol)
+{
+    return ( ( 2*fabs(i1 - i2) <= (fabs(i1) + fabs(i2))*ftol ) || fabs(i1-i2) <= abstol );
+}
+
+void
+cmp_real(FILE *fp, const char *s, int index, real i1, real i2, real ftol, real abstol)
+{
+    if (!equal_real(i1, i2, ftol, abstol))
+    {
+        if (index != -1)
+        {
+            fprintf(fp, "%s[%2d] (%e - %e)\n", s, index, i1, i2);
+        }
+        else
+        {
+            fprintf(fp, "%s (%e - %e)\n", s, i1, i2);
+        }
+    }
+}
+
+void
+cmp_float(FILE *fp, const char *s, int index, float i1, float i2, float ftol, float abstol)
+{
+    if (!equal_float(i1, i2, ftol, abstol))
+    {
+        if (index != -1)
+        {
+            fprintf(fp, "%s[%2d] (%e - %e)\n", s, index, i1, i2);
+        }
+        else
+        {
+            fprintf(fp, "%s (%e - %e)\n", s, i1, i2);
+        }
+    }
+}
+
+void
+cmp_double(FILE *fp, const char *s, int index, double i1, double i2, double ftol, double abstol)
+{
+    if (!equal_double(i1, i2, ftol, abstol))
+    {
+        if (index != -1)
+        {
+            fprintf(fp, "%s[%2d] (%16.9e - %16.9e)\n", s, index, i1, i2);
+        }
+        else
+        {
+            fprintf(fp, "%s (%16.9e - %16.9e)\n", s, i1, i2);
+        }
+    }
+}
diff --git a/src/gromacs/utility/compare.h b/src/gromacs/utility/compare.h
new file mode 100644 (file)
index 0000000..51e1f67
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * 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
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Utilities for comparing data structures (for gmx check).
+ *
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_COMPARE_H
+#define GMX_UTILITY_COMPARE_H
+
+#include <cstdio>
+
+#include "gromacs/utility/basedefinitions.h"
+#include "gromacs/utility/real.h"
+
+//! Compares two real values for equality.
+gmx_bool equal_real(real i1, real i2, real ftol, real abstol);
+
+//! Compares two integers and prints differences.
+void cmp_int(FILE *fp, const char *s, int index, int i1, int i2);
+
+//! Compares two 64-bit integers and prints differences.
+void cmp_int64(FILE *fp, const char *s, gmx_int64_t i1, gmx_int64_t i2);
+
+//! Compares two unsigned short values and prints differences.
+void cmp_us(FILE *fp, const char *s, int index, unsigned short i1, unsigned short i2);
+
+//! Compares two unsigned char values and prints differences.
+void cmp_uc(FILE *fp, const char *s, int index, unsigned char i1, unsigned char i2);
+
+//! Compares two boolean values and prints differences, and returns whether both are true.
+gmx_bool cmp_bool(FILE *fp, const char *s, int index, gmx_bool b1, gmx_bool b2);
+
+//! Compares two strings and prints differences.
+void cmp_str(FILE *fp, const char *s, int index, const char *s1, const char *s2);
+
+//! Compares two reals and prints differences.
+void cmp_real(FILE *fp, const char *s, int index, real i1, real i2, real ftol, real abstol);
+
+//! Compares two floats and prints differences.
+void cmp_float(FILE *fp, const char *s, int index, float i1, float i2, float ftol, float abstol);
+
+//! Compares two doubles and prints differences.
+void cmp_double(FILE *fp, const char *s, int index, double i1, double i2, double ftol, double abstol);
+
+#endif
index af7020e9395e129e74add506c511d3ba9a339108..598997ed33a020298abae4df8aba2853daa137a1 100644 (file)
@@ -227,7 +227,7 @@ DataFileFinder::enumerateFiles(const DataFileOptions &options) const
                         ".", options.filename_, false);
         for (i = files.begin(); i != files.end(); ++i)
         {
-            result.push_back(DataFileInfo(".", *i, false));
+            result.emplace_back(".", *i, false);
         }
     }
     if (impl_ != nullptr)
@@ -240,7 +240,7 @@ DataFileFinder::enumerateFiles(const DataFileOptions &options) const
                             j->c_str(), options.filename_, false);
             for (i = files.begin(); i != files.end(); ++i)
             {
-                result.push_back(DataFileInfo(*j, *i, false));
+                result.emplace_back(*j, *i, false);
             }
         }
     }
@@ -252,7 +252,7 @@ DataFileFinder::enumerateFiles(const DataFileOptions &options) const
                         defaultPath.c_str(), options.filename_, false);
         for (i = files.begin(); i != files.end(); ++i)
         {
-            result.push_back(DataFileInfo(defaultPath, *i, true));
+            result.emplace_back(defaultPath, *i, true);
         }
     }
     if (result.empty() && options.bThrow_)
index e093b3692a2fcd674a30610f257cfe4a80913aaa..eb2942a1f4e8bbfe0538d7f8a1edcc0a80d8e390 100644 (file)
@@ -34,7 +34,7 @@
  */
 /*! \libinternal \file
  * \brief
- * Wraps <mpi.h> usage in Gromacs.
+ * Wraps mpi.h usage in Gromacs.
  *
  * This header wraps the MPI header <mpi.h>, and should be included instead of
  * that one.  It abstracts away the case that depending on compilation
diff --git a/src/gromacs/utility/keyvaluetree.h b/src/gromacs/utility/keyvaluetree.h
new file mode 100644 (file)
index 0000000..6dd0c0a
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares a data structure for JSON-like structured key-value mapping.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_KEYVALUETREE_H
+#define GMX_UTILITY_KEYVALUETREE_H
+
+#include <algorithm>
+#include <functional>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "gromacs/utility/variant.h"
+
+namespace gmx
+{
+
+class KeyValueTreeArray;
+class KeyValueTreeObject;
+
+class KeyValueTreeValue
+{
+    public:
+        bool isArray() const;
+        bool isObject() const;
+
+        const KeyValueTreeArray  &asArray() const;
+        const KeyValueTreeObject &asObject() const;
+
+        const Variant            &asVariant() const { return value_; }
+
+    private:
+        explicit KeyValueTreeValue(Variant &&value) : value_(std::move(value)) {}
+
+        KeyValueTreeArray &asArray();
+        KeyValueTreeObject &asObject();
+
+        Variant             value_;
+
+        friend class KeyValueTreeBuilder;
+        friend class KeyValueTreeObjectBuilder;
+        friend class KeyValueTreeValueBuilder;
+};
+
+class KeyValueTreeArray
+{
+    public:
+        bool isObjectArray() const
+        {
+            return std::all_of(values_.begin(), values_.end(),
+                               std::mem_fn(&KeyValueTreeValue::isObject));
+        }
+
+        const std::vector<KeyValueTreeValue> &values() const { return values_; }
+
+    private:
+        std::vector<KeyValueTreeValue> values_;
+
+        friend class KeyValueTreeArrayBuilderBase;
+};
+
+class KeyValueTreeProperty
+{
+    public:
+        const std::string &key() const { return value_->first; }
+        const KeyValueTreeValue &value() const { return value_->second; }
+
+    private:
+        typedef std::map<std::string, KeyValueTreeValue>::const_iterator
+            IteratorType;
+
+        explicit KeyValueTreeProperty(IteratorType value) : value_(value) {}
+
+        IteratorType value_;
+
+        friend class KeyValueTreeObject;
+};
+
+class KeyValueTreeObject
+{
+    public:
+        KeyValueTreeObject() = default;
+        KeyValueTreeObject(const KeyValueTreeObject &other)
+        {
+            for (const auto &value : other.values_)
+            {
+                auto iter = valueMap_.insert(std::make_pair(value.key(), value.value())).first;
+                values_.push_back(KeyValueTreeProperty(iter));
+            }
+        }
+        KeyValueTreeObject &operator=(KeyValueTreeObject &other)
+        {
+            KeyValueTreeObject tmp(other);
+            std::swap(tmp.valueMap_, valueMap_);
+            std::swap(tmp.values_, values_);
+            return *this;
+        }
+        KeyValueTreeObject(KeyValueTreeObject &&)            = default;
+        KeyValueTreeObject &operator=(KeyValueTreeObject &&) = default;
+
+        const std::vector<KeyValueTreeProperty> &properties() const { return values_; }
+
+        bool keyExists(const std::string &key) const
+        {
+            return valueMap_.find(key) != valueMap_.end();
+        }
+        const KeyValueTreeValue &operator[](const std::string &key) const
+        {
+            return valueMap_.at(key);
+        }
+
+    private:
+        KeyValueTreeValue &operator[](const std::string &key)
+        {
+            return valueMap_.at(key);
+        }
+        std::map<std::string, KeyValueTreeValue>::iterator
+        addProperty(const std::string &key, KeyValueTreeValue &&value)
+        {
+            values_.reserve(values_.size() + 1);
+            auto iter = valueMap_.insert(std::make_pair(key, std::move(value))).first;
+            values_.push_back(KeyValueTreeProperty(iter));
+            return iter;
+        }
+
+        std::map<std::string, KeyValueTreeValue> valueMap_;
+        std::vector<KeyValueTreeProperty>        values_;
+
+        friend class KeyValueTreeObjectBuilder;
+};
+
+/********************************************************************
+ * Inline functions that could not be declared within the classes
+ */
+
+inline bool KeyValueTreeValue::isArray() const
+{
+    return value_.isType<KeyValueTreeArray>();
+}
+inline bool KeyValueTreeValue::isObject() const
+{
+    return value_.isType<KeyValueTreeObject>();
+}
+inline const KeyValueTreeArray &KeyValueTreeValue::asArray() const
+{
+    return value_.cast<KeyValueTreeArray>();
+}
+inline const KeyValueTreeObject &KeyValueTreeValue::asObject() const
+{
+    return value_.cast<KeyValueTreeObject>();
+}
+inline KeyValueTreeArray &KeyValueTreeValue::asArray()
+{
+    return value_.castRef<KeyValueTreeArray>();
+}
+inline KeyValueTreeObject &KeyValueTreeValue::asObject()
+{
+    return value_.castRef<KeyValueTreeObject>();
+}
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/utility/keyvaluetreebuilder.h b/src/gromacs/utility/keyvaluetreebuilder.h
new file mode 100644 (file)
index 0000000..94cd660
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares classes for building the data structures in keyvaluetree.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_KEYVALUETREEBUILDER_H
+#define GMX_UTILITY_KEYVALUETREEBUILDER_H
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "gromacs/utility/keyvaluetree.h"
+#include "gromacs/utility/variant.h"
+
+namespace gmx
+{
+
+class KeyValueTreeObjectBuilder;
+
+class KeyValueTreeBuilder
+{
+    public:
+        KeyValueTreeObjectBuilder rootObject();
+
+        KeyValueTreeObject build() { return std::move(root_); }
+
+    private:
+        template <typename T>
+        static KeyValueTreeValue createValue(const T &value)
+        {
+            return KeyValueTreeValue(Variant::create<T>(value));
+        }
+        template <typename T>
+        static KeyValueTreeValue createValue()
+        {
+            return KeyValueTreeValue(Variant::create<T>(T()));
+        }
+
+        KeyValueTreeObject root_;
+
+        friend class KeyValueTreeObjectArrayBuilder;
+        friend class KeyValueTreeObjectBuilder;
+        template <typename T>
+        friend class KeyValueTreeUniformArrayBuilder;
+};
+
+class KeyValueTreeValueBuilder
+{
+    public:
+        template <typename T>
+        void setValue(const T &value)
+        {
+            value_ = Variant::create<T>(value);
+        }
+        void setVariantValue(Variant &&value)
+        {
+            value_ = std::move(value);
+        }
+        KeyValueTreeObjectBuilder createObject();
+
+        KeyValueTreeValue build() { return KeyValueTreeValue(std::move(value_)); }
+
+    private:
+        Variant value_;
+};
+
+class KeyValueTreeArrayBuilderBase
+{
+    protected:
+        explicit KeyValueTreeArrayBuilderBase(KeyValueTreeArray *array)
+            : array_(array)
+        {
+        }
+
+        KeyValueTreeValue &addRawValue(KeyValueTreeValue &&value)
+        {
+            array_->values_.push_back(std::move(value));
+            return array_->values_.back();
+        }
+
+    private:
+        KeyValueTreeArray *array_;
+};
+
+template <typename T>
+class KeyValueTreeUniformArrayBuilder : public KeyValueTreeArrayBuilderBase
+{
+    public:
+        void addValue(const T &value)
+        {
+            addRawValue(KeyValueTreeBuilder::createValue<T>(value));
+        }
+
+    private:
+        explicit KeyValueTreeUniformArrayBuilder(KeyValueTreeArray *array)
+            : KeyValueTreeArrayBuilderBase(array)
+        {
+        }
+
+        friend class KeyValueTreeObjectBuilder;
+};
+
+class KeyValueTreeObjectArrayBuilder : public KeyValueTreeArrayBuilderBase
+{
+    public:
+        KeyValueTreeObjectBuilder addObject();
+
+    private:
+        explicit KeyValueTreeObjectArrayBuilder(KeyValueTreeArray *array)
+            : KeyValueTreeArrayBuilderBase(array)
+        {
+        }
+
+        friend class KeyValueTreeObjectBuilder;
+};
+
+class KeyValueTreeObjectBuilder
+{
+    public:
+        void addRawValue(const std::string &key, KeyValueTreeValue &&value)
+        {
+            object_->addProperty(key, std::move(value));
+        }
+        template <typename T>
+        void addValue(const std::string &key, const T &value)
+        {
+            addRawValue(key, KeyValueTreeBuilder::createValue<T>(value));
+        }
+        KeyValueTreeObjectBuilder addObject(const std::string &key)
+        {
+            auto iter = object_->addProperty(key, KeyValueTreeBuilder::createValue<KeyValueTreeObject>());
+            return KeyValueTreeObjectBuilder(&iter->second);
+        }
+        template <typename T>
+        KeyValueTreeUniformArrayBuilder<T> addUniformArray(const std::string &key)
+        {
+            auto iter = object_->addProperty(key, KeyValueTreeBuilder::createValue<KeyValueTreeArray>());
+            return KeyValueTreeUniformArrayBuilder<T>(&iter->second.asArray());
+        }
+        KeyValueTreeObjectArrayBuilder addObjectArray(const std::string &key)
+        {
+            auto iter = object_->addProperty(key, KeyValueTreeBuilder::createValue<KeyValueTreeArray>());
+            return KeyValueTreeObjectArrayBuilder(&iter->second.asArray());
+        }
+        void mergeObject(KeyValueTreeValue &&value)
+        {
+            KeyValueTreeObject &obj = value.asObject();
+            for (auto &prop : obj.valueMap_)
+            {
+                addRawValue(prop.first, std::move(prop.second));
+            }
+        }
+
+        bool keyExists(const std::string &key) const { return object_->keyExists(key); }
+        KeyValueTreeObjectBuilder getObject(const std::string &key) const
+        {
+            return KeyValueTreeObjectBuilder(&(*object_)[key].asObject());
+        }
+
+    private:
+        explicit KeyValueTreeObjectBuilder(KeyValueTreeObject *object)
+            : object_(object)
+        {
+        }
+        explicit KeyValueTreeObjectBuilder(KeyValueTreeValue *value)
+            : object_(&value->asObject())
+        {
+        }
+
+        KeyValueTreeObject *object_;
+
+        friend class KeyValueTreeBuilder;
+        friend class KeyValueTreeValueBuilder;
+        friend class KeyValueTreeObjectArrayBuilder;
+};
+
+/********************************************************************
+ * Inline functions that could not be declared within the classes
+ */
+
+inline KeyValueTreeObjectBuilder KeyValueTreeBuilder::rootObject()
+{
+    return KeyValueTreeObjectBuilder(&root_);
+}
+
+inline KeyValueTreeObjectBuilder KeyValueTreeValueBuilder::createObject()
+{
+    value_ = Variant::create<KeyValueTreeObject>(KeyValueTreeObject());
+    return KeyValueTreeObjectBuilder(&value_.castRef<KeyValueTreeObject>());
+}
+
+inline KeyValueTreeObjectBuilder KeyValueTreeObjectArrayBuilder::addObject()
+{
+    auto &value = addRawValue(KeyValueTreeBuilder::createValue<KeyValueTreeObject>());
+    return KeyValueTreeObjectBuilder(&value);
+}
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/utility/keyvaluetreetransform.cpp b/src/gromacs/utility/keyvaluetreetransform.cpp
new file mode 100644 (file)
index 0000000..00eb73c
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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 "gmxpre.h"
+
+#include "keyvaluetreetransform.h"
+
+#include <exception>
+#include <vector>
+
+#include "gromacs/utility/keyvaluetreebuilder.h"
+#include "gromacs/utility/stringutil.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * IKeyValueTreeTransformRules
+ */
+
+IKeyValueTreeTransformRules::~IKeyValueTreeTransformRules()
+{
+}
+
+/********************************************************************
+ * KeyValueTreeTransformRule
+ */
+
+namespace internal
+{
+
+class KeyValueTreeTransformRule
+{
+    public:
+
+    private:
+        std::function<KeyValueTreeValue(const KeyValueTreeValue &)> transform_;
+};
+
+/********************************************************************
+ * KeyValueTreeTransformer::Impl
+ */
+
+class KeyValueTreeTransformerImpl : public IKeyValueTreeTransformRules
+{
+    public:
+        class Rule
+        {
+            public:
+                typedef std::function<void(KeyValueTreeValueBuilder *, const KeyValueTreeValue &)>
+                    TransformFunction;
+                void doTransform(KeyValueTreeBuilder     *builder,
+                                 const KeyValueTreeValue &value) const;
+                void doChildTransforms(KeyValueTreeBuilder      *builder,
+                                       const KeyValueTreeObject &object) const;
+                void applyTransformedValue(KeyValueTreeBuilder  *builder,
+                                           KeyValueTreeValue   &&value) const;
+
+                const Rule *findMatchingChildRule(const std::string &key) const
+                {
+                    auto iter = childRules_.find(key);
+                    if (iter == childRules_.end())
+                    {
+                        return nullptr;
+                    }
+                    return &iter->second;
+                }
+                Rule *getOrCreateChildRule(const std::string &key)
+                {
+                    auto iter = childRules_.find(key);
+                    if (iter == childRules_.end())
+                    {
+                        iter = childRules_.insert(std::make_pair(key, Rule())).first;
+                    }
+                    return &iter->second;
+                }
+
+                std::vector<std::string>    targetPath_;
+                std::string                 targetKey_;
+                TransformFunction           transform_;
+                std::map<std::string, Rule> childRules_;
+        };
+
+        virtual KeyValueTreeTransformRuleBuilder addRule()
+        {
+            return KeyValueTreeTransformRuleBuilder(this);
+        }
+
+        Rule  rootRule_;
+};
+
+void KeyValueTreeTransformerImpl::Rule::doTransform(
+        KeyValueTreeBuilder *builder, const KeyValueTreeValue &value) const
+{
+    if (transform_)
+    {
+        KeyValueTreeValueBuilder valueBuilder;
+        transform_(&valueBuilder, value);
+        applyTransformedValue(builder, valueBuilder.build());
+        return;
+    }
+    if (!childRules_.empty())
+    {
+        doChildTransforms(builder, value.asObject());
+    }
+}
+
+void KeyValueTreeTransformerImpl::Rule::doChildTransforms(
+        KeyValueTreeBuilder *builder, const KeyValueTreeObject &object) const
+{
+    for (const auto &prop : object.properties())
+    {
+        const Rule *childRule = findMatchingChildRule(prop.key());
+        if (childRule != nullptr)
+        {
+            childRule->doTransform(builder, prop.value());
+        }
+    }
+}
+
+void KeyValueTreeTransformerImpl::Rule::applyTransformedValue(
+        KeyValueTreeBuilder *builder, KeyValueTreeValue &&value) const
+{
+    KeyValueTreeObjectBuilder objBuilder = builder->rootObject();
+    for (const std::string &key : targetPath_)
+    {
+        if (objBuilder.keyExists(key))
+        {
+            objBuilder = objBuilder.getObject(key);
+        }
+        else
+        {
+            objBuilder = objBuilder.addObject(key);
+        }
+    }
+    if (objBuilder.keyExists(targetKey_))
+    {
+        objBuilder.getObject(targetKey_).mergeObject(std::move(value));
+    }
+    else
+    {
+        objBuilder.addRawValue(targetKey_, std::move(value));
+    }
+}
+
+}   // namespace internal
+
+/********************************************************************
+ * KeyValueTreeTransformer
+ */
+
+KeyValueTreeTransformer::KeyValueTreeTransformer()
+    : impl_(new internal::KeyValueTreeTransformerImpl)
+{
+}
+
+KeyValueTreeTransformer::~KeyValueTreeTransformer()
+{
+}
+
+IKeyValueTreeTransformRules *KeyValueTreeTransformer::rules()
+{
+    return impl_.get();
+}
+
+KeyValueTreeObject KeyValueTreeTransformer::transform(const KeyValueTreeObject &tree) const
+{
+    gmx::KeyValueTreeBuilder builder;
+    impl_->rootRule_.doChildTransforms(&builder, tree);
+    return builder.build();
+}
+
+/********************************************************************
+ * KeyValueTreeTransformRuleBuilder::Data
+ */
+
+class KeyValueTreeTransformRuleBuilder::Data
+{
+    public:
+        typedef internal::KeyValueTreeTransformerImpl::Rule::TransformFunction
+            TransformFunction;
+
+        void createRule(internal::KeyValueTreeTransformerImpl *impl)
+        {
+            std::vector<std::string>                     from = splitDelimitedString(fromPath_.substr(1), '/');
+            std::vector<std::string>                     to   = splitDelimitedString(toPath_.substr(1), '/');
+            internal::KeyValueTreeTransformerImpl::Rule *rule = &impl->rootRule_;
+            for (const std::string &key : from)
+            {
+                rule = rule->getOrCreateChildRule(key);
+            }
+            rule->targetKey_  = to.back();
+            to.pop_back();
+            rule->targetPath_ = std::move(to);
+            rule->transform_  = transform_;
+        }
+
+        std::string       fromPath_;
+        std::string       toPath_;
+        TransformFunction transform_;
+};
+
+/********************************************************************
+ * KeyValueTreeTransformRuleBuilder
+ */
+
+KeyValueTreeTransformRuleBuilder::KeyValueTreeTransformRuleBuilder(
+        internal::KeyValueTreeTransformerImpl *impl)
+    : impl_(impl), data_(new Data)
+{
+}
+
+KeyValueTreeTransformRuleBuilder::~KeyValueTreeTransformRuleBuilder()
+{
+    if (!std::uncaught_exception())
+    {
+        data_->createRule(impl_);
+    }
+}
+
+void KeyValueTreeTransformRuleBuilder::setFromPath(const std::string &path)
+{
+    data_->fromPath_ = path;
+}
+
+void KeyValueTreeTransformRuleBuilder::setToPath(const std::string &path)
+{
+    data_->toPath_ = path;
+}
+
+void KeyValueTreeTransformRuleBuilder::addTransformToVariant(
+        std::function<Variant(const Variant &)> transform)
+{
+    data_->transform_ =
+        [transform] (KeyValueTreeValueBuilder *builder, const KeyValueTreeValue &value)
+        {
+            builder->setVariantValue(transform(value.asVariant()));
+        };
+}
+
+void KeyValueTreeTransformRuleBuilder::addTransformToObject(
+        std::function<void(KeyValueTreeObjectBuilder *, const Variant &)> transform)
+{
+    data_->transform_ =
+        [transform] (KeyValueTreeValueBuilder *builder, const KeyValueTreeValue &value)
+        {
+            KeyValueTreeObjectBuilder obj = builder->createObject();
+            transform(&obj, value.asVariant());
+        };
+}
+
+} // namespace gmx
diff --git a/src/gromacs/utility/keyvaluetreetransform.h b/src/gromacs/utility/keyvaluetreetransform.h
new file mode 100644 (file)
index 0000000..102df2b
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares utilities for transforming key-value trees.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_KEYVALUETREETRANSFORM_H
+#define GMX_UTILITY_KEYVALUETREETRANSFORM_H
+
+#include <functional>
+#include <string>
+
+#include "gromacs/utility/classhelpers.h"
+#include "gromacs/utility/variant.h"
+
+namespace gmx
+{
+
+class KeyValueTreeObject;
+class KeyValueTreeObjectBuilder;
+
+class KeyValueTreeTransformRuleBuilder;
+
+namespace internal
+{
+class KeyValueTreeTransformerImpl;
+}
+
+class IKeyValueTreeTransformRules
+{
+    public:
+        virtual KeyValueTreeTransformRuleBuilder addRule() = 0;
+
+    protected:
+        ~IKeyValueTreeTransformRules();
+};
+
+class KeyValueTreeTransformer
+{
+    public:
+        KeyValueTreeTransformer();
+        ~KeyValueTreeTransformer();
+
+        IKeyValueTreeTransformRules *rules();
+
+        KeyValueTreeObject transform(const KeyValueTreeObject &tree) const;
+
+    private:
+        PrivateImplPointer<internal::KeyValueTreeTransformerImpl> impl_;
+};
+
+class KeyValueTreeTransformRuleBuilder
+{
+    public:
+        class Base
+        {
+            protected:
+                explicit Base(KeyValueTreeTransformRuleBuilder *builder)
+                    : builder_(builder)
+                {
+                }
+
+                KeyValueTreeTransformRuleBuilder *builder_;
+        };
+
+        template <typename FromType, typename ToType>
+        class ToValue : public Base
+        {
+            public:
+                explicit ToValue(KeyValueTreeTransformRuleBuilder *builder)
+                    : Base(builder)
+                {
+                }
+
+                void transformWith(std::function<ToType(const FromType &)> transform)
+                {
+                    builder_->addTransformToVariant(
+                            [transform] (const Variant &value)
+                            {
+                                return Variant::create<ToType>(transform(value.cast<FromType>()));
+                            });
+                }
+        };
+
+        template <typename FromType>
+        class ToObject : public Base
+        {
+            public:
+                explicit ToObject(KeyValueTreeTransformRuleBuilder *builder)
+                    : Base(builder)
+                {
+                }
+
+                void transformWith(std::function<void(KeyValueTreeObjectBuilder *, const FromType &)> transform)
+                {
+                    builder_->addTransformToObject(
+                            [transform] (KeyValueTreeObjectBuilder *builder, const Variant &value)
+                            {
+                                transform(builder, value.cast<FromType>());
+                            });
+                }
+        };
+
+        template <typename FromType>
+        class AfterFrom : public Base
+        {
+            public:
+                explicit AfterFrom(KeyValueTreeTransformRuleBuilder *builder)
+                    : Base(builder)
+                {
+                }
+
+                template <typename ToType>
+                ToValue<FromType, ToType> to(const std::string &path)
+                {
+                    builder_->setToPath(path);
+                    return ToValue<FromType, ToType>(builder_);
+                }
+
+                ToObject<FromType> toObject(const std::string &path)
+                {
+                    builder_->setToPath(path);
+                    return ToObject<FromType>(builder_);
+                }
+        };
+
+        explicit KeyValueTreeTransformRuleBuilder(internal::KeyValueTreeTransformerImpl *impl);
+        KeyValueTreeTransformRuleBuilder(KeyValueTreeTransformRuleBuilder &&)            = default;
+        KeyValueTreeTransformRuleBuilder &operator=(KeyValueTreeTransformRuleBuilder &&) = default;
+        ~KeyValueTreeTransformRuleBuilder();
+
+        template <typename FromType>
+        AfterFrom<FromType> from(const std::string &path)
+        {
+            setFromPath(path);
+            return AfterFrom<FromType>(this);
+        }
+
+    private:
+        void setFromPath(const std::string &path);
+        void setToPath(const std::string &path);
+        void addTransformToVariant(std::function<Variant(const Variant &)> transform);
+        void addTransformToObject(std::function<void(KeyValueTreeObjectBuilder *, const Variant &)> transform);
+
+        class Data;
+
+        internal::KeyValueTreeTransformerImpl *impl_;
+        std::unique_ptr<Data>                  data_;
+};
+
+} // namespace gmx
+
+#endif
similarity index 60%
rename from src/gromacs/gmxlib/md_logging.cpp
rename to src/gromacs/utility/logger.cpp
index a114643162e7eb83c4d5a06039fbedf850afc9a1..7be58088b45acc62a9f1626c830a2d3442f180c2 100644 (file)
@@ -1,9 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2012,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2016, 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.
  */
 #include "gmxpre.h"
 
-#include "md_logging.h"
+#include "logger.h"
 
 #include <cstdarg>
-#include <cstdio>
 
-#include "gromacs/mdtypes/commrec.h"
+#include "gromacs/utility/stringutil.h"
 
-
-void md_print_info(const t_commrec *cr, FILE *fplog,
-                   const char *fmt, ...)
+namespace gmx
 {
-    va_list ap;
 
-    if (cr == NULL || SIMMASTER(cr))
-    {
-        va_start(ap, fmt);
-
-        vfprintf(stderr, fmt, ap);
+namespace
+{
 
-        va_end(ap);
-    }
-    if (fplog != NULL)
-    {
-        va_start(ap, fmt);
+//! Helper method for reading logging targets from an array.
+ILogTarget *getTarget(ILogTarget        *targets[MDLogger::LogLevelCount],
+                      MDLogger::LogLevel level)
+{
+    return targets[static_cast<int>(level)];
+}
 
-        vfprintf(fplog, fmt, ap);
+}   // namespace
 
-        va_end(ap);
-    }
+ILogTarget::~ILogTarget()
+{
 }
 
-void md_print_warn(const t_commrec *cr, FILE *fplog,
-                   const char *fmt, ...)
+
+LogEntryWriter &LogEntryWriter::appendTextFormatted(const char *fmt, ...)
 {
     va_list ap;
 
-    if (cr == NULL || SIMMASTER(cr))
-    {
-        va_start(ap, fmt);
-
-        fprintf(stderr, "\n");
-        vfprintf(stderr, fmt, ap);
-        fprintf(stderr, "\n");
-
-        va_end(ap);
-    }
-    if (fplog != NULL)
-    {
-        va_start(ap, fmt);
+    va_start(ap, fmt);
+    entry_.text.append(formatStringV(fmt, ap));
+    va_end(ap);
+    return *this;
+}
 
-        fprintf(fplog, "\n");
-        vfprintf(fplog, fmt, ap);
-        fprintf(fplog, "\n");
+MDLogger::MDLogger()
+    : warning(nullptr), info(nullptr)
+{
+}
 
-        va_end(ap);
-    }
+MDLogger::MDLogger(ILogTarget *targets[LogLevelCount])
+    : warning(getTarget(targets, LogLevel::Warning)),
+      info(getTarget(targets, LogLevel::Info))
+{
 }
+
+} // namespace gmx
diff --git a/src/gromacs/utility/logger.h b/src/gromacs/utility/logger.h
new file mode 100644 (file)
index 0000000..f9f4f6d
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares functionality for logging.
+ *
+ * See \ref page_logging for an overview of the functionality.
+ *
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_LOGGER_H
+#define GMX_UTILITY_LOGGER_H
+
+#include <string>
+
+namespace gmx
+{
+
+struct LogEntry
+{
+    LogEntry() : asParagraph(false) {}
+
+    std::string text;
+    bool        asParagraph;
+};
+
+/*! \libinternal \brief
+ * Target where log output can be written.
+ *
+ * \ingroup module_utility
+ */
+class ILogTarget
+{
+    public:
+        virtual ~ILogTarget();
+
+        //! Writes a log entry to this target.
+        virtual void writeEntry(const LogEntry &entry) = 0;
+};
+
+/*! \libinternal \brief
+ * Helper class for creating log entries with ::GMX_LOG.
+ *
+ * \ingroup module_utility
+ */
+class LogEntryWriter
+{
+    public:
+        //! Appends given text to the log entry.
+        LogEntryWriter &appendText(const char *text)
+        {
+            entry_.text.append(text);
+            return *this;
+        }
+        //! Appends given text to the log entry.
+        LogEntryWriter &appendText(const std::string &text)
+        {
+            entry_.text.append(text);
+            return *this;
+        }
+        //! Appends given text to the log entry, with printf-style formatting.
+        LogEntryWriter &appendTextFormatted(const char *fmt, ...);
+        //! Writes the log entry with empty lines before and after.
+        LogEntryWriter &asParagraph()
+        {
+            entry_.asParagraph = true;
+            return *this;
+        }
+
+    private:
+        LogEntry    entry_;
+
+        friend class LogWriteHelper;
+};
+
+/*! \internal \brief
+ * Helper class for implementing ::GMX_LOG.
+ *
+ * \ingroup module_utility
+ */
+class LogWriteHelper
+{
+    public:
+        //! Initializes a helper for writing to the given target.
+        explicit LogWriteHelper(ILogTarget *target) : target_(target) {}
+
+        // Should be explicit, once that works in CUDA.
+        /*! \brief
+         * Returns whether anything needs to be written.
+         *
+         * Note that the return value is unintuitively `false` when the target
+         * is active, to allow implementing ::GMX_LOG like it is now.
+         */
+        operator bool() const { return target_ == NULL; }
+
+        /*! \brief
+         * Writes the entry from the given writer to the log target.
+         *
+         * This is implemented as an assignment operator to get proper
+         * precedence for operations for the ::GMX_LOG macro; this is a common
+         * technique for implementing macros that allow streming information to
+         * them (see, e.g., Google Test).
+         */
+        void operator=(const LogEntryWriter &entryWriter)
+        {
+            target_->writeEntry(entryWriter.entry_);
+        }
+
+    private:
+        ILogTarget *target_;
+};
+
+/*! \libinternal \brief
+ * Represents a single logging level.
+ *
+ * Typically this type is not used directly, but instances in MDLogger are
+ * simply accessed through ::GMX_LOG in code that writes to the log.
+ *
+ * \ingroup module_utility
+ */
+class LogLevelHelper
+{
+    public:
+        //! Initializes a helper for writing to the given target.
+        explicit LogLevelHelper(ILogTarget *target) : target_(target) {}
+
+        // Both of the below should be explicit, once that works in CUDA.
+        //! Returns whether the output for this log level goes anywhere.
+        operator bool() const { return target_ != NULL; }
+
+        //! Creates a helper for ::GMX_LOG.
+        operator LogWriteHelper() const { return LogWriteHelper(target_); }
+
+    private:
+        ILogTarget *target_;
+};
+
+/*! \libinternal \brief
+ * Declares a logging interface.
+ *
+ * Typically, this object is not created directly, but instead through
+ * LoggerBuilder.
+ *
+ * For now, this is named MDLogger, since it is used only there, and it is not
+ * clear whether the logging levels can be the same throughout the code.  It
+ * should be relatively straightforward to split this into multiple classes
+ * with different supported logging levels without changing calling code, or to
+ * rename it to Logger if we do not need any specialization.
+ *
+ * \ingroup module_utility
+ */
+class MDLogger
+{
+    public:
+        //! Supported logging levels.
+        enum LogLevel
+        {
+            Warning,
+            Info
+        };
+        //! Number of logging levels.
+        static const int LogLevelCount = static_cast<int>(Info) + 1;
+
+        MDLogger();
+        //! Creates a logger with the given targets.
+        explicit MDLogger(ILogTarget *targets[LogLevelCount]);
+
+        //! For writing at LogLevel::Warning level.
+        LogLevelHelper warning;
+        //! For writing at LogLevel::Info level.
+        LogLevelHelper info;
+};
+
+/*! \brief
+ * Helper to log information using gmx::MDLogger.
+ *
+ * \param  logger  LogLevelHelper instance to use for logging.
+ *
+ * Used as
+ * \code
+   GMX_LOG(logger.warning).appendText(...);
+   \endcode
+ * and ensures that the code to format the output is only executed when the
+ * output goes somewhere.
+ *
+ * See LogEntryWriter for functions that can be used with the macro (such as
+ * the appendText() in the example).
+ *
+ * \ingroup module_utility
+ */
+#define GMX_LOG(logger) \
+    if (::gmx::LogWriteHelper helper = ::gmx::LogWriteHelper(logger)) { } else \
+        helper = ::gmx::LogEntryWriter()
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/utility/loggerbuilder.cpp b/src/gromacs/utility/loggerbuilder.cpp
new file mode 100644 (file)
index 0000000..a5da7d0
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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 "gmxpre.h"
+
+#include "loggerbuilder.h"
+
+#include <memory>
+#include <vector>
+
+#include "gromacs/utility/filestream.h"
+#include "gromacs/utility/logger.h"
+#include "gromacs/utility/stringutil.h"
+#include "gromacs/utility/textwriter.h"
+
+namespace gmx
+{
+
+class LogTargetCollection : public ILogTarget
+{
+    public:
+        void addTarget(ILogTarget *target)
+        {
+            targets_.push_back(target);
+        }
+
+        virtual void writeEntry(const LogEntry &entry)
+        {
+            for (ILogTarget *target : targets_)
+            {
+                target->writeEntry(entry);
+            }
+        }
+
+    private:
+        std::vector<ILogTarget *> targets_;
+};
+
+class LogTargetFormatter : public ILogTarget
+{
+    public:
+        explicit LogTargetFormatter(TextOutputStream *stream) : writer_(stream) {}
+
+        virtual void writeEntry(const LogEntry &entry);
+
+    private:
+        TextWriter writer_;
+};
+
+
+void LogTargetFormatter::writeEntry(const LogEntry &entry)
+{
+    if (entry.asParagraph)
+    {
+        writer_.ensureEmptyLine();
+    }
+    writer_.writeLine(entry.text);
+    if (entry.asParagraph)
+    {
+        writer_.ensureEmptyLine();
+    }
+}
+
+/********************************************************************
+ * LoggerOwner::Impl
+ */
+
+class LoggerOwner::Impl
+{
+    public:
+        explicit Impl(ILogTarget *loggerTargets[MDLogger::LogLevelCount])
+            : logger_(loggerTargets)
+        {
+        }
+
+        MDLogger                                        logger_;
+        std::vector<std::unique_ptr<TextOutputStream> > streams_;
+        std::vector<std::unique_ptr<ILogTarget> >       targets_;
+};
+
+/********************************************************************
+ * LoggerOwner
+ */
+
+LoggerOwner::LoggerOwner(std::unique_ptr<Impl> impl)
+    : impl_(impl.release()), logger_(&impl_->logger_)
+{
+}
+
+LoggerOwner::LoggerOwner(LoggerOwner &&other)
+    : impl_(std::move(other.impl_)), logger_(&impl_->logger_)
+{
+}
+
+LoggerOwner &LoggerOwner::operator=(LoggerOwner &&other)
+{
+    impl_   = std::move(other.impl_);
+    logger_ = &impl_->logger_;
+    return *this;
+}
+
+LoggerOwner::~LoggerOwner()
+{
+}
+
+/********************************************************************
+ * LoggerBuilder::Impl
+ */
+
+class LoggerBuilder::Impl
+{
+    public:
+        std::vector<std::unique_ptr<TextOutputStream> > streams_;
+        std::vector<std::unique_ptr<ILogTarget> >       targets_;
+        std::vector<ILogTarget *> loggerTargets_[MDLogger::LogLevelCount];
+};
+
+/********************************************************************
+ * LoggerBuilder
+ */
+
+LoggerBuilder::LoggerBuilder()
+    : impl_(new Impl)
+{
+}
+
+LoggerBuilder::~LoggerBuilder()
+{
+}
+
+void LoggerBuilder::addTargetStream(MDLogger::LogLevel level, TextOutputStream *stream)
+{
+    impl_->targets_.push_back(std::unique_ptr<ILogTarget>(new LogTargetFormatter(stream)));
+    ILogTarget *target = impl_->targets_.back().get();
+    for (int i = 0; i <= static_cast<int>(level); ++i)
+    {
+        impl_->loggerTargets_[i].push_back(target);
+    }
+}
+
+void LoggerBuilder::addTargetFile(MDLogger::LogLevel level, FILE *fp)
+{
+    std::unique_ptr<TextOutputStream> stream(new TextOutputFile(fp));
+    addTargetStream(level, stream.get());
+    impl_->streams_.push_back(std::move(stream));
+}
+
+LoggerOwner LoggerBuilder::build()
+{
+    ILogTarget *loggerTargets[MDLogger::LogLevelCount];
+    for (int i = 0; i < MDLogger::LogLevelCount; ++i)
+    {
+        auto &levelTargets = impl_->loggerTargets_[i];
+        loggerTargets[i] = nullptr;
+        if (!levelTargets.empty())
+        {
+            if (levelTargets.size() == 1)
+            {
+                loggerTargets[i] = levelTargets[0];
+            }
+            else
+            {
+                std::unique_ptr<LogTargetCollection> collection(new LogTargetCollection);
+                for (auto &target : levelTargets)
+                {
+                    collection->addTarget(target);
+                }
+                loggerTargets[i] = collection.get();
+                impl_->targets_.push_back(std::move(collection));
+            }
+        }
+        levelTargets.clear();
+    }
+    std::unique_ptr<LoggerOwner::Impl> data(new LoggerOwner::Impl(loggerTargets));
+    data->targets_ = std::move(impl_->targets_);
+    data->streams_ = std::move(impl_->streams_);
+    return LoggerOwner(std::move(data));
+}
+
+} // namespace gmx
diff --git a/src/gromacs/utility/loggerbuilder.h b/src/gromacs/utility/loggerbuilder.h
new file mode 100644 (file)
index 0000000..75ff25f
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares functionality for initializing logging.
+ *
+ * See \ref page_logging for an overview of the functionality.
+ *
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_LOGGERBUILDER_H
+#define GMX_UTILITY_LOGGERBUILDER_H
+
+#include <memory>
+#include <string>
+
+#include "gromacs/utility/classhelpers.h"
+#include "gromacs/utility/logger.h"
+
+namespace gmx
+{
+
+class TextOutputStream;
+
+class LoggerFormatterBuilder;
+class LoggerOwner;
+
+/*! \libinternal \brief
+ * Initializes loggers.
+ *
+ * This class provides methods for specifying logging targets for a logger and
+ * building the logger after all targets have been specified.  Having this
+ * separate from the logger allows using different internal data structures
+ * during initialization and operation, and simplifies the responsibilities of
+ * the involved classes.
+ *
+ * \ingroup module_utility
+ */
+class LoggerBuilder
+{
+    public:
+        LoggerBuilder();
+        ~LoggerBuilder();
+
+        /*! \brief
+         * Adds a stream to which log output is written.
+         *
+         * All output at level \p level or above it is written to \p stream.
+         * The caller is responsible of closing and freeing \p stream once the
+         * logger is discarded.
+         */
+        void addTargetStream(MDLogger::LogLevel level, TextOutputStream *stream);
+        /*! \brief
+         * Adds a file to which log output is written.
+         *
+         * All output at level \p level or above it is written to \p fp.
+         * The caller is responsible of closing \p fp once the logger is
+         * discarded.
+         */
+        void addTargetFile(MDLogger::LogLevel level, FILE *fp);
+
+        /*! \brief
+         * Builds the logger with the targets set for this builder.
+         *
+         * After this function has been called, the builder can (and should) be
+         * discarded.
+         */
+        LoggerOwner build();
+
+    private:
+        class Impl;
+
+        PrivateImplPointer<Impl> impl_;
+};
+
+/*! \libinternal \brief
+ * Manages memory for a logger built with LoggerBuilder.
+ *
+ * This class is responsible of managing all memory allocated by LoggerBuilder
+ * that is needed for operation of the actual logger.  Also the actual logger
+ * instance is owned by this class.  This allows keeing the actual logger simple
+ * and streamlined.
+ *
+ * This class supports move construction and assignment, which allows
+ * initializing it on the stack and assigning a new instance if the targets
+ * need to be changed.
+ *
+ * \ingroup module_utility
+ */
+class LoggerOwner
+{
+    public:
+        //! Move-constructs the owner.
+        LoggerOwner(LoggerOwner &&other);
+        ~LoggerOwner();
+
+        //! Move-assings the owner.
+        LoggerOwner &operator=(LoggerOwner &&other);
+
+        //! Returns the logger for writing the logs.
+        const MDLogger &logger() const { return *logger_; }
+
+    private:
+        class Impl;
+
+        LoggerOwner(std::unique_ptr<Impl> impl);
+
+        PrivateImplPointer<Impl>  impl_;
+        const MDLogger           *logger_;
+
+        friend class LoggerBuilder;
+};
+
+} // namespace gmx
+
+#endif
index 937bb541cb99510b665d0426b72a066b5ff73321..97d2853ec499829435a13cff94ad949b2def908d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2011,2012,2014, by the GROMACS development team, led by
+ * Copyright (c) 2011,2012,2014,2016, 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.
@@ -71,7 +71,7 @@ MessageStringCollector::~MessageStringCollector()
 
 void MessageStringCollector::startContext(const char *name)
 {
-    impl_->contexts_.push_back(name);
+    impl_->contexts_.emplace_back(name);
 }
 
 void MessageStringCollector::append(const std::string &message)
diff --git a/src/gromacs/utility/strconvert.cpp b/src/gromacs/utility/strconvert.cpp
new file mode 100644 (file)
index 0000000..f85fcd3
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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.
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions in strconvert.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_utility
+ */
+#include "gmxpre.h"
+
+#include "strconvert.h"
+
+#include <cerrno>
+#include <cstdlib>
+
+#include <limits>
+#include <string>
+
+#include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/exceptions.h"
+
+namespace gmx
+{
+
+//! \cond libapi
+
+bool boolFromString(const char *value)
+{
+    if (gmx_strcasecmp(value, "1") == 0
+        || gmx_strcasecmp(value, "yes") == 0
+        || gmx_strcasecmp(value, "true") == 0)
+    {
+        return true;
+    }
+    if (gmx_strcasecmp(value, "0") == 0
+        || gmx_strcasecmp(value, "no") == 0
+        || gmx_strcasecmp(value, "false") == 0)
+    {
+        return false;
+    }
+    GMX_THROW(InvalidInputError("Invalid value: '" + std::string(value) + "'; supported values are: 1, 0, yes, no, true, false"));
+}
+
+int intFromString(const char *str)
+{
+    errno = 0;
+    char           *endptr;
+    const long int  value = std::strtol(str, &endptr, 10);
+    if (errno == ERANGE
+        || value < std::numeric_limits<int>::min()
+        || value > std::numeric_limits<int>::max())
+    {
+        GMX_THROW(InvalidInputError("Invalid value: '" + std::string(str)
+                                    + "'; it causes an integer overflow"));
+    }
+    if (str[0] == '\0' || *endptr != '\0')
+    {
+        GMX_THROW(InvalidInputError("Invalid value: '" + std::string(str)
+                                    + "'; expected an integer"));
+    }
+    return value;
+}
+
+gmx_int64_t int64FromString(const char *str)
+{
+    errno = 0;
+    char              *endptr;
+    const gmx_int64_t  value = str_to_int64_t(str, &endptr);
+    if (errno == ERANGE)
+    {
+        GMX_THROW(InvalidInputError("Invalid value: '" + std::string(str)
+                                    + "'; it causes an integer overflow"));
+    }
+    if (str[0] == '\0' || *endptr != '\0')
+    {
+        GMX_THROW(InvalidInputError("Invalid value: '" + std::string(str)
+                                    + "'; expected an integer"));
+    }
+    return value;
+}
+
+float floatFromString(const char *str)
+{
+    errno = 0;
+    char         *endptr;
+    const double  value = std::strtod(str, &endptr);
+    if (errno == ERANGE
+        || value < -std::numeric_limits<float>::max()
+        || value >  std::numeric_limits<float>::max())
+    {
+        GMX_THROW(InvalidInputError("Invalid value: '" + std::string(str)
+                                    + "'; it causes an overflow/underflow"));
+    }
+    if (str[0] == '\0' || *endptr != '\0')
+    {
+        GMX_THROW(InvalidInputError("Invalid value: '" + std::string(str)
+                                    + "'; expected a number"));
+    }
+    return value;
+}
+
+double doubleFromString(const char *str)
+{
+    errno = 0;
+    char         *endptr;
+    const double  value = std::strtod(str, &endptr);
+    if (errno == ERANGE)
+    {
+        GMX_THROW(InvalidInputError("Invalid value: '" + std::string(str)
+                                    + "'; it causes an overflow/underflow"));
+    }
+    if (str[0] == '\0' || *endptr != '\0')
+    {
+        GMX_THROW(InvalidInputError("Invalid value: '" + std::string(str)
+                                    + "'; expected a number"));
+    }
+    return value;
+}
+
+//! \endcond
+
+} // namespace gmx
diff --git a/src/gromacs/utility/strconvert.h b/src/gromacs/utility/strconvert.h
new file mode 100644 (file)
index 0000000..8275e32
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares common utility functions for conversions from strings.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_STRCONVERT_H
+#define GMX_UTILITY_STRCONVERT_H
+
+#include <string>
+
+#include "gromacs/utility/basedefinitions.h"
+
+namespace gmx
+{
+
+//! \cond libapi
+//! \addtogroup module_utility
+//! \{
+
+/*! \brief
+ * Parses a boolean from a string.
+ *
+ * \throws  InvalidInputError if `str` is not recognized as a boolean value.
+ */
+bool boolFromString(const char *str);
+/*! \brief
+ * Parses an integer from a string.
+ *
+ * \throws  InvalidInputError if `str` is not a valid integer.
+ *
+ * Also checks for overflow.
+ */
+int intFromString(const char *str);
+/*! \brief
+ * Parses a 64-bit integer from a string.
+ *
+ * \throws  InvalidInputError if `str` is not a valid integer.
+ *
+ * Also checks for overflow.
+ */
+gmx_int64_t int64FromString(const char *str);
+/*! \brief
+ * Parses a float value from a string.
+ *
+ * \throws  InvalidInputError if `str` is not a valid number.
+ *
+ * Also checks for overflow.
+ */
+float floatFromString(const char *str);
+/*! \brief
+ * Parses a double value from a string.
+ *
+ * \throws  InvalidInputError if `str` is not a valid number.
+ *
+ * Also checks for overflow.
+ */
+double doubleFromString(const char *str);
+
+/*! \brief
+ * Parses a value from a string to a given type.
+ *
+ * \tparam T Type of value to parse.
+ *
+ * `T` can only be one of the types that is explicity supported.
+ * The main use for this function is to write `fromString<real>(value)`,
+ * but it can also be used for other types for consistency.
+ */
+template <typename T> static inline T fromString(const char *str);
+//! \copydoc fromString(const char *)
+template <typename T> static inline T fromString(const std::string &str)
+{
+    return fromString<T>(str.c_str());
+}
+/*! \copydoc fromString(const char *)
+ *
+ * Provided for situations where overload resolution cannot easily resolve the
+ * desired std::string parameter.
+ */
+template <typename T> static inline T fromStdString(const std::string &str)
+{
+    return fromString<T>(str.c_str());
+}
+
+//! Implementation for boolean values.
+template <> inline
+bool fromString<bool>(const char *str) { return boolFromString(str); }
+//! Implementation for integer values.
+template <> inline
+int fromString<int>(const char *str) { return intFromString(str); }
+//! Implementation for 64-bit integer values.
+template <> inline
+gmx_int64_t fromString<gmx_int64_t>(const char *str) { return int64FromString(str); }
+//! Implementation for float values.
+template <> inline
+float fromString<float>(const char *str) { return floatFromString(str); }
+//! Implementation for double values.
+template <> inline
+double fromString<double>(const char *str) { return doubleFromString(str); }
+
+//! \}
+//! \endcond
+
+} // namespace gmx
+
+#endif
index cc3b1bfa3b9928779c80ce1dd4f21360730453ee..1a1b1c1e224e4ef6e64da0e16aac0e13693e32dd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2011,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2011,2012,2013,2014,2015,2016, 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.
@@ -133,7 +133,16 @@ std::string stripString(const std::string &str)
 
 std::string formatString(const char *fmt, ...)
 {
-    va_list           ap;
+    va_list     ap;
+    va_start(ap, fmt);
+    std::string result = formatStringV(fmt, ap);
+    va_end(ap);
+    return result;
+}
+
+std::string formatStringV(const char *fmt, va_list ap)
+{
+    va_list           ap_copy;
     char              staticBuf[1024];
     int               length = 1024;
     std::vector<char> dynamicBuf;
@@ -143,9 +152,9 @@ std::string formatString(const char *fmt, ...)
     // provides their own way of doing things...
     while (1)
     {
-        va_start(ap, fmt);
-        int n = vsnprintf(buf, length, fmt, ap);
-        va_end(ap);
+        va_copy(ap_copy, ap);
+        int n = vsnprintf(buf, length, fmt, ap_copy);
+        va_end(ap_copy);
         if (n > -1 && n < length)
         {
             std::string result(buf);
@@ -182,8 +191,27 @@ std::vector<std::string> splitString(const std::string &str)
         }
         if (startPos != end)
         {
-            result.push_back(std::string(startPos, currPos));
+            result.emplace_back(startPos, currPos);
+        }
+    }
+    return result;
+}
+
+std::vector<std::string> splitDelimitedString(const std::string &str, char delim)
+{
+    std::vector<std::string> result;
+    size_t                   currPos = 0;
+    const size_t             len     = str.length();
+    if (len > 0)
+    {
+        size_t nextDelim;
+        do
+        {
+            nextDelim = str.find(delim, currPos);
+            result.push_back(str.substr(currPos, nextDelim - currPos));
+            currPos = nextDelim < len ? nextDelim + 1 : len;
         }
+        while (currPos < len || nextDelim < len);
     }
     return result;
 }
index f54aedaa9ebf0b700b632e40e2c7f7ef04414bd2..592d517c7332731c16eff2e046b5d2252fbe1bb9 100644 (file)
@@ -43,6 +43,7 @@
 #ifndef GMX_UTILITY_STRINGUTIL_H
 #define GMX_UTILITY_STRINGUTIL_H
 
+#include <cstdarg>
 #include <cstring>
 
 #include <string>
@@ -178,6 +179,16 @@ std::string stripString(const std::string &str);
  * supported.
  */
 std::string formatString(const char *fmt, ...);
+/*! \brief
+ * Formats a string (vsnprintf() wrapper).
+ *
+ * \throws  std::bad_alloc if out of memory.
+ *
+ * This function works like vsprintf(), except that it returns an std::string
+ * instead of requiring a preallocated buffer.  Arbitrary length output is
+ * supported.
+ */
+std::string formatStringV(const char *fmt, va_list ap);
 
 /*! \brief Function object that wraps a call to formatString() that
  * expects a single conversion argument, for use with algorithms. */
@@ -332,6 +343,19 @@ static inline const char *boolToString(bool value)
  * separator.
  */
 std::vector<std::string> splitString(const std::string &str);
+/*! \brief
+ * Splits a string to tokens separated by a given delimiter.
+ *
+ * \param[in] str   String to process.
+ * \param[in] delim Delimiter to use for splitting.
+ * \returns   \p str split into tokens at delimiter.
+ * \throws    std::bad_alloc if out of memory.
+ *
+ * Unlike splitString(), consencutive delimiters will generate empty tokens, as
+ * will leading or trailing delimiters.
+ * Empty input will return an empty vector.
+ */
+std::vector<std::string> splitDelimitedString(const std::string &str, char delim);
 
 /*! \brief
  * Replace all occurrences of a string with another string.
index 3fe52c713c5b9ec7cccf3a7a04d844df358b757c..dd562a6bb295d6e746ed589f3d389ea861d46e14 100644 (file)
@@ -37,6 +37,8 @@ gmx_add_unit_test(UtilityUnitTests utility-test
                   arrayref.cpp
                   basedefinitions.cpp
                   bitmask32.cpp bitmask64.cpp bitmask128.cpp
+                  keyvaluetreetransform.cpp
+                  logger.cpp
                   path.cpp
                   stringutil.cpp
                   textwriter.cpp
index d7868e2d05dbe0ead9b104609d3aeb816344a8fa..1face9567dcf0b300c4875a7155f8250d3b501e9 100644 (file)
@@ -42,8 +42,6 @@
 
 #include "gromacs/utility/arrayref.h"
 
-#include "config.h"
-
 #include <vector>
 
 #include <gtest/gtest.h>
@@ -217,16 +215,10 @@ struct Helper
  *
  * There, we take a non-const struct-field array of static length and
  * make an ArrayRef to it using the template constructor that is
- * supposed to infer the length from the static size. But on xlc on
- * BlueGene/Q, if the base type is not char (or unsigned char), the
- * generated code ends up with an ArrayRef of zero size, so everything
- * breaks. Presumably the default code path accidentally works for
- * char.
- *
- * Fortunately, all current uses of that constructor have a base type
- * of char, so there's no big problem. Using a pointer-based
- * constructor does work, if there's ever a problem (and that is
- * tested above). */
+ * supposed to infer the length from the static size. This has
+ * been a problem (for a compiler that we no longer support),
+ * so we test it.
+ */
 
 TYPED_TEST(ArrayRefTest, ConstructFromStructFieldWithTemplateConstructorWorks)
 {
@@ -238,12 +230,7 @@ TYPED_TEST(ArrayRefTest, ConstructFromStructFieldWithTemplateConstructorWorks)
         h.a[i] = a[i];
     }
     typename TestFixture::ArrayRefType arrayRef(h.a);
-#if GMX_TARGET_BGQ && defined(__xlC__)
-    if (sizeof(typename TestFixture::ValueType) == sizeof(char))
-#endif
-    {
-        this->runTests(h.a, h.size, h.a, arrayRef);
-    }
+    this->runTests(h.a, h.size, h.a, arrayRef);
 }
 
 #else   // GTEST_HAS_TYPED_TEST
diff --git a/src/gromacs/utility/tests/keyvaluetreetransform.cpp b/src/gromacs/utility/tests/keyvaluetreetransform.cpp
new file mode 100644 (file)
index 0000000..11834d8
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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 "gmxpre.h"
+
+#include "gromacs/utility/keyvaluetreetransform.h"
+
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "gromacs/utility/keyvaluetree.h"
+#include "gromacs/utility/keyvaluetreebuilder.h"
+#include "gromacs/utility/strconvert.h"
+#include "gromacs/utility/stringutil.h"
+
+#include "testutils/refdata.h"
+
+namespace
+{
+
+class TreeValueTransformTest : public ::testing::Test
+{
+    public:
+        void testTransform(const gmx::KeyValueTreeObject      &input,
+                           const gmx::KeyValueTreeTransformer &transform)
+        {
+            gmx::KeyValueTreeObject         result = transform.transform(input);
+
+            gmx::test::TestReferenceData    data;
+            gmx::test::TestReferenceChecker checker(data.rootChecker());
+            checker.checkKeyValueTreeObject(input, "Input");
+            checker.checkKeyValueTreeObject(result, "Tree");
+        }
+};
+
+TEST_F(TreeValueTransformTest, SimpleTransforms)
+{
+    gmx::KeyValueTreeBuilder     builder;
+    builder.rootObject().addValue<std::string>("a", "1");
+    builder.rootObject().addValue<std::string>("b", "2");
+    gmx::KeyValueTreeObject      input = builder.build();
+
+    gmx::KeyValueTreeTransformer transform;
+    transform.rules()->addRule()
+        .from<std::string>("/a").to<int>("/i").transformWith(&gmx::fromStdString<int>);
+    transform.rules()->addRule()
+        .from<std::string>("/b").to<int>("/j").transformWith(&gmx::fromStdString<int>);
+
+    testTransform(input, transform);
+}
+
+TEST_F(TreeValueTransformTest, SimpleTransformsToObject)
+{
+    gmx::KeyValueTreeBuilder     builder;
+    builder.rootObject().addValue<std::string>("a", "1");
+    builder.rootObject().addValue<std::string>("b", "2");
+    gmx::KeyValueTreeObject      input = builder.build();
+
+    gmx::KeyValueTreeTransformer transform;
+    transform.rules()->addRule()
+        .from<std::string>("/a").to<int>("/foo/i").transformWith(&gmx::fromStdString<int>);
+    transform.rules()->addRule()
+        .from<std::string>("/b").to<int>("/foo/j").transformWith(&gmx::fromStdString<int>);
+
+    testTransform(input, transform);
+}
+
+
+TEST_F(TreeValueTransformTest, ObjectFromString)
+{
+    gmx::KeyValueTreeBuilder     builder;
+    builder.rootObject().addValue<std::string>("a", "1 2");
+    gmx::KeyValueTreeObject      input = builder.build();
+
+    gmx::KeyValueTreeTransformer transform;
+    transform.rules()->addRule()
+        .from<std::string>("/a").toObject("/foo").transformWith(
+            [] (gmx::KeyValueTreeObjectBuilder *builder, const std::string &value)
+            {
+                std::vector<std::string> values = gmx::splitString(value);
+                builder->addValue<int>("a", gmx::fromString<int>(values[0]));
+                builder->addValue<int>("b", gmx::fromString<int>(values[1]));
+            });
+
+    testTransform(input, transform);
+}
+
+TEST_F(TreeValueTransformTest, ObjectFromMultipleStrings)
+{
+    gmx::KeyValueTreeBuilder     builder;
+    builder.rootObject().addValue<std::string>("a", "1");
+    builder.rootObject().addValue<std::string>("b", "2 3");
+    gmx::KeyValueTreeObject      input = builder.build();
+
+    gmx::KeyValueTreeTransformer transform;
+    transform.rules()->addRule()
+        .from<std::string>("/a").to<int>("/foo/a").transformWith(&gmx::fromStdString<int>);
+    transform.rules()->addRule()
+        .from<std::string>("/b").toObject("/foo").transformWith(
+            [] (gmx::KeyValueTreeObjectBuilder *builder, const std::string &value)
+            {
+                std::vector<std::string> values = gmx::splitString(value);
+                builder->addValue<int>("b", gmx::fromString<int>(values[0]));
+                builder->addValue<int>("c", gmx::fromString<int>(values[1]));
+            });
+
+    testTransform(input, transform);
+}
+
+} // namespace
diff --git a/src/gromacs/utility/tests/logger.cpp b/src/gromacs/utility/tests/logger.cpp
new file mode 100644 (file)
index 0000000..3385ab4
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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 "gmxpre.h"
+
+#include "gromacs/utility/logger.h"
+
+#include <gtest/gtest.h>
+
+#include "gromacs/utility/loggerbuilder.h"
+#include "gromacs/utility/stringstream.h"
+
+#include "testutils/stringtest.h"
+#include "testutils/testfilemanager.h"
+
+namespace
+{
+
+//! Test fixture for logging tests.
+typedef gmx::test::StringTestBase LoggerTest;
+
+TEST_F(LoggerTest, EmptyLoggerWorks)
+{
+    gmx::MDLogger logger;
+    GMX_LOG(logger.info).appendText("foobar");
+    GMX_LOG(logger.warning).appendText("foobar").asParagraph();
+}
+
+TEST_F(LoggerTest, LogsToStream)
+{
+    gmx::StringOutputStream stream;
+    gmx::LoggerBuilder      builder;
+    builder.addTargetStream(gmx::MDLogger::LogLevel::Info, &stream);
+    gmx::LoggerOwner        owner  = builder.build();
+    const gmx::MDLogger    &logger = owner.logger();
+    GMX_LOG(logger.info).appendText("line");
+    GMX_LOG(logger.warning).appendText("par").asParagraph();
+    GMX_LOG(logger.info).appendText("line2");
+    checkText(stream.toString(), "Output");
+}
+
+TEST_F(LoggerTest, LogsToFile)
+{
+    gmx::test::TestFileManager files;
+    std::string                filename(files.getTemporaryFilePath("log.txt"));
+    FILE                      *fp = fopen(filename.c_str(), "w");
+    {
+        gmx::LoggerBuilder      builder;
+        builder.addTargetFile(gmx::MDLogger::LogLevel::Info, fp);
+        gmx::LoggerOwner        owner  = builder.build();
+        const gmx::MDLogger    &logger = owner.logger();
+        GMX_LOG(logger.info).appendText("line");
+        GMX_LOG(logger.warning).appendText("par").asParagraph();
+        GMX_LOG(logger.info).appendText("line2");
+    }
+    fclose(fp);
+    checkFileContents(filename, "Output");
+}
+
+TEST_F(LoggerTest, LevelFilteringWorks)
+{
+    gmx::StringOutputStream stream;
+    gmx::LoggerBuilder      builder;
+    builder.addTargetStream(gmx::MDLogger::LogLevel::Warning, &stream);
+    gmx::LoggerOwner        owner  = builder.build();
+    const gmx::MDLogger    &logger = owner.logger();
+    GMX_LOG(logger.info).appendText("line");
+    GMX_LOG(logger.warning).appendText("par").asParagraph();
+    GMX_LOG(logger.info).appendText("line2");
+    checkText(stream.toString(), "Output");
+}
+
+TEST_F(LoggerTest, LogsToMultipleStreams)
+{
+    gmx::StringOutputStream stream1;
+    gmx::StringOutputStream stream2;
+    gmx::LoggerBuilder      builder;
+    builder.addTargetStream(gmx::MDLogger::LogLevel::Info, &stream1);
+    builder.addTargetStream(gmx::MDLogger::LogLevel::Warning, &stream2);
+    gmx::LoggerOwner        owner  = builder.build();
+    const gmx::MDLogger    &logger = owner.logger();
+    GMX_LOG(logger.info).appendText("line");
+    GMX_LOG(logger.warning).appendText("par").asParagraph();
+    GMX_LOG(logger.info).appendText("line2");
+    checkText(stream1.toString(), "Output1");
+    checkText(stream2.toString(), "Output2");
+}
+
+} // namespace
diff --git a/src/gromacs/utility/tests/refdata/LoggerTest_LevelFilteringWorks.xml b/src/gromacs/utility/tests/refdata/LoggerTest_LevelFilteringWorks.xml
new file mode 100644 (file)
index 0000000..fac25be
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="Output"><![CDATA[
+par
+]]></String>
+</ReferenceData>
diff --git a/src/gromacs/utility/tests/refdata/LoggerTest_LogsToFile.xml b/src/gromacs/utility/tests/refdata/LoggerTest_LogsToFile.xml
new file mode 100644 (file)
index 0000000..79dfcd4
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="Output"><![CDATA[
+line
+
+par
+
+line2
+]]></String>
+</ReferenceData>
diff --git a/src/gromacs/utility/tests/refdata/LoggerTest_LogsToMultipleStreams.xml b/src/gromacs/utility/tests/refdata/LoggerTest_LogsToMultipleStreams.xml
new file mode 100644 (file)
index 0000000..9a7bee1
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="Output1"><![CDATA[
+line
+
+par
+
+line2
+]]></String>
+  <String Name="Output2"><![CDATA[
+par
+]]></String>
+</ReferenceData>
diff --git a/src/gromacs/utility/tests/refdata/LoggerTest_LogsToStream.xml b/src/gromacs/utility/tests/refdata/LoggerTest_LogsToStream.xml
new file mode 100644 (file)
index 0000000..79dfcd4
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="Output"><![CDATA[
+line
+
+par
+
+line2
+]]></String>
+</ReferenceData>
diff --git a/src/gromacs/utility/tests/refdata/TreeValueTransformTest_ObjectFromMultipleStrings.xml b/src/gromacs/utility/tests/refdata/TreeValueTransformTest_ObjectFromMultipleStrings.xml
new file mode 100644 (file)
index 0000000..42e41f4
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Object Name="Input">
+    <String Name="a">1</String>
+    <String Name="b">2 3</String>
+  </Object>
+  <Object Name="Tree">
+    <Object Name="foo">
+      <Int Name="a">1</Int>
+      <Int Name="b">2</Int>
+      <Int Name="c">3</Int>
+    </Object>
+  </Object>
+</ReferenceData>
diff --git a/src/gromacs/utility/tests/refdata/TreeValueTransformTest_ObjectFromString.xml b/src/gromacs/utility/tests/refdata/TreeValueTransformTest_ObjectFromString.xml
new file mode 100644 (file)
index 0000000..a47a380
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Object Name="Input">
+    <String Name="a">1 2</String>
+  </Object>
+  <Object Name="Tree">
+    <Object Name="foo">
+      <Int Name="a">1</Int>
+      <Int Name="b">2</Int>
+    </Object>
+  </Object>
+</ReferenceData>
diff --git a/src/gromacs/utility/tests/refdata/TreeValueTransformTest_SimpleTransforms.xml b/src/gromacs/utility/tests/refdata/TreeValueTransformTest_SimpleTransforms.xml
new file mode 100644 (file)
index 0000000..eb275c7
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Object Name="Input">
+    <String Name="a">1</String>
+    <String Name="b">2</String>
+  </Object>
+  <Object Name="Tree">
+    <Int Name="i">1</Int>
+    <Int Name="j">2</Int>
+  </Object>
+</ReferenceData>
diff --git a/src/gromacs/utility/tests/refdata/TreeValueTransformTest_SimpleTransformsToObject.xml b/src/gromacs/utility/tests/refdata/TreeValueTransformTest_SimpleTransformsToObject.xml
new file mode 100644 (file)
index 0000000..72e2c38
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Object Name="Input">
+    <String Name="a">1</String>
+    <String Name="b">2</String>
+  </Object>
+  <Object Name="Tree">
+    <Object Name="foo">
+      <Int Name="i">1</Int>
+      <Int Name="j">2</Int>
+    </Object>
+  </Object>
+</ReferenceData>
index 7145fdb109a48cddf46ce992ad2fa340e5fce318..08a844d53bca90124447e143d1aa9edddb8e1ecb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2012,2014,2015,2016, 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.
@@ -126,6 +126,18 @@ TEST(StringUtilityTest, SplitString)
     EXPECT_THAT(gmx::splitString("   "), IsEmpty());
 }
 
+TEST(StringUtilityTest, SplitDelimitedString)
+{
+    using ::testing::ElementsAre;
+    using ::testing::IsEmpty;
+    EXPECT_THAT(gmx::splitDelimitedString("foo;bar", ';'), ElementsAre("foo", "bar"));
+    EXPECT_THAT(gmx::splitDelimitedString(";foo;bar;", ';'), ElementsAre("", "foo", "bar", ""));
+    EXPECT_THAT(gmx::splitDelimitedString("foo;;bar", ';'), ElementsAre("foo", "", "bar"));
+    EXPECT_THAT(gmx::splitDelimitedString("foo", ';'), ElementsAre("foo"));
+    EXPECT_THAT(gmx::splitDelimitedString(";", ';'), ElementsAre("", ""));
+    EXPECT_THAT(gmx::splitDelimitedString("", ';'), IsEmpty());
+}
+
 /********************************************************************
  * Tests for formatString()
  */
diff --git a/src/gromacs/utility/variant.h b/src/gromacs/utility/variant.h
new file mode 100644 (file)
index 0000000..c130bdb
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares gmx::Variant.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_VARIANT_H
+#define GMX_UTILITY_VARIANT_H
+
+#include <memory>
+#include <type_traits>
+#include <typeindex>
+#include <typeinfo>
+#include <utility>
+
+#include "gromacs/utility/gmxassert.h"
+
+namespace gmx
+{
+
+/*! \libinternal \brief
+ * Represents a dynamically typed value of an arbitrary type.
+ *
+ * To create a variant, either initialize it as empty, or with the create()
+ * method (or the equivalent constructor, if the type parameter can be deduced
+ * and is clear to the reader from the context).
+ *
+ * To query the type of the contents in the variant, use isEmpty(), type(), and
+ * isType().
+ *
+ * To access the value, you need to know the type as a compile-time constant
+ * (e.g., through branching based on isType()), and then use cast() or
+ * tryCast().
+ *
+ * Methods in this class do not throw unless otherwise indicated.
+ *
+ * This provides essentially the same functionality as boost::any.
+ *
+ * \ingroup module_utility
+ */
+class Variant
+{
+    public:
+        /*! \brief
+         * Creates a variant that holds the given value.
+         *
+         * \throws std::bad_alloc if out of memory.
+         *
+         * This method allows explicitly specifying the template argument,
+         * contrary to the templated constructor.
+         */
+        template <typename T>
+        static Variant create(const T &value) { return Variant(value); }
+        /*! \brief
+         * Creates a variant that holds the given value.
+         *
+         * \throws std::bad_alloc if out of memory.
+         *
+         * In addition to allowing specifying the template argument, this
+         * method avoids copying when move-construction is possible.
+         */
+        template <typename T>
+        static Variant create(T &&value) { return Variant(std::move(value)); }
+
+        //! Creates an empty variant value.
+        Variant() {}
+        /*! \brief
+         * Creates a variant that holds the given value.
+         *
+         * \throws std::bad_alloc if out of memory.
+         */
+        template <typename T>
+        explicit Variant(const T &value)
+            : content_(new Content<typename std::decay<T>::type>(value))
+        {
+        }
+        /*! \brief
+         * Creates a variant that holds the given value.
+         *
+         * \throws std::bad_alloc if out of memory.
+         */
+        template <typename T>
+        explicit Variant(T &&value)
+            : content_(new Content<typename std::decay<T>::type>(std::move(value)))
+        {
+        }
+        /*! \brief
+         * Creates a deep copy of a variant.
+         *
+         * \throws std::bad_alloc if out of memory.
+         */
+        Variant(const Variant &other) : content_(other.cloneContent()) {}
+        //! Move-constructs a variant.
+        Variant(Variant &&other) noexcept : content_(std::move(other.content_)) {}
+        /*! \brief
+         * Assigns the variant.
+         *
+         * \throws std::bad_alloc if out of memory.
+         */
+        Variant &operator=(const Variant &other)
+        {
+            content_.reset(other.cloneContent());
+            return *this;
+        }
+        //! Move-assigns the variant.
+        Variant &operator=(Variant &&other) noexcept
+        {
+            content_ = std::move(other.content_);
+            return *this;
+        }
+
+        //! Whether any value is stored.
+        bool isEmpty() const { return content_ == nullptr; }
+        //! Returns the dynamic type of the value that is currently stored.
+        std::type_index type() const
+        {
+            const std::type_info &info
+                = !isEmpty() ? content_->typeInfo() : typeid(void);
+            return std::type_index(info);
+        }
+        //! Returns whether the type stored matches the template parameter.
+        template <typename T>
+        bool isType() const
+        {
+            return !isEmpty() && content_->typeInfo() == typeid(T);
+        }
+
+        /*! \brief
+         * Tries to get the value as the given type.
+         *
+         * \tparam T  Type to get.
+         * \returns Pointer to the value, or nullptr if the type does not match
+         *     the stored value.
+         */
+        template <typename T>
+        const T *tryCast() const
+        {
+            return isType<T>() ? &static_cast<Content<T> *>(content_.get())->value_ : nullptr;
+        }
+        /*! \brief
+         * Gets the value when the type is known.
+         *
+         * \tparam T  Type to get (which must match what the variant stores).
+         *
+         * Asserts if the variant is empty or does not contain the requested type.
+         */
+        template <typename T>
+        const T &cast() const
+        {
+            const T *value = tryCast<T>();
+            GMX_RELEASE_ASSERT(value != nullptr, "Cast to incorrect type");
+            return *value;
+        }
+        /*! \brief
+         * Tries to get the value as the given type as a non-const pointer.
+         *
+         * \tparam T  Type to get.
+         * \returns Pointer to the value, or nullptr if the type does not match
+         *     the stored value.
+         *
+         * This method allows modifying the value in-place, which is useful
+         * with more complicated data structures.
+         */
+        template <typename T>
+        T *tryCastRef()
+        {
+            return isType<T>() ? &static_cast<Content<T> *>(content_.get())->value_ : nullptr;
+        }
+        /*! \brief
+         * Gets the value when the type is known as a modifiable reference.
+         *
+         * \tparam T  Type to get (which must match what the variant stores).
+         *
+         * Asserts if the variant is empty or does not contain the requested type.
+         */
+        template <typename T>
+        T &castRef()
+        {
+            T *value = tryCastRef<T>();
+            GMX_RELEASE_ASSERT(value != nullptr, "Cast to incorrect type");
+            return *value;
+        }
+
+    private:
+        class IContent
+        {
+            public:
+                virtual ~IContent() {}
+                virtual const std::type_info &typeInfo() const = 0;
+                virtual IContent *clone() const                = 0;
+        };
+
+        template <typename T>
+        class Content : public IContent
+        {
+            public:
+                explicit Content(const T &value) : value_(value) {}
+                explicit Content(T &&value) : value_(std::move(value)) {}
+
+                virtual const std::type_info &typeInfo() const { return typeid(T); }
+                virtual IContent *clone() const { return new Content(value_); }
+
+                T value_;
+        };
+
+        //! Creates a deep copy of the content.
+        IContent *cloneContent() const
+        {
+            return content_ != nullptr ? content_->clone() : nullptr;
+        }
+
+        std::unique_ptr<IContent> content_;
+};
+
+} // namespace gmx
+
+#endif
index 06c25f321404e012b870cfff79c5044308431b7e..9483763f1bbbbf205ddd8bfdceaa6ca34b7352e9 100644 (file)
@@ -55,7 +55,6 @@
 #include "gromacs/ewald/pme.h"
 #include "gromacs/ewald/pme-load-balancing.h"
 #include "gromacs/fileio/trxio.h"
-#include "gromacs/gmxlib/md_logging.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/gmxlib/nrnb.h"
 #include "gromacs/gpu_utils/gpu_utils.h"
@@ -76,6 +75,7 @@
 #include "gromacs/mdlib/mdebin.h"
 #include "gromacs/mdlib/mdoutf.h"
 #include "gromacs/mdlib/mdrun.h"
+#include "gromacs/mdlib/mdsetup.h"
 #include "gromacs/mdlib/nb_verlet.h"
 #include "gromacs/mdlib/nbnxn_gpu_data_mgmt.h"
 #include "gromacs/mdlib/ns.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/real.h"
 #include "gromacs/utility/smalloc.h"
 
@@ -153,7 +154,7 @@ static void checkNumberOfBondedInteractions(FILE *fplog, t_commrec *cr, int tota
     }
 }
 
-static void reset_all_counters(FILE *fplog, t_commrec *cr,
+static void reset_all_counters(FILE *fplog, const gmx::MDLogger &mdlog, t_commrec *cr,
                                gmx_int64_t step,
                                gmx_int64_t *step_rel, t_inputrec *ir,
                                gmx_wallcycle_t wcycle, t_nrnb *nrnb,
@@ -163,8 +164,9 @@ static void reset_all_counters(FILE *fplog, t_commrec *cr,
     char sbuf[STEPSTRSIZE];
 
     /* Reset all the counters related to performance over the run */
-    md_print_warn(cr, fplog, "step %s: resetting all time and cycle counters\n",
-                  gmx_step_str(step, sbuf));
+    GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+            "step %s: resetting all time and cycle counters",
+            gmx_step_str(step, sbuf));
 
     if (use_GPU(nbv))
     {
@@ -188,7 +190,7 @@ static void reset_all_counters(FILE *fplog, t_commrec *cr,
 }
 
 /*! \libinternal
-    \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,
@@ -207,7 +209,8 @@ static void reset_all_counters(FILE *fplog, t_commrec *cr,
                            unsigned long Flags,
                            gmx_walltime_accounting_t walltime_accounting)
  */
-double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
+double gmx::do_md(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,
@@ -331,7 +334,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
         nstglobalcomm     = 1;
     }
 
-    nstglobalcomm   = check_nstglobalcomm(fplog, cr, nstglobalcomm, ir);
+    nstglobalcomm   = check_nstglobalcomm(mdlog, nstglobalcomm, ir);
     bGStatEveryStep = (nstglobalcomm == 1);
 
     if (bRerunMD)
@@ -419,28 +422,11 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
     }
     else
     {
-        top = gmx_mtop_generate_local_top(top_global, ir->efep != efepNO);
-
         state    = serial_init_local_state(state_global);
 
-        atoms2md(top_global, ir, 0, NULL, top_global->natoms, mdatoms);
-
-        if (vsite)
-        {
-            set_vsite_top(vsite, top, mdatoms, cr);
-        }
-
-        if (ir->ePBC != epbcNONE && !fr->bMolPBC)
-        {
-            graph = mk_graph(fplog, &(top->idef), 0, top_global->natoms, FALSE, FALSE);
-        }
-
-        if (shellfc)
-        {
-            make_local_shells(cr, mdatoms, shellfc);
-        }
-
-        setup_bonded_threading(fr, &top->idef);
+        snew(top, 1);
+        mdAlgorithmsSetupAtomData(cr, ir, top_global, top, fr,
+                                  &graph, mdatoms, vsite, shellfc);
 
         update_realloc(upd, state->nalloc);
     }
@@ -467,7 +453,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
 
     if (ir->bExpanded)
     {
-        init_expanded_ensemble(startingFromCheckpoint, ir, &state->dfhist);
+        init_expanded_ensemble(startingFromCheckpoint, ir, state->dfhist);
     }
 
     if (MASTER(cr))
@@ -511,7 +497,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
                 !(Flags & MD_REPRODUCIBLE));
     if (bPMETune)
     {
-        pme_loadbal_init(&pme_loadbal, cr, fplog, ir, state->box,
+        pme_loadbal_init(&pme_loadbal, cr, mdlog, ir, state->box,
                          fr->ic, fr->pmedata, use_GPU(fr->nbv),
                          &bPMETunePrinting);
     }
@@ -776,15 +762,15 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
     {
         if (!multisim_int_all_are_equal(cr->ms, ir->nsteps))
         {
-            md_print_info(cr, fplog,
-                          "Note: The number of steps is not consistent across multi simulations,\n"
-                          "but we are proceeding anyway!\n");
+            GMX_LOG(mdlog.warning).appendText(
+                    "Note: The number of steps is not consistent across multi simulations,\n"
+                    "but we are proceeding anyway!");
         }
         if (!multisim_int_all_are_equal(cr->ms, ir->init_step))
         {
-            md_print_info(cr, fplog,
-                          "Note: The initial step is not consistent across multi simulations,\n"
-                          "but we are proceeding anyway!\n");
+            GMX_LOG(mdlog.warning).appendText(
+                    "Note: The initial step is not consistent across multi simulations,\n"
+                    "but we are proceeding anyway!");
         }
     }
 
@@ -801,7 +787,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
             /* PME grid + cut-off optimization with GPUs or PME nodes */
             pme_loadbal_do(pme_loadbal, cr,
                            (bVerbose && MASTER(cr)) ? stderr : NULL,
-                           fplog,
+                           fplog, mdlog,
                            ir, fr, state,
                            wcycle,
                            step, step_rel,
@@ -1253,9 +1239,9 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
                statistics, but if performing simulated tempering, we
                do update the velocities and the tau_t. */
 
-            lamnew = ExpandedEnsembleDynamics(fplog, ir, enerd, state, &MassQ, state->fep_state, &state->dfhist, step, state->v, mdatoms);
+            lamnew = ExpandedEnsembleDynamics(fplog, ir, enerd, state, &MassQ, state->fep_state, state->dfhist, step, state->v, mdatoms);
             /* history is maintained in state->dfhist, but state_global is what is sent to trajectory and log output */
-            copy_df_history(&state_global->dfhist, &state->dfhist);
+            copy_df_history(state_global->dfhist, state->dfhist);
         }
 
         /* Now we have the energies and forces corresponding to the
@@ -1601,7 +1587,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
             {
                 /* only needed if doing expanded ensemble */
                 PrintFreeEnergyInfoToFile(fplog, ir->fepvals, ir->expandedvals, ir->bSimTemp ? ir->simtempvals : NULL,
-                                          &state_global->dfhist, state->fep_state, ir->nstlog, step);
+                                          state_global->dfhist, state->fep_state, ir->nstlog, step);
             }
             if (bCalcEner)
             {
@@ -1766,7 +1752,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
                           "resetting counters later in the run, e.g. with gmx "
                           "mdrun -resetstep.", step);
             }
-            reset_all_counters(fplog, cr, step, &step_rel, ir, wcycle, nrnb, walltime_accounting,
+            reset_all_counters(fplog, mdlog, cr, step, &step_rel, ir, wcycle, nrnb, walltime_accounting,
                                use_GPU(fr->nbv) ? fr->nbv : NULL);
             wcycle_set_reset_counters(wcycle, -1);
             if (!(cr->duty & DUTY_PME))
@@ -1819,7 +1805,7 @@ double gmx::do_md(FILE *fplog, t_commrec *cr, int nfile, const t_filenm fnm[],
 
     if (bPMETune)
     {
-        pme_loadbal_done(pme_loadbal, cr, fplog, use_GPU(fr->nbv));
+        pme_loadbal_done(pme_loadbal, fplog, mdlog, use_GPU(fr->nbv));
     }
 
     done_shellfc(fplog, shellfc, step_rel);
index 7829a823a444275ed73b151559277993c710e31e..41f4603d58baa255b791a529057b6862a0cb778b 100644 (file)
@@ -67,6 +67,7 @@
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/utility/arraysize.h"
 #include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/smalloc.h"
 
 #include "mdrun_main.h"
 #include "runner.h"
@@ -449,6 +450,7 @@ int gmx_mdrun(int argc, char *argv[])
     if (!parse_common_args(&argc, argv, PCA_Flags, NFILE, fnm, asize(pa), pa,
                            asize(desc), desc, 0, NULL, &oenv))
     {
+        sfree(cr);
         return 0;
     }
 
index 7d489bb013bb83d98aa92b4e8192181b8bfb0f3f..5e51e7e106f491bfeb05d82f918b1eac1926a98e 100644 (file)
@@ -44,7 +44,6 @@
 
 #include <algorithm>
 
-#include "gromacs/gmxlib/md_logging.h"
 #include "gromacs/hardware/cpuinfo.h"
 #include "gromacs/hardware/detecthardware.h"
 #include "gromacs/hardware/gpu_hw_info.h"
@@ -57,6 +56,7 @@
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/stringutil.h"
 
 
@@ -258,7 +258,7 @@ static int get_tmpi_omp_thread_division(const gmx_hw_info_t *hwinfo,
 }
 
 
-static int getMaxGpuUsable(FILE *fplog, const t_commrec *cr, const gmx_hw_info_t *hwinfo,
+static int getMaxGpuUsable(const gmx::MDLogger &mdlog, const gmx_hw_info_t *hwinfo,
                            int cutoff_scheme, gmx_bool bUseGpu)
 {
     /* This code relies on the fact that GPU are not detected when GPU
@@ -276,7 +276,7 @@ static int getMaxGpuUsable(FILE *fplog, const t_commrec *cr, const gmx_hw_info_t
         {
             if (hwinfo->gpu_info.n_dev_compatible > 1)
             {
-                md_print_warn(cr, fplog, "More than one compatible GPU is available, but GROMACS can only use one of them. Using a single thread-MPI rank.\n");
+                GMX_LOG(mdlog.warning).asParagraph().appendText("More than one compatible GPU is available, but GROMACS can only use one of them. Using a single thread-MPI rank.");
             }
             return 1;
         }
@@ -345,8 +345,7 @@ int get_nthreads_mpi(const gmx_hw_info_t *hwinfo,
                      gmx_hw_opt_t        *hw_opt,
                      const t_inputrec    *inputrec,
                      const gmx_mtop_t    *mtop,
-                     const t_commrec     *cr,
-                     FILE                *fplog,
+                     const gmx::MDLogger &mdlog,
                      gmx_bool             bUseGpu,
                      bool                 doMembed)
 {
@@ -372,7 +371,7 @@ int get_nthreads_mpi(const gmx_hw_info_t *hwinfo,
             {
                 gmx_fatal(FARGS, "%s However, you asked for more than 1 thread-MPI rank, so mdrun cannot continue. Choose a single rank, or a different algorithm.", message.c_str());
             }
-            md_print_warn(cr, fplog, "%s Choosing to use only a single thread-MPI rank.", message.c_str());
+            GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted("%s Choosing to use only a single thread-MPI rank.", message.c_str());
             return 1;
         }
     }
@@ -401,7 +400,7 @@ int get_nthreads_mpi(const gmx_hw_info_t *hwinfo,
         nthreads_tot_max = nthreads_hw;
     }
 
-    ngpu = getMaxGpuUsable(fplog, cr, hwinfo, inputrec->cutoff_scheme, bUseGpu);
+    ngpu = getMaxGpuUsable(mdlog, hwinfo, inputrec->cutoff_scheme, bUseGpu);
 
     if (inputrec->cutoff_scheme == ecutsGROUP)
     {
@@ -523,7 +522,7 @@ void check_resource_division_efficiency(const gmx_hw_info_t *hwinfo,
                                         const gmx_hw_opt_t  *hw_opt,
                                         gmx_bool             bNtOmpOptionSet,
                                         t_commrec           *cr,
-                                        FILE                *fplog)
+                                        const gmx::MDLogger &mdlog)
 {
 #if GMX_OPENMP && GMX_MPI
     int         nth_omp_min, nth_omp_max, ngpu;
@@ -592,7 +591,7 @@ void check_resource_division_efficiency(const gmx_hw_info_t *hwinfo,
 
             if (bNtOmpOptionSet)
             {
-                md_print_warn(cr, fplog, "NOTE: %s\n", buf);
+                GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted("NOTE: %s", buf);
             }
             else
             {
@@ -640,7 +639,7 @@ void check_resource_division_efficiency(const gmx_hw_info_t *hwinfo,
              */
             if (bNtOmpOptionSet || (bEnvSet && nth_omp_min != nth_omp_max))
             {
-                md_print_warn(cr, fplog, "NOTE: %s\n", buf);
+                GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted("NOTE: %s", buf);
             }
             else
             {
@@ -652,20 +651,14 @@ void check_resource_division_efficiency(const gmx_hw_info_t *hwinfo,
       /* No OpenMP and/or MPI: it doesn't make much sense to check */
     GMX_UNUSED_VALUE(hw_opt);
     GMX_UNUSED_VALUE(bNtOmpOptionSet);
+    GMX_UNUSED_VALUE(cr);
     /* Check if we have more than 1 physical core, if detected,
      * or more than 1 hardware thread if physical cores were not detected.
      */
-#if !GMX_OPENMP && !GMX_MPI
-    if (hwinfo->hardwareTopology->numberOfCores() > 1)
+    if (!GMX_OPENMP && !GMX_MPI && hwinfo->hardwareTopology->numberOfCores() > 1)
     {
-        md_print_warn(cr, fplog, "NOTE: GROMACS was compiled without OpenMP and (thread-)MPI support, can only use a single CPU core\n");
+        GMX_LOG(mdlog.warning).asParagraph().appendText("NOTE: GROMACS was compiled without OpenMP and (thread-)MPI support, can only use a single CPU core");
     }
-#else
-    GMX_UNUSED_VALUE(hwinfo);
-    GMX_UNUSED_VALUE(cr);
-    GMX_UNUSED_VALUE(fplog);
-#endif
-
 #endif /* GMX_OPENMP && GMX_MPI */
 }
 
index 0f292aaf63a56386dd871da8ae4b356d53c863fb..5da5c2020c529318f549172d0e72aad7d3a7d3cf 100644 (file)
@@ -46,6 +46,11 @@ struct gmx_mtop_t;
 struct t_commrec;
 struct t_inputrec;
 
+namespace gmx
+{
+class MDLogger;
+}
+
 /* Return the number of threads to use for thread-MPI based on how many
  * were requested, which algorithms we're using,
  * and how many particles there are.
@@ -58,8 +63,7 @@ int get_nthreads_mpi(const gmx_hw_info_t *hwinfo,
                      gmx_hw_opt_t        *hw_opt,
                      const t_inputrec    *inputrec,
                      const gmx_mtop_t    *mtop,
-                     const t_commrec     *cr,
-                     FILE                *fplog,
+                     const gmx::MDLogger &mdlog,
                      gmx_bool             bUseGpu,
                      bool                 doMembed);
 
@@ -74,8 +78,8 @@ int get_nthreads_mpi(const gmx_hw_info_t *hwinfo,
 void check_resource_division_efficiency(const gmx_hw_info_t *hwinfo,
                                         const gmx_hw_opt_t  *hw_opt,
                                         gmx_bool             bNtOmpOptionSet,
-                                        struct t_commrec    *cr,
-                                        FILE                *fplog);
+                                        t_commrec           *cr,
+                                        const gmx::MDLogger &mdlog);
 
 /* Checks we can do when we don't (yet) know the cut-off scheme */
 void check_and_update_hw_opt_1(gmx_hw_opt_t    *hw_opt,
index 560b923ba600d4304b2eea72a1a5d76b7a1f6bfa..8fa892bfffd3764dbc82bab1f4797711a0f4832d 100644 (file)
@@ -62,7 +62,6 @@
 #include "gromacs/fileio/checkpoint.h"
 #include "gromacs/fileio/oenv.h"
 #include "gromacs/fileio/tpxio.h"
-#include "gromacs/gmxlib/md_logging.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/gpu_utils/gpu_utils.h"
 #include "gromacs/hardware/cpuinfo.h"
@@ -89,6 +88,7 @@
 #include "gromacs/mdlib/sighandler.h"
 #include "gromacs/mdlib/sim_util.h"
 #include "gromacs/mdlib/tpi.h"
+#include "gromacs/mdrunutility/mdmodules.h"
 #include "gromacs/mdrunutility/threadaffinity.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/filestream.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/gmxmpi.h"
+#include "gromacs/utility/logger.h"
+#include "gromacs/utility/loggerbuilder.h"
 #include "gromacs/utility/pleasecite.h"
 #include "gromacs/utility/smalloc.h"
 
@@ -597,13 +600,11 @@ static void prepare_verlet_scheme(FILE                           *fplog,
  *
  * with value passed on the command line (if any)
  */
-static void override_nsteps_cmdline(FILE            *fplog,
-                                    gmx_int64_t      nsteps_cmdline,
-                                    t_inputrec      *ir,
-                                    const t_commrec *cr)
+static void override_nsteps_cmdline(const gmx::MDLogger &mdlog,
+                                    gmx_int64_t          nsteps_cmdline,
+                                    t_inputrec          *ir)
 {
     assert(ir);
-    assert(cr);
 
     /* override with anything else than the default -2 */
     if (nsteps_cmdline > -2)
@@ -624,7 +625,7 @@ static void override_nsteps_cmdline(FILE            *fplog,
                     gmx_step_str(nsteps_cmdline, sbuf_steps));
         }
 
-        md_print_warn(cr, fplog, "%s\n", sbuf_msg);
+        GMX_LOG(mdlog.warning).asParagraph().appendText(sbuf_msg);
     }
     else if (nsteps_cmdline < -2)
     {
@@ -674,6 +675,22 @@ static integrator_t *my_integrator(unsigned int ei)
     }
 }
 
+//! Initializes the logger for mdrun.
+static gmx::LoggerOwner buildLogger(FILE *fplog, const t_commrec *cr)
+{
+    gmx::LoggerBuilder builder;
+    if (fplog != NULL)
+    {
+        builder.addTargetFile(gmx::MDLogger::LogLevel::Info, fplog);
+    }
+    if (cr == nullptr || SIMMASTER(cr))
+    {
+        builder.addTargetStream(gmx::MDLogger::LogLevel::Warning,
+                                &gmx::TextOutputFile::standardError());
+    }
+    return builder.build();
+}
+
 int mdrunner(gmx_hw_opt_t *hw_opt,
              FILE *fplog, t_commrec *cr, int nfile,
              const t_filenm fnm[], const gmx_output_env_t *oenv, gmx_bool bVerbose,
@@ -717,7 +734,8 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
 
     /* CAUTION: threads may be started later on in this function, so
        cr doesn't reflect the final parallel state right now */
-    snew(inputrec, 1);
+    gmx::MDModules mdModules;
+    inputrec = mdModules.inputrec();
     snew(mtop, 1);
 
     if (Flags & MD_APPENDFILES)
@@ -730,11 +748,16 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
     bForceUseGPU = (strncmp(nbpu_opt, "gpu", 3) == 0);
     bTryUseGPU   = (strncmp(nbpu_opt, "auto", 4) == 0) || bForceUseGPU;
 
+    // Here we assume that SIMMASTER(cr) does not change even after the
+    // threads are started.
+    gmx::LoggerOwner logOwner(buildLogger(fplog, cr));
+    gmx::MDLogger    mdlog(logOwner.logger());
+
     /* Detect hardware, gather information. This is an operation that is
      * global for this process (MPI rank). */
-    hwinfo = gmx_detect_hardware(fplog, cr, bTryUseGPU);
+    hwinfo = gmx_detect_hardware(mdlog, cr, bTryUseGPU);
 
-    gmx_print_detected_hardware(fplog, cr, hwinfo);
+    gmx_print_detected_hardware(fplog, cr, mdlog, hwinfo);
 
     if (fplog != NULL)
     {
@@ -766,7 +789,7 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
              * update the message text and the content of nbnxn_acceleration_supported.
              */
             if (bUseGPU &&
-                !nbnxn_gpu_acceleration_supported(fplog, cr, inputrec, bRerunMD))
+                !nbnxn_gpu_acceleration_supported(mdlog, inputrec, bRerunMD))
             {
                 /* Fallback message printed by nbnxn_acceleration_supported */
                 if (bForceUseGPU)
@@ -789,9 +812,9 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
 
             if (hwinfo->gpu_info.n_dev_compatible > 0)
             {
-                md_print_warn(cr, fplog,
-                              "NOTE: GPU(s) found, but the current simulation can not use GPUs\n"
-                              "      To use a GPU, set the mdp option: cutoff-scheme = Verlet\n");
+                GMX_LOG(mdlog.warning).asParagraph().appendText(
+                        "NOTE: GPU(s) found, but the current simulation can not use GPUs\n"
+                        "      To use a GPU, set the mdp option: cutoff-scheme = Verlet");
             }
 
             if (bForceUseGPU)
@@ -812,7 +835,7 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
     check_and_update_hw_opt_1(hw_opt, cr, npme);
 
     /* Early check for externally set process affinity. */
-    gmx_check_thread_affinity_set(fplog, cr,
+    gmx_check_thread_affinity_set(mdlog, cr,
                                   hw_opt, hwinfo->nthreads_hw_avail, FALSE);
 
 #if GMX_THREAD_MPI
@@ -833,7 +856,7 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
         hw_opt->nthreads_tmpi = get_nthreads_mpi(hwinfo,
                                                  hw_opt,
                                                  inputrec, mtop,
-                                                 cr, fplog, bUseGPU,
+                                                 mdlog, bUseGPU,
                                                  doMembed);
 
         if (hw_opt->nthreads_tmpi > 1)
@@ -996,14 +1019,16 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
         }
     }
 
-    if (MASTER(cr) && (Flags & MD_APPENDFILES))
+    if (SIMMASTER(cr) && (Flags & MD_APPENDFILES))
     {
         gmx_log_open(ftp2fn(efLOG, nfile, fnm), cr,
                      Flags, &fplog);
+        logOwner = buildLogger(fplog, nullptr);
+        mdlog    = logOwner.logger();
     }
 
     /* override nsteps with value from cmdline */
-    override_nsteps_cmdline(fplog, nsteps_cmdline, inputrec, cr);
+    override_nsteps_cmdline(mdlog, nsteps_cmdline, inputrec);
 
     if (SIMMASTER(cr))
     {
@@ -1066,19 +1091,20 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
 #if GMX_MPI
     if (MULTISIM(cr))
     {
-        md_print_info(cr, fplog,
-                      "This is simulation %d out of %d running as a composite GROMACS\n"
-                      "multi-simulation job. Setup for this simulation:\n\n",
-                      cr->ms->sim, cr->ms->nsim);
+        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+                "This is simulation %d out of %d running as a composite GROMACS\n"
+                "multi-simulation job. Setup for this simulation:\n",
+                cr->ms->sim, cr->ms->nsim);
     }
-    md_print_info(cr, fplog, "Using %d MPI %s\n",
-                  cr->nnodes,
+    GMX_LOG(mdlog.warning).appendTextFormatted(
+            "Using %d MPI %s\n",
+            cr->nnodes,
 #if GMX_THREAD_MPI
-                  cr->nnodes == 1 ? "thread" : "threads"
+            cr->nnodes == 1 ? "thread" : "threads"
 #else
-                  cr->nnodes == 1 ? "process" : "processes"
+            cr->nnodes == 1 ? "process" : "processes"
 #endif
-                  );
+            );
     fflush(stderr);
 #endif
 
@@ -1088,7 +1114,7 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
     /* Check and update hw_opt for the number of MPI ranks */
     check_and_update_hw_opt_3(hw_opt);
 
-    gmx_omp_nthreads_init(fplog, cr,
+    gmx_omp_nthreads_init(mdlog, cr,
                           hwinfo->nthreads_hw_avail,
                           hw_opt->nthreads_omp,
                           hw_opt->nthreads_omp_pme,
@@ -1106,7 +1132,7 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
     if (bUseGPU)
     {
         /* Select GPU id's to use */
-        gmx_select_gpu_ids(fplog, cr, &hwinfo->gpu_info, bForceUseGPU,
+        gmx_select_gpu_ids(mdlog, cr, &hwinfo->gpu_info, bForceUseGPU,
                            &hw_opt->gpu_opt);
     }
     else
@@ -1117,11 +1143,11 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
 
     /* check consistency across ranks of things like SIMD
      * support and number of GPUs selected */
-    gmx_check_hw_runconf_consistency(fplog, hwinfo, cr, hw_opt, bUseGPU);
+    gmx_check_hw_runconf_consistency(mdlog, hwinfo, cr, hw_opt, bUseGPU);
 
     /* Now that we know the setup is consistent, check for efficiency */
     check_resource_division_efficiency(hwinfo, hw_opt, Flags & MD_NTOMPSET,
-                                       cr, fplog);
+                                       cr, mdlog);
 
     if (DOMAINDECOMP(cr))
     {
@@ -1168,7 +1194,7 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
         fr          = mk_forcerec();
         fr->hwinfo  = hwinfo;
         fr->gpu_opt = &hw_opt->gpu_opt;
-        init_forcerec(fplog, fr, fcd, inputrec, mtop, cr, box,
+        init_forcerec(fplog, mdlog, fr, fcd, inputrec, mtop, cr, box,
                       opt2fn("-table", nfile, fnm),
                       opt2fn("-tablep", nfile, fnm),
                       getFilenm("-tableb", nfile, fnm),
@@ -1243,11 +1269,23 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
          * - which indicates that probably the OpenMP library has changed it
          * since we first checked).
          */
-        gmx_check_thread_affinity_set(fplog, cr,
+        gmx_check_thread_affinity_set(mdlog, cr,
                                       hw_opt, hwinfo->nthreads_hw_avail, TRUE);
 
+        int nthread_local;
+        /* threads on this MPI process or TMPI thread */
+        if (cr->duty & DUTY_PP)
+        {
+            nthread_local = gmx_omp_nthreads_get(emntNonbonded);
+        }
+        else
+        {
+            nthread_local = gmx_omp_nthreads_get(emntPME);
+        }
+
         /* Set the CPU affinity */
-        gmx_set_thread_affinity(fplog, cr, hw_opt, hwinfo);
+        gmx_set_thread_affinity(fplog, mdlog, cr, hw_opt, *hwinfo->hardwareTopology,
+                                nthread_local, nullptr);
     }
 
     /* Initiate PME if necessary,
@@ -1273,7 +1311,9 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
         {
             status = gmx_pme_init(pmedata, cr, npme_major, npme_minor, inputrec,
                                   mtop ? mtop->natoms : 0, nChargePerturbed, nTypePerturbed,
-                                  (Flags & MD_REPRODUCIBLE), nthreads_pme);
+                                  (Flags & MD_REPRODUCIBLE),
+                                  ewaldcoeff_q, ewaldcoeff_lj,
+                                  nthreads_pme);
             if (status != 0)
             {
                 gmx_fatal(FARGS, "Error %d initializing PME", status);
@@ -1326,7 +1366,7 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
         }
 
         /* Now do whatever the user wants us to do (how flexible...) */
-        my_integrator(inputrec->eI) (fplog, cr, nfile, fnm,
+        my_integrator(inputrec->eI) (fplog, cr, mdlog, nfile, fnm,
                                      oenv, bVerbose,
                                      nstglobalcomm,
                                      vsite, constr,
@@ -1364,11 +1404,17 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
     /* Finish up, write some stuff
      * if rerunMD, don't write last frame again
      */
-    finish_run(fplog, cr,
+    finish_run(fplog, mdlog, cr,
                inputrec, nrnb, wcycle, walltime_accounting,
                fr ? fr->nbv : NULL,
                EI_DYNAMICS(inputrec->eI) && !MULTISIM(cr));
 
+    // Free PME data
+    if (pmedata)
+    {
+        gmx_pme_destroy(pmedata);
+        pmedata = NULL;
+    }
 
     /* Free GPU memory and context */
     free_gpu_resources(fr, cr, &hwinfo->gpu_info, fr ? fr->gpu_opt : NULL);
index 6c5270d3e919639328fb87b9b83bd90aac04afa4..d4763d2f7b25a3422fe4192b104d1655cca79f27 100644 (file)
@@ -60,10 +60,7 @@ gmx_add_gtest_executable(
     # pseudo-library for code for mdrun
     $<TARGET_OBJECTS:mdrun_objlib>
     )
-gmx_register_integration_test(
-    ${testname}
-    ${exename}
-    )
+gmx_register_gtest_test(${testname} ${exename} INTEGRATION_TEST)
 
 set(testname "MdrunMpiTests")
 set(exename "mdrun-mpi-test")
@@ -80,8 +77,4 @@ gmx_add_gtest_executable(
     # pseudo-library for code for mdrun
     $<TARGET_OBJECTS:mdrun_objlib>
     )
-gmx_register_mpi_integration_test(
-    ${testname}
-    ${exename}
-    2
-    )
+gmx_register_gtest_test(${testname} ${exename} MPI_RANKS 2 INTEGRATION_TEST)
index cf1c3ada4ba36f10ee4f030eba1192600862ecbb..5d0760448b990ef85eb5a11b27990d11624cc226 100644 (file)
@@ -59,6 +59,7 @@
 
 #include "testutils/cmdlinetest.h"
 #include "testutils/integrationtests.h"
+#include "testutils/mpitest.h"
 #include "testutils/testoptions.h"
 
 namespace gmx
@@ -73,10 +74,6 @@ namespace test
 namespace
 {
 
-#if GMX_THREAD_MPI || defined(DOXYGEN)
-//! Number of tMPI threads for child mdrun call.
-int g_numThreads = 1;
-#endif
 #if GMX_OPENMP || defined(DOXYGEN)
 //! Number of OpenMP threads for child mdrun call.
 int g_numOpenMPThreads = 1;
@@ -85,10 +82,6 @@ int g_numOpenMPThreads = 1;
 GMX_TEST_OPTIONS(MdrunTestOptions, options)
 {
     GMX_UNUSED_VALUE(options);
-#if GMX_THREAD_MPI
-    options->addOption(IntegerOption("nt").store(&g_numThreads)
-                           .description("Number of thread-MPI threads/ranks for child mdrun calls"));
-#endif
 #if GMX_OPENMP
     options->addOption(IntegerOption("nt_omp").store(&g_numOpenMPThreads)
                            .description("Number of OpenMP threads for child mdrun calls"));
@@ -237,18 +230,14 @@ SimulationRunner::callMdrun(const CommandLine &callerRef)
 
 #if GMX_MPI
 #  if GMX_GPU != GMX_GPU_NONE
-#    if GMX_THREAD_MPI
-    int         numGpusNeeded = g_numThreads;
-#    else   /* Must be real MPI */
-    int         numGpusNeeded = gmx_node_num();
-#    endif
+    const int   numGpusNeeded = getNumberOfTestMpiRanks();
     std::string gpuIdString(numGpusNeeded, '0');
     caller.addOption("-gpu_id", gpuIdString.c_str());
 #  endif
 #endif
 
 #if GMX_THREAD_MPI
-    caller.addOption("-ntmpi", g_numThreads);
+    caller.addOption("-ntmpi", getNumberOfTestMpiRanks());
 #endif
 
 #if GMX_OPENMP
@@ -262,14 +251,7 @@ SimulationRunner::callMdrun(const CommandLine &callerRef)
      * node regardless of the number of ranks, because that's true in
      * Jenkins and for most developers running the tests. */
     int numberOfNodes = 1;
-#if GMX_THREAD_MPI
-    /* Can't use gmx_node_num() because it is only valid after spawn of thread-MPI threads */
-    int numberOfRanks = g_numThreads;
-#elif GMX_LIB_MPI
-    int numberOfRanks = gmx_node_num();
-#else
-    int numberOfRanks = 1;
-#endif
+    int numberOfRanks = getNumberOfTestMpiRanks();
     if (numberOfRanks > numberOfNodes && !gmx_multiple_gpu_per_node_supported())
     {
         if (gmx_node_rank() == 0)
index 2bd34f4b64dc1b13c057bc8cbc2ed17eabf7fbc6..a78e325931fdc2f55d6fa2c7692266c22fbfa202 100644 (file)
 # To help us fund GROMACS development, we humbly ask that you cite
 # the research papers on the package. Check out http://www.gromacs.org.
 
+if (NOT GMX_BUILD_UNITTESTS)
+    gmx_add_missing_tests_notice("Unit tests have not been run. You need to set GMX_BUILD_UNITTESTS=ON if you want to build and run them.")
+    return()
+endif()
+
 include_directories(BEFORE SYSTEM ${GMOCK_INCLUDE_DIRS})
 set(TESTUTILS_SOURCES
     cmdlinetest.cpp
     integrationtests.cpp
     interactivetest.cpp
     mpi-printer.cpp
+    mpitest.cpp
     refdata.cpp
     refdata-xml.cpp
     stringtest.cpp
@@ -67,8 +73,35 @@ else()
     include_directories(BEFORE SYSTEM "../external/tinyxml2")
 endif()
 
+# TODO Use gmx_add_missing_tests_notice() instead of the messages below.
+set(GMX_CAN_RUN_MPI_TESTS 1)
+if (GMX_MPI)
+    set(_an_mpi_variable_had_content 0)
+    foreach(VARNAME MPIEXEC MPIEXEC_NUMPROC_FLAG MPIEXEC_PREFLAGS MPIEXEC_POSTFLAGS)
+        # These variables need a valid value for the test to run
+        # and pass, but conceivably any of them might be valid
+        # with arbitrary (including empty) content. They can't be
+        # valid if they've been populated with the CMake
+        # find_package magic suffix/value "NOTFOUND", though.
+        if (${VARNAME} MATCHES ".*NOTFOUND")
+            message(STATUS "CMake variable ${VARNAME} was not detected to be a valid value. To test GROMACS correctly, check the advice in the install guide.")
+            set(GMX_CAN_RUN_MPI_TESTS 0)
+        endif()
+        if (NOT VARNAME STREQUAL MPIEXEC AND ${VARNAME})
+            set(_an_mpi_variable_had_content 1)
+        endif()
+    endforeach()
+    if(_an_mpi_variable_had_content AND NOT MPIEXEC)
+        message(STATUS "CMake variable MPIEXEC must have a valid value if one of the other related MPIEXEC variables does. To test GROMACS correctly, check the advice in the install guide.")
+        set(GMX_CAN_RUN_MPI_TESTS 0)
+    endif()
+elseif (NOT GMX_THREAD_MPI)
+    set(GMX_CAN_RUN_MPI_TESTS 0)
+endif()
+
 set(TESTUTILS_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 set(TESTUTILS_DIR ${TESTUTILS_DIR} PARENT_SCOPE)
 set(TESTUTILS_LIBS ${TESTUTILS_LIBS} PARENT_SCOPE)
+set(GMX_CAN_RUN_MPI_TESTS ${GMX_CAN_RUN_MPI_TESTS} PARENT_SCOPE)
 
 add_subdirectory(tests)
index faff8af3d290a8416d7635334253bbfd31806762..c351d13cb09c7721e01b193832a78d5e90e72722 100644 (file)
@@ -81,87 +81,61 @@ function (gmx_add_gtest_executable EXENAME)
     endif()
 endfunction()
 
-function (gmx_register_unit_test NAME EXENAME)
-    if (GMX_BUILD_UNITTESTS AND BUILD_TESTING)
-        add_test(NAME ${NAME}
-                 COMMAND ${EXENAME} --gtest_output=xml:${CMAKE_BINARY_DIR}/Testing/Temporary/${NAME}.xml)
-        set_tests_properties(${NAME} PROPERTIES LABELS "GTest;UnitTest")
-        add_dependencies(tests ${EXENAME})
-    endif()
-endfunction ()
-
-# Use this function to register a test binary as an integration test
-function (gmx_register_integration_test NAME EXENAME)
-    if (GMX_BUILD_UNITTESTS AND BUILD_TESTING)
-        add_test(NAME ${NAME}
-                 COMMAND ${EXENAME} --gtest_output=xml:${CMAKE_BINARY_DIR}/Testing/Temporary/${NAME}.xml)
-        set_tests_properties(${testname} PROPERTIES LABELS "IntegrationTest")
-        add_dependencies(tests ${EXENAME})
-
-        # GMX_EXTRA_LIBRARIES might be needed for mdrun integration tests at
-        # some point.
-        # target_link_libraries(${EXENAME} ${GMX_EXTRA_LIBRARIES} ${GMX_STDLIB_LIBRARIES})
-    endif()
-endfunction ()
-
-# Use this function to register a test binary as an integration test
-# that requires MPI. The intended number of MPI ranks is also passed
+# Use this function with MPI_RANKS <N> INTEGRATION_TEST to register a test
+# binary as an integration test that requires MPI. The intended number of MPI
+# ranks is also passed
 #
-# TODO When a test case needs it, generalize the NUMPROC mechanism so
+# TODO When a test case needs it, generalize the MPI_RANKS mechanism so
 # that ctest can run the test binary over a range of numbers of MPI
 # ranks.
-function (gmx_register_mpi_integration_test NAME EXENAME NUMPROC)
+function (gmx_register_gtest_test NAME EXENAME)
     if (GMX_BUILD_UNITTESTS AND BUILD_TESTING)
-        if (GMX_MPI)
-            foreach(VARNAME MPIEXEC MPIEXEC_NUMPROC_FLAG MPIEXEC_PREFLAGS MPIEXEC_POSTFLAGS)
-                # These variables need a valid value for the test to run
-                # and pass, but conceivably any of them might be valid
-                # with arbitrary (including empty) content. They can't be
-                # valid if they've been populated with the CMake
-                # find_package magic suffix/value "NOTFOUND", though.
-                if (${VARNAME} MATCHES ".*NOTFOUND")
-                    message(STATUS "CMake variable ${VARNAME} was not detected to be a valid value. To test GROMACS correctly, check the advice in the install guide.")
-                    set(_cannot_run_mpi_tests 1)
-                endif()
-                if (NOT VARNAME STREQUAL MPIEXEC AND ${VARNAME})
-                    set(_an_mpi_variable_had_content 1)
-                endif()
-            endforeach()
-            if(_an_mpi_variable_had_content AND NOT MPIEXEC)
-                message(STATUS "CMake variable MPIEXEC must have a valid value if one of the other related MPIEXEC variables does. To test GROMACS correctly, check the advice in the install guide.")
-                set(_cannot_run_mpi_tests 1)
-            endif()
-            if(NOT _cannot_run_mpi_tests)
-                add_test(NAME ${NAME}
-                    COMMAND
-                    ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${NUMPROC}
-                    ${MPIEXEC_PREFLAGS} $<TARGET_FILE:${EXENAME}> ${MPIEXEC_POSTFLAGS}
-                    --gtest_output=xml:${CMAKE_BINARY_DIR}/Testing/Temporary/${NAME}.xml
-                    )
-                set_tests_properties(${testname} PROPERTIES LABELS "MpiIntegrationTest")
-                add_dependencies(tests ${EXENAME})
-            endif()
-
-            # GMX_EXTRA_LIBRARIES might be needed for mdrun integration tests at
-            # some point.
-            # target_link_libraries(${EXENAME} ${GMX_EXTRA_LIBRARIES} ${GMX_STDLIB_LIBRARIES})
-        elseif(GMX_THREAD_MPI)
-            add_test(NAME ${NAME}
-                COMMAND
-                $<TARGET_FILE:${EXENAME}> -nt ${NUMPROC}
-                --gtest_output=xml:${CMAKE_BINARY_DIR}/Testing/Temporary/${NAME}.xml
-                )
-            set_tests_properties(${testname} PROPERTIES LABELS "MpiIntegrationTest")
-            add_dependencies(tests ${EXENAME})
+        set(_options INTEGRATION_TEST)
+        set(_one_value_args MPI_RANKS)
+        cmake_parse_arguments(ARG "${_options}" "${_one_value_args}" "" ${ARGN})
+        set(_xml_path ${CMAKE_BINARY_DIR}/Testing/Temporary/${NAME}.xml)
+        set(_cmd ${EXENAME})
+        set(_labels GTest)
+        set(_timeout 30)
+        if (ARG_INTEGRATION_TEST)
+            list(APPEND _labels IntegrationTest)
+            set(_timeout 120)
 
             # GMX_EXTRA_LIBRARIES might be needed for mdrun integration tests at
             # some point.
             # target_link_libraries(${EXENAME} ${GMX_EXTRA_LIBRARIES} ${GMX_STDLIB_LIBRARIES})
+        else()
+            list(APPEND _labels UnitTest)
         endif()
+        if (ARG_MPI_RANKS)
+            if (NOT GMX_CAN_RUN_MPI_TESTS)
+                return()
+            endif()
+            list(APPEND _labels MpiTest)
+            if (GMX_MPI)
+                set(_cmd
+                    ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${ARG_MPI_RANKS}
+                    ${MPIEXEC_PREFLAGS} $<TARGET_FILE:${EXENAME}> ${MPIEXEC_POSTFLAGS})
+            elseif (GMX_THREAD_MPI)
+                list(APPEND _cmd -ntmpi ${ARG_MPI_RANKS})
+            endif()
+        endif()
+        add_test(NAME ${NAME}
+                 COMMAND ${_cmd} --gtest_output=xml:${_xml_path})
+        set_tests_properties(${NAME} PROPERTIES LABELS "${_labels}")
+        set_tests_properties(${NAME} PROPERTIES TIMEOUT ${_timeout})
+        add_dependencies(tests ${EXENAME})
     endif()
 endfunction ()
 
 function (gmx_add_unit_test NAME EXENAME)
     gmx_add_gtest_executable(${EXENAME} ${ARGN})
-    gmx_register_unit_test(${NAME} ${EXENAME})
+    gmx_register_gtest_test(${NAME} ${EXENAME})
+endfunction()
+
+function (gmx_add_mpi_unit_test NAME EXENAME RANKS)
+    if (GMX_MPI OR (GMX_THREAD_MPI AND GTEST_IS_THREADSAFE))
+        gmx_add_gtest_executable(${EXENAME} MPI ${ARGN})
+        gmx_register_gtest_test(${NAME} ${EXENAME} MPI_RANKS ${RANKS})
+    endif()
 endfunction()
index d70187ea534dda0b7a83c88fb1c3f11e13b5fdbe..eb05df8a9bf31eb6c8b91fc61e229ffb77b624a9 100644 (file)
@@ -358,8 +358,7 @@ void CommandLineTestHelper::setOutputFile(
     }
     std::string fullFilename = impl_->fileManager_.getTemporaryFilePath(suffix);
     args->addOption(option, fullFilename);
-    impl_->outputFiles_.push_back(
-            Impl::OutputFileInfo(option, fullFilename, matcher.createMatcher()));
+    impl_->outputFiles_.emplace_back(option, fullFilename, matcher.createMatcher());
 }
 
 void CommandLineTestHelper::checkOutputFiles(TestReferenceChecker checker) const
index ce8c8541b52d659ddd71e88ca789ff3ed78a9f3a..da76c52d454f96125bff7d5bf5c9edfd6338abe1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016, 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.
@@ -122,19 +122,14 @@ class InteractiveTestHelper::Impl
 
         void checkOutput()
         {
-            const std::string id = formatString("Output%d", static_cast<int>(currentLine_));
-            if (checker_.checkPresent(bHasOutput_, id.c_str()))
+            if (bHasOutput_)
             {
+                const std::string id = formatString("Output%d", static_cast<int>(currentLine_));
                 StringTestBase::checkText(&checker_, currentOutput_, id.c_str());
+                bHasOutput_ = false;
             }
-            bHasOutput_ = false;
             currentOutput_.clear();
         }
-        void checkPendingInput()
-        {
-            const std::string id = formatString("Input%d", static_cast<int>(currentLine_+1));
-            checker_.checkPresent(false, id.c_str());
-        }
 
         TestReferenceChecker             checker_;
         ConstArrayRef<const char *>      inputLines_;
@@ -180,7 +175,7 @@ TextOutputStream &InteractiveTestHelper::outputStream()
 void InteractiveTestHelper::checkSession()
 {
     impl_->checkOutput();
-    impl_->checkPendingInput();
+    impl_->checker_.checkUnusedEntries();
 }
 
 } // namespace test
diff --git a/src/testutils/mpitest.cpp b/src/testutils/mpitest.cpp
new file mode 100644 (file)
index 0000000..959b9c5
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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.
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions in mpitest.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_testutils
+ */
+#include "gmxpre.h"
+
+#include "mpitest.h"
+
+#include "config.h"
+
+#include <gtest/gtest.h>
+
+#include "thread_mpi/tmpi.h"
+
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/ioptionscontainer.h"
+#include "gromacs/utility/basenetwork.h"
+#include "gromacs/utility/exceptions.h"
+
+#include "testutils/testoptions.h"
+
+namespace gmx
+{
+namespace test
+{
+
+#if GMX_THREAD_MPI
+
+namespace
+{
+
+//! Number of tMPI threads.
+int g_numThreads = 1;
+//! \cond
+GMX_TEST_OPTIONS(ThreadMpiTestOptions, options)
+{
+    options->addOption(IntegerOption("ntmpi").store(&g_numThreads)
+                           .description("Number of thread-MPI threads/ranks for the test"));
+}
+//! \endcond
+
+//! Thread entry function for other thread-MPI threads.
+void threadStartFunc(void *data)
+{
+    std::function<void()> &testBody = *reinterpret_cast<std::function<void()> *>(data);
+    try
+    {
+        testBody();
+    }
+    GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
+}
+
+//! Helper function for starting thread-MPI threads for a test.
+bool startThreads(std::function<void()> *testBody)
+{
+    int ret = tMPI_Init_fn(TRUE, g_numThreads, TMPI_AFFINITY_NONE,
+                           threadStartFunc, testBody);
+    return ret == TMPI_SUCCESS;
+}
+
+class InTestGuard
+{
+    public:
+        explicit InTestGuard(bool *inTest) : inTest_(inTest) { *inTest = true; }
+        ~InTestGuard() { *inTest_ = false; }
+
+    private:
+        bool *inTest_;
+};
+
+}       // namespace
+
+//! \cond internal
+bool threadMpiTestRunner(std::function<void()> testBody)
+{
+    static bool inTest = false;
+
+    if (inTest || g_numThreads <= 1)
+    {
+        return true;
+    }
+#if GMX_THREAD_MPI && !GTEST_IS_THREADSAFE
+    ADD_FAILURE()
+    << "Google Test is not thread safe on this platform. "
+    << "Cannot run multi-rank tests with thread-MPI.";
+#else
+    InTestGuard guard(&inTest);
+    if (!startThreads(&testBody))
+    {
+        return false;
+    }
+    try
+    {
+        testBody();
+    }
+    GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
+    tMPI_Finalize();
+#endif
+    return false;
+}
+//! \endcond
+
+#endif
+
+int getNumberOfTestMpiRanks()
+{
+#if GMX_THREAD_MPI
+    return g_numThreads;
+#else
+    return gmx_node_num();
+#endif
+}
+
+} // namespace test
+} // namespace gmx
diff --git a/src/testutils/mpitest.h b/src/testutils/mpitest.h
new file mode 100644 (file)
index 0000000..20629fd
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Helper functions for MPI tests to make thread-MPI look like real MPI.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_testutils
+ */
+#ifndef GMX_TESTUTILS_MPITEST_H
+#define GMX_TESTUTILS_MPITEST_H
+
+#include "config.h"
+
+#include <functional>
+#include <type_traits>
+
+#include "gromacs/utility/basenetwork.h"
+
+namespace gmx
+{
+namespace test
+{
+
+/*! \brief
+ * Returns the number of MPI ranks to use for an MPI test.
+ *
+ * For thread-MPI builds, this will return the requested number of ranks
+ * even before the thread-MPI threads have been started.
+ *
+ * \ingroup module_testutils
+ */
+int getNumberOfTestMpiRanks();
+//! \cond internal
+/*! \brief
+ * Helper function for GMX_MPI_TEST().
+ *
+ * \ingroup module_testutils
+ */
+bool threadMpiTestRunner(std::function<void()> testBody);
+//! \endcond
+
+/*! \brief
+ * Declares that this test is an MPI-enabled unit test.
+ *
+ * \param[in] expectedRankCount Expected number of ranks for this test.
+ *     The test will fail if run with unsupported number of ranks.
+ *
+ * To write unit tests that run under MPI, you need to do a few things:
+ *  - Put GMX_MPI_TEST() as the first statement in your test body and
+ *    specify the number of ranks this test expects.
+ *  - Declare your unit test in CMake with gmx_add_mpi_unit_test().
+ *    Note that all tests in the binary should fulfill the conditions above,
+ *    and work with the same number of ranks.
+ * TODO: Figure out a mechanism for mixing tests with different rank counts in
+ * the same binary (possibly, also MPI and non-MPI tests).
+ *
+ * When you do the above, the following will happen:
+ *  - The test will get compiled only if thread-MPI or real MPI is enabled.
+ *  - The test will get executed on the number of ranks specified.
+ *    If you are using real MPI, the whole test binary is run under MPI and
+ *    test execution across the processes is synchronized (GMX_MPI_TEST()
+ *    actually has no effect in this case, the synchronization is handled at a
+ *    higher level).
+ *    If you are using thread-MPI, GMX_MPI_TEST() is required and it
+ *    initializes thread-MPI with the specified number of threads and runs the
+ *    rest of the test on each of the threads.
+ *
+ * You need to be extra careful for variables in the test fixture, if you use
+ * one: when run under thread-MPI, these will be shared across all the ranks,
+ * while under real MPI, these are naturally different for each process.
+ * Local variables in the test body are private to each rank in both cases.
+ *
+ * Currently, it is not possible to specify the number of ranks as one, because
+ * that will lead to problems with (at least) thread-MPI, but such tests can be
+ * written as serial tests anyways.
+ *
+ * \ingroup module_testutils
+ */
+#if GMX_THREAD_MPI
+#define GMX_MPI_TEST(expectedRankCount) \
+    do { \
+        ASSERT_EQ(expectedRankCount, ::gmx::test::getNumberOfTestMpiRanks()); \
+        typedef std::remove_reference<decltype(*this)>::type MyTestClass; \
+        if (!::gmx::test::threadMpiTestRunner(std::bind(&MyTestClass::TestBody, this))) \
+        { \
+            return; \
+        } \
+    } while (0)
+#else
+#define GMX_MPI_TEST(expectedRankCount) \
+    ASSERT_EQ(expectedRankCount, ::gmx::test::getNumberOfTestMpiRanks())
+#endif
+
+} // namespace test
+} // namespace gmx
+
+#endif
index 4d80baeee37727bd76db95255b0011e7140127ca..3ac5b644c9b20d070a038440560d8527386a24f7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016, 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.
@@ -67,7 +67,7 @@ class ReferenceDataEntry
 
         ReferenceDataEntry(const char *type, const char *id)
             : type_(type), id_(id != NULL ? id : ""), isTextBlock_(false),
-              correspondingOutputEntry_(NULL)
+              hasBeenChecked_(false), correspondingOutputEntry_(NULL)
         {
         }
 
@@ -132,6 +132,18 @@ class ReferenceDataEntry
             return prev != children_.end();
         }
 
+        bool hasBeenChecked() const { return hasBeenChecked_; }
+        void setChecked() { hasBeenChecked_ = true; }
+
+        void setCheckedIncludingChildren()
+        {
+            setChecked();
+            for (const auto &child : children_)
+            {
+                child->setCheckedIncludingChildren();
+            }
+        }
+
         EntryPointer cloneToOutputEntry()
         {
             EntryPointer entry(new ReferenceDataEntry(type_.c_str(), id_.c_str()));
@@ -179,6 +191,7 @@ class ReferenceDataEntry
         std::string         value_;
         bool                isTextBlock_;
         ChildList           children_;
+        bool                hasBeenChecked_;
         ReferenceDataEntry *correspondingOutputEntry_;
 };
 
index 2afd1ec41ce81d46c591da5175b16f8d23ccbefe..0824cb93f46ed698a6919651fb3e9b8cb5eb81f2 100644 (file)
 #include "gromacs/options/ioptionscontainer.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/keyvaluetree.h"
 #include "gromacs/utility/path.h"
 #include "gromacs/utility/real.h"
 #include "gromacs/utility/stringutil.h"
+#include "gromacs/utility/variant.h"
 
 #include "testutils/refdata-checkers.h"
 #include "testutils/refdata-impl.h"
@@ -203,6 +205,67 @@ class ReferenceDataTestEventListener : public ::testing::EmptyTestEventListener
         }
 };
 
+//! Formats a path to a reference data entry with a non-null id.
+std::string formatEntryPath(const std::string &prefix, const std::string &id)
+{
+    return prefix + "/" + id;
+}
+
+//! Formats a path to a reference data entry with a null id.
+std::string formatSequenceEntryPath(const std::string &prefix, int seqIndex)
+{
+    return formatString("%s/[%d]", prefix.c_str(), seqIndex+1);
+}
+
+//! Finds all entries that have not been checked under a given root.
+void gatherUnusedEntries(const ReferenceDataEntry &root,
+                         const std::string        &rootPath,
+                         std::vector<std::string> *unusedPaths)
+{
+    if (!root.hasBeenChecked())
+    {
+        unusedPaths->push_back(rootPath);
+        return;
+    }
+    int seqIndex = 0;
+    for (const auto &child : root.children())
+    {
+        std::string path;
+        if (child->id().empty())
+        {
+            path = formatSequenceEntryPath(rootPath, seqIndex);
+            ++seqIndex;
+        }
+        else
+        {
+            path = formatEntryPath(rootPath, child->id());
+        }
+        gatherUnusedEntries(*child, path, unusedPaths);
+    }
+}
+
+//! Produces a GTest assertion of any entries under given root have not been checked.
+void checkUnusedEntries(const ReferenceDataEntry &root, const std::string &rootPath)
+{
+    std::vector<std::string> unusedPaths;
+    gatherUnusedEntries(root, rootPath, &unusedPaths);
+    if (!unusedPaths.empty())
+    {
+        std::string paths;
+        if (unusedPaths.size() > 5)
+        {
+            paths = joinStrings(unusedPaths.begin(), unusedPaths.begin() + 5, "\n  ");
+            paths = "  " + paths + "\n  ...";
+        }
+        else
+        {
+            paths = joinStrings(unusedPaths.begin(), unusedPaths.end(), "\n  ");
+            paths = "  " + paths;
+        }
+        ADD_FAILURE() << "Reference data items not used in test:" << std::endl << paths;
+    }
+}
+
 }       // namespace
 
 void initReferenceData(IOptionsContainer *options)
@@ -276,18 +339,29 @@ TestReferenceDataImpl::TestReferenceDataImpl(
 
 void TestReferenceDataImpl::onTestEnd(bool testPassed)
 {
+    if (!bInUse_)
+    {
+        return;
+    }
     // TODO: Only write the file with update-changed if there were actual changes.
-    if (testPassed && bInUse_ && outputRootEntry_)
+    if (outputRootEntry_)
     {
-        std::string dirname = Path::getParentPath(fullFilename_);
-        if (!Directory::exists(dirname))
+        if (testPassed)
         {
-            if (Directory::create(dirname) != 0)
+            std::string dirname = Path::getParentPath(fullFilename_);
+            if (!Directory::exists(dirname))
             {
-                GMX_THROW(TestException("Creation of reference data directory failed: " + dirname));
+                if (Directory::create(dirname) != 0)
+                {
+                    GMX_THROW(TestException("Creation of reference data directory failed: " + dirname));
+                }
             }
+            writeReferenceDataFile(fullFilename_, *outputRootEntry_);
         }
-        writeReferenceDataFile(fullFilename_, *outputRootEntry_);
+    }
+    else if (compareRootEntry_)
+    {
+        checkUnusedEntries(*compareRootEntry_, "");
     }
 }
 
@@ -322,6 +396,8 @@ class TestReferenceChecker::Impl
         static const char * const    cIdAttrName;
         //! String constant for naming compounds for vectors.
         static const char * const    cVectorType;
+        //! String constant for naming compounds for key-value tree objects.
+        static const char * const    cObjectType;
         //! String constant for naming compounds for sequences.
         static const char * const    cSequenceType;
         //! String constant for value identifier for sequence length.
@@ -468,7 +544,7 @@ class TestReferenceChecker::Impl
         /*! \brief
          * Current number of unnamed elements in a sequence.
          *
-         * It is the index of the next added unnamed element.
+         * It is the index of the current unnamed element.
          */
         int                     seqIndex_;
 };
@@ -481,6 +557,7 @@ const char *const TestReferenceChecker::Impl::cUInt64NodeName     = "UInt64";
 const char *const TestReferenceChecker::Impl::cRealNodeName       = "Real";
 const char *const TestReferenceChecker::Impl::cIdAttrName         = "Name";
 const char *const TestReferenceChecker::Impl::cVectorType         = "Vector";
+const char *const TestReferenceChecker::Impl::cObjectType         = "Object";
 const char *const TestReferenceChecker::Impl::cSequenceType       = "Sequence";
 const char *const TestReferenceChecker::Impl::cSequenceLengthName = "Length";
 
@@ -488,7 +565,7 @@ const char *const TestReferenceChecker::Impl::cSequenceLengthName = "Length";
 TestReferenceChecker::Impl::Impl(bool initialized)
     : initialized_(initialized), defaultTolerance_(defaultRealTolerance()),
       compareRootEntry_(NULL), outputRootEntry_(NULL),
-      updateMismatchingEntries_(false), bSelfTestMode_(false), seqIndex_(0)
+      updateMismatchingEntries_(false), bSelfTestMode_(false), seqIndex_(-1)
 {
 }
 
@@ -498,11 +575,11 @@ TestReferenceChecker::Impl::Impl(const std::string &path,
                                  ReferenceDataEntry *outputRootEntry,
                                  bool updateMismatchingEntries, bool bSelfTestMode,
                                  const FloatingPointTolerance &defaultTolerance)
-    : initialized_(true), defaultTolerance_(defaultTolerance), path_(path + "/"),
+    : initialized_(true), defaultTolerance_(defaultTolerance), path_(path),
       compareRootEntry_(compareRootEntry), outputRootEntry_(outputRootEntry),
       lastFoundEntry_(compareRootEntry->children().end()),
       updateMismatchingEntries_(updateMismatchingEntries),
-      bSelfTestMode_(bSelfTestMode), seqIndex_(0)
+      bSelfTestMode_(bSelfTestMode), seqIndex_(-1)
 {
 }
 
@@ -510,15 +587,16 @@ TestReferenceChecker::Impl::Impl(const std::string &path,
 std::string
 TestReferenceChecker::Impl::appendPath(const char *id) const
 {
-    std::string printId = (id != NULL) ? id : formatString("[%d]", seqIndex_);
-    return path_ + printId;
+    return id != nullptr
+           ? formatEntryPath(path_, id)
+           : formatSequenceEntryPath(path_, seqIndex_);
 }
 
 
 ReferenceDataEntry *TestReferenceChecker::Impl::findEntry(const char *id)
 {
     ReferenceDataEntry::ChildIterator entry = compareRootEntry_->findChild(id, lastFoundEntry_);
-    seqIndex_ = (id == NULL) ? seqIndex_+1 : 0;
+    seqIndex_ = (id == nullptr) ? seqIndex_+1 : -1;
     if (compareRootEntry_->isValidChild(entry))
     {
         lastFoundEntry_ = entry;
@@ -556,6 +634,7 @@ TestReferenceChecker::Impl::processItem(const char *type, const char *id,
         return ::testing::AssertionFailure()
                << "Reference data item " << fullId << " not found";
     }
+    entry->setChecked();
     ::testing::AssertionResult result(checkEntry(*entry, fullId, type, checker));
     if (outputRootEntry_ != NULL && entry->correspondingOutputEntry() == NULL)
     {
@@ -616,6 +695,7 @@ TestReferenceChecker TestReferenceData::rootChecker()
     {
         return TestReferenceChecker(new TestReferenceChecker::Impl(true));
     }
+    impl_->compareRootEntry_->setChecked();
     return TestReferenceChecker(
             new TestReferenceChecker::Impl("", impl_->compareRootEntry_.get(),
                                            impl_->outputRootEntry_.get(),
@@ -672,6 +752,17 @@ void TestReferenceChecker::setDefaultTolerance(
 }
 
 
+void TestReferenceChecker::checkUnusedEntries()
+{
+    if (impl_->compareRootEntry_)
+    {
+        gmx::test::checkUnusedEntries(*impl_->compareRootEntry_, impl_->path_);
+        // Mark them checked so that they are reported only once.
+        impl_->compareRootEntry_->setCheckedIncludingChildren();
+    }
+}
+
+
 bool TestReferenceChecker::checkPresent(bool bPresent, const char *id)
 {
     if (impl_->shouldIgnore() || impl_->outputRootEntry_ != NULL)
@@ -712,6 +803,7 @@ TestReferenceChecker TestReferenceChecker::checkCompound(const char *type, const
         ADD_FAILURE() << "Reference data item " << fullId << " not found";
         return TestReferenceChecker(new Impl(true));
     }
+    entry->setChecked();
     if (impl_->updateMismatchingEntries_)
     {
         entry->makeCompound(type);
@@ -871,6 +963,64 @@ void TestReferenceChecker::checkVector(const double value[3], const char *id)
 }
 
 
+void TestReferenceChecker::checkVariant(const Variant &variant, const char *id)
+{
+    if (variant.isType<bool>())
+    {
+        checkBoolean(variant.cast<bool>(), id);
+    }
+    else if (variant.isType<int>())
+    {
+        checkInteger(variant.cast<int>(), id);
+    }
+    else if (variant.isType<float>())
+    {
+        checkFloat(variant.cast<float>(), id);
+    }
+    else if (variant.isType<double>())
+    {
+        checkDouble(variant.cast<double>(), id);
+    }
+    else if (variant.isType<std::string>())
+    {
+        checkString(variant.cast<std::string>(), id);
+    }
+    else
+    {
+        GMX_THROW(TestException("Unsupported variant type"));
+    }
+}
+
+
+void TestReferenceChecker::checkKeyValueTreeObject(const KeyValueTreeObject &tree, const char *id)
+{
+    TestReferenceChecker compound(checkCompound(Impl::cObjectType, id));
+    for (const auto &prop : tree.properties())
+    {
+        compound.checkKeyValueTreeValue(prop.value(), prop.key().c_str());
+    }
+    compound.checkUnusedEntries();
+}
+
+
+void TestReferenceChecker::checkKeyValueTreeValue(const KeyValueTreeValue &value, const char *id)
+{
+    if (value.isObject())
+    {
+        checkKeyValueTreeObject(value.asObject(), id);
+    }
+    else if (value.isArray())
+    {
+        const auto &values = value.asArray().values();
+        checkSequence(values.begin(), values.end(), id);
+    }
+    else
+    {
+        checkVariant(value.asVariant(), id);
+    }
+}
+
+
 TestReferenceChecker
 TestReferenceChecker::checkSequenceCompound(const char *id, size_t length)
 {
index 99763e12c3f59a08fa8a41e918bd37e8c9cc6484..61904f6b40c304978f1a7ba41f413f44ede3aada 100644 (file)
@@ -56,6 +56,9 @@ namespace gmx
 {
 
 class IOptionsContainer;
+class KeyValueTreeObject;
+class KeyValueTreeValue;
+class Variant;
 
 namespace test
 {
@@ -274,6 +277,22 @@ class TestReferenceChecker
          */
         void setDefaultTolerance(const FloatingPointTolerance &tolerance);
 
+        /*! \brief
+         * Checks that all reference values have been compared against.
+         *
+         * All values under the compound represented by this checker are
+         * checked, and a non-fatal Google Test assertion is produced if some
+         * values have not been used.
+         *
+         * If not called explicitly, the same check will be done for all
+         * reference data values when the test ends.
+         *
+         * This method also marks the values used, so that subsequent checks
+         * (including the check at the end of the test) will not produce
+         * another assertion about the same values.
+         */
+        void checkUnusedEntries();
+
         /*! \brief
          * Checks whether a data item is present.
          *
@@ -351,6 +370,12 @@ class TestReferenceChecker
         void checkVector(const double value[3], const char *id);
         //! Check a single floating-point value from a string.
         void checkRealFromString(const std::string &value, const char *id);
+        //! Checks a variant value that contains a supported simple type.
+        void checkVariant(const Variant &value, const char *id);
+        //! Checks a key-value tree rooted at a object.
+        void checkKeyValueTreeObject(const KeyValueTreeObject &tree, const char *id);
+        //! Checks a generic key-value tree value.
+        void checkKeyValueTreeValue(const KeyValueTreeValue &value, const char *id);
 
         /*! \name Overloaded versions of simple checker methods
          *
@@ -416,6 +441,11 @@ class TestReferenceChecker
         {
             checkVector(value, id);
         }
+        //! Check a generic key-value tree value.
+        void checkValue(const KeyValueTreeValue &value, const char *id)
+        {
+            checkKeyValueTreeValue(value, id);
+        }
         /*!\}*/
 
         /*! \brief
index 4d9b499e9eb6a21f6da5541335170f2d8a8d4f21..a2c515120e6a0a1b51b2173ae420a5841bb3e3da 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016, 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.
@@ -193,16 +193,18 @@ gmx_uint64_t relativeToleranceToUlp(FloatType tolerance)
  * FloatingPointDifference
  */
 
-FloatingPointDifference::FloatingPointDifference(float value1, float value2)
+FloatingPointDifference::FloatingPointDifference(float ref, float value)
+    : termMagnitude_(std::abs(ref))
 {
-    initDifference(value1, value2,
+    initDifference(ref, value,
                    &absoluteDifference_, &ulpDifference_, &bSignDifference_);
     bDouble_ = false;
 }
 
-FloatingPointDifference::FloatingPointDifference(double value1, double value2)
+FloatingPointDifference::FloatingPointDifference(double ref, double value)
+    : termMagnitude_(std::abs(ref))
 {
-    initDifference(value1, value2,
+    initDifference(ref, value,
                    &absoluteDifference_, &ulpDifference_, &bSignDifference_);
     bDouble_ = true;
 }
@@ -214,11 +216,29 @@ bool FloatingPointDifference::isNaN() const
 
 std::string FloatingPointDifference::toString() const
 {
-    const double eps = isDouble() ? GMX_DOUBLE_EPS : GMX_FLOAT_EPS;
-    return formatString("%g (%" GMX_PRIu64 " %s-prec. ULPs, rel. %.3g)%s",
+    std::string relDiffStr;
+
+    if (termMagnitude_ > 0)
+    {
+        // If the reference value is finite we calculate the proper quotient
+        relDiffStr = formatString("%.3g", std::abs(absoluteDifference_/termMagnitude_));
+    }
+    else if (absoluteDifference_ == 0.0)
+    {
+        // If the numbers are identical the quotient is strictly NaN here, but
+        // there no reason to worry when we have a perfect match.
+        relDiffStr = formatString("%.3g", 0.0);
+    }
+    else
+    {
+        // If the reference value is zero and numbers are non-identical, relative difference is infinite.
+        relDiffStr = formatString("Inf");
+    }
+
+    return formatString("%g (%" GMX_PRIu64 " %s-prec. ULPs, rel. %s)%s",
                         absoluteDifference_, ulpDifference_,
                         isDouble() ? "double" : "single",
-                        ulpDifference_ * eps,
+                        relDiffStr.c_str(),
                         bSignDifference_ ? ", signs differ" : "");
 }
 
@@ -246,12 +266,23 @@ bool FloatingPointTolerance::isWithin(
         return true;
     }
 
+    // By using smaller-than-or-equal below, we allow the test to pass if
+    // the numbers are identical, even if the term magnitude is 0, which seems
+    // a reasonable thing to do...
+    const double relativeTolerance
+        = difference.isDouble() ? doubleRelativeTolerance_ : singleRelativeTolerance_;
+    if (difference.asAbsolute() <= relativeTolerance * difference.termMagnitude())
+    {
+        return true;
+    }
+
     const gmx_uint64_t ulpTolerance
         = difference.isDouble() ? doubleUlpTolerance_ : singleUlpTolerance_;
     if (ulpTolerance < GMX_UINT64_MAX && difference.asUlps() <= ulpTolerance)
     {
         return true;
     }
+
     return false;
 }
 
@@ -260,22 +291,30 @@ std::string FloatingPointTolerance::toString(const FloatingPointDifference &diff
     std::string        result;
     const double       absoluteTolerance
         = difference.isDouble() ? doubleAbsoluteTolerance_ : singleAbsoluteTolerance_;
+    const double       relativeTolerance
+        = difference.isDouble() ? doubleRelativeTolerance_ : singleRelativeTolerance_;
     const gmx_uint64_t ulpTolerance
         = difference.isDouble() ? doubleUlpTolerance_ : singleUlpTolerance_;
-    const double       eps
-        = difference.isDouble() ? GMX_DOUBLE_EPS : GMX_FLOAT_EPS;
 
     if (absoluteTolerance > 0.0)
     {
         result.append(formatString("abs. %g", absoluteTolerance));
     }
+    if (relativeTolerance > 0.0)
+    {
+        if (!result.empty())
+        {
+            result.append(", ");
+        }
+        result.append(formatString("rel. %.3g", relativeTolerance));
+    }
     if (ulpTolerance < GMX_UINT64_MAX)
     {
         if (!result.empty())
         {
             result.append(", ");
         }
-        result.append(formatString("%" GMX_PRIu64 " ULPs (rel. %.3g)", ulpTolerance, ulpTolerance * eps));
+        result.append(formatString("%" GMX_PRIu64 " ULPs", ulpTolerance));
     }
     if (bSignMustMatch_)
     {
@@ -293,10 +332,10 @@ std::string FloatingPointTolerance::toString(const FloatingPointDifference &diff
 FloatingPointTolerance
 relativeToleranceAsFloatingPoint(double magnitude, double tolerance)
 {
-    const double absoluteTolerance = magnitude * tolerance;
+    const double absoluteTolerance = std::abs(magnitude) * tolerance;
     return FloatingPointTolerance(absoluteTolerance, absoluteTolerance,
-                                  relativeToleranceToUlp<float>(tolerance),
-                                  relativeToleranceToUlp<double>(tolerance),
+                                  tolerance, tolerance,
+                                  GMX_UINT64_MAX, GMX_UINT64_MAX,
                                   false);
 }
 //! \endcond
index dc4b68bba235bbd84c57879b12d629f7e49da212..c13c00ec569555c21931e3366ccb36a4bf300f82 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, 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.
@@ -209,10 +209,30 @@ void processExpectedException(const std::exception &ex);
 class FloatingPointDifference
 {
     public:
-        //! Initializes a single-precision difference.
-        FloatingPointDifference(float value1, float value2);
-        //! Initializes a double-precision difference.
-        FloatingPointDifference(double value1, double value2);
+
+        /*! \brief Initializes a single-precision difference.
+         *
+         *  \param ref    First term in difference
+         *  \param value  Second term in difference
+         *
+         *  For absolute and ULP differences the two parameters are equivalent,
+         *  since the difference is symmetric. For relative differences
+         *  the first term is interpreted as the reference value, from which
+         *  we extract the magnitude to compare with.
+         */
+        FloatingPointDifference(float ref, float value);
+
+        /*! \brief Initializes a double-precision difference.
+         *
+         *  \param ref    First term in difference
+         *  \param value  Second term in difference
+         *
+         *  For absolute and ULP differences the two parameters are equivalent,
+         *  since the difference is symmetric. For relative differences
+         *  the first term is interpreted as the reference value, from which
+         *  we extract the magnitude to compare with.
+         */
+        FloatingPointDifference(double ref, double value);
 
         /*! \brief
          * Whether one or both of the compared values were NaN.
@@ -244,7 +264,13 @@ class FloatingPointDifference
         //! Formats the difference as a string for assertion failure messages.
         std::string toString() const;
 
+        //! Returns the magnitude of the original second term of the difference.
+        double termMagnitude() const { return termMagnitude_; }
+
     private:
+
+        //! Save the magnitude of the reference value for relative (i.e., not ULP) tolerance
+        double       termMagnitude_;
         //! Stores the absolute difference, or NaN if one or both values were NaN.
         double       absoluteDifference_;
         gmx_uint64_t ulpDifference_;
@@ -270,6 +296,9 @@ class FloatingPointDifference
  *    the given tolerance for the check to pass.
  *    Setting the absolute tolerance to zero disables the absolute tolerance
  *    check.
+ *  - _relative tolerance_: the absolute difference between the numbers must
+ *    be smaller than the tolerance multiplied by the first number. Setting
+ *    the relative tolerance to zero disables this check.
  *  - _ULP tolerance_: ULP (units of least precision) difference between the
  *    values must be smaller than the given tolerance for the check to pass.
  *    Setting the ULP tolerance to zero requires exact match.
@@ -279,13 +308,13 @@ class FloatingPointDifference
  *    check (note that this also applies to `0.0` and `-0.0`: a value with a
  *    different sign than the zero will fail the check).
  *
- * Either an absolute or a ULP tolerance must always be specified.
- * If both are specified, then the check passes if either of the tolerances is
- * satisfied.
+ * Either an absolute, relative, or ULP tolerance must always be specified.
+ * If several of them are specified, then the check passes if either of the
+ * tolerances is satisfied.
  *
- * Any combination of absolute and ULP tolerance can be combined with the sign
- * check.  In this case, the sign check must succeed for the check to pass,
- * even if other tolerances are satisfied.
+ * Any combination of absolute, relative, and ULP tolerance can be combined with
+ * the sign check.  In this case, the sign check must succeed for the check to
+ * pass, even if other tolerances are satisfied.
  *
  * The tolerances can be specified separately for single and double precision
  * comparison.  Different initialization functions have different semantics on
@@ -312,6 +341,10 @@ class FloatingPointTolerance
          *     Allowed absolute difference in a single-precision number.
          * \param[in]  doubleAbsoluteTolerance
          *     Allowed absolute difference in a double-precision number.
+         * \param[in]  singleRelativeTolerance
+         *     Allowed relative difference in a single-precision number.
+         * \param[in]  doubleRelativeTolerance
+         *     Allowed relative difference in a double-precision number.
          * \param[in]  singleUlpTolerance
          *     Allowed ULP difference in a single-precision number.
          * \param[in]  doubleUlpTolerance
@@ -321,11 +354,15 @@ class FloatingPointTolerance
          */
         FloatingPointTolerance(float        singleAbsoluteTolerance,
                                double       doubleAbsoluteTolerance,
+                               float        singleRelativeTolerance,
+                               double       doubleRelativeTolerance,
                                gmx_uint64_t singleUlpTolerance,
                                gmx_uint64_t doubleUlpTolerance,
                                bool         bSignMustMatch)
             : singleAbsoluteTolerance_(singleAbsoluteTolerance),
               doubleAbsoluteTolerance_(doubleAbsoluteTolerance),
+              singleRelativeTolerance_(singleRelativeTolerance),
+              doubleRelativeTolerance_(doubleRelativeTolerance),
               singleUlpTolerance_(singleUlpTolerance),
               doubleUlpTolerance_(doubleUlpTolerance),
               bSignMustMatch_(bSignMustMatch)
@@ -345,6 +382,8 @@ class FloatingPointTolerance
     private:
         float        singleAbsoluteTolerance_;
         double       doubleAbsoluteTolerance_;
+        float        singleRelativeTolerance_;
+        double       doubleRelativeTolerance_;
         gmx_uint64_t singleUlpTolerance_;
         gmx_uint64_t doubleUlpTolerance_;
         bool         bSignMustMatch_;
@@ -361,7 +400,7 @@ class FloatingPointTolerance
 static inline FloatingPointTolerance
 ulpTolerance(gmx_uint64_t ulpDiff)
 {
-    return FloatingPointTolerance(0.0, 0.0, ulpDiff, ulpDiff, false);
+    return FloatingPointTolerance(0.0, 0.0, 0.0, 0.0, ulpDiff, ulpDiff, false);
 }
 
 /*! \brief
@@ -371,7 +410,7 @@ ulpTolerance(gmx_uint64_t ulpDiff)
  * \param[in] magnitude  Magnitude of the numbers the computation operates in.
  * \param[in] tolerance  Relative tolerance permitted (e.g. 1e-4).
  *
- * In addition to setting an ULP tolerance equivalent to \p tolerance for both
+ * In addition to setting an relative tolerance for both
  * precisions, this sets the absolute tolerance such that values close to zero
  * (in general, smaller than \p magnitude) do not fail the check if they
  * differ by less than \p tolerance evaluated at \p magnitude.  This accounts
@@ -379,9 +418,6 @@ ulpTolerance(gmx_uint64_t ulpDiff)
  * accuracy of values much less than \p magnitude do not matter for
  * correctness.
  *
- * The ULP tolerance for different precisions will be different to make them
- * both match \p tolerance.
- *
  * \related FloatingPointTolerance
  */
 FloatingPointTolerance
@@ -412,6 +448,7 @@ relativeToleranceAsPrecisionDependentUlp(double       magnitude,
 {
     return FloatingPointTolerance(magnitude*singleUlpDiff*GMX_FLOAT_EPS,
                                   magnitude*doubleUlpDiff*GMX_DOUBLE_EPS,
+                                  0.0, 0.0,
                                   singleUlpDiff, doubleUlpDiff, false);
 }
 
@@ -423,7 +460,7 @@ relativeToleranceAsPrecisionDependentUlp(double       magnitude,
 static inline FloatingPointTolerance
 absoluteTolerance(double tolerance)
 {
-    return FloatingPointTolerance(tolerance, tolerance,
+    return FloatingPointTolerance(tolerance, tolerance, 0.0, 0.0,
                                   GMX_UINT64_MAX, GMX_UINT64_MAX, false);
 }
 
@@ -555,27 +592,6 @@ static inline ::testing::AssertionResult assertEqualWithinTolerance(
 
 //! \}
 
-/*! \name Assertions for NULL comparison
- *
- * These macros should be used instead of `(EXPECT|ASSERT)_EQ(NULL, ...)`,
- * because Google Test doesn't support the NULL comparison with xlC++ 12.1 on
- * BG/Q.
- */
-//! \{
-
-/*! \brief
- * Asserts that a pointer is null.
- *
- * Works exactly like EXPECT_EQ comparing with a null pointer. */
-#define EXPECT_NULL(val) EXPECT_EQ((void *) NULL, val)
-/*! \brief
- * Asserts that a pointer is null.
- *
- * Works exactly like ASSERT_EQ comparing with a null pointer. */
-#define ASSERT_NULL(val) ASSERT_EQ((void *) NULL, val)
-
-//! \}
-
 //! \cond internal
 /*! \internal \brief
  * Helper method for `(EXPECT|ASSERT)_PLAIN`.
index 5844d99966b51f804775c3ae0d5a94ff430a5e56..ef233ddf90ae5c060ad46e02591439468d0ca1b7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016, 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.
@@ -119,7 +119,7 @@ TextOutputStream &TestFileOutputRedirector::standardOutput()
     if (!impl_->stdoutStream_)
     {
         impl_->stdoutStream_.reset(new StringOutputStream);
-        impl_->fileList_.push_back(Impl::FileListEntry("<stdout>", impl_->stdoutStream_));
+        impl_->fileList_.emplace_back("<stdout>", impl_->stdoutStream_);
     }
     return *impl_->stdoutStream_;
 }
@@ -128,7 +128,7 @@ TextOutputStreamPointer
 TestFileOutputRedirector::openTextOutputFile(const char *filename)
 {
     Impl::StringStreamPointer stream(new StringOutputStream);
-    impl_->fileList_.push_back(Impl::FileListEntry(filename, stream));
+    impl_->fileList_.emplace_back(filename, stream);
     return stream;
 }
 
index 83e877d7be942f26d0397b5fe72b7b8aae6173f2..5ade1e5a1d373a388a9cd52023682611c1d77c22 100644 (file)
@@ -168,18 +168,18 @@ void initTestUtils(const char *dataPath, const char *tempPath, bool usesMpi,
     {
         if (!usesMpi && gmx_node_num() > 1)
         {
+            // We cannot continue, since some tests might be using
+            // MPI_COMM_WORLD, which could deadlock if we would only
+            // continue with the master rank here.
             if (gmx_node_rank() == 0)
             {
                 fprintf(stderr, "NOTE: You are running %s on %d MPI ranks, "
                         "but it is does not contain MPI-enabled tests. "
-                        "Rank 0 will run the tests, other ranks will exit.",
+                        "The test will now exit.\n",
                         context.programName(), gmx_node_num());
             }
-            else
-            {
-                finalizeForCommandLine();
-                std::exit(0);
-            }
+            finalizeForCommandLine();
+            std::exit(1);
         }
         g_testContext.reset(new TestProgramContext(context));
         setProgramContext(g_testContext.get());
@@ -198,7 +198,7 @@ void initTestUtils(const char *dataPath, const char *tempPath, bool usesMpi,
         }
         bool        bHelp = false;
         std::string sourceRoot;
-        Options     options(NULL, NULL);
+        Options     options;
         // TODO: A single option that accepts multiple names would be nicer.
         // Also, we recognize -help, but GTest doesn't, which leads to a bit
         // unintuitive behavior.
index 6f8cb9c9b7b69a2d6725456f9623b6e3ff8963ab..3070802cbf1f6398423ba507ab41f43d4a575b9a 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2011,2012,2014,2015, by the GROMACS development team, led by
+# Copyright (c) 2011,2012,2014,2015,2016, 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.
@@ -37,3 +37,6 @@ gmx_add_unit_test(TestUtilsUnitTests testutils-test
                   refdata_tests.cpp
                   testasserts_tests.cpp
                   xvgtest_tests.cpp)
+
+gmx_add_mpi_unit_test(TestUtilsMpiUnitTests testutils-mpi-test 2
+                      mpitest.cpp)
index 974688cdbee435f1ea167e49d97570c430c86aed..eb1ac9914feea3f08121287dc16c47c806bd7089 100644 (file)
@@ -65,7 +65,7 @@ class InteractiveSession
 
         void addOutput(const char *output)
         {
-            events_.push_back(Event(WriteOutput, output));
+            events_.emplace_back(WriteOutput, output);
         }
         void addInputLine(const char *inputLine)
         {
@@ -73,7 +73,7 @@ class InteractiveSession
         }
         void addReadInput()
         {
-            events_.push_back(Event(ReadInput, ""));
+            events_.emplace_back(ReadInput, "");
         }
         void addInput(const char *inputLine)
         {
@@ -84,7 +84,7 @@ class InteractiveSession
         {
             addInputLine(inputLine);
             helper_.setLastNewline(false);
-            events_.push_back(Event(ReadInputNoNewline, ""));
+            events_.emplace_back(ReadInputNoNewline, "");
         }
 
         void run()
diff --git a/src/testutils/tests/mpitest.cpp b/src/testutils/tests/mpitest.cpp
new file mode 100644 (file)
index 0000000..b810a25
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, 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.
+ */
+/*! \internal \file
+ * \brief
+ * Tests for infrastructure for running tests under MPI.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_testutils
+ */
+#include "gmxpre.h"
+
+#include "testutils/mpitest.h"
+
+#include "config.h"
+
+#include <gtest/gtest.h>
+
+#include "gromacs/utility/basenetwork.h"
+#include "gromacs/utility/gmxmpi.h"
+
+namespace
+{
+
+class MpiSelfTest : public ::testing::Test
+{
+    public:
+        MpiSelfTest() : reached {0, 0}
+        {}
+
+        int reached[2];
+};
+
+TEST_F(MpiSelfTest, Runs)
+{
+    GMX_MPI_TEST(2);
+#if GMX_THREAD_MPI
+    reached[gmx_node_rank()] = 1;
+    MPI_Barrier(MPI_COMM_WORLD);
+#else
+    int value = 1;
+    MPI_Gather(&value, 1, MPI_INT, reached, 1, MPI_INT, 0, MPI_COMM_WORLD);
+#endif
+    if (gmx_node_rank() == 0)
+    {
+        EXPECT_EQ(1, reached[0]);
+        EXPECT_EQ(1, reached[1]);
+    }
+}
+
+} // namespace
index 0a13555be2cd1b5944aca4d8d47ea109cce0bf90..d89226439aa79c5baef2fce8185e60f5586c52ac 100644 (file)
 
 #include "testutils/refdata.h"
 
+#include <string>
 #include <vector>
 
 #include <gtest/gtest.h>
 #include <gtest/gtest-spi.h>
 
+#include "gromacs/utility/keyvaluetree.h"
+#include "gromacs/utility/keyvaluetreebuilder.h"
+#include "gromacs/utility/variant.h"
+
 #include "testutils/testasserts.h"
 #include "testutils/testexceptions.h"
 
@@ -266,6 +271,203 @@ TEST(ReferenceDataTest, HandlesMissingData)
         TestReferenceChecker checker(data.rootChecker());
         EXPECT_NONFATAL_FAILURE(checker.checkInteger(1, "missing"), "");
         EXPECT_NONFATAL_FAILURE(checker.checkSequenceArray(5, seq, "missing"), "");
+        // Needed to not make the test fail because of unused "int" and "seq".
+        EXPECT_NONFATAL_FAILURE(checker.checkUnusedEntries(), "");
+    }
+}
+
+
+TEST(ReferenceDataTest, HandlesUncheckedData)
+{
+    const int seq[5] = { -1, 3, 5, 2, 4 };
+
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateAll);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkInteger(1, "int");
+        checker.checkSequenceArray(5, seq, "seq");
+        checker.checkUnusedEntries();
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataCompare);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkInteger(1, "int");
+        EXPECT_NONFATAL_FAILURE(checker.checkUnusedEntries(), "");
+    }
+}
+
+
+TEST(ReferenceDataTest, HandlesUncheckedDataInSequence)
+{
+    const int seq[5] = { -1, 3, 5, 2, 4 };
+
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateAll);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkInteger(1, "int");
+        checker.checkSequenceArray(5, seq, "seq");
+        checker.checkUnusedEntries();
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataCompare);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkInteger(1, "int");
+        EXPECT_NONFATAL_FAILURE(checker.checkSequenceArray(3, seq, "seq"), "");
+        // It might be nicer to not report the unused sequence entries also
+        // here, but both behaviors are quite OK.
+        EXPECT_NONFATAL_FAILURE(checker.checkUnusedEntries(), "");
+    }
+}
+
+
+TEST(ReferenceDataTest, HandlesUncheckedDataInCompound)
+{
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateAll);
+        TestReferenceChecker checker(data.rootChecker());
+        TestReferenceChecker compound(checker.checkCompound("Compound", "Compound"));
+        compound.checkInteger(1, "int1");
+        compound.checkInteger(2, "int2");
+        compound.checkUnusedEntries();
+        checker.checkInteger(1, "int");
+        checker.checkUnusedEntries();
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataCompare);
+        TestReferenceChecker checker(data.rootChecker());
+        TestReferenceChecker compound(checker.checkCompound("Compound", "Compound"));
+        compound.checkInteger(1, "int1");
+        EXPECT_NONFATAL_FAILURE(compound.checkUnusedEntries(), "");
+        checker.checkInteger(1, "int");
+        checker.checkUnusedEntries();
+    }
+}
+
+
+TEST(ReferenceDataTest, HandlesVariants)
+{
+    using gmx::Variant;
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateAll);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkVariant(Variant::create<bool>(true), "bool");
+        checker.checkVariant(Variant::create<int>(1), "int");
+        checker.checkVariant(Variant::create<double>(3.5), "real");
+        checker.checkVariant(Variant::create<std::string>("foo"), "str");
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataCompare);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkVariant(Variant::create<bool>(true), "bool");
+        checker.checkVariant(Variant::create<int>(1), "int");
+        checker.checkVariant(Variant::create<double>(3.5), "real");
+        checker.checkVariant(Variant::create<std::string>("foo"), "str");
+    }
+}
+
+//! Helper for building a KeyValueTree for testing.
+gmx::KeyValueTreeObject buildKeyValueTree(bool full)
+{
+    gmx::KeyValueTreeBuilder builder;
+    auto                     root = builder.rootObject();
+    auto                     obj  = root.addObject("o");
+    obj.addValue<int>("i", 1);
+    if (full)
+    {
+        obj.addValue<std::string>("s", "x");
+    }
+    auto arr  = root.addUniformArray<int>("a");
+    arr.addValue(2);
+    arr.addValue(3);
+    root.addValue<std::string>("s", "y");
+    return builder.build();
+}
+
+
+TEST(ReferenceDataTest, HandlesKeyValueTree)
+{
+    gmx::KeyValueTreeObject tree = buildKeyValueTree(true);
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateAll);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkKeyValueTreeObject(tree, "tree");
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataCompare);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkKeyValueTreeObject(tree, "tree");
+    }
+}
+
+
+TEST(ReferenceDataTest, HandlesKeyValueTreeExtraKey)
+{
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateAll);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkKeyValueTreeObject(buildKeyValueTree(false), "tree");
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataCompare);
+        TestReferenceChecker checker(data.rootChecker());
+        EXPECT_NONFATAL_FAILURE(checker.checkKeyValueTreeObject(buildKeyValueTree(true), "tree"), "");
+    }
+}
+
+
+TEST(ReferenceDataTest, HandlesKeyValueTreeMissingKey)
+{
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateAll);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkKeyValueTreeObject(buildKeyValueTree(true), "tree");
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataCompare);
+        TestReferenceChecker checker(data.rootChecker());
+        EXPECT_NONFATAL_FAILURE(checker.checkKeyValueTreeObject(buildKeyValueTree(false), "tree"), "");
+    }
+}
+
+
+TEST(ReferenceDataTest, HandlesVariantsWithIncorrectValue)
+{
+    using gmx::Variant;
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateAll);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkVariant(Variant::create<bool>(true), "bool");
+        checker.checkVariant(Variant::create<int>(1), "int");
+        checker.checkVariant(Variant::create<double>(3.5), "real");
+        checker.checkVariant(Variant::create<std::string>("foo"), "str");
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataCompare);
+        TestReferenceChecker checker(data.rootChecker());
+        EXPECT_NONFATAL_FAILURE(checker.checkVariant(Variant::create<bool>(false), "bool"), "");
+        EXPECT_NONFATAL_FAILURE(checker.checkVariant(Variant::create<int>(2), "int"), "");
+        EXPECT_NONFATAL_FAILURE(checker.checkVariant(Variant::create<double>(2.5), "real"), "");
+        EXPECT_NONFATAL_FAILURE(checker.checkVariant(Variant::create<std::string>("bar"), "str"), "");
+    }
+}
+
+
+TEST(ReferenceDataTest, HandlesVariantsWithIncorrectType)
+{
+    using gmx::Variant;
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateAll);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkVariant(Variant::create<bool>(true), "bool");
+        checker.checkVariant(Variant::create<int>(1), "int");
+        checker.checkVariant(Variant::create<double>(3.5), "real");
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataCompare);
+        TestReferenceChecker checker(data.rootChecker());
+        EXPECT_NONFATAL_FAILURE(checker.checkVariant(Variant::create<int>(1), "bool"), "");
+        EXPECT_NONFATAL_FAILURE(checker.checkVariant(Variant::create<bool>(true), "int"), "");
+        EXPECT_NONFATAL_FAILURE(checker.checkVariant(Variant::create<int>(2), "real"), "");
     }
 }
 
@@ -563,4 +765,24 @@ TEST(ReferenceDataTest, HandlesUpdateChangedWithCompoundChanges)
     }
 }
 
+TEST(ReferenceDataTest, HandlesUpdateChangedWithRemovedEntries)
+{
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateAll);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkInteger(1, "int");
+        checker.checkString("Test", "string");
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataUpdateChanged);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkInteger(2, "int");
+    }
+    {
+        TestReferenceData    data(gmx::test::erefdataCompare);
+        TestReferenceChecker checker(data.rootChecker());
+        checker.checkInteger(2, "int");
+    }
+}
+
 } // namespace
index 5621821b129458020fb8f405f5a766c342aa6d3e..37a336b89b678a058755699b5b947bac3b293baa 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016, 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.
@@ -110,7 +110,7 @@ TEST(XvgTests, CheckMissing)
         gmx::test::TestReferenceData    data(gmx::test::erefdataCompare);
         gmx::test::TestReferenceChecker checker(data.rootChecker());
         gmx::StringInputStream          sis(input);
-        EXPECT_NONFATAL_FAILURE(checkXvgFile(&sis, &checker, XvgMatchSettings()), "absent");
+        EXPECT_NONFATAL_FAILURE(checkXvgFile(&sis, &checker, XvgMatchSettings()), "not used in test");
     }
 }
 
index b69e0c87bb24088bb0317b1b1b9c4769dc15eb09..560232fd3886ad798adda0d251da0cb5dd82d11d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016, 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.
@@ -140,10 +140,7 @@ void checkXvgFile(TextInputStream        *input,
                                   &checkXvgDataPoint);
         ++dataRowCount;
     }
-    if (settings.testData)
-    {
-        dataChecker.checkPresent(false, formatString("Row%d", dataRowCount).c_str());
-    }
+    dataChecker.checkUnusedEntries();
     legendChecker.checkTextBlock(legendText, "XvgLegend");
 }
 
index ebffac5d7b9652d09e2009ebd0e67b14fa79d4f3..5a946bf27df69c596a0ff6f8ca2dda3bf4e200ce 100644 (file)
@@ -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
 # 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.
@@ -87,10 +87,10 @@ log: ${log}")
     set(REGRESSIONTEST_DOWNLOAD OFF CACHE BOOL "Tests already downloaded. Set to yes to download again" FORCE)
 endif()
 
-if(REGRESSIONTEST_PATH AND (GMX_BLUEGENE OR CMAKE_CROSSCOMPILING OR CMAKE_CONFIGURATION_TYPES OR GMX_BUILD_MDRUN_ONLY))
-    # TODO: It would be nicer to do these before potentially downloading the tests.
-    # Bluegene requires us to compile both front-end and back-end binaries
-    # (single build is insufficient)
+if(REGRESSIONTEST_PATH AND (CMAKE_CROSSCOMPILING OR CMAKE_CONFIGURATION_TYPES OR GMX_BUILD_MDRUN_ONLY))
+    # TODO: It would be nicer to do these checks before potentially downloading the tests.
+    # Cross-compiling toolchains require us to compile both front-end and
+    # back-end binaries to run gmxtest.pl.
     # Testing an mdrun-only builds require supporting binaries from a full build
     message(WARNING
         "With cross-compiling, multi-configuration generators (e.g. Visual Studio), or with mdrun-only builds, running regressiontests from build system is not supported. Please run gmxtest.pl directly.")
@@ -174,11 +174,8 @@ if(REGRESSIONTEST_PATH)
             ENVIRONMENT "PATH=${PATH}")
     endforeach()
 else()
-    add_custom_target(regressiontests-notice
-        ${CMAKE_COMMAND} -E echo "NOTE: Regression tests have not been run. If you want to run them from the build system, get the correct version of the regression tests package and set REGRESSIONTEST_PATH in CMake to point to it, or set REGRESSIONTEST_DOWNLOAD=ON."
-        DEPENDS run-ctest
-        COMMENT "Regression tests not available" VERBATIM)
-    add_dependencies(check regressiontests-notice)
+    gmx_add_missing_tests_notice("Regression tests have not been run. If you want to run them from the build system, get the correct version of the regression tests package and set REGRESSIONTEST_PATH in CMake to point to it, or set REGRESSIONTEST_DOWNLOAD=ON.")
 endif()
 
+gmx_create_missing_tests_notice_target()
 include(CppCheck.cmake)
diff --git a/tests/CheckTarget.cmake b/tests/CheckTarget.cmake
new file mode 100644 (file)
index 0000000..3cb3837
--- /dev/null
@@ -0,0 +1,67 @@
+#
+# This file is part of the GROMACS molecular simulation package.
+#
+# Copyright (c) 2014,2016, 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.
+
+# "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)
+
+# Global property for collecting notices to show at the end of the "check"
+# target.
+set_property(GLOBAL PROPERTY GMX_TESTS_NOTICE)
+
+function (gmx_add_missing_tests_notice TEXT)
+    set_property(GLOBAL APPEND PROPERTY GMX_TESTS_NOTICE ${TEXT})
+endfunction()
+
+function (gmx_create_missing_tests_notice_target)
+    get_property(_text GLOBAL PROPERTY GMX_TESTS_NOTICE)
+    set(_cmds)
+    foreach (_line ${_text})
+        list(APPEND _cmds COMMAND ${CMAKE_COMMAND} -E echo "NOTE: ${_line}")
+    endforeach()
+    add_custom_target(missing-tests-notice
+        ${_cmds}
+        DEPENDS run-ctest
+        COMMENT "Some tests not available" VERBATIM)
+    add_dependencies(check missing-tests-notice)
+endfunction()